summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore19
-rw-r--r--AUTHORS2
-rw-r--r--HH-TODO24
-rw-r--r--Makefile.am43
-rw-r--r--TODO8
-rw-r--r--codeblocks/chocolate.workspace32
-rw-r--r--codeblocks/config.h6
-rw-r--r--codeblocks/doom.cbp510
-rw-r--r--codeblocks/game-res.rc10
-rw-r--r--codeblocks/heretic.cbp444
-rw-r--r--codeblocks/hexen.cbp (renamed from codeblocks/game.cbp)371
-rw-r--r--codeblocks/libopl.cbp83
-rw-r--r--codeblocks/libpcsound.cbp2
-rw-r--r--codeblocks/libtextscreen.cbp (renamed from codeblocks/textscreen.cbp)4
-rw-r--r--codeblocks/main.workspace15
-rw-r--r--codeblocks/server.cbp18
-rw-r--r--codeblocks/setup-res.rc8
-rw-r--r--codeblocks/setup.cbp140
-rw-r--r--codeblocks/strife.cbp515
-rw-r--r--configure.in23
-rw-r--r--man/Makefile.am72
-rwxr-xr-xman/docgen59
-rw-r--r--msvc/.gitignore7
-rw-r--r--msvc/ChocolateDoom.sln32
-rw-r--r--msvc/ChocolateDoom.vcproj10288
-rw-r--r--msvc/chocolate.sln83
-rw-r--r--msvc/config.h6
-rw-r--r--msvc/doom.vcproj1019
-rw-r--r--msvc/heretic.vcproj698
-rw-r--r--msvc/hexen.vcproj764
-rw-r--r--msvc/libopl.vcproj237
-rw-r--r--msvc/libpcsound.vcproj195
-rw-r--r--msvc/libtextscreen.vcproj337
-rw-r--r--msvc/server.vcproj312
-rw-r--r--msvc/setup.vcproj320
-rw-r--r--msvc/strife.vcproj1107
-rw-r--r--msvc/win32.rc10
-rw-r--r--msvc/win_opendir.c340
-rw-r--r--msvc/win_opendir.h77
-rw-r--r--pkg/Makefile.am5
-rw-r--r--pkg/osx/GNUmakefile8
-rw-r--r--pkg/osx/IWADController.h5
-rw-r--r--pkg/osx/IWADController.m38
-rw-r--r--pkg/osx/LauncherManager.m26
-rw-r--r--pkg/osx/Resources/launcher.nib/designable.nib1641
-rw-r--r--pkg/osx/Resources/launcher.nib/keyedobjects.nibbin27157 -> 32366 bytes
-rw-r--r--pkg/win32/GNUmakefile8
-rw-r--r--pkg/wince/GNUmakefile34
-rw-r--r--pkg/wince/common.py9
-rw-r--r--pkg/wince/doom-cab.cfg27
-rw-r--r--pkg/wince/heretic-cab.cfg27
-rw-r--r--pkg/wince/hexen-cab.cfg27
-rw-r--r--pkg/wince/wince-cab.cfg25
-rw-r--r--rpm.spec.in39
-rw-r--r--setup/configfile.c803
-rw-r--r--setup/sound.c178
-rw-r--r--setup/sound.h54
-rw-r--r--src/.gitignore3
-rw-r--r--src/Makefile.am229
-rw-r--r--src/d_dedicated.c24
-rw-r--r--src/d_event.c72
-rw-r--r--src/d_event.h50
-rw-r--r--src/d_iwad.c375
-rw-r--r--src/d_iwad.h30
-rw-r--r--src/d_loop.c752
-rw-r--r--src/d_loop.h77
-rw-r--r--src/d_mode.c189
-rw-r--r--src/d_mode.h101
-rw-r--r--src/d_net.c644
-rw-r--r--src/d_ticcmd.h22
-rw-r--r--src/deh_main.c80
-rw-r--r--src/deh_main.h23
-rw-r--r--src/deh_mapping.c142
-rw-r--r--src/deh_mapping.h22
-rw-r--r--src/deh_str.c408
-rw-r--r--src/deh_str.h55
-rw-r--r--src/deh_text.c376
-rw-r--r--src/doom/.gitignore5
-rw-r--r--src/doom/Makefile.am77
-rw-r--r--src/doom/am_map.c (renamed from src/am_map.c)32
-rw-r--r--src/doom/am_map.h (renamed from src/am_map.h)0
-rw-r--r--src/doom/d_englsh.h (renamed from src/d_englsh.h)0
-rw-r--r--src/doom/d_items.c (renamed from src/d_items.c)0
-rw-r--r--src/doom/d_items.h (renamed from src/d_items.h)0
-rw-r--r--src/doom/d_main.c (renamed from src/d_main.c)653
-rw-r--r--src/doom/d_main.h (renamed from src/d_main.h)24
-rw-r--r--src/doom/d_net.c304
-rw-r--r--src/doom/d_player.h (renamed from src/d_player.h)1
-rw-r--r--src/doom/d_textur.h (renamed from src/d_textur.h)0
-rw-r--r--src/doom/d_think.h (renamed from src/d_think.h)0
-rw-r--r--src/doom/deh_ammo.c (renamed from src/deh_ammo.c)0
-rw-r--r--src/doom/deh_cheat.c (renamed from src/deh_cheat.c)4
-rw-r--r--src/doom/deh_doom.c74
-rw-r--r--src/doom/deh_frame.c (renamed from src/deh_frame.c)2
-rw-r--r--src/doom/deh_misc.c (renamed from src/deh_misc.c)1
-rw-r--r--src/doom/deh_misc.h (renamed from src/deh_misc.h)0
-rw-r--r--src/doom/deh_ptr.c (renamed from src/deh_ptr.c)2
-rw-r--r--src/doom/deh_sound.c (renamed from src/deh_sound.c)7
-rw-r--r--src/doom/deh_thing.c (renamed from src/deh_thing.c)2
-rw-r--r--src/doom/deh_weapon.c (renamed from src/deh_weapon.c)2
-rw-r--r--src/doom/doom.desktop.in7
-rw-r--r--src/doom/doomdata.h (renamed from src/doomdata.h)0
-rw-r--r--src/doom/doomdef.c (renamed from src/doomdef.c)0
-rw-r--r--src/doom/doomdef.h (renamed from src/doomdef.h)174
-rw-r--r--src/doom/doomstat.c (renamed from src/doomstat.c)2
-rw-r--r--src/doom/doomstat.h (renamed from src/doomstat.h)42
-rw-r--r--src/doom/dstrings.c (renamed from src/dstrings.c)0
-rw-r--r--src/doom/dstrings.h (renamed from src/dstrings.h)0
-rw-r--r--src/doom/f_finale.c (renamed from src/f_finale.c)40
-rw-r--r--src/doom/f_finale.h (renamed from src/f_finale.h)0
-rw-r--r--src/doom/f_wipe.c (renamed from src/f_wipe.c)20
-rw-r--r--src/doom/f_wipe.h (renamed from src/f_wipe.h)0
-rw-r--r--src/doom/g_game.c (renamed from src/g_game.c)236
-rw-r--r--src/doom/g_game.h (renamed from src/g_game.h)5
-rw-r--r--src/doom/hu_lib.c (renamed from src/hu_lib.c)5
-rw-r--r--src/doom/hu_lib.h (renamed from src/hu_lib.h)6
-rw-r--r--src/doom/hu_stuff.c (renamed from src/hu_stuff.c)72
-rw-r--r--src/doom/hu_stuff.h (renamed from src/hu_stuff.h)2
-rw-r--r--src/doom/info.c (renamed from src/info.c)2
-rw-r--r--src/doom/info.h (renamed from src/info.h)0
-rw-r--r--src/doom/m_menu.c (renamed from src/m_menu.c)167
-rw-r--r--src/doom/m_menu.h (renamed from src/m_menu.h)0
-rw-r--r--src/doom/m_random.c (renamed from src/m_random.c)0
-rw-r--r--src/doom/m_random.h (renamed from src/m_random.h)0
-rw-r--r--src/doom/p_ceilng.c (renamed from src/p_ceilng.c)0
-rw-r--r--src/doom/p_doors.c (renamed from src/p_doors.c)0
-rw-r--r--src/doom/p_enemy.c (renamed from src/p_enemy.c)2
-rw-r--r--src/doom/p_floor.c (renamed from src/p_floor.c)0
-rw-r--r--src/doom/p_inter.c (renamed from src/p_inter.c)0
-rw-r--r--src/doom/p_inter.h (renamed from src/p_inter.h)0
-rw-r--r--src/doom/p_lights.c (renamed from src/p_lights.c)0
-rw-r--r--src/doom/p_local.h (renamed from src/p_local.h)0
-rw-r--r--src/doom/p_map.c (renamed from src/p_map.c)2
-rw-r--r--src/doom/p_maputl.c (renamed from src/p_maputl.c)0
-rw-r--r--src/doom/p_mobj.c (renamed from src/p_mobj.c)1
-rw-r--r--src/doom/p_mobj.h (renamed from src/p_mobj.h)0
-rw-r--r--src/doom/p_plats.c (renamed from src/p_plats.c)2
-rw-r--r--src/doom/p_pspr.c (renamed from src/p_pspr.c)0
-rw-r--r--src/doom/p_pspr.h (renamed from src/p_pspr.h)0
-rw-r--r--src/doom/p_saveg.c (renamed from src/p_saveg.c)0
-rw-r--r--src/doom/p_saveg.h (renamed from src/p_saveg.h)0
-rw-r--r--src/doom/p_setup.c (renamed from src/p_setup.c)0
-rw-r--r--src/doom/p_setup.h (renamed from src/p_setup.h)0
-rw-r--r--src/doom/p_sight.c (renamed from src/p_sight.c)0
-rw-r--r--src/doom/p_spec.c (renamed from src/p_spec.c)0
-rw-r--r--src/doom/p_spec.h (renamed from src/p_spec.h)0
-rw-r--r--src/doom/p_switch.c (renamed from src/p_switch.c)2
-rw-r--r--src/doom/p_telept.c (renamed from src/p_telept.c)0
-rw-r--r--src/doom/p_tick.c (renamed from src/p_tick.c)0
-rw-r--r--src/doom/p_tick.h (renamed from src/p_tick.h)0
-rw-r--r--src/doom/p_user.c (renamed from src/p_user.c)0
-rw-r--r--src/doom/r_bsp.c (renamed from src/r_bsp.c)0
-rw-r--r--src/doom/r_bsp.h (renamed from src/r_bsp.h)0
-rw-r--r--src/doom/r_data.c (renamed from src/r_data.c)2
-rw-r--r--src/doom/r_data.h (renamed from src/r_data.h)0
-rw-r--r--src/doom/r_defs.h (renamed from src/r_defs.h)35
-rw-r--r--src/doom/r_draw.c (renamed from src/r_draw.c)106
-rw-r--r--src/doom/r_draw.h (renamed from src/r_draw.h)0
-rw-r--r--src/doom/r_local.h (renamed from src/r_local.h)0
-rw-r--r--src/doom/r_main.c (renamed from src/r_main.c)13
-rw-r--r--src/doom/r_main.h (renamed from src/r_main.h)2
-rw-r--r--src/doom/r_plane.c (renamed from src/r_plane.c)2
-rw-r--r--src/doom/r_plane.h (renamed from src/r_plane.h)0
-rw-r--r--src/doom/r_segs.c (renamed from src/r_segs.c)2
-rw-r--r--src/doom/r_segs.h (renamed from src/r_segs.h)0
-rw-r--r--src/doom/r_sky.c (renamed from src/r_sky.c)0
-rw-r--r--src/doom/r_sky.h (renamed from src/r_sky.h)0
-rw-r--r--src/doom/r_state.h (renamed from src/r_state.h)0
-rw-r--r--src/doom/r_things.c (renamed from src/r_things.c)0
-rw-r--r--src/doom/r_things.h (renamed from src/r_things.h)0
-rw-r--r--src/doom/s_sound.c (renamed from src/s_sound.c)284
-rw-r--r--src/doom/s_sound.h97
-rw-r--r--src/doom/sounds.c237
-rw-r--r--src/doom/sounds.h (renamed from src/sounds.h)63
-rw-r--r--src/doom/st_lib.c (renamed from src/st_lib.c)20
-rw-r--r--src/doom/st_lib.h (renamed from src/st_lib.h)9
-rw-r--r--src/doom/st_stuff.c (renamed from src/st_stuff.c)24
-rw-r--r--src/doom/st_stuff.h (renamed from src/st_stuff.h)2
-rw-r--r--src/doom/statdump.c362
-rw-r--r--src/doom/statdump.h29
-rw-r--r--src/doom/wi_stuff.c (renamed from src/wi_stuff.c)139
-rw-r--r--src/doom/wi_stuff.h (renamed from src/wi_stuff.h)0
-rw-r--r--src/doomkeys.h2
-rw-r--r--src/doomtype.h35
-rw-r--r--src/gusconf.c279
-rw-r--r--src/gusconf.h37
-rw-r--r--src/heretic/.gitignore6
-rw-r--r--src/heretic/Makefile.am70
-rw-r--r--src/heretic/am_data.h111
-rw-r--r--src/heretic/am_map.c1513
-rw-r--r--src/heretic/am_map.h119
-rw-r--r--src/heretic/ct_chat.c480
-rw-r--r--src/heretic/ct_chat.h46
-rw-r--r--src/heretic/d_main.c1078
-rw-r--r--src/heretic/d_net.c238
-rw-r--r--src/heretic/deh_ammo.c122
-rw-r--r--src/heretic/deh_frame.c344
-rw-r--r--src/heretic/deh_htext.c856
-rw-r--r--src/heretic/deh_htic.c186
-rw-r--r--src/heretic/deh_htic.h60
-rw-r--r--src/heretic/deh_sound.c118
-rw-r--r--src/heretic/deh_thing.c150
-rw-r--r--src/heretic/deh_weapon.c131
-rw-r--r--src/heretic/doomdata.h200
-rw-r--r--src/heretic/doomdef.h825
-rw-r--r--src/heretic/dstrings.h252
-rw-r--r--src/heretic/f_finale.c432
-rw-r--r--src/heretic/g_game.c1916
-rw-r--r--src/heretic/i_ibm.c1650
-rw-r--r--src/heretic/i_sound.c432
-rw-r--r--src/heretic/in_lude.c1075
-rw-r--r--src/heretic/info.c5608
-rw-r--r--src/heretic/info.h1586
-rw-r--r--src/heretic/m_random.c78
-rw-r--r--src/heretic/m_random.h42
-rw-r--r--src/heretic/mn_menu.c1667
-rw-r--r--src/heretic/p_action.h160
-rw-r--r--src/heretic/p_ceilng.c263
-rw-r--r--src/heretic/p_doors.c387
-rw-r--r--src/heretic/p_enemy.c2686
-rw-r--r--src/heretic/p_floor.c468
-rw-r--r--src/heretic/p_inter.c1493
-rw-r--r--src/heretic/p_lights.c282
-rw-r--r--src/heretic/p_local.h287
-rw-r--r--src/heretic/p_map.c1698
-rw-r--r--src/heretic/p_maputl.c784
-rw-r--r--src/heretic/p_mobj.c1633
-rw-r--r--src/heretic/p_plats.c266
-rw-r--r--src/heretic/p_pspr.c1908
-rw-r--r--src/heretic/p_setup.c660
-rw-r--r--src/heretic/p_sight.c363
-rw-r--r--src/heretic/p_spec.c1307
-rw-r--r--src/heretic/p_spec.h398
-rw-r--r--src/heretic/p_switch.c414
-rw-r--r--src/heretic/p_telept.c173
-rw-r--r--src/heretic/p_tick.c668
-rw-r--r--src/heretic/p_user.c1020
-rw-r--r--src/heretic/r_bsp.c484
-rw-r--r--src/heretic/r_data.c749
-rw-r--r--src/heretic/r_draw.c498
-rw-r--r--src/heretic/r_local.h484
-rw-r--r--src/heretic/r_main.c827
-rw-r--r--src/heretic/r_plane.c521
-rw-r--r--src/heretic/r_segs.c669
-rw-r--r--src/heretic/r_things.c1024
-rw-r--r--src/heretic/s_sound.c608
-rw-r--r--src/heretic/s_sound.h46
-rw-r--r--src/heretic/sb_bar.c1293
-rw-r--r--src/heretic/sounds.c257
-rw-r--r--src/heretic/sounds.h299
-rw-r--r--src/hexen/.gitignore5
-rw-r--r--src/hexen/Makefile.am67
-rw-r--r--src/hexen/a_action.c1349
-rw-r--r--src/hexen/am_data.h117
-rw-r--r--src/hexen/am_map.c1520
-rw-r--r--src/hexen/am_map.h130
-rw-r--r--src/hexen/ct_chat.c510
-rw-r--r--src/hexen/ct_chat.h (renamed from setup/m_argv.h)34
-rw-r--r--src/hexen/d_net.c280
-rw-r--r--src/hexen/f_finale.c395
-rw-r--r--src/hexen/g_game.c1892
-rw-r--r--src/hexen/h2_main.c899
-rw-r--r--src/hexen/h2def.h1069
-rw-r--r--src/hexen/i_header.h100
-rw-r--r--src/hexen/i_ibm.c1845
-rw-r--r--src/hexen/i_sound.c410
-rw-r--r--src/hexen/in_lude.c615
-rw-r--r--src/hexen/info.c13886
-rw-r--r--src/hexen/info.h3628
-rw-r--r--src/hexen/m_misc.c29
-rw-r--r--src/hexen/m_random.c82
-rw-r--r--src/hexen/m_random.h42
-rw-r--r--src/hexen/mn_menu.c1784
-rw-r--r--src/hexen/p_acs.c1884
-rw-r--r--src/hexen/p_anim.c488
-rw-r--r--src/hexen/p_ceilng.c310
-rw-r--r--src/hexen/p_doors.c326
-rw-r--r--src/hexen/p_enemy.c5390
-rw-r--r--src/hexen/p_floor.c952
-rw-r--r--src/hexen/p_inter.c2250
-rw-r--r--src/hexen/p_lights.c376
-rw-r--r--src/hexen/p_local.h387
-rw-r--r--src/hexen/p_map.c2312
-rw-r--r--src/hexen/p_maputl.c1078
-rw-r--r--src/hexen/p_mobj.c2474
-rw-r--r--src/hexen/p_plats.c284
-rw-r--r--src/hexen/p_pspr.c2477
-rw-r--r--src/hexen/p_setup.c1227
-rw-r--r--src/hexen/p_sight.c407
-rw-r--r--src/hexen/p_spec.c1199
-rw-r--r--src/hexen/p_spec.h578
-rw-r--r--src/hexen/p_switch.c159
-rw-r--r--src/hexen/p_telept.c198
-rw-r--r--src/hexen/p_things.c545
-rw-r--r--src/hexen/p_tick.c155
-rw-r--r--src/hexen/p_user.c1652
-rw-r--r--src/hexen/po_man.c1509
-rw-r--r--src/hexen/r_bsp.c505
-rw-r--r--src/hexen/r_data.c706
-rw-r--r--src/hexen/r_draw.c566
-rw-r--r--src/hexen/r_local.h552
-rw-r--r--src/hexen/r_main.c839
-rw-r--r--src/hexen/r_plane.c590
-rw-r--r--src/hexen/r_segs.c662
-rw-r--r--src/hexen/r_things.c1051
-rw-r--r--src/hexen/s_sound.c939
-rw-r--r--src/hexen/s_sound.h99
-rw-r--r--src/hexen/sb_bar.c1997
-rw-r--r--src/hexen/sc_man.c478
-rw-r--r--src/hexen/sn_sonix.c544
-rw-r--r--src/hexen/sounds.c321
-rw-r--r--src/hexen/sounds.h324
-rw-r--r--src/hexen/st_start.c316
-rw-r--r--src/hexen/st_start.h47
-rw-r--r--src/hexen/sv_save.c1768
-rw-r--r--src/hexen/textdefs.h180
-rw-r--r--src/hexen/xddefs.h197
-rw-r--r--src/i_cdmus.c182
-rw-r--r--src/i_cdmus.h48
-rw-r--r--src/i_endoom.c82
-rw-r--r--src/i_endoom.h37
-rw-r--r--src/i_joystick.c26
-rw-r--r--src/i_joystick.h8
-rw-r--r--src/i_main.c17
-rw-r--r--src/i_oplmusic.c5
-rw-r--r--src/i_pcsound.c69
-rw-r--r--src/i_scale.c7
-rw-r--r--src/i_sdlmusic.c126
-rw-r--r--src/i_sdlsound.c741
-rw-r--r--src/i_sound.c464
-rw-r--r--src/i_sound.h (renamed from src/s_sound.h)170
-rw-r--r--src/i_system.c188
-rw-r--r--src/i_system.h46
-rw-r--r--src/i_timer.c7
-rw-r--r--src/i_timer.h5
-rw-r--r--src/i_video.c470
-rw-r--r--src/i_video.h91
-rw-r--r--src/i_videohr.c222
-rw-r--r--src/i_videohr.h42
-rw-r--r--src/m_argv.c62
-rw-r--r--src/m_argv.h10
-rw-r--r--src/m_config.c1291
-rw-r--r--src/m_config.h7
-rw-r--r--src/m_controls.c448
-rw-r--r--src/m_controls.h (renamed from setup/keyboard.h)137
-rw-r--r--src/m_misc.c96
-rw-r--r--src/m_misc.h3
-rw-r--r--src/midifile.c11
-rw-r--r--src/mus2mid.c44
-rw-r--r--src/net_client.c380
-rw-r--r--src/net_client.h19
-rw-r--r--src/net_common.c46
-rw-r--r--src/net_common.h4
-rw-r--r--src/net_dedicated.c3
-rw-r--r--src/net_defs.h76
-rw-r--r--src/net_gui.c115
-rw-r--r--src/net_gui.h2
-rw-r--r--src/net_io.c2
-rw-r--r--src/net_loop.c2
-rw-r--r--src/net_query.c56
-rw-r--r--src/net_sdl.c2
-rw-r--r--src/net_server.c213
-rw-r--r--src/net_structrw.c242
-rw-r--r--src/net_structrw.h9
-rw-r--r--src/resource.rc.in2
-rw-r--r--src/setup-res.rc.in (renamed from setup/setup-res.rc.in)4
-rw-r--r--src/setup/.gitignore (renamed from setup/.gitignore)4
-rw-r--r--src/setup/Makefile.am (renamed from setup/Makefile.am)32
-rw-r--r--src/setup/compatibility.c (renamed from setup/compatibility.c)11
-rw-r--r--src/setup/compatibility.h (renamed from setup/compatibility.h)6
-rw-r--r--src/setup/display.c (renamed from setup/display.c)88
-rw-r--r--src/setup/display.h (renamed from setup/display.h)14
-rw-r--r--src/setup/execute.c (renamed from setup/execute.c)55
-rw-r--r--src/setup/execute.h (renamed from setup/execute.h)0
-rw-r--r--src/setup/joystick.c (renamed from setup/joystick.c)62
-rw-r--r--src/setup/joystick.h (renamed from setup/joystick.h)15
-rw-r--r--src/setup/keyboard.c (renamed from setup/keyboard.c)265
-rw-r--r--src/setup/keyboard.h30
-rw-r--r--src/setup/mainmenu.c (renamed from setup/mainmenu.c)117
-rw-r--r--src/setup/mode.c381
-rw-r--r--src/setup/mode.h37
-rw-r--r--src/setup/mouse.c (renamed from setup/mouse.c)52
-rw-r--r--src/setup/mouse.h (renamed from setup/mouse.h)21
-rw-r--r--src/setup/multiplayer.c (renamed from setup/multiplayer.c)592
-rw-r--r--src/setup/multiplayer.h (renamed from setup/multiplayer.h)5
-rw-r--r--src/setup/setup-manifest.xml.in (renamed from setup/setup-manifest.xml.in)0
-rw-r--r--src/setup/setup.desktop.in (renamed from setup/setup.desktop.in)0
-rw-r--r--src/setup/setup_icon.c (renamed from setup/setup_icon.c)0
-rw-r--r--src/setup/sound.c292
-rw-r--r--src/setup/sound.h30
-rw-r--r--src/setup/txt_joybinput.c (renamed from setup/txt_joybinput.c)22
-rw-r--r--src/setup/txt_joybinput.h (renamed from setup/txt_joybinput.h)0
-rw-r--r--src/setup/txt_keyinput.c (renamed from setup/txt_keyinput.c)12
-rw-r--r--src/setup/txt_keyinput.h (renamed from setup/txt_keyinput.h)0
-rw-r--r--src/setup/txt_mouseinput.c (renamed from setup/txt_mouseinput.c)12
-rw-r--r--src/setup/txt_mouseinput.h (renamed from setup/txt_mouseinput.h)0
-rw-r--r--src/sounds.c230
-rw-r--r--src/strife/.gitignore5
-rw-r--r--src/strife/Makefile.am78
-rw-r--r--src/strife/am_map.c1391
-rw-r--r--src/strife/am_map.h (renamed from src/d_net.h)40
-rw-r--r--src/strife/d_englsh.h600
-rw-r--r--src/strife/d_items.c167
-rw-r--r--src/strife/d_items.h50
-rw-r--r--src/strife/d_main.c2000
-rw-r--r--src/strife/d_main.h64
-rw-r--r--src/strife/d_net.c316
-rw-r--r--src/strife/d_player.h257
-rw-r--r--src/strife/d_textur.h51
-rw-r--r--src/strife/d_think.h76
-rw-r--r--src/strife/deh_ammo.c112
-rw-r--r--src/strife/deh_cheat.c157
-rw-r--r--src/strife/deh_frame.c168
-rw-r--r--src/strife/deh_misc.c237
-rw-r--r--src/strife/deh_misc.h92
-rw-r--r--src/strife/deh_ptr.c151
-rw-r--r--src/strife/deh_sound.c112
-rw-r--r--src/strife/deh_strife.c74
-rw-r--r--src/strife/deh_thing.c141
-rw-r--r--src/strife/deh_weapon.c111
-rw-r--r--src/strife/doomdata.h233
-rw-r--r--src/strife/doomdef.c36
-rw-r--r--src/strife/doomdef.h299
-rw-r--r--src/strife/doomstat.c43
-rw-r--r--src/strife/doomstat.h286
-rw-r--r--src/strife/dstrings.c81
-rw-r--r--src/strife/dstrings.h49
-rw-r--r--src/strife/f_finale.c1056
-rw-r--r--src/strife/f_finale.h56
-rw-r--r--src/strife/f_wipe.c300
-rw-r--r--src/strife/f_wipe.h71
-rw-r--r--src/strife/g_game.c2456
-rw-r--r--src/strife/g_game.h97
-rw-r--r--src/strife/hu_lib.c482
-rw-r--r--src/strife/hu_lib.h193
-rw-r--r--src/strife/hu_stuff.c666
-rw-r--r--src/strife/hu_stuff.h75
-rw-r--r--src/strife/info.c11049
-rw-r--r--src/strife/info.h2227
-rw-r--r--src/strife/m_menu.c2377
-rw-r--r--src/strife/m_menu.h109
-rw-r--r--src/strife/m_random.c88
-rw-r--r--src/strife/m_random.h (renamed from setup/configfile.h)23
-rw-r--r--src/strife/m_saves.c538
-rw-r--r--src/strife/m_saves.h64
-rw-r--r--src/strife/p_ceilng.c351
-rw-r--r--src/strife/p_dialog.c1420
-rw-r--r--src/strife/p_dialog.h108
-rw-r--r--src/strife/p_doors.c1378
-rw-r--r--src/strife/p_enemy.c3373
-rw-r--r--src/strife/p_floor.c590
-rw-r--r--src/strife/p_inter.c1408
-rw-r--r--src/strife/p_inter.h40
-rw-r--r--src/strife/p_lights.c380
-rw-r--r--src/strife/p_local.h309
-rw-r--r--src/strife/p_map.c1655
-rw-r--r--src/strife/p_maputl.c1061
-rw-r--r--src/strife/p_mobj.c1352
-rw-r--r--src/strife/p_mobj.h338
-rw-r--r--src/strife/p_plats.c362
-rw-r--r--src/strife/p_pspr.c1012
-rw-r--r--src/strife/p_pspr.h87
-rw-r--r--src/strife/p_saveg.c2215
-rw-r--r--src/strife/p_saveg.h70
-rw-r--r--src/strife/p_setup.c865
-rw-r--r--src/strife/p_setup.h45
-rw-r--r--src/strife/p_sight.c368
-rw-r--r--src/strife/p_spec.c1996
-rw-r--r--src/strife/p_spec.h686
-rw-r--r--src/strife/p_switch.c1082
-rw-r--r--src/strife/p_telept.c160
-rw-r--r--src/strife/p_tick.c165
-rw-r--r--src/strife/p_tick.h41
-rw-r--r--src/strife/p_user.c922
-rw-r--r--src/strife/r_bsp.c581
-rw-r--r--src/strife/r_bsp.h69
-rw-r--r--src/strife/r_data.c1026
-rw-r--r--src/strife/r_data.h61
-rw-r--r--src/strife/r_defs.h456
-rw-r--r--src/strife/r_draw.c976
-rw-r--r--src/strife/r_draw.h119
-rw-r--r--src/strife/r_local.h53
-rw-r--r--src/strife/r_main.c953
-rw-r--r--src/strife/r_main.h168
-rw-r--r--src/strife/r_plane.c455
-rw-r--r--src/strife/r_plane.h84
-rw-r--r--src/strife/r_segs.c762
-rw-r--r--src/strife/r_segs.h41
-rw-r--r--src/strife/r_sky.c (renamed from setup/m_argv.c)57
-rw-r--r--src/strife/r_sky.h45
-rw-r--r--src/strife/r_state.h135
-rw-r--r--src/strife/r_things.c1065
-rw-r--r--src/strife/r_things.h74
-rw-r--r--src/strife/s_sound.c828
-rw-r--r--src/strife/s_sound.h103
-rw-r--r--src/strife/sounds.c235
-rw-r--r--src/strife/sounds.h230
-rw-r--r--src/strife/st_lib.c340
-rw-r--r--src/strife/st_lib.h229
-rw-r--r--src/strife/st_stuff.c1555
-rw-r--r--src/strife/st_stuff.h108
-rw-r--r--src/strife/wi_stuff.c1844
-rw-r--r--src/strife/wi_stuff.h59
-rw-r--r--src/tables.c142
-rw-r--r--src/tables.h28
-rw-r--r--src/v_patch.h58
-rw-r--r--src/v_video.c964
-rw-r--r--src/v_video.h123
-rw-r--r--src/w_file.c3
-rw-r--r--src/w_main.c206
-rw-r--r--src/w_main.h32
-rw-r--r--src/w_merge.c39
-rw-r--r--src/w_wad.c40
-rw-r--r--src/z_native.c3
-rw-r--r--src/z_zone.c2
-rw-r--r--textscreen/Makefile.am2
-rw-r--r--textscreen/examples/Makefile.am2
-rw-r--r--textscreen/txt_desktop.c27
-rw-r--r--textscreen/txt_desktop.h19
-rw-r--r--textscreen/txt_dropdown.c19
-rw-r--r--textscreen/txt_scrollpane.c18
-rw-r--r--textscreen/txt_sdl.c7
-rw-r--r--textscreen/txt_window.c23
-rw-r--r--textscreen/txt_window.h10
524 files changed, 205120 insertions, 18407 deletions
diff --git a/.gitignore b/.gitignore
index 34652d0c..57ab998c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,21 +1,24 @@
-Makefile.in
-Makefile
-INSTALL
CMDLINE
-autotools
+INSTALL
+Makefile
+Makefile.in
+TAGS
aclocal.m4
-configure
+autom4te.cache
+autotools
+bin
+config.h
config.hin
config.log
config.status
-config.h
-autom4te.cache
+configure
+lib
+obj
rpm.spec
stamp-h
stamp-h.in
stamp-h1
tags
-TAGS
# These are the default patterns globally ignored by Subversion:
*.o
diff --git a/AUTHORS b/AUTHORS
index ed0ab083..21238bf2 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1 +1,3 @@
Simon Howard <fraggle@gmail.com>
+James Haley <haleyjd@hotmail.com>
+Samuel Villarreal <svkaiser@gmail.com>
diff --git a/HH-TODO b/HH-TODO
new file mode 100644
index 00000000..35060663
--- /dev/null
+++ b/HH-TODO
@@ -0,0 +1,24 @@
+ * Update docgen to generate manpages for Heretic/Hexen.
+
+Heretic:
+ * Frequency shifted sounds.
+ * Check all command line parameters
+ * Check for endianness assumptions
+ * Savegame code to write structures predictably and endianness-correct
+ * Remove NeXT and WATCOMC defines
+ * Structure packing macros for structures read from disk
+ * Merge r_draw.c to common version and delete duplicate
+ * v1.2 emulation (if possible)
+ * Screensaver mode
+
+Hexen:
+ * CD-ROM music playback
+ * Frequency shifted sounds.
+ * Check for endianness assumptions - mostly done now
+ * Savegame code to write structures predictably and endianness-correct
+ * Remove NeXT and WATCOMC defines
+ * Structure packing macros for structures read from disk
+ * Merge r_draw.c to common version and delete duplicate
+ * v1.0 emulation (if possible/necessary)
+ * Screensaver mode
+
diff --git a/Makefile.am b/Makefile.am
index d766ab61..a853c76c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3,25 +3,33 @@ AUX_DIST_GEN = \
$(ac_aux_dir)/missing
MSVC_FILES= \
- msvc/README \
+ msvc/chocolate.sln \
msvc/config.h \
+ msvc/doom.vcproj \
+ msvc/heretic.vcproj \
+ msvc/hexen.vcproj \
msvc/inttypes.h \
+ msvc/libpcsound.vcproj \
+ msvc/libtextscreen.vcproj \
+ msvc/README \
+ msvc/server.vcproj \
+ msvc/setup.vcproj \
msvc/stdint.h \
- msvc/win32.rc \
- msvc/ChocolateDoom.sln \
- msvc/ChocolateDoom.vcproj
+ msvc/win32.rc
CODEBLOCKS_FILES= \
- codeblocks/config.h \
- codeblocks/game.cbp \
- codeblocks/game-res.rc \
- codeblocks/libpcsound.cbp \
- codeblocks/main.workspace \
- codeblocks/README \
- codeblocks/server.cbp \
- codeblocks/setup.cbp \
- codeblocks/setup-res.rc \
- codeblocks/textscreen.cbp
+ codeblocks/chocolate.workspace \
+ codeblocks/config.h \
+ codeblocks/doom.cbp \
+ codeblocks/game-res.rc \
+ codeblocks/heretic.cbp \
+ codeblocks/hexen.cbp \
+ codeblocks/libpcsound.cbp \
+ codeblocks/libtextscreen.cbp \
+ codeblocks/README \
+ codeblocks/server.cbp \
+ codeblocks/setup.cbp \
+ codeblocks/setup-res.rc
DOC_FILES= \
CMDLINE \
@@ -46,15 +54,18 @@ doc_DATA=$(DOC_FILES)
MAINTAINERCLEANFILES = $(AUX_DIST_GEN)
-SUBDIRS=wince textscreen opl pcsound data src man setup
+SUBDIRS=wince textscreen opl pcsound data src man
+
DIST_SUBDIRS=pkg $(SUBDIRS)
if HAVE_PYTHON
noinst_DATA=CMDLINE
+# TODO: CMDLINE only documents the Doom command line, not other games.
+
CMDLINE : src/
- ./man/docgen -p man/CMDLINE.template src/ > $@
+ ./man/docgen -p man/CMDLINE.template src/ src/doom/ > $@
INSTALL : man/INSTALL.template man/simplecpp
./man/simplecpp < man/INSTALL.template > $@
diff --git a/TODO b/TODO
index 6772e86a..1705a6fa 100644
--- a/TODO
+++ b/TODO
@@ -1,19 +1,11 @@
-Currently in progress:
-
-* Heretic/Hexen support (see: raven-branch)
-* Strife support (see: strife-branch)
-
To do:
* Demo hashes for regression testing of this and other ports.
* File selector for chocolate-setup, so that WADs can be selected from
a browser, instead of simply typing the filenames.
* Multiplayer:
- - Master server for locating servers automatically - makes setting up
- public servers easier.
- Use UPnP to automatically configure port forwarding for NATted
networks.
- - Incorporate local LAN search into setup interface.
- Multiplayer options and configuration file (server name, etc)
* Improve multiplayer startup:
- Select an IWAD automatically from the server's game type rather than
diff --git a/codeblocks/chocolate.workspace b/codeblocks/chocolate.workspace
new file mode 100644
index 00000000..ed611b7b
--- /dev/null
+++ b/codeblocks/chocolate.workspace
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<CodeBlocks_workspace_file>
+ <Workspace title="Chocolate">
+ <Project filename="doom.cbp">
+ <Depends filename="libtextscreen.cbp" />
+ <Depends filename="libopl.cbp" />
+ <Depends filename="libpcsound.cbp" />
+ </Project>
+ <Project filename="heretic.cbp">
+ <Depends filename="libtextscreen.cbp" />
+ <Depends filename="libopl.cbp" />
+ <Depends filename="libpcsound.cbp" />
+ </Project>
+ <Project filename="hexen.cbp">
+ <Depends filename="libtextscreen.cbp" />
+ <Depends filename="libopl.cbp" />
+ <Depends filename="libpcsound.cbp" />
+ </Project>
+ <Project filename="strife.cbp" active="1">
+ <Depends filename="libtextscreen.cbp" />
+ <Depends filename="libopl.cbp" />
+ <Depends filename="libpcsound.cbp" />
+ </Project>
+ <Project filename="server.cbp" />
+ <Project filename="setup.cbp">
+ <Depends filename="libtextscreen.cbp" />
+ </Project>
+ <Project filename="libtextscreen.cbp" />
+ <Project filename="libopl.cbp" />
+ <Project filename="libpcsound.cbp" />
+ </Workspace>
+</CodeBlocks_workspace_file>
diff --git a/codeblocks/config.h b/codeblocks/config.h
index 889e3dd4..94c48005 100644
--- a/codeblocks/config.h
+++ b/codeblocks/config.h
@@ -9,13 +9,13 @@
#define PACKAGE_NAME "Chocolate Doom"
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "Chocolate Doom 1.7.0"
+#define PACKAGE_STRING "Chocolate Doom 1.99.0"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "chocolate-doom"
/* Define to the version of this package. */
-#define PACKAGE_VERSION "1.7.0"
+#define PACKAGE_VERSION "1.99.0"
/* Change this when you create your awesome forked version */
#define PROGRAM_PREFIX "chocolate-"
@@ -24,7 +24,7 @@
#define STDC_HEADERS 1
/* Version number of package */
-#define VERSION "1.7.0"
+#define VERSION "1.99.0"
/* Define to 1 if your processor stores words with the most significant byte
first (like Motorola and SPARC, unlike Intel and VAX). */
diff --git a/codeblocks/doom.cbp b/codeblocks/doom.cbp
new file mode 100644
index 00000000..bba39b74
--- /dev/null
+++ b/codeblocks/doom.cbp
@@ -0,0 +1,510 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<CodeBlocks_project_file>
+ <FileVersion major="1" minor="6" />
+ <Project>
+ <Option title="Doom" />
+ <Option pch_mode="2" />
+ <Option compiler="gcc" />
+ <Build>
+ <Target title="Debug">
+ <Option output="..\bin\chocolate-doom-dbg.exe" prefix_auto="0" extension_auto="0" />
+ <Option working_dir="..\bin" />
+ <Option object_output="..\obj\chocolate-doom\dbg" />
+ <Option type="0" />
+ <Option compiler="gcc" />
+ <Option projectLinkerOptionsRelation="2" />
+ <Compiler>
+ <Add option="-W" />
+ <Add option="-gdwarf-2" />
+ </Compiler>
+ <Linker>
+ <Add option="-lopl-dbg -lpcsound-dbg -ltextscreen-dbg" />
+ </Linker>
+ </Target>
+ <Target title="Release">
+ <Option output="..\bin\chocolate-doom.exe" prefix_auto="0" extension_auto="0" />
+ <Option working_dir="..\bin" />
+ <Option object_output="..\obj\chocolate-doom\rel" />
+ <Option type="0" />
+ <Option compiler="gcc" />
+ <Option projectLinkerOptionsRelation="2" />
+ <Compiler>
+ <Add option="-O2" />
+ </Compiler>
+ <Linker>
+ <Add option="-s" />
+ <Add option="-lopl -lpcsound -ltextscreen" />
+ </Linker>
+ </Target>
+ </Build>
+ <VirtualTargets>
+ <Add alias="All" targets="Debug;Release;" />
+ </VirtualTargets>
+ <Compiler>
+ <Add option='-DPROGRAM_PREFIX=&quot;\&quot;chocolate-\&quot;&quot;' />
+ <Add option='-DD_CDROM=&quot;\&quot;CD-ROM Version: default.cfg from c:\\doomdata\n\&quot;&quot;' />
+ <Add directory="." />
+ <Add directory="..\src" />
+ <Add directory="..\src\doom" />
+ <Add directory="..\textscreen" />
+ <Add directory="..\pcsound" />
+ <Add directory="..\opl" />
+ </Compiler>
+ <Linker>
+ <Add option="-lmingw32 -lSDLmain -lSDL -lSDL_mixer -lSDL_net -mwindows" />
+ <Add directory="..\lib" />
+ </Linker>
+ <Unit filename="config.h" />
+ <Unit filename="game-res.rc">
+ <Option compilerVar="WINDRES" />
+ </Unit>
+ <Unit filename="..\src\d_event.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\d_event.h" />
+ <Unit filename="..\src\d_iwad.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\d_iwad.h" />
+ <Unit filename="..\src\d_loop.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\d_loop.h" />
+ <Unit filename="..\src\d_mode.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\d_mode.h" />
+ <Unit filename="..\src\d_ticcmd.h" />
+ <Unit filename="..\src\deh_defs.h" />
+ <Unit filename="..\src\deh_io.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\deh_io.h" />
+ <Unit filename="..\src\deh_main.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\deh_main.h" />
+ <Unit filename="..\src\deh_mapping.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\deh_mapping.h" />
+ <Unit filename="..\src\deh_str.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\deh_str.h" />
+ <Unit filename="..\src\deh_text.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\am_map.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\am_map.h" />
+ <Unit filename="..\src\doom\d_englsh.h" />
+ <Unit filename="..\src\doom\d_items.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\d_items.h" />
+ <Unit filename="..\src\doom\d_main.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\d_main.h" />
+ <Unit filename="..\src\doom\d_net.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\d_net.h" />
+ <Unit filename="..\src\doom\d_player.h" />
+ <Unit filename="..\src\doom\d_textur.h" />
+ <Unit filename="..\src\doom\d_think.h" />
+ <Unit filename="..\src\doom\deh_ammo.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\deh_cheat.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\deh_doom.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\deh_frame.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\deh_misc.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\deh_misc.h" />
+ <Unit filename="..\src\doom\deh_ptr.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\deh_sound.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\deh_thing.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\deh_weapon.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\doomdata.h" />
+ <Unit filename="..\src\doom\doomdef.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\doomdef.h" />
+ <Unit filename="..\src\doom\doomstat.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\doomstat.h" />
+ <Unit filename="..\src\doom\dstrings.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\dstrings.h" />
+ <Unit filename="..\src\doom\f_finale.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\f_finale.h" />
+ <Unit filename="..\src\doom\f_wipe.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\f_wipe.h" />
+ <Unit filename="..\src\doom\g_game.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\g_game.h" />
+ <Unit filename="..\src\doom\hu_lib.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\hu_lib.h" />
+ <Unit filename="..\src\doom\hu_stuff.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\hu_stuff.h" />
+ <Unit filename="..\src\doom\info.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\info.h" />
+ <Unit filename="..\src\doom\m_menu.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\m_menu.h" />
+ <Unit filename="..\src\doom\m_random.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\m_random.h" />
+ <Unit filename="..\src\doom\p_ceilng.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\p_doors.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\p_enemy.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\p_floor.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\p_inter.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\p_inter.h" />
+ <Unit filename="..\src\doom\p_lights.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\p_local.h" />
+ <Unit filename="..\src\doom\p_map.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\p_maputl.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\p_mobj.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\p_mobj.h" />
+ <Unit filename="..\src\doom\p_plats.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\p_pspr.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\p_pspr.h" />
+ <Unit filename="..\src\doom\p_saveg.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\p_saveg.h" />
+ <Unit filename="..\src\doom\p_setup.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\p_setup.h" />
+ <Unit filename="..\src\doom\p_sight.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\p_spec.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\p_spec.h" />
+ <Unit filename="..\src\doom\p_switch.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\p_telept.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\p_tick.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\p_tick.h" />
+ <Unit filename="..\src\doom\p_user.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\r_bsp.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\r_bsp.h" />
+ <Unit filename="..\src\doom\r_data.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\r_data.h" />
+ <Unit filename="..\src\doom\r_defs.h" />
+ <Unit filename="..\src\doom\r_draw.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\r_draw.h" />
+ <Unit filename="..\src\doom\r_local.h" />
+ <Unit filename="..\src\doom\r_main.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\r_main.h" />
+ <Unit filename="..\src\doom\r_plane.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\r_plane.h" />
+ <Unit filename="..\src\doom\r_segs.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\r_segs.h" />
+ <Unit filename="..\src\doom\r_sky.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\r_sky.h" />
+ <Unit filename="..\src\doom\r_state.h" />
+ <Unit filename="..\src\doom\r_things.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\r_things.h" />
+ <Unit filename="..\src\doom\s_sound.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\s_sound.h" />
+ <Unit filename="..\src\doom\sounds.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\sounds.h" />
+ <Unit filename="..\src\doom\st_lib.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\st_lib.h" />
+ <Unit filename="..\src\doom\st_stuff.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\st_stuff.h" />
+ <Unit filename="..\src\doom\statdump.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\statdump.h" />
+ <Unit filename="..\src\doom\wi_stuff.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doom\wi_stuff.h" />
+ <Unit filename="..\src\doomfeatures.h" />
+ <Unit filename="..\src\doomkeys.h" />
+ <Unit filename="..\src\doomtype.h" />
+ <Unit filename="..\src\i_cdmus.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_cdmus.h" />
+ <Unit filename="..\src\i_endoom.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_endoom.h" />
+ <Unit filename="..\src\i_joystick.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_joystick.h" />
+ <Unit filename="..\src\i_main.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_oplmusic.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_pcsound.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_scale.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_scale.h" />
+ <Unit filename="..\src\i_sdlmusic.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_sdlsound.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_sound.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_sound.h" />
+ <Unit filename="..\src\i_swap.h" />
+ <Unit filename="..\src\i_system.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_system.h" />
+ <Unit filename="..\src\i_timer.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_timer.h" />
+ <Unit filename="..\src\i_video.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_video.h" />
+ <Unit filename="..\src\i_videohr.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_videohr.h" />
+ <Unit filename="..\src\icon.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\m_argv.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\m_argv.h" />
+ <Unit filename="..\src\m_bbox.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\m_bbox.h" />
+ <Unit filename="..\src\m_cheat.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\m_cheat.h" />
+ <Unit filename="..\src\m_config.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\m_config.h" />
+ <Unit filename="..\src\m_controls.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\m_controls.h" />
+ <Unit filename="..\src\m_fixed.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\m_fixed.h" />
+ <Unit filename="..\src\m_misc.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\m_misc.h" />
+ <Unit filename="..\src\md5.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\md5.h" />
+ <Unit filename="..\src\memio.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\memio.h" />
+ <Unit filename="..\src\midifile.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\midifile.h" />
+ <Unit filename="..\src\mus2mid.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\mus2mid.h" />
+ <Unit filename="..\src\net_client.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_client.h" />
+ <Unit filename="..\src\net_common.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_common.h" />
+ <Unit filename="..\src\net_dedicated.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_dedicated.h" />
+ <Unit filename="..\src\net_defs.h" />
+ <Unit filename="..\src\net_gui.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_gui.h" />
+ <Unit filename="..\src\net_io.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_io.h" />
+ <Unit filename="..\src\net_loop.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_loop.h" />
+ <Unit filename="..\src\net_packet.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_packet.h" />
+ <Unit filename="..\src\net_query.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_query.h" />
+ <Unit filename="..\src\net_sdl.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_sdl.h" />
+ <Unit filename="..\src\net_server.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_server.h" />
+ <Unit filename="..\src\net_structrw.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_structrw.h" />
+ <Unit filename="..\src\tables.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\tables.h" />
+ <Unit filename="..\src\v_patch.h" />
+ <Unit filename="..\src\v_video.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\v_video.h" />
+ <Unit filename="..\src\w_checksum.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\w_checksum.h" />
+ <Unit filename="..\src\w_file.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\w_file.h" />
+ <Unit filename="..\src\w_file_posix.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\w_file_stdc.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\w_file_win32.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\w_main.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\w_main.h" />
+ <Unit filename="..\src\w_merge.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\w_merge.h" />
+ <Unit filename="..\src\w_wad.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\w_wad.h" />
+ <Unit filename="..\src\z_zone.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\z_zone.h" />
+ <Extensions>
+ <code_completion />
+ <envvars />
+ <debugger />
+ </Extensions>
+ </Project>
+</CodeBlocks_project_file>
diff --git a/codeblocks/game-res.rc b/codeblocks/game-res.rc
index 3e80c721..f133e88a 100644
--- a/codeblocks/game-res.rc
+++ b/codeblocks/game-res.rc
@@ -1,21 +1,21 @@
1 ICON "../data/doom.ico"
1 VERSIONINFO
-PRODUCTVERSION 1,7,0,0
-FILEVERSION 1,7,0,0
+PRODUCTVERSION 1,99,0,0
+FILEVERSION 1,99,0,0
FILETYPE 1
{
BLOCK "StringFileInfo"
{
BLOCK "040904E4"
{
- VALUE "FileVersion", "1.7.0"
- VALUE "FileDescription", "1.7.0"
+ VALUE "FileVersion", "1.99.0"
+ VALUE "FileDescription", "1.99.0"
VALUE "InternalName", "Chocolate-Doom"
VALUE "CompanyName", "Chocolate-Doom"
VALUE "LegalCopyright", "GNU General Public License"
VALUE "ProductName", "Chocolate-Doom"
- VALUE "ProductVersion", "1.7.0"
+ VALUE "ProductVersion", "1.99.0"
}
}
}
diff --git a/codeblocks/heretic.cbp b/codeblocks/heretic.cbp
new file mode 100644
index 00000000..0322f7e9
--- /dev/null
+++ b/codeblocks/heretic.cbp
@@ -0,0 +1,444 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<CodeBlocks_project_file>
+ <FileVersion major="1" minor="6" />
+ <Project>
+ <Option title="Heretic" />
+ <Option pch_mode="2" />
+ <Option compiler="gcc" />
+ <Build>
+ <Target title="Debug">
+ <Option output="..\bin\chocolate-heretic-dbg.exe" prefix_auto="0" extension_auto="0" />
+ <Option working_dir="..\bin" />
+ <Option object_output="..\obj\chocolate-heretic\dbg" />
+ <Option type="0" />
+ <Option compiler="gcc" />
+ <Option projectLinkerOptionsRelation="2" />
+ <Compiler>
+ <Add option="-W" />
+ <Add option="-gdwarf-2" />
+ </Compiler>
+ <Linker>
+ <Add option="-lopl-dbg -lpcsound-dbg -ltextscreen-dbg" />
+ </Linker>
+ </Target>
+ <Target title="Release">
+ <Option output="..\bin\chocolate-heretic.exe" prefix_auto="0" extension_auto="0" />
+ <Option working_dir="..\bin" />
+ <Option object_output="..\obj\chocolate-heretic\rel" />
+ <Option type="0" />
+ <Option compiler="gcc" />
+ <Option projectLinkerOptionsRelation="2" />
+ <Compiler>
+ <Add option="-O2" />
+ </Compiler>
+ <Linker>
+ <Add option="-s" />
+ <Add option="-lopl -lpcsound -ltextscreen" />
+ </Linker>
+ </Target>
+ </Build>
+ <VirtualTargets>
+ <Add alias="All" targets="Debug;Release;" />
+ </VirtualTargets>
+ <Compiler>
+ <Add option='-DPROGRAM_PREFIX=&quot;\&quot;chocolate-\&quot;&quot;' />
+ <Add option='-DD_CDROM=&quot;\&quot;CD-ROM Version: default.cfg from c:\\doomdata\n\&quot;&quot;' />
+ <Add directory="." />
+ <Add directory="..\src" />
+ <Add directory="..\src\doom" />
+ <Add directory="..\src\heretic" />
+ <Add directory="..\textscreen" />
+ <Add directory="..\pcsound" />
+ <Add directory="..\opl" />
+ </Compiler>
+ <Linker>
+ <Add option="-lmingw32 -lSDLmain -lSDL -lSDL_mixer -lSDL_net -mwindows" />
+ <Add directory="..\lib" />
+ </Linker>
+ <Unit filename="config.h" />
+ <Unit filename="game-res.rc">
+ <Option compilerVar="WINDRES" />
+ </Unit>
+ <Unit filename="..\src\d_event.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\d_event.h" />
+ <Unit filename="..\src\d_iwad.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\d_iwad.h" />
+ <Unit filename="..\src\d_loop.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\d_loop.h" />
+ <Unit filename="..\src\d_mode.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\d_mode.h" />
+ <Unit filename="..\src\d_ticcmd.h" />
+ <Unit filename="..\src\deh_defs.h" />
+ <Unit filename="..\src\deh_io.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\deh_io.h" />
+ <Unit filename="..\src\deh_main.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\deh_main.h" />
+ <Unit filename="..\src\deh_mapping.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\deh_mapping.h" />
+ <Unit filename="..\src\deh_str.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\deh_str.h" />
+ <Unit filename="..\src\deh_text.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doomfeatures.h" />
+ <Unit filename="..\src\doomkeys.h" />
+ <Unit filename="..\src\doomtype.h" />
+ <Unit filename="..\src\heretic\am_data.h" />
+ <Unit filename="..\src\heretic\am_map.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\am_map.h" />
+ <Unit filename="..\src\heretic\ct_chat.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\ct_chat.h" />
+ <Unit filename="..\src\heretic\d_main.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\d_net.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\deh_ammo.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\deh_frame.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\deh_htext.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\deh_htic.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\deh_htic.h" />
+ <Unit filename="..\src\heretic\deh_sound.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\deh_thing.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\deh_weapon.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\doomdata.h" />
+ <Unit filename="..\src\heretic\doomdef.h" />
+ <Unit filename="..\src\heretic\dstrings.h" />
+ <Unit filename="..\src\heretic\f_finale.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\g_game.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\in_lude.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\info.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\info.h" />
+ <Unit filename="..\src\heretic\m_random.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\m_random.h" />
+ <Unit filename="..\src\heretic\mn_menu.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\p_action.h" />
+ <Unit filename="..\src\heretic\p_ceilng.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\p_doors.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\p_enemy.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\p_floor.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\p_inter.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\p_lights.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\p_local.h" />
+ <Unit filename="..\src\heretic\p_map.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\p_maputl.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\p_mobj.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\p_plats.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\p_pspr.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\p_setup.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\p_sight.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\p_spec.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\p_spec.h" />
+ <Unit filename="..\src\heretic\p_switch.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\p_telept.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\p_tick.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\p_user.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\r_bsp.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\r_data.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\r_draw.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\r_local.h" />
+ <Unit filename="..\src\heretic\r_main.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\r_plane.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\r_segs.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\r_things.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\s_sound.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\s_sound.h" />
+ <Unit filename="..\src\heretic\sb_bar.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\sounds.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\heretic\sounds.h" />
+ <Unit filename="..\src\i_cdmus.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_cdmus.h" />
+ <Unit filename="..\src\i_endoom.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_endoom.h" />
+ <Unit filename="..\src\i_joystick.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_joystick.h" />
+ <Unit filename="..\src\i_main.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_oplmusic.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_pcsound.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_scale.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_scale.h" />
+ <Unit filename="..\src\i_sdlmusic.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_sdlsound.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_sound.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_sound.h" />
+ <Unit filename="..\src\i_swap.h" />
+ <Unit filename="..\src\i_system.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_system.h" />
+ <Unit filename="..\src\i_timer.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_timer.h" />
+ <Unit filename="..\src\i_video.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_video.h" />
+ <Unit filename="..\src\i_videohr.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_videohr.h" />
+ <Unit filename="..\src\icon.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\m_argv.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\m_argv.h" />
+ <Unit filename="..\src\m_bbox.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\m_bbox.h" />
+ <Unit filename="..\src\m_cheat.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\m_cheat.h" />
+ <Unit filename="..\src\m_config.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\m_config.h" />
+ <Unit filename="..\src\m_controls.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\m_controls.h" />
+ <Unit filename="..\src\m_fixed.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\m_fixed.h" />
+ <Unit filename="..\src\m_misc.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\m_misc.h" />
+ <Unit filename="..\src\md5.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\md5.h" />
+ <Unit filename="..\src\memio.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\memio.h" />
+ <Unit filename="..\src\midifile.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\midifile.h" />
+ <Unit filename="..\src\mus2mid.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\mus2mid.h" />
+ <Unit filename="..\src\net_client.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_client.h" />
+ <Unit filename="..\src\net_common.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_common.h" />
+ <Unit filename="..\src\net_dedicated.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_dedicated.h" />
+ <Unit filename="..\src\net_defs.h" />
+ <Unit filename="..\src\net_gui.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_gui.h" />
+ <Unit filename="..\src\net_io.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_io.h" />
+ <Unit filename="..\src\net_loop.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_loop.h" />
+ <Unit filename="..\src\net_packet.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_packet.h" />
+ <Unit filename="..\src\net_query.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_query.h" />
+ <Unit filename="..\src\net_sdl.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_sdl.h" />
+ <Unit filename="..\src\net_server.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_server.h" />
+ <Unit filename="..\src\net_structrw.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_structrw.h" />
+ <Unit filename="..\src\tables.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\tables.h" />
+ <Unit filename="..\src\v_patch.h" />
+ <Unit filename="..\src\v_video.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\v_video.h" />
+ <Unit filename="..\src\w_checksum.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\w_checksum.h" />
+ <Unit filename="..\src\w_file.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\w_file.h" />
+ <Unit filename="..\src\w_file_posix.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\w_file_stdc.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\w_file_win32.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\w_main.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\w_main.h" />
+ <Unit filename="..\src\w_merge.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\w_merge.h" />
+ <Unit filename="..\src\w_wad.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\w_wad.h" />
+ <Unit filename="..\src\z_zone.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\z_zone.h" />
+ <Extensions>
+ <code_completion />
+ <envvars />
+ <debugger />
+ </Extensions>
+ </Project>
+</CodeBlocks_project_file>
diff --git a/codeblocks/game.cbp b/codeblocks/hexen.cbp
index 47b8c67e..00ea3770 100644
--- a/codeblocks/game.cbp
+++ b/codeblocks/hexen.cbp
@@ -2,30 +2,29 @@
<CodeBlocks_project_file>
<FileVersion major="1" minor="6" />
<Project>
- <Option title="chocolate-doom" />
+ <Option title="Hexen" />
<Option pch_mode="2" />
<Option compiler="gcc" />
<Build>
<Target title="Debug">
- <Option output="..\bin\$(PROJECT_NAME)-dbg.exe" prefix_auto="0" extension_auto="0" />
+ <Option output="..\bin\chocolate-hexen-dbg.exe" prefix_auto="0" extension_auto="0" />
<Option working_dir="..\bin" />
- <Option object_output="..\obj\dbg" />
+ <Option object_output="..\obj\chocolate-hexen\dbg" />
<Option type="0" />
<Option compiler="gcc" />
- <Option parameters="-iwad d:\russell\games\doom2\iwad\doom2.wad" />
<Option projectLinkerOptionsRelation="2" />
<Compiler>
<Add option="-W" />
<Add option="-gdwarf-2" />
</Compiler>
<Linker>
- <Add option="-lpcsound-dbg -ltextscreen-dbg" />
+ <Add option="-lopl-dbg -lpcsound-dbg -ltextscreen-dbg" />
</Linker>
</Target>
<Target title="Release">
- <Option output="..\bin\$(PROJECT_NAME).exe" prefix_auto="0" extension_auto="0" />
+ <Option output="..\bin\chocolate-hexen.exe" prefix_auto="0" extension_auto="0" />
<Option working_dir="..\bin" />
- <Option object_output="..\obj\rel" />
+ <Option object_output="..\obj\chocolate-hexen\rel" />
<Option type="0" />
<Option compiler="gcc" />
<Option projectLinkerOptionsRelation="2" />
@@ -34,7 +33,7 @@
</Compiler>
<Linker>
<Add option="-s" />
- <Add option="-lpcsound -ltextscreen" />
+ <Add option="-lopl -lpcsound -ltextscreen" />
</Linker>
</Target>
</Build>
@@ -42,8 +41,12 @@
<Add alias="All" targets="Debug;Release;" />
</VirtualTargets>
<Compiler>
+ <Add option='-DPROGRAM_PREFIX=&quot;\&quot;chocolate-\&quot;&quot;' />
+ <Add option='-DD_CDROM=&quot;\&quot;CD-ROM Version: default.cfg from c:\\doomdata\n\&quot;&quot;' />
<Add directory="." />
<Add directory="..\src" />
+ <Add directory="..\src\doom" />
+ <Add directory="..\src\hexen" />
<Add directory="..\textscreen" />
<Add directory="..\pcsound" />
<Add directory="..\opl" />
@@ -56,142 +59,207 @@
<Unit filename="game-res.rc">
<Option compilerVar="WINDRES" />
</Unit>
- <Unit filename="..\opl\dbopl.c">
+ <Unit filename="..\src\d_event.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\opl\dbopl.h" />
- <Unit filename="..\opl\ioperm_sys.c">
+ <Unit filename="..\src\d_event.h" />
+ <Unit filename="..\src\d_iwad.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\opl\ioperm_sys.h" />
- <Unit filename="..\opl\opl.c">
+ <Unit filename="..\src\d_iwad.h" />
+ <Unit filename="..\src\d_loop.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\opl\opl.h" />
- <Unit filename="..\opl\opl_internal.h" />
- <Unit filename="..\opl\opl_linux.c">
+ <Unit filename="..\src\d_loop.h" />
+ <Unit filename="..\src\d_mode.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\opl\opl_obsd.c">
+ <Unit filename="..\src\d_mode.h" />
+ <Unit filename="..\src\d_ticcmd.h" />
+ <Unit filename="..\src\deh_defs.h" />
+ <Unit filename="..\src\deh_io.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\opl\opl_queue.c">
+ <Unit filename="..\src\deh_io.h" />
+ <Unit filename="..\src\deh_main.h" />
+ <Unit filename="..\src\deh_mapping.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\opl\opl_queue.h" />
- <Unit filename="..\opl\opl_sdl.c">
+ <Unit filename="..\src\deh_mapping.h" />
+ <Unit filename="..\src\deh_str.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\opl\opl_timer.c">
+ <Unit filename="..\src\deh_str.h" />
+ <Unit filename="..\src\doomfeatures.h" />
+ <Unit filename="..\src\doomkeys.h" />
+ <Unit filename="..\src\doomtype.h" />
+ <Unit filename="..\src\hexen\a_action.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\opl\opl_timer.h" />
- <Unit filename="..\opl\opl_win32.c">
+ <Unit filename="..\src\hexen\am_data.h" />
+ <Unit filename="..\src\hexen\am_map.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\am_map.c">
+ <Unit filename="..\src\hexen\am_map.h" />
+ <Unit filename="..\src\hexen\ct_chat.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\am_map.h" />
- <Unit filename="..\src\d_englsh.h" />
- <Unit filename="..\src\d_event.h" />
- <Unit filename="..\src\d_items.c">
+ <Unit filename="..\src\hexen\ct_chat.h" />
+ <Unit filename="..\src\hexen\d_net.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\d_items.h" />
- <Unit filename="..\src\d_iwad.c">
+ <Unit filename="..\src\hexen\f_finale.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\d_iwad.h" />
- <Unit filename="..\src\d_main.c">
+ <Unit filename="..\src\hexen\g_game.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\d_main.h" />
- <Unit filename="..\src\d_net.c">
+ <Unit filename="..\src\hexen\h2_main.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\d_net.h" />
- <Unit filename="..\src\d_player.h" />
- <Unit filename="..\src\d_textur.h" />
- <Unit filename="..\src\d_think.h" />
- <Unit filename="..\src\d_ticcmd.h" />
- <Unit filename="..\src\deh_ammo.c">
+ <Unit filename="..\src\hexen\h2def.h" />
+ <Unit filename="..\src\hexen\i_header.h" />
+ <Unit filename="..\src\hexen\in_lude.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\deh_cheat.c">
+ <Unit filename="..\src\hexen\info.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\deh_defs.h" />
- <Unit filename="..\src\deh_frame.c">
+ <Unit filename="..\src\hexen\info.h" />
+ <Unit filename="..\src\hexen\m_misc.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\deh_io.c">
+ <Unit filename="..\src\hexen\m_random.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\deh_io.h" />
- <Unit filename="..\src\deh_main.c">
+ <Unit filename="..\src\hexen\m_random.h" />
+ <Unit filename="..\src\hexen\mn_menu.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\deh_main.h" />
- <Unit filename="..\src\deh_mapping.c">
+ <Unit filename="..\src\hexen\p_acs.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\deh_mapping.h" />
- <Unit filename="..\src\deh_misc.c">
+ <Unit filename="..\src\hexen\p_anim.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\deh_misc.h" />
- <Unit filename="..\src\deh_ptr.c">
+ <Unit filename="..\src\hexen\p_ceilng.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\deh_sound.c">
+ <Unit filename="..\src\hexen\p_doors.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\deh_text.c">
+ <Unit filename="..\src\hexen\p_enemy.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\deh_thing.c">
+ <Unit filename="..\src\hexen\p_floor.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\deh_weapon.c">
+ <Unit filename="..\src\hexen\p_inter.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\doomdata.h" />
- <Unit filename="..\src\doomdef.c">
+ <Unit filename="..\src\hexen\p_lights.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\doomdef.h" />
- <Unit filename="..\src\doomfeatures.h" />
- <Unit filename="..\src\doomkeys.h" />
- <Unit filename="..\src\doomstat.c">
+ <Unit filename="..\src\hexen\p_local.h" />
+ <Unit filename="..\src\hexen\p_map.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\doomstat.h" />
- <Unit filename="..\src\doomtype.h" />
- <Unit filename="..\src\dstrings.c">
+ <Unit filename="..\src\hexen\p_maputl.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\hexen\p_mobj.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\hexen\p_plats.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\hexen\p_pspr.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\hexen\p_setup.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\hexen\p_sight.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\hexen\p_spec.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\dstrings.h" />
- <Unit filename="..\src\f_finale.c">
+ <Unit filename="..\src\hexen\p_spec.h" />
+ <Unit filename="..\src\hexen\p_switch.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\f_finale.h" />
- <Unit filename="..\src\f_wipe.c">
+ <Unit filename="..\src\hexen\p_telept.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\f_wipe.h" />
- <Unit filename="..\src\g_game.c">
+ <Unit filename="..\src\hexen\p_things.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\g_game.h" />
- <Unit filename="..\src\hu_lib.c">
+ <Unit filename="..\src\hexen\p_tick.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\hu_lib.h" />
- <Unit filename="..\src\hu_stuff.c">
+ <Unit filename="..\src\hexen\p_user.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\hu_stuff.h" />
+ <Unit filename="..\src\hexen\po_man.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\hexen\r_bsp.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\hexen\r_data.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\hexen\r_draw.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\hexen\r_local.h" />
+ <Unit filename="..\src\hexen\r_main.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\hexen\r_plane.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\hexen\r_segs.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\hexen\r_things.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\hexen\s_sound.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\hexen\s_sound.h" />
+ <Unit filename="..\src\hexen\sb_bar.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\hexen\sc_man.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\hexen\sn_sonix.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\hexen\sounds.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\hexen\sounds.h" />
+ <Unit filename="..\src\hexen\st_start.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\hexen\st_start.h" />
+ <Unit filename="..\src\hexen\sv_save.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\hexen\textdefs.h" />
+ <Unit filename="..\src\hexen\xddefs.h" />
+ <Unit filename="..\src\i_cdmus.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_cdmus.h" />
+ <Unit filename="..\src\i_endoom.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_endoom.h" />
<Unit filename="..\src\i_joystick.c">
<Option compilerVar="CC" />
</Unit>
@@ -215,6 +283,10 @@
<Unit filename="..\src\i_sdlsound.c">
<Option compilerVar="CC" />
</Unit>
+ <Unit filename="..\src\i_sound.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_sound.h" />
<Unit filename="..\src\i_swap.h" />
<Unit filename="..\src\i_system.c">
<Option compilerVar="CC" />
@@ -228,10 +300,13 @@
<Option compilerVar="CC" />
</Unit>
<Unit filename="..\src\i_video.h" />
- <Unit filename="..\src\info.c">
+ <Unit filename="..\src\i_videohr.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_videohr.h" />
+ <Unit filename="..\src\icon.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\info.h" />
<Unit filename="..\src\m_argv.c">
<Option compilerVar="CC" />
</Unit>
@@ -248,22 +323,18 @@
<Option compilerVar="CC" />
</Unit>
<Unit filename="..\src\m_config.h" />
- <Unit filename="..\src\m_fixed.c">
+ <Unit filename="..\src\m_controls.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\m_fixed.h" />
- <Unit filename="..\src\m_menu.c">
+ <Unit filename="..\src\m_controls.h" />
+ <Unit filename="..\src\m_fixed.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\src\m_menu.h" />
+ <Unit filename="..\src\m_fixed.h" />
<Unit filename="..\src\m_misc.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="..\src\m_misc.h" />
- <Unit filename="..\src\m_random.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\m_random.h" />
<Unit filename="..\src\md5.c">
<Option compilerVar="CC" />
</Unit>
@@ -325,126 +396,11 @@
<Option compilerVar="CC" />
</Unit>
<Unit filename="..\src\net_structrw.h" />
- <Unit filename="..\src\p_ceilng.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\p_doors.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\p_enemy.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\p_floor.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\p_inter.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\p_inter.h" />
- <Unit filename="..\src\p_lights.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\p_local.h" />
- <Unit filename="..\src\p_map.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\p_maputl.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\p_mobj.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\p_mobj.h" />
- <Unit filename="..\src\p_plats.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\p_pspr.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\p_pspr.h" />
- <Unit filename="..\src\p_saveg.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\p_saveg.h" />
- <Unit filename="..\src\p_setup.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\p_setup.h" />
- <Unit filename="..\src\p_sight.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\p_spec.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\p_spec.h" />
- <Unit filename="..\src\p_switch.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\p_telept.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\p_tick.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\p_tick.h" />
- <Unit filename="..\src\p_user.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\r_bsp.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\r_bsp.h" />
- <Unit filename="..\src\r_data.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\r_data.h" />
- <Unit filename="..\src\r_defs.h" />
- <Unit filename="..\src\r_draw.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\r_draw.h" />
- <Unit filename="..\src\r_local.h" />
- <Unit filename="..\src\r_main.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\r_main.h" />
- <Unit filename="..\src\r_plane.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\r_plane.h" />
- <Unit filename="..\src\r_segs.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\r_segs.h" />
- <Unit filename="..\src\r_sky.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\r_sky.h" />
- <Unit filename="..\src\r_state.h" />
- <Unit filename="..\src\r_things.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\r_things.h" />
- <Unit filename="..\src\s_sound.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\s_sound.h" />
- <Unit filename="..\src\sounds.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\sounds.h" />
- <Unit filename="..\src\st_lib.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\st_lib.h" />
- <Unit filename="..\src\st_stuff.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\st_stuff.h" />
<Unit filename="..\src\tables.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="..\src\tables.h" />
+ <Unit filename="..\src\v_patch.h" />
<Unit filename="..\src\v_video.c">
<Option compilerVar="CC" />
</Unit>
@@ -457,12 +413,19 @@
<Option compilerVar="CC" />
</Unit>
<Unit filename="..\src\w_file.h" />
+ <Unit filename="..\src\w_file_posix.c">
+ <Option compilerVar="CC" />
+ </Unit>
<Unit filename="..\src\w_file_stdc.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="..\src\w_file_win32.c">
<Option compilerVar="CC" />
</Unit>
+ <Unit filename="..\src\w_main.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\w_main.h" />
<Unit filename="..\src\w_merge.c">
<Option compilerVar="CC" />
</Unit>
@@ -471,10 +434,6 @@
<Option compilerVar="CC" />
</Unit>
<Unit filename="..\src\w_wad.h" />
- <Unit filename="..\src\wi_stuff.c">
- <Option compilerVar="CC" />
- </Unit>
- <Unit filename="..\src\wi_stuff.h" />
<Unit filename="..\src\z_zone.c">
<Option compilerVar="CC" />
</Unit>
diff --git a/codeblocks/libopl.cbp b/codeblocks/libopl.cbp
new file mode 100644
index 00000000..a38460d0
--- /dev/null
+++ b/codeblocks/libopl.cbp
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<CodeBlocks_project_file>
+ <FileVersion major="1" minor="6" />
+ <Project>
+ <Option title="libopl" />
+ <Option pch_mode="2" />
+ <Option compiler="gcc" />
+ <Build>
+ <Target title="Debug">
+ <Option output="..\lib\libopl-dbg" prefix_auto="1" extension_auto="1" />
+ <Option working_dir="" />
+ <Option object_output="..\obj\libopl\dbg" />
+ <Option type="2" />
+ <Option compiler="gcc" />
+ <Compiler>
+ <Add option="-gdwarf-2" />
+ </Compiler>
+ </Target>
+ <Target title="Release">
+ <Option output="..\lib\libopl" prefix_auto="1" extension_auto="1" />
+ <Option working_dir="" />
+ <Option object_output="..\obj\libopl\rel" />
+ <Option type="2" />
+ <Option compiler="gcc" />
+ <Compiler>
+ <Add option="-O2" />
+ </Compiler>
+ <Linker>
+ <Add option="-s" />
+ </Linker>
+ </Target>
+ </Build>
+ <VirtualTargets>
+ <Add alias="All" targets="Debug;Release;" />
+ </VirtualTargets>
+ <Compiler>
+ <Add option="-Wall" />
+ <Add directory="." />
+ <Add directory="..\src" />
+ </Compiler>
+ <Linker>
+ <Add option="-lmingw32 -lSDLmain -lSDL -lSDL_mixer -mwindows" />
+ </Linker>
+ <Unit filename="..\opl\dbopl.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\opl\dbopl.h" />
+ <Unit filename="..\opl\ioperm_sys.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\opl\ioperm_sys.h" />
+ <Unit filename="..\opl\opl.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\opl\opl.h" />
+ <Unit filename="..\opl\opl_internal.h" />
+ <Unit filename="..\opl\opl_linux.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\opl\opl_obsd.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\opl\opl_queue.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\opl\opl_queue.h" />
+ <Unit filename="..\opl\opl_sdl.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\opl\opl_timer.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\opl\opl_timer.h" />
+ <Unit filename="..\opl\opl_win32.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Extensions>
+ <code_completion />
+ <envvars />
+ <debugger />
+ </Extensions>
+ </Project>
+</CodeBlocks_project_file>
diff --git a/codeblocks/libpcsound.cbp b/codeblocks/libpcsound.cbp
index 9ae9843b..83a24a08 100644
--- a/codeblocks/libpcsound.cbp
+++ b/codeblocks/libpcsound.cbp
@@ -19,7 +19,7 @@
<Target title="Release">
<Option output="..\lib\libpcsound" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
- <Option object_output="..\obj\libpcsound\release" />
+ <Option object_output="..\obj\libpcsound\rel" />
<Option type="2" />
<Option compiler="gcc" />
<Compiler>
diff --git a/codeblocks/textscreen.cbp b/codeblocks/libtextscreen.cbp
index 8db957b1..acc12fbd 100644
--- a/codeblocks/textscreen.cbp
+++ b/codeblocks/libtextscreen.cbp
@@ -9,7 +9,7 @@
<Target title="Debug">
<Option output="..\lib\libtextscreen-dbg.a" prefix_auto="0" extension_auto="0" />
<Option working_dir="" />
- <Option object_output="..\obj\libtextscreen\debug" />
+ <Option object_output="..\obj\libtextscreen\dbg" />
<Option type="2" />
<Option compiler="gcc" />
<Option createDefFile="1" />
@@ -21,7 +21,7 @@
<Target title="Release">
<Option output="..\lib\libtextscreen.a" prefix_auto="0" extension_auto="0" />
<Option working_dir="" />
- <Option object_output="..\obj\libtextscreen\release" />
+ <Option object_output="..\obj\libtextscreen\rel" />
<Option type="2" />
<Option compiler="gcc" />
<Option createDefFile="1" />
diff --git a/codeblocks/main.workspace b/codeblocks/main.workspace
deleted file mode 100644
index ae56d450..00000000
--- a/codeblocks/main.workspace
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
-<CodeBlocks_workspace_file>
- <Workspace title="chocolate-doom">
- <Project filename="game.cbp" active="1">
- <Depends filename="textscreen.cbp" />
- <Depends filename="libpcsound.cbp" />
- </Project>
- <Project filename="server.cbp" />
- <Project filename="setup.cbp">
- <Depends filename="textscreen.cbp" />
- </Project>
- <Project filename="textscreen.cbp" />
- <Project filename="libpcsound.cbp" />
- </Workspace>
-</CodeBlocks_workspace_file>
diff --git a/codeblocks/server.cbp b/codeblocks/server.cbp
index 28eda97a..8c8adfb8 100644
--- a/codeblocks/server.cbp
+++ b/codeblocks/server.cbp
@@ -2,14 +2,14 @@
<CodeBlocks_project_file>
<FileVersion major="1" minor="6" />
<Project>
- <Option title="chocolate-server" />
+ <Option title="Server" />
<Option pch_mode="2" />
<Option compiler="gcc" />
<Build>
<Target title="Debug">
- <Option output="..\bin\$(PROJECT_NAME)-dbg.exe" prefix_auto="0" extension_auto="0" />
+ <Option output="..\bin\chocolate-server-dbg.exe" prefix_auto="0" extension_auto="0" />
<Option working_dir="..\bin" />
- <Option object_output="..\obj\dbg" />
+ <Option object_output="..\obj\chocolate-server\dbg" />
<Option type="0" />
<Option compiler="gcc" />
<Compiler>
@@ -18,9 +18,9 @@
</Compiler>
</Target>
<Target title="Release">
- <Option output="..\bin\$(PROJECT_NAME).exe" prefix_auto="0" extension_auto="0" />
+ <Option output="..\bin\chocolate-server.exe" prefix_auto="0" extension_auto="0" />
<Option working_dir="..\bin" />
- <Option object_output="..\obj\rel" />
+ <Option object_output="..\obj\chocolate-server\rel" />
<Option type="0" />
<Option compiler="gcc" />
<Compiler>
@@ -45,9 +45,17 @@
<Unit filename="..\src\d_dedicated.c">
<Option compilerVar="CC" />
</Unit>
+ <Unit filename="..\src\d_mode.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\d_mode.h" />
<Unit filename="..\src\i_main.c">
<Option compilerVar="CC" />
</Unit>
+ <Unit filename="..\src\i_system.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_system.h" />
<Unit filename="..\src\i_timer.c">
<Option compilerVar="CC" />
</Unit>
diff --git a/codeblocks/setup-res.rc b/codeblocks/setup-res.rc
index ca791096..6199cfd6 100644
--- a/codeblocks/setup-res.rc
+++ b/codeblocks/setup-res.rc
@@ -3,21 +3,21 @@
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "setup-manifest.xml"
1 VERSIONINFO
-PRODUCTVERSION 1,7,0,0
-FILEVERSION 1,7,0,0
+PRODUCTVERSION 1,99,0,0
+FILEVERSION 1,99,0,0
FILETYPE 1
{
BLOCK "StringFileInfo"
{
BLOCK "040904E4"
{
- VALUE "FileVersion", "1.7.0"
+ VALUE "FileVersion", "1.99.0"
VALUE "FileDescription", "Chocolate-Doom Setup"
VALUE "InternalName", "chocolate-setup"
VALUE "CompanyName", "fraggle@gmail.com"
VALUE "LegalCopyright", "GNU General Public License"
VALUE "ProductName", "Chocolate-Doom Setup"
- VALUE "ProductVersion", "1.7.0"
+ VALUE "ProductVersion", "1.99.0"
}
}
}
diff --git a/codeblocks/setup.cbp b/codeblocks/setup.cbp
index 4cfe39e4..6b25af95 100644
--- a/codeblocks/setup.cbp
+++ b/codeblocks/setup.cbp
@@ -2,14 +2,14 @@
<CodeBlocks_project_file>
<FileVersion major="1" minor="6" />
<Project>
- <Option title="chocolate-setup" />
+ <Option title="Setup" />
<Option pch_mode="2" />
<Option compiler="gcc" />
<Build>
<Target title="Debug">
- <Option output="..\bin\$(PROJECT_NAME)-dbg.exe" prefix_auto="0" extension_auto="0" />
+ <Option output="..\bin\chocolate-setup-dbg.exe" prefix_auto="0" extension_auto="0" />
<Option working_dir="..\bin" />
- <Option object_output="..\obj\dbg\" />
+ <Option object_output="..\obj\chocolate-setup\dbg" />
<Option type="0" />
<Option compiler="gcc" />
<Option projectLinkerOptionsRelation="2" />
@@ -23,9 +23,9 @@
</Linker>
</Target>
<Target title="Release">
- <Option output="..\bin\$(PROJECT_NAME).exe" prefix_auto="0" extension_auto="0" />
+ <Option output="..\bin\chocolate-setup.exe" prefix_auto="0" extension_auto="0" />
<Option working_dir="..\bin" />
- <Option object_output="..\obj\rel\" />
+ <Option object_output="..\obj\chocolate-setup\rel" />
<Option type="0" />
<Option compiler="gcc" />
<Option projectLinkerOptionsRelation="2" />
@@ -44,75 +44,147 @@
<Compiler>
<Add option="-Wall" />
<Add option="-D_WIN32" />
+ <Add option='-DPROGRAM_PREFIX=&quot;\&quot;chocolate-\&quot;&quot;' />
<Add directory="." />
<Add directory="..\src" />
+ <Add directory="..\src\doom" />
<Add directory="..\textscreen" />
</Compiler>
<ResourceCompiler>
- <Add directory="..\setup" />
+ <Add directory="..\src\setup" />
</ResourceCompiler>
<Linker>
- <Add option="-lmingw32 -lSDLmain -lSDL -mwindows" />
+ <Add option="-lmingw32 -lSDLmain -lSDL -lSDL_net -mwindows" />
<Add directory="..\lib" />
</Linker>
<Unit filename="setup-res.rc">
<Option compilerVar="WINDRES" />
+ <Option compile="0" />
+ <Option link="0" />
</Unit>
- <Unit filename="..\setup\compatibility.c">
+ <Unit filename="..\src\d_iwad.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\setup\compatibility.h" />
- <Unit filename="..\setup\configfile.c">
+ <Unit filename="..\src\d_iwad.h" />
+ <Unit filename="..\src\d_mode.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\setup\configfile.h" />
- <Unit filename="..\setup\display.c">
+ <Unit filename="..\src\d_mode.h" />
+ <Unit filename="..\src\deh_str.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\setup\display.h" />
- <Unit filename="..\setup\execute.c">
+ <Unit filename="..\src\deh_str.h" />
+ <Unit filename="..\src\doomtype.h" />
+ <Unit filename="..\src\i_main.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\setup\execute.h" />
- <Unit filename="..\setup\joystick.c">
+ <Unit filename="..\src\i_system.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\setup\joystick.h" />
- <Unit filename="..\setup\keyboard.c">
+ <Unit filename="..\src\i_system.h" />
+ <Unit filename="..\src\i_timer.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\setup\keyboard.h" />
- <Unit filename="..\setup\m_argv.c">
+ <Unit filename="..\src\i_timer.h" />
+ <Unit filename="..\src\m_argv.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\setup\m_argv.h" />
- <Unit filename="..\setup\mainmenu.c">
+ <Unit filename="..\src\m_argv.h" />
+ <Unit filename="..\src\m_config.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\setup\mouse.c">
+ <Unit filename="..\src\m_config.h" />
+ <Unit filename="..\src\m_controls.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\setup\mouse.h" />
- <Unit filename="..\setup\multiplayer.c">
+ <Unit filename="..\src\m_controls.h" />
+ <Unit filename="..\src\m_misc.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\setup\multiplayer.h" />
- <Unit filename="..\setup\sound.c">
+ <Unit filename="..\src\m_misc.h" />
+ <Unit filename="..\src\net_defs.h" />
+ <Unit filename="..\src\net_io.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\setup\sound.h" />
- <Unit filename="..\setup\txt_joybinput.c">
+ <Unit filename="..\src\net_io.h" />
+ <Unit filename="..\src\net_loop.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\setup\txt_joybinput.h" />
- <Unit filename="..\setup\txt_keyinput.c">
+ <Unit filename="..\src\net_loop.h" />
+ <Unit filename="..\src\net_packet.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\setup\txt_keyinput.h" />
- <Unit filename="..\setup\txt_mouseinput.c">
+ <Unit filename="..\src\net_packet.h" />
+ <Unit filename="..\src\net_query.c">
<Option compilerVar="CC" />
</Unit>
- <Unit filename="..\setup\txt_mouseinput.h" />
+ <Unit filename="..\src\net_query.h" />
+ <Unit filename="..\src\net_sdl.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_sdl.h" />
+ <Unit filename="..\src\net_structrw.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_structrw.h" />
+ <Unit filename="..\src\setup\compatibility.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\setup\compatibility.h" />
+ <Unit filename="..\src\setup\display.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\setup\display.h" />
+ <Unit filename="..\src\setup\execute.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\setup\execute.h" />
+ <Unit filename="..\src\setup\joystick.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\setup\joystick.h" />
+ <Unit filename="..\src\setup\keyboard.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\setup\keyboard.h" />
+ <Unit filename="..\src\setup\mainmenu.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\setup\mode.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\setup\mode.h" />
+ <Unit filename="..\src\setup\mouse.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\setup\mouse.h" />
+ <Unit filename="..\src\setup\multiplayer.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\setup\multiplayer.h" />
+ <Unit filename="..\src\setup\setup_icon.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\setup\sound.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\setup\sound.h" />
+ <Unit filename="..\src\setup\txt_joybinput.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\setup\txt_joybinput.h" />
+ <Unit filename="..\src\setup\txt_keyinput.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\setup\txt_keyinput.h" />
+ <Unit filename="..\src\setup\txt_mouseinput.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\setup\txt_mouseinput.h" />
+ <Unit filename="..\src\z_native.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\z_zone.h" />
<Extensions>
<code_completion />
<envvars />
diff --git a/codeblocks/strife.cbp b/codeblocks/strife.cbp
new file mode 100644
index 00000000..55a03fe5
--- /dev/null
+++ b/codeblocks/strife.cbp
@@ -0,0 +1,515 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<CodeBlocks_project_file>
+ <FileVersion major="1" minor="6" />
+ <Project>
+ <Option title="Strife" />
+ <Option pch_mode="2" />
+ <Option compiler="gcc" />
+ <Build>
+ <Target title="Debug">
+ <Option output="..\bin\chocolate-strife-dbg.exe" prefix_auto="0" extension_auto="0" />
+ <Option working_dir="..\bin" />
+ <Option object_output="..\obj\chocolate-strife\dbg" />
+ <Option type="0" />
+ <Option compiler="gcc" />
+ <Option projectLinkerOptionsRelation="2" />
+ <Compiler>
+ <Add option="-W" />
+ <Add option="-gdwarf-2" />
+ </Compiler>
+ <Linker>
+ <Add option="-lopl-dbg -lpcsound-dbg -ltextscreen-dbg" />
+ </Linker>
+ </Target>
+ <Target title="Release">
+ <Option output="..\bin\chocolate-strife.exe" prefix_auto="0" extension_auto="0" />
+ <Option working_dir="..\bin" />
+ <Option object_output="..\obj\chocolate-strife\rel" />
+ <Option type="0" />
+ <Option compiler="gcc" />
+ <Option projectLinkerOptionsRelation="2" />
+ <Compiler>
+ <Add option="-O2" />
+ </Compiler>
+ <Linker>
+ <Add option="-s" />
+ <Add option="-lopl -lpcsound -ltextscreen" />
+ </Linker>
+ </Target>
+ </Build>
+ <VirtualTargets>
+ <Add alias="All" targets="Debug;Release;" />
+ </VirtualTargets>
+ <Compiler>
+ <Add option='-DPROGRAM_PREFIX=&quot;\&quot;chocolate-\&quot;&quot;' />
+ <Add option='-DD_CDROM=&quot;\&quot;CD-ROM Version: default.cfg from c:\\doomdata\n\&quot;&quot;' />
+ <Add directory="." />
+ <Add directory="..\src" />
+ <Add directory="..\src\doom" />
+ <Add directory="..\src\heretic" />
+ <Add directory="..\textscreen" />
+ <Add directory="..\pcsound" />
+ <Add directory="..\opl" />
+ </Compiler>
+ <Linker>
+ <Add option="-lmingw32 -lSDLmain -lSDL -lSDL_mixer -lSDL_net -mwindows" />
+ <Add directory="..\lib" />
+ </Linker>
+ <Unit filename="config.h" />
+ <Unit filename="game-res.rc">
+ <Option compilerVar="WINDRES" />
+ </Unit>
+ <Unit filename="..\src\d_event.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\d_event.h" />
+ <Unit filename="..\src\d_iwad.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\d_iwad.h" />
+ <Unit filename="..\src\d_loop.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\d_loop.h" />
+ <Unit filename="..\src\d_mode.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\d_mode.h" />
+ <Unit filename="..\src\d_ticcmd.h" />
+ <Unit filename="..\src\deh_defs.h" />
+ <Unit filename="..\src\deh_io.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\deh_io.h" />
+ <Unit filename="..\src\deh_main.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\deh_main.h" />
+ <Unit filename="..\src\deh_mapping.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\deh_mapping.h" />
+ <Unit filename="..\src\deh_str.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\deh_str.h" />
+ <Unit filename="..\src\deh_text.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\doomfeatures.h" />
+ <Unit filename="..\src\doomkeys.h" />
+ <Unit filename="..\src\doomtype.h" />
+ <Unit filename="..\src\i_cdmus.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_cdmus.h" />
+ <Unit filename="..\src\i_endoom.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_endoom.h" />
+ <Unit filename="..\src\i_joystick.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_joystick.h" />
+ <Unit filename="..\src\i_main.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_oplmusic.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_pcsound.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_scale.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_scale.h" />
+ <Unit filename="..\src\i_sdlmusic.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_sdlsound.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_sound.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_sound.h" />
+ <Unit filename="..\src\i_swap.h" />
+ <Unit filename="..\src\i_system.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_system.h" />
+ <Unit filename="..\src\i_timer.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_timer.h" />
+ <Unit filename="..\src\i_video.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_video.h" />
+ <Unit filename="..\src\i_videohr.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\i_videohr.h" />
+ <Unit filename="..\src\icon.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\m_argv.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\m_argv.h" />
+ <Unit filename="..\src\m_bbox.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\m_bbox.h" />
+ <Unit filename="..\src\m_cheat.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\m_cheat.h" />
+ <Unit filename="..\src\m_config.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\m_config.h" />
+ <Unit filename="..\src\m_controls.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\m_controls.h" />
+ <Unit filename="..\src\m_fixed.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\m_fixed.h" />
+ <Unit filename="..\src\m_misc.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\m_misc.h" />
+ <Unit filename="..\src\md5.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\md5.h" />
+ <Unit filename="..\src\memio.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\memio.h" />
+ <Unit filename="..\src\midifile.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\midifile.h" />
+ <Unit filename="..\src\mus2mid.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\mus2mid.h" />
+ <Unit filename="..\src\net_client.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_client.h" />
+ <Unit filename="..\src\net_common.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_common.h" />
+ <Unit filename="..\src\net_dedicated.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_dedicated.h" />
+ <Unit filename="..\src\net_defs.h" />
+ <Unit filename="..\src\net_gui.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_gui.h" />
+ <Unit filename="..\src\net_io.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_io.h" />
+ <Unit filename="..\src\net_loop.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_loop.h" />
+ <Unit filename="..\src\net_packet.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_packet.h" />
+ <Unit filename="..\src\net_query.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_query.h" />
+ <Unit filename="..\src\net_sdl.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_sdl.h" />
+ <Unit filename="..\src\net_server.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_server.h" />
+ <Unit filename="..\src\net_structrw.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\net_structrw.h" />
+ <Unit filename="..\src\strife\am_map.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\am_map.h" />
+ <Unit filename="..\src\strife\d_englsh.h" />
+ <Unit filename="..\src\strife\d_items.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\d_items.h" />
+ <Unit filename="..\src\strife\d_main.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\d_main.h" />
+ <Unit filename="..\src\strife\d_net.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\d_net.h" />
+ <Unit filename="..\src\strife\d_player.h" />
+ <Unit filename="..\src\strife\d_textur.h" />
+ <Unit filename="..\src\strife\d_think.h" />
+ <Unit filename="..\src\strife\deh_ammo.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\deh_cheat.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\deh_frame.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\deh_misc.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\deh_misc.h" />
+ <Unit filename="..\src\strife\deh_ptr.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\deh_sound.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\deh_strife.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\deh_thing.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\deh_weapon.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\doomdata.h" />
+ <Unit filename="..\src\strife\doomdef.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\doomdef.h" />
+ <Unit filename="..\src\strife\doomstat.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\doomstat.h" />
+ <Unit filename="..\src\strife\dstrings.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\dstrings.h" />
+ <Unit filename="..\src\strife\f_finale.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\f_finale.h" />
+ <Unit filename="..\src\strife\f_wipe.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\f_wipe.h" />
+ <Unit filename="..\src\strife\g_game.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\g_game.h" />
+ <Unit filename="..\src\strife\hu_lib.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\hu_lib.h" />
+ <Unit filename="..\src\strife\hu_stuff.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\hu_stuff.h" />
+ <Unit filename="..\src\strife\info.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\info.h" />
+ <Unit filename="..\src\strife\m_menu.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\m_menu.h" />
+ <Unit filename="..\src\strife\m_random.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\m_random.h" />
+ <Unit filename="..\src\strife\m_saves.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\m_saves.h" />
+ <Unit filename="..\src\strife\p_ceilng.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\p_dialog.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\p_dialog.h" />
+ <Unit filename="..\src\strife\p_doors.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\p_enemy.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\p_floor.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\p_inter.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\p_inter.h" />
+ <Unit filename="..\src\strife\p_lights.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\p_local.h" />
+ <Unit filename="..\src\strife\p_map.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\p_maputl.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\p_mobj.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\p_mobj.h" />
+ <Unit filename="..\src\strife\p_plats.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\p_pspr.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\p_pspr.h" />
+ <Unit filename="..\src\strife\p_saveg.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\p_saveg.h" />
+ <Unit filename="..\src\strife\p_setup.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\p_setup.h" />
+ <Unit filename="..\src\strife\p_sight.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\p_spec.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\p_spec.h" />
+ <Unit filename="..\src\strife\p_switch.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\p_telept.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\p_tick.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\p_tick.h" />
+ <Unit filename="..\src\strife\p_user.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\r_bsp.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\r_bsp.h" />
+ <Unit filename="..\src\strife\r_data.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\r_data.h" />
+ <Unit filename="..\src\strife\r_defs.h" />
+ <Unit filename="..\src\strife\r_draw.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\r_draw.h" />
+ <Unit filename="..\src\strife\r_local.h" />
+ <Unit filename="..\src\strife\r_main.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\r_main.h" />
+ <Unit filename="..\src\strife\r_plane.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\r_plane.h" />
+ <Unit filename="..\src\strife\r_segs.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\r_segs.h" />
+ <Unit filename="..\src\strife\r_sky.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\r_sky.h" />
+ <Unit filename="..\src\strife\r_state.h" />
+ <Unit filename="..\src\strife\r_things.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\r_things.h" />
+ <Unit filename="..\src\strife\s_sound.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\s_sound.h" />
+ <Unit filename="..\src\strife\sounds.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\sounds.h" />
+ <Unit filename="..\src\strife\st_lib.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\st_lib.h" />
+ <Unit filename="..\src\strife\st_stuff.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\st_stuff.h" />
+ <Unit filename="..\src\strife\wi_stuff.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\strife\wi_stuff.h" />
+ <Unit filename="..\src\tables.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\tables.h" />
+ <Unit filename="..\src\v_patch.h" />
+ <Unit filename="..\src\v_video.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\v_video.h" />
+ <Unit filename="..\src\w_checksum.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\w_checksum.h" />
+ <Unit filename="..\src\w_file.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\w_file.h" />
+ <Unit filename="..\src\w_file_posix.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\w_file_stdc.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\w_file_win32.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\w_main.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\w_main.h" />
+ <Unit filename="..\src\w_merge.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\w_merge.h" />
+ <Unit filename="..\src\w_wad.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\w_wad.h" />
+ <Unit filename="..\src\z_zone.c">
+ <Option compilerVar="CC" />
+ </Unit>
+ <Unit filename="..\src\z_zone.h" />
+ <Extensions>
+ <code_completion />
+ <envvars />
+ <debugger />
+ </Extensions>
+ </Project>
+</CodeBlocks_project_file>
diff --git a/configure.in b/configure.in
index 175a355f..77a7e6e9 100644
--- a/configure.in
+++ b/configure.in
@@ -1,4 +1,4 @@
-AC_INIT(Chocolate Doom, 1.7.0, fraggle@gmail.com, chocolate-doom)
+AC_INIT(Chocolate Doom, 1.99.0, fraggle@gmail.com, chocolate-doom)
PACKAGE_SHORTDESC="Conservative Doom source port"
PACKAGE_COPYRIGHT="Copyright (C) 1993-2012"
@@ -27,7 +27,8 @@ AC_ARG_ENABLE(penis-extension,
if test "$GCC" = "yes"
then
- CFLAGS="-O$OPT_LEVEL -g -Wall $orig_CFLAGS"
+ WARNINGS="-Wall -Wdeclaration-after-statement -Wredundant-decls"
+ CFLAGS="-O$OPT_LEVEL -g $WARNINGS $orig_CFLAGS"
fi
dnl Search for SDL ...
@@ -95,7 +96,7 @@ WINDOWS_CE=false
case "$host" in
*mingw32ce*|*cegcc*|*wince*)
- CFLAGS="-I../wince $CFLAGS"
+ CFLAGS="-I\$(top_builddir)/wince $CFLAGS"
WINDOWS_CE=true
;;
*)
@@ -145,24 +146,28 @@ AC_DEFUN([AC_DATAROOTDIR_CHECKED])
AC_OUTPUT([
Makefile
-rpm.spec
man/Makefile
opl/Makefile
opl/examples/Makefile
pcsound/Makefile
pkg/Makefile
pkg/config.make
-pkg/osx/Info.plist
pkg/osx/Info-gnustep.plist
-setup/Makefile
-setup/setup.desktop
-setup/setup-res.rc
-setup/setup-manifest.xml
+pkg/osx/Info.plist
+rpm.spec
data/Makefile
src/Makefile
src/doom.desktop
src/doom-screensaver.desktop
+src/doom/Makefile
+src/heretic/Makefile
+src/hexen/Makefile
src/resource.rc
+src/setup-res.rc
+src/setup/Makefile
+src/setup/setup.desktop
+src/setup/setup-manifest.xml
+src/strife/Makefile
textscreen/Makefile
textscreen/examples/Makefile
wince/Makefile
diff --git a/man/Makefile.am b/man/Makefile.am
index 618c0bde..1be69258 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -5,22 +5,76 @@ docdir=$(prefix)/share/doc/@PACKAGE@
if HAVE_PYTHON
-man_MANS=chocolate-doom.6 \
- chocolate-server.6 \
- chocolate-setup.6 \
- default.cfg.5 \
- $(PACKAGE).cfg.5
+man_MANS=chocolate-server.6 \
+ chocolate-setup.6 \
+ chocolate-doom.6 \
+ default.cfg.5 \
+ chocolate-doom.cfg.5 \
+ chocolate-heretic.6 \
+ heretic.cfg.5 \
+ chocolate-heretic.cfg.5 \
+ chocolate-hexen.6 \
+ hexen.cfg.5 \
+ chocolate-hexen.cfg.5 \
+ chocolate-strife.6 \
+ strife.cfg.5 \
+ chocolate-strife.cfg.5
nodist_doc_DATA=INSTALL
+
+
chocolate-doom.6: ../src $(MANPAGE_GEN_FILES)
- ./docgen -m manpage.template ../src > $@
+ ./docgen -g doom -m manpage.template ../src ../src/doom > $@
default.cfg.5: ../src default.cfg.template
- ./docgen -m default.cfg.template -c default.cfg ../src > $@
+ ./docgen -g doom -m default.cfg.template \
+ -c default ../src/m_config.c > $@
+
+chocolate-doom.cfg.5: ../src extra.cfg.template
+ ./docgen -g doom -m extra.cfg.template \
+ -c extended ../src/m_config.c > $@
+
+
+
+chocolate-heretic.6: ../src $(MANPAGE_GEN_FILES)
+ ./docgen -g heretic -m manpage.template ../src ../src/heretic > $@
+
+heretic.cfg.5: ../src default.cfg.template
+ ./docgen -g heretic -m default.cfg.template \
+ -c default ../src/m_config.c > $@
+
+chocolate-heretic.cfg.5: ../src extra.cfg.template
+ ./docgen -g heretic -m extra.cfg.template \
+ -c extended ../src/m_config.c > $@
+
+
+
+chocolate-hexen.6: ../src $(MANPAGE_GEN_FILES)
+ ./docgen -g hexen -m manpage.template ../src ../src/hexen > $@
+
+hexen.cfg.5: ../src default.cfg.template
+ ./docgen -g hexen -m default.cfg.template \
+ -c default ../src/m_config.c > $@
+
+chocolate-hexen.cfg.5: ../src extra.cfg.template
+ ./docgen -g hexen -m extra.cfg.template \
+ -c extended ../src/m_config.c > $@
+
+
+
+chocolate-strife.6: ../src $(MANPAGE_GEN_FILES)
+ ./docgen -g strife -m manpage.template ../src ../src/strife > $@
+
+strife.cfg.5: ../src default.cfg.template
+ ./docgen -g strife -m default.cfg.template \
+ -c default ../src/m_config.c > $@
+
+chocolate-strife.cfg.5: ../src extra.cfg.template
+ ./docgen -g strife -m extra.cfg.template \
+ -c extended ../src/m_config.c > $@
+
-$(PACKAGE).cfg.5: ../src extra.cfg.template
- ./docgen -m extra.cfg.template -c $(PACKAGE).cfg ../src > $@
INSTALL: INSTALL.template
./simplecpp -DPRECOMPILED < INSTALL.template > $@
diff --git a/man/docgen b/man/docgen
index 3016dc5a..219895a2 100755
--- a/man/docgen
+++ b/man/docgen
@@ -19,7 +19,7 @@
#
# For configuration file values:
#
-# //! @begin_config_file myconfig.cfg
+# //! @begin_config_file myconfig
#
# //!
# // Description of the configuration file value.
@@ -160,6 +160,7 @@ class Parameter:
self.platform = None
self.category = None
self.vanilla_option = False
+ self.games = None
def should_show(self):
return not self.vanilla_option or show_vanilla_options
@@ -184,12 +185,21 @@ class Parameter:
self.category = data
elif option_type == "vanilla":
self.vanilla_option = True
+ elif option_type == "game":
+ self.games = re.split(r'\s+', data.strip())
else:
raise "Unknown option type '%s'" % option_type
else:
self.text += text + " "
+ def _games_only_text(self, pattern="(%s only)"):
+ if not match_game and self.games:
+ games_list = ", ".join(map(str.capitalize, self.games))
+ return " " + (pattern % games_list)
+ else:
+ return ""
+
def manpage_output(self):
result = self.name
@@ -205,7 +215,7 @@ class Parameter:
escaped = re.sub('\\\\', '\\\\\\\\', self.text)
- result += escaped + "\n"
+ result += escaped + self._games_only_text() + "\n"
return result
@@ -221,6 +231,7 @@ class Parameter:
if self.platform:
result += "'''(%s only)'''" % self.platform
+ result += self._games_only_text("'''(%s only)'''")
return result
@@ -243,6 +254,8 @@ class Parameter:
if self.platform:
description += " (%s only)" % self.platform
+ description += self._games_only_text()
+
# Build the complete text for the argument
# Split the description into words and add a word at a time
@@ -291,18 +304,25 @@ def add_wiki_links(text):
def add_parameter(param, line, config_file):
+ # If we're only targeting a particular game, check this is one of
+ # the ones we're targeting.
+
+ if match_game and param.games and match_game not in param.games:
+ return
+
# Is this documenting a command line parameter?
- match = re.search('M_CheckParm(WithArgs)?\s*\(\s*"(.*?)"', line)
+ match = re.search('(M_CheckParm(WithArgs)|M_ParmExists)?\s*\(\s*"(.*?)"',
+ line)
if match:
- param.name = match.group(2)
+ param.name = match.group(3)
categories[param.category].add_param(param)
return
# Documenting a configuration file variable?
- match = re.search('CONFIG_VARIABLE_\S+\s*\(\s*(\S+?),', line)
+ match = re.search('CONFIG_VARIABLE_\S+\s*\(\s*(\S+?)\),', line)
if match:
param.name = match.group(1)
@@ -357,9 +377,9 @@ def process_file(file):
if match:
# Beginning a configuration file
- filename = match.group(1)
- current_config_file = ConfigFile(filename)
- config_files[filename] = current_config_file
+ tagname = match.group(1)
+ current_config_file = ConfigFile(tagname)
+ config_files[tagname] = current_config_file
else:
# Start of a normal comment
param = Parameter()
@@ -367,18 +387,18 @@ def process_file(file):
finally:
f.close()
-def process_files(dir):
+def process_files(path):
# Process all C source files.
- if os.path.isdir(dir):
- files = glob.glob(dir + "/*.c")
+ if os.path.isdir(path):
+ files = glob.glob(path + "/*.c")
for file in files:
process_file(file)
else:
# Special case to allow a single file to be specified as a target
- process_file(dir)
+ process_file(path)
def print_template(template_file, content):
f = open(template_file)
@@ -416,22 +436,25 @@ def plaintext_output(targets, template_file):
print_template(template_file, content)
def usage():
- print("Usage: %s [-V] [-c filename ]( -m | -w | -p ) <directory>" \
+ print("Usage: %s [-V] [-c tag] [-g game] ( -m | -w | -p ) <dir>..." \
% sys.argv[0])
print(" -c : Provide documentation for the specified configuration file")
+ print(" (matches the given tag name in the source file)")
print(" -m : Manpage output")
print(" -w : Wikitext output")
print(" -p : Plaintext output")
print(" -V : Don't show Vanilla Doom options")
+ print(" -g : Only document options for specified game.")
sys.exit(0)
# Parse command line
-opts, args = getopt.getopt(sys.argv[1:], "m:wp:c:V")
+opts, args = getopt.getopt(sys.argv[1:], "m:wp:c:g:V")
output_function = None
template = None
doc_config_file = None
+match_game = None
for opt in opts:
if opt[0] == "-m":
@@ -446,14 +469,16 @@ for opt in opts:
show_vanilla_options = False
elif opt[0] == "-c":
doc_config_file = opt[1]
+ elif opt[0] == "-g":
+ match_game = opt[1]
-if output_function == None or len(args) != 1:
+if output_function == None or len(args) < 1:
usage()
else:
-
# Process specified files
- process_files(args[0])
+ for path in args:
+ process_files(path)
# Build a list of things to document
diff --git a/msvc/.gitignore b/msvc/.gitignore
new file mode 100644
index 00000000..47e8226e
--- /dev/null
+++ b/msvc/.gitignore
@@ -0,0 +1,7 @@
+*.cfg
+*.ncb
+*.suo
+*.user
+savegames
+strfsav*
+*.pcx
diff --git a/msvc/ChocolateDoom.sln b/msvc/ChocolateDoom.sln
deleted file mode 100644
index b1ea0e67..00000000
--- a/msvc/ChocolateDoom.sln
+++ /dev/null
@@ -1,32 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 10.00
-# Visual C++ Express 2008
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Chocolate Doom", "ChocolateDoom.vcproj", "{8B744A3B-8F18-41A0-85A3-293816E85B6E}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug Client|Win32 = Debug Client|Win32
- Debug Server|Win32 = Debug Server|Win32
- Debug Setup|Win32 = Debug Setup|Win32
- Release Client|Win32 = Release Client|Win32
- Release Server|Win32 = Release Server|Win32
- Release Setup|Win32 = Release Setup|Win32
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {8B744A3B-8F18-41A0-85A3-293816E85B6E}.Debug Client|Win32.ActiveCfg = Debug|Win32
- {8B744A3B-8F18-41A0-85A3-293816E85B6E}.Debug Client|Win32.Build.0 = Debug|Win32
- {8B744A3B-8F18-41A0-85A3-293816E85B6E}.Debug Server|Win32.ActiveCfg = Debug Server|Win32
- {8B744A3B-8F18-41A0-85A3-293816E85B6E}.Debug Server|Win32.Build.0 = Debug Server|Win32
- {8B744A3B-8F18-41A0-85A3-293816E85B6E}.Debug Setup|Win32.ActiveCfg = Debug Setup|Win32
- {8B744A3B-8F18-41A0-85A3-293816E85B6E}.Debug Setup|Win32.Build.0 = Debug Setup|Win32
- {8B744A3B-8F18-41A0-85A3-293816E85B6E}.Release Client|Win32.ActiveCfg = Release|Win32
- {8B744A3B-8F18-41A0-85A3-293816E85B6E}.Release Client|Win32.Build.0 = Release|Win32
- {8B744A3B-8F18-41A0-85A3-293816E85B6E}.Release Server|Win32.ActiveCfg = Release Server|Win32
- {8B744A3B-8F18-41A0-85A3-293816E85B6E}.Release Server|Win32.Build.0 = Release Server|Win32
- {8B744A3B-8F18-41A0-85A3-293816E85B6E}.Release Setup|Win32.ActiveCfg = Release Setup|Win32
- {8B744A3B-8F18-41A0-85A3-293816E85B6E}.Release Setup|Win32.Build.0 = Release Setup|Win32
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
-EndGlobal
diff --git a/msvc/ChocolateDoom.vcproj b/msvc/ChocolateDoom.vcproj
deleted file mode 100644
index c87da01b..00000000
--- a/msvc/ChocolateDoom.vcproj
+++ /dev/null
@@ -1,10288 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="9.00"
- Name="Chocolate Doom"
- ProjectGUID="{8B744A3B-8F18-41A0-85A3-293816E85B6E}"
- RootNamespace="ChocolateDoom"
- Keyword="Win32Proj"
- TargetFrameworkVersion="196613"
- >
- <Platforms>
- <Platform
- Name="Win32"
- />
- </Platforms>
- <ToolFiles>
- </ToolFiles>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="$(SolutionDir)$(ConfigurationName)"
- IntermediateDirectory="$(ConfigurationName)"
- ConfigurationType="1"
- CharacterSet="0"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories="..\src;..\setup;..\textscreen;..\pcsound;..\msvc;..\opl"
- PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE"
- MinimalRebuild="true"
- BasicRuntimeChecks="3"
- RuntimeLibrary="3"
- StructMemberAlignment="1"
- UsePrecompiledHeader="0"
- ExpandAttributedSource="true"
- AssemblerOutput="2"
- WarningLevel="3"
- DebugInformationFormat="3"
- CompileAs="1"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="SDL.lib SDL_mixer.lib SDL_net.lib SDLmain.lib"
- OutputFile="$(OutDir)\chocolate-doom-debug.exe"
- LinkIncremental="2"
- GenerateDebugInformation="true"
- SubSystem="1"
- DataExecutionPrevention="0"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="$(SolutionDir)$(ConfigurationName)"
- IntermediateDirectory="$(ConfigurationName)"
- ConfigurationType="1"
- CharacterSet="0"
- WholeProgramOptimization="0"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- EnableIntrinsicFunctions="true"
- AdditionalIncludeDirectories="..\src;..\setup;..\textscreen;..\pcsound;..\msvc;..\opl"
- PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE"
- RuntimeLibrary="2"
- StructMemberAlignment="1"
- EnableFunctionLevelLinking="true"
- UsePrecompiledHeader="0"
- WarningLevel="3"
- DebugInformationFormat="3"
- CompileAs="1"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="SDL.lib SDL_mixer.lib SDL_net.lib SDLmain.lib"
- OutputFile="$(OutDir)\chocolate-doom.exe"
- LinkIncremental="1"
- GenerateDebugInformation="true"
- SubSystem="1"
- OptimizeReferences="2"
- EnableCOMDATFolding="2"
- DataExecutionPrevention="0"
- TurnOffAssemblyGeneration="false"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="Debug Server|Win32"
- OutputDirectory="$(SolutionDir)$(ConfigurationName)"
- IntermediateDirectory="$(ConfigurationName)"
- ConfigurationType="1"
- CharacterSet="0"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories="..\src;..\setup;..\textscreen;..\pcsound;..\msvc"
- PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE"
- MinimalRebuild="true"
- BasicRuntimeChecks="3"
- RuntimeLibrary="3"
- StructMemberAlignment="1"
- UsePrecompiledHeader="0"
- ExpandAttributedSource="true"
- AssemblerOutput="2"
- WarningLevel="3"
- DebugInformationFormat="3"
- CompileAs="1"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="DEDICATEDSERVER"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="SDL.lib SDL_net.lib SDLmain.lib"
- OutputFile="$(OutDir)\chocolate-server-debug.exe"
- LinkIncremental="2"
- GenerateDebugInformation="true"
- SubSystem="1"
- DataExecutionPrevention="0"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="Release Server|Win32"
- OutputDirectory="$(SolutionDir)$(ConfigurationName)"
- IntermediateDirectory="$(ConfigurationName)"
- ConfigurationType="1"
- CharacterSet="0"
- WholeProgramOptimization="0"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- EnableIntrinsicFunctions="true"
- AdditionalIncludeDirectories="..\src;..\setup;..\textscreen;..\pcsound;..\msvc"
- PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE"
- RuntimeLibrary="2"
- StructMemberAlignment="1"
- EnableFunctionLevelLinking="true"
- UsePrecompiledHeader="0"
- WarningLevel="3"
- DebugInformationFormat="3"
- CompileAs="1"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="DEDICATEDSERVER"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="SDL.lib SDL_net.lib SDLmain.lib"
- OutputFile="$(OutDir)\chocolate-server.exe"
- LinkIncremental="1"
- GenerateDebugInformation="true"
- SubSystem="1"
- OptimizeReferences="2"
- EnableCOMDATFolding="2"
- DataExecutionPrevention="0"
- TurnOffAssemblyGeneration="false"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="Debug Setup|Win32"
- OutputDirectory="$(SolutionDir)$(ConfigurationName)"
- IntermediateDirectory="$(ConfigurationName)"
- ConfigurationType="1"
- CharacterSet="0"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories="..\src;..\setup;..\textscreen;..\pcsound;..\msvc"
- PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE"
- MinimalRebuild="true"
- BasicRuntimeChecks="3"
- RuntimeLibrary="3"
- StructMemberAlignment="1"
- UsePrecompiledHeader="0"
- ExpandAttributedSource="true"
- AssemblerOutput="2"
- WarningLevel="3"
- DebugInformationFormat="3"
- CompileAs="1"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="CHOCOLATESETUP"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="SDL.lib SDLmain.lib"
- OutputFile="$(OutDir)\chocolate-setup-debug.exe"
- LinkIncremental="2"
- GenerateDebugInformation="true"
- SubSystem="1"
- DataExecutionPrevention="0"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="Release Setup|Win32"
- OutputDirectory="$(SolutionDir)$(ConfigurationName)"
- IntermediateDirectory="$(ConfigurationName)"
- ConfigurationType="1"
- CharacterSet="0"
- WholeProgramOptimization="0"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- EnableIntrinsicFunctions="true"
- AdditionalIncludeDirectories="..\src;..\setup;..\textscreen;..\pcsound;..\msvc"
- PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE"
- RuntimeLibrary="2"
- StructMemberAlignment="1"
- EnableFunctionLevelLinking="true"
- UsePrecompiledHeader="0"
- WarningLevel="3"
- DebugInformationFormat="3"
- CompileAs="1"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="CHOCOLATESETUP"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="SDL.lib SDLmain.lib"
- OutputFile="$(OutDir)\chocolate-setup.exe"
- LinkIncremental="1"
- GenerateDebugInformation="true"
- SubSystem="1"
- OptimizeReferences="2"
- EnableCOMDATFolding="2"
- DataExecutionPrevention="0"
- TurnOffAssemblyGeneration="false"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- </Configurations>
- <References>
- </References>
- <Files>
- <Filter
- Name="Source"
- >
- <File
- RelativePath="..\src\doomdata.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\doomdef.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\doomdef.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\doomfeatures.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\doomkeys.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\doomstat.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\doomstat.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\doomtype.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\dstrings.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\dstrings.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\icon.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\info.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\info.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\md5.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\md5.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\memio.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\memio.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\midifile.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\midifile.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\mus2mid.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\mus2mid.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\sounds.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\sounds.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\tables.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\tables.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <Filter
- Name="am_"
- >
- <File
- RelativePath="..\src\am_map.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\am_map.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="d_"
- >
- <File
- RelativePath="..\src\d_dedicated.c"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\d_englsh.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\d_event.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\d_items.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\d_items.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\d_iwad.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\d_iwad.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\d_main.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\d_main.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\d_net.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\d_net.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\d_player.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\d_textur.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\d_think.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\d_ticcmd.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="deh_"
- >
- <File
- RelativePath="..\src\deh_ammo.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\deh_cheat.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\deh_defs.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\deh_frame.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\deh_io.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\deh_io.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\deh_main.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\deh_main.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\deh_mapping.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\deh_mapping.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\deh_misc.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\deh_misc.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\deh_ptr.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\deh_sound.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\deh_text.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\deh_thing.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\deh_weapon.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="f_"
- >
- <File
- RelativePath="..\src\f_finale.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\f_finale.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\f_wipe.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\f_wipe.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="g_"
- >
- <File
- RelativePath="..\src\g_game.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\g_game.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="hu_"
- >
- <File
- RelativePath="..\src\hu_lib.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\hu_lib.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\hu_stuff.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\hu_stuff.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="i_"
- >
- <File
- RelativePath="..\src\i_joystick.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\i_joystick.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\i_main.c"
- >
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\i_oplmusic.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\i_pcsound.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\i_scale.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\i_scale.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\i_sdlmusic.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\i_sdlsound.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\i_swap.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\i_system.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\i_system.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\i_timer.c"
- >
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\i_timer.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\i_video.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\i_video.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="m_"
- >
- <File
- RelativePath="..\src\m_argv.c"
- >
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\m_argv.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\m_bbox.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\m_bbox.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\m_cheat.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\m_cheat.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\m_config.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\m_config.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\m_fixed.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\m_fixed.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\m_menu.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\m_menu.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\m_misc.c"
- >
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\m_misc.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\m_random.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\m_random.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="net_"
- >
- <File
- RelativePath="..\src\net_client.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\net_client.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\net_common.c"
- >
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\net_common.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\net_dedicated.c"
- >
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\net_dedicated.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\net_defs.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\net_gui.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\net_gui.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\net_io.c"
- >
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\net_io.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\net_loop.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\net_loop.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\net_packet.c"
- >
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\net_packet.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\net_query.c"
- >
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\net_query.h"
- >
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\net_sdl.c"
- >
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\net_sdl.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\net_server.c"
- >
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\net_server.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\net_structrw.c"
- >
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\net_structrw.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="p_"
- >
- <File
- RelativePath="..\src\p_ceilng.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\p_doors.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\p_enemy.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\p_floor.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\p_inter.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\p_inter.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\p_lights.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\p_local.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\p_map.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\p_maputl.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\p_mobj.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\p_mobj.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\p_plats.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\p_pspr.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\p_pspr.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\p_saveg.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\p_saveg.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\p_setup.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\p_setup.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\p_sight.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\p_spec.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\p_spec.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\p_switch.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\p_telept.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\p_tick.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\p_tick.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\p_user.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="r_"
- >
- <File
- RelativePath="..\src\r_bsp.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\r_bsp.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\r_data.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\r_data.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\r_defs.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\r_draw.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\r_draw.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\r_local.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\r_main.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\r_main.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\r_plane.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\r_plane.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\r_segs.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\r_segs.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\r_sky.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\r_sky.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\r_state.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\r_things.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\r_things.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="s_"
- >
- <File
- RelativePath="..\src\s_sound.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\s_sound.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="st_"
- >
- <File
- RelativePath="..\src\st_lib.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\st_lib.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\st_stuff.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\st_stuff.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="v_"
- >
- <File
- RelativePath="..\src\v_video.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\v_video.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="w_"
- >
- <File
- RelativePath="..\src\w_checksum.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\w_checksum.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\w_file.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\w_file.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\w_file_stdc.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\w_file_win32.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\w_merge.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\w_merge.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\w_wad.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\w_wad.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="wi_"
- >
- <File
- RelativePath="..\src\wi_stuff.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\wi_stuff.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="z_"
- >
- <File
- RelativePath="..\src\z_native.c"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\z_zone.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\src\z_zone.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- </Filter>
- </Filter>
- <Filter
- Name="MSVC"
- >
- <File
- RelativePath="..\msvc\config.h"
- >
- </File>
- <File
- RelativePath="..\msvc\inttypes.h"
- >
- </File>
- <File
- RelativePath="..\msvc\stdint.h"
- >
- </File>
- <File
- RelativePath="..\msvc\win32.rc"
- >
- </File>
- </Filter>
- <Filter
- Name="PC Sound"
- >
- <File
- RelativePath="..\pcsound\pcsound.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\pcsound\pcsound.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\pcsound\pcsound_internal.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\pcsound\pcsound_sdl.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\pcsound\pcsound_win32.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="Text Screen"
- >
- <File
- RelativePath="..\textscreen\textscreen.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_button.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_button.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_checkbox.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_checkbox.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_desktop.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_desktop.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_dropdown.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_dropdown.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_font.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_gui.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_gui.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_inputbox.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_inputbox.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_io.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_io.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_label.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_label.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_main.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_radiobutton.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_radiobutton.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_sdl.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_sdl.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_separator.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_separator.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_spinctrl.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_spinctrl.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_strut.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_strut.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_table.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_table.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_widget.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_widget.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_window.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_window.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_window_action.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_window_action.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="Setup"
- >
- <File
- RelativePath="..\setup\compatibility.c"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\setup\compatibility.h"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\setup\configfile.c"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\setup\configfile.h"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\setup\display.c"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\setup\display.h"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\setup\execute.c"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\setup\execute.h"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\setup\joystick.c"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\setup\joystick.h"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\setup\keyboard.c"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\setup\keyboard.h"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\setup\m_argv.c"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\setup\m_argv.h"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\setup\mainmenu.c"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\setup\mouse.c"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\setup\mouse.h"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\setup\multiplayer.c"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\setup\multiplayer.h"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\setup\setup_icon.c"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\setup\sound.c"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\setup\sound.h"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\setup\txt_joybinput.c"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\setup\txt_joybinput.h"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\setup\txt_keyinput.c"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\setup\txt_keyinput.h"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\setup\txt_mouseinput.c"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\setup\txt_mouseinput.h"
- >
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_scrollpane.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\textscreen\txt_scrollpane.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="OPL"
- >
- <File
- RelativePath="..\opl\dbopl.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\opl\dbopl.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\opl\ioperm_sys.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\opl\ioperm_sys.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\opl\opl.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\opl\opl.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\opl\opl_internal.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\opl\opl_queue.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\opl\opl_queue.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\opl\opl_sdl.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\opl\opl_timer.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\opl\opl_timer.h"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCustomBuildTool"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\opl\opl_win32.c"
- >
- <FileConfiguration
- Name="Debug Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Server|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release Setup|Win32"
- ExcludedFromBuild="true"
- >
- <Tool
- Name="VCCLCompilerTool"
- />
- </FileConfiguration>
- </File>
- </Filter>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
diff --git a/msvc/chocolate.sln b/msvc/chocolate.sln
new file mode 100644
index 00000000..2c9cca8b
--- /dev/null
+++ b/msvc/chocolate.sln
@@ -0,0 +1,83 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Doom", "doom.vcproj", "{8B744A3B-8F18-41A0-85A3-293816E85B6E}"
+ ProjectSection(ProjectDependencies) = postProject
+ {66CD7F50-73B9-482F-8B69-1AF54983F845} = {66CD7F50-73B9-482F-8B69-1AF54983F845}
+ {35F435DB-AC4A-4F28-BA2D-812E638FB01A} = {35F435DB-AC4A-4F28-BA2D-812E638FB01A}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Heretic", "heretic.vcproj", "{8D4FF322-7414-4668-94BD-D63B45D9CBF8}"
+ ProjectSection(ProjectDependencies) = postProject
+ {66CD7F50-73B9-482F-8B69-1AF54983F845} = {66CD7F50-73B9-482F-8B69-1AF54983F845}
+ {35F435DB-AC4A-4F28-BA2D-812E638FB01A} = {35F435DB-AC4A-4F28-BA2D-812E638FB01A}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Hexen", "hexen.vcproj", "{8FBB8720-340B-4185-9442-A76781FD6278}"
+ ProjectSection(ProjectDependencies) = postProject
+ {66CD7F50-73B9-482F-8B69-1AF54983F845} = {66CD7F50-73B9-482F-8B69-1AF54983F845}
+ {35F435DB-AC4A-4F28-BA2D-812E638FB01A} = {35F435DB-AC4A-4F28-BA2D-812E638FB01A}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Server", "server.vcproj", "{10DCBB24-F8BB-4796-A653-6DE9C8AAC24B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Setup", "setup.vcproj", "{01975BB6-D2DA-48E7-AE0D-6A8AC8ECF48A}"
+ ProjectSection(ProjectDependencies) = postProject
+ {35F435DB-AC4A-4F28-BA2D-812E638FB01A} = {35F435DB-AC4A-4F28-BA2D-812E638FB01A}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpcsound", "libpcsound.vcproj", "{66CD7F50-73B9-482F-8B69-1AF54983F845}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtextscreen", "libtextscreen.vcproj", "{35F435DB-AC4A-4F28-BA2D-812E638FB01A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Strife", "strife.vcproj", "{FC4DACBA-2A3E-4AF0-804A-AF5FFFD13B08}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libopl", "libopl.vcproj", "{FC8D0610-1507-4F36-99BC-6F5A422B6AD3}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {8B744A3B-8F18-41A0-85A3-293816E85B6E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {8B744A3B-8F18-41A0-85A3-293816E85B6E}.Debug|Win32.Build.0 = Debug|Win32
+ {8B744A3B-8F18-41A0-85A3-293816E85B6E}.Release|Win32.ActiveCfg = Release|Win32
+ {8B744A3B-8F18-41A0-85A3-293816E85B6E}.Release|Win32.Build.0 = Release|Win32
+ {8D4FF322-7414-4668-94BD-D63B45D9CBF8}.Debug|Win32.ActiveCfg = Debug|Win32
+ {8D4FF322-7414-4668-94BD-D63B45D9CBF8}.Debug|Win32.Build.0 = Debug|Win32
+ {8D4FF322-7414-4668-94BD-D63B45D9CBF8}.Release|Win32.ActiveCfg = Release|Win32
+ {8D4FF322-7414-4668-94BD-D63B45D9CBF8}.Release|Win32.Build.0 = Release|Win32
+ {8FBB8720-340B-4185-9442-A76781FD6278}.Debug|Win32.ActiveCfg = Debug|Win32
+ {8FBB8720-340B-4185-9442-A76781FD6278}.Debug|Win32.Build.0 = Debug|Win32
+ {8FBB8720-340B-4185-9442-A76781FD6278}.Release|Win32.ActiveCfg = Release|Win32
+ {8FBB8720-340B-4185-9442-A76781FD6278}.Release|Win32.Build.0 = Release|Win32
+ {10DCBB24-F8BB-4796-A653-6DE9C8AAC24B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {10DCBB24-F8BB-4796-A653-6DE9C8AAC24B}.Debug|Win32.Build.0 = Debug|Win32
+ {10DCBB24-F8BB-4796-A653-6DE9C8AAC24B}.Release|Win32.ActiveCfg = Release|Win32
+ {10DCBB24-F8BB-4796-A653-6DE9C8AAC24B}.Release|Win32.Build.0 = Release|Win32
+ {01975BB6-D2DA-48E7-AE0D-6A8AC8ECF48A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {01975BB6-D2DA-48E7-AE0D-6A8AC8ECF48A}.Debug|Win32.Build.0 = Debug|Win32
+ {01975BB6-D2DA-48E7-AE0D-6A8AC8ECF48A}.Release|Win32.ActiveCfg = Release|Win32
+ {01975BB6-D2DA-48E7-AE0D-6A8AC8ECF48A}.Release|Win32.Build.0 = Release|Win32
+ {66CD7F50-73B9-482F-8B69-1AF54983F845}.Debug|Win32.ActiveCfg = Debug|Win32
+ {66CD7F50-73B9-482F-8B69-1AF54983F845}.Debug|Win32.Build.0 = Debug|Win32
+ {66CD7F50-73B9-482F-8B69-1AF54983F845}.Release|Win32.ActiveCfg = Release|Win32
+ {66CD7F50-73B9-482F-8B69-1AF54983F845}.Release|Win32.Build.0 = Release|Win32
+ {35F435DB-AC4A-4F28-BA2D-812E638FB01A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {35F435DB-AC4A-4F28-BA2D-812E638FB01A}.Debug|Win32.Build.0 = Debug|Win32
+ {35F435DB-AC4A-4F28-BA2D-812E638FB01A}.Release|Win32.ActiveCfg = Release|Win32
+ {35F435DB-AC4A-4F28-BA2D-812E638FB01A}.Release|Win32.Build.0 = Release|Win32
+ {FC4DACBA-2A3E-4AF0-804A-AF5FFFD13B08}.Debug|Win32.ActiveCfg = Debug|Win32
+ {FC4DACBA-2A3E-4AF0-804A-AF5FFFD13B08}.Debug|Win32.Build.0 = Debug|Win32
+ {FC4DACBA-2A3E-4AF0-804A-AF5FFFD13B08}.Release|Win32.ActiveCfg = Release|Win32
+ {FC4DACBA-2A3E-4AF0-804A-AF5FFFD13B08}.Release|Win32.Build.0 = Release|Win32
+ {FC8D0610-1507-4F36-99BC-6F5A422B6AD3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {FC8D0610-1507-4F36-99BC-6F5A422B6AD3}.Debug|Win32.Build.0 = Debug|Win32
+ {FC8D0610-1507-4F36-99BC-6F5A422B6AD3}.Release|Win32.ActiveCfg = Release|Win32
+ {FC8D0610-1507-4F36-99BC-6F5A422B6AD3}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/msvc/config.h b/msvc/config.h
index 9a14d364..183b4504 100644
--- a/msvc/config.h
+++ b/msvc/config.h
@@ -11,19 +11,19 @@
#define PACKAGE_NAME "Chocolate Doom"
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "Chocolate Doom 1.7.0"
+#define PACKAGE_STRING "Chocolate Doom 1.99.0"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "chocolate-doom"
/* Define to the version of this package. */
-#define PACKAGE_VERSION "1.7.0"
+#define PACKAGE_VERSION "1.99.0"
/* Change this when you create your awesome forked version */
#define PROGRAM_PREFIX "chocolate-"
/* Version number of package */
-#define VERSION "1.7.0"
+#define VERSION "1.99.0"
/* Define to 1 if your processor stores words with the most significant byte
first (like Motorola and SPARC, unlike Intel and VAX). */
diff --git a/msvc/doom.vcproj b/msvc/doom.vcproj
new file mode 100644
index 00000000..c5714eea
--- /dev/null
+++ b/msvc/doom.vcproj
@@ -0,0 +1,1019 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="Doom"
+ ProjectGUID="{8B744A3B-8F18-41A0-85A3-293816E85B6E}"
+ RootNamespace="ChocolateDoom"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="..\bin"
+ IntermediateDirectory="..\obj\doom\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=".;..\src;..\src\doom;..\textscreen;..\pcsound"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;PROGRAM_PREFIX=&quot;\&quot;chocolate-\&quot;&quot;"
+ MinimalRebuild="true"
+ ExceptionHandling="0"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ ExpandAttributedSource="true"
+ AssemblerOutput="2"
+ WarningLevel="0"
+ DebugInformationFormat="4"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="SDL.lib SDL_mixer.lib SDL_net.lib SDLmain.lib"
+ OutputFile="$(OutDir)\chocolate-doom-dbg.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="..\bin"
+ IntermediateDirectory="..\obj\doom\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="0"
+ WholeProgramOptimization="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories=".;..\src;..\src\doom;..\textscreen;..\pcsound"
+ PreprocessorDefinitions="WIN32;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;PROGRAM_PREFIX=&quot;\&quot;chocolate-\&quot;&quot;"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="SDL.lib SDL_mixer.lib SDL_net.lib SDLmain.lib"
+ OutputFile="$(OutDir)\chocolate-doom.exe"
+ LinkIncremental="0"
+ GenerateDebugInformation="false"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ LinkTimeCodeGeneration="1"
+ DataExecutionPrevention="0"
+ TurnOffAssemblyGeneration="false"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Header Files"
+ >
+ <File
+ RelativePath="..\src\d_event.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\d_iwad.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\d_mode.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\d_ticcmd.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\deh_str.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doomfeatures.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doomkeys.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doomtype.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_cdmus.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_endoom.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_joystick.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_scale.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_sound.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_swap.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_system.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_timer.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_video.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_argv.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_bbox.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_cheat.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_config.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_controls.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_fixed.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_misc.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\md5.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\memio.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\mus2mid.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_client.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_common.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_dedicated.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_defs.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_gui.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_io.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_loop.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_packet.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_query.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_sdl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_server.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_structrw.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\tables.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\v_patch.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\v_video.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_checksum.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_file.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_merge.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_wad.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\z_zone.h"
+ >
+ </File>
+ <Filter
+ Name="doom"
+ >
+ <File
+ RelativePath="..\src\doom\am_map.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\d_englsh.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\d_items.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\d_main.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\d_net.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\d_player.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\d_textur.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\d_think.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\deh_defs.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\deh_io.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\deh_main.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\deh_mapping.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\deh_misc.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\doomdata.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\doomdef.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\doomstat.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\dstrings.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\f_finale.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\f_wipe.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\g_game.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\hu_lib.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\hu_stuff.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\info.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\m_menu.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\m_random.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\p_inter.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\p_local.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\p_mobj.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\p_pspr.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\p_saveg.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\p_setup.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\p_spec.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\p_tick.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\r_bsp.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\r_data.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\r_defs.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\r_draw.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\r_local.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\r_main.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\r_plane.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\r_segs.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\r_sky.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\r_state.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\r_things.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\s_sound.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\sounds.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\st_lib.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\st_stuff.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\wi_stuff.h"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="Source Files"
+ >
+ <File
+ RelativePath="..\src\d_event.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\d_iwad.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\d_mode.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\deh_str.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_cdmus.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_endoom.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_joystick.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_main.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_pcsound.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_scale.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_sdlmusic.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_sdlsound.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_sound.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_system.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_timer.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_video.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\icon.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_argv.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_bbox.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_cheat.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_config.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_controls.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_fixed.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_misc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\md5.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\memio.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\mus2mid.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_client.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_gui.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_io.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_loop.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_packet.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_query.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_sdl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_server.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_structrw.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\tables.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\v_video.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_checksum.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_file.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_file_posix.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_file_stdc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_file_win32.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_merge.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_wad.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\z_zone.c"
+ >
+ </File>
+ <Filter
+ Name="doom"
+ >
+ <File
+ RelativePath="..\src\doom\am_map.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\d_items.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\d_main.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\d_net.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\deh_ammo.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\deh_cheat.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\deh_frame.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\deh_io.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\deh_main.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\deh_mapping.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\deh_misc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\deh_ptr.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\deh_sound.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\deh_text.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\deh_thing.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\deh_weapon.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\doomdef.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\doomstat.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\dstrings.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\f_finale.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\f_wipe.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\g_game.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\hu_lib.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\hu_stuff.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\info.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\m_menu.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\m_random.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\p_ceilng.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\p_doors.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\p_enemy.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\p_floor.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\p_inter.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\p_lights.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\p_map.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\p_maputl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\p_mobj.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\p_plats.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\p_pspr.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\p_saveg.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\p_setup.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\p_sight.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\p_spec.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\p_switch.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\p_telept.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\p_tick.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\p_user.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\r_bsp.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\r_data.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\r_draw.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\r_main.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\r_plane.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\r_segs.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\r_sky.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\r_things.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\s_sound.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\sounds.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\st_lib.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\st_stuff.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doom\wi_stuff.c"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ >
+ <File
+ RelativePath=".\win32.rc"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/msvc/heretic.vcproj b/msvc/heretic.vcproj
new file mode 100644
index 00000000..e9dbb0dd
--- /dev/null
+++ b/msvc/heretic.vcproj
@@ -0,0 +1,698 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="Heretic"
+ ProjectGUID="{8D4FF322-7414-4668-94BD-D63B45D9CBF8}"
+ RootNamespace="Heretic"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="..\bin"
+ IntermediateDirectory="..\obj\heretic\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=".;..\src;..\src\doom;..\src\heretic;..\textscreen;..\pcsound"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;PROGRAM_PREFIX=&quot;\&quot;chocolate-\&quot;&quot;"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="SDL.lib SDL_mixer.lib SDL_net.lib SDLmain.lib"
+ OutputFile="$(OutDir)\chocolate-heretic-dbg.exe"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="..\bin"
+ IntermediateDirectory="..\obj\heretic\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories=".;..\src;..\src\doom;..\src\heretic;..\textscreen;..\pcsound"
+ PreprocessorDefinitions="WIN32;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;PROGRAM_PREFIX=&quot;\&quot;chocolate-\&quot;&quot;"
+ StringPooling="true"
+ ExceptionHandling="0"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ WarningLevel="0"
+ DebugInformationFormat="0"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="SDL.lib SDL_mixer.lib SDL_net.lib SDLmain.lib"
+ OutputFile="$(OutDir)\chocolate-heretic.exe"
+ GenerateDebugInformation="false"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\src\d_event.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\d_iwad.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\d_mode.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\deh_str.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_cdmus.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_endoom.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_joystick.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_main.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_pcsound.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_scale.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_sdlmusic.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_sdlsound.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_sound.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_system.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_timer.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_video.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\icon.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_argv.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_bbox.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_cheat.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_config.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_controls.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_fixed.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_misc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\md5.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\memio.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\mus2mid.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\tables.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\v_video.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_checksum.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_file.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_file_posix.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_file_stdc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_file_win32.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_merge.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_wad.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\z_zone.c"
+ >
+ </File>
+ <Filter
+ Name="heretic"
+ >
+ <File
+ RelativePath="..\src\heretic\am_map.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\ct_chat.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\d_main.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\d_net.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\f_finale.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\g_game.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\i_sound.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\in_lude.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\info.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\m_random.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\mn_menu.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\p_ceilng.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\p_doors.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\p_enemy.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\p_floor.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\p_inter.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\p_lights.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\p_map.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\p_maputl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\p_mobj.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\p_plats.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\p_pspr.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\p_setup.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\p_sight.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\p_spec.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\p_switch.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\p_telept.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\p_tick.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\p_user.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\r_bsp.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\r_data.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\r_draw.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\r_main.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\r_plane.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\r_segs.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\r_things.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\s_sound.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\sb_bar.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\sounds.c"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\src\d_event.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\d_iwad.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\d_mode.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\d_ticcmd.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\deh_str.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doomfeatures.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doomkeys.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doomtype.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_cdmus.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_joystick.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_scale.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_sound.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_swap.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_system.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_timer.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_video.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_argv.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_bbox.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_cheat.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_config.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_controls.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_fixed.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_misc.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\md5.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\memio.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\mus2mid.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\tables.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\v_patch.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\v_video.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_checksum.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_file.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_merge.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_wad.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\z_zone.h"
+ >
+ </File>
+ <Filter
+ Name="heretic"
+ >
+ <File
+ RelativePath="..\src\heretic\am_data.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\am_map.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\ct_chat.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\doomdata.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\doomdef.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\dstrings.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\info.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\m_random.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\p_local.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\p_spec.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\r_local.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\s_sound.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\heretic\sounds.h"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ <File
+ RelativePath=".\win32.rc"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/msvc/hexen.vcproj b/msvc/hexen.vcproj
new file mode 100644
index 00000000..42a7b2c3
--- /dev/null
+++ b/msvc/hexen.vcproj
@@ -0,0 +1,764 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="Hexen"
+ ProjectGUID="{8FBB8720-340B-4185-9442-A76781FD6278}"
+ RootNamespace="Hexen"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="..\bin"
+ IntermediateDirectory="..\obj\hexen\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=".;..\src;..\src\strife;..\src\doom;..\textscreen;..\pcsound;..\opl"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;PROGRAM_PREFIX=&quot;\&quot;chocolate-\&quot;&quot;"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="2"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="SDL.lib SDL_mixer.lib SDL_net.lib SDLmain.lib ..\lib\libpcsound.lib ..\lib\libtextscreen.lib ..\lib\libopl.lib"
+ OutputFile="$(OutDir)\chocolate-hexen-dbg.exe"
+ IgnoreAllDefaultLibraries="false"
+ IgnoreDefaultLibraryNames="msvcrtd.lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="..\bin"
+ IntermediateDirectory="..\obj\hexen\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories=".;..\src;..\src\doom;..\src\heretic;..\textscreen;..\pcsound"
+ PreprocessorDefinitions="WIN32;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;PROGRAM_PREFIX=&quot;\&quot;chocolate-\&quot;&quot;"
+ StringPooling="true"
+ ExceptionHandling="0"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ WarningLevel="0"
+ DebugInformationFormat="0"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="SDL.lib SDL_mixer.lib SDL_net.lib SDLmain.lib"
+ OutputFile="$(OutDir)\chocolate-hexen.exe"
+ GenerateDebugInformation="false"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\src\d_event.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\d_iwad.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\d_mode.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\deh_str.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_cdmus.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_joystick.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_main.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_oplmusic.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_pcsound.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_scale.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_sdlmusic.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_sdlsound.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_sound.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_system.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_timer.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_video.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_videohr.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\icon.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_argv.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_bbox.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_cheat.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_config.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_controls.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_fixed.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_misc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\md5.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\memio.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\midifile.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\mus2mid.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\tables.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\v_video.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_checksum.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_file.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_file_posix.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_file_stdc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_file_win32.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_main.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_merge.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_wad.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\z_zone.c"
+ >
+ </File>
+ <Filter
+ Name="hexen"
+ >
+ <File
+ RelativePath="..\src\hexen\a_action.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\am_map.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\ct_chat.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\d_net.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\f_finale.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\g_game.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\h2_main.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\i_sound.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\in_lude.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\info.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\m_misc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\m_random.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\mn_menu.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\p_acs.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\p_anim.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\p_ceilng.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\p_doors.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\p_enemy.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\p_floor.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\p_inter.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\p_lights.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\p_map.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\p_maputl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\p_mobj.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\p_plats.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\p_pspr.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\p_setup.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\p_sight.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\p_spec.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\p_switch.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\p_telept.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\p_things.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\p_tick.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\p_user.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\po_man.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\r_bsp.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\r_data.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\r_draw.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\r_main.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\r_plane.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\r_segs.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\r_things.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\s_sound.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\sb_bar.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\sc_man.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\sn_sonix.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\sounds.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\st_start.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\sv_save.c"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\src\d_event.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\d_iwad.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\d_mode.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\d_ticcmd.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\deh_str.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doomfeatures.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doomkeys.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doomtype.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_cdmus.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_joystick.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_scale.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_sound.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_swap.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_system.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_timer.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_video.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_videohr.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_argv.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_bbox.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_cheat.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_config.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_controls.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_fixed.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_misc.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\md5.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\memio.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\mus2mid.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\tables.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\v_patch.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\v_video.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_checksum.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_file.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_merge.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_wad.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\z_zone.h"
+ >
+ </File>
+ <Filter
+ Name="hexen"
+ >
+ <File
+ RelativePath="..\src\hexen\am_data.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\am_map.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\ct_chat.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\h2def.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\i_header.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\info.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\m_random.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\p_local.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\p_spec.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\r_local.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\s_sound.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\sounds.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\st_start.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\textdefs.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\hexen\xddefs.h"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ <File
+ RelativePath=".\win32.rc"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/msvc/libopl.vcproj b/msvc/libopl.vcproj
new file mode 100644
index 00000000..b0480b6c
--- /dev/null
+++ b/msvc/libopl.vcproj
@@ -0,0 +1,237 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="libopl"
+ ProjectGUID="{FC8D0610-1507-4F36-99BC-6F5A422B6AD3}"
+ RootNamespace="libopl"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="..\lib"
+ IntermediateDirectory="..\obj\libopl\$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=".;..\src"
+ PreprocessorDefinitions="WIN32;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="..\lib"
+ IntermediateDirectory="..\obj\libopl\$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="1"
+ OmitFramePointers="true"
+ WholeProgramOptimization="false"
+ AdditionalIncludeDirectories=".;..\src"
+ PreprocessorDefinitions="WIN32;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE"
+ StringPooling="true"
+ MinimalRebuild="false"
+ ExceptionHandling="0"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="false"
+ WarningLevel="3"
+ DebugInformationFormat="0"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ IgnoreDefaultLibraryNames="msvcrtd"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\opl\dbopl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\opl\ioperm_sys.c"
+ >
+ </File>
+ <File
+ RelativePath="..\opl\opl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\opl\opl_linux.c"
+ >
+ </File>
+ <File
+ RelativePath="..\opl\opl_obsd.c"
+ >
+ </File>
+ <File
+ RelativePath="..\opl\opl_queue.c"
+ >
+ </File>
+ <File
+ RelativePath="..\opl\opl_sdl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\opl\opl_timer.c"
+ >
+ </File>
+ <File
+ RelativePath="..\opl\opl_win32.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\opl\dbopl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\opl\ioperm_sys.h"
+ >
+ </File>
+ <File
+ RelativePath="..\opl\opl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\opl\opl_internal.h"
+ >
+ </File>
+ <File
+ RelativePath="..\opl\opl_queue.h"
+ >
+ </File>
+ <File
+ RelativePath="..\opl\opl_timer.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/msvc/libpcsound.vcproj b/msvc/libpcsound.vcproj
new file mode 100644
index 00000000..496f1f69
--- /dev/null
+++ b/msvc/libpcsound.vcproj
@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="libpcsound"
+ ProjectGUID="{66CD7F50-73B9-482F-8B69-1AF54983F845}"
+ RootNamespace="libpcsound"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="..\lib"
+ IntermediateDirectory="..\obj\libpcsound\$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=".;..\src"
+ PreprocessorDefinitions="WIN32;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="..\lib"
+ IntermediateDirectory="..\obj\libpcsound\$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="1"
+ OmitFramePointers="true"
+ EnableFiberSafeOptimizations="false"
+ WholeProgramOptimization="false"
+ AdditionalIncludeDirectories=".;..\src"
+ PreprocessorDefinitions="WIN32;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="false"
+ WarningLevel="3"
+ DebugInformationFormat="0"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ IgnoreDefaultLibraryNames="msvcrtd"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\pcsound\pcsound.c"
+ >
+ </File>
+ <File
+ RelativePath="..\pcsound\pcsound_sdl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\pcsound\pcsound_win32.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\pcsound\pcsound.h"
+ >
+ </File>
+ <File
+ RelativePath="..\pcsound\pcsound_internal.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/msvc/libtextscreen.vcproj b/msvc/libtextscreen.vcproj
new file mode 100644
index 00000000..3489cd77
--- /dev/null
+++ b/msvc/libtextscreen.vcproj
@@ -0,0 +1,337 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="libtextscreen"
+ ProjectGUID="{35F435DB-AC4A-4F28-BA2D-812E638FB01A}"
+ RootNamespace="libtextscreen"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="..\lib"
+ IntermediateDirectory="..\obj\libtextscreen\$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=".;..\src"
+ PreprocessorDefinitions="WIN32;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="..\lib"
+ IntermediateDirectory="..\obj\libtextscreen\$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="1"
+ OmitFramePointers="true"
+ WholeProgramOptimization="false"
+ AdditionalIncludeDirectories=".;..\src"
+ PreprocessorDefinitions="WIN32;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE"
+ StringPooling="true"
+ MinimalRebuild="false"
+ ExceptionHandling="0"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="false"
+ WarningLevel="0"
+ DebugInformationFormat="0"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ IgnoreDefaultLibraryNames="msvcrtd"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\textscreen\txt_button.c"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_checkbox.c"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_desktop.c"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_dropdown.c"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_gui.c"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_inputbox.c"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_io.c"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_label.c"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_radiobutton.c"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_sdl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_separator.c"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_spinctrl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_strut.c"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_table.c"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_utf8.c"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_widget.c"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_window.c"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_window_action.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\textscreen\textscreen.h"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_button.h"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_checkbox.h"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_desktop.h"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_dropdown.h"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_font.h"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_gui.h"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_inputbox.h"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_io.h"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_label.h"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_largefont.h"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_main.h"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_radiobutton.h"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_sdl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_separator.h"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_spinctrl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_strut.h"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_table.h"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_utf8.h"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_widget.h"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_window.h"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_window_action.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/msvc/server.vcproj b/msvc/server.vcproj
new file mode 100644
index 00000000..d692267f
--- /dev/null
+++ b/msvc/server.vcproj
@@ -0,0 +1,312 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="Server"
+ ProjectGUID="{10DCBB24-F8BB-4796-A653-6DE9C8AAC24B}"
+ RootNamespace="Server"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="..\bin"
+ IntermediateDirectory="..\obj\server\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=".;..\src;..\textscreen"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;DEDICATEDSERVER"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="DEDICATEDSERVER"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="SDL.lib SDL_net.lib SDLmain.lib"
+ OutputFile="$(OutDir)\chocolate-server-dbg.exe"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="..\bin"
+ IntermediateDirectory="..\obj\server\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories=".;..\src;..\textscreen"
+ PreprocessorDefinitions="WIN32;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE"
+ StringPooling="true"
+ ExceptionHandling="0"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ WarningLevel="0"
+ DebugInformationFormat="0"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="DEDICATEDSERVER"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="SDL.lib SDL_net.lib SDLmain.lib"
+ OutputFile="$(OutDir)\chocolate-server.exe"
+ GenerateDebugInformation="false"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\src\d_dedicated.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\d_mode.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_main.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_system.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_timer.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_argv.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_misc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_dedicated.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_io.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_packet.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_sdl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_server.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_structrw.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\z_native.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\src\d_mode.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_system.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_timer.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_argv.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_misc.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_common.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_dedicated.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_io.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_packet.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_sdl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_server.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_structrw.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\z_zone.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ <File
+ RelativePath=".\win32.rc"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/msvc/setup.vcproj b/msvc/setup.vcproj
new file mode 100644
index 00000000..5e2a2efe
--- /dev/null
+++ b/msvc/setup.vcproj
@@ -0,0 +1,320 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="Setup"
+ ProjectGUID="{01975BB6-D2DA-48E7-AE0D-6A8AC8ECF48A}"
+ RootNamespace="Setup"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="..\bin"
+ IntermediateDirectory="..\obj\setup\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=".;..\src;..\src\doom;..\textscreen"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;CHOCOLATESETUP"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="CHOCOLATESETUP"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="SDL.lib SDLmain.lib"
+ OutputFile="$(OutDir)\chocolate-setup-dbg.exe"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="..\bin"
+ IntermediateDirectory="..\obj\setup\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories=".;..\src;..\src\doom;..\textscreen"
+ PreprocessorDefinitions="WIN32;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;CHOCOLATESETUP"
+ StringPooling="true"
+ ExceptionHandling="0"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ WarningLevel="3"
+ DebugInformationFormat="0"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="CHOCOLATESETUP"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="SDL.lib SDLmain.lib"
+ OutputFile="$(OutDir)\chocolate-setup.exe"
+ GenerateDebugInformation="false"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\setup\compatibility.c"
+ >
+ </File>
+ <File
+ RelativePath="..\setup\configfile.c"
+ >
+ </File>
+ <File
+ RelativePath="..\setup\display.c"
+ >
+ </File>
+ <File
+ RelativePath="..\setup\execute.c"
+ >
+ </File>
+ <File
+ RelativePath="..\setup\joystick.c"
+ >
+ </File>
+ <File
+ RelativePath="..\setup\keyboard.c"
+ >
+ </File>
+ <File
+ RelativePath="..\setup\m_argv.c"
+ >
+ </File>
+ <File
+ RelativePath="..\setup\mainmenu.c"
+ >
+ </File>
+ <File
+ RelativePath="..\setup\mouse.c"
+ >
+ </File>
+ <File
+ RelativePath="..\setup\multiplayer.c"
+ >
+ </File>
+ <File
+ RelativePath="..\setup\setup_icon.c"
+ >
+ </File>
+ <File
+ RelativePath="..\setup\sound.c"
+ >
+ </File>
+ <File
+ RelativePath="..\setup\txt_joybinput.c"
+ >
+ </File>
+ <File
+ RelativePath="..\setup\txt_keyinput.c"
+ >
+ </File>
+ <File
+ RelativePath="..\setup\txt_mouseinput.c"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_scrollpane.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\setup\compatibility.h"
+ >
+ </File>
+ <File
+ RelativePath="..\setup\configfile.h"
+ >
+ </File>
+ <File
+ RelativePath="..\setup\display.h"
+ >
+ </File>
+ <File
+ RelativePath="..\setup\execute.h"
+ >
+ </File>
+ <File
+ RelativePath="..\setup\joystick.h"
+ >
+ </File>
+ <File
+ RelativePath="..\setup\keyboard.h"
+ >
+ </File>
+ <File
+ RelativePath="..\setup\m_argv.h"
+ >
+ </File>
+ <File
+ RelativePath="..\setup\mouse.h"
+ >
+ </File>
+ <File
+ RelativePath="..\setup\multiplayer.h"
+ >
+ </File>
+ <File
+ RelativePath="..\setup\sound.h"
+ >
+ </File>
+ <File
+ RelativePath="..\setup\txt_joybinput.h"
+ >
+ </File>
+ <File
+ RelativePath="..\setup\txt_keyinput.h"
+ >
+ </File>
+ <File
+ RelativePath="..\setup\txt_mouseinput.h"
+ >
+ </File>
+ <File
+ RelativePath="..\textscreen\txt_scrollpane.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ <File
+ RelativePath=".\win32.rc"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/msvc/strife.vcproj b/msvc/strife.vcproj
new file mode 100644
index 00000000..34f7a143
--- /dev/null
+++ b/msvc/strife.vcproj
@@ -0,0 +1,1107 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="Strife"
+ ProjectGUID="{FC4DACBA-2A3E-4AF0-804A-AF5FFFD13B08}"
+ RootNamespace="Strife"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="..\bin"
+ IntermediateDirectory="..\obj\strife\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=".;..\src;..\src\strife;..\src\doom;..\textscreen;..\pcsound;..\opl"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;PROGRAM_PREFIX=&quot;\&quot;chocolate-\&quot;&quot;"
+ MinimalRebuild="true"
+ ExceptionHandling="0"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ ExpandAttributedSource="true"
+ AssemblerOutput="2"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="SDL.lib SDL_mixer.lib SDL_net.lib SDLmain.lib ..\lib\libpcsound.lib ..\lib\libtextscreen.lib ..\lib\libopl.lib"
+ OutputFile="$(OutDir)\chocolate-strife-dbg.exe"
+ LinkIncremental="2"
+ IgnoreAllDefaultLibraries="false"
+ IgnoreDefaultLibraryNames="msvcrtd.lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="..\bin"
+ IntermediateDirectory="..\obj\strife\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="0"
+ WholeProgramOptimization="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="1"
+ OmitFramePointers="true"
+ WholeProgramOptimization="true"
+ AdditionalIncludeDirectories=".;..\src;..\src\strife;..\src\doom;..\textscreen;..\pcsound;..\opl"
+ PreprocessorDefinitions="WIN32;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;PROGRAM_PREFIX=&quot;\&quot;chocolate-\&quot;&quot;"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="0"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="SDL.lib SDL_mixer.lib SDL_net.lib SDLmain.lib ..\lib\libpcsound.lib ..\lib\libtextscreen.lib ..\lib\libopl.lib"
+ OutputFile="$(OutDir)\chocolate-strife.exe"
+ LinkIncremental="0"
+ IgnoreDefaultLibraryNames="msvcrtd"
+ GenerateDebugInformation="false"
+ GenerateMapFile="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ LinkTimeCodeGeneration="1"
+ DataExecutionPrevention="0"
+ TurnOffAssemblyGeneration="false"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Header Files"
+ >
+ <File
+ RelativePath="..\src\aes_prng.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\d_event.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\d_iwad.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\d_loop.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\d_mode.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\d_ticcmd.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\deh_io.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\deh_main.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\deh_mapping.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\deh_str.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doomfeatures.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doomkeys.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\doomtype.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_cdmus.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_endoom.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_joystick.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_scale.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_sound.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_swap.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_system.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_timer.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_video.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_argv.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_bbox.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_cheat.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_config.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_controls.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_fixed.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_misc.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\memio.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\midifile.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\mus2mid.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_client.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_common.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_dedicated.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_defs.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_gui.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_io.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_loop.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_packet.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_query.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_sdl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_server.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_structrw.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\sha1.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\tables.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\v_patch.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\v_video.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_checksum.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_file.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_main.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_merge.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_wad.h"
+ >
+ </File>
+ <File
+ RelativePath=".\win_opendir.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\z_zone.h"
+ >
+ </File>
+ <Filter
+ Name="strife"
+ >
+ <File
+ RelativePath="..\src\strife\am_map.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\d_englsh.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\d_items.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\d_main.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\d_net.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\d_player.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\d_textur.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\d_think.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\deh_defs.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\deh_io.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\deh_main.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\deh_mapping.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\deh_misc.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\doomdata.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\doomdef.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\doomstat.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\dstrings.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\f_finale.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\f_wipe.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\g_game.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\hu_lib.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\hu_stuff.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\info.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\m_menu.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\m_random.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\m_saves.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_dialog.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_inter.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_local.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_mobj.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_pspr.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_saveg.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_setup.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_spec.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_tick.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\r_bsp.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\r_data.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\r_defs.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\r_draw.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\r_local.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\r_main.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\r_plane.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\r_segs.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\r_sky.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\r_state.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\r_things.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\s_sound.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\sounds.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\st_lib.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\st_stuff.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\wi_stuff.h"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="Source Files"
+ >
+ <File
+ RelativePath="..\src\aes_prng.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\d_event.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\d_iwad.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\d_loop.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\d_mode.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\deh_io.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\deh_main.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\deh_mapping.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\deh_str.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\deh_text.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_cdmus.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_endoom.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_joystick.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_main.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_oplmusic.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_pcsound.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_scale.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_sdlmusic.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_sdlsound.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_sound.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_system.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_timer.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\i_video.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\icon.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_argv.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_bbox.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_cheat.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_config.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_controls.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_fixed.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\m_misc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\memio.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\midifile.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\mus2mid.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_client.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_dedicated.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_gui.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_io.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_loop.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_packet.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_query.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_sdl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_server.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\net_structrw.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\sha1.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\tables.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\v_video.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_checksum.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_file.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_file_posix.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_file_stdc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_file_win32.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_main.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_merge.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\w_wad.c"
+ >
+ </File>
+ <File
+ RelativePath=".\win_opendir.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\z_zone.c"
+ >
+ </File>
+ <Filter
+ Name="strife"
+ >
+ <File
+ RelativePath="..\src\strife\am_map.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\d_items.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\d_main.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\d_net.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\deh_ammo.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\deh_cheat.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\deh_frame.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\deh_misc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\deh_ptr.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\deh_sound.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\deh_strife.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\deh_thing.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\deh_weapon.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\doomdef.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\doomstat.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\dstrings.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\f_finale.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\f_wipe.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\g_game.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\hu_lib.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\hu_stuff.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\info.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\m_menu.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\m_random.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\m_saves.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_ceilng.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_dialog.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_doors.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_enemy.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_floor.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_inter.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_lights.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_map.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_maputl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_mobj.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_plats.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_pspr.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_saveg.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_setup.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_sight.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_spec.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_switch.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_telept.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_tick.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\p_user.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\r_bsp.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\r_data.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\r_draw.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\r_main.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\r_plane.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\r_segs.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\r_sky.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\r_things.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\s_sound.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\sounds.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\st_lib.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\st_stuff.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\strife\wi_stuff.c"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ >
+ <File
+ RelativePath=".\win32.rc"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/msvc/win32.rc b/msvc/win32.rc
index 91c30496..f0eba798 100644
--- a/msvc/win32.rc
+++ b/msvc/win32.rc
@@ -32,21 +32,21 @@
#endif
1 VERSIONINFO
-PRODUCTVERSION 1,7,0,0
-FILEVERSION 1,7,0,0
+PRODUCTVERSION 1,99,0,0
+FILEVERSION 1,99,0,0
FILETYPE 1
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
- VALUE "FileVersion", "1.7.0"
- VALUE "FileDescription", "Chocolate Doom 1.7.0"
+ VALUE "FileVersion", "1.99.0"
+ VALUE "FileDescription", "Chocolate Doom 1.99.0"
VALUE "InternalName", "chocolate-doom"
VALUE "CompanyName", "fraggle@gmail.com"
VALUE "LegalCopyright", "GNU General Public License"
VALUE "ProductName", "Chocolate Doom"
- VALUE "ProductVersion", "1.7.0"
+ VALUE "ProductVersion", "1.99.0"
END
END
END
diff --git a/msvc/win_opendir.c b/msvc/win_opendir.c
new file mode 100644
index 00000000..c37e232d
--- /dev/null
+++ b/msvc/win_opendir.c
@@ -0,0 +1,340 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// 03/10/2006 James Haley
+//
+// For this module only:
+// This code is public domain. No change sufficient enough to constitute a
+// significant or original work has been made, and thus it remains as such.
+//
+//----------------------------------------------------------------------------
+//
+// DESCRIPTION:
+//
+// Implementation of POSIX opendir for Visual C++.
+// Derived from the MinGW C Library Extensions Source (released to the
+// public domain). As with other Win32 modules, don't include most DOOM
+// headers into this or conflicts will occur.
+//
+// Original Header:
+//
+// * dirent.c
+// * This file has no copyright assigned and is placed in the Public Domain.
+// * This file is a part of the mingw-runtime package.
+// * No warranty is given; refer to the file DISCLAIMER within the package.
+// *
+// * Derived from DIRLIB.C by Matt J. Weinstein
+// * This note appears in the DIRLIB.H
+// * DIRLIB.H by M. J. Weinstein Released to public domain 1-Jan-89
+// *
+// * Updated by Jeremy Bettis <jeremy@hksys.com>
+// * Significantly revised and rewinddir, seekdir and telldir added by Colin
+// * Peters <colin@fu.is.saga-u.ac.jp>
+//
+//-----------------------------------------------------------------------------
+
+#ifndef _MSC_VER
+#error i_opndir.c is for Microsoft Visual C++ only
+#endif
+
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h> /* for GetFileAttributes */
+
+#include <tchar.h>
+#define SUFFIX _T("*")
+#define SLASH _T("\\")
+
+#include "win_opendir.h"
+
+//
+// opendir
+//
+// Returns a pointer to a DIR structure appropriately filled in to begin
+// searching a directory.
+//
+DIR *opendir(const _TCHAR *szPath)
+{
+ DIR *nd;
+ unsigned int rc;
+ _TCHAR szFullPath[MAX_PATH];
+
+ errno = 0;
+
+ if(!szPath)
+ {
+ errno = EFAULT;
+ return (DIR *)0;
+ }
+
+ if(szPath[0] == _T('\0'))
+ {
+ errno = ENOTDIR;
+ return (DIR *)0;
+ }
+
+ /* Attempt to determine if the given path really is a directory. */
+ rc = GetFileAttributes(szPath);
+ if(rc == (unsigned int)-1)
+ {
+ /* call GetLastError for more error info */
+ errno = ENOENT;
+ return (DIR *)0;
+ }
+ if(!(rc & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ /* Error, entry exists but not a directory. */
+ errno = ENOTDIR;
+ return (DIR *)0;
+ }
+
+ /* Make an absolute pathname. */
+ _tfullpath(szFullPath, szPath, MAX_PATH);
+
+ /* Allocate enough space to store DIR structure and the complete
+ * directory path given. */
+ nd = (DIR *)(malloc(sizeof(DIR) + (_tcslen(szFullPath)
+ + _tcslen(SLASH)
+ + _tcslen(SUFFIX) + 1)
+ * sizeof(_TCHAR)));
+
+ if(!nd)
+ {
+ /* Error, out of memory. */
+ errno = ENOMEM;
+ return (DIR *)0;
+ }
+
+ /* Create the search expression. */
+ _tcscpy(nd->dd_name, szFullPath);
+
+ /* Add on a slash if the path does not end with one. */
+ if(nd->dd_name[0] != _T('\0')
+ && _tcsrchr(nd->dd_name, _T('/')) != nd->dd_name
+ + _tcslen(nd->dd_name) - 1
+ && _tcsrchr(nd->dd_name, _T('\\')) != nd->dd_name
+ + _tcslen(nd->dd_name) - 1)
+ {
+ _tcscat(nd->dd_name, SLASH);
+ }
+
+ /* Add on the search pattern */
+ _tcscat(nd->dd_name, SUFFIX);
+
+ /* Initialize handle to -1 so that a premature closedir doesn't try
+ * to call _findclose on it. */
+ nd->dd_handle = -1;
+
+ /* Initialize the status. */
+ nd->dd_stat = 0;
+
+ /* Initialize the dirent structure. ino and reclen are invalid under
+ * Win32, and name simply points at the appropriate part of the
+ * findfirst_t structure. */
+ nd->dd_dir.d_ino = 0;
+ nd->dd_dir.d_reclen = 0;
+ nd->dd_dir.d_namlen = 0;
+ memset(nd->dd_dir.d_name, 0, FILENAME_MAX);
+
+ return nd;
+}
+
+//
+// readdir
+//
+// Return a pointer to a dirent structure filled with the information on the
+// next entry in the directory.
+//
+struct dirent *readdir(DIR *dirp)
+{
+ errno = 0;
+
+ /* Check for valid DIR struct. */
+ if(!dirp)
+ {
+ errno = EFAULT;
+ return (struct dirent *)0;
+ }
+
+ if (dirp->dd_stat < 0)
+ {
+ /* We have already returned all files in the directory
+ * (or the structure has an invalid dd_stat). */
+ return (struct dirent *)0;
+ }
+ else if (dirp->dd_stat == 0)
+ {
+ /* We haven't started the search yet. */
+ /* Start the search */
+ dirp->dd_handle = _tfindfirst(dirp->dd_name, &(dirp->dd_dta));
+
+ if(dirp->dd_handle == -1)
+ {
+ /* Whoops! Seems there are no files in that
+ * directory. */
+ dirp->dd_stat = -1;
+ }
+ else
+ {
+ dirp->dd_stat = 1;
+ }
+ }
+ else
+ {
+ /* Get the next search entry. */
+ if(_tfindnext(dirp->dd_handle, &(dirp->dd_dta)))
+ {
+ /* We are off the end or otherwise error.
+ _findnext sets errno to ENOENT if no more file
+ Undo this. */
+ DWORD winerr = GetLastError();
+ if(winerr == ERROR_NO_MORE_FILES)
+ errno = 0;
+ _findclose(dirp->dd_handle);
+ dirp->dd_handle = -1;
+ dirp->dd_stat = -1;
+ }
+ else
+ {
+ /* Update the status to indicate the correct
+ * number. */
+ dirp->dd_stat++;
+ }
+ }
+
+ if (dirp->dd_stat > 0)
+ {
+ /* Successfully got an entry. Everything about the file is
+ * already appropriately filled in except the length of the
+ * file name. */
+ dirp->dd_dir.d_namlen = _tcslen(dirp->dd_dta.name);
+ _tcscpy(dirp->dd_dir.d_name, dirp->dd_dta.name);
+ return &dirp->dd_dir;
+ }
+
+ return (struct dirent *)0;
+}
+
+
+//
+// closedir
+//
+// Frees up resources allocated by opendir.
+//
+int closedir(DIR *dirp)
+{
+ int rc;
+
+ errno = 0;
+ rc = 0;
+
+ if(!dirp)
+ {
+ errno = EFAULT;
+ return -1;
+ }
+
+ if(dirp->dd_handle != -1)
+ {
+ rc = _findclose(dirp->dd_handle);
+ }
+
+ /* Delete the dir structure. */
+ free(dirp);
+
+ return rc;
+}
+
+//
+// rewinddir
+//
+// Return to the beginning of the directory "stream". We simply call findclose
+// and then reset things like an opendir.
+//
+void rewinddir(DIR * dirp)
+{
+ errno = 0;
+
+ if(!dirp)
+ {
+ errno = EFAULT;
+ return;
+ }
+
+ if(dirp->dd_handle != -1)
+ {
+ _findclose(dirp->dd_handle);
+ }
+
+ dirp->dd_handle = -1;
+ dirp->dd_stat = 0;
+}
+
+//
+// telldir
+//
+// Returns the "position" in the "directory stream" which can be used with
+// seekdir to go back to an old entry. We simply return the value in stat.
+//
+long telldir(DIR *dirp)
+{
+ errno = 0;
+
+ if(!dirp)
+ {
+ errno = EFAULT;
+ return -1;
+ }
+ return dirp->dd_stat;
+}
+
+//
+// seekdir
+//
+// Seek to an entry previously returned by telldir. We rewind the directory
+// and call readdir repeatedly until either dd_stat is the position number
+// or -1 (off the end). This is not perfect, in that the directory may
+// have changed while we weren't looking. But that is probably the case with
+// any such system.
+//
+void seekdir(DIR *dirp, long lPos)
+{
+ errno = 0;
+
+ if(!dirp)
+ {
+ errno = EFAULT;
+ return;
+ }
+
+ if(lPos < -1)
+ {
+ /* Seeking to an invalid position. */
+ errno = EINVAL;
+ return;
+ }
+ else if(lPos == -1)
+ {
+ /* Seek past end. */
+ if(dirp->dd_handle != -1)
+ {
+ _findclose(dirp->dd_handle);
+ }
+ dirp->dd_handle = -1;
+ dirp->dd_stat = -1;
+ }
+ else
+ {
+ /* Rewind and read forward to the appropriate index. */
+ rewinddir(dirp);
+
+ while((dirp->dd_stat < lPos) && readdir(dirp))
+ ; /* do-nothing loop */
+ }
+}
+
+// EOF
+
diff --git a/msvc/win_opendir.h b/msvc/win_opendir.h
new file mode 100644
index 00000000..afa6aa12
--- /dev/null
+++ b/msvc/win_opendir.h
@@ -0,0 +1,77 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// 03/10/2006 James Haley
+//
+// For this module only:
+// This code is public domain. No change sufficient enough to constitute a
+// significant or original work has been made, and thus it remains as such.
+//
+//----------------------------------------------------------------------------
+//
+// DESCRIPTION:
+//
+// Implementation of POSIX opendir for Visual C++.
+// Derived from the MinGW C Library Extensions Source (released to the
+// public domain).
+//
+//-----------------------------------------------------------------------------
+
+#ifndef I_OPNDIR_H__
+#define I_OPNDIR_H__
+
+#include <io.h>
+
+#ifndef FILENAME_MAX
+#define FILENAME_MAX 260
+#endif
+
+struct dirent
+{
+ long d_ino; /* Always zero. */
+ unsigned short d_reclen; /* Always zero. */
+ unsigned short d_namlen; /* Length of name in d_name. */
+ char d_name[FILENAME_MAX]; /* File name. */
+};
+
+/*
+ * This is an internal data structure. Good programmers will not use it
+ * except as an argument to one of the functions below.
+ * dd_stat field is now int (was short in older versions).
+ */
+typedef struct
+{
+ /* disk transfer area for this dir */
+ struct _finddata_t dd_dta;
+
+ /* dirent struct to return from dir (NOTE: this makes this thread
+ * safe as long as only one thread uses a particular DIR struct at
+ * a time) */
+ struct dirent dd_dir;
+
+ /* _findnext handle */
+ long dd_handle;
+
+ /*
+ * Status of search:
+ * 0 = not started yet (next entry to read is first entry)
+ * -1 = off the end
+ * positive = 0 based index of next entry
+ */
+ int dd_stat;
+
+ /* given path for dir with search pattern (struct is extended) */
+ char dd_name[1];
+} DIR;
+
+DIR *opendir(const char *);
+struct dirent *readdir(DIR *);
+int closedir(DIR *);
+void rewinddir(DIR *);
+long telldir(DIR *);
+void seekdir(DIR *, long);
+
+#endif
+
+// EOF
+
diff --git a/pkg/Makefile.am b/pkg/Makefile.am
index a2850195..538b9e1e 100644
--- a/pkg/Makefile.am
+++ b/pkg/Makefile.am
@@ -23,7 +23,10 @@ osx/LauncherManager.m osx/LauncherManager.h
WINCE_FILES= \
wince/GNUmakefile \
-wince/wince-cab.cfg \
+wince/common.py \
+wince/doom-cab.cfg \
+wince/heretic-cab.cfg \
+wince/hexen-cab.cfg \
wince/wince-cabgen
WIN32_FILES= \
diff --git a/pkg/osx/GNUmakefile b/pkg/osx/GNUmakefile
index d53a9981..dc2f4f1a 100644
--- a/pkg/osx/GNUmakefile
+++ b/pkg/osx/GNUmakefile
@@ -80,7 +80,13 @@ $(STAGING_DIR): launcher $(TOPLEVEL_DOCS)
./cp-with-libs $(TOPLEVEL)/src/$(PROGRAM_PREFIX)doom "$(APP_BIN_DIR)"
$(STRIP) "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)doom"
- ./cp-with-libs $(TOPLEVEL)/setup/$(PROGRAM_PREFIX)setup "$(APP_BIN_DIR)"
+ ./cp-with-libs $(TOPLEVEL)/src/$(PROGRAM_PREFIX)heretic "$(APP_BIN_DIR)"
+ $(STRIP) "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)heretic"
+ ./cp-with-libs $(TOPLEVEL)/src/$(PROGRAM_PREFIX)hexen "$(APP_BIN_DIR)"
+ $(STRIP) "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)hexen"
+ ./cp-with-libs $(TOPLEVEL)/src/$(PROGRAM_PREFIX)strife "$(APP_BIN_DIR)"
+ $(STRIP) "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)strife"
+ ./cp-with-libs $(TOPLEVEL)/src/$(PROGRAM_PREFIX)setup "$(APP_BIN_DIR)"
$(STRIP) "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)setup"
$(TOPLEVEL)/man/simplecpp -DPRECOMPILED -D__MACOSX__ \
diff --git a/pkg/osx/IWADController.h b/pkg/osx/IWADController.h
index 7464af9f..0e3c3ae5 100644
--- a/pkg/osx/IWADController.h
+++ b/pkg/osx/IWADController.h
@@ -36,6 +36,10 @@
id doom2;
id plutonia;
id tnt;
+
+ id heretic;
+ id hexen;
+ id strife;
}
- (void) closeConfigWindow: (id)sender;
@@ -47,6 +51,7 @@
- (void) saveConfig;
- (char *) doomWadPath;
- (void) setEnvironment;
+- (const char *) getGameName;
- (BOOL) addIWADPath: (NSString *) path;
@end
diff --git a/pkg/osx/IWADController.m b/pkg/osx/IWADController.m
index 0c55b3f5..02f83238 100644
--- a/pkg/osx/IWADController.m
+++ b/pkg/osx/IWADController.m
@@ -33,6 +33,9 @@ typedef enum
IWAD_TNT,
IWAD_PLUTONIA,
IWAD_CHEX,
+ IWAD_HERETIC,
+ IWAD_HEXEN,
+ IWAD_STRIFE,
NUM_IWAD_TYPES
} IWAD;
@@ -42,7 +45,10 @@ static NSString *IWADLabels[NUM_IWAD_TYPES] =
@"Doom II: Hell on Earth",
@"Final Doom: TNT: Evilution",
@"Final Doom: Plutonia Experiment",
- @"Chex Quest"
+ @"Chex Quest",
+ @"Heretic",
+ @"Hexen",
+ @"Strife"
};
static NSString *IWADFilenames[NUM_IWAD_TYPES + 1] =
@@ -52,6 +58,9 @@ static NSString *IWADFilenames[NUM_IWAD_TYPES + 1] =
@"tnt.wad",
@"plutonia.wad",
@"chex.wad",
+ @"heretic.wad",
+ @"hexen.wad",
+ @"strife.wad",
@"undefined"
};
@@ -64,6 +73,9 @@ static NSString *IWADFilenames[NUM_IWAD_TYPES + 1] =
iwadList[IWAD_TNT] = self->tnt;
iwadList[IWAD_PLUTONIA] = self->plutonia;
iwadList[IWAD_CHEX] = self->chex;
+ iwadList[IWAD_HERETIC] = self->heretic;
+ iwadList[IWAD_HEXEN] = self->hexen;
+ iwadList[IWAD_STRIFE] = self->strife;
}
- (IWAD) getSelectedIWAD
@@ -102,6 +114,30 @@ static NSString *IWADFilenames[NUM_IWAD_TYPES + 1] =
}
}
+// Get the name used for the executable for the selected IWAD.
+
+- (const char *) getGameName
+{
+ IWAD selectedIWAD;
+
+ selectedIWAD = [self getSelectedIWAD];
+
+ switch (selectedIWAD)
+ {
+ case IWAD_HERETIC:
+ return "heretic";
+
+ case IWAD_HEXEN:
+ return "hexen";
+
+ case IWAD_STRIFE:
+ return "strife";
+
+ default:
+ return "doom";
+ }
+}
+
- (void) setIWADConfig
{
IWADLocation *iwadList[NUM_IWAD_TYPES];
diff --git a/pkg/osx/LauncherManager.m b/pkg/osx/LauncherManager.m
index 69c59577..a40ac7c9 100644
--- a/pkg/osx/LauncherManager.m
+++ b/pkg/osx/LauncherManager.m
@@ -278,6 +278,8 @@ static NSString *AppendQuotedFilename(NSString *str, NSString *fileName)
{
NSString *iwad;
NSString *args;
+ char *executable_name;
+ const char *game_name;
[self saveConfig];
@@ -294,8 +296,12 @@ static NSString *AppendQuotedFilename(NSString *str, NSString *fileName)
return;
}
- ExecuteProgram(PROGRAM_PREFIX "doom", [iwad UTF8String],
- [args UTF8String]);
+ game_name = [self->iwadController getGameName];
+ executable_name = malloc(strlen(PROGRAM_PREFIX) + strlen(game_name) + 1);
+ sprintf(executable_name, "%s%s", PROGRAM_PREFIX, game_name);
+
+ ExecuteProgram(executable_name, [iwad UTF8String],
+ [args UTF8String]);
[NSApp terminate:sender];
}
@@ -303,10 +309,22 @@ static NSString *AppendQuotedFilename(NSString *str, NSString *fileName)
- (void) runSetup: (id)sender
{
- [self saveConfig];
+ const char *game_name;
+ char *arg;
+ [self saveConfig];
[self->iwadController setEnvironment];
- ExecuteProgram(PROGRAM_PREFIX "setup", NULL, NULL);
+
+ // Provide the -game command line parameter to select the game
+ // to configure, based on the game selected in the dropdown.
+
+ game_name = [self->iwadController getGameName];
+ arg = malloc(strlen(game_name) + 8);
+ sprintf(arg, "-game %s", game_name);
+
+ ExecuteProgram(PROGRAM_PREFIX "setup", NULL, arg);
+
+ free(arg);
}
// Invoked when the "Terminal" option is selected from the menu, to open
diff --git a/pkg/osx/Resources/launcher.nib/designable.nib b/pkg/osx/Resources/launcher.nib/designable.nib
index b3e76d22..73a01abd 100644
--- a/pkg/osx/Resources/launcher.nib/designable.nib
+++ b/pkg/osx/Resources/launcher.nib/designable.nib
@@ -2,9 +2,9 @@
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
<data>
<int key="IBDocument.SystemTarget">1060</int>
- <string key="IBDocument.SystemVersion">10J869</string>
+ <string key="IBDocument.SystemVersion">10K549</string>
<string key="IBDocument.InterfaceBuilderVersion">851</string>
- <string key="IBDocument.AppKitVersion">1038.35</string>
+ <string key="IBDocument.AppKitVersion">1038.36</string>
<string key="IBDocument.HIToolboxVersion">461.00</string>
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
@@ -12,9 +12,9 @@
</object>
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
<bool key="EncodedWithXMLCoder">YES</bool>
- <integer value="370"/>
+ <integer value="227"/>
<integer value="2"/>
- <integer value="228"/>
+ <integer value="29"/>
</object>
<object class="NSArray" key="IBDocument.PluginDependencies">
<bool key="EncodedWithXMLCoder">YES</bool>
@@ -679,7 +679,7 @@
<object class="NSWindowTemplate" id="193084417">
<int key="NSWindowStyleMask">7</int>
<int key="NSWindowBacking">2</int>
- <string key="NSWindowRect">{{377, 409}, {480, 316}}</string>
+ <string key="NSWindowRect">{{377, 417}, {518, 308}}</string>
<int key="NSWTFlags">1886912512</int>
<string key="NSWindowTitle">IWAD configuration</string>
<object class="NSMutableString" key="NSWindowClass">
@@ -695,280 +695,10 @@
<int key="NSvFlags">256</int>
<object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSTextField" id="348674481">
- <reference key="NSNextResponder" ref="145141922"/>
- <int key="NSvFlags">256</int>
- <string key="NSFrame">{{17, 285}, {446, 11}}</string>
- <reference key="NSSuperview" ref="145141922"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSTextFieldCell" key="NSCell" id="522582983">
- <int key="NSCellFlags">67239424</int>
- <int key="NSCellFlags2">272629760</int>
- <string key="NSContents">Doom IWAD location (doom.wad):</string>
- <reference key="NSSupport" ref="22"/>
- <reference key="NSControlView" ref="348674481"/>
- <reference key="NSBackgroundColor" ref="77619338"/>
- <reference key="NSTextColor" ref="206071849"/>
- </object>
- </object>
- <object class="NSTextField" id="215057262">
- <reference key="NSNextResponder" ref="145141922"/>
- <int key="NSvFlags">256</int>
- <string key="NSFrame">{{20, 255}, {369, 22}}</string>
- <reference key="NSSuperview" ref="145141922"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSTextFieldCell" key="NSCell" id="596525351">
- <int key="NSCellFlags">-1804468671</int>
- <int key="NSCellFlags2">272630784</int>
- <string key="NSContents"/>
- <reference key="NSSupport" ref="407649812"/>
- <reference key="NSControlView" ref="215057262"/>
- <bool key="NSDrawsBackground">YES</bool>
- <reference key="NSBackgroundColor" ref="612330193"/>
- <reference key="NSTextColor" ref="943265597"/>
- </object>
- </object>
- <object class="NSButton" id="410786529">
- <reference key="NSNextResponder" ref="145141922"/>
- <int key="NSvFlags">256</int>
- <string key="NSFrame">{{397, 255}, {63, 23}}</string>
- <reference key="NSSuperview" ref="145141922"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSButtonCell" key="NSCell" id="673476660">
- <int key="NSCellFlags">67239424</int>
- <int key="NSCellFlags2">134217728</int>
- <string key="NSContents">Set...</string>
- <reference key="NSSupport" ref="407649812"/>
- <reference key="NSControlView" ref="410786529"/>
- <int key="NSButtonFlags">-2038021889</int>
- <int key="NSButtonFlags2">32</int>
- <reference key="NSAlternateImage" ref="813720862"/>
- <string key="NSAlternateContents"/>
- <string key="NSKeyEquivalent"/>
- <int key="NSPeriodicDelay">400</int>
- <int key="NSPeriodicInterval">75</int>
- </object>
- </object>
- <object class="NSTextField" id="316721564">
- <reference key="NSNextResponder" ref="145141922"/>
- <int key="NSvFlags">256</int>
- <string key="NSFrame">{{17, 236}, {446, 11}}</string>
- <reference key="NSSuperview" ref="145141922"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSTextFieldCell" key="NSCell" id="663066257">
- <int key="NSCellFlags">67239424</int>
- <int key="NSCellFlags2">272629760</int>
- <string key="NSContents">Doom II IWAD location (doom2.wad):</string>
- <reference key="NSSupport" ref="22"/>
- <reference key="NSControlView" ref="316721564"/>
- <reference key="NSBackgroundColor" ref="77619338"/>
- <reference key="NSTextColor" ref="206071849"/>
- </object>
- </object>
- <object class="NSTextField" id="458378991">
- <reference key="NSNextResponder" ref="145141922"/>
- <int key="NSvFlags">256</int>
- <string key="NSFrame">{{20, 206}, {369, 22}}</string>
- <reference key="NSSuperview" ref="145141922"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSTextFieldCell" key="NSCell" id="848829815">
- <int key="NSCellFlags">-1804468671</int>
- <int key="NSCellFlags2">272630784</int>
- <string key="NSContents"/>
- <reference key="NSSupport" ref="407649812"/>
- <reference key="NSControlView" ref="458378991"/>
- <bool key="NSDrawsBackground">YES</bool>
- <reference key="NSBackgroundColor" ref="612330193"/>
- <reference key="NSTextColor" ref="943265597"/>
- </object>
- </object>
- <object class="NSButton" id="644218899">
- <reference key="NSNextResponder" ref="145141922"/>
- <int key="NSvFlags">256</int>
- <string key="NSFrame">{{397, 206}, {63, 23}}</string>
- <reference key="NSSuperview" ref="145141922"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSButtonCell" key="NSCell" id="63361904">
- <int key="NSCellFlags">67239424</int>
- <int key="NSCellFlags2">134217728</int>
- <string key="NSContents">Set...</string>
- <reference key="NSSupport" ref="407649812"/>
- <reference key="NSControlView" ref="644218899"/>
- <int key="NSButtonFlags">-2038021889</int>
- <int key="NSButtonFlags2">32</int>
- <reference key="NSAlternateImage" ref="813720862"/>
- <string key="NSAlternateContents"/>
- <string key="NSKeyEquivalent"/>
- <int key="NSPeriodicDelay">400</int>
- <int key="NSPeriodicInterval">75</int>
- </object>
- </object>
- <object class="NSTextField" id="179636494">
- <reference key="NSNextResponder" ref="145141922"/>
- <int key="NSvFlags">256</int>
- <string key="NSFrame">{{17, 187}, {446, 11}}</string>
- <reference key="NSSuperview" ref="145141922"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSTextFieldCell" key="NSCell" id="84857374">
- <int key="NSCellFlags">67239424</int>
- <int key="NSCellFlags2">272629760</int>
- <string type="base64-UTF8" key="NSContents">RmluYWwgRG9vbTogVE5UOiBFdmlsdXRpb24gbG9jYXRpb24gKHRudC53YWQpOgo</string>
- <reference key="NSSupport" ref="22"/>
- <reference key="NSControlView" ref="179636494"/>
- <reference key="NSBackgroundColor" ref="77619338"/>
- <reference key="NSTextColor" ref="206071849"/>
- </object>
- </object>
- <object class="NSTextField" id="1021143679">
- <reference key="NSNextResponder" ref="145141922"/>
- <int key="NSvFlags">256</int>
- <string key="NSFrame">{{20, 157}, {369, 22}}</string>
- <reference key="NSSuperview" ref="145141922"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSTextFieldCell" key="NSCell" id="629867670">
- <int key="NSCellFlags">-1804468671</int>
- <int key="NSCellFlags2">272630784</int>
- <string key="NSContents"/>
- <reference key="NSSupport" ref="407649812"/>
- <reference key="NSControlView" ref="1021143679"/>
- <bool key="NSDrawsBackground">YES</bool>
- <reference key="NSBackgroundColor" ref="612330193"/>
- <reference key="NSTextColor" ref="943265597"/>
- </object>
- </object>
- <object class="NSButton" id="539465960">
- <reference key="NSNextResponder" ref="145141922"/>
- <int key="NSvFlags">256</int>
- <string key="NSFrame">{{397, 157}, {63, 23}}</string>
- <reference key="NSSuperview" ref="145141922"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSButtonCell" key="NSCell" id="979277836">
- <int key="NSCellFlags">67239424</int>
- <int key="NSCellFlags2">134217728</int>
- <string key="NSContents">Set...</string>
- <reference key="NSSupport" ref="407649812"/>
- <reference key="NSControlView" ref="539465960"/>
- <int key="NSButtonFlags">-2038021889</int>
- <int key="NSButtonFlags2">32</int>
- <reference key="NSAlternateImage" ref="813720862"/>
- <string key="NSAlternateContents"/>
- <string key="NSKeyEquivalent"/>
- <int key="NSPeriodicDelay">400</int>
- <int key="NSPeriodicInterval">75</int>
- </object>
- </object>
- <object class="NSTextField" id="712311825">
- <reference key="NSNextResponder" ref="145141922"/>
- <int key="NSvFlags">256</int>
- <string key="NSFrame">{{17, 138}, {446, 11}}</string>
- <reference key="NSSuperview" ref="145141922"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSTextFieldCell" key="NSCell" id="131918744">
- <int key="NSCellFlags">67239424</int>
- <int key="NSCellFlags2">272629760</int>
- <string type="base64-UTF8" key="NSContents">RmluYWwgRG9vbTogUGx1dG9uaWEgRXhwZXJpbWVudCBsb2NhdGlvbiAocGx1dG9uaWEud2FkKToKA</string>
- <reference key="NSSupport" ref="22"/>
- <reference key="NSControlView" ref="712311825"/>
- <reference key="NSBackgroundColor" ref="77619338"/>
- <reference key="NSTextColor" ref="206071849"/>
- </object>
- </object>
- <object class="NSTextField" id="355049668">
- <reference key="NSNextResponder" ref="145141922"/>
- <int key="NSvFlags">256</int>
- <string key="NSFrame">{{20, 108}, {369, 22}}</string>
- <reference key="NSSuperview" ref="145141922"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSTextFieldCell" key="NSCell" id="17259252">
- <int key="NSCellFlags">-1804468671</int>
- <int key="NSCellFlags2">272630784</int>
- <string key="NSContents"/>
- <reference key="NSSupport" ref="407649812"/>
- <reference key="NSControlView" ref="355049668"/>
- <bool key="NSDrawsBackground">YES</bool>
- <reference key="NSBackgroundColor" ref="612330193"/>
- <reference key="NSTextColor" ref="943265597"/>
- </object>
- </object>
- <object class="NSButton" id="602477213">
- <reference key="NSNextResponder" ref="145141922"/>
- <int key="NSvFlags">256</int>
- <string key="NSFrame">{{397, 108}, {63, 23}}</string>
- <reference key="NSSuperview" ref="145141922"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSButtonCell" key="NSCell" id="406066834">
- <int key="NSCellFlags">67239424</int>
- <int key="NSCellFlags2">134217728</int>
- <string key="NSContents">Set...</string>
- <reference key="NSSupport" ref="407649812"/>
- <reference key="NSControlView" ref="602477213"/>
- <int key="NSButtonFlags">-2038021889</int>
- <int key="NSButtonFlags2">32</int>
- <reference key="NSAlternateImage" ref="813720862"/>
- <string key="NSAlternateContents"/>
- <string key="NSKeyEquivalent"/>
- <int key="NSPeriodicDelay">400</int>
- <int key="NSPeriodicInterval">75</int>
- </object>
- </object>
- <object class="NSTextField" id="452288864">
- <reference key="NSNextResponder" ref="145141922"/>
- <int key="NSvFlags">256</int>
- <string key="NSFrame">{{17, 89}, {446, 11}}</string>
- <reference key="NSSuperview" ref="145141922"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSTextFieldCell" key="NSCell" id="969661180">
- <int key="NSCellFlags">67239424</int>
- <int key="NSCellFlags2">272629760</int>
- <string key="NSContents">Chex Quest IWAD location (chex.wad):</string>
- <reference key="NSSupport" ref="22"/>
- <reference key="NSControlView" ref="452288864"/>
- <reference key="NSBackgroundColor" ref="77619338"/>
- <reference key="NSTextColor" ref="206071849"/>
- </object>
- </object>
- <object class="NSTextField" id="625273251">
- <reference key="NSNextResponder" ref="145141922"/>
- <int key="NSvFlags">256</int>
- <string key="NSFrame">{{20, 59}, {369, 22}}</string>
- <reference key="NSSuperview" ref="145141922"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSTextFieldCell" key="NSCell" id="857754300">
- <int key="NSCellFlags">-1804468671</int>
- <int key="NSCellFlags2">272630784</int>
- <string key="NSContents"/>
- <reference key="NSSupport" ref="407649812"/>
- <reference key="NSControlView" ref="625273251"/>
- <bool key="NSDrawsBackground">YES</bool>
- <reference key="NSBackgroundColor" ref="612330193"/>
- <reference key="NSTextColor" ref="943265597"/>
- </object>
- </object>
- <object class="NSButton" id="680095551">
- <reference key="NSNextResponder" ref="145141922"/>
- <int key="NSvFlags">256</int>
- <string key="NSFrame">{{397, 59}, {63, 23}}</string>
- <reference key="NSSuperview" ref="145141922"/>
- <bool key="NSEnabled">YES</bool>
- <object class="NSButtonCell" key="NSCell" id="1012408786">
- <int key="NSCellFlags">67239424</int>
- <int key="NSCellFlags2">134217728</int>
- <string key="NSContents">Set...</string>
- <reference key="NSSupport" ref="407649812"/>
- <reference key="NSControlView" ref="680095551"/>
- <int key="NSButtonFlags">-2038021889</int>
- <int key="NSButtonFlags2">32</int>
- <reference key="NSAlternateImage" ref="813720862"/>
- <string key="NSAlternateContents"/>
- <string key="NSKeyEquivalent"/>
- <int key="NSPeriodicDelay">400</int>
- <int key="NSPeriodicInterval">75</int>
- </object>
- </object>
<object class="NSButton" id="658359713">
<reference key="NSNextResponder" ref="145141922"/>
<int key="NSvFlags">256</int>
- <string key="NSFrame">{{384, 12}, {82, 32}}</string>
+ <string key="NSFrame">{{422, 12}, {82, 32}}</string>
<reference key="NSSuperview" ref="145141922"/>
<bool key="NSEnabled">YES</bool>
<object class="NSButtonCell" key="NSCell" id="235375789">
@@ -1008,8 +738,487 @@
<int key="NSPeriodicInterval">25</int>
</object>
</object>
+ <object class="NSTabView" id="793342693">
+ <reference key="NSNextResponder" ref="145141922"/>
+ <int key="NSvFlags">12</int>
+ <string key="NSFrame">{{13, 42}, {492, 260}}</string>
+ <reference key="NSSuperview" ref="145141922"/>
+ <object class="NSMutableArray" key="NSTabViewItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSTabViewItem" id="939760325">
+ <string key="NSIdentifier">1</string>
+ <object class="NSView" key="NSView" id="948790550">
+ <reference key="NSNextResponder" ref="793342693"/>
+ <int key="NSvFlags">256</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSTextField" id="348674481">
+ <reference key="NSNextResponder" ref="948790550"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{14, 200}, {446, 11}}</string>
+ <reference key="NSSuperview" ref="948790550"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="522582983">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">272629760</int>
+ <string key="NSContents">Doom IWAD location (doom.wad):</string>
+ <reference key="NSSupport" ref="22"/>
+ <reference key="NSControlView" ref="348674481"/>
+ <reference key="NSBackgroundColor" ref="77619338"/>
+ <reference key="NSTextColor" ref="206071849"/>
+ </object>
+ </object>
+ <object class="NSTextField" id="215057262">
+ <reference key="NSNextResponder" ref="948790550"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{17, 171}, {369, 22}}</string>
+ <reference key="NSSuperview" ref="948790550"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="596525351">
+ <int key="NSCellFlags">-1804468671</int>
+ <int key="NSCellFlags2">272630784</int>
+ <string key="NSContents"/>
+ <reference key="NSSupport" ref="407649812"/>
+ <reference key="NSControlView" ref="215057262"/>
+ <bool key="NSDrawsBackground">YES</bool>
+ <reference key="NSBackgroundColor" ref="612330193"/>
+ <reference key="NSTextColor" ref="943265597"/>
+ </object>
+ </object>
+ <object class="NSButton" id="410786529">
+ <reference key="NSNextResponder" ref="948790550"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{393, 169}, {63, 23}}</string>
+ <reference key="NSSuperview" ref="948790550"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="673476660">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents">Set...</string>
+ <reference key="NSSupport" ref="407649812"/>
+ <reference key="NSControlView" ref="410786529"/>
+ <int key="NSButtonFlags">-2038021889</int>
+ <int key="NSButtonFlags2">32</int>
+ <reference key="NSAlternateImage" ref="813720862"/>
+ <string key="NSAlternateContents"/>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">400</int>
+ <int key="NSPeriodicInterval">75</int>
+ </object>
+ </object>
+ <object class="NSTextField" id="316721564">
+ <reference key="NSNextResponder" ref="948790550"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{14, 152}, {446, 11}}</string>
+ <reference key="NSSuperview" ref="948790550"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="663066257">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">272629760</int>
+ <string key="NSContents">Doom II IWAD location (doom2.wad):</string>
+ <reference key="NSSupport" ref="22"/>
+ <reference key="NSControlView" ref="316721564"/>
+ <reference key="NSBackgroundColor" ref="77619338"/>
+ <reference key="NSTextColor" ref="206071849"/>
+ </object>
+ </object>
+ <object class="NSTextField" id="458378991">
+ <reference key="NSNextResponder" ref="948790550"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{17, 122}, {369, 22}}</string>
+ <reference key="NSSuperview" ref="948790550"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="848829815">
+ <int key="NSCellFlags">-1804468671</int>
+ <int key="NSCellFlags2">272630784</int>
+ <string key="NSContents"/>
+ <reference key="NSSupport" ref="407649812"/>
+ <reference key="NSControlView" ref="458378991"/>
+ <bool key="NSDrawsBackground">YES</bool>
+ <reference key="NSBackgroundColor" ref="612330193"/>
+ <reference key="NSTextColor" ref="943265597"/>
+ </object>
+ </object>
+ <object class="NSButton" id="644218899">
+ <reference key="NSNextResponder" ref="948790550"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{393, 122}, {63, 23}}</string>
+ <reference key="NSSuperview" ref="948790550"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="63361904">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents">Set...</string>
+ <reference key="NSSupport" ref="407649812"/>
+ <reference key="NSControlView" ref="644218899"/>
+ <int key="NSButtonFlags">-2038021889</int>
+ <int key="NSButtonFlags2">32</int>
+ <reference key="NSAlternateImage" ref="813720862"/>
+ <string key="NSAlternateContents"/>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">400</int>
+ <int key="NSPeriodicInterval">75</int>
+ </object>
+ </object>
+ <object class="NSTextField" id="179636494">
+ <reference key="NSNextResponder" ref="948790550"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{14, 103}, {446, 11}}</string>
+ <reference key="NSSuperview" ref="948790550"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="84857374">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">272629760</int>
+ <string type="base64-UTF8" key="NSContents">RmluYWwgRG9vbTogVE5UOiBFdmlsdXRpb24gbG9jYXRpb24gKHRudC53YWQpOgo</string>
+ <reference key="NSSupport" ref="22"/>
+ <reference key="NSControlView" ref="179636494"/>
+ <reference key="NSBackgroundColor" ref="77619338"/>
+ <reference key="NSTextColor" ref="206071849"/>
+ </object>
+ </object>
+ <object class="NSTextField" id="1021143679">
+ <reference key="NSNextResponder" ref="948790550"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{17, 73}, {369, 22}}</string>
+ <reference key="NSSuperview" ref="948790550"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="629867670">
+ <int key="NSCellFlags">-1804468671</int>
+ <int key="NSCellFlags2">272630784</int>
+ <string key="NSContents"/>
+ <reference key="NSSupport" ref="407649812"/>
+ <reference key="NSControlView" ref="1021143679"/>
+ <bool key="NSDrawsBackground">YES</bool>
+ <reference key="NSBackgroundColor" ref="612330193"/>
+ <reference key="NSTextColor" ref="943265597"/>
+ </object>
+ </object>
+ <object class="NSButton" id="539465960">
+ <reference key="NSNextResponder" ref="948790550"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{393, 73}, {63, 23}}</string>
+ <reference key="NSSuperview" ref="948790550"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="979277836">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents">Set...</string>
+ <reference key="NSSupport" ref="407649812"/>
+ <reference key="NSControlView" ref="539465960"/>
+ <int key="NSButtonFlags">-2038021889</int>
+ <int key="NSButtonFlags2">32</int>
+ <reference key="NSAlternateImage" ref="813720862"/>
+ <string key="NSAlternateContents"/>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">400</int>
+ <int key="NSPeriodicInterval">75</int>
+ </object>
+ </object>
+ <object class="NSTextField" id="712311825">
+ <reference key="NSNextResponder" ref="948790550"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{14, 55}, {446, 11}}</string>
+ <reference key="NSSuperview" ref="948790550"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="131918744">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">272629760</int>
+ <string type="base64-UTF8" key="NSContents">RmluYWwgRG9vbTogUGx1dG9uaWEgRXhwZXJpbWVudCBsb2NhdGlvbiAocGx1dG9uaWEud2FkKToKA</string>
+ <reference key="NSSupport" ref="22"/>
+ <reference key="NSControlView" ref="712311825"/>
+ <reference key="NSBackgroundColor" ref="77619338"/>
+ <reference key="NSTextColor" ref="206071849"/>
+ </object>
+ </object>
+ <object class="NSTextField" id="355049668">
+ <reference key="NSNextResponder" ref="948790550"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{17, 25}, {369, 22}}</string>
+ <reference key="NSSuperview" ref="948790550"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="17259252">
+ <int key="NSCellFlags">-1804468671</int>
+ <int key="NSCellFlags2">272630784</int>
+ <string key="NSContents"/>
+ <reference key="NSSupport" ref="407649812"/>
+ <reference key="NSControlView" ref="355049668"/>
+ <bool key="NSDrawsBackground">YES</bool>
+ <reference key="NSBackgroundColor" ref="612330193"/>
+ <reference key="NSTextColor" ref="943265597"/>
+ </object>
+ </object>
+ <object class="NSButton" id="602477213">
+ <reference key="NSNextResponder" ref="948790550"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{393, 25}, {63, 23}}</string>
+ <reference key="NSSuperview" ref="948790550"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="406066834">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents">Set...</string>
+ <reference key="NSSupport" ref="407649812"/>
+ <reference key="NSControlView" ref="602477213"/>
+ <int key="NSButtonFlags">-2038021889</int>
+ <int key="NSButtonFlags2">32</int>
+ <reference key="NSAlternateImage" ref="813720862"/>
+ <string key="NSAlternateContents"/>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">400</int>
+ <int key="NSPeriodicInterval">75</int>
+ </object>
+ </object>
+ </object>
+ <string key="NSFrame">{{10, 33}, {472, 214}}</string>
+ <reference key="NSSuperview" ref="793342693"/>
+ </object>
+ <string key="NSLabel">Doom</string>
+ <reference key="NSColor" ref="77619338"/>
+ <reference key="NSTabView" ref="793342693"/>
+ </object>
+ <object class="NSTabViewItem" id="989716837">
+ <string key="NSIdentifier">2</string>
+ <object class="NSView" key="NSView" id="1000383860">
+ <nil key="NSNextResponder"/>
+ <int key="NSvFlags">256</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSTextField" id="452288864">
+ <reference key="NSNextResponder" ref="1000383860"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{14, 55}, {446, 11}}</string>
+ <reference key="NSSuperview" ref="1000383860"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="969661180">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">272629760</int>
+ <string key="NSContents">Chex Quest IWAD location (chex.wad):</string>
+ <reference key="NSSupport" ref="22"/>
+ <reference key="NSControlView" ref="452288864"/>
+ <reference key="NSBackgroundColor" ref="77619338"/>
+ <reference key="NSTextColor" ref="206071849"/>
+ </object>
+ </object>
+ <object class="NSTextField" id="625273251">
+ <reference key="NSNextResponder" ref="1000383860"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{17, 25}, {369, 22}}</string>
+ <reference key="NSSuperview" ref="1000383860"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="857754300">
+ <int key="NSCellFlags">-1804468671</int>
+ <int key="NSCellFlags2">272630784</int>
+ <string key="NSContents"/>
+ <reference key="NSSupport" ref="407649812"/>
+ <reference key="NSControlView" ref="625273251"/>
+ <bool key="NSDrawsBackground">YES</bool>
+ <reference key="NSBackgroundColor" ref="612330193"/>
+ <reference key="NSTextColor" ref="943265597"/>
+ </object>
+ </object>
+ <object class="NSButton" id="680095551">
+ <reference key="NSNextResponder" ref="1000383860"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{393, 25}, {63, 23}}</string>
+ <reference key="NSSuperview" ref="1000383860"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="1012408786">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents">Set...</string>
+ <reference key="NSSupport" ref="407649812"/>
+ <reference key="NSControlView" ref="680095551"/>
+ <int key="NSButtonFlags">-2038021889</int>
+ <int key="NSButtonFlags2">32</int>
+ <reference key="NSAlternateImage" ref="813720862"/>
+ <string key="NSAlternateContents"/>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">400</int>
+ <int key="NSPeriodicInterval">75</int>
+ </object>
+ </object>
+ <object class="NSButton" id="691203613">
+ <reference key="NSNextResponder" ref="1000383860"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{393, 73}, {63, 23}}</string>
+ <reference key="NSSuperview" ref="1000383860"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="598411346">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents">Set...</string>
+ <reference key="NSSupport" ref="407649812"/>
+ <reference key="NSControlView" ref="691203613"/>
+ <int key="NSButtonFlags">-2038021889</int>
+ <int key="NSButtonFlags2">32</int>
+ <reference key="NSAlternateImage" ref="813720862"/>
+ <string key="NSAlternateContents"/>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">400</int>
+ <int key="NSPeriodicInterval">75</int>
+ </object>
+ </object>
+ <object class="NSButton" id="318836161">
+ <reference key="NSNextResponder" ref="1000383860"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{393, 122}, {63, 23}}</string>
+ <reference key="NSSuperview" ref="1000383860"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="118467388">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents">Set...</string>
+ <reference key="NSSupport" ref="407649812"/>
+ <reference key="NSControlView" ref="318836161"/>
+ <int key="NSButtonFlags">-2038021889</int>
+ <int key="NSButtonFlags2">32</int>
+ <reference key="NSAlternateImage" ref="813720862"/>
+ <string key="NSAlternateContents"/>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">400</int>
+ <int key="NSPeriodicInterval">75</int>
+ </object>
+ </object>
+ <object class="NSTextField" id="634339523">
+ <reference key="NSNextResponder" ref="1000383860"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{17, 122}, {369, 22}}</string>
+ <reference key="NSSuperview" ref="1000383860"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="247064311">
+ <int key="NSCellFlags">-1804468671</int>
+ <int key="NSCellFlags2">272630784</int>
+ <string key="NSContents"/>
+ <reference key="NSSupport" ref="407649812"/>
+ <reference key="NSControlView" ref="634339523"/>
+ <bool key="NSDrawsBackground">YES</bool>
+ <reference key="NSBackgroundColor" ref="612330193"/>
+ <reference key="NSTextColor" ref="943265597"/>
+ </object>
+ </object>
+ <object class="NSTextField" id="568653906">
+ <reference key="NSNextResponder" ref="1000383860"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{17, 171}, {369, 22}}</string>
+ <reference key="NSSuperview" ref="1000383860"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="332680482">
+ <int key="NSCellFlags">-1804468671</int>
+ <int key="NSCellFlags2">272630784</int>
+ <string key="NSContents"/>
+ <reference key="NSSupport" ref="407649812"/>
+ <reference key="NSControlView" ref="568653906"/>
+ <bool key="NSDrawsBackground">YES</bool>
+ <reference key="NSBackgroundColor" ref="612330193"/>
+ <reference key="NSTextColor" ref="943265597"/>
+ </object>
+ </object>
+ <object class="NSTextField" id="840089166">
+ <reference key="NSNextResponder" ref="1000383860"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{14, 145}, {446, 17}}</string>
+ <reference key="NSSuperview" ref="1000383860"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="1045009541">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">272629760</int>
+ <string key="NSContents">Hexen IWAD location (hexen.wad):</string>
+ <reference key="NSSupport" ref="22"/>
+ <reference key="NSControlView" ref="840089166"/>
+ <reference key="NSBackgroundColor" ref="77619338"/>
+ <reference key="NSTextColor" ref="206071849"/>
+ </object>
+ </object>
+ <object class="NSTextField" id="10172086">
+ <reference key="NSNextResponder" ref="1000383860"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{14, 194}, {446, 17}}</string>
+ <reference key="NSSuperview" ref="1000383860"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="738481735">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">272629760</int>
+ <string key="NSContents">Heretic IWAD location (heretic.wad):</string>
+ <reference key="NSSupport" ref="22"/>
+ <reference key="NSControlView" ref="10172086"/>
+ <reference key="NSBackgroundColor" ref="77619338"/>
+ <reference key="NSTextColor" ref="206071849"/>
+ </object>
+ </object>
+ <object class="NSButton" id="198489100">
+ <reference key="NSNextResponder" ref="1000383860"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{393, 169}, {63, 23}}</string>
+ <reference key="NSSuperview" ref="1000383860"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="670956484">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents">Set...</string>
+ <reference key="NSSupport" ref="407649812"/>
+ <reference key="NSControlView" ref="198489100"/>
+ <int key="NSButtonFlags">-2038021889</int>
+ <int key="NSButtonFlags2">32</int>
+ <reference key="NSAlternateImage" ref="813720862"/>
+ <string key="NSAlternateContents"/>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">400</int>
+ <int key="NSPeriodicInterval">75</int>
+ </object>
+ </object>
+ <object class="NSTextField" id="1037067478">
+ <reference key="NSNextResponder" ref="1000383860"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{14, 103}, {446, 11}}</string>
+ <reference key="NSSuperview" ref="1000383860"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="320235490">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">272629760</int>
+ <string key="NSContents">Strife IWAD location (strife1.wad):</string>
+ <reference key="NSSupport" ref="22"/>
+ <reference key="NSControlView" ref="1037067478"/>
+ <reference key="NSBackgroundColor" ref="77619338"/>
+ <reference key="NSTextColor" ref="206071849"/>
+ </object>
+ </object>
+ <object class="NSTextField" id="610179448">
+ <reference key="NSNextResponder" ref="1000383860"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{17, 73}, {369, 22}}</string>
+ <reference key="NSSuperview" ref="1000383860"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="469800007">
+ <int key="NSCellFlags">-1804468671</int>
+ <int key="NSCellFlags2">272630784</int>
+ <string key="NSContents"/>
+ <reference key="NSSupport" ref="407649812"/>
+ <reference key="NSControlView" ref="610179448"/>
+ <bool key="NSDrawsBackground">YES</bool>
+ <reference key="NSBackgroundColor" ref="612330193"/>
+ <reference key="NSTextColor" ref="943265597"/>
+ </object>
+ </object>
+ </object>
+ <string key="NSFrame">{{10, 33}, {472, 214}}</string>
+ </object>
+ <string key="NSLabel">Other games</string>
+ <reference key="NSColor" ref="77619338"/>
+ <reference key="NSTabView" ref="793342693"/>
+ </object>
+ </object>
+ <reference key="NSSelectedTabViewItem" ref="939760325"/>
+ <reference key="NSFont" ref="407649812"/>
+ <int key="NSTvFlags">0</int>
+ <bool key="NSAllowTruncatedLabels">YES</bool>
+ <bool key="NSDrawsBackground">YES</bool>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="948790550"/>
+ </object>
+ </object>
</object>
- <string key="NSFrameSize">{480, 316}</string>
+ <string key="NSFrameSize">{518, 308}</string>
<reference key="NSSuperview"/>
</object>
<string key="NSScreenRect">{{0, 0}, {1440, 878}}</string>
@@ -1034,14 +1243,14 @@
<object class="NSCustomObject" id="825061065">
<string key="NSClassName">AppController</string>
</object>
- <object class="NSCustomObject" id="201870239">
- <string key="NSClassName">LauncherManager</string>
+ <object class="NSCustomObject" id="5964108">
+ <string key="NSClassName">IWADLocation</string>
</object>
- <object class="NSCustomObject" id="895790931">
- <string key="NSClassName">LauncherManager</string>
+ <object class="NSCustomObject" id="354490064">
+ <string key="NSClassName">IWADLocation</string>
</object>
- <object class="NSCustomObject" id="366010945">
- <string key="NSClassName">LauncherManager</string>
+ <object class="NSCustomObject" id="606841782">
+ <string key="NSClassName">IWADLocation</string>
</object>
</object>
<object class="IBObjectContainer" key="IBDocument.Objects">
@@ -1447,6 +1656,78 @@
</object>
<int key="connectionID">385</int>
</object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">locationConfigBox</string>
+ <reference key="source" ref="5964108"/>
+ <reference key="destination" ref="568653906"/>
+ </object>
+ <int key="connectionID">403</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">locationConfigBox</string>
+ <reference key="source" ref="354490064"/>
+ <reference key="destination" ref="634339523"/>
+ </object>
+ <int key="connectionID">404</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">setButtonClicked:</string>
+ <reference key="source" ref="5964108"/>
+ <reference key="destination" ref="198489100"/>
+ </object>
+ <int key="connectionID">411</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">setButtonClicked:</string>
+ <reference key="source" ref="354490064"/>
+ <reference key="destination" ref="318836161"/>
+ </object>
+ <int key="connectionID">412</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">heretic</string>
+ <reference key="source" ref="938927474"/>
+ <reference key="destination" ref="5964108"/>
+ </object>
+ <int key="connectionID">413</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">hexen</string>
+ <reference key="source" ref="938927474"/>
+ <reference key="destination" ref="354490064"/>
+ </object>
+ <int key="connectionID">414</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">locationConfigBox</string>
+ <reference key="source" ref="606841782"/>
+ <reference key="destination" ref="610179448"/>
+ </object>
+ <int key="connectionID">423</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">setButtonClicked:</string>
+ <reference key="source" ref="606841782"/>
+ <reference key="destination" ref="691203613"/>
+ </object>
+ <int key="connectionID">424</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">strife</string>
+ <reference key="source" ref="938927474"/>
+ <reference key="destination" ref="606841782"/>
+ </object>
+ <int key="connectionID">425</int>
+ </object>
</object>
<object class="IBMutableOrderedSet" key="objectRecords">
<object class="NSArray" key="orderedObjects">
@@ -1813,162 +2094,13 @@
<reference key="object" ref="145141922"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="348674481"/>
- <reference ref="215057262"/>
- <reference ref="410786529"/>
- <reference ref="316721564"/>
- <reference ref="458378991"/>
- <reference ref="644218899"/>
- <reference ref="179636494"/>
- <reference ref="1021143679"/>
- <reference ref="539465960"/>
- <reference ref="712311825"/>
- <reference ref="355049668"/>
- <reference ref="602477213"/>
- <reference ref="452288864"/>
- <reference ref="625273251"/>
- <reference ref="680095551"/>
+ <reference ref="793342693"/>
<reference ref="658359713"/>
<reference ref="811205099"/>
</object>
<reference key="parent" ref="193084417"/>
</object>
<object class="IBObjectRecord">
- <int key="objectID">234</int>
- <reference key="object" ref="348674481"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="522582983"/>
- </object>
- <reference key="parent" ref="145141922"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">235</int>
- <reference key="object" ref="215057262"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="596525351"/>
- </object>
- <reference key="parent" ref="145141922"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">236</int>
- <reference key="object" ref="410786529"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="673476660"/>
- </object>
- <reference key="parent" ref="145141922"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">238</int>
- <reference key="object" ref="316721564"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="663066257"/>
- </object>
- <reference key="parent" ref="145141922"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">239</int>
- <reference key="object" ref="458378991"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="848829815"/>
- </object>
- <reference key="parent" ref="145141922"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">240</int>
- <reference key="object" ref="644218899"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="63361904"/>
- </object>
- <reference key="parent" ref="145141922"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">241</int>
- <reference key="object" ref="179636494"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="84857374"/>
- </object>
- <reference key="parent" ref="145141922"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">242</int>
- <reference key="object" ref="1021143679"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="629867670"/>
- </object>
- <reference key="parent" ref="145141922"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">243</int>
- <reference key="object" ref="539465960"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="979277836"/>
- </object>
- <reference key="parent" ref="145141922"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">244</int>
- <reference key="object" ref="712311825"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="131918744"/>
- </object>
- <reference key="parent" ref="145141922"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">245</int>
- <reference key="object" ref="355049668"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="17259252"/>
- </object>
- <reference key="parent" ref="145141922"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">246</int>
- <reference key="object" ref="602477213"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="406066834"/>
- </object>
- <reference key="parent" ref="145141922"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">247</int>
- <reference key="object" ref="452288864"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="969661180"/>
- </object>
- <reference key="parent" ref="145141922"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">248</int>
- <reference key="object" ref="625273251"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="857754300"/>
- </object>
- <reference key="parent" ref="145141922"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">249</int>
- <reference key="object" ref="680095551"/>
- <object class="NSMutableArray" key="children">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="1012408786"/>
- </object>
- <reference key="parent" ref="145141922"/>
- </object>
- <object class="IBObjectRecord">
<int key="objectID">250</int>
<reference key="object" ref="658359713"/>
<object class="NSMutableArray" key="children">
@@ -2058,186 +2190,518 @@
<reference key="parent" ref="858516582"/>
</object>
<object class="IBObjectRecord">
+ <int key="objectID">348</int>
+ <reference key="object" ref="235375789"/>
+ <reference key="parent" ref="658359713"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">212</int>
+ <reference key="object" ref="562767686"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="532676330"/>
+ </object>
+ <reference key="parent" ref="968990884"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">213</int>
+ <reference key="object" ref="532676330"/>
+ <reference key="parent" ref="562767686"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-3</int>
+ <reference key="object" ref="226652452"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">Application</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">369</int>
+ <reference key="object" ref="391919375"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="733442466"/>
+ </object>
+ <reference key="parent" ref="624798014"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">370</int>
+ <reference key="object" ref="733442466"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="860531190"/>
+ <reference ref="378926680"/>
+ <reference ref="784926086"/>
+ <reference ref="913959081"/>
+ <reference ref="258703436"/>
+ <reference ref="590365178"/>
+ </object>
+ <reference key="parent" ref="391919375"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">371</int>
+ <reference key="object" ref="860531190"/>
+ <reference key="parent" ref="733442466"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">373</int>
+ <reference key="object" ref="378926680"/>
+ <reference key="parent" ref="733442466"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">375</int>
+ <reference key="object" ref="784926086"/>
+ <reference key="parent" ref="733442466"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">377</int>
+ <reference key="object" ref="913959081"/>
+ <reference key="parent" ref="733442466"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">379</int>
+ <reference key="object" ref="258703436"/>
+ <reference key="parent" ref="733442466"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">380</int>
+ <reference key="object" ref="590365178"/>
+ <reference key="parent" ref="733442466"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">383</int>
+ <reference key="object" ref="811205099"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="33467307"/>
+ </object>
+ <reference key="parent" ref="145141922"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">384</int>
+ <reference key="object" ref="33467307"/>
+ <reference key="parent" ref="811205099"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">386</int>
+ <reference key="object" ref="793342693"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="939760325"/>
+ <reference ref="989716837"/>
+ </object>
+ <reference key="parent" ref="145141922"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">387</int>
+ <reference key="object" ref="939760325"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="948790550"/>
+ </object>
+ <reference key="parent" ref="793342693"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">388</int>
+ <reference key="object" ref="989716837"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1000383860"/>
+ </object>
+ <reference key="parent" ref="793342693"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">389</int>
+ <reference key="object" ref="1000383860"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="568653906"/>
+ <reference ref="10172086"/>
+ <reference ref="198489100"/>
+ <reference ref="318836161"/>
+ <reference ref="840089166"/>
+ <reference ref="634339523"/>
+ <reference ref="1037067478"/>
+ <reference ref="610179448"/>
+ <reference ref="691203613"/>
+ <reference ref="452288864"/>
+ <reference ref="625273251"/>
+ <reference ref="680095551"/>
+ </object>
+ <reference key="parent" ref="989716837"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">390</int>
+ <reference key="object" ref="948790550"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="348674481"/>
+ <reference ref="410786529"/>
+ <reference ref="215057262"/>
+ <reference ref="316721564"/>
+ <reference ref="458378991"/>
+ <reference ref="644218899"/>
+ <reference ref="179636494"/>
+ <reference ref="1021143679"/>
+ <reference ref="539465960"/>
+ <reference ref="712311825"/>
+ <reference ref="355049668"/>
+ <reference ref="602477213"/>
+ </object>
+ <reference key="parent" ref="939760325"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">234</int>
+ <reference key="object" ref="348674481"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="522582983"/>
+ </object>
+ <reference key="parent" ref="948790550"/>
+ </object>
+ <object class="IBObjectRecord">
<int key="objectID">333</int>
<reference key="object" ref="522582983"/>
<reference key="parent" ref="348674481"/>
</object>
<object class="IBObjectRecord">
+ <int key="objectID">235</int>
+ <reference key="object" ref="215057262"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="596525351"/>
+ </object>
+ <reference key="parent" ref="948790550"/>
+ </object>
+ <object class="IBObjectRecord">
<int key="objectID">334</int>
<reference key="object" ref="596525351"/>
<reference key="parent" ref="215057262"/>
</object>
<object class="IBObjectRecord">
+ <int key="objectID">236</int>
+ <reference key="object" ref="410786529"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="673476660"/>
+ </object>
+ <reference key="parent" ref="948790550"/>
+ </object>
+ <object class="IBObjectRecord">
<int key="objectID">335</int>
<reference key="object" ref="673476660"/>
<reference key="parent" ref="410786529"/>
</object>
<object class="IBObjectRecord">
+ <int key="objectID">238</int>
+ <reference key="object" ref="316721564"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="663066257"/>
+ </object>
+ <reference key="parent" ref="948790550"/>
+ </object>
+ <object class="IBObjectRecord">
<int key="objectID">336</int>
<reference key="object" ref="663066257"/>
<reference key="parent" ref="316721564"/>
</object>
<object class="IBObjectRecord">
+ <int key="objectID">239</int>
+ <reference key="object" ref="458378991"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="848829815"/>
+ </object>
+ <reference key="parent" ref="948790550"/>
+ </object>
+ <object class="IBObjectRecord">
<int key="objectID">337</int>
<reference key="object" ref="848829815"/>
<reference key="parent" ref="458378991"/>
</object>
<object class="IBObjectRecord">
+ <int key="objectID">240</int>
+ <reference key="object" ref="644218899"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="63361904"/>
+ </object>
+ <reference key="parent" ref="948790550"/>
+ </object>
+ <object class="IBObjectRecord">
<int key="objectID">338</int>
<reference key="object" ref="63361904"/>
<reference key="parent" ref="644218899"/>
</object>
<object class="IBObjectRecord">
+ <int key="objectID">241</int>
+ <reference key="object" ref="179636494"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="84857374"/>
+ </object>
+ <reference key="parent" ref="948790550"/>
+ </object>
+ <object class="IBObjectRecord">
<int key="objectID">339</int>
<reference key="object" ref="84857374"/>
<reference key="parent" ref="179636494"/>
</object>
<object class="IBObjectRecord">
+ <int key="objectID">242</int>
+ <reference key="object" ref="1021143679"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="629867670"/>
+ </object>
+ <reference key="parent" ref="948790550"/>
+ </object>
+ <object class="IBObjectRecord">
<int key="objectID">340</int>
<reference key="object" ref="629867670"/>
<reference key="parent" ref="1021143679"/>
</object>
<object class="IBObjectRecord">
+ <int key="objectID">243</int>
+ <reference key="object" ref="539465960"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="979277836"/>
+ </object>
+ <reference key="parent" ref="948790550"/>
+ </object>
+ <object class="IBObjectRecord">
<int key="objectID">341</int>
<reference key="object" ref="979277836"/>
<reference key="parent" ref="539465960"/>
</object>
<object class="IBObjectRecord">
+ <int key="objectID">244</int>
+ <reference key="object" ref="712311825"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="131918744"/>
+ </object>
+ <reference key="parent" ref="948790550"/>
+ </object>
+ <object class="IBObjectRecord">
<int key="objectID">342</int>
<reference key="object" ref="131918744"/>
<reference key="parent" ref="712311825"/>
</object>
<object class="IBObjectRecord">
+ <int key="objectID">245</int>
+ <reference key="object" ref="355049668"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="17259252"/>
+ </object>
+ <reference key="parent" ref="948790550"/>
+ </object>
+ <object class="IBObjectRecord">
<int key="objectID">343</int>
<reference key="object" ref="17259252"/>
<reference key="parent" ref="355049668"/>
</object>
<object class="IBObjectRecord">
+ <int key="objectID">246</int>
+ <reference key="object" ref="602477213"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="406066834"/>
+ </object>
+ <reference key="parent" ref="948790550"/>
+ </object>
+ <object class="IBObjectRecord">
<int key="objectID">344</int>
<reference key="object" ref="406066834"/>
<reference key="parent" ref="602477213"/>
</object>
<object class="IBObjectRecord">
+ <int key="objectID">247</int>
+ <reference key="object" ref="452288864"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="969661180"/>
+ </object>
+ <reference key="parent" ref="1000383860"/>
+ </object>
+ <object class="IBObjectRecord">
<int key="objectID">345</int>
<reference key="object" ref="969661180"/>
<reference key="parent" ref="452288864"/>
</object>
<object class="IBObjectRecord">
+ <int key="objectID">248</int>
+ <reference key="object" ref="625273251"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="857754300"/>
+ </object>
+ <reference key="parent" ref="1000383860"/>
+ </object>
+ <object class="IBObjectRecord">
<int key="objectID">346</int>
<reference key="object" ref="857754300"/>
<reference key="parent" ref="625273251"/>
</object>
<object class="IBObjectRecord">
+ <int key="objectID">249</int>
+ <reference key="object" ref="680095551"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1012408786"/>
+ </object>
+ <reference key="parent" ref="1000383860"/>
+ </object>
+ <object class="IBObjectRecord">
<int key="objectID">347</int>
<reference key="object" ref="1012408786"/>
<reference key="parent" ref="680095551"/>
</object>
<object class="IBObjectRecord">
- <int key="objectID">348</int>
- <reference key="object" ref="235375789"/>
- <reference key="parent" ref="658359713"/>
+ <int key="objectID">391</int>
+ <reference key="object" ref="634339523"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="247064311"/>
+ </object>
+ <reference key="parent" ref="1000383860"/>
</object>
<object class="IBObjectRecord">
- <int key="objectID">212</int>
- <reference key="object" ref="562767686"/>
+ <int key="objectID">392</int>
+ <reference key="object" ref="247064311"/>
+ <reference key="parent" ref="634339523"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">393</int>
+ <reference key="object" ref="568653906"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="532676330"/>
+ <reference ref="332680482"/>
</object>
- <reference key="parent" ref="968990884"/>
+ <reference key="parent" ref="1000383860"/>
</object>
<object class="IBObjectRecord">
- <int key="objectID">213</int>
- <reference key="object" ref="532676330"/>
- <reference key="parent" ref="562767686"/>
+ <int key="objectID">394</int>
+ <reference key="object" ref="332680482"/>
+ <reference key="parent" ref="568653906"/>
</object>
<object class="IBObjectRecord">
- <int key="objectID">-3</int>
- <reference key="object" ref="226652452"/>
- <reference key="parent" ref="0"/>
- <string key="objectName">Application</string>
+ <int key="objectID">397</int>
+ <reference key="object" ref="840089166"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1045009541"/>
+ </object>
+ <reference key="parent" ref="1000383860"/>
</object>
<object class="IBObjectRecord">
- <int key="objectID">349</int>
- <reference key="object" ref="201870239"/>
- <reference key="parent" ref="0"/>
+ <int key="objectID">398</int>
+ <reference key="object" ref="1045009541"/>
+ <reference key="parent" ref="840089166"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">399</int>
+ <reference key="object" ref="10172086"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="738481735"/>
+ </object>
+ <reference key="parent" ref="1000383860"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">400</int>
+ <reference key="object" ref="738481735"/>
+ <reference key="parent" ref="10172086"/>
</object>
<object class="IBObjectRecord">
- <int key="objectID">350</int>
- <reference key="object" ref="895790931"/>
+ <int key="objectID">401</int>
+ <reference key="object" ref="5964108"/>
<reference key="parent" ref="0"/>
+ <string key="objectName">HereticIWAD</string>
</object>
<object class="IBObjectRecord">
- <int key="objectID">351</int>
- <reference key="object" ref="366010945"/>
+ <int key="objectID">402</int>
+ <reference key="object" ref="354490064"/>
<reference key="parent" ref="0"/>
+ <string key="objectName">HexenIWAD</string>
</object>
<object class="IBObjectRecord">
- <int key="objectID">369</int>
- <reference key="object" ref="391919375"/>
+ <int key="objectID">405</int>
+ <reference key="object" ref="318836161"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="733442466"/>
+ <reference ref="118467388"/>
</object>
- <reference key="parent" ref="624798014"/>
+ <reference key="parent" ref="1000383860"/>
</object>
<object class="IBObjectRecord">
- <int key="objectID">370</int>
- <reference key="object" ref="733442466"/>
+ <int key="objectID">406</int>
+ <reference key="object" ref="118467388"/>
+ <reference key="parent" ref="318836161"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">408</int>
+ <reference key="object" ref="198489100"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="860531190"/>
- <reference ref="378926680"/>
- <reference ref="784926086"/>
- <reference ref="913959081"/>
- <reference ref="258703436"/>
- <reference ref="590365178"/>
+ <reference ref="670956484"/>
</object>
- <reference key="parent" ref="391919375"/>
+ <reference key="parent" ref="1000383860"/>
</object>
<object class="IBObjectRecord">
- <int key="objectID">371</int>
- <reference key="object" ref="860531190"/>
- <reference key="parent" ref="733442466"/>
+ <int key="objectID">409</int>
+ <reference key="object" ref="670956484"/>
+ <reference key="parent" ref="198489100"/>
</object>
<object class="IBObjectRecord">
- <int key="objectID">373</int>
- <reference key="object" ref="378926680"/>
- <reference key="parent" ref="733442466"/>
- </object>
- <object class="IBObjectRecord">
- <int key="objectID">375</int>
- <reference key="object" ref="784926086"/>
- <reference key="parent" ref="733442466"/>
+ <int key="objectID">415</int>
+ <reference key="object" ref="1037067478"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="320235490"/>
+ </object>
+ <reference key="parent" ref="1000383860"/>
</object>
<object class="IBObjectRecord">
- <int key="objectID">377</int>
- <reference key="object" ref="913959081"/>
- <reference key="parent" ref="733442466"/>
+ <int key="objectID">416</int>
+ <reference key="object" ref="320235490"/>
+ <reference key="parent" ref="1037067478"/>
</object>
<object class="IBObjectRecord">
- <int key="objectID">379</int>
- <reference key="object" ref="258703436"/>
- <reference key="parent" ref="733442466"/>
+ <int key="objectID">417</int>
+ <reference key="object" ref="610179448"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="469800007"/>
+ </object>
+ <reference key="parent" ref="1000383860"/>
</object>
<object class="IBObjectRecord">
- <int key="objectID">380</int>
- <reference key="object" ref="590365178"/>
- <reference key="parent" ref="733442466"/>
+ <int key="objectID">418</int>
+ <reference key="object" ref="469800007"/>
+ <reference key="parent" ref="610179448"/>
</object>
<object class="IBObjectRecord">
- <int key="objectID">383</int>
- <reference key="object" ref="811205099"/>
+ <int key="objectID">419</int>
+ <reference key="object" ref="691203613"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
- <reference ref="33467307"/>
+ <reference ref="598411346"/>
</object>
- <reference key="parent" ref="145141922"/>
+ <reference key="parent" ref="1000383860"/>
</object>
<object class="IBObjectRecord">
- <int key="objectID">384</int>
- <reference key="object" ref="33467307"/>
- <reference key="parent" ref="811205099"/>
+ <int key="objectID">420</int>
+ <reference key="object" ref="598411346"/>
+ <reference key="parent" ref="691203613"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">422</int>
+ <reference key="object" ref="606841782"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">StrifeIWAD</string>
</object>
</object>
</object>
@@ -2327,39 +2791,55 @@
<string>232.ImportedFromIB2</string>
<string>233.ImportedFromIB2</string>
<string>234.IBPluginDependency</string>
+ <string>234.IBViewBoundsToFrameTransform</string>
<string>234.ImportedFromIB2</string>
<string>235.IBPluginDependency</string>
+ <string>235.IBViewBoundsToFrameTransform</string>
<string>235.ImportedFromIB2</string>
<string>236.IBPluginDependency</string>
+ <string>236.IBViewBoundsToFrameTransform</string>
<string>236.ImportedFromIB2</string>
<string>238.IBPluginDependency</string>
+ <string>238.IBViewBoundsToFrameTransform</string>
<string>238.ImportedFromIB2</string>
<string>239.IBPluginDependency</string>
+ <string>239.IBViewBoundsToFrameTransform</string>
<string>239.ImportedFromIB2</string>
<string>24.IBEditorWindowLastContentRect</string>
<string>24.IBPluginDependency</string>
<string>24.ImportedFromIB2</string>
<string>240.IBPluginDependency</string>
+ <string>240.IBViewBoundsToFrameTransform</string>
<string>240.ImportedFromIB2</string>
<string>241.IBPluginDependency</string>
+ <string>241.IBViewBoundsToFrameTransform</string>
<string>241.ImportedFromIB2</string>
<string>242.IBPluginDependency</string>
+ <string>242.IBViewBoundsToFrameTransform</string>
<string>242.ImportedFromIB2</string>
<string>243.IBPluginDependency</string>
+ <string>243.IBViewBoundsToFrameTransform</string>
<string>243.ImportedFromIB2</string>
<string>244.IBPluginDependency</string>
+ <string>244.IBViewBoundsToFrameTransform</string>
<string>244.ImportedFromIB2</string>
<string>245.IBPluginDependency</string>
+ <string>245.IBViewBoundsToFrameTransform</string>
<string>245.ImportedFromIB2</string>
<string>246.IBPluginDependency</string>
+ <string>246.IBViewBoundsToFrameTransform</string>
<string>246.ImportedFromIB2</string>
<string>247.IBPluginDependency</string>
+ <string>247.IBViewBoundsToFrameTransform</string>
<string>247.ImportedFromIB2</string>
<string>248.IBPluginDependency</string>
+ <string>248.IBViewBoundsToFrameTransform</string>
<string>248.ImportedFromIB2</string>
<string>249.IBPluginDependency</string>
+ <string>249.IBViewBoundsToFrameTransform</string>
<string>249.ImportedFromIB2</string>
<string>250.IBPluginDependency</string>
+ <string>250.IBViewBoundsToFrameTransform</string>
<string>250.ImportedFromIB2</string>
<string>270.ImportedFromIB2</string>
<string>274.IBPluginDependency</string>
@@ -2388,9 +2868,6 @@
<string>301.ImportedFromIB2</string>
<string>320.IBPluginDependency</string>
<string>320.ImportedFromIB2</string>
- <string>349.IBPluginDependency</string>
- <string>350.IBPluginDependency</string>
- <string>351.IBPluginDependency</string>
<string>369.IBPluginDependency</string>
<string>370.IBEditorWindowLastContentRect</string>
<string>370.IBPluginDependency</string>
@@ -2401,7 +2878,44 @@
<string>379.IBPluginDependency</string>
<string>380.IBPluginDependency</string>
<string>383.IBPluginDependency</string>
+ <string>383.IBViewBoundsToFrameTransform</string>
<string>384.IBPluginDependency</string>
+ <string>386.IBPluginDependency</string>
+ <string>386.IBViewBoundsToFrameTransform</string>
+ <string>387.IBPluginDependency</string>
+ <string>388.IBPluginDependency</string>
+ <string>389.IBPluginDependency</string>
+ <string>390.IBPluginDependency</string>
+ <string>391.IBPluginDependency</string>
+ <string>391.IBViewBoundsToFrameTransform</string>
+ <string>392.IBPluginDependency</string>
+ <string>393.IBPluginDependency</string>
+ <string>393.IBViewBoundsToFrameTransform</string>
+ <string>394.IBPluginDependency</string>
+ <string>397.IBPluginDependency</string>
+ <string>397.IBViewBoundsToFrameTransform</string>
+ <string>397.ImportedFromIB2</string>
+ <string>399.IBPluginDependency</string>
+ <string>399.IBViewBoundsToFrameTransform</string>
+ <string>399.ImportedFromIB2</string>
+ <string>401.IBPluginDependency</string>
+ <string>402.IBPluginDependency</string>
+ <string>405.IBPluginDependency</string>
+ <string>405.IBViewBoundsToFrameTransform</string>
+ <string>405.ImportedFromIB2</string>
+ <string>408.IBPluginDependency</string>
+ <string>408.IBViewBoundsToFrameTransform</string>
+ <string>408.ImportedFromIB2</string>
+ <string>415.IBPluginDependency</string>
+ <string>415.IBViewBoundsToFrameTransform</string>
+ <string>415.ImportedFromIB2</string>
+ <string>417.IBPluginDependency</string>
+ <string>417.IBViewBoundsToFrameTransform</string>
+ <string>417.ImportedFromIB2</string>
+ <string>419.IBPluginDependency</string>
+ <string>419.IBViewBoundsToFrameTransform</string>
+ <string>419.ImportedFromIB2</string>
+ <string>422.IBPluginDependency</string>
<string>5.IBPluginDependency</string>
<string>5.ImportedFromIB2</string>
<string>56.IBPluginDependency</string>
@@ -2498,9 +3012,9 @@
</object>
<boolean value="YES"/>
<boolean value="YES"/>
- <string>{{421, 438}, {480, 316}}</string>
+ <string>{{358, 421}, {518, 308}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>{{421, 438}, {480, 316}}</string>
+ <string>{{358, 421}, {518, 308}}</string>
<boolean value="YES"/>
<boolean value="YES"/>
<string>{213, 107}</string>
@@ -2514,39 +3028,87 @@
<boolean value="YES"/>
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABD24AAw5+AAA</bytes>
+ </object>
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABBiAAAwz8AAA</bytes>
+ </object>
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABDxoAAxBJAAA</bytes>
+ </object>
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABBYAAAwyAAAA</bytes>
+ </object>
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABBiAAAww8AAA</bytes>
+ </object>
<boolean value="YES"/>
<string>{{469, 741}, {194, 73}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABDyoAAwwcAAA</bytes>
+ </object>
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABBYAAAwuAAAA</bytes>
+ </object>
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABBiAAAwroAAA</bytes>
+ </object>
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABDzoAAwqwAAA</bytes>
+ </object>
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABBYAAAwmAAAA</bytes>
+ </object>
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABBiAAAwjQAAA</bytes>
+ </object>
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABDzoAAwdAAAA</bytes>
+ </object>
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABBYAAAwnwAAA</bytes>
+ </object>
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABBiAAAwjAAAA</bytes>
+ </object>
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABDy4AAwfgAAA</bytes>
+ </object>
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABD2gAAwqIAAA</bytes>
+ </object>
<boolean value="YES"/>
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
@@ -2576,18 +3138,74 @@
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>{{540, 701}, {238, 113}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>{{540, 701}, {238, 113}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABBiAAAwhwAAA</bytes>
+ </object>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABBUAAAw5YAAA</bytes>
+ </object>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABBiAAAwxAAAA</bytes>
+ </object>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABBgAAAw0EAAA</bytes>
+ </object>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABBYAAAwyEAAA</bytes>
+ </object>
+ <boolean value="YES"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABBUAAAw1EAAA</bytes>
+ </object>
+ <boolean value="YES"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABDxIAAww0AAA</bytes>
+ </object>
+ <boolean value="YES"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABDxIAAw0AAAA</bytes>
+ </object>
+ <boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABBYAAAwtYAAA</bytes>
+ </object>
+ <boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABBiAAAwq4AAA</bytes>
+ </object>
+ <boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform">
+ <bytes key="NSTransformStruct">P4AAAL+AAABD0YAAwpYAAA</bytes>
+ </object>
+ <boolean value="YES"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="YES"/>
@@ -2618,7 +3236,7 @@
</object>
</object>
<nil key="sourceID"/>
- <int key="maxID">385</int>
+ <int key="maxID">425</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
@@ -2693,8 +3311,11 @@
<string>configWindow</string>
<string>doom1</string>
<string>doom2</string>
+ <string>heretic</string>
+ <string>hexen</string>
<string>iwadSelector</string>
<string>plutonia</string>
+ <string>strife</string>
<string>tnt</string>
</object>
<object class="NSMutableArray" key="dict.values">
@@ -2706,6 +3327,9 @@
<string>id</string>
<string>id</string>
<string>id</string>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
</object>
</object>
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
@@ -2716,8 +3340,11 @@
<string>configWindow</string>
<string>doom1</string>
<string>doom2</string>
+ <string>heretic</string>
+ <string>hexen</string>
<string>iwadSelector</string>
<string>plutonia</string>
+ <string>strife</string>
<string>tnt</string>
</object>
<object class="NSMutableArray" key="dict.values">
@@ -2739,6 +3366,14 @@
<string key="candidateClassName">id</string>
</object>
<object class="IBToOneOutletInfo">
+ <string key="name">heretic</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBToOneOutletInfo">
+ <string key="name">hexen</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBToOneOutletInfo">
<string key="name">iwadSelector</string>
<string key="candidateClassName">id</string>
</object>
@@ -2747,6 +3382,10 @@
<string key="candidateClassName">id</string>
</object>
<object class="IBToOneOutletInfo">
+ <string key="name">strife</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBToOneOutletInfo">
<string key="name">tnt</string>
<string key="candidateClassName">id</string>
</object>
diff --git a/pkg/osx/Resources/launcher.nib/keyedobjects.nib b/pkg/osx/Resources/launcher.nib/keyedobjects.nib
index 7df7670c..e23926a7 100644
--- a/pkg/osx/Resources/launcher.nib/keyedobjects.nib
+++ b/pkg/osx/Resources/launcher.nib/keyedobjects.nib
Binary files differ
diff --git a/pkg/win32/GNUmakefile b/pkg/win32/GNUmakefile
index 34f2c9bd..6b45152e 100644
--- a/pkg/win32/GNUmakefile
+++ b/pkg/win32/GNUmakefile
@@ -3,9 +3,11 @@ include ../config.make
TOPLEVEL=../..
-EXE_FILES=$(TOPLEVEL)/src/$(PROGRAM_PREFIX)doom.exe \
- $(TOPLEVEL)/src/$(PROGRAM_PREFIX)server.exe \
- $(TOPLEVEL)/setup/$(PROGRAM_PREFIX)setup.exe
+EXE_FILES=$(TOPLEVEL)/src/$(PROGRAM_PREFIX)doom.exe \
+ $(TOPLEVEL)/src/$(PROGRAM_PREFIX)heretic.exe \
+ $(TOPLEVEL)/src/$(PROGRAM_PREFIX)hexen.exe \
+ $(TOPLEVEL)/src/$(PROGRAM_PREFIX)server.exe \
+ $(TOPLEVEL)/src/$(PROGRAM_PREFIX)setup.exe
DLL_FILES=$(TOPLEVEL)/src/SDL.dll \
$(TOPLEVEL)/src/SDL_mixer.dll \
diff --git a/pkg/wince/GNUmakefile b/pkg/wince/GNUmakefile
index b6acc3b8..3b8171aa 100644
--- a/pkg/wince/GNUmakefile
+++ b/pkg/wince/GNUmakefile
@@ -1,15 +1,35 @@
include ../config.make
-DEPS=$(shell ./wince-cabgen -d $(CONFIG_FILE))
-EXECUTABLES=$(filter %.exe, $(DEPS))
-CONFIG_FILE=wince-cab.cfg
-OUTPUT_FILE=$(PACKAGE_TARNAME)-$(PACKAGE_VERSION).cab
+# Doom:
-$(OUTPUT_FILE) : $(CONFIG_FILE) $(DEPS)
- $(STRIP) $(EXECUTABLES)
+DOOM_CAB=$(PROGRAM_PREFIX)doom-$(PACKAGE_VERSION).cab
+DOOM_CFG=doom-cab.cfg
+DOOM_DEPS=$(shell ./wince-cabgen -d $(DOOM_CFG))
+
+# Heretic:
+
+HERETIC_CAB=$(PROGRAM_PREFIX)heretic-$(PACKAGE_VERSION).cab
+HERETIC_CFG=heretic-cab.cfg
+HERETIC_DEPS=$(shell ./wince-cabgen -d $(HERETIC_CFG))
+
+# Hexen:
+
+HEXEN_CAB=$(PROGRAM_PREFIX)hexen-$(PACKAGE_VERSION).cab
+HEXEN_CFG=hexen-cab.cfg
+HEXEN_DEPS=$(shell ./wince-cabgen -d $(HEXEN_CFG))
+
+all: $(DOOM_CAB) $(HERETIC_CAB) $(HEXEN_CAB)
+
+$(DOOM_CAB) : $(DOOM_CFG) $(DOOM_DEPS)
+ ./wince-cabgen $< $@
+
+$(HERETIC_CAB) : $(HERETIC_CFG) $(HERETIC_DEPS)
+ ./wince-cabgen $< $@
+
+$(HEXEN_CAB) : $(HEXEN_CFG) $(HEXEN_DEPS)
./wince-cabgen $< $@
clean:
- rm -f $(OUTPUT_FILE)
+ rm -f $(DOOM_CAB) $(HERETIC_CAB) $(HEXEN_CAB)
diff --git a/pkg/wince/common.py b/pkg/wince/common.py
new file mode 100644
index 00000000..e142c2b7
--- /dev/null
+++ b/pkg/wince/common.py
@@ -0,0 +1,9 @@
+
+# SDL library files that need to be installed:
+
+LIBRARIES = [ "SDL.dll", "SDL_mixer.dll", "libSDL_net-1-2-0.dll" ]
+
+def add_libraries(dir, files):
+ for lib in LIBRARIES:
+ files[dir + lib] = lib
+
diff --git a/pkg/wince/doom-cab.cfg b/pkg/wince/doom-cab.cfg
new file mode 100644
index 00000000..2ffba5a3
--- /dev/null
+++ b/pkg/wince/doom-cab.cfg
@@ -0,0 +1,27 @@
+
+from common import *
+
+app_name = "Chocolate Doom"
+provider = "Simon Howard"
+arch = "strongarm"
+
+# Install files:
+
+d = "$(PROGRAMS_GAMES)/Chocolate Doom/"
+s = "$(START_GAMES)/"
+src = "../../src/"
+
+files = {
+ d+"chocolate-doom.exe": src+"chocolate-doom.exe",
+ d+"chocolate-doom-setup.exe": src+"chocolate-setup.exe",
+}
+
+add_libraries(d, files)
+
+# Start menu links:
+
+links = {
+ s+"Chocolate Doom.lnk": d+"chocolate-doom.exe",
+ s+"Chocolate Doom Setup.lnk": d+"chocolate-doom-setup.exe"
+}
+
diff --git a/pkg/wince/heretic-cab.cfg b/pkg/wince/heretic-cab.cfg
new file mode 100644
index 00000000..ead2081f
--- /dev/null
+++ b/pkg/wince/heretic-cab.cfg
@@ -0,0 +1,27 @@
+
+from common import *
+
+app_name = "Chocolate Heretic"
+provider = "Simon Howard"
+arch = "strongarm"
+
+# Install files:
+
+d = "$(PROGRAMS_GAMES)/Chocolate Heretic/"
+s = "$(START_GAMES)/"
+src = "../../src/"
+
+files = {
+ d+"chocolate-heretic.exe": src+"chocolate-heretic.exe",
+ d+"chocolate-heretic-setup.exe": src+"chocolate-setup.exe",
+}
+
+add_libraries(d, files)
+
+# Start menu links:
+
+links = {
+ s+"Chocolate Heretic.lnk": d+"chocolate-heretic.exe",
+ s+"Chocolate Heretic Setup.lnk": d+"chocolate-heretic-setup.exe"
+}
+
diff --git a/pkg/wince/hexen-cab.cfg b/pkg/wince/hexen-cab.cfg
new file mode 100644
index 00000000..9d88f01d
--- /dev/null
+++ b/pkg/wince/hexen-cab.cfg
@@ -0,0 +1,27 @@
+
+from common import *
+
+app_name = "Chocolate Hexen"
+provider = "Simon Howard"
+arch = "strongarm"
+
+# Install files:
+
+d = "$(PROGRAMS_GAMES)/Chocolate Hexen/"
+s = "$(START_GAMES)/"
+src = "../../src/"
+
+files = {
+ d+"chocolate-hexen.exe": src+"chocolate-hexen.exe",
+ d+"chocolate-hexen-setup.exe": src+"chocolate-setup.exe",
+}
+
+add_libraries(d, files)
+
+# Start menu links:
+
+links = {
+ s+"Chocolate Hexen.lnk": d+"chocolate-hexen.exe",
+ s+"Chocolate Hexen Setup.lnk": d+"chocolate-hexen-setup.exe"
+}
+
diff --git a/pkg/wince/wince-cab.cfg b/pkg/wince/wince-cab.cfg
deleted file mode 100644
index 5f37c5ab..00000000
--- a/pkg/wince/wince-cab.cfg
+++ /dev/null
@@ -1,25 +0,0 @@
-
-app_name = "Chocolate Doom"
-provider = "Simon Howard"
-arch = "strongarm"
-
-# Install files:
-
-d = "$(PROGRAMS_GAMES)/Chocolate Doom/"
-s = "$(START_GAMES)/"
-
-files = {
- d+"chocolate-doom.exe": "../../src/chocolate-doom.exe",
- d+"chocolate-setup.exe": "../../setup/chocolate-setup.exe",
- d+"SDL.dll": "SDL.dll",
- d+"SDL_mixer.dll": "SDL_mixer.dll",
- d+"libSDL_net-1-2-0.dll": "libSDL_net-1-2-0.dll",
-}
-
-# Start menu links:
-
-links = {
- s+"Chocolate Doom.lnk": d+"chocolate-doom.exe",
- s+"Chocolate Doom Setup.lnk": d+"chocolate-setup.exe"
-}
-
diff --git a/rpm.spec.in b/rpm.spec.in
index 137a9517..a31c2036 100644
--- a/rpm.spec.in
+++ b/rpm.spec.in
@@ -18,6 +18,16 @@ Requires: libSDL-1.2.so.0, libSDL_mixer-1.2.so.0, libSDL_net-1.2.so.0
See @PACKAGE_URL@ for more information.
+%package -n @PROGRAM_PREFIX@heretic
+Summary: @PACKAGE_SHORTDESC@ (Heretic binaries)
+Group: Amusements/Games
+Requires: libSDL-1.2.so.0, libSDL_mixer-1.2.so.0, libSDL_net-1.2.so.0
+
+%package -n @PROGRAM_PREFIX@hexen
+Summary: @PACKAGE_SHORTDESC@ (Hexen binaries)
+Group: Amusements/Games
+Requires: libSDL-1.2.so.0, libSDL_mixer-1.2.so.0, libSDL_net-1.2.so.0
+
%prep
rm -rf $RPM_BUILD_ROOT
@@ -47,10 +57,33 @@ make
rm -rf $RPM_BUILD_ROOT
%files
-%doc %{_mandir}/man5/*
-%doc %{_mandir}/man6/*
+%{_mandir}/man5/@PROGRAM_PREFIX@doom.cfg.5
+%{_mandir}/man5/default.cfg.5
+%{_mandir}/man6/@PROGRAM_PREFIX@doom.6
+%{_mandir}/man6/@PROGRAM_PREFIX@server.6
+%{_mandir}/man6/@PROGRAM_PREFIX@doom-setup.6
/usr/share/doc/@PACKAGE@/*
-/usr/games/*
+/usr/games/@PROGRAM_PREFIX@doom
+/usr/games/@PROGRAM_PREFIX@server
+/usr/games/@PROGRAM_PREFIX@doom-setup
/usr/share/icons/*
/usr/share/applications/*
+%files @PROGRAM_PREFIX@heretic
+%{_mandir}/man5/@PROGRAM_PREFIX@heretic.cfg.5
+%{_mandir}/man5/heretic.cfg.5
+%{_mandir}/man6/@PROGRAM_PREFIX@heretic.6
+%{_mandir}/man6/@PROGRAM_PREFIX@heretic-setup.6
+/usr/share/doc/@PROGRAM_PREFIX@heretic/*
+/usr/games/@PROGRAM_PREFIX@heretic
+/usr/games/@PROGRAM_PREFIX@heretic-setup
+
+%files @PROGRAM_PREFIX@hexen
+%{_mandir}/man5/@PROGRAM_PREFIX@hexen.cfg.5
+%{_mandir}/man5/hexen.cfg.5
+%{_mandir}/man6/@PROGRAM_PREFIX@hexen.6
+%{_mandir}/man6/@PROGRAM_PREFIX@hexen-setup.6
+/usr/share/doc/@PROGRAM_PREFIX@hexen/*
+/usr/games/@PROGRAM_PREFIX@hexen
+/usr/games/@PROGRAM_PREFIX@hexen-setup
+
diff --git a/setup/configfile.c b/setup/configfile.c
deleted file mode 100644
index 6a6eb3f6..00000000
--- a/setup/configfile.c
+++ /dev/null
@@ -1,803 +0,0 @@
-// Emacs style mode select -*- C++ -*-
-//-----------------------------------------------------------------------------
-//
-// Copyright(C) 1993-1996 Id Software, Inc.
-// Copyright(C) 2005 Simon Howard
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-// 02111-1307, USA.
-//
-//
-// DESCRIPTION:
-// Configuration file load/save code.
-//
-//-----------------------------------------------------------------------------
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
-
-// for mkdir:
-
-#ifdef _WIN32
-#include <io.h>
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#else
-#include <sys/stat.h>
-#include <sys/types.h>
-#endif
-
-#include "SDL_mixer.h"
-
-#include "config.h"
-
-#include "doomfeatures.h"
-#include "doomkeys.h"
-#include "doomtype.h"
-#include "d_englsh.h"
-
-#include "m_argv.h"
-
-#include "compatibility.h"
-#include "display.h"
-#include "joystick.h"
-#include "keyboard.h"
-#include "mouse.h"
-#include "multiplayer.h"
-#include "sound.h"
-
-char *configdir;
-
-//
-// Create a directory
-//
-
-void M_MakeDirectory(char *path)
-{
-#ifdef _WIN32
- mkdir(path);
-#else
- mkdir(path, 0755);
-#endif
-}
-
-
-//
-// M_SetConfigDir:
-//
-// Sets the location of the configuration directory, where configuration
-// files are stored - default.cfg, chocolate-doom.cfg, savegames, etc.
-//
-
-void M_SetConfigDir(void)
-{
-#if !defined(_WIN32) || defined(_WIN32_WCE)
-
- // Configuration settings are stored in ~/.chocolate-doom/,
- // except on Windows, where we behave like Vanilla Doom and
- // save in the current directory.
-
- char *homedir;
-
- homedir = getenv("HOME");
-
- if (homedir != NULL)
- {
- // put all configuration in a config directory off the
- // homedir
-
- configdir = malloc(strlen(homedir) + strlen(PACKAGE_TARNAME) + 5);
-
- sprintf(configdir, "%s%c.%s%c", homedir, DIR_SEPARATOR,
- PACKAGE_TARNAME, DIR_SEPARATOR);
-
- // make the directory if it doesnt already exist
-
- M_MakeDirectory(configdir);
- }
- else
-#endif /* #ifndef _WIN32 */
- {
-#if defined(_WIN32) && !defined(_WIN32_WCE)
- // when given the -cdrom option, save config+savegames in
- // c:\doomdata. This only applies under Windows.
-
- if (M_CheckParm("-cdrom") > 0)
- {
- printf(D_CDROM);
- configdir = strdup("c:\\doomdata\\");
-
- M_MakeDirectory(configdir);
- }
- else
-#endif
- {
- configdir = strdup("");
- }
- }
-}
-
-
-
-//
-// DEFAULTS
-//
-
-// These are options that are not controlled by setup.
-
-static int showMessages = 1;
-static int screenblocks = 9;
-static int detailLevel = 0;
-static int usegamma = 0;
-
-// dos specific options: these are unused but should be maintained
-// so that the config file can be shared between chocolate
-// doom and doom.exe
-
-static int snd_sbport = 0;
-static int snd_sbirq = 0;
-static int snd_sbdma = 0;
-static int snd_mport = 0;
-
-typedef enum
-{
- DEFAULT_INT,
- DEFAULT_INT_HEX,
- DEFAULT_STRING,
- DEFAULT_FLOAT,
- DEFAULT_KEY,
-} default_type_t;
-
-typedef struct
-{
- // Name of the variable
- char * name;
-
- // Pointer to the location in memory of the variable
- void * location;
-
- // Type of the variable
- default_type_t type;
-
- // If this is a key value, the original integer scancode we read from
- // the config file before translating it to the internal key value.
- // If zero, we didn't read this value from a config file.
- int untranslated;
-
- // The value we translated the scancode into when we read the
- // config file on startup. If the variable value is different from
- // this, it has been changed and needs to be converted; otherwise,
- // use the 'untranslated' value.
- int original_translated;
-} default_t;
-
-typedef struct
-{
- default_t *defaults;
- int numdefaults;
- char *filename;
-} default_collection_t;
-
-static default_t doom_defaults_list[] =
-{
- {"mouse_sensitivity", &mouseSensitivity, DEFAULT_INT, 0, 0},
- {"sfx_volume",&sfxVolume, DEFAULT_INT, 0, 0},
- {"music_volume",&musicVolume, DEFAULT_INT, 0, 0},
- {"show_messages",&showMessages, DEFAULT_INT, 0, 0},
-
- {"key_right",&key_right, DEFAULT_KEY, 0, 0},
- {"key_left",&key_left, DEFAULT_KEY, 0, 0},
- {"key_up",&key_up, DEFAULT_KEY, 0, 0},
- {"key_down",&key_down, DEFAULT_KEY, 0, 0},
- {"key_strafeleft",&key_strafeleft, DEFAULT_KEY, 0, 0},
- {"key_straferight",&key_straferight, DEFAULT_KEY, 0, 0},
-
- {"key_fire",&key_fire, DEFAULT_KEY, 0, 0},
- {"key_use",&key_use, DEFAULT_KEY, 0, 0},
- {"key_strafe",&key_strafe, DEFAULT_KEY, 0, 0},
- {"key_speed",&key_speed, DEFAULT_KEY, 0, 0},
-
- {"use_mouse",&usemouse, DEFAULT_INT, 0, 0},
- {"mouseb_fire",&mousebfire, DEFAULT_INT, 0, 0},
- {"mouseb_strafe",&mousebstrafe, DEFAULT_INT, 0, 0},
- {"mouseb_forward",&mousebforward, DEFAULT_INT, 0, 0},
-
- {"use_joystick",&usejoystick, DEFAULT_INT, 0, 0},
- {"joyb_fire",&joybfire, DEFAULT_INT, 0, 0},
- {"joyb_strafe",&joybstrafe, DEFAULT_INT, 0, 0},
- {"joyb_use",&joybuse, DEFAULT_INT, 0, 0},
- {"joyb_speed",&joybspeed, DEFAULT_INT, 0, 0},
-
- {"screenblocks",&screenblocks, DEFAULT_INT, 0, 0},
- {"detaillevel",&detailLevel, DEFAULT_INT, 0, 0},
-
- {"snd_channels",&numChannels, DEFAULT_INT, 0, 0},
-
- {"snd_musicdevice", &snd_musicdevice, DEFAULT_INT, 0, 0},
- {"snd_sfxdevice", &snd_sfxdevice, DEFAULT_INT, 0, 0},
- {"snd_sbport", &snd_sbport, DEFAULT_INT, 0, 0},
- {"snd_sbirq", &snd_sbirq, DEFAULT_INT, 0, 0},
- {"snd_sbdma", &snd_sbdma, DEFAULT_INT, 0, 0},
- {"snd_mport", &snd_mport, DEFAULT_INT, 0, 0},
-
- {"usegamma", &usegamma, DEFAULT_INT, 0, 0},
-
- {"chatmacro0", &chat_macros[0], DEFAULT_STRING, 0, 0 },
- {"chatmacro1", &chat_macros[1], DEFAULT_STRING, 0, 0 },
- {"chatmacro2", &chat_macros[2], DEFAULT_STRING, 0, 0 },
- {"chatmacro3", &chat_macros[3], DEFAULT_STRING, 0, 0 },
- {"chatmacro4", &chat_macros[4], DEFAULT_STRING, 0, 0 },
- {"chatmacro5", &chat_macros[5], DEFAULT_STRING, 0, 0 },
- {"chatmacro6", &chat_macros[6], DEFAULT_STRING, 0, 0 },
- {"chatmacro7", &chat_macros[7], DEFAULT_STRING, 0, 0 },
- {"chatmacro8", &chat_macros[8], DEFAULT_STRING, 0, 0 },
- {"chatmacro9", &chat_macros[9], DEFAULT_STRING, 0, 0 },
-
-};
-
-static default_collection_t doom_defaults =
-{
- doom_defaults_list,
- arrlen(doom_defaults_list),
- NULL,
-};
-
-static default_t extra_defaults_list[] =
-{
- {"autoadjust_video_settings", &autoadjust_video_settings, DEFAULT_INT, 0, 0},
- {"fullscreen", &fullscreen, DEFAULT_INT, 0, 0},
- {"aspect_ratio_correct", &aspect_ratio_correct, DEFAULT_INT, 0, 0},
- {"startup_delay", &startup_delay, DEFAULT_INT, 0, 0},
- {"screen_width", &screen_width, DEFAULT_INT, 0, 0},
- {"screen_height", &screen_height, DEFAULT_INT, 0, 0},
- {"screen_bpp", &screen_bpp, DEFAULT_INT, 0, 0},
- {"grabmouse", &grabmouse, DEFAULT_INT, 0, 0},
- {"novert", &novert, DEFAULT_INT, 0, 0},
- {"mouse_acceleration", &mouse_acceleration, DEFAULT_FLOAT, 0, 0},
- {"mouse_threshold", &mouse_threshold, DEFAULT_INT, 0, 0},
- {"snd_samplerate", &snd_samplerate, DEFAULT_INT, 0, 0},
- {"opl_io_port", &opl_io_port, DEFAULT_INT_HEX, 0, 0},
- {"show_endoom", &show_endoom, DEFAULT_INT, 0, 0},
- {"vanilla_savegame_limit", &vanilla_savegame_limit, DEFAULT_INT, 0, 0},
- {"vanilla_demo_limit", &vanilla_demo_limit, DEFAULT_INT, 0, 0},
- {"vanilla_keyboard_mapping", &vanilla_keyboard_mapping, DEFAULT_INT, 0, 0},
-#ifdef FEATURE_MULTIPLAYER
- {"player_name", &net_player_name, DEFAULT_STRING, 0, 0},
-#endif
- {"video_driver", &video_driver, DEFAULT_STRING, 0, 0},
- {"joystick_index", &joystick_index, DEFAULT_INT, 0, 0},
- {"joystick_x_axis", &joystick_x_axis, DEFAULT_INT, 0, 0},
- {"joystick_x_invert", &joystick_x_invert, DEFAULT_INT, 0, 0},
- {"joystick_y_axis", &joystick_y_axis, DEFAULT_INT, 0, 0},
- {"joystick_y_invert", &joystick_y_invert, DEFAULT_INT, 0, 0},
- {"joyb_strafeleft", &joybstrafeleft, DEFAULT_INT, 0, 0},
- {"joyb_straferight", &joybstraferight, DEFAULT_INT, 0, 0},
- {"joyb_prevweapon", &joybprevweapon, DEFAULT_INT, 0, 0},
- {"joyb_nextweapon", &joybnextweapon, DEFAULT_INT, 0, 0},
- {"dclick_use", &dclick_use, DEFAULT_INT, 0, 0},
- {"mouseb_strafeleft", &mousebstrafeleft, DEFAULT_INT, 0, 0},
- {"mouseb_straferight", &mousebstraferight, DEFAULT_INT, 0, 0},
- {"mouseb_use", &mousebuse, DEFAULT_INT, 0, 0},
- {"mouseb_backward", &mousebbackward, DEFAULT_INT, 0, 0},
- {"mouseb_prevweapon", &mousebprevweapon, DEFAULT_INT, 0, 0},
- {"mouseb_nextweapon", &mousebnextweapon, DEFAULT_INT, 0, 0},
- {"use_libsamplerate", &use_libsamplerate, DEFAULT_INT, 0, 0},
-
- {"key_pause", &key_pause, DEFAULT_KEY, 0, 0},
- {"key_menu_activate", &key_menu_activate, DEFAULT_KEY, 0, 0},
- {"key_menu_up", &key_menu_up, DEFAULT_KEY, 0, 0},
- {"key_menu_down", &key_menu_down, DEFAULT_KEY, 0, 0},
- {"key_menu_left", &key_menu_left, DEFAULT_KEY, 0, 0},
- {"key_menu_right", &key_menu_right, DEFAULT_KEY, 0, 0},
- {"key_menu_back", &key_menu_back, DEFAULT_KEY, 0, 0},
- {"key_menu_forward", &key_menu_forward, DEFAULT_KEY, 0, 0},
- {"key_menu_confirm", &key_menu_confirm, DEFAULT_KEY, 0, 0},
- {"key_menu_abort", &key_menu_abort, DEFAULT_KEY, 0, 0},
- {"key_menu_help", &key_menu_help, DEFAULT_KEY, 0, 0},
- {"key_menu_save", &key_menu_save, DEFAULT_KEY, 0, 0},
- {"key_menu_load", &key_menu_load, DEFAULT_KEY, 0, 0},
- {"key_menu_volume", &key_menu_volume, DEFAULT_KEY, 0, 0},
- {"key_menu_detail", &key_menu_detail, DEFAULT_KEY, 0, 0},
- {"key_menu_qsave", &key_menu_qsave, DEFAULT_KEY, 0, 0},
- {"key_menu_endgame", &key_menu_endgame, DEFAULT_KEY, 0, 0},
- {"key_menu_messages", &key_menu_messages, DEFAULT_KEY, 0, 0},
- {"key_menu_qload", &key_menu_qload, DEFAULT_KEY, 0, 0},
- {"key_menu_quit", &key_menu_quit, DEFAULT_KEY, 0, 0},
- {"key_menu_gamma", &key_menu_gamma, DEFAULT_KEY, 0, 0},
- {"key_spy", &key_spy, DEFAULT_KEY, 0, 0},
- {"key_menu_incscreen", &key_menu_incscreen, DEFAULT_KEY, 0, 0},
- {"key_menu_decscreen", &key_menu_decscreen, DEFAULT_KEY, 0, 0},
-
- {"key_map_toggle", &key_map_toggle, DEFAULT_KEY, 0, 0},
- {"key_map_north", &key_map_north, DEFAULT_KEY, 0, 0},
- {"key_map_south", &key_map_south, DEFAULT_KEY, 0, 0},
- {"key_map_east", &key_map_east, DEFAULT_KEY, 0, 0},
- {"key_map_west", &key_map_west, DEFAULT_KEY, 0, 0},
- {"key_map_zoomin", &key_map_zoomin, DEFAULT_KEY, 0, 0},
- {"key_map_zoomout", &key_map_zoomout, DEFAULT_KEY, 0, 0},
- {"key_map_maxzoom", &key_map_maxzoom, DEFAULT_KEY, 0, 0},
- {"key_map_follow", &key_map_follow, DEFAULT_KEY, 0, 0},
- {"key_map_grid", &key_map_grid, DEFAULT_KEY, 0, 0},
- {"key_map_mark", &key_map_mark, DEFAULT_KEY, 0, 0},
- {"key_map_clearmark", &key_map_clearmark, DEFAULT_KEY, 0, 0},
- {"key_weapon1", &key_weapon1, DEFAULT_KEY, 0, 0},
- {"key_weapon2", &key_weapon2, DEFAULT_KEY, 0, 0},
- {"key_weapon3", &key_weapon3, DEFAULT_KEY, 0, 0},
- {"key_weapon4", &key_weapon4, DEFAULT_KEY, 0, 0},
- {"key_weapon5", &key_weapon5, DEFAULT_KEY, 0, 0},
- {"key_weapon6", &key_weapon6, DEFAULT_KEY, 0, 0},
- {"key_weapon7", &key_weapon7, DEFAULT_KEY, 0, 0},
- {"key_weapon8", &key_weapon8, DEFAULT_KEY, 0, 0},
- {"key_prevweapon", &key_prevweapon, DEFAULT_KEY, 0, 0},
- {"key_nextweapon", &key_nextweapon, DEFAULT_KEY, 0, 0},
- {"key_message_refresh", &key_message_refresh, DEFAULT_KEY, 0, 0},
- {"key_demo_quit", &key_demo_quit, DEFAULT_KEY, 0, 0},
- {"key_multi_msg", &key_multi_msg, DEFAULT_KEY, 0, 0},
- {"key_multi_msgplayer1", &key_multi_msgplayer[0], DEFAULT_KEY, 0, 0},
- {"key_multi_msgplayer2", &key_multi_msgplayer[1], DEFAULT_KEY, 0, 0},
- {"key_multi_msgplayer3", &key_multi_msgplayer[2], DEFAULT_KEY, 0, 0},
- {"key_multi_msgplayer4", &key_multi_msgplayer[3], DEFAULT_KEY, 0, 0},
-};
-
-static default_collection_t extra_defaults =
-{
- extra_defaults_list,
- arrlen(extra_defaults_list),
- NULL,
-};
-
-static int scantokey[128] =
-{
- 0 , 27, '1', '2', '3', '4', '5', '6',
- '7', '8', '9', '0', '-', '=', KEY_BACKSPACE, 9,
- 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
- 'o', 'p', '[', ']', 13, KEY_RCTRL, 'a', 's',
- 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
- '\'', '`', KEY_RSHIFT,'\\', 'z', 'x', 'c', 'v',
- 'b', 'n', 'm', ',', '.', '/', KEY_RSHIFT,KEYP_MULTIPLY,
- KEY_RALT, ' ', KEY_CAPSLOCK,KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5,
- KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_PAUSE,KEY_SCRLCK,KEY_HOME,
- KEY_UPARROW,KEY_PGUP,KEYP_MINUS,KEY_LEFTARROW,KEYP_5,KEY_RIGHTARROW,KEYP_PLUS,KEY_END,
- KEY_DOWNARROW,KEY_PGDN,KEY_INS,KEY_DEL,0, 0, 0, KEY_F11,
- KEY_F12, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-
-static void SaveDefaultCollection(default_collection_t *collection)
-{
- default_t *defaults;
- int i, v;
- FILE *f;
-
- f = fopen (collection->filename, "w");
- if (!f)
- return; // can't write the file, but don't complain
-
- defaults = collection->defaults;
-
- for (i=0 ; i<collection->numdefaults ; i++)
- {
- int chars_written;
-
- // Print the name and line up all values at 30 characters
-
- chars_written = fprintf(f, "%s ", defaults[i].name);
-
- for (; chars_written < 30; ++chars_written)
- fprintf(f, " ");
-
- // Print the value
-
- switch (defaults[i].type)
- {
- case DEFAULT_KEY:
-
- // use the untranslated version if we can, to reduce
- // the possibility of screwing up the user's config
- // file
-
- v = * (int *) defaults[i].location;
-
- if (v == KEY_RSHIFT)
- {
- // Special case: for shift, force scan code for
- // right shift, as this is what Vanilla uses.
- // This overrides the change check below, to fix
- // configuration files made by old versions that
- // mistakenly used the scan code for left shift.
-
- v = 54;
- }
- else if (defaults[i].untranslated
- && v == defaults[i].original_translated)
- {
- // Has not been changed since the last time we
- // read the config file.
-
- v = defaults[i].untranslated;
- }
- else
- {
- // search for a reverse mapping back to a scancode
- // in the scantokey table
-
- int s;
-
- for (s=0; s<128; ++s)
- {
- if (scantokey[s] == v)
- {
- v = s;
- break;
- }
- }
- }
-
- fprintf(f, "%i", v);
- break;
-
- case DEFAULT_INT_HEX:
- fprintf(f, "0x%x", * (int *) defaults[i].location);
- break;
-
- case DEFAULT_INT:
- fprintf(f, "%i", * (int *) defaults[i].location);
- break;
-
- case DEFAULT_FLOAT:
- fprintf(f, "%f", * (float *) defaults[i].location);
- break;
-
- case DEFAULT_STRING:
- fprintf(f,"\"%s\"", * (char **) (defaults[i].location));
- break;
- }
-
- fprintf(f, "\n");
- }
-
- fclose (f);
-}
-
-// Parses integer values in the configuration file
-
-static int ParseIntParameter(char *strparm)
-{
- int parm;
-
- if (strparm[0] == '0' && strparm[1] == 'x')
- sscanf(strparm+2, "%x", &parm);
- else
- sscanf(strparm, "%i", &parm);
-
- return parm;
-}
-
-static void LoadDefaultCollection(default_collection_t *collection)
-{
- default_t *defaults = collection->defaults;
- int i;
- FILE* f;
- char defname[80];
- char strparm[100];
-
- // read the file in, overriding any set defaults
- f = fopen(collection->filename, "r");
-
- if (!f)
- {
- // File not opened, but don't complain
-
- return;
- }
-
- while (!feof(f))
- {
- if (fscanf (f, "%79s %[^\n]\n", defname, strparm) != 2)
- {
- // This line doesn't match
-
- continue;
- }
-
- // Strip off trailing non-printable characters (\r characters
- // from DOS text files)
-
- while (strlen(strparm) > 0 && !isprint(strparm[strlen(strparm)-1]))
- {
- strparm[strlen(strparm)-1] = '\0';
- }
-
- // Find the setting in the list
-
- for (i=0; i<collection->numdefaults; ++i)
- {
- default_t *def = &collection->defaults[i];
- char *s;
- int intparm;
-
- if (strcmp(defname, def->name) != 0)
- {
- // not this one
- continue;
- }
-
- // parameter found
-
- switch (def->type)
- {
- case DEFAULT_STRING:
- s = strdup(strparm + 1);
- s[strlen(s) - 1] = '\0';
- * (char **) def->location = s;
- break;
-
- case DEFAULT_INT:
- case DEFAULT_INT_HEX:
- * (int *) def->location = ParseIntParameter(strparm);
- break;
-
- case DEFAULT_KEY:
-
- // translate scancodes read from config
- // file (save the old value in untranslated)
-
- intparm = ParseIntParameter(strparm);
- defaults[i].untranslated = intparm;
-
- if (intparm >= 0 && intparm < 128)
- {
- intparm = scantokey[intparm];
- }
- else
- {
- intparm = 0;
- }
-
- defaults[i].original_translated = intparm;
- * (int *) def->location = intparm;
- break;
-
- case DEFAULT_FLOAT:
- * (float *) def->location = atof(strparm);
- break;
- }
-
- // finish
-
- break;
- }
- }
-
- fclose (f);
-}
-
-//
-// M_SaveDefaults
-//
-
-void M_SaveDefaults (void)
-{
- SaveDefaultCollection(&doom_defaults);
- SaveDefaultCollection(&extra_defaults);
-}
-
-
-//
-// M_LoadDefaults
-//
-
-void M_LoadDefaults (void)
-{
- int i;
-
- // check for a custom default file
- i = M_CheckParm ("-config");
-
- if (i && i<myargc-1)
- {
- doom_defaults.filename = myargv[i+1];
- printf (" default file: %s\n",doom_defaults.filename);
- }
- else
- {
- doom_defaults.filename = malloc(strlen(configdir) + 20);
- sprintf(doom_defaults.filename, "%sdefault.cfg", configdir);
- }
-
-// printf("saving config in %s\n", doom_defaults.filename);
-
- i = M_CheckParm("-extraconfig");
-
- if (i && i<myargc-1)
- {
- extra_defaults.filename = myargv[i+1];
- printf(" extra configuration file: %s\n",
- extra_defaults.filename);
- }
- else
- {
- extra_defaults.filename
- = malloc(strlen(configdir) + strlen(PROGRAM_PREFIX) + 15);
- sprintf(extra_defaults.filename, "%s%sdoom.cfg",
- configdir, PROGRAM_PREFIX);
- }
-
- LoadDefaultCollection(&doom_defaults);
- LoadDefaultCollection(&extra_defaults);
-}
-
-//
-// Save normal (default.cfg) defaults to a given file
-//
-
-void M_SaveMainDefaults(char *filename)
-{
- char *main_filename;
-
- // Save the normal filename and set this one
-
- main_filename = doom_defaults.filename;
- doom_defaults.filename = filename;
-
- // Save the file
-
- SaveDefaultCollection(&doom_defaults);
-
- // Restore the normal filename
-
- doom_defaults.filename = main_filename;
-}
-
-//
-// Save extra (chocolate-doom.cfg) defaults to a given file
-//
-
-void M_SaveExtraDefaults(char *filename)
-{
- char *main_filename;
-
- // Save the normal filename and set this one
-
- main_filename = extra_defaults.filename;
- extra_defaults.filename = filename;
-
- // Save the file
-
- SaveDefaultCollection(&extra_defaults);
-
- // Restore the normal filename
-
- extra_defaults.filename = main_filename;
-}
-
-#ifdef _WIN32_WCE
-
-static int SystemHasKeyboard(void)
-{
- HKEY key;
- DWORD valtype;
- DWORD valsize;
- DWORD result;
-
- if (RegOpenKeyExW(HKEY_CURRENT_USER,
- L"\\Software\\Microsoft\\Shell", 0,
- KEY_READ, &key) != ERROR_SUCCESS)
- {
- return 0;
- }
-
- valtype = REG_SZ;
- valsize = sizeof(DWORD);
-
- if (RegQueryValueExW(key, L"HasKeyboard", NULL, &valtype,
- (LPBYTE) &result, &valsize) != ERROR_SUCCESS)
- {
- result = 0;
- }
-
- // Close the key
-
- RegCloseKey(key);
-
- return result;
-}
-
-//
-// Apply custom defaults for Windows CE.
-//
-
-static void M_ApplyWindowsCEDefaults(void)
-{
- // If the system doesn't have a keyboard, patch the default
- // configuration to use the hardware keys.
-
- if (!SystemHasKeyboard())
- {
- key_use = KEY_F1;
- key_fire = KEY_F2;
- key_menu_activate = KEY_F3;
- key_map_toggle = KEY_F4;
-
- key_menu_help = 0;
- key_menu_save = 0;
- key_menu_load = 0;
- key_menu_volume = 0;
-
- key_menu_confirm = KEY_ENTER;
- key_menu_back = KEY_F2;
- key_menu_abort = KEY_F2;
- }
-}
-
-
-#endif
-
-//
-// Apply custom patches to the default values depending on the
-// platform we are running on.
-//
-
-void M_ApplyPlatformDefaults(void)
-{
-#ifdef _WIN32_WCE
- M_ApplyWindowsCEDefaults();
-#endif
-
- // Before SDL_mixer version 1.2.11, MIDI music caused the game
- // to crash when it looped. If this is an old SDL_mixer version,
- // disable MIDI.
-
-#ifdef __MACOSX__
- {
- const SDL_version *v = Mix_Linked_Version();
-
- if (SDL_VERSIONNUM(v->major, v->minor, v->patch)
- < SDL_VERSIONNUM(1, 2, 11))
- {
- snd_musicdevice = SNDDEVICE_NONE;
- }
- }
-#endif
-
- // Windows Vista or later? Set screen color depth to
- // 32 bits per pixel, as 8-bit palettized screen modes
- // don't work properly in recent versions.
-
-#if defined(_WIN32) && !defined(_WIN32_WCE)
- {
- OSVERSIONINFOEX version_info;
-
- ZeroMemory(&version_info, sizeof(OSVERSIONINFOEX));
- version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
-
- GetVersionEx((OSVERSIONINFO *) &version_info);
-
- if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT
- && version_info.dwMajorVersion >= 6)
- {
- screen_bpp = 32;
- }
- }
-#endif
-}
-
diff --git a/setup/sound.c b/setup/sound.c
deleted file mode 100644
index 7386e789..00000000
--- a/setup/sound.c
+++ /dev/null
@@ -1,178 +0,0 @@
-// Emacs style mode select -*- C++ -*-
-//-----------------------------------------------------------------------------
-//
-// Copyright(C) 2006 Simon Howard
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-// 02111-1307, USA.
-//
-
-// Sound control menu
-
-#include <stdlib.h>
-
-#include "textscreen.h"
-
-#include "sound.h"
-
-typedef enum
-{
- SFXMODE_DISABLED,
- SFXMODE_PCSPEAKER,
- SFXMODE_DIGITAL,
- NUM_SFXMODES
-} sfxmode_t;
-
-typedef enum
-{
- MUSMODE_DISABLED,
- MUSMODE_OPL,
- MUSMODE_NATIVE,
- NUM_MUSMODES
-} musmode_t;
-
-static char *sfxmode_strings[] =
-{
- "Disabled",
- "PC speaker",
- "Digital",
-};
-
-static char *musmode_strings[] =
-{
- "Disabled",
- "OPL (Adlib/SB)",
- "Native MIDI"
-};
-
-int snd_sfxdevice = SNDDEVICE_SB;
-int numChannels = 8;
-int sfxVolume = 8;
-
-int snd_musicdevice = SNDDEVICE_GENMIDI;
-int musicVolume = 8;
-
-int snd_samplerate = 44100;
-int opl_io_port = 0x388;
-
-int use_libsamplerate = 0;
-
-static int snd_sfxmode;
-static int snd_musmode;
-
-static void UpdateSndDevices(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(data))
-{
- switch (snd_sfxmode)
- {
- case SFXMODE_DISABLED:
- snd_sfxdevice = SNDDEVICE_NONE;
- break;
- case SFXMODE_PCSPEAKER:
- snd_sfxdevice = SNDDEVICE_PCSPEAKER;
- break;
- case SFXMODE_DIGITAL:
- snd_sfxdevice = SNDDEVICE_SB;
- break;
- }
-
- switch (snd_musmode)
- {
- case MUSMODE_DISABLED:
- snd_musicdevice = SNDDEVICE_NONE;
- break;
- case MUSMODE_OPL:
- snd_musicdevice = SNDDEVICE_SB;
- break;
- case MUSMODE_NATIVE:
- snd_musicdevice = SNDDEVICE_GENMIDI;
- break;
- }
-}
-
-void ConfigSound(void)
-{
- txt_window_t *window;
- txt_table_t *sfx_table;
- txt_table_t *music_table;
- txt_dropdown_list_t *sfx_mode_control;
- txt_dropdown_list_t *mus_mode_control;
-
- if (snd_sfxdevice == SNDDEVICE_PCSPEAKER)
- {
- snd_sfxmode = SFXMODE_PCSPEAKER;
- }
- else if (snd_sfxdevice >= SNDDEVICE_SB)
- {
- snd_sfxmode = SFXMODE_DIGITAL;
- }
- else
- {
- snd_sfxmode = SFXMODE_DISABLED;
- }
-
- if (snd_musicdevice == SNDDEVICE_GENMIDI)
- {
- snd_musmode = MUSMODE_NATIVE;
- }
- else if (snd_musicdevice == SNDDEVICE_SB
- || snd_musicdevice == SNDDEVICE_ADLIB
- || snd_musicdevice == SNDDEVICE_AWE32)
- {
- snd_musmode = MUSMODE_OPL;
- }
- else
- {
- snd_musmode = MUSMODE_DISABLED;
- }
-
- window = TXT_NewWindow("Sound configuration");
-
- TXT_AddWidgets(window,
- TXT_NewSeparator("Sound effects"),
- sfx_table = TXT_NewTable(2),
- TXT_NewSeparator("Music"),
- music_table = TXT_NewTable(2),
- NULL);
-
- TXT_SetColumnWidths(sfx_table, 20, 14);
-
- TXT_AddWidgets(sfx_table,
- TXT_NewLabel("Sound effects"),
- sfx_mode_control = TXT_NewDropdownList(&snd_sfxmode,
- sfxmode_strings,
- NUM_SFXMODES),
- TXT_NewLabel("Sound channels"),
- TXT_NewSpinControl(&numChannels, 1, 8),
- TXT_NewLabel("SFX volume"),
- TXT_NewSpinControl(&sfxVolume, 0, 15),
- NULL);
-
- TXT_SetColumnWidths(music_table, 20, 14);
-
- TXT_AddWidgets(music_table,
- TXT_NewLabel("Music playback"),
- mus_mode_control = TXT_NewDropdownList(&snd_musmode,
- musmode_strings,
- NUM_MUSMODES),
- TXT_NewLabel("Music volume"),
- TXT_NewSpinControl(&musicVolume, 0, 15),
- NULL);
-
- TXT_SignalConnect(sfx_mode_control, "changed",
- UpdateSndDevices, NULL);
- TXT_SignalConnect(mus_mode_control, "changed",
- UpdateSndDevices, NULL);
-}
-
diff --git a/setup/sound.h b/setup/sound.h
deleted file mode 100644
index eb386d6f..00000000
--- a/setup/sound.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Emacs style mode select -*- C++ -*-
-//-----------------------------------------------------------------------------
-//
-// Copyright(C) 2006 Simon Howard
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-// 02111-1307, USA.
-//
-
-#ifndef SETUP_SOUND_H
-#define SETUP_SOUND_H
-
-enum
-{
- SNDDEVICE_NONE = 0,
- SNDDEVICE_PCSPEAKER = 1,
- SNDDEVICE_ADLIB = 2,
- SNDDEVICE_SB = 3,
- SNDDEVICE_PAS = 4,
- SNDDEVICE_GUS = 5,
- SNDDEVICE_WAVEBLASTER = 6,
- SNDDEVICE_SOUNDCANVAS = 7,
- SNDDEVICE_GENMIDI = 8,
- SNDDEVICE_AWE32 = 9,
-};
-
-extern int snd_sfxdevice;
-extern int numChannels;
-extern int sfxVolume;
-
-extern int snd_musicdevice;
-extern int musicVolume;
-
-extern int snd_samplerate;
-extern int opl_io_port;
-
-extern int use_libsamplerate;
-
-void ConfigSound(void);
-
-#endif /* #ifndef SETUP_SOUND_H */
-
diff --git a/src/.gitignore b/src/.gitignore
index 2c4a3c48..aa8a4c05 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -3,7 +3,10 @@ Makefile.in
.deps
*.rc
chocolate-doom
+chocolate-heretic
+chocolate-hexen
chocolate-server
+chocolate-setup
*.exe
*.desktop
tags
diff --git a/src/Makefile.am b/src/Makefile.am
index 25766ca0..b9112c21 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,16 +1,34 @@
+SUBDIRS=doom heretic hexen strife setup
+
gamesdir = $(prefix)/games
-games_PROGRAMS = @PROGRAM_PREFIX@doom @PROGRAM_PREFIX@server
+games_PROGRAMS = @PROGRAM_PREFIX@doom \
+ @PROGRAM_PREFIX@heretic \
+ @PROGRAM_PREFIX@hexen \
+ @PROGRAM_PREFIX@strife \
+ @PROGRAM_PREFIX@server \
+ @PROGRAM_PREFIX@setup
+
+AM_CFLAGS = -I$(top_builddir)/textscreen \
+ -I$(top_builddir)/opl \
+ -I$(top_builddir)/pcsound \
+ @SDLMIXER_CFLAGS@ @SDLNET_CFLAGS@
+
+# Common source files used by absolutely everything:
+
+COMMON_SOURCE_FILES=\
+i_main.c \
+i_system.c i_system.h \
+m_argv.c m_argv.h \
+m_misc.c m_misc.h
-AM_CFLAGS = -I../opl -I../textscreen -I../pcsound @SDLMIXER_CFLAGS@ @SDLNET_CFLAGS@
+# Dedicated server (chocolate-server):
DEDSERV_FILES=\
d_dedicated.c \
-i_main.c \
+d_mode.c d_mode.h \
i_timer.c i_timer.h \
-m_argv.c m_argv.h \
-m_misc.c m_misc.h \
net_common.c net_common.h \
net_dedicated.c net_dedicated.h \
net_io.c net_io.h \
@@ -21,113 +39,58 @@ net_server.c net_server.h \
net_structrw.c net_structrw.h \
z_native.c z_zone.h
-@PROGRAM_PREFIX@server_SOURCES=$(DEDSERV_FILES)
-@PROGRAM_PREFIX@server_LDADD = ../wince/libc_wince.a @LDFLAGS@ @SDLNET_LIBS@
+@PROGRAM_PREFIX@server_SOURCES=$(COMMON_SOURCE_FILES) $(DEDSERV_FILES)
+@PROGRAM_PREFIX@server_LDADD = $(top_builddir)/wince/libc_wince.a \
+ @LDFLAGS@ @SDLNET_LIBS@
-MAIN_SOURCE_FILES=\
-am_map.c am_map.h \
-d_englsh.h \
-d_event.h \
-d_items.c d_items.h \
+# Source files used by the game binaries (chocolate-doom, etc.)
+
+GAME_SOURCE_FILES=\
+d_event.c d_event.h \
+ doomkeys.h \
+ doomfeatures.h \
+ doomtype.h \
d_iwad.c d_iwad.h \
-d_main.c d_main.h \
-d_net.c d_net.h \
-doomdata.h \
-doomdef.c doomdef.h \
-doomkeys.h \
-doomfeatures.h \
-doomstat.c doomstat.h \
-doomtype.h \
-d_player.h \
-dstrings.c dstrings.h \
-d_textur.h \
-d_think.h \
-d_ticcmd.h \
-f_finale.c f_finale.h \
-f_wipe.c f_wipe.h \
-g_game.c g_game.h \
-hu_lib.c hu_lib.h \
-hu_stuff.c hu_stuff.h \
-i_main.c \
-info.c info.h \
+d_loop.c d_loop.h \
+d_mode.c d_mode.h \
+ d_ticcmd.h \
+deh_str.c deh_str.h \
+i_cdmus.c i_cdmus.h \
+i_endoom.c i_endoom.h \
i_joystick.c i_joystick.h \
i_scale.c i_scale.h \
i_swap.h \
-i_system.c i_system.h \
+i_sound.c i_sound.h \
i_timer.c i_timer.h \
i_video.c i_video.h \
-m_argv.c m_argv.h \
+i_videohr.c i_videohr.h \
m_bbox.c m_bbox.h \
m_cheat.c m_cheat.h \
m_config.c m_config.h \
+m_controls.c m_controls.h \
m_fixed.c m_fixed.h \
-m_menu.c m_menu.h \
-m_misc.c m_misc.h \
sha1.c sha1.h \
memio.c memio.h \
-m_random.c m_random.h \
-p_ceilng.c \
-p_doors.c \
-p_enemy.c \
-p_floor.c \
-p_inter.c p_inter.h \
-p_lights.c \
-p_local.h \
-p_map.c \
-p_maputl.c \
-p_mobj.c p_mobj.h \
-p_plats.c \
-p_pspr.c p_pspr.h \
-p_saveg.c p_saveg.h \
-p_setup.c p_setup.h \
-p_sight.c \
-p_spec.c p_spec.h \
-p_switch.c \
-p_telept.c \
-p_tick.c p_tick.h \
-p_user.c \
-r_bsp.c r_bsp.h \
-r_data.c r_data.h \
-r_defs.h \
-r_draw.c r_draw.h \
-r_local.h \
-r_main.c r_main.h \
-r_plane.c r_plane.h \
-r_segs.c r_segs.h \
-r_sky.c r_sky.h \
-r_state.h \
-r_things.c r_things.h \
-sounds.c sounds.h \
-s_sound.c s_sound.h \
-st_lib.c st_lib.h \
-st_stuff.c st_stuff.h \
tables.c tables.h \
v_video.c v_video.h \
-wi_stuff.c wi_stuff.h \
+ v_patch.h \
w_checksum.c w_checksum.h \
+w_main.c w_main.h \
w_wad.c w_wad.h \
w_file.c w_file.h \
w_file_stdc.c \
w_file_posix.c \
w_file_win32.c \
-z_zone.c z_zone.h
+z_zone.c z_zone.h
# source files needed for FEATURE_DEHACKED
-FEATURE_DEHACKED_SOURCE_FILES= \
-deh_ammo.c \
-deh_cheat.c \
+FEATURE_DEHACKED_SOURCE_FILES = \
deh_defs.h \
-deh_frame.c \
deh_io.c deh_io.h \
deh_main.c deh_main.h \
deh_mapping.c deh_mapping.h \
-deh_misc.c deh_misc.h \
-deh_ptr.c \
-deh_sound.c \
-deh_text.c \
-deh_thing.c \
-deh_weapon.c
+deh_text.c
# source files needed for FEATURE_MULTIPLAYER
@@ -154,6 +117,7 @@ w_merge.c w_merge.h
# source files needed for FEATURE_SOUND
FEATURE_SOUND_SOURCE_FILES = \
+gusconf.c gusconf.h \
i_pcsound.c \
i_sdlsound.c \
i_sdlmusic.c \
@@ -161,28 +125,88 @@ i_oplmusic.c \
midifile.c midifile.h \
mus2mid.c mus2mid.h
-SOURCE_FILES = $(MAIN_SOURCE_FILES) \
- $(FEATURE_DEHACKED_SOURCE_FILES) \
- $(FEATURE_MULTIPLAYER_SOURCE_FILES) \
+# Some games support dehacked patches, some don't:
+
+SOURCE_FILES = $(COMMON_SOURCE_FILES) \
+ $(GAME_SOURCE_FILES) \
$(FEATURE_WAD_MERGE_SOURCE_FILES) \
- $(FEATURE_SOUND_SOURCE_FILES)
+ $(FEATURE_SOUND_SOURCE_FILES) \
+ $(FEATURE_MULTIPLAYER_SOURCE_FILES)
+
+SOURCE_FILES_WITH_DEH = $(SOURCE_FILES) \
+ $(FEATURE_DEHACKED_SOURCE_FILES)
+
+EXTRA_LIBS = \
+ $(top_builddir)/wince/libc_wince.a \
+ $(top_builddir)/textscreen/libtextscreen.a \
+ $(top_builddir)/pcsound/libpcsound.a \
+ $(top_builddir)/opl/libopl.a \
+ @LDFLAGS@ \
+ @SDL_LIBS@ \
+ @SDLMIXER_LIBS@ \
+ @SDLNET_LIBS@
if HAVE_WINDRES
-@PROGRAM_PREFIX@doom_SOURCES=$(SOURCE_FILES) resource.rc
+@PROGRAM_PREFIX@doom_SOURCES=$(SOURCE_FILES_WITH_DEH) resource.rc
else
-@PROGRAM_PREFIX@doom_SOURCES=$(SOURCE_FILES)
+@PROGRAM_PREFIX@doom_SOURCES=$(SOURCE_FILES_WITH_DEH)
endif
-@PROGRAM_PREFIX@doom_LDADD = \
- ../wince/libc_wince.a \
- ../textscreen/libtextscreen.a \
- ../pcsound/libpcsound.a \
- ../opl/libopl.a \
- @LDFLAGS@ \
- @SDLMIXER_LIBS@ \
- @SDLNET_LIBS@
+@PROGRAM_PREFIX@doom_LDADD = doom/libdoom.a $(EXTRA_LIBS)
+
+if HAVE_WINDRES
+@PROGRAM_PREFIX@heretic_SOURCES=$(SOURCE_FILES_WITH_DEH) resource.rc
+else
+@PROGRAM_PREFIX@heretic_SOURCES=$(SOURCE_FILES_WITH_DEH)
+endif
+
+@PROGRAM_PREFIX@heretic_LDADD = heretic/libheretic.a $(EXTRA_LIBS)
+
+if HAVE_WINDRES
+@PROGRAM_PREFIX@hexen_SOURCES=$(SOURCE_FILES) resource.rc
+else
+@PROGRAM_PREFIX@hexen_SOURCES=$(SOURCE_FILES)
+endif
-EXTRA_DIST = icon.c
+@PROGRAM_PREFIX@hexen_LDADD = hexen/libhexen.a $(EXTRA_LIBS)
+
+if HAVE_WINDRES
+@PROGRAM_PREFIX@strife_SOURCES=$(SOURCE_FILES_WITH_DEH) resource.rc
+else
+@PROGRAM_PREFIX@strife_SOURCES=$(SOURCE_FILES_WITH_DEH)
+endif
+
+@PROGRAM_PREFIX@strife_LDADD = strife/libstrife.a $(EXTRA_LIBS)
+
+# Source files needed for chocolate-setup:
+
+SETUP_FILES= \
+deh_str.c deh_str.h \
+d_mode.c d_mode.h \
+d_iwad.c d_iwad.h \
+i_timer.c i_timer.h \
+m_config.c m_config.h \
+m_controls.c m_controls.h \
+net_io.c net_io.h \
+net_packet.c net_packet.h \
+net_sdl.c net_sdl.h \
+net_query.c net_query.h \
+net_structrw.c net_structrw.h \
+z_native.c z_zone.h
+
+if HAVE_WINDRES
+@PROGRAM_PREFIX@setup_SOURCES=$(SETUP_FILES) $(COMMON_SOURCE_FILES) setup-res.rc
+else
+@PROGRAM_PREFIX@setup_SOURCES=$(SETUP_FILES) $(COMMON_SOURCE_FILES)
+endif
+@PROGRAM_PREFIX@setup_LDADD = setup/libsetup.a \
+ $(top_builddir)/wince/libc_wince.a \
+ $(top_builddir)/textscreen/libtextscreen.a \
+ @LDFLAGS@ @SDL_LIBS@ @SDLMIXER_LIBS@ @SDLNET_LIBS@
+
+EXTRA_DIST = \
+ icon.c \
+ doom-screensaver.desktop.in
appdir = $(prefix)/share/applications
app_DATA = @PROGRAM_PREFIX@doom.desktop
@@ -203,11 +227,14 @@ screensaver_DATA = @PROGRAM_PREFIX@doom-screensaver.desktop
if HAVE_PYTHON
-icon.c : ../data/doom8.ico
- ../data/convert-icon $< $@
+icon.c : $(top_builddir)/data/doom8.ico
+ $(top_builddir)/data/convert-icon $< $@
endif
midiread : midifile.c
$(CC) -DTEST $(CFLAGS) @LDFLAGS@ $< -o $@
+mus2mid : mus2mid.c memio.c z_native.c i_system.c m_argv.c m_misc.c
+ $(CC) -DSTANDALONE -I$(top_builddir) $(CFLAGS) @LDFLAGS@ $^ -o $@
+
diff --git a/src/d_dedicated.c b/src/d_dedicated.c
index 100c9b22..defe8083 100644
--- a/src/d_dedicated.c
+++ b/src/d_dedicated.c
@@ -21,6 +21,7 @@
// Code specific to the standalone dedicated server.
//
+#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
@@ -42,29 +43,6 @@ void NET_CL_Run(void)
// In a standalone dedicated server, we don't have a client.
}
-//
-// I_Error
-//
-// We have our own I_Error function for the dedicated server.
-// The normal one does extra things like shutdown graphics, etc.
-
-void I_Error (char *error, ...)
-{
- va_list argptr;
-
- // Message first.
- va_start(argptr,error);
- fprintf(stderr, "Error: ");
- vfprintf(stderr,error,argptr);
- fprintf(stderr, "\n");
- va_end(argptr);
-
- fflush(stderr);
-
- exit(-1);
-}
-
-
void D_DoomMain(void)
{
printf(PACKAGE_NAME " standalone dedicated server\n");
diff --git a/src/d_event.c b/src/d_event.c
new file mode 100644
index 00000000..a6faa85d
--- /dev/null
+++ b/src/d_event.c
@@ -0,0 +1,72 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// DESCRIPTION: Event handling.
+//
+// Events are asynchronous inputs generally generated by the game user.
+// Events can be discarded if no responder claims them
+//
+//-----------------------------------------------------------------------------
+
+#include <stdlib.h>
+#include "d_event.h"
+
+#define MAXEVENTS 64
+
+static event_t events[MAXEVENTS];
+static int eventhead;
+static int eventtail;
+
+//
+// D_PostEvent
+// Called by the I/O functions when input is detected
+//
+void D_PostEvent (event_t* ev)
+{
+ events[eventhead] = *ev;
+ eventhead = (eventhead + 1) % MAXEVENTS;
+}
+
+// Read an event from the queue.
+
+event_t *D_PopEvent(void)
+{
+ event_t *result;
+
+ // No more events waiting.
+
+ if (eventtail == eventhead)
+ {
+ return NULL;
+ }
+
+ result = &events[eventtail];
+
+ // Advance to the next event in the queue.
+
+ eventtail = (eventtail + 1) % MAXEVENTS;
+
+ return result;
+}
+
+
diff --git a/src/d_event.h b/src/d_event.h
index 4578870f..25334a96 100644
--- a/src/d_event.h
+++ b/src/d_event.h
@@ -42,7 +42,8 @@ typedef enum
ev_keydown,
ev_keyup,
ev_mouse,
- ev_joystick
+ ev_joystick,
+ ev_quit
} evtype_t;
// Event structure.
@@ -55,22 +56,6 @@ typedef struct
} 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.
//
@@ -104,14 +89,37 @@ typedef enum
} buttoncode_t;
+// villsa [STRIFE] Strife specific buttons
+// TODO - not finished
+typedef enum
+{
+ // Player view look up
+ BT2_LOOKUP = 1,
+ // Player view look down
+ BT2_LOOKDOWN = 2,
+ // Center player's view
+ BT2_CENTERVIEW = 4,
+ // Use inventory item
+ BT2_INVUSE = 8,
+ // Drop inventory item
+ BT2_INVDROP = 16,
+ // Jump up and down
+ BT2_JUMP = 32,
+ // Use medkit
+ BT2_HEALTH = 128,
+
+} buttoncode2_t;
-//
-// GLOBAL VARIABLES
-//
-extern gameaction_t gameaction;
+// Called by IO functions when input is detected.
+void D_PostEvent (event_t *ev);
+
+// Read an event from the event queue
+
+event_t *D_PopEvent(void);
#endif
+
diff --git a/src/d_iwad.c b/src/d_iwad.c
index a810f2a2..7e850d53 100644
--- a/src/d_iwad.c
+++ b/src/d_iwad.c
@@ -29,9 +29,9 @@
#include <ctype.h>
#include <string.h>
-#include "deh_main.h"
-#include "doomdef.h"
-#include "doomstat.h"
+#include "deh_str.h"
+#include "doomkeys.h"
+#include "d_iwad.h"
#include "i_system.h"
#include "m_argv.h"
#include "m_config.h"
@@ -39,6 +39,22 @@
#include "w_wad.h"
#include "z_zone.h"
+static iwad_t iwads[] =
+{
+ { "doom2.wad", doom2, commercial, "Doom II" },
+ { "plutonia.wad", pack_plut, commercial, "Final Doom: Plutonia Experiment" },
+ { "tnt.wad", pack_tnt, commercial, "Final Doom: TNT: Evilution" },
+ { "doom.wad", doom, retail, "Doom" },
+ { "doom1.wad", doom, shareware, "Doom Shareware" },
+ { "chex.wad", pack_chex, shareware, "Chex Quest" },
+ { "hacx.wad", pack_hacx, commercial, "Hacx" },
+ { "heretic.wad", heretic, retail, "Heretic" },
+ { "heretic1.wad", heretic, shareware, "Heretic Shareware" },
+ { "hexen.wad", hexen, commercial, "Hexen" },
+ //{ "strife0.wad", strife, commercial, "Strife" }, // haleyjd: STRIFE-FIXME
+ { "strife1.wad", strife, commercial, "Strife" },
+};
+
// Array of locations to search for IWAD files
//
// "128 IWAD search directories should be enough for anybody".
@@ -157,6 +173,8 @@ static char *steam_install_subdirs[] =
"steamapps\\common\\doom 2\\base",
"steamapps\\common\\final doom\\base",
"steamapps\\common\\ultimate doom\\base",
+ "steamapps\\common\\hexen\\base",
+ "steamapps\\common\\heretic shadow of the serpent riders\\base"
// From Doom 3: BFG Edition:
@@ -315,35 +333,6 @@ static void CheckDOSDefaults(void)
#endif
-static struct
-{
- char *name;
- GameMission_t mission;
-} iwads[] = {
- {"doom2.wad", doom2},
- {"plutonia.wad", pack_plut},
- {"tnt.wad", pack_tnt},
- {"doom.wad", doom},
- {"doom1.wad", doom},
- {"chex.wad", doom},
- {"hacx.wad", doom2},
-};
-
-// Hack for chex quest mode
-
-static void CheckSpecialIWADs(char *iwad_name)
-{
- if (!strcasecmp(iwad_name, "chex.wad"))
- {
- gameversion = exe_chex;
- }
-
- if (!strcasecmp(iwad_name, "hacx.wad"))
- {
- gameversion = exe_hacx;
- }
-}
-
// Returns true if the specified path is a path to a file
// of the specified name.
@@ -403,19 +392,23 @@ static char *CheckDirectoryHasIWAD(char *dir, char *iwadname)
// Search a directory to try to find an IWAD
// Returns the location of the IWAD if found, otherwise NULL.
-static char *SearchDirectoryForIWAD(char *dir)
+static char *SearchDirectoryForIWAD(char *dir, int mask, GameMission_t *mission)
{
char *filename;
size_t i;
for (i=0; i<arrlen(iwads); ++i)
{
+ if (((1 << iwads[i].mission) & mask) == 0)
+ {
+ continue;
+ }
+
filename = CheckDirectoryHasIWAD(dir, DEH_String(iwads[i].name));
if (filename != NULL)
{
- CheckSpecialIWADs(iwads[i].name);
- gamemission = iwads[i].mission;
+ *mission = iwads[i].mission;
return filename;
}
@@ -427,13 +420,12 @@ static char *SearchDirectoryForIWAD(char *dir)
// When given an IWAD with the '-iwad' parameter,
// attempt to identify it by its name.
-static void IdentifyIWADByName(char *name)
+static GameMission_t IdentifyIWADByName(char *name, int mask)
{
size_t i;
+ GameMission_t mission;
char *p;
- // Trim down the name to just the filename, ignoring the path.
-
p = strrchr(name, DIR_SEPARATOR);
if (p != NULL)
@@ -441,24 +433,32 @@ static void IdentifyIWADByName(char *name)
name = p + 1;
}
- gamemission = none;
+ mission = none;
for (i=0; i<arrlen(iwads); ++i)
{
// Check if the filename is this IWAD name.
- if (!strcasecmp(name, DEH_String(iwads[i].name)))
+ // Only use supported missions:
+
+ if (((1 << iwads[i].mission) & mask) == 0)
+ continue;
+
+ // Check if it ends in this IWAD name.
+
+ if (!strcasecmp(name, iwads[i].name))
{
- CheckSpecialIWADs(iwads[i].name);
- gamemission = iwads[i].mission;
+ mission = iwads[i].mission;
break;
}
}
+
+ return mission;
}
//
// Add directories from the list in the DOOMWADPATH environment variable.
-//
+//
static void AddDoomWadPath(void)
{
@@ -645,7 +645,7 @@ char *D_TryFindWADByName(char *filename)
// should be executed (notably loading PWADs).
//
-char *D_FindIWAD(void)
+char *D_FindIWAD(int mask, GameMission_t *mission)
{
char *result;
char *iwadfile;
@@ -675,7 +675,7 @@ char *D_FindIWAD(void)
I_Error("IWAD file '%s' not found!", iwadfile);
}
- IdentifyIWADByName(result);
+ *mission = IdentifyIWADByName(result, mask);
}
else
{
@@ -687,300 +687,105 @@ char *D_FindIWAD(void)
for (i=0; result == NULL && i<num_iwad_dirs; ++i)
{
- result = SearchDirectoryForIWAD(iwad_dirs[i]);
+ result = SearchDirectoryForIWAD(iwad_dirs[i], mask, mission);
}
}
return result;
}
-//
-// Get the IWAD name used for savegames.
-//
+// Find all IWADs in the IWAD search path matching the given mask.
-static char *SaveGameIWADName(void)
+iwad_t **D_FindAllIWADs(int mask)
{
- size_t i;
-
- // Chex quest hack
-
- if (gameversion == exe_chex)
- {
- return "chex.wad";
- }
+ iwad_t **result;
+ int result_len;
+ char *filename;
+ int i;
- // Hacx hack
+ result = malloc(sizeof(iwad_t *) * (arrlen(iwads) + 1));
+ result_len = 0;
- if (gameversion == exe_hacx)
- {
- return "hacx.wad";
- }
-
- // Find what subdirectory to use for savegames
- //
- // They should be stored in something like
- // ~/.chocolate-doom/savegames/doom.wad/
- //
- // The directory depends on the IWAD, so that savegames for
- // different IWADs are kept separate.
- //
- // Note that we match on gamemission rather than on IWAD name.
- // This ensures that doom1.wad and doom.wad saves are stored
- // in the same place.
+ // Try to find all IWADs
for (i=0; i<arrlen(iwads); ++i)
{
- if (gamemission == iwads[i].mission)
+ if (((1 << iwads[i].mission) & mask) == 0)
{
- return iwads[i].name;
+ continue;
}
- }
-
- return NULL;
-}
-//
-// SetSaveGameDir
-//
-// Chooses the directory used to store saved games.
-//
-
-void D_SetSaveGameDir(void)
-{
- char *iwad_name;
- if (!strcmp(configdir, ""))
- {
- // Use the current directory, just like configdir.
+ filename = D_FindWADByName(iwads[i].name);
- savegamedir = strdup("");
- }
- else
- {
- // Directory for savegames
-
- iwad_name = SaveGameIWADName();
-
- if (iwad_name == NULL)
+ if (filename != NULL)
{
- iwad_name = "unknown.wad";
+ result[result_len] = &iwads[i];
+ ++result_len;
}
+ }
- savegamedir = Z_Malloc(strlen(configdir) + 30, PU_STATIC, 0);
- sprintf(savegamedir, "%ssavegames%c", configdir,
- DIR_SEPARATOR);
-
- M_MakeDirectory(savegamedir);
+ // End of list
- sprintf(savegamedir + strlen(savegamedir), "%s%c",
- iwad_name, DIR_SEPARATOR);
+ result[result_len] = NULL;
- M_MakeDirectory(savegamedir);
- }
+ return result;
}
-// Strings for dehacked replacements of the startup banner
//
-// These are from the original source: some of them are perhaps
-// not used in any dehacked patches
-
-static char *banners[] =
-{
- // doom2.wad
- " "
- "DOOM 2: Hell on Earth v%i.%i"
- " ",
- // doom1.wad
- " "
- "DOOM Shareware Startup v%i.%i"
- " ",
- // doom.wad
- " "
- "DOOM Registered Startup v%i.%i"
- " ",
- // Registered DOOM uses this
- " "
- "DOOM System Startup v%i.%i"
- " ",
- // doom.wad (Ultimate DOOM)
- " "
- "The Ultimate DOOM Startup v%i.%i"
- " ",
- // tnt.wad
- " "
- "DOOM 2: TNT - Evilution v%i.%i"
- " ",
- // plutonia.wad
- " "
- "DOOM 2: Plutonia Experiment v%i.%i"
- " ",
-};
-
+// Get the IWAD name used for savegames.
//
-// Get game name: if the startup banner has been replaced, use that.
-// Otherwise, use the name given
-//
-static char *GetGameName(char *gamename)
+char *D_SaveGameIWADName(GameMission_t gamemission)
{
size_t i;
- char *deh_sub;
-
- for (i=0; i<arrlen(banners); ++i)
- {
- // Has the banner been replaced?
-
- deh_sub = DEH_String(banners[i]);
-
- if (deh_sub != banners[i])
- {
- // Has been replaced
- // We need to expand via printf to include the Doom version
- // number
- // We also need to cut off spaces to get the basic name
-
- gamename = Z_Malloc(strlen(deh_sub) + 10, PU_STATIC, 0);
- sprintf(gamename, deh_sub, DOOM_VERSION / 100, DOOM_VERSION % 100);
-
- while (gamename[0] != '\0' && isspace(gamename[0]))
- strcpy(gamename, gamename+1);
-
- while (gamename[0] != '\0' && isspace(gamename[strlen(gamename)-1]))
- gamename[strlen(gamename) - 1] = '\0';
-
- return gamename;
- }
- }
- return gamename;
-}
-
-
-//
-// Find out what version of Doom is playing.
-//
-
-void D_IdentifyVersion(void)
-{
- // gamemission is set up by the D_FindIWAD function. But if
- // we specify '-iwad', we have to identify using
- // IdentifyIWADByName. However, if the iwad does not match
- // any known IWAD name, we may have a dilemma. Try to
- // identify by its contents.
+ // Determine the IWAD name to use for savegames.
+ // This determines the directory the savegame files get put into.
+ //
+ // Note that we match on gamemission rather than on IWAD name.
+ // This ensures that doom1.wad and doom.wad saves are stored
+ // in the same place.
- if (gamemission == none)
+ for (i=0; i<arrlen(iwads); ++i)
{
- unsigned int i;
-
- for (i=0; i<numlumps; ++i)
- {
- if (!strncasecmp(lumpinfo[i].name, "MAP01", 8))
- {
- gamemission = doom2;
- break;
- }
- else if (!strncasecmp(lumpinfo[i].name, "E1M1", 8))
- {
- gamemission = doom;
- break;
- }
- }
-
- if (gamemission == none)
+ if (gamemission == iwads[i].mission)
{
- // Still no idea. I don't think this is going to work.
-
- I_Error("Unknown or invalid IWAD file.");
+ return iwads[i].name;
}
}
- // Make sure gamemode is set up correctly
+ // Default fallback:
- if (gamemission == doom)
- {
- // Doom 1. But which version?
-
- if (W_CheckNumForName("E4M1") > 0)
- {
- // Ultimate Doom
-
- gamemode = retail;
- }
- else if (W_CheckNumForName("E3M1") > 0)
- {
- gamemode = registered;
- }
- else
- {
- gamemode = shareware;
- }
- }
- else
- {
- // Doom 2 of some kind.
-
- gamemode = commercial;
- }
+ return "unknown.wad";
}
-// Set the gamedescription string
-
-void D_SetGameDescription(void)
+char *D_SuggestIWADName(GameMission_t mission, GameMode_t mode)
{
- gamedescription = "Unknown";
+ int i;
- if (gamemission == doom)
+ for (i = 0; i < arrlen(iwads); ++i)
{
- // Doom 1. But which version?
-
- if (gamemode == retail)
+ if (iwads[i].mission == mission && iwads[i].mode == mode)
{
- // Ultimate Doom
-
- gamedescription = GetGameName("The Ultimate DOOM");
- }
- else if (gamemode == registered)
- {
- gamedescription = GetGameName("DOOM Registered");
- }
- else if (gamemode == shareware)
- {
- gamedescription = GetGameName("DOOM Shareware");
+ return iwads[i].name;
}
}
- else
- {
- // Doom 2 of some kind. But which mission?
- if (gamemission == doom2)
- gamedescription = GetGameName("DOOM 2: Hell on Earth");
- else if (gamemission == pack_plut)
- gamedescription = GetGameName("DOOM 2: Plutonia Experiment");
- else if (gamemission == pack_tnt)
- gamedescription = GetGameName("DOOM 2: TNT - Evilution");
- }
+ return "unknown.wad";
}
-// Clever hack: Setup can invoke Doom to determine which IWADs are installed.
-// Doom searches install paths and exits with the return code being a
-// bitmask of the installed IWAD files.
-
-void D_FindInstalledIWADs(void)
+char *D_SuggestGameName(GameMission_t mission, GameMode_t mode)
{
- unsigned int i;
- int result;
-
- BuildIWADDirList();
-
- result = 0;
+ int i;
- for (i=0; i<arrlen(iwads); ++i)
+ for (i = 0; i < arrlen(iwads); ++i)
{
- if (D_FindWADByName(iwads[i].name) != NULL)
+ if (iwads[i].mission == mission && iwads[i].mode == mode)
{
- result |= 1 << i;
+ return iwads[i].description;
}
}
- exit(result);
+ return "Unknown game?";
}
diff --git a/src/d_iwad.h b/src/d_iwad.h
index cb101305..97eaf3eb 100644
--- a/src/d_iwad.h
+++ b/src/d_iwad.h
@@ -27,13 +27,33 @@
#ifndef __D_IWAD__
#define __D_IWAD__
+#include "d_mode.h"
+
+#define IWAD_MASK_DOOM ((1 << doom) \
+ | (1 << doom2) \
+ | (1 << pack_tnt) \
+ | (1 << pack_plut) \
+ | (1 << pack_chex) \
+ | (1 << pack_hacx))
+#define IWAD_MASK_HERETIC (1 << heretic)
+#define IWAD_MASK_HEXEN (1 << hexen)
+#define IWAD_MASK_STRIFE (1 << strife)
+
+typedef struct
+{
+ char *name;
+ GameMission_t mission;
+ GameMode_t mode;
+ char *description;
+} iwad_t;
+
char *D_FindWADByName(char *filename);
char *D_TryFindWADByName(char *filename);
-char *D_FindIWAD(void);
-void D_SetSaveGameDir(void);
-void D_IdentifyVersion(void);
-void D_SetGameDescription(void);
-void D_FindInstalledIWADs(void);
+char *D_FindIWAD(int mask, GameMission_t *mission);
+iwad_t **D_FindAllIWADs(int mask);
+char *D_SaveGameIWADName(GameMission_t gamemission);
+char *D_SuggestIWADName(GameMission_t mission, GameMode_t mode);
+char *D_SuggestGameName(GameMission_t mission, GameMode_t mode);
#endif
diff --git a/src/d_loop.c b/src/d_loop.c
new file mode 100644
index 00000000..0206e85a
--- /dev/null
+++ b/src/d_loop.c
@@ -0,0 +1,752 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Main loop code.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "doomfeatures.h"
+
+#include "d_event.h"
+#include "d_loop.h"
+#include "d_ticcmd.h"
+
+#include "i_system.h"
+#include "i_timer.h"
+#include "i_video.h"
+
+#include "m_argv.h"
+#include "m_fixed.h"
+
+#include "net_client.h"
+#include "net_gui.h"
+#include "net_io.h"
+#include "net_query.h"
+#include "net_server.h"
+#include "net_sdl.h"
+#include "net_loop.h"
+
+// The complete set of data for a particular tic.
+
+typedef struct
+{
+ ticcmd_t cmds[NET_MAXPLAYERS];
+ boolean ingame[NET_MAXPLAYERS];
+} ticcmd_set_t;
+
+//
+// gametic is the tic about to (or currently being) run
+// maketic is the tic that hasn't had control made for it yet
+// recvtic is the latest tic received from the server.
+//
+// a gametic cannot be run until ticcmds are received for it
+// from all players.
+//
+
+static ticcmd_set_t ticdata[BACKUPTICS];
+
+// The index of the next tic to be made (with a call to BuildTiccmd).
+
+static int maketic;
+
+// The number of complete tics received from the server so far.
+
+static int recvtic;
+
+// The number of tics that have been run (using RunTic) so far.
+
+int gametic;
+
+// When set to true, a single tic is run each time TryRunTics() is called.
+// This is used for -timedemo mode.
+
+boolean singletics = false;
+
+// Index of the local player.
+
+static int localplayer;
+
+// Used for original sync code.
+
+static int skiptics = 0;
+
+// Reduce the bandwidth needed by sampling game input less and transmitting
+// less. If ticdup is 2, sample half normal, 3 = one third normal, etc.
+
+int ticdup;
+
+// Amount to offset the timer for game sync.
+
+fixed_t offsetms;
+
+// Use new client syncronisation code
+
+static boolean new_sync = true;
+
+// Callback functions for loop code.
+
+static loop_interface_t *loop_interface = NULL;
+
+// Current players in the multiplayer game.
+// This is distinct from playeringame[] used by the game code, which may
+// modify playeringame[] when playing back multiplayer demos.
+
+static boolean local_playeringame[NET_MAXPLAYERS];
+
+
+// 35 fps clock adjusted by offsetms milliseconds
+
+static int GetAdjustedTime(void)
+{
+ int time_ms;
+
+ time_ms = I_GetTimeMS();
+
+ if (new_sync)
+ {
+ // Use the adjustments from net_client.c only if we are
+ // using the new sync mode.
+
+ time_ms += (offsetms / FRACUNIT);
+ }
+
+ return (time_ms * TICRATE) / 1000;
+}
+
+static boolean BuildNewTic(void)
+{
+ int gameticdiv;
+ ticcmd_t cmd;
+
+ gameticdiv = gametic/ticdup;
+
+ I_StartTic ();
+ loop_interface->ProcesEvents();
+
+ // Always run the menu
+
+ loop_interface->RunMenu();
+
+ if (drone)
+ {
+ // In drone mode, do not generate any ticcmds.
+
+ return false;
+ }
+
+ if (new_sync)
+ {
+ // If playing single player, do not allow tics to buffer
+ // up very far
+
+ if (!net_client_connected && maketic - gameticdiv > 2)
+ return false;
+
+ // Never go more than ~200ms ahead
+
+ if (maketic - gameticdiv > 8)
+ return false;
+ }
+ else
+ {
+ if (maketic - gameticdiv >= 5)
+ return false;
+ }
+
+ //printf ("mk:%i ",maketic);
+ memset(&cmd, 0, sizeof(ticcmd_t));
+ loop_interface->BuildTiccmd(&cmd, maketic);
+
+#ifdef FEATURE_MULTIPLAYER
+
+ if (net_client_connected)
+ {
+ NET_CL_SendTiccmd(&cmd, maketic);
+ }
+
+#endif
+ ticdata[maketic % BACKUPTICS].cmds[localplayer] = cmd;
+ ticdata[maketic % BACKUPTICS].ingame[localplayer] = true;
+
+ ++maketic;
+
+ return true;
+}
+
+//
+// NetUpdate
+// Builds ticcmds for console player,
+// sends out a packet
+//
+int lasttime;
+
+void NetUpdate (void)
+{
+ int nowtime;
+ int newtics;
+ int i;
+
+ // If we are running with singletics (timing a demo), this
+ // is all done separately.
+
+ if (singletics)
+ return;
+
+#ifdef FEATURE_MULTIPLAYER
+
+ // Run network subsystems
+
+ NET_CL_Run();
+ NET_SV_Run();
+
+#endif
+
+ // check time
+ nowtime = GetAdjustedTime() / ticdup;
+ newtics = nowtime - lasttime;
+
+ lasttime = nowtime;
+
+ if (skiptics <= newtics)
+ {
+ newtics -= skiptics;
+ skiptics = 0;
+ }
+ else
+ {
+ skiptics -= newtics;
+ newtics = 0;
+ }
+
+ // build new ticcmds for console player
+
+ for (i=0 ; i<newtics ; i++)
+ {
+ if (!BuildNewTic())
+ {
+ break;
+ }
+ }
+}
+
+static void D_Disconnected(void)
+{
+ // In drone mode, the game cannot continue once disconnected.
+
+ if (drone)
+ {
+ I_Error("Disconnected from server in drone mode.");
+ }
+
+ // disconnected from server
+
+ printf("Disconnected from server.\n");
+}
+
+//
+// Invoked by the network engine when a complete set of ticcmds is
+// available.
+//
+
+void D_ReceiveTic(ticcmd_t *ticcmds, boolean *players_mask)
+{
+ int i;
+
+ // Disconnected from server?
+
+ if (ticcmds == NULL && players_mask == NULL)
+ {
+ D_Disconnected();
+ return;
+ }
+
+ for (i = 0; i < NET_MAXPLAYERS; ++i)
+ {
+ if (!drone && i == localplayer)
+ {
+ // This is us. Don't overwrite it.
+ }
+ else
+ {
+ ticdata[recvtic % BACKUPTICS].cmds[i] = ticcmds[i];
+ ticdata[recvtic % BACKUPTICS].ingame[i] = players_mask[i];
+ }
+ }
+
+ ++recvtic;
+}
+
+//
+// Start game loop
+//
+// Called after the screen is set but before the game starts running.
+//
+
+void D_StartGameLoop(void)
+{
+ lasttime = GetAdjustedTime() / ticdup;
+}
+
+boolean D_InitNetGame(net_connect_data_t *connect_data,
+ net_gamesettings_t *settings)
+{
+ net_addr_t *addr = NULL;
+ boolean result = false;
+ int i;
+
+ offsetms = 0;
+ recvtic = 0;
+
+ settings->consoleplayer = 0;
+ settings->num_players = 1;
+
+ //!
+ // @category net
+ //
+ // Use original game sync code.
+ //
+
+ if (M_CheckParm("-oldsync") > 0)
+ settings->new_sync = 0;
+ else
+ settings->new_sync = 1;
+
+ //!
+ // @category net
+ // @arg <n>
+ //
+ // Send n extra tics in every packet as insurance against dropped
+ // packets.
+ //
+
+ i = M_CheckParmWithArgs("-extratics", 1);
+
+ if (i > 0)
+ settings->extratics = atoi(myargv[i+1]);
+ else
+ settings->extratics = 1;
+
+ //!
+ // @category net
+ // @arg <n>
+ //
+ // Reduce the resolution of the game by a factor of n, reducing
+ // the amount of network bandwidth needed.
+ //
+
+ i = M_CheckParmWithArgs("-dup", 1);
+
+ if (i > 0)
+ settings->ticdup = atoi(myargv[i+1]);
+ else
+ settings->ticdup = 1;
+
+#ifdef FEATURE_MULTIPLAYER
+
+ //!
+ // @category net
+ //
+ // Start a multiplayer server, listening for connections.
+ //
+
+ if (M_CheckParm("-server") > 0
+ || M_CheckParm("-privateserver") > 0)
+ {
+ NET_SV_Init();
+ NET_SV_AddModule(&net_loop_server_module);
+ NET_SV_AddModule(&net_sdl_module);
+ NET_SV_RegisterWithMaster();
+
+ net_loop_client_module.InitClient();
+ addr = net_loop_client_module.ResolveAddress(NULL);
+ }
+ else
+ {
+ //!
+ // @category net
+ //
+ // Automatically search the local LAN for a multiplayer
+ // server and join it.
+ //
+
+ i = M_CheckParm("-autojoin");
+
+ if (i > 0)
+ {
+ addr = NET_FindLANServer();
+
+ if (addr == NULL)
+ {
+ I_Error("No server found on local LAN");
+ }
+ }
+
+ //!
+ // @arg <address>
+ // @category net
+ //
+ // Connect to a multiplayer server running on the given
+ // address.
+ //
+
+ i = M_CheckParmWithArgs("-connect", 1);
+
+ if (i > 0)
+ {
+ net_sdl_module.InitClient();
+ addr = net_sdl_module.ResolveAddress(myargv[i+1]);
+
+ if (addr == NULL)
+ {
+ I_Error("Unable to resolve '%s'\n", myargv[i+1]);
+ }
+ }
+ }
+
+ if (addr != NULL)
+ {
+ if (M_CheckParm("-drone") > 0)
+ {
+ connect_data->drone = true;
+ }
+
+ if (!NET_CL_Connect(addr, connect_data))
+ {
+ I_Error("D_CheckNetGame: Failed to connect to %s\n",
+ NET_AddrToString(addr));
+ }
+
+ printf("D_CheckNetGame: Connected to %s\n", NET_AddrToString(addr));
+
+ // Wait for game start message received from server.
+
+ NET_WaitForStart(settings);
+
+ // Read the game settings that were received.
+
+ NET_CL_GetSettings(settings);
+
+ result = true;
+ }
+
+#endif
+
+ // Set the local player and playeringame[] values.
+
+ localplayer = settings->consoleplayer;
+
+ for (i = 0; i < NET_MAXPLAYERS; ++i)
+ {
+ local_playeringame[i] = i < settings->num_players;
+ }
+
+ // Check for sync mode.
+
+ new_sync = settings->new_sync;
+
+ if (new_sync == false)
+ {
+ printf("Syncing netgames like Vanilla Doom.\n");
+ }
+
+ return result;
+}
+
+
+//
+// D_QuitNetGame
+// Called before quitting to leave a net game
+// without hanging the other players
+//
+void D_QuitNetGame (void)
+{
+#ifdef FEATURE_MULTIPLAYER
+
+ NET_SV_Shutdown();
+ NET_CL_Disconnect();
+
+#endif
+
+}
+
+static int GetLowTic(void)
+{
+ int lowtic;
+
+ lowtic = maketic;
+
+#ifdef FEATURE_MULTIPLAYER
+ if (net_client_connected)
+ {
+ if (drone || recvtic < lowtic)
+ {
+ lowtic = recvtic;
+ }
+ }
+#endif
+
+ return lowtic;
+}
+
+static int frameon;
+static int frameskip[4];
+static int oldnettics;
+
+static void OldNetSync(void)
+{
+ unsigned int i;
+ unsigned int keyplayer = -1;
+
+ frameon++;
+
+ // ideally maketic should be 1 - 3 tics above lowtic
+ // if we are consistantly slower, speed up time
+
+ for (i=0 ; i<NET_MAXPLAYERS ; i++)
+ {
+ if (local_playeringame[i])
+ {
+ keyplayer = i;
+ break;
+ }
+ }
+
+ if (keyplayer < 0)
+ {
+ // If there are no players, we can never advance anyway
+
+ return;
+ }
+
+ if (localplayer == keyplayer)
+ {
+ // the key player does not adapt
+ }
+ else
+ {
+ if (maketic <= recvtic)
+ {
+ lasttime--;
+ // printf ("-");
+ }
+
+ frameskip[frameon & 3] = oldnettics > recvtic;
+ oldnettics = maketic;
+
+ if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3])
+ {
+ skiptics = 1;
+ // printf ("+");
+ }
+ }
+}
+
+// Returns true if there are players in the game:
+
+static boolean PlayersInGame(void)
+{
+ boolean result = false;
+ unsigned int i;
+
+ // If we are connected to a server, check if there are any players
+ // in the game.
+
+ if (net_client_connected)
+ {
+ for (i = 0; i < NET_MAXPLAYERS; ++i)
+ {
+ result = result || local_playeringame[i];
+ }
+ }
+
+ // Whether single or multi-player, unless we are running as a drone,
+ // we are in the game.
+
+ if (!drone)
+ {
+ result = true;
+ }
+
+ return result;
+}
+
+// When using ticdup, certain values must be cleared out when running
+// the duplicate ticcmds.
+
+static void TicdupSquash(ticcmd_set_t *set)
+{
+ ticcmd_t *cmd;
+ unsigned int i;
+
+ for (i = 0; i < NET_MAXPLAYERS ; ++i)
+ {
+ cmd = &set->cmds[i];
+ cmd->chatchar = 0;
+ if (cmd->buttons & BT_SPECIAL)
+ cmd->buttons = 0;
+ }
+}
+
+// When running in single player mode, clear all the ingame[] array
+// except the local player.
+
+static void SinglePlayerClear(ticcmd_set_t *set)
+{
+ unsigned int i;
+
+ for (i = 0; i < NET_MAXPLAYERS; ++i)
+ {
+ if (i != localplayer)
+ {
+ set->ingame[i] = false;
+ }
+ }
+}
+
+//
+// TryRunTics
+//
+
+void TryRunTics (void)
+{
+ int i;
+ int lowtic;
+ int entertic;
+ static int oldentertics;
+ int realtics;
+ int availabletics;
+ int counts;
+
+ // get real tics
+ entertic = I_GetTime() / ticdup;
+ realtics = entertic - oldentertics;
+ oldentertics = entertic;
+
+ // in singletics mode, run a single tic every time this function
+ // is called.
+
+ if (singletics)
+ {
+ BuildNewTic();
+ }
+ else
+ {
+ NetUpdate ();
+ }
+
+ lowtic = GetLowTic();
+
+ availabletics = lowtic - gametic/ticdup;
+
+ // decide how many tics to run
+
+ if (new_sync)
+ {
+ counts = availabletics;
+ }
+ else
+ {
+ // 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;
+
+ if (net_client_connected)
+ {
+ OldNetSync();
+ }
+ }
+
+ if (counts < 1)
+ counts = 1;
+
+ // wait for new tics if needed
+
+ while (!PlayersInGame() || lowtic < gametic/ticdup + counts)
+ {
+ NetUpdate ();
+
+ lowtic = GetLowTic();
+
+ if (lowtic < gametic/ticdup)
+ I_Error ("TryRunTics: lowtic < gametic");
+
+ // Don't stay in this loop forever. The menu is still running,
+ // so return to update the screen
+
+ if (I_GetTime() / ticdup - entertic > 0)
+ {
+ return;
+ }
+
+ I_Sleep(1);
+ }
+
+ // run the count * ticdup dics
+ while (counts--)
+ {
+ ticcmd_set_t *set;
+
+ if (!PlayersInGame())
+ {
+ return;
+ }
+
+ set = &ticdata[(gametic / ticdup) % BACKUPTICS];
+
+ if (!net_client_connected)
+ {
+ SinglePlayerClear(set);
+ }
+
+ for (i=0 ; i<ticdup ; i++)
+ {
+ if (gametic/ticdup > lowtic)
+ I_Error ("gametic>lowtic");
+
+ memcpy(local_playeringame, set->ingame, sizeof(local_playeringame));
+
+ loop_interface->RunTic(set->cmds, set->ingame);
+ gametic++;
+
+ // modify command for duplicated tics
+
+ TicdupSquash(set);
+ }
+
+ NetUpdate (); // check for new console commands
+ }
+}
+
+void D_RegisterLoopCallbacks(loop_interface_t *i)
+{
+ loop_interface = i;
+}
diff --git a/src/d_loop.h b/src/d_loop.h
new file mode 100644
index 00000000..d6d7a026
--- /dev/null
+++ b/src/d_loop.h
@@ -0,0 +1,77 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2011 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Main loop stuff.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef __D_LOOP__
+#define __D_LOOP__
+
+#include "net_defs.h"
+
+typedef struct
+{
+ // Read events from the event queue, and process them.
+
+ void (*ProcesEvents)();
+
+ // Given the current input state, fill in the fields of the specified
+ // ticcmd_t structure with data for a new tic.
+
+ void (*BuildTiccmd)(ticcmd_t *cmd, int maketic);
+
+ // Advance the game forward one tic, using the specified player input.
+
+ void (*RunTic)(ticcmd_t *cmds, boolean *ingame);
+
+ // Run the menu (runs independently of the game).
+
+ void (*RunMenu)();
+} loop_interface_t;
+
+// Register callback functions for the main loop code to use.
+void D_RegisterLoopCallbacks(loop_interface_t *i);
+
+// 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);
+
+// Called at start of game loop to initialize timers
+void D_StartGameLoop(void);
+
+// Initialize networking code; structures contain desired game settings,
+// these may be changed.
+boolean D_InitNetGame(net_connect_data_t *connect_data,
+ net_gamesettings_t *settings);
+
+extern boolean singletics;
+extern int gametic, ticdup;
+
+#endif
+
diff --git a/src/d_mode.c b/src/d_mode.c
new file mode 100644
index 00000000..8bdcf50c
--- /dev/null
+++ b/src/d_mode.c
@@ -0,0 +1,189 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// DESCRIPTION:
+// Functions and definitions relating to the game type and operational
+// mode.
+//
+
+#include "doomtype.h"
+#include "d_mode.h"
+
+// Valid game mode/mission combinations, with the number of
+// episodes/maps for each.
+
+static struct
+{
+ GameMission_t mission;
+ GameMode_t mode;
+ int episode;
+ int map;
+} valid_modes[] = {
+ { pack_chex, shareware, 1, 5 },
+ { doom, shareware, 1, 9 },
+ { doom, registered, 3, 9 },
+ { doom, retail, 4, 9 },
+ { doom2, commercial, 1, 32 },
+ { pack_tnt, commercial, 1, 32 },
+ { pack_plut, commercial, 1, 32 },
+ { pack_hacx, commercial, 1, 32 },
+ { heretic, shareware, 1, 9 },
+ { heretic, registered, 3, 9 },
+ { heretic, retail, 5, 9 },
+ { hexen, commercial, 1, 40 },
+ { strife, commercial, 1, 34 },
+};
+
+// Check that a gamemode+gamemission received over the network is valid.
+
+boolean D_ValidGameMode(GameMission_t mission, GameMode_t mode)
+{
+ int i;
+
+ for (i=0; i<arrlen(valid_modes); ++i)
+ {
+ if (valid_modes[i].mode == mode && valid_modes[i].mission == mission)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+boolean D_ValidEpisodeMap(GameMission_t mission, GameMode_t mode,
+ int episode, int map)
+{
+ int i;
+
+ // Hacks for Heretic secret episodes
+
+ if (mission == heretic)
+ {
+ if (mode == retail && episode == 6)
+ {
+ return map >= 1 && map <= 3;
+ }
+ else if (mode == registered && episode == 4)
+ {
+ return map == 1;
+ }
+ }
+
+ // Find the table entry for this mission/mode combination.
+
+ for (i=0; i<arrlen(valid_modes); ++i)
+ {
+ if (mission == valid_modes[i].mission
+ && mode == valid_modes[i].mode)
+ {
+ return episode >= 1 && episode <= valid_modes[i].episode
+ && map >= 1 && map <= valid_modes[i].map;
+ }
+ }
+
+ // Unknown mode/mission combination
+
+ return false;
+}
+
+// Get the number of valid episodes for the specified mission/mode.
+
+int D_GetNumEpisodes(GameMission_t mission, GameMode_t mode)
+{
+ int episode;
+
+ episode = 1;
+
+ while (D_ValidEpisodeMap(mission, mode, episode, 1))
+ {
+ ++episode;
+ }
+
+ return episode - 1;
+}
+
+// Table of valid versions
+
+static struct {
+ GameMission_t mission;
+ GameVersion_t version;
+} valid_versions[] = {
+ { doom, exe_doom_1_9 },
+ { doom, exe_hacx },
+ { doom, exe_ultimate },
+ { doom, exe_final },
+ { doom, exe_final2 },
+ { doom, exe_chex },
+ { heretic, exe_heretic_1_3 },
+ { hexen, exe_hexen_1_1 },
+ { strife, exe_strife_1_2 },
+ { strife, exe_strife_1_31 },
+};
+
+boolean D_ValidGameVersion(GameMission_t mission, GameVersion_t version)
+{
+ int i;
+
+ // All Doom variants can use the Doom versions.
+
+ if (mission == doom2 || mission == pack_plut || mission == pack_tnt
+ || mission == pack_hacx || mission == pack_chex)
+ {
+ mission = doom;
+ }
+
+ for (i=0; i<arrlen(valid_versions); ++i)
+ {
+ if (valid_versions[i].mission == mission
+ && valid_versions[i].version == version)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Does this mission type use ExMy form, rather than MAPxy form?
+
+boolean D_IsEpisodeMap(GameMission_t mission)
+{
+ switch (mission)
+ {
+ case doom:
+ case heretic:
+ case pack_chex:
+ return true;
+
+ case none:
+ case hexen:
+ case doom2:
+ case pack_hacx:
+ case pack_tnt:
+ case pack_plut:
+ case strife:
+ default:
+ return false;
+ }
+}
+
diff --git a/src/d_mode.h b/src/d_mode.h
new file mode 100644
index 00000000..f18c1c06
--- /dev/null
+++ b/src/d_mode.h
@@ -0,0 +1,101 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Functions and definitions relating to the game type and operational
+// mode.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef __D_MODE__
+#define __D_MODE__
+
+#include "doomtype.h"
+
+// The "mission" controls what game we are playing.
+
+typedef enum
+{
+ doom, // Doom 1
+ doom2, // Doom 2
+ pack_tnt, // Final Doom: TNT: Evilution
+ pack_plut, // Final Doom: The Plutonia Experiment
+ pack_chex, // Chex Quest (modded doom)
+ pack_hacx, // Hacx (modded doom2)
+ heretic, // Heretic
+ hexen, // Hexen
+ strife, // Strife
+
+ none
+} GameMission_t;
+
+// The "mode" allows more accurate specification of the game mode we are
+// in: eg. shareware vs. registered. So doom1.wad and doom.wad are the
+// same mission, but a different mode.
+
+typedef enum
+{
+ shareware, // Doom/Heretic shareware
+ registered, // Doom/Heretic registered
+ commercial, // Doom II/Hexen
+ retail, // Ultimate Doom
+ indetermined // Unknown.
+} GameMode_t;
+
+// What version are we emulating?
+
+typedef enum
+{
+ exe_doom_1_9, // Doom 1.9: used for shareware, registered and commercial
+ exe_hacx, // Hacx
+ exe_ultimate, // Ultimate Doom (retail)
+ exe_final, // Final Doom
+ exe_final2, // Final Doom (alternate exe)
+ exe_chex, // Chex Quest executable (based on Final Doom)
+
+ exe_heretic_1_3, // Heretic 1.3
+
+ exe_hexen_1_1, // Hexen 1.1
+ exe_strife_1_2, // Strife v1.2
+ exe_strife_1_31 // Strife v1.31
+} GameVersion_t;
+
+// Skill level.
+
+typedef enum
+{
+ sk_noitems = -1, // the "-skill 0" hack
+ sk_baby = 0,
+ sk_easy,
+ sk_medium,
+ sk_hard,
+ sk_nightmare
+} skill_t;
+
+boolean D_ValidGameMode(GameMission_t mission, GameMode_t mode);
+boolean D_ValidGameVersion(GameMission_t mission, GameVersion_t version);
+boolean D_ValidEpisodeMap(GameMission_t mission, GameMode_t mode,
+ int episode, int map);
+int D_GetNumEpisodes(GameMission_t mission, GameMode_t mode);
+boolean D_IsEpisodeMap(GameMission_t mission);
+
+#endif /* #ifndef __D_MODE__ */
+
diff --git a/src/d_net.c b/src/d_net.c
deleted file mode 100644
index 558c3e4d..00000000
--- a/src/d_net.c
+++ /dev/null
@@ -1,644 +0,0 @@
-// Emacs style mode select -*- C++ -*-
-//-----------------------------------------------------------------------------
-//
-// Copyright(C) 1993-1996 Id Software, Inc.
-// Copyright(C) 2005 Simon Howard
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-// 02111-1307, USA.
-//
-// DESCRIPTION:
-// DOOM Network game communication and protocol,
-// all OS independend parts.
-//
-//-----------------------------------------------------------------------------
-
-
-
-#include "doomfeatures.h"
-
-#include "d_main.h"
-#include "m_argv.h"
-#include "m_menu.h"
-#include "i_system.h"
-#include "i_timer.h"
-#include "i_video.h"
-#include "g_game.h"
-#include "doomdef.h"
-#include "doomstat.h"
-
-#include "deh_main.h"
-
-#include "net_client.h"
-#include "net_gui.h"
-#include "net_io.h"
-#include "net_query.h"
-#include "net_server.h"
-#include "net_sdl.h"
-#include "net_loop.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
-//
-
-ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS];
-int nettics[MAXPLAYERS];
-
-int maketic;
-
-// Used for original sync code.
-
-int lastnettic;
-int skiptics = 0;
-
-// Reduce the bandwidth needed by sampling game input less and transmitting
-// less. If ticdup is 2, sample half normal, 3 = one third normal, etc.
-
-int ticdup;
-
-// Send this many extra (backup) tics in each packet.
-
-int extratics;
-
-// Amount to offset the timer for game sync.
-
-fixed_t offsetms;
-
-// Use new client syncronisation code
-
-boolean net_cl_new_sync = true;
-
-// Connected but not participating in the game (observer)
-
-boolean drone = false;
-
-// 35 fps clock adjusted by offsetms milliseconds
-
-static int GetAdjustedTime(void)
-{
- int time_ms;
-
- time_ms = I_GetTimeMS();
-
- if (net_cl_new_sync)
- {
- // Use the adjustments from net_client.c only if we are
- // using the new sync mode.
-
- time_ms += (offsetms / FRACUNIT);
- }
-
- return (time_ms * TICRATE) / 1000;
-}
-
-//
-// NetUpdate
-// Builds ticcmds for console player,
-// sends out a packet
-//
-int lasttime;
-
-void NetUpdate (void)
-{
- int nowtime;
- int newtics;
- int i;
- int gameticdiv;
-
- // If we are running with singletics (timing a demo), this
- // is all done separately.
-
- if (singletics)
- return;
-
-#ifdef FEATURE_MULTIPLAYER
-
- // Run network subsystems
-
- NET_CL_Run();
- NET_SV_Run();
-
-#endif
-
- // check time
- nowtime = GetAdjustedTime() / ticdup;
- newtics = nowtime - lasttime;
-
- lasttime = nowtime;
-
- if (skiptics <= newtics)
- {
- newtics -= skiptics;
- skiptics = 0;
- }
- else
- {
- skiptics -= newtics;
- newtics = 0;
- }
-
- // build new ticcmds for console player
- gameticdiv = gametic/ticdup;
-
- for (i=0 ; i<newtics ; i++)
- {
- ticcmd_t cmd;
-
- I_StartTic ();
- D_ProcessEvents ();
-
- // Always run the menu
-
- M_Ticker ();
-
- if (drone)
- {
- // In drone mode, do not generate any ticcmds.
-
- continue;
- }
-
- if (net_cl_new_sync)
- {
- // If playing single player, do not allow tics to buffer
- // up very far
-
- if ((!netgame || demoplayback) && maketic - gameticdiv > 2)
- break;
-
- // Never go more than ~200ms ahead
-
- if (maketic - gameticdiv > 8)
- break;
- }
- else
- {
- if (maketic - gameticdiv >= 5)
- break;
- }
-
- //printf ("mk:%i ",maketic);
- G_BuildTiccmd(&cmd);
-
-#ifdef FEATURE_MULTIPLAYER
-
- if (net_client_connected)
- {
- NET_CL_SendTiccmd(&cmd, maketic);
- }
-
-#endif
- netcmds[consoleplayer][maketic % BACKUPTICS] = cmd;
-
- ++maketic;
- nettics[consoleplayer] = maketic;
- }
-}
-
-//
-// Start game loop
-//
-// Called after the screen is set but before the game starts running.
-//
-
-void D_StartGameLoop(void)
-{
- lasttime = GetAdjustedTime() / ticdup;
-}
-
-
-//
-// D_CheckNetGame
-// Works out player numbers among the net participants
-//
-extern int viewangleoffset;
-
-void D_CheckNetGame (void)
-{
- int i;
- int num_players;
-
- // default values for single player
-
- consoleplayer = 0;
- netgame = false;
- ticdup = 1;
- extratics = 1;
- lowres_turn = false;
- offsetms = 0;
-
- for (i=0; i<MAXPLAYERS; i++)
- {
- playeringame[i] = false;
- nettics[i] = 0;
- }
-
- playeringame[0] = true;
-
- //!
- // @category net
- //
- // Start the game playing as though in a netgame with a single
- // player. This can also be used to play back single player netgame
- // demos.
- //
-
- if (M_CheckParm("-solo-net") > 0)
- {
- netgame = true;
- }
-
-#ifdef FEATURE_MULTIPLAYER
-
- {
- net_addr_t *addr = NULL;
-
- //!
- // @category net
- //
- // Start a multiplayer server, listening for connections.
- //
-
- if (M_CheckParm("-server") > 0
- || M_CheckParm("-privateserver") > 0)
- {
- NET_SV_Init();
- NET_SV_AddModule(&net_loop_server_module);
- NET_SV_AddModule(&net_sdl_module);
- NET_SV_RegisterWithMaster();
-
- net_loop_client_module.InitClient();
- addr = net_loop_client_module.ResolveAddress(NULL);
- }
- else
- {
- //!
- // @category net
- //
- // Automatically search the local LAN for a multiplayer
- // server and join it.
- //
-
- i = M_CheckParm("-autojoin");
-
- if (i > 0)
- {
- addr = NET_FindLANServer();
-
- if (addr == NULL)
- {
- I_Error("No server found on local LAN");
- }
- }
-
- //!
- // @arg <address>
- // @category net
- //
- // Connect to a multiplayer server running on the given
- // address.
- //
-
- i = M_CheckParmWithArgs("-connect", 1);
-
- if (i > 0)
- {
- net_sdl_module.InitClient();
- addr = net_sdl_module.ResolveAddress(myargv[i+1]);
-
- if (addr == NULL)
- {
- I_Error("Unable to resolve '%s'\n", myargv[i+1]);
- }
- }
- }
-
- if (addr != NULL)
- {
- if (M_CheckParm("-drone") > 0)
- {
- drone = true;
- }
-
- //!
- // @category net
- //
- // Run as the left screen in three screen mode.
- //
-
- if (M_CheckParm("-left") > 0)
- {
- viewangleoffset = ANG90;
- drone = true;
- }
-
- //!
- // @category net
- //
- // Run as the right screen in three screen mode.
- //
-
- if (M_CheckParm("-right") > 0)
- {
- viewangleoffset = ANG270;
- drone = true;
- }
-
- if (!NET_CL_Connect(addr))
- {
- I_Error("D_CheckNetGame: Failed to connect to %s\n",
- NET_AddrToString(addr));
- }
-
- printf("D_CheckNetGame: Connected to %s\n", NET_AddrToString(addr));
-
- NET_WaitForStart();
- }
- }
-
-#endif
-
- num_players = 0;
-
- for (i=0; i<MAXPLAYERS; ++i)
- {
- if (playeringame[i])
- ++num_players;
- }
-
- DEH_printf("startskill %i deathmatch: %i startmap: %i startepisode: %i\n",
- startskill, deathmatch, startmap, startepisode);
-
- DEH_printf("player %i of %i (%i nodes)\n",
- consoleplayer+1, num_players, num_players);
-
- // Show players here; the server might have specified a time limit
-
- if (timelimit > 0 && deathmatch)
- {
- // Gross hack to work like Vanilla:
-
- if (timelimit == 20 && M_CheckParm("-avg"))
- {
- DEH_printf("Austin Virtual Gaming: Levels will end "
- "after 20 minutes\n");
- }
- else
- {
- DEH_printf("Levels will end after %d minute", timelimit);
- if (timelimit > 1)
- printf("s");
- printf(".\n");
- }
- }
-}
-
-
-//
-// D_QuitNetGame
-// Called before quitting to leave a net game
-// without hanging the other players
-//
-void D_QuitNetGame (void)
-{
-#ifdef FEATURE_MULTIPLAYER
-
- NET_SV_Shutdown();
- NET_CL_Disconnect();
-
-#endif
-
-}
-
-// Returns true if there are currently any players in the game.
-
-static boolean PlayersInGame(void)
-{
- int i;
-
- for (i=0; i<MAXPLAYERS; ++i)
- {
- if (playeringame[i])
- {
- return true;
- }
- }
-
- return false;
-}
-
-static int GetLowTic(void)
-{
- int i;
- int lowtic;
-
-#ifdef FEATURE_MULTIPLAYER
- if (net_client_connected)
- {
- lowtic = INT_MAX;
-
- for (i=0; i<MAXPLAYERS; ++i)
- {
- if (playeringame[i])
- {
- if (nettics[i] < lowtic)
- lowtic = nettics[i];
- }
- }
- }
- else
-#endif
- {
- lowtic = maketic;
- }
-
- return lowtic;
-}
-
-//
-// TryRunTics
-//
-int oldnettics;
-int frametics[4];
-int frameon;
-int frameskip[4];
-int oldnettics;
-
-extern boolean advancedemo;
-
-void TryRunTics (void)
-{
- int i;
- int lowtic;
- int entertic;
- static int oldentertics;
- int realtics;
- int availabletics;
- int counts;
-
- // get real tics
- entertic = I_GetTime() / ticdup;
- realtics = entertic - oldentertics;
- oldentertics = entertic;
-
- // get available tics
- NetUpdate ();
-
- lowtic = GetLowTic();
-
- availabletics = lowtic - gametic/ticdup;
-
- // decide how many tics to run
-
- if (net_cl_new_sync)
- {
- counts = availabletics;
- }
- else
- {
- // 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 (!demoplayback)
- {
- int keyplayer = -1;
-
- // ideally maketic should be 1 - 3 tics above lowtic
- // if we are consistantly slower, speed up time
-
- for (i=0 ; i<MAXPLAYERS ; i++)
- {
- if (playeringame[i])
- {
- keyplayer = i;
- break;
- }
- }
-
- if (keyplayer < 0)
- {
- // If there are no players, we can never advance anyway
-
- return;
- }
-
- if (consoleplayer == keyplayer)
- {
- // the key player does not adapt
- }
- else
- {
- if (maketic <= nettics[keyplayer])
- {
- lasttime--;
- // printf ("-");
- }
-
- frameskip[frameon & 3] = (oldnettics > nettics[keyplayer]);
- oldnettics = maketic;
-
- if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3])
- {
- skiptics = 1;
- // printf ("+");
- }
- }
- }
- }
-
- if (counts < 1)
- counts = 1;
-
- // wait for new tics if needed
-
- while (!PlayersInGame() || lowtic < gametic/ticdup + counts)
- {
- NetUpdate ();
-
- lowtic = GetLowTic();
-
- if (lowtic < gametic/ticdup)
- I_Error ("TryRunTics: lowtic < gametic");
-
- // Don't stay in this loop forever. The menu is still running,
- // so return to update the screen
-
- if (I_GetTime() / ticdup - entertic > 0)
- {
- return;
- }
-
- I_Sleep(1);
- }
-
- // run the count * ticdup dics
- while (counts--)
- {
- for (i=0 ; i<ticdup ; i++)
- {
- // check that there are players in the game. if not, we cannot
- // run a tic.
-
- if (!PlayersInGame())
- {
- return;
- }
-
- if (gametic/ticdup > lowtic)
- I_Error ("gametic>lowtic");
- if (advancedemo)
- D_DoAdvanceDemo ();
-
- 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
- }
-}
-
diff --git a/src/d_ticcmd.h b/src/d_ticcmd.h
index 2968a352..cb6156ad 100644
--- a/src/d_ticcmd.h
+++ b/src/d_ticcmd.h
@@ -2,6 +2,7 @@
//-----------------------------------------------------------------------------
//
// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
// Copyright(C) 2005 Simon Howard
//
// This program is free software; you can redistribute it and/or
@@ -35,14 +36,27 @@
// and transmitted to other peers (multiplayer).
// Mainly movements/button commands per game tick,
// plus a checksum for internal state consistency.
+
typedef struct
{
signed char forwardmove; // *2048 for move
signed char sidemove; // *2048 for move
- short angleturn; // <<16 for angle delta
- byte chatchar;
- byte buttons;
- byte consistancy; // checks for net game
+ short angleturn; // <<16 for angle delta
+ byte chatchar;
+ byte buttons;
+ // villsa [STRIFE] according to the asm,
+ // consistancy is a short, not a byte
+ byte consistancy; // checks for net game
+
+ // villsa - Strife specific:
+
+ byte buttons2;
+ int inventory;
+
+ // Heretic/Hexen specific:
+
+ byte lookfly; // look/fly up/down/centering
+ byte arti; // artitype_t to use
} ticcmd_t;
diff --git a/src/deh_main.c b/src/deh_main.c
index e61933fa..4bb3e383 100644
--- a/src/deh_main.c
+++ b/src/deh_main.c
@@ -24,9 +24,11 @@
//
//-----------------------------------------------------------------------------
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <ctype.h>
-#include "doomdef.h"
#include "doomtype.h"
#include "d_iwad.h"
#include "m_argv.h"
@@ -35,30 +37,10 @@
#include "deh_defs.h"
#include "deh_io.h"
-static char *deh_signatures[] =
-{
- "Patch File for DeHackEd v2.3",
- "Patch File for DeHackEd v3.0",
-};
-
-// deh_ammo.c:
-extern deh_section_t deh_section_ammo;
-// deh_cheat.c:
-extern deh_section_t deh_section_cheat;
-// deh_frame.c:
-extern deh_section_t deh_section_frame;
-// deh_misc.c:
-extern deh_section_t deh_section_misc;
-// deh_ptr.c:
-extern deh_section_t deh_section_pointer;
-// deh_sound.c
-extern deh_section_t deh_section_sound;
-// deh_text.c:
-extern deh_section_t deh_section_text;
-// deh_thing.c:
-extern deh_section_t deh_section_thing;
-// deh_weapon.c:
-extern deh_section_t deh_section_weapon;
+extern deh_section_t *deh_section_types[];
+extern char *deh_signatures[];
+
+static boolean deh_initialized = false;
// If true, we can do long string replacements.
@@ -72,23 +54,6 @@ boolean deh_allow_long_cheats = false;
boolean deh_apply_cheats = true;
-//
-// List of section types:
-//
-
-static deh_section_t *section_types[] =
-{
- &deh_section_ammo,
- &deh_section_cheat,
- &deh_section_frame,
- &deh_section_misc,
- &deh_section_pointer,
- &deh_section_sound,
- &deh_section_text,
- &deh_section_thing,
- &deh_section_weapon,
-};
-
void DEH_Checksum(sha1_digest_t digest)
{
sha1_context_t sha1_context;
@@ -96,11 +61,11 @@ void DEH_Checksum(sha1_digest_t digest)
SHA1_Init(&sha1_context);
- for (i=0; i<arrlen(section_types); ++i)
+ for (i=0; deh_section_types[i] != NULL; ++i)
{
- if (section_types[i]->sha1_hash != NULL)
+ if (deh_section_types[i]->sha1_hash != NULL)
{
- section_types[i]->sha1_hash(&sha1_context);
+ deh_section_types[i]->sha1_hash(&sha1_context);
}
}
@@ -113,11 +78,11 @@ static void InitializeSections(void)
{
unsigned int i;
- for (i=0; i<arrlen(section_types); ++i)
+ for (i=0; deh_section_types[i] != NULL; ++i)
{
- if (section_types[i]->init != NULL)
+ if (deh_section_types[i]->init != NULL)
{
- section_types[i]->init();
+ deh_section_types[i]->init();
}
}
}
@@ -128,11 +93,11 @@ static deh_section_t *GetSectionByName(char *name)
{
unsigned int i;
- for (i=0; i<arrlen(section_types); ++i)
+ for (i=0; deh_section_types[i] != NULL; ++i)
{
- if (!strcasecmp(section_types[i]->name, name))
+ if (!strcasecmp(deh_section_types[i]->name, name))
{
- return section_types[i];
+ return deh_section_types[i];
}
}
@@ -228,7 +193,7 @@ static boolean CheckSignatures(deh_context_t *context)
// Check all signatures to see if one matches
- for (i=0; i<arrlen(deh_signatures); ++i)
+ for (i=0; deh_signatures[i] != NULL; ++i)
{
if (!strcmp(deh_signatures[i], line))
{
@@ -359,10 +324,11 @@ int DEH_LoadFile(char *filename)
{
deh_context_t *context;
- // Vanilla dehacked files don't allow long string or cheat replacements.
-
- deh_allow_long_strings = false;
- deh_allow_long_cheats = false;
+ if (!deh_initialized)
+ {
+ InitializeSections();
+ deh_initialized = true;
+ }
printf(" loading %s\n", filename);
@@ -430,8 +396,6 @@ void DEH_Init(void)
char *filename;
int p;
- InitializeSections();
-
//!
// @category mod
//
diff --git a/src/deh_main.h b/src/deh_main.h
index ad31af7d..ea9e42da 100644
--- a/src/deh_main.h
+++ b/src/deh_main.h
@@ -27,10 +27,9 @@
#ifndef DEH_MAIN_H
#define DEH_MAIN_H
-#include <stdio.h>
-
#include "doomtype.h"
#include "doomfeatures.h"
+#include "deh_str.h"
#include "sha1.h"
// These are the limits that dehacked uses (from dheinit.h in the dehacked
@@ -49,26 +48,6 @@ boolean DEH_ParseAssignment(char *line, char **variable_name, char **value);
void DEH_Checksum(sha1_digest_t digest);
-// deh_text.c:
-//
-// Used to do dehacked text substitutions throughout the program
-
-#ifdef FEATURE_DEHACKED
-
-char *DEH_String(char *s);
-void DEH_printf(char *fmt, ...);
-void DEH_fprintf(FILE *fstream, char *fmt, ...);
-void DEH_snprintf(char *buffer, size_t len, char *fmt, ...);
-
-#else
-
-#define DEH_String(x) (x)
-#define DEH_printf printf
-#define DEH_fprintf fprintf
-#define DEH_snprintf snprintf
-
-#endif
-
extern boolean deh_allow_long_strings;
extern boolean deh_allow_long_cheats;
extern boolean deh_apply_cheats;
diff --git a/src/deh_mapping.c b/src/deh_mapping.c
index d73cda96..85c675b4 100644
--- a/src/deh_mapping.c
+++ b/src/deh_mapping.c
@@ -30,16 +30,13 @@
#include <stdlib.h>
#include <string.h>
-#include "doomdef.h"
+#include "doomtype.h"
#include "i_system.h"
#include "deh_mapping.h"
-//
-// Set the value of a particular field in a structure by name
-//
-
-boolean DEH_SetMapping(deh_context_t *context, deh_mapping_t *mapping,
- void *structptr, char *name, int value)
+static deh_mapping_entry_t *GetMappingEntryByName(deh_context_t *context,
+ deh_mapping_t *mapping,
+ char *name)
{
int i;
@@ -49,44 +46,121 @@ boolean DEH_SetMapping(deh_context_t *context, deh_mapping_t *mapping,
if (!strcasecmp(entry->name, name))
{
- void *location;
-
if (entry->location == NULL)
{
DEH_Warning(context, "Field '%s' is unsupported", name);
- return false;
+ return NULL;
}
- location = (uint8_t *)structptr + ((uint8_t *)entry->location - (uint8_t *)mapping->base);
-
- // printf("Setting %p::%s to %i (%i bytes)\n",
- // structptr, name, value, entry->size);
-
- switch (entry->size)
- {
- case 1:
- * ((uint8_t *) location) = value;
- break;
- case 2:
- * ((uint16_t *) location) = value;
- break;
- case 4:
- * ((uint32_t *) location) = value;
- break;
- default:
- DEH_Error(context, "Unknown field type for '%s' (BUG)", name);
- return false;
- }
-
- return true;
+ return entry;
}
}
- // field with this name not found
+ // Not found.
DEH_Warning(context, "Field named '%s' not found", name);
- return false;
+ return NULL;
+}
+
+//
+// Get the location of the specified field in the specified structure.
+//
+
+static void *GetStructField(void *structptr,
+ deh_mapping_t *mapping,
+ deh_mapping_entry_t *entry)
+{
+ unsigned int offset;
+
+ offset = (uint8_t *)entry->location - (uint8_t *)mapping->base;
+
+ return (uint8_t *)structptr + offset;
+}
+
+//
+// Set the value of a particular field in a structure by name
+//
+
+boolean DEH_SetMapping(deh_context_t *context, deh_mapping_t *mapping,
+ void *structptr, char *name, int value)
+{
+ deh_mapping_entry_t *entry;
+ void *location;
+
+ entry = GetMappingEntryByName(context, mapping, name);
+
+ if (entry == NULL)
+ {
+ return false;
+ }
+
+ // Sanity check:
+
+ if (entry->is_string)
+ {
+ DEH_Error(context, "Tried to set '%s' as integer (BUG)", name);
+ return false;
+ }
+
+ location = GetStructField(structptr, mapping, entry);
+
+ // printf("Setting %p::%s to %i (%i bytes)\n",
+ // structptr, name, value, entry->size);
+
+ // Set field content based on its type:
+
+ switch (entry->size)
+ {
+ case 1:
+ * ((uint8_t *) location) = value;
+ break;
+ case 2:
+ * ((uint16_t *) location) = value;
+ break;
+ case 4:
+ * ((uint32_t *) location) = value;
+ break;
+ default:
+ DEH_Error(context, "Unknown field type for '%s' (BUG)", name);
+ return false;
+ }
+
+ return true;
+}
+
+//
+// Set the value of a string field in a structure by name
+//
+
+boolean DEH_SetStringMapping(deh_context_t *context, deh_mapping_t *mapping,
+ void *structptr, char *name, char *value)
+{
+ deh_mapping_entry_t *entry;
+ void *location;
+
+ entry = GetMappingEntryByName(context, mapping, name);
+
+ if (entry == NULL)
+ {
+ return false;
+ }
+
+ // Sanity check:
+
+ if (!entry->is_string)
+ {
+ DEH_Error(context, "Tried to set '%s' as string (BUG)", name);
+ return false;
+ }
+
+ location = GetStructField(structptr, mapping, entry);
+
+ // Copy value into field:
+
+ strncpy(location, value, entry->size);
+
+ return true;
}
void DEH_StructSHA1Sum(sha1_context_t *context, deh_mapping_t *mapping,
diff --git a/src/deh_mapping.h b/src/deh_mapping.h
index 31e8aea3..91e34323 100644
--- a/src/deh_mapping.h
+++ b/src/deh_mapping.h
@@ -42,17 +42,23 @@
#define DEH_MAPPING(deh_name, fieldname) \
{deh_name, &deh_mapping_base.fieldname, \
- sizeof(deh_mapping_base.fieldname)},
+ sizeof(deh_mapping_base.fieldname), \
+ false},
+
+#define DEH_MAPPING_STRING(deh_name, fieldname) \
+ {deh_name, &deh_mapping_base.fieldname, \
+ sizeof(deh_mapping_base.fieldname), \
+ true},
#define DEH_UNSUPPORTED_MAPPING(deh_name) \
- {deh_name, NULL, -1},
-
+ {deh_name, NULL, -1, false},
+
#define DEH_END_MAPPING \
{NULL, NULL, -1} \
} \
};
-
+
#define MAX_MAPPING_ENTRIES 32
@@ -73,6 +79,10 @@ struct deh_mapping_entry_s
// field size
int size;
+
+ // if true, this is a string value.
+
+ boolean is_string;
};
struct deh_mapping_s
@@ -81,8 +91,10 @@ struct deh_mapping_s
deh_mapping_entry_t entries[MAX_MAPPING_ENTRIES];
};
-boolean DEH_SetMapping(deh_context_t *context, deh_mapping_t *mapping,
+boolean DEH_SetMapping(deh_context_t *context, deh_mapping_t *mapping,
void *structptr, char *name, int value);
+boolean DEH_SetStringMapping(deh_context_t *context, deh_mapping_t *mapping,
+ void *structptr, char *name, char *value);
void DEH_StructSHA1Sum(sha1_context_t *context, deh_mapping_t *mapping,
void *structptr);
diff --git a/src/deh_str.c b/src/deh_str.c
new file mode 100644
index 00000000..9bd429b6
--- /dev/null
+++ b/src/deh_str.c
@@ -0,0 +1,408 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// Parses Text substitution sections in dehacked files
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "doomtype.h"
+#include "deh_str.h"
+
+#include "z_zone.h"
+
+typedef struct
+{
+ char *from_text;
+ char *to_text;
+} deh_substitution_t;
+
+static deh_substitution_t **hash_table = NULL;
+static int hash_table_entries;
+static int hash_table_length = -1;
+
+// This is the algorithm used by glib
+
+static unsigned int strhash(char *s)
+{
+ char *p = s;
+ unsigned int h = *p;
+
+ if (h)
+ {
+ for (p += 1; *p; p++)
+ h = (h << 5) - h + *p;
+ }
+
+ return h;
+}
+
+// Look up a string to see if it has been replaced with something else
+// This will be used throughout the program to substitute text
+
+char *DEH_String(char *s)
+{
+ int entry;
+
+ // Fallback if we have not initialized the hash table yet
+
+ if (hash_table_length < 0)
+ return s;
+
+ entry = strhash(s) % hash_table_length;
+
+ while (hash_table[entry] != NULL)
+ {
+ if (!strcmp(hash_table[entry]->from_text, s))
+ {
+ // substitution found!
+
+ return hash_table[entry]->to_text;
+ }
+
+ entry = (entry + 1) % hash_table_length;
+ }
+
+ // no substitution found
+
+ return s;
+}
+
+static void InitHashTable(void)
+{
+ // init hash table
+
+ hash_table_entries = 0;
+ hash_table_length = 16;
+ hash_table = Z_Malloc(sizeof(deh_substitution_t *) * hash_table_length,
+ PU_STATIC, NULL);
+ memset(hash_table, 0, sizeof(deh_substitution_t *) * hash_table_length);
+}
+
+static void DEH_AddToHashtable(deh_substitution_t *sub);
+
+static void IncreaseHashtable(void)
+{
+ deh_substitution_t **old_table;
+ int old_table_length;
+ int i;
+
+ // save the old table
+
+ old_table = hash_table;
+ old_table_length = hash_table_length;
+
+ // double the size
+
+ hash_table_length *= 2;
+ hash_table = Z_Malloc(sizeof(deh_substitution_t *) * hash_table_length,
+ PU_STATIC, NULL);
+ memset(hash_table, 0, sizeof(deh_substitution_t *) * hash_table_length);
+
+ // go through the old table and insert all the old entries
+
+ for (i=0; i<old_table_length; ++i)
+ {
+ if (old_table[i] != NULL)
+ {
+ DEH_AddToHashtable(old_table[i]);
+ }
+ }
+
+ // free the old table
+
+ Z_Free(old_table);
+}
+
+static void DEH_AddToHashtable(deh_substitution_t *sub)
+{
+ int entry;
+
+ // if the hash table is more than 60% full, increase its size
+
+ if ((hash_table_entries * 10) / hash_table_length > 6)
+ {
+ IncreaseHashtable();
+ }
+
+ // find where to insert it
+
+ entry = strhash(sub->from_text) % hash_table_length;
+
+ while (hash_table[entry] != NULL)
+ {
+ entry = (entry + 1) % hash_table_length;
+ }
+
+ hash_table[entry] = sub;
+ ++hash_table_entries;
+}
+
+void DEH_AddStringReplacement(char *from_text, char *to_text)
+{
+ deh_substitution_t *sub;
+
+ // Initialize the hash table if this is the first time
+
+ if (hash_table_length < 0)
+ {
+ InitHashTable();
+ }
+
+ sub = Z_Malloc(sizeof(*sub), PU_STATIC, 0);
+
+ sub->from_text = from_text;
+ sub->to_text = to_text;
+
+ DEH_AddToHashtable(sub);
+}
+
+typedef enum
+{
+ FORMAT_ARG_INVALID,
+ FORMAT_ARG_INT,
+ FORMAT_ARG_FLOAT,
+ FORMAT_ARG_CHAR,
+ FORMAT_ARG_STRING,
+ FORMAT_ARG_PTR,
+ FORMAT_ARG_SAVE_POS
+} format_arg_t;
+
+// Get the type of a format argument.
+// We can mix-and-match different format arguments as long as they
+// are for the same data type.
+
+static format_arg_t FormatArgumentType(char c)
+{
+ switch (c)
+ {
+ case 'd': case 'i': case 'o': case 'u': case 'x': case 'X':
+ return FORMAT_ARG_INT;
+
+ case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
+ case 'a': case 'A':
+ return FORMAT_ARG_FLOAT;
+
+ case 'c': case 'C':
+ return FORMAT_ARG_CHAR;
+
+ case 's': case 'S':
+ return FORMAT_ARG_STRING;
+
+ case 'p':
+ return FORMAT_ARG_PTR;
+
+ case 'n':
+ return FORMAT_ARG_SAVE_POS;
+
+ default:
+ return FORMAT_ARG_INVALID;
+ }
+}
+
+// Given the specified string, get the type of the first format
+// string encountered.
+
+static format_arg_t NextFormatArgument(char **str)
+{
+ format_arg_t argtype;
+
+ // Search for the '%' starting the next string.
+
+ while (**str != '\0')
+ {
+ if (**str == '%')
+ {
+ ++*str;
+
+ // Don't stop for double-%s.
+
+ if (**str != '%')
+ {
+ break;
+ }
+ }
+
+ ++*str;
+ }
+
+ // Find the type of the format string.
+
+ while (**str != '\0')
+ {
+ argtype = FormatArgumentType(**str);
+
+ if (argtype != FORMAT_ARG_INVALID)
+ {
+ ++*str;
+
+ return argtype;
+ }
+
+ ++*str;
+ }
+
+ // Stop searching, we have reached the end.
+
+ *str = NULL;
+
+ return FORMAT_ARG_INVALID;
+}
+
+// Check if the specified argument type is a valid replacement for
+// the original.
+
+static boolean ValidArgumentReplacement(format_arg_t original,
+ format_arg_t replacement)
+{
+ // In general, the original and replacement types should be
+ // identical. However, there are some cases where the replacement
+ // is valid and the types don't match.
+
+ // Characters can be represented as ints.
+
+ if (original == FORMAT_ARG_CHAR && replacement == FORMAT_ARG_INT)
+ {
+ return true;
+ }
+
+ // Strings are pointers.
+
+ if (original == FORMAT_ARG_STRING && replacement == FORMAT_ARG_PTR)
+ {
+ return true;
+ }
+
+ return original == replacement;
+}
+
+// Return true if the specified string contains no format arguments.
+
+static boolean ValidFormatReplacement(char *original, char *replacement)
+{
+ char *rover1;
+ char *rover2;
+ int argtype1, argtype2;
+
+ // Check each argument in turn and compare types.
+
+ rover1 = original; rover2 = replacement;
+
+ for (;;)
+ {
+ argtype1 = NextFormatArgument(&rover1);
+ argtype2 = NextFormatArgument(&rover2);
+
+ if (argtype2 == FORMAT_ARG_INVALID)
+ {
+ // No more arguments left to read from the replacement string.
+
+ break;
+ }
+ else if (argtype1 == FORMAT_ARG_INVALID)
+ {
+ // Replacement string has more arguments than the original.
+
+ return false;
+ }
+ else if (!ValidArgumentReplacement(argtype1, argtype2))
+ {
+ // Not a valid replacement argument.
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Get replacement format string, checking arguments.
+
+static char *FormatStringReplacement(char *s)
+{
+ char *repl;
+
+ repl = DEH_String(s);
+
+ if (!ValidFormatReplacement(s, repl))
+ {
+ printf("WARNING: Unsafe dehacked replacement provided for "
+ "printf format string: %s\n", s);
+
+ return s;
+ }
+
+ return repl;
+}
+
+// printf(), performing a replacement on the format string.
+
+void DEH_printf(char *fmt, ...)
+{
+ va_list args;
+ char *repl;
+
+ repl = FormatStringReplacement(fmt);
+
+ va_start(args, fmt);
+
+ vprintf(repl, args);
+
+ va_end(args);
+}
+
+// fprintf(), performing a replacement on the format string.
+
+void DEH_fprintf(FILE *fstream, char *fmt, ...)
+{
+ va_list args;
+ char *repl;
+
+ repl = FormatStringReplacement(fmt);
+
+ va_start(args, fmt);
+
+ vfprintf(fstream, repl, args);
+
+ va_end(args);
+}
+
+// snprintf(), performing a replacement on the format string.
+
+void DEH_snprintf(char *buffer, size_t len, char *fmt, ...)
+{
+ va_list args;
+ char *repl;
+
+ repl = FormatStringReplacement(fmt);
+
+ va_start(args, fmt);
+
+ vsnprintf(buffer, len, repl, args);
+
+ va_end(args);
+}
+
diff --git a/src/deh_str.h b/src/deh_str.h
new file mode 100644
index 00000000..06bcb420
--- /dev/null
+++ b/src/deh_str.h
@@ -0,0 +1,55 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// Dehacked string replacements
+//
+//-----------------------------------------------------------------------------
+
+#ifndef DEH_STR_H
+#define DEH_STR_H
+
+#include <stdio.h>
+
+#include "doomfeatures.h"
+
+// Used to do dehacked text substitutions throughout the program
+
+#ifdef FEATURE_DEHACKED
+
+char *DEH_String(char *s);
+void DEH_printf(char *fmt, ...);
+void DEH_fprintf(FILE *fstream, char *fmt, ...);
+void DEH_snprintf(char *buffer, size_t len, char *fmt, ...);
+void DEH_AddStringReplacement(char *from_text, char *to_text);
+
+
+#else
+
+#define DEH_String(x) (x)
+#define DEH_printf printf
+#define DEH_fprintf fprintf
+#define DEH_snprintf snprintf
+
+#endif
+
+#endif /* #ifndef DEH_STR_H */
+
diff --git a/src/deh_text.c b/src/deh_text.c
index 5c6446dc..31e23db2 100644
--- a/src/deh_text.c
+++ b/src/deh_text.c
@@ -24,9 +24,9 @@
//
//-----------------------------------------------------------------------------
-#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
-#include "doomdef.h"
#include "doomtype.h"
#include "z_zone.h"
@@ -35,122 +35,6 @@
#include "deh_io.h"
#include "deh_main.h"
-typedef struct
-{
- char *from_text;
- char *to_text;
-} deh_substitution_t;
-
-static deh_substitution_t **hash_table;
-static int hash_table_entries;
-static int hash_table_length = -1;
-
-// This is the algorithm used by glib
-
-static unsigned int strhash(char *s)
-{
- char *p = s;
- unsigned int h = *p;
-
- if (h)
- {
- for (p += 1; *p; p++)
- h = (h << 5) - h + *p;
- }
-
- return h;
-}
-
-// Look up a string to see if it has been replaced with something else
-// This will be used throughout the program to substitute text
-
-char *DEH_String(char *s)
-{
- int entry;
-
- // Fallback if we have not initialized the hash table yet
-
- if (hash_table_length < 0)
- return s;
-
- entry = strhash(s) % hash_table_length;
-
- while (hash_table[entry] != NULL)
- {
- if (!strcmp(hash_table[entry]->from_text, s))
- {
- // substitution found!
-
- return hash_table[entry]->to_text;
- }
-
- entry = (entry + 1) % hash_table_length;
- }
-
- // no substitution found
-
- return s;
-}
-
-static void DEH_AddToHashtable(deh_substitution_t *sub);
-
-static void IncreaseHashtable(void)
-{
- deh_substitution_t **old_table;
- int old_table_length;
- int i;
-
- // save the old table
-
- old_table = hash_table;
- old_table_length = hash_table_length;
-
- // double the size
-
- hash_table_length *= 2;
- hash_table = Z_Malloc(sizeof(deh_substitution_t *) * hash_table_length,
- PU_STATIC, NULL);
- memset(hash_table, 0, sizeof(deh_substitution_t *) * hash_table_length);
-
- // go through the old table and insert all the old entries
-
- for (i=0; i<old_table_length; ++i)
- {
- if (old_table[i] != NULL)
- {
- DEH_AddToHashtable(old_table[i]);
- }
- }
-
- // free the old table
-
- Z_Free(old_table);
-}
-
-static void DEH_AddToHashtable(deh_substitution_t *sub)
-{
- int entry;
-
- // if the hash table is more than 60% full, increase its size
-
- if ((hash_table_entries * 10) / hash_table_length > 6)
- {
- IncreaseHashtable();
- }
-
- // find where to insert it
-
- entry = strhash(sub->from_text) % hash_table_length;
-
- while (hash_table[entry] != NULL)
- {
- entry = (entry + 1) % hash_table_length;
- }
-
- hash_table[entry] = sub;
- ++hash_table_entries;
-}
-
// Given a string length, find the maximum length of a
// string that can replace it.
@@ -171,20 +55,9 @@ static int TXT_MaxStringLength(int len)
return len - 1;
}
-static void DEH_TextInit(void)
-{
- // init hash table
-
- hash_table_entries = 0;
- hash_table_length = 16;
- hash_table = Z_Malloc(sizeof(deh_substitution_t *) * hash_table_length,
- PU_STATIC, NULL);
- memset(hash_table, 0, sizeof(deh_substitution_t *) * hash_table_length);
-}
-
static void *DEH_TextStart(deh_context_t *context, char *line)
{
- deh_substitution_t *sub;
+ char *from_text, *to_text;
int fromlen, tolen;
int i;
@@ -204,9 +77,8 @@ static void *DEH_TextStart(deh_context_t *context, char *line)
return NULL;
}
- sub = Z_Malloc(sizeof(deh_substitution_t), PU_STATIC, NULL);
- sub->from_text = Z_Malloc(fromlen + 1, PU_STATIC, NULL);
- sub->to_text = Z_Malloc(tolen + 1, PU_STATIC, NULL);
+ from_text = Z_Malloc(fromlen + 1, PU_STATIC, NULL);
+ to_text = Z_Malloc(tolen + 1, PU_STATIC, NULL);
// read in the "from" text
@@ -216,10 +88,10 @@ static void *DEH_TextStart(deh_context_t *context, char *line)
c = DEH_GetChar(context);
- sub->from_text[i] = c;
+ from_text[i] = c;
}
- sub->from_text[fromlen] = '\0';
+ from_text[fromlen] = '\0';
// read in the "to" text
@@ -229,11 +101,11 @@ static void *DEH_TextStart(deh_context_t *context, char *line)
c = DEH_GetChar(context);
- sub->to_text[i] = c;
+ to_text[i] = c;
}
- sub->to_text[tolen] = '\0';
+ to_text[tolen] = '\0';
- DEH_AddToHashtable(sub);
+ DEH_AddStringReplacement(from_text, to_text);
return NULL;
}
@@ -246,236 +118,10 @@ static void DEH_TextParseLine(deh_context_t *context, char *line, void *tag)
deh_section_t deh_section_text =
{
"Text",
- DEH_TextInit,
+ NULL,
DEH_TextStart,
DEH_TextParseLine,
NULL,
NULL,
};
-typedef enum
-{
- FORMAT_ARG_INVALID,
- FORMAT_ARG_INT,
- FORMAT_ARG_FLOAT,
- FORMAT_ARG_CHAR,
- FORMAT_ARG_STRING,
- FORMAT_ARG_PTR,
- FORMAT_ARG_SAVE_POS
-} format_arg_t;
-
-// Get the type of a format argument.
-// We can mix-and-match different format arguments as long as they
-// are for the same data type.
-
-static format_arg_t FormatArgumentType(char c)
-{
- switch (c)
- {
- case 'd': case 'i': case 'o': case 'u': case 'x': case 'X':
- return FORMAT_ARG_INT;
-
- case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
- case 'a': case 'A':
- return FORMAT_ARG_FLOAT;
-
- case 'c': case 'C':
- return FORMAT_ARG_CHAR;
-
- case 's': case 'S':
- return FORMAT_ARG_STRING;
-
- case 'p':
- return FORMAT_ARG_PTR;
-
- case 'n':
- return FORMAT_ARG_SAVE_POS;
-
- default:
- return FORMAT_ARG_INVALID;
- }
-}
-
-// Given the specified string, get the type of the first format
-// string encountered.
-
-static format_arg_t NextFormatArgument(char **str)
-{
- format_arg_t argtype;
-
- // Search for the '%' starting the next string.
-
- while (**str != '\0')
- {
- if (**str == '%')
- {
- ++*str;
-
- // Don't stop for double-%s.
-
- if (**str != '%')
- {
- break;
- }
- }
-
- ++*str;
- }
-
- // Find the type of the format string.
-
- while (**str != '\0')
- {
- argtype = FormatArgumentType(**str);
-
- if (argtype != FORMAT_ARG_INVALID)
- {
- ++*str;
-
- return argtype;
- }
-
- ++*str;
- }
-
- // Stop searching, we have reached the end.
-
- *str = NULL;
-
- return FORMAT_ARG_INVALID;
-}
-
-// Check if the specified argument type is a valid replacement for
-// the original.
-
-static boolean ValidArgumentReplacement(format_arg_t original,
- format_arg_t replacement)
-{
- // In general, the original and replacement types should be
- // identical. However, there are some cases where the replacement
- // is valid and the types don't match.
-
- // Characters can be represented as ints.
-
- if (original == FORMAT_ARG_CHAR && replacement == FORMAT_ARG_INT)
- {
- return true;
- }
-
- // Strings are pointers.
-
- if (original == FORMAT_ARG_STRING && replacement == FORMAT_ARG_PTR)
- {
- return true;
- }
-
- return original == replacement;
-}
-
-// Return true if the specified string contains no format arguments.
-
-static boolean ValidFormatReplacement(char *original, char *replacement)
-{
- char *rover1;
- char *rover2;
- int argtype1, argtype2;
-
- // Check each argument in turn and compare types.
-
- rover1 = original; rover2 = replacement;
-
- for (;;)
- {
- argtype1 = NextFormatArgument(&rover1);
- argtype2 = NextFormatArgument(&rover2);
-
- if (argtype2 == FORMAT_ARG_INVALID)
- {
- // No more arguments left to read from the replacement string.
-
- break;
- }
- else if (argtype1 == FORMAT_ARG_INVALID)
- {
- // Replacement string has more arguments than the original.
-
- return false;
- }
- else if (!ValidArgumentReplacement(argtype1, argtype2))
- {
- // Not a valid replacement argument.
-
- return false;
- }
- }
-
- return true;
-}
-
-// Get replacement format string, checking arguments.
-
-static char *FormatStringReplacement(char *s)
-{
- char *repl;
-
- repl = DEH_String(s);
-
- if (!ValidFormatReplacement(s, repl))
- {
- printf("WARNING: Unsafe dehacked replacement provided for "
- "printf format string: %s\n", s);
-
- return s;
- }
-
- return repl;
-}
-
-// printf(), performing a replacement on the format string.
-
-void DEH_printf(char *fmt, ...)
-{
- va_list args;
- char *repl;
-
- repl = FormatStringReplacement(fmt);
-
- va_start(args, fmt);
-
- vprintf(repl, args);
-
- va_end(args);
-}
-
-// fprintf(), performing a replacement on the format string.
-
-void DEH_fprintf(FILE *fstream, char *fmt, ...)
-{
- va_list args;
- char *repl;
-
- repl = FormatStringReplacement(fmt);
-
- va_start(args, fmt);
-
- vfprintf(fstream, repl, args);
-
- va_end(args);
-}
-
-// snprintf(), performing a replacement on the format string.
-
-void DEH_snprintf(char *buffer, size_t len, char *fmt, ...)
-{
- va_list args;
- char *repl;
-
- repl = FormatStringReplacement(fmt);
-
- va_start(args, fmt);
-
- vsnprintf(buffer, len, repl, args);
-
- va_end(args);
-}
-
diff --git a/src/doom/.gitignore b/src/doom/.gitignore
new file mode 100644
index 00000000..d4e88e5a
--- /dev/null
+++ b/src/doom/.gitignore
@@ -0,0 +1,5 @@
+Makefile
+Makefile.in
+.deps
+tags
+TAGS
diff --git a/src/doom/Makefile.am b/src/doom/Makefile.am
new file mode 100644
index 00000000..eb229acb
--- /dev/null
+++ b/src/doom/Makefile.am
@@ -0,0 +1,77 @@
+AM_CFLAGS = -I.. @SDL_CFLAGS@ @SDLMIXER_CFLAGS@ @SDLNET_CFLAGS@
+
+noinst_LIBRARIES=libdoom.a
+
+SOURCE_FILES= \
+am_map.c am_map.h \
+ d_englsh.h \
+d_items.c d_items.h \
+d_main.c d_main.h \
+d_net.c \
+ doomdata.h \
+doomdef.c doomdef.h \
+doomstat.c doomstat.h \
+ d_player.h \
+dstrings.c dstrings.h \
+ d_textur.h \
+ d_think.h \
+f_finale.c f_finale.h \
+f_wipe.c f_wipe.h \
+g_game.c g_game.h \
+hu_lib.c hu_lib.h \
+hu_stuff.c hu_stuff.h \
+info.c info.h \
+m_menu.c m_menu.h \
+m_random.c m_random.h \
+p_ceilng.c \
+p_doors.c \
+p_enemy.c \
+p_floor.c \
+p_inter.c p_inter.h \
+p_lights.c \
+ p_local.h \
+p_map.c \
+p_maputl.c \
+p_mobj.c p_mobj.h \
+p_plats.c \
+p_pspr.c p_pspr.h \
+p_saveg.c p_saveg.h \
+p_setup.c p_setup.h \
+p_sight.c \
+p_spec.c p_spec.h \
+p_switch.c \
+p_telept.c \
+p_tick.c p_tick.h \
+p_user.c \
+r_bsp.c r_bsp.h \
+r_data.c r_data.h \
+ r_defs.h \
+r_draw.c r_draw.h \
+ r_local.h \
+r_main.c r_main.h \
+r_plane.c r_plane.h \
+r_segs.c r_segs.h \
+r_sky.c r_sky.h \
+ r_state.h \
+r_things.c r_things.h \
+s_sound.c s_sound.h \
+sounds.c sounds.h \
+statdump.c statdump.h \
+st_lib.c st_lib.h \
+st_stuff.c st_stuff.h \
+wi_stuff.c wi_stuff.h
+
+FEATURE_DEHACKED_SOURCE_FILES = \
+deh_ammo.c \
+deh_cheat.c \
+deh_doom.c \
+deh_frame.c \
+deh_misc.c deh_misc.h \
+deh_ptr.c \
+deh_sound.c \
+deh_thing.c \
+deh_weapon.c
+
+libdoom_a_SOURCES = $(SOURCE_FILES) \
+ $(FEATURE_DEHACKED_SOURCE_FILES)
+
diff --git a/src/am_map.c b/src/doom/am_map.c
index aa6cae05..31f42df9 100644
--- a/src/am_map.c
+++ b/src/doom/am_map.c
@@ -30,12 +30,14 @@
#include "deh_main.h"
#include "z_zone.h"
+#include "doomkeys.h"
#include "doomdef.h"
#include "st_stuff.h"
#include "p_local.h"
#include "w_wad.h"
#include "m_cheat.h"
+#include "m_controls.h"
#include "i_system.h"
// Needs access to LFB.
@@ -88,20 +90,6 @@
#define XHAIRCOLORS GRAYS
// drawing stuff
-#define FB 0
-
-int key_map_north = KEY_UPARROW;
-int key_map_south = KEY_DOWNARROW;
-int key_map_east = KEY_RIGHTARROW;
-int key_map_west = KEY_LEFTARROW;
-int key_map_zoomin = '=';
-int key_map_zoomout = '-';
-int key_map_toggle = KEY_TAB;
-int key_map_maxzoom = '0';
-int key_map_follow = 'f';
-int key_map_grid = 'g';
-int key_map_mark = 'm';
-int key_map_clearmark = 'c';
#define AM_NUMMARKPOINTS 10
@@ -286,18 +274,6 @@ cheatseq_t cheat_amap = CHEAT("iddt", 0);
static boolean stopped = true;
-extern boolean viewactive;
-//extern byte screens[][SCREENWIDTH*SCREENHEIGHT];
-
-
-
-void
-V_MarkRect
-( int x,
- int y,
- int width,
- int height );
-
// Calculates the slope and slope according to the x-axis of a line
// segment in map coordinates (with the upright y-axis n' all) so
// that it can be used with the brain-dead drawing stuff.
@@ -458,7 +434,7 @@ void AM_initVariables(void)
static event_t st_notify = { ev_keyup, AM_MSGENTERED, 0, 0 };
automapactive = true;
- fb = screens[0];
+ fb = I_VideoBuffer;
f_oldloc.x = INT_MAX;
amclock = 0;
@@ -1353,7 +1329,7 @@ void AM_drawMarks(void)
fx = CXMTOF(markpoints[i].x);
fy = CYMTOF(markpoints[i].y);
if (fx >= f_x && fx <= f_w - w && fy >= f_y && fy <= f_h - h)
- V_DrawPatch(fx, fy, FB, marknums[i]);
+ V_DrawPatch(fx, fy, marknums[i]);
}
}
diff --git a/src/am_map.h b/src/doom/am_map.h
index af390d1b..af390d1b 100644
--- a/src/am_map.h
+++ b/src/doom/am_map.h
diff --git a/src/d_englsh.h b/src/doom/d_englsh.h
index de8ff7f0..de8ff7f0 100644
--- a/src/d_englsh.h
+++ b/src/doom/d_englsh.h
diff --git a/src/d_items.c b/src/doom/d_items.c
index 8f12be9f..8f12be9f 100644
--- a/src/d_items.c
+++ b/src/doom/d_items.c
diff --git a/src/d_items.h b/src/doom/d_items.h
index ffc34582..ffc34582 100644
--- a/src/d_items.h
+++ b/src/doom/d_items.h
diff --git a/src/d_main.c b/src/doom/d_main.c
index 025c31eb..0746a579 100644
--- a/src/d_main.c
+++ b/src/doom/d_main.c
@@ -45,8 +45,8 @@
#include "d_iwad.h"
#include "z_zone.h"
+#include "w_main.h"
#include "w_wad.h"
-#include "w_merge.h"
#include "s_sound.h"
#include "v_video.h"
@@ -55,10 +55,13 @@
#include "m_argv.h"
#include "m_config.h"
+#include "m_controls.h"
#include "m_misc.h"
#include "m_menu.h"
#include "p_saveg.h"
+#include "i_endoom.h"
+#include "i_joystick.h"
#include "i_system.h"
#include "i_timer.h"
#include "i_video.h"
@@ -75,6 +78,7 @@
#include "p_setup.h"
#include "r_local.h"
+#include "statdump.h"
#include "d_main.h"
@@ -104,14 +108,6 @@ boolean nomonsters; // checkparm of -nomonsters
boolean respawnparm; // checkparm of -respawn
boolean fastparm; // checkparm of -fast
-boolean singletics = false; // debug flag to cancel adaptiveness
-
-
-// If true, game is running as a screensaver
-
-boolean screensaver_mode = false;
-
-
//extern int soundVolume;
//extern int sfxVolume;
//extern int musicVolume;
@@ -135,58 +131,10 @@ boolean bfgedition;
char wadfile[1024]; // primary wad file
char mapdir[1024]; // directory of development maps
+int show_endoom = 1;
-void D_CheckNetGame (void);
-void D_ProcessEvents (void);
-void G_BuildTiccmd (ticcmd_t* cmd);
-void D_DoAdvanceDemo (void);
-
-
-//
-// EVENT HANDLING
-//
-// Events are asynchronous inputs generally generated by the game user.
-// Events can be discarded if no responder claims them
-//
-
-#define MAXEVENTS 64
-
-static event_t events[MAXEVENTS];
-static int eventhead;
-static int eventtail;
-
-
-//
-// D_PostEvent
-// Called by the I/O functions when input is detected
-//
-void D_PostEvent (event_t* ev)
-{
- events[eventhead] = *ev;
- eventhead = (eventhead + 1) % MAXEVENTS;
-}
-// Read an event from the queue.
-
-event_t *D_PopEvent(void)
-{
- event_t *result;
-
- // No more events waiting.
-
- if (eventtail == eventhead)
- {
- return NULL;
- }
-
- result = &events[eventtail];
-
- // Advance to the next event in the queue.
-
- eventtail = (eventtail + 1) % MAXEVENTS;
-
- return result;
-}
+void D_CheckNetGame (void);
//
@@ -331,7 +279,7 @@ void D_Display (void)
{
// Box showing current mouse speed
- G_DrawMouseSpeedBox();
+ V_DrawMouseSpeedBox(testcontrols_mousespeed);
}
menuactivestate = menuactive;
@@ -346,8 +294,8 @@ void D_Display (void)
y = 4;
else
y = viewwindowy+4;
- V_DrawPatchDirect(viewwindowx+(scaledviewwidth-68)/2,
- y,0,W_CacheLumpName (DEH_String("M_PAUSE"), PU_CACHE));
+ V_DrawPatchDirect(viewwindowx + (scaledviewwidth - 68) / 2, y,
+ W_CacheLumpName (DEH_String("M_PAUSE"), PU_CACHE));
}
@@ -386,13 +334,83 @@ void D_Display (void)
} while (!done);
}
+//
+// Add configuration file variable bindings.
+//
+void D_BindVariables(void)
+{
+ int i;
+
+ M_ApplyPlatformDefaults();
+
+ I_BindVideoVariables();
+ I_BindJoystickVariables();
+ I_BindSoundVariables();
+
+ M_BindBaseControls();
+ M_BindWeaponControls();
+ M_BindMapControls();
+ M_BindMenuControls();
+ M_BindChatControls(MAXPLAYERS);
+
+ key_multi_msgplayer[0] = HUSTR_KEYGREEN;
+ key_multi_msgplayer[1] = HUSTR_KEYINDIGO;
+ key_multi_msgplayer[2] = HUSTR_KEYBROWN;
+ key_multi_msgplayer[3] = HUSTR_KEYRED;
+
+#ifdef FEATURE_MULTIPLAYER
+ NET_BindVariables();
+#endif
+
+ M_BindVariable("mouse_sensitivity", &mouseSensitivity);
+ M_BindVariable("sfx_volume", &sfxVolume);
+ M_BindVariable("music_volume", &musicVolume);
+ M_BindVariable("show_messages", &showMessages);
+ M_BindVariable("screenblocks", &screenblocks);
+ M_BindVariable("detaillevel", &detailLevel);
+ M_BindVariable("snd_channels", &snd_channels);
+ M_BindVariable("vanilla_savegame_limit", &vanilla_savegame_limit);
+ M_BindVariable("vanilla_demo_limit", &vanilla_demo_limit);
+ M_BindVariable("show_endoom", &show_endoom);
+
+ // Multiplayer chat macros
+
+ for (i=0; i<10; ++i)
+ {
+ char buf[12];
+
+ sprintf(buf, "chatmacro%i", i);
+ M_BindVariable(buf, &chat_macros[i]);
+ }
+}
//
-// D_DoomLoop
+// D_GrabMouseCallback
//
-extern boolean demorecording;
+// Called to determine whether to grab the mouse pointer
+//
+
+boolean D_GrabMouseCallback(void)
+{
+ // Drone players don't need mouse focus
+
+ if (drone)
+ return false;
+ // when menu is active or game is paused, release the mouse
+
+ if (menuactive || paused)
+ return false;
+
+ // only grab mouse when playing levels (but not demos)
+
+ return (gamestate == GS_LEVEL) && !demoplayback;
+}
+
+//
+// D_DoomLoop
+//
void D_DoomLoop (void)
{
if (demorecording)
@@ -400,8 +418,13 @@ void D_DoomLoop (void)
TryRunTics();
- I_InitGraphics ();
+ I_SetWindowTitle(gamedescription);
+ I_GraphicsCheckCommandLine();
+ I_InitGraphics();
+ I_EnableLoadingDisk();
+ I_SetGrabMouseCallback(D_GrabMouseCallback);
+ V_RestoreBuffer();
R_ExecuteSetViewSize();
D_StartGameLoop();
@@ -414,26 +437,10 @@ void D_DoomLoop (void)
while (1)
{
// frame syncronous IO operations
- I_StartFrame ();
-
- // process one or more tics
- if (singletics)
- {
- I_StartTic ();
- D_ProcessEvents ();
- G_BuildTiccmd (&netcmds[consoleplayer][maketic%BACKUPTICS]);
- if (advancedemo)
- D_DoAdvanceDemo ();
- M_Ticker ();
- G_Ticker ();
- gametic++;
- maketic++;
- }
- else
- {
- TryRunTics (); // will run at least one tic
- }
-
+ I_StartFrame ();
+
+ TryRunTics (); // will run at least one tic
+
S_UpdateSounds (players[consoleplayer].mo);// move positional sounds
// Update display, next frame, with current state.
@@ -469,7 +476,7 @@ void D_PageTicker (void)
//
void D_PageDrawer (void)
{
- V_DrawPatch (0,0, 0, W_CacheLumpName(pagename, PU_CACHE));
+ V_DrawPatch (0, 0, W_CacheLumpName(pagename, PU_CACHE));
}
@@ -581,13 +588,190 @@ void D_StartTitle (void)
D_AdvanceDemo ();
}
+// Strings for dehacked replacements of the startup banner
+//
+// These are from the original source: some of them are perhaps
+// not used in any dehacked patches
+
+static char *banners[] =
+{
+ // doom2.wad
+ " "
+ "DOOM 2: Hell on Earth v%i.%i"
+ " ",
+ // doom1.wad
+ " "
+ "DOOM Shareware Startup v%i.%i"
+ " ",
+ // doom.wad
+ " "
+ "DOOM Registered Startup v%i.%i"
+ " ",
+ // Registered DOOM uses this
+ " "
+ "DOOM System Startup v%i.%i"
+ " ",
+ // doom.wad (Ultimate DOOM)
+ " "
+ "The Ultimate DOOM Startup v%i.%i"
+ " ",
+ // tnt.wad
+ " "
+ "DOOM 2: TNT - Evilution v%i.%i"
+ " ",
+ // plutonia.wad
+ " "
+ "DOOM 2: Plutonia Experiment v%i.%i"
+ " ",
+};
+
+//
+// Get game name: if the startup banner has been replaced, use that.
+// Otherwise, use the name given
+//
+
+static char *GetGameName(char *gamename)
+{
+ size_t i;
+ char *deh_sub;
+
+ for (i=0; i<arrlen(banners); ++i)
+ {
+ // Has the banner been replaced?
+
+ deh_sub = DEH_String(banners[i]);
+
+ if (deh_sub != banners[i])
+ {
+ // Has been replaced
+ // We need to expand via printf to include the Doom version
+ // number
+ // We also need to cut off spaces to get the basic name
+
+ gamename = Z_Malloc(strlen(deh_sub) + 10, PU_STATIC, 0);
+ sprintf(gamename, deh_sub, DOOM_VERSION / 100, DOOM_VERSION % 100);
+
+ while (gamename[0] != '\0' && isspace(gamename[0]))
+ strcpy(gamename, gamename+1);
+
+ while (gamename[0] != '\0' && isspace(gamename[strlen(gamename)-1]))
+ gamename[strlen(gamename) - 1] = '\0';
+
+ return gamename;
+ }
+ }
+
+ return gamename;
+}
+
+//
+// Find out what version of Doom is playing.
+//
+void D_IdentifyVersion(void)
+{
+ // gamemission is set up by the D_FindIWAD function. But if
+ // we specify '-iwad', we have to identify using
+ // IdentifyIWADByName. However, if the iwad does not match
+ // any known IWAD name, we may have a dilemma. Try to
+ // identify by its contents.
+
+ if (gamemission == none)
+ {
+ unsigned int i;
+
+ for (i=0; i<numlumps; ++i)
+ {
+ if (!strncasecmp(lumpinfo[i].name, "MAP01", 8))
+ {
+ gamemission = doom2;
+ break;
+ }
+ else if (!strncasecmp(lumpinfo[i].name, "E1M1", 8))
+ {
+ gamemission = doom;
+ break;
+ }
+ }
+ if (gamemission == none)
+ {
+ // Still no idea. I don't think this is going to work.
+
+ I_Error("Unknown or invalid IWAD file.");
+ }
+ }
+
+ // Make sure gamemode is set up correctly
+
+ if (logical_gamemission == doom)
+ {
+ // Doom 1. But which version?
+
+ if (W_CheckNumForName("E4M1") > 0)
+ {
+ // Ultimate Doom
+
+ gamemode = retail;
+ }
+ else if (W_CheckNumForName("E3M1") > 0)
+ {
+ gamemode = registered;
+ }
+ else
+ {
+ gamemode = shareware;
+ }
+ }
+ else
+ {
+ // Doom 2 of some kind.
+
+ gamemode = commercial;
+ }
+}
+
+// Set the gamedescription string
+
+void D_SetGameDescription(void)
+{
+ gamedescription = "Unknown";
+
+ if (logical_gamemission == doom)
+ {
+ // Doom 1. But which version?
+
+ if (gamemode == retail)
+ {
+ // Ultimate Doom
+
+ gamedescription = GetGameName("The Ultimate DOOM");
+ }
+ else if (gamemode == registered)
+ {
+ gamedescription = GetGameName("DOOM Registered");
+ }
+ else if (gamemode == shareware)
+ {
+ gamedescription = GetGameName("DOOM Shareware");
+ }
+ }
+ else
+ {
+ // Doom 2 of some kind. But which mission?
+
+ if (logical_gamemission == doom2)
+ gamedescription = GetGameName("DOOM 2: Hell on Earth");
+ else if (logical_gamemission == pack_plut)
+ gamedescription = GetGameName("DOOM 2: Plutonia Experiment");
+ else if (logical_gamemission == pack_tnt)
+ gamedescription = GetGameName("DOOM 2: TNT - Evilution");
+ }
+}
// print title for every printed line
char title[128];
-
static boolean D_AddFile(char *filename)
{
wad_file_t *handle;
@@ -597,18 +781,6 @@ static boolean D_AddFile(char *filename)
return handle != NULL;
}
-// Startup banner
-
-void PrintBanner(char *msg)
-{
- int i;
- int spaces = 35 - (strlen(msg) / 2);
-
- for (i=0; i<spaces; ++i)
- putchar(' ');
-
- puts(msg);
-}
// Copyright message banners
// Some dehacked mods replace these. These are only displayed if they are
@@ -720,9 +892,17 @@ static void InitGameVersion(void)
{
// Determine automatically
- if (gameversion == exe_chex || gameversion == exe_hacx)
+ if (gamemission == pack_chex)
{
- // Already determined
+ // chex.exe - identified by iwad filename
+
+ gameversion = exe_chex;
+ }
+ else if (gamemission == pack_hacx)
+ {
+ // hacx.exe: identified by iwad filename
+
+ gameversion = exe_hacx;
}
else if (gamemode == shareware || gamemode == registered)
{
@@ -762,7 +942,8 @@ static void InitGameVersion(void)
// EXEs prior to the Final Doom exes do not support Final Doom.
- if (gameversion < exe_final && gamemode == commercial)
+ if (gameversion < exe_final && gamemode == commercial
+ && (gamemission == pack_tnt || gamemission == pack_plut))
{
gamemission = doom2;
}
@@ -835,6 +1016,25 @@ static void LoadChexDeh(void)
}
}
+// Function called at exit to display the ENDOOM screen
+
+static void D_Endoom(void)
+{
+ byte *endoom;
+
+ // Don't show ENDOOM if we have it disabled, or we're running
+ // in screensaver or control test mode.
+
+ if (!show_endoom || screensaver_mode || M_CheckParm("-testcontrols") > 0)
+ {
+ return;
+ }
+
+ endoom = W_CacheLumpName(DEH_String("ENDOOM"), PU_STATIC);
+
+ I_Endoom(endoom);
+}
+
static void LoadHacxDeh(void)
{
// If this is the HACX IWAD, we need to load the DEHACKED lump.
@@ -858,19 +1058,11 @@ void D_DoomMain (void)
char file[256];
char demolumpname[9];
- M_FindResponseFile ();
-
- // Undocumented "search for IWADs" parameter used by the setup
- // tool.
-
- if (M_CheckParm("-findiwads") > 0)
- {
- D_FindInstalledIWADs();
- }
+ I_AtExit(D_Endoom, false);
// print banner
- PrintBanner(PACKAGE_STRING);
+ I_PrintBanner(PACKAGE_STRING);
DEH_printf("Z_Init: Init zone memory allocation daemon. \n");
Z_Init ();
@@ -939,7 +1131,7 @@ void D_DoomMain (void)
DEH_Init();
#endif
- iwadfile = D_FindIWAD();
+ iwadfile = D_FindIWAD(IWAD_MASK_DOOM, &gamemission);
// None found?
@@ -984,6 +1176,8 @@ void D_DoomMain (void)
devparm = M_CheckParm ("-devparm");
+ I_DisplayFPSDots(devparm);
+
//!
// @category net
// @vanilla
@@ -1010,7 +1204,29 @@ void D_DoomMain (void)
// find which dir to use for config files
- M_SetConfigDir();
+#ifdef _WIN32
+
+ //!
+ // @platform windows
+ // @vanilla
+ //
+ // Save configuration data and savegames in c:\doomdata,
+ // allowing play from CD.
+ //
+
+ if (M_CheckParm("-cdrom") > 0)
+ {
+ printf(D_CDROM);
+
+ M_SetConfigDir("c:\\doomdata\\");
+ }
+ else
+#endif
+ {
+ // Auto-detect the configuration dir.
+
+ M_SetConfigDir(NULL);
+ }
//!
// @arg <x>
@@ -1043,161 +1259,18 @@ void D_DoomMain (void)
DEH_printf("V_Init: allocate screens.\n");
V_Init ();
+ // Load configuration files before initialising other subsystems.
DEH_printf("M_LoadDefaults: Load system defaults.\n");
- M_ApplyPlatformDefaults();
- M_LoadDefaults (); // load before initing other systems
+ M_SetConfigFilenames("default.cfg", PROGRAM_PREFIX "doom.cfg");
+ D_BindVariables();
+ M_LoadDefaults();
+
+ // Save configuration at exit.
+ I_AtExit(M_SaveDefaults, false);
DEH_printf("W_Init: Init WADfiles.\n");
D_AddFile(iwadfile);
-
-#ifdef FEATURE_WAD_MERGE
-
- // Merged PWADs are loaded first, because they are supposed to be
- // modified IWADs.
-
- //!
- // @arg <files>
- // @category mod
- //
- // Simulates the behavior of deutex's -merge option, merging a PWAD
- // into the main IWAD. Multiple files may be specified.
- //
-
- p = M_CheckParmWithArgs("-merge", 1);
-
- if (p > 0)
- {
- for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
- {
- char *filename;
-
- filename = D_TryFindWADByName(myargv[p]);
-
- printf(" merging %s\n", filename);
- W_MergeFile(filename);
- }
- }
-
- // NWT-style merging:
-
- // NWT's -merge option:
-
- //!
- // @arg <files>
- // @category mod
- //
- // Simulates the behavior of NWT's -merge option. Multiple files
- // may be specified.
-
- p = M_CheckParmWithArgs("-nwtmerge", 1);
-
- if (p > 0)
- {
- for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
- {
- char *filename;
-
- filename = D_TryFindWADByName(myargv[p]);
-
- printf(" performing NWT-style merge of %s\n", filename);
- W_NWTDashMerge(filename);
- }
- }
-
- // Add flats
-
- //!
- // @arg <files>
- // @category mod
- //
- // Simulates the behavior of NWT's -af option, merging flats into
- // the main IWAD directory. Multiple files may be specified.
- //
-
- p = M_CheckParmWithArgs("-af", 1);
-
- if (p > 0)
- {
- for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
- {
- char *filename;
-
- filename = D_TryFindWADByName(myargv[p]);
-
- printf(" merging flats from %s\n", filename);
- W_NWTMergeFile(filename, W_NWT_MERGE_FLATS);
- }
- }
-
- //!
- // @arg <files>
- // @category mod
- //
- // Simulates the behavior of NWT's -as option, merging sprites
- // into the main IWAD directory. Multiple files may be specified.
- //
-
- p = M_CheckParmWithArgs("-as", 1);
-
- if (p > 0)
- {
- for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
- {
- char *filename;
-
- filename = D_TryFindWADByName(myargv[p]);
-
- printf(" merging sprites from %s\n", filename);
- W_NWTMergeFile(filename, W_NWT_MERGE_SPRITES);
- }
- }
-
- //!
- // @arg <files>
- // @category mod
- //
- // Equivalent to "-af <files> -as <files>".
- //
-
- p = M_CheckParmWithArgs("-aa", 1);
-
- if (p > 0)
- {
- for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
- {
- char *filename;
-
- filename = D_TryFindWADByName(myargv[p]);
-
- printf(" merging sprites and flats from %s\n", filename);
- W_NWTMergeFile(filename, W_NWT_MERGE_SPRITES | W_NWT_MERGE_FLATS);
- }
- }
-
-#endif
-
- //!
- // @arg <files>
- // @vanilla
- //
- // Load the specified PWAD files.
- //
-
- p = M_CheckParmWithArgs("-file", 1);
- if (p)
- {
- // the parms after p are wadfile/lump names,
- // until end of parms or another - preceded parm
- modifiedgame = true; // homebrew levels
- while (++p != myargc && myargv[p][0] != '-')
- {
- char *filename;
-
- filename = D_TryFindWADByName(myargv[p]);
-
- D_AddFile(filename);
- }
- }
+ modifiedgame = W_ParseCommandLine();
// Debug:
// W_PrintDirectory();
@@ -1256,6 +1329,8 @@ void D_DoomMain (void)
}
+ I_AtExit((atexit_func_t) G_CheckDemoStatus, true);
+
// Generate the WAD hash table. Speed things up a bit.
W_GenerateHashTable();
@@ -1265,7 +1340,7 @@ void D_DoomMain (void)
LoadChexDeh();
LoadHacxDeh();
D_SetGameDescription();
- D_SetSaveGameDir();
+ savegamedir = M_GetSaveGameDir(D_SaveGameIWADName(gamemission));
// Check for -file in shareware
if (modifiedgame)
@@ -1427,48 +1502,16 @@ void D_DoomMain (void)
startloadgame = -1;
}
- //!
- // @category video
- //
- // Disable vertical mouse movement.
- //
-
- if (M_CheckParm("-novert"))
- novert = true;
-
- //!
- // @category video
- //
- // Enable vertical mouse movement.
- //
-
- if (M_CheckParm("-nonovert"))
- novert = false;
-
if (W_CheckNumForName("SS_START") >= 0
|| W_CheckNumForName("FF_END") >= 0)
{
- printf ("===========================================================================\n");
+ I_PrintDivider();
printf(" WARNING: The loaded WAD file contains modified sprites or\n"
" floor textures. You may want to use the '-merge' command\n"
" line option instead of '-file'.\n");
}
-
- printf ("===========================================================================\n");
-
- PrintBanner(gamedescription);
-
-
- printf (
- "===========================================================================\n"
- " " PACKAGE_NAME " is free software, covered by the GNU General Public\n"
- " License. There is NO warranty; not even for MERCHANTABILITY or FITNESS\n"
- " FOR A PARTICULAR PURPOSE. You are welcome to change and distribute\n"
- " copies under certain conditions. See the source for more information.\n"
-
- "===========================================================================\n"
- );
+ I_PrintStartupBanner(gamedescription);
PrintDehackedBanners();
DEH_printf("M_Init: Init miscellaneous info.\n");
@@ -1481,7 +1524,9 @@ void D_DoomMain (void)
P_Init ();
DEH_printf("I_Init: Setting up machine state.\n");
- I_Init ();
+ I_CheckIsScreensaver();
+ I_InitTimer();
+ I_InitJoystick();
#ifdef FEATURE_MULTIPLAYER
printf ("NET_Init: Init network subsystem.\n");
@@ -1523,6 +1568,12 @@ void D_DoomMain (void)
bfgedition = true;
}
+ if (M_CheckParmWithArgs("-statdump", 1))
+ {
+ I_AtExit(StatDump, true);
+ DEH_printf("External statistics registered.\n");
+ }
+
//!
// @arg <x>
// @category demo
diff --git a/src/d_main.h b/src/doom/d_main.h
index 14536447..a1770536 100644
--- a/src/d_main.h
+++ b/src/doom/d_main.h
@@ -28,26 +28,11 @@
#ifndef __D_MAIN__
#define __D_MAIN__
-#include "d_event.h"
+#include "doomdef.h"
-//
-// 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);
-
-// Read an event from the event queue
-
-event_t *D_PopEvent(void);
-
// Read events from all input devices
void D_ProcessEvents (void);
@@ -62,5 +47,12 @@ void D_AdvanceDemo (void);
void D_DoAdvanceDemo (void);
void D_StartTitle (void);
+//
+// GLOBAL VARIABLES
+//
+
+extern gameaction_t gameaction;
+
#endif
+
diff --git a/src/doom/d_net.c b/src/doom/d_net.c
new file mode 100644
index 00000000..4ab61425
--- /dev/null
+++ b/src/doom/d_net.c
@@ -0,0 +1,304 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// DOOM Network game communication and protocol,
+// all OS independend parts.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdlib.h>
+
+#include "doomfeatures.h"
+
+#include "d_main.h"
+#include "m_argv.h"
+#include "m_menu.h"
+#include "i_system.h"
+#include "i_timer.h"
+#include "i_video.h"
+#include "g_game.h"
+#include "doomdef.h"
+#include "doomstat.h"
+#include "w_checksum.h"
+#include "w_wad.h"
+
+#include "deh_main.h"
+
+#include "d_loop.h"
+
+ticcmd_t *netcmds;
+
+// Called when a player leaves the game
+
+static void PlayerQuitGame(player_t *player)
+{
+ static char exitmsg[80];
+ unsigned int player_num;
+
+ player_num = player - players;
+
+ // Do this the same way as Vanilla Doom does, to allow dehacked
+ // replacements of this message
+
+ strncpy(exitmsg, DEH_String("Player 1 left the game"), sizeof(exitmsg));
+ exitmsg[sizeof(exitmsg) - 1] = '\0';
+
+ exitmsg[7] += player_num;
+
+ playeringame[player_num] = false;
+ players[consoleplayer].message = exitmsg;
+
+ // TODO: check if it is sensible to do this:
+
+ if (demorecording)
+ {
+ G_CheckDemoStatus ();
+ }
+}
+
+static void RunTic(ticcmd_t *cmds, boolean *ingame)
+{
+ extern boolean advancedemo;
+ unsigned int i;
+
+ // Check for player quits.
+
+ for (i = 0; i < MAXPLAYERS; ++i)
+ {
+ if (!demoplayback && playeringame[i] && !ingame[i])
+ {
+ PlayerQuitGame(&players[i]);
+ }
+ }
+
+ netcmds = cmds;
+
+ // check that there are players in the game. if not, we cannot
+ // run a tic.
+
+ if (advancedemo)
+ D_DoAdvanceDemo ();
+
+ G_Ticker ();
+}
+
+static loop_interface_t doom_loop_interface = {
+ D_ProcessEvents,
+ G_BuildTiccmd,
+ RunTic,
+ M_Ticker
+};
+
+
+// Load game settings from the specified structure and
+// set global variables.
+
+static void LoadGameSettings(net_gamesettings_t *settings,
+ net_connect_data_t *connect_data)
+{
+ unsigned int i;
+
+ deathmatch = settings->deathmatch;
+ ticdup = settings->ticdup;
+ startepisode = settings->episode;
+ startmap = settings->map;
+ startskill = settings->skill;
+ startloadgame = settings->loadgame;
+ lowres_turn = settings->lowres_turn;
+ nomonsters = settings->nomonsters;
+ fastparm = settings->fast_monsters;
+ respawnparm = settings->respawn_monsters;
+ timelimit = settings->timelimit;
+
+ if (lowres_turn)
+ {
+ printf("NOTE: Turning resolution is reduced; this is probably "
+ "because there is a client recording a Vanilla demo.\n");
+ }
+
+ if (!connect_data->drone)
+ {
+ consoleplayer = settings->consoleplayer;
+ }
+ else
+ {
+ consoleplayer = 0;
+ }
+
+ for (i=0; i<MAXPLAYERS; ++i)
+ {
+ playeringame[i] = i < settings->num_players;
+ }
+}
+
+// Save the game settings from global variables to the specified
+// game settings structure.
+
+static void SaveGameSettings(net_gamesettings_t *settings,
+ net_connect_data_t *connect_data)
+{
+ // Fill in game settings structure with appropriate parameters
+ // for the new game
+
+ settings->deathmatch = deathmatch;
+ settings->episode = startepisode;
+ settings->map = startmap;
+ settings->skill = startskill;
+ settings->loadgame = startloadgame;
+ settings->gameversion = gameversion;
+ settings->nomonsters = nomonsters;
+ settings->fast_monsters = fastparm;
+ settings->respawn_monsters = respawnparm;
+ settings->timelimit = timelimit;
+
+ settings->lowres_turn = M_CheckParm("-record") > 0
+ && M_CheckParm("-longtics") == 0;
+
+ connect_data->drone = false;
+ connect_data->max_players = MAXPLAYERS;
+
+ //!
+ // @category net
+ //
+ // Run as the left screen in three screen mode.
+ //
+
+ if (M_CheckParm("-left") > 0)
+ {
+ viewangleoffset = ANG90;
+ connect_data->drone = true;
+ }
+
+ //!
+ // @category net
+ //
+ // Run as the right screen in three screen mode.
+ //
+
+ if (M_CheckParm("-right") > 0)
+ {
+ viewangleoffset = ANG270;
+ connect_data->drone = true;
+ }
+
+ //
+ // Connect data
+ //
+
+ // Game type fields:
+
+ connect_data->gamemode = gamemode;
+ connect_data->gamemission = gamemission;
+
+ // Are we recording a demo? Possibly set lowres turn mode
+
+ connect_data->lowres_turn = settings->lowres_turn;
+
+ // Read checksums of our WAD directory and dehacked information
+
+ W_Checksum(connect_data->wad_sha1sum);
+ DEH_Checksum(connect_data->deh_sha1sum);
+
+ // Are we playing with the Freedoom IWAD?
+
+ connect_data->is_freedoom = W_CheckNumForName("FREEDOOM") >= 0;
+}
+
+void D_InitSinglePlayerGame(net_gamesettings_t *settings)
+{
+ // default values for single player
+
+ settings->consoleplayer = 0;
+ settings->num_players = 1;
+
+ netgame = false;
+
+ //!
+ // @category net
+ //
+ // Start the game playing as though in a netgame with a single
+ // player. This can also be used to play back single player netgame
+ // demos.
+ //
+
+ if (M_CheckParm("-solo-net") > 0)
+ {
+ netgame = true;
+ }
+}
+
+//
+// D_CheckNetGame
+// Works out player numbers among the net participants
+//
+void D_CheckNetGame (void)
+{
+ net_connect_data_t connect_data;
+ net_gamesettings_t settings;
+
+ D_RegisterLoopCallbacks(&doom_loop_interface);
+
+ // Call D_QuitNetGame on exit
+
+ I_AtExit(D_QuitNetGame, true);
+
+ SaveGameSettings(&settings, &connect_data);
+
+ if (D_InitNetGame(&connect_data, &settings))
+ {
+ netgame = true;
+ autostart = true;
+ }
+ else
+ {
+ D_InitSinglePlayerGame(&settings);
+ }
+
+ LoadGameSettings(&settings, &connect_data);
+
+ DEH_printf("startskill %i deathmatch: %i startmap: %i startepisode: %i\n",
+ startskill, deathmatch, startmap, startepisode);
+
+ DEH_printf("player %i of %i (%i nodes)\n",
+ consoleplayer+1, settings.num_players, settings.num_players);
+
+ // Show players here; the server might have specified a time limit
+
+ if (timelimit > 0 && deathmatch)
+ {
+ // Gross hack to work like Vanilla:
+
+ if (timelimit == 20 && M_CheckParm("-avg"))
+ {
+ DEH_printf("Austin Virtual Gaming: Levels will end "
+ "after 20 minutes\n");
+ }
+ else
+ {
+ DEH_printf("Levels will end after %d minute", timelimit);
+ if (timelimit > 1)
+ printf("s");
+ printf(".\n");
+ }
+ }
+}
+
diff --git a/src/d_player.h b/src/doom/d_player.h
index 46b9b6c0..8bdccf46 100644
--- a/src/d_player.h
+++ b/src/doom/d_player.h
@@ -45,6 +45,7 @@
// as commands per game tick.
#include "d_ticcmd.h"
+#include "net_defs.h"
diff --git a/src/d_textur.h b/src/doom/d_textur.h
index 084a5b1b..084a5b1b 100644
--- a/src/d_textur.h
+++ b/src/doom/d_textur.h
diff --git a/src/d_think.h b/src/doom/d_think.h
index 1405230d..1405230d 100644
--- a/src/d_think.h
+++ b/src/doom/d_think.h
diff --git a/src/deh_ammo.c b/src/doom/deh_ammo.c
index 952d8df3..952d8df3 100644
--- a/src/deh_ammo.c
+++ b/src/doom/deh_ammo.c
diff --git a/src/deh_cheat.c b/src/doom/deh_cheat.c
index 89e5d219..8817c56e 100644
--- a/src/deh_cheat.c
+++ b/src/doom/deh_cheat.c
@@ -24,7 +24,9 @@
//
//-----------------------------------------------------------------------------
-#include "doomdef.h"
+#include <stdlib.h>
+#include <string.h>
+
#include "doomtype.h"
#include "deh_defs.h"
diff --git a/src/doom/deh_doom.c b/src/doom/deh_doom.c
new file mode 100644
index 00000000..7549e09e
--- /dev/null
+++ b/src/doom/deh_doom.c
@@ -0,0 +1,74 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// Top-level dehacked definitions for Doom dehacked.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdlib.h>
+#include "deh_defs.h"
+#include "deh_main.h"
+
+char *deh_signatures[] =
+{
+ "Patch File for DeHackEd v2.3",
+ "Patch File for DeHackEd v3.0",
+ NULL
+};
+
+// deh_ammo.c:
+extern deh_section_t deh_section_ammo;
+// deh_cheat.c:
+extern deh_section_t deh_section_cheat;
+// deh_frame.c:
+extern deh_section_t deh_section_frame;
+// deh_misc.c:
+extern deh_section_t deh_section_misc;
+// deh_ptr.c:
+extern deh_section_t deh_section_pointer;
+// deh_sound.c
+extern deh_section_t deh_section_sound;
+// deh_text.c:
+extern deh_section_t deh_section_text;
+// deh_thing.c:
+extern deh_section_t deh_section_thing;
+// deh_weapon.c:
+extern deh_section_t deh_section_weapon;
+
+//
+// List of section types:
+//
+
+deh_section_t *deh_section_types[] =
+{
+ &deh_section_ammo,
+ &deh_section_cheat,
+ &deh_section_frame,
+ &deh_section_misc,
+ &deh_section_pointer,
+ &deh_section_sound,
+ &deh_section_text,
+ &deh_section_thing,
+ &deh_section_weapon,
+ NULL
+};
+
diff --git a/src/deh_frame.c b/src/doom/deh_frame.c
index d504637c..8fc01803 100644
--- a/src/deh_frame.c
+++ b/src/doom/deh_frame.c
@@ -24,9 +24,9 @@
//
//-----------------------------------------------------------------------------
+#include <stdio.h>
#include <stdlib.h>
-#include "doomdef.h"
#include "doomtype.h"
#include "d_items.h"
#include "info.h"
diff --git a/src/deh_misc.c b/src/doom/deh_misc.c
index 33faa807..eb5acece 100644
--- a/src/deh_misc.c
+++ b/src/doom/deh_misc.c
@@ -27,7 +27,6 @@
#include <stdlib.h>
#include <string.h>
-#include "doomdef.h"
#include "doomtype.h"
#include "deh_defs.h"
#include "deh_io.h"
diff --git a/src/deh_misc.h b/src/doom/deh_misc.h
index a589b104..a589b104 100644
--- a/src/deh_misc.h
+++ b/src/doom/deh_misc.h
diff --git a/src/deh_ptr.c b/src/doom/deh_ptr.c
index dbec5382..0d1764c9 100644
--- a/src/deh_ptr.c
+++ b/src/doom/deh_ptr.c
@@ -24,10 +24,10 @@
//
//-----------------------------------------------------------------------------
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "doomdef.h"
#include "doomtype.h"
#include "info.h"
diff --git a/src/deh_sound.c b/src/doom/deh_sound.c
index 4a13d0ca..251cdccb 100644
--- a/src/deh_sound.c
+++ b/src/doom/deh_sound.c
@@ -24,9 +24,9 @@
//
//-----------------------------------------------------------------------------
+#include <stdio.h>
#include <stdlib.h>
-#include "doomdef.h"
#include "doomfeatures.h"
#include "doomtype.h"
#include "deh_defs.h"
@@ -36,12 +36,12 @@
DEH_BEGIN_MAPPING(sound_mapping, sfxinfo_t)
DEH_UNSUPPORTED_MAPPING("Offset")
- DEH_MAPPING("Zero/One", singularity)
+ DEH_UNSUPPORTED_MAPPING("Zero/One")
DEH_MAPPING("Value", priority)
DEH_MAPPING("Zero 1", link)
DEH_MAPPING("Zero 2", pitch)
DEH_MAPPING("Zero 3", volume)
- DEH_MAPPING("Zero 4", data)
+ DEH_UNSUPPORTED_MAPPING("Zero 4")
DEH_MAPPING("Neg. One 1", usefulness)
DEH_MAPPING("Neg. One 2", lumpnum)
DEH_END_MAPPING
@@ -98,7 +98,6 @@ static void DEH_SoundParseLine(deh_context_t *context, char *line, void *tag)
// Set the field value
DEH_SetMapping(context, &sound_mapping, sfx, variable_name, ivalue);
-
}
deh_section_t deh_section_sound =
diff --git a/src/deh_thing.c b/src/doom/deh_thing.c
index 87b3c783..d4e05f01 100644
--- a/src/deh_thing.c
+++ b/src/doom/deh_thing.c
@@ -24,9 +24,9 @@
//
//-----------------------------------------------------------------------------
+#include <stdio.h>
#include <stdlib.h>
-#include "doomdef.h"
#include "doomtype.h"
#include "deh_defs.h"
diff --git a/src/deh_weapon.c b/src/doom/deh_weapon.c
index a0d47186..5c590fe8 100644
--- a/src/deh_weapon.c
+++ b/src/doom/deh_weapon.c
@@ -24,10 +24,10 @@
//
//-----------------------------------------------------------------------------
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "doomdef.h"
#include "doomtype.h"
#include "d_items.h"
diff --git a/src/doom/doom.desktop.in b/src/doom/doom.desktop.in
new file mode 100644
index 00000000..44b76e62
--- /dev/null
+++ b/src/doom/doom.desktop.in
@@ -0,0 +1,7 @@
+[Desktop Entry]
+Name=@PACKAGE_NAME@
+Exec=@PROGRAM_PREFIX@doom
+Icon=@PROGRAM_PREFIX@doom
+Type=Application
+Comment=@PACKAGE_SHORTDESC@
+Categories=Game;ActionGame;
diff --git a/src/doomdata.h b/src/doom/doomdata.h
index 66733aea..66733aea 100644
--- a/src/doomdata.h
+++ b/src/doom/doomdata.h
diff --git a/src/doomdef.c b/src/doom/doomdef.c
index 1ad48525..1ad48525 100644
--- a/src/doomdef.c
+++ b/src/doom/doomdef.c
diff --git a/src/doomdef.h b/src/doom/doomdef.h
index fa85a47f..049ba9e3 100644
--- a/src/doomdef.h
+++ b/src/doom/doomdef.h
@@ -31,38 +31,9 @@
#include <stdio.h>
#include <string.h>
-// #define macros to provide functions missing in Windows.
-// Outside Windows, we use strings.h for str[n]casecmp.
-
-
-#ifdef _WIN32
-
-#define snprintf _snprintf
-#define vsnprintf _vsnprintf
-#define strcasecmp stricmp
-#define strncasecmp strnicmp
-
-#else
-
-#include <strings.h>
-
-#endif
-
-
-//
-// The packed attribute forces structures to be packed into the minimum
-// space necessary. If this is not done, the compiler may align structure
-// fields differently to optimize memory access, inflating the overall
-// structure size. It is important to use the packed attribute on certain
-// structures where alignment is important, particularly data read/written
-// to disk.
-//
-
-#ifdef __GNUC__
-#define PACKEDATTR __attribute__((packed))
-#else
-#define PACKEDATTR
-#endif
+#include "doomtype.h"
+#include "i_timer.h"
+#include "d_mode.h"
//
// Global parameters/defines.
@@ -74,68 +45,12 @@
#define DOOM_191_VERSION 111
-// 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;
-
-// What version are we emulating?
-
-typedef enum
-{
- exe_doom_1_9, // Doom 1.9: used for shareware, registered and commercial
- exe_hacx, // Hacx executable (Doom 1.9 with patch applied)
- exe_ultimate, // Ultimate Doom (retail)
- exe_final, // Final Doom
- exe_final2, // Final Doom (alternate exe)
- exe_chex, // Chex Quest executable (based on Final Doom)
-} GameVersion_t;
-
-
// If rangecheck is undefined,
// most parameter validation debugging code will not be compiled
#define RANGECHECK
-
-
-// Screen width and height.
-
-#define SCREENWIDTH 320
-#define SCREENHEIGHT 200
-
-// Screen width used for "squash" scale functions
-
-#define SCREENWIDTH_4_3 256
-
-// Screen height used for "stretch" scale functions.
-
-#define SCREENHEIGHT_4_3 240
-
// The maximum number of players, multiplayer/networking.
-#define MAXPLAYERS 4
-
-// State updates, number of tics / second.
-#define TICRATE 35
+#define MAXPLAYERS 4
// The current state of the game: whether we are
// playing, gazing at the intermission screen,
@@ -148,6 +63,20 @@ typedef enum
GS_DEMOSCREEN,
} gamestate_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;
+
//
// Difficulty/skill settings/filters.
//
@@ -160,18 +89,6 @@ typedef enum
// Deaf monsters/do not react to sound.
#define MTF_AMBUSH 8
-typedef enum
-{
- sk_noitems = -1, // the "-skill 0" hack
- sk_baby = 0,
- sk_easy,
- sk_medium,
- sk_hard,
- sk_nightmare
-} skill_t;
-
-
-
//
// Key cards.
@@ -256,59 +173,4 @@ typedef enum
} powerduration_t;
-
-// fraggle: moved key definitions to a separate file
-
-#include "doomkeys.h"
-
-
-// DOOM basic types (boolean),
-// and max/min values.
-//#include "doomtype.h"
-
-// Fixed point.
-//#include "m_fixed.h"
-
-// Endianess handling.
-//#include "m_swap.h"
-
-
-// Binary Angles, sine/cosine/atan lookups.
-//#include "tables.h"
-
-// Event type.
-//#include "d_event.h"
-
-// Game function, skills.
-//#include "g_game.h"
-
-// All external data is defined here.
-//#include "doomdata.h"
-
-// All important printed strings.
-// Language selection (message strings).
-//#include "dstrings.h"
-
-// Player is a special actor.
-//struct player_s;
-
-
-//#include "d_items.h"
-//#include "d_player.h"
-//#include "p_mobj.h"
-//#include "d_net.h"
-
-// PLAY
-//#include "p_tick.h"
-
-
-
-
-// Header, generated by sound utility.
-// The utility was written by Dave Taylor.
-//#include "sounds.h"
-
-
-
-
#endif // __DOOMDEF__
diff --git a/src/doomstat.c b/src/doom/doomstat.c
index e5fe46b2..2bbb45e7 100644
--- a/src/doomstat.c
+++ b/src/doom/doomstat.c
@@ -24,7 +24,7 @@
//
//-----------------------------------------------------------------------------
-
+#include <stdio.h>
#include "doomstat.h"
diff --git a/src/doomstat.h b/src/doom/doomstat.h
index a0e21a25..9e09bb42 100644
--- a/src/doomstat.h
+++ b/src/doom/doomstat.h
@@ -36,12 +36,15 @@
// We need globally shared data structures,
// for defining the global state variables.
#include "doomdata.h"
-#include "d_net.h"
+#include "d_loop.h"
// We need the playr data structure as well.
#include "d_player.h"
+// Game mode/mission
+#include "d_mode.h"
+#include "net_defs.h"
@@ -55,8 +58,6 @@ extern boolean fastparm; // checkparm of -fast
extern boolean devparm; // DEBUG: launched with -devparm
-extern boolean screensaver_mode; // game running as a screensaver?
-
// -----------------------------------------------------
// Game Mode - identify IWAD as shareware, retail etc.
//
@@ -65,6 +66,15 @@ extern GameMission_t gamemission;
extern GameVersion_t gameversion;
extern char *gamedescription;
+// Convenience macro.
+// 'gamemission' can be equal to pack_chex or pack_hacx, but these are
+// just modified versions of doom and doom2, and should be interpreted
+// as the same most of the time.
+
+#define logical_gamemission \
+ (gamemission == pack_chex ? doom : \
+ gamemission == pack_hacx ? doom2 : gamemission)
+
// Set if homebrew PWAD stuff has been added.
extern boolean modifiedgame;
@@ -93,9 +103,6 @@ extern int gamemap;
// If non-zero, exit the level after this number of minutes
extern int timelimit;
-// vertical movement from mouse/joystick disabled
-extern int novert;
-
// Nightmare mode flag, single player.
extern boolean respawnmonsters;
@@ -147,15 +154,10 @@ extern boolean paused; // Game Pause?
extern boolean viewactive;
extern boolean nodrawers;
-extern boolean noblit;
-extern int viewwindowx;
-extern int viewwindowy;
-extern int viewheight;
-extern int viewwidth;
-extern int scaledviewwidth;
extern boolean testcontrols;
+extern int testcontrols_mousespeed;
@@ -220,9 +222,6 @@ extern gamestate_t gamestate;
-extern int gametic;
-
-
// Bookkeeping on players - state.
extern player_t players[MAXPLAYERS];
@@ -243,9 +242,6 @@ extern mapthing_t playerstarts[MAXPLAYERS];
extern wbstartstruct_t wminfo;
-// LUT of ammunition limits for each kind.
-// This doubles with BackPack powerup item.
-extern int maxammo[NUMAMMO];
@@ -268,9 +264,6 @@ extern boolean precache;
extern gamestate_t wipegamestate;
extern int mouseSensitivity;
-//?
-// debug flag to cancel adaptiveness
-extern boolean singletics;
extern int bodyqueslot;
@@ -288,12 +281,7 @@ extern int skyflatnum;
extern int rndindex;
-extern int maketic;
-extern int nettics[MAXPLAYERS];
-
-extern ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS];
-extern int ticdup;
-
+extern ticcmd_t *netcmds;
#endif
diff --git a/src/dstrings.c b/src/doom/dstrings.c
index 01a438ae..01a438ae 100644
--- a/src/dstrings.c
+++ b/src/doom/dstrings.c
diff --git a/src/dstrings.h b/src/doom/dstrings.h
index d47fc1af..d47fc1af 100644
--- a/src/dstrings.h
+++ b/src/doom/dstrings.h
diff --git a/src/f_finale.c b/src/doom/f_finale.c
index 3f0082cb..0b3e3813 100644
--- a/src/f_finale.c
+++ b/src/doom/f_finale.c
@@ -25,7 +25,7 @@
//-----------------------------------------------------------------------------
-
+#include <stdio.h>
#include <ctype.h>
// Functions.
@@ -38,6 +38,7 @@
#include "s_sound.h"
// Data.
+#include "d_main.h"
#include "dstrings.h"
#include "sounds.h"
@@ -121,7 +122,7 @@ void F_StartFinale (void)
viewactive = false;
automapactive = false;
- if (gamemission == doom)
+ if (logical_gamemission == doom)
{
S_ChangeMusic(mus_victor, true);
}
@@ -143,8 +144,8 @@ void F_StartFinale (void)
screen->level = 5;
}
- if (gamemission == screen->mission
- && (gamemission != doom || gameepisode == screen->episode)
+ if (logical_gamemission == screen->mission
+ && (logical_gamemission != doom || gameepisode == screen->episode)
&& gamemap == screen->level)
{
finaletext = screen->text;
@@ -245,7 +246,7 @@ void F_TextWrite (void)
// erase the entire screen to a tiled background
src = W_CacheLumpName ( finaleflat , PU_CACHE);
- dest = screens[0];
+ dest = I_VideoBuffer;
for (y=0 ; y<SCREENHEIGHT ; y++)
{
@@ -293,7 +294,7 @@ void F_TextWrite (void)
w = SHORT (hu_font[c]->width);
if (cx+w > SCREENWIDTH)
break;
- V_DrawPatch(cx, cy, 0, hu_font[c]);
+ V_DrawPatch(cx, cy, hu_font[c]);
cx+=w;
}
@@ -344,9 +345,6 @@ boolean castattacking;
//
// F_StartCast
//
-extern gamestate_t wipegamestate;
-
-
void F_StartCast (void)
{
wipegamestate = -1; // force a screen wipe
@@ -537,7 +535,7 @@ void F_CastPrint (char* text)
}
w = SHORT (hu_font[c]->width);
- V_DrawPatch(cx, 180, 0, hu_font[c]);
+ V_DrawPatch(cx, 180, hu_font[c]);
cx+=w;
}
@@ -547,7 +545,6 @@ void F_CastPrint (char* text)
//
// F_CastDrawer
//
-void V_DrawPatchFlipped (int x, int y, int scrn, patch_t *patch);
void F_CastDrawer (void)
{
@@ -558,7 +555,7 @@ void F_CastDrawer (void)
patch_t* patch;
// erase the entire screen to a background
- V_DrawPatch (0,0,0, W_CacheLumpName (DEH_String("BOSSBACK"), PU_CACHE));
+ V_DrawPatch (0, 0, W_CacheLumpName (DEH_String("BOSSBACK"), PU_CACHE));
F_CastPrint (DEH_String(castorder[castnum].name));
@@ -570,9 +567,9 @@ void F_CastDrawer (void)
patch = W_CacheLumpNum (lump+firstspritelump, PU_CACHE);
if (flip)
- V_DrawPatchFlipped (160,170,0,patch);
+ V_DrawPatchFlipped(160, 170, patch);
else
- V_DrawPatch (160,170,0,patch);
+ V_DrawPatch(160, 170, patch);
}
@@ -592,7 +589,7 @@ F_DrawPatchCol
int count;
column = (column_t *)((byte *)patch + LONG(patch->columnofs[col]));
- desttop = screens[0]+x;
+ desttop = I_VideoBuffer + x;
// step through the posts in a column
while (column->topdelta != 0xff )
@@ -647,9 +644,9 @@ void F_BunnyScroll (void)
return;
if (finalecount < 1180)
{
- V_DrawPatch ((SCREENWIDTH-13*8)/2,
- (SCREENHEIGHT-8*8)/2,0,
- W_CacheLumpName (DEH_String("END0"),PU_CACHE));
+ V_DrawPatch((SCREENWIDTH - 13 * 8) / 2,
+ (SCREENHEIGHT - 8 * 8) / 2,
+ W_CacheLumpName(DEH_String("END0"), PU_CACHE));
laststage = 0;
return;
}
@@ -664,8 +661,9 @@ void F_BunnyScroll (void)
}
DEH_snprintf(name, 10, "END%i", stage);
- V_DrawPatch ((SCREENWIDTH-13*8)/2, (SCREENHEIGHT-8*8)/2,0,
- W_CacheLumpName (name,PU_CACHE));
+ V_DrawPatch((SCREENWIDTH - 13 * 8) / 2,
+ (SCREENHEIGHT - 8 * 8) / 2,
+ W_CacheLumpName (name,PU_CACHE));
}
static void F_ArtScreenDrawer(void)
@@ -702,7 +700,7 @@ static void F_ArtScreenDrawer(void)
lumpname = DEH_String(lumpname);
- V_DrawPatch (0, 0, 0, W_CacheLumpName(lumpname, PU_CACHE));
+ V_DrawPatch (0, 0, W_CacheLumpName(lumpname, PU_CACHE));
}
}
diff --git a/src/f_finale.h b/src/doom/f_finale.h
index 69e1732f..69e1732f 100644
--- a/src/f_finale.h
+++ b/src/doom/f_finale.h
diff --git a/src/f_wipe.c b/src/doom/f_wipe.c
index a3fe1fb3..10c720ef 100644
--- a/src/f_wipe.c
+++ b/src/doom/f_wipe.c
@@ -24,16 +24,14 @@
//
//-----------------------------------------------------------------------------
-
-
-
+#include <string.h>
#include "z_zone.h"
#include "i_video.h"
#include "v_video.h"
#include "m_random.h"
-#include "doomdef.h"
+#include "doomtype.h"
#include "f_wipe.h"
@@ -232,6 +230,8 @@ wipe_exitMelt
int ticks )
{
Z_Free(y);
+ Z_Free(wipe_scr_start);
+ Z_Free(wipe_scr_end);
return 0;
}
@@ -242,7 +242,7 @@ wipe_StartScreen
int width,
int height )
{
- wipe_scr_start = screens[2];
+ wipe_scr_start = Z_Malloc(SCREENWIDTH * SCREENHEIGHT, PU_STATIC, NULL);
I_ReadScreen(wipe_scr_start);
return 0;
}
@@ -254,9 +254,9 @@ wipe_EndScreen
int width,
int height )
{
- wipe_scr_end = screens[3];
+ wipe_scr_end = Z_Malloc(SCREENWIDTH * SCREENHEIGHT, PU_STATIC, NULL);
I_ReadScreen(wipe_scr_end);
- V_DrawBlock(x, y, 0, width, height, wipe_scr_start); // restore start scr.
+ V_DrawBlock(x, y, width, height, wipe_scr_start); // restore start scr.
return 0;
}
@@ -276,14 +276,12 @@ wipe_ScreenWipe
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];
+ wipe_scr = I_VideoBuffer;
(*wipes[wipeno*3])(width, height, ticks);
}
@@ -300,5 +298,5 @@ wipe_ScreenWipe
}
return !go;
-
}
+
diff --git a/src/f_wipe.h b/src/doom/f_wipe.h
index 9045be3f..9045be3f 100644
--- a/src/f_wipe.h
+++ b/src/doom/f_wipe.h
diff --git a/src/g_game.c b/src/doom/g_game.c
index fe168fae..554fe542 100644
--- a/src/g_game.c
+++ b/src/doom/g_game.c
@@ -30,6 +30,7 @@
#include <math.h>
#include "doomdef.h"
+#include "doomkeys.h"
#include "doomstat.h"
#include "deh_main.h"
@@ -38,6 +39,7 @@
#include "z_zone.h"
#include "f_finale.h"
#include "m_argv.h"
+#include "m_controls.h"
#include "m_misc.h"
#include "m_menu.h"
#include "m_random.h"
@@ -55,6 +57,7 @@
#include "hu_stuff.h"
#include "st_stuff.h"
#include "am_map.h"
+#include "statdump.h"
// Needs access to LFB.
#include "v_video.h"
@@ -80,19 +83,14 @@
#define SAVEGAMESIZE 0x2c000
-
-
-boolean G_CheckDemoStatus (void);
void G_ReadDemoTiccmd (ticcmd_t* cmd);
void G_WriteDemoTiccmd (ticcmd_t* cmd);
void G_PlayerReborn (int player);
-void G_InitNew (skill_t skill, int episode, int map);
void G_DoReborn (int playernum);
void G_DoLoadLevel (void);
void G_DoNewGame (void);
-void G_DoLoadGame (void);
void G_DoPlayDemo (void);
void G_DoCompleted (void);
void G_DoVictory (void);
@@ -121,7 +119,6 @@ boolean usergame; // ok to save / end game
boolean timingdemo; // if true, exit with report on completion
boolean nodrawers; // for comparative timing purposes
-boolean noblit; // for comparative timing purposes
int starttime; // for comparative timing purposes
boolean viewactive;
@@ -135,7 +132,6 @@ boolean turbodetected[MAXPLAYERS];
int consoleplayer; // player taking events and displaying
int displayplayer; // view being displayed
-int gametic;
int levelstarttic; // gametic at level start
int totalkills, totalitems, totalsecret; // for intermission
@@ -153,76 +149,13 @@ boolean singledemo; // quit after playing a demo from cmdlin
boolean precache = true; // if true, load all graphics at start
boolean testcontrols = false; // Invoked by setup to test controls
+int testcontrols_mousespeed;
-wbstartstruct_t wminfo; // parms for world map / intermission
-
-byte consistancy[MAXPLAYERS][BACKUPTICS];
-
-
-//
-// Controls
-//
-int key_right = KEY_RIGHTARROW;
-int key_left = KEY_LEFTARROW;
-
-int key_up = KEY_UPARROW;
-int key_down = KEY_DOWNARROW;
-int key_strafeleft = ',';
-int key_straferight = '.';
-int key_fire = KEY_RCTRL;
-int key_use = ' ';
-int key_strafe = KEY_RALT;
-int key_speed = KEY_RSHIFT;
-
-int key_weapon1 = '1';
-int key_weapon2 = '2';
-int key_weapon3 = '3';
-int key_weapon4 = '4';
-int key_weapon5 = '5';
-int key_weapon6 = '6';
-int key_weapon7 = '7';
-int key_weapon8 = '8';
-int key_prevweapon = 0;
-int key_nextweapon = 0;
-
-int key_pause = KEY_PAUSE;
-int key_demo_quit = 'q';
-int key_spy = KEY_F12;
-
-int mousebfire = 0;
-int mousebstrafe = 1;
-int mousebforward = 2;
-
-int mousebstrafeleft = -1;
-int mousebstraferight = -1;
-int mousebbackward = -1;
-int mousebuse = -1;
-
-int mousebprevweapon = -1;
-int mousebnextweapon = -1;
-
-// Control whether if a mouse button is double clicked, it acts like
-// "use" has been pressed
-
-int dclick_use = 1;
-
-int joybfire = 0;
-int joybstrafe = 1;
-int joybuse = 3;
-int joybspeed = 2;
-int joybstrafeleft = -1;
-int joybstraferight = -1;
-int joybprevweapon = -1;
-int joybnextweapon = -1;
-
-// fraggle: Disallow mouse and joystick movement to cause forward/backward
-// motion. Specified with the '-novert' command line parameter.
-// This is an int to allow saving to config file
-
-int novert = 0;
+wbstartstruct_t wminfo; // parms for world map / intermission
+byte consistancy[MAXPLAYERS][BACKUPTICS];
#define MAXPLMOVE (forwardmove[1])
@@ -296,8 +229,6 @@ static boolean *joybuttons = &joyarray[1]; // allow [-1]
static int savegameslot;
static char savedescription[32];
-static int testcontrols_mousespeed;
-
#define BODYQUESIZE 32
mobj_t* bodyque[BODYQUESIZE];
@@ -306,115 +237,6 @@ int bodyqueslot;
int vanilla_savegame_limit = 1;
int vanilla_demo_limit = 1;
-
-#define MOUSE_SPEED_BOX_WIDTH 16
-#define COLOR_RED 0xb0
-#define COLOR_BLACK 0x00
-#define COLOR_WHITE 0x04
-#define COLOR_YELLOW 0xe7
-
-void G_DrawMouseSpeedBox(void)
-{
- extern int usemouse;
- int i;
- int box_x, box_y;
- int original_speed;
- int x, y;
- int redline_x;
- int linelen;
- char *lumpname;
- int color;
-
- // If the mouse is turned off or acceleration is turned off, don't
- // draw the box at all.
-
- if (!usemouse || fabs(mouse_acceleration - 1) < 0.01)
- {
- return;
- }
-
- // Calculate box position
-
- box_x = SCREENWIDTH - MOUSE_SPEED_BOX_WIDTH * 8;
- box_y = SCREENHEIGHT - 9;
-
- // Draw the box.
-
- x = box_x;
-
- for (i=0; i<MOUSE_SPEED_BOX_WIDTH; ++i)
- {
- if (i == 0)
- {
- lumpname = "M_LSLEFT";
- }
- else if (i == MOUSE_SPEED_BOX_WIDTH - 1)
- {
- lumpname = "M_LSRGHT";
- }
- else
- {
- lumpname = "M_LSCNTR";
- }
-
- V_DrawPatchDirect(x, box_y, 0, W_CacheLumpName(DEH_String(lumpname),
- PU_CACHE));
- x += 8;
- }
-
- // Calculate the position of the red line. This is 1/3 of the way
- // along the box.
-
- redline_x = (MOUSE_SPEED_BOX_WIDTH / 3) * 8;
-
- // Undo acceleration and get back the original mouse speed
-
- if (testcontrols_mousespeed < mouse_threshold)
- {
- original_speed = testcontrols_mousespeed;
- }
- else
- {
- original_speed = testcontrols_mousespeed - mouse_threshold;
- original_speed = (int) (original_speed / mouse_acceleration);
- original_speed += mouse_threshold;
- }
-
- // Calculate line length
-
- linelen = (original_speed * redline_x) / mouse_threshold;
-
- // Draw horizontal "thermometer"
-
- for (x=0; x<(MOUSE_SPEED_BOX_WIDTH - 1) * 8; ++x)
- {
- if (x < linelen)
- {
- if (x < redline_x)
- {
- color = COLOR_WHITE;
- }
- else
- {
- color = COLOR_YELLOW;
- }
- }
- else
- {
- color = COLOR_BLACK;
- }
-
- screens[0][(box_y - 4) * SCREENWIDTH + box_x + x + 1] = color;
- }
-
- // Draw red line
-
- for (y=box_y - 8; y<box_y; ++y)
- {
- screens[0][y * SCREENWIDTH + box_x + redline_x] = COLOR_RED;
- }
-}
-
int G_CmdChecksum (ticcmd_t* cmd)
{
size_t i;
@@ -430,7 +252,7 @@ static boolean WeaponSelectable(weapontype_t weapon)
{
// Can't select the super shotgun in Doom 1.
- if (weapon == wp_supershotgun && gamemission == doom)
+ if (weapon == wp_supershotgun && logical_gamemission == doom)
{
return false;
}
@@ -504,7 +326,7 @@ static int G_NextWeapon(int direction)
// or reads it from the demo buffer.
// If recording a demo, write it out
//
-void G_BuildTiccmd (ticcmd_t* cmd)
+void G_BuildTiccmd (ticcmd_t* cmd, int maketic)
{
int i;
boolean strafe;
@@ -716,12 +538,7 @@ void G_BuildTiccmd (ticcmd_t* cmd)
}
}
- // fraggle: allow disabling mouse y movement
-
- if (!novert)
- {
- forward += mousey;
- }
+ forward += mousey;
if (strafe)
side += mousex*2;
@@ -787,8 +604,6 @@ void G_BuildTiccmd (ticcmd_t* cmd)
//
// G_DoLoadLevel
//
-extern gamestate_t wipegamestate;
-
void G_DoLoadLevel (void)
{
int i;
@@ -1055,7 +870,7 @@ void G_Ticker (void)
G_DoWorldDone ();
break;
case ga_screenshot:
- V_ScreenShot ();
+ V_ScreenShot("DOOM%02i.pcx");
players[consoleplayer].message = DEH_String("screen shot");
gameaction = ga_nothing;
break;
@@ -1073,9 +888,9 @@ void G_Ticker (void)
if (playeringame[i])
{
cmd = &players[i].cmd;
-
- memcpy (cmd, &netcmds[i][buf], sizeof(ticcmd_t));
-
+
+ memcpy(cmd, &netcmds[i], sizeof(ticcmd_t));
+
if (demoplayback)
G_ReadDemoTiccmd (cmd);
if (demorecording)
@@ -1558,10 +1373,17 @@ void G_DoCompleted (void)
wminfo.maxitems = totalitems;
wminfo.maxsecret = totalsecret;
wminfo.maxfrags = 0;
- if ( gamemode == commercial )
- wminfo.partime = TICRATE*cpars[gamemap-1];
+
+ // Set par time. Doom episode 4 doesn't have a par time, so this
+ // overflows into the cpars array. It's necessary to emulate this
+ // for statcheck regression testing.
+ if (gamemode == commercial)
+ wminfo.partime = TICRATE*cpars[gamemap-1];
+ else if (gameepisode < 4)
+ wminfo.partime = TICRATE*pars[gameepisode][gamemap];
else
- wminfo.partime = TICRATE*pars[gameepisode][gamemap];
+ wminfo.partime = TICRATE*cpars[gamemap];
+
wminfo.pnum = consoleplayer;
for (i=0 ; i<MAXPLAYERS ; i++)
@@ -1578,6 +1400,8 @@ void G_DoCompleted (void)
gamestate = GS_INTERMISSION;
viewactive = false;
automapactive = false;
+
+ StatCopy(&wminfo);
WI_Start (&wminfo);
}
@@ -1798,9 +1622,6 @@ void G_DoNewGame (void)
gameaction = ga_nothing;
}
-// The sky texture to be used instead of the F_SKY1 dummy.
-extern int skytexture;
-
void
G_InitNew
@@ -2256,13 +2077,6 @@ void G_TimeDemo (char* name)
nodrawers = M_CheckParm ("-nodraw");
- //!
- // @vanilla
- //
- // Disable blitting the screen.
- //
-
- noblit = M_CheckParm ("-noblit");
timingdemo = true;
singletics = true;
diff --git a/src/g_game.h b/src/doom/g_game.h
index 65fb06b0..46c80bd8 100644
--- a/src/g_game.h
+++ b/src/doom/g_game.h
@@ -72,7 +72,7 @@ void G_WorldDone (void);
// Read current data from inputs and build a player movement command.
-void G_BuildTiccmd (ticcmd_t *cmd);
+void G_BuildTiccmd (ticcmd_t *cmd, int maketic);
void G_Ticker (void);
boolean G_Responder (event_t* ev);
@@ -81,4 +81,7 @@ void G_ScreenShot (void);
void G_DrawMouseSpeedBox(void);
+extern int vanilla_savegame_limit;
+extern int vanilla_demo_limit;
#endif
+
diff --git a/src/hu_lib.c b/src/doom/hu_lib.c
index 32c13b98..0feff7d7 100644
--- a/src/hu_lib.c
+++ b/src/doom/hu_lib.c
@@ -27,6 +27,7 @@
#include <ctype.h>
#include "doomdef.h"
+#include "doomkeys.h"
#include "v_video.h"
#include "i_swap.h"
@@ -120,7 +121,7 @@ HUlib_drawTextLine
w = SHORT(l->f[c - l->sc]->width);
if (x+w > SCREENWIDTH)
break;
- V_DrawPatchDirect(x, l->y, FG, l->f[c - l->sc]);
+ V_DrawPatchDirect(x, l->y, l->f[c - l->sc]);
x += w;
}
else
@@ -135,7 +136,7 @@ HUlib_drawTextLine
if (drawcursor
&& x + SHORT(l->f['_' - l->sc]->width) <= SCREENWIDTH)
{
- V_DrawPatchDirect(x, l->y, FG, l->f['_' - l->sc]);
+ V_DrawPatchDirect(x, l->y, l->f['_' - l->sc]);
}
}
diff --git a/src/hu_lib.h b/src/doom/hu_lib.h
index 21b6f8c5..a4649b48 100644
--- a/src/hu_lib.h
+++ b/src/doom/hu_lib.h
@@ -29,12 +29,6 @@
// 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
diff --git a/src/hu_stuff.c b/src/doom/hu_stuff.c
index 8547f34a..a6047606 100644
--- a/src/hu_stuff.c
+++ b/src/doom/hu_stuff.c
@@ -27,6 +27,7 @@
#include <ctype.h>
#include "doomdef.h"
+#include "doomkeys.h"
#include "z_zone.h"
@@ -36,6 +37,7 @@
#include "hu_stuff.h"
#include "hu_lib.h"
+#include "m_controls.h"
#include "w_wad.h"
#include "s_sound.h"
@@ -66,7 +68,7 @@
-char* chat_macros[] =
+char *chat_macros[10] =
{
HUSTR_CHATMACRO0,
HUSTR_CHATMACRO1,
@@ -88,18 +90,6 @@ char* player_names[] =
HUSTR_PLRRED
};
-int key_multi_msg = HU_INPUTTOGGLE;
-
-int key_multi_msgplayer[MAXPLAYERS] =
-{
- HUSTR_KEYGREEN,
- HUSTR_KEYINDIGO,
- HUSTR_KEYBROWN,
- HUSTR_KEYRED
-};
-
-int key_message_refresh = KEY_ENTER;
-
char chat_char; // remove later.
static player_t* plr;
patch_t* hu_font[HU_FONTSIZE];
@@ -118,7 +108,6 @@ static hu_stext_t w_message;
static int message_counter;
extern int showMessages;
-extern boolean automapactive;
static boolean headsupactive = false;
@@ -301,49 +290,6 @@ char *mapnames_commercial[] =
THUSTR_32
};
-static const char 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
-};
-
-
void HU_Init(void)
{
@@ -393,7 +339,7 @@ void HU_Start(void)
hu_font,
HU_FONTSTART);
- switch ( gamemission )
+ switch ( logical_gamemission )
{
case doom:
s = HU_TITLE;
@@ -576,7 +522,6 @@ boolean HU_Responder(event_t *ev)
static char lastmessage[HU_MAXLINELENGTH+1];
char* macromessage;
boolean eatkey = false;
- static boolean shiftdown = false;
static boolean altdown = false;
unsigned char c;
int i;
@@ -590,7 +535,6 @@ boolean HU_Responder(event_t *ev)
if (ev->data1 == KEY_RSHIFT)
{
- shiftdown = ev->type == ev_keydown;
return false;
}
else if (ev->data1 == KEY_RALT || ev->data1 == KEY_LALT)
@@ -676,14 +620,6 @@ boolean HU_Responder(event_t *ev)
{
c = ev->data2;
- if (vanilla_keyboard_mapping)
- {
- if (shiftdown || (c >= 'a' && c <= 'z'))
- {
- c = shiftxform[c];
- }
- }
-
eatkey = HUlib_keyInIText(&w_chat, c);
if (eatkey)
{
diff --git a/src/hu_stuff.h b/src/doom/hu_stuff.h
index 9b1618c1..2e56f763 100644
--- a/src/hu_stuff.h
+++ b/src/doom/hu_stuff.h
@@ -61,5 +61,7 @@ void HU_Drawer(void);
char HU_dequeueChatChar(void);
void HU_Erase(void);
+extern char *chat_macros[10];
#endif
+
diff --git a/src/info.c b/src/doom/info.c
index c21a4a4c..30d9f51d 100644
--- a/src/info.c
+++ b/src/doom/info.c
@@ -26,7 +26,7 @@
//
//-----------------------------------------------------------------------------
-
+#include <stdio.h>
#include <stdlib.h>
// Data.
diff --git a/src/info.h b/src/doom/info.h
index f94af13f..f94af13f 100644
--- a/src/info.h
+++ b/src/doom/info.h
diff --git a/src/m_menu.c b/src/doom/m_menu.c
index 5c30f2bc..d10a0622 100644
--- a/src/m_menu.c
+++ b/src/doom/m_menu.c
@@ -31,6 +31,7 @@
#include "doomdef.h"
+#include "doomkeys.h"
#include "dstrings.h"
#include "d_main.h"
@@ -52,6 +53,7 @@
#include "g_game.h"
#include "m_argv.h"
+#include "m_controls.h"
#include "p_saveg.h"
#include "s_sound.h"
@@ -64,43 +66,12 @@
#include "m_menu.h"
-extern void M_QuitDOOM(int);
-
extern patch_t* hu_font[HU_FONTSIZE];
extern boolean message_dontfuckwithme;
extern boolean chat_on; // in heads-up code
//
-// menu keys:
-//
-
-int key_menu_activate = KEY_ESCAPE;
-int key_menu_up = KEY_UPARROW;
-int key_menu_down = KEY_DOWNARROW;
-int key_menu_left = KEY_LEFTARROW;
-int key_menu_right = KEY_RIGHTARROW;
-int key_menu_back = KEY_BACKSPACE;
-int key_menu_forward = KEY_ENTER;
-int key_menu_confirm = 'y';
-int key_menu_abort = 'n';
-
-int key_menu_help = KEY_F1;
-int key_menu_save = KEY_F2;
-int key_menu_load = KEY_F3;
-int key_menu_volume = KEY_F4;
-int key_menu_detail = KEY_F5;
-int key_menu_qsave = KEY_F6;
-int key_menu_endgame = KEY_F7;
-int key_menu_messages = KEY_F8;
-int key_menu_qload = KEY_F9;
-int key_menu_quit = KEY_F10;
-int key_menu_gamma = KEY_F11;
-
-int key_menu_incscreen = KEY_EQUALS;
-int key_menu_decscreen = KEY_MINUS;
-
-//
// defaulted values
//
int mouseSensitivity = 5;
@@ -254,7 +225,6 @@ void M_DrawSelCell(menu_t *menu,int item);
void M_WriteText(int x, int y, char *string);
int M_StringWidth(char *string);
int M_StringHeight(char *string);
-void M_StartControlPanel(void);
void M_StartMessage(char *string,void *routine,boolean input);
void M_StopMessage(void);
void M_ClearMenus (void);
@@ -568,7 +538,9 @@ void M_DrawLoad(void)
{
int i;
- V_DrawPatchDirect (72,28,0,W_CacheLumpName(DEH_String("M_LOADG"),PU_CACHE));
+ V_DrawPatchDirect(72, 28,
+ W_CacheLumpName(DEH_String("M_LOADG"), PU_CACHE));
+
for (i = 0;i < load_end; i++)
{
M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i);
@@ -585,15 +557,18 @@ void M_DrawSaveLoadBorder(int x,int y)
{
int i;
- V_DrawPatchDirect (x-8,y+7,0,W_CacheLumpName(DEH_String("M_LSLEFT"),PU_CACHE));
+ V_DrawPatchDirect(x - 8, y + 7,
+ W_CacheLumpName(DEH_String("M_LSLEFT"), PU_CACHE));
for (i = 0;i < 24;i++)
{
- V_DrawPatchDirect (x,y+7,0,W_CacheLumpName(DEH_String("M_LSCNTR"),PU_CACHE));
+ V_DrawPatchDirect(x, y + 7,
+ W_CacheLumpName(DEH_String("M_LSCNTR"), PU_CACHE));
x += 8;
}
- V_DrawPatchDirect (x,y+7,0,W_CacheLumpName(DEH_String("M_LSRGHT"),PU_CACHE));
+ V_DrawPatchDirect(x, y + 7,
+ W_CacheLumpName(DEH_String("M_LSRGHT"), PU_CACHE));
}
@@ -634,7 +609,7 @@ void M_DrawSave(void)
{
int i;
- V_DrawPatchDirect (72,28,0,W_CacheLumpName(DEH_String("M_SAVEG"),PU_CACHE));
+ V_DrawPatchDirect(72, 28, W_CacheLumpName(DEH_String("M_SAVEG"), PU_CACHE));
for (i = 0;i < load_end; i++)
{
M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i);
@@ -827,11 +802,15 @@ void M_DrawReadThis1(void)
lumpname = "HELP";
break;
+
+ default:
+ I_Error("Unhandled game version");
+ break;
}
lumpname = DEH_String(lumpname);
- V_DrawPatchDirect (0, 0, 0, W_CacheLumpName(lumpname, PU_CACHE));
+ V_DrawPatchDirect (0, 0, W_CacheLumpName(lumpname, PU_CACHE));
ReadDef1.x = skullx;
ReadDef1.y = skully;
@@ -849,7 +828,7 @@ void M_DrawReadThis2(void)
// We only ever draw the second page if this is
// gameversion == exe_doom_1_9 and gamemode == registered
- V_DrawPatchDirect(0, 0, 0, W_CacheLumpName(DEH_String("HELP1"), PU_CACHE));
+ V_DrawPatchDirect(0, 0, W_CacheLumpName(DEH_String("HELP1"), PU_CACHE));
}
@@ -858,7 +837,7 @@ void M_DrawReadThis2(void)
//
void M_DrawSound(void)
{
- V_DrawPatchDirect (60,38,0,W_CacheLumpName(DEH_String("M_SVOL"),PU_CACHE));
+ V_DrawPatchDirect (60, 38, W_CacheLumpName(DEH_String("M_SVOL"), PU_CACHE));
M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(sfx_vol+1),
16,sfxVolume);
@@ -914,7 +893,8 @@ void M_MusicVol(int choice)
//
void M_DrawMainMenu(void)
{
- V_DrawPatchDirect (94,2,0,W_CacheLumpName(DEH_String("M_DOOM"),PU_CACHE));
+ V_DrawPatchDirect(94, 2,
+ W_CacheLumpName(DEH_String("M_DOOM"), PU_CACHE));
}
@@ -925,8 +905,8 @@ void M_DrawMainMenu(void)
//
void M_DrawNewGame(void)
{
- V_DrawPatchDirect (96,14,0,W_CacheLumpName(DEH_String("M_NEWG"),PU_CACHE));
- V_DrawPatchDirect (54,38,0,W_CacheLumpName(DEH_String("M_SKILL"),PU_CACHE));
+ V_DrawPatchDirect(96, 14, W_CacheLumpName(DEH_String("M_NEWG"), PU_CACHE));
+ V_DrawPatchDirect(54, 38, W_CacheLumpName(DEH_String("M_SKILL"), PU_CACHE));
}
void M_NewGame(int choice)
@@ -953,7 +933,7 @@ int epi;
void M_DrawEpisode(void)
{
- V_DrawPatchDirect (54,38,0,W_CacheLumpName(DEH_String("M_EPISOD"),PU_CACHE));
+ V_DrawPatchDirect(54, 38, W_CacheLumpName(DEH_String("M_EPISOD"), PU_CACHE));
}
void M_VerifyNightmare(int key)
@@ -1011,19 +991,20 @@ char msgNames[2][9] = {"M_MSGOFF","M_MSGON"};
void M_DrawOptions(void)
{
- V_DrawPatchDirect (108,15,0,W_CacheLumpName(DEH_String("M_OPTTTL"),PU_CACHE));
+ V_DrawPatchDirect(108, 15, W_CacheLumpName(DEH_String("M_OPTTTL"),
+ PU_CACHE));
- V_DrawPatchDirect (OptionsDef.x + 175,OptionsDef.y+LINEHEIGHT*detail,0,
- W_CacheLumpName(DEH_String(detailNames[detailLevel]),
- PU_CACHE));
+ V_DrawPatchDirect(OptionsDef.x + 175, OptionsDef.y + LINEHEIGHT * detail,
+ W_CacheLumpName(DEH_String(detailNames[detailLevel]),
+ PU_CACHE));
- V_DrawPatchDirect (OptionsDef.x + 120,OptionsDef.y+LINEHEIGHT*messages,0,
- W_CacheLumpName(DEH_String(msgNames[showMessages]),
- PU_CACHE));
+ V_DrawPatchDirect(OptionsDef.x + 120, OptionsDef.y + LINEHEIGHT * messages,
+ W_CacheLumpName(DEH_String(msgNames[showMessages]),
+ PU_CACHE));
+
+ M_DrawThermo(OptionsDef.x, OptionsDef.y + LINEHEIGHT * (mousesens + 1),
+ 10, mouseSensitivity);
- M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(mousesens+1),
- 10,mouseSensitivity);
-
M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(scrnsize+1),
9,screenSize);
}
@@ -1172,7 +1153,7 @@ static char *M_SelectEndMessage(void)
{
char **endmsg;
- if (gamemission == doom)
+ if (logical_gamemission == doom)
{
// Doom 1
@@ -1276,17 +1257,17 @@ M_DrawThermo
int i;
xx = x;
- V_DrawPatchDirect (xx,y,0,W_CacheLumpName(DEH_String("M_THERML"),PU_CACHE));
+ V_DrawPatchDirect(xx, y, W_CacheLumpName(DEH_String("M_THERML"), PU_CACHE));
xx += 8;
for (i=0;i<thermWidth;i++)
{
- V_DrawPatchDirect (xx,y,0,W_CacheLumpName(DEH_String("M_THERMM"),PU_CACHE));
+ V_DrawPatchDirect(xx, y, W_CacheLumpName(DEH_String("M_THERMM"), PU_CACHE));
xx += 8;
}
- V_DrawPatchDirect (xx,y,0,W_CacheLumpName(DEH_String("M_THERMR"),PU_CACHE));
+ V_DrawPatchDirect(xx, y, W_CacheLumpName(DEH_String("M_THERMR"), PU_CACHE));
- V_DrawPatchDirect ((x+8) + thermDot*8,y,
- 0,W_CacheLumpName(DEH_String("M_THERMO"),PU_CACHE));
+ V_DrawPatchDirect((x + 8) + thermDot * 8, y,
+ W_CacheLumpName(DEH_String("M_THERMO"), PU_CACHE));
}
@@ -1296,8 +1277,8 @@ M_DrawEmptyCell
( menu_t* menu,
int item )
{
- V_DrawPatchDirect (menu->x - 10, menu->y+item*LINEHEIGHT - 1, 0,
- W_CacheLumpName(DEH_String("M_CELL1"),PU_CACHE));
+ V_DrawPatchDirect(menu->x - 10, menu->y + item * LINEHEIGHT - 1,
+ W_CacheLumpName(DEH_String("M_CELL1"), PU_CACHE));
}
void
@@ -1305,8 +1286,8 @@ M_DrawSelCell
( menu_t* menu,
int item )
{
- V_DrawPatchDirect (menu->x - 10, menu->y+item*LINEHEIGHT - 1, 0,
- W_CacheLumpName(DEH_String("M_CELL2"),PU_CACHE));
+ V_DrawPatchDirect(menu->x - 10, menu->y + item * LINEHEIGHT - 1,
+ W_CacheLumpName(DEH_String("M_CELL2"), PU_CACHE));
}
@@ -1326,7 +1307,6 @@ M_StartMessage
}
-
void M_StopMessage(void)
{
menuactive = messageLastMenuActive;
@@ -1418,7 +1398,7 @@ M_WriteText
w = SHORT (hu_font[c]->width);
if (cx+w > SCREENWIDTH)
break;
- V_DrawPatchDirect(cx, cy, 0, hu_font[c]);
+ V_DrawPatchDirect(cx, cy, hu_font[c]);
cx+=w;
}
}
@@ -1443,7 +1423,42 @@ boolean M_Responder (event_t* ev)
static int lasty = 0;
static int mousex = 0;
static int lastx = 0;
-
+
+ // In testcontrols mode, none of the function keys should do anything
+ // - the only key is escape to quit.
+
+ if (testcontrols)
+ {
+ if (ev->type == ev_quit
+ || (ev->type == ev_keydown
+ && (ev->data1 == key_menu_activate || ev->data1 == key_menu_quit)))
+ {
+ I_Quit();
+ return true;
+ }
+
+ return false;
+ }
+
+ // "close" button pressed on window?
+ if (ev->type == ev_quit)
+ {
+ // First click on close button = bring up quit confirm message.
+ // Second click on close button = confirm quit
+
+ if (menuactive && messageToPrint && messageRoutine == M_QuitResponse)
+ {
+ M_QuitResponse(key_menu_confirm);
+ }
+ else
+ {
+ S_StartSound(NULL,sfx_swtchn);
+ M_QuitDOOM(0);
+ }
+
+ return true;
+ }
+
// key is the key pressed, ch is the actual character typed
ch = 0;
@@ -1541,20 +1556,6 @@ boolean M_Responder (event_t* ev)
if (key == -1)
return false;
- // In testcontrols mode, none of the function keys should do anything
- // - the only key is escape to quit.
-
- if (testcontrols)
- {
- if (key == key_menu_activate || key == key_menu_quit)
- {
- I_Quit();
- return true;
- }
-
- return false;
- }
-
// Save Game string input
if (saveStringEnter)
{
@@ -1992,14 +1993,14 @@ void M_Drawer (void)
if (name[0])
{
- V_DrawPatchDirect (x,y,0, W_CacheLumpName(name, PU_CACHE));
+ V_DrawPatchDirect (x, y, W_CacheLumpName(name, PU_CACHE));
}
y += LINEHEIGHT;
}
// DRAW SKULL
- V_DrawPatchDirect(x + SKULLXOFF,currentMenu->y - 5 + itemOn*LINEHEIGHT, 0,
+ V_DrawPatchDirect(x + SKULLXOFF, currentMenu->y - 5 + itemOn*LINEHEIGHT,
W_CacheLumpName(DEH_String(skullName[whichSkull]),
PU_CACHE));
}
diff --git a/src/m_menu.h b/src/doom/m_menu.h
index c06fe981..c06fe981 100644
--- a/src/m_menu.h
+++ b/src/doom/m_menu.h
diff --git a/src/m_random.c b/src/doom/m_random.c
index 31cdf1b2..31cdf1b2 100644
--- a/src/m_random.c
+++ b/src/doom/m_random.c
diff --git a/src/m_random.h b/src/doom/m_random.h
index be778362..be778362 100644
--- a/src/m_random.h
+++ b/src/doom/m_random.h
diff --git a/src/p_ceilng.c b/src/doom/p_ceilng.c
index 58b9eb06..58b9eb06 100644
--- a/src/p_ceilng.c
+++ b/src/doom/p_ceilng.c
diff --git a/src/p_doors.c b/src/doom/p_doors.c
index 6a0bea3a..6a0bea3a 100644
--- a/src/p_doors.c
+++ b/src/doom/p_doors.c
diff --git a/src/p_enemy.c b/src/doom/p_enemy.c
index 9b1d8e37..66321e2c 100644
--- a/src/p_enemy.c
+++ b/src/doom/p_enemy.c
@@ -26,7 +26,7 @@
//
//-----------------------------------------------------------------------------
-
+#include <stdio.h>
#include <stdlib.h>
#include "m_random.h"
diff --git a/src/p_floor.c b/src/doom/p_floor.c
index edeb44a1..edeb44a1 100644
--- a/src/p_floor.c
+++ b/src/doom/p_floor.c
diff --git a/src/p_inter.c b/src/doom/p_inter.c
index dda55c37..dda55c37 100644
--- a/src/p_inter.c
+++ b/src/doom/p_inter.c
diff --git a/src/p_inter.h b/src/doom/p_inter.h
index 066e8573..066e8573 100644
--- a/src/p_inter.h
+++ b/src/doom/p_inter.h
diff --git a/src/p_lights.c b/src/doom/p_lights.c
index 5ea03903..5ea03903 100644
--- a/src/p_lights.c
+++ b/src/doom/p_lights.c
diff --git a/src/p_local.h b/src/doom/p_local.h
index 5ffefa3a..5ffefa3a 100644
--- a/src/p_local.h
+++ b/src/doom/p_local.h
diff --git a/src/p_map.c b/src/doom/p_map.c
index cac44dd2..7e92e23a 100644
--- a/src/p_map.c
+++ b/src/doom/p_map.c
@@ -25,7 +25,7 @@
//
//-----------------------------------------------------------------------------
-
+#include <stdio.h>
#include <stdlib.h>
#include "deh_misc.h"
diff --git a/src/p_maputl.c b/src/doom/p_maputl.c
index 4ab5d1d5..4ab5d1d5 100644
--- a/src/p_maputl.c
+++ b/src/doom/p_maputl.c
diff --git a/src/p_mobj.c b/src/doom/p_mobj.c
index 15025139..a2cc227a 100644
--- a/src/p_mobj.c
+++ b/src/doom/p_mobj.c
@@ -24,6 +24,7 @@
//
//-----------------------------------------------------------------------------
+#include <stdio.h>
#include "i_system.h"
#include "z_zone.h"
diff --git a/src/p_mobj.h b/src/doom/p_mobj.h
index 145b009b..145b009b 100644
--- a/src/p_mobj.h
+++ b/src/doom/p_mobj.h
diff --git a/src/p_plats.c b/src/doom/p_plats.c
index 03d1acbc..dbd45161 100644
--- a/src/p_plats.c
+++ b/src/doom/p_plats.c
@@ -24,7 +24,7 @@
//
//-----------------------------------------------------------------------------
-
+#include <stdio.h>
#include "i_system.h"
#include "z_zone.h"
diff --git a/src/p_pspr.c b/src/doom/p_pspr.c
index fe32c53f..fe32c53f 100644
--- a/src/p_pspr.c
+++ b/src/doom/p_pspr.c
diff --git a/src/p_pspr.h b/src/doom/p_pspr.h
index 1ae7433b..1ae7433b 100644
--- a/src/p_pspr.h
+++ b/src/doom/p_pspr.h
diff --git a/src/p_saveg.c b/src/doom/p_saveg.c
index 968120c0..968120c0 100644
--- a/src/p_saveg.c
+++ b/src/doom/p_saveg.c
diff --git a/src/p_saveg.h b/src/doom/p_saveg.h
index 5488289c..5488289c 100644
--- a/src/p_saveg.h
+++ b/src/doom/p_saveg.h
diff --git a/src/p_setup.c b/src/doom/p_setup.c
index 58d5f462..58d5f462 100644
--- a/src/p_setup.c
+++ b/src/doom/p_setup.c
diff --git a/src/p_setup.h b/src/doom/p_setup.h
index 2241c1c3..2241c1c3 100644
--- a/src/p_setup.h
+++ b/src/doom/p_setup.h
diff --git a/src/p_sight.c b/src/doom/p_sight.c
index 79c1bb1d..79c1bb1d 100644
--- a/src/p_sight.c
+++ b/src/doom/p_sight.c
diff --git a/src/p_spec.c b/src/doom/p_spec.c
index c4d2ffc8..c4d2ffc8 100644
--- a/src/p_spec.c
+++ b/src/doom/p_spec.c
diff --git a/src/p_spec.h b/src/doom/p_spec.h
index f5b57032..f5b57032 100644
--- a/src/p_spec.h
+++ b/src/doom/p_spec.h
diff --git a/src/p_switch.c b/src/doom/p_switch.c
index 28b59fae..362ecccf 100644
--- a/src/p_switch.c
+++ b/src/doom/p_switch.c
@@ -25,7 +25,7 @@
//
//-----------------------------------------------------------------------------
-
+#include <stdio.h>
#include "i_system.h"
#include "deh_main.h"
diff --git a/src/p_telept.c b/src/doom/p_telept.c
index 73c3e9b5..73c3e9b5 100644
--- a/src/p_telept.c
+++ b/src/doom/p_telept.c
diff --git a/src/p_tick.c b/src/doom/p_tick.c
index 9429cf20..9429cf20 100644
--- a/src/p_tick.c
+++ b/src/doom/p_tick.c
diff --git a/src/p_tick.h b/src/doom/p_tick.h
index 06934bb8..06934bb8 100644
--- a/src/p_tick.h
+++ b/src/doom/p_tick.h
diff --git a/src/p_user.c b/src/doom/p_user.c
index 2ff7f818..2ff7f818 100644
--- a/src/p_user.c
+++ b/src/doom/p_user.c
diff --git a/src/r_bsp.c b/src/doom/r_bsp.c
index 47194d96..47194d96 100644
--- a/src/r_bsp.c
+++ b/src/doom/r_bsp.c
diff --git a/src/r_bsp.h b/src/doom/r_bsp.h
index 284f9cf6..284f9cf6 100644
--- a/src/r_bsp.h
+++ b/src/doom/r_bsp.h
diff --git a/src/r_data.c b/src/doom/r_data.c
index a9f8920c..13c9eb98 100644
--- a/src/r_data.c
+++ b/src/doom/r_data.c
@@ -25,7 +25,7 @@
//
//-----------------------------------------------------------------------------
-
+#include <stdio.h>
#include "deh_main.h"
#include "i_swap.h"
diff --git a/src/r_data.h b/src/doom/r_data.h
index c987284c..c987284c 100644
--- a/src/r_data.h
+++ b/src/doom/r_data.h
diff --git a/src/r_defs.h b/src/doom/r_defs.h
index 4e0d85b7..bbd4b211 100644
--- a/src/r_defs.h
+++ b/src/doom/r_defs.h
@@ -42,7 +42,9 @@
// SECTORS do store MObjs anyway.
#include "p_mobj.h"
+#include "i_video.h"
+#include "v_patch.h"
@@ -283,18 +285,6 @@ typedef struct
-// posts are runs of non masked source pixels
-typedef struct
-{
- byte topdelta; // -1 is the last post in a column
- byte length; // length data bytes follows
-} PACKEDATTR post_t;
-
-// column_t is a list of 0 or more post_t, (byte)-1 terminated
-typedef post_t column_t;
-
-
-
// PC direct to screen pointers
//B UNUSED - keep till detailshift in r_draw.c resolved
//extern byte* destview;
@@ -350,27 +340,6 @@ typedef struct drawseg_s
-// Patches.
-// A patch holds one or more columns.
-// Patches are used for sprites and all masked pictures,
-// and we compose textures from the TEXTURE1/2 lists
-// of patches.
-typedef struct
-{
- short width; // bounding box size
- short height;
- short leftoffset; // pixels to the left of origin
- short topoffset; // pixels below the origin
- int columnofs[8]; // only [width] used
- // the [0] is &columnofs[width]
-} PACKEDATTR patch_t;
-
-
-
-
-
-
-
// A vissprite_t is a thing
// that will be drawn during a refresh.
// I.e. a sprite object that is partly visible.
diff --git a/src/r_draw.c b/src/doom/r_draw.c
index b7d847d9..b1e3ffae 100644
--- a/src/r_draw.c
+++ b/src/doom/r_draw.c
@@ -77,7 +77,10 @@ int columnofs[MAXWIDTH];
//
byte translations[3][256];
-
+// Backing buffer containing the bezel drawn around the screen and
+// surrounding background.
+
+static byte *background_buffer = NULL;
//
@@ -802,7 +805,7 @@ R_InitBuffer
// Preclaculate all row offsets.
for (i=0 ; i<height ; i++)
- ylookup[i] = screens[0] + (i+viewwindowy)*SCREENWIDTH;
+ ylookup[i] = I_VideoBuffer + (i+viewwindowy)*SCREENWIDTH;
}
@@ -826,20 +829,39 @@ void R_FillBackScreen (void)
char *name1 = DEH_String("FLOOR7_2");
// DOOM II border patch.
- char *name2 = DEH_String("GRNROCK");
+ char *name2 = DEH_String("GRNROCK");
+
+ char *name;
+
+ // If we are running full screen, there is no need to do any of this,
+ // and the background buffer can be freed if it was previously in use.
+
+ if (scaledviewwidth == SCREENWIDTH)
+ {
+ if (background_buffer != NULL)
+ {
+ Z_Free(background_buffer);
+ background_buffer = NULL;
+ }
- char* name;
-
- if (scaledviewwidth == 320)
return;
+ }
+
+ // Allocate the background buffer if necessary
- if ( gamemode == commercial)
+ if (background_buffer == NULL)
+ {
+ background_buffer = Z_Malloc(SCREENWIDTH * (SCREENHEIGHT - SBARHEIGHT),
+ PU_STATIC, NULL);
+ }
+
+ if (gamemode == commercial)
name = name2;
else
name = name1;
- src = W_CacheLumpName (name, PU_CACHE);
- dest = screens[1];
+ src = W_CacheLumpName(name, PU_CACHE);
+ dest = background_buffer;
for (y=0 ; y<SCREENHEIGHT-SBARHEIGHT ; y++)
{
@@ -855,45 +877,46 @@ void R_FillBackScreen (void)
dest += (SCREENWIDTH&63);
}
}
-
- patch = W_CacheLumpName (DEH_String("brdr_t"),PU_CACHE);
+
+ // Draw screen and bezel; this is done to a separate screen buffer.
+
+ V_UseBuffer(background_buffer);
+
+ patch = W_CacheLumpName(DEH_String("brdr_t"),PU_CACHE);
for (x=0 ; x<scaledviewwidth ; x+=8)
- V_DrawPatch (viewwindowx+x,viewwindowy-8,1,patch);
- patch = W_CacheLumpName (DEH_String("brdr_b"),PU_CACHE);
+ V_DrawPatch(viewwindowx+x, viewwindowy-8, patch);
+ patch = W_CacheLumpName(DEH_String("brdr_b"),PU_CACHE);
for (x=0 ; x<scaledviewwidth ; x+=8)
- V_DrawPatch (viewwindowx+x,viewwindowy+viewheight,1,patch);
- patch = W_CacheLumpName (DEH_String("brdr_l"),PU_CACHE);
+ V_DrawPatch(viewwindowx+x, viewwindowy+viewheight, patch);
+ patch = W_CacheLumpName(DEH_String("brdr_l"),PU_CACHE);
for (y=0 ; y<viewheight ; y+=8)
- V_DrawPatch (viewwindowx-8,viewwindowy+y,1,patch);
- patch = W_CacheLumpName (DEH_String("brdr_r"),PU_CACHE);
+ V_DrawPatch(viewwindowx-8, viewwindowy+y, patch);
+ patch = W_CacheLumpName(DEH_String("brdr_r"),PU_CACHE);
for (y=0 ; y<viewheight ; y+=8)
- V_DrawPatch (viewwindowx+scaledviewwidth,viewwindowy+y,1,patch);
-
+ V_DrawPatch(viewwindowx+scaledviewwidth, viewwindowy+y, patch);
// Draw beveled edge.
- V_DrawPatch (viewwindowx-8,
- viewwindowy-8,
- 1,
- W_CacheLumpName (DEH_String("brdr_tl"),PU_CACHE));
+ V_DrawPatch(viewwindowx-8,
+ viewwindowy-8,
+ W_CacheLumpName(DEH_String("brdr_tl"),PU_CACHE));
- V_DrawPatch (viewwindowx+scaledviewwidth,
- viewwindowy-8,
- 1,
- W_CacheLumpName (DEH_String("brdr_tr"),PU_CACHE));
+ V_DrawPatch(viewwindowx+scaledviewwidth,
+ viewwindowy-8,
+ W_CacheLumpName(DEH_String("brdr_tr"),PU_CACHE));
- V_DrawPatch (viewwindowx-8,
- viewwindowy+viewheight,
- 1,
- W_CacheLumpName (DEH_String("brdr_bl"),PU_CACHE));
+ V_DrawPatch(viewwindowx-8,
+ viewwindowy+viewheight,
+ W_CacheLumpName(DEH_String("brdr_bl"),PU_CACHE));
- V_DrawPatch (viewwindowx+scaledviewwidth,
- viewwindowy+viewheight,
- 1,
- W_CacheLumpName (DEH_String("brdr_br"),PU_CACHE));
+ V_DrawPatch(viewwindowx+scaledviewwidth,
+ viewwindowy+viewheight,
+ W_CacheLumpName(DEH_String("brdr_br"),PU_CACHE));
+
+ V_RestoreBuffer();
}
@@ -910,7 +933,11 @@ R_VideoErase
// is not optiomal, e.g. byte by byte on
// a 32bit CPU, as GNU GCC/Linux libc did
// at one point.
- memcpy (screens[0]+ofs, screens[1]+ofs, count);
+
+ if (background_buffer != NULL)
+ {
+ memcpy(I_VideoBuffer + ofs, background_buffer + ofs, count);
+ }
}
@@ -919,13 +946,6 @@ R_VideoErase
// Draws the border around the view
// for different size windows?
//
-void
-V_MarkRect
-( int x,
- int y,
- int width,
- int height );
-
void R_DrawViewBorder (void)
{
int top;
diff --git a/src/r_draw.h b/src/doom/r_draw.h
index adaacd60..adaacd60 100644
--- a/src/r_draw.h
+++ b/src/doom/r_draw.h
diff --git a/src/r_local.h b/src/doom/r_local.h
index 8b97bdb0..8b97bdb0 100644
--- a/src/r_local.h
+++ b/src/doom/r_local.h
diff --git a/src/r_main.c b/src/doom/r_main.c
index e6a08691..5e020d53 100644
--- a/src/r_main.c
+++ b/src/doom/r_main.c
@@ -35,7 +35,7 @@
#include "doomdef.h"
-#include "d_net.h"
+#include "d_loop.h"
#include "m_bbox.h"
#include "m_menu.h"
@@ -105,17 +105,6 @@ int viewangletox[FINEANGLES/2];
// from clipangle to -clipangle.
angle_t xtoviewangle[SCREENWIDTH+1];
-
-// UNUSED.
-// The finetangentgent[angle+FINEANGLES/4] table
-// holds the fixed_t tangent values for view angles,
-// ranging from INT_MIN to 0 to INT_MAX.
-// fixed_t finetangent[FINEANGLES/2];
-
-// fixed_t finesine[5*FINEANGLES/4];
-const fixed_t* finecosine = &finesine[FINEANGLES/4];
-
-
lighttable_t* scalelight[LIGHTLEVELS][MAXLIGHTSCALE];
lighttable_t* scalelightfixed[MAXLIGHTSCALE];
lighttable_t* zlight[LIGHTLEVELS][MAXLIGHTZ];
diff --git a/src/r_main.h b/src/doom/r_main.h
index edc5dbbb..5cb858bb 100644
--- a/src/r_main.h
+++ b/src/doom/r_main.h
@@ -40,8 +40,6 @@
extern fixed_t viewcos;
extern fixed_t viewsin;
-extern int viewwidth;
-extern int viewheight;
extern int viewwindowx;
extern int viewwindowy;
diff --git a/src/r_plane.c b/src/doom/r_plane.c
index 400821d5..752f5d14 100644
--- a/src/r_plane.c
+++ b/src/doom/r_plane.c
@@ -27,7 +27,7 @@
//-----------------------------------------------------------------------------
-
+#include <stdio.h>
#include <stdlib.h>
#include "i_system.h"
diff --git a/src/r_plane.h b/src/doom/r_plane.h
index 2783443d..2783443d 100644
--- a/src/r_plane.h
+++ b/src/doom/r_plane.h
diff --git a/src/r_segs.c b/src/doom/r_segs.c
index 5150b694..29ed32a5 100644
--- a/src/r_segs.c
+++ b/src/doom/r_segs.c
@@ -29,7 +29,7 @@
-
+#include <stdio.h>
#include <stdlib.h>
#include "i_system.h"
diff --git a/src/r_segs.h b/src/doom/r_segs.h
index 197859ed..197859ed 100644
--- a/src/r_segs.h
+++ b/src/doom/r_segs.h
diff --git a/src/r_sky.c b/src/doom/r_sky.c
index 689dc113..689dc113 100644
--- a/src/r_sky.c
+++ b/src/doom/r_sky.c
diff --git a/src/r_sky.h b/src/doom/r_sky.h
index d436ce66..d436ce66 100644
--- a/src/r_sky.h
+++ b/src/doom/r_sky.h
diff --git a/src/r_state.h b/src/doom/r_state.h
index 535753c1..535753c1 100644
--- a/src/r_state.h
+++ b/src/doom/r_state.h
diff --git a/src/r_things.c b/src/doom/r_things.c
index 68f4b2fe..68f4b2fe 100644
--- a/src/r_things.c
+++ b/src/doom/r_things.c
diff --git a/src/r_things.h b/src/doom/r_things.h
index d0fce4e4..d0fce4e4 100644
--- a/src/r_things.h
+++ b/src/doom/r_things.h
diff --git a/src/s_sound.c b/src/doom/s_sound.c
index 27a47443..12a55d8f 100644
--- a/src/s_sound.c
+++ b/src/doom/s_sound.c
@@ -26,13 +26,14 @@
#include <stdio.h>
#include <stdlib.h>
+#include "i_sound.h"
#include "i_system.h"
#include "doomfeatures.h"
-#include "deh_main.h"
+#include "deh_str.h"
#include "doomstat.h"
-#include "doomdef.h"
+#include "doomtype.h"
#include "sounds.h"
#include "s_sound.h"
@@ -82,11 +83,6 @@ typedef struct
} channel_t;
-// Low-level sound and music modules we are using
-
-static sound_module_t *sound_module;
-static music_module_t *music_module;
-
// The set of channels available
static channel_t *channels;
@@ -100,10 +96,6 @@ int sfxVolume = 8;
int musicVolume = 8;
-// Sound sample rate to use for digital output (Hz)
-
-int snd_samplerate = 44100;
-
// Internal volume level, ranging from 0-127
static int snd_SfxVolume;
@@ -118,114 +110,7 @@ static musicinfo_t *mus_playing = NULL;
// Number of channels to use
-int numChannels = 8;
-
-int snd_musicdevice = SNDDEVICE_GENMIDI;
-int snd_sfxdevice = SNDDEVICE_SB;
-
-// Sound modules
-
-extern sound_module_t sound_sdl_module;
-extern sound_module_t sound_pcsound_module;
-extern music_module_t music_sdl_module;
-extern music_module_t music_opl_module;
-
-// Compiled-in sound modules:
-
-static sound_module_t *sound_modules[] =
-{
-#ifdef FEATURE_SOUND
- &sound_sdl_module,
- &sound_pcsound_module,
-#endif
- NULL,
-};
-
-// Compiled-in music modules:
-
-static music_module_t *music_modules[] =
-{
-#ifdef FEATURE_SOUND
- &music_sdl_module,
- &music_opl_module,
-#endif
- NULL,
-};
-
-// Check if a sound device is in the given list of devices
-
-static boolean SndDeviceInList(snddevice_t device, snddevice_t *list,
- int len)
-{
- int i;
-
- for (i=0; i<len; ++i)
- {
- if (device == list[i])
- {
- return true;
- }
- }
-
- return false;
-}
-
-// Find and initialize a sound_module_t appropriate for the setting
-// in snd_sfxdevice.
-
-static void InitSfxModule(void)
-{
- int i;
-
- sound_module = NULL;
-
- for (i=0; sound_modules[i] != NULL; ++i)
- {
- // Is the sfx device in the list of devices supported by
- // this module?
-
- if (SndDeviceInList(snd_sfxdevice,
- sound_modules[i]->sound_devices,
- sound_modules[i]->num_sound_devices))
- {
- // Initialize the module
-
- if (sound_modules[i]->Init())
- {
- sound_module = sound_modules[i];
- return;
- }
- }
- }
-}
-
-// Initialize music according to snd_musicdevice.
-
-static void InitMusicModule(void)
-{
- int i;
-
- music_module = NULL;
-
- for (i=0; music_modules[i] != NULL; ++i)
- {
- // Is the music device in the list of devices supported
- // by this module?
-
- if (SndDeviceInList(snd_musicdevice,
- music_modules[i]->sound_devices,
- music_modules[i]->num_sound_devices))
- {
- // Initialize the module
-
- if (music_modules[i]->Init())
- {
- music_module = music_modules[i];
- return;
- }
- }
- }
-}
+int snd_channels = 8;
//
// Initializes sound stuff, including volume
@@ -235,47 +120,12 @@ static void InitMusicModule(void)
void S_Init(int sfxVolume, int musicVolume)
{
- boolean nosound, nosfx, nomusic;
int i;
- //!
- // @vanilla
- //
- // Disable all sound output.
- //
-
- nosound = M_CheckParm("-nosound") > 0;
-
- //!
- // @vanilla
- //
- // Disable sound effects.
- //
-
- nosfx = M_CheckParm("-nosfx") > 0;
+ I_InitSound(true);
+ I_InitMusic();
- //!
- // @vanilla
- //
- // Disable music.
- //
-
- nomusic = M_CheckParm("-nomusic") > 0;
-
- // Initialize the sound and music subsystems.
-
- if (!nosound && !screensaver_mode)
- {
- if (!nosfx)
- {
- InitSfxModule();
- }
-
- if (!nomusic)
- {
- InitMusicModule();
- }
- }
+ I_PrecacheSounds(S_sfx, NUMSFX);
S_SetSfxVolume(sfxVolume);
S_SetMusicVolume(musicVolume);
@@ -283,10 +133,10 @@ void S_Init(int sfxVolume, int musicVolume)
// Allocating the internal channels for mixing
// (the maximum numer of sounds rendered
// simultaneously) within zone memory.
- channels = Z_Malloc(numChannels*sizeof(channel_t), PU_STATIC, 0);
+ channels = Z_Malloc(snd_channels*sizeof(channel_t), PU_STATIC, 0);
// Free all channels for use
- for (i=0 ; i<numChannels ; i++)
+ for (i=0 ; i<snd_channels ; i++)
{
channels[i].sfxinfo = 0;
}
@@ -299,19 +149,14 @@ void S_Init(int sfxVolume, int musicVolume)
{
S_sfx[i].lumpnum = S_sfx[i].usefulness = -1;
}
+
+ I_AtExit(S_Shutdown, true);
}
void S_Shutdown(void)
{
- if (sound_module != NULL)
- {
- sound_module->Shutdown();
- }
-
- if (music_module != NULL)
- {
- music_module->Shutdown();
- }
+ I_ShutdownSound();
+ I_ShutdownMusic();
}
static void S_StopChannel(int cnum)
@@ -325,17 +170,14 @@ static void S_StopChannel(int cnum)
{
// stop the sound playing
- if (sound_module != NULL)
+ if (I_SoundIsPlaying(c->handle))
{
- if (sound_module->SoundIsPlaying(c->handle))
- {
- sound_module->StopSound(c->handle);
- }
+ I_StopSound(c->handle);
}
// check to see if other channels are playing the sound
- for (i=0; i<numChannels; i++)
+ for (i=0; i<snd_channels; i++)
{
if (cnum != i && c->sfxinfo == channels[i].sfxinfo)
{
@@ -363,7 +205,7 @@ void S_Start(void)
// kill all playing sounds at start of level
// (trust me - a good idea)
- for (cnum=0 ; cnum<numChannels ; cnum++)
+ for (cnum=0 ; cnum<snd_channels ; cnum++)
{
if (channels[cnum].sfxinfo)
{
@@ -412,7 +254,7 @@ void S_StopSound(mobj_t *origin)
{
int cnum;
- for (cnum=0 ; cnum<numChannels ; cnum++)
+ for (cnum=0 ; cnum<snd_channels ; cnum++)
{
if (channels[cnum].sfxinfo && channels[cnum].origin == origin)
{
@@ -435,7 +277,7 @@ static int S_GetChannel(mobj_t *origin, sfxinfo_t *sfxinfo)
channel_t* c;
// Find an open channel
- for (cnum=0 ; cnum<numChannels ; cnum++)
+ for (cnum=0 ; cnum<snd_channels ; cnum++)
{
if (!channels[cnum].sfxinfo)
{
@@ -449,10 +291,10 @@ static int S_GetChannel(mobj_t *origin, sfxinfo_t *sfxinfo)
}
// None available
- if (cnum == numChannels)
+ if (cnum == snd_channels)
{
// Look for lower priority
- for (cnum=0 ; cnum<numChannels ; cnum++)
+ for (cnum=0 ; cnum<snd_channels ; cnum++)
{
if (channels[cnum].sfxinfo->priority >= sfxinfo->priority)
{
@@ -460,7 +302,7 @@ static int S_GetChannel(mobj_t *origin, sfxinfo_t *sfxinfo)
}
}
- if (cnum == numChannels)
+ if (cnum == snd_channels)
{
// FUCK! No lower priority. Sorry, Charlie.
return -1;
@@ -635,23 +477,12 @@ void S_StartSound(void *origin_p, int sfx_id)
sfx->usefulness = 1;
}
- if (sound_module != NULL)
+ if (sfx->lumpnum < 0)
{
- // Get lumpnum if necessary
-
- if (sfx->lumpnum < 0)
- {
- sfx->lumpnum = sound_module->GetSfxLumpNum(sfx);
- }
-
- // Assigns the handle to one of the channels in the
- // mix/output buffer.
-
- channels[cnum].handle = sound_module->StartSound(sfx_id,
- cnum,
- volume,
- sep);
+ sfx->lumpnum = I_GetSfxLumpNum(sfx);
}
+
+ channels[cnum].handle = I_StartSound(sfx, cnum, volume, sep);
}
//
@@ -662,10 +493,7 @@ void S_PauseSound(void)
{
if (mus_playing && !mus_paused)
{
- if (music_module != NULL)
- {
- music_module->PauseMusic();
- }
+ I_PauseSong();
mus_paused = true;
}
}
@@ -674,10 +502,7 @@ void S_ResumeSound(void)
{
if (mus_playing && mus_paused)
{
- if (music_module != NULL)
- {
- music_module->ResumeMusic();
- }
+ I_ResumeSong();
mus_paused = false;
}
}
@@ -695,14 +520,14 @@ void S_UpdateSounds(mobj_t *listener)
sfxinfo_t* sfx;
channel_t* c;
- for (cnum=0; cnum<numChannels; cnum++)
+ for (cnum=0; cnum<snd_channels; cnum++)
{
c = &channels[cnum];
sfx = c->sfxinfo;
if (c->sfxinfo)
{
- if (sound_module != NULL && sound_module->SoundIsPlaying(c->handle))
+ if (I_SoundIsPlaying(c->handle))
{
// initialize parameters
volume = snd_SfxVolume;
@@ -737,7 +562,7 @@ void S_UpdateSounds(mobj_t *listener)
}
else
{
- sound_module->UpdateSoundParams(c->handle, volume, sep);
+ I_UpdateSoundParams(c->handle, volume, sep);
}
}
}
@@ -759,10 +584,7 @@ void S_SetMusicVolume(int volume)
volume);
}
- if (music_module != NULL)
- {
- music_module->SetMusicVolume(volume);
- }
+ I_SetMusicVolume(volume);
}
void S_SetSfxVolume(int volume)
@@ -823,53 +645,33 @@ void S_ChangeMusic(int musicnum, int looping)
music->lumpnum = W_GetNumForName(namebuf);
}
- if (music_module != NULL)
- {
- // Load & register it
-
- music->data = W_CacheLumpNum(music->lumpnum, PU_STATIC);
- handle = music_module->RegisterSong(music->data,
- W_LumpLength(music->lumpnum));
- music->handle = handle;
-
- // Play it
+ music->data = W_CacheLumpNum(music->lumpnum, PU_STATIC);
- music_module->PlaySong(handle, looping);
- }
+ handle = I_RegisterSong(music->data, W_LumpLength(music->lumpnum));
+ music->handle = handle;
+ I_PlaySong(handle, looping);
mus_playing = music;
}
boolean S_MusicPlaying(void)
{
- if (music_module != NULL)
- {
- return music_module->MusicIsPlaying();
- }
- else
- {
- return false;
- }
+ return I_MusicIsPlaying();
}
void S_StopMusic(void)
{
if (mus_playing)
{
- if (music_module != NULL)
+ if (mus_paused)
{
- if (mus_paused)
- {
- music_module->ResumeMusic();
- }
-
- music_module->StopSong();
- music_module->UnRegisterSong(mus_playing->handle);
- W_ReleaseLumpNum(mus_playing->lumpnum);
-
- mus_playing->data = NULL;
+ I_ResumeSong();
}
+ I_StopSong();
+ I_UnRegisterSong(mus_playing->handle);
+ W_ReleaseLumpNum(mus_playing->lumpnum);
+ mus_playing->data = NULL;
mus_playing = NULL;
}
}
diff --git a/src/doom/s_sound.h b/src/doom/s_sound.h
new file mode 100644
index 00000000..7bb0a605
--- /dev/null
+++ b/src/doom/s_sound.h
@@ -0,0 +1,97 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// The not so system specific sound interface.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __S_SOUND__
+#define __S_SOUND__
+
+#include "p_mobj.h"
+#include "sounds.h"
+
+//
+// Initializes sound stuff, including volume
+// Sets channels, SFX and music volume,
+// allocates channel buffer, sets S_sfx lookup.
+//
+
+void S_Init(int sfxVolume, int musicVolume);
+
+
+// Shut down sound
+
+void S_Shutdown(void);
+
+
+
+//
+// Per level startup code.
+// Kills playing sounds at start of level,
+// determines music if any, changes music.
+//
+
+void S_Start(void);
+
+//
+// Start sound for thing at <origin>
+// using <sound_id> from sounds.h
+//
+
+void S_StartSound(void *origin, int sound_id);
+
+// Stop sound for thing at <origin>
+void S_StopSound(mobj_t *origin);
+
+
+// Start music using <music_id> from sounds.h
+void S_StartMusic(int music_id);
+
+// Start music using <music_id> from sounds.h,
+// and set whether looping
+void S_ChangeMusic(int music_id, int looping);
+
+// query if music is playing
+boolean S_MusicPlaying(void);
+
+// Stops the music fer sure.
+void S_StopMusic(void);
+
+// Stop and resume music, during game PAUSE.
+void S_PauseSound(void);
+void S_ResumeSound(void);
+
+
+//
+// Updates music & sounds
+//
+void S_UpdateSounds(mobj_t *listener);
+
+void S_SetMusicVolume(int volume);
+void S_SetSfxVolume(int volume);
+
+extern int snd_channels;
+
+#endif
+
diff --git a/src/doom/sounds.c b/src/doom/sounds.c
new file mode 100644
index 00000000..adfb2189
--- /dev/null
+++ b/src/doom/sounds.c
@@ -0,0 +1,237 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Created by a sound utility.
+// Kept as a sample, DOOM2 sounds.
+//
+//-----------------------------------------------------------------------------
+
+
+#include <stdlib.h>
+
+
+#include "doomtype.h"
+#include "sounds.h"
+
+//
+// Information about all the music
+//
+
+#define MUSIC(name) \
+ { name, 0, NULL, NULL }
+
+musicinfo_t S_music[] =
+{
+ MUSIC(NULL),
+ MUSIC("e1m1"),
+ MUSIC("e1m2"),
+ MUSIC("e1m3"),
+ MUSIC("e1m4"),
+ MUSIC("e1m5"),
+ MUSIC("e1m6"),
+ MUSIC("e1m7"),
+ MUSIC("e1m8"),
+ MUSIC("e1m9"),
+ MUSIC("e2m1"),
+ MUSIC("e2m2"),
+ MUSIC("e2m3"),
+ MUSIC("e2m4"),
+ MUSIC("e2m5"),
+ MUSIC("e2m6"),
+ MUSIC("e2m7"),
+ MUSIC("e2m8"),
+ MUSIC("e2m9"),
+ MUSIC("e3m1"),
+ MUSIC("e3m2"),
+ MUSIC("e3m3"),
+ MUSIC("e3m4"),
+ MUSIC("e3m5"),
+ MUSIC("e3m6"),
+ MUSIC("e3m7"),
+ MUSIC("e3m8"),
+ MUSIC("e3m9"),
+ MUSIC("inter"),
+ MUSIC("intro"),
+ MUSIC("bunny"),
+ MUSIC("victor"),
+ MUSIC("introa"),
+ MUSIC("runnin"),
+ MUSIC("stalks"),
+ MUSIC("countd"),
+ MUSIC("betwee"),
+ MUSIC("doom"),
+ MUSIC("the_da"),
+ MUSIC("shawn"),
+ MUSIC("ddtblu"),
+ MUSIC("in_cit"),
+ MUSIC("dead"),
+ MUSIC("stlks2"),
+ MUSIC("theda2"),
+ MUSIC("doom2"),
+ MUSIC("ddtbl2"),
+ MUSIC("runni2"),
+ MUSIC("dead2"),
+ MUSIC("stlks3"),
+ MUSIC("romero"),
+ MUSIC("shawn2"),
+ MUSIC("messag"),
+ MUSIC("count2"),
+ MUSIC("ddtbl3"),
+ MUSIC("ampie"),
+ MUSIC("theda3"),
+ MUSIC("adrian"),
+ MUSIC("messg2"),
+ MUSIC("romer2"),
+ MUSIC("tense"),
+ MUSIC("shawn3"),
+ MUSIC("openin"),
+ MUSIC("evil"),
+ MUSIC("ultima"),
+ MUSIC("read_m"),
+ MUSIC("dm2ttl"),
+ MUSIC("dm2int")
+};
+
+
+//
+// Information about all the sfx
+//
+
+#define SOUND(name, priority) \
+ { NULL, name, priority, NULL, -1, -1, 0, 0, -1, NULL }
+#define SOUND_LINK(name, priority, link_id, pitch, volume) \
+ { NULL, name, priority, &S_sfx[link_id], pitch, volume, 0, 0, -1, NULL }
+
+sfxinfo_t S_sfx[] =
+{
+ // S_sfx[0] needs to be a dummy for odd reasons.
+ SOUND("none", 0),
+ SOUND("pistol", 64),
+ SOUND("shotgn", 64),
+ SOUND("sgcock", 64),
+ SOUND("dshtgn", 64),
+ SOUND("dbopn", 64),
+ SOUND("dbcls", 64),
+ SOUND("dbload", 64),
+ SOUND("plasma", 64),
+ SOUND("bfg", 64),
+ SOUND("sawup", 64),
+ SOUND("sawidl", 118),
+ SOUND("sawful", 64),
+ SOUND("sawhit", 64),
+ SOUND("rlaunc", 64),
+ SOUND("rxplod", 70),
+ SOUND("firsht", 70),
+ SOUND("firxpl", 70),
+ SOUND("pstart", 100),
+ SOUND("pstop", 100),
+ SOUND("doropn", 100),
+ SOUND("dorcls", 100),
+ SOUND("stnmov", 119),
+ SOUND("swtchn", 78),
+ SOUND("swtchx", 78),
+ SOUND("plpain", 96),
+ SOUND("dmpain", 96),
+ SOUND("popain", 96),
+ SOUND("vipain", 96),
+ SOUND("mnpain", 96),
+ SOUND("pepain", 96),
+ SOUND("slop", 78),
+ SOUND("itemup", 78),
+ SOUND("wpnup", 78),
+ SOUND("oof", 96),
+ SOUND("telept", 32),
+ SOUND("posit1", 98),
+ SOUND("posit2", 98),
+ SOUND("posit3", 98),
+ SOUND("bgsit1", 98),
+ SOUND("bgsit2", 98),
+ SOUND("sgtsit", 98),
+ SOUND("cacsit", 98),
+ SOUND("brssit", 94),
+ SOUND("cybsit", 92),
+ SOUND("spisit", 90),
+ SOUND("bspsit", 90),
+ SOUND("kntsit", 90),
+ SOUND("vilsit", 90),
+ SOUND("mansit", 90),
+ SOUND("pesit", 90),
+ SOUND("sklatk", 70),
+ SOUND("sgtatk", 70),
+ SOUND("skepch", 70),
+ SOUND("vilatk", 70),
+ SOUND("claw", 70),
+ SOUND("skeswg", 70),
+ SOUND("pldeth", 32),
+ SOUND("pdiehi", 32),
+ SOUND("podth1", 70),
+ SOUND("podth2", 70),
+ SOUND("podth3", 70),
+ SOUND("bgdth1", 70),
+ SOUND("bgdth2", 70),
+ SOUND("sgtdth", 70),
+ SOUND("cacdth", 70),
+ SOUND("skldth", 70),
+ SOUND("brsdth", 32),
+ SOUND("cybdth", 32),
+ SOUND("spidth", 32),
+ SOUND("bspdth", 32),
+ SOUND("vildth", 32),
+ SOUND("kntdth", 32),
+ SOUND("pedth", 32),
+ SOUND("skedth", 32),
+ SOUND("posact", 120),
+ SOUND("bgact", 120),
+ SOUND("dmact", 120),
+ SOUND("bspact", 100),
+ SOUND("bspwlk", 100),
+ SOUND("vilact", 100),
+ SOUND("noway", 78),
+ SOUND("barexp", 60),
+ SOUND("punch", 64),
+ SOUND("hoof", 70),
+ SOUND("metal", 70),
+ SOUND_LINK("chgun", 64, sfx_pistol, 150, 0),
+ SOUND("tink", 60),
+ SOUND("bdopn", 100),
+ SOUND("bdcls", 100),
+ SOUND("itmbk", 100),
+ SOUND("flame", 32),
+ SOUND("flamst", 32),
+ SOUND("getpow", 60),
+ SOUND("bospit", 70),
+ SOUND("boscub", 70),
+ SOUND("bossit", 70),
+ SOUND("bospn", 70),
+ SOUND("bosdth", 70),
+ SOUND("manatk", 70),
+ SOUND("mandth", 70),
+ SOUND("sssit", 70),
+ SOUND("ssdth", 70),
+ SOUND("keenpn", 70),
+ SOUND("keendt", 70),
+ SOUND("skeact", 70),
+ SOUND("skesit", 70),
+ SOUND("skeatk", 70),
+ SOUND("radio", 60),
+};
+
diff --git a/src/sounds.h b/src/doom/sounds.h
index 325d1d63..3d190910 100644
--- a/src/sounds.h
+++ b/src/doom/sounds.h
@@ -28,68 +28,7 @@
#ifndef __SOUNDS__
#define __SOUNDS__
-
-//
-// SoundFX struct.
-//
-typedef struct sfxinfo_struct sfxinfo_t;
-
-struct sfxinfo_struct
-{
- // up to 6-character name
- char* name;
-
- // Sfx singularity (only one at a time)
- int singularity;
-
- // Sfx priority
- int priority;
-
- // referenced sound if a link
- sfxinfo_t* link;
-
- // pitch if a link
- int pitch;
-
- // volume if a link
- int volume;
-
- // sound data
- void* data;
-
- // this is checked every second to see if sound
- // can be thrown out (if 0, then decrement, if -1,
- // then throw out, if > 0, then it is in use)
- int usefulness;
-
- // lump number of sfx
- int lumpnum;
-};
-
-
-
-
-//
-// MusicInfo struct.
-//
-typedef struct
-{
- // up to 6-character name
- char* name;
-
- // lump number of music
- int lumpnum;
-
- // music data
- void* data;
-
- // music handle once registered
- void *handle;
-
-} musicinfo_t;
-
-
-
+#include "i_sound.h"
// the complete set of sound effects
extern sfxinfo_t S_sfx[];
diff --git a/src/st_lib.c b/src/doom/st_lib.c
index 11299a91..c90540cb 100644
--- a/src/st_lib.c
+++ b/src/doom/st_lib.c
@@ -25,7 +25,7 @@
//-----------------------------------------------------------------------------
-
+#include <stdio.h>
#include <ctype.h>
#include "deh_main.h"
@@ -123,7 +123,7 @@ STlib_drawNum
if (n->y - ST_Y < 0)
I_Error("drawNum: n->y - ST_Y < 0");
- V_CopyRect(x, n->y - ST_Y, BG, w*numdigits, h, x, n->y, FG);
+ V_CopyRect(x, n->y - ST_Y, st_backing_screen, w*numdigits, h, x, n->y);
// if non-number, do not draw it
if (num == 1994)
@@ -133,19 +133,19 @@ STlib_drawNum
// in the special case of 0, you draw 0
if (!num)
- V_DrawPatch(x - w, n->y, FG, n->p[ 0 ]);
+ V_DrawPatch(x - w, n->y, n->p[ 0 ]);
// draw the new number
while (num && numdigits--)
{
x -= w;
- V_DrawPatch(x, n->y, FG, n->p[ num % 10 ]);
+ V_DrawPatch(x, n->y, n->p[ num % 10 ]);
num /= 10;
}
// draw a minus sign if necessary
if (neg)
- V_DrawPatch(x - 8, n->y, FG, sttminus);
+ V_DrawPatch(x - 8, n->y, sttminus);
}
@@ -183,7 +183,7 @@ STlib_updatePercent
int refresh )
{
if (refresh && *per->n.on)
- V_DrawPatch(per->n.x, per->n.y, FG, per->p);
+ V_DrawPatch(per->n.x, per->n.y, per->p);
STlib_updateNum(&per->n, refresh);
}
@@ -233,9 +233,9 @@ STlib_updateMultIcon
if (y - ST_Y < 0)
I_Error("updateMultIcon: y - ST_Y < 0");
- V_CopyRect(x, y-ST_Y, BG, w, h, x, y, FG);
+ V_CopyRect(x, y-ST_Y, st_backing_screen, w, h, x, y);
}
- V_DrawPatch(mi->x, mi->y, FG, mi->p[*mi->inum]);
+ V_DrawPatch(mi->x, mi->y, mi->p[*mi->inum]);
mi->oldinum = *mi->inum;
}
}
@@ -283,9 +283,9 @@ STlib_updateBinIcon
I_Error("updateBinIcon: y - ST_Y < 0");
if (*bi->val)
- V_DrawPatch(bi->x, bi->y, FG, bi->p);
+ V_DrawPatch(bi->x, bi->y, bi->p);
else
- V_CopyRect(x, y-ST_Y, BG, w, h, x, y, FG);
+ V_CopyRect(x, y-ST_Y, st_backing_screen, w, h, x, y);
bi->oldval = *bi->val;
}
diff --git a/src/st_lib.h b/src/doom/st_lib.h
index bf9a6f87..344fd952 100644
--- a/src/st_lib.h
+++ b/src/doom/st_lib.h
@@ -31,15 +31,6 @@
// We are referring to patches.
#include "r_defs.h"
-
-//
-// Background and foreground screen numbers
-//
-#define BG 4
-#define FG 0
-
-
-
//
// Typedefs of widgets
//
diff --git a/src/st_stuff.c b/src/doom/st_stuff.c
index b1a46df5..df8592a4 100644
--- a/src/st_stuff.c
+++ b/src/doom/st_stuff.c
@@ -39,6 +39,7 @@
#include "deh_main.h"
#include "deh_misc.h"
#include "doomdef.h"
+#include "doomkeys.h"
#include "g_game.h"
@@ -265,6 +266,8 @@
#define ST_MAPTITLEY 0
#define ST_MAPHEIGHT 1
+// graphics are drawn to a backing screen and blitted to the real screen
+byte *st_backing_screen;
// main player in game
static player_t* plyr;
@@ -272,9 +275,6 @@ static player_t* plyr;
// ST_Start() has just been called
static boolean st_firsttime;
-// used to execute ST_Init() only once
-static int veryfirsttime = 1;
-
// lump number for PLAYPAL
static int lu_palette;
@@ -425,12 +425,16 @@ void ST_refreshBackground(void)
if (st_statusbaron)
{
- V_DrawPatch(ST_X, 0, BG, sbar);
+ V_UseBuffer(st_backing_screen);
+
+ V_DrawPatch(ST_X, 0, sbar);
if (netgame)
- V_DrawPatch(ST_FX, 0, BG, faceback);
+ V_DrawPatch(ST_FX, 0, faceback);
- V_CopyRect(ST_X, 0, BG, ST_WIDTH, ST_HEIGHT, ST_X, ST_Y, FG);
+ V_RestoreBuffer();
+
+ V_CopyRect(ST_X, 0, st_backing_screen, ST_WIDTH, ST_HEIGHT, ST_X, ST_Y);
}
}
@@ -546,9 +550,9 @@ ST_Responder (event_t* ev)
S_ChangeMusic(musnum, 1);
}
}
- else if ( (gamemission == doom
+ else if ( (logical_gamemission == doom
&& cht_CheckCheat(&cheat_noclip, ev->data2))
- || (gamemission != doom
+ || (logical_gamemission != doom
&& cht_CheckCheat(&cheat_commercial_noclip,ev->data2)))
{
// Noclip cheat.
@@ -1411,7 +1415,7 @@ void ST_Stop (void)
void ST_Init (void)
{
- veryfirsttime = 0;
ST_loadData();
- screens[4] = (byte *) Z_Malloc(ST_WIDTH*ST_HEIGHT, PU_STATIC, 0);
+ st_backing_screen = (byte *) Z_Malloc(ST_WIDTH * ST_HEIGHT, PU_STATIC, 0);
}
+
diff --git a/src/st_stuff.h b/src/doom/st_stuff.h
index c6b56fd6..2ee91cce 100644
--- a/src/st_stuff.h
+++ b/src/doom/st_stuff.h
@@ -80,8 +80,8 @@ typedef enum
} st_chatstateenum_t;
-boolean ST_Responder(event_t* ev);
+extern byte *st_backing_screen;
extern cheatseq_t cheat_mus;
extern cheatseq_t cheat_god;
extern cheatseq_t cheat_ammo;
diff --git a/src/doom/statdump.c b/src/doom/statdump.c
new file mode 100644
index 00000000..cba91776
--- /dev/null
+++ b/src/doom/statdump.c
@@ -0,0 +1,362 @@
+
+ /*
+
+ Copyright(C) 2007,2011 Simon Howard
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ --
+
+ Functions for presenting the information captured from the statistics
+ buffer to a file.
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "d_player.h"
+#include "d_mode.h"
+#include "m_argv.h"
+
+#include "statdump.h"
+
+/* Par times for E1M1-E1M9. */
+static const int doom1_par_times[] =
+{
+ 30, 75, 120, 90, 165, 180, 180, 30, 165,
+};
+
+/* Par times for MAP01-MAP09. */
+static const int doom2_par_times[] =
+{
+ 30, 90, 120, 120, 90, 150, 120, 120, 270,
+};
+
+/* Player colors. */
+static const char *player_colors[] =
+{
+ "Green", "Indigo", "Brown", "Red"
+};
+
+// Array of end-of-level statistics that have been captured.
+
+#define MAX_CAPTURES 32
+static wbstartstruct_t captured_stats[MAX_CAPTURES];
+static int num_captured_stats = 0;
+
+static GameMode_t discovered_gamemode = indetermined;
+
+/* Try to work out whether this is a Doom 1 or Doom 2 game, by looking
+ * at the episode and map, and the par times. This is used to decide
+ * how to format the level name. Unfortunately, in some cases it is
+ * impossible to determine whether this is Doom 1 or Doom 2. */
+
+static void DiscoverGamemode(wbstartstruct_t *stats, int num_stats)
+{
+ int partime;
+ int level;
+ int i;
+
+ if (discovered_gamemode != indetermined)
+ {
+ return;
+ }
+
+ for (i=0; i<num_stats; ++i)
+ {
+ level = stats[i].last;
+
+ /* If episode 2, 3 or 4, this is Doom 1. */
+
+ if (stats[i].epsd > 0)
+ {
+ discovered_gamemode = doom;
+ return;
+ }
+
+ /* This is episode 1. If this is level 10 or higher,
+ it must be Doom 2. */
+
+ if (level >= 9)
+ {
+ discovered_gamemode = doom2;
+ return;
+ }
+
+ /* Try to work out if this is Doom 1 or Doom 2 by looking
+ at the par time. */
+
+ partime = stats[i].partime;
+
+ if (partime == doom1_par_times[level] * TICRATE
+ && partime != doom2_par_times[level] * TICRATE)
+ {
+ discovered_gamemode = doom;
+ return;
+ }
+
+ if (partime != doom1_par_times[level] * TICRATE
+ && partime == doom2_par_times[level] * TICRATE)
+ {
+ discovered_gamemode = doom2;
+ return;
+ }
+ }
+}
+
+/* Returns the number of players active in the given stats buffer. */
+
+static int GetNumPlayers(wbstartstruct_t *stats)
+{
+ int i;
+ int num_players = 0;
+
+ for (i=0; i<MAXPLAYERS; ++i)
+ {
+ if (stats->plyr[i].in)
+ {
+ ++num_players;
+ }
+ }
+
+ return num_players;
+}
+
+static void PrintBanner(FILE *stream)
+{
+ fprintf(stream, "===========================================\n");
+}
+
+static void PrintPercentage(FILE *stream, int amount, int total)
+{
+ if (total == 0)
+ {
+ fprintf(stream, "0");
+ }
+ else
+ {
+ fprintf(stream, "%i / %i", amount, total);
+
+ // statdump.exe is a 16-bit program, so very occasionally an
+ // integer overflow can occur when doing this calculation with
+ // a large value. Therefore, cast to short to give the same
+ // output.
+
+ fprintf(stream, " (%i%%)", (short) (amount * 100) / total);
+ }
+}
+
+/* Display statistics for a single player. */
+
+static void PrintPlayerStats(FILE *stream, wbstartstruct_t *stats,
+ int player_num)
+{
+ wbplayerstruct_t *player = &stats->plyr[player_num];
+
+ fprintf(stream, "Player %i (%s):\n", player_num + 1,
+ player_colors[player_num]);
+
+ /* Kills percentage */
+
+ fprintf(stream, "\tKills: ");
+ PrintPercentage(stream, player->skills, stats->maxkills);
+ fprintf(stream, "\n");
+
+ /* Items percentage */
+
+ fprintf(stream, "\tItems: ");
+ PrintPercentage(stream, player->sitems, stats->maxitems);
+ fprintf(stream, "\n");
+
+ /* Secrets percentage */
+
+ fprintf(stream, "\tSecrets: ");
+ PrintPercentage(stream, player->ssecret, stats->maxsecret);
+ fprintf(stream, "\n");
+}
+
+/* Frags table for multiplayer games. */
+
+static void PrintFragsTable(FILE *stream, wbstartstruct_t *stats)
+{
+ int x, y;
+
+ fprintf(stream, "Frags:\n");
+
+ /* Print header */
+
+ fprintf(stream, "\t\t");
+
+ for (x=0; x<MAXPLAYERS; ++x)
+ {
+
+ if (!stats->plyr[x].in)
+ {
+ continue;
+ }
+
+ fprintf(stream, "%s\t", player_colors[x]);
+ }
+
+ fprintf(stream, "\n");
+
+ fprintf(stream, "\t\t-------------------------------- VICTIMS\n");
+
+ /* Print table */
+
+ for (y=0; y<MAXPLAYERS; ++y)
+ {
+ if (!stats->plyr[y].in)
+ {
+ continue;
+ }
+
+ fprintf(stream, "\t%s\t|", player_colors[y]);
+
+ for (x=0; x<MAXPLAYERS; ++x)
+ {
+ if (!stats->plyr[x].in)
+ {
+ continue;
+ }
+
+ fprintf(stream, "%i\t", stats->plyr[y].frags[x]);
+ }
+
+ fprintf(stream, "\n");
+ }
+
+ fprintf(stream, "\t\t|\n");
+ fprintf(stream, "\t KILLERS\n");
+}
+
+/* Displays the level name: MAPxy or ExMy, depending on game mode. */
+
+static void PrintLevelName(FILE *stream, int episode, int level)
+{
+ PrintBanner(stream);
+
+ switch (discovered_gamemode)
+ {
+
+ case doom:
+ fprintf(stream, "E%iM%i\n", episode + 1, level + 1);
+ break;
+ case doom2:
+ fprintf(stream, "MAP%02i\n", level + 1);
+ break;
+ default:
+ case indetermined:
+ fprintf(stream, "E%iM%i / MAP%02i\n",
+ episode + 1, level + 1, level + 1);
+ break;
+ }
+
+ PrintBanner(stream);
+}
+
+/* Print details of a statistics buffer to the given file. */
+
+static void PrintStats(FILE *stream, wbstartstruct_t *stats)
+{
+ int leveltime, partime;
+ int i;
+
+ PrintLevelName(stream, stats->epsd, stats->last);
+ fprintf(stream, "\n");
+
+ leveltime = stats->plyr[0].stime / TICRATE;
+ partime = stats->partime / TICRATE;
+ fprintf(stream, "Time: %i:%02i", leveltime / 60, leveltime % 60);
+ fprintf(stream, " (par: %i:%02i)\n", partime / 60, partime % 60);
+ fprintf(stream, "\n");
+
+ for (i=0; i<MAXPLAYERS; ++i)
+ {
+ if (stats->plyr[i].in)
+ {
+ PrintPlayerStats(stream, stats, i);
+ }
+ }
+
+ if (GetNumPlayers(stats) >= 2)
+ {
+ PrintFragsTable(stream, stats);
+ }
+
+ fprintf(stream, "\n");
+}
+
+void StatCopy(wbstartstruct_t *stats)
+{
+ if (M_ParmExists("-statdump") && num_captured_stats < MAX_CAPTURES)
+ {
+ memcpy(&captured_stats[num_captured_stats], stats,
+ sizeof(wbstartstruct_t));
+ ++num_captured_stats;
+ }
+}
+
+void StatDump(void)
+{
+ FILE *dumpfile;
+ int i;
+
+ //!
+ // @category compat
+ // @arg <filename>
+ //
+ // Dump statistics information to the specified file on the levels
+ // that were played. The output from this option matches the output
+ // from statdump.exe (see ctrlapi.zip in the /idgames archive).
+ //
+
+ i = M_CheckParmWithArgs("-statdump", 1);
+
+ if (i > 0)
+ {
+ printf("Statistics captured for %i level(s)\n", num_captured_stats);
+
+ // We actually know what the real gamemode is, but this has
+ // to match the output from statdump.exe.
+
+ DiscoverGamemode(captured_stats, num_captured_stats);
+
+ // Allow "-" as output file, for stdout.
+
+ if (strcmp(myargv[i + 1], "-") != 0)
+ {
+ dumpfile = fopen(myargv[i + 1], "w");
+ }
+ else
+ {
+ dumpfile = NULL;
+ }
+
+ for (i = 0; i < num_captured_stats; ++i)
+ {
+ PrintStats(dumpfile, &captured_stats[i]);
+ }
+
+ if (dumpfile != NULL)
+ {
+ fclose(dumpfile);
+ }
+ }
+}
+
diff --git a/src/doom/statdump.h b/src/doom/statdump.h
new file mode 100644
index 00000000..511d945b
--- /dev/null
+++ b/src/doom/statdump.h
@@ -0,0 +1,29 @@
+
+ /*
+
+ Copyright(C) 2007 Simon Howard
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ */
+
+#ifndef DOOM_STATDUMP_H
+#define DOOM_STATDUMP_H
+
+void StatCopy(wbstartstruct_t *stats);
+void StatDump(void);
+
+#endif /* #ifndef DOOM_STATDUMP_H */
diff --git a/src/wi_stuff.c b/src/doom/wi_stuff.c
index 37933eda..298dc07d 100644
--- a/src/wi_stuff.c
+++ b/src/doom/wi_stuff.c
@@ -290,8 +290,6 @@ static anim_t *anims[NUMEPISODES] =
//
// Locally used stuff.
//
-#define FB 0
-
// States for single-player
#define SP_KILLS 0
@@ -400,18 +398,17 @@ static patch_t* bp[MAXPLAYERS];
// Name graphics of each level (centered)
static patch_t** lnames;
+// Buffer storing the backdrop
+static patch_t *background;
+
//
// CODE
//
// slam background
-// UNUSED static unsigned char *background=0;
-
-
void WI_slamBackground(void)
{
- memcpy(screens[0], screens[1], SCREENWIDTH * SCREENHEIGHT);
- V_MarkRect (0, 0, SCREENWIDTH, SCREENHEIGHT);
+ V_DrawPatch(0, 0, background);
}
// The ticker is used to detect keys
@@ -431,10 +428,12 @@ void WI_drawLF(void)
{
// draw <LevelName>
V_DrawPatch((SCREENWIDTH - SHORT(lnames[wbs->last]->width))/2,
- y, FB, lnames[wbs->last]);
+ y, lnames[wbs->last]);
// draw "Finished!"
y += (5*SHORT(lnames[wbs->last]->height))/4;
+
+ V_DrawPatch((SCREENWIDTH - SHORT(finished->width)) / 2, y, finished);
}
else if (wbs->last == NUMCMAPS)
{
@@ -450,11 +449,8 @@ void WI_drawLF(void)
patch_t tmp = { SCREENWIDTH, SCREENHEIGHT, 1, 1,
{ 0, 0, 0, 0, 0, 0, 0, 0 } };
- V_DrawPatch(0, y, FB, &tmp);
+ V_DrawPatch(0, y, &tmp);
}
-
- V_DrawPatch((SCREENWIDTH - SHORT(finished->width))/2,
- y, FB, finished);
}
@@ -466,13 +462,15 @@ void WI_drawEL(void)
// draw "Entering"
V_DrawPatch((SCREENWIDTH - SHORT(entering->width))/2,
- y, FB, entering);
+ y,
+ entering);
// draw level
y += (5*SHORT(lnames[wbs->next]->height))/4;
V_DrawPatch((SCREENWIDTH - SHORT(lnames[wbs->next]->width))/2,
- y, FB, lnames[wbs->next]);
+ y,
+ lnames[wbs->next]);
}
@@ -512,8 +510,9 @@ WI_drawOnLnode
if (fits && i<2)
{
- V_DrawPatch(lnodes[wbs->epsd][n].x, lnodes[wbs->epsd][n].y,
- FB, c[i]);
+ V_DrawPatch(lnodes[wbs->epsd][n].x,
+ lnodes[wbs->epsd][n].y,
+ c[i]);
}
else
{
@@ -620,7 +619,7 @@ void WI_drawAnimatedBack(void)
a = &anims[wbs->epsd][i];
if (a->ctr >= 0)
- V_DrawPatch(a->loc.x, a->loc.y, FB, a->p[a->ctr]);
+ V_DrawPatch(a->loc.x, a->loc.y, a->p[a->ctr]);
}
}
@@ -677,13 +676,13 @@ WI_drawNum
while (digits--)
{
x -= fontwidth;
- V_DrawPatch(x, y, FB, num[ n % 10 ]);
+ V_DrawPatch(x, y, num[ n % 10 ]);
n /= 10;
}
// draw a minus sign if necessary
if (neg)
- V_DrawPatch(x-=8, y, FB, wiminus);
+ V_DrawPatch(x-=8, y, wiminus);
return x;
@@ -698,7 +697,7 @@ WI_drawPercent
if (p < 0)
return;
- V_DrawPatch(x, y, FB, percent);
+ V_DrawPatch(x, y, percent);
WI_drawNum(x, y, p, -1);
}
@@ -733,14 +732,14 @@ WI_drawTime
// draw
if (div==60 || t / div)
- V_DrawPatch(x, y, FB, colon);
+ V_DrawPatch(x, y, colon);
} while (t / div);
}
else
{
// "sucks"
- V_DrawPatch(x - SHORT(sucks->width), y, FB, sucks);
+ V_DrawPatch(x - SHORT(sucks->width), y, sucks);
}
}
@@ -1024,11 +1023,10 @@ void WI_drawDeathmatchStats(void)
// draw stat titles (top line)
V_DrawPatch(DM_TOTALSX-SHORT(total->width)/2,
DM_MATRIXY-WI_SPACINGY+10,
- FB,
total);
- V_DrawPatch(DM_KILLERSX, DM_KILLERSY, FB, killers);
- V_DrawPatch(DM_VICTIMSX, DM_VICTIMSY, FB, victims);
+ V_DrawPatch(DM_KILLERSX, DM_KILLERSY, killers);
+ V_DrawPatch(DM_VICTIMSX, DM_VICTIMSY, victims);
// draw P?
x = DM_MATRIXX + DM_SPACINGX;
@@ -1040,33 +1038,29 @@ void WI_drawDeathmatchStats(void)
{
V_DrawPatch(x-SHORT(p[i]->width)/2,
DM_MATRIXY - WI_SPACINGY,
- FB,
p[i]);
V_DrawPatch(DM_MATRIXX-SHORT(p[i]->width)/2,
y,
- FB,
p[i]);
if (i == me)
{
V_DrawPatch(x-SHORT(p[i]->width)/2,
DM_MATRIXY - WI_SPACINGY,
- FB,
bstar);
V_DrawPatch(DM_MATRIXX-SHORT(p[i]->width)/2,
y,
- FB,
star);
}
}
else
{
// V_DrawPatch(x-SHORT(bp[i]->width)/2,
- // DM_MATRIXY - WI_SPACINGY, FB, bp[i]);
+ // DM_MATRIXY - WI_SPACINGY, bp[i]);
// V_DrawPatch(DM_MATRIXX-SHORT(bp[i]->width)/2,
- // y, FB, bp[i]);
+ // y, bp[i]);
}
x += DM_SPACINGX;
y += WI_SPACINGY;
@@ -1298,17 +1292,17 @@ void WI_drawNetgameStats(void)
// draw stat titles (top line)
V_DrawPatch(NG_STATSX+NG_SPACINGX-SHORT(kills->width),
- NG_STATSY, FB, kills);
+ NG_STATSY, kills);
V_DrawPatch(NG_STATSX+2*NG_SPACINGX-SHORT(items->width),
- NG_STATSY, FB, items);
+ NG_STATSY, items);
V_DrawPatch(NG_STATSX+3*NG_SPACINGX-SHORT(secret->width),
- NG_STATSY, FB, secret);
+ NG_STATSY, secret);
if (dofrags)
V_DrawPatch(NG_STATSX+4*NG_SPACINGX-SHORT(frags->width),
- NG_STATSY, FB, frags);
+ NG_STATSY, frags);
// draw stats
y = NG_STATSY + SHORT(kills->height);
@@ -1319,10 +1313,10 @@ void WI_drawNetgameStats(void)
continue;
x = NG_STATSX;
- V_DrawPatch(x-SHORT(p[i]->width), y, FB, p[i]);
+ V_DrawPatch(x-SHORT(p[i]->width), y, p[i]);
if (i == me)
- V_DrawPatch(x-SHORT(p[i]->width), y, FB, star);
+ V_DrawPatch(x-SHORT(p[i]->width), y, star);
x += NG_SPACINGX;
WI_drawPercent(x-pwidth, y+10, cnt_kills[i]); x += NG_SPACINGX;
@@ -1471,21 +1465,21 @@ void WI_drawStats(void)
WI_drawLF();
- V_DrawPatch(SP_STATSX, SP_STATSY, FB, kills);
+ V_DrawPatch(SP_STATSX, SP_STATSY, kills);
WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY, cnt_kills[0]);
- V_DrawPatch(SP_STATSX, SP_STATSY+lh, FB, items);
+ V_DrawPatch(SP_STATSX, SP_STATSY+lh, items);
WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY+lh, cnt_items[0]);
- V_DrawPatch(SP_STATSX, SP_STATSY+2*lh, FB, sp_secret);
+ V_DrawPatch(SP_STATSX, SP_STATSY+2*lh, sp_secret);
WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY+2*lh, cnt_secret[0]);
- V_DrawPatch(SP_TIMEX, SP_TIMEY, FB, timepatch);
+ V_DrawPatch(SP_TIMEX, SP_TIMEY, timepatch);
WI_drawTime(SCREENWIDTH/2 - SP_TIMEX, SP_TIMEY, cnt_time);
if (wbs->epsd < 3)
{
- V_DrawPatch(SCREENWIDTH/2 + SP_TIMEX, SP_TIMEY, FB, par);
+ V_DrawPatch(SCREENWIDTH/2 + SP_TIMEX, SP_TIMEY, par);
WI_drawTime(SCREENWIDTH - SP_TIMEX, SP_TIMEY, cnt_par);
}
@@ -1566,21 +1560,9 @@ typedef void (*load_callback_t)(char *lumpname, patch_t **variable);
static void WI_loadUnloadData(load_callback_t callback)
{
- int i;
- int j;
- char name[9];
- anim_t* a;
-
- // UNUSED unsigned char *pic = screens[1];
- // if (gamemode == commercial)
- // {
- // darken the background image
- // while (pic != screens[1] + SCREENHEIGHT*SCREENWIDTH)
- // {
- // *pic = colormaps[256*25 + *pic];
- // pic++;
- // }
- //}
+ int i, j;
+ char name[9];
+ anim_t *a;
if (gamemode == commercial)
{
@@ -1706,6 +1688,26 @@ static void WI_loadUnloadData(load_callback_t callback)
callback(name, &bp[i]);
}
+ // Background image
+
+ if (gamemode == commercial)
+ {
+ strncpy(name, DEH_String("INTERPIC"), 9);
+ name[8] = '\0';
+ }
+ else if (gamemode == retail && wbs->epsd == 3)
+ {
+ strncpy(name, DEH_String("INTERPIC"), 9);
+ name[8] = '\0';
+ }
+ else
+ {
+ DEH_snprintf(name, 9, "WIMAP%d", wbs->epsd);
+ }
+
+ // Draw backdrop and save to a temporary buffer
+
+ callback(name, &background);
}
static void WI_loadCallback(char *name, patch_t **variable)
@@ -1715,9 +1717,6 @@ static void WI_loadCallback(char *name, patch_t **variable)
void WI_loadData(void)
{
- char bg_lumpname[9];
- patch_t *bg;
-
if (gamemode == commercial)
{
NUMCMAPS = 32;
@@ -1740,26 +1739,6 @@ void WI_loadData(void)
// dead face
bstar = W_CacheLumpName(DEH_String("STFDEAD0"), PU_STATIC);
-
- // Background image
-
- if (gamemode == commercial)
- {
- strncpy(bg_lumpname, DEH_String("INTERPIC"), 9);
- bg_lumpname[8] = '\0';
- }
- else if (gamemode == retail && wbs->epsd == 3)
- {
- strncpy(bg_lumpname, DEH_String("INTERPIC"), 9);
- bg_lumpname[8] = '\0';
- }
- else
- {
- DEH_snprintf(bg_lumpname, 9, "WIMAP%d", wbs->epsd);
- }
-
- bg = W_CacheLumpName(bg_lumpname, PU_CACHE);
- V_DrawPatch(0, 0, 1, bg);
}
static void WI_unloadCallback(char *name, patch_t **variable)
diff --git a/src/wi_stuff.h b/src/doom/wi_stuff.h
index 7d3a84b9..7d3a84b9 100644
--- a/src/wi_stuff.h
+++ b/src/doom/wi_stuff.h
diff --git a/src/doomkeys.h b/src/doomkeys.h
index 3db17a6d..4fd074e3 100644
--- a/src/doomkeys.h
+++ b/src/doomkeys.h
@@ -52,7 +52,7 @@
#define KEY_F11 (0x80+0x57)
#define KEY_F12 (0x80+0x58)
-#define KEY_BACKSPACE '\b'
+#define KEY_BACKSPACE 0x7f
#define KEY_PAUSE 0xff
#define KEY_EQUALS 0x3d
diff --git a/src/doomtype.h b/src/doomtype.h
index 0a5b5e38..b458c1cd 100644
--- a/src/doomtype.h
+++ b/src/doomtype.h
@@ -29,6 +29,41 @@
#ifndef __DOOMTYPE__
#define __DOOMTYPE__
+// #define macros to provide functions missing in Windows.
+// Outside Windows, we use strings.h for str[n]casecmp.
+
+
+#ifdef _WIN32
+
+#define snprintf _snprintf
+#if _MSC_VER < 1400 /* not needed for Visual Studio 2008 */
+#define vsnprintf _vsnprintf
+#endif
+#define strcasecmp stricmp
+#define strncasecmp strnicmp
+
+#else
+
+#include <strings.h>
+
+#endif
+
+
+//
+// The packed attribute forces structures to be packed into the minimum
+// space necessary. If this is not done, the compiler may align structure
+// fields differently to optimize memory access, inflating the overall
+// structure size. It is important to use the packed attribute on certain
+// structures where alignment is important, particularly data read/written
+// to disk.
+//
+
+#ifdef __GNUC__
+#define PACKEDATTR __attribute__((packed))
+#else
+#define PACKEDATTR
+#endif
+
// Windows CE is missing some vital ANSI C functions. We have to
// use our own replacements.
diff --git a/src/gusconf.c b/src/gusconf.c
new file mode 100644
index 00000000..e4be25e2
--- /dev/null
+++ b/src/gusconf.c
@@ -0,0 +1,279 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2013 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// GUS emulation code.
+//
+// Actually emulating a GUS is far too much work; fortunately
+// GUS "emulation" already exists in the form of Timidity, which
+// supports GUS patch files. This code therefore converts Doom's
+// DMXGUS lump into an equivalent Timidity configuration file.
+//
+//-----------------------------------------------------------------------------
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "w_wad.h"
+#include "z_zone.h"
+
+#define MAX_INSTRUMENTS 256
+
+typedef struct
+{
+ char *patch_names[MAX_INSTRUMENTS];
+ int mapping[MAX_INSTRUMENTS];
+} gus_config_t;
+
+char *gus_patch_path = "";
+unsigned int gus_ram_kb = 1024;
+
+static unsigned int MappingIndex(void)
+{
+ unsigned int result = gus_ram_kb / 256;
+
+ if (result < 1)
+ {
+ return 1;
+ }
+ else if (result > 4)
+ {
+ return 4;
+ }
+ else
+ {
+ return result;
+ }
+}
+
+static int SplitLine(char *line, char **fields, unsigned int max_fields)
+{
+ unsigned int num_fields;
+ char *p;
+
+ fields[0] = line;
+ num_fields = 1;
+
+ for (p = line; *p != '\0'; ++p)
+ {
+ if (*p == ',')
+ {
+ *p = '\0';
+
+ // Skip spaces following the comma.
+ do
+ {
+ ++p;
+ } while (*p != '\0' && isspace(*p));
+
+ fields[num_fields] = p;
+ ++num_fields;
+ --p;
+
+ if (num_fields >= max_fields)
+ {
+ break;
+ }
+ }
+ else if (*p == '#')
+ {
+ *p = '\0';
+ break;
+ }
+ }
+
+ // Strip off trailing whitespace from the end of the line.
+ p = fields[num_fields - 1] + strlen(fields[num_fields - 1]);
+ while (p > fields[num_fields - 1] && isspace(*(p - 1)))
+ {
+ --p;
+ *p = '\0';
+ }
+
+ return num_fields;
+}
+
+static void ParseLine(gus_config_t *config, char *line)
+{
+ char *fields[6];
+ unsigned int num_fields;
+ unsigned int instr_id, mapped_id;
+
+ num_fields = SplitLine(line, fields, 6);
+
+ if (num_fields < 6)
+ {
+ return;
+ }
+
+ instr_id = atoi(fields[0]);
+ mapped_id = atoi(fields[MappingIndex()]);
+
+ free(config->patch_names[instr_id]);
+ config->patch_names[instr_id] = strdup(fields[5]);
+ config->mapping[instr_id] = mapped_id;
+}
+
+static void ParseDMXConfig(char *dmxconf, gus_config_t *config)
+{
+ char *p, *newline;
+ unsigned int i;
+
+ memset(config, 0, sizeof(gus_config_t));
+
+ for (i = 0; i < MAX_INSTRUMENTS; ++i)
+ {
+ config->mapping[i] = -1;
+ }
+
+ p = dmxconf;
+
+ for (;;)
+ {
+ newline = strchr(p, '\n');
+
+ if (newline != NULL)
+ {
+ *newline = '\0';
+ }
+
+ ParseLine(config, p);
+
+ if (newline == NULL)
+ {
+ break;
+ }
+ else
+ {
+ p = newline + 1;
+ }
+ }
+}
+
+static void FreeDMXConfig(gus_config_t *config)
+{
+ unsigned int i;
+
+ for (i = 0; i < MAX_INSTRUMENTS; ++i)
+ {
+ free(config->patch_names[i]);
+ }
+}
+
+static char *ReadDMXConfig(void)
+{
+ int lumpnum;
+ unsigned int len;
+ char *data;
+
+ // TODO: This should be chosen based on gamemode == commercial:
+
+ lumpnum = W_CheckNumForName("DMXGUS");
+
+ if (lumpnum < 0)
+ {
+ lumpnum = W_GetNumForName("DMXGUSC");
+ }
+
+ len = W_LumpLength(lumpnum);
+ data = Z_Malloc(len + 1, PU_STATIC, NULL);
+ W_ReadLump(lumpnum, data);
+
+ return data;
+}
+
+static boolean WriteTimidityConfig(char *path, gus_config_t *config)
+{
+ FILE *fstream;
+ unsigned int i;
+
+ fstream = fopen(path, "w");
+
+ if (fstream == NULL)
+ {
+ return false;
+ }
+
+ fprintf(fstream, "# Autogenerated Timidity config.\n\n");
+
+ fprintf(fstream, "dir %s\n", gus_patch_path);
+
+ fprintf(fstream, "\nbank 0\n\n");
+
+ for (i = 0; i < 128; ++i)
+ {
+ if (config->mapping[i] >= 0 && config->mapping[i] < MAX_INSTRUMENTS
+ && config->patch_names[config->mapping[i]] != NULL)
+ {
+ fprintf(fstream, "%i %s\n",
+ i, config->patch_names[config->mapping[i]]);
+ }
+ }
+
+ fprintf(fstream, "\ndrumset 0\n\n");
+
+ for (i = 128 + 25; i < MAX_INSTRUMENTS; ++i)
+ {
+ if (config->mapping[i] >= 0 && config->mapping[i] < MAX_INSTRUMENTS
+ && config->patch_names[config->mapping[i]] != NULL)
+ {
+ fprintf(fstream, "%i %s\n",
+ i - 128, config->patch_names[config->mapping[i]]);
+ }
+ }
+
+ fprintf(fstream, "\n");
+
+ fclose(fstream);
+
+ return true;
+}
+
+boolean GUS_WriteConfig(char *path)
+{
+ boolean result;
+ char *dmxconf;
+ gus_config_t config;
+
+ if (!strcmp(gus_patch_path, ""))
+ {
+ printf("You haven't configured gus_patch_path.\n");
+ printf("gus_patch_path needs to point to the location of "
+ "your GUS patch set.\n"
+ "To get a copy of the \"standard\" GUS patches, "
+ "download a copy of dgguspat.zip.\n");
+
+ return false;
+ }
+
+ dmxconf = ReadDMXConfig();
+ ParseDMXConfig(dmxconf, &config);
+
+ result = WriteTimidityConfig(path, &config);
+
+ FreeDMXConfig(&config);
+ Z_Free(dmxconf);
+
+ return result;
+}
+
diff --git a/src/gusconf.h b/src/gusconf.h
new file mode 100644
index 00000000..b0757149
--- /dev/null
+++ b/src/gusconf.h
@@ -0,0 +1,37 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2013 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// GUS emulation code.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef __GUSCONF_H__
+#define __GUSCONF_H__
+
+#include "doomtype.h"
+
+extern char *gus_patch_path;
+extern unsigned int gus_ram_kb;
+
+boolean GUS_WriteConfig(char *path);
+
+#endif /* #ifndef __GUSCONF_H__ */
+
diff --git a/src/heretic/.gitignore b/src/heretic/.gitignore
new file mode 100644
index 00000000..76092240
--- /dev/null
+++ b/src/heretic/.gitignore
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+.deps
+tags
+TAGS
+
diff --git a/src/heretic/Makefile.am b/src/heretic/Makefile.am
new file mode 100644
index 00000000..e56ee806
--- /dev/null
+++ b/src/heretic/Makefile.am
@@ -0,0 +1,70 @@
+
+AM_CFLAGS=-I.. \
+ -I$(top_builddir)/textscreen \
+ @SDL_CFLAGS@ @SDLMIXER_CFLAGS@ @SDLNET_CFLAGS@
+
+noinst_LIBRARIES=libheretic.a
+
+SOURCE_FILES= \
+ am_data.h \
+am_map.c am_map.h \
+ct_chat.c ct_chat.h \
+d_main.c \
+d_net.c \
+ doomdata.h \
+ doomdef.h \
+ dstrings.h \
+f_finale.c \
+g_game.c \
+info.c info.h \
+in_lude.c \
+m_random.c m_random.h \
+mn_menu.c \
+ p_action.h \
+p_ceilng.c \
+p_doors.c \
+p_enemy.c \
+p_floor.c \
+p_inter.c \
+p_lights.c \
+p_local.h \
+p_map.c \
+p_maputl.c \
+p_mobj.c \
+p_plats.c \
+p_pspr.c \
+p_setup.c \
+p_sight.c \
+p_spec.c p_spec.h \
+p_switch.c \
+p_telept.c \
+p_tick.c \
+p_user.c \
+r_bsp.c \
+r_data.c \
+r_draw.c \
+ r_local.h \
+r_main.c \
+r_plane.c \
+r_segs.c \
+r_things.c \
+sb_bar.c \
+sounds.c sounds.h \
+s_sound.c s_sound.h
+
+EXTRA_DIST= \
+i_sound.c \
+i_ibm.c
+
+FEATURE_DEHACKED_SOURCE_FILES = \
+deh_ammo.c \
+deh_frame.c \
+deh_htext.c \
+deh_htic.c \
+deh_sound.c \
+deh_thing.c \
+deh_weapon.c
+
+libheretic_a_SOURCES=$(SOURCE_FILES) \
+ $(FEATURE_DEHACKED_SOURCE_FILES)
+
diff --git a/src/heretic/am_data.h b/src/heretic/am_data.h
new file mode 100644
index 00000000..342f06a9
--- /dev/null
+++ b/src/heretic/am_data.h
@@ -0,0 +1,111 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+// AM_data.h : The vector graphics for the automap
+
+#ifndef __AMDATA_H__
+#define __AMDATA_H__
+
+// a line drawing of the player pointing right, starting from the middle.
+
+#define R ((8*PLAYERRADIUS)/7)
+
+mline_t player_arrow[] = {
+ { { -R+R/4, 0 }, { 0, 0} }, // center line.
+ { { -R+R/4, R/8 }, { R, 0} }, // blade
+ { { -R+R/4, -R/8 }, { R, 0 } },
+ { { -R+R/4, -R/4 }, { -R+R/4, R/4 } }, // crosspiece
+ { { -R+R/8, -R/4 }, { -R+R/8, R/4 } },
+ { { -R+R/8, -R/4 }, { -R+R/4, -R/4} }, //crosspiece connectors
+ { { -R+R/8, R/4 }, { -R+R/4, R/4} },
+ { { -R-R/4, R/8 }, { -R-R/4, -R/8 } }, //pommel
+ { { -R-R/4, R/8 }, { -R+R/8, R/8 } },
+ { { -R-R/4, -R/8}, { -R+R/8, -R/8 } }
+ };
+
+mline_t keysquare[] = {
+ { { 0, 0 }, { R/4, -R/2 } },
+ { { R/4, -R/2 }, { R/2, -R/2 } },
+ { { R/2, -R/2 }, { R/2, R/2 } },
+ { { R/2, R/2 }, { R/4, R/2 } },
+ { { R/4, R/2 }, { 0, 0 } }, // handle part type thing
+ { { 0, 0 }, { -R, 0 } }, // stem
+ { { -R, 0 }, { -R, -R/2 } }, // end lockpick part
+ { { -3*R/4, 0 }, { -3*R/4, -R/4 } }
+ };
+
+/*mline_t player_arrow[] = {
+ { { -R+R/8, 0 }, { R, 0 } }, // -----
+ { { R, 0 }, { R-R/2, R/4 } }, // ----->
+ { { R, 0 }, { R-R/2, -R/4 } },
+ { { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >---->
+ { { -R+R/8, 0 }, { -R-R/8, -R/4 } },
+ { { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>--->
+ { { -R+3*R/8, 0 }, { -R+R/8, -R/4 } }
+ };
+*/
+#undef R
+#define NUMPLYRLINES (sizeof(player_arrow)/sizeof(mline_t))
+#define NUMKEYSQUARELINES (sizeof(keysquare)/sizeof(mline_t))
+
+#define R ((8*PLAYERRADIUS)/7)
+mline_t cheat_player_arrow[] = {
+ { { -R+R/8, 0 }, { R, 0 } }, // -----
+ { { R, 0 }, { R-R/2, R/6 } }, // ----->
+ { { R, 0 }, { R-R/2, -R/6 } },
+ { { -R+R/8, 0 }, { -R-R/8, R/6 } }, // >----->
+ { { -R+R/8, 0 }, { -R-R/8, -R/6 } },
+ { { -R+3*R/8, 0 }, { -R+R/8, R/6 } }, // >>----->
+ { { -R+3*R/8, 0 }, { -R+R/8, -R/6 } },
+ { { -R/2, 0 }, { -R/2, -R/6 } }, // >>-d--->
+ { { -R/2, -R/6 }, { -R/2+R/6, -R/6 } },
+ { { -R/2+R/6, -R/6 }, { -R/2+R/6, R/4 } },
+ { { -R/6, 0 }, { -R/6, -R/6 } }, // >>-dd-->
+ { { -R/6, -R/6 }, { 0, -R/6 } },
+ { { 0, -R/6 }, { 0, R/4 } },
+ { { R/6, R/4 }, { R/6, -R/7 } }, // >>-ddt->
+ { { R/6, -R/7 }, { R/6+R/32, -R/7-R/32 } },
+ { { R/6+R/32, -R/7-R/32 }, { R/6+R/10, -R/7 } }
+ };
+#undef R
+#define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow)/sizeof(mline_t))
+
+#define R (FRACUNIT)
+mline_t triangle_guy[] = {
+ { { (fixed_t)(-.867*R), (fixed_t)(-.5*R) }, { (fixed_t)(.867*R ), (fixed_t)(-.5*R) } },
+ { { (fixed_t)(.867*R ), (fixed_t)(-.5*R) }, { (fixed_t)(0 ), (fixed_t)(R ) } },
+ { { (fixed_t)(0 ), (fixed_t)(R ) }, { (fixed_t)(-.867*R), (fixed_t)(-.5*R) } }
+ };
+#undef R
+#define NUMTRIANGLEGUYLINES (sizeof(triangle_guy)/sizeof(mline_t))
+
+#define R (FRACUNIT)
+mline_t thintriangle_guy[] = {
+ { { (fixed_t)(-.5*R), (fixed_t)(-.7*R) }, { (fixed_t)(R ), (fixed_t)(0 ) } },
+ { { (fixed_t)(R ), (fixed_t)(0 ) }, { (fixed_t)(-.5*R), (fixed_t)(.7*R ) } },
+ { { (fixed_t)(-.5*R), (fixed_t)(.7*R ) }, { (fixed_t)(-.5*R), (fixed_t)(-.7*R) } }
+ };
+#undef R
+#define NUMTHINTRIANGLEGUYLINES (sizeof(thintriangle_guy)/sizeof(mline_t))
+
+#endif
diff --git a/src/heretic/am_map.c b/src/heretic/am_map.c
new file mode 100644
index 00000000..2230c69e
--- /dev/null
+++ b/src/heretic/am_map.c
@@ -0,0 +1,1513 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// AM_map.c
+
+#include <stdio.h>
+
+#include "doomdef.h"
+#include "deh_str.h"
+#include "i_video.h"
+#include "m_controls.h"
+#include "p_local.h"
+#include "am_map.h"
+#include "am_data.h"
+
+#include "doomkeys.h"
+#include "v_video.h"
+
+vertex_t KeyPoints[NUMKEYS];
+
+#define NUMALIAS 3 // Number of antialiased lines.
+
+char *LevelNames[] = {
+ // EPISODE 1 - THE CITY OF THE DAMNED
+ "E1M1: THE DOCKS",
+ "E1M2: THE DUNGEONS",
+ "E1M3: THE GATEHOUSE",
+ "E1M4: THE GUARD TOWER",
+ "E1M5: THE CITADEL",
+ "E1M6: THE CATHEDRAL",
+ "E1M7: THE CRYPTS",
+ "E1M8: HELL'S MAW",
+ "E1M9: THE GRAVEYARD",
+ // EPISODE 2 - HELL'S MAW
+ "E2M1: THE CRATER",
+ "E2M2: THE LAVA PITS",
+ "E2M3: THE RIVER OF FIRE",
+ "E2M4: THE ICE GROTTO",
+ "E2M5: THE CATACOMBS",
+ "E2M6: THE LABYRINTH",
+ "E2M7: THE GREAT HALL",
+ "E2M8: THE PORTALS OF CHAOS",
+ "E2M9: THE GLACIER",
+ // EPISODE 3 - THE DOME OF D'SPARIL
+ "E3M1: THE STOREHOUSE",
+ "E3M2: THE CESSPOOL",
+ "E3M3: THE CONFLUENCE",
+ "E3M4: THE AZURE FORTRESS",
+ "E3M5: THE OPHIDIAN LAIR",
+ "E3M6: THE HALLS OF FEAR",
+ "E3M7: THE CHASM",
+ "E3M8: D'SPARIL'S KEEP",
+ "E3M9: THE AQUIFER",
+ // EPISODE 4: THE OSSUARY
+ "E4M1: CATAFALQUE",
+ "E4M2: BLOCKHOUSE",
+ "E4M3: AMBULATORY",
+ "E4M4: SEPULCHER",
+ "E4M5: GREAT STAIR",
+ "E4M6: HALLS OF THE APOSTATE",
+ "E4M7: RAMPARTS OF PERDITION",
+ "E4M8: SHATTERED BRIDGE",
+ "E4M9: MAUSOLEUM",
+ // EPISODE 5: THE STAGNANT DEMESNE
+ "E5M1: OCHRE CLIFFS",
+ "E5M2: RAPIDS",
+ "E5M3: QUAY",
+ "E5M4: COURTYARD",
+ "E5M5: HYDRATYR",
+ "E5M6: COLONNADE",
+ "E5M7: FOETID MANSE",
+ "E5M8: FIELD OF JUDGEMENT",
+ "E5M9: SKEIN OF D'SPARIL"
+};
+
+static int cheating = 0;
+static int grid = 0;
+
+static int leveljuststarted = 1; // kluge until AM_LevelInit() is called
+
+boolean automapactive = false;
+static int finit_width = SCREENWIDTH;
+static int finit_height = SCREENHEIGHT - 42;
+static int f_x, f_y; // location of window on screen
+static int f_w, f_h; // size of window on screen
+static int lightlev; // used for funky strobing effect
+static byte *fb; // pseudo-frame buffer
+static int amclock;
+
+static mpoint_t m_paninc; // how far the window pans each tic (map coords)
+static fixed_t mtof_zoommul; // how far the window zooms in each tic (map coords)
+static fixed_t ftom_zoommul; // how far the window zooms in each tic (fb coords)
+
+static fixed_t m_x, m_y; // LL x,y where the window is on the map (map coords)
+static fixed_t m_x2, m_y2; // UR x,y where the window is on the map (map coords)
+
+// width/height of window on map (map coords)
+static fixed_t m_w, m_h;
+static fixed_t min_x, min_y; // based on level size
+static fixed_t max_x, max_y; // based on level size
+static fixed_t max_w, max_h; // max_x-min_x, max_y-min_y
+static fixed_t min_w, min_h; // based on player size
+static fixed_t min_scale_mtof; // used to tell when to stop zooming out
+static fixed_t max_scale_mtof; // used to tell when to stop zooming in
+
+// old stuff for recovery later
+static fixed_t old_m_w, old_m_h;
+static fixed_t old_m_x, old_m_y;
+
+// old location used by the Follower routine
+static mpoint_t f_oldloc;
+
+// used by MTOF to scale from map-to-frame-buffer coords
+static fixed_t scale_mtof = (fixed_t)INITSCALEMTOF;
+// used by FTOM to scale from frame-buffer-to-map coords (=1/scale_mtof)
+static fixed_t scale_ftom;
+
+static player_t *plr; // the player represented by an arrow
+static vertex_t oldplr;
+
+//static patch_t *marknums[10]; // numbers used for marking by the automap
+//static mpoint_t markpoints[AM_NUMMARKPOINTS]; // where the points are
+//static int markpointnum = 0; // next point to be assigned
+
+static int followplayer = 1; // specifies whether to follow the player around
+
+static char cheat_amap[] = { 'r', 'a', 'v', 'm', 'a', 'p' };
+
+static byte cheatcount = 0;
+
+extern boolean viewactive;
+
+static byte antialias[NUMALIAS][8] = {
+ {96, 97, 98, 99, 100, 101, 102, 103},
+ {110, 109, 108, 107, 106, 105, 104, 103},
+ {75, 76, 77, 78, 79, 80, 81, 103}
+};
+
+/*
+static byte *aliasmax[NUMALIAS] = {
+ &antialias[0][7], &antialias[1][7], &antialias[2][7]
+};*/
+
+static byte *maplump; // pointer to the raw data for the automap background.
+static short mapystart = 0; // y-value for the start of the map bitmap...used in the paralax stuff.
+static short mapxstart = 0; //x-value for the bitmap.
+
+//byte screens[][SCREENWIDTH*SCREENHEIGHT];
+//void V_MarkRect (int x, int y, int width, int height);
+
+// Functions
+
+void DrawWuLine(int X0, int Y0, int X1, int Y1, byte * BaseColor,
+ int NumLevels, unsigned short IntensityBits);
+
+// Calculates the slope and slope according to the x-axis of a line
+// segment in map coordinates (with the upright y-axis n' all) so
+// that it can be used with the brain-dead drawing stuff.
+
+// Ripped out for Heretic
+/*
+void AM_getIslope(mline_t *ml, islope_t *is)
+{
+ int dx, dy;
+
+ dy = ml->a.y - ml->b.y;
+ dx = ml->b.x - ml->a.x;
+ if (!dy) is->islp = (dx<0?-INT_MAX:INT_MAX);
+ else is->islp = FixedDiv(dx, dy);
+ if (!dx) is->slp = (dy<0?-INT_MAX:INT_MAX);
+ else is->slp = FixedDiv(dy, dx);
+}
+*/
+
+void AM_activateNewScale(void)
+{
+ m_x += m_w / 2;
+ m_y += m_h / 2;
+ m_w = FTOM(f_w);
+ m_h = FTOM(f_h);
+ m_x -= m_w / 2;
+ m_y -= m_h / 2;
+ m_x2 = m_x + m_w;
+ m_y2 = m_y + m_h;
+}
+
+void AM_saveScaleAndLoc(void)
+{
+ old_m_x = m_x;
+ old_m_y = m_y;
+ old_m_w = m_w;
+ old_m_h = m_h;
+}
+
+void AM_restoreScaleAndLoc(void)
+{
+
+ m_w = old_m_w;
+ m_h = old_m_h;
+ if (!followplayer)
+ {
+ m_x = old_m_x;
+ m_y = old_m_y;
+ }
+ else
+ {
+ m_x = plr->mo->x - m_w / 2;
+ m_y = plr->mo->y - m_h / 2;
+ }
+ m_x2 = m_x + m_w;
+ m_y2 = m_y + m_h;
+
+ // Change the scaling multipliers
+ scale_mtof = FixedDiv(f_w << FRACBITS, m_w);
+ scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+}
+
+// adds a marker at the current location
+
+/*
+void AM_addMark(void)
+{
+ markpoints[markpointnum].x = m_x + m_w/2;
+ markpoints[markpointnum].y = m_y + m_h/2;
+ markpointnum = (markpointnum + 1) % AM_NUMMARKPOINTS;
+
+}
+*/
+void AM_findMinMaxBoundaries(void)
+{
+ int i;
+ fixed_t a, b;
+
+ min_x = min_y = INT_MAX;
+ max_x = max_y = -INT_MAX;
+ for (i = 0; i < numvertexes; i++)
+ {
+ if (vertexes[i].x < min_x)
+ min_x = vertexes[i].x;
+ else if (vertexes[i].x > max_x)
+ max_x = vertexes[i].x;
+ if (vertexes[i].y < min_y)
+ min_y = vertexes[i].y;
+ else if (vertexes[i].y > max_y)
+ max_y = vertexes[i].y;
+ }
+ max_w = max_x - min_x;
+ max_h = max_y - min_y;
+ min_w = 2 * PLAYERRADIUS;
+ min_h = 2 * PLAYERRADIUS;
+
+ a = FixedDiv(f_w << FRACBITS, max_w);
+ b = FixedDiv(f_h << FRACBITS, max_h);
+ min_scale_mtof = a < b ? a : b;
+
+ max_scale_mtof = FixedDiv(f_h << FRACBITS, 2 * PLAYERRADIUS);
+
+}
+
+void AM_changeWindowLoc(void)
+{
+ if (m_paninc.x || m_paninc.y)
+ {
+ followplayer = 0;
+ f_oldloc.x = INT_MAX;
+ }
+
+ m_x += m_paninc.x;
+ m_y += m_paninc.y;
+
+ if (m_x + m_w / 2 > max_x)
+ {
+ m_x = max_x - m_w / 2;
+ m_paninc.x = 0;
+ }
+ else if (m_x + m_w / 2 < min_x)
+ {
+ m_x = min_x - m_w / 2;
+ m_paninc.x = 0;
+ }
+ if (m_y + m_h / 2 > max_y)
+ {
+ m_y = max_y - m_h / 2;
+ m_paninc.y = 0;
+ }
+ else if (m_y + m_h / 2 < min_y)
+ {
+ m_y = min_y - m_h / 2;
+ m_paninc.y = 0;
+ }
+/*
+ mapxstart += MTOF(m_paninc.x+FRACUNIT/2);
+ mapystart -= MTOF(m_paninc.y+FRACUNIT/2);
+ if(mapxstart >= finit_width)
+ mapxstart -= finit_width;
+ if(mapxstart < 0)
+ mapxstart += finit_width;
+ if(mapystart >= finit_height)
+ mapystart -= finit_height;
+ if(mapystart < 0)
+ mapystart += finit_height;
+*/
+ m_x2 = m_x + m_w;
+ m_y2 = m_y + m_h;
+}
+
+void AM_initVariables(void)
+{
+ int pnum;
+ thinker_t *think;
+ mobj_t *mo;
+
+ //static event_t st_notify = { ev_keyup, AM_MSGENTERED };
+
+ automapactive = true;
+ fb = I_VideoBuffer;
+
+ f_oldloc.x = INT_MAX;
+ amclock = 0;
+ lightlev = 0;
+
+ m_paninc.x = m_paninc.y = 0;
+ ftom_zoommul = FRACUNIT;
+ mtof_zoommul = FRACUNIT;
+
+ m_w = FTOM(f_w);
+ m_h = FTOM(f_h);
+
+ // find player to center on initially
+ if (!playeringame[pnum = consoleplayer])
+ for (pnum = 0; pnum < MAXPLAYERS; pnum++)
+ if (playeringame[pnum])
+ break;
+ plr = &players[pnum];
+ oldplr.x = plr->mo->x;
+ oldplr.y = plr->mo->y;
+ m_x = plr->mo->x - m_w / 2;
+ m_y = plr->mo->y - m_h / 2;
+ AM_changeWindowLoc();
+
+ // for saving & restoring
+ old_m_x = m_x;
+ old_m_y = m_y;
+ old_m_w = m_w;
+ old_m_h = m_h;
+
+ // load in the location of keys, if in baby mode
+
+ memset(KeyPoints, 0, sizeof(vertex_t) * 3);
+ if (gameskill == sk_baby)
+ {
+ for (think = thinkercap.next; think != &thinkercap;
+ think = think->next)
+ {
+ if (think->function != P_MobjThinker)
+ { //not a mobj
+ continue;
+ }
+ mo = (mobj_t *) think;
+ if (mo->type == MT_CKEY)
+ {
+ KeyPoints[0].x = mo->x;
+ KeyPoints[0].y = mo->y;
+ }
+ else if (mo->type == MT_AKYY)
+ {
+ KeyPoints[1].x = mo->x;
+ KeyPoints[1].y = mo->y;
+ }
+ else if (mo->type == MT_BKYY)
+ {
+ KeyPoints[2].x = mo->x;
+ KeyPoints[2].y = mo->y;
+ }
+ }
+ }
+
+ // inform the status bar of the change
+//c ST_Responder(&st_notify);
+}
+
+void AM_loadPics(void)
+{
+ //int i;
+ //char namebuf[9];
+/* for (i=0;i<10;i++)
+ {
+ sprintf(namebuf, "AMMNUM%d", i);
+ marknums[i] = W_CacheLumpName(namebuf, PU_STATIC);
+ }*/
+ maplump = W_CacheLumpName(DEH_String("AUTOPAGE"), PU_STATIC);
+}
+
+/*void AM_unloadPics(void)
+{
+ int i;
+ for (i=0;i<10;i++) Z_ChangeTag(marknums[i], PU_CACHE);
+
+}*/
+
+/*
+void AM_clearMarks(void)
+{
+ int i;
+ for (i=0;i<AM_NUMMARKPOINTS;i++) markpoints[i].x = -1; // means empty
+ markpointnum = 0;
+}
+*/
+
+// should be called at the start of every level
+// right now, i figure it out myself
+
+void AM_LevelInit(void)
+{
+ leveljuststarted = 0;
+
+ f_x = f_y = 0;
+ f_w = finit_width;
+ f_h = finit_height;
+ mapxstart = mapystart = 0;
+
+
+// AM_clearMarks();
+
+ AM_findMinMaxBoundaries();
+ scale_mtof = FixedDiv(min_scale_mtof, (int) (0.7 * FRACUNIT));
+ if (scale_mtof > max_scale_mtof)
+ scale_mtof = min_scale_mtof;
+ scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+}
+
+static boolean stopped = true;
+
+void AM_Stop(void)
+{
+ //static event_t st_notify = { 0, ev_keyup, AM_MSGEXITED };
+
+// AM_unloadPics();
+ automapactive = false;
+// ST_Responder(&st_notify);
+ stopped = true;
+ BorderNeedRefresh = true;
+}
+
+void AM_Start(void)
+{
+ static int lastlevel = -1, lastepisode = -1;
+
+ if (!stopped)
+ AM_Stop();
+ stopped = false;
+ if (gamestate != GS_LEVEL)
+ {
+ return; // don't show automap if we aren't in a game!
+ }
+ if (lastlevel != gamemap || lastepisode != gameepisode)
+ {
+ AM_LevelInit();
+ lastlevel = gamemap;
+ lastepisode = gameepisode;
+ }
+ AM_initVariables();
+ AM_loadPics();
+}
+
+// set the window scale to the maximum size
+
+void AM_minOutWindowScale(void)
+{
+ scale_mtof = min_scale_mtof;
+ scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+ AM_activateNewScale();
+}
+
+// set the window scale to the minimum size
+
+void AM_maxOutWindowScale(void)
+{
+ scale_mtof = max_scale_mtof;
+ scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+ AM_activateNewScale();
+}
+
+boolean AM_Responder(event_t * ev)
+{
+ int rc;
+ int key;
+ static int bigstate = 0;
+
+ key = ev->data1;
+ rc = false;
+
+ if (!automapactive)
+ {
+
+ if (ev->type == ev_keydown && key == key_map_toggle
+ && gamestate == GS_LEVEL)
+ {
+ AM_Start();
+ viewactive = false;
+ // viewactive = true;
+ rc = true;
+ }
+ }
+ else if (ev->type == ev_keydown)
+ {
+ rc = true;
+
+ if (key == key_map_east) // pan right
+ {
+ if (!followplayer)
+ m_paninc.x = FTOM(F_PANINC);
+ else
+ rc = false;
+ }
+ else if (key == key_map_west) // pan left
+ {
+ if (!followplayer)
+ m_paninc.x = -FTOM(F_PANINC);
+ else
+ rc = false;
+ }
+ else if (key == key_map_north) // pan up
+ {
+ if (!followplayer)
+ m_paninc.y = FTOM(F_PANINC);
+ else
+ rc = false;
+ }
+ else if (key == key_map_south) // pan down
+ {
+ if (!followplayer)
+ m_paninc.y = -FTOM(F_PANINC);
+ else
+ rc = false;
+ }
+ else if (key == key_map_zoomout) // zoom out
+ {
+ mtof_zoommul = M_ZOOMOUT;
+ ftom_zoommul = M_ZOOMIN;
+ }
+ else if (key == key_map_zoomin) // zoom in
+ {
+ mtof_zoommul = M_ZOOMIN;
+ ftom_zoommul = M_ZOOMOUT;
+ }
+ else if (key == key_map_toggle) // toggle map (tab)
+ {
+ bigstate = 0;
+ viewactive = true;
+ AM_Stop();
+ }
+ else if (key == key_map_maxzoom)
+ {
+ bigstate = !bigstate;
+ if (bigstate)
+ {
+ AM_saveScaleAndLoc();
+ AM_minOutWindowScale();
+ }
+ else
+ AM_restoreScaleAndLoc();
+ }
+ else if (key == key_map_follow)
+ {
+ followplayer = !followplayer;
+ f_oldloc.x = INT_MAX;
+ P_SetMessage(plr,
+ followplayer ? AMSTR_FOLLOWON : AMSTR_FOLLOWOFF,
+ true);
+ }
+ /*
+ else if (key == key_map_grid)
+ {
+ grid = !grid;
+ plr->message = grid ? AMSTR_GRIDON : AMSTR_GRIDOFF;
+ }
+ else if (key == key_map_mark)
+ {
+ sprintf(buffer, "%s %d", AMSTR_MARKEDSPOT, markpointnum);
+ plr->message = buffer;
+ AM_addMark();
+ }
+ else if (key == key_map_clearmark)
+ {
+ AM_clearMarks();
+ plr->message = AMSTR_MARKSCLEARED;
+ }
+ */
+ else
+ {
+ rc = false;
+ }
+
+ if (cheat_amap[cheatcount] == ev->data1 && !netgame)
+ cheatcount++;
+ else
+ cheatcount = 0;
+ if (cheatcount == 6)
+ {
+ cheatcount = 0;
+ rc = false;
+ cheating = (cheating + 1) % 3;
+ }
+ }
+
+ else if (ev->type == ev_keyup)
+ {
+ rc = false;
+
+ if (key == key_map_east)
+ {
+ if (!followplayer)
+ m_paninc.x = 0;
+ }
+ else if (key == key_map_east)
+ {
+ if (!followplayer)
+ m_paninc.x = 0;
+ }
+ else if (key == key_map_north)
+ {
+ if (!followplayer)
+ m_paninc.y = 0;
+ }
+ else if (key == key_map_south)
+ {
+ if (!followplayer)
+ m_paninc.y = 0;
+ }
+ else if (key == key_map_zoomout || key == key_map_zoomin)
+ {
+ mtof_zoommul = FRACUNIT;
+ ftom_zoommul = FRACUNIT;
+ }
+ }
+
+ return rc;
+
+}
+
+void AM_changeWindowScale(void)
+{
+
+ // Change the scaling multipliers
+ scale_mtof = FixedMul(scale_mtof, mtof_zoommul);
+ scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+
+ if (scale_mtof < min_scale_mtof)
+ AM_minOutWindowScale();
+ else if (scale_mtof > max_scale_mtof)
+ AM_maxOutWindowScale();
+ else
+ AM_activateNewScale();
+}
+
+void AM_doFollowPlayer(void)
+{
+ if (f_oldloc.x != plr->mo->x || f_oldloc.y != plr->mo->y)
+ {
+// m_x = FTOM(MTOF(plr->mo->x - m_w/2));
+// m_y = FTOM(MTOF(plr->mo->y - m_h/2));
+// m_x = plr->mo->x - m_w/2;
+// m_y = plr->mo->y - m_h/2;
+ m_x = FTOM(MTOF(plr->mo->x)) - m_w / 2;
+ m_y = FTOM(MTOF(plr->mo->y)) - m_h / 2;
+ m_x2 = m_x + m_w;
+ m_y2 = m_y + m_h;
+
+ // do the parallax parchment scrolling.
+/*
+ dmapx = (MTOF(plr->mo->x)-MTOF(f_oldloc.x)); //fixed point
+ dmapy = (MTOF(f_oldloc.y)-MTOF(plr->mo->y));
+
+ if(f_oldloc.x == INT_MAX) //to eliminate an error when the user first
+ dmapx=0; //goes into the automap.
+ mapxstart += dmapx;
+ mapystart += dmapy;
+
+ while(mapxstart >= finit_width)
+ mapxstart -= finit_width;
+ while(mapxstart < 0)
+ mapxstart += finit_width;
+ while(mapystart >= finit_height)
+ mapystart -= finit_height;
+ while(mapystart < 0)
+ mapystart += finit_height;
+*/
+ f_oldloc.x = plr->mo->x;
+ f_oldloc.y = plr->mo->y;
+ }
+}
+
+// Ripped out for Heretic
+/*
+void AM_updateLightLev(void)
+{
+ static nexttic = 0;
+//static int litelevels[] = { 0, 3, 5, 6, 6, 7, 7, 7 };
+ static int litelevels[] = { 0, 4, 7, 10, 12, 14, 15, 15 };
+ static int litelevelscnt = 0;
+
+ // Change light level
+ if (amclock>nexttic)
+ {
+ lightlev = litelevels[litelevelscnt++];
+ if (litelevelscnt == sizeof(litelevels)/sizeof(int)) litelevelscnt = 0;
+ nexttic = amclock + 6 - (amclock % 6);
+ }
+}
+*/
+
+void AM_Ticker(void)
+{
+
+ if (!automapactive)
+ return;
+
+ amclock++;
+
+ if (followplayer)
+ AM_doFollowPlayer();
+
+ // Change the zoom if necessary
+ if (ftom_zoommul != FRACUNIT)
+ AM_changeWindowScale();
+
+ // Change x,y location
+ if (m_paninc.x || m_paninc.y)
+ AM_changeWindowLoc();
+ // Update light level
+// AM_updateLightLev();
+
+}
+
+void AM_clearFB(int color)
+{
+ int i, j;
+ int dmapx;
+ int dmapy;
+
+ if (followplayer)
+ {
+ dmapx = (MTOF(plr->mo->x) - MTOF(oldplr.x)); //fixed point
+ dmapy = (MTOF(oldplr.y) - MTOF(plr->mo->y));
+
+ oldplr.x = plr->mo->x;
+ oldplr.y = plr->mo->y;
+// if(f_oldloc.x == INT_MAX) //to eliminate an error when the user first
+// dmapx=0; //goes into the automap.
+ mapxstart += dmapx >> 1;
+ mapystart += dmapy >> 1;
+
+ while (mapxstart >= finit_width)
+ mapxstart -= finit_width;
+ while (mapxstart < 0)
+ mapxstart += finit_width;
+ while (mapystart >= finit_height)
+ mapystart -= finit_height;
+ while (mapystart < 0)
+ mapystart += finit_height;
+ }
+ else
+ {
+ mapxstart += (MTOF(m_paninc.x) >> 1);
+ mapystart -= (MTOF(m_paninc.y) >> 1);
+ if (mapxstart >= finit_width)
+ mapxstart -= finit_width;
+ if (mapxstart < 0)
+ mapxstart += finit_width;
+ if (mapystart >= finit_height)
+ mapystart -= finit_height;
+ if (mapystart < 0)
+ mapystart += finit_height;
+ }
+
+ //blit the automap background to the screen.
+ j = mapystart * finit_width;
+ for (i = 0; i < finit_height; i++)
+ {
+ memcpy(I_VideoBuffer + i * finit_width, maplump + j + mapxstart,
+ finit_width - mapxstart);
+ memcpy(I_VideoBuffer + i * finit_width + finit_width - mapxstart,
+ maplump + j, mapxstart);
+ j += finit_width;
+ if (j >= finit_height * finit_width)
+ j = 0;
+ }
+
+// memcpy(I_VideoBuffer, maplump, finit_width*finit_height);
+// memset(fb, color, f_w*f_h);
+}
+
+// Based on Cohen-Sutherland clipping algorithm but with a slightly
+// faster reject and precalculated slopes. If I need the speed, will
+// hash algorithm to the common cases.
+
+boolean AM_clipMline(mline_t * ml, fline_t * fl)
+{
+ enum
+ { LEFT = 1, RIGHT = 2, BOTTOM = 4, TOP = 8 };
+ int outcode1 = 0, outcode2 = 0, outside;
+ fpoint_t tmp = { 0, 0 };
+ int dx, dy;
+
+#define DOOUTCODE(oc, mx, my) \
+ (oc) = 0; \
+ if ((my) < 0) (oc) |= TOP; \
+ else if ((my) >= f_h) (oc) |= BOTTOM; \
+ if ((mx) < 0) (oc) |= LEFT; \
+ else if ((mx) >= f_w) (oc) |= RIGHT
+
+ // do trivial rejects and outcodes
+ if (ml->a.y > m_y2)
+ outcode1 = TOP;
+ else if (ml->a.y < m_y)
+ outcode1 = BOTTOM;
+ if (ml->b.y > m_y2)
+ outcode2 = TOP;
+ else if (ml->b.y < m_y)
+ outcode2 = BOTTOM;
+ if (outcode1 & outcode2)
+ return false; // trivially outside
+
+ if (ml->a.x < m_x)
+ outcode1 |= LEFT;
+ else if (ml->a.x > m_x2)
+ outcode1 |= RIGHT;
+ if (ml->b.x < m_x)
+ outcode2 |= LEFT;
+ else if (ml->b.x > m_x2)
+ outcode2 |= RIGHT;
+ if (outcode1 & outcode2)
+ return false; // trivially outside
+
+ // transform to frame-buffer coordinates.
+ fl->a.x = CXMTOF(ml->a.x);
+ fl->a.y = CYMTOF(ml->a.y);
+ fl->b.x = CXMTOF(ml->b.x);
+ fl->b.y = CYMTOF(ml->b.y);
+ DOOUTCODE(outcode1, fl->a.x, fl->a.y);
+ DOOUTCODE(outcode2, fl->b.x, fl->b.y);
+ if (outcode1 & outcode2)
+ return false;
+
+ while (outcode1 | outcode2)
+ {
+ // may be partially inside box
+ // find an outside point
+ if (outcode1)
+ outside = outcode1;
+ else
+ outside = outcode2;
+ // clip to each side
+ if (outside & TOP)
+ {
+ dy = fl->a.y - fl->b.y;
+ dx = fl->b.x - fl->a.x;
+ tmp.x = fl->a.x + (dx * (fl->a.y)) / dy;
+ tmp.y = 0;
+ }
+ else if (outside & BOTTOM)
+ {
+ dy = fl->a.y - fl->b.y;
+ dx = fl->b.x - fl->a.x;
+ tmp.x = fl->a.x + (dx * (fl->a.y - f_h)) / dy;
+ tmp.y = f_h - 1;
+ }
+ else if (outside & RIGHT)
+ {
+ dy = fl->b.y - fl->a.y;
+ dx = fl->b.x - fl->a.x;
+ tmp.y = fl->a.y + (dy * (f_w - 1 - fl->a.x)) / dx;
+ tmp.x = f_w - 1;
+ }
+ else if (outside & LEFT)
+ {
+ dy = fl->b.y - fl->a.y;
+ dx = fl->b.x - fl->a.x;
+ tmp.y = fl->a.y + (dy * (-fl->a.x)) / dx;
+ tmp.x = 0;
+ }
+ if (outside == outcode1)
+ {
+ fl->a = tmp;
+ DOOUTCODE(outcode1, fl->a.x, fl->a.y);
+ }
+ else
+ {
+ fl->b = tmp;
+ DOOUTCODE(outcode2, fl->b.x, fl->b.y);
+ }
+ if (outcode1 & outcode2)
+ return false; // trivially outside
+ }
+
+ return true;
+}
+
+#undef DOOUTCODE
+
+// Classic Bresenham w/ whatever optimizations I need for speed
+
+void AM_drawFline(fline_t * fl, int color)
+{
+
+ register int x, y, dx, dy, sx, sy, ax, ay, d;
+ static int fuck = 0;
+
+ switch (color)
+ {
+ case WALLCOLORS:
+ DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y, &antialias[0][0],
+ 8, 3);
+ break;
+ case FDWALLCOLORS:
+ DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y, &antialias[1][0],
+ 8, 3);
+ break;
+ case CDWALLCOLORS:
+ DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y, &antialias[2][0],
+ 8, 3);
+ break;
+ default:
+ {
+ // For debugging only
+ if (fl->a.x < 0 || fl->a.x >= f_w
+ || fl->a.y < 0 || fl->a.y >= f_h
+ || fl->b.x < 0 || fl->b.x >= f_w
+ || fl->b.y < 0 || fl->b.y >= f_h)
+ {
+ fprintf(stderr, "fuck %d \r", fuck++);
+ return;
+ }
+
+#define DOT(xx,yy,cc) fb[(yy)*f_w+(xx)]=(cc) //the MACRO!
+
+ dx = fl->b.x - fl->a.x;
+ ax = 2 * (dx < 0 ? -dx : dx);
+ sx = dx < 0 ? -1 : 1;
+
+ dy = fl->b.y - fl->a.y;
+ ay = 2 * (dy < 0 ? -dy : dy);
+ sy = dy < 0 ? -1 : 1;
+
+ x = fl->a.x;
+ y = fl->a.y;
+
+ if (ax > ay)
+ {
+ d = ay - ax / 2;
+ while (1)
+ {
+ DOT(x, y, color);
+ if (x == fl->b.x)
+ return;
+ if (d >= 0)
+ {
+ y += sy;
+ d -= ax;
+ }
+ x += sx;
+ d += ay;
+ }
+ }
+ else
+ {
+ d = ax - ay / 2;
+ while (1)
+ {
+ DOT(x, y, color);
+ if (y == fl->b.y)
+ return;
+ if (d >= 0)
+ {
+ x += sx;
+ d -= ay;
+ }
+ y += sy;
+ d += ax;
+ }
+ }
+ }
+ }
+}
+
+/* Wu antialiased line drawer.
+ * (X0,Y0),(X1,Y1) = line to draw
+ * BaseColor = color # of first color in block used for antialiasing, the
+ * 100% intensity version of the drawing color
+ * NumLevels = size of color block, with BaseColor+NumLevels-1 being the
+ * 0% intensity version of the drawing color
+ * IntensityBits = log base 2 of NumLevels; the # of bits used to describe
+ * the intensity of the drawing color. 2**IntensityBits==NumLevels
+ */
+void PUTDOT(short xx, short yy, byte * cc, byte * cm)
+{
+ static int oldyy;
+ static int oldyyshifted;
+ byte *oldcc = cc;
+
+ if (xx < 32)
+ cc += 7 - (xx >> 2);
+ else if (xx > (finit_width - 32))
+ cc += 7 - ((finit_width - xx) >> 2);
+// if(cc==oldcc) //make sure that we don't double fade the corners.
+// {
+ if (yy < 32)
+ cc += 7 - (yy >> 2);
+ else if (yy > (finit_height - 32))
+ cc += 7 - ((finit_height - yy) >> 2);
+// }
+ if (cc > cm && cm != NULL)
+ {
+ cc = cm;
+ }
+ else if (cc > oldcc + 6) // don't let the color escape from the fade table...
+ {
+ cc = oldcc + 6;
+ }
+ if (yy == oldyy + 1)
+ {
+ oldyy++;
+ oldyyshifted += 320;
+ }
+ else if (yy == oldyy - 1)
+ {
+ oldyy--;
+ oldyyshifted -= 320;
+ }
+ else if (yy != oldyy)
+ {
+ oldyy = yy;
+ oldyyshifted = yy * 320;
+ }
+ fb[oldyyshifted + xx] = *(cc);
+// fb[(yy)*f_w+(xx)]=*(cc);
+}
+
+void DrawWuLine(int X0, int Y0, int X1, int Y1, byte * BaseColor,
+ int NumLevels, unsigned short IntensityBits)
+{
+ unsigned short IntensityShift, ErrorAdj, ErrorAcc;
+ unsigned short ErrorAccTemp, Weighting, WeightingComplementMask;
+ short DeltaX, DeltaY, Temp, XDir;
+
+ /* Make sure the line runs top to bottom */
+ if (Y0 > Y1)
+ {
+ Temp = Y0;
+ Y0 = Y1;
+ Y1 = Temp;
+ Temp = X0;
+ X0 = X1;
+ X1 = Temp;
+ }
+ /* Draw the initial pixel, which is always exactly intersected by
+ the line and so needs no weighting */
+ PUTDOT(X0, Y0, &BaseColor[0], NULL);
+
+ if ((DeltaX = X1 - X0) >= 0)
+ {
+ XDir = 1;
+ }
+ else
+ {
+ XDir = -1;
+ DeltaX = -DeltaX; /* make DeltaX positive */
+ }
+ /* Special-case horizontal, vertical, and diagonal lines, which
+ require no weighting because they go right through the center of
+ every pixel */
+ if ((DeltaY = Y1 - Y0) == 0)
+ {
+ /* Horizontal line */
+ while (DeltaX-- != 0)
+ {
+ X0 += XDir;
+ PUTDOT(X0, Y0, &BaseColor[0], NULL);
+ }
+ return;
+ }
+ if (DeltaX == 0)
+ {
+ /* Vertical line */
+ do
+ {
+ Y0++;
+ PUTDOT(X0, Y0, &BaseColor[0], NULL);
+ }
+ while (--DeltaY != 0);
+ return;
+ }
+ //diagonal line.
+ if (DeltaX == DeltaY)
+ {
+ do
+ {
+ X0 += XDir;
+ Y0++;
+ PUTDOT(X0, Y0, &BaseColor[0], NULL);
+ }
+ while (--DeltaY != 0);
+ return;
+ }
+ /* Line is not horizontal, diagonal, or vertical */
+ ErrorAcc = 0; /* initialize the line error accumulator to 0 */
+ /* # of bits by which to shift ErrorAcc to get intensity level */
+ IntensityShift = 16 - IntensityBits;
+ /* Mask used to flip all bits in an intensity weighting, producing the
+ result (1 - intensity weighting) */
+ WeightingComplementMask = NumLevels - 1;
+ /* Is this an X-major or Y-major line? */
+ if (DeltaY > DeltaX)
+ {
+ /* Y-major line; calculate 16-bit fixed-point fractional part of a
+ pixel that X advances each time Y advances 1 pixel, truncating the
+ result so that we won't overrun the endpoint along the X axis */
+ ErrorAdj = ((unsigned int) DeltaX << 16) / (unsigned int) DeltaY;
+ /* Draw all pixels other than the first and last */
+ while (--DeltaY)
+ {
+ ErrorAccTemp = ErrorAcc; /* remember currrent accumulated error */
+ ErrorAcc += ErrorAdj; /* calculate error for next pixel */
+ if (ErrorAcc <= ErrorAccTemp)
+ {
+ /* The error accumulator turned over, so advance the X coord */
+ X0 += XDir;
+ }
+ Y0++; /* Y-major, so always advance Y */
+ /* The IntensityBits most significant bits of ErrorAcc give us the
+ intensity weighting for this pixel, and the complement of the
+ weighting for the paired pixel */
+ Weighting = ErrorAcc >> IntensityShift;
+ PUTDOT(X0, Y0, &BaseColor[Weighting], &BaseColor[7]);
+ PUTDOT(X0 + XDir, Y0,
+ &BaseColor[(Weighting ^ WeightingComplementMask)],
+ &BaseColor[7]);
+ }
+ /* Draw the final pixel, which is always exactly intersected by the line
+ and so needs no weighting */
+ PUTDOT(X1, Y1, &BaseColor[0], NULL);
+ return;
+ }
+ /* It's an X-major line; calculate 16-bit fixed-point fractional part of a
+ pixel that Y advances each time X advances 1 pixel, truncating the
+ result to avoid overrunning the endpoint along the X axis */
+ ErrorAdj = ((unsigned int) DeltaY << 16) / (unsigned int) DeltaX;
+ /* Draw all pixels other than the first and last */
+ while (--DeltaX)
+ {
+ ErrorAccTemp = ErrorAcc; /* remember currrent accumulated error */
+ ErrorAcc += ErrorAdj; /* calculate error for next pixel */
+ if (ErrorAcc <= ErrorAccTemp)
+ {
+ /* The error accumulator turned over, so advance the Y coord */
+ Y0++;
+ }
+ X0 += XDir; /* X-major, so always advance X */
+ /* The IntensityBits most significant bits of ErrorAcc give us the
+ intensity weighting for this pixel, and the complement of the
+ weighting for the paired pixel */
+ Weighting = ErrorAcc >> IntensityShift;
+ PUTDOT(X0, Y0, &BaseColor[Weighting], &BaseColor[7]);
+ PUTDOT(X0, Y0 + 1,
+ &BaseColor[(Weighting ^ WeightingComplementMask)],
+ &BaseColor[7]);
+
+ }
+ /* Draw the final pixel, which is always exactly intersected by the line
+ and so needs no weighting */
+ PUTDOT(X1, Y1, &BaseColor[0], NULL);
+}
+
+void AM_drawMline(mline_t * ml, int color)
+{
+ static fline_t fl;
+
+ if (AM_clipMline(ml, &fl))
+ AM_drawFline(&fl, color); // draws it on frame buffer using fb coords
+
+}
+
+void AM_drawGrid(int color)
+{
+ fixed_t x, y;
+ fixed_t start, end;
+ mline_t ml;
+
+ // Figure out start of vertical gridlines
+ start = m_x;
+ if ((start - bmaporgx) % (MAPBLOCKUNITS << FRACBITS))
+ start += (MAPBLOCKUNITS << FRACBITS)
+ - ((start - bmaporgx) % (MAPBLOCKUNITS << FRACBITS));
+ end = m_x + m_w;
+
+ // draw vertical gridlines
+ ml.a.y = m_y;
+ ml.b.y = m_y + m_h;
+ for (x = start; x < end; x += (MAPBLOCKUNITS << FRACBITS))
+ {
+ ml.a.x = x;
+ ml.b.x = x;
+ AM_drawMline(&ml, color);
+ }
+
+ // Figure out start of horizontal gridlines
+ start = m_y;
+ if ((start - bmaporgy) % (MAPBLOCKUNITS << FRACBITS))
+ start += (MAPBLOCKUNITS << FRACBITS)
+ - ((start - bmaporgy) % (MAPBLOCKUNITS << FRACBITS));
+ end = m_y + m_h;
+
+ // draw horizontal gridlines
+ ml.a.x = m_x;
+ ml.b.x = m_x + m_w;
+ for (y = start; y < end; y += (MAPBLOCKUNITS << FRACBITS))
+ {
+ ml.a.y = y;
+ ml.b.y = y;
+ AM_drawMline(&ml, color);
+ }
+}
+
+void AM_drawWalls(void)
+{
+ int i;
+ static mline_t l;
+
+ for (i = 0; i < numlines; i++)
+ {
+ l.a.x = lines[i].v1->x;
+ l.a.y = lines[i].v1->y;
+ l.b.x = lines[i].v2->x;
+ l.b.y = lines[i].v2->y;
+ if (cheating || (lines[i].flags & ML_MAPPED))
+ {
+ if ((lines[i].flags & LINE_NEVERSEE) && !cheating)
+ continue;
+ if (!lines[i].backsector)
+ {
+ AM_drawMline(&l, WALLCOLORS + lightlev);
+ }
+ else
+ {
+ if (lines[i].special == 39)
+ { // teleporters
+ AM_drawMline(&l, WALLCOLORS + WALLRANGE / 2);
+ }
+ else if (lines[i].flags & ML_SECRET) // secret door
+ {
+ if (cheating)
+ AM_drawMline(&l, 0);
+ else
+ AM_drawMline(&l, WALLCOLORS + lightlev);
+ }
+ else if (lines[i].special > 25 && lines[i].special < 35)
+ {
+ switch (lines[i].special)
+ {
+ case 26:
+ case 32:
+ AM_drawMline(&l, BLUEKEY);
+ break;
+ case 27:
+ case 34:
+ AM_drawMline(&l, YELLOWKEY);
+ break;
+ case 28:
+ case 33:
+ AM_drawMline(&l, GREENKEY);
+ break;
+ default:
+ break;
+ }
+ }
+ else if (lines[i].backsector->floorheight
+ != lines[i].frontsector->floorheight)
+ {
+ AM_drawMline(&l, FDWALLCOLORS + lightlev); // floor level change
+ }
+ else if (lines[i].backsector->ceilingheight
+ != lines[i].frontsector->ceilingheight)
+ {
+ AM_drawMline(&l, CDWALLCOLORS + lightlev); // ceiling level change
+ }
+ else if (cheating)
+ {
+ AM_drawMline(&l, TSWALLCOLORS + lightlev);
+ }
+ }
+ }
+ else if (plr->powers[pw_allmap])
+ {
+ if (!(lines[i].flags & LINE_NEVERSEE))
+ AM_drawMline(&l, GRAYS + 3);
+ }
+ }
+
+}
+
+void AM_rotate(fixed_t * x, fixed_t * y, angle_t a)
+{
+ fixed_t tmpx;
+
+ tmpx = FixedMul(*x, finecosine[a >> ANGLETOFINESHIFT])
+ - FixedMul(*y, finesine[a >> ANGLETOFINESHIFT]);
+ *y = FixedMul(*x, finesine[a >> ANGLETOFINESHIFT])
+ + FixedMul(*y, finecosine[a >> ANGLETOFINESHIFT]);
+ *x = tmpx;
+}
+
+void AM_drawLineCharacter(mline_t * lineguy, int lineguylines, fixed_t scale,
+ angle_t angle, int color, fixed_t x, fixed_t y)
+{
+ int i;
+ mline_t l;
+
+ for (i = 0; i < lineguylines; i++)
+ {
+ l.a.x = lineguy[i].a.x;
+ l.a.y = lineguy[i].a.y;
+ if (scale)
+ {
+ l.a.x = FixedMul(scale, l.a.x);
+ l.a.y = FixedMul(scale, l.a.y);
+ }
+ if (angle)
+ AM_rotate(&l.a.x, &l.a.y, angle);
+ l.a.x += x;
+ l.a.y += y;
+
+ l.b.x = lineguy[i].b.x;
+ l.b.y = lineguy[i].b.y;
+ if (scale)
+ {
+ l.b.x = FixedMul(scale, l.b.x);
+ l.b.y = FixedMul(scale, l.b.y);
+ }
+ if (angle)
+ AM_rotate(&l.b.x, &l.b.y, angle);
+ l.b.x += x;
+ l.b.y += y;
+
+ AM_drawMline(&l, color);
+ }
+
+}
+
+void AM_drawPlayers(void)
+{
+
+ int i;
+ player_t *p;
+ static int their_colors[] = { GREENKEY, YELLOWKEY, BLOODRED, BLUEKEY };
+ int their_color = -1;
+ int color;
+
+ if (!netgame)
+ {
+ /*
+ if (cheating) AM_drawLineCharacter(cheat_player_arrow, NUMCHEATPLYRLINES, 0,
+ plr->mo->angle, WHITE, plr->mo->x, plr->mo->y);
+ *///cheat key player pointer is the same as non-cheat pointer..
+
+ AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 0, plr->mo->angle,
+ WHITE, plr->mo->x, plr->mo->y);
+ return;
+ }
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ their_color++;
+ p = &players[i];
+ if (deathmatch && !singledemo && p != plr)
+ {
+ continue;
+ }
+ if (!playeringame[i])
+ continue;
+ if (p->powers[pw_invisibility])
+ color = 102; // *close* to the automap color
+ else
+ color = their_colors[their_color];
+ AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 0, p->mo->angle,
+ color, p->mo->x, p->mo->y);
+ }
+}
+
+void AM_drawThings(int colors, int colorrange)
+{
+ int i;
+ mobj_t *t;
+
+ for (i = 0; i < numsectors; i++)
+ {
+ t = sectors[i].thinglist;
+ while (t)
+ {
+ AM_drawLineCharacter(thintriangle_guy, NUMTHINTRIANGLEGUYLINES,
+ 16 << FRACBITS, t->angle, colors + lightlev,
+ t->x, t->y);
+ t = t->snext;
+ }
+ }
+}
+
+/*
+void AM_drawMarks(void)
+{
+ int i, fx, fy, w, h;
+
+ for (i=0;i<AM_NUMMARKPOINTS;i++)
+ {
+ if (markpoints[i].x != -1)
+ {
+ w = SHORT(marknums[i]->width);
+ h = SHORT(marknums[i]->height);
+ fx = CXMTOF(markpoints[i].x);
+ fy = CYMTOF(markpoints[i].y);
+ if (fx >= f_x && fx <= f_w - w && fy >= f_y && fy <= f_h - h)
+ V_DrawPatch(fx, fy, marknums[i]);
+ }
+ }
+}
+*/
+
+void AM_drawkeys(void)
+{
+ if (KeyPoints[0].x != 0 || KeyPoints[0].y != 0)
+ {
+ AM_drawLineCharacter(keysquare, NUMKEYSQUARELINES, 0, 0, YELLOWKEY,
+ KeyPoints[0].x, KeyPoints[0].y);
+ }
+ if (KeyPoints[1].x != 0 || KeyPoints[1].y != 0)
+ {
+ AM_drawLineCharacter(keysquare, NUMKEYSQUARELINES, 0, 0, GREENKEY,
+ KeyPoints[1].x, KeyPoints[1].y);
+ }
+ if (KeyPoints[2].x != 0 || KeyPoints[2].y != 0)
+ {
+ AM_drawLineCharacter(keysquare, NUMKEYSQUARELINES, 0, 0, BLUEKEY,
+ KeyPoints[2].x, KeyPoints[2].y);
+ }
+}
+
+void AM_drawCrosshair(int color)
+{
+ fb[(f_w * (f_h + 1)) / 2] = color; // single point for now
+}
+
+void AM_Drawer(void)
+{
+ char *level_name;
+ int numepisodes;
+
+ if (!automapactive)
+ return;
+
+ UpdateState |= I_FULLSCRN;
+ AM_clearFB(BACKGROUND);
+ if (grid)
+ AM_drawGrid(GRIDCOLORS);
+ AM_drawWalls();
+ AM_drawPlayers();
+ if (cheating == 2)
+ AM_drawThings(THINGCOLORS, THINGRANGE);
+// AM_drawCrosshair(XHAIRCOLORS);
+
+// AM_drawMarks();
+ if (gameskill == sk_baby)
+ {
+ AM_drawkeys();
+ }
+
+ if (gamemode == retail)
+ {
+ numepisodes = 5;
+ }
+ else
+ {
+ numepisodes = 3;
+ }
+
+ if (gameepisode <= numepisodes && gamemap < 10)
+ {
+ level_name = LevelNames[(gameepisode - 1) * 9 + gamemap - 1];
+ MN_DrTextA(DEH_String(level_name), 20, 145);
+ }
+// I_Update();
+// V_MarkRect(f_x, f_y, f_w, f_h);
+}
diff --git a/src/heretic/am_map.h b/src/heretic/am_map.h
new file mode 100644
index 00000000..cbd2935a
--- /dev/null
+++ b/src/heretic/am_map.h
@@ -0,0 +1,119 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+#ifndef __AMMAP_H__
+#define __AMMAP_H__
+
+// For use if I do walls with outsides/insides
+#define REDS 12*8
+#define REDRANGE 1 //16
+#define BLUES (256-4*16+8)
+#define BLUERANGE 1 //8
+#define GREENS (33*8)
+#define GREENRANGE 1 //16
+#define GRAYS (5*8)
+#define GRAYSRANGE 1 //16
+#define BROWNS (14*8)
+#define BROWNRANGE 1 //16
+#define YELLOWS 10*8
+#define YELLOWRANGE 1
+#define BLACK 0
+#define WHITE 4*8
+#define PARCH 13*8-1
+#define BLOODRED 150
+#define BLUEKEY 197
+#define YELLOWKEY 144
+#define GREENKEY 220
+
+// Automap colors
+#define BACKGROUND PARCH
+#define YOURCOLORS WHITE
+#define YOURRANGE 0
+#define WALLCOLORS REDS
+#define WALLRANGE REDRANGE
+#define TSWALLCOLORS GRAYS
+#define TSWALLRANGE GRAYSRANGE
+#define FDWALLCOLORS BROWNS
+#define FDWALLRANGE BROWNRANGE
+#define CDWALLCOLORS YELLOWS
+#define CDWALLRANGE YELLOWRANGE
+#define THINGCOLORS GREENS
+#define THINGRANGE GREENRANGE
+#define SECRETWALLCOLORS WALLCOLORS
+#define SECRETWALLRANGE WALLRANGE
+#define GRIDCOLORS (GRAYS + GRAYSRANGE/2)
+#define GRIDRANGE 0
+#define XHAIRCOLORS GRAYS
+
+// drawing stuff
+#define FB 0
+
+#define AM_NUMMARKPOINTS 10
+
+#define AM_MSGHEADER (('a'<<24)+('m'<<16))
+#define AM_MSGENTERED (AM_MSGHEADER | ('e'<<8))
+#define AM_MSGEXITED (AM_MSGHEADER | ('x'<<8))
+
+#define INITSCALEMTOF (.2*FRACUNIT) // scale on entry
+// how much the automap moves window per tic in frame-buffer coordinates
+#define F_PANINC 4 // moves 140 pixels in 1 second
+// how much zoom-in per tic
+#define M_ZOOMIN ((int) (1.02*FRACUNIT)) // goes to 2x in 1 second
+// how much zoom-out per tic
+#define M_ZOOMOUT ((int) (FRACUNIT/1.02)) // pulls out to 0.5x in 1 second
+
+// translates between frame-buffer and map distances
+#define FTOM(x) FixedMul(((x)<<16),scale_ftom)
+#define MTOF(x) (FixedMul((x),scale_mtof)>>16)
+// translates between frame-buffer and map coordinates
+#define CXMTOF(x) (f_x + MTOF((x)-m_x))
+#define CYMTOF(y) (f_y + (f_h - MTOF((y)-m_y)))
+
+// the following is crap
+#define LINE_NEVERSEE ML_DONTDRAW
+
+typedef struct
+{
+ int x, y;
+} fpoint_t;
+
+typedef struct
+{
+ fpoint_t a, b;
+} fline_t;
+
+typedef vertex_t mpoint_t;
+
+typedef struct
+{
+ mpoint_t a, b;
+} mline_t;
+
+typedef struct
+{
+ fixed_t slp, islp;
+} islope_t;
+
+// extern int f_x, f_y, f_w, f_h;
+
+#endif
diff --git a/src/heretic/ct_chat.c b/src/heretic/ct_chat.c
new file mode 100644
index 00000000..19c27bb2
--- /dev/null
+++ b/src/heretic/ct_chat.c
@@ -0,0 +1,480 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// Chat mode
+//
+
+#include <string.h>
+#include <ctype.h>
+
+#include "doomdef.h"
+#include "doomkeys.h"
+
+#include "deh_str.h"
+#include "m_controls.h"
+#include "p_local.h"
+#include "s_sound.h"
+#include "v_video.h"
+
+#define QUEUESIZE 128
+#define MESSAGESIZE 128
+#define MESSAGELEN 265
+
+#define CT_PLR_GREEN 1
+#define CT_PLR_YELLOW 2
+#define CT_PLR_RED 3
+#define CT_PLR_BLUE 4
+#define CT_PLR_ALL 5
+
+#define CT_ESCAPE 6
+
+// Public data
+
+
+boolean chatmodeon;
+
+// Private data
+
+void CT_queueChatChar(char ch);
+void CT_ClearChatMessage(int player);
+void CT_AddChar(int player, char c);
+void CT_BackSpace(int player);
+
+int head;
+int tail;
+byte ChatQueue[QUEUESIZE];
+int chat_dest[MAXPLAYERS];
+char chat_msg[MAXPLAYERS][MESSAGESIZE];
+char plr_lastmsg[MAXPLAYERS][MESSAGESIZE + 9]; // add in the length of the pre-string
+int msgptr[MAXPLAYERS];
+int msglen[MAXPLAYERS];
+
+boolean cheated;
+
+static int FontABaseLump;
+
+char *CT_FromPlrText[MAXPLAYERS] = {
+ "GREEN: ",
+ "YELLOW: ",
+ "RED: ",
+ "BLUE: "
+};
+
+char *chat_macros[10];
+
+boolean altdown;
+boolean shiftdown;
+
+
+//===========================================================================
+//
+// CT_Init
+//
+// Initialize chat mode data
+//===========================================================================
+
+void CT_Init(void)
+{
+ int i;
+
+ head = 0; //initialize the queue index
+ tail = 0;
+ chatmodeon = false;
+ memset(ChatQueue, 0, QUEUESIZE);
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ chat_dest[i] = 0;
+ msgptr[i] = 0;
+ memset(plr_lastmsg[i], 0, MESSAGESIZE);
+ memset(chat_msg[i], 0, MESSAGESIZE);
+ }
+ FontABaseLump = W_GetNumForName(DEH_String("FONTA_S")) + 1;
+ return;
+}
+
+//===========================================================================
+//
+// CT_Stop
+//
+//===========================================================================
+
+void CT_Stop(void)
+{
+ chatmodeon = false;
+ return;
+}
+
+// These keys are allowed by Vanilla Heretic:
+
+static boolean ValidChatChar(char c)
+{
+ return (c >= 'a' && c <= 'z')
+ || (c >= 'A' && c <= 'Z')
+ || (c >= '0' && c <= '9')
+ || c == '!' || c == '?'
+ || c == ' ' || c == '\''
+ || c == ',' || c == '.'
+ || c == '-' || c == '=';
+}
+
+//===========================================================================
+//
+// CT_Responder
+//
+//===========================================================================
+
+boolean CT_Responder(event_t * ev)
+{
+ char *macro;
+
+ int sendto;
+
+ if (!netgame)
+ {
+ return false;
+ }
+ if (ev->data1 == KEY_LALT || ev->data2 == KEY_RALT)
+ {
+ altdown = (ev->type == ev_keydown);
+ return false;
+ }
+ if (ev->data1 == KEY_RSHIFT)
+ {
+ shiftdown = (ev->type == ev_keydown);
+ return false;
+ }
+ if (ev->type != ev_keydown)
+ {
+ return false;
+ }
+ if (!chatmodeon)
+ {
+ sendto = 0;
+ if (ev->data1 == key_multi_msg)
+ {
+ sendto = CT_PLR_ALL;
+ }
+ else if (ev->data1 == key_multi_msgplayer[0])
+ {
+ sendto = CT_PLR_GREEN;
+ }
+ else if (ev->data1 == key_multi_msgplayer[1])
+ {
+ sendto = CT_PLR_YELLOW;
+ }
+ else if (ev->data1 == key_multi_msgplayer[2])
+ {
+ sendto = CT_PLR_RED;
+ }
+ else if (ev->data1 == key_multi_msgplayer[3])
+ {
+ sendto = CT_PLR_BLUE;
+ }
+ if (sendto == 0 || (sendto != CT_PLR_ALL && !playeringame[sendto - 1])
+ || sendto == consoleplayer + 1)
+ {
+ return false;
+ }
+ CT_queueChatChar(sendto);
+ chatmodeon = true;
+ return true;
+ }
+ else
+ {
+ if (altdown)
+ {
+ if (ev->data1 >= '0' && ev->data1 <= '9')
+ {
+ if (ev->data1 == '0')
+ { // macro 0 comes after macro 9
+ ev->data1 = '9' + 1;
+ }
+ macro = chat_macros[ev->data1 - '1'];
+ CT_queueChatChar(KEY_ENTER); //send old message
+ CT_queueChatChar(chat_dest[consoleplayer]); // chose the dest.
+ while (*macro)
+ {
+ CT_queueChatChar(toupper(*macro++));
+ }
+ CT_queueChatChar(KEY_ENTER); //send it off...
+ CT_Stop();
+ return true;
+ }
+ }
+ if (ev->data1 == KEY_ENTER)
+ {
+ CT_queueChatChar(KEY_ENTER);
+ CT_Stop();
+ return true;
+ }
+ else if (ev->data1 == KEY_ESCAPE)
+ {
+ CT_queueChatChar(CT_ESCAPE);
+ CT_Stop();
+ return true;
+ }
+ else if (ev->data1 == KEY_BACKSPACE)
+ {
+ CT_queueChatChar(KEY_BACKSPACE);
+ return true;
+ }
+ else if (ValidChatChar(ev->data2))
+ {
+ CT_queueChatChar(toupper(ev->data2));
+ return true;
+ }
+ }
+ return false;
+}
+
+//===========================================================================
+//
+// CT_Ticker
+//
+//===========================================================================
+
+void CT_Ticker(void)
+{
+ int i;
+ int j;
+ char c;
+ int numplayers;
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (!playeringame[i])
+ {
+ continue;
+ }
+ if ((c = players[i].cmd.chatchar) != 0)
+ {
+ if (c <= 5)
+ {
+ chat_dest[i] = c;
+ continue;
+ }
+ else if (c == CT_ESCAPE)
+ {
+ CT_ClearChatMessage(i);
+ }
+ else if (c == KEY_ENTER)
+ {
+ numplayers = 0;
+ for (j = 0; j < MAXPLAYERS; j++)
+ {
+ numplayers += playeringame[j];
+ }
+ CT_AddChar(i, 0); // set the end of message character
+ if (numplayers > 2)
+ {
+ strncpy(plr_lastmsg[i], DEH_String(CT_FromPlrText[i]),
+ MESSAGESIZE + 9);
+ plr_lastmsg[i][MESSAGESIZE + 8] = '\0';
+ strcat(plr_lastmsg[i], chat_msg[i]);
+ }
+ else
+ {
+ strcpy(plr_lastmsg[i], chat_msg[i]);
+ }
+ if (i != consoleplayer && (chat_dest[i] == consoleplayer + 1
+ || chat_dest[i] == CT_PLR_ALL)
+ && *chat_msg[i])
+ {
+ P_SetMessage(&players[consoleplayer], plr_lastmsg[i],
+ true);
+ S_StartSound(NULL, sfx_chat);
+ }
+ else if (i == consoleplayer && (*chat_msg[i]))
+ {
+ if (numplayers > 1)
+ {
+ P_SetMessage(&players[consoleplayer],
+ DEH_String("-MESSAGE SENT-"), true);
+ S_StartSound(NULL, sfx_chat);
+ }
+ else
+ {
+ P_SetMessage(&players[consoleplayer],
+ DEH_String("THERE ARE NO OTHER PLAYERS IN THE GAME!"),
+ true);
+ S_StartSound(NULL, sfx_chat);
+ }
+ }
+ CT_ClearChatMessage(i);
+ }
+ else if (c == KEY_BACKSPACE)
+ {
+ CT_BackSpace(i);
+ }
+ else
+ {
+ CT_AddChar(i, c);
+ }
+ }
+ }
+ return;
+}
+
+//===========================================================================
+//
+// CT_Drawer
+//
+//===========================================================================
+
+void CT_Drawer(void)
+{
+ int i;
+ int x;
+ patch_t *patch;
+
+ if (chatmodeon)
+ {
+ x = 25;
+ for (i = 0; i < msgptr[consoleplayer]; i++)
+ {
+ if (chat_msg[consoleplayer][i] < 33)
+ {
+ x += 6;
+ }
+ else
+ {
+ patch = W_CacheLumpNum(FontABaseLump +
+ chat_msg[consoleplayer][i] - 33,
+ PU_CACHE);
+ V_DrawPatch(x, 10, patch);
+ x += patch->width;
+ }
+ }
+ V_DrawPatch(x, 10, W_CacheLumpName(DEH_String("FONTA59"), PU_CACHE));
+ BorderTopRefresh = true;
+ UpdateState |= I_MESSAGES;
+ }
+}
+
+//===========================================================================
+//
+// CT_queueChatChar
+//
+//===========================================================================
+
+void CT_queueChatChar(char ch)
+{
+ if (((tail + 1) & (QUEUESIZE - 1)) == head)
+ { // the queue is full
+ return;
+ }
+ ChatQueue[tail] = ch;
+ tail = (tail + 1) & (QUEUESIZE - 1);
+}
+
+//===========================================================================
+//
+// CT_dequeueChatChar
+//
+//===========================================================================
+
+char CT_dequeueChatChar(void)
+{
+ byte temp;
+
+ if (head == tail)
+ { // queue is empty
+ return 0;
+ }
+ temp = ChatQueue[head];
+ head = (head + 1) & (QUEUESIZE - 1);
+ return temp;
+}
+
+//===========================================================================
+//
+// CT_AddChar
+//
+//===========================================================================
+
+void CT_AddChar(int player, char c)
+{
+ patch_t *patch;
+
+ if (msgptr[player] + 1 >= MESSAGESIZE || msglen[player] >= MESSAGELEN)
+ { // full.
+ return;
+ }
+ chat_msg[player][msgptr[player]] = c;
+ msgptr[player]++;
+ if (c < 33)
+ {
+ msglen[player] += 6;
+ }
+ else
+ {
+ patch = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
+ msglen[player] += patch->width;
+ }
+}
+
+//===========================================================================
+//
+// CT_BackSpace
+//
+// Backs up a space, when the user hits (obviously) backspace
+//===========================================================================
+
+void CT_BackSpace(int player)
+{
+ patch_t *patch;
+ char c;
+
+ if (msgptr[player] == 0)
+ { // message is already blank
+ return;
+ }
+ msgptr[player]--;
+ c = chat_msg[player][msgptr[player]];
+ if (c < 33)
+ {
+ msglen[player] -= 6;
+ }
+ else
+ {
+ patch = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
+ msglen[player] -= patch->width;
+ }
+ chat_msg[player][msgptr[player]] = 0;
+}
+
+//===========================================================================
+//
+// CT_ClearChatMessage
+//
+// Clears out the data for the chat message, but the player's message
+// is still saved in plrmsg.
+//===========================================================================
+
+void CT_ClearChatMessage(int player)
+{
+ memset(chat_msg[player], 0, MESSAGESIZE);
+ msgptr[player] = 0;
+ msglen[player] = 0;
+}
diff --git a/src/heretic/ct_chat.h b/src/heretic/ct_chat.h
new file mode 100644
index 00000000..84544e56
--- /dev/null
+++ b/src/heretic/ct_chat.h
@@ -0,0 +1,46 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// Chat mode stuff
+//
+
+#ifndef HERETIC_CT_CHAT_H
+#define HERETIC_CT_CHAT_H
+
+#define CT_PLR_GREEN 1
+#define CT_PLR_YELLOW 2
+#define CT_PLR_RED 3
+#define CT_PLR_BLUE 4
+#define CT_PLR_ALL 5
+
+#define CT_KEY_GREEN 'g'
+#define CT_KEY_YELLOW 'y'
+#define CT_KEY_RED 'r'
+#define CT_KEY_BLUE 'b'
+#define CT_KEY_ALL 't'
+
+extern char *chat_macros[10];
+
+#endif /* #ifndef HERETIC_CT_CHAT_H */
+
diff --git a/src/heretic/d_main.c b/src/heretic/d_main.c
new file mode 100644
index 00000000..d1c74b7c
--- /dev/null
+++ b/src/heretic/d_main.c
@@ -0,0 +1,1078 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// D_main.c
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "doomfeatures.h"
+
+#include "txt_main.h"
+#include "txt_io.h"
+
+#include "net_client.h"
+
+#include "config.h"
+#include "ct_chat.h"
+#include "doomdef.h"
+#include "deh_main.h"
+#include "d_iwad.h"
+#include "i_endoom.h"
+#include "i_joystick.h"
+#include "i_sound.h"
+#include "i_system.h"
+#include "i_timer.h"
+#include "i_video.h"
+#include "m_argv.h"
+#include "m_config.h"
+#include "m_controls.h"
+#include "p_local.h"
+#include "s_sound.h"
+#include "w_main.h"
+#include "v_video.h"
+
+#define CT_KEY_GREEN 'g'
+#define CT_KEY_YELLOW 'y'
+#define CT_KEY_RED 'r'
+#define CT_KEY_BLUE 'b'
+
+#define STARTUP_WINDOW_X 17
+#define STARTUP_WINDOW_Y 7
+
+GameMission_t gamemission = heretic;
+GameMode_t gamemode = indetermined;
+char *gamedescription = "unknown";
+
+boolean nomonsters; // checkparm of -nomonsters
+boolean respawnparm; // checkparm of -respawn
+boolean debugmode; // checkparm of -debug
+boolean ravpic; // checkparm of -ravpic
+boolean cdrom; // true if cd-rom mode active
+boolean singletics; // debug flag to cancel adaptiveness
+boolean noartiskip; // whether shift-enter skips an artifact
+
+skill_t startskill;
+int startepisode;
+int startmap;
+int UpdateState;
+static int graphical_startup = 1;
+static boolean using_graphical_startup;
+boolean autostart;
+extern boolean automapactive;
+
+boolean advancedemo;
+
+FILE *debugfile;
+
+static int show_endoom = 1;
+
+void D_CheckNetGame(void);
+void D_PageDrawer(void);
+void D_AdvanceDemo(void);
+boolean F_Responder(event_t * ev);
+
+//---------------------------------------------------------------------------
+//
+// PROC D_ProcessEvents
+//
+// Send all the events of the given timestamp down the responder chain.
+//
+//---------------------------------------------------------------------------
+
+void D_ProcessEvents(void)
+{
+ event_t *ev;
+
+ while ((ev = D_PopEvent()) != NULL)
+ {
+ if (F_Responder(ev))
+ {
+ continue;
+ }
+ if (MN_Responder(ev))
+ {
+ continue;
+ }
+ G_Responder(ev);
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawMessage
+//
+//---------------------------------------------------------------------------
+
+void DrawMessage(void)
+{
+ player_t *player;
+
+ player = &players[consoleplayer];
+ if (player->messageTics <= 0 || !player->message)
+ { // No message
+ return;
+ }
+ MN_DrTextA(player->message, 160 - MN_TextAWidth(player->message) / 2, 1);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC D_Display
+//
+// Draw current display, possibly wiping it from the previous.
+//
+//---------------------------------------------------------------------------
+
+void R_ExecuteSetViewSize(void);
+
+extern boolean finalestage;
+
+void D_Display(void)
+{
+ extern boolean askforquit;
+
+ // Change the view size if needed
+ if (setsizeneeded)
+ {
+ R_ExecuteSetViewSize();
+ }
+
+//
+// do buffered drawing
+//
+ switch (gamestate)
+ {
+ case GS_LEVEL:
+ if (!gametic)
+ break;
+ if (automapactive)
+ AM_Drawer();
+ else
+ R_RenderPlayerView(&players[displayplayer]);
+ CT_Drawer();
+ UpdateState |= I_FULLVIEW;
+ SB_Drawer();
+ break;
+ case GS_INTERMISSION:
+ IN_Drawer();
+ break;
+ case GS_FINALE:
+ F_Drawer();
+ break;
+ case GS_DEMOSCREEN:
+ D_PageDrawer();
+ break;
+ }
+
+ if (testcontrols)
+ {
+ V_DrawMouseSpeedBox(testcontrols_mousespeed);
+ }
+
+ if (paused && !MenuActive && !askforquit)
+ {
+ if (!netgame)
+ {
+ V_DrawPatch(160, viewwindowy + 5, W_CacheLumpName(DEH_String("PAUSED"),
+ PU_CACHE));
+ }
+ else
+ {
+ V_DrawPatch(160, 70, W_CacheLumpName(DEH_String("PAUSED"), PU_CACHE));
+ }
+ }
+ // Handle player messages
+ DrawMessage();
+
+ // Menu drawing
+ MN_Drawer();
+
+ // Send out any new accumulation
+ NetUpdate();
+
+ // Flush buffered stuff to screen
+ I_FinishUpdate();
+}
+
+//
+// D_GrabMouseCallback
+//
+// Called to determine whether to grab the mouse pointer
+//
+
+boolean D_GrabMouseCallback(void)
+{
+ // when menu is active or game is paused, release the mouse
+
+ if (MenuActive || paused)
+ return false;
+
+ // only grab mouse when playing levels (but not demos)
+
+ return (gamestate == GS_LEVEL) && !demoplayback;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC D_DoomLoop
+//
+//---------------------------------------------------------------------------
+
+void D_DoomLoop(void)
+{
+ if (M_CheckParm("-debugfile"))
+ {
+ char filename[20];
+ sprintf(filename, "debug%i.txt", consoleplayer);
+ debugfile = fopen(filename, "w");
+ }
+ I_SetWindowTitle(gamedescription);
+ I_GraphicsCheckCommandLine();
+ I_InitGraphics();
+ I_SetGrabMouseCallback(D_GrabMouseCallback);
+
+ while (1)
+ {
+ // Frame syncronous IO operations
+ I_StartFrame();
+
+ // Process one or more tics
+ // Will run at least one tic
+ TryRunTics();
+
+ // Move positional sounds
+ S_UpdateSounds(players[consoleplayer].mo);
+ D_Display();
+ }
+}
+
+/*
+===============================================================================
+
+ DEMO LOOP
+
+===============================================================================
+*/
+
+int demosequence;
+int pagetic;
+char *pagename;
+
+
+/*
+================
+=
+= D_PageTicker
+=
+= Handles timing for warped projection
+=
+================
+*/
+
+void D_PageTicker(void)
+{
+ if (--pagetic < 0)
+ D_AdvanceDemo();
+}
+
+
+/*
+================
+=
+= D_PageDrawer
+=
+================
+*/
+
+void D_PageDrawer(void)
+{
+ V_DrawRawScreen(W_CacheLumpName(pagename, PU_CACHE));
+ if (demosequence == 1)
+ {
+ V_DrawPatch(4, 160, W_CacheLumpName(DEH_String("ADVISOR"), PU_CACHE));
+ }
+ UpdateState |= I_FULLSCRN;
+}
+
+/*
+=================
+=
+= D_AdvanceDemo
+=
+= Called after each demo or intro demosequence finishes
+=================
+*/
+
+void D_AdvanceDemo(void)
+{
+ advancedemo = true;
+}
+
+void D_DoAdvanceDemo(void)
+{
+ players[consoleplayer].playerstate = PST_LIVE; // don't reborn
+ advancedemo = false;
+ usergame = false; // can't save / end game here
+ paused = false;
+ gameaction = ga_nothing;
+ demosequence = (demosequence + 1) % 7;
+ switch (demosequence)
+ {
+ case 0:
+ pagetic = 210;
+ gamestate = GS_DEMOSCREEN;
+ pagename = DEH_String("TITLE");
+ S_StartSong(mus_titl, false);
+ break;
+ case 1:
+ pagetic = 140;
+ gamestate = GS_DEMOSCREEN;
+ pagename = DEH_String("TITLE");
+ break;
+ case 2:
+ BorderNeedRefresh = true;
+ UpdateState |= I_FULLSCRN;
+ G_DeferedPlayDemo(DEH_String("demo1"));
+ break;
+ case 3:
+ pagetic = 200;
+ gamestate = GS_DEMOSCREEN;
+ pagename = DEH_String("CREDIT");
+ break;
+ case 4:
+ BorderNeedRefresh = true;
+ UpdateState |= I_FULLSCRN;
+ G_DeferedPlayDemo(DEH_String("demo2"));
+ break;
+ case 5:
+ pagetic = 200;
+ gamestate = GS_DEMOSCREEN;
+ if (gamemode == shareware)
+ {
+ pagename = DEH_String("ORDER");
+ }
+ else
+ {
+ pagename = DEH_String("CREDIT");
+ }
+ break;
+ case 6:
+ BorderNeedRefresh = true;
+ UpdateState |= I_FULLSCRN;
+ G_DeferedPlayDemo(DEH_String("demo3"));
+ break;
+ }
+}
+
+
+/*
+=================
+=
+= D_StartTitle
+=
+=================
+*/
+
+void D_StartTitle(void)
+{
+ gameaction = ga_nothing;
+ demosequence = -1;
+ D_AdvanceDemo();
+}
+
+
+/*
+==============
+=
+= D_CheckRecordFrom
+=
+= -recordfrom <savegame num> <demoname>
+==============
+*/
+
+void D_CheckRecordFrom(void)
+{
+ int p;
+ char *filename;
+
+ p = M_CheckParm("-recordfrom");
+ if (!p || p > myargc - 2)
+ return;
+
+ filename = SV_Filename(myargv[p + 1][0] - '0');
+ G_LoadGame(filename);
+ G_DoLoadGame(); // load the gameskill etc info from savegame
+
+ G_RecordDemo(gameskill, 1, gameepisode, gamemap, myargv[p + 2]);
+ D_DoomLoop(); // never returns
+ free(filename);
+}
+
+/*
+===============
+=
+= D_AddFile
+=
+===============
+*/
+
+// MAPDIR should be defined as the directory that holds development maps
+// for the -wart # # command
+
+#define MAPDIR "\\data\\"
+
+#define SHAREWAREWADNAME "heretic1.wad"
+
+char *iwadfile;
+
+char *basedefault = "heretic.cfg";
+
+void wadprintf(void)
+{
+ if (debugmode)
+ {
+ return;
+ }
+ // haleyjd FIXME: convert to textscreen code?
+#ifdef __WATCOMC__
+ _settextposition(23, 2);
+ _setbkcolor(1);
+ _settextcolor(0);
+ _outtext(exrnwads);
+ _settextposition(24, 2);
+ _outtext(exrnwads2);
+#endif
+}
+
+boolean D_AddFile(char *file)
+{
+ wad_file_t *handle;
+
+ printf(" adding %s\n", file);
+
+ handle = W_AddFile(file);
+
+ return handle != NULL;
+}
+
+//==========================================================
+//
+// Startup Thermo code
+//
+//==========================================================
+#define MSG_Y 9
+#define THERM_X 14
+#define THERM_Y 14
+
+int thermMax;
+int thermCurrent;
+char smsg[80]; // status bar line
+
+//
+// Heretic startup screen shit
+//
+
+static int startup_line = STARTUP_WINDOW_Y;
+
+void hprintf(char *string)
+{
+ if (using_graphical_startup)
+ {
+ TXT_BGColor(TXT_COLOR_CYAN, 0);
+ TXT_FGColor(TXT_COLOR_BRIGHT_WHITE);
+
+ TXT_GotoXY(STARTUP_WINDOW_X, startup_line);
+ ++startup_line;
+ TXT_Puts(string);
+
+ TXT_UpdateScreen();
+ }
+
+ // haleyjd: shouldn't be WATCOMC-only
+ if (debugmode)
+ puts(string);
+}
+
+void drawstatus(void)
+{
+ int i;
+
+ TXT_GotoXY(1, 24);
+ TXT_BGColor(TXT_COLOR_BLUE, 0);
+ TXT_FGColor(TXT_COLOR_BRIGHT_WHITE);
+
+ for (i=0; smsg[i] != '\0'; ++i)
+ {
+ TXT_PutChar(smsg[i]);
+ }
+}
+
+void status(char *string)
+{
+ if (using_graphical_startup)
+ {
+ strcat(smsg, string);
+ drawstatus();
+ }
+}
+
+void DrawThermo(void)
+{
+ static int last_progress = -1;
+ int progress;
+ int i;
+
+ if (!using_graphical_startup)
+ {
+ return;
+ }
+
+#if 0
+ progress = (98 * thermCurrent) / thermMax;
+ screen = (char *) 0xb8000 + (THERM_Y * 160 + THERM_X * 2);
+ for (i = 0; i < progress / 2; i++)
+ {
+ switch (i)
+ {
+ case 4:
+ case 9:
+ case 14:
+ case 19:
+ case 29:
+ case 34:
+ case 39:
+ case 44:
+ *screen++ = 0xb3;
+ *screen++ = (THERMCOLOR << 4) + 15;
+ break;
+ case 24:
+ *screen++ = 0xba;
+ *screen++ = (THERMCOLOR << 4) + 15;
+ break;
+ default:
+ *screen++ = 0xdb;
+ *screen++ = 0x40 + THERMCOLOR;
+ break;
+ }
+ }
+ if (progress & 1)
+ {
+ *screen++ = 0xdd;
+ *screen++ = 0x40 + THERMCOLOR;
+ }
+#else
+
+ // No progress? Don't update the screen.
+
+ progress = (50 * thermCurrent) / thermMax + 2;
+
+ if (last_progress == progress)
+ {
+ return;
+ }
+
+ last_progress = progress;
+
+ TXT_GotoXY(THERM_X, THERM_Y);
+
+ TXT_FGColor(TXT_COLOR_BRIGHT_GREEN);
+ TXT_BGColor(TXT_COLOR_GREEN, 0);
+
+ for (i = 0; i < progress; i++)
+ {
+ TXT_PutChar(0xdb);
+ }
+
+ TXT_UpdateScreen();
+#endif
+}
+
+void initStartup(void)
+{
+ byte *textScreen;
+ byte *loading;
+
+ if (!graphical_startup || debugmode || testcontrols)
+ {
+ using_graphical_startup = false;
+ return;
+ }
+
+ if (!TXT_Init())
+ {
+ using_graphical_startup = false;
+ return;
+ }
+
+ // Blit main screen
+ textScreen = TXT_GetScreenData();
+ loading = W_CacheLumpName(DEH_String("LOADING"), PU_CACHE);
+ memcpy(textScreen, loading, 4000);
+
+ // Print version string
+
+ TXT_BGColor(TXT_COLOR_RED, 0);
+ TXT_FGColor(TXT_COLOR_YELLOW);
+ TXT_GotoXY(46, 2);
+ TXT_Puts(HERETIC_VERSION_TEXT);
+
+ TXT_UpdateScreen();
+
+ using_graphical_startup = true;
+}
+
+static void finishStartup(void)
+{
+ if (using_graphical_startup)
+ {
+ TXT_Shutdown();
+ }
+}
+
+char tmsg[300];
+void tprintf(char *msg, int initflag)
+{
+ // haleyjd FIXME: convert to textscreen code?
+#ifdef __WATCOMC__
+ char temp[80];
+ int start;
+ int add;
+ int i;
+
+ if (initflag)
+ tmsg[0] = 0;
+ strcat(tmsg, msg);
+ blitStartup();
+ DrawThermo();
+ _setbkcolor(4);
+ _settextcolor(15);
+ for (add = start = i = 0; i <= strlen(tmsg); i++)
+ if ((tmsg[i] == '\n') || (!tmsg[i]))
+ {
+ memset(temp, 0, 80);
+ strncpy(temp, tmsg + start, i - start);
+ _settextposition(MSG_Y + add, 40 - strlen(temp) / 2);
+ _outtext(temp);
+ start = i + 1;
+ add++;
+ }
+ _settextposition(25, 1);
+ drawstatus();
+#else
+ printf("%s", msg);
+#endif
+}
+
+// haleyjd: moved up, removed WATCOMC code
+void CleanExit(void)
+{
+ DEH_printf("Exited from HERETIC.\n");
+ exit(1);
+}
+
+void CheckAbortStartup(void)
+{
+ // haleyjd: removed WATCOMC
+ // haleyjd FIXME: this should actually work in text mode too, but how to
+ // get input before SDL video init?
+ if(using_graphical_startup)
+ {
+ if(TXT_GetChar() == 27)
+ CleanExit();
+ }
+}
+
+void IncThermo(void)
+{
+ thermCurrent++;
+ DrawThermo();
+ CheckAbortStartup();
+}
+
+void InitThermo(int max)
+{
+ thermMax = max;
+ thermCurrent = 0;
+}
+
+//
+// Add configuration file variable bindings.
+//
+
+void D_BindVariables(void)
+{
+ extern int screenblocks;
+ extern int snd_Channels;
+ int i;
+
+ M_ApplyPlatformDefaults();
+
+ I_BindVideoVariables();
+ I_BindJoystickVariables();
+ I_BindSoundVariables();
+
+ M_BindBaseControls();
+ M_BindHereticControls();
+ M_BindWeaponControls();
+ M_BindChatControls(MAXPLAYERS);
+
+ key_multi_msgplayer[0] = CT_KEY_GREEN;
+ key_multi_msgplayer[1] = CT_KEY_YELLOW;
+ key_multi_msgplayer[2] = CT_KEY_RED;
+ key_multi_msgplayer[3] = CT_KEY_BLUE;
+
+ M_BindMenuControls();
+ M_BindMapControls();
+
+ M_BindVariable("mouse_sensitivity", &mouseSensitivity);
+ M_BindVariable("sfx_volume", &snd_MaxVolume);
+ M_BindVariable("music_volume", &snd_MusicVolume);
+ M_BindVariable("screenblocks", &screenblocks);
+ M_BindVariable("snd_channels", &snd_Channels);
+ M_BindVariable("show_endoom", &show_endoom);
+ M_BindVariable("graphical_startup", &graphical_startup);
+
+ for (i=0; i<10; ++i)
+ {
+ char buf[12];
+
+ sprintf(buf, "chatmacro%i", i);
+ M_BindVariable(buf, &chat_macros[i]);
+ }
+}
+
+//
+// Called at exit to display the ENDOOM screen (ENDTEXT in Heretic)
+//
+
+static void D_Endoom(void)
+{
+ byte *endoom_data;
+
+ // Disable ENDOOM?
+
+ if (!show_endoom || testcontrols)
+ {
+ return;
+ }
+
+ endoom_data = W_CacheLumpName(DEH_String("ENDTEXT"), PU_STATIC);
+
+ I_Endoom(endoom_data);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC D_DoomMain
+//
+//---------------------------------------------------------------------------
+
+void D_DoomMain(void)
+{
+ int p;
+ char file[256];
+
+ I_PrintBanner(PACKAGE_STRING);
+
+ I_AtExit(D_Endoom, false);
+
+ nomonsters = M_CheckParm("-nomonsters");
+ respawnparm = M_CheckParm("-respawn");
+ ravpic = M_CheckParm("-ravpic");
+ noartiskip = M_CheckParm("-noartiskip");
+ debugmode = M_CheckParm("-debug");
+ startskill = sk_medium;
+ startepisode = 1;
+ startmap = 1;
+ autostart = false;
+
+//
+// get skill / episode / map from parms
+//
+ if (M_CheckParm("-deathmatch"))
+ {
+ deathmatch = true;
+ }
+
+ p = M_CheckParm("-skill");
+ if (p && p < myargc - 1)
+ {
+ startskill = myargv[p + 1][0] - '1';
+ autostart = true;
+ }
+
+ p = M_CheckParm("-episode");
+ if (p && p < myargc - 1)
+ {
+ startepisode = myargv[p + 1][0] - '0';
+ startmap = 1;
+ autostart = true;
+ }
+
+ p = M_CheckParm("-warp");
+ if (p && p < myargc - 2)
+ {
+ startepisode = myargv[p + 1][0] - '0';
+ startmap = myargv[p + 2][0] - '0';
+ autostart = true;
+ }
+
+//
+// init subsystems
+//
+ DEH_printf("V_Init: allocate screens.\n");
+ V_Init();
+
+ // Check for -CDROM
+
+ cdrom = false;
+
+#ifdef _WIN32
+
+ //!
+ // @platform windows
+ // @vanilla
+ //
+ // Save configuration data and savegames in c:\heretic.cd,
+ // allowing play from CD.
+ //
+
+ if (M_CheckParm("-cdrom"))
+ {
+ cdrom = true;
+ }
+#endif
+
+ if (cdrom)
+ {
+ M_SetConfigDir(DEH_String("c:\\heretic.cd"));
+ }
+ else
+ {
+ M_SetConfigDir(NULL);
+ }
+
+ // Load defaults before initing other systems
+ DEH_printf("M_LoadDefaults: Load system defaults.\n");
+ D_BindVariables();
+ M_SetConfigFilenames("heretic.cfg", PROGRAM_PREFIX "heretic.cfg");
+ M_LoadDefaults();
+
+ I_AtExit(M_SaveDefaults, false);
+
+ DEH_printf("Z_Init: Init zone memory allocation daemon.\n");
+ Z_Init();
+
+#ifdef FEATURE_DEHACKED
+ printf("DEH_Init: Init Dehacked support.\n");
+ DEH_Init();
+#endif
+
+ DEH_printf("W_Init: Init WADfiles.\n");
+
+ iwadfile = D_FindIWAD(IWAD_MASK_HERETIC, &gamemission);
+
+ if (iwadfile == NULL)
+ {
+ I_Error("Game mode indeterminate. No IWAD was found. Try specifying\n"
+ "one with the '-iwad' command line parameter.");
+ }
+
+ D_AddFile(iwadfile);
+ W_ParseCommandLine();
+
+ p = M_CheckParm("-playdemo");
+ if (!p)
+ {
+ p = M_CheckParm("-timedemo");
+ }
+ if (p && p < myargc - 1)
+ {
+ DEH_snprintf(file, sizeof(file), "%s.lmp", myargv[p + 1]);
+ D_AddFile(file);
+ DEH_printf("Playing demo %s.lmp.\n", myargv[p + 1]);
+ }
+
+ if (W_CheckNumForName(DEH_String("E2M1")) == -1)
+ {
+ gamemode = shareware;
+ gamedescription = "Heretic (shareware)";
+ }
+ else if (W_CheckNumForName("EXTENDED") != -1)
+ {
+ // Presence of the EXTENDED lump indicates the retail version
+
+ gamemode = retail;
+ gamedescription = "Heretic: Shadow of the Serpent Riders";
+ }
+ else
+ {
+ gamemode = registered;
+ gamedescription = "Heretic (registered)";
+ }
+
+ savegamedir = M_GetSaveGameDir("heretic.wad");
+
+ I_PrintStartupBanner(gamedescription);
+
+ if (M_ParmExists("-testcontrols"))
+ {
+ startepisode = 1;
+ startmap = 1;
+ autostart = true;
+ testcontrols = true;
+ }
+
+ // haleyjd: removed WATCOMC
+ initStartup();
+
+ //
+ // Build status bar line!
+ //
+ smsg[0] = 0;
+ if (deathmatch)
+ status(DEH_String("DeathMatch..."));
+ if (nomonsters)
+ status(DEH_String("No Monsters..."));
+ if (respawnparm)
+ status(DEH_String("Respawning..."));
+ if (autostart)
+ {
+ char temp[64];
+ DEH_snprintf(temp, sizeof(temp),
+ "Warp to Episode %d, Map %d, Skill %d ",
+ startepisode, startmap, startskill + 1);
+ status(temp);
+ }
+ wadprintf(); // print the added wadfiles
+
+ tprintf(DEH_String("MN_Init: Init menu system.\n"), 1);
+ MN_Init();
+
+#ifdef FEATURE_MULTIPLAYER
+ tprintf ("NET_Init: Init network subsystem.\n", 1);
+ NET_Init ();
+#endif
+
+ CT_Init();
+
+ tprintf(DEH_String("R_Init: Init Heretic refresh daemon."), 1);
+ hprintf(DEH_String("Loading graphics"));
+ R_Init();
+ tprintf("\n", 0);
+
+ tprintf(DEH_String("P_Init: Init Playloop state.\n"), 1);
+ hprintf(DEH_String("Init game engine."));
+ P_Init();
+ IncThermo();
+
+ tprintf(DEH_String("I_Init: Setting up machine state.\n"), 1);
+ I_CheckIsScreensaver();
+ I_InitTimer();
+ I_InitJoystick();
+ IncThermo();
+
+ tprintf(DEH_String("S_Init: Setting up sound.\n"), 1);
+ S_Init();
+ //IO_StartupTimer();
+ S_Start();
+
+ tprintf(DEH_String("D_CheckNetGame: Checking network game status.\n"), 1);
+ hprintf(DEH_String("Checking network game status."));
+ D_CheckNetGame();
+ IncThermo();
+
+ // haleyjd: removed WATCOMC
+
+ tprintf(DEH_String("SB_Init: Loading patches.\n"), 1);
+ SB_Init();
+ IncThermo();
+
+//
+// start the apropriate game based on parms
+//
+
+ D_CheckRecordFrom();
+
+ p = M_CheckParm("-record");
+ if (p && p < myargc - 1)
+ {
+ G_RecordDemo(startskill, 1, startepisode, startmap, myargv[p + 1]);
+ D_DoomLoop(); // Never returns
+ }
+
+ p = M_CheckParm("-playdemo");
+ if (p && p < myargc - 1)
+ {
+ singledemo = true; // Quit after one demo
+ G_DeferedPlayDemo(myargv[p + 1]);
+ D_DoomLoop(); // Never returns
+ }
+
+ p = M_CheckParm("-timedemo");
+ if (p && p < myargc - 1)
+ {
+ G_TimeDemo(myargv[p + 1]);
+ D_DoomLoop(); // Never returns
+ }
+
+ p = M_CheckParm("-loadgame");
+ if (p && p < myargc - 1)
+ {
+ char *filename;
+
+ filename = SV_Filename(myargv[p + 1][0] - '0');
+ G_LoadGame(filename);
+ free(filename);
+ }
+
+ // Check valid episode and map
+ if (autostart || netgame)
+ {
+ if (!D_ValidEpisodeMap(gamemission, gamemode, startepisode, startmap))
+ {
+ startepisode = 1;
+ startmap = 1;
+ }
+ }
+
+ if (gameaction != ga_loadgame)
+ {
+ UpdateState |= I_FULLSCRN;
+ BorderNeedRefresh = true;
+ if (autostart || netgame)
+ {
+ G_InitNew(startskill, startepisode, startmap);
+ }
+ else
+ {
+ D_StartTitle();
+ }
+ }
+
+ finishStartup();
+
+ D_DoomLoop(); // Never returns
+}
diff --git a/src/heretic/d_net.c b/src/heretic/d_net.c
new file mode 100644
index 00000000..73a09ec6
--- /dev/null
+++ b/src/heretic/d_net.c
@@ -0,0 +1,238 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// DOOM Network game communication and protocol,
+// all OS independend parts.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdlib.h>
+
+#include "doomfeatures.h"
+
+#include "m_argv.h"
+#include "i_system.h"
+#include "i_timer.h"
+#include "i_video.h"
+#include "doomdef.h"
+#include "w_checksum.h"
+
+#include "deh_main.h"
+
+#include "d_loop.h"
+
+ticcmd_t *netcmds;
+
+extern void D_DoAdvanceDemo(void);
+extern void D_ProcessEvents(void);
+extern void G_BuildTiccmd(ticcmd_t *cmd, int maketic);
+extern boolean G_CheckDemoStatus(void);
+
+// Called when a player leaves the game
+
+static void PlayerQuitGame(player_t *player)
+{
+ static char exitmsg[80];
+ unsigned int player_num;
+
+ player_num = player - players;
+
+ // Note:
+ // The Heretic source code does this, which doesn't actually work.
+ // As a result, the exit message is never seen.
+
+ strcpy(exitmsg, "PLAYER 1 LEFT THE GAME");
+ exitmsg[7] += player_num;
+ players[consoleplayer].message = exitmsg;
+
+ playeringame[player_num] = false;
+ players[consoleplayer].message = exitmsg;
+
+ // TODO: check if it is sensible to do this:
+
+ if (demorecording)
+ {
+ G_CheckDemoStatus ();
+ }
+}
+
+static void RunTic(ticcmd_t *cmds, boolean *ingame)
+{
+ extern boolean advancedemo;
+ unsigned int i;
+
+ // Check for player quits.
+
+ for (i = 0; i < MAXPLAYERS; ++i)
+ {
+ if (!demoplayback && playeringame[i] && !ingame[i])
+ {
+ PlayerQuitGame(&players[i]);
+ }
+ }
+
+ netcmds = cmds;
+
+ // check that there are players in the game. if not, we cannot
+ // run a tic.
+
+ if (advancedemo)
+ D_DoAdvanceDemo ();
+
+ G_Ticker ();
+}
+
+static loop_interface_t doom_loop_interface = {
+ D_ProcessEvents,
+ G_BuildTiccmd,
+ RunTic,
+ MN_Ticker
+};
+
+
+// Load game settings from the specified structure and
+// set global variables.
+
+static void LoadGameSettings(net_gamesettings_t *settings,
+ net_connect_data_t *connect_data)
+{
+ unsigned int i;
+
+ deathmatch = settings->deathmatch;
+ ticdup = settings->ticdup;
+ startepisode = settings->episode;
+ startmap = settings->map;
+ startskill = settings->skill;
+ // TODO startloadgame = settings->loadgame;
+ nomonsters = settings->nomonsters;
+ respawnparm = settings->respawn_monsters;
+
+ if (!connect_data->drone)
+ {
+ consoleplayer = settings->consoleplayer;
+ }
+ else
+ {
+ consoleplayer = 0;
+ }
+
+ for (i=0; i<MAXPLAYERS; ++i)
+ {
+ playeringame[i] = i < settings->num_players;
+ }
+}
+
+// Save the game settings from global variables to the specified
+// game settings structure.
+
+static void SaveGameSettings(net_gamesettings_t *settings,
+ net_connect_data_t *connect_data)
+{
+ // Fill in game settings structure with appropriate parameters
+ // for the new game
+
+ settings->deathmatch = deathmatch;
+ settings->episode = startepisode;
+ settings->map = startmap;
+ settings->skill = startskill;
+ // TODO settings->loadgame = startloadgame;
+ settings->gameversion = exe_heretic_1_3;
+ settings->nomonsters = nomonsters;
+ settings->respawn_monsters = respawnparm;
+ settings->timelimit = 0;
+ settings->lowres_turn = false;
+
+ connect_data->drone = false;
+ connect_data->max_players = MAXPLAYERS;
+
+ //
+ // Connect data
+ //
+
+ // Game type fields:
+
+ connect_data->gamemode = gamemode;
+ connect_data->gamemission = gamemission;
+
+ connect_data->lowres_turn = false;
+
+ // Read checksums of our WAD directory and dehacked information
+
+ W_Checksum(connect_data->wad_sha1sum);
+ DEH_Checksum(connect_data->deh_sha1sum);
+
+ connect_data->is_freedoom = 0;
+}
+
+void D_InitSinglePlayerGame(net_gamesettings_t *settings)
+{
+ // default values for single player
+
+ settings->consoleplayer = 0;
+ settings->num_players = 1;
+
+ netgame = false;
+
+ //!
+ // @category net
+ //
+ // Start the game playing as though in a netgame with a single
+ // player. This can also be used to play back single player netgame
+ // demos.
+ //
+
+ if (M_CheckParm("-solo-net") > 0)
+ {
+ netgame = true;
+ }
+}
+
+//
+// D_CheckNetGame
+// Works out player numbers among the net participants
+//
+
+void D_CheckNetGame (void)
+{
+ net_connect_data_t connect_data;
+ net_gamesettings_t settings;
+
+ D_RegisterLoopCallbacks(&doom_loop_interface);
+
+ // Call D_QuitNetGame on exit
+
+ I_AtExit(D_QuitNetGame, true);
+
+ SaveGameSettings(&settings, &connect_data);
+
+ if (D_InitNetGame(&connect_data, &settings))
+ {
+ netgame = true;
+ autostart = true;
+ }
+ else
+ {
+ D_InitSinglePlayerGame(&settings);
+ }
+
+ LoadGameSettings(&settings, &connect_data);
+}
diff --git a/src/heretic/deh_ammo.c b/src/heretic/deh_ammo.c
new file mode 100644
index 00000000..08241863
--- /dev/null
+++ b/src/heretic/deh_ammo.c
@@ -0,0 +1,122 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// Parses "Ammo" sections in dehacked files
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "doomdef.h"
+#include "doomtype.h"
+#include "deh_defs.h"
+#include "deh_io.h"
+#include "deh_main.h"
+#include "p_local.h"
+
+static void *DEH_AmmoStart(deh_context_t *context, char *line)
+{
+ int ammo_number = 0;
+
+ if (sscanf(line, "Ammo %i", &ammo_number) != 1)
+ {
+ DEH_Warning(context, "Parse error on section start");
+ return NULL;
+ }
+
+ if (ammo_number < 0 || ammo_number >= NUMAMMO)
+ {
+ DEH_Warning(context, "Invalid ammo number: %i", ammo_number);
+ return NULL;
+ }
+
+ return &maxammo[ammo_number];
+}
+
+static void DEH_AmmoParseLine(deh_context_t *context, char *line, void *tag)
+{
+ char *variable_name, *value;
+ int ivalue;
+ int ammo_number;
+
+ if (tag == NULL)
+ return;
+
+ ammo_number = ((int *) tag) - maxammo;
+
+ // Parse the assignment
+
+ if (!DEH_ParseAssignment(line, &variable_name, &value))
+ {
+ // Failed to parse
+
+ DEH_Warning(context, "Failed to parse assignment");
+ return;
+ }
+
+ ivalue = atoi(value);
+
+ if (!strcasecmp(variable_name, "Per ammo"))
+ {
+ // Heretic doesn't have a "per clip" ammo array, instead
+ // it is per weapon. However, the weapon number lines
+ // up with the ammo number if we add one.
+
+ GetWeaponAmmo[ammo_number + 1] = ivalue;
+ }
+ else if (!strcasecmp(variable_name, "Max ammo"))
+ {
+ maxammo[ammo_number] = ivalue;
+ }
+ else
+ {
+ DEH_Warning(context, "Field named '%s' not found", variable_name);
+ }
+}
+
+static void DEH_AmmoSHA1Hash(sha1_context_t *context)
+{
+ int i;
+
+ for (i=0; i<NUMAMMO; ++i)
+ {
+ SHA1_UpdateInt32(context, maxammo[i]);
+ }
+
+ for (i=0; i<NUMWEAPONS; ++i)
+ {
+ SHA1_UpdateInt32(context, GetWeaponAmmo[i]);
+ }
+}
+
+deh_section_t deh_section_ammo =
+{
+ "Ammo",
+ NULL,
+ DEH_AmmoStart,
+ DEH_AmmoParseLine,
+ NULL,
+ DEH_AmmoSHA1Hash,
+};
+
diff --git a/src/heretic/deh_frame.c b/src/heretic/deh_frame.c
new file mode 100644
index 00000000..4a1581a7
--- /dev/null
+++ b/src/heretic/deh_frame.c
@@ -0,0 +1,344 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// Parses "Frame" sections in dehacked files
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "doomtype.h"
+#include "info.h"
+
+#include "deh_defs.h"
+#include "deh_io.h"
+#include "deh_main.h"
+#include "deh_mapping.h"
+#include "deh_htic.h"
+
+#include "p_action.h"
+
+typedef struct
+{
+ int offsets[deh_hhe_num_versions];
+ void (*func)();
+} hhe_action_pointer_t;
+
+// Offsets of action pointers within the Heretic executables.
+// Different versions have different offsets.
+// (Seriously Greg, was this really necessary? What was wrong with the
+// "copying action pointer from another frame" technique used in dehacked?)
+
+// Offset Action function
+// v1.0 v1.2 v1.3
+
+static const hhe_action_pointer_t action_pointers[] =
+{
+ { { 77680, 80144, 80208 }, A_AccTeleGlitter },
+ { { 78608, 81104, 81168 }, A_AddPlayerCorpse },
+ { { 115808, 118000, 118240 }, A_AddPlayerRain },
+ { { 112272, 114480, 114720 }, A_BeakAttackPL1 },
+ { { 112448, 114656, 114896 }, A_BeakAttackPL2 },
+ { { 111856, 114176, 114416 }, A_BeakRaise },
+ { { 111568, 113888, 114128 }, A_BeakReady },
+ { { 74640, 77120, 77184 }, A_BeastAttack },
+ { { 70480, 72992, 73056 }, A_BeastPuff },
+ { { 73120, 75600, 75664 }, A_BlueSpark },
+ { { 115456, 117648, 117888 }, A_BoltSpark },
+ { { 77344, 79808, 79872 }, A_BossDeath },
+ { { 69328, 71856, 71920 }, A_Chase },
+ { { 0, 80976, 81040 }, A_CheckBurnGone },
+ { { 78480, 80944, 81008 }, A_CheckSkullDone },
+ { { 78448, 80912, 80976 }, A_CheckSkullFloor },
+ { { 71376, 73888, 73952 }, A_ChicAttack },
+ { { 71488, 74000, 74064 }, A_ChicChase },
+ { { 71456, 73968, 74032 }, A_ChicLook },
+ { { 71520, 74032, 74096 }, A_ChicPain },
+ { { 75792, 78208, 78272 }, A_ClinkAttack },
+ { { 108432, 110816, 111056 }, A_ContMobjSound },
+ { { 114752, 116944, 117184 }, A_DeathBallImpact },
+ { { 70016, 72528, 72592 }, A_DripBlood },
+ { { 77472, 79936, 80000 }, A_ESound },
+ { { 76784, 79248, 79312 }, A_Explode },
+ { { 69872, 72400, 72464 }, A_FaceTarget },
+ { { 71568, 74080, 74144 }, A_Feathers },
+ { { 112928, 115136, 115376 }, A_FireBlasterPL1 },
+ { { 113072, 115280, 115520 }, A_FireBlasterPL2 },
+ { { 115232, 117424, 117664 }, A_FireCrossbowPL1 },
+ { { 115312, 117504, 117744 }, A_FireCrossbowPL2 },
+ { { 113152, 115360, 115600 }, A_FireGoldWandPL1 },
+ { { 113296, 115504, 115744 }, A_FireGoldWandPL2 },
+ { { 113760, 115968, 116208 }, A_FireMacePL1 },
+ { { 114624, 116816, 117056 }, A_FireMacePL2 },
+ { { 116368, 118544, 118784 }, A_FirePhoenixPL1 },
+ { { 116736, 118896, 119136 }, A_FirePhoenixPL2 },
+ { { 115568, 117760, 118000 }, A_FireSkullRodPL1 },
+ { { 115648, 117840, 118080 }, A_FireSkullRodPL2 },
+ { { 117120, 119280, 119520 }, A_FlameEnd },
+ { { 78704, 81200, 81264 }, A_FlameSnd },
+ { { 117152, 119312, 119552 }, A_FloatPuff },
+ { { 78512, 81008, 81072 }, A_FreeTargMobj },
+ { { 117184, 119344, 119584 }, A_GauntletAttack },
+ { { 73232, 75712, 75776 }, A_GenWizard },
+ { { 75872, 78304, 78368 }, A_GhostOff },
+ { { 74752, 77232, 77296 }, A_HeadAttack },
+ { { 75488, 77984, 78048 }, A_HeadFireGrow },
+ { { 75328, 77824, 77888 }, A_HeadIceImpact },
+ { { 116336, 118512, 118752 }, A_HideInCeiling },
+ { { 78736, 81232, 81296 }, A_HideThing },
+ { { 70976, 73488, 73552 }, A_ImpDeath },
+ { { 70304, 72816, 72880 }, A_ImpExplode },
+ { { 70592, 73104, 73168 }, A_ImpMeAttack },
+ { { 70672, 73184, 73248 }, A_ImpMsAttack },
+ { { 70880, 73392, 73456 }, A_ImpMsAttack2 },
+ { { 71024, 73536, 73600 }, A_ImpXDeath1 },
+ { { 71072, 73584, 73648 }, A_ImpXDeath2 },
+ { { 77728, 80192, 80256 }, A_InitKeyGizmo },
+ { { 116720, 118880, 119120 }, A_InitPhoenixPL2 },
+ { { 70160, 72672, 72736 }, A_KnightAttack },
+ { { 117648, 119824, 120064 }, A_Light0 },
+ { { 69200, 71728, 71792 }, A_Look },
+ { { 111760, 114080, 114320 }, A_Lower },
+ { { 114032, 116224, 116464 }, A_MaceBallImpact },
+ { { 114192, 116384, 116624 }, A_MaceBallImpact2 },
+ { { 113904, 116112, 116352 }, A_MacePL1Check },
+ { { 77104, 79568, 79632 }, A_MakePod },
+ { { 73648, 76128, 76192 }, A_MinotaurAtk1 },
+ { { 74112, 76592, 76656 }, A_MinotaurAtk2 },
+ { { 74352, 76832, 76896 }, A_MinotaurAtk3 },
+ { { 74032, 76512, 76576 }, A_MinotaurCharge },
+ { { 73760, 76240, 76304 }, A_MinotaurDecide },
+ { { 74528, 77008, 77072 }, A_MntrFloorFire },
+ { { 71808, 74288, 74352 }, A_MummyAttack },
+ { { 71920, 74400, 74464 }, A_MummyAttack2 },
+ { { 72016, 74496, 74560 }, A_MummyFX1Seek },
+ { { 72048, 74528, 74592 }, A_MummySoul },
+ { { 76400, 78832, 78896 }, A_NoBlocking },
+ { { 69984, 72496, 72560 }, A_Pain },
+ { { 116496, 118656, 118896 }, A_PhoenixPuff },
+ { { 76896, 79360, 79424 }, A_PodPain },
+ { { 116272, 118448, 118688 }, A_RainImpact },
+ { { 111920, 114240, 114480 }, A_Raise },
+ { { 111696, 114016, 114256 }, A_ReFire },
+ { { 77056, 79520, 79584 }, A_RemovePod },
+ { { 116480, 0, 0 }, A_RemovedPhoenixFunc },
+ { { 81952, 84464, 84528 }, A_RestoreArtifact },
+ { { 82048, 84544, 84608 }, A_RestoreSpecialThing1 },
+ { { 82128, 84592, 84656 }, A_RestoreSpecialThing2 },
+ { { 76144, 78576, 78640 }, A_Scream },
+ { { 117104, 119264, 119504 }, A_ShutdownPhoenixPL2 },
+ { { 78288, 80752, 80816 }, A_SkullPop },
+ { { 115776, 117968, 118208 }, A_SkullRodPL2Seek },
+ { { 115984, 118176, 118416 }, A_SkullRodStorm },
+ { { 75632, 78048, 78112 }, A_SnakeAttack },
+ { { 75712, 78128, 78192 }, A_SnakeAttack2 },
+ { { 72144, 74624, 74688 }, A_Sor1Chase },
+ { { 72096, 74576, 74640 }, A_Sor1Pain },
+ { { 73392, 75872, 75936 }, A_Sor2DthInit },
+ { { 73424, 75904, 75968 }, A_Sor2DthLoop },
+ { { 73584, 76064, 76128 }, A_SorDBon },
+ { { 73552, 76032, 76096 }, A_SorDExp },
+ { { 73520, 76000, 76064 }, A_SorDSph },
+ { { 73488, 75968, 76032 }, A_SorRise },
+ { { 73616, 76096, 76160 }, A_SorSightSnd },
+ { { 73456, 75936, 76000 }, A_SorZap },
+ { { 72480, 74960, 75024 }, A_SorcererRise },
+ { { 115088, 117280, 117520 }, A_SpawnRippers },
+ { { 77520, 79984, 80048 }, A_SpawnTeleGlitter },
+ { { 77600, 80064, 80128 }, A_SpawnTeleGlitter2 },
+ { { 72192, 74672, 74736 }, A_Srcr1Attack },
+ { { 72896, 75376, 75440 }, A_Srcr2Attack },
+ { { 72816, 75296, 75360 }, A_Srcr2Decide },
+ { { 112640, 114848, 115088 }, A_StaffAttackPL1 },
+ { { 112784, 114992, 115232 }, A_StaffAttackPL2 },
+ { { 78752, 81248, 81312 }, A_UnHideThing },
+ { { 78080, 80544, 80608 }, A_VolcBallImpact },
+ { { 77856, 80320, 80384 }, A_VolcanoBlast },
+ { { 77824, 80288, 80352 }, A_VolcanoSet },
+ { { 111168, 113488, 113728 }, A_WeaponReady },
+ { { 75168, 77664, 77728 }, A_WhirlwindSeek },
+ { { 75888, 78320, 78384 }, A_WizAtk1 },
+ { { 75920, 78352, 78416 }, A_WizAtk2 },
+ { { 75952, 78384, 78448 }, A_WizAtk3 },
+};
+
+DEH_BEGIN_MAPPING(state_mapping, state_t)
+ DEH_MAPPING("Sprite number", sprite)
+ DEH_MAPPING("Sprite subnumber", frame)
+ DEH_MAPPING("Duration", tics)
+ DEH_MAPPING("Next frame", nextstate)
+ DEH_MAPPING("Unknown 1", misc1)
+ DEH_MAPPING("Unknown 2", misc2)
+DEH_END_MAPPING
+
+static void DEH_FrameInit(void)
+{
+ // Bit of a hack here:
+ DEH_HereticInit();
+}
+
+static void *DEH_FrameStart(deh_context_t *context, char *line)
+{
+ int frame_number = 0;
+ int mapped_frame_number;
+ state_t *state;
+
+ if (sscanf(line, "Frame %i", &frame_number) != 1)
+ {
+ DEH_Warning(context, "Parse error on section start");
+ return NULL;
+ }
+
+ // Map the HHE frame number (which assumes a Heretic 1.0 state table)
+ // to the internal frame number (which is is the Heretic 1.3 state table):
+
+ mapped_frame_number = DEH_MapHereticFrameNumber(frame_number);
+
+ if (mapped_frame_number < 0 || mapped_frame_number >= DEH_HERETIC_NUMSTATES)
+ {
+ DEH_Warning(context, "Invalid frame number: %i", frame_number);
+ return NULL;
+ }
+
+ state = &states[mapped_frame_number];
+
+ return state;
+}
+
+static boolean GetActionPointerForOffset(int offset, void **result)
+{
+ int i;
+
+ // Special case.
+
+ if (offset == 0)
+ {
+ *result = NULL;
+ return true;
+ }
+
+ for (i=0; i<arrlen(action_pointers); ++i)
+ {
+ if (action_pointers[i].offsets[deh_hhe_version] == offset)
+ {
+ *result = action_pointers[i].func;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// If an invalid action pointer is specified, the patch may be for a
+// different version from the version we are currently set to. Try to
+// suggest a different version to use.
+
+static void SuggestOtherVersions(unsigned int offset)
+{
+ unsigned int i, v;
+
+ for (i=0; i<arrlen(action_pointers); ++i)
+ {
+ for (v=0; v<deh_hhe_num_versions; ++v)
+ {
+ if (action_pointers[i].offsets[v] == offset)
+ {
+ DEH_SuggestHereticVersion(v);
+ }
+ }
+ }
+}
+
+static void DEH_FrameParseLine(deh_context_t *context, char *line, void *tag)
+{
+ state_t *state;
+ char *variable_name, *value;
+ int ivalue;
+
+ if (tag == NULL)
+ return;
+
+ state = (state_t *) tag;
+
+ // Parse the assignment
+
+ if (!DEH_ParseAssignment(line, &variable_name, &value))
+ {
+ // Failed to parse
+
+ DEH_Warning(context, "Failed to parse assignment");
+ return;
+ }
+
+ // all values are integers
+
+ ivalue = atoi(value);
+
+ // Action pointer field is a special case:
+
+ if (!strcasecmp(variable_name, "Action pointer"))
+ {
+ void *func;
+
+ if (!GetActionPointerForOffset(ivalue, &func))
+ {
+ SuggestOtherVersions(ivalue);
+ DEH_Error(context, "Unknown action pointer: %i", ivalue);
+ return;
+ }
+
+ state->action = func;
+ }
+ else
+ {
+ // "Next frame" numbers need to undergo mapping.
+
+ if (!strcasecmp(variable_name, "Next frame"))
+ {
+ ivalue = DEH_MapHereticFrameNumber(ivalue);
+ }
+
+ DEH_SetMapping(context, &state_mapping, state, variable_name, ivalue);
+ }
+}
+
+static void DEH_FrameSHA1Sum(sha1_context_t *context)
+{
+ int i;
+
+ for (i=0; i<NUMSTATES; ++i)
+ {
+ DEH_StructSHA1Sum(context, &state_mapping, &states[i]);
+ }
+}
+
+deh_section_t deh_section_frame =
+{
+ "Frame",
+ DEH_FrameInit,
+ DEH_FrameStart,
+ DEH_FrameParseLine,
+ NULL,
+ DEH_FrameSHA1Sum,
+};
+
diff --git a/src/heretic/deh_htext.c b/src/heretic/deh_htext.c
new file mode 100644
index 00000000..5dfddac3
--- /dev/null
+++ b/src/heretic/deh_htext.c
@@ -0,0 +1,856 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005-2010 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// Parses Text substitution sections in dehacked files
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <string.h>
+
+#include "doomtype.h"
+#include "dstrings.h"
+
+#include "z_zone.h"
+
+#include "deh_defs.h"
+#include "deh_io.h"
+#include "deh_htic.h"
+#include "deh_main.h"
+
+//
+// Ok, Greg, the action pointers thing was bad enough, but this really
+// takes the biscuit. Why does HHE's text replacement address strings
+// by offset??!! The dehacked way was much nicer, why change it?
+//
+
+typedef struct
+{
+ unsigned int offsets[deh_hhe_num_versions];
+ char *string;
+} hhe_string_t;
+
+// Offsets String
+// v1.0 v1.2 v1.3
+
+static const hhe_string_t strings[] =
+{
+ { { 228, 228, 228 }, "PLAYPAL" },
+ { { 1240, 1252, 1252 }, "E1M1: THE DOCKS" },
+ { { 1260, 1272, 1272 }, "E1M2: THE DUNGEONS" },
+ { { 1280, 1292, 1292 }, "E1M3: THE GATEHOUSE" },
+ { { 1304, 1316, 1316 }, "E1M4: THE GUARD TOWER" },
+ { { 1328, 1340, 1340 }, "E1M5: THE CITADEL" },
+ { { 1348, 1360, 1360 }, "E1M6: THE CATHEDRAL" },
+ { { 1372, 1384, 1384 }, "E1M7: THE CRYPTS" },
+ { { 1392, 1404, 1404 }, "E1M8: HELL'S MAW" },
+ { { 1412, 1424, 1424 }, "E1M9: THE GRAVEYARD" },
+ { { 1436, 1448, 1448 }, "E2M1: THE CRATER" },
+ { { 1456, 1468, 1468 }, "E2M2: THE LAVA PITS" },
+ { { 1480, 1492, 1492 }, "E2M3: THE RIVER OF FIRE" },
+ { { 1508, 1520, 1520 }, "E2M4: THE ICE GROTTO" },
+ { { 1532, 1544, 1544 }, "E2M5: THE CATACOMBS" },
+ { { 1556, 1568, 1568 }, "E2M6: THE LABYRINTH" },
+ { { 1580, 1592, 1592 }, "E2M7: THE GREAT HALL" },
+ { { 1604, 1616, 1616 }, "E2M8: THE PORTALS OF CHAOS" },
+ { { 1632, 1644, 1644 }, "E2M9: THE GLACIER" },
+ { { 1652, 1664, 1664 }, "E3M1: THE STOREHOUSE" },
+ { { 1676, 1688, 1688 }, "E3M2: THE CESSPOOL" },
+ { { 1696, 1708, 1708 }, "E3M3: THE CONFLUENCE" },
+ { { 1720, 1732, 1732 }, "E3M4: THE AZURE FORTRESS" },
+ { { 1748, 1760, 1760 }, "E3M5: THE OPHIDIAN LAIR" },
+ { { 1776, 1788, 1788 }, "E3M6: THE HALLS OF FEAR" },
+ { { 1804, 1816, 1816 }, "E3M7: THE CHASM" },
+ { { 1824, 1836, 1836 }, "E3M8: D'SPARIL'S KEEP" },
+ { { 1848, 1860, 1860 }, "E3M9: THE AQUIFER" },
+ { { 0, 1880, 1880 }, "E4M1: CATAFALQUE" },
+ { { 0, 1900, 1900 }, "E4M2: BLOCKHOUSE" },
+ { { 0, 1920, 1920 }, "E4M3: AMBULATORY" },
+ { { 0, 1940, 1940 }, "E4M4: SEPULCHER" },
+ { { 0, 1960, 1960 }, "E4M5: GREAT STAIR" },
+ { { 0, 1980, 1980 }, "E4M6: HALLS OF THE APOSTATE" },
+ { { 0, 2012, 2012 }, "E4M7: RAMPARTS OF PERDITION" },
+ { { 0, 2044, 2044 }, "E4M8: SHATTERED BRIDGE" },
+ { { 0, 2068, 2068 }, "E4M9: MAUSOLEUM" },
+ { { 0, 2088, 2088 }, "E5M1: OCHRE CLIFFS" },
+ { { 0, 2108, 2108 }, "E5M2: RAPIDS" },
+ { { 0, 2124, 2124 }, "E5M3: QUAY" },
+ { { 0, 2136, 2136 }, "E5M4: COURTYARD" },
+ { { 0, 2156, 2156 }, "E5M5: HYDRATYR" },
+ { { 0, 2172, 2172 }, "E5M6: COLONNADE" },
+ { { 0, 2192, 2192 }, "E5M7: FOETID MANSE" },
+ { { 0, 2212, 2212 }, "E5M8: FIELD OF JUDGEMENT" },
+ { { 0, 2240, 2240 }, "E5M9: SKEIN OF D'SPARIL" },
+ { { 1868, 2268, 2268 }, "AUTOPAGE" },
+ { { 1880, 2280, 2280 }, "FOLLOW MODE ON" },
+ { { 1896, 2296, 2296 }, "FOLLOW MODE OFF" },
+ { { 1924, 2324, 2324 }, "GREEN: " },
+ { { 1936, 2336, 2336 }, "YELLOW: " },
+ { { 1948, 2348, 2348 }, "RED: " },
+ { { 1956, 2356, 2356 }, "BLUE: " },
+ { { 1964, 2364, 2364 }, "FONTA_S" },
+ { { 1972, 2372, 2372 }, "-MESSAGE SENT-" },
+ { { 1988, 2388, 2388 }, "THERE ARE NO OTHER PLAYERS IN THE GAME!" },
+ { { 2028, 2428, 2428 }, "FONTA59" },
+ { { 2036, 2504, 2504 }, "PAUSED" },
+ { { 2072, 2540, 2540 }, "ADVISOR" },
+ { { 2080, 2548, 2548 }, "TITLE" },
+ { { 2088, 2556, 2556 }, "demo1" },
+ { { 2096, 2564, 2564 }, "CREDIT" },
+ { { 2104, 2572, 2572 }, "demo2" },
+ { { 2112, 2580, 2580 }, "ORDER" },
+ { { 2120, 2588, 2588 }, "demo3" },
+ { { 2304, 2696, 2696 }, "Exited from HERETIC.\n" },
+ { { 2412, 2800, 2800 }, "c:\\heretic.cd" },
+ { { 2528, 2916, 2916 }, "Playing demo %s.lmp.\n" },
+ { { 2592, 2980, 2980 }, "V_Init: allocate screens.\n" },
+ { { 2620, 3008, 3008 }, "M_LoadDefaults: Load system defaults.\n" },
+ { { 2660, 3048, 3048 }, "Z_Init: Init zone memory allocation daemon.\n" },
+ { { 2708, 3096, 3096 }, "W_Init: Init WADfiles.\n" },
+ { { 2732, 3120, 3120 }, "E2M1" },
+ { { 0, 3128, 3128 }, "EXTENDED" },
+ { { 2740, 3140, 3140 }, "LOADING" },
+ { { 2748, 3148, 3148 }, "DeathMatch..." },
+ { { 2764, 3164, 3164 }, "No Monsters..." },
+ { { 2780, 3180, 3180 }, "Respawning..." },
+ { { 2796, 3196, 3196 }, "Warp to Episode %d, Map %d, Skill %d " },
+ { { 2836, 3236, 3236 }, "MN_Init: Init menu system.\n" },
+ { { 2864, 3264, 3264 }, "R_Init: Init Heretic refresh daemon." },
+ { { 2904, 3304, 3304 }, "Loading graphics" },
+ { { 2924, 3324, 3324 }, "P_Init: Init Playloop state." },
+ { { 2956, 3356, 3356 }, "Init game engine." },
+ { { 2976, 3376, 3376 }, "I_Init: Setting up machine state.\n" },
+ { { 3012, 3412, 3412 }, "D_CheckNetGame: Checking network game status.\n" },
+ { { 3060, 3460, 3460 }, "Checking network game status." },
+ { { 3092, 3492, 3492 }, "SB_Init: Loading patches.\n" },
+ { { 0, 3752, 3752 }, "PLAYER 1 LEFT THE GAME" },
+ { { 3508, 3932, 3932 }, "Network game synchronization aborted." },
+ { { 0, 3972, 3972 }, "Different DOOM versions cannot play a net game!" },
+ { { 3908, 4132, 4132 }, "SKY1" },
+ { { 3916, 4140, 4140 }, "SKY2" },
+ { { 3924, 4148, 4148 }, "SKY3" },
+ { { 3736, 4196, 4196 }, "NET GAME" },
+ { { 3748, 4208, 4208 }, "SAVE GAME" },
+ { { 3760, 4220, 4220 }, "Only %i deathmatch spots, 4 required" },
+ { { 3800, 4260, 4260 }, "version %i" },
+ { { 3828, 4372, 4372 }, "c:\\heretic.cd\\hticsav%d.hsg" },
+ { { 3856, 4400, 4400 }, "hticsav%d.hsg" },
+ { { 3896, 4416, 4416 }, "GAME SAVED" },
+ { { 4016, 4456, 4456 }, E1TEXT },
+ { { 4536, 4976, 4976 }, E2TEXT },
+ { { 5068, 5508, 5508 }, E3TEXT },
+ { { 0, 6072, 6072 }, E4TEXT },
+ { { 0, 6780, 6780 }, E5TEXT },
+ { { 5632, 7468, 7468 }, "FLOOR25" },
+ { { 5640, 7476, 7476 }, "FLATHUH1" },
+ { { 5652, 7488, 7488 }, "FLTWAWA2" },
+ { { 0, 7500, 7500 }, "FLOOR28" },
+ { { 0, 7508, 7508 }, "FLOOR08" },
+ { { 5664, 7516, 7516 }, "FONTA_S" },
+ { { 5704, 7524, 7524 }, "PLAYPAL" },
+ { { 5672, 7532, 7532 }, "FINAL1" },
+ { { 5680, 7540, 7540 }, "FINAL2" },
+ { { 5688, 7548, 7548 }, "E2PAL" },
+ { { 5696, 7556, 7556 }, "E2END" },
+ { { 7884, 7564, 7564 }, "TITLE" },
+ { { 5712, 7572, 7572 }, "ORDER" },
+ { { 0, 7580, 7580 }, "CREDIT" },
+ { { 5720, 7588, 7588 }, "IMPX" },
+ { { 5728, 7596, 7596 }, "ACLO" },
+ { { 5736, 7604, 7604 }, "PTN1" },
+ { { 5744, 7612, 7612 }, "SHLD" },
+ { { 5752, 7620, 7620 }, "SHD2" },
+ { { 5760, 7628, 7628 }, "BAGH" },
+ { { 5768, 7636, 7636 }, "SPMP" },
+ { { 5776, 7644, 7644 }, "INVS" },
+ { { 5784, 7652, 7652 }, "PTN2" },
+ { { 5792, 7660, 7660 }, "SOAR" },
+ { { 5800, 7668, 7668 }, "INVU" },
+ { { 5808, 7676, 7676 }, "PWBK" },
+ { { 5816, 7684, 7684 }, "EGGC" },
+ { { 5824, 7692, 7692 }, "EGGM" },
+ { { 5832, 7700, 7700 }, "FX01" },
+ { { 5840, 7708, 7708 }, "SPHL" },
+ { { 5848, 7716, 7716 }, "TRCH" },
+ { { 5856, 7724, 7724 }, "FBMB" },
+ { { 5864, 7732, 7732 }, "XPL1" },
+ { { 5872, 7740, 7740 }, "ATLP" },
+ { { 5880, 7748, 7748 }, "PPOD" },
+ { { 5888, 7756, 7756 }, "AMG1" },
+ { { 5896, 7764, 7764 }, "SPSH" },
+ { { 5904, 7772, 7772 }, "LVAS" },
+ { { 5912, 7780, 7780 }, "SLDG" },
+ { { 5920, 7788, 7788 }, "SKH1" },
+ { { 5928, 7796, 7796 }, "SKH2" },
+ { { 5936, 7804, 7804 }, "SKH3" },
+ { { 5944, 7812, 7812 }, "SKH4" },
+ { { 5952, 7820, 7820 }, "CHDL" },
+ { { 5960, 7828, 7828 }, "SRTC" },
+ { { 5968, 7836, 7836 }, "SMPL" },
+ { { 5976, 7844, 7844 }, "STGS" },
+ { { 5984, 7852, 7852 }, "STGL" },
+ { { 5992, 7860, 7860 }, "STCS" },
+ { { 6000, 7868, 7868 }, "STCL" },
+ { { 6008, 7876, 7876 }, "KFR1" },
+ { { 6016, 7884, 7884 }, "BARL" },
+ { { 6024, 7892, 7892 }, "BRPL" },
+ { { 6032, 7900, 7900 }, "MOS1" },
+ { { 6040, 7908, 7908 }, "MOS2" },
+ { { 6048, 7916, 7916 }, "WTRH" },
+ { { 6056, 7924, 7924 }, "HCOR" },
+ { { 6064, 7932, 7932 }, "KGZ1" },
+ { { 6072, 7940, 7940 }, "KGZB" },
+ { { 6080, 7948, 7948 }, "KGZG" },
+ { { 6088, 7956, 7956 }, "KGZY" },
+ { { 6096, 7964, 7964 }, "VLCO" },
+ { { 6104, 7972, 7972 }, "VFBL" },
+ { { 6112, 7980, 7980 }, "VTFB" },
+ { { 6120, 7988, 7988 }, "SFFI" },
+ { { 6128, 7996, 7996 }, "TGLT" },
+ { { 6136, 8004, 8004 }, "TELE" },
+ { { 6144, 8012, 8012 }, "STFF" },
+ { { 6152, 8020, 8020 }, "PUF3" },
+ { { 6160, 8028, 8028 }, "PUF4" },
+ { { 6168, 8036, 8036 }, "BEAK" },
+ { { 6176, 8044, 8044 }, "WGNT" },
+ { { 6184, 8052, 8052 }, "GAUN" },
+ { { 6192, 8060, 8060 }, "PUF1" },
+ { { 6200, 8068, 8068 }, "WBLS" },
+ { { 6208, 8076, 8076 }, "BLSR" },
+ { { 6216, 8084, 8084 }, "FX18" },
+ { { 6224, 8092, 8092 }, "FX17" },
+ { { 6232, 8100, 8100 }, "WMCE" },
+ { { 6240, 8108, 8108 }, "MACE" },
+ { { 6248, 8116, 8116 }, "FX02" },
+ { { 6256, 8124, 8124 }, "WSKL" },
+ { { 6264, 8132, 8132 }, "HROD" },
+ { { 6272, 8140, 8140 }, "FX00" },
+ { { 6280, 8148, 8148 }, "FX20" },
+ { { 6288, 8156, 8156 }, "FX21" },
+ { { 6296, 8164, 8164 }, "FX22" },
+ { { 6304, 8172, 8172 }, "FX23" },
+ { { 6312, 8180, 8180 }, "GWND" },
+ { { 6320, 8188, 8188 }, "PUF2" },
+ { { 6328, 8196, 8196 }, "WPHX" },
+ { { 6336, 8204, 8204 }, "PHNX" },
+ { { 6344, 8212, 8212 }, "FX04" },
+ { { 6352, 8220, 8220 }, "FX08" },
+ { { 6360, 8228, 8228 }, "FX09" },
+ { { 6368, 8236, 8236 }, "WBOW" },
+ { { 6376, 8244, 8244 }, "CRBW" },
+ { { 6384, 8252, 8252 }, "FX03" },
+ { { 6392, 8260, 8260 }, "BLOD" },
+ { { 6400, 8268, 8268 }, "PLAY" },
+ { { 6408, 8276, 8276 }, "FDTH" },
+ { { 6416, 8284, 8284 }, "BSKL" },
+ { { 6424, 8292, 8292 }, "CHKN" },
+ { { 6432, 8300, 8300 }, "MUMM" },
+ { { 6440, 8308, 8308 }, "FX15" },
+ { { 6448, 8316, 8316 }, "BEAS" },
+ { { 6456, 8324, 8324 }, "FRB1" },
+ { { 6464, 8332, 8332 }, "SNKE" },
+ { { 6472, 8340, 8340 }, "SNFX" },
+ { { 6480, 8348, 8348 }, "HEAD" },
+ { { 6488, 8356, 8356 }, "FX05" },
+ { { 6496, 8364, 8364 }, "FX06" },
+ { { 6504, 8372, 8372 }, "FX07" },
+ { { 6512, 8380, 8380 }, "CLNK" },
+ { { 6520, 8388, 8388 }, "WZRD" },
+ { { 6528, 8396, 8396 }, "FX11" },
+ { { 6536, 8404, 8404 }, "FX10" },
+ { { 6544, 8412, 8412 }, "KNIG" },
+ { { 6552, 8420, 8420 }, "SPAX" },
+ { { 6560, 8428, 8428 }, "RAXE" },
+ { { 6568, 8436, 8436 }, "SRCR" },
+ { { 6576, 8444, 8444 }, "FX14" },
+ { { 6584, 8452, 8452 }, "SOR2" },
+ { { 6592, 8460, 8460 }, "SDTH" },
+ { { 6600, 8468, 8468 }, "FX16" },
+ { { 6608, 8476, 8476 }, "MNTR" },
+ { { 6616, 8484, 8484 }, "FX12" },
+ { { 6624, 8492, 8492 }, "FX13" },
+ { { 6632, 8500, 8500 }, "AKYY" },
+ { { 6640, 8508, 8508 }, "BKYY" },
+ { { 6648, 8516, 8516 }, "CKYY" },
+ { { 6656, 8524, 8524 }, "AMG2" },
+ { { 6664, 8532, 8532 }, "AMM1" },
+ { { 6672, 8540, 8540 }, "AMM2" },
+ { { 6680, 8548, 8548 }, "AMC1" },
+ { { 6688, 8556, 8556 }, "AMC2" },
+ { { 6696, 8564, 8564 }, "AMS1" },
+ { { 6704, 8572, 8572 }, "AMS2" },
+ { { 6712, 8580, 8580 }, "AMP1" },
+ { { 6720, 8588, 8588 }, "AMP2" },
+ { { 6728, 8596, 8596 }, "AMB1" },
+ { { 6736, 8604, 8604 }, "AMB2" },
+ { { 6744, 8612, 8612 }, "K" },
+ { { 6748, 8616, 8616 }, "I" },
+ { { 6752, 8620, 8620 }, "L" },
+ { { 6756, 8624, 8624 }, "E" },
+ { { 6760, 8628, 8628 }, "R" },
+ { { 6764, 8632, 8632 }, "S" },
+ { { 6768, 8636, 8636 }, "PLAYPAL" },
+ { { 6776, 8644, 8644 }, "MAPE1" },
+ { { 6784, 8652, 8652 }, "MAPE2" },
+ { { 6792, 8660, 8660 }, "MAPE3" },
+ { { 6800, 8668, 8668 }, "IN_X" },
+ { { 6808, 8676, 8676 }, "IN_YAH" },
+ { { 6816, 8684, 8684 }, "FONTB16" },
+ { { 6824, 8692, 8692 }, "FONTB_S" },
+ { { 6832, 8700, 8700 }, "FONTB13" },
+ { { 6840, 8708, 8708 }, "FONTB15" },
+ { { 6848, 8716, 8716 }, "FONTB05" },
+ { { 6856, 8724, 8724 }, "FACEA0" },
+ { { 6864, 8732, 8732 }, "FACEB0" },
+ { { 6940, 8808, 8808 }, "FLOOR16" },
+ { { 6948, 8816, 8816 }, "FINISHED" },
+ { { 6960, 8828, 8828 }, "NOW ENTERING:" },
+ { { 6976, 8844, 8844 }, "KILLS" },
+ { { 6984, 8852, 8852 }, "ITEMS" },
+ { { 6992, 8860, 8860 }, "SECRETS" },
+ { { 7000, 8868, 8868 }, "TIME" },
+ { { 7008, 8876, 8876 }, "BONUS" },
+ { { 7016, 8884, 8884 }, "SECRET" },
+ { { 7024, 8892, 8892 }, "TOTAL" },
+ { { 7032, 8900, 8900 }, "VICTIMS" },
+ { { 7040, 8908, 8908 }, ":" },
+ { { 7044, 8912, 8912 }, "NEW GAME" },
+ { { 7056, 8924, 8924 }, "OPTIONS" },
+ { { 7064, 8932, 8932 }, "GAME FILES" },
+ { { 7076, 8944, 8944 }, "INFO" },
+ { { 7084, 8952, 8952 }, "QUIT GAME" },
+ { { 7096, 8964, 8964 }, "CITY OF THE DAMNED" },
+ { { 7116, 8984, 8984 }, "HELL'S MAW" },
+ { { 7128, 8996, 8996 }, "THE DOME OF D'SPARIL" },
+ { { 0, 9020, 9020 }, "THE OSSUARY" },
+ { { 0, 9032, 9032 }, "THE STAGNANT DEMESNE" },
+ { { 7152, 9056, 9056 }, "LOAD GAME" },
+ { { 7164, 9068, 9068 }, "SAVE GAME" },
+ { { 7176, 9080, 9080 }, "THOU NEEDETH A WET-NURSE" },
+ { { 7204, 9108, 9108 }, "YELLOWBELLIES-R-US" },
+ { { 7224, 9128, 9128 }, "BRINGEST THEM ONETH" },
+ { { 7244, 9148, 9148 }, "THOU ART A SMITE-MEISTER" },
+ { { 7272, 9176, 9176 }, "BLACK PLAGUE POSSESSES THEE" },
+ { { 7300, 9204, 9204 }, "END GAME" },
+ { { 7312, 9216, 9216 }, "MESSAGES : " },
+ { { 7324, 9228, 9228 }, "MOUSE SENSITIVITY" },
+ { { 7344, 9248, 9248 }, "MORE..." },
+ { { 7352, 9256, 9256 }, "SCREEN SIZE" },
+ { { 7364, 9268, 9268 }, "SFX VOLUME" },
+ { { 7376, 9280, 9280 }, "MUSIC VOLUME" },
+ { { 7416, 9296, 9296 }, "ARE YOU SURE YOU WANT TO QUIT?" },
+ { { 7448, 9328, 9328 }, "ARE YOU SURE YOU WANT TO END THE GAME?" },
+ { { 7488, 9368, 9368 }, "DO YOU WANT TO QUICKSAVE THE GAME NAMED" },
+ { { 7528, 9408, 9408 }, "DO YOU WANT TO QUICKLOAD THE GAME NAMED" },
+ { { 7392, 9448, 9448 }, "M_SKL00" },
+ { { 7400, 9456, 9456 }, "FONTA_S" },
+ { { 7408, 9464, 9464 }, "FONTB_S" },
+ { { 7568, 9472, 9472 }, "?" },
+ { { 7572, 9476, 9476 }, "M_SLCTR1" },
+ { { 7584, 9488, 9488 }, "M_SLCTR2" },
+ { { 7596, 9500, 9500 }, "M_HTIC" },
+ { { 7604, 9508, 9508 }, "c:\\heretic.cd\\hticsav%d.hsg" },
+ { { 7632, 9536, 9536 }, "hticsav%d.hsg" },
+ { { 7652, 9556, 9556 }, "M_FSLOT" },
+ { { 7660, 9564, 9564 }, "ON" },
+ { { 7664, 9568, 9568 }, "OFF" },
+ { { 0, 9572, 9572 }, "YOU CAN'T START A NEW GAME IN NETPLAY!" },
+ { { 0, 9612, 9612 }, "YOU CAN'T LOAD A GAME IN NETPLAY!" },
+ { { 7668, 9648, 9648 }, "MESSAGES ON" },
+ { { 7680, 9660, 9660 }, "MESSAGES OFF" },
+ { { 7748, 9676, 9676 }, "ONLY AVAILABLE IN THE REGISTERED VERSION" },
+ { { 7792, 9720, 9720 }, "PLAYPAL" },
+ { { 7800, 9728, 9728 }, "QUICKSAVING...." },
+ { { 7816, 9744, 9744 }, "QUICKLOADING...." },
+ { { 7836, 9764, 9764 }, "CHOOSE A QUICKSAVE SLOT" },
+ { { 7860, 9788, 9788 }, "CHOOSE A QUICKLOAD SLOT" },
+ { { 0, 9812, 9812 }, "TITLE" },
+ { { 7892, 9820, 9820 }, "M_SLDLT" },
+ { { 7900, 9828, 9828 }, "M_SLDMD1" },
+ { { 7912, 9840, 9840 }, "M_SLDMD2" },
+ { { 7924, 9852, 9852 }, "M_SLDRT" },
+ { { 7932, 9860, 9860 }, "M_SLDKB" },
+ { { 9016, 10944, 10944 }, "SCREEN SHOT" },
+ { { 9028, 10956, 10956 }, "YOU NEED A BLUE KEY TO OPEN THIS DOOR" },
+ { { 9068, 10996, 10996 }, "YOU NEED A YELLOW KEY TO OPEN THIS DOOR" },
+ { { 9108, 11036, 11036 }, "YOU NEED A GREEN KEY TO OPEN THIS DOOR" },
+ { { 9244, 11172, 11172 }, "CRYSTAL VIAL" },
+ { { 9260, 11188, 11188 }, "SILVER SHIELD" },
+ { { 9276, 11204, 11204 }, "ENCHANTED SHIELD" },
+ { { 9296, 11224, 11224 }, "BAG OF HOLDING" },
+ { { 9312, 11240, 11240 }, "MAP SCROLL" },
+ { { 9324, 11252, 11252 }, "BLUE KEY" },
+ { { 9336, 11264, 11264 }, "YELLOW KEY" },
+ { { 9348, 11276, 11276 }, "GREEN KEY" },
+ { { 9360, 11288, 11288 }, "QUARTZ FLASK" },
+ { { 9376, 11304, 11304 }, "WINGS OF WRATH" },
+ { { 9392, 11320, 11320 }, "RING OF INVINCIBILITY" },
+ { { 9416, 11344, 11344 }, "TOME OF POWER" },
+ { { 9432, 11360, 11360 }, "SHADOWSPHERE" },
+ { { 9448, 11376, 11376 }, "MORPH OVUM" },
+ { { 9460, 11388, 11388 }, "MYSTIC URN" },
+ { { 9472, 11400, 11400 }, "TORCH" },
+ { { 9480, 11408, 11408 }, "TIME BOMB OF THE ANCIENTS" },
+ { { 9508, 11436, 11436 }, "CHAOS DEVICE" },
+ { { 9524, 11452, 11452 }, "WAND CRYSTAL" },
+ { { 9540, 11468, 11468 }, "CRYSTAL GEODE" },
+ { { 9556, 11484, 11484 }, "MACE SPHERES" },
+ { { 9572, 11500, 11500 }, "PILE OF MACE SPHERES" },
+ { { 9596, 11524, 11524 }, "ETHEREAL ARROWS" },
+ { { 9612, 11540, 11540 }, "QUIVER OF ETHEREAL ARROWS" },
+ { { 9640, 11568, 11568 }, "CLAW ORB" },
+ { { 9652, 11580, 11580 }, "ENERGY ORB" },
+ { { 9664, 11592, 11592 }, "LESSER RUNES" },
+ { { 9680, 11608, 11608 }, "GREATER RUNES" },
+ { { 9696, 11624, 11624 }, "FLAME ORB" },
+ { { 9708, 11636, 11636 }, "INFERNO ORB" },
+ { { 9720, 11648, 11648 }, "FIREMACE" },
+ { { 9732, 11660, 11660 }, "ETHEREAL CROSSBOW" },
+ { { 9752, 11680, 11680 }, "DRAGON CLAW" },
+ { { 9764, 11692, 11692 }, "HELLSTAFF" },
+ { { 9776, 11704, 11704 }, "PHOENIX ROD" },
+ { { 9788, 11716, 11716 }, "GAUNTLETS OF THE NECROMANCER" },
+ { { 10088, 12016, 12016 }, "FLTWAWA1" },
+ { { 10100, 12028, 12028 }, "FLTFLWW1" },
+ { { 10112, 12040, 12040 }, "FLTLAVA1" },
+ { { 10124, 12052, 12052 }, "FLATHUH1" },
+ { { 10136, 12064, 12064 }, "FLTSLUD1" },
+ { { 10148, 12076, 12076 }, "END" },
+ { { 10236, 12164, 12164 }, "texture2" },
+ { { 10444, 12372, 12372 }, "PLAYPAL" },
+ { { 10596, 12488, 12488 }, "PNAMES" },
+ { { 10604, 12496, 12496 }, "TEXTURE1" },
+ { { 10616, 12508, 12508 }, "TEXTURE2" },
+ { { 10628, 12520, 12520 }, "S_END" },
+ { { 10636, 12528, 12528 }, "S_START" },
+ { { 10728, 12620, 12620 }, "F_START" },
+ { { 10736, 12628, 12628 }, "F_END" },
+ { { 10744, 12636, 12636 }, "COLORMAP" },
+ { { 10756, 12648, 12648 }, "\nR_InitTextures " },
+ { { 10776, 12668, 12668 }, "R_InitFlats\n" },
+ { { 10792, 12684, 12684 }, "R_InitSpriteLumps " },
+ { { 10948, 12772, 12772 }, "TINTTAB" },
+ { { 10984, 12780, 12780 }, "FLOOR04" },
+ { { 10992, 12788, 12788 }, "FLAT513" },
+ { { 11000, 12796, 12796 }, "bordt" },
+ { { 11008, 12804, 12804 }, "bordb" },
+ { { 11016, 12812, 12812 }, "bordl" },
+ { { 11024, 12820, 12820 }, "bordr" },
+ { { 11032, 12828, 12828 }, "bordtl" },
+ { { 11040, 12836, 12836 }, "bordtr" },
+ { { 11048, 12844, 12844 }, "bordbr" },
+ { { 11056, 12852, 12852 }, "bordbl" },
+ { { 11064, 12860, 12860 }, "R_InitData " },
+ { { 11076, 12872, 12872 }, "R_InitPointToAngle\n" },
+ { { 11096, 12892, 12892 }, "R_InitTables " },
+ { { 11112, 12908, 12908 }, "R_InitPlanes\n" },
+ { { 11128, 12924, 12924 }, "R_InitLightTables " },
+ { { 11148, 12944, 12944 }, "R_InitSkyMap\n" },
+ { { 11164, 12960, 12960 }, "F_SKY1" },
+ { { 12120, 13484, 13484 }, "LTFACE" },
+ { { 12128, 13492, 13492 }, "RTFACE" },
+ { { 12136, 13500, 13500 }, "BARBACK" },
+ { { 12144, 13508, 13508 }, "INVBAR" },
+ { { 12152, 13516, 13516 }, "CHAIN" },
+ { { 12160, 13524, 13524 }, "STATBAR" },
+ { { 12168, 13532, 13532 }, "LIFEBAR" },
+ { { 12176, 13540, 13540 }, "LIFEGEM2" },
+ { { 12188, 13552, 13552 }, "LIFEGEM0" },
+ { { 12200, 13564, 13564 }, "LTFCTOP" },
+ { { 12208, 13572, 13572 }, "RTFCTOP" },
+ { { 12224, 13580, 13580 }, "SELECTBOX" },
+ { { 12236, 13592, 13592 }, "INVGEML1" },
+ { { 12248, 13604, 13604 }, "INVGEML2" },
+ { { 12260, 13616, 13616 }, "INVGEMR1" },
+ { { 12272, 13628, 13628 }, "INVGEMR2" },
+ { { 12284, 13640, 13640 }, "BLACKSQ" },
+ { { 12292, 13648, 13648 }, "ARMCLEAR" },
+ { { 12304, 13660, 13660 }, "CHAINBACK" },
+ { { 12316, 13672, 13672 }, "IN0" },
+ { { 12320, 13676, 13676 }, "NEGNUM" },
+ { { 12328, 13684, 13684 }, "FONTB16" },
+ { { 12336, 13692, 13692 }, "SMALLIN0" },
+ { { 12348, 13704, 13704 }, "PLAYPAL" },
+ { { 12356, 13712, 13712 }, "SPINBK0" },
+ { { 12364, 13720, 13720 }, "SPFLY0" },
+ { { 12372, 13728, 13728 }, "LAME" },
+ { { 12380, 13736, 13736 }, "*** SOUND DEBUG INFO ***" },
+ { { 12408, 13764, 13764 }, "NAME" },
+ { { 12416, 13772, 13772 }, "MO.T" },
+ { { 12424, 13780, 13780 }, "MO.X" },
+ { { 12432, 13788, 13788 }, "MO.Y" },
+ { { 12440, 13796, 13796 }, "ID" },
+ { { 12444, 13800, 13800 }, "PRI" },
+ { { 12448, 13804, 13804 }, "DIST" },
+ { { 12456, 13812, 13812 }, "------" },
+ { { 12464, 13820, 13820 }, "%s" },
+ { { 12468, 13824, 13824 }, "%d" },
+ { { 12472, 13828, 13828 }, "GOD1" },
+ { { 12480, 13836, 13836 }, "GOD2" },
+ { { 12488, 13844, 13844 }, "useartia" },
+ { { 12500, 13856, 13856 }, "ykeyicon" },
+ { { 12512, 13868, 13868 }, "gkeyicon" },
+ { { 12524, 13880, 13880 }, "bkeyicon" },
+ { { 12216, 13892, 13892 }, "ARTIBOX" },
+ { { 12536, 13900, 13900 }, "GOD MODE ON" },
+ { { 12548, 13912, 13912 }, "GOD MODE OFF" },
+ { { 12564, 13928, 13928 }, "NO CLIPPING ON" },
+ { { 12580, 13944, 13944 }, "NO CLIPPING OFF" },
+ { { 12596, 13960, 13960 }, "ALL WEAPONS" },
+ { { 12608, 13972, 13972 }, "POWER OFF" },
+ { { 12620, 13984, 13984 }, "POWER ON" },
+ { { 12632, 13996, 13996 }, "FULL HEALTH" },
+ { { 12644, 14008, 14008 }, "ALL KEYS" },
+ { { 12656, 14020, 14020 }, "SOUND DEBUG ON" },
+ { { 12672, 14036, 14036 }, "SOUND DEBUG OFF" },
+ { { 12688, 14052, 14052 }, "TICKER ON" },
+ { { 12700, 14064, 14064 }, "TICKER OFF" },
+ { { 12712, 14076, 14076 }, "CHOOSE AN ARTIFACT ( A - J )" },
+ { { 12744, 14108, 14108 }, "HOW MANY ( 1 - 9 )" },
+ { { 12764, 14128, 14128 }, "YOU GOT IT" },
+ { { 12776, 14140, 14140 }, "BAD INPUT" },
+ { { 12788, 14152, 14152 }, "LEVEL WARP" },
+ { { 12800, 14164, 14164 }, "CHICKEN OFF" },
+ { { 12812, 14176, 14176 }, "CHICKEN ON" },
+ { { 12824, 14188, 14188 }, "MASSACRE" },
+ { { 12836, 14200, 14200 }, "CHEATER - YOU DON'T DESERVE WEAPONS" },
+ { { 12872, 14236, 14236 }, "TRYING TO CHEAT, EH? NOW YOU DIE!" },
+};
+
+// String offsets that are valid but we don't support.
+
+static const int unsupported_strings_1_0[] =
+{
+ 0, 4, 64, 104, 160, 200, 220, 236,
+ 244, 252, 272, 288, 296, 316, 332, 372,
+ 436, 500, 504, 536, 544, 560, 576, 584,
+ 592, 612, 640, 664, 708, 712, 744, 764,
+ 808, 820, 828, 840, 876, 884, 908, 952,
+ 992, 1028, 1036, 1048, 1088, 1128, 1160, 1192,
+ 1212, 1912, 2044, 2056, 2068, 2128, 2140, 2168,
+ 2184, 2196, 2212, 2228, 2240, 2252, 2260, 2264,
+ 2284, 2292, 2296, 2300, 2328, 2340, 2352, 2364,
+ 2372, 2384, 2388, 2404, 2428, 2436, 2444, 2464,
+ 2496, 2508, 2520, 2552, 2564, 2572, 2584, 3120,
+ 3128, 3140, 3184, 3220, 3248, 3252, 3256, 3280,
+ 3304, 3320, 3352, 3380, 3400, 3432, 3464, 3548,
+ 3600, 3624, 3664, 3696, 3812, 3872, 3932, 3940,
+ 3976, 3996, 6872, 6896, 7648, 7696, 7940, 7964,
+ 7968, 7992, 8020, 8028, 8052, 8056, 8076, 8088,
+ 8104, 8116, 8128, 8136, 8148, 8164, 8180, 8192,
+ 8204, 8220, 8232, 8248, 8264, 8276, 8292, 8308,
+ 8320, 8328, 8340, 8352, 8364, 8376, 8392, 8408,
+ 8424, 8436, 8448, 8460, 8472, 8488, 8504, 8520,
+ 8536, 8548, 8560, 8572, 8584, 8596, 8608, 8612,
+ 8624, 8648, 8660, 8668, 8680, 8708, 8720, 8728,
+ 8740, 8752, 8764, 8788, 8800, 8812, 8824, 8848,
+ 8860, 8864, 8868, 8876, 8888, 8896, 8916, 8944,
+ 8948, 8960, 8964, 8968, 8980, 9148, 9172, 9212,
+ 9216, 9220, 9820, 9860, 9892, 9940, 9972, 10012,
+ 10036, 10040, 10052, 10080, 10152, 10192, 10248, 10284,
+ 10320, 10360, 10392, 10452, 10488, 10508, 10556, 10644,
+ 10684, 10812, 10844, 10880, 10912, 10956, 11172, 11200,
+ 11232, 11272, 11312, 11348, 11380, 11404, 11436, 11492,
+ 11548, 11616, 11684, 11748, 11792, 11840, 11896, 11936,
+ 11980, 12028, 12072, 12908, 12924, 12956, 12960, 12968,
+ 12976, 13020, 13048, 13076, 13104, 13136, 13168, 13196,
+ 13240, 13272, 13292, 13296, 13308, 13312, 13320, 13324,
+ 13364, 13408, 13460, 13492, 13516, 13560, 13612, 13664,
+ 13700, 13744, 13796, 13848, 13884, 13940, 13996, 14040,
+ 14084, 14140, 14148, 14156, 14164, 14184, 14192, 14204,
+ 14208, 14212, 14256, 14272, 14284, 14296, 14300, 14312,
+ 14320, 14324, 14348, 14356, 14360, 14372, 14380, 14392,
+ 14432, 14440, 14444, 14472, 14496, 14516, 14536, 14548,
+ 14560, 14572, 14580, 14588, 14596, 14604, 14612, 14620,
+ 14636, 14660, 14704, 14740, 14748, 14756, 14760, 14768,
+ -1,
+};
+
+static const int unsupported_strings_1_2[] =
+{
+ 0, 4, 64, 104, 160, 200, 220, 236,
+ 244, 252, 272, 288, 296, 316, 332, 372,
+ 436, 500, 504, 536, 544, 560, 576, 584,
+ 592, 612, 640, 664, 708, 712, 744, 756,
+ 776, 820, 832, 840, 852, 888, 896, 920,
+ 964, 1004, 1040, 1048, 1060, 1100, 1140, 1172,
+ 1204, 1224, 2312, 2436, 2448, 2464, 2480, 2492,
+ 2512, 2524, 2536, 2596, 2608, 2636, 2652, 2656,
+ 2676, 2684, 2688, 2720, 2732, 2744, 2752, 2764,
+ 2772, 2776, 2792, 2816, 2824, 2832, 2852, 2884,
+ 2896, 2908, 2940, 2952, 2960, 2972, 3520, 3528,
+ 3540, 3584, 3620, 3648, 3652, 3656, 3680, 3704,
+ 3720, 3776, 3804, 3824, 3856, 3888, 4020, 4044,
+ 4084, 4116, 4156, 4272, 4288, 4296, 4332, 4352,
+ 4428, 4432, 8740, 8764, 9552, 9868, 9888, 9900,
+ 9916, 9928, 9940, 9948, 9960, 9976, 9992, 10004,
+ 10016, 10032, 10044, 10060, 10076, 10088, 10104, 10120,
+ 10132, 10140, 10152, 10164, 10176, 10188, 10204, 10220,
+ 10236, 10248, 10260, 10272, 10284, 10300, 10316, 10332,
+ 10348, 10360, 10372, 10384, 10396, 10408, 10420, 10424,
+ 10436, 10460, 10472, 10480, 10492, 10520, 10532, 10540,
+ 10552, 10564, 10576, 10600, 10612, 10624, 10636, 10660,
+ 10672, 10676, 10700, 10704, 10728, 10756, 10764, 10788,
+ 10792, 10796, 10804, 10816, 10824, 10844, 10872, 10876,
+ 10888, 10892, 10896, 10908, 11076, 11100, 11140, 11144,
+ 11148, 11748, 11788, 11820, 11868, 11900, 11940, 11964,
+ 11968, 11980, 12008, 12080, 12120, 12176, 12212, 12248,
+ 12288, 12320, 12380, 12400, 12448, 12536, 12576, 12704,
+ 12736, 12968, 13000, 13024, 13080, 13136, 13204, 13272,
+ 13336, 13380, 13428, 14272, 14288, 14320, 14324, 14332,
+ 14340, 14384, 14412, 14440, 14468, 14500, 14532, 14560,
+ 14604, 14636, 14656, 14696, 14740, 14792, 14824, 14848,
+ 14892, 14944, 14996, 15032, 15076, 15128, 15180, 15216,
+ 15272, 15328, 15372, 15416, 15472, 15480, 15488, 15496,
+ 15516, 15524, 15536, 15540, 15544, 15588, 15604, 15616,
+ 15628, 15632, 15644, 15652, 15656, 15680, 15688, 15692,
+ 15704, 15712, 15724, 15764, 15772, 15776, 15804, 15828,
+ 15848, 15868, 15880, 15892, 15904, 15912, 15920, 15928,
+ 15936, -1,
+};
+
+static const int unsupported_strings_1_3[] =
+{
+ 0, 4, 64, 104, 160, 200, 220, 236,
+ 244, 252, 272, 288, 296, 316, 332, 372,
+ 436, 500, 504, 536, 544, 560, 576, 584,
+ 592, 612, 640, 664, 708, 712, 744, 756,
+ 776, 820, 832, 840, 852, 888, 896, 920,
+ 964, 1004, 1040, 1048, 1060, 1100, 1140, 1172,
+ 1204, 1224, 2312, 2436, 2448, 2464, 2480, 2492,
+ 2512, 2524, 2536, 2596, 2608, 2636, 2652, 2656,
+ 2676, 2684, 2688, 2720, 2732, 2744, 2752, 2764,
+ 2772, 2776, 2792, 2816, 2824, 2832, 2852, 2884,
+ 2896, 2908, 2940, 2952, 2960, 2972, 3520, 3528,
+ 3540, 3584, 3620, 3648, 3652, 3656, 3680, 3704,
+ 3720, 3776, 3804, 3824, 3856, 3888, 4020, 4044,
+ 4084, 4116, 4156, 4272, 4288, 4296, 4332, 4352,
+ 4428, 4432, 8740, 8764, 9552, 9868, 9888, 9900,
+ 9916, 9928, 9940, 9948, 9960, 9976, 9992, 10004,
+ 10016, 10032, 10044, 10060, 10076, 10088, 10104, 10120,
+ 10132, 10140, 10152, 10164, 10176, 10188, 10204, 10220,
+ 10236, 10248, 10260, 10272, 10284, 10300, 10316, 10332,
+ 10348, 10360, 10372, 10384, 10396, 10408, 10420, 10424,
+ 10436, 10460, 10472, 10480, 10492, 10520, 10532, 10540,
+ 10552, 10564, 10576, 10600, 10612, 10624, 10636, 10660,
+ 10672, 10676, 10700, 10704, 10728, 10756, 10764, 10788,
+ 10792, 10796, 10804, 10816, 10824, 10844, 10872, 10876,
+ 10888, 10892, 10896, 10908, 11076, 11100, 11140, 11144,
+ 11148, 11748, 11788, 11820, 11868, 11900, 11940, 11964,
+ 11968, 11980, 12008, 12080, 12120, 12176, 12212, 12248,
+ 12288, 12320, 12380, 12400, 12448, 12536, 12576, 12704,
+ 12736, 12968, 13000, 13024, 13080, 13136, 13204, 13272,
+ 13336, 13380, 13428, 14272, 14288, 14320, 14324, 14332,
+ 14340, 14384, 14412, 14440, 14468, 14500, 14532, 14560,
+ 14604, 14636, 14656, 14696, 14740, 14792, 14824, 14848,
+ 14892, 14944, 14996, 15032, 15076, 15128, 15180, 15216,
+ 15272, 15328, 15372, 15416, 15472, 15480, 15488, 15496,
+ 15516, 15524, 15536, 15540, 15544, 15588, 15604, 15616,
+ 15628, 15632, 15644, 15652, 15656, 15680, 15688, 15692,
+ 15704, 15712, 15724, 15764, 15772, 15776, 15804, 15828,
+ 15848, 15868, 15880, 15892, 15904, 15912, 15920, 15928,
+ 15936, -1,
+};
+
+static const int *unsupported_strings[] =
+{
+ unsupported_strings_1_0,
+ unsupported_strings_1_2,
+ unsupported_strings_1_3,
+};
+
+static boolean StringIsUnsupported(unsigned int offset)
+{
+ const int *string_list;
+ int i;
+
+ string_list = unsupported_strings[deh_hhe_version];
+
+ for (i=0; string_list[i] >= 0; ++i)
+ {
+ if ((unsigned int) string_list[i] == offset)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static boolean GetStringByOffset(unsigned int offset, char **result)
+{
+ int i;
+
+ for (i=0; i<arrlen(strings); ++i)
+ {
+ if (strings[i].offsets[deh_hhe_version] == offset)
+ {
+ *result = strings[i].string;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Given a string length, find the maximum length of a
+// string that can replace it.
+
+static int MaxStringLength(int len)
+{
+ // Enough bytes for the string and the NUL terminator
+
+ len += 1;
+
+ // All strings in doom.exe are on 4-byte boundaries, so we may be able
+ // to support a slightly longer string.
+ // Extend up to the next 4-byte boundary
+
+ len += (4 - (len % 4)) % 4;
+
+ // Less one for the NUL terminator.
+
+ return len - 1;
+}
+
+// If a string offset does not match any string, it may be because
+// we are running in the wrong version mode, and the patch was generated
+// for a different Heretic version. Search the lookup tables to find
+// versiosn that match.
+
+static void SuggestOtherVersions(unsigned int offset)
+{
+ const int *string_list;
+ unsigned int i;
+ unsigned int v;
+
+ // Check main string table.
+
+ for (i=0; i<arrlen(strings); ++i)
+ {
+ for (v=0; v<deh_hhe_num_versions; ++v)
+ {
+ if (strings[i].offsets[v] == offset)
+ {
+ DEH_SuggestHereticVersion(v);
+ }
+ }
+ }
+
+ // Check unsupported string tables.
+
+ for (v=0; v<deh_hhe_num_versions; ++v)
+ {
+ string_list = unsupported_strings[v];
+
+ for (i=0; string_list[i] >= 0; ++i)
+ {
+ if (string_list[i] == offset)
+ {
+ DEH_SuggestHereticVersion(v);
+ }
+ }
+ }
+}
+
+static void *DEH_TextStart(deh_context_t *context, char *line)
+{
+ char *repl_text;
+ char *orig_text;
+ int orig_offset, repl_len;
+ int i;
+
+ if (sscanf(line, "Text %i %i", &orig_offset, &repl_len) != 2)
+ {
+ DEH_Warning(context, "Parse error on section start");
+ return NULL;
+ }
+
+ repl_text = Z_Malloc(repl_len + 1, PU_STATIC, NULL);
+
+ // read in the "to" text
+
+ for (i=0; i<repl_len; ++i)
+ {
+ int c;
+
+ c = DEH_GetChar(context);
+
+ repl_text[i] = c;
+ }
+ repl_text[repl_len] = '\0';
+
+ // We don't support all strings, but at least recognise them:
+
+ if (StringIsUnsupported(orig_offset))
+ {
+ DEH_Warning(context, "Unsupported string replacement: %i", orig_offset);
+ }
+
+ // Find the string to replace:
+
+ else if (!GetStringByOffset(orig_offset, &orig_text))
+ {
+ SuggestOtherVersions(orig_offset);
+ DEH_Error(context, "Unknown string offset: %i", orig_offset);
+ }
+
+ // Only allow string replacements that are possible in Vanilla Doom.
+ // Chocolate Doom is unforgiving!
+
+ else if (!deh_allow_long_strings
+ && repl_len > MaxStringLength(strlen(orig_text)))
+ {
+ DEH_Error(context, "Replacement string is longer than the maximum "
+ "possible in heretic.exe");
+ }
+ else
+ {
+ // Success.
+
+ DEH_AddStringReplacement(orig_text, repl_text);
+
+ return NULL;
+ }
+
+ // Failure.
+
+ Z_Free(repl_text);
+
+ return NULL;
+}
+
+static void DEH_TextParseLine(deh_context_t *context, char *line, void *tag)
+{
+ // not used
+}
+
+deh_section_t deh_section_heretic_text =
+{
+ "Text",
+ NULL,
+ DEH_TextStart,
+ DEH_TextParseLine,
+ NULL,
+ NULL,
+};
+
diff --git a/src/heretic/deh_htic.c b/src/heretic/deh_htic.c
new file mode 100644
index 00000000..e4e91082
--- /dev/null
+++ b/src/heretic/deh_htic.c
@@ -0,0 +1,186 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// Top-level dehacked definitions for Heretic dehacked (HHE).
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "deh_defs.h"
+#include "deh_main.h"
+#include "deh_htic.h"
+#include "info.h"
+#include "m_argv.h"
+
+char *deh_signatures[] =
+{
+ "Patch File for HHE v1.0",
+ "Patch File for HHE v1.1",
+ NULL
+};
+
+static char *hhe_versions[] =
+{
+ "1.0", "1.2", "1.3"
+};
+
+// Version number for patches.
+
+deh_hhe_version_t deh_hhe_version = deh_hhe_1_0;
+
+// deh_ammo.c:
+extern deh_section_t deh_section_ammo;
+// deh_frame.c:
+extern deh_section_t deh_section_frame;
+// deh_ptr.c:
+extern deh_section_t deh_section_pointer;
+// deh_sound.c
+extern deh_section_t deh_section_sound;
+// deh_htext.c:
+extern deh_section_t deh_section_heretic_text;
+// deh_thing.c:
+extern deh_section_t deh_section_thing;
+// deh_weapon.c:
+extern deh_section_t deh_section_weapon;
+
+//
+// List of section types:
+//
+
+deh_section_t *deh_section_types[] =
+{
+ &deh_section_ammo,
+ &deh_section_frame,
+// &deh_section_pointer, TODO
+ &deh_section_sound,
+ &deh_section_heretic_text,
+ &deh_section_thing,
+ &deh_section_weapon,
+ NULL
+};
+
+static void SetHHEVersionByName(char *name)
+{
+ int i;
+
+ for (i=0; i<arrlen(hhe_versions); ++i)
+ {
+ if (!strcmp(hhe_versions[i], name))
+ {
+ deh_hhe_version = i;
+ return;
+ }
+ }
+
+ fprintf(stderr, "Unknown Heretic version: %s\n", name);
+ fprintf(stderr, "Valid versions:\n");
+
+ for (i=0; i<arrlen(hhe_versions); ++i)
+ {
+ fprintf(stderr, "\t%s\n", hhe_versions[i]);
+ }
+}
+
+// Initialize Heretic(HHE)-specific dehacked bits.
+
+void DEH_HereticInit(void)
+{
+ int i;
+
+ //!
+ // @arg <version>
+ //
+ // Select the Heretic version number that was used to generate the
+ // HHE patch to be loaded. Patches for each of the Vanilla
+ // Heretic versions (1.0, 1.2, 1.3) can be loaded, but the correct
+ // version number must be specified.
+
+ i = M_CheckParm("-hhever");
+
+ if (i > 0)
+ {
+ SetHHEVersionByName(myargv[i + 1]);
+ }
+
+ // For v1.0 patches, we must apply a slight change to the states[]
+ // table. The table was changed between 1.0 and 1.3 to add two extra
+ // frames to the player "burning death" animation.
+ //
+ // If we are using a v1.0 patch, we must change the table to cut
+ // these out again.
+
+ if (deh_hhe_version < deh_hhe_1_2)
+ {
+ states[S_PLAY_FDTH18].nextstate = S_NULL;
+ }
+}
+
+int DEH_MapHereticFrameNumber(int frame)
+{
+ if (deh_hhe_version < deh_hhe_1_2)
+ {
+ // Between Heretic 1.0 and 1.2, two new frames
+ // were added to the "states" table, to extend the "flame death"
+ // animation displayed when the player is killed by fire. Therefore,
+ // we must map Heretic 1.0 frame numbers to corresponding indexes
+ // for our state table.
+
+ if (frame >= S_PLAY_FDTH19)
+ {
+ frame = (frame - S_PLAY_FDTH19) + S_BLOODYSKULL1;
+ }
+ }
+ else
+ {
+ // After Heretic 1.2, three unused frames were removed from the
+ // states table, unused phoenix rod frames. Our state table includes
+ // these missing states for backwards compatibility. We must therefore
+ // adjust frame numbers for v1.2/v1.3 to corresponding indexes for
+ // our state table.
+
+ if (frame >= S_PHOENIXFXIX_1)
+ {
+ frame = (frame - S_PHOENIXFXIX_1) + S_PHOENIXPUFF1;
+ }
+ }
+
+ return frame;
+}
+
+void DEH_SuggestHereticVersion(deh_hhe_version_t version)
+{
+ fprintf(stderr,
+ "\n"
+ "This patch may be for version %s. You are currently running in\n"
+ "Heretic %s mode. For %s mode, add this to your command line:\n"
+ "\n"
+ "\t-hhever %s\n"
+ "\n",
+ hhe_versions[version],
+ hhe_versions[deh_hhe_version],
+ hhe_versions[version],
+ hhe_versions[version]);
+}
+
diff --git a/src/heretic/deh_htic.h b/src/heretic/deh_htic.h
new file mode 100644
index 00000000..7855da8c
--- /dev/null
+++ b/src/heretic/deh_htic.h
@@ -0,0 +1,60 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2010 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// Common header for Heretic dehacked (HHE) support.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef DEH_HTIC_H
+#define DEH_HTIC_H
+
+#include "info.h"
+
+// HHE executable version. Loading HHE patches is (unfortunately)
+// dependent on the version of the Heretic executable used to make them.
+
+typedef enum
+{
+ deh_hhe_1_0,
+ deh_hhe_1_2,
+ deh_hhe_1_3,
+ deh_hhe_num_versions
+} deh_hhe_version_t;
+
+// HHE doesn't know about the last two states in the state table, so
+// these are considered invalid.
+
+#define DEH_HERETIC_NUMSTATES (NUMSTATES - 2)
+
+// It also doesn't know about the last two things in the mobjinfo table
+// (which correspond to the states above)
+
+#define DEH_HERETIC_NUMMOBJTYPES (NUMMOBJTYPES - 2)
+
+void DEH_HereticInit(void);
+int DEH_MapHereticFrameNumber(int frame);
+void DEH_SuggestHereticVersion(deh_hhe_version_t version);
+
+extern deh_hhe_version_t deh_hhe_version;
+
+#endif /* #ifndef DEH_HTIC_H */
+
diff --git a/src/heretic/deh_sound.c b/src/heretic/deh_sound.c
new file mode 100644
index 00000000..d1f266dd
--- /dev/null
+++ b/src/heretic/deh_sound.c
@@ -0,0 +1,118 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// Parses "Sound" sections in dehacked files
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "doomfeatures.h"
+#include "doomtype.h"
+#include "deh_defs.h"
+#include "deh_main.h"
+#include "deh_mapping.h"
+
+#include "doomdef.h"
+#include "i_sound.h"
+
+#include "sounds.h"
+
+DEH_BEGIN_MAPPING(sound_mapping, sfxinfo_t)
+ DEH_MAPPING_STRING("Name", name)
+ DEH_UNSUPPORTED_MAPPING("Special")
+ DEH_MAPPING("Value", priority)
+ DEH_MAPPING("Unknown 1", usefulness)
+ DEH_UNSUPPORTED_MAPPING("Unknown 2")
+ DEH_UNSUPPORTED_MAPPING("Unknown 3")
+ DEH_MAPPING("One/Two", numchannels)
+DEH_END_MAPPING
+
+static void *DEH_SoundStart(deh_context_t *context, char *line)
+{
+ int sound_number = 0;
+
+ if (sscanf(line, "Sound %i", &sound_number) != 1)
+ {
+ DEH_Warning(context, "Parse error on section start");
+ return NULL;
+ }
+
+ if (sound_number < 0 || sound_number >= NUMSFX)
+ {
+ DEH_Warning(context, "Invalid sound number: %i", sound_number);
+ return NULL;
+ }
+
+ if (sound_number >= DEH_VANILLA_NUMSFX)
+ {
+ DEH_Warning(context, "Attempt to modify SFX %i. This will cause "
+ "problems in Vanilla dehacked.", sound_number);
+ }
+
+ return &S_sfx[sound_number];
+}
+
+static void DEH_SoundParseLine(deh_context_t *context, char *line, void *tag)
+{
+ sfxinfo_t *sfx;
+ char *variable_name, *value;
+
+ if (tag == NULL)
+ return;
+
+ sfx = (sfxinfo_t *) tag;
+
+ // Parse the assignment
+
+ if (!DEH_ParseAssignment(line, &variable_name, &value))
+ {
+ // Failed to parse
+ DEH_Warning(context, "Failed to parse assignment");
+ return;
+ }
+
+ // Set the field value:
+
+ if (!strcasecmp(variable_name, "Name"))
+ {
+ DEH_SetStringMapping(context, &sound_mapping, sfx,
+ variable_name, value);
+ }
+ else
+ {
+ DEH_SetMapping(context, &sound_mapping, sfx,
+ variable_name, atoi(value));
+ }
+}
+
+deh_section_t deh_section_sound =
+{
+ "Sound",
+ NULL,
+ DEH_SoundStart,
+ DEH_SoundParseLine,
+ NULL,
+ NULL,
+};
+
diff --git a/src/heretic/deh_thing.c b/src/heretic/deh_thing.c
new file mode 100644
index 00000000..dbb239e4
--- /dev/null
+++ b/src/heretic/deh_thing.c
@@ -0,0 +1,150 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// Parses "Thing" sections in dehacked files
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "doomtype.h"
+#include "m_misc.h"
+
+#include "deh_defs.h"
+#include "deh_main.h"
+#include "deh_mapping.h"
+#include "deh_htic.h"
+
+#include "info.h"
+
+DEH_BEGIN_MAPPING(thing_mapping, mobjinfo_t)
+ DEH_MAPPING("ID #", doomednum)
+ DEH_MAPPING("Initial frame", spawnstate)
+ DEH_MAPPING("Hit points", spawnhealth)
+ DEH_MAPPING("First moving frame", seestate)
+ DEH_MAPPING("Alert sound", seesound)
+ DEH_MAPPING("Reaction time", reactiontime)
+ DEH_MAPPING("Attack sound", attacksound)
+ DEH_MAPPING("Injury frame", painstate)
+ DEH_MAPPING("Pain chance", painchance)
+ DEH_MAPPING("Pain sound", painsound)
+ DEH_MAPPING("Close attack frame", meleestate)
+ DEH_MAPPING("Far attack frame", missilestate)
+ DEH_MAPPING("Burning frame", crashstate)
+ DEH_MAPPING("Death frame", deathstate)
+ DEH_MAPPING("Exploding frame", xdeathstate)
+ DEH_MAPPING("Death sound", deathsound)
+ DEH_MAPPING("Speed", speed)
+ DEH_MAPPING("Width", radius)
+ DEH_MAPPING("Height", height)
+ DEH_MAPPING("Mass", mass)
+ DEH_MAPPING("Missile damage", damage)
+ DEH_MAPPING("Action sound", activesound)
+ DEH_MAPPING("Bits 1", flags)
+ DEH_MAPPING("Bits 2", flags2)
+DEH_END_MAPPING
+
+static void *DEH_ThingStart(deh_context_t *context, char *line)
+{
+ int thing_number = 0;
+ mobjinfo_t *mobj;
+
+ if (sscanf(line, "Thing %i", &thing_number) != 1)
+ {
+ DEH_Warning(context, "Parse error on section start");
+ return NULL;
+ }
+
+ // HHE thing numbers are indexed from 1
+ --thing_number;
+
+ if (thing_number < 0 || thing_number >= DEH_HERETIC_NUMMOBJTYPES)
+ {
+ DEH_Warning(context, "Invalid thing number: %i", thing_number);
+ return NULL;
+ }
+
+ mobj = &mobjinfo[thing_number];
+
+ return mobj;
+}
+
+static void DEH_ThingParseLine(deh_context_t *context, char *line, void *tag)
+{
+ mobjinfo_t *mobj;
+ char *variable_name, *value;
+ int ivalue;
+
+ if (tag == NULL)
+ return;
+
+ mobj = (mobjinfo_t *) tag;
+
+ // Parse the assignment
+
+ if (!DEH_ParseAssignment(line, &variable_name, &value))
+ {
+ // Failed to parse
+
+ DEH_Warning(context, "Failed to parse assignment");
+ return;
+ }
+
+ // all values are integers
+
+ ivalue = atoi(value);
+
+ // If the value to be set is a frame, the frame number must
+ // undergo transformation from a Heretic 1.0 index to a
+ // Heretic 1.3 index.
+
+ if (M_StrCaseStr(variable_name, "frame") != NULL)
+ {
+ ivalue = DEH_MapHereticFrameNumber(ivalue);
+ }
+
+ // Set the field value
+
+ DEH_SetMapping(context, &thing_mapping, mobj, variable_name, ivalue);
+}
+
+static void DEH_ThingSHA1Sum(sha1_context_t *context)
+{
+ int i;
+
+ for (i=0; i<NUMMOBJTYPES; ++i)
+ {
+ DEH_StructSHA1Sum(context, &thing_mapping, &mobjinfo[i]);
+ }
+}
+
+deh_section_t deh_section_thing =
+{
+ "Thing",
+ NULL,
+ DEH_ThingStart,
+ DEH_ThingParseLine,
+ NULL,
+ DEH_ThingSHA1Sum,
+};
+
diff --git a/src/heretic/deh_weapon.c b/src/heretic/deh_weapon.c
new file mode 100644
index 00000000..0c417e2b
--- /dev/null
+++ b/src/heretic/deh_weapon.c
@@ -0,0 +1,131 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// Parses "Weapon" sections in dehacked files
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "doomtype.h"
+#include "m_misc.h"
+
+#include "doomdef.h"
+
+#include "deh_defs.h"
+#include "deh_main.h"
+#include "deh_mapping.h"
+#include "deh_htic.h"
+
+DEH_BEGIN_MAPPING(weapon_mapping, weaponinfo_t)
+ DEH_MAPPING("Ammo type", ammo)
+ DEH_MAPPING("Deselect frame", upstate)
+ DEH_MAPPING("Select frame", downstate)
+ DEH_MAPPING("Bobbing frame", readystate)
+ DEH_MAPPING("Shooting frame", atkstate)
+ DEH_MAPPING("Firing frame", holdatkstate)
+ DEH_MAPPING("Unknown frame", flashstate)
+DEH_END_MAPPING
+
+static void *DEH_WeaponStart(deh_context_t *context, char *line)
+{
+ int weapon_number = 0;
+
+ if (sscanf(line, "Weapon %i", &weapon_number) != 1)
+ {
+ DEH_Warning(context, "Parse error on section start");
+ return NULL;
+ }
+
+ if (weapon_number < 0 || weapon_number >= NUMWEAPONS * 2)
+ {
+ DEH_Warning(context, "Invalid weapon number: %i", weapon_number);
+ return NULL;
+ }
+
+ // Because of the tome of power, we have two levels of weapons:
+
+ if (weapon_number < NUMWEAPONS)
+ {
+ return &wpnlev1info[weapon_number];
+ }
+ else
+ {
+ return &wpnlev2info[weapon_number - NUMWEAPONS];
+ }
+}
+
+static void DEH_WeaponParseLine(deh_context_t *context, char *line, void *tag)
+{
+ char *variable_name, *value;
+ weaponinfo_t *weapon;
+ int ivalue;
+
+ if (tag == NULL)
+ return;
+
+ weapon = (weaponinfo_t *) tag;
+
+ if (!DEH_ParseAssignment(line, &variable_name, &value))
+ {
+ // Failed to parse
+
+ DEH_Warning(context, "Failed to parse assignment");
+ return;
+ }
+
+ ivalue = atoi(value);
+
+ // If this is a frame field, we need to map from Heretic 1.0 frame
+ // numbers to Heretic 1.3 frame numbers.
+
+ if (M_StrCaseStr(variable_name, "frame") != NULL)
+ {
+ ivalue = DEH_MapHereticFrameNumber(ivalue);
+ }
+
+ DEH_SetMapping(context, &weapon_mapping, weapon, variable_name, ivalue);
+}
+
+static void DEH_WeaponSHA1Sum(sha1_context_t *context)
+{
+ int i;
+
+ for (i=0; i<NUMWEAPONS ;++i)
+ {
+ DEH_StructSHA1Sum(context, &weapon_mapping, &wpnlev1info[i]);
+ DEH_StructSHA1Sum(context, &weapon_mapping, &wpnlev2info[i]);
+ }
+}
+
+deh_section_t deh_section_weapon =
+{
+ "Weapon",
+ NULL,
+ DEH_WeaponStart,
+ DEH_WeaponParseLine,
+ NULL,
+ DEH_WeaponSHA1Sum,
+};
+
diff --git a/src/heretic/doomdata.h b/src/heretic/doomdata.h
new file mode 100644
index 00000000..ac84ec46
--- /dev/null
+++ b/src/heretic/doomdata.h
@@ -0,0 +1,200 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+// DoomData.h
+
+// all external data is defined here
+// most of the data is loaded into different structures at run time
+
+#ifndef __DOOMDATA__
+#define __DOOMDATA__
+
+#include "doomtype.h"
+
+/*
+===============================================================================
+
+ map level types
+
+===============================================================================
+*/
+
+// lump order in a map wad
+enum
+{
+ ML_LABEL,
+ ML_THINGS,
+ ML_LINEDEFS,
+ ML_SIDEDEFS,
+ ML_VERTEXES,
+ ML_SEGS,
+ ML_SSECTORS,
+ ML_NODES,
+ ML_SECTORS,
+ ML_REJECT,
+ ML_BLOCKMAP
+};
+
+
+typedef struct
+{
+ short x, y;
+} PACKEDATTR mapvertex_t;
+
+typedef struct
+{
+ short textureoffset;
+ short rowoffset;
+ char toptexture[8], bottomtexture[8], midtexture[8];
+ short sector; // on viewer's side
+} PACKEDATTR mapsidedef_t;
+
+typedef struct
+{
+ short v1, v2;
+ short flags;
+ short special, tag;
+ short sidenum[2]; // sidenum[1] will be -1 if one sided
+} PACKEDATTR maplinedef_t;
+
+#define ML_BLOCKING 1
+#define ML_BLOCKMONSTERS 2
+#define ML_TWOSIDED 4 // backside will not be present at all
+ // if not two sided
+
+// 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 (windows)
+#define ML_DONTPEGTOP 8
+#define ML_DONTPEGBOTTOM 16
+
+#define ML_SECRET 32 // don't map as two sided: IT'S A SECRET!
+#define ML_SOUNDBLOCK 64 // don't let sound cross two of these
+#define ML_DONTDRAW 128 // don't draw on the automap
+#define ML_MAPPED 256 // set if allready drawn in automap
+
+
+typedef struct
+{
+ short floorheight, ceilingheight;
+ char floorpic[8], ceilingpic[8];
+ short lightlevel;
+ short special, tag;
+} PACKEDATTR mapsector_t;
+
+typedef struct
+{
+ short numsegs;
+ short firstseg; // segs are stored sequentially
+} PACKEDATTR mapsubsector_t;
+
+typedef struct
+{
+ short v1, v2;
+ short angle;
+ short linedef, side;
+ short offset;
+} PACKEDATTR mapseg_t;
+
+#define NF_SUBSECTOR 0x8000
+typedef struct
+{
+ short x, y, dx, dy; // partition line
+ short bbox[2][4]; // bounding box for each child
+ unsigned short children[2]; // if NF_SUBSECTOR its a subsector
+} PACKEDATTR mapnode_t;
+
+typedef struct
+{
+ short x, y;
+ short angle;
+ short type;
+ short options;
+} PACKEDATTR mapthing_t;
+
+#define MTF_EASY 1
+#define MTF_NORMAL 2
+#define MTF_HARD 4
+#define MTF_AMBUSH 8
+
+/*
+===============================================================================
+
+ texture definition
+
+===============================================================================
+*/
+
+typedef struct
+{
+ short originx;
+ short originy;
+ short patch;
+ short stepdir;
+ short colormap;
+} PACKEDATTR mappatch_t;
+
+typedef struct
+{
+ char name[8];
+ boolean masked;
+ short width;
+ short height;
+ int obsolete;
+ short patchcount;
+ mappatch_t patches[1];
+} PACKEDATTR maptexture_t;
+
+
+/*
+===============================================================================
+
+ graphics
+
+===============================================================================
+*/
+
+// a pic is an unmasked block of pixels
+typedef struct
+{
+ byte width, height;
+ byte data;
+} pic_t;
+
+
+
+
+/*
+===============================================================================
+
+ status
+
+===============================================================================
+*/
+
+
+
+
+#endif // __DOOMDATA__
diff --git a/src/heretic/doomdef.h b/src/heretic/doomdef.h
new file mode 100644
index 00000000..9f6122d8
--- /dev/null
+++ b/src/heretic/doomdef.h
@@ -0,0 +1,825 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// DoomDef.h
+
+#ifndef __DOOMDEF__
+#define __DOOMDEF__
+#include <stdio.h>
+#include <string.h>
+//haleyjd: removed WATCOMC
+#include <limits.h>
+
+#define HERETIC_VERSION 130
+#define HERETIC_VERSION_TEXT "v1.3"
+
+// if rangecheck is undefined, most parameter validation debugging code
+// will not be compiled
+//#define RANGECHECK
+
+// all external data is defined here
+#include "doomdata.h"
+
+// all important printed strings
+#include "dstrings.h"
+
+// header generated by multigen utility
+#include "info.h"
+
+// WAD file access
+#include "w_wad.h"
+
+// fixed_t
+#include "m_fixed.h"
+
+// angle_t
+#include "tables.h"
+
+// events
+#include "d_event.h"
+
+// gamemode/mission
+#include "d_mode.h"
+
+// ticcmd_t
+#include "d_ticcmd.h"
+
+#include "d_loop.h"
+
+#define SAVEGAMENAME "hticsav"
+
+/*
+===============================================================================
+
+ GLOBAL TYPES
+
+===============================================================================
+*/
+
+#define NUMARTIFCTS 28
+#define MAXPLAYERS 4
+
+#define BT_ATTACK 1
+#define BT_USE 2
+#define BT_CHANGE 4 // if true, the next 3 bits hold weapon num
+#define BT_WEAPONMASK (8+16+32)
+#define BT_WEAPONSHIFT 3
+
+#define BT_SPECIAL 128 // game events, not really buttons
+#define BTS_SAVEMASK (4+8+16)
+#define BTS_SAVESHIFT 2
+#define BT_SPECIALMASK 3
+#define BTS_PAUSE 1 // pause the game
+#define BTS_SAVEGAME 2 // save the game at each console
+// savegame slot numbers occupy the second byte of buttons
+
+typedef enum
+{
+ GS_LEVEL,
+ GS_INTERMISSION,
+ GS_FINALE,
+ GS_DEMOSCREEN
+} gamestate_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;
+
+typedef enum
+{
+ wipe_0,
+ wipe_1,
+ wipe_2,
+ wipe_3,
+ wipe_4,
+ NUMWIPES,
+ wipe_random
+} wipe_t;
+
+/*
+===============================================================================
+
+ MAPOBJ DATA
+
+===============================================================================
+*/
+
+// think_t is a function pointer to a routine to handle an actor
+typedef void (*think_t) ();
+
+typedef struct thinker_s
+{
+ struct thinker_s *prev, *next;
+ think_t function;
+} thinker_t;
+
+typedef union
+{
+ int i;
+ struct mobj_s *m;
+} specialval_t;
+
+struct player_s;
+
+typedef struct mobj_s
+{
+ thinker_t thinker; // thinker links
+
+// info for drawing
+ fixed_t x, y, z;
+ struct mobj_s *snext, *sprev; // links in sector (if needed)
+ angle_t angle;
+ spritenum_t sprite; // used to find patch_t and flip value
+ int frame; // might be ord with FF_FULLBRIGHT
+
+// interaction info
+ struct mobj_s *bnext, *bprev; // links in blocks (if needed)
+ struct subsector_s *subsector;
+ fixed_t floorz, ceilingz; // closest together of contacted secs
+ fixed_t radius, height; // for movement checking
+ fixed_t momx, momy, momz; // momentums
+
+ int validcount; // if == validcount, already checked
+
+ mobjtype_t type;
+ mobjinfo_t *info; // &mobjinfo[mobj->type]
+ int tics; // state tic counter
+ state_t *state;
+ int damage; // For missiles
+ int flags;
+ int flags2; // Heretic flags
+ specialval_t special1; // Special info
+ specialval_t special2; // Special info
+ int health;
+ int movedir; // 0-7
+ int movecount; // when 0, select a new dir
+ struct mobj_s *target; // thing being chased/attacked (or NULL)
+ // also the originator for missiles
+ int reactiontime; // if non 0, don't attack yet
+ // used by player to freeze a bit after
+ // teleporting
+ int threshold; // if >0, the target will be chased
+ // no matter what (even if shot)
+ struct player_s *player; // only valid if type == MT_PLAYER
+ int lastlook; // player number last looked for
+
+ mapthing_t spawnpoint; // for nightmare respawn
+} mobj_t;
+
+// each sector has a degenmobj_t in it's center for sound origin purposes
+typedef struct
+{
+ thinker_t thinker; // not used for anything
+ fixed_t x, y, z;
+} degenmobj_t;
+
+//
+// frame flags
+//
+#define FF_FULLBRIGHT 0x8000 // flag in thing->frame
+#define FF_FRAMEMASK 0x7fff
+
+// --- mobj.flags ---
+
+#define MF_SPECIAL 1 // call P_SpecialThing when touched
+#define MF_SOLID 2
+#define MF_SHOOTABLE 4
+#define MF_NOSECTOR 8 // don't use the sector links
+ // (invisible but touchable)
+#define MF_NOBLOCKMAP 16 // don't use the blocklinks
+ // (inert but displayable)
+#define MF_AMBUSH 32
+#define MF_JUSTHIT 64 // try to attack right back
+#define MF_JUSTATTACKED 128 // take at least one step before attacking
+#define MF_SPAWNCEILING 256 // hang from ceiling instead of floor
+#define MF_NOGRAVITY 512 // don't apply gravity every tic
+
+// movement flags
+#define MF_DROPOFF 0x400 // allow jumps from high places
+#define MF_PICKUP 0x800 // for players to pick up items
+#define MF_NOCLIP 0x1000 // player cheat
+#define MF_SLIDE 0x2000 // keep info about sliding along walls
+#define MF_FLOAT 0x4000 // allow moves to any height, no gravity
+#define MF_TELEPORT 0x8000 // don't cross lines or look at heights
+#define MF_MISSILE 0x10000 // don't hit same species, explode on block
+
+#define MF_DROPPED 0x20000 // dropped by a demon, not level spawned
+#define MF_SHADOW 0x40000 // use translucent draw (shadow demons / invis)
+#define MF_NOBLOOD 0x80000 // don't bleed when shot (use puff)
+#define MF_CORPSE 0x100000 // don't stop moving halfway off a step
+#define MF_INFLOAT 0x200000 // floating to a height for a move, don't
+ // auto float to target's height
+
+#define MF_COUNTKILL 0x400000 // count towards intermission kill total
+#define MF_COUNTITEM 0x800000 // count towards intermission item total
+
+#define MF_SKULLFLY 0x1000000 // skull in flight
+#define MF_NOTDMATCH 0x2000000 // don't spawn in death match (key cards)
+
+#define MF_TRANSLATION 0xc000000 // if 0x4 0x8 or 0xc, use a translation
+#define MF_TRANSSHIFT 26 // table for player colormaps
+
+// --- mobj.flags2 ---
+
+#define MF2_LOGRAV 0x00000001 // alternate gravity setting
+#define MF2_WINDTHRUST 0x00000002 // gets pushed around by the wind
+ // specials
+#define MF2_FLOORBOUNCE 0x00000004 // bounces off the floor
+#define MF2_THRUGHOST 0x00000008 // missile will pass through ghosts
+#define MF2_FLY 0x00000010 // fly mode is active
+#define MF2_FOOTCLIP 0x00000020 // if feet are allowed to be clipped
+#define MF2_SPAWNFLOAT 0x00000040 // spawn random float z
+#define MF2_NOTELEPORT 0x00000080 // does not teleport
+#define MF2_RIP 0x00000100 // missile rips through solid
+ // targets
+#define MF2_PUSHABLE 0x00000200 // can be pushed by other moving
+ // mobjs
+#define MF2_SLIDE 0x00000400 // slides against walls
+#define MF2_ONMOBJ 0x00000800 // mobj is resting on top of another
+ // mobj
+#define MF2_PASSMOBJ 0x00001000 // Enable z block checking. If on,
+ // this flag will allow the mobj to
+ // pass over/under other mobjs.
+#define MF2_CANNOTPUSH 0x00002000 // cannot push other pushable mobjs
+#define MF2_FEETARECLIPPED 0x00004000 // a mobj's feet are now being cut
+#define MF2_BOSS 0x00008000 // mobj is a major boss
+#define MF2_FIREDAMAGE 0x00010000 // does fire damage
+#define MF2_NODMGTHRUST 0x00020000 // does not thrust target when
+ // damaging
+#define MF2_TELESTOMP 0x00040000 // mobj can stomp another
+#define MF2_FLOATBOB 0x00080000 // use float bobbing z movement
+#define MF2_DONTDRAW 0X00100000 // don't generate a vissprite
+
+//=============================================================================
+typedef enum
+{
+ PST_LIVE, // playing
+ PST_DEAD, // dead on the ground
+ PST_REBORN // ready to restart
+} playerstate_t;
+
+// psprites are scaled shapes 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 NULL state means not active
+ int tics;
+ fixed_t sx, sy;
+} pspdef_t;
+
+typedef enum
+{
+ key_yellow,
+ key_green,
+ key_blue,
+ NUMKEYS
+} keytype_t;
+
+typedef enum
+{
+ wp_staff,
+ wp_goldwand,
+ wp_crossbow,
+ wp_blaster,
+ wp_skullrod,
+ wp_phoenixrod,
+ wp_mace,
+ wp_gauntlets,
+ wp_beak,
+ NUMWEAPONS,
+ wp_nochange
+} weapontype_t;
+
+#define AMMO_GWND_WIMPY 10
+#define AMMO_GWND_HEFTY 50
+#define AMMO_CBOW_WIMPY 5
+#define AMMO_CBOW_HEFTY 20
+#define AMMO_BLSR_WIMPY 10
+#define AMMO_BLSR_HEFTY 25
+#define AMMO_SKRD_WIMPY 20
+#define AMMO_SKRD_HEFTY 100
+#define AMMO_PHRD_WIMPY 1
+#define AMMO_PHRD_HEFTY 10
+#define AMMO_MACE_WIMPY 20
+#define AMMO_MACE_HEFTY 100
+
+typedef enum
+{
+ am_goldwand,
+ am_crossbow,
+ am_blaster,
+ am_skullrod,
+ am_phoenixrod,
+ am_mace,
+ NUMAMMO,
+ am_noammo // staff, gauntlets
+} ammotype_t;
+
+typedef struct
+{
+ ammotype_t ammo;
+ int upstate;
+ int downstate;
+ int readystate;
+ int atkstate;
+ int holdatkstate;
+ int flashstate;
+} weaponinfo_t;
+
+extern weaponinfo_t wpnlev1info[NUMWEAPONS];
+extern weaponinfo_t wpnlev2info[NUMWEAPONS];
+
+typedef enum
+{
+ arti_none,
+ arti_invulnerability,
+ arti_invisibility,
+ arti_health,
+ arti_superhealth,
+ arti_tomeofpower,
+ arti_torch,
+ arti_firebomb,
+ arti_egg,
+ arti_fly,
+ arti_teleport,
+ NUMARTIFACTS
+} artitype_t;
+
+typedef enum
+{
+ pw_None,
+ pw_invulnerability,
+ pw_invisibility,
+ pw_allmap,
+ pw_infrared,
+ pw_weaponlevel2,
+ pw_flight,
+ pw_shield,
+ pw_health2,
+ NUMPOWERS
+} powertype_t;
+
+#define INVULNTICS (30*35)
+#define INVISTICS (60*35)
+#define INFRATICS (120*35)
+#define IRONTICS (60*35)
+#define WPNLEV2TICS (40*35)
+#define FLIGHTTICS (60*35)
+
+#define CHICKENTICS (40*35)
+
+#define MESSAGETICS (4*35)
+#define BLINKTHRESHOLD (4*32)
+
+#define NUMINVENTORYSLOTS 14
+typedef struct
+{
+ int type;
+ int count;
+} inventory_t;
+
+/*
+================
+=
+= player_t
+=
+================
+*/
+
+typedef struct player_s
+{
+ mobj_t *mo;
+ playerstate_t playerstate;
+ ticcmd_t cmd;
+
+ fixed_t viewz; // focal origin above r.z
+ fixed_t viewheight; // base height above floor for viewz
+ fixed_t deltaviewheight; // squat speed
+ fixed_t bob; // bounded/scaled total momentum
+
+ int flyheight;
+ int lookdir;
+ boolean centering;
+ int health; // only used between levels, mo->health
+ // is used during levels
+ int armorpoints, armortype; // armor type is 0-2
+
+ inventory_t inventory[NUMINVENTORYSLOTS];
+ artitype_t readyArtifact;
+ int artifactCount;
+ int inventorySlotNum;
+ int powers[NUMPOWERS];
+ boolean keys[NUMKEYS];
+ boolean backpack;
+ signed int frags[MAXPLAYERS]; // kills of other players
+ weapontype_t readyweapon;
+ weapontype_t pendingweapon; // wp_nochange if not changing
+ boolean weaponowned[NUMWEAPONS];
+ int ammo[NUMAMMO];
+ int maxammo[NUMAMMO];
+ int attackdown, usedown; // true if button down last tic
+ int cheats; // bit flags
+
+ int refire; // refired shots are less accurate
+
+ int killcount, itemcount, secretcount; // for intermission
+ char *message; // hint messages
+ int messageTics; // counter for showing messages
+ int damagecount, bonuscount; // for screen flashing
+ int flamecount; // for flame thrower duration
+ mobj_t *attacker; // who did damage (NULL for floors)
+ int extralight; // so gun flashes light up areas
+ int fixedcolormap; // can be set to REDCOLORMAP, etc
+ int colormap; // 0-3 for which color to draw player
+ pspdef_t psprites[NUMPSPRITES]; // view sprites (gun, etc)
+ boolean didsecret; // true if secret level has been done
+ int chickenTics; // player is a chicken if > 0
+ int chickenPeck; // chicken peck countdown
+ mobj_t *rain1; // active rain maker 1
+ mobj_t *rain2; // active rain maker 2
+} player_t;
+
+#define CF_NOCLIP 1
+#define CF_GODMODE 2
+#define CF_NOMOMENTUM 4 // not really a cheat, just a debug aid
+
+#define SBARHEIGHT 42 // status bar height at bottom of screen
+
+
+/*
+===============================================================================
+
+ GLOBAL VARIABLES
+
+===============================================================================
+*/
+
+#define TELEFOGHEIGHT (32*FRACUNIT)
+
+extern gameaction_t gameaction;
+
+extern boolean paused;
+
+extern GameMode_t gamemode;
+extern GameMission_t gamemission;
+
+extern boolean ExtendedWAD; // true if main WAD is the extended version
+
+extern boolean nomonsters; // checkparm of -nomonsters
+
+extern boolean respawnparm; // checkparm of -respawn
+
+extern boolean debugmode; // checkparm of -debug
+
+extern boolean usergame; // ok to save / end game
+
+extern boolean ravpic; // checkparm of -ravpic
+
+extern boolean altpal; // checkparm to use an alternate palette routine
+
+extern boolean cdrom; // true if cd-rom mode active ("-cdrom")
+
+extern boolean deathmatch; // only if started as net death
+
+extern boolean netgame; // only true if >1 player
+
+extern boolean playeringame[MAXPLAYERS];
+
+extern int consoleplayer; // player taking events and displaying
+
+extern int displayplayer;
+
+extern int viewangleoffset; // ANG90 = left side, ANG270 = right
+
+extern player_t players[MAXPLAYERS];
+
+extern boolean DebugSound; // debug flag for displaying sound info
+
+extern int GetWeaponAmmo[NUMWEAPONS];
+
+extern boolean demorecording;
+extern boolean demoplayback;
+extern int skytexture;
+
+extern gamestate_t gamestate;
+extern skill_t gameskill;
+extern boolean respawnmonsters;
+extern int gameepisode;
+extern int gamemap;
+extern int prevmap;
+extern int totalkills, totalitems, totalsecret; // for intermission
+extern int levelstarttic; // gametic at level start
+extern int leveltime; // tics in game play for par
+
+extern ticcmd_t *netcmds;
+
+#define SAVEGAMESIZE 0x30000
+#define SAVESTRINGSIZE 24
+extern byte *savebuffer;
+extern byte *save_p;
+
+extern mapthing_t *deathmatch_p;
+extern mapthing_t deathmatchstarts[10];
+extern mapthing_t playerstarts[MAXPLAYERS];
+
+extern int mouseSensitivity;
+
+extern boolean precache; // if true, load all graphics at level load
+
+extern boolean singledemo; // quit after playing a demo from cmdline
+
+extern int bodyqueslot;
+extern skill_t startskill;
+extern int startepisode;
+extern int startmap;
+extern boolean autostart;
+
+extern boolean testcontrols;
+extern int testcontrols_mousespeed;
+
+/*
+===============================================================================
+
+ GLOBAL FUNCTIONS
+
+===============================================================================
+*/
+
+#include "z_zone.h"
+
+//----------
+//BASE LEVEL
+//----------
+void D_DoomMain(void);
+void IncThermo(void);
+void InitThermo(int max);
+void tprintf(char *string, int initflag);
+// not a globally visible function, just included for source reference
+// calls all startup code
+// parses command line options
+// if not overrided, calls N_AdvanceDemo
+
+void D_DoomLoop(void);
+// not a globally visible function, just included for source reference
+// called by D_DoomMain, never exits
+// manages timing and IO
+// calls all ?_Responder, ?_Ticker, and ?_Drawer functions
+// calls I_GetTime, I_StartFrame, and I_StartTic
+
+//---------
+//SYSTEM IO
+//---------
+byte *I_AllocLow(int length);
+// allocates from low memory under dos, just mallocs under unix
+
+// haleyjd: was WATCOMC, preserved for historical interest.
+// This is similar to the -control structure in DOOM v1.4 and Strife.
+#if 0
+extern boolean useexterndriver;
+
+#define EBT_FIRE 1
+#define EBT_OPENDOOR 2
+#define EBT_SPEED 4
+#define EBT_STRAFE 8
+#define EBT_MAP 0x10
+#define EBT_INVENTORYLEFT 0x20
+#define EBT_INVENTORYRIGHT 0x40
+#define EBT_USEARTIFACT 0x80
+#define EBT_FLYDROP 0x100
+#define EBT_CENTERVIEW 0x200
+#define EBT_PAUSE 0x400
+#define EBT_WEAPONCYCLE 0x800
+
+typedef struct
+{
+ short vector; // Interrupt vector
+
+ signed char moveForward; // forward/backward (maxes at 50)
+ signed char moveSideways; // strafe (maxes at 24)
+ short angleTurn; // turning speed (640 [slow] 1280 [fast])
+ short angleHead; // head angle (+2080 [left] : 0 [center] : -2048 [right])
+ signed char pitch; // look up/down (-110 : +90)
+ signed char flyDirection; // flyheight (+1/-1)
+ unsigned short buttons; // EBT_* flags
+} externdata_t;
+#endif
+
+//----
+//GAME
+//----
+
+void G_DeathMatchSpawnPlayer(int playernum);
+
+void G_InitNew(skill_t skill, int episode, int map);
+
+void G_DeferedInitNew(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_DeferedPlayDemo(char *demo);
+
+void G_LoadGame(char *name);
+// can be called by the startup code or M_Responder
+// calls P_SetupLevel or W_EnterWorld
+void G_DoLoadGame(void);
+
+void G_SaveGame(int slot, char *description);
+// called by M_Responder
+
+// Support routines for saving games
+char *SV_Filename(int slot);
+void SV_Open(char *fileName);
+void SV_Close(char *fileName);
+void SV_Write(void *buffer, int size);
+void SV_WriteByte(byte val);
+void SV_WriteWord(unsigned short val);
+void SV_WriteLong(unsigned int val);
+
+extern char *savegamedir;
+
+void G_RecordDemo(skill_t skill, int numplayers, int episode, int map,
+ char *name);
+// only called by startup code
+
+void G_PlayDemo(char *name);
+void G_TimeDemo(char *name);
+
+void G_ExitLevel(void);
+void G_SecretExitLevel(void);
+
+void G_WorldDone(void);
+
+void G_Ticker(void);
+boolean G_Responder(event_t * ev);
+
+void G_ScreenShot(void);
+
+//-----
+//PLAY
+//-----
+
+void P_Ticker(void);
+// called by C_Ticker
+// can call G_PlayerExited
+// carries out all thinking of monsters and players
+
+void P_SetupLevel(int episode, int map, int playermask, skill_t skill);
+// called by W_Ticker
+
+void P_Init(void);
+// called by startup code
+
+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);
+// load / save game routines
+
+
+//-------
+//REFRESH
+//-------
+
+extern boolean setsizeneeded;
+
+extern boolean BorderNeedRefresh;
+extern boolean BorderTopRefresh;
+
+extern int UpdateState;
+// define the different areas for the dirty map
+#define I_NOUPDATE 0
+#define I_FULLVIEW 1
+#define I_STATBAR 2
+#define I_MESSAGES 4
+#define I_FULLSCRN 8
+
+void R_RenderPlayerView(player_t * player);
+// called by G_Drawer
+
+void R_Init(void);
+// called by startup code
+
+void R_DrawViewBorder(void);
+void R_DrawTopBorder(void);
+// if the view size is not full screen, draws a border around it
+
+void R_SetViewSize(int blocks, int detail);
+// called by M_Responder
+
+int R_FlatNumForName(char *name);
+
+int R_TextureNumForName(char *name);
+int R_CheckTextureNumForName(char *name);
+// called by P_Ticker for switches and animations
+// returns the texture number for the texture name
+
+
+//----
+//MISC
+//----
+// returns the position of the given parameter in the arg list (0 if not found)
+
+int M_DrawText(int x, int y, boolean direct, char *string);
+
+//----------------------
+// Interlude (IN_lude.c)
+//----------------------
+
+extern boolean intermission;
+
+void IN_Start(void);
+void IN_Ticker(void);
+void IN_Drawer(void);
+
+//----------------------
+// Chat mode (CT_chat.c)
+//----------------------
+
+void CT_Init(void);
+void CT_Drawer(void);
+boolean CT_Responder(event_t * ev);
+void CT_Ticker(void);
+char CT_dequeueChatChar(void);
+
+extern boolean chatmodeon;
+extern boolean ultimatemsg;
+
+//--------------------
+// Finale (F_finale.c)
+//--------------------
+
+void F_Drawer(void);
+void F_Ticker(void);
+void F_StartFinale(void);
+
+//----------------------
+// STATUS BAR (SB_bar.c)
+//----------------------
+
+void SB_Init(void);
+boolean SB_Responder(event_t * event);
+void SB_Ticker(void);
+void SB_Drawer(void);
+
+//-----------------
+// MENU (MN_menu.c)
+//-----------------
+
+extern boolean MenuActive;
+
+void MN_Init(void);
+void MN_ActivateMenu(void);
+void MN_DeactivateMenu(void);
+boolean MN_Responder(event_t * event);
+void MN_Ticker(void);
+void MN_Drawer(void);
+void MN_DrTextA(char *text, int x, int y);
+int MN_TextAWidth(char *text);
+void MN_DrTextB(char *text, int x, int y);
+int MN_TextBWidth(char *text);
+
+#include "sounds.h"
+
+#endif // __DOOMDEF__
diff --git a/src/heretic/dstrings.h b/src/heretic/dstrings.h
new file mode 100644
index 00000000..93900f9d
--- /dev/null
+++ b/src/heretic/dstrings.h
@@ -0,0 +1,252 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// DStrings.h
+
+//---------------------------------------------------------------------------
+//
+// P_inter.c
+//
+//---------------------------------------------------------------------------
+
+// Keys
+
+#define TXT_GOTBLUEKEY "BLUE KEY"
+#define TXT_GOTYELLOWKEY "YELLOW KEY"
+#define TXT_GOTGREENKEY "GREEN KEY"
+
+// Artifacts
+
+#define TXT_ARTIHEALTH "QUARTZ FLASK"
+#define TXT_ARTIFLY "WINGS OF WRATH"
+#define TXT_ARTIINVULNERABILITY "RING OF INVINCIBILITY"
+#define TXT_ARTITOMEOFPOWER "TOME OF POWER"
+#define TXT_ARTIINVISIBILITY "SHADOWSPHERE"
+#define TXT_ARTIEGG "MORPH OVUM"
+#define TXT_ARTISUPERHEALTH "MYSTIC URN"
+#define TXT_ARTITORCH "TORCH"
+#define TXT_ARTIFIREBOMB "TIME BOMB OF THE ANCIENTS"
+#define TXT_ARTITELEPORT "CHAOS DEVICE"
+
+// Items
+
+#define TXT_ITEMHEALTH "CRYSTAL VIAL"
+#define TXT_ITEMBAGOFHOLDING "BAG OF HOLDING"
+#define TXT_ITEMSHIELD1 "SILVER SHIELD"
+#define TXT_ITEMSHIELD2 "ENCHANTED SHIELD"
+#define TXT_ITEMSUPERMAP "MAP SCROLL"
+
+// Ammo
+
+#define TXT_AMMOGOLDWAND1 "WAND CRYSTAL"
+#define TXT_AMMOGOLDWAND2 "CRYSTAL GEODE"
+#define TXT_AMMOMACE1 "MACE SPHERES"
+#define TXT_AMMOMACE2 "PILE OF MACE SPHERES"
+#define TXT_AMMOCROSSBOW1 "ETHEREAL ARROWS"
+#define TXT_AMMOCROSSBOW2 "QUIVER OF ETHEREAL ARROWS"
+#define TXT_AMMOBLASTER1 "CLAW ORB"
+#define TXT_AMMOBLASTER2 "ENERGY ORB"
+#define TXT_AMMOSKULLROD1 "LESSER RUNES"
+#define TXT_AMMOSKULLROD2 "GREATER RUNES"
+#define TXT_AMMOPHOENIXROD1 "FLAME ORB"
+#define TXT_AMMOPHOENIXROD2 "INFERNO ORB"
+
+// Weapons
+
+#define TXT_WPNMACE "FIREMACE"
+#define TXT_WPNCROSSBOW "ETHEREAL CROSSBOW"
+#define TXT_WPNBLASTER "DRAGON CLAW"
+#define TXT_WPNSKULLROD "HELLSTAFF"
+#define TXT_WPNPHOENIXROD "PHOENIX ROD"
+#define TXT_WPNGAUNTLETS "GAUNTLETS OF THE NECROMANCER"
+
+//---------------------------------------------------------------------------
+//
+// SB_bar.c
+//
+//---------------------------------------------------------------------------
+
+#define TXT_CHEATGODON "GOD MODE ON"
+#define TXT_CHEATGODOFF "GOD MODE OFF"
+#define TXT_CHEATNOCLIPON "NO CLIPPING ON"
+#define TXT_CHEATNOCLIPOFF "NO CLIPPING OFF"
+#define TXT_CHEATWEAPONS "ALL WEAPONS"
+#define TXT_CHEATFLIGHTON "FLIGHT ON"
+#define TXT_CHEATFLIGHTOFF "FLIGHT OFF"
+#define TXT_CHEATPOWERON "POWER ON"
+#define TXT_CHEATPOWEROFF "POWER OFF"
+#define TXT_CHEATHEALTH "FULL HEALTH"
+#define TXT_CHEATKEYS "ALL KEYS"
+#define TXT_CHEATSOUNDON "SOUND DEBUG ON"
+#define TXT_CHEATSOUNDOFF "SOUND DEBUG OFF"
+#define TXT_CHEATTICKERON "TICKER ON"
+#define TXT_CHEATTICKEROFF "TICKER OFF"
+#define TXT_CHEATARTIFACTS1 "CHOOSE AN ARTIFACT ( A - J )"
+#define TXT_CHEATARTIFACTS2 "HOW MANY ( 1 - 9 )"
+#define TXT_CHEATARTIFACTS3 "YOU GOT IT"
+#define TXT_CHEATARTIFACTSFAIL "BAD INPUT"
+#define TXT_CHEATWARP "LEVEL WARP"
+#define TXT_CHEATSCREENSHOT "SCREENSHOT"
+#define TXT_CHEATCHICKENON "CHICKEN ON"
+#define TXT_CHEATCHICKENOFF "CHICKEN OFF"
+#define TXT_CHEATMASSACRE "MASSACRE"
+#define TXT_CHEATIDDQD "TRYING TO CHEAT, EH? NOW YOU DIE!"
+#define TXT_CHEATIDKFA "CHEATER - YOU DON'T DESERVE WEAPONS"
+
+//---------------------------------------------------------------------------
+//
+// P_doors.c
+//
+//---------------------------------------------------------------------------
+
+#define TXT_NEEDBLUEKEY "YOU NEED A BLUE KEY TO OPEN THIS DOOR"
+#define TXT_NEEDGREENKEY "YOU NEED A GREEN KEY TO OPEN THIS DOOR"
+#define TXT_NEEDYELLOWKEY "YOU NEED A YELLOW KEY TO OPEN THIS DOOR"
+
+//---------------------------------------------------------------------------
+//
+// G_game.c
+//
+//---------------------------------------------------------------------------
+
+#define TXT_GAMESAVED "GAME SAVED"
+
+//---------------------------------------------------------------------------
+//
+// 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"
+
+//---------------------------------------------------------------------------
+//
+// F_finale.c
+//
+//---------------------------------------------------------------------------
+
+#define E1TEXT "with the destruction of the iron\n"\
+ "liches and their minions, the last\n"\
+ "of the undead are cleared from this\n"\
+ "plane of existence.\n\n"\
+ "those creatures had to come from\n"\
+ "somewhere, though, and you have the\n"\
+ "sneaky suspicion that the fiery\n"\
+ "portal of hell's maw opens onto\n"\
+ "their home dimension.\n\n"\
+ "to make sure that more undead\n"\
+ "(or even worse things) don't come\n"\
+ "through, you'll have to seal hell's\n"\
+ "maw from the other side. of course\n"\
+ "this means you may get stuck in a\n"\
+ "very unfriendly world, but no one\n"\
+ "ever said being a Heretic was easy!"
+
+#define E2TEXT "the mighty maulotaurs have proved\n"\
+ "to be no match for you, and as\n"\
+ "their steaming corpses slide to the\n"\
+ "ground you feel a sense of grim\n"\
+ "satisfaction that they have been\n"\
+ "destroyed.\n\n"\
+ "the gateways which they guarded\n"\
+ "have opened, revealing what you\n"\
+ "hope is the way home. but as you\n"\
+ "step through, mocking laughter\n"\
+ "rings in your ears.\n\n"\
+ "was some other force controlling\n"\
+ "the maulotaurs? could there be even\n"\
+ "more horrific beings through this\n"\
+ "gate? the sweep of a crystal dome\n"\
+ "overhead where the sky should be is\n"\
+ "certainly not a good sign...."
+
+#define E3TEXT "the death of d'sparil has loosed\n"\
+ "the magical bonds holding his\n"\
+ "creatures on this plane, their\n"\
+ "dying screams overwhelming his own\n"\
+ "cries of agony.\n\n"\
+ "your oath of vengeance fulfilled,\n"\
+ "you enter the portal to your own\n"\
+ "world, mere moments before the dome\n"\
+ "shatters into a million pieces.\n\n"\
+ "but if d'sparil's power is broken\n"\
+ "forever, why don't you feel safe?\n"\
+ "was it that last shout just before\n"\
+ "his death, the one that sounded\n"\
+ "like a curse? or a summoning? you\n"\
+ "can't really be sure, but it might\n"\
+ "just have been a scream.\n\n"\
+ "then again, what about the other\n"\
+ "serpent riders?"
+
+#define E4TEXT "you thought you would return to your\n"\
+ "own world after d'sparil died, but\n"\
+ "his final act banished you to his\n"\
+ "own plane. here you entered the\n"\
+ "shattered remnants of lands\n"\
+ "conquered by d'sparil. you defeated\n"\
+ "the last guardians of these lands,\n"\
+ "but now you stand before the gates\n"\
+ "to d'sparil's stronghold. until this\n"\
+ "moment you had no doubts about your\n"\
+ "ability to face anything you might\n"\
+ "encounter, but beyond this portal\n"\
+ "lies the very heart of the evil\n"\
+ "which invaded your world. d'sparil\n"\
+ "might be dead, but the pit where he\n"\
+ "was spawned remains. now you must\n"\
+ "enter that pit in the hopes of\n"\
+ "finding a way out. and somewhere,\n"\
+ "in the darkest corner of d'sparil's\n"\
+ "demesne, his personal bodyguards\n"\
+ "await your arrival ..."
+
+#define E5TEXT "as the final maulotaur bellows his\n"\
+ "death-agony, you realize that you\n"\
+ "have never come so close to your own\n"\
+ "destruction. not even the fight with\n"\
+ "d'sparil and his disciples had been\n"\
+ "this desperate. grimly you stare at\n"\
+ "the gates which open before you,\n"\
+ "wondering if they lead home, or if\n"\
+ "they open onto some undreamed-of\n"\
+ "horror. you find yourself wondering\n"\
+ "if you have the strength to go on,\n"\
+ "if nothing but death and pain await\n"\
+ "you. but what else can you do, if\n"\
+ "the will to fight is gone? can you\n"\
+ "force yourself to continue in the\n"\
+ "face of such despair? do you have\n"\
+ "the courage? you find, in the end,\n"\
+ "that it is not within you to\n"\
+ "surrender without a fight. eyes\n"\
+ "wide, you go to meet your fate."
+
diff --git a/src/heretic/f_finale.c b/src/heretic/f_finale.c
new file mode 100644
index 00000000..7f6b3594
--- /dev/null
+++ b/src/heretic/f_finale.c
@@ -0,0 +1,432 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+// F_finale.c
+
+#include <ctype.h>
+
+#include "doomdef.h"
+#include "deh_str.h"
+#include "i_swap.h"
+#include "i_video.h"
+#include "s_sound.h"
+#include "v_video.h"
+
+int finalestage; // 0 = text, 1 = art screen
+int finalecount;
+
+#define TEXTSPEED 3
+#define TEXTWAIT 250
+
+char *finaletext;
+char *finaleflat;
+
+int FontABaseLump;
+
+extern boolean automapactive;
+extern boolean viewactive;
+
+extern void D_StartTitle(void);
+
+/*
+=======================
+=
+= F_StartFinale
+=
+=======================
+*/
+
+void F_StartFinale(void)
+{
+ gameaction = ga_nothing;
+ gamestate = GS_FINALE;
+ viewactive = false;
+ automapactive = false;
+ players[consoleplayer].messageTics = 1;
+ players[consoleplayer].message = NULL;
+
+ switch (gameepisode)
+ {
+ case 1:
+ finaleflat = DEH_String("FLOOR25");
+ finaletext = DEH_String(E1TEXT);
+ break;
+ case 2:
+ finaleflat = DEH_String("FLATHUH1");
+ finaletext = DEH_String(E2TEXT);
+ break;
+ case 3:
+ finaleflat = DEH_String("FLTWAWA2");
+ finaletext = DEH_String(E3TEXT);
+ break;
+ case 4:
+ finaleflat = DEH_String("FLOOR28");
+ finaletext = DEH_String(E4TEXT);
+ break;
+ case 5:
+ finaleflat = DEH_String("FLOOR08");
+ finaletext = DEH_String(E5TEXT);
+ break;
+ }
+
+ finalestage = 0;
+ finalecount = 0;
+ FontABaseLump = W_GetNumForName(DEH_String("FONTA_S")) + 1;
+
+// S_ChangeMusic(mus_victor, true);
+ S_StartSong(mus_cptd, true);
+}
+
+
+
+boolean F_Responder(event_t * event)
+{
+ if (event->type != ev_keydown)
+ {
+ return false;
+ }
+ if (finalestage == 1 && gameepisode == 2)
+ { // we're showing the water pic, make any key kick to demo mode
+ finalestage++;
+ /*
+ memset((byte *) 0xa0000, 0, SCREENWIDTH * SCREENHEIGHT);
+ memset(I_VideoBuffer, 0, SCREENWIDTH * SCREENHEIGHT);
+ I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE));
+ */
+ return true;
+ }
+ return false;
+}
+
+
+/*
+=======================
+=
+= F_Ticker
+=
+=======================
+*/
+
+void F_Ticker(void)
+{
+ finalecount++;
+ if (!finalestage
+ && finalecount > strlen(finaletext) * TEXTSPEED + TEXTWAIT)
+ {
+ finalecount = 0;
+ if (!finalestage)
+ {
+ finalestage = 1;
+ }
+
+// wipegamestate = -1; // force a wipe
+/*
+ if (gameepisode == 3)
+ S_StartMusic (mus_bunny);
+*/
+ }
+}
+
+
+/*
+=======================
+=
+= F_TextWrite
+=
+=======================
+*/
+
+//#include "hu_stuff.h"
+//extern patch_t *hu_font[HU_FONTSIZE];
+
+void F_TextWrite(void)
+{
+ byte *src, *dest;
+ int x, y;
+ int count;
+ char *ch;
+ int c;
+ int cx, cy;
+ patch_t *w;
+
+//
+// erase the entire screen to a tiled background
+//
+ src = W_CacheLumpName(finaleflat, PU_CACHE);
+ dest = I_VideoBuffer;
+ for (y = 0; y < SCREENHEIGHT; y++)
+ {
+ for (x = 0; x < SCREENWIDTH / 64; x++)
+ {
+ memcpy(dest, src + ((y & 63) << 6), 64);
+ dest += 64;
+ }
+ if (SCREENWIDTH & 63)
+ {
+ 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 = 20;
+ cy = 5;
+ ch = finaletext;
+
+ count = (finalecount - 10) / TEXTSPEED;
+ if (count < 0)
+ count = 0;
+ for (; count; count--)
+ {
+ c = *ch++;
+ if (!c)
+ break;
+ if (c == '\n')
+ {
+ cx = 20;
+ cy += 9;
+ continue;
+ }
+
+ c = toupper(c);
+ if (c < 33)
+ {
+ cx += 5;
+ continue;
+ }
+
+ w = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
+ if (cx + w->width > SCREENWIDTH)
+ break;
+ V_DrawPatch(cx, cy, w);
+ cx += w->width;
+ }
+
+}
+
+
+void F_DrawPatchCol(int x, patch_t * patch, int col)
+{
+ column_t *column;
+ byte *source, *dest, *desttop;
+ int count;
+
+ column = (column_t *) ((byte *) patch + LONG(patch->columnofs[col]));
+ desttop = I_VideoBuffer + 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_DemonScroll
+=
+==================
+*/
+
+void F_DemonScroll(void)
+{
+ byte *p1, *p2;
+ static int yval = 0;
+ static int nextscroll = 0;
+
+ if (finalecount < nextscroll)
+ {
+ return;
+ }
+ p1 = W_CacheLumpName(DEH_String("FINAL1"), PU_LEVEL);
+ p2 = W_CacheLumpName(DEH_String("FINAL2"), PU_LEVEL);
+ if (finalecount < 70)
+ {
+ memcpy(I_VideoBuffer, p1, SCREENHEIGHT * SCREENWIDTH);
+ nextscroll = finalecount;
+ return;
+ }
+ if (yval < 64000)
+ {
+ memcpy(I_VideoBuffer, p2 + SCREENHEIGHT * SCREENWIDTH - yval, yval);
+ memcpy(I_VideoBuffer + yval, p1, SCREENHEIGHT * SCREENWIDTH - yval);
+ yval += SCREENWIDTH;
+ nextscroll = finalecount + 3;
+ }
+ else
+ { //else, we'll just sit here and wait, for now
+ memcpy(I_VideoBuffer, p2, SCREENWIDTH * SCREENHEIGHT);
+ }
+}
+
+/*
+==================
+=
+= F_DrawUnderwater
+=
+==================
+*/
+
+void F_DrawUnderwater(void)
+{
+ static boolean underwawa;
+ extern boolean askforquit;
+
+ switch (finalestage)
+ {
+ case 1:
+ if (!underwawa)
+ {
+ underwawa = true;
+ memset((byte *) 0xa0000, 0, SCREENWIDTH * SCREENHEIGHT);
+ I_SetPalette(W_CacheLumpName(DEH_String("E2PAL"), PU_CACHE));
+ V_DrawRawScreen(W_CacheLumpName(DEH_String("E2END"), PU_CACHE));
+ }
+ paused = false;
+ MenuActive = false;
+ askforquit = false;
+
+ break;
+ case 2:
+ V_DrawRawScreen(W_CacheLumpName(DEH_String("TITLE"), PU_CACHE));
+ //D_StartTitle(); // go to intro/demo mode.
+ }
+}
+
+
+#if 0
+/*
+==================
+=
+= F_BunnyScroll
+=
+==================
+*/
+
+void F_BunnyScroll(void)
+{
+ int scrolled, x;
+ patch_t *p1, *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(NULL, sfx_pistol);
+ laststage = stage;
+ }
+
+ sprintf(name, "END%i", stage);
+ V_DrawPatch((SCREENWIDTH - 13 * 8) / 2, (SCREENHEIGHT - 8 * 8) / 2,
+ W_CacheLumpName(name, PU_CACHE));
+}
+#endif
+
+/*
+=======================
+=
+= F_Drawer
+=
+=======================
+*/
+
+void F_Drawer(void)
+{
+ UpdateState |= I_FULLSCRN;
+ if (!finalestage)
+ F_TextWrite();
+ else
+ {
+ switch (gameepisode)
+ {
+ case 1:
+ if (gamemode == shareware)
+ {
+ V_DrawRawScreen(W_CacheLumpName("ORDER", PU_CACHE));
+ }
+ else
+ {
+ V_DrawRawScreen(W_CacheLumpName("CREDIT", PU_CACHE));
+ }
+ break;
+ case 2:
+ F_DrawUnderwater();
+ break;
+ case 3:
+ F_DemonScroll();
+ break;
+ case 4: // Just show credits screen for extended episodes
+ case 5:
+ V_DrawRawScreen(W_CacheLumpName("CREDIT", PU_CACHE));
+ break;
+ }
+ }
+}
diff --git a/src/heretic/g_game.c b/src/heretic/g_game.c
new file mode 100644
index 00000000..961314ef
--- /dev/null
+++ b/src/heretic/g_game.c
@@ -0,0 +1,1916 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// G_game.c
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "doomdef.h"
+#include "doomkeys.h"
+#include "deh_str.h"
+#include "i_timer.h"
+#include "i_system.h"
+#include "m_controls.h"
+#include "m_misc.h"
+#include "m_random.h"
+#include "p_local.h"
+#include "s_sound.h"
+#include "v_video.h"
+
+// Macros
+
+#define SVG_RAM 0
+#define SVG_FILE 1
+#define SAVE_GAME_TERMINATOR 0x1d
+#define AM_STARTKEY 9
+
+// Functions
+
+boolean G_CheckDemoStatus(void);
+void G_ReadDemoTiccmd(ticcmd_t * cmd);
+void G_WriteDemoTiccmd(ticcmd_t * cmd);
+void G_PlayerReborn(int player);
+
+void G_DoReborn(int playernum);
+
+void G_DoLoadLevel(void);
+void G_DoNewGame(void);
+void G_DoPlayDemo(void);
+void G_DoCompleted(void);
+void G_DoVictory(void);
+void G_DoWorldDone(void);
+void G_DoSaveGame(void);
+
+void D_PageTicker(void);
+void D_AdvanceDemo(void);
+
+struct
+{
+ mobjtype_t type;
+ int speed[2];
+} MonsterMissileInfo[] = {
+ { MT_IMPBALL, { 10, 20 } },
+ { MT_MUMMYFX1, { 9, 18 } },
+ { MT_KNIGHTAXE, { 9, 18 } },
+ { MT_REDAXE, { 9, 18 } },
+ { MT_BEASTBALL, { 12, 20 } },
+ { MT_WIZFX1, { 18, 24 } },
+ { MT_SNAKEPRO_A, { 14, 20 } },
+ { MT_SNAKEPRO_B, { 14, 20 } },
+ { MT_HEADFX1, { 13, 20 } },
+ { MT_HEADFX3, { 10, 18 } },
+ { MT_MNTRFX1, { 20, 26 } },
+ { MT_MNTRFX2, { 14, 20 } },
+ { MT_SRCRFX1, { 20, 28 } },
+ { MT_SOR2FX1, { 20, 28 } },
+ { -1, { -1, -1 } } // Terminator
+};
+
+FILE *SaveGameFP;
+int SaveGameType;
+
+gameaction_t gameaction;
+gamestate_t gamestate;
+skill_t gameskill;
+boolean respawnmonsters;
+int gameepisode;
+int gamemap;
+int prevmap;
+
+boolean paused;
+boolean sendpause; // send a pause event next tic
+boolean sendsave; // send a save event next tic
+boolean usergame; // ok to save / end game
+
+boolean timingdemo; // if true, exit with report on completion
+int starttime; // for comparative timing purposes
+
+boolean viewactive;
+
+boolean deathmatch; // only if started as net death
+boolean netgame; // only true if packets are broadcast
+boolean playeringame[MAXPLAYERS];
+player_t players[MAXPLAYERS];
+
+int consoleplayer; // player taking events and displaying
+int displayplayer; // view being displayed
+int gametic;
+int levelstarttic; // gametic at level start
+int totalkills, totalitems, totalsecret; // for intermission
+
+int mouseSensitivity;
+
+char demoname[32];
+boolean demorecording;
+boolean demoplayback;
+byte *demobuffer, *demo_p;
+boolean singledemo; // quit after playing a demo from cmdline
+
+boolean precache = true; // if true, load all graphics at start
+
+// TODO: Heretic uses 16-bit shorts for consistency?
+byte consistancy[MAXPLAYERS][BACKUPTICS];
+
+char *savegamedir;
+byte *savebuffer, *save_p;
+
+boolean testcontrols = false;
+int testcontrols_mousespeed;
+
+
+//
+// controls (have defaults)
+//
+
+
+
+#define MAXPLMOVE 0x32
+
+fixed_t forwardmove[2] = { 0x19, 0x32 };
+fixed_t sidemove[2] = { 0x18, 0x28 };
+fixed_t angleturn[3] = { 640, 1280, 320 }; // + slow turn
+
+static int *weapon_keys[] =
+{
+ &key_weapon1,
+ &key_weapon2,
+ &key_weapon3,
+ &key_weapon4,
+ &key_weapon5,
+ &key_weapon6,
+ &key_weapon7
+};
+
+// Set to -1 or +1 to switch to the previous or next weapon.
+
+static int next_weapon = 0;
+
+// Used for prev/next weapon keys.
+
+static const struct
+{
+ weapontype_t weapon;
+ weapontype_t weapon_num;
+} weapon_order_table[] = {
+ { wp_staff, wp_staff },
+ { wp_gauntlets, wp_staff },
+ { wp_goldwand, wp_goldwand },
+ { wp_crossbow, wp_crossbow },
+ { wp_blaster, wp_blaster },
+ { wp_skullrod, wp_skullrod },
+ { wp_phoenixrod, wp_phoenixrod },
+ { wp_mace, wp_mace },
+ { wp_beak, wp_beak },
+};
+
+#define SLOWTURNTICS 6
+
+#define NUMKEYS 256
+boolean gamekeydown[NUMKEYS];
+int turnheld; // for accelerative turning
+int lookheld;
+
+
+boolean mousearray[4];
+boolean *mousebuttons = &mousearray[1];
+ // allow [-1]
+int mousex, mousey; // mouse values are used once
+int dclicktime, dclickstate, dclicks;
+int dclicktime2, dclickstate2, dclicks2;
+
+#define MAX_JOY_BUTTONS 20
+
+int joyxmove, joyymove; // joystick values are repeated
+boolean joyarray[MAX_JOY_BUTTONS + 1];
+boolean *joybuttons = &joyarray[1]; // allow [-1]
+
+int savegameslot;
+char savedescription[32];
+
+int inventoryTics;
+
+// haleyjd: removed WATCOMC
+
+//=============================================================================
+// Not used - ripped out for Heretic
+/*
+int G_CmdChecksum(ticcmd_t *cmd)
+{
+ int i;
+ int sum;
+
+ sum = 0;
+ for(i = 0; i < sizeof(*cmd)/4-1; i++)
+ {
+ sum += ((int *)cmd)[i];
+ }
+ return(sum);
+}
+*/
+
+static boolean WeaponSelectable(weapontype_t weapon)
+{
+ if (weapon == wp_beak)
+ {
+ return false;
+ }
+
+ return players[consoleplayer].weaponowned[weapon];
+}
+
+static int G_NextWeapon(int direction)
+{
+ weapontype_t weapon;
+ int i;
+
+ // Find index in the table.
+
+ if (players[consoleplayer].pendingweapon == wp_nochange)
+ {
+ weapon = players[consoleplayer].readyweapon;
+ }
+ else
+ {
+ weapon = players[consoleplayer].pendingweapon;
+ }
+
+ for (i=0; i<arrlen(weapon_order_table); ++i)
+ {
+ if (weapon_order_table[i].weapon == weapon)
+ {
+ break;
+ }
+ }
+
+ // Switch weapon.
+
+ do
+ {
+ i += direction;
+ i = (i + arrlen(weapon_order_table)) % arrlen(weapon_order_table);
+ } while (!WeaponSelectable(weapon_order_table[i].weapon));
+
+ return weapon_order_table[i].weapon_num;
+}
+
+/*
+====================
+=
+= G_BuildTiccmd
+=
+= Builds a ticcmd from all of the available inputs or reads it from the
+= demo buffer.
+= If recording a demo, write it out
+====================
+*/
+
+extern boolean inventory;
+extern int curpos;
+extern int inv_ptr;
+
+boolean usearti = true;
+
+void G_BuildTiccmd(ticcmd_t *cmd, int maketic)
+{
+ int i;
+ boolean strafe, bstrafe;
+ int speed, tspeed, lspeed;
+ int forward, side;
+ int look, arti;
+ int flyheight;
+
+ extern boolean noartiskip;
+
+ // haleyjd: removed externdriver crap
+
+ memset(cmd, 0, sizeof(*cmd));
+ //cmd->consistancy =
+ // consistancy[consoleplayer][(maketic*ticdup)%BACKUPTICS];
+ cmd->consistancy = consistancy[consoleplayer][maketic % BACKUPTICS];
+
+//printf ("cons: %i\n",cmd->consistancy);
+
+ strafe = gamekeydown[key_strafe] || mousebuttons[mousebstrafe]
+ || joybuttons[joybstrafe];
+ speed = joybspeed >= MAX_JOY_BUTTONS
+ || gamekeydown[key_speed]
+ || joybuttons[joybspeed];
+
+ // haleyjd: removed externdriver crap
+
+ forward = side = look = arti = flyheight = 0;
+
+//
+// use two stage accelerative turning on the keyboard and joystick
+//
+ if (joyxmove < 0 || joyxmove > 0
+ || gamekeydown[key_right] || gamekeydown[key_left])
+ turnheld += ticdup;
+ else
+ turnheld = 0;
+ if (turnheld < SLOWTURNTICS)
+ tspeed = 2; // slow turn
+ else
+ tspeed = speed;
+
+ if (gamekeydown[key_lookdown] || gamekeydown[key_lookup])
+ {
+ lookheld += ticdup;
+ }
+ else
+ {
+ lookheld = 0;
+ }
+ if (lookheld < SLOWTURNTICS)
+ {
+ lspeed = 1;
+ }
+ else
+ {
+ lspeed = 2;
+ }
+
+//
+// let movement keys cancel each other out
+//
+ if (strafe)
+ {
+ if (gamekeydown[key_right])
+ side += sidemove[speed];
+ if (gamekeydown[key_left])
+ side -= sidemove[speed];
+ if (joyxmove > 0)
+ side += sidemove[speed];
+ if (joyxmove < 0)
+ side -= sidemove[speed];
+ }
+ else
+ {
+ if (gamekeydown[key_right])
+ cmd->angleturn -= angleturn[tspeed];
+ if (gamekeydown[key_left])
+ cmd->angleturn += angleturn[tspeed];
+ if (joyxmove > 0)
+ cmd->angleturn -= angleturn[tspeed];
+ if (joyxmove < 0)
+ cmd->angleturn += angleturn[tspeed];
+ }
+
+ if (gamekeydown[key_up])
+ forward += forwardmove[speed];
+ if (gamekeydown[key_down])
+ forward -= forwardmove[speed];
+ if (joyymove < 0)
+ forward += forwardmove[speed];
+ if (joyymove > 0)
+ forward -= forwardmove[speed];
+ if (gamekeydown[key_straferight] || mousebuttons[mousebstraferight]
+ || joybuttons[joybstraferight])
+ side += sidemove[speed];
+ if (gamekeydown[key_strafeleft] || mousebuttons[mousebstrafeleft]
+ || joybuttons[joybstrafeleft])
+ side -= sidemove[speed];
+
+ // Look up/down/center keys
+ if (gamekeydown[key_lookup])
+ {
+ look = lspeed;
+ }
+ if (gamekeydown[key_lookdown])
+ {
+ look = -lspeed;
+ }
+ // haleyjd: removed externdriver crap
+ if (gamekeydown[key_lookcenter])
+ {
+ look = TOCENTER;
+ }
+
+ // haleyjd: removed externdriver crap
+
+ // Fly up/down/drop keys
+ if (gamekeydown[key_flyup])
+ {
+ flyheight = 5; // note that the actual flyheight will be twice this
+ }
+ if (gamekeydown[key_flydown])
+ {
+ flyheight = -5;
+ }
+ if (gamekeydown[key_flycenter])
+ {
+ flyheight = TOCENTER;
+ // haleyjd: removed externdriver crap
+ look = TOCENTER;
+ }
+
+ // Use artifact key
+ if (gamekeydown[key_useartifact])
+ {
+ if (gamekeydown[key_speed] && !noartiskip)
+ {
+ if (players[consoleplayer].inventory[inv_ptr].type != arti_none)
+ {
+ gamekeydown[key_useartifact] = false;
+ cmd->arti = 0xff; // skip artifact code
+ }
+ }
+ else
+ {
+ if (inventory)
+ {
+ players[consoleplayer].readyArtifact =
+ players[consoleplayer].inventory[inv_ptr].type;
+ inventory = false;
+ cmd->arti = 0;
+ usearti = false;
+ }
+ else if (usearti)
+ {
+ cmd->arti = players[consoleplayer].inventory[inv_ptr].type;
+ usearti = false;
+ }
+ }
+ }
+ if (gamekeydown[127] && !cmd->arti
+ && !players[consoleplayer].powers[pw_weaponlevel2])
+ {
+ gamekeydown[127] = false;
+ cmd->arti = arti_tomeofpower;
+ }
+
+//
+// buttons
+//
+ cmd->chatchar = CT_dequeueChatChar();
+
+ if (gamekeydown[key_fire] || mousebuttons[mousebfire]
+ || joybuttons[joybfire])
+ cmd->buttons |= BT_ATTACK;
+
+ if (gamekeydown[key_use] || joybuttons[joybuse] || mousebuttons[mousebuse])
+ {
+ cmd->buttons |= BT_USE;
+ dclicks = 0; // clear double clicks if hit use button
+ }
+
+ // If the previous or next weapon button is pressed, the
+ // next_weapon variable is set to change weapons when
+ // we generate a ticcmd. Choose a new weapon.
+ // (Can't weapon cycle when the player is a chicken)
+
+ if (players[consoleplayer].chickenTics == 0 && next_weapon != 0)
+ {
+ i = G_NextWeapon(next_weapon);
+ cmd->buttons |= BT_CHANGE;
+ cmd->buttons |= i << BT_WEAPONSHIFT;
+ }
+ else
+ {
+ for (i=0; i<arrlen(weapon_keys); ++i)
+ {
+ int key = *weapon_keys[i];
+
+ if (gamekeydown[key])
+ {
+ cmd->buttons |= BT_CHANGE;
+ cmd->buttons |= i<<BT_WEAPONSHIFT;
+ break;
+ }
+ }
+ }
+
+ next_weapon = 0;
+
+//
+// mouse
+//
+ if (mousebuttons[mousebforward])
+ {
+ forward += forwardmove[speed];
+ }
+
+ if (mousebuttons[mousebbackward])
+ {
+ forward -= forwardmove[speed];
+ }
+
+ // Double click to use can be disabled
+
+ if (dclick_use)
+ {
+ //
+ // forward double click
+ //
+ if (mousebuttons[mousebforward] != dclickstate && dclicktime > 1)
+ {
+ dclickstate = mousebuttons[mousebforward];
+ if (dclickstate)
+ dclicks++;
+ if (dclicks == 2)
+ {
+ cmd->buttons |= BT_USE;
+ dclicks = 0;
+ }
+ else
+ dclicktime = 0;
+ }
+ else
+ {
+ dclicktime += ticdup;
+ if (dclicktime > 20)
+ {
+ dclicks = 0;
+ dclickstate = 0;
+ }
+ }
+
+ //
+ // strafe double click
+ //
+
+ bstrafe = mousebuttons[mousebstrafe] || joybuttons[joybstrafe];
+ if (bstrafe != dclickstate2 && dclicktime2 > 1)
+ {
+ dclickstate2 = bstrafe;
+ if (dclickstate2)
+ dclicks2++;
+ if (dclicks2 == 2)
+ {
+ cmd->buttons |= BT_USE;
+ dclicks2 = 0;
+ }
+ else
+ dclicktime2 = 0;
+ }
+ else
+ {
+ dclicktime2 += ticdup;
+ if (dclicktime2 > 20)
+ {
+ dclicks2 = 0;
+ dclickstate2 = 0;
+ }
+ }
+ }
+
+ if (strafe)
+ {
+ side += mousex * 2;
+ }
+ else
+ {
+ cmd->angleturn -= mousex * 0x8;
+ }
+
+ // No mouse movement in previous frame?
+
+ if (mousex == 0)
+ {
+ testcontrols_mousespeed = 0;
+ }
+
+ forward += mousey;
+ mousex = mousey = 0;
+
+ if (forward > MAXPLMOVE)
+ forward = MAXPLMOVE;
+ else if (forward < -MAXPLMOVE)
+ forward = -MAXPLMOVE;
+ if (side > MAXPLMOVE)
+ side = MAXPLMOVE;
+ else if (side < -MAXPLMOVE)
+ side = -MAXPLMOVE;
+
+ cmd->forwardmove += forward;
+ cmd->sidemove += side;
+ if (players[consoleplayer].playerstate == PST_LIVE)
+ {
+ if (look < 0)
+ {
+ look += 16;
+ }
+ cmd->lookfly = look;
+ }
+ if (flyheight < 0)
+ {
+ flyheight += 16;
+ }
+ cmd->lookfly |= flyheight << 4;
+
+//
+// special buttons
+//
+ if (sendpause)
+ {
+ sendpause = false;
+ cmd->buttons = BT_SPECIAL | BTS_PAUSE;
+ }
+
+ if (sendsave)
+ {
+ sendsave = false;
+ cmd->buttons =
+ BT_SPECIAL | BTS_SAVEGAME | (savegameslot << BTS_SAVESHIFT);
+ }
+
+}
+
+
+/*
+==============
+=
+= G_DoLoadLevel
+=
+==============
+*/
+
+void G_DoLoadLevel(void)
+{
+ int i;
+
+ levelstarttic = gametic; // for time calculation
+ gamestate = GS_LEVEL;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i] && players[i].playerstate == PST_DEAD)
+ players[i].playerstate = PST_REBORN;
+ memset(players[i].frags, 0, sizeof(players[i].frags));
+ }
+
+ P_SetupLevel(gameepisode, gamemap, 0, gameskill);
+ displayplayer = consoleplayer; // view the guy you are playing
+ starttime = I_GetTime();
+ gameaction = ga_nothing;
+ Z_CheckHeap();
+
+//
+// clear cmd building stuff
+//
+
+ memset(gamekeydown, 0, sizeof(gamekeydown));
+ joyxmove = joyymove = 0;
+ mousex = mousey = 0;
+ sendpause = sendsave = paused = false;
+ memset(mousebuttons, 0, sizeof(mousebuttons));
+ memset(joybuttons, 0, sizeof(joybuttons));
+
+ if (testcontrols)
+ {
+ P_SetMessage(&players[consoleplayer], "PRESS ESCAPE TO QUIT.", false);
+ }
+}
+
+static void SetJoyButtons(unsigned int buttons_mask)
+{
+ int i;
+
+ for (i=0; i<MAX_JOY_BUTTONS; ++i)
+ {
+ joybuttons[i] = (buttons_mask & (1 << i)) != 0;
+ }
+}
+
+/*
+===============================================================================
+=
+= G_Responder
+=
+= get info needed to make ticcmd_ts for the players
+=
+===============================================================================
+*/
+
+boolean G_Responder(event_t * ev)
+{
+ player_t *plr;
+
+ plr = &players[consoleplayer];
+ if (ev->type == ev_keyup && ev->data1 == key_useartifact)
+ { // flag to denote that it's okay to use an artifact
+ if (!inventory)
+ {
+ plr->readyArtifact = plr->inventory[inv_ptr].type;
+ }
+ usearti = true;
+ }
+
+ // Check for spy mode player cycle
+ if (gamestate == GS_LEVEL && ev->type == ev_keydown
+ && ev->data1 == KEY_F12 && !deathmatch)
+ { // Cycle the display player
+ do
+ {
+ displayplayer++;
+ if (displayplayer == MAXPLAYERS)
+ {
+ displayplayer = 0;
+ }
+ }
+ while (!playeringame[displayplayer]
+ && displayplayer != consoleplayer);
+ return (true);
+ }
+
+ if (gamestate == GS_LEVEL)
+ {
+ if (CT_Responder(ev))
+ { // Chat ate the event
+ return (true);
+ }
+ if (SB_Responder(ev))
+ { // Status bar ate the event
+ return (true);
+ }
+ if (AM_Responder(ev))
+ { // Automap ate the event
+ return (true);
+ }
+ }
+
+ if (ev->type == ev_mouse)
+ {
+ testcontrols_mousespeed = abs(ev->data2);
+ }
+
+ if (ev->type == ev_keydown && ev->data1 == key_prevweapon)
+ {
+ next_weapon = -1;
+ }
+ else if (ev->type == ev_keydown && ev->data1 == key_nextweapon)
+ {
+ next_weapon = 1;
+ }
+
+ switch (ev->type)
+ {
+ case ev_keydown:
+ if (ev->data1 == key_invleft)
+ {
+ inventoryTics = 5 * 35;
+ if (!inventory)
+ {
+ inventory = true;
+ break;
+ }
+ inv_ptr--;
+ if (inv_ptr < 0)
+ {
+ inv_ptr = 0;
+ }
+ else
+ {
+ curpos--;
+ if (curpos < 0)
+ {
+ curpos = 0;
+ }
+ }
+ return (true);
+ }
+ if (ev->data1 == key_invright)
+ {
+ inventoryTics = 5 * 35;
+ if (!inventory)
+ {
+ inventory = true;
+ break;
+ }
+ inv_ptr++;
+ if (inv_ptr >= plr->inventorySlotNum)
+ {
+ inv_ptr--;
+ if (inv_ptr < 0)
+ inv_ptr = 0;
+ }
+ else
+ {
+ curpos++;
+ if (curpos > 6)
+ {
+ curpos = 6;
+ }
+ }
+ return (true);
+ }
+ if (ev->data1 == KEY_PAUSE && !MenuActive)
+ {
+ sendpause = true;
+ return (true);
+ }
+ if (ev->data1 < NUMKEYS)
+ {
+ gamekeydown[ev->data1] = true;
+ }
+ return (true); // eat key down events
+
+ case ev_keyup:
+ if (ev->data1 < NUMKEYS)
+ {
+ gamekeydown[ev->data1] = false;
+ }
+ return (false); // always let key up events filter down
+
+ case ev_mouse:
+ mousebuttons[0] = ev->data1 & 1;
+ mousebuttons[1] = ev->data1 & 2;
+ mousebuttons[2] = ev->data1 & 4;
+ mousex = ev->data2 * (mouseSensitivity + 5) / 10;
+ mousey = ev->data3 * (mouseSensitivity + 5) / 10;
+ return (true); // eat events
+
+ case ev_joystick:
+ SetJoyButtons(ev->data1);
+ joyxmove = ev->data2;
+ joyymove = ev->data3;
+ return (true); // eat events
+
+ default:
+ break;
+ }
+ return (false);
+}
+
+/*
+===============================================================================
+=
+= G_Ticker
+=
+===============================================================================
+*/
+
+void G_Ticker(void)
+{
+ int i, buf;
+ ticcmd_t *cmd = NULL;
+
+//
+// do player reborns if needed
+//
+ for (i = 0; i < MAXPLAYERS; i++)
+ if (playeringame[i] && players[i].playerstate == PST_REBORN)
+ G_DoReborn(i);
+
+//
+// do things to change the game state
+//
+ while (gameaction != ga_nothing)
+ {
+ switch (gameaction)
+ {
+ case ga_loadlevel:
+ G_DoLoadLevel();
+ break;
+ case ga_newgame:
+ G_DoNewGame();
+ break;
+ case ga_loadgame:
+ G_DoLoadGame();
+ break;
+ case ga_savegame:
+ G_DoSaveGame();
+ break;
+ case ga_playdemo:
+ G_DoPlayDemo();
+ break;
+ case ga_screenshot:
+ V_ScreenShot("HTIC%02i.pcx");
+ gameaction = ga_nothing;
+ break;
+ case ga_completed:
+ G_DoCompleted();
+ break;
+ case ga_worlddone:
+ G_DoWorldDone();
+ break;
+ case ga_victory:
+ F_StartFinale();
+ break;
+ default:
+ break;
+ }
+ }
+
+
+//
+// get commands, check consistancy, and build new consistancy check
+//
+ //buf = gametic%BACKUPTICS;
+ buf = (gametic / ticdup) % BACKUPTICS;
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ if (playeringame[i])
+ {
+ cmd = &players[i].cmd;
+
+ memcpy(cmd, &netcmds[i], sizeof(ticcmd_t));
+
+ if (demoplayback)
+ G_ReadDemoTiccmd(cmd);
+ if (demorecording)
+ G_WriteDemoTiccmd(cmd);
+
+ if (netgame && !(gametic % ticdup))
+ {
+ if (gametic > BACKUPTICS
+ && consistancy[i][buf] != cmd->consistancy)
+ {
+ I_Error("consistency failure (%i should be %i)",
+ cmd->consistancy, consistancy[i][buf]);
+ }
+ if (players[i].mo)
+ consistancy[i][buf] = players[i].mo->x;
+ else
+ consistancy[i][buf] = rndindex;
+ }
+ }
+
+//
+// check for special buttons
+//
+ for (i = 0; i < MAXPLAYERS; i++)
+ if (playeringame[i])
+ {
+ if (players[i].cmd.buttons & BT_SPECIAL)
+ {
+ switch (players[i].cmd.buttons & BT_SPECIALMASK)
+ {
+ case BTS_PAUSE:
+ paused ^= 1;
+ if (paused)
+ {
+ S_PauseSound();
+ }
+ else
+ {
+ S_ResumeSound();
+ }
+ break;
+
+ case BTS_SAVEGAME:
+ if (!savedescription[0])
+ {
+ if (netgame)
+ {
+ strncpy(savedescription, DEH_String("NET GAME"),
+ sizeof(savedescription));
+ }
+ else
+ {
+ strncpy(savedescription, DEH_String("SAVE GAME"),
+ sizeof(savedescription));
+ }
+
+ savedescription[sizeof(savedescription) - 1] = '\0';
+ }
+ savegameslot =
+ (players[i].cmd.
+ buttons & BTS_SAVEMASK) >> BTS_SAVESHIFT;
+ gameaction = ga_savegame;
+ break;
+ }
+ }
+ }
+ // turn inventory off after a certain amount of time
+ if (inventory && !(--inventoryTics))
+ {
+ players[consoleplayer].readyArtifact =
+ players[consoleplayer].inventory[inv_ptr].type;
+ inventory = false;
+ cmd->arti = 0;
+ }
+//
+// do main actions
+//
+//
+// do main actions
+//
+ switch (gamestate)
+ {
+ case GS_LEVEL:
+ P_Ticker();
+ SB_Ticker();
+ AM_Ticker();
+ CT_Ticker();
+ break;
+ case GS_INTERMISSION:
+ IN_Ticker();
+ break;
+ case GS_FINALE:
+ F_Ticker();
+ break;
+ case GS_DEMOSCREEN:
+ D_PageTicker();
+ break;
+ }
+}
+
+
+/*
+==============================================================================
+
+ PLAYER STRUCTURE FUNCTIONS
+
+also see P_SpawnPlayer in P_Things
+==============================================================================
+*/
+
+/*
+====================
+=
+= G_InitPlayer
+=
+= Called at the start
+= Called by the game initialization functions
+====================
+*/
+
+void G_InitPlayer(int player)
+{
+ // clear everything else to defaults
+ G_PlayerReborn(player);
+}
+
+
+/*
+====================
+=
+= G_PlayerFinishLevel
+=
+= Can when a player completes a level
+====================
+*/
+extern int playerkeys;
+
+void G_PlayerFinishLevel(int player)
+{
+ player_t *p;
+ int i;
+
+/* // BIG HACK
+ inv_ptr = 0;
+ curpos = 0;
+*/
+ // END HACK
+ p = &players[player];
+ for (i = 0; i < p->inventorySlotNum; i++)
+ {
+ p->inventory[i].count = 1;
+ }
+ p->artifactCount = p->inventorySlotNum;
+
+ if (!deathmatch)
+ {
+ for (i = 0; i < 16; i++)
+ {
+ P_PlayerUseArtifact(p, arti_fly);
+ }
+ }
+ memset(p->powers, 0, sizeof(p->powers));
+ memset(p->keys, 0, sizeof(p->keys));
+ playerkeys = 0;
+// memset(p->inventory, 0, sizeof(p->inventory));
+ if (p->chickenTics)
+ {
+ p->readyweapon = p->mo->special1.i; // Restore weapon
+ p->chickenTics = 0;
+ }
+ p->messageTics = 0;
+ p->lookdir = 0;
+ p->mo->flags &= ~MF_SHADOW; // Remove invisibility
+ p->extralight = 0; // Remove weapon flashes
+ p->fixedcolormap = 0; // Remove torch
+ p->damagecount = 0; // No palette changes
+ p->bonuscount = 0;
+ p->rain1 = NULL;
+ p->rain2 = NULL;
+ if (p == &players[consoleplayer])
+ {
+ SB_state = -1; // refresh the status bar
+ }
+}
+
+/*
+====================
+=
+= G_PlayerReborn
+=
+= Called after a player dies
+= almost everything is cleared and initialized
+====================
+*/
+
+void G_PlayerReborn(int player)
+{
+ player_t *p;
+ int i;
+ int frags[MAXPLAYERS];
+ int killcount, itemcount, secretcount;
+ boolean secret;
+
+ secret = false;
+ memcpy(frags, players[player].frags, sizeof(frags));
+ killcount = players[player].killcount;
+ itemcount = players[player].itemcount;
+ secretcount = players[player].secretcount;
+
+ p = &players[player];
+ if (p->didsecret)
+ {
+ secret = true;
+ }
+ memset(p, 0, sizeof(*p));
+
+ memcpy(players[player].frags, frags, sizeof(players[player].frags));
+ players[player].killcount = killcount;
+ players[player].itemcount = itemcount;
+ players[player].secretcount = secretcount;
+
+ p->usedown = p->attackdown = true; // don't do anything immediately
+ p->playerstate = PST_LIVE;
+ p->health = MAXHEALTH;
+ p->readyweapon = p->pendingweapon = wp_goldwand;
+ p->weaponowned[wp_staff] = true;
+ p->weaponowned[wp_goldwand] = true;
+ p->messageTics = 0;
+ p->lookdir = 0;
+ p->ammo[am_goldwand] = 50;
+ for (i = 0; i < NUMAMMO; i++)
+ {
+ p->maxammo[i] = maxammo[i];
+ }
+ if (gamemap == 9 || secret)
+ {
+ p->didsecret = true;
+ }
+ if (p == &players[consoleplayer])
+ {
+ SB_state = -1; // refresh the status bar
+ inv_ptr = 0; // reset the inventory pointer
+ curpos = 0;
+ }
+}
+
+/*
+====================
+=
+= G_CheckSpot
+=
+= Returns false if the player cannot be respawned at the given mapthing_t spot
+= because something is occupying it
+====================
+*/
+
+void P_SpawnPlayer(mapthing_t * mthing);
+
+boolean G_CheckSpot(int playernum, mapthing_t * mthing)
+{
+ fixed_t x, y;
+ subsector_t *ss;
+ unsigned an;
+ mobj_t *mo;
+
+ x = mthing->x << FRACBITS;
+ y = mthing->y << FRACBITS;
+
+ players[playernum].mo->flags2 &= ~MF2_PASSMOBJ;
+ if (!P_CheckPosition(players[playernum].mo, x, y))
+ {
+ players[playernum].mo->flags2 |= MF2_PASSMOBJ;
+ return false;
+ }
+ players[playernum].mo->flags2 |= MF2_PASSMOBJ;
+
+// spawn a teleport fog
+ ss = R_PointInSubsector(x, y);
+ an = ((unsigned) ANG45 * (mthing->angle / 45)) >> ANGLETOFINESHIFT;
+
+ mo = P_SpawnMobj(x + 20 * finecosine[an], y + 20 * finesine[an],
+ ss->sector->floorheight + TELEFOGHEIGHT, MT_TFOG);
+
+ if (players[consoleplayer].viewz != 1)
+ S_StartSound(mo, sfx_telept); // don't start sound on first frame
+
+ return true;
+}
+
+/*
+====================
+=
+= G_DeathMatchSpawnPlayer
+=
+= Spawns a player at one of the random death match spots
+= called at level load and each death
+====================
+*/
+
+void G_DeathMatchSpawnPlayer(int playernum)
+{
+ int i, j;
+ int selections;
+
+ selections = deathmatch_p - deathmatchstarts;
+ if (selections < 4)
+ I_Error("Only %i deathmatch spots, 4 required", selections);
+
+ for (j = 0; j < 20; j++)
+ {
+ i = P_Random() % selections;
+ if (G_CheckSpot(playernum, &deathmatchstarts[i]))
+ {
+ deathmatchstarts[i].type = playernum + 1;
+ P_SpawnPlayer(&deathmatchstarts[i]);
+ return;
+ }
+ }
+
+// no good spot, so the player will probably get stuck
+ P_SpawnPlayer(&playerstarts[playernum]);
+}
+
+/*
+====================
+=
+= G_DoReborn
+=
+====================
+*/
+
+void G_DoReborn(int playernum)
+{
+ int i;
+
+ if (G_CheckDemoStatus())
+ return;
+ if (!netgame)
+ gameaction = ga_loadlevel; // reload the level from scratch
+ else
+ { // respawn at the start
+ players[playernum].mo->player = NULL; // dissasociate the corpse
+
+ // spawn at random spot if in death match
+ if (deathmatch)
+ {
+ G_DeathMatchSpawnPlayer(playernum);
+ return;
+ }
+
+ if (G_CheckSpot(playernum, &playerstarts[playernum]))
+ {
+ P_SpawnPlayer(&playerstarts[playernum]);
+ return;
+ }
+ // try to spawn at one of the other players spots
+ for (i = 0; i < MAXPLAYERS; i++)
+ if (G_CheckSpot(playernum, &playerstarts[i]))
+ {
+ playerstarts[i].type = playernum + 1; // fake as other player
+ P_SpawnPlayer(&playerstarts[i]);
+ playerstarts[i].type = i + 1; // restore
+ return;
+ }
+ // he's going to be inside something. Too bad.
+ P_SpawnPlayer(&playerstarts[playernum]);
+ }
+}
+
+
+void G_ScreenShot(void)
+{
+ gameaction = ga_screenshot;
+}
+
+
+/*
+====================
+=
+= G_DoCompleted
+=
+====================
+*/
+
+boolean secretexit;
+
+void G_ExitLevel(void)
+{
+ secretexit = false;
+ gameaction = ga_completed;
+}
+
+void G_SecretExitLevel(void)
+{
+ secretexit = true;
+ gameaction = ga_completed;
+}
+
+void G_DoCompleted(void)
+{
+ int i;
+ static int afterSecret[5] = { 7, 5, 5, 5, 4 };
+
+ gameaction = ga_nothing;
+ if (G_CheckDemoStatus())
+ {
+ return;
+ }
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ {
+ G_PlayerFinishLevel(i);
+ }
+ }
+ prevmap = gamemap;
+ if (secretexit == true)
+ {
+ gamemap = 9;
+ }
+ else if (gamemap == 9)
+ { // Finished secret level
+ gamemap = afterSecret[gameepisode - 1];
+ }
+ else if (gamemap == 8)
+ {
+ gameaction = ga_victory;
+ return;
+ }
+ else
+ {
+ gamemap++;
+ }
+ gamestate = GS_INTERMISSION;
+ IN_Start();
+}
+
+//============================================================================
+//
+// G_WorldDone
+//
+//============================================================================
+
+void G_WorldDone(void)
+{
+ gameaction = ga_worlddone;
+}
+
+//============================================================================
+//
+// G_DoWorldDone
+//
+//============================================================================
+
+void G_DoWorldDone(void)
+{
+ gamestate = GS_LEVEL;
+ G_DoLoadLevel();
+ gameaction = ga_nothing;
+ viewactive = true;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC G_LoadGame
+//
+// Can be called by the startup code or the menu task.
+//
+//---------------------------------------------------------------------------
+
+static char *savename = NULL;
+
+void G_LoadGame(char *name)
+{
+ savename = strdup(name);
+ gameaction = ga_loadgame;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC G_DoLoadGame
+//
+// Called by G_Ticker based on gameaction.
+//
+//---------------------------------------------------------------------------
+
+#define VERSIONSIZE 16
+
+void G_DoLoadGame(void)
+{
+ int i;
+ int a, b, c;
+ char vcheck[VERSIONSIZE];
+
+ gameaction = ga_nothing;
+
+ M_ReadFile(savename, &savebuffer);
+ free(savename);
+ savename = NULL;
+
+ save_p = savebuffer + SAVESTRINGSIZE;
+ // Skip the description field
+ memset(vcheck, 0, sizeof(vcheck));
+
+ DEH_snprintf(vcheck, VERSIONSIZE, "version %i", HERETIC_VERSION);
+
+ if (strcmp((char *) save_p, vcheck) != 0)
+ { // Bad version
+ return;
+ }
+ save_p += VERSIONSIZE;
+ gameskill = *save_p++;
+ gameepisode = *save_p++;
+ gamemap = *save_p++;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ playeringame[i] = *save_p++;
+ }
+ // Load a base level
+ G_InitNew(gameskill, gameepisode, gamemap);
+
+ // Create leveltime
+ a = *save_p++;
+ b = *save_p++;
+ c = *save_p++;
+ leveltime = (a << 16) + (b << 8) + c;
+
+ // De-archive all the modifications
+ P_UnArchivePlayers();
+ P_UnArchiveWorld();
+ P_UnArchiveThinkers();
+ P_UnArchiveSpecials();
+
+ if (*save_p != SAVE_GAME_TERMINATOR)
+ { // Missing savegame termination marker
+ I_Error("Bad savegame");
+ }
+ Z_Free(savebuffer);
+}
+
+
+/*
+====================
+=
+= G_InitNew
+=
+= Can be called by the startup code or the menu task
+= consoleplayer, displayplayer, playeringame[] should be set
+====================
+*/
+
+skill_t d_skill;
+int d_episode;
+int d_map;
+
+void G_DeferedInitNew(skill_t skill, int episode, int map)
+{
+ d_skill = skill;
+ d_episode = episode;
+ d_map = map;
+ gameaction = ga_newgame;
+}
+
+void G_DoNewGame(void)
+{
+ G_InitNew(d_skill, d_episode, d_map);
+ gameaction = ga_nothing;
+}
+
+void G_InitNew(skill_t skill, int episode, int map)
+{
+ int i;
+ int speed;
+ static char *skyLumpNames[5] = {
+ "SKY1", "SKY2", "SKY3", "SKY1", "SKY3"
+ };
+
+ if (paused)
+ {
+ paused = false;
+ S_ResumeSound();
+ }
+ if (skill < sk_baby)
+ skill = sk_baby;
+ if (skill > sk_nightmare)
+ skill = sk_nightmare;
+ if (episode < 1)
+ episode = 1;
+ // Up to 9 episodes for testing
+ if (episode > 9)
+ episode = 9;
+ if (map < 1)
+ map = 1;
+ if (map > 9)
+ map = 9;
+ M_ClearRandom();
+ if (respawnparm)
+ {
+ respawnmonsters = true;
+ }
+ else
+ {
+ respawnmonsters = false;
+ }
+ // Set monster missile speeds
+ speed = skill == sk_nightmare;
+ for (i = 0; MonsterMissileInfo[i].type != -1; i++)
+ {
+ mobjinfo[MonsterMissileInfo[i].type].speed
+ = MonsterMissileInfo[i].speed[speed] << FRACBITS;
+ }
+ // Force players to be initialized upon first level load
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ players[i].playerstate = PST_REBORN;
+ players[i].didsecret = false;
+ }
+ // Set up a bunch of globals
+ usergame = true; // will be set false if a demo
+ paused = false;
+ demorecording = false;
+ demoplayback = false;
+ viewactive = true;
+ gameepisode = episode;
+ gamemap = map;
+ gameskill = skill;
+ viewactive = true;
+ BorderNeedRefresh = true;
+
+ // Set the sky map
+ if (episode > 5)
+ {
+ skytexture = R_TextureNumForName(DEH_String("SKY1"));
+ }
+ else
+ {
+ skytexture = R_TextureNumForName(DEH_String(skyLumpNames[episode - 1]));
+ }
+
+//
+// give one null ticcmd_t
+//
+#if 0
+ gametic = 0;
+ maketic = 1;
+ for (i = 0; i < MAXPLAYERS; i++)
+ nettics[i] = 1; // one null event for this gametic
+ memset(localcmds, 0, sizeof(localcmds));
+ memset(netcmds, 0, sizeof(netcmds));
+#endif
+ G_DoLoadLevel();
+}
+
+
+/*
+===============================================================================
+
+ DEMO RECORDING
+
+===============================================================================
+*/
+
+#define DEMOMARKER 0x80
+
+void G_ReadDemoTiccmd(ticcmd_t * cmd)
+{
+ if (*demo_p == DEMOMARKER)
+ { // end of demo data stream
+ G_CheckDemoStatus();
+ return;
+ }
+ cmd->forwardmove = ((signed char) *demo_p++);
+ cmd->sidemove = ((signed char) *demo_p++);
+ cmd->angleturn = ((unsigned char) *demo_p++) << 8;
+ cmd->buttons = (unsigned char) *demo_p++;
+ cmd->lookfly = (unsigned char) *demo_p++;
+ cmd->arti = (unsigned char) *demo_p++;
+}
+
+void G_WriteDemoTiccmd(ticcmd_t * cmd)
+{
+ if (gamekeydown['q']) // press q to end demo recording
+ G_CheckDemoStatus();
+ *demo_p++ = cmd->forwardmove;
+ *demo_p++ = cmd->sidemove;
+ *demo_p++ = cmd->angleturn >> 8;
+ *demo_p++ = cmd->buttons;
+ *demo_p++ = cmd->lookfly;
+ *demo_p++ = cmd->arti;
+ demo_p -= 6;
+ G_ReadDemoTiccmd(cmd); // make SURE it is exactly the same
+}
+
+
+
+/*
+===================
+=
+= G_RecordDemo
+=
+===================
+*/
+
+void G_RecordDemo(skill_t skill, int numplayers, int episode, int map,
+ char *name)
+{
+ int i;
+
+ G_InitNew(skill, episode, map);
+ usergame = false;
+ strcpy(demoname, name);
+ strcat(demoname, ".lmp");
+ demobuffer = demo_p = Z_Malloc(0x20000, PU_STATIC, NULL);
+ *demo_p++ = skill;
+ *demo_p++ = episode;
+ *demo_p++ = map;
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ *demo_p++ = playeringame[i];
+
+ demorecording = true;
+}
+
+
+/*
+===================
+=
+= G_PlayDemo
+=
+===================
+*/
+
+char *defdemoname;
+
+void G_DeferedPlayDemo(char *name)
+{
+ defdemoname = name;
+ gameaction = ga_playdemo;
+}
+
+void G_DoPlayDemo(void)
+{
+ skill_t skill;
+ int i, episode, map;
+
+ gameaction = ga_nothing;
+ demobuffer = demo_p = W_CacheLumpName(defdemoname, PU_STATIC);
+ skill = *demo_p++;
+ episode = *demo_p++;
+ map = *demo_p++;
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ playeringame[i] = *demo_p++;
+
+ precache = false; // don't spend a lot of time in loadlevel
+ G_InitNew(skill, episode, map);
+ precache = true;
+ usergame = false;
+ demoplayback = true;
+}
+
+
+/*
+===================
+=
+= G_TimeDemo
+=
+===================
+*/
+
+void G_TimeDemo(char *name)
+{
+ skill_t skill;
+ int episode, map;
+
+ demobuffer = demo_p = W_CacheLumpName(name, PU_STATIC);
+ skill = *demo_p++;
+ episode = *demo_p++;
+ map = *demo_p++;
+ G_InitNew(skill, episode, map);
+ usergame = false;
+ demoplayback = true;
+ timingdemo = true;
+ singletics = true;
+}
+
+
+/*
+===================
+=
+= G_CheckDemoStatus
+=
+= Called after a death or level completion to allow demos to be cleaned up
+= Returns true if a new demo loop action will take place
+===================
+*/
+
+boolean G_CheckDemoStatus(void)
+{
+ int endtime;
+
+ if (timingdemo)
+ {
+ endtime = I_GetTime();
+ I_Error("timed %i gametics in %i realtics", gametic,
+ endtime - starttime);
+ }
+
+ if (demoplayback)
+ {
+ if (singledemo)
+ I_Quit();
+
+ W_ReleaseLumpName(defdemoname);
+ demoplayback = false;
+ D_AdvanceDemo();
+ return true;
+ }
+
+ if (demorecording)
+ {
+ *demo_p++ = DEMOMARKER;
+ M_WriteFile(demoname, demobuffer, demo_p - demobuffer);
+ Z_Free(demobuffer);
+ demorecording = false;
+ I_Error("Demo %s recorded", demoname);
+ }
+
+ return false;
+}
+
+/**************************************************************************/
+/**************************************************************************/
+
+//==========================================================================
+//
+// G_SaveGame
+//
+// Called by the menu task. <description> is a 24 byte text string.
+//
+//==========================================================================
+
+void G_SaveGame(int slot, char *description)
+{
+ savegameslot = slot;
+ strcpy(savedescription, description);
+ sendsave = true;
+}
+
+//==========================================================================
+//
+// G_DoSaveGame
+//
+// Called by G_Ticker based on gameaction.
+//
+//==========================================================================
+
+void G_DoSaveGame(void)
+{
+ int i;
+ char *filename;
+ char verString[VERSIONSIZE];
+ char *description;
+
+ filename = SV_Filename(savegameslot);
+
+ description = savedescription;
+
+ SV_Open(filename);
+ SV_Write(description, SAVESTRINGSIZE);
+ memset(verString, 0, sizeof(verString));
+ DEH_snprintf(verString, VERSIONSIZE, "version %i", HERETIC_VERSION);
+ SV_Write(verString, VERSIONSIZE);
+ SV_WriteByte(gameskill);
+ SV_WriteByte(gameepisode);
+ SV_WriteByte(gamemap);
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ SV_WriteByte(playeringame[i]);
+ }
+ SV_WriteByte(leveltime >> 16);
+ SV_WriteByte(leveltime >> 8);
+ SV_WriteByte(leveltime);
+ P_ArchivePlayers();
+ P_ArchiveWorld();
+ P_ArchiveThinkers();
+ P_ArchiveSpecials();
+ SV_Close(filename);
+
+ gameaction = ga_nothing;
+ savedescription[0] = 0;
+ P_SetMessage(&players[consoleplayer], DEH_String(TXT_GAMESAVED), true);
+
+ free(filename);
+}
+
+//==========================================================================
+//
+// SV_Filename
+//
+// Generate the filename to use for a particular savegame slot.
+// Returns a malloc()'d buffer that must be freed by the caller.
+//
+//==========================================================================
+
+char *SV_Filename(int slot)
+{
+ char *filename;
+
+ filename = malloc(strlen(savegamedir) + strlen(SAVEGAMENAME) + 8);
+ sprintf(filename, "%s" SAVEGAMENAME "%d.hsg", savegamedir, slot);
+
+ return filename;
+}
+
+//==========================================================================
+//
+// SV_Open
+//
+//==========================================================================
+
+void SV_Open(char *fileName)
+{
+ SaveGameType = SVG_FILE;
+ SaveGameFP = fopen(fileName, "wb");
+}
+
+//==========================================================================
+//
+// SV_Close
+//
+//==========================================================================
+
+void SV_Close(char *fileName)
+{
+ int length;
+
+ SV_WriteByte(SAVE_GAME_TERMINATOR);
+ if (SaveGameType == SVG_RAM)
+ {
+ length = save_p - savebuffer;
+ if (length > SAVEGAMESIZE)
+ {
+ I_Error("Savegame buffer overrun");
+ }
+ M_WriteFile(fileName, savebuffer, length);
+ Z_Free(savebuffer);
+ }
+ else
+ { // SVG_FILE
+ fclose(SaveGameFP);
+ }
+}
+
+//==========================================================================
+//
+// SV_Write
+//
+//==========================================================================
+
+void SV_Write(void *buffer, int size)
+{
+ if (SaveGameType == SVG_RAM)
+ {
+ memcpy(save_p, buffer, size);
+ save_p += size;
+ }
+ else
+ { // SVG_FILE
+ fwrite(buffer, size, 1, SaveGameFP);
+ }
+}
+
+void SV_WriteByte(byte val)
+{
+ SV_Write(&val, sizeof(byte));
+}
+
+void SV_WriteWord(unsigned short val)
+{
+ SV_Write(&val, sizeof(unsigned short));
+}
+
+void SV_WriteLong(unsigned int val)
+{
+ SV_Write(&val, sizeof(int));
+}
diff --git a/src/heretic/i_ibm.c b/src/heretic/i_ibm.c
new file mode 100644
index 00000000..cf668680
--- /dev/null
+++ b/src/heretic/i_ibm.c
@@ -0,0 +1,1650 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// I_IBM.C
+
+#include <dos.h>
+#include <conio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <graph.h>
+#include "doomdef.h"
+#include "r_local.h"
+#include "dmx.h"
+#include "v_video.h"
+
+// Macros
+
+#define DPMI_INT 0x31
+//#define NOKBD
+//#define NOTIMER
+
+// Public Data
+
+int DisplayTicker = 0;
+
+// Code
+
+void main(int argc, char **argv)
+{
+ myargc = argc;
+ myargv = argv;
+ D_DoomMain();
+}
+
+void I_StartupNet(void);
+void I_ShutdownNet(void);
+void I_ReadExternDriver(void);
+
+typedef struct
+{
+ unsigned edi, esi, ebp, reserved, ebx, edx, ecx, eax;
+ unsigned short flags, es, ds, fs, gs, ip, cs, sp, ss;
+} dpmiregs_t;
+
+extern dpmiregs_t dpmiregs;
+
+void I_ReadMouse(void);
+void I_InitDiskFlash(void);
+
+extern int usemouse, usejoystick;
+
+extern void **lumpcache;
+
+/*
+=============================================================================
+
+ CONSTANTS
+
+=============================================================================
+*/
+
+#define SC_INDEX 0x3C4
+#define SC_RESET 0
+#define SC_CLOCK 1
+#define SC_MAPMASK 2
+#define SC_CHARMAP 3
+#define SC_MEMMODE 4
+
+#define CRTC_INDEX 0x3D4
+#define CRTC_H_TOTAL 0
+#define CRTC_H_DISPEND 1
+#define CRTC_H_BLANK 2
+#define CRTC_H_ENDBLANK 3
+#define CRTC_H_RETRACE 4
+#define CRTC_H_ENDRETRACE 5
+#define CRTC_V_TOTAL 6
+#define CRTC_OVERFLOW 7
+#define CRTC_ROWSCAN 8
+#define CRTC_MAXSCANLINE 9
+#define CRTC_CURSORSTART 10
+#define CRTC_CURSOREND 11
+#define CRTC_STARTHIGH 12
+#define CRTC_STARTLOW 13
+#define CRTC_CURSORHIGH 14
+#define CRTC_CURSORLOW 15
+#define CRTC_V_RETRACE 16
+#define CRTC_V_ENDRETRACE 17
+#define CRTC_V_DISPEND 18
+#define CRTC_OFFSET 19
+#define CRTC_UNDERLINE 20
+#define CRTC_V_BLANK 21
+#define CRTC_V_ENDBLANK 22
+#define CRTC_MODE 23
+#define CRTC_LINECOMPARE 24
+
+
+#define GC_INDEX 0x3CE
+#define GC_SETRESET 0
+#define GC_ENABLESETRESET 1
+#define GC_COLORCOMPARE 2
+#define GC_DATAROTATE 3
+#define GC_READMAP 4
+#define GC_MODE 5
+#define GC_MISCELLANEOUS 6
+#define GC_COLORDONTCARE 7
+#define GC_BITMASK 8
+
+#define ATR_INDEX 0x3c0
+#define ATR_MODE 16
+#define ATR_OVERSCAN 17
+#define ATR_COLORPLANEENABLE 18
+#define ATR_PELPAN 19
+#define ATR_COLORSELECT 20
+
+#define STATUS_REGISTER_1 0x3da
+
+#define PEL_WRITE_ADR 0x3c8
+#define PEL_READ_ADR 0x3c7
+#define PEL_DATA 0x3c9
+#define PEL_MASK 0x3c6
+
+boolean grmode;
+
+//==================================================
+//
+// joystick vars
+//
+//==================================================
+
+boolean joystickpresent;
+extern unsigned joystickx, joysticky;
+boolean I_ReadJoystick(void); // returns false if not connected
+
+
+//==================================================
+
+#define VBLCOUNTER 34000 // hardware tics to a frame
+
+
+#define TIMERINT 8
+#define KEYBOARDINT 9
+
+#define CRTCOFF (_inbyte(STATUS_REGISTER_1)&1)
+#define CLI _disable()
+#define STI _enable()
+
+#define _outbyte(x,y) (outp(x,y))
+#define _outhword(x,y) (outpw(x,y))
+
+#define _inbyte(x) (inp(x))
+#define _inhword(x) (inpw(x))
+
+#define MOUSEB1 1
+#define MOUSEB2 2
+#define MOUSEB3 4
+
+boolean mousepresent;
+//static int tsm_ID = -1; // tsm init flag
+
+//===============================
+
+int ticcount;
+
+// REGS stuff used for int calls
+union REGS regs;
+struct SREGS segregs;
+
+boolean novideo; // if true, stay in text mode for debugging
+
+#define KBDQUESIZE 32
+byte keyboardque[KBDQUESIZE];
+int kbdtail, kbdhead;
+
+#define KEY_LSHIFT 0xfe
+
+#define KEY_INS (0x80+0x52)
+#define KEY_DEL (0x80+0x53)
+#define KEY_PGUP (0x80+0x49)
+#define KEY_PGDN (0x80+0x51)
+#define KEY_HOME (0x80+0x47)
+#define KEY_END (0x80+0x4f)
+
+#define SC_RSHIFT 0x36
+#define SC_LSHIFT 0x2a
+
+byte scantokey[128] = {
+// 0 1 2 3 4 5 6 7
+// 8 9 A B C D E F
+ 0, 27, '1', '2', '3', '4', '5', '6',
+ '7', '8', '9', '0', '-', '=', KEY_BACKSPACE, 9, // 0
+ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
+ 'o', 'p', '[', ']', 13, KEY_RCTRL, 'a', 's', // 1
+ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
+ 39, '`', KEY_LSHIFT, 92, 'z', 'x', 'c', 'v', // 2
+ 'b', 'n', 'm', ',', '.', '/', KEY_RSHIFT, '*',
+ KEY_RALT, ' ', 0, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, // 3
+ KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, 0, 0, KEY_HOME,
+ KEY_UPARROW, KEY_PGUP, '-', KEY_LEFTARROW, '5', KEY_RIGHTARROW, '+', KEY_END, //4
+ KEY_DOWNARROW, KEY_PGDN, KEY_INS, KEY_DEL, 0, 0, 0, KEY_F11,
+ KEY_F12, 0, 0, 0, 0, 0, 0, 0, // 5
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, // 6
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 // 7
+};
+
+//==========================================================================
+
+//--------------------------------------------------------------------------
+//
+// FUNC I_GetTime
+//
+// Returns time in 1/35th second tics.
+//
+//--------------------------------------------------------------------------
+
+int I_GetTime(void)
+{
+#ifdef NOTIMER
+ ticcount++;
+#endif
+ return (ticcount);
+}
+
+//--------------------------------------------------------------------------
+//
+// PROC I_ColorBorder
+//
+//--------------------------------------------------------------------------
+
+void I_ColorBorder(void)
+{
+ int i;
+
+ I_WaitVBL(1);
+ _outbyte(PEL_WRITE_ADR, 0);
+ for (i = 0; i < 3; i++)
+ {
+ _outbyte(PEL_DATA, 63);
+ }
+}
+
+//--------------------------------------------------------------------------
+//
+// PROC I_UnColorBorder
+//
+//--------------------------------------------------------------------------
+
+void I_UnColorBorder(void)
+{
+ int i;
+
+ I_WaitVBL(1);
+ _outbyte(PEL_WRITE_ADR, 0);
+ for (i = 0; i < 3; i++)
+ {
+ _outbyte(PEL_DATA, 0);
+ }
+}
+
+/*
+============================================================================
+
+ USER INPUT
+
+============================================================================
+*/
+
+//--------------------------------------------------------------------------
+//
+// PROC I_WaitVBL
+//
+//--------------------------------------------------------------------------
+
+void I_WaitVBL(int vbls)
+{
+ int i;
+ int old;
+ int stat;
+
+ if (novideo)
+ {
+ return;
+ }
+ while (vbls--)
+ {
+ do
+ {
+ stat = inp(STATUS_REGISTER_1);
+ if (stat & 8)
+ {
+ break;
+ }
+ }
+ while (1);
+ do
+ {
+ stat = inp(STATUS_REGISTER_1);
+ if ((stat & 8) == 0)
+ {
+ break;
+ }
+ }
+ while (1);
+ }
+}
+
+//--------------------------------------------------------------------------
+//
+// PROC I_SetPalette
+//
+// Palette source must use 8 bit RGB elements.
+//
+//--------------------------------------------------------------------------
+
+void I_SetPalette(byte * palette)
+{
+ int i;
+
+ if (novideo)
+ {
+ return;
+ }
+ I_WaitVBL(1);
+ _outbyte(PEL_WRITE_ADR, 0);
+ for (i = 0; i < 768; i++)
+ {
+ _outbyte(PEL_DATA, (gammatable[usegamma][*palette++]) >> 2);
+ }
+}
+
+/*
+============================================================================
+
+ GRAPHICS MODE
+
+============================================================================
+*/
+
+byte *pcscreen, *destscreen, *destview;
+
+
+/*
+==============
+=
+= I_Update
+=
+==============
+*/
+
+int UpdateState;
+extern int screenblocks;
+
+void I_Update(void)
+{
+ int i;
+ byte *dest;
+ int tics;
+ static int lasttic;
+
+//
+// blit screen to video
+//
+ if (DisplayTicker)
+ {
+ if (screenblocks > 9 || UpdateState & (I_FULLSCRN | I_MESSAGES))
+ {
+ dest = (byte *) screen;
+ }
+ else
+ {
+ dest = (byte *) pcscreen;
+ }
+ tics = ticcount - lasttic;
+ lasttic = ticcount;
+ if (tics > 20)
+ {
+ tics = 20;
+ }
+ for (i = 0; i < tics; i++)
+ {
+ *dest = 0xff;
+ dest += 2;
+ }
+ for (i = tics; i < 20; i++)
+ {
+ *dest = 0x00;
+ dest += 2;
+ }
+ }
+ if (UpdateState == I_NOUPDATE)
+ {
+ return;
+ }
+ if (UpdateState & I_FULLSCRN)
+ {
+ memcpy(pcscreen, screen, SCREENWIDTH * SCREENHEIGHT);
+ UpdateState = I_NOUPDATE; // clear out all draw types
+ }
+ if (UpdateState & I_FULLVIEW)
+ {
+ if (UpdateState & I_MESSAGES && screenblocks > 7)
+ {
+ for (i = 0; i <
+ (viewwindowy + viewheight) * SCREENWIDTH; i += SCREENWIDTH)
+ {
+ memcpy(pcscreen + i, screen + i, SCREENWIDTH);
+ }
+ UpdateState &= ~(I_FULLVIEW | I_MESSAGES);
+ }
+ else
+ {
+ for (i = viewwindowy * SCREENWIDTH + viewwindowx; i <
+ (viewwindowy + viewheight) * SCREENWIDTH; i += SCREENWIDTH)
+ {
+ memcpy(pcscreen + i, screen + i, viewwidth);
+ }
+ UpdateState &= ~I_FULLVIEW;
+ }
+ }
+ if (UpdateState & I_STATBAR)
+ {
+ memcpy(pcscreen + SCREENWIDTH * (SCREENHEIGHT - SBARHEIGHT),
+ screen + SCREENWIDTH * (SCREENHEIGHT - SBARHEIGHT),
+ SCREENWIDTH * SBARHEIGHT);
+ UpdateState &= ~I_STATBAR;
+ }
+ if (UpdateState & I_MESSAGES)
+ {
+ memcpy(pcscreen, screen, SCREENWIDTH * 28);
+ UpdateState &= ~I_MESSAGES;
+ }
+
+// memcpy(pcscreen, screen, SCREENHEIGHT*SCREENWIDTH);
+}
+
+//--------------------------------------------------------------------------
+//
+// PROC I_InitGraphics
+//
+//--------------------------------------------------------------------------
+
+void I_InitGraphics(void)
+{
+ if (novideo)
+ {
+ return;
+ }
+ grmode = true;
+ regs.w.ax = 0x13;
+ int386(0x10, (const union REGS *) &regs, &regs);
+ pcscreen = destscreen = (byte *) 0xa0000;
+ I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE));
+ I_InitDiskFlash();
+}
+
+//--------------------------------------------------------------------------
+//
+// PROC I_ShutdownGraphics
+//
+//--------------------------------------------------------------------------
+
+void I_ShutdownGraphics(void)
+{
+
+ if (*(byte *) 0x449 == 0x13) // don't reset mode if it didn't get set
+ {
+ regs.w.ax = 3;
+ int386(0x10, &regs, &regs); // back to text mode
+ }
+}
+
+//--------------------------------------------------------------------------
+//
+// PROC I_ReadScreen
+//
+// Reads the screen currently displayed into a linear buffer.
+//
+//--------------------------------------------------------------------------
+
+void I_ReadScreen(byte * scr)
+{
+ memcpy(scr, screen, SCREENWIDTH * SCREENHEIGHT);
+}
+
+
+//===========================================================================
+
+/*
+===================
+=
+= I_StartTic
+=
+// called by D_DoomLoop
+// called before processing each tic in a frame
+// can call D_PostEvent
+// asyncronous interrupt functions should maintain private ques that are
+// read by the syncronous functions to be converted into events
+===================
+*/
+
+/*
+ OLD STARTTIC STUFF
+
+void I_StartTic (void)
+{
+ int k;
+ event_t ev;
+
+
+ I_ReadMouse ();
+
+//
+// keyboard events
+//
+ while (kbdtail < kbdhead)
+ {
+ k = keyboardque[kbdtail&(KBDQUESIZE-1)];
+
+// if (k==14)
+// I_Error ("exited");
+
+ kbdtail++;
+
+ // extended keyboard shift key bullshit
+ if ( (k&0x7f)==KEY_RSHIFT )
+ {
+ if ( keyboardque[(kbdtail-2)&(KBDQUESIZE-1)]==0xe0 )
+ continue;
+ k &= 0x80;
+ k |= KEY_RSHIFT;
+ }
+
+ if (k==0xe0)
+ continue; // special / pause keys
+ if (keyboardque[(kbdtail-2)&(KBDQUESIZE-1)] == 0xe1)
+ continue; // pause key bullshit
+
+ if (k==0xc5 && keyboardque[(kbdtail-2)&(KBDQUESIZE-1)] == 0x9d)
+ {
+ ev.type = ev_keydown;
+ ev.data1 = KEY_PAUSE;
+ D_PostEvent (&ev);
+ continue;
+ }
+
+ if (k&0x80)
+ ev.type = ev_keyup;
+ else
+ ev.type = ev_keydown;
+ k &= 0x7f;
+
+ ev.data1 = k;
+ //ev.data1 = scantokey[k];
+
+ D_PostEvent (&ev);
+ }
+}
+*/
+
+#define SC_UPARROW 0x48
+#define SC_DOWNARROW 0x50
+#define SC_LEFTARROW 0x4b
+#define SC_RIGHTARROW 0x4d
+
+void I_StartTic(void)
+{
+ int k;
+ event_t ev;
+
+
+ I_ReadMouse();
+
+//
+// keyboard events
+//
+ while (kbdtail < kbdhead)
+ {
+ k = keyboardque[kbdtail & (KBDQUESIZE - 1)];
+ kbdtail++;
+
+ // extended keyboard shift key bullshit
+ if ((k & 0x7f) == SC_LSHIFT || (k & 0x7f) == SC_RSHIFT)
+ {
+ if (keyboardque[(kbdtail - 2) & (KBDQUESIZE - 1)] == 0xe0)
+ continue;
+ k &= 0x80;
+ k |= SC_RSHIFT;
+ }
+
+ if (k == 0xe0)
+ continue; // special / pause keys
+ if (keyboardque[(kbdtail - 2) & (KBDQUESIZE - 1)] == 0xe1)
+ continue; // pause key bullshit
+
+ if (k == 0xc5
+ && keyboardque[(kbdtail - 2) & (KBDQUESIZE - 1)] == 0x9d)
+ {
+ ev.type = ev_keydown;
+ ev.data1 = KEY_PAUSE;
+ D_PostEvent(&ev);
+ continue;
+ }
+
+ if (k & 0x80)
+ ev.type = ev_keyup;
+ else
+ ev.type = ev_keydown;
+ k &= 0x7f;
+ switch (k)
+ {
+ case SC_UPARROW:
+ ev.data1 = KEY_UPARROW;
+ break;
+ case SC_DOWNARROW:
+ ev.data1 = KEY_DOWNARROW;
+ break;
+ case SC_LEFTARROW:
+ ev.data1 = KEY_LEFTARROW;
+ break;
+ case SC_RIGHTARROW:
+ ev.data1 = KEY_RIGHTARROW;
+ break;
+ default:
+ ev.data1 = scantokey[k];
+ break;
+ }
+ D_PostEvent(&ev);
+ }
+
+}
+
+
+void I_ReadKeys(void)
+{
+ int k;
+ event_t ev;
+
+
+ while (1)
+ {
+ while (kbdtail < kbdhead)
+ {
+ k = keyboardque[kbdtail & (KBDQUESIZE - 1)];
+ kbdtail++;
+ printf("0x%x\n", k);
+ if (k == 1)
+ I_Quit();
+ }
+ }
+}
+
+/*
+===============
+=
+= I_StartFrame
+=
+===============
+*/
+
+void I_StartFrame(void)
+{
+ I_JoystickEvents();
+ I_ReadExternDriver();
+}
+
+/*
+============================================================================
+
+ TIMER INTERRUPT
+
+============================================================================
+*/
+
+void I_ColorBlack(int r, int g, int b)
+{
+ _outbyte(PEL_WRITE_ADR, 0);
+ _outbyte(PEL_DATA, r);
+ _outbyte(PEL_DATA, g);
+ _outbyte(PEL_DATA, b);
+}
+
+
+/*
+================
+=
+= I_TimerISR
+=
+================
+*/
+
+int I_TimerISR(void)
+{
+ ticcount++;
+ return 0;
+}
+
+/*
+============================================================================
+
+ KEYBOARD
+
+============================================================================
+*/
+
+void (__interrupt __far * oldkeyboardisr) () = NULL;
+
+int lastpress;
+
+/*
+================
+=
+= I_KeyboardISR
+=
+================
+*/
+
+void __interrupt I_KeyboardISR(void)
+{
+// Get the scan code
+
+ keyboardque[kbdhead & (KBDQUESIZE - 1)] = lastpress = _inbyte(0x60);
+ kbdhead++;
+
+// acknowledge the interrupt
+
+ _outbyte(0x20, 0x20);
+}
+
+
+
+/*
+===============
+=
+= I_StartupKeyboard
+=
+===============
+*/
+
+void I_StartupKeyboard(void)
+{
+#ifndef NOKBD
+ oldkeyboardisr = _dos_getvect(KEYBOARDINT);
+ _dos_setvect(0x8000 | KEYBOARDINT, I_KeyboardISR);
+#endif
+
+//I_ReadKeys ();
+}
+
+
+void I_ShutdownKeyboard(void)
+{
+ if (oldkeyboardisr)
+ _dos_setvect(KEYBOARDINT, oldkeyboardisr);
+ *(short *) 0x41c = *(short *) 0x41a; // clear bios key buffer
+}
+
+
+
+/*
+============================================================================
+
+ MOUSE
+
+============================================================================
+*/
+
+
+int I_ResetMouse(void)
+{
+ regs.w.ax = 0; // reset
+ int386(0x33, &regs, &regs);
+ return regs.w.ax;
+}
+
+
+
+/*
+================
+=
+= StartupMouse
+=
+================
+*/
+
+void I_StartupCyberMan(void);
+
+void I_StartupMouse(void)
+{
+ int (far * function) ();
+
+ //
+ // General mouse detection
+ //
+ mousepresent = 0;
+ if (M_CheckParm("-nomouse") || !usemouse)
+ return;
+
+ if (I_ResetMouse() != 0xffff)
+ {
+ tprintf("Mouse: not present ", 0);
+ return;
+ }
+ tprintf("Mouse: detected ", 0);
+
+ mousepresent = 1;
+
+ I_StartupCyberMan();
+}
+
+
+/*
+================
+=
+= ShutdownMouse
+=
+================
+*/
+
+void I_ShutdownMouse(void)
+{
+ if (!mousepresent)
+ return;
+
+ I_ResetMouse();
+}
+
+
+/*
+================
+=
+= I_ReadMouse
+=
+================
+*/
+
+void I_ReadMouse(void)
+{
+ event_t ev;
+
+//
+// mouse events
+//
+ if (!mousepresent)
+ return;
+
+ ev.type = ev_mouse;
+
+ memset(&dpmiregs, 0, sizeof(dpmiregs));
+ dpmiregs.eax = 3; // read buttons / position
+ DPMIInt(0x33);
+ ev.data1 = dpmiregs.ebx;
+
+ dpmiregs.eax = 11; // read counters
+ DPMIInt(0x33);
+ ev.data2 = (short) dpmiregs.ecx;
+ ev.data3 = -(short) dpmiregs.edx;
+
+ D_PostEvent(&ev);
+}
+
+/*
+============================================================================
+
+ JOYSTICK
+
+============================================================================
+*/
+
+int joyxl, joyxh, joyyl, joyyh;
+
+boolean WaitJoyButton(void)
+{
+ int oldbuttons, buttons;
+
+ oldbuttons = 0;
+ do
+ {
+ I_WaitVBL(1);
+ buttons = ((inp(0x201) >> 4) & 1) ^ 1;
+ if (buttons != oldbuttons)
+ {
+ oldbuttons = buttons;
+ continue;
+ }
+
+ if ((lastpress & 0x7f) == 1)
+ {
+ joystickpresent = false;
+ return false;
+ }
+ }
+ while (!buttons);
+
+ do
+ {
+ I_WaitVBL(1);
+ buttons = ((inp(0x201) >> 4) & 1) ^ 1;
+ if (buttons != oldbuttons)
+ {
+ oldbuttons = buttons;
+ continue;
+ }
+
+ if ((lastpress & 0x7f) == 1)
+ {
+ joystickpresent = false;
+ return false;
+ }
+ }
+ while (buttons);
+
+ return true;
+}
+
+
+
+/*
+===============
+=
+= I_StartupJoystick
+=
+===============
+*/
+
+int basejoyx, basejoyy;
+
+void I_StartupJoystick(void)
+{
+ int buttons;
+ int count;
+ int centerx, centery;
+
+ joystickpresent = 0;
+ if (M_CheckParm("-nojoy") || !usejoystick)
+ return;
+
+ if (!I_ReadJoystick())
+ {
+ joystickpresent = false;
+ tprintf("joystick not found ", 0);
+ return;
+ }
+ printf("joystick found\n");
+ joystickpresent = true;
+
+ printf("CENTER the joystick and press button 1:");
+ if (!WaitJoyButton())
+ return;
+ I_ReadJoystick();
+ centerx = joystickx;
+ centery = joysticky;
+
+ printf
+ ("\nPush the joystick to the UPPER LEFT corner and press button 1:");
+ if (!WaitJoyButton())
+ return;
+ I_ReadJoystick();
+ joyxl = (centerx + joystickx) / 2;
+ joyyl = (centerx + joysticky) / 2;
+
+ printf
+ ("\nPush the joystick to the LOWER RIGHT corner and press button 1:");
+ if (!WaitJoyButton())
+ return;
+ I_ReadJoystick();
+ joyxh = (centerx + joystickx) / 2;
+ joyyh = (centery + joysticky) / 2;
+ printf("\n");
+}
+
+/*
+===============
+=
+= I_JoystickEvents
+=
+===============
+*/
+
+void I_JoystickEvents(void)
+{
+ event_t ev;
+
+//
+// joystick events
+//
+ if (!joystickpresent)
+ return;
+
+ I_ReadJoystick();
+ ev.type = ev_joystick;
+ ev.data1 = ((inp(0x201) >> 4) & 15) ^ 15;
+
+ if (joystickx < joyxl)
+ ev.data2 = -1;
+ else if (joystickx > joyxh)
+ ev.data2 = 1;
+ else
+ ev.data2 = 0;
+ if (joysticky < joyyl)
+ ev.data3 = -1;
+ else if (joysticky > joyyh)
+ ev.data3 = 1;
+ else
+ ev.data3 = 0;
+
+ D_PostEvent(&ev);
+}
+
+
+
+/*
+============================================================================
+
+ DPMI STUFF
+
+============================================================================
+*/
+
+#define REALSTACKSIZE 1024
+
+dpmiregs_t dpmiregs;
+
+unsigned realstackseg;
+
+void I_DivException(void);
+int I_SetDivException(void);
+
+void DPMIFarCall(void)
+{
+ segread(&segregs);
+ regs.w.ax = 0x301;
+ regs.w.bx = 0;
+ regs.w.cx = 0;
+ regs.x.edi = (unsigned) &dpmiregs;
+ segregs.es = segregs.ds;
+ int386x(DPMI_INT, &regs, &regs, &segregs);
+}
+
+
+void DPMIInt(int i)
+{
+ dpmiregs.ss = realstackseg;
+ dpmiregs.sp = REALSTACKSIZE - 4;
+
+ segread(&segregs);
+ regs.w.ax = 0x300;
+ regs.w.bx = i;
+ regs.w.cx = 0;
+ regs.x.edi = (unsigned) &dpmiregs;
+ segregs.es = segregs.ds;
+ int386x(DPMI_INT, &regs, &regs, &segregs);
+}
+
+
+/*
+==============
+=
+= I_StartupDPMI
+=
+==============
+*/
+
+void I_StartupDPMI(void)
+{
+ extern char __begtext;
+ extern char ___argc;
+ int n, d;
+
+//
+// allocate a decent stack for real mode ISRs
+//
+ realstackseg = (int) I_AllocLow(1024) >> 4;
+
+//
+// lock the entire program down
+//
+
+// _dpmi_lockregion (&__begtext, &___argc - &__begtext);
+
+
+//
+// catch divide by 0 exception
+//
+#if 0
+ segread(&segregs);
+ regs.w.ax = 0x0203; // DPMI set processor exception handler vector
+ regs.w.bx = 0; // int 0
+ regs.w.cx = segregs.cs;
+ regs.x.edx = (int) &I_DivException;
+ printf("%x : %x\n", regs.w.cx, regs.x.edx);
+ int386(DPMI_INT, &regs, &regs);
+#endif
+
+#if 0
+ n = I_SetDivException();
+ printf("return: %i\n", n);
+ n = 100;
+ d = 0;
+ printf("100 / 0 = %i\n", n / d);
+
+ exit(1);
+#endif
+}
+
+
+
+/*
+============================================================================
+
+ TIMER INTERRUPT
+
+============================================================================
+*/
+
+void (__interrupt __far * oldtimerisr) ();
+
+
+void IO_ColorBlack(int r, int g, int b)
+{
+ _outbyte(PEL_WRITE_ADR, 0);
+ _outbyte(PEL_DATA, r);
+ _outbyte(PEL_DATA, g);
+ _outbyte(PEL_DATA, b);
+}
+
+
+/*
+================
+=
+= IO_TimerISR
+=
+================
+*/
+
+//void __interrupt IO_TimerISR (void)
+
+void __interrupt __far IO_TimerISR(void)
+{
+ ticcount++;
+ _outbyte(0x20, 0x20); // Ack the interrupt
+}
+
+/*
+=====================
+=
+= IO_SetTimer0
+=
+= Sets system timer 0 to the specified speed
+=
+=====================
+*/
+
+void IO_SetTimer0(int speed)
+{
+ if (speed > 0 && speed < 150)
+ I_Error("INT_SetTimer0: %i is a bad value", speed);
+
+ _outbyte(0x43, 0x36); // Change timer 0
+ _outbyte(0x40, speed);
+ _outbyte(0x40, speed >> 8);
+}
+
+
+
+/*
+===============
+=
+= IO_StartupTimer
+=
+===============
+*/
+
+void IO_StartupTimer(void)
+{
+ oldtimerisr = _dos_getvect(TIMERINT);
+
+ _dos_setvect(0x8000 | TIMERINT, IO_TimerISR);
+ IO_SetTimer0(VBLCOUNTER);
+}
+
+void IO_ShutdownTimer(void)
+{
+ if (oldtimerisr)
+ {
+ IO_SetTimer0(0); // back to 18.4 ips
+ _dos_setvect(TIMERINT, oldtimerisr);
+ }
+}
+
+//===========================================================================
+
+
+/*
+===============
+=
+= I_Init
+=
+= hook interrupts and set graphics mode
+=
+===============
+*/
+
+void I_Init(void)
+{
+ extern void I_StartupTimer(void);
+
+ novideo = M_CheckParm("novideo");
+ tprintf("I_StartupDPMI", 1);
+ I_StartupDPMI();
+ tprintf("I_StartupMouse ", 1);
+ I_StartupMouse();
+// tprintf("I_StartupJoystick ",1);
+// I_StartupJoystick();
+// tprintf("I_StartupKeyboard ",1);
+// I_StartupKeyboard();
+}
+
+
+/*
+===============
+=
+= I_Shutdown
+=
+= return to default system state
+=
+===============
+*/
+
+void I_Shutdown(void)
+{
+ I_ShutdownGraphics();
+ IO_ShutdownTimer();
+ S_ShutDown();
+ I_ShutdownMouse();
+ I_ShutdownKeyboard();
+
+ IO_SetTimer0(0);
+}
+
+
+/*
+================
+=
+= I_Error
+=
+================
+*/
+
+void I_Error(char *error, ...)
+{
+ union REGS regs;
+
+ va_list argptr;
+
+ D_QuitNetGame();
+ I_Shutdown();
+ va_start(argptr, error);
+ regs.x.eax = 0x3;
+ int386(0x10, &regs, &regs);
+ vprintf(error, argptr);
+ va_end(argptr);
+ printf("\n");
+ exit(1);
+}
+
+//--------------------------------------------------------------------------
+//
+// I_Quit
+//
+// Shuts down net game, saves defaults, prints the exit text message,
+// goes to text mode, and exits.
+//
+//--------------------------------------------------------------------------
+
+void I_Quit(void)
+{
+ byte *scr;
+ char *lumpName;
+ int r;
+
+ D_QuitNetGame();
+ M_SaveDefaults();
+ scr = (byte *) W_CacheLumpName("ENDTEXT", PU_CACHE);
+ I_Shutdown();
+ memcpy((void *) 0xb8000, scr, 80 * 25 * 2);
+ regs.w.ax = 0x0200;
+ regs.h.bh = 0;
+ regs.h.dl = 0;
+ regs.h.dh = 23;
+ int386(0x10, (const union REGS *) &regs, &regs); // Set text pos
+ _settextposition(24, 1);
+ exit(0);
+}
+
+/*
+===============
+=
+= I_ZoneBase
+=
+===============
+*/
+
+byte *I_ZoneBase(int *size)
+{
+ int meminfo[32];
+ int heap;
+ int i;
+ int block;
+ byte *ptr;
+
+ memset(meminfo, 0, sizeof(meminfo));
+ segread(&segregs);
+ segregs.es = segregs.ds;
+ regs.w.ax = 0x500; // get memory info
+ regs.x.edi = (int) &meminfo;
+ int386x(0x31, &regs, &regs, &segregs);
+
+ heap = meminfo[0];
+ printf("DPMI memory: 0x%x, ", heap);
+
+ do
+ {
+ heap -= 0x10000; // leave 64k alone
+ if (heap > 0x800000)
+ heap = 0x800000;
+ ptr = malloc(heap);
+ }
+ while (!ptr);
+
+ printf("0x%x allocated for zone\n", heap);
+ if (heap < 0x180000)
+ I_Error("Insufficient DPMI memory!");
+#if 0
+ regs.w.ax = 0x501; // allocate linear block
+ regs.w.bx = heap >> 16;
+ regs.w.cx = heap & 0xffff;
+ int386(0x31, &regs, &regs);
+ if (regs.w.cflag)
+ I_Error("Couldn't allocate DPMI memory!");
+
+ block = (regs.w.si << 16) + regs.w.di;
+#endif
+
+ *size = heap;
+ return ptr;
+}
+
+/*
+=============================================================================
+
+ DISK ICON FLASHING
+
+=============================================================================
+*/
+
+void I_InitDiskFlash(void)
+{
+#if 0
+ void *pic;
+ byte *temp;
+
+ pic = W_CacheLumpName("STDISK", PU_CACHE);
+ temp = destscreen;
+ destscreen = (byte *) 0xac000;
+ V_DrawPatchDirect(SCREENWIDTH - 16, SCREENHEIGHT - 16, 0, pic);
+ destscreen = temp;
+#endif
+}
+
+// draw disk icon
+void I_BeginRead(void)
+{
+#if 0
+ byte *src, *dest;
+ int y;
+
+ if (!grmode)
+ return;
+
+// write through all planes
+ outp(SC_INDEX, SC_MAPMASK);
+ outp(SC_INDEX + 1, 15);
+// set write mode 1
+ outp(GC_INDEX, GC_MODE);
+ outp(GC_INDEX + 1, inp(GC_INDEX + 1) | 1);
+
+// copy to backup
+ src = currentscreen + 184 * 80 + 304 / 4;
+ dest = (byte *) 0xac000 + 184 * 80 + 288 / 4;
+ for (y = 0; y < 16; y++)
+ {
+ dest[0] = src[0];
+ dest[1] = src[1];
+ dest[2] = src[2];
+ dest[3] = src[3];
+ src += 80;
+ dest += 80;
+ }
+
+// copy disk over
+ dest = currentscreen + 184 * 80 + 304 / 4;
+ src = (byte *) 0xac000 + 184 * 80 + 304 / 4;
+ for (y = 0; y < 16; y++)
+ {
+ dest[0] = src[0];
+ dest[1] = src[1];
+ dest[2] = src[2];
+ dest[3] = src[3];
+ src += 80;
+ dest += 80;
+ }
+
+
+// set write mode 0
+ outp(GC_INDEX, GC_MODE);
+ outp(GC_INDEX + 1, inp(GC_INDEX + 1) & ~1);
+#endif
+}
+
+// erase disk icon
+void I_EndRead(void)
+{
+#if 0
+ byte *src, *dest;
+ int y;
+
+ if (!grmode)
+ return;
+
+// write through all planes
+ outp(SC_INDEX, SC_MAPMASK);
+ outp(SC_INDEX + 1, 15);
+// set write mode 1
+ outp(GC_INDEX, GC_MODE);
+ outp(GC_INDEX + 1, inp(GC_INDEX + 1) | 1);
+
+
+// copy disk over
+ dest = currentscreen + 184 * 80 + 304 / 4;
+ src = (byte *) 0xac000 + 184 * 80 + 288 / 4;
+ for (y = 0; y < 16; y++)
+ {
+ dest[0] = src[0];
+ dest[1] = src[1];
+ dest[2] = src[2];
+ dest[3] = src[3];
+ src += 80;
+ dest += 80;
+ }
+
+// set write mode 0
+ outp(GC_INDEX, GC_MODE);
+ outp(GC_INDEX + 1, inp(GC_INDEX + 1) & ~1);
+#endif
+}
+
+
+
+/*
+=============
+=
+= I_AllocLow
+=
+=============
+*/
+
+byte *I_AllocLow(int length)
+{
+ byte *mem;
+
+ // DPMI call 100h allocates DOS memory
+ segread(&segregs);
+ regs.w.ax = 0x0100; // DPMI allocate DOS memory
+ regs.w.bx = (length + 15) / 16;
+ int386(DPMI_INT, &regs, &regs);
+// segment = regs.w.ax;
+// selector = regs.w.dx;
+ if (regs.w.cflag != 0)
+ I_Error("I_AllocLow: DOS alloc of %i failed, %i free",
+ length, regs.w.bx * 16);
+
+
+ mem = (void *) ((regs.x.eax & 0xFFFF) << 4);
+
+ memset(mem, 0, length);
+ return mem;
+}
+
+/*
+============================================================================
+
+ NETWORKING
+
+============================================================================
+*/
+
+/* // FUCKED LINES
+typedef struct
+{
+ char priv[508];
+ } doomdata_t;
+*/// FUCKED LINES
+
+#define DOOMCOM_ID 0x12345678l
+
+/* // FUCKED LINES
+typedef struct
+{
+ long id;
+ short intnum; // DOOM executes an int to execute commands
+
+// communication between DOOM and the driver
+ short command; // CMD_SEND or CMD_GET
+ short remotenode; // dest for send, set by get (-1 = no packet)
+ short datalength; // bytes in doomdata to be sent
+
+// info common to all nodes
+ short numnodes; // console is allways node 0
+ short ticdup; // 1 = no duplication, 2-5 = dup for slow nets
+ short extratics; // 1 = send a backup tic in every packet
+ short deathmatch; // 1 = deathmatch
+ short savegame; // -1 = new game, 0-5 = load savegame
+ short episode; // 1-3
+ short map; // 1-9
+ short skill; // 1-5
+
+// info specific to this node
+ short consoleplayer;
+ short numplayers;
+ short angleoffset; // 1 = left, 0 = center, -1 = right
+ short drone; // 1 = drone
+
+// packet data to be sent
+ doomdata_t data;
+ } doomcom_t;
+*/// FUCKED LINES
+
+extern doomcom_t *doomcom;
+
+/*
+====================
+=
+= I_InitNetwork
+=
+====================
+*/
+
+void I_InitNetwork(void)
+{
+ int i;
+
+ i = M_CheckParm("-net");
+ if (!i)
+ {
+ //
+ // single player game
+ //
+ doomcom = malloc(sizeof(*doomcom));
+ memset(doomcom, 0, sizeof(*doomcom));
+ netgame = false;
+ doomcom->id = DOOMCOM_ID;
+ doomcom->numplayers = doomcom->numnodes = 1;
+ doomcom->deathmatch = false;
+ doomcom->consoleplayer = 0;
+ doomcom->ticdup = 1;
+ doomcom->extratics = 0;
+ return;
+ }
+
+ netgame = true;
+ doomcom = (doomcom_t *) atoi(myargv[i + 1]);
+//DEBUG
+ doomcom->skill = startskill;
+ doomcom->episode = startepisode;
+ doomcom->map = startmap;
+ doomcom->deathmatch = deathmatch;
+
+}
+
+void I_NetCmd(void)
+{
+ if (!netgame)
+ I_Error("I_NetCmd when not in netgame");
+ DPMIInt(doomcom->intnum);
+}
+
+int i_Vector;
+externdata_t *i_ExternData;
+boolean useexterndriver;
+
+//=========================================================================
+//
+// I_CheckExternDriver
+//
+// Checks to see if a vector, and an address for an external driver
+// have been passed.
+//=========================================================================
+
+void I_CheckExternDriver(void)
+{
+ int i;
+
+ if (!(i = M_CheckParm("-externdriver")))
+ {
+ return;
+ }
+ i_ExternData = (externdata_t *) atoi(myargv[i + 1]);
+ i_Vector = i_ExternData->vector;
+
+ useexterndriver = true;
+}
+
+//=========================================================================
+//
+// I_ReadExternDriver
+//
+// calls the external interrupt, which should then update i_ExternDriver
+//=========================================================================
+
+void I_ReadExternDriver(void)
+{
+ event_t ev;
+
+ if (useexterndriver)
+ {
+ DPMIInt(i_Vector);
+ }
+}
diff --git a/src/heretic/i_sound.c b/src/heretic/i_sound.c
new file mode 100644
index 00000000..d3f04767
--- /dev/null
+++ b/src/heretic/i_sound.c
@@ -0,0 +1,432 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// I_SOUND.C
+
+#include <stdio.h>
+#include "doomdef.h"
+#include "dmx.h"
+#include "sounds.h"
+#include "i_sound.h"
+#include "v_video.h"
+
+/*
+===============
+=
+= I_StartupTimer
+=
+===============
+*/
+
+int tsm_ID = -1;
+
+void I_StartupTimer(void)
+{
+#ifndef NOTIMER
+ extern int I_TimerISR(void);
+
+ tprintf("I_StartupTimer()\n", 0);
+ // installs master timer. Must be done before StartupTimer()!
+ TSM_Install(SND_TICRATE);
+ tsm_ID = TSM_NewService(I_TimerISR, 35, 255, 0); // max priority
+ if (tsm_ID == -1)
+ {
+ I_Error("Can't register 35 Hz timer w/ DMX library");
+ }
+#endif
+}
+
+void I_ShutdownTimer(void)
+{
+ TSM_DelService(tsm_ID);
+ TSM_Remove();
+}
+
+/*
+ *
+ * SOUND HEADER & DATA
+ *
+ *
+ */
+
+// sound information
+#if 0
+const char *dnames[] = { "None",
+ "PC_Speaker",
+ "Adlib",
+ "Sound_Blaster",
+ "ProAudio_Spectrum16",
+ "Gravis_Ultrasound",
+ "MPU",
+ "AWE32"
+};
+#endif
+
+const char snd_prefixen[] = { 'P', 'P', 'A', 'S', 'S', 'S', 'M',
+ 'M', 'M', 'S'
+};
+
+int snd_Channels;
+int snd_DesiredMusicDevice, snd_DesiredSfxDevice;
+int snd_MusicDevice, // current music card # (index to dmxCodes)
+ snd_SfxDevice, // current sfx card # (index to dmxCodes)
+ snd_MaxVolume, // maximum volume for sound
+ snd_MusicVolume; // maximum volume for music
+int dmxCodes[NUM_SCARDS]; // the dmx code for a given card
+
+int snd_SBport, snd_SBirq, snd_SBdma; // sound blaster variables
+int snd_Mport; // midi variables
+
+extern boolean snd_MusicAvail, // whether music is available
+ snd_SfxAvail; // whether sfx are available
+
+void I_PauseSong(int handle)
+{
+ MUS_PauseSong(handle);
+}
+
+void I_ResumeSong(int handle)
+{
+ MUS_ResumeSong(handle);
+}
+
+void I_SetMusicVolume(int volume)
+{
+ MUS_SetMasterVolume(volume * 8);
+// snd_MusicVolume = volume;
+}
+
+void I_SetSfxVolume(int volume)
+{
+ snd_MaxVolume = volume; // THROW AWAY?
+}
+
+/*
+ *
+ * SONG API
+ *
+ */
+
+int I_RegisterSong(void *data)
+{
+ int rc = MUS_RegisterSong(data);
+#ifdef SNDDEBUG
+ if (rc < 0)
+ printf("MUS_Reg() returned %d\n", rc);
+#endif
+ return rc;
+}
+
+void I_UnRegisterSong(int handle)
+{
+ int rc = MUS_UnregisterSong(handle);
+#ifdef SNDDEBUG
+ if (rc < 0)
+ printf("MUS_Unreg() returned %d\n", rc);
+#endif
+}
+
+int I_QrySongPlaying(int handle)
+{
+ int rc = MUS_QrySongPlaying(handle);
+#ifdef SNDDEBUG
+ if (rc < 0)
+ printf("MUS_QrySP() returned %d\n", rc);
+#endif
+ return rc;
+}
+
+// Stops a song. MUST be called before I_UnregisterSong().
+
+void I_StopSong(int handle)
+{
+ int rc;
+ rc = MUS_StopSong(handle);
+#ifdef SNDDEBUG
+ if (rc < 0)
+ printf("MUS_StopSong() returned %d\n", rc);
+#endif
+ // Fucking kluge pause
+ {
+ int s;
+ extern volatile int ticcount;
+ for (s = ticcount; ticcount - s < 10;);
+ }
+}
+
+void I_PlaySong(int handle, boolean looping)
+{
+ int rc;
+ rc = MUS_ChainSong(handle, looping ? handle : -1);
+#ifdef SNDDEBUG
+ if (rc < 0)
+ printf("MUS_ChainSong() returned %d\n", rc);
+#endif
+ rc = MUS_PlaySong(handle, snd_MusicVolume);
+#ifdef SNDDEBUG
+ if (rc < 0)
+ printf("MUS_PlaySong() returned %d\n", rc);
+#endif
+
+}
+
+/*
+ *
+ * SOUND FX API
+ *
+ */
+
+// Gets lump nums of the named sound. Returns pointer which will be
+// passed to I_StartSound() when you want to start an SFX. Must be
+// sure to pass this to UngetSoundEffect() so that they can be
+// freed!
+
+
+int I_GetSfxLumpNum(sfxinfo_t * sound)
+{
+ char namebuf[9];
+
+ if (sound->name == 0)
+ return 0;
+ if (sound->link)
+ sound = sound->link;
+// sprintf(namebuf, "d%c%s", snd_prefixen[snd_SfxDevice], sound->name);
+ return W_GetNumForName(sound->name);
+
+}
+
+int I_StartSound(int id, void *data, int vol, int sep, int pitch,
+ int priority)
+{
+/*
+ // hacks out certain PC sounds
+ if (snd_SfxDevice == PC
+ && (data == S_sfx[sfx_posact].data
+ || data == S_sfx[sfx_bgact].data
+ || data == S_sfx[sfx_dmact].data
+ || data == S_sfx[sfx_dmpain].data
+ || data == S_sfx[sfx_popain].data
+ || data == S_sfx[sfx_sawidl].data)) return -1;
+
+ else
+ */
+ return SFX_PlayPatch(data, pitch, sep, vol, 0, 0);
+
+}
+
+void I_StopSound(int handle)
+{
+// extern volatile long gDmaCount;
+// long waittocount;
+ SFX_StopPatch(handle);
+// waittocount = gDmaCount + 2;
+// while (gDmaCount < waittocount) ;
+}
+
+int I_SoundIsPlaying(int handle)
+{
+ return SFX_Playing(handle);
+}
+
+void I_UpdateSoundParams(int handle, int vol, int sep, int pitch)
+{
+ SFX_SetOrigin(handle, pitch, sep, vol);
+}
+
+/*
+ *
+ * SOUND STARTUP STUFF
+ *
+ *
+ */
+
+//
+// Why PC's Suck, Reason #8712
+//
+
+void I_sndArbitrateCards(void)
+{
+ char tmp[160];
+ boolean gus, adlib, pc, sb, midi;
+ int i, rc, mputype, p, opltype, wait, dmxlump;
+
+// snd_MaxVolume = 127;
+ //Damn you, Dave Taylor!
+
+ snd_MusicDevice = snd_DesiredMusicDevice;
+ snd_SfxDevice = snd_DesiredSfxDevice;
+
+ // check command-line parameters- overrides config file
+ //
+ if (M_CheckParm("-nosound"))
+ snd_MusicDevice = snd_SfxDevice = snd_none;
+ if (M_CheckParm("-nosfx"))
+ snd_SfxDevice = snd_none;
+ if (M_CheckParm("-nomusic"))
+ snd_MusicDevice = snd_none;
+
+ if (snd_MusicDevice > snd_MPU && snd_MusicDevice <= snd_MPU3)
+ snd_MusicDevice = snd_MPU;
+ if (snd_MusicDevice == snd_SB)
+ snd_MusicDevice = snd_Adlib;
+ if (snd_MusicDevice == snd_PAS)
+ snd_MusicDevice = snd_Adlib;
+
+ // figure out what i've got to initialize
+ //
+ gus = snd_MusicDevice == snd_GUS || snd_SfxDevice == snd_GUS;
+ sb = snd_SfxDevice == snd_SB || snd_MusicDevice == snd_SB;
+ adlib = snd_MusicDevice == snd_Adlib;
+ pc = snd_SfxDevice == snd_PC;
+ midi = snd_MusicDevice == snd_MPU;
+
+ // initialize whatever i've got
+ //
+ if (gus)
+ {
+ if (GF1_Detect())
+ tprintf("Dude. The GUS ain't responding.\n", 1);
+ else
+ {
+ dmxlump = W_GetNumForName("dmxgus");
+ GF1_SetMap(W_CacheLumpNum(dmxlump, PU_CACHE),
+ lumpinfo[dmxlump].size);
+ }
+
+ }
+ if (sb)
+ {
+ if (debugmode)
+ {
+ sprintf(tmp, "cfg p=0x%x, i=%d, d=%d\n",
+ snd_SBport, snd_SBirq, snd_SBdma);
+ tprintf(tmp, 0);
+ }
+ if (SB_Detect(&snd_SBport, &snd_SBirq, &snd_SBdma, 0))
+ {
+ sprintf(tmp, "SB isn't responding at p=0x%x, i=%d, d=%d\n",
+ snd_SBport, snd_SBirq, snd_SBdma);
+ tprintf(tmp, 0);
+ }
+ else
+ SB_SetCard(snd_SBport, snd_SBirq, snd_SBdma);
+
+ if (debugmode)
+ {
+ sprintf(tmp, "SB_Detect returned p=0x%x,i=%d,d=%d\n",
+ snd_SBport, snd_SBirq, snd_SBdma);
+ tprintf(tmp, 0);
+ }
+ }
+
+ if (adlib)
+ {
+ if (AL_Detect(&wait, 0))
+ tprintf("Dude. The Adlib isn't responding.\n", 1);
+ else
+ AL_SetCard(wait, W_CacheLumpName("genmidi", PU_STATIC));
+ }
+
+ if (midi)
+ {
+ if (debugmode)
+ {
+ sprintf(tmp, "cfg p=0x%x\n", snd_Mport);
+ tprintf(tmp, 0);
+ }
+
+ if (MPU_Detect(&snd_Mport, &i))
+ {
+ sprintf(tmp, "The MPU-401 isn't reponding @ p=0x%x.\n",
+ snd_Mport);
+ tprintf(tmp, 0);
+ }
+ else
+ MPU_SetCard(snd_Mport);
+ }
+
+}
+
+// inits all sound stuff
+
+void I_StartupSound(void)
+{
+ char tmp[80];
+ int rc, i;
+
+ if (debugmode)
+ tprintf("I_StartupSound: Hope you hear a pop.\n", 1);
+
+ // initialize dmxCodes[]
+ dmxCodes[0] = 0;
+ dmxCodes[snd_PC] = AHW_PC_SPEAKER;
+ dmxCodes[snd_Adlib] = AHW_ADLIB;
+ dmxCodes[snd_SB] = AHW_SOUND_BLASTER;
+ dmxCodes[snd_PAS] = AHW_MEDIA_VISION;
+ dmxCodes[snd_GUS] = AHW_ULTRA_SOUND;
+ dmxCodes[snd_MPU] = AHW_MPU_401;
+ dmxCodes[snd_AWE] = AHW_AWE32;
+
+ // inits sound library timer stuff
+ I_StartupTimer();
+
+ // pick the sound cards i'm going to use
+ //
+ I_sndArbitrateCards();
+
+ if (debugmode)
+ {
+ sprintf(tmp, " Music device #%d & dmxCode=%d", snd_MusicDevice,
+ dmxCodes[snd_MusicDevice]);
+ tprintf(tmp, 0);
+ sprintf(tmp, " Sfx device #%d & dmxCode=%d\n", snd_SfxDevice,
+ dmxCodes[snd_SfxDevice]);
+ tprintf(tmp, 0);
+ }
+
+ // inits DMX sound library
+ tprintf(" calling DMX_Init", 0);
+ rc = DMX_Init(SND_TICRATE, SND_MAXSONGS, dmxCodes[snd_MusicDevice],
+ dmxCodes[snd_SfxDevice]);
+
+ if (debugmode)
+ {
+ sprintf(tmp, " DMX_Init() returned %d", rc);
+ tprintf(tmp, 0);
+ }
+
+}
+
+// shuts down all sound stuff
+
+void I_ShutdownSound(void)
+{
+ DMX_DeInit();
+ I_ShutdownTimer();
+}
+
+void I_SetChannels(int channels)
+{
+ WAV_PlayMode(channels, SND_SAMPLERATE);
+}
diff --git a/src/heretic/in_lude.c b/src/heretic/in_lude.c
new file mode 100644
index 00000000..e389371f
--- /dev/null
+++ b/src/heretic/in_lude.c
@@ -0,0 +1,1075 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+/*
+========================
+=
+= IN_lude.c
+=
+========================
+*/
+
+#include "doomdef.h"
+#include "deh_str.h"
+#include "p_local.h"
+#include "s_sound.h"
+#include "i_system.h"
+#include "i_video.h"
+#include "v_video.h"
+
+typedef enum
+{
+ SINGLE,
+ COOPERATIVE,
+ DEATHMATCH
+} gametype_t;
+
+// Public functions
+
+
+boolean intermission;
+
+// Private functions
+
+void IN_WaitStop(void);
+void IN_Stop(void);
+void IN_LoadPics(void);
+void IN_UnloadPics(void);
+void IN_CheckForSkip(void);
+void IN_InitStats(void);
+void IN_InitDeathmatchStats(void);
+void IN_InitNetgameStats(void);
+void IN_DrawOldLevel(void);
+void IN_DrawYAH(void);
+void IN_DrawStatBack(void);
+void IN_DrawSingleStats(void);
+void IN_DrawCoopStats(void);
+void IN_DrawDMStats(void);
+void IN_DrawNumber(int val, int x, int y, int digits);
+void IN_DrawTime(int x, int y, int h, int m, int s);
+void IN_DrTextB(char *text, int x, int y);
+
+static boolean skipintermission;
+static int interstate = 0;
+static int intertime = -1;
+static int oldintertime = 0;
+static gametype_t gametype;
+
+static int cnt;
+
+static int hours;
+static int minutes;
+static int seconds;
+
+static int slaughterboy; // in DM, the player with the most kills
+
+static int killPercent[MAXPLAYERS];
+static int bonusPercent[MAXPLAYERS];
+static int secretPercent[MAXPLAYERS];
+
+static patch_t *patchINTERPIC;
+static patch_t *patchBEENTHERE;
+static patch_t *patchGOINGTHERE;
+static patch_t *FontBNumbers[10];
+static patch_t *FontBNegative;
+static patch_t *FontBSlash;
+static patch_t *FontBPercent;
+
+static int FontBLump;
+static int FontBLumpBase;
+static int patchFaceOkayBase;
+static int patchFaceDeadBase;
+
+static signed int totalFrags[MAXPLAYERS];
+static fixed_t dSlideX[MAXPLAYERS];
+static fixed_t dSlideY[MAXPLAYERS];
+
+static char *KillersText[] = { "K", "I", "L", "L", "E", "R", "S" };
+
+extern char *LevelNames[];
+
+typedef struct
+{
+ int x;
+ int y;
+} yahpt_t;
+
+static yahpt_t YAHspot[3][9] = {
+ {
+ {172, 78},
+ {86, 90},
+ {73, 66},
+ {159, 95},
+ {148, 126},
+ {132, 54},
+ {131, 74},
+ {208, 138},
+ {52, 101}
+ },
+ {
+ {218, 57},
+ {137, 81},
+ {155, 124},
+ {171, 68},
+ {250, 86},
+ {136, 98},
+ {203, 90},
+ {220, 140},
+ {279, 106}
+ },
+ {
+ {86, 99},
+ {124, 103},
+ {154, 79},
+ {202, 83},
+ {178, 59},
+ {142, 58},
+ {219, 66},
+ {247, 57},
+ {107, 80}
+ }
+};
+
+//========================================================================
+//
+// IN_Start
+//
+//========================================================================
+
+extern void AM_Stop(void);
+
+void IN_Start(void)
+{
+ I_SetPalette(W_CacheLumpName(DEH_String("PLAYPAL"), PU_CACHE));
+ IN_LoadPics();
+ IN_InitStats();
+ intermission = true;
+ interstate = -1;
+ skipintermission = false;
+ intertime = 0;
+ oldintertime = 0;
+ AM_Stop();
+ S_StartSong(mus_intr, true);
+}
+
+//========================================================================
+//
+// IN_WaitStop
+//
+//========================================================================
+
+void IN_WaitStop(void)
+{
+ if (!--cnt)
+ {
+ IN_Stop();
+ G_WorldDone();
+ }
+}
+
+//========================================================================
+//
+// IN_Stop
+//
+//========================================================================
+
+void IN_Stop(void)
+{
+ intermission = false;
+ IN_UnloadPics();
+ SB_state = -1;
+ BorderNeedRefresh = true;
+}
+
+//========================================================================
+//
+// IN_InitStats
+//
+// Initializes the stats for single player mode
+//========================================================================
+
+void IN_InitStats(void)
+{
+ int i;
+ int j;
+ signed int slaughterfrags;
+ int posnum;
+ int slaughtercount;
+ int playercount;
+ int count;
+
+ if (!netgame)
+ {
+ gametype = SINGLE;
+ count = leveltime / 35;
+ hours = count / 3600;
+ count -= hours * 3600;
+ minutes = count / 60;
+ count -= minutes * 60;
+ seconds = count;
+ }
+ else if (netgame && !deathmatch)
+ {
+ gametype = COOPERATIVE;
+ memset(killPercent, 0, MAXPLAYERS * sizeof(int));
+ memset(bonusPercent, 0, MAXPLAYERS * sizeof(int));
+ memset(secretPercent, 0, MAXPLAYERS * sizeof(int));
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ {
+ if (totalkills)
+ {
+ killPercent[i] = players[i].killcount * 100 / totalkills;
+ }
+ if (totalitems)
+ {
+ bonusPercent[i] = players[i].itemcount * 100 / totalitems;
+ }
+ if (totalsecret)
+ {
+ secretPercent[i] =
+ players[i].secretcount * 100 / totalsecret;
+ }
+ }
+ }
+ }
+ else
+ {
+ gametype = DEATHMATCH;
+ slaughterboy = 0;
+ slaughterfrags = -9999;
+ posnum = 0;
+ playercount = 0;
+ slaughtercount = 0;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ totalFrags[i] = 0;
+ if (playeringame[i])
+ {
+ playercount++;
+ for (j = 0; j < MAXPLAYERS; j++)
+ {
+ if (playeringame[j])
+ {
+ totalFrags[i] += players[i].frags[j];
+ }
+ }
+ dSlideX[i] = (43 * posnum * FRACUNIT) / 20;
+ dSlideY[i] = (36 * posnum * FRACUNIT) / 20;
+ posnum++;
+ }
+ if (totalFrags[i] > slaughterfrags)
+ {
+ slaughterboy = 1 << i;
+ slaughterfrags = totalFrags[i];
+ slaughtercount = 1;
+ }
+ else if (totalFrags[i] == slaughterfrags)
+ {
+ slaughterboy |= 1 << i;
+ slaughtercount++;
+ }
+ }
+ if (playercount == slaughtercount)
+ { // don't do the slaughter stuff if everyone is equal
+ slaughterboy = 0;
+ }
+ }
+}
+
+static void IN_LoadUnloadPics(void (*callback)(char *lumpname,
+ int lumpnum,
+ patch_t **ptr))
+{
+ int i;
+
+ switch (gameepisode)
+ {
+ case 1:
+ callback(DEH_String("MAPE1"), 0, &patchINTERPIC);
+ break;
+ case 2:
+ callback(DEH_String("MAPE2"), 0, &patchINTERPIC);
+ break;
+ case 3:
+ callback(DEH_String("MAPE3"), 0, &patchINTERPIC);
+ break;
+ default:
+ break;
+ }
+
+ callback(DEH_String("IN_X"), 0, &patchBEENTHERE);
+ callback(DEH_String("IN_YAH"), 0, &patchGOINGTHERE);
+ callback(DEH_String("FONTB13"), 0, &FontBNegative);
+
+ callback(DEH_String("FONTB15"), 0, &FontBSlash);
+ callback(DEH_String("FONTB05"), 0, &FontBPercent);
+
+ FontBLumpBase = W_GetNumForName(DEH_String("FONTB16"));
+
+ for (i = 0; i < 10; i++)
+ {
+ callback(NULL, FontBLumpBase + i, &FontBNumbers[i]);
+ }
+}
+
+//========================================================================
+//
+// IN_LoadPics
+//
+//========================================================================
+
+static void LoadLumpCallback(char *lumpname, int lumpnum, patch_t **ptr)
+{
+ if (lumpname != NULL)
+ {
+ lumpnum = W_GetNumForName(lumpname);
+ }
+
+ // Cache the lump
+
+ *ptr = W_CacheLumpNum(lumpnum, PU_STATIC);
+}
+
+void IN_LoadPics(void)
+{
+ FontBLump = W_GetNumForName(DEH_String("FONTB_S")) + 1;
+ patchFaceOkayBase = W_GetNumForName(DEH_String("FACEA0"));
+ patchFaceDeadBase = W_GetNumForName(DEH_String("FACEB0"));
+
+ IN_LoadUnloadPics(LoadLumpCallback);
+}
+
+//========================================================================
+//
+// IN_UnloadPics
+//
+//========================================================================
+
+static void UnloadLumpCallback(char *lumpname, int lumpnum, patch_t **ptr)
+{
+ if (lumpname != NULL)
+ {
+ W_ReleaseLumpName(lumpname);
+ }
+ else
+ {
+ W_ReleaseLumpNum(lumpnum);
+ }
+}
+
+void IN_UnloadPics(void)
+{
+ IN_LoadUnloadPics(UnloadLumpCallback);
+}
+
+//========================================================================
+//
+// IN_Ticker
+//
+//========================================================================
+
+void IN_Ticker(void)
+{
+ if (!intermission)
+ {
+ return;
+ }
+ if (interstate == 3)
+ {
+ IN_WaitStop();
+ return;
+ }
+ IN_CheckForSkip();
+ intertime++;
+ if (oldintertime < intertime)
+ {
+ interstate++;
+ if (gameepisode > 3 && interstate >= 1)
+ { // Extended Wad levels: skip directly to the next level
+ interstate = 3;
+ }
+ switch (interstate)
+ {
+ case 0:
+ oldintertime = intertime + 300;
+ if (gameepisode > 3)
+ {
+ oldintertime = intertime + 1200;
+ }
+ break;
+ case 1:
+ oldintertime = intertime + 200;
+ break;
+ case 2:
+ oldintertime = INT_MAX;
+ break;
+ case 3:
+ cnt = 10;
+ break;
+ default:
+ break;
+ }
+ }
+ if (skipintermission)
+ {
+ if (interstate == 0 && intertime < 150)
+ {
+ intertime = 150;
+ skipintermission = false;
+ return;
+ }
+ else if (interstate < 2 && gameepisode < 4)
+ {
+ interstate = 2;
+ skipintermission = false;
+ S_StartSound(NULL, sfx_dorcls);
+ return;
+ }
+ interstate = 3;
+ cnt = 10;
+ skipintermission = false;
+ S_StartSound(NULL, sfx_dorcls);
+ }
+}
+
+//========================================================================
+//
+// IN_CheckForSkip
+//
+// Check to see if any player hit a key
+//========================================================================
+
+void IN_CheckForSkip(void)
+{
+ int i;
+ player_t *player;
+
+ for (i = 0, player = players; i < MAXPLAYERS; i++, player++)
+ {
+ if (playeringame[i])
+ {
+ if (player->cmd.buttons & BT_ATTACK)
+ {
+ if (!player->attackdown)
+ {
+ skipintermission = 1;
+ }
+ player->attackdown = true;
+ }
+ else
+ {
+ player->attackdown = false;
+ }
+ if (player->cmd.buttons & BT_USE)
+ {
+ if (!player->usedown)
+ {
+ skipintermission = 1;
+ }
+ player->usedown = true;
+ }
+ else
+ {
+ player->usedown = false;
+ }
+ }
+ }
+}
+
+//========================================================================
+//
+// IN_Drawer
+//
+//========================================================================
+
+void IN_Drawer(void)
+{
+ static int oldinterstate;
+
+ if (!intermission)
+ {
+ return;
+ }
+ if (interstate == 3)
+ {
+ return;
+ }
+ UpdateState |= I_FULLSCRN;
+ if (oldinterstate != 2 && interstate == 2)
+ {
+ S_StartSound(NULL, sfx_pstop);
+ }
+ oldinterstate = interstate;
+ switch (interstate)
+ {
+ case 0: // draw stats
+ IN_DrawStatBack();
+ switch (gametype)
+ {
+ case SINGLE:
+ IN_DrawSingleStats();
+ break;
+ case COOPERATIVE:
+ IN_DrawCoopStats();
+ break;
+ case DEATHMATCH:
+ IN_DrawDMStats();
+ break;
+ }
+ break;
+ case 1: // leaving old level
+ if (gameepisode < 4)
+ {
+ V_DrawPatch(0, 0, patchINTERPIC);
+ IN_DrawOldLevel();
+ }
+ break;
+ case 2: // going to the next level
+ if (gameepisode < 4)
+ {
+ V_DrawPatch(0, 0, patchINTERPIC);
+ IN_DrawYAH();
+ }
+ break;
+ case 3: // waiting before going to the next level
+ if (gameepisode < 4)
+ {
+ V_DrawPatch(0, 0, patchINTERPIC);
+ }
+ break;
+ default:
+ I_Error("IN_lude: Intermission state out of range.\n");
+ break;
+ }
+}
+
+//========================================================================
+//
+// IN_DrawStatBack
+//
+//========================================================================
+
+void IN_DrawStatBack(void)
+{
+ int x;
+ int y;
+
+ byte *src;
+ byte *dest;
+
+ src = W_CacheLumpName(DEH_String("FLOOR16"), PU_CACHE);
+ dest = I_VideoBuffer;
+
+ for (y = 0; y < SCREENHEIGHT; y++)
+ {
+ for (x = 0; x < SCREENWIDTH / 64; x++)
+ {
+ memcpy(dest, src + ((y & 63) << 6), 64);
+ dest += 64;
+ }
+ if (SCREENWIDTH & 63)
+ {
+ memcpy(dest, src + ((y & 63) << 6), SCREENWIDTH & 63);
+ dest += (SCREENWIDTH & 63);
+ }
+ }
+}
+
+//========================================================================
+//
+// IN_DrawOldLevel
+//
+//========================================================================
+
+void IN_DrawOldLevel(void)
+{
+ int i;
+ int x;
+
+ x = 160 - MN_TextBWidth(LevelNames[(gameepisode - 1) * 9 + prevmap - 1] +
+ 7) / 2;
+ IN_DrTextB(LevelNames[(gameepisode - 1) * 9 + prevmap - 1] + 7, x, 3);
+ x = 160 - MN_TextAWidth(DEH_String("FINISHED")) / 2;
+ MN_DrTextA(DEH_String("FINISHED"), x, 25);
+
+ if (prevmap == 9)
+ {
+ for (i = 0; i < gamemap - 1; i++)
+ {
+ V_DrawPatch(YAHspot[gameepisode - 1][i].x,
+ YAHspot[gameepisode - 1][i].y, patchBEENTHERE);
+ }
+ if (!(intertime & 16))
+ {
+ V_DrawPatch(YAHspot[gameepisode - 1][8].x,
+ YAHspot[gameepisode - 1][8].y, patchBEENTHERE);
+ }
+ }
+ else
+ {
+ for (i = 0; i < prevmap - 1; i++)
+ {
+ V_DrawPatch(YAHspot[gameepisode - 1][i].x,
+ YAHspot[gameepisode - 1][i].y, patchBEENTHERE);
+ }
+ if (players[consoleplayer].didsecret)
+ {
+ V_DrawPatch(YAHspot[gameepisode - 1][8].x,
+ YAHspot[gameepisode - 1][8].y, patchBEENTHERE);
+ }
+ if (!(intertime & 16))
+ {
+ V_DrawPatch(YAHspot[gameepisode - 1][prevmap - 1].x,
+ YAHspot[gameepisode - 1][prevmap - 1].y,
+ patchBEENTHERE);
+ }
+ }
+}
+
+//========================================================================
+//
+// IN_DrawYAH
+//
+//========================================================================
+
+void IN_DrawYAH(void)
+{
+ int i;
+ int x;
+
+ x = 160 - MN_TextAWidth(DEH_String("NOW ENTERING:")) / 2;
+ MN_DrTextA(DEH_String("NOW ENTERING:"), x, 10);
+ x = 160 - MN_TextBWidth(LevelNames[(gameepisode - 1) * 9 + gamemap - 1] +
+ 7) / 2;
+ IN_DrTextB(LevelNames[(gameepisode - 1) * 9 + gamemap - 1] + 7, x, 20);
+
+ if (prevmap == 9)
+ {
+ prevmap = gamemap - 1;
+ }
+ for (i = 0; i < prevmap; i++)
+ {
+ V_DrawPatch(YAHspot[gameepisode - 1][i].x,
+ YAHspot[gameepisode - 1][i].y, patchBEENTHERE);
+ }
+ if (players[consoleplayer].didsecret)
+ {
+ V_DrawPatch(YAHspot[gameepisode - 1][8].x,
+ YAHspot[gameepisode - 1][8].y, patchBEENTHERE);
+ }
+ if (!(intertime & 16) || interstate == 3)
+ { // draw the destination 'X'
+ V_DrawPatch(YAHspot[gameepisode - 1][gamemap - 1].x,
+ YAHspot[gameepisode - 1][gamemap - 1].y, patchGOINGTHERE);
+ }
+}
+
+//========================================================================
+//
+// IN_DrawSingleStats
+//
+//========================================================================
+
+void IN_DrawSingleStats(void)
+{
+ int x;
+ static int sounds;
+
+ IN_DrTextB(DEH_String("KILLS"), 50, 65);
+ IN_DrTextB(DEH_String("ITEMS"), 50, 90);
+ IN_DrTextB(DEH_String("SECRETS"), 50, 115);
+
+ x = 160 - MN_TextBWidth(LevelNames[(gameepisode - 1) * 9 + prevmap - 1] +
+ 7) / 2;
+ IN_DrTextB(LevelNames[(gameepisode - 1) * 9 + prevmap - 1] + 7, x, 3);
+ x = 160 - MN_TextAWidth(DEH_String("FINISHED")) / 2;
+ MN_DrTextA(DEH_String("FINISHED"), x, 25);
+
+ if (intertime < 30)
+ {
+ sounds = 0;
+ return;
+ }
+ if (sounds < 1 && intertime >= 30)
+ {
+ S_StartSound(NULL, sfx_dorcls);
+ sounds++;
+ }
+ IN_DrawNumber(players[consoleplayer].killcount, 200, 65, 3);
+ V_DrawShadowedPatch(237, 65, FontBSlash);
+ IN_DrawNumber(totalkills, 248, 65, 3);
+ if (intertime < 60)
+ {
+ return;
+ }
+ if (sounds < 2 && intertime >= 60)
+ {
+ S_StartSound(NULL, sfx_dorcls);
+ sounds++;
+ }
+ IN_DrawNumber(players[consoleplayer].itemcount, 200, 90, 3);
+ V_DrawShadowedPatch(237, 90, FontBSlash);
+ IN_DrawNumber(totalitems, 248, 90, 3);
+ if (intertime < 90)
+ {
+ return;
+ }
+ if (sounds < 3 && intertime >= 90)
+ {
+ S_StartSound(NULL, sfx_dorcls);
+ sounds++;
+ }
+ IN_DrawNumber(players[consoleplayer].secretcount, 200, 115, 3);
+ V_DrawShadowedPatch(237, 115, FontBSlash);
+ IN_DrawNumber(totalsecret, 248, 115, 3);
+ if (intertime < 150)
+ {
+ return;
+ }
+ if (sounds < 4 && intertime >= 150)
+ {
+ S_StartSound(NULL, sfx_dorcls);
+ sounds++;
+ }
+
+ if (gamemode != retail || gameepisode <= 3)
+ {
+ IN_DrTextB(DEH_String("TIME"), 85, 160);
+ IN_DrawTime(155, 160, hours, minutes, seconds);
+ }
+ else
+ {
+ x = 160 - MN_TextAWidth(DEH_String("NOW ENTERING:")) / 2;
+ MN_DrTextA(DEH_String("NOW ENTERING:"), x, 160);
+ x = 160 -
+ MN_TextBWidth(LevelNames[(gameepisode - 1) * 9 + gamemap - 1] +
+ 7) / 2;
+ IN_DrTextB(LevelNames[(gameepisode - 1) * 9 + gamemap - 1] + 7, x,
+ 170);
+ skipintermission = false;
+ }
+}
+
+//========================================================================
+//
+// IN_DrawCoopStats
+//
+//========================================================================
+
+void IN_DrawCoopStats(void)
+{
+ int i;
+ int x;
+ int ypos;
+
+ static int sounds;
+
+ IN_DrTextB(DEH_String("KILLS"), 95, 35);
+ IN_DrTextB(DEH_String("BONUS"), 155, 35);
+ IN_DrTextB(DEH_String("SECRET"), 232, 35);
+ x = 160 - MN_TextBWidth(LevelNames[(gameepisode - 1) * 9 + prevmap - 1] +
+ 7) / 2;
+ IN_DrTextB(LevelNames[(gameepisode - 1) * 9 + prevmap - 1] + 7, x, 3);
+ x = 160 - MN_TextAWidth(DEH_String("FINISHED")) / 2;
+ MN_DrTextA(DEH_String("FINISHED"), x, 25);
+
+ ypos = 50;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ {
+ V_DrawShadowedPatch(25, ypos,
+ W_CacheLumpNum(patchFaceOkayBase + i,
+ PU_CACHE));
+ if (intertime < 40)
+ {
+ sounds = 0;
+ ypos += 37;
+ continue;
+ }
+ else if (intertime >= 40 && sounds < 1)
+ {
+ S_StartSound(NULL, sfx_dorcls);
+ sounds++;
+ }
+ IN_DrawNumber(killPercent[i], 85, ypos + 10, 3);
+ V_DrawShadowedPatch(121, ypos + 10, FontBPercent);
+ IN_DrawNumber(bonusPercent[i], 160, ypos + 10, 3);
+ V_DrawShadowedPatch(196, ypos + 10, FontBPercent);
+ IN_DrawNumber(secretPercent[i], 237, ypos + 10, 3);
+ V_DrawShadowedPatch(273, ypos + 10, FontBPercent);
+ ypos += 37;
+ }
+ }
+}
+
+//========================================================================
+//
+// IN_DrawDMStats
+//
+//========================================================================
+
+void IN_DrawDMStats(void)
+{
+ int i;
+ int j;
+ int ypos;
+ int xpos;
+ int kpos;
+
+ static int sounds;
+
+ xpos = 90;
+ ypos = 55;
+
+ IN_DrTextB(DEH_String("TOTAL"), 265, 30);
+ MN_DrTextA(DEH_String("VICTIMS"), 140, 8);
+ for (i = 0; i < 7; i++)
+ {
+ MN_DrTextA(DEH_String(KillersText[i]), 10, 80 + 9 * i);
+ }
+ if (intertime < 20)
+ {
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ {
+ V_DrawShadowedPatch(40,
+ ((ypos << FRACBITS) +
+ dSlideY[i] * intertime) >> FRACBITS,
+ W_CacheLumpNum(patchFaceOkayBase + i,
+ PU_CACHE));
+ V_DrawShadowedPatch(((xpos << FRACBITS) +
+ dSlideX[i] * intertime) >> FRACBITS, 18,
+ W_CacheLumpNum(patchFaceDeadBase + i,
+ PU_CACHE));
+ }
+ }
+ sounds = 0;
+ return;
+ }
+ if (intertime >= 20 && sounds < 1)
+ {
+ S_StartSound(NULL, sfx_dorcls);
+ sounds++;
+ }
+ if (intertime >= 100 && slaughterboy && sounds < 2)
+ {
+ S_StartSound(NULL, sfx_wpnup);
+ sounds++;
+ }
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ {
+ if (intertime < 100 || i == consoleplayer)
+ {
+ V_DrawShadowedPatch(40, ypos,
+ W_CacheLumpNum(patchFaceOkayBase + i,
+ PU_CACHE));
+ V_DrawShadowedPatch(xpos, 18,
+ W_CacheLumpNum(patchFaceDeadBase + i,
+ PU_CACHE));
+ }
+ else
+ {
+ V_DrawTLPatch(40, ypos,
+ W_CacheLumpNum(patchFaceOkayBase + i,
+ PU_CACHE));
+ V_DrawTLPatch(xpos, 18,
+ W_CacheLumpNum(patchFaceDeadBase + i,
+ PU_CACHE));
+ }
+ kpos = 86;
+ for (j = 0; j < MAXPLAYERS; j++)
+ {
+ if (playeringame[j])
+ {
+ IN_DrawNumber(players[i].frags[j], kpos, ypos + 10, 3);
+ kpos += 43;
+ }
+ }
+ if (slaughterboy & (1 << i))
+ {
+ if (!(intertime & 16))
+ {
+ IN_DrawNumber(totalFrags[i], 263, ypos + 10, 3);
+ }
+ }
+ else
+ {
+ IN_DrawNumber(totalFrags[i], 263, ypos + 10, 3);
+ }
+ ypos += 36;
+ xpos += 43;
+ }
+ }
+}
+
+//========================================================================
+//
+// IN_DrawTime
+//
+//========================================================================
+
+void IN_DrawTime(int x, int y, int h, int m, int s)
+{
+ if (h)
+ {
+ IN_DrawNumber(h, x, y, 2);
+ IN_DrTextB(DEH_String(":"), x + 26, y);
+ }
+ x += 34;
+ if (m || h)
+ {
+ IN_DrawNumber(m, x, y, 2);
+ }
+ x += 34;
+ if (s)
+ {
+ IN_DrTextB(DEH_String(":"), x - 8, y);
+ IN_DrawNumber(s, x, y, 2);
+ }
+}
+
+//========================================================================
+//
+// IN_DrawNumber
+//
+//========================================================================
+
+void IN_DrawNumber(int val, int x, int y, int digits)
+{
+ patch_t *patch;
+ int xpos;
+ int oldval;
+ int realdigits;
+ boolean neg;
+
+ oldval = val;
+ xpos = x;
+ neg = false;
+ realdigits = 1;
+
+ if (val < 0)
+ { //...this should reflect negative frags
+ val = -val;
+ neg = true;
+ if (val > 99)
+ {
+ val = 99;
+ }
+ }
+ if (val > 9)
+ {
+ realdigits++;
+ if (digits < realdigits)
+ {
+ realdigits = digits;
+ val = 9;
+ }
+ }
+ if (val > 99)
+ {
+ realdigits++;
+ if (digits < realdigits)
+ {
+ realdigits = digits;
+ val = 99;
+ }
+ }
+ if (val > 999)
+ {
+ realdigits++;
+ if (digits < realdigits)
+ {
+ realdigits = digits;
+ val = 999;
+ }
+ }
+ if (digits == 4)
+ {
+ patch = FontBNumbers[val / 1000];
+ V_DrawShadowedPatch(xpos + 6 - patch->width / 2 - 12, y, patch);
+ }
+ if (digits > 2)
+ {
+ if (realdigits > 2)
+ {
+ patch = FontBNumbers[val / 100];
+ V_DrawShadowedPatch(xpos + 6 - patch->width / 2, y, patch);
+ }
+ xpos += 12;
+ }
+ val = val % 100;
+ if (digits > 1)
+ {
+ if (val > 9)
+ {
+ patch = FontBNumbers[val / 10];
+ V_DrawShadowedPatch(xpos + 6 - patch->width / 2, y, patch);
+ }
+ else if (digits == 2 || oldval > 99)
+ {
+ V_DrawShadowedPatch(xpos, y, FontBNumbers[0]);
+ }
+ xpos += 12;
+ }
+ val = val % 10;
+ patch = FontBNumbers[val];
+ V_DrawShadowedPatch(xpos + 6 - patch->width / 2, y, patch);
+ if (neg)
+ {
+ patch = FontBNegative;
+ V_DrawShadowedPatch(xpos + 6 - patch->width / 2 - 12 * (realdigits),
+ y, patch);
+ }
+}
+
+//========================================================================
+//
+// IN_DrTextB
+//
+//========================================================================
+
+void IN_DrTextB(char *text, int x, int y)
+{
+ char c;
+ patch_t *p;
+
+ while ((c = *text++) != 0)
+ {
+ if (c < 33)
+ {
+ x += 8;
+ }
+ else
+ {
+ p = W_CacheLumpNum(FontBLump + c - 33, PU_CACHE);
+ V_DrawShadowedPatch(x, y, p);
+ x += p->width - 1;
+ }
+ }
+}
diff --git a/src/heretic/info.c b/src/heretic/info.c
new file mode 100644
index 00000000..b6dd921f
--- /dev/null
+++ b/src/heretic/info.c
@@ -0,0 +1,5608 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+#include "doomdef.h"
+#include "p_action.h"
+
+char *sprnames[] = {
+ "IMPX","ACLO","PTN1","SHLD","SHD2","BAGH","SPMP","INVS","PTN2","SOAR",
+ "INVU","PWBK","EGGC","EGGM","FX01","SPHL","TRCH","FBMB","XPL1","ATLP",
+ "PPOD","AMG1","SPSH","LVAS","SLDG","SKH1","SKH2","SKH3","SKH4","CHDL",
+ "SRTC","SMPL","STGS","STGL","STCS","STCL","KFR1","BARL","BRPL","MOS1",
+ "MOS2","WTRH","HCOR","KGZ1","KGZB","KGZG","KGZY","VLCO","VFBL","VTFB",
+ "SFFI","TGLT","TELE","STFF","PUF3","PUF4","BEAK","WGNT","GAUN","PUF1",
+ "WBLS","BLSR","FX18","FX17","WMCE","MACE","FX02","WSKL","HROD","FX00",
+ "FX20","FX21","FX22","FX23","GWND","PUF2","WPHX","PHNX","FX04","FX08",
+ "FX09","WBOW","CRBW","FX03","BLOD","PLAY","FDTH","BSKL","CHKN","MUMM",
+ "FX15","BEAS","FRB1","SNKE","SNFX","HEAD","FX05","FX06","FX07","CLNK",
+ "WZRD","FX11","FX10","KNIG","SPAX","RAXE","SRCR","FX14","SOR2","SDTH",
+ "FX16","MNTR","FX12","FX13","AKYY","BKYY","CKYY","AMG2","AMM1","AMM2",
+ "AMC1","AMC2","AMS1","AMS2","AMP1","AMP2","AMB1","AMB2",
+ NULL
+};
+
+state_t states[NUMSTATES] = {
+ {SPR_IMPX, 0, -1, NULL, S_NULL, 0, 0}, // S_NULL
+ {SPR_ACLO, 4, 1050, A_FreeTargMobj, S_NULL, 0, 0}, // S_FREETARGMOBJ
+ {SPR_PTN1, 0, 3, NULL, S_ITEM_PTN1_2, 0, 0}, // S_ITEM_PTN1_1
+ {SPR_PTN1, 1, 3, NULL, S_ITEM_PTN1_3, 0, 0}, // S_ITEM_PTN1_2
+ {SPR_PTN1, 2, 3, NULL, S_ITEM_PTN1_1, 0, 0}, // S_ITEM_PTN1_3
+ {SPR_SHLD, 0, -1, NULL, S_NULL, 0, 0}, // S_ITEM_SHLD1
+ {SPR_SHD2, 0, -1, NULL, S_NULL, 0, 0}, // S_ITEM_SHD2_1
+ {SPR_BAGH, 0, -1, NULL, S_NULL, 0, 0}, // S_ITEM_BAGH1
+ {SPR_SPMP, 0, -1, NULL, S_NULL, 0, 0}, // S_ITEM_SPMP1
+ {SPR_ACLO, 4, 1400, NULL, S_HIDESPECIAL2, 0, 0}, // S_HIDESPECIAL1
+ {SPR_ACLO, 0, 4, A_RestoreSpecialThing1, S_HIDESPECIAL3, 0, 0}, // S_HIDESPECIAL2
+ {SPR_ACLO, 1, 4, NULL, S_HIDESPECIAL4, 0, 0}, // S_HIDESPECIAL3
+ {SPR_ACLO, 0, 4, NULL, S_HIDESPECIAL5, 0, 0}, // S_HIDESPECIAL4
+ {SPR_ACLO, 1, 4, NULL, S_HIDESPECIAL6, 0, 0}, // S_HIDESPECIAL5
+ {SPR_ACLO, 2, 4, NULL, S_HIDESPECIAL7, 0, 0}, // S_HIDESPECIAL6
+ {SPR_ACLO, 1, 4, NULL, S_HIDESPECIAL8, 0, 0}, // S_HIDESPECIAL7
+ {SPR_ACLO, 2, 4, NULL, S_HIDESPECIAL9, 0, 0}, // S_HIDESPECIAL8
+ {SPR_ACLO, 3, 4, NULL, S_HIDESPECIAL10, 0, 0}, // S_HIDESPECIAL9
+ {SPR_ACLO, 2, 4, NULL, S_HIDESPECIAL11, 0, 0}, // S_HIDESPECIAL10
+ {SPR_ACLO, 3, 4, A_RestoreSpecialThing2, S_NULL, 0, 0}, // S_HIDESPECIAL11
+ {SPR_ACLO, 3, 3, NULL, S_DORMANTARTI2, 0, 0}, // S_DORMANTARTI1
+ {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI3, 0, 0}, // S_DORMANTARTI2
+ {SPR_ACLO, 3, 3, NULL, S_DORMANTARTI4, 0, 0}, // S_DORMANTARTI3
+ {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI5, 0, 0}, // S_DORMANTARTI4
+ {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI6, 0, 0}, // S_DORMANTARTI5
+ {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI7, 0, 0}, // S_DORMANTARTI6
+ {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI8, 0, 0}, // S_DORMANTARTI7
+ {SPR_ACLO, 0, 3, NULL, S_DORMANTARTI9, 0, 0}, // S_DORMANTARTI8
+ {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI10, 0, 0}, // S_DORMANTARTI9
+ {SPR_ACLO, 0, 3, NULL, S_DORMANTARTI11, 0, 0}, // S_DORMANTARTI10
+ {SPR_ACLO, 0, 1400, A_HideThing, S_DORMANTARTI12, 0, 0}, // S_DORMANTARTI11
+ {SPR_ACLO, 0, 3, A_UnHideThing, S_DORMANTARTI13, 0, 0}, // S_DORMANTARTI12
+ {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI14, 0, 0}, // S_DORMANTARTI13
+ {SPR_ACLO, 0, 3, NULL, S_DORMANTARTI15, 0, 0}, // S_DORMANTARTI14
+ {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI16, 0, 0}, // S_DORMANTARTI15
+ {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI17, 0, 0}, // S_DORMANTARTI16
+ {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI18, 0, 0}, // S_DORMANTARTI17
+ {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI19, 0, 0}, // S_DORMANTARTI18
+ {SPR_ACLO, 3, 3, NULL, S_DORMANTARTI20, 0, 0}, // S_DORMANTARTI19
+ {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI21, 0, 0}, // S_DORMANTARTI20
+ {SPR_ACLO, 3, 3, A_RestoreArtifact, S_NULL, 0, 0}, // S_DORMANTARTI21
+ {SPR_ACLO, 3, 3, NULL, S_DEADARTI2, 0, 0}, // S_DEADARTI1
+ {SPR_ACLO, 2, 3, NULL, S_DEADARTI3, 0, 0}, // S_DEADARTI2
+ {SPR_ACLO, 3, 3, NULL, S_DEADARTI4, 0, 0}, // S_DEADARTI3
+ {SPR_ACLO, 2, 3, NULL, S_DEADARTI5, 0, 0}, // S_DEADARTI4
+ {SPR_ACLO, 1, 3, NULL, S_DEADARTI6, 0, 0}, // S_DEADARTI5
+ {SPR_ACLO, 2, 3, NULL, S_DEADARTI7, 0, 0}, // S_DEADARTI6
+ {SPR_ACLO, 1, 3, NULL, S_DEADARTI8, 0, 0}, // S_DEADARTI7
+ {SPR_ACLO, 0, 3, NULL, S_DEADARTI9, 0, 0}, // S_DEADARTI8
+ {SPR_ACLO, 1, 3, NULL, S_DEADARTI10, 0, 0}, // S_DEADARTI9
+ {SPR_ACLO, 0, 3, NULL, S_NULL, 0, 0}, // S_DEADARTI10
+ {SPR_INVS, 32768, 350, NULL, S_ARTI_INVS1, 0, 0}, // S_ARTI_INVS1
+ {SPR_PTN2, 0, 4, NULL, S_ARTI_PTN2_2, 0, 0}, // S_ARTI_PTN2_1
+ {SPR_PTN2, 1, 4, NULL, S_ARTI_PTN2_3, 0, 0}, // S_ARTI_PTN2_2
+ {SPR_PTN2, 2, 4, NULL, S_ARTI_PTN2_1, 0, 0}, // S_ARTI_PTN2_3
+ {SPR_SOAR, 0, 5, NULL, S_ARTI_SOAR2, 0, 0}, // S_ARTI_SOAR1
+ {SPR_SOAR, 1, 5, NULL, S_ARTI_SOAR3, 0, 0}, // S_ARTI_SOAR2
+ {SPR_SOAR, 2, 5, NULL, S_ARTI_SOAR4, 0, 0}, // S_ARTI_SOAR3
+ {SPR_SOAR, 1, 5, NULL, S_ARTI_SOAR1, 0, 0}, // S_ARTI_SOAR4
+ {SPR_INVU, 0, 3, NULL, S_ARTI_INVU2, 0, 0}, // S_ARTI_INVU1
+ {SPR_INVU, 1, 3, NULL, S_ARTI_INVU3, 0, 0}, // S_ARTI_INVU2
+ {SPR_INVU, 2, 3, NULL, S_ARTI_INVU4, 0, 0}, // S_ARTI_INVU3
+ {SPR_INVU, 3, 3, NULL, S_ARTI_INVU1, 0, 0}, // S_ARTI_INVU4
+ {SPR_PWBK, 0, 350, NULL, S_ARTI_PWBK1, 0, 0}, // S_ARTI_PWBK1
+ {SPR_EGGC, 0, 6, NULL, S_ARTI_EGGC2, 0, 0}, // S_ARTI_EGGC1
+ {SPR_EGGC, 1, 6, NULL, S_ARTI_EGGC3, 0, 0}, // S_ARTI_EGGC2
+ {SPR_EGGC, 2, 6, NULL, S_ARTI_EGGC4, 0, 0}, // S_ARTI_EGGC3
+ {SPR_EGGC, 1, 6, NULL, S_ARTI_EGGC1, 0, 0}, // S_ARTI_EGGC4
+ {SPR_EGGM, 0, 4, NULL, S_EGGFX2, 0, 0}, // S_EGGFX1
+ {SPR_EGGM, 1, 4, NULL, S_EGGFX3, 0, 0}, // S_EGGFX2
+ {SPR_EGGM, 2, 4, NULL, S_EGGFX4, 0, 0}, // S_EGGFX3
+ {SPR_EGGM, 3, 4, NULL, S_EGGFX5, 0, 0}, // S_EGGFX4
+ {SPR_EGGM, 4, 4, NULL, S_EGGFX1, 0, 0}, // S_EGGFX5
+ {SPR_FX01, 32772, 3, NULL, S_EGGFXI1_2, 0, 0}, // S_EGGFXI1_1
+ {SPR_FX01, 32773, 3, NULL, S_EGGFXI1_3, 0, 0}, // S_EGGFXI1_2
+ {SPR_FX01, 32774, 3, NULL, S_EGGFXI1_4, 0, 0}, // S_EGGFXI1_3
+ {SPR_FX01, 32775, 3, NULL, S_NULL, 0, 0}, // S_EGGFXI1_4
+ {SPR_SPHL, 0, 350, NULL, S_ARTI_SPHL1, 0, 0}, // S_ARTI_SPHL1
+ {SPR_TRCH, 32768, 3, NULL, S_ARTI_TRCH2, 0, 0}, // S_ARTI_TRCH1
+ {SPR_TRCH, 32769, 3, NULL, S_ARTI_TRCH3, 0, 0}, // S_ARTI_TRCH2
+ {SPR_TRCH, 32770, 3, NULL, S_ARTI_TRCH1, 0, 0}, // S_ARTI_TRCH3
+ {SPR_FBMB, 4, 350, NULL, S_ARTI_FBMB1, 0, 0}, // S_ARTI_FBMB1
+ {SPR_FBMB, 0, 10, NULL, S_FIREBOMB2, 0, 0}, // S_FIREBOMB1
+ {SPR_FBMB, 1, 10, NULL, S_FIREBOMB3, 0, 0}, // S_FIREBOMB2
+ {SPR_FBMB, 2, 10, NULL, S_FIREBOMB4, 0, 0}, // S_FIREBOMB3
+ {SPR_FBMB, 3, 10, NULL, S_FIREBOMB5, 0, 0}, // S_FIREBOMB4
+ {SPR_FBMB, 4, 6, A_Scream, S_FIREBOMB6, 0, 0}, // S_FIREBOMB5
+ {SPR_XPL1, 32768, 4, A_Explode, S_FIREBOMB7, 0, 0}, // S_FIREBOMB6
+ {SPR_XPL1, 32769, 4, NULL, S_FIREBOMB8, 0, 0}, // S_FIREBOMB7
+ {SPR_XPL1, 32770, 4, NULL, S_FIREBOMB9, 0, 0}, // S_FIREBOMB8
+ {SPR_XPL1, 32771, 4, NULL, S_FIREBOMB10, 0, 0}, // S_FIREBOMB9
+ {SPR_XPL1, 32772, 4, NULL, S_FIREBOMB11, 0, 0}, // S_FIREBOMB10
+ {SPR_XPL1, 32773, 4, NULL, S_NULL, 0, 0}, // S_FIREBOMB11
+ {SPR_ATLP, 0, 4, NULL, S_ARTI_ATLP2, 0, 0}, // S_ARTI_ATLP1
+ {SPR_ATLP, 1, 4, NULL, S_ARTI_ATLP3, 0, 0}, // S_ARTI_ATLP2
+ {SPR_ATLP, 2, 4, NULL, S_ARTI_ATLP4, 0, 0}, // S_ARTI_ATLP3
+ {SPR_ATLP, 1, 4, NULL, S_ARTI_ATLP1, 0, 0}, // S_ARTI_ATLP4
+ {SPR_PPOD, 0, 10, NULL, S_POD_WAIT1, 0, 0}, // S_POD_WAIT1
+ {SPR_PPOD, 1, 14, A_PodPain, S_POD_WAIT1, 0, 0}, // S_POD_PAIN1
+ {SPR_PPOD, 32770, 5, A_RemovePod, S_POD_DIE2, 0, 0}, // S_POD_DIE1
+ {SPR_PPOD, 32771, 5, A_Scream, S_POD_DIE3, 0, 0}, // S_POD_DIE2
+ {SPR_PPOD, 32772, 5, A_Explode, S_POD_DIE4, 0, 0}, // S_POD_DIE3
+ {SPR_PPOD, 32773, 10, NULL, S_FREETARGMOBJ, 0, 0}, // S_POD_DIE4
+ {SPR_PPOD, 8, 3, NULL, S_POD_GROW2, 0, 0}, // S_POD_GROW1
+ {SPR_PPOD, 9, 3, NULL, S_POD_GROW3, 0, 0}, // S_POD_GROW2
+ {SPR_PPOD, 10, 3, NULL, S_POD_GROW4, 0, 0}, // S_POD_GROW3
+ {SPR_PPOD, 11, 3, NULL, S_POD_GROW5, 0, 0}, // S_POD_GROW4
+ {SPR_PPOD, 12, 3, NULL, S_POD_GROW6, 0, 0}, // S_POD_GROW5
+ {SPR_PPOD, 13, 3, NULL, S_POD_GROW7, 0, 0}, // S_POD_GROW6
+ {SPR_PPOD, 14, 3, NULL, S_POD_GROW8, 0, 0}, // S_POD_GROW7
+ {SPR_PPOD, 15, 3, NULL, S_POD_WAIT1, 0, 0}, // S_POD_GROW8
+ {SPR_PPOD, 6, 8, NULL, S_PODGOO2, 0, 0}, // S_PODGOO1
+ {SPR_PPOD, 7, 8, NULL, S_PODGOO1, 0, 0}, // S_PODGOO2
+ {SPR_PPOD, 6, 10, NULL, S_NULL, 0, 0}, // S_PODGOOX
+ {SPR_AMG1, 0, 35, A_MakePod, S_PODGENERATOR, 0, 0}, // S_PODGENERATOR
+ {SPR_SPSH, 0, 8, NULL, S_SPLASH2, 0, 0}, // S_SPLASH1
+ {SPR_SPSH, 1, 8, NULL, S_SPLASH3, 0, 0}, // S_SPLASH2
+ {SPR_SPSH, 2, 8, NULL, S_SPLASH4, 0, 0}, // S_SPLASH3
+ {SPR_SPSH, 3, 16, NULL, S_NULL, 0, 0}, // S_SPLASH4
+ {SPR_SPSH, 3, 10, NULL, S_NULL, 0, 0}, // S_SPLASHX
+ {SPR_SPSH, 4, 5, NULL, S_SPLASHBASE2, 0, 0}, // S_SPLASHBASE1
+ {SPR_SPSH, 5, 5, NULL, S_SPLASHBASE3, 0, 0}, // S_SPLASHBASE2
+ {SPR_SPSH, 6, 5, NULL, S_SPLASHBASE4, 0, 0}, // S_SPLASHBASE3
+ {SPR_SPSH, 7, 5, NULL, S_SPLASHBASE5, 0, 0}, // S_SPLASHBASE4
+ {SPR_SPSH, 8, 5, NULL, S_SPLASHBASE6, 0, 0}, // S_SPLASHBASE5
+ {SPR_SPSH, 9, 5, NULL, S_SPLASHBASE7, 0, 0}, // S_SPLASHBASE6
+ {SPR_SPSH, 10, 5, NULL, S_NULL, 0, 0}, // S_SPLASHBASE7
+ {SPR_LVAS, 32768, 5, NULL, S_LAVASPLASH2, 0, 0}, // S_LAVASPLASH1
+ {SPR_LVAS, 32769, 5, NULL, S_LAVASPLASH3, 0, 0}, // S_LAVASPLASH2
+ {SPR_LVAS, 32770, 5, NULL, S_LAVASPLASH4, 0, 0}, // S_LAVASPLASH3
+ {SPR_LVAS, 32771, 5, NULL, S_LAVASPLASH5, 0, 0}, // S_LAVASPLASH4
+ {SPR_LVAS, 32772, 5, NULL, S_LAVASPLASH6, 0, 0}, // S_LAVASPLASH5
+ {SPR_LVAS, 32773, 5, NULL, S_NULL, 0, 0}, // S_LAVASPLASH6
+ {SPR_LVAS, 32774, 5, NULL, S_LAVASMOKE2, 0, 0}, // S_LAVASMOKE1
+ {SPR_LVAS, 32775, 5, NULL, S_LAVASMOKE3, 0, 0}, // S_LAVASMOKE2
+ {SPR_LVAS, 32776, 5, NULL, S_LAVASMOKE4, 0, 0}, // S_LAVASMOKE3
+ {SPR_LVAS, 32777, 5, NULL, S_LAVASMOKE5, 0, 0}, // S_LAVASMOKE4
+ {SPR_LVAS, 32778, 5, NULL, S_NULL, 0, 0}, // S_LAVASMOKE5
+ {SPR_SLDG, 0, 8, NULL, S_SLUDGECHUNK2, 0, 0}, // S_SLUDGECHUNK1
+ {SPR_SLDG, 1, 8, NULL, S_SLUDGECHUNK3, 0, 0}, // S_SLUDGECHUNK2
+ {SPR_SLDG, 2, 8, NULL, S_SLUDGECHUNK4, 0, 0}, // S_SLUDGECHUNK3
+ {SPR_SLDG, 3, 8, NULL, S_NULL, 0, 0}, // S_SLUDGECHUNK4
+ {SPR_SLDG, 3, 6, NULL, S_NULL, 0, 0}, // S_SLUDGECHUNKX
+ {SPR_SLDG, 4, 5, NULL, S_SLUDGESPLASH2, 0, 0}, // S_SLUDGESPLASH1
+ {SPR_SLDG, 5, 5, NULL, S_SLUDGESPLASH3, 0, 0}, // S_SLUDGESPLASH2
+ {SPR_SLDG, 6, 5, NULL, S_SLUDGESPLASH4, 0, 0}, // S_SLUDGESPLASH3
+ {SPR_SLDG, 7, 5, NULL, S_NULL, 0, 0}, // S_SLUDGESPLASH4
+ {SPR_SKH1, 0, -1, NULL, S_NULL, 0, 0}, // S_SKULLHANG70_1
+ {SPR_SKH2, 0, -1, NULL, S_NULL, 0, 0}, // S_SKULLHANG60_1
+ {SPR_SKH3, 0, -1, NULL, S_NULL, 0, 0}, // S_SKULLHANG45_1
+ {SPR_SKH4, 0, -1, NULL, S_NULL, 0, 0}, // S_SKULLHANG35_1
+ {SPR_CHDL, 0, 4, NULL, S_CHANDELIER2, 0, 0}, // S_CHANDELIER1
+ {SPR_CHDL, 1, 4, NULL, S_CHANDELIER3, 0, 0}, // S_CHANDELIER2
+ {SPR_CHDL, 2, 4, NULL, S_CHANDELIER1, 0, 0}, // S_CHANDELIER3
+ {SPR_SRTC, 0, 4, NULL, S_SERPTORCH2, 0, 0}, // S_SERPTORCH1
+ {SPR_SRTC, 1, 4, NULL, S_SERPTORCH3, 0, 0}, // S_SERPTORCH2
+ {SPR_SRTC, 2, 4, NULL, S_SERPTORCH1, 0, 0}, // S_SERPTORCH3
+ {SPR_SMPL, 0, -1, NULL, S_NULL, 0, 0}, // S_SMALLPILLAR
+ {SPR_STGS, 0, -1, NULL, S_NULL, 0, 0}, // S_STALAGMITESMALL
+ {SPR_STGL, 0, -1, NULL, S_NULL, 0, 0}, // S_STALAGMITELARGE
+ {SPR_STCS, 0, -1, NULL, S_NULL, 0, 0}, // S_STALACTITESMALL
+ {SPR_STCL, 0, -1, NULL, S_NULL, 0, 0}, // S_STALACTITELARGE
+ {SPR_KFR1, 32768, 3, NULL, S_FIREBRAZIER2, 0, 0}, // S_FIREBRAZIER1
+ {SPR_KFR1, 32769, 3, NULL, S_FIREBRAZIER3, 0, 0}, // S_FIREBRAZIER2
+ {SPR_KFR1, 32770, 3, NULL, S_FIREBRAZIER4, 0, 0}, // S_FIREBRAZIER3
+ {SPR_KFR1, 32771, 3, NULL, S_FIREBRAZIER5, 0, 0}, // S_FIREBRAZIER4
+ {SPR_KFR1, 32772, 3, NULL, S_FIREBRAZIER6, 0, 0}, // S_FIREBRAZIER5
+ {SPR_KFR1, 32773, 3, NULL, S_FIREBRAZIER7, 0, 0}, // S_FIREBRAZIER6
+ {SPR_KFR1, 32774, 3, NULL, S_FIREBRAZIER8, 0, 0}, // S_FIREBRAZIER7
+ {SPR_KFR1, 32775, 3, NULL, S_FIREBRAZIER1, 0, 0}, // S_FIREBRAZIER8
+ {SPR_BARL, 0, -1, NULL, S_NULL, 0, 0}, // S_BARREL
+ {SPR_BRPL, 0, -1, NULL, S_NULL, 0, 0}, // S_BRPILLAR
+ {SPR_MOS1, 0, -1, NULL, S_NULL, 0, 0}, // S_MOSS1
+ {SPR_MOS2, 0, -1, NULL, S_NULL, 0, 0}, // S_MOSS2
+ {SPR_WTRH, 32768, 6, NULL, S_WALLTORCH2, 0, 0}, // S_WALLTORCH1
+ {SPR_WTRH, 32769, 6, NULL, S_WALLTORCH3, 0, 0}, // S_WALLTORCH2
+ {SPR_WTRH, 32770, 6, NULL, S_WALLTORCH1, 0, 0}, // S_WALLTORCH3
+ {SPR_HCOR, 0, -1, NULL, S_NULL, 0, 0}, // S_HANGINGCORPSE
+ {SPR_KGZ1, 0, 1, NULL, S_KEYGIZMO2, 0, 0}, // S_KEYGIZMO1
+ {SPR_KGZ1, 0, 1, A_InitKeyGizmo, S_KEYGIZMO3, 0, 0}, // S_KEYGIZMO2
+ {SPR_KGZ1, 0, -1, NULL, S_NULL, 0, 0}, // S_KEYGIZMO3
+ {SPR_KGZB, 0, 1, NULL, S_KGZ_START, 0, 0}, // S_KGZ_START
+ {SPR_KGZB, 32768, -1, NULL, S_NULL, 0, 0}, // S_KGZ_BLUEFLOAT1
+ {SPR_KGZG, 32768, -1, NULL, S_NULL, 0, 0}, // S_KGZ_GREENFLOAT1
+ {SPR_KGZY, 32768, -1, NULL, S_NULL, 0, 0}, // S_KGZ_YELLOWFLOAT1
+ {SPR_VLCO, 0, 350, NULL, S_VOLCANO2, 0, 0}, // S_VOLCANO1
+ {SPR_VLCO, 0, 35, A_VolcanoSet, S_VOLCANO3, 0, 0}, // S_VOLCANO2
+ {SPR_VLCO, 1, 3, NULL, S_VOLCANO4, 0, 0}, // S_VOLCANO3
+ {SPR_VLCO, 2, 3, NULL, S_VOLCANO5, 0, 0}, // S_VOLCANO4
+ {SPR_VLCO, 3, 3, NULL, S_VOLCANO6, 0, 0}, // S_VOLCANO5
+ {SPR_VLCO, 1, 3, NULL, S_VOLCANO7, 0, 0}, // S_VOLCANO6
+ {SPR_VLCO, 2, 3, NULL, S_VOLCANO8, 0, 0}, // S_VOLCANO7
+ {SPR_VLCO, 3, 3, NULL, S_VOLCANO9, 0, 0}, // S_VOLCANO8
+ {SPR_VLCO, 4, 10, A_VolcanoBlast, S_VOLCANO2, 0, 0}, // S_VOLCANO9
+ {SPR_VFBL, 0, 4, A_BeastPuff, S_VOLCANOBALL2, 0, 0}, // S_VOLCANOBALL1
+ {SPR_VFBL, 1, 4, A_BeastPuff, S_VOLCANOBALL1, 0, 0}, // S_VOLCANOBALL2
+ {SPR_XPL1, 0, 4, A_VolcBallImpact, S_VOLCANOBALLX2, 0, 0}, // S_VOLCANOBALLX1
+ {SPR_XPL1, 1, 4, NULL, S_VOLCANOBALLX3, 0, 0}, // S_VOLCANOBALLX2
+ {SPR_XPL1, 2, 4, NULL, S_VOLCANOBALLX4, 0, 0}, // S_VOLCANOBALLX3
+ {SPR_XPL1, 3, 4, NULL, S_VOLCANOBALLX5, 0, 0}, // S_VOLCANOBALLX4
+ {SPR_XPL1, 4, 4, NULL, S_VOLCANOBALLX6, 0, 0}, // S_VOLCANOBALLX5
+ {SPR_XPL1, 5, 4, NULL, S_NULL, 0, 0}, // S_VOLCANOBALLX6
+ {SPR_VTFB, 0, 4, NULL, S_VOLCANOTBALL2, 0, 0}, // S_VOLCANOTBALL1
+ {SPR_VTFB, 1, 4, NULL, S_VOLCANOTBALL1, 0, 0}, // S_VOLCANOTBALL2
+ {SPR_SFFI, 2, 4, NULL, S_VOLCANOTBALLX2, 0, 0}, // S_VOLCANOTBALLX1
+ {SPR_SFFI, 1, 4, NULL, S_VOLCANOTBALLX3, 0, 0}, // S_VOLCANOTBALLX2
+ {SPR_SFFI, 0, 4, NULL, S_VOLCANOTBALLX4, 0, 0}, // S_VOLCANOTBALLX3
+ {SPR_SFFI, 1, 4, NULL, S_VOLCANOTBALLX5, 0, 0}, // S_VOLCANOTBALLX4
+ {SPR_SFFI, 2, 4, NULL, S_VOLCANOTBALLX6, 0, 0}, // S_VOLCANOTBALLX5
+ {SPR_SFFI, 3, 4, NULL, S_VOLCANOTBALLX7, 0, 0}, // S_VOLCANOTBALLX6
+ {SPR_SFFI, 4, 4, NULL, S_NULL, 0, 0}, // S_VOLCANOTBALLX7
+ {SPR_TGLT, 0, 8, A_SpawnTeleGlitter, S_TELEGLITGEN1, 0, 0}, // S_TELEGLITGEN1
+ {SPR_TGLT, 5, 8, A_SpawnTeleGlitter2, S_TELEGLITGEN2, 0, 0}, // S_TELEGLITGEN2
+ {SPR_TGLT, 32768, 2, NULL, S_TELEGLITTER1_2, 0, 0}, // S_TELEGLITTER1_1
+ {SPR_TGLT, 32769, 2, A_AccTeleGlitter, S_TELEGLITTER1_3, 0, 0}, // S_TELEGLITTER1_2
+ {SPR_TGLT, 32770, 2, NULL, S_TELEGLITTER1_4, 0, 0}, // S_TELEGLITTER1_3
+ {SPR_TGLT, 32771, 2, A_AccTeleGlitter, S_TELEGLITTER1_5, 0, 0}, // S_TELEGLITTER1_4
+ {SPR_TGLT, 32772, 2, NULL, S_TELEGLITTER1_1, 0, 0}, // S_TELEGLITTER1_5
+ {SPR_TGLT, 32773, 2, NULL, S_TELEGLITTER2_2, 0, 0}, // S_TELEGLITTER2_1
+ {SPR_TGLT, 32774, 2, A_AccTeleGlitter, S_TELEGLITTER2_3, 0, 0}, // S_TELEGLITTER2_2
+ {SPR_TGLT, 32775, 2, NULL, S_TELEGLITTER2_4, 0, 0}, // S_TELEGLITTER2_3
+ {SPR_TGLT, 32776, 2, A_AccTeleGlitter, S_TELEGLITTER2_5, 0, 0}, // S_TELEGLITTER2_4
+ {SPR_TGLT, 32777, 2, NULL, S_TELEGLITTER2_1, 0, 0}, // S_TELEGLITTER2_5
+ {SPR_TELE, 32768, 6, NULL, S_TFOG2, 0, 0}, // S_TFOG1
+ {SPR_TELE, 32769, 6, NULL, S_TFOG3, 0, 0}, // S_TFOG2
+ {SPR_TELE, 32770, 6, NULL, S_TFOG4, 0, 0}, // S_TFOG3
+ {SPR_TELE, 32771, 6, NULL, S_TFOG5, 0, 0}, // S_TFOG4
+ {SPR_TELE, 32772, 6, NULL, S_TFOG6, 0, 0}, // S_TFOG5
+ {SPR_TELE, 32773, 6, NULL, S_TFOG7, 0, 0}, // S_TFOG6
+ {SPR_TELE, 32774, 6, NULL, S_TFOG8, 0, 0}, // S_TFOG7
+ {SPR_TELE, 32775, 6, NULL, S_TFOG9, 0, 0}, // S_TFOG8
+ {SPR_TELE, 32774, 6, NULL, S_TFOG10, 0, 0}, // S_TFOG9
+ {SPR_TELE, 32773, 6, NULL, S_TFOG11, 0, 0}, // S_TFOG10
+ {SPR_TELE, 32772, 6, NULL, S_TFOG12, 0, 0}, // S_TFOG11
+ {SPR_TELE, 32771, 6, NULL, S_TFOG13, 0, 0}, // S_TFOG12
+ {SPR_TELE, 32770, 6, NULL, S_NULL, 0, 0}, // S_TFOG13
+ {SPR_STFF, 0, 0, A_Light0, S_NULL, 0, 0}, // S_LIGHTDONE
+ {SPR_STFF, 0, 1, A_WeaponReady, S_STAFFREADY, 0, 0}, // S_STAFFREADY
+ {SPR_STFF, 0, 1, A_Lower, S_STAFFDOWN, 0, 0}, // S_STAFFDOWN
+ {SPR_STFF, 0, 1, A_Raise, S_STAFFUP, 0, 0}, // S_STAFFUP
+ {SPR_STFF, 3, 4, A_WeaponReady, S_STAFFREADY2_2, 0, 0}, // S_STAFFREADY2_1
+ {SPR_STFF, 4, 4, A_WeaponReady, S_STAFFREADY2_3, 0, 0}, // S_STAFFREADY2_2
+ {SPR_STFF, 5, 4, A_WeaponReady, S_STAFFREADY2_1, 0, 0}, // S_STAFFREADY2_3
+ {SPR_STFF, 3, 1, A_Lower, S_STAFFDOWN2, 0, 0}, // S_STAFFDOWN2
+ {SPR_STFF, 3, 1, A_Raise, S_STAFFUP2, 0, 0}, // S_STAFFUP2
+ {SPR_STFF, 1, 6, NULL, S_STAFFATK1_2, 0, 0}, // S_STAFFATK1_1
+ {SPR_STFF, 2, 8, A_StaffAttackPL1, S_STAFFATK1_3, 0, 0}, // S_STAFFATK1_2
+ {SPR_STFF, 1, 8, A_ReFire, S_STAFFREADY, 0, 0}, // S_STAFFATK1_3
+ {SPR_STFF, 6, 6, NULL, S_STAFFATK2_2, 0, 0}, // S_STAFFATK2_1
+ {SPR_STFF, 7, 8, A_StaffAttackPL2, S_STAFFATK2_3, 0, 0}, // S_STAFFATK2_2
+ {SPR_STFF, 6, 8, A_ReFire, S_STAFFREADY2_1, 0, 0}, // S_STAFFATK2_3
+ {SPR_PUF3, 32768, 4, NULL, S_STAFFPUFF2, 0, 0}, // S_STAFFPUFF1
+ {SPR_PUF3, 1, 4, NULL, S_STAFFPUFF3, 0, 0}, // S_STAFFPUFF2
+ {SPR_PUF3, 2, 4, NULL, S_STAFFPUFF4, 0, 0}, // S_STAFFPUFF3
+ {SPR_PUF3, 3, 4, NULL, S_NULL, 0, 0}, // S_STAFFPUFF4
+ {SPR_PUF4, 32768, 4, NULL, S_STAFFPUFF2_2, 0, 0}, // S_STAFFPUFF2_1
+ {SPR_PUF4, 32769, 4, NULL, S_STAFFPUFF2_3, 0, 0}, // S_STAFFPUFF2_2
+ {SPR_PUF4, 32770, 4, NULL, S_STAFFPUFF2_4, 0, 0}, // S_STAFFPUFF2_3
+ {SPR_PUF4, 32771, 4, NULL, S_STAFFPUFF2_5, 0, 0}, // S_STAFFPUFF2_4
+ {SPR_PUF4, 32772, 4, NULL, S_STAFFPUFF2_6, 0, 0}, // S_STAFFPUFF2_5
+ {SPR_PUF4, 32773, 4, NULL, S_NULL, 0, 0}, // S_STAFFPUFF2_6
+ {SPR_BEAK, 0, 1, A_BeakReady, S_BEAKREADY, 0, 0}, // S_BEAKREADY
+ {SPR_BEAK, 0, 1, A_Lower, S_BEAKDOWN, 0, 0}, // S_BEAKDOWN
+ {SPR_BEAK, 0, 1, A_BeakRaise, S_BEAKUP, 0, 0}, // S_BEAKUP
+ {SPR_BEAK, 0, 18, A_BeakAttackPL1, S_BEAKREADY, 0, 0}, // S_BEAKATK1_1
+ {SPR_BEAK, 0, 12, A_BeakAttackPL2, S_BEAKREADY, 0, 0}, // S_BEAKATK2_1
+ {SPR_WGNT, 0, -1, NULL, S_NULL, 0, 0}, // S_WGNT
+ {SPR_GAUN, 0, 1, A_WeaponReady, S_GAUNTLETREADY, 0, 0}, // S_GAUNTLETREADY
+ {SPR_GAUN, 0, 1, A_Lower, S_GAUNTLETDOWN, 0, 0}, // S_GAUNTLETDOWN
+ {SPR_GAUN, 0, 1, A_Raise, S_GAUNTLETUP, 0, 0}, // S_GAUNTLETUP
+ {SPR_GAUN, 6, 4, A_WeaponReady, S_GAUNTLETREADY2_2, 0, 0}, // S_GAUNTLETREADY2_1
+ {SPR_GAUN, 7, 4, A_WeaponReady, S_GAUNTLETREADY2_3, 0, 0}, // S_GAUNTLETREADY2_2
+ {SPR_GAUN, 8, 4, A_WeaponReady, S_GAUNTLETREADY2_1, 0, 0}, // S_GAUNTLETREADY2_3
+ {SPR_GAUN, 6, 1, A_Lower, S_GAUNTLETDOWN2, 0, 0}, // S_GAUNTLETDOWN2
+ {SPR_GAUN, 6, 1, A_Raise, S_GAUNTLETUP2, 0, 0}, // S_GAUNTLETUP2
+ {SPR_GAUN, 1, 4, NULL, S_GAUNTLETATK1_2, 0, 0}, // S_GAUNTLETATK1_1
+ {SPR_GAUN, 2, 4, NULL, S_GAUNTLETATK1_3, 0, 0}, // S_GAUNTLETATK1_2
+ {SPR_GAUN, 32771, 4, A_GauntletAttack, S_GAUNTLETATK1_4, 0, 0}, // S_GAUNTLETATK1_3
+ {SPR_GAUN, 32772, 4, A_GauntletAttack, S_GAUNTLETATK1_5, 0, 0}, // S_GAUNTLETATK1_4
+ {SPR_GAUN, 32773, 4, A_GauntletAttack, S_GAUNTLETATK1_6, 0, 0}, // S_GAUNTLETATK1_5
+ {SPR_GAUN, 2, 4, A_ReFire, S_GAUNTLETATK1_7, 0, 0}, // S_GAUNTLETATK1_6
+ {SPR_GAUN, 1, 4, A_Light0, S_GAUNTLETREADY, 0, 0}, // S_GAUNTLETATK1_7
+ {SPR_GAUN, 9, 4, NULL, S_GAUNTLETATK2_2, 0, 0}, // S_GAUNTLETATK2_1
+ {SPR_GAUN, 10, 4, NULL, S_GAUNTLETATK2_3, 0, 0}, // S_GAUNTLETATK2_2
+ {SPR_GAUN, 32779, 4, A_GauntletAttack, S_GAUNTLETATK2_4, 0, 0}, // S_GAUNTLETATK2_3
+ {SPR_GAUN, 32780, 4, A_GauntletAttack, S_GAUNTLETATK2_5, 0, 0}, // S_GAUNTLETATK2_4
+ {SPR_GAUN, 32781, 4, A_GauntletAttack, S_GAUNTLETATK2_6, 0, 0}, // S_GAUNTLETATK2_5
+ {SPR_GAUN, 10, 4, A_ReFire, S_GAUNTLETATK2_7, 0, 0}, // S_GAUNTLETATK2_6
+ {SPR_GAUN, 9, 4, A_Light0, S_GAUNTLETREADY2_1, 0, 0}, // S_GAUNTLETATK2_7
+ {SPR_PUF1, 32768, 4, NULL, S_GAUNTLETPUFF1_2, 0, 0}, // S_GAUNTLETPUFF1_1
+ {SPR_PUF1, 32769, 4, NULL, S_GAUNTLETPUFF1_3, 0, 0}, // S_GAUNTLETPUFF1_2
+ {SPR_PUF1, 32770, 4, NULL, S_GAUNTLETPUFF1_4, 0, 0}, // S_GAUNTLETPUFF1_3
+ {SPR_PUF1, 32771, 4, NULL, S_NULL, 0, 0}, // S_GAUNTLETPUFF1_4
+ {SPR_PUF1, 32772, 4, NULL, S_GAUNTLETPUFF2_2, 0, 0}, // S_GAUNTLETPUFF2_1
+ {SPR_PUF1, 32773, 4, NULL, S_GAUNTLETPUFF2_3, 0, 0}, // S_GAUNTLETPUFF2_2
+ {SPR_PUF1, 32774, 4, NULL, S_GAUNTLETPUFF2_4, 0, 0}, // S_GAUNTLETPUFF2_3
+ {SPR_PUF1, 32775, 4, NULL, S_NULL, 0, 0}, // S_GAUNTLETPUFF2_4
+ {SPR_WBLS, 0, -1, NULL, S_NULL, 0, 0}, // S_BLSR
+ {SPR_BLSR, 0, 1, A_WeaponReady, S_BLASTERREADY, 0, 0}, // S_BLASTERREADY
+ {SPR_BLSR, 0, 1, A_Lower, S_BLASTERDOWN, 0, 0}, // S_BLASTERDOWN
+ {SPR_BLSR, 0, 1, A_Raise, S_BLASTERUP, 0, 0}, // S_BLASTERUP
+ {SPR_BLSR, 1, 3, NULL, S_BLASTERATK1_2, 0, 0}, // S_BLASTERATK1_1
+ {SPR_BLSR, 2, 3, NULL, S_BLASTERATK1_3, 0, 0}, // S_BLASTERATK1_2
+ {SPR_BLSR, 3, 2, A_FireBlasterPL1, S_BLASTERATK1_4, 0, 0}, // S_BLASTERATK1_3
+ {SPR_BLSR, 2, 2, NULL, S_BLASTERATK1_5, 0, 0}, // S_BLASTERATK1_4
+ {SPR_BLSR, 1, 2, NULL, S_BLASTERATK1_6, 0, 0}, // S_BLASTERATK1_5
+ {SPR_BLSR, 0, 0, A_ReFire, S_BLASTERREADY, 0, 0}, // S_BLASTERATK1_6
+ {SPR_BLSR, 1, 0, NULL, S_BLASTERATK2_2, 0, 0}, // S_BLASTERATK2_1
+ {SPR_BLSR, 2, 0, NULL, S_BLASTERATK2_3, 0, 0}, // S_BLASTERATK2_2
+ {SPR_BLSR, 3, 3, A_FireBlasterPL2, S_BLASTERATK2_4, 0, 0}, // S_BLASTERATK2_3
+ {SPR_BLSR, 2, 4, NULL, S_BLASTERATK2_5, 0, 0}, // S_BLASTERATK2_4
+ {SPR_BLSR, 1, 4, NULL, S_BLASTERATK2_6, 0, 0}, // S_BLASTERATK2_5
+ {SPR_BLSR, 0, 0, A_ReFire, S_BLASTERREADY, 0, 0}, // S_BLASTERATK2_6
+ {SPR_ACLO, 4, 200, NULL, S_BLASTERFX1_1, 0, 0}, // S_BLASTERFX1_1
+ {SPR_FX18, 32768, 3, A_SpawnRippers, S_BLASTERFXI1_2, 0, 0}, // S_BLASTERFXI1_1
+ {SPR_FX18, 32769, 3, NULL, S_BLASTERFXI1_3, 0, 0}, // S_BLASTERFXI1_2
+ {SPR_FX18, 32770, 4, NULL, S_BLASTERFXI1_4, 0, 0}, // S_BLASTERFXI1_3
+ {SPR_FX18, 32771, 4, NULL, S_BLASTERFXI1_5, 0, 0}, // S_BLASTERFXI1_4
+ {SPR_FX18, 32772, 4, NULL, S_BLASTERFXI1_6, 0, 0}, // S_BLASTERFXI1_5
+ {SPR_FX18, 32773, 4, NULL, S_BLASTERFXI1_7, 0, 0}, // S_BLASTERFXI1_6
+ {SPR_FX18, 32774, 4, NULL, S_NULL, 0, 0}, // S_BLASTERFXI1_7
+ {SPR_FX18, 7, 4, NULL, S_BLASTERSMOKE2, 0, 0}, // S_BLASTERSMOKE1
+ {SPR_FX18, 8, 4, NULL, S_BLASTERSMOKE3, 0, 0}, // S_BLASTERSMOKE2
+ {SPR_FX18, 9, 4, NULL, S_BLASTERSMOKE4, 0, 0}, // S_BLASTERSMOKE3
+ {SPR_FX18, 10, 4, NULL, S_BLASTERSMOKE5, 0, 0}, // S_BLASTERSMOKE4
+ {SPR_FX18, 11, 4, NULL, S_NULL, 0, 0}, // S_BLASTERSMOKE5
+ {SPR_FX18, 12, 4, NULL, S_RIPPER2, 0, 0}, // S_RIPPER1
+ {SPR_FX18, 13, 5, NULL, S_RIPPER1, 0, 0}, // S_RIPPER2
+ {SPR_FX18, 32782, 4, NULL, S_RIPPERX2, 0, 0}, // S_RIPPERX1
+ {SPR_FX18, 32783, 4, NULL, S_RIPPERX3, 0, 0}, // S_RIPPERX2
+ {SPR_FX18, 32784, 4, NULL, S_RIPPERX4, 0, 0}, // S_RIPPERX3
+ {SPR_FX18, 32785, 4, NULL, S_RIPPERX5, 0, 0}, // S_RIPPERX4
+ {SPR_FX18, 32786, 4, NULL, S_NULL, 0, 0}, // S_RIPPERX5
+ {SPR_FX17, 32768, 4, NULL, S_BLASTERPUFF1_2, 0, 0}, // S_BLASTERPUFF1_1
+ {SPR_FX17, 32769, 4, NULL, S_BLASTERPUFF1_3, 0, 0}, // S_BLASTERPUFF1_2
+ {SPR_FX17, 32770, 4, NULL, S_BLASTERPUFF1_4, 0, 0}, // S_BLASTERPUFF1_3
+ {SPR_FX17, 32771, 4, NULL, S_BLASTERPUFF1_5, 0, 0}, // S_BLASTERPUFF1_4
+ {SPR_FX17, 32772, 4, NULL, S_NULL, 0, 0}, // S_BLASTERPUFF1_5
+ {SPR_FX17, 32773, 3, NULL, S_BLASTERPUFF2_2, 0, 0}, // S_BLASTERPUFF2_1
+ {SPR_FX17, 32774, 3, NULL, S_BLASTERPUFF2_3, 0, 0}, // S_BLASTERPUFF2_2
+ {SPR_FX17, 32775, 4, NULL, S_BLASTERPUFF2_4, 0, 0}, // S_BLASTERPUFF2_3
+ {SPR_FX17, 32776, 4, NULL, S_BLASTERPUFF2_5, 0, 0}, // S_BLASTERPUFF2_4
+ {SPR_FX17, 32777, 4, NULL, S_BLASTERPUFF2_6, 0, 0}, // S_BLASTERPUFF2_5
+ {SPR_FX17, 32778, 4, NULL, S_BLASTERPUFF2_7, 0, 0}, // S_BLASTERPUFF2_6
+ {SPR_FX17, 32779, 4, NULL, S_NULL, 0, 0}, // S_BLASTERPUFF2_7
+ {SPR_WMCE, 0, -1, NULL, S_NULL, 0, 0}, // S_WMCE
+ {SPR_MACE, 0, 1, A_WeaponReady, S_MACEREADY, 0, 0}, // S_MACEREADY
+ {SPR_MACE, 0, 1, A_Lower, S_MACEDOWN, 0, 0}, // S_MACEDOWN
+ {SPR_MACE, 0, 1, A_Raise, S_MACEUP, 0, 0}, // S_MACEUP
+ {SPR_MACE, 1, 4, NULL, S_MACEATK1_2, 0, 0}, // S_MACEATK1_1
+ {SPR_MACE, 2, 3, A_FireMacePL1, S_MACEATK1_3, 0, 0}, // S_MACEATK1_2
+ {SPR_MACE, 3, 3, A_FireMacePL1, S_MACEATK1_4, 0, 0}, // S_MACEATK1_3
+ {SPR_MACE, 4, 3, A_FireMacePL1, S_MACEATK1_5, 0, 0}, // S_MACEATK1_4
+ {SPR_MACE, 5, 3, A_FireMacePL1, S_MACEATK1_6, 0, 0}, // S_MACEATK1_5
+ {SPR_MACE, 2, 4, A_ReFire, S_MACEATK1_7, 0, 0}, // S_MACEATK1_6
+ {SPR_MACE, 3, 4, NULL, S_MACEATK1_8, 0, 0}, // S_MACEATK1_7
+ {SPR_MACE, 4, 4, NULL, S_MACEATK1_9, 0, 0}, // S_MACEATK1_8
+ {SPR_MACE, 5, 4, NULL, S_MACEATK1_10, 0, 0}, // S_MACEATK1_9
+ {SPR_MACE, 1, 4, NULL, S_MACEREADY, 0, 0}, // S_MACEATK1_10
+ {SPR_MACE, 1, 4, NULL, S_MACEATK2_2, 0, 0}, // S_MACEATK2_1
+ {SPR_MACE, 3, 4, A_FireMacePL2, S_MACEATK2_3, 0, 0}, // S_MACEATK2_2
+ {SPR_MACE, 1, 4, NULL, S_MACEATK2_4, 0, 0}, // S_MACEATK2_3
+ {SPR_MACE, 0, 8, A_ReFire, S_MACEREADY, 0, 0}, // S_MACEATK2_4
+ {SPR_FX02, 0, 4, A_MacePL1Check, S_MACEFX1_2, 0, 0}, // S_MACEFX1_1
+ {SPR_FX02, 1, 4, A_MacePL1Check, S_MACEFX1_1, 0, 0}, // S_MACEFX1_2
+ {SPR_FX02, 32773, 4, A_MaceBallImpact, S_MACEFXI1_2, 0, 0}, // S_MACEFXI1_1
+ {SPR_FX02, 32774, 4, NULL, S_MACEFXI1_3, 0, 0}, // S_MACEFXI1_2
+ {SPR_FX02, 32775, 4, NULL, S_MACEFXI1_4, 0, 0}, // S_MACEFXI1_3
+ {SPR_FX02, 32776, 4, NULL, S_MACEFXI1_5, 0, 0}, // S_MACEFXI1_4
+ {SPR_FX02, 32777, 4, NULL, S_NULL, 0, 0}, // S_MACEFXI1_5
+ {SPR_FX02, 2, 4, NULL, S_MACEFX2_2, 0, 0}, // S_MACEFX2_1
+ {SPR_FX02, 3, 4, NULL, S_MACEFX2_1, 0, 0}, // S_MACEFX2_2
+ {SPR_FX02, 32773, 4, A_MaceBallImpact2, S_MACEFXI1_2, 0, 0}, // S_MACEFXI2_1
+ {SPR_FX02, 0, 4, NULL, S_MACEFX3_2, 0, 0}, // S_MACEFX3_1
+ {SPR_FX02, 1, 4, NULL, S_MACEFX3_1, 0, 0}, // S_MACEFX3_2
+ {SPR_FX02, 4, 99, NULL, S_MACEFX4_1, 0, 0}, // S_MACEFX4_1
+ {SPR_FX02, 32770, 4, A_DeathBallImpact, S_MACEFXI1_2, 0, 0}, // S_MACEFXI4_1
+ {SPR_WSKL, 0, -1, NULL, S_NULL, 0, 0}, // S_WSKL
+ {SPR_HROD, 0, 1, A_WeaponReady, S_HORNRODREADY, 0, 0}, // S_HORNRODREADY
+ {SPR_HROD, 0, 1, A_Lower, S_HORNRODDOWN, 0, 0}, // S_HORNRODDOWN
+ {SPR_HROD, 0, 1, A_Raise, S_HORNRODUP, 0, 0}, // S_HORNRODUP
+ {SPR_HROD, 0, 4, A_FireSkullRodPL1, S_HORNRODATK1_2, 0, 0}, // S_HORNRODATK1_1
+ {SPR_HROD, 1, 4, A_FireSkullRodPL1, S_HORNRODATK1_3, 0, 0}, // S_HORNRODATK1_2
+ {SPR_HROD, 1, 0, A_ReFire, S_HORNRODREADY, 0, 0}, // S_HORNRODATK1_3
+ {SPR_HROD, 2, 2, NULL, S_HORNRODATK2_2, 0, 0}, // S_HORNRODATK2_1
+ {SPR_HROD, 3, 3, NULL, S_HORNRODATK2_3, 0, 0}, // S_HORNRODATK2_2
+ {SPR_HROD, 4, 2, NULL, S_HORNRODATK2_4, 0, 0}, // S_HORNRODATK2_3
+ {SPR_HROD, 5, 3, NULL, S_HORNRODATK2_5, 0, 0}, // S_HORNRODATK2_4
+ {SPR_HROD, 6, 4, A_FireSkullRodPL2, S_HORNRODATK2_6, 0, 0}, // S_HORNRODATK2_5
+ {SPR_HROD, 5, 2, NULL, S_HORNRODATK2_7, 0, 0}, // S_HORNRODATK2_6
+ {SPR_HROD, 4, 3, NULL, S_HORNRODATK2_8, 0, 0}, // S_HORNRODATK2_7
+ {SPR_HROD, 3, 2, NULL, S_HORNRODATK2_9, 0, 0}, // S_HORNRODATK2_8
+ {SPR_HROD, 2, 2, A_ReFire, S_HORNRODREADY, 0, 0}, // S_HORNRODATK2_9
+ {SPR_FX00, 32768, 6, NULL, S_HRODFX1_2, 0, 0}, // S_HRODFX1_1
+ {SPR_FX00, 32769, 6, NULL, S_HRODFX1_1, 0, 0}, // S_HRODFX1_2
+ {SPR_FX00, 32775, 5, NULL, S_HRODFXI1_2, 0, 0}, // S_HRODFXI1_1
+ {SPR_FX00, 32776, 5, NULL, S_HRODFXI1_3, 0, 0}, // S_HRODFXI1_2
+ {SPR_FX00, 32777, 4, NULL, S_HRODFXI1_4, 0, 0}, // S_HRODFXI1_3
+ {SPR_FX00, 32778, 4, NULL, S_HRODFXI1_5, 0, 0}, // S_HRODFXI1_4
+ {SPR_FX00, 32779, 3, NULL, S_HRODFXI1_6, 0, 0}, // S_HRODFXI1_5
+ {SPR_FX00, 32780, 3, NULL, S_NULL, 0, 0}, // S_HRODFXI1_6
+ {SPR_FX00, 32770, 3, NULL, S_HRODFX2_2, 0, 0}, // S_HRODFX2_1
+ {SPR_FX00, 32771, 3, A_SkullRodPL2Seek, S_HRODFX2_3, 0, 0}, // S_HRODFX2_2
+ {SPR_FX00, 32772, 3, NULL, S_HRODFX2_4, 0, 0}, // S_HRODFX2_3
+ {SPR_FX00, 32773, 3, A_SkullRodPL2Seek, S_HRODFX2_1, 0, 0}, // S_HRODFX2_4
+ {SPR_FX00, 32775, 5, A_AddPlayerRain, S_HRODFXI2_2, 0, 0}, // S_HRODFXI2_1
+ {SPR_FX00, 32776, 5, NULL, S_HRODFXI2_3, 0, 0}, // S_HRODFXI2_2
+ {SPR_FX00, 32777, 4, NULL, S_HRODFXI2_4, 0, 0}, // S_HRODFXI2_3
+ {SPR_FX00, 32778, 3, NULL, S_HRODFXI2_5, 0, 0}, // S_HRODFXI2_4
+ {SPR_FX00, 32779, 3, NULL, S_HRODFXI2_6, 0, 0}, // S_HRODFXI2_5
+ {SPR_FX00, 32780, 3, NULL, S_HRODFXI2_7, 0, 0}, // S_HRODFXI2_6
+ {SPR_FX00, 6, 1, A_HideInCeiling, S_HRODFXI2_8, 0, 0}, // S_HRODFXI2_7
+ {SPR_FX00, 6, 1, A_SkullRodStorm, S_HRODFXI2_8, 0, 0}, // S_HRODFXI2_8
+ {SPR_FX20, 32768, -1, NULL, S_NULL, 0, 0}, // S_RAINPLR1_1
+ {SPR_FX21, 32768, -1, NULL, S_NULL, 0, 0}, // S_RAINPLR2_1
+ {SPR_FX22, 32768, -1, NULL, S_NULL, 0, 0}, // S_RAINPLR3_1
+ {SPR_FX23, 32768, -1, NULL, S_NULL, 0, 0}, // S_RAINPLR4_1
+ {SPR_FX20, 32769, 4, A_RainImpact, S_RAINPLR1X_2, 0, 0}, // S_RAINPLR1X_1
+ {SPR_FX20, 32770, 4, NULL, S_RAINPLR1X_3, 0, 0}, // S_RAINPLR1X_2
+ {SPR_FX20, 32771, 4, NULL, S_RAINPLR1X_4, 0, 0}, // S_RAINPLR1X_3
+ {SPR_FX20, 32772, 4, NULL, S_RAINPLR1X_5, 0, 0}, // S_RAINPLR1X_4
+ {SPR_FX20, 32773, 4, NULL, S_NULL, 0, 0}, // S_RAINPLR1X_5
+ {SPR_FX21, 32769, 4, A_RainImpact, S_RAINPLR2X_2, 0, 0}, // S_RAINPLR2X_1
+ {SPR_FX21, 32770, 4, NULL, S_RAINPLR2X_3, 0, 0}, // S_RAINPLR2X_2
+ {SPR_FX21, 32771, 4, NULL, S_RAINPLR2X_4, 0, 0}, // S_RAINPLR2X_3
+ {SPR_FX21, 32772, 4, NULL, S_RAINPLR2X_5, 0, 0}, // S_RAINPLR2X_4
+ {SPR_FX21, 32773, 4, NULL, S_NULL, 0, 0}, // S_RAINPLR2X_5
+ {SPR_FX22, 32769, 4, A_RainImpact, S_RAINPLR3X_2, 0, 0}, // S_RAINPLR3X_1
+ {SPR_FX22, 32770, 4, NULL, S_RAINPLR3X_3, 0, 0}, // S_RAINPLR3X_2
+ {SPR_FX22, 32771, 4, NULL, S_RAINPLR3X_4, 0, 0}, // S_RAINPLR3X_3
+ {SPR_FX22, 32772, 4, NULL, S_RAINPLR3X_5, 0, 0}, // S_RAINPLR3X_4
+ {SPR_FX22, 32773, 4, NULL, S_NULL, 0, 0}, // S_RAINPLR3X_5
+ {SPR_FX23, 32769, 4, A_RainImpact, S_RAINPLR4X_2, 0, 0}, // S_RAINPLR4X_1
+ {SPR_FX23, 32770, 4, NULL, S_RAINPLR4X_3, 0, 0}, // S_RAINPLR4X_2
+ {SPR_FX23, 32771, 4, NULL, S_RAINPLR4X_4, 0, 0}, // S_RAINPLR4X_3
+ {SPR_FX23, 32772, 4, NULL, S_RAINPLR4X_5, 0, 0}, // S_RAINPLR4X_4
+ {SPR_FX23, 32773, 4, NULL, S_NULL, 0, 0}, // S_RAINPLR4X_5
+ {SPR_FX20, 32774, 4, NULL, S_RAINAIRXPLR1_2, 0, 0}, // S_RAINAIRXPLR1_1
+ {SPR_FX21, 32774, 4, NULL, S_RAINAIRXPLR2_2, 0, 0}, // S_RAINAIRXPLR2_1
+ {SPR_FX22, 32774, 4, NULL, S_RAINAIRXPLR3_2, 0, 0}, // S_RAINAIRXPLR3_1
+ {SPR_FX23, 32774, 4, NULL, S_RAINAIRXPLR4_2, 0, 0}, // S_RAINAIRXPLR4_1
+ {SPR_FX20, 32775, 4, NULL, S_RAINAIRXPLR1_3, 0, 0}, // S_RAINAIRXPLR1_2
+ {SPR_FX21, 32775, 4, NULL, S_RAINAIRXPLR2_3, 0, 0}, // S_RAINAIRXPLR2_2
+ {SPR_FX22, 32775, 4, NULL, S_RAINAIRXPLR3_3, 0, 0}, // S_RAINAIRXPLR3_2
+ {SPR_FX23, 32775, 4, NULL, S_RAINAIRXPLR4_3, 0, 0}, // S_RAINAIRXPLR4_2
+ {SPR_FX20, 32776, 4, NULL, S_NULL, 0, 0}, // S_RAINAIRXPLR1_3
+ {SPR_FX21, 32776, 4, NULL, S_NULL, 0, 0}, // S_RAINAIRXPLR2_3
+ {SPR_FX22, 32776, 4, NULL, S_NULL, 0, 0}, // S_RAINAIRXPLR3_3
+ {SPR_FX23, 32776, 4, NULL, S_NULL, 0, 0}, // S_RAINAIRXPLR4_3
+ {SPR_GWND, 0, 1, A_WeaponReady, S_GOLDWANDREADY, 0, 0}, // S_GOLDWANDREADY
+ {SPR_GWND, 0, 1, A_Lower, S_GOLDWANDDOWN, 0, 0}, // S_GOLDWANDDOWN
+ {SPR_GWND, 0, 1, A_Raise, S_GOLDWANDUP, 0, 0}, // S_GOLDWANDUP
+ {SPR_GWND, 1, 3, NULL, S_GOLDWANDATK1_2, 0, 0}, // S_GOLDWANDATK1_1
+ {SPR_GWND, 2, 5, A_FireGoldWandPL1, S_GOLDWANDATK1_3, 0, 0}, // S_GOLDWANDATK1_2
+ {SPR_GWND, 3, 3, NULL, S_GOLDWANDATK1_4, 0, 0}, // S_GOLDWANDATK1_3
+ {SPR_GWND, 3, 0, A_ReFire, S_GOLDWANDREADY, 0, 0}, // S_GOLDWANDATK1_4
+ {SPR_GWND, 1, 3, NULL, S_GOLDWANDATK2_2, 0, 0}, // S_GOLDWANDATK2_1
+ {SPR_GWND, 2, 4, A_FireGoldWandPL2, S_GOLDWANDATK2_3, 0, 0}, // S_GOLDWANDATK2_2
+ {SPR_GWND, 3, 3, NULL, S_GOLDWANDATK2_4, 0, 0}, // S_GOLDWANDATK2_3
+ {SPR_GWND, 3, 0, A_ReFire, S_GOLDWANDREADY, 0, 0}, // S_GOLDWANDATK2_4
+ {SPR_FX01, 32768, 6, NULL, S_GWANDFX1_2, 0, 0}, // S_GWANDFX1_1
+ {SPR_FX01, 32769, 6, NULL, S_GWANDFX1_1, 0, 0}, // S_GWANDFX1_2
+ {SPR_FX01, 32772, 3, NULL, S_GWANDFXI1_2, 0, 0}, // S_GWANDFXI1_1
+ {SPR_FX01, 32773, 3, NULL, S_GWANDFXI1_3, 0, 0}, // S_GWANDFXI1_2
+ {SPR_FX01, 32774, 3, NULL, S_GWANDFXI1_4, 0, 0}, // S_GWANDFXI1_3
+ {SPR_FX01, 32775, 3, NULL, S_NULL, 0, 0}, // S_GWANDFXI1_4
+ {SPR_FX01, 32770, 6, NULL, S_GWANDFX2_2, 0, 0}, // S_GWANDFX2_1
+ {SPR_FX01, 32771, 6, NULL, S_GWANDFX2_1, 0, 0}, // S_GWANDFX2_2
+ {SPR_PUF2, 32768, 3, NULL, S_GWANDPUFF1_2, 0, 0}, // S_GWANDPUFF1_1
+ {SPR_PUF2, 32769, 3, NULL, S_GWANDPUFF1_3, 0, 0}, // S_GWANDPUFF1_2
+ {SPR_PUF2, 32770, 3, NULL, S_GWANDPUFF1_4, 0, 0}, // S_GWANDPUFF1_3
+ {SPR_PUF2, 32771, 3, NULL, S_GWANDPUFF1_5, 0, 0}, // S_GWANDPUFF1_4
+ {SPR_PUF2, 32772, 3, NULL, S_NULL, 0, 0}, // S_GWANDPUFF1_5
+ {SPR_WPHX, 0, -1, NULL, S_NULL, 0, 0}, // S_WPHX
+ {SPR_PHNX, 0, 1, A_WeaponReady, S_PHOENIXREADY, 0, 0}, // S_PHOENIXREADY
+ {SPR_PHNX, 0, 1, A_Lower, S_PHOENIXDOWN, 0, 0}, // S_PHOENIXDOWN
+ {SPR_PHNX, 0, 1, A_Raise, S_PHOENIXUP, 0, 0}, // S_PHOENIXUP
+ {SPR_PHNX, 1, 5, NULL, S_PHOENIXATK1_2, 0, 0}, // S_PHOENIXATK1_1
+ {SPR_PHNX, 2, 7, A_FirePhoenixPL1, S_PHOENIXATK1_3, 0, 0}, // S_PHOENIXATK1_2
+ {SPR_PHNX, 3, 4, NULL, S_PHOENIXATK1_4, 0, 0}, // S_PHOENIXATK1_3
+ {SPR_PHNX, 1, 4, NULL, S_PHOENIXATK1_5, 0, 0}, // S_PHOENIXATK1_4
+ {SPR_PHNX, 1, 0, A_ReFire, S_PHOENIXREADY, 0, 0}, // S_PHOENIXATK1_5
+ {SPR_PHNX, 1, 3, A_InitPhoenixPL2, S_PHOENIXATK2_2, 0, 0}, // S_PHOENIXATK2_1
+ {SPR_PHNX, 32770, 1, A_FirePhoenixPL2, S_PHOENIXATK2_3, 0, 0}, // S_PHOENIXATK2_2
+ {SPR_PHNX, 1, 4, A_ReFire, S_PHOENIXATK2_4, 0, 0}, // S_PHOENIXATK2_3
+ {SPR_PHNX, 1, 4, A_ShutdownPhoenixPL2, S_PHOENIXREADY, 0, 0}, // S_PHOENIXATK2_4
+ {SPR_FX04, 32768, 4, A_PhoenixPuff, S_PHOENIXFX1_1, 0, 0}, // S_PHOENIXFX1_1
+ {SPR_FX08, 32768, 6, A_Explode, S_PHOENIXFXI1_2, 0, 0}, // S_PHOENIXFXI1_1
+ {SPR_FX08, 32769, 5, NULL, S_PHOENIXFXI1_3, 0, 0}, // S_PHOENIXFXI1_2
+ {SPR_FX08, 32770, 5, NULL, S_PHOENIXFXI1_4, 0, 0}, // S_PHOENIXFXI1_3
+ {SPR_FX08, 32771, 4, NULL, S_PHOENIXFXI1_5, 0, 0}, // S_PHOENIXFXI1_4
+ {SPR_FX08, 32772, 4, NULL, S_PHOENIXFXI1_6, 0, 0}, // S_PHOENIXFXI1_5
+ {SPR_FX08, 32773, 4, NULL, S_PHOENIXFXI1_7, 0, 0}, // S_PHOENIXFXI1_6
+ {SPR_FX08, 32774, 4, NULL, S_PHOENIXFXI1_8, 0, 0}, // S_PHOENIXFXI1_7
+ {SPR_FX08, 32775, 4, NULL, S_NULL, 0, 0}, // S_PHOENIXFXI1_8
+ {SPR_FX08, 32776, 8, NULL, S_PHOENIXFXIX_1, 0, 0 }, // S_PHOENIXFXIX_1
+ {SPR_FX08, 32777, 8, A_RemovedPhoenixFunc, S_PHOENIXFXIX_2, 0, 0 }, // S_PHOENIXFXIX_2
+ {SPR_FX08, 32778, 8, NULL, S_NULL, 0, 0 }, // S_PHOENIXFXIX_3
+ {SPR_FX04, 1, 4, NULL, S_PHOENIXPUFF2, 0, 0}, // S_PHOENIXPUFF1
+ {SPR_FX04, 2, 4, NULL, S_PHOENIXPUFF3, 0, 0}, // S_PHOENIXPUFF2
+ {SPR_FX04, 3, 4, NULL, S_PHOENIXPUFF4, 0, 0}, // S_PHOENIXPUFF3
+ {SPR_FX04, 4, 4, NULL, S_PHOENIXPUFF5, 0, 0}, // S_PHOENIXPUFF4
+ {SPR_FX04, 5, 4, NULL, S_NULL, 0, 0}, // S_PHOENIXPUFF5
+ {SPR_FX09, 32768, 2, NULL, S_PHOENIXFX2_2, 0, 0}, // S_PHOENIXFX2_1
+ {SPR_FX09, 32769, 2, NULL, S_PHOENIXFX2_3, 0, 0}, // S_PHOENIXFX2_2
+ {SPR_FX09, 32768, 2, NULL, S_PHOENIXFX2_4, 0, 0}, // S_PHOENIXFX2_3
+ {SPR_FX09, 32769, 2, NULL, S_PHOENIXFX2_5, 0, 0}, // S_PHOENIXFX2_4
+ {SPR_FX09, 32768, 2, NULL, S_PHOENIXFX2_6, 0, 0}, // S_PHOENIXFX2_5
+ {SPR_FX09, 32769, 2, A_FlameEnd, S_PHOENIXFX2_7, 0, 0}, // S_PHOENIXFX2_6
+ {SPR_FX09, 32770, 2, NULL, S_PHOENIXFX2_8, 0, 0}, // S_PHOENIXFX2_7
+ {SPR_FX09, 32771, 2, NULL, S_PHOENIXFX2_9, 0, 0}, // S_PHOENIXFX2_8
+ {SPR_FX09, 32772, 2, NULL, S_PHOENIXFX2_10, 0, 0}, // S_PHOENIXFX2_9
+ {SPR_FX09, 32773, 2, NULL, S_NULL, 0, 0}, // S_PHOENIXFX2_10
+ {SPR_FX09, 32774, 3, NULL, S_PHOENIXFXI2_2, 0, 0}, // S_PHOENIXFXI2_1
+ {SPR_FX09, 32775, 3, A_FloatPuff, S_PHOENIXFXI2_3, 0, 0}, // S_PHOENIXFXI2_2
+ {SPR_FX09, 32776, 4, NULL, S_PHOENIXFXI2_4, 0, 0}, // S_PHOENIXFXI2_3
+ {SPR_FX09, 32777, 5, NULL, S_PHOENIXFXI2_5, 0, 0}, // S_PHOENIXFXI2_4
+ {SPR_FX09, 32778, 5, NULL, S_NULL, 0, 0}, // S_PHOENIXFXI2_5
+ {SPR_WBOW, 0, -1, NULL, S_NULL, 0, 0}, // S_WBOW
+ {SPR_CRBW, 0, 1, A_WeaponReady, S_CRBOW2, 0, 0}, // S_CRBOW1
+ {SPR_CRBW, 0, 1, A_WeaponReady, S_CRBOW3, 0, 0}, // S_CRBOW2
+ {SPR_CRBW, 0, 1, A_WeaponReady, S_CRBOW4, 0, 0}, // S_CRBOW3
+ {SPR_CRBW, 0, 1, A_WeaponReady, S_CRBOW5, 0, 0}, // S_CRBOW4
+ {SPR_CRBW, 0, 1, A_WeaponReady, S_CRBOW6, 0, 0}, // S_CRBOW5
+ {SPR_CRBW, 0, 1, A_WeaponReady, S_CRBOW7, 0, 0}, // S_CRBOW6
+ {SPR_CRBW, 1, 1, A_WeaponReady, S_CRBOW8, 0, 0}, // S_CRBOW7
+ {SPR_CRBW, 1, 1, A_WeaponReady, S_CRBOW9, 0, 0}, // S_CRBOW8
+ {SPR_CRBW, 1, 1, A_WeaponReady, S_CRBOW10, 0, 0}, // S_CRBOW9
+ {SPR_CRBW, 1, 1, A_WeaponReady, S_CRBOW11, 0, 0}, // S_CRBOW10
+ {SPR_CRBW, 1, 1, A_WeaponReady, S_CRBOW12, 0, 0}, // S_CRBOW11
+ {SPR_CRBW, 1, 1, A_WeaponReady, S_CRBOW13, 0, 0}, // S_CRBOW12
+ {SPR_CRBW, 2, 1, A_WeaponReady, S_CRBOW14, 0, 0}, // S_CRBOW13
+ {SPR_CRBW, 2, 1, A_WeaponReady, S_CRBOW15, 0, 0}, // S_CRBOW14
+ {SPR_CRBW, 2, 1, A_WeaponReady, S_CRBOW16, 0, 0}, // S_CRBOW15
+ {SPR_CRBW, 2, 1, A_WeaponReady, S_CRBOW17, 0, 0}, // S_CRBOW16
+ {SPR_CRBW, 2, 1, A_WeaponReady, S_CRBOW18, 0, 0}, // S_CRBOW17
+ {SPR_CRBW, 2, 1, A_WeaponReady, S_CRBOW1, 0, 0}, // S_CRBOW18
+ {SPR_CRBW, 0, 1, A_Lower, S_CRBOWDOWN, 0, 0}, // S_CRBOWDOWN
+ {SPR_CRBW, 0, 1, A_Raise, S_CRBOWUP, 0, 0}, // S_CRBOWUP
+ {SPR_CRBW, 3, 6, A_FireCrossbowPL1, S_CRBOWATK1_2, 0, 0}, // S_CRBOWATK1_1
+ {SPR_CRBW, 4, 3, NULL, S_CRBOWATK1_3, 0, 0}, // S_CRBOWATK1_2
+ {SPR_CRBW, 5, 3, NULL, S_CRBOWATK1_4, 0, 0}, // S_CRBOWATK1_3
+ {SPR_CRBW, 6, 3, NULL, S_CRBOWATK1_5, 0, 0}, // S_CRBOWATK1_4
+ {SPR_CRBW, 7, 3, NULL, S_CRBOWATK1_6, 0, 0}, // S_CRBOWATK1_5
+ {SPR_CRBW, 0, 4, NULL, S_CRBOWATK1_7, 0, 0}, // S_CRBOWATK1_6
+ {SPR_CRBW, 1, 4, NULL, S_CRBOWATK1_8, 0, 0}, // S_CRBOWATK1_7
+ {SPR_CRBW, 2, 5, A_ReFire, S_CRBOW1, 0, 0}, // S_CRBOWATK1_8
+ {SPR_CRBW, 3, 5, A_FireCrossbowPL2, S_CRBOWATK2_2, 0, 0}, // S_CRBOWATK2_1
+ {SPR_CRBW, 4, 3, NULL, S_CRBOWATK2_3, 0, 0}, // S_CRBOWATK2_2
+ {SPR_CRBW, 5, 2, NULL, S_CRBOWATK2_4, 0, 0}, // S_CRBOWATK2_3
+ {SPR_CRBW, 6, 3, NULL, S_CRBOWATK2_5, 0, 0}, // S_CRBOWATK2_4
+ {SPR_CRBW, 7, 2, NULL, S_CRBOWATK2_6, 0, 0}, // S_CRBOWATK2_5
+ {SPR_CRBW, 0, 3, NULL, S_CRBOWATK2_7, 0, 0}, // S_CRBOWATK2_6
+ {SPR_CRBW, 1, 3, NULL, S_CRBOWATK2_8, 0, 0}, // S_CRBOWATK2_7
+ {SPR_CRBW, 2, 4, A_ReFire, S_CRBOW1, 0, 0}, // S_CRBOWATK2_8
+ {SPR_FX03, 32769, 1, NULL, S_CRBOWFX1, 0, 0}, // S_CRBOWFX1
+ {SPR_FX03, 32775, 8, NULL, S_CRBOWFXI1_2, 0, 0}, // S_CRBOWFXI1_1
+ {SPR_FX03, 32776, 8, NULL, S_CRBOWFXI1_3, 0, 0}, // S_CRBOWFXI1_2
+ {SPR_FX03, 32777, 8, NULL, S_NULL, 0, 0}, // S_CRBOWFXI1_3
+ {SPR_FX03, 32769, 1, A_BoltSpark, S_CRBOWFX2, 0, 0}, // S_CRBOWFX2
+ {SPR_FX03, 32768, 1, NULL, S_CRBOWFX3, 0, 0}, // S_CRBOWFX3
+ {SPR_FX03, 32770, 8, NULL, S_CRBOWFXI3_2, 0, 0}, // S_CRBOWFXI3_1
+ {SPR_FX03, 32771, 8, NULL, S_CRBOWFXI3_3, 0, 0}, // S_CRBOWFXI3_2
+ {SPR_FX03, 32772, 8, NULL, S_NULL, 0, 0}, // S_CRBOWFXI3_3
+ {SPR_FX03, 32773, 8, NULL, S_CRBOWFX4_2, 0, 0}, // S_CRBOWFX4_1
+ {SPR_FX03, 32774, 8, NULL, S_NULL, 0, 0}, // S_CRBOWFX4_2
+ {SPR_BLOD, 2, 8, NULL, S_BLOOD2, 0, 0}, // S_BLOOD1
+ {SPR_BLOD, 1, 8, NULL, S_BLOOD3, 0, 0}, // S_BLOOD2
+ {SPR_BLOD, 0, 8, NULL, S_NULL, 0, 0}, // S_BLOOD3
+ {SPR_BLOD, 2, 8, NULL, S_BLOODSPLATTER2, 0, 0}, // S_BLOODSPLATTER1
+ {SPR_BLOD, 1, 8, NULL, S_BLOODSPLATTER3, 0, 0}, // S_BLOODSPLATTER2
+ {SPR_BLOD, 0, 8, NULL, S_NULL, 0, 0}, // S_BLOODSPLATTER3
+ {SPR_BLOD, 0, 6, NULL, S_NULL, 0, 0}, // S_BLOODSPLATTERX
+ {SPR_PLAY, 0, -1, NULL, S_NULL, 0, 0}, // S_PLAY
+ {SPR_PLAY, 0, 4, NULL, S_PLAY_RUN2, 0, 0}, // S_PLAY_RUN1
+ {SPR_PLAY, 1, 4, NULL, S_PLAY_RUN3, 0, 0}, // S_PLAY_RUN2
+ {SPR_PLAY, 2, 4, NULL, S_PLAY_RUN4, 0, 0}, // S_PLAY_RUN3
+ {SPR_PLAY, 3, 4, NULL, S_PLAY_RUN1, 0, 0}, // S_PLAY_RUN4
+ {SPR_PLAY, 4, 12, NULL, S_PLAY, 0, 0}, // S_PLAY_ATK1
+ {SPR_PLAY, 32773, 6, NULL, S_PLAY_ATK1, 0, 0}, // S_PLAY_ATK2
+ {SPR_PLAY, 6, 4, NULL, S_PLAY_PAIN2, 0, 0}, // S_PLAY_PAIN
+ {SPR_PLAY, 6, 4, A_Pain, S_PLAY, 0, 0}, // S_PLAY_PAIN2
+ {SPR_PLAY, 7, 6, NULL, S_PLAY_DIE2, 0, 0}, // S_PLAY_DIE1
+ {SPR_PLAY, 8, 6, A_Scream, S_PLAY_DIE3, 0, 0}, // S_PLAY_DIE2
+ {SPR_PLAY, 9, 6, NULL, S_PLAY_DIE4, 0, 0}, // S_PLAY_DIE3
+ {SPR_PLAY, 10, 6, NULL, S_PLAY_DIE5, 0, 0}, // S_PLAY_DIE4
+ {SPR_PLAY, 11, 6, A_NoBlocking, S_PLAY_DIE6, 0, 0}, // S_PLAY_DIE5
+ {SPR_PLAY, 12, 6, NULL, S_PLAY_DIE7, 0, 0}, // S_PLAY_DIE6
+ {SPR_PLAY, 13, 6, NULL, S_PLAY_DIE8, 0, 0}, // S_PLAY_DIE7
+ {SPR_PLAY, 14, 6, NULL, S_PLAY_DIE9, 0, 0}, // S_PLAY_DIE8
+ {SPR_PLAY, 15, -1, A_AddPlayerCorpse, S_NULL, 0, 0}, // S_PLAY_DIE9
+ {SPR_PLAY, 16, 5, A_Scream, S_PLAY_XDIE2, 0, 0}, // S_PLAY_XDIE1
+ {SPR_PLAY, 17, 5, A_SkullPop, S_PLAY_XDIE3, 0, 0}, // S_PLAY_XDIE2
+ {SPR_PLAY, 18, 5, A_NoBlocking, S_PLAY_XDIE4, 0, 0}, // S_PLAY_XDIE3
+ {SPR_PLAY, 19, 5, NULL, S_PLAY_XDIE5, 0, 0}, // S_PLAY_XDIE4
+ {SPR_PLAY, 20, 5, NULL, S_PLAY_XDIE6, 0, 0}, // S_PLAY_XDIE5
+ {SPR_PLAY, 21, 5, NULL, S_PLAY_XDIE7, 0, 0}, // S_PLAY_XDIE6
+ {SPR_PLAY, 22, 5, NULL, S_PLAY_XDIE8, 0, 0}, // S_PLAY_XDIE7
+ {SPR_PLAY, 23, 5, NULL, S_PLAY_XDIE9, 0, 0}, // S_PLAY_XDIE8
+ {SPR_PLAY, 24, -1, A_AddPlayerCorpse, S_NULL, 0, 0}, // S_PLAY_XDIE9
+ {SPR_FDTH, 32768, 5, A_FlameSnd, S_PLAY_FDTH2, 0, 0}, // S_PLAY_FDTH1
+ {SPR_FDTH, 32769, 4, NULL, S_PLAY_FDTH3, 0, 0}, // S_PLAY_FDTH2
+ {SPR_FDTH, 32770, 5, NULL, S_PLAY_FDTH4, 0, 0}, // S_PLAY_FDTH3
+ {SPR_FDTH, 32771, 4, A_Scream, S_PLAY_FDTH5, 0, 0}, // S_PLAY_FDTH4
+ {SPR_FDTH, 32772, 5, NULL, S_PLAY_FDTH6, 0, 0}, // S_PLAY_FDTH5
+ {SPR_FDTH, 32773, 4, NULL, S_PLAY_FDTH7, 0, 0}, // S_PLAY_FDTH6
+ {SPR_FDTH, 32774, 5, A_FlameSnd, S_PLAY_FDTH8, 0, 0}, // S_PLAY_FDTH7
+ {SPR_FDTH, 32775, 4, NULL, S_PLAY_FDTH9, 0, 0}, // S_PLAY_FDTH8
+ {SPR_FDTH, 32776, 5, NULL, S_PLAY_FDTH10, 0, 0}, // S_PLAY_FDTH9
+ {SPR_FDTH, 32777, 4, NULL, S_PLAY_FDTH11, 0, 0}, // S_PLAY_FDTH10
+ {SPR_FDTH, 32778, 5, NULL, S_PLAY_FDTH12, 0, 0}, // S_PLAY_FDTH11
+ {SPR_FDTH, 32779, 4, NULL, S_PLAY_FDTH13, 0, 0}, // S_PLAY_FDTH12
+ {SPR_FDTH, 32780, 5, NULL, S_PLAY_FDTH14, 0, 0}, // S_PLAY_FDTH13
+ {SPR_FDTH, 32781, 4, NULL, S_PLAY_FDTH15, 0, 0}, // S_PLAY_FDTH14
+ {SPR_FDTH, 32782, 5, A_NoBlocking, S_PLAY_FDTH16, 0, 0}, // S_PLAY_FDTH15
+ {SPR_FDTH, 32783, 4, NULL, S_PLAY_FDTH17, 0, 0}, // S_PLAY_FDTH16
+ {SPR_FDTH, 32784, 5, NULL, S_PLAY_FDTH18, 0, 0}, // S_PLAY_FDTH17
+ {SPR_FDTH, 32785, 4, NULL, S_PLAY_FDTH19, 0, 0}, // S_PLAY_FDTH18
+ {SPR_ACLO, 4, 35, A_CheckBurnGone, S_PLAY_FDTH19, 0, 0}, // S_PLAY_FDTH19
+ {SPR_ACLO, 4, 8, NULL, S_NULL, 0, 0}, // S_PLAY_FDTH20
+ {SPR_BSKL, 0, 5, A_CheckSkullFloor, S_BLOODYSKULL2, 0, 0}, // S_BLOODYSKULL1
+ {SPR_BSKL, 1, 5, A_CheckSkullFloor, S_BLOODYSKULL3, 0, 0}, // S_BLOODYSKULL2
+ {SPR_BSKL, 2, 5, A_CheckSkullFloor, S_BLOODYSKULL4, 0, 0}, // S_BLOODYSKULL3
+ {SPR_BSKL, 3, 5, A_CheckSkullFloor, S_BLOODYSKULL5, 0, 0}, // S_BLOODYSKULL4
+ {SPR_BSKL, 4, 5, A_CheckSkullFloor, S_BLOODYSKULL1, 0, 0}, // S_BLOODYSKULL5
+ {SPR_BSKL, 5, 16, A_CheckSkullDone, S_BLOODYSKULLX1, 0, 0}, // S_BLOODYSKULLX1
+ {SPR_BSKL, 5, 1050, NULL, S_NULL, 0, 0}, // S_BLOODYSKULLX2
+ {SPR_CHKN, 0, -1, NULL, S_NULL, 0, 0}, // S_CHICPLAY
+ {SPR_CHKN, 0, 3, NULL, S_CHICPLAY_RUN2, 0, 0}, // S_CHICPLAY_RUN1
+ {SPR_CHKN, 1, 3, NULL, S_CHICPLAY_RUN3, 0, 0}, // S_CHICPLAY_RUN2
+ {SPR_CHKN, 0, 3, NULL, S_CHICPLAY_RUN4, 0, 0}, // S_CHICPLAY_RUN3
+ {SPR_CHKN, 1, 3, NULL, S_CHICPLAY_RUN1, 0, 0}, // S_CHICPLAY_RUN4
+ {SPR_CHKN, 2, 12, NULL, S_CHICPLAY, 0, 0}, // S_CHICPLAY_ATK1
+ {SPR_CHKN, 3, 4, A_Feathers, S_CHICPLAY_PAIN2, 0, 0}, // S_CHICPLAY_PAIN
+ {SPR_CHKN, 2, 4, A_Pain, S_CHICPLAY, 0, 0}, // S_CHICPLAY_PAIN2
+ {SPR_CHKN, 0, 10, A_ChicLook, S_CHICKEN_LOOK2, 0, 0}, // S_CHICKEN_LOOK1
+ {SPR_CHKN, 1, 10, A_ChicLook, S_CHICKEN_LOOK1, 0, 0}, // S_CHICKEN_LOOK2
+ {SPR_CHKN, 0, 3, A_ChicChase, S_CHICKEN_WALK2, 0, 0}, // S_CHICKEN_WALK1
+ {SPR_CHKN, 1, 3, A_ChicChase, S_CHICKEN_WALK1, 0, 0}, // S_CHICKEN_WALK2
+ {SPR_CHKN, 3, 5, A_Feathers, S_CHICKEN_PAIN2, 0, 0}, // S_CHICKEN_PAIN1
+ {SPR_CHKN, 2, 5, A_ChicPain, S_CHICKEN_WALK1, 0, 0}, // S_CHICKEN_PAIN2
+ {SPR_CHKN, 0, 8, A_FaceTarget, S_CHICKEN_ATK2, 0, 0}, // S_CHICKEN_ATK1
+ {SPR_CHKN, 2, 10, A_ChicAttack, S_CHICKEN_WALK1, 0, 0}, // S_CHICKEN_ATK2
+ {SPR_CHKN, 4, 6, A_Scream, S_CHICKEN_DIE2, 0, 0}, // S_CHICKEN_DIE1
+ {SPR_CHKN, 5, 6, A_Feathers, S_CHICKEN_DIE3, 0, 0}, // S_CHICKEN_DIE2
+ {SPR_CHKN, 6, 6, NULL, S_CHICKEN_DIE4, 0, 0}, // S_CHICKEN_DIE3
+ {SPR_CHKN, 7, 6, A_NoBlocking, S_CHICKEN_DIE5, 0, 0}, // S_CHICKEN_DIE4
+ {SPR_CHKN, 8, 6, NULL, S_CHICKEN_DIE6, 0, 0}, // S_CHICKEN_DIE5
+ {SPR_CHKN, 9, 6, NULL, S_CHICKEN_DIE7, 0, 0}, // S_CHICKEN_DIE6
+ {SPR_CHKN, 10, 6, NULL, S_CHICKEN_DIE8, 0, 0}, // S_CHICKEN_DIE7
+ {SPR_CHKN, 11, -1, NULL, S_NULL, 0, 0}, // S_CHICKEN_DIE8
+ {SPR_CHKN, 12, 3, NULL, S_FEATHER2, 0, 0}, // S_FEATHER1
+ {SPR_CHKN, 13, 3, NULL, S_FEATHER3, 0, 0}, // S_FEATHER2
+ {SPR_CHKN, 14, 3, NULL, S_FEATHER4, 0, 0}, // S_FEATHER3
+ {SPR_CHKN, 15, 3, NULL, S_FEATHER5, 0, 0}, // S_FEATHER4
+ {SPR_CHKN, 16, 3, NULL, S_FEATHER6, 0, 0}, // S_FEATHER5
+ {SPR_CHKN, 15, 3, NULL, S_FEATHER7, 0, 0}, // S_FEATHER6
+ {SPR_CHKN, 14, 3, NULL, S_FEATHER8, 0, 0}, // S_FEATHER7
+ {SPR_CHKN, 13, 3, NULL, S_FEATHER1, 0, 0}, // S_FEATHER8
+ {SPR_CHKN, 13, 6, NULL, S_NULL, 0, 0}, // S_FEATHERX
+ {SPR_MUMM, 0, 10, A_Look, S_MUMMY_LOOK2, 0, 0}, // S_MUMMY_LOOK1
+ {SPR_MUMM, 1, 10, A_Look, S_MUMMY_LOOK1, 0, 0}, // S_MUMMY_LOOK2
+ {SPR_MUMM, 0, 4, A_Chase, S_MUMMY_WALK2, 0, 0}, // S_MUMMY_WALK1
+ {SPR_MUMM, 1, 4, A_Chase, S_MUMMY_WALK3, 0, 0}, // S_MUMMY_WALK2
+ {SPR_MUMM, 2, 4, A_Chase, S_MUMMY_WALK4, 0, 0}, // S_MUMMY_WALK3
+ {SPR_MUMM, 3, 4, A_Chase, S_MUMMY_WALK1, 0, 0}, // S_MUMMY_WALK4
+ {SPR_MUMM, 4, 6, A_FaceTarget, S_MUMMY_ATK2, 0, 0}, // S_MUMMY_ATK1
+ {SPR_MUMM, 5, 6, A_MummyAttack, S_MUMMY_ATK3, 0, 0}, // S_MUMMY_ATK2
+ {SPR_MUMM, 6, 6, A_FaceTarget, S_MUMMY_WALK1, 0, 0}, // S_MUMMY_ATK3
+ {SPR_MUMM, 23, 5, A_FaceTarget, S_MUMMYL_ATK2, 0, 0}, // S_MUMMYL_ATK1
+ {SPR_MUMM, 32792, 5, A_FaceTarget, S_MUMMYL_ATK3, 0, 0}, // S_MUMMYL_ATK2
+ {SPR_MUMM, 23, 5, A_FaceTarget, S_MUMMYL_ATK4, 0, 0}, // S_MUMMYL_ATK3
+ {SPR_MUMM, 32792, 5, A_FaceTarget, S_MUMMYL_ATK5, 0, 0}, // S_MUMMYL_ATK4
+ {SPR_MUMM, 23, 5, A_FaceTarget, S_MUMMYL_ATK6, 0, 0}, // S_MUMMYL_ATK5
+ {SPR_MUMM, 32792, 15, A_MummyAttack2, S_MUMMY_WALK1, 0, 0}, // S_MUMMYL_ATK6
+ {SPR_MUMM, 7, 4, NULL, S_MUMMY_PAIN2, 0, 0}, // S_MUMMY_PAIN1
+ {SPR_MUMM, 7, 4, A_Pain, S_MUMMY_WALK1, 0, 0}, // S_MUMMY_PAIN2
+ {SPR_MUMM, 8, 5, NULL, S_MUMMY_DIE2, 0, 0}, // S_MUMMY_DIE1
+ {SPR_MUMM, 9, 5, A_Scream, S_MUMMY_DIE3, 0, 0}, // S_MUMMY_DIE2
+ {SPR_MUMM, 10, 5, A_MummySoul, S_MUMMY_DIE4, 0, 0}, // S_MUMMY_DIE3
+ {SPR_MUMM, 11, 5, NULL, S_MUMMY_DIE5, 0, 0}, // S_MUMMY_DIE4
+ {SPR_MUMM, 12, 5, A_NoBlocking, S_MUMMY_DIE6, 0, 0}, // S_MUMMY_DIE5
+ {SPR_MUMM, 13, 5, NULL, S_MUMMY_DIE7, 0, 0}, // S_MUMMY_DIE6
+ {SPR_MUMM, 14, 5, NULL, S_MUMMY_DIE8, 0, 0}, // S_MUMMY_DIE7
+ {SPR_MUMM, 15, -1, NULL, S_NULL, 0, 0}, // S_MUMMY_DIE8
+ {SPR_MUMM, 16, 5, NULL, S_MUMMY_SOUL2, 0, 0}, // S_MUMMY_SOUL1
+ {SPR_MUMM, 17, 5, NULL, S_MUMMY_SOUL3, 0, 0}, // S_MUMMY_SOUL2
+ {SPR_MUMM, 18, 5, NULL, S_MUMMY_SOUL4, 0, 0}, // S_MUMMY_SOUL3
+ {SPR_MUMM, 19, 9, NULL, S_MUMMY_SOUL5, 0, 0}, // S_MUMMY_SOUL4
+ {SPR_MUMM, 20, 5, NULL, S_MUMMY_SOUL6, 0, 0}, // S_MUMMY_SOUL5
+ {SPR_MUMM, 21, 5, NULL, S_MUMMY_SOUL7, 0, 0}, // S_MUMMY_SOUL6
+ {SPR_MUMM, 22, 5, NULL, S_NULL, 0, 0}, // S_MUMMY_SOUL7
+ {SPR_FX15, 32768, 5, A_ContMobjSound, S_MUMMYFX1_2, 0, 0}, // S_MUMMYFX1_1
+ {SPR_FX15, 32769, 5, A_MummyFX1Seek, S_MUMMYFX1_3, 0, 0}, // S_MUMMYFX1_2
+ {SPR_FX15, 32770, 5, NULL, S_MUMMYFX1_4, 0, 0}, // S_MUMMYFX1_3
+ {SPR_FX15, 32769, 5, A_MummyFX1Seek, S_MUMMYFX1_1, 0, 0}, // S_MUMMYFX1_4
+ {SPR_FX15, 32771, 5, NULL, S_MUMMYFXI1_2, 0, 0}, // S_MUMMYFXI1_1
+ {SPR_FX15, 32772, 5, NULL, S_MUMMYFXI1_3, 0, 0}, // S_MUMMYFXI1_2
+ {SPR_FX15, 32773, 5, NULL, S_MUMMYFXI1_4, 0, 0}, // S_MUMMYFXI1_3
+ {SPR_FX15, 32774, 5, NULL, S_NULL, 0, 0}, // S_MUMMYFXI1_4
+ {SPR_BEAS, 0, 10, A_Look, S_BEAST_LOOK2, 0, 0}, // S_BEAST_LOOK1
+ {SPR_BEAS, 1, 10, A_Look, S_BEAST_LOOK1, 0, 0}, // S_BEAST_LOOK2
+ {SPR_BEAS, 0, 3, A_Chase, S_BEAST_WALK2, 0, 0}, // S_BEAST_WALK1
+ {SPR_BEAS, 1, 3, A_Chase, S_BEAST_WALK3, 0, 0}, // S_BEAST_WALK2
+ {SPR_BEAS, 2, 3, A_Chase, S_BEAST_WALK4, 0, 0}, // S_BEAST_WALK3
+ {SPR_BEAS, 3, 3, A_Chase, S_BEAST_WALK5, 0, 0}, // S_BEAST_WALK4
+ {SPR_BEAS, 4, 3, A_Chase, S_BEAST_WALK6, 0, 0}, // S_BEAST_WALK5
+ {SPR_BEAS, 5, 3, A_Chase, S_BEAST_WALK1, 0, 0}, // S_BEAST_WALK6
+ {SPR_BEAS, 7, 10, A_FaceTarget, S_BEAST_ATK2, 0, 0}, // S_BEAST_ATK1
+ {SPR_BEAS, 8, 10, A_BeastAttack, S_BEAST_WALK1, 0, 0}, // S_BEAST_ATK2
+ {SPR_BEAS, 6, 3, NULL, S_BEAST_PAIN2, 0, 0}, // S_BEAST_PAIN1
+ {SPR_BEAS, 6, 3, A_Pain, S_BEAST_WALK1, 0, 0}, // S_BEAST_PAIN2
+ {SPR_BEAS, 17, 6, NULL, S_BEAST_DIE2, 0, 0}, // S_BEAST_DIE1
+ {SPR_BEAS, 18, 6, A_Scream, S_BEAST_DIE3, 0, 0}, // S_BEAST_DIE2
+ {SPR_BEAS, 19, 6, NULL, S_BEAST_DIE4, 0, 0}, // S_BEAST_DIE3
+ {SPR_BEAS, 20, 6, NULL, S_BEAST_DIE5, 0, 0}, // S_BEAST_DIE4
+ {SPR_BEAS, 21, 6, NULL, S_BEAST_DIE6, 0, 0}, // S_BEAST_DIE5
+ {SPR_BEAS, 22, 6, A_NoBlocking, S_BEAST_DIE7, 0, 0}, // S_BEAST_DIE6
+ {SPR_BEAS, 23, 6, NULL, S_BEAST_DIE8, 0, 0}, // S_BEAST_DIE7
+ {SPR_BEAS, 24, 6, NULL, S_BEAST_DIE9, 0, 0}, // S_BEAST_DIE8
+ {SPR_BEAS, 25, -1, NULL, S_NULL, 0, 0}, // S_BEAST_DIE9
+ {SPR_BEAS, 9, 5, NULL, S_BEAST_XDIE2, 0, 0}, // S_BEAST_XDIE1
+ {SPR_BEAS, 10, 6, A_Scream, S_BEAST_XDIE3, 0, 0}, // S_BEAST_XDIE2
+ {SPR_BEAS, 11, 5, NULL, S_BEAST_XDIE4, 0, 0}, // S_BEAST_XDIE3
+ {SPR_BEAS, 12, 6, NULL, S_BEAST_XDIE5, 0, 0}, // S_BEAST_XDIE4
+ {SPR_BEAS, 13, 5, NULL, S_BEAST_XDIE6, 0, 0}, // S_BEAST_XDIE5
+ {SPR_BEAS, 14, 6, A_NoBlocking, S_BEAST_XDIE7, 0, 0}, // S_BEAST_XDIE6
+ {SPR_BEAS, 15, 5, NULL, S_BEAST_XDIE8, 0, 0}, // S_BEAST_XDIE7
+ {SPR_BEAS, 16, -1, NULL, S_NULL, 0, 0}, // S_BEAST_XDIE8
+ {SPR_FRB1, 0, 2, A_BeastPuff, S_BEASTBALL2, 0, 0}, // S_BEASTBALL1
+ {SPR_FRB1, 0, 2, A_BeastPuff, S_BEASTBALL3, 0, 0}, // S_BEASTBALL2
+ {SPR_FRB1, 1, 2, A_BeastPuff, S_BEASTBALL4, 0, 0}, // S_BEASTBALL3
+ {SPR_FRB1, 1, 2, A_BeastPuff, S_BEASTBALL5, 0, 0}, // S_BEASTBALL4
+ {SPR_FRB1, 2, 2, A_BeastPuff, S_BEASTBALL6, 0, 0}, // S_BEASTBALL5
+ {SPR_FRB1, 2, 2, A_BeastPuff, S_BEASTBALL1, 0, 0}, // S_BEASTBALL6
+ {SPR_FRB1, 3, 4, NULL, S_BEASTBALLX2, 0, 0}, // S_BEASTBALLX1
+ {SPR_FRB1, 4, 4, NULL, S_BEASTBALLX3, 0, 0}, // S_BEASTBALLX2
+ {SPR_FRB1, 5, 4, NULL, S_BEASTBALLX4, 0, 0}, // S_BEASTBALLX3
+ {SPR_FRB1, 6, 4, NULL, S_BEASTBALLX5, 0, 0}, // S_BEASTBALLX4
+ {SPR_FRB1, 7, 4, NULL, S_NULL, 0, 0}, // S_BEASTBALLX5
+ {SPR_FRB1, 0, 4, NULL, S_BURNBALL2, 0, 0}, // S_BURNBALL1
+ {SPR_FRB1, 1, 4, NULL, S_BURNBALL3, 0, 0}, // S_BURNBALL2
+ {SPR_FRB1, 2, 4, NULL, S_BURNBALL4, 0, 0}, // S_BURNBALL3
+ {SPR_FRB1, 3, 4, NULL, S_BURNBALL5, 0, 0}, // S_BURNBALL4
+ {SPR_FRB1, 4, 4, NULL, S_BURNBALL6, 0, 0}, // S_BURNBALL5
+ {SPR_FRB1, 5, 4, NULL, S_BURNBALL7, 0, 0}, // S_BURNBALL6
+ {SPR_FRB1, 6, 4, NULL, S_BURNBALL8, 0, 0}, // S_BURNBALL7
+ {SPR_FRB1, 7, 4, NULL, S_NULL, 0, 0}, // S_BURNBALL8
+ {SPR_FRB1, 32768, 4, NULL, S_BURNBALLFB2, 0, 0}, // S_BURNBALLFB1
+ {SPR_FRB1, 32769, 4, NULL, S_BURNBALLFB3, 0, 0}, // S_BURNBALLFB2
+ {SPR_FRB1, 32770, 4, NULL, S_BURNBALLFB4, 0, 0}, // S_BURNBALLFB3
+ {SPR_FRB1, 32771, 4, NULL, S_BURNBALLFB5, 0, 0}, // S_BURNBALLFB4
+ {SPR_FRB1, 32772, 4, NULL, S_BURNBALLFB6, 0, 0}, // S_BURNBALLFB5
+ {SPR_FRB1, 32773, 4, NULL, S_BURNBALLFB7, 0, 0}, // S_BURNBALLFB6
+ {SPR_FRB1, 32774, 4, NULL, S_BURNBALLFB8, 0, 0}, // S_BURNBALLFB7
+ {SPR_FRB1, 32775, 4, NULL, S_NULL, 0, 0}, // S_BURNBALLFB8
+ {SPR_FRB1, 3, 4, NULL, S_PUFFY2, 0, 0}, // S_PUFFY1
+ {SPR_FRB1, 4, 4, NULL, S_PUFFY3, 0, 0}, // S_PUFFY2
+ {SPR_FRB1, 5, 4, NULL, S_PUFFY4, 0, 0}, // S_PUFFY3
+ {SPR_FRB1, 6, 4, NULL, S_PUFFY5, 0, 0}, // S_PUFFY4
+ {SPR_FRB1, 7, 4, NULL, S_NULL, 0, 0}, // S_PUFFY5
+ {SPR_SNKE, 0, 10, A_Look, S_SNAKE_LOOK2, 0, 0}, // S_SNAKE_LOOK1
+ {SPR_SNKE, 1, 10, A_Look, S_SNAKE_LOOK1, 0, 0}, // S_SNAKE_LOOK2
+ {SPR_SNKE, 0, 4, A_Chase, S_SNAKE_WALK2, 0, 0}, // S_SNAKE_WALK1
+ {SPR_SNKE, 1, 4, A_Chase, S_SNAKE_WALK3, 0, 0}, // S_SNAKE_WALK2
+ {SPR_SNKE, 2, 4, A_Chase, S_SNAKE_WALK4, 0, 0}, // S_SNAKE_WALK3
+ {SPR_SNKE, 3, 4, A_Chase, S_SNAKE_WALK1, 0, 0}, // S_SNAKE_WALK4
+ {SPR_SNKE, 5, 5, A_FaceTarget, S_SNAKE_ATK2, 0, 0}, // S_SNAKE_ATK1
+ {SPR_SNKE, 5, 5, A_FaceTarget, S_SNAKE_ATK3, 0, 0}, // S_SNAKE_ATK2
+ {SPR_SNKE, 5, 4, A_SnakeAttack, S_SNAKE_ATK4, 0, 0}, // S_SNAKE_ATK3
+ {SPR_SNKE, 5, 4, A_SnakeAttack, S_SNAKE_ATK5, 0, 0}, // S_SNAKE_ATK4
+ {SPR_SNKE, 5, 4, A_SnakeAttack, S_SNAKE_ATK6, 0, 0}, // S_SNAKE_ATK5
+ {SPR_SNKE, 5, 5, A_FaceTarget, S_SNAKE_ATK7, 0, 0}, // S_SNAKE_ATK6
+ {SPR_SNKE, 5, 5, A_FaceTarget, S_SNAKE_ATK8, 0, 0}, // S_SNAKE_ATK7
+ {SPR_SNKE, 5, 5, A_FaceTarget, S_SNAKE_ATK9, 0, 0}, // S_SNAKE_ATK8
+ {SPR_SNKE, 5, 4, A_SnakeAttack2, S_SNAKE_WALK1, 0, 0}, // S_SNAKE_ATK9
+ {SPR_SNKE, 4, 3, NULL, S_SNAKE_PAIN2, 0, 0}, // S_SNAKE_PAIN1
+ {SPR_SNKE, 4, 3, A_Pain, S_SNAKE_WALK1, 0, 0}, // S_SNAKE_PAIN2
+ {SPR_SNKE, 6, 5, NULL, S_SNAKE_DIE2, 0, 0}, // S_SNAKE_DIE1
+ {SPR_SNKE, 7, 5, A_Scream, S_SNAKE_DIE3, 0, 0}, // S_SNAKE_DIE2
+ {SPR_SNKE, 8, 5, NULL, S_SNAKE_DIE4, 0, 0}, // S_SNAKE_DIE3
+ {SPR_SNKE, 9, 5, NULL, S_SNAKE_DIE5, 0, 0}, // S_SNAKE_DIE4
+ {SPR_SNKE, 10, 5, NULL, S_SNAKE_DIE6, 0, 0}, // S_SNAKE_DIE5
+ {SPR_SNKE, 11, 5, NULL, S_SNAKE_DIE7, 0, 0}, // S_SNAKE_DIE6
+ {SPR_SNKE, 12, 5, A_NoBlocking, S_SNAKE_DIE8, 0, 0}, // S_SNAKE_DIE7
+ {SPR_SNKE, 13, 5, NULL, S_SNAKE_DIE9, 0, 0}, // S_SNAKE_DIE8
+ {SPR_SNKE, 14, 5, NULL, S_SNAKE_DIE10, 0, 0}, // S_SNAKE_DIE9
+ {SPR_SNKE, 15, -1, NULL, S_NULL, 0, 0}, // S_SNAKE_DIE10
+ {SPR_SNFX, 32768, 5, NULL, S_SNAKEPRO_A2, 0, 0}, // S_SNAKEPRO_A1
+ {SPR_SNFX, 32769, 5, NULL, S_SNAKEPRO_A3, 0, 0}, // S_SNAKEPRO_A2
+ {SPR_SNFX, 32770, 5, NULL, S_SNAKEPRO_A4, 0, 0}, // S_SNAKEPRO_A3
+ {SPR_SNFX, 32771, 5, NULL, S_SNAKEPRO_A1, 0, 0}, // S_SNAKEPRO_A4
+ {SPR_SNFX, 32772, 5, NULL, S_SNAKEPRO_AX2, 0, 0}, // S_SNAKEPRO_AX1
+ {SPR_SNFX, 32773, 5, NULL, S_SNAKEPRO_AX3, 0, 0}, // S_SNAKEPRO_AX2
+ {SPR_SNFX, 32774, 4, NULL, S_SNAKEPRO_AX4, 0, 0}, // S_SNAKEPRO_AX3
+ {SPR_SNFX, 32775, 3, NULL, S_SNAKEPRO_AX5, 0, 0}, // S_SNAKEPRO_AX4
+ {SPR_SNFX, 32776, 3, NULL, S_NULL, 0, 0}, // S_SNAKEPRO_AX5
+ {SPR_SNFX, 32777, 6, NULL, S_SNAKEPRO_B2, 0, 0}, // S_SNAKEPRO_B1
+ {SPR_SNFX, 32778, 6, NULL, S_SNAKEPRO_B1, 0, 0}, // S_SNAKEPRO_B2
+ {SPR_SNFX, 32779, 5, NULL, S_SNAKEPRO_BX2, 0, 0}, // S_SNAKEPRO_BX1
+ {SPR_SNFX, 32780, 5, NULL, S_SNAKEPRO_BX3, 0, 0}, // S_SNAKEPRO_BX2
+ {SPR_SNFX, 32781, 4, NULL, S_SNAKEPRO_BX4, 0, 0}, // S_SNAKEPRO_BX3
+ {SPR_SNFX, 32782, 3, NULL, S_NULL, 0, 0}, // S_SNAKEPRO_BX4
+ {SPR_HEAD, 0, 10, A_Look, S_HEAD_LOOK, 0, 0}, // S_HEAD_LOOK
+ {SPR_HEAD, 0, 4, A_Chase, S_HEAD_FLOAT, 0, 0}, // S_HEAD_FLOAT
+ {SPR_HEAD, 0, 5, A_FaceTarget, S_HEAD_ATK2, 0, 0}, // S_HEAD_ATK1
+ {SPR_HEAD, 1, 20, A_HeadAttack, S_HEAD_FLOAT, 0, 0}, // S_HEAD_ATK2
+ {SPR_HEAD, 0, 4, NULL, S_HEAD_PAIN2, 0, 0}, // S_HEAD_PAIN1
+ {SPR_HEAD, 0, 4, A_Pain, S_HEAD_FLOAT, 0, 0}, // S_HEAD_PAIN2
+ {SPR_HEAD, 2, 7, NULL, S_HEAD_DIE2, 0, 0}, // S_HEAD_DIE1
+ {SPR_HEAD, 3, 7, A_Scream, S_HEAD_DIE3, 0, 0}, // S_HEAD_DIE2
+ {SPR_HEAD, 4, 7, NULL, S_HEAD_DIE4, 0, 0}, // S_HEAD_DIE3
+ {SPR_HEAD, 5, 7, NULL, S_HEAD_DIE5, 0, 0}, // S_HEAD_DIE4
+ {SPR_HEAD, 6, 7, A_NoBlocking, S_HEAD_DIE6, 0, 0}, // S_HEAD_DIE5
+ {SPR_HEAD, 7, 7, NULL, S_HEAD_DIE7, 0, 0}, // S_HEAD_DIE6
+ {SPR_HEAD, 8, -1, A_BossDeath, S_NULL, 0, 0}, // S_HEAD_DIE7
+ {SPR_FX05, 0, 6, NULL, S_HEADFX1_2, 0, 0}, // S_HEADFX1_1
+ {SPR_FX05, 1, 6, NULL, S_HEADFX1_3, 0, 0}, // S_HEADFX1_2
+ {SPR_FX05, 2, 6, NULL, S_HEADFX1_1, 0, 0}, // S_HEADFX1_3
+ {SPR_FX05, 3, 5, A_HeadIceImpact, S_HEADFXI1_2, 0, 0}, // S_HEADFXI1_1
+ {SPR_FX05, 4, 5, NULL, S_HEADFXI1_3, 0, 0}, // S_HEADFXI1_2
+ {SPR_FX05, 5, 5, NULL, S_HEADFXI1_4, 0, 0}, // S_HEADFXI1_3
+ {SPR_FX05, 6, 5, NULL, S_NULL, 0, 0}, // S_HEADFXI1_4
+ {SPR_FX05, 7, 6, NULL, S_HEADFX2_2, 0, 0}, // S_HEADFX2_1
+ {SPR_FX05, 8, 6, NULL, S_HEADFX2_3, 0, 0}, // S_HEADFX2_2
+ {SPR_FX05, 9, 6, NULL, S_HEADFX2_1, 0, 0}, // S_HEADFX2_3
+ {SPR_FX05, 3, 5, NULL, S_HEADFXI2_2, 0, 0}, // S_HEADFXI2_1
+ {SPR_FX05, 4, 5, NULL, S_HEADFXI2_3, 0, 0}, // S_HEADFXI2_2
+ {SPR_FX05, 5, 5, NULL, S_HEADFXI2_4, 0, 0}, // S_HEADFXI2_3
+ {SPR_FX05, 6, 5, NULL, S_NULL, 0, 0}, // S_HEADFXI2_4
+ {SPR_FX06, 0, 4, A_HeadFireGrow, S_HEADFX3_2, 0, 0}, // S_HEADFX3_1
+ {SPR_FX06, 1, 4, A_HeadFireGrow, S_HEADFX3_3, 0, 0}, // S_HEADFX3_2
+ {SPR_FX06, 2, 4, A_HeadFireGrow, S_HEADFX3_1, 0, 0}, // S_HEADFX3_3
+ {SPR_FX06, 0, 5, NULL, S_HEADFX3_5, 0, 0}, // S_HEADFX3_4
+ {SPR_FX06, 1, 5, NULL, S_HEADFX3_6, 0, 0}, // S_HEADFX3_5
+ {SPR_FX06, 2, 5, NULL, S_HEADFX3_4, 0, 0}, // S_HEADFX3_6
+ {SPR_FX06, 3, 5, NULL, S_HEADFXI3_2, 0, 0}, // S_HEADFXI3_1
+ {SPR_FX06, 4, 5, NULL, S_HEADFXI3_3, 0, 0}, // S_HEADFXI3_2
+ {SPR_FX06, 5, 5, NULL, S_HEADFXI3_4, 0, 0}, // S_HEADFXI3_3
+ {SPR_FX06, 6, 5, NULL, S_NULL, 0, 0}, // S_HEADFXI3_4
+ {SPR_FX07, 3, 3, NULL, S_HEADFX4_2, 0, 0}, // S_HEADFX4_1
+ {SPR_FX07, 4, 3, NULL, S_HEADFX4_3, 0, 0}, // S_HEADFX4_2
+ {SPR_FX07, 5, 3, NULL, S_HEADFX4_4, 0, 0}, // S_HEADFX4_3
+ {SPR_FX07, 6, 3, NULL, S_HEADFX4_5, 0, 0}, // S_HEADFX4_4
+ {SPR_FX07, 0, 3, A_WhirlwindSeek, S_HEADFX4_6, 0, 0}, // S_HEADFX4_5
+ {SPR_FX07, 1, 3, A_WhirlwindSeek, S_HEADFX4_7, 0, 0}, // S_HEADFX4_6
+ {SPR_FX07, 2, 3, A_WhirlwindSeek, S_HEADFX4_5, 0, 0}, // S_HEADFX4_7
+ {SPR_FX07, 6, 4, NULL, S_HEADFXI4_2, 0, 0}, // S_HEADFXI4_1
+ {SPR_FX07, 5, 4, NULL, S_HEADFXI4_3, 0, 0}, // S_HEADFXI4_2
+ {SPR_FX07, 4, 4, NULL, S_HEADFXI4_4, 0, 0}, // S_HEADFXI4_3
+ {SPR_FX07, 3, 4, NULL, S_NULL, 0, 0}, // S_HEADFXI4_4
+ {SPR_CLNK, 0, 10, A_Look, S_CLINK_LOOK2, 0, 0}, // S_CLINK_LOOK1
+ {SPR_CLNK, 1, 10, A_Look, S_CLINK_LOOK1, 0, 0}, // S_CLINK_LOOK2
+ {SPR_CLNK, 0, 3, A_Chase, S_CLINK_WALK2, 0, 0}, // S_CLINK_WALK1
+ {SPR_CLNK, 1, 3, A_Chase, S_CLINK_WALK3, 0, 0}, // S_CLINK_WALK2
+ {SPR_CLNK, 2, 3, A_Chase, S_CLINK_WALK4, 0, 0}, // S_CLINK_WALK3
+ {SPR_CLNK, 3, 3, A_Chase, S_CLINK_WALK1, 0, 0}, // S_CLINK_WALK4
+ {SPR_CLNK, 4, 5, A_FaceTarget, S_CLINK_ATK2, 0, 0}, // S_CLINK_ATK1
+ {SPR_CLNK, 5, 4, A_FaceTarget, S_CLINK_ATK3, 0, 0}, // S_CLINK_ATK2
+ {SPR_CLNK, 6, 7, A_ClinkAttack, S_CLINK_WALK1, 0, 0}, // S_CLINK_ATK3
+ {SPR_CLNK, 7, 3, NULL, S_CLINK_PAIN2, 0, 0}, // S_CLINK_PAIN1
+ {SPR_CLNK, 7, 3, A_Pain, S_CLINK_WALK1, 0, 0}, // S_CLINK_PAIN2
+ {SPR_CLNK, 8, 6, NULL, S_CLINK_DIE2, 0, 0}, // S_CLINK_DIE1
+ {SPR_CLNK, 9, 6, NULL, S_CLINK_DIE3, 0, 0}, // S_CLINK_DIE2
+ {SPR_CLNK, 10, 5, A_Scream, S_CLINK_DIE4, 0, 0}, // S_CLINK_DIE3
+ {SPR_CLNK, 11, 5, A_NoBlocking, S_CLINK_DIE5, 0, 0}, // S_CLINK_DIE4
+ {SPR_CLNK, 12, 5, NULL, S_CLINK_DIE6, 0, 0}, // S_CLINK_DIE5
+ {SPR_CLNK, 13, 5, NULL, S_CLINK_DIE7, 0, 0}, // S_CLINK_DIE6
+ {SPR_CLNK, 14, -1, NULL, S_NULL, 0, 0}, // S_CLINK_DIE7
+ {SPR_WZRD, 0, 10, A_Look, S_WIZARD_LOOK2, 0, 0}, // S_WIZARD_LOOK1
+ {SPR_WZRD, 1, 10, A_Look, S_WIZARD_LOOK1, 0, 0}, // S_WIZARD_LOOK2
+ {SPR_WZRD, 0, 3, A_Chase, S_WIZARD_WALK2, 0, 0}, // S_WIZARD_WALK1
+ {SPR_WZRD, 0, 4, A_Chase, S_WIZARD_WALK3, 0, 0}, // S_WIZARD_WALK2
+ {SPR_WZRD, 0, 3, A_Chase, S_WIZARD_WALK4, 0, 0}, // S_WIZARD_WALK3
+ {SPR_WZRD, 0, 4, A_Chase, S_WIZARD_WALK5, 0, 0}, // S_WIZARD_WALK4
+ {SPR_WZRD, 1, 3, A_Chase, S_WIZARD_WALK6, 0, 0}, // S_WIZARD_WALK5
+ {SPR_WZRD, 1, 4, A_Chase, S_WIZARD_WALK7, 0, 0}, // S_WIZARD_WALK6
+ {SPR_WZRD, 1, 3, A_Chase, S_WIZARD_WALK8, 0, 0}, // S_WIZARD_WALK7
+ {SPR_WZRD, 1, 4, A_Chase, S_WIZARD_WALK1, 0, 0}, // S_WIZARD_WALK8
+ {SPR_WZRD, 2, 4, A_WizAtk1, S_WIZARD_ATK2, 0, 0}, // S_WIZARD_ATK1
+ {SPR_WZRD, 2, 4, A_WizAtk2, S_WIZARD_ATK3, 0, 0}, // S_WIZARD_ATK2
+ {SPR_WZRD, 2, 4, A_WizAtk1, S_WIZARD_ATK4, 0, 0}, // S_WIZARD_ATK3
+ {SPR_WZRD, 2, 4, A_WizAtk2, S_WIZARD_ATK5, 0, 0}, // S_WIZARD_ATK4
+ {SPR_WZRD, 2, 4, A_WizAtk1, S_WIZARD_ATK6, 0, 0}, // S_WIZARD_ATK5
+ {SPR_WZRD, 2, 4, A_WizAtk2, S_WIZARD_ATK7, 0, 0}, // S_WIZARD_ATK6
+ {SPR_WZRD, 2, 4, A_WizAtk1, S_WIZARD_ATK8, 0, 0}, // S_WIZARD_ATK7
+ {SPR_WZRD, 2, 4, A_WizAtk2, S_WIZARD_ATK9, 0, 0}, // S_WIZARD_ATK8
+ {SPR_WZRD, 3, 12, A_WizAtk3, S_WIZARD_WALK1, 0, 0}, // S_WIZARD_ATK9
+ {SPR_WZRD, 4, 3, A_GhostOff, S_WIZARD_PAIN2, 0, 0}, // S_WIZARD_PAIN1
+ {SPR_WZRD, 4, 3, A_Pain, S_WIZARD_WALK1, 0, 0}, // S_WIZARD_PAIN2
+ {SPR_WZRD, 5, 6, A_GhostOff, S_WIZARD_DIE2, 0, 0}, // S_WIZARD_DIE1
+ {SPR_WZRD, 6, 6, A_Scream, S_WIZARD_DIE3, 0, 0}, // S_WIZARD_DIE2
+ {SPR_WZRD, 7, 6, NULL, S_WIZARD_DIE4, 0, 0}, // S_WIZARD_DIE3
+ {SPR_WZRD, 8, 6, NULL, S_WIZARD_DIE5, 0, 0}, // S_WIZARD_DIE4
+ {SPR_WZRD, 9, 6, A_NoBlocking, S_WIZARD_DIE6, 0, 0}, // S_WIZARD_DIE5
+ {SPR_WZRD, 10, 6, NULL, S_WIZARD_DIE7, 0, 0}, // S_WIZARD_DIE6
+ {SPR_WZRD, 11, 6, NULL, S_WIZARD_DIE8, 0, 0}, // S_WIZARD_DIE7
+ {SPR_WZRD, 12, -1, NULL, S_NULL, 0, 0}, // S_WIZARD_DIE8
+ {SPR_FX11, 32768, 6, NULL, S_WIZFX1_2, 0, 0}, // S_WIZFX1_1
+ {SPR_FX11, 32769, 6, NULL, S_WIZFX1_1, 0, 0}, // S_WIZFX1_2
+ {SPR_FX11, 32770, 5, NULL, S_WIZFXI1_2, 0, 0}, // S_WIZFXI1_1
+ {SPR_FX11, 32771, 5, NULL, S_WIZFXI1_3, 0, 0}, // S_WIZFXI1_2
+ {SPR_FX11, 32772, 5, NULL, S_WIZFXI1_4, 0, 0}, // S_WIZFXI1_3
+ {SPR_FX11, 32773, 5, NULL, S_WIZFXI1_5, 0, 0}, // S_WIZFXI1_4
+ {SPR_FX11, 32774, 5, NULL, S_NULL, 0, 0}, // S_WIZFXI1_5
+ {SPR_IMPX, 0, 10, A_Look, S_IMP_LOOK2, 0, 0}, // S_IMP_LOOK1
+ {SPR_IMPX, 1, 10, A_Look, S_IMP_LOOK3, 0, 0}, // S_IMP_LOOK2
+ {SPR_IMPX, 2, 10, A_Look, S_IMP_LOOK4, 0, 0}, // S_IMP_LOOK3
+ {SPR_IMPX, 1, 10, A_Look, S_IMP_LOOK1, 0, 0}, // S_IMP_LOOK4
+ {SPR_IMPX, 0, 3, A_Chase, S_IMP_FLY2, 0, 0}, // S_IMP_FLY1
+ {SPR_IMPX, 0, 3, A_Chase, S_IMP_FLY3, 0, 0}, // S_IMP_FLY2
+ {SPR_IMPX, 1, 3, A_Chase, S_IMP_FLY4, 0, 0}, // S_IMP_FLY3
+ {SPR_IMPX, 1, 3, A_Chase, S_IMP_FLY5, 0, 0}, // S_IMP_FLY4
+ {SPR_IMPX, 2, 3, A_Chase, S_IMP_FLY6, 0, 0}, // S_IMP_FLY5
+ {SPR_IMPX, 2, 3, A_Chase, S_IMP_FLY7, 0, 0}, // S_IMP_FLY6
+ {SPR_IMPX, 1, 3, A_Chase, S_IMP_FLY8, 0, 0}, // S_IMP_FLY7
+ {SPR_IMPX, 1, 3, A_Chase, S_IMP_FLY1, 0, 0}, // S_IMP_FLY8
+ {SPR_IMPX, 3, 6, A_FaceTarget, S_IMP_MEATK2, 0, 0}, // S_IMP_MEATK1
+ {SPR_IMPX, 4, 6, A_FaceTarget, S_IMP_MEATK3, 0, 0}, // S_IMP_MEATK2
+ {SPR_IMPX, 5, 6, A_ImpMeAttack, S_IMP_FLY1, 0, 0}, // S_IMP_MEATK3
+ {SPR_IMPX, 0, 10, A_FaceTarget, S_IMP_MSATK1_2, 0, 0}, // S_IMP_MSATK1_1
+ {SPR_IMPX, 1, 6, A_ImpMsAttack, S_IMP_MSATK1_3, 0, 0}, // S_IMP_MSATK1_2
+ {SPR_IMPX, 2, 6, NULL, S_IMP_MSATK1_4, 0, 0}, // S_IMP_MSATK1_3
+ {SPR_IMPX, 1, 6, NULL, S_IMP_MSATK1_5, 0, 0}, // S_IMP_MSATK1_4
+ {SPR_IMPX, 0, 6, NULL, S_IMP_MSATK1_6, 0, 0}, // S_IMP_MSATK1_5
+ {SPR_IMPX, 1, 6, NULL, S_IMP_MSATK1_3, 0, 0}, // S_IMP_MSATK1_6
+ {SPR_IMPX, 3, 6, A_FaceTarget, S_IMP_MSATK2_2, 0, 0}, // S_IMP_MSATK2_1
+ {SPR_IMPX, 4, 6, A_FaceTarget, S_IMP_MSATK2_3, 0, 0}, // S_IMP_MSATK2_2
+ {SPR_IMPX, 5, 6, A_ImpMsAttack2, S_IMP_FLY1, 0, 0}, // S_IMP_MSATK2_3
+ {SPR_IMPX, 6, 3, NULL, S_IMP_PAIN2, 0, 0}, // S_IMP_PAIN1
+ {SPR_IMPX, 6, 3, A_Pain, S_IMP_FLY1, 0, 0}, // S_IMP_PAIN2
+ {SPR_IMPX, 6, 4, A_ImpDeath, S_IMP_DIE2, 0, 0}, // S_IMP_DIE1
+ {SPR_IMPX, 7, 5, NULL, S_IMP_DIE2, 0, 0}, // S_IMP_DIE2
+ {SPR_IMPX, 18, 5, A_ImpXDeath1, S_IMP_XDIE2, 0, 0}, // S_IMP_XDIE1
+ {SPR_IMPX, 19, 5, NULL, S_IMP_XDIE3, 0, 0}, // S_IMP_XDIE2
+ {SPR_IMPX, 20, 5, NULL, S_IMP_XDIE4, 0, 0}, // S_IMP_XDIE3
+ {SPR_IMPX, 21, 5, A_ImpXDeath2, S_IMP_XDIE5, 0, 0}, // S_IMP_XDIE4
+ {SPR_IMPX, 22, 5, NULL, S_IMP_XDIE5, 0, 0}, // S_IMP_XDIE5
+ {SPR_IMPX, 8, 7, A_ImpExplode, S_IMP_CRASH2, 0, 0}, // S_IMP_CRASH1
+ {SPR_IMPX, 9, 7, A_Scream, S_IMP_CRASH3, 0, 0}, // S_IMP_CRASH2
+ {SPR_IMPX, 10, 7, NULL, S_IMP_CRASH4, 0, 0}, // S_IMP_CRASH3
+ {SPR_IMPX, 11, -1, NULL, S_NULL, 0, 0}, // S_IMP_CRASH4
+ {SPR_IMPX, 23, 7, NULL, S_IMP_XCRASH2, 0, 0}, // S_IMP_XCRASH1
+ {SPR_IMPX, 24, 7, NULL, S_IMP_XCRASH3, 0, 0}, // S_IMP_XCRASH2
+ {SPR_IMPX, 25, -1, NULL, S_NULL, 0, 0}, // S_IMP_XCRASH3
+ {SPR_IMPX, 12, 5, NULL, S_IMP_CHUNKA2, 0, 0}, // S_IMP_CHUNKA1
+ {SPR_IMPX, 13, 700, NULL, S_IMP_CHUNKA3, 0, 0}, // S_IMP_CHUNKA2
+ {SPR_IMPX, 14, 700, NULL, S_NULL, 0, 0}, // S_IMP_CHUNKA3
+ {SPR_IMPX, 15, 5, NULL, S_IMP_CHUNKB2, 0, 0}, // S_IMP_CHUNKB1
+ {SPR_IMPX, 16, 700, NULL, S_IMP_CHUNKB3, 0, 0}, // S_IMP_CHUNKB2
+ {SPR_IMPX, 17, 700, NULL, S_NULL, 0, 0}, // S_IMP_CHUNKB3
+ {SPR_FX10, 32768, 6, NULL, S_IMPFX2, 0, 0}, // S_IMPFX1
+ {SPR_FX10, 32769, 6, NULL, S_IMPFX3, 0, 0}, // S_IMPFX2
+ {SPR_FX10, 32770, 6, NULL, S_IMPFX1, 0, 0}, // S_IMPFX3
+ {SPR_FX10, 32771, 5, NULL, S_IMPFXI2, 0, 0}, // S_IMPFXI1
+ {SPR_FX10, 32772, 5, NULL, S_IMPFXI3, 0, 0}, // S_IMPFXI2
+ {SPR_FX10, 32773, 5, NULL, S_IMPFXI4, 0, 0}, // S_IMPFXI3
+ {SPR_FX10, 32774, 5, NULL, S_NULL, 0, 0}, // S_IMPFXI4
+ {SPR_KNIG, 0, 10, A_Look, S_KNIGHT_STND2, 0, 0}, // S_KNIGHT_STND1
+ {SPR_KNIG, 1, 10, A_Look, S_KNIGHT_STND1, 0, 0}, // S_KNIGHT_STND2
+ {SPR_KNIG, 0, 4, A_Chase, S_KNIGHT_WALK2, 0, 0}, // S_KNIGHT_WALK1
+ {SPR_KNIG, 1, 4, A_Chase, S_KNIGHT_WALK3, 0, 0}, // S_KNIGHT_WALK2
+ {SPR_KNIG, 2, 4, A_Chase, S_KNIGHT_WALK4, 0, 0}, // S_KNIGHT_WALK3
+ {SPR_KNIG, 3, 4, A_Chase, S_KNIGHT_WALK1, 0, 0}, // S_KNIGHT_WALK4
+ {SPR_KNIG, 4, 10, A_FaceTarget, S_KNIGHT_ATK2, 0, 0}, // S_KNIGHT_ATK1
+ {SPR_KNIG, 5, 8, A_FaceTarget, S_KNIGHT_ATK3, 0, 0}, // S_KNIGHT_ATK2
+ {SPR_KNIG, 6, 8, A_KnightAttack, S_KNIGHT_ATK4, 0, 0}, // S_KNIGHT_ATK3
+ {SPR_KNIG, 4, 10, A_FaceTarget, S_KNIGHT_ATK5, 0, 0}, // S_KNIGHT_ATK4
+ {SPR_KNIG, 5, 8, A_FaceTarget, S_KNIGHT_ATK6, 0, 0}, // S_KNIGHT_ATK5
+ {SPR_KNIG, 6, 8, A_KnightAttack, S_KNIGHT_WALK1, 0, 0}, // S_KNIGHT_ATK6
+ {SPR_KNIG, 7, 3, NULL, S_KNIGHT_PAIN2, 0, 0}, // S_KNIGHT_PAIN1
+ {SPR_KNIG, 7, 3, A_Pain, S_KNIGHT_WALK1, 0, 0}, // S_KNIGHT_PAIN2
+ {SPR_KNIG, 8, 6, NULL, S_KNIGHT_DIE2, 0, 0}, // S_KNIGHT_DIE1
+ {SPR_KNIG, 9, 6, A_Scream, S_KNIGHT_DIE3, 0, 0}, // S_KNIGHT_DIE2
+ {SPR_KNIG, 10, 6, NULL, S_KNIGHT_DIE4, 0, 0}, // S_KNIGHT_DIE3
+ {SPR_KNIG, 11, 6, A_NoBlocking, S_KNIGHT_DIE5, 0, 0}, // S_KNIGHT_DIE4
+ {SPR_KNIG, 12, 6, NULL, S_KNIGHT_DIE6, 0, 0}, // S_KNIGHT_DIE5
+ {SPR_KNIG, 13, 6, NULL, S_KNIGHT_DIE7, 0, 0}, // S_KNIGHT_DIE6
+ {SPR_KNIG, 14, -1, NULL, S_NULL, 0, 0}, // S_KNIGHT_DIE7
+ {SPR_SPAX, 32768, 3, A_ContMobjSound, S_SPINAXE2, 0, 0}, // S_SPINAXE1
+ {SPR_SPAX, 32769, 3, NULL, S_SPINAXE3, 0, 0}, // S_SPINAXE2
+ {SPR_SPAX, 32770, 3, NULL, S_SPINAXE1, 0, 0}, // S_SPINAXE3
+ {SPR_SPAX, 32771, 6, NULL, S_SPINAXEX2, 0, 0}, // S_SPINAXEX1
+ {SPR_SPAX, 32772, 6, NULL, S_SPINAXEX3, 0, 0}, // S_SPINAXEX2
+ {SPR_SPAX, 32773, 6, NULL, S_NULL, 0, 0}, // S_SPINAXEX3
+ {SPR_RAXE, 32768, 5, A_DripBlood, S_REDAXE2, 0, 0}, // S_REDAXE1
+ {SPR_RAXE, 32769, 5, A_DripBlood, S_REDAXE1, 0, 0}, // S_REDAXE2
+ {SPR_RAXE, 32770, 6, NULL, S_REDAXEX2, 0, 0}, // S_REDAXEX1
+ {SPR_RAXE, 32771, 6, NULL, S_REDAXEX3, 0, 0}, // S_REDAXEX2
+ {SPR_RAXE, 32772, 6, NULL, S_NULL, 0, 0}, // S_REDAXEX3
+ {SPR_SRCR, 0, 10, A_Look, S_SRCR1_LOOK2, 0, 0}, // S_SRCR1_LOOK1
+ {SPR_SRCR, 1, 10, A_Look, S_SRCR1_LOOK1, 0, 0}, // S_SRCR1_LOOK2
+ {SPR_SRCR, 0, 5, A_Sor1Chase, S_SRCR1_WALK2, 0, 0}, // S_SRCR1_WALK1
+ {SPR_SRCR, 1, 5, A_Sor1Chase, S_SRCR1_WALK3, 0, 0}, // S_SRCR1_WALK2
+ {SPR_SRCR, 2, 5, A_Sor1Chase, S_SRCR1_WALK4, 0, 0}, // S_SRCR1_WALK3
+ {SPR_SRCR, 3, 5, A_Sor1Chase, S_SRCR1_WALK1, 0, 0}, // S_SRCR1_WALK4
+ {SPR_SRCR, 16, 6, A_Sor1Pain, S_SRCR1_WALK1, 0, 0}, // S_SRCR1_PAIN1
+ {SPR_SRCR, 16, 7, A_FaceTarget, S_SRCR1_ATK2, 0, 0}, // S_SRCR1_ATK1
+ {SPR_SRCR, 17, 6, A_FaceTarget, S_SRCR1_ATK3, 0, 0}, // S_SRCR1_ATK2
+ {SPR_SRCR, 18, 10, A_Srcr1Attack, S_SRCR1_WALK1, 0, 0}, // S_SRCR1_ATK3
+ {SPR_SRCR, 18, 10, A_FaceTarget, S_SRCR1_ATK5, 0, 0}, // S_SRCR1_ATK4
+ {SPR_SRCR, 16, 7, A_FaceTarget, S_SRCR1_ATK6, 0, 0}, // S_SRCR1_ATK5
+ {SPR_SRCR, 17, 6, A_FaceTarget, S_SRCR1_ATK7, 0, 0}, // S_SRCR1_ATK6
+ {SPR_SRCR, 18, 10, A_Srcr1Attack, S_SRCR1_WALK1, 0, 0}, // S_SRCR1_ATK7
+ {SPR_SRCR, 4, 7, NULL, S_SRCR1_DIE2, 0, 0}, // S_SRCR1_DIE1
+ {SPR_SRCR, 5, 7, A_Scream, S_SRCR1_DIE3, 0, 0}, // S_SRCR1_DIE2
+ {SPR_SRCR, 6, 7, NULL, S_SRCR1_DIE4, 0, 0}, // S_SRCR1_DIE3
+ {SPR_SRCR, 7, 6, NULL, S_SRCR1_DIE5, 0, 0}, // S_SRCR1_DIE4
+ {SPR_SRCR, 8, 6, NULL, S_SRCR1_DIE6, 0, 0}, // S_SRCR1_DIE5
+ {SPR_SRCR, 9, 6, NULL, S_SRCR1_DIE7, 0, 0}, // S_SRCR1_DIE6
+ {SPR_SRCR, 10, 6, NULL, S_SRCR1_DIE8, 0, 0}, // S_SRCR1_DIE7
+ {SPR_SRCR, 11, 25, A_SorZap, S_SRCR1_DIE9, 0, 0}, // S_SRCR1_DIE8
+ {SPR_SRCR, 12, 5, NULL, S_SRCR1_DIE10, 0, 0}, // S_SRCR1_DIE9
+ {SPR_SRCR, 13, 5, NULL, S_SRCR1_DIE11, 0, 0}, // S_SRCR1_DIE10
+ {SPR_SRCR, 14, 4, NULL, S_SRCR1_DIE12, 0, 0}, // S_SRCR1_DIE11
+ {SPR_SRCR, 11, 20, A_SorZap, S_SRCR1_DIE13, 0, 0}, // S_SRCR1_DIE12
+ {SPR_SRCR, 12, 5, NULL, S_SRCR1_DIE14, 0, 0}, // S_SRCR1_DIE13
+ {SPR_SRCR, 13, 5, NULL, S_SRCR1_DIE15, 0, 0}, // S_SRCR1_DIE14
+ {SPR_SRCR, 14, 4, NULL, S_SRCR1_DIE16, 0, 0}, // S_SRCR1_DIE15
+ {SPR_SRCR, 11, 12, NULL, S_SRCR1_DIE17, 0, 0}, // S_SRCR1_DIE16
+ {SPR_SRCR, 15, -1, A_SorcererRise, S_NULL, 0, 0}, // S_SRCR1_DIE17
+ {SPR_FX14, 32768, 6, NULL, S_SRCRFX1_2, 0, 0}, // S_SRCRFX1_1
+ {SPR_FX14, 32769, 6, NULL, S_SRCRFX1_3, 0, 0}, // S_SRCRFX1_2
+ {SPR_FX14, 32770, 6, NULL, S_SRCRFX1_1, 0, 0}, // S_SRCRFX1_3
+ {SPR_FX14, 32771, 5, NULL, S_SRCRFXI1_2, 0, 0}, // S_SRCRFXI1_1
+ {SPR_FX14, 32772, 5, NULL, S_SRCRFXI1_3, 0, 0}, // S_SRCRFXI1_2
+ {SPR_FX14, 32773, 5, NULL, S_SRCRFXI1_4, 0, 0}, // S_SRCRFXI1_3
+ {SPR_FX14, 32774, 5, NULL, S_SRCRFXI1_5, 0, 0}, // S_SRCRFXI1_4
+ {SPR_FX14, 32775, 5, NULL, S_NULL, 0, 0}, // S_SRCRFXI1_5
+ {SPR_SOR2, 0, 4, NULL, S_SOR2_RISE2, 0, 0}, // S_SOR2_RISE1
+ {SPR_SOR2, 1, 4, NULL, S_SOR2_RISE3, 0, 0}, // S_SOR2_RISE2
+ {SPR_SOR2, 2, 4, A_SorRise, S_SOR2_RISE4, 0, 0}, // S_SOR2_RISE3
+ {SPR_SOR2, 3, 4, NULL, S_SOR2_RISE5, 0, 0}, // S_SOR2_RISE4
+ {SPR_SOR2, 4, 4, NULL, S_SOR2_RISE6, 0, 0}, // S_SOR2_RISE5
+ {SPR_SOR2, 5, 4, NULL, S_SOR2_RISE7, 0, 0}, // S_SOR2_RISE6
+ {SPR_SOR2, 6, 12, A_SorSightSnd, S_SOR2_WALK1, 0, 0}, // S_SOR2_RISE7
+ {SPR_SOR2, 12, 10, A_Look, S_SOR2_LOOK2, 0, 0}, // S_SOR2_LOOK1
+ {SPR_SOR2, 13, 10, A_Look, S_SOR2_LOOK1, 0, 0}, // S_SOR2_LOOK2
+ {SPR_SOR2, 12, 4, A_Chase, S_SOR2_WALK2, 0, 0}, // S_SOR2_WALK1
+ {SPR_SOR2, 13, 4, A_Chase, S_SOR2_WALK3, 0, 0}, // S_SOR2_WALK2
+ {SPR_SOR2, 14, 4, A_Chase, S_SOR2_WALK4, 0, 0}, // S_SOR2_WALK3
+ {SPR_SOR2, 15, 4, A_Chase, S_SOR2_WALK1, 0, 0}, // S_SOR2_WALK4
+ {SPR_SOR2, 16, 3, NULL, S_SOR2_PAIN2, 0, 0}, // S_SOR2_PAIN1
+ {SPR_SOR2, 16, 6, A_Pain, S_SOR2_WALK1, 0, 0}, // S_SOR2_PAIN2
+ {SPR_SOR2, 17, 9, A_Srcr2Decide, S_SOR2_ATK2, 0, 0}, // S_SOR2_ATK1
+ {SPR_SOR2, 18, 9, A_FaceTarget, S_SOR2_ATK3, 0, 0}, // S_SOR2_ATK2
+ {SPR_SOR2, 19, 20, A_Srcr2Attack, S_SOR2_WALK1, 0, 0}, // S_SOR2_ATK3
+ {SPR_SOR2, 11, 6, NULL, S_SOR2_TELE2, 0, 0}, // S_SOR2_TELE1
+ {SPR_SOR2, 10, 6, NULL, S_SOR2_TELE3, 0, 0}, // S_SOR2_TELE2
+ {SPR_SOR2, 9, 6, NULL, S_SOR2_TELE4, 0, 0}, // S_SOR2_TELE3
+ {SPR_SOR2, 8, 6, NULL, S_SOR2_TELE5, 0, 0}, // S_SOR2_TELE4
+ {SPR_SOR2, 7, 6, NULL, S_SOR2_TELE6, 0, 0}, // S_SOR2_TELE5
+ {SPR_SOR2, 6, 6, NULL, S_SOR2_WALK1, 0, 0}, // S_SOR2_TELE6
+ {SPR_SDTH, 0, 8, A_Sor2DthInit, S_SOR2_DIE2, 0, 0}, // S_SOR2_DIE1
+ {SPR_SDTH, 1, 8, NULL, S_SOR2_DIE3, 0, 0}, // S_SOR2_DIE2
+ {SPR_SDTH, 2, 8, A_SorDSph, S_SOR2_DIE4, 0, 0}, // S_SOR2_DIE3
+ {SPR_SDTH, 3, 7, NULL, S_SOR2_DIE5, 0, 0}, // S_SOR2_DIE4
+ {SPR_SDTH, 4, 7, NULL, S_SOR2_DIE6, 0, 0}, // S_SOR2_DIE5
+ {SPR_SDTH, 5, 7, A_Sor2DthLoop, S_SOR2_DIE7, 0, 0}, // S_SOR2_DIE6
+ {SPR_SDTH, 6, 6, A_SorDExp, S_SOR2_DIE8, 0, 0}, // S_SOR2_DIE7
+ {SPR_SDTH, 7, 6, NULL, S_SOR2_DIE9, 0, 0}, // S_SOR2_DIE8
+ {SPR_SDTH, 8, 18, NULL, S_SOR2_DIE10, 0, 0}, // S_SOR2_DIE9
+ {SPR_SDTH, 9, 6, A_NoBlocking, S_SOR2_DIE11, 0, 0}, // S_SOR2_DIE10
+ {SPR_SDTH, 10, 6, A_SorDBon, S_SOR2_DIE12, 0, 0}, // S_SOR2_DIE11
+ {SPR_SDTH, 11, 6, NULL, S_SOR2_DIE13, 0, 0}, // S_SOR2_DIE12
+ {SPR_SDTH, 12, 6, NULL, S_SOR2_DIE14, 0, 0}, // S_SOR2_DIE13
+ {SPR_SDTH, 13, 6, NULL, S_SOR2_DIE15, 0, 0}, // S_SOR2_DIE14
+ {SPR_SDTH, 14, -1, A_BossDeath, S_NULL, 0, 0}, // S_SOR2_DIE15
+ {SPR_FX16, 32768, 3, A_BlueSpark, S_SOR2FX1_2, 0, 0}, // S_SOR2FX1_1
+ {SPR_FX16, 32769, 3, A_BlueSpark, S_SOR2FX1_3, 0, 0}, // S_SOR2FX1_2
+ {SPR_FX16, 32770, 3, A_BlueSpark, S_SOR2FX1_1, 0, 0}, // S_SOR2FX1_3
+ {SPR_FX16, 32774, 5, A_Explode, S_SOR2FXI1_2, 0, 0}, // S_SOR2FXI1_1
+ {SPR_FX16, 32775, 5, NULL, S_SOR2FXI1_3, 0, 0}, // S_SOR2FXI1_2
+ {SPR_FX16, 32776, 5, NULL, S_SOR2FXI1_4, 0, 0}, // S_SOR2FXI1_3
+ {SPR_FX16, 32777, 5, NULL, S_SOR2FXI1_5, 0, 0}, // S_SOR2FXI1_4
+ {SPR_FX16, 32778, 5, NULL, S_SOR2FXI1_6, 0, 0}, // S_SOR2FXI1_5
+ {SPR_FX16, 32779, 5, NULL, S_NULL, 0, 0}, // S_SOR2FXI1_6
+ {SPR_FX16, 32771, 12, NULL, S_SOR2FXSPARK2, 0, 0}, // S_SOR2FXSPARK1
+ {SPR_FX16, 32772, 12, NULL, S_SOR2FXSPARK3, 0, 0}, // S_SOR2FXSPARK2
+ {SPR_FX16, 32773, 12, NULL, S_NULL, 0, 0}, // S_SOR2FXSPARK3
+ {SPR_FX11, 32768, 35, NULL, S_SOR2FX2_2, 0, 0}, // S_SOR2FX2_1
+ {SPR_FX11, 32768, 5, A_GenWizard, S_SOR2FX2_3, 0, 0}, // S_SOR2FX2_2
+ {SPR_FX11, 32769, 5, NULL, S_SOR2FX2_2, 0, 0}, // S_SOR2FX2_3
+ {SPR_FX11, 32770, 5, NULL, S_SOR2FXI2_2, 0, 0}, // S_SOR2FXI2_1
+ {SPR_FX11, 32771, 5, NULL, S_SOR2FXI2_3, 0, 0}, // S_SOR2FXI2_2
+ {SPR_FX11, 32772, 5, NULL, S_SOR2FXI2_4, 0, 0}, // S_SOR2FXI2_3
+ {SPR_FX11, 32773, 5, NULL, S_SOR2FXI2_5, 0, 0}, // S_SOR2FXI2_4
+ {SPR_FX11, 32774, 5, NULL, S_NULL, 0, 0}, // S_SOR2FXI2_5
+ {SPR_SOR2, 6, 8, NULL, S_SOR2TELEFADE2, 0, 0}, // S_SOR2TELEFADE1
+ {SPR_SOR2, 7, 6, NULL, S_SOR2TELEFADE3, 0, 0}, // S_SOR2TELEFADE2
+ {SPR_SOR2, 8, 6, NULL, S_SOR2TELEFADE4, 0, 0}, // S_SOR2TELEFADE3
+ {SPR_SOR2, 9, 6, NULL, S_SOR2TELEFADE5, 0, 0}, // S_SOR2TELEFADE4
+ {SPR_SOR2, 10, 6, NULL, S_SOR2TELEFADE6, 0, 0}, // S_SOR2TELEFADE5
+ {SPR_SOR2, 11, 6, NULL, S_NULL, 0, 0}, // S_SOR2TELEFADE6
+ {SPR_MNTR, 0, 10, A_Look, S_MNTR_LOOK2, 0, 0}, // S_MNTR_LOOK1
+ {SPR_MNTR, 1, 10, A_Look, S_MNTR_LOOK1, 0, 0}, // S_MNTR_LOOK2
+ {SPR_MNTR, 0, 5, A_Chase, S_MNTR_WALK2, 0, 0}, // S_MNTR_WALK1
+ {SPR_MNTR, 1, 5, A_Chase, S_MNTR_WALK3, 0, 0}, // S_MNTR_WALK2
+ {SPR_MNTR, 2, 5, A_Chase, S_MNTR_WALK4, 0, 0}, // S_MNTR_WALK3
+ {SPR_MNTR, 3, 5, A_Chase, S_MNTR_WALK1, 0, 0}, // S_MNTR_WALK4
+ {SPR_MNTR, 21, 10, A_FaceTarget, S_MNTR_ATK1_2, 0, 0}, // S_MNTR_ATK1_1
+ {SPR_MNTR, 22, 7, A_FaceTarget, S_MNTR_ATK1_3, 0, 0}, // S_MNTR_ATK1_2
+ {SPR_MNTR, 23, 12, A_MinotaurAtk1, S_MNTR_WALK1, 0, 0}, // S_MNTR_ATK1_3
+ {SPR_MNTR, 21, 10, A_MinotaurDecide, S_MNTR_ATK2_2, 0, 0}, // S_MNTR_ATK2_1
+ {SPR_MNTR, 24, 4, A_FaceTarget, S_MNTR_ATK2_3, 0, 0}, // S_MNTR_ATK2_2
+ {SPR_MNTR, 25, 9, A_MinotaurAtk2, S_MNTR_WALK1, 0, 0}, // S_MNTR_ATK2_3
+ {SPR_MNTR, 21, 10, A_FaceTarget, S_MNTR_ATK3_2, 0, 0}, // S_MNTR_ATK3_1
+ {SPR_MNTR, 22, 7, A_FaceTarget, S_MNTR_ATK3_3, 0, 0}, // S_MNTR_ATK3_2
+ {SPR_MNTR, 23, 12, A_MinotaurAtk3, S_MNTR_WALK1, 0, 0}, // S_MNTR_ATK3_3
+ {SPR_MNTR, 23, 12, NULL, S_MNTR_ATK3_1, 0, 0}, // S_MNTR_ATK3_4
+ {SPR_MNTR, 20, 2, A_MinotaurCharge, S_MNTR_ATK4_1, 0, 0}, // S_MNTR_ATK4_1
+ {SPR_MNTR, 4, 3, NULL, S_MNTR_PAIN2, 0, 0}, // S_MNTR_PAIN1
+ {SPR_MNTR, 4, 6, A_Pain, S_MNTR_WALK1, 0, 0}, // S_MNTR_PAIN2
+ {SPR_MNTR, 5, 6, NULL, S_MNTR_DIE2, 0, 0}, // S_MNTR_DIE1
+ {SPR_MNTR, 6, 5, NULL, S_MNTR_DIE3, 0, 0}, // S_MNTR_DIE2
+ {SPR_MNTR, 7, 6, A_Scream, S_MNTR_DIE4, 0, 0}, // S_MNTR_DIE3
+ {SPR_MNTR, 8, 5, NULL, S_MNTR_DIE5, 0, 0}, // S_MNTR_DIE4
+ {SPR_MNTR, 9, 6, NULL, S_MNTR_DIE6, 0, 0}, // S_MNTR_DIE5
+ {SPR_MNTR, 10, 5, NULL, S_MNTR_DIE7, 0, 0}, // S_MNTR_DIE6
+ {SPR_MNTR, 11, 6, NULL, S_MNTR_DIE8, 0, 0}, // S_MNTR_DIE7
+ {SPR_MNTR, 12, 5, A_NoBlocking, S_MNTR_DIE9, 0, 0}, // S_MNTR_DIE8
+ {SPR_MNTR, 13, 6, NULL, S_MNTR_DIE10, 0, 0}, // S_MNTR_DIE9
+ {SPR_MNTR, 14, 5, NULL, S_MNTR_DIE11, 0, 0}, // S_MNTR_DIE10
+ {SPR_MNTR, 15, 6, NULL, S_MNTR_DIE12, 0, 0}, // S_MNTR_DIE11
+ {SPR_MNTR, 16, 5, NULL, S_MNTR_DIE13, 0, 0}, // S_MNTR_DIE12
+ {SPR_MNTR, 17, 6, NULL, S_MNTR_DIE14, 0, 0}, // S_MNTR_DIE13
+ {SPR_MNTR, 18, 5, NULL, S_MNTR_DIE15, 0, 0}, // S_MNTR_DIE14
+ {SPR_MNTR, 19, -1, A_BossDeath, S_NULL, 0, 0}, // S_MNTR_DIE15
+ {SPR_FX12, 32768, 6, NULL, S_MNTRFX1_2, 0, 0}, // S_MNTRFX1_1
+ {SPR_FX12, 32769, 6, NULL, S_MNTRFX1_1, 0, 0}, // S_MNTRFX1_2
+ {SPR_FX12, 32770, 5, NULL, S_MNTRFXI1_2, 0, 0}, // S_MNTRFXI1_1
+ {SPR_FX12, 32771, 5, NULL, S_MNTRFXI1_3, 0, 0}, // S_MNTRFXI1_2
+ {SPR_FX12, 32772, 5, NULL, S_MNTRFXI1_4, 0, 0}, // S_MNTRFXI1_3
+ {SPR_FX12, 32773, 5, NULL, S_MNTRFXI1_5, 0, 0}, // S_MNTRFXI1_4
+ {SPR_FX12, 32774, 5, NULL, S_MNTRFXI1_6, 0, 0}, // S_MNTRFXI1_5
+ {SPR_FX12, 32775, 5, NULL, S_NULL, 0, 0}, // S_MNTRFXI1_6
+ {SPR_FX13, 0, 2, A_MntrFloorFire, S_MNTRFX2_1, 0, 0}, // S_MNTRFX2_1
+ {SPR_FX13, 32776, 4, A_Explode, S_MNTRFXI2_2, 0, 0}, // S_MNTRFXI2_1
+ {SPR_FX13, 32777, 4, NULL, S_MNTRFXI2_3, 0, 0}, // S_MNTRFXI2_2
+ {SPR_FX13, 32778, 4, NULL, S_MNTRFXI2_4, 0, 0}, // S_MNTRFXI2_3
+ {SPR_FX13, 32779, 4, NULL, S_MNTRFXI2_5, 0, 0}, // S_MNTRFXI2_4
+ {SPR_FX13, 32780, 4, NULL, S_NULL, 0, 0}, // S_MNTRFXI2_5
+ {SPR_FX13, 32771, 4, NULL, S_MNTRFX3_2, 0, 0}, // S_MNTRFX3_1
+ {SPR_FX13, 32770, 4, NULL, S_MNTRFX3_3, 0, 0}, // S_MNTRFX3_2
+ {SPR_FX13, 32769, 5, NULL, S_MNTRFX3_4, 0, 0}, // S_MNTRFX3_3
+ {SPR_FX13, 32770, 5, NULL, S_MNTRFX3_5, 0, 0}, // S_MNTRFX3_4
+ {SPR_FX13, 32771, 5, NULL, S_MNTRFX3_6, 0, 0}, // S_MNTRFX3_5
+ {SPR_FX13, 32772, 5, NULL, S_MNTRFX3_7, 0, 0}, // S_MNTRFX3_6
+ {SPR_FX13, 32773, 4, NULL, S_MNTRFX3_8, 0, 0}, // S_MNTRFX3_7
+ {SPR_FX13, 32774, 4, NULL, S_MNTRFX3_9, 0, 0}, // S_MNTRFX3_8
+ {SPR_FX13, 32775, 4, NULL, S_NULL, 0, 0}, // S_MNTRFX3_9
+ {SPR_AKYY, 32768, 3, NULL, S_AKYY2, 0, 0}, // S_AKYY1
+ {SPR_AKYY, 32769, 3, NULL, S_AKYY3, 0, 0}, // S_AKYY2
+ {SPR_AKYY, 32770, 3, NULL, S_AKYY4, 0, 0}, // S_AKYY3
+ {SPR_AKYY, 32771, 3, NULL, S_AKYY5, 0, 0}, // S_AKYY4
+ {SPR_AKYY, 32772, 3, NULL, S_AKYY6, 0, 0}, // S_AKYY5
+ {SPR_AKYY, 32773, 3, NULL, S_AKYY7, 0, 0}, // S_AKYY6
+ {SPR_AKYY, 32774, 3, NULL, S_AKYY8, 0, 0}, // S_AKYY7
+ {SPR_AKYY, 32775, 3, NULL, S_AKYY9, 0, 0}, // S_AKYY8
+ {SPR_AKYY, 32776, 3, NULL, S_AKYY10, 0, 0}, // S_AKYY9
+ {SPR_AKYY, 32777, 3, NULL, S_AKYY1, 0, 0}, // S_AKYY10
+ {SPR_BKYY, 32768, 3, NULL, S_BKYY2, 0, 0}, // S_BKYY1
+ {SPR_BKYY, 32769, 3, NULL, S_BKYY3, 0, 0}, // S_BKYY2
+ {SPR_BKYY, 32770, 3, NULL, S_BKYY4, 0, 0}, // S_BKYY3
+ {SPR_BKYY, 32771, 3, NULL, S_BKYY5, 0, 0}, // S_BKYY4
+ {SPR_BKYY, 32772, 3, NULL, S_BKYY6, 0, 0}, // S_BKYY5
+ {SPR_BKYY, 32773, 3, NULL, S_BKYY7, 0, 0}, // S_BKYY6
+ {SPR_BKYY, 32774, 3, NULL, S_BKYY8, 0, 0}, // S_BKYY7
+ {SPR_BKYY, 32775, 3, NULL, S_BKYY9, 0, 0}, // S_BKYY8
+ {SPR_BKYY, 32776, 3, NULL, S_BKYY10, 0, 0}, // S_BKYY9
+ {SPR_BKYY, 32777, 3, NULL, S_BKYY1, 0, 0}, // S_BKYY10
+ {SPR_CKYY, 32768, 3, NULL, S_CKYY2, 0, 0}, // S_CKYY1
+ {SPR_CKYY, 32769, 3, NULL, S_CKYY3, 0, 0}, // S_CKYY2
+ {SPR_CKYY, 32770, 3, NULL, S_CKYY4, 0, 0}, // S_CKYY3
+ {SPR_CKYY, 32771, 3, NULL, S_CKYY5, 0, 0}, // S_CKYY4
+ {SPR_CKYY, 32772, 3, NULL, S_CKYY6, 0, 0}, // S_CKYY5
+ {SPR_CKYY, 32773, 3, NULL, S_CKYY7, 0, 0}, // S_CKYY6
+ {SPR_CKYY, 32774, 3, NULL, S_CKYY8, 0, 0}, // S_CKYY7
+ {SPR_CKYY, 32775, 3, NULL, S_CKYY9, 0, 0}, // S_CKYY8
+ {SPR_CKYY, 32776, 3, NULL, S_CKYY1, 0, 0}, // S_CKYY9
+ {SPR_AMG1, 0, -1, NULL, S_NULL, 0, 0}, // S_AMG1
+ {SPR_AMG2, 0, 4, NULL, S_AMG2_2, 0, 0}, // S_AMG2_1
+ {SPR_AMG2, 1, 4, NULL, S_AMG2_3, 0, 0}, // S_AMG2_2
+ {SPR_AMG2, 2, 4, NULL, S_AMG2_1, 0, 0}, // S_AMG2_3
+ {SPR_AMM1, 0, -1, NULL, S_NULL, 0, 0}, // S_AMM1
+ {SPR_AMM2, 0, -1, NULL, S_NULL, 0, 0}, // S_AMM2
+ {SPR_AMC1, 0, -1, NULL, S_NULL, 0, 0}, // S_AMC1
+ {SPR_AMC2, 0, 5, NULL, S_AMC2_2, 0, 0}, // S_AMC2_1
+ {SPR_AMC2, 1, 5, NULL, S_AMC2_3, 0, 0}, // S_AMC2_2
+ {SPR_AMC2, 2, 5, NULL, S_AMC2_1, 0, 0}, // S_AMC2_3
+ {SPR_AMS1, 0, 5, NULL, S_AMS1_2, 0, 0}, // S_AMS1_1
+ {SPR_AMS1, 1, 5, NULL, S_AMS1_1, 0, 0}, // S_AMS1_2
+ {SPR_AMS2, 0, 5, NULL, S_AMS2_2, 0, 0}, // S_AMS2_1
+ {SPR_AMS2, 1, 5, NULL, S_AMS2_1, 0, 0}, // S_AMS2_2
+ {SPR_AMP1, 0, 4, NULL, S_AMP1_2, 0, 0}, // S_AMP1_1
+ {SPR_AMP1, 1, 4, NULL, S_AMP1_3, 0, 0}, // S_AMP1_2
+ {SPR_AMP1, 2, 4, NULL, S_AMP1_1, 0, 0}, // S_AMP1_3
+ {SPR_AMP2, 0, 4, NULL, S_AMP2_2, 0, 0}, // S_AMP2_1
+ {SPR_AMP2, 1, 4, NULL, S_AMP2_3, 0, 0}, // S_AMP2_2
+ {SPR_AMP2, 2, 4, NULL, S_AMP2_1, 0, 0}, // S_AMP2_3
+ {SPR_AMB1, 0, 4, NULL, S_AMB1_2, 0, 0}, // S_AMB1_1
+ {SPR_AMB1, 1, 4, NULL, S_AMB1_3, 0, 0}, // S_AMB1_2
+ {SPR_AMB1, 2, 4, NULL, S_AMB1_1, 0, 0}, // S_AMB1_3
+ {SPR_AMB2, 0, 4, NULL, S_AMB2_2, 0, 0}, // S_AMB2_1
+ {SPR_AMB2, 1, 4, NULL, S_AMB2_3, 0, 0}, // S_AMB2_2
+ {SPR_AMB2, 2, 4, NULL, S_AMB2_1, 0, 0}, // S_AMB2_3
+ {SPR_AMG1, 0, 100, A_ESound, S_SND_WIND, 0, 0}, // S_SND_WIND
+ {SPR_AMG1, 0, 85, A_ESound, S_SND_WATERFALL, 0, 0} // S_SND_WATERFALL
+};
+
+
+mobjinfo_t mobjinfo[NUMMOBJTYPES] = {
+
+ { // MT_MISC0
+ 81, // doomednum
+ S_ITEM_PTN1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_ITEMSHIELD1
+ 85, // doomednum
+ S_ITEM_SHLD1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_ITEMSHIELD2
+ 31, // doomednum
+ S_ITEM_SHD2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_MISC1
+ 8, // doomednum
+ S_ITEM_BAGH1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL | MF_COUNTITEM, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_MISC2
+ 35, // doomednum
+ S_ITEM_SPMP1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL | MF_COUNTITEM, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_ARTIINVISIBILITY
+ 75, // doomednum
+ S_ARTI_INVS1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL | MF_SHADOW | MF_COUNTITEM, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_MISC3
+ 82, // doomednum
+ S_ARTI_PTN2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL | MF_COUNTITEM, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_ARTIFLY
+ 83, // doomednum
+ S_ARTI_SOAR1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL | MF_COUNTITEM, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_ARTIINVULNERABILITY
+ 84, // doomednum
+ S_ARTI_INVU1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL | MF_COUNTITEM, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_ARTITOMEOFPOWER
+ 86, // doomednum
+ S_ARTI_PWBK1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL | MF_COUNTITEM, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_ARTIEGG
+ 30, // doomednum
+ S_ARTI_EGGC1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL | MF_COUNTITEM, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_EGGFX
+ -1, // doomednum
+ S_EGGFX1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_EGGFXI1_1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 18 * FRACUNIT, // speed
+ 8 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 1, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_ARTISUPERHEAL
+ 32, // doomednum
+ S_ARTI_SPHL1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL | MF_COUNTITEM, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_MISC4
+ 33, // doomednum
+ S_ARTI_TRCH1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL | MF_COUNTITEM, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_MISC5
+ 34, // doomednum
+ S_ARTI_FBMB1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL | MF_COUNTITEM, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_FIREBOMB
+ -1, // doomednum
+ S_FIREBOMB1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_phohit, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOGRAVITY | MF_SHADOW, // flags
+ 0 // flags2
+ },
+
+ { // MT_ARTITELEPORT
+ 36, // doomednum
+ S_ARTI_ATLP1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL | MF_COUNTITEM, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_POD
+ 2035, // doomednum
+ S_POD_WAIT1, // spawnstate
+ 45, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_POD_PAIN1, // painstate
+ 255, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_POD_DIE1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_podexp, // deathsound
+ 0, // speed
+ 16 * FRACUNIT, // radius
+ 54 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SOLID | MF_NOBLOOD | MF_SHOOTABLE | MF_DROPOFF, // flags
+ MF2_WINDTHRUST | MF2_PUSHABLE | MF2_SLIDE | MF2_PASSMOBJ | MF2_TELESTOMP // flags2
+ },
+
+ { // MT_PODGOO
+ -1, // doomednum
+ S_PODGOO1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_PODGOOX, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 2 * FRACUNIT, // radius
+ 4 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF, // flags
+ MF2_NOTELEPORT | MF2_LOGRAV | MF2_CANNOTPUSH // flags2
+ },
+
+ { // MT_PODGENERATOR
+ 43, // doomednum
+ S_PODGENERATOR, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_NOSECTOR, // flags
+ 0 // flags2
+ },
+
+ { // MT_SPLASH
+ -1, // doomednum
+ S_SPLASH1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SPLASHX, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 2 * FRACUNIT, // radius
+ 4 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF, // flags
+ MF2_NOTELEPORT | MF2_LOGRAV | MF2_CANNOTPUSH // flags2
+ },
+
+ { // MT_SPLASHBASE
+ -1, // doomednum
+ S_SPLASHBASE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP, // flags
+ 0 // flags2
+ },
+
+ { // MT_LAVASPLASH
+ -1, // doomednum
+ S_LAVASPLASH1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP, // flags
+ 0 // flags2
+ },
+
+ { // MT_LAVASMOKE
+ -1, // doomednum
+ S_LAVASMOKE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags
+ 0 // flags2
+ },
+
+ { // MT_SLUDGECHUNK
+ -1, // doomednum
+ S_SLUDGECHUNK1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SLUDGECHUNKX, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 2 * FRACUNIT, // radius
+ 4 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF, // flags
+ MF2_NOTELEPORT | MF2_LOGRAV | MF2_CANNOTPUSH // flags2
+ },
+
+ { // MT_SLUDGESPLASH
+ -1, // doomednum
+ S_SLUDGESPLASH1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP, // flags
+ 0 // flags2
+ },
+
+ { // MT_SKULLHANG70
+ 17, // doomednum
+ S_SKULLHANG70_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 70 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPAWNCEILING | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_SKULLHANG60
+ 24, // doomednum
+ S_SKULLHANG60_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 60 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPAWNCEILING | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_SKULLHANG45
+ 25, // doomednum
+ S_SKULLHANG45_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 45 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPAWNCEILING | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_SKULLHANG35
+ 26, // doomednum
+ S_SKULLHANG35_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 35 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPAWNCEILING | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_CHANDELIER
+ 28, // doomednum
+ S_CHANDELIER1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 60 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPAWNCEILING | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_SERPTORCH
+ 27, // doomednum
+ S_SERPTORCH1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 12 * FRACUNIT, // radius
+ 54 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_SMALLPILLAR
+ 29, // doomednum
+ S_SMALLPILLAR, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 16 * FRACUNIT, // radius
+ 34 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_STALAGMITESMALL
+ 37, // doomednum
+ S_STALAGMITESMALL, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 32 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_STALAGMITELARGE
+ 38, // doomednum
+ S_STALAGMITELARGE, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 12 * FRACUNIT, // radius
+ 64 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_STALACTITESMALL
+ 39, // doomednum
+ S_STALACTITESMALL, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 36 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_STALACTITELARGE
+ 40, // doomednum
+ S_STALACTITELARGE, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 12 * FRACUNIT, // radius
+ 68 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC6
+ 76, // doomednum
+ S_FIREBRAZIER1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 16 * FRACUNIT, // radius
+ 44 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_BARREL
+ 44, // doomednum
+ S_BARREL, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 12 * FRACUNIT, // radius
+ 32 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC7
+ 47, // doomednum
+ S_BRPILLAR, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 14 * FRACUNIT, // radius
+ 128 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC8
+ 48, // doomednum
+ S_MOSS1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 23 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPAWNCEILING | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC9
+ 49, // doomednum
+ S_MOSS2, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 27 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPAWNCEILING | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC10
+ 50, // doomednum
+ S_WALLTORCH1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC11
+ 51, // doomednum
+ S_HANGINGCORPSE, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 104 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_KEYGIZMOBLUE
+ 94, // doomednum
+ S_KEYGIZMO1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 16 * FRACUNIT, // radius
+ 50 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_KEYGIZMOGREEN
+ 95, // doomednum
+ S_KEYGIZMO1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 16 * FRACUNIT, // radius
+ 50 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_KEYGIZMOYELLOW
+ 96, // doomednum
+ S_KEYGIZMO1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 16 * FRACUNIT, // radius
+ 50 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_KEYGIZMOFLOAT
+ -1, // doomednum
+ S_KGZ_START, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 16 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SOLID | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC12
+ 87, // doomednum
+ S_VOLCANO1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 12 * FRACUNIT, // radius
+ 20 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_VOLCANOBLAST
+ -1, // doomednum
+ S_VOLCANOBALL1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_VOLCANOBALLX1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_volhit, // deathsound
+ 2 * FRACUNIT, // speed
+ 8 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 2, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF, // flags
+ MF2_LOGRAV | MF2_NOTELEPORT | MF2_FIREDAMAGE // flags2
+ },
+
+ { // MT_VOLCANOTBLAST
+ -1, // doomednum
+ S_VOLCANOTBALL1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_VOLCANOTBALLX1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 2 * FRACUNIT, // speed
+ 8 * FRACUNIT, // radius
+ 6 * FRACUNIT, // height
+ 100, // mass
+ 1, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF, // flags
+ MF2_LOGRAV | MF2_NOTELEPORT | MF2_FIREDAMAGE // flags2
+ },
+
+ { // MT_TELEGLITGEN
+ 74, // doomednum
+ S_TELEGLITGEN1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_NOSECTOR, // flags
+ 0 // flags2
+ },
+
+ { // MT_TELEGLITGEN2
+ 52, // doomednum
+ S_TELEGLITGEN2, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_NOSECTOR, // flags
+ 0 // flags2
+ },
+
+ { // MT_TELEGLITTER
+ -1, // doomednum
+ S_TELEGLITTER1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_MISSILE, // flags
+ 0 // flags2
+ },
+
+ { // MT_TELEGLITTER2
+ -1, // doomednum
+ S_TELEGLITTER2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_MISSILE, // flags
+ 0 // flags2
+ },
+
+ { // MT_TFOG
+ -1, // doomednum
+ S_TFOG1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_TELEPORTMAN
+ 14, // doomednum
+ S_NULL, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_NOSECTOR, // flags
+ 0 // flags2
+ },
+
+ { // MT_STAFFPUFF
+ -1, // doomednum
+ S_STAFFPUFF1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_stfhit, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_STAFFPUFF2
+ -1, // doomednum
+ S_STAFFPUFF2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_stfpow, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_BEAKPUFF
+ -1, // doomednum
+ S_STAFFPUFF1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_chicatk, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC13
+ 2005, // doomednum
+ S_WGNT, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_GAUNTLETPUFF1
+ -1, // doomednum
+ S_GAUNTLETPUFF1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags
+ 0 // flags2
+ },
+
+ { // MT_GAUNTLETPUFF2
+ -1, // doomednum
+ S_GAUNTLETPUFF2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC14
+ 53, // doomednum
+ S_BLSR, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_BLASTERFX1
+ -1, // doomednum
+ S_BLASTERFX1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_BLASTERFXI1_1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_blshit, // deathsound
+ 184 * FRACUNIT, // speed
+ 12 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 2, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_BLASTERSMOKE
+ -1, // doomednum
+ S_BLASTERSMOKE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags
+ MF2_NOTELEPORT | MF2_CANNOTPUSH // flags2
+ },
+
+ { // MT_RIPPER
+ -1, // doomednum
+ S_RIPPER1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_RIPPERX1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_hrnhit, // deathsound
+ 14 * FRACUNIT, // speed
+ 8 * FRACUNIT, // radius
+ 6 * FRACUNIT, // height
+ 100, // mass
+ 1, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_RIP // flags2
+ },
+
+ { // MT_BLASTERPUFF1
+ -1, // doomednum
+ S_BLASTERPUFF1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_BLASTERPUFF2
+ -1, // doomednum
+ S_BLASTERPUFF2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_WMACE
+ 2002, // doomednum
+ S_WMCE, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_MACEFX1
+ -1, // doomednum
+ S_MACEFX1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_lobsht, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_MACEFXI1_1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 20 * FRACUNIT, // speed
+ 8 * FRACUNIT, // radius
+ 6 * FRACUNIT, // height
+ 100, // mass
+ 2, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_FLOORBOUNCE | MF2_THRUGHOST | MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_MACEFX2
+ -1, // doomednum
+ S_MACEFX2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_MACEFXI2_1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 10 * FRACUNIT, // speed
+ 8 * FRACUNIT, // radius
+ 6 * FRACUNIT, // height
+ 100, // mass
+ 6, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF, // flags
+ MF2_LOGRAV | MF2_FLOORBOUNCE | MF2_THRUGHOST | MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_MACEFX3
+ -1, // doomednum
+ S_MACEFX3_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_MACEFXI1_1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 7 * FRACUNIT, // speed
+ 8 * FRACUNIT, // radius
+ 6 * FRACUNIT, // height
+ 100, // mass
+ 4, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF, // flags
+ MF2_LOGRAV | MF2_FLOORBOUNCE | MF2_THRUGHOST | MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_MACEFX4
+ -1, // doomednum
+ S_MACEFX4_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_MACEFXI4_1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 7 * FRACUNIT, // speed
+ 8 * FRACUNIT, // radius
+ 6 * FRACUNIT, // height
+ 100, // mass
+ 18, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF, // flags
+ MF2_LOGRAV | MF2_FLOORBOUNCE | MF2_THRUGHOST | MF2_TELESTOMP // flags2
+ },
+
+ { // MT_WSKULLROD
+ 2004, // doomednum
+ S_WSKL, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_HORNRODFX1
+ -1, // doomednum
+ S_HRODFX1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_hrnsht, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_HRODFXI1_1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_hrnhit, // deathsound
+ 22 * FRACUNIT, // speed
+ 12 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 3, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_WINDTHRUST | MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_HORNRODFX2
+ -1, // doomednum
+ S_HRODFX2_1, // spawnstate
+ 4 * 35, // spawnhealth
+ S_NULL, // seestate
+ sfx_hrnsht, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_HRODFXI2_1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_ramphit, // deathsound
+ 22 * FRACUNIT, // speed
+ 12 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 10, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_RAINPLR1
+ -1, // doomednum
+ S_RAINPLR1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_RAINPLR1X_1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 12 * FRACUNIT, // speed
+ 5 * FRACUNIT, // radius
+ 12 * FRACUNIT, // height
+ 100, // mass
+ 5, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_RAINPLR2
+ -1, // doomednum
+ S_RAINPLR2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_RAINPLR2X_1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 12 * FRACUNIT, // speed
+ 5 * FRACUNIT, // radius
+ 12 * FRACUNIT, // height
+ 100, // mass
+ 5, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_RAINPLR3
+ -1, // doomednum
+ S_RAINPLR3_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_RAINPLR3X_1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 12 * FRACUNIT, // speed
+ 5 * FRACUNIT, // radius
+ 12 * FRACUNIT, // height
+ 100, // mass
+ 5, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_RAINPLR4
+ -1, // doomednum
+ S_RAINPLR4_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_RAINPLR4X_1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 12 * FRACUNIT, // speed
+ 5 * FRACUNIT, // radius
+ 12 * FRACUNIT, // height
+ 100, // mass
+ 5, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_GOLDWANDFX1
+ -1, // doomednum
+ S_GWANDFX1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_GWANDFXI1_1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_gldhit, // deathsound
+ 22 * FRACUNIT, // speed
+ 10 * FRACUNIT, // radius
+ 6 * FRACUNIT, // height
+ 100, // mass
+ 2, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_GOLDWANDFX2
+ -1, // doomednum
+ S_GWANDFX2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_GWANDFXI1_1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 18 * FRACUNIT, // speed
+ 10 * FRACUNIT, // radius
+ 6 * FRACUNIT, // height
+ 100, // mass
+ 1, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_GOLDWANDPUFF1
+ -1, // doomednum
+ S_GWANDPUFF1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_GOLDWANDPUFF2
+ -1, // doomednum
+ S_GWANDFXI1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_WPHOENIXROD
+ 2003, // doomednum
+ S_WPHX, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_PHOENIXFX1
+ -1, // doomednum
+ S_PHOENIXFX1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_phosht, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_PHOENIXFXI1_1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_phohit, // deathsound
+ 20 * FRACUNIT, // speed
+ 11 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 20, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_THRUGHOST | MF2_NOTELEPORT // flags2
+ },
+
+ // The following thing is present in the mobjinfo table from Heretic 1.0,
+ // but not in Heretic 1.3 (ie. it was removed). It has been re-inserted
+ // here to support HHE patches.
+
+ { // MT_PHOENIXFX_REMOVED
+ -1, // doomednum
+ S_PHOENIXFXIX_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_PHOENIXFXIX_3, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 2 * FRACUNIT, // radius
+ 4 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_PHOENIXPUFF
+ -1, // doomednum
+ S_PHOENIXPUFF1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags
+ MF2_NOTELEPORT | MF2_CANNOTPUSH // flags2
+ },
+
+ { // MT_PHOENIXFX2
+ -1, // doomednum
+ S_PHOENIXFX2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_PHOENIXFXI2_1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 10 * FRACUNIT, // speed
+ 6 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 2, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_FIREDAMAGE // flags2
+ },
+
+ { // MT_MISC15
+ 2001, // doomednum
+ S_WBOW, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_CRBOWFX1
+ -1, // doomednum
+ S_CRBOWFX1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_bowsht, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_CRBOWFXI1_1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_hrnhit, // deathsound
+ 30 * FRACUNIT, // speed
+ 11 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 10, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_CRBOWFX2
+ -1, // doomednum
+ S_CRBOWFX2, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_bowsht, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_CRBOWFXI1_1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_hrnhit, // deathsound
+ 32 * FRACUNIT, // speed
+ 11 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 6, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_CRBOWFX3
+ -1, // doomednum
+ S_CRBOWFX3, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_CRBOWFXI3_1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_hrnhit, // deathsound
+ 20 * FRACUNIT, // speed
+ 11 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 2, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_WINDTHRUST | MF2_THRUGHOST | MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_CRBOWFX4
+ -1, // doomednum
+ S_CRBOWFX4_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP, // flags
+ MF2_LOGRAV // flags2
+ },
+
+ { // MT_BLOOD
+ -1, // doomednum
+ S_BLOOD1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP, // flags
+ 0 // flags2
+ },
+
+ { // MT_BLOODSPLATTER
+ -1, // doomednum
+ S_BLOODSPLATTER1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_BLOODSPLATTERX, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 2 * FRACUNIT, // radius
+ 4 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF, // flags
+ MF2_NOTELEPORT | MF2_CANNOTPUSH // flags2
+ },
+
+ { // MT_PLAYER
+ -1, // doomednum
+ S_PLAY, // spawnstate
+ 100, // spawnhealth
+ S_PLAY_RUN1, // seestate
+ sfx_None, // seesound
+ 0, // reactiontime
+ sfx_None, // attacksound
+ S_PLAY_PAIN, // painstate
+ 255, // painchance
+ sfx_plrpai, // painsound
+ S_NULL, // meleestate
+ S_PLAY_ATK1, // missilestate
+ S_NULL, // crashstate
+ S_PLAY_DIE1, // deathstate
+ S_PLAY_XDIE1, // xdeathstate
+ sfx_plrdth, // deathsound
+ 0, // speed
+ 16 * FRACUNIT, // radius
+ 56 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_DROPOFF | MF_PICKUP | MF_NOTDMATCH, // flags
+ MF2_WINDTHRUST | MF2_FOOTCLIP | MF2_SLIDE | MF2_PASSMOBJ | MF2_TELESTOMP // flags2
+ },
+
+ { // MT_BLOODYSKULL
+ -1, // doomednum
+ S_BLOODYSKULL1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 4 * FRACUNIT, // radius
+ 4 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF, // flags
+ MF2_LOGRAV | MF2_CANNOTPUSH // flags2
+ },
+
+ { // MT_CHICPLAYER
+ -1, // doomednum
+ S_CHICPLAY, // spawnstate
+ 100, // spawnhealth
+ S_CHICPLAY_RUN1, // seestate
+ sfx_None, // seesound
+ 0, // reactiontime
+ sfx_None, // attacksound
+ S_CHICPLAY_PAIN, // painstate
+ 255, // painchance
+ sfx_chicpai, // painsound
+ S_NULL, // meleestate
+ S_CHICPLAY_ATK1, // missilestate
+ S_NULL, // crashstate
+ S_CHICKEN_DIE1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_chicdth, // deathsound
+ 0, // speed
+ 16 * FRACUNIT, // radius
+ 24 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_DROPOFF | MF_NOTDMATCH, // flags
+ MF2_WINDTHRUST | MF2_SLIDE | MF2_PASSMOBJ | MF2_FOOTCLIP | MF2_LOGRAV | MF2_TELESTOMP // flags2
+ },
+
+ { // MT_CHICKEN
+ -1, // doomednum
+ S_CHICKEN_LOOK1, // spawnstate
+ 10, // spawnhealth
+ S_CHICKEN_WALK1, // seestate
+ sfx_chicpai, // seesound
+ 8, // reactiontime
+ sfx_chicatk, // attacksound
+ S_CHICKEN_PAIN1, // painstate
+ 200, // painchance
+ sfx_chicpai, // painsound
+ S_CHICKEN_ATK1, // meleestate
+ 0, // missilestate
+ S_NULL, // crashstate
+ S_CHICKEN_DIE1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_chicdth, // deathsound
+ 4, // speed
+ 9 * FRACUNIT, // radius
+ 22 * FRACUNIT, // height
+ 40, // mass
+ 0, // damage
+ sfx_chicact, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_DROPOFF, // flags
+ MF2_WINDTHRUST | MF2_FOOTCLIP | MF2_PASSMOBJ // flags2
+ },
+
+ { // MT_FEATHER
+ -1, // doomednum
+ S_FEATHER1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_FEATHERX, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 2 * FRACUNIT, // radius
+ 4 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF, // flags
+ MF2_NOTELEPORT | MF2_LOGRAV | MF2_CANNOTPUSH | MF2_WINDTHRUST // flags2
+ },
+
+ { // MT_MUMMY
+ 68, // doomednum
+ S_MUMMY_LOOK1, // spawnstate
+ 80, // spawnhealth
+ S_MUMMY_WALK1, // seestate
+ sfx_mumsit, // seesound
+ 8, // reactiontime
+ sfx_mumat1, // attacksound
+ S_MUMMY_PAIN1, // painstate
+ 128, // painchance
+ sfx_mumpai, // painsound
+ S_MUMMY_ATK1, // meleestate
+ 0, // missilestate
+ S_NULL, // crashstate
+ S_MUMMY_DIE1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_mumdth, // deathsound
+ 12, // speed
+ 22 * FRACUNIT, // radius
+ 62 * FRACUNIT, // height
+ 75, // mass
+ 0, // damage
+ sfx_mumact, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags
+ MF2_FOOTCLIP | MF2_PASSMOBJ // flags2
+ },
+
+ { // MT_MUMMYLEADER
+ 45, // doomednum
+ S_MUMMY_LOOK1, // spawnstate
+ 100, // spawnhealth
+ S_MUMMY_WALK1, // seestate
+ sfx_mumsit, // seesound
+ 8, // reactiontime
+ sfx_mumat1, // attacksound
+ S_MUMMY_PAIN1, // painstate
+ 64, // painchance
+ sfx_mumpai, // painsound
+ S_MUMMY_ATK1, // meleestate
+ S_MUMMYL_ATK1, // missilestate
+ S_NULL, // crashstate
+ S_MUMMY_DIE1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_mumdth, // deathsound
+ 12, // speed
+ 22 * FRACUNIT, // radius
+ 62 * FRACUNIT, // height
+ 75, // mass
+ 0, // damage
+ sfx_mumact, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags
+ MF2_FOOTCLIP | MF2_PASSMOBJ // flags2
+ },
+
+ { // MT_MUMMYGHOST
+ 69, // doomednum
+ S_MUMMY_LOOK1, // spawnstate
+ 80, // spawnhealth
+ S_MUMMY_WALK1, // seestate
+ sfx_mumsit, // seesound
+ 8, // reactiontime
+ sfx_mumat1, // attacksound
+ S_MUMMY_PAIN1, // painstate
+ 128, // painchance
+ sfx_mumpai, // painsound
+ S_MUMMY_ATK1, // meleestate
+ 0, // missilestate
+ S_NULL, // crashstate
+ S_MUMMY_DIE1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_mumdth, // deathsound
+ 12, // speed
+ 22 * FRACUNIT, // radius
+ 62 * FRACUNIT, // height
+ 75, // mass
+ 0, // damage
+ sfx_mumact, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_SHADOW, // flags
+ MF2_FOOTCLIP | MF2_PASSMOBJ // flags2
+ },
+
+ { // MT_MUMMYLEADERGHOST
+ 46, // doomednum
+ S_MUMMY_LOOK1, // spawnstate
+ 100, // spawnhealth
+ S_MUMMY_WALK1, // seestate
+ sfx_mumsit, // seesound
+ 8, // reactiontime
+ sfx_mumat1, // attacksound
+ S_MUMMY_PAIN1, // painstate
+ 64, // painchance
+ sfx_mumpai, // painsound
+ S_MUMMY_ATK1, // meleestate
+ S_MUMMYL_ATK1, // missilestate
+ S_NULL, // crashstate
+ S_MUMMY_DIE1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_mumdth, // deathsound
+ 12, // speed
+ 22 * FRACUNIT, // radius
+ 62 * FRACUNIT, // height
+ 75, // mass
+ 0, // damage
+ sfx_mumact, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_SHADOW, // flags
+ MF2_FOOTCLIP | MF2_PASSMOBJ // flags2
+ },
+
+ { // MT_MUMMYSOUL
+ -1, // doomednum
+ S_MUMMY_SOUL1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_MUMMYFX1
+ -1, // doomednum
+ S_MUMMYFX1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_MUMMYFXI1_1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 9 * FRACUNIT, // speed
+ 8 * FRACUNIT, // radius
+ 14 * FRACUNIT, // height
+ 100, // mass
+ 4, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_BEAST
+ 70, // doomednum
+ S_BEAST_LOOK1, // spawnstate
+ 220, // spawnhealth
+ S_BEAST_WALK1, // seestate
+ sfx_bstsit, // seesound
+ 8, // reactiontime
+ sfx_bstatk, // attacksound
+ S_BEAST_PAIN1, // painstate
+ 100, // painchance
+ sfx_bstpai, // painsound
+ 0, // meleestate
+ S_BEAST_ATK1, // missilestate
+ S_NULL, // crashstate
+ S_BEAST_DIE1, // deathstate
+ S_BEAST_XDIE1, // xdeathstate
+ sfx_bstdth, // deathsound
+ 14, // speed
+ 32 * FRACUNIT, // radius
+ 74 * FRACUNIT, // height
+ 200, // mass
+ 0, // damage
+ sfx_bstact, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags
+ MF2_FOOTCLIP | MF2_PASSMOBJ // flags2
+ },
+
+ { // MT_BEASTBALL
+ -1, // doomednum
+ S_BEASTBALL1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_BEASTBALLX1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 12 * FRACUNIT, // speed
+ 9 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 4, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_WINDTHRUST | MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_BURNBALL
+ -1, // doomednum
+ S_BURNBALL1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_BEASTBALLX1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 10 * FRACUNIT, // speed
+ 6 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 2, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_MISSILE, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_BURNBALLFB
+ -1, // doomednum
+ S_BURNBALLFB1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_BEASTBALLX1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 10 * FRACUNIT, // speed
+ 6 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 2, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_MISSILE, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_PUFFY
+ -1, // doomednum
+ S_PUFFY1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_PUFFY1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 10 * FRACUNIT, // speed
+ 6 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 2, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_MISSILE, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_SNAKE
+ 92, // doomednum
+ S_SNAKE_LOOK1, // spawnstate
+ 280, // spawnhealth
+ S_SNAKE_WALK1, // seestate
+ sfx_snksit, // seesound
+ 8, // reactiontime
+ sfx_snkatk, // attacksound
+ S_SNAKE_PAIN1, // painstate
+ 48, // painchance
+ sfx_snkpai, // painsound
+ 0, // meleestate
+ S_SNAKE_ATK1, // missilestate
+ S_NULL, // crashstate
+ S_SNAKE_DIE1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_snkdth, // deathsound
+ 10, // speed
+ 22 * FRACUNIT, // radius
+ 70 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_snkact, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags
+ MF2_FOOTCLIP | MF2_PASSMOBJ // flags2
+ },
+
+ { // MT_SNAKEPRO_A
+ -1, // doomednum
+ S_SNAKEPRO_A1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SNAKEPRO_AX1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 14 * FRACUNIT, // speed
+ 12 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 1, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_WINDTHRUST | MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_SNAKEPRO_B
+ -1, // doomednum
+ S_SNAKEPRO_B1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SNAKEPRO_BX1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 14 * FRACUNIT, // speed
+ 12 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 3, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_HEAD
+ 6, // doomednum
+ S_HEAD_LOOK, // spawnstate
+ 700, // spawnhealth
+ S_HEAD_FLOAT, // seestate
+ sfx_hedsit, // seesound
+ 8, // reactiontime
+ sfx_hedat1, // attacksound
+ S_HEAD_PAIN1, // painstate
+ 32, // painchance
+ sfx_hedpai, // painsound
+ 0, // meleestate
+ S_HEAD_ATK1, // missilestate
+ S_NULL, // crashstate
+ S_HEAD_DIE1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_heddth, // deathsound
+ 6, // speed
+ 40 * FRACUNIT, // radius
+ 72 * FRACUNIT, // height
+ 325, // mass
+ 0, // damage
+ sfx_hedact, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_NOBLOOD, // flags
+ MF2_PASSMOBJ // flags2
+ },
+
+ { // MT_HEADFX1
+ -1, // doomednum
+ S_HEADFX1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_HEADFXI1_1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 13 * FRACUNIT, // speed
+ 12 * FRACUNIT, // radius
+ 6 * FRACUNIT, // height
+ 100, // mass
+ 1, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_THRUGHOST // flags2
+ },
+
+ { // MT_HEADFX2
+ -1, // doomednum
+ S_HEADFX2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_HEADFXI2_1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 8 * FRACUNIT, // speed
+ 12 * FRACUNIT, // radius
+ 6 * FRACUNIT, // height
+ 100, // mass
+ 3, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_HEADFX3
+ -1, // doomednum
+ S_HEADFX3_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_HEADFXI3_1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 10 * FRACUNIT, // speed
+ 14 * FRACUNIT, // radius
+ 12 * FRACUNIT, // height
+ 100, // mass
+ 5, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_WINDTHRUST | MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_WHIRLWIND
+ -1, // doomednum
+ S_HEADFX4_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_HEADFXI4_1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 10 * FRACUNIT, // speed
+ 16 * FRACUNIT, // radius
+ 74 * FRACUNIT, // height
+ 100, // mass
+ 1, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY | MF_SHADOW, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_CLINK
+ 90, // doomednum
+ S_CLINK_LOOK1, // spawnstate
+ 150, // spawnhealth
+ S_CLINK_WALK1, // seestate
+ sfx_clksit, // seesound
+ 8, // reactiontime
+ sfx_clkatk, // attacksound
+ S_CLINK_PAIN1, // painstate
+ 32, // painchance
+ sfx_clkpai, // painsound
+ S_CLINK_ATK1, // meleestate
+ 0, // missilestate
+ S_NULL, // crashstate
+ S_CLINK_DIE1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_clkdth, // deathsound
+ 14, // speed
+ 20 * FRACUNIT, // radius
+ 64 * FRACUNIT, // height
+ 75, // mass
+ 0, // damage
+ sfx_clkact, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_NOBLOOD, // flags
+ MF2_FOOTCLIP | MF2_PASSMOBJ // flags2
+ },
+
+ { // MT_WIZARD
+ 15, // doomednum
+ S_WIZARD_LOOK1, // spawnstate
+ 180, // spawnhealth
+ S_WIZARD_WALK1, // seestate
+ sfx_wizsit, // seesound
+ 8, // reactiontime
+ sfx_wizatk, // attacksound
+ S_WIZARD_PAIN1, // painstate
+ 64, // painchance
+ sfx_wizpai, // painsound
+ 0, // meleestate
+ S_WIZARD_ATK1, // missilestate
+ S_NULL, // crashstate
+ S_WIZARD_DIE1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_wizdth, // deathsound
+ 12, // speed
+ 16 * FRACUNIT, // radius
+ 68 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_wizact, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_FLOAT | MF_NOGRAVITY, // flags
+ MF2_PASSMOBJ // flags2
+ },
+
+ { // MT_WIZFX1
+ -1, // doomednum
+ S_WIZFX1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_WIZFXI1_1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 18 * FRACUNIT, // speed
+ 10 * FRACUNIT, // radius
+ 6 * FRACUNIT, // height
+ 100, // mass
+ 3, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_IMP
+ 66, // doomednum
+ S_IMP_LOOK1, // spawnstate
+ 40, // spawnhealth
+ S_IMP_FLY1, // seestate
+ sfx_impsit, // seesound
+ 8, // reactiontime
+ sfx_impat1, // attacksound
+ S_IMP_PAIN1, // painstate
+ 200, // painchance
+ sfx_imppai, // painsound
+ S_IMP_MEATK1, // meleestate
+ S_IMP_MSATK1_1, // missilestate
+ S_IMP_CRASH1, // crashstate
+ S_IMP_DIE1, // deathstate
+ S_IMP_XDIE1, // xdeathstate
+ sfx_impdth, // deathsound
+ 10, // speed
+ 16 * FRACUNIT, // radius
+ 36 * FRACUNIT, // height
+ 50, // mass
+ 0, // damage
+ sfx_impact, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_FLOAT | MF_NOGRAVITY | MF_COUNTKILL, // flags
+ MF2_SPAWNFLOAT | MF2_PASSMOBJ // flags2
+ },
+
+ { // MT_IMPLEADER
+ 5, // doomednum
+ S_IMP_LOOK1, // spawnstate
+ 80, // spawnhealth
+ S_IMP_FLY1, // seestate
+ sfx_impsit, // seesound
+ 8, // reactiontime
+ sfx_impat2, // attacksound
+ S_IMP_PAIN1, // painstate
+ 200, // painchance
+ sfx_imppai, // painsound
+ 0, // meleestate
+ S_IMP_MSATK2_1, // missilestate
+ S_IMP_CRASH1, // crashstate
+ S_IMP_DIE1, // deathstate
+ S_IMP_XDIE1, // xdeathstate
+ sfx_impdth, // deathsound
+ 10, // speed
+ 16 * FRACUNIT, // radius
+ 36 * FRACUNIT, // height
+ 50, // mass
+ 0, // damage
+ sfx_impact, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_FLOAT | MF_NOGRAVITY | MF_COUNTKILL, // flags
+ MF2_SPAWNFLOAT | MF2_PASSMOBJ // flags2
+ },
+
+ { // MT_IMPCHUNK1
+ -1, // doomednum
+ S_IMP_CHUNKA1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP, // flags
+ 0 // flags2
+ },
+
+ { // MT_IMPCHUNK2
+ -1, // doomednum
+ S_IMP_CHUNKB1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP, // flags
+ 0 // flags2
+ },
+
+ { // MT_IMPBALL
+ -1, // doomednum
+ S_IMPFX1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_IMPFXI1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 10 * FRACUNIT, // speed
+ 8 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 1, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_WINDTHRUST | MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_KNIGHT
+ 64, // doomednum
+ S_KNIGHT_STND1, // spawnstate
+ 200, // spawnhealth
+ S_KNIGHT_WALK1, // seestate
+ sfx_kgtsit, // seesound
+ 8, // reactiontime
+ sfx_kgtatk, // attacksound
+ S_KNIGHT_PAIN1, // painstate
+ 100, // painchance
+ sfx_kgtpai, // painsound
+ S_KNIGHT_ATK1, // meleestate
+ S_KNIGHT_ATK1, // missilestate
+ S_NULL, // crashstate
+ S_KNIGHT_DIE1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_kgtdth, // deathsound
+ 12, // speed
+ 24 * FRACUNIT, // radius
+ 78 * FRACUNIT, // height
+ 150, // mass
+ 0, // damage
+ sfx_kgtact, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags
+ MF2_FOOTCLIP | MF2_PASSMOBJ // flags2
+ },
+
+ { // MT_KNIGHTGHOST
+ 65, // doomednum
+ S_KNIGHT_STND1, // spawnstate
+ 200, // spawnhealth
+ S_KNIGHT_WALK1, // seestate
+ sfx_kgtsit, // seesound
+ 8, // reactiontime
+ sfx_kgtatk, // attacksound
+ S_KNIGHT_PAIN1, // painstate
+ 100, // painchance
+ sfx_kgtpai, // painsound
+ S_KNIGHT_ATK1, // meleestate
+ S_KNIGHT_ATK1, // missilestate
+ S_NULL, // crashstate
+ S_KNIGHT_DIE1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_kgtdth, // deathsound
+ 12, // speed
+ 24 * FRACUNIT, // radius
+ 78 * FRACUNIT, // height
+ 150, // mass
+ 0, // damage
+ sfx_kgtact, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_SHADOW, // flags
+ MF2_FOOTCLIP | MF2_PASSMOBJ // flags2
+ },
+
+ { // MT_KNIGHTAXE
+ -1, // doomednum
+ S_SPINAXE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SPINAXEX1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_hrnhit, // deathsound
+ 9 * FRACUNIT, // speed
+ 10 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 2, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_WINDTHRUST | MF2_NOTELEPORT | MF2_THRUGHOST // flags2
+ },
+
+ { // MT_REDAXE
+ -1, // doomednum
+ S_REDAXE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_REDAXEX1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_hrnhit, // deathsound
+ 9 * FRACUNIT, // speed
+ 10 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 7, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_THRUGHOST // flags2
+ },
+
+ { // MT_SORCERER1
+ 7, // doomednum
+ S_SRCR1_LOOK1, // spawnstate
+ 2000, // spawnhealth
+ S_SRCR1_WALK1, // seestate
+ sfx_sbtsit, // seesound
+ 8, // reactiontime
+ sfx_sbtatk, // attacksound
+ S_SRCR1_PAIN1, // painstate
+ 56, // painchance
+ sfx_sbtpai, // painsound
+ 0, // meleestate
+ S_SRCR1_ATK1, // missilestate
+ S_NULL, // crashstate
+ S_SRCR1_DIE1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_sbtdth, // deathsound
+ 16, // speed
+ 28 * FRACUNIT, // radius
+ 100 * FRACUNIT, // height
+ 800, // mass
+ 0, // damage
+ sfx_sbtact, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags
+ MF2_FOOTCLIP | MF2_PASSMOBJ | MF2_BOSS // flags2
+ },
+
+ { // MT_SRCRFX1
+ -1, // doomednum
+ S_SRCRFX1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SRCRFXI1_1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 20 * FRACUNIT, // speed
+ 10 * FRACUNIT, // radius
+ 10 * FRACUNIT, // height
+ 100, // mass
+ 10, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_FIREDAMAGE // flags2
+ },
+
+ { // MT_SORCERER2
+ -1, // doomednum
+ S_SOR2_LOOK1, // spawnstate
+ 3500, // spawnhealth
+ S_SOR2_WALK1, // seestate
+ sfx_sorsit, // seesound
+ 8, // reactiontime
+ sfx_soratk, // attacksound
+ S_SOR2_PAIN1, // painstate
+ 32, // painchance
+ sfx_sorpai, // painsound
+ 0, // meleestate
+ S_SOR2_ATK1, // missilestate
+ S_NULL, // crashstate
+ S_SOR2_DIE1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 14, // speed
+ 16 * FRACUNIT, // radius
+ 70 * FRACUNIT, // height
+ 300, // mass
+ 0, // damage
+ sfx_soract, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_DROPOFF, // flags
+ MF2_FOOTCLIP | MF2_PASSMOBJ | MF2_BOSS // flags2
+ },
+
+ { // MT_SOR2FX1
+ -1, // doomednum
+ S_SOR2FX1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SOR2FXI1_1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 20 * FRACUNIT, // speed
+ 10 * FRACUNIT, // radius
+ 6 * FRACUNIT, // height
+ 100, // mass
+ 1, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_SOR2FXSPARK
+ -1, // doomednum
+ S_SOR2FXSPARK1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_CANNOTPUSH // flags2
+ },
+
+ { // MT_SOR2FX2
+ -1, // doomednum
+ S_SOR2FX2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SOR2FXI2_1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 6 * FRACUNIT, // speed
+ 10 * FRACUNIT, // radius
+ 6 * FRACUNIT, // height
+ 100, // mass
+ 10, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_SOR2TELEFADE
+ -1, // doomednum
+ S_SOR2TELEFADE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP, // flags
+ 0 // flags2
+ },
+
+ { // MT_MINOTAUR
+ 9, // doomednum
+ S_MNTR_LOOK1, // spawnstate
+ 3000, // spawnhealth
+ S_MNTR_WALK1, // seestate
+ sfx_minsit, // seesound
+ 8, // reactiontime
+ sfx_minat1, // attacksound
+ S_MNTR_PAIN1, // painstate
+ 25, // painchance
+ sfx_minpai, // painsound
+ S_MNTR_ATK1_1, // meleestate
+ S_MNTR_ATK2_1, // missilestate
+ S_NULL, // crashstate
+ S_MNTR_DIE1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_mindth, // deathsound
+ 16, // speed
+ 28 * FRACUNIT, // radius
+ 100 * FRACUNIT, // height
+ 800, // mass
+ 7, // damage
+ sfx_minact, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_DROPOFF, // flags
+ MF2_FOOTCLIP | MF2_PASSMOBJ | MF2_BOSS // flags2
+ },
+
+ { // MT_MNTRFX1
+ -1, // doomednum
+ S_MNTRFX1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_MNTRFXI1_1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 20 * FRACUNIT, // speed
+ 10 * FRACUNIT, // radius
+ 6 * FRACUNIT, // height
+ 100, // mass
+ 3, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_FIREDAMAGE // flags2
+ },
+
+ { // MT_MNTRFX2
+ -1, // doomednum
+ S_MNTRFX2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_MNTRFXI2_1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_phohit, // deathsound
+ 14 * FRACUNIT, // speed
+ 5 * FRACUNIT, // radius
+ 12 * FRACUNIT, // height
+ 100, // mass
+ 4, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_FIREDAMAGE // flags2
+ },
+
+ { // MT_MNTRFX3
+ -1, // doomednum
+ S_MNTRFX3_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_MNTRFXI2_1, // deathstate
+ S_NULL, // xdeathstate
+ sfx_phohit, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 4, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_FIREDAMAGE // flags2
+ },
+
+ { // MT_AKYY
+ 73, // doomednum
+ S_AKYY1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL | MF_NOTDMATCH, // flags
+ 0 // flags2
+ },
+
+ { // MT_BKYY
+ 79, // doomednum
+ S_BKYY1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL | MF_NOTDMATCH, // flags
+ 0 // flags2
+ },
+
+ { // MT_CKEY
+ 80, // doomednum
+ S_CKYY1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL | MF_NOTDMATCH, // flags
+ 0 // flags2
+ },
+
+ { // MT_AMGWNDWIMPY
+ 10, // doomednum
+ S_AMG1, // spawnstate
+ AMMO_GWND_WIMPY, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_AMGWNDHEFTY
+ 12, // doomednum
+ S_AMG2_1, // spawnstate
+ AMMO_GWND_HEFTY, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_AMMACEWIMPY
+ 13, // doomednum
+ S_AMM1, // spawnstate
+ AMMO_MACE_WIMPY, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_AMMACEHEFTY
+ 16, // doomednum
+ S_AMM2, // spawnstate
+ AMMO_MACE_HEFTY, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_AMCBOWWIMPY
+ 18, // doomednum
+ S_AMC1, // spawnstate
+ AMMO_CBOW_WIMPY, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_AMCBOWHEFTY
+ 19, // doomednum
+ S_AMC2_1, // spawnstate
+ AMMO_CBOW_HEFTY, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_AMSKRDWIMPY
+ 20, // doomednum
+ S_AMS1_1, // spawnstate
+ AMMO_SKRD_WIMPY, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_AMSKRDHEFTY
+ 21, // doomednum
+ S_AMS2_1, // spawnstate
+ AMMO_SKRD_HEFTY, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_AMPHRDWIMPY
+ 22, // doomednum
+ S_AMP1_1, // spawnstate
+ AMMO_PHRD_WIMPY, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_AMPHRDHEFTY
+ 23, // doomednum
+ S_AMP2_1, // spawnstate
+ AMMO_PHRD_HEFTY, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_AMBLSRWIMPY
+ 54, // doomednum
+ S_AMB1_1, // spawnstate
+ AMMO_BLSR_WIMPY, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_AMBLSRHEFTY
+ 55, // doomednum
+ S_AMB2_1, // spawnstate
+ AMMO_BLSR_HEFTY, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_SOUNDWIND
+ 42, // doomednum
+ S_SND_WIND, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_NOSECTOR, // flags
+ 0 // flags2
+ },
+
+ { // MT_SOUNDWATERFALL
+ 41, // doomednum
+ S_SND_WATERFALL, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_NOSECTOR, // flags
+ 0 // flags2
+ }
+};
diff --git a/src/heretic/info.h b/src/heretic/info.h
new file mode 100644
index 00000000..236826cb
--- /dev/null
+++ b/src/heretic/info.h
@@ -0,0 +1,1586 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef HERETIC_INFO_H
+#define HERETIC_INFO_H
+
+typedef enum
+{
+ SPR_IMPX,
+ SPR_ACLO,
+ SPR_PTN1,
+ SPR_SHLD,
+ SPR_SHD2,
+ SPR_BAGH,
+ SPR_SPMP,
+ SPR_INVS,
+ SPR_PTN2,
+ SPR_SOAR,
+ SPR_INVU,
+ SPR_PWBK,
+ SPR_EGGC,
+ SPR_EGGM,
+ SPR_FX01,
+ SPR_SPHL,
+ SPR_TRCH,
+ SPR_FBMB,
+ SPR_XPL1,
+ SPR_ATLP,
+ SPR_PPOD,
+ SPR_AMG1,
+ SPR_SPSH,
+ SPR_LVAS,
+ SPR_SLDG,
+ SPR_SKH1,
+ SPR_SKH2,
+ SPR_SKH3,
+ SPR_SKH4,
+ SPR_CHDL,
+ SPR_SRTC,
+ SPR_SMPL,
+ SPR_STGS,
+ SPR_STGL,
+ SPR_STCS,
+ SPR_STCL,
+ SPR_KFR1,
+ SPR_BARL,
+ SPR_BRPL,
+ SPR_MOS1,
+ SPR_MOS2,
+ SPR_WTRH,
+ SPR_HCOR,
+ SPR_KGZ1,
+ SPR_KGZB,
+ SPR_KGZG,
+ SPR_KGZY,
+ SPR_VLCO,
+ SPR_VFBL,
+ SPR_VTFB,
+ SPR_SFFI,
+ SPR_TGLT,
+ SPR_TELE,
+ SPR_STFF,
+ SPR_PUF3,
+ SPR_PUF4,
+ SPR_BEAK,
+ SPR_WGNT,
+ SPR_GAUN,
+ SPR_PUF1,
+ SPR_WBLS,
+ SPR_BLSR,
+ SPR_FX18,
+ SPR_FX17,
+ SPR_WMCE,
+ SPR_MACE,
+ SPR_FX02,
+ SPR_WSKL,
+ SPR_HROD,
+ SPR_FX00,
+ SPR_FX20,
+ SPR_FX21,
+ SPR_FX22,
+ SPR_FX23,
+ SPR_GWND,
+ SPR_PUF2,
+ SPR_WPHX,
+ SPR_PHNX,
+ SPR_FX04,
+ SPR_FX08,
+ SPR_FX09,
+ SPR_WBOW,
+ SPR_CRBW,
+ SPR_FX03,
+ SPR_BLOD,
+ SPR_PLAY,
+ SPR_FDTH,
+ SPR_BSKL,
+ SPR_CHKN,
+ SPR_MUMM,
+ SPR_FX15,
+ SPR_BEAS,
+ SPR_FRB1,
+ SPR_SNKE,
+ SPR_SNFX,
+ SPR_HEAD,
+ SPR_FX05,
+ SPR_FX06,
+ SPR_FX07,
+ SPR_CLNK,
+ SPR_WZRD,
+ SPR_FX11,
+ SPR_FX10,
+ SPR_KNIG,
+ SPR_SPAX,
+ SPR_RAXE,
+ SPR_SRCR,
+ SPR_FX14,
+ SPR_SOR2,
+ SPR_SDTH,
+ SPR_FX16,
+ SPR_MNTR,
+ SPR_FX12,
+ SPR_FX13,
+ SPR_AKYY,
+ SPR_BKYY,
+ SPR_CKYY,
+ SPR_AMG2,
+ SPR_AMM1,
+ SPR_AMM2,
+ SPR_AMC1,
+ SPR_AMC2,
+ SPR_AMS1,
+ SPR_AMS2,
+ SPR_AMP1,
+ SPR_AMP2,
+ SPR_AMB1,
+ SPR_AMB2,
+ NUMSPRITES
+} spritenum_t;
+
+typedef enum
+{
+ S_NULL,
+ S_FREETARGMOBJ,
+ S_ITEM_PTN1_1,
+ S_ITEM_PTN1_2,
+ S_ITEM_PTN1_3,
+ S_ITEM_SHLD1,
+ S_ITEM_SHD2_1,
+ S_ITEM_BAGH1,
+ S_ITEM_SPMP1,
+ S_HIDESPECIAL1,
+ S_HIDESPECIAL2,
+ S_HIDESPECIAL3,
+ S_HIDESPECIAL4,
+ S_HIDESPECIAL5,
+ S_HIDESPECIAL6,
+ S_HIDESPECIAL7,
+ S_HIDESPECIAL8,
+ S_HIDESPECIAL9,
+ S_HIDESPECIAL10,
+ S_HIDESPECIAL11,
+ S_DORMANTARTI1,
+ S_DORMANTARTI2,
+ S_DORMANTARTI3,
+ S_DORMANTARTI4,
+ S_DORMANTARTI5,
+ S_DORMANTARTI6,
+ S_DORMANTARTI7,
+ S_DORMANTARTI8,
+ S_DORMANTARTI9,
+ S_DORMANTARTI10,
+ S_DORMANTARTI11,
+ S_DORMANTARTI12,
+ S_DORMANTARTI13,
+ S_DORMANTARTI14,
+ S_DORMANTARTI15,
+ S_DORMANTARTI16,
+ S_DORMANTARTI17,
+ S_DORMANTARTI18,
+ S_DORMANTARTI19,
+ S_DORMANTARTI20,
+ S_DORMANTARTI21,
+ S_DEADARTI1,
+ S_DEADARTI2,
+ S_DEADARTI3,
+ S_DEADARTI4,
+ S_DEADARTI5,
+ S_DEADARTI6,
+ S_DEADARTI7,
+ S_DEADARTI8,
+ S_DEADARTI9,
+ S_DEADARTI10,
+ S_ARTI_INVS1,
+ S_ARTI_PTN2_1,
+ S_ARTI_PTN2_2,
+ S_ARTI_PTN2_3,
+ S_ARTI_SOAR1,
+ S_ARTI_SOAR2,
+ S_ARTI_SOAR3,
+ S_ARTI_SOAR4,
+ S_ARTI_INVU1,
+ S_ARTI_INVU2,
+ S_ARTI_INVU3,
+ S_ARTI_INVU4,
+ S_ARTI_PWBK1,
+ S_ARTI_EGGC1,
+ S_ARTI_EGGC2,
+ S_ARTI_EGGC3,
+ S_ARTI_EGGC4,
+ S_EGGFX1,
+ S_EGGFX2,
+ S_EGGFX3,
+ S_EGGFX4,
+ S_EGGFX5,
+ S_EGGFXI1_1,
+ S_EGGFXI1_2,
+ S_EGGFXI1_3,
+ S_EGGFXI1_4,
+ S_ARTI_SPHL1,
+ S_ARTI_TRCH1,
+ S_ARTI_TRCH2,
+ S_ARTI_TRCH3,
+ S_ARTI_FBMB1,
+ S_FIREBOMB1,
+ S_FIREBOMB2,
+ S_FIREBOMB3,
+ S_FIREBOMB4,
+ S_FIREBOMB5,
+ S_FIREBOMB6,
+ S_FIREBOMB7,
+ S_FIREBOMB8,
+ S_FIREBOMB9,
+ S_FIREBOMB10,
+ S_FIREBOMB11,
+ S_ARTI_ATLP1,
+ S_ARTI_ATLP2,
+ S_ARTI_ATLP3,
+ S_ARTI_ATLP4,
+ S_POD_WAIT1,
+ S_POD_PAIN1,
+ S_POD_DIE1,
+ S_POD_DIE2,
+ S_POD_DIE3,
+ S_POD_DIE4,
+ S_POD_GROW1,
+ S_POD_GROW2,
+ S_POD_GROW3,
+ S_POD_GROW4,
+ S_POD_GROW5,
+ S_POD_GROW6,
+ S_POD_GROW7,
+ S_POD_GROW8,
+ S_PODGOO1,
+ S_PODGOO2,
+ S_PODGOOX,
+ S_PODGENERATOR,
+ S_SPLASH1,
+ S_SPLASH2,
+ S_SPLASH3,
+ S_SPLASH4,
+ S_SPLASHX,
+ S_SPLASHBASE1,
+ S_SPLASHBASE2,
+ S_SPLASHBASE3,
+ S_SPLASHBASE4,
+ S_SPLASHBASE5,
+ S_SPLASHBASE6,
+ S_SPLASHBASE7,
+ S_LAVASPLASH1,
+ S_LAVASPLASH2,
+ S_LAVASPLASH3,
+ S_LAVASPLASH4,
+ S_LAVASPLASH5,
+ S_LAVASPLASH6,
+ S_LAVASMOKE1,
+ S_LAVASMOKE2,
+ S_LAVASMOKE3,
+ S_LAVASMOKE4,
+ S_LAVASMOKE5,
+ S_SLUDGECHUNK1,
+ S_SLUDGECHUNK2,
+ S_SLUDGECHUNK3,
+ S_SLUDGECHUNK4,
+ S_SLUDGECHUNKX,
+ S_SLUDGESPLASH1,
+ S_SLUDGESPLASH2,
+ S_SLUDGESPLASH3,
+ S_SLUDGESPLASH4,
+ S_SKULLHANG70_1,
+ S_SKULLHANG60_1,
+ S_SKULLHANG45_1,
+ S_SKULLHANG35_1,
+ S_CHANDELIER1,
+ S_CHANDELIER2,
+ S_CHANDELIER3,
+ S_SERPTORCH1,
+ S_SERPTORCH2,
+ S_SERPTORCH3,
+ S_SMALLPILLAR,
+ S_STALAGMITESMALL,
+ S_STALAGMITELARGE,
+ S_STALACTITESMALL,
+ S_STALACTITELARGE,
+ S_FIREBRAZIER1,
+ S_FIREBRAZIER2,
+ S_FIREBRAZIER3,
+ S_FIREBRAZIER4,
+ S_FIREBRAZIER5,
+ S_FIREBRAZIER6,
+ S_FIREBRAZIER7,
+ S_FIREBRAZIER8,
+ S_BARREL,
+ S_BRPILLAR,
+ S_MOSS1,
+ S_MOSS2,
+ S_WALLTORCH1,
+ S_WALLTORCH2,
+ S_WALLTORCH3,
+ S_HANGINGCORPSE,
+ S_KEYGIZMO1,
+ S_KEYGIZMO2,
+ S_KEYGIZMO3,
+ S_KGZ_START,
+ S_KGZ_BLUEFLOAT1,
+ S_KGZ_GREENFLOAT1,
+ S_KGZ_YELLOWFLOAT1,
+ S_VOLCANO1,
+ S_VOLCANO2,
+ S_VOLCANO3,
+ S_VOLCANO4,
+ S_VOLCANO5,
+ S_VOLCANO6,
+ S_VOLCANO7,
+ S_VOLCANO8,
+ S_VOLCANO9,
+ S_VOLCANOBALL1,
+ S_VOLCANOBALL2,
+ S_VOLCANOBALLX1,
+ S_VOLCANOBALLX2,
+ S_VOLCANOBALLX3,
+ S_VOLCANOBALLX4,
+ S_VOLCANOBALLX5,
+ S_VOLCANOBALLX6,
+ S_VOLCANOTBALL1,
+ S_VOLCANOTBALL2,
+ S_VOLCANOTBALLX1,
+ S_VOLCANOTBALLX2,
+ S_VOLCANOTBALLX3,
+ S_VOLCANOTBALLX4,
+ S_VOLCANOTBALLX5,
+ S_VOLCANOTBALLX6,
+ S_VOLCANOTBALLX7,
+ S_TELEGLITGEN1,
+ S_TELEGLITGEN2,
+ S_TELEGLITTER1_1,
+ S_TELEGLITTER1_2,
+ S_TELEGLITTER1_3,
+ S_TELEGLITTER1_4,
+ S_TELEGLITTER1_5,
+ S_TELEGLITTER2_1,
+ S_TELEGLITTER2_2,
+ S_TELEGLITTER2_3,
+ S_TELEGLITTER2_4,
+ S_TELEGLITTER2_5,
+ S_TFOG1,
+ S_TFOG2,
+ S_TFOG3,
+ S_TFOG4,
+ S_TFOG5,
+ S_TFOG6,
+ S_TFOG7,
+ S_TFOG8,
+ S_TFOG9,
+ S_TFOG10,
+ S_TFOG11,
+ S_TFOG12,
+ S_TFOG13,
+ S_LIGHTDONE,
+ S_STAFFREADY,
+ S_STAFFDOWN,
+ S_STAFFUP,
+ S_STAFFREADY2_1,
+ S_STAFFREADY2_2,
+ S_STAFFREADY2_3,
+ S_STAFFDOWN2,
+ S_STAFFUP2,
+ S_STAFFATK1_1,
+ S_STAFFATK1_2,
+ S_STAFFATK1_3,
+ S_STAFFATK2_1,
+ S_STAFFATK2_2,
+ S_STAFFATK2_3,
+ S_STAFFPUFF1,
+ S_STAFFPUFF2,
+ S_STAFFPUFF3,
+ S_STAFFPUFF4,
+ S_STAFFPUFF2_1,
+ S_STAFFPUFF2_2,
+ S_STAFFPUFF2_3,
+ S_STAFFPUFF2_4,
+ S_STAFFPUFF2_5,
+ S_STAFFPUFF2_6,
+ S_BEAKREADY,
+ S_BEAKDOWN,
+ S_BEAKUP,
+ S_BEAKATK1_1,
+ S_BEAKATK2_1,
+ S_WGNT,
+ S_GAUNTLETREADY,
+ S_GAUNTLETDOWN,
+ S_GAUNTLETUP,
+ S_GAUNTLETREADY2_1,
+ S_GAUNTLETREADY2_2,
+ S_GAUNTLETREADY2_3,
+ S_GAUNTLETDOWN2,
+ S_GAUNTLETUP2,
+ S_GAUNTLETATK1_1,
+ S_GAUNTLETATK1_2,
+ S_GAUNTLETATK1_3,
+ S_GAUNTLETATK1_4,
+ S_GAUNTLETATK1_5,
+ S_GAUNTLETATK1_6,
+ S_GAUNTLETATK1_7,
+ S_GAUNTLETATK2_1,
+ S_GAUNTLETATK2_2,
+ S_GAUNTLETATK2_3,
+ S_GAUNTLETATK2_4,
+ S_GAUNTLETATK2_5,
+ S_GAUNTLETATK2_6,
+ S_GAUNTLETATK2_7,
+ S_GAUNTLETPUFF1_1,
+ S_GAUNTLETPUFF1_2,
+ S_GAUNTLETPUFF1_3,
+ S_GAUNTLETPUFF1_4,
+ S_GAUNTLETPUFF2_1,
+ S_GAUNTLETPUFF2_2,
+ S_GAUNTLETPUFF2_3,
+ S_GAUNTLETPUFF2_4,
+ S_BLSR,
+ S_BLASTERREADY,
+ S_BLASTERDOWN,
+ S_BLASTERUP,
+ S_BLASTERATK1_1,
+ S_BLASTERATK1_2,
+ S_BLASTERATK1_3,
+ S_BLASTERATK1_4,
+ S_BLASTERATK1_5,
+ S_BLASTERATK1_6,
+ S_BLASTERATK2_1,
+ S_BLASTERATK2_2,
+ S_BLASTERATK2_3,
+ S_BLASTERATK2_4,
+ S_BLASTERATK2_5,
+ S_BLASTERATK2_6,
+ S_BLASTERFX1_1,
+ S_BLASTERFXI1_1,
+ S_BLASTERFXI1_2,
+ S_BLASTERFXI1_3,
+ S_BLASTERFXI1_4,
+ S_BLASTERFXI1_5,
+ S_BLASTERFXI1_6,
+ S_BLASTERFXI1_7,
+ S_BLASTERSMOKE1,
+ S_BLASTERSMOKE2,
+ S_BLASTERSMOKE3,
+ S_BLASTERSMOKE4,
+ S_BLASTERSMOKE5,
+ S_RIPPER1,
+ S_RIPPER2,
+ S_RIPPERX1,
+ S_RIPPERX2,
+ S_RIPPERX3,
+ S_RIPPERX4,
+ S_RIPPERX5,
+ S_BLASTERPUFF1_1,
+ S_BLASTERPUFF1_2,
+ S_BLASTERPUFF1_3,
+ S_BLASTERPUFF1_4,
+ S_BLASTERPUFF1_5,
+ S_BLASTERPUFF2_1,
+ S_BLASTERPUFF2_2,
+ S_BLASTERPUFF2_3,
+ S_BLASTERPUFF2_4,
+ S_BLASTERPUFF2_5,
+ S_BLASTERPUFF2_6,
+ S_BLASTERPUFF2_7,
+ S_WMCE,
+ S_MACEREADY,
+ S_MACEDOWN,
+ S_MACEUP,
+ S_MACEATK1_1,
+ S_MACEATK1_2,
+ S_MACEATK1_3,
+ S_MACEATK1_4,
+ S_MACEATK1_5,
+ S_MACEATK1_6,
+ S_MACEATK1_7,
+ S_MACEATK1_8,
+ S_MACEATK1_9,
+ S_MACEATK1_10,
+ S_MACEATK2_1,
+ S_MACEATK2_2,
+ S_MACEATK2_3,
+ S_MACEATK2_4,
+ S_MACEFX1_1,
+ S_MACEFX1_2,
+ S_MACEFXI1_1,
+ S_MACEFXI1_2,
+ S_MACEFXI1_3,
+ S_MACEFXI1_4,
+ S_MACEFXI1_5,
+ S_MACEFX2_1,
+ S_MACEFX2_2,
+ S_MACEFXI2_1,
+ S_MACEFX3_1,
+ S_MACEFX3_2,
+ S_MACEFX4_1,
+ S_MACEFXI4_1,
+ S_WSKL,
+ S_HORNRODREADY,
+ S_HORNRODDOWN,
+ S_HORNRODUP,
+ S_HORNRODATK1_1,
+ S_HORNRODATK1_2,
+ S_HORNRODATK1_3,
+ S_HORNRODATK2_1,
+ S_HORNRODATK2_2,
+ S_HORNRODATK2_3,
+ S_HORNRODATK2_4,
+ S_HORNRODATK2_5,
+ S_HORNRODATK2_6,
+ S_HORNRODATK2_7,
+ S_HORNRODATK2_8,
+ S_HORNRODATK2_9,
+ S_HRODFX1_1,
+ S_HRODFX1_2,
+ S_HRODFXI1_1,
+ S_HRODFXI1_2,
+ S_HRODFXI1_3,
+ S_HRODFXI1_4,
+ S_HRODFXI1_5,
+ S_HRODFXI1_6,
+ S_HRODFX2_1,
+ S_HRODFX2_2,
+ S_HRODFX2_3,
+ S_HRODFX2_4,
+ S_HRODFXI2_1,
+ S_HRODFXI2_2,
+ S_HRODFXI2_3,
+ S_HRODFXI2_4,
+ S_HRODFXI2_5,
+ S_HRODFXI2_6,
+ S_HRODFXI2_7,
+ S_HRODFXI2_8,
+ S_RAINPLR1_1,
+ S_RAINPLR2_1,
+ S_RAINPLR3_1,
+ S_RAINPLR4_1,
+ S_RAINPLR1X_1,
+ S_RAINPLR1X_2,
+ S_RAINPLR1X_3,
+ S_RAINPLR1X_4,
+ S_RAINPLR1X_5,
+ S_RAINPLR2X_1,
+ S_RAINPLR2X_2,
+ S_RAINPLR2X_3,
+ S_RAINPLR2X_4,
+ S_RAINPLR2X_5,
+ S_RAINPLR3X_1,
+ S_RAINPLR3X_2,
+ S_RAINPLR3X_3,
+ S_RAINPLR3X_4,
+ S_RAINPLR3X_5,
+ S_RAINPLR4X_1,
+ S_RAINPLR4X_2,
+ S_RAINPLR4X_3,
+ S_RAINPLR4X_4,
+ S_RAINPLR4X_5,
+ S_RAINAIRXPLR1_1,
+ S_RAINAIRXPLR2_1,
+ S_RAINAIRXPLR3_1,
+ S_RAINAIRXPLR4_1,
+ S_RAINAIRXPLR1_2,
+ S_RAINAIRXPLR2_2,
+ S_RAINAIRXPLR3_2,
+ S_RAINAIRXPLR4_2,
+ S_RAINAIRXPLR1_3,
+ S_RAINAIRXPLR2_3,
+ S_RAINAIRXPLR3_3,
+ S_RAINAIRXPLR4_3,
+ S_GOLDWANDREADY,
+ S_GOLDWANDDOWN,
+ S_GOLDWANDUP,
+ S_GOLDWANDATK1_1,
+ S_GOLDWANDATK1_2,
+ S_GOLDWANDATK1_3,
+ S_GOLDWANDATK1_4,
+ S_GOLDWANDATK2_1,
+ S_GOLDWANDATK2_2,
+ S_GOLDWANDATK2_3,
+ S_GOLDWANDATK2_4,
+ S_GWANDFX1_1,
+ S_GWANDFX1_2,
+ S_GWANDFXI1_1,
+ S_GWANDFXI1_2,
+ S_GWANDFXI1_3,
+ S_GWANDFXI1_4,
+ S_GWANDFX2_1,
+ S_GWANDFX2_2,
+ S_GWANDPUFF1_1,
+ S_GWANDPUFF1_2,
+ S_GWANDPUFF1_3,
+ S_GWANDPUFF1_4,
+ S_GWANDPUFF1_5,
+ S_WPHX,
+ S_PHOENIXREADY,
+ S_PHOENIXDOWN,
+ S_PHOENIXUP,
+ S_PHOENIXATK1_1,
+ S_PHOENIXATK1_2,
+ S_PHOENIXATK1_3,
+ S_PHOENIXATK1_4,
+ S_PHOENIXATK1_5,
+ S_PHOENIXATK2_1,
+ S_PHOENIXATK2_2,
+ S_PHOENIXATK2_3,
+ S_PHOENIXATK2_4,
+ S_PHOENIXFX1_1,
+ S_PHOENIXFXI1_1,
+ S_PHOENIXFXI1_2,
+ S_PHOENIXFXI1_3,
+ S_PHOENIXFXI1_4,
+ S_PHOENIXFXI1_5,
+ S_PHOENIXFXI1_6,
+ S_PHOENIXFXI1_7,
+ S_PHOENIXFXI1_8,
+ S_PHOENIXFXIX_1, // [ States in Heretic 1.0 that were removed
+ S_PHOENIXFXIX_2,
+ S_PHOENIXFXIX_3, // ]
+ S_PHOENIXPUFF1,
+ S_PHOENIXPUFF2,
+ S_PHOENIXPUFF3,
+ S_PHOENIXPUFF4,
+ S_PHOENIXPUFF5,
+ S_PHOENIXFX2_1,
+ S_PHOENIXFX2_2,
+ S_PHOENIXFX2_3,
+ S_PHOENIXFX2_4,
+ S_PHOENIXFX2_5,
+ S_PHOENIXFX2_6,
+ S_PHOENIXFX2_7,
+ S_PHOENIXFX2_8,
+ S_PHOENIXFX2_9,
+ S_PHOENIXFX2_10,
+ S_PHOENIXFXI2_1,
+ S_PHOENIXFXI2_2,
+ S_PHOENIXFXI2_3,
+ S_PHOENIXFXI2_4,
+ S_PHOENIXFXI2_5,
+ S_WBOW,
+ S_CRBOW1,
+ S_CRBOW2,
+ S_CRBOW3,
+ S_CRBOW4,
+ S_CRBOW5,
+ S_CRBOW6,
+ S_CRBOW7,
+ S_CRBOW8,
+ S_CRBOW9,
+ S_CRBOW10,
+ S_CRBOW11,
+ S_CRBOW12,
+ S_CRBOW13,
+ S_CRBOW14,
+ S_CRBOW15,
+ S_CRBOW16,
+ S_CRBOW17,
+ S_CRBOW18,
+ S_CRBOWDOWN,
+ S_CRBOWUP,
+ S_CRBOWATK1_1,
+ S_CRBOWATK1_2,
+ S_CRBOWATK1_3,
+ S_CRBOWATK1_4,
+ S_CRBOWATK1_5,
+ S_CRBOWATK1_6,
+ S_CRBOWATK1_7,
+ S_CRBOWATK1_8,
+ S_CRBOWATK2_1,
+ S_CRBOWATK2_2,
+ S_CRBOWATK2_3,
+ S_CRBOWATK2_4,
+ S_CRBOWATK2_5,
+ S_CRBOWATK2_6,
+ S_CRBOWATK2_7,
+ S_CRBOWATK2_8,
+ S_CRBOWFX1,
+ S_CRBOWFXI1_1,
+ S_CRBOWFXI1_2,
+ S_CRBOWFXI1_3,
+ S_CRBOWFX2,
+ S_CRBOWFX3,
+ S_CRBOWFXI3_1,
+ S_CRBOWFXI3_2,
+ S_CRBOWFXI3_3,
+ S_CRBOWFX4_1,
+ S_CRBOWFX4_2,
+ S_BLOOD1,
+ S_BLOOD2,
+ S_BLOOD3,
+ S_BLOODSPLATTER1,
+ S_BLOODSPLATTER2,
+ S_BLOODSPLATTER3,
+ S_BLOODSPLATTERX,
+ S_PLAY,
+ S_PLAY_RUN1,
+ S_PLAY_RUN2,
+ S_PLAY_RUN3,
+ S_PLAY_RUN4,
+ S_PLAY_ATK1,
+ S_PLAY_ATK2,
+ S_PLAY_PAIN,
+ S_PLAY_PAIN2,
+ S_PLAY_DIE1,
+ S_PLAY_DIE2,
+ S_PLAY_DIE3,
+ S_PLAY_DIE4,
+ S_PLAY_DIE5,
+ S_PLAY_DIE6,
+ S_PLAY_DIE7,
+ S_PLAY_DIE8,
+ S_PLAY_DIE9,
+ S_PLAY_XDIE1,
+ S_PLAY_XDIE2,
+ S_PLAY_XDIE3,
+ S_PLAY_XDIE4,
+ S_PLAY_XDIE5,
+ S_PLAY_XDIE6,
+ S_PLAY_XDIE7,
+ S_PLAY_XDIE8,
+ S_PLAY_XDIE9,
+ S_PLAY_FDTH1,
+ S_PLAY_FDTH2,
+ S_PLAY_FDTH3,
+ S_PLAY_FDTH4,
+ S_PLAY_FDTH5,
+ S_PLAY_FDTH6,
+ S_PLAY_FDTH7,
+ S_PLAY_FDTH8,
+ S_PLAY_FDTH9,
+ S_PLAY_FDTH10,
+ S_PLAY_FDTH11,
+ S_PLAY_FDTH12,
+ S_PLAY_FDTH13,
+ S_PLAY_FDTH14,
+ S_PLAY_FDTH15,
+ S_PLAY_FDTH16,
+ S_PLAY_FDTH17,
+ S_PLAY_FDTH18,
+ S_PLAY_FDTH19, // < These two frames were not present in the Heretic
+ S_PLAY_FDTH20, // < 1.0 executable (fire death animation was extended)
+ S_BLOODYSKULL1,
+ S_BLOODYSKULL2,
+ S_BLOODYSKULL3,
+ S_BLOODYSKULL4,
+ S_BLOODYSKULL5,
+ S_BLOODYSKULLX1,
+ S_BLOODYSKULLX2,
+ S_CHICPLAY,
+ S_CHICPLAY_RUN1,
+ S_CHICPLAY_RUN2,
+ S_CHICPLAY_RUN3,
+ S_CHICPLAY_RUN4,
+ S_CHICPLAY_ATK1,
+ S_CHICPLAY_PAIN,
+ S_CHICPLAY_PAIN2,
+ S_CHICKEN_LOOK1,
+ S_CHICKEN_LOOK2,
+ S_CHICKEN_WALK1,
+ S_CHICKEN_WALK2,
+ S_CHICKEN_PAIN1,
+ S_CHICKEN_PAIN2,
+ S_CHICKEN_ATK1,
+ S_CHICKEN_ATK2,
+ S_CHICKEN_DIE1,
+ S_CHICKEN_DIE2,
+ S_CHICKEN_DIE3,
+ S_CHICKEN_DIE4,
+ S_CHICKEN_DIE5,
+ S_CHICKEN_DIE6,
+ S_CHICKEN_DIE7,
+ S_CHICKEN_DIE8,
+ S_FEATHER1,
+ S_FEATHER2,
+ S_FEATHER3,
+ S_FEATHER4,
+ S_FEATHER5,
+ S_FEATHER6,
+ S_FEATHER7,
+ S_FEATHER8,
+ S_FEATHERX,
+ S_MUMMY_LOOK1,
+ S_MUMMY_LOOK2,
+ S_MUMMY_WALK1,
+ S_MUMMY_WALK2,
+ S_MUMMY_WALK3,
+ S_MUMMY_WALK4,
+ S_MUMMY_ATK1,
+ S_MUMMY_ATK2,
+ S_MUMMY_ATK3,
+ S_MUMMYL_ATK1,
+ S_MUMMYL_ATK2,
+ S_MUMMYL_ATK3,
+ S_MUMMYL_ATK4,
+ S_MUMMYL_ATK5,
+ S_MUMMYL_ATK6,
+ S_MUMMY_PAIN1,
+ S_MUMMY_PAIN2,
+ S_MUMMY_DIE1,
+ S_MUMMY_DIE2,
+ S_MUMMY_DIE3,
+ S_MUMMY_DIE4,
+ S_MUMMY_DIE5,
+ S_MUMMY_DIE6,
+ S_MUMMY_DIE7,
+ S_MUMMY_DIE8,
+ S_MUMMY_SOUL1,
+ S_MUMMY_SOUL2,
+ S_MUMMY_SOUL3,
+ S_MUMMY_SOUL4,
+ S_MUMMY_SOUL5,
+ S_MUMMY_SOUL6,
+ S_MUMMY_SOUL7,
+ S_MUMMYFX1_1,
+ S_MUMMYFX1_2,
+ S_MUMMYFX1_3,
+ S_MUMMYFX1_4,
+ S_MUMMYFXI1_1,
+ S_MUMMYFXI1_2,
+ S_MUMMYFXI1_3,
+ S_MUMMYFXI1_4,
+ S_BEAST_LOOK1,
+ S_BEAST_LOOK2,
+ S_BEAST_WALK1,
+ S_BEAST_WALK2,
+ S_BEAST_WALK3,
+ S_BEAST_WALK4,
+ S_BEAST_WALK5,
+ S_BEAST_WALK6,
+ S_BEAST_ATK1,
+ S_BEAST_ATK2,
+ S_BEAST_PAIN1,
+ S_BEAST_PAIN2,
+ S_BEAST_DIE1,
+ S_BEAST_DIE2,
+ S_BEAST_DIE3,
+ S_BEAST_DIE4,
+ S_BEAST_DIE5,
+ S_BEAST_DIE6,
+ S_BEAST_DIE7,
+ S_BEAST_DIE8,
+ S_BEAST_DIE9,
+ S_BEAST_XDIE1,
+ S_BEAST_XDIE2,
+ S_BEAST_XDIE3,
+ S_BEAST_XDIE4,
+ S_BEAST_XDIE5,
+ S_BEAST_XDIE6,
+ S_BEAST_XDIE7,
+ S_BEAST_XDIE8,
+ S_BEASTBALL1,
+ S_BEASTBALL2,
+ S_BEASTBALL3,
+ S_BEASTBALL4,
+ S_BEASTBALL5,
+ S_BEASTBALL6,
+ S_BEASTBALLX1,
+ S_BEASTBALLX2,
+ S_BEASTBALLX3,
+ S_BEASTBALLX4,
+ S_BEASTBALLX5,
+ S_BURNBALL1,
+ S_BURNBALL2,
+ S_BURNBALL3,
+ S_BURNBALL4,
+ S_BURNBALL5,
+ S_BURNBALL6,
+ S_BURNBALL7,
+ S_BURNBALL8,
+ S_BURNBALLFB1,
+ S_BURNBALLFB2,
+ S_BURNBALLFB3,
+ S_BURNBALLFB4,
+ S_BURNBALLFB5,
+ S_BURNBALLFB6,
+ S_BURNBALLFB7,
+ S_BURNBALLFB8,
+ S_PUFFY1,
+ S_PUFFY2,
+ S_PUFFY3,
+ S_PUFFY4,
+ S_PUFFY5,
+ S_SNAKE_LOOK1,
+ S_SNAKE_LOOK2,
+ S_SNAKE_WALK1,
+ S_SNAKE_WALK2,
+ S_SNAKE_WALK3,
+ S_SNAKE_WALK4,
+ S_SNAKE_ATK1,
+ S_SNAKE_ATK2,
+ S_SNAKE_ATK3,
+ S_SNAKE_ATK4,
+ S_SNAKE_ATK5,
+ S_SNAKE_ATK6,
+ S_SNAKE_ATK7,
+ S_SNAKE_ATK8,
+ S_SNAKE_ATK9,
+ S_SNAKE_PAIN1,
+ S_SNAKE_PAIN2,
+ S_SNAKE_DIE1,
+ S_SNAKE_DIE2,
+ S_SNAKE_DIE3,
+ S_SNAKE_DIE4,
+ S_SNAKE_DIE5,
+ S_SNAKE_DIE6,
+ S_SNAKE_DIE7,
+ S_SNAKE_DIE8,
+ S_SNAKE_DIE9,
+ S_SNAKE_DIE10,
+ S_SNAKEPRO_A1,
+ S_SNAKEPRO_A2,
+ S_SNAKEPRO_A3,
+ S_SNAKEPRO_A4,
+ S_SNAKEPRO_AX1,
+ S_SNAKEPRO_AX2,
+ S_SNAKEPRO_AX3,
+ S_SNAKEPRO_AX4,
+ S_SNAKEPRO_AX5,
+ S_SNAKEPRO_B1,
+ S_SNAKEPRO_B2,
+ S_SNAKEPRO_BX1,
+ S_SNAKEPRO_BX2,
+ S_SNAKEPRO_BX3,
+ S_SNAKEPRO_BX4,
+ S_HEAD_LOOK,
+ S_HEAD_FLOAT,
+ S_HEAD_ATK1,
+ S_HEAD_ATK2,
+ S_HEAD_PAIN1,
+ S_HEAD_PAIN2,
+ S_HEAD_DIE1,
+ S_HEAD_DIE2,
+ S_HEAD_DIE3,
+ S_HEAD_DIE4,
+ S_HEAD_DIE5,
+ S_HEAD_DIE6,
+ S_HEAD_DIE7,
+ S_HEADFX1_1,
+ S_HEADFX1_2,
+ S_HEADFX1_3,
+ S_HEADFXI1_1,
+ S_HEADFXI1_2,
+ S_HEADFXI1_3,
+ S_HEADFXI1_4,
+ S_HEADFX2_1,
+ S_HEADFX2_2,
+ S_HEADFX2_3,
+ S_HEADFXI2_1,
+ S_HEADFXI2_2,
+ S_HEADFXI2_3,
+ S_HEADFXI2_4,
+ S_HEADFX3_1,
+ S_HEADFX3_2,
+ S_HEADFX3_3,
+ S_HEADFX3_4,
+ S_HEADFX3_5,
+ S_HEADFX3_6,
+ S_HEADFXI3_1,
+ S_HEADFXI3_2,
+ S_HEADFXI3_3,
+ S_HEADFXI3_4,
+ S_HEADFX4_1,
+ S_HEADFX4_2,
+ S_HEADFX4_3,
+ S_HEADFX4_4,
+ S_HEADFX4_5,
+ S_HEADFX4_6,
+ S_HEADFX4_7,
+ S_HEADFXI4_1,
+ S_HEADFXI4_2,
+ S_HEADFXI4_3,
+ S_HEADFXI4_4,
+ S_CLINK_LOOK1,
+ S_CLINK_LOOK2,
+ S_CLINK_WALK1,
+ S_CLINK_WALK2,
+ S_CLINK_WALK3,
+ S_CLINK_WALK4,
+ S_CLINK_ATK1,
+ S_CLINK_ATK2,
+ S_CLINK_ATK3,
+ S_CLINK_PAIN1,
+ S_CLINK_PAIN2,
+ S_CLINK_DIE1,
+ S_CLINK_DIE2,
+ S_CLINK_DIE3,
+ S_CLINK_DIE4,
+ S_CLINK_DIE5,
+ S_CLINK_DIE6,
+ S_CLINK_DIE7,
+ S_WIZARD_LOOK1,
+ S_WIZARD_LOOK2,
+ S_WIZARD_WALK1,
+ S_WIZARD_WALK2,
+ S_WIZARD_WALK3,
+ S_WIZARD_WALK4,
+ S_WIZARD_WALK5,
+ S_WIZARD_WALK6,
+ S_WIZARD_WALK7,
+ S_WIZARD_WALK8,
+ S_WIZARD_ATK1,
+ S_WIZARD_ATK2,
+ S_WIZARD_ATK3,
+ S_WIZARD_ATK4,
+ S_WIZARD_ATK5,
+ S_WIZARD_ATK6,
+ S_WIZARD_ATK7,
+ S_WIZARD_ATK8,
+ S_WIZARD_ATK9,
+ S_WIZARD_PAIN1,
+ S_WIZARD_PAIN2,
+ S_WIZARD_DIE1,
+ S_WIZARD_DIE2,
+ S_WIZARD_DIE3,
+ S_WIZARD_DIE4,
+ S_WIZARD_DIE5,
+ S_WIZARD_DIE6,
+ S_WIZARD_DIE7,
+ S_WIZARD_DIE8,
+ S_WIZFX1_1,
+ S_WIZFX1_2,
+ S_WIZFXI1_1,
+ S_WIZFXI1_2,
+ S_WIZFXI1_3,
+ S_WIZFXI1_4,
+ S_WIZFXI1_5,
+ S_IMP_LOOK1,
+ S_IMP_LOOK2,
+ S_IMP_LOOK3,
+ S_IMP_LOOK4,
+ S_IMP_FLY1,
+ S_IMP_FLY2,
+ S_IMP_FLY3,
+ S_IMP_FLY4,
+ S_IMP_FLY5,
+ S_IMP_FLY6,
+ S_IMP_FLY7,
+ S_IMP_FLY8,
+ S_IMP_MEATK1,
+ S_IMP_MEATK2,
+ S_IMP_MEATK3,
+ S_IMP_MSATK1_1,
+ S_IMP_MSATK1_2,
+ S_IMP_MSATK1_3,
+ S_IMP_MSATK1_4,
+ S_IMP_MSATK1_5,
+ S_IMP_MSATK1_6,
+ S_IMP_MSATK2_1,
+ S_IMP_MSATK2_2,
+ S_IMP_MSATK2_3,
+ S_IMP_PAIN1,
+ S_IMP_PAIN2,
+ S_IMP_DIE1,
+ S_IMP_DIE2,
+ S_IMP_XDIE1,
+ S_IMP_XDIE2,
+ S_IMP_XDIE3,
+ S_IMP_XDIE4,
+ S_IMP_XDIE5,
+ S_IMP_CRASH1,
+ S_IMP_CRASH2,
+ S_IMP_CRASH3,
+ S_IMP_CRASH4,
+ S_IMP_XCRASH1,
+ S_IMP_XCRASH2,
+ S_IMP_XCRASH3,
+ S_IMP_CHUNKA1,
+ S_IMP_CHUNKA2,
+ S_IMP_CHUNKA3,
+ S_IMP_CHUNKB1,
+ S_IMP_CHUNKB2,
+ S_IMP_CHUNKB3,
+ S_IMPFX1,
+ S_IMPFX2,
+ S_IMPFX3,
+ S_IMPFXI1,
+ S_IMPFXI2,
+ S_IMPFXI3,
+ S_IMPFXI4,
+ S_KNIGHT_STND1,
+ S_KNIGHT_STND2,
+ S_KNIGHT_WALK1,
+ S_KNIGHT_WALK2,
+ S_KNIGHT_WALK3,
+ S_KNIGHT_WALK4,
+ S_KNIGHT_ATK1,
+ S_KNIGHT_ATK2,
+ S_KNIGHT_ATK3,
+ S_KNIGHT_ATK4,
+ S_KNIGHT_ATK5,
+ S_KNIGHT_ATK6,
+ S_KNIGHT_PAIN1,
+ S_KNIGHT_PAIN2,
+ S_KNIGHT_DIE1,
+ S_KNIGHT_DIE2,
+ S_KNIGHT_DIE3,
+ S_KNIGHT_DIE4,
+ S_KNIGHT_DIE5,
+ S_KNIGHT_DIE6,
+ S_KNIGHT_DIE7,
+ S_SPINAXE1,
+ S_SPINAXE2,
+ S_SPINAXE3,
+ S_SPINAXEX1,
+ S_SPINAXEX2,
+ S_SPINAXEX3,
+ S_REDAXE1,
+ S_REDAXE2,
+ S_REDAXEX1,
+ S_REDAXEX2,
+ S_REDAXEX3,
+ S_SRCR1_LOOK1,
+ S_SRCR1_LOOK2,
+ S_SRCR1_WALK1,
+ S_SRCR1_WALK2,
+ S_SRCR1_WALK3,
+ S_SRCR1_WALK4,
+ S_SRCR1_PAIN1,
+ S_SRCR1_ATK1,
+ S_SRCR1_ATK2,
+ S_SRCR1_ATK3,
+ S_SRCR1_ATK4,
+ S_SRCR1_ATK5,
+ S_SRCR1_ATK6,
+ S_SRCR1_ATK7,
+ S_SRCR1_DIE1,
+ S_SRCR1_DIE2,
+ S_SRCR1_DIE3,
+ S_SRCR1_DIE4,
+ S_SRCR1_DIE5,
+ S_SRCR1_DIE6,
+ S_SRCR1_DIE7,
+ S_SRCR1_DIE8,
+ S_SRCR1_DIE9,
+ S_SRCR1_DIE10,
+ S_SRCR1_DIE11,
+ S_SRCR1_DIE12,
+ S_SRCR1_DIE13,
+ S_SRCR1_DIE14,
+ S_SRCR1_DIE15,
+ S_SRCR1_DIE16,
+ S_SRCR1_DIE17,
+ S_SRCRFX1_1,
+ S_SRCRFX1_2,
+ S_SRCRFX1_3,
+ S_SRCRFXI1_1,
+ S_SRCRFXI1_2,
+ S_SRCRFXI1_3,
+ S_SRCRFXI1_4,
+ S_SRCRFXI1_5,
+ S_SOR2_RISE1,
+ S_SOR2_RISE2,
+ S_SOR2_RISE3,
+ S_SOR2_RISE4,
+ S_SOR2_RISE5,
+ S_SOR2_RISE6,
+ S_SOR2_RISE7,
+ S_SOR2_LOOK1,
+ S_SOR2_LOOK2,
+ S_SOR2_WALK1,
+ S_SOR2_WALK2,
+ S_SOR2_WALK3,
+ S_SOR2_WALK4,
+ S_SOR2_PAIN1,
+ S_SOR2_PAIN2,
+ S_SOR2_ATK1,
+ S_SOR2_ATK2,
+ S_SOR2_ATK3,
+ S_SOR2_TELE1,
+ S_SOR2_TELE2,
+ S_SOR2_TELE3,
+ S_SOR2_TELE4,
+ S_SOR2_TELE5,
+ S_SOR2_TELE6,
+ S_SOR2_DIE1,
+ S_SOR2_DIE2,
+ S_SOR2_DIE3,
+ S_SOR2_DIE4,
+ S_SOR2_DIE5,
+ S_SOR2_DIE6,
+ S_SOR2_DIE7,
+ S_SOR2_DIE8,
+ S_SOR2_DIE9,
+ S_SOR2_DIE10,
+ S_SOR2_DIE11,
+ S_SOR2_DIE12,
+ S_SOR2_DIE13,
+ S_SOR2_DIE14,
+ S_SOR2_DIE15,
+ S_SOR2FX1_1,
+ S_SOR2FX1_2,
+ S_SOR2FX1_3,
+ S_SOR2FXI1_1,
+ S_SOR2FXI1_2,
+ S_SOR2FXI1_3,
+ S_SOR2FXI1_4,
+ S_SOR2FXI1_5,
+ S_SOR2FXI1_6,
+ S_SOR2FXSPARK1,
+ S_SOR2FXSPARK2,
+ S_SOR2FXSPARK3,
+ S_SOR2FX2_1,
+ S_SOR2FX2_2,
+ S_SOR2FX2_3,
+ S_SOR2FXI2_1,
+ S_SOR2FXI2_2,
+ S_SOR2FXI2_3,
+ S_SOR2FXI2_4,
+ S_SOR2FXI2_5,
+ S_SOR2TELEFADE1,
+ S_SOR2TELEFADE2,
+ S_SOR2TELEFADE3,
+ S_SOR2TELEFADE4,
+ S_SOR2TELEFADE5,
+ S_SOR2TELEFADE6,
+ S_MNTR_LOOK1,
+ S_MNTR_LOOK2,
+ S_MNTR_WALK1,
+ S_MNTR_WALK2,
+ S_MNTR_WALK3,
+ S_MNTR_WALK4,
+ S_MNTR_ATK1_1,
+ S_MNTR_ATK1_2,
+ S_MNTR_ATK1_3,
+ S_MNTR_ATK2_1,
+ S_MNTR_ATK2_2,
+ S_MNTR_ATK2_3,
+ S_MNTR_ATK3_1,
+ S_MNTR_ATK3_2,
+ S_MNTR_ATK3_3,
+ S_MNTR_ATK3_4,
+ S_MNTR_ATK4_1,
+ S_MNTR_PAIN1,
+ S_MNTR_PAIN2,
+ S_MNTR_DIE1,
+ S_MNTR_DIE2,
+ S_MNTR_DIE3,
+ S_MNTR_DIE4,
+ S_MNTR_DIE5,
+ S_MNTR_DIE6,
+ S_MNTR_DIE7,
+ S_MNTR_DIE8,
+ S_MNTR_DIE9,
+ S_MNTR_DIE10,
+ S_MNTR_DIE11,
+ S_MNTR_DIE12,
+ S_MNTR_DIE13,
+ S_MNTR_DIE14,
+ S_MNTR_DIE15,
+ S_MNTRFX1_1,
+ S_MNTRFX1_2,
+ S_MNTRFXI1_1,
+ S_MNTRFXI1_2,
+ S_MNTRFXI1_3,
+ S_MNTRFXI1_4,
+ S_MNTRFXI1_5,
+ S_MNTRFXI1_6,
+ S_MNTRFX2_1,
+ S_MNTRFXI2_1,
+ S_MNTRFXI2_2,
+ S_MNTRFXI2_3,
+ S_MNTRFXI2_4,
+ S_MNTRFXI2_5,
+ S_MNTRFX3_1,
+ S_MNTRFX3_2,
+ S_MNTRFX3_3,
+ S_MNTRFX3_4,
+ S_MNTRFX3_5,
+ S_MNTRFX3_6,
+ S_MNTRFX3_7,
+ S_MNTRFX3_8,
+ S_MNTRFX3_9,
+ S_AKYY1,
+ S_AKYY2,
+ S_AKYY3,
+ S_AKYY4,
+ S_AKYY5,
+ S_AKYY6,
+ S_AKYY7,
+ S_AKYY8,
+ S_AKYY9,
+ S_AKYY10,
+ S_BKYY1,
+ S_BKYY2,
+ S_BKYY3,
+ S_BKYY4,
+ S_BKYY5,
+ S_BKYY6,
+ S_BKYY7,
+ S_BKYY8,
+ S_BKYY9,
+ S_BKYY10,
+ S_CKYY1,
+ S_CKYY2,
+ S_CKYY3,
+ S_CKYY4,
+ S_CKYY5,
+ S_CKYY6,
+ S_CKYY7,
+ S_CKYY8,
+ S_CKYY9,
+ S_AMG1,
+ S_AMG2_1,
+ S_AMG2_2,
+ S_AMG2_3,
+ S_AMM1,
+ S_AMM2,
+ S_AMC1,
+ S_AMC2_1,
+ S_AMC2_2,
+ S_AMC2_3,
+ S_AMS1_1,
+ S_AMS1_2,
+ S_AMS2_1,
+ S_AMS2_2,
+ S_AMP1_1,
+ S_AMP1_2,
+ S_AMP1_3,
+ S_AMP2_1,
+ S_AMP2_2,
+ S_AMP2_3,
+ S_AMB1_1,
+ S_AMB1_2,
+ S_AMB1_3,
+ S_AMB2_1,
+ S_AMB2_2,
+ S_AMB2_3,
+ S_SND_WIND,
+ S_SND_WATERFALL,
+ NUMSTATES
+} statenum_t;
+
+typedef struct
+{
+ spritenum_t sprite;
+ int frame;
+ int tics;
+ void (*action) ();
+ statenum_t nextstate;
+ int misc1, misc2;
+} state_t;
+
+extern state_t states[NUMSTATES];
+extern char *sprnames[];
+
+
+
+typedef enum
+{
+ MT_MISC0,
+ MT_ITEMSHIELD1,
+ MT_ITEMSHIELD2,
+ MT_MISC1,
+ MT_MISC2,
+ MT_ARTIINVISIBILITY,
+ MT_MISC3,
+ MT_ARTIFLY,
+ MT_ARTIINVULNERABILITY,
+ MT_ARTITOMEOFPOWER,
+ MT_ARTIEGG,
+ MT_EGGFX,
+ MT_ARTISUPERHEAL,
+ MT_MISC4,
+ MT_MISC5,
+ MT_FIREBOMB,
+ MT_ARTITELEPORT,
+ MT_POD,
+ MT_PODGOO,
+ MT_PODGENERATOR,
+ MT_SPLASH,
+ MT_SPLASHBASE,
+ MT_LAVASPLASH,
+ MT_LAVASMOKE,
+ MT_SLUDGECHUNK,
+ MT_SLUDGESPLASH,
+ MT_SKULLHANG70,
+ MT_SKULLHANG60,
+ MT_SKULLHANG45,
+ MT_SKULLHANG35,
+ MT_CHANDELIER,
+ MT_SERPTORCH,
+ MT_SMALLPILLAR,
+ MT_STALAGMITESMALL,
+ MT_STALAGMITELARGE,
+ MT_STALACTITESMALL,
+ MT_STALACTITELARGE,
+ MT_MISC6,
+ MT_BARREL,
+ MT_MISC7,
+ MT_MISC8,
+ MT_MISC9,
+ MT_MISC10,
+ MT_MISC11,
+ MT_KEYGIZMOBLUE,
+ MT_KEYGIZMOGREEN,
+ MT_KEYGIZMOYELLOW,
+ MT_KEYGIZMOFLOAT,
+ MT_MISC12,
+ MT_VOLCANOBLAST,
+ MT_VOLCANOTBLAST,
+ MT_TELEGLITGEN,
+ MT_TELEGLITGEN2,
+ MT_TELEGLITTER,
+ MT_TELEGLITTER2,
+ MT_TFOG,
+ MT_TELEPORTMAN,
+ MT_STAFFPUFF,
+ MT_STAFFPUFF2,
+ MT_BEAKPUFF,
+ MT_MISC13,
+ MT_GAUNTLETPUFF1,
+ MT_GAUNTLETPUFF2,
+ MT_MISC14,
+ MT_BLASTERFX1,
+ MT_BLASTERSMOKE,
+ MT_RIPPER,
+ MT_BLASTERPUFF1,
+ MT_BLASTERPUFF2,
+ MT_WMACE,
+ MT_MACEFX1,
+ MT_MACEFX2,
+ MT_MACEFX3,
+ MT_MACEFX4,
+ MT_WSKULLROD,
+ MT_HORNRODFX1,
+ MT_HORNRODFX2,
+ MT_RAINPLR1,
+ MT_RAINPLR2,
+ MT_RAINPLR3,
+ MT_RAINPLR4,
+ MT_GOLDWANDFX1,
+ MT_GOLDWANDFX2,
+ MT_GOLDWANDPUFF1,
+ MT_GOLDWANDPUFF2,
+ MT_WPHOENIXROD,
+ MT_PHOENIXFX1,
+ MT_PHOENIXFX_REMOVED, // In Heretic 1.0, but removed.
+ MT_PHOENIXPUFF,
+ MT_PHOENIXFX2,
+ MT_MISC15,
+ MT_CRBOWFX1,
+ MT_CRBOWFX2,
+ MT_CRBOWFX3,
+ MT_CRBOWFX4,
+ MT_BLOOD,
+ MT_BLOODSPLATTER,
+ MT_PLAYER,
+ MT_BLOODYSKULL,
+ MT_CHICPLAYER,
+ MT_CHICKEN,
+ MT_FEATHER,
+ MT_MUMMY,
+ MT_MUMMYLEADER,
+ MT_MUMMYGHOST,
+ MT_MUMMYLEADERGHOST,
+ MT_MUMMYSOUL,
+ MT_MUMMYFX1,
+ MT_BEAST,
+ MT_BEASTBALL,
+ MT_BURNBALL,
+ MT_BURNBALLFB,
+ MT_PUFFY,
+ MT_SNAKE,
+ MT_SNAKEPRO_A,
+ MT_SNAKEPRO_B,
+ MT_HEAD,
+ MT_HEADFX1,
+ MT_HEADFX2,
+ MT_HEADFX3,
+ MT_WHIRLWIND,
+ MT_CLINK,
+ MT_WIZARD,
+ MT_WIZFX1,
+ MT_IMP,
+ MT_IMPLEADER,
+ MT_IMPCHUNK1,
+ MT_IMPCHUNK2,
+ MT_IMPBALL,
+ MT_KNIGHT,
+ MT_KNIGHTGHOST,
+ MT_KNIGHTAXE,
+ MT_REDAXE,
+ MT_SORCERER1,
+ MT_SRCRFX1,
+ MT_SORCERER2,
+ MT_SOR2FX1,
+ MT_SOR2FXSPARK,
+ MT_SOR2FX2,
+ MT_SOR2TELEFADE,
+ MT_MINOTAUR,
+ MT_MNTRFX1,
+ MT_MNTRFX2,
+ MT_MNTRFX3,
+ MT_AKYY,
+ MT_BKYY,
+ MT_CKEY,
+ MT_AMGWNDWIMPY,
+ MT_AMGWNDHEFTY,
+ MT_AMMACEWIMPY,
+ MT_AMMACEHEFTY,
+ MT_AMCBOWWIMPY,
+ MT_AMCBOWHEFTY,
+ MT_AMSKRDWIMPY,
+ MT_AMSKRDHEFTY,
+ MT_AMPHRDWIMPY,
+ MT_AMPHRDHEFTY,
+ MT_AMBLSRWIMPY,
+ MT_AMBLSRHEFTY,
+ MT_SOUNDWIND,
+ MT_SOUNDWATERFALL,
+ NUMMOBJTYPES
+} mobjtype_t;
+
+typedef struct
+{
+ int doomednum;
+ int spawnstate;
+ int spawnhealth;
+ int seestate;
+ int seesound;
+ int reactiontime;
+ int attacksound;
+ int painstate;
+ int painchance;
+ int painsound;
+ int meleestate;
+ int missilestate;
+ int crashstate;
+ int deathstate;
+ int xdeathstate;
+ int deathsound;
+ int speed;
+ int radius;
+ int height;
+ int mass;
+ int damage;
+ int activesound;
+ int flags;
+ int flags2;
+} mobjinfo_t;
+
+extern mobjinfo_t mobjinfo[NUMMOBJTYPES];
+
+#endif /* #ifndef HERETIC_INFO_H */
+
diff --git a/src/heretic/m_random.c b/src/heretic/m_random.c
new file mode 100644
index 00000000..383d906c
--- /dev/null
+++ b/src/heretic/m_random.c
@@ -0,0 +1,78 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+#include "m_random.h"
+
+/*
+===============
+=
+= M_Random
+=
+= Returns a 0-255 number
+=
+===============
+*/
+
+const unsigned int 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;
+
+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;
+}
+
diff --git a/src/heretic/m_random.h b/src/heretic/m_random.h
new file mode 100644
index 00000000..b1d2ca7d
--- /dev/null
+++ b/src/heretic/m_random.h
@@ -0,0 +1,42 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef HERETIC_M_RANDOM_H
+#define HERETIC_M_RANDOM_H
+
+// Most damage defined using HITDICE
+#define HITDICE(a) ((1+(P_Random()&7))*a)
+
+int M_Random(void);
+// returns a number from 0 to 255
+int P_Random(void);
+// as M_Random, but used only by the play simulation
+
+void M_ClearRandom(void);
+// fix randoms for demos
+
+extern int rndindex;
+
+#endif // HERETIC_M_RANDOM_H
+
diff --git a/src/heretic/mn_menu.c b/src/heretic/mn_menu.c
new file mode 100644
index 00000000..4958d9be
--- /dev/null
+++ b/src/heretic/mn_menu.c
@@ -0,0 +1,1667 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// MN_menu.c
+
+#include <ctype.h>
+
+#include "deh_str.h"
+#include "doomdef.h"
+#include "doomkeys.h"
+#include "i_system.h"
+#include "i_swap.h"
+#include "m_controls.h"
+#include "p_local.h"
+#include "r_local.h"
+#include "s_sound.h"
+#include "v_video.h"
+
+// Macros
+
+#define LEFT_DIR 0
+#define RIGHT_DIR 1
+#define ITEM_HEIGHT 20
+#define SELECTOR_XOFFSET (-28)
+#define SELECTOR_YOFFSET (-1)
+#define SLOTTEXTLEN 16
+#define ASCII_CURSOR '['
+
+// Types
+
+typedef enum
+{
+ ITT_EMPTY,
+ ITT_EFUNC,
+ ITT_LRFUNC,
+ ITT_SETMENU,
+ ITT_INERT
+} ItemType_t;
+
+typedef enum
+{
+ MENU_MAIN,
+ MENU_EPISODE,
+ MENU_SKILL,
+ MENU_OPTIONS,
+ MENU_OPTIONS2,
+ MENU_FILES,
+ MENU_LOAD,
+ MENU_SAVE,
+ MENU_NONE
+} MenuType_t;
+
+typedef struct
+{
+ ItemType_t type;
+ char *text;
+ boolean(*func) (int option);
+ int option;
+ MenuType_t menu;
+} MenuItem_t;
+
+typedef struct
+{
+ int x;
+ int y;
+ void (*drawFunc) (void);
+ int itemCount;
+ MenuItem_t *items;
+ int oldItPos;
+ MenuType_t prevMenu;
+} Menu_t;
+
+// Private Functions
+
+static void InitFonts(void);
+static void SetMenu(MenuType_t menu);
+static boolean SCNetCheck(int option);
+static boolean SCQuitGame(int option);
+static boolean SCEpisode(int option);
+static boolean SCSkill(int option);
+static boolean SCMouseSensi(int option);
+static boolean SCSfxVolume(int option);
+static boolean SCMusicVolume(int option);
+static boolean SCScreenSize(int option);
+static boolean SCLoadGame(int option);
+static boolean SCSaveGame(int option);
+static boolean SCMessages(int option);
+static boolean SCEndGame(int option);
+static boolean SCInfo(int option);
+static void DrawMainMenu(void);
+static void DrawEpisodeMenu(void);
+static void DrawSkillMenu(void);
+static void DrawOptionsMenu(void);
+static void DrawOptions2Menu(void);
+static void DrawFileSlots(Menu_t * menu);
+static void DrawFilesMenu(void);
+static void MN_DrawInfo(void);
+static void DrawLoadMenu(void);
+static void DrawSaveMenu(void);
+static void DrawSlider(Menu_t * menu, int item, int width, int slot);
+void MN_LoadSlotText(void);
+
+// External Data
+
+extern int detailLevel;
+extern int screenblocks;
+
+// Public Data
+
+boolean MenuActive;
+int InfoType;
+boolean messageson;
+
+// Private Data
+
+static int FontABaseLump;
+static int FontBBaseLump;
+static int SkullBaseLump;
+static Menu_t *CurrentMenu;
+static int CurrentItPos;
+static int MenuEpisode;
+static int MenuTime;
+static boolean soundchanged;
+
+boolean askforquit;
+static int typeofask;
+static boolean FileMenuKeySteal;
+static boolean slottextloaded;
+static char SlotText[6][SLOTTEXTLEN + 2];
+static char oldSlotText[SLOTTEXTLEN + 2];
+static int SlotStatus[6];
+static int slotptr;
+static int currentSlot;
+static int quicksave;
+static int quickload;
+
+static MenuItem_t MainItems[] = {
+ {ITT_EFUNC, "NEW GAME", SCNetCheck, 1, MENU_EPISODE},
+ {ITT_SETMENU, "OPTIONS", NULL, 0, MENU_OPTIONS},
+ {ITT_SETMENU, "GAME FILES", NULL, 0, MENU_FILES},
+ {ITT_EFUNC, "INFO", SCInfo, 0, MENU_NONE},
+ {ITT_EFUNC, "QUIT GAME", SCQuitGame, 0, MENU_NONE}
+};
+
+static Menu_t MainMenu = {
+ 110, 56,
+ DrawMainMenu,
+ 5, MainItems,
+ 0,
+ MENU_NONE
+};
+
+static MenuItem_t EpisodeItems[] = {
+ {ITT_EFUNC, "CITY OF THE DAMNED", SCEpisode, 1, MENU_NONE},
+ {ITT_EFUNC, "HELL'S MAW", SCEpisode, 2, MENU_NONE},
+ {ITT_EFUNC, "THE DOME OF D'SPARIL", SCEpisode, 3, MENU_NONE},
+ {ITT_EFUNC, "THE OSSUARY", SCEpisode, 4, MENU_NONE},
+ {ITT_EFUNC, "THE STAGNANT DEMESNE", SCEpisode, 5, MENU_NONE}
+};
+
+static Menu_t EpisodeMenu = {
+ 80, 50,
+ DrawEpisodeMenu,
+ 3, EpisodeItems,
+ 0,
+ MENU_MAIN
+};
+
+static MenuItem_t FilesItems[] = {
+ {ITT_EFUNC, "LOAD GAME", SCNetCheck, 2, MENU_LOAD},
+ {ITT_SETMENU, "SAVE GAME", NULL, 0, MENU_SAVE}
+};
+
+static Menu_t FilesMenu = {
+ 110, 60,
+ DrawFilesMenu,
+ 2, FilesItems,
+ 0,
+ MENU_MAIN
+};
+
+static MenuItem_t LoadItems[] = {
+ {ITT_EFUNC, NULL, SCLoadGame, 0, MENU_NONE},
+ {ITT_EFUNC, NULL, SCLoadGame, 1, MENU_NONE},
+ {ITT_EFUNC, NULL, SCLoadGame, 2, MENU_NONE},
+ {ITT_EFUNC, NULL, SCLoadGame, 3, MENU_NONE},
+ {ITT_EFUNC, NULL, SCLoadGame, 4, MENU_NONE},
+ {ITT_EFUNC, NULL, SCLoadGame, 5, MENU_NONE}
+};
+
+static Menu_t LoadMenu = {
+ 70, 30,
+ DrawLoadMenu,
+ 6, LoadItems,
+ 0,
+ MENU_FILES
+};
+
+static MenuItem_t SaveItems[] = {
+ {ITT_EFUNC, NULL, SCSaveGame, 0, MENU_NONE},
+ {ITT_EFUNC, NULL, SCSaveGame, 1, MENU_NONE},
+ {ITT_EFUNC, NULL, SCSaveGame, 2, MENU_NONE},
+ {ITT_EFUNC, NULL, SCSaveGame, 3, MENU_NONE},
+ {ITT_EFUNC, NULL, SCSaveGame, 4, MENU_NONE},
+ {ITT_EFUNC, NULL, SCSaveGame, 5, MENU_NONE}
+};
+
+static Menu_t SaveMenu = {
+ 70, 30,
+ DrawSaveMenu,
+ 6, SaveItems,
+ 0,
+ MENU_FILES
+};
+
+static MenuItem_t SkillItems[] = {
+ {ITT_EFUNC, "THOU NEEDETH A WET-NURSE", SCSkill, sk_baby, MENU_NONE},
+ {ITT_EFUNC, "YELLOWBELLIES-R-US", SCSkill, sk_easy, MENU_NONE},
+ {ITT_EFUNC, "BRINGEST THEM ONETH", SCSkill, sk_medium, MENU_NONE},
+ {ITT_EFUNC, "THOU ART A SMITE-MEISTER", SCSkill, sk_hard, MENU_NONE},
+ {ITT_EFUNC, "BLACK PLAGUE POSSESSES THEE",
+ SCSkill, sk_nightmare, MENU_NONE}
+};
+
+static Menu_t SkillMenu = {
+ 38, 30,
+ DrawSkillMenu,
+ 5, SkillItems,
+ 2,
+ MENU_EPISODE
+};
+
+static MenuItem_t OptionsItems[] = {
+ {ITT_EFUNC, "END GAME", SCEndGame, 0, MENU_NONE},
+ {ITT_EFUNC, "MESSAGES : ", SCMessages, 0, MENU_NONE},
+ {ITT_LRFUNC, "MOUSE SENSITIVITY", SCMouseSensi, 0, MENU_NONE},
+ {ITT_EMPTY, NULL, NULL, 0, MENU_NONE},
+ {ITT_SETMENU, "MORE...", NULL, 0, MENU_OPTIONS2}
+};
+
+static Menu_t OptionsMenu = {
+ 88, 30,
+ DrawOptionsMenu,
+ 5, OptionsItems,
+ 0,
+ MENU_MAIN
+};
+
+static MenuItem_t Options2Items[] = {
+ {ITT_LRFUNC, "SCREEN SIZE", SCScreenSize, 0, MENU_NONE},
+ {ITT_EMPTY, NULL, NULL, 0, MENU_NONE},
+ {ITT_LRFUNC, "SFX VOLUME", SCSfxVolume, 0, MENU_NONE},
+ {ITT_EMPTY, NULL, NULL, 0, MENU_NONE},
+ {ITT_LRFUNC, "MUSIC VOLUME", SCMusicVolume, 0, MENU_NONE},
+ {ITT_EMPTY, NULL, NULL, 0, MENU_NONE}
+};
+
+static Menu_t Options2Menu = {
+ 90, 20,
+ DrawOptions2Menu,
+ 6, Options2Items,
+ 0,
+ MENU_OPTIONS
+};
+
+static Menu_t *Menus[] = {
+ &MainMenu,
+ &EpisodeMenu,
+ &SkillMenu,
+ &OptionsMenu,
+ &Options2Menu,
+ &FilesMenu,
+ &LoadMenu,
+ &SaveMenu
+};
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_Init
+//
+//---------------------------------------------------------------------------
+
+void MN_Init(void)
+{
+ InitFonts();
+ MenuActive = false;
+ messageson = true;
+ SkullBaseLump = W_GetNumForName(DEH_String("M_SKL00"));
+
+ if (gamemode == retail)
+ { // Add episodes 4 and 5 to the menu
+ EpisodeMenu.itemCount = 5;
+ EpisodeMenu.y -= ITEM_HEIGHT;
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC InitFonts
+//
+//---------------------------------------------------------------------------
+
+static void InitFonts(void)
+{
+ FontABaseLump = W_GetNumForName(DEH_String("FONTA_S")) + 1;
+ FontBBaseLump = W_GetNumForName(DEH_String("FONTB_S")) + 1;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_DrTextA
+//
+// Draw text using font A.
+//
+//---------------------------------------------------------------------------
+
+void MN_DrTextA(char *text, int x, int y)
+{
+ char c;
+ patch_t *p;
+
+ while ((c = *text++) != 0)
+ {
+ if (c < 33)
+ {
+ x += 5;
+ }
+ else
+ {
+ p = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
+ V_DrawPatch(x, y, p);
+ x += SHORT(p->width) - 1;
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC MN_TextAWidth
+//
+// Returns the pixel width of a string using font A.
+//
+//---------------------------------------------------------------------------
+
+int MN_TextAWidth(char *text)
+{
+ char c;
+ int width;
+ patch_t *p;
+
+ width = 0;
+ while ((c = *text++) != 0)
+ {
+ if (c < 33)
+ {
+ width += 5;
+ }
+ else
+ {
+ p = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
+ width += SHORT(p->width) - 1;
+ }
+ }
+ return (width);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_DrTextB
+//
+// Draw text using font B.
+//
+//---------------------------------------------------------------------------
+
+void MN_DrTextB(char *text, int x, int y)
+{
+ char c;
+ patch_t *p;
+
+ while ((c = *text++) != 0)
+ {
+ if (c < 33)
+ {
+ x += 8;
+ }
+ else
+ {
+ p = W_CacheLumpNum(FontBBaseLump + c - 33, PU_CACHE);
+ V_DrawPatch(x, y, p);
+ x += SHORT(p->width) - 1;
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC MN_TextBWidth
+//
+// Returns the pixel width of a string using font B.
+//
+//---------------------------------------------------------------------------
+
+int MN_TextBWidth(char *text)
+{
+ char c;
+ int width;
+ patch_t *p;
+
+ width = 0;
+ while ((c = *text++) != 0)
+ {
+ if (c < 33)
+ {
+ width += 5;
+ }
+ else
+ {
+ p = W_CacheLumpNum(FontBBaseLump + c - 33, PU_CACHE);
+ width += SHORT(p->width) - 1;
+ }
+ }
+ return (width);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_Ticker
+//
+//---------------------------------------------------------------------------
+
+void MN_Ticker(void)
+{
+ if (MenuActive == false)
+ {
+ return;
+ }
+ MenuTime++;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_Drawer
+//
+//---------------------------------------------------------------------------
+
+char *QuitEndMsg[] = {
+ "ARE YOU SURE YOU WANT TO QUIT?",
+ "ARE YOU SURE YOU WANT TO END THE GAME?",
+ "DO YOU WANT TO QUICKSAVE THE GAME NAMED",
+ "DO YOU WANT TO QUICKLOAD THE GAME NAMED"
+};
+
+void MN_Drawer(void)
+{
+ int i;
+ int x;
+ int y;
+ MenuItem_t *item;
+ char *message;
+ char *selName;
+
+ if (MenuActive == false)
+ {
+ if (askforquit)
+ {
+ message = DEH_String(QuitEndMsg[typeofask - 1]);
+
+ MN_DrTextA(message, 160 - MN_TextAWidth(message) / 2, 80);
+ if (typeofask == 3)
+ {
+ MN_DrTextA(SlotText[quicksave - 1], 160 -
+ MN_TextAWidth(SlotText[quicksave - 1]) / 2, 90);
+ MN_DrTextA(DEH_String("?"), 160 +
+ MN_TextAWidth(SlotText[quicksave - 1]) / 2, 90);
+ }
+ if (typeofask == 4)
+ {
+ MN_DrTextA(SlotText[quickload - 1], 160 -
+ MN_TextAWidth(SlotText[quickload - 1]) / 2, 90);
+ MN_DrTextA(DEH_String("?"), 160 +
+ MN_TextAWidth(SlotText[quickload - 1]) / 2, 90);
+ }
+ UpdateState |= I_FULLSCRN;
+ }
+ return;
+ }
+ else
+ {
+ UpdateState |= I_FULLSCRN;
+ if (InfoType)
+ {
+ MN_DrawInfo();
+ return;
+ }
+ if (screenblocks < 10)
+ {
+ BorderNeedRefresh = true;
+ }
+ if (CurrentMenu->drawFunc != NULL)
+ {
+ CurrentMenu->drawFunc();
+ }
+ x = CurrentMenu->x;
+ y = CurrentMenu->y;
+ item = CurrentMenu->items;
+ for (i = 0; i < CurrentMenu->itemCount; i++)
+ {
+ if (item->type != ITT_EMPTY && item->text)
+ {
+ MN_DrTextB(DEH_String(item->text), x, y);
+ }
+ y += ITEM_HEIGHT;
+ item++;
+ }
+ y = CurrentMenu->y + (CurrentItPos * ITEM_HEIGHT) + SELECTOR_YOFFSET;
+ selName = DEH_String(MenuTime & 16 ? "M_SLCTR1" : "M_SLCTR2");
+ V_DrawPatch(x + SELECTOR_XOFFSET, y,
+ W_CacheLumpName(selName, PU_CACHE));
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawMainMenu
+//
+//---------------------------------------------------------------------------
+
+static void DrawMainMenu(void)
+{
+ int frame;
+
+ frame = (MenuTime / 3) % 18;
+ V_DrawPatch(88, 0, W_CacheLumpName(DEH_String("M_HTIC"), PU_CACHE));
+ V_DrawPatch(40, 10, W_CacheLumpNum(SkullBaseLump + (17 - frame),
+ PU_CACHE));
+ V_DrawPatch(232, 10, W_CacheLumpNum(SkullBaseLump + frame, PU_CACHE));
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawEpisodeMenu
+//
+//---------------------------------------------------------------------------
+
+static void DrawEpisodeMenu(void)
+{
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawSkillMenu
+//
+//---------------------------------------------------------------------------
+
+static void DrawSkillMenu(void)
+{
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawFilesMenu
+//
+//---------------------------------------------------------------------------
+
+static void DrawFilesMenu(void)
+{
+// clear out the quicksave/quickload stuff
+ quicksave = 0;
+ quickload = 0;
+ players[consoleplayer].message = NULL;
+ players[consoleplayer].messageTics = 1;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawLoadMenu
+//
+//---------------------------------------------------------------------------
+
+static void DrawLoadMenu(void)
+{
+ char *title;
+
+ title = DEH_String("LOAD GAME");
+
+ MN_DrTextB(title, 160 - MN_TextBWidth(title) / 2, 10);
+ if (!slottextloaded)
+ {
+ MN_LoadSlotText();
+ }
+ DrawFileSlots(&LoadMenu);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawSaveMenu
+//
+//---------------------------------------------------------------------------
+
+static void DrawSaveMenu(void)
+{
+ char *title;
+
+ title = DEH_String("SAVE GAME");
+
+ MN_DrTextB(title, 160 - MN_TextBWidth(title) / 2, 10);
+ if (!slottextloaded)
+ {
+ MN_LoadSlotText();
+ }
+ DrawFileSlots(&SaveMenu);
+}
+
+//===========================================================================
+//
+// MN_LoadSlotText
+//
+// Loads in the text message for each slot
+//===========================================================================
+
+void MN_LoadSlotText(void)
+{
+ FILE *fp;
+ int i;
+ char *filename;
+
+ for (i = 0; i < 6; i++)
+ {
+ filename = SV_Filename(i);
+ fp = fopen(filename, "rb+");
+ free(filename);
+
+ if (!fp)
+ {
+ SlotText[i][0] = 0; // empty the string
+ SlotStatus[i] = 0;
+ continue;
+ }
+ fread(&SlotText[i], SLOTTEXTLEN, 1, fp);
+ fclose(fp);
+ SlotStatus[i] = 1;
+ }
+ slottextloaded = true;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawFileSlots
+//
+//---------------------------------------------------------------------------
+
+static void DrawFileSlots(Menu_t * menu)
+{
+ int i;
+ int x;
+ int y;
+
+ x = menu->x;
+ y = menu->y;
+ for (i = 0; i < 6; i++)
+ {
+ V_DrawPatch(x, y, W_CacheLumpName(DEH_String("M_FSLOT"), PU_CACHE));
+ if (SlotStatus[i])
+ {
+ MN_DrTextA(SlotText[i], x + 5, y + 5);
+ }
+ y += ITEM_HEIGHT;
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawOptionsMenu
+//
+//---------------------------------------------------------------------------
+
+static void DrawOptionsMenu(void)
+{
+ if (messageson)
+ {
+ MN_DrTextB(DEH_String("ON"), 196, 50);
+ }
+ else
+ {
+ MN_DrTextB(DEH_String("OFF"), 196, 50);
+ }
+ DrawSlider(&OptionsMenu, 3, 10, mouseSensitivity);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawOptions2Menu
+//
+//---------------------------------------------------------------------------
+
+static void DrawOptions2Menu(void)
+{
+ DrawSlider(&Options2Menu, 1, 9, screenblocks - 3);
+ DrawSlider(&Options2Menu, 3, 16, snd_MaxVolume);
+ DrawSlider(&Options2Menu, 5, 16, snd_MusicVolume);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCNetCheck
+//
+//---------------------------------------------------------------------------
+
+static boolean SCNetCheck(int option)
+{
+ if (!netgame)
+ { // okay to go into the menu
+ return true;
+ }
+ switch (option)
+ {
+ case 1:
+ P_SetMessage(&players[consoleplayer],
+ "YOU CAN'T START A NEW GAME IN NETPLAY!", true);
+ break;
+ case 2:
+ P_SetMessage(&players[consoleplayer],
+ "YOU CAN'T LOAD A GAME IN NETPLAY!", true);
+ break;
+ default:
+ break;
+ }
+ MenuActive = false;
+ return false;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCQuitGame
+//
+//---------------------------------------------------------------------------
+
+static boolean SCQuitGame(int option)
+{
+ MenuActive = false;
+ askforquit = true;
+ typeofask = 1; //quit game
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCEndGame
+//
+//---------------------------------------------------------------------------
+
+static boolean SCEndGame(int option)
+{
+ if (demoplayback || netgame)
+ {
+ return false;
+ }
+ MenuActive = false;
+ askforquit = true;
+ typeofask = 2; //endgame
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCMessages
+//
+//---------------------------------------------------------------------------
+
+static boolean SCMessages(int option)
+{
+ messageson ^= 1;
+ if (messageson)
+ {
+ P_SetMessage(&players[consoleplayer], DEH_String("MESSAGES ON"), true);
+ }
+ else
+ {
+ P_SetMessage(&players[consoleplayer], DEH_String("MESSAGES OFF"), true);
+ }
+ S_StartSound(NULL, sfx_chat);
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCLoadGame
+//
+//---------------------------------------------------------------------------
+
+static boolean SCLoadGame(int option)
+{
+ char *filename;
+
+ if (!SlotStatus[option])
+ { // slot's empty...don't try and load
+ return false;
+ }
+
+ filename = SV_Filename(option);
+ G_LoadGame(filename);
+ free(filename);
+
+ MN_DeactivateMenu();
+ BorderNeedRefresh = true;
+ if (quickload == -1)
+ {
+ quickload = option + 1;
+ players[consoleplayer].message = NULL;
+ players[consoleplayer].messageTics = 1;
+ }
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCSaveGame
+//
+//---------------------------------------------------------------------------
+
+static boolean SCSaveGame(int option)
+{
+ char *ptr;
+
+ if (!FileMenuKeySteal)
+ {
+ FileMenuKeySteal = true;
+ strcpy(oldSlotText, SlotText[option]);
+ ptr = SlotText[option];
+ while (*ptr)
+ {
+ ptr++;
+ }
+ *ptr = '[';
+ *(ptr + 1) = 0;
+ SlotStatus[option]++;
+ currentSlot = option;
+ slotptr = ptr - SlotText[option];
+ return false;
+ }
+ else
+ {
+ G_SaveGame(option, SlotText[option]);
+ FileMenuKeySteal = false;
+ MN_DeactivateMenu();
+ }
+ BorderNeedRefresh = true;
+ if (quicksave == -1)
+ {
+ quicksave = option + 1;
+ players[consoleplayer].message = NULL;
+ players[consoleplayer].messageTics = 1;
+ }
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCEpisode
+//
+//---------------------------------------------------------------------------
+
+static boolean SCEpisode(int option)
+{
+ if (gamemode == shareware && option > 1)
+ {
+ P_SetMessage(&players[consoleplayer],
+ "ONLY AVAILABLE IN THE REGISTERED VERSION", true);
+ }
+ else
+ {
+ MenuEpisode = option;
+ SetMenu(MENU_SKILL);
+ }
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCSkill
+//
+//---------------------------------------------------------------------------
+
+static boolean SCSkill(int option)
+{
+ G_DeferedInitNew(option, MenuEpisode, 1);
+ MN_DeactivateMenu();
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCMouseSensi
+//
+//---------------------------------------------------------------------------
+
+static boolean SCMouseSensi(int option)
+{
+ if (option == RIGHT_DIR)
+ {
+ if (mouseSensitivity < 9)
+ {
+ mouseSensitivity++;
+ }
+ }
+ else if (mouseSensitivity)
+ {
+ mouseSensitivity--;
+ }
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCSfxVolume
+//
+//---------------------------------------------------------------------------
+
+static boolean SCSfxVolume(int option)
+{
+ if (option == RIGHT_DIR)
+ {
+ if (snd_MaxVolume < 15)
+ {
+ snd_MaxVolume++;
+ }
+ }
+ else if (snd_MaxVolume)
+ {
+ snd_MaxVolume--;
+ }
+ S_SetMaxVolume(false); // don't recalc the sound curve, yet
+ soundchanged = true; // we'll set it when we leave the menu
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCMusicVolume
+//
+//---------------------------------------------------------------------------
+
+static boolean SCMusicVolume(int option)
+{
+ if (option == RIGHT_DIR)
+ {
+ if (snd_MusicVolume < 15)
+ {
+ snd_MusicVolume++;
+ }
+ }
+ else if (snd_MusicVolume)
+ {
+ snd_MusicVolume--;
+ }
+ S_SetMusicVolume();
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCScreenSize
+//
+//---------------------------------------------------------------------------
+
+static boolean SCScreenSize(int option)
+{
+ if (option == RIGHT_DIR)
+ {
+ if (screenblocks < 11)
+ {
+ screenblocks++;
+ }
+ }
+ else if (screenblocks > 3)
+ {
+ screenblocks--;
+ }
+ R_SetViewSize(screenblocks, detailLevel);
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCInfo
+//
+//---------------------------------------------------------------------------
+
+static boolean SCInfo(int option)
+{
+ InfoType = 1;
+ S_StartSound(NULL, sfx_dorcls);
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC MN_Responder
+//
+//---------------------------------------------------------------------------
+
+boolean MN_Responder(event_t * event)
+{
+ int charTyped;
+ int key;
+ int i;
+ MenuItem_t *item;
+ extern boolean automapactive;
+ extern void D_StartTitle(void);
+ extern void G_CheckDemoStatus(void);
+ char *textBuffer;
+
+ // In testcontrols mode, none of the function keys should do anything
+ // - the only key is escape to quit.
+
+ if (testcontrols)
+ {
+ if (event->type == ev_quit
+ || (event->type == ev_keydown
+ && (event->data1 == key_menu_activate
+ || event->data1 == key_menu_quit)))
+ {
+ I_Quit();
+ return true;
+ }
+
+ return false;
+ }
+
+ // "close" button pressed on window?
+ if (event->type == ev_quit)
+ {
+ // First click on close = bring up quit confirm message.
+ // Second click = confirm quit.
+
+ if (!MenuActive && askforquit && typeofask == 1)
+ {
+ G_CheckDemoStatus();
+ I_Quit();
+ }
+ else
+ {
+ SCQuitGame(0);
+ S_StartSound(NULL, sfx_chat);
+ }
+ return true;
+ }
+
+ if (event->data1 != KEY_RSHIFT && event->type != ev_keydown)
+ {
+ return (false);
+ }
+ key = event->data1;
+ charTyped = event->data2;
+
+ if (InfoType)
+ {
+ if (gamemode == shareware)
+ {
+ InfoType = (InfoType + 1) % 5;
+ }
+ else
+ {
+ InfoType = (InfoType + 1) % 4;
+ }
+ if (key == KEY_ESCAPE)
+ {
+ InfoType = 0;
+ }
+ if (!InfoType)
+ {
+ paused = false;
+ MN_DeactivateMenu();
+ SB_state = -1; //refresh the statbar
+ BorderNeedRefresh = true;
+ }
+ S_StartSound(NULL, sfx_dorcls);
+ return (true); //make the info screen eat the keypress
+ }
+
+ if (ravpic && key == KEY_F1)
+ {
+ G_ScreenShot();
+ return (true);
+ }
+
+ if (askforquit)
+ {
+ if (key == key_menu_confirm)
+ {
+ switch (typeofask)
+ {
+ case 1:
+ G_CheckDemoStatus();
+ I_Quit();
+ return false;
+
+ case 2:
+ players[consoleplayer].messageTics = 0;
+ //set the msg to be cleared
+ players[consoleplayer].message = NULL;
+ paused = false;
+ I_SetPalette(W_CacheLumpName
+ ("PLAYPAL", PU_CACHE));
+ D_StartTitle(); // go to intro/demo mode.
+ break;
+
+ case 3:
+ P_SetMessage(&players[consoleplayer],
+ "QUICKSAVING....", false);
+ FileMenuKeySteal = true;
+ SCSaveGame(quicksave - 1);
+ BorderNeedRefresh = true;
+ break;
+
+ case 4:
+ P_SetMessage(&players[consoleplayer],
+ "QUICKLOADING....", false);
+ SCLoadGame(quickload - 1);
+ BorderNeedRefresh = true;
+ break;
+
+ default:
+ break;
+ }
+
+ askforquit = false;
+ typeofask = 0;
+
+ return true;
+ }
+ else if (key == key_menu_abort || key == KEY_ESCAPE)
+ {
+ players[consoleplayer].messageTics = 1; //set the msg to be cleared
+ askforquit = false;
+ typeofask = 0;
+ paused = false;
+ UpdateState |= I_FULLSCRN;
+ BorderNeedRefresh = true;
+ return true;
+ }
+
+ return false; // don't let the keys filter thru
+ }
+
+ if (!MenuActive && !chatmodeon)
+ {
+ if (key == key_menu_decscreen)
+ {
+ if (automapactive)
+ { // Don't screen size in automap
+ return (false);
+ }
+ SCScreenSize(LEFT_DIR);
+ S_StartSound(NULL, sfx_keyup);
+ BorderNeedRefresh = true;
+ UpdateState |= I_FULLSCRN;
+ return (true);
+ }
+ else if (key == key_menu_incscreen)
+ {
+ if (automapactive)
+ { // Don't screen size in automap
+ return (false);
+ }
+ SCScreenSize(RIGHT_DIR);
+ S_StartSound(NULL, sfx_keyup);
+ BorderNeedRefresh = true;
+ UpdateState |= I_FULLSCRN;
+ return (true);
+ }
+ else if (key == key_menu_help) // F1
+ {
+ SCInfo(0); // start up info screens
+ MenuActive = true;
+ return (true);
+ }
+ else if (key == key_menu_save) // F2 (save game)
+ {
+ if (gamestate == GS_LEVEL && !demoplayback)
+ {
+ MenuActive = true;
+ FileMenuKeySteal = false;
+ MenuTime = 0;
+ CurrentMenu = &SaveMenu;
+ CurrentItPos = CurrentMenu->oldItPos;
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ S_StartSound(NULL, sfx_dorcls);
+ slottextloaded = false; //reload the slot text, when needed
+ }
+ return true;
+ }
+ else if (key == key_menu_load) // F3 (load game)
+ {
+ if (SCNetCheck(2))
+ {
+ MenuActive = true;
+ FileMenuKeySteal = false;
+ MenuTime = 0;
+ CurrentMenu = &LoadMenu;
+ CurrentItPos = CurrentMenu->oldItPos;
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ S_StartSound(NULL, sfx_dorcls);
+ slottextloaded = false; //reload the slot text, when needed
+ }
+ return true;
+ }
+ else if (key == key_menu_volume) // F4 (volume)
+ {
+ MenuActive = true;
+ FileMenuKeySteal = false;
+ MenuTime = 0;
+ CurrentMenu = &Options2Menu;
+ CurrentItPos = CurrentMenu->oldItPos;
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ S_StartSound(NULL, sfx_dorcls);
+ slottextloaded = false; //reload the slot text, when needed
+ return true;
+ }
+ else if (key == key_menu_detail) // F5 (detail)
+ {
+ // F5 isn't used in Heretic. (detail level)
+ return true;
+ }
+ else if (key == key_menu_qsave) // F6 (quicksave)
+ {
+ if (gamestate == GS_LEVEL && !demoplayback)
+ {
+ if (!quicksave || quicksave == -1)
+ {
+ MenuActive = true;
+ FileMenuKeySteal = false;
+ MenuTime = 0;
+ CurrentMenu = &SaveMenu;
+ CurrentItPos = CurrentMenu->oldItPos;
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ S_StartSound(NULL, sfx_dorcls);
+ slottextloaded = false; //reload the slot text, when needed
+ quicksave = -1;
+ P_SetMessage(&players[consoleplayer],
+ "CHOOSE A QUICKSAVE SLOT", true);
+ }
+ else
+ {
+ askforquit = true;
+ typeofask = 3;
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ S_StartSound(NULL, sfx_chat);
+ }
+ }
+ return true;
+ }
+ else if (key == key_menu_endgame) // F7 (end game)
+ {
+ if (gamestate == GS_LEVEL && !demoplayback)
+ {
+ S_StartSound(NULL, sfx_chat);
+ SCEndGame(0);
+ }
+ return true;
+ }
+ else if (key == key_menu_messages) // F8 (toggle messages)
+ {
+ SCMessages(0);
+ return true;
+ }
+ else if (key == key_menu_qload) // F9 (quickload)
+ {
+ if (!quickload || quickload == -1)
+ {
+ MenuActive = true;
+ FileMenuKeySteal = false;
+ MenuTime = 0;
+ CurrentMenu = &LoadMenu;
+ CurrentItPos = CurrentMenu->oldItPos;
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ S_StartSound(NULL, sfx_dorcls);
+ slottextloaded = false; //reload the slot text, when needed
+ quickload = -1;
+ P_SetMessage(&players[consoleplayer],
+ "CHOOSE A QUICKLOAD SLOT", true);
+ }
+ else
+ {
+ askforquit = true;
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ typeofask = 4;
+ S_StartSound(NULL, sfx_chat);
+ }
+ return true;
+ }
+ else if (key == key_menu_quit) // F10 (quit)
+ {
+ if (gamestate == GS_LEVEL)
+ {
+ SCQuitGame(0);
+ S_StartSound(NULL, sfx_chat);
+ }
+ return true;
+ }
+ else if (key == key_menu_gamma) // F11 (gamma correction)
+ {
+ usegamma++;
+ if (usegamma > 4)
+ {
+ usegamma = 0;
+ }
+ I_SetPalette((byte *) W_CacheLumpName("PLAYPAL", PU_CACHE));
+ return true;
+ }
+
+ }
+
+ if (!MenuActive)
+ {
+ if (key == key_menu_activate || gamestate == GS_DEMOSCREEN || demoplayback)
+ {
+ MN_ActivateMenu();
+ return (true);
+ }
+ return (false);
+ }
+ if (!FileMenuKeySteal)
+ {
+ item = &CurrentMenu->items[CurrentItPos];
+
+ if (key == key_menu_down) // Next menu item
+ {
+ do
+ {
+ if (CurrentItPos + 1 > CurrentMenu->itemCount - 1)
+ {
+ CurrentItPos = 0;
+ }
+ else
+ {
+ CurrentItPos++;
+ }
+ }
+ while (CurrentMenu->items[CurrentItPos].type == ITT_EMPTY);
+ S_StartSound(NULL, sfx_switch);
+ return (true);
+ }
+ else if (key == key_menu_up) // Previous menu item
+ {
+ do
+ {
+ if (CurrentItPos == 0)
+ {
+ CurrentItPos = CurrentMenu->itemCount - 1;
+ }
+ else
+ {
+ CurrentItPos--;
+ }
+ }
+ while (CurrentMenu->items[CurrentItPos].type == ITT_EMPTY);
+ S_StartSound(NULL, sfx_switch);
+ return (true);
+ }
+ else if (key == key_menu_left) // Slider left
+ {
+ if (item->type == ITT_LRFUNC && item->func != NULL)
+ {
+ item->func(LEFT_DIR);
+ S_StartSound(NULL, sfx_keyup);
+ }
+ return (true);
+ }
+ else if (key == key_menu_right) // Slider right
+ {
+ if (item->type == ITT_LRFUNC && item->func != NULL)
+ {
+ item->func(RIGHT_DIR);
+ S_StartSound(NULL, sfx_keyup);
+ }
+ return (true);
+ }
+ else if (key == key_menu_forward) // Activate item (enter)
+ {
+ if (item->type == ITT_SETMENU)
+ {
+ SetMenu(item->menu);
+ }
+ else if (item->func != NULL)
+ {
+ CurrentMenu->oldItPos = CurrentItPos;
+ if (item->type == ITT_LRFUNC)
+ {
+ item->func(RIGHT_DIR);
+ }
+ else if (item->type == ITT_EFUNC)
+ {
+ if (item->func(item->option))
+ {
+ if (item->menu != MENU_NONE)
+ {
+ SetMenu(item->menu);
+ }
+ }
+ }
+ }
+ S_StartSound(NULL, sfx_dorcls);
+ return (true);
+ }
+ else if (key == key_menu_activate) // Toggle menu
+ {
+ MN_DeactivateMenu();
+ return (true);
+ }
+ else if (key == key_menu_back) // Go back to previous menu
+ {
+ S_StartSound(NULL, sfx_switch);
+ if (CurrentMenu->prevMenu == MENU_NONE)
+ {
+ MN_DeactivateMenu();
+ }
+ else
+ {
+ SetMenu(CurrentMenu->prevMenu);
+ }
+ return (true);
+ }
+ else if (charTyped != 0)
+ {
+ // Jump to menu item based on first letter:
+
+ for (i = 0; i < CurrentMenu->itemCount; i++)
+ {
+ if (CurrentMenu->items[i].text)
+ {
+ if (toupper(charTyped)
+ == toupper(DEH_String(CurrentMenu->items[i].text)[0]))
+ {
+ CurrentItPos = i;
+ return (true);
+ }
+ }
+ }
+ }
+
+ return (false);
+ }
+ else
+ { // Editing file names
+ textBuffer = &SlotText[currentSlot][slotptr];
+ if (key == KEY_BACKSPACE)
+ {
+ if (slotptr)
+ {
+ *textBuffer-- = 0;
+ *textBuffer = ASCII_CURSOR;
+ slotptr--;
+ }
+ return (true);
+ }
+ if (key == KEY_ESCAPE)
+ {
+ memset(SlotText[currentSlot], 0, SLOTTEXTLEN + 2);
+ strcpy(SlotText[currentSlot], oldSlotText);
+ SlotStatus[currentSlot]--;
+ MN_DeactivateMenu();
+ return (true);
+ }
+ if (key == KEY_ENTER)
+ {
+ SlotText[currentSlot][slotptr] = 0; // clear the cursor
+ item = &CurrentMenu->items[CurrentItPos];
+ CurrentMenu->oldItPos = CurrentItPos;
+ if (item->type == ITT_EFUNC)
+ {
+ item->func(item->option);
+ if (item->menu != MENU_NONE)
+ {
+ SetMenu(item->menu);
+ }
+ }
+ return (true);
+ }
+ if (slotptr < SLOTTEXTLEN && key != KEY_BACKSPACE)
+ {
+ if (isalpha(charTyped))
+ {
+ *textBuffer++ = toupper(charTyped);
+ *textBuffer = ASCII_CURSOR;
+ slotptr++;
+ return (true);
+ }
+ if (isdigit(charTyped) || charTyped == ' '
+ || charTyped == ',' || charTyped == '.' || charTyped == '-'
+ || charTyped == '!')
+ {
+ *textBuffer++ = charTyped;
+ *textBuffer = ASCII_CURSOR;
+ slotptr++;
+ return (true);
+ }
+ }
+ return (true);
+ }
+ return (false);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_ActivateMenu
+//
+//---------------------------------------------------------------------------
+
+void MN_ActivateMenu(void)
+{
+ if (MenuActive)
+ {
+ return;
+ }
+ if (paused)
+ {
+ S_ResumeSound();
+ }
+ MenuActive = true;
+ FileMenuKeySteal = false;
+ MenuTime = 0;
+ CurrentMenu = &MainMenu;
+ CurrentItPos = CurrentMenu->oldItPos;
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ S_StartSound(NULL, sfx_dorcls);
+ slottextloaded = false; //reload the slot text, when needed
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_DeactivateMenu
+//
+//---------------------------------------------------------------------------
+
+void MN_DeactivateMenu(void)
+{
+ if (CurrentMenu != NULL)
+ {
+ CurrentMenu->oldItPos = CurrentItPos;
+ }
+ MenuActive = false;
+ if (!netgame)
+ {
+ paused = false;
+ }
+ S_StartSound(NULL, sfx_dorcls);
+ if (soundchanged)
+ {
+ S_SetMaxVolume(true); //recalc the sound curve
+ soundchanged = false;
+ }
+ players[consoleplayer].message = NULL;
+ players[consoleplayer].messageTics = 1;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_DrawInfo
+//
+//---------------------------------------------------------------------------
+
+void MN_DrawInfo(void)
+{
+ I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE));
+ V_DrawRawScreen(W_CacheLumpNum(W_GetNumForName("TITLE") + InfoType,
+ PU_CACHE));
+// V_DrawPatch(0, 0, W_CacheLumpNum(W_GetNumForName("TITLE")+InfoType,
+// PU_CACHE));
+}
+
+
+//---------------------------------------------------------------------------
+//
+// PROC SetMenu
+//
+//---------------------------------------------------------------------------
+
+static void SetMenu(MenuType_t menu)
+{
+ CurrentMenu->oldItPos = CurrentItPos;
+ CurrentMenu = Menus[menu];
+ CurrentItPos = CurrentMenu->oldItPos;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawSlider
+//
+//---------------------------------------------------------------------------
+
+static void DrawSlider(Menu_t * menu, int item, int width, int slot)
+{
+ int x;
+ int y;
+ int x2;
+ int count;
+
+ x = menu->x + 24;
+ y = menu->y + 2 + (item * ITEM_HEIGHT);
+ V_DrawPatch(x - 32, y, W_CacheLumpName(DEH_String("M_SLDLT"), PU_CACHE));
+ for (x2 = x, count = width; count--; x2 += 8)
+ {
+ V_DrawPatch(x2, y, W_CacheLumpName(DEH_String(count & 1 ? "M_SLDMD1"
+ : "M_SLDMD2"), PU_CACHE));
+ }
+ V_DrawPatch(x2, y, W_CacheLumpName(DEH_String("M_SLDRT"), PU_CACHE));
+ V_DrawPatch(x + 4 + slot * 8, y + 7,
+ W_CacheLumpName(DEH_String("M_SLDKB"), PU_CACHE));
+}
diff --git a/src/heretic/p_action.h b/src/heretic/p_action.h
new file mode 100644
index 00000000..8d8e383c
--- /dev/null
+++ b/src/heretic/p_action.h
@@ -0,0 +1,160 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// External definitions for action pointer functions.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef HERETIC_P_ACTION_H
+#define HERETIC_P_ACTION_H
+
+void A_FreeTargMobj();
+void A_RestoreSpecialThing1();
+void A_RestoreSpecialThing2();
+void A_HideThing();
+void A_UnHideThing();
+void A_RestoreArtifact();
+void A_Scream();
+void A_Explode();
+void A_PodPain();
+void A_RemovePod();
+void A_MakePod();
+void A_InitKeyGizmo();
+void A_VolcanoSet();
+void A_VolcanoBlast();
+void A_BeastPuff();
+void A_VolcBallImpact();
+void A_SpawnTeleGlitter();
+void A_SpawnTeleGlitter2();
+void A_AccTeleGlitter();
+void A_Light0();
+void A_WeaponReady();
+void A_Lower();
+void A_Raise();
+void A_StaffAttackPL1();
+void A_ReFire();
+void A_StaffAttackPL2();
+void A_BeakReady();
+void A_BeakRaise();
+void A_BeakAttackPL1();
+void A_BeakAttackPL2();
+void A_GauntletAttack();
+void A_FireBlasterPL1();
+void A_FireBlasterPL2();
+void A_SpawnRippers();
+void A_FireMacePL1();
+void A_FireMacePL2();
+void A_MacePL1Check();
+void A_MaceBallImpact();
+void A_MaceBallImpact2();
+void A_DeathBallImpact();
+void A_FireSkullRodPL1();
+void A_FireSkullRodPL2();
+void A_SkullRodPL2Seek();
+void A_AddPlayerRain();
+void A_HideInCeiling();
+void A_SkullRodStorm();
+void A_RainImpact();
+void A_FireGoldWandPL1();
+void A_FireGoldWandPL2();
+void A_FirePhoenixPL1();
+void A_InitPhoenixPL2();
+void A_FirePhoenixPL2();
+void A_ShutdownPhoenixPL2();
+void A_PhoenixPuff();
+void A_RemovedPhoenixFunc();
+void A_FlameEnd();
+void A_FloatPuff();
+void A_FireCrossbowPL1();
+void A_FireCrossbowPL2();
+void A_BoltSpark();
+void A_Pain();
+void A_NoBlocking();
+void A_AddPlayerCorpse();
+void A_SkullPop();
+void A_FlameSnd();
+void A_CheckBurnGone();
+void A_CheckSkullFloor();
+void A_CheckSkullDone();
+void A_Feathers();
+void A_ChicLook();
+void A_ChicChase();
+void A_ChicPain();
+void A_FaceTarget();
+void A_ChicAttack();
+void A_Look();
+void A_Chase();
+void A_MummyAttack();
+void A_MummyAttack2();
+void A_MummySoul();
+void A_ContMobjSound();
+void A_MummyFX1Seek();
+void A_BeastAttack();
+void A_SnakeAttack();
+void A_SnakeAttack2();
+void A_HeadAttack();
+void A_BossDeath();
+void A_HeadIceImpact();
+void A_HeadFireGrow();
+void A_WhirlwindSeek();
+void A_ClinkAttack();
+void A_WizAtk1();
+void A_WizAtk2();
+void A_WizAtk3();
+void A_GhostOff();
+void A_ImpMeAttack();
+void A_ImpMsAttack();
+void A_ImpMsAttack2();
+void A_ImpDeath();
+void A_ImpXDeath1();
+void A_ImpXDeath2();
+void A_ImpExplode();
+void A_KnightAttack();
+void A_DripBlood();
+void A_Sor1Chase();
+void A_Sor1Pain();
+void A_Srcr1Attack();
+void A_SorZap();
+void A_SorcererRise();
+void A_SorRise();
+void A_SorSightSnd();
+void A_Srcr2Decide();
+void A_Srcr2Attack();
+void A_Sor2DthInit();
+void A_SorDSph();
+void A_Sor2DthLoop();
+void A_SorDExp();
+void A_SorDBon();
+void A_BlueSpark();
+void A_GenWizard();
+void A_MinotaurAtk1();
+void A_MinotaurDecide();
+void A_MinotaurAtk2();
+void A_MinotaurAtk3();
+void A_MinotaurCharge();
+void A_MntrFloorFire();
+void A_ESound();
+
+#endif /* #ifndef HERETIC_P_ACTION_H */
+
diff --git a/src/heretic/p_ceilng.c b/src/heretic/p_ceilng.c
new file mode 100644
index 00000000..bf7ef676
--- /dev/null
+++ b/src/heretic/p_ceilng.c
@@ -0,0 +1,263 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+#include "doomdef.h"
+#include "p_local.h"
+#include "s_sound.h"
+#include "v_video.h"
+
+//==================================================================
+//==================================================================
+//
+// 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))
+ S_StartSound(&ceiling->sector->soundorg,
+ sfx_dormov);
+ if (res == pastdest)
+ switch (ceiling->type)
+ {
+ case raiseToHighest:
+ P_RemoveActiveCeiling(ceiling);
+ break;
+ 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))
+ S_StartSound(&ceiling->sector->soundorg,
+ sfx_dormov);
+ if (res == pastdest)
+ switch (ceiling->type)
+ {
+ case crushAndRaise:
+ ceiling->speed = CEILSPEED;
+ case fastCrushAndRaise:
+ ceiling->direction = 1;
+ break;
+ case lowerAndCrush:
+ case lowerToFloor:
+ P_RemoveActiveCeiling(ceiling);
+ break;
+ default:
+ break;
+ }
+ else if (res == crushed)
+ switch (ceiling->type)
+ {
+ 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, rtn;
+ sector_t *sec;
+ ceiling_t *ceiling;
+
+ secnum = -1;
+ rtn = 0;
+
+ //
+ // Reactivate in-stasis ceilings...for certain types.
+ //
+ switch (type)
+ {
+ case fastCrushAndRaise:
+ 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 = 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 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] == NULL)
+ {
+ 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 = NULL;
+ P_RemoveThinker(&activeceilings[i]->thinker);
+ activeceilings[i] = NULL;
+ 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 = 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 = NULL;
+ activeceilings[i]->direction = 0; // in-stasis
+ rtn = 1;
+ }
+
+ return rtn;
+}
diff --git a/src/heretic/p_doors.c b/src/heretic/p_doors.c
new file mode 100644
index 00000000..cd5e4e87
--- /dev/null
+++ b/src/heretic/p_doors.c
@@ -0,0 +1,387 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// P_doors.c
+
+#include "doomdef.h"
+#include "deh_str.h"
+#include "p_local.h"
+#include "s_sound.h"
+#include "v_video.h"
+
+//==================================================================
+//==================================================================
+//
+// 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 normal:
+ door->direction = -1; // time to go back down
+ S_StartSound(&door->sector->soundorg, sfx_doropn);
+ break;
+ case close30ThenOpen:
+ door->direction = 1;
+ S_StartSound(&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 = normal;
+ S_StartSound(&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 normal:
+ case close:
+ door->sector->specialdata = NULL;
+ P_RemoveThinker(&door->thinker); // unlink and free
+ S_StartSound(&door->sector->soundorg, sfx_dorcls);
+ break;
+ case close30ThenOpen:
+ door->direction = 0;
+ door->topcountdown = 35 * 30;
+ break;
+ default:
+ break;
+ }
+ }
+ else if (res == crushed)
+ {
+ switch (door->type)
+ {
+ case close: // DON'T GO BACK UP!
+ break;
+ default:
+ door->direction = 1;
+ S_StartSound(&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 normal:
+ door->direction = 0; // wait at top
+ door->topcountdown = door->topwait;
+ break;
+ case close30ThenOpen:
+ case open:
+ door->sector->specialdata = NULL;
+ P_RemoveThinker(&door->thinker); // unlink and free
+ S_StopSound(&door->sector->soundorg);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// EV_DoDoor
+//
+// Move a door up/down
+//
+//----------------------------------------------------------------------------
+
+int EV_DoDoor(line_t * line, vldoor_e type, fixed_t speed)
+{
+ int secnum;
+ int retcode;
+ sector_t *sec;
+ vldoor_t *door;
+
+ secnum = -1;
+ retcode = 0;
+ while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0)
+ {
+ sec = &sectors[secnum];
+ if (sec->specialdata)
+ {
+ continue;
+ }
+ // Add new door thinker
+ retcode = 1;
+ door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0);
+ P_AddThinker(&door->thinker);
+ sec->specialdata = door;
+ door->thinker.function = T_VerticalDoor;
+ door->sector = sec;
+ switch (type)
+ {
+ case close:
+ door->topheight = P_FindLowestCeilingSurrounding(sec);
+ door->topheight -= 4 * FRACUNIT;
+ door->direction = -1;
+ S_StartSound(&door->sector->soundorg, sfx_doropn);
+ break;
+ case close30ThenOpen:
+ door->topheight = sec->ceilingheight;
+ door->direction = -1;
+ S_StartSound(&door->sector->soundorg, sfx_doropn);
+ break;
+ case normal:
+ case open:
+ door->direction = 1;
+ door->topheight = P_FindLowestCeilingSurrounding(sec);
+ door->topheight -= 4 * FRACUNIT;
+ if (door->topheight != sec->ceilingheight)
+ {
+ S_StartSound(&door->sector->soundorg,
+ sfx_doropn);
+ }
+ break;
+ default:
+ break;
+ }
+ door->type = type;
+ door->speed = speed;
+ door->topwait = VDOORWAIT;
+ }
+ return (retcode);
+}
+
+//==================================================================
+//
+// EV_VerticalDoor : open a door manually, no tag value
+//
+//==================================================================
+void EV_VerticalDoor(line_t * line, mobj_t * thing)
+{
+ player_t *player;
+ 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->keys[key_blue])
+ {
+ P_SetMessage(player, DEH_String(TXT_NEEDBLUEKEY), false);
+ S_StartSound(NULL, sfx_plroof);
+ return;
+ }
+ break;
+ case 27: // Yellow Lock
+ case 34:
+ if (!player)
+ {
+ return;
+ }
+ if (!player->keys[key_yellow])
+ {
+ P_SetMessage(player, DEH_String(TXT_NEEDYELLOWKEY), false);
+ S_StartSound(NULL, sfx_plroof);
+ return;
+ }
+ break;
+ case 28: // Green Lock
+ case 33:
+ if (!player)
+ {
+ return;
+ }
+ if (!player->keys[key_green])
+ {
+ P_SetMessage(player, DEH_String(TXT_NEEDGREENKEY), false);
+ S_StartSound(NULL, sfx_plroof);
+ return;
+ }
+ break;
+ }
+
+ // if the sector has an active thinker, use it
+ sec = sides[line->sidenum[side ^ 1]].sector;
+ if (sec->specialdata)
+ {
+ door = sec->specialdata;
+ switch (line->special)
+ {
+ case 1: // ONLY FOR "RAISE" DOORS, NOT "OPEN"s
+ case 26:
+ case 27:
+ case 28:
+ if (door->direction == -1)
+ {
+ door->direction = 1; // go back up
+ }
+ else
+ {
+ if (!thing->player)
+ { // Monsters don't close doors
+ return;
+ }
+ door->direction = -1; // start going down immediately
+ }
+ return;
+ }
+ }
+
+ // for proper sound
+ switch (line->special)
+ {
+ case 1: // NORMAL DOOR SOUND
+ case 31:
+ S_StartSound(&sec->soundorg, sfx_doropn);
+ //S_StartSound(&sec->soundorg, sfx_dormov);
+ break;
+ default: // LOCKED DOOR SOUND
+ S_StartSound(&sec->soundorg, sfx_doropn);
+ //S_StartSound(&sec->soundorg, sfx_dormov);
+ break;
+ }
+
+ //
+ // new door thinker
+ //
+ door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0);
+ P_AddThinker(&door->thinker);
+ sec->specialdata = door;
+ door->thinker.function = T_VerticalDoor;
+ door->sector = sec;
+ door->direction = 1;
+ switch (line->special)
+ {
+ case 1:
+ case 26:
+ case 27:
+ case 28:
+ door->type = normal;
+ break;
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ door->type = open;
+ line->special = 0;
+ break;
+ }
+ door->speed = VDOORSPEED;
+ door->topwait = VDOORWAIT;
+
+ //
+ // 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 = T_VerticalDoor;
+ door->sector = sec;
+ door->direction = 0;
+ door->type = 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 = 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;
+}
diff --git a/src/heretic/p_enemy.c b/src/heretic/p_enemy.c
new file mode 100644
index 00000000..d569c78e
--- /dev/null
+++ b/src/heretic/p_enemy.c
@@ -0,0 +1,2686 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// P_enemy.c
+
+#include <stdlib.h>
+#include "doomdef.h"
+#include "i_system.h"
+#include "i_timer.h"
+#include "m_random.h"
+#include "p_local.h"
+#include "s_sound.h"
+#include "v_video.h"
+
+// Macros
+
+#define MAX_BOSS_SPOTS 8
+
+// Types
+
+typedef struct
+{
+ fixed_t x;
+ fixed_t y;
+ angle_t angle;
+} BossSpot_t;
+
+// Private Data
+
+static int BossSpotCount;
+static BossSpot_t BossSpots[MAX_BOSS_SPOTS];
+
+//----------------------------------------------------------------------------
+//
+// PROC P_InitMonsters
+//
+// Called at level load.
+//
+//----------------------------------------------------------------------------
+
+void P_InitMonsters(void)
+{
+ BossSpotCount = 0;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_AddBossSpot
+//
+//----------------------------------------------------------------------------
+
+void P_AddBossSpot(fixed_t x, fixed_t y, angle_t angle)
+{
+ if (BossSpotCount == MAX_BOSS_SPOTS)
+ {
+ I_Error("Too many boss spots.");
+ }
+ BossSpots[BossSpotCount].x = x;
+ BossSpots[BossSpotCount].y = y;
+ BossSpots[BossSpotCount].angle = angle;
+ BossSpotCount++;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_RecursiveSound
+//
+//----------------------------------------------------------------------------
+
+mobj_t *soundtarget;
+
+void P_RecursiveSound(sector_t * sec, int soundblocks)
+{
+ int i;
+ line_t *check;
+ sector_t *other;
+
+ // Wake up all monsters in this sector
+ if (sec->validcount == validcount
+ && sec->soundtraversed <= soundblocks + 1)
+ { // Already flooded
+ return;
+ }
+ sec->validcount = validcount;
+ sec->soundtraversed = soundblocks + 1;
+ sec->soundtarget = soundtarget;
+ for (i = 0; i < sec->linecount; i++)
+ {
+ check = sec->lines[i];
+ if (!(check->flags & ML_TWOSIDED))
+ {
+ continue;
+ }
+ P_LineOpening(check);
+ if (openrange <= 0)
+ { // Closed door
+ continue;
+ }
+ if (sides[check->sidenum[0]].sector == sec)
+ {
+ other = sides[check->sidenum[1]].sector;
+ }
+ else
+ {
+ other = sides[check->sidenum[0]].sector;
+ }
+ if (check->flags & ML_SOUNDBLOCK)
+ {
+ if (!soundblocks)
+ {
+ P_RecursiveSound(other, 1);
+ }
+ }
+ else
+ {
+ P_RecursiveSound(other, soundblocks);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_NoiseAlert
+//
+// If a monster yells at a player, it will alert other monsters to the
+// player.
+//
+//----------------------------------------------------------------------------
+
+void P_NoiseAlert(mobj_t * target, mobj_t * emmiter)
+{
+ soundtarget = target;
+ validcount++;
+ P_RecursiveSound(emmiter->subsector->sector, 0);
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_CheckMeleeRange
+//
+//----------------------------------------------------------------------------
+
+boolean P_CheckMeleeRange(mobj_t * actor)
+{
+ mobj_t *mo;
+ fixed_t dist;
+
+ if (!actor->target)
+ {
+ return (false);
+ }
+ mo = actor->target;
+ dist = P_AproxDistance(mo->x - actor->x, mo->y - actor->y);
+ if (dist >= MELEERANGE)
+ {
+ return (false);
+ }
+ if (!P_CheckSight(actor, mo))
+ {
+ return (false);
+ }
+ if (mo->z > actor->z + actor->height)
+ { // Target is higher than the attacker
+ return (false);
+ }
+ else if (actor->z > mo->z + mo->height)
+ { // Attacker is higher
+ return (false);
+ }
+ return (true);
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_CheckMissileRange
+//
+//----------------------------------------------------------------------------
+
+boolean P_CheckMissileRange(mobj_t * actor)
+{
+ fixed_t dist;
+
+ if (!P_CheckSight(actor, actor->target))
+ {
+ return (false);
+ }
+ if (actor->flags & MF_JUSTHIT)
+ { // The target just hit the enemy, so fight back!
+ actor->flags &= ~MF_JUSTHIT;
+ return (true);
+ }
+ if (actor->reactiontime)
+ { // Don't attack yet
+ return (false);
+ }
+ dist = (P_AproxDistance(actor->x - actor->target->x,
+ actor->y - actor->target->y) >> FRACBITS) - 64;
+ if (!actor->info->meleestate)
+ { // No melee attack, so fire more frequently
+ dist -= 128;
+ }
+ if (actor->type == MT_IMP)
+ { // Imp's fly attack from far away
+ dist >>= 1;
+ }
+ if (dist > 200)
+ {
+ dist = 200;
+ }
+ if (P_Random() < dist)
+ {
+ return (false);
+ }
+ return (true);
+}
+
+/*
+================
+=
+= P_Move
+=
+= Move in the current direction
+= returns false if the move is blocked
+================
+*/
+
+fixed_t xspeed[8] =
+ { FRACUNIT, 47000, 0, -47000, -FRACUNIT, -47000, 0, 47000 };
+fixed_t yspeed[8] =
+ { 0, 47000, FRACUNIT, 47000, 0, -47000, -FRACUNIT, -47000 };
+
+#define MAXSPECIALCROSS 8
+extern line_t *spechit[MAXSPECIALCROSS];
+extern int numspechit;
+
+boolean P_Move(mobj_t * actor)
+{
+ fixed_t tryx, tryy;
+ line_t *ld;
+ boolean good;
+
+ if (actor->movedir == DI_NODIR)
+ {
+ return (false);
+ }
+ tryx = actor->x + actor->info->speed * xspeed[actor->movedir];
+ tryy = actor->y + actor->info->speed * yspeed[actor->movedir];
+ if (!P_TryMove(actor, tryx, tryy))
+ { // open any specials
+ if (actor->flags & MF_FLOAT && floatok)
+ { // must adjust height
+ if (actor->z < tmfloorz)
+ {
+ actor->z += FLOATSPEED;
+ }
+ else
+ {
+ actor->z -= FLOATSPEED;
+ }
+ actor->flags |= MF_INFLOAT;
+ return (true);
+ }
+ if (!numspechit)
+ {
+ return false;
+ }
+ actor->movedir = DI_NODIR;
+ good = false;
+ while (numspechit--)
+ {
+ ld = spechit[numspechit];
+ // if the special isn't a door that can be opened, return false
+ if (P_UseSpecialLine(actor, ld))
+ {
+ good = true;
+ }
+ }
+ return (good);
+ }
+ else
+ {
+ actor->flags &= ~MF_INFLOAT;
+ }
+ if (!(actor->flags & MF_FLOAT))
+ {
+ if (actor->z > actor->floorz)
+ {
+ P_HitFloor(actor);
+ }
+ actor->z = actor->floorz;
+ }
+ return (true);
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_TryWalk
+//
+// Attempts to move actor in its current (ob->moveangle) direction.
+// If blocked by either a wall or an actor returns FALSE.
+// If move is either clear of block only by a door, returns TRUE and sets.
+// If a door is in the way, an OpenDoor call is made to start it opening.
+//
+//----------------------------------------------------------------------------
+
+boolean P_TryWalk(mobj_t * actor)
+{
+ if (!P_Move(actor))
+ {
+ return (false);
+ }
+ actor->movecount = P_Random() & 15;
+ return (true);
+}
+
+/*
+================
+=
+= P_NewChaseDir
+=
+================
+*/
+
+dirtype_t opposite[] =
+ { DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST, DI_EAST, DI_NORTHEAST,
+ DI_NORTH, DI_NORTHWEST, DI_NODIR
+};
+
+dirtype_t diags[] =
+ { DI_NORTHWEST, DI_NORTHEAST, DI_SOUTHWEST, DI_SOUTHEAST };
+
+void P_NewChaseDir(mobj_t * actor)
+{
+ fixed_t deltax, deltay;
+ dirtype_t d[3];
+ dirtype_t tdir, olddir, turnaround;
+
+ if (!actor->target)
+ I_Error("P_NewChaseDir: called with no target");
+
+ olddir = actor->movedir;
+ turnaround = opposite[olddir];
+
+ deltax = actor->target->x - actor->x;
+ deltay = actor->target->y - actor->y;
+ if (deltax > 10 * FRACUNIT)
+ d[1] = DI_EAST;
+ else if (deltax < -10 * FRACUNIT)
+ d[1] = DI_WEST;
+ else
+ d[1] = DI_NODIR;
+ if (deltay < -10 * FRACUNIT)
+ d[2] = DI_SOUTH;
+ else if (deltay > 10 * FRACUNIT)
+ d[2] = DI_NORTH;
+ else
+ d[2] = DI_NODIR;
+
+// try direct route
+ if (d[1] != DI_NODIR && d[2] != DI_NODIR)
+ {
+ actor->movedir = diags[((deltay < 0) << 1) + (deltax > 0)];
+ if (actor->movedir != turnaround && P_TryWalk(actor))
+ return;
+ }
+
+// try other directions
+ if (P_Random() > 200 || abs(deltay) > abs(deltax))
+ {
+ tdir = d[1];
+ d[1] = d[2];
+ d[2] = tdir;
+ }
+
+ if (d[1] == turnaround)
+ d[1] = DI_NODIR;
+ if (d[2] == turnaround)
+ d[2] = DI_NODIR;
+
+ if (d[1] != DI_NODIR)
+ {
+ actor->movedir = d[1];
+ if (P_TryWalk(actor))
+ return; /*either moved forward or attacked */
+ }
+
+ if (d[2] != DI_NODIR)
+ {
+ actor->movedir = d[2];
+ if (P_TryWalk(actor))
+ return;
+ }
+
+/* there is no direct path to the player, so pick another direction */
+
+ if (olddir != DI_NODIR)
+ {
+ actor->movedir = olddir;
+ if (P_TryWalk(actor))
+ return;
+ }
+
+ if (P_Random() & 1) /*randomly determine direction of search */
+ {
+ for (tdir = DI_EAST; tdir <= DI_SOUTHEAST; tdir++)
+ {
+ if (tdir != turnaround)
+ {
+ actor->movedir = tdir;
+ if (P_TryWalk(actor))
+ return;
+ }
+ }
+ }
+ else
+ {
+ for (tdir = DI_SOUTHEAST; tdir != DI_EAST-1; tdir--)
+ {
+ if (tdir != turnaround)
+ {
+ actor->movedir = tdir;
+ if (P_TryWalk(actor))
+ return;
+ }
+ }
+ }
+
+ if (turnaround != DI_NODIR)
+ {
+ actor->movedir = turnaround;
+ if (P_TryWalk(actor))
+ return;
+ }
+
+ actor->movedir = DI_NODIR; // can't move
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_LookForMonsters
+//
+//---------------------------------------------------------------------------
+
+#define MONS_LOOK_RANGE (20*64*FRACUNIT)
+#define MONS_LOOK_LIMIT 64
+
+boolean P_LookForMonsters(mobj_t * actor)
+{
+ int count;
+ mobj_t *mo;
+ thinker_t *think;
+
+ if (!P_CheckSight(players[0].mo, actor))
+ { // Player can't see monster
+ return (false);
+ }
+ count = 0;
+ for (think = thinkercap.next; think != &thinkercap; think = think->next)
+ {
+ if (think->function != P_MobjThinker)
+ { // Not a mobj thinker
+ continue;
+ }
+ mo = (mobj_t *) think;
+ if (!(mo->flags & MF_COUNTKILL) || (mo == actor) || (mo->health <= 0))
+ { // Not a valid monster
+ continue;
+ }
+ if (P_AproxDistance(actor->x - mo->x, actor->y - mo->y)
+ > MONS_LOOK_RANGE)
+ { // Out of range
+ continue;
+ }
+ if (P_Random() < 16)
+ { // Skip
+ continue;
+ }
+ if (count++ > MONS_LOOK_LIMIT)
+ { // Stop searching
+ return (false);
+ }
+ if (!P_CheckSight(actor, mo))
+ { // Out of sight
+ continue;
+ }
+ // Found a target monster
+ actor->target = mo;
+ return (true);
+ }
+ return (false);
+}
+
+/*
+================
+=
+= P_LookForPlayers
+=
+= If allaround is false, only look 180 degrees in front
+= returns true if a player is targeted
+================
+*/
+
+boolean P_LookForPlayers(mobj_t * actor, boolean allaround)
+{
+ int c;
+ int stop;
+ player_t *player;
+ angle_t an;
+ fixed_t dist;
+
+ if (!netgame && players[0].health <= 0)
+ { // Single player game and player is dead, look for monsters
+ return (P_LookForMonsters(actor));
+ }
+ c = 0;
+ stop = (actor->lastlook - 1) & 3;
+ for (;; actor->lastlook = (actor->lastlook + 1) & 3)
+ {
+ if (!playeringame[actor->lastlook])
+ continue;
+
+ if (c++ == 2 || actor->lastlook == stop)
+ return false; // done looking
+
+ player = &players[actor->lastlook];
+ if (player->health <= 0)
+ continue; // dead
+ if (!P_CheckSight(actor, player->mo))
+ continue; // out of sight
+
+ if (!allaround)
+ {
+ an = R_PointToAngle2(actor->x, actor->y,
+ player->mo->x, player->mo->y) - actor->angle;
+ if (an > ANG90 && an < ANG270)
+ {
+ dist = P_AproxDistance(player->mo->x - actor->x,
+ player->mo->y - actor->y);
+ // if real close, react anyway
+ if (dist > MELEERANGE)
+ continue; // behind back
+ }
+ }
+ if (player->mo->flags & MF_SHADOW)
+ { // Player is invisible
+ if ((P_AproxDistance(player->mo->x - actor->x,
+ player->mo->y - actor->y) > 2 * MELEERANGE)
+ && P_AproxDistance(player->mo->momx, player->mo->momy)
+ < 5 * FRACUNIT)
+ { // Player is sneaking - can't detect
+ return (false);
+ }
+ if (P_Random() < 225)
+ { // Player isn't sneaking, but still didn't detect
+ return (false);
+ }
+ }
+ actor->target = player->mo;
+ return (true);
+ }
+ return (false);
+}
+
+/*
+===============================================================================
+
+ ACTION ROUTINES
+
+===============================================================================
+*/
+
+/*
+==============
+=
+= A_Look
+=
+= Stay in state until a player is sighted
+=
+==============
+*/
+
+void A_Look(mobj_t * actor)
+{
+ mobj_t *targ;
+
+ actor->threshold = 0; // any shot will wake up
+ targ = actor->subsector->sector->soundtarget;
+ if (targ && (targ->flags & MF_SHOOTABLE))
+ {
+ actor->target = targ;
+ if (actor->flags & MF_AMBUSH)
+ {
+ if (P_CheckSight(actor, actor->target))
+ goto seeyou;
+ }
+ else
+ goto seeyou;
+ }
+
+
+ if (!P_LookForPlayers(actor, false))
+ return;
+
+// go into chase state
+ seeyou:
+ if (actor->info->seesound)
+ {
+ int sound;
+
+/*
+ switch (actor->info->seesound)
+ {
+ case sfx_posit1:
+ case sfx_posit2:
+ case sfx_posit3:
+ sound = sfx_posit1+P_Random()%3;
+ break;
+ case sfx_bgsit1:
+ case sfx_bgsit2:
+ sound = sfx_bgsit1+P_Random()%2;
+ break;
+ default:
+ sound = actor->info->seesound;
+ break;
+ }
+*/
+ sound = actor->info->seesound;
+ if (actor->flags2 & MF2_BOSS)
+ { // Full volume
+ S_StartSound(NULL, sound);
+ }
+ else
+ {
+ S_StartSound(actor, sound);
+ }
+ }
+ P_SetMobjState(actor, actor->info->seestate);
+}
+
+
+/*
+==============
+=
+= A_Chase
+=
+= Actor has a melee attack, so it tries to close as fast as possible
+=
+==============
+*/
+
+void A_Chase(mobj_t * actor)
+{
+ int delta;
+
+ if (actor->reactiontime)
+ {
+ actor->reactiontime--;
+ }
+
+ // Modify target threshold
+ if (actor->threshold)
+ {
+ actor->threshold--;
+ }
+
+ if (gameskill == sk_nightmare)
+ { // Monsters move faster in nightmare mode
+ actor->tics -= actor->tics / 2;
+ if (actor->tics < 3)
+ {
+ actor->tics = 3;
+ }
+ }
+
+//
+// turn towards movement direction if not there yet
+//
+ if (actor->movedir < 8)
+ {
+ actor->angle &= (7 << 29);
+ delta = actor->angle - (actor->movedir << 29);
+ if (delta > 0)
+ {
+ actor->angle -= ANG90 / 2;
+ }
+ else if (delta < 0)
+ {
+ actor->angle += ANG90 / 2;
+ }
+ }
+
+ if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+ { // look for a new target
+ if (P_LookForPlayers(actor, true))
+ { // got a new target
+ return;
+ }
+ P_SetMobjState(actor, actor->info->spawnstate);
+ return;
+ }
+
+//
+// don't attack twice in a row
+//
+ if (actor->flags & MF_JUSTATTACKED)
+ {
+ actor->flags &= ~MF_JUSTATTACKED;
+ if (gameskill != sk_nightmare)
+ P_NewChaseDir(actor);
+ return;
+ }
+
+//
+// check for melee attack
+//
+ if (actor->info->meleestate && P_CheckMeleeRange(actor))
+ {
+ if (actor->info->attacksound)
+ S_StartSound(actor, actor->info->attacksound);
+ P_SetMobjState(actor, actor->info->meleestate);
+ return;
+ }
+
+//
+// check for missile attack
+//
+ if (actor->info->missilestate)
+ {
+ if (gameskill < sk_nightmare && actor->movecount)
+ goto nomissile;
+ if (!P_CheckMissileRange(actor))
+ goto nomissile;
+ P_SetMobjState(actor, actor->info->missilestate);
+ actor->flags |= MF_JUSTATTACKED;
+ return;
+ }
+ nomissile:
+
+//
+// possibly choose another target
+//
+ if (netgame && !actor->threshold && !P_CheckSight(actor, actor->target))
+ {
+ if (P_LookForPlayers(actor, true))
+ return; // got a new target
+ }
+
+//
+// chase towards player
+//
+ if (--actor->movecount < 0 || !P_Move(actor))
+ {
+ P_NewChaseDir(actor);
+ }
+
+//
+// make active sound
+//
+ if (actor->info->activesound && P_Random() < 3)
+ {
+ if (actor->type == MT_WIZARD && P_Random() < 128)
+ {
+ S_StartSound(actor, actor->info->seesound);
+ }
+ else if (actor->type == MT_SORCERER2)
+ {
+ S_StartSound(NULL, actor->info->activesound);
+ }
+ else
+ {
+ S_StartSound(actor, actor->info->activesound);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FaceTarget
+//
+//----------------------------------------------------------------------------
+
+void A_FaceTarget(mobj_t * actor)
+{
+ if (!actor->target)
+ {
+ return;
+ }
+ actor->flags &= ~MF_AMBUSH;
+ actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x,
+ actor->target->y);
+ if (actor->target->flags & MF_SHADOW)
+ { // Target is a ghost
+ actor->angle += (P_Random() - P_Random()) << 21;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_Pain
+//
+//----------------------------------------------------------------------------
+
+void A_Pain(mobj_t * actor)
+{
+ if (actor->info->painsound)
+ {
+ S_StartSound(actor, actor->info->painsound);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_DripBlood
+//
+//----------------------------------------------------------------------------
+
+void A_DripBlood(mobj_t * actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x + ((P_Random() - P_Random()) << 11),
+ actor->y + ((P_Random() - P_Random()) << 11), actor->z,
+ MT_BLOOD);
+ mo->momx = (P_Random() - P_Random()) << 10;
+ mo->momy = (P_Random() - P_Random()) << 10;
+ mo->flags2 |= MF2_LOGRAV;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_KnightAttack
+//
+//----------------------------------------------------------------------------
+
+void A_KnightAttack(mobj_t * actor)
+{
+ if (!actor->target)
+ {
+ return;
+ }
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(3));
+ S_StartSound(actor, sfx_kgtat2);
+ return;
+ }
+ // Throw axe
+ S_StartSound(actor, actor->info->attacksound);
+ if (actor->type == MT_KNIGHTGHOST || P_Random() < 40)
+ { // Red axe
+ P_SpawnMissile(actor, actor->target, MT_REDAXE);
+ return;
+ }
+ // Green axe
+ P_SpawnMissile(actor, actor->target, MT_KNIGHTAXE);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_ImpExplode
+//
+//----------------------------------------------------------------------------
+
+void A_ImpExplode(mobj_t * actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_IMPCHUNK1);
+ mo->momx = (P_Random() - P_Random()) << 10;
+ mo->momy = (P_Random() - P_Random()) << 10;
+ mo->momz = 9 * FRACUNIT;
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_IMPCHUNK2);
+ mo->momx = (P_Random() - P_Random()) << 10;
+ mo->momy = (P_Random() - P_Random()) << 10;
+ mo->momz = 9 * FRACUNIT;
+ if (actor->special1.i == 666)
+ { // Extreme death crash
+ P_SetMobjState(actor, S_IMP_XCRASH1);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_BeastPuff
+//
+//----------------------------------------------------------------------------
+
+void A_BeastPuff(mobj_t * actor)
+{
+ if (P_Random() > 64)
+ {
+ P_SpawnMobj(actor->x + ((P_Random() - P_Random()) << 10),
+ actor->y + ((P_Random() - P_Random()) << 10),
+ actor->z + ((P_Random() - P_Random()) << 10), MT_PUFFY);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_ImpMeAttack
+//
+//----------------------------------------------------------------------------
+
+void A_ImpMeAttack(mobj_t * actor)
+{
+ if (!actor->target)
+ {
+ return;
+ }
+ S_StartSound(actor, actor->info->attacksound);
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, 5 + (P_Random() & 7));
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_ImpMsAttack
+//
+//----------------------------------------------------------------------------
+
+void A_ImpMsAttack(mobj_t * actor)
+{
+ mobj_t *dest;
+ angle_t an;
+ int dist;
+
+ if (!actor->target || P_Random() > 64)
+ {
+ P_SetMobjState(actor, actor->info->seestate);
+ return;
+ }
+ dest = actor->target;
+ actor->flags |= MF_SKULLFLY;
+ S_StartSound(actor, actor->info->attacksound);
+ A_FaceTarget(actor);
+ an = actor->angle >> ANGLETOFINESHIFT;
+ actor->momx = FixedMul(12 * FRACUNIT, finecosine[an]);
+ actor->momy = FixedMul(12 * FRACUNIT, finesine[an]);
+ dist = P_AproxDistance(dest->x - actor->x, dest->y - actor->y);
+ dist = dist / (12 * FRACUNIT);
+ if (dist < 1)
+ {
+ dist = 1;
+ }
+ actor->momz = (dest->z + (dest->height >> 1) - actor->z) / dist;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_ImpMsAttack2
+//
+// Fireball attack of the imp leader.
+//
+//----------------------------------------------------------------------------
+
+void A_ImpMsAttack2(mobj_t * actor)
+{
+ if (!actor->target)
+ {
+ return;
+ }
+ S_StartSound(actor, actor->info->attacksound);
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, 5 + (P_Random() & 7));
+ return;
+ }
+ P_SpawnMissile(actor, actor->target, MT_IMPBALL);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_ImpDeath
+//
+//----------------------------------------------------------------------------
+
+void A_ImpDeath(mobj_t * actor)
+{
+ actor->flags &= ~MF_SOLID;
+ actor->flags2 |= MF2_FOOTCLIP;
+ if (actor->z <= actor->floorz)
+ {
+ P_SetMobjState(actor, S_IMP_CRASH1);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_ImpXDeath1
+//
+//----------------------------------------------------------------------------
+
+void A_ImpXDeath1(mobj_t * actor)
+{
+ actor->flags &= ~MF_SOLID;
+ actor->flags |= MF_NOGRAVITY;
+ actor->flags2 |= MF2_FOOTCLIP;
+ actor->special1.i = 666; // Flag the crash routine
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_ImpXDeath2
+//
+//----------------------------------------------------------------------------
+
+void A_ImpXDeath2(mobj_t * actor)
+{
+ actor->flags &= ~MF_NOGRAVITY;
+ if (actor->z <= actor->floorz)
+ {
+ P_SetMobjState(actor, S_IMP_CRASH1);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_UpdateChicken
+//
+// Returns true if the chicken morphs.
+//
+//----------------------------------------------------------------------------
+
+boolean P_UpdateChicken(mobj_t * actor, int tics)
+{
+ mobj_t *fog;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ mobjtype_t moType;
+ mobj_t *mo;
+ mobj_t oldChicken;
+
+ actor->special1.i -= tics;
+ if (actor->special1.i > 0)
+ {
+ return (false);
+ }
+ moType = actor->special2.i;
+ x = actor->x;
+ y = actor->y;
+ z = actor->z;
+ oldChicken = *actor;
+ P_SetMobjState(actor, S_FREETARGMOBJ);
+ mo = P_SpawnMobj(x, y, z, moType);
+ if (P_TestMobjLocation(mo) == false)
+ { // Didn't fit
+ P_RemoveMobj(mo);
+ mo = P_SpawnMobj(x, y, z, MT_CHICKEN);
+ mo->angle = oldChicken.angle;
+ mo->flags = oldChicken.flags;
+ mo->health = oldChicken.health;
+ mo->target = oldChicken.target;
+ mo->special1.i = 5 * 35; // Next try in 5 seconds
+ mo->special2.i = moType;
+ return (false);
+ }
+ mo->angle = oldChicken.angle;
+ mo->target = oldChicken.target;
+ fog = P_SpawnMobj(x, y, z + TELEFOGHEIGHT, MT_TFOG);
+ S_StartSound(fog, sfx_telept);
+ return (true);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_ChicAttack
+//
+//----------------------------------------------------------------------------
+
+void A_ChicAttack(mobj_t * actor)
+{
+ if (P_UpdateChicken(actor, 18))
+ {
+ return;
+ }
+ if (!actor->target)
+ {
+ return;
+ }
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, 1 + (P_Random() & 1));
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_ChicLook
+//
+//----------------------------------------------------------------------------
+
+void A_ChicLook(mobj_t * actor)
+{
+ if (P_UpdateChicken(actor, 10))
+ {
+ return;
+ }
+ A_Look(actor);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_ChicChase
+//
+//----------------------------------------------------------------------------
+
+void A_ChicChase(mobj_t * actor)
+{
+ if (P_UpdateChicken(actor, 3))
+ {
+ return;
+ }
+ A_Chase(actor);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_ChicPain
+//
+//----------------------------------------------------------------------------
+
+void A_ChicPain(mobj_t * actor)
+{
+ if (P_UpdateChicken(actor, 10))
+ {
+ return;
+ }
+ S_StartSound(actor, actor->info->painsound);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_Feathers
+//
+//----------------------------------------------------------------------------
+
+void A_Feathers(mobj_t * actor)
+{
+ int i;
+ int count;
+ mobj_t *mo;
+
+ if (actor->health > 0)
+ { // Pain
+ count = P_Random() < 32 ? 2 : 1;
+ }
+ else
+ { // Death
+ count = 5 + (P_Random() & 3);
+ }
+ for (i = 0; i < count; i++)
+ {
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 20 * FRACUNIT,
+ MT_FEATHER);
+ mo->target = actor;
+ mo->momx = (P_Random() - P_Random()) << 8;
+ mo->momy = (P_Random() - P_Random()) << 8;
+ mo->momz = FRACUNIT + (P_Random() << 9);
+ P_SetMobjState(mo, S_FEATHER1 + (P_Random() & 7));
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MummyAttack
+//
+//----------------------------------------------------------------------------
+
+void A_MummyAttack(mobj_t * actor)
+{
+ if (!actor->target)
+ {
+ return;
+ }
+ S_StartSound(actor, actor->info->attacksound);
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(2));
+ S_StartSound(actor, sfx_mumat2);
+ return;
+ }
+ S_StartSound(actor, sfx_mumat1);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MummyAttack2
+//
+// Mummy leader missile attack.
+//
+//----------------------------------------------------------------------------
+
+void A_MummyAttack2(mobj_t * actor)
+{
+ mobj_t *mo;
+
+ if (!actor->target)
+ {
+ return;
+ }
+ //S_StartSound(actor, actor->info->attacksound);
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(2));
+ return;
+ }
+ mo = P_SpawnMissile(actor, actor->target, MT_MUMMYFX1);
+ //mo = P_SpawnMissile(actor, actor->target, MT_EGGFX);
+ if (mo != NULL)
+ {
+ mo->special1.m = actor->target;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MummyFX1Seek
+//
+//----------------------------------------------------------------------------
+
+void A_MummyFX1Seek(mobj_t * actor)
+{
+ P_SeekerMissile(actor, ANG1_X * 10, ANG1_X * 20);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MummySoul
+//
+//----------------------------------------------------------------------------
+
+void A_MummySoul(mobj_t * mummy)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(mummy->x, mummy->y, mummy->z + 10 * FRACUNIT,
+ MT_MUMMYSOUL);
+ mo->momz = FRACUNIT;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_Sor1Pain
+//
+//----------------------------------------------------------------------------
+
+void A_Sor1Pain(mobj_t * actor)
+{
+ actor->special1.i = 20; // Number of steps to walk fast
+ A_Pain(actor);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_Sor1Chase
+//
+//----------------------------------------------------------------------------
+
+void A_Sor1Chase(mobj_t * actor)
+{
+ if (actor->special1.i)
+ {
+ actor->special1.i--;
+ actor->tics -= 3;
+ }
+ A_Chase(actor);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_Srcr1Attack
+//
+// Sorcerer demon attack.
+//
+//----------------------------------------------------------------------------
+
+void A_Srcr1Attack(mobj_t * actor)
+{
+ mobj_t *mo;
+ fixed_t momz;
+ angle_t angle;
+
+ if (!actor->target)
+ {
+ return;
+ }
+ S_StartSound(actor, actor->info->attacksound);
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(8));
+ return;
+ }
+ if (actor->health > (actor->info->spawnhealth / 3) * 2)
+ { // Spit one fireball
+ P_SpawnMissile(actor, actor->target, MT_SRCRFX1);
+ }
+ else
+ { // Spit three fireballs
+ mo = P_SpawnMissile(actor, actor->target, MT_SRCRFX1);
+ if (mo)
+ {
+ momz = mo->momz;
+ angle = mo->angle;
+ P_SpawnMissileAngle(actor, MT_SRCRFX1, angle - ANG1_X * 3, momz);
+ P_SpawnMissileAngle(actor, MT_SRCRFX1, angle + ANG1_X * 3, momz);
+ }
+ if (actor->health < actor->info->spawnhealth / 3)
+ { // Maybe attack again
+ if (actor->special1.i)
+ { // Just attacked, so don't attack again
+ actor->special1.i = 0;
+ }
+ else
+ { // Set state to attack again
+ actor->special1.i = 1;
+ P_SetMobjState(actor, S_SRCR1_ATK4);
+ }
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_SorcererRise
+//
+//----------------------------------------------------------------------------
+
+void A_SorcererRise(mobj_t * actor)
+{
+ mobj_t *mo;
+
+ actor->flags &= ~MF_SOLID;
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SORCERER2);
+ P_SetMobjState(mo, S_SOR2_RISE1);
+ mo->angle = actor->angle;
+ mo->target = actor->target;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_DSparilTeleport
+//
+//----------------------------------------------------------------------------
+
+void P_DSparilTeleport(mobj_t * actor)
+{
+ int i;
+ fixed_t x;
+ fixed_t y;
+ fixed_t prevX;
+ fixed_t prevY;
+ fixed_t prevZ;
+ mobj_t *mo;
+
+ if (!BossSpotCount)
+ { // No spots
+ return;
+ }
+ i = P_Random();
+ do
+ {
+ i++;
+ x = BossSpots[i % BossSpotCount].x;
+ y = BossSpots[i % BossSpotCount].y;
+ }
+ while (P_AproxDistance(actor->x - x, actor->y - y) < 128 * FRACUNIT);
+ prevX = actor->x;
+ prevY = actor->y;
+ prevZ = actor->z;
+ if (P_TeleportMove(actor, x, y))
+ {
+ mo = P_SpawnMobj(prevX, prevY, prevZ, MT_SOR2TELEFADE);
+ S_StartSound(mo, sfx_telept);
+ P_SetMobjState(actor, S_SOR2_TELE1);
+ S_StartSound(actor, sfx_telept);
+ actor->z = actor->floorz;
+ actor->angle = BossSpots[i % BossSpotCount].angle;
+ actor->momx = actor->momy = actor->momz = 0;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_Srcr2Decide
+//
+//----------------------------------------------------------------------------
+
+void A_Srcr2Decide(mobj_t * actor)
+{
+ static int chance[] = {
+ 192, 120, 120, 120, 64, 64, 32, 16, 0
+ };
+
+ if (!BossSpotCount)
+ { // No spots
+ return;
+ }
+ if (P_Random() < chance[actor->health / (actor->info->spawnhealth / 8)])
+ {
+ P_DSparilTeleport(actor);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_Srcr2Attack
+//
+//----------------------------------------------------------------------------
+
+void A_Srcr2Attack(mobj_t * actor)
+{
+ int chance;
+
+ if (!actor->target)
+ {
+ return;
+ }
+ S_StartSound(NULL, actor->info->attacksound);
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(20));
+ return;
+ }
+ chance = actor->health < actor->info->spawnhealth / 2 ? 96 : 48;
+ if (P_Random() < chance)
+ { // Wizard spawners
+ P_SpawnMissileAngle(actor, MT_SOR2FX2,
+ actor->angle - ANG45, FRACUNIT / 2);
+ P_SpawnMissileAngle(actor, MT_SOR2FX2,
+ actor->angle + ANG45, FRACUNIT / 2);
+ }
+ else
+ { // Blue bolt
+ P_SpawnMissile(actor, actor->target, MT_SOR2FX1);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_BlueSpark
+//
+//----------------------------------------------------------------------------
+
+void A_BlueSpark(mobj_t * actor)
+{
+ int i;
+ mobj_t *mo;
+
+ for (i = 0; i < 2; i++)
+ {
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SOR2FXSPARK);
+ mo->momx = (P_Random() - P_Random()) << 9;
+ mo->momy = (P_Random() - P_Random()) << 9;
+ mo->momz = FRACUNIT + (P_Random() << 8);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_GenWizard
+//
+//----------------------------------------------------------------------------
+
+void A_GenWizard(mobj_t * actor)
+{
+ mobj_t *mo;
+ mobj_t *fog;
+
+ mo = P_SpawnMobj(actor->x, actor->y,
+ actor->z - mobjinfo[MT_WIZARD].height / 2, MT_WIZARD);
+ if (P_TestMobjLocation(mo) == false)
+ { // Didn't fit
+ P_RemoveMobj(mo);
+ return;
+ }
+ actor->momx = actor->momy = actor->momz = 0;
+ P_SetMobjState(actor, mobjinfo[actor->type].deathstate);
+ actor->flags &= ~MF_MISSILE;
+ fog = P_SpawnMobj(actor->x, actor->y, actor->z, MT_TFOG);
+ S_StartSound(fog, sfx_telept);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_Sor2DthInit
+//
+//----------------------------------------------------------------------------
+
+void A_Sor2DthInit(mobj_t * actor)
+{
+ actor->special1.i = 7; // Animation loop counter
+ P_Massacre(); // Kill monsters early
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_Sor2DthLoop
+//
+//----------------------------------------------------------------------------
+
+void A_Sor2DthLoop(mobj_t * actor)
+{
+ if (--actor->special1.i)
+ { // Need to loop
+ P_SetMobjState(actor, S_SOR2_DIE4);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// D'Sparil Sound Routines
+//
+//----------------------------------------------------------------------------
+
+void A_SorZap(mobj_t * actor)
+{
+ S_StartSound(NULL, sfx_sorzap);
+}
+
+void A_SorRise(mobj_t * actor)
+{
+ S_StartSound(NULL, sfx_sorrise);
+}
+
+void A_SorDSph(mobj_t * actor)
+{
+ S_StartSound(NULL, sfx_sordsph);
+}
+
+void A_SorDExp(mobj_t * actor)
+{
+ S_StartSound(NULL, sfx_sordexp);
+}
+
+void A_SorDBon(mobj_t * actor)
+{
+ S_StartSound(NULL, sfx_sordbon);
+}
+
+void A_SorSightSnd(mobj_t * actor)
+{
+ S_StartSound(NULL, sfx_sorsit);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MinotaurAtk1
+//
+// Melee attack.
+//
+//----------------------------------------------------------------------------
+
+void A_MinotaurAtk1(mobj_t * actor)
+{
+ player_t *player;
+
+ if (!actor->target)
+ {
+ return;
+ }
+ S_StartSound(actor, sfx_stfpow);
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(4));
+ if ((player = actor->target->player) != NULL)
+ { // Squish the player
+ player->deltaviewheight = -16 * FRACUNIT;
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MinotaurDecide
+//
+// Choose a missile attack.
+//
+//----------------------------------------------------------------------------
+
+#define MNTR_CHARGE_SPEED (13*FRACUNIT)
+
+void A_MinotaurDecide(mobj_t * actor)
+{
+ angle_t angle;
+ mobj_t *target;
+ int dist;
+
+ target = actor->target;
+ if (!target)
+ {
+ return;
+ }
+ S_StartSound(actor, sfx_minsit);
+ dist = P_AproxDistance(actor->x - target->x, actor->y - target->y);
+ if (target->z + target->height > actor->z
+ && target->z + target->height < actor->z + actor->height
+ && dist < 8 * 64 * FRACUNIT
+ && dist > 1 * 64 * FRACUNIT && P_Random() < 150)
+ { // Charge attack
+ // Don't call the state function right away
+ P_SetMobjStateNF(actor, S_MNTR_ATK4_1);
+ actor->flags |= MF_SKULLFLY;
+ A_FaceTarget(actor);
+ angle = actor->angle >> ANGLETOFINESHIFT;
+ actor->momx = FixedMul(MNTR_CHARGE_SPEED, finecosine[angle]);
+ actor->momy = FixedMul(MNTR_CHARGE_SPEED, finesine[angle]);
+ actor->special1.i = 35 / 2; // Charge duration
+ }
+ else if (target->z == target->floorz
+ && dist < 9 * 64 * FRACUNIT && P_Random() < 220)
+ { // Floor fire attack
+ P_SetMobjState(actor, S_MNTR_ATK3_1);
+ actor->special2.i = 0;
+ }
+ else
+ { // Swing attack
+ A_FaceTarget(actor);
+ // Don't need to call P_SetMobjState because the current state
+ // falls through to the swing attack
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MinotaurCharge
+//
+//----------------------------------------------------------------------------
+
+void A_MinotaurCharge(mobj_t * actor)
+{
+ mobj_t *puff;
+
+ if (actor->special1.i)
+ {
+ puff = P_SpawnMobj(actor->x, actor->y, actor->z, MT_PHOENIXPUFF);
+ puff->momz = 2 * FRACUNIT;
+ actor->special1.i--;
+ }
+ else
+ {
+ actor->flags &= ~MF_SKULLFLY;
+ P_SetMobjState(actor, actor->info->seestate);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MinotaurAtk2
+//
+// Swing attack.
+//
+//----------------------------------------------------------------------------
+
+void A_MinotaurAtk2(mobj_t * actor)
+{
+ mobj_t *mo;
+ angle_t angle;
+ fixed_t momz;
+
+ if (!actor->target)
+ {
+ return;
+ }
+ S_StartSound(actor, sfx_minat2);
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(5));
+ return;
+ }
+ mo = P_SpawnMissile(actor, actor->target, MT_MNTRFX1);
+ if (mo)
+ {
+ S_StartSound(mo, sfx_minat2);
+ momz = mo->momz;
+ angle = mo->angle;
+ P_SpawnMissileAngle(actor, MT_MNTRFX1, angle - (ANG45 / 8), momz);
+ P_SpawnMissileAngle(actor, MT_MNTRFX1, angle + (ANG45 / 8), momz);
+ P_SpawnMissileAngle(actor, MT_MNTRFX1, angle - (ANG45 / 16), momz);
+ P_SpawnMissileAngle(actor, MT_MNTRFX1, angle + (ANG45 / 16), momz);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MinotaurAtk3
+//
+// Floor fire attack.
+//
+//----------------------------------------------------------------------------
+
+void A_MinotaurAtk3(mobj_t * actor)
+{
+ mobj_t *mo;
+ player_t *player;
+
+ if (!actor->target)
+ {
+ return;
+ }
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(5));
+ if ((player = actor->target->player) != NULL)
+ { // Squish the player
+ player->deltaviewheight = -16 * FRACUNIT;
+ }
+ }
+ else
+ {
+ mo = P_SpawnMissile(actor, actor->target, MT_MNTRFX2);
+ if (mo != NULL)
+ {
+ S_StartSound(mo, sfx_minat1);
+ }
+ }
+ if (P_Random() < 192 && actor->special2.i == 0)
+ {
+ P_SetMobjState(actor, S_MNTR_ATK3_4);
+ actor->special2.i = 1;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MntrFloorFire
+//
+//----------------------------------------------------------------------------
+
+void A_MntrFloorFire(mobj_t * actor)
+{
+ mobj_t *mo;
+
+ actor->z = actor->floorz;
+ mo = P_SpawnMobj(actor->x + ((P_Random() - P_Random()) << 10),
+ actor->y + ((P_Random() - P_Random()) << 10), ONFLOORZ,
+ MT_MNTRFX3);
+ mo->target = actor->target;
+ mo->momx = 1; // Force block checking
+ P_CheckMissileSpawn(mo);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_BeastAttack
+//
+//----------------------------------------------------------------------------
+
+void A_BeastAttack(mobj_t * actor)
+{
+ if (!actor->target)
+ {
+ return;
+ }
+ S_StartSound(actor, actor->info->attacksound);
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(3));
+ return;
+ }
+ P_SpawnMissile(actor, actor->target, MT_BEASTBALL);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_HeadAttack
+//
+//----------------------------------------------------------------------------
+
+void A_HeadAttack(mobj_t * actor)
+{
+ int i;
+ mobj_t *fire;
+ mobj_t *baseFire;
+ mobj_t *mo;
+ mobj_t *target;
+ int randAttack;
+ static int atkResolve1[] = { 50, 150 };
+ static int atkResolve2[] = { 150, 200 };
+ int dist;
+
+ // Ice ball (close 20% : far 60%)
+ // Fire column (close 40% : far 20%)
+ // Whirlwind (close 40% : far 20%)
+ // Distance threshold = 8 cells
+
+ target = actor->target;
+ if (target == NULL)
+ {
+ return;
+ }
+ A_FaceTarget(actor);
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(target, actor, actor, HITDICE(6));
+ return;
+ }
+ dist = P_AproxDistance(actor->x - target->x, actor->y - target->y)
+ > 8 * 64 * FRACUNIT;
+ randAttack = P_Random();
+ if (randAttack < atkResolve1[dist])
+ { // Ice ball
+ P_SpawnMissile(actor, target, MT_HEADFX1);
+ S_StartSound(actor, sfx_hedat2);
+ }
+ else if (randAttack < atkResolve2[dist])
+ { // Fire column
+ baseFire = P_SpawnMissile(actor, target, MT_HEADFX3);
+ if (baseFire != NULL)
+ {
+ P_SetMobjState(baseFire, S_HEADFX3_4); // Don't grow
+ for (i = 0; i < 5; i++)
+ {
+ fire = P_SpawnMobj(baseFire->x, baseFire->y,
+ baseFire->z, MT_HEADFX3);
+ if (i == 0)
+ {
+ S_StartSound(actor, sfx_hedat1);
+ }
+ fire->target = baseFire->target;
+ fire->angle = baseFire->angle;
+ fire->momx = baseFire->momx;
+ fire->momy = baseFire->momy;
+ fire->momz = baseFire->momz;
+ fire->damage = 0;
+ fire->health = (i + 1) * 2;
+ P_CheckMissileSpawn(fire);
+ }
+ }
+ }
+ else
+ { // Whirlwind
+ mo = P_SpawnMissile(actor, target, MT_WHIRLWIND);
+ if (mo != NULL)
+ {
+ mo->z -= 32 * FRACUNIT;
+ mo->special1.m = target;
+ mo->special2.i = 50; // Timer for active sound
+ mo->health = 20 * TICRATE; // Duration
+ S_StartSound(actor, sfx_hedat3);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_WhirlwindSeek
+//
+//----------------------------------------------------------------------------
+
+void A_WhirlwindSeek(mobj_t * actor)
+{
+ actor->health -= 3;
+ if (actor->health < 0)
+ {
+ actor->momx = actor->momy = actor->momz = 0;
+ P_SetMobjState(actor, mobjinfo[actor->type].deathstate);
+ actor->flags &= ~MF_MISSILE;
+ return;
+ }
+ if ((actor->special2.i -= 3) < 0)
+ {
+ actor->special2.i = 58 + (P_Random() & 31);
+ S_StartSound(actor, sfx_hedat3);
+ }
+ if (actor->special1.m
+ && (((mobj_t *) (actor->special1.m))->flags & MF_SHADOW))
+ {
+ return;
+ }
+ P_SeekerMissile(actor, ANG1_X * 10, ANG1_X * 30);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_HeadIceImpact
+//
+//----------------------------------------------------------------------------
+
+void A_HeadIceImpact(mobj_t * ice)
+{
+ int i;
+ angle_t angle;
+ mobj_t *shard;
+
+ for (i = 0; i < 8; i++)
+ {
+ shard = P_SpawnMobj(ice->x, ice->y, ice->z, MT_HEADFX2);
+ angle = i * ANG45;
+ shard->target = ice->target;
+ shard->angle = angle;
+ angle >>= ANGLETOFINESHIFT;
+ shard->momx = FixedMul(shard->info->speed, finecosine[angle]);
+ shard->momy = FixedMul(shard->info->speed, finesine[angle]);
+ shard->momz = (fixed_t)(-.6 * FRACUNIT);
+ P_CheckMissileSpawn(shard);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_HeadFireGrow
+//
+//----------------------------------------------------------------------------
+
+void A_HeadFireGrow(mobj_t * fire)
+{
+ fire->health--;
+ fire->z += 9 * FRACUNIT;
+ if (fire->health == 0)
+ {
+ fire->damage = fire->info->damage;
+ P_SetMobjState(fire, S_HEADFX3_4);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_SnakeAttack
+//
+//----------------------------------------------------------------------------
+
+void A_SnakeAttack(mobj_t * actor)
+{
+ if (!actor->target)
+ {
+ P_SetMobjState(actor, S_SNAKE_WALK1);
+ return;
+ }
+ S_StartSound(actor, actor->info->attacksound);
+ A_FaceTarget(actor);
+ P_SpawnMissile(actor, actor->target, MT_SNAKEPRO_A);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_SnakeAttack2
+//
+//----------------------------------------------------------------------------
+
+void A_SnakeAttack2(mobj_t * actor)
+{
+ if (!actor->target)
+ {
+ P_SetMobjState(actor, S_SNAKE_WALK1);
+ return;
+ }
+ S_StartSound(actor, actor->info->attacksound);
+ A_FaceTarget(actor);
+ P_SpawnMissile(actor, actor->target, MT_SNAKEPRO_B);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_ClinkAttack
+//
+//----------------------------------------------------------------------------
+
+void A_ClinkAttack(mobj_t * actor)
+{
+ int damage;
+
+ if (!actor->target)
+ {
+ return;
+ }
+ S_StartSound(actor, actor->info->attacksound);
+ if (P_CheckMeleeRange(actor))
+ {
+ damage = ((P_Random() % 7) + 3);
+ P_DamageMobj(actor->target, actor, actor, damage);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_GhostOff
+//
+//----------------------------------------------------------------------------
+
+void A_GhostOff(mobj_t * actor)
+{
+ actor->flags &= ~MF_SHADOW;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_WizAtk1
+//
+//----------------------------------------------------------------------------
+
+void A_WizAtk1(mobj_t * actor)
+{
+ A_FaceTarget(actor);
+ actor->flags &= ~MF_SHADOW;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_WizAtk2
+//
+//----------------------------------------------------------------------------
+
+void A_WizAtk2(mobj_t * actor)
+{
+ A_FaceTarget(actor);
+ actor->flags |= MF_SHADOW;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_WizAtk3
+//
+//----------------------------------------------------------------------------
+
+void A_WizAtk3(mobj_t * actor)
+{
+ mobj_t *mo;
+ angle_t angle;
+ fixed_t momz;
+
+ actor->flags &= ~MF_SHADOW;
+ if (!actor->target)
+ {
+ return;
+ }
+ S_StartSound(actor, actor->info->attacksound);
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(4));
+ return;
+ }
+ mo = P_SpawnMissile(actor, actor->target, MT_WIZFX1);
+ if (mo)
+ {
+ momz = mo->momz;
+ angle = mo->angle;
+ P_SpawnMissileAngle(actor, MT_WIZFX1, angle - (ANG45 / 8), momz);
+ P_SpawnMissileAngle(actor, MT_WIZFX1, angle + (ANG45 / 8), momz);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_Scream
+//
+//----------------------------------------------------------------------------
+
+void A_Scream(mobj_t * actor)
+{
+ switch (actor->type)
+ {
+ case MT_CHICPLAYER:
+ case MT_SORCERER1:
+ case MT_MINOTAUR:
+ // Make boss death sounds full volume
+ S_StartSound(NULL, actor->info->deathsound);
+ break;
+ case MT_PLAYER:
+ // Handle the different player death screams
+ if (actor->special1.i < 10)
+ { // Wimpy death sound
+ S_StartSound(actor, sfx_plrwdth);
+ }
+ else if (actor->health > -50)
+ { // Normal death sound
+ S_StartSound(actor, actor->info->deathsound);
+ }
+ else if (actor->health > -100)
+ { // Crazy death sound
+ S_StartSound(actor, sfx_plrcdth);
+ }
+ else
+ { // Extreme death sound
+ S_StartSound(actor, sfx_gibdth);
+ }
+ break;
+ default:
+ S_StartSound(actor, actor->info->deathsound);
+ break;
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_DropItem
+//
+//---------------------------------------------------------------------------
+
+void P_DropItem(mobj_t * source, mobjtype_t type, int special, int chance)
+{
+ mobj_t *mo;
+
+ if (P_Random() > chance)
+ {
+ return;
+ }
+ mo = P_SpawnMobj(source->x, source->y,
+ source->z + (source->height >> 1), type);
+ mo->momx = (P_Random() - P_Random()) << 8;
+ mo->momy = (P_Random() - P_Random()) << 8;
+ mo->momz = FRACUNIT * 5 + (P_Random() << 10);
+ mo->flags |= MF_DROPPED;
+ mo->health = special;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_NoBlocking
+//
+//----------------------------------------------------------------------------
+
+void A_NoBlocking(mobj_t * actor)
+{
+ actor->flags &= ~MF_SOLID;
+ // Check for monsters dropping things
+ switch (actor->type)
+ {
+ case MT_MUMMY:
+ case MT_MUMMYLEADER:
+ case MT_MUMMYGHOST:
+ case MT_MUMMYLEADERGHOST:
+ P_DropItem(actor, MT_AMGWNDWIMPY, 3, 84);
+ break;
+ case MT_KNIGHT:
+ case MT_KNIGHTGHOST:
+ P_DropItem(actor, MT_AMCBOWWIMPY, 5, 84);
+ break;
+ case MT_WIZARD:
+ P_DropItem(actor, MT_AMBLSRWIMPY, 10, 84);
+ P_DropItem(actor, MT_ARTITOMEOFPOWER, 0, 4);
+ break;
+ case MT_HEAD:
+ P_DropItem(actor, MT_AMBLSRWIMPY, 10, 84);
+ P_DropItem(actor, MT_ARTIEGG, 0, 51);
+ break;
+ case MT_BEAST:
+ P_DropItem(actor, MT_AMCBOWWIMPY, 10, 84);
+ break;
+ case MT_CLINK:
+ P_DropItem(actor, MT_AMSKRDWIMPY, 20, 84);
+ break;
+ case MT_SNAKE:
+ P_DropItem(actor, MT_AMPHRDWIMPY, 5, 84);
+ break;
+ case MT_MINOTAUR:
+ P_DropItem(actor, MT_ARTISUPERHEAL, 0, 51);
+ P_DropItem(actor, MT_AMPHRDWIMPY, 10, 84);
+ break;
+ default:
+ break;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_Explode
+//
+// Handles a bunch of exploding things.
+//
+//----------------------------------------------------------------------------
+
+void A_Explode(mobj_t * actor)
+{
+ int damage;
+
+ damage = 128;
+ switch (actor->type)
+ {
+ case MT_FIREBOMB: // Time Bombs
+ actor->z += 32 * FRACUNIT;
+ actor->flags &= ~MF_SHADOW;
+ break;
+ case MT_MNTRFX2: // Minotaur floor fire
+ damage = 24;
+ break;
+ case MT_SOR2FX1: // D'Sparil missile
+ damage = 80 + (P_Random() & 31);
+ break;
+ default:
+ break;
+ }
+ P_RadiusAttack(actor, actor->target, damage);
+ P_HitFloor(actor);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_PodPain
+//
+//----------------------------------------------------------------------------
+
+void A_PodPain(mobj_t * actor)
+{
+ int i;
+ int count;
+ int chance;
+ mobj_t *goo;
+
+ chance = P_Random();
+ if (chance < 128)
+ {
+ return;
+ }
+ count = chance > 240 ? 2 : 1;
+ for (i = 0; i < count; i++)
+ {
+ goo = P_SpawnMobj(actor->x, actor->y,
+ actor->z + 48 * FRACUNIT, MT_PODGOO);
+ goo->target = actor;
+ goo->momx = (P_Random() - P_Random()) << 9;
+ goo->momy = (P_Random() - P_Random()) << 9;
+ goo->momz = FRACUNIT / 2 + (P_Random() << 9);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_RemovePod
+//
+//----------------------------------------------------------------------------
+
+void A_RemovePod(mobj_t * actor)
+{
+ mobj_t *mo;
+
+ if (actor->special2.m)
+ {
+ mo = (mobj_t *) actor->special2.m;
+ if (mo->special1.i > 0)
+ {
+ mo->special1.i--;
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MakePod
+//
+//----------------------------------------------------------------------------
+
+#define MAX_GEN_PODS 16
+
+void A_MakePod(mobj_t * actor)
+{
+ mobj_t *mo;
+ fixed_t x;
+ fixed_t y;
+
+ if (actor->special1.i == MAX_GEN_PODS)
+ { // Too many generated pods
+ return;
+ }
+ x = actor->x;
+ y = actor->y;
+ mo = P_SpawnMobj(x, y, ONFLOORZ, MT_POD);
+ if (P_CheckPosition(mo, x, y) == false)
+ { // Didn't fit
+ P_RemoveMobj(mo);
+ return;
+ }
+ P_SetMobjState(mo, S_POD_GROW1);
+ P_ThrustMobj(mo, P_Random() << 24, (fixed_t) (4.5 * FRACUNIT));
+ S_StartSound(mo, sfx_newpod);
+ actor->special1.i++; // Increment generated pod count
+ mo->special2.m = actor; // Link the generator to the pod
+ return;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_Massacre
+//
+// Kills all monsters.
+//
+//----------------------------------------------------------------------------
+
+void P_Massacre(void)
+{
+ mobj_t *mo;
+ thinker_t *think;
+
+ for (think = thinkercap.next; think != &thinkercap; think = think->next)
+ {
+ if (think->function != P_MobjThinker)
+ { // Not a mobj thinker
+ continue;
+ }
+ mo = (mobj_t *) think;
+ if ((mo->flags & MF_COUNTKILL) && (mo->health > 0))
+ {
+ P_DamageMobj(mo, NULL, NULL, 10000);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_BossDeath
+//
+// Trigger special effects if all bosses are dead.
+//
+//----------------------------------------------------------------------------
+
+void A_BossDeath(mobj_t * actor)
+{
+ mobj_t *mo;
+ thinker_t *think;
+ line_t dummyLine;
+ static mobjtype_t bossType[6] = {
+ MT_HEAD,
+ MT_MINOTAUR,
+ MT_SORCERER2,
+ MT_HEAD,
+ MT_MINOTAUR,
+ -1
+ };
+
+ if (gamemap != 8)
+ { // Not a boss level
+ return;
+ }
+ if (actor->type != bossType[gameepisode - 1])
+ { // Not considered a boss in this episode
+ return;
+ }
+ // Make sure all bosses are dead
+ for (think = thinkercap.next; think != &thinkercap; think = think->next)
+ {
+ if (think->function != P_MobjThinker)
+ { // Not a mobj thinker
+ continue;
+ }
+ mo = (mobj_t *) think;
+ if ((mo != actor) && (mo->type == actor->type) && (mo->health > 0))
+ { // Found a living boss
+ return;
+ }
+ }
+ if (gameepisode > 1)
+ { // Kill any remaining monsters
+ P_Massacre();
+ }
+ dummyLine.tag = 666;
+ EV_DoFloor(&dummyLine, lowerFloor);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_ESound
+//
+//----------------------------------------------------------------------------
+
+void A_ESound(mobj_t * mo)
+{
+ int sound = sfx_None;
+
+ switch (mo->type)
+ {
+ case MT_SOUNDWATERFALL:
+ sound = sfx_waterfl;
+ break;
+ case MT_SOUNDWIND:
+ sound = sfx_wind;
+ break;
+ default:
+ break;
+ }
+ S_StartSound(mo, sound);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_SpawnTeleGlitter
+//
+//----------------------------------------------------------------------------
+
+void A_SpawnTeleGlitter(mobj_t * actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x + ((P_Random() & 31) - 16) * FRACUNIT,
+ actor->y + ((P_Random() & 31) - 16) * FRACUNIT,
+ actor->subsector->sector->floorheight, MT_TELEGLITTER);
+ mo->momz = FRACUNIT / 4;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_SpawnTeleGlitter2
+//
+//----------------------------------------------------------------------------
+
+void A_SpawnTeleGlitter2(mobj_t * actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x + ((P_Random() & 31) - 16) * FRACUNIT,
+ actor->y + ((P_Random() & 31) - 16) * FRACUNIT,
+ actor->subsector->sector->floorheight, MT_TELEGLITTER2);
+ mo->momz = FRACUNIT / 4;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_AccTeleGlitter
+//
+//----------------------------------------------------------------------------
+
+void A_AccTeleGlitter(mobj_t * actor)
+{
+ if (++actor->health > 35)
+ {
+ actor->momz += actor->momz / 2;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_InitKeyGizmo
+//
+//----------------------------------------------------------------------------
+
+void A_InitKeyGizmo(mobj_t * gizmo)
+{
+ mobj_t *mo;
+ statenum_t state = S_NULL;
+
+ switch (gizmo->type)
+ {
+ case MT_KEYGIZMOBLUE:
+ state = S_KGZ_BLUEFLOAT1;
+ break;
+ case MT_KEYGIZMOGREEN:
+ state = S_KGZ_GREENFLOAT1;
+ break;
+ case MT_KEYGIZMOYELLOW:
+ state = S_KGZ_YELLOWFLOAT1;
+ break;
+ default:
+ break;
+ }
+ mo = P_SpawnMobj(gizmo->x, gizmo->y, gizmo->z + 60 * FRACUNIT,
+ MT_KEYGIZMOFLOAT);
+ P_SetMobjState(mo, state);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_VolcanoSet
+//
+//----------------------------------------------------------------------------
+
+void A_VolcanoSet(mobj_t * volcano)
+{
+ volcano->tics = 105 + (P_Random() & 127);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_VolcanoBlast
+//
+//----------------------------------------------------------------------------
+
+void A_VolcanoBlast(mobj_t * volcano)
+{
+ int i;
+ int count;
+ mobj_t *blast;
+ angle_t angle;
+
+ count = 1 + (P_Random() % 3);
+ for (i = 0; i < count; i++)
+ {
+ blast = P_SpawnMobj(volcano->x, volcano->y, volcano->z + 44 * FRACUNIT, MT_VOLCANOBLAST); // MT_VOLCANOBLAST
+ blast->target = volcano;
+ angle = P_Random() << 24;
+ blast->angle = angle;
+ angle >>= ANGLETOFINESHIFT;
+ blast->momx = FixedMul(1 * FRACUNIT, finecosine[angle]);
+ blast->momy = FixedMul(1 * FRACUNIT, finesine[angle]);
+ blast->momz = (fixed_t)(2.5 * FRACUNIT) + (P_Random() << 10);
+ S_StartSound(blast, sfx_volsht);
+ P_CheckMissileSpawn(blast);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_VolcBallImpact
+//
+//----------------------------------------------------------------------------
+
+void A_VolcBallImpact(mobj_t * ball)
+{
+ int i;
+ mobj_t *tiny;
+ angle_t angle;
+
+ if (ball->z <= ball->floorz)
+ {
+ ball->flags |= MF_NOGRAVITY;
+ ball->flags2 &= ~MF2_LOGRAV;
+ ball->z += 28 * FRACUNIT;
+ //ball->momz = 3*FRACUNIT;
+ }
+ P_RadiusAttack(ball, ball->target, 25);
+ for (i = 0; i < 4; i++)
+ {
+ tiny = P_SpawnMobj(ball->x, ball->y, ball->z, MT_VOLCANOTBLAST);
+ tiny->target = ball;
+ angle = i * ANG90;
+ tiny->angle = angle;
+ angle >>= ANGLETOFINESHIFT;
+ tiny->momx = FixedMul((fixed_t)(FRACUNIT * .7), finecosine[angle]);
+ tiny->momy = FixedMul((fixed_t)(FRACUNIT * .7), finesine[angle]);
+ tiny->momz = FRACUNIT + (P_Random() << 9);
+ P_CheckMissileSpawn(tiny);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_SkullPop
+//
+//----------------------------------------------------------------------------
+
+void A_SkullPop(mobj_t * actor)
+{
+ mobj_t *mo;
+ player_t *player;
+
+ actor->flags &= ~MF_SOLID;
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 48 * FRACUNIT,
+ MT_BLOODYSKULL);
+ //mo->target = actor;
+ mo->momx = (P_Random() - P_Random()) << 9;
+ mo->momy = (P_Random() - P_Random()) << 9;
+ mo->momz = FRACUNIT * 2 + (P_Random() << 6);
+ // Attach player mobj to bloody skull
+ player = actor->player;
+ actor->player = NULL;
+ mo->player = player;
+ mo->health = actor->health;
+ mo->angle = actor->angle;
+ player->mo = mo;
+ player->lookdir = 0;
+ player->damagecount = 32;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_CheckSkullFloor
+//
+//----------------------------------------------------------------------------
+
+void A_CheckSkullFloor(mobj_t * actor)
+{
+ if (actor->z <= actor->floorz)
+ {
+ P_SetMobjState(actor, S_BLOODYSKULLX1);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_CheckSkullDone
+//
+//----------------------------------------------------------------------------
+
+void A_CheckSkullDone(mobj_t * actor)
+{
+ if (actor->special2.i == 666)
+ {
+ P_SetMobjState(actor, S_BLOODYSKULLX2);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_CheckBurnGone
+//
+//----------------------------------------------------------------------------
+
+void A_CheckBurnGone(mobj_t * actor)
+{
+ if (actor->special2.i == 666)
+ {
+ P_SetMobjState(actor, S_PLAY_FDTH20);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FreeTargMobj
+//
+//----------------------------------------------------------------------------
+
+void A_FreeTargMobj(mobj_t * mo)
+{
+ mo->momx = mo->momy = mo->momz = 0;
+ mo->z = mo->ceilingz + 4 * FRACUNIT;
+ mo->flags &= ~(MF_SHOOTABLE | MF_FLOAT | MF_SKULLFLY | MF_SOLID);
+ mo->flags |= MF_CORPSE | MF_DROPOFF | MF_NOGRAVITY;
+ mo->flags2 &= ~(MF2_PASSMOBJ | MF2_LOGRAV);
+ mo->player = NULL;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_AddPlayerCorpse
+//
+//----------------------------------------------------------------------------
+
+#define BODYQUESIZE 32
+mobj_t *bodyque[BODYQUESIZE];
+int bodyqueslot;
+
+void A_AddPlayerCorpse(mobj_t * actor)
+{
+ if (bodyqueslot >= BODYQUESIZE)
+ { // Too many player corpses - remove an old one
+ P_RemoveMobj(bodyque[bodyqueslot % BODYQUESIZE]);
+ }
+ bodyque[bodyqueslot % BODYQUESIZE] = actor;
+ bodyqueslot++;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FlameSnd
+//
+//----------------------------------------------------------------------------
+
+void A_FlameSnd(mobj_t * actor)
+{
+ S_StartSound(actor, sfx_hedat1); // Burn sound
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_HideThing
+//
+//----------------------------------------------------------------------------
+
+void A_HideThing(mobj_t * actor)
+{
+ //P_UnsetThingPosition(actor);
+ actor->flags2 |= MF2_DONTDRAW;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_UnHideThing
+//
+//----------------------------------------------------------------------------
+
+void A_UnHideThing(mobj_t * actor)
+{
+ //P_SetThingPosition(actor);
+ actor->flags2 &= ~MF2_DONTDRAW;
+}
diff --git a/src/heretic/p_floor.c b/src/heretic/p_floor.c
new file mode 100644
index 00000000..24c7ffa2
--- /dev/null
+++ b/src/heretic/p_floor.c
@@ -0,0 +1,468 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+#include "doomdef.h"
+#include "p_local.h"
+#include "s_sound.h"
+#include "v_video.h"
+
+//==================================================================
+//==================================================================
+//
+// FLOORS
+//
+//==================================================================
+//==================================================================
+
+
+
+//==================================================================
+//
+// Move a plane (floor or ceiling) and check for crushing
+//
+//==================================================================
+result_e T_MovePlane(sector_t * sector, fixed_t speed,
+ fixed_t dest, boolean crush, int floorOrCeiling,
+ int direction)
+{
+ 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);
+#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(&floor->sector->soundorg, sfx_dormov);
+ }
+
+ if (res == pastdest)
+ {
+ floor->sector->specialdata = NULL;
+ if (floor->type == raiseBuildStep)
+ {
+ S_StartSound(&floor->sector->soundorg, sfx_pstop);
+ }
+ 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);
+ }
+
+}
+
+//==================================================================
+//
+// 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 = 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 = (8 * FRACUNIT) +
+ P_FindHighestFloorSurrounding(sec);
+ 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 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 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 = INT_MAX;
+ 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);
+ floor->texture = sec->floorpic;
+ floor->newspecial = sec->special;
+ break;
+ }
+ else
+ {
+ sec = getSector(secnum, i, 0);
+ floor->texture = sec->floorpic;
+ floor->newspecial = sec->special;
+ break;
+ }
+ }
+ default:
+ break;
+ }
+ }
+ return rtn;
+}
+
+//==================================================================
+//
+// BUILD A STAIRCASE!
+//
+//==================================================================
+int EV_BuildStairs(line_t * line, fixed_t stepDelta)
+{
+ int secnum;
+ int height;
+ int i;
+ int newsecnum;
+ int texture;
+ int ok;
+ int rtn;
+ sector_t *sec, *tsec;
+ 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;
+ height = sec->floorheight + stepDelta;
+ floor = Z_Malloc(sizeof(*floor), PU_LEVSPEC, 0);
+ P_AddThinker(&floor->thinker);
+ sec->specialdata = floor;
+ floor->thinker.function = T_MoveFloor;
+ floor->type = raiseBuildStep;
+ floor->direction = 1;
+ floor->sector = sec;
+ floor->speed = FLOORSPEED;
+ 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 = tsec - sectors;
+ if (secnum != newsecnum)
+ continue;
+ tsec = (sec->lines[i])->backsector;
+ newsecnum = tsec - sectors;
+ if (tsec->floorpic != texture)
+ continue;
+
+ height += stepDelta;
+ 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 = T_MoveFloor;
+ floor->type = raiseBuildStep;
+ floor->direction = 1;
+ floor->sector = sec;
+ floor->speed = FLOORSPEED;
+ floor->floordestheight = height;
+ ok = 1;
+ break;
+ }
+ }
+ while (ok);
+ }
+ return (rtn);
+}
diff --git a/src/heretic/p_inter.c b/src/heretic/p_inter.c
new file mode 100644
index 00000000..0e7b24b8
--- /dev/null
+++ b/src/heretic/p_inter.c
@@ -0,0 +1,1493 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// P_inter.c
+
+#include "doomdef.h"
+#include "deh_str.h"
+#include "i_system.h"
+#include "i_timer.h"
+#include "m_random.h"
+#include "p_local.h"
+#include "s_sound.h"
+
+#define BONUSADD 6
+
+int WeaponValue[] = {
+ 1, // staff
+ 3, // goldwand
+ 4, // crossbow
+ 5, // blaster
+ 6, // skullrod
+ 7, // phoenixrod
+ 8, // mace
+ 2, // gauntlets
+ 0 // beak
+};
+
+int maxammo[NUMAMMO] = {
+ 100, // gold wand
+ 50, // crossbow
+ 200, // blaster
+ 200, // skull rod
+ 20, // phoenix rod
+ 150 // mace
+};
+
+int GetWeaponAmmo[NUMWEAPONS] = {
+ 0, // staff
+ 25, // gold wand
+ 10, // crossbow
+ 30, // blaster
+ 50, // skull rod
+ 2, // phoenix rod
+ 50, // mace
+ 0, // gauntlets
+ 0 // beak
+};
+
+static weapontype_t GetAmmoChange[] = {
+ wp_goldwand,
+ wp_crossbow,
+ wp_blaster,
+ wp_skullrod,
+ wp_phoenixrod,
+ wp_mace
+};
+
+/*
+static boolean GetAmmoChangePL1[NUMWEAPONS][NUMAMMO] =
+{
+ // staff
+ {wp_goldwand, wp_crossbow, wp_blaster, wp_skullrod, -1, wp_mace},
+ // gold wand
+ {-1, wp_crossbow, wp_blaster, wp_skullrod, -1, wp_mace},
+ // crossbow
+ {-1, -1, wp_blaster, wp_skullrod, -1, -1},
+ // blaster
+ {-1, -1, -1, -1, -1, -1},
+ // skull rod
+ {-1, -1, -1, -1, -1, -1},
+ // phoenix rod
+ {-1, -1, -1, -1, -1, -1},
+ // mace
+ {-1, wp_crossbow, wp_blaster, wp_skullrod, -1, -1},
+ // gauntlets
+ {-1, wp_crossbow, wp_blaster, wp_skullrod, -1, wp_mace}
+};
+*/
+
+/*
+static boolean GetAmmoChangePL2[NUMWEAPONS][NUMAMMO] =
+{
+ // staff
+ {wp_goldwand, wp_crossbow, wp_blaster, wp_skullrod, wp_phoenixrod,
+ wp_mace},
+ // gold wand
+ {-1, wp_crossbow, wp_blaster, wp_skullrod, wp_phoenixrod, wp_mace},
+ // crossbow
+ {-1, -1, wp_blaster, wp_skullrod, wp_phoenixrod, -1},
+ // blaster
+ {-1, -1, -1, wp_skullrod, wp_phoenixrod, -1},
+ // skull rod
+ {-1, -1, -1, -1, -1, -1},
+ // phoenix rod
+ {-1, -1, -1, -1, -1, -1},
+ // mace
+ {-1, wp_crossbow, wp_blaster, wp_skullrod, -1, -1},
+ // gauntlets
+ {-1, -1, -1, wp_skullrod, wp_phoenixrod, wp_mace}
+};
+*/
+
+//--------------------------------------------------------------------------
+//
+// PROC P_SetMessage
+//
+//--------------------------------------------------------------------------
+
+boolean ultimatemsg;
+
+void P_SetMessage(player_t * player, char *message, boolean ultmsg)
+{
+ extern boolean messageson;
+
+ if ((ultimatemsg || !messageson) && !ultmsg)
+ {
+ return;
+ }
+ player->message = message;
+ player->messageTics = MESSAGETICS;
+ BorderTopRefresh = true;
+ if (ultmsg)
+ {
+ ultimatemsg = true;
+ }
+}
+
+//--------------------------------------------------------------------------
+//
+// FUNC P_GiveAmmo
+//
+// Returns true if the player accepted the ammo, false if it was
+// refused (player has maxammo[ammo]).
+//
+//--------------------------------------------------------------------------
+
+boolean P_GiveAmmo(player_t * player, ammotype_t ammo, int count)
+{
+ int prevAmmo;
+ //weapontype_t changeWeapon;
+
+ if (ammo == am_noammo)
+ {
+ return (false);
+ }
+ if (ammo < 0 || ammo > NUMAMMO)
+ {
+ I_Error("P_GiveAmmo: bad type %i", ammo);
+ }
+ if (player->ammo[ammo] == player->maxammo[ammo])
+ {
+ return (false);
+ }
+ if (gameskill == sk_baby || gameskill == sk_nightmare)
+ { // extra ammo in baby mode and nightmare mode
+ count += count >> 1;
+ }
+ prevAmmo = player->ammo[ammo];
+
+ player->ammo[ammo] += count;
+ if (player->ammo[ammo] > player->maxammo[ammo])
+ {
+ player->ammo[ammo] = player->maxammo[ammo];
+ }
+ if (prevAmmo)
+ {
+ // Don't attempt to change weapons if the player already had
+ // ammo of the type just given
+ return (true);
+ }
+ if (player->readyweapon == wp_staff
+ || player->readyweapon == wp_gauntlets)
+ {
+ if (player->weaponowned[GetAmmoChange[ammo]])
+ {
+ player->pendingweapon = GetAmmoChange[ammo];
+ }
+ }
+/*
+ if(player->powers[pw_weaponlevel2])
+ {
+ changeWeapon = GetAmmoChangePL2[player->readyweapon][ammo];
+ }
+ else
+ {
+ changeWeapon = GetAmmoChangePL1[player->readyweapon][ammo];
+ }
+ if(changeWeapon != -1)
+ {
+ if(player->weaponowned[changeWeapon])
+ {
+ player->pendingweapon = changeWeapon;
+ }
+ }
+*/
+ return (true);
+}
+
+//--------------------------------------------------------------------------
+//
+// FUNC P_GiveWeapon
+//
+// Returns true if the weapon or its ammo was accepted.
+//
+//--------------------------------------------------------------------------
+
+boolean P_GiveWeapon(player_t * player, weapontype_t weapon)
+{
+ boolean gaveAmmo;
+ boolean gaveWeapon;
+
+ if (netgame && !deathmatch)
+ { // Cooperative net-game
+ if (player->weaponowned[weapon])
+ {
+ return (false);
+ }
+ player->bonuscount += BONUSADD;
+ player->weaponowned[weapon] = true;
+ P_GiveAmmo(player, wpnlev1info[weapon].ammo, GetWeaponAmmo[weapon]);
+ player->pendingweapon = weapon;
+ if (player == &players[consoleplayer])
+ {
+ S_StartSound(NULL, sfx_wpnup);
+ }
+ return (false);
+ }
+ gaveAmmo = P_GiveAmmo(player, wpnlev1info[weapon].ammo,
+ GetWeaponAmmo[weapon]);
+ if (player->weaponowned[weapon])
+ {
+ gaveWeapon = false;
+ }
+ else
+ {
+ gaveWeapon = true;
+ player->weaponowned[weapon] = true;
+ if (WeaponValue[weapon] > WeaponValue[player->readyweapon])
+ { // Only switch to more powerful weapons
+ player->pendingweapon = weapon;
+ }
+ }
+ return (gaveWeapon || gaveAmmo);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_GiveBody
+//
+// Returns false if the body isn't needed at all.
+//
+//---------------------------------------------------------------------------
+
+boolean P_GiveBody(player_t * player, int num)
+{
+ int max;
+
+ max = MAXHEALTH;
+ if (player->chickenTics)
+ {
+ max = MAXCHICKENHEALTH;
+ }
+ if (player->health >= max)
+ {
+ return (false);
+ }
+ player->health += num;
+ if (player->health > max)
+ {
+ player->health = max;
+ }
+ player->mo->health = player->health;
+ return (true);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_GiveArmor
+//
+// Returns false if the armor is worse than the current armor.
+//
+//---------------------------------------------------------------------------
+
+boolean P_GiveArmor(player_t * player, int armortype)
+{
+ int hits;
+
+ hits = armortype * 100;
+ if (player->armorpoints >= hits)
+ {
+ return (false);
+ }
+ player->armortype = armortype;
+ player->armorpoints = hits;
+ return (true);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_GiveKey
+//
+//---------------------------------------------------------------------------
+
+void P_GiveKey(player_t * player, keytype_t key)
+{
+ extern int playerkeys;
+ extern vertex_t KeyPoints[];
+
+ if (player->keys[key])
+ {
+ return;
+ }
+ if (player == &players[consoleplayer])
+ {
+ playerkeys |= 1 << key;
+ KeyPoints[key].x = 0;
+ KeyPoints[key].y = 0;
+ }
+ player->bonuscount = BONUSADD;
+ player->keys[key] = true;
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_GivePower
+//
+// Returns true if power accepted.
+//
+//---------------------------------------------------------------------------
+
+boolean P_GivePower(player_t * player, powertype_t power)
+{
+ if (power == pw_invulnerability)
+ {
+ if (player->powers[power] > BLINKTHRESHOLD)
+ { // Already have it
+ return (false);
+ }
+ player->powers[power] = INVULNTICS;
+ return (true);
+ }
+ if (power == pw_weaponlevel2)
+ {
+ if (player->powers[power] > BLINKTHRESHOLD)
+ { // Already have it
+ return (false);
+ }
+ player->powers[power] = WPNLEV2TICS;
+ return (true);
+ }
+ if (power == pw_invisibility)
+ {
+ if (player->powers[power] > BLINKTHRESHOLD)
+ { // Already have it
+ return (false);
+ }
+ player->powers[power] = INVISTICS;
+ player->mo->flags |= MF_SHADOW;
+ return (true);
+ }
+ if (power == pw_flight)
+ {
+ if (player->powers[power] > BLINKTHRESHOLD)
+ { // Already have it
+ return (false);
+ }
+ player->powers[power] = FLIGHTTICS;
+ player->mo->flags2 |= MF2_FLY;
+ player->mo->flags |= MF_NOGRAVITY;
+ if (player->mo->z <= player->mo->floorz)
+ {
+ player->flyheight = 10; // thrust the player in the air a bit
+ }
+ return (true);
+ }
+ if (power == pw_infrared)
+ {
+ if (player->powers[power] > BLINKTHRESHOLD)
+ { // Already have it
+ return (false);
+ }
+ 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);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_GiveArtifact
+//
+// Returns true if artifact accepted.
+//
+//---------------------------------------------------------------------------
+
+boolean P_GiveArtifact(player_t * player, artitype_t arti, mobj_t * mo)
+{
+ int i;
+
+ i = 0;
+ while (player->inventory[i].type != arti && i < player->inventorySlotNum)
+ {
+ i++;
+ }
+ if (i == player->inventorySlotNum)
+ {
+ player->inventory[i].count = 1;
+ player->inventory[i].type = arti;
+ player->inventorySlotNum++;
+ }
+ else
+ {
+ if (player->inventory[i].count >= 16)
+ { // Player already has 16 of this item
+ return (false);
+ }
+ player->inventory[i].count++;
+ }
+ if (player->artifactCount == 0)
+ {
+ player->readyArtifact = arti;
+ }
+ player->artifactCount++;
+ if (mo && (mo->flags & MF_COUNTITEM))
+ {
+ player->itemcount++;
+ }
+ return (true);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_SetDormantArtifact
+//
+// Removes the MF_SPECIAL flag, and initiates the artifact pickup
+// animation.
+//
+//---------------------------------------------------------------------------
+
+void P_SetDormantArtifact(mobj_t * arti)
+{
+ arti->flags &= ~MF_SPECIAL;
+ if (deathmatch && (arti->type != MT_ARTIINVULNERABILITY)
+ && (arti->type != MT_ARTIINVISIBILITY))
+ {
+ P_SetMobjState(arti, S_DORMANTARTI1);
+ }
+ else
+ { // Don't respawn
+ P_SetMobjState(arti, S_DEADARTI1);
+ }
+ S_StartSound(arti, sfx_artiup);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_RestoreArtifact
+//
+//---------------------------------------------------------------------------
+
+void A_RestoreArtifact(mobj_t * arti)
+{
+ arti->flags |= MF_SPECIAL;
+ P_SetMobjState(arti, arti->info->spawnstate);
+ S_StartSound(arti, sfx_respawn);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_HideSpecialThing
+//
+//----------------------------------------------------------------------------
+
+void P_HideSpecialThing(mobj_t * thing)
+{
+ thing->flags &= ~MF_SPECIAL;
+ thing->flags2 |= MF2_DONTDRAW;
+ P_SetMobjState(thing, S_HIDESPECIAL1);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_RestoreSpecialThing1
+//
+// Make a special thing visible again.
+//
+//---------------------------------------------------------------------------
+
+void A_RestoreSpecialThing1(mobj_t * thing)
+{
+ if (thing->type == MT_WMACE)
+ { // Do random mace placement
+ P_RepositionMace(thing);
+ }
+ thing->flags2 &= ~MF2_DONTDRAW;
+ S_StartSound(thing, sfx_respawn);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_RestoreSpecialThing2
+//
+//---------------------------------------------------------------------------
+
+void A_RestoreSpecialThing2(mobj_t * thing)
+{
+ thing->flags |= MF_SPECIAL;
+ P_SetMobjState(thing, thing->info->spawnstate);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_TouchSpecialThing
+//
+//---------------------------------------------------------------------------
+
+void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher)
+{
+ int i;
+ player_t *player;
+ fixed_t delta;
+ int sound;
+ boolean respawn;
+
+ delta = special->z - toucher->z;
+ if (delta > toucher->height || delta < -32 * FRACUNIT)
+ { // Out of reach
+ return;
+ }
+ if (toucher->health <= 0)
+ { // Toucher is dead
+ return;
+ }
+ sound = sfx_itemup;
+ player = toucher->player;
+ respawn = true;
+ switch (special->sprite)
+ {
+ // Items
+ case SPR_PTN1: // Item_HealingPotion
+ if (!P_GiveBody(player, 10))
+ {
+ return;
+ }
+ P_SetMessage(player, DEH_String(TXT_ITEMHEALTH), false);
+ break;
+ case SPR_SHLD: // Item_Shield1
+ if (!P_GiveArmor(player, 1))
+ {
+ return;
+ }
+ P_SetMessage(player, DEH_String(TXT_ITEMSHIELD1), false);
+ break;
+ case SPR_SHD2: // Item_Shield2
+ if (!P_GiveArmor(player, 2))
+ {
+ return;
+ }
+ P_SetMessage(player, DEH_String(TXT_ITEMSHIELD2), false);
+ break;
+ case SPR_BAGH: // Item_BagOfHolding
+ if (!player->backpack)
+ {
+ for (i = 0; i < NUMAMMO; i++)
+ {
+ player->maxammo[i] *= 2;
+ }
+ player->backpack = true;
+ }
+ P_GiveAmmo(player, am_goldwand, AMMO_GWND_WIMPY);
+ P_GiveAmmo(player, am_blaster, AMMO_BLSR_WIMPY);
+ P_GiveAmmo(player, am_crossbow, AMMO_CBOW_WIMPY);
+ P_GiveAmmo(player, am_skullrod, AMMO_SKRD_WIMPY);
+ P_GiveAmmo(player, am_phoenixrod, AMMO_PHRD_WIMPY);
+ P_SetMessage(player, DEH_String(TXT_ITEMBAGOFHOLDING), false);
+ break;
+ case SPR_SPMP: // Item_SuperMap
+ if (!P_GivePower(player, pw_allmap))
+ {
+ return;
+ }
+ P_SetMessage(player, DEH_String(TXT_ITEMSUPERMAP), false);
+ break;
+
+ // Keys
+ case SPR_BKYY: // Key_Blue
+ if (!player->keys[key_blue])
+ {
+ P_SetMessage(player, DEH_String(TXT_GOTBLUEKEY), false);
+ }
+ P_GiveKey(player, key_blue);
+ sound = sfx_keyup;
+ if (!netgame)
+ {
+ break;
+ }
+ return;
+ case SPR_CKYY: // Key_Yellow
+ if (!player->keys[key_yellow])
+ {
+ P_SetMessage(player, DEH_String(TXT_GOTYELLOWKEY), false);
+ }
+ sound = sfx_keyup;
+ P_GiveKey(player, key_yellow);
+ if (!netgame)
+ {
+ break;
+ }
+ return;
+ case SPR_AKYY: // Key_Green
+ if (!player->keys[key_green])
+ {
+ P_SetMessage(player, DEH_String(TXT_GOTGREENKEY), false);
+ }
+ sound = sfx_keyup;
+ P_GiveKey(player, key_green);
+ if (!netgame)
+ {
+ break;
+ }
+ return;
+
+ // Artifacts
+ case SPR_PTN2: // Arti_HealingPotion
+ if (P_GiveArtifact(player, arti_health, special))
+ {
+ P_SetMessage(player, DEH_String(TXT_ARTIHEALTH), false);
+ P_SetDormantArtifact(special);
+ }
+ return;
+ case SPR_SOAR: // Arti_Fly
+ if (P_GiveArtifact(player, arti_fly, special))
+ {
+ P_SetMessage(player, DEH_String(TXT_ARTIFLY), false);
+ P_SetDormantArtifact(special);
+ }
+ return;
+ case SPR_INVU: // Arti_Invulnerability
+ if (P_GiveArtifact(player, arti_invulnerability, special))
+ {
+ P_SetMessage(player, DEH_String(TXT_ARTIINVULNERABILITY), false);
+ P_SetDormantArtifact(special);
+ }
+ return;
+ case SPR_PWBK: // Arti_TomeOfPower
+ if (P_GiveArtifact(player, arti_tomeofpower, special))
+ {
+ P_SetMessage(player, DEH_String(TXT_ARTITOMEOFPOWER), false);
+ P_SetDormantArtifact(special);
+ }
+ return;
+ case SPR_INVS: // Arti_Invisibility
+ if (P_GiveArtifact(player, arti_invisibility, special))
+ {
+ P_SetMessage(player, DEH_String(TXT_ARTIINVISIBILITY), false);
+ P_SetDormantArtifact(special);
+ }
+ return;
+ case SPR_EGGC: // Arti_Egg
+ if (P_GiveArtifact(player, arti_egg, special))
+ {
+ P_SetMessage(player, DEH_String(TXT_ARTIEGG), false);
+ P_SetDormantArtifact(special);
+ }
+ return;
+ case SPR_SPHL: // Arti_SuperHealth
+ if (P_GiveArtifact(player, arti_superhealth, special))
+ {
+ P_SetMessage(player, DEH_String(TXT_ARTISUPERHEALTH), false);
+ P_SetDormantArtifact(special);
+ }
+ return;
+ case SPR_TRCH: // Arti_Torch
+ if (P_GiveArtifact(player, arti_torch, special))
+ {
+ P_SetMessage(player, DEH_String(TXT_ARTITORCH), false);
+ P_SetDormantArtifact(special);
+ }
+ return;
+ case SPR_FBMB: // Arti_FireBomb
+ if (P_GiveArtifact(player, arti_firebomb, special))
+ {
+ P_SetMessage(player, DEH_String(TXT_ARTIFIREBOMB), false);
+ P_SetDormantArtifact(special);
+ }
+ return;
+ case SPR_ATLP: // Arti_Teleport
+ if (P_GiveArtifact(player, arti_teleport, special))
+ {
+ P_SetMessage(player, DEH_String(TXT_ARTITELEPORT), false);
+ P_SetDormantArtifact(special);
+ }
+ return;
+
+ // Ammo
+ case SPR_AMG1: // Ammo_GoldWandWimpy
+ if (!P_GiveAmmo(player, am_goldwand, special->health))
+ {
+ return;
+ }
+ P_SetMessage(player, DEH_String(TXT_AMMOGOLDWAND1), false);
+ break;
+ case SPR_AMG2: // Ammo_GoldWandHefty
+ if (!P_GiveAmmo(player, am_goldwand, special->health))
+ {
+ return;
+ }
+ P_SetMessage(player, DEH_String(TXT_AMMOGOLDWAND2), false);
+ break;
+ case SPR_AMM1: // Ammo_MaceWimpy
+ if (!P_GiveAmmo(player, am_mace, special->health))
+ {
+ return;
+ }
+ P_SetMessage(player, DEH_String(TXT_AMMOMACE1), false);
+ break;
+ case SPR_AMM2: // Ammo_MaceHefty
+ if (!P_GiveAmmo(player, am_mace, special->health))
+ {
+ return;
+ }
+ P_SetMessage(player, DEH_String(TXT_AMMOMACE2), false);
+ break;
+ case SPR_AMC1: // Ammo_CrossbowWimpy
+ if (!P_GiveAmmo(player, am_crossbow, special->health))
+ {
+ return;
+ }
+ P_SetMessage(player, DEH_String(TXT_AMMOCROSSBOW1), false);
+ break;
+ case SPR_AMC2: // Ammo_CrossbowHefty
+ if (!P_GiveAmmo(player, am_crossbow, special->health))
+ {
+ return;
+ }
+ P_SetMessage(player, DEH_String(TXT_AMMOCROSSBOW2), false);
+ break;
+ case SPR_AMB1: // Ammo_BlasterWimpy
+ if (!P_GiveAmmo(player, am_blaster, special->health))
+ {
+ return;
+ }
+ P_SetMessage(player, DEH_String(TXT_AMMOBLASTER1), false);
+ break;
+ case SPR_AMB2: // Ammo_BlasterHefty
+ if (!P_GiveAmmo(player, am_blaster, special->health))
+ {
+ return;
+ }
+ P_SetMessage(player, DEH_String(TXT_AMMOBLASTER2), false);
+ break;
+ case SPR_AMS1: // Ammo_SkullRodWimpy
+ if (!P_GiveAmmo(player, am_skullrod, special->health))
+ {
+ return;
+ }
+ P_SetMessage(player, DEH_String(TXT_AMMOSKULLROD1), false);
+ break;
+ case SPR_AMS2: // Ammo_SkullRodHefty
+ if (!P_GiveAmmo(player, am_skullrod, special->health))
+ {
+ return;
+ }
+ P_SetMessage(player, DEH_String(TXT_AMMOSKULLROD2), false);
+ break;
+ case SPR_AMP1: // Ammo_PhoenixRodWimpy
+ if (!P_GiveAmmo(player, am_phoenixrod, special->health))
+ {
+ return;
+ }
+ P_SetMessage(player, DEH_String(TXT_AMMOPHOENIXROD1), false);
+ break;
+ case SPR_AMP2: // Ammo_PhoenixRodHefty
+ if (!P_GiveAmmo(player, am_phoenixrod, special->health))
+ {
+ return;
+ }
+ P_SetMessage(player, DEH_String(TXT_AMMOPHOENIXROD2), false);
+ break;
+
+ // Weapons
+ case SPR_WMCE: // Weapon_Mace
+ if (!P_GiveWeapon(player, wp_mace))
+ {
+ return;
+ }
+ P_SetMessage(player, DEH_String(TXT_WPNMACE), false);
+ sound = sfx_wpnup;
+ break;
+ case SPR_WBOW: // Weapon_Crossbow
+ if (!P_GiveWeapon(player, wp_crossbow))
+ {
+ return;
+ }
+ P_SetMessage(player, DEH_String(TXT_WPNCROSSBOW), false);
+ sound = sfx_wpnup;
+ break;
+ case SPR_WBLS: // Weapon_Blaster
+ if (!P_GiveWeapon(player, wp_blaster))
+ {
+ return;
+ }
+ P_SetMessage(player, DEH_String(TXT_WPNBLASTER), false);
+ sound = sfx_wpnup;
+ break;
+ case SPR_WSKL: // Weapon_SkullRod
+ if (!P_GiveWeapon(player, wp_skullrod))
+ {
+ return;
+ }
+ P_SetMessage(player, DEH_String(TXT_WPNSKULLROD), false);
+ sound = sfx_wpnup;
+ break;
+ case SPR_WPHX: // Weapon_PhoenixRod
+ if (!P_GiveWeapon(player, wp_phoenixrod))
+ {
+ return;
+ }
+ P_SetMessage(player, DEH_String(TXT_WPNPHOENIXROD), false);
+ sound = sfx_wpnup;
+ break;
+ case SPR_WGNT: // Weapon_Gauntlets
+ if (!P_GiveWeapon(player, wp_gauntlets))
+ {
+ return;
+ }
+ P_SetMessage(player, DEH_String(TXT_WPNGAUNTLETS), false);
+ sound = sfx_wpnup;
+ break;
+ default:
+ I_Error("P_SpecialThing: Unknown gettable thing");
+ }
+ if (special->flags & MF_COUNTITEM)
+ {
+ player->itemcount++;
+ }
+ if (deathmatch && respawn && !(special->flags & MF_DROPPED))
+ {
+ P_HideSpecialThing(special);
+ }
+ else
+ {
+ P_RemoveMobj(special);
+ }
+ player->bonuscount += BONUSADD;
+ if (player == &players[consoleplayer])
+ {
+ S_StartSound(NULL, sound);
+ SB_PaletteFlash();
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_KillMobj
+//
+//---------------------------------------------------------------------------
+
+void P_KillMobj(mobj_t * source, mobj_t * target)
+{
+ target->flags &= ~(MF_SHOOTABLE | MF_FLOAT | MF_SKULLFLY | MF_NOGRAVITY);
+ target->flags |= MF_CORPSE | MF_DROPOFF;
+ target->flags2 &= ~MF2_PASSMOBJ;
+ target->height >>= 2;
+ if (source && source->player)
+ {
+ if (target->flags & MF_COUNTKILL)
+ { // Count for intermission
+ source->player->killcount++;
+ }
+ if (target->player)
+ { // Frag stuff
+ if (target == source)
+ { // Self-frag
+ target->player->frags[target->player - players]--;
+ }
+ else
+ {
+ source->player->frags[target->player - players]++;
+ if (source->player == &players[consoleplayer])
+ {
+ S_StartSound(NULL, sfx_gfrag);
+ }
+ if (source->player->chickenTics)
+ { // Make a super chicken
+ P_GivePower(source->player, pw_weaponlevel2);
+ }
+ }
+ }
+ }
+ else if (!netgame && (target->flags & MF_COUNTKILL))
+ { // Count all monster deaths
+ players[0].killcount++;
+ }
+ if (target->player)
+ {
+ if (!source)
+ { // Self-frag
+ target->player->frags[target->player - players]--;
+ }
+ target->flags &= ~MF_SOLID;
+ target->flags2 &= ~MF2_FLY;
+ target->player->powers[pw_flight] = 0;
+ target->player->powers[pw_weaponlevel2] = 0;
+ target->player->playerstate = PST_DEAD;
+ P_DropWeapon(target->player);
+ if (target->flags2 & MF2_FIREDAMAGE)
+ { // Player flame death
+ P_SetMobjState(target, S_PLAY_FDTH1);
+ //S_StartSound(target, sfx_hedat1); // Burn sound
+ return;
+ }
+ }
+ if (target->health < -(target->info->spawnhealth >> 1)
+ && target->info->xdeathstate)
+ { // Extreme death
+ P_SetMobjState(target, target->info->xdeathstate);
+ }
+ else
+ { // Normal death
+ P_SetMobjState(target, target->info->deathstate);
+ }
+ target->tics -= P_Random() & 3;
+// I_StartSound(&actor->r, actor->info->deathsound);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_MinotaurSlam
+//
+//---------------------------------------------------------------------------
+
+void P_MinotaurSlam(mobj_t * source, mobj_t * target)
+{
+ angle_t angle;
+ fixed_t thrust;
+
+ angle = R_PointToAngle2(source->x, source->y, target->x, target->y);
+ angle >>= ANGLETOFINESHIFT;
+ thrust = 16 * FRACUNIT + (P_Random() << 10);
+ target->momx += FixedMul(thrust, finecosine[angle]);
+ target->momy += FixedMul(thrust, finesine[angle]);
+ P_DamageMobj(target, NULL, NULL, HITDICE(6));
+ if (target->player)
+ {
+ target->reactiontime = 14 + (P_Random() & 7);
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_TouchWhirlwind
+//
+//---------------------------------------------------------------------------
+
+void P_TouchWhirlwind(mobj_t * target)
+{
+ int randVal;
+
+ target->angle += (P_Random() - P_Random()) << 20;
+ target->momx += (P_Random() - P_Random()) << 10;
+ target->momy += (P_Random() - P_Random()) << 10;
+ if (leveltime & 16 && !(target->flags2 & MF2_BOSS))
+ {
+ randVal = P_Random();
+ if (randVal > 160)
+ {
+ randVal = 160;
+ }
+ target->momz += randVal << 10;
+ if (target->momz > 12 * FRACUNIT)
+ {
+ target->momz = 12 * FRACUNIT;
+ }
+ }
+ if (!(leveltime & 7))
+ {
+ P_DamageMobj(target, NULL, NULL, 3);
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_ChickenMorphPlayer
+//
+// Returns true if the player gets turned into a chicken.
+//
+//---------------------------------------------------------------------------
+
+boolean P_ChickenMorphPlayer(player_t * player)
+{
+ mobj_t *pmo;
+ mobj_t *fog;
+ mobj_t *chicken;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ angle_t angle;
+ int oldFlags2;
+
+ if (player->chickenTics)
+ {
+ if ((player->chickenTics < CHICKENTICS - TICRATE)
+ && !player->powers[pw_weaponlevel2])
+ { // Make a super chicken
+ P_GivePower(player, pw_weaponlevel2);
+ }
+ return (false);
+ }
+ if (player->powers[pw_invulnerability])
+ { // Immune when invulnerable
+ return (false);
+ }
+ pmo = player->mo;
+ x = pmo->x;
+ y = pmo->y;
+ z = pmo->z;
+ angle = pmo->angle;
+ oldFlags2 = pmo->flags2;
+ P_SetMobjState(pmo, S_FREETARGMOBJ);
+ fog = P_SpawnMobj(x, y, z + TELEFOGHEIGHT, MT_TFOG);
+ S_StartSound(fog, sfx_telept);
+ chicken = P_SpawnMobj(x, y, z, MT_CHICPLAYER);
+ chicken->special1.i = player->readyweapon;
+ chicken->angle = angle;
+ chicken->player = player;
+ player->health = chicken->health = MAXCHICKENHEALTH;
+ player->mo = chicken;
+ player->armorpoints = player->armortype = 0;
+ player->powers[pw_invisibility] = 0;
+ player->powers[pw_weaponlevel2] = 0;
+ if (oldFlags2 & MF2_FLY)
+ {
+ chicken->flags2 |= MF2_FLY;
+ }
+ player->chickenTics = CHICKENTICS;
+ P_ActivateBeak(player);
+ return (true);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_ChickenMorph
+//
+//---------------------------------------------------------------------------
+
+boolean P_ChickenMorph(mobj_t * actor)
+{
+ mobj_t *fog;
+ mobj_t *chicken;
+ mobj_t *target;
+ mobjtype_t moType;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ angle_t angle;
+ int ghost;
+
+ if (actor->player)
+ {
+ return (false);
+ }
+ moType = actor->type;
+ switch (moType)
+ {
+ case MT_POD:
+ case MT_CHICKEN:
+ case MT_HEAD:
+ case MT_MINOTAUR:
+ case MT_SORCERER1:
+ case MT_SORCERER2:
+ return (false);
+ default:
+ break;
+ }
+ x = actor->x;
+ y = actor->y;
+ z = actor->z;
+ angle = actor->angle;
+ ghost = actor->flags & MF_SHADOW;
+ target = actor->target;
+ P_SetMobjState(actor, S_FREETARGMOBJ);
+ fog = P_SpawnMobj(x, y, z + TELEFOGHEIGHT, MT_TFOG);
+ S_StartSound(fog, sfx_telept);
+ chicken = P_SpawnMobj(x, y, z, MT_CHICKEN);
+ chicken->special2.i = moType;
+ chicken->special1.i = CHICKENTICS + P_Random();
+ chicken->flags |= ghost;
+ chicken->target = target;
+ chicken->angle = angle;
+ return (true);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_AutoUseChaosDevice
+//
+//---------------------------------------------------------------------------
+
+boolean P_AutoUseChaosDevice(player_t * player)
+{
+ int i;
+
+ for (i = 0; i < player->inventorySlotNum; i++)
+ {
+ if (player->inventory[i].type == arti_teleport)
+ {
+ P_PlayerUseArtifact(player, arti_teleport);
+ player->health = player->mo->health = (player->health + 1) / 2;
+ return (true);
+ }
+ }
+ return (false);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_AutoUseHealth
+//
+//---------------------------------------------------------------------------
+
+void P_AutoUseHealth(player_t * player, int saveHealth)
+{
+ int i;
+ int count;
+ int normalCount;
+ int normalSlot;
+ int superCount;
+ int superSlot;
+
+ normalCount = 0;
+ superCount = 0;
+ normalSlot = 0;
+ superSlot = 0;
+
+ for (i = 0; i < player->inventorySlotNum; i++)
+ {
+ if (player->inventory[i].type == arti_health)
+ {
+ normalSlot = i;
+ normalCount = player->inventory[i].count;
+ }
+ else if (player->inventory[i].type == arti_superhealth)
+ {
+ superSlot = i;
+ superCount = player->inventory[i].count;
+ }
+ }
+ if ((gameskill == sk_baby) && (normalCount * 25 >= saveHealth))
+ { // Use quartz flasks
+ count = (saveHealth + 24) / 25;
+ for (i = 0; i < count; i++)
+ {
+ player->health += 25;
+ P_PlayerRemoveArtifact(player, normalSlot);
+ }
+ }
+ else if (superCount * 100 >= saveHealth)
+ { // Use mystic urns
+ count = (saveHealth + 99) / 100;
+ for (i = 0; i < count; i++)
+ {
+ player->health += 100;
+ P_PlayerRemoveArtifact(player, superSlot);
+ }
+ }
+ else if ((gameskill == sk_baby)
+ && (superCount * 100 + normalCount * 25 >= saveHealth))
+ { // Use mystic urns and quartz flasks
+ count = (saveHealth + 24) / 25;
+ saveHealth -= count * 25;
+ for (i = 0; i < count; i++)
+ {
+ player->health += 25;
+ P_PlayerRemoveArtifact(player, normalSlot);
+ }
+ count = (saveHealth + 99) / 100;
+ for (i = 0; i < count; i++)
+ {
+ player->health += 100;
+ P_PlayerRemoveArtifact(player, normalSlot);
+ }
+ }
+ player->mo->health = player->health;
+}
+
+/*
+=================
+=
+= P_DamageMobj
+=
+= Damages both enemies and players
+= inflictor is the thing that caused the damage
+= creature or missile, can be NULL (slime, etc)
+= source is the thing to target after taking damage
+= creature or NULL
+= Source and inflictor are the same for melee attacks
+= source can be null for 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))
+ {
+ // Shouldn't happen
+ return;
+ }
+ if (target->health <= 0)
+ {
+ return;
+ }
+ if (target->flags & MF_SKULLFLY)
+ {
+ if (target->type == MT_MINOTAUR)
+ { // Minotaur is invulnerable during charge attack
+ return;
+ }
+ target->momx = target->momy = target->momz = 0;
+ }
+ player = target->player;
+ if (player && gameskill == sk_baby)
+ {
+ // Take half damage in trainer mode
+ damage >>= 1;
+ }
+ // Special damage types
+ if (inflictor)
+ {
+ switch (inflictor->type)
+ {
+ case MT_EGGFX:
+ if (player)
+ {
+ P_ChickenMorphPlayer(player);
+ }
+ else
+ {
+ P_ChickenMorph(target);
+ }
+ return; // Always return
+ case MT_WHIRLWIND:
+ P_TouchWhirlwind(target);
+ return;
+ case MT_MINOTAUR:
+ if (inflictor->flags & MF_SKULLFLY)
+ { // Slam only when in charge mode
+ P_MinotaurSlam(inflictor, target);
+ return;
+ }
+ break;
+ case MT_MACEFX4: // Death ball
+ if ((target->flags2 & MF2_BOSS) || target->type == MT_HEAD)
+ { // Don't allow cheap boss kills
+ break;
+ }
+ else if (target->player)
+ { // Player specific checks
+ if (target->player->powers[pw_invulnerability])
+ { // Can't hurt invulnerable players
+ break;
+ }
+ if (P_AutoUseChaosDevice(target->player))
+ { // Player was saved using chaos device
+ return;
+ }
+ }
+ damage = 10000; // Something's gonna die
+ break;
+ case MT_PHOENIXFX2: // Flame thrower
+ if (target->player && P_Random() < 128)
+ { // Freeze player for a bit
+ target->reactiontime += 4;
+ }
+ break;
+ case MT_RAINPLR1: // Rain missiles
+ case MT_RAINPLR2:
+ case MT_RAINPLR3:
+ case MT_RAINPLR4:
+ if (target->flags2 & MF2_BOSS)
+ { // Decrease damage for bosses
+ damage = (P_Random() & 7) + 1;
+ }
+ break;
+ case MT_HORNRODFX2:
+ case MT_PHOENIXFX1:
+ if (target->type == MT_SORCERER2 && P_Random() < 96)
+ { // D'Sparil teleports away
+ P_DSparilTeleport(target);
+ return;
+ }
+ break;
+ case MT_BLASTERFX1:
+ case MT_RIPPER:
+ if (target->type == MT_HEAD)
+ { // Less damage to Ironlich bosses
+ damage = P_Random() & 1;
+ if (!damage)
+ {
+ return;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ // Push the target unless source is using the gauntlets
+ if (inflictor && (!source || !source->player
+ || source->player->readyweapon != wp_gauntlets)
+ && !(inflictor->flags2 & MF2_NODMGTHRUST))
+ {
+ ang = R_PointToAngle2(inflictor->x, inflictor->y,
+ target->x, target->y);
+ //thrust = damage*(FRACUNIT>>3)*100/target->info->mass;
+ thrust = damage * (FRACUNIT >> 3) * 150 / 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;
+ if (source && source->player && (source == inflictor)
+ && source->player->powers[pw_weaponlevel2]
+ && source->player->readyweapon == wp_staff)
+ {
+ // Staff power level 2
+ target->momx += FixedMul(10 * FRACUNIT, finecosine[ang]);
+ target->momy += FixedMul(10 * FRACUNIT, finesine[ang]);
+ if (!(target->flags & MF_NOGRAVITY))
+ {
+ target->momz += 5 * FRACUNIT;
+ }
+ }
+ else
+ {
+ 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;
+ //}
+
+ if (damage < 1000 && ((player->cheats & CF_GODMODE)
+ || player->powers[pw_invulnerability]))
+ {
+ return;
+ }
+ if (player->armortype)
+ {
+ if (player->armortype == 1)
+ {
+ saved = damage >> 1;
+ }
+ else
+ {
+ saved = (damage >> 1) + (damage >> 2);
+ }
+ if (player->armorpoints <= saved)
+ {
+ // armor is used up
+ saved = player->armorpoints;
+ player->armortype = 0;
+ }
+ player->armorpoints -= saved;
+ damage -= saved;
+ }
+ if (damage >= player->health
+ && ((gameskill == sk_baby) || deathmatch) && !player->chickenTics)
+ { // Try to use some inventory health
+ P_AutoUseHealth(player, damage - player->health + 1);
+ }
+ 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);
+ SB_PaletteFlash();
+ }
+ }
+
+ //
+ // do the damage
+ //
+ target->health -= damage;
+ if (target->health <= 0)
+ { // Death
+ target->special1.i = damage;
+ if (target->type == MT_POD && source && source->type != MT_POD)
+ { // Make sure players get frags for chain-reaction kills
+ target->target = source;
+ }
+ if (player && inflictor && !player->chickenTics)
+ { // Check for flame death
+ if ((inflictor->flags2 & MF2_FIREDAMAGE)
+ || ((inflictor->type == MT_PHOENIXFX1)
+ && (target->health > -50) && (damage > 25)))
+ {
+ target->flags2 |= MF2_FIREDAMAGE;
+ }
+ }
+ 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 && source && !(source->flags2 & MF2_BOSS)
+ && !(target->type == MT_SORCERER2 && source->type == MT_WIZARD))
+ {
+ // Target actor is not intent on another actor,
+ // so make him chase after source
+ target->target = source;
+ target->threshold = BASETHRESHOLD;
+ if (target->state == &states[target->info->spawnstate]
+ && target->info->seestate != S_NULL)
+ {
+ P_SetMobjState(target, target->info->seestate);
+ }
+ }
+}
diff --git a/src/heretic/p_lights.c b/src/heretic/p_lights.c
new file mode 100644
index 00000000..5d97a55e
--- /dev/null
+++ b/src/heretic/p_lights.c
@@ -0,0 +1,282 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+#include "doomdef.h"
+#include "m_random.h"
+#include "p_local.h"
+#include "v_video.h"
+
+//==================================================================
+//==================================================================
+//
+// BROKEN LIGHT FLASHING
+//
+//==================================================================
+//==================================================================
+
+//==================================================================
+//
+// T_LightFlash
+//
+// After the map has been loaded, scan each sector for specials
+// that spawn thinkers
+//
+//==================================================================
+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;
+
+ sector->special = 0; // nothing special about it during gameplay
+
+ flash = Z_Malloc(sizeof(*flash), PU_LEVSPEC, 0);
+ P_AddThinker(&flash->thinker);
+ flash->thinker.function = 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
+//
+// After the map has been loaded, scan each sector for specials that spawn thinkers
+//
+//==================================================================
+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_SpawnLightFlash
+//
+// 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 = T_StrobeFlash;
+ flash->maxlight = sector->lightlevel;
+ flash->minlight = P_FindMinSurroundingLight(sector, sector->lightlevel);
+
+ if (flash->minlight == flash->maxlight)
+ flash->minlight = 0;
+ sector->special = 0; // nothing special about it during gameplay
+
+ 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 = T_Glow;
+ g->direction = -1;
+
+ sector->special = 0;
+}
diff --git a/src/heretic/p_local.h b/src/heretic/p_local.h
new file mode 100644
index 00000000..4fb58236
--- /dev/null
+++ b/src/heretic/p_local.h
@@ -0,0 +1,287 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// P_local.h
+
+#ifndef __P_LOCAL__
+#define __P_LOCAL__
+
+#ifndef __R_LOCAL__
+#include "r_local.h"
+#endif
+
+#define STARTREDPALS 1
+#define STARTBONUSPALS 9
+#define NUMREDPALS 8
+#define NUMBONUSPALS 4
+
+#define FOOTCLIPSIZE 10*FRACUNIT
+
+#define TOCENTER -8
+#define FLOATSPEED (FRACUNIT*4)
+
+#define MAXHEALTH 100
+#define MAXCHICKENHEALTH 30
+#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 don't 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)
+
+typedef enum
+{
+ DI_EAST,
+ DI_NORTHEAST,
+ DI_NORTH,
+ DI_NORTHWEST,
+ DI_WEST,
+ DI_SOUTHWEST,
+ DI_SOUTH,
+ DI_SOUTHEAST,
+ DI_NODIR,
+ NUMDIRS
+} dirtype_t;
+
+#define BASETHRESHOLD 100 // follow a player exlusively for 3 seconds
+
+// ***** P_TICK *****
+
+extern thinker_t thinkercap; // both the head and tail of the thinker list
+extern int TimerGame; // tic countdown for deathmatch
+
+void P_InitThinkers(void);
+void P_AddThinker(thinker_t * thinker);
+void P_RemoveThinker(thinker_t * thinker);
+
+// ***** P_PSPR *****
+
+#define USE_GWND_AMMO_1 1
+#define USE_GWND_AMMO_2 1
+#define USE_CBOW_AMMO_1 1
+#define USE_CBOW_AMMO_2 1
+#define USE_BLSR_AMMO_1 1
+#define USE_BLSR_AMMO_2 5
+#define USE_SKRD_AMMO_1 1
+#define USE_SKRD_AMMO_2 5
+#define USE_PHRD_AMMO_1 1
+#define USE_PHRD_AMMO_2 1
+#define USE_MACE_AMMO_1 1
+#define USE_MACE_AMMO_2 5
+
+void P_OpenWeapons(void);
+void P_CloseWeapons(void);
+void P_AddMaceSpot(mapthing_t * mthing);
+void P_RepositionMace(mobj_t * mo);
+void P_SetPsprite(player_t * player, int position, statenum_t stnum);
+void P_SetupPsprites(player_t * curplayer);
+void P_MovePsprites(player_t * curplayer);
+void P_DropWeapon(player_t * player);
+void P_ActivateBeak(player_t * player);
+void P_PostChickenWeapon(player_t * player, weapontype_t weapon);
+void P_UpdateBeak(player_t * player, pspdef_t * psp);
+
+// ***** P_USER *****
+
+void P_PlayerThink(player_t * player);
+void P_Thrust(player_t * player, angle_t angle, fixed_t move);
+void P_PlayerRemoveArtifact(player_t * player, int slot);
+void P_PlayerUseArtifact(player_t * player, artitype_t arti);
+boolean P_UseArtifact(player_t * player, artitype_t arti);
+int P_GetPlayerNum(player_t * player);
+
+// ***** P_MOBJ *****
+
+#define FLOOR_SOLID 0
+#define FLOOR_WATER 1
+#define FLOOR_LAVA 2
+#define FLOOR_SLUDGE 3
+
+#define ONFLOORZ INT_MIN
+#define ONCEILINGZ INT_MAX
+#define FLOATRANDZ (INT_MAX-1)
+
+extern mobjtype_t PuffType;
+extern mobj_t *MissileMobj;
+
+mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type);
+void P_RemoveMobj(mobj_t * th);
+boolean P_SetMobjState(mobj_t * mobj, statenum_t state);
+boolean P_SetMobjStateNF(mobj_t * mobj, statenum_t state);
+void P_ThrustMobj(mobj_t * mo, angle_t angle, fixed_t move);
+int P_FaceMobj(mobj_t * source, mobj_t * target, angle_t * delta);
+boolean P_SeekerMissile(mobj_t * actor, angle_t thresh, angle_t turnMax);
+void P_MobjThinker(mobj_t * mobj);
+void P_BlasterMobjThinker(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);
+void P_BloodSplatter(fixed_t x, fixed_t y, fixed_t z, mobj_t * originator);
+void P_RipperBlood(mobj_t * mo);
+int P_GetThingFloorType(mobj_t * thing);
+int P_HitFloor(mobj_t * thing);
+boolean P_CheckMissileSpawn(mobj_t * missile);
+mobj_t *P_SpawnMissile(mobj_t * source, mobj_t * dest, mobjtype_t type);
+mobj_t *P_SpawnMissileAngle(mobj_t * source, mobjtype_t type,
+ angle_t angle, fixed_t momz);
+mobj_t *P_SpawnPlayerMissile(mobj_t * source, mobjtype_t type);
+mobj_t *P_SPMAngle(mobj_t * source, mobjtype_t type, angle_t angle);
+
+// ***** P_ENEMY *****
+
+void P_NoiseAlert(mobj_t * target, mobj_t * emmiter);
+void P_InitMonsters(void);
+void P_AddBossSpot(fixed_t x, fixed_t y, angle_t angle);
+void P_Massacre(void);
+void P_DSparilTeleport(mobj_t * actor);
+
+// ***** P_MAPUTL *****
+
+typedef struct
+{
+ fixed_t x, y, dx, dy;
+} divline_t;
+
+typedef struct
+{
+ fixed_t frac; // along trace line
+ boolean isaline;
+ union
+ {
+ mobj_t *thing;
+ line_t *line;
+ } d;
+} intercept_t;
+
+#define MAXINTERCEPTS 128
+extern intercept_t intercepts[MAXINTERCEPTS], *intercept_p;
+typedef 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, openbottom, openrange;
+extern fixed_t lowfloor;
+void P_LineOpening(line_t * linedef);
+
+boolean P_BlockLinesIterator(int x, int y, boolean(*func) (line_t *));
+boolean P_BlockThingsIterator(int x, int y, boolean(*func) (mobj_t *));
+
+#define PT_ADDLINES 1
+#define PT_ADDTHINGS 2
+#define PT_EARLYOUT 4
+
+extern divline_t trace;
+boolean P_PathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2,
+ int flags, boolean(*trav) (intercept_t *));
+
+void P_UnsetThingPosition(mobj_t * thing);
+void P_SetThingPosition(mobj_t * thing);
+
+// ***** P_MAP *****
+
+extern boolean floatok; // if true, move would be ok if
+extern fixed_t tmfloorz, tmceilingz; // within tmfloorz - tmceilingz
+
+extern line_t *ceilingline;
+boolean P_TestMobjLocation(mobj_t * mobj);
+boolean P_CheckPosition(mobj_t * thing, fixed_t x, fixed_t y);
+mobj_t *P_CheckOnmobj(mobj_t * thing);
+void P_FakeZMovement(mobj_t * mo);
+boolean P_TryMove(mobj_t * thing, fixed_t x, fixed_t y);
+boolean P_TeleportMove(mobj_t * thing, fixed_t x, fixed_t y);
+void P_SlideMove(mobj_t * mo);
+boolean P_CheckSight(mobj_t * t1, mobj_t * t2);
+void P_UseLines(player_t * player);
+
+boolean P_ChangeSector(sector_t * sector, boolean crunch);
+
+extern mobj_t *linetarget; // who got hit (or NULL)
+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, bmapheight; // in mapblocks
+extern fixed_t bmaporgx, bmaporgy; // origin of block map
+extern mobj_t **blocklinks; // for thing chains
+
+// ***** P_INTER *****
+
+extern int maxammo[NUMAMMO];
+extern int clipammo[NUMAMMO];
+
+void P_SetMessage(player_t * player, char *message, boolean ultmsg);
+void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher);
+void P_DamageMobj(mobj_t * target, mobj_t * inflictor, mobj_t * source,
+ int damage);
+boolean P_GiveAmmo(player_t * player, ammotype_t ammo, int count);
+boolean P_GiveArtifact(player_t * player, artitype_t arti, mobj_t * mo);
+boolean P_GiveBody(player_t * player, int num);
+boolean P_GivePower(player_t * player, powertype_t power);
+boolean P_ChickenMorphPlayer(player_t * player);
+
+// ***** AM_MAP *****
+
+boolean AM_Responder(event_t * ev);
+void AM_Ticker(void);
+void AM_Drawer(void);
+
+// ***** SB_BAR *****
+
+extern int SB_state;
+extern int ArtifactFlash;
+void SB_PaletteFlash(void);
+
+#include "p_spec.h"
+
+#endif // __P_LOCAL__
diff --git a/src/heretic/p_map.c b/src/heretic/p_map.c
new file mode 100644
index 00000000..0b1c6df1
--- /dev/null
+++ b/src/heretic/p_map.c
@@ -0,0 +1,1698 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+// P_map.c
+
+#include <stdlib.h>
+
+#include "doomdef.h"
+#include "i_system.h"
+#include "m_bbox.h"
+#include "m_random.h"
+#include "p_local.h"
+#include "s_sound.h"
+
+/*
+===============================================================================
+
+NOTES:
+
+
+===============================================================================
+*/
+
+/*
+===============================================================================
+
+mobj_t NOTES
+
+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 it's 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 be 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 it's origin contained.
+
+A valid mobj_t is a mobj_t that has the proper subsector_t filled in for it's
+xy coordinates and is linked into the subsector's sector 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.
+
+
+===============================================================================
+*/
+
+fixed_t tmbbox[4];
+mobj_t *tmthing;
+int tmflags;
+fixed_t tmx, tmy;
+
+boolean floatok; // if true, move would be ok if
+ // within tmfloorz - tmceilingz
+
+fixed_t tmfloorz, tmceilingz, tmdropoffz;
+
+// keep track of the line that lowers the ceiling, so missiles don't explode
+// against sky hack walls
+line_t *ceilingline;
+
+// keep track of special lines as they are hit, but don't process them
+// until the move is proven valid
+#define MAXSPECIALCROSS 8
+line_t *spechit[MAXSPECIALCROSS];
+int numspechit;
+
+mobj_t *onmobj; //generic global onmobj...used for landing on pods/players
+
+/*
+===============================================================================
+
+ TELEPORT MOVE
+
+===============================================================================
+*/
+
+/*
+==================
+=
+= PIT_StompThing
+=
+==================
+*/
+
+boolean PIT_StompThing(mobj_t * thing)
+{
+ fixed_t blockdist;
+
+ if (!(thing->flags & MF_SHOOTABLE))
+ return true;
+
+ blockdist = thing->radius + tmthing->radius;
+ if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist)
+ return true; // didn't hit it
+
+ if (thing == tmthing)
+ return true; // don't clip against self
+
+ if (!(tmthing->flags2 & MF2_TELESTOMP))
+ { // Not allowed to stomp things
+ return (false);
+ }
+
+ P_DamageMobj(thing, tmthing, tmthing, 10000);
+
+ return true;
+}
+
+
+/*
+===================
+=
+= P_TeleportMove
+=
+===================
+*/
+
+boolean P_TeleportMove(mobj_t * thing, fixed_t x, fixed_t y)
+{
+ int xl, xh, yl, yh, bx, by;
+ subsector_t *newsubsec;
+
+//
+// kill anything occupying the position
+//
+
+ tmthing = thing;
+ tmflags = thing->flags;
+
+ tmx = x;
+ tmy = y;
+
+ tmbbox[BOXTOP] = y + tmthing->radius;
+ tmbbox[BOXBOTTOM] = y - tmthing->radius;
+ tmbbox[BOXRIGHT] = x + tmthing->radius;
+ tmbbox[BOXLEFT] = x - tmthing->radius;
+
+ newsubsec = R_PointInSubsector(x, y);
+ ceilingline = NULL;
+
+//
+// the base floor / ceiling is from the subsector that contains the
+// point. Any contacted lines the step closer together will adjust them
+//
+ tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
+ tmceilingz = newsubsec->sector->ceilingheight;
+
+ validcount++;
+ numspechit = 0;
+
+//
+// stomp on any things contacted
+//
+ xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS) >> MAPBLOCKSHIFT;
+ xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS) >> MAPBLOCKSHIFT;
+ yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS) >> MAPBLOCKSHIFT;
+ yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS) >> MAPBLOCKSHIFT;
+
+ for (bx = xl; bx <= xh; bx++)
+ for (by = yl; by <= yh; by++)
+ if (!P_BlockThingsIterator(bx, by, PIT_StompThing))
+ return false;
+
+//
+// the move is ok, so link the thing into its new position
+//
+ P_UnsetThingPosition(thing);
+
+ thing->floorz = tmfloorz;
+ thing->ceilingz = tmceilingz;
+ thing->x = x;
+ thing->y = y;
+
+ P_SetThingPosition(thing);
+
+ return true;
+}
+
+/*
+===============================================================================
+
+ MOVEMENT ITERATOR FUNCTIONS
+
+===============================================================================
+*/
+
+/*
+==================
+=
+= PIT_CheckLine
+=
+= Adjusts tmfloorz and tmceilingz as lines are contacted
+==================
+*/
+
+boolean PIT_CheckLine(line_t * ld)
+{
+ if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT]
+ || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
+ || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM]
+ || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
+ {
+ return (true);
+ }
+ if (P_BoxOnLineSide(tmbbox, ld) != -1)
+ {
+ return (true);
+ }
+
+// a line has been hit
+/*
+=
+= The moving thing's destination position will cross the given line.
+= If this should not be allowed, return false.
+= If the line is special, keep track of it to process later if the move
+= is proven ok. NOTE: specials are NOT sorted by order, so two special lines
+= that are only 8 pixels apart could be crossed in either order.
+*/
+
+ if (!ld->backsector)
+ { // One sided line
+ if (tmthing->flags & MF_MISSILE)
+ { // Missiles can trigger impact specials
+ if (ld->special)
+ {
+ spechit[numspechit] = ld;
+ numspechit++;
+ }
+ }
+ return false;
+ }
+ if (!(tmthing->flags & MF_MISSILE))
+ {
+ if (ld->flags & ML_BLOCKING)
+ { // Explicitly blocking everything
+ return (false);
+ }
+ if (!tmthing->player && ld->flags & ML_BLOCKMONSTERS
+ && tmthing->type != MT_POD)
+ { // Block monsters only
+ return (false);
+ }
+ }
+ P_LineOpening(ld); // set openrange, opentop, openbottom
+ // adjust floor / ceiling heights
+ if (opentop < tmceilingz)
+ {
+ tmceilingz = opentop;
+ ceilingline = ld;
+ }
+ if (openbottom > tmfloorz)
+ {
+ tmfloorz = openbottom;
+ }
+ if (lowfloor < tmdropoffz)
+ {
+ tmdropoffz = lowfloor;
+ }
+ if (ld->special)
+ { // Contacted a special line, add it to the list
+ spechit[numspechit] = ld;
+ numspechit++;
+ }
+ return (true);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC PIT_CheckThing
+//
+//---------------------------------------------------------------------------
+
+boolean PIT_CheckThing(mobj_t * thing)
+{
+ fixed_t blockdist;
+ boolean solid;
+ int damage;
+
+ if (!(thing->flags & (MF_SOLID | MF_SPECIAL | MF_SHOOTABLE)))
+ { // Can't hit thing
+ return (true);
+ }
+ blockdist = thing->radius + tmthing->radius;
+ if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist)
+ { // Didn't hit thing
+ return (true);
+ }
+ if (thing == tmthing)
+ { // Don't clip against self
+ return (true);
+ }
+ if (tmthing->flags2 & MF2_PASSMOBJ)
+ { // check if a mobj passed over/under another object
+ if ((tmthing->type == MT_IMP || tmthing->type == MT_WIZARD)
+ && (thing->type == MT_IMP || thing->type == MT_WIZARD))
+ { // don't let imps/wizards fly over other imps/wizards
+ return false;
+ }
+ if (tmthing->z > thing->z + thing->height
+ && !(thing->flags & MF_SPECIAL))
+ {
+ return (true);
+ }
+ else if (tmthing->z + tmthing->height < thing->z
+ && !(thing->flags & MF_SPECIAL))
+ { // under thing
+ return (true);
+ }
+ }
+ // Check for skulls slamming into things
+ if (tmthing->flags & MF_SKULLFLY)
+ {
+ damage = ((P_Random() % 8) + 1) * tmthing->damage;
+ P_DamageMobj(thing, tmthing, tmthing, damage);
+ tmthing->flags &= ~MF_SKULLFLY;
+ tmthing->momx = tmthing->momy = tmthing->momz = 0;
+ P_SetMobjState(tmthing, tmthing->info->seestate);
+ return (false);
+ }
+ // Check for missile
+ if (tmthing->flags & MF_MISSILE)
+ {
+ // Check for passing through a ghost
+ if ((thing->flags & MF_SHADOW) && (tmthing->flags2 & MF2_THRUGHOST))
+ {
+ return (true);
+ }
+ // Check if it went over / under
+ if (tmthing->z > thing->z + thing->height)
+ { // Over thing
+ return (true);
+ }
+ if (tmthing->z + tmthing->height < thing->z)
+ { // Under thing
+ return (true);
+ }
+ if (tmthing->target && tmthing->target->type == thing->type)
+ { // Don't hit same species as originator
+ if (thing == tmthing->target)
+ { // Don't missile self
+ return (true);
+ }
+ if (thing->type != MT_PLAYER)
+ { // Hit same species as originator, explode, no damage
+ return (false);
+ }
+ }
+ if (!(thing->flags & MF_SHOOTABLE))
+ { // Didn't do any damage
+ return !(thing->flags & MF_SOLID);
+ }
+ if (tmthing->flags2 & MF2_RIP)
+ {
+ if (!(thing->flags & MF_NOBLOOD))
+ { // Ok to spawn some blood
+ P_RipperBlood(tmthing);
+ }
+ S_StartSound(tmthing, sfx_ripslop);
+ damage = ((P_Random() & 3) + 2) * tmthing->damage;
+ P_DamageMobj(thing, tmthing, tmthing->target, damage);
+ if (thing->flags2 & MF2_PUSHABLE
+ && !(tmthing->flags2 & MF2_CANNOTPUSH))
+ { // Push thing
+ thing->momx += tmthing->momx >> 2;
+ thing->momy += tmthing->momy >> 2;
+ }
+ numspechit = 0;
+ return (true);
+ }
+ // Do damage
+ damage = ((P_Random() % 8) + 1) * tmthing->damage;
+ if (damage)
+ {
+ if (!(thing->flags & MF_NOBLOOD) && P_Random() < 192)
+ {
+ P_BloodSplatter(tmthing->x, tmthing->y, tmthing->z, thing);
+ }
+ P_DamageMobj(thing, tmthing, tmthing->target, damage);
+ }
+ return (false);
+ }
+ if (thing->flags2 & MF2_PUSHABLE && !(tmthing->flags2 & MF2_CANNOTPUSH))
+ { // Push thing
+ thing->momx += tmthing->momx >> 2;
+ thing->momy += tmthing->momy >> 2;
+ }
+ // Check for special thing
+ if (thing->flags & MF_SPECIAL)
+ {
+ solid = thing->flags & MF_SOLID;
+ if (tmflags & MF_PICKUP)
+ { // Can be picked up by tmthing
+ P_TouchSpecialThing(thing, tmthing); // Can remove thing
+ }
+ return (!solid);
+ }
+ return (!(thing->flags & MF_SOLID));
+}
+
+//---------------------------------------------------------------------------
+//
+// PIT_CheckOnmobjZ
+//
+//---------------------------------------------------------------------------
+
+boolean PIT_CheckOnmobjZ(mobj_t * thing)
+{
+ fixed_t blockdist;
+
+ if (!(thing->flags & (MF_SOLID | MF_SPECIAL | MF_SHOOTABLE)))
+ { // Can't hit thing
+ return (true);
+ }
+ blockdist = thing->radius + tmthing->radius;
+ if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist)
+ { // Didn't hit thing
+ return (true);
+ }
+ if (thing == tmthing)
+ { // Don't clip against self
+ return (true);
+ }
+ if (tmthing->z > thing->z + thing->height)
+ {
+ return (true);
+ }
+ else if (tmthing->z + tmthing->height < thing->z)
+ { // under thing
+ return (true);
+ }
+ if (thing->flags & MF_SOLID)
+ {
+ onmobj = thing;
+ }
+ return (!(thing->flags & MF_SOLID));
+}
+
+/*
+===============================================================================
+
+ MOVEMENT CLIPPING
+
+===============================================================================
+*/
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_TestMobjLocation
+//
+// Returns true if the mobj is not blocked by anything at its current
+// location, otherwise returns false.
+//
+//----------------------------------------------------------------------------
+
+boolean P_TestMobjLocation(mobj_t * mobj)
+{
+ int flags;
+
+ flags = mobj->flags;
+ mobj->flags &= ~MF_PICKUP;
+ if (P_CheckPosition(mobj, mobj->x, mobj->y))
+ { // XY is ok, now check Z
+ mobj->flags = flags;
+ if ((mobj->z < mobj->floorz)
+ || (mobj->z + mobj->height > mobj->ceilingz))
+ { // Bad Z
+ return (false);
+ }
+ return (true);
+ }
+ mobj->flags = flags;
+ return (false);
+}
+
+/*
+==================
+=
+= P_CheckPosition
+=
+= This is purely informative, nothing is modified (except things picked up)
+
+in:
+a mobj_t (can be valid or invalid)
+a position to be checked (doesn't need to be related to the mobj_t->x,y)
+
+during:
+special things are touched if MF_PICKUP
+early out on solid lines?
+
+out:
+newsubsec
+floorz
+ceilingz
+tmdropoffz the lowest point contacted (monsters won't move to a dropoff)
+speciallines[]
+numspeciallines
+
+==================
+*/
+
+boolean P_CheckPosition(mobj_t * thing, fixed_t x, fixed_t y)
+{
+ int xl, xh, yl, yh, bx, by;
+ subsector_t *newsubsec;
+
+ tmthing = thing;
+ tmflags = thing->flags;
+
+ tmx = x;
+ tmy = y;
+
+ tmbbox[BOXTOP] = y + tmthing->radius;
+ tmbbox[BOXBOTTOM] = y - tmthing->radius;
+ tmbbox[BOXRIGHT] = x + tmthing->radius;
+ tmbbox[BOXLEFT] = x - tmthing->radius;
+
+ newsubsec = R_PointInSubsector(x, y);
+ ceilingline = NULL;
+
+//
+// the base floor / ceiling is from the subsector that contains the
+// point. Any contacted lines the step closer together will adjust them
+//
+ tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
+ tmceilingz = newsubsec->sector->ceilingheight;
+
+ validcount++;
+ numspechit = 0;
+
+ if (tmflags & MF_NOCLIP)
+ return true;
+
+//
+// check things first, possibly picking things up
+// the bounding box is extended by MAXRADIUS because mobj_ts are grouped
+// into mapblocks based on their origin point, and can overlap into adjacent
+// blocks by up to MAXRADIUS units
+//
+ xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS) >> MAPBLOCKSHIFT;
+ xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS) >> MAPBLOCKSHIFT;
+ yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS) >> MAPBLOCKSHIFT;
+ yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS) >> MAPBLOCKSHIFT;
+
+ for (bx = xl; bx <= xh; bx++)
+ for (by = yl; by <= yh; by++)
+ if (!P_BlockThingsIterator(bx, by, PIT_CheckThing))
+ return false;
+//
+// check lines
+//
+ xl = (tmbbox[BOXLEFT] - bmaporgx) >> MAPBLOCKSHIFT;
+ xh = (tmbbox[BOXRIGHT] - bmaporgx) >> MAPBLOCKSHIFT;
+ yl = (tmbbox[BOXBOTTOM] - bmaporgy) >> MAPBLOCKSHIFT;
+ yh = (tmbbox[BOXTOP] - bmaporgy) >> MAPBLOCKSHIFT;
+
+ for (bx = xl; bx <= xh; bx++)
+ for (by = yl; by <= yh; by++)
+ if (!P_BlockLinesIterator(bx, by, PIT_CheckLine))
+ return false;
+
+ return true;
+}
+
+//=============================================================================
+//
+// P_CheckOnmobj(mobj_t *thing)
+//
+// Checks if the new Z position is legal
+//=============================================================================
+
+mobj_t *P_CheckOnmobj(mobj_t * thing)
+{
+ int xl, xh, yl, yh, bx, by;
+ subsector_t *newsubsec;
+ fixed_t x;
+ fixed_t y;
+ mobj_t oldmo;
+
+ x = thing->x;
+ y = thing->y;
+ tmthing = thing;
+ tmflags = thing->flags;
+ oldmo = *thing; // save the old mobj before the fake zmovement
+ P_FakeZMovement(tmthing);
+
+ tmx = x;
+ tmy = y;
+
+ tmbbox[BOXTOP] = y + tmthing->radius;
+ tmbbox[BOXBOTTOM] = y - tmthing->radius;
+ tmbbox[BOXRIGHT] = x + tmthing->radius;
+ tmbbox[BOXLEFT] = x - tmthing->radius;
+
+ newsubsec = R_PointInSubsector(x, y);
+ ceilingline = NULL;
+
+//
+// the base floor / ceiling is from the subsector that contains the
+// point. Any contacted lines the step closer together will adjust them
+//
+ tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
+ tmceilingz = newsubsec->sector->ceilingheight;
+
+ validcount++;
+ numspechit = 0;
+
+ if (tmflags & MF_NOCLIP)
+ return NULL;
+
+//
+// check things first, possibly picking things up
+// the bounding box is extended by MAXRADIUS because mobj_ts are grouped
+// into mapblocks based on their origin point, and can overlap into adjacent
+// blocks by up to MAXRADIUS units
+//
+ xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS) >> MAPBLOCKSHIFT;
+ xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS) >> MAPBLOCKSHIFT;
+ yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS) >> MAPBLOCKSHIFT;
+ yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS) >> MAPBLOCKSHIFT;
+
+ for (bx = xl; bx <= xh; bx++)
+ for (by = yl; by <= yh; by++)
+ if (!P_BlockThingsIterator(bx, by, PIT_CheckOnmobjZ))
+ {
+ *tmthing = oldmo;
+ return onmobj;
+ }
+ *tmthing = oldmo;
+ return NULL;
+}
+
+//=============================================================================
+//
+// P_FakeZMovement
+//
+// Fake the zmovement so that we can check if a move is legal
+//=============================================================================
+
+void P_FakeZMovement(mobj_t * mo)
+{
+ int dist;
+ int delta;
+//
+// 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;
+ }
+ }
+ if (mo->player && mo->flags2 & MF2_FLY && !(mo->z <= mo->floorz)
+ && leveltime & 2)
+ {
+ mo->z += finesine[(FINEANGLES / 20 * leveltime >> 2) & FINEMASK];
+ }
+
+//
+// clip movement
+//
+ if (mo->z <= mo->floorz)
+ { // Hit the floor
+ mo->z = mo->floorz;
+ if (mo->momz < 0)
+ {
+ mo->momz = 0;
+ }
+ if (mo->flags & MF_SKULLFLY)
+ { // The skull slammed into something
+ mo->momz = -mo->momz;
+ }
+ if (mo->info->crashstate && (mo->flags & MF_CORPSE))
+ {
+ return;
+ }
+ }
+ else if (mo->flags2 & MF2_LOGRAV)
+ {
+ if (mo->momz == 0)
+ mo->momz = -(GRAVITY >> 3) * 2;
+ else
+ mo->momz -= GRAVITY >> 3;
+ }
+ 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;
+ }
+ }
+}
+
+//==========================================================================
+//
+// CheckMissileImpact
+//
+//==========================================================================
+
+void CheckMissileImpact(mobj_t * mobj)
+{
+ int i;
+
+ if (!numspechit || !(mobj->flags & MF_MISSILE) || !mobj->target)
+ {
+ return;
+ }
+ if (!mobj->target->player)
+ {
+ return;
+ }
+ for (i = numspechit - 1; i >= 0; i--)
+ {
+ P_ShootSpecialLine(mobj->target, spechit[i]);
+ }
+}
+
+/*
+===================
+=
+= P_TryMove
+=
+= Attempt to move to a new position, crossing special lines unless MF_TELEPORT
+= is set
+=
+===================
+*/
+
+boolean P_TryMove(mobj_t * thing, fixed_t x, fixed_t y)
+{
+ fixed_t oldx, oldy;
+ int side, oldside;
+ line_t *ld;
+
+ floatok = false;
+ if (!P_CheckPosition(thing, x, y))
+ { // Solid wall or thing
+ CheckMissileImpact(thing);
+ return false;
+ }
+ if (!(thing->flags & MF_NOCLIP))
+ {
+ if (tmceilingz - tmfloorz < thing->height)
+ { // Doesn't fit
+ CheckMissileImpact(thing);
+ return false;
+ }
+ floatok = true;
+ if (!(thing->flags & MF_TELEPORT)
+ && tmceilingz - thing->z < thing->height
+ && !(thing->flags2 & MF2_FLY))
+ { // mobj must lower itself to fit
+ CheckMissileImpact(thing);
+ return false;
+ }
+ if (thing->flags2 & MF2_FLY)
+ {
+ if (thing->z + thing->height > tmceilingz)
+ {
+ thing->momz = -8 * FRACUNIT;
+ return false;
+ }
+ else if (thing->z < tmfloorz
+ && tmfloorz - tmdropoffz > 24 * FRACUNIT)
+ {
+ thing->momz = 8 * FRACUNIT;
+ return false;
+ }
+ }
+ if (!(thing->flags & MF_TELEPORT)
+ // The Minotaur floor fire (MT_MNTRFX2) can step up any amount
+ && thing->type != MT_MNTRFX2
+ && tmfloorz - thing->z > 24 * FRACUNIT)
+ { // Too big a step up
+ CheckMissileImpact(thing);
+ return false;
+ }
+ if ((thing->flags & MF_MISSILE) && tmfloorz > thing->z)
+ {
+ CheckMissileImpact(thing);
+ }
+ if (!(thing->flags & (MF_DROPOFF | MF_FLOAT))
+ && tmfloorz - tmdropoffz > 24 * FRACUNIT)
+ { // Can't move over a dropoff
+ return false;
+ }
+ }
+
+//
+// the move is ok, so link the thing into its new position
+//
+ P_UnsetThingPosition(thing);
+
+ oldx = thing->x;
+ oldy = thing->y;
+ thing->floorz = tmfloorz;
+ thing->ceilingz = tmceilingz;
+ thing->x = x;
+ thing->y = y;
+
+ P_SetThingPosition(thing);
+
+ if (thing->flags2 & MF2_FOOTCLIP
+ && P_GetThingFloorType(thing) != FLOOR_SOLID)
+ {
+ thing->flags2 |= MF2_FEETARECLIPPED;
+ }
+ else if (thing->flags2 & MF2_FEETARECLIPPED)
+ {
+ thing->flags2 &= ~MF2_FEETARECLIPPED;
+ }
+
+//
+// if any special lines were hit, do the effect
+//
+ if (!(thing->flags & (MF_TELEPORT | MF_NOCLIP)))
+ while (numspechit--)
+ {
+ // see if the line was crossed
+ ld = spechit[numspechit];
+ side = P_PointOnLineSide(thing->x, thing->y, ld);
+ oldside = P_PointOnLineSide(oldx, oldy, ld);
+ if (side != oldside)
+ {
+ if (ld->special)
+ P_CrossSpecialLine(ld - lines, oldside, thing);
+ }
+ }
+
+ return true;
+}
+
+/*
+==================
+=
+= P_ThingHeightClip
+=
+= Takes a valid thing and adjusts the thing->floorz, thing->ceilingz,
+= anf possibly thing->z
+=
+= This is called for all nearby monsters whenever a sector changes height
+=
+= If the thing doesn't fit, the z will be set to the lowest value and
+= false will be returned
+==================
+*/
+
+boolean P_ThingHeightClip(mobj_t * thing)
+{
+ boolean onfloor;
+
+ onfloor = (thing->z == thing->floorz);
+
+ P_CheckPosition(thing, thing->x, thing->y);
+ // what about stranding a monster partially off an edge?
+
+ thing->floorz = tmfloorz;
+ thing->ceilingz = tmceilingz;
+
+ if (onfloor)
+ // walking monsters rise and fall with the floor
+ thing->z = thing->floorz;
+ else
+ { // don't adjust a floating monster unless forced to
+ if (thing->z + thing->height > thing->ceilingz)
+ thing->z = thing->ceilingz - thing->height;
+ }
+
+ if (thing->ceilingz - thing->floorz < thing->height)
+ return false;
+
+ return true;
+}
+
+
+/*
+==============================================================================
+
+ SLIDE MOVE
+
+Allows the player to slide along any angled walls
+
+==============================================================================
+*/
+
+fixed_t bestslidefrac, secondslidefrac;
+line_t *bestslideline, *secondslideline;
+mobj_t *slidemo;
+
+fixed_t tmxmove, tmymove;
+
+/*
+==================
+=
+= P_HitSlideLine
+=
+= Adjusts the xmove / ymove so that the next move will slide along the wall
+==================
+*/
+
+void P_HitSlideLine(line_t * ld)
+{
+ int side;
+ angle_t lineangle, moveangle, deltaangle;
+ fixed_t movelen, newlen;
+
+
+ if (ld->slopetype == ST_HORIZONTAL)
+ {
+ tmymove = 0;
+ return;
+ }
+ if (ld->slopetype == ST_VERTICAL)
+ {
+ tmxmove = 0;
+ return;
+ }
+
+ side = P_PointOnLineSide(slidemo->x, slidemo->y, ld);
+
+ lineangle = R_PointToAngle2(0, 0, ld->dx, ld->dy);
+ if (side == 1)
+ lineangle += ANG180;
+ moveangle = R_PointToAngle2(0, 0, tmxmove, tmymove);
+ deltaangle = moveangle - lineangle;
+ if (deltaangle > ANG180)
+ deltaangle += ANG180;
+// I_Error ("SlideLine: ang>ANG180");
+
+ lineangle >>= ANGLETOFINESHIFT;
+ deltaangle >>= ANGLETOFINESHIFT;
+
+ movelen = P_AproxDistance(tmxmove, tmymove);
+ newlen = FixedMul(movelen, finecosine[deltaangle]);
+ tmxmove = FixedMul(newlen, finecosine[lineangle]);
+ tmymove = FixedMul(newlen, finesine[lineangle]);
+}
+
+/*
+==============
+=
+= PTR_SlideTraverse
+=
+==============
+*/
+
+boolean PTR_SlideTraverse(intercept_t * in)
+{
+ line_t *li;
+
+ if (!in->isaline)
+ I_Error("PTR_SlideTraverse: not a line?");
+
+ li = in->d.line;
+ if (!(li->flags & ML_TWOSIDED))
+ {
+ if (P_PointOnLineSide(slidemo->x, slidemo->y, li))
+ return true; // don't hit the back side
+ goto isblocking;
+ }
+
+ P_LineOpening(li); // set openrange, opentop, openbottom
+ if (openrange < slidemo->height)
+ goto isblocking; // doesn't fit
+
+ if (opentop - slidemo->z < slidemo->height)
+ goto isblocking; // mobj is too high
+
+ if (openbottom - slidemo->z > 24 * FRACUNIT)
+ goto isblocking; // too big a step up
+
+ return true; // this line doesn't block movement
+
+// the line does block movement, see if it is closer than best so far
+ isblocking:
+ if (in->frac < bestslidefrac)
+ {
+ secondslidefrac = bestslidefrac;
+ secondslideline = bestslideline;
+ bestslidefrac = in->frac;
+ bestslideline = li;
+ }
+
+ return false; // stop
+}
+
+
+/*
+==================
+=
+= P_SlideMove
+=
+= The momx / momy move is bad, so try to slide along a wall
+=
+= Find the first line hit, move flush to it, and slide along it
+=
+= This is a kludgy mess.
+==================
+*/
+
+void P_SlideMove(mobj_t * mo)
+{
+ fixed_t leadx, leady;
+ fixed_t trailx, traily;
+ fixed_t newx, newy;
+ int hitcount;
+
+ slidemo = mo;
+ hitcount = 0;
+ retry:
+ if (++hitcount == 3)
+ goto stairstep; // don't loop forever
+
+//
+// trace along the three leading corners
+//
+ if (mo->momx > 0)
+ {
+ leadx = mo->x + mo->radius;
+ trailx = mo->x - mo->radius;
+ }
+ else
+ {
+ leadx = mo->x - mo->radius;
+ trailx = mo->x + mo->radius;
+ }
+
+ if (mo->momy > 0)
+ {
+ leady = mo->y + mo->radius;
+ traily = mo->y - mo->radius;
+ }
+ else
+ {
+ leady = mo->y - mo->radius;
+ traily = mo->y + mo->radius;
+ }
+
+ bestslidefrac = FRACUNIT + 1;
+
+ P_PathTraverse(leadx, leady, leadx + mo->momx, leady + mo->momy,
+ PT_ADDLINES, PTR_SlideTraverse);
+ P_PathTraverse(trailx, leady, trailx + mo->momx, leady + mo->momy,
+ PT_ADDLINES, PTR_SlideTraverse);
+ P_PathTraverse(leadx, traily, leadx + mo->momx, traily + mo->momy,
+ PT_ADDLINES, PTR_SlideTraverse);
+
+//
+// move up to the wall
+//
+ if (bestslidefrac == FRACUNIT + 1)
+ { // the move most have hit the middle, so stairstep
+ stairstep:
+ if (!P_TryMove(mo, mo->x, mo->y + mo->momy))
+ P_TryMove(mo, mo->x + mo->momx, mo->y);
+ return;
+ }
+
+ bestslidefrac -= 0x800; // fudge a bit to make sure it doesn't hit
+ if (bestslidefrac > 0)
+ {
+ newx = FixedMul(mo->momx, bestslidefrac);
+ newy = FixedMul(mo->momy, bestslidefrac);
+ if (!P_TryMove(mo, mo->x + newx, mo->y + newy))
+ goto stairstep;
+ }
+
+//
+// now continue along the wall
+//
+ bestslidefrac = FRACUNIT - (bestslidefrac + 0x800); // remainder
+ if (bestslidefrac > FRACUNIT)
+ bestslidefrac = FRACUNIT;
+ if (bestslidefrac <= 0)
+ return;
+
+ tmxmove = FixedMul(mo->momx, bestslidefrac);
+ tmymove = FixedMul(mo->momy, bestslidefrac);
+
+ P_HitSlideLine(bestslideline); // clip the moves
+
+ mo->momx = tmxmove;
+ mo->momy = tmymove;
+
+ if (!P_TryMove(mo, mo->x + tmxmove, mo->y + tmymove))
+ {
+ goto retry;
+ }
+}
+
+
+
+/*
+==============================================================================
+
+ P_LineAttack
+
+==============================================================================
+*/
+
+
+mobj_t *linetarget; // who got hit (or NULL)
+mobj_t *shootthing;
+fixed_t shootz; // height if not aiming up or down
+ // ???: use slope for monsters?
+int la_damage;
+fixed_t attackrange;
+
+fixed_t aimslope;
+
+extern fixed_t topslope, bottomslope; // slopes to top and bottom of target
+
+/*
+===============================================================================
+=
+= PTR_AimTraverse
+=
+= Sets linetaget and aimslope when a target is aimed at
+===============================================================================
+*/
+
+boolean PTR_AimTraverse(intercept_t * in)
+{
+ line_t *li;
+ mobj_t *th;
+ fixed_t slope, thingtopslope, thingbottomslope;
+ fixed_t dist;
+
+ if (in->isaline)
+ {
+ li = in->d.line;
+ if (!(li->flags & ML_TWOSIDED))
+ return false; // stop
+//
+// crosses a two sided line
+// a two sided line will restrict the possible target ranges
+ P_LineOpening(li);
+
+ if (openbottom >= opentop)
+ return false; // stop
+
+ dist = FixedMul(attackrange, in->frac);
+
+ if (li->frontsector->floorheight != li->backsector->floorheight)
+ {
+ slope = FixedDiv(openbottom - shootz, dist);
+ if (slope > bottomslope)
+ bottomslope = slope;
+ }
+
+ if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
+ {
+ slope = FixedDiv(opentop - shootz, dist);
+ if (slope < topslope)
+ topslope = slope;
+ }
+
+ if (topslope <= bottomslope)
+ return false; // stop
+
+ return true; // shot continues
+ }
+
+//
+// shoot a thing
+//
+ th = in->d.thing;
+ if (th == shootthing)
+ return true; // can't shoot self
+ if (!(th->flags & MF_SHOOTABLE))
+ return true; // corpse or something
+ if (th->type == MT_POD)
+ { // Can't auto-aim at pods
+ return (true);
+ }
+
+// check angles to see if the thing can be aimed at
+
+ dist = FixedMul(attackrange, in->frac);
+ thingtopslope = FixedDiv(th->z + th->height - shootz, dist);
+ if (thingtopslope < bottomslope)
+ return true; // shot over the thing
+ thingbottomslope = FixedDiv(th->z - shootz, dist);
+ if (thingbottomslope > topslope)
+ return true; // shot under the thing
+
+//
+// this thing can be hit!
+//
+ if (thingtopslope > topslope)
+ thingtopslope = topslope;
+ if (thingbottomslope < bottomslope)
+ thingbottomslope = bottomslope;
+
+ aimslope = (thingtopslope + thingbottomslope) / 2;
+ linetarget = th;
+
+ return false; // don't go any farther
+}
+
+
+/*
+==============================================================================
+=
+= PTR_ShootTraverse
+=
+==============================================================================
+*/
+
+boolean PTR_ShootTraverse(intercept_t * in)
+{
+ fixed_t x, y, z;
+ fixed_t frac;
+ line_t *li;
+ mobj_t *th;
+ fixed_t slope;
+ fixed_t dist;
+ fixed_t thingtopslope, thingbottomslope;
+ mobj_t *mo;
+
+ if (in->isaline)
+ {
+ li = in->d.line;
+ if (li->special)
+ P_ShootSpecialLine(shootthing, li);
+ if (!(li->flags & ML_TWOSIDED))
+ goto hitline;
+
+//
+// crosses a two sided line
+//
+ P_LineOpening(li);
+
+ dist = FixedMul(attackrange, in->frac);
+
+ if (li->frontsector->floorheight != li->backsector->floorheight)
+ {
+ slope = FixedDiv(openbottom - shootz, dist);
+ if (slope > aimslope)
+ goto hitline;
+ }
+
+ if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
+ {
+ slope = FixedDiv(opentop - shootz, dist);
+ if (slope < aimslope)
+ goto hitline;
+ }
+
+ return true; // shot continues
+//
+// hit line
+//
+ hitline:
+ // position a bit closer
+ frac = in->frac - FixedDiv(4 * FRACUNIT, attackrange);
+ x = trace.x + FixedMul(trace.dx, frac);
+ y = trace.y + FixedMul(trace.dy, frac);
+ z = shootz + FixedMul(aimslope, FixedMul(frac, attackrange));
+
+ if (li->frontsector->ceilingpic == skyflatnum)
+ {
+ if (z > li->frontsector->ceilingheight)
+ return false; // don't shoot the sky!
+ if (li->backsector && li->backsector->ceilingpic == skyflatnum)
+ return false; // it's a sky hack wall
+ }
+
+ P_SpawnPuff(x, y, z);
+ return false; // don't go any farther
+ }
+
+//
+// shoot a thing
+//
+ th = in->d.thing;
+ if (th == shootthing)
+ return true; // can't shoot self
+ if (!(th->flags & MF_SHOOTABLE))
+ return true; // corpse or something
+
+//
+// check for physical attacks on a ghost
+//
+ if (th->flags & MF_SHADOW && shootthing->player->readyweapon == wp_staff)
+ {
+ return (true);
+ }
+
+// check angles to see if the thing can be aimed at
+ dist = FixedMul(attackrange, in->frac);
+ thingtopslope = FixedDiv(th->z + th->height - shootz, dist);
+ if (thingtopslope < aimslope)
+ return true; // shot over the thing
+ thingbottomslope = FixedDiv(th->z - shootz, dist);
+ if (thingbottomslope > aimslope)
+ return true; // shot under the thing
+
+//
+// hit thing
+//
+ // position a bit closer
+ frac = in->frac - FixedDiv(10 * FRACUNIT, attackrange);
+ x = trace.x + FixedMul(trace.dx, frac);
+ y = trace.y + FixedMul(trace.dy, frac);
+ z = shootz + FixedMul(aimslope, FixedMul(frac, attackrange));
+ if (PuffType == MT_BLASTERPUFF1)
+ { // Make blaster big puff
+ mo = P_SpawnMobj(x, y, z, MT_BLASTERPUFF2);
+ S_StartSound(mo, sfx_blshit);
+ }
+ else
+ {
+ P_SpawnPuff(x, y, z);
+ }
+ if (la_damage)
+ {
+ if (!(in->d.thing->flags & MF_NOBLOOD) && P_Random() < 192)
+ {
+ P_BloodSplatter(x, y, z, in->d.thing);
+ }
+ P_DamageMobj(th, shootthing, shootthing, la_damage);
+ }
+ return (false); // don't go any farther
+}
+
+/*
+=================
+=
+= P_AimLineAttack
+=
+=================
+*/
+
+fixed_t P_AimLineAttack(mobj_t * t1, angle_t angle, fixed_t distance)
+{
+ fixed_t x2, y2;
+
+ angle >>= ANGLETOFINESHIFT;
+ shootthing = t1;
+ x2 = t1->x + (distance >> FRACBITS) * finecosine[angle];
+ y2 = t1->y + (distance >> FRACBITS) * finesine[angle];
+ shootz = t1->z + (t1->height >> 1) + 8 * FRACUNIT;
+ topslope = 100 * FRACUNIT / 160; // can't shoot outside view angles
+ bottomslope = -100 * FRACUNIT / 160;
+ attackrange = distance;
+ linetarget = NULL;
+
+ P_PathTraverse(t1->x, t1->y, x2, y2, PT_ADDLINES | PT_ADDTHINGS,
+ PTR_AimTraverse);
+
+ if (linetarget)
+ return aimslope;
+ return 0;
+}
+
+
+
+/*
+=================
+=
+= P_LineAttack
+=
+= if damage == 0, it is just a test trace that will leave linetarget set
+=
+=================
+*/
+
+void P_LineAttack(mobj_t * t1, angle_t angle, fixed_t distance, fixed_t slope,
+ int damage)
+{
+ fixed_t x2, y2;
+
+ angle >>= ANGLETOFINESHIFT;
+ shootthing = t1;
+ la_damage = damage;
+ x2 = t1->x + (distance >> FRACBITS) * finecosine[angle];
+ y2 = t1->y + (distance >> FRACBITS) * finesine[angle];
+ shootz = t1->z + (t1->height >> 1) + 8 * FRACUNIT;
+ if (t1->flags2 & MF2_FEETARECLIPPED)
+ {
+ shootz -= FOOTCLIPSIZE;
+ }
+ attackrange = distance;
+ aimslope = slope;
+
+ P_PathTraverse(t1->x, t1->y, x2, y2, PT_ADDLINES | PT_ADDTHINGS,
+ PTR_ShootTraverse);
+}
+
+
+
+/*
+==============================================================================
+
+ USE LINES
+
+==============================================================================
+*/
+
+mobj_t *usething;
+
+boolean PTR_UseTraverse(intercept_t * in)
+{
+ if (!in->d.line->special)
+ {
+ P_LineOpening(in->d.line);
+ if (openrange <= 0)
+ {
+ //S_StartSound (usething, sfx_noway);
+ return false; // can't use through a wall
+ }
+ return true; // not a special line, but keep checking
+ }
+
+ if (P_PointOnLineSide(usething->x, usething->y, in->d.line) == 1)
+ return false; // don't use back sides
+
+ P_UseSpecialLine(usething, in->d.line);
+
+ return false; // can't use for than one special line in a row
+}
+
+
+/*
+================
+=
+= P_UseLines
+=
+= Looks for special lines in front of the player to activate
+================
+*/
+
+void P_UseLines(player_t * player)
+{
+ int angle;
+ fixed_t x1, y1, x2, y2;
+
+ usething = player->mo;
+
+ angle = player->mo->angle >> ANGLETOFINESHIFT;
+ x1 = player->mo->x;
+ y1 = player->mo->y;
+ x2 = x1 + (USERANGE >> FRACBITS) * finecosine[angle];
+ y2 = y1 + (USERANGE >> FRACBITS) * finesine[angle];
+
+ P_PathTraverse(x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse);
+}
+
+
+
+/*
+==============================================================================
+
+ RADIUS ATTACK
+
+==============================================================================
+*/
+
+mobj_t *bombsource;
+mobj_t *bombspot;
+int bombdamage;
+
+/*
+=================
+=
+= PIT_RadiusAttack
+=
+= Source is the creature that casued the explosion at spot
+=================
+*/
+
+boolean PIT_RadiusAttack(mobj_t * thing)
+{
+ fixed_t dx, dy, dist;
+
+ if (!(thing->flags & MF_SHOOTABLE))
+ {
+ return true;
+ }
+ if (thing->type == MT_MINOTAUR || thing->type == MT_SORCERER1
+ || thing->type == MT_SORCERER2)
+ { // Episode 2 and 3 bosses take no damage from PIT_RadiusAttack
+ return (true);
+ }
+ dx = abs(thing->x - bombspot->x);
+ dy = abs(thing->y - bombspot->y);
+ dist = dx > dy ? dx : dy;
+ dist = (dist - thing->radius) >> FRACBITS;
+ if (dist < 0)
+ {
+ dist = 0;
+ }
+ if (dist >= bombdamage)
+ { // Out of range
+ return true;
+ }
+ if (P_CheckSight(thing, bombspot))
+ { // OK to damage, target is in direct path
+ P_DamageMobj(thing, bombspot, bombsource, bombdamage - dist);
+ }
+ return (true);
+}
+
+/*
+=================
+=
+= P_RadiusAttack
+=
+= Source is the creature that casued the explosion at spot
+=================
+*/
+
+void P_RadiusAttack(mobj_t * spot, mobj_t * source, int damage)
+{
+ int x, y, xl, xh, yl, yh;
+ fixed_t dist;
+
+ dist = (damage + MAXRADIUS) << FRACBITS;
+ yh = (spot->y + dist - bmaporgy) >> MAPBLOCKSHIFT;
+ yl = (spot->y - dist - bmaporgy) >> MAPBLOCKSHIFT;
+ xh = (spot->x + dist - bmaporgx) >> MAPBLOCKSHIFT;
+ xl = (spot->x - dist - bmaporgx) >> MAPBLOCKSHIFT;
+ bombspot = spot;
+ if (spot->type == MT_POD && spot->target)
+ {
+ bombsource = spot->target;
+ }
+ else
+ {
+ bombsource = source;
+ }
+ bombdamage = damage;
+ for (y = yl; y <= yh; y++)
+ for (x = xl; x <= xh; x++)
+ P_BlockThingsIterator(x, y, PIT_RadiusAttack);
+}
+
+
+/*
+==============================================================================
+
+ SECTOR HEIGHT CHANGING
+
+= After modifying a sectors floor or ceiling height, call this
+= routine to adjust the positions of all things that touch the
+= sector.
+=
+= If anything doesn't fit anymore, true will be returned.
+= If crunch is true, they will take damage as they are being crushed
+= If Crunch is false, you should set the sector height back the way it
+= was and call P_ChangeSector again to undo the changes
+==============================================================================
+*/
+
+boolean crushchange;
+boolean nofit;
+
+/*
+===============
+=
+= PIT_ChangeSector
+=
+===============
+*/
+
+boolean PIT_ChangeSector(mobj_t * thing)
+{
+ mobj_t *mo;
+
+ if (P_ThingHeightClip(thing))
+ return true; // keep checking
+
+ // crunch bodies to giblets
+ if (thing->health <= 0)
+ {
+ //P_SetMobjState (thing, S_GIBS);
+ thing->height = 0;
+ thing->radius = 0;
+ return true; // keep checking
+ }
+
+ // crunch dropped items
+ if (thing->flags & MF_DROPPED)
+ {
+ P_RemoveMobj(thing);
+ return true; // keep checking
+ }
+
+ if (!(thing->flags & MF_SHOOTABLE))
+ return true; // assume it is bloody gibs or something
+
+ nofit = true;
+ if (crushchange && !(leveltime & 3))
+ {
+ P_DamageMobj(thing, NULL, NULL, 10);
+ // spray blood in a random direction
+ mo = P_SpawnMobj(thing->x, thing->y, thing->z + thing->height / 2,
+ MT_BLOOD);
+ mo->momx = (P_Random() - P_Random()) << 12;
+ mo->momy = (P_Random() - P_Random()) << 12;
+ }
+
+ return true; // keep checking (crush other things)
+}
+
+/*
+===============
+=
+= P_ChangeSector
+=
+===============
+*/
+
+boolean P_ChangeSector(sector_t * sector, boolean crunch)
+{
+ int x, y;
+
+ nofit = false;
+ crushchange = crunch;
+
+// recheck heights for all things near the moving sector
+
+ for (x = sector->blockbox[BOXLEFT]; x <= sector->blockbox[BOXRIGHT]; x++)
+ for (y = sector->blockbox[BOXBOTTOM]; y <= sector->blockbox[BOXTOP];
+ y++)
+ P_BlockThingsIterator(x, y, PIT_ChangeSector);
+
+
+ return nofit;
+}
diff --git a/src/heretic/p_maputl.c b/src/heretic/p_maputl.c
new file mode 100644
index 00000000..3d848af2
--- /dev/null
+++ b/src/heretic/p_maputl.c
@@ -0,0 +1,784 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// P_maputl.c
+
+#include <stdlib.h>
+
+#include "doomdef.h"
+#include "m_bbox.h"
+#include "p_local.h"
+
+
+/*
+===================
+=
+= P_AproxDistance
+=
+= Gives an estimation of distance (not exact)
+=
+===================
+*/
+
+fixed_t P_AproxDistance(fixed_t dx, fixed_t dy)
+{
+ dx = abs(dx);
+ dy = 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, dy;
+ fixed_t left, 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 = 0, p2 = 0;
+
+ 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, dy;
+ fixed_t left, 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)
+{
+#if 1
+ fixed_t frac, num, 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;
+#else
+ float frac, num, den, v1x, v1y, v1dx, v1dy, v2x, v2y, v2dx, v2dy;
+
+ v1x = (float) v1->x / FRACUNIT;
+ v1y = (float) v1->y / FRACUNIT;
+ v1dx = (float) v1->dx / FRACUNIT;
+ v1dy = (float) v1->dy / FRACUNIT;
+ v2x = (float) v2->x / FRACUNIT;
+ v2y = (float) v2->y / FRACUNIT;
+ v2dx = (float) v2->dx / FRACUNIT;
+ v2dy = (float) v2->dy / FRACUNIT;
+
+ den = v1dy * v2dx - v1dx * v2dy;
+ if (den == 0)
+ return 0; // parallel
+ num = (v1x - v2x) * v1dy + (v2y - v1y) * v1dx;
+ frac = num / den;
+
+ return frac * FRACUNIT;
+#endif
+}
+
+/*
+==================
+=
+= P_LineOpening
+=
+= Sets opentop and openbottom to the window through a two sided line
+= OPTIMIZE: keep this precalculated
+==================
+*/
+
+fixed_t opentop, openbottom, openrange;
+fixed_t lowfloor;
+
+void P_LineOpening(line_t * linedef)
+{
+ sector_t *front, *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
+=
+===================
+*/
+
+void P_UnsetThingPosition(mobj_t * thing)
+{
+ int blockx, 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, 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 = NULL;
+ 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 = NULL;
+ thing->bnext = *link;
+ if (*link)
+ (*link)->bprev = thing;
+ *link = thing;
+ }
+ else
+ { // thing is off the map
+ thing->bnext = thing->bprev = NULL;
+ }
+ }
+}
+
+
+
+/*
+===============================================================================
+
+ BLOCK MAP ITERATORS
+
+For each line/thing in the given mapblock, call the passed 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
+===================
+*/
+
+boolean P_BlockLinesIterator(int x, int y, 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
+=
+==================
+*/
+
+boolean P_BlockThingsIterator(int x, int y, 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
+
+===============================================================================
+*/
+
+intercept_t intercepts[MAXINTERCEPTS], *intercept_p;
+
+divline_t trace;
+boolean earlyout;
+int ptflags;
+
+/*
+==================
+=
+= 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
+==================
+*/
+
+boolean PIT_AddLineIntercepts(line_t * ld)
+{
+ int s1, 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
+=
+==================
+*/
+
+boolean PIT_AddThingIntercepts(mobj_t * thing)
+{
+ fixed_t x1, y1, x2, y2;
+ int s1, s2;
+ 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
+====================
+*/
+
+boolean P_TraverseIntercepts(traverser_t func, fixed_t maxfrac)
+{
+ int count;
+ fixed_t dist;
+ intercept_t *scan, *in;
+
+ count = intercept_p - intercepts;
+ in = 0; // shut up compiler warning
+
+ while (count--)
+ {
+ dist = INT_MAX;
+ 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
+ { // don't check these yet, ther 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 = INT_MAX;
+ }
+
+ 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
+==================
+*/
+
+boolean P_PathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2,
+ int flags, boolean(*trav) (intercept_t *))
+{
+ fixed_t xt1, yt1, xt2, yt2;
+ fixed_t xstep, ystep;
+ fixed_t partial;
+ fixed_t xintercept, yintercept;
+ int mapx, mapy, mapxstep, 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, abs(x2 - x1));
+ }
+ else if (xt2 < xt1)
+ {
+ mapxstep = -1;
+ partial = (x1 >> MAPBTOFRAC) & (FRACUNIT - 1);
+ ystep = FixedDiv(y2 - y1, 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, abs(y2 - y1));
+ }
+ else if (yt2 < yt1)
+ {
+ mapystep = -1;
+ partial = (y1 >> MAPBTOFRAC) & (FRACUNIT - 1);
+ xstep = FixedDiv(x2 - x1, 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);
+}
diff --git a/src/heretic/p_mobj.c b/src/heretic/p_mobj.c
new file mode 100644
index 00000000..59681f86
--- /dev/null
+++ b/src/heretic/p_mobj.c
@@ -0,0 +1,1633 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// P_mobj.c
+
+#include "doomdef.h"
+#include "i_system.h"
+#include "m_random.h"
+#include "p_local.h"
+#include "sounds.h"
+#include "s_sound.h"
+
+void G_PlayerReborn(int player);
+void P_SpawnMapThing(mapthing_t * mthing);
+
+mobjtype_t PuffType;
+mobj_t *MissileMobj;
+
+static fixed_t FloatBobOffsets[64] = {
+ 0, 51389, 102283, 152192,
+ 200636, 247147, 291278, 332604,
+ 370727, 405280, 435929, 462380,
+ 484378, 501712, 514213, 521763,
+ 524287, 521763, 514213, 501712,
+ 484378, 462380, 435929, 405280,
+ 370727, 332604, 291278, 247147,
+ 200636, 152192, 102283, 51389,
+ -1, -51390, -102284, -152193,
+ -200637, -247148, -291279, -332605,
+ -370728, -405281, -435930, -462381,
+ -484380, -501713, -514215, -521764,
+ -524288, -521764, -514214, -501713,
+ -484379, -462381, -435930, -405280,
+ -370728, -332605, -291279, -247148,
+ -200637, -152193, -102284, -51389
+};
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_SetMobjState
+//
+// Returns true if the mobj is still present.
+//
+//----------------------------------------------------------------------------
+
+boolean P_SetMobjState(mobj_t * mobj, statenum_t state)
+{
+ state_t *st;
+
+ if (state == S_NULL)
+ { // Remove mobj
+ 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;
+ if (st->action)
+ { // Call action function
+ st->action(mobj);
+ }
+ return (true);
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_SetMobjStateNF
+//
+// Same as P_SetMobjState, but does not call the state function.
+//
+//----------------------------------------------------------------------------
+
+boolean P_SetMobjStateNF(mobj_t * mobj, statenum_t state)
+{
+ state_t *st;
+
+ if (state == S_NULL)
+ { // Remove mobj
+ 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;
+ return (true);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_ExplodeMissile
+//
+//----------------------------------------------------------------------------
+
+void P_ExplodeMissile(mobj_t * mo)
+{
+ if (mo->type == MT_WHIRLWIND)
+ {
+ if (++mo->special2.i < 60)
+ {
+ return;
+ }
+ }
+ mo->momx = mo->momy = mo->momz = 0;
+ P_SetMobjState(mo, mobjinfo[mo->type].deathstate);
+ //mo->tics -= P_Random()&3;
+ mo->flags &= ~MF_MISSILE;
+ if (mo->info->deathsound)
+ {
+ S_StartSound(mo, mo->info->deathsound);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_FloorBounceMissile
+//
+//----------------------------------------------------------------------------
+
+void P_FloorBounceMissile(mobj_t * mo)
+{
+ mo->momz = -mo->momz;
+ P_SetMobjState(mo, mobjinfo[mo->type].deathstate);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_ThrustMobj
+//
+//----------------------------------------------------------------------------
+
+void P_ThrustMobj(mobj_t * mo, angle_t angle, fixed_t move)
+{
+ angle >>= ANGLETOFINESHIFT;
+ mo->momx += FixedMul(move, finecosine[angle]);
+ mo->momy += FixedMul(move, finesine[angle]);
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_FaceMobj
+//
+// Returns 1 if 'source' needs to turn clockwise, or 0 if 'source' needs
+// to turn counter clockwise. 'delta' is set to the amount 'source'
+// needs to turn.
+//
+//----------------------------------------------------------------------------
+
+int P_FaceMobj(mobj_t * source, mobj_t * target, angle_t * delta)
+{
+ angle_t diff;
+ angle_t angle1;
+ angle_t angle2;
+
+ angle1 = source->angle;
+ angle2 = R_PointToAngle2(source->x, source->y, target->x, target->y);
+ if (angle2 > angle1)
+ {
+ diff = angle2 - angle1;
+ if (diff > ANG180)
+ {
+ *delta = ANG_MAX - diff;
+ return (0);
+ }
+ else
+ {
+ *delta = diff;
+ return (1);
+ }
+ }
+ else
+ {
+ diff = angle1 - angle2;
+ if (diff > ANG180)
+ {
+ *delta = ANG_MAX - diff;
+ return (1);
+ }
+ else
+ {
+ *delta = diff;
+ return (0);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_SeekerMissile
+//
+// The missile special1 field must be mobj_t *target. Returns true if
+// target was tracked, false if not.
+//
+//----------------------------------------------------------------------------
+
+boolean P_SeekerMissile(mobj_t * actor, angle_t thresh, angle_t turnMax)
+{
+ int dir;
+ int dist;
+ angle_t delta;
+ angle_t angle;
+ mobj_t *target;
+
+ target = (mobj_t *) actor->special1.m;
+ if (target == NULL)
+ {
+ return (false);
+ }
+ if (!(target->flags & MF_SHOOTABLE))
+ { // Target died
+ actor->special1.m = NULL;
+ return (false);
+ }
+ dir = P_FaceMobj(actor, target, &delta);
+ if (delta > thresh)
+ {
+ delta >>= 1;
+ if (delta > turnMax)
+ {
+ delta = turnMax;
+ }
+ }
+ if (dir)
+ { // Turn clockwise
+ actor->angle += delta;
+ }
+ else
+ { // Turn counter clockwise
+ actor->angle -= delta;
+ }
+ angle = actor->angle >> ANGLETOFINESHIFT;
+ actor->momx = FixedMul(actor->info->speed, finecosine[angle]);
+ actor->momy = FixedMul(actor->info->speed, finesine[angle]);
+ if (actor->z + actor->height < target->z ||
+ target->z + target->height < actor->z)
+ { // Need to seek vertically
+ dist = P_AproxDistance(target->x - actor->x, target->y - actor->y);
+ dist = dist / actor->info->speed;
+ if (dist < 1)
+ {
+ dist = 1;
+ }
+ actor->momz = (target->z - actor->z) / dist;
+ }
+ return (true);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_XYMovement
+//
+//----------------------------------------------------------------------------
+
+#define STOPSPEED 0x1000
+#define FRICTION_NORMAL 0xe800
+#define FRICTION_LOW 0xf900
+#define FRICTION_FLY 0xeb00
+
+void P_XYMovement(mobj_t * mo)
+{
+ fixed_t ptryx, ptryy;
+ player_t *player;
+ fixed_t xmove, ymove;
+ int special;
+ static int windTab[3] = { 2048 * 5, 2048 * 10, 2048 * 25 };
+
+ if (!mo->momx && !mo->momy)
+ {
+ if (mo->flags & MF_SKULLFLY)
+ { // A flying mobj slammed into something
+ mo->flags &= ~MF_SKULLFLY;
+ mo->momx = mo->momy = mo->momz = 0;
+ P_SetMobjState(mo, mo->info->seestate);
+ }
+ return;
+ }
+ special = mo->subsector->sector->special;
+ if (mo->flags2 & MF2_WINDTHRUST)
+ {
+ switch (special)
+ {
+ case 40:
+ case 41:
+ case 42: // Wind_East
+ P_ThrustMobj(mo, 0, windTab[special - 40]);
+ break;
+ case 43:
+ case 44:
+ case 45: // Wind_North
+ P_ThrustMobj(mo, ANG90, windTab[special - 43]);
+ break;
+ case 46:
+ case 47:
+ case 48: // Wind_South
+ P_ThrustMobj(mo, ANG270, windTab[special - 46]);
+ break;
+ case 49:
+ case 50:
+ case 51: // Wind_West
+ P_ThrustMobj(mo, ANG180, windTab[special - 49]);
+ break;
+ }
+ }
+ 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->flags2 & MF2_SLIDE)
+ { // 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
+ if (mo->type == MT_BLOODYSKULL)
+ {
+ mo->momx = mo->momy = 0;
+ mo->momz = -FRACUNIT;
+ }
+ else
+ {
+ P_RemoveMobj(mo);
+ }
+ return;
+ }
+ P_ExplodeMissile(mo);
+ }
+ //else if(mo->info->crashstate)
+ //{
+ // mo->momx = mo->momy = 0;
+ // P_SetMobjState(mo, mo->info->crashstate);
+ // return;
+ //}
+ else
+ {
+ mo->momx = mo->momy = 0;
+ }
+ }
+ }
+ while (xmove || ymove);
+
+ // Friction
+
+ 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))
+ { // No friction for missiles
+ return;
+ }
+ if (mo->z > mo->floorz && !(mo->flags2 & MF2_FLY)
+ && !(mo->flags2 & MF2_ONMOBJ))
+ { // No friction when falling
+ return;
+ }
+ if (mo->flags & MF_CORPSE)
+ { // Don't 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)
+ {
+ if (player->chickenTics)
+ {
+ if ((unsigned) ((player->mo->state - states)
+ - S_CHICPLAY_RUN1) < 4)
+ {
+ P_SetMobjState(player->mo, S_CHICPLAY);
+ }
+ }
+ else
+ {
+ if ((unsigned) ((player->mo->state - states)
+ - S_PLAY_RUN1) < 4)
+ {
+ P_SetMobjState(player->mo, S_PLAY);
+ }
+ }
+ }
+ mo->momx = 0;
+ mo->momy = 0;
+ }
+ else
+ {
+ if (mo->flags2 & MF2_FLY && !(mo->z <= mo->floorz)
+ && !(mo->flags2 & MF2_ONMOBJ))
+ {
+ mo->momx = FixedMul(mo->momx, FRICTION_FLY);
+ mo->momy = FixedMul(mo->momy, FRICTION_FLY);
+ }
+ else if (special == 15) // Friction_Low
+ {
+ mo->momx = FixedMul(mo->momx, FRICTION_LOW);
+ mo->momy = FixedMul(mo->momy, FRICTION_LOW);
+ }
+ else
+ {
+ mo->momx = FixedMul(mo->momx, FRICTION_NORMAL);
+ mo->momy = FixedMul(mo->momy, FRICTION_NORMAL);
+ }
+ }
+}
+
+
+/*
+===============
+=
+= P_ZMovement
+=
+===============
+*/
+
+void P_ZMovement(mobj_t * mo)
+{
+ int dist;
+ int 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;
+ }
+ }
+ if (mo->player && mo->flags2 & MF2_FLY && !(mo->z <= mo->floorz)
+ && leveltime & 2)
+ {
+ mo->z += finesine[(FINEANGLES / 20 * leveltime >> 2) & FINEMASK];
+ }
+
+//
+// clip movement
+//
+ if (mo->z <= mo->floorz)
+ { // Hit the floor
+ if (mo->flags & MF_MISSILE)
+ {
+ mo->z = mo->floorz;
+ if (mo->flags2 & MF2_FLOORBOUNCE)
+ {
+ P_FloorBounceMissile(mo);
+ return;
+ }
+ else if (mo->type == MT_MNTRFX2)
+ { // Minotaur floor fire can go up steps
+ return;
+ }
+ else
+ {
+ P_ExplodeMissile(mo);
+ return;
+ }
+ }
+ if (mo->z - mo->momz > mo->floorz)
+ { // Spawn splashes, etc.
+ P_HitFloor(mo);
+ }
+ mo->z = mo->floorz;
+ if (mo->momz < 0)
+ {
+ if (mo->player && mo->momz < -GRAVITY * 8 && !(mo->flags2 & MF2_FLY)) // squat down
+ {
+ mo->player->deltaviewheight = mo->momz >> 3;
+ S_StartSound(mo, sfx_plroof);
+ // haleyjd: removed externdriver crap
+ mo->player->centering = true;
+ }
+ mo->momz = 0;
+ }
+ if (mo->flags & MF_SKULLFLY)
+ { // The skull slammed into something
+ mo->momz = -mo->momz;
+ }
+ if (mo->info->crashstate && (mo->flags & MF_CORPSE))
+ {
+ P_SetMobjState(mo, mo->info->crashstate);
+ return;
+ }
+ }
+ else if (mo->flags2 & MF2_LOGRAV)
+ {
+ if (mo->momz == 0)
+ mo->momz = -(GRAVITY >> 3) * 2;
+ else
+ mo->momz -= GRAVITY >> 3;
+ }
+ 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)
+ {
+ if (mo->subsector->sector->ceilingpic == skyflatnum)
+ {
+ if (mo->type == MT_BLOODYSKULL)
+ {
+ mo->momx = mo->momy = 0;
+ mo->momz = -FRACUNIT;
+ }
+ else
+ {
+ P_RemoveMobj(mo);
+ }
+ return;
+ }
+ P_ExplodeMissile(mo);
+ return;
+ }
+ }
+}
+
+
+/*
+================
+=
+= P_NightmareRespawn
+=
+================
+*/
+
+void P_NightmareRespawn(mobj_t * mobj)
+{
+ fixed_t x, y, z;
+ subsector_t *ss;
+ mobj_t *mo;
+ mapthing_t *mthing;
+
+ x = mobj->spawnpoint.x << FRACBITS;
+ y = mobj->spawnpoint.y << FRACBITS;
+
+ if (!P_CheckPosition(mobj, x, y))
+ return; // somthing is occupying it's position
+
+
+// spawn a teleport fog at old spot
+
+ mo = P_SpawnMobj(mobj->x, mobj->y,
+ mobj->subsector->sector->floorheight + TELEFOGHEIGHT,
+ MT_TFOG);
+ 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 + TELEFOGHEIGHT, 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;
+ 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);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_BlasterMobjThinker
+//
+// Thinker for the ultra-fast blaster PL2 ripper-spawning missile.
+//
+//----------------------------------------------------------------------------
+
+void P_BlasterMobjThinker(mobj_t * mobj)
+{
+ int i;
+ fixed_t xfrac;
+ fixed_t yfrac;
+ fixed_t zfrac;
+ fixed_t z;
+ boolean changexy;
+
+ // Handle movement
+ if (mobj->momx || mobj->momy || (mobj->z != mobj->floorz) || mobj->momz)
+ {
+ xfrac = mobj->momx >> 3;
+ yfrac = mobj->momy >> 3;
+ zfrac = mobj->momz >> 3;
+ changexy = xfrac || yfrac;
+ for (i = 0; i < 8; i++)
+ {
+ if (changexy)
+ {
+ if (!P_TryMove(mobj, mobj->x + xfrac, mobj->y + yfrac))
+ { // Blocked move
+ P_ExplodeMissile(mobj);
+ return;
+ }
+ }
+ mobj->z += zfrac;
+ if (mobj->z <= mobj->floorz)
+ { // Hit the floor
+ mobj->z = mobj->floorz;
+ P_HitFloor(mobj);
+ P_ExplodeMissile(mobj);
+ return;
+ }
+ if (mobj->z + mobj->height > mobj->ceilingz)
+ { // Hit the ceiling
+ mobj->z = mobj->ceilingz - mobj->height;
+ P_ExplodeMissile(mobj);
+ return;
+ }
+ if (changexy && (P_Random() < 64))
+ {
+ z = mobj->z - 8 * FRACUNIT;
+ if (z < mobj->floorz)
+ {
+ z = mobj->floorz;
+ }
+ P_SpawnMobj(mobj->x, mobj->y, z, MT_BLASTERSMOKE);
+ }
+ }
+ }
+ // Advance the state
+ if (mobj->tics != -1)
+ {
+ mobj->tics--;
+ while (!mobj->tics)
+ {
+ if (!P_SetMobjState(mobj, mobj->state->nextstate))
+ { // mobj was removed
+ return;
+ }
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_MobjThinker
+//
+//----------------------------------------------------------------------------
+
+void P_MobjThinker(mobj_t * mobj)
+{
+ mobj_t *onmo;
+
+ // Handle X and Y momentums
+ if (mobj->momx || mobj->momy || (mobj->flags & MF_SKULLFLY))
+ {
+ P_XYMovement(mobj);
+ if (mobj->thinker.function == (think_t) - 1)
+ { // mobj was removed
+ return;
+ }
+ }
+ if (mobj->flags2 & MF2_FLOATBOB)
+ { // Floating item bobbing motion
+ mobj->z = mobj->floorz + FloatBobOffsets[(mobj->health++) & 63];
+ }
+ else if ((mobj->z != mobj->floorz) || mobj->momz)
+ { // Handle Z momentum and gravity
+ if (mobj->flags2 & MF2_PASSMOBJ)
+ {
+ if (!(onmo = P_CheckOnmobj(mobj)))
+ {
+ P_ZMovement(mobj);
+ }
+ else
+ {
+ if (mobj->player && mobj->momz < 0)
+ {
+ mobj->flags2 |= MF2_ONMOBJ;
+ mobj->momz = 0;
+ }
+ if (mobj->player && (onmo->player || onmo->type == MT_POD))
+ {
+ mobj->momx = onmo->momx;
+ mobj->momy = onmo->momy;
+ if (onmo->z < onmo->floorz)
+ {
+ mobj->z += onmo->floorz - onmo->z;
+ if (onmo->player)
+ {
+ onmo->player->viewheight -=
+ onmo->floorz - onmo->z;
+ onmo->player->deltaviewheight =
+ (VIEWHEIGHT - onmo->player->viewheight) >> 3;
+ }
+ onmo->z = onmo->floorz;
+ }
+ }
+ }
+ }
+ else
+ {
+ P_ZMovement(mobj);
+ }
+ if (mobj->thinker.function == (think_t) - 1)
+ { // mobj was removed
+ return;
+ }
+ }
+
+//
+// cycle through states, calling action functions at transitions
+//
+ if (mobj->tics != -1)
+ {
+ mobj->tics--;
+ // you can cycle through multiple states in a tic
+ while (!mobj->tics)
+ {
+ if (!P_SetMobjState(mobj, mobj->state->nextstate))
+ { // mobj was removed
+ return;
+ }
+ }
+ }
+ else
+ { // Check for monster 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;
+ fixed_t space;
+
+ mobj = Z_Malloc(sizeof(*mobj), PU_LEVEL, NULL);
+ 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->flags2 = info->flags2;
+ mobj->damage = info->damage;
+ mobj->health = info->spawnhealth;
+ if (gameskill != sk_nightmare)
+ {
+ mobj->reactiontime = info->reactiontime;
+ }
+ mobj->lastlook = P_Random() % MAXPLAYERS;
+
+ // Set the state, but do not use P_SetMobjState, because action
+ // routines can't be called yet. If the spawnstate has an action
+ // routine, it will not be called.
+ 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 if (z == FLOATRANDZ)
+ {
+ space = ((mobj->ceilingz) - (mobj->info->height)) - mobj->floorz;
+ if (space > 48 * FRACUNIT)
+ {
+ space -= 40 * FRACUNIT;
+ mobj->z =
+ ((space * P_Random()) >> 8) + mobj->floorz + 40 * FRACUNIT;
+ }
+ else
+ {
+ mobj->z = mobj->floorz;
+ }
+ }
+ else
+ {
+ mobj->z = z;
+ }
+ if (mobj->flags2 & MF2_FOOTCLIP
+ && P_GetThingFloorType(mobj) != FLOOR_SOLID
+ && mobj->floorz == mobj->subsector->sector->floorheight)
+ {
+ mobj->flags2 |= MF2_FEETARECLIPPED;
+ }
+ else
+ {
+ mobj->flags2 &= ~MF2_FEETARECLIPPED;
+ }
+
+ mobj->thinker.function = P_MobjThinker;
+ P_AddThinker(&mobj->thinker);
+ return (mobj);
+}
+
+/*
+===============
+=
+= P_RemoveMobj
+=
+===============
+*/
+
+void P_RemoveMobj(mobj_t * mobj)
+{
+// unlink from sector and block lists
+ P_UnsetThingPosition(mobj);
+// stop any playing sound
+ S_StopSound(mobj);
+// free block
+ P_RemoveThinker((thinker_t *) mobj);
+}
+
+//=============================================================================
+
+
+/*
+============
+=
+= 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, y, z;
+ mobj_t *mobj;
+ int i;
+ extern int playerkeys;
+
+ if (!playeringame[mthing->type - 1])
+ return; // not playing
+
+ 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);
+ if (mthing->type > 1) // set color translations for player sprites
+ 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 = NULL;
+ p->damagecount = 0;
+ p->bonuscount = 0;
+ p->chickenTics = 0;
+ p->rain1 = NULL;
+ p->rain2 = NULL;
+ p->extralight = 0;
+ p->fixedcolormap = 0;
+ p->viewheight = VIEWHEIGHT;
+ P_SetupPsprites(p); // setup gun psprite
+ if (deathmatch)
+ { // Give all keys in death match mode
+ for (i = 0; i < NUMKEYS; i++)
+ {
+ p->keys[i] = true;
+ if (p == &players[consoleplayer])
+ {
+ playerkeys = 7;
+ UpdateState |= I_STATBAR;
+ }
+ }
+ }
+ else if (p == &players[consoleplayer])
+ {
+ playerkeys = 0;
+ UpdateState |= I_STATBAR;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC 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, y, z;
+
+// count deathmatch start positions
+ if (mthing->type == 11)
+ {
+ if (deathmatch_p < &deathmatchstarts[10])
+ {
+ 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;
+ }
+
+ // Ambient sound sequences
+ if (mthing->type >= 1200 && mthing->type < 1300)
+ {
+ P_AddAmbientSfx(mthing->type - 1200);
+ return;
+ }
+
+ // Check for boss spots
+ if (mthing->type == 56) // Monster_BossSpot
+ {
+ P_AddBossSpot(mthing->x << FRACBITS, mthing->y << FRACBITS,
+ ANG45 * (mthing->angle / 45));
+ 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("P_SpawnMapThing: Unknown type %i at (%i, %i)", mthing->type,
+ mthing->x, mthing->y);
+
+// don't spawn keys and players in deathmatch
+ if (deathmatch && mobjinfo[i].flags & MF_NOTDMATCH)
+ return;
+
+// don't spawn any monsters if -nomonsters
+ if (nomonsters && (mobjinfo[i].flags & MF_COUNTKILL))
+ return;
+
+// spawn it
+ switch (i)
+ { // Special stuff
+ case MT_WSKULLROD:
+ case MT_WPHOENIXROD:
+ case MT_AMSKRDWIMPY:
+ case MT_AMSKRDHEFTY:
+ case MT_AMPHRDWIMPY:
+ case MT_AMPHRDHEFTY:
+ case MT_AMMACEWIMPY:
+ case MT_AMMACEHEFTY:
+ case MT_ARTISUPERHEAL:
+ case MT_ARTITELEPORT:
+ case MT_ITEMSHIELD2:
+ if (gamemode == shareware)
+ { // Don't place on map in shareware version
+ return;
+ }
+ break;
+ case MT_WMACE:
+ if (gamemode != shareware)
+ { // Put in the mace spot list
+ P_AddMaceSpot(mthing);
+ return;
+ }
+ return;
+ default:
+ break;
+ }
+ x = mthing->x << FRACBITS;
+ y = mthing->y << FRACBITS;
+ if (mobjinfo[i].flags & MF_SPAWNCEILING)
+ {
+ z = ONCEILINGZ;
+ }
+ else if (mobjinfo[i].flags2 & MF2_SPAWNFLOAT)
+ {
+ z = FLOATRANDZ;
+ }
+ else
+ {
+ z = ONFLOORZ;
+ }
+ mobj = P_SpawnMobj(x, y, z, i);
+ if (mobj->flags2 & MF2_FLOATBOB)
+ { // Seed random starting index for bobbing motion
+ mobj->health = P_Random();
+ }
+ if (mobj->tics > 0)
+ {
+ mobj->tics = 1 + (P_Random() % mobj->tics);
+ }
+ if (mobj->flags & MF_COUNTKILL)
+ {
+ totalkills++;
+ mobj->spawnpoint = *mthing;
+ }
+ if (mobj->flags & MF_COUNTITEM)
+ {
+ totalitems++;
+ }
+ mobj->angle = ANG45 * (mthing->angle / 45);
+ if (mthing->options & MTF_AMBUSH)
+ {
+ mobj->flags |= MF_AMBUSH;
+ }
+}
+
+/*
+===============================================================================
+
+ GAME SPAWN FUNCTIONS
+
+===============================================================================
+*/
+
+//---------------------------------------------------------------------------
+//
+// PROC P_SpawnPuff
+//
+//---------------------------------------------------------------------------
+
+extern fixed_t attackrange;
+
+void P_SpawnPuff(fixed_t x, fixed_t y, fixed_t z)
+{
+ mobj_t *puff;
+
+ z += ((P_Random() - P_Random()) << 10);
+ puff = P_SpawnMobj(x, y, z, PuffType);
+ if (puff->info->attacksound)
+ {
+ S_StartSound(puff, puff->info->attacksound);
+ }
+ switch (PuffType)
+ {
+ case MT_BEAKPUFF:
+ case MT_STAFFPUFF:
+ puff->momz = FRACUNIT;
+ break;
+ case MT_GAUNTLETPUFF1:
+ case MT_GAUNTLETPUFF2:
+ puff->momz = (fixed_t)(.8 * FRACUNIT);
+ default:
+ break;
+ }
+}
+
+/*
+================
+=
+= 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 (damage <= 12 && damage >= 9)
+ P_SetMobjState (th,S_BLOOD2);
+ else if (damage < 9)
+ P_SetMobjState (th,S_BLOOD3);
+}
+*/
+
+//---------------------------------------------------------------------------
+//
+// PROC P_BloodSplatter
+//
+//---------------------------------------------------------------------------
+
+void P_BloodSplatter(fixed_t x, fixed_t y, fixed_t z, mobj_t * originator)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(x, y, z, MT_BLOODSPLATTER);
+ mo->target = originator;
+ mo->momx = (P_Random() - P_Random()) << 9;
+ mo->momy = (P_Random() - P_Random()) << 9;
+ mo->momz = FRACUNIT * 2;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_RipperBlood
+//
+//---------------------------------------------------------------------------
+
+void P_RipperBlood(mobj_t * mo)
+{
+ mobj_t *th;
+ fixed_t x, y, z;
+
+ x = mo->x + ((P_Random() - P_Random()) << 12);
+ y = mo->y + ((P_Random() - P_Random()) << 12);
+ z = mo->z + ((P_Random() - P_Random()) << 12);
+ th = P_SpawnMobj(x, y, z, MT_BLOOD);
+ th->flags |= MF_NOGRAVITY;
+ th->momx = mo->momx >> 1;
+ th->momy = mo->momy >> 1;
+ th->tics += P_Random() & 3;
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_GetThingFloorType
+//
+//---------------------------------------------------------------------------
+
+int P_GetThingFloorType(mobj_t * thing)
+{
+ return (TerrainTypes[thing->subsector->sector->floorpic]);
+/*
+ if(thing->subsector->sector->floorpic
+ == W_GetNumForName("FLTWAWA1")-firstflat)
+ {
+ return(FLOOR_WATER);
+ }
+ else
+ {
+ return(FLOOR_SOLID);
+ }
+*/
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_HitFloor
+//
+//---------------------------------------------------------------------------
+
+int P_HitFloor(mobj_t * thing)
+{
+ mobj_t *mo;
+
+ if (thing->floorz != thing->subsector->sector->floorheight)
+ { // don't splash if landing on the edge above water/lava/etc....
+ return (FLOOR_SOLID);
+ }
+ switch (P_GetThingFloorType(thing))
+ {
+ case FLOOR_WATER:
+ P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SPLASHBASE);
+ mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SPLASH);
+ mo->target = thing;
+ mo->momx = (P_Random() - P_Random()) << 8;
+ mo->momy = (P_Random() - P_Random()) << 8;
+ mo->momz = 2 * FRACUNIT + (P_Random() << 8);
+ S_StartSound(mo, sfx_gloop);
+ return (FLOOR_WATER);
+ case FLOOR_LAVA:
+ P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_LAVASPLASH);
+ mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_LAVASMOKE);
+ mo->momz = FRACUNIT + (P_Random() << 7);
+ S_StartSound(mo, sfx_burn);
+ return (FLOOR_LAVA);
+ case FLOOR_SLUDGE:
+ P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SLUDGESPLASH);
+ mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SLUDGECHUNK);
+ mo->target = thing;
+ mo->momx = (P_Random() - P_Random()) << 8;
+ mo->momy = (P_Random() - P_Random()) << 8;
+ mo->momz = FRACUNIT + (P_Random() << 8);
+ return (FLOOR_SLUDGE);
+ }
+ return (FLOOR_SOLID);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_CheckMissileSpawn
+//
+// Returns true if the missile is at a valid spawn point, otherwise
+// explodes it and returns false.
+//
+//---------------------------------------------------------------------------
+
+boolean P_CheckMissileSpawn(mobj_t * missile)
+{
+ //missile->tics -= P_Random()&3;
+
+ // move a little forward so an angle can be computed if it
+ // immediately explodes
+ missile->x += (missile->momx >> 1);
+ missile->y += (missile->momy >> 1);
+ missile->z += (missile->momz >> 1);
+ if (!P_TryMove(missile, missile->x, missile->y))
+ {
+ P_ExplodeMissile(missile);
+ return (false);
+ }
+ return (true);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_SpawnMissile
+//
+// Returns NULL if the missile exploded immediately, otherwise returns
+// a mobj_t pointer to the missile.
+//
+//---------------------------------------------------------------------------
+
+mobj_t *P_SpawnMissile(mobj_t * source, mobj_t * dest, mobjtype_t type)
+{
+ fixed_t z;
+ mobj_t *th;
+ angle_t an;
+ int dist;
+
+ switch (type)
+ {
+ case MT_MNTRFX1: // Minotaur swing attack missile
+ z = source->z + 40 * FRACUNIT;
+ break;
+ case MT_MNTRFX2: // Minotaur floor fire missile
+ z = ONFLOORZ;
+ break;
+ case MT_SRCRFX1: // Sorcerer Demon fireball
+ z = source->z + 48 * FRACUNIT;
+ break;
+ case MT_KNIGHTAXE: // Knight normal axe
+ case MT_REDAXE: // Knight red power axe
+ z = source->z + 36 * FRACUNIT;
+ break;
+ default:
+ z = source->z + 32 * FRACUNIT;
+ break;
+ }
+ if (source->flags2 & MF2_FEETARECLIPPED)
+ {
+ z -= FOOTCLIPSIZE;
+ }
+ th = P_SpawnMobj(source->x, source->y, z, type);
+ if (th->info->seesound)
+ {
+ S_StartSound(th, th->info->seesound);
+ }
+ th->target = source; // Originator
+ an = R_PointToAngle2(source->x, source->y, dest->x, dest->y);
+ if (dest->flags & MF_SHADOW)
+ { // Invisible target
+ an += (P_Random() - P_Random()) << 21;
+ }
+ 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;
+ return (P_CheckMissileSpawn(th) ? th : NULL);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_SpawnMissileAngle
+//
+// Returns NULL if the missile exploded immediately, otherwise returns
+// a mobj_t pointer to the missile.
+//
+//---------------------------------------------------------------------------
+
+mobj_t *P_SpawnMissileAngle(mobj_t * source, mobjtype_t type,
+ angle_t angle, fixed_t momz)
+{
+ fixed_t z;
+ mobj_t *mo;
+
+ switch (type)
+ {
+ case MT_MNTRFX1: // Minotaur swing attack missile
+ z = source->z + 40 * FRACUNIT;
+ break;
+ case MT_MNTRFX2: // Minotaur floor fire missile
+ z = ONFLOORZ;
+ break;
+ case MT_SRCRFX1: // Sorcerer Demon fireball
+ z = source->z + 48 * FRACUNIT;
+ break;
+ default:
+ z = source->z + 32 * FRACUNIT;
+ break;
+ }
+ if (source->flags2 & MF2_FEETARECLIPPED)
+ {
+ z -= FOOTCLIPSIZE;
+ }
+ mo = P_SpawnMobj(source->x, source->y, z, type);
+ if (mo->info->seesound)
+ {
+ S_StartSound(mo, mo->info->seesound);
+ }
+ mo->target = source; // Originator
+ mo->angle = angle;
+ angle >>= ANGLETOFINESHIFT;
+ mo->momx = FixedMul(mo->info->speed, finecosine[angle]);
+ mo->momy = FixedMul(mo->info->speed, finesine[angle]);
+ mo->momz = momz;
+ return (P_CheckMissileSpawn(mo) ? mo : NULL);
+}
+
+/*
+================
+=
+= P_SpawnPlayerMissile
+=
+= Tries to aim at a nearby monster
+================
+*/
+
+mobj_t *P_SpawnPlayerMissile(mobj_t * source, mobjtype_t type)
+{
+ angle_t an;
+ fixed_t x, y, z, slope;
+
+ // Try to find a target
+ 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 = ((source->player->lookdir) << FRACBITS) / 173;
+ }
+ }
+ x = source->x;
+ y = source->y;
+ z = source->z + 4 * 8 * FRACUNIT +
+ ((source->player->lookdir) << FRACBITS) / 173;
+ if (source->flags2 & MF2_FEETARECLIPPED)
+ {
+ z -= FOOTCLIPSIZE;
+ }
+ MissileMobj = P_SpawnMobj(x, y, z, type);
+ if (MissileMobj->info->seesound)
+ {
+ S_StartSound(MissileMobj, MissileMobj->info->seesound);
+ }
+ MissileMobj->target = source;
+ MissileMobj->angle = an;
+ MissileMobj->momx = FixedMul(MissileMobj->info->speed,
+ finecosine[an >> ANGLETOFINESHIFT]);
+ MissileMobj->momy = FixedMul(MissileMobj->info->speed,
+ finesine[an >> ANGLETOFINESHIFT]);
+ MissileMobj->momz = FixedMul(MissileMobj->info->speed, slope);
+ if (MissileMobj->type == MT_BLASTERFX1)
+ { // Ultra-fast ripper spawning missile
+ MissileMobj->x += (MissileMobj->momx >> 3);
+ MissileMobj->y += (MissileMobj->momy >> 3);
+ MissileMobj->z += (MissileMobj->momz >> 3);
+ }
+ else
+ { // Normal missile
+ MissileMobj->x += (MissileMobj->momx >> 1);
+ MissileMobj->y += (MissileMobj->momy >> 1);
+ MissileMobj->z += (MissileMobj->momz >> 1);
+ }
+ if (!P_TryMove(MissileMobj, MissileMobj->x, MissileMobj->y))
+ { // Exploded immediately
+ P_ExplodeMissile(MissileMobj);
+ return (NULL);
+ }
+ return (MissileMobj);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_SPMAngle
+//
+//---------------------------------------------------------------------------
+
+mobj_t *P_SPMAngle(mobj_t * source, mobjtype_t type, angle_t angle)
+{
+ mobj_t *th;
+ angle_t an;
+ fixed_t x, y, z, slope;
+
+//
+// see which target is to be aimed at
+//
+ an = 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 = angle;
+ slope = ((source->player->lookdir) << FRACBITS) / 173;
+ }
+ }
+ x = source->x;
+ y = source->y;
+ z = source->z + 4 * 8 * FRACUNIT +
+ ((source->player->lookdir) << FRACBITS) / 173;
+ if (source->flags2 & MF2_FEETARECLIPPED)
+ {
+ z -= FOOTCLIPSIZE;
+ }
+ 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);
+ return (P_CheckMissileSpawn(th) ? th : NULL);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_ContMobjSound
+//
+//---------------------------------------------------------------------------
+
+void A_ContMobjSound(mobj_t * actor)
+{
+ switch (actor->type)
+ {
+ case MT_KNIGHTAXE:
+ S_StartSound(actor, sfx_kgtatk);
+ break;
+ case MT_MUMMYFX1:
+ S_StartSound(actor, sfx_mumhed);
+ break;
+ default:
+ break;
+ }
+}
diff --git a/src/heretic/p_plats.c b/src/heretic/p_plats.c
new file mode 100644
index 00000000..23aa99d9
--- /dev/null
+++ b/src/heretic/p_plats.c
@@ -0,0 +1,266 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// P_plats.c
+
+#include "doomdef.h"
+#include "i_system.h"
+#include "m_random.h"
+#include "p_local.h"
+#include "s_sound.h"
+#include "v_video.h"
+
+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 (!(leveltime & 31))
+ {
+ S_StartSound(&plat->sector->soundorg, sfx_stnmov);
+ }
+ if (plat->type == raiseAndChange
+ || plat->type == raiseToNearestAndChange)
+ {
+ if (!(leveltime & 7))
+ {
+ S_StartSound(&plat->sector->soundorg,
+ sfx_stnmov);
+ }
+ }
+ if (res == crushed && (!plat->crush))
+ {
+ plat->count = plat->wait;
+ plat->status = down;
+ S_StartSound(&plat->sector->soundorg, sfx_pstart);
+ }
+ else if (res == pastdest)
+ {
+ plat->count = plat->wait;
+ plat->status = waiting;
+ S_StartSound(&plat->sector->soundorg, sfx_pstop);
+ switch (plat->type)
+ {
+ case downWaitUpStay:
+ P_RemoveActivePlat(plat);
+ break;
+ case raiseAndChange:
+ 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(&plat->sector->soundorg, sfx_pstop);
+ }
+ else
+ {
+ if (!(leveltime & 31))
+ {
+ S_StartSound(&plat->sector->soundorg,
+ sfx_stnmov);
+ }
+ }
+ break;
+ case waiting:
+ if (!--plat->count)
+ {
+ if (plat->sector->floorheight == plat->low)
+ plat->status = up;
+ else
+ plat->status = down;
+ S_StartSound(&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 = 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;
+ sec->special = 0; // NO MORE DAMAGE, IF APPLICABLE
+ S_StartSound(&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(&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(&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(&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 = 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 = NULL;
+ }
+}
+
+void P_AddActivePlat(plat_t * plat)
+{
+ int i;
+ for (i = 0; i < MAXPLATS; i++)
+ if (activeplats[i] == NULL)
+ {
+ activeplats[i] = plat;
+ return;
+ }
+ I_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 = NULL;
+ P_RemoveThinker(&(activeplats[i])->thinker);
+ activeplats[i] = NULL;
+ return;
+ }
+ I_Error("P_RemoveActivePlat: can't find plat!");
+}
diff --git a/src/heretic/p_pspr.c b/src/heretic/p_pspr.c
new file mode 100644
index 00000000..c0abf559
--- /dev/null
+++ b/src/heretic/p_pspr.c
@@ -0,0 +1,1908 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// P_pspr.c
+
+#include "doomdef.h"
+#include "i_system.h"
+#include "m_random.h"
+#include "p_local.h"
+#include "s_sound.h"
+
+// Macros
+
+#define LOWERSPEED FRACUNIT*6
+#define RAISESPEED FRACUNIT*6
+#define WEAPONBOTTOM 128*FRACUNIT
+#define WEAPONTOP 32*FRACUNIT
+#define FLAME_THROWER_TICS 10*35
+#define MAGIC_JUNK 1234
+#define MAX_MACE_SPOTS 8
+
+static int MaceSpotCount;
+static struct
+{
+ fixed_t x;
+ fixed_t y;
+} MaceSpots[MAX_MACE_SPOTS];
+
+fixed_t bulletslope;
+
+static int WeaponAmmoUsePL1[NUMWEAPONS] = {
+ 0, // staff
+ USE_GWND_AMMO_1, // gold wand
+ USE_CBOW_AMMO_1, // crossbow
+ USE_BLSR_AMMO_1, // blaster
+ USE_SKRD_AMMO_1, // skull rod
+ USE_PHRD_AMMO_1, // phoenix rod
+ USE_MACE_AMMO_1, // mace
+ 0, // gauntlets
+ 0 // beak
+};
+
+static int WeaponAmmoUsePL2[NUMWEAPONS] = {
+ 0, // staff
+ USE_GWND_AMMO_2, // gold wand
+ USE_CBOW_AMMO_2, // crossbow
+ USE_BLSR_AMMO_2, // blaster
+ USE_SKRD_AMMO_2, // skull rod
+ USE_PHRD_AMMO_2, // phoenix rod
+ USE_MACE_AMMO_2, // mace
+ 0, // gauntlets
+ 0 // beak
+};
+
+weaponinfo_t wpnlev1info[NUMWEAPONS] = {
+ { // Staff
+ am_noammo, // ammo
+ S_STAFFUP, // upstate
+ S_STAFFDOWN, // downstate
+ S_STAFFREADY, // readystate
+ S_STAFFATK1_1, // atkstate
+ S_STAFFATK1_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Gold wand
+ am_goldwand, // ammo
+ S_GOLDWANDUP, // upstate
+ S_GOLDWANDDOWN, // downstate
+ S_GOLDWANDREADY, // readystate
+ S_GOLDWANDATK1_1, // atkstate
+ S_GOLDWANDATK1_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Crossbow
+ am_crossbow, // ammo
+ S_CRBOWUP, // upstate
+ S_CRBOWDOWN, // downstate
+ S_CRBOW1, // readystate
+ S_CRBOWATK1_1, // atkstate
+ S_CRBOWATK1_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Blaster
+ am_blaster, // ammo
+ S_BLASTERUP, // upstate
+ S_BLASTERDOWN, // downstate
+ S_BLASTERREADY, // readystate
+ S_BLASTERATK1_1, // atkstate
+ S_BLASTERATK1_3, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Skull rod
+ am_skullrod, // ammo
+ S_HORNRODUP, // upstate
+ S_HORNRODDOWN, // downstate
+ S_HORNRODREADY, // readystae
+ S_HORNRODATK1_1, // atkstate
+ S_HORNRODATK1_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Phoenix rod
+ am_phoenixrod, // ammo
+ S_PHOENIXUP, // upstate
+ S_PHOENIXDOWN, // downstate
+ S_PHOENIXREADY, // readystate
+ S_PHOENIXATK1_1, // atkstate
+ S_PHOENIXATK1_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Mace
+ am_mace, // ammo
+ S_MACEUP, // upstate
+ S_MACEDOWN, // downstate
+ S_MACEREADY, // readystate
+ S_MACEATK1_1, // atkstate
+ S_MACEATK1_2, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Gauntlets
+ am_noammo, // ammo
+ S_GAUNTLETUP, // upstate
+ S_GAUNTLETDOWN, // downstate
+ S_GAUNTLETREADY, // readystate
+ S_GAUNTLETATK1_1, // atkstate
+ S_GAUNTLETATK1_3, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Beak
+ am_noammo, // ammo
+ S_BEAKUP, // upstate
+ S_BEAKDOWN, // downstate
+ S_BEAKREADY, // readystate
+ S_BEAKATK1_1, // atkstate
+ S_BEAKATK1_1, // holdatkstate
+ S_NULL // flashstate
+ }
+};
+
+weaponinfo_t wpnlev2info[NUMWEAPONS] = {
+ { // Staff
+ am_noammo, // ammo
+ S_STAFFUP2, // upstate
+ S_STAFFDOWN2, // downstate
+ S_STAFFREADY2_1, // readystate
+ S_STAFFATK2_1, // atkstate
+ S_STAFFATK2_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Gold wand
+ am_goldwand, // ammo
+ S_GOLDWANDUP, // upstate
+ S_GOLDWANDDOWN, // downstate
+ S_GOLDWANDREADY, // readystate
+ S_GOLDWANDATK2_1, // atkstate
+ S_GOLDWANDATK2_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Crossbow
+ am_crossbow, // ammo
+ S_CRBOWUP, // upstate
+ S_CRBOWDOWN, // downstate
+ S_CRBOW1, // readystate
+ S_CRBOWATK2_1, // atkstate
+ S_CRBOWATK2_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Blaster
+ am_blaster, // ammo
+ S_BLASTERUP, // upstate
+ S_BLASTERDOWN, // downstate
+ S_BLASTERREADY, // readystate
+ S_BLASTERATK2_1, // atkstate
+ S_BLASTERATK2_3, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Skull rod
+ am_skullrod, // ammo
+ S_HORNRODUP, // upstate
+ S_HORNRODDOWN, // downstate
+ S_HORNRODREADY, // readystae
+ S_HORNRODATK2_1, // atkstate
+ S_HORNRODATK2_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Phoenix rod
+ am_phoenixrod, // ammo
+ S_PHOENIXUP, // upstate
+ S_PHOENIXDOWN, // downstate
+ S_PHOENIXREADY, // readystate
+ S_PHOENIXATK2_1, // atkstate
+ S_PHOENIXATK2_2, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Mace
+ am_mace, // ammo
+ S_MACEUP, // upstate
+ S_MACEDOWN, // downstate
+ S_MACEREADY, // readystate
+ S_MACEATK2_1, // atkstate
+ S_MACEATK2_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Gauntlets
+ am_noammo, // ammo
+ S_GAUNTLETUP2, // upstate
+ S_GAUNTLETDOWN2, // downstate
+ S_GAUNTLETREADY2_1, // readystate
+ S_GAUNTLETATK2_1, // atkstate
+ S_GAUNTLETATK2_3, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Beak
+ am_noammo, // ammo
+ S_BEAKUP, // upstate
+ S_BEAKDOWN, // downstate
+ S_BEAKREADY, // readystate
+ S_BEAKATK2_1, // atkstate
+ S_BEAKATK2_1, // holdatkstate
+ S_NULL // flashstate
+ }
+};
+
+//---------------------------------------------------------------------------
+//
+// PROC P_OpenWeapons
+//
+// Called at level load before things are loaded.
+//
+//---------------------------------------------------------------------------
+
+void P_OpenWeapons(void)
+{
+ MaceSpotCount = 0;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_AddMaceSpot
+//
+//---------------------------------------------------------------------------
+
+void P_AddMaceSpot(mapthing_t * mthing)
+{
+ if (MaceSpotCount == MAX_MACE_SPOTS)
+ {
+ I_Error("Too many mace spots.");
+ }
+ MaceSpots[MaceSpotCount].x = mthing->x << FRACBITS;
+ MaceSpots[MaceSpotCount].y = mthing->y << FRACBITS;
+ MaceSpotCount++;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_RepositionMace
+//
+// Chooses the next spot to place the mace.
+//
+//---------------------------------------------------------------------------
+
+void P_RepositionMace(mobj_t * mo)
+{
+ int spot;
+ subsector_t *ss;
+
+ P_UnsetThingPosition(mo);
+ spot = P_Random() % MaceSpotCount;
+ mo->x = MaceSpots[spot].x;
+ mo->y = MaceSpots[spot].y;
+ ss = R_PointInSubsector(mo->x, mo->y);
+ mo->z = mo->floorz = ss->sector->floorheight;
+ mo->ceilingz = ss->sector->ceilingheight;
+ P_SetThingPosition(mo);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_CloseWeapons
+//
+// Called at level load after things are loaded.
+//
+//---------------------------------------------------------------------------
+
+void P_CloseWeapons(void)
+{
+ int spot;
+
+ if (!MaceSpotCount)
+ { // No maces placed
+ return;
+ }
+ if (!deathmatch && P_Random() < 64)
+ { // Sometimes doesn't show up if not in deathmatch
+ return;
+ }
+ spot = P_Random() % MaceSpotCount;
+ P_SpawnMobj(MaceSpots[spot].x, MaceSpots[spot].y, ONFLOORZ, MT_WMACE);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC 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 = NULL;
+ break;
+ }
+ state = &states[stnum];
+ psp->state = state;
+ psp->tics = state->tics; // could be 0
+ if (state->misc1)
+ { // Set coordinates.
+ psp->sx = state->misc1 << FRACBITS;
+ psp->sy = state->misc2 << FRACBITS;
+ }
+ if (state->action)
+ { // Call action routine.
+ state->action(player, psp);
+ if (!psp->state)
+ {
+ break;
+ }
+ }
+ stnum = psp->state->nextstate;
+ }
+ while (!psp->tics); // An initial state of 0 could cycle through.
+}
+
+/*
+=================
+=
+= P_CalcSwing
+=
+=================
+*/
+
+/*
+fixed_t swingx, swingy;
+void P_CalcSwing (player_t *player)
+{
+ fixed_t swing;
+ int angle;
+
+// OPTIMIZE: tablify this
+
+ swing = player->bob;
+
+ angle = (FINEANGLES/70*leveltime)&FINEMASK;
+ swingx = FixedMul ( swing, finesine[angle]);
+
+ angle = (FINEANGLES/70*leveltime+FINEANGLES/2)&FINEMASK;
+ swingy = -FixedMul ( swingx, finesine[angle]);
+}
+*/
+
+//---------------------------------------------------------------------------
+//
+// PROC P_ActivateBeak
+//
+//---------------------------------------------------------------------------
+
+void P_ActivateBeak(player_t * player)
+{
+ player->pendingweapon = wp_nochange;
+ player->readyweapon = wp_beak;
+ player->psprites[ps_weapon].sy = WEAPONTOP;
+ P_SetPsprite(player, ps_weapon, S_BEAKREADY);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_PostChickenWeapon
+//
+//---------------------------------------------------------------------------
+
+void P_PostChickenWeapon(player_t * player, weapontype_t weapon)
+{
+ if (weapon == wp_beak)
+ { // Should never happen
+ weapon = wp_staff;
+ }
+ player->pendingweapon = wp_nochange;
+ player->readyweapon = weapon;
+ player->psprites[ps_weapon].sy = WEAPONBOTTOM;
+ P_SetPsprite(player, ps_weapon, wpnlev1info[weapon].upstate);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_BringUpWeapon
+//
+// Starts bringing the pending weapon up from the bottom of the screen.
+//
+//---------------------------------------------------------------------------
+
+void P_BringUpWeapon(player_t * player)
+{
+ statenum_t new;
+
+ if (player->pendingweapon == wp_nochange)
+ {
+ player->pendingweapon = player->readyweapon;
+ }
+ if (player->pendingweapon == wp_gauntlets)
+ {
+ S_StartSound(player->mo, sfx_gntact);
+ }
+ if (player->powers[pw_weaponlevel2])
+ {
+ new = wpnlev2info[player->pendingweapon].upstate;
+ }
+ else
+ {
+ new = wpnlev1info[player->pendingweapon].upstate;
+ }
+ player->pendingweapon = wp_nochange;
+ player->psprites[ps_weapon].sy = WEAPONBOTTOM;
+ P_SetPsprite(player, ps_weapon, new);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_CheckAmmo
+//
+// Returns true if there is enough ammo to shoot. If not, selects the
+// next weapon to use.
+//
+//---------------------------------------------------------------------------
+
+boolean P_CheckAmmo(player_t * player)
+{
+ ammotype_t ammo;
+ int *ammoUse;
+ int count;
+
+ ammo = wpnlev1info[player->readyweapon].ammo;
+ if (player->powers[pw_weaponlevel2] && !deathmatch)
+ {
+ ammoUse = WeaponAmmoUsePL2;
+ }
+ else
+ {
+ ammoUse = WeaponAmmoUsePL1;
+ }
+ count = ammoUse[player->readyweapon];
+ if (ammo == am_noammo || player->ammo[ammo] >= count)
+ {
+ return (true);
+ }
+ // out of ammo, pick a weapon to change to
+ do
+ {
+ if (player->weaponowned[wp_skullrod]
+ && player->ammo[am_skullrod] > ammoUse[wp_skullrod])
+ {
+ player->pendingweapon = wp_skullrod;
+ }
+ else if (player->weaponowned[wp_blaster]
+ && player->ammo[am_blaster] > ammoUse[wp_blaster])
+ {
+ player->pendingweapon = wp_blaster;
+ }
+ else if (player->weaponowned[wp_crossbow]
+ && player->ammo[am_crossbow] > ammoUse[wp_crossbow])
+ {
+ player->pendingweapon = wp_crossbow;
+ }
+ else if (player->weaponowned[wp_mace]
+ && player->ammo[am_mace] > ammoUse[wp_mace])
+ {
+ player->pendingweapon = wp_mace;
+ }
+ else if (player->ammo[am_goldwand] > ammoUse[wp_goldwand])
+ {
+ player->pendingweapon = wp_goldwand;
+ }
+ else if (player->weaponowned[wp_gauntlets])
+ {
+ player->pendingweapon = wp_gauntlets;
+ }
+ else if (player->weaponowned[wp_phoenixrod]
+ && player->ammo[am_phoenixrod] > ammoUse[wp_phoenixrod])
+ {
+ player->pendingweapon = wp_phoenixrod;
+ }
+ else
+ {
+ player->pendingweapon = wp_staff;
+ }
+ }
+ while (player->pendingweapon == wp_nochange);
+ if (player->powers[pw_weaponlevel2])
+ {
+ P_SetPsprite(player, ps_weapon,
+ wpnlev2info[player->readyweapon].downstate);
+ }
+ else
+ {
+ P_SetPsprite(player, ps_weapon,
+ wpnlev1info[player->readyweapon].downstate);
+ }
+ return (false);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_FireWeapon
+//
+//---------------------------------------------------------------------------
+
+void P_FireWeapon(player_t * player)
+{
+ weaponinfo_t *wpinfo;
+ statenum_t attackState;
+
+ if (!P_CheckAmmo(player))
+ {
+ return;
+ }
+ P_SetMobjState(player->mo, S_PLAY_ATK2);
+ wpinfo = player->powers[pw_weaponlevel2] ? &wpnlev2info[0]
+ : &wpnlev1info[0];
+ attackState = player->refire ? wpinfo[player->readyweapon].holdatkstate
+ : wpinfo[player->readyweapon].atkstate;
+ P_SetPsprite(player, ps_weapon, attackState);
+ P_NoiseAlert(player->mo, player->mo);
+ if (player->readyweapon == wp_gauntlets && !player->refire)
+ { // Play the sound for the initial gauntlet attack
+ S_StartSound(player->mo, sfx_gntuse);
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_DropWeapon
+//
+// The player died, so put the weapon away.
+//
+//---------------------------------------------------------------------------
+
+void P_DropWeapon(player_t * player)
+{
+ if (player->powers[pw_weaponlevel2])
+ {
+ P_SetPsprite(player, ps_weapon,
+ wpnlev2info[player->readyweapon].downstate);
+ }
+ else
+ {
+ P_SetPsprite(player, ps_weapon,
+ wpnlev1info[player->readyweapon].downstate);
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_WeaponReady
+//
+// The player can fire the weapon or change to another weapon at this time.
+//
+//---------------------------------------------------------------------------
+
+void A_WeaponReady(player_t * player, pspdef_t * psp)
+{
+ int angle;
+
+ if (player->chickenTics)
+ { // Change to the chicken beak
+ P_ActivateBeak(player);
+ return;
+ }
+ // Change player from attack state
+ if (player->mo->state == &states[S_PLAY_ATK1]
+ || player->mo->state == &states[S_PLAY_ATK2])
+ {
+ P_SetMobjState(player->mo, S_PLAY);
+ }
+ // Check for staff PL2 active sound
+ if ((player->readyweapon == wp_staff)
+ && (psp->state == &states[S_STAFFREADY2_1]) && P_Random() < 128)
+ {
+ S_StartSound(player->mo, sfx_stfcrk);
+ }
+ // Put the weapon away if the player has a pending weapon or has
+ // died.
+ if (player->pendingweapon != wp_nochange || !player->health)
+ {
+ if (player->powers[pw_weaponlevel2])
+ {
+ P_SetPsprite(player, ps_weapon,
+ wpnlev2info[player->readyweapon].downstate);
+ }
+ else
+ {
+ P_SetPsprite(player, ps_weapon,
+ wpnlev1info[player->readyweapon].downstate);
+ }
+ return;
+ }
+
+ // Check for fire. The phoenix rod does not auto fire.
+ if (player->cmd.buttons & BT_ATTACK)
+ {
+ if (!player->attackdown || (player->readyweapon != wp_phoenixrod))
+ {
+ 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]);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_UpdateBeak
+//
+//---------------------------------------------------------------------------
+
+void P_UpdateBeak(player_t * player, pspdef_t * psp)
+{
+ psp->sy = WEAPONTOP + (player->chickenPeck << (FRACBITS - 1));
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_BeakReady
+//
+//---------------------------------------------------------------------------
+
+void A_BeakReady(player_t * player, pspdef_t * psp)
+{
+ if (player->cmd.buttons & BT_ATTACK)
+ { // Chicken beak attack
+ player->attackdown = true;
+ P_SetMobjState(player->mo, S_CHICPLAY_ATK1);
+ if (player->powers[pw_weaponlevel2])
+ {
+ P_SetPsprite(player, ps_weapon, S_BEAKATK2_1);
+ }
+ else
+ {
+ P_SetPsprite(player, ps_weapon, S_BEAKATK1_1);
+ }
+ P_NoiseAlert(player->mo, player->mo);
+ }
+ else
+ {
+ if (player->mo->state == &states[S_CHICPLAY_ATK1])
+ { // Take out of attack state
+ P_SetMobjState(player->mo, S_CHICPLAY);
+ }
+ player->attackdown = false;
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_ReFire
+//
+// The player can re fire the weapon without lowering it entirely.
+//
+//---------------------------------------------------------------------------
+
+void A_ReFire(player_t * player, pspdef_t * psp)
+{
+ if ((player->cmd.buttons & BT_ATTACK)
+ && player->pendingweapon == wp_nochange && player->health)
+ {
+ player->refire++;
+ P_FireWeapon(player);
+ }
+ else
+ {
+ player->refire = 0;
+ P_CheckAmmo(player);
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_Lower
+//
+//---------------------------------------------------------------------------
+
+void A_Lower(player_t * player, pspdef_t * psp)
+{
+ if (player->chickenTics)
+ {
+ psp->sy = WEAPONBOTTOM;
+ }
+ else
+ {
+ psp->sy += LOWERSPEED;
+ }
+ if (psp->sy < WEAPONBOTTOM)
+ { // Not lowered all the way yet
+ return;
+ }
+ if (player->playerstate == PST_DEAD)
+ { // Player is dead, so don't bring up a pending weapon
+ psp->sy = WEAPONBOTTOM;
+ return;
+ }
+ 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);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_BeakRaise
+//
+//---------------------------------------------------------------------------
+
+void A_BeakRaise(player_t * player, pspdef_t * psp)
+{
+ psp->sy = WEAPONTOP;
+ P_SetPsprite(player, ps_weapon,
+ wpnlev1info[player->readyweapon].readystate);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_Raise
+//
+//---------------------------------------------------------------------------
+
+void A_Raise(player_t * player, pspdef_t * psp)
+{
+ psp->sy -= RAISESPEED;
+ if (psp->sy > WEAPONTOP)
+ { // Not raised all the way yet
+ return;
+ }
+ psp->sy = WEAPONTOP;
+ if (player->powers[pw_weaponlevel2])
+ {
+ P_SetPsprite(player, ps_weapon,
+ wpnlev2info[player->readyweapon].readystate);
+ }
+ else
+ {
+ P_SetPsprite(player, ps_weapon,
+ wpnlev1info[player->readyweapon].readystate);
+ }
+}
+
+/*
+===============
+=
+= 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);
+ }
+ if (!linetarget)
+ {
+ an += 2 << 26;
+ bulletslope = (mo->player->lookdir << FRACBITS) / 173;
+ }
+ }
+}
+
+//****************************************************************************
+//
+// WEAPON ATTACKS
+//
+//****************************************************************************
+
+//----------------------------------------------------------------------------
+//
+// PROC A_BeakAttackPL1
+//
+//----------------------------------------------------------------------------
+
+void A_BeakAttackPL1(player_t * player, pspdef_t * psp)
+{
+ angle_t angle;
+ int damage;
+ int slope;
+
+ damage = 1 + (P_Random() & 3);
+ angle = player->mo->angle;
+ slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
+ PuffType = MT_BEAKPUFF;
+ P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
+ if (linetarget)
+ {
+ player->mo->angle = R_PointToAngle2(player->mo->x,
+ player->mo->y, linetarget->x,
+ linetarget->y);
+ }
+ S_StartSound(player->mo, sfx_chicpk1 + (P_Random() % 3));
+ player->chickenPeck = 12;
+ psp->tics -= P_Random() & 7;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_BeakAttackPL2
+//
+//----------------------------------------------------------------------------
+
+void A_BeakAttackPL2(player_t * player, pspdef_t * psp)
+{
+ angle_t angle;
+ int damage;
+ int slope;
+
+ damage = HITDICE(4);
+ angle = player->mo->angle;
+ slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
+ PuffType = MT_BEAKPUFF;
+ P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
+ if (linetarget)
+ {
+ player->mo->angle = R_PointToAngle2(player->mo->x,
+ player->mo->y, linetarget->x,
+ linetarget->y);
+ }
+ S_StartSound(player->mo, sfx_chicpk1 + (P_Random() % 3));
+ player->chickenPeck = 12;
+ psp->tics -= P_Random() & 3;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_StaffAttackPL1
+//
+//----------------------------------------------------------------------------
+
+void A_StaffAttackPL1(player_t * player, pspdef_t * psp)
+{
+ angle_t angle;
+ int damage;
+ int slope;
+
+ damage = 5 + (P_Random() & 15);
+ angle = player->mo->angle;
+ angle += (P_Random() - P_Random()) << 18;
+ slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
+ PuffType = MT_STAFFPUFF;
+ P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
+ if (linetarget)
+ {
+ //S_StartSound(player->mo, sfx_stfhit);
+ // turn to face target
+ player->mo->angle = R_PointToAngle2(player->mo->x,
+ player->mo->y, linetarget->x,
+ linetarget->y);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_StaffAttackPL2
+//
+//----------------------------------------------------------------------------
+
+void A_StaffAttackPL2(player_t * player, pspdef_t * psp)
+{
+ angle_t angle;
+ int damage;
+ int slope;
+
+ // P_inter.c:P_DamageMobj() handles target momentums
+ damage = 18 + (P_Random() & 63);
+ angle = player->mo->angle;
+ angle += (P_Random() - P_Random()) << 18;
+ slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
+ PuffType = MT_STAFFPUFF2;
+ P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
+ if (linetarget)
+ {
+ //S_StartSound(player->mo, sfx_stfpow);
+ // turn to face target
+ player->mo->angle = R_PointToAngle2(player->mo->x,
+ player->mo->y, linetarget->x,
+ linetarget->y);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FireBlasterPL1
+//
+//----------------------------------------------------------------------------
+
+void A_FireBlasterPL1(player_t * player, pspdef_t * psp)
+{
+ mobj_t *mo;
+ angle_t angle;
+ int damage;
+
+ mo = player->mo;
+ S_StartSound(mo, sfx_gldhit);
+ player->ammo[am_blaster] -= USE_BLSR_AMMO_1;
+ P_BulletSlope(mo);
+ damage = HITDICE(4);
+ angle = mo->angle;
+ if (player->refire)
+ {
+ angle += (P_Random() - P_Random()) << 18;
+ }
+ PuffType = MT_BLASTERPUFF1;
+ P_LineAttack(mo, angle, MISSILERANGE, bulletslope, damage);
+ S_StartSound(player->mo, sfx_blssht);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FireBlasterPL2
+//
+//----------------------------------------------------------------------------
+
+void A_FireBlasterPL2(player_t * player, pspdef_t * psp)
+{
+ mobj_t *mo;
+
+ player->ammo[am_blaster] -=
+ deathmatch ? USE_BLSR_AMMO_1 : USE_BLSR_AMMO_2;
+ mo = P_SpawnPlayerMissile(player->mo, MT_BLASTERFX1);
+ if (mo)
+ {
+ mo->thinker.function = P_BlasterMobjThinker;
+ }
+ S_StartSound(player->mo, sfx_blssht);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FireGoldWandPL1
+//
+//----------------------------------------------------------------------------
+
+void A_FireGoldWandPL1(player_t * player, pspdef_t * psp)
+{
+ mobj_t *mo;
+ angle_t angle;
+ int damage;
+
+ mo = player->mo;
+ player->ammo[am_goldwand] -= USE_GWND_AMMO_1;
+ P_BulletSlope(mo);
+ damage = 7 + (P_Random() & 7);
+ angle = mo->angle;
+ if (player->refire)
+ {
+ angle += (P_Random() - P_Random()) << 18;
+ }
+ PuffType = MT_GOLDWANDPUFF1;
+ P_LineAttack(mo, angle, MISSILERANGE, bulletslope, damage);
+ S_StartSound(player->mo, sfx_gldhit);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FireGoldWandPL2
+//
+//----------------------------------------------------------------------------
+
+void A_FireGoldWandPL2(player_t * player, pspdef_t * psp)
+{
+ int i;
+ mobj_t *mo;
+ angle_t angle;
+ int damage;
+ fixed_t momz;
+
+ mo = player->mo;
+ player->ammo[am_goldwand] -=
+ deathmatch ? USE_GWND_AMMO_1 : USE_GWND_AMMO_2;
+ PuffType = MT_GOLDWANDPUFF2;
+ P_BulletSlope(mo);
+ momz = FixedMul(mobjinfo[MT_GOLDWANDFX2].speed, bulletslope);
+ P_SpawnMissileAngle(mo, MT_GOLDWANDFX2, mo->angle - (ANG45 / 8), momz);
+ P_SpawnMissileAngle(mo, MT_GOLDWANDFX2, mo->angle + (ANG45 / 8), momz);
+ angle = mo->angle - (ANG45 / 8);
+ for (i = 0; i < 5; i++)
+ {
+ damage = 1 + (P_Random() & 7);
+ P_LineAttack(mo, angle, MISSILERANGE, bulletslope, damage);
+ angle += ((ANG45 / 8) * 2) / 4;
+ }
+ S_StartSound(player->mo, sfx_gldhit);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FireMacePL1B
+//
+//----------------------------------------------------------------------------
+
+void A_FireMacePL1B(player_t * player, pspdef_t * psp)
+{
+ mobj_t *pmo;
+ mobj_t *ball;
+ angle_t angle;
+
+ if (player->ammo[am_mace] < USE_MACE_AMMO_1)
+ {
+ return;
+ }
+ player->ammo[am_mace] -= USE_MACE_AMMO_1;
+ pmo = player->mo;
+ ball = P_SpawnMobj(pmo->x, pmo->y, pmo->z + 28 * FRACUNIT
+ - FOOTCLIPSIZE * ((pmo->flags2 & MF2_FEETARECLIPPED) !=
+ 0), MT_MACEFX2);
+ ball->momz = 2 * FRACUNIT + ((player->lookdir) << (FRACBITS - 5));
+ angle = pmo->angle;
+ ball->target = pmo;
+ ball->angle = angle;
+ ball->z += (player->lookdir) << (FRACBITS - 4);
+ angle >>= ANGLETOFINESHIFT;
+ ball->momx = (pmo->momx >> 1)
+ + FixedMul(ball->info->speed, finecosine[angle]);
+ ball->momy = (pmo->momy >> 1)
+ + FixedMul(ball->info->speed, finesine[angle]);
+ S_StartSound(ball, sfx_lobsht);
+ P_CheckMissileSpawn(ball);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FireMacePL1
+//
+//----------------------------------------------------------------------------
+
+void A_FireMacePL1(player_t * player, pspdef_t * psp)
+{
+ mobj_t *ball;
+
+ if (P_Random() < 28)
+ {
+ A_FireMacePL1B(player, psp);
+ return;
+ }
+ if (player->ammo[am_mace] < USE_MACE_AMMO_1)
+ {
+ return;
+ }
+ player->ammo[am_mace] -= USE_MACE_AMMO_1;
+ psp->sx = ((P_Random() & 3) - 2) * FRACUNIT;
+ psp->sy = WEAPONTOP + (P_Random() & 3) * FRACUNIT;
+ ball = P_SPMAngle(player->mo, MT_MACEFX1, player->mo->angle
+ + (((P_Random() & 7) - 4) << 24));
+ if (ball)
+ {
+ ball->special1.i = 16; // tics till dropoff
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MacePL1Check
+//
+//----------------------------------------------------------------------------
+
+void A_MacePL1Check(mobj_t * ball)
+{
+ angle_t angle;
+
+ if (ball->special1.i == 0)
+ {
+ return;
+ }
+ ball->special1.i -= 4;
+ if (ball->special1.i > 0)
+ {
+ return;
+ }
+ ball->special1.i = 0;
+ ball->flags2 |= MF2_LOGRAV;
+ angle = ball->angle >> ANGLETOFINESHIFT;
+ ball->momx = FixedMul(7 * FRACUNIT, finecosine[angle]);
+ ball->momy = FixedMul(7 * FRACUNIT, finesine[angle]);
+ ball->momz -= ball->momz >> 1;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MaceBallImpact
+//
+//----------------------------------------------------------------------------
+
+void A_MaceBallImpact(mobj_t * ball)
+{
+ if ((ball->z <= ball->floorz) && (P_HitFloor(ball) != FLOOR_SOLID))
+ { // Landed in some sort of liquid
+ P_RemoveMobj(ball);
+ return;
+ }
+ if ((ball->health != MAGIC_JUNK) && (ball->z <= ball->floorz)
+ && ball->momz)
+ { // Bounce
+ ball->health = MAGIC_JUNK;
+ ball->momz = (ball->momz * 192) >> 8;
+ ball->flags2 &= ~MF2_FLOORBOUNCE;
+ P_SetMobjState(ball, ball->info->spawnstate);
+ S_StartSound(ball, sfx_bounce);
+ }
+ else
+ { // Explode
+ ball->flags |= MF_NOGRAVITY;
+ ball->flags2 &= ~MF2_LOGRAV;
+ S_StartSound(ball, sfx_lobhit);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MaceBallImpact2
+//
+//----------------------------------------------------------------------------
+
+void A_MaceBallImpact2(mobj_t * ball)
+{
+ mobj_t *tiny;
+ angle_t angle;
+
+ if ((ball->z <= ball->floorz) && (P_HitFloor(ball) != FLOOR_SOLID))
+ { // Landed in some sort of liquid
+ P_RemoveMobj(ball);
+ return;
+ }
+ if ((ball->z != ball->floorz) || (ball->momz < 2 * FRACUNIT))
+ { // Explode
+ ball->momx = ball->momy = ball->momz = 0;
+ ball->flags |= MF_NOGRAVITY;
+ ball->flags2 &= ~(MF2_LOGRAV | MF2_FLOORBOUNCE);
+ }
+ else
+ { // Bounce
+ ball->momz = (ball->momz * 192) >> 8;
+ P_SetMobjState(ball, ball->info->spawnstate);
+
+ tiny = P_SpawnMobj(ball->x, ball->y, ball->z, MT_MACEFX3);
+ angle = ball->angle + ANG90;
+ tiny->target = ball->target;
+ tiny->angle = angle;
+ angle >>= ANGLETOFINESHIFT;
+ tiny->momx = (ball->momx >> 1) + FixedMul(ball->momz - FRACUNIT,
+ finecosine[angle]);
+ tiny->momy = (ball->momy >> 1) + FixedMul(ball->momz - FRACUNIT,
+ finesine[angle]);
+ tiny->momz = ball->momz;
+ P_CheckMissileSpawn(tiny);
+
+ tiny = P_SpawnMobj(ball->x, ball->y, ball->z, MT_MACEFX3);
+ angle = ball->angle - ANG90;
+ tiny->target = ball->target;
+ tiny->angle = angle;
+ angle >>= ANGLETOFINESHIFT;
+ tiny->momx = (ball->momx >> 1) + FixedMul(ball->momz - FRACUNIT,
+ finecosine[angle]);
+ tiny->momy = (ball->momy >> 1) + FixedMul(ball->momz - FRACUNIT,
+ finesine[angle]);
+ tiny->momz = ball->momz;
+ P_CheckMissileSpawn(tiny);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FireMacePL2
+//
+//----------------------------------------------------------------------------
+
+void A_FireMacePL2(player_t * player, pspdef_t * psp)
+{
+ mobj_t *mo;
+
+ player->ammo[am_mace] -= deathmatch ? USE_MACE_AMMO_1 : USE_MACE_AMMO_2;
+ mo = P_SpawnPlayerMissile(player->mo, MT_MACEFX4);
+ if (mo)
+ {
+ mo->momx += player->mo->momx;
+ mo->momy += player->mo->momy;
+ mo->momz = 2 * FRACUNIT + ((player->lookdir) << (FRACBITS - 5));
+ if (linetarget)
+ {
+ mo->special1.m = linetarget;
+ }
+ }
+ S_StartSound(player->mo, sfx_lobsht);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_DeathBallImpact
+//
+//----------------------------------------------------------------------------
+
+void A_DeathBallImpact(mobj_t * ball)
+{
+ int i;
+ mobj_t *target;
+ angle_t angle;
+ boolean newAngle;
+
+ if ((ball->z <= ball->floorz) && (P_HitFloor(ball) != FLOOR_SOLID))
+ { // Landed in some sort of liquid
+ P_RemoveMobj(ball);
+ return;
+ }
+ if ((ball->z <= ball->floorz) && ball->momz)
+ { // Bounce
+ newAngle = false;
+ target = (mobj_t *) ball->special1.m;
+ if (target)
+ {
+ if (!(target->flags & MF_SHOOTABLE))
+ { // Target died
+ ball->special1.m = NULL;
+ }
+ else
+ { // Seek
+ angle = R_PointToAngle2(ball->x, ball->y,
+ target->x, target->y);
+ newAngle = true;
+ }
+ }
+ else
+ { // Find new target
+ angle = 0;
+ for (i = 0; i < 16; i++)
+ {
+ P_AimLineAttack(ball, angle, 10 * 64 * FRACUNIT);
+ if (linetarget && ball->target != linetarget)
+ {
+ ball->special1.m = linetarget;
+ angle = R_PointToAngle2(ball->x, ball->y,
+ linetarget->x, linetarget->y);
+ newAngle = true;
+ break;
+ }
+ angle += ANG45 / 2;
+ }
+ }
+ if (newAngle)
+ {
+ ball->angle = angle;
+ angle >>= ANGLETOFINESHIFT;
+ ball->momx = FixedMul(ball->info->speed, finecosine[angle]);
+ ball->momy = FixedMul(ball->info->speed, finesine[angle]);
+ }
+ P_SetMobjState(ball, ball->info->spawnstate);
+ S_StartSound(ball, sfx_pstop);
+ }
+ else
+ { // Explode
+ ball->flags |= MF_NOGRAVITY;
+ ball->flags2 &= ~MF2_LOGRAV;
+ S_StartSound(ball, sfx_phohit);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_SpawnRippers
+//
+//----------------------------------------------------------------------------
+
+void A_SpawnRippers(mobj_t * actor)
+{
+ int i;
+ angle_t angle;
+ mobj_t *ripper;
+
+ for (i = 0; i < 8; i++)
+ {
+ ripper = P_SpawnMobj(actor->x, actor->y, actor->z, MT_RIPPER);
+ angle = i * ANG45;
+ ripper->target = actor->target;
+ ripper->angle = angle;
+ angle >>= ANGLETOFINESHIFT;
+ ripper->momx = FixedMul(ripper->info->speed, finecosine[angle]);
+ ripper->momy = FixedMul(ripper->info->speed, finesine[angle]);
+ P_CheckMissileSpawn(ripper);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FireCrossbowPL1
+//
+//----------------------------------------------------------------------------
+
+void A_FireCrossbowPL1(player_t * player, pspdef_t * psp)
+{
+ mobj_t *pmo;
+
+ pmo = player->mo;
+ player->ammo[am_crossbow] -= USE_CBOW_AMMO_1;
+ P_SpawnPlayerMissile(pmo, MT_CRBOWFX1);
+ P_SPMAngle(pmo, MT_CRBOWFX3, pmo->angle - (ANG45 / 10));
+ P_SPMAngle(pmo, MT_CRBOWFX3, pmo->angle + (ANG45 / 10));
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FireCrossbowPL2
+//
+//----------------------------------------------------------------------------
+
+void A_FireCrossbowPL2(player_t * player, pspdef_t * psp)
+{
+ mobj_t *pmo;
+
+ pmo = player->mo;
+ player->ammo[am_crossbow] -=
+ deathmatch ? USE_CBOW_AMMO_1 : USE_CBOW_AMMO_2;
+ P_SpawnPlayerMissile(pmo, MT_CRBOWFX2);
+ P_SPMAngle(pmo, MT_CRBOWFX2, pmo->angle - (ANG45 / 10));
+ P_SPMAngle(pmo, MT_CRBOWFX2, pmo->angle + (ANG45 / 10));
+ P_SPMAngle(pmo, MT_CRBOWFX3, pmo->angle - (ANG45 / 5));
+ P_SPMAngle(pmo, MT_CRBOWFX3, pmo->angle + (ANG45 / 5));
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_BoltSpark
+//
+//----------------------------------------------------------------------------
+
+void A_BoltSpark(mobj_t * bolt)
+{
+ mobj_t *spark;
+
+ if (P_Random() > 50)
+ {
+ spark = P_SpawnMobj(bolt->x, bolt->y, bolt->z, MT_CRBOWFX4);
+ spark->x += (P_Random() - P_Random()) << 10;
+ spark->y += (P_Random() - P_Random()) << 10;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FireSkullRodPL1
+//
+//----------------------------------------------------------------------------
+
+void A_FireSkullRodPL1(player_t * player, pspdef_t * psp)
+{
+ mobj_t *mo;
+
+ if (player->ammo[am_skullrod] < USE_SKRD_AMMO_1)
+ {
+ return;
+ }
+ player->ammo[am_skullrod] -= USE_SKRD_AMMO_1;
+ mo = P_SpawnPlayerMissile(player->mo, MT_HORNRODFX1);
+ // Randomize the first frame
+ if (mo && P_Random() > 128)
+ {
+ P_SetMobjState(mo, S_HRODFX1_2);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FireSkullRodPL2
+//
+// The special2 field holds the player number that shot the rain missile.
+// The special1 field is used for the seeking routines, then as a counter
+// for the sound looping.
+//
+//----------------------------------------------------------------------------
+
+void A_FireSkullRodPL2(player_t * player, pspdef_t * psp)
+{
+ player->ammo[am_skullrod] -=
+ deathmatch ? USE_SKRD_AMMO_1 : USE_SKRD_AMMO_2;
+ P_SpawnPlayerMissile(player->mo, MT_HORNRODFX2);
+ // Use MissileMobj instead of the return value from
+ // P_SpawnPlayerMissile because we need to give info to the mobj
+ // even if it exploded immediately.
+ if (netgame)
+ { // Multi-player game
+ MissileMobj->special2.i = P_GetPlayerNum(player);
+ }
+ else
+ { // Always use red missiles in single player games
+ MissileMobj->special2.i = 2;
+ }
+ if (linetarget)
+ {
+ MissileMobj->special1.m = linetarget;
+ }
+ S_StartSound(MissileMobj, sfx_hrnpow);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_SkullRodPL2Seek
+//
+//----------------------------------------------------------------------------
+
+void A_SkullRodPL2Seek(mobj_t * actor)
+{
+ P_SeekerMissile(actor, ANG1_X * 10, ANG1_X * 30);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_AddPlayerRain
+//
+//----------------------------------------------------------------------------
+
+void A_AddPlayerRain(mobj_t * actor)
+{
+ int playerNum;
+ player_t *player;
+
+ playerNum = netgame ? actor->special2.i : 0;
+ if (!playeringame[playerNum])
+ { // Player left the game
+ return;
+ }
+ player = &players[playerNum];
+ if (player->health <= 0)
+ { // Player is dead
+ return;
+ }
+ if (player->rain1 && player->rain2)
+ { // Terminate an active rain
+ if (player->rain1->health < player->rain2->health)
+ {
+ if (player->rain1->health > 16)
+ {
+ player->rain1->health = 16;
+ }
+ player->rain1 = NULL;
+ }
+ else
+ {
+ if (player->rain2->health > 16)
+ {
+ player->rain2->health = 16;
+ }
+ player->rain2 = NULL;
+ }
+ }
+ // Add rain mobj to list
+ if (player->rain1)
+ {
+ player->rain2 = actor;
+ }
+ else
+ {
+ player->rain1 = actor;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_SkullRodStorm
+//
+//----------------------------------------------------------------------------
+
+void A_SkullRodStorm(mobj_t * actor)
+{
+ fixed_t x;
+ fixed_t y;
+ mobj_t *mo;
+ int playerNum;
+ player_t *player;
+
+ if (actor->health-- == 0)
+ {
+ P_SetMobjState(actor, S_NULL);
+ playerNum = netgame ? actor->special2.i : 0;
+ if (!playeringame[playerNum])
+ { // Player left the game
+ return;
+ }
+ player = &players[playerNum];
+ if (player->health <= 0)
+ { // Player is dead
+ return;
+ }
+ if (player->rain1 == actor)
+ {
+ player->rain1 = NULL;
+ }
+ else if (player->rain2 == actor)
+ {
+ player->rain2 = NULL;
+ }
+ return;
+ }
+ if (P_Random() < 25)
+ { // Fudge rain frequency
+ return;
+ }
+ x = actor->x + ((P_Random() & 127) - 64) * FRACUNIT;
+ y = actor->y + ((P_Random() & 127) - 64) * FRACUNIT;
+ mo = P_SpawnMobj(x, y, ONCEILINGZ, MT_RAINPLR1 + actor->special2.i);
+ mo->target = actor->target;
+ mo->momx = 1; // Force collision detection
+ mo->momz = -mo->info->speed;
+ mo->special2.i = actor->special2.i; // Transfer player number
+ P_CheckMissileSpawn(mo);
+ if (!(actor->special1.i & 31))
+ {
+ S_StartSound(actor, sfx_ramrain);
+ }
+ actor->special1.i++;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_RainImpact
+//
+//----------------------------------------------------------------------------
+
+void A_RainImpact(mobj_t * actor)
+{
+ if (actor->z > actor->floorz)
+ {
+ P_SetMobjState(actor, S_RAINAIRXPLR1_1 + actor->special2.i);
+ }
+ else if (P_Random() < 40)
+ {
+ P_HitFloor(actor);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_HideInCeiling
+//
+//----------------------------------------------------------------------------
+
+void A_HideInCeiling(mobj_t * actor)
+{
+ actor->z = actor->ceilingz + 4 * FRACUNIT;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FirePhoenixPL1
+//
+//----------------------------------------------------------------------------
+
+void A_FirePhoenixPL1(player_t * player, pspdef_t * psp)
+{
+ angle_t angle;
+
+ player->ammo[am_phoenixrod] -= USE_PHRD_AMMO_1;
+ P_SpawnPlayerMissile(player->mo, MT_PHOENIXFX1);
+ //P_SpawnPlayerMissile(player->mo, MT_MNTRFX2);
+ angle = player->mo->angle + ANG180;
+ angle >>= ANGLETOFINESHIFT;
+ player->mo->momx += FixedMul(4 * FRACUNIT, finecosine[angle]);
+ player->mo->momy += FixedMul(4 * FRACUNIT, finesine[angle]);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_PhoenixPuff
+//
+//----------------------------------------------------------------------------
+
+void A_PhoenixPuff(mobj_t * actor)
+{
+ mobj_t *puff;
+ angle_t angle;
+
+ P_SeekerMissile(actor, ANG1_X * 5, ANG1_X * 10);
+ puff = P_SpawnMobj(actor->x, actor->y, actor->z, MT_PHOENIXPUFF);
+ angle = actor->angle + ANG90;
+ angle >>= ANGLETOFINESHIFT;
+ puff->momx = FixedMul((fixed_t)(FRACUNIT * 1.3), finecosine[angle]);
+ puff->momy = FixedMul((fixed_t)(FRACUNIT * 1.3), finesine[angle]);
+ puff->momz = 0;
+ puff = P_SpawnMobj(actor->x, actor->y, actor->z, MT_PHOENIXPUFF);
+ angle = actor->angle - ANG90;
+ angle >>= ANGLETOFINESHIFT;
+ puff->momx = FixedMul((fixed_t)(FRACUNIT * 1.3), finecosine[angle]);
+ puff->momy = FixedMul((fixed_t)(FRACUNIT * 1.3), finesine[angle]);
+ puff->momz = 0;
+}
+
+//
+// This function was present in the Heretic 1.0 executable for the
+// removed "secondary phoenix flash" object (MT_PHOENIXFX_REMOVED).
+// The purpose of this object is unknown, as is this function.
+//
+
+void A_RemovedPhoenixFunc(mobj_t *actor)
+{
+ I_Error("Action function invoked for removed Phoenix action!");
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_InitPhoenixPL2
+//
+//----------------------------------------------------------------------------
+
+void A_InitPhoenixPL2(player_t * player, pspdef_t * psp)
+{
+ player->flamecount = FLAME_THROWER_TICS;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FirePhoenixPL2
+//
+// Flame thrower effect.
+//
+//----------------------------------------------------------------------------
+
+void A_FirePhoenixPL2(player_t * player, pspdef_t * psp)
+{
+ mobj_t *mo;
+ mobj_t *pmo;
+ angle_t angle;
+ fixed_t x, y, z;
+ fixed_t slope;
+
+ if (--player->flamecount == 0)
+ { // Out of flame
+ P_SetPsprite(player, ps_weapon, S_PHOENIXATK2_4);
+ player->refire = 0;
+ return;
+ }
+ pmo = player->mo;
+ angle = pmo->angle;
+ x = pmo->x + ((P_Random() - P_Random()) << 9);
+ y = pmo->y + ((P_Random() - P_Random()) << 9);
+ z = pmo->z + 26 * FRACUNIT + ((player->lookdir) << FRACBITS) / 173;
+ if (pmo->flags2 & MF2_FEETARECLIPPED)
+ {
+ z -= FOOTCLIPSIZE;
+ }
+ slope = ((player->lookdir) << FRACBITS) / 173 + (FRACUNIT / 10);
+ mo = P_SpawnMobj(x, y, z, MT_PHOENIXFX2);
+ mo->target = pmo;
+ mo->angle = angle;
+ mo->momx = pmo->momx + FixedMul(mo->info->speed,
+ finecosine[angle >> ANGLETOFINESHIFT]);
+ mo->momy = pmo->momy + FixedMul(mo->info->speed,
+ finesine[angle >> ANGLETOFINESHIFT]);
+ mo->momz = FixedMul(mo->info->speed, slope);
+ if (!player->refire || !(leveltime % 38))
+ {
+ S_StartSound(player->mo, sfx_phopow);
+ }
+ P_CheckMissileSpawn(mo);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_ShutdownPhoenixPL2
+//
+//----------------------------------------------------------------------------
+
+void A_ShutdownPhoenixPL2(player_t * player, pspdef_t * psp)
+{
+ player->ammo[am_phoenixrod] -= USE_PHRD_AMMO_2;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FlameEnd
+//
+//----------------------------------------------------------------------------
+
+void A_FlameEnd(mobj_t * actor)
+{
+ actor->momz += (fixed_t)(1.5 * FRACUNIT);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FloatPuff
+//
+//----------------------------------------------------------------------------
+
+void A_FloatPuff(mobj_t * puff)
+{
+ puff->momz += (fixed_t)(1.8 * FRACUNIT);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_GauntletAttack
+//
+//---------------------------------------------------------------------------
+
+void A_GauntletAttack(player_t * player, pspdef_t * psp)
+{
+ angle_t angle;
+ int damage;
+ int slope;
+ int randVal;
+ fixed_t dist;
+
+ psp->sx = ((P_Random() & 3) - 2) * FRACUNIT;
+ psp->sy = WEAPONTOP + (P_Random() & 3) * FRACUNIT;
+ angle = player->mo->angle;
+ if (player->powers[pw_weaponlevel2])
+ {
+ damage = HITDICE(2);
+ dist = 4 * MELEERANGE;
+ angle += (P_Random() - P_Random()) << 17;
+ PuffType = MT_GAUNTLETPUFF2;
+ }
+ else
+ {
+ damage = HITDICE(2);
+ dist = MELEERANGE + 1;
+ angle += (P_Random() - P_Random()) << 18;
+ PuffType = MT_GAUNTLETPUFF1;
+ }
+ slope = P_AimLineAttack(player->mo, angle, dist);
+ P_LineAttack(player->mo, angle, dist, slope, damage);
+ if (!linetarget)
+ {
+ if (P_Random() > 64)
+ {
+ player->extralight = !player->extralight;
+ }
+ S_StartSound(player->mo, sfx_gntful);
+ return;
+ }
+ randVal = P_Random();
+ if (randVal < 64)
+ {
+ player->extralight = 0;
+ }
+ else if (randVal < 160)
+ {
+ player->extralight = 1;
+ }
+ else
+ {
+ player->extralight = 2;
+ }
+ if (player->powers[pw_weaponlevel2])
+ {
+ P_GiveBody(player, damage >> 1);
+ S_StartSound(player->mo, sfx_gntpow);
+ }
+ else
+ {
+ S_StartSound(player->mo, sfx_gnthit);
+ }
+ // 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;
+}
+
+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;
+}
+
+//------------------------------------------------------------------------
+//
+// PROC 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 = NULL;
+ }
+ // Spawn the ready weapon
+ player->pendingweapon = player->readyweapon;
+ P_BringUpWeapon(player);
+}
+
+//------------------------------------------------------------------------
+//
+// PROC 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++)
+ {
+ if ((state = psp->state) != 0) // a null state means not active
+ {
+ // drop tic count and possibly change state
+ if (psp->tics != -1) // a -1 tic count never changes
+ {
+ 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;
+}
diff --git a/src/heretic/p_setup.c b/src/heretic/p_setup.c
new file mode 100644
index 00000000..a3bd2912
--- /dev/null
+++ b/src/heretic/p_setup.c
@@ -0,0 +1,660 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// P_main.c
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "doomdef.h"
+#include "i_swap.h"
+#include "i_system.h"
+#include "m_argv.h"
+#include "m_bbox.h"
+#include "p_local.h"
+#include "s_sound.h"
+
+void P_SpawnMapThing(mapthing_t * mthing);
+
+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;
+
+short *blockmaplump; // offsets in blockmap are from here
+short *blockmap;
+int bmapwidth, bmapheight; // in mapblocks
+fixed_t bmaporgx, bmaporgy; // origin of block map
+mobj_t **blocklinks; // for thing chains
+
+byte *rejectmatrix; // for fast sight rejection
+
+mapthing_t deathmatchstarts[10], *deathmatch_p;
+mapthing_t playerstarts[MAXPLAYERS];
+
+/*
+=================
+=
+= P_LoadVertexes
+=
+=================
+*/
+
+void P_LoadVertexes(int lump)
+{
+ byte *data;
+ int i;
+ mapvertex_t *ml;
+ vertex_t *li;
+
+ numvertexes = W_LumpLength(lump) / sizeof(mapvertex_t);
+ vertexes = Z_Malloc(numvertexes * sizeof(vertex_t), PU_LEVEL, 0);
+ data = W_CacheLumpNum(lump, PU_STATIC);
+
+ ml = (mapvertex_t *) data;
+ li = vertexes;
+ for (i = 0; i < numvertexes; i++, li++, ml++)
+ {
+ li->x = SHORT(ml->x) << FRACBITS;
+ li->y = SHORT(ml->y) << FRACBITS;
+ }
+
+ W_ReleaseLumpNum(lump);
+}
+
+
+/*
+=================
+=
+= P_LoadSegs
+=
+=================
+*/
+
+void P_LoadSegs(int lump)
+{
+ byte *data;
+ int i;
+ mapseg_t *ml;
+ seg_t *li;
+ line_t *ldef;
+ int linedef, side;
+
+ numsegs = W_LumpLength(lump) / sizeof(mapseg_t);
+ segs = Z_Malloc(numsegs * sizeof(seg_t), PU_LEVEL, 0);
+ 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;
+ }
+
+ W_ReleaseLumpNum(lump);
+}
+
+
+/*
+=================
+=
+= 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;
+ 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);
+ }
+
+ W_ReleaseLumpNum(lump);
+}
+
+
+/*
+=================
+=
+= 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);
+ 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 = NULL;
+ }
+
+ W_ReleaseLumpNum(lump);
+}
+
+
+/*
+=================
+=
+= P_LoadNodes
+=
+=================
+*/
+
+void P_LoadNodes(int lump)
+{
+ byte *data;
+ int i, j, 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;
+ }
+ }
+
+ W_ReleaseLumpNum(lump);
+}
+
+
+
+/*
+=================
+=
+= P_LoadThings
+=
+=================
+*/
+
+void P_LoadThings(int lump)
+{
+ byte *data;
+ int i;
+ mapthing_t spawnthing;
+ mapthing_t *mt;
+ int numthings;
+
+ data = W_CacheLumpNum(lump, PU_STATIC);
+ numthings = W_LumpLength(lump) / sizeof(mapthing_t);
+
+ mt = (mapthing_t *) data;
+ for (i = 0; i < numthings; i++, mt++)
+ {
+ spawnthing.x = SHORT(mt->x);
+ spawnthing.y = SHORT(mt->y);
+ spawnthing.angle = SHORT(mt->angle);
+ spawnthing.type = SHORT(mt->type);
+ spawnthing.options = SHORT(mt->options);
+ P_SpawnMapThing(&spawnthing);
+ }
+
+ W_ReleaseLumpNum(lump);
+}
+
+
+
+/*
+=================
+=
+= 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, *v2;
+
+ numlines = W_LumpLength(lump) / sizeof(maplinedef_t);
+ lines = Z_Malloc(numlines * sizeof(line_t), PU_LEVEL, 0);
+ 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;
+ }
+
+ W_ReleaseLumpNum(lump);
+}
+
+
+/*
+=================
+=
+= 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);
+ 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)];
+ }
+
+ W_ReleaseLumpNum(lump);
+}
+
+
+
+/*
+=================
+=
+= P_LoadBlockMap
+=
+=================
+*/
+
+void P_LoadBlockMap(int lump)
+{
+ int i, count;
+ int lumplen;
+
+ lumplen = W_LumpLength(lump);
+
+ blockmaplump = Z_Malloc(lumplen, PU_LEVEL, NULL);
+ W_ReadLump(lump, blockmaplump);
+ blockmap = blockmaplump + 4;
+
+ // Swap all short integers to native byte ordering:
+
+ count = lumplen / 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);
+ 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, j, 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("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;
+ int parm;
+ char lumpname[9];
+ int lumpnum;
+ mobj_t *mobj;
+
+ totalkills = totalitems = totalsecret = 0;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ players[i].killcount = players[i].secretcount
+ = players[i].itemcount = 0;
+ }
+ players[consoleplayer].viewz = 1; // will be set by player think
+
+ S_Start(); // make sure all sounds are stopped before Z_FreeTags
+
+ Z_FreeTags(PU_LEVEL, PU_PURGELEVEL - 1);
+
+ P_InitThinkers();
+
+//
+// look for a regular (development) map first
+//
+ lumpname[0] = 'E';
+ lumpname[1] = '0' + episode;
+ lumpname[2] = 'M';
+ lumpname[3] = '0' + map;
+ lumpname[4] = 0;
+ leveltime = 0;
+
+ lumpnum = W_GetNumForName(lumpname);
+
+// 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_InitAmbientSound();
+ P_InitMonsters();
+ P_OpenWeapons();
+ P_LoadThings(lumpnum + ML_THINGS);
+ P_CloseWeapons();
+
+//
+// if deathmatch, randomly spawn the active players
+//
+ TimerGame = 0;
+ if (deathmatch)
+ {
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ { // must give a player spot before deathmatchspawn
+ mobj = P_SpawnMobj(playerstarts[i].x << 16,
+ playerstarts[i].y << 16, 0, MT_PLAYER);
+ players[i].mo = mobj;
+ G_DeathMatchSpawnPlayer(i);
+ P_RemoveMobj(mobj);
+ }
+ }
+ parm = M_CheckParm("-timer");
+ if (parm && parm < myargc - 1)
+ {
+ TimerGame = atoi(myargv[parm + 1]) * 35 * 60;
+ }
+ }
+
+// set up world state
+ P_SpawnSpecials();
+
+// build subsector connect matrix
+// P_ConnectSubsectors ();
+
+// preload graphics
+ if (precache)
+ R_PrecacheLevel();
+
+//printf ("free memory: 0x%x\n", Z_FreeMemory());
+
+}
+
+
+/*
+=================
+=
+= P_Init
+=
+=================
+*/
+
+void P_Init(void)
+{
+ P_InitSwitchList();
+ P_InitPicAnims();
+ P_InitTerrainTypes();
+ P_InitLava();
+ R_InitSprites(sprnames);
+}
diff --git a/src/heretic/p_sight.c b/src/heretic/p_sight.c
new file mode 100644
index 00000000..002b32a9
--- /dev/null
+++ b/src/heretic/p_sight.c
@@ -0,0 +1,363 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+// P_sight.c
+
+#include <stdlib.h>
+
+#include "doomdef.h"
+#include "p_local.h"
+
+/*
+==============================================================================
+
+ P_CheckSight
+
+This uses specialized forms of the maputils routines for optimized performance
+
+==============================================================================
+*/
+
+fixed_t sightzstart; // eye z of looker
+fixed_t topslope, bottomslope; // slopes to top and bottom of target
+
+int sightcounts[3];
+
+/*
+==============
+=
+= PTR_SightTraverse
+=
+==============
+*/
+
+boolean PTR_SightTraverse(intercept_t * in)
+{
+ line_t *li;
+ fixed_t slope;
+
+ li = in->d.line;
+
+//
+// crosses a two sided line
+//
+ P_LineOpening(li);
+
+ if (openbottom >= opentop) // quick test for totally closed doors
+ return false; // stop
+
+ if (li->frontsector->floorheight != li->backsector->floorheight)
+ {
+ slope = FixedDiv(openbottom - sightzstart, in->frac);
+ if (slope > bottomslope)
+ bottomslope = slope;
+ }
+
+ if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
+ {
+ slope = FixedDiv(opentop - sightzstart, in->frac);
+ if (slope < topslope)
+ topslope = slope;
+ }
+
+ if (topslope <= bottomslope)
+ return false; // stop
+
+ return true; // keep going
+}
+
+
+
+/*
+==================
+=
+= P_SightBlockLinesIterator
+=
+===================
+*/
+
+boolean P_SightBlockLinesIterator(int x, int y)
+{
+ int offset;
+ short *list;
+ line_t *ld;
+ int s1, s2;
+ divline_t dl;
+
+ 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;
+
+ s1 = P_PointOnDivlineSide(ld->v1->x, ld->v1->y, &trace);
+ s2 = P_PointOnDivlineSide(ld->v2->x, ld->v2->y, &trace);
+ if (s1 == s2)
+ continue; // line isn't crossed
+ P_MakeDivline(ld, &dl);
+ s1 = P_PointOnDivlineSide(trace.x, trace.y, &dl);
+ s2 = P_PointOnDivlineSide(trace.x + trace.dx, trace.y + trace.dy,
+ &dl);
+ if (s1 == s2)
+ continue; // line isn't crossed
+
+ // try to early out the check
+ if (!ld->backsector)
+ return false; // stop checking
+
+ // store the line for later intersection testing
+ intercept_p->d.line = ld;
+ intercept_p++;
+
+ }
+
+ return true; // everything was checked
+}
+
+/*
+====================
+=
+= P_SightTraverseIntercepts
+=
+= Returns true if the traverser function returns true for all lines
+====================
+*/
+
+boolean P_SightTraverseIntercepts(void)
+{
+ int count;
+ fixed_t dist;
+ intercept_t *scan, *in;
+ divline_t dl;
+
+ count = intercept_p - intercepts;
+//
+// calculate intercept distance
+//
+ for (scan = intercepts; scan < intercept_p; scan++)
+ {
+ P_MakeDivline(scan->d.line, &dl);
+ scan->frac = P_InterceptVector(&trace, &dl);
+ }
+
+//
+// go through in order
+//
+ in = 0; // shut up compiler warning
+
+ while (count--)
+ {
+ dist = INT_MAX;
+ for (scan = intercepts; scan < intercept_p; scan++)
+ if (scan->frac < dist)
+ {
+ dist = scan->frac;
+ in = scan;
+ }
+
+ if (!PTR_SightTraverse(in))
+ return false; // don't bother going farther
+ in->frac = INT_MAX;
+ }
+
+ return true; // everything was traversed
+}
+
+
+
+/*
+==================
+=
+= P_SightPathTraverse
+=
+= 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
+==================
+*/
+
+boolean P_SightPathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)
+{
+ fixed_t xt1, yt1, xt2, yt2;
+ fixed_t xstep, ystep;
+ fixed_t partial;
+ fixed_t xintercept, yintercept;
+ int mapx, mapy, mapxstep, mapystep;
+ int count;
+
+ 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;
+
+// points should never be out of bounds, but check once instead of
+// each block
+ if (xt1 < 0 || yt1 < 0 || xt1 >= bmapwidth || yt1 >= bmapheight
+ || xt2 < 0 || yt2 < 0 || xt2 >= bmapwidth || yt2 >= bmapheight)
+ return false;
+
+ if (xt2 > xt1)
+ {
+ mapxstep = 1;
+ partial = FRACUNIT - ((x1 >> MAPBTOFRAC) & (FRACUNIT - 1));
+ ystep = FixedDiv(y2 - y1, abs(x2 - x1));
+ }
+ else if (xt2 < xt1)
+ {
+ mapxstep = -1;
+ partial = (x1 >> MAPBTOFRAC) & (FRACUNIT - 1);
+ ystep = FixedDiv(y2 - y1, 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, abs(y2 - y1));
+ }
+ else if (yt2 < yt1)
+ {
+ mapystep = -1;
+ partial = (y1 >> MAPBTOFRAC) & (FRACUNIT - 1);
+ xstep = FixedDiv(x2 - x1, 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 (!P_SightBlockLinesIterator(mapx, mapy))
+ {
+ sightcounts[1]++;
+ 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;
+ }
+
+ }
+
+
+//
+// couldn't early out, so go through the sorted list
+//
+ sightcounts[2]++;
+
+ return P_SightTraverseIntercepts();
+}
+
+
+
+/*
+=====================
+=
+= P_CheckSight
+=
+= Returns true if a straight line between t1 and t2 is unobstructed
+= look from eyes of t1 to any part of t2
+=
+=====================
+*/
+
+boolean P_CheckSight(mobj_t * t1, mobj_t * t2)
+{
+ int s1, s2;
+ int pnum, bytenum, bitnum;
+
+//
+// check for trivial rejection
+//
+ s1 = (t1->subsector->sector - sectors);
+ s2 = (t2->subsector->sector - sectors);
+ pnum = s1 * numsectors + s2;
+ bytenum = pnum >> 3;
+ bitnum = 1 << (pnum & 7);
+
+ if (rejectmatrix[bytenum] & bitnum)
+ {
+ sightcounts[0]++;
+ return false; // can't possibly be connected
+ }
+
+//
+// check precisely
+//
+ sightzstart = t1->z + t1->height - (t1->height >> 2);
+ topslope = (t2->z + t2->height) - sightzstart;
+ bottomslope = (t2->z) - sightzstart;
+
+ return P_SightPathTraverse(t1->x, t1->y, t2->x, t2->y);
+}
diff --git a/src/heretic/p_spec.c b/src/heretic/p_spec.c
new file mode 100644
index 00000000..923d1f32
--- /dev/null
+++ b/src/heretic/p_spec.c
@@ -0,0 +1,1307 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// P_Spec.c
+
+#include "doomdef.h"
+#include "deh_str.h"
+#include "i_system.h"
+#include "i_timer.h"
+#include "m_random.h"
+#include "p_local.h"
+#include "s_sound.h"
+#include "v_video.h"
+
+// Macros
+
+#define MAX_AMBIENT_SFX 8 // Per level
+
+// Types
+
+typedef enum
+{
+ afxcmd_play, // (sound)
+ afxcmd_playabsvol, // (sound, volume)
+ afxcmd_playrelvol, // (sound, volume)
+ afxcmd_delay, // (ticks)
+ afxcmd_delayrand, // (andbits)
+ afxcmd_end // ()
+} afxcmd_t;
+
+// Data
+
+int *LevelAmbientSfx[MAX_AMBIENT_SFX];
+int *AmbSfxPtr;
+int AmbSfxCount;
+int AmbSfxTics;
+int AmbSfxVolume;
+
+int AmbSndSeqInit[] = { // Startup
+ afxcmd_end
+};
+int AmbSndSeq1[] = { // Scream
+ afxcmd_play, sfx_amb1,
+ afxcmd_end
+};
+int AmbSndSeq2[] = { // Squish
+ afxcmd_play, sfx_amb2,
+ afxcmd_end
+};
+int AmbSndSeq3[] = { // Drops
+ afxcmd_play, sfx_amb3,
+ afxcmd_delay, 16,
+ afxcmd_delayrand, 31,
+ afxcmd_play, sfx_amb7,
+ afxcmd_delay, 16,
+ afxcmd_delayrand, 31,
+ afxcmd_play, sfx_amb3,
+ afxcmd_delay, 16,
+ afxcmd_delayrand, 31,
+ afxcmd_play, sfx_amb7,
+ afxcmd_delay, 16,
+ afxcmd_delayrand, 31,
+ afxcmd_play, sfx_amb3,
+ afxcmd_delay, 16,
+ afxcmd_delayrand, 31,
+ afxcmd_play, sfx_amb7,
+ afxcmd_delay, 16,
+ afxcmd_delayrand, 31,
+ afxcmd_end
+};
+int AmbSndSeq4[] = { // SlowFootSteps
+ afxcmd_play, sfx_amb4,
+ afxcmd_delay, 15,
+ afxcmd_playrelvol, sfx_amb11, -3,
+ afxcmd_delay, 15,
+ afxcmd_playrelvol, sfx_amb4, -3,
+ afxcmd_delay, 15,
+ afxcmd_playrelvol, sfx_amb11, -3,
+ afxcmd_delay, 15,
+ afxcmd_playrelvol, sfx_amb4, -3,
+ afxcmd_delay, 15,
+ afxcmd_playrelvol, sfx_amb11, -3,
+ afxcmd_delay, 15,
+ afxcmd_playrelvol, sfx_amb4, -3,
+ afxcmd_delay, 15,
+ afxcmd_playrelvol, sfx_amb11, -3,
+ afxcmd_end
+};
+int AmbSndSeq5[] = { // Heartbeat
+ afxcmd_play, sfx_amb5,
+ afxcmd_delay, 35,
+ afxcmd_play, sfx_amb5,
+ afxcmd_delay, 35,
+ afxcmd_play, sfx_amb5,
+ afxcmd_delay, 35,
+ afxcmd_play, sfx_amb5,
+ afxcmd_end
+};
+int AmbSndSeq6[] = { // Bells
+ afxcmd_play, sfx_amb6,
+ afxcmd_delay, 17,
+ afxcmd_playrelvol, sfx_amb6, -8,
+ afxcmd_delay, 17,
+ afxcmd_playrelvol, sfx_amb6, -8,
+ afxcmd_delay, 17,
+ afxcmd_playrelvol, sfx_amb6, -8,
+ afxcmd_end
+};
+int AmbSndSeq7[] = { // Growl
+ afxcmd_play, sfx_bstsit,
+ afxcmd_end
+};
+int AmbSndSeq8[] = { // Magic
+ afxcmd_play, sfx_amb8,
+ afxcmd_end
+};
+int AmbSndSeq9[] = { // Laughter
+ afxcmd_play, sfx_amb9,
+ afxcmd_delay, 16,
+ afxcmd_playrelvol, sfx_amb9, -4,
+ afxcmd_delay, 16,
+ afxcmd_playrelvol, sfx_amb9, -4,
+ afxcmd_delay, 16,
+ afxcmd_playrelvol, sfx_amb10, -4,
+ afxcmd_delay, 16,
+ afxcmd_playrelvol, sfx_amb10, -4,
+ afxcmd_delay, 16,
+ afxcmd_playrelvol, sfx_amb10, -4,
+ afxcmd_end
+};
+int AmbSndSeq10[] = { // FastFootsteps
+ afxcmd_play, sfx_amb4,
+ afxcmd_delay, 8,
+ afxcmd_playrelvol, sfx_amb11, -3,
+ afxcmd_delay, 8,
+ afxcmd_playrelvol, sfx_amb4, -3,
+ afxcmd_delay, 8,
+ afxcmd_playrelvol, sfx_amb11, -3,
+ afxcmd_delay, 8,
+ afxcmd_playrelvol, sfx_amb4, -3,
+ afxcmd_delay, 8,
+ afxcmd_playrelvol, sfx_amb11, -3,
+ afxcmd_delay, 8,
+ afxcmd_playrelvol, sfx_amb4, -3,
+ afxcmd_delay, 8,
+ afxcmd_playrelvol, sfx_amb11, -3,
+ afxcmd_end
+};
+
+int *AmbientSfx[] = {
+ AmbSndSeq1, // Scream
+ AmbSndSeq2, // Squish
+ AmbSndSeq3, // Drops
+ AmbSndSeq4, // SlowFootsteps
+ AmbSndSeq5, // Heartbeat
+ AmbSndSeq6, // Bells
+ AmbSndSeq7, // Growl
+ AmbSndSeq8, // Magic
+ AmbSndSeq9, // Laughter
+ AmbSndSeq10 // FastFootsteps
+};
+
+animdef_t animdefs[] = {
+ // false = flat
+ // true = texture
+ {false, "FLTWAWA3", "FLTWAWA1", 8}, // Water
+ {false, "FLTSLUD3", "FLTSLUD1", 8}, // Sludge
+ {false, "FLTTELE4", "FLTTELE1", 6}, // Teleport
+ {false, "FLTFLWW3", "FLTFLWW1", 9}, // River - West
+ {false, "FLTLAVA4", "FLTLAVA1", 8}, // Lava
+ {false, "FLATHUH4", "FLATHUH1", 8}, // Super Lava
+ {true, "LAVAFL3", "LAVAFL1", 6}, // Texture: Lavaflow
+ {true, "WATRWAL3", "WATRWAL1", 4}, // Texture: Waterfall
+ {-1}
+};
+
+anim_t anims[MAXANIMS];
+anim_t *lastanim;
+
+int *TerrainTypes;
+struct
+{
+ char *name;
+ int type;
+} TerrainTypeDefs[] =
+{
+ { "FLTWAWA1", FLOOR_WATER },
+ { "FLTFLWW1", FLOOR_WATER },
+ { "FLTLAVA1", FLOOR_LAVA },
+ { "FLATHUH1", FLOOR_LAVA },
+ { "FLTSLUD1", FLOOR_SLUDGE },
+ { "END", -1 }
+};
+
+mobj_t LavaInflictor;
+
+//----------------------------------------------------------------------------
+//
+// PROC P_InitLava
+//
+//----------------------------------------------------------------------------
+
+void P_InitLava(void)
+{
+ memset(&LavaInflictor, 0, sizeof(mobj_t));
+ LavaInflictor.type = MT_PHOENIXFX2;
+ LavaInflictor.flags2 = MF2_FIREDAMAGE | MF2_NODMGTHRUST;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_InitTerrainTypes
+//
+//----------------------------------------------------------------------------
+
+void P_InitTerrainTypes(void)
+{
+ int i;
+ int lump;
+ int size;
+
+ size = (numflats + 1) * sizeof(int);
+ TerrainTypes = Z_Malloc(size, PU_STATIC, 0);
+ memset(TerrainTypes, 0, size);
+ for (i = 0; TerrainTypeDefs[i].type != -1; i++)
+ {
+ lump = W_CheckNumForName(TerrainTypeDefs[i].name);
+ if (lump != -1)
+ {
+ TerrainTypes[lump - firstflat] = TerrainTypeDefs[i].type;
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_InitPicAnims
+//
+//----------------------------------------------------------------------------
+
+void P_InitPicAnims(void)
+{
+ char *startname;
+ char *endname;
+ int i;
+
+ lastanim = anims;
+ for (i = 0; animdefs[i].istexture != -1; i++)
+ {
+ startname = DEH_String(animdefs[i].startname);
+ endname = DEH_String(animdefs[i].endname);
+
+ if (animdefs[i].istexture)
+ { // Texture animation
+ if (R_CheckTextureNumForName(startname) == -1)
+ { // Texture doesn't exist
+ continue;
+ }
+ lastanim->picnum = R_TextureNumForName(endname);
+ lastanim->basepic = R_TextureNumForName(startname);
+ }
+ else
+ { // Flat animation
+ if (W_CheckNumForName(startname) == -1)
+ { // Flat doesn't exist
+ continue;
+ }
+ lastanim->picnum = R_FlatNumForName(endname);
+ lastanim->basepic = R_FlatNumForName(startname);
+ }
+ lastanim->istexture = animdefs[i].istexture;
+ lastanim->numpics = lastanim->picnum - lastanim->basepic + 1;
+ if (lastanim->numpics < 2)
+ {
+ I_Error("P_InitPicAnims: bad cycle from %s to %s",
+ startname, endname);
+ }
+ lastanim->speed = animdefs[i].speed;
+ lastanim++;
+ }
+}
+
+/*
+==============================================================================
+
+ UTILITIES
+
+==============================================================================
+*/
+
+//
+// Will return a side_t* given the number of the current sector,
+// the line number, and the side (0/1) that you want.
+//
+side_t *getSide(int currentSector, int line, int side)
+{
+ return &sides[(sectors[currentSector].lines[line])->sidenum[side]];
+}
+
+//
+// Will return a sector_t* given the number of the current sector,
+// the line number and the side (0/1) that you want.
+//
+sector_t *getSector(int currentSector, int line, int side)
+{
+ return sides[(sectors[currentSector].lines[line])->sidenum[side]].sector;
+}
+
+//
+// Given the sector number and the line number, will tell you whether
+// the line is two-sided or not.
+//
+int twoSided(int sector, int line)
+{
+ return (sectors[sector].lines[line])->flags & ML_TWOSIDED;
+}
+
+//==================================================================
+//
+// Return sector_t * of sector next to current. NULL if not two-sided line
+//
+//==================================================================
+sector_t *getNextSector(line_t * line, sector_t * sec)
+{
+ if (!(line->flags & ML_TWOSIDED))
+ return NULL;
+
+ if (line->frontsector == sec)
+ return line->backsector;
+
+ return line->frontsector;
+}
+
+//==================================================================
+//
+// FIND LOWEST FLOOR HEIGHT IN SURROUNDING SECTORS
+//
+//==================================================================
+fixed_t P_FindLowestFloorSurrounding(sector_t * sec)
+{
+ int i;
+ line_t *check;
+ sector_t *other;
+ fixed_t floor = sec->floorheight;
+
+ for (i = 0; i < sec->linecount; i++)
+ {
+ check = sec->lines[i];
+ other = getNextSector(check, sec);
+ if (!other)
+ continue;
+ if (other->floorheight < floor)
+ floor = other->floorheight;
+ }
+ return floor;
+}
+
+//==================================================================
+//
+// FIND HIGHEST FLOOR HEIGHT IN SURROUNDING SECTORS
+//
+//==================================================================
+fixed_t P_FindHighestFloorSurrounding(sector_t * sec)
+{
+ int i;
+ line_t *check;
+ sector_t *other;
+ fixed_t floor = -500 * FRACUNIT;
+
+ for (i = 0; i < sec->linecount; i++)
+ {
+ check = sec->lines[i];
+ other = getNextSector(check, sec);
+ if (!other)
+ continue;
+ if (other->floorheight > floor)
+ floor = other->floorheight;
+ }
+ return floor;
+}
+
+//==================================================================
+//
+// FIND NEXT HIGHEST FLOOR IN SURROUNDING SECTORS
+//
+//==================================================================
+fixed_t P_FindNextHighestFloor(sector_t * sec, int currentheight)
+{
+ int i;
+ int h;
+ fixed_t min;
+ line_t *check;
+ sector_t *other;
+ fixed_t height = currentheight;
+
+ min = INT_MAX;
+
+ for (i = 0, h = 0; i < sec->linecount; i++)
+ {
+ check = sec->lines[i];
+ other = getNextSector(check, sec);
+
+ if (other != NULL && other->floorheight > height)
+ {
+ if (other->floorheight < min)
+ {
+ min = other->floorheight;
+ }
+
+ ++h;
+ }
+ }
+
+ // Compatibility note, in case of demo desyncs.
+
+ if (h > 20)
+ {
+ fprintf(stderr, "P_FindNextHighestFloor: exceeded Vanilla limit\n");
+ }
+
+ return min;
+}
+
+//==================================================================
+//
+// FIND LOWEST CEILING IN THE SURROUNDING SECTORS
+//
+//==================================================================
+fixed_t P_FindLowestCeilingSurrounding(sector_t * sec)
+{
+ int i;
+ line_t *check;
+ sector_t *other;
+ fixed_t height = INT_MAX;
+
+ for (i = 0; i < sec->linecount; i++)
+ {
+ check = sec->lines[i];
+ other = getNextSector(check, sec);
+ if (!other)
+ continue;
+ if (other->ceilingheight < height)
+ height = other->ceilingheight;
+ }
+ return height;
+}
+
+//==================================================================
+//
+// FIND HIGHEST CEILING IN THE SURROUNDING SECTORS
+//
+//==================================================================
+fixed_t P_FindHighestCeilingSurrounding(sector_t * sec)
+{
+ int i;
+ line_t *check;
+ sector_t *other;
+ fixed_t height = 0;
+
+ for (i = 0; i < sec->linecount; i++)
+ {
+ check = sec->lines[i];
+ other = getNextSector(check, sec);
+ if (!other)
+ continue;
+ if (other->ceilingheight > height)
+ height = other->ceilingheight;
+ }
+ return height;
+}
+
+//==================================================================
+//
+// RETURN NEXT SECTOR # THAT LINE TAG REFERS TO
+//
+//==================================================================
+int P_FindSectorFromLineTag(line_t * line, int start)
+{
+ int i;
+
+ for (i = start + 1; i < numsectors; i++)
+ if (sectors[i].tag == line->tag)
+ return i;
+ return -1;
+}
+
+//==================================================================
+//
+// Find minimum light from an adjacent sector
+//
+//==================================================================
+int P_FindMinSurroundingLight(sector_t * sector, int max)
+{
+ int i;
+ int min;
+ line_t *line;
+ sector_t *check;
+
+ min = max;
+ for (i = 0; i < sector->linecount; i++)
+ {
+ line = sector->lines[i];
+ check = getNextSector(line, sector);
+ if (!check)
+ continue;
+ if (check->lightlevel < min)
+ min = check->lightlevel;
+ }
+ return min;
+}
+
+/*
+==============================================================================
+
+ EVENTS
+
+Events are operations triggered by using, crossing, or shooting special lines, or by timed thinkers
+
+==============================================================================
+*/
+
+
+
+/*
+===============================================================================
+=
+= P_CrossSpecialLine - TRIGGER
+=
+= Called every time a thing origin is about to cross
+= a line with a non 0 special
+=
+===============================================================================
+*/
+
+void P_CrossSpecialLine(int linenum, int side, mobj_t * thing)
+{
+ line_t *line;
+
+ line = &lines[linenum];
+ if (!thing->player)
+ { // Check if trigger allowed by non-player mobj
+ switch (line->special)
+ {
+ case 39: // Trigger_TELEPORT
+ case 97: // Retrigger_TELEPORT
+ case 4: // Trigger_Raise_Door
+ //case 10: // PLAT DOWN-WAIT-UP-STAY TRIGGER
+ //case 88: // PLAT DOWN-WAIT-UP-STAY RETRIGGER
+ break;
+ default:
+ return;
+ break;
+ }
+ }
+ switch (line->special)
+ {
+ //====================================================
+ // TRIGGERS
+ //====================================================
+ case 2: // Open Door
+ EV_DoDoor(line, open, VDOORSPEED);
+ line->special = 0;
+ break;
+ case 3: // Close Door
+ EV_DoDoor(line, close, VDOORSPEED);
+ line->special = 0;
+ break;
+ case 4: // Raise Door
+ EV_DoDoor(line, normal, VDOORSPEED);
+ line->special = 0;
+ break;
+ case 5: // Raise Floor
+ EV_DoFloor(line, raiseFloor);
+ line->special = 0;
+ break;
+ case 6: // Fast Ceiling Crush & Raise
+ EV_DoCeiling(line, fastCrushAndRaise);
+ line->special = 0;
+ break;
+ case 8: // Trigger_Build_Stairs (8 pixel steps)
+ EV_BuildStairs(line, 8 * FRACUNIT);
+ line->special = 0;
+ break;
+ case 106: // Trigger_Build_Stairs_16 (16 pixel steps)
+ EV_BuildStairs(line, 16 * FRACUNIT);
+ line->special = 0;
+ break;
+ case 10: // PlatDownWaitUp
+ EV_DoPlat(line, downWaitUpStay, 0);
+ line->special = 0;
+ break;
+ case 12: // Light Turn On - brightest near
+ EV_LightTurnOn(line, 0);
+ line->special = 0;
+ break;
+ case 13: // Light Turn On 255
+ EV_LightTurnOn(line, 255);
+ line->special = 0;
+ break;
+ case 16: // Close Door 30
+ EV_DoDoor(line, close30ThenOpen, VDOORSPEED);
+ line->special = 0;
+ break;
+ case 17: // Start Light Strobing
+ EV_StartLightStrobing(line);
+ line->special = 0;
+ break;
+ case 19: // Lower Floor
+ EV_DoFloor(line, lowerFloor);
+ line->special = 0;
+ break;
+ case 22: // Raise floor to nearest height and change texture
+ EV_DoPlat(line, raiseToNearestAndChange, 0);
+ line->special = 0;
+ break;
+ case 25: // Ceiling Crush and Raise
+ EV_DoCeiling(line, crushAndRaise);
+ line->special = 0;
+ break;
+ case 30: // Raise floor to shortest texture height
+ // on either side of lines
+ EV_DoFloor(line, raiseToTexture);
+ line->special = 0;
+ break;
+ case 35: // Lights Very Dark
+ EV_LightTurnOn(line, 35);
+ line->special = 0;
+ break;
+ case 36: // Lower Floor (TURBO)
+ EV_DoFloor(line, turboLower);
+ line->special = 0;
+ break;
+ case 37: // LowerAndChange
+ EV_DoFloor(line, lowerAndChange);
+ line->special = 0;
+ break;
+ case 38: // Lower Floor To Lowest
+ EV_DoFloor(line, lowerFloorToLowest);
+ line->special = 0;
+ break;
+ case 39: // TELEPORT!
+ EV_Teleport(line, side, thing);
+ line->special = 0;
+ break;
+ case 40: // RaiseCeilingLowerFloor
+ EV_DoCeiling(line, raiseToHighest);
+ EV_DoFloor(line, lowerFloorToLowest);
+ line->special = 0;
+ break;
+ case 44: // Ceiling Crush
+ EV_DoCeiling(line, lowerAndCrush);
+ line->special = 0;
+ break;
+ case 52: // EXIT!
+ G_ExitLevel();
+ line->special = 0;
+ break;
+ case 53: // Perpetual Platform Raise
+ EV_DoPlat(line, perpetualRaise, 0);
+ line->special = 0;
+ break;
+ case 54: // Platform Stop
+ EV_StopPlat(line);
+ line->special = 0;
+ break;
+ case 56: // Raise Floor Crush
+ EV_DoFloor(line, raiseFloorCrush);
+ line->special = 0;
+ break;
+ case 57: // Ceiling Crush Stop
+ EV_CeilingCrushStop(line);
+ line->special = 0;
+ break;
+ case 58: // Raise Floor 24
+ EV_DoFloor(line, raiseFloor24);
+ line->special = 0;
+ break;
+ case 59: // Raise Floor 24 And Change
+ EV_DoFloor(line, raiseFloor24AndChange);
+ line->special = 0;
+ break;
+ case 104: // Turn lights off in sector(tag)
+ EV_TurnTagLightsOff(line);
+ line->special = 0;
+ break;
+ case 105: // Trigger_SecretExit
+ G_SecretExitLevel();
+ line->special = 0;
+ break;
+
+ //====================================================
+ // RE-DOABLE TRIGGERS
+ //====================================================
+
+ case 72: // Ceiling Crush
+ EV_DoCeiling(line, lowerAndCrush);
+ break;
+ case 73: // Ceiling Crush and Raise
+ EV_DoCeiling(line, crushAndRaise);
+ break;
+ case 74: // Ceiling Crush Stop
+ EV_CeilingCrushStop(line);
+ break;
+ case 75: // Close Door
+ EV_DoDoor(line, close, VDOORSPEED);
+ break;
+ case 76: // Close Door 30
+ EV_DoDoor(line, close30ThenOpen, VDOORSPEED);
+ break;
+ case 77: // Fast Ceiling Crush & Raise
+ EV_DoCeiling(line, fastCrushAndRaise);
+ break;
+ case 79: // Lights Very Dark
+ EV_LightTurnOn(line, 35);
+ break;
+ case 80: // Light Turn On - brightest near
+ EV_LightTurnOn(line, 0);
+ break;
+ case 81: // Light Turn On 255
+ EV_LightTurnOn(line, 255);
+ break;
+ case 82: // Lower Floor To Lowest
+ EV_DoFloor(line, lowerFloorToLowest);
+ break;
+ case 83: // Lower Floor
+ EV_DoFloor(line, lowerFloor);
+ break;
+ case 84: // LowerAndChange
+ EV_DoFloor(line, lowerAndChange);
+ break;
+ case 86: // Open Door
+ EV_DoDoor(line, open, VDOORSPEED);
+ break;
+ case 87: // Perpetual Platform Raise
+ EV_DoPlat(line, perpetualRaise, 0);
+ break;
+ case 88: // PlatDownWaitUp
+ EV_DoPlat(line, downWaitUpStay, 0);
+ break;
+ case 89: // Platform Stop
+ EV_StopPlat(line);
+ break;
+ case 90: // Raise Door
+ EV_DoDoor(line, normal, VDOORSPEED);
+ break;
+ case 100: // Retrigger_Raise_Door_Turbo
+ EV_DoDoor(line, normal, VDOORSPEED * 3);
+ break;
+ case 91: // Raise Floor
+ EV_DoFloor(line, raiseFloor);
+ break;
+ case 92: // Raise Floor 24
+ EV_DoFloor(line, raiseFloor24);
+ break;
+ case 93: // Raise Floor 24 And Change
+ EV_DoFloor(line, raiseFloor24AndChange);
+ break;
+ case 94: // Raise Floor Crush
+ EV_DoFloor(line, raiseFloorCrush);
+ break;
+ case 95: // Raise floor to nearest height and change texture
+ EV_DoPlat(line, raiseToNearestAndChange, 0);
+ break;
+ case 96: // Raise floor to shortest texture height
+ // on either side of lines
+ EV_DoFloor(line, raiseToTexture);
+ break;
+ case 97: // TELEPORT!
+ EV_Teleport(line, side, thing);
+ break;
+ case 98: // Lower Floor (TURBO)
+ EV_DoFloor(line, turboLower);
+ break;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_ShootSpecialLine
+//
+// Called when a thing shoots a special line.
+//
+//----------------------------------------------------------------------------
+
+void P_ShootSpecialLine(mobj_t * thing, line_t * line)
+{
+ if (!thing->player)
+ { // Check if trigger allowed by non-player mobj
+ switch (line->special)
+ {
+ case 46: // Impact_OpenDoor
+ break;
+ default:
+ return;
+ break;
+ }
+ }
+ switch (line->special)
+ {
+ case 24: // Impact_RaiseFloor
+ EV_DoFloor(line, raiseFloor);
+ P_ChangeSwitchTexture(line, 0);
+ break;
+ case 46: // Impact_OpenDoor
+ EV_DoDoor(line, open, VDOORSPEED);
+ P_ChangeSwitchTexture(line, 1);
+ break;
+ case 47: // Impact_RaiseFloorNear&Change
+ EV_DoPlat(line, raiseToNearestAndChange, 0);
+ P_ChangeSwitchTexture(line, 0);
+ break;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_PlayerInSpecialSector
+//
+// Called every tic frame that the player origin is in a special sector.
+//
+//----------------------------------------------------------------------------
+
+void P_PlayerInSpecialSector(player_t * player)
+{
+ sector_t *sector;
+ static int pushTab[5] = {
+ 2048 * 5,
+ 2048 * 10,
+ 2048 * 25,
+ 2048 * 30,
+ 2048 * 35
+ };
+
+ sector = player->mo->subsector->sector;
+ if (player->mo->z != sector->floorheight)
+ { // Player is not touching the floor
+ return;
+ }
+ switch (sector->special)
+ {
+ case 7: // Damage_Sludge
+ if (!(leveltime & 31))
+ {
+ P_DamageMobj(player->mo, NULL, NULL, 4);
+ }
+ break;
+ case 5: // Damage_LavaWimpy
+ if (!(leveltime & 15))
+ {
+ P_DamageMobj(player->mo, &LavaInflictor, NULL, 5);
+ P_HitFloor(player->mo);
+ }
+ break;
+ case 16: // Damage_LavaHefty
+ if (!(leveltime & 15))
+ {
+ P_DamageMobj(player->mo, &LavaInflictor, NULL, 8);
+ P_HitFloor(player->mo);
+ }
+ break;
+ case 4: // Scroll_EastLavaDamage
+ P_Thrust(player, 0, 2048 * 28);
+ if (!(leveltime & 15))
+ {
+ P_DamageMobj(player->mo, &LavaInflictor, NULL, 5);
+ P_HitFloor(player->mo);
+ }
+ break;
+ case 9: // SecretArea
+ player->secretcount++;
+ sector->special = 0;
+ break;
+ case 11: // Exit_SuperDamage (DOOM E1M8 finale)
+ /*
+ player->cheats &= ~CF_GODMODE;
+ if(!(leveltime&0x1f))
+ {
+ P_DamageMobj(player->mo, NULL, NULL, 20);
+ }
+ if(player->health <= 10)
+ {
+ G_ExitLevel();
+ }
+ */
+ break;
+
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29: // Scroll_North
+ P_Thrust(player, ANG90, pushTab[sector->special - 25]);
+ break;
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24: // Scroll_East
+ P_Thrust(player, 0, pushTab[sector->special - 20]);
+ break;
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ case 34: // Scroll_South
+ P_Thrust(player, ANG270, pushTab[sector->special - 30]);
+ break;
+ case 35:
+ case 36:
+ case 37:
+ case 38:
+ case 39: // Scroll_West
+ P_Thrust(player, ANG180, pushTab[sector->special - 35]);
+ break;
+
+ case 40:
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 45:
+ case 46:
+ case 47:
+ case 48:
+ case 49:
+ case 50:
+ case 51:
+ // Wind specials are handled in (P_mobj):P_XYMovement
+ break;
+
+ case 15: // Friction_Low
+ // Only used in (P_mobj):P_XYMovement and (P_user):P_Thrust
+ break;
+
+ default:
+ I_Error("P_PlayerInSpecialSector: "
+ "unknown special %i", sector->special);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_UpdateSpecials
+//
+// Animate planes, scroll walls, etc.
+//
+//----------------------------------------------------------------------------
+
+void P_UpdateSpecials(void)
+{
+ int i;
+ int pic;
+ anim_t *anim;
+ line_t *line;
+
+ // Animate flats and textures
+ for (anim = anims; anim < lastanim; anim++)
+ {
+ for (i = anim->basepic; i < anim->basepic + anim->numpics; i++)
+ {
+ pic =
+ anim->basepic +
+ ((leveltime / anim->speed + i) % anim->numpics);
+ if (anim->istexture)
+ {
+ texturetranslation[i] = pic;
+ }
+ else
+ {
+ flattranslation[i] = pic;
+ }
+ }
+ }
+ // Update scrolling texture offsets
+ for (i = 0; i < numlinespecials; i++)
+ {
+ line = linespeciallist[i];
+ switch (line->special)
+ {
+ case 48: // Effect_Scroll_Left
+ sides[line->sidenum[0]].textureoffset += FRACUNIT;
+ break;
+ case 99: // Effect_Scroll_Right
+ sides[line->sidenum[0]].textureoffset -= FRACUNIT;
+ break;
+ }
+ }
+ // Handle buttons
+ for (i = 0; i < MAXBUTTONS; i++)
+ {
+ if (buttonlist[i].btimer)
+ {
+ buttonlist[i].btimer--;
+ if (!buttonlist[i].btimer)
+ {
+ switch (buttonlist[i].where)
+ {
+ case top:
+ sides[buttonlist[i].line->sidenum[0]].toptexture =
+ buttonlist[i].btexture;
+ break;
+ case middle:
+ sides[buttonlist[i].line->sidenum[0]].midtexture =
+ buttonlist[i].btexture;
+ break;
+ case bottom:
+ sides[buttonlist[i].line->sidenum[0]].bottomtexture =
+ buttonlist[i].btexture;
+ break;
+ }
+ S_StartSound(buttonlist[i].soundorg, sfx_switch);
+ memset(&buttonlist[i], 0, sizeof(button_t));
+ }
+ }
+ }
+}
+
+//============================================================
+//
+// Special Stuff that can't be categorized
+//
+//============================================================
+int EV_DoDonut(line_t * line)
+{
+ sector_t *s1;
+ sector_t *s2;
+ sector_t *s3;
+ int secnum;
+ int rtn;
+ int i;
+ floormove_t *floor;
+
+ secnum = -1;
+ rtn = 0;
+ while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0)
+ {
+ s1 = &sectors[secnum];
+
+ // ALREADY MOVING? IF SO, KEEP GOING...
+ if (s1->specialdata)
+ continue;
+
+ rtn = 1;
+ s2 = getNextSector(s1->lines[0], s1);
+ for (i = 0; i < s2->linecount; i++)
+ {
+ // Note: This was originally part of the following test:
+ // (!s2->lines[i]->flags & ML_TWOSIDED) ||
+ // Due to the apparent mistaken formatting, this can never be
+ // true.
+
+ if (s2->lines[i]->backsector == s1)
+ continue;
+ s3 = s2->lines[i]->backsector;
+
+ //
+ // Spawn rising slime
+ //
+ floor = Z_Malloc(sizeof(*floor), PU_LEVSPEC, 0);
+ P_AddThinker(&floor->thinker);
+ s2->specialdata = floor;
+ floor->thinker.function = T_MoveFloor;
+ floor->type = donutRaise;
+ floor->crush = false;
+ floor->direction = 1;
+ floor->sector = s2;
+ floor->speed = FLOORSPEED / 2;
+ floor->texture = s3->floorpic;
+ floor->newspecial = 0;
+ floor->floordestheight = s3->floorheight;
+
+ //
+ // Spawn lowering donut-hole
+ //
+ floor = Z_Malloc(sizeof(*floor), PU_LEVSPEC, 0);
+ P_AddThinker(&floor->thinker);
+ s1->specialdata = floor;
+ floor->thinker.function = T_MoveFloor;
+ floor->type = lowerFloor;
+ floor->crush = false;
+ floor->direction = -1;
+ floor->sector = s1;
+ floor->speed = FLOORSPEED / 2;
+ floor->floordestheight = s3->floorheight;
+ break;
+ }
+ }
+ return rtn;
+}
+
+/*
+==============================================================================
+
+ SPECIAL SPAWNING
+
+==============================================================================
+*/
+/*
+================================================================================
+= P_SpawnSpecials
+=
+= After the map has been loaded, scan for specials that
+= spawn thinkers
+=
+===============================================================================
+*/
+
+short numlinespecials;
+line_t *linespeciallist[MAXLINEANIMS];
+
+void P_SpawnSpecials(void)
+{
+ sector_t *sector;
+ int i;
+
+ //
+ // Init special SECTORs
+ //
+ sector = sectors;
+ for (i = 0; i < numsectors; i++, sector++)
+ {
+ if (!sector->special)
+ continue;
+ switch (sector->special)
+ {
+ case 1: // FLICKERING LIGHTS
+ P_SpawnLightFlash(sector);
+ break;
+ case 2: // STROBE FAST
+ P_SpawnStrobeFlash(sector, FASTDARK, 0);
+ break;
+ case 3: // STROBE SLOW
+ P_SpawnStrobeFlash(sector, SLOWDARK, 0);
+ break;
+ case 4: // STROBE FAST/DEATH SLIME
+ P_SpawnStrobeFlash(sector, FASTDARK, 0);
+ sector->special = 4;
+ break;
+ case 8: // GLOWING LIGHT
+ P_SpawnGlowingLight(sector);
+ break;
+ case 9: // SECRET SECTOR
+ totalsecret++;
+ break;
+ case 10: // DOOR CLOSE IN 30 SECONDS
+ P_SpawnDoorCloseIn30(sector);
+ break;
+ case 12: // SYNC STROBE SLOW
+ P_SpawnStrobeFlash(sector, SLOWDARK, 1);
+ break;
+ case 13: // SYNC STROBE FAST
+ P_SpawnStrobeFlash(sector, FASTDARK, 1);
+ break;
+ case 14: // DOOR RAISE IN 5 MINUTES
+ P_SpawnDoorRaiseIn5Mins(sector, i);
+ break;
+ }
+ }
+
+
+ //
+ // Init line EFFECTs
+ //
+ numlinespecials = 0;
+ for (i = 0; i < numlines; i++)
+ switch (lines[i].special)
+ {
+ case 48: // Effect_Scroll_Left
+ case 99: // Effect_Scroll_Right
+ linespeciallist[numlinespecials] = &lines[i];
+ numlinespecials++;
+ break;
+ }
+
+ //
+ // Init other misc stuff
+ //
+ for (i = 0; i < MAXCEILINGS; i++)
+ activeceilings[i] = NULL;
+ for (i = 0; i < MAXPLATS; i++)
+ activeplats[i] = NULL;
+ for (i = 0; i < MAXBUTTONS; i++)
+ memset(&buttonlist[i], 0, sizeof(button_t));
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_InitAmbientSound
+//
+//----------------------------------------------------------------------------
+
+void P_InitAmbientSound(void)
+{
+ AmbSfxCount = 0;
+ AmbSfxVolume = 0;
+ AmbSfxTics = 10 * TICRATE;
+ AmbSfxPtr = AmbSndSeqInit;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_AddAmbientSfx
+//
+// Called by (P_mobj):P_SpawnMapThing during (P_setup):P_SetupLevel.
+//
+//----------------------------------------------------------------------------
+
+void P_AddAmbientSfx(int sequence)
+{
+ if (AmbSfxCount == MAX_AMBIENT_SFX)
+ {
+ I_Error("Too many ambient sound sequences");
+ }
+ LevelAmbientSfx[AmbSfxCount++] = AmbientSfx[sequence];
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_AmbientSound
+//
+// Called every tic by (P_tick):P_Ticker.
+//
+//----------------------------------------------------------------------------
+
+void P_AmbientSound(void)
+{
+ afxcmd_t cmd;
+ int sound;
+ boolean done;
+
+ if (!AmbSfxCount)
+ { // No ambient sound sequences on current level
+ return;
+ }
+ if (--AmbSfxTics)
+ {
+ return;
+ }
+ done = false;
+ do
+ {
+ cmd = *AmbSfxPtr++;
+ switch (cmd)
+ {
+ case afxcmd_play:
+ AmbSfxVolume = P_Random() >> 2;
+ S_StartSoundAtVolume(NULL, *AmbSfxPtr++, AmbSfxVolume);
+ break;
+ case afxcmd_playabsvol:
+ sound = *AmbSfxPtr++;
+ AmbSfxVolume = *AmbSfxPtr++;
+ S_StartSoundAtVolume(NULL, sound, AmbSfxVolume);
+ break;
+ case afxcmd_playrelvol:
+ sound = *AmbSfxPtr++;
+ AmbSfxVolume += *AmbSfxPtr++;
+ if (AmbSfxVolume < 0)
+ {
+ AmbSfxVolume = 0;
+ }
+ else if (AmbSfxVolume > 127)
+ {
+ AmbSfxVolume = 127;
+ }
+ S_StartSoundAtVolume(NULL, sound, AmbSfxVolume);
+ break;
+ case afxcmd_delay:
+ AmbSfxTics = *AmbSfxPtr++;
+ done = true;
+ break;
+ case afxcmd_delayrand:
+ AmbSfxTics = P_Random() & (*AmbSfxPtr++);
+ done = true;
+ break;
+ case afxcmd_end:
+ AmbSfxTics = 6 * TICRATE + P_Random();
+ AmbSfxPtr = LevelAmbientSfx[P_Random() % AmbSfxCount];
+ done = true;
+ break;
+ default:
+ I_Error("P_AmbientSound: Unknown afxcmd %d", cmd);
+ break;
+ }
+ }
+ while (done == false);
+}
diff --git a/src/heretic/p_spec.h b/src/heretic/p_spec.h
new file mode 100644
index 00000000..7f5e2c43
--- /dev/null
+++ b/src/heretic/p_spec.h
@@ -0,0 +1,398 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// P_spec.h
+
+/*
+===============================================================================
+
+ P_SPEC
+
+===============================================================================
+*/
+
+//
+// Animating textures and planes
+//
+typedef struct
+{
+ boolean istexture;
+ int picnum;
+ int basepic;
+ int numpics;
+ int speed;
+} anim_t;
+
+//
+// source animation definition
+//
+typedef struct
+{
+ boolean istexture; // if false, it's a flat
+ char endname[9];
+ char startname[9];
+ int speed;
+} animdef_t;
+
+#define MAXANIMS 32
+
+extern anim_t anims[MAXANIMS], *lastanim;
+extern int *TerrainTypes;
+
+//
+// Animating line specials
+//
+#define MAXLINEANIMS 64
+extern short numlinespecials;
+extern line_t *linespeciallist[MAXLINEANIMS];
+
+// Define values for map objects
+#define MO_TELEPORTMAN 14
+
+// at game start
+void P_InitPicAnims(void);
+void P_InitTerrainTypes(void);
+void P_InitLava(void);
+
+// at map load
+void P_SpawnSpecials(void);
+void P_InitAmbientSound(void);
+void P_AddAmbientSfx(int sequence);
+
+// every tic
+void P_UpdateSpecials(void);
+void P_AmbientSound(void);
+
+// when needed
+boolean P_UseSpecialLine(mobj_t * thing, line_t * line);
+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;
+ 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 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;
+ void *soundorg;
+} button_t;
+
+#define MAXSWITCHES 50 // max # of wall switches in a level
+#define MAXBUTTONS 16 // 4 players, 4 buttons each at once, max.
+#define BUTTONTIME 35 // 1 second
+
+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
+} 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;
+ 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
+{
+ normal,
+ close30ThenOpen,
+ close,
+ open,
+ raiseIn5Mins
+} vldoor_e;
+
+typedef struct
+{
+ thinker_t thinker;
+ vldoor_e type;
+ sector_t *sector;
+ fixed_t topheight;
+ fixed_t speed;
+ int direction; // 1 = up, 0 = waiting at top, -1 = down
+ int topwait; // tics to wait at the top
+ // (keep in case a door going down is reset)
+ int topcountdown; // when it reaches 0, start going down
+} 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, fixed_t speed);
+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
+} ceiling_e;
+
+typedef struct
+{
+ thinker_t thinker;
+ ceiling_e type;
+ sector_t *sector;
+ fixed_t bottomheight, topheight;
+ fixed_t speed;
+ boolean crush;
+ int direction; // 1 = up, 0 = waiting, -1 = down
+ int tag; // ID
+ 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
+{
+ lowerFloor, // lower floor to highest surrounding floor
+ lowerFloorToLowest, // lower floor to lowest surrounding floor
+ turboLower, // lower floor to highest surrounding floor VERY FAST
+ raiseFloor, // raise floor to lowest surrounding CEILING
+ raiseFloorToNearest, // raise floor to next highest surrounding floor
+ raiseToTexture, // raise floor to shortest height texture around it
+ lowerAndChange, // lower floor to lowest surrounding floor and change
+ // floorpic
+ raiseFloor24,
+ raiseFloor24AndChange,
+ raiseFloorCrush,
+ donutRaise,
+ raiseBuildStep // One step of a staircase
+} floor_e;
+
+typedef struct
+{
+ thinker_t thinker;
+ floor_e type;
+ 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, boolean crush, int floorOrCeiling,
+ int direction);
+
+int EV_BuildStairs(line_t * line, fixed_t stepDelta);
+int EV_DoFloor(line_t * line, floor_e floortype);
+void T_MoveFloor(floormove_t * floor);
+
+/*
+===============================================================================
+
+ P_TELEPT
+
+===============================================================================
+*/
+
+boolean P_Teleport(mobj_t * thing, fixed_t x, fixed_t y, angle_t angle);
+boolean EV_Teleport(line_t * line, int side, mobj_t * thing);
diff --git a/src/heretic/p_switch.c b/src/heretic/p_switch.c
new file mode 100644
index 00000000..2ec758b6
--- /dev/null
+++ b/src/heretic/p_switch.c
@@ -0,0 +1,414 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+#include "doomdef.h"
+#include "deh_str.h"
+#include "i_system.h"
+#include "p_local.h"
+#include "s_sound.h"
+#include "v_video.h"
+
+//==================================================================
+//
+// CHANGE THE TEXTURE OF A WALL SWITCH TO ITS OPPOSITE
+//
+//==================================================================
+switchlist_t alphSwitchList[] = {
+ {"SW1OFF", "SW1ON", 1},
+ {"SW2OFF", "SW2ON", 1},
+
+/*
+ {"SW1CTY", "SW2CTY", 1},
+ {"SW1ORGRY", "SW2ORGRY", 1},
+ {"SW1GRSTN", "SW2GRSTN", 1},
+ {"SW1SNDP", "SW2SNDP", 1},
+ {"SW1SPINE", "SW2SPINE", 1},
+ {"SW1SQPEB", "SW2SQPEB", 1},
+ {"SW1TRST1", "SW2TRST1", 1},
+ {"SW1CSTL", "SW2CSTL", 1},
+ {"SW1MOSS", "SW2MOSS", 1},
+ {"SW1SNDSQ", "SW2SNDSQ", 1},
+ {"SW1RED", "SW2RED", 1},
+ {"SW1WOOD", "SW2WOOD", 1},
+ {"SW1BROWN", "SW2BROWN", 1},
+
+ {"SW1TRST2", "SW2TRST2", 2},
+ {"SW1MSC", "SW2MSC", 2},
+ {"SW1MSC2", "SW2MSC2", 2},
+ {"SW1GRDMD", "SW2GRDMD", 2},
+*/
+
+#if 0
+ {"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},
+
+ {"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},
+#endif
+ {"\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 != shareware)
+ episode = 2;
+
+ 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(DEH_String(alphSwitchList[i].name1));
+ switchlist[index++] =
+ R_TextureNumForName(DEH_String(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;
+
+ 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 = &line->frontsector->soundorg;
+ return;
+ }
+
+ I_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_switch;
+ //if (line->special == 11) // EXIT SWITCH?
+ // 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
+===============================================================================
+*/
+
+boolean P_UseSpecialLine(mobj_t * thing, line_t * line)
+{
+ //
+ // Switches that other things can activate
+ //
+ if (!thing->player)
+ {
+ if (line->flags & ML_SECRET)
+ return false; // never open secret doors
+ switch (line->special)
+ {
+ case 1: // MANUAL DOOR RAISE
+ case 32: // MANUAL BLUE
+ case 33: // MANUAL RED
+ case 34: // MANUAL YELLOW
+ break;
+ default:
+ return false;
+ }
+ }
+
+ //
+ // 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
+ EV_VerticalDoor(line, thing);
+ break;
+ //===============================================
+ // SWITCHES
+ //===============================================
+ case 7: // Switch_Build_Stairs (8 pixel steps)
+ if (EV_BuildStairs(line, 8 * FRACUNIT))
+ {
+ P_ChangeSwitchTexture(line, 0);
+ }
+ break;
+ case 107: // Switch_Build_Stairs_16 (16 pixel steps)
+ if (EV_BuildStairs(line, 16 * FRACUNIT))
+ {
+ P_ChangeSwitchTexture(line, 0);
+ }
+ break;
+ case 9: // Change Donut
+ if (EV_DoDonut(line))
+ P_ChangeSwitchTexture(line, 0);
+ break;
+ case 11: // Exit level
+ G_ExitLevel();
+ P_ChangeSwitchTexture(line, 0);
+ 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, normal, VDOORSPEED))
+ 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: // Lower Ceiling And Crush
+ if (EV_DoCeiling(line, lowerAndCrush))
+ P_ChangeSwitchTexture(line, 0);
+ break;
+ case 50: // Close Door
+ if (EV_DoDoor(line, close, VDOORSPEED))
+ P_ChangeSwitchTexture(line, 0);
+ break;
+ case 51: // Secret EXIT
+ G_SecretExitLevel();
+ P_ChangeSwitchTexture(line, 0);
+ 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, open, VDOORSPEED))
+ P_ChangeSwitchTexture(line, 0);
+ break;
+ //===============================================
+ // BUTTONS
+ //===============================================
+ case 42: // Close Door
+ if (EV_DoDoor(line, close, VDOORSPEED))
+ 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, open, VDOORSPEED))
+ 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, normal, VDOORSPEED))
+ 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;
+ }
+
+ return true;
+}
diff --git a/src/heretic/p_telept.c b/src/heretic/p_telept.c
new file mode 100644
index 00000000..91d10f9b
--- /dev/null
+++ b/src/heretic/p_telept.c
@@ -0,0 +1,173 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// P_telept.c
+
+#include "doomdef.h"
+#include "p_local.h"
+#include "s_sound.h"
+#include "v_video.h"
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_Teleport
+//
+//----------------------------------------------------------------------------
+
+boolean P_Teleport(mobj_t * thing, fixed_t x, fixed_t y, angle_t angle)
+{
+ fixed_t oldx;
+ fixed_t oldy;
+ fixed_t oldz;
+ fixed_t aboveFloor;
+ fixed_t fogDelta;
+ player_t *player;
+ unsigned an;
+ mobj_t *fog;
+
+ oldx = thing->x;
+ oldy = thing->y;
+ oldz = thing->z;
+ aboveFloor = thing->z - thing->floorz;
+ if (!P_TeleportMove(thing, x, y))
+ {
+ return (false);
+ }
+ if (thing->player)
+ {
+ player = thing->player;
+ if (player->powers[pw_flight] && aboveFloor)
+ {
+ thing->z = thing->floorz + aboveFloor;
+ if (thing->z + thing->height > thing->ceilingz)
+ {
+ thing->z = thing->ceilingz - thing->height;
+ }
+ player->viewz = thing->z + player->viewheight;
+ }
+ else
+ {
+ thing->z = thing->floorz;
+ player->viewz = thing->z + player->viewheight;
+ player->lookdir = 0;
+ }
+ }
+ else if (thing->flags & MF_MISSILE)
+ {
+ thing->z = thing->floorz + aboveFloor;
+ if (thing->z + thing->height > thing->ceilingz)
+ {
+ thing->z = thing->ceilingz - thing->height;
+ }
+ }
+ else
+ {
+ thing->z = thing->floorz;
+ }
+ // Spawn teleport fog at source and destination
+ fogDelta = thing->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT;
+ fog = P_SpawnMobj(oldx, oldy, oldz + fogDelta, MT_TFOG);
+ S_StartSound(fog, sfx_telept);
+ an = angle >> ANGLETOFINESHIFT;
+ fog = P_SpawnMobj(x + 20 * finecosine[an],
+ y + 20 * finesine[an], thing->z + fogDelta, MT_TFOG);
+ S_StartSound(fog, sfx_telept);
+ if (thing->player && !thing->player->powers[pw_weaponlevel2])
+ { // Freeze player for about .5 sec
+ thing->reactiontime = 18;
+ }
+ thing->angle = angle;
+ if (thing->flags2 & MF2_FOOTCLIP
+ && P_GetThingFloorType(thing) != FLOOR_SOLID)
+ {
+ thing->flags2 |= MF2_FEETARECLIPPED;
+ }
+ else if (thing->flags2 & MF2_FEETARECLIPPED)
+ {
+ thing->flags2 &= ~MF2_FEETARECLIPPED;
+ }
+ if (thing->flags & MF_MISSILE)
+ {
+ angle >>= ANGLETOFINESHIFT;
+ thing->momx = FixedMul(thing->info->speed, finecosine[angle]);
+ thing->momy = FixedMul(thing->info->speed, finesine[angle]);
+ }
+ else
+ {
+ thing->momx = thing->momy = thing->momz = 0;
+ }
+ return (true);
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC EV_Teleport
+//
+//----------------------------------------------------------------------------
+
+boolean EV_Teleport(line_t * line, int side, mobj_t * thing)
+{
+ int i;
+ int tag;
+ mobj_t *m;
+ thinker_t *thinker;
+ sector_t *sector;
+
+ if (thing->flags2 & MF2_NOTELEPORT)
+ {
+ return (false);
+ }
+ if (side == 1)
+ { // Don't teleport when crossing back side
+ return (false);
+ }
+ 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)
+ {
+ if (thinker->function != P_MobjThinker)
+ { // Not a mobj
+ continue;
+ }
+ m = (mobj_t *) thinker;
+ if (m->type != MT_TELEPORTMAN)
+ { // Not a teleportman
+ continue;
+ }
+ sector = m->subsector->sector;
+ if (sector - sectors != i)
+ { // Wrong sector
+ continue;
+ }
+ return (P_Teleport(thing, m->x, m->y, m->angle));
+ }
+ }
+ }
+ return (false);
+}
diff --git a/src/heretic/p_tick.c b/src/heretic/p_tick.c
new file mode 100644
index 00000000..9758be3a
--- /dev/null
+++ b/src/heretic/p_tick.c
@@ -0,0 +1,668 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// P_tick.c
+
+#include "doomdef.h"
+#include "i_system.h"
+#include "p_local.h"
+#include "v_video.h"
+
+int leveltime;
+int TimerGame;
+
+/*
+====================
+=
+= P_ArchivePlayers
+=
+====================
+*/
+
+void P_ArchivePlayers(void)
+{
+ int i;
+ int j;
+ player_t dest;
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (!playeringame[i])
+ {
+ continue;
+ }
+ memcpy(&dest, &players[i], 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);
+ }
+ }
+ SV_Write(&dest, sizeof(player_t));
+ }
+}
+
+/*
+====================
+=
+= P_UnArchivePlayers
+=
+====================
+*/
+
+void P_UnArchivePlayers(void)
+{
+ int i, j;
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (!playeringame[i])
+ continue;
+ memcpy(&players[i], save_p, sizeof(player_t));
+ save_p += sizeof(player_t);
+ players[i].mo = NULL; // will be set when unarc thinker
+ players[i].message = NULL;
+ players[i].attacker = NULL;
+ for (j = 0; j < NUMPSPRITES; j++)
+ if (players[i].psprites[j].state)
+ players[i].psprites[j].state
+ = &states[(int) players[i].psprites[j].state];
+ }
+}
+
+//=============================================================================
+
+
+/*
+====================
+=
+= P_ArchiveWorld
+=
+====================
+*/
+
+void P_ArchiveWorld(void)
+{
+ int i, j;
+ sector_t *sec;
+ line_t *li;
+ side_t *si;
+
+ // Sectors
+ for (i = 0, sec = sectors; i < numsectors; i++, sec++)
+ {
+ SV_WriteWord(sec->floorheight >> FRACBITS);
+ SV_WriteWord(sec->ceilingheight >> FRACBITS);
+ SV_WriteWord(sec->floorpic);
+ SV_WriteWord(sec->ceilingpic);
+ SV_WriteWord(sec->lightlevel);
+ SV_WriteWord(sec->special); // needed?
+ SV_WriteWord(sec->tag); // needed?
+ }
+
+ // Lines
+ for (i = 0, li = lines; i < numlines; i++, li++)
+ {
+ SV_WriteWord(li->flags);
+ SV_WriteWord(li->special);
+ SV_WriteWord(li->tag);
+ for (j = 0; j < 2; j++)
+ {
+ if (li->sidenum[j] == -1)
+ {
+ continue;
+ }
+ si = &sides[li->sidenum[j]];
+ SV_WriteWord(si->textureoffset >> FRACBITS);
+ SV_WriteWord(si->rowoffset >> FRACBITS);
+ SV_WriteWord(si->toptexture);
+ SV_WriteWord(si->bottomtexture);
+ SV_WriteWord(si->midtexture);
+ }
+ }
+}
+
+/*
+====================
+=
+= P_UnArchiveWorld
+=
+====================
+*/
+
+void P_UnArchiveWorld(void)
+{
+ int i, 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;
+}
+
+//=============================================================================
+
+typedef enum
+{
+ tc_end,
+ tc_mobj
+} thinkerclass_t;
+
+/*
+====================
+=
+= P_ArchiveThinkers
+=
+====================
+*/
+
+void P_ArchiveThinkers(void)
+{
+ thinker_t *th;
+ mobj_t mobj;
+
+ for (th = thinkercap.next; th != &thinkercap; th = th->next)
+ {
+ if (th->function == P_MobjThinker)
+ {
+ SV_WriteByte(tc_mobj);
+ memcpy(&mobj, th, sizeof(mobj_t));
+ mobj.state = (state_t *) (mobj.state - states);
+ if (mobj.player)
+ {
+ mobj.player = (player_t *) ((mobj.player - players) + 1);
+ }
+ SV_Write(&mobj, sizeof(mobj_t));
+ continue;
+ }
+ //I_Error("P_ArchiveThinkers: Unknown thinker function");
+ }
+
+ // Add a terminating marker
+ SV_WriteByte(tc_end);
+}
+
+/*
+====================
+=
+= P_UnArchiveThinkers
+=
+====================
+*/
+
+void P_UnArchiveThinkers(void)
+{
+ byte tclass;
+ thinker_t *currentthinker, *next;
+ mobj_t *mobj;
+
+//
+// remove all the current thinkers
+//
+ currentthinker = thinkercap.next;
+ while (currentthinker != &thinkercap)
+ {
+ next = currentthinker->next;
+ if (currentthinker->function == 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:
+ mobj = Z_Malloc(sizeof(*mobj), PU_LEVEL, NULL);
+ memcpy(mobj, save_p, sizeof(*mobj));
+ save_p += sizeof(*mobj);
+ mobj->state = &states[(int) mobj->state];
+ mobj->target = NULL;
+ if (mobj->player)
+ {
+ mobj->player = &players[(int) 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 = P_MobjThinker;
+ P_AddThinker(&mobj->thinker);
+ break;
+
+ default:
+ I_Error("Unknown tclass %i in savegame", tclass);
+ }
+
+ }
+
+}
+
+//=============================================================================
+
+
+/*
+====================
+=
+= P_ArchiveSpecials
+=
+====================
+*/
+enum
+{
+ tc_ceiling,
+ tc_door,
+ tc_floor,
+ tc_plat,
+ tc_flash,
+ tc_strobe,
+ tc_glow,
+ tc_endspecials
+} specials_e;
+
+void P_ArchiveSpecials(void)
+{
+/*
+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
+*/
+
+ thinker_t *th;
+ ceiling_t ceiling;
+ vldoor_t door;
+ floormove_t floor;
+ plat_t plat;
+ lightflash_t flash;
+ strobe_t strobe;
+ glow_t glow;
+
+ for (th = thinkercap.next; th != &thinkercap; th = th->next)
+ {
+ if (th->function == T_MoveCeiling)
+ {
+ SV_WriteByte(tc_ceiling);
+ memcpy(&ceiling, th, sizeof(ceiling_t));
+ ceiling.sector = (sector_t *) (ceiling.sector - sectors);
+ SV_Write(&ceiling, sizeof(ceiling_t));
+ continue;
+ }
+ if (th->function == T_VerticalDoor)
+ {
+ SV_WriteByte(tc_door);
+ memcpy(&door, th, sizeof(vldoor_t));
+ door.sector = (sector_t *) (door.sector - sectors);
+ SV_Write(&door, sizeof(vldoor_t));
+ continue;
+ }
+ if (th->function == T_MoveFloor)
+ {
+ SV_WriteByte(tc_floor);
+ memcpy(&floor, th, sizeof(floormove_t));
+ floor.sector = (sector_t *) (floor.sector - sectors);
+ SV_Write(&floor, sizeof(floormove_t));
+ continue;
+ }
+ if (th->function == T_PlatRaise)
+ {
+ SV_WriteByte(tc_plat);
+ memcpy(&plat, th, sizeof(plat_t));
+ plat.sector = (sector_t *) (plat.sector - sectors);
+ SV_Write(&plat, sizeof(plat_t));
+ continue;
+ }
+ if (th->function == T_LightFlash)
+ {
+ SV_WriteByte(tc_flash);
+ memcpy(&flash, th, sizeof(lightflash_t));
+ flash.sector = (sector_t *) (flash.sector - sectors);
+ SV_Write(&flash, sizeof(lightflash_t));
+ continue;
+ }
+ if (th->function == T_StrobeFlash)
+ {
+ SV_WriteByte(tc_strobe);
+ memcpy(&strobe, th, sizeof(strobe_t));
+ strobe.sector = (sector_t *) (strobe.sector - sectors);
+ SV_Write(&strobe, sizeof(strobe_t));
+ continue;
+ }
+ if (th->function == T_Glow)
+ {
+ SV_WriteByte(tc_glow);
+ memcpy(&glow, th, sizeof(glow_t));
+ glow.sector = (sector_t *) (glow.sector - sectors);
+ SV_Write(&glow, sizeof(glow_t));
+ continue;
+ }
+ }
+ // Add a terminating marker
+ SV_WriteByte(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:
+ ceiling = Z_Malloc(sizeof(*ceiling), PU_LEVEL, NULL);
+ memcpy(ceiling, save_p, sizeof(*ceiling));
+ save_p += sizeof(*ceiling);
+ ceiling->sector = &sectors[(int) ceiling->sector];
+ ceiling->sector->specialdata = T_MoveCeiling;
+ if (ceiling->thinker.function)
+ ceiling->thinker.function = T_MoveCeiling;
+ P_AddThinker(&ceiling->thinker);
+ P_AddActiveCeiling(ceiling);
+ break;
+
+ case tc_door:
+ door = Z_Malloc(sizeof(*door), PU_LEVEL, NULL);
+ memcpy(door, save_p, sizeof(*door));
+ save_p += sizeof(*door);
+ door->sector = &sectors[(int) door->sector];
+ door->sector->specialdata = door;
+ door->thinker.function = T_VerticalDoor;
+ P_AddThinker(&door->thinker);
+ break;
+
+ case tc_floor:
+ floor = Z_Malloc(sizeof(*floor), PU_LEVEL, NULL);
+ memcpy(floor, save_p, sizeof(*floor));
+ save_p += sizeof(*floor);
+ floor->sector = &sectors[(int) floor->sector];
+ floor->sector->specialdata = T_MoveFloor;
+ floor->thinker.function = T_MoveFloor;
+ P_AddThinker(&floor->thinker);
+ break;
+
+ case tc_plat:
+ plat = Z_Malloc(sizeof(*plat), PU_LEVEL, NULL);
+ memcpy(plat, save_p, sizeof(*plat));
+ save_p += sizeof(*plat);
+ plat->sector = &sectors[(int) plat->sector];
+ plat->sector->specialdata = T_PlatRaise;
+ if (plat->thinker.function)
+ plat->thinker.function = T_PlatRaise;
+ P_AddThinker(&plat->thinker);
+ P_AddActivePlat(plat);
+ break;
+
+ case tc_flash:
+ flash = Z_Malloc(sizeof(*flash), PU_LEVEL, NULL);
+ memcpy(flash, save_p, sizeof(*flash));
+ save_p += sizeof(*flash);
+ flash->sector = &sectors[(int) flash->sector];
+ flash->thinker.function = T_LightFlash;
+ P_AddThinker(&flash->thinker);
+ break;
+
+ case tc_strobe:
+ strobe = Z_Malloc(sizeof(*strobe), PU_LEVEL, NULL);
+ memcpy(strobe, save_p, sizeof(*strobe));
+ save_p += sizeof(*strobe);
+ strobe->sector = &sectors[(int) strobe->sector];
+ strobe->thinker.function = T_StrobeFlash;
+ P_AddThinker(&strobe->thinker);
+ break;
+
+ case tc_glow:
+ glow = Z_Malloc(sizeof(*glow), PU_LEVEL, NULL);
+ memcpy(glow, save_p, sizeof(*glow));
+ save_p += sizeof(*glow);
+ glow->sector = &sectors[(int) glow->sector];
+ glow->thinker.function = T_Glow;
+ P_AddThinker(&glow->thinker);
+ break;
+
+ default:
+ I_Error("P_UnarchiveSpecials:Unknown tclass %i "
+ "in savegame", tclass);
+ }
+
+ }
+
+}
+
+
+
+/*
+===============================================================================
+
+ 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.
+
+===============================================================================
+*/
+
+thinker_t thinkercap; // both the head and tail of the thinker list
+
+/*
+===============
+=
+= 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)
+{
+ thinker->function = (think_t) - 1;
+}
+
+/*
+===============
+=
+= P_AllocateThinker
+=
+= Allocates memory and adds a new thinker at the end of the list
+=
+===============
+*/
+
+void P_AllocateThinker(thinker_t * thinker)
+{
+}
+
+
+/*
+===============
+=
+= P_RunThinkers
+=
+===============
+*/
+
+void P_RunThinkers(void)
+{
+ thinker_t *currentthinker;
+
+ currentthinker = thinkercap.next;
+ while (currentthinker != &thinkercap)
+ {
+ if (currentthinker->function == (think_t) - 1)
+ { // time to remove it
+ currentthinker->next->prev = currentthinker->prev;
+ currentthinker->prev->next = currentthinker->next;
+ Z_Free(currentthinker);
+ }
+ else
+ {
+ if (currentthinker->function)
+ currentthinker->function(currentthinker);
+ }
+ currentthinker = currentthinker->next;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_Ticker
+//
+//----------------------------------------------------------------------------
+
+void P_Ticker(void)
+{
+ int i;
+
+ if (paused)
+ {
+ return;
+ }
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ {
+ P_PlayerThink(&players[i]);
+ }
+ }
+ if (TimerGame)
+ {
+ if (!--TimerGame)
+ {
+ G_ExitLevel();
+ }
+ }
+ P_RunThinkers();
+ P_UpdateSpecials();
+ P_AmbientSound();
+ leveltime++;
+}
diff --git a/src/heretic/p_user.c b/src/heretic/p_user.c
new file mode 100644
index 00000000..79620630
--- /dev/null
+++ b/src/heretic/p_user.c
@@ -0,0 +1,1020 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// P_user.c
+
+#include <stdlib.h>
+
+#include "doomdef.h"
+#include "deh_str.h"
+#include "m_random.h"
+#include "p_local.h"
+#include "s_sound.h"
+
+void P_PlayerNextArtifact(player_t * player);
+
+// Macros
+
+#define MAXBOB 0x100000 // 16 pixels of bob
+
+// Data
+
+boolean onground;
+int newtorch; // used in the torch flicker effect.
+int newtorchdelta;
+
+boolean WeaponInShareware[] = {
+ true, // Staff
+ true, // Gold wand
+ true, // Crossbow
+ true, // Blaster
+ false, // Skull rod
+ false, // Phoenix rod
+ false, // Mace
+ true, // Gauntlets
+ true // Beak
+};
+
+/*
+==================
+=
+= P_Thrust
+=
+= moves the given origin along a given angle
+=
+==================
+*/
+
+void P_Thrust(player_t * player, angle_t angle, fixed_t move)
+{
+ angle >>= ANGLETOFINESHIFT;
+ if (player->powers[pw_flight] && !(player->mo->z <= player->mo->floorz))
+ {
+ player->mo->momx += FixedMul(move, finecosine[angle]);
+ player->mo->momy += FixedMul(move, finesine[angle]);
+ }
+ else if (player->mo->subsector->sector->special == 15) // Friction_Low
+ {
+ player->mo->momx += FixedMul(move >> 2, finecosine[angle]);
+ player->mo->momy += FixedMul(move >> 2, finesine[angle]);
+ }
+ else
+ {
+ 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
+
+ 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->mo->flags2 & MF2_FLY && !onground)
+ {
+ player->bob = FRACUNIT / 2;
+ }
+
+ if ((player->cheats & CF_NOMOMENTUM))
+ {
+ 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;
+ }
+ }
+
+ if (player->chickenTics)
+ {
+ player->viewz = player->mo->z + player->viewheight - (20 * FRACUNIT);
+ }
+ else
+ {
+ player->viewz = player->mo->z + player->viewheight + bob;
+ }
+ if (player->mo->flags2 & MF2_FEETARECLIPPED
+ && player->playerstate != PST_DEAD
+ && player->mo->z <= player->mo->floorz)
+ {
+ player->viewz -= FOOTCLIPSIZE;
+ }
+ if (player->viewz > player->mo->ceilingz - 4 * FRACUNIT)
+ {
+ player->viewz = player->mo->ceilingz - 4 * FRACUNIT;
+ }
+ if (player->viewz < player->mo->floorz + 4 * FRACUNIT)
+ {
+ player->viewz = player->mo->floorz + 4 * FRACUNIT;
+ }
+}
+
+/*
+=================
+=
+= P_MovePlayer
+=
+=================
+*/
+
+void P_MovePlayer(player_t * player)
+{
+ int look;
+ int fly;
+ ticcmd_t *cmd;
+
+ cmd = &player->cmd;
+ player->mo->angle += (cmd->angleturn << 16);
+
+ onground = (player->mo->z <= player->mo->floorz
+ || (player->mo->flags2 & MF2_ONMOBJ));
+
+ if (player->chickenTics)
+ { // Chicken speed
+ if (cmd->forwardmove && (onground || player->mo->flags2 & MF2_FLY))
+ P_Thrust(player, player->mo->angle, cmd->forwardmove * 2500);
+ if (cmd->sidemove && (onground || player->mo->flags2 & MF2_FLY))
+ P_Thrust(player, player->mo->angle - ANG90, cmd->sidemove * 2500);
+ }
+ else
+ { // Normal speed
+ if (cmd->forwardmove && (onground || player->mo->flags2 & MF2_FLY))
+ P_Thrust(player, player->mo->angle, cmd->forwardmove * 2048);
+ if (cmd->sidemove && (onground || player->mo->flags2 & MF2_FLY))
+ P_Thrust(player, player->mo->angle - ANG90, cmd->sidemove * 2048);
+ }
+
+ if (cmd->forwardmove || cmd->sidemove)
+ {
+ if (player->chickenTics)
+ {
+ if (player->mo->state == &states[S_CHICPLAY])
+ {
+ P_SetMobjState(player->mo, S_CHICPLAY_RUN1);
+ }
+ }
+ else
+ {
+ if (player->mo->state == &states[S_PLAY])
+ {
+ P_SetMobjState(player->mo, S_PLAY_RUN1);
+ }
+ }
+ }
+
+ look = cmd->lookfly & 15;
+ if (look > 7)
+ {
+ look -= 16;
+ }
+ if (look)
+ {
+ if (look == TOCENTER)
+ {
+ player->centering = true;
+ }
+ else
+ {
+ player->lookdir += 5 * look;
+ if (player->lookdir > 90 || player->lookdir < -110)
+ {
+ player->lookdir -= 5 * look;
+ }
+ }
+ }
+ if (player->centering)
+ {
+ if (player->lookdir > 0)
+ {
+ player->lookdir -= 8;
+ }
+ else if (player->lookdir < 0)
+ {
+ player->lookdir += 8;
+ }
+ if (abs(player->lookdir) < 8)
+ {
+ player->lookdir = 0;
+ player->centering = false;
+ }
+ }
+ fly = cmd->lookfly >> 4;
+ if (fly > 7)
+ {
+ fly -= 16;
+ }
+ if (fly && player->powers[pw_flight])
+ {
+ if (fly != TOCENTER)
+ {
+ player->flyheight = fly * 2;
+ if (!(player->mo->flags2 & MF2_FLY))
+ {
+ player->mo->flags2 |= MF2_FLY;
+ player->mo->flags |= MF_NOGRAVITY;
+ }
+ }
+ else
+ {
+ player->mo->flags2 &= ~MF2_FLY;
+ player->mo->flags &= ~MF_NOGRAVITY;
+ }
+ }
+ else if (fly > 0)
+ {
+ P_PlayerUseArtifact(player, arti_fly);
+ }
+ if (player->mo->flags2 & MF2_FLY)
+ {
+ player->mo->momz = player->flyheight * FRACUNIT;
+ if (player->flyheight)
+ {
+ player->flyheight /= 2;
+ }
+ }
+}
+
+/*
+=================
+=
+= P_DeathThink
+=
+=================
+*/
+
+#define ANG5 (ANG90/18)
+extern int inv_ptr;
+extern int curpos;
+
+void P_DeathThink(player_t * player)
+{
+ angle_t angle, delta;
+ int lookDelta;
+
+ P_MovePsprites(player);
+
+ onground = (player->mo->z <= player->mo->floorz);
+ if (player->mo->type == MT_BLOODYSKULL)
+ { // Flying bloody skull
+ player->viewheight = 6 * FRACUNIT;
+ player->deltaviewheight = 0;
+ //player->damagecount = 20;
+ if (onground)
+ {
+ if (player->lookdir < 60)
+ {
+ lookDelta = (60 - player->lookdir) / 8;
+ if (lookDelta < 1 && (leveltime & 1))
+ {
+ lookDelta = 1;
+ }
+ else if (lookDelta > 6)
+ {
+ lookDelta = 6;
+ }
+ player->lookdir += lookDelta;
+ }
+ }
+ }
+ else
+ { // Fall to ground
+ player->deltaviewheight = 0;
+ if (player->viewheight > 6 * FRACUNIT)
+ player->viewheight -= FRACUNIT;
+ if (player->viewheight < 6 * FRACUNIT)
+ player->viewheight = 6 * FRACUNIT;
+ if (player->lookdir > 0)
+ {
+ player->lookdir -= 6;
+ }
+ else if (player->lookdir < 0)
+ {
+ player->lookdir += 6;
+ }
+ if (abs(player->lookdir) < 6)
+ {
+ player->lookdir = 0;
+ }
+ }
+ 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)
+ {
+ if (player == &players[consoleplayer])
+ {
+ I_SetPalette(W_CacheLumpName(DEH_String("PLAYPAL"), PU_CACHE));
+ inv_ptr = 0;
+ curpos = 0;
+ newtorch = 0;
+ newtorchdelta = 0;
+ }
+ player->playerstate = PST_REBORN;
+ // Let the mobj know the player has entered the reborn state. Some
+ // mobjs need to know when it's ok to remove themselves.
+ player->mo->special2.i = 666;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_ChickenPlayerThink
+//
+//----------------------------------------------------------------------------
+
+void P_ChickenPlayerThink(player_t * player)
+{
+ mobj_t *pmo;
+
+ if (player->health > 0)
+ { // Handle beak movement
+ P_UpdateBeak(player, &player->psprites[ps_weapon]);
+ }
+ if (player->chickenTics & 15)
+ {
+ return;
+ }
+ pmo = player->mo;
+ if (!(pmo->momx + pmo->momy) && P_Random() < 160)
+ { // Twitch view angle
+ pmo->angle += (P_Random() - P_Random()) << 19;
+ }
+ if ((pmo->z <= pmo->floorz) && (P_Random() < 32))
+ { // Jump and noise
+ pmo->momz += FRACUNIT;
+ P_SetMobjState(pmo, S_CHICPLAY_PAIN);
+ return;
+ }
+ if (P_Random() < 48)
+ { // Just noise
+ S_StartSound(pmo, sfx_chicact);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_GetPlayerNum
+//
+//----------------------------------------------------------------------------
+
+int P_GetPlayerNum(player_t * player)
+{
+ int i;
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (player == &players[i])
+ {
+ return (i);
+ }
+ }
+ return (0);
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_UndoPlayerChicken
+//
+//----------------------------------------------------------------------------
+
+boolean P_UndoPlayerChicken(player_t * player)
+{
+ mobj_t *fog;
+ mobj_t *mo;
+ mobj_t *pmo;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ angle_t angle;
+ int playerNum;
+ weapontype_t weapon;
+ int oldFlags;
+ int oldFlags2;
+
+ pmo = player->mo;
+ x = pmo->x;
+ y = pmo->y;
+ z = pmo->z;
+ angle = pmo->angle;
+ weapon = pmo->special1.i;
+ oldFlags = pmo->flags;
+ oldFlags2 = pmo->flags2;
+ P_SetMobjState(pmo, S_FREETARGMOBJ);
+ mo = P_SpawnMobj(x, y, z, MT_PLAYER);
+ if (P_TestMobjLocation(mo) == false)
+ { // Didn't fit
+ P_RemoveMobj(mo);
+ mo = P_SpawnMobj(x, y, z, MT_CHICPLAYER);
+ mo->angle = angle;
+ mo->health = player->health;
+ mo->special1.i = weapon;
+ mo->player = player;
+ mo->flags = oldFlags;
+ mo->flags2 = oldFlags2;
+ player->mo = mo;
+ player->chickenTics = 2 * 35;
+ return (false);
+ }
+ playerNum = P_GetPlayerNum(player);
+ if (playerNum != 0)
+ { // Set color translation
+ mo->flags |= playerNum << MF_TRANSSHIFT;
+ }
+ mo->angle = angle;
+ mo->player = player;
+ mo->reactiontime = 18;
+ if (oldFlags2 & MF2_FLY)
+ {
+ mo->flags2 |= MF2_FLY;
+ mo->flags |= MF_NOGRAVITY;
+ }
+ player->chickenTics = 0;
+ player->powers[pw_weaponlevel2] = 0;
+ player->health = mo->health = MAXHEALTH;
+ player->mo = mo;
+ angle >>= ANGLETOFINESHIFT;
+ fog = P_SpawnMobj(x + 20 * finecosine[angle],
+ y + 20 * finesine[angle], z + TELEFOGHEIGHT, MT_TFOG);
+ S_StartSound(fog, sfx_telept);
+ P_PostChickenWeapon(player, weapon);
+ return (true);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_PlayerThink
+//
+//----------------------------------------------------------------------------
+
+void P_PlayerThink(player_t * player)
+{
+ ticcmd_t *cmd;
+ weapontype_t newweapon;
+
+ // No-clip cheat
+ if (player->cheats & CF_NOCLIP)
+ {
+ player->mo->flags |= MF_NOCLIP;
+ }
+ else
+ {
+ player->mo->flags &= ~MF_NOCLIP;
+ }
+ cmd = &player->cmd;
+ if (player->mo->flags & MF_JUSTATTACKED)
+ { // Gauntlets attack auto forward motion
+ cmd->angleturn = 0;
+ cmd->forwardmove = 0xc800 / 512;
+ cmd->sidemove = 0;
+ player->mo->flags &= ~MF_JUSTATTACKED;
+ }
+// messageTics is above the rest of the counters so that messages will
+// go away, even in death.
+ player->messageTics--; // Can go negative
+ if (!player->messageTics)
+ { // Refresh the screen when a message goes away
+ ultimatemsg = false; // clear out any chat messages.
+ BorderTopRefresh = true;
+ }
+ if (player->playerstate == PST_DEAD)
+ {
+ P_DeathThink(player);
+ return;
+ }
+ if (player->chickenTics)
+ {
+ P_ChickenPlayerThink(player);
+ }
+ // Handle movement
+ if (player->mo->reactiontime)
+ { // Player is frozen
+ player->mo->reactiontime--;
+ }
+ else
+ {
+ P_MovePlayer(player);
+ }
+ P_CalcHeight(player);
+ if (player->mo->subsector->sector->special)
+ {
+ P_PlayerInSpecialSector(player);
+ }
+ if (cmd->arti)
+ { // Use an artifact
+ if (cmd->arti == 0xff)
+ {
+ P_PlayerNextArtifact(player);
+ }
+ else
+ {
+ P_PlayerUseArtifact(player, cmd->arti);
+ }
+ }
+ // Check for weapon change
+ if (cmd->buttons & BT_SPECIAL)
+ { // A special event has no other buttons
+ cmd->buttons = 0;
+ }
+ if (cmd->buttons & BT_CHANGE)
+ {
+ // The actual changing of the weapon is done when the weapon
+ // psprite can do it (A_WeaponReady), so it doesn't happen in
+ // the middle of an attack.
+ newweapon = (cmd->buttons & BT_WEAPONMASK) >> BT_WEAPONSHIFT;
+ if (newweapon == wp_staff && player->weaponowned[wp_gauntlets]
+ && !(player->readyweapon == wp_gauntlets))
+ {
+ newweapon = wp_gauntlets;
+ }
+ if (player->weaponowned[newweapon]
+ && newweapon != player->readyweapon)
+ {
+ if (WeaponInShareware[newweapon] || 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;
+ }
+ // Chicken counter
+ if (player->chickenTics)
+ {
+ if (player->chickenPeck)
+ { // Chicken attack counter
+ player->chickenPeck -= 3;
+ }
+ if (!--player->chickenTics)
+ { // Attempt to undo the chicken
+ P_UndoPlayerChicken(player);
+ }
+ }
+ // Cycle psprites
+ P_MovePsprites(player);
+ // Other Counters
+ 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_flight])
+ {
+ if (!--player->powers[pw_flight])
+ {
+ // haleyjd: removed externdriver crap
+ if (player->mo->z != player->mo->floorz)
+ {
+ player->centering = true;
+ }
+
+ player->mo->flags2 &= ~MF2_FLY;
+ player->mo->flags &= ~MF_NOGRAVITY;
+ BorderTopRefresh = true; //make sure the sprite's cleared out
+ }
+ }
+ if (player->powers[pw_weaponlevel2])
+ {
+ if (!--player->powers[pw_weaponlevel2])
+ {
+ if ((player->readyweapon == wp_phoenixrod)
+ && (player->psprites[ps_weapon].state
+ != &states[S_PHOENIXREADY])
+ && (player->psprites[ps_weapon].state
+ != &states[S_PHOENIXUP]))
+ {
+ P_SetPsprite(player, ps_weapon, S_PHOENIXREADY);
+ player->ammo[am_phoenixrod] -= USE_PHRD_AMMO_2;
+ player->refire = 0;
+ }
+ else if ((player->readyweapon == wp_gauntlets)
+ || (player->readyweapon == wp_staff))
+ {
+ player->pendingweapon = player->readyweapon;
+ }
+ BorderTopRefresh = true;
+ }
+ }
+ if (player->damagecount)
+ {
+ player->damagecount--;
+ }
+ if (player->bonuscount)
+ {
+ player->bonuscount--;
+ }
+ // Colormaps
+ if (player->powers[pw_invulnerability])
+ {
+ if (player->powers[pw_invulnerability] > BLINKTHRESHOLD
+ || (player->powers[pw_invulnerability] & 8))
+ {
+ player->fixedcolormap = INVERSECOLORMAP;
+ }
+ else
+ {
+ player->fixedcolormap = 0;
+ }
+ }
+ else if (player->powers[pw_infrared])
+ {
+ if (player->powers[pw_infrared] <= BLINKTHRESHOLD)
+ {
+ if (player->powers[pw_infrared] & 8)
+ {
+ player->fixedcolormap = 0;
+ }
+ else
+ {
+ player->fixedcolormap = 1;
+ }
+ }
+ else if (!(leveltime & 16) && player == &players[consoleplayer])
+ {
+ if (newtorch)
+ {
+ if (player->fixedcolormap + newtorchdelta > 7
+ || player->fixedcolormap + newtorchdelta < 1
+ || newtorch == player->fixedcolormap)
+ {
+ newtorch = 0;
+ }
+ else
+ {
+ player->fixedcolormap += newtorchdelta;
+ }
+ }
+ else
+ {
+ newtorch = (M_Random() & 7) + 1;
+ newtorchdelta = (newtorch == player->fixedcolormap) ?
+ 0 : ((newtorch > player->fixedcolormap) ? 1 : -1);
+ }
+ }
+ }
+ else
+ {
+ player->fixedcolormap = 0;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_ArtiTele
+//
+//----------------------------------------------------------------------------
+
+void P_ArtiTele(player_t * player)
+{
+ int i;
+ int selections;
+ fixed_t destX;
+ fixed_t destY;
+ angle_t destAngle;
+
+ if (deathmatch)
+ {
+ selections = deathmatch_p - deathmatchstarts;
+ i = P_Random() % selections;
+ destX = deathmatchstarts[i].x << FRACBITS;
+ destY = deathmatchstarts[i].y << FRACBITS;
+ destAngle = ANG45 * (deathmatchstarts[i].angle / 45);
+ }
+ else
+ {
+ destX = playerstarts[0].x << FRACBITS;
+ destY = playerstarts[0].y << FRACBITS;
+ destAngle = ANG45 * (playerstarts[0].angle / 45);
+ }
+ P_Teleport(player->mo, destX, destY, destAngle);
+ S_StartSound(NULL, sfx_wpnup); // Full volume laugh
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_PlayerNextArtifact
+//
+//----------------------------------------------------------------------------
+
+void P_PlayerNextArtifact(player_t * player)
+{
+ if (player == &players[consoleplayer])
+ {
+ inv_ptr--;
+ if (inv_ptr < 6)
+ {
+ curpos--;
+ if (curpos < 0)
+ {
+ curpos = 0;
+ }
+ }
+ if (inv_ptr < 0)
+ {
+ inv_ptr = player->inventorySlotNum - 1;
+ if (inv_ptr < 6)
+ {
+ curpos = inv_ptr;
+ }
+ else
+ {
+ curpos = 6;
+ }
+ }
+ player->readyArtifact = player->inventory[inv_ptr].type;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_PlayerRemoveArtifact
+//
+//----------------------------------------------------------------------------
+
+void P_PlayerRemoveArtifact(player_t * player, int slot)
+{
+ int i;
+ player->artifactCount--;
+ if (!(--player->inventory[slot].count))
+ { // Used last of a type - compact the artifact list
+ player->readyArtifact = arti_none;
+ player->inventory[slot].type = arti_none;
+ for (i = slot + 1; i < player->inventorySlotNum; i++)
+ {
+ player->inventory[i - 1] = player->inventory[i];
+ }
+ player->inventorySlotNum--;
+ if (player == &players[consoleplayer])
+ { // Set position markers and get next readyArtifact
+ inv_ptr--;
+ if (inv_ptr < 6)
+ {
+ curpos--;
+ if (curpos < 0)
+ {
+ curpos = 0;
+ }
+ }
+ if (inv_ptr >= player->inventorySlotNum)
+ {
+ inv_ptr = player->inventorySlotNum - 1;
+ }
+ if (inv_ptr < 0)
+ {
+ inv_ptr = 0;
+ }
+ player->readyArtifact = player->inventory[inv_ptr].type;
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_PlayerUseArtifact
+//
+//----------------------------------------------------------------------------
+
+void P_PlayerUseArtifact(player_t * player, artitype_t arti)
+{
+ int i;
+
+ for (i = 0; i < player->inventorySlotNum; i++)
+ {
+ if (player->inventory[i].type == arti)
+ { // Found match - try to use
+ if (P_UseArtifact(player, arti))
+ { // Artifact was used - remove it from inventory
+ P_PlayerRemoveArtifact(player, i);
+ if (player == &players[consoleplayer])
+ {
+ S_StartSound(NULL, sfx_artiuse);
+ ArtifactFlash = 4;
+ }
+ }
+ else
+ { // Unable to use artifact, advance pointer
+ P_PlayerNextArtifact(player);
+ }
+ break;
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_UseArtifact
+//
+// Returns true if artifact was used.
+//
+//----------------------------------------------------------------------------
+
+boolean P_UseArtifact(player_t * player, artitype_t arti)
+{
+ mobj_t *mo;
+ angle_t angle;
+
+ switch (arti)
+ {
+ case arti_invulnerability:
+ if (!P_GivePower(player, pw_invulnerability))
+ {
+ return (false);
+ }
+ break;
+ case arti_invisibility:
+ if (!P_GivePower(player, pw_invisibility))
+ {
+ return (false);
+ }
+ break;
+ case arti_health:
+ if (!P_GiveBody(player, 25))
+ {
+ return (false);
+ }
+ break;
+ case arti_superhealth:
+ if (!P_GiveBody(player, 100))
+ {
+ return (false);
+ }
+ break;
+ case arti_tomeofpower:
+ if (player->chickenTics)
+ { // Attempt to undo chicken
+ if (P_UndoPlayerChicken(player) == false)
+ { // Failed
+ P_DamageMobj(player->mo, NULL, NULL, 10000);
+ }
+ else
+ { // Succeeded
+ player->chickenTics = 0;
+ S_StartSound(player->mo, sfx_wpnup);
+ }
+ }
+ else
+ {
+ if (!P_GivePower(player, pw_weaponlevel2))
+ {
+ return (false);
+ }
+ if (player->readyweapon == wp_staff)
+ {
+ P_SetPsprite(player, ps_weapon, S_STAFFREADY2_1);
+ }
+ else if (player->readyweapon == wp_gauntlets)
+ {
+ P_SetPsprite(player, ps_weapon, S_GAUNTLETREADY2_1);
+ }
+ }
+ break;
+ case arti_torch:
+ if (!P_GivePower(player, pw_infrared))
+ {
+ return (false);
+ }
+ break;
+ case arti_firebomb:
+ angle = player->mo->angle >> ANGLETOFINESHIFT;
+ mo = P_SpawnMobj(player->mo->x + 24 * finecosine[angle],
+ player->mo->y + 24 * finesine[angle],
+ player->mo->z -
+ 15 * FRACUNIT *
+ (player->mo->flags2 & MF2_FEETARECLIPPED) != 0,
+ MT_FIREBOMB);
+ mo->target = player->mo;
+ break;
+ case arti_egg:
+ mo = player->mo;
+ P_SpawnPlayerMissile(mo, MT_EGGFX);
+ P_SPMAngle(mo, MT_EGGFX, mo->angle - (ANG45 / 6));
+ P_SPMAngle(mo, MT_EGGFX, mo->angle + (ANG45 / 6));
+ P_SPMAngle(mo, MT_EGGFX, mo->angle - (ANG45 / 3));
+ P_SPMAngle(mo, MT_EGGFX, mo->angle + (ANG45 / 3));
+ break;
+ case arti_fly:
+ if (!P_GivePower(player, pw_flight))
+ {
+ return (false);
+ }
+ break;
+ case arti_teleport:
+ P_ArtiTele(player);
+ break;
+ default:
+ return (false);
+ }
+ return (true);
+}
diff --git a/src/heretic/r_bsp.c b/src/heretic/r_bsp.c
new file mode 100644
index 00000000..16ef8ae1
--- /dev/null
+++ b/src/heretic/r_bsp.c
@@ -0,0 +1,484 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+// R_bsp.c
+
+#include "doomdef.h"
+#include "m_bbox.h"
+#include "r_local.h"
+
+seg_t *curline;
+side_t *sidedef;
+line_t *linedef;
+sector_t *frontsector, *backsector;
+
+drawseg_t drawsegs[MAXDRAWSEGS], *ds_p;
+
+void R_StoreWallRange(int start, int stop);
+
+/*
+====================
+=
+= R_ClearDrawSegs
+=
+====================
+*/
+
+void R_ClearDrawSegs(void)
+{
+ ds_p = drawsegs;
+}
+
+//=============================================================================
+
+
+/*
+===============================================================================
+=
+= ClipWallSegment
+=
+= Clips the given range of columns and includes it in the new clip list
+===============================================================================
+*/
+
+typedef struct
+{
+ int first, last;
+} cliprange_t;
+
+#define MAXSEGS 32
+
+cliprange_t solidsegs[MAXSEGS], *newend; // newend is one past the last valid seg
+
+
+void R_ClipSolidWallSegment(int first, int last)
+{
+ cliprange_t *next, *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);
+ start->first = first; // adjust the clip size
+ }
+
+ if (last <= start->last)
+ return; // bottom contained in start
+
+ 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
+ start->last = next->last; // adjust the clip size
+ goto crunch;
+ }
+ }
+
+ // there is a fragment after *next
+ R_StoreWallRange(next->last + 1, last);
+ start->last = last; // adjust the clip size
+
+
+// remove start+1 to next from the clip list,
+// because start now covers their area
+ crunch:
+ if (next == start)
+ return; // post just extended past the bottom of one post
+
+ 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
+===============================================================================
+*/
+
+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);
+ }
+
+ if (last <= start->last)
+ return; // bottom contained in start
+
+ 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, x2;
+ angle_t angle1, angle2, span, 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;
+ if (span >= ANG180)
+ return; // back side
+
+ rw_angle1 = angle1; // global angle needed by segcalc
+ angle1 -= viewangle;
+ angle2 -= viewangle;
+
+ tspan = angle1 + clipangle;
+ if (tspan > 2 * clipangle)
+ {
+ tspan -= 2 * clipangle;
+ if (tspan >= span)
+ return; // totally off the left edge
+ angle1 = clipangle;
+ }
+ tspan = clipangle - angle2;
+ if (tspan > 2 * clipangle)
+ {
+ tspan -= 2 * clipangle;
+ if (tspan >= span)
+ return; // totally off the left edge
+ angle2 = -clipangle;
+ }
+
+//
+// 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];
+ if (x1 == x2)
+ return; // does not cross a pixel
+
+ backsector = line->backsector;
+
+ if (!backsector)
+ goto clipsolid; // single sided line
+
+ if (backsector->ceilingheight <= frontsector->floorheight
+ || backsector->floorheight >= frontsector->ceilingheight)
+ goto clipsolid; // closed door
+
+ if (backsector->ceilingheight != frontsector->ceilingheight
+ || backsector->floorheight != frontsector->floorheight)
+ goto clippass; // window
+
+// reject empty lines used for triggers and special events
+ 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
+=
+= Returns true if some part of the bbox might be visible
+=
+===============================================================================
+*/
+
+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}
+};
+
+
+boolean R_CheckBBox(fixed_t * bspcoord)
+{
+ int boxx, boxy, boxpos;
+ fixed_t x1, y1, x2, y2;
+ angle_t angle1, angle2, span, tspan;
+ cliprange_t *start;
+ int sx1, 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;
+ if (span >= ANG180)
+ return true; // sitting on a line
+ tspan = angle1 + clipangle;
+ if (tspan > 2 * clipangle)
+ {
+ tspan -= 2 * clipangle;
+ if (tspan >= span)
+ return false; // totally off the left edge
+ angle1 = clipangle;
+ }
+ tspan = clipangle - angle2;
+ if (tspan > 2 * clipangle)
+ {
+ tspan -= 2 * clipangle;
+ if (tspan >= span)
+ return false; // totally off the left edge
+ angle2 = -clipangle;
+ }
+
+
+// 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];
+ if (sx1 == sx2)
+ return false; // does not cross a pixel
+ sx2--;
+
+ start = solidsegs;
+ while (start->last < sx2)
+ start++;
+ if (sx1 >= start->first && sx2 <= start->last)
+ return false; // the clippost contains the new span
+
+ return true;
+}
+
+
+/*
+================
+=
+= R_Subsector
+=
+= Draw one or more segments
+================
+*/
+
+void R_Subsector(int num)
+{
+ int count;
+ seg_t *line;
+ subsector_t *sub;
+
+#ifdef RANGECHECK
+ if (num >= numsubsectors)
+ I_Error("R_Subsector: ss %i with numss = %i", num, numsubsectors);
+#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,
+ frontsector->special);
+ else
+ floorplane = NULL;
+ if (frontsector->ceilingheight > viewz
+ || frontsector->ceilingpic == skyflatnum)
+ ceilingplane = R_FindPlane(frontsector->ceilingheight,
+ frontsector->ceilingpic,
+ frontsector->lightlevel, 0);
+ else
+ ceilingplane = NULL;
+
+ R_AddSprites(frontsector);
+
+ while (count--)
+ {
+ R_AddLine(line);
+ line++;
+ }
+}
+
+
+/*
+===============================================================================
+=
+= RenderBSPNode
+=
+===============================================================================
+*/
+
+void R_RenderBSPNode(int bspnum)
+{
+ node_t *bsp;
+ int side;
+
+ 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);
+
+ R_RenderBSPNode(bsp->children[side]); // recursively divide front space
+
+ if (R_CheckBBox(bsp->bbox[side ^ 1])) // possibly divide back space
+ R_RenderBSPNode(bsp->children[side ^ 1]);
+}
diff --git a/src/heretic/r_data.c b/src/heretic/r_data.c
new file mode 100644
index 00000000..a2f3f10e
--- /dev/null
+++ b/src/heretic/r_data.c
@@ -0,0 +1,749 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// R_data.c
+
+#include "doomdef.h"
+#include "deh_str.h"
+
+#include "i_swap.h"
+#include "i_system.h"
+#include "r_local.h"
+#include "p_local.h"
+
+extern void CheckAbortStartup(void);
+
+typedef struct
+{
+ int originx; // block origin (allways UL), which has allready
+ int originy; // accounted for the patch's internal origin
+ int patch;
+} texpatch_t;
+
+// a maptexturedef_t describes a rectangular texture, which is composed of one
+// or more mappatch_t structures that arrange graphic patches
+typedef struct
+{
+ char name[8]; // for switch changing, etc
+ short width;
+ short height;
+ short patchcount;
+ texpatch_t patches[1]; // [patchcount] drawn back to front
+ // into the cached texture
+} texture_t;
+
+
+
+int firstflat, lastflat, numflats;
+int firstpatch, lastpatch, numpatches;
+int firstspritelump, lastspritelump, numspritelumps;
+
+int numtextures;
+texture_t **textures;
+int *texturewidthmask;
+fixed_t *textureheight; // needed for texture pegging
+int *texturecompositesize;
+short **texturecolumnlump;
+unsigned short **texturecolumnofs;
+byte **texturecomposite;
+
+int *flattranslation; // for global animation
+int *texturetranslation; // for global animation
+
+fixed_t *spritewidth; // needed for pre rendering
+fixed_t *spriteoffset;
+fixed_t *spritetopoffset;
+
+lighttable_t *colormaps;
+
+
+/*
+==============================================================================
+
+ MAPTEXTURE_T CACHING
+
+when a texture is first needed, it counts the number of composite columns
+required in the texture and allocates space for a column directory and any
+new columns. The directory will simply point inside other patches if there
+is only one patch in a given column, but any columns with multiple patches
+will have new column_ts generated.
+
+==============================================================================
+*/
+
+/*
+===================
+=
+= R_DrawColumnInCache
+=
+= Clip and draw a column from a patch into a cached post
+=
+===================
+*/
+
+void R_DrawColumnInCache(column_t * patch, byte * cache, int originy,
+ int cacheheight)
+{
+ int count, position;
+ byte *source;
+
+ while (patch->topdelta != 0xff)
+ {
+ source = (byte *) patch + 3;
+ count = patch->length;
+ position = originy + patch->topdelta;
+ if (position < 0)
+ {
+ count += position;
+ position = 0;
+ }
+ if (position + count > cacheheight)
+ count = cacheheight - position;
+ if (count > 0)
+ memcpy(cache + position, source, count);
+
+ patch = (column_t *) ((byte *) patch + patch->length + 4);
+ }
+}
+
+
+/*
+===================
+=
+= R_GenerateComposite
+=
+===================
+*/
+
+void R_GenerateComposite(int texnum)
+{
+ byte *block;
+ texture_t *texture;
+ texpatch_t *patch;
+ patch_t *realpatch;
+ int x, x1, x2;
+ int i;
+ column_t *patchcol;
+ short *collump;
+ unsigned short *colofs;
+
+ texture = textures[texnum];
+ block = Z_Malloc(texturecompositesize[texnum], PU_STATIC,
+ &texturecomposite[texnum]);
+ collump = texturecolumnlump[texnum];
+ colofs = texturecolumnofs[texnum];
+
+//
+// composite the columns together
+//
+ patch = texture->patches;
+
+ for (i = 0, patch = texture->patches; i < texture->patchcount;
+ i++, patch++)
+ {
+ realpatch = W_CacheLumpNum(patch->patch, PU_CACHE);
+ x1 = patch->originx;
+ x2 = x1 + SHORT(realpatch->width);
+
+ if (x1 < 0)
+ x = 0;
+ else
+ x = x1;
+ if (x2 > texture->width)
+ x2 = texture->width;
+
+ for (; x < x2; x++)
+ {
+ if (collump[x] >= 0)
+ continue; // column does not have multiple patches
+ patchcol = (column_t *) ((byte *) realpatch +
+ LONG(realpatch->columnofs[x - x1]));
+ R_DrawColumnInCache(patchcol, block + colofs[x], patch->originy,
+ texture->height);
+ }
+
+ }
+
+// now that the texture has been built, it is purgable
+ Z_ChangeTag(block, PU_CACHE);
+}
+
+
+/*
+===================
+=
+= R_GenerateLookup
+=
+===================
+*/
+
+void R_GenerateLookup(int texnum)
+{
+ texture_t *texture;
+ byte *patchcount; // [texture->width]
+ texpatch_t *patch;
+ patch_t *realpatch;
+ int x, x1, x2;
+ int i;
+ short *collump;
+ unsigned short *colofs;
+
+ texture = textures[texnum];
+
+ texturecomposite[texnum] = 0; // composited not created yet
+ texturecompositesize[texnum] = 0;
+ collump = texturecolumnlump[texnum];
+ colofs = texturecolumnofs[texnum];
+
+//
+// count the number of columns that are covered by more than one patch
+// fill in the lump / offset, so columns with only a single patch are
+// all done
+//
+ patchcount = (byte *) Z_Malloc(texture->width, PU_STATIC, &patchcount);
+ memset(patchcount, 0, texture->width);
+ patch = texture->patches;
+
+ for (i = 0, patch = texture->patches; i < texture->patchcount;
+ i++, patch++)
+ {
+ realpatch = W_CacheLumpNum(patch->patch, PU_CACHE);
+ x1 = patch->originx;
+ x2 = x1 + SHORT(realpatch->width);
+ if (x1 < 0)
+ x = 0;
+ else
+ x = x1;
+ if (x2 > texture->width)
+ x2 = texture->width;
+ for (; x < x2; x++)
+ {
+ patchcount[x]++;
+ collump[x] = patch->patch;
+ colofs[x] = LONG(realpatch->columnofs[x - x1]) + 3;
+ }
+ }
+
+ for (x = 0; x < texture->width; x++)
+ {
+ if (!patchcount[x])
+ {
+ printf("R_GenerateLookup: column without a patch (%s)\n",
+ texture->name);
+ return;
+ }
+// I_Error ("R_GenerateLookup: column without a patch");
+ if (patchcount[x] > 1)
+ {
+ collump[x] = -1; // use the cached block
+ colofs[x] = texturecompositesize[texnum];
+ if (texturecompositesize[texnum] > 0x10000 - texture->height)
+ I_Error("R_GenerateLookup: texture %i is >64k", texnum);
+ texturecompositesize[texnum] += texture->height;
+ }
+ }
+
+ Z_Free(patchcount);
+}
+
+
+/*
+================
+=
+= R_GetColumn
+=
+================
+*/
+
+byte *R_GetColumn(int tex, int col)
+{
+ int lump, ofs;
+
+ col &= texturewidthmask[tex];
+ lump = texturecolumnlump[tex][col];
+ ofs = texturecolumnofs[tex][col];
+ if (lump > 0)
+ return (byte *) W_CacheLumpNum(lump, PU_CACHE) + ofs;
+ if (!texturecomposite[tex])
+ R_GenerateComposite(tex);
+ return texturecomposite[tex] + ofs;
+}
+
+
+/*
+==================
+=
+= R_InitTextures
+=
+= Initializes the texture list with the textures from the world map
+=
+==================
+*/
+
+void R_InitTextures(void)
+{
+ maptexture_t *mtexture;
+ texture_t *texture;
+ mappatch_t *mpatch;
+ texpatch_t *patch;
+ int i, j;
+ int *maptex, *maptex2, *maptex1;
+ char name[9], *names, *name_p;
+ int *patchlookup;
+ int totalwidth;
+ int nummappatches;
+ int offset, maxoff, maxoff2;
+ int numtextures1, numtextures2;
+ int *directory;
+ char *texture1, *texture2, *pnames;
+
+ texture1 = DEH_String("TEXTURE1");
+ texture2 = DEH_String("TEXTURE2");
+ pnames = DEH_String("PNAMES");
+
+//
+// load the patch names from pnames.lmp
+//
+ name[8] = 0;
+ names = W_CacheLumpName(pnames, PU_STATIC);
+ nummappatches = LONG(*((int *) names));
+ name_p = names + 4;
+ patchlookup = Z_Malloc(nummappatches * sizeof(*patchlookup), PU_STATIC, NULL);
+ for (i = 0; i < nummappatches; i++)
+ {
+ strncpy(name, name_p + i * 8, 8);
+ patchlookup[i] = W_CheckNumForName(name);
+ }
+ W_ReleaseLumpName(pnames);
+
+//
+// load the map texture definitions from textures.lmp
+//
+ maptex = maptex1 = W_CacheLumpName(texture1, PU_STATIC);
+ numtextures1 = LONG(*maptex);
+ maxoff = W_LumpLength(W_GetNumForName(texture1));
+ directory = maptex + 1;
+
+ if (W_CheckNumForName(texture2) != -1)
+ {
+ maptex2 = W_CacheLumpName(texture2, PU_STATIC);
+ numtextures2 = LONG(*maptex2);
+ maxoff2 = W_LumpLength(W_GetNumForName(texture2));
+ }
+ else
+ {
+ maptex2 = NULL;
+ numtextures2 = 0;
+ maxoff2 = 0;
+ }
+ numtextures = numtextures1 + numtextures2;
+
+ //
+ // Init the startup thermometer at this point...
+ //
+ {
+ int start, end;
+ int spramount;
+ start = W_GetNumForName(DEH_String("S_START"));
+ end = W_GetNumForName(DEH_String("S_END"));
+ spramount = end - start + 1;
+ InitThermo(spramount + numtextures + 6);
+ }
+
+ textures = Z_Malloc(numtextures * sizeof(texture_t *), PU_STATIC, 0);
+ texturecolumnlump = Z_Malloc(numtextures * sizeof(short *), PU_STATIC, 0);
+ texturecolumnofs = Z_Malloc(numtextures * sizeof(unsigned short *), PU_STATIC, 0);
+ texturecomposite = Z_Malloc(numtextures * sizeof(byte *), PU_STATIC, 0);
+ texturecompositesize = Z_Malloc(numtextures * sizeof(int), PU_STATIC, 0);
+ texturewidthmask = Z_Malloc(numtextures * sizeof(int), PU_STATIC, 0);
+ textureheight = Z_Malloc(numtextures * sizeof(fixed_t), PU_STATIC, 0);
+
+ totalwidth = 0;
+
+ for (i = 0; i < numtextures; i++, directory++)
+ {
+#ifdef __NEXT__
+ if (!(i & 63))
+ printf(".");
+#else
+ IncThermo();
+#endif
+ if (i == numtextures1)
+ { // start looking in second texture file
+ maptex = maptex2;
+ maxoff = maxoff2;
+ directory = maptex + 1;
+ }
+
+ offset = LONG(*directory);
+ if (offset > maxoff)
+ I_Error("R_InitTextures: bad texture directory");
+ mtexture = (maptexture_t *) ((byte *) maptex + offset);
+ texture = textures[i] = Z_Malloc(sizeof(texture_t)
+ +
+ sizeof(texpatch_t) *
+ (SHORT(mtexture->patchcount) - 1),
+ PU_STATIC, 0);
+ texture->width = SHORT(mtexture->width);
+ texture->height = SHORT(mtexture->height);
+ texture->patchcount = SHORT(mtexture->patchcount);
+ memcpy(texture->name, mtexture->name, sizeof(texture->name));
+ mpatch = &mtexture->patches[0];
+ patch = &texture->patches[0];
+ for (j = 0; j < texture->patchcount; j++, mpatch++, patch++)
+ {
+ patch->originx = SHORT(mpatch->originx);
+ patch->originy = SHORT(mpatch->originy);
+ patch->patch = patchlookup[SHORT(mpatch->patch)];
+ if (patch->patch == -1)
+ I_Error("R_InitTextures: Missing patch in texture %s",
+ texture->name);
+ }
+ texturecolumnlump[i] = Z_Malloc(texture->width * sizeof(short),
+ PU_STATIC, 0);
+ texturecolumnofs[i] = Z_Malloc(texture->width * sizeof(short),
+ PU_STATIC, 0);
+ j = 1;
+ while (j * 2 <= texture->width)
+ j <<= 1;
+ texturewidthmask[i] = j - 1;
+ textureheight[i] = texture->height << FRACBITS;
+
+ totalwidth += texture->width;
+ }
+
+ Z_Free(patchlookup);
+
+ W_ReleaseLumpName(texture1);
+ if (maptex2)
+ {
+ W_ReleaseLumpName(texture2);
+ }
+
+//
+// precalculate whatever possible
+//
+ for (i = 0; i < numtextures; i++)
+ {
+ R_GenerateLookup(i);
+ CheckAbortStartup();
+ }
+
+//
+// translation table for global animation
+//
+ texturetranslation = Z_Malloc((numtextures + 1) * sizeof(int), PU_STATIC, 0);
+ for (i = 0; i < numtextures; i++)
+ texturetranslation[i] = i;
+}
+
+
+/*
+================
+=
+= R_InitFlats
+=
+=================
+*/
+
+void R_InitFlats(void)
+{
+ int i;
+
+ firstflat = W_GetNumForName(DEH_String("F_START")) + 1;
+ lastflat = W_GetNumForName(DEH_String("F_END")) - 1;
+ numflats = lastflat - firstflat + 1;
+
+// translation table for global animation
+ flattranslation = Z_Malloc((numflats + 1) * sizeof(int), PU_STATIC, 0);
+ for (i = 0; i < numflats; i++)
+ flattranslation[i] = i;
+}
+
+
+/*
+================
+=
+= R_InitSpriteLumps
+=
+= Finds the width and hoffset of all sprites in the wad, so the sprite doesn't
+= need to be cached just for the header during rendering
+=================
+*/
+
+void R_InitSpriteLumps(void)
+{
+ int i;
+ patch_t *patch;
+
+ firstspritelump = W_GetNumForName(DEH_String("S_START")) + 1;
+ lastspritelump = W_GetNumForName(DEH_String("S_END")) - 1;
+ numspritelumps = lastspritelump - firstspritelump + 1;
+ spritewidth = Z_Malloc(numspritelumps * sizeof(fixed_t), PU_STATIC, 0);
+ spriteoffset = Z_Malloc(numspritelumps * sizeof(fixed_t), PU_STATIC, 0);
+ spritetopoffset = Z_Malloc(numspritelumps * sizeof(fixed_t), PU_STATIC, 0);
+
+ for (i = 0; i < numspritelumps; i++)
+ {
+#ifdef __NEXT__
+ if (!(i & 63))
+ printf(".");
+#else
+ IncThermo();
+#endif
+ patch = W_CacheLumpNum(firstspritelump + i, PU_CACHE);
+ spritewidth[i] = SHORT(patch->width) << FRACBITS;
+ spriteoffset[i] = SHORT(patch->leftoffset) << FRACBITS;
+ spritetopoffset[i] = SHORT(patch->topoffset) << FRACBITS;
+ }
+}
+
+
+/*
+================
+=
+= R_InitColormaps
+=
+=================
+*/
+
+void R_InitColormaps(void)
+{
+ int lump, length;
+//
+// load in the light tables
+// 256 byte align tables
+//
+ lump = W_GetNumForName(DEH_String("COLORMAP"));
+ length = W_LumpLength(lump);
+ colormaps = Z_Malloc(length, PU_STATIC, 0);
+ W_ReadLump(lump, colormaps);
+}
+
+
+/*
+================
+=
+= R_InitData
+=
+= Locates all the lumps that will be used by all views
+= Must be called after W_Init
+=================
+*/
+
+void R_InitData(void)
+{
+ //tprintf("\nR_InitTextures ", 0);
+ R_InitTextures();
+ printf (".");
+ //tprintf("R_InitFlats\n", 0);
+ R_InitFlats();
+ IncThermo();
+ printf (".");
+ //tprintf("R_InitSpriteLumps ", 0);
+ R_InitSpriteLumps();
+ IncThermo();
+ printf (".");
+ R_InitColormaps();
+}
+
+
+//=============================================================================
+
+/*
+================
+=
+= R_FlatNumForName
+=
+================
+*/
+
+int R_FlatNumForName(char *name)
+{
+ int i;
+ char namet[9];
+
+ i = W_CheckNumForName(name);
+ if (i == -1)
+ {
+ namet[8] = 0;
+ memcpy(namet, name, 8);
+ I_Error("R_FlatNumForName: %s not found", namet);
+ }
+ return i - firstflat;
+}
+
+
+/*
+================
+=
+= R_CheckTextureNumForName
+=
+================
+*/
+
+int R_CheckTextureNumForName(char *name)
+{
+ int i;
+
+ if (name[0] == '-') // no texture marker
+ return 0;
+
+ for (i = 0; i < numtextures; i++)
+ if (!strncasecmp(textures[i]->name, name, 8))
+ return i;
+
+ return -1;
+}
+
+
+/*
+================
+=
+= R_TextureNumForName
+=
+================
+*/
+
+int R_TextureNumForName(char *name)
+{
+ int i;
+ //char namet[9];
+
+ i = R_CheckTextureNumForName(name);
+ if (i == -1)
+ I_Error("R_TextureNumForName: %s not found", name);
+
+ return i;
+}
+
+
+/*
+=================
+=
+= R_PrecacheLevel
+=
+= Preloads all relevent graphics for the level
+=================
+*/
+
+int flatmemory, texturememory, spritememory;
+
+void R_PrecacheLevel(void)
+{
+ char *flatpresent;
+ char *texturepresent;
+ char *spritepresent;
+ int i, j, k, lump;
+ texture_t *texture;
+ thinker_t *th;
+ spriteframe_t *sf;
+
+ if (demoplayback)
+ return;
+
+//
+// precache flats
+//
+ flatpresent = Z_Malloc(numflats, PU_STATIC, NULL);
+ memset(flatpresent, 0, numflats);
+ for (i = 0; i < numsectors; i++)
+ {
+ flatpresent[sectors[i].floorpic] = 1;
+ flatpresent[sectors[i].ceilingpic] = 1;
+ }
+
+ flatmemory = 0;
+ for (i = 0; i < numflats; i++)
+ if (flatpresent[i])
+ {
+ lump = firstflat + i;
+ flatmemory += lumpinfo[lump].size;
+ W_CacheLumpNum(lump, PU_CACHE);
+ }
+
+ Z_Free(flatpresent);
+
+//
+// precache textures
+//
+ texturepresent = Z_Malloc(numtextures, PU_STATIC, NULL);
+ memset(texturepresent, 0, numtextures);
+
+ for (i = 0; i < numsides; i++)
+ {
+ texturepresent[sides[i].toptexture] = 1;
+ texturepresent[sides[i].midtexture] = 1;
+ texturepresent[sides[i].bottomtexture] = 1;
+ }
+
+ texturepresent[skytexture] = 1;
+
+ texturememory = 0;
+ for (i = 0; i < numtextures; i++)
+ {
+ if (!texturepresent[i])
+ continue;
+ texture = textures[i];
+ for (j = 0; j < texture->patchcount; j++)
+ {
+ lump = texture->patches[j].patch;
+ texturememory += lumpinfo[lump].size;
+ W_CacheLumpNum(lump, PU_CACHE);
+ }
+ }
+
+ Z_Free(texturepresent);
+
+//
+// precache sprites
+//
+ spritepresent = Z_Malloc(numsprites, PU_STATIC, NULL);
+ memset(spritepresent, 0, numsprites);
+
+ for (th = thinkercap.next; th != &thinkercap; th = th->next)
+ {
+ if (th->function == P_MobjThinker)
+ spritepresent[((mobj_t *) th)->sprite] = 1;
+ }
+
+ spritememory = 0;
+ for (i = 0; i < numsprites; i++)
+ {
+ if (!spritepresent[i])
+ continue;
+ for (j = 0; j < sprites[i].numframes; j++)
+ {
+ sf = &sprites[i].spriteframes[j];
+ for (k = 0; k < 8; k++)
+ {
+ lump = firstspritelump + sf->lump[k];
+ spritememory += lumpinfo[lump].size;
+ W_CacheLumpNum(lump, PU_CACHE);
+ }
+ }
+ }
+
+ Z_Free(spritepresent);
+}
diff --git a/src/heretic/r_draw.c b/src/heretic/r_draw.c
new file mode 100644
index 00000000..88653df1
--- /dev/null
+++ b/src/heretic/r_draw.c
@@ -0,0 +1,498 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+// R_draw.c
+
+#include "doomdef.h"
+#include "deh_str.h"
+#include "r_local.h"
+#include "i_video.h"
+#include "v_video.h"
+
+/*
+
+All drawing to the view buffer is accomplished in this file. The other refresh
+files only know about ccordinates, not the architecture of the frame buffer.
+
+*/
+
+byte *viewimage;
+int viewwidth, scaledviewwidth, viewheight, viewwindowx, viewwindowy;
+byte *ylookup[MAXHEIGHT];
+int columnofs[MAXWIDTH];
+byte translations[3][256]; // color tables for different players
+
+/*
+==================
+=
+= R_DrawColumn
+=
+= Source is the top of the column to scale
+=
+==================
+*/
+
+lighttable_t *dc_colormap;
+int dc_x;
+int dc_yl;
+int dc_yh;
+fixed_t dc_iscale;
+fixed_t dc_texturemid;
+byte *dc_source; // first pixel in a column (possibly virtual)
+
+int dccount; // just for profiling
+
+void R_DrawColumn(void)
+{
+ int count;
+ byte *dest;
+ fixed_t frac, fracstep;
+
+ count = dc_yh - dc_yl;
+ if (count < 0)
+ return;
+
+#ifdef RANGECHECK
+ if ((unsigned) dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+ I_Error("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ fracstep = dc_iscale;
+ frac = dc_texturemid + (dc_yl - centery) * fracstep;
+
+ do
+ {
+ *dest = dc_colormap[dc_source[(frac >> FRACBITS) & 127]];
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ }
+ while (count--);
+}
+
+void R_DrawColumnLow(void)
+{
+ int count;
+ byte *dest;
+ fixed_t frac, fracstep;
+
+ count = dc_yh - dc_yl;
+ if (count < 0)
+ return;
+
+#ifdef RANGECHECK
+ if ((unsigned) dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+ I_Error("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
+// dccount++;
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ fracstep = dc_iscale;
+ frac = dc_texturemid + (dc_yl - centery) * fracstep;
+
+ do
+ {
+ *dest = dc_colormap[dc_source[(frac >> FRACBITS) & 127]];
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ }
+ while (count--);
+}
+
+// Translucent column draw - blended with background using tinttable.
+
+void R_DrawTLColumn(void)
+{
+ int count;
+ byte *dest;
+ fixed_t frac, fracstep;
+
+ if (!dc_yl)
+ dc_yl = 1;
+ if (dc_yh == viewheight - 1)
+ dc_yh = viewheight - 2;
+
+ count = dc_yh - dc_yl;
+ if (count < 0)
+ return;
+
+#ifdef RANGECHECK
+ if ((unsigned) dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+ I_Error("R_DrawTLColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ fracstep = dc_iscale;
+ frac = dc_texturemid + (dc_yl - centery) * fracstep;
+
+ do
+ {
+ *dest =
+ tinttable[((*dest) << 8) +
+ dc_colormap[dc_source[(frac >> FRACBITS) & 127]]];
+
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ }
+ while (count--);
+}
+
+/*
+========================
+=
+= R_DrawTranslatedColumn
+=
+========================
+*/
+
+byte *dc_translation;
+byte *translationtables;
+
+void R_DrawTranslatedColumn(void)
+{
+ int count;
+ byte *dest;
+ fixed_t frac, fracstep;
+
+ count = dc_yh - dc_yl;
+ if (count < 0)
+ return;
+
+#ifdef RANGECHECK
+ if ((unsigned) dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+ I_Error("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ fracstep = dc_iscale;
+ frac = dc_texturemid + (dc_yl - centery) * fracstep;
+
+ do
+ {
+ *dest = dc_colormap[dc_translation[dc_source[frac >> FRACBITS]]];
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ }
+ while (count--);
+}
+
+void R_DrawTranslatedTLColumn(void)
+{
+ int count;
+ byte *dest;
+ fixed_t frac, fracstep;
+
+ count = dc_yh - dc_yl;
+ if (count < 0)
+ return;
+
+#ifdef RANGECHECK
+ if ((unsigned) dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+ I_Error("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ fracstep = dc_iscale;
+ frac = dc_texturemid + (dc_yl - centery) * fracstep;
+
+ do
+ {
+ *dest = tinttable[((*dest) << 8)
+ +
+ dc_colormap[dc_translation
+ [dc_source[frac >> FRACBITS]]]];
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ }
+ while (count--);
+}
+
+//--------------------------------------------------------------------------
+//
+// PROC R_InitTranslationTables
+//
+//--------------------------------------------------------------------------
+
+void R_InitTranslationTables(void)
+{
+ int i;
+
+ V_LoadTintTable();
+
+ // Allocate translation tables
+ translationtables = Z_Malloc(256 * 3, PU_STATIC, 0);
+
+ // Fill out the translation tables
+ for (i = 0; i < 256; i++)
+ {
+ if (i >= 225 && i <= 240)
+ {
+ translationtables[i] = 114 + (i - 225); // yellow
+ translationtables[i + 256] = 145 + (i - 225); // red
+ translationtables[i + 512] = 190 + (i - 225); // blue
+ }
+ else
+ {
+ translationtables[i] = translationtables[i + 256]
+ = translationtables[i + 512] = i;
+ }
+ }
+}
+
+/*
+================
+=
+= R_DrawSpan
+=
+================
+*/
+
+int ds_y;
+int ds_x1;
+int ds_x2;
+lighttable_t *ds_colormap;
+fixed_t ds_xfrac;
+fixed_t ds_yfrac;
+fixed_t ds_xstep;
+fixed_t ds_ystep;
+byte *ds_source; // start of a 64*64 tile image
+
+int dscount; // just for profiling
+
+void R_DrawSpan(void)
+{
+ fixed_t xfrac, yfrac;
+ byte *dest;
+ int count, spot;
+
+#ifdef RANGECHECK
+ if (ds_x2 < ds_x1 || ds_x1 < 0 || ds_x2 >= SCREENWIDTH
+ || (unsigned) ds_y > SCREENHEIGHT)
+ I_Error("R_DrawSpan: %i to %i at %i", ds_x1, ds_x2, ds_y);
+// dscount++;
+#endif
+
+ xfrac = ds_xfrac;
+ yfrac = ds_yfrac;
+
+ dest = ylookup[ds_y] + columnofs[ds_x1];
+ count = ds_x2 - ds_x1;
+ do
+ {
+ spot = ((yfrac >> (16 - 6)) & (63 * 64)) + ((xfrac >> 16) & 63);
+ *dest++ = ds_colormap[ds_source[spot]];
+ xfrac += ds_xstep;
+ yfrac += ds_ystep;
+ }
+ while (count--);
+}
+
+void R_DrawSpanLow(void)
+{
+ fixed_t xfrac, yfrac;
+ byte *dest;
+ int count, spot;
+
+#ifdef RANGECHECK
+ if (ds_x2 < ds_x1 || ds_x1 < 0 || ds_x2 >= SCREENWIDTH
+ || (unsigned) ds_y > SCREENHEIGHT)
+ I_Error("R_DrawSpan: %i to %i at %i", ds_x1, ds_x2, ds_y);
+// dscount++;
+#endif
+
+ xfrac = ds_xfrac;
+ yfrac = ds_yfrac;
+
+ dest = ylookup[ds_y] + columnofs[ds_x1];
+ count = ds_x2 - ds_x1;
+ do
+ {
+ spot = ((yfrac >> (16 - 6)) & (63 * 64)) + ((xfrac >> 16) & 63);
+ *dest++ = ds_colormap[ds_source[spot]];
+ xfrac += ds_xstep;
+ yfrac += ds_ystep;
+ }
+ while (count--);
+}
+
+
+
+/*
+================
+=
+= R_InitBuffer
+=
+=================
+*/
+
+void R_InitBuffer(int width, int height)
+{
+ int i;
+
+ viewwindowx = (SCREENWIDTH - width) >> 1;
+ for (i = 0; i < width; i++)
+ columnofs[i] = viewwindowx + i;
+ if (width == SCREENWIDTH)
+ viewwindowy = 0;
+ else
+ viewwindowy = (SCREENHEIGHT - SBARHEIGHT - height) >> 1;
+ for (i = 0; i < height; i++)
+ ylookup[i] = I_VideoBuffer + (i + viewwindowy) * SCREENWIDTH;
+}
+
+
+/*
+==================
+=
+= R_DrawViewBorder
+=
+= Draws the border around the view for different size windows
+==================
+*/
+
+boolean BorderNeedRefresh;
+
+void R_DrawViewBorder(void)
+{
+ byte *src, *dest;
+ int x, y;
+
+ if (scaledviewwidth == SCREENWIDTH)
+ return;
+
+ if (gamemode == shareware)
+ {
+ src = W_CacheLumpName(DEH_String("FLOOR04"), PU_CACHE);
+ }
+ else
+ {
+ src = W_CacheLumpName(DEH_String("FLAT513"), PU_CACHE);
+ }
+ dest = I_VideoBuffer;
+
+ for (y = 0; y < SCREENHEIGHT - SBARHEIGHT; y++)
+ {
+ for (x = 0; x < SCREENWIDTH / 64; x++)
+ {
+ memcpy(dest, src + ((y & 63) << 6), 64);
+ dest += 64;
+ }
+ if (SCREENWIDTH & 63)
+ {
+ memcpy(dest, src + ((y & 63) << 6), SCREENWIDTH & 63);
+ dest += (SCREENWIDTH & 63);
+ }
+ }
+ for (x = viewwindowx; x < viewwindowx + viewwidth; x += 16)
+ {
+ V_DrawPatch(x, viewwindowy - 4,
+ W_CacheLumpName(DEH_String("bordt"), PU_CACHE));
+ V_DrawPatch(x, viewwindowy + viewheight,
+ W_CacheLumpName(DEH_String("bordb"), PU_CACHE));
+ }
+ for (y = viewwindowy; y < viewwindowy + viewheight; y += 16)
+ {
+ V_DrawPatch(viewwindowx - 4, y,
+ W_CacheLumpName(DEH_String("bordl"), PU_CACHE));
+ V_DrawPatch(viewwindowx + viewwidth, y,
+ W_CacheLumpName(DEH_String("bordr"), PU_CACHE));
+ }
+ V_DrawPatch(viewwindowx - 4, viewwindowy - 4,
+ W_CacheLumpName(DEH_String("bordtl"), PU_CACHE));
+ V_DrawPatch(viewwindowx + viewwidth, viewwindowy - 4,
+ W_CacheLumpName(DEH_String("bordtr"), PU_CACHE));
+ V_DrawPatch(viewwindowx + viewwidth, viewwindowy + viewheight,
+ W_CacheLumpName(DEH_String("bordbr"), PU_CACHE));
+ V_DrawPatch(viewwindowx - 4, viewwindowy + viewheight,
+ W_CacheLumpName(DEH_String("bordbl"), PU_CACHE));
+}
+
+/*
+==================
+=
+= R_DrawTopBorder
+=
+= Draws the top border around the view for different size windows
+==================
+*/
+
+boolean BorderTopRefresh;
+
+void R_DrawTopBorder(void)
+{
+ byte *src, *dest;
+ int x, y;
+
+ if (scaledviewwidth == SCREENWIDTH)
+ return;
+
+ if (gamemode == shareware)
+ {
+ src = W_CacheLumpName(DEH_String("FLOOR04"), PU_CACHE);
+ }
+ else
+ {
+ src = W_CacheLumpName(DEH_String("FLAT513"), PU_CACHE);
+ }
+ dest = I_VideoBuffer;
+
+ for (y = 0; y < 30; y++)
+ {
+ for (x = 0; x < SCREENWIDTH / 64; x++)
+ {
+ memcpy(dest, src + ((y & 63) << 6), 64);
+ dest += 64;
+ }
+ if (SCREENWIDTH & 63)
+ {
+ memcpy(dest, src + ((y & 63) << 6), SCREENWIDTH & 63);
+ dest += (SCREENWIDTH & 63);
+ }
+ }
+ if (viewwindowy < 25)
+ {
+ for (x = viewwindowx; x < viewwindowx + viewwidth; x += 16)
+ {
+ V_DrawPatch(x, viewwindowy - 4,
+ W_CacheLumpName(DEH_String("bordt"), PU_CACHE));
+ }
+ V_DrawPatch(viewwindowx - 4, viewwindowy,
+ W_CacheLumpName(DEH_String("bordl"), PU_CACHE));
+ V_DrawPatch(viewwindowx + viewwidth, viewwindowy,
+ W_CacheLumpName(DEH_String("bordr"), PU_CACHE));
+ V_DrawPatch(viewwindowx - 4, viewwindowy + 16,
+ W_CacheLumpName(DEH_String("bordl"), PU_CACHE));
+ V_DrawPatch(viewwindowx + viewwidth, viewwindowy + 16,
+ W_CacheLumpName(DEH_String("bordr"), PU_CACHE));
+
+ V_DrawPatch(viewwindowx - 4, viewwindowy - 4,
+ W_CacheLumpName(DEH_String("bordtl"), PU_CACHE));
+ V_DrawPatch(viewwindowx + viewwidth, viewwindowy - 4,
+ W_CacheLumpName(DEH_String("bordtr"), PU_CACHE));
+ }
+}
diff --git a/src/heretic/r_local.h b/src/heretic/r_local.h
new file mode 100644
index 00000000..ade120a1
--- /dev/null
+++ b/src/heretic/r_local.h
@@ -0,0 +1,484 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+// R_local.h
+
+#ifndef __R_LOCAL__
+#define __R_LOCAL__
+
+#include "i_video.h"
+#include "v_patch.h"
+
+#define ANGLETOSKYSHIFT 22 // sky map is 256*128*4 maps
+
+#define BASEYCENTER 100
+
+#define MAXWIDTH 1120
+#define MAXHEIGHT 832
+
+#define PI 3.141592657
+
+#define CENTERY (SCREENHEIGHT/2)
+
+#define MINZ (FRACUNIT*4)
+
+#define FIELDOFVIEW 2048 // fineangles in the SCREENWIDTH wide window
+
+//
+// lighting constants
+//
+#define LIGHTLEVELS 16
+#define LIGHTSEGSHIFT 4
+#define MAXLIGHTSCALE 48
+#define LIGHTSCALESHIFT 12
+#define MAXLIGHTZ 128
+#define LIGHTZSHIFT 20
+#define NUMCOLORMAPS 32 // number of diminishing
+#define INVERSECOLORMAP 32
+
+/*
+==============================================================================
+
+ INTERNAL MAP TYPES
+
+==============================================================================
+*/
+
+//================ used by play and refresh
+
+typedef struct
+{
+ fixed_t x, y;
+} vertex_t;
+
+struct line_s;
+
+typedef struct
+{
+ fixed_t floorheight, ceilingheight;
+ short floorpic, ceilingpic;
+ short lightlevel;
+ short special, tag;
+
+ int soundtraversed; // 0 = untraversed, 1,2 = sndlines -1
+ mobj_t *soundtarget; // thing that made a sound (or null)
+
+ int blockbox[4]; // mapblock bounding box for height changes
+ degenmobj_t soundorg; // for any sounds played by the sector
+
+ int validcount; // if == validcount, already checked
+ mobj_t *thinglist; // list of mobjs in sector
+ void *specialdata; // thinker_t for reversable actions
+ int linecount;
+ struct line_s **lines; // [linecount] size
+} sector_t;
+
+typedef struct
+{
+ fixed_t textureoffset; // add this to the calculated texture col
+ fixed_t rowoffset; // add this to the calculated texture top
+ short toptexture, bottomtexture, midtexture;
+ sector_t *sector;
+} side_t;
+
+typedef enum
+{ ST_HORIZONTAL, ST_VERTICAL, ST_POSITIVE, ST_NEGATIVE } slopetype_t;
+
+typedef struct line_s
+{
+ vertex_t *v1, *v2;
+ fixed_t dx, dy; // v2 - v1 for side checking
+ short flags;
+ short special, tag;
+ short sidenum[2]; // sidenum[1] will be -1 if one sided
+ fixed_t bbox[4];
+ slopetype_t slopetype; // to aid move clipping
+ sector_t *frontsector, *backsector;
+ int validcount; // if == validcount, already checked
+ void *specialdata; // thinker_t for reversable actions
+} line_t;
+
+
+typedef struct subsector_s
+{
+ sector_t *sector;
+ short numlines;
+ short firstline;
+} subsector_t;
+
+typedef struct
+{
+ vertex_t *v1, *v2;
+ fixed_t offset;
+ angle_t angle;
+ side_t *sidedef;
+ line_t *linedef;
+ sector_t *frontsector;
+ sector_t *backsector; // NULL for one sided lines
+} seg_t;
+
+typedef struct
+{
+ fixed_t x, y, dx, dy; // partition line
+ fixed_t bbox[2][4]; // bounding box for each child
+ unsigned short children[2]; // if NF_SUBSECTOR its a subsector
+} node_t;
+
+
+/*
+==============================================================================
+
+ OTHER TYPES
+
+==============================================================================
+*/
+
+typedef byte lighttable_t; // this could be wider for >8 bit display
+
+#define MAXVISPLANES 128
+#define MAXOPENINGS SCREENWIDTH*64
+
+typedef struct
+{
+ fixed_t height;
+ int picnum;
+ int lightlevel;
+ int special;
+ int minx, maxx;
+ byte pad1; // leave pads for [minx-1]/[maxx+1]
+ byte top[SCREENWIDTH];
+ byte pad2;
+ byte pad3;
+ byte bottom[SCREENWIDTH];
+ byte pad4;
+} visplane_t;
+
+typedef struct drawseg_s
+{
+ seg_t *curline;
+ int x1, x2;
+ fixed_t scale1, scale2, scalestep;
+ int silhouette; // 0=none, 1=bottom, 2=top, 3=both
+ fixed_t bsilheight; // don't clip sprites above this
+ fixed_t tsilheight; // don't clip sprites below this
+// pointers to lists for sprite clipping
+ short *sprtopclip; // adjusted so [x1] is first value
+ short *sprbottomclip; // adjusted so [x1] is first value
+ short *maskedtexturecol; // adjusted so [x1] is first value
+} drawseg_t;
+
+#define SIL_NONE 0
+#define SIL_BOTTOM 1
+#define SIL_TOP 2
+#define SIL_BOTH 3
+
+#define MAXDRAWSEGS 256
+
+// A vissprite_t is a thing that will be drawn during a refresh
+typedef struct vissprite_s
+{
+ struct vissprite_s *prev, *next;
+ int x1, x2;
+ fixed_t gx, gy; // for line side calculation
+ fixed_t gz, gzt; // global bottom / top for silhouette clipping
+ fixed_t startfrac; // horizontal position of x1
+ fixed_t scale;
+ fixed_t xiscale; // negative if flipped
+ fixed_t texturemid;
+ int patch;
+ lighttable_t *colormap;
+ int mobjflags; // for color translation and shadow draw
+ boolean psprite; // true if psprite
+ fixed_t footclip; // foot clipping
+} vissprite_t;
+
+
+extern visplane_t *floorplane, *ceilingplane;
+
+// Sprites are patches with a special naming convention so they can be
+// recognized by R_InitSprites. The sprite and frame specified by a
+// thing_t is range checked at run time.
+// a sprite is a patch_t that is assumed to represent a three dimensional
+// object and may have multiple rotations pre drawn. Horizontal flipping
+// is used to save space. Some sprites will only have one picture used
+// for all views.
+
+typedef struct
+{
+ boolean rotate; // if false use 0 for any position
+ short lump[8]; // lump to use for view angles 0-7
+ byte flip[8]; // flip (1 = flip) to use for view angles 0-7
+} spriteframe_t;
+
+typedef struct
+{
+ int numframes;
+ spriteframe_t *spriteframes;
+} spritedef_t;
+
+extern spritedef_t *sprites;
+extern int numsprites;
+
+//=============================================================================
+
+extern int numvertexes;
+extern vertex_t *vertexes;
+
+extern int numsegs;
+extern seg_t *segs;
+
+extern int numsectors;
+extern sector_t *sectors;
+
+extern int numsubsectors;
+extern subsector_t *subsectors;
+
+extern int numnodes;
+extern node_t *nodes;
+
+extern int numlines;
+extern line_t *lines;
+
+extern int numsides;
+extern side_t *sides;
+
+
+
+extern fixed_t viewx, viewy, viewz;
+extern angle_t viewangle;
+extern player_t *viewplayer;
+
+
+extern angle_t clipangle;
+
+extern int viewangletox[FINEANGLES / 2];
+extern angle_t xtoviewangle[SCREENWIDTH + 1];
+
+extern fixed_t rw_distance;
+extern angle_t rw_normalangle;
+
+//
+// R_main.c
+//
+extern int viewwidth, viewheight, viewwindowx, viewwindowy;
+extern int scaledviewwidth;
+extern int centerx, centery;
+extern int flyheight;
+extern fixed_t centerxfrac;
+extern fixed_t centeryfrac;
+extern fixed_t projection;
+
+extern int validcount;
+
+extern int sscount, linecount, loopcount;
+extern lighttable_t *scalelight[LIGHTLEVELS][MAXLIGHTSCALE];
+extern lighttable_t *scalelightfixed[MAXLIGHTSCALE];
+extern lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ];
+
+extern int extralight;
+extern lighttable_t *fixedcolormap;
+
+extern fixed_t viewcos, viewsin;
+
+extern int detailshift; // 0 = high, 1 = low
+
+extern void (*colfunc) (void);
+extern void (*basecolfunc) (void);
+extern void (*tlcolfunc) (void);
+extern void (*spanfunc) (void);
+
+int R_PointOnSide(fixed_t x, fixed_t y, node_t * node);
+int R_PointOnSegSide(fixed_t x, fixed_t y, seg_t * line);
+angle_t R_PointToAngle(fixed_t x, fixed_t y);
+angle_t R_PointToAngle2(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2);
+fixed_t R_PointToDist(fixed_t x, fixed_t y);
+fixed_t R_ScaleFromGlobalAngle(angle_t visangle);
+subsector_t *R_PointInSubsector(fixed_t x, fixed_t y);
+void R_AddPointToBox(int x, int y, fixed_t * box);
+
+
+//
+// R_bsp.c
+//
+extern seg_t *curline;
+extern side_t *sidedef;
+extern line_t *linedef;
+extern sector_t *frontsector, *backsector;
+
+extern int rw_x;
+extern int rw_stopx;
+
+extern boolean segtextured;
+extern boolean markfloor; // false if the back side is the same plane
+extern boolean markceiling;
+extern boolean skymap;
+
+extern drawseg_t drawsegs[MAXDRAWSEGS], *ds_p;
+
+extern lighttable_t **hscalelight, **vscalelight, **dscalelight;
+
+typedef void (*drawfunc_t) (int start, int stop);
+void R_ClearClipSegs(void);
+
+void R_ClearDrawSegs(void);
+void R_InitSkyMap(void);
+void R_RenderBSPNode(int bspnum);
+
+//
+// R_segs.c
+//
+extern int rw_angle1; // angle to line origin
+
+void R_RenderMaskedSegRange(drawseg_t * ds, int x1, int x2);
+
+
+//
+// R_plane.c
+//
+typedef void (*planefunction_t) (int top, int bottom);
+extern planefunction_t floorfunc, ceilingfunc;
+
+extern int skyflatnum;
+
+extern short openings[MAXOPENINGS], *lastopening;
+
+extern short floorclip[SCREENWIDTH];
+extern short ceilingclip[SCREENWIDTH];
+
+extern fixed_t yslope[SCREENHEIGHT];
+extern fixed_t distscale[SCREENWIDTH];
+
+void R_InitPlanes(void);
+void R_ClearPlanes(void);
+void R_MapPlane(int y, int x1, int x2);
+void R_MakeSpans(int x, int t1, int b1, int t2, int b2);
+void R_DrawPlanes(void);
+
+visplane_t *R_FindPlane(fixed_t height, int picnum, int lightlevel,
+ int special);
+visplane_t *R_CheckPlane(visplane_t * pl, int start, int stop);
+
+
+//
+// R_debug.m
+//
+extern int drawbsp;
+
+//
+// R_data.c
+//
+extern fixed_t *textureheight; // needed for texture pegging
+extern fixed_t *spritewidth; // needed for pre rendering (fracs)
+extern fixed_t *spriteoffset;
+extern fixed_t *spritetopoffset;
+extern lighttable_t *colormaps;
+extern int firstflat;
+extern int numflats;
+
+extern int *flattranslation; // for global animation
+extern int *texturetranslation; // for global animation
+
+extern int firstspritelump, lastspritelump, numspritelumps;
+
+byte *R_GetColumn(int tex, int col);
+void R_InitData(void);
+void R_PrecacheLevel(void);
+
+
+//
+// R_things.c
+//
+#define MAXVISSPRITES 128
+
+extern vissprite_t vissprites[MAXVISSPRITES], *vissprite_p;
+extern vissprite_t vsprsortedhead;
+
+// constant arrays used for psprite clipping and initializing clipping
+extern short negonearray[SCREENWIDTH];
+extern short screenheightarray[SCREENWIDTH];
+
+// vars for R_DrawMaskedColumn
+extern short *mfloorclip;
+extern short *mceilingclip;
+extern fixed_t spryscale;
+extern fixed_t sprtopscreen;
+extern fixed_t sprbotscreen;
+
+extern fixed_t pspritescale, pspriteiscale;
+
+
+void R_DrawMaskedColumn(column_t * column, signed int baseclip);
+
+
+void R_SortVisSprites(void);
+
+void R_AddSprites(sector_t * sec);
+void R_AddPSprites(void);
+void R_DrawSprites(void);
+void R_InitSprites(char **namelist);
+void R_ClearSprites(void);
+void R_DrawMasked(void);
+void R_ClipVisSprite(vissprite_t * vis, int xl, int xh);
+
+//=============================================================================
+//
+// R_draw.c
+//
+//=============================================================================
+
+extern lighttable_t *dc_colormap;
+extern int dc_x;
+extern int dc_yl;
+extern int dc_yh;
+extern fixed_t dc_iscale;
+extern fixed_t dc_texturemid;
+extern byte *dc_source; // first pixel in a column
+
+void R_DrawColumn(void);
+void R_DrawColumnLow(void);
+void R_DrawTLColumn(void);
+void R_DrawTLColumnLow(void);
+void R_DrawTranslatedColumn(void);
+void R_DrawTranslatedTLColumn(void);
+void R_DrawTranslatedColumnLow(void);
+
+extern int ds_y;
+extern int ds_x1;
+extern int ds_x2;
+extern lighttable_t *ds_colormap;
+extern fixed_t ds_xfrac;
+extern fixed_t ds_yfrac;
+extern fixed_t ds_xstep;
+extern fixed_t ds_ystep;
+extern byte *ds_source; // start of a 64*64 tile image
+
+extern byte *translationtables;
+extern byte *dc_translation;
+
+void R_DrawSpan(void);
+void R_DrawSpanLow(void);
+
+void R_InitBuffer(int width, int height);
+void R_InitTranslationTables(void);
+
+#endif // __R_LOCAL__
diff --git a/src/heretic/r_main.c b/src/heretic/r_main.c
new file mode 100644
index 00000000..1101c234
--- /dev/null
+++ b/src/heretic/r_main.c
@@ -0,0 +1,827 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+// R_main.c
+
+#include <stdlib.h>
+#include <math.h>
+#include "doomdef.h"
+#include "m_bbox.h"
+#include "r_local.h"
+#include "tables.h"
+
+int viewangleoffset;
+
+// haleyjd: removed WATCOMC
+
+int validcount = 1; // increment every time a check is made
+
+lighttable_t *fixedcolormap;
+extern lighttable_t **walllights;
+
+int centerx, centery;
+fixed_t centerxfrac, centeryfrac;
+fixed_t projection;
+
+int framecount; // just for profiling purposes
+
+int sscount, linecount, loopcount;
+
+fixed_t viewx, viewy, viewz;
+angle_t viewangle;
+fixed_t viewcos, viewsin;
+player_t *viewplayer;
+
+int detailshift; // 0 = high, 1 = low
+
+//
+// precalculated math tables
+//
+angle_t clipangle;
+
+// The viewangletox[viewangle + FINEANGLES/4] lookup maps the visible view
+// angles to screen X coordinates, flattening the arc to a flat projection
+// plane. There will be many angles mapped to the same X.
+int viewangletox[FINEANGLES / 2];
+
+// The xtoviewangleangle[] table maps a screen pixel to the lowest viewangle
+// that maps back to x ranges from clipangle to -clipangle
+angle_t xtoviewangle[SCREENWIDTH + 1];
+
+lighttable_t *scalelight[LIGHTLEVELS][MAXLIGHTSCALE];
+lighttable_t *scalelightfixed[MAXLIGHTSCALE];
+lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ];
+
+int extralight; // bumped light from gun blasts
+
+void (*colfunc) (void);
+void (*basecolfunc) (void);
+void (*tlcolfunc) (void);
+void (*transcolfunc) (void);
+void (*spanfunc) (void);
+
+/*
+===================
+=
+= R_AddPointToBox
+=
+===================
+*/
+
+void R_AddPointToBox(int x, int y, fixed_t * box)
+{
+ if (x < box[BOXLEFT])
+ box[BOXLEFT] = x;
+ if (x > box[BOXRIGHT])
+ box[BOXRIGHT] = x;
+ if (y < box[BOXBOTTOM])
+ box[BOXBOTTOM] = y;
+ if (y > box[BOXTOP])
+ box[BOXTOP] = y;
+}
+
+
+
+/*
+===============================================================================
+=
+= R_PointOnSide
+=
+= Returns side 0 (front) or 1 (back)
+===============================================================================
+*/
+
+int R_PointOnSide(fixed_t x, fixed_t y, node_t * node)
+{
+ fixed_t dx, dy;
+ fixed_t left, right;
+
+ if (!node->dx)
+ {
+ if (x <= node->x)
+ return node->dy > 0;
+ return node->dy < 0;
+ }
+ if (!node->dy)
+ {
+ if (y <= node->y)
+ return node->dx < 0;
+ return node->dx > 0;
+ }
+
+ dx = (x - node->x);
+ dy = (y - node->y);
+
+// try to quickly decide by looking at sign bits
+ if ((node->dy ^ node->dx ^ dx ^ dy) & 0x80000000)
+ {
+ if ((node->dy ^ dx) & 0x80000000)
+ return 1; // (left is negative)
+ return 0;
+ }
+
+ left = FixedMul(node->dy >> FRACBITS, dx);
+ right = FixedMul(dy, node->dx >> FRACBITS);
+
+ if (right < left)
+ return 0; // front side
+ return 1; // back side
+}
+
+
+int R_PointOnSegSide(fixed_t x, fixed_t y, seg_t * line)
+{
+ fixed_t lx, ly;
+ fixed_t ldx, ldy;
+ fixed_t dx, dy;
+ fixed_t left, right;
+
+ lx = line->v1->x;
+ ly = line->v1->y;
+
+ ldx = line->v2->x - lx;
+ ldy = line->v2->y - ly;
+
+ if (!ldx)
+ {
+ if (x <= lx)
+ return ldy > 0;
+ return ldy < 0;
+ }
+ if (!ldy)
+ {
+ if (y <= ly)
+ return ldx < 0;
+ return ldx > 0;
+ }
+
+ dx = (x - lx);
+ dy = (y - ly);
+
+// try to quickly decide by looking at sign bits
+ if ((ldy ^ ldx ^ dx ^ dy) & 0x80000000)
+ {
+ if ((ldy ^ dx) & 0x80000000)
+ return 1; // (left is negative)
+ return 0;
+ }
+
+ left = FixedMul(ldy >> FRACBITS, dx);
+ right = FixedMul(dy, ldx >> FRACBITS);
+
+ if (right < left)
+ return 0; // front side
+ return 1; // back side
+}
+
+
+/*
+===============================================================================
+=
+= R_PointToAngle
+=
+===============================================================================
+*/
+
+angle_t R_PointToAngle(fixed_t x, fixed_t y)
+{
+ x -= viewx;
+ y -= viewy;
+ if ((!x) && (!y))
+ return 0;
+ if (x >= 0)
+ { // x >=0
+ if (y >= 0)
+ { // y>= 0
+ if (x > y)
+ return tantoangle[SlopeDiv(y, x)]; // octant 0
+ else
+ return ANG90 - 1 - tantoangle[SlopeDiv(x, y)]; // octant 1
+ }
+ else
+ { // y<0
+ y = -y;
+ if (x > y)
+ return -tantoangle[SlopeDiv(y, x)]; // octant 8
+ else
+ return ANG270 + tantoangle[SlopeDiv(x, y)]; // octant 7
+ }
+ }
+ else
+ { // x<0
+ x = -x;
+ if (y >= 0)
+ { // y>= 0
+ if (x > y)
+ return ANG180 - 1 - tantoangle[SlopeDiv(y, x)]; // octant 3
+ else
+ return ANG90 + tantoangle[SlopeDiv(x, y)]; // octant 2
+ }
+ else
+ { // y<0
+ y = -y;
+ if (x > y)
+ return ANG180 + tantoangle[SlopeDiv(y, x)]; // octant 4
+ else
+ return ANG270 - 1 - tantoangle[SlopeDiv(x, y)]; // octant 5
+ }
+ }
+
+ return 0;
+}
+
+
+angle_t R_PointToAngle2(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)
+{
+ viewx = x1;
+ viewy = y1;
+ return R_PointToAngle(x2, y2);
+}
+
+
+fixed_t R_PointToDist(fixed_t x, fixed_t y)
+{
+ int angle;
+ fixed_t dx, dy, temp;
+ fixed_t dist;
+
+ dx = abs(x - viewx);
+ dy = abs(y - viewy);
+
+ if (dy > dx)
+ {
+ temp = dx;
+ dx = dy;
+ dy = temp;
+ }
+
+ angle =
+ (tantoangle[FixedDiv(dy, dx) >> DBITS] + ANG90) >> ANGLETOFINESHIFT;
+
+ dist = FixedDiv(dx, finesine[angle]); // use as cosine
+
+ return dist;
+}
+
+
+
+/*
+=================
+=
+= R_InitPointToAngle
+=
+=================
+*/
+
+void R_InitPointToAngle(void)
+{
+// now getting from tables.c
+#if 0
+ int i;
+ long t;
+ float f;
+//
+// slope (tangent) to angle lookup
+//
+ for (i = 0; i <= SLOPERANGE; i++)
+ {
+ f = atan((float) i / SLOPERANGE) / (3.141592657 * 2);
+ t = 0xffffffff * f;
+ tantoangle[i] = t;
+ }
+#endif
+}
+
+//=============================================================================
+
+/*
+================
+=
+= R_ScaleFromGlobalAngle
+=
+= Returns the texture mapping scale for the current line at the given angle
+= rw_distance must be calculated first
+================
+*/
+
+fixed_t R_ScaleFromGlobalAngle(angle_t visangle)
+{
+ fixed_t scale;
+ int anglea, angleb;
+ int sinea, sineb;
+ fixed_t num, den;
+
+#if 0
+ {
+ fixed_t dist, z;
+ fixed_t sinv, cosv;
+
+ sinv = finesine[(visangle - rw_normalangle) >> ANGLETOFINESHIFT];
+ dist = FixedDiv(rw_distance, sinv);
+ cosv = finecosine[(viewangle - visangle) >> ANGLETOFINESHIFT];
+ z = abs(FixedMul(dist, cosv));
+ scale = FixedDiv(projection, z);
+ return scale;
+ }
+#endif
+
+ anglea = ANG90 + (visangle - viewangle);
+ angleb = ANG90 + (visangle - rw_normalangle);
+// bothe sines are allways positive
+ sinea = finesine[anglea >> ANGLETOFINESHIFT];
+ sineb = finesine[angleb >> ANGLETOFINESHIFT];
+ num = FixedMul(projection, sineb) << detailshift;
+ den = FixedMul(rw_distance, sinea);
+ if (den > num >> 16)
+ {
+ scale = FixedDiv(num, den);
+ if (scale > 64 * FRACUNIT)
+ scale = 64 * FRACUNIT;
+ else if (scale < 256)
+ scale = 256;
+ }
+ else
+ scale = 64 * FRACUNIT;
+
+ return scale;
+}
+
+
+
+/*
+=================
+=
+= R_InitTables
+=
+=================
+*/
+
+void R_InitTables(void)
+{
+// now getting from tables.c
+#if 0
+ int i;
+ float a, fv;
+ int t;
+
+//
+// viewangle tangent table
+//
+ for (i = 0; i < FINEANGLES / 2; i++)
+ {
+ a = (i - FINEANGLES / 4 + 0.5) * PI * 2 / FINEANGLES;
+ fv = FRACUNIT * tan(a);
+ t = fv;
+ finetangent[i] = t;
+ }
+
+//
+// finesine table
+//
+ for (i = 0; i < 5 * FINEANGLES / 4; i++)
+ {
+// OPTIMIZE: mirror...
+ a = (i + 0.5) * PI * 2 / FINEANGLES;
+ t = FRACUNIT * sin(a);
+ finesine[i] = t;
+ }
+#endif
+
+}
+
+
+/*
+=================
+=
+= R_InitTextureMapping
+=
+=================
+*/
+
+void R_InitTextureMapping(void)
+{
+ int i;
+ int x;
+ int t;
+ fixed_t focallength;
+
+
+//
+// use tangent table to generate viewangletox
+// viewangletox will give the next greatest x after the view angle
+//
+ // calc focallength so FIELDOFVIEW angles covers SCREENWIDTH
+ focallength =
+ FixedDiv(centerxfrac, finetangent[FINEANGLES / 4 + FIELDOFVIEW / 2]);
+
+ for (i = 0; i < FINEANGLES / 2; i++)
+ {
+ if (finetangent[i] > FRACUNIT * 2)
+ t = -1;
+ else if (finetangent[i] < -FRACUNIT * 2)
+ t = viewwidth + 1;
+ else
+ {
+ t = FixedMul(finetangent[i], focallength);
+ t = (centerxfrac - t + FRACUNIT - 1) >> FRACBITS;
+ if (t < -1)
+ t = -1;
+ else if (t > viewwidth + 1)
+ t = viewwidth + 1;
+ }
+ viewangletox[i] = t;
+ }
+
+//
+// scan viewangletox[] to generate xtoviewangleangle[]
+//
+// xtoviewangle will give the smallest view angle that maps to x
+ for (x = 0; x <= viewwidth; x++)
+ {
+ i = 0;
+ while (viewangletox[i] > x)
+ i++;
+ xtoviewangle[x] = (i << ANGLETOFINESHIFT) - ANG90;
+ }
+
+//
+// take out the fencepost cases from viewangletox
+//
+ for (i = 0; i < FINEANGLES / 2; i++)
+ {
+ t = FixedMul(finetangent[i], focallength);
+ t = centerx - t;
+ if (viewangletox[i] == -1)
+ viewangletox[i] = 0;
+ else if (viewangletox[i] == viewwidth + 1)
+ viewangletox[i] = viewwidth;
+ }
+
+ clipangle = xtoviewangle[0];
+}
+
+//=============================================================================
+
+/*
+====================
+=
+= R_InitLightTables
+=
+= Only inits the zlight table, because the scalelight table changes
+= with view size
+=
+====================
+*/
+
+#define DISTMAP 2
+
+void R_InitLightTables(void)
+{
+ int i, j, level, startmap;
+ int scale;
+
+//
+// Calculate the light levels to use for each level / distance combination
+//
+ for (i = 0; i < LIGHTLEVELS; i++)
+ {
+ startmap = ((LIGHTLEVELS - 1 - i) * 2) * NUMCOLORMAPS / LIGHTLEVELS;
+ for (j = 0; j < MAXLIGHTZ; j++)
+ {
+ scale =
+ FixedDiv((SCREENWIDTH / 2 * FRACUNIT),
+ (j + 1) << LIGHTZSHIFT);
+ scale >>= LIGHTSCALESHIFT;
+ level = startmap - scale / DISTMAP;
+ if (level < 0)
+ level = 0;
+ if (level >= NUMCOLORMAPS)
+ level = NUMCOLORMAPS - 1;
+ zlight[i][j] = colormaps + level * 256;
+ }
+ }
+}
+
+
+/*
+==============
+=
+= R_SetViewSize
+=
+= Don't really change anything here, because i might be in the middle of
+= a refresh. The change will take effect next refresh.
+=
+==============
+*/
+
+boolean setsizeneeded;
+int setblocks, setdetail;
+
+void R_SetViewSize(int blocks, int detail)
+{
+ setsizeneeded = true;
+ setblocks = blocks;
+ setdetail = detail;
+}
+
+/*
+==============
+=
+= R_ExecuteSetViewSize
+=
+==============
+*/
+
+void R_ExecuteSetViewSize(void)
+{
+ fixed_t cosadj, dy;
+ int i, j, level, startmap;
+
+ setsizeneeded = false;
+
+ if (setblocks == 11)
+ {
+ scaledviewwidth = SCREENWIDTH;
+ viewheight = SCREENHEIGHT;
+ }
+ else
+ {
+ scaledviewwidth = setblocks * 32;
+ viewheight = (setblocks * 158 / 10);
+ }
+
+ detailshift = setdetail;
+ viewwidth = scaledviewwidth >> detailshift;
+
+ centery = viewheight / 2;
+ centerx = viewwidth / 2;
+ centerxfrac = centerx << FRACBITS;
+ centeryfrac = centery << FRACBITS;
+ projection = centerxfrac;
+
+ if (!detailshift)
+ {
+ colfunc = basecolfunc = R_DrawColumn;
+ tlcolfunc = R_DrawTLColumn;
+ transcolfunc = R_DrawTranslatedColumn;
+ spanfunc = R_DrawSpan;
+ }
+ else
+ {
+ colfunc = basecolfunc = R_DrawColumnLow;
+ tlcolfunc = R_DrawTLColumn;
+ transcolfunc = R_DrawTranslatedColumn;
+ spanfunc = R_DrawSpanLow;
+ }
+
+ R_InitBuffer(scaledviewwidth, viewheight);
+
+ R_InitTextureMapping();
+
+//
+// psprite scales
+//
+ pspritescale = FRACUNIT * viewwidth / SCREENWIDTH;
+ pspriteiscale = FRACUNIT * SCREENWIDTH / viewwidth;
+
+//
+// thing clipping
+//
+ for (i = 0; i < viewwidth; i++)
+ screenheightarray[i] = viewheight;
+
+//
+// planes
+//
+ for (i = 0; i < viewheight; i++)
+ {
+ dy = ((i - viewheight / 2) << FRACBITS) + FRACUNIT / 2;
+ dy = abs(dy);
+ yslope[i] = FixedDiv((viewwidth << detailshift) / 2 * FRACUNIT, dy);
+ }
+
+ for (i = 0; i < viewwidth; i++)
+ {
+ cosadj = abs(finecosine[xtoviewangle[i] >> ANGLETOFINESHIFT]);
+ distscale[i] = FixedDiv(FRACUNIT, cosadj);
+ }
+
+//
+// Calculate the light levels to use for each level / scale combination
+//
+ for (i = 0; i < LIGHTLEVELS; i++)
+ {
+ startmap = ((LIGHTLEVELS - 1 - i) * 2) * NUMCOLORMAPS / LIGHTLEVELS;
+ for (j = 0; j < MAXLIGHTSCALE; j++)
+ {
+ level =
+ startmap -
+ j * SCREENWIDTH / (viewwidth << detailshift) / DISTMAP;
+ if (level < 0)
+ level = 0;
+ if (level >= NUMCOLORMAPS)
+ level = NUMCOLORMAPS - 1;
+ scalelight[i][j] = colormaps + level * 256;
+ }
+ }
+
+//
+// draw the border
+//
+ R_DrawViewBorder(); // erase old menu stuff
+}
+
+
+/*
+==============
+=
+= R_Init
+=
+==============
+*/
+
+int detailLevel;
+int screenblocks = 10;
+
+void R_Init(void)
+{
+ //tprintf("R_InitData ", 1);
+ R_InitData();
+ printf (".");
+ //tprintf("R_InitPointToAngle\n", 0);
+ R_InitPointToAngle();
+ printf (".");
+ //tprintf("R_InitTables ", 0);
+ R_InitTables();
+ // viewwidth / viewheight / detailLevel are set by the defaults
+ printf (".");
+ R_SetViewSize(screenblocks, detailLevel);
+ //tprintf("R_InitPlanes\n", 0);
+ R_InitPlanes();
+ printf (".");
+ //tprintf("R_InitLightTables ", 0);
+ R_InitLightTables();
+ printf (".");
+ //tprintf("R_InitSkyMap\n", 0);
+ R_InitSkyMap();
+ printf (".");
+ R_InitTranslationTables();
+ framecount = 0;
+}
+
+
+/*
+==============
+=
+= R_PointInSubsector
+=
+==============
+*/
+
+subsector_t *R_PointInSubsector(fixed_t x, fixed_t y)
+{
+ node_t *node;
+ int side, nodenum;
+
+ if (!numnodes) // single subsector is a special case
+ return subsectors;
+
+ nodenum = numnodes - 1;
+
+ while (!(nodenum & NF_SUBSECTOR))
+ {
+ node = &nodes[nodenum];
+ side = R_PointOnSide(x, y, node);
+ nodenum = node->children[side];
+ }
+
+ return &subsectors[nodenum & ~NF_SUBSECTOR];
+
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC R_SetupFrame
+//
+//----------------------------------------------------------------------------
+
+void R_SetupFrame(player_t * player)
+{
+ int i;
+ int tableAngle;
+ int tempCentery;
+
+ //drawbsp = 1;
+ viewplayer = player;
+ // haleyjd: removed WATCOMC
+ // haleyjd FIXME: viewangleoffset handling?
+ viewangle = player->mo->angle + viewangleoffset;
+ tableAngle = viewangle >> ANGLETOFINESHIFT;
+ if (player->chickenTics && player->chickenPeck)
+ { // Set chicken attack view position
+ viewx = player->mo->x + player->chickenPeck * finecosine[tableAngle];
+ viewy = player->mo->y + player->chickenPeck * finesine[tableAngle];
+ }
+ else
+ { // Normal view position
+ viewx = player->mo->x;
+ viewy = player->mo->y;
+ }
+ extralight = player->extralight;
+ viewz = player->viewz;
+
+ tempCentery = viewheight / 2 + (player->lookdir) * screenblocks / 10;
+ if (centery != tempCentery)
+ {
+ centery = tempCentery;
+ centeryfrac = centery << FRACBITS;
+ for (i = 0; i < viewheight; i++)
+ {
+ yslope[i] = FixedDiv((viewwidth << detailshift) / 2 * FRACUNIT,
+ abs(((i - centery) << FRACBITS) +
+ FRACUNIT / 2));
+ }
+ }
+ viewsin = finesine[tableAngle];
+ viewcos = finecosine[tableAngle];
+ sscount = 0;
+ if (player->fixedcolormap)
+ {
+ fixedcolormap = colormaps + player->fixedcolormap
+ * 256 * sizeof(lighttable_t);
+ walllights = scalelightfixed;
+ for (i = 0; i < MAXLIGHTSCALE; i++)
+ {
+ scalelightfixed[i] = fixedcolormap;
+ }
+ }
+ else
+ {
+ fixedcolormap = 0;
+ }
+ framecount++;
+ validcount++;
+ if (BorderNeedRefresh)
+ {
+ if (setblocks < 10)
+ {
+ R_DrawViewBorder();
+ }
+ BorderNeedRefresh = false;
+ BorderTopRefresh = false;
+ UpdateState |= I_FULLSCRN;
+ }
+ if (BorderTopRefresh)
+ {
+ if (setblocks < 10)
+ {
+ R_DrawTopBorder();
+ }
+ BorderTopRefresh = false;
+ UpdateState |= I_MESSAGES;
+ }
+}
+
+/*
+==============
+=
+= R_RenderView
+=
+==============
+*/
+
+void R_RenderPlayerView(player_t * player)
+{
+ R_SetupFrame(player);
+ R_ClearClipSegs();
+ R_ClearDrawSegs();
+ R_ClearPlanes();
+ R_ClearSprites();
+ NetUpdate(); // check for new console commands
+ R_RenderBSPNode(numnodes - 1); // the head node is the last node output
+ NetUpdate(); // check for new console commands
+ R_DrawPlanes();
+ NetUpdate(); // check for new console commands
+ R_DrawMasked();
+ NetUpdate(); // check for new console commands
+}
diff --git a/src/heretic/r_plane.c b/src/heretic/r_plane.c
new file mode 100644
index 00000000..cc86b118
--- /dev/null
+++ b/src/heretic/r_plane.c
@@ -0,0 +1,521 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+// R_planes.c
+
+#include <stdlib.h>
+#include "doomdef.h"
+#include "deh_str.h"
+#include "i_system.h"
+#include "r_local.h"
+
+planefunction_t floorfunc, ceilingfunc;
+
+//
+// sky mapping
+//
+int skyflatnum;
+int skytexture;
+int skytexturemid;
+fixed_t skyiscale;
+
+//
+// opening
+//
+
+visplane_t visplanes[MAXVISPLANES], *lastvisplane;
+visplane_t *floorplane, *ceilingplane;
+
+short openings[MAXOPENINGS], *lastopening;
+
+//
+// clip values are the solid pixel bounding the range
+// floorclip starts out SCREENHEIGHT
+// ceilingclip starts out -1
+//
+short floorclip[SCREENWIDTH];
+short ceilingclip[SCREENWIDTH];
+
+//
+// spanstart holds the start of a plane span
+// initialized to 0 at start
+//
+int spanstart[SCREENHEIGHT];
+int spanstop[SCREENHEIGHT];
+
+//
+// texture mapping
+//
+lighttable_t **planezlight;
+fixed_t planeheight;
+
+fixed_t yslope[SCREENHEIGHT];
+fixed_t distscale[SCREENWIDTH];
+fixed_t basexscale, baseyscale;
+
+fixed_t cachedheight[SCREENHEIGHT];
+fixed_t cacheddistance[SCREENHEIGHT];
+fixed_t cachedxstep[SCREENHEIGHT];
+fixed_t cachedystep[SCREENHEIGHT];
+
+
+/*
+================
+=
+= R_InitSkyMap
+=
+= Called whenever the view size changes
+=
+================
+*/
+
+void R_InitSkyMap(void)
+{
+ skyflatnum = R_FlatNumForName(DEH_String("F_SKY1"));
+ skytexturemid = 200 * FRACUNIT;
+ skyiscale = FRACUNIT;
+}
+
+
+/*
+====================
+=
+= R_InitPlanes
+=
+= Only at game startup
+====================
+*/
+
+void R_InitPlanes(void)
+{
+}
+
+
+/*
+================
+=
+= R_MapPlane
+=
+global vars:
+
+planeheight
+ds_source
+basexscale
+baseyscale
+viewx
+viewy
+
+BASIC PRIMITIVE
+================
+*/
+
+void R_MapPlane(int y, int x1, int x2)
+{
+ angle_t angle;
+ fixed_t distance, length;
+ unsigned index;
+
+#ifdef RANGECHECK
+ if (x2 < x1 || x1 < 0 || x2 >= viewwidth || (unsigned) y > viewheight)
+ I_Error("R_MapPlane: %i, %i at %i", x1, x2, y);
+#endif
+
+ if (planeheight != cachedheight[y])
+ {
+ cachedheight[y] = planeheight;
+ distance = cacheddistance[y] = FixedMul(planeheight, yslope[y]);
+
+ ds_xstep = cachedxstep[y] = FixedMul(distance, basexscale);
+ ds_ystep = cachedystep[y] = FixedMul(distance, baseyscale);
+ }
+ else
+ {
+ distance = cacheddistance[y];
+ ds_xstep = cachedxstep[y];
+ ds_ystep = cachedystep[y];
+ }
+
+ length = FixedMul(distance, distscale[x1]);
+ angle = (viewangle + xtoviewangle[x1]) >> ANGLETOFINESHIFT;
+ ds_xfrac = viewx + FixedMul(finecosine[angle], length);
+ ds_yfrac = -viewy - FixedMul(finesine[angle], length);
+
+ if (fixedcolormap)
+ ds_colormap = fixedcolormap;
+ else
+ {
+ index = distance >> LIGHTZSHIFT;
+ if (index >= MAXLIGHTZ)
+ index = MAXLIGHTZ - 1;
+ ds_colormap = planezlight[index];
+ }
+
+ ds_y = y;
+ ds_x1 = x1;
+ ds_x2 = x2;
+
+ spanfunc(); // high or low detail
+}
+
+//=============================================================================
+
+/*
+====================
+=
+= R_ClearPlanes
+=
+= At begining of frame
+====================
+*/
+
+void R_ClearPlanes(void)
+{
+ int i;
+ angle_t angle;
+
+//
+// opening / clipping determination
+//
+ for (i = 0; i < viewwidth; i++)
+ {
+ floorclip[i] = viewheight;
+ ceilingclip[i] = -1;
+ }
+
+ lastvisplane = visplanes;
+ lastopening = openings;
+
+//
+// texture calculation
+//
+ memset(cachedheight, 0, sizeof(cachedheight));
+ angle = (viewangle - ANG90) >> ANGLETOFINESHIFT; // left to right mapping
+
+ // scale will be unit scale at SCREENWIDTH/2 distance
+ basexscale = FixedDiv(finecosine[angle], centerxfrac);
+ baseyscale = -FixedDiv(finesine[angle], centerxfrac);
+}
+
+
+
+/*
+===============
+=
+= R_FindPlane
+=
+===============
+*/
+
+visplane_t *R_FindPlane(fixed_t height, int picnum,
+ int lightlevel, int special)
+{
+ visplane_t *check;
+
+ if (picnum == skyflatnum)
+ {
+ // all skies map together
+ height = 0;
+ lightlevel = 0;
+ }
+
+ for (check = visplanes; check < lastvisplane; check++)
+ {
+ if (height == check->height
+ && picnum == check->picnum
+ && lightlevel == check->lightlevel && special == check->special)
+ break;
+ }
+
+ if (check < lastvisplane)
+ {
+ return (check);
+ }
+
+ if (lastvisplane - visplanes == MAXVISPLANES)
+ {
+ I_Error("R_FindPlane: no more visplanes");
+ }
+
+ lastvisplane++;
+ check->height = height;
+ check->picnum = picnum;
+ check->lightlevel = lightlevel;
+ check->special = special;
+ check->minx = SCREENWIDTH;
+ check->maxx = -1;
+ memset(check->top, 0xff, sizeof(check->top));
+ return (check);
+}
+
+/*
+===============
+=
+= R_CheckPlane
+=
+===============
+*/
+
+visplane_t *R_CheckPlane(visplane_t * pl, int start, int stop)
+{
+ int intrl, intrh;
+ int unionl, unionh;
+ int x;
+
+ if (start < pl->minx)
+ {
+ intrl = pl->minx;
+ unionl = start;
+ }
+ else
+ {
+ unionl = pl->minx;
+ intrl = start;
+ }
+
+ if (stop > pl->maxx)
+ {
+ intrh = pl->maxx;
+ unionh = stop;
+ }
+ else
+ {
+ unionh = pl->maxx;
+ intrh = stop;
+ }
+
+ for (x = intrl; x <= intrh; x++)
+ if (pl->top[x] != 0xff)
+ break;
+
+ if (x > intrh)
+ {
+ pl->minx = unionl;
+ pl->maxx = unionh;
+ return pl; // use the same one
+ }
+
+// make a new visplane
+
+ lastvisplane->height = pl->height;
+ lastvisplane->picnum = pl->picnum;
+ lastvisplane->lightlevel = pl->lightlevel;
+ lastvisplane->special = pl->special;
+ pl = lastvisplane++;
+ pl->minx = start;
+ pl->maxx = stop;
+ memset(pl->top, 0xff, sizeof(pl->top));
+
+ return pl;
+}
+
+
+
+//=============================================================================
+
+/*
+================
+=
+= R_MakeSpans
+=
+================
+*/
+
+void R_MakeSpans(int x, int t1, int b1, int t2, int b2)
+{
+ while (t1 < t2 && t1 <= b1)
+ {
+ R_MapPlane(t1, spanstart[t1], x - 1);
+ t1++;
+ }
+ while (b1 > b2 && b1 >= t1)
+ {
+ R_MapPlane(b1, spanstart[b1], x - 1);
+ b1--;
+ }
+
+ while (t2 < t1 && t2 <= b2)
+ {
+ spanstart[t2] = x;
+ t2++;
+ }
+ while (b2 > b1 && b2 >= t2)
+ {
+ spanstart[b2] = x;
+ b2--;
+ }
+}
+
+
+
+/*
+================
+=
+= R_DrawPlanes
+=
+= At the end of each frame
+================
+*/
+
+void R_DrawPlanes(void)
+{
+ visplane_t *pl;
+ int light;
+ int x, stop;
+ int lumpnum;
+ int angle;
+ byte *tempSource;
+
+ byte *dest;
+ int count;
+ fixed_t frac, fracstep;
+
+ extern byte *ylookup[MAXHEIGHT];
+ extern int columnofs[MAXWIDTH];
+
+#ifdef RANGECHECK
+ if (ds_p - drawsegs > MAXDRAWSEGS)
+ I_Error("R_DrawPlanes: drawsegs overflow (%i)", ds_p - drawsegs);
+ if (lastvisplane - visplanes > MAXVISPLANES)
+ I_Error("R_DrawPlanes: visplane overflow (%i)",
+ lastvisplane - visplanes);
+ if (lastopening - openings > MAXOPENINGS)
+ I_Error("R_DrawPlanes: opening overflow (%i)",
+ lastopening - openings);
+#endif
+
+ for (pl = visplanes; pl < lastvisplane; pl++)
+ {
+ if (pl->minx > pl->maxx)
+ continue;
+ //
+ // sky flat
+ //
+ if (pl->picnum == skyflatnum)
+ {
+ dc_iscale = skyiscale;
+ dc_colormap = colormaps; // sky is allways drawn full bright
+ dc_texturemid = skytexturemid;
+ for (x = pl->minx; x <= pl->maxx; x++)
+ {
+ dc_yl = pl->top[x];
+ dc_yh = pl->bottom[x];
+ if (dc_yl <= dc_yh)
+ {
+ angle = (viewangle + xtoviewangle[x]) >> ANGLETOSKYSHIFT;
+ dc_x = x;
+ dc_source = R_GetColumn(skytexture, angle);
+
+ count = dc_yh - dc_yl;
+ if (count < 0)
+ return;
+
+#ifdef RANGECHECK
+ if ((unsigned) dc_x >= SCREENWIDTH || dc_yl < 0
+ || dc_yh >= SCREENHEIGHT)
+ I_Error("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh,
+ dc_x);
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ fracstep = 1;
+ frac = (dc_texturemid >> FRACBITS) + (dc_yl - centery);
+ do
+ {
+ *dest = dc_source[frac];
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ }
+ while (count--);
+
+// colfunc ();
+ }
+ }
+ continue;
+ }
+
+ //
+ // regular flat
+ //
+ lumpnum = firstflat + flattranslation[pl->picnum];
+
+ tempSource = W_CacheLumpNum(lumpnum, PU_STATIC);
+
+ switch (pl->special)
+ {
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29: // Scroll_North
+ ds_source = tempSource;
+ break;
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24: // Scroll_East
+ ds_source = tempSource + ((63 - ((leveltime >> 1) & 63)) <<
+ (pl->special - 20) & 63);
+ //ds_source = tempSource+((leveltime>>1)&63);
+ break;
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ case 34: // Scroll_South
+ ds_source = tempSource;
+ break;
+ case 35:
+ case 36:
+ case 37:
+ case 38:
+ case 39: // Scroll_West
+ ds_source = tempSource;
+ break;
+ case 4: // Scroll_EastLavaDamage
+ ds_source =
+ tempSource + (((63 - ((leveltime >> 1) & 63)) << 3) & 63);
+ break;
+ default:
+ ds_source = tempSource;
+ }
+ planeheight = abs(pl->height - viewz);
+ light = (pl->lightlevel >> LIGHTSEGSHIFT) + extralight;
+ if (light >= LIGHTLEVELS)
+ light = LIGHTLEVELS - 1;
+ if (light < 0)
+ light = 0;
+ planezlight = zlight[light];
+
+ pl->top[pl->maxx + 1] = 0xff;
+ pl->top[pl->minx - 1] = 0xff;
+
+ stop = pl->maxx + 1;
+ for (x = pl->minx; x <= stop; x++)
+ R_MakeSpans(x, pl->top[x - 1], pl->bottom[x - 1], pl->top[x],
+ pl->bottom[x]);
+
+ W_ReleaseLumpNum(lumpnum);
+ }
+}
diff --git a/src/heretic/r_segs.c b/src/heretic/r_segs.c
new file mode 100644
index 00000000..4e95a2ae
--- /dev/null
+++ b/src/heretic/r_segs.c
@@ -0,0 +1,669 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+//**************************************************************************
+//**
+//** R_SEGS.C
+//**
+//** This version has the tall-sector-crossing-precision-bug fixed.
+//**
+//**************************************************************************
+
+#include <stdlib.h>
+
+#include "doomdef.h"
+#include "r_local.h"
+
+// OPTIMIZE: closed two sided lines as single sided
+
+boolean segtextured; // true if any of the segs textures might be vis
+boolean markfloor; // false if the back side is the same plane
+boolean markceiling;
+boolean maskedtexture;
+int toptexture, bottomtexture, midtexture;
+
+
+angle_t rw_normalangle;
+int rw_angle1; // angle to line origin
+
+//
+// wall
+//
+int rw_x;
+int rw_stopx;
+angle_t rw_centerangle;
+fixed_t rw_offset;
+fixed_t rw_distance;
+fixed_t rw_scale;
+fixed_t rw_scalestep;
+fixed_t rw_midtexturemid;
+fixed_t rw_toptexturemid;
+fixed_t rw_bottomtexturemid;
+
+int worldtop, worldbottom, worldhigh, worldlow;
+
+fixed_t pixhigh, pixlow;
+fixed_t pixhighstep, pixlowstep;
+fixed_t topfrac, topstep;
+fixed_t bottomfrac, bottomstep;
+
+
+lighttable_t **walllights;
+
+short *maskedtexturecol;
+
+/*
+================
+=
+= R_RenderMaskedSegRange
+=
+================
+*/
+
+void R_RenderMaskedSegRange(drawseg_t * ds, int x1, int x2)
+{
+ unsigned index;
+ column_t *col;
+ int lightnum;
+ int texnum;
+
+//
+// calculate light table
+// use different light tables for horizontal / vertical / diagonal
+// OPTIMIZE: get rid of LIGHTSEGSHIFT globally
+ curline = ds->curline;
+ frontsector = curline->frontsector;
+ backsector = curline->backsector;
+ texnum = texturetranslation[curline->sidedef->midtexture];
+
+ lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT) + extralight;
+ if (curline->v1->y == curline->v2->y)
+ lightnum--;
+ else if (curline->v1->x == curline->v2->x)
+ lightnum++;
+ if (lightnum < 0)
+ walllights = scalelight[0];
+ else if (lightnum >= LIGHTLEVELS)
+ walllights = scalelight[LIGHTLEVELS - 1];
+ else
+ walllights = scalelight[lightnum];
+
+ maskedtexturecol = ds->maskedtexturecol;
+
+ rw_scalestep = ds->scalestep;
+ spryscale = ds->scale1 + (x1 - ds->x1) * rw_scalestep;
+ mfloorclip = ds->sprbottomclip;
+ mceilingclip = ds->sprtopclip;
+
+//
+// find positioning
+//
+ if (curline->linedef->flags & ML_DONTPEGBOTTOM)
+ {
+ dc_texturemid = frontsector->floorheight > backsector->floorheight
+ ? frontsector->floorheight : backsector->floorheight;
+ dc_texturemid = dc_texturemid + textureheight[texnum] - viewz;
+ }
+ else
+ {
+ dc_texturemid = frontsector->ceilingheight < backsector->ceilingheight
+ ? frontsector->ceilingheight : backsector->ceilingheight;
+ dc_texturemid = dc_texturemid - viewz;
+ }
+ dc_texturemid += curline->sidedef->rowoffset;
+
+ if (fixedcolormap)
+ dc_colormap = fixedcolormap;
+//
+// draw the columns
+//
+ for (dc_x = x1; dc_x <= x2; dc_x++)
+ {
+ // calculate lighting
+ if (maskedtexturecol[dc_x] != SHRT_MAX)
+ {
+ if (!fixedcolormap)
+ {
+ index = spryscale >> LIGHTSCALESHIFT;
+ if (index >= MAXLIGHTSCALE)
+ index = MAXLIGHTSCALE - 1;
+ dc_colormap = walllights[index];
+ }
+
+ sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale);
+ dc_iscale = 0xffffffffu / (unsigned) spryscale;
+
+ //
+ // draw the texture
+ //
+ col = (column_t *) ((byte *)
+ R_GetColumn(texnum,
+ maskedtexturecol[dc_x]) - 3);
+
+ R_DrawMaskedColumn(col, -1);
+ maskedtexturecol[dc_x] = SHRT_MAX;
+ }
+ spryscale += rw_scalestep;
+ }
+
+}
+
+/*
+================
+=
+= R_RenderSegLoop
+=
+= Draws zero, one, or two textures (and possibly a masked texture) for walls
+= Can draw or mark the starting pixel of floor and ceiling textures
+=
+= CALLED: CORE LOOPING ROUTINE
+================
+*/
+
+#define HEIGHTBITS 12
+#define HEIGHTUNIT (1<<HEIGHTBITS)
+
+void R_RenderSegLoop(void)
+{
+ angle_t angle;
+ unsigned index;
+ int yl, yh, mid;
+ fixed_t texturecolumn;
+ int top, bottom;
+
+ texturecolumn = 0; // shut up compiler warning
+
+ for (; rw_x < rw_stopx; rw_x++)
+ {
+//
+// mark floor / ceiling areas
+//
+ yl = (topfrac + HEIGHTUNIT - 1) >> HEIGHTBITS;
+ if (yl < ceilingclip[rw_x] + 1)
+ yl = ceilingclip[rw_x] + 1; // no space above wall
+ if (markceiling)
+ {
+ top = ceilingclip[rw_x] + 1;
+ bottom = yl - 1;
+ if (bottom >= floorclip[rw_x])
+ bottom = floorclip[rw_x] - 1;
+ if (top <= bottom)
+ {
+ ceilingplane->top[rw_x] = top;
+ ceilingplane->bottom[rw_x] = bottom;
+ }
+ }
+
+ yh = bottomfrac >> HEIGHTBITS;
+ if (yh >= floorclip[rw_x])
+ yh = floorclip[rw_x] - 1;
+ if (markfloor)
+ {
+ top = yh + 1;
+ bottom = floorclip[rw_x] - 1;
+ if (top <= ceilingclip[rw_x])
+ top = ceilingclip[rw_x] + 1;
+ if (top <= bottom)
+ {
+ floorplane->top[rw_x] = top;
+ floorplane->bottom[rw_x] = bottom;
+ }
+ }
+
+//
+// texturecolumn and lighting are independent of wall tiers
+//
+ if (segtextured)
+ {
+ // calculate texture offset
+ angle = (rw_centerangle + xtoviewangle[rw_x]) >> ANGLETOFINESHIFT;
+ texturecolumn =
+ rw_offset - FixedMul(finetangent[angle], rw_distance);
+ texturecolumn >>= FRACBITS;
+ // calculate lighting
+ index = rw_scale >> LIGHTSCALESHIFT;
+ if (index >= MAXLIGHTSCALE)
+ index = MAXLIGHTSCALE - 1;
+ dc_colormap = walllights[index];
+ dc_x = rw_x;
+ dc_iscale = 0xffffffffu / (unsigned) rw_scale;
+ }
+
+//
+// draw the wall tiers
+//
+ if (midtexture)
+ { // single sided line
+ dc_yl = yl;
+ dc_yh = yh;
+ dc_texturemid = rw_midtexturemid;
+ dc_source = R_GetColumn(midtexture, texturecolumn);
+ colfunc();
+ ceilingclip[rw_x] = viewheight;
+ floorclip[rw_x] = -1;
+ }
+ else
+ { // two sided line
+ if (toptexture)
+ { // top wall
+ mid = pixhigh >> HEIGHTBITS;
+ pixhigh += pixhighstep;
+ if (mid >= floorclip[rw_x])
+ mid = floorclip[rw_x] - 1;
+ if (mid >= yl)
+ {
+ dc_yl = yl;
+ dc_yh = mid;
+ dc_texturemid = rw_toptexturemid;
+ dc_source = R_GetColumn(toptexture, texturecolumn);
+ colfunc();
+ ceilingclip[rw_x] = mid;
+ }
+ else
+ ceilingclip[rw_x] = yl - 1;
+ }
+ else
+ { // no top wall
+ if (markceiling)
+ ceilingclip[rw_x] = yl - 1;
+ }
+
+ if (bottomtexture)
+ { // bottom wall
+ mid = (pixlow + HEIGHTUNIT - 1) >> HEIGHTBITS;
+ pixlow += pixlowstep;
+ if (mid <= ceilingclip[rw_x])
+ mid = ceilingclip[rw_x] + 1; // no space above wall
+ if (mid <= yh)
+ {
+ dc_yl = mid;
+ dc_yh = yh;
+ dc_texturemid = rw_bottomtexturemid;
+ dc_source = R_GetColumn(bottomtexture, texturecolumn);
+ colfunc();
+ floorclip[rw_x] = mid;
+ }
+ else
+ floorclip[rw_x] = yh + 1;
+ }
+ else
+ { // no bottom wall
+ if (markfloor)
+ floorclip[rw_x] = yh + 1;
+ }
+
+ if (maskedtexture)
+ { // save texturecol for backdrawing of masked mid texture
+ maskedtexturecol[rw_x] = texturecolumn;
+ }
+ }
+
+ rw_scale += rw_scalestep;
+ topfrac += topstep;
+ bottomfrac += bottomstep;
+ }
+
+}
+
+
+
+/*
+=====================
+=
+= R_StoreWallRange
+=
+= A wall segment will be drawn between start and stop pixels (inclusive)
+=
+======================
+*/
+
+void R_StoreWallRange(int start, int stop)
+{
+ fixed_t hyp;
+ fixed_t sineval;
+ angle_t distangle, offsetangle;
+ fixed_t vtop;
+ int lightnum;
+
+ if (ds_p == &drawsegs[MAXDRAWSEGS])
+ return; // don't overflow and crash
+
+#ifdef RANGECHECK
+ if (start >= viewwidth || start > stop)
+ I_Error("Bad R_RenderWallRange: %i to %i", start, stop);
+#endif
+
+ sidedef = curline->sidedef;
+ linedef = curline->linedef;
+
+// mark the segment as visible for auto map
+ linedef->flags |= ML_MAPPED;
+
+//
+// calculate rw_distance for scale calculation
+//
+ rw_normalangle = curline->angle + ANG90;
+ offsetangle = abs(rw_normalangle - rw_angle1);
+ if (offsetangle > ANG90)
+ offsetangle = ANG90;
+ distangle = ANG90 - offsetangle;
+ hyp = R_PointToDist(curline->v1->x, curline->v1->y);
+ sineval = finesine[distangle >> ANGLETOFINESHIFT];
+ rw_distance = FixedMul(hyp, sineval);
+
+
+ ds_p->x1 = rw_x = start;
+ ds_p->x2 = stop;
+ ds_p->curline = curline;
+ rw_stopx = stop + 1;
+
+//
+// calculate scale at both ends and step
+//
+ ds_p->scale1 = rw_scale =
+ R_ScaleFromGlobalAngle(viewangle + xtoviewangle[start]);
+ if (stop > start)
+ {
+ ds_p->scale2 = R_ScaleFromGlobalAngle(viewangle + xtoviewangle[stop]);
+ ds_p->scalestep = rw_scalestep =
+ (ds_p->scale2 - rw_scale) / (stop - start);
+ }
+ else
+ {
+ //
+ // try to fix the stretched line bug
+ //
+#if 0
+ if (rw_distance < FRACUNIT / 2)
+ {
+ fixed_t trx, try;
+ fixed_t gxt, gyt;
+
+ trx = curline->v1->x - viewx;
+ try = curline->v1->y - viewy;
+
+ gxt = FixedMul(trx, viewcos);
+ gyt = -FixedMul(try, viewsin);
+ ds_p->scale1 = FixedDiv(projection, gxt - gyt);
+ }
+#endif
+ ds_p->scale2 = ds_p->scale1;
+ }
+
+
+//
+// calculate texture boundaries and decide if floor / ceiling marks
+// are needed
+//
+ worldtop = frontsector->ceilingheight - viewz;
+ worldbottom = frontsector->floorheight - viewz;
+
+ midtexture = toptexture = bottomtexture = maskedtexture = 0;
+ ds_p->maskedtexturecol = NULL;
+
+ if (!backsector)
+ {
+//
+// single sided line
+//
+ midtexture = texturetranslation[sidedef->midtexture];
+ // a single sided line is terminal, so it must mark ends
+ markfloor = markceiling = true;
+ if (linedef->flags & ML_DONTPEGBOTTOM)
+ {
+ vtop = frontsector->floorheight +
+ textureheight[sidedef->midtexture];
+ rw_midtexturemid = vtop - viewz; // bottom of texture at bottom
+ }
+ else
+ rw_midtexturemid = worldtop; // top of texture at top
+ rw_midtexturemid += sidedef->rowoffset;
+ ds_p->silhouette = SIL_BOTH;
+ ds_p->sprtopclip = screenheightarray;
+ ds_p->sprbottomclip = negonearray;
+ ds_p->bsilheight = INT_MAX;
+ ds_p->tsilheight = INT_MIN;
+ }
+ else
+ {
+//
+// two sided line
+//
+ ds_p->sprtopclip = ds_p->sprbottomclip = NULL;
+ ds_p->silhouette = 0;
+ if (frontsector->floorheight > backsector->floorheight)
+ {
+ ds_p->silhouette = SIL_BOTTOM;
+ ds_p->bsilheight = frontsector->floorheight;
+ }
+ else if (backsector->floorheight > viewz)
+ {
+ ds_p->silhouette = SIL_BOTTOM;
+ ds_p->bsilheight = INT_MAX;
+// ds_p->sprbottomclip = negonearray;
+ }
+ if (frontsector->ceilingheight < backsector->ceilingheight)
+ {
+ ds_p->silhouette |= SIL_TOP;
+ ds_p->tsilheight = frontsector->ceilingheight;
+ }
+ else if (backsector->ceilingheight < viewz)
+ {
+ ds_p->silhouette |= SIL_TOP;
+ ds_p->tsilheight = INT_MIN;
+// ds_p->sprtopclip = screenheightarray;
+ }
+
+ if (backsector->ceilingheight <= frontsector->floorheight)
+ {
+ ds_p->sprbottomclip = negonearray;
+ ds_p->bsilheight = INT_MAX;
+ ds_p->silhouette |= SIL_BOTTOM;
+ }
+ if (backsector->floorheight >= frontsector->ceilingheight)
+ {
+ ds_p->sprtopclip = screenheightarray;
+ ds_p->tsilheight = INT_MIN;
+ ds_p->silhouette |= SIL_TOP;
+ }
+ worldhigh = backsector->ceilingheight - viewz;
+ worldlow = backsector->floorheight - viewz;
+
+ // hack to allow height changes in outdoor areas
+ if (frontsector->ceilingpic == skyflatnum
+ && backsector->ceilingpic == skyflatnum)
+ worldtop = worldhigh;
+
+ if (worldlow != worldbottom
+ || backsector->floorpic != frontsector->floorpic
+ || backsector->lightlevel != frontsector->lightlevel)
+ markfloor = true;
+ else
+ markfloor = false; // same plane on both sides
+
+ if (worldhigh != worldtop
+ || backsector->ceilingpic != frontsector->ceilingpic
+ || backsector->lightlevel != frontsector->lightlevel)
+ markceiling = true;
+ else
+ markceiling = false; // same plane on both sides
+
+ if (backsector->ceilingheight <= frontsector->floorheight
+ || backsector->floorheight >= frontsector->ceilingheight)
+ markceiling = markfloor = true; // closed door
+
+ if (worldhigh < worldtop)
+ { // top texture
+ toptexture = texturetranslation[sidedef->toptexture];
+ if (linedef->flags & ML_DONTPEGTOP)
+ rw_toptexturemid = worldtop; // top of texture at top
+ else
+ {
+ vtop = backsector->ceilingheight +
+ textureheight[sidedef->toptexture];
+ rw_toptexturemid = vtop - viewz; // bottom of texture
+ }
+ }
+ if (worldlow > worldbottom)
+ { // bottom texture
+ bottomtexture = texturetranslation[sidedef->bottomtexture];
+ if (linedef->flags & ML_DONTPEGBOTTOM)
+ { // bottom of texture at bottom
+ rw_bottomtexturemid = worldtop; // top of texture at top
+ }
+ else // top of texture at top
+ rw_bottomtexturemid = worldlow;
+ }
+ rw_toptexturemid += sidedef->rowoffset;
+ rw_bottomtexturemid += sidedef->rowoffset;
+
+ //
+ // allocate space for masked texture tables
+ //
+ if (sidedef->midtexture)
+ { // masked midtexture
+ maskedtexture = true;
+ ds_p->maskedtexturecol = maskedtexturecol = lastopening - rw_x;
+ lastopening += rw_stopx - rw_x;
+ }
+ }
+
+//
+// calculate rw_offset (only needed for textured lines)
+//
+ segtextured = midtexture | toptexture | bottomtexture | maskedtexture;
+
+ if (segtextured)
+ {
+ offsetangle = rw_normalangle - rw_angle1;
+ if (offsetangle > ANG180)
+ offsetangle = -offsetangle;
+ if (offsetangle > ANG90)
+ offsetangle = ANG90;
+ sineval = finesine[offsetangle >> ANGLETOFINESHIFT];
+ rw_offset = FixedMul(hyp, sineval);
+ if (rw_normalangle - rw_angle1 < ANG180)
+ rw_offset = -rw_offset;
+ rw_offset += sidedef->textureoffset + curline->offset;
+ rw_centerangle = ANG90 + viewangle - rw_normalangle;
+
+ //
+ // calculate light table
+ // use different light tables for horizontal / vertical / diagonal
+ // OPTIMIZE: get rid of LIGHTSEGSHIFT globally
+ if (!fixedcolormap)
+ {
+ lightnum =
+ (frontsector->lightlevel >> LIGHTSEGSHIFT) + extralight;
+ if (curline->v1->y == curline->v2->y)
+ lightnum--;
+ else if (curline->v1->x == curline->v2->x)
+ lightnum++;
+ if (lightnum < 0)
+ walllights = scalelight[0];
+ else if (lightnum >= LIGHTLEVELS)
+ walllights = scalelight[LIGHTLEVELS - 1];
+ else
+ walllights = scalelight[lightnum];
+ }
+ }
+
+
+//
+// if a floor / ceiling plane is on the wrong side of the view plane
+// it is definately invisible and doesn't need to be marked
+//
+ if (frontsector->floorheight >= viewz)
+ markfloor = false; // above view plane
+ if (frontsector->ceilingheight <= viewz
+ && frontsector->ceilingpic != skyflatnum)
+ markceiling = false; // below view plane
+
+//
+// calculate incremental stepping values for texture edges
+//
+ worldtop >>= 4;
+ worldbottom >>= 4;
+
+ topstep = -FixedMul(rw_scalestep, worldtop);
+ topfrac = (centeryfrac >> 4) - FixedMul(worldtop, rw_scale);
+
+ bottomstep = -FixedMul(rw_scalestep, worldbottom);
+ bottomfrac = (centeryfrac >> 4) - FixedMul(worldbottom, rw_scale);
+
+ if (backsector)
+ {
+ worldhigh >>= 4;
+ worldlow >>= 4;
+
+ if (worldhigh < worldtop)
+ {
+ pixhigh = (centeryfrac >> 4) - FixedMul(worldhigh, rw_scale);
+ pixhighstep = -FixedMul(rw_scalestep, worldhigh);
+ }
+ if (worldlow > worldbottom)
+ {
+ pixlow = (centeryfrac >> 4) - FixedMul(worldlow, rw_scale);
+ pixlowstep = -FixedMul(rw_scalestep, worldlow);
+ }
+ }
+
+//
+// render it
+//
+ if (markceiling)
+ ceilingplane = R_CheckPlane(ceilingplane, rw_x, rw_stopx - 1);
+ if (markfloor)
+ floorplane = R_CheckPlane(floorplane, rw_x, rw_stopx - 1);
+
+ R_RenderSegLoop();
+
+//
+// save sprite clipping info
+//
+ if (((ds_p->silhouette & SIL_TOP) || maskedtexture) && !ds_p->sprtopclip)
+ {
+ memcpy(lastopening, ceilingclip + start, 2 * (rw_stopx - start));
+ ds_p->sprtopclip = lastopening - start;
+ lastopening += rw_stopx - start;
+ }
+ if (((ds_p->silhouette & SIL_BOTTOM) || maskedtexture)
+ && !ds_p->sprbottomclip)
+ {
+ memcpy(lastopening, floorclip + start, 2 * (rw_stopx - start));
+ ds_p->sprbottomclip = lastopening - start;
+ lastopening += rw_stopx - start;
+ }
+ if (maskedtexture && !(ds_p->silhouette & SIL_TOP))
+ {
+ ds_p->silhouette |= SIL_TOP;
+ ds_p->tsilheight = INT_MIN;
+ }
+ if (maskedtexture && !(ds_p->silhouette & SIL_BOTTOM))
+ {
+ ds_p->silhouette |= SIL_BOTTOM;
+ ds_p->bsilheight = INT_MAX;
+ }
+ ds_p++;
+}
diff --git a/src/heretic/r_things.c b/src/heretic/r_things.c
new file mode 100644
index 00000000..353ce7ad
--- /dev/null
+++ b/src/heretic/r_things.c
@@ -0,0 +1,1024 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+// R_things.c
+#include <stdio.h>
+#include <stdlib.h>
+#include "doomdef.h"
+#include "deh_str.h"
+#include "i_swap.h"
+#include "i_system.h"
+#include "r_local.h"
+
+typedef struct
+{
+ int x1, x2;
+
+ int column;
+ int topclip;
+ int bottomclip;
+} maskdraw_t;
+
+/*
+
+Sprite rotation 0 is facing the viewer, rotation 1 is one angle turn CLOCKWISE around the axis.
+This is not the same as the angle, which increases counter clockwise
+(protractor). There was a lot of stuff grabbed wrong, so I changed it...
+
+*/
+
+
+fixed_t pspritescale, pspriteiscale;
+
+lighttable_t **spritelights;
+
+// constant arrays used for psprite clipping and initializing clipping
+short negonearray[SCREENWIDTH];
+short screenheightarray[SCREENWIDTH];
+
+/*
+===============================================================================
+
+ INITIALIZATION FUNCTIONS
+
+===============================================================================
+*/
+
+// variables used to look up and range check thing_t sprites patches
+spritedef_t *sprites;
+int numsprites;
+
+spriteframe_t sprtemp[26];
+int maxframe;
+char *spritename;
+
+
+
+/*
+=================
+=
+= R_InstallSpriteLump
+=
+= Local function for R_InitSprites
+=================
+*/
+
+void R_InstallSpriteLump(int lump, unsigned frame, unsigned rotation,
+ boolean flipped)
+{
+ int r;
+
+ if (frame >= 26 || rotation > 8)
+ I_Error("R_InstallSpriteLump: Bad frame characters in lump %i", lump);
+
+ if ((int) frame > maxframe)
+ maxframe = frame;
+
+ if (rotation == 0)
+ {
+// the lump should be used for all rotations
+ if (sprtemp[frame].rotate == false)
+ I_Error("R_InitSprites: Sprite %s frame %c has multip rot=0 lump",
+ spritename, 'A' + frame);
+ if (sprtemp[frame].rotate == true)
+ I_Error
+ ("R_InitSprites: Sprite %s frame %c has rotations and a rot=0 lump",
+ spritename, 'A' + frame);
+
+ sprtemp[frame].rotate = false;
+ for (r = 0; r < 8; r++)
+ {
+ sprtemp[frame].lump[r] = lump - firstspritelump;
+ sprtemp[frame].flip[r] = (byte) flipped;
+ }
+ return;
+ }
+
+// the lump is only used for one rotation
+ if (sprtemp[frame].rotate == false)
+ I_Error
+ ("R_InitSprites: Sprite %s frame %c has rotations and a rot=0 lump",
+ spritename, 'A' + frame);
+
+ sprtemp[frame].rotate = true;
+
+ rotation--; // make 0 based
+ if (sprtemp[frame].lump[rotation] != -1)
+ I_Error
+ ("R_InitSprites: Sprite %s : %c : %c has two lumps mapped to it",
+ spritename, 'A' + frame, '1' + rotation);
+
+ sprtemp[frame].lump[rotation] = lump - firstspritelump;
+ sprtemp[frame].flip[rotation] = (byte) flipped;
+}
+
+/*
+=================
+=
+= R_InitSpriteDefs
+=
+= Pass a null terminated list of sprite names (4 chars exactly) to be used
+= Builds the sprite rotation matrixes to account for horizontally flipped
+= sprites. Will report an error if the lumps are inconsistant
+=Only called at startup
+=
+= Sprite lump names are 4 characters for the actor, a letter for the frame,
+= and a number for the rotation, A sprite that is flippable will have an
+= additional letter/number appended. The rotation character can be 0 to
+= signify no rotations
+=================
+*/
+
+void R_InitSpriteDefs(char **namelist)
+{
+ char **check;
+ int i, l, frame, rotation;
+ int start, end;
+
+// count the number of sprite names
+ check = namelist;
+ while (*check != NULL)
+ check++;
+ numsprites = check - namelist;
+
+ if (!numsprites)
+ return;
+
+ sprites = Z_Malloc(numsprites * sizeof(*sprites), PU_STATIC, NULL);
+
+ start = firstspritelump - 1;
+ end = lastspritelump + 1;
+
+// scan all the lump names for each of the names, noting the highest
+// frame letter
+// Just compare 4 characters as ints
+ for (i = 0; i < numsprites; i++)
+ {
+ spritename = DEH_String(namelist[i]);
+ memset(sprtemp, -1, sizeof(sprtemp));
+
+ maxframe = -1;
+
+ //
+ // scan the lumps, filling in the frames for whatever is found
+ //
+ for (l = start + 1; l < end; l++)
+ if (!strncasecmp(lumpinfo[l].name, spritename, 4))
+ {
+ frame = lumpinfo[l].name[4] - 'A';
+ rotation = lumpinfo[l].name[5] - '0';
+ R_InstallSpriteLump(l, frame, rotation, false);
+ if (lumpinfo[l].name[6])
+ {
+ frame = lumpinfo[l].name[6] - 'A';
+ rotation = lumpinfo[l].name[7] - '0';
+ R_InstallSpriteLump(l, frame, rotation, true);
+ }
+ }
+
+ //
+ // check the frames that were found for completeness
+ //
+ if (maxframe == -1)
+ {
+ //continue;
+ sprites[i].numframes = 0;
+ if (gamemode == shareware)
+ continue;
+ I_Error("R_InitSprites: No lumps found for sprite %s",
+ spritename);
+ }
+
+ maxframe++;
+ for (frame = 0; frame < maxframe; frame++)
+ {
+ switch ((int) sprtemp[frame].rotate)
+ {
+ case -1: // no rotations were found for that frame at all
+ I_Error("R_InitSprites: No patches found for %s frame %c",
+ spritename, frame + 'A');
+ case 0: // only the first rotation is needed
+ break;
+
+ case 1: // must have all 8 frames
+ for (rotation = 0; rotation < 8; rotation++)
+ if (sprtemp[frame].lump[rotation] == -1)
+ I_Error
+ ("R_InitSprites: Sprite %s frame %c is missing rotations",
+ spritename, frame + 'A');
+ }
+ }
+
+ //
+ // allocate space for the frames present and copy sprtemp to it
+ //
+ sprites[i].numframes = maxframe;
+ sprites[i].spriteframes =
+ Z_Malloc(maxframe * sizeof(spriteframe_t), PU_STATIC, NULL);
+ memcpy(sprites[i].spriteframes, sprtemp,
+ maxframe * sizeof(spriteframe_t));
+ }
+
+}
+
+
+/*
+===============================================================================
+
+ GAME FUNCTIONS
+
+===============================================================================
+*/
+
+vissprite_t vissprites[MAXVISSPRITES], *vissprite_p;
+int newvissprite;
+
+
+/*
+===================
+=
+= R_InitSprites
+=
+= Called at program start
+===================
+*/
+
+void R_InitSprites(char **namelist)
+{
+ int i;
+
+ for (i = 0; i < SCREENWIDTH; i++)
+ {
+ negonearray[i] = -1;
+ }
+
+ R_InitSpriteDefs(namelist);
+}
+
+
+/*
+===================
+=
+= R_ClearSprites
+=
+= Called at frame start
+===================
+*/
+
+void R_ClearSprites(void)
+{
+ vissprite_p = vissprites;
+}
+
+
+/*
+===================
+=
+= R_NewVisSprite
+=
+===================
+*/
+
+vissprite_t overflowsprite;
+
+vissprite_t *R_NewVisSprite(void)
+{
+ if (vissprite_p == &vissprites[MAXVISSPRITES])
+ return &overflowsprite;
+ vissprite_p++;
+ return vissprite_p - 1;
+}
+
+
+/*
+================
+=
+= R_DrawMaskedColumn
+=
+= Used for sprites and masked mid textures
+================
+*/
+
+short *mfloorclip;
+short *mceilingclip;
+fixed_t spryscale;
+fixed_t sprtopscreen;
+fixed_t sprbotscreen;
+
+void R_DrawMaskedColumn(column_t * column, signed int baseclip)
+{
+ int topscreen, bottomscreen;
+ fixed_t basetexturemid;
+
+ basetexturemid = dc_texturemid;
+
+ for (; column->topdelta != 0xff;)
+ {
+// calculate unclipped screen coordinates for post
+ topscreen = sprtopscreen + spryscale * column->topdelta;
+ bottomscreen = topscreen + spryscale * column->length;
+ dc_yl = (topscreen + FRACUNIT - 1) >> FRACBITS;
+ dc_yh = (bottomscreen - 1) >> FRACBITS;
+
+ if (dc_yh >= mfloorclip[dc_x])
+ dc_yh = mfloorclip[dc_x] - 1;
+ if (dc_yl <= mceilingclip[dc_x])
+ dc_yl = mceilingclip[dc_x] + 1;
+
+ if (dc_yh >= baseclip && baseclip != -1)
+ dc_yh = baseclip;
+
+ if (dc_yl <= dc_yh)
+ {
+ dc_source = (byte *) column + 3;
+ dc_texturemid = basetexturemid - (column->topdelta << FRACBITS);
+// dc_source = (byte *)column + 3 - column->topdelta;
+ colfunc(); // either R_DrawColumn or R_DrawTLColumn
+ }
+ column = (column_t *) ((byte *) column + column->length + 4);
+ }
+
+ dc_texturemid = basetexturemid;
+}
+
+
+/*
+================
+=
+= R_DrawVisSprite
+=
+= mfloorclip and mceilingclip should also be set
+================
+*/
+
+void R_DrawVisSprite(vissprite_t * vis, int x1, int x2)
+{
+ column_t *column;
+ int texturecolumn;
+ fixed_t frac;
+ patch_t *patch;
+ fixed_t baseclip;
+
+
+ patch = W_CacheLumpNum(vis->patch + firstspritelump, PU_CACHE);
+
+ dc_colormap = vis->colormap;
+
+// if(!dc_colormap)
+// colfunc = tlcolfunc; // NULL colormap = shadow draw
+
+ if (vis->mobjflags & MF_SHADOW)
+ {
+ if (vis->mobjflags & MF_TRANSLATION)
+ {
+ colfunc = R_DrawTranslatedTLColumn;
+ dc_translation = translationtables - 256 +
+ ((vis->mobjflags & MF_TRANSLATION) >> (MF_TRANSSHIFT - 8));
+ }
+ else
+ { // Draw using shadow column function
+ colfunc = tlcolfunc;
+ }
+ }
+ else if (vis->mobjflags & MF_TRANSLATION)
+ {
+ // Draw using translated column function
+ colfunc = R_DrawTranslatedColumn;
+ dc_translation = translationtables - 256 +
+ ((vis->mobjflags & MF_TRANSLATION) >> (MF_TRANSSHIFT - 8));
+ }
+
+ dc_iscale = abs(vis->xiscale) >> detailshift;
+ dc_texturemid = vis->texturemid;
+ frac = vis->startfrac;
+ spryscale = vis->scale;
+
+ sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale);
+
+// check to see if weapon is a vissprite
+ if (vis->psprite)
+ {
+ dc_texturemid += FixedMul(((centery - viewheight / 2) << FRACBITS),
+ vis->xiscale);
+ sprtopscreen += (viewheight / 2 - centery) << FRACBITS;
+ }
+
+ if (vis->footclip && !vis->psprite)
+ {
+ sprbotscreen = sprtopscreen + FixedMul(patch->height << FRACBITS,
+ spryscale);
+ baseclip = (sprbotscreen - FixedMul(vis->footclip << FRACBITS,
+ spryscale)) >> FRACBITS;
+ }
+ else
+ {
+ baseclip = -1;
+ }
+
+ for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, frac += vis->xiscale)
+ {
+ texturecolumn = frac >> FRACBITS;
+#ifdef RANGECHECK
+ if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width))
+ I_Error("R_DrawSpriteRange: bad texturecolumn");
+#endif
+ column = (column_t *) ((byte *) patch +
+ LONG(patch->columnofs[texturecolumn]));
+ R_DrawMaskedColumn(column, baseclip);
+ }
+
+ colfunc = basecolfunc;
+}
+
+
+
+/*
+===================
+=
+= R_ProjectSprite
+=
+= Generates a vissprite for a thing if it might be visible
+=
+===================
+*/
+
+void R_ProjectSprite(mobj_t * thing)
+{
+ fixed_t trx, try;
+ fixed_t gxt, gyt;
+ fixed_t tx, tz;
+ fixed_t xscale;
+ int x1, x2;
+ spritedef_t *sprdef;
+ spriteframe_t *sprframe;
+ int lump;
+ unsigned rot;
+ boolean flip;
+ int index;
+ vissprite_t *vis;
+ angle_t ang;
+ fixed_t iscale;
+
+ if (thing->flags2 & MF2_DONTDRAW)
+ { // Never make a vissprite when MF2_DONTDRAW is flagged.
+ return;
+ }
+
+//
+// transform the origin point
+//
+ trx = thing->x - viewx;
+ try = thing->y - viewy;
+
+ gxt = FixedMul(trx, viewcos);
+ gyt = -FixedMul(try, viewsin);
+ tz = gxt - gyt;
+
+ if (tz < MINZ)
+ return; // thing is behind view plane
+ xscale = FixedDiv(projection, tz);
+
+ gxt = -FixedMul(trx, viewsin);
+ gyt = FixedMul(try, viewcos);
+ tx = -(gyt + gxt);
+
+ if (abs(tx) > (tz << 2))
+ return; // too far off the side
+
+//
+// decide which patch to use for sprite reletive to player
+//
+#ifdef RANGECHECK
+ if ((unsigned) thing->sprite >= numsprites)
+ I_Error("R_ProjectSprite: invalid sprite number %i ", thing->sprite);
+#endif
+ sprdef = &sprites[thing->sprite];
+#ifdef RANGECHECK
+ if ((thing->frame & FF_FRAMEMASK) >= sprdef->numframes)
+ I_Error("R_ProjectSprite: invalid sprite frame %i : %i ",
+ thing->sprite, thing->frame);
+#endif
+ sprframe = &sprdef->spriteframes[thing->frame & FF_FRAMEMASK];
+
+ if (sprframe->rotate)
+ { // choose a different rotation based on player view
+ ang = R_PointToAngle(thing->x, thing->y);
+ rot = (ang - thing->angle + (unsigned) (ANG45 / 2) * 9) >> 29;
+ lump = sprframe->lump[rot];
+ flip = (boolean) sprframe->flip[rot];
+ }
+ else
+ { // use single rotation for all views
+ lump = sprframe->lump[0];
+ flip = (boolean) sprframe->flip[0];
+ }
+
+//
+// calculate edges of the shape
+//
+ tx -= spriteoffset[lump];
+ x1 = (centerxfrac + FixedMul(tx, xscale)) >> FRACBITS;
+ if (x1 > viewwidth)
+ return; // off the right side
+ tx += spritewidth[lump];
+ x2 = ((centerxfrac + FixedMul(tx, xscale)) >> FRACBITS) - 1;
+ if (x2 < 0)
+ return; // off the left side
+
+
+//
+// store information in a vissprite
+//
+ vis = R_NewVisSprite();
+ vis->mobjflags = thing->flags;
+ vis->psprite = false;
+ vis->scale = xscale << detailshift;
+ vis->gx = thing->x;
+ vis->gy = thing->y;
+ vis->gz = thing->z;
+ vis->gzt = thing->z + spritetopoffset[lump];
+
+ // foot clipping
+ if (thing->flags2 & MF2_FEETARECLIPPED
+ && thing->z <= thing->subsector->sector->floorheight)
+ {
+ vis->footclip = 10;
+ }
+ else
+ vis->footclip = 0;
+ vis->texturemid = vis->gzt - viewz - (vis->footclip << FRACBITS);
+
+ vis->x1 = x1 < 0 ? 0 : x1;
+ vis->x2 = x2 >= viewwidth ? viewwidth - 1 : x2;
+ iscale = FixedDiv(FRACUNIT, xscale);
+ if (flip)
+ {
+ vis->startfrac = spritewidth[lump] - 1;
+ vis->xiscale = -iscale;
+ }
+ else
+ {
+ vis->startfrac = 0;
+ vis->xiscale = iscale;
+ }
+ if (vis->x1 > x1)
+ vis->startfrac += vis->xiscale * (vis->x1 - x1);
+ vis->patch = lump;
+//
+// get light level
+//
+
+// if (thing->flags & MF_SHADOW)
+// vis->colormap = NULL; // shadow draw
+// else ...
+
+ if (fixedcolormap)
+ vis->colormap = fixedcolormap; // fixed map
+ else if (thing->frame & FF_FULLBRIGHT)
+ vis->colormap = colormaps; // full bright
+ else
+ { // diminished light
+ index = xscale >> (LIGHTSCALESHIFT - detailshift);
+ if (index >= MAXLIGHTSCALE)
+ index = MAXLIGHTSCALE - 1;
+ vis->colormap = spritelights[index];
+ }
+}
+
+
+
+
+/*
+========================
+=
+= R_AddSprites
+=
+========================
+*/
+
+void R_AddSprites(sector_t * sec)
+{
+ mobj_t *thing;
+ int lightnum;
+
+ if (sec->validcount == validcount)
+ return; // already added
+
+ sec->validcount = validcount;
+
+ lightnum = (sec->lightlevel >> LIGHTSEGSHIFT) + extralight;
+ if (lightnum < 0)
+ spritelights = scalelight[0];
+ else if (lightnum >= LIGHTLEVELS)
+ spritelights = scalelight[LIGHTLEVELS - 1];
+ else
+ spritelights = scalelight[lightnum];
+
+
+ for (thing = sec->thinglist; thing; thing = thing->snext)
+ R_ProjectSprite(thing);
+}
+
+
+/*
+========================
+=
+= R_DrawPSprite
+=
+========================
+*/
+
+int PSpriteSY[NUMWEAPONS] = {
+ 0, // staff
+ 5 * FRACUNIT, // goldwand
+ 15 * FRACUNIT, // crossbow
+ 15 * FRACUNIT, // blaster
+ 15 * FRACUNIT, // skullrod
+ 15 * FRACUNIT, // phoenix rod
+ 15 * FRACUNIT, // mace
+ 15 * FRACUNIT, // gauntlets
+ 15 * FRACUNIT // beak
+};
+
+void R_DrawPSprite(pspdef_t * psp)
+{
+ fixed_t tx;
+ int x1, x2;
+ spritedef_t *sprdef;
+ spriteframe_t *sprframe;
+ int lump;
+ boolean flip;
+ vissprite_t *vis, avis;
+
+ int tempangle;
+
+//
+// decide which patch to use
+//
+#ifdef RANGECHECK
+ if ((unsigned) psp->state->sprite >= numsprites)
+ I_Error("R_ProjectSprite: invalid sprite number %i ",
+ psp->state->sprite);
+#endif
+ sprdef = &sprites[psp->state->sprite];
+#ifdef RANGECHECK
+ if ((psp->state->frame & FF_FRAMEMASK) >= sprdef->numframes)
+ I_Error("R_ProjectSprite: invalid sprite frame %i : %i ",
+ psp->state->sprite, psp->state->frame);
+#endif
+ sprframe = &sprdef->spriteframes[psp->state->frame & FF_FRAMEMASK];
+
+ lump = sprframe->lump[0];
+ flip = (boolean) sprframe->flip[0];
+
+//
+// calculate edges of the shape
+//
+ tx = psp->sx - 160 * FRACUNIT;
+
+ tx -= spriteoffset[lump];
+ if (viewangleoffset)
+ {
+ tempangle =
+ ((centerxfrac / 1024) * (viewangleoffset >> ANGLETOFINESHIFT));
+ }
+ else
+ {
+ tempangle = 0;
+ }
+ x1 = (centerxfrac + FixedMul(tx, pspritescale) + tempangle) >> FRACBITS;
+ if (x1 > viewwidth)
+ return; // off the right side
+ tx += spritewidth[lump];
+ x2 = ((centerxfrac + FixedMul(tx, pspritescale) +
+ tempangle) >> FRACBITS) - 1;
+ if (x2 < 0)
+ return; // off the left side
+
+//
+// store information in a vissprite
+//
+ vis = &avis;
+ vis->mobjflags = 0;
+ vis->psprite = true;
+ vis->texturemid =
+ (BASEYCENTER << FRACBITS) + FRACUNIT / 2 - (psp->sy -
+ spritetopoffset[lump]);
+ if (viewheight == SCREENHEIGHT)
+ {
+ vis->texturemid -= PSpriteSY[players[consoleplayer].readyweapon];
+ }
+ vis->x1 = x1 < 0 ? 0 : x1;
+ vis->x2 = x2 >= viewwidth ? viewwidth - 1 : x2;
+ vis->scale = pspritescale << detailshift;
+ if (flip)
+ {
+ vis->xiscale = -pspriteiscale;
+ vis->startfrac = spritewidth[lump] - 1;
+ }
+ else
+ {
+ vis->xiscale = pspriteiscale;
+ vis->startfrac = 0;
+ }
+ if (vis->x1 > x1)
+ vis->startfrac += vis->xiscale * (vis->x1 - x1);
+ vis->patch = lump;
+
+ if (viewplayer->powers[pw_invisibility] > 4 * 32 ||
+ viewplayer->powers[pw_invisibility] & 8)
+ {
+ // Invisibility
+ vis->colormap = spritelights[MAXLIGHTSCALE - 1];
+ vis->mobjflags |= MF_SHADOW;
+ }
+ else if (fixedcolormap)
+ {
+ // Fixed color
+ vis->colormap = fixedcolormap;
+ }
+ else if (psp->state->frame & FF_FULLBRIGHT)
+ {
+ // Full bright
+ vis->colormap = colormaps;
+ }
+ else
+ {
+ // local light
+ vis->colormap = spritelights[MAXLIGHTSCALE - 1];
+ }
+ R_DrawVisSprite(vis, vis->x1, vis->x2);
+}
+
+/*
+========================
+=
+= R_DrawPlayerSprites
+=
+========================
+*/
+
+void R_DrawPlayerSprites(void)
+{
+ int i, lightnum;
+ pspdef_t *psp;
+
+//
+// get light level
+//
+ lightnum =
+ (viewplayer->mo->subsector->sector->lightlevel >> LIGHTSEGSHIFT) +
+ extralight;
+ if (lightnum < 0)
+ spritelights = scalelight[0];
+ else if (lightnum >= LIGHTLEVELS)
+ spritelights = scalelight[LIGHTLEVELS - 1];
+ else
+ spritelights = scalelight[lightnum];
+//
+// clip to screen bounds
+//
+ mfloorclip = screenheightarray;
+ mceilingclip = negonearray;
+
+//
+// add all active psprites
+//
+ for (i = 0, psp = viewplayer->psprites; i < NUMPSPRITES; i++, psp++)
+ if (psp->state)
+ R_DrawPSprite(psp);
+
+}
+
+
+/*
+========================
+=
+= R_SortVisSprites
+=
+========================
+*/
+
+vissprite_t vsprsortedhead;
+
+void R_SortVisSprites(void)
+{
+ int i, count;
+ vissprite_t *ds, *best;
+ vissprite_t unsorted;
+ fixed_t bestscale;
+
+ count = vissprite_p - vissprites;
+
+ unsorted.next = unsorted.prev = &unsorted;
+ if (!count)
+ return;
+
+ for (ds = vissprites; ds < vissprite_p; ds++)
+ {
+ ds->next = ds + 1;
+ ds->prev = ds - 1;
+ }
+ vissprites[0].prev = &unsorted;
+ unsorted.next = &vissprites[0];
+ (vissprite_p - 1)->next = &unsorted;
+ unsorted.prev = vissprite_p - 1;
+
+//
+// pull the vissprites out by scale
+//
+ best = 0; // shut up the compiler warning
+ vsprsortedhead.next = vsprsortedhead.prev = &vsprsortedhead;
+ for (i = 0; i < count; i++)
+ {
+ bestscale = INT_MAX;
+ for (ds = unsorted.next; ds != &unsorted; ds = ds->next)
+ {
+ if (ds->scale < bestscale)
+ {
+ bestscale = ds->scale;
+ best = ds;
+ }
+ }
+ best->next->prev = best->prev;
+ best->prev->next = best->next;
+ best->next = &vsprsortedhead;
+ best->prev = vsprsortedhead.prev;
+ vsprsortedhead.prev->next = best;
+ vsprsortedhead.prev = best;
+ }
+}
+
+
+
+/*
+========================
+=
+= R_DrawSprite
+=
+========================
+*/
+
+void R_DrawSprite(vissprite_t * spr)
+{
+ drawseg_t *ds;
+ short clipbot[SCREENWIDTH], cliptop[SCREENWIDTH];
+ int x, r1, r2;
+ fixed_t scale, lowscale;
+ int silhouette;
+
+ for (x = spr->x1; x <= spr->x2; x++)
+ clipbot[x] = cliptop[x] = -2;
+
+//
+// scan drawsegs from end to start for obscuring segs
+// the first drawseg that has a greater scale is the clip seg
+//
+ for (ds = ds_p - 1; ds >= drawsegs; ds--)
+ {
+ //
+ // determine if the drawseg obscures the sprite
+ //
+ if (ds->x1 > spr->x2 || ds->x2 < spr->x1 ||
+ (!ds->silhouette && !ds->maskedtexturecol))
+ continue; // doesn't cover sprite
+
+ r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1;
+ r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2;
+ if (ds->scale1 > ds->scale2)
+ {
+ lowscale = ds->scale2;
+ scale = ds->scale1;
+ }
+ else
+ {
+ lowscale = ds->scale1;
+ scale = ds->scale2;
+ }
+
+ if (scale < spr->scale || (lowscale < spr->scale
+ && !R_PointOnSegSide(spr->gx, spr->gy,
+ ds->curline)))
+ {
+ if (ds->maskedtexturecol) // masked mid texture
+ R_RenderMaskedSegRange(ds, r1, r2);
+ continue; // seg is behind sprite
+ }
+
+//
+// clip this piece of the sprite
+//
+ silhouette = ds->silhouette;
+ if (spr->gz >= ds->bsilheight)
+ silhouette &= ~SIL_BOTTOM;
+ if (spr->gzt <= ds->tsilheight)
+ silhouette &= ~SIL_TOP;
+
+ if (silhouette == 1)
+ { // bottom sil
+ for (x = r1; x <= r2; x++)
+ if (clipbot[x] == -2)
+ clipbot[x] = ds->sprbottomclip[x];
+ }
+ else if (silhouette == 2)
+ { // top sil
+ for (x = r1; x <= r2; x++)
+ if (cliptop[x] == -2)
+ cliptop[x] = ds->sprtopclip[x];
+ }
+ else if (silhouette == 3)
+ { // both
+ for (x = r1; x <= r2; x++)
+ {
+ if (clipbot[x] == -2)
+ clipbot[x] = ds->sprbottomclip[x];
+ if (cliptop[x] == -2)
+ cliptop[x] = ds->sprtopclip[x];
+ }
+ }
+
+ }
+
+//
+// all clipping has been performed, so draw the sprite
+//
+
+// check for unclipped columns
+ for (x = spr->x1; x <= spr->x2; x++)
+ {
+ if (clipbot[x] == -2)
+ clipbot[x] = viewheight;
+ if (cliptop[x] == -2)
+ cliptop[x] = -1;
+ }
+
+ mfloorclip = clipbot;
+ mceilingclip = cliptop;
+ R_DrawVisSprite(spr, spr->x1, spr->x2);
+}
+
+
+/*
+========================
+=
+= R_DrawMasked
+=
+========================
+*/
+
+void R_DrawMasked(void)
+{
+ vissprite_t *spr;
+ drawseg_t *ds;
+
+ R_SortVisSprites();
+
+ if (vissprite_p > vissprites)
+ {
+ // draw all vissprites back to front
+
+ for (spr = vsprsortedhead.next; spr != &vsprsortedhead;
+ spr = spr->next)
+ R_DrawSprite(spr);
+ }
+
+//
+// render any remaining masked mid textures
+//
+ for (ds = ds_p - 1; ds >= drawsegs; ds--)
+ if (ds->maskedtexturecol)
+ R_RenderMaskedSegRange(ds, ds->x1, ds->x2);
+
+//
+// draw the psprites on top of everything
+//
+// Added for the sideviewing with an external device
+ if (viewangleoffset <= 1024 << ANGLETOFINESHIFT || viewangleoffset >=
+ -1024 << ANGLETOFINESHIFT)
+ { // don't draw on side views
+ R_DrawPlayerSprites();
+ }
+
+// if (!viewangleoffset) // don't draw on side views
+// R_DrawPlayerSprites ();
+}
diff --git a/src/heretic/s_sound.c b/src/heretic/s_sound.c
new file mode 100644
index 00000000..e94f17a5
--- /dev/null
+++ b/src/heretic/s_sound.c
@@ -0,0 +1,608 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdlib.h>
+
+#include "doomdef.h"
+#include "i_system.h"
+#include "m_random.h"
+#include "sounds.h"
+#include "s_sound.h"
+#include "i_sound.h"
+#include "r_local.h"
+#include "p_local.h"
+
+#include "sounds.h"
+
+#include "w_wad.h"
+#include "z_zone.h"
+
+/*
+===============================================================================
+
+ MUSIC & SFX API
+
+===============================================================================
+*/
+
+void S_ShutDown(void);
+boolean S_StopSoundID(int sound_id, int priority);
+
+static channel_t channel[MAX_CHANNELS];
+
+static void *rs; // Handle for the registered song
+int mus_song = -1;
+int mus_lumpnum;
+void *mus_sndptr;
+byte *soundCurve;
+
+int snd_MaxVolume = 10;
+int snd_MusicVolume = 10;
+int snd_Channels = 16;
+
+int AmbChan;
+
+void S_Start(void)
+{
+ int i;
+
+ S_StartSong((gameepisode - 1) * 9 + gamemap - 1, true);
+
+ //stop all sounds
+ for (i = 0; i < snd_Channels; i++)
+ {
+ if (channel[i].handle)
+ {
+ S_StopSound(channel[i].mo);
+ }
+ }
+ memset(channel, 0, 8 * sizeof(channel_t));
+}
+
+void S_StartSong(int song, boolean loop)
+{
+ int mus_len;
+
+ if (song == mus_song)
+ { // don't replay an old song
+ return;
+ }
+
+ if (rs != NULL)
+ {
+ I_StopSong();
+ I_UnRegisterSong(rs);
+ }
+
+ if (song < mus_e1m1 || song > NUMMUSIC)
+ {
+ return;
+ }
+ mus_lumpnum = W_GetNumForName(S_music[song].name);
+ mus_sndptr = W_CacheLumpNum(mus_lumpnum, PU_MUSIC);
+ mus_len = W_LumpLength(mus_lumpnum);
+ rs = I_RegisterSong(mus_sndptr, mus_len);
+ I_PlaySong(rs, loop); //'true' denotes endless looping.
+ mus_song = song;
+}
+
+static mobj_t *GetSoundListener(void)
+{
+ static degenmobj_t dummy_listener;
+
+ // If we are at the title screen, the console player doesn't have an
+ // object yet, so return a pointer to a static dummy listener instead.
+
+ if (players[consoleplayer].mo != NULL)
+ {
+ return players[consoleplayer].mo;
+ }
+ else
+ {
+ dummy_listener.x = 0;
+ dummy_listener.y = 0;
+ dummy_listener.z = 0;
+
+ return (mobj_t *) &dummy_listener;
+ }
+}
+
+void S_StartSound(void *_origin, int sound_id)
+{
+ mobj_t *origin = _origin;
+ mobj_t *listener;
+ int dist, vol;
+ int i;
+ int priority;
+ int sep;
+ int angle;
+ int absx;
+ int absy;
+
+ static int sndcount = 0;
+ int chan;
+
+ listener = GetSoundListener();
+
+ if (sound_id == 0 || snd_MaxVolume == 0)
+ return;
+ if (origin == NULL)
+ {
+ origin = listener;
+ }
+
+// calculate the distance before other stuff so that we can throw out
+// sounds that are beyond the hearing range.
+ absx = abs(origin->x - listener->x);
+ absy = abs(origin->y - listener->y);
+ dist = absx + absy - (absx > absy ? absy >> 1 : absx >> 1);
+ dist >>= FRACBITS;
+// dist = P_AproxDistance(origin->x-viewx, origin->y-viewy)>>FRACBITS;
+
+ if (dist >= MAX_SND_DIST)
+ {
+// dist = MAX_SND_DIST - 1;
+ return; //sound is beyond the hearing range...
+ }
+ if (dist < 0)
+ {
+ dist = 0;
+ }
+ priority = S_sfx[sound_id].priority;
+ priority *= (10 - (dist / 160));
+ if (!S_StopSoundID(sound_id, priority))
+ {
+ return; // other sounds have greater priority
+ }
+ for (i = 0; i < snd_Channels; i++)
+ {
+ if (origin->player)
+ {
+ i = snd_Channels;
+ break; // let the player have more than one sound.
+ }
+ if (origin == channel[i].mo)
+ { // only allow other mobjs one sound
+ S_StopSound(channel[i].mo);
+ break;
+ }
+ }
+ if (i >= snd_Channels)
+ {
+ if (sound_id >= sfx_wind)
+ {
+ if (AmbChan != -1 && S_sfx[sound_id].priority <=
+ S_sfx[channel[AmbChan].sound_id].priority)
+ {
+ return; //ambient channel already in use
+ }
+ else
+ {
+ AmbChan = -1;
+ }
+ }
+ for (i = 0; i < snd_Channels; i++)
+ {
+ if (channel[i].mo == NULL)
+ {
+ break;
+ }
+ }
+ if (i >= snd_Channels)
+ {
+ //look for a lower priority sound to replace.
+ sndcount++;
+ if (sndcount >= snd_Channels)
+ {
+ sndcount = 0;
+ }
+ for (chan = 0; chan < snd_Channels; chan++)
+ {
+ i = (sndcount + chan) % snd_Channels;
+ if (priority >= channel[i].priority)
+ {
+ chan = -1; //denote that sound should be replaced.
+ break;
+ }
+ }
+ if (chan != -1)
+ {
+ return; //no free channels.
+ }
+ else //replace the lower priority sound.
+ {
+ if (channel[i].handle)
+ {
+ if (I_SoundIsPlaying(channel[i].handle))
+ {
+ I_StopSound(channel[i].handle);
+ }
+ if (S_sfx[channel[i].sound_id].usefulness > 0)
+ {
+ S_sfx[channel[i].sound_id].usefulness--;
+ }
+
+ if (AmbChan == i)
+ {
+ AmbChan = -1;
+ }
+ }
+ }
+ }
+ }
+ if (S_sfx[sound_id].lumpnum == 0)
+ {
+ S_sfx[sound_id].lumpnum = I_GetSfxLumpNum(&S_sfx[sound_id]);
+ }
+
+ // calculate the volume based upon the distance from the sound origin.
+// vol = (snd_MaxVolume*16 + dist*(-snd_MaxVolume*16)/MAX_SND_DIST)>>9;
+ vol = soundCurve[dist];
+
+ if (origin == listener)
+ {
+ sep = 128;
+ }
+ else
+ {
+ angle = R_PointToAngle2(listener->x, listener->y,
+ origin->x, origin->y);
+ angle = (angle - viewangle) >> 24;
+ sep = angle * 2 - 128;
+ if (sep < 64)
+ sep = -sep;
+ if (sep > 192)
+ sep = 512 - sep;
+ }
+
+ // TODO: Play pitch-shifted sounds as in Vanilla Heretic
+
+ channel[i].pitch = (byte) (127 + (M_Random() & 7) - (M_Random() & 7));
+ channel[i].handle = I_StartSound(&S_sfx[sound_id], i, vol, sep);
+ channel[i].mo = origin;
+ channel[i].sound_id = sound_id;
+ channel[i].priority = priority;
+ if (sound_id >= sfx_wind)
+ {
+ AmbChan = i;
+ }
+ if (S_sfx[sound_id].usefulness == -1)
+ {
+ S_sfx[sound_id].usefulness = 1;
+ }
+ else
+ {
+ S_sfx[sound_id].usefulness++;
+ }
+}
+
+void S_StartSoundAtVolume(void *_origin, int sound_id, int volume)
+{
+ mobj_t *origin = _origin;
+ mobj_t *listener;
+ int i;
+
+ listener = GetSoundListener();
+
+ if (sound_id == 0 || snd_MaxVolume == 0)
+ return;
+ if (origin == NULL)
+ {
+ origin = listener;
+ }
+
+ if (volume == 0)
+ {
+ return;
+ }
+ volume = (volume * (snd_MaxVolume + 1) * 8) >> 7;
+
+// no priority checking, as ambient sounds would be the LOWEST.
+ for (i = 0; i < snd_Channels; i++)
+ {
+ if (channel[i].mo == NULL)
+ {
+ break;
+ }
+ }
+ if (i >= snd_Channels)
+ {
+ return;
+ }
+ if (S_sfx[sound_id].lumpnum == 0)
+ {
+ S_sfx[sound_id].lumpnum = I_GetSfxLumpNum(&S_sfx[sound_id]);
+ }
+
+ // TODO: Pitch shifting.
+ channel[i].pitch = (byte) (127 - (M_Random() & 3) + (M_Random() & 3));
+ channel[i].handle = I_StartSound(&S_sfx[sound_id], i, volume, 128);
+ channel[i].mo = origin;
+ channel[i].sound_id = sound_id;
+ channel[i].priority = 1; //super low priority.
+ if (S_sfx[sound_id].usefulness == -1)
+ {
+ S_sfx[sound_id].usefulness = 1;
+ }
+ else
+ {
+ S_sfx[sound_id].usefulness++;
+ }
+}
+
+boolean S_StopSoundID(int sound_id, int priority)
+{
+ int i;
+ int lp; //least priority
+ int found;
+
+ if (S_sfx[sound_id].numchannels == -1)
+ {
+ return (true);
+ }
+ lp = -1; //denote the argument sound_id
+ found = 0;
+ for (i = 0; i < snd_Channels; i++)
+ {
+ if (channel[i].sound_id == sound_id && channel[i].mo)
+ {
+ found++; //found one. Now, should we replace it??
+ if (priority >= channel[i].priority)
+ { // if we're gonna kill one, then this'll be it
+ lp = i;
+ priority = channel[i].priority;
+ }
+ }
+ }
+ if (found < S_sfx[sound_id].numchannels)
+ {
+ return (true);
+ }
+ else if (lp == -1)
+ {
+ return (false); // don't replace any sounds
+ }
+ if (channel[lp].handle)
+ {
+ if (I_SoundIsPlaying(channel[lp].handle))
+ {
+ I_StopSound(channel[lp].handle);
+ }
+ if (S_sfx[channel[i].sound_id].usefulness > 0)
+ {
+ S_sfx[channel[i].sound_id].usefulness--;
+ }
+ channel[lp].mo = NULL;
+ }
+ return (true);
+}
+
+void S_StopSound(void *_origin)
+{
+ mobj_t *origin = _origin;
+ int i;
+
+ for (i = 0; i < snd_Channels; i++)
+ {
+ if (channel[i].mo == origin)
+ {
+ I_StopSound(channel[i].handle);
+ if (S_sfx[channel[i].sound_id].usefulness > 0)
+ {
+ S_sfx[channel[i].sound_id].usefulness--;
+ }
+ channel[i].handle = 0;
+ channel[i].mo = NULL;
+ if (AmbChan == i)
+ {
+ AmbChan = -1;
+ }
+ }
+ }
+}
+
+void S_SoundLink(mobj_t * oldactor, mobj_t * newactor)
+{
+ int i;
+
+ for (i = 0; i < snd_Channels; i++)
+ {
+ if (channel[i].mo == oldactor)
+ channel[i].mo = newactor;
+ }
+}
+
+void S_PauseSound(void)
+{
+ I_PauseSong();
+}
+
+void S_ResumeSound(void)
+{
+ I_ResumeSong();
+}
+
+void S_UpdateSounds(mobj_t * listener)
+{
+ int i, dist, vol;
+ int angle;
+ int sep;
+ int priority;
+ int absx;
+ int absy;
+
+ listener = GetSoundListener();
+ if (snd_MaxVolume == 0)
+ {
+ return;
+ }
+
+ for (i = 0; i < snd_Channels; i++)
+ {
+ if (!channel[i].handle || S_sfx[channel[i].sound_id].usefulness == -1)
+ {
+ continue;
+ }
+ if (!I_SoundIsPlaying(channel[i].handle))
+ {
+ if (S_sfx[channel[i].sound_id].usefulness > 0)
+ {
+ S_sfx[channel[i].sound_id].usefulness--;
+ }
+ channel[i].handle = 0;
+ channel[i].mo = NULL;
+ channel[i].sound_id = 0;
+ if (AmbChan == i)
+ {
+ AmbChan = -1;
+ }
+ }
+ if (channel[i].mo == NULL || channel[i].sound_id == 0
+ || channel[i].mo == listener || listener == NULL)
+ {
+ continue;
+ }
+ else
+ {
+ absx = abs(channel[i].mo->x - listener->x);
+ absy = abs(channel[i].mo->y - listener->y);
+ dist = absx + absy - (absx > absy ? absy >> 1 : absx >> 1);
+ dist >>= FRACBITS;
+// dist = P_AproxDistance(channel[i].mo->x-listener->x, channel[i].mo->y-listener->y)>>FRACBITS;
+
+ if (dist >= MAX_SND_DIST)
+ {
+ S_StopSound(channel[i].mo);
+ continue;
+ }
+ if (dist < 0)
+ dist = 0;
+
+// calculate the volume based upon the distance from the sound origin.
+// vol = (*((byte *)W_CacheLumpName("SNDCURVE", PU_CACHE)+dist)*(snd_MaxVolume*8))>>7;
+ vol = soundCurve[dist];
+
+ angle = R_PointToAngle2(listener->x, listener->y,
+ channel[i].mo->x, channel[i].mo->y);
+ angle = (angle - viewangle) >> 24;
+ sep = angle * 2 - 128;
+ if (sep < 64)
+ sep = -sep;
+ if (sep > 192)
+ sep = 512 - sep;
+ // TODO: Pitch shifting.
+ I_UpdateSoundParams(channel[i].handle, vol, sep);
+ priority = S_sfx[channel[i].sound_id].priority;
+ priority *= (10 - (dist >> 8));
+ channel[i].priority = priority;
+ }
+ }
+}
+
+void S_Init(void)
+{
+ soundCurve = Z_Malloc(MAX_SND_DIST, PU_STATIC, NULL);
+ I_InitSound(false);
+ if (snd_Channels > 8)
+ {
+ snd_Channels = 8;
+ }
+ I_SetMusicVolume(snd_MusicVolume * 8);
+ S_SetMaxVolume(true);
+
+ I_AtExit(S_ShutDown, true);
+}
+
+void S_GetChannelInfo(SoundInfo_t * s)
+{
+ int i;
+ ChanInfo_t *c;
+
+ s->channelCount = snd_Channels;
+ s->musicVolume = snd_MusicVolume;
+ s->soundVolume = snd_MaxVolume;
+ for (i = 0; i < snd_Channels; i++)
+ {
+ c = &s->chan[i];
+ c->id = channel[i].sound_id;
+ c->priority = channel[i].priority;
+ c->name = S_sfx[c->id].name;
+ c->mo = channel[i].mo;
+
+ if (c->mo != NULL)
+ {
+ c->distance = P_AproxDistance(c->mo->x - viewx, c->mo->y - viewy)
+ >> FRACBITS;
+ }
+ else
+ {
+ c->distance = 0;
+ }
+ }
+}
+
+void S_SetMaxVolume(boolean fullprocess)
+{
+ int i;
+
+ if (!fullprocess)
+ {
+ soundCurve[0] =
+ (*((byte *) W_CacheLumpName("SNDCURVE", PU_CACHE)) *
+ (snd_MaxVolume * 8)) >> 7;
+ }
+ else
+ {
+ for (i = 0; i < MAX_SND_DIST; i++)
+ {
+ soundCurve[i] =
+ (*((byte *) W_CacheLumpName("SNDCURVE", PU_CACHE) + i) *
+ (snd_MaxVolume * 8)) >> 7;
+ }
+ }
+}
+
+static boolean musicPaused;
+void S_SetMusicVolume(void)
+{
+ I_SetMusicVolume(snd_MusicVolume * 8);
+ if (snd_MusicVolume == 0)
+ {
+ I_PauseSong();
+ musicPaused = true;
+ }
+ else if (musicPaused)
+ {
+ musicPaused = false;
+ I_ResumeSong();
+ }
+}
+
+void S_ShutDown(void)
+{
+ I_StopSong();
+ I_UnRegisterSong(rs);
+ I_ShutdownSound();
+}
+
diff --git a/src/heretic/s_sound.h b/src/heretic/s_sound.h
new file mode 100644
index 00000000..e678fc99
--- /dev/null
+++ b/src/heretic/s_sound.h
@@ -0,0 +1,46 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// soundst.h
+
+#ifndef __SOUNDSTH__
+#define __SOUNDSTH__
+
+extern int snd_MaxVolume;
+extern int snd_MusicVolume;
+
+void S_Start(void);
+void S_StartSound(void *origin, int sound_id);
+void S_StartSoundAtVolume(void *origin, int sound_id, int volume);
+void S_StopSound(void *origin);
+void S_PauseSound(void);
+void S_ResumeSound(void);
+void S_UpdateSounds(mobj_t * listener);
+void S_StartSong(int song, boolean loop);
+void S_Init(void);
+void S_GetChannelInfo(SoundInfo_t * s);
+void S_SetMaxVolume(boolean fullprocess);
+void S_SetMusicVolume(void);
+
+#endif
diff --git a/src/heretic/sb_bar.c b/src/heretic/sb_bar.c
new file mode 100644
index 00000000..03ec453d
--- /dev/null
+++ b/src/heretic/sb_bar.c
@@ -0,0 +1,1293 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// SB_bar.c
+
+#include "doomdef.h"
+#include "deh_str.h"
+#include "i_video.h"
+#include "m_cheat.h"
+#include "m_misc.h"
+#include "m_random.h"
+#include "p_local.h"
+#include "s_sound.h"
+#include "v_video.h"
+
+// Types
+
+typedef struct Cheat_s
+{
+ void (*func) (player_t * player, struct Cheat_s * cheat);
+ cheatseq_t *seq;
+} Cheat_t;
+
+// Private Functions
+
+static void DrawSoundInfo(void);
+static void ShadeLine(int x, int y, int height, int shade);
+static void ShadeChain(void);
+static void DrINumber(signed int val, int x, int y);
+static void DrBNumber(signed int val, int x, int y);
+static void DrawCommonBar(void);
+static void DrawMainBar(void);
+static void DrawInventoryBar(void);
+static void DrawFullScreenStuff(void);
+static boolean HandleCheats(byte key);
+static void CheatGodFunc(player_t * player, Cheat_t * cheat);
+static void CheatNoClipFunc(player_t * player, Cheat_t * cheat);
+static void CheatWeaponsFunc(player_t * player, Cheat_t * cheat);
+static void CheatPowerFunc(player_t * player, Cheat_t * cheat);
+static void CheatHealthFunc(player_t * player, Cheat_t * cheat);
+static void CheatKeysFunc(player_t * player, Cheat_t * cheat);
+static void CheatSoundFunc(player_t * player, Cheat_t * cheat);
+static void CheatTickerFunc(player_t * player, Cheat_t * cheat);
+static void CheatArtifact1Func(player_t * player, Cheat_t * cheat);
+static void CheatArtifact2Func(player_t * player, Cheat_t * cheat);
+static void CheatArtifact3Func(player_t * player, Cheat_t * cheat);
+static void CheatWarpFunc(player_t * player, Cheat_t * cheat);
+static void CheatChickenFunc(player_t * player, Cheat_t * cheat);
+static void CheatMassacreFunc(player_t * player, Cheat_t * cheat);
+static void CheatIDKFAFunc(player_t * player, Cheat_t * cheat);
+static void CheatIDDQDFunc(player_t * player, Cheat_t * cheat);
+
+// Public Data
+
+boolean DebugSound; // debug flag for displaying sound info
+
+boolean inventory;
+int curpos;
+int inv_ptr;
+int ArtifactFlash;
+
+static int DisplayTicker = 0;
+
+// Private Data
+
+static int HealthMarker;
+static int ChainWiggle;
+static player_t *CPlayer;
+int playpalette;
+
+patch_t *PatchLTFACE;
+patch_t *PatchRTFACE;
+patch_t *PatchBARBACK;
+patch_t *PatchCHAIN;
+patch_t *PatchSTATBAR;
+patch_t *PatchLIFEGEM;
+//patch_t *PatchEMPWEAP;
+//patch_t *PatchLIL4BOX;
+patch_t *PatchLTFCTOP;
+patch_t *PatchRTFCTOP;
+//patch_t *PatchARMORBOX;
+//patch_t *PatchARTIBOX;
+patch_t *PatchSELECTBOX;
+//patch_t *PatchKILLSPIC;
+//patch_t *PatchMANAPIC;
+//patch_t *PatchPOWERICN;
+patch_t *PatchINVLFGEM1;
+patch_t *PatchINVLFGEM2;
+patch_t *PatchINVRTGEM1;
+patch_t *PatchINVRTGEM2;
+patch_t *PatchINumbers[10];
+patch_t *PatchNEGATIVE;
+patch_t *PatchSmNumbers[10];
+patch_t *PatchBLACKSQ;
+patch_t *PatchINVBAR;
+patch_t *PatchARMCLEAR;
+patch_t *PatchCHAINBACK;
+//byte *ShadeTables;
+int FontBNumBase;
+int spinbooklump;
+int spinflylump;
+
+// Toggle god mode
+cheatseq_t CheatGodSeq = CHEAT("quicken", 0);
+
+// Toggle no clipping mode
+cheatseq_t CheatNoClipSeq = CHEAT("kitty", 0);
+
+// Get all weapons and ammo
+cheatseq_t CheatWeaponsSeq = CHEAT("rambo", 0);
+
+// Toggle tome of power
+cheatseq_t CheatPowerSeq = CHEAT("shazam", 0);
+
+// Get full health
+cheatseq_t CheatHealthSeq = CHEAT("ponce", 0);
+
+// Get all keys
+cheatseq_t CheatKeysSeq = CHEAT("skel", 0);
+
+// Toggle sound debug info
+cheatseq_t CheatSoundSeq = CHEAT("noise", 0);
+
+// Toggle ticker
+cheatseq_t CheatTickerSeq = CHEAT("ticker", 0);
+
+// Get an artifact 1st stage (ask for type)
+cheatseq_t CheatArtifact1Seq = CHEAT("gimme", 0);
+
+// Get an artifact 2nd stage (ask for count)
+cheatseq_t CheatArtifact2Seq = CHEAT("gimme", 1);
+
+// Get an artifact final stage
+cheatseq_t CheatArtifact3Seq = CHEAT("gimme", 2);
+
+// Warp to new level
+cheatseq_t CheatWarpSeq = CHEAT("engage", 2);
+
+// Save a screenshot
+cheatseq_t CheatChickenSeq = CHEAT("cockadoodledoo", 0);
+
+// Kill all monsters
+cheatseq_t CheatMassacreSeq = CHEAT("massacre", 0);
+
+cheatseq_t CheatIDKFASeq = CHEAT("idkfa", 0);
+cheatseq_t CheatIDDQDSeq = CHEAT("iddqd", 0);
+
+static Cheat_t Cheats[] = {
+ {CheatGodFunc, &CheatGodSeq},
+ {CheatNoClipFunc, &CheatNoClipSeq},
+ {CheatWeaponsFunc, &CheatWeaponsSeq},
+ {CheatPowerFunc, &CheatPowerSeq},
+ {CheatHealthFunc, &CheatHealthSeq},
+ {CheatKeysFunc, &CheatKeysSeq},
+ {CheatSoundFunc, &CheatSoundSeq},
+ {CheatTickerFunc, &CheatTickerSeq},
+ {CheatArtifact1Func, &CheatArtifact1Seq},
+ {CheatArtifact2Func, &CheatArtifact2Seq},
+ {CheatArtifact3Func, &CheatArtifact3Seq},
+ {CheatWarpFunc, &CheatWarpSeq},
+ {CheatChickenFunc, &CheatChickenSeq},
+ {CheatMassacreFunc, &CheatMassacreSeq},
+ {CheatIDKFAFunc, &CheatIDKFASeq},
+ {CheatIDDQDFunc, &CheatIDDQDSeq},
+ {NULL, NULL}
+};
+
+//---------------------------------------------------------------------------
+//
+// PROC SB_Init
+//
+//---------------------------------------------------------------------------
+
+void SB_Init(void)
+{
+ int i;
+ int startLump;
+
+ PatchLTFACE = W_CacheLumpName(DEH_String("LTFACE"), PU_STATIC);
+ PatchRTFACE = W_CacheLumpName(DEH_String("RTFACE"), PU_STATIC);
+ PatchBARBACK = W_CacheLumpName(DEH_String("BARBACK"), PU_STATIC);
+ PatchINVBAR = W_CacheLumpName(DEH_String("INVBAR"), PU_STATIC);
+ PatchCHAIN = W_CacheLumpName(DEH_String("CHAIN"), PU_STATIC);
+ if (deathmatch)
+ {
+ PatchSTATBAR = W_CacheLumpName(DEH_String("STATBAR"), PU_STATIC);
+ }
+ else
+ {
+ PatchSTATBAR = W_CacheLumpName(DEH_String("LIFEBAR"), PU_STATIC);
+ }
+ if (!netgame)
+ { // single player game uses red life gem
+ PatchLIFEGEM = W_CacheLumpName(DEH_String("LIFEGEM2"), PU_STATIC);
+ }
+ else
+ {
+ PatchLIFEGEM = W_CacheLumpNum(W_GetNumForName(DEH_String("LIFEGEM0"))
+ + consoleplayer, PU_STATIC);
+ }
+ PatchLTFCTOP = W_CacheLumpName(DEH_String("LTFCTOP"), PU_STATIC);
+ PatchRTFCTOP = W_CacheLumpName(DEH_String("RTFCTOP"), PU_STATIC);
+ PatchSELECTBOX = W_CacheLumpName(DEH_String("SELECTBOX"), PU_STATIC);
+ PatchINVLFGEM1 = W_CacheLumpName(DEH_String("INVGEML1"), PU_STATIC);
+ PatchINVLFGEM2 = W_CacheLumpName(DEH_String("INVGEML2"), PU_STATIC);
+ PatchINVRTGEM1 = W_CacheLumpName(DEH_String("INVGEMR1"), PU_STATIC);
+ PatchINVRTGEM2 = W_CacheLumpName(DEH_String("INVGEMR2"), PU_STATIC);
+ PatchBLACKSQ = W_CacheLumpName(DEH_String("BLACKSQ"), PU_STATIC);
+ PatchARMCLEAR = W_CacheLumpName(DEH_String("ARMCLEAR"), PU_STATIC);
+ PatchCHAINBACK = W_CacheLumpName(DEH_String("CHAINBACK"), PU_STATIC);
+ startLump = W_GetNumForName(DEH_String("IN0"));
+ for (i = 0; i < 10; i++)
+ {
+ PatchINumbers[i] = W_CacheLumpNum(startLump + i, PU_STATIC);
+ }
+ PatchNEGATIVE = W_CacheLumpName(DEH_String("NEGNUM"), PU_STATIC);
+ FontBNumBase = W_GetNumForName(DEH_String("FONTB16"));
+ startLump = W_GetNumForName(DEH_String("SMALLIN0"));
+ for (i = 0; i < 10; i++)
+ {
+ PatchSmNumbers[i] = W_CacheLumpNum(startLump + i, PU_STATIC);
+ }
+ playpalette = W_GetNumForName(DEH_String("PLAYPAL"));
+ spinbooklump = W_GetNumForName(DEH_String("SPINBK0"));
+ spinflylump = W_GetNumForName(DEH_String("SPFLY0"));
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SB_Ticker
+//
+//---------------------------------------------------------------------------
+
+void SB_Ticker(void)
+{
+ int delta;
+ int curHealth;
+
+ if (leveltime & 1)
+ {
+ ChainWiggle = P_Random() & 1;
+ }
+ curHealth = players[consoleplayer].mo->health;
+ if (curHealth < 0)
+ {
+ curHealth = 0;
+ }
+ if (curHealth < HealthMarker)
+ {
+ delta = (HealthMarker - curHealth) >> 2;
+ if (delta < 1)
+ {
+ delta = 1;
+ }
+ else if (delta > 8)
+ {
+ delta = 8;
+ }
+ HealthMarker -= delta;
+ }
+ else if (curHealth > HealthMarker)
+ {
+ delta = (curHealth - HealthMarker) >> 2;
+ if (delta < 1)
+ {
+ delta = 1;
+ }
+ else if (delta > 8)
+ {
+ delta = 8;
+ }
+ HealthMarker += delta;
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrINumber
+//
+// Draws a three digit number.
+//
+//---------------------------------------------------------------------------
+
+static void DrINumber(signed int val, int x, int y)
+{
+ patch_t *patch;
+ int oldval;
+
+ oldval = val;
+ if (val < 0)
+ {
+ if (val < -9)
+ {
+ V_DrawPatch(x + 1, y + 1, W_CacheLumpName(DEH_String("LAME"), PU_CACHE));
+ }
+ else
+ {
+ val = -val;
+ V_DrawPatch(x + 18, y, PatchINumbers[val]);
+ V_DrawPatch(x + 9, y, PatchNEGATIVE);
+ }
+ return;
+ }
+ if (val > 99)
+ {
+ patch = PatchINumbers[val / 100];
+ V_DrawPatch(x, y, patch);
+ }
+ val = val % 100;
+ if (val > 9 || oldval > 99)
+ {
+ patch = PatchINumbers[val / 10];
+ V_DrawPatch(x + 9, y, patch);
+ }
+ val = val % 10;
+ patch = PatchINumbers[val];
+ V_DrawPatch(x + 18, y, patch);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrBNumber
+//
+// Draws a three digit number using FontB
+//
+//---------------------------------------------------------------------------
+
+static void DrBNumber(signed int val, int x, int y)
+{
+ patch_t *patch;
+ int xpos;
+ int oldval;
+
+ oldval = val;
+ xpos = x;
+ if (val < 0)
+ {
+ val = 0;
+ }
+ if (val > 99)
+ {
+ patch = W_CacheLumpNum(FontBNumBase + val / 100, PU_CACHE);
+ V_DrawShadowedPatch(xpos + 6 - patch->width / 2, y, patch);
+ }
+ val = val % 100;
+ xpos += 12;
+ if (val > 9 || oldval > 99)
+ {
+ patch = W_CacheLumpNum(FontBNumBase + val / 10, PU_CACHE);
+ V_DrawShadowedPatch(xpos + 6 - patch->width / 2, y, patch);
+ }
+ val = val % 10;
+ xpos += 12;
+ patch = W_CacheLumpNum(FontBNumBase + val, PU_CACHE);
+ V_DrawShadowedPatch(xpos + 6 - patch->width / 2, y, patch);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrSmallNumber
+//
+// Draws a small two digit number.
+//
+//---------------------------------------------------------------------------
+
+static void DrSmallNumber(int val, int x, int y)
+{
+ patch_t *patch;
+
+ if (val == 1)
+ {
+ return;
+ }
+ if (val > 9)
+ {
+ patch = PatchSmNumbers[val / 10];
+ V_DrawPatch(x, y, patch);
+ }
+ val = val % 10;
+ patch = PatchSmNumbers[val];
+ V_DrawPatch(x + 4, y, patch);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC ShadeLine
+//
+//---------------------------------------------------------------------------
+
+static void ShadeLine(int x, int y, int height, int shade)
+{
+ byte *dest;
+ byte *shades;
+
+ shades = colormaps + 9 * 256 + shade * 2 * 256;
+ dest = I_VideoBuffer + y * SCREENWIDTH + x;
+ while (height--)
+ {
+ *(dest) = *(shades + *dest);
+ dest += SCREENWIDTH;
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC ShadeChain
+//
+//---------------------------------------------------------------------------
+
+static void ShadeChain(void)
+{
+ int i;
+
+ for (i = 0; i < 16; i++)
+ {
+ ShadeLine(277 + i, 190, 10, i / 2);
+ ShadeLine(19 + i, 190, 10, 7 - (i / 2));
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawSoundInfo
+//
+// Displays sound debugging information.
+//
+//---------------------------------------------------------------------------
+
+static void DrawSoundInfo(void)
+{
+ int i;
+ SoundInfo_t s;
+ ChanInfo_t *c;
+ char text[32];
+ int x;
+ int y;
+ int xPos[7] = { 1, 75, 112, 156, 200, 230, 260 };
+
+ if (leveltime & 16)
+ {
+ MN_DrTextA(DEH_String("*** SOUND DEBUG INFO ***"), xPos[0], 20);
+ }
+ S_GetChannelInfo(&s);
+ if (s.channelCount == 0)
+ {
+ return;
+ }
+ x = 0;
+ MN_DrTextA(DEH_String("NAME"), xPos[x++], 30);
+ MN_DrTextA(DEH_String("MO.T"), xPos[x++], 30);
+ MN_DrTextA(DEH_String("MO.X"), xPos[x++], 30);
+ MN_DrTextA(DEH_String("MO.Y"), xPos[x++], 30);
+ MN_DrTextA(DEH_String("ID"), xPos[x++], 30);
+ MN_DrTextA(DEH_String("PRI"), xPos[x++], 30);
+ MN_DrTextA(DEH_String("DIST"), xPos[x++], 30);
+ for (i = 0; i < s.channelCount; i++)
+ {
+ c = &s.chan[i];
+ x = 0;
+ y = 40 + i * 10;
+ if (c->mo == NULL)
+ { // Channel is unused
+ MN_DrTextA(DEH_String("------"), xPos[0], y);
+ continue;
+ }
+ sprintf(text, "%s", c->name);
+ M_ForceUppercase(text);
+ MN_DrTextA(text, xPos[x++], y);
+ sprintf(text, "%d", c->mo->type);
+ MN_DrTextA(text, xPos[x++], y);
+ sprintf(text, "%d", c->mo->x >> FRACBITS);
+ MN_DrTextA(text, xPos[x++], y);
+ sprintf(text, "%d", c->mo->y >> FRACBITS);
+ MN_DrTextA(text, xPos[x++], y);
+ sprintf(text, "%d", c->id);
+ MN_DrTextA(text, xPos[x++], y);
+ sprintf(text, "%d", c->priority);
+ MN_DrTextA(text, xPos[x++], y);
+ sprintf(text, "%d", c->distance);
+ MN_DrTextA(text, xPos[x++], y);
+ }
+ UpdateState |= I_FULLSCRN;
+ BorderNeedRefresh = true;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SB_Drawer
+//
+//---------------------------------------------------------------------------
+
+char patcharti[][10] = {
+ {"ARTIBOX"}, // none
+ {"ARTIINVU"}, // invulnerability
+ {"ARTIINVS"}, // invisibility
+ {"ARTIPTN2"}, // health
+ {"ARTISPHL"}, // superhealth
+ {"ARTIPWBK"}, // tomeofpower
+ {"ARTITRCH"}, // torch
+ {"ARTIFBMB"}, // firebomb
+ {"ARTIEGGC"}, // egg
+ {"ARTISOAR"}, // fly
+ {"ARTIATLP"} // teleport
+};
+
+char ammopic[][10] = {
+ {"INAMGLD"},
+ {"INAMBOW"},
+ {"INAMBST"},
+ {"INAMRAM"},
+ {"INAMPNX"},
+ {"INAMLOB"}
+};
+
+int SB_state = -1;
+static int oldarti = 0;
+static int oldartiCount = 0;
+static int oldfrags = -9999;
+static int oldammo = -1;
+static int oldarmor = -1;
+static int oldweapon = -1;
+static int oldhealth = -1;
+static int oldlife = -1;
+static int oldkeys = -1;
+
+int playerkeys = 0;
+
+extern boolean automapactive;
+
+void SB_Drawer(void)
+{
+ int frame;
+ static boolean hitCenterFrame;
+
+ // Sound info debug stuff
+ if (DebugSound == true)
+ {
+ DrawSoundInfo();
+ }
+ CPlayer = &players[consoleplayer];
+ if (viewheight == SCREENHEIGHT && !automapactive)
+ {
+ DrawFullScreenStuff();
+ SB_state = -1;
+ }
+ else
+ {
+ if (SB_state == -1)
+ {
+ V_DrawPatch(0, 158, PatchBARBACK);
+ if (players[consoleplayer].cheats & CF_GODMODE)
+ {
+ V_DrawPatch(16, 167,
+ W_CacheLumpName(DEH_String("GOD1"), PU_CACHE));
+ V_DrawPatch(287, 167,
+ W_CacheLumpName(DEH_String("GOD2"), PU_CACHE));
+ }
+ oldhealth = -1;
+ }
+ DrawCommonBar();
+ if (!inventory)
+ {
+ if (SB_state != 0)
+ {
+ // Main interface
+ V_DrawPatch(34, 160, PatchSTATBAR);
+ oldarti = 0;
+ oldammo = -1;
+ oldarmor = -1;
+ oldweapon = -1;
+ oldfrags = -9999; //can't use -1, 'cuz of negative frags
+ oldlife = -1;
+ oldkeys = -1;
+ }
+ DrawMainBar();
+ SB_state = 0;
+ }
+ else
+ {
+ if (SB_state != 1)
+ {
+ V_DrawPatch(34, 160, PatchINVBAR);
+ }
+ DrawInventoryBar();
+ SB_state = 1;
+ }
+ }
+ SB_PaletteFlash();
+
+ // Flight icons
+ if (CPlayer->powers[pw_flight])
+ {
+ if (CPlayer->powers[pw_flight] > BLINKTHRESHOLD
+ || !(CPlayer->powers[pw_flight] & 16))
+ {
+ frame = (leveltime / 3) & 15;
+ if (CPlayer->mo->flags2 & MF2_FLY)
+ {
+ if (hitCenterFrame && (frame != 15 && frame != 0))
+ {
+ V_DrawPatch(20, 17, W_CacheLumpNum(spinflylump + 15,
+ PU_CACHE));
+ }
+ else
+ {
+ V_DrawPatch(20, 17, W_CacheLumpNum(spinflylump + frame,
+ PU_CACHE));
+ hitCenterFrame = false;
+ }
+ }
+ else
+ {
+ if (!hitCenterFrame && (frame != 15 && frame != 0))
+ {
+ V_DrawPatch(20, 17, W_CacheLumpNum(spinflylump + frame,
+ PU_CACHE));
+ hitCenterFrame = false;
+ }
+ else
+ {
+ V_DrawPatch(20, 17, W_CacheLumpNum(spinflylump + 15,
+ PU_CACHE));
+ hitCenterFrame = true;
+ }
+ }
+ BorderTopRefresh = true;
+ UpdateState |= I_MESSAGES;
+ }
+ else
+ {
+ BorderTopRefresh = true;
+ UpdateState |= I_MESSAGES;
+ }
+ }
+
+ if (CPlayer->powers[pw_weaponlevel2] && !CPlayer->chickenTics)
+ {
+ if (CPlayer->powers[pw_weaponlevel2] > BLINKTHRESHOLD
+ || !(CPlayer->powers[pw_weaponlevel2] & 16))
+ {
+ frame = (leveltime / 3) & 15;
+ V_DrawPatch(300, 17,
+ W_CacheLumpNum(spinbooklump + frame, PU_CACHE));
+ BorderTopRefresh = true;
+ UpdateState |= I_MESSAGES;
+ }
+ else
+ {
+ BorderTopRefresh = true;
+ UpdateState |= I_MESSAGES;
+ }
+ }
+/*
+ if(CPlayer->powers[pw_weaponlevel2] > BLINKTHRESHOLD
+ || (CPlayer->powers[pw_weaponlevel2]&8))
+ {
+ V_DrawPatch(291, 0, W_CacheLumpName("ARTIPWBK", PU_CACHE));
+ }
+ else
+ {
+ BorderTopRefresh = true;
+ }
+ }
+*/
+}
+
+// sets the new palette based upon current values of player->damagecount
+// and player->bonuscount
+void SB_PaletteFlash(void)
+{
+ static int sb_palette = 0;
+ int palette;
+ byte *pal;
+
+ CPlayer = &players[consoleplayer];
+
+ if (CPlayer->damagecount)
+ {
+ palette = (CPlayer->damagecount + 7) >> 3;
+ if (palette >= NUMREDPALS)
+ {
+ palette = NUMREDPALS - 1;
+ }
+ palette += STARTREDPALS;
+ }
+ else if (CPlayer->bonuscount)
+ {
+ palette = (CPlayer->bonuscount + 7) >> 3;
+ if (palette >= NUMBONUSPALS)
+ {
+ palette = NUMBONUSPALS - 1;
+ }
+ palette += STARTBONUSPALS;
+ }
+ else
+ {
+ palette = 0;
+ }
+ if (palette != sb_palette)
+ {
+ sb_palette = palette;
+ pal = (byte *) W_CacheLumpNum(playpalette, PU_CACHE) + palette * 768;
+ I_SetPalette(pal);
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawCommonBar
+//
+//---------------------------------------------------------------------------
+
+void DrawCommonBar(void)
+{
+ int chainY;
+ int healthPos;
+
+ V_DrawPatch(0, 148, PatchLTFCTOP);
+ V_DrawPatch(290, 148, PatchRTFCTOP);
+
+ if (oldhealth != HealthMarker)
+ {
+ oldhealth = HealthMarker;
+ healthPos = HealthMarker;
+ if (healthPos < 0)
+ {
+ healthPos = 0;
+ }
+ if (healthPos > 100)
+ {
+ healthPos = 100;
+ }
+ healthPos = (healthPos * 256) / 100;
+ chainY =
+ (HealthMarker == CPlayer->mo->health) ? 191 : 191 + ChainWiggle;
+ V_DrawPatch(0, 190, PatchCHAINBACK);
+ V_DrawPatch(2 + (healthPos % 17), chainY, PatchCHAIN);
+ V_DrawPatch(17 + healthPos, chainY, PatchLIFEGEM);
+ V_DrawPatch(0, 190, PatchLTFACE);
+ V_DrawPatch(276, 190, PatchRTFACE);
+ ShadeChain();
+ UpdateState |= I_STATBAR;
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawMainBar
+//
+//---------------------------------------------------------------------------
+
+void DrawMainBar(void)
+{
+ int i;
+ int temp;
+
+ // Ready artifact
+ if (ArtifactFlash)
+ {
+ V_DrawPatch(180, 161, PatchBLACKSQ);
+
+ temp = W_GetNumForName(DEH_String("useartia")) + ArtifactFlash - 1;
+
+ V_DrawPatch(182, 161, W_CacheLumpNum(temp, PU_CACHE));
+ ArtifactFlash--;
+ oldarti = -1; // so that the correct artifact fills in after the flash
+ UpdateState |= I_STATBAR;
+ }
+ else if (oldarti != CPlayer->readyArtifact
+ || oldartiCount != CPlayer->inventory[inv_ptr].count)
+ {
+ V_DrawPatch(180, 161, PatchBLACKSQ);
+ if (CPlayer->readyArtifact > 0)
+ {
+ V_DrawPatch(179, 160,
+ W_CacheLumpName(DEH_String(patcharti[CPlayer->readyArtifact]),
+ PU_CACHE));
+ DrSmallNumber(CPlayer->inventory[inv_ptr].count, 201, 182);
+ }
+ oldarti = CPlayer->readyArtifact;
+ oldartiCount = CPlayer->inventory[inv_ptr].count;
+ UpdateState |= I_STATBAR;
+ }
+
+ // Frags
+ if (deathmatch)
+ {
+ temp = 0;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ temp += CPlayer->frags[i];
+ }
+ if (temp != oldfrags)
+ {
+ V_DrawPatch(57, 171, PatchARMCLEAR);
+ DrINumber(temp, 61, 170);
+ oldfrags = temp;
+ UpdateState |= I_STATBAR;
+ }
+ }
+ else
+ {
+ temp = HealthMarker;
+ if (temp < 0)
+ {
+ temp = 0;
+ }
+ else if (temp > 100)
+ {
+ temp = 100;
+ }
+ if (oldlife != temp)
+ {
+ oldlife = temp;
+ V_DrawPatch(57, 171, PatchARMCLEAR);
+ DrINumber(temp, 61, 170);
+ UpdateState |= I_STATBAR;
+ }
+ }
+
+ // Keys
+ if (oldkeys != playerkeys)
+ {
+ if (CPlayer->keys[key_yellow])
+ {
+ V_DrawPatch(153, 164, W_CacheLumpName(DEH_String("ykeyicon"), PU_CACHE));
+ }
+ if (CPlayer->keys[key_green])
+ {
+ V_DrawPatch(153, 172, W_CacheLumpName(DEH_String("gkeyicon"), PU_CACHE));
+ }
+ if (CPlayer->keys[key_blue])
+ {
+ V_DrawPatch(153, 180, W_CacheLumpName(DEH_String("bkeyicon"), PU_CACHE));
+ }
+ oldkeys = playerkeys;
+ UpdateState |= I_STATBAR;
+ }
+ // Ammo
+ temp = CPlayer->ammo[wpnlev1info[CPlayer->readyweapon].ammo];
+ if (oldammo != temp || oldweapon != CPlayer->readyweapon)
+ {
+ V_DrawPatch(108, 161, PatchBLACKSQ);
+ if (temp && CPlayer->readyweapon > 0 && CPlayer->readyweapon < 7)
+ {
+ DrINumber(temp, 109, 162);
+ V_DrawPatch(111, 172,
+ W_CacheLumpName(DEH_String(ammopic[CPlayer->readyweapon - 1]),
+ PU_CACHE));
+ }
+ oldammo = temp;
+ oldweapon = CPlayer->readyweapon;
+ UpdateState |= I_STATBAR;
+ }
+
+ // Armor
+ if (oldarmor != CPlayer->armorpoints)
+ {
+ V_DrawPatch(224, 171, PatchARMCLEAR);
+ DrINumber(CPlayer->armorpoints, 228, 170);
+ oldarmor = CPlayer->armorpoints;
+ UpdateState |= I_STATBAR;
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawInventoryBar
+//
+//---------------------------------------------------------------------------
+
+void DrawInventoryBar(void)
+{
+ char *patch;
+ int i;
+ int x;
+
+ x = inv_ptr - curpos;
+ UpdateState |= I_STATBAR;
+ V_DrawPatch(34, 160, PatchINVBAR);
+ for (i = 0; i < 7; i++)
+ {
+ //V_DrawPatch(50+i*31, 160, W_CacheLumpName("ARTIBOX", PU_CACHE));
+ if (CPlayer->inventorySlotNum > x + i
+ && CPlayer->inventory[x + i].type != arti_none)
+ {
+ patch = DEH_String(patcharti[CPlayer->inventory[x + i].type]);
+
+ V_DrawPatch(50 + i * 31, 160, W_CacheLumpName(patch, PU_CACHE));
+ DrSmallNumber(CPlayer->inventory[x + i].count, 69 + i * 31, 182);
+ }
+ }
+ V_DrawPatch(50 + curpos * 31, 189, PatchSELECTBOX);
+ if (x != 0)
+ {
+ V_DrawPatch(38, 159, !(leveltime & 4) ? PatchINVLFGEM1 :
+ PatchINVLFGEM2);
+ }
+ if (CPlayer->inventorySlotNum - x > 7)
+ {
+ V_DrawPatch(269, 159, !(leveltime & 4) ?
+ PatchINVRTGEM1 : PatchINVRTGEM2);
+ }
+}
+
+void DrawFullScreenStuff(void)
+{
+ char *patch;
+ int i;
+ int x;
+ int temp;
+
+ UpdateState |= I_FULLSCRN;
+ if (CPlayer->mo->health > 0)
+ {
+ DrBNumber(CPlayer->mo->health, 5, 180);
+ }
+ else
+ {
+ DrBNumber(0, 5, 180);
+ }
+ if (deathmatch)
+ {
+ temp = 0;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ {
+ temp += CPlayer->frags[i];
+ }
+ }
+ DrINumber(temp, 45, 185);
+ }
+ if (!inventory)
+ {
+ if (CPlayer->readyArtifact > 0)
+ {
+ patch = DEH_String(patcharti[CPlayer->readyArtifact]);
+ V_DrawTLPatch(286, 170, W_CacheLumpName(DEH_String("ARTIBOX"), PU_CACHE));
+ V_DrawPatch(286, 170, W_CacheLumpName(patch, PU_CACHE));
+ DrSmallNumber(CPlayer->inventory[inv_ptr].count, 307, 192);
+ }
+ }
+ else
+ {
+ x = inv_ptr - curpos;
+ for (i = 0; i < 7; i++)
+ {
+ V_DrawTLPatch(50 + i * 31, 168,
+ W_CacheLumpName(DEH_String("ARTIBOX"), PU_CACHE));
+ if (CPlayer->inventorySlotNum > x + i
+ && CPlayer->inventory[x + i].type != arti_none)
+ {
+ patch = DEH_String(patcharti[CPlayer->inventory[x + i].type]);
+ V_DrawPatch(50 + i * 31, 168,
+ W_CacheLumpName(patch, PU_CACHE));
+ DrSmallNumber(CPlayer->inventory[x + i].count, 69 + i * 31,
+ 190);
+ }
+ }
+ V_DrawPatch(50 + curpos * 31, 197, PatchSELECTBOX);
+ if (x != 0)
+ {
+ V_DrawPatch(38, 167, !(leveltime & 4) ? PatchINVLFGEM1 :
+ PatchINVLFGEM2);
+ }
+ if (CPlayer->inventorySlotNum - x > 7)
+ {
+ V_DrawPatch(269, 167, !(leveltime & 4) ?
+ PatchINVRTGEM1 : PatchINVRTGEM2);
+ }
+ }
+}
+
+//--------------------------------------------------------------------------
+//
+// FUNC SB_Responder
+//
+//--------------------------------------------------------------------------
+
+boolean SB_Responder(event_t * event)
+{
+ if (event->type == ev_keydown)
+ {
+ if (HandleCheats(event->data1))
+ { // Need to eat the key
+ return (true);
+ }
+ }
+ return (false);
+}
+
+//--------------------------------------------------------------------------
+//
+// FUNC HandleCheats
+//
+// Returns true if the caller should eat the key.
+//
+//--------------------------------------------------------------------------
+
+static boolean HandleCheats(byte key)
+{
+ int i;
+ boolean eat;
+
+ if (netgame || gameskill == sk_nightmare)
+ { // Can't cheat in a net-game, or in nightmare mode
+ return (false);
+ }
+ if (players[consoleplayer].health <= 0)
+ { // Dead players can't cheat
+ return (false);
+ }
+ eat = false;
+ for (i = 0; Cheats[i].func != NULL; i++)
+ {
+ if (cht_CheckCheat(Cheats[i].seq, key))
+ {
+ Cheats[i].func(&players[consoleplayer], &Cheats[i]);
+ S_StartSound(NULL, sfx_dorcls);
+ }
+ }
+ return (eat);
+}
+
+//--------------------------------------------------------------------------
+//
+// CHEAT FUNCTIONS
+//
+//--------------------------------------------------------------------------
+
+static void CheatGodFunc(player_t * player, Cheat_t * cheat)
+{
+ player->cheats ^= CF_GODMODE;
+ if (player->cheats & CF_GODMODE)
+ {
+ P_SetMessage(player, DEH_String(TXT_CHEATGODON), false);
+ }
+ else
+ {
+ P_SetMessage(player, DEH_String(TXT_CHEATGODOFF), false);
+ }
+ SB_state = -1;
+}
+
+static void CheatNoClipFunc(player_t * player, Cheat_t * cheat)
+{
+ player->cheats ^= CF_NOCLIP;
+ if (player->cheats & CF_NOCLIP)
+ {
+ P_SetMessage(player, DEH_String(TXT_CHEATNOCLIPON), false);
+ }
+ else
+ {
+ P_SetMessage(player, DEH_String(TXT_CHEATNOCLIPOFF), false);
+ }
+}
+
+static void CheatWeaponsFunc(player_t * player, Cheat_t * cheat)
+{
+ int i;
+ //extern boolean *WeaponInShareware;
+
+ player->armorpoints = 200;
+ player->armortype = 2;
+ if (!player->backpack)
+ {
+ for (i = 0; i < NUMAMMO; i++)
+ {
+ player->maxammo[i] *= 2;
+ }
+ player->backpack = true;
+ }
+ for (i = 0; i < NUMWEAPONS - 1; i++)
+ {
+ player->weaponowned[i] = true;
+ }
+ if (gamemode == shareware)
+ {
+ player->weaponowned[wp_skullrod] = false;
+ player->weaponowned[wp_phoenixrod] = false;
+ player->weaponowned[wp_mace] = false;
+ }
+ for (i = 0; i < NUMAMMO; i++)
+ {
+ player->ammo[i] = player->maxammo[i];
+ }
+ P_SetMessage(player, DEH_String(TXT_CHEATWEAPONS), false);
+}
+
+static void CheatPowerFunc(player_t * player, Cheat_t * cheat)
+{
+ if (player->powers[pw_weaponlevel2])
+ {
+ player->powers[pw_weaponlevel2] = 0;
+ P_SetMessage(player, DEH_String(TXT_CHEATPOWEROFF), false);
+ }
+ else
+ {
+ P_UseArtifact(player, arti_tomeofpower);
+ P_SetMessage(player, DEH_String(TXT_CHEATPOWERON), false);
+ }
+}
+
+static void CheatHealthFunc(player_t * player, Cheat_t * cheat)
+{
+ if (player->chickenTics)
+ {
+ player->health = player->mo->health = MAXCHICKENHEALTH;
+ }
+ else
+ {
+ player->health = player->mo->health = MAXHEALTH;
+ }
+ P_SetMessage(player, DEH_String(TXT_CHEATHEALTH), false);
+}
+
+static void CheatKeysFunc(player_t * player, Cheat_t * cheat)
+{
+ player->keys[key_yellow] = true;
+ player->keys[key_green] = true;
+ player->keys[key_blue] = true;
+ playerkeys = 7; // Key refresh flags
+ P_SetMessage(player, DEH_String(TXT_CHEATKEYS), false);
+}
+
+static void CheatSoundFunc(player_t * player, Cheat_t * cheat)
+{
+ DebugSound = !DebugSound;
+ if (DebugSound)
+ {
+ P_SetMessage(player, DEH_String(TXT_CHEATSOUNDON), false);
+ }
+ else
+ {
+ P_SetMessage(player, DEH_String(TXT_CHEATSOUNDOFF), false);
+ }
+}
+
+static void CheatTickerFunc(player_t * player, Cheat_t * cheat)
+{
+ DisplayTicker = !DisplayTicker;
+ if (DisplayTicker)
+ {
+ P_SetMessage(player, DEH_String(TXT_CHEATTICKERON), false);
+ }
+ else
+ {
+ P_SetMessage(player, DEH_String(TXT_CHEATTICKEROFF), false);
+ }
+
+ I_DisplayFPSDots(DisplayTicker);
+}
+
+static void CheatArtifact1Func(player_t * player, Cheat_t * cheat)
+{
+ P_SetMessage(player, DEH_String(TXT_CHEATARTIFACTS1), false);
+}
+
+static void CheatArtifact2Func(player_t * player, Cheat_t * cheat)
+{
+ P_SetMessage(player, DEH_String(TXT_CHEATARTIFACTS2), false);
+}
+
+static void CheatArtifact3Func(player_t * player, Cheat_t * cheat)
+{
+ char args[2];
+ int i;
+ int j;
+ artitype_t type;
+ int count;
+
+ cht_GetParam(cheat->seq, args);
+ type = args[0] - 'a' + 1;
+ count = args[1] - '0';
+ if (type == 26 && count == 0)
+ { // All artifacts
+ for (i = arti_none + 1; i < NUMARTIFACTS; i++)
+ {
+ if (gamemode == shareware
+ && (i == arti_superhealth || i == arti_teleport))
+ {
+ continue;
+ }
+ for (j = 0; j < 16; j++)
+ {
+ P_GiveArtifact(player, i, NULL);
+ }
+ }
+ P_SetMessage(player, DEH_String(TXT_CHEATARTIFACTS3), false);
+ }
+ else if (type > arti_none && type < NUMARTIFACTS
+ && count > 0 && count < 10)
+ {
+ if (gamemode == shareware
+ && (type == arti_superhealth || type == arti_teleport))
+ {
+ P_SetMessage(player, DEH_String(TXT_CHEATARTIFACTSFAIL), false);
+ return;
+ }
+ for (i = 0; i < count; i++)
+ {
+ P_GiveArtifact(player, type, NULL);
+ }
+ P_SetMessage(player, DEH_String(TXT_CHEATARTIFACTS3), false);
+ }
+ else
+ { // Bad input
+ P_SetMessage(player, DEH_String(TXT_CHEATARTIFACTSFAIL), false);
+ }
+}
+
+static void CheatWarpFunc(player_t * player, Cheat_t * cheat)
+{
+ char args[2];
+ int episode;
+ int map;
+
+ cht_GetParam(cheat->seq, args);
+
+ episode = args[0] - '0';
+ map = args[1] - '0';
+ if (D_ValidEpisodeMap(gamemission, gamemode, episode, map))
+ {
+ G_DeferedInitNew(gameskill, episode, map);
+ P_SetMessage(player, DEH_String(TXT_CHEATWARP), false);
+ }
+}
+
+static void CheatChickenFunc(player_t * player, Cheat_t * cheat)
+{
+ extern boolean P_UndoPlayerChicken(player_t * player);
+
+ if (player->chickenTics)
+ {
+ if (P_UndoPlayerChicken(player))
+ {
+ P_SetMessage(player, DEH_String(TXT_CHEATCHICKENOFF), false);
+ }
+ }
+ else if (P_ChickenMorphPlayer(player))
+ {
+ P_SetMessage(player, DEH_String(TXT_CHEATCHICKENON), false);
+ }
+}
+
+static void CheatMassacreFunc(player_t * player, Cheat_t * cheat)
+{
+ P_Massacre();
+ P_SetMessage(player, DEH_String(TXT_CHEATMASSACRE), false);
+}
+
+static void CheatIDKFAFunc(player_t * player, Cheat_t * cheat)
+{
+ int i;
+ if (player->chickenTics)
+ {
+ return;
+ }
+ for (i = 1; i < 8; i++)
+ {
+ player->weaponowned[i] = false;
+ }
+ player->pendingweapon = wp_staff;
+ P_SetMessage(player, DEH_String(TXT_CHEATIDKFA), true);
+}
+
+static void CheatIDDQDFunc(player_t * player, Cheat_t * cheat)
+{
+ P_DamageMobj(player->mo, NULL, player->mo, 10000);
+ P_SetMessage(player, DEH_String(TXT_CHEATIDDQD), true);
+}
diff --git a/src/heretic/sounds.c b/src/heretic/sounds.c
new file mode 100644
index 00000000..f62110c6
--- /dev/null
+++ b/src/heretic/sounds.c
@@ -0,0 +1,257 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+// sounds.c
+
+#include "doomdef.h"
+#include "i_sound.h"
+#include "sounds.h"
+
+// Music info
+
+#define MUSIC(name) \
+ { name, 0, NULL, NULL }
+
+musicinfo_t S_music[] = {
+ MUSIC("MUS_E1M1"), // 1-1
+ MUSIC("MUS_E1M2"),
+ MUSIC("MUS_E1M3"),
+ MUSIC("MUS_E1M4"),
+ MUSIC("MUS_E1M5"),
+ MUSIC("MUS_E1M6"),
+ MUSIC("MUS_E1M7"),
+ MUSIC("MUS_E1M8"),
+ MUSIC("MUS_E1M9"),
+
+ MUSIC("MUS_E2M1"), // 2-1
+ MUSIC("MUS_E2M2"),
+ MUSIC("MUS_E2M3"),
+ MUSIC("MUS_E2M4"),
+ MUSIC("MUS_E1M4"),
+ MUSIC("MUS_E2M6"),
+ MUSIC("MUS_E2M7"),
+ MUSIC("MUS_E2M8"),
+ MUSIC("MUS_E2M9"),
+
+ MUSIC("MUS_E1M1"), // 3-1
+ MUSIC("MUS_E3M2"),
+ MUSIC("MUS_E3M3"),
+ MUSIC("MUS_E1M6"),
+ MUSIC("MUS_E1M3"),
+ MUSIC("MUS_E1M2"),
+ MUSIC("MUS_E1M5"),
+ MUSIC("MUS_E1M9"),
+ MUSIC("MUS_E2M6"),
+
+ MUSIC("MUS_E1M6"), // 4-1
+ MUSIC("MUS_E1M2"),
+ MUSIC("MUS_E1M3"),
+ MUSIC("MUS_E1M4"),
+ MUSIC("MUS_E1M5"),
+ MUSIC("MUS_E1M1"),
+ MUSIC("MUS_E1M7"),
+ MUSIC("MUS_E1M8"),
+ MUSIC("MUS_E1M9"),
+
+ MUSIC("MUS_E2M1"), // 5-1
+ MUSIC("MUS_E2M2"),
+ MUSIC("MUS_E2M3"),
+ MUSIC("MUS_E2M4"),
+ MUSIC("MUS_E1M4"),
+ MUSIC("MUS_E2M6"),
+ MUSIC("MUS_E2M7"),
+ MUSIC("MUS_E2M8"),
+ MUSIC("MUS_E2M9"),
+
+ MUSIC("MUS_E3M2"), // 6-1
+ MUSIC("MUS_E3M3"), // 6-2
+ MUSIC("MUS_E1M6"), // 6-3
+
+ MUSIC("MUS_TITL"),
+ MUSIC("MUS_INTR"),
+ MUSIC("MUS_CPTD")
+};
+
+// Sound info
+
+ /* Macro for original heretic sfxinfo_t
+#define SOUND(name, priority, numchannels) \
+ { name, NULL, priority, -1, NULL, 0, numchannels }
+#define SOUND_LINK(name, link_id, priority, numchannels) \
+ { name, &S_sfx[link_id], priority, -1, NULL, 0, numchannels }
+ */
+
+#define SOUND(name, priority, numchannels) \
+ { NULL, name, priority, NULL, -1, -1, -1, 0, numchannels, NULL }
+#define SOUND_LINK(name, link_id, priority, numchannels) \
+ { NULL, name, priority, &S_sfx[link_id], 0, 0, -1, 0, numchannels, NULL }
+
+sfxinfo_t S_sfx[] = {
+ SOUND("", 0, 0),
+ SOUND("gldhit", 32, 2),
+ SOUND("gntful", 32, -1),
+ SOUND("gnthit", 32, -1),
+ SOUND("gntpow", 32, -1),
+ SOUND("gntact", 32, -1),
+ SOUND("gntuse", 32, -1),
+ SOUND("phosht", 32, 2),
+ SOUND("phohit", 32, -1),
+ SOUND_LINK("-phopow", sfx_hedat1, 32, 1),
+ SOUND("lobsht", 20, 2),
+ SOUND("lobhit", 20, 2),
+ SOUND("lobpow", 20, 2),
+ SOUND("hrnsht", 32, 2),
+ SOUND("hrnhit", 32, 2),
+ SOUND("hrnpow", 32, 2),
+ SOUND("ramphit", 32, 2),
+ SOUND("ramrain", 10, 2),
+ SOUND("bowsht", 32, 2),
+ SOUND("stfhit", 32, 2),
+ SOUND("stfpow", 32, 2),
+ SOUND("stfcrk", 32, 2),
+ SOUND("impsit", 32, 2),
+ SOUND("impat1", 32, 2),
+ SOUND("impat2", 32, 2),
+ SOUND("impdth", 80, 2),
+ SOUND_LINK("-impact", sfx_impsit, 20, 2),
+ SOUND("imppai", 32, 2),
+ SOUND("mumsit", 32, 2),
+ SOUND("mumat1", 32, 2),
+ SOUND("mumat2", 32, 2),
+ SOUND("mumdth", 80, 2),
+ SOUND_LINK("-mumact", sfx_mumsit, 20, 2),
+ SOUND("mumpai", 32, 2),
+ SOUND("mumhed", 32, 2),
+ SOUND("bstsit", 32, 2),
+ SOUND("bstatk", 32, 2),
+ SOUND("bstdth", 80, 2),
+ SOUND("bstact", 20, 2),
+ SOUND("bstpai", 32, 2),
+ SOUND("clksit", 32, 2),
+ SOUND("clkatk", 32, 2),
+ SOUND("clkdth", 80, 2),
+ SOUND("clkact", 20, 2),
+ SOUND("clkpai", 32, 2),
+ SOUND("snksit", 32, 2),
+ SOUND("snkatk", 32, 2),
+ SOUND("snkdth", 80, 2),
+ SOUND("snkact", 20, 2),
+ SOUND("snkpai", 32, 2),
+ SOUND("kgtsit", 32, 2),
+ SOUND("kgtatk", 32, 2),
+ SOUND("kgtat2", 32, 2),
+ SOUND("kgtdth", 80, 2),
+ SOUND_LINK("-kgtact", sfx_kgtsit, 20, 2),
+ SOUND("kgtpai", 32, 2),
+ SOUND("wizsit", 32, 2),
+ SOUND("wizatk", 32, 2),
+ SOUND("wizdth", 80, 2),
+ SOUND("wizact", 20, 2),
+ SOUND("wizpai", 32, 2),
+ SOUND("minsit", 32, 2),
+ SOUND("minat1", 32, 2),
+ SOUND("minat2", 32, 2),
+ SOUND("minat3", 32, 2),
+ SOUND("mindth", 80, 2),
+ SOUND("minact", 20, 2),
+ SOUND("minpai", 32, 2),
+ SOUND("hedsit", 32, 2),
+ SOUND("hedat1", 32, 2),
+ SOUND("hedat2", 32, 2),
+ SOUND("hedat3", 32, 2),
+ SOUND("heddth", 80, 2),
+ SOUND("hedact", 20, 2),
+ SOUND("hedpai", 32, 2),
+ SOUND("sorzap", 32, 2),
+ SOUND("sorrise", 32, 2),
+ SOUND("sorsit", 200, 2),
+ SOUND("soratk", 32, 2),
+ SOUND("soract", 200, 2),
+ SOUND("sorpai", 200, 2),
+ SOUND("sordsph", 200, 2),
+ SOUND("sordexp", 200, 2),
+ SOUND("sordbon", 200, 2),
+ SOUND_LINK("-sbtsit", sfx_bstsit, 32, 2),
+ SOUND_LINK("-sbtatk", sfx_bstatk, 32, 2),
+ SOUND("sbtdth", 80, 2),
+ SOUND("sbtact", 20, 2),
+ SOUND("sbtpai", 32, 2),
+ SOUND("plroof", 32, 2),
+ SOUND("plrpai", 32, 2),
+ SOUND("plrdth", 80, 2),
+ SOUND("gibdth", 100, 2),
+ SOUND("plrwdth", 80, 2),
+ SOUND("plrcdth", 100, 2),
+ SOUND("itemup", 32, 2),
+ SOUND("wpnup", 32, 2),
+ SOUND("telept", 50, 2),
+ SOUND("doropn", 40, 2),
+ SOUND("dorcls", 40, 2),
+ SOUND("dormov", 40, 2),
+ SOUND("artiup", 32, 2),
+ SOUND("switch", 40, 2),
+ SOUND("pstart", 40, 2),
+ SOUND("pstop", 40, 2),
+ SOUND("stnmov", 40, 2),
+ SOUND("chicpai", 32, 2),
+ SOUND("chicatk", 32, 2),
+ SOUND("chicdth", 40, 2),
+ SOUND("chicact", 32, 2),
+ SOUND("chicpk1", 32, 2),
+ SOUND("chicpk2", 32, 2),
+ SOUND("chicpk3", 32, 2),
+ SOUND("keyup", 50, 2),
+ SOUND("ripslop", 16, 2),
+ SOUND("newpod", 16, -1),
+ SOUND("podexp", 40, -1),
+ SOUND("bounce", 16, 2),
+ SOUND_LINK("-volsht", sfx_bstatk, 16, 2),
+ SOUND_LINK("-volhit", sfx_lobhit, 16, 2),
+ SOUND("burn", 10, 2),
+ SOUND("splash", 10, 1),
+ SOUND("gloop", 10, 2),
+ SOUND("respawn", 10, 1),
+ SOUND("blssht", 32, 2),
+ SOUND("blshit", 32, 2),
+ SOUND("chat", 100, 1),
+ SOUND("artiuse", 32, 1),
+ SOUND("gfrag", 100, 1),
+ SOUND("waterfl", 16, 2),
+
+ // Monophonic sounds
+
+ SOUND("wind", 16, 1),
+ SOUND("amb1", 1, 1),
+ SOUND("amb2", 1, 1),
+ SOUND("amb3", 1, 1),
+ SOUND("amb4", 1, 1),
+ SOUND("amb5", 1, 1),
+ SOUND("amb6", 1, 1),
+ SOUND("amb7", 1, 1),
+ SOUND("amb8", 1, 1),
+ SOUND("amb9", 1, 1),
+ SOUND("amb10", 1, 1),
+ SOUND("amb11", 1, 0)
+};
diff --git a/src/heretic/sounds.h b/src/heretic/sounds.h
new file mode 100644
index 00000000..e50a6ad6
--- /dev/null
+++ b/src/heretic/sounds.h
@@ -0,0 +1,299 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// sounds.h
+
+#ifndef __SOUNDSH__
+#define __SOUNDSH__
+
+#include "i_sound.h"
+
+#define MAX_SND_DIST 1600
+#define MAX_CHANNELS 16
+
+// Music identifiers
+
+typedef enum
+{
+ mus_e1m1,
+ mus_e1m2,
+ mus_e1m3,
+ mus_e1m4,
+ mus_e1m5,
+ mus_e1m6,
+ mus_e1m7,
+ mus_e1m8,
+ mus_e1m9,
+
+ mus_e2m1,
+ mus_e2m2,
+ mus_e2m3,
+ mus_e2m4,
+ mus_e2m5,
+ mus_e2m6,
+ mus_e2m7,
+ mus_e2m8,
+ mus_e2m9,
+
+ mus_e3m1,
+ mus_e3m2,
+ mus_e3m3,
+ mus_e3m4,
+ mus_e3m5,
+ mus_e3m6,
+ mus_e3m7,
+ mus_e3m8,
+ mus_e3m9,
+
+ mus_e4m1,
+ mus_e4m2,
+ mus_e4m3,
+ mus_e4m4,
+ mus_e4m5,
+ mus_e4m6,
+ mus_e4m7,
+ mus_e4m8,
+ mus_e4m9,
+
+ mus_e5m1,
+ mus_e5m2,
+ mus_e5m3,
+ mus_e5m4,
+ mus_e5m5,
+ mus_e5m6,
+ mus_e5m7,
+ mus_e5m8,
+ mus_e5m9,
+
+ mus_e6m1,
+ mus_e6m2,
+ mus_e6m3,
+
+ mus_titl,
+ mus_intr,
+ mus_cptd,
+ NUMMUSIC
+} musicenum_t;
+
+#if 0
+typedef struct
+{
+ char name[8];
+} musicinfo_t;
+
+typedef struct sfxinfo_s
+{
+ char name[8];
+ struct sfxinfo_s *link; // Make alias for another sound
+ unsigned short priority; // Higher priority takes precendence
+ int usefulness; // Determines when a sound should be cached out
+ void *snd_ptr;
+ int lumpnum;
+ int numchannels; // total number of channels a sound type may occupy
+} sfxinfo_t;
+
+#endif
+
+typedef struct
+{
+ mobj_t *mo;
+ int sound_id;
+ int handle;
+ int pitch;
+ int priority;
+} channel_t;
+
+typedef struct
+{
+ int id;
+ unsigned short priority;
+ char *name;
+ mobj_t *mo;
+ int distance;
+} ChanInfo_t;
+
+typedef struct
+{
+ int channelCount;
+ int musicVolume;
+ int soundVolume;
+ ChanInfo_t chan[8];
+} SoundInfo_t;
+
+// Sound identifiers
+
+typedef enum
+{
+ sfx_None,
+ sfx_gldhit,
+ sfx_gntful,
+ sfx_gnthit,
+ sfx_gntpow,
+ sfx_gntact,
+ sfx_gntuse,
+ sfx_phosht,
+ sfx_phohit,
+ sfx_phopow,
+ sfx_lobsht,
+ sfx_lobhit,
+ sfx_lobpow,
+ sfx_hrnsht,
+ sfx_hrnhit,
+ sfx_hrnpow,
+ sfx_ramphit,
+ sfx_ramrain,
+ sfx_bowsht,
+ sfx_stfhit,
+ sfx_stfpow,
+ sfx_stfcrk,
+ sfx_impsit,
+ sfx_impat1,
+ sfx_impat2,
+ sfx_impdth,
+ sfx_impact,
+ sfx_imppai,
+ sfx_mumsit,
+ sfx_mumat1,
+ sfx_mumat2,
+ sfx_mumdth,
+ sfx_mumact,
+ sfx_mumpai,
+ sfx_mumhed,
+ sfx_bstsit,
+ sfx_bstatk,
+ sfx_bstdth,
+ sfx_bstact,
+ sfx_bstpai,
+ sfx_clksit,
+ sfx_clkatk,
+ sfx_clkdth,
+ sfx_clkact,
+ sfx_clkpai,
+ sfx_snksit,
+ sfx_snkatk,
+ sfx_snkdth,
+ sfx_snkact,
+ sfx_snkpai,
+ sfx_kgtsit,
+ sfx_kgtatk,
+ sfx_kgtat2,
+ sfx_kgtdth,
+ sfx_kgtact,
+ sfx_kgtpai,
+ sfx_wizsit,
+ sfx_wizatk,
+ sfx_wizdth,
+ sfx_wizact,
+ sfx_wizpai,
+ sfx_minsit,
+ sfx_minat1,
+ sfx_minat2,
+ sfx_minat3,
+ sfx_mindth,
+ sfx_minact,
+ sfx_minpai,
+ sfx_hedsit,
+ sfx_hedat1,
+ sfx_hedat2,
+ sfx_hedat3,
+ sfx_heddth,
+ sfx_hedact,
+ sfx_hedpai,
+ sfx_sorzap,
+ sfx_sorrise,
+ sfx_sorsit,
+ sfx_soratk,
+ sfx_soract,
+ sfx_sorpai,
+ sfx_sordsph,
+ sfx_sordexp,
+ sfx_sordbon,
+ sfx_sbtsit,
+ sfx_sbtatk,
+ sfx_sbtdth,
+ sfx_sbtact,
+ sfx_sbtpai,
+ sfx_plroof,
+ sfx_plrpai,
+ sfx_plrdth, // Normal
+ sfx_gibdth, // Extreme
+ sfx_plrwdth, // Wimpy
+ sfx_plrcdth, // Crazy
+ sfx_itemup,
+ sfx_wpnup,
+ sfx_telept,
+ sfx_doropn,
+ sfx_dorcls,
+ sfx_dormov,
+ sfx_artiup,
+ sfx_switch,
+ sfx_pstart,
+ sfx_pstop,
+ sfx_stnmov,
+ sfx_chicpai,
+ sfx_chicatk,
+ sfx_chicdth,
+ sfx_chicact,
+ sfx_chicpk1,
+ sfx_chicpk2,
+ sfx_chicpk3,
+ sfx_keyup,
+ sfx_ripslop,
+ sfx_newpod,
+ sfx_podexp,
+ sfx_bounce,
+ sfx_volsht,
+ sfx_volhit,
+ sfx_burn,
+ sfx_splash,
+ sfx_gloop,
+ sfx_respawn,
+ sfx_blssht,
+ sfx_blshit,
+ sfx_chat,
+ sfx_artiuse,
+ sfx_gfrag,
+ sfx_waterfl,
+
+ // Monophonic sounds
+
+ sfx_wind,
+ sfx_amb1,
+ sfx_amb2,
+ sfx_amb3,
+ sfx_amb4,
+ sfx_amb5,
+ sfx_amb6,
+ sfx_amb7,
+ sfx_amb8,
+ sfx_amb9,
+ sfx_amb10,
+ sfx_amb11,
+ NUMSFX
+} sfxenum_t;
+
+extern sfxinfo_t S_sfx[];
+extern musicinfo_t S_music[];
+
+#endif
diff --git a/src/hexen/.gitignore b/src/hexen/.gitignore
new file mode 100644
index 00000000..d4e88e5a
--- /dev/null
+++ b/src/hexen/.gitignore
@@ -0,0 +1,5 @@
+Makefile
+Makefile.in
+.deps
+tags
+TAGS
diff --git a/src/hexen/Makefile.am b/src/hexen/Makefile.am
new file mode 100644
index 00000000..e8ca8b98
--- /dev/null
+++ b/src/hexen/Makefile.am
@@ -0,0 +1,67 @@
+AM_CFLAGS=-I.. @SDL_CFLAGS@ @SDLMIXER_CFLAGS@ @SDLNET_CFLAGS@
+
+noinst_LIBRARIES=libhexen.a
+
+SOURCE_FILES= \
+a_action.c \
+ am_data.h \
+am_map.c am_map.h \
+ct_chat.c \
+ ct_chat.h \
+d_net.c \
+f_finale.c \
+g_game.c \
+ h2def.h \
+h2_main.c \
+ i_header.h \
+info.c info.h \
+in_lude.c \
+m_misc.c \
+m_random.c m_random.h \
+mn_menu.c \
+p_acs.c \
+p_anim.c \
+p_ceilng.c \
+p_doors.c \
+p_enemy.c \
+p_floor.c \
+p_inter.c \
+p_lights.c \
+ p_local.h \
+p_map.c \
+p_maputl.c \
+p_mobj.c \
+po_man.c \
+p_plats.c \
+p_pspr.c \
+p_setup.c \
+p_sight.c \
+p_spec.c p_spec.h \
+p_switch.c \
+p_telept.c \
+p_things.c \
+p_tick.c \
+p_user.c \
+r_bsp.c \
+r_data.c \
+r_draw.c \
+ r_local.h \
+r_main.c \
+r_plane.c \
+r_segs.c \
+r_things.c \
+s_sound.c s_sound.h \
+sb_bar.c \
+sc_man.c \
+sn_sonix.c \
+sounds.c sounds.h \
+st_start.c st_start.h \
+sv_save.c \
+ textdefs.h \
+ xddefs.h
+
+EXTRA_DIST= \
+i_ibm.c \
+i_sound.c
+
+libhexen_a_SOURCES=$(SOURCE_FILES)
diff --git a/src/hexen/a_action.c b/src/hexen/a_action.c
new file mode 100644
index 00000000..af727480
--- /dev/null
+++ b/src/hexen/a_action.c
@@ -0,0 +1,1349 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2def.h"
+#include "m_random.h"
+#include "p_local.h"
+#include "s_sound.h"
+
+// MACROS ------------------------------------------------------------------
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+extern fixed_t FloatBobOffsets[64];
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+int orbitTableX[256] = {
+ 983025, 982725, 981825, 980340, 978255, 975600, 972330, 968490,
+ 964065, 959070, 953475, 947325, 940590, 933300, 925440, 917025,
+ 908055, 898545, 888495, 877905, 866775, 855135, 842985, 830310,
+ 817155, 803490, 789360, 774735, 759660, 744120, 728130, 711690,
+ 694845, 677565, 659880, 641805, 623340, 604500, 585285, 565725,
+ 545820, 525600, 505050, 484200, 463065, 441645, 419955, 398010,
+ 375840, 353430, 330810, 307995, 285000, 261825, 238485, 215010,
+ 191400, 167685, 143865, 119955, 95970, 71940, 47850, 23745,
+ -375, -24495, -48600, -72690, -96720, -120705, -144600, -168420,
+ -192150, -215745, -239220, -262545, -285720, -308715, -331530, -354135,
+ -376530, -398700, -420630, -442320, -463725, -484860, -505695, -526230,
+ -546450, -566340, -585885, -605085, -623925, -642375, -660435, -678105,
+ -695370, -712215, -728625, -744600, -760125, -775200, -789795, -803925,
+ -817575, -830715, -843375, -855510, -867135, -878235, -888810, -898845,
+ -908340, -917295, -925695, -933540, -940815, -947520, -953670, -959235,
+ -964215, -968625, -972450, -975690, -978330, -980400, -981870, -982740,
+ -983025, -982725, -981825, -980340, -978255, -975600, -972330, -968490,
+ -964065, -959070, -953475, -947325, -940590, -933300, -925440, -917025,
+ -908055, -898545, -888495, -877905, -866775, -855135, -842985, -830310,
+ -817155, -803490, -789360, -774735, -759660, -744120, -728130, -711690,
+ -694845, -677565, -659880, -641805, -623340, -604485, -585285, -565725,
+ -545820, -525600, -505050, -484200, -463065, -441645, -419955, -398010,
+ -375840, -353430, -330810, -307995, -285000, -261825, -238485, -215010,
+ -191400, -167685, -143865, -119955, -95970, -71940, -47850, -23745,
+ 375, 24495, 48600, 72690, 96720, 120705, 144600, 168420,
+ 192150, 215745, 239220, 262545, 285720, 308715, 331530, 354135,
+ 376530, 398700, 420630, 442320, 463725, 484860, 505695, 526230,
+ 546450, 566340, 585885, 605085, 623925, 642375, 660435, 678105,
+ 695370, 712215, 728625, 744600, 760125, 775200, 789795, 803925,
+ 817575, 830715, 843375, 855510, 867135, 878235, 888810, 898845,
+ 908340, 917295, 925695, 933540, 940815, 947520, 953670, 959235,
+ 964215, 968625, 972450, 975690, 978330, 980400, 981870, 982740
+};
+
+int orbitTableY[256] = {
+ 375, 24495, 48600, 72690, 96720, 120705, 144600, 168420,
+ 192150, 215745, 239220, 262545, 285720, 308715, 331530, 354135,
+ 376530, 398700, 420630, 442320, 463725, 484860, 505695, 526230,
+ 546450, 566340, 585885, 605085, 623925, 642375, 660435, 678105,
+ 695370, 712215, 728625, 744600, 760125, 775200, 789795, 803925,
+ 817575, 830715, 843375, 855510, 867135, 878235, 888810, 898845,
+ 908340, 917295, 925695, 933540, 940815, 947520, 953670, 959235,
+ 964215, 968625, 972450, 975690, 978330, 980400, 981870, 982740,
+ 983025, 982725, 981825, 980340, 978255, 975600, 972330, 968490,
+ 964065, 959070, 953475, 947325, 940590, 933300, 925440, 917025,
+ 908055, 898545, 888495, 877905, 866775, 855135, 842985, 830310,
+ 817155, 803490, 789360, 774735, 759660, 744120, 728130, 711690,
+ 694845, 677565, 659880, 641805, 623340, 604500, 585285, 565725,
+ 545820, 525600, 505050, 484200, 463065, 441645, 419955, 398010,
+ 375840, 353430, 330810, 307995, 285000, 261825, 238485, 215010,
+ 191400, 167685, 143865, 119955, 95970, 71940, 47850, 23745,
+ -375, -24495, -48600, -72690, -96720, -120705, -144600, -168420,
+ -192150, -215745, -239220, -262545, -285720, -308715, -331530, -354135,
+ -376530, -398700, -420630, -442320, -463725, -484860, -505695, -526230,
+ -546450, -566340, -585885, -605085, -623925, -642375, -660435, -678105,
+ -695370, -712215, -728625, -744600, -760125, -775200, -789795, -803925,
+ -817575, -830715, -843375, -855510, -867135, -878235, -888810, -898845,
+ -908340, -917295, -925695, -933540, -940815, -947520, -953670, -959235,
+ -964215, -968625, -972450, -975690, -978330, -980400, -981870, -982740,
+ -983025, -982725, -981825, -980340, -978255, -975600, -972330, -968490,
+ -964065, -959070, -953475, -947325, -940590, -933300, -925440, -917025,
+ -908055, -898545, -888495, -877905, -866775, -855135, -842985, -830310,
+ -817155, -803490, -789360, -774735, -759660, -744120, -728130, -711690,
+ -694845, -677565, -659880, -641805, -623340, -604485, -585285, -565725,
+ -545820, -525600, -505050, -484200, -463065, -441645, -419955, -398010,
+ -375840, -353430, -330810, -307995, -285000, -261825, -238485, -215010,
+ -191400, -167685, -143865, -119955, -95970, -71940, -47850, -23745
+};
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+// CODE --------------------------------------------------------------------
+
+//--------------------------------------------------------------------------
+//
+// Environmental Action routines
+//
+//--------------------------------------------------------------------------
+
+//==========================================================================
+//
+// A_DripBlood
+//
+//==========================================================================
+
+/*
+void A_DripBlood(mobj_t *actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x+((P_Random()-P_Random())<<11),
+ actor->y+((P_Random()-P_Random())<<11), actor->z, MT_BLOOD);
+ mo->momx = (P_Random()-P_Random())<<10;
+ mo->momy = (P_Random()-P_Random())<<10;
+ mo->flags2 |= MF2_LOGRAV;
+}
+*/
+
+//============================================================================
+//
+// A_PotteryExplode
+//
+//============================================================================
+
+void A_PotteryExplode(mobj_t * actor)
+{
+ mobj_t *mo = NULL;
+ int i;
+
+ for (i = (P_Random() & 3) + 3; i; i--)
+ {
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_POTTERYBIT1);
+ P_SetMobjState(mo, mo->info->spawnstate + (P_Random() % 5));
+ if (mo)
+ {
+ mo->momz = ((P_Random() & 7) + 5) * (3 * FRACUNIT / 4);
+ mo->momx = (P_Random() - P_Random()) << (FRACBITS - 6);
+ mo->momy = (P_Random() - P_Random()) << (FRACBITS - 6);
+ }
+ }
+ S_StartSound(mo, SFX_POTTERY_EXPLODE);
+ if (actor->args[0])
+ { // Spawn an item
+ if (!nomonsters
+ || !(mobjinfo[TranslateThingType[actor->args[0]]].
+ flags & MF_COUNTKILL))
+ { // Only spawn monsters if not -nomonsters
+ P_SpawnMobj(actor->x, actor->y, actor->z,
+ TranslateThingType[actor->args[0]]);
+ }
+ }
+ P_RemoveMobj(actor);
+}
+
+//============================================================================
+//
+// A_PotteryChooseBit
+//
+//============================================================================
+
+void A_PotteryChooseBit(mobj_t * actor)
+{
+ P_SetMobjState(actor, actor->info->deathstate + (P_Random() % 5) + 1);
+ actor->tics = 256 + (P_Random() << 1);
+}
+
+//============================================================================
+//
+// A_PotteryCheck
+//
+//============================================================================
+
+void A_PotteryCheck(mobj_t * actor)
+{
+ int i;
+ mobj_t *pmo;
+
+ if (!netgame)
+ {
+ pmo = players[consoleplayer].mo;
+ if (P_CheckSight(actor, pmo) && (abs(R_PointToAngle2(pmo->x,
+ pmo->y, actor->x,
+ actor->y) -
+ pmo->angle) <= ANG45))
+ { // Previous state (pottery bit waiting state)
+ P_SetMobjState(actor, actor->state - &states[0] - 1);
+ }
+ else
+ {
+ return;
+ }
+ }
+ else
+ {
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (!playeringame[i])
+ {
+ continue;
+ }
+ pmo = players[i].mo;
+ if (P_CheckSight(actor, pmo) && (abs(R_PointToAngle2(pmo->x,
+ pmo->y,
+ actor->x,
+ actor->y) -
+ pmo->angle) <= ANG45))
+ { // Previous state (pottery bit waiting state)
+ P_SetMobjState(actor, actor->state - &states[0] - 1);
+ return;
+ }
+ }
+ }
+}
+
+//============================================================================
+//
+// A_CorpseBloodDrip
+//
+//============================================================================
+
+void A_CorpseBloodDrip(mobj_t * actor)
+{
+ if (P_Random() > 128)
+ {
+ return;
+ }
+ P_SpawnMobj(actor->x, actor->y, actor->z + actor->height / 2,
+ MT_CORPSEBLOODDRIP);
+}
+
+//============================================================================
+//
+// A_CorpseExplode
+//
+//============================================================================
+
+void A_CorpseExplode(mobj_t * actor)
+{
+ mobj_t *mo;
+ int i;
+
+ for (i = (P_Random() & 3) + 3; i; i--)
+ {
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_CORPSEBIT);
+ P_SetMobjState(mo, mo->info->spawnstate + (P_Random() % 3));
+ if (mo)
+ {
+ mo->momz = ((P_Random() & 7) + 5) * (3 * FRACUNIT / 4);
+ mo->momx = (P_Random() - P_Random()) << (FRACBITS - 6);
+ mo->momy = (P_Random() - P_Random()) << (FRACBITS - 6);
+ }
+ }
+ // Spawn a skull
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_CORPSEBIT);
+ P_SetMobjState(mo, S_CORPSEBIT_4);
+ if (mo)
+ {
+ mo->momz = ((P_Random() & 7) + 5) * (3 * FRACUNIT / 4);
+ mo->momx = (P_Random() - P_Random()) << (FRACBITS - 6);
+ mo->momy = (P_Random() - P_Random()) << (FRACBITS - 6);
+ S_StartSound(mo, SFX_FIRED_DEATH);
+ }
+ P_RemoveMobj(actor);
+}
+
+//============================================================================
+//
+// A_LeafSpawn
+//
+//============================================================================
+
+void A_LeafSpawn(mobj_t * actor)
+{
+ mobj_t *mo;
+ int i;
+
+ for (i = (P_Random() & 3) + 1; i; i--)
+ {
+ mo = P_SpawnMobj(actor->x + ((P_Random() - P_Random()) << 14),
+ actor->y + ((P_Random() - P_Random()) << 14),
+ actor->z + (P_Random() << 14),
+ MT_LEAF1 + (P_Random() & 1));
+ if (mo)
+ {
+ P_ThrustMobj(mo, actor->angle, (P_Random() << 9) + 3 * FRACUNIT);
+ mo->target = actor;
+ mo->special1.i = 0;
+ }
+ }
+}
+
+//============================================================================
+//
+// A_LeafThrust
+//
+//============================================================================
+
+void A_LeafThrust(mobj_t * actor)
+{
+ if (P_Random() > 96)
+ {
+ return;
+ }
+ actor->momz += (P_Random() << 9) + FRACUNIT;
+}
+
+//============================================================================
+//
+// A_LeafCheck
+//
+//============================================================================
+
+void A_LeafCheck(mobj_t * actor)
+{
+ actor->special1.i++;
+ if (actor->special1.i >= 20)
+ {
+ P_SetMobjState(actor, S_NULL);
+ return;
+ }
+ if (P_Random() > 64)
+ {
+ if (!actor->momx && !actor->momy)
+ {
+ P_ThrustMobj(actor, actor->target->angle,
+ (P_Random() << 9) + FRACUNIT);
+ }
+ return;
+ }
+ P_SetMobjState(actor, S_LEAF1_8);
+ actor->momz = (P_Random() << 9) + FRACUNIT;
+ P_ThrustMobj(actor, actor->target->angle,
+ (P_Random() << 9) + 2 * FRACUNIT);
+ actor->flags |= MF_MISSILE;
+}
+
+/*
+#define ORBIT_RADIUS (15*FRACUNIT)
+void GenerateOrbitTable(void)
+{
+ int angle;
+
+ for (angle=0; angle<256; angle++)
+ {
+ orbitTableX[angle] = FixedMul(ORBIT_RADIUS, finecosine[angle<<5]);
+ orbitTableY[angle] = FixedMul(ORBIT_RADIUS, finesine[angle<<5]);
+ }
+
+ printf("int orbitTableX[256]=\n{\n");
+ for (angle=0; angle<256; angle+=8)
+ {
+ printf("%d, %d, %d, %d, %d, %d, %d, %d,\n",
+ orbitTableX[angle],
+ orbitTableX[angle+1],
+ orbitTableX[angle+2],
+ orbitTableX[angle+3],
+ orbitTableX[angle+4],
+ orbitTableX[angle+5],
+ orbitTableX[angle+6],
+ orbitTableX[angle+7]);
+ }
+ printf("};\n\n");
+
+ printf("int orbitTableY[256]=\n{\n");
+ for (angle=0; angle<256; angle+=8)
+ {
+ printf("%d, %d, %d, %d, %d, %d, %d, %d,\n",
+ orbitTableY[angle],
+ orbitTableY[angle+1],
+ orbitTableY[angle+2],
+ orbitTableY[angle+3],
+ orbitTableY[angle+4],
+ orbitTableY[angle+5],
+ orbitTableY[angle+6],
+ orbitTableY[angle+7]);
+ }
+ printf("};\n");
+}
+*/
+
+// New bridge stuff
+// Parent
+// special1 true == removing from world
+//
+// Child
+// target pointer to center mobj
+// args[0] angle of ball
+
+void A_BridgeOrbit(mobj_t * actor)
+{
+ if (actor->target->special1.i)
+ {
+ P_SetMobjState(actor, S_NULL);
+ }
+ actor->args[0] += 3;
+ actor->x = actor->target->x + orbitTableX[actor->args[0]];
+ actor->y = actor->target->y + orbitTableY[actor->args[0]];
+ actor->z = actor->target->z;
+}
+
+
+void A_BridgeInit(mobj_t * actor)
+{
+ byte startangle;
+ mobj_t *ball1, *ball2, *ball3;
+ fixed_t cx, cy, cz;
+
+// GenerateOrbitTable();
+
+ cx = actor->x;
+ cy = actor->y;
+ cz = actor->z;
+ startangle = P_Random();
+ actor->special1.i = 0;
+
+ // Spawn triad into world
+ ball1 = P_SpawnMobj(cx, cy, cz, MT_BRIDGEBALL);
+ ball1->args[0] = startangle;
+ ball1->target = actor;
+
+ ball2 = P_SpawnMobj(cx, cy, cz, MT_BRIDGEBALL);
+ ball2->args[0] = (startangle + 85) & 255;
+ ball2->target = actor;
+
+ ball3 = P_SpawnMobj(cx, cy, cz, MT_BRIDGEBALL);
+ ball3->args[0] = (startangle + 170) & 255;
+ ball3->target = actor;
+
+ A_BridgeOrbit(ball1);
+ A_BridgeOrbit(ball2);
+ A_BridgeOrbit(ball3);
+}
+
+void A_BridgeRemove(mobj_t * actor)
+{
+ actor->special1.i = true; // Removing the bridge
+ actor->flags &= ~MF_SOLID;
+ P_SetMobjState(actor, S_FREE_BRIDGE1);
+}
+
+
+//==========================================================================
+//
+// A_GhostOn
+//
+//==========================================================================
+
+/*
+void A_GhostOn(mobj_t *actor)
+{
+ actor->flags |= MF_SHADOW;
+}
+*/
+
+//==========================================================================
+//
+// A_GhostOff
+//
+//==========================================================================
+
+/*
+void A_GhostOff(mobj_t *actor)
+{
+ actor->flags &= ~MF_SHADOW;
+}
+*/
+
+//==========================================================================
+//
+// A_HideThing
+//
+//==========================================================================
+
+void A_HideThing(mobj_t * actor)
+{
+ actor->flags2 |= MF2_DONTDRAW;
+}
+
+//==========================================================================
+//
+// A_UnHideThing
+//
+//==========================================================================
+
+void A_UnHideThing(mobj_t * actor)
+{
+ actor->flags2 &= ~MF2_DONTDRAW;
+}
+
+//==========================================================================
+//
+// A_SetShootable
+//
+//==========================================================================
+
+void A_SetShootable(mobj_t * actor)
+{
+ actor->flags2 &= ~MF2_NONSHOOTABLE;
+ actor->flags |= MF_SHOOTABLE;
+}
+
+//==========================================================================
+//
+// A_UnSetShootable
+//
+//==========================================================================
+
+void A_UnSetShootable(mobj_t * actor)
+{
+ actor->flags2 |= MF2_NONSHOOTABLE;
+ actor->flags &= ~MF_SHOOTABLE;
+}
+
+//==========================================================================
+//
+// A_SetAltShadow
+//
+//==========================================================================
+
+void A_SetAltShadow(mobj_t * actor)
+{
+ actor->flags &= ~MF_SHADOW;
+ actor->flags |= MF_ALTSHADOW;
+}
+
+//==========================================================================
+//
+// A_UnSetAltShadow
+//
+//==========================================================================
+
+/*
+void A_UnSetAltShadow(mobj_t *actor)
+{
+ actor->flags &= ~MF_ALTSHADOW;
+}
+*/
+
+//--------------------------------------------------------------------------
+//
+// Sound Action Routines
+//
+//--------------------------------------------------------------------------
+
+//==========================================================================
+//
+// A_ContMobjSound
+//
+//==========================================================================
+
+void A_ContMobjSound(mobj_t * actor)
+{
+ switch (actor->type)
+ {
+ case MT_SERPENTFX:
+ S_StartSound(actor, SFX_SERPENTFX_CONTINUOUS);
+ break;
+ case MT_HAMMER_MISSILE:
+ S_StartSound(actor, SFX_FIGHTER_HAMMER_CONTINUOUS);
+ break;
+ case MT_QUAKE_FOCUS:
+ S_StartSound(actor, SFX_EARTHQUAKE);
+ break;
+ default:
+ break;
+ }
+}
+
+//==========================================================================
+//
+// PROC A_ESound
+//
+//==========================================================================
+
+void A_ESound(mobj_t * mo)
+{
+ int sound;
+
+ switch (mo->type)
+ {
+ case MT_SOUNDWIND:
+ sound = SFX_WIND;
+ break;
+ default:
+ sound = SFX_NONE;
+ break;
+ }
+ S_StartSound(mo, sound);
+}
+
+
+
+//==========================================================================
+// Summon Minotaur -- see p_enemy for variable descriptions
+//==========================================================================
+
+
+void A_Summon(mobj_t * actor)
+{
+ mobj_t *mo;
+ mobj_t *master;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_MINOTAUR);
+ if (mo)
+ {
+ if (P_TestMobjLocation(mo) == false || !actor->special1.m)
+ { // Didn't fit - change back to artifact
+ P_SetMobjState(mo, S_NULL);
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SUMMONMAULATOR);
+ if (mo)
+ mo->flags2 |= MF2_DROPPED;
+ return;
+ }
+
+ memcpy((void *) mo->args, &leveltime, sizeof(leveltime));
+ master = actor->special1.m;
+ if (master->flags & MF_CORPSE)
+ { // Master dead
+ mo->special1.m = NULL; // No master
+ }
+ else
+ {
+ mo->special1.m = actor->special1.m; // Pointer to master (mobj_t *)
+ P_GivePower(master->player, pw_minotaur);
+ }
+
+ // Make smoke puff
+ P_SpawnMobj(actor->x, actor->y, actor->z, MT_MNTRSMOKE);
+ S_StartSound(actor, SFX_MAULATOR_ACTIVE);
+ }
+}
+
+
+
+//==========================================================================
+// Fog Variables:
+//
+// args[0] Speed (0..10) of fog
+// args[1] Angle of spread (0..128)
+// args[2] Frequency of spawn (1..10)
+// args[3] Lifetime countdown
+// args[4] Boolean: fog moving?
+// special1 Internal: Counter for spawn frequency
+// special2 Internal: Index into floatbob table
+//
+//==========================================================================
+
+void A_FogSpawn(mobj_t * actor)
+{
+ mobj_t *mo = NULL;
+ angle_t delta;
+
+ if (actor->special1.i-- > 0)
+ return;
+
+ actor->special1.i = actor->args[2]; // Reset frequency count
+
+ switch (P_Random() % 3)
+ {
+ case 0:
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FOGPATCHS);
+ break;
+ case 1:
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FOGPATCHM);
+ break;
+ case 2:
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FOGPATCHL);
+ break;
+ }
+
+ if (mo)
+ {
+ delta = actor->args[1];
+ if (delta == 0)
+ delta = 1;
+ mo->angle =
+ actor->angle + (((P_Random() % delta) - (delta >> 1)) << 24);
+ mo->target = actor;
+ if (actor->args[0] < 1)
+ actor->args[0] = 1;
+ mo->args[0] = (P_Random() % (actor->args[0])) + 1; // Random speed
+ mo->args[3] = actor->args[3]; // Set lifetime
+ mo->args[4] = 1; // Set to moving
+ mo->special2.i = P_Random() & 63;
+ }
+}
+
+
+void A_FogMove(mobj_t * actor)
+{
+ int speed = actor->args[0] << FRACBITS;
+ angle_t angle;
+ int weaveindex;
+
+ if (!(actor->args[4]))
+ return;
+
+ if (actor->args[3]-- <= 0)
+ {
+ P_SetMobjStateNF(actor, actor->info->deathstate);
+ return;
+ }
+
+ if ((actor->args[3] % 4) == 0)
+ {
+ weaveindex = actor->special2.i;
+ actor->z += FloatBobOffsets[weaveindex] >> 1;
+ actor->special2.i = (weaveindex + 1) & 63;
+ }
+
+ angle = actor->angle >> ANGLETOFINESHIFT;
+ actor->momx = FixedMul(speed, finecosine[angle]);
+ actor->momy = FixedMul(speed, finesine[angle]);
+}
+
+//===========================================================================
+//
+// A_PoisonBagInit
+//
+//===========================================================================
+
+void A_PoisonBagInit(mobj_t * actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 28 * FRACUNIT,
+ MT_POISONCLOUD);
+ if (!mo)
+ {
+ return;
+ }
+ mo->momx = 1; // missile objects must move to impact other objects
+ mo->special1.i = 24 + (P_Random() & 7);
+ mo->special2.i = 0;
+ mo->target = actor->target;
+ mo->radius = 20 * FRACUNIT;
+ mo->height = 30 * FRACUNIT;
+ mo->flags &= ~MF_NOCLIP;
+}
+
+//===========================================================================
+//
+// A_PoisonBagCheck
+//
+//===========================================================================
+
+void A_PoisonBagCheck(mobj_t * actor)
+{
+ if (!--actor->special1.i)
+ {
+ P_SetMobjState(actor, S_POISONCLOUD_X1);
+ }
+ else
+ {
+ return;
+ }
+}
+
+//===========================================================================
+//
+// A_PoisonBagDamage
+//
+//===========================================================================
+
+void A_PoisonBagDamage(mobj_t * actor)
+{
+ int bobIndex;
+
+ extern void A_Explode(mobj_t * actor);
+
+ A_Explode(actor);
+
+ bobIndex = actor->special2.i;
+ actor->z += FloatBobOffsets[bobIndex] >> 4;
+ actor->special2.i = (bobIndex + 1) & 63;
+}
+
+//===========================================================================
+//
+// A_PoisonShroom
+//
+//===========================================================================
+
+void A_PoisonShroom(mobj_t * actor)
+{
+ actor->tics = 128 + (P_Random() << 1);
+}
+
+//===========================================================================
+//
+// A_CheckThrowBomb
+//
+//===========================================================================
+
+void A_CheckThrowBomb(mobj_t * actor)
+{
+ if (abs(actor->momx) < 1.5 * FRACUNIT && abs(actor->momy) < 1.5 * FRACUNIT
+ && actor->momz < 2 * FRACUNIT
+ && actor->state == &states[S_THROWINGBOMB6])
+ {
+ P_SetMobjState(actor, S_THROWINGBOMB7);
+ actor->z = actor->floorz;
+ actor->momz = 0;
+ actor->flags2 &= ~MF2_FLOORBOUNCE;
+ actor->flags &= ~MF_MISSILE;
+ }
+ if (!--actor->health)
+ {
+ P_SetMobjState(actor, actor->info->deathstate);
+ }
+}
+
+//===========================================================================
+// Quake variables
+//
+// args[0] Intensity on richter scale (2..9)
+// args[1] Duration in tics
+// args[2] Radius for damage
+// args[3] Radius for tremor
+// args[4] TID of map thing for focus of quake
+//
+//===========================================================================
+
+//===========================================================================
+//
+// A_LocalQuake
+//
+//===========================================================================
+
+boolean A_LocalQuake(byte * args, mobj_t * actor)
+{
+ mobj_t *focus, *target;
+ int lastfound = 0;
+ int success = false;
+
+ actor = actor; // suppress warning
+
+ // Find all quake foci
+ do
+ {
+ target = P_FindMobjFromTID(args[4], &lastfound);
+ if (target)
+ {
+ focus = P_SpawnMobj(target->x,
+ target->y, target->z, MT_QUAKE_FOCUS);
+ if (focus)
+ {
+ focus->args[0] = args[0];
+ focus->args[1] = args[1] >> 1; // decremented every 2 tics
+ focus->args[2] = args[2];
+ focus->args[3] = args[3];
+ focus->args[4] = args[4];
+ success = true;
+ }
+ }
+ }
+ while (target != NULL);
+
+ return (success);
+}
+
+
+//===========================================================================
+//
+// A_Quake
+//
+//===========================================================================
+int localQuakeHappening[MAXPLAYERS];
+
+void A_Quake(mobj_t * actor)
+{
+ angle_t an;
+ player_t *player;
+ mobj_t *victim;
+ int richters = actor->args[0];
+ int playnum;
+ fixed_t dist;
+
+ if (actor->args[1]-- > 0)
+ {
+ for (playnum = 0; playnum < MAXPLAYERS; playnum++)
+ {
+ player = &players[playnum];
+ if (!playeringame[playnum])
+ continue;
+
+ victim = player->mo;
+ dist = P_AproxDistance(actor->x - victim->x,
+ actor->y - victim->y) >> (FRACBITS + 6);
+ // Tested in tile units (64 pixels)
+ if (dist < actor->args[3]) // In tremor radius
+ {
+ localQuakeHappening[playnum] = richters;
+ }
+ // Check if in damage radius
+ if ((dist < actor->args[2]) && (victim->z <= victim->floorz))
+ {
+ if (P_Random() < 50)
+ {
+ P_DamageMobj(victim, NULL, NULL, HITDICE(1));
+ }
+ // Thrust player around
+ an = victim->angle + ANG1 * P_Random();
+ P_ThrustMobj(victim, an, richters << (FRACBITS - 1));
+ }
+ }
+ }
+ else
+ {
+ for (playnum = 0; playnum < MAXPLAYERS; playnum++)
+ {
+ localQuakeHappening[playnum] = false;
+ }
+ P_SetMobjState(actor, S_NULL);
+ }
+}
+
+
+
+
+//===========================================================================
+//
+// Teleport other stuff
+//
+//===========================================================================
+
+#define TELEPORT_LIFE 1
+
+void A_TeloSpawnA(mobj_t * actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_TELOTHER_FX2);
+ if (mo)
+ {
+ mo->special1.i = TELEPORT_LIFE; // Lifetime countdown
+ mo->angle = actor->angle;
+ mo->target = actor->target;
+ mo->momx = actor->momx >> 1;
+ mo->momy = actor->momy >> 1;
+ mo->momz = actor->momz >> 1;
+ }
+}
+
+void A_TeloSpawnB(mobj_t * actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_TELOTHER_FX3);
+ if (mo)
+ {
+ mo->special1.i = TELEPORT_LIFE; // Lifetime countdown
+ mo->angle = actor->angle;
+ mo->target = actor->target;
+ mo->momx = actor->momx >> 1;
+ mo->momy = actor->momy >> 1;
+ mo->momz = actor->momz >> 1;
+ }
+}
+
+void A_TeloSpawnC(mobj_t * actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_TELOTHER_FX4);
+ if (mo)
+ {
+ mo->special1.i = TELEPORT_LIFE; // Lifetime countdown
+ mo->angle = actor->angle;
+ mo->target = actor->target;
+ mo->momx = actor->momx >> 1;
+ mo->momy = actor->momy >> 1;
+ mo->momz = actor->momz >> 1;
+ }
+}
+
+void A_TeloSpawnD(mobj_t * actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_TELOTHER_FX5);
+ if (mo)
+ {
+ mo->special1.i = TELEPORT_LIFE; // Lifetime countdown
+ mo->angle = actor->angle;
+ mo->target = actor->target;
+ mo->momx = actor->momx >> 1;
+ mo->momy = actor->momy >> 1;
+ mo->momz = actor->momz >> 1;
+ }
+}
+
+void A_CheckTeleRing(mobj_t * actor)
+{
+ if (actor->special1.i-- <= 0)
+ {
+ P_SetMobjState(actor, actor->info->deathstate);
+ }
+}
+
+
+
+
+// Dirt stuff
+
+void P_SpawnDirt(mobj_t * actor, fixed_t radius)
+{
+ fixed_t x, y, z;
+ int dtype = 0;
+ mobj_t *mo;
+ angle_t angle;
+
+ angle = P_Random() << 5; // <<24 >>19
+ x = actor->x + FixedMul(radius, finecosine[angle]);
+ y = actor->y + FixedMul(radius, finesine[angle]);
+// x = actor->x + ((P_Random()-P_Random())%radius)<<FRACBITS;
+// y = actor->y + ((P_Random()-P_Random()<<FRACBITS)%radius);
+ z = actor->z + (P_Random() << 9) + FRACUNIT;
+ switch (P_Random() % 6)
+ {
+ case 0:
+ dtype = MT_DIRT1;
+ break;
+ case 1:
+ dtype = MT_DIRT2;
+ break;
+ case 2:
+ dtype = MT_DIRT3;
+ break;
+ case 3:
+ dtype = MT_DIRT4;
+ break;
+ case 4:
+ dtype = MT_DIRT5;
+ break;
+ case 5:
+ dtype = MT_DIRT6;
+ break;
+ }
+ mo = P_SpawnMobj(x, y, z, dtype);
+ if (mo)
+ {
+ mo->momz = P_Random() << 10;
+ }
+}
+
+
+
+
+//===========================================================================
+//
+// Thrust floor stuff
+//
+// Thrust Spike Variables
+// special1 pointer to dirt clump mobj
+// special2 speed of raise
+// args[0] 0 = lowered, 1 = raised
+// args[1] 0 = normal, 1 = bloody
+//===========================================================================
+
+void A_ThrustInitUp(mobj_t * actor)
+{
+ actor->special2.i = 5; // Raise speed
+ actor->args[0] = 1; // Mark as up
+ actor->floorclip = 0;
+ actor->flags = MF_SOLID;
+ actor->flags2 = MF2_NOTELEPORT | MF2_FLOORCLIP;
+ actor->special1.m = NULL;
+}
+
+void A_ThrustInitDn(mobj_t * actor)
+{
+ mobj_t *mo;
+ actor->special2.i = 5; // Raise speed
+ actor->args[0] = 0; // Mark as down
+ actor->floorclip = actor->info->height;
+ actor->flags = 0;
+ actor->flags2 = MF2_NOTELEPORT | MF2_FLOORCLIP | MF2_DONTDRAW;
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_DIRTCLUMP);
+ actor->special1.m = mo;
+}
+
+
+void A_ThrustRaise(mobj_t * actor)
+{
+ if (A_RaiseMobj(actor))
+ { // Reached it's target height
+ actor->args[0] = 1;
+ if (actor->args[1])
+ P_SetMobjStateNF(actor, S_BTHRUSTINIT2_1);
+ else
+ P_SetMobjStateNF(actor, S_THRUSTINIT2_1);
+ }
+
+ // Lose the dirt clump
+ if ((actor->floorclip < actor->height) && actor->special1.m)
+ {
+ P_RemoveMobj(actor->special1.m);
+ actor->special1.m = NULL;
+ }
+
+ // Spawn some dirt
+ if (P_Random() < 40)
+ P_SpawnDirt(actor, actor->radius);
+ actor->special2.i++; // Increase raise speed
+}
+
+void A_ThrustLower(mobj_t * actor)
+{
+ if (A_SinkMobj(actor))
+ {
+ actor->args[0] = 0;
+ if (actor->args[1])
+ P_SetMobjStateNF(actor, S_BTHRUSTINIT1_1);
+ else
+ P_SetMobjStateNF(actor, S_THRUSTINIT1_1);
+ }
+}
+
+void A_ThrustBlock(mobj_t * actor)
+{
+ actor->flags |= MF_SOLID;
+}
+
+void A_ThrustImpale(mobj_t * actor)
+{
+ // Impale all shootables in radius
+ PIT_ThrustSpike(actor);
+}
+
+//===========================================================================
+//
+// A_SoAExplode - Suit of Armor Explode
+//
+//===========================================================================
+
+void A_SoAExplode(mobj_t * actor)
+{
+ mobj_t *mo;
+ int i;
+
+ for (i = 0; i < 10; i++)
+ {
+ mo = P_SpawnMobj(actor->x + ((P_Random() - 128) << 12),
+ actor->y + ((P_Random() - 128) << 12),
+ actor->z + (P_Random() * actor->height / 256),
+ MT_ZARMORCHUNK);
+ P_SetMobjState(mo, mo->info->spawnstate + i);
+ if (mo)
+ {
+ mo->momz = ((P_Random() & 7) + 5) * FRACUNIT;
+ mo->momx = (P_Random() - P_Random()) << (FRACBITS - 6);
+ mo->momy = (P_Random() - P_Random()) << (FRACBITS - 6);
+ }
+ }
+ if (actor->args[0])
+ { // Spawn an item
+ if (!nomonsters
+ || !(mobjinfo[TranslateThingType[actor->args[0]]].
+ flags & MF_COUNTKILL))
+ { // Only spawn monsters if not -nomonsters
+ P_SpawnMobj(actor->x, actor->y, actor->z,
+ TranslateThingType[actor->args[0]]);
+ }
+ }
+ S_StartSound(mo, SFX_SUITOFARMOR_BREAK);
+ P_RemoveMobj(actor);
+}
+
+//===========================================================================
+//
+// A_BellReset1
+//
+//===========================================================================
+
+void A_BellReset1(mobj_t * actor)
+{
+ actor->flags |= MF_NOGRAVITY;
+ actor->height <<= 2;
+}
+
+//===========================================================================
+//
+// A_BellReset2
+//
+//===========================================================================
+
+void A_BellReset2(mobj_t * actor)
+{
+ actor->flags |= MF_SHOOTABLE;
+ actor->flags &= ~MF_CORPSE;
+ actor->health = 5;
+}
+
+
+//===========================================================================
+//
+// A_FlameCheck
+//
+//===========================================================================
+
+void A_FlameCheck(mobj_t * actor)
+{
+ if (!actor->args[0]--) // Called every 8 tics
+ {
+ P_SetMobjState(actor, S_NULL);
+ }
+}
+
+
+//===========================================================================
+// Bat Spawner Variables
+// special1 frequency counter
+// special2
+// args[0] frequency of spawn (1=fastest, 10=slowest)
+// args[1] spread angle (0..255)
+// args[2]
+// args[3] duration of bats (in octics)
+// args[4] turn amount per move (in degrees)
+//
+// Bat Variables
+// special2 lifetime counter
+// args[4] turn amount per move (in degrees)
+//===========================================================================
+
+void A_BatSpawnInit(mobj_t * actor)
+{
+ actor->special1.i = 0; // Frequency count
+}
+
+void A_BatSpawn(mobj_t * actor)
+{
+ mobj_t *mo;
+ int delta;
+ angle_t angle;
+
+ // Countdown until next spawn
+ if (actor->special1.i-- > 0)
+ return;
+ actor->special1.i = actor->args[0]; // Reset frequency count
+
+ delta = actor->args[1];
+ if (delta == 0)
+ delta = 1;
+ angle = actor->angle + (((P_Random() % delta) - (delta >> 1)) << 24);
+ mo = P_SpawnMissileAngle(actor, MT_BAT, angle, 0);
+ if (mo)
+ {
+ mo->args[0] = P_Random() & 63; // floatbob index
+ mo->args[4] = actor->args[4]; // turn degrees
+ mo->special2.i = actor->args[3] << 3; // Set lifetime
+ mo->target = actor;
+ }
+}
+
+
+void A_BatMove(mobj_t * actor)
+{
+ angle_t newangle;
+ fixed_t speed;
+
+ if (actor->special2.i < 0)
+ {
+ P_SetMobjState(actor, actor->info->deathstate);
+ }
+ actor->special2.i -= 2; // Called every 2 tics
+
+ if (P_Random() < 128)
+ {
+ newangle = actor->angle + ANG1 * actor->args[4];
+ }
+ else
+ {
+ newangle = actor->angle - ANG1 * actor->args[4];
+ }
+
+ // Adjust momentum vector to new direction
+ newangle >>= ANGLETOFINESHIFT;
+ speed = FixedMul(actor->info->speed, P_Random() << 10);
+ actor->momx = FixedMul(speed, finecosine[newangle]);
+ actor->momy = FixedMul(speed, finesine[newangle]);
+
+ if (P_Random() < 15)
+ S_StartSound(actor, SFX_BAT_SCREAM);
+
+ // Handle Z movement
+ actor->z = actor->target->z + 2 * FloatBobOffsets[actor->args[0]];
+ actor->args[0] = (actor->args[0] + 3) & 63;
+}
+
+//===========================================================================
+//
+// A_TreeDeath
+//
+//===========================================================================
+
+void A_TreeDeath(mobj_t * actor)
+{
+ if (!(actor->flags2 & MF2_FIREDAMAGE))
+ {
+ actor->height <<= 2;
+ actor->flags |= MF_SHOOTABLE;
+ actor->flags &= ~(MF_CORPSE + MF_DROPOFF);
+ actor->health = 35;
+ return;
+ }
+ else
+ {
+ P_SetMobjState(actor, actor->info->meleestate);
+ }
+}
+
+//===========================================================================
+//
+// A_NoGravity
+//
+//===========================================================================
+
+void A_NoGravity(mobj_t * actor)
+{
+ actor->flags |= MF_NOGRAVITY;
+}
diff --git a/src/hexen/am_data.h b/src/hexen/am_data.h
new file mode 100644
index 00000000..a4cb47f3
--- /dev/null
+++ b/src/hexen/am_data.h
@@ -0,0 +1,117 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef __AMDATA_H__
+#define __AMDATA_H__
+
+// a line drawing of the player pointing right, starting from the middle.
+
+#define R ((8*PLAYERRADIUS)/7)
+
+mline_t player_arrow[] = {
+ { { -R+R/4, 0 }, { 0, 0} }, // center line.
+ { { -R+R/4, R/8 }, { R, 0} }, // blade
+ { { -R+R/4, -R/8 }, { R, 0 } },
+ { { -R+R/4, -R/4 }, { -R+R/4, R/4 } }, // crosspiece
+ { { -R+R/8, -R/4 }, { -R+R/8, R/4 } },
+ { { -R+R/8, -R/4 }, { -R+R/4, -R/4} }, //crosspiece connectors
+ { { -R+R/8, R/4 }, { -R+R/4, R/4} },
+ { { -R-R/4, R/8 }, { -R-R/4, -R/8 } }, //pommel
+ { { -R-R/4, R/8 }, { -R+R/8, R/8 } },
+ { { -R-R/4, -R/8}, { -R+R/8, -R/8 } }
+ };
+
+/*
+mline_t keysquare[] = {
+ { { 0, 0 }, { R/4, -R/2 } },
+ { { R/4, -R/2 }, { R/2, -R/2 } },
+ { { R/2, -R/2 }, { R/2, R/2 } },
+ { { R/2, R/2 }, { R/4, R/2 } },
+ { { R/4, R/2 }, { 0, 0 } }, // handle part type thing
+ { { 0, 0 }, { -R, 0 } }, // stem
+ { { -R, 0 }, { -R, -R/2 } }, // end lockpick part
+ { { -3*R/4, 0 }, { -3*R/4, -R/4 } }
+ };
+*/
+
+/*mline_t player_arrow[] = {
+ { { -R+R/8, 0 }, { R, 0 } }, // -----
+ { { R, 0 }, { R-R/2, R/4 } }, // ----->
+ { { R, 0 }, { R-R/2, -R/4 } },
+ { { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >---->
+ { { -R+R/8, 0 }, { -R-R/8, -R/4 } },
+ { { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>--->
+ { { -R+3*R/8, 0 }, { -R+R/8, -R/4 } }
+ };
+*/
+#undef R
+#define NUMPLYRLINES (sizeof(player_arrow)/sizeof(mline_t))
+#define NUMKEYSQUARELINES (sizeof(keysquare)/sizeof(mline_t))
+
+/*
+#define R ((8*PLAYERRADIUS)/7)
+mline_t cheat_player_arrow[] = {
+ { { -R+R/8, 0 }, { R, 0 } }, // -----
+ { { R, 0 }, { R-R/2, R/6 } }, // ----->
+ { { R, 0 }, { R-R/2, -R/6 } },
+ { { -R+R/8, 0 }, { -R-R/8, R/6 } }, // >----->
+ { { -R+R/8, 0 }, { -R-R/8, -R/6 } },
+ { { -R+3*R/8, 0 }, { -R+R/8, R/6 } }, // >>----->
+ { { -R+3*R/8, 0 }, { -R+R/8, -R/6 } },
+ { { -R/2, 0 }, { -R/2, -R/6 } }, // >>-d--->
+ { { -R/2, -R/6 }, { -R/2+R/6, -R/6 } },
+ { { -R/2+R/6, -R/6 }, { -R/2+R/6, R/4 } },
+ { { -R/6, 0 }, { -R/6, -R/6 } }, // >>-dd-->
+ { { -R/6, -R/6 }, { 0, -R/6 } },
+ { { 0, -R/6 }, { 0, R/4 } },
+ { { R/6, R/4 }, { R/6, -R/7 } }, // >>-ddt->
+ { { R/6, -R/7 }, { R/6+R/32, -R/7-R/32 } },
+ { { R/6+R/32, -R/7-R/32 }, { R/6+R/10, -R/7 } }
+ };
+#undef R
+#define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow)/sizeof(mline_t))
+*/
+
+
+/*
+#define R (FRACUNIT)
+mline_t triangle_guy[] = {
+ { { -.867*R, -.5*R }, { .867*R, -.5*R } },
+ { { .867*R, -.5*R } , { 0, R } },
+ { { 0, R }, { -.867*R, -.5*R } }
+ };
+#undef R
+#define NUMTRIANGLEGUYLINES (sizeof(triangle_guy)/sizeof(mline_t))
+*/
+
+#define R (FRACUNIT)
+mline_t thintriangle_guy[] = {
+ { { (fixed_t)(-.5*R), (fixed_t)(-.7*R) }, { (fixed_t)(R ), (fixed_t)(0 ) } },
+ { { (fixed_t)(R ), (fixed_t)(0 ) }, { (fixed_t)(-.5*R), (fixed_t)(.7*R ) } },
+ { { (fixed_t)(-.5*R), (fixed_t)(.7*R ) }, { (fixed_t)(-.5*R), (fixed_t)(-.7*R) } }
+ };
+#undef R
+#define NUMTHINTRIANGLEGUYLINES (sizeof(thintriangle_guy)/sizeof(mline_t))
+
+#endif
diff --git a/src/hexen/am_map.c b/src/hexen/am_map.c
new file mode 100644
index 00000000..05d03d8f
--- /dev/null
+++ b/src/hexen/am_map.c
@@ -0,0 +1,1520 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+
+#include "h2def.h"
+#include "doomkeys.h"
+#include "i_video.h"
+#include "i_swap.h"
+#include "m_controls.h"
+#include "p_local.h"
+#include "am_map.h"
+#include "am_data.h"
+#include "v_video.h"
+
+#define NUMALIAS 3 // Number of antialiased lines.
+
+int cheating = 0;
+static int grid = 0;
+
+static int leveljuststarted = 1; // kluge until AM_LevelInit() is called
+
+boolean automapactive = false;
+static int finit_width = SCREENWIDTH;
+static int finit_height = SCREENHEIGHT - SBARHEIGHT - 3;
+static int f_x, f_y; // location of window on screen
+static int f_w, f_h; // size of window on screen
+static int lightlev; // used for funky strobing effect
+static byte *fb; // pseudo-frame buffer
+static int amclock;
+
+static mpoint_t m_paninc; // how far the window pans each tic (map coords)
+static fixed_t mtof_zoommul; // how far the window zooms in each tic (map coords)
+static fixed_t ftom_zoommul; // how far the window zooms in each tic (fb coords)
+
+static fixed_t m_x, m_y; // LL x,y where the window is on the map (map coords)
+static fixed_t m_x2, m_y2; // UR x,y where the window is on the map (map coords)
+
+// width/height of window on map (map coords)
+static fixed_t m_w, m_h;
+static fixed_t min_x, min_y; // based on level size
+static fixed_t max_x, max_y; // based on level size
+static fixed_t max_w, max_h; // max_x-min_x, max_y-min_y
+static fixed_t min_w, min_h; // based on player size
+static fixed_t min_scale_mtof; // used to tell when to stop zooming out
+static fixed_t max_scale_mtof; // used to tell when to stop zooming in
+
+// old stuff for recovery later
+static fixed_t old_m_w, old_m_h;
+static fixed_t old_m_x, old_m_y;
+
+// old location used by the Follower routine
+static mpoint_t f_oldloc;
+
+// used by MTOF to scale from map-to-frame-buffer coords
+static fixed_t scale_mtof = INITSCALEMTOF;
+// used by FTOM to scale from frame-buffer-to-map coords (=1/scale_mtof)
+static fixed_t scale_ftom;
+
+static player_t *plr; // the player represented by an arrow
+static vertex_t oldplr;
+
+//static patch_t *marknums[10]; // numbers used for marking by the automap
+//static mpoint_t markpoints[AM_NUMMARKPOINTS]; // where the points are
+//static int markpointnum = 0; // next point to be assigned
+
+static int followplayer = 1; // specifies whether to follow the player around
+
+static char cheat_kills[] = { 'k', 'i', 'l', 'l', 's' };
+static boolean ShowKills = 0;
+static unsigned ShowKillsCount = 0;
+
+extern boolean viewactive;
+
+static byte antialias[NUMALIAS][8] = {
+ {83, 84, 85, 86, 87, 88, 89, 90},
+ {96, 96, 95, 94, 93, 92, 91, 90},
+ {107, 108, 109, 110, 111, 112, 89, 90}
+};
+
+/*
+static byte *aliasmax[NUMALIAS] = {
+ &antialias[0][7], &antialias[1][7], &antialias[2][7]
+};*/
+
+static byte *maplump; // pointer to the raw data for the automap background.
+static short mapystart = 0; // y-value for the start of the map bitmap...used in
+ //the parallax stuff.
+static short mapxstart = 0; //x-value for the bitmap.
+
+//byte screens[][SCREENWIDTH*SCREENHEIGHT];
+//void V_MarkRect (int x, int y, int width, int height);
+
+// Functions
+
+void DrawWuLine(int X0, int Y0, int X1, int Y1, byte * BaseColor,
+ int NumLevels, unsigned short IntensityBits);
+
+void AM_DrawDeathmatchStats(void);
+static void DrawWorldTimer(void);
+
+// Calculates the slope and slope according to the x-axis of a line
+// segment in map coordinates (with the upright y-axis n' all) so
+// that it can be used with the brain-dead drawing stuff.
+
+// Ripped out for Heretic
+/*
+void AM_getIslope(mline_t *ml, islope_t *is)
+{
+ int dx, dy;
+
+ dy = ml->a.y - ml->b.y;
+ dx = ml->b.x - ml->a.x;
+ if (!dy) is->islp = (dx<0?-INT_MAX:INT_MAX);
+ else is->islp = FixedDiv(dx, dy);
+ if (!dx) is->slp = (dy<0?-INT_MAX:INT_MAX);
+ else is->slp = FixedDiv(dy, dx);
+}
+*/
+
+void AM_activateNewScale(void)
+{
+ m_x += m_w / 2;
+ m_y += m_h / 2;
+ m_w = FTOM(f_w);
+ m_h = FTOM(f_h);
+ m_x -= m_w / 2;
+ m_y -= m_h / 2;
+ m_x2 = m_x + m_w;
+ m_y2 = m_y + m_h;
+}
+
+void AM_saveScaleAndLoc(void)
+{
+ old_m_x = m_x;
+ old_m_y = m_y;
+ old_m_w = m_w;
+ old_m_h = m_h;
+}
+
+void AM_restoreScaleAndLoc(void)
+{
+
+ m_w = old_m_w;
+ m_h = old_m_h;
+ if (!followplayer)
+ {
+ m_x = old_m_x;
+ m_y = old_m_y;
+ }
+ else
+ {
+ m_x = plr->mo->x - m_w / 2;
+ m_y = plr->mo->y - m_h / 2;
+ }
+ m_x2 = m_x + m_w;
+ m_y2 = m_y + m_h;
+
+ // Change the scaling multipliers
+ scale_mtof = FixedDiv(f_w << FRACBITS, m_w);
+ scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+}
+
+// adds a marker at the current location
+
+/*
+void AM_addMark(void)
+{
+ markpoints[markpointnum].x = m_x + m_w/2;
+ markpoints[markpointnum].y = m_y + m_h/2;
+ markpointnum = (markpointnum + 1) % AM_NUMMARKPOINTS;
+
+}
+*/
+void AM_findMinMaxBoundaries(void)
+{
+ int i;
+ fixed_t a, b;
+
+ min_x = min_y = INT_MAX;
+ max_x = max_y = -INT_MAX;
+ for (i = 0; i < numvertexes; i++)
+ {
+ if (vertexes[i].x < min_x)
+ min_x = vertexes[i].x;
+ else if (vertexes[i].x > max_x)
+ max_x = vertexes[i].x;
+ if (vertexes[i].y < min_y)
+ min_y = vertexes[i].y;
+ else if (vertexes[i].y > max_y)
+ max_y = vertexes[i].y;
+ }
+ max_w = max_x - min_x;
+ max_h = max_y - min_y;
+ min_w = 2 * PLAYERRADIUS;
+ min_h = 2 * PLAYERRADIUS;
+
+ a = FixedDiv(f_w << FRACBITS, max_w);
+ b = FixedDiv(f_h << FRACBITS, max_h);
+ min_scale_mtof = a < b ? a : b;
+
+ max_scale_mtof = FixedDiv(f_h << FRACBITS, 2 * PLAYERRADIUS);
+
+}
+
+void AM_changeWindowLoc(void)
+{
+ if (m_paninc.x || m_paninc.y)
+ {
+ followplayer = 0;
+ f_oldloc.x = INT_MAX;
+ }
+
+ m_x += m_paninc.x;
+ m_y += m_paninc.y;
+
+ if (m_x + m_w / 2 > max_x)
+ {
+ m_x = max_x - m_w / 2;
+ m_paninc.x = 0;
+ }
+ else if (m_x + m_w / 2 < min_x)
+ {
+ m_x = min_x - m_w / 2;
+ m_paninc.x = 0;
+ }
+ if (m_y + m_h / 2 > max_y)
+ {
+ m_y = max_y - m_h / 2;
+ m_paninc.y = 0;
+ }
+ else if (m_y + m_h / 2 < min_y)
+ {
+ m_y = min_y - m_h / 2;
+ m_paninc.y = 0;
+ }
+/*
+ mapxstart += MTOF(m_paninc.x+FRACUNIT/2);
+ mapystart -= MTOF(m_paninc.y+FRACUNIT/2);
+ if(mapxstart >= finit_width)
+ mapxstart -= finit_width;
+ if(mapxstart < 0)
+ mapxstart += finit_width;
+ if(mapystart >= finit_height)
+ mapystart -= finit_height;
+ if(mapystart < 0)
+ mapystart += finit_height;
+*/
+ m_x2 = m_x + m_w;
+ m_y2 = m_y + m_h;
+}
+
+void AM_initVariables(void)
+{
+ int pnum;
+ thinker_t *think;
+
+ //static event_t st_notify = { ev_keyup, AM_MSGENTERED };
+
+ automapactive = true;
+ fb = I_VideoBuffer;
+
+ f_oldloc.x = INT_MAX;
+ amclock = 0;
+ lightlev = 0;
+
+ m_paninc.x = m_paninc.y = 0;
+ ftom_zoommul = FRACUNIT;
+ mtof_zoommul = FRACUNIT;
+
+ m_w = FTOM(f_w);
+ m_h = FTOM(f_h);
+
+ // find player to center on initially
+ if (!playeringame[pnum = consoleplayer])
+ for (pnum = 0; pnum < MAXPLAYERS; pnum++)
+ if (playeringame[pnum])
+ break;
+ plr = &players[pnum];
+ oldplr.x = plr->mo->x;
+ oldplr.y = plr->mo->y;
+ m_x = plr->mo->x - m_w / 2;
+ m_y = plr->mo->y - m_h / 2;
+ AM_changeWindowLoc();
+
+ // for saving & restoring
+ old_m_x = m_x;
+ old_m_y = m_y;
+ old_m_w = m_w;
+ old_m_h = m_h;
+
+ // load in the location of keys, if in baby mode
+
+// memset(KeyPoints, 0, sizeof(vertex_t)*3);
+ if (gameskill == sk_baby)
+ {
+ for (think = thinkercap.next; think != &thinkercap;
+ think = think->next)
+ {
+ if (think->function != P_MobjThinker)
+ { //not a mobj
+ continue;
+ }
+ }
+ }
+
+ // inform the status bar of the change
+//c ST_Responder(&st_notify);
+}
+
+void AM_loadPics(void)
+{
+ maplump = W_CacheLumpName("AUTOPAGE", PU_STATIC);
+}
+
+
+/*
+void AM_clearMarks(void)
+{
+ int i;
+ for (i=0;i<AM_NUMMARKPOINTS;i++) markpoints[i].x = -1; // means empty
+ markpointnum = 0;
+}
+*/
+
+// should be called at the start of every level
+// right now, i figure it out myself
+
+void AM_LevelInit(void)
+{
+ leveljuststarted = 0;
+
+ f_x = f_y = 0;
+ f_w = finit_width;
+ f_h = finit_height;
+ mapxstart = mapystart = 0;
+
+
+// AM_clearMarks();
+
+ AM_findMinMaxBoundaries();
+ scale_mtof = FixedDiv(min_scale_mtof, (int) (0.7 * FRACUNIT));
+ if (scale_mtof > max_scale_mtof)
+ scale_mtof = min_scale_mtof;
+ scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+}
+
+static boolean stopped = true;
+
+void AM_Stop(void)
+{
+ //static event_t st_notify = { 0, ev_keyup, AM_MSGEXITED };
+
+// AM_unloadPics();
+ automapactive = false;
+// ST_Responder(&st_notify);
+ stopped = true;
+ BorderNeedRefresh = true;
+}
+
+void AM_Start(void)
+{
+ static int lastlevel = -1, lastepisode = -1;
+
+ if (!stopped)
+ AM_Stop();
+ stopped = false;
+ if (gamestate != GS_LEVEL)
+ {
+ return; // don't show automap if we aren't in a game!
+ }
+ if (lastlevel != gamemap || lastepisode != gameepisode)
+ {
+ AM_LevelInit();
+ lastlevel = gamemap;
+ lastepisode = gameepisode;
+ }
+ AM_initVariables();
+ AM_loadPics();
+}
+
+// set the window scale to the maximum size
+
+void AM_minOutWindowScale(void)
+{
+ scale_mtof = min_scale_mtof;
+ scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+ AM_activateNewScale();
+}
+
+// set the window scale to the minimum size
+
+void AM_maxOutWindowScale(void)
+{
+ scale_mtof = max_scale_mtof;
+ scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+ AM_activateNewScale();
+}
+
+boolean AM_Responder(event_t * ev)
+{
+ int rc;
+ int key;
+ static int bigstate = 0;
+
+ key = ev->data1;
+
+ rc = false;
+ if (!automapactive)
+ {
+ if (ev->type == ev_keydown && key == key_map_toggle
+ && gamestate == GS_LEVEL)
+ {
+ AM_Start();
+ SB_state = -1;
+ viewactive = false;
+ rc = true;
+ }
+ }
+ else if (ev->type == ev_keydown)
+ {
+ rc = true;
+
+ if (key == key_map_east) // pan right
+ {
+ if (!followplayer)
+ m_paninc.x = FTOM(F_PANINC);
+ else
+ rc = false;
+ }
+ else if (key == key_map_west) // pan left
+ {
+ if (!followplayer)
+ m_paninc.x = -FTOM(F_PANINC);
+ else
+ rc = false;
+ }
+ else if (key == key_map_north) // pan up
+ {
+ if (!followplayer)
+ m_paninc.y = FTOM(F_PANINC);
+ else
+ rc = false;
+ }
+ else if (key == key_map_south) // pan down
+ {
+ if (!followplayer)
+ m_paninc.y = -FTOM(F_PANINC);
+ else
+ rc = false;
+ }
+ else if (key == key_map_zoomout) // zoom out
+ {
+ mtof_zoommul = M_ZOOMOUT;
+ ftom_zoommul = M_ZOOMIN;
+ }
+ else if (key == key_map_zoomin) // zoom in
+ {
+ mtof_zoommul = M_ZOOMIN;
+ ftom_zoommul = M_ZOOMOUT;
+ }
+ else if (key == key_map_toggle)
+ {
+ bigstate = 0;
+ viewactive = true;
+ AM_Stop();
+ SB_state = -1;
+ }
+ else if (key == key_map_maxzoom)
+ {
+ bigstate = !bigstate;
+ if (bigstate)
+ {
+ AM_saveScaleAndLoc();
+ AM_minOutWindowScale();
+ }
+ else
+ AM_restoreScaleAndLoc();
+ }
+ else if (key == key_map_follow)
+ {
+ followplayer = !followplayer;
+ f_oldloc.x = INT_MAX;
+ P_SetMessage(plr,
+ followplayer ? AMSTR_FOLLOWON : AMSTR_FOLLOWOFF,
+ true);
+ }
+ else
+ {
+ rc = false;
+ }
+
+ if (cheat_kills[ShowKillsCount] == ev->data1 && netgame && deathmatch)
+ {
+ ShowKillsCount++;
+ if (ShowKillsCount == 5)
+ {
+ ShowKillsCount = 0;
+ rc = false;
+ ShowKills ^= 1;
+ }
+ }
+ else
+ {
+ ShowKillsCount = 0;
+ }
+ }
+ else if (ev->type == ev_keyup)
+ {
+ rc = false;
+
+ if (key == key_map_east)
+ {
+ if (!followplayer)
+ m_paninc.x = 0;
+ }
+ else if (key == key_map_west)
+ {
+ if (!followplayer)
+ m_paninc.x = 0;
+ }
+ else if (key == key_map_north)
+ {
+ if (!followplayer)
+ m_paninc.y = 0;
+ }
+ else if (key == key_map_south)
+ {
+ if (!followplayer)
+ m_paninc.y = 0;
+ }
+ else if (key == key_map_zoomin || key == key_map_zoomout)
+ {
+ mtof_zoommul = FRACUNIT;
+ ftom_zoommul = FRACUNIT;
+ }
+ }
+ return rc;
+}
+
+void AM_changeWindowScale(void)
+{
+
+ // Change the scaling multipliers
+ scale_mtof = FixedMul(scale_mtof, mtof_zoommul);
+ scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+
+ if (scale_mtof < min_scale_mtof)
+ AM_minOutWindowScale();
+ else if (scale_mtof > max_scale_mtof)
+ AM_maxOutWindowScale();
+ else
+ AM_activateNewScale();
+}
+
+void AM_doFollowPlayer(void)
+{
+ if (f_oldloc.x != plr->mo->x || f_oldloc.y != plr->mo->y)
+ {
+// m_x = FTOM(MTOF(plr->mo->x - m_w/2));
+// m_y = FTOM(MTOF(plr->mo->y - m_h/2));
+// m_x = plr->mo->x - m_w/2;
+// m_y = plr->mo->y - m_h/2;
+ m_x = FTOM(MTOF(plr->mo->x)) - m_w / 2;
+ m_y = FTOM(MTOF(plr->mo->y)) - m_h / 2;
+ m_x2 = m_x + m_w;
+ m_y2 = m_y + m_h;
+
+ // do the parallax parchment scrolling.
+/*
+ dmapx = (MTOF(plr->mo->x)-MTOF(f_oldloc.x)); //fixed point
+ dmapy = (MTOF(f_oldloc.y)-MTOF(plr->mo->y));
+
+ if(f_oldloc.x == INT_MAX) //to eliminate an error when the user first
+ dmapx=0; //goes into the automap.
+ mapxstart += dmapx;
+ mapystart += dmapy;
+
+ while(mapxstart >= finit_width)
+ mapxstart -= finit_width;
+ while(mapxstart < 0)
+ mapxstart += finit_width;
+ while(mapystart >= finit_height)
+ mapystart -= finit_height;
+ while(mapystart < 0)
+ mapystart += finit_height;
+*/
+ f_oldloc.x = plr->mo->x;
+ f_oldloc.y = plr->mo->y;
+ }
+}
+
+// Ripped out for Heretic
+/*
+void AM_updateLightLev(void)
+{
+ static nexttic = 0;
+//static int litelevels[] = { 0, 3, 5, 6, 6, 7, 7, 7 };
+ static int litelevels[] = { 0, 4, 7, 10, 12, 14, 15, 15 };
+ static int litelevelscnt = 0;
+
+ // Change light level
+ if (amclock>nexttic)
+ {
+ lightlev = litelevels[litelevelscnt++];
+ if (litelevelscnt == sizeof(litelevels)/sizeof(int)) litelevelscnt = 0;
+ nexttic = amclock + 6 - (amclock % 6);
+ }
+}
+*/
+
+void AM_Ticker(void)
+{
+
+ if (!automapactive)
+ return;
+
+ amclock++;
+
+ if (followplayer)
+ AM_doFollowPlayer();
+
+ // Change the zoom if necessary
+ if (ftom_zoommul != FRACUNIT)
+ AM_changeWindowScale();
+
+ // Change x,y location
+ if (m_paninc.x || m_paninc.y)
+ AM_changeWindowLoc();
+ // Update light level
+// AM_updateLightLev();
+
+}
+
+void AM_clearFB(int color)
+{
+ int i, j;
+ int dmapx;
+ int dmapy;
+
+ if (followplayer)
+ {
+ dmapx = (MTOF(plr->mo->x) - MTOF(oldplr.x)); //fixed point
+ dmapy = (MTOF(oldplr.y) - MTOF(plr->mo->y));
+
+ oldplr.x = plr->mo->x;
+ oldplr.y = plr->mo->y;
+// if(f_oldloc.x == INT_MAX) //to eliminate an error when the user first
+// dmapx=0; //goes into the automap.
+ mapxstart += dmapx >> 1;
+ mapystart += dmapy >> 1;
+
+ while (mapxstart >= finit_width)
+ mapxstart -= finit_width;
+ while (mapxstart < 0)
+ mapxstart += finit_width;
+ while (mapystart >= finit_height)
+ mapystart -= finit_height;
+ while (mapystart < 0)
+ mapystart += finit_height;
+ }
+ else
+ {
+ mapxstart += (MTOF(m_paninc.x) >> 1);
+ mapystart -= (MTOF(m_paninc.y) >> 1);
+ if (mapxstart >= finit_width)
+ mapxstart -= finit_width;
+ if (mapxstart < 0)
+ mapxstart += finit_width;
+ if (mapystart >= finit_height)
+ mapystart -= finit_height;
+ if (mapystart < 0)
+ mapystart += finit_height;
+ }
+
+ //blit the automap background to the screen.
+ j = mapystart * finit_width;
+ for (i = 0; i < SCREENHEIGHT - SBARHEIGHT; i++)
+ {
+ memcpy(I_VideoBuffer + i * finit_width, maplump + j + mapxstart,
+ finit_width - mapxstart);
+ memcpy(I_VideoBuffer + i * finit_width + finit_width - mapxstart,
+ maplump + j, mapxstart);
+ j += finit_width;
+ if (j >= finit_height * finit_width)
+ j = 0;
+ }
+
+// memcpy(I_VideoBuffer, maplump, finit_width*finit_height);
+// memset(fb, color, f_w*f_h);
+}
+
+// Based on Cohen-Sutherland clipping algorithm but with a slightly
+// faster reject and precalculated slopes. If I need the speed, will
+// hash algorithm to the common cases.
+
+boolean AM_clipMline(mline_t * ml, fline_t * fl)
+{
+ enum
+ { LEFT = 1, RIGHT = 2, BOTTOM = 4, TOP = 8 };
+ int outcode1 = 0, outcode2 = 0, outside;
+ fpoint_t tmp = { 0, 0 };
+ int dx, dy;
+
+#define DOOUTCODE(oc, mx, my) \
+ (oc) = 0; \
+ if ((my) < 0) (oc) |= TOP; \
+ else if ((my) >= f_h) (oc) |= BOTTOM; \
+ if ((mx) < 0) (oc) |= LEFT; \
+ else if ((mx) >= f_w) (oc) |= RIGHT
+
+ // do trivial rejects and outcodes
+ if (ml->a.y > m_y2)
+ outcode1 = TOP;
+ else if (ml->a.y < m_y)
+ outcode1 = BOTTOM;
+ if (ml->b.y > m_y2)
+ outcode2 = TOP;
+ else if (ml->b.y < m_y)
+ outcode2 = BOTTOM;
+ if (outcode1 & outcode2)
+ return false; // trivially outside
+
+ if (ml->a.x < m_x)
+ outcode1 |= LEFT;
+ else if (ml->a.x > m_x2)
+ outcode1 |= RIGHT;
+ if (ml->b.x < m_x)
+ outcode2 |= LEFT;
+ else if (ml->b.x > m_x2)
+ outcode2 |= RIGHT;
+ if (outcode1 & outcode2)
+ return false; // trivially outside
+
+ // transform to frame-buffer coordinates.
+ fl->a.x = CXMTOF(ml->a.x);
+ fl->a.y = CYMTOF(ml->a.y);
+ fl->b.x = CXMTOF(ml->b.x);
+ fl->b.y = CYMTOF(ml->b.y);
+ DOOUTCODE(outcode1, fl->a.x, fl->a.y);
+ DOOUTCODE(outcode2, fl->b.x, fl->b.y);
+ if (outcode1 & outcode2)
+ return false;
+
+ while (outcode1 | outcode2)
+ {
+ // may be partially inside box
+ // find an outside point
+ if (outcode1)
+ outside = outcode1;
+ else
+ outside = outcode2;
+ // clip to each side
+ if (outside & TOP)
+ {
+ dy = fl->a.y - fl->b.y;
+ dx = fl->b.x - fl->a.x;
+ tmp.x = fl->a.x + (dx * (fl->a.y)) / dy;
+ tmp.y = 0;
+ }
+ else if (outside & BOTTOM)
+ {
+ dy = fl->a.y - fl->b.y;
+ dx = fl->b.x - fl->a.x;
+ tmp.x = fl->a.x + (dx * (fl->a.y - f_h)) / dy;
+ tmp.y = f_h - 1;
+ }
+ else if (outside & RIGHT)
+ {
+ dy = fl->b.y - fl->a.y;
+ dx = fl->b.x - fl->a.x;
+ tmp.y = fl->a.y + (dy * (f_w - 1 - fl->a.x)) / dx;
+ tmp.x = f_w - 1;
+ }
+ else if (outside & LEFT)
+ {
+ dy = fl->b.y - fl->a.y;
+ dx = fl->b.x - fl->a.x;
+ tmp.y = fl->a.y + (dy * (-fl->a.x)) / dx;
+ tmp.x = 0;
+ }
+ if (outside == outcode1)
+ {
+ fl->a = tmp;
+ DOOUTCODE(outcode1, fl->a.x, fl->a.y);
+ }
+ else
+ {
+ fl->b = tmp;
+ DOOUTCODE(outcode2, fl->b.x, fl->b.y);
+ }
+ if (outcode1 & outcode2)
+ return false; // trivially outside
+ }
+
+ return true;
+}
+
+#undef DOOUTCODE
+
+// Classic Bresenham w/ whatever optimizations I need for speed
+
+void AM_drawFline(fline_t * fl, int color)
+{
+ register int x, y, dx, dy, sx, sy, ax, ay, d;
+ //static fuck = 0;
+
+ switch (color)
+ {
+ case WALLCOLORS:
+ DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y,
+ &antialias[0][0], 8, 3);
+ break;
+ case FDWALLCOLORS:
+ DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y,
+ &antialias[1][0], 8, 3);
+ break;
+ case CDWALLCOLORS:
+ DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y,
+ &antialias[2][0], 8, 3);
+ break;
+ default:
+ {
+ // For debugging only
+ if (fl->a.x < 0 || fl->a.x >= f_w
+ || fl->a.y < 0 || fl->a.y >= f_h
+ || fl->b.x < 0 || fl->b.x >= f_w
+ || fl->b.y < 0 || fl->b.y >= f_h)
+ {
+ //fprintf(stderr, "fuck %d \r", fuck++);
+ return;
+ }
+
+#define DOT(xx,yy,cc) fb[(yy)*f_w+(xx)]=(cc) //the MACRO!
+
+ dx = fl->b.x - fl->a.x;
+ ax = 2 * (dx < 0 ? -dx : dx);
+ sx = dx < 0 ? -1 : 1;
+
+ dy = fl->b.y - fl->a.y;
+ ay = 2 * (dy < 0 ? -dy : dy);
+ sy = dy < 0 ? -1 : 1;
+
+ x = fl->a.x;
+ y = fl->a.y;
+
+ if (ax > ay)
+ {
+ d = ay - ax / 2;
+ while (1)
+ {
+ DOT(x, y, color);
+ if (x == fl->b.x)
+ return;
+ if (d >= 0)
+ {
+ y += sy;
+ d -= ax;
+ }
+ x += sx;
+ d += ay;
+ }
+ }
+ else
+ {
+ d = ax - ay / 2;
+ while (1)
+ {
+ DOT(x, y, color);
+ if (y == fl->b.y)
+ return;
+ if (d >= 0)
+ {
+ x += sx;
+ d -= ay;
+ }
+ y += sy;
+ d += ax;
+ }
+ }
+ }
+ }
+}
+
+/* Wu antialiased line drawer.
+ * (X0,Y0),(X1,Y1) = line to draw
+ * BaseColor = color # of first color in block used for antialiasing, the
+ * 100% intensity version of the drawing color
+ * NumLevels = size of color block, with BaseColor+NumLevels-1 being the
+ * 0% intensity version of the drawing color
+ * IntensityBits = log base 2 of NumLevels; the # of bits used to describe
+ * the intensity of the drawing color. 2**IntensityBits==NumLevels
+ */
+void PUTDOT(short xx, short yy, byte * cc, byte * cm)
+{
+ static int oldyy;
+ static int oldyyshifted;
+ byte *oldcc = cc;
+
+ if (xx < 32)
+ cc += 7 - (xx >> 2);
+ else if (xx > (finit_width - 32))
+ cc += 7 - ((finit_width - xx) >> 2);
+// if(cc==oldcc) //make sure that we don't double fade the corners.
+// {
+ if (yy < 32)
+ cc += 7 - (yy >> 2);
+ else if (yy > (finit_height - 32))
+ cc += 7 - ((finit_height - yy) >> 2);
+// }
+ if (cc > cm && cm != NULL)
+ {
+ cc = cm;
+ }
+ else if (cc > oldcc + 6) // don't let the color escape from the fade table...
+ {
+ cc = oldcc + 6;
+ }
+ if (yy == oldyy + 1)
+ {
+ oldyy++;
+ oldyyshifted += 320;
+ }
+ else if (yy == oldyy - 1)
+ {
+ oldyy--;
+ oldyyshifted -= 320;
+ }
+ else if (yy != oldyy)
+ {
+ oldyy = yy;
+ oldyyshifted = yy * 320;
+ }
+ fb[oldyyshifted + xx] = *(cc);
+// fb[(yy)*f_w+(xx)]=*(cc);
+}
+
+void DrawWuLine(int X0, int Y0, int X1, int Y1, byte * BaseColor,
+ int NumLevels, unsigned short IntensityBits)
+{
+ unsigned short IntensityShift, ErrorAdj, ErrorAcc;
+ unsigned short ErrorAccTemp, Weighting, WeightingComplementMask;
+ short DeltaX, DeltaY, Temp, XDir;
+
+ /* Make sure the line runs top to bottom */
+ if (Y0 > Y1)
+ {
+ Temp = Y0;
+ Y0 = Y1;
+ Y1 = Temp;
+ Temp = X0;
+ X0 = X1;
+ X1 = Temp;
+ }
+ /* Draw the initial pixel, which is always exactly intersected by
+ the line and so needs no weighting */
+ PUTDOT(X0, Y0, &BaseColor[0], NULL);
+
+ if ((DeltaX = X1 - X0) >= 0)
+ {
+ XDir = 1;
+ }
+ else
+ {
+ XDir = -1;
+ DeltaX = -DeltaX; /* make DeltaX positive */
+ }
+ /* Special-case horizontal, vertical, and diagonal lines, which
+ require no weighting because they go right through the center of
+ every pixel */
+ if ((DeltaY = Y1 - Y0) == 0)
+ {
+ /* Horizontal line */
+ while (DeltaX-- != 0)
+ {
+ X0 += XDir;
+ PUTDOT(X0, Y0, &BaseColor[0], NULL);
+ }
+ return;
+ }
+ if (DeltaX == 0)
+ {
+ /* Vertical line */
+ do
+ {
+ Y0++;
+ PUTDOT(X0, Y0, &BaseColor[0], NULL);
+ }
+ while (--DeltaY != 0);
+ return;
+ }
+ //diagonal line.
+ if (DeltaX == DeltaY)
+ {
+ do
+ {
+ X0 += XDir;
+ Y0++;
+ PUTDOT(X0, Y0, &BaseColor[0], NULL);
+ }
+ while (--DeltaY != 0);
+ return;
+ }
+ /* Line is not horizontal, diagonal, or vertical */
+ ErrorAcc = 0; /* initialize the line error accumulator to 0 */
+ /* # of bits by which to shift ErrorAcc to get intensity level */
+ IntensityShift = 16 - IntensityBits;
+ /* Mask used to flip all bits in an intensity weighting, producing the
+ result (1 - intensity weighting) */
+ WeightingComplementMask = NumLevels - 1;
+ /* Is this an X-major or Y-major line? */
+ if (DeltaY > DeltaX)
+ {
+ /* Y-major line; calculate 16-bit fixed-point fractional part of a
+ pixel that X advances each time Y advances 1 pixel, truncating the
+ result so that we won't overrun the endpoint along the X axis */
+ ErrorAdj = ((unsigned long) DeltaX << 16) / (unsigned long) DeltaY;
+ /* Draw all pixels other than the first and last */
+ while (--DeltaY)
+ {
+ ErrorAccTemp = ErrorAcc; /* remember currrent accumulated error */
+ ErrorAcc += ErrorAdj; /* calculate error for next pixel */
+ if (ErrorAcc <= ErrorAccTemp)
+ {
+ /* The error accumulator turned over, so advance the X coord */
+ X0 += XDir;
+ }
+ Y0++; /* Y-major, so always advance Y */
+ /* The IntensityBits most significant bits of ErrorAcc give us the
+ intensity weighting for this pixel, and the complement of the
+ weighting for the paired pixel */
+ Weighting = ErrorAcc >> IntensityShift;
+ PUTDOT(X0, Y0, &BaseColor[Weighting], &BaseColor[7]);
+ PUTDOT(X0 + XDir, Y0,
+ &BaseColor[(Weighting ^ WeightingComplementMask)],
+ &BaseColor[7]);
+ }
+ /* Draw the final pixel, which is always exactly intersected by the line
+ and so needs no weighting */
+ PUTDOT(X1, Y1, &BaseColor[0], NULL);
+ return;
+ }
+ /* It's an X-major line; calculate 16-bit fixed-point fractional part of a
+ pixel that Y advances each time X advances 1 pixel, truncating the
+ result to avoid overrunning the endpoint along the X axis */
+ ErrorAdj = ((unsigned long) DeltaY << 16) / (unsigned long) DeltaX;
+ /* Draw all pixels other than the first and last */
+ while (--DeltaX)
+ {
+ ErrorAccTemp = ErrorAcc; /* remember currrent accumulated error */
+ ErrorAcc += ErrorAdj; /* calculate error for next pixel */
+ if (ErrorAcc <= ErrorAccTemp)
+ {
+ /* The error accumulator turned over, so advance the Y coord */
+ Y0++;
+ }
+ X0 += XDir; /* X-major, so always advance X */
+ /* The IntensityBits most significant bits of ErrorAcc give us the
+ intensity weighting for this pixel, and the complement of the
+ weighting for the paired pixel */
+ Weighting = ErrorAcc >> IntensityShift;
+ PUTDOT(X0, Y0, &BaseColor[Weighting], &BaseColor[7]);
+ PUTDOT(X0, Y0 + 1,
+ &BaseColor[(Weighting ^ WeightingComplementMask)],
+ &BaseColor[7]);
+
+ }
+ /* Draw the final pixel, which is always exactly intersected by the line
+ and so needs no weighting */
+ PUTDOT(X1, Y1, &BaseColor[0], NULL);
+}
+
+void AM_drawMline(mline_t * ml, int color)
+{
+ static fline_t fl;
+
+ if (AM_clipMline(ml, &fl))
+ AM_drawFline(&fl, color); // draws it on frame buffer using fb coords
+
+}
+
+void AM_drawGrid(int color)
+{
+ fixed_t x, y;
+ fixed_t start, end;
+ mline_t ml;
+
+ // Figure out start of vertical gridlines
+ start = m_x;
+ if ((start - bmaporgx) % (MAPBLOCKUNITS << FRACBITS))
+ start += (MAPBLOCKUNITS << FRACBITS)
+ - ((start - bmaporgx) % (MAPBLOCKUNITS << FRACBITS));
+ end = m_x + m_w;
+
+ // draw vertical gridlines
+ ml.a.y = m_y;
+ ml.b.y = m_y + m_h;
+ for (x = start; x < end; x += (MAPBLOCKUNITS << FRACBITS))
+ {
+ ml.a.x = x;
+ ml.b.x = x;
+ AM_drawMline(&ml, color);
+ }
+
+ // Figure out start of horizontal gridlines
+ start = m_y;
+ if ((start - bmaporgy) % (MAPBLOCKUNITS << FRACBITS))
+ start += (MAPBLOCKUNITS << FRACBITS)
+ - ((start - bmaporgy) % (MAPBLOCKUNITS << FRACBITS));
+ end = m_y + m_h;
+
+ // draw horizontal gridlines
+ ml.a.x = m_x;
+ ml.b.x = m_x + m_w;
+ for (y = start; y < end; y += (MAPBLOCKUNITS << FRACBITS))
+ {
+ ml.a.y = y;
+ ml.b.y = y;
+ AM_drawMline(&ml, color);
+ }
+}
+
+void AM_drawWalls(void)
+{
+ int i;
+ static mline_t l;
+
+ for (i = 0; i < numlines; i++)
+ {
+ l.a.x = lines[i].v1->x;
+ l.a.y = lines[i].v1->y;
+ l.b.x = lines[i].v2->x;
+ l.b.y = lines[i].v2->y;
+ if (cheating || (lines[i].flags & ML_MAPPED))
+ {
+ if ((lines[i].flags & LINE_NEVERSEE) && !cheating)
+ continue;
+ if (!lines[i].backsector)
+ {
+ AM_drawMline(&l, WALLCOLORS + lightlev);
+ }
+ else
+ {
+ if (lines[i].flags & ML_SECRET) // secret door
+ {
+ if (cheating)
+ AM_drawMline(&l, 0);
+ else
+ AM_drawMline(&l, WALLCOLORS + lightlev);
+ }
+ else if (lines[i].special == 13 || lines[i].special == 83)
+ { // Locked door line -- all locked doors are greed
+ AM_drawMline(&l, GREENKEY);
+ }
+ else if (lines[i].special == 70 || lines[i].special == 71)
+ { // intra-level teleports are blue
+ AM_drawMline(&l, BLUEKEY);
+ }
+ else if (lines[i].special == 74 || lines[i].special == 75)
+ { // inter-level teleport/game-winning exit -- both are red
+ AM_drawMline(&l, BLOODRED);
+ }
+ else if (lines[i].backsector->floorheight
+ != lines[i].frontsector->floorheight)
+ {
+ AM_drawMline(&l, FDWALLCOLORS + lightlev); // floor level change
+ }
+ else if (lines[i].backsector->ceilingheight
+ != lines[i].frontsector->ceilingheight)
+ {
+ AM_drawMline(&l, CDWALLCOLORS + lightlev); // ceiling level change
+ }
+ else if (cheating)
+ {
+ AM_drawMline(&l, TSWALLCOLORS + lightlev);
+ }
+ }
+ }
+ else if (plr->powers[pw_allmap])
+ {
+ if (!(lines[i].flags & LINE_NEVERSEE))
+ AM_drawMline(&l, GRAYS + 3);
+ }
+ }
+
+}
+
+void AM_rotate(fixed_t * x, fixed_t * y, angle_t a)
+{
+ fixed_t tmpx;
+
+ tmpx = FixedMul(*x, finecosine[a >> ANGLETOFINESHIFT])
+ - FixedMul(*y, finesine[a >> ANGLETOFINESHIFT]);
+ *y = FixedMul(*x, finesine[a >> ANGLETOFINESHIFT])
+ + FixedMul(*y, finecosine[a >> ANGLETOFINESHIFT]);
+ *x = tmpx;
+}
+
+void AM_drawLineCharacter(mline_t * lineguy, int lineguylines, fixed_t scale,
+ angle_t angle, int color, fixed_t x, fixed_t y)
+{
+ int i;
+ mline_t l;
+
+ for (i = 0; i < lineguylines; i++)
+ {
+ l.a.x = lineguy[i].a.x;
+ l.a.y = lineguy[i].a.y;
+ if (scale)
+ {
+ l.a.x = FixedMul(scale, l.a.x);
+ l.a.y = FixedMul(scale, l.a.y);
+ }
+ if (angle)
+ AM_rotate(&l.a.x, &l.a.y, angle);
+ l.a.x += x;
+ l.a.y += y;
+
+ l.b.x = lineguy[i].b.x;
+ l.b.y = lineguy[i].b.y;
+ if (scale)
+ {
+ l.b.x = FixedMul(scale, l.b.x);
+ l.b.y = FixedMul(scale, l.b.y);
+ }
+ if (angle)
+ AM_rotate(&l.b.x, &l.b.y, angle);
+ l.b.x += x;
+ l.b.y += y;
+
+ AM_drawMline(&l, color);
+ }
+}
+
+void AM_drawPlayers(void)
+{
+ int i;
+ player_t *p;
+ static int their_colors[] = {
+ AM_PLR1_COLOR,
+ AM_PLR2_COLOR,
+ AM_PLR3_COLOR,
+ AM_PLR4_COLOR,
+ AM_PLR5_COLOR,
+ AM_PLR6_COLOR,
+ AM_PLR7_COLOR,
+ AM_PLR8_COLOR
+ };
+ int their_color = -1;
+ int color;
+
+ if (!netgame)
+ {
+ AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 0, plr->mo->angle,
+ WHITE, plr->mo->x, plr->mo->y);
+ return;
+ }
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ their_color++;
+ p = &players[i];
+ if (deathmatch && !singledemo && p != plr)
+ {
+ continue;
+ }
+ if (!playeringame[i])
+ continue;
+ color = their_colors[their_color];
+ AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 0, p->mo->angle,
+ color, p->mo->x, p->mo->y);
+ }
+}
+
+void AM_drawThings(int colors, int colorrange)
+{
+ int i;
+ mobj_t *t;
+
+ for (i = 0; i < numsectors; i++)
+ {
+ t = sectors[i].thinglist;
+ while (t)
+ {
+ AM_drawLineCharacter(thintriangle_guy, NUMTHINTRIANGLEGUYLINES,
+ 16 << FRACBITS, t->angle, colors + lightlev,
+ t->x, t->y);
+ t = t->snext;
+ }
+ }
+}
+
+/*
+void AM_drawMarks(void)
+{
+ int i, fx, fy, w, h;
+
+ for (i=0;i<AM_NUMMARKPOINTS;i++)
+ {
+ if (markpoints[i].x != -1)
+ {
+ w = SHORT(marknums[i]->width);
+ h = SHORT(marknums[i]->height);
+ fx = CXMTOF(markpoints[i].x);
+ fy = CYMTOF(markpoints[i].y);
+ if (fx >= f_x && fx <= f_w - w && fy >= f_y && fy <= f_h - h)
+ V_DrawPatch(fx, fy, marknums[i]);
+ }
+ }
+}
+*/
+/*
+void AM_drawkeys(void)
+{
+ if(KeyPoints[0].x != 0 || KeyPoints[0].y != 0)
+ {
+ AM_drawLineCharacter(keysquare, NUMKEYSQUARELINES, 0, 0, YELLOWKEY,
+ KeyPoints[0].x, KeyPoints[0].y);
+ }
+ if(KeyPoints[1].x != 0 || KeyPoints[1].y != 0)
+ {
+ AM_drawLineCharacter(keysquare, NUMKEYSQUARELINES, 0, 0, GREENKEY,
+ KeyPoints[1].x, KeyPoints[1].y);
+ }
+ if(KeyPoints[2].x != 0 || KeyPoints[2].y != 0)
+ {
+ AM_drawLineCharacter(keysquare, NUMKEYSQUARELINES, 0, 0, BLUEKEY,
+ KeyPoints[2].x, KeyPoints[2].y);
+ }
+}
+*/
+
+/*
+void AM_drawCrosshair(int color)
+{
+ fb[(f_w*(f_h+1))/2] = color; // single point for now
+}
+*/
+
+void AM_Drawer(void)
+{
+ if (!automapactive)
+ return;
+
+ UpdateState |= I_FULLSCRN;
+ AM_clearFB(BACKGROUND);
+ if (grid)
+ AM_drawGrid(GRIDCOLORS);
+ AM_drawWalls();
+ AM_drawPlayers();
+ DrawWorldTimer();
+
+ if (cheating == 2)
+ AM_drawThings(THINGCOLORS, THINGRANGE);
+
+// AM_drawCrosshair(XHAIRCOLORS);
+// AM_drawMarks();
+// if(gameskill == sk_baby) AM_drawkeys();
+
+ MN_DrTextA(P_GetMapName(gamemap), 38, 144);
+ if (ShowKills && netgame && deathmatch)
+ {
+ AM_DrawDeathmatchStats();
+ }
+// I_Update();
+// V_MarkRect(f_x, f_y, f_w, f_h);
+
+}
+
+//===========================================================================
+//
+// AM_DrawDeathmatchStats
+//
+//===========================================================================
+
+// 8-player note: Proper player color names here, too
+
+char *PlayerColorText[MAXPLAYERS] = {
+ "BLUE:",
+ "RED:",
+ "YELLOW:",
+ "GREEN:",
+ "JADE:",
+ "WHITE:",
+ "HAZEL:",
+ "PURPLE:"
+};
+
+void AM_DrawDeathmatchStats(void)
+{
+ int i, j, k, m;
+ int fragCount[MAXPLAYERS];
+ int order[MAXPLAYERS];
+ char textBuffer[80];
+ int yPosition;
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ fragCount[i] = 0;
+ order[i] = -1;
+ }
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (!playeringame[i])
+ {
+ continue;
+ }
+ else
+ {
+ for (j = 0; j < MAXPLAYERS; j++)
+ {
+ if (playeringame[j])
+ {
+ fragCount[i] += players[i].frags[j];
+ }
+ }
+ for (k = 0; k < MAXPLAYERS; k++)
+ {
+ if (order[k] == -1)
+ {
+ order[k] = i;
+ break;
+ }
+ else if (fragCount[i] > fragCount[order[k]])
+ {
+ for (m = MAXPLAYERS - 1; m > k; m--)
+ {
+ order[m] = order[m - 1];
+ }
+ order[k] = i;
+ break;
+ }
+ }
+ }
+ }
+ yPosition = 15;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (!playeringame[order[i]])
+ {
+ continue;
+ }
+ else
+ {
+ MN_DrTextA(PlayerColorText[order[i]], 8, yPosition);
+ sprintf(textBuffer, "%d", fragCount[order[i]]);
+ MN_DrTextA(textBuffer, 80, yPosition);
+ yPosition += 10;
+ }
+ }
+}
+
+//===========================================================================
+//
+// DrawWorldTimer
+//
+//===========================================================================
+
+static void DrawWorldTimer(void)
+{
+ int days;
+ int hours;
+ int minutes;
+ int seconds;
+ int worldTimer;
+ char timeBuffer[15];
+ char dayBuffer[20];
+
+ worldTimer = players[consoleplayer].worldTimer;
+
+ worldTimer /= 35;
+ days = worldTimer / 86400;
+ worldTimer -= days * 86400;
+ hours = worldTimer / 3600;
+ worldTimer -= hours * 3600;
+ minutes = worldTimer / 60;
+ worldTimer -= minutes * 60;
+ seconds = worldTimer;
+
+ sprintf(timeBuffer, "%.2d : %.2d : %.2d", hours, minutes, seconds);
+ MN_DrTextA(timeBuffer, 240, 8);
+
+ if (days)
+ {
+ if (days == 1)
+ {
+ sprintf(dayBuffer, "%.2d DAY", days);
+ }
+ else
+ {
+ sprintf(dayBuffer, "%.2d DAYS", days);
+ }
+ MN_DrTextA(dayBuffer, 240, 20);
+ if (days >= 5)
+ {
+ MN_DrTextA("YOU FREAK!!!", 230, 35);
+ }
+ }
+}
diff --git a/src/hexen/am_map.h b/src/hexen/am_map.h
new file mode 100644
index 00000000..1be272a0
--- /dev/null
+++ b/src/hexen/am_map.h
@@ -0,0 +1,130 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __AMMAP_H__
+#define __AMMAP_H__
+
+// For use if I do walls with outsides/insides
+#define REDS 12*8
+#define REDRANGE 1 //16
+#define BLUES (256-4*16+8)
+#define BLUERANGE 1 //8
+#define GREENS (33*8)
+#define GREENRANGE 1 //16
+#define GRAYS (5*8)
+#define GRAYSRANGE 1 //16
+#define BROWNS (14*8)
+#define BROWNRANGE 1 //16
+#define YELLOWS 10*8
+#define YELLOWRANGE 1
+#define BLACK 0
+#define WHITE 4*8
+#define PARCH 13*8-1
+#define BLOODRED 177
+#define BLUEKEY 157
+#define YELLOWKEY 137
+#define GREENKEY 198
+
+// Automap colors
+
+#define AM_PLR1_COLOR 157 // Blue
+#define AM_PLR2_COLOR 177 // Red
+#define AM_PLR3_COLOR 137 // Yellow
+#define AM_PLR4_COLOR 198 // Green
+#define AM_PLR5_COLOR 215 // Jade
+#define AM_PLR6_COLOR 32 // White
+#define AM_PLR7_COLOR 106 // Hazel
+#define AM_PLR8_COLOR 234 // Purple
+
+#define BACKGROUND PARCH
+#define YOURCOLORS WHITE
+#define YOURRANGE 0
+#define WALLCOLORS REDS
+#define WALLRANGE REDRANGE
+#define TSWALLCOLORS GRAYS
+#define TSWALLRANGE GRAYSRANGE
+#define FDWALLCOLORS BROWNS
+#define FDWALLRANGE BROWNRANGE
+#define CDWALLCOLORS YELLOWS
+#define CDWALLRANGE YELLOWRANGE
+#define THINGCOLORS GREENS
+#define THINGRANGE GREENRANGE
+#define SECRETWALLCOLORS WALLCOLORS
+#define SECRETWALLRANGE WALLRANGE
+#define GRIDCOLORS (GRAYS + GRAYSRANGE/2)
+#define GRIDRANGE 0
+#define XHAIRCOLORS GRAYS
+
+// drawing stuff
+
+#define AM_NUMMARKPOINTS 10
+
+#define AM_MSGHEADER (('a'<<24)+('m'<<16))
+#define AM_MSGENTERED (AM_MSGHEADER | ('e'<<8))
+#define AM_MSGEXITED (AM_MSGHEADER | ('x'<<8))
+
+#define INITSCALEMTOF (.2*FRACUNIT) // scale on entry
+// how much the automap moves window per tic in frame-buffer coordinates
+#define F_PANINC 4 // moves 140 pixels in 1 second
+// how much zoom-in per tic
+#define M_ZOOMIN ((int) (1.02*FRACUNIT)) // goes to 2x in 1 second
+// how much zoom-out per tic
+#define M_ZOOMOUT ((int) (FRACUNIT/1.02)) // pulls out to 0.5x in 1 second
+
+// translates between frame-buffer and map distances
+#define FTOM(x) FixedMul(((x)<<16),scale_ftom)
+#define MTOF(x) (FixedMul((x),scale_mtof)>>16)
+// translates between frame-buffer and map coordinates
+#define CXMTOF(x) (f_x + MTOF((x)-m_x))
+#define CYMTOF(y) (f_y + (f_h - MTOF((y)-m_y)))
+
+// the following is crap
+#define LINE_NEVERSEE ML_DONTDRAW
+
+typedef struct
+{
+ int x, y;
+} fpoint_t;
+
+typedef struct
+{
+ fpoint_t a, b;
+} fline_t;
+
+typedef vertex_t mpoint_t;
+
+typedef struct
+{
+ mpoint_t a, b;
+} mline_t;
+
+typedef struct
+{
+ fixed_t slp, islp;
+} islope_t;
+
+// extern int f_x, f_y, f_w, f_h;
+
+#endif
diff --git a/src/hexen/ct_chat.c b/src/hexen/ct_chat.c
new file mode 100644
index 00000000..6ef39e44
--- /dev/null
+++ b/src/hexen/ct_chat.c
@@ -0,0 +1,510 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#include <string.h>
+#include <ctype.h>
+#include "h2def.h"
+#include "s_sound.h"
+#include "doomkeys.h"
+#include "m_controls.h"
+#include "p_local.h"
+#include "v_video.h"
+
+#define NUMKEYS 256
+
+#define QUEUESIZE 128
+#define MESSAGESIZE 128
+#define MESSAGELEN 265
+
+// 8-player note: Change this stuff (CT_PLR_*, and the key mappings)
+enum
+{
+ CT_PLR_BLUE = 1,
+ CT_PLR_RED,
+ CT_PLR_YELLOW,
+ CT_PLR_GREEN,
+ CT_PLR_PLAYER5,
+ CT_PLR_PLAYER6,
+ CT_PLR_PLAYER7,
+ CT_PLR_PLAYER8,
+ CT_PLR_ALL
+};
+
+#define CT_ESCAPE 6
+
+// Public data
+
+
+boolean chatmodeon;
+
+// Private data
+
+void CT_queueChatChar(char ch);
+void CT_ClearChatMessage(int player);
+void CT_AddChar(int player, char c);
+void CT_BackSpace(int player);
+
+int head;
+int tail;
+byte ChatQueue[QUEUESIZE];
+int chat_dest[MAXPLAYERS];
+char chat_msg[MAXPLAYERS][MESSAGESIZE];
+char plr_lastmsg[MAXPLAYERS][MESSAGESIZE + 9];
+int msgptr[MAXPLAYERS];
+int msglen[MAXPLAYERS];
+
+boolean cheated;
+
+static int FontABaseLump;
+
+char *CT_FromPlrText[MAXPLAYERS] = {
+ "BLUE: ",
+ "RED: ",
+ "YELLOW: ",
+ "GREEN: ",
+ "JADE: ",
+ "WHITE: ",
+ "HAZEL: ",
+ "PURPLE: "
+};
+
+char *chat_macros[10] = {
+ HUSTR_CHATMACRO0,
+ HUSTR_CHATMACRO1,
+ HUSTR_CHATMACRO2,
+ HUSTR_CHATMACRO3,
+ HUSTR_CHATMACRO4,
+ HUSTR_CHATMACRO5,
+ HUSTR_CHATMACRO6,
+ HUSTR_CHATMACRO7,
+ HUSTR_CHATMACRO8,
+ HUSTR_CHATMACRO9,
+};
+
+boolean altdown;
+boolean shiftdown;
+
+extern boolean usearti;
+
+//===========================================================================
+//
+// CT_Init
+//
+// Initialize chat mode data
+//===========================================================================
+
+void CT_Init(void)
+{
+ int i;
+
+ head = 0; //initialize the queue index
+ tail = 0;
+ chatmodeon = false;
+ memset(ChatQueue, 0, QUEUESIZE);
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ chat_dest[i] = 0;
+ msgptr[i] = 0;
+ memset(plr_lastmsg[i], 0, MESSAGESIZE);
+ memset(chat_msg[i], 0, MESSAGESIZE);
+ }
+ FontABaseLump = W_GetNumForName("FONTA_S") + 1;
+ return;
+}
+
+//===========================================================================
+//
+// CT_Stop
+//
+//===========================================================================
+
+void CT_Stop(void)
+{
+ chatmodeon = false;
+ return;
+}
+
+// These keys are allowed by Vanilla Heretic:
+
+static boolean ValidChatChar(char c)
+{
+ return (c >= 'a' && c <= 'z')
+ || (c >= 'A' && c <= 'Z')
+ || (c >= '0' && c <= '9')
+ || c == '!' || c == '?'
+ || c == ' ' || c == '\''
+ || c == ',' || c == '.'
+ || c == '-' || c == '=';
+}
+
+//===========================================================================
+//
+// CT_Responder
+//
+//===========================================================================
+
+boolean CT_Responder(event_t * ev)
+{
+ char *macro;
+
+ int sendto;
+
+ if (!netgame)
+ {
+ return false;
+ }
+ if (ev->data1 == KEY_RALT)
+ {
+ altdown = (ev->type == ev_keydown);
+ return false;
+ }
+ if (ev->data1 == KEY_RSHIFT)
+ {
+ shiftdown = (ev->type == ev_keydown);
+ return false;
+ }
+ if (gamestate != GS_LEVEL || ev->type != ev_keydown)
+ {
+ return false;
+ }
+ if (!chatmodeon)
+ {
+ sendto = 0;
+ if (ev->data1 == key_multi_msg)
+ {
+ sendto = CT_PLR_ALL;
+ }
+ else if (ev->data1 == key_multi_msgplayer[0])
+ {
+ sendto = CT_PLR_BLUE;
+ }
+ else if (ev->data1 == key_multi_msgplayer[1])
+ {
+ sendto = CT_PLR_RED;
+ }
+ else if (ev->data1 == key_multi_msgplayer[2])
+ {
+ sendto = CT_PLR_YELLOW;
+ }
+ else if (ev->data1 == key_multi_msgplayer[3])
+ {
+ sendto = CT_PLR_GREEN;
+ }
+ else if (ev->data1 == key_multi_msgplayer[4])
+ {
+ sendto = CT_PLR_PLAYER5;
+ }
+ else if (ev->data1 == key_multi_msgplayer[5])
+ {
+ sendto = CT_PLR_PLAYER6;
+ }
+ else if (ev->data1 == key_multi_msgplayer[6])
+ {
+ sendto = CT_PLR_PLAYER7;
+ }
+ else if (ev->data1 == key_multi_msgplayer[7])
+ {
+ sendto = CT_PLR_PLAYER8;
+ }
+ if (sendto == 0 || (sendto != CT_PLR_ALL && !playeringame[sendto - 1])
+ || sendto == consoleplayer + 1)
+ {
+ return false;
+ }
+ CT_queueChatChar(sendto);
+ chatmodeon = true;
+ return true;
+ }
+ else
+ {
+ if (altdown)
+ {
+ if (ev->data1 >= '0' && ev->data1 <= '9')
+ {
+ if (ev->data1 == '0')
+ { // macro 0 comes after macro 9
+ ev->data1 = '9' + 1;
+ }
+ macro = chat_macros[ev->data1 - '1'];
+ CT_queueChatChar(KEY_ENTER); //send old message
+ CT_queueChatChar(chat_dest[consoleplayer]); // chose the dest.
+ while (*macro)
+ {
+ CT_queueChatChar(toupper(*macro++));
+ }
+ CT_queueChatChar(KEY_ENTER); //send it off...
+ CT_Stop();
+ return true;
+ }
+ }
+ if (ev->data1 == KEY_ENTER)
+ {
+ CT_queueChatChar(KEY_ENTER);
+ usearti = false;
+ CT_Stop();
+ return true;
+ }
+ else if (ev->data1 == KEY_ESCAPE)
+ {
+ CT_queueChatChar(CT_ESCAPE);
+ CT_Stop();
+ return true;
+ }
+ else if (ev->data1 == KEY_BACKSPACE)
+ {
+ CT_queueChatChar(KEY_BACKSPACE);
+ return true;
+ }
+ else if (ValidChatChar(ev->data2))
+ {
+ CT_queueChatChar(toupper(ev->data2));
+ return true;
+ }
+ }
+ return false;
+}
+
+//===========================================================================
+//
+// CT_Ticker
+//
+//===========================================================================
+
+void CT_Ticker(void)
+{
+ int i;
+ int j;
+ char c;
+ int numplayers;
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (!playeringame[i])
+ {
+ continue;
+ }
+ if ((c = players[i].cmd.chatchar) != 0)
+ {
+ if (c <= CT_PLR_ALL)
+ {
+ chat_dest[i] = c;
+ continue;
+ }
+ else if (c == CT_ESCAPE)
+ {
+ CT_ClearChatMessage(i);
+ }
+ else if (c == KEY_ENTER)
+ {
+ numplayers = 0;
+ for (j = 0; j < MAXPLAYERS; j++)
+ {
+ numplayers += playeringame[j];
+ }
+ CT_AddChar(i, 0); // set the end of message character
+ if (numplayers > 2)
+ {
+ strcpy(plr_lastmsg[i], CT_FromPlrText[i]);
+ strcat(plr_lastmsg[i], chat_msg[i]);
+ }
+ else
+ {
+ strcpy(plr_lastmsg[i], chat_msg[i]);
+ }
+ if (i != consoleplayer && (chat_dest[i] == consoleplayer + 1
+ || chat_dest[i] == CT_PLR_ALL)
+ && *chat_msg[i])
+ {
+ P_SetMessage(&players[consoleplayer], plr_lastmsg[i],
+ true);
+ S_StartSound(NULL, SFX_CHAT);
+ }
+ else if (i == consoleplayer && (*chat_msg[i]))
+ {
+ if (numplayers <= 1)
+ {
+ P_SetMessage(&players[consoleplayer],
+ "THERE ARE NO OTHER PLAYERS IN THE GAME!",
+ true);
+ S_StartSound(NULL, SFX_CHAT);
+ }
+ }
+ CT_ClearChatMessage(i);
+ }
+ else if (c == KEY_BACKSPACE)
+ {
+ CT_BackSpace(i);
+ }
+ else
+ {
+ CT_AddChar(i, c);
+ }
+ }
+ }
+ return;
+}
+
+//===========================================================================
+//
+// CT_Drawer
+//
+//===========================================================================
+
+void CT_Drawer(void)
+{
+ int i;
+ int x;
+ patch_t *patch;
+
+ if (chatmodeon)
+ {
+ x = 25;
+ for (i = 0; i < msgptr[consoleplayer]; i++)
+ {
+ if (chat_msg[consoleplayer][i] < 33)
+ {
+ x += 6;
+ }
+ else
+ {
+ patch = W_CacheLumpNum(FontABaseLump +
+ chat_msg[consoleplayer][i] - 33,
+ PU_CACHE);
+ V_DrawPatch(x, 10, patch);
+ x += patch->width;
+ }
+ }
+ V_DrawPatch(x, 10, W_CacheLumpName("FONTA59", PU_CACHE));
+ BorderTopRefresh = true;
+ UpdateState |= I_MESSAGES;
+ }
+}
+
+//===========================================================================
+//
+// CT_queueChatChar
+//
+//===========================================================================
+
+void CT_queueChatChar(char ch)
+{
+ if (((tail + 1) & (QUEUESIZE - 1)) == head)
+ { // the queue is full
+ return;
+ }
+ ChatQueue[tail] = ch;
+ tail = (tail + 1) & (QUEUESIZE - 1);
+}
+
+//===========================================================================
+//
+// CT_dequeueChatChar
+//
+//===========================================================================
+
+char CT_dequeueChatChar(void)
+{
+ byte temp;
+
+ if (head == tail)
+ { // queue is empty
+ return 0;
+ }
+ temp = ChatQueue[head];
+ head = (head + 1) & (QUEUESIZE - 1);
+ return temp;
+}
+
+//===========================================================================
+//
+// CT_AddChar
+//
+//===========================================================================
+
+void CT_AddChar(int player, char c)
+{
+ patch_t *patch;
+
+ if (msgptr[player] + 1 >= MESSAGESIZE || msglen[player] >= MESSAGELEN)
+ { // full.
+ return;
+ }
+ chat_msg[player][msgptr[player]] = c;
+ msgptr[player]++;
+ if (c < 33)
+ {
+ msglen[player] += 6;
+ }
+ else
+ {
+ patch = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
+ msglen[player] += patch->width;
+ }
+}
+
+//===========================================================================
+//
+// CT_BackSpace
+//
+// Backs up a space, when the user hits (obviously) backspace
+//===========================================================================
+
+void CT_BackSpace(int player)
+{
+ patch_t *patch;
+ char c;
+
+ if (msgptr[player] == 0)
+ { // message is already blank
+ return;
+ }
+ msgptr[player]--;
+ c = chat_msg[player][msgptr[player]];
+ if (c < 33)
+ {
+ msglen[player] -= 6;
+ }
+ else
+ {
+ patch = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
+ msglen[player] -= patch->width;
+ }
+ chat_msg[player][msgptr[player]] = 0;
+}
+
+//===========================================================================
+//
+// CT_ClearChatMessage
+//
+// Clears out the data for the chat message, but the player's message
+// is still saved in plrmsg.
+//===========================================================================
+
+void CT_ClearChatMessage(int player)
+{
+ memset(chat_msg[player], 0, MESSAGESIZE);
+ msgptr[player] = 0;
+ msglen[player] = 0;
+}
diff --git a/setup/m_argv.h b/src/hexen/ct_chat.h
index bd1518b9..e390c28b 100644
--- a/setup/m_argv.h
+++ b/src/hexen/ct_chat.h
@@ -2,7 +2,8 @@
//-----------------------------------------------------------------------------
//
// Copyright(C) 1993-1996 Id Software, Inc.
-// Copyright(C) 2005 Simon Howard
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -19,24 +20,27 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
-// DESCRIPTION:
-// Nil.
-//
//-----------------------------------------------------------------------------
-
-
-#ifndef __M_ARGV__
-#define __M_ARGV__
-
//
-// MISC
+// Chat mode stuff
//
-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);
+#ifndef HEXEN_CT_CHAT_H
+#define HEXEN_CT_CHAT_H
+#define CT_PLR_GREEN 1
+#define CT_PLR_YELLOW 2
+#define CT_PLR_RED 3
+#define CT_PLR_BLUE 4
+#define CT_PLR_ALL 5
+
+#define CT_KEY_GREEN 'g'
+#define CT_KEY_YELLOW 'y'
+#define CT_KEY_RED 'r'
+#define CT_KEY_BLUE 'b'
+#define CT_KEY_ALL 't'
+
+extern char *chat_macros[10];
#endif
+
diff --git a/src/hexen/d_net.c b/src/hexen/d_net.c
new file mode 100644
index 00000000..7d663154
--- /dev/null
+++ b/src/hexen/d_net.c
@@ -0,0 +1,280 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// DOOM Network game communication and protocol,
+// all OS independend parts.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdlib.h>
+
+#include "doomfeatures.h"
+
+#include "m_argv.h"
+#include "i_system.h"
+#include "i_timer.h"
+#include "i_video.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "s_sound.h"
+#include "w_checksum.h"
+
+#include "deh_main.h"
+
+#include "d_loop.h"
+
+ticcmd_t *netcmds;
+
+extern void H2_DoAdvanceDemo(void);
+extern void H2_ProcessEvents(void);
+extern void G_BuildTiccmd(ticcmd_t *cmd, int maketic);
+extern boolean G_CheckDemoStatus(void);
+
+extern boolean demorecording;
+
+// Called when a player leaves the game
+
+static void PlayerQuitGame(player_t *player)
+{
+ static char exitmsg[80];
+ unsigned int player_num;
+
+ player_num = player - players;
+
+ strcpy(exitmsg, "PLAYER 1 LEFT THE GAME");
+ exitmsg[7] += player_num;
+ P_SetMessage(&players[consoleplayer], exitmsg, true);
+ S_StartSound(NULL, SFX_CHAT);
+
+ playeringame[player_num] = false;
+
+ // TODO: check if it is sensible to do this:
+
+ if (demorecording)
+ {
+ G_CheckDemoStatus ();
+ }
+}
+
+static void RunTic(ticcmd_t *cmds, boolean *ingame)
+{
+ extern boolean advancedemo;
+ unsigned int i;
+
+ // Check for player quits.
+
+ for (i = 0; i < MAXPLAYERS; ++i)
+ {
+ if (!demoplayback && playeringame[i] && !ingame[i])
+ {
+ PlayerQuitGame(&players[i]);
+ }
+ }
+
+ netcmds = cmds;
+
+ // check that there are players in the game. if not, we cannot
+ // run a tic.
+
+ if (advancedemo)
+ H2_DoAdvanceDemo ();
+
+ G_Ticker ();
+}
+
+static loop_interface_t hexen_loop_interface = {
+ H2_ProcessEvents,
+ G_BuildTiccmd,
+ RunTic,
+ MN_Ticker
+};
+
+
+// Load game settings from the specified structure and
+// set global variables.
+
+static void LoadGameSettings(net_gamesettings_t *settings,
+ net_connect_data_t *connect_data)
+{
+ unsigned int i;
+
+ deathmatch = settings->deathmatch;
+ ticdup = settings->ticdup;
+ startepisode = settings->episode;
+ startmap = settings->map;
+ startskill = settings->skill;
+ // TODO startloadgame = settings->loadgame;
+ nomonsters = settings->nomonsters;
+ respawnparm = settings->respawn_monsters;
+
+ if (!connect_data->drone)
+ {
+ consoleplayer = settings->consoleplayer;
+ }
+ else
+ {
+ consoleplayer = 0;
+ }
+
+ for (i=0; i<MAXPLAYERS; ++i)
+ {
+ playeringame[i] = i < settings->num_players;
+ PlayerClass[i] = settings->player_classes[i];
+
+ if (PlayerClass[i] >= NUMCLASSES)
+ {
+ PlayerClass[i] = PCLASS_FIGHTER;
+ }
+ }
+}
+
+// Save the game settings from global variables to the specified
+// game settings structure.
+
+static void SaveGameSettings(net_gamesettings_t *settings,
+ net_connect_data_t *connect_data)
+{
+ int i;
+
+ // jhaley 20120715: Some parts of the structure are being left
+ // uninitialized. If -class is not used on the command line, this
+ // can lead to a crash in SB_Init due to player class == 0xCCCCCCCC.
+ memset(settings, 0, sizeof(*settings));
+
+ // Fill in game settings structure with appropriate parameters
+ // for the new game
+
+ settings->deathmatch = deathmatch;
+ settings->episode = startepisode;
+ settings->map = startmap;
+ settings->skill = startskill;
+ // TODO settings->loadgame = startloadgame;
+ settings->gameversion = exe_hexen_1_1;
+ settings->nomonsters = nomonsters;
+ settings->respawn_monsters = respawnparm;
+ settings->timelimit = 0;
+ settings->lowres_turn = false;
+
+ //
+ // Connect data
+ //
+
+ // Game type fields:
+
+ connect_data->gamemode = gamemode;
+ connect_data->gamemission = gamemission;
+
+ connect_data->lowres_turn = false;
+ connect_data->drone = false;
+ connect_data->max_players = MAXPLAYERS;
+
+ //!
+ // @category net
+ // @arg <n>
+ //
+ // Specify player class: 0=fighter, 1=cleric, 2=mage, 3=pig.
+ //
+
+ i = M_CheckParmWithArgs("-class", 1);
+
+ if (i > 0)
+ {
+ connect_data->player_class = atoi(myargv[i + 1]);
+ }
+ else
+ {
+ connect_data->player_class = PCLASS_FIGHTER;
+ }
+
+ // Read checksums of our WAD directory and dehacked information
+
+ W_Checksum(connect_data->wad_sha1sum);
+ memset(connect_data->deh_sha1sum, 0, sizeof(sha1_digest_t));
+
+ connect_data->is_freedoom = 0;
+}
+
+void D_InitSinglePlayerGame(net_gamesettings_t *settings)
+{
+ // default values for single player
+
+ settings->consoleplayer = 0;
+ settings->num_players = 1;
+
+ netgame = false;
+
+ //!
+ // @category net
+ //
+ // Start the game playing as though in a netgame with a single
+ // player. This can also be used to play back single player netgame
+ // demos.
+ //
+
+ if (M_CheckParm("-solo-net") > 0)
+ {
+ netgame = true;
+ }
+}
+
+//
+// D_CheckNetGame
+// Works out player numbers among the net participants
+//
+
+void D_CheckNetGame (void)
+{
+ net_connect_data_t connect_data;
+ net_gamesettings_t settings;
+
+ D_RegisterLoopCallbacks(&hexen_loop_interface);
+
+ // Call D_QuitNetGame on exit
+
+ I_AtExit(D_QuitNetGame, true);
+
+ SaveGameSettings(&settings, &connect_data);
+
+ if (D_InitNetGame(&connect_data, &settings))
+ {
+ netgame = true;
+ autostart = true;
+ }
+ else
+ {
+ D_InitSinglePlayerGame(&settings);
+ }
+
+ LoadGameSettings(&settings, &connect_data);
+}
+
+//==========================================================================
+//
+// NET_SendFrags
+//
+//==========================================================================
+
+void NET_SendFrags(player_t * player)
+{
+ // Not sure what this is intended for. Unused?
+}
+
diff --git a/src/hexen/f_finale.c b/src/hexen/f_finale.c
new file mode 100644
index 00000000..e728ae58
--- /dev/null
+++ b/src/hexen/f_finale.c
@@ -0,0 +1,395 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2def.h"
+#include "i_system.h"
+#include "i_video.h"
+#include "p_local.h"
+#include "s_sound.h"
+#include <ctype.h>
+#include "v_video.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define TEXTSPEED 3
+#define TEXTWAIT 250
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void TextWrite(void);
+static void DrawPic(void);
+static void InitializeFade(boolean fadeIn);
+static void DeInitializeFade(void);
+static void FadePic(void);
+static char *GetFinaleText(int sequence);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern boolean automapactive;
+extern boolean viewactive;
+
+// PUBLIC DATA DECLARATIONS ------------------------------------------------
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static int FinaleStage;
+static int FinaleCount;
+static int FinaleEndCount;
+static int FinaleLumpNum;
+static int FontABaseLump;
+static char *FinaleText;
+
+static fixed_t *Palette;
+static fixed_t *PaletteDelta;
+static byte *RealPalette;
+
+// CODE --------------------------------------------------------------------
+
+//===========================================================================
+//
+// F_StartFinale
+//
+//===========================================================================
+
+void F_StartFinale(void)
+{
+ gameaction = ga_nothing;
+ gamestate = GS_FINALE;
+ viewactive = false;
+ automapactive = false;
+ P_ClearMessage(&players[consoleplayer]);
+
+ FinaleStage = 0;
+ FinaleCount = 0;
+ FinaleText = GetFinaleText(0);
+ FinaleEndCount = 70;
+ FinaleLumpNum = W_GetNumForName("FINALE1");
+ FontABaseLump = W_GetNumForName("FONTA_S") + 1;
+ InitializeFade(1);
+
+// S_ChangeMusic(mus_victor, true);
+ S_StartSongName("hall", false); // don't loop the song
+}
+
+//===========================================================================
+//
+// F_Responder
+//
+//===========================================================================
+
+boolean F_Responder(event_t * event)
+{
+ return false;
+}
+
+//===========================================================================
+//
+// F_Ticker
+//
+//===========================================================================
+
+void F_Ticker(void)
+{
+ FinaleCount++;
+ if (FinaleStage < 5 && FinaleCount >= FinaleEndCount)
+ {
+ FinaleCount = 0;
+ FinaleStage++;
+ switch (FinaleStage)
+ {
+ case 1: // Text 1
+ FinaleEndCount = strlen(FinaleText) * TEXTSPEED + TEXTWAIT;
+ break;
+ case 2: // Pic 2, Text 2
+ FinaleText = GetFinaleText(1);
+ FinaleEndCount = strlen(FinaleText) * TEXTSPEED + TEXTWAIT;
+ FinaleLumpNum = W_GetNumForName("FINALE2");
+ S_StartSongName("orb", false);
+ break;
+ case 3: // Pic 2 -- Fade out
+ FinaleEndCount = 70;
+ DeInitializeFade();
+ InitializeFade(0);
+ break;
+ case 4: // Pic 3 -- Fade in
+ FinaleLumpNum = W_GetNumForName("FINALE3");
+ FinaleEndCount = 71;
+ DeInitializeFade();
+ InitializeFade(1);
+ S_StartSongName("chess", true);
+ break;
+ case 5: // Pic 3 , Text 3
+ FinaleText = GetFinaleText(2);
+ DeInitializeFade();
+ break;
+ default:
+ break;
+ }
+ return;
+ }
+ if (FinaleStage == 0 || FinaleStage == 3 || FinaleStage == 4)
+ {
+ FadePic();
+ }
+}
+
+//===========================================================================
+//
+// TextWrite
+//
+//===========================================================================
+
+static void TextWrite(void)
+{
+ int count;
+ char *ch;
+ int c;
+ int cx, cy;
+ patch_t *w;
+
+ memcpy(I_VideoBuffer, W_CacheLumpNum(FinaleLumpNum, PU_CACHE),
+ SCREENWIDTH * SCREENHEIGHT);
+ if (FinaleStage == 5)
+ { // Chess pic, draw the correct character graphic
+ if (netgame)
+ {
+ V_DrawPatch(20, 0, W_CacheLumpName("chessall", PU_CACHE));
+ }
+ else if (PlayerClass[consoleplayer])
+ {
+ V_DrawPatch(60, 0, W_CacheLumpNum(W_GetNumForName("chessc")
+ + PlayerClass[consoleplayer] -
+ 1, PU_CACHE));
+ }
+ }
+ // Draw the actual text
+ if (FinaleStage == 5)
+ {
+ cy = 135;
+ }
+ else
+ {
+ cy = 5;
+ }
+ cx = 20;
+ ch = FinaleText;
+ count = (FinaleCount - 10) / TEXTSPEED;
+ if (count < 0)
+ {
+ count = 0;
+ }
+ for (; count; count--)
+ {
+ c = *ch++;
+ if (!c)
+ {
+ break;
+ }
+ if (c == '\n')
+ {
+ cx = 20;
+ cy += 9;
+ continue;
+ }
+ if (c < 32)
+ {
+ continue;
+ }
+ c = toupper(c);
+ if (c == 32)
+ {
+ cx += 5;
+ continue;
+ }
+ w = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
+ if (cx + w->width > SCREENWIDTH)
+ {
+ break;
+ }
+ V_DrawPatch(cx, cy, w);
+ cx += w->width;
+ }
+}
+
+//===========================================================================
+//
+// InitializeFade
+//
+//===========================================================================
+
+static void InitializeFade(boolean fadeIn)
+{
+ unsigned i;
+
+ Palette = Z_Malloc(768 * sizeof(fixed_t), PU_STATIC, 0);
+ PaletteDelta = Z_Malloc(768 * sizeof(fixed_t), PU_STATIC, 0);
+ RealPalette = Z_Malloc(768 * sizeof(byte), PU_STATIC, 0);
+
+ if (fadeIn)
+ {
+ memset(RealPalette, 0, 768 * sizeof(byte));
+ for (i = 0; i < 768; i++)
+ {
+ Palette[i] = 0;
+ PaletteDelta[i] = FixedDiv((*((byte *) W_CacheLumpName("playpal",
+ PU_CACHE) +
+ i)) << FRACBITS, 70 * FRACUNIT);
+ }
+ }
+ else
+ {
+ for (i = 0; i < 768; i++)
+ {
+ RealPalette[i] =
+ *((byte *) W_CacheLumpName("playpal", PU_CACHE) + i);
+ Palette[i] = RealPalette[i] << FRACBITS;
+ PaletteDelta[i] = FixedDiv(Palette[i], -70 * FRACUNIT);
+ }
+ }
+ I_SetPalette(RealPalette);
+}
+
+//===========================================================================
+//
+// DeInitializeFade
+//
+//===========================================================================
+
+static void DeInitializeFade(void)
+{
+ Z_Free(Palette);
+ Z_Free(PaletteDelta);
+ Z_Free(RealPalette);
+}
+
+//===========================================================================
+//
+// FadePic
+//
+//===========================================================================
+
+static void FadePic(void)
+{
+ unsigned i;
+
+ for (i = 0; i < 768; i++)
+ {
+ Palette[i] += PaletteDelta[i];
+ RealPalette[i] = Palette[i] >> FRACBITS;
+ }
+ I_SetPalette(RealPalette);
+}
+
+//===========================================================================
+//
+// DrawPic
+//
+//===========================================================================
+
+static void DrawPic(void)
+{
+ memcpy(I_VideoBuffer, W_CacheLumpNum(FinaleLumpNum, PU_CACHE),
+ SCREENWIDTH * SCREENHEIGHT);
+ if (FinaleStage == 4 || FinaleStage == 5)
+ { // Chess pic, draw the correct character graphic
+ if (netgame)
+ {
+ V_DrawPatch(20, 0, W_CacheLumpName("chessall", PU_CACHE));
+ }
+ else if (PlayerClass[consoleplayer])
+ {
+ V_DrawPatch(60, 0, W_CacheLumpNum(W_GetNumForName("chessc")
+ + PlayerClass[consoleplayer] -
+ 1, PU_CACHE));
+ }
+ }
+}
+
+//===========================================================================
+//
+// F_Drawer
+//
+//===========================================================================
+
+void F_Drawer(void)
+{
+ switch (FinaleStage)
+ {
+ case 0: // Fade in initial finale screen
+ DrawPic();
+ break;
+ case 1:
+ case 2:
+ TextWrite();
+ break;
+ case 3: // Fade screen out
+ DrawPic();
+ break;
+ case 4: // Fade in chess screen
+ DrawPic();
+ break;
+ case 5:
+ TextWrite();
+ break;
+ }
+ UpdateState |= I_FULLSCRN;
+}
+
+//==========================================================================
+//
+// GetFinaleText
+//
+//==========================================================================
+
+static char *GetFinaleText(int sequence)
+{
+ char *msgLumpName;
+ int msgSize;
+ int msgLump;
+ static char *winMsgLumpNames[] = {
+ "win1msg",
+ "win2msg",
+ "win3msg"
+ };
+
+ msgLumpName = winMsgLumpNames[sequence];
+ msgLump = W_GetNumForName(msgLumpName);
+ msgSize = W_LumpLength(msgLump);
+ if (msgSize >= MAX_INTRMSN_MESSAGE_SIZE)
+ {
+ I_Error("Finale message too long (%s)", msgLumpName);
+ }
+ W_ReadLump(msgLump, ClusterMessage);
+ ClusterMessage[msgSize] = 0; // Append terminator
+ return ClusterMessage;
+}
diff --git a/src/hexen/g_game.c b/src/hexen/g_game.c
new file mode 100644
index 00000000..707f2cac
--- /dev/null
+++ b/src/hexen/g_game.c
@@ -0,0 +1,1892 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#include <string.h>
+#include "m_random.h"
+#include "h2def.h"
+#include "s_sound.h"
+#include "doomkeys.h"
+#include "i_video.h"
+#include "i_system.h"
+#include "i_timer.h"
+#include "m_controls.h"
+#include "m_misc.h"
+#include "p_local.h"
+#include "v_video.h"
+
+#define AM_STARTKEY 9
+
+// External functions
+
+extern void R_InitSky(int map);
+extern void P_PlayerNextArtifact(player_t * player);
+
+// Functions
+
+boolean G_CheckDemoStatus(void);
+void G_ReadDemoTiccmd(ticcmd_t * cmd);
+void G_WriteDemoTiccmd(ticcmd_t * cmd);
+
+void G_DoReborn(int playernum);
+
+void G_DoLoadLevel(void);
+void G_DoInitNew(void);
+void G_DoNewGame(void);
+void G_DoPlayDemo(void);
+void G_DoTeleportNewMap(void);
+void G_DoCompleted(void);
+void G_DoVictory(void);
+void G_DoWorldDone(void);
+void G_DoSaveGame(void);
+void G_DoSingleReborn(void);
+
+void H2_PageTicker(void);
+void H2_AdvanceDemo(void);
+
+extern boolean mn_SuicideConsole;
+
+gameaction_t gameaction;
+gamestate_t gamestate;
+skill_t gameskill;
+//boolean respawnmonsters;
+int gameepisode;
+int gamemap;
+int prevmap;
+
+boolean paused;
+boolean sendpause; // send a pause event next tic
+boolean sendsave; // send a save event next tic
+boolean usergame; // ok to save / end game
+
+boolean timingdemo; // if true, exit with report on completion
+int starttime; // for comparative timing purposes
+
+boolean viewactive;
+
+boolean deathmatch; // only if started as net death
+boolean netgame; // only true if packets are broadcast
+boolean playeringame[MAXPLAYERS];
+player_t players[MAXPLAYERS];
+pclass_t PlayerClass[MAXPLAYERS];
+
+// Position indicator for cooperative net-play reborn
+int RebornPosition;
+
+int consoleplayer; // player taking events and displaying
+int displayplayer; // view being displayed
+int gametic;
+int levelstarttic; // gametic at level start
+
+char demoname[32];
+boolean demorecording;
+boolean demoplayback;
+byte *demobuffer, *demo_p;
+boolean singledemo; // quit after playing a demo from cmdline
+
+boolean precache = true; // if true, load all graphics at start
+
+// TODO: Hexen uses 16-bit shorts for consistancy?
+byte consistancy[MAXPLAYERS][BACKUPTICS];
+
+int mouseSensitivity = 5;
+
+int LeaveMap;
+static int LeavePosition;
+
+//#define MAXPLMOVE 0x32 // Old Heretic Max move
+
+fixed_t MaxPlayerMove[NUMCLASSES] = { 0x3C, 0x32, 0x2D, 0x31 };
+fixed_t forwardmove[NUMCLASSES][2] = {
+ {0x1D, 0x3C},
+ {0x19, 0x32},
+ {0x16, 0x2E},
+ {0x18, 0x31}
+};
+
+fixed_t sidemove[NUMCLASSES][2] = {
+ {0x1B, 0x3B},
+ {0x18, 0x28},
+ {0x15, 0x25},
+ {0x17, 0x27}
+};
+
+fixed_t angleturn[3] = { 640, 1280, 320 }; // + slow turn
+
+static int *weapon_keys[] =
+{
+ &key_weapon1,
+ &key_weapon2,
+ &key_weapon3,
+ &key_weapon4,
+};
+
+static int next_weapon = 0;
+
+#define SLOWTURNTICS 6
+
+#define NUMKEYS 256
+boolean gamekeydown[NUMKEYS];
+int turnheld; // for accelerative turning
+int lookheld;
+
+
+boolean mousearray[4];
+boolean *mousebuttons = &mousearray[1];
+ // allow [-1]
+int mousex, mousey; // mouse values are used once
+int dclicktime, dclickstate, dclicks;
+int dclicktime2, dclickstate2, dclicks2;
+
+#define MAX_JOY_BUTTONS 20
+
+int joyxmove, joyymove; // joystick values are repeated
+boolean joyarray[MAX_JOY_BUTTONS + 1];
+boolean *joybuttons = &joyarray[1]; // allow [-1]
+
+int savegameslot;
+char savedescription[32];
+
+int inventoryTics;
+
+// haleyjd: removed externdriver crap
+
+static skill_t TempSkill;
+static int TempEpisode;
+static int TempMap;
+
+boolean testcontrols = false;
+int testcontrols_mousespeed;
+
+//=============================================================================
+/*
+====================
+=
+= G_BuildTiccmd
+=
+= Builds a ticcmd from all of the available inputs or reads it from the
+= demo buffer.
+= If recording a demo, write it out
+====================
+*/
+
+extern boolean inventory;
+boolean usearti = true;
+
+void G_BuildTiccmd(ticcmd_t *cmd, int maketic)
+{
+ int i;
+ boolean strafe, bstrafe;
+ int speed, tspeed, lspeed;
+ int forward, side;
+ int look, arti;
+ int flyheight;
+ int pClass;
+
+ extern boolean artiskip;
+
+ // haleyjd: removed externdriver crap
+
+ pClass = players[consoleplayer].class;
+ memset(cmd, 0, sizeof(*cmd));
+
+// cmd->consistancy =
+// consistancy[consoleplayer][(maketic*ticdup)%BACKUPTICS];
+
+ cmd->consistancy = consistancy[consoleplayer][maketic % BACKUPTICS];
+
+//printf ("cons: %i\n",cmd->consistancy);
+
+ strafe = gamekeydown[key_strafe]
+ || mousebuttons[mousebstrafe]
+ || joybuttons[joybstrafe];
+
+ // Allow joybspeed hack.
+
+ speed = key_speed >= NUMKEYS
+ || joybspeed >= MAX_JOY_BUTTONS
+ || gamekeydown[key_speed]
+ || joybuttons[joybspeed];
+
+ // haleyjd: removed externdriver crap
+
+ forward = side = look = arti = flyheight = 0;
+
+//
+// use two stage accelerative turning on the keyboard and joystick
+//
+ if (joyxmove < 0 || joyxmove > 0
+ || gamekeydown[key_right] || gamekeydown[key_left])
+ turnheld += ticdup;
+ else
+ turnheld = 0;
+ if (turnheld < SLOWTURNTICS)
+ tspeed = 2; // slow turn
+ else
+ tspeed = speed;
+
+ if (gamekeydown[key_lookdown] || gamekeydown[key_lookup])
+ {
+ lookheld += ticdup;
+ }
+ else
+ {
+ lookheld = 0;
+ }
+ if (lookheld < SLOWTURNTICS)
+ {
+ lspeed = 1; // 3;
+ }
+ else
+ {
+ lspeed = 2; // 5;
+ }
+
+//
+// let movement keys cancel each other out
+//
+ if (strafe)
+ {
+ if (gamekeydown[key_right])
+ {
+ side += sidemove[pClass][speed];
+ }
+ if (gamekeydown[key_left])
+ {
+ side -= sidemove[pClass][speed];
+ }
+ if (joyxmove > 0)
+ {
+ side += sidemove[pClass][speed];
+ }
+ if (joyxmove < 0)
+ {
+ side -= sidemove[pClass][speed];
+ }
+ }
+ else
+ {
+ if (gamekeydown[key_right])
+ cmd->angleturn -= angleturn[tspeed];
+ if (gamekeydown[key_left])
+ cmd->angleturn += angleturn[tspeed];
+ if (joyxmove > 0)
+ cmd->angleturn -= angleturn[tspeed];
+ if (joyxmove < 0)
+ cmd->angleturn += angleturn[tspeed];
+ }
+
+ if (gamekeydown[key_up])
+ {
+ forward += forwardmove[pClass][speed];
+ }
+ if (gamekeydown[key_down])
+ {
+ forward -= forwardmove[pClass][speed];
+ }
+ if (joyymove < 0)
+ {
+ forward += forwardmove[pClass][speed];
+ }
+ if (joyymove > 0)
+ {
+ forward -= forwardmove[pClass][speed];
+ }
+ if (gamekeydown[key_straferight])
+ {
+ side += sidemove[pClass][speed];
+ }
+ if (gamekeydown[key_strafeleft])
+ {
+ side -= sidemove[pClass][speed];
+ }
+
+ // Look up/down/center keys
+ if (gamekeydown[key_lookup])
+ {
+ look = lspeed;
+ }
+ if (gamekeydown[key_lookdown])
+ {
+ look = -lspeed;
+ }
+ // haleyjd: removed externdriver crap
+ if (gamekeydown[key_lookcenter])
+ {
+ look = TOCENTER;
+ }
+
+ // haleyjd: removed externdriver crap
+
+ // Fly up/down/drop keys
+ if (gamekeydown[key_flyup])
+ {
+ flyheight = 5; // note that the actual flyheight will be twice this
+ }
+ if (gamekeydown[key_flydown])
+ {
+ flyheight = -5;
+ }
+ if (gamekeydown[key_flycenter])
+ {
+ flyheight = TOCENTER;
+ // haleyjd: removed externdriver crap
+ look = TOCENTER;
+ }
+ // Use artifact key
+ if (gamekeydown[key_useartifact])
+ {
+ if (gamekeydown[key_speed] && artiskip)
+ {
+ if (players[consoleplayer].inventory[inv_ptr].type != arti_none)
+ { // Skip an artifact
+ gamekeydown[key_useartifact] = false;
+ P_PlayerNextArtifact(&players[consoleplayer]);
+ }
+ }
+ else
+ {
+ if (inventory)
+ {
+ players[consoleplayer].readyArtifact =
+ players[consoleplayer].inventory[inv_ptr].type;
+ inventory = false;
+ cmd->arti = 0;
+ usearti = false;
+ }
+ else if (usearti)
+ {
+ cmd->arti |=
+ players[consoleplayer].inventory[inv_ptr].
+ type & AFLAG_MASK;
+ usearti = false;
+ }
+ }
+ }
+ if (gamekeydown[key_jump] || mousebuttons[mousebjump]
+ || joybuttons[joybjump])
+ {
+ cmd->arti |= AFLAG_JUMP;
+ }
+ if (mn_SuicideConsole)
+ {
+ cmd->arti |= AFLAG_SUICIDE;
+ mn_SuicideConsole = false;
+ }
+
+ // Artifact hot keys
+ if (gamekeydown[KEY_BACKSPACE] && !cmd->arti)
+ {
+ gamekeydown[KEY_BACKSPACE] = false; // Use one of each artifact
+ cmd->arti = NUMARTIFACTS;
+ }
+ else if (gamekeydown['\\'] && !cmd->arti
+ && (players[consoleplayer].mo->health < MAXHEALTH))
+ {
+ gamekeydown['\\'] = false;
+ cmd->arti = arti_health;
+ }
+ else if (gamekeydown['0'] && !cmd->arti)
+ {
+ gamekeydown['0'] = false;
+ cmd->arti = arti_poisonbag;
+ }
+ else if (gamekeydown['9'] && !cmd->arti)
+ {
+ gamekeydown['9'] = false;
+ cmd->arti = arti_blastradius;
+ }
+ else if (gamekeydown['8'] && !cmd->arti)
+ {
+ gamekeydown['8'] = false;
+ cmd->arti = arti_teleport;
+ }
+ else if (gamekeydown['7'] && !cmd->arti)
+ {
+ gamekeydown['7'] = false;
+ cmd->arti = arti_teleportother;
+ }
+ else if (gamekeydown['6'] && !cmd->arti)
+ {
+ gamekeydown['6'] = false;
+ cmd->arti = arti_egg;
+ }
+ else if (gamekeydown['5'] && !cmd->arti
+ && !players[consoleplayer].powers[pw_invulnerability])
+ {
+ gamekeydown['5'] = false;
+ cmd->arti = arti_invulnerability;
+ }
+
+//
+// buttons
+//
+ cmd->chatchar = CT_dequeueChatChar();
+
+ if (gamekeydown[key_fire] || mousebuttons[mousebfire]
+ || joybuttons[joybfire])
+ cmd->buttons |= BT_ATTACK;
+
+ if (gamekeydown[key_use] || joybuttons[joybuse])
+ {
+ cmd->buttons |= BT_USE;
+ dclicks = 0; // clear double clicks if hit use button
+ }
+
+ // Weapon cycling. Switch to previous or next weapon.
+ // (Disabled when player is a pig).
+
+ if (players[consoleplayer].morphTics == 0 && next_weapon != 0)
+ {
+ if (players[consoleplayer].pendingweapon == WP_NOCHANGE)
+ {
+ i = players[consoleplayer].readyweapon;
+ }
+ else
+ {
+ i = players[consoleplayer].pendingweapon;
+ }
+
+ do {
+ i = (i + next_weapon) % NUMWEAPONS;
+ } while (!players[consoleplayer].weaponowned[i]);
+
+ cmd->buttons |= BT_CHANGE;
+ cmd->buttons |= i << BT_WEAPONSHIFT;
+ }
+ else
+ {
+ for (i=0; i<arrlen(weapon_keys); ++i)
+ {
+ int key = *weapon_keys[i];
+
+ if (gamekeydown[key])
+ {
+ cmd->buttons |= BT_CHANGE;
+ cmd->buttons |= i<<BT_WEAPONSHIFT;
+ break;
+ }
+ }
+ }
+
+ next_weapon = 0;
+
+//
+// mouse
+//
+ if (mousebuttons[mousebforward])
+ {
+ forward += forwardmove[pClass][speed];
+ }
+
+//
+// forward double click
+//
+ if (mousebuttons[mousebforward] != dclickstate && dclicktime > 1)
+ {
+ dclickstate = mousebuttons[mousebforward];
+ if (dclickstate)
+ dclicks++;
+ if (dclicks == 2)
+ {
+ cmd->buttons |= BT_USE;
+ dclicks = 0;
+ }
+ else
+ dclicktime = 0;
+ }
+ else
+ {
+ dclicktime += ticdup;
+ if (dclicktime > 20)
+ {
+ dclicks = 0;
+ dclickstate = 0;
+ }
+ }
+
+//
+// strafe double click
+//
+ bstrafe = mousebuttons[mousebstrafe] || joybuttons[joybstrafe];
+ if (bstrafe != dclickstate2 && dclicktime2 > 1)
+ {
+ dclickstate2 = bstrafe;
+ if (dclickstate2)
+ dclicks2++;
+ if (dclicks2 == 2)
+ {
+ cmd->buttons |= BT_USE;
+ dclicks2 = 0;
+ }
+ else
+ dclicktime2 = 0;
+ }
+ else
+ {
+ dclicktime2 += ticdup;
+ if (dclicktime2 > 20)
+ {
+ dclicks2 = 0;
+ dclickstate2 = 0;
+ }
+ }
+
+ if (strafe)
+ {
+ side += mousex * 2;
+ }
+ else
+ {
+ cmd->angleturn -= mousex * 0x8;
+ }
+
+ if (mousex == 0)
+ {
+ testcontrols_mousespeed = 0;
+ }
+
+ forward += mousey;
+ mousex = mousey = 0;
+
+ if (forward > MaxPlayerMove[pClass])
+ {
+ forward = MaxPlayerMove[pClass];
+ }
+ else if (forward < -MaxPlayerMove[pClass])
+ {
+ forward = -MaxPlayerMove[pClass];
+ }
+ if (side > MaxPlayerMove[pClass])
+ {
+ side = MaxPlayerMove[pClass];
+ }
+ else if (side < -MaxPlayerMove[pClass])
+ {
+ side = -MaxPlayerMove[pClass];
+ }
+ if (players[consoleplayer].powers[pw_speed]
+ && !players[consoleplayer].morphTics)
+ { // Adjust for a player with a speed artifact
+ forward = (3 * forward) >> 1;
+ side = (3 * side) >> 1;
+ }
+ cmd->forwardmove += forward;
+ cmd->sidemove += side;
+ if (players[consoleplayer].playerstate == PST_LIVE)
+ {
+ if (look < 0)
+ {
+ look += 16;
+ }
+ cmd->lookfly = look;
+ }
+ if (flyheight < 0)
+ {
+ flyheight += 16;
+ }
+ cmd->lookfly |= flyheight << 4;
+
+//
+// special buttons
+//
+ if (sendpause)
+ {
+ sendpause = false;
+ cmd->buttons = BT_SPECIAL | BTS_PAUSE;
+ }
+
+ if (sendsave)
+ {
+ sendsave = false;
+ cmd->buttons =
+ BT_SPECIAL | BTS_SAVEGAME | (savegameslot << BTS_SAVESHIFT);
+ }
+}
+
+
+/*
+==============
+=
+= G_DoLoadLevel
+=
+==============
+*/
+
+void G_DoLoadLevel(void)
+{
+ int i;
+
+ levelstarttic = gametic; // for time calculation
+ gamestate = GS_LEVEL;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i] && players[i].playerstate == PST_DEAD)
+ players[i].playerstate = PST_REBORN;
+ memset(players[i].frags, 0, sizeof(players[i].frags));
+ }
+
+ SN_StopAllSequences();
+ P_SetupLevel(gameepisode, gamemap, 0, gameskill);
+ displayplayer = consoleplayer; // view the guy you are playing
+ starttime = I_GetTime();
+ gameaction = ga_nothing;
+ Z_CheckHeap();
+
+//
+// clear cmd building stuff
+//
+
+ memset(gamekeydown, 0, sizeof(gamekeydown));
+ joyxmove = joyymove = 0;
+ mousex = mousey = 0;
+ sendpause = sendsave = paused = false;
+ memset(mousebuttons, 0, sizeof(mousebuttons));
+ memset(joybuttons, 0, sizeof(joybuttons));
+
+ if (testcontrols)
+ {
+ P_SetMessage(&players[consoleplayer], "PRESS ESCAPE TO QUIT.", false);
+ }
+}
+
+
+/*
+===============================================================================
+=
+= G_Responder
+=
+= get info needed to make ticcmd_ts for the players
+=
+===============================================================================
+*/
+
+boolean G_Responder(event_t * ev)
+{
+ player_t *plr;
+ extern boolean MenuActive;
+
+ plr = &players[consoleplayer];
+ if (ev->type == ev_keyup && ev->data1 == key_useartifact)
+ { // flag to denote that it's okay to use an artifact
+ if (!inventory)
+ {
+ plr->readyArtifact = plr->inventory[inv_ptr].type;
+ }
+ usearti = true;
+ }
+
+ // Check for spy mode player cycle
+ if (gamestate == GS_LEVEL && ev->type == ev_keydown
+ && ev->data1 == key_spy && !deathmatch)
+ { // Cycle the display player
+ do
+ {
+ displayplayer++;
+ if (displayplayer == MAXPLAYERS)
+ {
+ displayplayer = 0;
+ }
+ }
+ while (!playeringame[displayplayer]
+ && displayplayer != consoleplayer);
+ return (true);
+ }
+
+ if (CT_Responder(ev))
+ { // Chat ate the event
+ return (true);
+ }
+ if (gamestate == GS_LEVEL)
+ {
+ if (SB_Responder(ev))
+ { // Status bar ate the event
+ return (true);
+ }
+ if (AM_Responder(ev))
+ { // Automap ate the event
+ return (true);
+ }
+ }
+
+ if (ev->type == ev_mouse)
+ {
+ testcontrols_mousespeed = abs(ev->data2);
+ }
+
+ if (ev->type == ev_keydown && ev->data1 == key_prevweapon)
+ {
+ next_weapon = -1;
+ }
+ else if (ev->type == ev_keydown && ev->data1 == key_nextweapon)
+ {
+ next_weapon = 1;
+ }
+
+ switch (ev->type)
+ {
+ case ev_keydown:
+ if (ev->data1 == key_invleft)
+ {
+ inventoryTics = 5 * 35;
+ if (!inventory)
+ {
+ inventory = true;
+ break;
+ }
+ inv_ptr--;
+ if (inv_ptr < 0)
+ {
+ inv_ptr = 0;
+ }
+ else
+ {
+ curpos--;
+ if (curpos < 0)
+ {
+ curpos = 0;
+ }
+ }
+ return (true);
+ }
+ if (ev->data1 == key_invright)
+ {
+ inventoryTics = 5 * 35;
+ if (!inventory)
+ {
+ inventory = true;
+ break;
+ }
+ inv_ptr++;
+ if (inv_ptr >= plr->inventorySlotNum)
+ {
+ inv_ptr--;
+ if (inv_ptr < 0)
+ inv_ptr = 0;
+ }
+ else
+ {
+ curpos++;
+ if (curpos > 6)
+ {
+ curpos = 6;
+ }
+ }
+ return (true);
+ }
+ if (ev->data1 == KEY_PAUSE && !MenuActive)
+ {
+ sendpause = true;
+ return (true);
+ }
+ if (ev->data1 < NUMKEYS)
+ {
+ gamekeydown[ev->data1] = true;
+ }
+ return (true); // eat key down events
+
+ case ev_keyup:
+ if (ev->data1 < NUMKEYS)
+ {
+ gamekeydown[ev->data1] = false;
+ }
+ return (false); // always let key up events filter down
+
+ case ev_mouse:
+ mousebuttons[0] = ev->data1 & 1;
+ mousebuttons[1] = ev->data1 & 2;
+ mousebuttons[2] = ev->data1 & 4;
+ mousex = ev->data2 * (mouseSensitivity + 5) / 10;
+ mousey = ev->data3 * (mouseSensitivity + 5) / 10;
+ return (true); // eat events
+
+ case ev_joystick:
+ joybuttons[0] = ev->data1 & 1;
+ joybuttons[1] = ev->data1 & 2;
+ joybuttons[2] = ev->data1 & 4;
+ joybuttons[3] = ev->data1 & 8;
+ joyxmove = ev->data2;
+ joyymove = ev->data3;
+ return (true); // eat events
+
+ default:
+ break;
+ }
+ return (false);
+}
+
+
+//==========================================================================
+//
+// G_Ticker
+//
+//==========================================================================
+
+void G_Ticker(void)
+{
+ int i, buf;
+ ticcmd_t *cmd = NULL;
+
+//
+// do player reborns if needed
+//
+ for (i = 0; i < MAXPLAYERS; i++)
+ if (playeringame[i] && players[i].playerstate == PST_REBORN)
+ G_DoReborn(i);
+
+//
+// do things to change the game state
+//
+ while (gameaction != ga_nothing)
+ {
+ switch (gameaction)
+ {
+ case ga_loadlevel:
+ G_DoLoadLevel();
+ break;
+ case ga_initnew:
+ G_DoInitNew();
+ break;
+ case ga_newgame:
+ G_DoNewGame();
+ break;
+ case ga_loadgame:
+ Draw_LoadIcon();
+ G_DoLoadGame();
+ break;
+ case ga_savegame:
+ Draw_SaveIcon();
+ G_DoSaveGame();
+ break;
+ case ga_singlereborn:
+ G_DoSingleReborn();
+ break;
+ case ga_playdemo:
+ G_DoPlayDemo();
+ break;
+ case ga_screenshot:
+ V_ScreenShot("HEXEN%02i.pcx");
+ P_SetMessage(&players[consoleplayer], "SCREEN SHOT", false);
+ gameaction = ga_nothing;
+ break;
+ case ga_leavemap:
+ Draw_TeleportIcon();
+ G_DoTeleportNewMap();
+ break;
+ case ga_completed:
+ G_DoCompleted();
+ break;
+ case ga_worlddone:
+ G_DoWorldDone();
+ break;
+ case ga_victory:
+ F_StartFinale();
+ break;
+ default:
+ break;
+ }
+ }
+
+
+//
+// get commands, check consistancy, and build new consistancy check
+//
+ //buf = gametic%BACKUPTICS;
+ buf = (gametic / ticdup) % BACKUPTICS;
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ if (playeringame[i])
+ {
+ cmd = &players[i].cmd;
+
+ memcpy(cmd, &netcmds[i], sizeof(ticcmd_t));
+
+ if (demoplayback)
+ G_ReadDemoTiccmd(cmd);
+ if (demorecording)
+ G_WriteDemoTiccmd(cmd);
+
+ if (netgame && !(gametic % ticdup))
+ {
+ if (gametic > BACKUPTICS
+ && consistancy[i][buf] != cmd->consistancy)
+ {
+ I_Error("consistency failure (%i should be %i)",
+ cmd->consistancy, consistancy[i][buf]);
+ }
+ if (players[i].mo)
+ consistancy[i][buf] = players[i].mo->x;
+ else
+ consistancy[i][buf] = rndindex;
+ }
+ }
+
+//
+// check for special buttons
+//
+ for (i = 0; i < MAXPLAYERS; i++)
+ if (playeringame[i])
+ {
+ if (players[i].cmd.buttons & BT_SPECIAL)
+ {
+ switch (players[i].cmd.buttons & BT_SPECIALMASK)
+ {
+ case BTS_PAUSE:
+ paused ^= 1;
+ if (paused)
+ {
+ S_PauseSound();
+ }
+ else
+ {
+ S_ResumeSound();
+ }
+ break;
+
+ case BTS_SAVEGAME:
+ if (!savedescription[0])
+ {
+ if (netgame)
+ {
+ strcpy(savedescription, "NET GAME");
+ }
+ else
+ {
+ strcpy(savedescription, "SAVE GAME");
+ }
+ }
+ savegameslot =
+ (players[i].cmd.
+ buttons & BTS_SAVEMASK) >> BTS_SAVESHIFT;
+ gameaction = ga_savegame;
+ break;
+ }
+ }
+ }
+ // turn inventory off after a certain amount of time
+ if (inventory && !(--inventoryTics))
+ {
+ players[consoleplayer].readyArtifact =
+ players[consoleplayer].inventory[inv_ptr].type;
+ inventory = false;
+ cmd->arti = 0;
+ }
+//
+// do main actions
+//
+//
+// do main actions
+//
+ switch (gamestate)
+ {
+ case GS_LEVEL:
+ P_Ticker();
+ SB_Ticker();
+ AM_Ticker();
+ CT_Ticker();
+ break;
+ case GS_INTERMISSION:
+ IN_Ticker();
+ break;
+ case GS_FINALE:
+ F_Ticker();
+ break;
+ case GS_DEMOSCREEN:
+ H2_PageTicker();
+ break;
+ }
+}
+
+
+/*
+==============================================================================
+
+ PLAYER STRUCTURE FUNCTIONS
+
+also see P_SpawnPlayer in P_Things
+==============================================================================
+*/
+
+//==========================================================================
+//
+// G_PlayerExitMap
+//
+// Called when the player leaves a map.
+//
+//==========================================================================
+
+void G_PlayerExitMap(int playerNumber)
+{
+ int i;
+ player_t *player;
+ int flightPower;
+
+ player = &players[playerNumber];
+
+// if(deathmatch)
+// {
+// // Strip all but one of each type of artifact
+// for(i = 0; i < player->inventorySlotNum; i++)
+// {
+// player->inventory[i].count = 1;
+// }
+// player->artifactCount = player->inventorySlotNum;
+// }
+// else
+
+ // Strip all current powers (retain flight)
+ flightPower = player->powers[pw_flight];
+ memset(player->powers, 0, sizeof(player->powers));
+ player->powers[pw_flight] = flightPower;
+
+ if (deathmatch)
+ {
+ player->powers[pw_flight] = 0;
+ }
+ else
+ {
+ if (P_GetMapCluster(gamemap) != P_GetMapCluster(LeaveMap))
+ { // Entering new cluster
+ // Strip all keys
+ player->keys = 0;
+
+ // Strip flight artifact
+ for (i = 0; i < 25; i++)
+ {
+ player->powers[pw_flight] = 0;
+ P_PlayerUseArtifact(player, arti_fly);
+ }
+ player->powers[pw_flight] = 0;
+ }
+ }
+
+ if (player->morphTics)
+ {
+ player->readyweapon = player->mo->special1.i; // Restore weapon
+ player->morphTics = 0;
+ }
+ player->messageTics = 0;
+ player->lookdir = 0;
+ player->mo->flags &= ~MF_SHADOW; // Remove invisibility
+ player->extralight = 0; // Remove weapon flashes
+ player->fixedcolormap = 0; // Remove torch
+ player->damagecount = 0; // No palette changes
+ player->bonuscount = 0;
+ player->poisoncount = 0;
+ if (player == &players[consoleplayer])
+ {
+ SB_state = -1; // refresh the status bar
+ viewangleoffset = 0;
+ }
+}
+
+//==========================================================================
+//
+// G_PlayerReborn
+//
+// Called after a player dies. Almost everything is cleared and
+// initialized.
+//
+//==========================================================================
+
+void G_PlayerReborn(int player)
+{
+ player_t *p;
+ int frags[MAXPLAYERS];
+ int killcount, itemcount, secretcount;
+ unsigned int worldTimer;
+
+ memcpy(frags, players[player].frags, sizeof(frags));
+ killcount = players[player].killcount;
+ itemcount = players[player].itemcount;
+ secretcount = players[player].secretcount;
+ worldTimer = players[player].worldTimer;
+
+ p = &players[player];
+ memset(p, 0, sizeof(*p));
+
+ memcpy(players[player].frags, frags, sizeof(players[player].frags));
+ players[player].killcount = killcount;
+ players[player].itemcount = itemcount;
+ players[player].secretcount = secretcount;
+ players[player].worldTimer = worldTimer;
+ players[player].class = PlayerClass[player];
+
+ p->usedown = p->attackdown = true; // don't do anything immediately
+ p->playerstate = PST_LIVE;
+ p->health = MAXHEALTH;
+ p->readyweapon = p->pendingweapon = WP_FIRST;
+ p->weaponowned[WP_FIRST] = true;
+ p->messageTics = 0;
+ p->lookdir = 0;
+ localQuakeHappening[player] = false;
+ if (p == &players[consoleplayer])
+ {
+ SB_state = -1; // refresh the status bar
+ inv_ptr = 0; // reset the inventory pointer
+ curpos = 0;
+ viewangleoffset = 0;
+ }
+}
+
+/*
+====================
+=
+= G_CheckSpot
+=
+= Returns false if the player cannot be respawned at the given mapthing_t spot
+= because something is occupying it
+====================
+*/
+
+void P_SpawnPlayer(mapthing_t * mthing);
+
+boolean G_CheckSpot(int playernum, mapthing_t * mthing)
+{
+ fixed_t x, y;
+ subsector_t *ss;
+ unsigned an;
+ mobj_t *mo;
+
+ x = mthing->x << FRACBITS;
+ y = mthing->y << FRACBITS;
+
+ players[playernum].mo->flags2 &= ~MF2_PASSMOBJ;
+ if (!P_CheckPosition(players[playernum].mo, x, y))
+ {
+ players[playernum].mo->flags2 |= MF2_PASSMOBJ;
+ return false;
+ }
+ players[playernum].mo->flags2 |= MF2_PASSMOBJ;
+
+// spawn a teleport fog
+ ss = R_PointInSubsector(x, y);
+ an = ((unsigned) ANG45 * (mthing->angle / 45)) >> ANGLETOFINESHIFT;
+
+ mo = P_SpawnMobj(x + 20 * finecosine[an], y + 20 * finesine[an],
+ ss->sector->floorheight + TELEFOGHEIGHT, MT_TFOG);
+ if (players[consoleplayer].viewz != 1)
+ S_StartSound(mo, SFX_TELEPORT); // don't start sound on first frame
+
+ return true;
+}
+
+/*
+====================
+=
+= G_DeathMatchSpawnPlayer
+=
+= Spawns a player at one of the random death match spots
+= called at level load and each death
+====================
+*/
+
+void G_DeathMatchSpawnPlayer(int playernum)
+{
+ int i, j;
+ int selections;
+
+ selections = deathmatch_p - deathmatchstarts;
+
+ // This check has been moved to p_setup.c:P_LoadThings()
+ //if (selections < 8)
+ // I_Error ("Only %i deathmatch spots, 8 required", selections);
+
+ for (j = 0; j < 20; j++)
+ {
+ i = P_Random() % selections;
+ if (G_CheckSpot(playernum, &deathmatchstarts[i]))
+ {
+ deathmatchstarts[i].type = playernum + 1;
+ P_SpawnPlayer(&deathmatchstarts[i]);
+ return;
+ }
+ }
+
+// no good spot, so the player will probably get stuck
+ P_SpawnPlayer(&playerstarts[0][playernum]);
+}
+
+//==========================================================================
+//
+// G_DoReborn
+//
+//==========================================================================
+
+void G_DoReborn(int playernum)
+{
+ int i;
+ boolean oldWeaponowned[NUMWEAPONS];
+ int oldKeys;
+ int oldPieces;
+ boolean foundSpot;
+ int bestWeapon;
+
+ if (G_CheckDemoStatus())
+ {
+ return;
+ }
+ if (!netgame)
+ {
+ if (SV_RebornSlotAvailable())
+ { // Use the reborn code if the slot is available
+ gameaction = ga_singlereborn;
+ }
+ else
+ { // Start a new game if there's no reborn info
+ gameaction = ga_newgame;
+ }
+ }
+ else
+ { // Net-game
+ players[playernum].mo->player = NULL; // Dissassociate the corpse
+
+ if (deathmatch)
+ { // Spawn at random spot if in death match
+ G_DeathMatchSpawnPlayer(playernum);
+ return;
+ }
+
+ // Cooperative net-play, retain keys and weapons
+ oldKeys = players[playernum].keys;
+ oldPieces = players[playernum].pieces;
+ for (i = 0; i < NUMWEAPONS; i++)
+ {
+ oldWeaponowned[i] = players[playernum].weaponowned[i];
+ }
+
+ foundSpot = false;
+ if (G_CheckSpot(playernum, &playerstarts[RebornPosition][playernum]))
+ { // Appropriate player start spot is open
+ P_SpawnPlayer(&playerstarts[RebornPosition][playernum]);
+ foundSpot = true;
+ }
+ else
+ {
+ // Try to spawn at one of the other player start spots
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (G_CheckSpot(playernum, &playerstarts[RebornPosition][i]))
+ { // Found an open start spot
+
+ // Fake as other player
+ playerstarts[RebornPosition][i].type = playernum + 1;
+ P_SpawnPlayer(&playerstarts[RebornPosition][i]);
+
+ // Restore proper player type
+ playerstarts[RebornPosition][i].type = i + 1;
+
+ foundSpot = true;
+ break;
+ }
+ }
+ }
+
+ if (foundSpot == false)
+ { // Player's going to be inside something
+ P_SpawnPlayer(&playerstarts[RebornPosition][playernum]);
+ }
+
+ // Restore keys and weapons
+ players[playernum].keys = oldKeys;
+ players[playernum].pieces = oldPieces;
+ for (bestWeapon = 0, i = 0; i < NUMWEAPONS; i++)
+ {
+ if (oldWeaponowned[i])
+ {
+ bestWeapon = i;
+ players[playernum].weaponowned[i] = true;
+ }
+ }
+ players[playernum].mana[MANA_1] = 25;
+ players[playernum].mana[MANA_2] = 25;
+ if (bestWeapon)
+ { // Bring up the best weapon
+ players[playernum].pendingweapon = bestWeapon;
+ }
+ }
+}
+
+void G_ScreenShot(void)
+{
+ gameaction = ga_screenshot;
+}
+
+//==========================================================================
+//
+// G_StartNewInit
+//
+//==========================================================================
+
+void G_StartNewInit(void)
+{
+ SV_InitBaseSlot();
+ SV_ClearRebornSlot();
+ P_ACSInitNewGame();
+ // Default the player start spot group to 0
+ RebornPosition = 0;
+}
+
+//==========================================================================
+//
+// G_StartNewGame
+//
+//==========================================================================
+
+void G_StartNewGame(skill_t skill)
+{
+ int realMap;
+
+ G_StartNewInit();
+ realMap = P_TranslateMap(1);
+ if (realMap == -1)
+ {
+ realMap = 1;
+ }
+ G_InitNew(TempSkill, 1, realMap);
+}
+
+//==========================================================================
+//
+// G_TeleportNewMap
+//
+// Only called by the warp cheat code. Works just like normal map to map
+// teleporting, but doesn't do any interlude stuff.
+//
+//==========================================================================
+
+void G_TeleportNewMap(int map, int position)
+{
+ gameaction = ga_leavemap;
+ LeaveMap = map;
+ LeavePosition = position;
+}
+
+//==========================================================================
+//
+// G_DoTeleportNewMap
+//
+//==========================================================================
+
+void G_DoTeleportNewMap(void)
+{
+ SV_MapTeleport(LeaveMap, LeavePosition);
+ gamestate = GS_LEVEL;
+ gameaction = ga_nothing;
+ RebornPosition = LeavePosition;
+}
+
+/*
+boolean secretexit;
+void G_ExitLevel (void)
+{
+ secretexit = false;
+ gameaction = ga_completed;
+}
+void G_SecretExitLevel (void)
+{
+ secretexit = true;
+ gameaction = ga_completed;
+}
+*/
+
+//==========================================================================
+//
+// G_Completed
+//
+// Starts intermission routine, which is used only during hub exits,
+// and DeathMatch games.
+//==========================================================================
+
+void G_Completed(int map, int position)
+{
+ gameaction = ga_completed;
+ LeaveMap = map;
+ LeavePosition = position;
+}
+
+void G_DoCompleted(void)
+{
+ int i;
+
+ gameaction = ga_nothing;
+ if (G_CheckDemoStatus())
+ {
+ return;
+ }
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ {
+ G_PlayerExitMap(i);
+ }
+ }
+ if (LeaveMap == -1 && LeavePosition == -1)
+ {
+ gameaction = ga_victory;
+ return;
+ }
+ else
+ {
+ gamestate = GS_INTERMISSION;
+ IN_Start();
+ }
+
+/*
+ int i;
+ static int afterSecret[3] = { 7, 5, 5 };
+
+ gameaction = ga_nothing;
+ if(G_CheckDemoStatus())
+ {
+ return;
+ }
+ for(i = 0; i < MAXPLAYERS; i++)
+ {
+ if(playeringame[i])
+ {
+ G_PlayerFinishLevel(i);
+ }
+ }
+ prevmap = gamemap;
+ if(secretexit == true)
+ {
+ gamemap = 9;
+ }
+ else if(gamemap == 9)
+ { // Finished secret level
+ gamemap = afterSecret[gameepisode-1];
+ }
+ else if(gamemap == 8)
+ {
+ gameaction = ga_victory;
+ return;
+ }
+ else
+ {
+ gamemap++;
+ }
+ gamestate = GS_INTERMISSION;
+ IN_Start();
+*/
+}
+
+//============================================================================
+//
+// G_WorldDone
+//
+//============================================================================
+
+void G_WorldDone(void)
+{
+ gameaction = ga_worlddone;
+}
+
+//============================================================================
+//
+// G_DoWorldDone
+//
+//============================================================================
+
+void G_DoWorldDone(void)
+{
+ gamestate = GS_LEVEL;
+ G_DoLoadLevel();
+ gameaction = ga_nothing;
+ viewactive = true;
+}
+
+//==========================================================================
+//
+// G_DoSingleReborn
+//
+// Called by G_Ticker based on gameaction. Loads a game from the reborn
+// save slot.
+//
+//==========================================================================
+
+void G_DoSingleReborn(void)
+{
+ gameaction = ga_nothing;
+ SV_LoadGame(SV_GetRebornSlot());
+ SB_SetClassData();
+}
+
+//==========================================================================
+//
+// G_LoadGame
+//
+// Can be called by the startup code or the menu task.
+//
+//==========================================================================
+
+static int GameLoadSlot;
+
+void G_LoadGame(int slot)
+{
+ GameLoadSlot = slot;
+ gameaction = ga_loadgame;
+}
+
+//==========================================================================
+//
+// G_DoLoadGame
+//
+// Called by G_Ticker based on gameaction.
+//
+//==========================================================================
+
+void G_DoLoadGame(void)
+{
+ gameaction = ga_nothing;
+ SV_LoadGame(GameLoadSlot);
+ if (!netgame)
+ { // Copy the base slot to the reborn slot
+ SV_UpdateRebornSlot();
+ }
+ SB_SetClassData();
+}
+
+//==========================================================================
+//
+// G_SaveGame
+//
+// Called by the menu task. <description> is a 24 byte text string.
+//
+//==========================================================================
+
+void G_SaveGame(int slot, char *description)
+{
+ savegameslot = slot;
+ strcpy(savedescription, description);
+ sendsave = true;
+}
+
+//==========================================================================
+//
+// G_DoSaveGame
+//
+// Called by G_Ticker based on gameaction.
+//
+//==========================================================================
+
+void G_DoSaveGame(void)
+{
+ SV_SaveGame(savegameslot, savedescription);
+ gameaction = ga_nothing;
+ savedescription[0] = 0;
+ P_SetMessage(&players[consoleplayer], TXT_GAMESAVED, true);
+}
+
+//==========================================================================
+//
+// G_DeferredNewGame
+//
+//==========================================================================
+
+void G_DeferredNewGame(skill_t skill)
+{
+ TempSkill = skill;
+ gameaction = ga_newgame;
+}
+
+//==========================================================================
+//
+// G_DoNewGame
+//
+//==========================================================================
+
+void G_DoNewGame(void)
+{
+ G_StartNewGame(TempSkill);
+ gameaction = ga_nothing;
+}
+
+/*
+====================
+=
+= G_InitNew
+=
+= Can be called by the startup code or the menu task
+= consoleplayer, displayplayer, playeringame[] should be set
+====================
+*/
+
+void G_DeferedInitNew(skill_t skill, int episode, int map)
+{
+ TempSkill = skill;
+ TempEpisode = episode;
+ TempMap = map;
+ gameaction = ga_initnew;
+}
+
+void G_DoInitNew(void)
+{
+ SV_InitBaseSlot();
+ G_InitNew(TempSkill, TempEpisode, TempMap);
+ gameaction = ga_nothing;
+}
+
+void G_InitNew(skill_t skill, int episode, int map)
+{
+ int i;
+
+ if (paused)
+ {
+ paused = false;
+ S_ResumeSound();
+ }
+ if (skill < sk_baby)
+ {
+ skill = sk_baby;
+ }
+ if (skill > sk_nightmare)
+ {
+ skill = sk_nightmare;
+ }
+ if (map < 1)
+ {
+ map = 1;
+ }
+ if (map > 99)
+ {
+ map = 99;
+ }
+ M_ClearRandom();
+ // Force players to be initialized upon first level load
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ players[i].playerstate = PST_REBORN;
+ players[i].worldTimer = 0;
+ }
+
+ // Set up a bunch of globals
+ usergame = true; // will be set false if a demo
+ paused = false;
+ demorecording = false;
+ demoplayback = false;
+ viewactive = true;
+ gameepisode = episode;
+ gamemap = map;
+ gameskill = skill;
+ BorderNeedRefresh = true;
+
+ // Initialize the sky
+ R_InitSky(map);
+
+ // Give one null ticcmd_t
+ //gametic = 0;
+ //maketic = 1;
+ //for (i=0 ; i<MAXPLAYERS ; i++)
+ // nettics[i] = 1; // one null event for this gametic
+ //memset (localcmds,0,sizeof(localcmds));
+ //memset (netcmds,0,sizeof(netcmds));
+
+ G_DoLoadLevel();
+}
+
+/*
+===============================================================================
+
+ DEMO RECORDING
+
+===============================================================================
+*/
+
+#define DEMOMARKER 0x80
+
+void G_ReadDemoTiccmd(ticcmd_t * cmd)
+{
+ if (*demo_p == DEMOMARKER)
+ { // end of demo data stream
+ G_CheckDemoStatus();
+ return;
+ }
+ cmd->forwardmove = ((signed char) *demo_p++);
+ cmd->sidemove = ((signed char) *demo_p++);
+ cmd->angleturn = ((unsigned char) *demo_p++) << 8;
+ cmd->buttons = (unsigned char) *demo_p++;
+ cmd->lookfly = (unsigned char) *demo_p++;
+ cmd->arti = (unsigned char) *demo_p++;
+}
+
+void G_WriteDemoTiccmd(ticcmd_t * cmd)
+{
+ if (gamekeydown['q']) // press q to end demo recording
+ G_CheckDemoStatus();
+ *demo_p++ = cmd->forwardmove;
+ *demo_p++ = cmd->sidemove;
+ *demo_p++ = cmd->angleturn >> 8;
+ *demo_p++ = cmd->buttons;
+ *demo_p++ = cmd->lookfly;
+ *demo_p++ = cmd->arti;
+ demo_p -= 6;
+ G_ReadDemoTiccmd(cmd); // make SURE it is exactly the same
+}
+
+
+
+/*
+===================
+=
+= G_RecordDemo
+=
+===================
+*/
+
+void G_RecordDemo(skill_t skill, int numplayers, int episode, int map,
+ char *name)
+{
+ int i;
+
+ G_InitNew(skill, episode, map);
+ usergame = false;
+ strcpy(demoname, name);
+ strcat(demoname, ".lmp");
+ demobuffer = demo_p = Z_Malloc(0x20000, PU_STATIC, NULL);
+ *demo_p++ = skill;
+ *demo_p++ = episode;
+ *demo_p++ = map;
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ *demo_p++ = playeringame[i];
+ *demo_p++ = PlayerClass[i];
+ }
+ demorecording = true;
+}
+
+
+/*
+===================
+=
+= G_PlayDemo
+=
+===================
+*/
+
+char *defdemoname;
+
+void G_DeferedPlayDemo(char *name)
+{
+ defdemoname = name;
+ gameaction = ga_playdemo;
+}
+
+void G_DoPlayDemo(void)
+{
+ skill_t skill;
+ int i, episode, map;
+
+ gameaction = ga_nothing;
+ demobuffer = demo_p = W_CacheLumpName(defdemoname, PU_STATIC);
+ skill = *demo_p++;
+ episode = *demo_p++;
+ map = *demo_p++;
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ playeringame[i] = *demo_p++;
+ PlayerClass[i] = *demo_p++;
+ }
+
+ // Initialize world info, etc.
+ G_StartNewInit();
+
+ precache = false; // don't spend a lot of time in loadlevel
+ G_InitNew(skill, episode, map);
+ precache = true;
+ usergame = false;
+ demoplayback = true;
+}
+
+
+/*
+===================
+=
+= G_TimeDemo
+=
+===================
+*/
+
+void G_TimeDemo(char *name)
+{
+ skill_t skill;
+ int episode, map;
+
+ demobuffer = demo_p = W_CacheLumpName(name, PU_STATIC);
+ skill = *demo_p++;
+ episode = *demo_p++;
+ map = *demo_p++;
+ G_InitNew(skill, episode, map);
+ usergame = false;
+ demoplayback = true;
+ timingdemo = true;
+ singletics = true;
+}
+
+
+/*
+===================
+=
+= G_CheckDemoStatus
+=
+= Called after a death or level completion to allow demos to be cleaned up
+= Returns true if a new demo loop action will take place
+===================
+*/
+
+boolean G_CheckDemoStatus(void)
+{
+ int endtime;
+
+ if (timingdemo)
+ {
+ endtime = I_GetTime();
+ I_Error("timed %i gametics in %i realtics", gametic,
+ endtime - starttime);
+ }
+
+ if (demoplayback)
+ {
+ if (singledemo)
+ I_Quit();
+
+ W_ReleaseLumpName(defdemoname);
+ demoplayback = false;
+ H2_AdvanceDemo();
+ return true;
+ }
+
+ if (demorecording)
+ {
+ *demo_p++ = DEMOMARKER;
+ M_WriteFile(demoname, demobuffer, demo_p - demobuffer);
+ Z_Free(demobuffer);
+ demorecording = false;
+ I_Error("Demo %s recorded", demoname);
+ }
+
+ return false;
+}
diff --git a/src/hexen/h2_main.c b/src/hexen/h2_main.c
new file mode 100644
index 00000000..3d9ae87d
--- /dev/null
+++ b/src/hexen/h2_main.c
@@ -0,0 +1,899 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+// HEADER FILES ------------------------------------------------------------
+
+// haleyjd: removed WATCOMC
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "config.h"
+#include "doomfeatures.h"
+
+#include "h2def.h"
+#include "ct_chat.h"
+#include "d_iwad.h"
+#include "d_mode.h"
+#include "m_misc.h"
+#include "s_sound.h"
+#include "i_joystick.h"
+#include "i_system.h"
+#include "i_timer.h"
+#include "m_argv.h"
+#include "m_config.h"
+#include "m_controls.h"
+#include "net_client.h"
+#include "p_local.h"
+#include "v_video.h"
+#include "w_main.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define MAXWADFILES 20
+#define CT_KEY_BLUE 'b'
+#define CT_KEY_RED 'r'
+#define CT_KEY_YELLOW 'y'
+#define CT_KEY_GREEN 'g'
+#define CT_KEY_PLAYER5 'j' // Jade
+#define CT_KEY_PLAYER6 'w' // White
+#define CT_KEY_PLAYER7 'h' // Hazel
+#define CT_KEY_PLAYER8 'p' // Purple
+#define CT_KEY_ALL 't'
+
+// TYPES -------------------------------------------------------------------
+
+typedef struct
+{
+ char *name;
+ void (*func) (char **args, int tag);
+ int requiredArgs;
+ int tag;
+} execOpt_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+void R_ExecuteSetViewSize(void);
+void D_CheckNetGame(void);
+boolean F_Responder(event_t * ev);
+void I_StartupKeyboard(void);
+void I_StartupJoystick(void);
+void I_ShutdownKeyboard(void);
+void S_InitScript(void);
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+void H2_ProcessEvents(void);
+void H2_DoAdvanceDemo(void);
+void H2_AdvanceDemo(void);
+void H2_StartTitle(void);
+void H2_PageTicker(void);
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void DrawMessage(void);
+static void PageDrawer(void);
+static void HandleArgs(void);
+static void CheckRecordFrom(void);
+static void DrawAndBlit(void);
+static void ExecOptionSCRIPTS(char **args, int tag);
+static void ExecOptionSKILL(char **args, int tag);
+static void ExecOptionPLAYDEMO(char **args, int tag);
+static void ExecOptionTestControls(char **args, int tag);
+static void CreateSavePath(void);
+static void WarpCheck(void);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern boolean automapactive;
+extern boolean MenuActive;
+extern boolean askforquit;
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+GameMode_t gamemode;
+GameMission_t gamemission;
+char *iwadfile;
+boolean nomonsters; // checkparm of -nomonsters
+boolean respawnparm; // checkparm of -respawn
+boolean randomclass; // checkparm of -randclass
+boolean debugmode; // checkparm of -debug
+boolean ravpic; // checkparm of -ravpic
+boolean cdrom = false; // true if cd-rom mode active
+boolean cmdfrag; // true if a CMD_FRAG packet should be sent out
+boolean singletics; // debug flag to cancel adaptiveness
+boolean artiskip; // whether shift-enter skips an artifact
+int maxzone = 0x800000; // Maximum allocated for zone heap (8meg default)
+skill_t startskill;
+int startepisode;
+int startmap;
+boolean autostart;
+boolean advancedemo;
+FILE *debugfile;
+int UpdateState;
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static int WarpMap;
+static int demosequence;
+static int pagetic;
+static char *pagename;
+
+static execOpt_t ExecOptions[] = {
+ {"-scripts", ExecOptionSCRIPTS, 1, 0},
+ {"-skill", ExecOptionSKILL, 1, 0},
+ {"-playdemo", ExecOptionPLAYDEMO, 1, 0},
+ {"-timedemo", ExecOptionPLAYDEMO, 1, 0},
+ {"-testcontrols", ExecOptionTestControls, 0, 0},
+ {NULL, NULL, 0, 0} // Terminator
+};
+
+// CODE --------------------------------------------------------------------
+
+void D_BindVariables(void)
+{
+ int i;
+
+ M_ApplyPlatformDefaults();
+
+ I_BindVideoVariables();
+ I_BindJoystickVariables();
+ I_BindSoundVariables();
+
+ M_BindBaseControls();
+ M_BindMapControls();
+ M_BindMenuControls();
+ M_BindWeaponControls();
+ M_BindChatControls(MAXPLAYERS);
+ M_BindHereticControls();
+ M_BindHexenControls();
+
+ key_multi_msgplayer[0] = CT_KEY_BLUE;
+ key_multi_msgplayer[1] = CT_KEY_RED;
+ key_multi_msgplayer[2] = CT_KEY_YELLOW;
+ key_multi_msgplayer[3] = CT_KEY_GREEN;
+ key_multi_msgplayer[4] = CT_KEY_PLAYER5;
+ key_multi_msgplayer[5] = CT_KEY_PLAYER6;
+ key_multi_msgplayer[6] = CT_KEY_PLAYER7;
+ key_multi_msgplayer[7] = CT_KEY_PLAYER8;
+
+ M_BindVariable("graphical_startup", &graphical_startup);
+ M_BindVariable("mouse_sensitivity", &mouseSensitivity);
+ M_BindVariable("sfx_volume", &snd_MaxVolume);
+ M_BindVariable("music_volume", &snd_MusicVolume);
+ M_BindVariable("messageson", &messageson);
+ M_BindVariable("screenblocks", &screenblocks);
+ M_BindVariable("snd_channels", &snd_Channels);
+ M_BindVariable("savedir", &SavePath);
+
+ // Multiplayer chat macros
+
+ for (i=0; i<10; ++i)
+ {
+ char buf[12];
+
+ sprintf(buf, "chatmacro%i", i);
+ M_BindVariable(buf, &chat_macros[i]);
+ }
+}
+
+// Set the default directory where hub savegames are saved.
+
+static void D_SetDefaultSavePath(void)
+{
+ SavePath = M_GetSaveGameDir("hexen.wad");
+
+ // If we are not using a savegame path (probably because we are on
+ // Windows and not using a config dir), behave like Vanilla Hexen
+ // and use hexndata/:
+
+ if (!strcmp(SavePath, ""))
+ {
+ SavePath = malloc(10);
+ sprintf(SavePath, "hexndata%c", DIR_SEPARATOR);
+ }
+}
+
+//
+// D_GrabMouseCallback
+//
+// Called to determine whether to grab the mouse pointer
+//
+
+static boolean D_GrabMouseCallback(void)
+{
+ // when menu is active or game is paused, release the mouse
+
+ if (MenuActive || paused)
+ return false;
+
+ // only grab mouse when playing levels (but not demos)
+
+ return (gamestate == GS_LEVEL) && !demoplayback;
+}
+
+// Message displayed when quitting Hexen
+
+static void D_HexenQuitMessage(void)
+{
+ printf("\nHexen: Beyond Heretic\n");
+}
+
+static void D_AddFile(char *filename)
+{
+ printf(" adding %s\n", filename);
+
+ W_AddFile(filename);
+}
+
+//==========================================================================
+//
+// H2_Main
+//
+//==========================================================================
+void InitMapMusicInfo(void);
+
+void D_DoomMain(void)
+{
+ int p;
+
+ I_AtExit(D_HexenQuitMessage, false);
+ startepisode = 1;
+ autostart = false;
+ startskill = sk_medium;
+ startmap = 1;
+ gamemode = commercial;
+
+ // Initialize subsystems
+
+ ST_Message("V_Init: allocate screens.\n");
+ V_Init();
+
+ // Load defaults before initing other systems
+ ST_Message("M_LoadDefaults: Load system defaults.\n");
+ D_BindVariables();
+
+#ifdef _WIN32
+
+ //!
+ // @platform windows
+ // @vanilla
+ //
+ // Save configuration data and savegames in c:\hexndata,
+ // allowing play from CD.
+ //
+
+ cdrom = M_ParmExists("-cdrom");
+#endif
+
+ if (cdrom)
+ {
+ M_SetConfigDir("c:\\hexndata\\");
+ }
+ else
+ {
+ M_SetConfigDir(NULL);
+ }
+
+ D_SetDefaultSavePath();
+ M_SetConfigFilenames("hexen.cfg", PROGRAM_PREFIX "hexen.cfg");
+ M_LoadDefaults();
+
+ I_AtExit(M_SaveDefaults, false);
+
+
+ // Now that the savedir is loaded from .CFG, make sure it exists
+ CreateSavePath();
+
+ ST_Message("Z_Init: Init zone memory allocation daemon.\n");
+ Z_Init();
+
+ // haleyjd: removed WATCOMC
+
+ ST_Message("W_Init: Init WADfiles.\n");
+
+ iwadfile = D_FindIWAD(IWAD_MASK_HEXEN, &gamemission);
+
+ if (iwadfile == NULL)
+ {
+ I_Error("Game mode indeterminate. No IWAD was found. Try specifying\n"
+ "one with the '-iwad' command line parameter.");
+ }
+
+ D_AddFile(iwadfile);
+
+ HandleArgs();
+
+ I_PrintStartupBanner("Hexen");
+
+ ST_Message("MN_Init: Init menu system.\n");
+ MN_Init();
+
+#ifdef FEATURE_MULTIPLAYER
+ ST_Message("NET_Init: Init networking subsystem.\n");
+ NET_Init();
+#endif
+
+ ST_Message("CT_Init: Init chat mode data.\n");
+ CT_Init();
+
+ InitMapMusicInfo(); // Init music fields in mapinfo
+
+ ST_Message("S_InitScript\n");
+ S_InitScript();
+
+ ST_Message("SN_InitSequenceScript: Registering sound sequences.\n");
+ SN_InitSequenceScript();
+ ST_Message("I_Init: Setting up machine state.\n");
+ I_CheckIsScreensaver();
+ I_InitTimer();
+ I_InitJoystick();
+
+ S_Init();
+ S_Start();
+
+ ST_Message("ST_Init: Init startup screen.\n");
+ ST_Init();
+
+ // Show version message now, so it's visible during R_Init()
+ ST_Message("R_Init: Init Hexen refresh daemon");
+ R_Init();
+ ST_Message("\n");
+
+ //if (M_CheckParm("-net"))
+ // ST_NetProgress(); // Console player found
+
+ ST_Message("P_Init: Init Playloop state.\n");
+ P_Init();
+
+ // Check for command line warping. Follows P_Init() because the
+ // MAPINFO.TXT script must be already processed.
+ WarpCheck();
+
+ ST_Done();
+
+ // Netgame start must be here, after the splash screen has finished.
+ ST_Message("D_CheckNetGame: Checking network game status.\n");
+ D_CheckNetGame();
+
+ // SB_Init has been moved here; the status bar must be initialized
+ // *after* the netgame has started.
+ ST_Message("SB_Init: Loading patches.\n");
+ SB_Init();
+
+ if (autostart)
+ {
+ ST_Message("Warp to Map %d (\"%s\":%d), Skill %d\n",
+ WarpMap, P_GetMapName(startmap), startmap, startskill + 1);
+ }
+
+ CheckRecordFrom();
+
+ p = M_CheckParm("-record");
+ if (p && p < myargc - 1)
+ {
+ G_RecordDemo(startskill, 1, startepisode, startmap, myargv[p + 1]);
+ H2_GameLoop(); // Never returns
+ }
+
+ p = M_CheckParm("-playdemo");
+ if (p && p < myargc - 1)
+ {
+ singledemo = true; // Quit after one demo
+ G_DeferedPlayDemo(myargv[p + 1]);
+ H2_GameLoop(); // Never returns
+ }
+
+ p = M_CheckParm("-timedemo");
+ if (p && p < myargc - 1)
+ {
+ G_TimeDemo(myargv[p + 1]);
+ H2_GameLoop(); // Never returns
+ }
+
+ p = M_CheckParm("-loadgame");
+ if (p && p < myargc - 1)
+ {
+ G_LoadGame(atoi(myargv[p + 1]));
+ }
+
+ if (gameaction != ga_loadgame)
+ {
+ UpdateState |= I_FULLSCRN;
+ BorderNeedRefresh = true;
+ if (autostart || netgame)
+ {
+ G_StartNewInit();
+ G_InitNew(startskill, startepisode, startmap);
+ }
+ else
+ {
+ H2_StartTitle();
+ }
+ }
+ H2_GameLoop(); // Never returns
+}
+
+//==========================================================================
+//
+// HandleArgs
+//
+//==========================================================================
+
+static void HandleArgs(void)
+{
+ int p;
+ execOpt_t *opt;
+
+ nomonsters = M_ParmExists("-nomonsters");
+ respawnparm = M_ParmExists("-respawn");
+ randomclass = M_ParmExists("-randclass");
+ ravpic = M_ParmExists("-ravpic");
+ artiskip = M_ParmExists("-artiskip");
+ debugmode = M_ParmExists("-debug");
+ deathmatch = M_ParmExists("-deathmatch");
+
+ cmdfrag = M_ParmExists("-cmdfrag");
+
+ // Check WAD file command line options
+ W_ParseCommandLine();
+
+ // Process command line options
+ for (opt = ExecOptions; opt->name != NULL; opt++)
+ {
+ p = M_CheckParm(opt->name);
+ if (p && p < myargc - opt->requiredArgs)
+ {
+ opt->func(&myargv[p], opt->tag);
+ }
+ }
+}
+
+//==========================================================================
+//
+// WarpCheck
+//
+//==========================================================================
+
+static void WarpCheck(void)
+{
+ int p;
+ int map;
+
+ p = M_CheckParm("-warp");
+ if (p && p < myargc - 1)
+ {
+ WarpMap = atoi(myargv[p + 1]);
+ map = P_TranslateMap(WarpMap);
+ if (map == -1)
+ { // Couldn't find real map number
+ startmap = 1;
+ ST_Message("-WARP: Invalid map number.\n");
+ }
+ else
+ { // Found a valid startmap
+ startmap = map;
+ autostart = true;
+ }
+ }
+ else
+ {
+ WarpMap = 1;
+ startmap = P_TranslateMap(1);
+ if (startmap == -1)
+ {
+ startmap = 1;
+ }
+ }
+}
+
+//==========================================================================
+//
+// ExecOptionSKILL
+//
+//==========================================================================
+
+static void ExecOptionSKILL(char **args, int tag)
+{
+ startskill = args[1][0] - '1';
+ autostart = true;
+}
+
+//==========================================================================
+//
+// ExecOptionPLAYDEMO
+//
+//==========================================================================
+
+static void ExecOptionPLAYDEMO(char **args, int tag)
+{
+ char file[256];
+
+ strcpy(file, args[1]);
+
+ if (strcasecmp(file + strlen(file) - 4, ".lmp") != 0)
+ {
+ strcat(file, ".lmp");
+ }
+
+ W_AddFile(file);
+ ST_Message("Playing demo %s.\n", file);
+}
+
+//==========================================================================
+//
+// ExecOptionTestControls
+//
+//==========================================================================
+
+static void ExecOptionTestControls(char **args, int tag)
+{
+ autostart = true;
+ testcontrols = true;
+}
+
+//==========================================================================
+//
+// ExecOptionSCRIPTS
+//
+//==========================================================================
+
+static void ExecOptionSCRIPTS(char **args, int tag)
+{
+ sc_FileScripts = true;
+ sc_ScriptsDir = args[1];
+}
+
+
+//==========================================================================
+//
+// H2_GameLoop
+//
+//==========================================================================
+
+void H2_GameLoop(void)
+{
+ if (M_CheckParm("-debugfile"))
+ {
+ char filename[20];
+ sprintf(filename, "debug%i.txt", consoleplayer);
+ debugfile = fopen(filename, "w");
+ }
+ I_SetWindowTitle("Hexen");
+ I_GraphicsCheckCommandLine();
+ I_InitGraphics();
+ I_SetGrabMouseCallback(D_GrabMouseCallback);
+
+ while (1)
+ {
+ // Frame syncronous IO operations
+ I_StartFrame();
+
+ // Process one or more tics
+ // Will run at least one tic
+ TryRunTics();
+
+ // Move positional sounds
+ S_UpdateSounds(players[displayplayer].mo);
+
+ DrawAndBlit();
+ }
+}
+
+//==========================================================================
+//
+// H2_ProcessEvents
+//
+// Send all the events of the given timestamp down the responder chain.
+//
+//==========================================================================
+
+void H2_ProcessEvents(void)
+{
+ event_t *ev;
+
+ for (;;)
+ {
+ ev = D_PopEvent();
+
+ if (ev == NULL)
+ {
+ break;
+ }
+
+ if (F_Responder(ev))
+ {
+ continue;
+ }
+ if (MN_Responder(ev))
+ {
+ continue;
+ }
+ G_Responder(ev);
+ }
+}
+
+//==========================================================================
+//
+// DrawAndBlit
+//
+//==========================================================================
+
+static void DrawAndBlit(void)
+{
+ // Change the view size if needed
+ if (setsizeneeded)
+ {
+ R_ExecuteSetViewSize();
+ }
+
+ // Do buffered drawing
+ switch (gamestate)
+ {
+ case GS_LEVEL:
+ if (!gametic)
+ {
+ break;
+ }
+ if (automapactive)
+ {
+ AM_Drawer();
+ }
+ else
+ {
+ R_RenderPlayerView(&players[displayplayer]);
+ }
+ CT_Drawer();
+ UpdateState |= I_FULLVIEW;
+ SB_Drawer();
+ break;
+ case GS_INTERMISSION:
+ IN_Drawer();
+ break;
+ case GS_FINALE:
+ F_Drawer();
+ break;
+ case GS_DEMOSCREEN:
+ PageDrawer();
+ break;
+ }
+
+ if (testcontrols)
+ {
+ V_DrawMouseSpeedBox(testcontrols_mousespeed);
+ }
+
+ if (paused && !MenuActive && !askforquit)
+ {
+ if (!netgame)
+ {
+ V_DrawPatch(160, viewwindowy + 5, W_CacheLumpName("PAUSED",
+ PU_CACHE));
+ }
+ else
+ {
+ V_DrawPatch(160, 70, W_CacheLumpName("PAUSED", PU_CACHE));
+ }
+ }
+
+ // Draw current message
+ DrawMessage();
+
+ // Draw Menu
+ MN_Drawer();
+
+ // Send out any new accumulation
+ NetUpdate();
+
+ // Flush buffered stuff to screen
+ I_FinishUpdate();
+}
+
+//==========================================================================
+//
+// DrawMessage
+//
+//==========================================================================
+
+static void DrawMessage(void)
+{
+ player_t *player;
+
+ player = &players[consoleplayer];
+ if (player->messageTics <= 0 || !player->message)
+ { // No message
+ return;
+ }
+ if (player->yellowMessage)
+ {
+ MN_DrTextAYellow(player->message,
+ 160 - MN_TextAWidth(player->message) / 2, 1);
+ }
+ else
+ {
+ MN_DrTextA(player->message, 160 - MN_TextAWidth(player->message) / 2,
+ 1);
+ }
+}
+
+//==========================================================================
+//
+// H2_PageTicker
+//
+//==========================================================================
+
+void H2_PageTicker(void)
+{
+ if (--pagetic < 0)
+ {
+ H2_AdvanceDemo();
+ }
+}
+
+//==========================================================================
+//
+// PageDrawer
+//
+//==========================================================================
+
+static void PageDrawer(void)
+{
+ V_DrawRawScreen(W_CacheLumpName(pagename, PU_CACHE));
+ if (demosequence == 1)
+ {
+ V_DrawPatch(4, 160, W_CacheLumpName("ADVISOR", PU_CACHE));
+ }
+ UpdateState |= I_FULLSCRN;
+}
+
+//==========================================================================
+//
+// H2_AdvanceDemo
+//
+// Called after each demo or intro demosequence finishes.
+//
+//==========================================================================
+
+void H2_AdvanceDemo(void)
+{
+ advancedemo = true;
+}
+
+//==========================================================================
+//
+// H2_DoAdvanceDemo
+//
+//==========================================================================
+
+void H2_DoAdvanceDemo(void)
+{
+ players[consoleplayer].playerstate = PST_LIVE; // don't reborn
+ advancedemo = false;
+ usergame = false; // can't save/end game here
+ paused = false;
+ gameaction = ga_nothing;
+ demosequence = (demosequence + 1) % 7;
+ switch (demosequence)
+ {
+ case 0:
+ pagetic = 280;
+ gamestate = GS_DEMOSCREEN;
+ pagename = "TITLE";
+ S_StartSongName("hexen", true);
+ break;
+ case 1:
+ pagetic = 210;
+ gamestate = GS_DEMOSCREEN;
+ pagename = "TITLE";
+ break;
+ case 2:
+ BorderNeedRefresh = true;
+ UpdateState |= I_FULLSCRN;
+ G_DeferedPlayDemo("demo1");
+ break;
+ case 3:
+ pagetic = 200;
+ gamestate = GS_DEMOSCREEN;
+ pagename = "CREDIT";
+ break;
+ case 4:
+ BorderNeedRefresh = true;
+ UpdateState |= I_FULLSCRN;
+ G_DeferedPlayDemo("demo2");
+ break;
+ case 5:
+ pagetic = 200;
+ gamestate = GS_DEMOSCREEN;
+ pagename = "CREDIT";
+ break;
+ case 6:
+ BorderNeedRefresh = true;
+ UpdateState |= I_FULLSCRN;
+ G_DeferedPlayDemo("demo3");
+ break;
+ }
+}
+
+//==========================================================================
+//
+// H2_StartTitle
+//
+//==========================================================================
+
+void H2_StartTitle(void)
+{
+ gameaction = ga_nothing;
+ demosequence = -1;
+ H2_AdvanceDemo();
+}
+
+//==========================================================================
+//
+// CheckRecordFrom
+//
+// -recordfrom <savegame num> <demoname>
+//
+//==========================================================================
+
+static void CheckRecordFrom(void)
+{
+ int p;
+
+ p = M_CheckParm("-recordfrom");
+ if (!p || p > myargc - 2)
+ { // Bad args
+ return;
+ }
+ G_LoadGame(atoi(myargv[p + 1]));
+ G_DoLoadGame(); // Load the gameskill etc info from savegame
+ G_RecordDemo(gameskill, 1, gameepisode, gamemap, myargv[p + 2]);
+
+ H2_GameLoop(); // Never returns
+}
+
+// haleyjd: removed WATCOMC
+/*
+void CleanExit(void)
+{
+ union REGS regs;
+
+ I_ShutdownKeyboard();
+ regs.x.eax = 0x3;
+ int386(0x10, &regs, &regs);
+ printf("Exited from HEXEN: Beyond Heretic.\n");
+ exit(1);
+}
+*/
+
+//==========================================================================
+//
+// CreateSavePath
+//
+//==========================================================================
+
+static void CreateSavePath(void)
+{
+ M_MakeDirectory(SavePath);
+}
diff --git a/src/hexen/h2def.h b/src/hexen/h2def.h
new file mode 100644
index 00000000..95f3e554
--- /dev/null
+++ b/src/hexen/h2def.h
@@ -0,0 +1,1069 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __H2DEF__
+#define __H2DEF__
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+//#include <values.h>
+
+#include "st_start.h"
+// haleyjd: removed WATCOMC
+
+// ticcmd:
+
+#include "d_ticcmd.h"
+
+// events
+
+#include "d_event.h"
+
+// gamemode/mission
+
+#include "d_mode.h"
+
+// for fixed_t:
+
+#include "m_fixed.h"
+
+// angle definitions:
+
+#include "tables.h"
+
+#include "d_loop.h"
+#include "net_defs.h"
+
+#define HEXEN_VERSION 110
+#define HEXEN_VERSION_TEXT "v1.1"
+
+// if rangecheck is undefined, most parameter validation debugging code
+// will not be compiled
+#ifndef NORANGECHECKING
+#define RANGECHECK
+#endif
+
+// Past distributions
+#ifndef VER_ID
+#define VER_ID "DVL"
+#endif
+//#define HEXEN_VERSIONTEXT "ID V1.2"
+//#define HEXEN_VERSIONTEXT "RETAIL STORE BETA" // 9/26/95
+//#define HEXEN_VERSIONTEXT "DVL BETA 10 05 95" // Used for GT for testing
+//#define HEXEN_VERSIONTEXT "DVL BETA 10 07 95" // Just an update for Romero
+//#define HEXEN_VERSIONTEXT "FINAL 1.0 (10 13 95)" // Just an update for Romero
+#ifdef RANGECHECK
+#define HEXEN_VERSIONTEXT "Version 1.1 +R "__DATE__" ("VER_ID")"
+#else
+#define HEXEN_VERSIONTEXT "Version 1.1 "__DATE__" ("VER_ID")"
+#endif
+
+// all exterior data is defined here
+#include "xddefs.h"
+
+// all important printed strings
+#include "textdefs.h"
+
+// header generated by multigen utility
+#include "info.h"
+
+/*
+===============================================================================
+
+ GLOBAL TYPES
+
+===============================================================================
+*/
+
+//#define NUMARTIFCTS 28
+#define MAXPLAYERS 8
+
+#define BT_ATTACK 1
+#define BT_USE 2
+#define BT_CHANGE 4 // if true, the next 3 bits hold weapon num
+#define BT_WEAPONMASK (8+16+32)
+#define BT_WEAPONSHIFT 3
+
+#define BT_SPECIAL 128 // game events, not really buttons
+#define BTS_SAVEMASK (4+8+16)
+#define BTS_SAVESHIFT 2
+#define BT_SPECIALMASK 3
+#define BTS_PAUSE 1 // pause the game
+#define BTS_SAVEGAME 2 // save the game at each console
+// savegame slot numbers occupy the second byte of buttons
+
+// The top 3 bits of the artifact field in the ticcmd_t struct are used
+// as additional flags
+#define AFLAG_MASK 0x3F
+#define AFLAG_SUICIDE 0x40
+#define AFLAG_JUMP 0x80
+
+typedef enum
+{
+ GS_LEVEL,
+ GS_INTERMISSION,
+ GS_FINALE,
+ GS_DEMOSCREEN
+} gamestate_t;
+
+typedef enum
+{
+ ga_nothing,
+ ga_loadlevel,
+ ga_initnew,
+ ga_newgame,
+ ga_loadgame,
+ ga_savegame,
+ ga_playdemo,
+ ga_completed,
+ ga_leavemap,
+ ga_singlereborn,
+ ga_victory,
+ ga_worlddone,
+ ga_screenshot
+} gameaction_t;
+
+typedef enum
+{
+ wipe_0,
+ wipe_1,
+ wipe_2,
+ wipe_3,
+ wipe_4,
+ NUMWIPES,
+ wipe_random
+} wipe_t;
+
+/*
+===============================================================================
+
+ MAPOBJ DATA
+
+===============================================================================
+*/
+
+// think_t is a function pointer to a routine to handle an actor
+typedef void (*think_t) ();
+
+typedef struct thinker_s
+{
+ struct thinker_s *prev, *next;
+ think_t function;
+} thinker_t;
+
+struct player_s;
+
+typedef union
+{
+ int i;
+ struct mobj_s *m;
+ struct player_s *p;
+} specialval_t;
+
+typedef struct mobj_s
+{
+ thinker_t thinker; // thinker node
+
+// info for drawing
+ fixed_t x, y, z;
+ struct mobj_s *snext, *sprev; // links in sector (if needed)
+ angle_t angle;
+ spritenum_t sprite; // used to find patch_t and flip value
+ int frame; // might be ord with FF_FULLBRIGHT
+
+// interaction info
+ struct mobj_s *bnext, *bprev; // links in blocks (if needed)
+ struct subsector_s *subsector;
+ fixed_t floorz, ceilingz; // closest together of contacted secs
+ fixed_t floorpic; // contacted sec floorpic
+ fixed_t radius, height; // for movement checking
+ fixed_t momx, momy, momz; // momentums
+ int validcount; // if == validcount, already checked
+ mobjtype_t type;
+ mobjinfo_t *info; // &mobjinfo[mobj->type]
+ int tics; // state tic counter
+ state_t *state;
+ int damage; // For missiles
+ int flags;
+ int flags2; // Heretic flags
+ specialval_t special1; // Special info
+ specialval_t special2; // Special info
+ int health;
+ int movedir; // 0-7
+ int movecount; // when 0, select a new dir
+ struct mobj_s *target; // thing being chased/attacked (or NULL)
+ // also the originator for missiles
+ int reactiontime; // if non 0, don't attack yet
+ // used by player to freeze a bit after
+ // teleporting
+ int threshold; // if > 0, the target will be chased
+ // no matter what (even if shot)
+ struct player_s *player; // only valid if type == MT_PLAYER
+ int lastlook; // player number last looked for
+ fixed_t floorclip; // value to use for floor clipping
+ int archiveNum; // Identity during archive
+ short tid; // thing identifier
+ byte special; // special
+ byte args[5]; // special arguments
+} mobj_t;
+
+// each sector has a degenmobj_t in it's center for sound origin purposes
+typedef struct
+{
+ thinker_t thinker; // not used for anything
+ fixed_t x, y, z;
+} degenmobj_t;
+
+//
+// frame flags
+//
+#define FF_FULLBRIGHT 0x8000 // flag in thing->frame
+#define FF_FRAMEMASK 0x7fff
+
+// --- mobj.flags ---
+
+#define MF_SPECIAL 1 // call P_SpecialThing when touched
+#define MF_SOLID 2
+#define MF_SHOOTABLE 4
+#define MF_NOSECTOR 8 // don't use the sector links
+ // (invisible but touchable)
+#define MF_NOBLOCKMAP 16 // don't use the blocklinks
+ // (inert but displayable)
+#define MF_AMBUSH 32
+#define MF_JUSTHIT 64 // try to attack right back
+#define MF_JUSTATTACKED 128 // take at least one step before attacking
+#define MF_SPAWNCEILING 256 // hang from ceiling instead of floor
+#define MF_NOGRAVITY 512 // don't apply gravity every tic
+
+// movement flags
+#define MF_DROPOFF 0x400 // allow jumps from high places
+#define MF_PICKUP 0x800 // for players to pick up items
+#define MF_NOCLIP 0x1000 // player cheat
+#define MF_SLIDE 0x2000 // keep info about sliding along walls
+#define MF_FLOAT 0x4000 // allow moves to any height, no gravity
+#define MF_TELEPORT 0x8000 // don't cross lines or look at heights
+#define MF_MISSILE 0x10000 // don't hit same species, explode on block
+
+#define MF_ALTSHADOW 0x20000 // alternate translucent draw
+#define MF_SHADOW 0x40000 // use translucent draw (shadow demons / invis)
+#define MF_NOBLOOD 0x80000 // don't bleed when shot (use puff)
+#define MF_CORPSE 0x100000 // don't stop moving halfway off a step
+#define MF_INFLOAT 0x200000 // floating to a height for a move, don't
+ // auto float to target's height
+
+#define MF_COUNTKILL 0x400000 // count towards intermission kill total
+#define MF_ICECORPSE 0x800000 // a frozen corpse (for blasting)
+
+#define MF_SKULLFLY 0x1000000 // skull in flight
+#define MF_NOTDMATCH 0x2000000 // don't spawn in death match (key cards)
+
+//#define MF_TRANSLATION 0xc000000 // if 0x4 0x8 or 0xc, use a translation
+#define MF_TRANSLATION 0x1c000000 // use a translation table (>>MF_TRANSHIFT)
+#define MF_TRANSSHIFT 26 // table for player colormaps
+
+
+// --- mobj.flags2 ---
+
+#define MF2_LOGRAV 0x00000001 // alternate gravity setting
+#define MF2_WINDTHRUST 0x00000002 // gets pushed around by the wind
+ // specials
+#define MF2_FLOORBOUNCE 0x00000004 // bounces off the floor
+#define MF2_BLASTED 0x00000008 // missile will pass through ghosts
+#define MF2_FLY 0x00000010 // fly mode is active
+#define MF2_FLOORCLIP 0x00000020 // if feet are allowed to be clipped
+#define MF2_SPAWNFLOAT 0x00000040 // spawn random float z
+#define MF2_NOTELEPORT 0x00000080 // does not teleport
+#define MF2_RIP 0x00000100 // missile rips through solid
+ // targets
+#define MF2_PUSHABLE 0x00000200 // can be pushed by other moving
+ // mobjs
+#define MF2_SLIDE 0x00000400 // slides against walls
+#define MF2_ONMOBJ 0x00000800 // mobj is resting on top of another
+ // mobj
+#define MF2_PASSMOBJ 0x00001000 // Enable z block checking. If on,
+ // this flag will allow the mobj to
+ // pass over/under other mobjs.
+#define MF2_CANNOTPUSH 0x00002000 // cannot push other pushable mobjs
+#define MF2_DROPPED 0x00004000 // dropped by a demon
+#define MF2_BOSS 0x00008000 // mobj is a major boss
+#define MF2_FIREDAMAGE 0x00010000 // does fire damage
+#define MF2_NODMGTHRUST 0x00020000 // does not thrust target when
+ // damaging
+#define MF2_TELESTOMP 0x00040000 // mobj can stomp another
+#define MF2_FLOATBOB 0x00080000 // use float bobbing z movement
+#define MF2_DONTDRAW 0x00100000 // don't generate a vissprite
+#define MF2_IMPACT 0x00200000 // an MF_MISSILE mobj can activate
+ // SPAC_IMPACT
+#define MF2_PUSHWALL 0x00400000 // mobj can push walls
+#define MF2_MCROSS 0x00800000 // can activate monster cross lines
+#define MF2_PCROSS 0x01000000 // can activate projectile cross lines
+#define MF2_CANTLEAVEFLOORPIC 0x02000000 // stay within a certain floor type
+#define MF2_NONSHOOTABLE 0x04000000 // mobj is totally non-shootable,
+ // but still considered solid
+#define MF2_INVULNERABLE 0x08000000 // mobj is invulnerable
+#define MF2_DORMANT 0x10000000 // thing is dormant
+#define MF2_ICEDAMAGE 0x20000000 // does ice damage
+#define MF2_SEEKERMISSILE 0x40000000 // is a seeker (for reflection)
+#define MF2_REFLECTIVE 0x80000000 // reflects missiles
+
+//=============================================================================
+
+// ===== Player Class Types =====
+typedef enum
+{
+ PCLASS_FIGHTER,
+ PCLASS_CLERIC,
+ PCLASS_MAGE,
+ PCLASS_PIG,
+ NUMCLASSES
+} pclass_t;
+
+typedef enum
+{
+ PST_LIVE, // playing
+ PST_DEAD, // dead on the ground
+ PST_REBORN // ready to restart
+} playerstate_t;
+
+// psprites are scaled shapes 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 NULL state means not active
+ int tics;
+ fixed_t sx, sy;
+} pspdef_t;
+
+/* Old Heretic key type
+typedef enum
+{
+ key_yellow,
+ key_green,
+ key_blue,
+ NUMKEYS
+} keytype_t;
+*/
+
+typedef enum
+{
+ KEY_1,
+ KEY_2,
+ KEY_3,
+ KEY_4,
+ KEY_5,
+ KEY_6,
+ KEY_7,
+ KEY_8,
+ KEY_9,
+ KEY_A,
+ KEY_B,
+ NUMKEYS
+} keytype_t;
+
+typedef enum
+{
+ ARMOR_ARMOR,
+ ARMOR_SHIELD,
+ ARMOR_HELMET,
+ ARMOR_AMULET,
+ NUMARMOR
+} armortype_t;
+
+typedef enum
+{
+ WP_FIRST,
+ WP_SECOND,
+ WP_THIRD,
+ WP_FOURTH,
+ NUMWEAPONS,
+ WP_NOCHANGE
+} weapontype_t;
+
+typedef enum
+{
+ MANA_1,
+ MANA_2,
+ NUMMANA,
+ MANA_BOTH,
+ MANA_NONE
+} manatype_t;
+
+#define MAX_MANA 200
+
+#define WPIECE1 1
+#define WPIECE2 2
+#define WPIECE3 4
+
+typedef struct
+{
+ manatype_t mana;
+ int upstate;
+ int downstate;
+ int readystate;
+ int atkstate;
+ int holdatkstate;
+ int flashstate;
+} weaponinfo_t;
+
+extern weaponinfo_t WeaponInfo[NUMWEAPONS][NUMCLASSES];
+
+typedef enum
+{
+ arti_none,
+ arti_invulnerability,
+ arti_health,
+ arti_superhealth,
+ arti_healingradius,
+ arti_summon,
+ arti_torch,
+ arti_egg,
+ arti_fly,
+ arti_blastradius,
+ arti_poisonbag,
+ arti_teleportother,
+ arti_speed,
+ arti_boostmana,
+ arti_boostarmor,
+ arti_teleport,
+ // Puzzle artifacts
+ arti_firstpuzzitem,
+ arti_puzzskull = arti_firstpuzzitem,
+ arti_puzzgembig,
+ arti_puzzgemred,
+ arti_puzzgemgreen1,
+ arti_puzzgemgreen2,
+ arti_puzzgemblue1,
+ arti_puzzgemblue2,
+ arti_puzzbook1,
+ arti_puzzbook2,
+ arti_puzzskull2,
+ arti_puzzfweapon,
+ arti_puzzcweapon,
+ arti_puzzmweapon,
+ arti_puzzgear1,
+ arti_puzzgear2,
+ arti_puzzgear3,
+ arti_puzzgear4,
+ NUMARTIFACTS
+} artitype_t;
+
+typedef enum
+{
+ pw_None,
+ pw_invulnerability,
+ pw_allmap,
+ pw_infrared,
+ pw_flight,
+ pw_shield,
+ pw_health2,
+ pw_speed,
+ pw_minotaur,
+ NUMPOWERS
+} powertype_t;
+
+#define INVULNTICS (30*35)
+#define INVISTICS (60*35)
+#define INFRATICS (120*35)
+#define IRONTICS (60*35)
+#define WPNLEV2TICS (40*35)
+#define FLIGHTTICS (60*35)
+#define SPEEDTICS (45*35)
+#define MORPHTICS (40*35)
+#define MAULATORTICS (25*35)
+
+#define MESSAGETICS (4*35)
+#define BLINKTHRESHOLD (4*35)
+
+#define NUMINVENTORYSLOTS NUMARTIFACTS
+
+typedef struct
+{
+ int type;
+ int count;
+} inventory_t;
+
+/*
+================
+=
+= player_t
+=
+================
+*/
+
+typedef struct player_s
+{
+ mobj_t *mo;
+ playerstate_t playerstate;
+ ticcmd_t cmd;
+
+ pclass_t class; // player class type
+
+ fixed_t viewz; // focal origin above r.z
+ fixed_t viewheight; // base height above floor for viewz
+ fixed_t deltaviewheight; // squat speed
+ fixed_t bob; // bounded/scaled total momentum
+
+ int flyheight;
+ int lookdir;
+ boolean centering;
+ int health; // only used between levels, mo->health
+ // is used during levels
+ int armorpoints[NUMARMOR];
+
+ inventory_t inventory[NUMINVENTORYSLOTS];
+ artitype_t readyArtifact;
+ int artifactCount;
+ int inventorySlotNum;
+ int powers[NUMPOWERS];
+ int keys;
+ int pieces; // Fourth Weapon pieces
+ signed int frags[MAXPLAYERS]; // kills of other players
+ weapontype_t readyweapon;
+ weapontype_t pendingweapon; // wp_nochange if not changing
+ boolean weaponowned[NUMWEAPONS];
+ int mana[NUMMANA];
+ int attackdown, usedown; // true if button down last tic
+ int cheats; // bit flags
+
+ int refire; // refired shots are less accurate
+
+ int killcount, itemcount, secretcount; // for intermission
+ char message[80]; // hint messages
+ int messageTics; // counter for showing messages
+ short ultimateMessage;
+ short yellowMessage;
+ int damagecount, bonuscount; // for screen flashing
+ int poisoncount; // screen flash for poison damage
+ mobj_t *poisoner; // NULL for non-player mobjs
+ mobj_t *attacker; // who did damage (NULL for floors)
+ int extralight; // so gun flashes light up areas
+ int fixedcolormap; // can be set to REDCOLORMAP, etc
+ int colormap; // 0-3 for which color to draw player
+ pspdef_t psprites[NUMPSPRITES]; // view sprites (gun, etc)
+ int morphTics; // player is a pig if > 0
+ unsigned int jumpTics; // delay the next jump for a moment
+ unsigned int worldTimer; // total time the player's been playing
+} player_t;
+
+#define CF_NOCLIP 1
+#define CF_GODMODE 2
+#define CF_NOMOMENTUM 4 // not really a cheat, just a debug aid
+
+#define SBARHEIGHT 39 // status bar height at bottom of screen
+
+void NET_SendFrags(player_t * player);
+
+/*
+===============================================================================
+
+ GLOBAL VARIABLES
+
+===============================================================================
+*/
+
+#define TELEFOGHEIGHT (32*FRACUNIT)
+
+extern GameMode_t gamemode; // Always commercial
+extern GameMission_t gamemission; // Always hexen
+
+extern gameaction_t gameaction;
+
+extern boolean paused;
+
+extern boolean DevMaps; // true = map development mode
+extern char *DevMapsDir; // development maps directory
+
+extern boolean nomonsters; // checkparm of -nomonsters
+
+extern boolean respawnparm; // checkparm of -respawn
+
+extern boolean randomclass; // checkparm of -randclass
+
+extern boolean debugmode; // checkparm of -debug
+
+extern boolean usergame; // ok to save / end game
+
+extern boolean ravpic; // checkparm of -ravpic
+
+extern boolean altpal; // checkparm to use an alternate palette routine
+
+extern boolean cdrom; // true if cd-rom mode active ("-cdrom")
+
+extern boolean deathmatch; // only if started as net death
+
+extern boolean netgame; // only true if >1 player
+
+extern boolean cmdfrag; // true if a CMD_FRAG packet should be sent out every
+ // kill
+
+extern boolean playeringame[MAXPLAYERS];
+extern pclass_t PlayerClass[MAXPLAYERS];
+
+extern int consoleplayer; // player taking events and displaying
+
+extern int displayplayer;
+
+extern int viewangleoffset; // ANG90 = left side, ANG270 = right
+
+extern player_t players[MAXPLAYERS];
+
+extern boolean DebugSound; // debug flag for displaying sound info
+
+extern boolean demoplayback;
+extern int maxzone; // Maximum chunk allocated for zone heap
+
+extern int Sky1Texture;
+extern int Sky2Texture;
+
+extern gamestate_t gamestate;
+extern skill_t gameskill;
+//extern boolean respawnmonsters;
+extern int gameepisode;
+extern int gamemap;
+extern int prevmap;
+extern int levelstarttic; // gametic at level start
+extern int leveltime; // tics in game play for par
+
+extern ticcmd_t *netcmds;
+
+#define MAXDEATHMATCHSTARTS 16
+extern mapthing_t *deathmatch_p;
+extern mapthing_t deathmatchstarts[MAXDEATHMATCHSTARTS];
+
+// Position indicator for cooperative net-play reborn
+extern int RebornPosition;
+
+#define MAX_PLAYER_STARTS 8
+extern mapthing_t playerstarts[MAX_PLAYER_STARTS][MAXPLAYERS];
+
+extern int mouseSensitivity;
+
+extern boolean precache; // if true, load all graphics at level load
+
+extern byte *screen; // off screen work buffer, from V_video.c
+
+extern boolean singledemo; // quit after playing a demo from cmdline
+
+extern int bodyqueslot;
+extern skill_t startskill;
+extern int startepisode;
+extern int startmap;
+extern boolean autostart;
+
+extern boolean testcontrols;
+extern int testcontrols_mousespeed;
+
+/*
+===============================================================================
+
+ GLOBAL FUNCTIONS
+
+===============================================================================
+*/
+
+#include "w_wad.h"
+#include "z_zone.h"
+
+//----------
+//BASE LEVEL
+//----------
+void H2_Main(void);
+// not a globally visible function, just included for source reference
+// calls all startup code
+// parses command line options
+// if not overrided, calls N_AdvanceDemo
+
+void H2_GameLoop(void);
+// not a globally visible function, just included for source reference
+// called by H2_Main, never exits
+// manages timing and IO
+// calls all ?_Responder, ?_Ticker, and ?_Drawer functions
+// calls I_GetTime, I_StartFrame, and I_StartTic
+
+//---------
+//SYSTEM IO
+//---------
+byte *I_AllocLow(int length);
+// allocates from low memory under dos, just mallocs under unix
+
+// haleyjd: was WATCOMC, again preserved for historical interest as in Heretic
+#if 0
+extern boolean useexterndriver;
+
+#define EBT_FIRE 1
+#define EBT_OPENDOOR 2
+#define EBT_SPEED 4
+#define EBT_STRAFE 8
+#define EBT_MAP 0x10
+#define EBT_INVENTORYLEFT 0x20
+#define EBT_INVENTORYRIGHT 0x40
+#define EBT_USEARTIFACT 0x80
+#define EBT_FLYDROP 0x100
+#define EBT_CENTERVIEW 0x200
+#define EBT_PAUSE 0x400
+#define EBT_WEAPONCYCLE 0x800
+#define EBT_JUMP 0x1000
+
+typedef struct
+{
+ short vector; // Interrupt vector
+
+ signed char moveForward; // forward/backward (maxes at 50)
+ signed char moveSideways; // strafe (maxes at 24)
+ short angleTurn; // turning speed (640 [slow] 1280 [fast])
+ short angleHead; // head angle (+2080 [left] : 0 [center] : -2048 [right])
+ signed char pitch; // look up/down (-110 : +90)
+ signed char flyDirection; // flyheight (+1/-1)
+ unsigned short buttons; // EBT_* flags
+} externdata_t;
+#endif
+
+//----
+//GAME
+//----
+
+void G_DeathMatchSpawnPlayer(int playernum);
+
+void G_InitNew(skill_t skill, int episode, int map);
+
+void G_DeferedInitNew(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_DeferredNewGame(skill_t skill);
+
+void G_DeferedPlayDemo(char *demo);
+
+void G_LoadGame(int slot);
+// can be called by the startup code or M_Responder
+// calls P_SetupLevel or W_EnterWorld
+void G_DoLoadGame(void);
+
+void G_SaveGame(int slot, char *description);
+// called by M_Responder
+
+void G_RecordDemo(skill_t skill, int numplayers, int episode, int map,
+ char *name);
+// only called by startup code
+
+void G_PlayDemo(char *name);
+void G_TimeDemo(char *name);
+
+void G_TeleportNewMap(int map, int position);
+
+void G_Completed(int map, int position);
+//void G_ExitLevel (void);
+//void G_SecretExitLevel (void);
+
+void G_StartNewGame(skill_t skill);
+void G_StartNewInit(void);
+
+void G_WorldDone(void);
+
+void G_Ticker(void);
+boolean G_Responder(event_t * ev);
+
+void G_ScreenShot(void);
+
+//-------
+//SV_SAVE
+//-------
+
+#define HXS_VERSION_TEXT "HXS Ver 2.37"
+#define HXS_VERSION_TEXT_LENGTH 16
+#define HXS_DESCRIPTION_LENGTH 24
+
+extern char *SavePath;
+
+void SV_SaveGame(int slot, char *description);
+void SV_SaveMap(boolean savePlayers);
+void SV_LoadGame(int slot);
+void SV_MapTeleport(int map, int position);
+void SV_LoadMap(void);
+void SV_InitBaseSlot(void);
+void SV_UpdateRebornSlot(void);
+void SV_ClearRebornSlot(void);
+boolean SV_RebornSlotAvailable(void);
+int SV_GetRebornSlot(void);
+
+//-----
+//PLAY
+//-----
+
+void P_Ticker(void);
+// called by C_Ticker
+// can call G_PlayerExited
+// carries out all thinking of monsters and players
+
+void P_SetupLevel(int episode, int map, int playermask, skill_t skill);
+// called by W_Ticker
+
+void P_Init(void);
+// called by startup code
+
+int P_GetMapCluster(int map);
+int P_TranslateMap(int map);
+int P_GetMapCDTrack(int map);
+int P_GetMapWarpTrans(int map);
+int P_GetMapNextMap(int map);
+int P_GetMapSky1Texture(int map);
+int P_GetMapSky2Texture(int map);
+char *P_GetMapName(int map);
+fixed_t P_GetMapSky1ScrollDelta(int map);
+fixed_t P_GetMapSky2ScrollDelta(int map);
+boolean P_GetMapDoubleSky(int map);
+boolean P_GetMapLightning(int map);
+boolean P_GetMapFadeTable(int map);
+char *P_GetMapSongLump(int map);
+void P_PutMapSongLump(int map, char *lumpName);
+int P_GetCDStartTrack(void);
+int P_GetCDEnd1Track(void);
+int P_GetCDEnd2Track(void);
+int P_GetCDEnd3Track(void);
+int P_GetCDIntermissionTrack(void);
+int P_GetCDTitleTrack(void);
+
+//-------
+//REFRESH
+//-------
+
+extern boolean setsizeneeded;
+
+extern boolean BorderNeedRefresh;
+extern boolean BorderTopRefresh;
+
+extern int UpdateState;
+// define the different areas for the dirty map
+#define I_NOUPDATE 0
+#define I_FULLVIEW 1
+#define I_STATBAR 2
+#define I_MESSAGES 4
+#define I_FULLSCRN 8
+
+void R_RenderPlayerView(player_t * player);
+// called by G_Drawer
+
+void R_Init(void);
+// called by startup code
+
+void R_DrawViewBorder(void);
+void R_DrawTopBorder(void);
+// if the view size is not full screen, draws a border around it
+
+void R_SetViewSize(int blocks, int detail);
+// called by M_Responder
+
+int R_FlatNumForName(char *name);
+
+int R_TextureNumForName(char *name);
+int R_CheckTextureNumForName(char *name);
+// called by P_Ticker for switches and animations
+// returns the texture number for the texture name
+
+
+//----
+//MISC
+//----
+extern int localQuakeHappening[MAXPLAYERS];
+
+int M_DrawText(int x, int y, boolean direct, char *string);
+
+//------------------------------
+// SC_man.c
+//------------------------------
+
+void SC_Open(char *name);
+void SC_OpenLump(char *name);
+void SC_OpenFile(char *name);
+void SC_Close(void);
+boolean SC_GetString(void);
+void SC_MustGetString(void);
+void SC_MustGetStringName(char *name);
+boolean SC_GetNumber(void);
+void SC_MustGetNumber(void);
+void SC_UnGet(void);
+//boolean SC_Check(void);
+boolean SC_Compare(char *text);
+int SC_MatchString(char **strings);
+int SC_MustMatchString(char **strings);
+void SC_ScriptError(char *message);
+
+extern char *sc_String;
+extern int sc_Number;
+extern int sc_Line;
+extern boolean sc_End;
+extern boolean sc_Crossed;
+extern boolean sc_FileScripts;
+extern char *sc_ScriptsDir;
+
+//------------------------------
+// SN_sonix.c
+//------------------------------
+
+enum
+{
+ SEQ_PLATFORM,
+ SEQ_PLATFORM_HEAVY, // same script as a normal platform
+ SEQ_PLATFORM_METAL,
+ SEQ_PLATFORM_CREAK, // same script as a normal platform
+ SEQ_PLATFORM_SILENCE,
+ SEQ_PLATFORM_LAVA,
+ SEQ_PLATFORM_WATER,
+ SEQ_PLATFORM_ICE,
+ SEQ_PLATFORM_EARTH,
+ SEQ_PLATFORM_METAL2,
+ SEQ_DOOR_STONE,
+ SEQ_DOOR_HEAVY,
+ SEQ_DOOR_METAL,
+ SEQ_DOOR_CREAK,
+ SEQ_DOOR_SILENCE,
+ SEQ_DOOR_LAVA,
+ SEQ_DOOR_WATER,
+ SEQ_DOOR_ICE,
+ SEQ_DOOR_EARTH,
+ SEQ_DOOR_METAL2,
+ SEQ_ESOUND_WIND,
+ SEQ_NUMSEQ
+};
+
+typedef enum
+{
+ SEQTYPE_STONE,
+ SEQTYPE_HEAVY,
+ SEQTYPE_METAL,
+ SEQTYPE_CREAK,
+ SEQTYPE_SILENCE,
+ SEQTYPE_LAVA,
+ SEQTYPE_WATER,
+ SEQTYPE_ICE,
+ SEQTYPE_EARTH,
+ SEQTYPE_METAL2,
+ SEQTYPE_NUMSEQ
+} seqtype_t;
+
+void SN_InitSequenceScript(void);
+void SN_StartSequence(mobj_t * mobj, int sequence);
+void SN_StartSequenceName(mobj_t * mobj, char *name);
+void SN_StopSequence(mobj_t * mobj);
+void SN_UpdateActiveSequences(void);
+void SN_StopAllSequences(void);
+int SN_GetSequenceOffset(int sequence, int *sequencePtr);
+void SN_ChangeNodeData(int nodeNum, int seqOffset, int delayTics, int volume,
+ int currentSoundID);
+
+
+typedef struct seqnode_s seqnode_t;
+struct seqnode_s
+{
+ int *sequencePtr;
+ int sequence;
+ mobj_t *mobj;
+ int currentSoundID;
+ int delayTics;
+ int volume;
+ int stopSound;
+ seqnode_t *prev;
+ seqnode_t *next;
+};
+
+extern int ActiveSequences;
+extern seqnode_t *SequenceListHead;
+
+//----------------------
+// Interlude (IN_lude.c)
+//----------------------
+
+#define MAX_INTRMSN_MESSAGE_SIZE 1024
+
+extern boolean intermission;
+extern char ClusterMessage[MAX_INTRMSN_MESSAGE_SIZE];
+
+void IN_Start(void);
+void IN_Ticker(void);
+void IN_Drawer(void);
+
+//----------------------
+// Chat mode (CT_chat.c)
+//----------------------
+
+void CT_Init(void);
+void CT_Drawer(void);
+boolean CT_Responder(event_t * ev);
+void CT_Ticker(void);
+char CT_dequeueChatChar(void);
+
+extern boolean chatmodeon;
+
+//--------------------
+// Finale (F_finale.c)
+//--------------------
+
+void F_Drawer(void);
+void F_Ticker(void);
+void F_StartFinale(void);
+
+//----------------------
+// STATUS BAR (SB_bar.c)
+//----------------------
+
+extern int inv_ptr;
+extern int curpos;
+void SB_Init(void);
+void SB_SetClassData(void);
+boolean SB_Responder(event_t * event);
+void SB_Ticker(void);
+void SB_Drawer(void);
+void Draw_TeleportIcon(void);
+void Draw_SaveIcon(void);
+void Draw_LoadIcon(void);
+
+//-----------------
+// MENU (MN_menu.c)
+//-----------------
+
+void MN_Init(void);
+void MN_ActivateMenu(void);
+void MN_DeactivateMenu(void);
+boolean MN_Responder(event_t * event);
+void MN_Ticker(void);
+void MN_Drawer(void);
+void MN_DrTextA(char *text, int x, int y);
+void MN_DrTextAYellow(char *text, int x, int y);
+int MN_TextAWidth(char *text);
+void MN_DrTextB(char *text, int x, int y);
+int MN_TextBWidth(char *text);
+
+extern int messageson;
+
+#include "sounds.h"
+
+#endif // __H2DEF__
diff --git a/src/hexen/i_header.h b/src/hexen/i_header.h
new file mode 100644
index 00000000..6f930b6a
--- /dev/null
+++ b/src/hexen/i_header.h
@@ -0,0 +1,100 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+#ifndef __I_HEADER_H__
+#define __I_HEADER_H__
+
+#include "h2def.h"
+
+//--------
+//SOUND IO
+//--------
+#define FREQ_LOW 0x40
+#define FREQ_NORM 0x80
+#define FREQ_HIGH 0xff
+
+void I_SetMasterVolume(int volume);
+
+void I_TurnOffSfx(void);
+void I_TurnOnSfx(void);
+void I_TurnOffMusic(void);
+void I_TurnOnMusic(void);
+
+// MUSIC I/O
+//
+
+int I_RegisterSong(void *songdata);
+// called by anything that wants to register a song lump with the sound lib
+// calls Paul's function of the similar name to register music only.
+// note that the song data is the same for any sound card and is paul's
+// MUS format. Returns a handle which will be passed to all other music
+// functions.
+
+void I_UnregisterSong(int handle);
+// called by anything which is finished with a song and no longer needs
+// the sound library to be aware of it. All songs should be stopped
+// before calling this, but it will double check and stop it if necessary.
+
+void I_LoopSong(int handle);
+// 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. the start is faded in over three seconds.
+
+void I_FadeOutSong(int handle, int fotime);
+// called by anything that wishes to stop music.
+// fades out the song over <fotime> milliseconds.
+
+void I_StopSong(int handle);
+// called by anything that wishes to stop music.
+// stops a song abruptly.
+
+// SFX I/O
+//
+
+void *I_GetSoundEffect(char *soundname);
+// called by routines which wish to play a sound effect at some later
+// time. Pass it the lump name of a sound effect WITHOUT the sfx
+// prefix. This means the maximum name length is 7 letters/digits.
+// The prefixes for different sound cards are 'S','M','A', and 'P'.
+// They refer to the card type. The routine will cache in the
+// appropriate sound effect when it is played.
+
+void I_UngetSoundEffect(void *soundset);
+// called by routines which wish to no longer use the sounds at all
+// frees up the associated structure. It stops any currently playing
+// sound effects.
+
+void I_StartSound(channel_t * c, int vol, int sep, int pitch, int priority);
+// Starts a sound in a particular sound channel
+
+void I_UpdateSoundParams(channel_t * c, int vol, int sep, int pitch);
+// Updates the volume, separation, and pitch of a sound channel
+
+void I_StopSound(channel_t * c);
+// Stops a sound channel
+
+int I_SoundIsPlaying(channel_t * c);
+// called by S_*()'s to see if a channel is still playing. Returns 0
+// if no longer playing, 1 if playing.
+
+#endif
diff --git a/src/hexen/i_ibm.c b/src/hexen/i_ibm.c
new file mode 100644
index 00000000..ff476d37
--- /dev/null
+++ b/src/hexen/i_ibm.c
@@ -0,0 +1,1845 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#include <dos.h>
+#include <conio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <graph.h>
+#include "h2def.h"
+#include "i_system.h"
+#include "m_argv.h"
+#include "r_local.h"
+#include "p_local.h" // for P_AproxDistance
+#include "sounds.h"
+#include "i_sound.h"
+#include "st_start.h"
+#include "dmx.h"
+#include "dpmiapi.h"
+
+// Macros
+
+#define DPMI_INT 0x31
+
+#define SEQ_ADDR 0x3C4
+#define SEQ_DATA 0x3C5
+#define REG_MAPMASK 0x02
+
+#define MASK_PLANE0 0x01
+#define MASK_PLANE1 0x02
+#define MASK_PLANE2 0x04
+#define MASK_PLANE3 0x08
+
+#define P0OFFSET 38400*0
+#define P1OFFSET 38400*1
+#define P2OFFSET 38400*2
+#define P3OFFSET 38400*3
+
+#define VID_INT 0x10
+#define VB_SYNC {while(!(inp(0x3da)&8)); while(inp(0x3da)&8);}
+#define BITPLANE(p) (outp(SEQ_ADDR,REG_MAPMASK),outp(SEQ_DATA,(p)))
+
+//#define NOKBD
+//#define NOTIMER
+
+// Public Data
+
+int DisplayTicker = 0;
+
+// Code
+
+void main(int argc, char **argv)
+{
+ myargc = argc;
+ myargv = argv;
+ H2_Main();
+}
+
+void I_StartupNet(void);
+void I_ShutdownNet(void);
+void I_ReadExternDriver(void);
+
+typedef struct
+{
+ unsigned edi, esi, ebp, reserved, ebx, edx, ecx, eax;
+ unsigned short flags, es, ds, fs, gs, ip, cs, sp, ss;
+} dpmiregs_t;
+
+extern dpmiregs_t dpmiregs;
+
+void I_ReadMouse(void);
+
+extern int usemouse, usejoystick;
+
+extern void **lumpcache;
+
+int i_Vector;
+externdata_t *i_ExternData;
+boolean useexterndriver;
+
+//==========================================================================
+//
+// I_UpdateCDMusic
+//
+// Updates playing time for current track, and restarts the track, if
+// needed
+//
+//==========================================================================
+
+void I_UpdateCDMusic(void)
+{
+ extern boolean MenuActive;
+
+ if (MusicPaused || i_CDMusicLength < 0 || (paused && !MenuActive))
+ { // Non-looping song/song paused
+ return;
+ }
+ i_CDMusicLength -= gametic - oldTic;
+ oldTic = gametic;
+ if (i_CDMusicLength <= 0)
+ {
+ S_StartSong(gamemap, true);
+ }
+}
+
+/*
+============================================================================
+
+ CONSTANTS
+
+============================================================================
+*/
+
+#define SC_INDEX 0x3C4
+#define SC_RESET 0
+#define SC_CLOCK 1
+#define SC_MAPMASK 2
+#define SC_CHARMAP 3
+#define SC_MEMMODE 4
+
+#define CRTC_INDEX 0x3D4
+#define CRTC_H_TOTAL 0
+#define CRTC_H_DISPEND 1
+#define CRTC_H_BLANK 2
+#define CRTC_H_ENDBLANK 3
+#define CRTC_H_RETRACE 4
+#define CRTC_H_ENDRETRACE 5
+#define CRTC_V_TOTAL 6
+#define CRTC_OVERFLOW 7
+#define CRTC_ROWSCAN 8
+#define CRTC_MAXSCANLINE 9
+#define CRTC_CURSORSTART 10
+#define CRTC_CURSOREND 11
+#define CRTC_STARTHIGH 12
+#define CRTC_STARTLOW 13
+#define CRTC_CURSORHIGH 14
+#define CRTC_CURSORLOW 15
+#define CRTC_V_RETRACE 16
+#define CRTC_V_ENDRETRACE 17
+#define CRTC_V_DISPEND 18
+#define CRTC_OFFSET 19
+#define CRTC_UNDERLINE 20
+#define CRTC_V_BLANK 21
+#define CRTC_V_ENDBLANK 22
+#define CRTC_MODE 23
+#define CRTC_LINECOMPARE 24
+
+
+#define GC_INDEX 0x3CE
+#define GC_SETRESET 0
+#define GC_ENABLESETRESET 1
+#define GC_COLORCOMPARE 2
+#define GC_DATAROTATE 3
+#define GC_READMAP 4
+#define GC_MODE 5
+#define GC_MISCELLANEOUS 6
+#define GC_COLORDONTCARE 7
+#define GC_BITMASK 8
+
+#define ATR_INDEX 0x3c0
+#define ATR_MODE 16
+#define ATR_OVERSCAN 17
+#define ATR_COLORPLANEENABLE 18
+#define ATR_PELPAN 19
+#define ATR_COLORSELECT 20
+
+#define STATUS_REGISTER_1 0x3da
+
+#define PEL_WRITE_ADR 0x3c8
+#define PEL_READ_ADR 0x3c7
+#define PEL_DATA 0x3c9
+#define PEL_MASK 0x3c6
+
+// boolean grmode;
+
+//==================================================
+//
+// joystick vars
+//
+//==================================================
+
+boolean joystickpresent;
+extern unsigned joystickx, joysticky;
+boolean I_ReadJoystick(void); // returns false if not connected
+
+
+//==================================================
+
+#define VBLCOUNTER 34000 // hardware tics to a frame
+
+
+#define TIMERINT 8
+#define KEYBOARDINT 9
+
+#define CRTCOFF (_inbyte(STATUS_REGISTER_1)&1)
+#define CLI _disable()
+#define STI _enable()
+
+#define _outbyte(x,y) (outp(x,y))
+#define _outhword(x,y) (outpw(x,y))
+
+#define _inbyte(x) (inp(x))
+#define _inhword(x) (inpw(x))
+
+#define MOUSEB1 1
+#define MOUSEB2 2
+#define MOUSEB3 4
+
+boolean mousepresent;
+//static int tsm_ID = -1; // tsm init flag
+
+//===============================
+
+int ticcount;
+
+// REGS stuff used for int calls
+union REGS regs;
+struct SREGS segregs;
+
+boolean novideo; // if true, stay in text mode for debugging
+
+#define KBDQUESIZE 32
+byte keyboardque[KBDQUESIZE];
+int kbdtail, kbdhead;
+
+#define KEY_LSHIFT 0xfe
+
+#define KEY_INS (0x80+0x52)
+#define KEY_DEL (0x80+0x53)
+#define KEY_PGUP (0x80+0x49)
+#define KEY_PGDN (0x80+0x51)
+#define KEY_HOME (0x80+0x47)
+#define KEY_END (0x80+0x4f)
+
+#define SC_RSHIFT 0x36
+#define SC_LSHIFT 0x2a
+
+byte scantokey[128] = {
+// 0 1 2 3 4 5 6 7
+// 8 9 A B C D E F
+ 0, 27, '1', '2', '3', '4', '5', '6',
+ '7', '8', '9', '0', '-', '=', KEY_BACKSPACE, 9, // 0
+ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
+ 'o', 'p', '[', ']', 13, KEY_RCTRL, 'a', 's', // 1
+ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
+ 39, '`', KEY_LSHIFT, 92, 'z', 'x', 'c', 'v', // 2
+ 'b', 'n', 'm', ',', '.', '/', KEY_RSHIFT, '*',
+ KEY_RALT, ' ', 0, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, // 3
+ KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, 0, 0, KEY_HOME,
+ KEY_UPARROW, KEY_PGUP, '-', KEY_LEFTARROW, '5', KEY_RIGHTARROW, '+', KEY_END, //4
+ KEY_DOWNARROW, KEY_PGDN, KEY_INS, KEY_DEL, 0, 0, 0, KEY_F11,
+ KEY_F12, 0, 0, 0, 0, 0, 0, 0, // 5
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, // 6
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 // 7
+};
+
+//==========================================================================
+
+//--------------------------------------------------------------------------
+//
+// FUNC I_GetTime
+//
+// Returns time in 1/35th second tics.
+//
+//--------------------------------------------------------------------------
+
+int I_GetTime(void)
+{
+#ifdef NOTIMER
+ ticcount++;
+#endif
+ return (ticcount);
+}
+
+//--------------------------------------------------------------------------
+//
+// PROC I_ColorBorder
+//
+//--------------------------------------------------------------------------
+
+/*
+void I_ColorBorder(void)
+{
+ int i;
+
+ I_WaitVBL(1);
+ _outbyte(PEL_WRITE_ADR, 0);
+ for(i = 0; i < 3; i++)
+ {
+ _outbyte(PEL_DATA, 63);
+ }
+}
+*/
+
+//--------------------------------------------------------------------------
+//
+// PROC I_UnColorBorder
+//
+//--------------------------------------------------------------------------
+
+/*
+void I_UnColorBorder(void)
+{
+ int i;
+
+ I_WaitVBL(1);
+ _outbyte(PEL_WRITE_ADR, 0);
+ for(i = 0; i < 3; i++)
+ {
+ _outbyte(PEL_DATA, 0);
+ }
+}
+*/
+
+/*
+============================================================================
+
+ USER INPUT
+
+============================================================================
+*/
+
+//--------------------------------------------------------------------------
+//
+// PROC I_WaitVBL
+//
+//--------------------------------------------------------------------------
+
+void I_WaitVBL(int vbls)
+{
+ int stat;
+
+ if (novideo)
+ {
+ return;
+ }
+ while (vbls--)
+ {
+ do
+ {
+ stat = inp(STATUS_REGISTER_1);
+ if (stat & 8)
+ {
+ break;
+ }
+ }
+ while (1);
+ do
+ {
+ stat = inp(STATUS_REGISTER_1);
+ if ((stat & 8) == 0)
+ {
+ break;
+ }
+ }
+ while (1);
+ }
+}
+
+//--------------------------------------------------------------------------
+//
+// PROC I_SetPalette
+//
+// Palette source must use 8 bit RGB elements.
+//
+//--------------------------------------------------------------------------
+
+void I_SetPalette(byte * palette)
+{
+ int i;
+
+ if (novideo)
+ {
+ return;
+ }
+ I_WaitVBL(1);
+ _outbyte(PEL_WRITE_ADR, 0);
+ for (i = 0; i < 768; i++)
+ {
+ _outbyte(PEL_DATA, (gammatable[usegamma][*palette++]) >> 2);
+ }
+}
+
+/*
+============================================================================
+
+ GRAPHICS MODE
+
+============================================================================
+*/
+
+byte *pcscreen, *destscreen, *destview;
+
+
+/*
+==============
+=
+= I_Update
+=
+==============
+*/
+
+int UpdateState;
+extern int screenblocks;
+
+void I_Update(void)
+{
+ int i;
+ byte *dest;
+ int tics;
+ static int lasttic;
+
+//
+// blit screen to video
+//
+ if (DisplayTicker)
+ {
+ if (screenblocks > 9 || UpdateState & (I_FULLSCRN | I_MESSAGES))
+ {
+ dest = (byte *) screen;
+ }
+ else
+ {
+ dest = (byte *) pcscreen;
+ }
+ tics = ticcount - lasttic;
+ lasttic = ticcount;
+ if (tics > 20)
+ {
+ tics = 20;
+ }
+ for (i = 0; i < tics; i++)
+ {
+ *dest = 0xff;
+ dest += 2;
+ }
+ for (i = tics; i < 20; i++)
+ {
+ *dest = 0x00;
+ dest += 2;
+ }
+ }
+
+ //memset(pcscreen, 255, SCREENHEIGHT*SCREENWIDTH);
+
+ if (UpdateState == I_NOUPDATE)
+ {
+ return;
+ }
+ if (UpdateState & I_FULLSCRN)
+ {
+ memcpy(pcscreen, screen, SCREENWIDTH * SCREENHEIGHT);
+ UpdateState = I_NOUPDATE; // clear out all draw types
+ }
+ if (UpdateState & I_FULLVIEW)
+ {
+ if (UpdateState & I_MESSAGES && screenblocks > 7)
+ {
+ for (i = 0; i <
+ (viewwindowy + viewheight) * SCREENWIDTH; i += SCREENWIDTH)
+ {
+ memcpy(pcscreen + i, screen + i, SCREENWIDTH);
+ }
+ UpdateState &= ~(I_FULLVIEW | I_MESSAGES);
+ }
+ else
+ {
+ for (i = viewwindowy * SCREENWIDTH + viewwindowx; i <
+ (viewwindowy + viewheight) * SCREENWIDTH; i += SCREENWIDTH)
+ {
+ memcpy(pcscreen + i, screen + i, viewwidth);
+ }
+ UpdateState &= ~I_FULLVIEW;
+ }
+ }
+ if (UpdateState & I_STATBAR)
+ {
+ memcpy(pcscreen + SCREENWIDTH * (SCREENHEIGHT - SBARHEIGHT),
+ screen + SCREENWIDTH * (SCREENHEIGHT - SBARHEIGHT),
+ SCREENWIDTH * SBARHEIGHT);
+ UpdateState &= ~I_STATBAR;
+ }
+ if (UpdateState & I_MESSAGES)
+ {
+ memcpy(pcscreen, screen, SCREENWIDTH * 28);
+ UpdateState &= ~I_MESSAGES;
+ }
+
+
+// memcpy(pcscreen, screen, SCREENHEIGHT*SCREENWIDTH);
+}
+
+//--------------------------------------------------------------------------
+//
+// PROC I_InitGraphics
+//
+//--------------------------------------------------------------------------
+
+void I_InitGraphics(void)
+{
+ if (novideo)
+ {
+ return;
+ }
+ //grmode = true;
+ regs.w.ax = 0x13;
+ int386(0x10, (const union REGS *) &regs, &regs);
+ pcscreen = destscreen = (byte *) 0xa0000;
+ I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE));
+}
+
+//--------------------------------------------------------------------------
+//
+// PROC I_ShutdownGraphics
+//
+//--------------------------------------------------------------------------
+
+void I_ShutdownGraphics(void)
+{
+ byte mode;
+
+ // don't reset mode if it didn't get set
+ mode = *(byte *) 0x449;
+ if (mode == 0x12 || mode == 0x13)
+ {
+ regs.w.ax = 3;
+ int386(0x10, &regs, &regs); // back to text mode
+ }
+}
+
+//--------------------------------------------------------------------------
+//
+// PROC I_ReadScreen
+//
+// Reads the screen currently displayed into a linear buffer.
+//
+//--------------------------------------------------------------------------
+
+/*
+void I_ReadScreen(byte *scr)
+{
+ memcpy(scr, screen, SCREENWIDTH*SCREENHEIGHT);
+}
+*/
+
+//===========================================================================
+
+/*
+===================
+=
+= I_StartTic
+=
+// called by D_DoomLoop
+// called before processing each tic in a frame
+// can call D_PostEvent
+// asyncronous interrupt functions should maintain private ques that are
+// read by the syncronous functions to be converted into events
+===================
+*/
+
+/*
+ OLD STARTTIC STUFF
+
+void I_StartTic (void)
+{
+ int k;
+ event_t ev;
+
+
+ I_ReadMouse ();
+
+//
+// keyboard events
+//
+ while (kbdtail < kbdhead)
+ {
+ k = keyboardque[kbdtail&(KBDQUESIZE-1)];
+
+// if (k==14)
+// I_Error ("exited");
+
+ kbdtail++;
+
+ // extended keyboard shift key bullshit
+ if ( (k&0x7f)==KEY_RSHIFT )
+ {
+ if ( keyboardque[(kbdtail-2)&(KBDQUESIZE-1)]==0xe0 )
+ continue;
+ k &= 0x80;
+ k |= KEY_RSHIFT;
+ }
+
+ if (k==0xe0)
+ continue; // special / pause keys
+ if (keyboardque[(kbdtail-2)&(KBDQUESIZE-1)] == 0xe1)
+ continue; // pause key bullshit
+
+ if (k==0xc5 && keyboardque[(kbdtail-2)&(KBDQUESIZE-1)] == 0x9d)
+ {
+ ev.type = ev_keydown;
+ ev.data1 = KEY_PAUSE;
+ D_PostEvent (&ev);
+ continue;
+ }
+
+ if (k&0x80)
+ ev.type = ev_keyup;
+ else
+ ev.type = ev_keydown;
+ k &= 0x7f;
+
+ ev.data1 = k;
+ //ev.data1 = scantokey[k];
+
+ D_PostEvent (&ev);
+ }
+}
+*/
+
+#define SC_UPARROW 0x48
+#define SC_DOWNARROW 0x50
+#define SC_LEFTARROW 0x4b
+#define SC_RIGHTARROW 0x4d
+
+void I_StartTic(void)
+{
+ int k;
+ event_t ev;
+
+
+ I_ReadMouse();
+
+//
+// keyboard events
+//
+ while (kbdtail < kbdhead)
+ {
+ k = keyboardque[kbdtail & (KBDQUESIZE - 1)];
+ kbdtail++;
+
+ // extended keyboard shift key bullshit
+ if ((k & 0x7f) == SC_LSHIFT || (k & 0x7f) == SC_RSHIFT)
+ {
+ if (keyboardque[(kbdtail - 2) & (KBDQUESIZE - 1)] == 0xe0)
+ continue;
+ k &= 0x80;
+ k |= SC_RSHIFT;
+ }
+
+ if (k == 0xe0)
+ continue; // special / pause keys
+ if (keyboardque[(kbdtail - 2) & (KBDQUESIZE - 1)] == 0xe1)
+ continue; // pause key bullshit
+
+ if (k == 0xc5
+ && keyboardque[(kbdtail - 2) & (KBDQUESIZE - 1)] == 0x9d)
+ {
+ ev.type = ev_keydown;
+ ev.data1 = KEY_PAUSE;
+ H2_PostEvent(&ev);
+ continue;
+ }
+
+ if (k & 0x80)
+ ev.type = ev_keyup;
+ else
+ ev.type = ev_keydown;
+ k &= 0x7f;
+ switch (k)
+ {
+ case SC_UPARROW:
+ ev.data1 = KEY_UPARROW;
+ break;
+ case SC_DOWNARROW:
+ ev.data1 = KEY_DOWNARROW;
+ break;
+ case SC_LEFTARROW:
+ ev.data1 = KEY_LEFTARROW;
+ break;
+ case SC_RIGHTARROW:
+ ev.data1 = KEY_RIGHTARROW;
+ break;
+ default:
+ ev.data1 = scantokey[k];
+ break;
+ }
+ H2_PostEvent(&ev);
+ }
+
+}
+
+
+/*
+void I_ReadKeys (void)
+{
+ int k;
+
+
+ while (1)
+ {
+ while (kbdtail < kbdhead)
+ {
+ k = keyboardque[kbdtail&(KBDQUESIZE-1)];
+ kbdtail++;
+ printf ("0x%x\n",k);
+ if (k == 1)
+ I_Quit ();
+ }
+ }
+}
+*/
+
+/*
+===============
+=
+= I_StartFrame
+=
+===============
+*/
+
+void I_StartFrame(void)
+{
+ I_JoystickEvents();
+ if (useexterndriver)
+ {
+ DPMIInt(i_Vector);
+ }
+}
+
+/*
+============================================================================
+
+ TIMER INTERRUPT
+
+============================================================================
+*/
+
+/*
+void I_ColorBlack (int r, int g, int b)
+{
+_outbyte (PEL_WRITE_ADR,0);
+_outbyte(PEL_DATA,r);
+_outbyte(PEL_DATA,g);
+_outbyte(PEL_DATA,b);
+}
+*/
+
+
+/*
+================
+=
+= I_TimerISR
+=
+================
+*/
+
+int I_TimerISR(void)
+{
+ ticcount++;
+ return 0;
+}
+
+/*
+============================================================================
+
+ KEYBOARD
+
+============================================================================
+*/
+
+void (__interrupt __far * oldkeyboardisr) () = NULL;
+
+int lastpress;
+
+/*
+================
+=
+= I_KeyboardISR
+=
+================
+*/
+
+void __interrupt I_KeyboardISR(void)
+{
+// Get the scan code
+
+ keyboardque[kbdhead & (KBDQUESIZE - 1)] = lastpress = _inbyte(0x60);
+ kbdhead++;
+
+// acknowledge the interrupt
+
+ _outbyte(0x20, 0x20);
+}
+
+
+
+/*
+===============
+=
+= I_StartupKeyboard
+=
+===============
+*/
+
+void I_StartupKeyboard(void)
+{
+#ifndef NOKBD
+ oldkeyboardisr = _dos_getvect(KEYBOARDINT);
+ _dos_setvect(0x8000 | KEYBOARDINT, I_KeyboardISR);
+#endif
+
+//I_ReadKeys ();
+}
+
+
+void I_ShutdownKeyboard(void)
+{
+ if (oldkeyboardisr)
+ _dos_setvect(KEYBOARDINT, oldkeyboardisr);
+ *(short *) 0x41c = *(short *) 0x41a; // clear bios key buffer
+}
+
+
+
+/*
+============================================================================
+
+ MOUSE
+
+============================================================================
+*/
+
+
+int I_ResetMouse(void)
+{
+ regs.w.ax = 0; // reset
+ int386(0x33, &regs, &regs);
+ return regs.w.ax;
+}
+
+
+
+/*
+================
+=
+= StartupMouse
+=
+================
+*/
+
+void I_StartupCyberMan(void);
+
+void I_StartupMouse(void)
+{
+ //
+ // General mouse detection
+ //
+ mousepresent = 0;
+ if (M_CheckParm("-nomouse") || !usemouse)
+ return;
+
+ if (I_ResetMouse() != 0xffff)
+ {
+ ST_Message("Mouse: not present\n");
+ return;
+ }
+ ST_Message("Mouse: detected\n");
+
+ mousepresent = 1;
+
+ I_StartupCyberMan();
+}
+
+
+/*
+================
+=
+= ShutdownMouse
+=
+================
+*/
+
+void I_ShutdownMouse(void)
+{
+ if (!mousepresent)
+ return;
+
+ I_ResetMouse();
+}
+
+
+/*
+================
+=
+= I_ReadMouse
+=
+================
+*/
+
+void I_ReadMouse(void)
+{
+ event_t ev;
+
+//
+// mouse events
+//
+ if (!mousepresent)
+ return;
+
+ ev.type = ev_mouse;
+
+ memset(&dpmiregs, 0, sizeof(dpmiregs));
+ dpmiregs.eax = 3; // read buttons / position
+ DPMIInt(0x33);
+ ev.data1 = dpmiregs.ebx;
+
+ dpmiregs.eax = 11; // read counters
+ DPMIInt(0x33);
+ ev.data2 = (short) dpmiregs.ecx;
+ ev.data3 = -(short) dpmiregs.edx;
+
+ H2_PostEvent(&ev);
+}
+
+/*
+============================================================================
+
+ JOYSTICK
+
+============================================================================
+*/
+
+int joyxl, joyxh, joyyl, joyyh;
+
+boolean WaitJoyButton(void)
+{
+ int oldbuttons, buttons;
+
+ oldbuttons = 0;
+ do
+ {
+ I_WaitVBL(1);
+ buttons = ((inp(0x201) >> 4) & 1) ^ 1;
+ if (buttons != oldbuttons)
+ {
+ oldbuttons = buttons;
+ continue;
+ }
+
+ if ((lastpress & 0x7f) == 1)
+ {
+ joystickpresent = false;
+ return false;
+ }
+ }
+ while (!buttons);
+
+ do
+ {
+ I_WaitVBL(1);
+ buttons = ((inp(0x201) >> 4) & 1) ^ 1;
+ if (buttons != oldbuttons)
+ {
+ oldbuttons = buttons;
+ continue;
+ }
+
+ if ((lastpress & 0x7f) == 1)
+ {
+ joystickpresent = false;
+ return false;
+ }
+ }
+ while (buttons);
+
+ return true;
+}
+
+
+
+/*
+===============
+=
+= I_StartupJoystick
+=
+===============
+*/
+
+int basejoyx, basejoyy;
+
+void I_StartupJoystick(void)
+{
+ int centerx, centery;
+
+ joystickpresent = 0;
+ if (M_CheckParm("-nojoy") || !usejoystick)
+ return;
+
+ if (!I_ReadJoystick())
+ {
+ joystickpresent = false;
+ ST_Message("joystick not found\n ");
+ return;
+ }
+ ST_Message("joystick found\n");
+ joystickpresent = true;
+
+ ST_RealMessage("CENTER the joystick and press button 1:");
+ if (!WaitJoyButton())
+ return;
+ I_ReadJoystick();
+ centerx = joystickx;
+ centery = joysticky;
+
+ ST_RealMessage
+ ("\nPush the joystick to the UPPER LEFT corner and press button 1:");
+ if (!WaitJoyButton())
+ return;
+ I_ReadJoystick();
+ joyxl = (centerx + joystickx) / 2;
+ joyyl = (centerx + joysticky) / 2;
+
+ ST_RealMessage
+ ("\nPush the joystick to the LOWER RIGHT corner and press button 1:");
+ if (!WaitJoyButton())
+ return;
+ I_ReadJoystick();
+ joyxh = (centerx + joystickx) / 2;
+ joyyh = (centery + joysticky) / 2;
+ ST_RealMessage("\n");
+}
+
+/*
+===============
+=
+= I_JoystickEvents
+=
+===============
+*/
+
+void I_JoystickEvents(void)
+{
+ event_t ev;
+
+//
+// joystick events
+//
+ if (!joystickpresent)
+ return;
+
+ I_ReadJoystick();
+ ev.type = ev_joystick;
+ ev.data1 = ((inp(0x201) >> 4) & 15) ^ 15;
+
+ if (joystickx < joyxl)
+ ev.data2 = -1;
+ else if (joystickx > joyxh)
+ ev.data2 = 1;
+ else
+ ev.data2 = 0;
+ if (joysticky < joyyl)
+ ev.data3 = -1;
+ else if (joysticky > joyyh)
+ ev.data3 = 1;
+ else
+ ev.data3 = 0;
+
+ H2_PostEvent(&ev);
+}
+
+
+
+/*
+============================================================================
+
+ DPMI STUFF
+
+============================================================================
+*/
+
+#define REALSTACKSIZE 1024
+
+dpmiregs_t dpmiregs;
+
+unsigned realstackseg;
+
+void I_DivException(void);
+int I_SetDivException(void);
+
+/*
+void DPMIFarCall (void)
+{
+ segread (&segregs);
+ regs.w.ax = 0x301;
+ regs.w.bx = 0;
+ regs.w.cx = 0;
+ regs.x.edi = (unsigned)&dpmiregs;
+ segregs.es = segregs.ds;
+ int386x( DPMI_INT, &regs, &regs, &segregs );
+}
+*/
+
+void DPMIInt(int i)
+{
+ dpmiregs.ss = realstackseg;
+ dpmiregs.sp = REALSTACKSIZE - 4;
+
+ segread(&segregs);
+ regs.w.ax = 0x300;
+ regs.w.bx = i;
+ regs.w.cx = 0;
+ regs.x.edi = (unsigned) &dpmiregs;
+ segregs.es = segregs.ds;
+ int386x(DPMI_INT, &regs, &regs, &segregs);
+}
+
+
+/*
+==============
+=
+= I_StartupDPMI
+=
+==============
+*/
+
+void I_StartupDPMI(void)
+{
+// extern char __begtext;
+// extern char ___argc;
+// int n,d;
+
+//
+// allocate a decent stack for real mode ISRs
+//
+ realstackseg = (int) I_AllocLow(1024) >> 4;
+
+//
+// lock the entire program down
+//
+
+// _dpmi_lockregion (&__begtext, &___argc - &__begtext);
+
+
+//
+// catch divide by 0 exception
+//
+#if 0
+ segread(&segregs);
+ regs.w.ax = 0x0203; // DPMI set processor exception handler vector
+ regs.w.bx = 0; // int 0
+ regs.w.cx = segregs.cs;
+ regs.x.edx = (int) &I_DivException;
+ printf("%x : %x\n", regs.w.cx, regs.x.edx);
+ int386(DPMI_INT, &regs, &regs);
+#endif
+
+#if 0
+ n = I_SetDivException();
+ printf("return: %i\n", n);
+ n = 100;
+ d = 0;
+ printf("100 / 0 = %i\n", n / d);
+
+ exit(1);
+#endif
+}
+
+
+
+/*
+============================================================================
+
+ TIMER INTERRUPT
+
+============================================================================
+*/
+
+void (__interrupt __far * oldtimerisr) ();
+
+
+/*
+void IO_ColorBlack (int r, int g, int b)
+{
+_outbyte (PEL_WRITE_ADR,0);
+_outbyte(PEL_DATA,r);
+_outbyte(PEL_DATA,g);
+_outbyte(PEL_DATA,b);
+}
+*/
+
+
+/*
+================
+=
+= IO_TimerISR
+=
+================
+*/
+
+//void __interrupt IO_TimerISR (void)
+
+void __interrupt __far IO_TimerISR(void)
+{
+ ticcount++;
+ _outbyte(0x20, 0x20); // Ack the interrupt
+}
+
+/*
+=====================
+=
+= IO_SetTimer0
+=
+= Sets system timer 0 to the specified speed
+=
+=====================
+*/
+
+void IO_SetTimer0(int speed)
+{
+ if (speed > 0 && speed < 150)
+ I_Error("INT_SetTimer0: %i is a bad value", speed);
+
+ _outbyte(0x43, 0x36); // Change timer 0
+ _outbyte(0x40, speed);
+ _outbyte(0x40, speed >> 8);
+}
+
+
+
+/*
+===============
+=
+= IO_StartupTimer
+=
+===============
+*/
+
+/*
+void IO_StartupTimer (void)
+{
+ oldtimerisr = _dos_getvect(TIMERINT);
+
+ _dos_setvect (0x8000 | TIMERINT, IO_TimerISR);
+ IO_SetTimer0 (VBLCOUNTER);
+}
+*/
+
+void IO_ShutdownTimer(void)
+{
+ if (oldtimerisr)
+ {
+ IO_SetTimer0(0); // back to 18.4 ips
+ _dos_setvect(TIMERINT, oldtimerisr);
+ }
+}
+
+//===========================================================================
+
+
+/*
+===============
+=
+= I_Init
+=
+= hook interrupts and set graphics mode
+=
+===============
+*/
+
+void I_Init(void)
+{
+ extern void I_StartupTimer(void);
+
+ novideo = M_CheckParm("novideo");
+ ST_Message(" I_StartupDPMI\n");
+ I_StartupDPMI();
+ ST_Message(" I_StartupMouse ");
+ I_StartupMouse();
+// tprintf("I_StartupJoystick ",1);
+// I_StartupJoystick();
+// tprintf("I_StartupKeyboard ",1);
+// I_StartupKeyboard();
+ ST_Message(" S_Init... ");
+ S_Init();
+ //IO_StartupTimer();
+ S_Start();
+}
+
+
+/*
+===============
+=
+= I_Shutdown
+=
+= return to default system state
+=
+===============
+*/
+
+void I_Shutdown(void)
+{
+ I_ShutdownGraphics();
+ IO_ShutdownTimer();
+ S_ShutDown();
+ I_ShutdownMouse();
+ I_ShutdownKeyboard();
+
+ IO_SetTimer0(0);
+}
+
+
+/*
+================
+=
+= I_Error
+=
+================
+*/
+
+void I_Error(char *error, ...)
+{
+ union REGS regs;
+
+ va_list argptr;
+
+ D_QuitNetGame();
+ I_Shutdown();
+ va_start(argptr, error);
+ regs.x.eax = 0x3;
+ int386(0x10, &regs, &regs);
+ vprintf(error, argptr);
+ va_end(argptr);
+ printf("\n");
+ exit(1);
+}
+
+//--------------------------------------------------------------------------
+//
+// I_Quit
+//
+// Shuts down net game, saves defaults, prints the exit text message,
+// goes to text mode, and exits.
+//
+//--------------------------------------------------------------------------
+
+void I_Quit(void)
+{
+ D_QuitNetGame();
+ M_SaveDefaults();
+ I_Shutdown();
+
+// scr = (byte *)W_CacheLumpName("ENDTEXT", PU_CACHE);
+/*
+ memcpy((void *)0xb8000, scr, 80*25*2);
+ regs.w.ax = 0x0200;
+ regs.h.bh = 0;
+ regs.h.dl = 0;
+ regs.h.dh = 23;
+ int386(0x10, (const union REGS *)&regs, &regs); // Set text pos
+ _settextposition(24, 1);
+*/
+ printf("\nHexen: Beyond Heretic\n");
+ exit(0);
+}
+
+/*
+===============
+=
+= I_ZoneBase
+=
+===============
+*/
+
+byte *I_ZoneBase(int *size)
+{
+ int meminfo[32];
+ int heap;
+ byte *ptr;
+
+ memset(meminfo, 0, sizeof(meminfo));
+ segread(&segregs);
+ segregs.es = segregs.ds;
+ regs.w.ax = 0x500; // get memory info
+ regs.x.edi = (int) &meminfo;
+ int386x(0x31, &regs, &regs, &segregs);
+
+ heap = meminfo[0];
+ ST_Message(" DPMI memory: 0x%x, ", heap);
+ ST_Message("Maxzone: 0x%x\n", maxzone);
+
+ do
+ {
+ heap -= 0x10000; // leave 64k alone
+ if (heap > maxzone)
+ heap = maxzone;
+ ptr = malloc(heap);
+ }
+ while (!ptr);
+
+ ST_Message(" 0x%x allocated for zone, ", heap);
+ ST_Message("ZoneBase: 0x%X\n", (int) ptr);
+
+ if (heap < 0x180000)
+ I_Error(" Insufficient DPMI memory!");
+#if 0
+ regs.w.ax = 0x501; // allocate linear block
+ regs.w.bx = heap >> 16;
+ regs.w.cx = heap & 0xffff;
+ int386(0x31, &regs, &regs);
+ if (regs.w.cflag)
+ I_Error(" Couldn't allocate DPMI memory!");
+
+ block = (regs.w.si << 16) + regs.w.di;
+#endif
+
+ *size = heap;
+ return ptr;
+}
+
+/*
+=============
+=
+= I_AllocLow
+=
+=============
+*/
+
+byte *I_AllocLow(int length)
+{
+ byte *mem;
+
+ // DPMI call 100h allocates DOS memory
+ segread(&segregs);
+ regs.w.ax = 0x0100; // DPMI allocate DOS memory
+ regs.w.bx = (length + 15) / 16;
+ int386(DPMI_INT, &regs, &regs);
+// segment = regs.w.ax;
+// selector = regs.w.dx;
+ if (regs.w.cflag != 0)
+ I_Error("I_AllocLow: DOS alloc of %i failed, %i free",
+ length, regs.w.bx * 16);
+
+
+ mem = (void *) ((regs.x.eax & 0xFFFF) << 4);
+
+ memset(mem, 0, length);
+ return mem;
+}
+
+/*
+============================================================================
+
+ NETWORKING
+
+============================================================================
+*/
+
+/* // FUCKED LINES
+typedef struct
+{
+ char priv[508];
+ } doomdata_t;
+*/// FUCKED LINES
+
+#define DOOMCOM_ID 0x12345678l
+
+/* // FUCKED LINES
+typedef struct
+{
+ long id;
+ short intnum; // DOOM executes an int to execute commands
+
+// communication between DOOM and the driver
+ short command; // CMD_SEND or CMD_GET
+ short remotenode; // dest for send, set by get (-1 = no packet)
+ short datalength; // bytes in doomdata to be sent
+
+// info common to all nodes
+ short numnodes; // console is allways node 0
+ short ticdup; // 1 = no duplication, 2-5 = dup for slow nets
+ short extratics; // 1 = send a backup tic in every packet
+ short deathmatch; // 1 = deathmatch
+ short savegame; // -1 = new game, 0-5 = load savegame
+ short episode; // 1-3
+ short map; // 1-9
+ short skill; // 1-5
+
+// info specific to this node
+ short consoleplayer;
+ short numplayers;
+ short angleoffset; // 1 = left, 0 = center, -1 = right
+ short drone; // 1 = drone
+
+// packet data to be sent
+ doomdata_t data;
+ } doomcom_t;
+*/// FUCKED LINES
+
+extern doomcom_t *doomcom;
+
+/*
+====================
+=
+= I_InitNetwork
+=
+====================
+*/
+
+void I_InitNetwork(void)
+{
+ int i;
+
+ i = M_CheckParm("-net");
+ if (!i)
+ {
+ //
+ // single player game
+ //
+ doomcom = malloc(sizeof(*doomcom));
+ memset(doomcom, 0, sizeof(*doomcom));
+ netgame = false;
+ doomcom->id = DOOMCOM_ID;
+ doomcom->numplayers = doomcom->numnodes = 1;
+ doomcom->deathmatch = false;
+ doomcom->consoleplayer = 0;
+ doomcom->ticdup = 1;
+ doomcom->extratics = 0;
+ return;
+ }
+
+ netgame = true;
+ doomcom = (doomcom_t *) atoi(myargv[i + 1]);
+//DEBUG
+ doomcom->skill = startskill;
+ doomcom->episode = startepisode;
+ doomcom->map = startmap;
+ doomcom->deathmatch = deathmatch;
+
+}
+
+void I_NetCmd(void)
+{
+ if (!netgame)
+ I_Error("I_NetCmd when not in netgame");
+ DPMIInt(doomcom->intnum);
+}
+
+//=========================================================================
+//
+// I_CheckExternDriver
+//
+// Checks to see if a vector, and an address for an external driver
+// have been passed.
+//=========================================================================
+
+void I_CheckExternDriver(void)
+{
+ int i;
+
+ if (!(i = M_CheckParm("-externdriver")))
+ {
+ return;
+ }
+ i_ExternData = (externdata_t *) atoi(myargv[i + 1]);
+ i_Vector = i_ExternData->vector;
+
+ useexterndriver = true;
+}
+
+//=========================================================================
+//=========================================================================
+// Hi-Res (mode 12) stuff
+//=========================================================================
+//=========================================================================
+
+
+//==========================================================================
+//
+// SetVideoModeHR - Set video mode to 640x480x16
+//
+//==========================================================================
+
+
+void SetVideoModeHR(void)
+{
+ union REGS regs;
+ regs.x.eax = 0x12;
+ int386(VID_INT, &regs, &regs);
+}
+
+
+//==========================================================================
+//
+// ClearScreenHR - Clear the screen to color 0
+//
+//==========================================================================
+
+void ClearScreenHR(void)
+{
+ BITPLANE(MASK_PLANE0 | MASK_PLANE1 | MASK_PLANE2 | MASK_PLANE3);
+ memset((char *) 0xa0000, 0, 38400);
+}
+
+
+//==========================================================================
+//
+// SlamHR - copy 4-plane buffer to screen
+//
+//==========================================================================
+
+void SlamHR(char *buffer)
+{
+ BITPLANE(MASK_PLANE0);
+ memcpy((char *) 0xA0000, buffer + P0OFFSET, 38400);
+ BITPLANE(MASK_PLANE1);
+ memcpy((char *) 0xA0000, buffer + P1OFFSET, 38400);
+ BITPLANE(MASK_PLANE2);
+ memcpy((char *) 0xA0000, buffer + P2OFFSET, 38400);
+ BITPLANE(MASK_PLANE3);
+ memcpy((char *) 0xA0000, buffer + P3OFFSET, 38400);
+}
+
+
+//==========================================================================
+//
+// SlamHR - copy 4-plane buffer to screen
+//
+// X and Width should be a multiple of 8
+// src should be 4 planes of block size, back to back
+//==========================================================================
+
+void SlamBlockHR(int x, int y, int w, int h, char *src)
+{
+ int srcwid = w >> 3;
+ char *dest = ((char *) 0xA0000) + (y * (640 / 8)) + (x >> 3);
+ char *dst;
+ int i;
+
+ VB_SYNC;
+
+ BITPLANE(MASK_PLANE0);
+ dst = dest;
+ for (i = 0; i < h; i++)
+ {
+ memcpy(dst, src, srcwid);
+ dst += 640 / 8;
+ src += srcwid;
+ }
+ BITPLANE(MASK_PLANE1);
+ dst = dest;
+ for (i = 0; i < h; i++)
+ {
+ memcpy(dst, src, srcwid);
+ dst += 640 / 8;
+ src += srcwid;
+ }
+ BITPLANE(MASK_PLANE2);
+ dst = dest;
+ for (i = 0; i < h; i++)
+ {
+ memcpy(dst, src, srcwid);
+ dst += 640 / 8;
+ src += srcwid;
+ }
+ BITPLANE(MASK_PLANE3);
+ dst = dest;
+ for (i = 0; i < h; i++)
+ {
+ memcpy(dst, src, srcwid);
+ dst += 640 / 8;
+ src += srcwid;
+ }
+}
+
+//==========================================================================
+//
+// InitPaletteHR
+//
+//==========================================================================
+
+void InitPaletteHR(void)
+{
+ int i;
+ union REGS regs;
+
+ // Set palette registers to point into color registers
+ for (i = 0; i < 16; i++)
+ {
+ regs.x.eax = (0x10 << 8) | 0x00;
+ regs.x.ebx = (i << 8) | i;
+ int386(VID_INT, &regs, &regs);
+ }
+
+}
+
+
+//==========================================================================
+//
+// SetPaletteHR - Set the HR palette
+//
+//==========================================================================
+
+void SetPaletteHR(byte * palette)
+{
+ int i;
+ VB_SYNC;
+ outp(PEL_WRITE_ADR, 0);
+
+ for (i = 0; i < 16 * 3; i++)
+ {
+ outp(PEL_DATA, (*palette++));
+ }
+}
+
+
+//==========================================================================
+//
+// GetPaletteHR - Get the HR palette
+//
+//==========================================================================
+
+void GetPaletteHR(byte * palette)
+{
+ int i;
+ outp(PEL_READ_ADR, 0);
+ for (i = 0; i < 16 * 3; i++)
+ {
+ *palette++ = inp(PEL_DATA);
+ }
+}
+
+
+//==========================================================================
+//
+// FadeToPaletteHR
+//
+//==========================================================================
+
+void FadeToPaletteHR(byte * palette)
+{
+ int i, j;
+ int steps = 140; // two-seconds
+ byte basep[16 * 3];
+ byte work[16 * 3];
+ int delta;
+
+ GetPaletteHR(basep);
+ for (i = 0; i < steps; i++)
+ {
+ for (j = 0; j < 16 * 3; j++)
+ {
+ delta = palette[j] - basep[j];
+ work[j] = basep[j] + delta * i / steps;
+ }
+ SetPaletteHR(work);
+ }
+ SetPaletteHR(palette);
+}
+
+
+//==========================================================================
+//
+// FadeToBlackHR - Fades the palette out to black
+//
+//==========================================================================
+
+/*
+void FadeToBlackHR(void)
+{
+ char work[16*3];
+ char base[16*3];
+ int i,j,steps=70;
+
+ GetPaletteHR(base);
+ for (i=0; i<steps; i++)
+ {
+ for (j=0; j<16*3; j++)
+ {
+ work[j] = base[j]-(base[j]*i/steps);
+ }
+ VB_SYNC;
+ SetPaletteHR(work);
+ }
+ memset(work,0,16*3);
+ SetPaletteHR(work);
+}
+*/
+
+//==========================================================================
+//
+// BlackPaletteHR - Instantly blacks out the palette
+//
+//==========================================================================
+
+void BlackPaletteHR(void)
+{
+ char blackpal[16 * 3];
+
+ memset(blackpal, 0, 16 * 3);
+ SetPaletteHR(blackpal);
+}
+
+//==========================================================================
+//
+//
+// I_StartupReadKeys
+//
+//
+//==========================================================================
+
+void I_StartupReadKeys(void)
+{
+ int k;
+
+ while (kbdtail < kbdhead)
+ {
+ k = keyboardque[kbdtail & (KBDQUESIZE - 1)];
+ kbdtail++;
+ if (k == 1)
+ I_Quit();
+ }
+}
diff --git a/src/hexen/i_sound.c b/src/hexen/i_sound.c
new file mode 100644
index 00000000..9b68be60
--- /dev/null
+++ b/src/hexen/i_sound.c
@@ -0,0 +1,410 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// I_SOUND.C
+
+#include <stdio.h>
+#include "h2def.h"
+#include "i_system.h"
+#include "m_argv.h"
+#include "dmx.h"
+#include "sounds.h"
+#include "i_sound.h"
+
+/*
+===============
+=
+= I_StartupTimer
+=
+===============
+*/
+
+int tsm_ID = -1;
+
+void I_StartupTimer(void)
+{
+#ifndef NOTIMER
+ extern int I_TimerISR(void);
+
+ ST_Message(" I_StartupTimer()\n");
+ // installs master timer. Must be done before StartupTimer()!
+ TSM_Install(SND_TICRATE);
+ tsm_ID = TSM_NewService(I_TimerISR, 35, 255, 0); // max priority
+ if (tsm_ID == -1)
+ {
+ I_Error("Can't register 35 Hz timer w/ DMX library");
+ }
+#endif
+}
+
+void I_ShutdownTimer(void)
+{
+ TSM_DelService(tsm_ID);
+ TSM_Remove();
+}
+
+/*
+ *
+ * SOUND HEADER & DATA
+ *
+ *
+ */
+
+// sound information
+#if 0
+const char *dnames[] = { "None",
+ "PC_Speaker",
+ "Adlib",
+ "Sound_Blaster",
+ "ProAudio_Spectrum16",
+ "Gravis_Ultrasound",
+ "MPU",
+ "AWE32"
+};
+#endif
+
+const char snd_prefixen[] = { 'P', 'P', 'A', 'S', 'S', 'S', 'M',
+ 'M', 'M', 'S'
+};
+
+int snd_Channels;
+int snd_DesiredMusicDevice, snd_DesiredSfxDevice;
+int snd_MusicDevice, // current music card # (index to dmxCodes)
+ snd_SfxDevice, // current sfx card # (index to dmxCodes)
+ snd_MaxVolume, // maximum volume for sound
+ snd_MusicVolume; // maximum volume for music
+int dmxCodes[NUM_SCARDS]; // the dmx code for a given card
+
+int snd_SBport, snd_SBirq, snd_SBdma; // sound blaster variables
+int snd_Mport; // midi variables
+
+extern boolean snd_MusicAvail, // whether music is available
+ snd_SfxAvail; // whether sfx are available
+
+void I_PauseSong(int handle)
+{
+ MUS_PauseSong(handle);
+}
+
+void I_ResumeSong(int handle)
+{
+ MUS_ResumeSong(handle);
+}
+
+void I_SetMusicVolume(int volume)
+{
+ MUS_SetMasterVolume(volume * 8);
+// snd_MusicVolume = volume;
+}
+
+void I_SetSfxVolume(int volume)
+{
+ snd_MaxVolume = volume; // THROW AWAY?
+}
+
+/*
+ *
+ * SONG API
+ *
+ */
+
+int I_RegisterSong(void *data)
+{
+ int rc = MUS_RegisterSong(data);
+#ifdef SNDDEBUG
+ if (rc < 0)
+ ST_Message(" MUS_Reg() returned %d\n", rc);
+#endif
+ return rc;
+}
+
+void I_UnRegisterSong(int handle)
+{
+ int rc = MUS_UnregisterSong(handle);
+#ifdef SNDDEBUG
+ if (rc < 0)
+ ST_Message(" MUS_Unreg() returned %d\n", rc);
+#endif
+}
+
+int I_QrySongPlaying(int handle)
+{
+ int rc = MUS_QrySongPlaying(handle);
+#ifdef SNDDEBUG
+ if (rc < 0)
+ ST_Message(" MUS_QrySP() returned %d\n", rc);
+#endif
+ return rc;
+}
+
+// Stops a song. MUST be called before I_UnregisterSong().
+
+void I_StopSong(int handle)
+{
+ int rc;
+ rc = MUS_StopSong(handle);
+#ifdef SNDDEBUG
+ if (rc < 0)
+ ST_Message(" MUS_StopSong() returned %d\n", rc);
+#endif
+/*
+ // Fucking kluge pause
+ {
+ int s;
+ extern volatile int ticcount;
+ for (s=ticcount ; ticcount - s < 10 ; );
+ }
+*/
+}
+
+void I_PlaySong(int handle, boolean looping)
+{
+ int rc;
+ rc = MUS_ChainSong(handle, looping ? handle : -1);
+#ifdef SNDDEBUG
+ if (rc < 0)
+ ST_Message(" MUS_ChainSong() returned %d\n", rc);
+#endif
+ rc = MUS_PlaySong(handle, snd_MusicVolume);
+#ifdef SNDDEBUG
+ if (rc < 0)
+ ST_Message(" MUS_PlaySong() returned %d\n", rc);
+#endif
+
+}
+
+/*
+ *
+ * SOUND FX API
+ *
+ */
+
+// Gets lump nums of the named sound. Returns pointer which will be
+// passed to I_StartSound() when you want to start an SFX. Must be
+// sure to pass this to UngetSoundEffect() so that they can be
+// freed!
+
+
+int I_GetSfxLumpNum(sfxinfo_t * sound)
+{
+ return W_GetNumForName(sound->lumpname);
+
+}
+
+int I_StartSound(int id, void *data, int vol, int sep, int pitch,
+ int priority)
+{
+ return SFX_PlayPatch(data, pitch, sep, vol, 0, 0);
+}
+
+void I_StopSound(int handle)
+{
+// extern volatile long gDmaCount;
+// long waittocount;
+ SFX_StopPatch(handle);
+// waittocount = gDmaCount + 2;
+// while (gDmaCount < waittocount) ;
+}
+
+int I_SoundIsPlaying(int handle)
+{
+ return SFX_Playing(handle);
+}
+
+void I_UpdateSoundParams(int handle, int vol, int sep, int pitch)
+{
+ SFX_SetOrigin(handle, pitch, sep, vol);
+}
+
+/*
+ *
+ * SOUND STARTUP STUFF
+ *
+ *
+ */
+
+//
+// Why PC's Suck, Reason #8712
+//
+
+void I_sndArbitrateCards(void)
+{
+ char tmp[160];
+ boolean gus, adlib, pc, sb, midi;
+ int i, rc, mputype, p, opltype, wait, dmxlump;
+
+ snd_MusicDevice = snd_DesiredMusicDevice;
+ snd_SfxDevice = snd_DesiredSfxDevice;
+
+ // check command-line parameters- overrides config file
+ //
+ if (M_CheckParm("-nosound"))
+ snd_MusicDevice = snd_SfxDevice = snd_none;
+ if (M_CheckParm("-nosfx"))
+ snd_SfxDevice = snd_none;
+ if (M_CheckParm("-nomusic"))
+ snd_MusicDevice = snd_none;
+
+ if (snd_MusicDevice > snd_MPU && snd_MusicDevice <= snd_MPU3)
+ snd_MusicDevice = snd_MPU;
+ if (snd_MusicDevice == snd_SB)
+ snd_MusicDevice = snd_Adlib;
+ if (snd_MusicDevice == snd_PAS)
+ snd_MusicDevice = snd_Adlib;
+
+ // figure out what i've got to initialize
+ //
+ gus = snd_MusicDevice == snd_GUS || snd_SfxDevice == snd_GUS;
+ sb = snd_SfxDevice == snd_SB || snd_MusicDevice == snd_SB;
+ adlib = snd_MusicDevice == snd_Adlib;
+ pc = snd_SfxDevice == snd_PC;
+ midi = snd_MusicDevice == snd_MPU;
+
+ // initialize whatever i've got
+ //
+ if (gus)
+ {
+ if (GF1_Detect())
+ ST_Message(" Dude. The GUS ain't responding.\n");
+ else
+ {
+ dmxlump = W_GetNumForName("dmxgus");
+ GF1_SetMap(W_CacheLumpNum(dmxlump, PU_CACHE),
+ lumpinfo[dmxlump].size);
+ }
+
+ }
+ if (sb)
+ {
+ if (debugmode)
+ {
+ ST_Message(" Sound cfg p=0x%x, i=%d, d=%d\n",
+ snd_SBport, snd_SBirq, snd_SBdma);
+ }
+ if (SB_Detect(&snd_SBport, &snd_SBirq, &snd_SBdma, 0))
+ {
+ ST_Message(" SB isn't responding at p=0x%x, i=%d, d=%d\n",
+ snd_SBport, snd_SBirq, snd_SBdma);
+ }
+ else
+ SB_SetCard(snd_SBport, snd_SBirq, snd_SBdma);
+
+ if (debugmode)
+ {
+ ST_Message(" SB_Detect returned p=0x%x, i=%d, d=%d\n",
+ snd_SBport, snd_SBirq, snd_SBdma);
+ }
+ }
+
+ if (adlib)
+ {
+ if (AL_Detect(&wait, 0))
+ {
+ ST_Message(" Dude. The Adlib isn't responding.\n");
+ }
+ else
+ {
+ AL_SetCard(wait, W_CacheLumpName("genmidi", PU_STATIC));
+ }
+ }
+
+ if (midi)
+ {
+ if (debugmode)
+ {
+ ST_Message(" cfg p=0x%x\n", snd_Mport);
+ }
+
+ if (MPU_Detect(&snd_Mport, &i))
+ {
+ ST_Message(" The MPU-401 isn't reponding @ p=0x%x.\n",
+ snd_Mport);
+ }
+ else
+ MPU_SetCard(snd_Mport);
+ }
+
+}
+
+// inits all sound stuff
+
+void I_StartupSound(void)
+{
+ int rc, i;
+
+ if (debugmode)
+ ST_Message("I_StartupSound: Hope you hear a pop.\n");
+
+ // initialize dmxCodes[]
+ dmxCodes[0] = 0;
+ dmxCodes[snd_PC] = AHW_PC_SPEAKER;
+ dmxCodes[snd_Adlib] = AHW_ADLIB;
+ dmxCodes[snd_SB] = AHW_SOUND_BLASTER;
+ dmxCodes[snd_PAS] = AHW_MEDIA_VISION;
+ dmxCodes[snd_GUS] = AHW_ULTRA_SOUND;
+ dmxCodes[snd_MPU] = AHW_MPU_401;
+ dmxCodes[snd_MPU2] = AHW_MPU_401;
+ dmxCodes[snd_MPU3] = AHW_MPU_401;
+ dmxCodes[snd_AWE] = AHW_AWE32;
+ dmxCodes[snd_CDMUSIC] = 0;
+
+ // inits sound library timer stuff
+ I_StartupTimer();
+
+ // pick the sound cards i'm going to use
+ //
+ I_sndArbitrateCards();
+
+ if (debugmode)
+ {
+ ST_Message(" Music device #%d & dmxCode=%d,", snd_MusicDevice,
+ dmxCodes[snd_MusicDevice]);
+ ST_Message(" Sfx device #%d & dmxCode=%d\n", snd_SfxDevice,
+ dmxCodes[snd_SfxDevice]);
+ }
+
+ // inits DMX sound library
+ ST_Message(" Calling DMX_Init...");
+ rc = DMX_Init(SND_TICRATE, SND_MAXSONGS, dmxCodes[snd_MusicDevice],
+ dmxCodes[snd_SfxDevice]);
+
+ if (debugmode)
+ {
+ ST_Message(" DMX_Init() returned %d\n", rc);
+ }
+
+}
+
+// shuts down all sound stuff
+
+void I_ShutdownSound(void)
+{
+ DMX_DeInit();
+ I_ShutdownTimer();
+}
+
+void I_SetChannels(int channels)
+{
+ WAV_PlayMode(channels, SND_SAMPLERATE);
+}
diff --git a/src/hexen/in_lude.c b/src/hexen/in_lude.c
new file mode 100644
index 00000000..4164d549
--- /dev/null
+++ b/src/hexen/in_lude.c
@@ -0,0 +1,615 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+#include <ctype.h>
+
+#include "h2def.h"
+#include "s_sound.h"
+#include "i_system.h"
+#include "i_video.h"
+#include "p_local.h"
+#include "v_video.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define TEXTSPEED 3
+#define TEXTWAIT 140
+
+// TYPES -------------------------------------------------------------------
+
+typedef enum
+{
+ SINGLE,
+ COOPERATIVE,
+ DEATHMATCH
+} gametype_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void WaitStop(void);
+static void Stop(void);
+static void LoadPics(void);
+static void UnloadPics(void);
+static void CheckForSkip(void);
+static void InitStats(void);
+static void DrDeathTally(void);
+static void DrNumber(int val, int x, int y, int wrapThresh);
+static void DrNumberBold(int val, int x, int y, int wrapThresh);
+static void DrawHubText(void);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DECLARATIONS ------------------------------------------------
+
+boolean intermission;
+char ClusterMessage[MAX_INTRMSN_MESSAGE_SIZE];
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static boolean skipintermission;
+static int interstate = 0;
+static int intertime = -1;
+static gametype_t gametype;
+static int cnt;
+static int slaughterboy; // in DM, the player with the most kills
+static patch_t *patchINTERPIC;
+static patch_t *FontBNumbers[10];
+static patch_t *FontBNegative;
+static patch_t *FontBSlash;
+static patch_t *FontBPercent;
+static int FontABaseLump;
+static int FontBLump;
+static int FontBLumpBase;
+
+static signed int totalFrags[MAXPLAYERS];
+
+static int HubCount;
+static char *HubText;
+
+// CODE --------------------------------------------------------------------
+
+//========================================================================
+//
+// IN_Start
+//
+//========================================================================
+
+extern void AM_Stop(void);
+
+void IN_Start(void)
+{
+ int i;
+ I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE));
+ InitStats();
+ LoadPics();
+ intermission = true;
+ interstate = 0;
+ skipintermission = false;
+ intertime = 0;
+ AM_Stop();
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ players[i].messageTics = 0;
+ players[i].message[0] = 0;
+ }
+ SN_StopAllSequences();
+}
+
+//========================================================================
+//
+// WaitStop
+//
+//========================================================================
+
+void WaitStop(void)
+{
+ if (!--cnt)
+ {
+ Stop();
+// gamestate = GS_LEVEL;
+// G_DoLoadLevel();
+ gameaction = ga_leavemap;
+// G_WorldDone();
+ }
+}
+
+//========================================================================
+//
+// Stop
+//
+//========================================================================
+
+static void Stop(void)
+{
+ intermission = false;
+ UnloadPics();
+ SB_state = -1;
+ BorderNeedRefresh = true;
+}
+
+//========================================================================
+//
+// InitStats
+//
+// Initializes the stats for single player mode
+//========================================================================
+
+static char *ClusMsgLumpNames[] = {
+ "clus1msg",
+ "clus2msg",
+ "clus3msg",
+ "clus4msg",
+ "clus5msg"
+};
+
+static void InitStats(void)
+{
+ int i;
+ int j;
+ int oldCluster;
+ signed int slaughterfrags;
+ int posnum;
+ int slaughtercount;
+ int playercount;
+ char *msgLumpName;
+ int msgSize;
+ int msgLump;
+
+ extern int LeaveMap;
+
+ if (!deathmatch)
+ {
+ gametype = SINGLE;
+ HubCount = 0;
+ oldCluster = P_GetMapCluster(gamemap);
+ if (oldCluster != P_GetMapCluster(LeaveMap))
+ {
+ if (oldCluster >= 1 && oldCluster <= 5)
+ {
+ msgLumpName = ClusMsgLumpNames[oldCluster - 1];
+ msgLump = W_GetNumForName(msgLumpName);
+ msgSize = W_LumpLength(msgLump);
+ if (msgSize >= MAX_INTRMSN_MESSAGE_SIZE)
+ {
+ I_Error("Cluster message too long (%s)", msgLumpName);
+ }
+ W_ReadLump(msgLump, ClusterMessage);
+ ClusterMessage[msgSize] = 0; // Append terminator
+ HubText = ClusterMessage;
+ HubCount = strlen(HubText) * TEXTSPEED + TEXTWAIT;
+ S_StartSongName("hub", true);
+ }
+ }
+ }
+ else
+ {
+ gametype = DEATHMATCH;
+ slaughterboy = 0;
+ slaughterfrags = -9999;
+ posnum = 0;
+ playercount = 0;
+ slaughtercount = 0;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ totalFrags[i] = 0;
+ if (playeringame[i])
+ {
+ playercount++;
+ for (j = 0; j < MAXPLAYERS; j++)
+ {
+ if (playeringame[j])
+ {
+ totalFrags[i] += players[i].frags[j];
+ }
+ }
+ posnum++;
+ }
+ if (totalFrags[i] > slaughterfrags)
+ {
+ slaughterboy = 1 << i;
+ slaughterfrags = totalFrags[i];
+ slaughtercount = 1;
+ }
+ else if (totalFrags[i] == slaughterfrags)
+ {
+ slaughterboy |= 1 << i;
+ slaughtercount++;
+ }
+ }
+ if (playercount == slaughtercount)
+ { // don't do the slaughter stuff if everyone is equal
+ slaughterboy = 0;
+ }
+ S_StartSongName("hub", true);
+ }
+}
+
+//========================================================================
+//
+// LoadPics
+//
+//========================================================================
+
+static void LoadPics(void)
+{
+ int i;
+
+ if (HubCount || gametype == DEATHMATCH)
+ {
+ patchINTERPIC = W_CacheLumpName("INTERPIC", PU_STATIC);
+ FontBLumpBase = W_GetNumForName("FONTB16");
+ for (i = 0; i < 10; i++)
+ {
+ FontBNumbers[i] = W_CacheLumpNum(FontBLumpBase + i, PU_STATIC);
+ }
+ FontBLump = W_GetNumForName("FONTB_S") + 1;
+ FontBNegative = W_CacheLumpName("FONTB13", PU_STATIC);
+ FontABaseLump = W_GetNumForName("FONTA_S") + 1;
+
+ FontBSlash = W_CacheLumpName("FONTB15", PU_STATIC);
+ FontBPercent = W_CacheLumpName("FONTB05", PU_STATIC);
+ }
+}
+
+//========================================================================
+//
+// UnloadPics
+//
+//========================================================================
+
+static void UnloadPics(void)
+{
+ int i;
+
+ if (HubCount || gametype == DEATHMATCH)
+ {
+ W_ReleaseLumpName("INTERPIC");
+
+ patchINTERPIC = W_CacheLumpName("INTERPIC", PU_STATIC);
+ FontBLumpBase = W_GetNumForName("FONTB16");
+ for (i = 0; i < 10; i++)
+ {
+ W_ReleaseLumpNum(FontBLumpBase + i);
+ }
+ W_ReleaseLumpName("FONTB13");
+ W_ReleaseLumpName("FONTB15");
+ W_ReleaseLumpName("FONTB05");
+ }
+}
+
+//========================================================================
+//
+// IN_Ticker
+//
+//========================================================================
+
+void IN_Ticker(void)
+{
+ if (!intermission)
+ {
+ return;
+ }
+ if (interstate)
+ {
+ WaitStop();
+ return;
+ }
+ skipintermission = false;
+ CheckForSkip();
+ intertime++;
+ if (skipintermission || (gametype == SINGLE && !HubCount))
+ {
+ interstate = 1;
+ cnt = 10;
+ skipintermission = false;
+ //S_StartSound(NULL, sfx_dorcls);
+ }
+}
+
+//========================================================================
+//
+// CheckForSkip
+//
+// Check to see if any player hit a key
+//========================================================================
+
+static void CheckForSkip(void)
+{
+ int i;
+ player_t *player;
+ static boolean triedToSkip;
+
+ for (i = 0, player = players; i < MAXPLAYERS; i++, player++)
+ {
+ if (playeringame[i])
+ {
+ if (player->cmd.buttons & BT_ATTACK)
+ {
+ if (!player->attackdown)
+ {
+ skipintermission = 1;
+ }
+ player->attackdown = true;
+ }
+ else
+ {
+ player->attackdown = false;
+ }
+ if (player->cmd.buttons & BT_USE)
+ {
+ if (!player->usedown)
+ {
+ skipintermission = 1;
+ }
+ player->usedown = true;
+ }
+ else
+ {
+ player->usedown = false;
+ }
+ }
+ }
+ if (deathmatch && intertime < 140)
+ { // wait for 4 seconds before allowing a skip
+ if (skipintermission == 1)
+ {
+ triedToSkip = true;
+ skipintermission = 0;
+ }
+ }
+ else
+ {
+ if (triedToSkip)
+ {
+ skipintermission = 1;
+ triedToSkip = false;
+ }
+ }
+}
+
+//========================================================================
+//
+// IN_Drawer
+//
+//========================================================================
+
+void IN_Drawer(void)
+{
+ if (!intermission)
+ {
+ return;
+ }
+ if (interstate)
+ {
+ return;
+ }
+ UpdateState |= I_FULLSCRN;
+ memcpy(I_VideoBuffer, (byte *) patchINTERPIC, SCREENWIDTH * SCREENHEIGHT);
+
+ if (gametype == SINGLE)
+ {
+ if (HubCount)
+ {
+ DrawHubText();
+ }
+ }
+ else
+ {
+ DrDeathTally();
+ }
+}
+
+//========================================================================
+//
+// DrDeathTally
+//
+//========================================================================
+
+#define TALLY_EFFECT_TICKS 20
+#define TALLY_FINAL_X_DELTA (23*FRACUNIT)
+#define TALLY_FINAL_Y_DELTA (13*FRACUNIT)
+#define TALLY_START_XPOS (178*FRACUNIT)
+#define TALLY_STOP_XPOS (90*FRACUNIT)
+#define TALLY_START_YPOS (132*FRACUNIT)
+#define TALLY_STOP_YPOS (83*FRACUNIT)
+#define TALLY_TOP_X 85
+#define TALLY_TOP_Y 9
+#define TALLY_LEFT_X 7
+#define TALLY_LEFT_Y 71
+#define TALLY_TOTALS_X 291
+
+static void DrDeathTally(void)
+{
+ int i, j;
+ fixed_t xPos, yPos;
+ fixed_t xDelta, yDelta;
+ fixed_t xStart, scale;
+ int x, y;
+ boolean bold;
+ static boolean showTotals;
+ int temp;
+
+ V_DrawPatch(TALLY_TOP_X, TALLY_TOP_Y,
+ W_CacheLumpName("tallytop", PU_CACHE));
+ V_DrawPatch(TALLY_LEFT_X, TALLY_LEFT_Y,
+ W_CacheLumpName("tallylft", PU_CACHE));
+ if (intertime < TALLY_EFFECT_TICKS)
+ {
+ showTotals = false;
+ scale = (intertime * FRACUNIT) / TALLY_EFFECT_TICKS;
+ xDelta = FixedMul(scale, TALLY_FINAL_X_DELTA);
+ yDelta = FixedMul(scale, TALLY_FINAL_Y_DELTA);
+ xStart = TALLY_START_XPOS - FixedMul(scale,
+ TALLY_START_XPOS -
+ TALLY_STOP_XPOS);
+ yPos =
+ TALLY_START_YPOS - FixedMul(scale,
+ TALLY_START_YPOS - TALLY_STOP_YPOS);
+ }
+ else
+ {
+ xDelta = TALLY_FINAL_X_DELTA;
+ yDelta = TALLY_FINAL_Y_DELTA;
+ xStart = TALLY_STOP_XPOS;
+ yPos = TALLY_STOP_YPOS;
+ }
+ if (intertime >= TALLY_EFFECT_TICKS && showTotals == false)
+ {
+ showTotals = true;
+ S_StartSound(NULL, SFX_PLATFORM_STOP);
+ }
+ y = yPos >> FRACBITS;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ xPos = xStart;
+ for (j = 0; j < MAXPLAYERS; j++, xPos += xDelta)
+ {
+ x = xPos >> FRACBITS;
+ bold = (i == consoleplayer || j == consoleplayer);
+ if (playeringame[i] && playeringame[j])
+ {
+ if (bold)
+ {
+ DrNumberBold(players[i].frags[j], x, y, 100);
+ }
+ else
+ {
+ DrNumber(players[i].frags[j], x, y, 100);
+ }
+ }
+ else
+ {
+ temp = MN_TextAWidth("--") / 2;
+ if (bold)
+ {
+ MN_DrTextAYellow("--", x - temp, y);
+ }
+ else
+ {
+ MN_DrTextA("--", x - temp, y);
+ }
+ }
+ }
+ if (showTotals && playeringame[i]
+ && !((slaughterboy & (1 << i)) && !(intertime & 16)))
+ {
+ DrNumber(totalFrags[i], TALLY_TOTALS_X, y, 1000);
+ }
+ yPos += yDelta;
+ y = yPos >> FRACBITS;
+ }
+}
+
+//==========================================================================
+//
+// DrNumber
+//
+//==========================================================================
+
+static void DrNumber(int val, int x, int y, int wrapThresh)
+{
+ char buff[8] = "XX";
+
+ if (!(val < -9 && wrapThresh < 1000))
+ {
+ sprintf(buff, "%d", val >= wrapThresh ? val % wrapThresh : val);
+ }
+ MN_DrTextA(buff, x - MN_TextAWidth(buff) / 2, y);
+}
+
+//==========================================================================
+//
+// DrNumberBold
+//
+//==========================================================================
+
+static void DrNumberBold(int val, int x, int y, int wrapThresh)
+{
+ char buff[8] = "XX";
+
+ if (!(val < -9 && wrapThresh < 1000))
+ {
+ sprintf(buff, "%d", val >= wrapThresh ? val % wrapThresh : val);
+ }
+ MN_DrTextAYellow(buff, x - MN_TextAWidth(buff) / 2, y);
+}
+
+//===========================================================================
+//
+// DrawHubText
+//
+//===========================================================================
+
+static void DrawHubText(void)
+{
+ int count;
+ char *ch;
+ int c;
+ int cx, cy;
+ patch_t *w;
+
+ cy = 5;
+ cx = 10;
+ ch = HubText;
+ count = (intertime - 10) / TEXTSPEED;
+ if (count < 0)
+ {
+ count = 0;
+ }
+ for (; count; count--)
+ {
+ c = *ch++;
+ if (!c)
+ {
+ break;
+ }
+ if (c == '\n')
+ {
+ cx = 10;
+ cy += 9;
+ continue;
+ }
+ if (c < 32)
+ {
+ continue;
+ }
+ c = toupper(c);
+ if (c == 32)
+ {
+ cx += 5;
+ continue;
+ }
+ w = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
+ if (cx + w->width > SCREENWIDTH)
+ {
+ break;
+ }
+ V_DrawPatch(cx, cy, w);
+ cx += w->width;
+ }
+}
diff --git a/src/hexen/info.c b/src/hexen/info.c
new file mode 100644
index 00000000..e0d768d6
--- /dev/null
+++ b/src/hexen/info.c
@@ -0,0 +1,13886 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+#include "h2def.h"
+#include "i_swap.h"
+// generated by stateco
+
+char *sprnames[] = {
+ "MAN1","ACLO","TLGL","FBL1","XPL1","ARRW","DART","RIPP","CFCF","BLAD",
+ "SHRD","FFSM","FFLG","PTN1","PTN2","SOAR","INVU","SUMN","TSPK","TELO",
+ "TRNG","ROCK","FOGS","FOGM","FOGL","SGSA","SGSB","PORK","EGGM","FHFX",
+ "SPHL","STWN","GMPD","ASKU","ABGM","AGMR","AGMG","AGG2","AGMB","AGB2",
+ "ABK1","ABK2","ASK2","AFWP","ACWP","AMWP","AGER","AGR2","AGR3","AGR4",
+ "TRCH","PSBG","ATLP","THRW","SPED","BMAN","BRAC","BLST","HRAD","SPSH",
+ "LVAS","SLDG","STTW","RCK1","RCK2","RCK3","RCK4","CDLR","TRE1","TRDT",
+ "TRE2","TRE3","STM1","STM2","STM3","STM4","MSH1","MSH2","MSH3","MSH4",
+ "MSH5","MSH6","MSH7","MSH8","SGMP","SGM1","SGM2","SGM3","SLC1","SLC2",
+ "SLC3","MSS1","MSS2","SWMV","CPS1","CPS2","TMS1","TMS2","TMS3","TMS4",
+ "TMS5","TMS6","TMS7","CPS3","STT2","STT3","STT4","STT5","GAR1","GAR2",
+ "GAR3","GAR4","GAR5","GAR6","GAR7","GAR8","GAR9","BNR1","TRE4","TRE5",
+ "TRE6","TRE7","LOGG","ICT1","ICT2","ICT3","ICT4","ICM1","ICM2","ICM3",
+ "ICM4","RKBL","RKBS","RKBK","RBL1","RBL2","RBL3","VASE","POT1","POT2",
+ "POT3","PBIT","CPS4","CPS5","CPS6","CPB1","CPB2","CPB3","CPB4","BDRP",
+ "BDSH","BDPL","CNDL","LEF1","LEF3","LEF2","TWTR","WLTR","BARL","SHB1",
+ "SHB2","BCKT","SHRM","FBUL","FSKL","BRTR","SUIT","BBLL","CAND","IRON",
+ "XMAS","CDRN","CHNS","TST1","TST2","TST3","TST4","TST5","TST6","TST7",
+ "TST8","TST9","TST0","TELE","TSMK","FPCH","WFAX","FAXE","WFHM","FHMR",
+ "FSRD","FSFX","CMCE","WCSS","CSSF","WCFM","CFLM","CFFX","CHLY","SPIR",
+ "MWND","WMLG","MLNG","MLFX","MLF2","MSTF","MSP1","MSP2","WFR1","WFR2",
+ "WFR3","WCH1","WCH2","WCH3","WMS1","WMS2","WMS3","WPIG","WMCS","CONE",
+ "SHEX","BLOD","GIBS","PLAY","FDTH","BSKL","ICEC","CLER","MAGE","PIGY",
+ "CENT","CTXD","CTFX","CTDP","DEMN","DEMA","DEMB","DEMC","DEMD","DEME",
+ "DMFX","DEM2","DMBA","DMBB","DMBC","DMBD","DMBE","D2FX","WRTH","WRT2",
+ "WRBL","MNTR","FX12","FX13","MNSM","SSPT","SSDV","SSXD","SSFX","BISH",
+ "BPFX","DRAG","DRFX","ARM1","ARM2","ARM3","ARM4","MAN2","MAN3","KEY1",
+ "KEY2","KEY3","KEY4","KEY5","KEY6","KEY7","KEY8","KEY9","KEYA","KEYB",
+ "ETTN","ETTB","FDMN","FDMB","ICEY","ICPR","ICWS","SORC","SBMP","SBS4",
+ "SBMB","SBS3","SBMG","SBS1","SBS2","SBFX","RADE","WATR","KORX","ABAT",
+ NULL
+};
+
+void A_FreeTargMobj();
+void A_FlameCheck();
+void A_HideThing();
+void A_UnHideThing();
+void A_RestoreSpecialThing1();
+void A_RestoreSpecialThing2();
+void A_RestoreArtifact();
+void A_Summon();
+void A_ThrustInitUp();
+void A_ThrustInitDn();
+void A_ThrustRaise();
+void A_ThrustBlock();
+void A_ThrustImpale();
+void A_ThrustLower();
+void A_TeloSpawnC();
+void A_TeloSpawnB();
+void A_TeloSpawnA();
+void A_TeloSpawnD();
+void A_CheckTeleRing();
+void A_FogSpawn();
+void A_FogMove();
+void A_Quake();
+void A_ContMobjSound();
+void A_Scream();
+void A_Explode();
+void A_PoisonBagInit();
+void A_PoisonBagDamage();
+void A_PoisonBagCheck();
+void A_CheckThrowBomb();
+void A_NoGravity();
+void A_PotteryExplode();
+void A_PotteryChooseBit();
+void A_PotteryCheck();
+void A_CorpseBloodDrip();
+void A_CorpseExplode();
+void A_LeafSpawn();
+void A_LeafThrust();
+void A_LeafCheck();
+void A_BridgeInit();
+void A_BridgeOrbit();
+void A_TreeDeath();
+void A_PoisonShroom();
+void A_Pain();
+void A_SoAExplode();
+void A_BellReset1();
+void A_BellReset2();
+void A_NoBlocking();
+void A_Light0();
+void A_WeaponReady();
+void A_Lower();
+void A_Raise();
+void A_FPunchAttack();
+void A_ReFire();
+void A_FAxeAttack();
+void A_FHammerAttack();
+void A_FHammerThrow();
+void A_FSwordAttack();
+void A_FSwordFlames();
+void A_CMaceAttack();
+void A_CStaffInitBlink();
+void A_CStaffCheckBlink();
+void A_CStaffCheck();
+void A_CStaffAttack();
+void A_CStaffMissileSlither();
+void A_CFlameAttack();
+void A_CFlameRotate();
+void A_CFlamePuff();
+void A_CFlameMissile();
+void A_CHolyAttack();
+void A_CHolyPalette();
+void A_CHolySeek();
+void A_CHolyCheckScream();
+void A_CHolyTail();
+void A_CHolySpawnPuff();
+void A_CHolyAttack2();
+void A_MWandAttack();
+void A_LightningReady();
+void A_MLightningAttack();
+void A_LightningZap();
+void A_LightningClip();
+void A_LightningRemove();
+void A_LastZap();
+void A_ZapMimic();
+void A_MStaffAttack();
+void A_MStaffPalette();
+void A_MStaffWeave();
+void A_MStaffTrack();
+void A_SnoutAttack();
+void A_FireConePL1();
+void A_ShedShard();
+void A_AddPlayerCorpse();
+void A_SkullPop();
+void A_FreezeDeath();
+void A_FreezeDeathChunks();
+void A_CheckBurnGone();
+void A_CheckSkullFloor();
+void A_CheckSkullDone();
+void A_SpeedFade();
+void A_IceSetTics();
+void A_IceCheckHeadDone();
+void A_PigPain();
+void A_PigLook();
+void A_PigChase();
+void A_FaceTarget();
+void A_PigAttack();
+void A_QueueCorpse();
+void A_Look();
+void A_Chase();
+void A_CentaurAttack();
+void A_CentaurAttack2();
+void A_SetReflective();
+void A_CentaurDefend();
+void A_UnSetReflective();
+void A_CentaurDropStuff();
+void A_CheckFloor();
+void A_DemonAttack1();
+void A_DemonAttack2();
+void A_DemonDeath();
+void A_Demon2Death();
+void A_WraithRaiseInit();
+void A_WraithRaise();
+void A_WraithInit();
+void A_WraithLook();
+void A_WraithChase();
+void A_WraithFX3();
+void A_WraithMelee();
+void A_WraithMissile();
+void A_WraithFX2();
+void A_MinotaurFade1();
+void A_MinotaurFade2();
+void A_MinotaurLook();
+void A_MinotaurChase();
+void A_MinotaurRoam();
+void A_MinotaurAtk1();
+void A_MinotaurDecide();
+void A_MinotaurAtk2();
+void A_MinotaurAtk3();
+void A_MinotaurCharge();
+void A_SmokePuffExit();
+void A_MinotaurFade0();
+void A_MntrFloorFire();
+void A_SerpentChase();
+void A_SerpentHumpDecide();
+void A_SerpentUnHide();
+void A_SerpentRaiseHump();
+void A_SerpentLowerHump();
+void A_SerpentHide();
+void A_SerpentBirthScream();
+void A_SetShootable();
+void A_SerpentCheckForAttack();
+void A_UnSetShootable();
+void A_SerpentDiveSound();
+void A_SerpentWalk();
+void A_SerpentChooseAttack();
+void A_SerpentMeleeAttack();
+void A_SerpentMissileAttack();
+void A_SerpentHeadPop();
+void A_SerpentSpawnGibs();
+void A_SerpentHeadCheck();
+void A_FloatGib();
+void A_DelayGib();
+void A_SinkGib();
+void A_BishopDecide();
+void A_BishopDoBlur();
+void A_BishopSpawnBlur();
+void A_BishopChase();
+void A_BishopAttack();
+void A_BishopAttack2();
+void A_BishopPainBlur();
+void A_BishopPuff();
+void A_SetAltShadow();
+void A_BishopMissileWeave();
+void A_BishopMissileSeek();
+void A_DragonInitFlight();
+void A_DragonFlap();
+void A_DragonFlight();
+void A_DragonAttack();
+void A_DragonPain();
+void A_DragonCheckCrash();
+void A_DragonFX2();
+void A_ESound();
+void A_EttinAttack();
+void A_DropMace();
+void A_FiredRocks();
+void A_UnSetInvulnerable();
+void A_FiredChase();
+void A_FiredAttack();
+void A_FiredSplotch();
+void A_SmBounce();
+void A_IceGuyLook();
+void A_IceGuyChase();
+void A_IceGuyAttack();
+void A_IceGuyDie();
+void A_IceGuyMissilePuff();
+void A_IceGuyMissileExplode();
+void A_ClassBossHealth();
+void A_FastChase();
+void A_FighterAttack();
+void A_ClericAttack();
+void A_MageAttack();
+void A_SorcSpinBalls();
+void A_SpeedBalls();
+void A_SpawnFizzle();
+void A_SorcBossAttack();
+void A_SorcBallOrbit();
+void A_SorcBallPop();
+void A_BounceCheck();
+void A_SorcFX1Seek();
+void A_SorcFX2Split();
+void A_SorcFX2Orbit();
+void A_SorcererBishopEntry();
+void A_SpawnBishop();
+void A_SorcFX4Check();
+void A_KoraxStep2();
+void A_KoraxChase();
+void A_KoraxStep();
+void A_KoraxDecide();
+void A_KoraxMissile();
+void A_KoraxCommand();
+void A_KoraxBonePop();
+void A_KSpiritRoam();
+void A_KBoltRaise();
+void A_KBolt();
+void A_BatSpawnInit();
+void A_BatSpawn();
+void A_BatMove();
+
+state_t states[NUMSTATES] = {
+ {SPR_MAN1, 0, -1, NULL, S_NULL, 0, 0}, // S_NULL
+ {SPR_ACLO, 4, 1050, A_FreeTargMobj, S_NULL, 0, 0}, // S_FREETARGMOBJ
+ {SPR_TLGL, 0, -1, NULL, S_NULL, 0, 0}, // S_MAPSPOT
+ {SPR_FBL1, 32768, 4, NULL, S_FIREBALL1_2, 0, 0}, // S_FIREBALL1_1
+ {SPR_FBL1, 32769, 4, NULL, S_FIREBALL1_1, 0, 0}, // S_FIREBALL1_2
+ {SPR_XPL1, 32768, 4, NULL, S_FIREBALL1_X2, 0, 0}, // S_FIREBALL1_X1
+ {SPR_XPL1, 32769, 4, NULL, S_FIREBALL1_X3, 0, 0}, // S_FIREBALL1_X2
+ {SPR_XPL1, 32770, 4, NULL, S_FIREBALL1_X4, 0, 0}, // S_FIREBALL1_X3
+ {SPR_XPL1, 32771, 4, NULL, S_FIREBALL1_X5, 0, 0}, // S_FIREBALL1_X4
+ {SPR_XPL1, 32772, 4, NULL, S_FIREBALL1_X6, 0, 0}, // S_FIREBALL1_X5
+ {SPR_XPL1, 32773, 4, NULL, S_NULL, 0, 0}, // S_FIREBALL1_X6
+ {SPR_ARRW, 0, -1, NULL, S_NULL, 0, 0}, // S_ARROW_1
+ {SPR_ARRW, 0, 1, NULL, S_NULL, 0, 0}, // S_ARROW_X1
+ {SPR_DART, 0, -1, NULL, S_NULL, 0, 0}, // S_DART_1
+ {SPR_DART, 0, 1, NULL, S_NULL, 0, 0}, // S_DART_X1
+ {SPR_DART, 0, -1, NULL, S_NULL, 0, 0}, // S_POISONDART_1
+ {SPR_DART, 0, 1, NULL, S_NULL, 0, 0}, // S_POISONDART_X1
+ {SPR_RIPP, 0, 3, NULL, S_RIPPERBALL_2, 0, 0}, // S_RIPPERBALL_1
+ {SPR_RIPP, 1, 3, NULL, S_RIPPERBALL_3, 0, 0}, // S_RIPPERBALL_2
+ {SPR_RIPP, 2, 3, NULL, S_RIPPERBALL_1, 0, 0}, // S_RIPPERBALL_3
+ {SPR_CFCF, 32784, 4, NULL, S_RIPPERBALL_X2, 0, 0}, // S_RIPPERBALL_X1
+ {SPR_CFCF, 32785, 3, NULL, S_RIPPERBALL_X3, 0, 0}, // S_RIPPERBALL_X2
+ {SPR_CFCF, 32786, 4, NULL, S_RIPPERBALL_X4, 0, 0}, // S_RIPPERBALL_X3
+ {SPR_CFCF, 32787, 3, NULL, S_RIPPERBALL_X5, 0, 0}, // S_RIPPERBALL_X4
+ {SPR_CFCF, 32788, 4, NULL, S_RIPPERBALL_X6, 0, 0}, // S_RIPPERBALL_X5
+ {SPR_CFCF, 32789, 3, NULL, S_RIPPERBALL_X7, 0, 0}, // S_RIPPERBALL_X6
+ {SPR_CFCF, 32790, 4, NULL, S_RIPPERBALL_X8, 0, 0}, // S_RIPPERBALL_X7
+ {SPR_CFCF, 32791, 3, NULL, S_RIPPERBALL_X9, 0, 0}, // S_RIPPERBALL_X8
+ {SPR_CFCF, 32792, 4, NULL, S_RIPPERBALL_X10, 0, 0}, // S_RIPPERBALL_X9
+ {SPR_CFCF, 32793, 3, NULL, S_NULL, 0, 0}, // S_RIPPERBALL_X10
+ {SPR_BLAD, 0, -1, NULL, S_NULL, 0, 0}, // S_PRJ_BLADE1
+ {SPR_BLAD, 0, 1, NULL, S_NULL, 0, 0}, // S_PRJ_BLADE_X1
+ {SPR_SHRD, 32768, 3, NULL, S_ICESHARD2, 0, 0}, // S_ICESHARD1
+ {SPR_SHRD, 32769, 3, NULL, S_ICESHARD3, 0, 0}, // S_ICESHARD2
+ {SPR_SHRD, 32770, 3, NULL, S_ICESHARD1, 0, 0}, // S_ICESHARD3
+ {SPR_FFSM, 32768, 3, NULL, S_FLAME_TSMALL2, 0, 0}, // S_FLAME_TSMALL1
+ {SPR_FFSM, 32769, 3, NULL, S_FLAME_TSMALL3, 0, 0}, // S_FLAME_TSMALL2
+ {SPR_FFSM, 32770, 2, A_FlameCheck, S_FLAME_TSMALL4, 0, 0}, // S_FLAME_TSMALL3
+ {SPR_FFSM, 32770, 2, NULL, S_FLAME_TSMALL5, 0, 0}, // S_FLAME_TSMALL4
+ {SPR_FFSM, 32771, 3, NULL, S_FLAME_TSMALL6, 0, 0}, // S_FLAME_TSMALL5
+ {SPR_FFSM, 32772, 3, A_FlameCheck, S_FLAME_TSMALL1, 0, 0}, // S_FLAME_TSMALL6
+ {SPR_FFLG, 32768, 4, NULL, S_FLAME_TLARGE2, 0, 0}, // S_FLAME_TLARGE1
+ {SPR_FFLG, 32769, 4, A_FlameCheck, S_FLAME_TLARGE3, 0, 0}, // S_FLAME_TLARGE2
+ {SPR_FFLG, 32770, 4, NULL, S_FLAME_TLARGE4, 0, 0}, // S_FLAME_TLARGE3
+ {SPR_FFLG, 32771, 4, A_FlameCheck, S_FLAME_TLARGE5, 0, 0}, // S_FLAME_TLARGE4
+ {SPR_FFLG, 32772, 4, NULL, S_FLAME_TLARGE6, 0, 0}, // S_FLAME_TLARGE5
+ {SPR_FFLG, 32773, 4, A_FlameCheck, S_FLAME_TLARGE7, 0, 0}, // S_FLAME_TLARGE6
+ {SPR_FFLG, 32774, 4, NULL, S_FLAME_TLARGE8, 0, 0}, // S_FLAME_TLARGE7
+ {SPR_FFLG, 32775, 4, A_FlameCheck, S_FLAME_TLARGE9, 0, 0}, // S_FLAME_TLARGE8
+ {SPR_FFLG, 32776, 4, NULL, S_FLAME_TLARGE10, 0, 0}, // S_FLAME_TLARGE9
+ {SPR_FFLG, 32777, 4, A_FlameCheck, S_FLAME_TLARGE11, 0, 0}, // S_FLAME_TLARGE10
+ {SPR_FFLG, 32778, 4, NULL, S_FLAME_TLARGE12, 0, 0}, // S_FLAME_TLARGE11
+ {SPR_FFLG, 32779, 4, A_FlameCheck, S_FLAME_TLARGE13, 0, 0}, // S_FLAME_TLARGE12
+ {SPR_FFLG, 32780, 4, NULL, S_FLAME_TLARGE14, 0, 0}, // S_FLAME_TLARGE13
+ {SPR_FFLG, 32781, 4, A_FlameCheck, S_FLAME_TLARGE15, 0, 0}, // S_FLAME_TLARGE14
+ {SPR_FFLG, 32782, 4, NULL, S_FLAME_TLARGE16, 0, 0}, // S_FLAME_TLARGE15
+ {SPR_FFLG, 32783, 4, A_FlameCheck, S_FLAME_TLARGE5, 0, 0}, // S_FLAME_TLARGE16
+ {SPR_FFSM, 0, 2, NULL, S_FLAME_SDORM2, 0, 0}, // S_FLAME_SDORM1
+ {SPR_FFSM, 1, 2, A_HideThing, S_FLAME_SDORM3, 0, 0}, // S_FLAME_SDORM2
+ {SPR_FFSM, 2, 200, NULL, S_FLAME_SDORM3, 0, 0}, // S_FLAME_SDORM3
+ {SPR_FFSM, 32768, 3, NULL, S_FLAME_SMALL2, 0, 0}, // S_FLAME_SMALL1
+ {SPR_FFSM, 32768, 3, A_UnHideThing, S_FLAME_SMALL3, 0, 0}, // S_FLAME_SMALL2
+ {SPR_FFSM, 32768, 3, NULL, S_FLAME_SMALL4, 0, 0}, // S_FLAME_SMALL3
+ {SPR_FFSM, 32769, 3, NULL, S_FLAME_SMALL5, 0, 0}, // S_FLAME_SMALL4
+ {SPR_FFSM, 32770, 3, NULL, S_FLAME_SMALL6, 0, 0}, // S_FLAME_SMALL5
+ {SPR_FFSM, 32771, 3, NULL, S_FLAME_SMALL7, 0, 0}, // S_FLAME_SMALL6
+ {SPR_FFSM, 32772, 3, NULL, S_FLAME_SMALL3, 0, 0}, // S_FLAME_SMALL7
+ {SPR_FFLG, 3, 2, NULL, S_FLAME_LDORM2, 0, 0}, // S_FLAME_LDORM1
+ {SPR_FFLG, 2, 2, NULL, S_FLAME_LDORM3, 0, 0}, // S_FLAME_LDORM2
+ {SPR_FFLG, 1, 2, NULL, S_FLAME_LDORM4, 0, 0}, // S_FLAME_LDORM3
+ {SPR_FFLG, 0, 2, A_HideThing, S_FLAME_LDORM5, 0, 0}, // S_FLAME_LDORM4
+ {SPR_FFLG, 0, 200, NULL, S_FLAME_LDORM5, 0, 0}, // S_FLAME_LDORM5
+ {SPR_FFLG, 32768, 2, NULL, S_FLAME_LARGE2, 0, 0}, // S_FLAME_LARGE1
+ {SPR_FFLG, 32768, 2, A_UnHideThing, S_FLAME_LARGE3, 0, 0}, // S_FLAME_LARGE2
+ {SPR_FFLG, 32768, 4, NULL, S_FLAME_LARGE4, 0, 0}, // S_FLAME_LARGE3
+ {SPR_FFLG, 32769, 4, NULL, S_FLAME_LARGE5, 0, 0}, // S_FLAME_LARGE4
+ {SPR_FFLG, 32770, 4, NULL, S_FLAME_LARGE6, 0, 0}, // S_FLAME_LARGE5
+ {SPR_FFLG, 32771, 4, NULL, S_FLAME_LARGE7, 0, 0}, // S_FLAME_LARGE6
+ {SPR_FFLG, 32772, 4, NULL, S_FLAME_LARGE8, 0, 0}, // S_FLAME_LARGE7
+ {SPR_FFLG, 32773, 4, NULL, S_FLAME_LARGE9, 0, 0}, // S_FLAME_LARGE8
+ {SPR_FFLG, 32774, 4, NULL, S_FLAME_LARGE10, 0, 0}, // S_FLAME_LARGE9
+ {SPR_FFLG, 32775, 4, NULL, S_FLAME_LARGE11, 0, 0}, // S_FLAME_LARGE10
+ {SPR_FFLG, 32776, 4, NULL, S_FLAME_LARGE12, 0, 0}, // S_FLAME_LARGE11
+ {SPR_FFLG, 32777, 4, NULL, S_FLAME_LARGE13, 0, 0}, // S_FLAME_LARGE12
+ {SPR_FFLG, 32778, 4, NULL, S_FLAME_LARGE14, 0, 0}, // S_FLAME_LARGE13
+ {SPR_FFLG, 32779, 4, NULL, S_FLAME_LARGE15, 0, 0}, // S_FLAME_LARGE14
+ {SPR_FFLG, 32780, 4, NULL, S_FLAME_LARGE16, 0, 0}, // S_FLAME_LARGE15
+ {SPR_FFLG, 32781, 4, NULL, S_FLAME_LARGE17, 0, 0}, // S_FLAME_LARGE16
+ {SPR_FFLG, 32782, 4, NULL, S_FLAME_LARGE18, 0, 0}, // S_FLAME_LARGE17
+ {SPR_FFLG, 32783, 4, NULL, S_FLAME_LARGE7, 0, 0}, // S_FLAME_LARGE18
+ {SPR_PTN1, 0, 3, NULL, S_ITEM_PTN1_2, 0, 0}, // S_ITEM_PTN1_1
+ {SPR_PTN1, 1, 3, NULL, S_ITEM_PTN1_3, 0, 0}, // S_ITEM_PTN1_2
+ {SPR_PTN1, 2, 3, NULL, S_ITEM_PTN1_1, 0, 0}, // S_ITEM_PTN1_3
+ {SPR_ACLO, 4, 1400, NULL, S_HIDESPECIAL2, 0, 0}, // S_HIDESPECIAL1
+ {SPR_ACLO, 0, 4, A_RestoreSpecialThing1, S_HIDESPECIAL3, 0, 0}, // S_HIDESPECIAL2
+ {SPR_ACLO, 1, 4, NULL, S_HIDESPECIAL4, 0, 0}, // S_HIDESPECIAL3
+ {SPR_ACLO, 0, 4, NULL, S_HIDESPECIAL5, 0, 0}, // S_HIDESPECIAL4
+ {SPR_ACLO, 1, 4, NULL, S_HIDESPECIAL6, 0, 0}, // S_HIDESPECIAL5
+ {SPR_ACLO, 2, 4, NULL, S_HIDESPECIAL7, 0, 0}, // S_HIDESPECIAL6
+ {SPR_ACLO, 1, 4, NULL, S_HIDESPECIAL8, 0, 0}, // S_HIDESPECIAL7
+ {SPR_ACLO, 2, 4, NULL, S_HIDESPECIAL9, 0, 0}, // S_HIDESPECIAL8
+ {SPR_ACLO, 3, 4, NULL, S_HIDESPECIAL10, 0, 0}, // S_HIDESPECIAL9
+ {SPR_ACLO, 2, 4, NULL, S_HIDESPECIAL11, 0, 0}, // S_HIDESPECIAL10
+ {SPR_ACLO, 3, 4, A_RestoreSpecialThing2, S_NULL, 0, 0}, // S_HIDESPECIAL11
+ {SPR_ACLO, 3, 3, NULL, S_DORMANTARTI1_2, 0, 0}, // S_DORMANTARTI1_1
+ {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI1_3, 0, 0}, // S_DORMANTARTI1_2
+ {SPR_ACLO, 3, 3, NULL, S_DORMANTARTI1_4, 0, 0}, // S_DORMANTARTI1_3
+ {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI1_5, 0, 0}, // S_DORMANTARTI1_4
+ {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI1_6, 0, 0}, // S_DORMANTARTI1_5
+ {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI1_7, 0, 0}, // S_DORMANTARTI1_6
+ {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI1_8, 0, 0}, // S_DORMANTARTI1_7
+ {SPR_ACLO, 0, 3, NULL, S_DORMANTARTI1_9, 0, 0}, // S_DORMANTARTI1_8
+ {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI1_10, 0, 0}, // S_DORMANTARTI1_9
+ {SPR_ACLO, 0, 3, NULL, S_DORMANTARTI1_11, 0, 0}, // S_DORMANTARTI1_10
+ {SPR_ACLO, 0, 1400, A_HideThing, S_DORMANTARTI1_12, 0, 0}, // S_DORMANTARTI1_11
+ {SPR_ACLO, 0, 3, A_UnHideThing, S_DORMANTARTI1_13, 0, 0}, // S_DORMANTARTI1_12
+ {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI1_14, 0, 0}, // S_DORMANTARTI1_13
+ {SPR_ACLO, 0, 3, NULL, S_DORMANTARTI1_15, 0, 0}, // S_DORMANTARTI1_14
+ {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI1_16, 0, 0}, // S_DORMANTARTI1_15
+ {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI1_17, 0, 0}, // S_DORMANTARTI1_16
+ {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI1_18, 0, 0}, // S_DORMANTARTI1_17
+ {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI1_19, 0, 0}, // S_DORMANTARTI1_18
+ {SPR_ACLO, 3, 3, NULL, S_DORMANTARTI1_20, 0, 0}, // S_DORMANTARTI1_19
+ {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI1_21, 0, 0}, // S_DORMANTARTI1_20
+ {SPR_ACLO, 3, 3, A_RestoreArtifact, S_NULL, 0, 0}, // S_DORMANTARTI1_21
+ {SPR_ACLO, 3, 3, NULL, S_DORMANTARTI2_2, 0, 0}, // S_DORMANTARTI2_1
+ {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI2_3, 0, 0}, // S_DORMANTARTI2_2
+ {SPR_ACLO, 3, 3, NULL, S_DORMANTARTI2_4, 0, 0}, // S_DORMANTARTI2_3
+ {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI2_5, 0, 0}, // S_DORMANTARTI2_4
+ {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI2_6, 0, 0}, // S_DORMANTARTI2_5
+ {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI2_7, 0, 0}, // S_DORMANTARTI2_6
+ {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI2_8, 0, 0}, // S_DORMANTARTI2_7
+ {SPR_ACLO, 0, 3, NULL, S_DORMANTARTI2_9, 0, 0}, // S_DORMANTARTI2_8
+ {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI2_10, 0, 0}, // S_DORMANTARTI2_9
+ {SPR_ACLO, 0, 3, NULL, S_DORMANTARTI2_11, 0, 0}, // S_DORMANTARTI2_10
+ {SPR_ACLO, 0, 4200, A_HideThing, S_DORMANTARTI2_12, 0, 0}, // S_DORMANTARTI2_11
+ {SPR_ACLO, 0, 3, A_UnHideThing, S_DORMANTARTI2_13, 0, 0}, // S_DORMANTARTI2_12
+ {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI2_14, 0, 0}, // S_DORMANTARTI2_13
+ {SPR_ACLO, 0, 3, NULL, S_DORMANTARTI2_15, 0, 0}, // S_DORMANTARTI2_14
+ {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI2_16, 0, 0}, // S_DORMANTARTI2_15
+ {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI2_17, 0, 0}, // S_DORMANTARTI2_16
+ {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI2_18, 0, 0}, // S_DORMANTARTI2_17
+ {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI2_19, 0, 0}, // S_DORMANTARTI2_18
+ {SPR_ACLO, 3, 3, NULL, S_DORMANTARTI2_20, 0, 0}, // S_DORMANTARTI2_19
+ {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI2_21, 0, 0}, // S_DORMANTARTI2_20
+ {SPR_ACLO, 3, 3, A_RestoreArtifact, S_NULL, 0, 0}, // S_DORMANTARTI2_21
+ {SPR_ACLO, 3, 3, NULL, S_DORMANTARTI3_2, 0, 0}, // S_DORMANTARTI3_1
+ {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI3_3, 0, 0}, // S_DORMANTARTI3_2
+ {SPR_ACLO, 3, 3, NULL, S_DORMANTARTI3_4, 0, 0}, // S_DORMANTARTI3_3
+ {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI3_5, 0, 0}, // S_DORMANTARTI3_4
+ {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI3_6, 0, 0}, // S_DORMANTARTI3_5
+ {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI3_7, 0, 0}, // S_DORMANTARTI3_6
+ {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI3_8, 0, 0}, // S_DORMANTARTI3_7
+ {SPR_ACLO, 0, 3, NULL, S_DORMANTARTI3_9, 0, 0}, // S_DORMANTARTI3_8
+ {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI3_10, 0, 0}, // S_DORMANTARTI3_9
+ {SPR_ACLO, 0, 3, NULL, S_DORMANTARTI3_11, 0, 0}, // S_DORMANTARTI3_10
+ {SPR_ACLO, 0, 21000, A_HideThing, S_DORMANTARTI3_12, 0, 0}, // S_DORMANTARTI3_11
+ {SPR_ACLO, 0, 3, A_UnHideThing, S_DORMANTARTI3_13, 0, 0}, // S_DORMANTARTI3_12
+ {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI3_14, 0, 0}, // S_DORMANTARTI3_13
+ {SPR_ACLO, 0, 3, NULL, S_DORMANTARTI3_15, 0, 0}, // S_DORMANTARTI3_14
+ {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI3_16, 0, 0}, // S_DORMANTARTI3_15
+ {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI3_17, 0, 0}, // S_DORMANTARTI3_16
+ {SPR_ACLO, 1, 3, NULL, S_DORMANTARTI3_18, 0, 0}, // S_DORMANTARTI3_17
+ {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI3_19, 0, 0}, // S_DORMANTARTI3_18
+ {SPR_ACLO, 3, 3, NULL, S_DORMANTARTI3_20, 0, 0}, // S_DORMANTARTI3_19
+ {SPR_ACLO, 2, 3, NULL, S_DORMANTARTI3_21, 0, 0}, // S_DORMANTARTI3_20
+ {SPR_ACLO, 3, 3, A_RestoreArtifact, S_NULL, 0, 0}, // S_DORMANTARTI3_21
+ {SPR_ACLO, 3, 3, NULL, S_DEADARTI2, 0, 0}, // S_DEADARTI1
+ {SPR_ACLO, 2, 3, NULL, S_DEADARTI3, 0, 0}, // S_DEADARTI2
+ {SPR_ACLO, 3, 3, NULL, S_DEADARTI4, 0, 0}, // S_DEADARTI3
+ {SPR_ACLO, 2, 3, NULL, S_DEADARTI5, 0, 0}, // S_DEADARTI4
+ {SPR_ACLO, 1, 3, NULL, S_DEADARTI6, 0, 0}, // S_DEADARTI5
+ {SPR_ACLO, 2, 3, NULL, S_DEADARTI7, 0, 0}, // S_DEADARTI6
+ {SPR_ACLO, 1, 3, NULL, S_DEADARTI8, 0, 0}, // S_DEADARTI7
+ {SPR_ACLO, 0, 3, NULL, S_DEADARTI9, 0, 0}, // S_DEADARTI8
+ {SPR_ACLO, 1, 3, NULL, S_DEADARTI10, 0, 0}, // S_DEADARTI9
+ {SPR_ACLO, 0, 3, NULL, S_NULL, 0, 0}, // S_DEADARTI10
+ {SPR_PTN2, 0, 4, NULL, S_ARTI_PTN2_2, 0, 0}, // S_ARTI_PTN2_1
+ {SPR_PTN2, 1, 4, NULL, S_ARTI_PTN2_3, 0, 0}, // S_ARTI_PTN2_2
+ {SPR_PTN2, 2, 4, NULL, S_ARTI_PTN2_1, 0, 0}, // S_ARTI_PTN2_3
+ {SPR_SOAR, 0, 5, NULL, S_ARTI_SOAR2, 0, 0}, // S_ARTI_SOAR1
+ {SPR_SOAR, 1, 5, NULL, S_ARTI_SOAR3, 0, 0}, // S_ARTI_SOAR2
+ {SPR_SOAR, 2, 5, NULL, S_ARTI_SOAR4, 0, 0}, // S_ARTI_SOAR3
+ {SPR_SOAR, 1, 5, NULL, S_ARTI_SOAR1, 0, 0}, // S_ARTI_SOAR4
+ {SPR_INVU, 0, 3, NULL, S_ARTI_INVU2, 0, 0}, // S_ARTI_INVU1
+ {SPR_INVU, 1, 3, NULL, S_ARTI_INVU3, 0, 0}, // S_ARTI_INVU2
+ {SPR_INVU, 2, 3, NULL, S_ARTI_INVU4, 0, 0}, // S_ARTI_INVU3
+ {SPR_INVU, 3, 3, NULL, S_ARTI_INVU1, 0, 0}, // S_ARTI_INVU4
+ {SPR_SUMN, 0, 350, NULL, S_ARTI_SUMMON, 0, 0}, // S_ARTI_SUMMON
+ {SPR_SUMN, 0, 4, NULL, S_SUMMON_FX1_1, 0, 0}, // S_SUMMON_FX1_1
+ {SPR_SUMN, 0, 4, NULL, S_SUMMON_FX2_2, 0, 0}, // S_SUMMON_FX2_1
+ {SPR_SUMN, 0, 4, NULL, S_SUMMON_FX2_3, 0, 0}, // S_SUMMON_FX2_2
+ {SPR_SUMN, 0, 4, A_Summon, S_NULL, 0, 0}, // S_SUMMON_FX2_3
+ {SPR_TSPK, 0, 3, NULL, S_THRUSTINIT2_2, 0, 0}, // S_THRUSTINIT2_1
+ {SPR_TSPK, 0, 4, A_ThrustInitUp, S_THRUSTBLOCK, 0, 0}, // S_THRUSTINIT2_2
+ {SPR_TSPK, 1, 3, NULL, S_BTHRUSTINIT2_2, 0, 0}, // S_BTHRUSTINIT2_1
+ {SPR_TSPK, 1, 4, A_ThrustInitUp, S_BTHRUSTBLOCK, 0, 0}, // S_BTHRUSTINIT2_2
+ {SPR_TSPK, 0, 3, NULL, S_THRUSTINIT1_2, 0, 0}, // S_THRUSTINIT1_1
+ {SPR_TSPK, 0, 4, A_ThrustInitDn, S_THRUSTSTAY, 0, 0}, // S_THRUSTINIT1_2
+ {SPR_TSPK, 1, 3, NULL, S_BTHRUSTINIT1_2, 0, 0}, // S_BTHRUSTINIT1_1
+ {SPR_TSPK, 1, 4, A_ThrustInitDn, S_BTHRUSTSTAY, 0, 0}, // S_BTHRUSTINIT1_2
+ {SPR_TSPK, 0, 8, A_ThrustRaise, S_THRUSTRAISE2, 0, 0}, // S_THRUSTRAISE1
+ {SPR_TSPK, 0, 6, A_ThrustRaise, S_THRUSTRAISE3, 0, 0}, // S_THRUSTRAISE2
+ {SPR_TSPK, 0, 4, A_ThrustRaise, S_THRUSTRAISE4, 0, 0}, // S_THRUSTRAISE3
+ {SPR_TSPK, 0, 3, A_ThrustBlock, S_THRUSTIMPALE, 0, 0}, // S_THRUSTRAISE4
+ {SPR_TSPK, 1, 8, A_ThrustRaise, S_BTHRUSTRAISE2, 0, 0}, // S_BTHRUSTRAISE1
+ {SPR_TSPK, 1, 6, A_ThrustRaise, S_BTHRUSTRAISE3, 0, 0}, // S_BTHRUSTRAISE2
+ {SPR_TSPK, 1, 4, A_ThrustRaise, S_BTHRUSTRAISE4, 0, 0}, // S_BTHRUSTRAISE3
+ {SPR_TSPK, 1, 3, A_ThrustBlock, S_BTHRUSTIMPALE, 0, 0}, // S_BTHRUSTRAISE4
+ {SPR_TSPK, 0, 2, A_ThrustImpale, S_THRUSTRAISE, 0, 0}, // S_THRUSTIMPALE
+ {SPR_TSPK, 1, 2, A_ThrustImpale, S_BTHRUSTRAISE, 0, 0}, // S_BTHRUSTIMPALE
+ {SPR_TSPK, 0, 2, A_ThrustRaise, S_THRUSTRAISE, 0, 0}, // S_THRUSTRAISE
+ {SPR_TSPK, 1, 2, A_ThrustRaise, S_BTHRUSTRAISE, 0, 0}, // S_BTHRUSTRAISE
+ {SPR_TSPK, 0, 10, NULL, S_THRUSTBLOCK, 0, 0}, // S_THRUSTBLOCK
+ {SPR_TSPK, 1, 10, NULL, S_BTHRUSTBLOCK, 0, 0}, // S_BTHRUSTBLOCK
+ {SPR_TSPK, 0, 2, A_ThrustLower, S_THRUSTLOWER, 0, 0}, // S_THRUSTLOWER
+ {SPR_TSPK, 1, 2, A_ThrustLower, S_BTHRUSTLOWER, 0, 0}, // S_BTHRUSTLOWER
+ {SPR_TSPK, 0, -1, NULL, S_THRUSTSTAY, 0, 0}, // S_THRUSTSTAY
+ {SPR_TSPK, 1, -1, NULL, S_BTHRUSTSTAY, 0, 0}, // S_BTHRUSTSTAY
+ {SPR_TELO, 0, 5, NULL, S_ARTI_TELOTHER2, 0, 0}, // S_ARTI_TELOTHER1
+ {SPR_TELO, 1, 5, NULL, S_ARTI_TELOTHER3, 0, 0}, // S_ARTI_TELOTHER2
+ {SPR_TELO, 2, 5, NULL, S_ARTI_TELOTHER4, 0, 0}, // S_ARTI_TELOTHER3
+ {SPR_TELO, 3, 5, NULL, S_ARTI_TELOTHER1, 0, 0}, // S_ARTI_TELOTHER4
+ {SPR_TRNG, 32772, 5, NULL, S_TELO_FX2, 0, 0}, // S_TELO_FX1
+ {SPR_TRNG, 32771, 4, NULL, S_TELO_FX3, 0, 0}, // S_TELO_FX2
+ {SPR_TRNG, 32770, 3, A_TeloSpawnC, S_TELO_FX4, 0, 0}, // S_TELO_FX3
+ {SPR_TRNG, 32769, 3, A_TeloSpawnB, S_TELO_FX5, 0, 0}, // S_TELO_FX4
+ {SPR_TRNG, 32768, 3, A_TeloSpawnA, S_TELO_FX6, 0, 0}, // S_TELO_FX5
+ {SPR_TRNG, 32769, 3, A_TeloSpawnB, S_TELO_FX7, 0, 0}, // S_TELO_FX6
+ {SPR_TRNG, 32770, 3, A_TeloSpawnC, S_TELO_FX8, 0, 0}, // S_TELO_FX7
+ {SPR_TRNG, 32771, 3, A_TeloSpawnD, S_TELO_FX3, 0, 0}, // S_TELO_FX8
+ {SPR_TRNG, 32772, 3, NULL, S_NULL, 0, 0}, // S_TELO_FX9
+ {SPR_TRNG, 32769, 4, NULL, S_TELO_FX2_2, 0, 0}, // S_TELO_FX2_1
+ {SPR_TRNG, 32770, 4, NULL, S_TELO_FX2_3, 0, 0}, // S_TELO_FX2_2
+ {SPR_TRNG, 32771, 4, NULL, S_TELO_FX2_4, 0, 0}, // S_TELO_FX2_3
+ {SPR_TRNG, 32770, 4, NULL, S_TELO_FX2_5, 0, 0}, // S_TELO_FX2_4
+ {SPR_TRNG, 32769, 4, NULL, S_TELO_FX2_6, 0, 0}, // S_TELO_FX2_5
+ {SPR_TRNG, 32768, 4, A_CheckTeleRing, S_TELO_FX2_1, 0, 0}, // S_TELO_FX2_6
+ {SPR_TRNG, 32770, 4, NULL, S_TELO_FX3_2, 0, 0}, // S_TELO_FX3_1
+ {SPR_TRNG, 32771, 4, NULL, S_TELO_FX3_3, 0, 0}, // S_TELO_FX3_2
+ {SPR_TRNG, 32770, 4, NULL, S_TELO_FX3_4, 0, 0}, // S_TELO_FX3_3
+ {SPR_TRNG, 32769, 4, NULL, S_TELO_FX3_5, 0, 0}, // S_TELO_FX3_4
+ {SPR_TRNG, 32768, 4, NULL, S_TELO_FX3_6, 0, 0}, // S_TELO_FX3_5
+ {SPR_TRNG, 32769, 4, A_CheckTeleRing, S_TELO_FX3_1, 0, 0}, // S_TELO_FX3_6
+ {SPR_TRNG, 32771, 4, NULL, S_TELO_FX4_2, 0, 0}, // S_TELO_FX4_1
+ {SPR_TRNG, 32770, 4, NULL, S_TELO_FX4_3, 0, 0}, // S_TELO_FX4_2
+ {SPR_TRNG, 32769, 4, NULL, S_TELO_FX4_4, 0, 0}, // S_TELO_FX4_3
+ {SPR_TRNG, 32768, 4, NULL, S_TELO_FX4_5, 0, 0}, // S_TELO_FX4_4
+ {SPR_TRNG, 32769, 4, NULL, S_TELO_FX4_6, 0, 0}, // S_TELO_FX4_5
+ {SPR_TRNG, 32770, 4, A_CheckTeleRing, S_TELO_FX4_1, 0, 0}, // S_TELO_FX4_6
+ {SPR_TRNG, 32770, 4, NULL, S_TELO_FX5_2, 0, 0}, // S_TELO_FX5_1
+ {SPR_TRNG, 32769, 4, NULL, S_TELO_FX5_3, 0, 0}, // S_TELO_FX5_2
+ {SPR_TRNG, 32768, 4, NULL, S_TELO_FX5_4, 0, 0}, // S_TELO_FX5_3
+ {SPR_TRNG, 32769, 4, NULL, S_TELO_FX5_5, 0, 0}, // S_TELO_FX5_4
+ {SPR_TRNG, 32770, 4, NULL, S_TELO_FX5_6, 0, 0}, // S_TELO_FX5_5
+ {SPR_TRNG, 32771, 4, A_CheckTeleRing, S_TELO_FX5_1, 0, 0}, // S_TELO_FX5_6
+ {SPR_ROCK, 3, 20, NULL, S_DIRT1_1, 0, 0}, // S_DIRT1_1
+ {SPR_ROCK, 3, 10, NULL, S_NULL, 0, 0}, // S_DIRT1_D
+ {SPR_ROCK, 4, 20, NULL, S_DIRT2_1, 0, 0}, // S_DIRT2_1
+ {SPR_ROCK, 4, 10, NULL, S_NULL, 0, 0}, // S_DIRT2_D
+ {SPR_ROCK, 5, 20, NULL, S_DIRT3_1, 0, 0}, // S_DIRT3_1
+ {SPR_ROCK, 5, 10, NULL, S_NULL, 0, 0}, // S_DIRT3_D
+ {SPR_ROCK, 6, 20, NULL, S_DIRT4_1, 0, 0}, // S_DIRT4_1
+ {SPR_ROCK, 6, 10, NULL, S_NULL, 0, 0}, // S_DIRT4_D
+ {SPR_ROCK, 7, 20, NULL, S_DIRT5_1, 0, 0}, // S_DIRT5_1
+ {SPR_ROCK, 7, 10, NULL, S_NULL, 0, 0}, // S_DIRT5_D
+ {SPR_ROCK, 8, 20, NULL, S_DIRT6_1, 0, 0}, // S_DIRT6_1
+ {SPR_ROCK, 8, 10, NULL, S_NULL, 0, 0}, // S_DIRT6_D
+ {SPR_TSPK, 2, 20, NULL, S_DIRTCLUMP1, 0, 0}, // S_DIRTCLUMP1
+ {SPR_ROCK, 0, 20, NULL, S_ROCK1_1, 0, 0}, // S_ROCK1_1
+ {SPR_ROCK, 0, 10, NULL, S_NULL, 0, 0}, // S_ROCK1_D
+ {SPR_ROCK, 1, 20, NULL, S_ROCK2_1, 0, 0}, // S_ROCK2_1
+ {SPR_ROCK, 1, 10, NULL, S_NULL, 0, 0}, // S_ROCK2_D
+ {SPR_ROCK, 2, 20, NULL, S_ROCK3_1, 0, 0}, // S_ROCK3_1
+ {SPR_ROCK, 2, 10, NULL, S_NULL, 0, 0}, // S_ROCK3_D
+ {SPR_MAN1, 0, 20, A_FogSpawn, S_SPAWNFOG1, 0, 0}, // S_SPAWNFOG1
+ {SPR_FOGS, 0, 7, A_FogMove, S_FOGPATCHS2, 0, 0}, // S_FOGPATCHS1
+ {SPR_FOGS, 1, 7, A_FogMove, S_FOGPATCHS3, 0, 0}, // S_FOGPATCHS2
+ {SPR_FOGS, 2, 7, A_FogMove, S_FOGPATCHS4, 0, 0}, // S_FOGPATCHS3
+ {SPR_FOGS, 3, 7, A_FogMove, S_FOGPATCHS5, 0, 0}, // S_FOGPATCHS4
+ {SPR_FOGS, 4, 7, A_FogMove, S_FOGPATCHS1, 0, 0}, // S_FOGPATCHS5
+ {SPR_FOGS, 4, 5, NULL, S_NULL, 0, 0}, // S_FOGPATCHS0
+ {SPR_FOGM, 0, 7, A_FogMove, S_FOGPATCHM2, 0, 0}, // S_FOGPATCHM1
+ {SPR_FOGM, 1, 7, A_FogMove, S_FOGPATCHM3, 0, 0}, // S_FOGPATCHM2
+ {SPR_FOGM, 2, 7, A_FogMove, S_FOGPATCHM4, 0, 0}, // S_FOGPATCHM3
+ {SPR_FOGM, 3, 7, A_FogMove, S_FOGPATCHM5, 0, 0}, // S_FOGPATCHM4
+ {SPR_FOGM, 4, 7, A_FogMove, S_FOGPATCHM1, 0, 0}, // S_FOGPATCHM5
+ {SPR_FOGS, 0, 5, NULL, S_FOGPATCHMA, 0, 0}, // S_FOGPATCHM0
+ {SPR_FOGS, 1, 5, NULL, S_FOGPATCHMB, 0, 0}, // S_FOGPATCHMA
+ {SPR_FOGS, 2, 5, NULL, S_FOGPATCHMC, 0, 0}, // S_FOGPATCHMB
+ {SPR_FOGS, 3, 5, NULL, S_FOGPATCHMD, 0, 0}, // S_FOGPATCHMC
+ {SPR_FOGS, 4, 5, NULL, S_FOGPATCHS0, 0, 0}, // S_FOGPATCHMD
+ {SPR_FOGL, 0, 7, A_FogMove, S_FOGPATCHL2, 0, 0}, // S_FOGPATCHL1
+ {SPR_FOGL, 1, 7, A_FogMove, S_FOGPATCHL3, 0, 0}, // S_FOGPATCHL2
+ {SPR_FOGL, 2, 7, A_FogMove, S_FOGPATCHL4, 0, 0}, // S_FOGPATCHL3
+ {SPR_FOGL, 3, 7, A_FogMove, S_FOGPATCHL5, 0, 0}, // S_FOGPATCHL4
+ {SPR_FOGL, 4, 7, A_FogMove, S_FOGPATCHL1, 0, 0}, // S_FOGPATCHL5
+ {SPR_FOGM, 0, 4, NULL, S_FOGPATCHLA, 0, 0}, // S_FOGPATCHL0
+ {SPR_FOGM, 1, 4, NULL, S_FOGPATCHLB, 0, 0}, // S_FOGPATCHLA
+ {SPR_FOGM, 2, 4, NULL, S_FOGPATCHLC, 0, 0}, // S_FOGPATCHLB
+ {SPR_FOGM, 3, 4, NULL, S_FOGPATCHLD, 0, 0}, // S_FOGPATCHLC
+ {SPR_FOGM, 4, 4, NULL, S_FOGPATCHM0, 0, 0}, // S_FOGPATCHLD
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVE2, 0, 0}, // S_QUAKE_ACTIVE1
+ {SPR_MAN1, 0, 1, A_ContMobjSound, S_QUAKE_ACTIVE3, 0, 0}, // S_QUAKE_ACTIVE2
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVE4, 0, 0}, // S_QUAKE_ACTIVE3
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVE5, 0, 0}, // S_QUAKE_ACTIVE4
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVE6, 0, 0}, // S_QUAKE_ACTIVE5
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVE7, 0, 0}, // S_QUAKE_ACTIVE6
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVE8, 0, 0}, // S_QUAKE_ACTIVE7
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVE9, 0, 0}, // S_QUAKE_ACTIVE8
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVE0, 0, 0}, // S_QUAKE_ACTIVE9
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEA, 0, 0}, // S_QUAKE_ACTIVE0
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEB, 0, 0}, // S_QUAKE_ACTIVEA
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEC, 0, 0}, // S_QUAKE_ACTIVEB
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVED, 0, 0}, // S_QUAKE_ACTIVEC
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEE, 0, 0}, // S_QUAKE_ACTIVED
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEF, 0, 0}, // S_QUAKE_ACTIVEE
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEG, 0, 0}, // S_QUAKE_ACTIVEF
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEH, 0, 0}, // S_QUAKE_ACTIVEG
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEI, 0, 0}, // S_QUAKE_ACTIVEH
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEJ, 0, 0}, // S_QUAKE_ACTIVEI
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEK, 0, 0}, // S_QUAKE_ACTIVEJ
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEL, 0, 0}, // S_QUAKE_ACTIVEK
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEM, 0, 0}, // S_QUAKE_ACTIVEL
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEN, 0, 0}, // S_QUAKE_ACTIVEM
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEO, 0, 0}, // S_QUAKE_ACTIVEN
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEP, 0, 0}, // S_QUAKE_ACTIVEO
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEQ, 0, 0}, // S_QUAKE_ACTIVEP
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVER, 0, 0}, // S_QUAKE_ACTIVEQ
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVES, 0, 0}, // S_QUAKE_ACTIVER
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVET, 0, 0}, // S_QUAKE_ACTIVES
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEU, 0, 0}, // S_QUAKE_ACTIVET
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEV, 0, 0}, // S_QUAKE_ACTIVEU
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEW, 0, 0}, // S_QUAKE_ACTIVEV
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEX, 0, 0}, // S_QUAKE_ACTIVEW
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEY, 0, 0}, // S_QUAKE_ACTIVEX
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVEZ, 0, 0}, // S_QUAKE_ACTIVEY
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACT1, 0, 0}, // S_QUAKE_ACTIVEZ
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACT2, 0, 0}, // S_QUAKE_ACT1
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACT3, 0, 0}, // S_QUAKE_ACT2
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACT4, 0, 0}, // S_QUAKE_ACT3
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACT5, 0, 0}, // S_QUAKE_ACT4
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACT6, 0, 0}, // S_QUAKE_ACT5
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACT7, 0, 0}, // S_QUAKE_ACT6
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACT8, 0, 0}, // S_QUAKE_ACT7
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACT9, 0, 0}, // S_QUAKE_ACT8
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACT0, 0, 0}, // S_QUAKE_ACT9
+ {SPR_MAN1, 0, 2, A_Quake, S_QUAKE_ACTIVE1, 0, 0}, // S_QUAKE_ACT0
+ {SPR_SGSA, 0, 4, NULL, S_SGSHARD1_2, 0, 0}, // S_SGSHARD1_1
+ {SPR_SGSA, 1, 4, NULL, S_SGSHARD1_3, 0, 0}, // S_SGSHARD1_2
+ {SPR_SGSA, 2, 4, NULL, S_SGSHARD1_4, 0, 0}, // S_SGSHARD1_3
+ {SPR_SGSA, 3, 4, NULL, S_SGSHARD1_5, 0, 0}, // S_SGSHARD1_4
+ {SPR_SGSA, 4, 4, NULL, S_SGSHARD1_1, 0, 0}, // S_SGSHARD1_5
+ {SPR_SGSA, 4, 30, NULL, S_NULL, 0, 0}, // S_SGSHARD1_D
+ {SPR_SGSA, 5, 4, NULL, S_SGSHARD2_2, 0, 0}, // S_SGSHARD2_1
+ {SPR_SGSA, 6, 4, NULL, S_SGSHARD2_3, 0, 0}, // S_SGSHARD2_2
+ {SPR_SGSA, 7, 4, NULL, S_SGSHARD2_4, 0, 0}, // S_SGSHARD2_3
+ {SPR_SGSA, 8, 4, NULL, S_SGSHARD2_5, 0, 0}, // S_SGSHARD2_4
+ {SPR_SGSA, 9, 4, NULL, S_SGSHARD2_1, 0, 0}, // S_SGSHARD2_5
+ {SPR_SGSA, 9, 30, NULL, S_NULL, 0, 0}, // S_SGSHARD2_D
+ {SPR_SGSA, 10, 4, NULL, S_SGSHARD3_2, 0, 0}, // S_SGSHARD3_1
+ {SPR_SGSA, 11, 4, NULL, S_SGSHARD3_3, 0, 0}, // S_SGSHARD3_2
+ {SPR_SGSA, 12, 4, NULL, S_SGSHARD3_4, 0, 0}, // S_SGSHARD3_3
+ {SPR_SGSA, 13, 4, NULL, S_SGSHARD3_5, 0, 0}, // S_SGSHARD3_4
+ {SPR_SGSA, 14, 4, NULL, S_SGSHARD3_1, 0, 0}, // S_SGSHARD3_5
+ {SPR_SGSA, 14, 30, NULL, S_NULL, 0, 0}, // S_SGSHARD3_D
+ {SPR_SGSA, 15, 4, NULL, S_SGSHARD4_2, 0, 0}, // S_SGSHARD4_1
+ {SPR_SGSA, 16, 4, NULL, S_SGSHARD4_3, 0, 0}, // S_SGSHARD4_2
+ {SPR_SGSA, 17, 4, NULL, S_SGSHARD4_4, 0, 0}, // S_SGSHARD4_3
+ {SPR_SGSA, 18, 4, NULL, S_SGSHARD4_5, 0, 0}, // S_SGSHARD4_4
+ {SPR_SGSA, 19, 4, NULL, S_SGSHARD4_1, 0, 0}, // S_SGSHARD4_5
+ {SPR_SGSA, 19, 30, NULL, S_NULL, 0, 0}, // S_SGSHARD4_D
+ {SPR_SGSA, 20, 4, NULL, S_SGSHARD5_2, 0, 0}, // S_SGSHARD5_1
+ {SPR_SGSA, 21, 4, NULL, S_SGSHARD5_3, 0, 0}, // S_SGSHARD5_2
+ {SPR_SGSA, 22, 4, NULL, S_SGSHARD5_4, 0, 0}, // S_SGSHARD5_3
+ {SPR_SGSA, 23, 4, NULL, S_SGSHARD5_5, 0, 0}, // S_SGSHARD5_4
+ {SPR_SGSA, 24, 4, NULL, S_SGSHARD5_1, 0, 0}, // S_SGSHARD5_5
+ {SPR_SGSA, 24, 30, NULL, S_NULL, 0, 0}, // S_SGSHARD5_D
+ {SPR_SGSB, 0, 4, NULL, S_SGSHARD6_1, 0, 0}, // S_SGSHARD6_1
+ {SPR_SGSB, 0, 30, NULL, S_NULL, 0, 0}, // S_SGSHARD6_D
+ {SPR_SGSB, 1, 4, NULL, S_SGSHARD7_1, 0, 0}, // S_SGSHARD7_1
+ {SPR_SGSB, 1, 30, NULL, S_NULL, 0, 0}, // S_SGSHARD7_D
+ {SPR_SGSB, 2, 4, NULL, S_SGSHARD8_1, 0, 0}, // S_SGSHARD8_1
+ {SPR_SGSB, 2, 30, NULL, S_NULL, 0, 0}, // S_SGSHARD8_D
+ {SPR_SGSB, 3, 4, NULL, S_SGSHARD9_1, 0, 0}, // S_SGSHARD9_1
+ {SPR_SGSB, 3, 30, NULL, S_NULL, 0, 0}, // S_SGSHARD9_D
+ {SPR_SGSB, 4, 4, NULL, S_SGSHARD0_1, 0, 0}, // S_SGSHARD0_1
+ {SPR_SGSB, 4, 30, NULL, S_NULL, 0, 0}, // S_SGSHARD0_D
+ {SPR_PORK, 0, 5, NULL, S_ARTI_EGGC2, 0, 0}, // S_ARTI_EGGC1
+ {SPR_PORK, 1, 5, NULL, S_ARTI_EGGC3, 0, 0}, // S_ARTI_EGGC2
+ {SPR_PORK, 2, 5, NULL, S_ARTI_EGGC4, 0, 0}, // S_ARTI_EGGC3
+ {SPR_PORK, 3, 5, NULL, S_ARTI_EGGC5, 0, 0}, // S_ARTI_EGGC4
+ {SPR_PORK, 4, 5, NULL, S_ARTI_EGGC6, 0, 0}, // S_ARTI_EGGC5
+ {SPR_PORK, 5, 5, NULL, S_ARTI_EGGC7, 0, 0}, // S_ARTI_EGGC6
+ {SPR_PORK, 6, 5, NULL, S_ARTI_EGGC8, 0, 0}, // S_ARTI_EGGC7
+ {SPR_PORK, 7, 5, NULL, S_ARTI_EGGC1, 0, 0}, // S_ARTI_EGGC8
+ {SPR_EGGM, 0, 4, NULL, S_EGGFX2, 0, 0}, // S_EGGFX1
+ {SPR_EGGM, 1, 4, NULL, S_EGGFX3, 0, 0}, // S_EGGFX2
+ {SPR_EGGM, 2, 4, NULL, S_EGGFX4, 0, 0}, // S_EGGFX3
+ {SPR_EGGM, 3, 4, NULL, S_EGGFX5, 0, 0}, // S_EGGFX4
+ {SPR_EGGM, 4, 4, NULL, S_EGGFX1, 0, 0}, // S_EGGFX5
+ {SPR_FHFX, 32776, 3, NULL, S_EGGFXI1_2, 0, 0}, // S_EGGFXI1_1
+ {SPR_FHFX, 32777, 3, NULL, S_EGGFXI1_3, 0, 0}, // S_EGGFXI1_2
+ {SPR_FHFX, 32778, 3, NULL, S_EGGFXI1_4, 0, 0}, // S_EGGFXI1_3
+ {SPR_FHFX, 32779, 3, NULL, S_NULL, 0, 0}, // S_EGGFXI1_4
+ {SPR_SPHL, 0, 350, NULL, S_ARTI_SPHL1, 0, 0}, // S_ARTI_SPHL1
+ {SPR_STWN, 0, -1, NULL, S_NULL, 0, 0}, // S_ZWINGEDSTATUENOSKULL
+ {SPR_STWN, 1, -1, NULL, S_NULL, 0, 0}, // S_ZWINGEDSTATUENOSKULL2
+ {SPR_GMPD, 0, -1, NULL, S_NULL, 0, 0}, // S_ZGEMPEDESTAL1
+ {SPR_GMPD, 1, -1, NULL, S_NULL, 0, 0}, // S_ZGEMPEDESTAL2
+ {SPR_ASKU, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTIPUZZSKULL
+ {SPR_ABGM, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTIPUZZGEMBIG
+ {SPR_AGMR, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTIPUZZGEMRED
+ {SPR_AGMG, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTIPUZZGEMGREEN1
+ {SPR_AGG2, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTIPUZZGEMGREEN2
+ {SPR_AGMB, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTIPUZZGEMBLUE1
+ {SPR_AGB2, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTIPUZZGEMBLUE2
+ {SPR_ABK1, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTIPUZZBOOK1
+ {SPR_ABK2, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTIPUZZBOOK2
+ {SPR_ASK2, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTIPUZZSKULL2
+ {SPR_AFWP, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTIPUZZFWEAPON
+ {SPR_ACWP, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTIPUZZCWEAPON
+ {SPR_AMWP, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTIPUZZMWEAPON
+ {SPR_AGER, 32768, 4, NULL, S_ARTIPUZZGEAR_2, 0, 0}, // S_ARTIPUZZGEAR_1
+ {SPR_AGER, 32769, 4, NULL, S_ARTIPUZZGEAR_3, 0, 0}, // S_ARTIPUZZGEAR_2
+ {SPR_AGER, 32770, 4, NULL, S_ARTIPUZZGEAR_4, 0, 0}, // S_ARTIPUZZGEAR_3
+ {SPR_AGER, 32771, 4, NULL, S_ARTIPUZZGEAR_5, 0, 0}, // S_ARTIPUZZGEAR_4
+ {SPR_AGER, 32772, 4, NULL, S_ARTIPUZZGEAR_6, 0, 0}, // S_ARTIPUZZGEAR_5
+ {SPR_AGER, 32773, 4, NULL, S_ARTIPUZZGEAR_7, 0, 0}, // S_ARTIPUZZGEAR_6
+ {SPR_AGER, 32774, 4, NULL, S_ARTIPUZZGEAR_8, 0, 0}, // S_ARTIPUZZGEAR_7
+ {SPR_AGER, 32775, 4, NULL, S_ARTIPUZZGEAR_1, 0, 0}, // S_ARTIPUZZGEAR_8
+ {SPR_AGR2, 32768, 4, NULL, S_ARTIPUZZGEAR2_2, 0, 0}, // S_ARTIPUZZGEAR2_1
+ {SPR_AGR2, 32769, 4, NULL, S_ARTIPUZZGEAR2_3, 0, 0}, // S_ARTIPUZZGEAR2_2
+ {SPR_AGR2, 32770, 4, NULL, S_ARTIPUZZGEAR2_4, 0, 0}, // S_ARTIPUZZGEAR2_3
+ {SPR_AGR2, 32771, 4, NULL, S_ARTIPUZZGEAR2_5, 0, 0}, // S_ARTIPUZZGEAR2_4
+ {SPR_AGR2, 32772, 4, NULL, S_ARTIPUZZGEAR2_6, 0, 0}, // S_ARTIPUZZGEAR2_5
+ {SPR_AGR2, 32773, 4, NULL, S_ARTIPUZZGEAR2_7, 0, 0}, // S_ARTIPUZZGEAR2_6
+ {SPR_AGR2, 32774, 4, NULL, S_ARTIPUZZGEAR2_8, 0, 0}, // S_ARTIPUZZGEAR2_7
+ {SPR_AGR2, 32775, 4, NULL, S_ARTIPUZZGEAR2_1, 0, 0}, // S_ARTIPUZZGEAR2_8
+ {SPR_AGR3, 32768, 4, NULL, S_ARTIPUZZGEAR3_2, 0, 0}, // S_ARTIPUZZGEAR3_1
+ {SPR_AGR3, 32769, 4, NULL, S_ARTIPUZZGEAR3_3, 0, 0}, // S_ARTIPUZZGEAR3_2
+ {SPR_AGR3, 32770, 4, NULL, S_ARTIPUZZGEAR3_4, 0, 0}, // S_ARTIPUZZGEAR3_3
+ {SPR_AGR3, 32771, 4, NULL, S_ARTIPUZZGEAR3_5, 0, 0}, // S_ARTIPUZZGEAR3_4
+ {SPR_AGR3, 32772, 4, NULL, S_ARTIPUZZGEAR3_6, 0, 0}, // S_ARTIPUZZGEAR3_5
+ {SPR_AGR3, 32773, 4, NULL, S_ARTIPUZZGEAR3_7, 0, 0}, // S_ARTIPUZZGEAR3_6
+ {SPR_AGR3, 32774, 4, NULL, S_ARTIPUZZGEAR3_8, 0, 0}, // S_ARTIPUZZGEAR3_7
+ {SPR_AGR3, 32775, 4, NULL, S_ARTIPUZZGEAR3_1, 0, 0}, // S_ARTIPUZZGEAR3_8
+ {SPR_AGR4, 32768, 4, NULL, S_ARTIPUZZGEAR4_2, 0, 0}, // S_ARTIPUZZGEAR4_1
+ {SPR_AGR4, 32769, 4, NULL, S_ARTIPUZZGEAR4_3, 0, 0}, // S_ARTIPUZZGEAR4_2
+ {SPR_AGR4, 32770, 4, NULL, S_ARTIPUZZGEAR4_4, 0, 0}, // S_ARTIPUZZGEAR4_3
+ {SPR_AGR4, 32771, 4, NULL, S_ARTIPUZZGEAR4_5, 0, 0}, // S_ARTIPUZZGEAR4_4
+ {SPR_AGR4, 32772, 4, NULL, S_ARTIPUZZGEAR4_6, 0, 0}, // S_ARTIPUZZGEAR4_5
+ {SPR_AGR4, 32773, 4, NULL, S_ARTIPUZZGEAR4_7, 0, 0}, // S_ARTIPUZZGEAR4_6
+ {SPR_AGR4, 32774, 4, NULL, S_ARTIPUZZGEAR4_8, 0, 0}, // S_ARTIPUZZGEAR4_7
+ {SPR_AGR4, 32775, 4, NULL, S_ARTIPUZZGEAR4_1, 0, 0}, // S_ARTIPUZZGEAR4_8
+ {SPR_TRCH, 32768, 3, NULL, S_ARTI_TRCH2, 0, 0}, // S_ARTI_TRCH1
+ {SPR_TRCH, 32769, 3, NULL, S_ARTI_TRCH3, 0, 0}, // S_ARTI_TRCH2
+ {SPR_TRCH, 32770, 3, NULL, S_ARTI_TRCH1, 0, 0}, // S_ARTI_TRCH3
+ {SPR_PSBG, 0, 20, NULL, S_FIREBOMB2, 0, 0}, // S_FIREBOMB1
+ {SPR_PSBG, 0, 10, NULL, S_FIREBOMB3, 0, 0}, // S_FIREBOMB2
+ {SPR_PSBG, 0, 10, NULL, S_FIREBOMB4, 0, 0}, // S_FIREBOMB3
+ {SPR_PSBG, 1, 4, NULL, S_FIREBOMB5, 0, 0}, // S_FIREBOMB4
+ {SPR_PSBG, 2, 4, A_Scream, S_FIREBOMB6, 0, 0}, // S_FIREBOMB5
+ {SPR_XPL1, 32768, 4, A_Explode, S_FIREBOMB7, 0, 0}, // S_FIREBOMB6
+ {SPR_XPL1, 32769, 4, NULL, S_FIREBOMB8, 0, 0}, // S_FIREBOMB7
+ {SPR_XPL1, 32770, 4, NULL, S_FIREBOMB9, 0, 0}, // S_FIREBOMB8
+ {SPR_XPL1, 32771, 4, NULL, S_FIREBOMB10, 0, 0}, // S_FIREBOMB9
+ {SPR_XPL1, 32772, 4, NULL, S_FIREBOMB11, 0, 0}, // S_FIREBOMB10
+ {SPR_XPL1, 32773, 4, NULL, S_NULL, 0, 0}, // S_FIREBOMB11
+ {SPR_ATLP, 0, 4, NULL, S_ARTI_ATLP2, 0, 0}, // S_ARTI_ATLP1
+ {SPR_ATLP, 1, 4, NULL, S_ARTI_ATLP3, 0, 0}, // S_ARTI_ATLP2
+ {SPR_ATLP, 2, 4, NULL, S_ARTI_ATLP4, 0, 0}, // S_ARTI_ATLP3
+ {SPR_ATLP, 1, 4, NULL, S_ARTI_ATLP1, 0, 0}, // S_ARTI_ATLP4
+ {SPR_PSBG, 0, -1, NULL, S_NULL, 0, 0}, // S_ARTI_PSBG1
+ {SPR_PSBG, 32768, 18, NULL, S_POISONBAG2, 0, 0}, // S_POISONBAG1
+ {SPR_PSBG, 32769, 4, NULL, S_POISONBAG3, 0, 0}, // S_POISONBAG2
+ {SPR_PSBG, 2, 3, NULL, S_POISONBAG4, 0, 0}, // S_POISONBAG3
+ {SPR_PSBG, 2, 1, A_PoisonBagInit, S_NULL, 0, 0}, // S_POISONBAG4
+ {SPR_PSBG, 3, 1, NULL, S_POISONCLOUD2, 0, 0}, // S_POISONCLOUD1
+ {SPR_PSBG, 3, 1, A_Scream, S_POISONCLOUD3, 0, 0}, // S_POISONCLOUD2
+ {SPR_PSBG, 3, 2, A_PoisonBagDamage, S_POISONCLOUD4, 0, 0}, // S_POISONCLOUD3
+ {SPR_PSBG, 4, 2, A_PoisonBagDamage, S_POISONCLOUD5, 0, 0}, // S_POISONCLOUD4
+ {SPR_PSBG, 4, 2, A_PoisonBagDamage, S_POISONCLOUD6, 0, 0}, // S_POISONCLOUD5
+ {SPR_PSBG, 4, 2, A_PoisonBagDamage, S_POISONCLOUD7, 0, 0}, // S_POISONCLOUD6
+ {SPR_PSBG, 5, 2, A_PoisonBagDamage, S_POISONCLOUD8, 0, 0}, // S_POISONCLOUD7
+ {SPR_PSBG, 5, 2, A_PoisonBagDamage, S_POISONCLOUD9, 0, 0}, // S_POISONCLOUD8
+ {SPR_PSBG, 5, 2, A_PoisonBagDamage, S_POISONCLOUD10, 0, 0}, // S_POISONCLOUD9
+ {SPR_PSBG, 6, 2, A_PoisonBagDamage, S_POISONCLOUD11, 0, 0}, // S_POISONCLOUD10
+ {SPR_PSBG, 6, 2, A_PoisonBagDamage, S_POISONCLOUD12, 0, 0}, // S_POISONCLOUD11
+ {SPR_PSBG, 6, 2, A_PoisonBagDamage, S_POISONCLOUD13, 0, 0}, // S_POISONCLOUD12
+ {SPR_PSBG, 7, 2, A_PoisonBagDamage, S_POISONCLOUD14, 0, 0}, // S_POISONCLOUD13
+ {SPR_PSBG, 7, 2, A_PoisonBagDamage, S_POISONCLOUD15, 0, 0}, // S_POISONCLOUD14
+ {SPR_PSBG, 7, 2, A_PoisonBagDamage, S_POISONCLOUD16, 0, 0}, // S_POISONCLOUD15
+ {SPR_PSBG, 8, 2, A_PoisonBagDamage, S_POISONCLOUD17, 0, 0}, // S_POISONCLOUD16
+ {SPR_PSBG, 8, 1, A_PoisonBagDamage, S_POISONCLOUD18, 0, 0}, // S_POISONCLOUD17
+ {SPR_PSBG, 8, 1, A_PoisonBagCheck, S_POISONCLOUD4, 0, 0}, // S_POISONCLOUD18
+ {SPR_PSBG, 7, 7, NULL, S_POISONCLOUD_X2, 0, 0}, // S_POISONCLOUD_X1
+ {SPR_PSBG, 6, 7, NULL, S_POISONCLOUD_X3, 0, 0}, // S_POISONCLOUD_X2
+ {SPR_PSBG, 5, 6, NULL, S_POISONCLOUD_X4, 0, 0}, // S_POISONCLOUD_X3
+ {SPR_PSBG, 3, 6, NULL, S_NULL, 0, 0}, // S_POISONCLOUD_X4
+ {SPR_THRW, 0, 4, A_CheckThrowBomb, S_THROWINGBOMB2, 0, 0}, // S_THROWINGBOMB1
+ {SPR_THRW, 1, 3, A_CheckThrowBomb, S_THROWINGBOMB3, 0, 0}, // S_THROWINGBOMB2
+ {SPR_THRW, 2, 3, A_CheckThrowBomb, S_THROWINGBOMB4, 0, 0}, // S_THROWINGBOMB3
+ {SPR_THRW, 3, 3, A_CheckThrowBomb, S_THROWINGBOMB5, 0, 0}, // S_THROWINGBOMB4
+ {SPR_THRW, 4, 3, A_CheckThrowBomb, S_THROWINGBOMB6, 0, 0}, // S_THROWINGBOMB5
+ {SPR_THRW, 5, 3, A_CheckThrowBomb, S_THROWINGBOMB1, 0, 0}, // S_THROWINGBOMB6
+ {SPR_THRW, 6, 6, A_CheckThrowBomb, S_THROWINGBOMB8, 0, 0}, // S_THROWINGBOMB7
+ {SPR_THRW, 5, 4, A_CheckThrowBomb, S_THROWINGBOMB9, 0, 0}, // S_THROWINGBOMB8
+ {SPR_THRW, 7, 6, A_CheckThrowBomb, S_THROWINGBOMB10, 0, 0}, // S_THROWINGBOMB9
+ {SPR_THRW, 5, 4, A_CheckThrowBomb, S_THROWINGBOMB11, 0, 0}, // S_THROWINGBOMB10
+ {SPR_THRW, 6, 6, A_CheckThrowBomb, S_THROWINGBOMB12, 0, 0}, // S_THROWINGBOMB11
+ {SPR_THRW, 5, 3, A_CheckThrowBomb, S_THROWINGBOMB12, 0, 0}, // S_THROWINGBOMB12
+ {SPR_CFCF, 32784, 4, A_NoGravity, S_THROWINGBOMB_X2, 0, 0}, // S_THROWINGBOMB_X1
+ {SPR_CFCF, 32785, 3, A_Scream, S_THROWINGBOMB_X3, 0, 0}, // S_THROWINGBOMB_X2
+ {SPR_CFCF, 32786, 4, A_Explode, S_THROWINGBOMB_X4, 0, 0}, // S_THROWINGBOMB_X3
+ {SPR_CFCF, 32787, 3, NULL, S_THROWINGBOMB_X5, 0, 0}, // S_THROWINGBOMB_X4
+ {SPR_CFCF, 32788, 4, NULL, S_THROWINGBOMB_X6, 0, 0}, // S_THROWINGBOMB_X5
+ {SPR_CFCF, 32790, 3, NULL, S_THROWINGBOMB_X7, 0, 0}, // S_THROWINGBOMB_X6
+ {SPR_CFCF, 32791, 4, NULL, S_THROWINGBOMB_X8, 0, 0}, // S_THROWINGBOMB_X7
+ {SPR_CFCF, 32793, 3, NULL, S_NULL, 0, 0}, // S_THROWINGBOMB_X8
+ {SPR_SPED, 32768, 3, NULL, S_ARTI_BOOTS2, 0, 0}, // S_ARTI_BOOTS1
+ {SPR_SPED, 32769, 3, NULL, S_ARTI_BOOTS3, 0, 0}, // S_ARTI_BOOTS2
+ {SPR_SPED, 32770, 3, NULL, S_ARTI_BOOTS4, 0, 0}, // S_ARTI_BOOTS3
+ {SPR_SPED, 32771, 3, NULL, S_ARTI_BOOTS5, 0, 0}, // S_ARTI_BOOTS4
+ {SPR_SPED, 32772, 3, NULL, S_ARTI_BOOTS6, 0, 0}, // S_ARTI_BOOTS5
+ {SPR_SPED, 32773, 3, NULL, S_ARTI_BOOTS7, 0, 0}, // S_ARTI_BOOTS6
+ {SPR_SPED, 32774, 3, NULL, S_ARTI_BOOTS8, 0, 0}, // S_ARTI_BOOTS7
+ {SPR_SPED, 32775, 3, NULL, S_ARTI_BOOTS1, 0, 0}, // S_ARTI_BOOTS8
+ {SPR_BMAN, 32768, -1, NULL, S_NULL, 0, 0}, // S_ARTI_MANA
+ {SPR_BRAC, 32768, 4, NULL, S_ARTI_ARMOR2, 0, 0}, // S_ARTI_ARMOR1
+ {SPR_BRAC, 32769, 4, NULL, S_ARTI_ARMOR3, 0, 0}, // S_ARTI_ARMOR2
+ {SPR_BRAC, 32770, 4, NULL, S_ARTI_ARMOR4, 0, 0}, // S_ARTI_ARMOR3
+ {SPR_BRAC, 32771, 4, NULL, S_ARTI_ARMOR5, 0, 0}, // S_ARTI_ARMOR4
+ {SPR_BRAC, 32772, 4, NULL, S_ARTI_ARMOR6, 0, 0}, // S_ARTI_ARMOR5
+ {SPR_BRAC, 32773, 4, NULL, S_ARTI_ARMOR7, 0, 0}, // S_ARTI_ARMOR6
+ {SPR_BRAC, 32774, 4, NULL, S_ARTI_ARMOR8, 0, 0}, // S_ARTI_ARMOR7
+ {SPR_BRAC, 32775, 4, NULL, S_ARTI_ARMOR1, 0, 0}, // S_ARTI_ARMOR8
+ {SPR_BLST, 32768, 4, NULL, S_ARTI_BLAST2, 0, 0}, // S_ARTI_BLAST1
+ {SPR_BLST, 32769, 4, NULL, S_ARTI_BLAST3, 0, 0}, // S_ARTI_BLAST2
+ {SPR_BLST, 32770, 4, NULL, S_ARTI_BLAST4, 0, 0}, // S_ARTI_BLAST3
+ {SPR_BLST, 32771, 4, NULL, S_ARTI_BLAST5, 0, 0}, // S_ARTI_BLAST4
+ {SPR_BLST, 32772, 4, NULL, S_ARTI_BLAST6, 0, 0}, // S_ARTI_BLAST5
+ {SPR_BLST, 32773, 4, NULL, S_ARTI_BLAST7, 0, 0}, // S_ARTI_BLAST6
+ {SPR_BLST, 32774, 4, NULL, S_ARTI_BLAST8, 0, 0}, // S_ARTI_BLAST7
+ {SPR_BLST, 32775, 4, NULL, S_ARTI_BLAST1, 0, 0}, // S_ARTI_BLAST8
+ {SPR_HRAD, 32768, 4, NULL, S_ARTI_HEALRAD2, 0, 0}, // S_ARTI_HEALRAD1
+ {SPR_HRAD, 32769, 4, NULL, S_ARTI_HEALRAD3, 0, 0}, // S_ARTI_HEALRAD2
+ {SPR_HRAD, 32770, 4, NULL, S_ARTI_HEALRAD4, 0, 0}, // S_ARTI_HEALRAD3
+ {SPR_HRAD, 32771, 4, NULL, S_ARTI_HEALRAD5, 0, 0}, // S_ARTI_HEALRAD4
+ {SPR_HRAD, 32772, 4, NULL, S_ARTI_HEALRAD6, 0, 0}, // S_ARTI_HEALRAD5
+ {SPR_HRAD, 32773, 4, NULL, S_ARTI_HEALRAD7, 0, 0}, // S_ARTI_HEALRAD6
+ {SPR_HRAD, 32774, 4, NULL, S_ARTI_HEALRAD8, 0, 0}, // S_ARTI_HEALRAD7
+ {SPR_HRAD, 32775, 4, NULL, S_ARTI_HEALRAD9, 0, 0}, // S_ARTI_HEALRAD8
+ {SPR_HRAD, 32776, 4, NULL, S_ARTI_HEALRAD0, 0, 0}, // S_ARTI_HEALRAD9
+ {SPR_HRAD, 32777, 4, NULL, S_ARTI_HEALRADA, 0, 0}, // S_ARTI_HEALRAD0
+ {SPR_HRAD, 32778, 4, NULL, S_ARTI_HEALRADB, 0, 0}, // S_ARTI_HEALRADA
+ {SPR_HRAD, 32779, 4, NULL, S_ARTI_HEALRADC, 0, 0}, // S_ARTI_HEALRADB
+ {SPR_HRAD, 32780, 4, NULL, S_ARTI_HEALRADD, 0, 0}, // S_ARTI_HEALRADC
+ {SPR_HRAD, 32781, 4, NULL, S_ARTI_HEALRADE, 0, 0}, // S_ARTI_HEALRADD
+ {SPR_HRAD, 32782, 4, NULL, S_ARTI_HEALRADF, 0, 0}, // S_ARTI_HEALRADE
+ {SPR_HRAD, 32783, 4, NULL, S_ARTI_HEALRAD1, 0, 0}, // S_ARTI_HEALRADF
+ {SPR_SPSH, 0, 8, NULL, S_SPLASH2, 0, 0}, // S_SPLASH1
+ {SPR_SPSH, 1, 8, NULL, S_SPLASH3, 0, 0}, // S_SPLASH2
+ {SPR_SPSH, 2, 8, NULL, S_SPLASH4, 0, 0}, // S_SPLASH3
+ {SPR_SPSH, 3, 16, NULL, S_NULL, 0, 0}, // S_SPLASH4
+ {SPR_SPSH, 3, 10, NULL, S_NULL, 0, 0}, // S_SPLASHX
+ {SPR_SPSH, 4, 5, NULL, S_SPLASHBASE2, 0, 0}, // S_SPLASHBASE1
+ {SPR_SPSH, 5, 5, NULL, S_SPLASHBASE3, 0, 0}, // S_SPLASHBASE2
+ {SPR_SPSH, 6, 5, NULL, S_SPLASHBASE4, 0, 0}, // S_SPLASHBASE3
+ {SPR_SPSH, 7, 5, NULL, S_SPLASHBASE5, 0, 0}, // S_SPLASHBASE4
+ {SPR_SPSH, 8, 5, NULL, S_SPLASHBASE6, 0, 0}, // S_SPLASHBASE5
+ {SPR_SPSH, 9, 5, NULL, S_SPLASHBASE7, 0, 0}, // S_SPLASHBASE6
+ {SPR_SPSH, 10, 5, NULL, S_NULL, 0, 0}, // S_SPLASHBASE7
+ {SPR_LVAS, 32768, 5, NULL, S_LAVASPLASH2, 0, 0}, // S_LAVASPLASH1
+ {SPR_LVAS, 32769, 5, NULL, S_LAVASPLASH3, 0, 0}, // S_LAVASPLASH2
+ {SPR_LVAS, 32770, 5, NULL, S_LAVASPLASH4, 0, 0}, // S_LAVASPLASH3
+ {SPR_LVAS, 32771, 5, NULL, S_LAVASPLASH5, 0, 0}, // S_LAVASPLASH4
+ {SPR_LVAS, 32772, 5, NULL, S_LAVASPLASH6, 0, 0}, // S_LAVASPLASH5
+ {SPR_LVAS, 32773, 5, NULL, S_NULL, 0, 0}, // S_LAVASPLASH6
+ {SPR_LVAS, 32774, 5, NULL, S_LAVASMOKE2, 0, 0}, // S_LAVASMOKE1
+ {SPR_LVAS, 32775, 5, NULL, S_LAVASMOKE3, 0, 0}, // S_LAVASMOKE2
+ {SPR_LVAS, 32776, 5, NULL, S_LAVASMOKE4, 0, 0}, // S_LAVASMOKE3
+ {SPR_LVAS, 32777, 5, NULL, S_LAVASMOKE5, 0, 0}, // S_LAVASMOKE4
+ {SPR_LVAS, 32778, 5, NULL, S_NULL, 0, 0}, // S_LAVASMOKE5
+ {SPR_SLDG, 0, 8, NULL, S_SLUDGECHUNK2, 0, 0}, // S_SLUDGECHUNK1
+ {SPR_SLDG, 1, 8, NULL, S_SLUDGECHUNK3, 0, 0}, // S_SLUDGECHUNK2
+ {SPR_SLDG, 2, 8, NULL, S_SLUDGECHUNK4, 0, 0}, // S_SLUDGECHUNK3
+ {SPR_SLDG, 3, 8, NULL, S_NULL, 0, 0}, // S_SLUDGECHUNK4
+ {SPR_SLDG, 3, 6, NULL, S_NULL, 0, 0}, // S_SLUDGECHUNKX
+ {SPR_SLDG, 4, 6, NULL, S_SLUDGESPLASH2, 0, 0}, // S_SLUDGESPLASH1
+ {SPR_SLDG, 5, 6, NULL, S_SLUDGESPLASH3, 0, 0}, // S_SLUDGESPLASH2
+ {SPR_SLDG, 6, 6, NULL, S_SLUDGESPLASH4, 0, 0}, // S_SLUDGESPLASH3
+ {SPR_SLDG, 7, 6, NULL, S_NULL, 0, 0}, // S_SLUDGESPLASH4
+ {SPR_STTW, 0, -1, NULL, S_NULL, 0, 0}, // S_ZWINGEDSTATUE1
+ {SPR_RCK1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZROCK1_1
+ {SPR_RCK2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZROCK2_1
+ {SPR_RCK3, 0, -1, NULL, S_NULL, 0, 0}, // S_ZROCK3_1
+ {SPR_RCK4, 0, -1, NULL, S_NULL, 0, 0}, // S_ZROCK4_1
+ {SPR_CDLR, 0, 4, NULL, S_ZCHANDELIER2, 0, 0}, // S_ZCHANDELIER1
+ {SPR_CDLR, 1, 4, NULL, S_ZCHANDELIER3, 0, 0}, // S_ZCHANDELIER2
+ {SPR_CDLR, 2, 4, NULL, S_ZCHANDELIER1, 0, 0}, // S_ZCHANDELIER3
+ {SPR_CDLR, 3, -1, NULL, S_NULL, 0, 0}, // S_ZCHANDELIER_U
+ {SPR_TRE1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTREEDEAD1
+ {SPR_TRE1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTREE
+ {SPR_TRDT, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTREEDESTRUCTIBLE1
+ {SPR_TRDT, 1, 5, NULL, S_ZTREEDES_D2, 0, 0}, // S_ZTREEDES_D1
+ {SPR_TRDT, 2, 5, A_Scream, S_ZTREEDES_D3, 0, 0}, // S_ZTREEDES_D2
+ {SPR_TRDT, 3, 5, NULL, S_ZTREEDES_D4, 0, 0}, // S_ZTREEDES_D3
+ {SPR_TRDT, 4, 5, NULL, S_ZTREEDES_D5, 0, 0}, // S_ZTREEDES_D4
+ {SPR_TRDT, 5, 5, NULL, S_ZTREEDES_D6, 0, 0}, // S_ZTREEDES_D5
+ {SPR_TRDT, 6, -1, NULL, S_NULL, 0, 0}, // S_ZTREEDES_D6
+ {SPR_TRDT, 32775, 5, NULL, S_ZTREEDES_X2, 0, 0}, // S_ZTREEDES_X1
+ {SPR_TRDT, 32776, 5, NULL, S_ZTREEDES_X3, 0, 0}, // S_ZTREEDES_X2
+ {SPR_TRDT, 32777, 5, NULL, S_ZTREEDES_X4, 0, 0}, // S_ZTREEDES_X3
+ {SPR_TRDT, 32778, 5, NULL, S_ZTREEDES_X5, 0, 0}, // S_ZTREEDES_X4
+ {SPR_TRDT, 32779, 5, NULL, S_ZTREEDES_X6, 0, 0}, // S_ZTREEDES_X5
+ {SPR_TRDT, 32780, 5, A_Explode, S_ZTREEDES_X7, 0, 0}, // S_ZTREEDES_X6
+ {SPR_TRDT, 32781, 5, NULL, S_ZTREEDES_X8, 0, 0}, // S_ZTREEDES_X7
+ {SPR_TRDT, 14, 5, NULL, S_ZTREEDES_X9, 0, 0}, // S_ZTREEDES_X8
+ {SPR_TRDT, 15, 5, NULL, S_ZTREEDES_X10, 0, 0}, // S_ZTREEDES_X9
+ {SPR_TRDT, 16, -1, NULL, S_NULL, 0, 0}, // S_ZTREEDES_X10
+ {SPR_TRE2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTREESWAMP182_1
+ {SPR_TRE3, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTREESWAMP172_1
+ {SPR_STM1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTUMPBURNED1
+ {SPR_STM2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTUMPBARE1
+ {SPR_STM3, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTUMPSWAMP1_1
+ {SPR_STM4, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTUMPSWAMP2_1
+ {SPR_MSH1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSHROOMLARGE1_1
+ {SPR_MSH2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSHROOMLARGE2_1
+ {SPR_MSH3, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSHROOMLARGE3_1
+ {SPR_MSH4, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSHROOMSMALL1_1
+ {SPR_MSH5, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSHROOMSMALL2_1
+ {SPR_MSH6, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSHROOMSMALL3_1
+ {SPR_MSH7, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSHROOMSMALL4_1
+ {SPR_MSH8, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSHROOMSMALL5_1
+ {SPR_SGMP, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALAGMITEPILLAR1
+ {SPR_SGM1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALAGMITELARGE1
+ {SPR_SGM2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALAGMITEMEDIUM1
+ {SPR_SGM3, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALAGMITESMALL1
+ {SPR_SLC1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALACTITELARGE1
+ {SPR_SLC2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALACTITEMEDIUM1
+ {SPR_SLC3, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALACTITESMALL1
+ {SPR_MSS1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZMOSSCEILING1_1
+ {SPR_MSS2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZMOSSCEILING2_1
+ {SPR_SWMV, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSWAMPVINE1
+ {SPR_CPS1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZCORPSEKABOB1
+ {SPR_CPS2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZCORPSESLEEPING1
+ {SPR_TMS1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTOMBSTONERIP1
+ {SPR_TMS2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTOMBSTONESHANE1
+ {SPR_TMS3, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTOMBSTONEBIGCROSS1
+ {SPR_TMS4, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTOMBSTONEBRIANR1
+ {SPR_TMS5, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTOMBSTONECROSSCIRCLE1
+ {SPR_TMS6, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTOMBSTONESMALLCROSS1
+ {SPR_TMS7, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTOMBSTONEBRIANP1
+ {SPR_CPS3, 0, -1, NULL, S_NULL, 0, 0}, // S_CORPSEHANGING_1
+ {SPR_STT2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTATUEGARGOYLEGREENTALL_1
+ {SPR_STT3, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTATUEGARGOYLEBLUETALL_1
+ {SPR_STT4, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTATUEGARGOYLEGREENSHORT_1
+ {SPR_STT5, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTATUEGARGOYLEBLUESHORT_1
+ {SPR_GAR1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTATUEGARGOYLESTRIPETALL_1
+ {SPR_GAR2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTATUEGARGOYLEDARKREDTALL_1
+ {SPR_GAR3, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTATUEGARGOYLEREDTALL_1
+ {SPR_GAR4, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTATUEGARGOYLETANTALL_1
+ {SPR_GAR5, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTATUEGARGOYLERUSTTALL_1
+ {SPR_GAR6, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTATUEGARGOYLEDARKREDSHORT_1
+ {SPR_GAR7, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTATUEGARGOYLEREDSHORT_1
+ {SPR_GAR8, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTATUEGARGOYLETANSHORT_1
+ {SPR_GAR9, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTATUEGARGOYLERUSTSHORT_1
+ {SPR_BNR1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZBANNERTATTERED_1
+ {SPR_TRE4, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTREELARGE1
+ {SPR_TRE5, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTREELARGE2
+ {SPR_TRE6, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTREEGNARLED1
+ {SPR_TRE7, 0, -1, NULL, S_NULL, 0, 0}, // S_ZTREEGNARLED2
+ {SPR_LOGG, 0, -1, NULL, S_NULL, 0, 0}, // S_ZLOG
+ {SPR_ICT1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALACTITEICELARGE
+ {SPR_ICT2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALACTITEICEMEDIUM
+ {SPR_ICT3, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALACTITEICESMALL
+ {SPR_ICT4, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALACTITEICETINY
+ {SPR_ICM1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALAGMITEICELARGE
+ {SPR_ICM2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALAGMITEICEMEDIUM
+ {SPR_ICM3, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALAGMITEICESMALL
+ {SPR_ICM4, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSTALAGMITEICETINY
+ {SPR_RKBL, 0, -1, NULL, S_NULL, 0, 0}, // S_ZROCKBROWN1
+ {SPR_RKBS, 0, -1, NULL, S_NULL, 0, 0}, // S_ZROCKBROWN2
+ {SPR_RKBK, 0, -1, NULL, S_NULL, 0, 0}, // S_ZROCKBLACK
+ {SPR_RBL1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZRUBBLE1
+ {SPR_RBL2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZRUBBLE2
+ {SPR_RBL3, 0, -1, NULL, S_NULL, 0, 0}, // S_ZRUBBLE3
+ {SPR_VASE, 0, -1, NULL, S_NULL, 0, 0}, // S_ZVASEPILLAR
+ {SPR_POT1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZPOTTERY1
+ {SPR_POT2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZPOTTERY2
+ {SPR_POT3, 0, -1, NULL, S_NULL, 0, 0}, // S_ZPOTTERY3
+ {SPR_POT1, 0, 0, A_PotteryExplode, S_NULL, 0, 0}, // S_ZPOTTERY_EXPLODE
+ {SPR_PBIT, 0, -1, NULL, S_NULL, 0, 0}, // S_POTTERYBIT_1
+ {SPR_PBIT, 1, -1, NULL, S_NULL, 0, 0}, // S_POTTERYBIT_2
+ {SPR_PBIT, 2, -1, NULL, S_NULL, 0, 0}, // S_POTTERYBIT_3
+ {SPR_PBIT, 3, -1, NULL, S_NULL, 0, 0}, // S_POTTERYBIT_4
+ {SPR_PBIT, 4, -1, NULL, S_NULL, 0, 0}, // S_POTTERYBIT_5
+ {SPR_PBIT, 5, 0, A_PotteryChooseBit, S_NULL, 0, 0}, // S_POTTERYBIT_EX0
+ {SPR_PBIT, 5, 140, NULL, S_POTTERYBIT_EX1_2, 0, 0}, // S_POTTERYBIT_EX1
+ {SPR_PBIT, 5, 1, A_PotteryCheck, S_NULL, 0, 0}, // S_POTTERYBIT_EX1_2
+ {SPR_PBIT, 6, 140, NULL, S_POTTERYBIT_EX2_2, 0, 0}, // S_POTTERYBIT_EX2
+ {SPR_PBIT, 6, 1, A_PotteryCheck, S_NULL, 0, 0}, // S_POTTERYBIT_EX2_2
+ {SPR_PBIT, 7, 140, NULL, S_POTTERYBIT_EX3_2, 0, 0}, // S_POTTERYBIT_EX3
+ {SPR_PBIT, 7, 1, A_PotteryCheck, S_NULL, 0, 0}, // S_POTTERYBIT_EX3_2
+ {SPR_PBIT, 8, 140, NULL, S_POTTERYBIT_EX4_2, 0, 0}, // S_POTTERYBIT_EX4
+ {SPR_PBIT, 8, 1, A_PotteryCheck, S_NULL, 0, 0}, // S_POTTERYBIT_EX4_2
+ {SPR_PBIT, 9, 140, NULL, S_POTTERYBIT_EX5_2, 0, 0}, // S_POTTERYBIT_EX5
+ {SPR_PBIT, 9, 1, A_PotteryCheck, S_NULL, 0, 0}, // S_POTTERYBIT_EX5_2
+ {SPR_CPS4, 0, -1, NULL, S_NULL, 0, 0}, // S_ZCORPSELYNCHED1
+ {SPR_CPS5, 0, 140, A_CorpseBloodDrip, S_ZCORPSELYNCHED2, 0, 0}, // S_ZCORPSELYNCHED2
+ {SPR_CPS6, 0, -1, NULL, S_NULL, 0, 0}, // S_ZCORPSESITTING
+ {SPR_CPS6, 0, 1, A_CorpseExplode, S_NULL, 0, 0}, // S_ZCORPSESITTING_X
+ {SPR_CPB1, 0, -1, NULL, S_NULL, 0, 0}, // S_CORPSEBIT_1
+ {SPR_CPB2, 0, -1, NULL, S_NULL, 0, 0}, // S_CORPSEBIT_2
+ {SPR_CPB3, 0, -1, NULL, S_NULL, 0, 0}, // S_CORPSEBIT_3
+ {SPR_CPB4, 0, -1, NULL, S_NULL, 0, 0}, // S_CORPSEBIT_4
+ {SPR_BDRP, 0, -1, NULL, S_NULL, 0, 0}, // S_CORPSEBLOODDRIP
+ {SPR_BDSH, 0, 3, NULL, S_CORPSEBLOODDRIP_X2, 0, 0}, // S_CORPSEBLOODDRIP_X1
+ {SPR_BDSH, 1, 3, NULL, S_CORPSEBLOODDRIP_X3, 0, 0}, // S_CORPSEBLOODDRIP_X2
+ {SPR_BDSH, 2, 2, NULL, S_CORPSEBLOODDRIP_X4, 0, 0}, // S_CORPSEBLOODDRIP_X3
+ {SPR_BDSH, 3, 2, NULL, S_NULL, 0, 0}, // S_CORPSEBLOODDRIP_X4
+ {SPR_BDPL, 0, -1, NULL, S_NULL, 0, 0}, // S_BLOODPOOL
+ {SPR_CNDL, 32768, 4, NULL, S_ZCANDLE2, 0, 0}, // S_ZCANDLE1
+ {SPR_CNDL, 32769, 4, NULL, S_ZCANDLE3, 0, 0}, // S_ZCANDLE2
+ {SPR_CNDL, 32770, 4, NULL, S_ZCANDLE1, 0, 0}, // S_ZCANDLE3
+ {SPR_MAN1, 0, 20, A_LeafSpawn, S_ZLEAFSPAWNER, 0, 0}, // S_ZLEAFSPAWNER
+ {SPR_LEF1, 0, 4, NULL, S_LEAF1_2, 0, 0}, // S_LEAF1_1
+ {SPR_LEF1, 1, 4, NULL, S_LEAF1_3, 0, 0}, // S_LEAF1_2
+ {SPR_LEF1, 2, 4, NULL, S_LEAF1_4, 0, 0}, // S_LEAF1_3
+ {SPR_LEF1, 3, 4, A_LeafThrust, S_LEAF1_5, 0, 0}, // S_LEAF1_4
+ {SPR_LEF1, 4, 4, NULL, S_LEAF1_6, 0, 0}, // S_LEAF1_5
+ {SPR_LEF1, 5, 4, NULL, S_LEAF1_7, 0, 0}, // S_LEAF1_6
+ {SPR_LEF1, 6, 4, NULL, S_LEAF1_8, 0, 0}, // S_LEAF1_7
+ {SPR_LEF1, 7, 4, A_LeafThrust, S_LEAF1_9, 0, 0}, // S_LEAF1_8
+ {SPR_LEF1, 8, 4, NULL, S_LEAF1_10, 0, 0}, // S_LEAF1_9
+ {SPR_LEF1, 0, 4, NULL, S_LEAF1_11, 0, 0}, // S_LEAF1_10
+ {SPR_LEF1, 1, 4, NULL, S_LEAF1_12, 0, 0}, // S_LEAF1_11
+ {SPR_LEF1, 2, 4, A_LeafThrust, S_LEAF1_13, 0, 0}, // S_LEAF1_12
+ {SPR_LEF1, 3, 4, NULL, S_LEAF1_14, 0, 0}, // S_LEAF1_13
+ {SPR_LEF1, 4, 4, NULL, S_LEAF1_15, 0, 0}, // S_LEAF1_14
+ {SPR_LEF1, 5, 4, NULL, S_LEAF1_16, 0, 0}, // S_LEAF1_15
+ {SPR_LEF1, 6, 4, A_LeafThrust, S_LEAF1_17, 0, 0}, // S_LEAF1_16
+ {SPR_LEF1, 7, 4, NULL, S_LEAF1_18, 0, 0}, // S_LEAF1_17
+ {SPR_LEF1, 8, 4, NULL, S_NULL, 0, 0}, // S_LEAF1_18
+ {SPR_LEF3, 3, 10, A_LeafCheck, S_LEAF_X1, 0, 0}, // S_LEAF_X1
+ {SPR_LEF2, 0, 4, NULL, S_LEAF2_2, 0, 0}, // S_LEAF2_1
+ {SPR_LEF2, 1, 4, NULL, S_LEAF2_3, 0, 0}, // S_LEAF2_2
+ {SPR_LEF2, 2, 4, NULL, S_LEAF2_4, 0, 0}, // S_LEAF2_3
+ {SPR_LEF2, 3, 4, A_LeafThrust, S_LEAF2_5, 0, 0}, // S_LEAF2_4
+ {SPR_LEF2, 4, 4, NULL, S_LEAF2_6, 0, 0}, // S_LEAF2_5
+ {SPR_LEF2, 5, 4, NULL, S_LEAF2_7, 0, 0}, // S_LEAF2_6
+ {SPR_LEF2, 6, 4, NULL, S_LEAF2_8, 0, 0}, // S_LEAF2_7
+ {SPR_LEF2, 7, 4, A_LeafThrust, S_LEAF2_9, 0, 0}, // S_LEAF2_8
+ {SPR_LEF2, 8, 4, NULL, S_LEAF2_10, 0, 0}, // S_LEAF2_9
+ {SPR_LEF2, 0, 4, NULL, S_LEAF2_11, 0, 0}, // S_LEAF2_10
+ {SPR_LEF2, 1, 4, NULL, S_LEAF2_12, 0, 0}, // S_LEAF2_11
+ {SPR_LEF2, 2, 4, A_LeafThrust, S_LEAF2_13, 0, 0}, // S_LEAF2_12
+ {SPR_LEF2, 3, 4, NULL, S_LEAF2_14, 0, 0}, // S_LEAF2_13
+ {SPR_LEF2, 4, 4, NULL, S_LEAF2_15, 0, 0}, // S_LEAF2_14
+ {SPR_LEF2, 5, 4, NULL, S_LEAF2_16, 0, 0}, // S_LEAF2_15
+ {SPR_LEF2, 6, 4, A_LeafThrust, S_LEAF2_17, 0, 0}, // S_LEAF2_16
+ {SPR_LEF2, 7, 4, NULL, S_LEAF2_18, 0, 0}, // S_LEAF2_17
+ {SPR_LEF2, 8, 4, NULL, S_NULL, 0, 0}, // S_LEAF2_18
+ {SPR_TWTR, 32768, 4, NULL, S_ZTWINEDTORCH_2, 0, 0}, // S_ZTWINEDTORCH_1
+ {SPR_TWTR, 32769, 4, NULL, S_ZTWINEDTORCH_3, 0, 0}, // S_ZTWINEDTORCH_2
+ {SPR_TWTR, 32770, 4, NULL, S_ZTWINEDTORCH_4, 0, 0}, // S_ZTWINEDTORCH_3
+ {SPR_TWTR, 32771, 4, NULL, S_ZTWINEDTORCH_5, 0, 0}, // S_ZTWINEDTORCH_4
+ {SPR_TWTR, 32772, 4, NULL, S_ZTWINEDTORCH_6, 0, 0}, // S_ZTWINEDTORCH_5
+ {SPR_TWTR, 32773, 4, NULL, S_ZTWINEDTORCH_7, 0, 0}, // S_ZTWINEDTORCH_6
+ {SPR_TWTR, 32774, 4, NULL, S_ZTWINEDTORCH_8, 0, 0}, // S_ZTWINEDTORCH_7
+ {SPR_TWTR, 32775, 4, NULL, S_ZTWINEDTORCH_1, 0, 0}, // S_ZTWINEDTORCH_8
+ {SPR_TWTR, 8, -1, NULL, S_NULL, 0, 0}, // S_ZTWINEDTORCH_UNLIT
+ {SPR_TLGL, 0, 2, NULL, S_BRIDGE2, 0, 0}, // S_BRIDGE1
+ {SPR_TLGL, 0, 2, A_BridgeInit, S_BRIDGE3, 0, 0}, // S_BRIDGE2
+ {SPR_TLGL, 0, -1, NULL, S_NULL, 0, 0}, // S_BRIDGE3
+ {SPR_TLGL, 0, 2, NULL, S_FREE_BRIDGE2, 0, 0}, // S_FREE_BRIDGE1
+ {SPR_TLGL, 0, 300, NULL, S_NULL, 0, 0}, // S_FREE_BRIDGE2
+ {SPR_TLGL, 0, 2, NULL, S_BBALL2, 0, 0}, // S_BBALL1
+ {SPR_TLGL, 0, 5, A_BridgeOrbit, S_BBALL2, 0, 0}, // S_BBALL2
+ {SPR_WLTR, 32768, 5, NULL, S_ZWALLTORCH2, 0, 0}, // S_ZWALLTORCH1
+ {SPR_WLTR, 32769, 5, NULL, S_ZWALLTORCH3, 0, 0}, // S_ZWALLTORCH2
+ {SPR_WLTR, 32770, 5, NULL, S_ZWALLTORCH4, 0, 0}, // S_ZWALLTORCH3
+ {SPR_WLTR, 32771, 5, NULL, S_ZWALLTORCH5, 0, 0}, // S_ZWALLTORCH4
+ {SPR_WLTR, 32772, 5, NULL, S_ZWALLTORCH6, 0, 0}, // S_ZWALLTORCH5
+ {SPR_WLTR, 32773, 5, NULL, S_ZWALLTORCH7, 0, 0}, // S_ZWALLTORCH6
+ {SPR_WLTR, 32774, 5, NULL, S_ZWALLTORCH8, 0, 0}, // S_ZWALLTORCH7
+ {SPR_WLTR, 32775, 5, NULL, S_ZWALLTORCH1, 0, 0}, // S_ZWALLTORCH8
+ {SPR_WLTR, 8, -1, NULL, S_NULL, 0, 0}, // S_ZWALLTORCH_U
+ {SPR_BARL, 0, -1, NULL, S_NULL, 0, 0}, // S_ZBARREL1
+ {SPR_SHB1, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSHRUB1
+ {SPR_SHB1, 0, 1, A_TreeDeath, S_ZSHRUB1, 0, 0}, // S_ZSHRUB1_DIE
+ {SPR_SHB1, 32769, 7, NULL, S_ZSHRUB1_X2, 0, 0}, // S_ZSHRUB1_X1
+ {SPR_SHB1, 32770, 6, A_Scream, S_ZSHRUB1_X3, 0, 0}, // S_ZSHRUB1_X2
+ {SPR_SHB1, 32771, 5, NULL, S_NULL, 0, 0}, // S_ZSHRUB1_X3
+ {SPR_SHB2, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSHRUB2
+ {SPR_SHB2, 0, 1, A_TreeDeath, S_ZSHRUB2, 0, 0}, // S_ZSHRUB2_DIE
+ {SPR_SHB2, 32769, 7, NULL, S_ZSHRUB2_X2, 0, 0}, // S_ZSHRUB2_X1
+ {SPR_SHB2, 32770, 6, A_Scream, S_ZSHRUB2_X3, 0, 0}, // S_ZSHRUB2_X2
+ {SPR_SHB2, 32771, 5, A_Explode, S_ZSHRUB2_X4, 0, 0}, // S_ZSHRUB2_X3
+ {SPR_SHB2, 32772, 5, NULL, S_NULL, 0, 0}, // S_ZSHRUB2_X4
+ {SPR_BCKT, 0, -1, NULL, S_NULL, 0, 0}, // S_ZBUCKET1
+ {SPR_SHRM, 0, 5, A_PoisonShroom, S_ZPOISONSHROOM_P2, 0, 0}, // S_ZPOISONSHROOM1
+ {SPR_SHRM, 0, 6, NULL, S_ZPOISONSHROOM_P2, 0, 0}, // S_ZPOISONSHROOM_P1
+ {SPR_SHRM, 1, 8, A_Pain, S_ZPOISONSHROOM1, 0, 0}, // S_ZPOISONSHROOM_P2
+ {SPR_SHRM, 2, 5, NULL, S_ZPOISONSHROOM_X2, 0, 0}, // S_ZPOISONSHROOM_X1
+ {SPR_SHRM, 3, 5, NULL, S_ZPOISONSHROOM_X3, 0, 0}, // S_ZPOISONSHROOM_X2
+ {SPR_SHRM, 4, 5, A_PoisonBagInit, S_ZPOISONSHROOM_X4, 0, 0}, // S_ZPOISONSHROOM_X3
+ {SPR_SHRM, 5, -1, NULL, S_NULL, 0, 0}, // S_ZPOISONSHROOM_X4
+ {SPR_FBUL, 32768, 4, NULL, S_ZFIREBULL2, 0, 0}, // S_ZFIREBULL1
+ {SPR_FBUL, 32769, 4, NULL, S_ZFIREBULL3, 0, 0}, // S_ZFIREBULL2
+ {SPR_FBUL, 32770, 4, NULL, S_ZFIREBULL4, 0, 0}, // S_ZFIREBULL3
+ {SPR_FBUL, 32771, 4, NULL, S_ZFIREBULL5, 0, 0}, // S_ZFIREBULL4
+ {SPR_FBUL, 32772, 4, NULL, S_ZFIREBULL6, 0, 0}, // S_ZFIREBULL5
+ {SPR_FBUL, 32773, 4, NULL, S_ZFIREBULL7, 0, 0}, // S_ZFIREBULL6
+ {SPR_FBUL, 32774, 4, NULL, S_ZFIREBULL1, 0, 0}, // S_ZFIREBULL7
+ {SPR_FBUL, 32777, 4, NULL, S_ZFIREBULL_DEATH2, 0, 0}, // S_ZFIREBULL_DEATH
+ {SPR_FBUL, 32776, 4, NULL, S_ZFIREBULL_U, 0, 0}, // S_ZFIREBULL_DEATH2
+ {SPR_FBUL, 7, -1, NULL, S_NULL, 0, 0}, // S_ZFIREBULL_U
+ {SPR_FBUL, 32776, 4, NULL, S_ZFIREBULL_BIRTH2, 0, 0}, // S_ZFIREBULL_BIRTH
+ {SPR_FBUL, 32777, 4, NULL, S_ZFIREBULL1, 0, 0}, // S_ZFIREBULL_BIRTH2
+ {SPR_FSKL, 32768, 4, NULL, S_ZFIRETHING2, 0, 0}, // S_ZFIRETHING1
+ {SPR_FSKL, 32769, 3, NULL, S_ZFIRETHING3, 0, 0}, // S_ZFIRETHING2
+ {SPR_FSKL, 32770, 4, NULL, S_ZFIRETHING4, 0, 0}, // S_ZFIRETHING3
+ {SPR_FSKL, 32771, 3, NULL, S_ZFIRETHING5, 0, 0}, // S_ZFIRETHING4
+ {SPR_FSKL, 32772, 4, NULL, S_ZFIRETHING6, 0, 0}, // S_ZFIRETHING5
+ {SPR_FSKL, 32773, 3, NULL, S_ZFIRETHING7, 0, 0}, // S_ZFIRETHING6
+ {SPR_FSKL, 32774, 4, NULL, S_ZFIRETHING8, 0, 0}, // S_ZFIRETHING7
+ {SPR_FSKL, 32775, 3, NULL, S_ZFIRETHING9, 0, 0}, // S_ZFIRETHING8
+ {SPR_FSKL, 32776, 4, NULL, S_ZFIRETHING1, 0, 0}, // S_ZFIRETHING9
+ {SPR_BRTR, 32768, 4, NULL, S_ZBRASSTORCH2, 0, 0}, // S_ZBRASSTORCH1
+ {SPR_BRTR, 32769, 4, NULL, S_ZBRASSTORCH3, 0, 0}, // S_ZBRASSTORCH2
+ {SPR_BRTR, 32770, 4, NULL, S_ZBRASSTORCH4, 0, 0}, // S_ZBRASSTORCH3
+ {SPR_BRTR, 32771, 4, NULL, S_ZBRASSTORCH5, 0, 0}, // S_ZBRASSTORCH4
+ {SPR_BRTR, 32772, 4, NULL, S_ZBRASSTORCH6, 0, 0}, // S_ZBRASSTORCH5
+ {SPR_BRTR, 32773, 4, NULL, S_ZBRASSTORCH7, 0, 0}, // S_ZBRASSTORCH6
+ {SPR_BRTR, 32774, 4, NULL, S_ZBRASSTORCH8, 0, 0}, // S_ZBRASSTORCH7
+ {SPR_BRTR, 32775, 4, NULL, S_ZBRASSTORCH9, 0, 0}, // S_ZBRASSTORCH8
+ {SPR_BRTR, 32776, 4, NULL, S_ZBRASSTORCH10, 0, 0}, // S_ZBRASSTORCH9
+ {SPR_BRTR, 32777, 4, NULL, S_ZBRASSTORCH11, 0, 0}, // S_ZBRASSTORCH10
+ {SPR_BRTR, 32778, 4, NULL, S_ZBRASSTORCH12, 0, 0}, // S_ZBRASSTORCH11
+ {SPR_BRTR, 32779, 4, NULL, S_ZBRASSTORCH13, 0, 0}, // S_ZBRASSTORCH12
+ {SPR_BRTR, 32780, 4, NULL, S_ZBRASSTORCH1, 0, 0}, // S_ZBRASSTORCH13
+ {SPR_SUIT, 0, -1, NULL, S_NULL, 0, 0}, // S_ZSUITOFARMOR
+ {SPR_SUIT, 0, 1, A_SoAExplode, S_NULL, 0, 0}, // S_ZSUITOFARMOR_X1
+ {SPR_SUIT, 1, -1, NULL, S_NULL, 0, 0}, // S_ZARMORCHUNK1
+ {SPR_SUIT, 2, -1, NULL, S_NULL, 0, 0}, // S_ZARMORCHUNK2
+ {SPR_SUIT, 3, -1, NULL, S_NULL, 0, 0}, // S_ZARMORCHUNK3
+ {SPR_SUIT, 4, -1, NULL, S_NULL, 0, 0}, // S_ZARMORCHUNK4
+ {SPR_SUIT, 5, -1, NULL, S_NULL, 0, 0}, // S_ZARMORCHUNK5
+ {SPR_SUIT, 6, -1, NULL, S_NULL, 0, 0}, // S_ZARMORCHUNK6
+ {SPR_SUIT, 7, -1, NULL, S_NULL, 0, 0}, // S_ZARMORCHUNK7
+ {SPR_SUIT, 8, -1, NULL, S_NULL, 0, 0}, // S_ZARMORCHUNK8
+ {SPR_SUIT, 9, -1, NULL, S_NULL, 0, 0}, // S_ZARMORCHUNK9
+ {SPR_SUIT, 10, -1, NULL, S_NULL, 0, 0}, // S_ZARMORCHUNK10
+ {SPR_BBLL, 5, -1, NULL, S_NULL, 0, 0}, // S_ZBELL
+ {SPR_BBLL, 0, 4, A_BellReset1, S_ZBELL_X2, 0, 0}, // S_ZBELL_X1
+ {SPR_BBLL, 1, 4, NULL, S_ZBELL_X3, 0, 0}, // S_ZBELL_X2
+ {SPR_BBLL, 2, 4, NULL, S_ZBELL_X4, 0, 0}, // S_ZBELL_X3
+ {SPR_BBLL, 3, 5, A_Scream, S_ZBELL_X5, 0, 0}, // S_ZBELL_X4
+ {SPR_BBLL, 2, 4, NULL, S_ZBELL_X6, 0, 0}, // S_ZBELL_X5
+ {SPR_BBLL, 1, 4, NULL, S_ZBELL_X7, 0, 0}, // S_ZBELL_X6
+ {SPR_BBLL, 0, 3, NULL, S_ZBELL_X8, 0, 0}, // S_ZBELL_X7
+ {SPR_BBLL, 4, 4, NULL, S_ZBELL_X9, 0, 0}, // S_ZBELL_X8
+ {SPR_BBLL, 5, 5, NULL, S_ZBELL_X10, 0, 0}, // S_ZBELL_X9
+ {SPR_BBLL, 6, 6, A_Scream, S_ZBELL_X11, 0, 0}, // S_ZBELL_X10
+ {SPR_BBLL, 5, 5, NULL, S_ZBELL_X12, 0, 0}, // S_ZBELL_X11
+ {SPR_BBLL, 4, 4, NULL, S_ZBELL_X13, 0, 0}, // S_ZBELL_X12
+ {SPR_BBLL, 0, 4, NULL, S_ZBELL_X14, 0, 0}, // S_ZBELL_X13
+ {SPR_BBLL, 1, 5, NULL, S_ZBELL_X15, 0, 0}, // S_ZBELL_X14
+ {SPR_BBLL, 2, 5, NULL, S_ZBELL_X16, 0, 0}, // S_ZBELL_X15
+ {SPR_BBLL, 3, 6, A_Scream, S_ZBELL_X17, 0, 0}, // S_ZBELL_X16
+ {SPR_BBLL, 2, 5, NULL, S_ZBELL_X18, 0, 0}, // S_ZBELL_X17
+ {SPR_BBLL, 1, 5, NULL, S_ZBELL_X19, 0, 0}, // S_ZBELL_X18
+ {SPR_BBLL, 0, 4, NULL, S_ZBELL_X20, 0, 0}, // S_ZBELL_X19
+ {SPR_BBLL, 4, 5, NULL, S_ZBELL_X21, 0, 0}, // S_ZBELL_X20
+ {SPR_BBLL, 5, 5, NULL, S_ZBELL_X22, 0, 0}, // S_ZBELL_X21
+ {SPR_BBLL, 6, 7, A_Scream, S_ZBELL_X23, 0, 0}, // S_ZBELL_X22
+ {SPR_BBLL, 5, 5, NULL, S_ZBELL_X24, 0, 0}, // S_ZBELL_X23
+ {SPR_BBLL, 4, 5, NULL, S_ZBELL_X25, 0, 0}, // S_ZBELL_X24
+ {SPR_BBLL, 0, 5, NULL, S_ZBELL_X26, 0, 0}, // S_ZBELL_X25
+ {SPR_BBLL, 1, 6, NULL, S_ZBELL_X27, 0, 0}, // S_ZBELL_X26
+ {SPR_BBLL, 2, 6, NULL, S_ZBELL_X28, 0, 0}, // S_ZBELL_X27
+ {SPR_BBLL, 3, 7, A_Scream, S_ZBELL_X29, 0, 0}, // S_ZBELL_X28
+ {SPR_BBLL, 2, 6, NULL, S_ZBELL_X30, 0, 0}, // S_ZBELL_X29
+ {SPR_BBLL, 1, 6, NULL, S_ZBELL_X31, 0, 0}, // S_ZBELL_X30
+ {SPR_BBLL, 0, 5, NULL, S_ZBELL_X32, 0, 0}, // S_ZBELL_X31
+ {SPR_BBLL, 4, 6, NULL, S_ZBELL_X33, 0, 0}, // S_ZBELL_X32
+ {SPR_BBLL, 5, 6, NULL, S_ZBELL_X34, 0, 0}, // S_ZBELL_X33
+ {SPR_BBLL, 6, 7, A_Scream, S_ZBELL_X35, 0, 0}, // S_ZBELL_X34
+ {SPR_BBLL, 5, 6, NULL, S_ZBELL_X36, 0, 0}, // S_ZBELL_X35
+ {SPR_BBLL, 4, 6, NULL, S_ZBELL_X37, 0, 0}, // S_ZBELL_X36
+ {SPR_BBLL, 0, 6, NULL, S_ZBELL_X38, 0, 0}, // S_ZBELL_X37
+ {SPR_BBLL, 1, 6, NULL, S_ZBELL_X39, 0, 0}, // S_ZBELL_X38
+ {SPR_BBLL, 2, 6, NULL, S_ZBELL_X40, 0, 0}, // S_ZBELL_X39
+ {SPR_BBLL, 1, 7, NULL, S_ZBELL_X41, 0, 0}, // S_ZBELL_X40
+ {SPR_BBLL, 0, 8, NULL, S_ZBELL_X42, 0, 0}, // S_ZBELL_X41
+ {SPR_BBLL, 4, 12, NULL, S_ZBELL_X43, 0, 0}, // S_ZBELL_X42
+ {SPR_BBLL, 0, 10, NULL, S_ZBELL_X44, 0, 0}, // S_ZBELL_X43
+ {SPR_BBLL, 1, 12, NULL, S_ZBELL_X45, 0, 0}, // S_ZBELL_X44
+ {SPR_BBLL, 0, 12, NULL, S_ZBELL_X46, 0, 0}, // S_ZBELL_X45
+ {SPR_BBLL, 4, 14, NULL, S_ZBELL_X47, 0, 0}, // S_ZBELL_X46
+ {SPR_BBLL, 0, 1, A_BellReset2, S_ZBELL, 0, 0}, // S_ZBELL_X47
+ {SPR_CAND, 32768, 5, NULL, S_ZBLUE_CANDLE2, 0, 0}, // S_ZBLUE_CANDLE1
+ {SPR_CAND, 32769, 5, NULL, S_ZBLUE_CANDLE3, 0, 0}, // S_ZBLUE_CANDLE2
+ {SPR_CAND, 32770, 5, NULL, S_ZBLUE_CANDLE4, 0, 0}, // S_ZBLUE_CANDLE3
+ {SPR_CAND, 32771, 5, NULL, S_ZBLUE_CANDLE5, 0, 0}, // S_ZBLUE_CANDLE4
+ {SPR_CAND, 32772, 5, NULL, S_ZBLUE_CANDLE1, 0, 0}, // S_ZBLUE_CANDLE5
+ {SPR_IRON, 0, -1, NULL, S_NULL, 0, 0}, // S_ZIRON_MAIDEN
+ {SPR_XMAS, 0, -1, NULL, S_NULL, 0, 0}, // S_ZXMAS_TREE
+ {SPR_XMAS, 0, 4, A_TreeDeath, S_ZXMAS_TREE, 0, 0}, // S_ZXMAS_TREE_DIE
+ {SPR_XMAS, 32769, 6, NULL, S_ZXMAS_TREE_X2, 0, 0}, // S_ZXMAS_TREE_X1
+ {SPR_XMAS, 32770, 6, A_Scream, S_ZXMAS_TREE_X3, 0, 0}, // S_ZXMAS_TREE_X2
+ {SPR_XMAS, 32771, 5, NULL, S_ZXMAS_TREE_X4, 0, 0}, // S_ZXMAS_TREE_X3
+ {SPR_XMAS, 32772, 5, A_Explode, S_ZXMAS_TREE_X5, 0, 0}, // S_ZXMAS_TREE_X4
+ {SPR_XMAS, 32773, 5, NULL, S_ZXMAS_TREE_X6, 0, 0}, // S_ZXMAS_TREE_X5
+ {SPR_XMAS, 32774, 4, NULL, S_ZXMAS_TREE_X7, 0, 0}, // S_ZXMAS_TREE_X6
+ {SPR_XMAS, 7, 5, NULL, S_ZXMAS_TREE_X8, 0, 0}, // S_ZXMAS_TREE_X7
+ {SPR_XMAS, 8, 4, A_NoBlocking, S_ZXMAS_TREE_X9, 0, 0}, // S_ZXMAS_TREE_X8
+ {SPR_XMAS, 9, 4, NULL, S_ZXMAS_TREE_X10, 0, 0}, // S_ZXMAS_TREE_X9
+ {SPR_XMAS, 10, -1, NULL, S_NULL, 0, 0}, // S_ZXMAS_TREE_X10
+ {SPR_CDRN, 32769, 4, NULL, S_ZCAULDRON2, 0, 0}, // S_ZCAULDRON1
+ {SPR_CDRN, 32770, 4, NULL, S_ZCAULDRON3, 0, 0}, // S_ZCAULDRON2
+ {SPR_CDRN, 32771, 4, NULL, S_ZCAULDRON4, 0, 0}, // S_ZCAULDRON3
+ {SPR_CDRN, 32772, 4, NULL, S_ZCAULDRON5, 0, 0}, // S_ZCAULDRON4
+ {SPR_CDRN, 32773, 4, NULL, S_ZCAULDRON6, 0, 0}, // S_ZCAULDRON5
+ {SPR_CDRN, 32774, 4, NULL, S_ZCAULDRON7, 0, 0}, // S_ZCAULDRON6
+ {SPR_CDRN, 32775, 4, NULL, S_ZCAULDRON1, 0, 0}, // S_ZCAULDRON7
+ {SPR_CDRN, 0, -1, NULL, S_NULL, 0, 0}, // S_ZCAULDRON_U
+ {SPR_CHNS, 0, -1, NULL, S_NULL, 0, 0}, // S_ZCHAINBIT32
+ {SPR_CHNS, 1, -1, NULL, S_NULL, 0, 0}, // S_ZCHAINBIT64
+ {SPR_CHNS, 2, -1, NULL, S_NULL, 0, 0}, // S_ZCHAINEND_HEART
+ {SPR_CHNS, 3, -1, NULL, S_NULL, 0, 0}, // S_ZCHAINEND_HOOK1
+ {SPR_CHNS, 4, -1, NULL, S_NULL, 0, 0}, // S_ZCHAINEND_HOOK2
+ {SPR_CHNS, 5, -1, NULL, S_NULL, 0, 0}, // S_ZCHAINEND_SPIKE
+ {SPR_CHNS, 6, -1, NULL, S_NULL, 0, 0}, // S_ZCHAINEND_SKULL
+ {SPR_TST1, 0, -1, NULL, S_NULL, 0, 0}, // S_TABLE_SHIT1
+ {SPR_TST2, 0, -1, NULL, S_NULL, 0, 0}, // S_TABLE_SHIT2
+ {SPR_TST3, 0, -1, NULL, S_NULL, 0, 0}, // S_TABLE_SHIT3
+ {SPR_TST4, 0, -1, NULL, S_NULL, 0, 0}, // S_TABLE_SHIT4
+ {SPR_TST5, 0, -1, NULL, S_NULL, 0, 0}, // S_TABLE_SHIT5
+ {SPR_TST6, 0, -1, NULL, S_NULL, 0, 0}, // S_TABLE_SHIT6
+ {SPR_TST7, 0, -1, NULL, S_NULL, 0, 0}, // S_TABLE_SHIT7
+ {SPR_TST8, 0, -1, NULL, S_NULL, 0, 0}, // S_TABLE_SHIT8
+ {SPR_TST9, 0, -1, NULL, S_NULL, 0, 0}, // S_TABLE_SHIT9
+ {SPR_TST0, 0, -1, NULL, S_NULL, 0, 0}, // S_TABLE_SHIT10
+ {SPR_TELE, 32768, 6, NULL, S_TFOG2, 0, 0}, // S_TFOG1
+ {SPR_TELE, 32769, 6, NULL, S_TFOG3, 0, 0}, // S_TFOG2
+ {SPR_TELE, 32770, 6, NULL, S_TFOG4, 0, 0}, // S_TFOG3
+ {SPR_TELE, 32771, 6, NULL, S_TFOG5, 0, 0}, // S_TFOG4
+ {SPR_TELE, 32772, 6, NULL, S_TFOG6, 0, 0}, // S_TFOG5
+ {SPR_TELE, 32773, 6, NULL, S_TFOG7, 0, 0}, // S_TFOG6
+ {SPR_TELE, 32774, 6, NULL, S_TFOG8, 0, 0}, // S_TFOG7
+ {SPR_TELE, 32775, 6, NULL, S_TFOG9, 0, 0}, // S_TFOG8
+ {SPR_TELE, 32774, 6, NULL, S_TFOG10, 0, 0}, // S_TFOG9
+ {SPR_TELE, 32773, 6, NULL, S_TFOG11, 0, 0}, // S_TFOG10
+ {SPR_TELE, 32772, 6, NULL, S_TFOG12, 0, 0}, // S_TFOG11
+ {SPR_TELE, 32771, 6, NULL, S_TFOG13, 0, 0}, // S_TFOG12
+ {SPR_TELE, 32770, 6, NULL, S_NULL, 0, 0}, // S_TFOG13
+ {SPR_TSMK, 0, 4, NULL, S_TELESMOKE2, 0, 0}, // S_TELESMOKE1
+ {SPR_TSMK, 1, 3, NULL, S_TELESMOKE3, 0, 0}, // S_TELESMOKE2
+ {SPR_TSMK, 2, 4, NULL, S_TELESMOKE4, 0, 0}, // S_TELESMOKE3
+ {SPR_TSMK, 3, 3, NULL, S_TELESMOKE5, 0, 0}, // S_TELESMOKE4
+ {SPR_TSMK, 4, 4, NULL, S_TELESMOKE6, 0, 0}, // S_TELESMOKE5
+ {SPR_TSMK, 5, 3, NULL, S_TELESMOKE7, 0, 0}, // S_TELESMOKE6
+ {SPR_TSMK, 6, 4, NULL, S_TELESMOKE8, 0, 0}, // S_TELESMOKE7
+ {SPR_TSMK, 7, 3, NULL, S_TELESMOKE9, 0, 0}, // S_TELESMOKE8
+ {SPR_TSMK, 8, 4, NULL, S_TELESMOKE10, 0, 0}, // S_TELESMOKE9
+ {SPR_TSMK, 9, 3, NULL, S_TELESMOKE11, 0, 0}, // S_TELESMOKE10
+ {SPR_TSMK, 10, 4, NULL, S_TELESMOKE12, 0, 0}, // S_TELESMOKE11
+ {SPR_TSMK, 11, 3, NULL, S_TELESMOKE13, 0, 0}, // S_TELESMOKE12
+ {SPR_TSMK, 12, 4, NULL, S_TELESMOKE14, 0, 0}, // S_TELESMOKE13
+ {SPR_TSMK, 13, 3, NULL, S_TELESMOKE15, 0, 0}, // S_TELESMOKE14
+ {SPR_TSMK, 14, 4, NULL, S_TELESMOKE16, 0, 0}, // S_TELESMOKE15
+ {SPR_TSMK, 15, 3, NULL, S_TELESMOKE17, 0, 0}, // S_TELESMOKE16
+ {SPR_TSMK, 16, 4, NULL, S_TELESMOKE18, 0, 0}, // S_TELESMOKE17
+ {SPR_TSMK, 17, 3, NULL, S_TELESMOKE19, 0, 0}, // S_TELESMOKE18
+ {SPR_TSMK, 18, 4, NULL, S_TELESMOKE20, 0, 0}, // S_TELESMOKE19
+ {SPR_TSMK, 19, 3, NULL, S_TELESMOKE21, 0, 0}, // S_TELESMOKE20
+ {SPR_TSMK, 20, 4, NULL, S_TELESMOKE22, 0, 0}, // S_TELESMOKE21
+ {SPR_TSMK, 21, 3, NULL, S_TELESMOKE23, 0, 0}, // S_TELESMOKE22
+ {SPR_TSMK, 22, 4, NULL, S_TELESMOKE24, 0, 0}, // S_TELESMOKE23
+ {SPR_TSMK, 23, 3, NULL, S_TELESMOKE25, 0, 0}, // S_TELESMOKE24
+ {SPR_TSMK, 24, 4, NULL, S_TELESMOKE26, 0, 0}, // S_TELESMOKE25
+ {SPR_TSMK, 25, 3, NULL, S_TELESMOKE1, 0, 0}, // S_TELESMOKE26
+ {SPR_FPCH, 0, 0, A_Light0, S_NULL, 0, 0}, // S_LIGHTDONE
+ {SPR_FPCH, 0, 1, A_WeaponReady, S_PUNCHREADY, 0, 0}, // S_PUNCHREADY
+ {SPR_FPCH, 0, 1, A_Lower, S_PUNCHDOWN, 0, 0}, // S_PUNCHDOWN
+ {SPR_FPCH, 0, 1, A_Raise, S_PUNCHUP, 0, 0}, // S_PUNCHUP
+ {SPR_FPCH, 1, 5, NULL, S_PUNCHATK1_2, 5, 40}, // S_PUNCHATK1_1
+ {SPR_FPCH, 2, 4, NULL, S_PUNCHATK1_3, 5, 40}, // S_PUNCHATK1_2
+ {SPR_FPCH, 3, 4, A_FPunchAttack, S_PUNCHATK1_4, 5, 40}, // S_PUNCHATK1_3
+ {SPR_FPCH, 2, 4, NULL, S_PUNCHATK1_5, 5, 40}, // S_PUNCHATK1_4
+ {SPR_FPCH, 1, 5, A_ReFire, S_PUNCHREADY, 5, 40}, // S_PUNCHATK1_5
+ {SPR_FPCH, 3, 4, NULL, S_PUNCHATK2_2, 5, 40}, // S_PUNCHATK2_1
+ {SPR_FPCH, 4, 4, NULL, S_PUNCHATK2_3, 5, 40}, // S_PUNCHATK2_2
+ {SPR_FPCH, 4, 1, NULL, S_PUNCHATK2_4, 15, 50}, // S_PUNCHATK2_3
+ {SPR_FPCH, 4, 1, NULL, S_PUNCHATK2_5, 25, 60}, // S_PUNCHATK2_4
+ {SPR_FPCH, 4, 1, NULL, S_PUNCHATK2_6, 35, 70}, // S_PUNCHATK2_5
+ {SPR_FPCH, 4, 1, NULL, S_PUNCHATK2_7, 45, 80}, // S_PUNCHATK2_6
+ {SPR_FPCH, 4, 1, NULL, S_PUNCHATK2_8, 55, 90}, // S_PUNCHATK2_7
+ {SPR_FPCH, 4, 1, NULL, S_PUNCHATK2_9, 65, 100}, // S_PUNCHATK2_8
+ {SPR_FPCH, 4, 10, NULL, S_PUNCHREADY, 0, 150}, // S_PUNCHATK2_9
+ {SPR_FHFX, 18, 4, NULL, S_PUNCHPUFF2, 0, 0}, // S_PUNCHPUFF1
+ {SPR_FHFX, 19, 4, NULL, S_PUNCHPUFF3, 0, 0}, // S_PUNCHPUFF2
+ {SPR_FHFX, 20, 4, NULL, S_PUNCHPUFF4, 0, 0}, // S_PUNCHPUFF3
+ {SPR_FHFX, 21, 4, NULL, S_PUNCHPUFF5, 0, 0}, // S_PUNCHPUFF4
+ {SPR_FHFX, 22, 4, NULL, S_NULL, 0, 0}, // S_PUNCHPUFF5
+ {SPR_WFAX, 0, -1, NULL, S_NULL, 0, 0}, // S_AXE
+ {SPR_FAXE, 0, 1, A_WeaponReady, S_FAXEREADY, 0, 0}, // S_FAXEREADY
+ {SPR_FAXE, 0, 1, A_Lower, S_FAXEDOWN, 0, 0}, // S_FAXEDOWN
+ {SPR_FAXE, 0, 1, A_Raise, S_FAXEUP, 0, 0}, // S_FAXEUP
+ {SPR_FAXE, 1, 4, NULL, S_FAXEATK_2, 15, 32}, // S_FAXEATK_1
+ {SPR_FAXE, 2, 3, NULL, S_FAXEATK_3, 15, 32}, // S_FAXEATK_2
+ {SPR_FAXE, 3, 2, NULL, S_FAXEATK_4, 15, 32}, // S_FAXEATK_3
+ {SPR_FAXE, 3, 1, A_FAxeAttack, S_FAXEATK_5, -5, 70}, // S_FAXEATK_4
+ {SPR_FAXE, 3, 2, NULL, S_FAXEATK_6, -25, 90}, // S_FAXEATK_5
+ {SPR_FAXE, 4, 1, NULL, S_FAXEATK_7, 15, 32}, // S_FAXEATK_6
+ {SPR_FAXE, 4, 2, NULL, S_FAXEATK_8, 10, 54}, // S_FAXEATK_7
+ {SPR_FAXE, 4, 7, NULL, S_FAXEATK_9, 10, 150}, // S_FAXEATK_8
+ {SPR_FAXE, 0, 1, A_ReFire, S_FAXEATK_10, 0, 60}, // S_FAXEATK_9
+ {SPR_FAXE, 0, 1, NULL, S_FAXEATK_11, 0, 52}, // S_FAXEATK_10
+ {SPR_FAXE, 0, 1, NULL, S_FAXEATK_12, 0, 44}, // S_FAXEATK_11
+ {SPR_FAXE, 0, 1, NULL, S_FAXEATK_13, 0, 36}, // S_FAXEATK_12
+ {SPR_FAXE, 0, 1, NULL, S_FAXEREADY, 0, 0}, // S_FAXEATK_13
+ {SPR_FAXE, 11, 1, A_WeaponReady, S_FAXEREADY_G1, 0, 0}, // S_FAXEREADY_G
+ {SPR_FAXE, 11, 1, A_WeaponReady, S_FAXEREADY_G2, 0, 0}, // S_FAXEREADY_G1
+ {SPR_FAXE, 11, 1, A_WeaponReady, S_FAXEREADY_G3, 0, 0}, // S_FAXEREADY_G2
+ {SPR_FAXE, 12, 1, A_WeaponReady, S_FAXEREADY_G4, 0, 0}, // S_FAXEREADY_G3
+ {SPR_FAXE, 12, 1, A_WeaponReady, S_FAXEREADY_G5, 0, 0}, // S_FAXEREADY_G4
+ {SPR_FAXE, 12, 1, A_WeaponReady, S_FAXEREADY_G, 0, 0}, // S_FAXEREADY_G5
+ {SPR_FAXE, 11, 1, A_Lower, S_FAXEDOWN_G, 0, 0}, // S_FAXEDOWN_G
+ {SPR_FAXE, 11, 1, A_Raise, S_FAXEUP_G, 0, 0}, // S_FAXEUP_G
+ {SPR_FAXE, 13, 4, NULL, S_FAXEATK_G2, 15, 32}, // S_FAXEATK_G1
+ {SPR_FAXE, 14, 3, NULL, S_FAXEATK_G3, 15, 32}, // S_FAXEATK_G2
+ {SPR_FAXE, 15, 2, NULL, S_FAXEATK_G4, 15, 32}, // S_FAXEATK_G3
+ {SPR_FAXE, 15, 1, A_FAxeAttack, S_FAXEATK_G5, -5, 70}, // S_FAXEATK_G4
+ {SPR_FAXE, 15, 2, NULL, S_FAXEATK_G6, -25, 90}, // S_FAXEATK_G5
+ {SPR_FAXE, 16, 1, NULL, S_FAXEATK_G7, 15, 32}, // S_FAXEATK_G6
+ {SPR_FAXE, 16, 2, NULL, S_FAXEATK_G8, 10, 54}, // S_FAXEATK_G7
+ {SPR_FAXE, 16, 7, NULL, S_FAXEATK_G9, 10, 150}, // S_FAXEATK_G8
+ {SPR_FAXE, 0, 1, A_ReFire, S_FAXEATK_G10, 0, 60}, // S_FAXEATK_G9
+ {SPR_FAXE, 0, 1, NULL, S_FAXEATK_G11, 0, 52}, // S_FAXEATK_G10
+ {SPR_FAXE, 0, 1, NULL, S_FAXEATK_G12, 0, 44}, // S_FAXEATK_G11
+ {SPR_FAXE, 0, 1, NULL, S_FAXEATK_G13, 0, 36}, // S_FAXEATK_G12
+ {SPR_FAXE, 0, 1, NULL, S_FAXEREADY_G, 0, 0}, // S_FAXEATK_G13
+ {SPR_FAXE, 32785, 4, NULL, S_AXEPUFF_GLOW2, 0, 0}, // S_AXEPUFF_GLOW1
+ {SPR_FAXE, 32786, 4, NULL, S_AXEPUFF_GLOW3, 0, 0}, // S_AXEPUFF_GLOW2
+ {SPR_FAXE, 32787, 4, NULL, S_AXEPUFF_GLOW4, 0, 0}, // S_AXEPUFF_GLOW3
+ {SPR_FAXE, 32788, 4, NULL, S_AXEPUFF_GLOW5, 0, 0}, // S_AXEPUFF_GLOW4
+ {SPR_FAXE, 32789, 4, NULL, S_AXEPUFF_GLOW6, 0, 0}, // S_AXEPUFF_GLOW5
+ {SPR_FAXE, 32790, 4, NULL, S_AXEPUFF_GLOW7, 0, 0}, // S_AXEPUFF_GLOW6
+ {SPR_FAXE, 32791, 4, NULL, S_NULL, 0, 0}, // S_AXEPUFF_GLOW7
+ {SPR_FAXE, 5, 3, NULL, S_AXEBLOOD2, 0, 0}, // S_AXEBLOOD1
+ {SPR_FAXE, 6, 3, NULL, S_AXEBLOOD3, 0, 0}, // S_AXEBLOOD2
+ {SPR_FAXE, 7, 3, NULL, S_AXEBLOOD4, 0, 0}, // S_AXEBLOOD3
+ {SPR_FAXE, 8, 3, NULL, S_AXEBLOOD5, 0, 0}, // S_AXEBLOOD4
+ {SPR_FAXE, 9, 3, NULL, S_AXEBLOOD6, 0, 0}, // S_AXEBLOOD5
+ {SPR_FAXE, 10, 3, NULL, S_NULL, 0, 0}, // S_AXEBLOOD6
+ {SPR_WFHM, 0, -1, NULL, S_NULL, 0, 0}, // S_HAMM
+ {SPR_FHMR, 0, 1, A_WeaponReady, S_FHAMMERREADY, 0, 0}, // S_FHAMMERREADY
+ {SPR_FHMR, 0, 1, A_Lower, S_FHAMMERDOWN, 0, 0}, // S_FHAMMERDOWN
+ {SPR_FHMR, 0, 1, A_Raise, S_FHAMMERUP, 0, 0}, // S_FHAMMERUP
+ {SPR_FHMR, 1, 6, NULL, S_FHAMMERATK_2, 5, 0}, // S_FHAMMERATK_1
+ {SPR_FHMR, 2, 3, A_FHammerAttack, S_FHAMMERATK_3, 5, 0}, // S_FHAMMERATK_2
+ {SPR_FHMR, 3, 3, NULL, S_FHAMMERATK_4, 5, 0}, // S_FHAMMERATK_3
+ {SPR_FHMR, 4, 2, NULL, S_FHAMMERATK_5, 5, 0}, // S_FHAMMERATK_4
+ {SPR_FHMR, 4, 10, A_FHammerThrow, S_FHAMMERATK_6, 5, 150}, // S_FHAMMERATK_5
+ {SPR_FHMR, 0, 1, NULL, S_FHAMMERATK_7, 0, 60}, // S_FHAMMERATK_6
+ {SPR_FHMR, 0, 1, NULL, S_FHAMMERATK_8, 0, 55}, // S_FHAMMERATK_7
+ {SPR_FHMR, 0, 1, NULL, S_FHAMMERATK_9, 0, 50}, // S_FHAMMERATK_8
+ {SPR_FHMR, 0, 1, NULL, S_FHAMMERATK_10, 0, 45}, // S_FHAMMERATK_9
+ {SPR_FHMR, 0, 1, NULL, S_FHAMMERATK_11, 0, 40}, // S_FHAMMERATK_10
+ {SPR_FHMR, 0, 1, NULL, S_FHAMMERATK_12, 0, 35}, // S_FHAMMERATK_11
+ {SPR_FHMR, 0, 1, NULL, S_FHAMMERREADY, 0, 0}, // S_FHAMMERATK_12
+ {SPR_FHFX, 32768, 2, NULL, S_HAMMER_MISSILE_2, 0, 0}, // S_HAMMER_MISSILE_1
+ {SPR_FHFX, 32769, 2, A_ContMobjSound, S_HAMMER_MISSILE_3, 0, 0}, // S_HAMMER_MISSILE_2
+ {SPR_FHFX, 32770, 2, NULL, S_HAMMER_MISSILE_4, 0, 0}, // S_HAMMER_MISSILE_3
+ {SPR_FHFX, 32771, 2, NULL, S_HAMMER_MISSILE_5, 0, 0}, // S_HAMMER_MISSILE_4
+ {SPR_FHFX, 32772, 2, NULL, S_HAMMER_MISSILE_6, 0, 0}, // S_HAMMER_MISSILE_5
+ {SPR_FHFX, 32773, 2, NULL, S_HAMMER_MISSILE_7, 0, 0}, // S_HAMMER_MISSILE_6
+ {SPR_FHFX, 32774, 2, NULL, S_HAMMER_MISSILE_8, 0, 0}, // S_HAMMER_MISSILE_7
+ {SPR_FHFX, 32775, 2, NULL, S_HAMMER_MISSILE_1, 0, 0}, // S_HAMMER_MISSILE_8
+ {SPR_FHFX, 32776, 3, NULL, S_HAMMER_MISSILE_X2, 0, 0}, // S_HAMMER_MISSILE_X1
+ {SPR_FHFX, 32777, 3, NULL, S_HAMMER_MISSILE_X3, 0, 0}, // S_HAMMER_MISSILE_X2
+ {SPR_FHFX, 32778, 3, A_Explode, S_HAMMER_MISSILE_X4, 0, 0}, // S_HAMMER_MISSILE_X3
+ {SPR_FHFX, 32779, 3, NULL, S_HAMMER_MISSILE_X5, 0, 0}, // S_HAMMER_MISSILE_X4
+ {SPR_FHFX, 32780, 3, NULL, S_HAMMER_MISSILE_X6, 0, 0}, // S_HAMMER_MISSILE_X5
+ {SPR_FHFX, 13, 3, NULL, S_HAMMER_MISSILE_X7, 0, 0}, // S_HAMMER_MISSILE_X6
+ {SPR_FHFX, 32782, 3, NULL, S_HAMMER_MISSILE_X8, 0, 0}, // S_HAMMER_MISSILE_X7
+ {SPR_FHFX, 32783, 3, NULL, S_HAMMER_MISSILE_X9, 0, 0}, // S_HAMMER_MISSILE_X8
+ {SPR_FHFX, 32784, 3, NULL, S_HAMMER_MISSILE_X10, 0, 0}, // S_HAMMER_MISSILE_X9
+ {SPR_FHFX, 32785, 3, NULL, S_NULL, 0, 0}, // S_HAMMER_MISSILE_X10
+ {SPR_FHFX, 18, 4, NULL, S_HAMMERPUFF2, 0, 0}, // S_HAMMERPUFF1
+ {SPR_FHFX, 19, 4, NULL, S_HAMMERPUFF3, 0, 0}, // S_HAMMERPUFF2
+ {SPR_FHFX, 20, 4, NULL, S_HAMMERPUFF4, 0, 0}, // S_HAMMERPUFF3
+ {SPR_FHFX, 21, 4, NULL, S_HAMMERPUFF5, 0, 0}, // S_HAMMERPUFF4
+ {SPR_FHFX, 22, 4, NULL, S_NULL, 0, 0}, // S_HAMMERPUFF5
+ {SPR_FSRD, 32768, 1, A_WeaponReady, S_FSWORDREADY1, 0, 0}, // S_FSWORDREADY
+ {SPR_FSRD, 32768, 1, A_WeaponReady, S_FSWORDREADY2, 0, 0}, // S_FSWORDREADY1
+ {SPR_FSRD, 32768, 1, A_WeaponReady, S_FSWORDREADY3, 0, 0}, // S_FSWORDREADY2
+ {SPR_FSRD, 32768, 1, A_WeaponReady, S_FSWORDREADY4, 0, 0}, // S_FSWORDREADY3
+ {SPR_FSRD, 32769, 1, A_WeaponReady, S_FSWORDREADY5, 0, 0}, // S_FSWORDREADY4
+ {SPR_FSRD, 32769, 1, A_WeaponReady, S_FSWORDREADY6, 0, 0}, // S_FSWORDREADY5
+ {SPR_FSRD, 32769, 1, A_WeaponReady, S_FSWORDREADY7, 0, 0}, // S_FSWORDREADY6
+ {SPR_FSRD, 32769, 1, A_WeaponReady, S_FSWORDREADY8, 0, 0}, // S_FSWORDREADY7
+ {SPR_FSRD, 32770, 1, A_WeaponReady, S_FSWORDREADY9, 0, 0}, // S_FSWORDREADY8
+ {SPR_FSRD, 32770, 1, A_WeaponReady, S_FSWORDREADY10, 0, 0}, // S_FSWORDREADY9
+ {SPR_FSRD, 32770, 1, A_WeaponReady, S_FSWORDREADY11, 0, 0}, // S_FSWORDREADY10
+ {SPR_FSRD, 32770, 1, A_WeaponReady, S_FSWORDREADY, 0, 0}, // S_FSWORDREADY11
+ {SPR_FSRD, 32768, 1, A_Lower, S_FSWORDDOWN, 0, 0}, // S_FSWORDDOWN
+ {SPR_FSRD, 32768, 1, A_Raise, S_FSWORDUP, 0, 0}, // S_FSWORDUP
+ {SPR_FSRD, 32771, 3, NULL, S_FSWORDATK_2, 5, 36}, // S_FSWORDATK_1
+ {SPR_FSRD, 32772, 3, NULL, S_FSWORDATK_3, 5, 36}, // S_FSWORDATK_2
+ {SPR_FSRD, 32773, 2, NULL, S_FSWORDATK_4, 5, 36}, // S_FSWORDATK_3
+ {SPR_FSRD, 32774, 3, A_FSwordAttack, S_FSWORDATK_5, 5, 36}, // S_FSWORDATK_4
+ {SPR_FSRD, 32775, 2, NULL, S_FSWORDATK_6, 5, 36}, // S_FSWORDATK_5
+ {SPR_FSRD, 32776, 2, NULL, S_FSWORDATK_7, 5, 36}, // S_FSWORDATK_6
+ {SPR_FSRD, 32776, 10, NULL, S_FSWORDATK_8, 5, 150}, // S_FSWORDATK_7
+ {SPR_FSRD, 32768, 1, NULL, S_FSWORDATK_9, 5, 60}, // S_FSWORDATK_8
+ {SPR_FSRD, 32769, 1, NULL, S_FSWORDATK_10, 5, 55}, // S_FSWORDATK_9
+ {SPR_FSRD, 32770, 1, NULL, S_FSWORDATK_11, 5, 50}, // S_FSWORDATK_10
+ {SPR_FSRD, 32768, 1, NULL, S_FSWORDATK_12, 5, 45}, // S_FSWORDATK_11
+ {SPR_FSRD, 32769, 1, NULL, S_FSWORDREADY, 5, 40}, // S_FSWORDATK_12
+ {SPR_FSFX, 32768, 3, NULL, S_FSWORD_MISSILE2, 0, 0}, // S_FSWORD_MISSILE1
+ {SPR_FSFX, 32769, 3, NULL, S_FSWORD_MISSILE3, 0, 0}, // S_FSWORD_MISSILE2
+ {SPR_FSFX, 32770, 3, NULL, S_FSWORD_MISSILE1, 0, 0}, // S_FSWORD_MISSILE3
+ {SPR_FSFX, 32771, 4, NULL, S_FSWORD_MISSILE_X2, 0, 0}, // S_FSWORD_MISSILE_X1
+ {SPR_FSFX, 32772, 3, A_FSwordFlames, S_FSWORD_MISSILE_X3, 0, 0}, // S_FSWORD_MISSILE_X2
+ {SPR_FSFX, 32773, 4, A_Explode, S_FSWORD_MISSILE_X4, 0, 0}, // S_FSWORD_MISSILE_X3
+ {SPR_FSFX, 32774, 3, NULL, S_FSWORD_MISSILE_X5, 0, 0}, // S_FSWORD_MISSILE_X4
+ {SPR_FSFX, 32775, 4, NULL, S_FSWORD_MISSILE_X6, 0, 0}, // S_FSWORD_MISSILE_X5
+ {SPR_FSFX, 32776, 3, NULL, S_FSWORD_MISSILE_X7, 0, 0}, // S_FSWORD_MISSILE_X6
+ {SPR_FSFX, 32777, 4, NULL, S_FSWORD_MISSILE_X8, 0, 0}, // S_FSWORD_MISSILE_X7
+ {SPR_FSFX, 32778, 3, NULL, S_FSWORD_MISSILE_X9, 0, 0}, // S_FSWORD_MISSILE_X8
+ {SPR_FSFX, 32779, 3, NULL, S_FSWORD_MISSILE_X10, 0, 0}, // S_FSWORD_MISSILE_X9
+ {SPR_FSFX, 32780, 3, NULL, S_NULL, 0, 0}, // S_FSWORD_MISSILE_X10
+ {SPR_FSFX, 32781, 3, NULL, S_FSWORD_FLAME2, 0, 0}, // S_FSWORD_FLAME1
+ {SPR_FSFX, 32782, 3, NULL, S_FSWORD_FLAME3, 0, 0}, // S_FSWORD_FLAME2
+ {SPR_FSFX, 32783, 3, NULL, S_FSWORD_FLAME4, 0, 0}, // S_FSWORD_FLAME3
+ {SPR_FSFX, 32784, 3, NULL, S_FSWORD_FLAME5, 0, 0}, // S_FSWORD_FLAME4
+ {SPR_FSFX, 32785, 3, NULL, S_FSWORD_FLAME6, 0, 0}, // S_FSWORD_FLAME5
+ {SPR_FSFX, 32786, 3, NULL, S_FSWORD_FLAME7, 0, 0}, // S_FSWORD_FLAME6
+ {SPR_FSFX, 32787, 3, NULL, S_FSWORD_FLAME8, 0, 0}, // S_FSWORD_FLAME7
+ {SPR_FSFX, 32788, 3, NULL, S_FSWORD_FLAME9, 0, 0}, // S_FSWORD_FLAME8
+ {SPR_FSFX, 32789, 3, NULL, S_FSWORD_FLAME10, 0, 0}, // S_FSWORD_FLAME9
+ {SPR_FSFX, 32790, 3, NULL, S_NULL, 0, 0}, // S_FSWORD_FLAME10
+ {SPR_CMCE, 0, 1, A_WeaponReady, S_CMACEREADY, 0, 0}, // S_CMACEREADY
+ {SPR_CMCE, 0, 1, A_Lower, S_CMACEDOWN, 0, 0}, // S_CMACEDOWN
+ {SPR_CMCE, 0, 1, A_Raise, S_CMACEUP, 0, 0}, // S_CMACEUP
+ {SPR_CMCE, 1, 2, NULL, S_CMACEATK_2, 60, 20}, // S_CMACEATK_1
+ {SPR_CMCE, 1, 1, NULL, S_CMACEATK_3, 30, 33}, // S_CMACEATK_2
+ {SPR_CMCE, 1, 2, NULL, S_CMACEATK_4, 8, 45}, // S_CMACEATK_3
+ {SPR_CMCE, 2, 1, NULL, S_CMACEATK_5, 8, 45}, // S_CMACEATK_4
+ {SPR_CMCE, 3, 1, NULL, S_CMACEATK_6, 8, 45}, // S_CMACEATK_5
+ {SPR_CMCE, 4, 1, NULL, S_CMACEATK_7, 8, 45}, // S_CMACEATK_6
+ {SPR_CMCE, 4, 1, A_CMaceAttack, S_CMACEATK_8, -11, 58}, // S_CMACEATK_7
+ {SPR_CMCE, 5, 1, NULL, S_CMACEATK_9, 8, 45}, // S_CMACEATK_8
+ {SPR_CMCE, 5, 2, NULL, S_CMACEATK_10, -8, 74}, // S_CMACEATK_9
+ {SPR_CMCE, 5, 1, NULL, S_CMACEATK_11, -20, 96}, // S_CMACEATK_10
+ {SPR_CMCE, 5, 8, NULL, S_CMACEATK_12, -33, 160}, // S_CMACEATK_11
+ {SPR_CMCE, 0, 2, A_ReFire, S_CMACEATK_13, 8, 75}, // S_CMACEATK_12
+ {SPR_CMCE, 0, 1, NULL, S_CMACEATK_14, 8, 65}, // S_CMACEATK_13
+ {SPR_CMCE, 0, 2, NULL, S_CMACEATK_15, 8, 60}, // S_CMACEATK_14
+ {SPR_CMCE, 0, 1, NULL, S_CMACEATK_16, 8, 55}, // S_CMACEATK_15
+ {SPR_CMCE, 0, 2, NULL, S_CMACEATK_17, 8, 50}, // S_CMACEATK_16
+ {SPR_CMCE, 0, 1, NULL, S_CMACEREADY, 8, 45}, // S_CMACEATK_17
+ {SPR_WCSS, 0, -1, NULL, S_NULL, 0, 0}, // S_CSTAFF
+ {SPR_CSSF, 2, 4, NULL, S_CSTAFFREADY1, 0, 0}, // S_CSTAFFREADY
+ {SPR_CSSF, 1, 3, A_CStaffInitBlink, S_CSTAFFREADY2, 0, 0}, // S_CSTAFFREADY1
+ {SPR_CSSF, 0, 1, A_WeaponReady, S_CSTAFFREADY3, 0, 0}, // S_CSTAFFREADY2
+ {SPR_CSSF, 0, 1, A_WeaponReady, S_CSTAFFREADY4, 0, 0}, // S_CSTAFFREADY3
+ {SPR_CSSF, 0, 1, A_WeaponReady, S_CSTAFFREADY5, 0, 0}, // S_CSTAFFREADY4
+ {SPR_CSSF, 0, 1, A_WeaponReady, S_CSTAFFREADY6, 0, 0}, // S_CSTAFFREADY5
+ {SPR_CSSF, 0, 1, A_WeaponReady, S_CSTAFFREADY7, 0, 0}, // S_CSTAFFREADY6
+ {SPR_CSSF, 0, 1, A_WeaponReady, S_CSTAFFREADY8, 0, 0}, // S_CSTAFFREADY7
+ {SPR_CSSF, 0, 1, A_WeaponReady, S_CSTAFFREADY9, 0, 0}, // S_CSTAFFREADY8
+ {SPR_CSSF, 0, 1, A_CStaffCheckBlink, S_CSTAFFREADY2, 0, 0}, // S_CSTAFFREADY9
+ {SPR_CSSF, 1, 1, A_WeaponReady, S_CSTAFFBLINK2, 0, 0}, // S_CSTAFFBLINK1
+ {SPR_CSSF, 1, 1, A_WeaponReady, S_CSTAFFBLINK3, 0, 0}, // S_CSTAFFBLINK2
+ {SPR_CSSF, 1, 1, A_WeaponReady, S_CSTAFFBLINK4, 0, 0}, // S_CSTAFFBLINK3
+ {SPR_CSSF, 2, 1, A_WeaponReady, S_CSTAFFBLINK5, 0, 0}, // S_CSTAFFBLINK4
+ {SPR_CSSF, 2, 1, A_WeaponReady, S_CSTAFFBLINK6, 0, 0}, // S_CSTAFFBLINK5
+ {SPR_CSSF, 2, 1, A_WeaponReady, S_CSTAFFBLINK7, 0, 0}, // S_CSTAFFBLINK6
+ {SPR_CSSF, 2, 1, A_WeaponReady, S_CSTAFFBLINK8, 0, 0}, // S_CSTAFFBLINK7
+ {SPR_CSSF, 2, 1, A_WeaponReady, S_CSTAFFBLINK9, 0, 0}, // S_CSTAFFBLINK8
+ {SPR_CSSF, 1, 1, A_WeaponReady, S_CSTAFFBLINK10, 0, 0}, // S_CSTAFFBLINK9
+ {SPR_CSSF, 1, 1, A_WeaponReady, S_CSTAFFBLINK11, 0, 0}, // S_CSTAFFBLINK10
+ {SPR_CSSF, 1, 1, A_WeaponReady, S_CSTAFFREADY2, 0, 0}, // S_CSTAFFBLINK11
+ {SPR_CSSF, 1, 3, NULL, S_CSTAFFDOWN2, 0, 0}, // S_CSTAFFDOWN
+ {SPR_CSSF, 2, 4, NULL, S_CSTAFFDOWN3, 0, 0}, // S_CSTAFFDOWN2
+ {SPR_CSSF, 2, 1, A_Lower, S_CSTAFFDOWN3, 0, 0}, // S_CSTAFFDOWN3
+ {SPR_CSSF, 2, 1, A_Raise, S_CSTAFFUP, 0, 0}, // S_CSTAFFUP
+ {SPR_CSSF, 0, 1, A_CStaffCheck, S_CSTAFFATK_2, 0, 45}, // S_CSTAFFATK_1
+ {SPR_CSSF, 9, 1, A_CStaffAttack, S_CSTAFFATK_3, 0, 50}, // S_CSTAFFATK_2
+ {SPR_CSSF, 9, 2, NULL, S_CSTAFFATK_4, 0, 50}, // S_CSTAFFATK_3
+ {SPR_CSSF, 9, 2, NULL, S_CSTAFFATK_5, 0, 45}, // S_CSTAFFATK_4
+ {SPR_CSSF, 0, 2, NULL, S_CSTAFFATK_6, 0, 40}, // S_CSTAFFATK_5
+ {SPR_CSSF, 0, 2, NULL, S_CSTAFFREADY2, 0, 36}, // S_CSTAFFATK_6
+ {SPR_CSSF, 10, 10, NULL, S_CSTAFFREADY2, 0, 36}, // S_CSTAFFATK2_1
+ {SPR_CSSF, 32771, 1, A_CStaffMissileSlither, S_CSTAFF_MISSILE2, 0, 0}, // S_CSTAFF_MISSILE1
+ {SPR_CSSF, 32771, 1, A_CStaffMissileSlither, S_CSTAFF_MISSILE3, 0, 0}, // S_CSTAFF_MISSILE2
+ {SPR_CSSF, 32772, 1, A_CStaffMissileSlither, S_CSTAFF_MISSILE4, 0, 0}, // S_CSTAFF_MISSILE3
+ {SPR_CSSF, 32772, 1, A_CStaffMissileSlither, S_CSTAFF_MISSILE1, 0, 0}, // S_CSTAFF_MISSILE4
+ {SPR_CSSF, 32773, 4, NULL, S_CSTAFF_MISSILE_X2, 0, 0}, // S_CSTAFF_MISSILE_X1
+ {SPR_CSSF, 32774, 4, NULL, S_CSTAFF_MISSILE_X3, 0, 0}, // S_CSTAFF_MISSILE_X2
+ {SPR_CSSF, 32775, 3, NULL, S_CSTAFF_MISSILE_X4, 0, 0}, // S_CSTAFF_MISSILE_X3
+ {SPR_CSSF, 32776, 3, NULL, S_NULL, 0, 0}, // S_CSTAFF_MISSILE_X4
+ {SPR_FHFX, 18, 4, NULL, S_CSTAFFPUFF2, 0, 0}, // S_CSTAFFPUFF1
+ {SPR_FHFX, 19, 4, NULL, S_CSTAFFPUFF3, 0, 0}, // S_CSTAFFPUFF2
+ {SPR_FHFX, 20, 4, NULL, S_CSTAFFPUFF4, 0, 0}, // S_CSTAFFPUFF3
+ {SPR_FHFX, 21, 4, NULL, S_CSTAFFPUFF5, 0, 0}, // S_CSTAFFPUFF4
+ {SPR_FHFX, 22, 4, NULL, S_NULL, 0, 0}, // S_CSTAFFPUFF5
+ {SPR_WCFM, 32768, 4, NULL, S_CFLAME2, 0, 0}, // S_CFLAME1
+ {SPR_WCFM, 32769, 4, NULL, S_CFLAME3, 0, 0}, // S_CFLAME2
+ {SPR_WCFM, 32770, 4, NULL, S_CFLAME4, 0, 0}, // S_CFLAME3
+ {SPR_WCFM, 32771, 4, NULL, S_CFLAME5, 0, 0}, // S_CFLAME4
+ {SPR_WCFM, 32772, 4, NULL, S_CFLAME6, 0, 0}, // S_CFLAME5
+ {SPR_WCFM, 32773, 4, NULL, S_CFLAME7, 0, 0}, // S_CFLAME6
+ {SPR_WCFM, 32774, 4, NULL, S_CFLAME8, 0, 0}, // S_CFLAME7
+ {SPR_WCFM, 32775, 4, NULL, S_CFLAME1, 0, 0}, // S_CFLAME8
+ {SPR_CFLM, 0, 1, A_WeaponReady, S_CFLAMEREADY2, 0, 0}, // S_CFLAMEREADY1
+ {SPR_CFLM, 0, 1, A_WeaponReady, S_CFLAMEREADY3, 0, 0}, // S_CFLAMEREADY2
+ {SPR_CFLM, 0, 1, A_WeaponReady, S_CFLAMEREADY4, 0, 0}, // S_CFLAMEREADY3
+ {SPR_CFLM, 0, 1, A_WeaponReady, S_CFLAMEREADY5, 0, 0}, // S_CFLAMEREADY4
+ {SPR_CFLM, 1, 1, A_WeaponReady, S_CFLAMEREADY6, 0, 0}, // S_CFLAMEREADY5
+ {SPR_CFLM, 1, 1, A_WeaponReady, S_CFLAMEREADY7, 0, 0}, // S_CFLAMEREADY6
+ {SPR_CFLM, 1, 1, A_WeaponReady, S_CFLAMEREADY8, 0, 0}, // S_CFLAMEREADY7
+ {SPR_CFLM, 1, 1, A_WeaponReady, S_CFLAMEREADY9, 0, 0}, // S_CFLAMEREADY8
+ {SPR_CFLM, 2, 1, A_WeaponReady, S_CFLAMEREADY10, 0, 0}, // S_CFLAMEREADY9
+ {SPR_CFLM, 2, 1, A_WeaponReady, S_CFLAMEREADY11, 0, 0}, // S_CFLAMEREADY10
+ {SPR_CFLM, 2, 1, A_WeaponReady, S_CFLAMEREADY12, 0, 0}, // S_CFLAMEREADY11
+ {SPR_CFLM, 2, 1, A_WeaponReady, S_CFLAMEREADY1, 0, 0}, // S_CFLAMEREADY12
+ {SPR_CFLM, 0, 1, A_Lower, S_CFLAMEDOWN, 0, 0}, // S_CFLAMEDOWN
+ {SPR_CFLM, 0, 1, A_Raise, S_CFLAMEUP, 0, 0}, // S_CFLAMEUP
+ {SPR_CFLM, 0, 2, NULL, S_CFLAMEATK_2, 0, 40}, // S_CFLAMEATK_1
+ {SPR_CFLM, 3, 2, NULL, S_CFLAMEATK_3, 0, 50}, // S_CFLAMEATK_2
+ {SPR_CFLM, 3, 2, NULL, S_CFLAMEATK_4, 0, 36}, // S_CFLAMEATK_3
+ {SPR_CFLM, 32772, 4, NULL, S_CFLAMEATK_5, 0, 0}, // S_CFLAMEATK_4
+ {SPR_CFLM, 32773, 4, A_CFlameAttack, S_CFLAMEATK_6, 0, 0}, // S_CFLAMEATK_5
+ {SPR_CFLM, 32772, 4, NULL, S_CFLAMEATK_7, 0, 0}, // S_CFLAMEATK_6
+ {SPR_CFLM, 6, 2, NULL, S_CFLAMEATK_8, 0, 40}, // S_CFLAMEATK_7
+ {SPR_CFLM, 6, 2, NULL, S_CFLAMEREADY1, 0, 0}, // S_CFLAMEATK_8
+ {SPR_CFFX, 32781, 5, NULL, S_CFLAMEFLOOR2, 0, 0}, // S_CFLAMEFLOOR1
+ {SPR_CFFX, 32782, 4, NULL, S_CFLAMEFLOOR3, 0, 0}, // S_CFLAMEFLOOR2
+ {SPR_CFFX, 32783, 3, NULL, S_NULL, 0, 0}, // S_CFLAMEFLOOR3
+ {SPR_CFFX, 32768, 3, NULL, S_FLAMEPUFF2, 0, 0}, // S_FLAMEPUFF1
+ {SPR_CFFX, 32769, 3, NULL, S_FLAMEPUFF3, 0, 0}, // S_FLAMEPUFF2
+ {SPR_CFFX, 32770, 3, NULL, S_FLAMEPUFF4, 0, 0}, // S_FLAMEPUFF3
+ {SPR_CFFX, 32771, 4, NULL, S_FLAMEPUFF5, 0, 0}, // S_FLAMEPUFF4
+ {SPR_CFFX, 32772, 3, NULL, S_FLAMEPUFF6, 0, 0}, // S_FLAMEPUFF5
+ {SPR_CFFX, 32773, 4, NULL, S_FLAMEPUFF7, 0, 0}, // S_FLAMEPUFF6
+ {SPR_CFFX, 32774, 3, NULL, S_FLAMEPUFF8, 0, 0}, // S_FLAMEPUFF7
+ {SPR_CFFX, 32775, 4, NULL, S_FLAMEPUFF9, 0, 0}, // S_FLAMEPUFF8
+ {SPR_CFFX, 32776, 3, NULL, S_FLAMEPUFF10, 0, 0}, // S_FLAMEPUFF9
+ {SPR_CFFX, 32777, 4, NULL, S_FLAMEPUFF11, 0, 0}, // S_FLAMEPUFF10
+ {SPR_CFFX, 32778, 3, NULL, S_FLAMEPUFF12, 0, 0}, // S_FLAMEPUFF11
+ {SPR_CFFX, 32779, 4, NULL, S_FLAMEPUFF13, 0, 0}, // S_FLAMEPUFF12
+ {SPR_CFFX, 32780, 3, NULL, S_NULL, 0, 0}, // S_FLAMEPUFF13
+ {SPR_CFFX, 32768, 3, NULL, S_FLAMEPUFF2_2, 0, 0}, // S_FLAMEPUFF2_1
+ {SPR_CFFX, 32769, 3, NULL, S_FLAMEPUFF2_3, 0, 0}, // S_FLAMEPUFF2_2
+ {SPR_CFFX, 32770, 3, NULL, S_FLAMEPUFF2_4, 0, 0}, // S_FLAMEPUFF2_3
+ {SPR_CFFX, 32771, 4, NULL, S_FLAMEPUFF2_5, 0, 0}, // S_FLAMEPUFF2_4
+ {SPR_CFFX, 32772, 3, NULL, S_FLAMEPUFF2_6, 0, 0}, // S_FLAMEPUFF2_5
+ {SPR_CFFX, 32773, 4, NULL, S_FLAMEPUFF2_7, 0, 0}, // S_FLAMEPUFF2_6
+ {SPR_CFFX, 32774, 3, NULL, S_FLAMEPUFF2_8, 0, 0}, // S_FLAMEPUFF2_7
+ {SPR_CFFX, 32775, 4, NULL, S_FLAMEPUFF2_9, 0, 0}, // S_FLAMEPUFF2_8
+ {SPR_CFFX, 32776, 3, NULL, S_FLAMEPUFF2_10, 0, 0}, // S_FLAMEPUFF2_9
+ {SPR_CFFX, 32770, 3, NULL, S_FLAMEPUFF2_11, 0, 0}, // S_FLAMEPUFF2_10
+ {SPR_CFFX, 32771, 4, NULL, S_FLAMEPUFF2_12, 0, 0}, // S_FLAMEPUFF2_11
+ {SPR_CFFX, 32772, 3, NULL, S_FLAMEPUFF2_13, 0, 0}, // S_FLAMEPUFF2_12
+ {SPR_CFFX, 32773, 4, NULL, S_FLAMEPUFF2_14, 0, 0}, // S_FLAMEPUFF2_13
+ {SPR_CFFX, 32774, 3, NULL, S_FLAMEPUFF2_15, 0, 0}, // S_FLAMEPUFF2_14
+ {SPR_CFFX, 32775, 4, NULL, S_FLAMEPUFF2_16, 0, 0}, // S_FLAMEPUFF2_15
+ {SPR_CFFX, 32776, 3, NULL, S_FLAMEPUFF2_17, 0, 0}, // S_FLAMEPUFF2_16
+ {SPR_CFFX, 32777, 4, NULL, S_FLAMEPUFF2_18, 0, 0}, // S_FLAMEPUFF2_17
+ {SPR_CFFX, 32778, 3, NULL, S_FLAMEPUFF2_19, 0, 0}, // S_FLAMEPUFF2_18
+ {SPR_CFFX, 32779, 4, NULL, S_FLAMEPUFF2_20, 0, 0}, // S_FLAMEPUFF2_19
+ {SPR_CFFX, 32780, 3, NULL, S_NULL, 0, 0}, // S_FLAMEPUFF2_20
+ {SPR_CFCF, 32768, 4, NULL, S_CIRCLE_FLAME2, 0, 0}, // S_CIRCLE_FLAME1
+ {SPR_CFCF, 32769, 2, A_CFlameRotate, S_CIRCLE_FLAME3, 0, 0}, // S_CIRCLE_FLAME2
+ {SPR_CFCF, 32770, 2, NULL, S_CIRCLE_FLAME4, 0, 0}, // S_CIRCLE_FLAME3
+ {SPR_CFCF, 32771, 1, NULL, S_CIRCLE_FLAME5, 0, 0}, // S_CIRCLE_FLAME4
+ {SPR_CFCF, 32772, 2, NULL, S_CIRCLE_FLAME6, 0, 0}, // S_CIRCLE_FLAME5
+ {SPR_CFCF, 32773, 2, A_CFlameRotate, S_CIRCLE_FLAME7, 0, 0}, // S_CIRCLE_FLAME6
+ {SPR_CFCF, 32774, 1, NULL, S_CIRCLE_FLAME8, 0, 0}, // S_CIRCLE_FLAME7
+ {SPR_CFCF, 32775, 2, NULL, S_CIRCLE_FLAME9, 0, 0}, // S_CIRCLE_FLAME8
+ {SPR_CFCF, 32776, 2, NULL, S_CIRCLE_FLAME10, 0, 0}, // S_CIRCLE_FLAME9
+ {SPR_CFCF, 32777, 1, A_CFlameRotate, S_CIRCLE_FLAME11, 0, 0}, // S_CIRCLE_FLAME10
+ {SPR_CFCF, 32778, 2, NULL, S_CIRCLE_FLAME12, 0, 0}, // S_CIRCLE_FLAME11
+ {SPR_CFCF, 32779, 3, NULL, S_CIRCLE_FLAME13, 0, 0}, // S_CIRCLE_FLAME12
+ {SPR_CFCF, 32780, 3, NULL, S_CIRCLE_FLAME14, 0, 0}, // S_CIRCLE_FLAME13
+ {SPR_CFCF, 32781, 2, A_CFlameRotate, S_CIRCLE_FLAME15, 0, 0}, // S_CIRCLE_FLAME14
+ {SPR_CFCF, 32782, 3, NULL, S_CIRCLE_FLAME16, 0, 0}, // S_CIRCLE_FLAME15
+ {SPR_CFCF, 32783, 2, NULL, S_NULL, 0, 0}, // S_CIRCLE_FLAME16
+ {SPR_CFCF, 32784, 3, NULL, S_CIRCLE_FLAME_X2, 0, 0}, // S_CIRCLE_FLAME_X1
+ {SPR_CFCF, 32785, 3, NULL, S_CIRCLE_FLAME_X3, 0, 0}, // S_CIRCLE_FLAME_X2
+ {SPR_CFCF, 32786, 3, A_Explode, S_CIRCLE_FLAME_X4, 0, 0}, // S_CIRCLE_FLAME_X3
+ {SPR_CFCF, 32787, 3, NULL, S_CIRCLE_FLAME_X5, 0, 0}, // S_CIRCLE_FLAME_X4
+ {SPR_CFCF, 32788, 3, NULL, S_CIRCLE_FLAME_X6, 0, 0}, // S_CIRCLE_FLAME_X5
+ {SPR_CFCF, 32789, 3, NULL, S_CIRCLE_FLAME_X7, 0, 0}, // S_CIRCLE_FLAME_X6
+ {SPR_CFCF, 32790, 3, NULL, S_CIRCLE_FLAME_X8, 0, 0}, // S_CIRCLE_FLAME_X7
+ {SPR_CFCF, 32791, 3, NULL, S_CIRCLE_FLAME_X9, 0, 0}, // S_CIRCLE_FLAME_X8
+ {SPR_CFCF, 32792, 3, NULL, S_CIRCLE_FLAME_X10, 0, 0}, // S_CIRCLE_FLAME_X9
+ {SPR_CFCF, 32793, 3, NULL, S_NULL, 0, 0}, // S_CIRCLE_FLAME_X10
+ {SPR_CFFX, 32768, 4, NULL, S_CFLAME_MISSILE2, 0, 0}, // S_CFLAME_MISSILE1
+ {SPR_CFFX, 0, 1, A_CFlamePuff, S_FLAMEPUFF1, 0, 0}, // S_CFLAME_MISSILE2
+ {SPR_CFFX, 32768, 1, A_CFlameMissile, S_FLAMEPUFF1, 0, 0}, // S_CFLAME_MISSILE_X
+ {SPR_CHLY, 0, 1, A_WeaponReady, S_CHOLYREADY, 0, 0}, // S_CHOLYREADY
+ {SPR_CHLY, 0, 1, A_Lower, S_CHOLYDOWN, 0, 0}, // S_CHOLYDOWN
+ {SPR_CHLY, 0, 1, A_Raise, S_CHOLYUP, 0, 0}, // S_CHOLYUP
+ {SPR_CHLY, 32768, 1, NULL, S_CHOLYATK_2, 0, 40}, // S_CHOLYATK_1
+ {SPR_CHLY, 32769, 1, NULL, S_CHOLYATK_3, 0, 40}, // S_CHOLYATK_2
+ {SPR_CHLY, 32770, 2, NULL, S_CHOLYATK_4, 0, 43}, // S_CHOLYATK_3
+ {SPR_CHLY, 32771, 2, NULL, S_CHOLYATK_5, 0, 43}, // S_CHOLYATK_4
+ {SPR_CHLY, 32772, 2, NULL, S_CHOLYATK_6, 0, 45}, // S_CHOLYATK_5
+ {SPR_CHLY, 32773, 6, A_CHolyAttack, S_CHOLYATK_7, 0, 48}, // S_CHOLYATK_6
+ {SPR_CHLY, 32774, 2, A_CHolyPalette, S_CHOLYATK_8, 0, 40}, // S_CHOLYATK_7
+ {SPR_CHLY, 32774, 2, A_CHolyPalette, S_CHOLYATK_9, 0, 40}, // S_CHOLYATK_8
+ {SPR_CHLY, 32774, 2, A_CHolyPalette, S_CHOLYREADY, 0, 36}, // S_CHOLYATK_9
+ {SPR_SPIR, 0, 2, A_CHolySeek, S_HOLY_FX2, 0, 0}, // S_HOLY_FX1
+ {SPR_SPIR, 0, 2, A_CHolySeek, S_HOLY_FX3, 0, 0}, // S_HOLY_FX2
+ {SPR_SPIR, 1, 2, A_CHolySeek, S_HOLY_FX4, 0, 0}, // S_HOLY_FX3
+ {SPR_SPIR, 1, 2, A_CHolyCheckScream, S_HOLY_FX1, 0, 0}, // S_HOLY_FX4
+ {SPR_SPIR, 3, 4, NULL, S_HOLY_FX_X2, 0, 0}, // S_HOLY_FX_X1
+ {SPR_SPIR, 4, 4, A_Scream, S_HOLY_FX_X3, 0, 0}, // S_HOLY_FX_X2
+ {SPR_SPIR, 5, 4, NULL, S_HOLY_FX_X4, 0, 0}, // S_HOLY_FX_X3
+ {SPR_SPIR, 6, 4, NULL, S_HOLY_FX_X5, 0, 0}, // S_HOLY_FX_X4
+ {SPR_SPIR, 7, 4, NULL, S_HOLY_FX_X6, 0, 0}, // S_HOLY_FX_X5
+ {SPR_SPIR, 8, 4, NULL, S_NULL, 0, 0}, // S_HOLY_FX_X6
+ {SPR_SPIR, 2, 1, A_CHolyTail, S_HOLY_TAIL1, 0, 0}, // S_HOLY_TAIL1
+ {SPR_SPIR, 3, -1, NULL, S_NULL, 0, 0}, // S_HOLY_TAIL2
+ {SPR_SPIR, 10, 3, NULL, S_HOLY_PUFF2, 0, 0}, // S_HOLY_PUFF1
+ {SPR_SPIR, 11, 3, NULL, S_HOLY_PUFF3, 0, 0}, // S_HOLY_PUFF2
+ {SPR_SPIR, 12, 3, NULL, S_HOLY_PUFF4, 0, 0}, // S_HOLY_PUFF3
+ {SPR_SPIR, 13, 3, NULL, S_HOLY_PUFF5, 0, 0}, // S_HOLY_PUFF4
+ {SPR_SPIR, 14, 3, NULL, S_NULL, 0, 0}, // S_HOLY_PUFF5
+ {SPR_SPIR, 32783, 3, A_CHolySpawnPuff, S_HOLY_MISSILE2, 0, 0}, // S_HOLY_MISSILE1
+ {SPR_SPIR, 32783, 3, A_CHolySpawnPuff, S_HOLY_MISSILE3, 0, 0}, // S_HOLY_MISSILE2
+ {SPR_SPIR, 32783, 3, A_CHolySpawnPuff, S_HOLY_MISSILE4, 0, 0}, // S_HOLY_MISSILE3
+ {SPR_SPIR, 32783, 3, A_CHolySpawnPuff, S_HOLY_MISSILE_X, 0, 0}, // S_HOLY_MISSILE4
+ {SPR_SPIR, 32783, 1, A_CHolyAttack2, S_NULL, 0, 0}, // S_HOLY_MISSILE_X
+ {SPR_SPIR, 16, 3, NULL, S_HOLY_MISSILE_P2, 0, 0}, // S_HOLY_MISSILE_P1
+ {SPR_SPIR, 17, 3, NULL, S_HOLY_MISSILE_P3, 0, 0}, // S_HOLY_MISSILE_P2
+ {SPR_SPIR, 18, 3, NULL, S_HOLY_MISSILE_P4, 0, 0}, // S_HOLY_MISSILE_P3
+ {SPR_SPIR, 19, 3, NULL, S_HOLY_MISSILE_P5, 0, 0}, // S_HOLY_MISSILE_P4
+ {SPR_SPIR, 20, 3, NULL, S_NULL, 0, 0}, // S_HOLY_MISSILE_P5
+ {SPR_MWND, 0, 1, A_WeaponReady, S_MWANDREADY, 0, 0}, // S_MWANDREADY
+ {SPR_MWND, 0, 1, A_Lower, S_MWANDDOWN, 0, 0}, // S_MWANDDOWN
+ {SPR_MWND, 0, 1, A_Raise, S_MWANDUP, 0, 0}, // S_MWANDUP
+ {SPR_MWND, 0, 6, NULL, S_MWANDATK_2, 0, 0}, // S_MWANDATK_1
+ {SPR_MWND, 32769, 6, A_MWandAttack, S_MWANDATK_3, 0, 48}, // S_MWANDATK_2
+ {SPR_MWND, 0, 3, NULL, S_MWANDATK_4, 0, 40}, // S_MWANDATK_3
+ {SPR_MWND, 0, 3, A_ReFire, S_MWANDREADY, 0, 36}, // S_MWANDATK_4
+ {SPR_MWND, 32772, 4, NULL, S_MWANDPUFF2, 0, 0}, // S_MWANDPUFF1
+ {SPR_MWND, 32773, 3, NULL, S_MWANDPUFF3, 0, 0}, // S_MWANDPUFF2
+ {SPR_MWND, 32774, 4, NULL, S_MWANDPUFF4, 0, 0}, // S_MWANDPUFF3
+ {SPR_MWND, 32775, 3, NULL, S_MWANDPUFF5, 0, 0}, // S_MWANDPUFF4
+ {SPR_MWND, 32776, 4, NULL, S_NULL, 0, 0}, // S_MWANDPUFF5
+ {SPR_MWND, 2, 4, NULL, S_MWANDSMOKE2, 0, 0}, // S_MWANDSMOKE1
+ {SPR_MWND, 3, 4, NULL, S_MWANDSMOKE3, 0, 0}, // S_MWANDSMOKE2
+ {SPR_MWND, 2, 4, NULL, S_MWANDSMOKE4, 0, 0}, // S_MWANDSMOKE3
+ {SPR_MWND, 3, 4, NULL, S_NULL, 0, 0}, // S_MWANDSMOKE4
+ {SPR_MWND, 32770, 4, NULL, S_MWAND_MISSILE2, 0, 0}, // S_MWAND_MISSILE1
+ {SPR_MWND, 32771, 4, NULL, S_MWAND_MISSILE1, 0, 0}, // S_MWAND_MISSILE2
+ {SPR_WMLG, 32768, 4, NULL, S_MW_LIGHTNING2, 0, 0}, // S_MW_LIGHTNING1
+ {SPR_WMLG, 32769, 4, NULL, S_MW_LIGHTNING3, 0, 0}, // S_MW_LIGHTNING2
+ {SPR_WMLG, 32770, 4, NULL, S_MW_LIGHTNING4, 0, 0}, // S_MW_LIGHTNING3
+ {SPR_WMLG, 32771, 4, NULL, S_MW_LIGHTNING5, 0, 0}, // S_MW_LIGHTNING4
+ {SPR_WMLG, 32772, 4, NULL, S_MW_LIGHTNING6, 0, 0}, // S_MW_LIGHTNING5
+ {SPR_WMLG, 32773, 4, NULL, S_MW_LIGHTNING7, 0, 0}, // S_MW_LIGHTNING6
+ {SPR_WMLG, 32774, 4, NULL, S_MW_LIGHTNING8, 0, 0}, // S_MW_LIGHTNING7
+ {SPR_WMLG, 32775, 4, NULL, S_MW_LIGHTNING1, 0, 0}, // S_MW_LIGHTNING8
+ {SPR_MLNG, 32768, 1, A_WeaponReady, S_MLIGHTNINGREADY2, 0, 0}, // S_MLIGHTNINGREADY
+ {SPR_MLNG, 32768, 1, A_WeaponReady, S_MLIGHTNINGREADY3, 0, 0}, // S_MLIGHTNINGREADY2
+ {SPR_MLNG, 32768, 1, A_WeaponReady, S_MLIGHTNINGREADY4, 0, 0}, // S_MLIGHTNINGREADY3
+ {SPR_MLNG, 32768, 1, A_WeaponReady, S_MLIGHTNINGREADY5, 0, 0}, // S_MLIGHTNINGREADY4
+ {SPR_MLNG, 32768, 1, A_WeaponReady, S_MLIGHTNINGREADY6, 0, 0}, // S_MLIGHTNINGREADY5
+ {SPR_MLNG, 32768, 1, A_LightningReady, S_MLIGHTNINGREADY7, 0, 0}, // S_MLIGHTNINGREADY6
+ {SPR_MLNG, 32769, 1, A_WeaponReady, S_MLIGHTNINGREADY8, 0, 0}, // S_MLIGHTNINGREADY7
+ {SPR_MLNG, 32769, 1, A_WeaponReady, S_MLIGHTNINGREADY9, 0, 0}, // S_MLIGHTNINGREADY8
+ {SPR_MLNG, 32769, 1, A_WeaponReady, S_MLIGHTNINGREADY10, 0, 0}, // S_MLIGHTNINGREADY9
+ {SPR_MLNG, 32769, 1, A_WeaponReady, S_MLIGHTNINGREADY11, 0, 0}, // S_MLIGHTNINGREADY10
+ {SPR_MLNG, 32769, 1, A_WeaponReady, S_MLIGHTNINGREADY12, 0, 0}, // S_MLIGHTNINGREADY11
+ {SPR_MLNG, 32769, 1, A_WeaponReady, S_MLIGHTNINGREADY13, 0, 0}, // S_MLIGHTNINGREADY12
+ {SPR_MLNG, 32770, 1, A_WeaponReady, S_MLIGHTNINGREADY14, 0, 0}, // S_MLIGHTNINGREADY13
+ {SPR_MLNG, 32770, 1, A_WeaponReady, S_MLIGHTNINGREADY15, 0, 0}, // S_MLIGHTNINGREADY14
+ {SPR_MLNG, 32770, 1, A_WeaponReady, S_MLIGHTNINGREADY16, 0, 0}, // S_MLIGHTNINGREADY15
+ {SPR_MLNG, 32770, 1, A_WeaponReady, S_MLIGHTNINGREADY17, 0, 0}, // S_MLIGHTNINGREADY16
+ {SPR_MLNG, 32770, 1, A_WeaponReady, S_MLIGHTNINGREADY18, 0, 0}, // S_MLIGHTNINGREADY17
+ {SPR_MLNG, 32770, 1, A_LightningReady, S_MLIGHTNINGREADY19, 0, 0}, // S_MLIGHTNINGREADY18
+ {SPR_MLNG, 32769, 1, A_WeaponReady, S_MLIGHTNINGREADY20, 0, 0}, // S_MLIGHTNINGREADY19
+ {SPR_MLNG, 32769, 1, A_WeaponReady, S_MLIGHTNINGREADY21, 0, 0}, // S_MLIGHTNINGREADY20
+ {SPR_MLNG, 32769, 1, A_WeaponReady, S_MLIGHTNINGREADY22, 0, 0}, // S_MLIGHTNINGREADY21
+ {SPR_MLNG, 32769, 1, A_WeaponReady, S_MLIGHTNINGREADY23, 0, 0}, // S_MLIGHTNINGREADY22
+ {SPR_MLNG, 32769, 1, A_WeaponReady, S_MLIGHTNINGREADY24, 0, 0}, // S_MLIGHTNINGREADY23
+ {SPR_MLNG, 32769, 1, A_WeaponReady, S_MLIGHTNINGREADY, 0, 0}, // S_MLIGHTNINGREADY24
+ {SPR_MLNG, 32768, 1, A_Lower, S_MLIGHTNINGDOWN, 0, 0}, // S_MLIGHTNINGDOWN
+ {SPR_MLNG, 32768, 1, A_Raise, S_MLIGHTNINGUP, 0, 0}, // S_MLIGHTNINGUP
+ {SPR_MLNG, 32771, 3, NULL, S_MLIGHTNINGATK_2, 0, 0}, // S_MLIGHTNINGATK_1
+ {SPR_MLNG, 32772, 3, NULL, S_MLIGHTNINGATK_3, 0, 0}, // S_MLIGHTNINGATK_2
+ {SPR_MLNG, 32773, 4, A_MLightningAttack, S_MLIGHTNINGATK_4, 0, 0}, // S_MLIGHTNINGATK_3
+ {SPR_MLNG, 32774, 4, NULL, S_MLIGHTNINGATK_5, 0, 0}, // S_MLIGHTNINGATK_4
+ {SPR_MLNG, 32775, 3, NULL, S_MLIGHTNINGATK_6, 0, 0}, // S_MLIGHTNINGATK_5
+ {SPR_MLNG, 32776, 3, NULL, S_MLIGHTNINGATK_7, 0, 0}, // S_MLIGHTNINGATK_6
+ {SPR_MLNG, 32776, 6, NULL, S_MLIGHTNINGATK_8, 0, 199}, // S_MLIGHTNINGATK_7
+ {SPR_MLNG, 32770, 2, NULL, S_MLIGHTNINGATK_9, 0, 55}, // S_MLIGHTNINGATK_8
+ {SPR_MLNG, 32769, 2, NULL, S_MLIGHTNINGATK_10, 0, 50}, // S_MLIGHTNINGATK_9
+ {SPR_MLNG, 32769, 2, NULL, S_MLIGHTNINGATK_11, 0, 45}, // S_MLIGHTNINGATK_10
+ {SPR_MLNG, 32769, 2, NULL, S_MLIGHTNINGREADY, 0, 40}, // S_MLIGHTNINGATK_11
+ {SPR_MLFX, 32768, 2, A_LightningZap, S_LIGHTNING_CEILING2, 0, 0}, // S_LIGHTNING_CEILING1
+ {SPR_MLFX, 32769, 2, A_LightningClip, S_LIGHTNING_CEILING3, 0, 0}, // S_LIGHTNING_CEILING2
+ {SPR_MLFX, 32770, 2, A_LightningClip, S_LIGHTNING_CEILING4, 0, 0}, // S_LIGHTNING_CEILING3
+ {SPR_MLFX, 32771, 2, A_LightningClip, S_LIGHTNING_CEILING1, 0, 0}, // S_LIGHTNING_CEILING4
+ {SPR_MLF2, 32768, 2, A_LightningRemove, S_LIGHTNING_C_X2, 0, 0}, // S_LIGHTNING_C_X1
+ {SPR_MLF2, 32769, 3, NULL, S_LIGHTNING_C_X3, 0, 0}, // S_LIGHTNING_C_X2
+ {SPR_MLF2, 32770, 3, NULL, S_LIGHTNING_C_X4, 0, 0}, // S_LIGHTNING_C_X3
+ {SPR_MLF2, 32771, 3, NULL, S_LIGHTNING_C_X5, 0, 0}, // S_LIGHTNING_C_X4
+ {SPR_MLF2, 32772, 3, NULL, S_LIGHTNING_C_X6, 0, 0}, // S_LIGHTNING_C_X5
+ {SPR_MLF2, 32778, 3, NULL, S_LIGHTNING_C_X7, 0, 0}, // S_LIGHTNING_C_X6
+ {SPR_MLF2, 32779, 3, NULL, S_LIGHTNING_C_X8, 0, 0}, // S_LIGHTNING_C_X7
+ {SPR_MLF2, 32780, 3, NULL, S_LIGHTNING_C_X9, 0, 0}, // S_LIGHTNING_C_X8
+ {SPR_ACLO, 4, 35, NULL, S_LIGHTNING_C_X10, 0, 0}, // S_LIGHTNING_C_X9
+ {SPR_MLF2, 32781, 3, NULL, S_LIGHTNING_C_X11, 0, 0}, // S_LIGHTNING_C_X10
+ {SPR_MLF2, 32782, 3, NULL, S_LIGHTNING_C_X12, 0, 0}, // S_LIGHTNING_C_X11
+ {SPR_MLF2, 32783, 4, NULL, S_LIGHTNING_C_X13, 0, 0}, // S_LIGHTNING_C_X12
+ {SPR_MLF2, 32784, 3, NULL, S_LIGHTNING_C_X14, 0, 0}, // S_LIGHTNING_C_X13
+ {SPR_MLF2, 32783, 3, NULL, S_LIGHTNING_C_X15, 0, 0}, // S_LIGHTNING_C_X14
+ {SPR_MLF2, 32784, 4, NULL, S_LIGHTNING_C_X16, 0, 0}, // S_LIGHTNING_C_X15
+ {SPR_MLF2, 32783, 3, NULL, S_LIGHTNING_C_X17, 0, 0}, // S_LIGHTNING_C_X16
+ {SPR_MLF2, 32782, 3, NULL, S_LIGHTNING_C_X18, 0, 0}, // S_LIGHTNING_C_X17
+ {SPR_MLF2, 32783, 3, NULL, S_LIGHTNING_C_X19, 0, 0}, // S_LIGHTNING_C_X18
+ {SPR_MLF2, 32783, 1, A_HideThing, S_FREETARGMOBJ, 0, 0}, // S_LIGHTNING_C_X19
+ {SPR_MLFX, 32772, 2, A_LightningZap, S_LIGHTNING_FLOOR2, 0, 0}, // S_LIGHTNING_FLOOR1
+ {SPR_MLFX, 32773, 2, A_LightningClip, S_LIGHTNING_FLOOR3, 0, 0}, // S_LIGHTNING_FLOOR2
+ {SPR_MLFX, 32774, 2, A_LightningClip, S_LIGHTNING_FLOOR4, 0, 0}, // S_LIGHTNING_FLOOR3
+ {SPR_MLFX, 32775, 2, A_LightningClip, S_LIGHTNING_FLOOR1, 0, 0}, // S_LIGHTNING_FLOOR4
+ {SPR_MLF2, 32773, 2, A_LightningRemove, S_LIGHTNING_F_X2, 0, 0}, // S_LIGHTNING_F_X1
+ {SPR_MLF2, 32774, 3, NULL, S_LIGHTNING_F_X3, 0, 0}, // S_LIGHTNING_F_X2
+ {SPR_MLF2, 32775, 3, NULL, S_LIGHTNING_F_X4, 0, 0}, // S_LIGHTNING_F_X3
+ {SPR_MLF2, 32776, 3, NULL, S_LIGHTNING_F_X5, 0, 0}, // S_LIGHTNING_F_X4
+ {SPR_MLF2, 32777, 3, NULL, S_LIGHTNING_F_X6, 0, 0}, // S_LIGHTNING_F_X5
+ {SPR_MLF2, 32778, 3, NULL, S_LIGHTNING_F_X7, 0, 0}, // S_LIGHTNING_F_X6
+ {SPR_MLF2, 32779, 3, NULL, S_LIGHTNING_F_X8, 0, 0}, // S_LIGHTNING_F_X7
+ {SPR_MLF2, 32780, 3, NULL, S_LIGHTNING_F_X9, 0, 0}, // S_LIGHTNING_F_X8
+ {SPR_ACLO, 4, 20, NULL, S_LIGHTNING_F_X10, 0, 0}, // S_LIGHTNING_F_X9
+ {SPR_MLF2, 32781, 3, NULL, S_LIGHTNING_F_X11, 0, 0}, // S_LIGHTNING_F_X10
+ {SPR_MLF2, 32782, 3, NULL, S_LIGHTNING_F_X12, 0, 0}, // S_LIGHTNING_F_X11
+ {SPR_MLF2, 32783, 4, NULL, S_LIGHTNING_F_X13, 0, 0}, // S_LIGHTNING_F_X12
+ {SPR_MLF2, 32784, 3, NULL, S_LIGHTNING_F_X14, 0, 0}, // S_LIGHTNING_F_X13
+ {SPR_MLF2, 32783, 3, NULL, S_LIGHTNING_F_X15, 0, 0}, // S_LIGHTNING_F_X14
+ {SPR_MLF2, 32784, 4, A_LastZap, S_LIGHTNING_F_X16, 0, 0}, // S_LIGHTNING_F_X15
+ {SPR_MLF2, 32783, 3, NULL, S_LIGHTNING_F_X17, 0, 0}, // S_LIGHTNING_F_X16
+ {SPR_MLF2, 32782, 3, NULL, S_LIGHTNING_F_X18, 0, 0}, // S_LIGHTNING_F_X17
+ {SPR_MLF2, 32783, 3, NULL, S_LIGHTNING_F_X19, 0, 0}, // S_LIGHTNING_F_X18
+ {SPR_MLF2, 32783, 1, A_HideThing, S_FREETARGMOBJ, 0, 0}, // S_LIGHTNING_F_X19
+ {SPR_MLFX, 32776, 2, A_ZapMimic, S_LIGHTNING_ZAP2, 0, 0}, // S_LIGHTNING_ZAP1
+ {SPR_MLFX, 32777, 2, A_ZapMimic, S_LIGHTNING_ZAP3, 0, 0}, // S_LIGHTNING_ZAP2
+ {SPR_MLFX, 32778, 2, A_ZapMimic, S_LIGHTNING_ZAP4, 0, 0}, // S_LIGHTNING_ZAP3
+ {SPR_MLFX, 32779, 2, A_ZapMimic, S_LIGHTNING_ZAP5, 0, 0}, // S_LIGHTNING_ZAP4
+ {SPR_MLFX, 32780, 2, A_ZapMimic, S_LIGHTNING_ZAP1, 0, 0}, // S_LIGHTNING_ZAP5
+ {SPR_MLFX, 32781, 2, NULL, S_LIGHTNING_ZAP_X2, 0, 0}, // S_LIGHTNING_ZAP_X1
+ {SPR_MLFX, 32782, 2, NULL, S_LIGHTNING_ZAP_X3, 0, 0}, // S_LIGHTNING_ZAP_X2
+ {SPR_MLFX, 32783, 2, NULL, S_LIGHTNING_ZAP_X4, 0, 0}, // S_LIGHTNING_ZAP_X3
+ {SPR_MLFX, 32784, 2, NULL, S_LIGHTNING_ZAP_X5, 0, 0}, // S_LIGHTNING_ZAP_X4
+ {SPR_MLFX, 32785, 2, NULL, S_LIGHTNING_ZAP_X6, 0, 0}, // S_LIGHTNING_ZAP_X5
+ {SPR_MLFX, 32786, 2, NULL, S_LIGHTNING_ZAP_X7, 0, 0}, // S_LIGHTNING_ZAP_X6
+ {SPR_MLFX, 32787, 2, NULL, S_LIGHTNING_ZAP_X8, 0, 0}, // S_LIGHTNING_ZAP_X7
+ {SPR_MLFX, 32788, 2, NULL, S_NULL, 0, 0}, // S_LIGHTNING_ZAP_X8
+ {SPR_MSTF, 0, 1, A_WeaponReady, S_MSTAFFREADY2, 0, 0}, // S_MSTAFFREADY
+ {SPR_MSTF, 0, 1, A_WeaponReady, S_MSTAFFREADY3, 0, 0}, // S_MSTAFFREADY2
+ {SPR_MSTF, 0, 1, A_WeaponReady, S_MSTAFFREADY4, 0, 0}, // S_MSTAFFREADY3
+ {SPR_MSTF, 0, 1, A_WeaponReady, S_MSTAFFREADY5, 0, 0}, // S_MSTAFFREADY4
+ {SPR_MSTF, 0, 1, A_WeaponReady, S_MSTAFFREADY6, 0, 0}, // S_MSTAFFREADY5
+ {SPR_MSTF, 0, 1, A_WeaponReady, S_MSTAFFREADY7, 0, 0}, // S_MSTAFFREADY6
+ {SPR_MSTF, 1, 1, A_WeaponReady, S_MSTAFFREADY8, 0, 0}, // S_MSTAFFREADY7
+ {SPR_MSTF, 1, 1, A_WeaponReady, S_MSTAFFREADY9, 0, 0}, // S_MSTAFFREADY8
+ {SPR_MSTF, 1, 1, A_WeaponReady, S_MSTAFFREADY10, 0, 0}, // S_MSTAFFREADY9
+ {SPR_MSTF, 1, 1, A_WeaponReady, S_MSTAFFREADY11, 0, 0}, // S_MSTAFFREADY10
+ {SPR_MSTF, 1, 1, A_WeaponReady, S_MSTAFFREADY12, 0, 0}, // S_MSTAFFREADY11
+ {SPR_MSTF, 1, 1, A_WeaponReady, S_MSTAFFREADY13, 0, 0}, // S_MSTAFFREADY12
+ {SPR_MSTF, 2, 1, A_WeaponReady, S_MSTAFFREADY14, 0, 0}, // S_MSTAFFREADY13
+ {SPR_MSTF, 2, 1, A_WeaponReady, S_MSTAFFREADY15, 0, 0}, // S_MSTAFFREADY14
+ {SPR_MSTF, 2, 1, A_WeaponReady, S_MSTAFFREADY16, 0, 0}, // S_MSTAFFREADY15
+ {SPR_MSTF, 2, 1, A_WeaponReady, S_MSTAFFREADY17, 0, 0}, // S_MSTAFFREADY16
+ {SPR_MSTF, 2, 1, A_WeaponReady, S_MSTAFFREADY18, 0, 0}, // S_MSTAFFREADY17
+ {SPR_MSTF, 2, 1, A_WeaponReady, S_MSTAFFREADY19, 0, 0}, // S_MSTAFFREADY18
+ {SPR_MSTF, 3, 1, A_WeaponReady, S_MSTAFFREADY20, 0, 0}, // S_MSTAFFREADY19
+ {SPR_MSTF, 3, 1, A_WeaponReady, S_MSTAFFREADY21, 0, 0}, // S_MSTAFFREADY20
+ {SPR_MSTF, 3, 1, A_WeaponReady, S_MSTAFFREADY22, 0, 0}, // S_MSTAFFREADY21
+ {SPR_MSTF, 3, 1, A_WeaponReady, S_MSTAFFREADY23, 0, 0}, // S_MSTAFFREADY22
+ {SPR_MSTF, 3, 1, A_WeaponReady, S_MSTAFFREADY24, 0, 0}, // S_MSTAFFREADY23
+ {SPR_MSTF, 3, 1, A_WeaponReady, S_MSTAFFREADY25, 0, 0}, // S_MSTAFFREADY24
+ {SPR_MSTF, 4, 1, A_WeaponReady, S_MSTAFFREADY26, 0, 0}, // S_MSTAFFREADY25
+ {SPR_MSTF, 4, 1, A_WeaponReady, S_MSTAFFREADY27, 0, 0}, // S_MSTAFFREADY26
+ {SPR_MSTF, 4, 1, A_WeaponReady, S_MSTAFFREADY28, 0, 0}, // S_MSTAFFREADY27
+ {SPR_MSTF, 4, 1, A_WeaponReady, S_MSTAFFREADY29, 0, 0}, // S_MSTAFFREADY28
+ {SPR_MSTF, 4, 1, A_WeaponReady, S_MSTAFFREADY30, 0, 0}, // S_MSTAFFREADY29
+ {SPR_MSTF, 4, 1, A_WeaponReady, S_MSTAFFREADY31, 0, 0}, // S_MSTAFFREADY30
+ {SPR_MSTF, 5, 1, A_WeaponReady, S_MSTAFFREADY32, 0, 0}, // S_MSTAFFREADY31
+ {SPR_MSTF, 5, 1, A_WeaponReady, S_MSTAFFREADY33, 0, 0}, // S_MSTAFFREADY32
+ {SPR_MSTF, 5, 1, A_WeaponReady, S_MSTAFFREADY34, 0, 0}, // S_MSTAFFREADY33
+ {SPR_MSTF, 5, 1, A_WeaponReady, S_MSTAFFREADY35, 0, 0}, // S_MSTAFFREADY34
+ {SPR_MSTF, 5, 1, A_WeaponReady, S_MSTAFFREADY, 0, 0}, // S_MSTAFFREADY35
+ {SPR_MSTF, 0, 1, A_Lower, S_MSTAFFDOWN, 0, 0}, // S_MSTAFFDOWN
+ {SPR_MSTF, 0, 1, A_Raise, S_MSTAFFUP, 0, 0}, // S_MSTAFFUP
+ {SPR_MSTF, 6, 4, NULL, S_MSTAFFATK_2, 0, 40}, // S_MSTAFFATK_1
+ {SPR_MSTF, 32775, 4, A_MStaffAttack, S_MSTAFFATK_3, 0, 48}, // S_MSTAFFATK_2
+ {SPR_MSTF, 32775, 2, A_MStaffPalette, S_MSTAFFATK_4, 0, 48}, // S_MSTAFFATK_3
+ {SPR_MSTF, 8, 2, A_MStaffPalette, S_MSTAFFATK_5, 0, 48}, // S_MSTAFFATK_4
+ {SPR_MSTF, 8, 2, A_MStaffPalette, S_MSTAFFATK_6, 0, 48}, // S_MSTAFFATK_5
+ {SPR_MSTF, 8, 1, NULL, S_MSTAFFATK_7, 0, 40}, // S_MSTAFFATK_6
+ {SPR_MSTF, 9, 5, NULL, S_MSTAFFREADY, 0, 36}, // S_MSTAFFATK_7
+ {SPR_MSP1, 32768, 3, A_MStaffWeave, S_MSTAFF_FX1_2, 0, 0}, // S_MSTAFF_FX1_1
+ {SPR_MSP1, 32769, 3, A_MStaffWeave, S_MSTAFF_FX1_3, 0, 0}, // S_MSTAFF_FX1_2
+ {SPR_MSP1, 32770, 3, A_MStaffWeave, S_MSTAFF_FX1_4, 0, 0}, // S_MSTAFF_FX1_3
+ {SPR_MSP1, 32771, 3, A_MStaffWeave, S_MSTAFF_FX1_5, 0, 0}, // S_MSTAFF_FX1_4
+ {SPR_MSP1, 32772, 3, A_MStaffWeave, S_MSTAFF_FX1_6, 0, 0}, // S_MSTAFF_FX1_5
+ {SPR_MSP1, 32773, 3, A_MStaffWeave, S_MSTAFF_FX1_1, 0, 0}, // S_MSTAFF_FX1_6
+ {SPR_MSP1, 32774, 4, NULL, S_MSTAFF_FX_X2, 0, 0}, // S_MSTAFF_FX_X1
+ {SPR_MSP1, 32775, 5, A_Explode, S_MSTAFF_FX_X3, 0, 0}, // S_MSTAFF_FX_X2
+ {SPR_MSP1, 32776, 4, NULL, S_MSTAFF_FX_X4, 0, 0}, // S_MSTAFF_FX_X3
+ {SPR_MSP1, 32777, 5, NULL, S_MSTAFF_FX_X5, 0, 0}, // S_MSTAFF_FX_X4
+ {SPR_MSP1, 32778, 4, NULL, S_MSTAFF_FX_X6, 0, 0}, // S_MSTAFF_FX_X5
+ {SPR_MSP1, 32779, 5, NULL, S_MSTAFF_FX_X7, 0, 0}, // S_MSTAFF_FX_X6
+ {SPR_MSP1, 32780, 4, NULL, S_MSTAFF_FX_X8, 0, 0}, // S_MSTAFF_FX_X7
+ {SPR_MSP1, 32781, 5, NULL, S_MSTAFF_FX_X9, 0, 0}, // S_MSTAFF_FX_X8
+ {SPR_MSP1, 32782, 4, NULL, S_MSTAFF_FX_X10, 0, 0}, // S_MSTAFF_FX_X9
+ {SPR_MSP1, 32783, 4, NULL, S_NULL, 0, 0}, // S_MSTAFF_FX_X10
+ {SPR_MSP2, 32768, 2, A_MStaffTrack, S_MSTAFF_FX2_2, 0, 0}, // S_MSTAFF_FX2_1
+ {SPR_MSP2, 32769, 2, A_MStaffTrack, S_MSTAFF_FX2_3, 0, 0}, // S_MSTAFF_FX2_2
+ {SPR_MSP2, 32770, 2, A_MStaffTrack, S_MSTAFF_FX2_4, 0, 0}, // S_MSTAFF_FX2_3
+ {SPR_MSP2, 32771, 2, A_MStaffTrack, S_MSTAFF_FX2_1, 0, 0}, // S_MSTAFF_FX2_4
+ {SPR_MSP2, 32772, 4, NULL, S_MSTAFF_FX2_X2, 0, 0}, // S_MSTAFF_FX2_X1
+ {SPR_MSP2, 32773, 5, A_Explode, S_MSTAFF_FX2_X3, 0, 0}, // S_MSTAFF_FX2_X2
+ {SPR_MSP2, 32774, 5, NULL, S_MSTAFF_FX2_X4, 0, 0}, // S_MSTAFF_FX2_X3
+ {SPR_MSP2, 32775, 5, NULL, S_MSTAFF_FX2_X5, 0, 0}, // S_MSTAFF_FX2_X4
+ {SPR_MSP2, 32776, 4, NULL, S_NULL, 0, 0}, // S_MSTAFF_FX2_X5
+ {SPR_WFR1, 32768, -1, NULL, S_NULL, 0, 0}, // S_FSWORD1
+ {SPR_WFR2, 32768, -1, NULL, S_NULL, 0, 0}, // S_FSWORD2
+ {SPR_WFR3, 32768, -1, NULL, S_NULL, 0, 0}, // S_FSWORD3
+ {SPR_WCH1, 32768, -1, NULL, S_NULL, 0, 0}, // S_CHOLY1
+ {SPR_WCH2, 32768, -1, NULL, S_NULL, 0, 0}, // S_CHOLY2
+ {SPR_WCH3, 32768, -1, NULL, S_NULL, 0, 0}, // S_CHOLY3
+ {SPR_WMS1, 32768, -1, NULL, S_NULL, 0, 0}, // S_MSTAFF1
+ {SPR_WMS2, 32768, -1, NULL, S_NULL, 0, 0}, // S_MSTAFF2
+ {SPR_WMS3, 32768, -1, NULL, S_NULL, 0, 0}, // S_MSTAFF3
+ {SPR_WPIG, 0, 1, A_WeaponReady, S_SNOUTREADY, 0, 0}, // S_SNOUTREADY
+ {SPR_WPIG, 0, 1, A_Lower, S_SNOUTDOWN, 0, 0}, // S_SNOUTDOWN
+ {SPR_WPIG, 0, 1, A_Raise, S_SNOUTUP, 0, 0}, // S_SNOUTUP
+ {SPR_WPIG, 0, 4, A_SnoutAttack, S_SNOUTATK2, 0, 0}, // S_SNOUTATK1
+ {SPR_WPIG, 1, 8, A_SnoutAttack, S_SNOUTREADY, 0, 0}, // S_SNOUTATK2
+ {SPR_WMCS, 32768, 8, NULL, S_COS2, 0, 0}, // S_COS1
+ {SPR_WMCS, 32769, 8, NULL, S_COS3, 0, 0}, // S_COS2
+ {SPR_WMCS, 32770, 8, NULL, S_COS1, 0, 0}, // S_COS3
+ {SPR_CONE, 0, 1, A_WeaponReady, S_CONEREADY, 0, 0}, // S_CONEREADY
+ {SPR_CONE, 0, 1, A_Lower, S_CONEDOWN, 0, 0}, // S_CONEDOWN
+ {SPR_CONE, 0, 1, A_Raise, S_CONEUP, 0, 0}, // S_CONEUP
+ {SPR_CONE, 1, 3, NULL, S_CONEATK1_2, 0, 0}, // S_CONEATK1_1
+ {SPR_CONE, 2, 4, NULL, S_CONEATK1_3, 0, 0}, // S_CONEATK1_2
+ {SPR_CONE, 3, 3, NULL, S_CONEATK1_4, 0, 0}, // S_CONEATK1_3
+ {SPR_CONE, 4, 5, NULL, S_CONEATK1_5, 0, 0}, // S_CONEATK1_4
+ {SPR_CONE, 5, 3, A_FireConePL1, S_CONEATK1_6, 0, 0}, // S_CONEATK1_5
+ {SPR_CONE, 6, 3, NULL, S_CONEATK1_7, 0, 0}, // S_CONEATK1_6
+ {SPR_CONE, 0, 9, NULL, S_CONEATK1_8, 0, 0}, // S_CONEATK1_7
+ {SPR_CONE, 0, 10, A_ReFire, S_CONEREADY, 0, 0}, // S_CONEATK1_8
+ {SPR_SHRD, 32768, 2, NULL, S_SHARDFX1_2, 0, 0}, // S_SHARDFX1_1
+ {SPR_SHRD, 32768, 3, A_ShedShard, S_SHARDFX1_3, 0, 0}, // S_SHARDFX1_2
+ {SPR_SHRD, 32769, 3, NULL, S_SHARDFX1_4, 0, 0}, // S_SHARDFX1_3
+ {SPR_SHRD, 32770, 3, NULL, S_SHARDFX1_1, 0, 0}, // S_SHARDFX1_4
+ {SPR_SHEX, 32768, 5, NULL, S_SHARDFXE1_2, 0, 0}, // S_SHARDFXE1_1
+ {SPR_SHEX, 32769, 5, NULL, S_SHARDFXE1_3, 0, 0}, // S_SHARDFXE1_2
+ {SPR_SHEX, 32770, 5, NULL, S_SHARDFXE1_4, 0, 0}, // S_SHARDFXE1_3
+ {SPR_SHEX, 32771, 5, NULL, S_SHARDFXE1_5, 0, 0}, // S_SHARDFXE1_4
+ {SPR_SHEX, 32772, 5, NULL, S_NULL, 0, 0}, // S_SHARDFXE1_5
+ {SPR_BLOD, 2, 8, NULL, S_BLOOD2, 0, 0}, // S_BLOOD1
+ {SPR_BLOD, 1, 8, NULL, S_BLOOD3, 0, 0}, // S_BLOOD2
+ {SPR_BLOD, 0, 8, NULL, S_NULL, 0, 0}, // S_BLOOD3
+ {SPR_BLOD, 2, 8, NULL, S_BLOODSPLATTER2, 0, 0}, // S_BLOODSPLATTER1
+ {SPR_BLOD, 1, 8, NULL, S_BLOODSPLATTER3, 0, 0}, // S_BLOODSPLATTER2
+ {SPR_BLOD, 0, 8, NULL, S_NULL, 0, 0}, // S_BLOODSPLATTER3
+ {SPR_BLOD, 0, 6, NULL, S_NULL, 0, 0}, // S_BLOODSPLATTERX
+ {SPR_GIBS, 0, -1, NULL, S_NULL, 0, 0}, // S_GIBS1
+ {SPR_PLAY, 0, -1, NULL, S_NULL, 0, 0}, // S_FPLAY
+ {SPR_PLAY, 0, 4, NULL, S_FPLAY_RUN2, 0, 0}, // S_FPLAY_RUN1
+ {SPR_PLAY, 1, 4, NULL, S_FPLAY_RUN3, 0, 0}, // S_FPLAY_RUN2
+ {SPR_PLAY, 2, 4, NULL, S_FPLAY_RUN4, 0, 0}, // S_FPLAY_RUN3
+ {SPR_PLAY, 3, 4, NULL, S_FPLAY_RUN1, 0, 0}, // S_FPLAY_RUN4
+ {SPR_PLAY, 4, 8, NULL, S_FPLAY_ATK2, 0, 0}, // S_FPLAY_ATK1
+ {SPR_PLAY, 5, 8, NULL, S_FPLAY, 0, 0}, // S_FPLAY_ATK2
+ {SPR_PLAY, 6, 4, NULL, S_FPLAY_PAIN2, 0, 0}, // S_FPLAY_PAIN
+ {SPR_PLAY, 6, 4, A_Pain, S_FPLAY, 0, 0}, // S_FPLAY_PAIN2
+ {SPR_PLAY, 7, 6, NULL, S_FPLAY_DIE2, 0, 0}, // S_FPLAY_DIE1
+ {SPR_PLAY, 8, 6, A_Scream, S_FPLAY_DIE3, 0, 0}, // S_FPLAY_DIE2
+ {SPR_PLAY, 9, 6, NULL, S_FPLAY_DIE4, 0, 0}, // S_FPLAY_DIE3
+ {SPR_PLAY, 10, 6, NULL, S_FPLAY_DIE5, 0, 0}, // S_FPLAY_DIE4
+ {SPR_PLAY, 11, 6, A_NoBlocking, S_FPLAY_DIE6, 0, 0}, // S_FPLAY_DIE5
+ {SPR_PLAY, 12, 6, NULL, S_FPLAY_DIE7, 0, 0}, // S_FPLAY_DIE6
+ {SPR_PLAY, 13, -1, A_AddPlayerCorpse, S_NULL, 0, 0}, // S_FPLAY_DIE7
+ {SPR_PLAY, 14, 5, A_Scream, S_FPLAY_XDIE2, 0, 0}, // S_FPLAY_XDIE1
+ {SPR_PLAY, 15, 5, A_SkullPop, S_FPLAY_XDIE3, 0, 0}, // S_FPLAY_XDIE2
+ {SPR_PLAY, 17, 5, A_NoBlocking, S_FPLAY_XDIE4, 0, 0}, // S_FPLAY_XDIE3
+ {SPR_PLAY, 18, 5, NULL, S_FPLAY_XDIE5, 0, 0}, // S_FPLAY_XDIE4
+ {SPR_PLAY, 19, 5, NULL, S_FPLAY_XDIE6, 0, 0}, // S_FPLAY_XDIE5
+ {SPR_PLAY, 20, 5, NULL, S_FPLAY_XDIE7, 0, 0}, // S_FPLAY_XDIE6
+ {SPR_PLAY, 21, 5, NULL, S_FPLAY_XDIE8, 0, 0}, // S_FPLAY_XDIE7
+ {SPR_PLAY, 22, -1, A_AddPlayerCorpse, S_NULL, 0, 0}, // S_FPLAY_XDIE8
+ {SPR_PLAY, 23, 5, A_FreezeDeath, S_FPLAY_ICE2, 0, 0}, // S_FPLAY_ICE
+ {SPR_PLAY, 23, 1, A_FreezeDeathChunks, S_FPLAY_ICE2, 0, 0}, // S_FPLAY_ICE2
+ {SPR_FDTH, 32768, 5, NULL, S_PLAY_F_FDTH2, 0, 0}, // S_PLAY_F_FDTH1
+ {SPR_FDTH, 32769, 4, NULL, S_PLAY_FDTH3, 0, 0}, // S_PLAY_F_FDTH2
+ {SPR_FDTH, 32770, 5, NULL, S_PLAY_C_FDTH2, 0, 0}, // S_PLAY_C_FDTH1
+ {SPR_FDTH, 32771, 4, NULL, S_PLAY_FDTH3, 0, 0}, // S_PLAY_C_FDTH2
+ {SPR_FDTH, 32772, 5, NULL, S_PLAY_M_FDTH2, 0, 0}, // S_PLAY_M_FDTH1
+ {SPR_FDTH, 32773, 4, NULL, S_PLAY_FDTH3, 0, 0}, // S_PLAY_M_FDTH2
+ {SPR_FDTH, 32774, 5, NULL, S_PLAY_FDTH4, 0, 0}, // S_PLAY_FDTH3
+ {SPR_FDTH, 32775, 4, A_Scream, S_PLAY_FDTH5, 0, 0}, // S_PLAY_FDTH4
+ {SPR_FDTH, 32776, 5, NULL, S_PLAY_FDTH6, 0, 0}, // S_PLAY_FDTH5
+ {SPR_FDTH, 32777, 4, NULL, S_PLAY_FDTH7, 0, 0}, // S_PLAY_FDTH6
+ {SPR_FDTH, 32778, 5, NULL, S_PLAY_FDTH8, 0, 0}, // S_PLAY_FDTH7
+ {SPR_FDTH, 32779, 4, NULL, S_PLAY_FDTH9, 0, 0}, // S_PLAY_FDTH8
+ {SPR_FDTH, 32780, 5, NULL, S_PLAY_FDTH10, 0, 0}, // S_PLAY_FDTH9
+ {SPR_FDTH, 32781, 4, NULL, S_PLAY_FDTH11, 0, 0}, // S_PLAY_FDTH10
+ {SPR_FDTH, 32782, 5, NULL, S_PLAY_FDTH12, 0, 0}, // S_PLAY_FDTH11
+ {SPR_FDTH, 32783, 4, NULL, S_PLAY_FDTH13, 0, 0}, // S_PLAY_FDTH12
+ {SPR_FDTH, 32784, 5, NULL, S_PLAY_FDTH14, 0, 0}, // S_PLAY_FDTH13
+ {SPR_FDTH, 32785, 4, NULL, S_PLAY_FDTH15, 0, 0}, // S_PLAY_FDTH14
+ {SPR_FDTH, 32786, 5, A_NoBlocking, S_PLAY_FDTH16, 0, 0}, // S_PLAY_FDTH15
+ {SPR_FDTH, 32787, 4, NULL, S_PLAY_FDTH17, 0, 0}, // S_PLAY_FDTH16
+ {SPR_FDTH, 32788, 5, NULL, S_PLAY_FDTH18, 0, 0}, // S_PLAY_FDTH17
+ {SPR_FDTH, 32789, 4, NULL, S_PLAY_FDTH19, 0, 0}, // S_PLAY_FDTH18
+ {SPR_ACLO, 4, 35, A_CheckBurnGone, S_PLAY_FDTH19, 0, 0}, // S_PLAY_FDTH19
+ {SPR_ACLO, 4, 8, NULL, S_NULL, 0, 0}, // S_PLAY_FDTH20
+ {SPR_BSKL, 0, 5, A_CheckSkullFloor, S_BLOODYSKULL2, 0, 0}, // S_BLOODYSKULL1
+ {SPR_BSKL, 1, 5, A_CheckSkullFloor, S_BLOODYSKULL3, 0, 0}, // S_BLOODYSKULL2
+ {SPR_BSKL, 2, 5, A_CheckSkullFloor, S_BLOODYSKULL4, 0, 0}, // S_BLOODYSKULL3
+ {SPR_BSKL, 3, 5, A_CheckSkullFloor, S_BLOODYSKULL5, 0, 0}, // S_BLOODYSKULL4
+ {SPR_BSKL, 5, 5, A_CheckSkullFloor, S_BLOODYSKULL6, 0, 0}, // S_BLOODYSKULL5
+ {SPR_BSKL, 6, 5, A_CheckSkullFloor, S_BLOODYSKULL7, 0, 0}, // S_BLOODYSKULL6
+ {SPR_BSKL, 7, 5, A_CheckSkullFloor, S_BLOODYSKULL1, 0, 0}, // S_BLOODYSKULL7
+ {SPR_BSKL, 8, 16, A_CheckSkullDone, S_BLOODYSKULLX1, 0, 0}, // S_BLOODYSKULLX1
+ {SPR_BSKL, 8, 1050, NULL, S_NULL, 0, 0}, // S_BLOODYSKULLX2
+ {SPR_PLAY, 0, 5, NULL, S_PLAYER_SPEED2, 0, 0}, // S_PLAYER_SPEED1
+ {SPR_PLAY, 0, 3, A_SpeedFade, S_NULL, 0, 0}, // S_PLAYER_SPEED2
+ {SPR_ICEC, 0, 10, NULL, S_ICECHUNK2, 0, 0}, // S_ICECHUNK1
+ {SPR_ICEC, 1, 10, A_IceSetTics, S_ICECHUNK3, 0, 0}, // S_ICECHUNK2
+ {SPR_ICEC, 2, 10, A_IceSetTics, S_ICECHUNK4, 0, 0}, // S_ICECHUNK3
+ {SPR_ICEC, 3, 10, A_IceSetTics, S_NULL, 0, 0}, // S_ICECHUNK4
+ {SPR_ICEC, 0, 10, A_IceCheckHeadDone, S_ICECHUNK_HEAD, 0, 0}, // S_ICECHUNK_HEAD
+ {SPR_ICEC, 0, 1050, NULL, S_NULL, 0, 0}, // S_ICECHUNK_HEAD2
+ {SPR_CLER, 0, -1, NULL, S_NULL, 0, 0}, // S_CPLAY
+ {SPR_CLER, 0, 4, NULL, S_CPLAY_RUN2, 0, 0}, // S_CPLAY_RUN1
+ {SPR_CLER, 1, 4, NULL, S_CPLAY_RUN3, 0, 0}, // S_CPLAY_RUN2
+ {SPR_CLER, 2, 4, NULL, S_CPLAY_RUN4, 0, 0}, // S_CPLAY_RUN3
+ {SPR_CLER, 3, 4, NULL, S_CPLAY_RUN1, 0, 0}, // S_CPLAY_RUN4
+ {SPR_CLER, 4, 6, NULL, S_CPLAY_ATK2, 0, 0}, // S_CPLAY_ATK1
+ {SPR_CLER, 5, 6, NULL, S_CPLAY_ATK3, 0, 0}, // S_CPLAY_ATK2
+ {SPR_CLER, 6, 6, NULL, S_CPLAY, 0, 0}, // S_CPLAY_ATK3
+ {SPR_CLER, 7, 4, NULL, S_CPLAY_PAIN2, 0, 0}, // S_CPLAY_PAIN
+ {SPR_CLER, 7, 4, A_Pain, S_CPLAY, 0, 0}, // S_CPLAY_PAIN2
+ {SPR_CLER, 8, 6, NULL, S_CPLAY_DIE2, 0, 0}, // S_CPLAY_DIE1
+ {SPR_CLER, 10, 6, A_Scream, S_CPLAY_DIE3, 0, 0}, // S_CPLAY_DIE2
+ {SPR_CLER, 11, 6, NULL, S_CPLAY_DIE4, 0, 0}, // S_CPLAY_DIE3
+ {SPR_CLER, 11, 6, NULL, S_CPLAY_DIE5, 0, 0}, // S_CPLAY_DIE4
+ {SPR_CLER, 12, 6, A_NoBlocking, S_CPLAY_DIE6, 0, 0}, // S_CPLAY_DIE5
+ {SPR_CLER, 13, 6, NULL, S_CPLAY_DIE7, 0, 0}, // S_CPLAY_DIE6
+ {SPR_CLER, 14, 6, NULL, S_CPLAY_DIE8, 0, 0}, // S_CPLAY_DIE7
+ {SPR_CLER, 15, 6, NULL, S_CPLAY_DIE9, 0, 0}, // S_CPLAY_DIE8
+ {SPR_CLER, 16, -1, A_AddPlayerCorpse, S_NULL, 0, 0}, // S_CPLAY_DIE9
+ {SPR_CLER, 17, 5, A_Scream, S_CPLAY_XDIE2, 0, 0}, // S_CPLAY_XDIE1
+ {SPR_CLER, 18, 5, NULL, S_CPLAY_XDIE3, 0, 0}, // S_CPLAY_XDIE2
+ {SPR_CLER, 19, 5, A_NoBlocking, S_CPLAY_XDIE4, 0, 0}, // S_CPLAY_XDIE3
+ {SPR_CLER, 20, 5, NULL, S_CPLAY_XDIE5, 0, 0}, // S_CPLAY_XDIE4
+ {SPR_CLER, 21, 5, NULL, S_CPLAY_XDIE6, 0, 0}, // S_CPLAY_XDIE5
+ {SPR_CLER, 22, 5, NULL, S_CPLAY_XDIE7, 0, 0}, // S_CPLAY_XDIE6
+ {SPR_CLER, 23, 5, NULL, S_CPLAY_XDIE8, 0, 0}, // S_CPLAY_XDIE7
+ {SPR_CLER, 24, 5, NULL, S_CPLAY_XDIE9, 0, 0}, // S_CPLAY_XDIE8
+ {SPR_CLER, 25, 5, NULL, S_CPLAY_XDIE10, 0, 0}, // S_CPLAY_XDIE9
+ {SPR_CLER, 26, -1, A_AddPlayerCorpse, S_NULL, 0, 0}, // S_CPLAY_XDIE10
+ {SPR_CLER, 27, 5, A_FreezeDeath, S_CPLAY_ICE2, 0, 0}, // S_CPLAY_ICE
+ {SPR_CLER, 27, 1, A_FreezeDeathChunks, S_CPLAY_ICE2, 0, 0}, // S_CPLAY_ICE2
+ {SPR_MAGE, 0, -1, NULL, S_NULL, 0, 0}, // S_MPLAY
+ {SPR_MAGE, 0, 4, NULL, S_MPLAY_RUN2, 0, 0}, // S_MPLAY_RUN1
+ {SPR_MAGE, 1, 4, NULL, S_MPLAY_RUN3, 0, 0}, // S_MPLAY_RUN2
+ {SPR_MAGE, 2, 4, NULL, S_MPLAY_RUN4, 0, 0}, // S_MPLAY_RUN3
+ {SPR_MAGE, 3, 4, NULL, S_MPLAY_RUN1, 0, 0}, // S_MPLAY_RUN4
+ {SPR_MAGE, 4, 8, NULL, S_MPLAY_ATK2, 0, 0}, // S_MPLAY_ATK1
+ {SPR_MAGE, 32773, 8, NULL, S_MPLAY, 0, 0}, // S_MPLAY_ATK2
+ {SPR_MAGE, 6, 4, NULL, S_MPLAY_PAIN2, 0, 0}, // S_MPLAY_PAIN
+ {SPR_MAGE, 6, 4, A_Pain, S_MPLAY, 0, 0}, // S_MPLAY_PAIN2
+ {SPR_MAGE, 7, 6, NULL, S_MPLAY_DIE2, 0, 0}, // S_MPLAY_DIE1
+ {SPR_MAGE, 8, 6, A_Scream, S_MPLAY_DIE3, 0, 0}, // S_MPLAY_DIE2
+ {SPR_MAGE, 9, 6, NULL, S_MPLAY_DIE4, 0, 0}, // S_MPLAY_DIE3
+ {SPR_MAGE, 10, 6, NULL, S_MPLAY_DIE5, 0, 0}, // S_MPLAY_DIE4
+ {SPR_MAGE, 11, 6, A_NoBlocking, S_MPLAY_DIE6, 0, 0}, // S_MPLAY_DIE5
+ {SPR_MAGE, 12, 6, NULL, S_MPLAY_DIE7, 0, 0}, // S_MPLAY_DIE6
+ {SPR_MAGE, 13, -1, A_AddPlayerCorpse, S_NULL, 0, 0}, // S_MPLAY_DIE7
+ {SPR_MAGE, 14, 5, A_Scream, S_MPLAY_XDIE2, 0, 0}, // S_MPLAY_XDIE1
+ {SPR_MAGE, 15, 5, NULL, S_MPLAY_XDIE3, 0, 0}, // S_MPLAY_XDIE2
+ {SPR_MAGE, 17, 5, A_NoBlocking, S_MPLAY_XDIE4, 0, 0}, // S_MPLAY_XDIE3
+ {SPR_MAGE, 18, 5, NULL, S_MPLAY_XDIE5, 0, 0}, // S_MPLAY_XDIE4
+ {SPR_MAGE, 19, 5, NULL, S_MPLAY_XDIE6, 0, 0}, // S_MPLAY_XDIE5
+ {SPR_MAGE, 20, 5, NULL, S_MPLAY_XDIE7, 0, 0}, // S_MPLAY_XDIE6
+ {SPR_MAGE, 21, 5, NULL, S_MPLAY_XDIE8, 0, 0}, // S_MPLAY_XDIE7
+ {SPR_MAGE, 22, 5, NULL, S_MPLAY_XDIE9, 0, 0}, // S_MPLAY_XDIE8
+ {SPR_MAGE, 23, -1, A_AddPlayerCorpse, S_NULL, 0, 0}, // S_MPLAY_XDIE9
+ {SPR_MAGE, 24, 5, A_FreezeDeath, S_MPLAY_ICE2, 0, 0}, // S_MPLAY_ICE
+ {SPR_MAGE, 24, 1, A_FreezeDeathChunks, S_MPLAY_ICE2, 0, 0}, // S_MPLAY_ICE2
+ {SPR_PIGY, 0, -1, NULL, S_NULL, 0, 0}, // S_PIGPLAY
+ {SPR_PIGY, 0, 3, NULL, S_PIGPLAY_RUN2, 0, 0}, // S_PIGPLAY_RUN1
+ {SPR_PIGY, 1, 3, NULL, S_PIGPLAY_RUN3, 0, 0}, // S_PIGPLAY_RUN2
+ {SPR_PIGY, 2, 3, NULL, S_PIGPLAY_RUN4, 0, 0}, // S_PIGPLAY_RUN3
+ {SPR_PIGY, 3, 3, NULL, S_PIGPLAY_RUN1, 0, 0}, // S_PIGPLAY_RUN4
+ {SPR_PIGY, 0, 12, NULL, S_PIGPLAY, 0, 0}, // S_PIGPLAY_ATK1
+ {SPR_PIGY, 3, 4, A_PigPain, S_PIGPLAY, 0, 0}, // S_PIGPLAY_PAIN
+ {SPR_PIGY, 1, 10, A_PigLook, S_PIG_LOOK1, 0, 0}, // S_PIG_LOOK1
+ {SPR_PIGY, 0, 3, A_PigChase, S_PIG_WALK2, 0, 0}, // S_PIG_WALK1
+ {SPR_PIGY, 1, 3, A_PigChase, S_PIG_WALK3, 0, 0}, // S_PIG_WALK2
+ {SPR_PIGY, 2, 3, A_PigChase, S_PIG_WALK4, 0, 0}, // S_PIG_WALK3
+ {SPR_PIGY, 3, 3, A_PigChase, S_PIG_WALK1, 0, 0}, // S_PIG_WALK4
+ {SPR_PIGY, 3, 4, A_PigPain, S_PIG_WALK1, 0, 0}, // S_PIG_PAIN
+ {SPR_PIGY, 0, 5, A_FaceTarget, S_PIG_ATK2, 0, 0}, // S_PIG_ATK1
+ {SPR_PIGY, 0, 10, A_PigAttack, S_PIG_WALK1, 0, 0}, // S_PIG_ATK2
+ {SPR_PIGY, 4, 4, A_Scream, S_PIG_DIE2, 0, 0}, // S_PIG_DIE1
+ {SPR_PIGY, 5, 3, A_NoBlocking, S_PIG_DIE3, 0, 0}, // S_PIG_DIE2
+ {SPR_PIGY, 6, 4, A_QueueCorpse, S_PIG_DIE4, 0, 0}, // S_PIG_DIE3
+ {SPR_PIGY, 7, 3, NULL, S_PIG_DIE5, 0, 0}, // S_PIG_DIE4
+ {SPR_PIGY, 8, 4, NULL, S_PIG_DIE6, 0, 0}, // S_PIG_DIE5
+ {SPR_PIGY, 9, 4, NULL, S_PIG_DIE7, 0, 0}, // S_PIG_DIE6
+ {SPR_PIGY, 10, 4, NULL, S_PIG_DIE8, 0, 0}, // S_PIG_DIE7
+ {SPR_PIGY, 11, -1, NULL, S_NULL, 0, 0}, // S_PIG_DIE8
+ {SPR_PIGY, 12, 5, A_FreezeDeath, S_PIG_ICE2, 0, 0}, // S_PIG_ICE
+ {SPR_PIGY, 12, 1, A_FreezeDeathChunks, S_PIG_ICE2, 0, 0}, // S_PIG_ICE2
+ {SPR_CENT, 0, 10, A_Look, S_CENTAUR_LOOK2, 0, 0}, // S_CENTAUR_LOOK1
+ {SPR_CENT, 1, 10, A_Look, S_CENTAUR_LOOK1, 0, 0}, // S_CENTAUR_LOOK2
+ {SPR_CENT, 0, 4, A_Chase, S_CENTAUR_WALK2, 0, 0}, // S_CENTAUR_WALK1
+ {SPR_CENT, 1, 4, A_Chase, S_CENTAUR_WALK3, 0, 0}, // S_CENTAUR_WALK2
+ {SPR_CENT, 2, 4, A_Chase, S_CENTAUR_WALK4, 0, 0}, // S_CENTAUR_WALK3
+ {SPR_CENT, 3, 4, A_Chase, S_CENTAUR_WALK1, 0, 0}, // S_CENTAUR_WALK4
+ {SPR_CENT, 7, 5, A_FaceTarget, S_CENTAUR_ATK2, 0, 0}, // S_CENTAUR_ATK1
+ {SPR_CENT, 8, 4, A_FaceTarget, S_CENTAUR_ATK3, 0, 0}, // S_CENTAUR_ATK2
+ {SPR_CENT, 9, 7, A_CentaurAttack, S_CENTAUR_WALK1, 0, 0}, // S_CENTAUR_ATK3
+ {SPR_CENT, 4, 10, A_FaceTarget, S_CENTAUR_MISSILE2, 0, 0}, // S_CENTAUR_MISSILE1
+ {SPR_CENT, 32773, 8, A_CentaurAttack2, S_CENTAUR_MISSILE3, 0, 0}, // S_CENTAUR_MISSILE2
+ {SPR_CENT, 4, 10, A_FaceTarget, S_CENTAUR_MISSILE4, 0, 0}, // S_CENTAUR_MISSILE3
+ {SPR_CENT, 32773, 8, A_CentaurAttack2, S_CENTAUR_WALK1, 0, 0}, // S_CENTAUR_MISSILE4
+ {SPR_CENT, 6, 6, A_Pain, S_CENTAUR_PAIN2, 0, 0}, // S_CENTAUR_PAIN1
+ {SPR_CENT, 6, 6, A_SetReflective, S_CENTAUR_PAIN3, 0, 0}, // S_CENTAUR_PAIN2
+ {SPR_CENT, 4, 15, A_CentaurDefend, S_CENTAUR_PAIN4, 0, 0}, // S_CENTAUR_PAIN3
+ {SPR_CENT, 4, 15, A_CentaurDefend, S_CENTAUR_PAIN5, 0, 0}, // S_CENTAUR_PAIN4
+ {SPR_CENT, 4, 15, A_CentaurDefend, S_CENTAUR_PAIN6, 0, 0}, // S_CENTAUR_PAIN5
+ {SPR_CENT, 4, 1, A_UnSetReflective, S_CENTAUR_WALK1, 0, 0}, // S_CENTAUR_PAIN6
+ {SPR_CENT, 10, 4, NULL, S_CENTAUR_DEATH2, 0, 0}, // S_CENTAUR_DEATH1
+ {SPR_CENT, 11, 4, A_Scream, S_CENTAUR_DEATH3, 0, 0}, // S_CENTAUR_DEATH2
+ {SPR_CENT, 12, 4, NULL, S_CENTAUR_DEATH4, 0, 0}, // S_CENTAUR_DEATH3
+ {SPR_CENT, 13, 4, NULL, S_CENTAUR_DEATH5, 0, 0}, // S_CENTAUR_DEATH4
+ {SPR_CENT, 14, 4, A_NoBlocking, S_CENTAUR_DEATH6, 0, 0}, // S_CENTAUR_DEATH5
+ {SPR_CENT, 15, 4, NULL, S_CENTAUR_DEATH7, 0, 0}, // S_CENTAUR_DEATH6
+ {SPR_CENT, 16, 4, NULL, S_CENTAUR_DEATH8, 0, 0}, // S_CENTAUR_DEATH7
+ {SPR_CENT, 17, 4, A_QueueCorpse, S_CENTAUR_DEATH9, 0, 0}, // S_CENTAUR_DEATH8
+ {SPR_CENT, 18, 4, NULL, S_CENTAUR_DEATH0, 0, 0}, // S_CENTAUR_DEATH9
+ {SPR_CENT, 19, -1, NULL, S_NULL, 0, 0}, // S_CENTAUR_DEATH0
+ {SPR_CTXD, 0, 4, NULL, S_CENTAUR_DEATH_X2, 0, 0}, // S_CENTAUR_DEATH_X1
+ {SPR_CTXD, 1, 4, A_NoBlocking, S_CENTAUR_DEATH_X3, 0, 0}, // S_CENTAUR_DEATH_X2
+ {SPR_CTXD, 2, 4, A_CentaurDropStuff, S_CENTAUR_DEATH_X4, 0, 0}, // S_CENTAUR_DEATH_X3
+ {SPR_CTXD, 3, 3, A_Scream, S_CENTAUR_DEATH_X5, 0, 0}, // S_CENTAUR_DEATH_X4
+ {SPR_CTXD, 4, 4, A_QueueCorpse, S_CENTAUR_DEATH_X6, 0, 0}, // S_CENTAUR_DEATH_X5
+ {SPR_CTXD, 5, 3, NULL, S_CENTAUR_DEATH_X7, 0, 0}, // S_CENTAUR_DEATH_X6
+ {SPR_CTXD, 6, 4, NULL, S_CENTAUR_DEATH_X8, 0, 0}, // S_CENTAUR_DEATH_X7
+ {SPR_CTXD, 7, 3, NULL, S_CENTAUR_DEATH_X9, 0, 0}, // S_CENTAUR_DEATH_X8
+ {SPR_CTXD, 8, 4, NULL, S_CENTAUR_DEATH_X10, 0, 0}, // S_CENTAUR_DEATH_X9
+ {SPR_CTXD, 9, 3, NULL, S_CENTAUR_DEATH_X11, 0, 0}, // S_CENTAUR_DEATH_X10
+ {SPR_CTXD, 10, -1, NULL, S_NULL, 0, 0}, // S_CENTAUR_DEATH_X11
+ {SPR_CENT, 20, 5, A_FreezeDeath, S_CENTAUR_ICE2, 0, 0}, // S_CENTAUR_ICE
+ {SPR_CENT, 20, 1, A_FreezeDeathChunks, S_CENTAUR_ICE2, 0, 0}, // S_CENTAUR_ICE2
+ {SPR_CTFX, 32768, -1, NULL, S_NULL, 0, 0}, // S_CENTAUR_FX1
+ {SPR_CTFX, 32769, 4, NULL, S_CENTAUR_FX_X2, 0, 0}, // S_CENTAUR_FX_X1
+ {SPR_CTFX, 32770, 3, NULL, S_CENTAUR_FX_X3, 0, 0}, // S_CENTAUR_FX_X2
+ {SPR_CTFX, 32771, 4, NULL, S_CENTAUR_FX_X4, 0, 0}, // S_CENTAUR_FX_X3
+ {SPR_CTFX, 32772, 3, NULL, S_CENTAUR_FX_X5, 0, 0}, // S_CENTAUR_FX_X4
+ {SPR_CTFX, 32773, 2, NULL, S_NULL, 0, 0}, // S_CENTAUR_FX_X5
+ {SPR_CTDP, 0, 3, A_CheckFloor, S_CENTAUR_SHIELD2, 0, 0}, // S_CENTAUR_SHIELD1
+ {SPR_CTDP, 1, 3, A_CheckFloor, S_CENTAUR_SHIELD3, 0, 0}, // S_CENTAUR_SHIELD2
+ {SPR_CTDP, 2, 3, A_CheckFloor, S_CENTAUR_SHIELD4, 0, 0}, // S_CENTAUR_SHIELD3
+ {SPR_CTDP, 3, 3, A_CheckFloor, S_CENTAUR_SHIELD5, 0, 0}, // S_CENTAUR_SHIELD4
+ {SPR_CTDP, 4, 3, A_CheckFloor, S_CENTAUR_SHIELD6, 0, 0}, // S_CENTAUR_SHIELD5
+ {SPR_CTDP, 5, 3, A_CheckFloor, S_CENTAUR_SHIELD3, 0, 0}, // S_CENTAUR_SHIELD6
+ {SPR_CTDP, 6, 4, NULL, S_CENTAUR_SHIELD_X2, 0, 0}, // S_CENTAUR_SHIELD_X1
+ {SPR_CTDP, 7, 4, A_QueueCorpse, S_CENTAUR_SHIELD_X3, 0, 0}, // S_CENTAUR_SHIELD_X2
+ {SPR_CTDP, 8, 4, NULL, S_CENTAUR_SHIELD_X4, 0, 0}, // S_CENTAUR_SHIELD_X3
+ {SPR_CTDP, 9, -1, NULL, S_NULL, 0, 0}, // S_CENTAUR_SHIELD_X4
+ {SPR_CTDP, 10, 3, A_CheckFloor, S_CENTAUR_SWORD2, 0, 0}, // S_CENTAUR_SWORD1
+ {SPR_CTDP, 11, 3, A_CheckFloor, S_CENTAUR_SWORD3, 0, 0}, // S_CENTAUR_SWORD2
+ {SPR_CTDP, 12, 3, A_CheckFloor, S_CENTAUR_SWORD4, 0, 0}, // S_CENTAUR_SWORD3
+ {SPR_CTDP, 13, 3, A_CheckFloor, S_CENTAUR_SWORD5, 0, 0}, // S_CENTAUR_SWORD4
+ {SPR_CTDP, 14, 3, A_CheckFloor, S_CENTAUR_SWORD6, 0, 0}, // S_CENTAUR_SWORD5
+ {SPR_CTDP, 15, 3, A_CheckFloor, S_CENTAUR_SWORD7, 0, 0}, // S_CENTAUR_SWORD6
+ {SPR_CTDP, 16, 3, A_CheckFloor, S_CENTAUR_SWORD3, 0, 0}, // S_CENTAUR_SWORD7
+ {SPR_CTDP, 17, 4, NULL, S_CENTAUR_SWORD_X2, 0, 0}, // S_CENTAUR_SWORD_X1
+ {SPR_CTDP, 18, 4, A_QueueCorpse, S_CENTAUR_SWORD_X3, 0, 0}, // S_CENTAUR_SWORD_X2
+ {SPR_CTDP, 19, -1, NULL, S_NULL, 0, 0}, // S_CENTAUR_SWORD_X3
+ {SPR_DEMN, 0, 10, A_Look, S_DEMN_LOOK2, 0, 0}, // S_DEMN_LOOK1
+ {SPR_DEMN, 0, 10, A_Look, S_DEMN_LOOK1, 0, 0}, // S_DEMN_LOOK2
+ {SPR_DEMN, 0, 4, A_Chase, S_DEMN_CHASE2, 0, 0}, // S_DEMN_CHASE1
+ {SPR_DEMN, 1, 4, A_Chase, S_DEMN_CHASE3, 0, 0}, // S_DEMN_CHASE2
+ {SPR_DEMN, 2, 4, A_Chase, S_DEMN_CHASE4, 0, 0}, // S_DEMN_CHASE3
+ {SPR_DEMN, 3, 4, A_Chase, S_DEMN_CHASE1, 0, 0}, // S_DEMN_CHASE4
+ {SPR_DEMN, 4, 6, A_FaceTarget, S_DEMN_ATK1_2, 0, 0}, // S_DEMN_ATK1_1
+ {SPR_DEMN, 5, 8, A_FaceTarget, S_DEMN_ATK1_3, 0, 0}, // S_DEMN_ATK1_2
+ {SPR_DEMN, 6, 6, A_DemonAttack1, S_DEMN_CHASE1, 0, 0}, // S_DEMN_ATK1_3
+ {SPR_DEMN, 4, 5, A_FaceTarget, S_DEMN_ATK2_2, 0, 0}, // S_DEMN_ATK2_1
+ {SPR_DEMN, 5, 6, A_FaceTarget, S_DEMN_ATK2_3, 0, 0}, // S_DEMN_ATK2_2
+ {SPR_DEMN, 6, 5, A_DemonAttack2, S_DEMN_CHASE1, 0, 0}, // S_DEMN_ATK2_3
+ {SPR_DEMN, 4, 4, NULL, S_DEMN_PAIN2, 0, 0}, // S_DEMN_PAIN1
+ {SPR_DEMN, 4, 4, A_Pain, S_DEMN_CHASE1, 0, 0}, // S_DEMN_PAIN2
+ {SPR_DEMN, 7, 6, NULL, S_DEMN_DEATH2, 0, 0}, // S_DEMN_DEATH1
+ {SPR_DEMN, 8, 6, NULL, S_DEMN_DEATH3, 0, 0}, // S_DEMN_DEATH2
+ {SPR_DEMN, 9, 6, A_Scream, S_DEMN_DEATH4, 0, 0}, // S_DEMN_DEATH3
+ {SPR_DEMN, 10, 6, A_NoBlocking, S_DEMN_DEATH5, 0, 0}, // S_DEMN_DEATH4
+ {SPR_DEMN, 11, 6, A_QueueCorpse, S_DEMN_DEATH6, 0, 0}, // S_DEMN_DEATH5
+ {SPR_DEMN, 12, 6, NULL, S_DEMN_DEATH7, 0, 0}, // S_DEMN_DEATH6
+ {SPR_DEMN, 13, 6, NULL, S_DEMN_DEATH8, 0, 0}, // S_DEMN_DEATH7
+ {SPR_DEMN, 14, 6, NULL, S_DEMN_DEATH9, 0, 0}, // S_DEMN_DEATH8
+ {SPR_DEMN, 15, -1, NULL, S_NULL, 0, 0}, // S_DEMN_DEATH9
+ {SPR_DEMN, 7, 6, NULL, S_DEMN_XDEATH2, 0, 0}, // S_DEMN_XDEATH1
+ {SPR_DEMN, 8, 6, A_DemonDeath, S_DEMN_XDEATH3, 0, 0}, // S_DEMN_XDEATH2
+ {SPR_DEMN, 9, 6, A_Scream, S_DEMN_XDEATH4, 0, 0}, // S_DEMN_XDEATH3
+ {SPR_DEMN, 10, 6, A_NoBlocking, S_DEMN_XDEATH5, 0, 0}, // S_DEMN_XDEATH4
+ {SPR_DEMN, 11, 6, A_QueueCorpse, S_DEMN_XDEATH6, 0, 0}, // S_DEMN_XDEATH5
+ {SPR_DEMN, 12, 6, NULL, S_DEMN_XDEATH7, 0, 0}, // S_DEMN_XDEATH6
+ {SPR_DEMN, 13, 6, NULL, S_DEMN_XDEATH8, 0, 0}, // S_DEMN_XDEATH7
+ {SPR_DEMN, 14, 6, NULL, S_DEMN_XDEATH9, 0, 0}, // S_DEMN_XDEATH8
+ {SPR_DEMN, 15, -1, NULL, S_NULL, 0, 0}, // S_DEMN_XDEATH9
+ {SPR_DEMN, 16, 5, A_FreezeDeath, S_DEMON_ICE2, 0, 0}, // S_DEMON_ICE
+ {SPR_DEMN, 16, 1, A_FreezeDeathChunks, S_DEMON_ICE2, 0, 0}, // S_DEMON_ICE2
+ {SPR_DEMA, 0, 4, NULL, S_DEMONCHUNK1_2, 0, 0}, // S_DEMONCHUNK1_1
+ {SPR_DEMA, 0, 10, A_QueueCorpse, S_DEMONCHUNK1_3, 0, 0}, // S_DEMONCHUNK1_2
+ {SPR_DEMA, 0, 20, NULL, S_DEMONCHUNK1_3, 0, 0}, // S_DEMONCHUNK1_3
+ {SPR_DEMA, 0, -1, NULL, S_NULL, 0, 0}, // S_DEMONCHUNK1_4
+ {SPR_DEMB, 0, 4, NULL, S_DEMONCHUNK2_2, 0, 0}, // S_DEMONCHUNK2_1
+ {SPR_DEMB, 0, 10, A_QueueCorpse, S_DEMONCHUNK2_3, 0, 0}, // S_DEMONCHUNK2_2
+ {SPR_DEMB, 0, 20, NULL, S_DEMONCHUNK2_3, 0, 0}, // S_DEMONCHUNK2_3
+ {SPR_DEMB, 0, -1, NULL, S_NULL, 0, 0}, // S_DEMONCHUNK2_4
+ {SPR_DEMC, 0, 4, NULL, S_DEMONCHUNK3_2, 0, 0}, // S_DEMONCHUNK3_1
+ {SPR_DEMC, 0, 10, A_QueueCorpse, S_DEMONCHUNK3_3, 0, 0}, // S_DEMONCHUNK3_2
+ {SPR_DEMC, 0, 20, NULL, S_DEMONCHUNK3_3, 0, 0}, // S_DEMONCHUNK3_3
+ {SPR_DEMC, 0, -1, NULL, S_NULL, 0, 0}, // S_DEMONCHUNK3_4
+ {SPR_DEMD, 0, 4, NULL, S_DEMONCHUNK4_2, 0, 0}, // S_DEMONCHUNK4_1
+ {SPR_DEMD, 0, 10, A_QueueCorpse, S_DEMONCHUNK4_3, 0, 0}, // S_DEMONCHUNK4_2
+ {SPR_DEMD, 0, 20, NULL, S_DEMONCHUNK4_3, 0, 0}, // S_DEMONCHUNK4_3
+ {SPR_DEMD, 0, -1, NULL, S_NULL, 0, 0}, // S_DEMONCHUNK4_4
+ {SPR_DEME, 0, 4, NULL, S_DEMONCHUNK5_2, 0, 0}, // S_DEMONCHUNK5_1
+ {SPR_DEME, 0, 10, A_QueueCorpse, S_DEMONCHUNK5_3, 0, 0}, // S_DEMONCHUNK5_2
+ {SPR_DEME, 0, 20, NULL, S_DEMONCHUNK5_3, 0, 0}, // S_DEMONCHUNK5_3
+ {SPR_DEME, 0, -1, NULL, S_NULL, 0, 0}, // S_DEMONCHUNK5_4
+ {SPR_DMFX, 32768, 4, NULL, S_DEMONFX_MOVE2, 0, 0}, // S_DEMONFX_MOVE1
+ {SPR_DMFX, 32769, 4, NULL, S_DEMONFX_MOVE3, 0, 0}, // S_DEMONFX_MOVE2
+ {SPR_DMFX, 32770, 4, NULL, S_DEMONFX_MOVE1, 0, 0}, // S_DEMONFX_MOVE3
+ {SPR_DMFX, 32771, 4, NULL, S_DEMONFX_BOOM2, 0, 0}, // S_DEMONFX_BOOM1
+ {SPR_DMFX, 32772, 4, NULL, S_DEMONFX_BOOM3, 0, 0}, // S_DEMONFX_BOOM2
+ {SPR_DMFX, 32773, 3, NULL, S_DEMONFX_BOOM4, 0, 0}, // S_DEMONFX_BOOM3
+ {SPR_DMFX, 32774, 3, NULL, S_DEMONFX_BOOM5, 0, 0}, // S_DEMONFX_BOOM4
+ {SPR_DMFX, 32775, 3, NULL, S_NULL, 0, 0}, // S_DEMONFX_BOOM5
+ {SPR_DEM2, 0, 10, A_Look, S_DEMN2_LOOK2, 0, 0}, // S_DEMN2_LOOK1
+ {SPR_DEM2, 0, 10, A_Look, S_DEMN2_LOOK1, 0, 0}, // S_DEMN2_LOOK2
+ {SPR_DEM2, 0, 4, A_Chase, S_DEMN2_CHASE2, 0, 0}, // S_DEMN2_CHASE1
+ {SPR_DEM2, 1, 4, A_Chase, S_DEMN2_CHASE3, 0, 0}, // S_DEMN2_CHASE2
+ {SPR_DEM2, 2, 4, A_Chase, S_DEMN2_CHASE4, 0, 0}, // S_DEMN2_CHASE3
+ {SPR_DEM2, 3, 4, A_Chase, S_DEMN2_CHASE1, 0, 0}, // S_DEMN2_CHASE4
+ {SPR_DEM2, 4, 6, A_FaceTarget, S_DEMN2_ATK1_2, 0, 0}, // S_DEMN2_ATK1_1
+ {SPR_DEM2, 5, 8, A_FaceTarget, S_DEMN2_ATK1_3, 0, 0}, // S_DEMN2_ATK1_2
+ {SPR_DEM2, 6, 6, A_DemonAttack1, S_DEMN2_CHASE1, 0, 0}, // S_DEMN2_ATK1_3
+ {SPR_DEM2, 4, 5, A_FaceTarget, S_DEMN2_ATK2_2, 0, 0}, // S_DEMN2_ATK2_1
+ {SPR_DEM2, 5, 6, A_FaceTarget, S_DEMN2_ATK2_3, 0, 0}, // S_DEMN2_ATK2_2
+ {SPR_DEM2, 6, 5, A_DemonAttack2, S_DEMN2_CHASE1, 0, 0}, // S_DEMN2_ATK2_3
+ {SPR_DEM2, 4, 4, NULL, S_DEMN2_PAIN2, 0, 0}, // S_DEMN2_PAIN1
+ {SPR_DEM2, 4, 4, A_Pain, S_DEMN2_CHASE1, 0, 0}, // S_DEMN2_PAIN2
+ {SPR_DEM2, 7, 6, NULL, S_DEMN2_DEATH2, 0, 0}, // S_DEMN2_DEATH1
+ {SPR_DEM2, 8, 6, NULL, S_DEMN2_DEATH3, 0, 0}, // S_DEMN2_DEATH2
+ {SPR_DEM2, 9, 6, A_Scream, S_DEMN2_DEATH4, 0, 0}, // S_DEMN2_DEATH3
+ {SPR_DEM2, 10, 6, A_NoBlocking, S_DEMN2_DEATH5, 0, 0}, // S_DEMN2_DEATH4
+ {SPR_DEM2, 11, 6, A_QueueCorpse, S_DEMN2_DEATH6, 0, 0}, // S_DEMN2_DEATH5
+ {SPR_DEM2, 12, 6, NULL, S_DEMN2_DEATH7, 0, 0}, // S_DEMN2_DEATH6
+ {SPR_DEM2, 13, 6, NULL, S_DEMN2_DEATH8, 0, 0}, // S_DEMN2_DEATH7
+ {SPR_DEM2, 14, 6, NULL, S_DEMN2_DEATH9, 0, 0}, // S_DEMN2_DEATH8
+ {SPR_DEM2, 15, -1, NULL, S_NULL, 0, 0}, // S_DEMN2_DEATH9
+ {SPR_DEM2, 7, 6, NULL, S_DEMN2_XDEATH2, 0, 0}, // S_DEMN2_XDEATH1
+ {SPR_DEM2, 8, 6, A_Demon2Death, S_DEMN2_XDEATH3, 0, 0}, // S_DEMN2_XDEATH2
+ {SPR_DEM2, 9, 6, A_Scream, S_DEMN2_XDEATH4, 0, 0}, // S_DEMN2_XDEATH3
+ {SPR_DEM2, 10, 6, A_NoBlocking, S_DEMN2_XDEATH5, 0, 0}, // S_DEMN2_XDEATH4
+ {SPR_DEM2, 11, 6, A_QueueCorpse, S_DEMN2_XDEATH6, 0, 0}, // S_DEMN2_XDEATH5
+ {SPR_DEM2, 12, 6, NULL, S_DEMN2_XDEATH7, 0, 0}, // S_DEMN2_XDEATH6
+ {SPR_DEM2, 13, 6, NULL, S_DEMN2_XDEATH8, 0, 0}, // S_DEMN2_XDEATH7
+ {SPR_DEM2, 14, 6, NULL, S_DEMN2_XDEATH9, 0, 0}, // S_DEMN2_XDEATH8
+ {SPR_DEM2, 15, -1, NULL, S_NULL, 0, 0}, // S_DEMN2_XDEATH9
+ {SPR_DMBA, 0, 4, NULL, S_DEMON2CHUNK1_2, 0, 0}, // S_DEMON2CHUNK1_1
+ {SPR_DMBA, 0, 10, A_QueueCorpse, S_DEMON2CHUNK1_3, 0, 0}, // S_DEMON2CHUNK1_2
+ {SPR_DMBA, 0, 20, NULL, S_DEMON2CHUNK1_3, 0, 0}, // S_DEMON2CHUNK1_3
+ {SPR_DMBA, 0, -1, NULL, S_NULL, 0, 0}, // S_DEMON2CHUNK1_4
+ {SPR_DMBB, 0, 4, NULL, S_DEMON2CHUNK2_2, 0, 0}, // S_DEMON2CHUNK2_1
+ {SPR_DMBB, 0, 10, A_QueueCorpse, S_DEMON2CHUNK2_3, 0, 0}, // S_DEMON2CHUNK2_2
+ {SPR_DMBB, 0, 20, NULL, S_DEMON2CHUNK2_3, 0, 0}, // S_DEMON2CHUNK2_3
+ {SPR_DMBB, 0, -1, NULL, S_NULL, 0, 0}, // S_DEMON2CHUNK2_4
+ {SPR_DMBC, 0, 4, NULL, S_DEMON2CHUNK3_2, 0, 0}, // S_DEMON2CHUNK3_1
+ {SPR_DMBC, 0, 10, A_QueueCorpse, S_DEMON2CHUNK3_3, 0, 0}, // S_DEMON2CHUNK3_2
+ {SPR_DMBC, 0, 20, NULL, S_DEMON2CHUNK3_3, 0, 0}, // S_DEMON2CHUNK3_3
+ {SPR_DMBC, 0, -1, NULL, S_NULL, 0, 0}, // S_DEMON2CHUNK3_4
+ {SPR_DMBD, 0, 4, NULL, S_DEMON2CHUNK4_2, 0, 0}, // S_DEMON2CHUNK4_1
+ {SPR_DMBD, 0, 10, A_QueueCorpse, S_DEMON2CHUNK4_3, 0, 0}, // S_DEMON2CHUNK4_2
+ {SPR_DMBD, 0, 20, NULL, S_DEMON2CHUNK4_3, 0, 0}, // S_DEMON2CHUNK4_3
+ {SPR_DMBD, 0, -1, NULL, S_NULL, 0, 0}, // S_DEMON2CHUNK4_4
+ {SPR_DMBE, 0, 4, NULL, S_DEMON2CHUNK5_2, 0, 0}, // S_DEMON2CHUNK5_1
+ {SPR_DMBE, 0, 10, NULL, S_DEMON2CHUNK5_3, 0, 0}, // S_DEMON2CHUNK5_2
+ {SPR_DMBE, 0, 20, NULL, S_DEMON2CHUNK5_3, 0, 0}, // S_DEMON2CHUNK5_3
+ {SPR_DMBE, 0, -1, NULL, S_NULL, 0, 0}, // S_DEMON2CHUNK5_4
+ {SPR_D2FX, 32768, 4, NULL, S_DEMON2FX_MOVE2, 0, 0}, // S_DEMON2FX_MOVE1
+ {SPR_D2FX, 32769, 4, NULL, S_DEMON2FX_MOVE3, 0, 0}, // S_DEMON2FX_MOVE2
+ {SPR_D2FX, 32770, 4, NULL, S_DEMON2FX_MOVE4, 0, 0}, // S_DEMON2FX_MOVE3
+ {SPR_D2FX, 32771, 4, NULL, S_DEMON2FX_MOVE5, 0, 0}, // S_DEMON2FX_MOVE4
+ {SPR_D2FX, 32772, 4, NULL, S_DEMON2FX_MOVE6, 0, 0}, // S_DEMON2FX_MOVE5
+ {SPR_D2FX, 32773, 4, NULL, S_DEMON2FX_MOVE1, 0, 0}, // S_DEMON2FX_MOVE6
+ {SPR_D2FX, 32774, 4, NULL, S_DEMON2FX_BOOM2, 0, 0}, // S_DEMON2FX_BOOM1
+ {SPR_D2FX, 32775, 4, NULL, S_DEMON2FX_BOOM3, 0, 0}, // S_DEMON2FX_BOOM2
+ {SPR_D2FX, 32776, 4, NULL, S_DEMON2FX_BOOM4, 0, 0}, // S_DEMON2FX_BOOM3
+ {SPR_D2FX, 32777, 4, NULL, S_DEMON2FX_BOOM5, 0, 0}, // S_DEMON2FX_BOOM4
+ {SPR_D2FX, 32778, 3, NULL, S_DEMON2FX_BOOM6, 0, 0}, // S_DEMON2FX_BOOM5
+ {SPR_D2FX, 32779, 3, NULL, S_NULL, 0, 0}, // S_DEMON2FX_BOOM6
+ {SPR_WRTH, 0, 2, A_WraithRaiseInit, S_WRAITH_RAISE2, 0, 0}, // S_WRAITH_RAISE1
+ {SPR_WRTH, 0, 2, A_WraithRaise, S_WRAITH_RAISE3, 0, 0}, // S_WRAITH_RAISE2
+ {SPR_WRTH, 0, 2, A_FaceTarget, S_WRAITH_RAISE4, 0, 0}, // S_WRAITH_RAISE3
+ {SPR_WRTH, 1, 2, A_WraithRaise, S_WRAITH_RAISE5, 0, 0}, // S_WRAITH_RAISE4
+ {SPR_WRTH, 1, 2, A_WraithRaise, S_WRAITH_RAISE2, 0, 0}, // S_WRAITH_RAISE5
+ {SPR_WRTH, 0, 10, NULL, S_WRAITH_INIT2, 0, 0}, // S_WRAITH_INIT1
+ {SPR_WRTH, 1, 5, A_WraithInit, S_WRAITH_LOOK1, 0, 0}, // S_WRAITH_INIT2
+ {SPR_WRTH, 0, 15, A_WraithLook, S_WRAITH_LOOK2, 0, 0}, // S_WRAITH_LOOK1
+ {SPR_WRTH, 1, 15, A_WraithLook, S_WRAITH_LOOK1, 0, 0}, // S_WRAITH_LOOK2
+ {SPR_WRTH, 0, 4, A_WraithChase, S_WRAITH_CHASE2, 0, 0}, // S_WRAITH_CHASE1
+ {SPR_WRTH, 1, 4, A_WraithChase, S_WRAITH_CHASE3, 0, 0}, // S_WRAITH_CHASE2
+ {SPR_WRTH, 2, 4, A_WraithChase, S_WRAITH_CHASE4, 0, 0}, // S_WRAITH_CHASE3
+ {SPR_WRTH, 3, 4, A_WraithChase, S_WRAITH_CHASE1, 0, 0}, // S_WRAITH_CHASE4
+ {SPR_WRTH, 4, 6, A_FaceTarget, S_WRAITH_ATK1_2, 0, 0}, // S_WRAITH_ATK1_1
+ {SPR_WRTH, 5, 6, A_WraithFX3, S_WRAITH_ATK1_3, 0, 0}, // S_WRAITH_ATK1_2
+ {SPR_WRTH, 6, 6, A_WraithMelee, S_WRAITH_CHASE1, 0, 0}, // S_WRAITH_ATK1_3
+ {SPR_WRTH, 4, 6, A_FaceTarget, S_WRAITH_ATK2_2, 0, 0}, // S_WRAITH_ATK2_1
+ {SPR_WRTH, 5, 6, NULL, S_WRAITH_ATK2_3, 0, 0}, // S_WRAITH_ATK2_2
+ {SPR_WRTH, 6, 6, A_WraithMissile, S_WRAITH_CHASE1, 0, 0}, // S_WRAITH_ATK2_3
+ {SPR_WRTH, 0, 2, NULL, S_WRAITH_PAIN2, 0, 0}, // S_WRAITH_PAIN1
+ {SPR_WRTH, 7, 6, A_Pain, S_WRAITH_CHASE1, 0, 0}, // S_WRAITH_PAIN2
+ {SPR_WRTH, 8, 4, NULL, S_WRAITH_DEATH1_2, 0, 0}, // S_WRAITH_DEATH1_1
+ {SPR_WRTH, 9, 4, A_Scream, S_WRAITH_DEATH1_3, 0, 0}, // S_WRAITH_DEATH1_2
+ {SPR_WRTH, 10, 4, NULL, S_WRAITH_DEATH1_4, 0, 0}, // S_WRAITH_DEATH1_3
+ {SPR_WRTH, 11, 4, NULL, S_WRAITH_DEATH1_5, 0, 0}, // S_WRAITH_DEATH1_4
+ {SPR_WRTH, 12, 4, A_NoBlocking, S_WRAITH_DEATH1_6, 0, 0}, // S_WRAITH_DEATH1_5
+ {SPR_WRTH, 13, 4, A_QueueCorpse, S_WRAITH_DEATH1_7, 0, 0}, // S_WRAITH_DEATH1_6
+ {SPR_WRTH, 14, 4, NULL, S_WRAITH_DEATH1_8, 0, 0}, // S_WRAITH_DEATH1_7
+ {SPR_WRTH, 15, 5, NULL, S_WRAITH_DEATH1_9, 0, 0}, // S_WRAITH_DEATH1_8
+ {SPR_WRTH, 16, 5, NULL, S_WRAITH_DEATH1_0, 0, 0}, // S_WRAITH_DEATH1_9
+ {SPR_WRTH, 17, -1, NULL, S_NULL, 0, 0}, // S_WRAITH_DEATH1_0
+ {SPR_WRT2, 0, 5, NULL, S_WRAITH_DEATH2_2, 0, 0}, // S_WRAITH_DEATH2_1
+ {SPR_WRT2, 1, 5, A_Scream, S_WRAITH_DEATH2_3, 0, 0}, // S_WRAITH_DEATH2_2
+ {SPR_WRT2, 2, 5, NULL, S_WRAITH_DEATH2_4, 0, 0}, // S_WRAITH_DEATH2_3
+ {SPR_WRT2, 3, 5, NULL, S_WRAITH_DEATH2_5, 0, 0}, // S_WRAITH_DEATH2_4
+ {SPR_WRT2, 4, 5, A_NoBlocking, S_WRAITH_DEATH2_6, 0, 0}, // S_WRAITH_DEATH2_5
+ {SPR_WRT2, 5, 5, A_QueueCorpse, S_WRAITH_DEATH2_7, 0, 0}, // S_WRAITH_DEATH2_6
+ {SPR_WRT2, 6, 5, NULL, S_WRAITH_DEATH2_8, 0, 0}, // S_WRAITH_DEATH2_7
+ {SPR_WRT2, 7, -1, NULL, S_NULL, 0, 0}, // S_WRAITH_DEATH2_8
+ {SPR_WRT2, 8, 5, A_FreezeDeath, S_WRAITH_ICE2, 0, 0}, // S_WRAITH_ICE
+ {SPR_WRT2, 8, 1, A_FreezeDeathChunks, S_WRAITH_ICE2, 0, 0}, // S_WRAITH_ICE2
+ {SPR_WRBL, 32768, 3, NULL, S_WRTHFX_MOVE2, 0, 0}, // S_WRTHFX_MOVE1
+ {SPR_WRBL, 32769, 3, A_WraithFX2, S_WRTHFX_MOVE3, 0, 0}, // S_WRTHFX_MOVE2
+ {SPR_WRBL, 32770, 3, NULL, S_WRTHFX_MOVE1, 0, 0}, // S_WRTHFX_MOVE3
+ {SPR_WRBL, 32771, 4, NULL, S_WRTHFX_BOOM2, 0, 0}, // S_WRTHFX_BOOM1
+ {SPR_WRBL, 32772, 4, A_WraithFX2, S_WRTHFX_BOOM3, 0, 0}, // S_WRTHFX_BOOM2
+ {SPR_WRBL, 32773, 4, NULL, S_WRTHFX_BOOM4, 0, 0}, // S_WRTHFX_BOOM3
+ {SPR_WRBL, 32774, 3, A_WraithFX2, S_WRTHFX_BOOM5, 0, 0}, // S_WRTHFX_BOOM4
+ {SPR_WRBL, 32775, 3, A_WraithFX2, S_WRTHFX_BOOM6, 0, 0}, // S_WRTHFX_BOOM5
+ {SPR_WRBL, 32776, 3, NULL, S_NULL, 0, 0}, // S_WRTHFX_BOOM6
+ {SPR_WRBL, 32777, 4, NULL, S_WRTHFX_SIZZLE2, 0, 0}, // S_WRTHFX_SIZZLE1
+ {SPR_WRBL, 32778, 4, NULL, S_WRTHFX_SIZZLE3, 0, 0}, // S_WRTHFX_SIZZLE2
+ {SPR_WRBL, 32779, 4, NULL, S_WRTHFX_SIZZLE4, 0, 0}, // S_WRTHFX_SIZZLE3
+ {SPR_WRBL, 32780, 4, NULL, S_WRTHFX_SIZZLE5, 0, 0}, // S_WRTHFX_SIZZLE4
+ {SPR_WRBL, 32781, 4, NULL, S_WRTHFX_SIZZLE6, 0, 0}, // S_WRTHFX_SIZZLE5
+ {SPR_WRBL, 32782, 4, NULL, S_WRTHFX_SIZZLE7, 0, 0}, // S_WRTHFX_SIZZLE6
+ {SPR_WRBL, 32783, 4, NULL, S_NULL, 0, 0}, // S_WRTHFX_SIZZLE7
+ {SPR_WRBL, 32784, 4, NULL, S_WRTHFX_DROP2, 0, 0}, // S_WRTHFX_DROP1
+ {SPR_WRBL, 32785, 4, NULL, S_WRTHFX_DROP3, 0, 0}, // S_WRTHFX_DROP2
+ {SPR_WRBL, 32786, 4, NULL, S_WRTHFX_DROP1, 0, 0}, // S_WRTHFX_DROP3
+ {SPR_WRBL, 32786, 4, NULL, S_NULL, 0, 0}, // S_WRTHFX_DEAD1
+ {SPR_WRBL, 19, 4, NULL, S_WRTHFX_ADROP2, 0, 0}, // S_WRTHFX_ADROP1
+ {SPR_WRBL, 20, 4, NULL, S_WRTHFX_ADROP3, 0, 0}, // S_WRTHFX_ADROP2
+ {SPR_WRBL, 21, 4, NULL, S_WRTHFX_ADROP4, 0, 0}, // S_WRTHFX_ADROP3
+ {SPR_WRBL, 22, 4, NULL, S_WRTHFX_ADROP1, 0, 0}, // S_WRTHFX_ADROP4
+ {SPR_WRBL, 22, 10, NULL, S_NULL, 0, 0}, // S_WRTHFX_ADEAD1
+ {SPR_WRBL, 23, 7, NULL, S_WRTHFX_BDROP2, 0, 0}, // S_WRTHFX_BDROP1
+ {SPR_WRBL, 24, 7, NULL, S_WRTHFX_BDROP3, 0, 0}, // S_WRTHFX_BDROP2
+ {SPR_WRBL, 25, 7, NULL, S_WRTHFX_BDROP1, 0, 0}, // S_WRTHFX_BDROP3
+ {SPR_WRBL, 25, 35, NULL, S_NULL, 0, 0}, // S_WRTHFX_BDEAD1
+ {SPR_MNTR, 0, 15, NULL, S_MNTR_SPAWN2, 0, 0}, // S_MNTR_SPAWN1
+ {SPR_MNTR, 0, 15, A_MinotaurFade1, S_MNTR_SPAWN3, 0, 0}, // S_MNTR_SPAWN2
+ {SPR_MNTR, 0, 3, A_MinotaurFade2, S_MNTR_LOOK1, 0, 0}, // S_MNTR_SPAWN3
+ {SPR_MNTR, 0, 10, A_MinotaurLook, S_MNTR_LOOK2, 0, 0}, // S_MNTR_LOOK1
+ {SPR_MNTR, 1, 10, A_MinotaurLook, S_MNTR_LOOK1, 0, 0}, // S_MNTR_LOOK2
+ {SPR_MNTR, 0, 5, A_MinotaurChase, S_MNTR_WALK2, 0, 0}, // S_MNTR_WALK1
+ {SPR_MNTR, 1, 5, A_MinotaurChase, S_MNTR_WALK3, 0, 0}, // S_MNTR_WALK2
+ {SPR_MNTR, 2, 5, A_MinotaurChase, S_MNTR_WALK4, 0, 0}, // S_MNTR_WALK3
+ {SPR_MNTR, 3, 5, A_MinotaurChase, S_MNTR_WALK1, 0, 0}, // S_MNTR_WALK4
+ {SPR_MNTR, 0, 5, A_MinotaurRoam, S_MNTR_ROAM2, 0, 0}, // S_MNTR_ROAM1
+ {SPR_MNTR, 1, 5, A_MinotaurRoam, S_MNTR_ROAM3, 0, 0}, // S_MNTR_ROAM2
+ {SPR_MNTR, 2, 5, A_MinotaurRoam, S_MNTR_ROAM4, 0, 0}, // S_MNTR_ROAM3
+ {SPR_MNTR, 3, 5, A_MinotaurRoam, S_MNTR_ROAM1, 0, 0}, // S_MNTR_ROAM4
+ {SPR_MNTR, 6, 10, A_FaceTarget, S_MNTR_ATK1_2, 0, 0}, // S_MNTR_ATK1_1
+ {SPR_MNTR, 7, 7, A_FaceTarget, S_MNTR_ATK1_3, 0, 0}, // S_MNTR_ATK1_2
+ {SPR_MNTR, 8, 12, A_MinotaurAtk1, S_MNTR_WALK1, 0, 0}, // S_MNTR_ATK1_3
+ {SPR_MNTR, 6, 10, A_MinotaurDecide, S_MNTR_ATK2_2, 0, 0}, // S_MNTR_ATK2_1
+ {SPR_MNTR, 9, 4, A_FaceTarget, S_MNTR_ATK2_3, 0, 0}, // S_MNTR_ATK2_2
+ {SPR_MNTR, 10, 9, A_MinotaurAtk2, S_MNTR_WALK1, 0, 0}, // S_MNTR_ATK2_3
+ {SPR_MNTR, 6, 10, A_FaceTarget, S_MNTR_ATK3_2, 0, 0}, // S_MNTR_ATK3_1
+ {SPR_MNTR, 7, 7, A_FaceTarget, S_MNTR_ATK3_3, 0, 0}, // S_MNTR_ATK3_2
+ {SPR_MNTR, 8, 12, A_MinotaurAtk3, S_MNTR_WALK1, 0, 0}, // S_MNTR_ATK3_3
+ {SPR_MNTR, 8, 12, NULL, S_MNTR_ATK3_1, 0, 0}, // S_MNTR_ATK3_4
+ {SPR_MNTR, 5, 2, A_MinotaurCharge, S_MNTR_ATK4_1, 0, 0}, // S_MNTR_ATK4_1
+ {SPR_MNTR, 4, 3, NULL, S_MNTR_PAIN2, 0, 0}, // S_MNTR_PAIN1
+ {SPR_MNTR, 4, 6, A_Pain, S_MNTR_WALK1, 0, 0}, // S_MNTR_PAIN2
+ {SPR_MNTR, 4, 6, NULL, S_MNTR_DIE2, 0, 0}, // S_MNTR_DIE1
+ {SPR_MNTR, 4, 2, A_Scream, S_MNTR_DIE3, 0, 0}, // S_MNTR_DIE2
+ {SPR_MNTR, 4, 5, A_SmokePuffExit, S_MNTR_DIE4, 0, 0}, // S_MNTR_DIE3
+ {SPR_MNTR, 4, 5, NULL, S_MNTR_DIE5, 0, 0}, // S_MNTR_DIE4
+ {SPR_MNTR, 4, 5, A_NoBlocking, S_MNTR_DIE6, 0, 0}, // S_MNTR_DIE5
+ {SPR_MNTR, 4, 5, NULL, S_MNTR_DIE7, 0, 0}, // S_MNTR_DIE6
+ {SPR_MNTR, 4, 5, A_MinotaurFade1, S_MNTR_DIE8, 0, 0}, // S_MNTR_DIE7
+ {SPR_MNTR, 4, 5, A_MinotaurFade0, S_MNTR_DIE9, 0, 0}, // S_MNTR_DIE8
+ {SPR_MNTR, 4, 10, NULL, S_NULL, 0, 0}, // S_MNTR_DIE9
+ {SPR_FX12, 32768, 6, NULL, S_MNTRFX1_2, 0, 0}, // S_MNTRFX1_1
+ {SPR_FX12, 32769, 6, NULL, S_MNTRFX1_1, 0, 0}, // S_MNTRFX1_2
+ {SPR_FX12, 32770, 5, NULL, S_MNTRFXI1_2, 0, 0}, // S_MNTRFXI1_1
+ {SPR_FX12, 32771, 5, NULL, S_MNTRFXI1_3, 0, 0}, // S_MNTRFXI1_2
+ {SPR_FX12, 32772, 5, NULL, S_MNTRFXI1_4, 0, 0}, // S_MNTRFXI1_3
+ {SPR_FX12, 32773, 5, NULL, S_MNTRFXI1_5, 0, 0}, // S_MNTRFXI1_4
+ {SPR_FX12, 32774, 5, NULL, S_MNTRFXI1_6, 0, 0}, // S_MNTRFXI1_5
+ {SPR_FX12, 32775, 5, NULL, S_NULL, 0, 0}, // S_MNTRFXI1_6
+ {SPR_FX13, 0, 2, A_MntrFloorFire, S_MNTRFX2_1, 0, 0}, // S_MNTRFX2_1
+ {SPR_FX13, 32776, 4, A_Explode, S_MNTRFXI2_2, 0, 0}, // S_MNTRFXI2_1
+ {SPR_FX13, 32777, 4, NULL, S_MNTRFXI2_3, 0, 0}, // S_MNTRFXI2_2
+ {SPR_FX13, 32778, 4, NULL, S_MNTRFXI2_4, 0, 0}, // S_MNTRFXI2_3
+ {SPR_FX13, 32779, 4, NULL, S_MNTRFXI2_5, 0, 0}, // S_MNTRFXI2_4
+ {SPR_FX13, 32780, 4, NULL, S_NULL, 0, 0}, // S_MNTRFXI2_5
+ {SPR_FX13, 32771, 4, NULL, S_MNTRFX3_2, 0, 0}, // S_MNTRFX3_1
+ {SPR_FX13, 32770, 4, NULL, S_MNTRFX3_3, 0, 0}, // S_MNTRFX3_2
+ {SPR_FX13, 32769, 5, NULL, S_MNTRFX3_4, 0, 0}, // S_MNTRFX3_3
+ {SPR_FX13, 32770, 5, NULL, S_MNTRFX3_5, 0, 0}, // S_MNTRFX3_4
+ {SPR_FX13, 32771, 5, NULL, S_MNTRFX3_6, 0, 0}, // S_MNTRFX3_5
+ {SPR_FX13, 32772, 5, NULL, S_MNTRFX3_7, 0, 0}, // S_MNTRFX3_6
+ {SPR_FX13, 32773, 4, NULL, S_MNTRFX3_8, 0, 0}, // S_MNTRFX3_7
+ {SPR_FX13, 32774, 4, NULL, S_MNTRFX3_9, 0, 0}, // S_MNTRFX3_8
+ {SPR_FX13, 32775, 4, NULL, S_NULL, 0, 0}, // S_MNTRFX3_9
+ {SPR_MNSM, 0, 3, NULL, S_MINOSMOKE2, 0, 0}, // S_MINOSMOKE1
+ {SPR_MNSM, 1, 3, NULL, S_MINOSMOKE3, 0, 0}, // S_MINOSMOKE2
+ {SPR_MNSM, 2, 3, NULL, S_MINOSMOKE4, 0, 0}, // S_MINOSMOKE3
+ {SPR_MNSM, 3, 3, NULL, S_MINOSMOKE5, 0, 0}, // S_MINOSMOKE4
+ {SPR_MNSM, 4, 3, NULL, S_MINOSMOKE6, 0, 0}, // S_MINOSMOKE5
+ {SPR_MNSM, 5, 3, NULL, S_MINOSMOKE7, 0, 0}, // S_MINOSMOKE6
+ {SPR_MNSM, 6, 3, NULL, S_MINOSMOKE8, 0, 0}, // S_MINOSMOKE7
+ {SPR_MNSM, 7, 3, NULL, S_MINOSMOKE9, 0, 0}, // S_MINOSMOKE8
+ {SPR_MNSM, 8, 3, NULL, S_MINOSMOKE0, 0, 0}, // S_MINOSMOKE9
+ {SPR_MNSM, 9, 3, NULL, S_MINOSMOKEA, 0, 0}, // S_MINOSMOKE0
+ {SPR_MNSM, 10, 3, NULL, S_MINOSMOKEB, 0, 0}, // S_MINOSMOKEA
+ {SPR_MNSM, 11, 3, NULL, S_MINOSMOKEC, 0, 0}, // S_MINOSMOKEB
+ {SPR_MNSM, 12, 3, NULL, S_MINOSMOKED, 0, 0}, // S_MINOSMOKEC
+ {SPR_MNSM, 13, 3, NULL, S_MINOSMOKEE, 0, 0}, // S_MINOSMOKED
+ {SPR_MNSM, 14, 3, NULL, S_MINOSMOKEF, 0, 0}, // S_MINOSMOKEE
+ {SPR_MNSM, 15, 3, NULL, S_MINOSMOKEG, 0, 0}, // S_MINOSMOKEF
+ {SPR_MNSM, 16, 3, NULL, S_NULL, 0, 0}, // S_MINOSMOKEG
+ {SPR_MNSM, 0, 3, NULL, S_MINOSMOKEX2, 0, 0}, // S_MINOSMOKEX1
+ {SPR_MNSM, 1, 3, NULL, S_MINOSMOKEX3, 0, 0}, // S_MINOSMOKEX2
+ {SPR_MNSM, 2, 3, NULL, S_MINOSMOKEX4, 0, 0}, // S_MINOSMOKEX3
+ {SPR_MNSM, 3, 3, NULL, S_MINOSMOKEX5, 0, 0}, // S_MINOSMOKEX4
+ {SPR_MNSM, 4, 3, NULL, S_MINOSMOKEX6, 0, 0}, // S_MINOSMOKEX5
+ {SPR_MNSM, 5, 3, NULL, S_MINOSMOKEX7, 0, 0}, // S_MINOSMOKEX6
+ {SPR_MNSM, 6, 3, NULL, S_MINOSMOKEX8, 0, 0}, // S_MINOSMOKEX7
+ {SPR_MNSM, 7, 3, NULL, S_MINOSMOKEX9, 0, 0}, // S_MINOSMOKEX8
+ {SPR_MNSM, 8, 3, NULL, S_MINOSMOKEX0, 0, 0}, // S_MINOSMOKEX9
+ {SPR_MNSM, 9, 3, NULL, S_MINOSMOKEXA, 0, 0}, // S_MINOSMOKEX0
+ {SPR_MNSM, 8, 3, NULL, S_MINOSMOKEXB, 0, 0}, // S_MINOSMOKEXA
+ {SPR_MNSM, 7, 3, NULL, S_MINOSMOKEXC, 0, 0}, // S_MINOSMOKEXB
+ {SPR_MNSM, 6, 3, NULL, S_MINOSMOKEXD, 0, 0}, // S_MINOSMOKEXC
+ {SPR_MNSM, 5, 3, NULL, S_MINOSMOKEXE, 0, 0}, // S_MINOSMOKEXD
+ {SPR_MNSM, 4, 3, NULL, S_MINOSMOKEXF, 0, 0}, // S_MINOSMOKEXE
+ {SPR_MNSM, 3, 3, NULL, S_MINOSMOKEXG, 0, 0}, // S_MINOSMOKEXF
+ {SPR_MNSM, 2, 3, NULL, S_MINOSMOKEXH, 0, 0}, // S_MINOSMOKEXG
+ {SPR_MNSM, 1, 3, NULL, S_MINOSMOKEXI, 0, 0}, // S_MINOSMOKEXH
+ {SPR_MNSM, 0, 3, NULL, S_NULL, 0, 0}, // S_MINOSMOKEXI
+ {SPR_SSPT, 7, 10, A_Look, S_SERPENT_LOOK1, 0, 0}, // S_SERPENT_LOOK1
+ {SPR_SSPT, 7, 1, A_SerpentChase, S_SERPENT_SWIM2, 0, 0}, // S_SERPENT_SWIM1
+ {SPR_SSPT, 7, 1, A_SerpentChase, S_SERPENT_SWIM3, 0, 0}, // S_SERPENT_SWIM2
+ {SPR_SSPT, 7, 2, A_SerpentHumpDecide, S_SERPENT_SWIM1, 0, 0}, // S_SERPENT_SWIM3
+ {SPR_SSPT, 7, 3, A_SerpentUnHide, S_SERPENT_HUMP2, 0, 0}, // S_SERPENT_HUMP1
+ {SPR_SSPT, 4, 3, A_SerpentRaiseHump, S_SERPENT_HUMP3, 0, 0}, // S_SERPENT_HUMP2
+ {SPR_SSPT, 5, 3, A_SerpentRaiseHump, S_SERPENT_HUMP4, 0, 0}, // S_SERPENT_HUMP3
+ {SPR_SSPT, 6, 3, A_SerpentRaiseHump, S_SERPENT_HUMP5, 0, 0}, // S_SERPENT_HUMP4
+ {SPR_SSPT, 4, 3, A_SerpentRaiseHump, S_SERPENT_HUMP6, 0, 0}, // S_SERPENT_HUMP5
+ {SPR_SSPT, 5, 3, A_SerpentRaiseHump, S_SERPENT_HUMP7, 0, 0}, // S_SERPENT_HUMP6
+ {SPR_SSPT, 6, 3, NULL, S_SERPENT_HUMP8, 0, 0}, // S_SERPENT_HUMP7
+ {SPR_SSPT, 4, 3, NULL, S_SERPENT_HUMP9, 0, 0}, // S_SERPENT_HUMP8
+ {SPR_SSPT, 5, 3, NULL, S_SERPENT_HUMP10, 0, 0}, // S_SERPENT_HUMP9
+ {SPR_SSPT, 6, 3, A_SerpentLowerHump, S_SERPENT_HUMP11, 0, 0}, // S_SERPENT_HUMP10
+ {SPR_SSPT, 4, 3, A_SerpentLowerHump, S_SERPENT_HUMP12, 0, 0}, // S_SERPENT_HUMP11
+ {SPR_SSPT, 5, 3, A_SerpentLowerHump, S_SERPENT_HUMP13, 0, 0}, // S_SERPENT_HUMP12
+ {SPR_SSPT, 6, 3, A_SerpentLowerHump, S_SERPENT_HUMP14, 0, 0}, // S_SERPENT_HUMP13
+ {SPR_SSPT, 4, 3, A_SerpentLowerHump, S_SERPENT_HUMP15, 0, 0}, // S_SERPENT_HUMP14
+ {SPR_SSPT, 5, 3, A_SerpentHide, S_SERPENT_SWIM1, 0, 0}, // S_SERPENT_HUMP15
+ {SPR_SSPT, 0, 1, A_UnHideThing, S_SERPENT_SURFACE2, 0, 0}, // S_SERPENT_SURFACE1
+ {SPR_SSPT, 0, 1, A_SerpentBirthScream, S_SERPENT_SURFACE3, 0, 0}, // S_SERPENT_SURFACE2
+ {SPR_SSPT, 1, 3, A_SetShootable, S_SERPENT_SURFACE4, 0, 0}, // S_SERPENT_SURFACE3
+ {SPR_SSPT, 2, 3, NULL, S_SERPENT_SURFACE5, 0, 0}, // S_SERPENT_SURFACE4
+ {SPR_SSPT, 3, 4, A_SerpentCheckForAttack, S_SERPENT_DIVE1, 0, 0}, // S_SERPENT_SURFACE5
+ {SPR_SSDV, 0, 4, NULL, S_SERPENT_DIVE2, 0, 0}, // S_SERPENT_DIVE1
+ {SPR_SSDV, 1, 4, NULL, S_SERPENT_DIVE3, 0, 0}, // S_SERPENT_DIVE2
+ {SPR_SSDV, 2, 4, NULL, S_SERPENT_DIVE4, 0, 0}, // S_SERPENT_DIVE3
+ {SPR_SSDV, 3, 4, A_UnSetShootable, S_SERPENT_DIVE5, 0, 0}, // S_SERPENT_DIVE4
+ {SPR_SSDV, 4, 3, A_SerpentDiveSound, S_SERPENT_DIVE6, 0, 0}, // S_SERPENT_DIVE5
+ {SPR_SSDV, 5, 3, NULL, S_SERPENT_DIVE7, 0, 0}, // S_SERPENT_DIVE6
+ {SPR_SSDV, 6, 4, NULL, S_SERPENT_DIVE8, 0, 0}, // S_SERPENT_DIVE7
+ {SPR_SSDV, 7, 4, NULL, S_SERPENT_DIVE9, 0, 0}, // S_SERPENT_DIVE8
+ {SPR_SSDV, 8, 3, NULL, S_SERPENT_DIVE10, 0, 0}, // S_SERPENT_DIVE9
+ {SPR_SSDV, 9, 3, A_SerpentHide, S_SERPENT_SWIM1, 0, 0}, // S_SERPENT_DIVE10
+ {SPR_SSPT, 8, 5, A_SerpentWalk, S_SERPENT_WALK2, 0, 0}, // S_SERPENT_WALK1
+ {SPR_SSPT, 9, 5, A_SerpentWalk, S_SERPENT_WALK3, 0, 0}, // S_SERPENT_WALK2
+ {SPR_SSPT, 8, 5, A_SerpentWalk, S_SERPENT_WALK4, 0, 0}, // S_SERPENT_WALK3
+ {SPR_SSPT, 9, 5, A_SerpentCheckForAttack, S_SERPENT_DIVE1, 0, 0}, // S_SERPENT_WALK4
+ {SPR_SSPT, 11, 5, NULL, S_SERPENT_PAIN2, 0, 0}, // S_SERPENT_PAIN1
+ {SPR_SSPT, 11, 5, A_Pain, S_SERPENT_DIVE1, 0, 0}, // S_SERPENT_PAIN2
+ {SPR_SSPT, 10, 6, A_FaceTarget, S_SERPENT_ATK2, 0, 0}, // S_SERPENT_ATK1
+ {SPR_SSPT, 11, 5, A_SerpentChooseAttack, S_SERPENT_MELEE1, 0, 0}, // S_SERPENT_ATK2
+ {SPR_SSPT, 13, 5, A_SerpentMeleeAttack, S_SERPENT_DIVE1, 0, 0}, // S_SERPENT_MELEE1
+ {SPR_SSPT, 13, 5, A_SerpentMissileAttack, S_SERPENT_DIVE1, 0, 0}, // S_SERPENT_MISSILE1
+ {SPR_SSPT, 14, 4, NULL, S_SERPENT_DIE2, 0, 0}, // S_SERPENT_DIE1
+ {SPR_SSPT, 15, 4, A_Scream, S_SERPENT_DIE3, 0, 0}, // S_SERPENT_DIE2
+ {SPR_SSPT, 16, 4, A_NoBlocking, S_SERPENT_DIE4, 0, 0}, // S_SERPENT_DIE3
+ {SPR_SSPT, 17, 4, NULL, S_SERPENT_DIE5, 0, 0}, // S_SERPENT_DIE4
+ {SPR_SSPT, 18, 4, NULL, S_SERPENT_DIE6, 0, 0}, // S_SERPENT_DIE5
+ {SPR_SSPT, 19, 4, NULL, S_SERPENT_DIE7, 0, 0}, // S_SERPENT_DIE6
+ {SPR_SSPT, 20, 4, NULL, S_SERPENT_DIE8, 0, 0}, // S_SERPENT_DIE7
+ {SPR_SSPT, 21, 4, NULL, S_SERPENT_DIE9, 0, 0}, // S_SERPENT_DIE8
+ {SPR_SSPT, 22, 4, NULL, S_SERPENT_DIE10, 0, 0}, // S_SERPENT_DIE9
+ {SPR_SSPT, 23, 4, NULL, S_SERPENT_DIE11, 0, 0}, // S_SERPENT_DIE10
+ {SPR_SSPT, 24, 4, NULL, S_SERPENT_DIE12, 0, 0}, // S_SERPENT_DIE11
+ {SPR_SSPT, 25, 4, NULL, S_NULL, 0, 0}, // S_SERPENT_DIE12
+ {SPR_SSXD, 0, 4, NULL, S_SERPENT_XDIE2, 0, 0}, // S_SERPENT_XDIE1
+ {SPR_SSXD, 1, 4, A_SerpentHeadPop, S_SERPENT_XDIE3, 0, 0}, // S_SERPENT_XDIE2
+ {SPR_SSXD, 2, 4, A_NoBlocking, S_SERPENT_XDIE4, 0, 0}, // S_SERPENT_XDIE3
+ {SPR_SSXD, 3, 4, NULL, S_SERPENT_XDIE5, 0, 0}, // S_SERPENT_XDIE4
+ {SPR_SSXD, 4, 4, NULL, S_SERPENT_XDIE6, 0, 0}, // S_SERPENT_XDIE5
+ {SPR_SSXD, 5, 3, NULL, S_SERPENT_XDIE7, 0, 0}, // S_SERPENT_XDIE6
+ {SPR_SSXD, 6, 3, NULL, S_SERPENT_XDIE8, 0, 0}, // S_SERPENT_XDIE7
+ {SPR_SSXD, 7, 3, A_SerpentSpawnGibs, S_NULL, 0, 0}, // S_SERPENT_XDIE8
+ {SPR_SSPT, 26, 5, A_FreezeDeath, S_SERPENT_ICE2, 0, 0}, // S_SERPENT_ICE
+ {SPR_SSPT, 26, 1, A_FreezeDeathChunks, S_SERPENT_ICE2, 0, 0}, // S_SERPENT_ICE2
+ {SPR_SSFX, 32768, 3, A_ContMobjSound, S_SERPENT_FX2, 0, 0}, // S_SERPENT_FX1
+ {SPR_SSFX, 32769, 3, NULL, S_SERPENT_FX3, 0, 0}, // S_SERPENT_FX2
+ {SPR_SSFX, 32768, 3, NULL, S_SERPENT_FX4, 0, 0}, // S_SERPENT_FX3
+ {SPR_SSFX, 32769, 3, NULL, S_SERPENT_FX1, 0, 0}, // S_SERPENT_FX4
+ {SPR_SSFX, 32770, 4, NULL, S_SERPENT_FX_X2, 0, 0}, // S_SERPENT_FX_X1
+ {SPR_SSFX, 32771, 4, NULL, S_SERPENT_FX_X3, 0, 0}, // S_SERPENT_FX_X2
+ {SPR_SSFX, 32772, 4, NULL, S_SERPENT_FX_X4, 0, 0}, // S_SERPENT_FX_X3
+ {SPR_SSFX, 32773, 4, NULL, S_SERPENT_FX_X5, 0, 0}, // S_SERPENT_FX_X4
+ {SPR_SSFX, 32774, 4, NULL, S_SERPENT_FX_X6, 0, 0}, // S_SERPENT_FX_X5
+ {SPR_SSFX, 32775, 4, NULL, S_NULL, 0, 0}, // S_SERPENT_FX_X6
+ {SPR_SSXD, 8, 4, A_SerpentHeadCheck, S_SERPENT_HEAD2, 0, 0}, // S_SERPENT_HEAD1
+ {SPR_SSXD, 9, 4, A_SerpentHeadCheck, S_SERPENT_HEAD3, 0, 0}, // S_SERPENT_HEAD2
+ {SPR_SSXD, 10, 4, A_SerpentHeadCheck, S_SERPENT_HEAD4, 0, 0}, // S_SERPENT_HEAD3
+ {SPR_SSXD, 11, 4, A_SerpentHeadCheck, S_SERPENT_HEAD5, 0, 0}, // S_SERPENT_HEAD4
+ {SPR_SSXD, 12, 4, A_SerpentHeadCheck, S_SERPENT_HEAD6, 0, 0}, // S_SERPENT_HEAD5
+ {SPR_SSXD, 13, 4, A_SerpentHeadCheck, S_SERPENT_HEAD7, 0, 0}, // S_SERPENT_HEAD6
+ {SPR_SSXD, 14, 4, A_SerpentHeadCheck, S_SERPENT_HEAD8, 0, 0}, // S_SERPENT_HEAD7
+ {SPR_SSXD, 15, 4, A_SerpentHeadCheck, S_SERPENT_HEAD1, 0, 0}, // S_SERPENT_HEAD8
+ {SPR_SSXD, 18, -1, NULL, S_SERPENT_HEAD_X1, 0, 0}, // S_SERPENT_HEAD_X1
+ {SPR_SSXD, 16, 6, NULL, S_SERPENT_GIB1_2, 0, 0}, // S_SERPENT_GIB1_1
+ {SPR_SSXD, 16, 6, A_FloatGib, S_SERPENT_GIB1_3, 0, 0}, // S_SERPENT_GIB1_2
+ {SPR_SSXD, 16, 8, A_FloatGib, S_SERPENT_GIB1_4, 0, 0}, // S_SERPENT_GIB1_3
+ {SPR_SSXD, 16, 8, A_FloatGib, S_SERPENT_GIB1_5, 0, 0}, // S_SERPENT_GIB1_4
+ {SPR_SSXD, 16, 12, A_FloatGib, S_SERPENT_GIB1_6, 0, 0}, // S_SERPENT_GIB1_5
+ {SPR_SSXD, 16, 12, A_FloatGib, S_SERPENT_GIB1_7, 0, 0}, // S_SERPENT_GIB1_6
+ {SPR_SSXD, 16, 232, A_DelayGib, S_SERPENT_GIB1_8, 0, 0}, // S_SERPENT_GIB1_7
+ {SPR_SSXD, 16, 12, A_SinkGib, S_SERPENT_GIB1_9, 0, 0}, // S_SERPENT_GIB1_8
+ {SPR_SSXD, 16, 12, A_SinkGib, S_SERPENT_GIB1_10, 0, 0}, // S_SERPENT_GIB1_9
+ {SPR_SSXD, 16, 8, A_SinkGib, S_SERPENT_GIB1_11, 0, 0}, // S_SERPENT_GIB1_10
+ {SPR_SSXD, 16, 8, A_SinkGib, S_SERPENT_GIB1_12, 0, 0}, // S_SERPENT_GIB1_11
+ {SPR_SSXD, 16, 8, A_SinkGib, S_NULL, 0, 0}, // S_SERPENT_GIB1_12
+ {SPR_SSXD, 17, 6, NULL, S_SERPENT_GIB2_2, 0, 0}, // S_SERPENT_GIB2_1
+ {SPR_SSXD, 17, 6, A_FloatGib, S_SERPENT_GIB2_3, 0, 0}, // S_SERPENT_GIB2_2
+ {SPR_SSXD, 17, 8, A_FloatGib, S_SERPENT_GIB2_4, 0, 0}, // S_SERPENT_GIB2_3
+ {SPR_SSXD, 17, 8, A_FloatGib, S_SERPENT_GIB2_5, 0, 0}, // S_SERPENT_GIB2_4
+ {SPR_SSXD, 17, 12, A_FloatGib, S_SERPENT_GIB2_6, 0, 0}, // S_SERPENT_GIB2_5
+ {SPR_SSXD, 17, 12, A_FloatGib, S_SERPENT_GIB2_7, 0, 0}, // S_SERPENT_GIB2_6
+ {SPR_SSXD, 17, 232, A_DelayGib, S_SERPENT_GIB2_8, 0, 0}, // S_SERPENT_GIB2_7
+ {SPR_SSXD, 17, 12, A_SinkGib, S_SERPENT_GIB2_9, 0, 0}, // S_SERPENT_GIB2_8
+ {SPR_SSXD, 17, 12, A_SinkGib, S_SERPENT_GIB2_10, 0, 0}, // S_SERPENT_GIB2_9
+ {SPR_SSXD, 17, 8, A_SinkGib, S_SERPENT_GIB2_11, 0, 0}, // S_SERPENT_GIB2_10
+ {SPR_SSXD, 17, 8, A_SinkGib, S_SERPENT_GIB2_12, 0, 0}, // S_SERPENT_GIB2_11
+ {SPR_SSXD, 17, 8, A_SinkGib, S_NULL, 0, 0}, // S_SERPENT_GIB2_12
+ {SPR_SSXD, 19, 6, NULL, S_SERPENT_GIB3_2, 0, 0}, // S_SERPENT_GIB3_1
+ {SPR_SSXD, 19, 6, A_FloatGib, S_SERPENT_GIB3_3, 0, 0}, // S_SERPENT_GIB3_2
+ {SPR_SSXD, 19, 8, A_FloatGib, S_SERPENT_GIB3_4, 0, 0}, // S_SERPENT_GIB3_3
+ {SPR_SSXD, 19, 8, A_FloatGib, S_SERPENT_GIB3_5, 0, 0}, // S_SERPENT_GIB3_4
+ {SPR_SSXD, 19, 12, A_FloatGib, S_SERPENT_GIB3_6, 0, 0}, // S_SERPENT_GIB3_5
+ {SPR_SSXD, 19, 12, A_FloatGib, S_SERPENT_GIB3_7, 0, 0}, // S_SERPENT_GIB3_6
+ {SPR_SSXD, 19, 232, A_DelayGib, S_SERPENT_GIB3_8, 0, 0}, // S_SERPENT_GIB3_7
+ {SPR_SSXD, 19, 12, A_SinkGib, S_SERPENT_GIB3_9, 0, 0}, // S_SERPENT_GIB3_8
+ {SPR_SSXD, 19, 12, A_SinkGib, S_SERPENT_GIB3_10, 0, 0}, // S_SERPENT_GIB3_9
+ {SPR_SSXD, 19, 8, A_SinkGib, S_SERPENT_GIB3_11, 0, 0}, // S_SERPENT_GIB3_10
+ {SPR_SSXD, 19, 8, A_SinkGib, S_SERPENT_GIB3_12, 0, 0}, // S_SERPENT_GIB3_11
+ {SPR_SSXD, 19, 8, A_SinkGib, S_NULL, 0, 0}, // S_SERPENT_GIB3_12
+ {SPR_BISH, 0, 10, A_Look, S_BISHOP_LOOK1, 0, 0}, // S_BISHOP_LOOK1
+ {SPR_BISH, 0, 1, A_BishopDecide, S_BISHOP_WALK1, 0, 0}, // S_BISHOP_DECIDE
+ {SPR_BISH, 0, 2, A_BishopDoBlur, S_BISHOP_BLUR2, 0, 0}, // S_BISHOP_BLUR1
+ {SPR_BISH, 0, 4, A_BishopSpawnBlur, S_BISHOP_BLUR2, 0, 0}, // S_BISHOP_BLUR2
+ {SPR_BISH, 0, 2, A_Chase, S_BISHOP_WALK2, 0, 0}, // S_BISHOP_WALK1
+ {SPR_BISH, 0, 2, A_BishopChase, S_BISHOP_WALK3, 0, 0}, // S_BISHOP_WALK2
+ {SPR_BISH, 0, 2, NULL, S_BISHOP_WALK4, 0, 0}, // S_BISHOP_WALK3
+ {SPR_BISH, 1, 2, A_BishopChase, S_BISHOP_WALK5, 0, 0}, // S_BISHOP_WALK4
+ {SPR_BISH, 1, 2, A_Chase, S_BISHOP_WALK6, 0, 0}, // S_BISHOP_WALK5
+ {SPR_BISH, 1, 2, A_BishopChase, S_BISHOP_DECIDE, 0, 0}, // S_BISHOP_WALK6
+ {SPR_BISH, 0, 3, A_FaceTarget, S_BISHOP_ATK2, 0, 0}, // S_BISHOP_ATK1
+ {SPR_BISH, 32771, 3, A_FaceTarget, S_BISHOP_ATK3, 0, 0}, // S_BISHOP_ATK2
+ {SPR_BISH, 32772, 3, A_FaceTarget, S_BISHOP_ATK4, 0, 0}, // S_BISHOP_ATK3
+ {SPR_BISH, 32773, 3, A_BishopAttack, S_BISHOP_ATK5, 0, 0}, // S_BISHOP_ATK4
+ {SPR_BISH, 32773, 5, A_BishopAttack2, S_BISHOP_ATK5, 0, 0}, // S_BISHOP_ATK5
+ {SPR_BISH, 2, 6, A_Pain, S_BISHOP_PAIN2, 0, 0}, // S_BISHOP_PAIN1
+ {SPR_BISH, 2, 6, A_BishopPainBlur, S_BISHOP_PAIN3, 0, 0}, // S_BISHOP_PAIN2
+ {SPR_BISH, 2, 6, A_BishopPainBlur, S_BISHOP_PAIN4, 0, 0}, // S_BISHOP_PAIN3
+ {SPR_BISH, 2, 6, A_BishopPainBlur, S_BISHOP_PAIN5, 0, 0}, // S_BISHOP_PAIN4
+ {SPR_BISH, 2, 0, NULL, S_BISHOP_WALK1, 0, 0}, // S_BISHOP_PAIN5
+ {SPR_BISH, 6, 6, NULL, S_BISHOP_DEATH2, 0, 0}, // S_BISHOP_DEATH1
+ {SPR_BISH, 32775, 6, A_Scream, S_BISHOP_DEATH3, 0, 0}, // S_BISHOP_DEATH2
+ {SPR_BISH, 32776, 5, A_NoBlocking, S_BISHOP_DEATH4, 0, 0}, // S_BISHOP_DEATH3
+ {SPR_BISH, 32777, 5, A_Explode, S_BISHOP_DEATH5, 0, 0}, // S_BISHOP_DEATH4
+ {SPR_BISH, 32778, 5, NULL, S_BISHOP_DEATH6, 0, 0}, // S_BISHOP_DEATH5
+ {SPR_BISH, 32779, 4, NULL, S_BISHOP_DEATH7, 0, 0}, // S_BISHOP_DEATH6
+ {SPR_BISH, 32780, 4, NULL, S_BISHOP_DEATH8, 0, 0}, // S_BISHOP_DEATH7
+ {SPR_BISH, 13, 4, A_BishopPuff, S_BISHOP_DEATH9, 0, 0}, // S_BISHOP_DEATH8
+ {SPR_BISH, 14, 4, A_QueueCorpse, S_BISHOP_DEATH10, 0, 0}, // S_BISHOP_DEATH9
+ {SPR_BISH, 15, -1, NULL, S_NULL, 0, 0}, // S_BISHOP_DEATH10
+ {SPR_BISH, 23, 5, A_FreezeDeath, S_BISHOP_ICE2, 0, 0}, // S_BISHOP_ICE
+ {SPR_BISH, 23, 1, A_FreezeDeathChunks, S_BISHOP_ICE2, 0, 0}, // S_BISHOP_ICE2
+ {SPR_BISH, 16, 5, NULL, S_BISHOP_PUFF2, 0, 0}, // S_BISHOP_PUFF1
+ {SPR_BISH, 17, 5, NULL, S_BISHOP_PUFF3, 0, 0}, // S_BISHOP_PUFF2
+ {SPR_BISH, 18, 5, NULL, S_BISHOP_PUFF4, 0, 0}, // S_BISHOP_PUFF3
+ {SPR_BISH, 19, 5, NULL, S_BISHOP_PUFF5, 0, 0}, // S_BISHOP_PUFF4
+ {SPR_BISH, 20, 6, NULL, S_BISHOP_PUFF6, 0, 0}, // S_BISHOP_PUFF5
+ {SPR_BISH, 21, 6, NULL, S_BISHOP_PUFF7, 0, 0}, // S_BISHOP_PUFF6
+ {SPR_BISH, 22, 5, NULL, S_NULL, 0, 0}, // S_BISHOP_PUFF7
+ {SPR_BISH, 0, 16, NULL, S_BISHOPBLUR2, 0, 0}, // S_BISHOPBLUR1
+ {SPR_BISH, 0, 8, A_SetAltShadow, S_NULL, 0, 0}, // S_BISHOPBLUR2
+ {SPR_BISH, 2, 8, NULL, S_NULL, 0, 0}, // S_BISHOPPAINBLUR1
+ {SPR_BPFX, 32768, 1, A_BishopMissileWeave, S_BISHFX1_2, 0, 0}, // S_BISHFX1_1
+ {SPR_BPFX, 32769, 1, A_BishopMissileWeave, S_BISHFX1_3, 0, 0}, // S_BISHFX1_2
+ {SPR_BPFX, 32768, 1, A_BishopMissileWeave, S_BISHFX1_4, 0, 0}, // S_BISHFX1_3
+ {SPR_BPFX, 32769, 1, A_BishopMissileWeave, S_BISHFX1_5, 0, 0}, // S_BISHFX1_4
+ {SPR_BPFX, 32769, 0, A_BishopMissileSeek, S_BISHFX1_1, 0, 0}, // S_BISHFX1_5
+ {SPR_BPFX, 32770, 4, NULL, S_BISHFXI1_2, 0, 0}, // S_BISHFXI1_1
+ {SPR_BPFX, 32771, 4, NULL, S_BISHFXI1_3, 0, 0}, // S_BISHFXI1_2
+ {SPR_BPFX, 32772, 4, NULL, S_BISHFXI1_4, 0, 0}, // S_BISHFXI1_3
+ {SPR_BPFX, 32773, 4, NULL, S_BISHFXI1_5, 0, 0}, // S_BISHFXI1_4
+ {SPR_BPFX, 32774, 3, NULL, S_BISHFXI1_6, 0, 0}, // S_BISHFXI1_5
+ {SPR_BPFX, 32775, 3, NULL, S_NULL, 0, 0}, // S_BISHFXI1_6
+ {SPR_DRAG, 3, 10, A_Look, S_DRAGON_LOOK1, 0, 0}, // S_DRAGON_LOOK1
+ {SPR_DRAG, 2, 5, NULL, S_DRAGON_INIT2, 0, 0}, // S_DRAGON_INIT
+ {SPR_DRAG, 1, 5, NULL, S_DRAGON_INIT3, 0, 0}, // S_DRAGON_INIT2
+ {SPR_DRAG, 0, 5, A_DragonInitFlight, S_DRAGON_WALK1, 0, 0}, // S_DRAGON_INIT3
+ {SPR_DRAG, 1, 3, A_DragonFlap, S_DRAGON_WALK2, 0, 0}, // S_DRAGON_WALK1
+ {SPR_DRAG, 1, 3, A_DragonFlight, S_DRAGON_WALK3, 0, 0}, // S_DRAGON_WALK2
+ {SPR_DRAG, 2, 3, A_DragonFlight, S_DRAGON_WALK4, 0, 0}, // S_DRAGON_WALK3
+ {SPR_DRAG, 2, 3, A_DragonFlight, S_DRAGON_WALK5, 0, 0}, // S_DRAGON_WALK4
+ {SPR_DRAG, 3, 3, A_DragonFlight, S_DRAGON_WALK6, 0, 0}, // S_DRAGON_WALK5
+ {SPR_DRAG, 3, 3, A_DragonFlight, S_DRAGON_WALK7, 0, 0}, // S_DRAGON_WALK6
+ {SPR_DRAG, 2, 3, A_DragonFlight, S_DRAGON_WALK8, 0, 0}, // S_DRAGON_WALK7
+ {SPR_DRAG, 2, 3, A_DragonFlight, S_DRAGON_WALK9, 0, 0}, // S_DRAGON_WALK8
+ {SPR_DRAG, 1, 3, A_DragonFlight, S_DRAGON_WALK10, 0, 0}, // S_DRAGON_WALK9
+ {SPR_DRAG, 1, 3, A_DragonFlight, S_DRAGON_WALK11, 0, 0}, // S_DRAGON_WALK10
+ {SPR_DRAG, 0, 3, A_DragonFlight, S_DRAGON_WALK12, 0, 0}, // S_DRAGON_WALK11
+ {SPR_DRAG, 0, 3, A_DragonFlight, S_DRAGON_WALK1, 0, 0}, // S_DRAGON_WALK12
+ {SPR_DRAG, 4, 8, A_DragonAttack, S_DRAGON_WALK1, 0, 0}, // S_DRAGON_ATK1
+ {SPR_DRAG, 5, 10, A_DragonPain, S_DRAGON_WALK1, 0, 0}, // S_DRAGON_PAIN1
+ {SPR_DRAG, 6, 5, A_Scream, S_DRAGON_DEATH2, 0, 0}, // S_DRAGON_DEATH1
+ {SPR_DRAG, 7, 4, A_NoBlocking, S_DRAGON_DEATH3, 0, 0}, // S_DRAGON_DEATH2
+ {SPR_DRAG, 8, 4, NULL, S_DRAGON_DEATH4, 0, 0}, // S_DRAGON_DEATH3
+ {SPR_DRAG, 9, 4, A_DragonCheckCrash, S_DRAGON_DEATH4, 0, 0}, // S_DRAGON_DEATH4
+ {SPR_DRAG, 10, 5, NULL, S_DRAGON_CRASH2, 0, 0}, // S_DRAGON_CRASH1
+ {SPR_DRAG, 11, 5, NULL, S_DRAGON_CRASH3, 0, 0}, // S_DRAGON_CRASH2
+ {SPR_DRAG, 12, -1, NULL, S_NULL, 0, 0}, // S_DRAGON_CRASH3
+ {SPR_DRFX, 32768, 4, NULL, S_DRAGON_FX1_2, 0, 0}, // S_DRAGON_FX1_1
+ {SPR_DRFX, 32769, 4, NULL, S_DRAGON_FX1_3, 0, 0}, // S_DRAGON_FX1_2
+ {SPR_DRFX, 32770, 4, NULL, S_DRAGON_FX1_4, 0, 0}, // S_DRAGON_FX1_3
+ {SPR_DRFX, 32771, 4, NULL, S_DRAGON_FX1_5, 0, 0}, // S_DRAGON_FX1_4
+ {SPR_DRFX, 32772, 4, NULL, S_DRAGON_FX1_6, 0, 0}, // S_DRAGON_FX1_5
+ {SPR_DRFX, 32773, 4, NULL, S_DRAGON_FX1_1, 0, 0}, // S_DRAGON_FX1_6
+ {SPR_DRFX, 32774, 4, NULL, S_DRAGON_FX1_X2, 0, 0}, // S_DRAGON_FX1_X1
+ {SPR_DRFX, 32775, 4, NULL, S_DRAGON_FX1_X3, 0, 0}, // S_DRAGON_FX1_X2
+ {SPR_DRFX, 32776, 4, NULL, S_DRAGON_FX1_X4, 0, 0}, // S_DRAGON_FX1_X3
+ {SPR_DRFX, 32777, 4, A_DragonFX2, S_DRAGON_FX1_X5, 0, 0}, // S_DRAGON_FX1_X4
+ {SPR_DRFX, 32778, 3, NULL, S_DRAGON_FX1_X6, 0, 0}, // S_DRAGON_FX1_X5
+ {SPR_DRFX, 32779, 3, NULL, S_NULL, 0, 0}, // S_DRAGON_FX1_X6
+ {SPR_CFCF, 32784, 1, NULL, S_DRAGON_FX2_2, 0, 0}, // S_DRAGON_FX2_1
+ {SPR_CFCF, 32784, 4, A_UnHideThing, S_DRAGON_FX2_3, 0, 0}, // S_DRAGON_FX2_2
+ {SPR_CFCF, 32785, 3, A_Scream, S_DRAGON_FX2_4, 0, 0}, // S_DRAGON_FX2_3
+ {SPR_CFCF, 32786, 4, NULL, S_DRAGON_FX2_5, 0, 0}, // S_DRAGON_FX2_4
+ {SPR_CFCF, 32787, 3, A_Explode, S_DRAGON_FX2_6, 0, 0}, // S_DRAGON_FX2_5
+ {SPR_CFCF, 32788, 4, NULL, S_DRAGON_FX2_7, 0, 0}, // S_DRAGON_FX2_6
+ {SPR_CFCF, 32789, 3, NULL, S_DRAGON_FX2_8, 0, 0}, // S_DRAGON_FX2_7
+ {SPR_CFCF, 32790, 4, NULL, S_DRAGON_FX2_9, 0, 0}, // S_DRAGON_FX2_8
+ {SPR_CFCF, 32791, 3, NULL, S_DRAGON_FX2_10, 0, 0}, // S_DRAGON_FX2_9
+ {SPR_CFCF, 32792, 4, NULL, S_DRAGON_FX2_11, 0, 0}, // S_DRAGON_FX2_10
+ {SPR_CFCF, 32793, 3, NULL, S_NULL, 0, 0}, // S_DRAGON_FX2_11
+ {SPR_ARM1, 0, -1, NULL, S_NULL, 0, 0}, // S_ARMOR_1
+ {SPR_ARM2, 0, -1, NULL, S_NULL, 0, 0}, // S_ARMOR_2
+ {SPR_ARM3, 0, -1, NULL, S_NULL, 0, 0}, // S_ARMOR_3
+ {SPR_ARM4, 0, -1, NULL, S_NULL, 0, 0}, // S_ARMOR_4
+ {SPR_MAN1, 32768, 4, NULL, S_MANA1_2, 0, 0}, // S_MANA1_1
+ {SPR_MAN1, 32769, 4, NULL, S_MANA1_3, 0, 0}, // S_MANA1_2
+ {SPR_MAN1, 32770, 4, NULL, S_MANA1_4, 0, 0}, // S_MANA1_3
+ {SPR_MAN1, 32771, 4, NULL, S_MANA1_5, 0, 0}, // S_MANA1_4
+ {SPR_MAN1, 32772, 4, NULL, S_MANA1_6, 0, 0}, // S_MANA1_5
+ {SPR_MAN1, 32773, 4, NULL, S_MANA1_7, 0, 0}, // S_MANA1_6
+ {SPR_MAN1, 32774, 4, NULL, S_MANA1_8, 0, 0}, // S_MANA1_7
+ {SPR_MAN1, 32775, 4, NULL, S_MANA1_9, 0, 0}, // S_MANA1_8
+ {SPR_MAN1, 32776, 4, NULL, S_MANA1_1, 0, 0}, // S_MANA1_9
+ {SPR_MAN2, 32768, 4, NULL, S_MANA2_2, 0, 0}, // S_MANA2_1
+ {SPR_MAN2, 32769, 4, NULL, S_MANA2_3, 0, 0}, // S_MANA2_2
+ {SPR_MAN2, 32770, 4, NULL, S_MANA2_4, 0, 0}, // S_MANA2_3
+ {SPR_MAN2, 32771, 4, NULL, S_MANA2_5, 0, 0}, // S_MANA2_4
+ {SPR_MAN2, 32772, 4, NULL, S_MANA2_6, 0, 0}, // S_MANA2_5
+ {SPR_MAN2, 32773, 4, NULL, S_MANA2_7, 0, 0}, // S_MANA2_6
+ {SPR_MAN2, 32774, 4, NULL, S_MANA2_8, 0, 0}, // S_MANA2_7
+ {SPR_MAN2, 32775, 4, NULL, S_MANA2_9, 0, 0}, // S_MANA2_8
+ {SPR_MAN2, 32776, 4, NULL, S_MANA2_10, 0, 0}, // S_MANA2_9
+ {SPR_MAN2, 32777, 4, NULL, S_MANA2_11, 0, 0}, // S_MANA2_10
+ {SPR_MAN2, 32778, 4, NULL, S_MANA2_12, 0, 0}, // S_MANA2_11
+ {SPR_MAN2, 32779, 4, NULL, S_MANA2_13, 0, 0}, // S_MANA2_12
+ {SPR_MAN2, 32780, 4, NULL, S_MANA2_14, 0, 0}, // S_MANA2_13
+ {SPR_MAN2, 32781, 4, NULL, S_MANA2_15, 0, 0}, // S_MANA2_14
+ {SPR_MAN2, 32782, 4, NULL, S_MANA2_16, 0, 0}, // S_MANA2_15
+ {SPR_MAN2, 32783, 4, NULL, S_MANA2_1, 0, 0}, // S_MANA2_16
+ {SPR_MAN3, 32768, 4, NULL, S_MANA3_2, 0, 0}, // S_MANA3_1
+ {SPR_MAN3, 32769, 4, NULL, S_MANA3_3, 0, 0}, // S_MANA3_2
+ {SPR_MAN3, 32770, 4, NULL, S_MANA3_4, 0, 0}, // S_MANA3_3
+ {SPR_MAN3, 32771, 4, NULL, S_MANA3_5, 0, 0}, // S_MANA3_4
+ {SPR_MAN3, 32772, 4, NULL, S_MANA3_6, 0, 0}, // S_MANA3_5
+ {SPR_MAN3, 32773, 4, NULL, S_MANA3_7, 0, 0}, // S_MANA3_6
+ {SPR_MAN3, 32774, 4, NULL, S_MANA3_8, 0, 0}, // S_MANA3_7
+ {SPR_MAN3, 32775, 4, NULL, S_MANA3_9, 0, 0}, // S_MANA3_8
+ {SPR_MAN3, 32776, 4, NULL, S_MANA3_10, 0, 0}, // S_MANA3_9
+ {SPR_MAN3, 32777, 4, NULL, S_MANA3_11, 0, 0}, // S_MANA3_10
+ {SPR_MAN3, 32778, 4, NULL, S_MANA3_12, 0, 0}, // S_MANA3_11
+ {SPR_MAN3, 32779, 4, NULL, S_MANA3_13, 0, 0}, // S_MANA3_12
+ {SPR_MAN3, 32780, 4, NULL, S_MANA3_14, 0, 0}, // S_MANA3_13
+ {SPR_MAN3, 32781, 4, NULL, S_MANA3_15, 0, 0}, // S_MANA3_14
+ {SPR_MAN3, 32782, 4, NULL, S_MANA3_16, 0, 0}, // S_MANA3_15
+ {SPR_MAN3, 32783, 4, NULL, S_MANA3_1, 0, 0}, // S_MANA3_16
+ {SPR_KEY1, 0, -1, NULL, S_NULL, 0, 0}, // S_KEY1
+ {SPR_KEY2, 0, -1, NULL, S_NULL, 0, 0}, // S_KEY2
+ {SPR_KEY3, 0, -1, NULL, S_NULL, 0, 0}, // S_KEY3
+ {SPR_KEY4, 0, -1, NULL, S_NULL, 0, 0}, // S_KEY4
+ {SPR_KEY5, 0, -1, NULL, S_NULL, 0, 0}, // S_KEY5
+ {SPR_KEY6, 0, -1, NULL, S_NULL, 0, 0}, // S_KEY6
+ {SPR_KEY7, 0, -1, NULL, S_NULL, 0, 0}, // S_KEY7
+ {SPR_KEY8, 0, -1, NULL, S_NULL, 0, 0}, // S_KEY8
+ {SPR_KEY9, 0, -1, NULL, S_NULL, 0, 0}, // S_KEY9
+ {SPR_KEYA, 0, -1, NULL, S_NULL, 0, 0}, // S_KEYA
+ {SPR_KEYB, 0, -1, NULL, S_NULL, 0, 0}, // S_KEYB
+ {SPR_TLGL, 0, 1, NULL, S_SND_WIND2, 0, 0}, // S_SND_WIND1
+ {SPR_TLGL, 0, 200, A_ESound, S_SND_WIND2, 0, 0}, // S_SND_WIND2
+ {SPR_TLGL, 0, 85, A_ESound, S_SND_WATERFALL, 0, 0}, // S_SND_WATERFALL
+ {SPR_ETTN, 0, 10, A_Look, S_ETTIN_LOOK2, 0, 0}, // S_ETTIN_LOOK1
+ {SPR_ETTN, 0, 10, A_Look, S_ETTIN_LOOK1, 0, 0}, // S_ETTIN_LOOK2
+ {SPR_ETTN, 0, 5, A_Chase, S_ETTIN_CHASE2, 0, 0}, // S_ETTIN_CHASE1
+ {SPR_ETTN, 1, 5, A_Chase, S_ETTIN_CHASE3, 0, 0}, // S_ETTIN_CHASE2
+ {SPR_ETTN, 2, 5, A_Chase, S_ETTIN_CHASE4, 0, 0}, // S_ETTIN_CHASE3
+ {SPR_ETTN, 3, 5, A_Chase, S_ETTIN_CHASE1, 0, 0}, // S_ETTIN_CHASE4
+ {SPR_ETTN, 7, 7, A_Pain, S_ETTIN_CHASE1, 0, 0}, // S_ETTIN_PAIN1
+ {SPR_ETTN, 4, 6, A_FaceTarget, S_ETTIN_ATK1_2, 0, 0}, // S_ETTIN_ATK1_1
+ {SPR_ETTN, 5, 6, A_FaceTarget, S_ETTIN_ATK1_3, 0, 0}, // S_ETTIN_ATK1_2
+ {SPR_ETTN, 6, 8, A_EttinAttack, S_ETTIN_CHASE1, 0, 0}, // S_ETTIN_ATK1_3
+ {SPR_ETTN, 8, 4, NULL, S_ETTIN_DEATH1_2, 0, 0}, // S_ETTIN_DEATH1_1
+ {SPR_ETTN, 9, 4, NULL, S_ETTIN_DEATH1_3, 0, 0}, // S_ETTIN_DEATH1_2
+ {SPR_ETTN, 10, 4, A_Scream, S_ETTIN_DEATH1_4, 0, 0}, // S_ETTIN_DEATH1_3
+ {SPR_ETTN, 11, 4, A_NoBlocking, S_ETTIN_DEATH1_5, 0, 0}, // S_ETTIN_DEATH1_4
+ {SPR_ETTN, 12, 4, A_QueueCorpse, S_ETTIN_DEATH1_6, 0, 0}, // S_ETTIN_DEATH1_5
+ {SPR_ETTN, 13, 4, NULL, S_ETTIN_DEATH1_7, 0, 0}, // S_ETTIN_DEATH1_6
+ {SPR_ETTN, 14, 4, NULL, S_ETTIN_DEATH1_8, 0, 0}, // S_ETTIN_DEATH1_7
+ {SPR_ETTN, 15, 4, NULL, S_ETTIN_DEATH1_9, 0, 0}, // S_ETTIN_DEATH1_8
+ {SPR_ETTN, 16, -1, NULL, S_NULL, 0, 0}, // S_ETTIN_DEATH1_9
+ {SPR_ETTB, 0, 4, NULL, S_ETTIN_DEATH2_2, 0, 0}, // S_ETTIN_DEATH2_1
+ {SPR_ETTB, 1, 4, A_NoBlocking, S_ETTIN_DEATH2_3, 0, 0}, // S_ETTIN_DEATH2_2
+ {SPR_ETTB, 2, 4, A_DropMace, S_ETTIN_DEATH2_4, 0, 0}, // S_ETTIN_DEATH2_3
+ {SPR_ETTB, 3, 4, A_Scream, S_ETTIN_DEATH2_5, 0, 0}, // S_ETTIN_DEATH2_4
+ {SPR_ETTB, 4, 4, A_QueueCorpse, S_ETTIN_DEATH2_6, 0, 0}, // S_ETTIN_DEATH2_5
+ {SPR_ETTB, 5, 4, NULL, S_ETTIN_DEATH2_7, 0, 0}, // S_ETTIN_DEATH2_6
+ {SPR_ETTB, 6, 4, NULL, S_ETTIN_DEATH2_8, 0, 0}, // S_ETTIN_DEATH2_7
+ {SPR_ETTB, 7, 4, NULL, S_ETTIN_DEATH2_9, 0, 0}, // S_ETTIN_DEATH2_8
+ {SPR_ETTB, 8, 4, NULL, S_ETTIN_DEATH2_0, 0, 0}, // S_ETTIN_DEATH2_9
+ {SPR_ETTB, 9, 4, NULL, S_ETTIN_DEATH2_A, 0, 0}, // S_ETTIN_DEATH2_0
+ {SPR_ETTB, 10, 4, NULL, S_ETTIN_DEATH2_B, 0, 0}, // S_ETTIN_DEATH2_A
+ {SPR_ETTB, 11, -1, NULL, S_NULL, 0, 0}, // S_ETTIN_DEATH2_B
+ {SPR_ETTN, 17, 5, A_FreezeDeath, S_ETTIN_ICE2, 0, 0}, // S_ETTIN_ICE1
+ {SPR_ETTN, 17, 1, A_FreezeDeathChunks, S_ETTIN_ICE2, 0, 0}, // S_ETTIN_ICE2
+ {SPR_ETTB, 12, 5, A_CheckFloor, S_ETTIN_MACE2, 0, 0}, // S_ETTIN_MACE1
+ {SPR_ETTB, 13, 5, A_CheckFloor, S_ETTIN_MACE3, 0, 0}, // S_ETTIN_MACE2
+ {SPR_ETTB, 14, 5, A_CheckFloor, S_ETTIN_MACE4, 0, 0}, // S_ETTIN_MACE3
+ {SPR_ETTB, 15, 5, A_CheckFloor, S_ETTIN_MACE1, 0, 0}, // S_ETTIN_MACE4
+ {SPR_ETTB, 16, 5, NULL, S_ETTIN_MACE6, 0, 0}, // S_ETTIN_MACE5
+ {SPR_ETTB, 17, 5, A_QueueCorpse, S_ETTIN_MACE7, 0, 0}, // S_ETTIN_MACE6
+ {SPR_ETTB, 18, -1, NULL, S_NULL, 0, 0}, // S_ETTIN_MACE7
+ {SPR_FDMN, 32791, 5, NULL, S_FIRED_LOOK1, 0, 0}, // S_FIRED_SPAWN1
+ {SPR_FDMN, 32772, 10, A_Look, S_FIRED_LOOK2, 0, 0}, // S_FIRED_LOOK1
+ {SPR_FDMN, 32773, 10, A_Look, S_FIRED_LOOK3, 0, 0}, // S_FIRED_LOOK2
+ {SPR_FDMN, 32774, 10, A_Look, S_FIRED_LOOK1, 0, 0}, // S_FIRED_LOOK3
+ {SPR_FDMN, 32772, 8, NULL, S_FIRED_LOOK5, 0, 0}, // S_FIRED_LOOK4
+ {SPR_FDMN, 32773, 6, NULL, S_FIRED_LOOK6, 0, 0}, // S_FIRED_LOOK5
+ {SPR_FDMN, 32774, 5, NULL, S_FIRED_LOOK7, 0, 0}, // S_FIRED_LOOK6
+ {SPR_FDMN, 32773, 8, NULL, S_FIRED_LOOK8, 0, 0}, // S_FIRED_LOOK7
+ {SPR_FDMN, 32772, 6, NULL, S_FIRED_LOOK9, 0, 0}, // S_FIRED_LOOK8
+ {SPR_FDMN, 32773, 7, A_FiredRocks, S_FIRED_LOOK0, 0, 0}, // S_FIRED_LOOK9
+ {SPR_FDMN, 32775, 5, NULL, S_FIRED_LOOKA, 0, 0}, // S_FIRED_LOOK0
+ {SPR_FDMN, 32776, 5, NULL, S_FIRED_LOOKB, 0, 0}, // S_FIRED_LOOKA
+ {SPR_FDMN, 32777, 5, A_UnSetInvulnerable, S_FIRED_WALK1, 0, 0}, // S_FIRED_LOOKB
+ {SPR_FDMN, 32768, 5, A_FiredChase, S_FIRED_WALK2, 0, 0}, // S_FIRED_WALK1
+ {SPR_FDMN, 32769, 5, A_FiredChase, S_FIRED_WALK3, 0, 0}, // S_FIRED_WALK2
+ {SPR_FDMN, 32770, 5, A_FiredChase, S_FIRED_WALK1, 0, 0}, // S_FIRED_WALK3
+ {SPR_FDMN, 32771, 6, A_Pain, S_FIRED_WALK1, 0, 0}, // S_FIRED_PAIN1
+ {SPR_FDMN, 32778, 3, A_FaceTarget, S_FIRED_ATTACK2, 0, 0}, // S_FIRED_ATTACK1
+ {SPR_FDMN, 32778, 5, A_FiredAttack, S_FIRED_ATTACK3, 0, 0}, // S_FIRED_ATTACK2
+ {SPR_FDMN, 32778, 5, A_FiredAttack, S_FIRED_ATTACK4, 0, 0}, // S_FIRED_ATTACK3
+ {SPR_FDMN, 32778, 5, A_FiredAttack, S_FIRED_WALK1, 0, 0}, // S_FIRED_ATTACK4
+ {SPR_FDMN, 32771, 4, A_FaceTarget, S_FIRED_DEATH2, 0, 0}, // S_FIRED_DEATH1
+ {SPR_FDMN, 32779, 4, A_Scream, S_FIRED_DEATH3, 0, 0}, // S_FIRED_DEATH2
+ {SPR_FDMN, 32779, 4, A_NoBlocking, S_FIRED_DEATH4, 0, 0}, // S_FIRED_DEATH3
+ {SPR_FDMN, 32779, 200, NULL, S_NULL, 0, 0}, // S_FIRED_DEATH4
+ {SPR_FDMN, 12, 5, A_FaceTarget, S_FIRED_XDEATH2, 0, 0}, // S_FIRED_XDEATH1
+ {SPR_FDMN, 13, 5, A_NoBlocking, S_FIRED_XDEATH3, 0, 0}, // S_FIRED_XDEATH2
+ {SPR_FDMN, 14, 5, A_FiredSplotch, S_NULL, 0, 0}, // S_FIRED_XDEATH3
+ {SPR_FDMN, 17, 5, A_FreezeDeath, S_FIRED_ICE2, 0, 0}, // S_FIRED_ICE1
+ {SPR_FDMN, 17, 1, A_FreezeDeathChunks, S_FIRED_ICE2, 0, 0}, // S_FIRED_ICE2
+ {SPR_FDMN, 15, 3, NULL, S_FIRED_CORPSE2, 0, 0}, // S_FIRED_CORPSE1
+ {SPR_FDMN, 15, 6, A_QueueCorpse, S_FIRED_CORPSE3, 0, 0}, // S_FIRED_CORPSE2
+ {SPR_FDMN, 24, -1, NULL, S_NULL, 0, 0}, // S_FIRED_CORPSE3
+ {SPR_FDMN, 16, 3, NULL, S_FIRED_CORPSE5, 0, 0}, // S_FIRED_CORPSE4
+ {SPR_FDMN, 16, 6, A_QueueCorpse, S_FIRED_CORPSE6, 0, 0}, // S_FIRED_CORPSE5
+ {SPR_FDMN, 25, -1, NULL, S_NULL, 0, 0}, // S_FIRED_CORPSE6
+ {SPR_FDMN, 18, 4, NULL, S_FIRED_RDROP1, 0, 0}, // S_FIRED_RDROP1
+ {SPR_FDMN, 18, 5, A_SmBounce, S_FIRED_RDEAD1_2, 0, 0}, // S_FIRED_RDEAD1_1
+ {SPR_FDMN, 18, 200, NULL, S_NULL, 0, 0}, // S_FIRED_RDEAD1_2
+ {SPR_FDMN, 19, 4, NULL, S_FIRED_RDROP2, 0, 0}, // S_FIRED_RDROP2
+ {SPR_FDMN, 19, 5, A_SmBounce, S_FIRED_RDEAD2_2, 0, 0}, // S_FIRED_RDEAD2_1
+ {SPR_FDMN, 19, 200, NULL, S_NULL, 0, 0}, // S_FIRED_RDEAD2_2
+ {SPR_FDMN, 20, 4, NULL, S_FIRED_RDROP3, 0, 0}, // S_FIRED_RDROP3
+ {SPR_FDMN, 20, 5, A_SmBounce, S_FIRED_RDEAD3_2, 0, 0}, // S_FIRED_RDEAD3_1
+ {SPR_FDMN, 20, 200, NULL, S_NULL, 0, 0}, // S_FIRED_RDEAD3_2
+ {SPR_FDMN, 21, 4, NULL, S_FIRED_RDROP4, 0, 0}, // S_FIRED_RDROP4
+ {SPR_FDMN, 21, 5, A_SmBounce, S_FIRED_RDEAD4_2, 0, 0}, // S_FIRED_RDEAD4_1
+ {SPR_FDMN, 21, 200, NULL, S_NULL, 0, 0}, // S_FIRED_RDEAD4_2
+ {SPR_FDMN, 22, 4, NULL, S_FIRED_RDROP5, 0, 0}, // S_FIRED_RDROP5
+ {SPR_FDMN, 22, 5, A_SmBounce, S_FIRED_RDEAD5_2, 0, 0}, // S_FIRED_RDEAD5_1
+ {SPR_FDMN, 22, 200, NULL, S_NULL, 0, 0}, // S_FIRED_RDEAD5_2
+ {SPR_FDMB, 32768, 5, NULL, S_FIRED_FX6_1, 0, 0}, // S_FIRED_FX6_1
+ {SPR_FDMB, 32769, 5, NULL, S_FIRED_FX6_3, 0, 0}, // S_FIRED_FX6_2
+ {SPR_FDMB, 32770, 5, NULL, S_FIRED_FX6_4, 0, 0}, // S_FIRED_FX6_3
+ {SPR_FDMB, 32771, 5, NULL, S_FIRED_FX6_5, 0, 0}, // S_FIRED_FX6_4
+ {SPR_FDMB, 32772, 5, NULL, S_NULL, 0, 0}, // S_FIRED_FX6_5
+ {SPR_ICEY, 0, 10, A_IceGuyLook, S_ICEGUY_LOOK, 0, 0}, // S_ICEGUY_LOOK
+ {SPR_ICEY, 0, -1, NULL, S_ICEGUY_LOOK, 0, 0}, // S_ICEGUY_DORMANT
+ {SPR_ICEY, 0, 4, A_Chase, S_ICEGUY_WALK2, 0, 0}, // S_ICEGUY_WALK1
+ {SPR_ICEY, 1, 4, A_IceGuyChase, S_ICEGUY_WALK3, 0, 0}, // S_ICEGUY_WALK2
+ {SPR_ICEY, 2, 4, A_Chase, S_ICEGUY_WALK4, 0, 0}, // S_ICEGUY_WALK3
+ {SPR_ICEY, 3, 4, A_Chase, S_ICEGUY_WALK1, 0, 0}, // S_ICEGUY_WALK4
+ {SPR_ICEY, 4, 3, A_FaceTarget, S_ICEGUY_ATK2, 0, 0}, // S_ICEGUY_ATK1
+ {SPR_ICEY, 5, 3, A_FaceTarget, S_ICEGUY_ATK3, 0, 0}, // S_ICEGUY_ATK2
+ {SPR_ICEY, 32774, 8, A_IceGuyAttack, S_ICEGUY_ATK4, 0, 0}, // S_ICEGUY_ATK3
+ {SPR_ICEY, 5, 4, A_FaceTarget, S_ICEGUY_WALK1, 0, 0}, // S_ICEGUY_ATK4
+ {SPR_ICEY, 0, 1, A_Pain, S_ICEGUY_WALK1, 0, 0}, // S_ICEGUY_PAIN1
+ {SPR_ICEY, 0, 1, A_IceGuyDie, S_NULL, 0, 0}, // S_ICEGUY_DEATH
+ {SPR_ICPR, 32768, 3, A_IceGuyMissilePuff, S_ICEGUY_FX2, 0, 0}, // S_ICEGUY_FX1
+ {SPR_ICPR, 32769, 3, A_IceGuyMissilePuff, S_ICEGUY_FX3, 0, 0}, // S_ICEGUY_FX2
+ {SPR_ICPR, 32770, 3, A_IceGuyMissilePuff, S_ICEGUY_FX1, 0, 0}, // S_ICEGUY_FX3
+ {SPR_ICPR, 32771, 4, NULL, S_ICEGUY_FX_X2, 0, 0}, // S_ICEGUY_FX_X1
+ {SPR_ICPR, 32772, 4, A_IceGuyMissileExplode, S_ICEGUY_FX_X3, 0, 0}, // S_ICEGUY_FX_X2
+ {SPR_ICPR, 32773, 4, NULL, S_ICEGUY_FX_X4, 0, 0}, // S_ICEGUY_FX_X3
+ {SPR_ICPR, 32774, 4, NULL, S_ICEGUY_FX_X5, 0, 0}, // S_ICEGUY_FX_X4
+ {SPR_ICPR, 32775, 3, NULL, S_NULL, 0, 0}, // S_ICEGUY_FX_X5
+ {SPR_ICPR, 8, 3, NULL, S_ICEFX_PUFF2, 0, 0}, // S_ICEFX_PUFF1
+ {SPR_ICPR, 9, 3, NULL, S_ICEFX_PUFF3, 0, 0}, // S_ICEFX_PUFF2
+ {SPR_ICPR, 10, 3, NULL, S_ICEFX_PUFF4, 0, 0}, // S_ICEFX_PUFF3
+ {SPR_ICPR, 11, 2, NULL, S_ICEFX_PUFF5, 0, 0}, // S_ICEFX_PUFF4
+ {SPR_ICPR, 12, 2, NULL, S_NULL, 0, 0}, // S_ICEFX_PUFF5
+ {SPR_ICPR, 32781, 3, NULL, S_ICEGUY_FX2_2, 0, 0}, // S_ICEGUY_FX2_1
+ {SPR_ICPR, 32782, 3, NULL, S_ICEGUY_FX2_3, 0, 0}, // S_ICEGUY_FX2_2
+ {SPR_ICPR, 32783, 3, NULL, S_ICEGUY_FX2_1, 0, 0}, // S_ICEGUY_FX2_3
+ {SPR_ICPR, 32784, 50, NULL, S_NULL, 0, 0}, // S_ICEGUY_BIT1
+ {SPR_ICPR, 32785, 50, NULL, S_NULL, 0, 0}, // S_ICEGUY_BIT2
+ {SPR_ICWS, 0, 2, NULL, S_ICEGUY_WISP1_2, 0, 0}, // S_ICEGUY_WISP1_1
+ {SPR_ICWS, 1, 2, NULL, S_ICEGUY_WISP1_3, 0, 0}, // S_ICEGUY_WISP1_2
+ {SPR_ICWS, 2, 2, NULL, S_ICEGUY_WISP1_4, 0, 0}, // S_ICEGUY_WISP1_3
+ {SPR_ICWS, 3, 2, NULL, S_ICEGUY_WISP1_5, 0, 0}, // S_ICEGUY_WISP1_4
+ {SPR_ICWS, 4, 2, NULL, S_ICEGUY_WISP1_6, 0, 0}, // S_ICEGUY_WISP1_5
+ {SPR_ICWS, 5, 2, NULL, S_ICEGUY_WISP1_7, 0, 0}, // S_ICEGUY_WISP1_6
+ {SPR_ICWS, 6, 2, NULL, S_ICEGUY_WISP1_8, 0, 0}, // S_ICEGUY_WISP1_7
+ {SPR_ICWS, 7, 2, NULL, S_ICEGUY_WISP1_9, 0, 0}, // S_ICEGUY_WISP1_8
+ {SPR_ICWS, 8, 2, NULL, S_NULL, 0, 0}, // S_ICEGUY_WISP1_9
+ {SPR_ICWS, 9, 2, NULL, S_ICEGUY_WISP2_2, 0, 0}, // S_ICEGUY_WISP2_1
+ {SPR_ICWS, 10, 2, NULL, S_ICEGUY_WISP2_3, 0, 0}, // S_ICEGUY_WISP2_2
+ {SPR_ICWS, 11, 2, NULL, S_ICEGUY_WISP2_4, 0, 0}, // S_ICEGUY_WISP2_3
+ {SPR_ICWS, 12, 2, NULL, S_ICEGUY_WISP2_5, 0, 0}, // S_ICEGUY_WISP2_4
+ {SPR_ICWS, 13, 2, NULL, S_ICEGUY_WISP2_6, 0, 0}, // S_ICEGUY_WISP2_5
+ {SPR_ICWS, 14, 2, NULL, S_ICEGUY_WISP2_7, 0, 0}, // S_ICEGUY_WISP2_6
+ {SPR_ICWS, 15, 2, NULL, S_ICEGUY_WISP2_8, 0, 0}, // S_ICEGUY_WISP2_7
+ {SPR_ICWS, 16, 2, NULL, S_ICEGUY_WISP2_9, 0, 0}, // S_ICEGUY_WISP2_8
+ {SPR_ICWS, 17, 2, NULL, S_NULL, 0, 0}, // S_ICEGUY_WISP2_9
+ {SPR_PLAY, 0, 2, NULL, S_FIGHTER2, 0, 0}, // S_FIGHTER
+ {SPR_PLAY, 0, 3, A_ClassBossHealth, S_FIGHTERLOOK, 0, 0}, // S_FIGHTER2
+ {SPR_PLAY, 0, 5, A_Look, S_FIGHTERLOOK, 0, 0}, // S_FIGHTERLOOK
+ {SPR_PLAY, 0, 4, A_FastChase, S_FIGHTER_RUN2, 0, 0}, // S_FIGHTER_RUN1
+ {SPR_PLAY, 1, 4, A_FastChase, S_FIGHTER_RUN3, 0, 0}, // S_FIGHTER_RUN2
+ {SPR_PLAY, 2, 4, A_FastChase, S_FIGHTER_RUN4, 0, 0}, // S_FIGHTER_RUN3
+ {SPR_PLAY, 3, 4, A_FastChase, S_FIGHTER_RUN1, 0, 0}, // S_FIGHTER_RUN4
+ {SPR_PLAY, 4, 8, A_FaceTarget, S_FIGHTER_ATK2, 0, 0}, // S_FIGHTER_ATK1
+ {SPR_PLAY, 5, 8, A_FighterAttack, S_FIGHTER_RUN1, 0, 0}, // S_FIGHTER_ATK2
+ {SPR_PLAY, 6, 4, NULL, S_FIGHTER_PAIN2, 0, 0}, // S_FIGHTER_PAIN
+ {SPR_PLAY, 6, 4, A_Pain, S_FIGHTER_RUN1, 0, 0}, // S_FIGHTER_PAIN2
+ {SPR_PLAY, 7, 6, NULL, S_FIGHTER_DIE2, 0, 0}, // S_FIGHTER_DIE1
+ {SPR_PLAY, 8, 6, A_Scream, S_FIGHTER_DIE3, 0, 0}, // S_FIGHTER_DIE2
+ {SPR_PLAY, 9, 6, NULL, S_FIGHTER_DIE4, 0, 0}, // S_FIGHTER_DIE3
+ {SPR_PLAY, 10, 6, NULL, S_FIGHTER_DIE5, 0, 0}, // S_FIGHTER_DIE4
+ {SPR_PLAY, 11, 6, A_NoBlocking, S_FIGHTER_DIE6, 0, 0}, // S_FIGHTER_DIE5
+ {SPR_PLAY, 12, 6, NULL, S_FIGHTER_DIE7, 0, 0}, // S_FIGHTER_DIE6
+ {SPR_PLAY, 13, -1, NULL, S_NULL, 0, 0}, // S_FIGHTER_DIE7
+ {SPR_PLAY, 14, 5, A_Scream, S_FIGHTER_XDIE2, 0, 0}, // S_FIGHTER_XDIE1
+ {SPR_PLAY, 15, 5, A_SkullPop, S_FIGHTER_XDIE3, 0, 0}, // S_FIGHTER_XDIE2
+ {SPR_PLAY, 17, 5, A_NoBlocking, S_FIGHTER_XDIE4, 0, 0}, // S_FIGHTER_XDIE3
+ {SPR_PLAY, 18, 5, NULL, S_FIGHTER_XDIE5, 0, 0}, // S_FIGHTER_XDIE4
+ {SPR_PLAY, 19, 5, NULL, S_FIGHTER_XDIE6, 0, 0}, // S_FIGHTER_XDIE5
+ {SPR_PLAY, 20, 5, NULL, S_FIGHTER_XDIE7, 0, 0}, // S_FIGHTER_XDIE6
+ {SPR_PLAY, 21, 5, NULL, S_FIGHTER_XDIE8, 0, 0}, // S_FIGHTER_XDIE7
+ {SPR_PLAY, 22, -1, NULL, S_NULL, 0, 0}, // S_FIGHTER_XDIE8
+ {SPR_PLAY, 23, 5, A_FreezeDeath, S_FIGHTER_ICE2, 0, 0}, // S_FIGHTER_ICE
+ {SPR_PLAY, 23, 1, A_FreezeDeathChunks, S_FIGHTER_ICE2, 0, 0}, // S_FIGHTER_ICE2
+ {SPR_CLER, 0, 2, NULL, S_CLERIC2, 0, 0}, // S_CLERIC
+ {SPR_CLER, 0, 3, A_ClassBossHealth, S_CLERICLOOK, 0, 0}, // S_CLERIC2
+ {SPR_CLER, 0, 5, A_Look, S_CLERICLOOK, 0, 0}, // S_CLERICLOOK
+ {SPR_CLER, 0, 4, A_FastChase, S_CLERIC_RUN2, 0, 0}, // S_CLERIC_RUN1
+ {SPR_CLER, 1, 4, A_FastChase, S_CLERIC_RUN3, 0, 0}, // S_CLERIC_RUN2
+ {SPR_CLER, 2, 4, A_FastChase, S_CLERIC_RUN4, 0, 0}, // S_CLERIC_RUN3
+ {SPR_CLER, 3, 4, A_FastChase, S_CLERIC_RUN1, 0, 0}, // S_CLERIC_RUN4
+ {SPR_CLER, 4, 8, A_FaceTarget, S_CLERIC_ATK2, 0, 0}, // S_CLERIC_ATK1
+ {SPR_CLER, 5, 8, A_FaceTarget, S_CLERIC_ATK3, 0, 0}, // S_CLERIC_ATK2
+ {SPR_CLER, 6, 10, A_ClericAttack, S_CLERIC_RUN1, 0, 0}, // S_CLERIC_ATK3
+ {SPR_CLER, 7, 4, NULL, S_CLERIC_PAIN2, 0, 0}, // S_CLERIC_PAIN
+ {SPR_CLER, 7, 4, A_Pain, S_CLERIC_RUN1, 0, 0}, // S_CLERIC_PAIN2
+ {SPR_CLER, 8, 6, NULL, S_CLERIC_DIE2, 0, 0}, // S_CLERIC_DIE1
+ {SPR_CLER, 10, 6, A_Scream, S_CLERIC_DIE3, 0, 0}, // S_CLERIC_DIE2
+ {SPR_CLER, 11, 6, NULL, S_CLERIC_DIE4, 0, 0}, // S_CLERIC_DIE3
+ {SPR_CLER, 11, 6, NULL, S_CLERIC_DIE5, 0, 0}, // S_CLERIC_DIE4
+ {SPR_CLER, 12, 6, A_NoBlocking, S_CLERIC_DIE6, 0, 0}, // S_CLERIC_DIE5
+ {SPR_CLER, 13, 6, NULL, S_CLERIC_DIE7, 0, 0}, // S_CLERIC_DIE6
+ {SPR_CLER, 14, 6, NULL, S_CLERIC_DIE8, 0, 0}, // S_CLERIC_DIE7
+ {SPR_CLER, 15, 6, NULL, S_CLERIC_DIE9, 0, 0}, // S_CLERIC_DIE8
+ {SPR_CLER, 16, -1, NULL, S_NULL, 0, 0}, // S_CLERIC_DIE9
+ {SPR_CLER, 17, 5, A_Scream, S_CLERIC_XDIE2, 0, 0}, // S_CLERIC_XDIE1
+ {SPR_CLER, 18, 5, NULL, S_CLERIC_XDIE3, 0, 0}, // S_CLERIC_XDIE2
+ {SPR_CLER, 19, 5, A_NoBlocking, S_CLERIC_XDIE4, 0, 0}, // S_CLERIC_XDIE3
+ {SPR_CLER, 20, 5, NULL, S_CLERIC_XDIE5, 0, 0}, // S_CLERIC_XDIE4
+ {SPR_CLER, 21, 5, NULL, S_CLERIC_XDIE6, 0, 0}, // S_CLERIC_XDIE5
+ {SPR_CLER, 22, 5, NULL, S_CLERIC_XDIE7, 0, 0}, // S_CLERIC_XDIE6
+ {SPR_CLER, 23, 5, NULL, S_CLERIC_XDIE8, 0, 0}, // S_CLERIC_XDIE7
+ {SPR_CLER, 24, 5, NULL, S_CLERIC_XDIE9, 0, 0}, // S_CLERIC_XDIE8
+ {SPR_CLER, 25, 5, NULL, S_CLERIC_XDIE10, 0, 0}, // S_CLERIC_XDIE9
+ {SPR_CLER, 26, -1, NULL, S_NULL, 0, 0}, // S_CLERIC_XDIE10
+ {SPR_CLER, 27, 5, A_FreezeDeath, S_CLERIC_ICE2, 0, 0}, // S_CLERIC_ICE
+ {SPR_CLER, 27, 1, A_FreezeDeathChunks, S_CLERIC_ICE2, 0, 0}, // S_CLERIC_ICE2
+ {SPR_MAGE, 0, 2, NULL, S_MAGE2, 0, 0}, // S_MAGE
+ {SPR_MAGE, 0, 3, A_ClassBossHealth, S_MAGELOOK, 0, 0}, // S_MAGE2
+ {SPR_MAGE, 0, 5, A_Look, S_MAGELOOK, 0, 0}, // S_MAGELOOK
+ {SPR_MAGE, 0, 4, A_FastChase, S_MAGE_RUN2, 0, 0}, // S_MAGE_RUN1
+ {SPR_MAGE, 1, 4, A_FastChase, S_MAGE_RUN3, 0, 0}, // S_MAGE_RUN2
+ {SPR_MAGE, 2, 4, A_FastChase, S_MAGE_RUN4, 0, 0}, // S_MAGE_RUN3
+ {SPR_MAGE, 3, 4, A_FastChase, S_MAGE_RUN1, 0, 0}, // S_MAGE_RUN4
+ {SPR_MAGE, 4, 8, A_FaceTarget, S_MAGE_ATK2, 0, 0}, // S_MAGE_ATK1
+ {SPR_MAGE, 32773, 8, A_MageAttack, S_MAGE_RUN1, 0, 0}, // S_MAGE_ATK2
+ {SPR_MAGE, 6, 4, NULL, S_MAGE_PAIN2, 0, 0}, // S_MAGE_PAIN
+ {SPR_MAGE, 6, 4, A_Pain, S_MAGE_RUN1, 0, 0}, // S_MAGE_PAIN2
+ {SPR_MAGE, 7, 6, NULL, S_MAGE_DIE2, 0, 0}, // S_MAGE_DIE1
+ {SPR_MAGE, 8, 6, A_Scream, S_MAGE_DIE3, 0, 0}, // S_MAGE_DIE2
+ {SPR_MAGE, 9, 6, NULL, S_MAGE_DIE4, 0, 0}, // S_MAGE_DIE3
+ {SPR_MAGE, 10, 6, NULL, S_MAGE_DIE5, 0, 0}, // S_MAGE_DIE4
+ {SPR_MAGE, 11, 6, A_NoBlocking, S_MAGE_DIE6, 0, 0}, // S_MAGE_DIE5
+ {SPR_MAGE, 12, 6, NULL, S_MAGE_DIE7, 0, 0}, // S_MAGE_DIE6
+ {SPR_MAGE, 13, -1, NULL, S_NULL, 0, 0}, // S_MAGE_DIE7
+ {SPR_MAGE, 14, 5, A_Scream, S_MAGE_XDIE2, 0, 0}, // S_MAGE_XDIE1
+ {SPR_MAGE, 15, 5, NULL, S_MAGE_XDIE3, 0, 0}, // S_MAGE_XDIE2
+ {SPR_MAGE, 17, 5, A_NoBlocking, S_MAGE_XDIE4, 0, 0}, // S_MAGE_XDIE3
+ {SPR_MAGE, 18, 5, NULL, S_MAGE_XDIE5, 0, 0}, // S_MAGE_XDIE4
+ {SPR_MAGE, 19, 5, NULL, S_MAGE_XDIE6, 0, 0}, // S_MAGE_XDIE5
+ {SPR_MAGE, 20, 5, NULL, S_MAGE_XDIE7, 0, 0}, // S_MAGE_XDIE6
+ {SPR_MAGE, 21, 5, NULL, S_MAGE_XDIE8, 0, 0}, // S_MAGE_XDIE7
+ {SPR_MAGE, 22, 5, NULL, S_MAGE_XDIE9, 0, 0}, // S_MAGE_XDIE8
+ {SPR_MAGE, 23, -1, NULL, S_NULL, 0, 0}, // S_MAGE_XDIE9
+ {SPR_MAGE, 24, 5, A_FreezeDeath, S_MAGE_ICE2, 0, 0}, // S_MAGE_ICE
+ {SPR_MAGE, 24, 1, A_FreezeDeathChunks, S_MAGE_ICE2, 0, 0}, // S_MAGE_ICE2
+ {SPR_SORC, 0, 3, NULL, S_SORC_SPAWN2, 0, 0}, // S_SORC_SPAWN1
+ {SPR_SORC, 0, 2, A_SorcSpinBalls, S_SORC_LOOK1, 0, 0}, // S_SORC_SPAWN2
+ {SPR_SORC, 0, 10, A_Look, S_SORC_LOOK1, 0, 0}, // S_SORC_LOOK1
+ {SPR_SORC, 0, 5, A_Chase, S_SORC_WALK2, 0, 0}, // S_SORC_WALK1
+ {SPR_SORC, 1, 5, A_Chase, S_SORC_WALK3, 0, 0}, // S_SORC_WALK2
+ {SPR_SORC, 2, 5, A_Chase, S_SORC_WALK4, 0, 0}, // S_SORC_WALK3
+ {SPR_SORC, 3, 5, A_Chase, S_SORC_WALK1, 0, 0}, // S_SORC_WALK4
+ {SPR_SORC, 6, 8, NULL, S_SORC_PAIN2, 0, 0}, // S_SORC_PAIN1
+ {SPR_SORC, 6, 8, A_Pain, S_SORC_WALK1, 0, 0}, // S_SORC_PAIN2
+ {SPR_SORC, 32773, 6, A_FaceTarget, S_SORC_ATK2_2, 0, 0}, // S_SORC_ATK2_1
+ {SPR_SORC, 32773, 6, A_SpeedBalls, S_SORC_ATK2_3, 0, 0}, // S_SORC_ATK2_2
+ {SPR_SORC, 32773, 6, A_FaceTarget, S_SORC_ATK2_3, 0, 0}, // S_SORC_ATK2_3
+ {SPR_SORC, 32772, 6, NULL, S_SORC_ATTACK2, 0, 0}, // S_SORC_ATTACK1
+ {SPR_SORC, 32772, 6, A_SpawnFizzle, S_SORC_ATTACK3, 0, 0}, // S_SORC_ATTACK2
+ {SPR_SORC, 32772, 5, A_FaceTarget, S_SORC_ATTACK2, 0, 0}, // S_SORC_ATTACK3
+ {SPR_SORC, 32772, 2, NULL, S_SORC_ATTACK5, 0, 0}, // S_SORC_ATTACK4
+ {SPR_SORC, 32772, 2, A_SorcBossAttack, S_SORC_WALK1, 0, 0}, // S_SORC_ATTACK5
+ {SPR_SORC, 32775, 5, NULL, S_SORC_DIE2, 0, 0}, // S_SORC_DIE1
+ {SPR_SORC, 32776, 5, A_FaceTarget, S_SORC_DIE3, 0, 0}, // S_SORC_DIE2
+ {SPR_SORC, 32777, 5, A_Scream, S_SORC_DIE4, 0, 0}, // S_SORC_DIE3
+ {SPR_SORC, 32778, 5, NULL, S_SORC_DIE5, 0, 0}, // S_SORC_DIE4
+ {SPR_SORC, 32779, 5, NULL, S_SORC_DIE6, 0, 0}, // S_SORC_DIE5
+ {SPR_SORC, 32780, 5, NULL, S_SORC_DIE7, 0, 0}, // S_SORC_DIE6
+ {SPR_SORC, 32781, 5, NULL, S_SORC_DIE8, 0, 0}, // S_SORC_DIE7
+ {SPR_SORC, 32782, 5, NULL, S_SORC_DIE9, 0, 0}, // S_SORC_DIE8
+ {SPR_SORC, 32783, 5, NULL, S_SORC_DIE0, 0, 0}, // S_SORC_DIE9
+ {SPR_SORC, 32784, 5, NULL, S_SORC_DIEA, 0, 0}, // S_SORC_DIE0
+ {SPR_SORC, 32785, 5, NULL, S_SORC_DIEB, 0, 0}, // S_SORC_DIEA
+ {SPR_SORC, 32786, 5, NULL, S_SORC_DIEC, 0, 0}, // S_SORC_DIEB
+ {SPR_SORC, 32787, 5, NULL, S_SORC_DIED, 0, 0}, // S_SORC_DIEC
+ {SPR_SORC, 32788, 5, A_NoBlocking, S_SORC_DIEE, 0, 0}, // S_SORC_DIED
+ {SPR_SORC, 32789, 5, NULL, S_SORC_DIEF, 0, 0}, // S_SORC_DIEE
+ {SPR_SORC, 32790, 5, NULL, S_SORC_DIEG, 0, 0}, // S_SORC_DIEF
+ {SPR_SORC, 32791, 5, NULL, S_SORC_DIEH, 0, 0}, // S_SORC_DIEG
+ {SPR_SORC, 32792, 5, NULL, S_SORC_DIEI, 0, 0}, // S_SORC_DIEH
+ {SPR_SORC, 32793, -1, NULL, S_NULL, 0, 0}, // S_SORC_DIEI
+ {SPR_SBMP, 0, 2, A_SorcBallOrbit, S_SORCBALL1_2, 0, 0}, // S_SORCBALL1_1
+ {SPR_SBMP, 1, 2, A_SorcBallOrbit, S_SORCBALL1_3, 0, 0}, // S_SORCBALL1_2
+ {SPR_SBMP, 2, 2, A_SorcBallOrbit, S_SORCBALL1_4, 0, 0}, // S_SORCBALL1_3
+ {SPR_SBMP, 3, 2, A_SorcBallOrbit, S_SORCBALL1_5, 0, 0}, // S_SORCBALL1_4
+ {SPR_SBMP, 4, 2, A_SorcBallOrbit, S_SORCBALL1_6, 0, 0}, // S_SORCBALL1_5
+ {SPR_SBMP, 5, 2, A_SorcBallOrbit, S_SORCBALL1_7, 0, 0}, // S_SORCBALL1_6
+ {SPR_SBMP, 6, 2, A_SorcBallOrbit, S_SORCBALL1_8, 0, 0}, // S_SORCBALL1_7
+ {SPR_SBMP, 7, 2, A_SorcBallOrbit, S_SORCBALL1_9, 0, 0}, // S_SORCBALL1_8
+ {SPR_SBMP, 8, 2, A_SorcBallOrbit, S_SORCBALL1_0, 0, 0}, // S_SORCBALL1_9
+ {SPR_SBMP, 9, 2, A_SorcBallOrbit, S_SORCBALL1_A, 0, 0}, // S_SORCBALL1_0
+ {SPR_SBMP, 10, 2, A_SorcBallOrbit, S_SORCBALL1_B, 0, 0}, // S_SORCBALL1_A
+ {SPR_SBMP, 11, 2, A_SorcBallOrbit, S_SORCBALL1_C, 0, 0}, // S_SORCBALL1_B
+ {SPR_SBMP, 12, 2, A_SorcBallOrbit, S_SORCBALL1_D, 0, 0}, // S_SORCBALL1_C
+ {SPR_SBMP, 13, 2, A_SorcBallOrbit, S_SORCBALL1_E, 0, 0}, // S_SORCBALL1_D
+ {SPR_SBMP, 14, 2, A_SorcBallOrbit, S_SORCBALL1_F, 0, 0}, // S_SORCBALL1_E
+ {SPR_SBMP, 15, 2, A_SorcBallOrbit, S_SORCBALL1_1, 0, 0}, // S_SORCBALL1_F
+ {SPR_SBMP, 0, 5, A_SorcBallPop, S_SORCBALL1_D2, 0, 0}, // S_SORCBALL1_D1
+ {SPR_SBMP, 1, 2, A_BounceCheck, S_SORCBALL1_D2, 0, 0}, // S_SORCBALL1_D2
+ {SPR_SBS4, 3, 5, A_Explode, S_SORCBALL1_D6, 0, 0}, // S_SORCBALL1_D5
+ {SPR_SBS4, 4, 5, NULL, S_SORCBALL1_D7, 0, 0}, // S_SORCBALL1_D6
+ {SPR_SBS4, 5, 6, NULL, S_SORCBALL1_D8, 0, 0}, // S_SORCBALL1_D7
+ {SPR_SBS4, 6, 6, NULL, S_SORCBALL1_D9, 0, 0}, // S_SORCBALL1_D8
+ {SPR_SBS4, 7, 6, NULL, S_NULL, 0, 0}, // S_SORCBALL1_D9
+ {SPR_SBMB, 0, 2, A_SorcBallOrbit, S_SORCBALL2_2, 0, 0}, // S_SORCBALL2_1
+ {SPR_SBMB, 1, 2, A_SorcBallOrbit, S_SORCBALL2_3, 0, 0}, // S_SORCBALL2_2
+ {SPR_SBMB, 2, 2, A_SorcBallOrbit, S_SORCBALL2_4, 0, 0}, // S_SORCBALL2_3
+ {SPR_SBMB, 3, 2, A_SorcBallOrbit, S_SORCBALL2_5, 0, 0}, // S_SORCBALL2_4
+ {SPR_SBMB, 4, 2, A_SorcBallOrbit, S_SORCBALL2_6, 0, 0}, // S_SORCBALL2_5
+ {SPR_SBMB, 5, 2, A_SorcBallOrbit, S_SORCBALL2_7, 0, 0}, // S_SORCBALL2_6
+ {SPR_SBMB, 6, 2, A_SorcBallOrbit, S_SORCBALL2_8, 0, 0}, // S_SORCBALL2_7
+ {SPR_SBMB, 7, 2, A_SorcBallOrbit, S_SORCBALL2_9, 0, 0}, // S_SORCBALL2_8
+ {SPR_SBMB, 8, 2, A_SorcBallOrbit, S_SORCBALL2_0, 0, 0}, // S_SORCBALL2_9
+ {SPR_SBMB, 9, 2, A_SorcBallOrbit, S_SORCBALL2_A, 0, 0}, // S_SORCBALL2_0
+ {SPR_SBMB, 10, 2, A_SorcBallOrbit, S_SORCBALL2_B, 0, 0}, // S_SORCBALL2_A
+ {SPR_SBMB, 11, 2, A_SorcBallOrbit, S_SORCBALL2_C, 0, 0}, // S_SORCBALL2_B
+ {SPR_SBMB, 12, 2, A_SorcBallOrbit, S_SORCBALL2_D, 0, 0}, // S_SORCBALL2_C
+ {SPR_SBMB, 13, 2, A_SorcBallOrbit, S_SORCBALL2_E, 0, 0}, // S_SORCBALL2_D
+ {SPR_SBMB, 14, 2, A_SorcBallOrbit, S_SORCBALL2_F, 0, 0}, // S_SORCBALL2_E
+ {SPR_SBMB, 15, 2, A_SorcBallOrbit, S_SORCBALL2_1, 0, 0}, // S_SORCBALL2_F
+ {SPR_SBMB, 0, 5, A_SorcBallPop, S_SORCBALL2_D2, 0, 0}, // S_SORCBALL2_D1
+ {SPR_SBMB, 1, 2, A_BounceCheck, S_SORCBALL2_D2, 0, 0}, // S_SORCBALL2_D2
+ {SPR_SBS3, 3, 5, A_Explode, S_SORCBALL2_D6, 0, 0}, // S_SORCBALL2_D5
+ {SPR_SBS3, 4, 5, NULL, S_SORCBALL2_D7, 0, 0}, // S_SORCBALL2_D6
+ {SPR_SBS3, 5, 6, NULL, S_SORCBALL2_D8, 0, 0}, // S_SORCBALL2_D7
+ {SPR_SBS3, 6, 6, NULL, S_SORCBALL2_D9, 0, 0}, // S_SORCBALL2_D8
+ {SPR_SBS3, 7, 6, NULL, S_NULL, 0, 0}, // S_SORCBALL2_D9
+ {SPR_SBMG, 0, 2, A_SorcBallOrbit, S_SORCBALL3_2, 0, 0}, // S_SORCBALL3_1
+ {SPR_SBMG, 1, 2, A_SorcBallOrbit, S_SORCBALL3_3, 0, 0}, // S_SORCBALL3_2
+ {SPR_SBMG, 2, 2, A_SorcBallOrbit, S_SORCBALL3_4, 0, 0}, // S_SORCBALL3_3
+ {SPR_SBMG, 3, 2, A_SorcBallOrbit, S_SORCBALL3_5, 0, 0}, // S_SORCBALL3_4
+ {SPR_SBMG, 4, 2, A_SorcBallOrbit, S_SORCBALL3_6, 0, 0}, // S_SORCBALL3_5
+ {SPR_SBMG, 5, 2, A_SorcBallOrbit, S_SORCBALL3_7, 0, 0}, // S_SORCBALL3_6
+ {SPR_SBMG, 6, 2, A_SorcBallOrbit, S_SORCBALL3_8, 0, 0}, // S_SORCBALL3_7
+ {SPR_SBMG, 7, 2, A_SorcBallOrbit, S_SORCBALL3_9, 0, 0}, // S_SORCBALL3_8
+ {SPR_SBMG, 8, 2, A_SorcBallOrbit, S_SORCBALL3_0, 0, 0}, // S_SORCBALL3_9
+ {SPR_SBMG, 9, 2, A_SorcBallOrbit, S_SORCBALL3_A, 0, 0}, // S_SORCBALL3_0
+ {SPR_SBMG, 10, 2, A_SorcBallOrbit, S_SORCBALL3_B, 0, 0}, // S_SORCBALL3_A
+ {SPR_SBMG, 11, 2, A_SorcBallOrbit, S_SORCBALL3_C, 0, 0}, // S_SORCBALL3_B
+ {SPR_SBMG, 12, 2, A_SorcBallOrbit, S_SORCBALL3_D, 0, 0}, // S_SORCBALL3_C
+ {SPR_SBMG, 13, 2, A_SorcBallOrbit, S_SORCBALL3_E, 0, 0}, // S_SORCBALL3_D
+ {SPR_SBMG, 14, 2, A_SorcBallOrbit, S_SORCBALL3_F, 0, 0}, // S_SORCBALL3_E
+ {SPR_SBMG, 15, 2, A_SorcBallOrbit, S_SORCBALL3_1, 0, 0}, // S_SORCBALL3_F
+ {SPR_SBMG, 0, 5, A_SorcBallPop, S_SORCBALL3_D2, 0, 0}, // S_SORCBALL3_D1
+ {SPR_SBMG, 1, 2, A_BounceCheck, S_SORCBALL3_D2, 0, 0}, // S_SORCBALL3_D2
+ {SPR_SBS3, 3, 5, A_Explode, S_SORCBALL3_D6, 0, 0}, // S_SORCBALL3_D5
+ {SPR_SBS3, 4, 5, NULL, S_SORCBALL3_D7, 0, 0}, // S_SORCBALL3_D6
+ {SPR_SBS3, 5, 6, NULL, S_SORCBALL3_D8, 0, 0}, // S_SORCBALL3_D7
+ {SPR_SBS3, 6, 6, NULL, S_SORCBALL3_D9, 0, 0}, // S_SORCBALL3_D8
+ {SPR_SBS3, 7, 6, NULL, S_NULL, 0, 0}, // S_SORCBALL3_D9
+ {SPR_SBS1, 32768, 2, NULL, S_SORCFX1_2, 0, 0}, // S_SORCFX1_1
+ {SPR_SBS1, 32769, 3, A_SorcFX1Seek, S_SORCFX1_3, 0, 0}, // S_SORCFX1_2
+ {SPR_SBS1, 32770, 3, A_SorcFX1Seek, S_SORCFX1_4, 0, 0}, // S_SORCFX1_3
+ {SPR_SBS1, 32771, 3, A_SorcFX1Seek, S_SORCFX1_1, 0, 0}, // S_SORCFX1_4
+ {SPR_FHFX, 32786, 2, A_Explode, S_SORCFX1_D2, 0, 0}, // S_SORCFX1_D1
+ {SPR_FHFX, 32786, 6, NULL, S_SORCFX1_D3, 0, 0}, // S_SORCFX1_D2
+ {SPR_FHFX, 32786, 6, NULL, S_NULL, 0, 0}, // S_SORCFX1_D3
+ {SPR_SBS2, 32768, 3, A_SorcFX2Split, S_SORCFX2_SPLIT1, 0, 0}, // S_SORCFX2_SPLIT1
+ {SPR_SBS2, 32768, 2, A_SorcFX2Orbit, S_SORCFX2_ORBIT2, 0, 0}, // S_SORCFX2_ORBIT1
+ {SPR_SBS2, 32769, 2, A_SorcFX2Orbit, S_SORCFX2_ORBIT3, 0, 0}, // S_SORCFX2_ORBIT2
+ {SPR_SBS2, 32770, 2, A_SorcFX2Orbit, S_SORCFX2_ORBIT4, 0, 0}, // S_SORCFX2_ORBIT3
+ {SPR_SBS2, 32771, 2, A_SorcFX2Orbit, S_SORCFX2_ORBIT5, 0, 0}, // S_SORCFX2_ORBIT4
+ {SPR_SBS2, 32772, 2, A_SorcFX2Orbit, S_SORCFX2_ORBIT6, 0, 0}, // S_SORCFX2_ORBIT5
+ {SPR_SBS2, 32773, 2, A_SorcFX2Orbit, S_SORCFX2_ORBIT7, 0, 0}, // S_SORCFX2_ORBIT6
+ {SPR_SBS2, 32774, 2, A_SorcFX2Orbit, S_SORCFX2_ORBIT8, 0, 0}, // S_SORCFX2_ORBIT7
+ {SPR_SBS2, 32775, 2, A_SorcFX2Orbit, S_SORCFX2_ORBIT9, 0, 0}, // S_SORCFX2_ORBIT8
+ {SPR_SBS2, 32776, 2, A_SorcFX2Orbit, S_SORCFX2_ORBIT0, 0, 0}, // S_SORCFX2_ORBIT9
+ {SPR_SBS2, 32777, 2, A_SorcFX2Orbit, S_SORCFX2_ORBITA, 0, 0}, // S_SORCFX2_ORBIT0
+ {SPR_SBS2, 32778, 2, A_SorcFX2Orbit, S_SORCFX2_ORBITB, 0, 0}, // S_SORCFX2_ORBITA
+ {SPR_SBS2, 32779, 2, A_SorcFX2Orbit, S_SORCFX2_ORBITC, 0, 0}, // S_SORCFX2_ORBITB
+ {SPR_SBS2, 32780, 2, A_SorcFX2Orbit, S_SORCFX2_ORBITD, 0, 0}, // S_SORCFX2_ORBITC
+ {SPR_SBS2, 32781, 2, A_SorcFX2Orbit, S_SORCFX2_ORBITE, 0, 0}, // S_SORCFX2_ORBITD
+ {SPR_SBS2, 32782, 2, A_SorcFX2Orbit, S_SORCFX2_ORBITF, 0, 0}, // S_SORCFX2_ORBITE
+ {SPR_SBS2, 32783, 2, A_SorcFX2Orbit, S_SORCFX2_ORBIT1, 0, 0}, // S_SORCFX2_ORBITF
+ {SPR_SBS2, 0, 10, NULL, S_NULL, 0, 0}, // S_SORCFX2T1
+ {SPR_SBS3, 32768, 2, NULL, S_SORCFX3_2, 0, 0}, // S_SORCFX3_1
+ {SPR_SBS3, 32769, 2, NULL, S_SORCFX3_3, 0, 0}, // S_SORCFX3_2
+ {SPR_SBS3, 32770, 2, NULL, S_SORCFX3_1, 0, 0}, // S_SORCFX3_3
+ {SPR_SBS3, 32768, 4, NULL, S_BISHMORPHA, 0, 0}, // S_BISHMORPH1
+ {SPR_BISH, 15, 4, A_SorcererBishopEntry, S_BISHMORPHB, 0, 0}, // S_BISHMORPHA
+ {SPR_BISH, 14, 4, NULL, S_BISHMORPHC, 0, 0}, // S_BISHMORPHB
+ {SPR_BISH, 13, 4, NULL, S_BISHMORPHD, 0, 0}, // S_BISHMORPHC
+ {SPR_BISH, 12, 3, NULL, S_BISHMORPHE, 0, 0}, // S_BISHMORPHD
+ {SPR_BISH, 11, 3, NULL, S_BISHMORPHF, 0, 0}, // S_BISHMORPHE
+ {SPR_BISH, 10, 3, NULL, S_BISHMORPHG, 0, 0}, // S_BISHMORPHF
+ {SPR_BISH, 9, 3, NULL, S_BISHMORPHH, 0, 0}, // S_BISHMORPHG
+ {SPR_BISH, 8, 3, NULL, S_BISHMORPHI, 0, 0}, // S_BISHMORPHH
+ {SPR_BISH, 7, 3, NULL, S_BISHMORPHJ, 0, 0}, // S_BISHMORPHI
+ {SPR_BISH, 6, 3, A_SpawnBishop, S_NULL, 0, 0}, // S_BISHMORPHJ
+ {SPR_SBS3, 3, 3, NULL, S_SORCFX3_EXP2, 0, 0}, // S_SORCFX3_EXP1
+ {SPR_SBS3, 4, 3, NULL, S_SORCFX3_EXP3, 0, 0}, // S_SORCFX3_EXP2
+ {SPR_SBS3, 5, 3, NULL, S_SORCFX3_EXP4, 0, 0}, // S_SORCFX3_EXP3
+ {SPR_SBS3, 6, 3, NULL, S_SORCFX3_EXP5, 0, 0}, // S_SORCFX3_EXP4
+ {SPR_SBS3, 7, 3, NULL, S_NULL, 0, 0}, // S_SORCFX3_EXP5
+ {SPR_SBS4, 32768, 2, A_SorcFX4Check, S_SORCFX4_2, 0, 0}, // S_SORCFX4_1
+ {SPR_SBS4, 32769, 2, A_SorcFX4Check, S_SORCFX4_3, 0, 0}, // S_SORCFX4_2
+ {SPR_SBS4, 32770, 2, A_SorcFX4Check, S_SORCFX4_1, 0, 0}, // S_SORCFX4_3
+ {SPR_SBS4, 32771, 2, NULL, S_SORCFX4_D2, 0, 0}, // S_SORCFX4_D1
+ {SPR_SBS4, 32772, 2, A_Explode, S_SORCFX4_D3, 0, 0}, // S_SORCFX4_D2
+ {SPR_SBS4, 32773, 2, NULL, S_SORCFX4_D4, 0, 0}, // S_SORCFX4_D3
+ {SPR_SBS4, 32774, 2, NULL, S_SORCFX4_D5, 0, 0}, // S_SORCFX4_D4
+ {SPR_SBS4, 32775, 2, NULL, S_NULL, 0, 0}, // S_SORCFX4_D5
+ {SPR_SBFX, 32768, 4, NULL, S_SORCSPARK2, 0, 0}, // S_SORCSPARK1
+ {SPR_SBFX, 32769, 4, NULL, S_SORCSPARK3, 0, 0}, // S_SORCSPARK2
+ {SPR_SBFX, 32770, 4, NULL, S_SORCSPARK4, 0, 0}, // S_SORCSPARK3
+ {SPR_SBFX, 32771, 4, NULL, S_SORCSPARK5, 0, 0}, // S_SORCSPARK4
+ {SPR_SBFX, 32772, 4, NULL, S_SORCSPARK6, 0, 0}, // S_SORCSPARK5
+ {SPR_SBFX, 32773, 4, NULL, S_SORCSPARK7, 0, 0}, // S_SORCSPARK6
+ {SPR_SBFX, 32774, 4, NULL, S_NULL, 0, 0}, // S_SORCSPARK7
+ {SPR_RADE, 0, 4, NULL, S_BLASTEFFECT2, 0, 0}, // S_BLASTEFFECT1
+ {SPR_RADE, 1, 4, NULL, S_BLASTEFFECT3, 0, 0}, // S_BLASTEFFECT2
+ {SPR_RADE, 2, 4, NULL, S_BLASTEFFECT4, 0, 0}, // S_BLASTEFFECT3
+ {SPR_RADE, 3, 4, NULL, S_BLASTEFFECT5, 0, 0}, // S_BLASTEFFECT4
+ {SPR_RADE, 4, 4, NULL, S_BLASTEFFECT6, 0, 0}, // S_BLASTEFFECT5
+ {SPR_RADE, 5, 4, NULL, S_BLASTEFFECT7, 0, 0}, // S_BLASTEFFECT6
+ {SPR_RADE, 6, 4, NULL, S_BLASTEFFECT8, 0, 0}, // S_BLASTEFFECT7
+ {SPR_RADE, 7, 4, NULL, S_BLASTEFFECT9, 0, 0}, // S_BLASTEFFECT8
+ {SPR_RADE, 8, 4, NULL, S_NULL, 0, 0}, // S_BLASTEFFECT9
+ {SPR_WATR, 0, 5, NULL, S_WATERDRIP1, 0, 0}, // S_WATERDRIP1
+ {SPR_KORX, 0, 5, A_Look, S_KORAX_LOOK1, 0, 0}, // S_KORAX_LOOK1
+ {SPR_KORX, 0, 3, A_KoraxStep2, S_KORAX_CHASE2, 0, 0}, // S_KORAX_CHASE1
+ {SPR_KORX, 0, 3, A_KoraxChase, S_KORAX_CHASE3, 0, 0}, // S_KORAX_CHASE2
+ {SPR_KORX, 0, 3, A_KoraxChase, S_KORAX_CHASE4, 0, 0}, // S_KORAX_CHASE3
+ {SPR_KORX, 0, 3, A_KoraxChase, S_KORAX_CHASE5, 0, 0}, // S_KORAX_CHASE4
+ {SPR_KORX, 1, 3, A_KoraxStep, S_KORAX_CHASE6, 0, 0}, // S_KORAX_CHASE5
+ {SPR_KORX, 1, 3, A_KoraxChase, S_KORAX_CHASE7, 0, 0}, // S_KORAX_CHASE6
+ {SPR_KORX, 1, 3, A_KoraxChase, S_KORAX_CHASE8, 0, 0}, // S_KORAX_CHASE7
+ {SPR_KORX, 1, 3, A_KoraxChase, S_KORAX_CHASE9, 0, 0}, // S_KORAX_CHASE8
+ {SPR_KORX, 2, 3, A_KoraxStep2, S_KORAX_CHASE0, 0, 0}, // S_KORAX_CHASE9
+ {SPR_KORX, 2, 3, A_KoraxChase, S_KORAX_CHASEA, 0, 0}, // S_KORAX_CHASE0
+ {SPR_KORX, 2, 3, A_KoraxChase, S_KORAX_CHASEB, 0, 0}, // S_KORAX_CHASEA
+ {SPR_KORX, 2, 3, A_KoraxChase, S_KORAX_CHASEC, 0, 0}, // S_KORAX_CHASEB
+ {SPR_KORX, 3, 3, A_KoraxStep, S_KORAX_CHASED, 0, 0}, // S_KORAX_CHASEC
+ {SPR_KORX, 3, 3, A_KoraxChase, S_KORAX_CHASEE, 0, 0}, // S_KORAX_CHASED
+ {SPR_KORX, 3, 3, A_KoraxChase, S_KORAX_CHASEF, 0, 0}, // S_KORAX_CHASEE
+ {SPR_KORX, 3, 3, A_KoraxChase, S_KORAX_CHASE1, 0, 0}, // S_KORAX_CHASEF
+ {SPR_KORX, 7, 5, A_Pain, S_KORAX_PAIN2, 0, 0}, // S_KORAX_PAIN1
+ {SPR_KORX, 7, 5, NULL, S_KORAX_CHASE2, 0, 0}, // S_KORAX_PAIN2
+ {SPR_KORX, 32772, 2, A_FaceTarget, S_KORAX_ATTACK2, 0, 0}, // S_KORAX_ATTACK1
+ {SPR_KORX, 32772, 5, A_KoraxDecide, S_KORAX_ATTACK2, 0, 0}, // S_KORAX_ATTACK2
+ {SPR_KORX, 32772, 4, A_FaceTarget, S_KORAX_MISSILE2, 0, 0}, // S_KORAX_MISSILE1
+ {SPR_KORX, 32773, 8, A_KoraxMissile, S_KORAX_MISSILE3, 0, 0}, // S_KORAX_MISSILE2
+ {SPR_KORX, 32772, 8, NULL, S_KORAX_CHASE2, 0, 0}, // S_KORAX_MISSILE3
+ {SPR_KORX, 32772, 5, A_FaceTarget, S_KORAX_COMMAND2, 0, 0}, // S_KORAX_COMMAND1
+ {SPR_KORX, 32790, 10, A_FaceTarget, S_KORAX_COMMAND3, 0, 0}, // S_KORAX_COMMAND2
+ {SPR_KORX, 32774, 15, A_KoraxCommand, S_KORAX_COMMAND4, 0, 0}, // S_KORAX_COMMAND3
+ {SPR_KORX, 32790, 10, NULL, S_KORAX_COMMAND5, 0, 0}, // S_KORAX_COMMAND4
+ {SPR_KORX, 32772, 5, NULL, S_KORAX_CHASE2, 0, 0}, // S_KORAX_COMMAND5
+ {SPR_KORX, 8, 5, NULL, S_KORAX_DEATH2, 0, 0}, // S_KORAX_DEATH1
+ {SPR_KORX, 9, 5, A_FaceTarget, S_KORAX_DEATH3, 0, 0}, // S_KORAX_DEATH2
+ {SPR_KORX, 10, 5, A_Scream, S_KORAX_DEATH4, 0, 0}, // S_KORAX_DEATH3
+ {SPR_KORX, 11, 5, NULL, S_KORAX_DEATH5, 0, 0}, // S_KORAX_DEATH4
+ {SPR_KORX, 12, 5, NULL, S_KORAX_DEATH6, 0, 0}, // S_KORAX_DEATH5
+ {SPR_KORX, 13, 5, NULL, S_KORAX_DEATH7, 0, 0}, // S_KORAX_DEATH6
+ {SPR_KORX, 14, 5, NULL, S_KORAX_DEATH8, 0, 0}, // S_KORAX_DEATH7
+ {SPR_KORX, 15, 5, NULL, S_KORAX_DEATH9, 0, 0}, // S_KORAX_DEATH8
+ {SPR_KORX, 16, 10, NULL, S_KORAX_DEATH0, 0, 0}, // S_KORAX_DEATH9
+ {SPR_KORX, 17, 5, A_KoraxBonePop, S_KORAX_DEATHA, 0, 0}, // S_KORAX_DEATH0
+ {SPR_KORX, 18, 5, A_NoBlocking, S_KORAX_DEATHB, 0, 0}, // S_KORAX_DEATHA
+ {SPR_KORX, 19, 5, NULL, S_KORAX_DEATHC, 0, 0}, // S_KORAX_DEATHB
+ {SPR_KORX, 20, 5, NULL, S_KORAX_DEATHD, 0, 0}, // S_KORAX_DEATHC
+ {SPR_KORX, 21, -1, NULL, S_NULL, 0, 0}, // S_KORAX_DEATHD
+ {SPR_SPIR, 0, 5, A_KSpiritRoam, S_KSPIRIT_ROAM2, 0, 0}, // S_KSPIRIT_ROAM1
+ {SPR_SPIR, 1, 5, A_KSpiritRoam, S_KSPIRIT_ROAM1, 0, 0}, // S_KSPIRIT_ROAM2
+ {SPR_SPIR, 3, 5, NULL, S_KSPIRIT_DEATH2, 0, 0}, // S_KSPIRIT_DEATH1
+ {SPR_SPIR, 4, 5, NULL, S_KSPIRIT_DEATH3, 0, 0}, // S_KSPIRIT_DEATH2
+ {SPR_SPIR, 5, 5, NULL, S_KSPIRIT_DEATH4, 0, 0}, // S_KSPIRIT_DEATH3
+ {SPR_SPIR, 6, 5, NULL, S_KSPIRIT_DEATH5, 0, 0}, // S_KSPIRIT_DEATH4
+ {SPR_SPIR, 7, 5, NULL, S_KSPIRIT_DEATH6, 0, 0}, // S_KSPIRIT_DEATH5
+ {SPR_SPIR, 8, 5, NULL, S_NULL, 0, 0}, // S_KSPIRIT_DEATH6
+ {SPR_MLFX, 32776, 2, NULL, S_KBOLT2, 0, 0}, // S_KBOLT1
+ {SPR_MLFX, 32777, 2, A_KBoltRaise, S_KBOLT3, 0, 0}, // S_KBOLT2
+ {SPR_MLFX, 32776, 2, A_KBolt, S_KBOLT4, 0, 0}, // S_KBOLT3
+ {SPR_MLFX, 32777, 2, A_KBolt, S_KBOLT5, 0, 0}, // S_KBOLT4
+ {SPR_MLFX, 32778, 2, A_KBolt, S_KBOLT6, 0, 0}, // S_KBOLT5
+ {SPR_MLFX, 32779, 2, A_KBolt, S_KBOLT7, 0, 0}, // S_KBOLT6
+ {SPR_MLFX, 32780, 2, A_KBolt, S_KBOLT3, 0, 0}, // S_KBOLT7
+ {SPR_MAN1, 0, 2, NULL, S_SPAWNBATS2, 0, 0}, // S_SPAWNBATS1
+ {SPR_MAN1, 0, 2, A_BatSpawnInit, S_SPAWNBATS3, 0, 0}, // S_SPAWNBATS2
+ {SPR_MAN1, 0, 2, A_BatSpawn, S_SPAWNBATS3, 0, 0}, // S_SPAWNBATS3
+ {SPR_MAN1, 0, -1, NULL, S_NULL, 0, 0}, // S_SPAWNBATS_OFF
+ {SPR_ABAT, 0, 2, A_BatMove, S_BAT2, 0, 0}, // S_BAT1
+ {SPR_ABAT, 1, 2, A_BatMove, S_BAT3, 0, 0}, // S_BAT2
+ {SPR_ABAT, 2, 2, A_BatMove, S_BAT1, 0, 0}, // S_BAT3
+ {SPR_ABAT, 0, 2, NULL, S_NULL, 0, 0} // S_BAT_DEATH
+};
+
+
+mobjinfo_t mobjinfo[NUMMOBJTYPES] = {
+
+ { // MT_MAPSPOT
+ 9001, // doomednum
+ S_MAPSPOT, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOSECTOR | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_MAPSPOTGRAVITY
+ 9013, // doomednum
+ S_MAPSPOT, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ 0, // flags
+ MF2_DONTDRAW // flags2
+ },
+
+ { // MT_FIREBALL1
+ -1, // doomednum
+ S_FIREBALL1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_FIREBALL1_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_FIREBALL, // deathsound
+ 2 * FRACUNIT, // speed
+ 8 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 4, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_FIREDAMAGE // flags2
+ },
+
+ { // MT_ARROW
+ -1, // doomednum
+ S_ARROW_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_ARROW_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 6 * FRACUNIT, // speed
+ 8 * FRACUNIT, // radius
+ 4 * FRACUNIT, // height
+ 100, // mass
+ 4, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_DART
+ -1, // doomednum
+ S_DART_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_DART_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 6 * FRACUNIT, // speed
+ 8 * FRACUNIT, // radius
+ 4 * FRACUNIT, // height
+ 100, // mass
+ 2, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_POISONDART
+ -1, // doomednum
+ S_POISONDART_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_POISONDART_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 6 * FRACUNIT, // speed
+ 8 * FRACUNIT, // radius
+ 4 * FRACUNIT, // height
+ 100, // mass
+ 2, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_RIPPERBALL
+ -1, // doomednum
+ S_RIPPERBALL_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_RIPPERBALL_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 6 * FRACUNIT, // speed
+ 8 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 2, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_RIP // flags2
+ },
+
+ { // MT_PROJECTILE_BLADE
+ -1, // doomednum
+ S_PRJ_BLADE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_PRJ_BLADE_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 6 * FRACUNIT, // speed
+ 6 * FRACUNIT, // radius
+ 6 * FRACUNIT, // height
+ 100, // mass
+ 3, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_ICESHARD
+ -1, // doomednum
+ S_ICESHARD1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SHARDFXE1_1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_MAGE_SHARDS_EXPLODE, // deathsound
+ 25 * FRACUNIT, // speed
+ 13 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 1, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_ICEDAMAGE // flags2
+ },
+
+ { // MT_FLAME_SMALL_TEMP
+ 10500, // doomednum
+ S_FLAME_TSMALL1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ 0, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_FLAME_LARGE_TEMP
+ 10502, // doomednum
+ S_FLAME_TLARGE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ 0, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_FLAME_SMALL
+ 10501, // doomednum
+ S_FLAME_SMALL1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ 0, // flags
+ MF2_NOTELEPORT | MF2_DONTDRAW // flags2
+ },
+
+ { // MT_FLAME_LARGE
+ 10503, // doomednum
+ S_FLAME_LARGE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ 0, // flags
+ MF2_NOTELEPORT | MF2_DONTDRAW // flags2
+ },
+
+ { // MT_HEALINGBOTTLE
+ 81, // doomednum
+ S_ITEM_PTN1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_HEALTHFLASK
+ 82, // doomednum
+ S_ARTI_PTN2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_ARTIFLY
+ 83, // doomednum
+ S_ARTI_SOAR1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_ARTIINVULNERABILITY
+ 84, // doomednum
+ S_ARTI_INVU1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_SUMMONMAULATOR
+ 86, // doomednum
+ S_ARTI_SUMMON, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_SUMMON_FX
+ -1, // doomednum
+ S_SUMMON_FX1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SUMMON_FX2_1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 20 * FRACUNIT, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_MISSILE | MF_DROPOFF | MF_NOBLOCKMAP, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_THRUSTFLOOR_UP
+ 10091, // doomednum
+ S_THRUSTINIT2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 128 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ MF2_NOTELEPORT | MF2_FLOORCLIP // flags2
+ },
+
+ { // MT_THRUSTFLOOR_DOWN
+ 10090, // doomednum
+ S_THRUSTINIT1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 128 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ 0, // flags
+ MF2_NOTELEPORT | MF2_FLOORCLIP | MF2_DONTDRAW // flags2
+ },
+
+ { // MT_TELEPORTOTHER
+ 10040, // doomednum
+ S_ARTI_TELOTHER1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_TELOTHER_FX1
+ -1, // doomednum
+ S_TELO_FX1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_TELO_FX9, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 20 * FRACUNIT, // speed
+ 16 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 10001, // damage
+ SFX_NONE, // activesound
+ MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY | MF_NOBLOCKMAP, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_TELOTHER_FX2
+ -1, // doomednum
+ S_TELO_FX2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_TELO_FX9, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 16 * FRACUNIT, // speed
+ 16 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 10001, // damage
+ SFX_NONE, // activesound
+ MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY | MF_NOBLOCKMAP, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_TELOTHER_FX3
+ -1, // doomednum
+ S_TELO_FX3_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_TELO_FX9, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 16 * FRACUNIT, // speed
+ 16 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 10001, // damage
+ SFX_NONE, // activesound
+ MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY | MF_NOBLOCKMAP, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_TELOTHER_FX4
+ -1, // doomednum
+ S_TELO_FX4_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_TELO_FX9, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 16 * FRACUNIT, // speed
+ 16 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 10001, // damage
+ SFX_NONE, // activesound
+ MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY | MF_NOBLOCKMAP, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_TELOTHER_FX5
+ -1, // doomednum
+ S_TELO_FX5_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_TELO_FX9, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 16 * FRACUNIT, // speed
+ 16 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 10001, // damage
+ SFX_NONE, // activesound
+ MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY | MF_NOBLOCKMAP, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_DIRT1
+ -1, // doomednum
+ S_DIRT1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_DIRT1_D, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_DIRT2
+ -1, // doomednum
+ S_DIRT2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_DIRT2_D, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_DIRT3
+ -1, // doomednum
+ S_DIRT3_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_DIRT3_D, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_DIRT4
+ -1, // doomednum
+ S_DIRT4_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_DIRT4_D, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags
+ MF2_NOTELEPORT | MF2_LOGRAV // flags2
+ },
+
+ { // MT_DIRT5
+ -1, // doomednum
+ S_DIRT5_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_DIRT5_D, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags
+ MF2_NOTELEPORT | MF2_LOGRAV // flags2
+ },
+
+ { // MT_DIRT6
+ -1, // doomednum
+ S_DIRT6_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_DIRT6_D, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags
+ MF2_NOTELEPORT | MF2_LOGRAV // flags2
+ },
+
+ { // MT_DIRTCLUMP
+ -1, // doomednum
+ S_DIRTCLUMP1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_ROCK1
+ -1, // doomednum
+ S_ROCK1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_ROCK1_D, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_ROCK2
+ -1, // doomednum
+ S_ROCK2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_ROCK2_D, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_ROCK3
+ -1, // doomednum
+ S_ROCK3_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_ROCK3_D, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_FOGSPAWNER
+ 10000, // doomednum
+ S_SPAWNFOG1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOSECTOR, // flags
+ MF2_DONTDRAW | MF2_FLOATBOB // flags2
+ },
+
+ { // MT_FOGPATCHS
+ 10001, // doomednum
+ S_FOGPATCHS1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_FOGPATCHS0, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ FRACUNIT, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_FLOAT | MF_NOGRAVITY | MF_SHADOW | MF_NOCLIP, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_FOGPATCHM
+ 10002, // doomednum
+ S_FOGPATCHM1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_FOGPATCHM0, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ FRACUNIT, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_FLOAT | MF_NOGRAVITY | MF_SHADOW | MF_NOCLIP, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_FOGPATCHL
+ 10003, // doomednum
+ S_FOGPATCHL1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_FOGPATCHL0, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ FRACUNIT, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_FLOAT | MF_NOGRAVITY | MF_SHADOW | MF_NOCLIP, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_QUAKE_FOCUS
+ -1, // doomednum
+ S_QUAKE_ACTIVE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOSECTOR, // flags
+ MF2_DONTDRAW // flags2
+ },
+
+ { // MT_SGSHARD1
+ -1, // doomednum
+ S_SGSHARD1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SGSHARD1_D, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 5, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2
+ },
+
+ { // MT_SGSHARD2
+ -1, // doomednum
+ S_SGSHARD2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SGSHARD2_D, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 5, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2
+ },
+
+ { // MT_SGSHARD3
+ -1, // doomednum
+ S_SGSHARD3_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SGSHARD3_D, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 5, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2
+ },
+
+ { // MT_SGSHARD4
+ -1, // doomednum
+ S_SGSHARD4_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SGSHARD4_D, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 5, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2
+ },
+
+ { // MT_SGSHARD5
+ -1, // doomednum
+ S_SGSHARD5_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SGSHARD5_D, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 5, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2
+ },
+
+ { // MT_SGSHARD6
+ -1, // doomednum
+ S_SGSHARD6_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SGSHARD6_D, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 5, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2
+ },
+
+ { // MT_SGSHARD7
+ -1, // doomednum
+ S_SGSHARD7_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SGSHARD7_D, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 5, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2
+ },
+
+ { // MT_SGSHARD8
+ -1, // doomednum
+ S_SGSHARD8_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SGSHARD8_D, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 5, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2
+ },
+
+ { // MT_SGSHARD9
+ -1, // doomednum
+ S_SGSHARD9_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SGSHARD9_D, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 5, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2
+ },
+
+ { // MT_SGSHARD0
+ -1, // doomednum
+ S_SGSHARD0_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SGSHARD0_D, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 5, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2
+ },
+
+ { // MT_ARTIEGG
+ 30, // doomednum
+ S_ARTI_EGGC1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_EGGFX
+ -1, // doomednum
+ S_EGGFX1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_EGGFXI1_1, // deathstate
+ S_NULL, // xdeathstate
+ 0, // deathsound
+ 18 * FRACUNIT, // speed
+ 8 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 1, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_ARTISUPERHEAL
+ 32, // doomednum
+ S_ARTI_SPHL1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_ZWINGEDSTATUENOSKULL
+ 9011, // doomednum
+ S_ZWINGEDSTATUENOSKULL, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 10 * FRACUNIT, // radius
+ 62 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_ZGEMPEDESTAL
+ 9012, // doomednum
+ S_ZGEMPEDESTAL1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 10 * FRACUNIT, // radius
+ 40 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_ARTIPUZZSKULL
+ 9002, // doomednum
+ S_ARTIPUZZSKULL, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_ARTIPUZZGEMBIG
+ 9003, // doomednum
+ S_ARTIPUZZGEMBIG, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_ARTIPUZZGEMRED
+ 9004, // doomednum
+ S_ARTIPUZZGEMRED, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_ARTIPUZZGEMGREEN1
+ 9005, // doomednum
+ S_ARTIPUZZGEMGREEN1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_ARTIPUZZGEMGREEN2
+ 9009, // doomednum
+ S_ARTIPUZZGEMGREEN2, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_ARTIPUZZGEMBLUE1
+ 9006, // doomednum
+ S_ARTIPUZZGEMBLUE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_ARTIPUZZGEMBLUE2
+ 9010, // doomednum
+ S_ARTIPUZZGEMBLUE2, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_ARTIPUZZBOOK1
+ 9007, // doomednum
+ S_ARTIPUZZBOOK1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_ARTIPUZZBOOK2
+ 9008, // doomednum
+ S_ARTIPUZZBOOK2, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_ARTIPUZZSKULL2
+ 9014, // doomednum
+ S_ARTIPUZZSKULL2, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_ARTIPUZZFWEAPON
+ 9015, // doomednum
+ S_ARTIPUZZFWEAPON, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_ARTIPUZZCWEAPON
+ 9016, // doomednum
+ S_ARTIPUZZCWEAPON, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_ARTIPUZZMWEAPON
+ 9017, // doomednum
+ S_ARTIPUZZMWEAPON, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_ARTIPUZZGEAR
+ 9018, // doomednum
+ S_ARTIPUZZGEAR_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_ARTIPUZZGEAR2
+ 9019, // doomednum
+ S_ARTIPUZZGEAR2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_ARTIPUZZGEAR3
+ 9020, // doomednum
+ S_ARTIPUZZGEAR3_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_ARTIPUZZGEAR4
+ 9021, // doomednum
+ S_ARTIPUZZGEAR4_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_ARTITORCH
+ 33, // doomednum
+ S_ARTI_TRCH1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_FIREBOMB
+ -1, // doomednum
+ S_FIREBOMB1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_FLECHETTE_EXPLODE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOGRAVITY | MF_ALTSHADOW, // flags
+ MF2_FIREDAMAGE // flags2
+ },
+
+ { // MT_ARTITELEPORT
+ 36, // doomednum
+ S_ARTI_ATLP1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_ARTIPOISONBAG
+ 8000, // doomednum
+ S_ARTI_PSBG1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_POISONBAG
+ -1, // doomednum
+ S_POISONBAG1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOGRAVITY | MF_NOBLOCKMAP, // flags
+ 0 // flags2
+ },
+
+ { // MT_POISONCLOUD
+ -1, // doomednum
+ S_POISONCLOUD1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_POISONSHROOM_DEATH, // deathsound
+ 0, // speed
+ 1, // radius
+ 1, // height
+ INT_MAX, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOGRAVITY | MF_NOBLOCKMAP | MF_SHADOW | MF_NOCLIP | MF_DROPOFF, // flags
+ MF2_NODMGTHRUST // flags2
+ },
+
+ { // MT_THROWINGBOMB
+ -1, // doomednum
+ S_THROWINGBOMB1, // spawnstate
+ 48, // spawnhealth
+ S_NULL, // seestate
+ SFX_FLECHETTE_BOUNCE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_THROWINGBOMB_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_FLECHETTE_EXPLODE, // deathsound
+ 12 * FRACUNIT, // speed
+ 8 * FRACUNIT, // radius
+ 10 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags
+ MF2_FLOORBOUNCE | MF2_FIREDAMAGE // flags2
+ },
+
+ { // MT_SPEEDBOOTS
+ 8002, // doomednum
+ S_ARTI_BOOTS1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_BOOSTMANA
+ 8003, // doomednum
+ S_ARTI_MANA, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_BOOSTARMOR
+ 8041, // doomednum
+ S_ARTI_ARMOR1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_BLASTRADIUS
+ 10110, // doomednum
+ S_ARTI_BLAST1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_HEALRADIUS
+ 10120, // doomednum
+ S_ARTI_HEALRAD1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_SPLASH
+ -1, // doomednum
+ S_SPLASH1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SPLASHX, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 2 * FRACUNIT, // radius
+ 4 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF, // flags
+ MF2_NOTELEPORT | MF2_LOGRAV | MF2_CANNOTPUSH // flags2
+ },
+
+ { // MT_SPLASHBASE
+ -1, // doomednum
+ S_SPLASHBASE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP, // flags
+ 0 // flags2
+ },
+
+ { // MT_LAVASPLASH
+ -1, // doomednum
+ S_LAVASPLASH1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP, // flags
+ 0 // flags2
+ },
+
+ { // MT_LAVASMOKE
+ -1, // doomednum
+ S_LAVASMOKE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags
+ 0 // flags2
+ },
+
+ { // MT_SLUDGECHUNK
+ -1, // doomednum
+ S_SLUDGECHUNK1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SLUDGECHUNKX, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 2 * FRACUNIT, // radius
+ 4 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF, // flags
+ MF2_NOTELEPORT | MF2_LOGRAV | MF2_CANNOTPUSH // flags2
+ },
+
+ { // MT_SLUDGESPLASH
+ -1, // doomednum
+ S_SLUDGESPLASH1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC0
+ 5, // doomednum
+ S_ZWINGEDSTATUE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 10 * FRACUNIT, // radius
+ 62 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC1
+ 6, // doomednum
+ S_ZROCK1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ 0, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC2
+ 7, // doomednum
+ S_ZROCK2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ 0, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC3
+ 9, // doomednum
+ S_ZROCK3_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ 0, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC4
+ 15, // doomednum
+ S_ZROCK4_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC5
+ 17, // doomednum
+ S_ZCHANDELIER1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 60 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPAWNCEILING | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC6
+ 8063, // doomednum
+ S_ZCHANDELIER_U, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 60 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPAWNCEILING | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC7
+ 24, // doomednum
+ S_ZTREEDEAD1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 10 * FRACUNIT, // radius
+ 96 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC8
+ 25, // doomednum
+ S_ZTREE, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 15 * FRACUNIT, // radius
+ 128 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_TREEDESTRUCTIBLE
+ 8062, // doomednum
+ S_ZTREEDESTRUCTIBLE1, // spawnstate
+ 70, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_ZTREEDES_D1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_TREE_BREAK, // deathsound
+ 0, // speed
+ 15 * FRACUNIT, // radius
+ 180 * FRACUNIT, // height
+ INT_MAX, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_NOBLOOD, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC9
+ 26, // doomednum
+ S_ZTREESWAMP182_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 10 * FRACUNIT, // radius
+ 150 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC10
+ 27, // doomednum
+ S_ZTREESWAMP172_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 10 * FRACUNIT, // radius
+ 120 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC11
+ 28, // doomednum
+ S_ZSTUMPBURNED1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 12 * FRACUNIT, // radius
+ 20 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC12
+ 29, // doomednum
+ S_ZSTUMPBARE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 12 * FRACUNIT, // radius
+ 20 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC13
+ 37, // doomednum
+ S_ZSTUMPSWAMP1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ 0, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC14
+ 38, // doomednum
+ S_ZSTUMPSWAMP2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ 0, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC15
+ 39, // doomednum
+ S_ZSHROOMLARGE1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ 0, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC16
+ 40, // doomednum
+ S_ZSHROOMLARGE2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ 0, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC17
+ 41, // doomednum
+ S_ZSHROOMLARGE3_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ 0, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC18
+ 42, // doomednum
+ S_ZSHROOMSMALL1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ 0, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC19
+ 44, // doomednum
+ S_ZSHROOMSMALL2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ 0, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC20
+ 45, // doomednum
+ S_ZSHROOMSMALL3_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ 0, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC21
+ 46, // doomednum
+ S_ZSHROOMSMALL4_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ 0, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC22
+ 47, // doomednum
+ S_ZSHROOMSMALL5_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ 0, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC23
+ 48, // doomednum
+ S_ZSTALAGMITEPILLAR1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 138 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC24
+ 49, // doomednum
+ S_ZSTALAGMITELARGE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 48 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC25
+ 50, // doomednum
+ S_ZSTALAGMITEMEDIUM1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 6 * FRACUNIT, // radius
+ 40 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC26
+ 51, // doomednum
+ S_ZSTALAGMITESMALL1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 36 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC27
+ 52, // doomednum
+ S_ZSTALACTITELARGE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 66 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC28
+ 56, // doomednum
+ S_ZSTALACTITEMEDIUM1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 6 * FRACUNIT, // radius
+ 50 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC29
+ 57, // doomednum
+ S_ZSTALACTITESMALL1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 40 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC30
+ 58, // doomednum
+ S_ZMOSSCEILING1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 20 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPAWNCEILING | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC31
+ 59, // doomednum
+ S_ZMOSSCEILING2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 24 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPAWNCEILING | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC32
+ 60, // doomednum
+ S_ZSWAMPVINE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 52 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC33
+ 61, // doomednum
+ S_ZCORPSEKABOB1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 10 * FRACUNIT, // radius
+ 92 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC34
+ 62, // doomednum
+ S_ZCORPSESLEEPING1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ 0, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC35
+ 63, // doomednum
+ S_ZTOMBSTONERIP1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 10 * FRACUNIT, // radius
+ 46 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC36
+ 64, // doomednum
+ S_ZTOMBSTONESHANE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 10 * FRACUNIT, // radius
+ 46 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC37
+ 65, // doomednum
+ S_ZTOMBSTONEBIGCROSS1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 10 * FRACUNIT, // radius
+ 46 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC38
+ 66, // doomednum
+ S_ZTOMBSTONEBRIANR1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 10 * FRACUNIT, // radius
+ 52 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC39
+ 67, // doomednum
+ S_ZTOMBSTONECROSSCIRCLE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 10 * FRACUNIT, // radius
+ 52 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC40
+ 68, // doomednum
+ S_ZTOMBSTONESMALLCROSS1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 46 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC41
+ 69, // doomednum
+ S_ZTOMBSTONEBRIANP1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 46 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC42
+ 71, // doomednum
+ S_CORPSEHANGING_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 6 * FRACUNIT, // radius
+ 75 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC43
+ 72, // doomednum
+ S_ZSTATUEGARGOYLEGREENTALL_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 14 * FRACUNIT, // radius
+ 108 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC44
+ 73, // doomednum
+ S_ZSTATUEGARGOYLEBLUETALL_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 14 * FRACUNIT, // radius
+ 108 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC45
+ 74, // doomednum
+ S_ZSTATUEGARGOYLEGREENSHORT_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 14 * FRACUNIT, // radius
+ 62 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC46
+ 76, // doomednum
+ S_ZSTATUEGARGOYLEBLUESHORT_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 14 * FRACUNIT, // radius
+ 62 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC47
+ 8044, // doomednum
+ S_ZSTATUEGARGOYLESTRIPETALL_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 14 * FRACUNIT, // radius
+ 108 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC48
+ 8045, // doomednum
+ S_ZSTATUEGARGOYLEDARKREDTALL_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 14 * FRACUNIT, // radius
+ 108 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC49
+ 8046, // doomednum
+ S_ZSTATUEGARGOYLEREDTALL_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 14 * FRACUNIT, // radius
+ 108 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC50
+ 8047, // doomednum
+ S_ZSTATUEGARGOYLETANTALL_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 14 * FRACUNIT, // radius
+ 108 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC51
+ 8048, // doomednum
+ S_ZSTATUEGARGOYLERUSTTALL_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 14 * FRACUNIT, // radius
+ 108 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC52
+ 8049, // doomednum
+ S_ZSTATUEGARGOYLEDARKREDSHORT_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 14 * FRACUNIT, // radius
+ 62 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC53
+ 8050, // doomednum
+ S_ZSTATUEGARGOYLEREDSHORT_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 14 * FRACUNIT, // radius
+ 62 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC54
+ 8051, // doomednum
+ S_ZSTATUEGARGOYLETANSHORT_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 14 * FRACUNIT, // radius
+ 62 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC55
+ 8052, // doomednum
+ S_ZSTATUEGARGOYLERUSTSHORT_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 14 * FRACUNIT, // radius
+ 62 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC56
+ 77, // doomednum
+ S_ZBANNERTATTERED_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 120 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC57
+ 78, // doomednum
+ S_ZTREELARGE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_ZTREELARGE1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 15 * FRACUNIT, // radius
+ 180 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC58
+ 79, // doomednum
+ S_ZTREELARGE2, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_ZTREELARGE2, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 15 * FRACUNIT, // radius
+ 180 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC59
+ 80, // doomednum
+ S_ZTREEGNARLED1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 22 * FRACUNIT, // radius
+ 100 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC60
+ 87, // doomednum
+ S_ZTREEGNARLED2, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 22 * FRACUNIT, // radius
+ 100 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC61
+ 88, // doomednum
+ S_ZLOG, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 25 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC62
+ 89, // doomednum
+ S_ZSTALACTITEICELARGE, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 66 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC63
+ 90, // doomednum
+ S_ZSTALACTITEICEMEDIUM, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 50 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC64
+ 91, // doomednum
+ S_ZSTALACTITEICESMALL, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 4 * FRACUNIT, // radius
+ 32 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC65
+ 92, // doomednum
+ S_ZSTALACTITEICETINY, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 4 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC66
+ 93, // doomednum
+ S_ZSTALAGMITEICELARGE, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 66 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC67
+ 94, // doomednum
+ S_ZSTALAGMITEICEMEDIUM, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 50 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC68
+ 95, // doomednum
+ S_ZSTALAGMITEICESMALL, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 4 * FRACUNIT, // radius
+ 32 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC69
+ 96, // doomednum
+ S_ZSTALAGMITEICETINY, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 4 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC70
+ 97, // doomednum
+ S_ZROCKBROWN1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 17 * FRACUNIT, // radius
+ 72 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC71
+ 98, // doomednum
+ S_ZROCKBROWN2, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 15 * FRACUNIT, // radius
+ 50 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC72
+ 99, // doomednum
+ S_ZROCKBLACK, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 40 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC73
+ 100, // doomednum
+ S_ZRUBBLE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ 0, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC74
+ 101, // doomednum
+ S_ZRUBBLE2, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ 0, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC75
+ 102, // doomednum
+ S_ZRUBBLE3, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ 0, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC76
+ 103, // doomednum
+ S_ZVASEPILLAR, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 12 * FRACUNIT, // radius
+ 54 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_POTTERY1
+ 104, // doomednum
+ S_ZPOTTERY1, // spawnstate
+ 15, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_ZPOTTERY_EXPLODE, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 10 * FRACUNIT, // radius
+ 32 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_NOBLOOD | MF_DROPOFF, // flags
+ MF2_SLIDE | MF2_PUSHABLE | MF2_TELESTOMP | MF2_PASSMOBJ // flags2
+ },
+
+ { // MT_POTTERY2
+ 105, // doomednum
+ S_ZPOTTERY2, // spawnstate
+ 15, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_ZPOTTERY_EXPLODE, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 10 * FRACUNIT, // radius
+ 25 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_NOBLOOD | MF_DROPOFF, // flags
+ MF2_SLIDE | MF2_PUSHABLE | MF2_TELESTOMP | MF2_PASSMOBJ // flags2
+ },
+
+ { // MT_POTTERY3
+ 106, // doomednum
+ S_ZPOTTERY3, // spawnstate
+ 15, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_ZPOTTERY_EXPLODE, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 15 * FRACUNIT, // radius
+ 25 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_NOBLOOD | MF_DROPOFF, // flags
+ MF2_SLIDE | MF2_PUSHABLE | MF2_TELESTOMP | MF2_PASSMOBJ // flags2
+ },
+
+ { // MT_POTTERYBIT1
+ -1, // doomednum
+ S_POTTERYBIT_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_POTTERYBIT_EX0, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_MISSILE, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_MISC77
+ 108, // doomednum
+ S_ZCORPSELYNCHED1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 11 * FRACUNIT, // radius
+ 95 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_ZLYNCHED_NOHEART
+ 109, // doomednum
+ S_ZCORPSELYNCHED2, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 10 * FRACUNIT, // radius
+ 100 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC78
+ 110, // doomednum
+ S_ZCORPSESITTING, // spawnstate
+ 30, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_ZCORPSESITTING_X, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 15 * FRACUNIT, // radius
+ 35 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_NOBLOOD, // flags
+ 0 // flags2
+ },
+
+ { // MT_CORPSEBIT
+ -1, // doomednum
+ S_CORPSEBIT_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP, // flags
+ MF2_TELESTOMP // flags2
+ },
+
+ { // MT_CORPSEBLOODDRIP
+ -1, // doomednum
+ S_CORPSEBLOODDRIP, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_CORPSEBLOODDRIP_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_DRIP, // deathsound
+ 0, // speed
+ FRACUNIT, // radius
+ 4 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_MISSILE, // flags
+ MF2_LOGRAV // flags2
+ },
+
+ { // MT_BLOODPOOL
+ 111, // doomednum
+ S_BLOODPOOL, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC79
+ 119, // doomednum
+ S_ZCANDLE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC80
+ 113, // doomednum
+ S_ZLEAFSPAWNER, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOSECTOR, // flags
+ MF2_DONTDRAW // flags2
+ },
+
+ { // MT_LEAF1
+ -1, // doomednum
+ S_LEAF1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_LEAF_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 2 * FRACUNIT, // radius
+ 4 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE, // flags
+ MF2_NOTELEPORT | MF2_LOGRAV // flags2
+ },
+
+ { // MT_LEAF2
+ -1, // doomednum
+ S_LEAF2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_LEAF_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 2 * FRACUNIT, // radius
+ 4 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE, // flags
+ MF2_NOTELEPORT | MF2_LOGRAV // flags2
+ },
+
+ { // MT_ZTWINEDTORCH
+ 116, // doomednum
+ S_ZTWINEDTORCH_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 10 * FRACUNIT, // radius
+ 64 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_ZTWINEDTORCH_UNLIT
+ 117, // doomednum
+ S_ZTWINEDTORCH_UNLIT, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 10 * FRACUNIT, // radius
+ 64 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_BRIDGE
+ 118, // doomednum
+ S_BRIDGE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 32 * FRACUNIT, // radius
+ 2 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_NOGRAVITY, // flags
+ MF2_DONTDRAW // flags2
+ },
+
+ { // MT_BRIDGEBALL
+ -1, // doomednum
+ S_BBALL1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_ZWALLTORCH
+ 54, // doomednum
+ S_ZWALLTORCH1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_ZWALLTORCH_UNLIT
+ 55, // doomednum
+ S_ZWALLTORCH_U, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_ZBARREL
+ 8100, // doomednum
+ S_ZBARREL1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 15 * FRACUNIT, // radius
+ 32 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_ZSHRUB1
+ 8101, // doomednum
+ S_ZSHRUB1, // spawnstate
+ 20, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_ZSHRUB1_X1, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_ZSHRUB1_DIE, // deathstate
+ S_NULL, // xdeathstate
+ SFX_TREE_EXPLODE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 24 * FRACUNIT, // height
+ INT_MAX, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_NOBLOOD, // flags
+ 0 // flags2
+ },
+
+ { // MT_ZSHRUB2
+ 8102, // doomednum
+ S_ZSHRUB2, // spawnstate
+ 10, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_ZSHRUB2_X1, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_ZSHRUB2_DIE, // deathstate
+ S_NULL, // xdeathstate
+ SFX_TREE_EXPLODE, // deathsound
+ 0, // speed
+ 16 * FRACUNIT, // radius
+ 40 * FRACUNIT, // height
+ INT_MAX, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_NOBLOOD, // flags
+ 0 // flags2
+ },
+
+ { // MT_ZBUCKET
+ 8103, // doomednum
+ S_ZBUCKET1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 72 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SPAWNCEILING | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_ZPOISONSHROOM
+ 8104, // doomednum
+ S_ZPOISONSHROOM1, // spawnstate
+ 30, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_ZPOISONSHROOM_P1, // painstate
+ 255, // painchance
+ SFX_POISONSHROOM_PAIN, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_ZPOISONSHROOM_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_POISONSHROOM_DEATH, // deathsound
+ 0, // speed
+ 6 * FRACUNIT, // radius
+ 20 * FRACUNIT, // height
+ INT_MAX, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SHOOTABLE | MF_SOLID | MF_NOBLOOD, // flags
+ 0 // flags2
+ },
+
+ { // MT_ZFIREBULL
+ 8042, // doomednum
+ S_ZFIREBULL1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 80 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_ZFIREBULL_UNLIT
+ 8043, // doomednum
+ S_ZFIREBULL_U, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 80 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_FIRETHING
+ 8060, // doomednum
+ S_ZFIRETHING1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 10 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_BRASSTORCH
+ 8061, // doomednum
+ S_ZBRASSTORCH1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 6 * FRACUNIT, // radius
+ 35 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_ZSUITOFARMOR
+ 8064, // doomednum
+ S_ZSUITOFARMOR, // spawnstate
+ 60, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_ZSUITOFARMOR_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_SUITOFARMOR_BREAK, // deathsound
+ 0, // speed
+ 16 * FRACUNIT, // radius
+ 72 * FRACUNIT, // height
+ INT_MAX, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_NOBLOOD, // flags
+ 0 // flags2
+ },
+
+ { // MT_ZARMORCHUNK
+ -1, // doomednum
+ S_ZARMORCHUNK1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 4 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ 0, // flags
+ 0 // flags2
+ },
+
+ { // MT_ZBELL
+ 8065, // doomednum
+ S_ZBELL, // spawnstate
+ 5, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_ZBELL_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_BELLRING, // deathsound
+ 0, // speed
+ 56 * FRACUNIT, // radius
+ 120 * FRACUNIT, // height
+ INT_MAX, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_NOBLOOD | MF_NOGRAVITY | MF_SPAWNCEILING, // flags
+ 0 // flags2
+ },
+
+ { // MT_ZBLUE_CANDLE
+ 8066, // doomednum
+ S_ZBLUE_CANDLE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP, // flags
+ 0 // flags2
+ },
+
+ { // MT_ZIRON_MAIDEN
+ 8067, // doomednum
+ S_ZIRON_MAIDEN, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 12 * FRACUNIT, // radius
+ 60 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_ZXMAS_TREE
+ 8068, // doomednum
+ S_ZXMAS_TREE, // spawnstate
+ 20, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_ZXMAS_TREE_X1, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_ZXMAS_TREE_DIE, // deathstate
+ S_NULL, // xdeathstate
+ SFX_TREE_EXPLODE, // deathsound
+ 0, // speed
+ 11 * FRACUNIT, // radius
+ 130 * FRACUNIT, // height
+ INT_MAX, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_NOBLOOD, // flags
+ 0 // flags2
+ },
+
+ { // MT_ZCAULDRON
+ 8069, // doomednum
+ S_ZCAULDRON1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 12 * FRACUNIT, // radius
+ 26 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_ZCAULDRON_UNLIT
+ 8070, // doomednum
+ S_ZCAULDRON_U, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 12 * FRACUNIT, // radius
+ 26 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID, // flags
+ 0 // flags2
+ },
+
+ { // MT_ZCHAINBIT32
+ 8071, // doomednum
+ S_ZCHAINBIT32, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 4 * FRACUNIT, // radius
+ 32 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SPAWNCEILING, // flags
+ 0 // flags2
+ },
+
+ { // MT_ZCHAINBIT64
+ 8072, // doomednum
+ S_ZCHAINBIT64, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 4 * FRACUNIT, // radius
+ 64 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SPAWNCEILING, // flags
+ 0 // flags2
+ },
+
+ { // MT_ZCHAINEND_HEART
+ 8073, // doomednum
+ S_ZCHAINEND_HEART, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 4 * FRACUNIT, // radius
+ 32 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SPAWNCEILING, // flags
+ 0 // flags2
+ },
+
+ { // MT_ZCHAINEND_HOOK1
+ 8074, // doomednum
+ S_ZCHAINEND_HOOK1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 4 * FRACUNIT, // radius
+ 32 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SPAWNCEILING, // flags
+ 0 // flags2
+ },
+
+ { // MT_ZCHAINEND_HOOK2
+ 8075, // doomednum
+ S_ZCHAINEND_HOOK2, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 4 * FRACUNIT, // radius
+ 32 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SPAWNCEILING, // flags
+ 0 // flags2
+ },
+
+ { // MT_ZCHAINEND_SPIKE
+ 8076, // doomednum
+ S_ZCHAINEND_SPIKE, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 4 * FRACUNIT, // radius
+ 32 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SPAWNCEILING, // flags
+ 0 // flags2
+ },
+
+ { // MT_ZCHAINEND_SKULL
+ 8077, // doomednum
+ S_ZCHAINEND_SKULL, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 4 * FRACUNIT, // radius
+ 32 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SPAWNCEILING, // flags
+ 0 // flags2
+ },
+
+ { // MT_TABLE_SHIT1
+ 8500, // doomednum
+ S_TABLE_SHIT1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP, // flags
+ 0 // flags2
+ },
+
+ { // MT_TABLE_SHIT2
+ 8501, // doomednum
+ S_TABLE_SHIT2, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP, // flags
+ 0 // flags2
+ },
+
+ { // MT_TABLE_SHIT3
+ 8502, // doomednum
+ S_TABLE_SHIT3, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP, // flags
+ 0 // flags2
+ },
+
+ { // MT_TABLE_SHIT4
+ 8503, // doomednum
+ S_TABLE_SHIT4, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP, // flags
+ 0 // flags2
+ },
+
+ { // MT_TABLE_SHIT5
+ 8504, // doomednum
+ S_TABLE_SHIT5, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP, // flags
+ 0 // flags2
+ },
+
+ { // MT_TABLE_SHIT6
+ 8505, // doomednum
+ S_TABLE_SHIT6, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP, // flags
+ 0 // flags2
+ },
+
+ { // MT_TABLE_SHIT7
+ 8506, // doomednum
+ S_TABLE_SHIT7, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP, // flags
+ 0 // flags2
+ },
+
+ { // MT_TABLE_SHIT8
+ 8507, // doomednum
+ S_TABLE_SHIT8, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP, // flags
+ 0 // flags2
+ },
+
+ { // MT_TABLE_SHIT9
+ 8508, // doomednum
+ S_TABLE_SHIT9, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP, // flags
+ 0 // flags2
+ },
+
+ { // MT_TABLE_SHIT10
+ 8509, // doomednum
+ S_TABLE_SHIT10, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP, // flags
+ 0 // flags2
+ },
+
+ { // MT_TFOG
+ -1, // doomednum
+ S_TFOG1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_MISC81
+ 140, // doomednum
+ S_TELESMOKE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_TELEPORTMAN
+ 14, // doomednum
+ S_NULL, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOSECTOR, // flags
+ 0 // flags2
+ },
+
+ { // MT_PUNCHPUFF
+ -1, // doomednum
+ S_PUNCHPUFF1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_FIGHTER_PUNCH_HITTHING, // seesound
+ 8, // reactiontime
+ SFX_FIGHTER_PUNCH_HITWALL, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags
+ 0 // flags2
+ },
+
+ { // MT_FW_AXE
+ 8010, // doomednum
+ S_AXE, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_AXEPUFF
+ -1, // doomednum
+ S_HAMMERPUFF1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_FIGHTER_AXE_HITTHING, // seesound
+ 8, // reactiontime
+ SFX_FIGHTER_HAMMER_HITWALL, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags
+ 0 // flags2
+ },
+
+ { // MT_AXEPUFF_GLOW
+ -1, // doomednum
+ S_AXEPUFF_GLOW1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_FIGHTER_AXE_HITTHING, // seesound
+ 8, // reactiontime
+ SFX_FIGHTER_HAMMER_HITWALL, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_AXEBLOOD
+ -1, // doomednum
+ S_AXEBLOOD1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_AXEBLOOD6, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 2 * FRACUNIT, // radius
+ 4 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_DROPOFF, // flags
+ MF2_NOTELEPORT | MF2_CANNOTPUSH // flags2
+ },
+
+ { // MT_FW_HAMMER
+ 123, // doomednum
+ S_HAMM, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_HAMMER_MISSILE
+ -1, // doomednum
+ S_HAMMER_MISSILE_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_HAMMER_MISSILE_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_FIGHTER_HAMMER_EXPLODE, // deathsound
+ 25 * FRACUNIT, // speed
+ 14 * FRACUNIT, // radius
+ 20 * FRACUNIT, // height
+ 100, // mass
+ 10, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_IMPACT | MF2_PCROSS | MF2_FIREDAMAGE // flags2
+ },
+
+ { // MT_HAMMERPUFF
+ -1, // doomednum
+ S_HAMMERPUFF1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_FIGHTER_HAMMER_HITTHING, // seesound
+ 8, // reactiontime
+ SFX_FIGHTER_HAMMER_HITWALL, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags
+ 0 // flags2
+ },
+
+ { // MT_FSWORD_MISSILE
+ -1, // doomednum
+ S_FSWORD_MISSILE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_FSWORD_MISSILE_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_FIGHTER_SWORD_EXPLODE, // deathsound
+ 30 * FRACUNIT, // speed
+ 16 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 8, // damage
+ SFX_NONE, // activesound
+ MF_MISSILE | MF_NOBLOCKMAP | MF_NOGRAVITY | MF_DROPOFF, // flags
+ MF2_NOTELEPORT | MF2_IMPACT | MF2_PCROSS // flags2
+ },
+
+ { // MT_FSWORD_FLAME
+ -1, // doomednum
+ S_FSWORD_FLAME1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags
+ 0 // flags2
+ },
+
+ { // MT_CW_SERPSTAFF
+ 10, // doomednum
+ S_CSTAFF, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_CSTAFF_MISSILE
+ -1, // doomednum
+ S_CSTAFF_MISSILE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_CSTAFF_MISSILE_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_CLERIC_CSTAFF_EXPLODE, // deathsound
+ 22 * FRACUNIT, // speed
+ 12 * FRACUNIT, // radius
+ 10 * FRACUNIT, // height
+ 100, // mass
+ 5, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_IMPACT | MF2_PCROSS // flags2
+ },
+
+ { // MT_CSTAFFPUFF
+ -1, // doomednum
+ S_CSTAFFPUFF1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_CLERIC_CSTAFF_HITTHING, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags
+ 0 // flags2
+ },
+
+ { // MT_CW_FLAME
+ 8009, // doomednum
+ S_CFLAME1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_CFLAMEFLOOR
+ -1, // doomednum
+ S_CFLAMEFLOOR1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_FLAMEPUFF
+ -1, // doomednum
+ S_FLAMEPUFF1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_CLERIC_FLAME_EXPLODE, // seesound
+ 8, // reactiontime
+ SFX_CLERIC_FLAME_EXPLODE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ FRACUNIT, // radius
+ FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_FLAMEPUFF2
+ -1, // doomednum
+ S_FLAMEPUFF2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_CLERIC_FLAME_EXPLODE, // seesound
+ 8, // reactiontime
+ SFX_CLERIC_FLAME_EXPLODE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ FRACUNIT, // radius
+ FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_CIRCLEFLAME
+ -1, // doomednum
+ S_CIRCLE_FLAME1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_CIRCLE_FLAME_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_CLERIC_FLAME_CIRCLE, // deathsound
+ 0, // speed
+ 6 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 2, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_FIREDAMAGE // flags2
+ },
+
+ { // MT_CFLAME_MISSILE
+ -1, // doomednum
+ S_CFLAME_MISSILE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_CFLAME_MISSILE_X, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 200 * FRACUNIT, // speed
+ 14 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 8, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_IMPACT | MF2_PCROSS | MF2_DONTDRAW | MF2_FIREDAMAGE // flags2
+ },
+
+ { // MT_HOLY_FX
+ -1, // doomednum
+ S_HOLY_FX1, // spawnstate
+ 105, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_HOLY_FX_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_SPIRIT_DIE, // deathsound
+ 12 * FRACUNIT, // speed
+ 10 * FRACUNIT, // radius
+ 6 * FRACUNIT, // height
+ 100, // mass
+ 3, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_NOGRAVITY | MF_ALTSHADOW | MF_MISSILE, // flags
+ MF2_NOTELEPORT | MF2_SEEKERMISSILE | MF2_RIP | MF2_IMPACT | MF2_PCROSS // flags2
+ },
+
+ { // MT_HOLY_TAIL
+ -1, // doomednum
+ S_HOLY_TAIL1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ FRACUNIT, // radius
+ FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_NOGRAVITY | MF_NOCLIP | MF_ALTSHADOW, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_HOLY_PUFF
+ -1, // doomednum
+ S_HOLY_PUFF1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags
+ 0 // flags2
+ },
+
+ { // MT_HOLY_MISSILE
+ -1, // doomednum
+ S_HOLY_MISSILE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_HOLY_MISSILE_X, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 30 * FRACUNIT, // speed
+ 15 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 4, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_NOGRAVITY | MF_MISSILE, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_HOLY_MISSILE_PUFF
+ -1, // doomednum
+ S_HOLY_MISSILE_P1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 4 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_NOGRAVITY | MF_ALTSHADOW, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_MWANDPUFF
+ -1, // doomednum
+ S_MWANDPUFF1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_CANNOTPUSH | MF2_NODMGTHRUST // flags2
+ },
+
+ { // MT_MWANDSMOKE
+ -1, // doomednum
+ S_MWANDSMOKE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags
+ MF2_NOTELEPORT | MF2_CANNOTPUSH | MF2_NODMGTHRUST // flags2
+ },
+
+ { // MT_MWAND_MISSILE
+ -1, // doomednum
+ S_MWAND_MISSILE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_MWANDPUFF1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 184 * FRACUNIT, // speed
+ 12 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 2, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_RIP | MF2_IMPACT | MF2_PCROSS | MF2_NODMGTHRUST | MF2_CANNOTPUSH // flags2
+ },
+
+ { // MT_MW_LIGHTNING
+ 8040, // doomednum
+ S_MW_LIGHTNING1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_LIGHTNING_CEILING
+ -1, // doomednum
+ S_LIGHTNING_CEILING1, // spawnstate
+ 144, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_LIGHTNING_C_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 25 * FRACUNIT, // speed
+ 16 * FRACUNIT, // radius
+ 40 * FRACUNIT, // height
+ 100, // mass
+ 8, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_MISSILE | MF_DROPOFF, // flags
+ MF2_NOTELEPORT | MF2_IMPACT | MF2_PCROSS // flags2
+ },
+
+ { // MT_LIGHTNING_FLOOR
+ -1, // doomednum
+ S_LIGHTNING_FLOOR1, // spawnstate
+ 144, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_LIGHTNING_F_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 25 * FRACUNIT, // speed
+ 16 * FRACUNIT, // radius
+ 40 * FRACUNIT, // height
+ 100, // mass
+ 8, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_MISSILE | MF_DROPOFF, // flags
+ MF2_NOTELEPORT | MF2_IMPACT | MF2_PCROSS // flags2
+ },
+
+ { // MT_LIGHTNING_ZAP
+ -1, // doomednum
+ S_LIGHTNING_ZAP1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_LIGHTNING_ZAP_X8, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 15 * FRACUNIT, // radius
+ 35 * FRACUNIT, // height
+ 100, // mass
+ 2, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_MISSILE | MF_DROPOFF, // flags
+ 0 // flags2
+ },
+
+ { // MT_MSTAFF_FX
+ -1, // doomednum
+ S_MSTAFF_FX1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_MSTAFF_FX_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_MAGE_STAFF_EXPLODE, // deathsound
+ 20 * FRACUNIT, // speed
+ 16 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 6, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_FIREDAMAGE | MF2_RIP | MF2_IMPACT | MF2_PCROSS // flags2
+ },
+
+ { // MT_MSTAFF_FX2
+ -1, // doomednum
+ S_MSTAFF_FX2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_MSTAFF_FX2_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_MAGE_STAFF_EXPLODE, // deathsound
+ 17 * FRACUNIT, // speed
+ 20 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 4, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_FIREDAMAGE | MF2_IMPACT | MF2_PCROSS | MF2_SEEKERMISSILE // flags2
+ },
+
+ { // MT_FW_SWORD1
+ 12, // doomednum
+ S_FSWORD1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_FW_SWORD2
+ 13, // doomednum
+ S_FSWORD2, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_FW_SWORD3
+ 16, // doomednum
+ S_FSWORD3, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_CW_HOLY1
+ 18, // doomednum
+ S_CHOLY1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_CW_HOLY2
+ 19, // doomednum
+ S_CHOLY2, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_CW_HOLY3
+ 20, // doomednum
+ S_CHOLY3, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_MW_STAFF1
+ 21, // doomednum
+ S_MSTAFF1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_MW_STAFF2
+ 22, // doomednum
+ S_MSTAFF2, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_MW_STAFF3
+ 23, // doomednum
+ S_MSTAFF3, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_SNOUTPUFF
+ -1, // doomednum
+ S_PUNCHPUFF1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags
+ 0 // flags2
+ },
+
+ { // MT_MW_CONE
+ 53, // doomednum
+ S_COS1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_SHARDFX1
+ -1, // doomednum
+ S_SHARDFX1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SHARDFXE1_1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_MAGE_SHARDS_EXPLODE, // deathsound
+ 25 * FRACUNIT, // speed
+ 13 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 1, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_IMPACT | MF2_PCROSS | MF2_ICEDAMAGE // flags2
+ },
+
+ { // MT_BLOOD
+ -1, // doomednum
+ S_BLOOD1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 5, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP, // flags
+ 0 // flags2
+ },
+
+ { // MT_BLOODSPLATTER
+ -1, // doomednum
+ S_BLOODSPLATTER1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_BLOODSPLATTERX, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 2 * FRACUNIT, // radius
+ 4 * FRACUNIT, // height
+ 5, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF, // flags
+ MF2_NOTELEPORT | MF2_CANNOTPUSH // flags2
+ },
+
+ { // MT_GIBS
+ -1, // doomednum
+ S_GIBS1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_CORPSE, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_PLAYER_FIGHTER
+ -1, // doomednum
+ S_FPLAY, // spawnstate
+ 100, // spawnhealth
+ S_FPLAY_RUN1, // seestate
+ SFX_NONE, // seesound
+ 0, // reactiontime
+ SFX_NONE, // attacksound
+ S_FPLAY_PAIN, // painstate
+ 255, // painchance
+ SFX_PLAYER_FIGHTER_PAIN, // painsound
+ S_NULL, // meleestate
+ S_FPLAY_ATK1, // missilestate
+ S_NULL, // crashstate
+ S_FPLAY_DIE1, // deathstate
+ S_FPLAY_XDIE1, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 16 * FRACUNIT, // radius
+ 64 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_DROPOFF | MF_PICKUP | MF_NOTDMATCH, // flags
+ MF2_WINDTHRUST | MF2_FLOORCLIP | MF2_SLIDE | MF2_PASSMOBJ | MF2_TELESTOMP | MF2_PUSHWALL // flags2
+ },
+
+ { // MT_BLOODYSKULL
+ -1, // doomednum
+ S_BLOODYSKULL1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 4 * FRACUNIT, // radius
+ 4 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF, // flags
+ MF2_LOGRAV | MF2_CANNOTPUSH // flags2
+ },
+
+ { // MT_PLAYER_SPEED
+ -1, // doomednum
+ S_PLAYER_SPEED1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_ALTSHADOW, // flags
+ 0 // flags2
+ },
+
+ { // MT_ICECHUNK
+ -1, // doomednum
+ S_ICECHUNK1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 3 * FRACUNIT, // radius
+ 4 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF, // flags
+ MF2_LOGRAV | MF2_CANNOTPUSH | MF2_FLOORCLIP // flags2
+ },
+
+ { // MT_PLAYER_CLERIC
+ -1, // doomednum
+ S_CPLAY, // spawnstate
+ 100, // spawnhealth
+ S_CPLAY_RUN1, // seestate
+ SFX_NONE, // seesound
+ 0, // reactiontime
+ SFX_NONE, // attacksound
+ S_CPLAY_PAIN, // painstate
+ 255, // painchance
+ SFX_PLAYER_CLERIC_PAIN, // painsound
+ S_NULL, // meleestate
+ S_CPLAY_ATK1, // missilestate
+ S_NULL, // crashstate
+ S_CPLAY_DIE1, // deathstate
+ S_CPLAY_XDIE1, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 16 * FRACUNIT, // radius
+ 64 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_DROPOFF | MF_PICKUP | MF_NOTDMATCH, // flags
+ MF2_WINDTHRUST | MF2_FLOORCLIP | MF2_SLIDE | MF2_PASSMOBJ | MF2_TELESTOMP | MF2_PUSHWALL // flags2
+ },
+
+ { // MT_PLAYER_MAGE
+ -1, // doomednum
+ S_MPLAY, // spawnstate
+ 100, // spawnhealth
+ S_MPLAY_RUN1, // seestate
+ SFX_NONE, // seesound
+ 0, // reactiontime
+ SFX_NONE, // attacksound
+ S_MPLAY_PAIN, // painstate
+ 255, // painchance
+ SFX_PLAYER_MAGE_PAIN, // painsound
+ S_NULL, // meleestate
+ S_MPLAY_ATK1, // missilestate
+ S_NULL, // crashstate
+ S_MPLAY_DIE1, // deathstate
+ S_MPLAY_XDIE1, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 16 * FRACUNIT, // radius
+ 64 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_DROPOFF | MF_PICKUP | MF_NOTDMATCH, // flags
+ MF2_WINDTHRUST | MF2_FLOORCLIP | MF2_SLIDE | MF2_PASSMOBJ | MF2_TELESTOMP | MF2_PUSHWALL // flags2
+ },
+
+ { // MT_PIGPLAYER
+ -1, // doomednum
+ S_PIGPLAY, // spawnstate
+ 100, // spawnhealth
+ S_PIGPLAY_RUN1, // seestate
+ SFX_NONE, // seesound
+ 0, // reactiontime
+ SFX_NONE, // attacksound
+ S_PIGPLAY_PAIN, // painstate
+ 255, // painchance
+ SFX_PIG_PAIN, // painsound
+ S_NULL, // meleestate
+ S_PIGPLAY_ATK1, // missilestate
+ S_NULL, // crashstate
+ S_PIG_DIE1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_PIG_DEATH, // deathsound
+ 0, // speed
+ 16 * FRACUNIT, // radius
+ 24 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_DROPOFF | MF_NOTDMATCH, // flags
+ MF2_WINDTHRUST | MF2_SLIDE | MF2_PASSMOBJ | MF2_FLOORCLIP | MF2_TELESTOMP | MF2_PUSHWALL // flags2
+ },
+
+ { // MT_PIG
+ -1, // doomednum
+ S_PIG_LOOK1, // spawnstate
+ 25, // spawnhealth
+ S_PIG_WALK1, // seestate
+ SFX_PIG_ACTIVE1, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_PIG_PAIN, // painstate
+ 128, // painchance
+ SFX_PIG_PAIN, // painsound
+ S_PIG_ATK1, // meleestate
+ 0, // missilestate
+ S_NULL, // crashstate
+ S_PIG_DIE1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_PIG_DEATH, // deathsound
+ 10, // speed
+ 12 * FRACUNIT, // radius
+ 22 * FRACUNIT, // height
+ 60, // mass
+ 0, // damage
+ SFX_PIG_ACTIVE1, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags
+ MF2_WINDTHRUST | MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_PUSHWALL | MF2_TELESTOMP // flags2
+ },
+
+ { // MT_CENTAUR
+ 107, // doomednum
+ S_CENTAUR_LOOK1, // spawnstate
+ 200, // spawnhealth
+ S_CENTAUR_WALK1, // seestate
+ SFX_CENTAUR_SIGHT, // seesound
+ 8, // reactiontime
+ SFX_CENTAUR_ATTACK, // attacksound
+ S_CENTAUR_PAIN1, // painstate
+ 135, // painchance
+ SFX_CENTAUR_PAIN, // painsound
+ S_CENTAUR_ATK1, // meleestate
+ 0, // missilestate
+ S_NULL, // crashstate
+ S_CENTAUR_DEATH1, // deathstate
+ S_CENTAUR_DEATH_X1, // xdeathstate
+ SFX_CENTAUR_DEATH, // deathsound
+ 13, // speed
+ 20 * FRACUNIT, // radius
+ 64 * FRACUNIT, // height
+ 120, // mass
+ 0, // damage
+ SFX_CENTAUR_ACTIVE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags
+ MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_PUSHWALL | MF2_MCROSS | MF2_TELESTOMP // flags2
+ },
+
+ { // MT_CENTAURLEADER
+ 115, // doomednum
+ S_CENTAUR_LOOK1, // spawnstate
+ 250, // spawnhealth
+ S_CENTAUR_WALK1, // seestate
+ SFX_CENTAUR_SIGHT, // seesound
+ 8, // reactiontime
+ SFX_CENTAUR_ATTACK, // attacksound
+ S_CENTAUR_PAIN1, // painstate
+ 96, // painchance
+ SFX_CENTAUR_PAIN, // painsound
+ S_CENTAUR_ATK1, // meleestate
+ S_CENTAUR_MISSILE1, // missilestate
+ S_NULL, // crashstate
+ S_CENTAUR_DEATH1, // deathstate
+ S_CENTAUR_DEATH_X1, // xdeathstate
+ SFX_CENTAUR_DEATH, // deathsound
+ 10, // speed
+ 20 * FRACUNIT, // radius
+ 64 * FRACUNIT, // height
+ 120, // mass
+ 0, // damage
+ SFX_CENTAUR_ACTIVE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags
+ MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_PUSHWALL | MF2_MCROSS | MF2_TELESTOMP // flags2
+ },
+
+ { // MT_CENTAUR_FX
+ -1, // doomednum
+ S_CENTAUR_FX1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_CENTAUR_FX_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_CENTAUR_MISSILE_EXPLODE, // deathsound
+ 20 * FRACUNIT, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 4, // damage
+ SFX_NONE, // activesound
+ MF_MISSILE | MF_NOBLOCKMAP | MF_NOGRAVITY | MF_DROPOFF, // flags
+ MF2_NOTELEPORT | MF2_IMPACT | MF2_PCROSS // flags2
+ },
+
+ { // MT_CENTAUR_SHIELD
+ -1, // doomednum
+ S_CENTAUR_SHIELD1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_CENTAUR_SHIELD_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_DROPOFF | MF_CORPSE, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_CENTAUR_SWORD
+ -1, // doomednum
+ S_CENTAUR_SWORD1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_CENTAUR_SWORD_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_DROPOFF | MF_CORPSE, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_DEMON
+ 31, // doomednum
+ S_DEMN_LOOK1, // spawnstate
+ 250, // spawnhealth
+ S_DEMN_CHASE1, // seestate
+ SFX_DEMON_SIGHT, // seesound
+ 8, // reactiontime
+ SFX_DEMON_ATTACK, // attacksound
+ S_DEMN_PAIN1, // painstate
+ 50, // painchance
+ SFX_DEMON_PAIN, // painsound
+ S_DEMN_ATK1_1, // meleestate
+ S_DEMN_ATK2_1, // missilestate
+ S_NULL, // crashstate
+ S_DEMN_DEATH1, // deathstate
+ S_DEMN_XDEATH1, // xdeathstate
+ SFX_DEMON_DEATH, // deathsound
+ 13, // speed
+ 32 * FRACUNIT, // radius
+ 64 * FRACUNIT, // height
+ 220, // mass
+ 0, // damage
+ SFX_DEMON_ACTIVE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags
+ MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_MCROSS | MF2_TELESTOMP // flags2
+ },
+
+ { // MT_DEMONCHUNK1
+ -1, // doomednum
+ S_DEMONCHUNK1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_DEMONCHUNK1_4, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_CORPSE, // flags
+ MF2_NOTELEPORT | MF2_FLOORCLIP // flags2
+ },
+
+ { // MT_DEMONCHUNK2
+ -1, // doomednum
+ S_DEMONCHUNK2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_DEMONCHUNK2_4, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_CORPSE, // flags
+ MF2_NOTELEPORT | MF2_FLOORCLIP // flags2
+ },
+
+ { // MT_DEMONCHUNK3
+ -1, // doomednum
+ S_DEMONCHUNK3_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_DEMONCHUNK3_4, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_CORPSE, // flags
+ MF2_NOTELEPORT | MF2_FLOORCLIP // flags2
+ },
+
+ { // MT_DEMONCHUNK4
+ -1, // doomednum
+ S_DEMONCHUNK4_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_DEMONCHUNK4_4, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_CORPSE, // flags
+ MF2_NOTELEPORT | MF2_FLOORCLIP // flags2
+ },
+
+ { // MT_DEMONCHUNK5
+ -1, // doomednum
+ S_DEMONCHUNK5_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_DEMONCHUNK5_4, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_CORPSE, // flags
+ MF2_NOTELEPORT | MF2_FLOORCLIP // flags2
+ },
+
+ { // MT_DEMONFX1
+ -1, // doomednum
+ S_DEMONFX_MOVE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_DEMONFX_BOOM1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_DEMON_MISSILE_EXPLODE, // deathsound
+ 15 * FRACUNIT, // speed
+ 10 * FRACUNIT, // radius
+ 6 * FRACUNIT, // height
+ 100, // mass
+ 5, // damage
+ SFX_NONE, // activesound
+ MF_MISSILE | MF_NOBLOCKMAP | MF_NOGRAVITY | MF_DROPOFF, // flags
+ MF2_NOTELEPORT | MF2_IMPACT | MF2_PCROSS | MF2_FIREDAMAGE // flags2
+ },
+
+ { // MT_DEMON2
+ 8080, // doomednum
+ S_DEMN2_LOOK1, // spawnstate
+ 250, // spawnhealth
+ S_DEMN2_CHASE1, // seestate
+ SFX_DEMON_SIGHT, // seesound
+ 8, // reactiontime
+ SFX_DEMON_ATTACK, // attacksound
+ S_DEMN2_PAIN1, // painstate
+ 50, // painchance
+ SFX_DEMON_PAIN, // painsound
+ S_DEMN2_ATK1_1, // meleestate
+ S_DEMN2_ATK2_1, // missilestate
+ S_NULL, // crashstate
+ S_DEMN2_DEATH1, // deathstate
+ S_DEMN2_XDEATH1, // xdeathstate
+ SFX_DEMON_DEATH, // deathsound
+ 13, // speed
+ 32 * FRACUNIT, // radius
+ 64 * FRACUNIT, // height
+ 220, // mass
+ 0, // damage
+ SFX_DEMON_ACTIVE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags
+ MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_MCROSS | MF2_TELESTOMP // flags2
+ },
+
+ { // MT_DEMON2CHUNK1
+ -1, // doomednum
+ S_DEMON2CHUNK1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_DEMON2CHUNK1_4, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_CORPSE, // flags
+ MF2_NOTELEPORT | MF2_FLOORCLIP // flags2
+ },
+
+ { // MT_DEMON2CHUNK2
+ -1, // doomednum
+ S_DEMON2CHUNK2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_DEMON2CHUNK2_4, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_CORPSE, // flags
+ MF2_NOTELEPORT | MF2_FLOORCLIP // flags2
+ },
+
+ { // MT_DEMON2CHUNK3
+ -1, // doomednum
+ S_DEMON2CHUNK3_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_DEMON2CHUNK3_4, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_CORPSE, // flags
+ MF2_NOTELEPORT | MF2_FLOORCLIP // flags2
+ },
+
+ { // MT_DEMON2CHUNK4
+ -1, // doomednum
+ S_DEMON2CHUNK4_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_DEMON2CHUNK4_4, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_CORPSE, // flags
+ MF2_NOTELEPORT | MF2_FLOORCLIP // flags2
+ },
+
+ { // MT_DEMON2CHUNK5
+ -1, // doomednum
+ S_DEMON2CHUNK5_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_DEMON2CHUNK5_4, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_CORPSE, // flags
+ MF2_NOTELEPORT | MF2_FLOORCLIP // flags2
+ },
+
+ { // MT_DEMON2FX1
+ -1, // doomednum
+ S_DEMON2FX_MOVE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_DEMON2FX_BOOM1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_DEMON_MISSILE_EXPLODE, // deathsound
+ 15 * FRACUNIT, // speed
+ 10 * FRACUNIT, // radius
+ 6 * FRACUNIT, // height
+ 100, // mass
+ 5, // damage
+ SFX_NONE, // activesound
+ MF_MISSILE | MF_NOBLOCKMAP | MF_NOGRAVITY | MF_DROPOFF, // flags
+ MF2_NOTELEPORT | MF2_IMPACT | MF2_PCROSS | MF2_FIREDAMAGE // flags2
+ },
+
+ { // MT_WRAITHB
+ 10011, // doomednum
+ S_WRAITH_LOOK1, // spawnstate
+ 150, // spawnhealth
+ S_WRAITH_RAISE1, // seestate
+ SFX_WRAITH_SIGHT, // seesound
+ 8, // reactiontime
+ SFX_WRAITH_ATTACK, // attacksound
+ S_WRAITH_PAIN1, // painstate
+ 25, // painchance
+ SFX_WRAITH_PAIN, // painsound
+ S_WRAITH_ATK1_1, // meleestate
+ S_WRAITH_ATK2_1, // missilestate
+ S_NULL, // crashstate
+ S_WRAITH_DEATH1_1, // deathstate
+ S_WRAITH_DEATH2_1, // xdeathstate
+ SFX_WRAITH_DEATH, // deathsound
+ 11, // speed
+ 20 * FRACUNIT, // radius
+ 68 * FRACUNIT, // height
+ 75, // mass
+ 10, // damage
+ SFX_WRAITH_ACTIVE, // activesound
+ MF_DROPOFF | MF_NOGRAVITY | MF_FLOAT | MF_COUNTKILL, // flags
+ MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_PUSHWALL | MF2_TELESTOMP | MF2_DONTDRAW // flags2
+ },
+
+ { // MT_WRAITH
+ 34, // doomednum
+ S_WRAITH_INIT1, // spawnstate
+ 150, // spawnhealth
+ S_WRAITH_CHASE1, // seestate
+ SFX_WRAITH_SIGHT, // seesound
+ 8, // reactiontime
+ SFX_WRAITH_ATTACK, // attacksound
+ S_WRAITH_PAIN1, // painstate
+ 25, // painchance
+ SFX_WRAITH_PAIN, // painsound
+ S_WRAITH_ATK1_1, // meleestate
+ S_WRAITH_ATK2_1, // missilestate
+ S_NULL, // crashstate
+ S_WRAITH_DEATH1_1, // deathstate
+ S_WRAITH_DEATH2_1, // xdeathstate
+ SFX_WRAITH_DEATH, // deathsound
+ 11, // speed
+ 20 * FRACUNIT, // radius
+ 55 * FRACUNIT, // height
+ 75, // mass
+ 10, // damage
+ SFX_WRAITH_ACTIVE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_DROPOFF | MF_NOGRAVITY | MF_FLOAT, // flags
+ MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_PUSHWALL | MF2_TELESTOMP // flags2
+ },
+
+ { // MT_WRAITHFX1
+ -1, // doomednum
+ S_WRTHFX_MOVE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_WRTHFX_BOOM1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_WRAITH_MISSILE_EXPLODE, // deathsound
+ 14 * FRACUNIT, // speed
+ 10 * FRACUNIT, // radius
+ 6 * FRACUNIT, // height
+ 5, // mass
+ 5, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_DROPOFF | MF_MISSILE, // flags
+ MF2_NOTELEPORT | MF2_IMPACT | MF2_PCROSS | MF2_FLOORCLIP | MF2_FIREDAMAGE // flags2
+ },
+
+ { // MT_WRAITHFX2
+ -1, // doomednum
+ S_WRTHFX_SIZZLE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 2 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 5, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF, // flags
+ MF2_NOTELEPORT | MF2_FLOORCLIP // flags2
+ },
+
+ { // MT_WRAITHFX3
+ -1, // doomednum
+ S_WRTHFX_DROP1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_WRTHFX_DEAD1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_DRIP, // deathsound
+ 0, // speed
+ 2 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 5, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags
+ MF2_NOTELEPORT | MF2_FLOORCLIP // flags2
+ },
+
+ { // MT_WRAITHFX4
+ -1, // doomednum
+ S_WRTHFX_ADROP1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_WRTHFX_ADEAD1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_DRIP, // deathsound
+ 0, // speed
+ 2 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 5, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_WRAITHFX5
+ -1, // doomednum
+ S_WRTHFX_BDROP1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_WRTHFX_BDEAD1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_DRIP, // deathsound
+ 0, // speed
+ 2 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 5, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_MINOTAUR
+ 9, // doomednum
+ S_MNTR_SPAWN1, // spawnstate
+ 2500, // spawnhealth
+ S_MNTR_WALK1, // seestate
+ SFX_MAULATOR_SIGHT, // seesound
+ 8, // reactiontime
+ SFX_MAULATOR_HAMMER_SWING, // attacksound
+ S_MNTR_PAIN1, // painstate
+ 25, // painchance
+ SFX_MAULATOR_PAIN, // painsound
+ S_MNTR_ATK1_1, // meleestate
+ S_MNTR_ATK2_1, // missilestate
+ S_NULL, // crashstate
+ S_MNTR_DIE1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_MAULATOR_DEATH, // deathsound
+ 16, // speed
+ 28 * FRACUNIT, // radius
+ 100 * FRACUNIT, // height
+ 800, // mass
+ 7, // damage
+ SFX_MAULATOR_ACTIVE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_SHADOW, // flags
+ MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_PUSHWALL | MF2_TELESTOMP // flags2
+ },
+
+ { // MT_MNTRFX1
+ -1, // doomednum
+ S_MNTRFX1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_MNTRFXI1_1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 20 * FRACUNIT, // speed
+ 10 * FRACUNIT, // radius
+ 6 * FRACUNIT, // height
+ 100, // mass
+ 3, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_FIREDAMAGE // flags2
+ },
+
+ { // MT_MNTRFX2
+ -1, // doomednum
+ S_MNTRFX2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_MNTRFXI2_1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 14 * FRACUNIT, // speed
+ 5 * FRACUNIT, // radius
+ 12 * FRACUNIT, // height
+ 100, // mass
+ 4, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_FIREDAMAGE // flags2
+ },
+
+ { // MT_MNTRFX3
+ -1, // doomednum
+ S_MNTRFX3_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_MNTRFXI2_1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 4, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_FIREDAMAGE // flags2
+ },
+
+ { // MT_MNTRSMOKE
+ -1, // doomednum
+ S_MINOSMOKE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_MNTRSMOKEEXIT
+ -1, // doomednum
+ S_MINOSMOKEX1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_SERPENT
+ 121, // doomednum
+ S_SERPENT_LOOK1, // spawnstate
+ 90, // spawnhealth
+ S_SERPENT_SWIM1, // seestate
+ SFX_SERPENT_SIGHT, // seesound
+ 8, // reactiontime
+ SFX_SERPENT_ATTACK, // attacksound
+ S_SERPENT_PAIN1, // painstate
+ 96, // painchance
+ SFX_SERPENT_PAIN, // painsound
+ S_SERPENT_SURFACE1, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SERPENT_DIE1, // deathstate
+ S_SERPENT_XDIE1, // xdeathstate
+ SFX_SERPENT_DEATH, // deathsound
+ 12, // speed
+ 32 * FRACUNIT, // radius
+ 70 * FRACUNIT, // height
+ INT_MAX, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_COUNTKILL | MF_NOBLOOD, // flags
+ MF2_PASSMOBJ | MF2_DONTDRAW | MF2_CANTLEAVEFLOORPIC | MF2_NONSHOOTABLE | MF2_MCROSS // flags2
+ },
+
+ { // MT_SERPENTLEADER
+ 120, // doomednum
+ S_SERPENT_LOOK1, // spawnstate
+ 90, // spawnhealth
+ S_SERPENT_SWIM1, // seestate
+ SFX_SERPENT_SIGHT, // seesound
+ 8, // reactiontime
+ SFX_SERPENT_ATTACK, // attacksound
+ S_SERPENT_PAIN1, // painstate
+ 96, // painchance
+ SFX_SERPENT_PAIN, // painsound
+ S_SERPENT_SURFACE1, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SERPENT_DIE1, // deathstate
+ S_SERPENT_XDIE1, // xdeathstate
+ SFX_SERPENT_DEATH, // deathsound
+ 12, // speed
+ 32 * FRACUNIT, // radius
+ 70 * FRACUNIT, // height
+ 200, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_COUNTKILL | MF_NOBLOOD, // flags
+ MF2_PASSMOBJ | MF2_DONTDRAW | MF2_CANTLEAVEFLOORPIC | MF2_NONSHOOTABLE | MF2_MCROSS // flags2
+ },
+
+ { // MT_SERPENTFX
+ -1, // doomednum
+ S_SERPENT_FX1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ 0, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SERPENT_FX_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_SERPENTFX_HIT, // deathsound
+ 15 * FRACUNIT, // speed
+ 8 * FRACUNIT, // radius
+ 10 * FRACUNIT, // height
+ 100, // mass
+ 4, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_SERPENT_HEAD
+ -1, // doomednum
+ S_SERPENT_HEAD1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 10 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP, // flags
+ MF2_LOGRAV // flags2
+ },
+
+ { // MT_SERPENT_GIB1
+ -1, // doomednum
+ S_SERPENT_GIB1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 3 * FRACUNIT, // radius
+ 3 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_SERPENT_GIB2
+ -1, // doomednum
+ S_SERPENT_GIB2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 3 * FRACUNIT, // radius
+ 3 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_SERPENT_GIB3
+ -1, // doomednum
+ S_SERPENT_GIB3_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 3 * FRACUNIT, // radius
+ 3 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_BISHOP
+ 114, // doomednum
+ S_BISHOP_LOOK1, // spawnstate
+ 130, // spawnhealth
+ S_BISHOP_WALK1, // seestate
+ SFX_BISHOP_SIGHT, // seesound
+ 8, // reactiontime
+ SFX_BISHOP_ATTACK, // attacksound
+ S_BISHOP_PAIN1, // painstate
+ 110, // painchance
+ SFX_BISHOP_PAIN, // painsound
+ 0, // meleestate
+ S_BISHOP_ATK1, // missilestate
+ S_NULL, // crashstate
+ S_BISHOP_DEATH1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_BISHOP_DEATH, // deathsound
+ 10, // speed
+ 22 * FRACUNIT, // radius
+ 65 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_BISHOP_ACTIVE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_FLOAT | MF_NOGRAVITY | MF_NOBLOOD, // flags
+ MF2_PASSMOBJ | MF2_PUSHWALL | MF2_TELESTOMP // flags2
+ },
+
+ { // MT_BISHOP_PUFF
+ -1, // doomednum
+ S_BISHOP_PUFF1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SHADOW | MF_NOBLOCKMAP | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_BISHOPBLUR
+ -1, // doomednum
+ S_BISHOPBLUR1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags
+ 0 // flags2
+ },
+
+ { // MT_BISHOPPAINBLUR
+ -1, // doomednum
+ S_BISHOPPAINBLUR1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW, // flags
+ 0 // flags2
+ },
+
+ { // MT_BISH_FX
+ -1, // doomednum
+ S_BISHFX1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_BISHFXI1_1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_BISHOP_MISSILE_EXPLODE, // deathsound
+ 10 * FRACUNIT, // speed
+ 10 * FRACUNIT, // radius
+ 6 * FRACUNIT, // height
+ 100, // mass
+ 1, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_SEEKERMISSILE // flags2
+ },
+
+ { // MT_DRAGON
+ 254, // doomednum
+ S_DRAGON_LOOK1, // spawnstate
+ 640, // spawnhealth
+ S_DRAGON_INIT, // seestate
+ SFX_DRAGON_SIGHT, // seesound
+ 8, // reactiontime
+ SFX_DRAGON_ATTACK, // attacksound
+ S_DRAGON_PAIN1, // painstate
+ 128, // painchance
+ SFX_DRAGON_PAIN, // painsound
+ S_NULL, // meleestate
+ S_DRAGON_ATK1, // missilestate
+ S_NULL, // crashstate
+ S_DRAGON_DEATH1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_DRAGON_DEATH, // deathsound
+ 10 * FRACUNIT, // speed
+ 20 * FRACUNIT, // radius
+ 65 * FRACUNIT, // height
+ INT_MAX, // mass
+ 0, // damage
+ SFX_DRAGON_ACTIVE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_FLOAT | MF_NOGRAVITY | MF_NOBLOOD, // flags
+ MF2_PASSMOBJ | MF2_BOSS // flags2
+ },
+
+ { // MT_DRAGON_FX
+ -1, // doomednum
+ S_DRAGON_FX1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_DRAGON_FX1_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_DRAGON_FIREBALL_EXPLODE, // deathsound
+ 24 * FRACUNIT, // speed
+ 12 * FRACUNIT, // radius
+ 10 * FRACUNIT, // height
+ 100, // mass
+ 6, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_FIREDAMAGE // flags2
+ },
+
+ { // MT_DRAGON_FX2
+ -1, // doomednum
+ S_DRAGON_FX2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_DRAGON_FIREBALL_EXPLODE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP, // flags
+ MF2_NOTELEPORT | MF2_FIREDAMAGE | MF2_DONTDRAW // flags2
+ },
+
+ { // MT_ARMOR_1
+ 8005, // doomednum
+ S_ARMOR_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_ARMOR_2
+ 8006, // doomednum
+ S_ARMOR_2, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_ARMOR_3
+ 8007, // doomednum
+ S_ARMOR_3, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_ARMOR_4
+ 8008, // doomednum
+ S_ARMOR_4, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL | MF_NOGRAVITY, // flags
+ 0 // flags2
+ },
+
+ { // MT_MANA1
+ 122, // doomednum
+ S_MANA1_1, // spawnstate
+ 10, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_MANA2
+ 124, // doomednum
+ S_MANA2_1, // spawnstate
+ 10, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_MANA3
+ 8004, // doomednum
+ S_MANA3_1, // spawnstate
+ 20, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 8 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ MF2_FLOATBOB // flags2
+ },
+
+ { // MT_KEY1
+ 8030, // doomednum
+ S_KEY1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 20 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_KEY2
+ 8031, // doomednum
+ S_KEY2, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 20 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_KEY3
+ 8032, // doomednum
+ S_KEY3, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 20 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_KEY4
+ 8033, // doomednum
+ S_KEY4, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 20 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_KEY5
+ 8034, // doomednum
+ S_KEY5, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 20 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_KEY6
+ 8035, // doomednum
+ S_KEY6, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 20 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_KEY7
+ 8036, // doomednum
+ S_KEY7, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 20 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_KEY8
+ 8037, // doomednum
+ S_KEY8, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 20 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_KEY9
+ 8038, // doomednum
+ S_KEY9, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 20 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_KEYA
+ 8039, // doomednum
+ S_KEYA, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 20 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_KEYB
+ 8200, // doomednum
+ S_KEYB, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 8 * FRACUNIT, // radius
+ 20 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SPECIAL, // flags
+ 0 // flags2
+ },
+
+ { // MT_SOUNDWIND
+ 1410, // doomednum
+ S_SND_WIND1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOSECTOR, // flags
+ 0 // flags2
+ },
+
+ { // MT_SOUNDWATERFALL
+ 41, // doomednum
+ S_SND_WATERFALL, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOSECTOR, // flags
+ 0 // flags2
+ },
+
+ { // MT_ETTIN
+ 10030, // doomednum
+ S_ETTIN_LOOK1, // spawnstate
+ 175, // spawnhealth
+ S_ETTIN_CHASE1, // seestate
+ SFX_ETTIN_SIGHT, // seesound
+ 8, // reactiontime
+ SFX_ETTIN_ATTACK, // attacksound
+ S_ETTIN_PAIN1, // painstate
+ 60, // painchance
+ SFX_ETTIN_PAIN, // painsound
+ S_ETTIN_ATK1_1, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_ETTIN_DEATH1_1, // deathstate
+ S_ETTIN_DEATH2_1, // xdeathstate
+ SFX_ETTIN_DEATH, // deathsound
+ 13, // speed
+ 25 * FRACUNIT, // radius
+ 68 * FRACUNIT, // height
+ 175, // mass
+ 3, // damage
+ SFX_ETTIN_ACTIVE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags
+ MF2_FLOORCLIP | MF2_PUSHWALL | MF2_MCROSS | MF2_TELESTOMP // flags2
+ },
+
+ { // MT_ETTIN_MACE
+ -1, // doomednum
+ S_ETTIN_MACE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_ETTIN_MACE5, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_DROPOFF | MF_CORPSE, // flags
+ MF2_NOTELEPORT | MF2_FLOORCLIP // flags2
+ },
+
+ { // MT_FIREDEMON
+ 10060, // doomednum
+ S_FIRED_SPAWN1, // spawnstate
+ 80, // spawnhealth
+ S_FIRED_LOOK4, // seestate
+ SFX_FIRED_SPAWN, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_FIRED_PAIN1, // painstate
+ 1, // painchance
+ SFX_FIRED_PAIN, // painsound
+ S_NULL, // meleestate
+ S_FIRED_ATTACK1, // missilestate
+ S_FIRED_XDEATH1, // crashstate
+ S_FIRED_DEATH1, // deathstate
+ S_FIRED_XDEATH1, // xdeathstate
+ SFX_FIRED_DEATH, // deathsound
+ 13, // speed
+ 20 * FRACUNIT, // radius
+ 68 * FRACUNIT, // height
+ 75, // mass
+ 1, // damage
+ SFX_FIRED_ACTIVE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_DROPOFF | MF_NOGRAVITY | MF_FLOAT, // flags
+ MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_PUSHWALL | MF2_INVULNERABLE | MF2_MCROSS | MF2_TELESTOMP // flags2
+ },
+
+ { // MT_FIREDEMON_SPLOTCH1
+ -1, // doomednum
+ S_FIRED_CORPSE1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 3 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_DROPOFF | MF_CORPSE, // flags
+ MF2_NOTELEPORT | MF2_FLOORCLIP // flags2
+ },
+
+ { // MT_FIREDEMON_SPLOTCH2
+ -1, // doomednum
+ S_FIRED_CORPSE4, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 3 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_DROPOFF | MF_CORPSE, // flags
+ MF2_NOTELEPORT | MF2_FLOORCLIP // flags2
+ },
+
+ { // MT_FIREDEMON_FX1
+ -1, // doomednum
+ S_FIRED_RDROP1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_FIRED_RDEAD1_1, // deathstate
+ S_FIRED_RDEAD1_2, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 3 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 16, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_FIREDEMON_FX2
+ -1, // doomednum
+ S_FIRED_RDROP2, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_FIRED_RDEAD2_1, // deathstate
+ S_FIRED_RDEAD2_2, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 3 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 16, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_FIREDEMON_FX3
+ -1, // doomednum
+ S_FIRED_RDROP3, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_FIRED_RDEAD3_1, // deathstate
+ S_FIRED_RDEAD3_2, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 3 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 16, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_FIREDEMON_FX4
+ -1, // doomednum
+ S_FIRED_RDROP4, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_FIRED_RDEAD4_1, // deathstate
+ S_FIRED_RDEAD4_2, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 3 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 16, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_FIREDEMON_FX5
+ -1, // doomednum
+ S_FIRED_RDROP5, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_FIRED_RDEAD5_1, // deathstate
+ S_FIRED_RDEAD5_2, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 3 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 16, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_FIREDEMON_FX6
+ -1, // doomednum
+ S_FIRED_FX6_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_FIRED_FX6_2, // deathstate
+ S_NULL, // xdeathstate
+ SFX_FIRED_MISSILE_HIT, // deathsound
+ 10 * FRACUNIT, // speed
+ 10 * FRACUNIT, // radius
+ 6 * FRACUNIT, // height
+ 15, // mass
+ 1, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_DROPOFF | MF_MISSILE, // flags
+ MF2_NOTELEPORT | MF2_IMPACT | MF2_PCROSS | MF2_FLOORCLIP | MF2_FIREDAMAGE // flags2
+ },
+
+ { // MT_ICEGUY
+ 8020, // doomednum
+ S_ICEGUY_LOOK, // spawnstate
+ 120, // spawnhealth
+ S_ICEGUY_WALK1, // seestate
+ SFX_ICEGUY_SIGHT, // seesound
+ 8, // reactiontime
+ SFX_ICEGUY_ATTACK, // attacksound
+ S_ICEGUY_PAIN1, // painstate
+ 144, // painchance
+ SFX_NONE, // painsound
+ 0, // meleestate
+ S_ICEGUY_ATK1, // missilestate
+ S_NULL, // crashstate
+ S_ICEGUY_DEATH, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 14, // speed
+ 22 * FRACUNIT, // radius
+ 75 * FRACUNIT, // height
+ 150, // mass
+ 0, // damage
+ SFX_ICEGUY_ACTIVE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_NOBLOOD, // flags
+ MF2_PASSMOBJ | MF2_PUSHWALL | MF2_ICEDAMAGE | MF2_MCROSS | MF2_TELESTOMP // flags2
+ },
+
+ { // MT_ICEGUY_FX
+ -1, // doomednum
+ S_ICEGUY_FX1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_ICEGUY_FX_X1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_ICEGUY_FX_EXPLODE, // deathsound
+ 14 * FRACUNIT, // speed
+ 8 * FRACUNIT, // radius
+ 10 * FRACUNIT, // height
+ 100, // mass
+ 1, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT | MF2_ICEDAMAGE // flags2
+ },
+
+ { // MT_ICEFX_PUFF
+ -1, // doomednum
+ S_ICEFX_PUFF1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ FRACUNIT, // radius
+ FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_SHADOW | MF_DROPOFF, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_ICEGUY_FX2
+ -1, // doomednum
+ S_ICEGUY_FX2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 10 * FRACUNIT, // speed
+ 4 * FRACUNIT, // radius
+ 4 * FRACUNIT, // height
+ 100, // mass
+ 1, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_MISSILE, // flags
+ MF2_NOTELEPORT | MF2_LOGRAV | MF2_ICEDAMAGE // flags2
+ },
+
+ { // MT_ICEGUY_BIT
+ -1, // doomednum
+ S_ICEGUY_BIT1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ FRACUNIT, // radius
+ FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF, // flags
+ MF2_NOTELEPORT | MF2_LOGRAV // flags2
+ },
+
+ { // MT_ICEGUY_WISP1
+ -1, // doomednum
+ S_ICEGUY_WISP1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_NOGRAVITY | MF_ALTSHADOW | MF_MISSILE, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_ICEGUY_WISP2
+ -1, // doomednum
+ S_ICEGUY_WISP2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_NOGRAVITY | MF_ALTSHADOW | MF_MISSILE, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_FIGHTER_BOSS
+ 10100, // doomednum
+ S_FIGHTER, // spawnstate
+ 800, // spawnhealth
+ S_FIGHTER_RUN1, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_FIGHTER_PAIN, // painstate
+ 50, // painchance
+ SFX_PLAYER_FIGHTER_PAIN, // painsound
+ S_FIGHTER_ATK1, // meleestate
+ S_FIGHTER_ATK1, // missilestate
+ S_NULL, // crashstate
+ S_FIGHTER_DIE1, // deathstate
+ S_FIGHTER_XDIE1, // xdeathstate
+ SFX_PLAYER_FIGHTER_CRAZY_DEATH, // deathsound
+ 25, // speed
+ 16 * FRACUNIT, // radius
+ 64 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags
+ MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_TELESTOMP | MF2_PUSHWALL | MF2_MCROSS // flags2
+ },
+
+ { // MT_CLERIC_BOSS
+ 10101, // doomednum
+ S_CLERIC, // spawnstate
+ 800, // spawnhealth
+ S_CLERIC_RUN1, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_CLERIC_PAIN, // painstate
+ 50, // painchance
+ SFX_PLAYER_CLERIC_PAIN, // painsound
+ S_CLERIC_ATK1, // meleestate
+ S_CLERIC_ATK1, // missilestate
+ S_NULL, // crashstate
+ S_CLERIC_DIE1, // deathstate
+ S_CLERIC_XDIE1, // xdeathstate
+ SFX_PLAYER_CLERIC_CRAZY_DEATH, // deathsound
+ 25, // speed
+ 16 * FRACUNIT, // radius
+ 64 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags
+ MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_TELESTOMP | MF2_PUSHWALL | MF2_MCROSS // flags2
+ },
+
+ { // MT_MAGE_BOSS
+ 10102, // doomednum
+ S_MAGE, // spawnstate
+ 800, // spawnhealth
+ S_MAGE_RUN1, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_MAGE_PAIN, // painstate
+ 50, // painchance
+ SFX_PLAYER_MAGE_PAIN, // painsound
+ S_MAGE_ATK1, // meleestate
+ S_MAGE_ATK1, // missilestate
+ S_NULL, // crashstate
+ S_MAGE_DIE1, // deathstate
+ S_MAGE_XDIE1, // xdeathstate
+ SFX_PLAYER_MAGE_CRAZY_DEATH, // deathsound
+ 25, // speed
+ 16 * FRACUNIT, // radius
+ 64 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags
+ MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_TELESTOMP | MF2_PUSHWALL | MF2_MCROSS // flags2
+ },
+
+ { // MT_SORCBOSS
+ 10080, // doomednum
+ S_SORC_SPAWN1, // spawnstate
+ 5000, // spawnhealth
+ S_SORC_WALK1, // seestate
+ SFX_SORCERER_SIGHT, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_SORC_PAIN1, // painstate
+ 10, // painchance
+ SFX_SORCERER_PAIN, // painsound
+ S_NULL, // meleestate
+ S_SORC_ATK2_1, // missilestate
+ S_NULL, // crashstate
+ S_SORC_DIE1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_SORCERER_DEATHSCREAM, // deathsound
+ 16, // speed
+ 40 * FRACUNIT, // radius
+ 110 * FRACUNIT, // height
+ 500, // mass
+ 9, // damage
+ SFX_SORCERER_ACTIVE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_NOBLOOD, // flags
+ MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_PUSHWALL | MF2_BOSS | MF2_MCROSS // flags2
+ },
+
+ { // MT_SORCBALL1
+ -1, // doomednum
+ S_SORCBALL1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_SORCERER_BALLBOUNCE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_SORCBALL1_D1, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SORCBALL1_D5, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 10 * FRACUNIT, // speed
+ 5 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_MISSILE, // flags
+ MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2
+ },
+
+ { // MT_SORCBALL2
+ -1, // doomednum
+ S_SORCBALL2_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_SORCERER_BALLBOUNCE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_SORCBALL2_D1, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SORCBALL2_D5, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 10 * FRACUNIT, // speed
+ 5 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_MISSILE, // flags
+ MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2
+ },
+
+ { // MT_SORCBALL3
+ -1, // doomednum
+ S_SORCBALL3_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_SORCERER_BALLBOUNCE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_SORCBALL3_D1, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SORCBALL3_D5, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 10 * FRACUNIT, // speed
+ 5 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_MISSILE, // flags
+ MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2
+ },
+
+ { // MT_SORCFX1
+ -1, // doomednum
+ S_SORCFX1_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_SORCERER_BALLBOUNCE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SORCFX1_D1, // deathstate
+ S_SORCFX1_D1, // xdeathstate
+ SFX_NONE, // deathsound
+ 7 * FRACUNIT, // speed
+ 5 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE, // flags
+ MF2_NOTELEPORT | MF2_FLOORBOUNCE // flags2
+ },
+
+ { // MT_SORCFX2
+ -1, // doomednum
+ S_SORCFX2_SPLIT1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SORCFX2T1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 15 * FRACUNIT, // speed
+ 5 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_SORCFX2_T1
+ -1, // doomednum
+ S_SORCFX2T1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_ALTSHADOW, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_SORCFX3
+ -1, // doomednum
+ S_SORCFX3_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_SORCERER_BISHOPSPAWN, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_BISHMORPH1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 15 * FRACUNIT, // speed
+ 22 * FRACUNIT, // radius
+ 65 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_SORCFX3_EXPLOSION
+ -1, // doomednum
+ S_SORCFX3_EXP1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_ALTSHADOW, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_SORCFX4
+ -1, // doomednum
+ S_SORCFX4_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_SORCFX4_D1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_SORCERER_BALLEXPLODE, // deathsound
+ 12 * FRACUNIT, // speed
+ 10 * FRACUNIT, // radius
+ 10 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_SORCSPARK1
+ -1, // doomednum
+ S_SORCSPARK1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 5 * FRACUNIT, // radius
+ 5 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF, // flags
+ MF2_NOTELEPORT | MF2_LOGRAV // flags2
+ },
+
+ { // MT_BLASTEFFECT
+ -1, // doomednum
+ S_BLASTEFFECT1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_NOCLIP | MF_ALTSHADOW, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_WATER_DRIP
+ -1, // doomednum
+ S_WATERDRIP1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_DRIP, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 1, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_MISSILE, // flags
+ MF2_LOGRAV | MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_KORAX
+ 10200, // doomednum
+ S_KORAX_LOOK1, // spawnstate
+ 5000, // spawnhealth
+ S_KORAX_CHASE2, // seestate
+ SFX_KORAX_SIGHT, // seesound
+ 8, // reactiontime
+ SFX_KORAX_ATTACK, // attacksound
+ S_KORAX_PAIN1, // painstate
+ 20, // painchance
+ SFX_KORAX_PAIN, // painsound
+ S_NULL, // meleestate
+ S_KORAX_ATTACK1, // missilestate
+ S_NULL, // crashstate
+ S_KORAX_DEATH1, // deathstate
+ S_NULL, // xdeathstate
+ SFX_KORAX_DEATH, // deathsound
+ 10, // speed
+ 65 * FRACUNIT, // radius
+ 115 * FRACUNIT, // height
+ 2000, // mass
+ 15, // damage
+ SFX_KORAX_ACTIVE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL, // flags
+ MF2_FLOORCLIP | MF2_PUSHWALL | MF2_MCROSS | MF2_TELESTOMP | MF2_BOSS // flags2
+ },
+
+ { // MT_KORAX_SPIRIT1
+ -1, // doomednum
+ S_KSPIRIT_ROAM1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 8 * FRACUNIT, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_NOGRAVITY | MF_ALTSHADOW | MF_MISSILE | MF_NOCLIP, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_KORAX_SPIRIT2
+ -1, // doomednum
+ S_KSPIRIT_ROAM1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 8 * FRACUNIT, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_NOGRAVITY | MF_ALTSHADOW | MF_MISSILE | MF_NOCLIP, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_KORAX_SPIRIT3
+ -1, // doomednum
+ S_KSPIRIT_ROAM1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 8 * FRACUNIT, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_NOGRAVITY | MF_ALTSHADOW | MF_MISSILE | MF_NOCLIP, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_KORAX_SPIRIT4
+ -1, // doomednum
+ S_KSPIRIT_ROAM1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 8 * FRACUNIT, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_NOGRAVITY | MF_ALTSHADOW | MF_MISSILE | MF_NOCLIP, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_KORAX_SPIRIT5
+ -1, // doomednum
+ S_KSPIRIT_ROAM1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 8 * FRACUNIT, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_NOGRAVITY | MF_ALTSHADOW | MF_MISSILE | MF_NOCLIP, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_KORAX_SPIRIT6
+ -1, // doomednum
+ S_KSPIRIT_ROAM1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 8 * FRACUNIT, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_DROPOFF | MF_NOGRAVITY | MF_ALTSHADOW | MF_MISSILE | MF_NOCLIP, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_DEMON_MASH
+ -1, // doomednum
+ S_DEMN_LOOK1, // spawnstate
+ 250, // spawnhealth
+ S_DEMN_CHASE1, // seestate
+ SFX_DEMON_SIGHT, // seesound
+ 8, // reactiontime
+ SFX_DEMON_ATTACK, // attacksound
+ S_DEMN_PAIN1, // painstate
+ 50, // painchance
+ SFX_DEMON_PAIN, // painsound
+ S_DEMN_ATK1_1, // meleestate
+ S_DEMN_ATK2_1, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_DEMON_DEATH, // deathsound
+ 13, // speed
+ 32 * FRACUNIT, // radius
+ 64 * FRACUNIT, // height
+ 220, // mass
+ 0, // damage
+ SFX_DEMON_ACTIVE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_ALTSHADOW | MF_NOBLOOD, // flags
+ MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_MCROSS | MF2_PUSHWALL | MF2_BLASTED // flags2
+ },
+
+ { // MT_DEMON2_MASH
+ -1, // doomednum
+ S_DEMN2_LOOK1, // spawnstate
+ 250, // spawnhealth
+ S_DEMN2_CHASE1, // seestate
+ SFX_DEMON_SIGHT, // seesound
+ 8, // reactiontime
+ SFX_DEMON_ATTACK, // attacksound
+ S_DEMN2_PAIN1, // painstate
+ 50, // painchance
+ SFX_DEMON_PAIN, // painsound
+ S_DEMN2_ATK1_1, // meleestate
+ S_DEMN2_ATK2_1, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_DEMON_DEATH, // deathsound
+ 13, // speed
+ 32 * FRACUNIT, // radius
+ 64 * FRACUNIT, // height
+ 220, // mass
+ 0, // damage
+ SFX_DEMON_ACTIVE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_ALTSHADOW | MF_NOBLOOD, // flags
+ MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_MCROSS | MF2_PUSHWALL | MF2_BLASTED // flags2
+ },
+
+ { // MT_ETTIN_MASH
+ -1, // doomednum
+ S_ETTIN_LOOK1, // spawnstate
+ 175, // spawnhealth
+ S_ETTIN_CHASE1, // seestate
+ SFX_ETTIN_SIGHT, // seesound
+ 8, // reactiontime
+ SFX_ETTIN_ATTACK, // attacksound
+ S_ETTIN_PAIN1, // painstate
+ 60, // painchance
+ SFX_ETTIN_PAIN, // painsound
+ S_ETTIN_ATK1_1, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_ETTIN_DEATH, // deathsound
+ 13, // speed
+ 25 * FRACUNIT, // radius
+ 68 * FRACUNIT, // height
+ 175, // mass
+ 3, // damage
+ SFX_ETTIN_ACTIVE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_ALTSHADOW | MF_NOBLOOD, // flags
+ MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_MCROSS | MF2_PUSHWALL | MF2_BLASTED // flags2
+ },
+
+ { // MT_CENTAUR_MASH
+ -1, // doomednum
+ S_CENTAUR_LOOK1, // spawnstate
+ 200, // spawnhealth
+ S_CENTAUR_WALK1, // seestate
+ SFX_CENTAUR_SIGHT, // seesound
+ 8, // reactiontime
+ SFX_CENTAUR_ATTACK, // attacksound
+ S_CENTAUR_PAIN1, // painstate
+ 135, // painchance
+ SFX_CENTAUR_PAIN, // painsound
+ S_CENTAUR_ATK1, // meleestate
+ 0, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_CENTAUR_DEATH, // deathsound
+ 13, // speed
+ 20 * FRACUNIT, // radius
+ 64 * FRACUNIT, // height
+ 120, // mass
+ 0, // damage
+ SFX_CENTAUR_ACTIVE, // activesound
+ MF_SOLID | MF_SHOOTABLE | MF_COUNTKILL | MF_ALTSHADOW | MF_NOBLOOD, // flags
+ MF2_FLOORCLIP | MF2_PASSMOBJ | MF2_MCROSS | MF2_PUSHWALL | MF2_BLASTED // flags2
+ },
+
+ { // MT_KORAX_BOLT
+ -1, // doomednum
+ S_KBOLT1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 15 * FRACUNIT, // radius
+ 35 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_MISSILE | MF_DROPOFF, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
+ { // MT_BAT_SPAWNER
+ 10225, // doomednum
+ S_SPAWNBATS1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_NULL, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 0, // speed
+ 20 * FRACUNIT, // radius
+ 16 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOSECTOR | MF_NOGRAVITY, // flags
+ MF2_DONTDRAW // flags2
+ },
+
+ { // MT_BAT
+ -1, // doomednum
+ S_BAT1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ SFX_NONE, // seesound
+ 8, // reactiontime
+ SFX_NONE, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ SFX_NONE, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_BAT_DEATH, // deathstate
+ S_NULL, // xdeathstate
+ SFX_NONE, // deathsound
+ 5 * FRACUNIT, // speed
+ 3 * FRACUNIT, // radius
+ 3 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ SFX_NONE, // activesound
+ MF_NOBLOCKMAP | MF_NOGRAVITY | MF_MISSILE, // flags
+ MF2_PASSMOBJ | MF2_NOTELEPORT // flags2
+ }
+};
diff --git a/src/hexen/info.h b/src/hexen/info.h
new file mode 100644
index 00000000..6ad2975e
--- /dev/null
+++ b/src/hexen/info.h
@@ -0,0 +1,3628 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+// generated by stateco
+
+typedef enum
+{
+ SPR_MAN1,
+ SPR_ACLO,
+ SPR_TLGL,
+ SPR_FBL1,
+ SPR_XPL1,
+ SPR_ARRW,
+ SPR_DART,
+ SPR_RIPP,
+ SPR_CFCF,
+ SPR_BLAD,
+ SPR_SHRD,
+ SPR_FFSM,
+ SPR_FFLG,
+ SPR_PTN1,
+ SPR_PTN2,
+ SPR_SOAR,
+ SPR_INVU,
+ SPR_SUMN,
+ SPR_TSPK,
+ SPR_TELO,
+ SPR_TRNG,
+ SPR_ROCK,
+ SPR_FOGS,
+ SPR_FOGM,
+ SPR_FOGL,
+ SPR_SGSA,
+ SPR_SGSB,
+ SPR_PORK,
+ SPR_EGGM,
+ SPR_FHFX,
+ SPR_SPHL,
+ SPR_STWN,
+ SPR_GMPD,
+ SPR_ASKU,
+ SPR_ABGM,
+ SPR_AGMR,
+ SPR_AGMG,
+ SPR_AGG2,
+ SPR_AGMB,
+ SPR_AGB2,
+ SPR_ABK1,
+ SPR_ABK2,
+ SPR_ASK2,
+ SPR_AFWP,
+ SPR_ACWP,
+ SPR_AMWP,
+ SPR_AGER,
+ SPR_AGR2,
+ SPR_AGR3,
+ SPR_AGR4,
+ SPR_TRCH,
+ SPR_PSBG,
+ SPR_ATLP,
+ SPR_THRW,
+ SPR_SPED,
+ SPR_BMAN,
+ SPR_BRAC,
+ SPR_BLST,
+ SPR_HRAD,
+ SPR_SPSH,
+ SPR_LVAS,
+ SPR_SLDG,
+ SPR_STTW,
+ SPR_RCK1,
+ SPR_RCK2,
+ SPR_RCK3,
+ SPR_RCK4,
+ SPR_CDLR,
+ SPR_TRE1,
+ SPR_TRDT,
+ SPR_TRE2,
+ SPR_TRE3,
+ SPR_STM1,
+ SPR_STM2,
+ SPR_STM3,
+ SPR_STM4,
+ SPR_MSH1,
+ SPR_MSH2,
+ SPR_MSH3,
+ SPR_MSH4,
+ SPR_MSH5,
+ SPR_MSH6,
+ SPR_MSH7,
+ SPR_MSH8,
+ SPR_SGMP,
+ SPR_SGM1,
+ SPR_SGM2,
+ SPR_SGM3,
+ SPR_SLC1,
+ SPR_SLC2,
+ SPR_SLC3,
+ SPR_MSS1,
+ SPR_MSS2,
+ SPR_SWMV,
+ SPR_CPS1,
+ SPR_CPS2,
+ SPR_TMS1,
+ SPR_TMS2,
+ SPR_TMS3,
+ SPR_TMS4,
+ SPR_TMS5,
+ SPR_TMS6,
+ SPR_TMS7,
+ SPR_CPS3,
+ SPR_STT2,
+ SPR_STT3,
+ SPR_STT4,
+ SPR_STT5,
+ SPR_GAR1,
+ SPR_GAR2,
+ SPR_GAR3,
+ SPR_GAR4,
+ SPR_GAR5,
+ SPR_GAR6,
+ SPR_GAR7,
+ SPR_GAR8,
+ SPR_GAR9,
+ SPR_BNR1,
+ SPR_TRE4,
+ SPR_TRE5,
+ SPR_TRE6,
+ SPR_TRE7,
+ SPR_LOGG,
+ SPR_ICT1,
+ SPR_ICT2,
+ SPR_ICT3,
+ SPR_ICT4,
+ SPR_ICM1,
+ SPR_ICM2,
+ SPR_ICM3,
+ SPR_ICM4,
+ SPR_RKBL,
+ SPR_RKBS,
+ SPR_RKBK,
+ SPR_RBL1,
+ SPR_RBL2,
+ SPR_RBL3,
+ SPR_VASE,
+ SPR_POT1,
+ SPR_POT2,
+ SPR_POT3,
+ SPR_PBIT,
+ SPR_CPS4,
+ SPR_CPS5,
+ SPR_CPS6,
+ SPR_CPB1,
+ SPR_CPB2,
+ SPR_CPB3,
+ SPR_CPB4,
+ SPR_BDRP,
+ SPR_BDSH,
+ SPR_BDPL,
+ SPR_CNDL,
+ SPR_LEF1,
+ SPR_LEF3,
+ SPR_LEF2,
+ SPR_TWTR,
+ SPR_WLTR,
+ SPR_BARL,
+ SPR_SHB1,
+ SPR_SHB2,
+ SPR_BCKT,
+ SPR_SHRM,
+ SPR_FBUL,
+ SPR_FSKL,
+ SPR_BRTR,
+ SPR_SUIT,
+ SPR_BBLL,
+ SPR_CAND,
+ SPR_IRON,
+ SPR_XMAS,
+ SPR_CDRN,
+ SPR_CHNS,
+ SPR_TST1,
+ SPR_TST2,
+ SPR_TST3,
+ SPR_TST4,
+ SPR_TST5,
+ SPR_TST6,
+ SPR_TST7,
+ SPR_TST8,
+ SPR_TST9,
+ SPR_TST0,
+ SPR_TELE,
+ SPR_TSMK,
+ SPR_FPCH,
+ SPR_WFAX,
+ SPR_FAXE,
+ SPR_WFHM,
+ SPR_FHMR,
+ SPR_FSRD,
+ SPR_FSFX,
+ SPR_CMCE,
+ SPR_WCSS,
+ SPR_CSSF,
+ SPR_WCFM,
+ SPR_CFLM,
+ SPR_CFFX,
+ SPR_CHLY,
+ SPR_SPIR,
+ SPR_MWND,
+ SPR_WMLG,
+ SPR_MLNG,
+ SPR_MLFX,
+ SPR_MLF2,
+ SPR_MSTF,
+ SPR_MSP1,
+ SPR_MSP2,
+ SPR_WFR1,
+ SPR_WFR2,
+ SPR_WFR3,
+ SPR_WCH1,
+ SPR_WCH2,
+ SPR_WCH3,
+ SPR_WMS1,
+ SPR_WMS2,
+ SPR_WMS3,
+ SPR_WPIG,
+ SPR_WMCS,
+ SPR_CONE,
+ SPR_SHEX,
+ SPR_BLOD,
+ SPR_GIBS,
+ SPR_PLAY,
+ SPR_FDTH,
+ SPR_BSKL,
+ SPR_ICEC,
+ SPR_CLER,
+ SPR_MAGE,
+ SPR_PIGY,
+ SPR_CENT,
+ SPR_CTXD,
+ SPR_CTFX,
+ SPR_CTDP,
+ SPR_DEMN,
+ SPR_DEMA,
+ SPR_DEMB,
+ SPR_DEMC,
+ SPR_DEMD,
+ SPR_DEME,
+ SPR_DMFX,
+ SPR_DEM2,
+ SPR_DMBA,
+ SPR_DMBB,
+ SPR_DMBC,
+ SPR_DMBD,
+ SPR_DMBE,
+ SPR_D2FX,
+ SPR_WRTH,
+ SPR_WRT2,
+ SPR_WRBL,
+ SPR_MNTR,
+ SPR_FX12,
+ SPR_FX13,
+ SPR_MNSM,
+ SPR_SSPT,
+ SPR_SSDV,
+ SPR_SSXD,
+ SPR_SSFX,
+ SPR_BISH,
+ SPR_BPFX,
+ SPR_DRAG,
+ SPR_DRFX,
+ SPR_ARM1,
+ SPR_ARM2,
+ SPR_ARM3,
+ SPR_ARM4,
+ SPR_MAN2,
+ SPR_MAN3,
+ SPR_KEY1,
+ SPR_KEY2,
+ SPR_KEY3,
+ SPR_KEY4,
+ SPR_KEY5,
+ SPR_KEY6,
+ SPR_KEY7,
+ SPR_KEY8,
+ SPR_KEY9,
+ SPR_KEYA,
+ SPR_KEYB,
+ SPR_ETTN,
+ SPR_ETTB,
+ SPR_FDMN,
+ SPR_FDMB,
+ SPR_ICEY,
+ SPR_ICPR,
+ SPR_ICWS,
+ SPR_SORC,
+ SPR_SBMP,
+ SPR_SBS4,
+ SPR_SBMB,
+ SPR_SBS3,
+ SPR_SBMG,
+ SPR_SBS1,
+ SPR_SBS2,
+ SPR_SBFX,
+ SPR_RADE,
+ SPR_WATR,
+ SPR_KORX,
+ SPR_ABAT,
+ NUMSPRITES
+} spritenum_t;
+
+typedef enum
+{
+ S_NULL,
+ S_FREETARGMOBJ,
+ S_MAPSPOT,
+ S_FIREBALL1_1,
+ S_FIREBALL1_2,
+ S_FIREBALL1_X1,
+ S_FIREBALL1_X2,
+ S_FIREBALL1_X3,
+ S_FIREBALL1_X4,
+ S_FIREBALL1_X5,
+ S_FIREBALL1_X6,
+ S_ARROW_1,
+ S_ARROW_X1,
+ S_DART_1,
+ S_DART_X1,
+ S_POISONDART_1,
+ S_POISONDART_X1,
+ S_RIPPERBALL_1,
+ S_RIPPERBALL_2,
+ S_RIPPERBALL_3,
+ S_RIPPERBALL_X1,
+ S_RIPPERBALL_X2,
+ S_RIPPERBALL_X3,
+ S_RIPPERBALL_X4,
+ S_RIPPERBALL_X5,
+ S_RIPPERBALL_X6,
+ S_RIPPERBALL_X7,
+ S_RIPPERBALL_X8,
+ S_RIPPERBALL_X9,
+ S_RIPPERBALL_X10,
+ S_PRJ_BLADE1,
+ S_PRJ_BLADE_X1,
+ S_ICESHARD1,
+ S_ICESHARD2,
+ S_ICESHARD3,
+ S_FLAME_TSMALL1,
+ S_FLAME_TSMALL2,
+ S_FLAME_TSMALL3,
+ S_FLAME_TSMALL4,
+ S_FLAME_TSMALL5,
+ S_FLAME_TSMALL6,
+ S_FLAME_TLARGE1,
+ S_FLAME_TLARGE2,
+ S_FLAME_TLARGE3,
+ S_FLAME_TLARGE4,
+ S_FLAME_TLARGE5,
+ S_FLAME_TLARGE6,
+ S_FLAME_TLARGE7,
+ S_FLAME_TLARGE8,
+ S_FLAME_TLARGE9,
+ S_FLAME_TLARGE10,
+ S_FLAME_TLARGE11,
+ S_FLAME_TLARGE12,
+ S_FLAME_TLARGE13,
+ S_FLAME_TLARGE14,
+ S_FLAME_TLARGE15,
+ S_FLAME_TLARGE16,
+ S_FLAME_SDORM1,
+ S_FLAME_SDORM2,
+ S_FLAME_SDORM3,
+ S_FLAME_SMALL1,
+ S_FLAME_SMALL2,
+ S_FLAME_SMALL3,
+ S_FLAME_SMALL4,
+ S_FLAME_SMALL5,
+ S_FLAME_SMALL6,
+ S_FLAME_SMALL7,
+ S_FLAME_LDORM1,
+ S_FLAME_LDORM2,
+ S_FLAME_LDORM3,
+ S_FLAME_LDORM4,
+ S_FLAME_LDORM5,
+ S_FLAME_LARGE1,
+ S_FLAME_LARGE2,
+ S_FLAME_LARGE3,
+ S_FLAME_LARGE4,
+ S_FLAME_LARGE5,
+ S_FLAME_LARGE6,
+ S_FLAME_LARGE7,
+ S_FLAME_LARGE8,
+ S_FLAME_LARGE9,
+ S_FLAME_LARGE10,
+ S_FLAME_LARGE11,
+ S_FLAME_LARGE12,
+ S_FLAME_LARGE13,
+ S_FLAME_LARGE14,
+ S_FLAME_LARGE15,
+ S_FLAME_LARGE16,
+ S_FLAME_LARGE17,
+ S_FLAME_LARGE18,
+ S_ITEM_PTN1_1,
+ S_ITEM_PTN1_2,
+ S_ITEM_PTN1_3,
+ S_HIDESPECIAL1,
+ S_HIDESPECIAL2,
+ S_HIDESPECIAL3,
+ S_HIDESPECIAL4,
+ S_HIDESPECIAL5,
+ S_HIDESPECIAL6,
+ S_HIDESPECIAL7,
+ S_HIDESPECIAL8,
+ S_HIDESPECIAL9,
+ S_HIDESPECIAL10,
+ S_HIDESPECIAL11,
+ S_DORMANTARTI1_1,
+ S_DORMANTARTI1_2,
+ S_DORMANTARTI1_3,
+ S_DORMANTARTI1_4,
+ S_DORMANTARTI1_5,
+ S_DORMANTARTI1_6,
+ S_DORMANTARTI1_7,
+ S_DORMANTARTI1_8,
+ S_DORMANTARTI1_9,
+ S_DORMANTARTI1_10,
+ S_DORMANTARTI1_11,
+ S_DORMANTARTI1_12,
+ S_DORMANTARTI1_13,
+ S_DORMANTARTI1_14,
+ S_DORMANTARTI1_15,
+ S_DORMANTARTI1_16,
+ S_DORMANTARTI1_17,
+ S_DORMANTARTI1_18,
+ S_DORMANTARTI1_19,
+ S_DORMANTARTI1_20,
+ S_DORMANTARTI1_21,
+ S_DORMANTARTI2_1,
+ S_DORMANTARTI2_2,
+ S_DORMANTARTI2_3,
+ S_DORMANTARTI2_4,
+ S_DORMANTARTI2_5,
+ S_DORMANTARTI2_6,
+ S_DORMANTARTI2_7,
+ S_DORMANTARTI2_8,
+ S_DORMANTARTI2_9,
+ S_DORMANTARTI2_10,
+ S_DORMANTARTI2_11,
+ S_DORMANTARTI2_12,
+ S_DORMANTARTI2_13,
+ S_DORMANTARTI2_14,
+ S_DORMANTARTI2_15,
+ S_DORMANTARTI2_16,
+ S_DORMANTARTI2_17,
+ S_DORMANTARTI2_18,
+ S_DORMANTARTI2_19,
+ S_DORMANTARTI2_20,
+ S_DORMANTARTI2_21,
+ S_DORMANTARTI3_1,
+ S_DORMANTARTI3_2,
+ S_DORMANTARTI3_3,
+ S_DORMANTARTI3_4,
+ S_DORMANTARTI3_5,
+ S_DORMANTARTI3_6,
+ S_DORMANTARTI3_7,
+ S_DORMANTARTI3_8,
+ S_DORMANTARTI3_9,
+ S_DORMANTARTI3_10,
+ S_DORMANTARTI3_11,
+ S_DORMANTARTI3_12,
+ S_DORMANTARTI3_13,
+ S_DORMANTARTI3_14,
+ S_DORMANTARTI3_15,
+ S_DORMANTARTI3_16,
+ S_DORMANTARTI3_17,
+ S_DORMANTARTI3_18,
+ S_DORMANTARTI3_19,
+ S_DORMANTARTI3_20,
+ S_DORMANTARTI3_21,
+ S_DEADARTI1,
+ S_DEADARTI2,
+ S_DEADARTI3,
+ S_DEADARTI4,
+ S_DEADARTI5,
+ S_DEADARTI6,
+ S_DEADARTI7,
+ S_DEADARTI8,
+ S_DEADARTI9,
+ S_DEADARTI10,
+ S_ARTI_PTN2_1,
+ S_ARTI_PTN2_2,
+ S_ARTI_PTN2_3,
+ S_ARTI_SOAR1,
+ S_ARTI_SOAR2,
+ S_ARTI_SOAR3,
+ S_ARTI_SOAR4,
+ S_ARTI_INVU1,
+ S_ARTI_INVU2,
+ S_ARTI_INVU3,
+ S_ARTI_INVU4,
+ S_ARTI_SUMMON,
+ S_SUMMON_FX1_1,
+ S_SUMMON_FX2_1,
+ S_SUMMON_FX2_2,
+ S_SUMMON_FX2_3,
+ S_THRUSTINIT2_1,
+ S_THRUSTINIT2_2,
+ S_BTHRUSTINIT2_1,
+ S_BTHRUSTINIT2_2,
+ S_THRUSTINIT1_1,
+ S_THRUSTINIT1_2,
+ S_BTHRUSTINIT1_1,
+ S_BTHRUSTINIT1_2,
+ S_THRUSTRAISE1,
+ S_THRUSTRAISE2,
+ S_THRUSTRAISE3,
+ S_THRUSTRAISE4,
+ S_BTHRUSTRAISE1,
+ S_BTHRUSTRAISE2,
+ S_BTHRUSTRAISE3,
+ S_BTHRUSTRAISE4,
+ S_THRUSTIMPALE,
+ S_BTHRUSTIMPALE,
+ S_THRUSTRAISE,
+ S_BTHRUSTRAISE,
+ S_THRUSTBLOCK,
+ S_BTHRUSTBLOCK,
+ S_THRUSTLOWER,
+ S_BTHRUSTLOWER,
+ S_THRUSTSTAY,
+ S_BTHRUSTSTAY,
+ S_ARTI_TELOTHER1,
+ S_ARTI_TELOTHER2,
+ S_ARTI_TELOTHER3,
+ S_ARTI_TELOTHER4,
+ S_TELO_FX1,
+ S_TELO_FX2,
+ S_TELO_FX3,
+ S_TELO_FX4,
+ S_TELO_FX5,
+ S_TELO_FX6,
+ S_TELO_FX7,
+ S_TELO_FX8,
+ S_TELO_FX9,
+ S_TELO_FX2_1,
+ S_TELO_FX2_2,
+ S_TELO_FX2_3,
+ S_TELO_FX2_4,
+ S_TELO_FX2_5,
+ S_TELO_FX2_6,
+ S_TELO_FX3_1,
+ S_TELO_FX3_2,
+ S_TELO_FX3_3,
+ S_TELO_FX3_4,
+ S_TELO_FX3_5,
+ S_TELO_FX3_6,
+ S_TELO_FX4_1,
+ S_TELO_FX4_2,
+ S_TELO_FX4_3,
+ S_TELO_FX4_4,
+ S_TELO_FX4_5,
+ S_TELO_FX4_6,
+ S_TELO_FX5_1,
+ S_TELO_FX5_2,
+ S_TELO_FX5_3,
+ S_TELO_FX5_4,
+ S_TELO_FX5_5,
+ S_TELO_FX5_6,
+ S_DIRT1_1,
+ S_DIRT1_D,
+ S_DIRT2_1,
+ S_DIRT2_D,
+ S_DIRT3_1,
+ S_DIRT3_D,
+ S_DIRT4_1,
+ S_DIRT4_D,
+ S_DIRT5_1,
+ S_DIRT5_D,
+ S_DIRT6_1,
+ S_DIRT6_D,
+ S_DIRTCLUMP1,
+ S_ROCK1_1,
+ S_ROCK1_D,
+ S_ROCK2_1,
+ S_ROCK2_D,
+ S_ROCK3_1,
+ S_ROCK3_D,
+ S_SPAWNFOG1,
+ S_FOGPATCHS1,
+ S_FOGPATCHS2,
+ S_FOGPATCHS3,
+ S_FOGPATCHS4,
+ S_FOGPATCHS5,
+ S_FOGPATCHS0,
+ S_FOGPATCHM1,
+ S_FOGPATCHM2,
+ S_FOGPATCHM3,
+ S_FOGPATCHM4,
+ S_FOGPATCHM5,
+ S_FOGPATCHM0,
+ S_FOGPATCHMA,
+ S_FOGPATCHMB,
+ S_FOGPATCHMC,
+ S_FOGPATCHMD,
+ S_FOGPATCHL1,
+ S_FOGPATCHL2,
+ S_FOGPATCHL3,
+ S_FOGPATCHL4,
+ S_FOGPATCHL5,
+ S_FOGPATCHL0,
+ S_FOGPATCHLA,
+ S_FOGPATCHLB,
+ S_FOGPATCHLC,
+ S_FOGPATCHLD,
+ S_QUAKE_ACTIVE1,
+ S_QUAKE_ACTIVE2,
+ S_QUAKE_ACTIVE3,
+ S_QUAKE_ACTIVE4,
+ S_QUAKE_ACTIVE5,
+ S_QUAKE_ACTIVE6,
+ S_QUAKE_ACTIVE7,
+ S_QUAKE_ACTIVE8,
+ S_QUAKE_ACTIVE9,
+ S_QUAKE_ACTIVE0,
+ S_QUAKE_ACTIVEA,
+ S_QUAKE_ACTIVEB,
+ S_QUAKE_ACTIVEC,
+ S_QUAKE_ACTIVED,
+ S_QUAKE_ACTIVEE,
+ S_QUAKE_ACTIVEF,
+ S_QUAKE_ACTIVEG,
+ S_QUAKE_ACTIVEH,
+ S_QUAKE_ACTIVEI,
+ S_QUAKE_ACTIVEJ,
+ S_QUAKE_ACTIVEK,
+ S_QUAKE_ACTIVEL,
+ S_QUAKE_ACTIVEM,
+ S_QUAKE_ACTIVEN,
+ S_QUAKE_ACTIVEO,
+ S_QUAKE_ACTIVEP,
+ S_QUAKE_ACTIVEQ,
+ S_QUAKE_ACTIVER,
+ S_QUAKE_ACTIVES,
+ S_QUAKE_ACTIVET,
+ S_QUAKE_ACTIVEU,
+ S_QUAKE_ACTIVEV,
+ S_QUAKE_ACTIVEW,
+ S_QUAKE_ACTIVEX,
+ S_QUAKE_ACTIVEY,
+ S_QUAKE_ACTIVEZ,
+ S_QUAKE_ACT1,
+ S_QUAKE_ACT2,
+ S_QUAKE_ACT3,
+ S_QUAKE_ACT4,
+ S_QUAKE_ACT5,
+ S_QUAKE_ACT6,
+ S_QUAKE_ACT7,
+ S_QUAKE_ACT8,
+ S_QUAKE_ACT9,
+ S_QUAKE_ACT0,
+ S_SGSHARD1_1,
+ S_SGSHARD1_2,
+ S_SGSHARD1_3,
+ S_SGSHARD1_4,
+ S_SGSHARD1_5,
+ S_SGSHARD1_D,
+ S_SGSHARD2_1,
+ S_SGSHARD2_2,
+ S_SGSHARD2_3,
+ S_SGSHARD2_4,
+ S_SGSHARD2_5,
+ S_SGSHARD2_D,
+ S_SGSHARD3_1,
+ S_SGSHARD3_2,
+ S_SGSHARD3_3,
+ S_SGSHARD3_4,
+ S_SGSHARD3_5,
+ S_SGSHARD3_D,
+ S_SGSHARD4_1,
+ S_SGSHARD4_2,
+ S_SGSHARD4_3,
+ S_SGSHARD4_4,
+ S_SGSHARD4_5,
+ S_SGSHARD4_D,
+ S_SGSHARD5_1,
+ S_SGSHARD5_2,
+ S_SGSHARD5_3,
+ S_SGSHARD5_4,
+ S_SGSHARD5_5,
+ S_SGSHARD5_D,
+ S_SGSHARD6_1,
+ S_SGSHARD6_D,
+ S_SGSHARD7_1,
+ S_SGSHARD7_D,
+ S_SGSHARD8_1,
+ S_SGSHARD8_D,
+ S_SGSHARD9_1,
+ S_SGSHARD9_D,
+ S_SGSHARD0_1,
+ S_SGSHARD0_D,
+ S_ARTI_EGGC1,
+ S_ARTI_EGGC2,
+ S_ARTI_EGGC3,
+ S_ARTI_EGGC4,
+ S_ARTI_EGGC5,
+ S_ARTI_EGGC6,
+ S_ARTI_EGGC7,
+ S_ARTI_EGGC8,
+ S_EGGFX1,
+ S_EGGFX2,
+ S_EGGFX3,
+ S_EGGFX4,
+ S_EGGFX5,
+ S_EGGFXI1_1,
+ S_EGGFXI1_2,
+ S_EGGFXI1_3,
+ S_EGGFXI1_4,
+ S_ARTI_SPHL1,
+ S_ZWINGEDSTATUENOSKULL,
+ S_ZWINGEDSTATUENOSKULL2,
+ S_ZGEMPEDESTAL1,
+ S_ZGEMPEDESTAL2,
+ S_ARTIPUZZSKULL,
+ S_ARTIPUZZGEMBIG,
+ S_ARTIPUZZGEMRED,
+ S_ARTIPUZZGEMGREEN1,
+ S_ARTIPUZZGEMGREEN2,
+ S_ARTIPUZZGEMBLUE1,
+ S_ARTIPUZZGEMBLUE2,
+ S_ARTIPUZZBOOK1,
+ S_ARTIPUZZBOOK2,
+ S_ARTIPUZZSKULL2,
+ S_ARTIPUZZFWEAPON,
+ S_ARTIPUZZCWEAPON,
+ S_ARTIPUZZMWEAPON,
+ S_ARTIPUZZGEAR_1,
+ S_ARTIPUZZGEAR_2,
+ S_ARTIPUZZGEAR_3,
+ S_ARTIPUZZGEAR_4,
+ S_ARTIPUZZGEAR_5,
+ S_ARTIPUZZGEAR_6,
+ S_ARTIPUZZGEAR_7,
+ S_ARTIPUZZGEAR_8,
+ S_ARTIPUZZGEAR2_1,
+ S_ARTIPUZZGEAR2_2,
+ S_ARTIPUZZGEAR2_3,
+ S_ARTIPUZZGEAR2_4,
+ S_ARTIPUZZGEAR2_5,
+ S_ARTIPUZZGEAR2_6,
+ S_ARTIPUZZGEAR2_7,
+ S_ARTIPUZZGEAR2_8,
+ S_ARTIPUZZGEAR3_1,
+ S_ARTIPUZZGEAR3_2,
+ S_ARTIPUZZGEAR3_3,
+ S_ARTIPUZZGEAR3_4,
+ S_ARTIPUZZGEAR3_5,
+ S_ARTIPUZZGEAR3_6,
+ S_ARTIPUZZGEAR3_7,
+ S_ARTIPUZZGEAR3_8,
+ S_ARTIPUZZGEAR4_1,
+ S_ARTIPUZZGEAR4_2,
+ S_ARTIPUZZGEAR4_3,
+ S_ARTIPUZZGEAR4_4,
+ S_ARTIPUZZGEAR4_5,
+ S_ARTIPUZZGEAR4_6,
+ S_ARTIPUZZGEAR4_7,
+ S_ARTIPUZZGEAR4_8,
+ S_ARTI_TRCH1,
+ S_ARTI_TRCH2,
+ S_ARTI_TRCH3,
+ S_FIREBOMB1,
+ S_FIREBOMB2,
+ S_FIREBOMB3,
+ S_FIREBOMB4,
+ S_FIREBOMB5,
+ S_FIREBOMB6,
+ S_FIREBOMB7,
+ S_FIREBOMB8,
+ S_FIREBOMB9,
+ S_FIREBOMB10,
+ S_FIREBOMB11,
+ S_ARTI_ATLP1,
+ S_ARTI_ATLP2,
+ S_ARTI_ATLP3,
+ S_ARTI_ATLP4,
+ S_ARTI_PSBG1,
+ S_POISONBAG1,
+ S_POISONBAG2,
+ S_POISONBAG3,
+ S_POISONBAG4,
+ S_POISONCLOUD1,
+ S_POISONCLOUD2,
+ S_POISONCLOUD3,
+ S_POISONCLOUD4,
+ S_POISONCLOUD5,
+ S_POISONCLOUD6,
+ S_POISONCLOUD7,
+ S_POISONCLOUD8,
+ S_POISONCLOUD9,
+ S_POISONCLOUD10,
+ S_POISONCLOUD11,
+ S_POISONCLOUD12,
+ S_POISONCLOUD13,
+ S_POISONCLOUD14,
+ S_POISONCLOUD15,
+ S_POISONCLOUD16,
+ S_POISONCLOUD17,
+ S_POISONCLOUD18,
+ S_POISONCLOUD_X1,
+ S_POISONCLOUD_X2,
+ S_POISONCLOUD_X3,
+ S_POISONCLOUD_X4,
+ S_THROWINGBOMB1,
+ S_THROWINGBOMB2,
+ S_THROWINGBOMB3,
+ S_THROWINGBOMB4,
+ S_THROWINGBOMB5,
+ S_THROWINGBOMB6,
+ S_THROWINGBOMB7,
+ S_THROWINGBOMB8,
+ S_THROWINGBOMB9,
+ S_THROWINGBOMB10,
+ S_THROWINGBOMB11,
+ S_THROWINGBOMB12,
+ S_THROWINGBOMB_X1,
+ S_THROWINGBOMB_X2,
+ S_THROWINGBOMB_X3,
+ S_THROWINGBOMB_X4,
+ S_THROWINGBOMB_X5,
+ S_THROWINGBOMB_X6,
+ S_THROWINGBOMB_X7,
+ S_THROWINGBOMB_X8,
+ S_ARTI_BOOTS1,
+ S_ARTI_BOOTS2,
+ S_ARTI_BOOTS3,
+ S_ARTI_BOOTS4,
+ S_ARTI_BOOTS5,
+ S_ARTI_BOOTS6,
+ S_ARTI_BOOTS7,
+ S_ARTI_BOOTS8,
+ S_ARTI_MANA,
+ S_ARTI_ARMOR1,
+ S_ARTI_ARMOR2,
+ S_ARTI_ARMOR3,
+ S_ARTI_ARMOR4,
+ S_ARTI_ARMOR5,
+ S_ARTI_ARMOR6,
+ S_ARTI_ARMOR7,
+ S_ARTI_ARMOR8,
+ S_ARTI_BLAST1,
+ S_ARTI_BLAST2,
+ S_ARTI_BLAST3,
+ S_ARTI_BLAST4,
+ S_ARTI_BLAST5,
+ S_ARTI_BLAST6,
+ S_ARTI_BLAST7,
+ S_ARTI_BLAST8,
+ S_ARTI_HEALRAD1,
+ S_ARTI_HEALRAD2,
+ S_ARTI_HEALRAD3,
+ S_ARTI_HEALRAD4,
+ S_ARTI_HEALRAD5,
+ S_ARTI_HEALRAD6,
+ S_ARTI_HEALRAD7,
+ S_ARTI_HEALRAD8,
+ S_ARTI_HEALRAD9,
+ S_ARTI_HEALRAD0,
+ S_ARTI_HEALRADA,
+ S_ARTI_HEALRADB,
+ S_ARTI_HEALRADC,
+ S_ARTI_HEALRADD,
+ S_ARTI_HEALRADE,
+ S_ARTI_HEALRADF,
+ S_SPLASH1,
+ S_SPLASH2,
+ S_SPLASH3,
+ S_SPLASH4,
+ S_SPLASHX,
+ S_SPLASHBASE1,
+ S_SPLASHBASE2,
+ S_SPLASHBASE3,
+ S_SPLASHBASE4,
+ S_SPLASHBASE5,
+ S_SPLASHBASE6,
+ S_SPLASHBASE7,
+ S_LAVASPLASH1,
+ S_LAVASPLASH2,
+ S_LAVASPLASH3,
+ S_LAVASPLASH4,
+ S_LAVASPLASH5,
+ S_LAVASPLASH6,
+ S_LAVASMOKE1,
+ S_LAVASMOKE2,
+ S_LAVASMOKE3,
+ S_LAVASMOKE4,
+ S_LAVASMOKE5,
+ S_SLUDGECHUNK1,
+ S_SLUDGECHUNK2,
+ S_SLUDGECHUNK3,
+ S_SLUDGECHUNK4,
+ S_SLUDGECHUNKX,
+ S_SLUDGESPLASH1,
+ S_SLUDGESPLASH2,
+ S_SLUDGESPLASH3,
+ S_SLUDGESPLASH4,
+ S_ZWINGEDSTATUE1,
+ S_ZROCK1_1,
+ S_ZROCK2_1,
+ S_ZROCK3_1,
+ S_ZROCK4_1,
+ S_ZCHANDELIER1,
+ S_ZCHANDELIER2,
+ S_ZCHANDELIER3,
+ S_ZCHANDELIER_U,
+ S_ZTREEDEAD1,
+ S_ZTREE,
+ S_ZTREEDESTRUCTIBLE1,
+ S_ZTREEDES_D1,
+ S_ZTREEDES_D2,
+ S_ZTREEDES_D3,
+ S_ZTREEDES_D4,
+ S_ZTREEDES_D5,
+ S_ZTREEDES_D6,
+ S_ZTREEDES_X1,
+ S_ZTREEDES_X2,
+ S_ZTREEDES_X3,
+ S_ZTREEDES_X4,
+ S_ZTREEDES_X5,
+ S_ZTREEDES_X6,
+ S_ZTREEDES_X7,
+ S_ZTREEDES_X8,
+ S_ZTREEDES_X9,
+ S_ZTREEDES_X10,
+ S_ZTREESWAMP182_1,
+ S_ZTREESWAMP172_1,
+ S_ZSTUMPBURNED1,
+ S_ZSTUMPBARE1,
+ S_ZSTUMPSWAMP1_1,
+ S_ZSTUMPSWAMP2_1,
+ S_ZSHROOMLARGE1_1,
+ S_ZSHROOMLARGE2_1,
+ S_ZSHROOMLARGE3_1,
+ S_ZSHROOMSMALL1_1,
+ S_ZSHROOMSMALL2_1,
+ S_ZSHROOMSMALL3_1,
+ S_ZSHROOMSMALL4_1,
+ S_ZSHROOMSMALL5_1,
+ S_ZSTALAGMITEPILLAR1,
+ S_ZSTALAGMITELARGE1,
+ S_ZSTALAGMITEMEDIUM1,
+ S_ZSTALAGMITESMALL1,
+ S_ZSTALACTITELARGE1,
+ S_ZSTALACTITEMEDIUM1,
+ S_ZSTALACTITESMALL1,
+ S_ZMOSSCEILING1_1,
+ S_ZMOSSCEILING2_1,
+ S_ZSWAMPVINE1,
+ S_ZCORPSEKABOB1,
+ S_ZCORPSESLEEPING1,
+ S_ZTOMBSTONERIP1,
+ S_ZTOMBSTONESHANE1,
+ S_ZTOMBSTONEBIGCROSS1,
+ S_ZTOMBSTONEBRIANR1,
+ S_ZTOMBSTONECROSSCIRCLE1,
+ S_ZTOMBSTONESMALLCROSS1,
+ S_ZTOMBSTONEBRIANP1,
+ S_CORPSEHANGING_1,
+ S_ZSTATUEGARGOYLEGREENTALL_1,
+ S_ZSTATUEGARGOYLEBLUETALL_1,
+ S_ZSTATUEGARGOYLEGREENSHORT_1,
+ S_ZSTATUEGARGOYLEBLUESHORT_1,
+ S_ZSTATUEGARGOYLESTRIPETALL_1,
+ S_ZSTATUEGARGOYLEDARKREDTALL_1,
+ S_ZSTATUEGARGOYLEREDTALL_1,
+ S_ZSTATUEGARGOYLETANTALL_1,
+ S_ZSTATUEGARGOYLERUSTTALL_1,
+ S_ZSTATUEGARGOYLEDARKREDSHORT_1,
+ S_ZSTATUEGARGOYLEREDSHORT_1,
+ S_ZSTATUEGARGOYLETANSHORT_1,
+ S_ZSTATUEGARGOYLERUSTSHORT_1,
+ S_ZBANNERTATTERED_1,
+ S_ZTREELARGE1,
+ S_ZTREELARGE2,
+ S_ZTREEGNARLED1,
+ S_ZTREEGNARLED2,
+ S_ZLOG,
+ S_ZSTALACTITEICELARGE,
+ S_ZSTALACTITEICEMEDIUM,
+ S_ZSTALACTITEICESMALL,
+ S_ZSTALACTITEICETINY,
+ S_ZSTALAGMITEICELARGE,
+ S_ZSTALAGMITEICEMEDIUM,
+ S_ZSTALAGMITEICESMALL,
+ S_ZSTALAGMITEICETINY,
+ S_ZROCKBROWN1,
+ S_ZROCKBROWN2,
+ S_ZROCKBLACK,
+ S_ZRUBBLE1,
+ S_ZRUBBLE2,
+ S_ZRUBBLE3,
+ S_ZVASEPILLAR,
+ S_ZPOTTERY1,
+ S_ZPOTTERY2,
+ S_ZPOTTERY3,
+ S_ZPOTTERY_EXPLODE,
+ S_POTTERYBIT_1,
+ S_POTTERYBIT_2,
+ S_POTTERYBIT_3,
+ S_POTTERYBIT_4,
+ S_POTTERYBIT_5,
+ S_POTTERYBIT_EX0,
+ S_POTTERYBIT_EX1,
+ S_POTTERYBIT_EX1_2,
+ S_POTTERYBIT_EX2,
+ S_POTTERYBIT_EX2_2,
+ S_POTTERYBIT_EX3,
+ S_POTTERYBIT_EX3_2,
+ S_POTTERYBIT_EX4,
+ S_POTTERYBIT_EX4_2,
+ S_POTTERYBIT_EX5,
+ S_POTTERYBIT_EX5_2,
+ S_ZCORPSELYNCHED1,
+ S_ZCORPSELYNCHED2,
+ S_ZCORPSESITTING,
+ S_ZCORPSESITTING_X,
+ S_CORPSEBIT_1,
+ S_CORPSEBIT_2,
+ S_CORPSEBIT_3,
+ S_CORPSEBIT_4,
+ S_CORPSEBLOODDRIP,
+ S_CORPSEBLOODDRIP_X1,
+ S_CORPSEBLOODDRIP_X2,
+ S_CORPSEBLOODDRIP_X3,
+ S_CORPSEBLOODDRIP_X4,
+ S_BLOODPOOL,
+ S_ZCANDLE1,
+ S_ZCANDLE2,
+ S_ZCANDLE3,
+ S_ZLEAFSPAWNER,
+ S_LEAF1_1,
+ S_LEAF1_2,
+ S_LEAF1_3,
+ S_LEAF1_4,
+ S_LEAF1_5,
+ S_LEAF1_6,
+ S_LEAF1_7,
+ S_LEAF1_8,
+ S_LEAF1_9,
+ S_LEAF1_10,
+ S_LEAF1_11,
+ S_LEAF1_12,
+ S_LEAF1_13,
+ S_LEAF1_14,
+ S_LEAF1_15,
+ S_LEAF1_16,
+ S_LEAF1_17,
+ S_LEAF1_18,
+ S_LEAF_X1,
+ S_LEAF2_1,
+ S_LEAF2_2,
+ S_LEAF2_3,
+ S_LEAF2_4,
+ S_LEAF2_5,
+ S_LEAF2_6,
+ S_LEAF2_7,
+ S_LEAF2_8,
+ S_LEAF2_9,
+ S_LEAF2_10,
+ S_LEAF2_11,
+ S_LEAF2_12,
+ S_LEAF2_13,
+ S_LEAF2_14,
+ S_LEAF2_15,
+ S_LEAF2_16,
+ S_LEAF2_17,
+ S_LEAF2_18,
+ S_ZTWINEDTORCH_1,
+ S_ZTWINEDTORCH_2,
+ S_ZTWINEDTORCH_3,
+ S_ZTWINEDTORCH_4,
+ S_ZTWINEDTORCH_5,
+ S_ZTWINEDTORCH_6,
+ S_ZTWINEDTORCH_7,
+ S_ZTWINEDTORCH_8,
+ S_ZTWINEDTORCH_UNLIT,
+ S_BRIDGE1,
+ S_BRIDGE2,
+ S_BRIDGE3,
+ S_FREE_BRIDGE1,
+ S_FREE_BRIDGE2,
+ S_BBALL1,
+ S_BBALL2,
+ S_ZWALLTORCH1,
+ S_ZWALLTORCH2,
+ S_ZWALLTORCH3,
+ S_ZWALLTORCH4,
+ S_ZWALLTORCH5,
+ S_ZWALLTORCH6,
+ S_ZWALLTORCH7,
+ S_ZWALLTORCH8,
+ S_ZWALLTORCH_U,
+ S_ZBARREL1,
+ S_ZSHRUB1,
+ S_ZSHRUB1_DIE,
+ S_ZSHRUB1_X1,
+ S_ZSHRUB1_X2,
+ S_ZSHRUB1_X3,
+ S_ZSHRUB2,
+ S_ZSHRUB2_DIE,
+ S_ZSHRUB2_X1,
+ S_ZSHRUB2_X2,
+ S_ZSHRUB2_X3,
+ S_ZSHRUB2_X4,
+ S_ZBUCKET1,
+ S_ZPOISONSHROOM1,
+ S_ZPOISONSHROOM_P1,
+ S_ZPOISONSHROOM_P2,
+ S_ZPOISONSHROOM_X1,
+ S_ZPOISONSHROOM_X2,
+ S_ZPOISONSHROOM_X3,
+ S_ZPOISONSHROOM_X4,
+ S_ZFIREBULL1,
+ S_ZFIREBULL2,
+ S_ZFIREBULL3,
+ S_ZFIREBULL4,
+ S_ZFIREBULL5,
+ S_ZFIREBULL6,
+ S_ZFIREBULL7,
+ S_ZFIREBULL_DEATH,
+ S_ZFIREBULL_DEATH2,
+ S_ZFIREBULL_U,
+ S_ZFIREBULL_BIRTH,
+ S_ZFIREBULL_BIRTH2,
+ S_ZFIRETHING1,
+ S_ZFIRETHING2,
+ S_ZFIRETHING3,
+ S_ZFIRETHING4,
+ S_ZFIRETHING5,
+ S_ZFIRETHING6,
+ S_ZFIRETHING7,
+ S_ZFIRETHING8,
+ S_ZFIRETHING9,
+ S_ZBRASSTORCH1,
+ S_ZBRASSTORCH2,
+ S_ZBRASSTORCH3,
+ S_ZBRASSTORCH4,
+ S_ZBRASSTORCH5,
+ S_ZBRASSTORCH6,
+ S_ZBRASSTORCH7,
+ S_ZBRASSTORCH8,
+ S_ZBRASSTORCH9,
+ S_ZBRASSTORCH10,
+ S_ZBRASSTORCH11,
+ S_ZBRASSTORCH12,
+ S_ZBRASSTORCH13,
+ S_ZSUITOFARMOR,
+ S_ZSUITOFARMOR_X1,
+ S_ZARMORCHUNK1,
+ S_ZARMORCHUNK2,
+ S_ZARMORCHUNK3,
+ S_ZARMORCHUNK4,
+ S_ZARMORCHUNK5,
+ S_ZARMORCHUNK6,
+ S_ZARMORCHUNK7,
+ S_ZARMORCHUNK8,
+ S_ZARMORCHUNK9,
+ S_ZARMORCHUNK10,
+ S_ZBELL,
+ S_ZBELL_X1,
+ S_ZBELL_X2,
+ S_ZBELL_X3,
+ S_ZBELL_X4,
+ S_ZBELL_X5,
+ S_ZBELL_X6,
+ S_ZBELL_X7,
+ S_ZBELL_X8,
+ S_ZBELL_X9,
+ S_ZBELL_X10,
+ S_ZBELL_X11,
+ S_ZBELL_X12,
+ S_ZBELL_X13,
+ S_ZBELL_X14,
+ S_ZBELL_X15,
+ S_ZBELL_X16,
+ S_ZBELL_X17,
+ S_ZBELL_X18,
+ S_ZBELL_X19,
+ S_ZBELL_X20,
+ S_ZBELL_X21,
+ S_ZBELL_X22,
+ S_ZBELL_X23,
+ S_ZBELL_X24,
+ S_ZBELL_X25,
+ S_ZBELL_X26,
+ S_ZBELL_X27,
+ S_ZBELL_X28,
+ S_ZBELL_X29,
+ S_ZBELL_X30,
+ S_ZBELL_X31,
+ S_ZBELL_X32,
+ S_ZBELL_X33,
+ S_ZBELL_X34,
+ S_ZBELL_X35,
+ S_ZBELL_X36,
+ S_ZBELL_X37,
+ S_ZBELL_X38,
+ S_ZBELL_X39,
+ S_ZBELL_X40,
+ S_ZBELL_X41,
+ S_ZBELL_X42,
+ S_ZBELL_X43,
+ S_ZBELL_X44,
+ S_ZBELL_X45,
+ S_ZBELL_X46,
+ S_ZBELL_X47,
+ S_ZBLUE_CANDLE1,
+ S_ZBLUE_CANDLE2,
+ S_ZBLUE_CANDLE3,
+ S_ZBLUE_CANDLE4,
+ S_ZBLUE_CANDLE5,
+ S_ZIRON_MAIDEN,
+ S_ZXMAS_TREE,
+ S_ZXMAS_TREE_DIE,
+ S_ZXMAS_TREE_X1,
+ S_ZXMAS_TREE_X2,
+ S_ZXMAS_TREE_X3,
+ S_ZXMAS_TREE_X4,
+ S_ZXMAS_TREE_X5,
+ S_ZXMAS_TREE_X6,
+ S_ZXMAS_TREE_X7,
+ S_ZXMAS_TREE_X8,
+ S_ZXMAS_TREE_X9,
+ S_ZXMAS_TREE_X10,
+ S_ZCAULDRON1,
+ S_ZCAULDRON2,
+ S_ZCAULDRON3,
+ S_ZCAULDRON4,
+ S_ZCAULDRON5,
+ S_ZCAULDRON6,
+ S_ZCAULDRON7,
+ S_ZCAULDRON_U,
+ S_ZCHAINBIT32,
+ S_ZCHAINBIT64,
+ S_ZCHAINEND_HEART,
+ S_ZCHAINEND_HOOK1,
+ S_ZCHAINEND_HOOK2,
+ S_ZCHAINEND_SPIKE,
+ S_ZCHAINEND_SKULL,
+ S_TABLE_SHIT1,
+ S_TABLE_SHIT2,
+ S_TABLE_SHIT3,
+ S_TABLE_SHIT4,
+ S_TABLE_SHIT5,
+ S_TABLE_SHIT6,
+ S_TABLE_SHIT7,
+ S_TABLE_SHIT8,
+ S_TABLE_SHIT9,
+ S_TABLE_SHIT10,
+ S_TFOG1,
+ S_TFOG2,
+ S_TFOG3,
+ S_TFOG4,
+ S_TFOG5,
+ S_TFOG6,
+ S_TFOG7,
+ S_TFOG8,
+ S_TFOG9,
+ S_TFOG10,
+ S_TFOG11,
+ S_TFOG12,
+ S_TFOG13,
+ S_TELESMOKE1,
+ S_TELESMOKE2,
+ S_TELESMOKE3,
+ S_TELESMOKE4,
+ S_TELESMOKE5,
+ S_TELESMOKE6,
+ S_TELESMOKE7,
+ S_TELESMOKE8,
+ S_TELESMOKE9,
+ S_TELESMOKE10,
+ S_TELESMOKE11,
+ S_TELESMOKE12,
+ S_TELESMOKE13,
+ S_TELESMOKE14,
+ S_TELESMOKE15,
+ S_TELESMOKE16,
+ S_TELESMOKE17,
+ S_TELESMOKE18,
+ S_TELESMOKE19,
+ S_TELESMOKE20,
+ S_TELESMOKE21,
+ S_TELESMOKE22,
+ S_TELESMOKE23,
+ S_TELESMOKE24,
+ S_TELESMOKE25,
+ S_TELESMOKE26,
+ S_LIGHTDONE,
+ S_PUNCHREADY,
+ S_PUNCHDOWN,
+ S_PUNCHUP,
+ S_PUNCHATK1_1,
+ S_PUNCHATK1_2,
+ S_PUNCHATK1_3,
+ S_PUNCHATK1_4,
+ S_PUNCHATK1_5,
+ S_PUNCHATK2_1,
+ S_PUNCHATK2_2,
+ S_PUNCHATK2_3,
+ S_PUNCHATK2_4,
+ S_PUNCHATK2_5,
+ S_PUNCHATK2_6,
+ S_PUNCHATK2_7,
+ S_PUNCHATK2_8,
+ S_PUNCHATK2_9,
+ S_PUNCHPUFF1,
+ S_PUNCHPUFF2,
+ S_PUNCHPUFF3,
+ S_PUNCHPUFF4,
+ S_PUNCHPUFF5,
+ S_AXE,
+ S_FAXEREADY,
+ S_FAXEDOWN,
+ S_FAXEUP,
+ S_FAXEATK_1,
+ S_FAXEATK_2,
+ S_FAXEATK_3,
+ S_FAXEATK_4,
+ S_FAXEATK_5,
+ S_FAXEATK_6,
+ S_FAXEATK_7,
+ S_FAXEATK_8,
+ S_FAXEATK_9,
+ S_FAXEATK_10,
+ S_FAXEATK_11,
+ S_FAXEATK_12,
+ S_FAXEATK_13,
+ S_FAXEREADY_G,
+ S_FAXEREADY_G1,
+ S_FAXEREADY_G2,
+ S_FAXEREADY_G3,
+ S_FAXEREADY_G4,
+ S_FAXEREADY_G5,
+ S_FAXEDOWN_G,
+ S_FAXEUP_G,
+ S_FAXEATK_G1,
+ S_FAXEATK_G2,
+ S_FAXEATK_G3,
+ S_FAXEATK_G4,
+ S_FAXEATK_G5,
+ S_FAXEATK_G6,
+ S_FAXEATK_G7,
+ S_FAXEATK_G8,
+ S_FAXEATK_G9,
+ S_FAXEATK_G10,
+ S_FAXEATK_G11,
+ S_FAXEATK_G12,
+ S_FAXEATK_G13,
+ S_AXEPUFF_GLOW1,
+ S_AXEPUFF_GLOW2,
+ S_AXEPUFF_GLOW3,
+ S_AXEPUFF_GLOW4,
+ S_AXEPUFF_GLOW5,
+ S_AXEPUFF_GLOW6,
+ S_AXEPUFF_GLOW7,
+ S_AXEBLOOD1,
+ S_AXEBLOOD2,
+ S_AXEBLOOD3,
+ S_AXEBLOOD4,
+ S_AXEBLOOD5,
+ S_AXEBLOOD6,
+ S_HAMM,
+ S_FHAMMERREADY,
+ S_FHAMMERDOWN,
+ S_FHAMMERUP,
+ S_FHAMMERATK_1,
+ S_FHAMMERATK_2,
+ S_FHAMMERATK_3,
+ S_FHAMMERATK_4,
+ S_FHAMMERATK_5,
+ S_FHAMMERATK_6,
+ S_FHAMMERATK_7,
+ S_FHAMMERATK_8,
+ S_FHAMMERATK_9,
+ S_FHAMMERATK_10,
+ S_FHAMMERATK_11,
+ S_FHAMMERATK_12,
+ S_HAMMER_MISSILE_1,
+ S_HAMMER_MISSILE_2,
+ S_HAMMER_MISSILE_3,
+ S_HAMMER_MISSILE_4,
+ S_HAMMER_MISSILE_5,
+ S_HAMMER_MISSILE_6,
+ S_HAMMER_MISSILE_7,
+ S_HAMMER_MISSILE_8,
+ S_HAMMER_MISSILE_X1,
+ S_HAMMER_MISSILE_X2,
+ S_HAMMER_MISSILE_X3,
+ S_HAMMER_MISSILE_X4,
+ S_HAMMER_MISSILE_X5,
+ S_HAMMER_MISSILE_X6,
+ S_HAMMER_MISSILE_X7,
+ S_HAMMER_MISSILE_X8,
+ S_HAMMER_MISSILE_X9,
+ S_HAMMER_MISSILE_X10,
+ S_HAMMERPUFF1,
+ S_HAMMERPUFF2,
+ S_HAMMERPUFF3,
+ S_HAMMERPUFF4,
+ S_HAMMERPUFF5,
+ S_FSWORDREADY,
+ S_FSWORDREADY1,
+ S_FSWORDREADY2,
+ S_FSWORDREADY3,
+ S_FSWORDREADY4,
+ S_FSWORDREADY5,
+ S_FSWORDREADY6,
+ S_FSWORDREADY7,
+ S_FSWORDREADY8,
+ S_FSWORDREADY9,
+ S_FSWORDREADY10,
+ S_FSWORDREADY11,
+ S_FSWORDDOWN,
+ S_FSWORDUP,
+ S_FSWORDATK_1,
+ S_FSWORDATK_2,
+ S_FSWORDATK_3,
+ S_FSWORDATK_4,
+ S_FSWORDATK_5,
+ S_FSWORDATK_6,
+ S_FSWORDATK_7,
+ S_FSWORDATK_8,
+ S_FSWORDATK_9,
+ S_FSWORDATK_10,
+ S_FSWORDATK_11,
+ S_FSWORDATK_12,
+ S_FSWORD_MISSILE1,
+ S_FSWORD_MISSILE2,
+ S_FSWORD_MISSILE3,
+ S_FSWORD_MISSILE_X1,
+ S_FSWORD_MISSILE_X2,
+ S_FSWORD_MISSILE_X3,
+ S_FSWORD_MISSILE_X4,
+ S_FSWORD_MISSILE_X5,
+ S_FSWORD_MISSILE_X6,
+ S_FSWORD_MISSILE_X7,
+ S_FSWORD_MISSILE_X8,
+ S_FSWORD_MISSILE_X9,
+ S_FSWORD_MISSILE_X10,
+ S_FSWORD_FLAME1,
+ S_FSWORD_FLAME2,
+ S_FSWORD_FLAME3,
+ S_FSWORD_FLAME4,
+ S_FSWORD_FLAME5,
+ S_FSWORD_FLAME6,
+ S_FSWORD_FLAME7,
+ S_FSWORD_FLAME8,
+ S_FSWORD_FLAME9,
+ S_FSWORD_FLAME10,
+ S_CMACEREADY,
+ S_CMACEDOWN,
+ S_CMACEUP,
+ S_CMACEATK_1,
+ S_CMACEATK_2,
+ S_CMACEATK_3,
+ S_CMACEATK_4,
+ S_CMACEATK_5,
+ S_CMACEATK_6,
+ S_CMACEATK_7,
+ S_CMACEATK_8,
+ S_CMACEATK_9,
+ S_CMACEATK_10,
+ S_CMACEATK_11,
+ S_CMACEATK_12,
+ S_CMACEATK_13,
+ S_CMACEATK_14,
+ S_CMACEATK_15,
+ S_CMACEATK_16,
+ S_CMACEATK_17,
+ S_CSTAFF,
+ S_CSTAFFREADY,
+ S_CSTAFFREADY1,
+ S_CSTAFFREADY2,
+ S_CSTAFFREADY3,
+ S_CSTAFFREADY4,
+ S_CSTAFFREADY5,
+ S_CSTAFFREADY6,
+ S_CSTAFFREADY7,
+ S_CSTAFFREADY8,
+ S_CSTAFFREADY9,
+ S_CSTAFFBLINK1,
+ S_CSTAFFBLINK2,
+ S_CSTAFFBLINK3,
+ S_CSTAFFBLINK4,
+ S_CSTAFFBLINK5,
+ S_CSTAFFBLINK6,
+ S_CSTAFFBLINK7,
+ S_CSTAFFBLINK8,
+ S_CSTAFFBLINK9,
+ S_CSTAFFBLINK10,
+ S_CSTAFFBLINK11,
+ S_CSTAFFDOWN,
+ S_CSTAFFDOWN2,
+ S_CSTAFFDOWN3,
+ S_CSTAFFUP,
+ S_CSTAFFATK_1,
+ S_CSTAFFATK_2,
+ S_CSTAFFATK_3,
+ S_CSTAFFATK_4,
+ S_CSTAFFATK_5,
+ S_CSTAFFATK_6,
+ S_CSTAFFATK2_1,
+ S_CSTAFF_MISSILE1,
+ S_CSTAFF_MISSILE2,
+ S_CSTAFF_MISSILE3,
+ S_CSTAFF_MISSILE4,
+ S_CSTAFF_MISSILE_X1,
+ S_CSTAFF_MISSILE_X2,
+ S_CSTAFF_MISSILE_X3,
+ S_CSTAFF_MISSILE_X4,
+ S_CSTAFFPUFF1,
+ S_CSTAFFPUFF2,
+ S_CSTAFFPUFF3,
+ S_CSTAFFPUFF4,
+ S_CSTAFFPUFF5,
+ S_CFLAME1,
+ S_CFLAME2,
+ S_CFLAME3,
+ S_CFLAME4,
+ S_CFLAME5,
+ S_CFLAME6,
+ S_CFLAME7,
+ S_CFLAME8,
+ S_CFLAMEREADY1,
+ S_CFLAMEREADY2,
+ S_CFLAMEREADY3,
+ S_CFLAMEREADY4,
+ S_CFLAMEREADY5,
+ S_CFLAMEREADY6,
+ S_CFLAMEREADY7,
+ S_CFLAMEREADY8,
+ S_CFLAMEREADY9,
+ S_CFLAMEREADY10,
+ S_CFLAMEREADY11,
+ S_CFLAMEREADY12,
+ S_CFLAMEDOWN,
+ S_CFLAMEUP,
+ S_CFLAMEATK_1,
+ S_CFLAMEATK_2,
+ S_CFLAMEATK_3,
+ S_CFLAMEATK_4,
+ S_CFLAMEATK_5,
+ S_CFLAMEATK_6,
+ S_CFLAMEATK_7,
+ S_CFLAMEATK_8,
+ S_CFLAMEFLOOR1,
+ S_CFLAMEFLOOR2,
+ S_CFLAMEFLOOR3,
+ S_FLAMEPUFF1,
+ S_FLAMEPUFF2,
+ S_FLAMEPUFF3,
+ S_FLAMEPUFF4,
+ S_FLAMEPUFF5,
+ S_FLAMEPUFF6,
+ S_FLAMEPUFF7,
+ S_FLAMEPUFF8,
+ S_FLAMEPUFF9,
+ S_FLAMEPUFF10,
+ S_FLAMEPUFF11,
+ S_FLAMEPUFF12,
+ S_FLAMEPUFF13,
+ S_FLAMEPUFF2_1,
+ S_FLAMEPUFF2_2,
+ S_FLAMEPUFF2_3,
+ S_FLAMEPUFF2_4,
+ S_FLAMEPUFF2_5,
+ S_FLAMEPUFF2_6,
+ S_FLAMEPUFF2_7,
+ S_FLAMEPUFF2_8,
+ S_FLAMEPUFF2_9,
+ S_FLAMEPUFF2_10,
+ S_FLAMEPUFF2_11,
+ S_FLAMEPUFF2_12,
+ S_FLAMEPUFF2_13,
+ S_FLAMEPUFF2_14,
+ S_FLAMEPUFF2_15,
+ S_FLAMEPUFF2_16,
+ S_FLAMEPUFF2_17,
+ S_FLAMEPUFF2_18,
+ S_FLAMEPUFF2_19,
+ S_FLAMEPUFF2_20,
+ S_CIRCLE_FLAME1,
+ S_CIRCLE_FLAME2,
+ S_CIRCLE_FLAME3,
+ S_CIRCLE_FLAME4,
+ S_CIRCLE_FLAME5,
+ S_CIRCLE_FLAME6,
+ S_CIRCLE_FLAME7,
+ S_CIRCLE_FLAME8,
+ S_CIRCLE_FLAME9,
+ S_CIRCLE_FLAME10,
+ S_CIRCLE_FLAME11,
+ S_CIRCLE_FLAME12,
+ S_CIRCLE_FLAME13,
+ S_CIRCLE_FLAME14,
+ S_CIRCLE_FLAME15,
+ S_CIRCLE_FLAME16,
+ S_CIRCLE_FLAME_X1,
+ S_CIRCLE_FLAME_X2,
+ S_CIRCLE_FLAME_X3,
+ S_CIRCLE_FLAME_X4,
+ S_CIRCLE_FLAME_X5,
+ S_CIRCLE_FLAME_X6,
+ S_CIRCLE_FLAME_X7,
+ S_CIRCLE_FLAME_X8,
+ S_CIRCLE_FLAME_X9,
+ S_CIRCLE_FLAME_X10,
+ S_CFLAME_MISSILE1,
+ S_CFLAME_MISSILE2,
+ S_CFLAME_MISSILE_X,
+ S_CHOLYREADY,
+ S_CHOLYDOWN,
+ S_CHOLYUP,
+ S_CHOLYATK_1,
+ S_CHOLYATK_2,
+ S_CHOLYATK_3,
+ S_CHOLYATK_4,
+ S_CHOLYATK_5,
+ S_CHOLYATK_6,
+ S_CHOLYATK_7,
+ S_CHOLYATK_8,
+ S_CHOLYATK_9,
+ S_HOLY_FX1,
+ S_HOLY_FX2,
+ S_HOLY_FX3,
+ S_HOLY_FX4,
+ S_HOLY_FX_X1,
+ S_HOLY_FX_X2,
+ S_HOLY_FX_X3,
+ S_HOLY_FX_X4,
+ S_HOLY_FX_X5,
+ S_HOLY_FX_X6,
+ S_HOLY_TAIL1,
+ S_HOLY_TAIL2,
+ S_HOLY_PUFF1,
+ S_HOLY_PUFF2,
+ S_HOLY_PUFF3,
+ S_HOLY_PUFF4,
+ S_HOLY_PUFF5,
+ S_HOLY_MISSILE1,
+ S_HOLY_MISSILE2,
+ S_HOLY_MISSILE3,
+ S_HOLY_MISSILE4,
+ S_HOLY_MISSILE_X,
+ S_HOLY_MISSILE_P1,
+ S_HOLY_MISSILE_P2,
+ S_HOLY_MISSILE_P3,
+ S_HOLY_MISSILE_P4,
+ S_HOLY_MISSILE_P5,
+ S_MWANDREADY,
+ S_MWANDDOWN,
+ S_MWANDUP,
+ S_MWANDATK_1,
+ S_MWANDATK_2,
+ S_MWANDATK_3,
+ S_MWANDATK_4,
+ S_MWANDPUFF1,
+ S_MWANDPUFF2,
+ S_MWANDPUFF3,
+ S_MWANDPUFF4,
+ S_MWANDPUFF5,
+ S_MWANDSMOKE1,
+ S_MWANDSMOKE2,
+ S_MWANDSMOKE3,
+ S_MWANDSMOKE4,
+ S_MWAND_MISSILE1,
+ S_MWAND_MISSILE2,
+ S_MW_LIGHTNING1,
+ S_MW_LIGHTNING2,
+ S_MW_LIGHTNING3,
+ S_MW_LIGHTNING4,
+ S_MW_LIGHTNING5,
+ S_MW_LIGHTNING6,
+ S_MW_LIGHTNING7,
+ S_MW_LIGHTNING8,
+ S_MLIGHTNINGREADY,
+ S_MLIGHTNINGREADY2,
+ S_MLIGHTNINGREADY3,
+ S_MLIGHTNINGREADY4,
+ S_MLIGHTNINGREADY5,
+ S_MLIGHTNINGREADY6,
+ S_MLIGHTNINGREADY7,
+ S_MLIGHTNINGREADY8,
+ S_MLIGHTNINGREADY9,
+ S_MLIGHTNINGREADY10,
+ S_MLIGHTNINGREADY11,
+ S_MLIGHTNINGREADY12,
+ S_MLIGHTNINGREADY13,
+ S_MLIGHTNINGREADY14,
+ S_MLIGHTNINGREADY15,
+ S_MLIGHTNINGREADY16,
+ S_MLIGHTNINGREADY17,
+ S_MLIGHTNINGREADY18,
+ S_MLIGHTNINGREADY19,
+ S_MLIGHTNINGREADY20,
+ S_MLIGHTNINGREADY21,
+ S_MLIGHTNINGREADY22,
+ S_MLIGHTNINGREADY23,
+ S_MLIGHTNINGREADY24,
+ S_MLIGHTNINGDOWN,
+ S_MLIGHTNINGUP,
+ S_MLIGHTNINGATK_1,
+ S_MLIGHTNINGATK_2,
+ S_MLIGHTNINGATK_3,
+ S_MLIGHTNINGATK_4,
+ S_MLIGHTNINGATK_5,
+ S_MLIGHTNINGATK_6,
+ S_MLIGHTNINGATK_7,
+ S_MLIGHTNINGATK_8,
+ S_MLIGHTNINGATK_9,
+ S_MLIGHTNINGATK_10,
+ S_MLIGHTNINGATK_11,
+ S_LIGHTNING_CEILING1,
+ S_LIGHTNING_CEILING2,
+ S_LIGHTNING_CEILING3,
+ S_LIGHTNING_CEILING4,
+ S_LIGHTNING_C_X1,
+ S_LIGHTNING_C_X2,
+ S_LIGHTNING_C_X3,
+ S_LIGHTNING_C_X4,
+ S_LIGHTNING_C_X5,
+ S_LIGHTNING_C_X6,
+ S_LIGHTNING_C_X7,
+ S_LIGHTNING_C_X8,
+ S_LIGHTNING_C_X9,
+ S_LIGHTNING_C_X10,
+ S_LIGHTNING_C_X11,
+ S_LIGHTNING_C_X12,
+ S_LIGHTNING_C_X13,
+ S_LIGHTNING_C_X14,
+ S_LIGHTNING_C_X15,
+ S_LIGHTNING_C_X16,
+ S_LIGHTNING_C_X17,
+ S_LIGHTNING_C_X18,
+ S_LIGHTNING_C_X19,
+ S_LIGHTNING_FLOOR1,
+ S_LIGHTNING_FLOOR2,
+ S_LIGHTNING_FLOOR3,
+ S_LIGHTNING_FLOOR4,
+ S_LIGHTNING_F_X1,
+ S_LIGHTNING_F_X2,
+ S_LIGHTNING_F_X3,
+ S_LIGHTNING_F_X4,
+ S_LIGHTNING_F_X5,
+ S_LIGHTNING_F_X6,
+ S_LIGHTNING_F_X7,
+ S_LIGHTNING_F_X8,
+ S_LIGHTNING_F_X9,
+ S_LIGHTNING_F_X10,
+ S_LIGHTNING_F_X11,
+ S_LIGHTNING_F_X12,
+ S_LIGHTNING_F_X13,
+ S_LIGHTNING_F_X14,
+ S_LIGHTNING_F_X15,
+ S_LIGHTNING_F_X16,
+ S_LIGHTNING_F_X17,
+ S_LIGHTNING_F_X18,
+ S_LIGHTNING_F_X19,
+ S_LIGHTNING_ZAP1,
+ S_LIGHTNING_ZAP2,
+ S_LIGHTNING_ZAP3,
+ S_LIGHTNING_ZAP4,
+ S_LIGHTNING_ZAP5,
+ S_LIGHTNING_ZAP_X1,
+ S_LIGHTNING_ZAP_X2,
+ S_LIGHTNING_ZAP_X3,
+ S_LIGHTNING_ZAP_X4,
+ S_LIGHTNING_ZAP_X5,
+ S_LIGHTNING_ZAP_X6,
+ S_LIGHTNING_ZAP_X7,
+ S_LIGHTNING_ZAP_X8,
+ S_MSTAFFREADY,
+ S_MSTAFFREADY2,
+ S_MSTAFFREADY3,
+ S_MSTAFFREADY4,
+ S_MSTAFFREADY5,
+ S_MSTAFFREADY6,
+ S_MSTAFFREADY7,
+ S_MSTAFFREADY8,
+ S_MSTAFFREADY9,
+ S_MSTAFFREADY10,
+ S_MSTAFFREADY11,
+ S_MSTAFFREADY12,
+ S_MSTAFFREADY13,
+ S_MSTAFFREADY14,
+ S_MSTAFFREADY15,
+ S_MSTAFFREADY16,
+ S_MSTAFFREADY17,
+ S_MSTAFFREADY18,
+ S_MSTAFFREADY19,
+ S_MSTAFFREADY20,
+ S_MSTAFFREADY21,
+ S_MSTAFFREADY22,
+ S_MSTAFFREADY23,
+ S_MSTAFFREADY24,
+ S_MSTAFFREADY25,
+ S_MSTAFFREADY26,
+ S_MSTAFFREADY27,
+ S_MSTAFFREADY28,
+ S_MSTAFFREADY29,
+ S_MSTAFFREADY30,
+ S_MSTAFFREADY31,
+ S_MSTAFFREADY32,
+ S_MSTAFFREADY33,
+ S_MSTAFFREADY34,
+ S_MSTAFFREADY35,
+ S_MSTAFFDOWN,
+ S_MSTAFFUP,
+ S_MSTAFFATK_1,
+ S_MSTAFFATK_2,
+ S_MSTAFFATK_3,
+ S_MSTAFFATK_4,
+ S_MSTAFFATK_5,
+ S_MSTAFFATK_6,
+ S_MSTAFFATK_7,
+ S_MSTAFF_FX1_1,
+ S_MSTAFF_FX1_2,
+ S_MSTAFF_FX1_3,
+ S_MSTAFF_FX1_4,
+ S_MSTAFF_FX1_5,
+ S_MSTAFF_FX1_6,
+ S_MSTAFF_FX_X1,
+ S_MSTAFF_FX_X2,
+ S_MSTAFF_FX_X3,
+ S_MSTAFF_FX_X4,
+ S_MSTAFF_FX_X5,
+ S_MSTAFF_FX_X6,
+ S_MSTAFF_FX_X7,
+ S_MSTAFF_FX_X8,
+ S_MSTAFF_FX_X9,
+ S_MSTAFF_FX_X10,
+ S_MSTAFF_FX2_1,
+ S_MSTAFF_FX2_2,
+ S_MSTAFF_FX2_3,
+ S_MSTAFF_FX2_4,
+ S_MSTAFF_FX2_X1,
+ S_MSTAFF_FX2_X2,
+ S_MSTAFF_FX2_X3,
+ S_MSTAFF_FX2_X4,
+ S_MSTAFF_FX2_X5,
+ S_FSWORD1,
+ S_FSWORD2,
+ S_FSWORD3,
+ S_CHOLY1,
+ S_CHOLY2,
+ S_CHOLY3,
+ S_MSTAFF1,
+ S_MSTAFF2,
+ S_MSTAFF3,
+ S_SNOUTREADY,
+ S_SNOUTDOWN,
+ S_SNOUTUP,
+ S_SNOUTATK1,
+ S_SNOUTATK2,
+ S_COS1,
+ S_COS2,
+ S_COS3,
+ S_CONEREADY,
+ S_CONEDOWN,
+ S_CONEUP,
+ S_CONEATK1_1,
+ S_CONEATK1_2,
+ S_CONEATK1_3,
+ S_CONEATK1_4,
+ S_CONEATK1_5,
+ S_CONEATK1_6,
+ S_CONEATK1_7,
+ S_CONEATK1_8,
+ S_SHARDFX1_1,
+ S_SHARDFX1_2,
+ S_SHARDFX1_3,
+ S_SHARDFX1_4,
+ S_SHARDFXE1_1,
+ S_SHARDFXE1_2,
+ S_SHARDFXE1_3,
+ S_SHARDFXE1_4,
+ S_SHARDFXE1_5,
+ S_BLOOD1,
+ S_BLOOD2,
+ S_BLOOD3,
+ S_BLOODSPLATTER1,
+ S_BLOODSPLATTER2,
+ S_BLOODSPLATTER3,
+ S_BLOODSPLATTERX,
+ S_GIBS1,
+ S_FPLAY,
+ S_FPLAY_RUN1,
+ S_FPLAY_RUN2,
+ S_FPLAY_RUN3,
+ S_FPLAY_RUN4,
+ S_FPLAY_ATK1,
+ S_FPLAY_ATK2,
+ S_FPLAY_PAIN,
+ S_FPLAY_PAIN2,
+ S_FPLAY_DIE1,
+ S_FPLAY_DIE2,
+ S_FPLAY_DIE3,
+ S_FPLAY_DIE4,
+ S_FPLAY_DIE5,
+ S_FPLAY_DIE6,
+ S_FPLAY_DIE7,
+ S_FPLAY_XDIE1,
+ S_FPLAY_XDIE2,
+ S_FPLAY_XDIE3,
+ S_FPLAY_XDIE4,
+ S_FPLAY_XDIE5,
+ S_FPLAY_XDIE6,
+ S_FPLAY_XDIE7,
+ S_FPLAY_XDIE8,
+ S_FPLAY_ICE,
+ S_FPLAY_ICE2,
+ S_PLAY_F_FDTH1,
+ S_PLAY_F_FDTH2,
+ S_PLAY_C_FDTH1,
+ S_PLAY_C_FDTH2,
+ S_PLAY_M_FDTH1,
+ S_PLAY_M_FDTH2,
+ S_PLAY_FDTH3,
+ S_PLAY_FDTH4,
+ S_PLAY_FDTH5,
+ S_PLAY_FDTH6,
+ S_PLAY_FDTH7,
+ S_PLAY_FDTH8,
+ S_PLAY_FDTH9,
+ S_PLAY_FDTH10,
+ S_PLAY_FDTH11,
+ S_PLAY_FDTH12,
+ S_PLAY_FDTH13,
+ S_PLAY_FDTH14,
+ S_PLAY_FDTH15,
+ S_PLAY_FDTH16,
+ S_PLAY_FDTH17,
+ S_PLAY_FDTH18,
+ S_PLAY_FDTH19,
+ S_PLAY_FDTH20,
+ S_BLOODYSKULL1,
+ S_BLOODYSKULL2,
+ S_BLOODYSKULL3,
+ S_BLOODYSKULL4,
+ S_BLOODYSKULL5,
+ S_BLOODYSKULL6,
+ S_BLOODYSKULL7,
+ S_BLOODYSKULLX1,
+ S_BLOODYSKULLX2,
+ S_PLAYER_SPEED1,
+ S_PLAYER_SPEED2,
+ S_ICECHUNK1,
+ S_ICECHUNK2,
+ S_ICECHUNK3,
+ S_ICECHUNK4,
+ S_ICECHUNK_HEAD,
+ S_ICECHUNK_HEAD2,
+ S_CPLAY,
+ S_CPLAY_RUN1,
+ S_CPLAY_RUN2,
+ S_CPLAY_RUN3,
+ S_CPLAY_RUN4,
+ S_CPLAY_ATK1,
+ S_CPLAY_ATK2,
+ S_CPLAY_ATK3,
+ S_CPLAY_PAIN,
+ S_CPLAY_PAIN2,
+ S_CPLAY_DIE1,
+ S_CPLAY_DIE2,
+ S_CPLAY_DIE3,
+ S_CPLAY_DIE4,
+ S_CPLAY_DIE5,
+ S_CPLAY_DIE6,
+ S_CPLAY_DIE7,
+ S_CPLAY_DIE8,
+ S_CPLAY_DIE9,
+ S_CPLAY_XDIE1,
+ S_CPLAY_XDIE2,
+ S_CPLAY_XDIE3,
+ S_CPLAY_XDIE4,
+ S_CPLAY_XDIE5,
+ S_CPLAY_XDIE6,
+ S_CPLAY_XDIE7,
+ S_CPLAY_XDIE8,
+ S_CPLAY_XDIE9,
+ S_CPLAY_XDIE10,
+ S_CPLAY_ICE,
+ S_CPLAY_ICE2,
+ S_MPLAY,
+ S_MPLAY_RUN1,
+ S_MPLAY_RUN2,
+ S_MPLAY_RUN3,
+ S_MPLAY_RUN4,
+ S_MPLAY_ATK1,
+ S_MPLAY_ATK2,
+ S_MPLAY_PAIN,
+ S_MPLAY_PAIN2,
+ S_MPLAY_DIE1,
+ S_MPLAY_DIE2,
+ S_MPLAY_DIE3,
+ S_MPLAY_DIE4,
+ S_MPLAY_DIE5,
+ S_MPLAY_DIE6,
+ S_MPLAY_DIE7,
+ S_MPLAY_XDIE1,
+ S_MPLAY_XDIE2,
+ S_MPLAY_XDIE3,
+ S_MPLAY_XDIE4,
+ S_MPLAY_XDIE5,
+ S_MPLAY_XDIE6,
+ S_MPLAY_XDIE7,
+ S_MPLAY_XDIE8,
+ S_MPLAY_XDIE9,
+ S_MPLAY_ICE,
+ S_MPLAY_ICE2,
+ S_PIGPLAY,
+ S_PIGPLAY_RUN1,
+ S_PIGPLAY_RUN2,
+ S_PIGPLAY_RUN3,
+ S_PIGPLAY_RUN4,
+ S_PIGPLAY_ATK1,
+ S_PIGPLAY_PAIN,
+ S_PIG_LOOK1,
+ S_PIG_WALK1,
+ S_PIG_WALK2,
+ S_PIG_WALK3,
+ S_PIG_WALK4,
+ S_PIG_PAIN,
+ S_PIG_ATK1,
+ S_PIG_ATK2,
+ S_PIG_DIE1,
+ S_PIG_DIE2,
+ S_PIG_DIE3,
+ S_PIG_DIE4,
+ S_PIG_DIE5,
+ S_PIG_DIE6,
+ S_PIG_DIE7,
+ S_PIG_DIE8,
+ S_PIG_ICE,
+ S_PIG_ICE2,
+ S_CENTAUR_LOOK1,
+ S_CENTAUR_LOOK2,
+ S_CENTAUR_WALK1,
+ S_CENTAUR_WALK2,
+ S_CENTAUR_WALK3,
+ S_CENTAUR_WALK4,
+ S_CENTAUR_ATK1,
+ S_CENTAUR_ATK2,
+ S_CENTAUR_ATK3,
+ S_CENTAUR_MISSILE1,
+ S_CENTAUR_MISSILE2,
+ S_CENTAUR_MISSILE3,
+ S_CENTAUR_MISSILE4,
+ S_CENTAUR_PAIN1,
+ S_CENTAUR_PAIN2,
+ S_CENTAUR_PAIN3,
+ S_CENTAUR_PAIN4,
+ S_CENTAUR_PAIN5,
+ S_CENTAUR_PAIN6,
+ S_CENTAUR_DEATH1,
+ S_CENTAUR_DEATH2,
+ S_CENTAUR_DEATH3,
+ S_CENTAUR_DEATH4,
+ S_CENTAUR_DEATH5,
+ S_CENTAUR_DEATH6,
+ S_CENTAUR_DEATH7,
+ S_CENTAUR_DEATH8,
+ S_CENTAUR_DEATH9,
+ S_CENTAUR_DEATH0,
+ S_CENTAUR_DEATH_X1,
+ S_CENTAUR_DEATH_X2,
+ S_CENTAUR_DEATH_X3,
+ S_CENTAUR_DEATH_X4,
+ S_CENTAUR_DEATH_X5,
+ S_CENTAUR_DEATH_X6,
+ S_CENTAUR_DEATH_X7,
+ S_CENTAUR_DEATH_X8,
+ S_CENTAUR_DEATH_X9,
+ S_CENTAUR_DEATH_X10,
+ S_CENTAUR_DEATH_X11,
+ S_CENTAUR_ICE,
+ S_CENTAUR_ICE2,
+ S_CENTAUR_FX1,
+ S_CENTAUR_FX_X1,
+ S_CENTAUR_FX_X2,
+ S_CENTAUR_FX_X3,
+ S_CENTAUR_FX_X4,
+ S_CENTAUR_FX_X5,
+ S_CENTAUR_SHIELD1,
+ S_CENTAUR_SHIELD2,
+ S_CENTAUR_SHIELD3,
+ S_CENTAUR_SHIELD4,
+ S_CENTAUR_SHIELD5,
+ S_CENTAUR_SHIELD6,
+ S_CENTAUR_SHIELD_X1,
+ S_CENTAUR_SHIELD_X2,
+ S_CENTAUR_SHIELD_X3,
+ S_CENTAUR_SHIELD_X4,
+ S_CENTAUR_SWORD1,
+ S_CENTAUR_SWORD2,
+ S_CENTAUR_SWORD3,
+ S_CENTAUR_SWORD4,
+ S_CENTAUR_SWORD5,
+ S_CENTAUR_SWORD6,
+ S_CENTAUR_SWORD7,
+ S_CENTAUR_SWORD_X1,
+ S_CENTAUR_SWORD_X2,
+ S_CENTAUR_SWORD_X3,
+ S_DEMN_LOOK1,
+ S_DEMN_LOOK2,
+ S_DEMN_CHASE1,
+ S_DEMN_CHASE2,
+ S_DEMN_CHASE3,
+ S_DEMN_CHASE4,
+ S_DEMN_ATK1_1,
+ S_DEMN_ATK1_2,
+ S_DEMN_ATK1_3,
+ S_DEMN_ATK2_1,
+ S_DEMN_ATK2_2,
+ S_DEMN_ATK2_3,
+ S_DEMN_PAIN1,
+ S_DEMN_PAIN2,
+ S_DEMN_DEATH1,
+ S_DEMN_DEATH2,
+ S_DEMN_DEATH3,
+ S_DEMN_DEATH4,
+ S_DEMN_DEATH5,
+ S_DEMN_DEATH6,
+ S_DEMN_DEATH7,
+ S_DEMN_DEATH8,
+ S_DEMN_DEATH9,
+ S_DEMN_XDEATH1,
+ S_DEMN_XDEATH2,
+ S_DEMN_XDEATH3,
+ S_DEMN_XDEATH4,
+ S_DEMN_XDEATH5,
+ S_DEMN_XDEATH6,
+ S_DEMN_XDEATH7,
+ S_DEMN_XDEATH8,
+ S_DEMN_XDEATH9,
+ S_DEMON_ICE,
+ S_DEMON_ICE2,
+ S_DEMONCHUNK1_1,
+ S_DEMONCHUNK1_2,
+ S_DEMONCHUNK1_3,
+ S_DEMONCHUNK1_4,
+ S_DEMONCHUNK2_1,
+ S_DEMONCHUNK2_2,
+ S_DEMONCHUNK2_3,
+ S_DEMONCHUNK2_4,
+ S_DEMONCHUNK3_1,
+ S_DEMONCHUNK3_2,
+ S_DEMONCHUNK3_3,
+ S_DEMONCHUNK3_4,
+ S_DEMONCHUNK4_1,
+ S_DEMONCHUNK4_2,
+ S_DEMONCHUNK4_3,
+ S_DEMONCHUNK4_4,
+ S_DEMONCHUNK5_1,
+ S_DEMONCHUNK5_2,
+ S_DEMONCHUNK5_3,
+ S_DEMONCHUNK5_4,
+ S_DEMONFX_MOVE1,
+ S_DEMONFX_MOVE2,
+ S_DEMONFX_MOVE3,
+ S_DEMONFX_BOOM1,
+ S_DEMONFX_BOOM2,
+ S_DEMONFX_BOOM3,
+ S_DEMONFX_BOOM4,
+ S_DEMONFX_BOOM5,
+ S_DEMN2_LOOK1,
+ S_DEMN2_LOOK2,
+ S_DEMN2_CHASE1,
+ S_DEMN2_CHASE2,
+ S_DEMN2_CHASE3,
+ S_DEMN2_CHASE4,
+ S_DEMN2_ATK1_1,
+ S_DEMN2_ATK1_2,
+ S_DEMN2_ATK1_3,
+ S_DEMN2_ATK2_1,
+ S_DEMN2_ATK2_2,
+ S_DEMN2_ATK2_3,
+ S_DEMN2_PAIN1,
+ S_DEMN2_PAIN2,
+ S_DEMN2_DEATH1,
+ S_DEMN2_DEATH2,
+ S_DEMN2_DEATH3,
+ S_DEMN2_DEATH4,
+ S_DEMN2_DEATH5,
+ S_DEMN2_DEATH6,
+ S_DEMN2_DEATH7,
+ S_DEMN2_DEATH8,
+ S_DEMN2_DEATH9,
+ S_DEMN2_XDEATH1,
+ S_DEMN2_XDEATH2,
+ S_DEMN2_XDEATH3,
+ S_DEMN2_XDEATH4,
+ S_DEMN2_XDEATH5,
+ S_DEMN2_XDEATH6,
+ S_DEMN2_XDEATH7,
+ S_DEMN2_XDEATH8,
+ S_DEMN2_XDEATH9,
+ S_DEMON2CHUNK1_1,
+ S_DEMON2CHUNK1_2,
+ S_DEMON2CHUNK1_3,
+ S_DEMON2CHUNK1_4,
+ S_DEMON2CHUNK2_1,
+ S_DEMON2CHUNK2_2,
+ S_DEMON2CHUNK2_3,
+ S_DEMON2CHUNK2_4,
+ S_DEMON2CHUNK3_1,
+ S_DEMON2CHUNK3_2,
+ S_DEMON2CHUNK3_3,
+ S_DEMON2CHUNK3_4,
+ S_DEMON2CHUNK4_1,
+ S_DEMON2CHUNK4_2,
+ S_DEMON2CHUNK4_3,
+ S_DEMON2CHUNK4_4,
+ S_DEMON2CHUNK5_1,
+ S_DEMON2CHUNK5_2,
+ S_DEMON2CHUNK5_3,
+ S_DEMON2CHUNK5_4,
+ S_DEMON2FX_MOVE1,
+ S_DEMON2FX_MOVE2,
+ S_DEMON2FX_MOVE3,
+ S_DEMON2FX_MOVE4,
+ S_DEMON2FX_MOVE5,
+ S_DEMON2FX_MOVE6,
+ S_DEMON2FX_BOOM1,
+ S_DEMON2FX_BOOM2,
+ S_DEMON2FX_BOOM3,
+ S_DEMON2FX_BOOM4,
+ S_DEMON2FX_BOOM5,
+ S_DEMON2FX_BOOM6,
+ S_WRAITH_RAISE1,
+ S_WRAITH_RAISE2,
+ S_WRAITH_RAISE3,
+ S_WRAITH_RAISE4,
+ S_WRAITH_RAISE5,
+ S_WRAITH_INIT1,
+ S_WRAITH_INIT2,
+ S_WRAITH_LOOK1,
+ S_WRAITH_LOOK2,
+ S_WRAITH_CHASE1,
+ S_WRAITH_CHASE2,
+ S_WRAITH_CHASE3,
+ S_WRAITH_CHASE4,
+ S_WRAITH_ATK1_1,
+ S_WRAITH_ATK1_2,
+ S_WRAITH_ATK1_3,
+ S_WRAITH_ATK2_1,
+ S_WRAITH_ATK2_2,
+ S_WRAITH_ATK2_3,
+ S_WRAITH_PAIN1,
+ S_WRAITH_PAIN2,
+ S_WRAITH_DEATH1_1,
+ S_WRAITH_DEATH1_2,
+ S_WRAITH_DEATH1_3,
+ S_WRAITH_DEATH1_4,
+ S_WRAITH_DEATH1_5,
+ S_WRAITH_DEATH1_6,
+ S_WRAITH_DEATH1_7,
+ S_WRAITH_DEATH1_8,
+ S_WRAITH_DEATH1_9,
+ S_WRAITH_DEATH1_0,
+ S_WRAITH_DEATH2_1,
+ S_WRAITH_DEATH2_2,
+ S_WRAITH_DEATH2_3,
+ S_WRAITH_DEATH2_4,
+ S_WRAITH_DEATH2_5,
+ S_WRAITH_DEATH2_6,
+ S_WRAITH_DEATH2_7,
+ S_WRAITH_DEATH2_8,
+ S_WRAITH_ICE,
+ S_WRAITH_ICE2,
+ S_WRTHFX_MOVE1,
+ S_WRTHFX_MOVE2,
+ S_WRTHFX_MOVE3,
+ S_WRTHFX_BOOM1,
+ S_WRTHFX_BOOM2,
+ S_WRTHFX_BOOM3,
+ S_WRTHFX_BOOM4,
+ S_WRTHFX_BOOM5,
+ S_WRTHFX_BOOM6,
+ S_WRTHFX_SIZZLE1,
+ S_WRTHFX_SIZZLE2,
+ S_WRTHFX_SIZZLE3,
+ S_WRTHFX_SIZZLE4,
+ S_WRTHFX_SIZZLE5,
+ S_WRTHFX_SIZZLE6,
+ S_WRTHFX_SIZZLE7,
+ S_WRTHFX_DROP1,
+ S_WRTHFX_DROP2,
+ S_WRTHFX_DROP3,
+ S_WRTHFX_DEAD1,
+ S_WRTHFX_ADROP1,
+ S_WRTHFX_ADROP2,
+ S_WRTHFX_ADROP3,
+ S_WRTHFX_ADROP4,
+ S_WRTHFX_ADEAD1,
+ S_WRTHFX_BDROP1,
+ S_WRTHFX_BDROP2,
+ S_WRTHFX_BDROP3,
+ S_WRTHFX_BDEAD1,
+ S_MNTR_SPAWN1,
+ S_MNTR_SPAWN2,
+ S_MNTR_SPAWN3,
+ S_MNTR_LOOK1,
+ S_MNTR_LOOK2,
+ S_MNTR_WALK1,
+ S_MNTR_WALK2,
+ S_MNTR_WALK3,
+ S_MNTR_WALK4,
+ S_MNTR_ROAM1,
+ S_MNTR_ROAM2,
+ S_MNTR_ROAM3,
+ S_MNTR_ROAM4,
+ S_MNTR_ATK1_1,
+ S_MNTR_ATK1_2,
+ S_MNTR_ATK1_3,
+ S_MNTR_ATK2_1,
+ S_MNTR_ATK2_2,
+ S_MNTR_ATK2_3,
+ S_MNTR_ATK3_1,
+ S_MNTR_ATK3_2,
+ S_MNTR_ATK3_3,
+ S_MNTR_ATK3_4,
+ S_MNTR_ATK4_1,
+ S_MNTR_PAIN1,
+ S_MNTR_PAIN2,
+ S_MNTR_DIE1,
+ S_MNTR_DIE2,
+ S_MNTR_DIE3,
+ S_MNTR_DIE4,
+ S_MNTR_DIE5,
+ S_MNTR_DIE6,
+ S_MNTR_DIE7,
+ S_MNTR_DIE8,
+ S_MNTR_DIE9,
+ S_MNTRFX1_1,
+ S_MNTRFX1_2,
+ S_MNTRFXI1_1,
+ S_MNTRFXI1_2,
+ S_MNTRFXI1_3,
+ S_MNTRFXI1_4,
+ S_MNTRFXI1_5,
+ S_MNTRFXI1_6,
+ S_MNTRFX2_1,
+ S_MNTRFXI2_1,
+ S_MNTRFXI2_2,
+ S_MNTRFXI2_3,
+ S_MNTRFXI2_4,
+ S_MNTRFXI2_5,
+ S_MNTRFX3_1,
+ S_MNTRFX3_2,
+ S_MNTRFX3_3,
+ S_MNTRFX3_4,
+ S_MNTRFX3_5,
+ S_MNTRFX3_6,
+ S_MNTRFX3_7,
+ S_MNTRFX3_8,
+ S_MNTRFX3_9,
+ S_MINOSMOKE1,
+ S_MINOSMOKE2,
+ S_MINOSMOKE3,
+ S_MINOSMOKE4,
+ S_MINOSMOKE5,
+ S_MINOSMOKE6,
+ S_MINOSMOKE7,
+ S_MINOSMOKE8,
+ S_MINOSMOKE9,
+ S_MINOSMOKE0,
+ S_MINOSMOKEA,
+ S_MINOSMOKEB,
+ S_MINOSMOKEC,
+ S_MINOSMOKED,
+ S_MINOSMOKEE,
+ S_MINOSMOKEF,
+ S_MINOSMOKEG,
+ S_MINOSMOKEX1,
+ S_MINOSMOKEX2,
+ S_MINOSMOKEX3,
+ S_MINOSMOKEX4,
+ S_MINOSMOKEX5,
+ S_MINOSMOKEX6,
+ S_MINOSMOKEX7,
+ S_MINOSMOKEX8,
+ S_MINOSMOKEX9,
+ S_MINOSMOKEX0,
+ S_MINOSMOKEXA,
+ S_MINOSMOKEXB,
+ S_MINOSMOKEXC,
+ S_MINOSMOKEXD,
+ S_MINOSMOKEXE,
+ S_MINOSMOKEXF,
+ S_MINOSMOKEXG,
+ S_MINOSMOKEXH,
+ S_MINOSMOKEXI,
+ S_SERPENT_LOOK1,
+ S_SERPENT_SWIM1,
+ S_SERPENT_SWIM2,
+ S_SERPENT_SWIM3,
+ S_SERPENT_HUMP1,
+ S_SERPENT_HUMP2,
+ S_SERPENT_HUMP3,
+ S_SERPENT_HUMP4,
+ S_SERPENT_HUMP5,
+ S_SERPENT_HUMP6,
+ S_SERPENT_HUMP7,
+ S_SERPENT_HUMP8,
+ S_SERPENT_HUMP9,
+ S_SERPENT_HUMP10,
+ S_SERPENT_HUMP11,
+ S_SERPENT_HUMP12,
+ S_SERPENT_HUMP13,
+ S_SERPENT_HUMP14,
+ S_SERPENT_HUMP15,
+ S_SERPENT_SURFACE1,
+ S_SERPENT_SURFACE2,
+ S_SERPENT_SURFACE3,
+ S_SERPENT_SURFACE4,
+ S_SERPENT_SURFACE5,
+ S_SERPENT_DIVE1,
+ S_SERPENT_DIVE2,
+ S_SERPENT_DIVE3,
+ S_SERPENT_DIVE4,
+ S_SERPENT_DIVE5,
+ S_SERPENT_DIVE6,
+ S_SERPENT_DIVE7,
+ S_SERPENT_DIVE8,
+ S_SERPENT_DIVE9,
+ S_SERPENT_DIVE10,
+ S_SERPENT_WALK1,
+ S_SERPENT_WALK2,
+ S_SERPENT_WALK3,
+ S_SERPENT_WALK4,
+ S_SERPENT_PAIN1,
+ S_SERPENT_PAIN2,
+ S_SERPENT_ATK1,
+ S_SERPENT_ATK2,
+ S_SERPENT_MELEE1,
+ S_SERPENT_MISSILE1,
+ S_SERPENT_DIE1,
+ S_SERPENT_DIE2,
+ S_SERPENT_DIE3,
+ S_SERPENT_DIE4,
+ S_SERPENT_DIE5,
+ S_SERPENT_DIE6,
+ S_SERPENT_DIE7,
+ S_SERPENT_DIE8,
+ S_SERPENT_DIE9,
+ S_SERPENT_DIE10,
+ S_SERPENT_DIE11,
+ S_SERPENT_DIE12,
+ S_SERPENT_XDIE1,
+ S_SERPENT_XDIE2,
+ S_SERPENT_XDIE3,
+ S_SERPENT_XDIE4,
+ S_SERPENT_XDIE5,
+ S_SERPENT_XDIE6,
+ S_SERPENT_XDIE7,
+ S_SERPENT_XDIE8,
+ S_SERPENT_ICE,
+ S_SERPENT_ICE2,
+ S_SERPENT_FX1,
+ S_SERPENT_FX2,
+ S_SERPENT_FX3,
+ S_SERPENT_FX4,
+ S_SERPENT_FX_X1,
+ S_SERPENT_FX_X2,
+ S_SERPENT_FX_X3,
+ S_SERPENT_FX_X4,
+ S_SERPENT_FX_X5,
+ S_SERPENT_FX_X6,
+ S_SERPENT_HEAD1,
+ S_SERPENT_HEAD2,
+ S_SERPENT_HEAD3,
+ S_SERPENT_HEAD4,
+ S_SERPENT_HEAD5,
+ S_SERPENT_HEAD6,
+ S_SERPENT_HEAD7,
+ S_SERPENT_HEAD8,
+ S_SERPENT_HEAD_X1,
+ S_SERPENT_GIB1_1,
+ S_SERPENT_GIB1_2,
+ S_SERPENT_GIB1_3,
+ S_SERPENT_GIB1_4,
+ S_SERPENT_GIB1_5,
+ S_SERPENT_GIB1_6,
+ S_SERPENT_GIB1_7,
+ S_SERPENT_GIB1_8,
+ S_SERPENT_GIB1_9,
+ S_SERPENT_GIB1_10,
+ S_SERPENT_GIB1_11,
+ S_SERPENT_GIB1_12,
+ S_SERPENT_GIB2_1,
+ S_SERPENT_GIB2_2,
+ S_SERPENT_GIB2_3,
+ S_SERPENT_GIB2_4,
+ S_SERPENT_GIB2_5,
+ S_SERPENT_GIB2_6,
+ S_SERPENT_GIB2_7,
+ S_SERPENT_GIB2_8,
+ S_SERPENT_GIB2_9,
+ S_SERPENT_GIB2_10,
+ S_SERPENT_GIB2_11,
+ S_SERPENT_GIB2_12,
+ S_SERPENT_GIB3_1,
+ S_SERPENT_GIB3_2,
+ S_SERPENT_GIB3_3,
+ S_SERPENT_GIB3_4,
+ S_SERPENT_GIB3_5,
+ S_SERPENT_GIB3_6,
+ S_SERPENT_GIB3_7,
+ S_SERPENT_GIB3_8,
+ S_SERPENT_GIB3_9,
+ S_SERPENT_GIB3_10,
+ S_SERPENT_GIB3_11,
+ S_SERPENT_GIB3_12,
+ S_BISHOP_LOOK1,
+ S_BISHOP_DECIDE,
+ S_BISHOP_BLUR1,
+ S_BISHOP_BLUR2,
+ S_BISHOP_WALK1,
+ S_BISHOP_WALK2,
+ S_BISHOP_WALK3,
+ S_BISHOP_WALK4,
+ S_BISHOP_WALK5,
+ S_BISHOP_WALK6,
+ S_BISHOP_ATK1,
+ S_BISHOP_ATK2,
+ S_BISHOP_ATK3,
+ S_BISHOP_ATK4,
+ S_BISHOP_ATK5,
+ S_BISHOP_PAIN1,
+ S_BISHOP_PAIN2,
+ S_BISHOP_PAIN3,
+ S_BISHOP_PAIN4,
+ S_BISHOP_PAIN5,
+ S_BISHOP_DEATH1,
+ S_BISHOP_DEATH2,
+ S_BISHOP_DEATH3,
+ S_BISHOP_DEATH4,
+ S_BISHOP_DEATH5,
+ S_BISHOP_DEATH6,
+ S_BISHOP_DEATH7,
+ S_BISHOP_DEATH8,
+ S_BISHOP_DEATH9,
+ S_BISHOP_DEATH10,
+ S_BISHOP_ICE,
+ S_BISHOP_ICE2,
+ S_BISHOP_PUFF1,
+ S_BISHOP_PUFF2,
+ S_BISHOP_PUFF3,
+ S_BISHOP_PUFF4,
+ S_BISHOP_PUFF5,
+ S_BISHOP_PUFF6,
+ S_BISHOP_PUFF7,
+ S_BISHOPBLUR1,
+ S_BISHOPBLUR2,
+ S_BISHOPPAINBLUR1,
+ S_BISHFX1_1,
+ S_BISHFX1_2,
+ S_BISHFX1_3,
+ S_BISHFX1_4,
+ S_BISHFX1_5,
+ S_BISHFXI1_1,
+ S_BISHFXI1_2,
+ S_BISHFXI1_3,
+ S_BISHFXI1_4,
+ S_BISHFXI1_5,
+ S_BISHFXI1_6,
+ S_DRAGON_LOOK1,
+ S_DRAGON_INIT,
+ S_DRAGON_INIT2,
+ S_DRAGON_INIT3,
+ S_DRAGON_WALK1,
+ S_DRAGON_WALK2,
+ S_DRAGON_WALK3,
+ S_DRAGON_WALK4,
+ S_DRAGON_WALK5,
+ S_DRAGON_WALK6,
+ S_DRAGON_WALK7,
+ S_DRAGON_WALK8,
+ S_DRAGON_WALK9,
+ S_DRAGON_WALK10,
+ S_DRAGON_WALK11,
+ S_DRAGON_WALK12,
+ S_DRAGON_ATK1,
+ S_DRAGON_PAIN1,
+ S_DRAGON_DEATH1,
+ S_DRAGON_DEATH2,
+ S_DRAGON_DEATH3,
+ S_DRAGON_DEATH4,
+ S_DRAGON_CRASH1,
+ S_DRAGON_CRASH2,
+ S_DRAGON_CRASH3,
+ S_DRAGON_FX1_1,
+ S_DRAGON_FX1_2,
+ S_DRAGON_FX1_3,
+ S_DRAGON_FX1_4,
+ S_DRAGON_FX1_5,
+ S_DRAGON_FX1_6,
+ S_DRAGON_FX1_X1,
+ S_DRAGON_FX1_X2,
+ S_DRAGON_FX1_X3,
+ S_DRAGON_FX1_X4,
+ S_DRAGON_FX1_X5,
+ S_DRAGON_FX1_X6,
+ S_DRAGON_FX2_1,
+ S_DRAGON_FX2_2,
+ S_DRAGON_FX2_3,
+ S_DRAGON_FX2_4,
+ S_DRAGON_FX2_5,
+ S_DRAGON_FX2_6,
+ S_DRAGON_FX2_7,
+ S_DRAGON_FX2_8,
+ S_DRAGON_FX2_9,
+ S_DRAGON_FX2_10,
+ S_DRAGON_FX2_11,
+ S_ARMOR_1,
+ S_ARMOR_2,
+ S_ARMOR_3,
+ S_ARMOR_4,
+ S_MANA1_1,
+ S_MANA1_2,
+ S_MANA1_3,
+ S_MANA1_4,
+ S_MANA1_5,
+ S_MANA1_6,
+ S_MANA1_7,
+ S_MANA1_8,
+ S_MANA1_9,
+ S_MANA2_1,
+ S_MANA2_2,
+ S_MANA2_3,
+ S_MANA2_4,
+ S_MANA2_5,
+ S_MANA2_6,
+ S_MANA2_7,
+ S_MANA2_8,
+ S_MANA2_9,
+ S_MANA2_10,
+ S_MANA2_11,
+ S_MANA2_12,
+ S_MANA2_13,
+ S_MANA2_14,
+ S_MANA2_15,
+ S_MANA2_16,
+ S_MANA3_1,
+ S_MANA3_2,
+ S_MANA3_3,
+ S_MANA3_4,
+ S_MANA3_5,
+ S_MANA3_6,
+ S_MANA3_7,
+ S_MANA3_8,
+ S_MANA3_9,
+ S_MANA3_10,
+ S_MANA3_11,
+ S_MANA3_12,
+ S_MANA3_13,
+ S_MANA3_14,
+ S_MANA3_15,
+ S_MANA3_16,
+ S_KEY1,
+ S_KEY2,
+ S_KEY3,
+ S_KEY4,
+ S_KEY5,
+ S_KEY6,
+ S_KEY7,
+ S_KEY8,
+ S_KEY9,
+ S_KEYA,
+ S_KEYB,
+ S_SND_WIND1,
+ S_SND_WIND2,
+ S_SND_WATERFALL,
+ S_ETTIN_LOOK1,
+ S_ETTIN_LOOK2,
+ S_ETTIN_CHASE1,
+ S_ETTIN_CHASE2,
+ S_ETTIN_CHASE3,
+ S_ETTIN_CHASE4,
+ S_ETTIN_PAIN1,
+ S_ETTIN_ATK1_1,
+ S_ETTIN_ATK1_2,
+ S_ETTIN_ATK1_3,
+ S_ETTIN_DEATH1_1,
+ S_ETTIN_DEATH1_2,
+ S_ETTIN_DEATH1_3,
+ S_ETTIN_DEATH1_4,
+ S_ETTIN_DEATH1_5,
+ S_ETTIN_DEATH1_6,
+ S_ETTIN_DEATH1_7,
+ S_ETTIN_DEATH1_8,
+ S_ETTIN_DEATH1_9,
+ S_ETTIN_DEATH2_1,
+ S_ETTIN_DEATH2_2,
+ S_ETTIN_DEATH2_3,
+ S_ETTIN_DEATH2_4,
+ S_ETTIN_DEATH2_5,
+ S_ETTIN_DEATH2_6,
+ S_ETTIN_DEATH2_7,
+ S_ETTIN_DEATH2_8,
+ S_ETTIN_DEATH2_9,
+ S_ETTIN_DEATH2_0,
+ S_ETTIN_DEATH2_A,
+ S_ETTIN_DEATH2_B,
+ S_ETTIN_ICE1,
+ S_ETTIN_ICE2,
+ S_ETTIN_MACE1,
+ S_ETTIN_MACE2,
+ S_ETTIN_MACE3,
+ S_ETTIN_MACE4,
+ S_ETTIN_MACE5,
+ S_ETTIN_MACE6,
+ S_ETTIN_MACE7,
+ S_FIRED_SPAWN1,
+ S_FIRED_LOOK1,
+ S_FIRED_LOOK2,
+ S_FIRED_LOOK3,
+ S_FIRED_LOOK4,
+ S_FIRED_LOOK5,
+ S_FIRED_LOOK6,
+ S_FIRED_LOOK7,
+ S_FIRED_LOOK8,
+ S_FIRED_LOOK9,
+ S_FIRED_LOOK0,
+ S_FIRED_LOOKA,
+ S_FIRED_LOOKB,
+ S_FIRED_WALK1,
+ S_FIRED_WALK2,
+ S_FIRED_WALK3,
+ S_FIRED_PAIN1,
+ S_FIRED_ATTACK1,
+ S_FIRED_ATTACK2,
+ S_FIRED_ATTACK3,
+ S_FIRED_ATTACK4,
+ S_FIRED_DEATH1,
+ S_FIRED_DEATH2,
+ S_FIRED_DEATH3,
+ S_FIRED_DEATH4,
+ S_FIRED_XDEATH1,
+ S_FIRED_XDEATH2,
+ S_FIRED_XDEATH3,
+ S_FIRED_ICE1,
+ S_FIRED_ICE2,
+ S_FIRED_CORPSE1,
+ S_FIRED_CORPSE2,
+ S_FIRED_CORPSE3,
+ S_FIRED_CORPSE4,
+ S_FIRED_CORPSE5,
+ S_FIRED_CORPSE6,
+ S_FIRED_RDROP1,
+ S_FIRED_RDEAD1_1,
+ S_FIRED_RDEAD1_2,
+ S_FIRED_RDROP2,
+ S_FIRED_RDEAD2_1,
+ S_FIRED_RDEAD2_2,
+ S_FIRED_RDROP3,
+ S_FIRED_RDEAD3_1,
+ S_FIRED_RDEAD3_2,
+ S_FIRED_RDROP4,
+ S_FIRED_RDEAD4_1,
+ S_FIRED_RDEAD4_2,
+ S_FIRED_RDROP5,
+ S_FIRED_RDEAD5_1,
+ S_FIRED_RDEAD5_2,
+ S_FIRED_FX6_1,
+ S_FIRED_FX6_2,
+ S_FIRED_FX6_3,
+ S_FIRED_FX6_4,
+ S_FIRED_FX6_5,
+ S_ICEGUY_LOOK,
+ S_ICEGUY_DORMANT,
+ S_ICEGUY_WALK1,
+ S_ICEGUY_WALK2,
+ S_ICEGUY_WALK3,
+ S_ICEGUY_WALK4,
+ S_ICEGUY_ATK1,
+ S_ICEGUY_ATK2,
+ S_ICEGUY_ATK3,
+ S_ICEGUY_ATK4,
+ S_ICEGUY_PAIN1,
+ S_ICEGUY_DEATH,
+ S_ICEGUY_FX1,
+ S_ICEGUY_FX2,
+ S_ICEGUY_FX3,
+ S_ICEGUY_FX_X1,
+ S_ICEGUY_FX_X2,
+ S_ICEGUY_FX_X3,
+ S_ICEGUY_FX_X4,
+ S_ICEGUY_FX_X5,
+ S_ICEFX_PUFF1,
+ S_ICEFX_PUFF2,
+ S_ICEFX_PUFF3,
+ S_ICEFX_PUFF4,
+ S_ICEFX_PUFF5,
+ S_ICEGUY_FX2_1,
+ S_ICEGUY_FX2_2,
+ S_ICEGUY_FX2_3,
+ S_ICEGUY_BIT1,
+ S_ICEGUY_BIT2,
+ S_ICEGUY_WISP1_1,
+ S_ICEGUY_WISP1_2,
+ S_ICEGUY_WISP1_3,
+ S_ICEGUY_WISP1_4,
+ S_ICEGUY_WISP1_5,
+ S_ICEGUY_WISP1_6,
+ S_ICEGUY_WISP1_7,
+ S_ICEGUY_WISP1_8,
+ S_ICEGUY_WISP1_9,
+ S_ICEGUY_WISP2_1,
+ S_ICEGUY_WISP2_2,
+ S_ICEGUY_WISP2_3,
+ S_ICEGUY_WISP2_4,
+ S_ICEGUY_WISP2_5,
+ S_ICEGUY_WISP2_6,
+ S_ICEGUY_WISP2_7,
+ S_ICEGUY_WISP2_8,
+ S_ICEGUY_WISP2_9,
+ S_FIGHTER,
+ S_FIGHTER2,
+ S_FIGHTERLOOK,
+ S_FIGHTER_RUN1,
+ S_FIGHTER_RUN2,
+ S_FIGHTER_RUN3,
+ S_FIGHTER_RUN4,
+ S_FIGHTER_ATK1,
+ S_FIGHTER_ATK2,
+ S_FIGHTER_PAIN,
+ S_FIGHTER_PAIN2,
+ S_FIGHTER_DIE1,
+ S_FIGHTER_DIE2,
+ S_FIGHTER_DIE3,
+ S_FIGHTER_DIE4,
+ S_FIGHTER_DIE5,
+ S_FIGHTER_DIE6,
+ S_FIGHTER_DIE7,
+ S_FIGHTER_XDIE1,
+ S_FIGHTER_XDIE2,
+ S_FIGHTER_XDIE3,
+ S_FIGHTER_XDIE4,
+ S_FIGHTER_XDIE5,
+ S_FIGHTER_XDIE6,
+ S_FIGHTER_XDIE7,
+ S_FIGHTER_XDIE8,
+ S_FIGHTER_ICE,
+ S_FIGHTER_ICE2,
+ S_CLERIC,
+ S_CLERIC2,
+ S_CLERICLOOK,
+ S_CLERIC_RUN1,
+ S_CLERIC_RUN2,
+ S_CLERIC_RUN3,
+ S_CLERIC_RUN4,
+ S_CLERIC_ATK1,
+ S_CLERIC_ATK2,
+ S_CLERIC_ATK3,
+ S_CLERIC_PAIN,
+ S_CLERIC_PAIN2,
+ S_CLERIC_DIE1,
+ S_CLERIC_DIE2,
+ S_CLERIC_DIE3,
+ S_CLERIC_DIE4,
+ S_CLERIC_DIE5,
+ S_CLERIC_DIE6,
+ S_CLERIC_DIE7,
+ S_CLERIC_DIE8,
+ S_CLERIC_DIE9,
+ S_CLERIC_XDIE1,
+ S_CLERIC_XDIE2,
+ S_CLERIC_XDIE3,
+ S_CLERIC_XDIE4,
+ S_CLERIC_XDIE5,
+ S_CLERIC_XDIE6,
+ S_CLERIC_XDIE7,
+ S_CLERIC_XDIE8,
+ S_CLERIC_XDIE9,
+ S_CLERIC_XDIE10,
+ S_CLERIC_ICE,
+ S_CLERIC_ICE2,
+ S_MAGE,
+ S_MAGE2,
+ S_MAGELOOK,
+ S_MAGE_RUN1,
+ S_MAGE_RUN2,
+ S_MAGE_RUN3,
+ S_MAGE_RUN4,
+ S_MAGE_ATK1,
+ S_MAGE_ATK2,
+ S_MAGE_PAIN,
+ S_MAGE_PAIN2,
+ S_MAGE_DIE1,
+ S_MAGE_DIE2,
+ S_MAGE_DIE3,
+ S_MAGE_DIE4,
+ S_MAGE_DIE5,
+ S_MAGE_DIE6,
+ S_MAGE_DIE7,
+ S_MAGE_XDIE1,
+ S_MAGE_XDIE2,
+ S_MAGE_XDIE3,
+ S_MAGE_XDIE4,
+ S_MAGE_XDIE5,
+ S_MAGE_XDIE6,
+ S_MAGE_XDIE7,
+ S_MAGE_XDIE8,
+ S_MAGE_XDIE9,
+ S_MAGE_ICE,
+ S_MAGE_ICE2,
+ S_SORC_SPAWN1,
+ S_SORC_SPAWN2,
+ S_SORC_LOOK1,
+ S_SORC_WALK1,
+ S_SORC_WALK2,
+ S_SORC_WALK3,
+ S_SORC_WALK4,
+ S_SORC_PAIN1,
+ S_SORC_PAIN2,
+ S_SORC_ATK2_1,
+ S_SORC_ATK2_2,
+ S_SORC_ATK2_3,
+ S_SORC_ATTACK1,
+ S_SORC_ATTACK2,
+ S_SORC_ATTACK3,
+ S_SORC_ATTACK4,
+ S_SORC_ATTACK5,
+ S_SORC_DIE1,
+ S_SORC_DIE2,
+ S_SORC_DIE3,
+ S_SORC_DIE4,
+ S_SORC_DIE5,
+ S_SORC_DIE6,
+ S_SORC_DIE7,
+ S_SORC_DIE8,
+ S_SORC_DIE9,
+ S_SORC_DIE0,
+ S_SORC_DIEA,
+ S_SORC_DIEB,
+ S_SORC_DIEC,
+ S_SORC_DIED,
+ S_SORC_DIEE,
+ S_SORC_DIEF,
+ S_SORC_DIEG,
+ S_SORC_DIEH,
+ S_SORC_DIEI,
+ S_SORCBALL1_1,
+ S_SORCBALL1_2,
+ S_SORCBALL1_3,
+ S_SORCBALL1_4,
+ S_SORCBALL1_5,
+ S_SORCBALL1_6,
+ S_SORCBALL1_7,
+ S_SORCBALL1_8,
+ S_SORCBALL1_9,
+ S_SORCBALL1_0,
+ S_SORCBALL1_A,
+ S_SORCBALL1_B,
+ S_SORCBALL1_C,
+ S_SORCBALL1_D,
+ S_SORCBALL1_E,
+ S_SORCBALL1_F,
+ S_SORCBALL1_D1,
+ S_SORCBALL1_D2,
+ S_SORCBALL1_D5,
+ S_SORCBALL1_D6,
+ S_SORCBALL1_D7,
+ S_SORCBALL1_D8,
+ S_SORCBALL1_D9,
+ S_SORCBALL2_1,
+ S_SORCBALL2_2,
+ S_SORCBALL2_3,
+ S_SORCBALL2_4,
+ S_SORCBALL2_5,
+ S_SORCBALL2_6,
+ S_SORCBALL2_7,
+ S_SORCBALL2_8,
+ S_SORCBALL2_9,
+ S_SORCBALL2_0,
+ S_SORCBALL2_A,
+ S_SORCBALL2_B,
+ S_SORCBALL2_C,
+ S_SORCBALL2_D,
+ S_SORCBALL2_E,
+ S_SORCBALL2_F,
+ S_SORCBALL2_D1,
+ S_SORCBALL2_D2,
+ S_SORCBALL2_D5,
+ S_SORCBALL2_D6,
+ S_SORCBALL2_D7,
+ S_SORCBALL2_D8,
+ S_SORCBALL2_D9,
+ S_SORCBALL3_1,
+ S_SORCBALL3_2,
+ S_SORCBALL3_3,
+ S_SORCBALL3_4,
+ S_SORCBALL3_5,
+ S_SORCBALL3_6,
+ S_SORCBALL3_7,
+ S_SORCBALL3_8,
+ S_SORCBALL3_9,
+ S_SORCBALL3_0,
+ S_SORCBALL3_A,
+ S_SORCBALL3_B,
+ S_SORCBALL3_C,
+ S_SORCBALL3_D,
+ S_SORCBALL3_E,
+ S_SORCBALL3_F,
+ S_SORCBALL3_D1,
+ S_SORCBALL3_D2,
+ S_SORCBALL3_D5,
+ S_SORCBALL3_D6,
+ S_SORCBALL3_D7,
+ S_SORCBALL3_D8,
+ S_SORCBALL3_D9,
+ S_SORCFX1_1,
+ S_SORCFX1_2,
+ S_SORCFX1_3,
+ S_SORCFX1_4,
+ S_SORCFX1_D1,
+ S_SORCFX1_D2,
+ S_SORCFX1_D3,
+ S_SORCFX2_SPLIT1,
+ S_SORCFX2_ORBIT1,
+ S_SORCFX2_ORBIT2,
+ S_SORCFX2_ORBIT3,
+ S_SORCFX2_ORBIT4,
+ S_SORCFX2_ORBIT5,
+ S_SORCFX2_ORBIT6,
+ S_SORCFX2_ORBIT7,
+ S_SORCFX2_ORBIT8,
+ S_SORCFX2_ORBIT9,
+ S_SORCFX2_ORBIT0,
+ S_SORCFX2_ORBITA,
+ S_SORCFX2_ORBITB,
+ S_SORCFX2_ORBITC,
+ S_SORCFX2_ORBITD,
+ S_SORCFX2_ORBITE,
+ S_SORCFX2_ORBITF,
+ S_SORCFX2T1,
+ S_SORCFX3_1,
+ S_SORCFX3_2,
+ S_SORCFX3_3,
+ S_BISHMORPH1,
+ S_BISHMORPHA,
+ S_BISHMORPHB,
+ S_BISHMORPHC,
+ S_BISHMORPHD,
+ S_BISHMORPHE,
+ S_BISHMORPHF,
+ S_BISHMORPHG,
+ S_BISHMORPHH,
+ S_BISHMORPHI,
+ S_BISHMORPHJ,
+ S_SORCFX3_EXP1,
+ S_SORCFX3_EXP2,
+ S_SORCFX3_EXP3,
+ S_SORCFX3_EXP4,
+ S_SORCFX3_EXP5,
+ S_SORCFX4_1,
+ S_SORCFX4_2,
+ S_SORCFX4_3,
+ S_SORCFX4_D1,
+ S_SORCFX4_D2,
+ S_SORCFX4_D3,
+ S_SORCFX4_D4,
+ S_SORCFX4_D5,
+ S_SORCSPARK1,
+ S_SORCSPARK2,
+ S_SORCSPARK3,
+ S_SORCSPARK4,
+ S_SORCSPARK5,
+ S_SORCSPARK6,
+ S_SORCSPARK7,
+ S_BLASTEFFECT1,
+ S_BLASTEFFECT2,
+ S_BLASTEFFECT3,
+ S_BLASTEFFECT4,
+ S_BLASTEFFECT5,
+ S_BLASTEFFECT6,
+ S_BLASTEFFECT7,
+ S_BLASTEFFECT8,
+ S_BLASTEFFECT9,
+ S_WATERDRIP1,
+ S_KORAX_LOOK1,
+ S_KORAX_CHASE1,
+ S_KORAX_CHASE2,
+ S_KORAX_CHASE3,
+ S_KORAX_CHASE4,
+ S_KORAX_CHASE5,
+ S_KORAX_CHASE6,
+ S_KORAX_CHASE7,
+ S_KORAX_CHASE8,
+ S_KORAX_CHASE9,
+ S_KORAX_CHASE0,
+ S_KORAX_CHASEA,
+ S_KORAX_CHASEB,
+ S_KORAX_CHASEC,
+ S_KORAX_CHASED,
+ S_KORAX_CHASEE,
+ S_KORAX_CHASEF,
+ S_KORAX_PAIN1,
+ S_KORAX_PAIN2,
+ S_KORAX_ATTACK1,
+ S_KORAX_ATTACK2,
+ S_KORAX_MISSILE1,
+ S_KORAX_MISSILE2,
+ S_KORAX_MISSILE3,
+ S_KORAX_COMMAND1,
+ S_KORAX_COMMAND2,
+ S_KORAX_COMMAND3,
+ S_KORAX_COMMAND4,
+ S_KORAX_COMMAND5,
+ S_KORAX_DEATH1,
+ S_KORAX_DEATH2,
+ S_KORAX_DEATH3,
+ S_KORAX_DEATH4,
+ S_KORAX_DEATH5,
+ S_KORAX_DEATH6,
+ S_KORAX_DEATH7,
+ S_KORAX_DEATH8,
+ S_KORAX_DEATH9,
+ S_KORAX_DEATH0,
+ S_KORAX_DEATHA,
+ S_KORAX_DEATHB,
+ S_KORAX_DEATHC,
+ S_KORAX_DEATHD,
+ S_KSPIRIT_ROAM1,
+ S_KSPIRIT_ROAM2,
+ S_KSPIRIT_DEATH1,
+ S_KSPIRIT_DEATH2,
+ S_KSPIRIT_DEATH3,
+ S_KSPIRIT_DEATH4,
+ S_KSPIRIT_DEATH5,
+ S_KSPIRIT_DEATH6,
+ S_KBOLT1,
+ S_KBOLT2,
+ S_KBOLT3,
+ S_KBOLT4,
+ S_KBOLT5,
+ S_KBOLT6,
+ S_KBOLT7,
+ S_SPAWNBATS1,
+ S_SPAWNBATS2,
+ S_SPAWNBATS3,
+ S_SPAWNBATS_OFF,
+ S_BAT1,
+ S_BAT2,
+ S_BAT3,
+ S_BAT_DEATH,
+ NUMSTATES
+} statenum_t;
+
+typedef struct
+{
+ spritenum_t sprite;
+ int frame;
+ int tics;
+ void (*action) ();
+ statenum_t nextstate;
+ int misc1, misc2;
+} state_t;
+
+extern state_t states[NUMSTATES];
+extern char *sprnames[];
+
+
+
+typedef enum
+{
+ MT_MAPSPOT,
+ MT_MAPSPOTGRAVITY,
+ MT_FIREBALL1,
+ MT_ARROW,
+ MT_DART,
+ MT_POISONDART,
+ MT_RIPPERBALL,
+ MT_PROJECTILE_BLADE,
+ MT_ICESHARD,
+ MT_FLAME_SMALL_TEMP,
+ MT_FLAME_LARGE_TEMP,
+ MT_FLAME_SMALL,
+ MT_FLAME_LARGE,
+ MT_HEALINGBOTTLE,
+ MT_HEALTHFLASK,
+ MT_ARTIFLY,
+ MT_ARTIINVULNERABILITY,
+ MT_SUMMONMAULATOR,
+ MT_SUMMON_FX,
+ MT_THRUSTFLOOR_UP,
+ MT_THRUSTFLOOR_DOWN,
+ MT_TELEPORTOTHER,
+ MT_TELOTHER_FX1,
+ MT_TELOTHER_FX2,
+ MT_TELOTHER_FX3,
+ MT_TELOTHER_FX4,
+ MT_TELOTHER_FX5,
+ MT_DIRT1,
+ MT_DIRT2,
+ MT_DIRT3,
+ MT_DIRT4,
+ MT_DIRT5,
+ MT_DIRT6,
+ MT_DIRTCLUMP,
+ MT_ROCK1,
+ MT_ROCK2,
+ MT_ROCK3,
+ MT_FOGSPAWNER,
+ MT_FOGPATCHS,
+ MT_FOGPATCHM,
+ MT_FOGPATCHL,
+ MT_QUAKE_FOCUS,
+ MT_SGSHARD1,
+ MT_SGSHARD2,
+ MT_SGSHARD3,
+ MT_SGSHARD4,
+ MT_SGSHARD5,
+ MT_SGSHARD6,
+ MT_SGSHARD7,
+ MT_SGSHARD8,
+ MT_SGSHARD9,
+ MT_SGSHARD0,
+ MT_ARTIEGG,
+ MT_EGGFX,
+ MT_ARTISUPERHEAL,
+ MT_ZWINGEDSTATUENOSKULL,
+ MT_ZGEMPEDESTAL,
+ MT_ARTIPUZZSKULL,
+ MT_ARTIPUZZGEMBIG,
+ MT_ARTIPUZZGEMRED,
+ MT_ARTIPUZZGEMGREEN1,
+ MT_ARTIPUZZGEMGREEN2,
+ MT_ARTIPUZZGEMBLUE1,
+ MT_ARTIPUZZGEMBLUE2,
+ MT_ARTIPUZZBOOK1,
+ MT_ARTIPUZZBOOK2,
+ MT_ARTIPUZZSKULL2,
+ MT_ARTIPUZZFWEAPON,
+ MT_ARTIPUZZCWEAPON,
+ MT_ARTIPUZZMWEAPON,
+ MT_ARTIPUZZGEAR,
+ MT_ARTIPUZZGEAR2,
+ MT_ARTIPUZZGEAR3,
+ MT_ARTIPUZZGEAR4,
+ MT_ARTITORCH,
+ MT_FIREBOMB,
+ MT_ARTITELEPORT,
+ MT_ARTIPOISONBAG,
+ MT_POISONBAG,
+ MT_POISONCLOUD,
+ MT_THROWINGBOMB,
+ MT_SPEEDBOOTS,
+ MT_BOOSTMANA,
+ MT_BOOSTARMOR,
+ MT_BLASTRADIUS,
+ MT_HEALRADIUS,
+ MT_SPLASH,
+ MT_SPLASHBASE,
+ MT_LAVASPLASH,
+ MT_LAVASMOKE,
+ MT_SLUDGECHUNK,
+ MT_SLUDGESPLASH,
+ MT_MISC0,
+ MT_MISC1,
+ MT_MISC2,
+ MT_MISC3,
+ MT_MISC4,
+ MT_MISC5,
+ MT_MISC6,
+ MT_MISC7,
+ MT_MISC8,
+ MT_TREEDESTRUCTIBLE,
+ MT_MISC9,
+ MT_MISC10,
+ MT_MISC11,
+ MT_MISC12,
+ MT_MISC13,
+ MT_MISC14,
+ MT_MISC15,
+ MT_MISC16,
+ MT_MISC17,
+ MT_MISC18,
+ MT_MISC19,
+ MT_MISC20,
+ MT_MISC21,
+ MT_MISC22,
+ MT_MISC23,
+ MT_MISC24,
+ MT_MISC25,
+ MT_MISC26,
+ MT_MISC27,
+ MT_MISC28,
+ MT_MISC29,
+ MT_MISC30,
+ MT_MISC31,
+ MT_MISC32,
+ MT_MISC33,
+ MT_MISC34,
+ MT_MISC35,
+ MT_MISC36,
+ MT_MISC37,
+ MT_MISC38,
+ MT_MISC39,
+ MT_MISC40,
+ MT_MISC41,
+ MT_MISC42,
+ MT_MISC43,
+ MT_MISC44,
+ MT_MISC45,
+ MT_MISC46,
+ MT_MISC47,
+ MT_MISC48,
+ MT_MISC49,
+ MT_MISC50,
+ MT_MISC51,
+ MT_MISC52,
+ MT_MISC53,
+ MT_MISC54,
+ MT_MISC55,
+ MT_MISC56,
+ MT_MISC57,
+ MT_MISC58,
+ MT_MISC59,
+ MT_MISC60,
+ MT_MISC61,
+ MT_MISC62,
+ MT_MISC63,
+ MT_MISC64,
+ MT_MISC65,
+ MT_MISC66,
+ MT_MISC67,
+ MT_MISC68,
+ MT_MISC69,
+ MT_MISC70,
+ MT_MISC71,
+ MT_MISC72,
+ MT_MISC73,
+ MT_MISC74,
+ MT_MISC75,
+ MT_MISC76,
+ MT_POTTERY1,
+ MT_POTTERY2,
+ MT_POTTERY3,
+ MT_POTTERYBIT1,
+ MT_MISC77,
+ MT_ZLYNCHED_NOHEART,
+ MT_MISC78,
+ MT_CORPSEBIT,
+ MT_CORPSEBLOODDRIP,
+ MT_BLOODPOOL,
+ MT_MISC79,
+ MT_MISC80,
+ MT_LEAF1,
+ MT_LEAF2,
+ MT_ZTWINEDTORCH,
+ MT_ZTWINEDTORCH_UNLIT,
+ MT_BRIDGE,
+ MT_BRIDGEBALL,
+ MT_ZWALLTORCH,
+ MT_ZWALLTORCH_UNLIT,
+ MT_ZBARREL,
+ MT_ZSHRUB1,
+ MT_ZSHRUB2,
+ MT_ZBUCKET,
+ MT_ZPOISONSHROOM,
+ MT_ZFIREBULL,
+ MT_ZFIREBULL_UNLIT,
+ MT_FIRETHING,
+ MT_BRASSTORCH,
+ MT_ZSUITOFARMOR,
+ MT_ZARMORCHUNK,
+ MT_ZBELL,
+ MT_ZBLUE_CANDLE,
+ MT_ZIRON_MAIDEN,
+ MT_ZXMAS_TREE,
+ MT_ZCAULDRON,
+ MT_ZCAULDRON_UNLIT,
+ MT_ZCHAINBIT32,
+ MT_ZCHAINBIT64,
+ MT_ZCHAINEND_HEART,
+ MT_ZCHAINEND_HOOK1,
+ MT_ZCHAINEND_HOOK2,
+ MT_ZCHAINEND_SPIKE,
+ MT_ZCHAINEND_SKULL,
+ MT_TABLE_SHIT1,
+ MT_TABLE_SHIT2,
+ MT_TABLE_SHIT3,
+ MT_TABLE_SHIT4,
+ MT_TABLE_SHIT5,
+ MT_TABLE_SHIT6,
+ MT_TABLE_SHIT7,
+ MT_TABLE_SHIT8,
+ MT_TABLE_SHIT9,
+ MT_TABLE_SHIT10,
+ MT_TFOG,
+ MT_MISC81,
+ MT_TELEPORTMAN,
+ MT_PUNCHPUFF,
+ MT_FW_AXE,
+ MT_AXEPUFF,
+ MT_AXEPUFF_GLOW,
+ MT_AXEBLOOD,
+ MT_FW_HAMMER,
+ MT_HAMMER_MISSILE,
+ MT_HAMMERPUFF,
+ MT_FSWORD_MISSILE,
+ MT_FSWORD_FLAME,
+ MT_CW_SERPSTAFF,
+ MT_CSTAFF_MISSILE,
+ MT_CSTAFFPUFF,
+ MT_CW_FLAME,
+ MT_CFLAMEFLOOR,
+ MT_FLAMEPUFF,
+ MT_FLAMEPUFF2,
+ MT_CIRCLEFLAME,
+ MT_CFLAME_MISSILE,
+ MT_HOLY_FX,
+ MT_HOLY_TAIL,
+ MT_HOLY_PUFF,
+ MT_HOLY_MISSILE,
+ MT_HOLY_MISSILE_PUFF,
+ MT_MWANDPUFF,
+ MT_MWANDSMOKE,
+ MT_MWAND_MISSILE,
+ MT_MW_LIGHTNING,
+ MT_LIGHTNING_CEILING,
+ MT_LIGHTNING_FLOOR,
+ MT_LIGHTNING_ZAP,
+ MT_MSTAFF_FX,
+ MT_MSTAFF_FX2,
+ MT_FW_SWORD1,
+ MT_FW_SWORD2,
+ MT_FW_SWORD3,
+ MT_CW_HOLY1,
+ MT_CW_HOLY2,
+ MT_CW_HOLY3,
+ MT_MW_STAFF1,
+ MT_MW_STAFF2,
+ MT_MW_STAFF3,
+ MT_SNOUTPUFF,
+ MT_MW_CONE,
+ MT_SHARDFX1,
+ MT_BLOOD,
+ MT_BLOODSPLATTER,
+ MT_GIBS,
+ MT_PLAYER_FIGHTER,
+ MT_BLOODYSKULL,
+ MT_PLAYER_SPEED,
+ MT_ICECHUNK,
+ MT_PLAYER_CLERIC,
+ MT_PLAYER_MAGE,
+ MT_PIGPLAYER,
+ MT_PIG,
+ MT_CENTAUR,
+ MT_CENTAURLEADER,
+ MT_CENTAUR_FX,
+ MT_CENTAUR_SHIELD,
+ MT_CENTAUR_SWORD,
+ MT_DEMON,
+ MT_DEMONCHUNK1,
+ MT_DEMONCHUNK2,
+ MT_DEMONCHUNK3,
+ MT_DEMONCHUNK4,
+ MT_DEMONCHUNK5,
+ MT_DEMONFX1,
+ MT_DEMON2,
+ MT_DEMON2CHUNK1,
+ MT_DEMON2CHUNK2,
+ MT_DEMON2CHUNK3,
+ MT_DEMON2CHUNK4,
+ MT_DEMON2CHUNK5,
+ MT_DEMON2FX1,
+ MT_WRAITHB,
+ MT_WRAITH,
+ MT_WRAITHFX1,
+ MT_WRAITHFX2,
+ MT_WRAITHFX3,
+ MT_WRAITHFX4,
+ MT_WRAITHFX5,
+ MT_MINOTAUR,
+ MT_MNTRFX1,
+ MT_MNTRFX2,
+ MT_MNTRFX3,
+ MT_MNTRSMOKE,
+ MT_MNTRSMOKEEXIT,
+ MT_SERPENT,
+ MT_SERPENTLEADER,
+ MT_SERPENTFX,
+ MT_SERPENT_HEAD,
+ MT_SERPENT_GIB1,
+ MT_SERPENT_GIB2,
+ MT_SERPENT_GIB3,
+ MT_BISHOP,
+ MT_BISHOP_PUFF,
+ MT_BISHOPBLUR,
+ MT_BISHOPPAINBLUR,
+ MT_BISH_FX,
+ MT_DRAGON,
+ MT_DRAGON_FX,
+ MT_DRAGON_FX2,
+ MT_ARMOR_1,
+ MT_ARMOR_2,
+ MT_ARMOR_3,
+ MT_ARMOR_4,
+ MT_MANA1,
+ MT_MANA2,
+ MT_MANA3,
+ MT_KEY1,
+ MT_KEY2,
+ MT_KEY3,
+ MT_KEY4,
+ MT_KEY5,
+ MT_KEY6,
+ MT_KEY7,
+ MT_KEY8,
+ MT_KEY9,
+ MT_KEYA,
+ MT_KEYB,
+ MT_SOUNDWIND,
+ MT_SOUNDWATERFALL,
+ MT_ETTIN,
+ MT_ETTIN_MACE,
+ MT_FIREDEMON,
+ MT_FIREDEMON_SPLOTCH1,
+ MT_FIREDEMON_SPLOTCH2,
+ MT_FIREDEMON_FX1,
+ MT_FIREDEMON_FX2,
+ MT_FIREDEMON_FX3,
+ MT_FIREDEMON_FX4,
+ MT_FIREDEMON_FX5,
+ MT_FIREDEMON_FX6,
+ MT_ICEGUY,
+ MT_ICEGUY_FX,
+ MT_ICEFX_PUFF,
+ MT_ICEGUY_FX2,
+ MT_ICEGUY_BIT,
+ MT_ICEGUY_WISP1,
+ MT_ICEGUY_WISP2,
+ MT_FIGHTER_BOSS,
+ MT_CLERIC_BOSS,
+ MT_MAGE_BOSS,
+ MT_SORCBOSS,
+ MT_SORCBALL1,
+ MT_SORCBALL2,
+ MT_SORCBALL3,
+ MT_SORCFX1,
+ MT_SORCFX2,
+ MT_SORCFX2_T1,
+ MT_SORCFX3,
+ MT_SORCFX3_EXPLOSION,
+ MT_SORCFX4,
+ MT_SORCSPARK1,
+ MT_BLASTEFFECT,
+ MT_WATER_DRIP,
+ MT_KORAX,
+ MT_KORAX_SPIRIT1,
+ MT_KORAX_SPIRIT2,
+ MT_KORAX_SPIRIT3,
+ MT_KORAX_SPIRIT4,
+ MT_KORAX_SPIRIT5,
+ MT_KORAX_SPIRIT6,
+ MT_DEMON_MASH,
+ MT_DEMON2_MASH,
+ MT_ETTIN_MASH,
+ MT_CENTAUR_MASH,
+ MT_KORAX_BOLT,
+ MT_BAT_SPAWNER,
+ MT_BAT,
+ NUMMOBJTYPES
+} mobjtype_t;
+
+typedef struct
+{
+ int doomednum;
+ int spawnstate;
+ int spawnhealth;
+ int seestate;
+ int seesound;
+ int reactiontime;
+ int attacksound;
+ int painstate;
+ int painchance;
+ int painsound;
+ int meleestate;
+ int missilestate;
+ int crashstate;
+ int deathstate;
+ int xdeathstate;
+ int deathsound;
+ int speed;
+ int radius;
+ int height;
+ int mass;
+ int damage;
+ int activesound;
+ int flags;
+ int flags2;
+} mobjinfo_t;
+
+extern mobjinfo_t mobjinfo[NUMMOBJTYPES];
diff --git a/src/hexen/m_misc.c b/src/hexen/m_misc.c
new file mode 100644
index 00000000..dee6bd56
--- /dev/null
+++ b/src/hexen/m_misc.c
@@ -0,0 +1,29 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2def.h"
+
diff --git a/src/hexen/m_random.c b/src/hexen/m_random.c
new file mode 100644
index 00000000..1496490f
--- /dev/null
+++ b/src/hexen/m_random.c
@@ -0,0 +1,82 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "m_random.h"
+
+// This is the new flat distribution table
+
+static const unsigned char rndtable[256] = {
+ 201, 1, 243, 19, 18, 42, 183, 203, 101, 123, 154, 137, 34, 118, 10, 216,
+ 135, 246, 0, 107, 133, 229, 35, 113, 177, 211, 110, 17, 139, 84, 251, 235,
+ 182, 166, 161, 230, 143, 91, 24, 81, 22, 94, 7, 51, 232, 104, 122, 248,
+ 175, 138, 127, 171, 222, 213, 44, 16, 9, 33, 88, 102, 170, 150, 136, 114,
+ 62, 3, 142, 237, 6, 252, 249, 56, 74, 30, 13, 21, 180, 199, 32, 132,
+ 187, 234, 78, 210, 46, 131, 197, 8, 206, 244, 73, 4, 236, 178, 195, 70,
+ 121, 97, 167, 217, 103, 40, 247, 186, 105, 39, 95, 163, 99, 149, 253, 29,
+ 119, 83, 254, 26, 202, 65, 130, 155, 60, 64, 184, 106, 221, 93, 164, 196,
+ 112, 108, 179, 141, 54, 109, 11, 126, 75, 165, 191, 227, 87, 225, 156, 15,
+ 98, 162, 116, 79, 169, 140, 190, 205, 168, 194, 41, 250, 27, 20, 14, 241,
+ 50, 214, 72, 192, 220, 233, 67, 148, 96, 185, 176, 181, 215, 207, 172, 85,
+ 89, 90, 209, 128, 124, 2, 55, 173, 66, 152, 47, 129, 59, 43, 159, 240,
+ 239, 12, 189, 212, 144, 28, 200, 77, 219, 198, 134, 228, 45, 92, 125, 151,
+ 5, 53, 255, 52, 68, 245, 160, 158, 61, 86, 58, 82, 117, 37, 242, 145,
+ 69, 188, 115, 76, 63, 100, 49, 111, 153, 80, 38, 57, 174, 224, 71, 231,
+ 23, 25, 48, 218, 120, 147, 208, 36, 226, 223, 193, 238, 157, 204, 146, 31
+};
+
+
+int rndindex = 0;
+int prndindex = 0;
+
+/*
+===============
+=
+= M_Random
+=
+= Returns a 0-255 number
+=
+===============
+*/
+
+
+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;
+}
+
diff --git a/src/hexen/m_random.h b/src/hexen/m_random.h
new file mode 100644
index 00000000..582bcfa7
--- /dev/null
+++ b/src/hexen/m_random.h
@@ -0,0 +1,42 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef HEXEN_M_RANDOM_H
+#define HEXEN_M_RANDOM_H
+
+// Most damage defined using HITDICE
+#define HITDICE(a) ((1+(P_Random()&7))*a)
+
+int M_Random(void);
+// returns a number from 0 to 255
+int P_Random(void);
+// as M_Random, but used only by the play simulation
+
+void M_ClearRandom(void);
+// fix randoms for demos
+
+extern int rndindex;
+
+#endif // HEXEN_M_RANDOM_H
+
diff --git a/src/hexen/mn_menu.c b/src/hexen/mn_menu.c
new file mode 100644
index 00000000..3d068b0e
--- /dev/null
+++ b/src/hexen/mn_menu.c
@@ -0,0 +1,1784 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+// HEADER FILES ------------------------------------------------------------
+
+#include <ctype.h>
+#include "h2def.h"
+#include "doomkeys.h"
+#include "i_system.h"
+#include "i_swap.h"
+#include "i_video.h"
+#include "m_controls.h"
+#include "p_local.h"
+#include "r_local.h"
+#include "s_sound.h"
+#include "v_video.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define LEFT_DIR 0
+#define RIGHT_DIR 1
+#define ITEM_HEIGHT 20
+#define SELECTOR_XOFFSET (-28)
+#define SELECTOR_YOFFSET (-1)
+#define SLOTTEXTLEN 16
+#define ASCII_CURSOR '['
+
+// TYPES -------------------------------------------------------------------
+
+typedef enum
+{
+ ITT_EMPTY,
+ ITT_EFUNC,
+ ITT_LRFUNC,
+ ITT_SETMENU,
+ ITT_INERT
+} ItemType_t;
+
+typedef enum
+{
+ MENU_MAIN,
+ MENU_CLASS,
+ MENU_SKILL,
+ MENU_OPTIONS,
+ MENU_OPTIONS2,
+ MENU_FILES,
+ MENU_LOAD,
+ MENU_SAVE,
+ MENU_NONE
+} MenuType_t;
+
+typedef struct
+{
+ ItemType_t type;
+ char *text;
+ void (*func) (int option);
+ int option;
+ MenuType_t menu;
+} MenuItem_t;
+
+typedef struct
+{
+ int x;
+ int y;
+ void (*drawFunc) (void);
+ int itemCount;
+ MenuItem_t *items;
+ int oldItPos;
+ MenuType_t prevMenu;
+} Menu_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void InitFonts(void);
+static void SetMenu(MenuType_t menu);
+static void SCQuitGame(int option);
+static void SCClass(int option);
+static void SCSkill(int option);
+static void SCMouseSensi(int option);
+static void SCSfxVolume(int option);
+static void SCMusicVolume(int option);
+static void SCScreenSize(int option);
+static boolean SCNetCheck(int option);
+static void SCNetCheck2(int option);
+static void SCLoadGame(int option);
+static void SCSaveGame(int option);
+static void SCMessages(int option);
+static void SCEndGame(int option);
+static void SCInfo(int option);
+static void DrawMainMenu(void);
+static void DrawClassMenu(void);
+static void DrawSkillMenu(void);
+static void DrawOptionsMenu(void);
+static void DrawOptions2Menu(void);
+static void DrawFileSlots(Menu_t * menu);
+static void DrawFilesMenu(void);
+static void MN_DrawInfo(void);
+static void DrawLoadMenu(void);
+static void DrawSaveMenu(void);
+static void DrawSlider(Menu_t * menu, int item, int width, int slot);
+void MN_LoadSlotText(void);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern int detailLevel;
+extern boolean gamekeydown[256]; // The NUMKEYS macro is local to g_game
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+boolean MenuActive;
+int InfoType;
+int messageson = true;
+boolean mn_SuicideConsole;
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static int FontABaseLump;
+static int FontAYellowBaseLump;
+static int FontBBaseLump;
+static int MauloBaseLump;
+static Menu_t *CurrentMenu;
+static int CurrentItPos;
+static int MenuPClass;
+static int MenuTime;
+static boolean soundchanged;
+
+boolean askforquit;
+static int typeofask;
+static boolean FileMenuKeySteal;
+static boolean slottextloaded;
+static char SlotText[6][SLOTTEXTLEN + 2];
+static char oldSlotText[SLOTTEXTLEN + 2];
+static int SlotStatus[6];
+static int slotptr;
+static int currentSlot;
+static int quicksave;
+static int quickload;
+
+static MenuItem_t MainItems[] = {
+ {ITT_SETMENU, "NEW GAME", SCNetCheck2, 1, MENU_CLASS},
+ {ITT_SETMENU, "OPTIONS", NULL, 0, MENU_OPTIONS},
+ {ITT_SETMENU, "GAME FILES", NULL, 0, MENU_FILES},
+ {ITT_EFUNC, "INFO", SCInfo, 0, MENU_NONE},
+ {ITT_EFUNC, "QUIT GAME", SCQuitGame, 0, MENU_NONE}
+};
+
+static Menu_t MainMenu = {
+ 110, 56,
+ DrawMainMenu,
+ 5, MainItems,
+ 0,
+ MENU_NONE
+};
+
+static MenuItem_t ClassItems[] = {
+ {ITT_EFUNC, "FIGHTER", SCClass, 0, MENU_NONE},
+ {ITT_EFUNC, "CLERIC", SCClass, 1, MENU_NONE},
+ {ITT_EFUNC, "MAGE", SCClass, 2, MENU_NONE}
+};
+
+static Menu_t ClassMenu = {
+ 66, 66,
+ DrawClassMenu,
+ 3, ClassItems,
+ 0,
+ MENU_MAIN
+};
+
+static MenuItem_t FilesItems[] = {
+ {ITT_SETMENU, "LOAD GAME", SCNetCheck2, 2, MENU_LOAD},
+ {ITT_SETMENU, "SAVE GAME", NULL, 0, MENU_SAVE}
+};
+
+static Menu_t FilesMenu = {
+ 110, 60,
+ DrawFilesMenu,
+ 2, FilesItems,
+ 0,
+ MENU_MAIN
+};
+
+static MenuItem_t LoadItems[] = {
+ {ITT_EFUNC, NULL, SCLoadGame, 0, MENU_NONE},
+ {ITT_EFUNC, NULL, SCLoadGame, 1, MENU_NONE},
+ {ITT_EFUNC, NULL, SCLoadGame, 2, MENU_NONE},
+ {ITT_EFUNC, NULL, SCLoadGame, 3, MENU_NONE},
+ {ITT_EFUNC, NULL, SCLoadGame, 4, MENU_NONE},
+ {ITT_EFUNC, NULL, SCLoadGame, 5, MENU_NONE}
+};
+
+static Menu_t LoadMenu = {
+ 70, 30,
+ DrawLoadMenu,
+ 6, LoadItems,
+ 0,
+ MENU_FILES
+};
+
+static MenuItem_t SaveItems[] = {
+ {ITT_EFUNC, NULL, SCSaveGame, 0, MENU_NONE},
+ {ITT_EFUNC, NULL, SCSaveGame, 1, MENU_NONE},
+ {ITT_EFUNC, NULL, SCSaveGame, 2, MENU_NONE},
+ {ITT_EFUNC, NULL, SCSaveGame, 3, MENU_NONE},
+ {ITT_EFUNC, NULL, SCSaveGame, 4, MENU_NONE},
+ {ITT_EFUNC, NULL, SCSaveGame, 5, MENU_NONE}
+};
+
+static Menu_t SaveMenu = {
+ 70, 30,
+ DrawSaveMenu,
+ 6, SaveItems,
+ 0,
+ MENU_FILES
+};
+
+static MenuItem_t SkillItems[] = {
+ {ITT_EFUNC, NULL, SCSkill, sk_baby, MENU_NONE},
+ {ITT_EFUNC, NULL, SCSkill, sk_easy, MENU_NONE},
+ {ITT_EFUNC, NULL, SCSkill, sk_medium, MENU_NONE},
+ {ITT_EFUNC, NULL, SCSkill, sk_hard, MENU_NONE},
+ {ITT_EFUNC, NULL, SCSkill, sk_nightmare, MENU_NONE}
+};
+
+static Menu_t SkillMenu = {
+ 120, 44,
+ DrawSkillMenu,
+ 5, SkillItems,
+ 2,
+ MENU_CLASS
+};
+
+static MenuItem_t OptionsItems[] = {
+ {ITT_EFUNC, "END GAME", SCEndGame, 0, MENU_NONE},
+ {ITT_EFUNC, "MESSAGES : ", SCMessages, 0, MENU_NONE},
+ {ITT_LRFUNC, "MOUSE SENSITIVITY", SCMouseSensi, 0, MENU_NONE},
+ {ITT_EMPTY, NULL, NULL, 0, MENU_NONE},
+ {ITT_SETMENU, "MORE...", NULL, 0, MENU_OPTIONS2}
+};
+
+static Menu_t OptionsMenu = {
+ 88, 30,
+ DrawOptionsMenu,
+ 5, OptionsItems,
+ 0,
+ MENU_MAIN
+};
+
+static MenuItem_t Options2Items[] = {
+ {ITT_LRFUNC, "SCREEN SIZE", SCScreenSize, 0, MENU_NONE},
+ {ITT_EMPTY, NULL, NULL, 0, MENU_NONE},
+ {ITT_LRFUNC, "SFX VOLUME", SCSfxVolume, 0, MENU_NONE},
+ {ITT_EMPTY, NULL, NULL, 0, MENU_NONE},
+ {ITT_LRFUNC, "MUSIC VOLUME", SCMusicVolume, 0, MENU_NONE},
+ {ITT_EMPTY, NULL, NULL, 0, MENU_NONE}
+};
+
+static Menu_t Options2Menu = {
+ 90, 20,
+ DrawOptions2Menu,
+ 6, Options2Items,
+ 0,
+ MENU_OPTIONS
+};
+
+static Menu_t *Menus[] = {
+ &MainMenu,
+ &ClassMenu,
+ &SkillMenu,
+ &OptionsMenu,
+ &Options2Menu,
+ &FilesMenu,
+ &LoadMenu,
+ &SaveMenu
+};
+
+static char *GammaText[] = {
+ TXT_GAMMA_LEVEL_OFF,
+ TXT_GAMMA_LEVEL_1,
+ TXT_GAMMA_LEVEL_2,
+ TXT_GAMMA_LEVEL_3,
+ TXT_GAMMA_LEVEL_4
+};
+
+// CODE --------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_Init
+//
+//---------------------------------------------------------------------------
+
+void MN_Init(void)
+{
+ InitFonts();
+ MenuActive = false;
+// messageson = true; // Set by defaults in .CFG
+ MauloBaseLump = W_GetNumForName("FBULA0"); // ("M_SKL00");
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC InitFonts
+//
+//---------------------------------------------------------------------------
+
+static void InitFonts(void)
+{
+ FontABaseLump = W_GetNumForName("FONTA_S") + 1;
+ FontAYellowBaseLump = W_GetNumForName("FONTAY_S") + 1;
+ FontBBaseLump = W_GetNumForName("FONTB_S") + 1;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_DrTextA
+//
+// Draw text using font A.
+//
+//---------------------------------------------------------------------------
+
+void MN_DrTextA(char *text, int x, int y)
+{
+ char c;
+ patch_t *p;
+
+ while ((c = *text++) != 0)
+ {
+ if (c < 33)
+ {
+ x += 5;
+ }
+ else
+ {
+ p = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
+ V_DrawPatch(x, y, p);
+ x += SHORT(p->width) - 1;
+ }
+ }
+}
+
+//==========================================================================
+//
+// MN_DrTextAYellow
+//
+//==========================================================================
+
+void MN_DrTextAYellow(char *text, int x, int y)
+{
+ char c;
+ patch_t *p;
+
+ while ((c = *text++) != 0)
+ {
+ if (c < 33)
+ {
+ x += 5;
+ }
+ else
+ {
+ p = W_CacheLumpNum(FontAYellowBaseLump + c - 33, PU_CACHE);
+ V_DrawPatch(x, y, p);
+ x += p->width - 1;
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC MN_TextAWidth
+//
+// Returns the pixel width of a string using font A.
+//
+//---------------------------------------------------------------------------
+
+int MN_TextAWidth(char *text)
+{
+ char c;
+ int width;
+ patch_t *p;
+
+ width = 0;
+ while ((c = *text++) != 0)
+ {
+ if (c < 33)
+ {
+ width += 5;
+ }
+ else
+ {
+ p = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
+ width += SHORT(p->width) - 1;
+ }
+ }
+ return (width);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_DrTextB
+//
+// Draw text using font B.
+//
+//---------------------------------------------------------------------------
+
+void MN_DrTextB(char *text, int x, int y)
+{
+ char c;
+ patch_t *p;
+
+ while ((c = *text++) != 0)
+ {
+ if (c < 33)
+ {
+ x += 8;
+ }
+ else
+ {
+ p = W_CacheLumpNum(FontBBaseLump + c - 33, PU_CACHE);
+ V_DrawPatch(x, y, p);
+ x += SHORT(p->width) - 1;
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC MN_TextBWidth
+//
+// Returns the pixel width of a string using font B.
+//
+//---------------------------------------------------------------------------
+
+int MN_TextBWidth(char *text)
+{
+ char c;
+ int width;
+ patch_t *p;
+
+ width = 0;
+ while ((c = *text++) != 0)
+ {
+ if (c < 33)
+ {
+ width += 5;
+ }
+ else
+ {
+ p = W_CacheLumpNum(FontBBaseLump + c - 33, PU_CACHE);
+ width += SHORT(p->width) - 1;
+ }
+ }
+ return (width);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_Ticker
+//
+//---------------------------------------------------------------------------
+
+void MN_Ticker(void)
+{
+ if (MenuActive == false)
+ {
+ return;
+ }
+ MenuTime++;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_Drawer
+//
+//---------------------------------------------------------------------------
+
+char *QuitEndMsg[] = {
+ "ARE YOU SURE YOU WANT TO QUIT?",
+ "ARE YOU SURE YOU WANT TO END THE GAME?",
+ "DO YOU WANT TO QUICKSAVE THE GAME NAMED",
+ "DO YOU WANT TO QUICKLOAD THE GAME NAMED",
+ "ARE YOU SURE YOU WANT TO SUICIDE?"
+};
+
+void MN_Drawer(void)
+{
+ int i;
+ int x;
+ int y;
+ MenuItem_t *item;
+ char *selName;
+
+ if (MenuActive == false)
+ {
+ if (askforquit)
+ {
+ MN_DrTextA(QuitEndMsg[typeofask - 1], 160 -
+ MN_TextAWidth(QuitEndMsg[typeofask - 1]) / 2, 80);
+ if (typeofask == 3)
+ {
+ MN_DrTextA(SlotText[quicksave - 1], 160 -
+ MN_TextAWidth(SlotText[quicksave - 1]) / 2, 90);
+ MN_DrTextA("?", 160 +
+ MN_TextAWidth(SlotText[quicksave - 1]) / 2, 90);
+ }
+ if (typeofask == 4)
+ {
+ MN_DrTextA(SlotText[quickload - 1], 160 -
+ MN_TextAWidth(SlotText[quickload - 1]) / 2, 90);
+ MN_DrTextA("?", 160 +
+ MN_TextAWidth(SlotText[quicksave - 1]) / 2, 90);
+ }
+ UpdateState |= I_FULLSCRN;
+ }
+ return;
+ }
+ else
+ {
+ UpdateState |= I_FULLSCRN;
+ if (InfoType)
+ {
+ MN_DrawInfo();
+ return;
+ }
+ if (screenblocks < 10)
+ {
+ BorderNeedRefresh = true;
+ }
+ if (CurrentMenu->drawFunc != NULL)
+ {
+ CurrentMenu->drawFunc();
+ }
+ x = CurrentMenu->x;
+ y = CurrentMenu->y;
+ item = CurrentMenu->items;
+ for (i = 0; i < CurrentMenu->itemCount; i++)
+ {
+ if (item->type != ITT_EMPTY && item->text)
+ {
+ MN_DrTextB(item->text, x, y);
+ }
+ y += ITEM_HEIGHT;
+ item++;
+ }
+ y = CurrentMenu->y + (CurrentItPos * ITEM_HEIGHT) + SELECTOR_YOFFSET;
+ selName = MenuTime & 16 ? "M_SLCTR1" : "M_SLCTR2";
+ V_DrawPatch(x + SELECTOR_XOFFSET, y,
+ W_CacheLumpName(selName, PU_CACHE));
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawMainMenu
+//
+//---------------------------------------------------------------------------
+
+static void DrawMainMenu(void)
+{
+ int frame;
+
+ frame = (MenuTime / 5) % 7;
+ V_DrawPatch(88, 0, W_CacheLumpName("M_HTIC", PU_CACHE));
+// Old Gold skull positions: (40, 10) and (232, 10)
+ V_DrawPatch(37, 80, W_CacheLumpNum(MauloBaseLump + (frame + 2) % 7,
+ PU_CACHE));
+ V_DrawPatch(278, 80, W_CacheLumpNum(MauloBaseLump + frame, PU_CACHE));
+}
+
+//==========================================================================
+//
+// DrawClassMenu
+//
+//==========================================================================
+
+static void DrawClassMenu(void)
+{
+ pclass_t class;
+ static char *boxLumpName[3] = {
+ "m_fbox",
+ "m_cbox",
+ "m_mbox"
+ };
+ static char *walkLumpName[3] = {
+ "m_fwalk1",
+ "m_cwalk1",
+ "m_mwalk1"
+ };
+
+ MN_DrTextB("CHOOSE CLASS:", 34, 24);
+ class = (pclass_t) CurrentMenu->items[CurrentItPos].option;
+ V_DrawPatch(174, 8, W_CacheLumpName(boxLumpName[class], PU_CACHE));
+ V_DrawPatch(174 + 24, 8 + 12,
+ W_CacheLumpNum(W_GetNumForName(walkLumpName[class])
+ + ((MenuTime >> 3) & 3), PU_CACHE));
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawSkillMenu
+//
+//---------------------------------------------------------------------------
+
+static void DrawSkillMenu(void)
+{
+ MN_DrTextB("CHOOSE SKILL LEVEL:", 74, 16);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawFilesMenu
+//
+//---------------------------------------------------------------------------
+
+static void DrawFilesMenu(void)
+{
+// clear out the quicksave/quickload stuff
+ quicksave = 0;
+ quickload = 0;
+ P_ClearMessage(&players[consoleplayer]);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawLoadMenu
+//
+//---------------------------------------------------------------------------
+
+static void DrawLoadMenu(void)
+{
+ MN_DrTextB("LOAD GAME", 160 - MN_TextBWidth("LOAD GAME") / 2, 10);
+ if (!slottextloaded)
+ {
+ MN_LoadSlotText();
+ }
+ DrawFileSlots(&LoadMenu);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawSaveMenu
+//
+//---------------------------------------------------------------------------
+
+static void DrawSaveMenu(void)
+{
+ MN_DrTextB("SAVE GAME", 160 - MN_TextBWidth("SAVE GAME") / 2, 10);
+ if (!slottextloaded)
+ {
+ MN_LoadSlotText();
+ }
+ DrawFileSlots(&SaveMenu);
+}
+
+static boolean ReadDescriptionForSlot(int slot, char *description)
+{
+ FILE *fp;
+ boolean found;
+ char name[100];
+ char versionText[HXS_VERSION_TEXT_LENGTH];
+
+ sprintf(name, "%shex%d.hxs", SavePath, slot);
+
+ fp = fopen(name, "rb");
+
+ if (fp == NULL)
+ {
+ return false;
+ }
+
+ found = fread(description, HXS_DESCRIPTION_LENGTH, 1, fp) == 1
+ && fread(versionText, HXS_VERSION_TEXT_LENGTH, 1, fp) == 1;
+
+ found = found && strcmp(versionText, HXS_VERSION_TEXT) == 0;
+
+ fclose(fp);
+
+ return found;
+}
+
+//===========================================================================
+//
+// MN_LoadSlotText
+//
+// For each slot, looks for save games and reads the description field.
+//
+//===========================================================================
+
+void MN_LoadSlotText(void)
+{
+ char description[HXS_DESCRIPTION_LENGTH];
+ int slot;
+
+ for (slot = 0; slot < 6; slot++)
+ {
+ if (ReadDescriptionForSlot(slot, description))
+ {
+ memcpy(SlotText[slot], description, SLOTTEXTLEN);
+ SlotStatus[slot] = 1;
+ }
+ else
+ {
+ memset(SlotText[slot], 0, SLOTTEXTLEN);
+ SlotStatus[slot] = 0;
+ }
+ }
+ slottextloaded = true;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawFileSlots
+//
+//---------------------------------------------------------------------------
+
+static void DrawFileSlots(Menu_t * menu)
+{
+ int i;
+ int x;
+ int y;
+
+ x = menu->x;
+ y = menu->y;
+ for (i = 0; i < 6; i++)
+ {
+ V_DrawPatch(x, y, W_CacheLumpName("M_FSLOT", PU_CACHE));
+ if (SlotStatus[i])
+ {
+ MN_DrTextA(SlotText[i], x + 5, y + 5);
+ }
+ y += ITEM_HEIGHT;
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawOptionsMenu
+//
+//---------------------------------------------------------------------------
+
+static void DrawOptionsMenu(void)
+{
+ if (messageson)
+ {
+ MN_DrTextB("ON", 196, 50);
+ }
+ else
+ {
+ MN_DrTextB("OFF", 196, 50);
+ }
+ DrawSlider(&OptionsMenu, 3, 10, mouseSensitivity);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawOptions2Menu
+//
+//---------------------------------------------------------------------------
+
+static void DrawOptions2Menu(void)
+{
+ DrawSlider(&Options2Menu, 1, 9, screenblocks - 3);
+ DrawSlider(&Options2Menu, 3, 16, snd_MaxVolume);
+ DrawSlider(&Options2Menu, 5, 16, snd_MusicVolume);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCQuitGame
+//
+//---------------------------------------------------------------------------
+
+static void SCQuitGame(int option)
+{
+ MenuActive = false;
+ askforquit = true;
+ typeofask = 1; //quit game
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCEndGame
+//
+//---------------------------------------------------------------------------
+
+static void SCEndGame(int option)
+{
+ if (demoplayback)
+ {
+ return;
+ }
+ if (SCNetCheck(3))
+ {
+ MenuActive = false;
+ askforquit = true;
+ typeofask = 2; //endgame
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCMessages
+//
+//---------------------------------------------------------------------------
+
+static void SCMessages(int option)
+{
+ messageson ^= 1;
+ if (messageson)
+ {
+ P_SetMessage(&players[consoleplayer], "MESSAGES ON", true);
+ }
+ else
+ {
+ P_SetMessage(&players[consoleplayer], "MESSAGES OFF", true);
+ }
+ S_StartSound(NULL, SFX_CHAT);
+}
+
+//===========================================================================
+//
+// SCNetCheck
+//
+//===========================================================================
+
+static boolean SCNetCheck(int option)
+{
+ if (!netgame)
+ {
+ return true;
+ }
+ switch (option)
+ {
+ case 1: // new game
+ P_SetMessage(&players[consoleplayer],
+ "YOU CAN'T START A NEW GAME IN NETPLAY!", true);
+ break;
+ case 2: // load game
+ P_SetMessage(&players[consoleplayer],
+ "YOU CAN'T LOAD A GAME IN NETPLAY!", true);
+ break;
+ case 3: // end game
+ P_SetMessage(&players[consoleplayer],
+ "YOU CAN'T END A GAME IN NETPLAY!", true);
+ break;
+ }
+ MenuActive = false;
+ S_StartSound(NULL, SFX_CHAT);
+ return false;
+}
+
+//===========================================================================
+//
+// SCNetCheck2
+//
+//===========================================================================
+
+static void SCNetCheck2(int option)
+{
+ SCNetCheck(option);
+ return;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCLoadGame
+//
+//---------------------------------------------------------------------------
+
+static void SCLoadGame(int option)
+{
+ if (!SlotStatus[option])
+ { // Don't try to load from an empty slot
+ return;
+ }
+ G_LoadGame(option);
+ MN_DeactivateMenu();
+ BorderNeedRefresh = true;
+ if (quickload == -1)
+ {
+ quickload = option + 1;
+ P_ClearMessage(&players[consoleplayer]);
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCSaveGame
+//
+//---------------------------------------------------------------------------
+
+static void SCSaveGame(int option)
+{
+ char *ptr;
+
+ if (!FileMenuKeySteal)
+ {
+ FileMenuKeySteal = true;
+ strcpy(oldSlotText, SlotText[option]);
+ ptr = SlotText[option];
+ while (*ptr)
+ {
+ ptr++;
+ }
+ *ptr = '[';
+ *(ptr + 1) = 0;
+ SlotStatus[option]++;
+ currentSlot = option;
+ slotptr = ptr - SlotText[option];
+ return;
+ }
+ else
+ {
+ G_SaveGame(option, SlotText[option]);
+ FileMenuKeySteal = false;
+ MN_DeactivateMenu();
+ }
+ BorderNeedRefresh = true;
+ if (quicksave == -1)
+ {
+ quicksave = option + 1;
+ P_ClearMessage(&players[consoleplayer]);
+ }
+}
+
+//==========================================================================
+//
+// SCClass
+//
+//==========================================================================
+
+static void SCClass(int option)
+{
+ if (netgame)
+ {
+ P_SetMessage(&players[consoleplayer],
+ "YOU CAN'T START A NEW GAME FROM WITHIN A NETGAME!",
+ true);
+ return;
+ }
+ MenuPClass = option;
+ switch (MenuPClass)
+ {
+ case PCLASS_FIGHTER:
+ SkillMenu.x = 120;
+ SkillItems[0].text = "SQUIRE";
+ SkillItems[1].text = "KNIGHT";
+ SkillItems[2].text = "WARRIOR";
+ SkillItems[3].text = "BERSERKER";
+ SkillItems[4].text = "TITAN";
+ break;
+ case PCLASS_CLERIC:
+ SkillMenu.x = 116;
+ SkillItems[0].text = "ALTAR BOY";
+ SkillItems[1].text = "ACOLYTE";
+ SkillItems[2].text = "PRIEST";
+ SkillItems[3].text = "CARDINAL";
+ SkillItems[4].text = "POPE";
+ break;
+ case PCLASS_MAGE:
+ SkillMenu.x = 112;
+ SkillItems[0].text = "APPRENTICE";
+ SkillItems[1].text = "ENCHANTER";
+ SkillItems[2].text = "SORCERER";
+ SkillItems[3].text = "WARLOCK";
+ SkillItems[4].text = "ARCHIMAGE";
+ break;
+ }
+ SetMenu(MENU_SKILL);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCSkill
+//
+//---------------------------------------------------------------------------
+
+static void SCSkill(int option)
+{
+ PlayerClass[consoleplayer] = MenuPClass;
+ G_DeferredNewGame(option);
+ SB_SetClassData();
+ SB_state = -1;
+ MN_DeactivateMenu();
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCMouseSensi
+//
+//---------------------------------------------------------------------------
+
+static void SCMouseSensi(int option)
+{
+ if (option == RIGHT_DIR)
+ {
+ if (mouseSensitivity < 9)
+ {
+ mouseSensitivity++;
+ }
+ }
+ else if (mouseSensitivity)
+ {
+ mouseSensitivity--;
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCSfxVolume
+//
+//---------------------------------------------------------------------------
+
+static void SCSfxVolume(int option)
+{
+ if (option == RIGHT_DIR)
+ {
+ if (snd_MaxVolume < 15)
+ {
+ snd_MaxVolume++;
+ }
+ }
+ else if (snd_MaxVolume)
+ {
+ snd_MaxVolume--;
+ }
+ soundchanged = true; // we'll set it when we leave the menu
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCMusicVolume
+//
+//---------------------------------------------------------------------------
+
+static void SCMusicVolume(int option)
+{
+ if (option == RIGHT_DIR)
+ {
+ if (snd_MusicVolume < 15)
+ {
+ snd_MusicVolume++;
+ }
+ }
+ else if (snd_MusicVolume)
+ {
+ snd_MusicVolume--;
+ }
+ S_SetMusicVolume();
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCScreenSize
+//
+//---------------------------------------------------------------------------
+
+static void SCScreenSize(int option)
+{
+ if (option == RIGHT_DIR)
+ {
+ if (screenblocks < 11)
+ {
+ screenblocks++;
+ }
+ }
+ else if (screenblocks > 3)
+ {
+ screenblocks--;
+ }
+ R_SetViewSize(screenblocks, detailLevel);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCInfo
+//
+//---------------------------------------------------------------------------
+
+static void SCInfo(int option)
+{
+ InfoType = 1;
+ S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC MN_Responder
+//
+//---------------------------------------------------------------------------
+
+boolean MN_Responder(event_t * event)
+{
+ int key;
+ int charTyped;
+ int i;
+ MenuItem_t *item;
+ extern boolean automapactive;
+ extern void H2_StartTitle(void);
+ extern void G_CheckDemoStatus(void);
+ char *textBuffer;
+
+ // In testcontrols mode, none of the function keys should do anything
+ // - the only key is escape to quit.
+
+ if (testcontrols)
+ {
+ if (event->type == ev_quit
+ || (event->type == ev_keydown
+ && (event->data1 == key_menu_activate
+ || event->data1 == key_menu_quit)))
+ {
+ I_Quit();
+ return true;
+ }
+
+ return false;
+ }
+
+ // "close" button pressed on window?
+ if (event->type == ev_quit)
+ {
+ // First click on close = bring up quit confirm message.
+ // Second click = confirm quit.
+
+ if (!MenuActive && askforquit && typeofask == 1)
+ {
+ G_CheckDemoStatus();
+ I_Quit();
+ }
+ else
+ {
+ SCQuitGame(0);
+ S_StartSound(NULL, SFX_CHAT);
+ }
+
+ return true;
+ }
+
+ if (event->data1 != KEY_RSHIFT && event->type != ev_keydown)
+ {
+ return false;
+ }
+
+ key = event->data1;
+ charTyped = event->data2;
+
+ if (InfoType)
+ {
+ if (gamemode == shareware)
+ {
+ InfoType = (InfoType + 1) % 5;
+ }
+ else
+ {
+ InfoType = (InfoType + 1) % 4;
+ }
+ if (key == KEY_ESCAPE)
+ {
+ InfoType = 0;
+ }
+ if (!InfoType)
+ {
+ if (!netgame && !demoplayback)
+ {
+ paused = false;
+ }
+ MN_DeactivateMenu();
+ SB_state = -1; //refresh the statbar
+ BorderNeedRefresh = true;
+ }
+ S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
+ return (true); //make the info screen eat the keypress
+ }
+
+ if (ravpic && key == KEY_F1)
+ {
+ G_ScreenShot();
+ return (true);
+ }
+
+ if (askforquit)
+ {
+ if (key == key_menu_confirm)
+ {
+ switch (typeofask)
+ {
+ case 1:
+ G_CheckDemoStatus();
+ I_Quit();
+ return false;
+ case 2:
+ P_ClearMessage(&players[consoleplayer]);
+ askforquit = false;
+ typeofask = 0;
+ paused = false;
+ I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE));
+ H2_StartTitle(); // go to intro/demo mode.
+ return false;
+ case 3:
+ P_SetMessage(&players[consoleplayer],
+ "QUICKSAVING....", false);
+ FileMenuKeySteal = true;
+ SCSaveGame(quicksave - 1);
+ BorderNeedRefresh = true;
+ break;
+ case 4:
+ P_SetMessage(&players[consoleplayer],
+ "QUICKLOADING....", false);
+ SCLoadGame(quickload - 1);
+ BorderNeedRefresh = true;
+ break;
+ case 5:
+ BorderNeedRefresh = true;
+ mn_SuicideConsole = true;
+ break;
+ default:
+ break;
+ }
+
+ askforquit = false;
+ typeofask = 0;
+
+ return true;
+ }
+ else if (key == key_menu_abort || key == KEY_ESCAPE)
+ {
+ players[consoleplayer].messageTics = 0;
+ askforquit = false;
+ typeofask = 0;
+ paused = false;
+ UpdateState |= I_FULLSCRN;
+ BorderNeedRefresh = true;
+ return true;
+ }
+
+ return false; // don't let the keys filter thru
+ }
+ if (!MenuActive && !chatmodeon)
+ {
+ if (key == key_menu_decscreen)
+ {
+ if (automapactive)
+ { // Don't screen size in automap
+ return (false);
+ }
+ SCScreenSize(LEFT_DIR);
+ S_StartSound(NULL, SFX_PICKUP_KEY);
+ BorderNeedRefresh = true;
+ UpdateState |= I_FULLSCRN;
+ return (true);
+ }
+ else if (key == key_menu_incscreen)
+ {
+ if (automapactive)
+ { // Don't screen size in automap
+ return (false);
+ }
+ SCScreenSize(RIGHT_DIR);
+ S_StartSound(NULL, SFX_PICKUP_KEY);
+ BorderNeedRefresh = true;
+ UpdateState |= I_FULLSCRN;
+ return (true);
+ }
+ else if (key == key_menu_help) // F1 (help screen)
+ {
+ SCInfo(0); // start up info screens
+ MenuActive = true;
+ return (true);
+ }
+ else if (key == key_menu_save) // F2 (save game)
+ {
+ if (gamestate == GS_LEVEL && !demoplayback)
+ {
+ MenuActive = true;
+ FileMenuKeySteal = false;
+ MenuTime = 0;
+ CurrentMenu = &SaveMenu;
+ CurrentItPos = CurrentMenu->oldItPos;
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
+ slottextloaded = false; //reload the slot text, when needed
+ }
+ return true;
+ }
+ else if (key == key_menu_load) // F3 (load game)
+ {
+ if (SCNetCheck(2))
+ {
+ MenuActive = true;
+ FileMenuKeySteal = false;
+ MenuTime = 0;
+ CurrentMenu = &LoadMenu;
+ CurrentItPos = CurrentMenu->oldItPos;
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
+ slottextloaded = false; //reload the slot text, when needed
+ }
+ return true;
+ }
+ else if (key == key_menu_volume) // F4 (volume)
+ {
+ MenuActive = true;
+ FileMenuKeySteal = false;
+ MenuTime = 0;
+ CurrentMenu = &Options2Menu;
+ CurrentItPos = CurrentMenu->oldItPos;
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
+ slottextloaded = false; //reload the slot text, when needed
+ return true;
+ }
+ else if (key == key_menu_detail) // F5 (suicide)
+ {
+ MenuActive = false;
+ askforquit = true;
+ typeofask = 5; // suicide
+ return true;
+ }
+ else if (key == key_menu_qsave) // F6 (quicksave)
+ {
+ if (gamestate == GS_LEVEL && !demoplayback)
+ {
+ if (!quicksave || quicksave == -1)
+ {
+ MenuActive = true;
+ FileMenuKeySteal = false;
+ MenuTime = 0;
+ CurrentMenu = &SaveMenu;
+ CurrentItPos = CurrentMenu->oldItPos;
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
+ slottextloaded = false; //reload the slot text
+ quicksave = -1;
+ P_SetMessage(&players[consoleplayer],
+ "CHOOSE A QUICKSAVE SLOT", true);
+ }
+ else
+ {
+ askforquit = true;
+ typeofask = 3;
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ S_StartSound(NULL, SFX_CHAT);
+ }
+ }
+ return true;
+ }
+ else if (key == key_menu_endgame) // F7 (end game)
+ {
+ if (SCNetCheck(3))
+ {
+ if (gamestate == GS_LEVEL && !demoplayback)
+ {
+ S_StartSound(NULL, SFX_CHAT);
+ SCEndGame(0);
+ }
+ }
+ return true;
+ }
+ else if (key == key_menu_messages) // F8 (toggle messages)
+ {
+ SCMessages(0);
+ return true;
+ }
+ else if (key == key_menu_qload) // F9 (quickload)
+ {
+ if (SCNetCheck(2))
+ {
+ if (!quickload || quickload == -1)
+ {
+ MenuActive = true;
+ FileMenuKeySteal = false;
+ MenuTime = 0;
+ CurrentMenu = &LoadMenu;
+ CurrentItPos = CurrentMenu->oldItPos;
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
+ slottextloaded = false; // reload the slot text
+ quickload = -1;
+ P_SetMessage(&players[consoleplayer],
+ "CHOOSE A QUICKLOAD SLOT", true);
+ }
+ else
+ {
+ askforquit = true;
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ typeofask = 4;
+ S_StartSound(NULL, SFX_CHAT);
+ }
+ }
+ return true;
+ }
+ else if (key == key_menu_quit) // F10 (quit)
+ {
+ if (gamestate == GS_LEVEL || gamestate == GS_FINALE)
+ {
+ SCQuitGame(0);
+ S_StartSound(NULL, SFX_CHAT);
+ }
+ return true;
+ }
+ else if (key == key_menu_gamma) // F11 (gamma correction)
+ {
+ usegamma++;
+ if (usegamma > 4)
+ {
+ usegamma = 0;
+ }
+ SB_PaletteFlash(true); // force change
+ P_SetMessage(&players[consoleplayer], GammaText[usegamma],
+ false);
+ return true;
+ }
+ else if (key == KEY_F12) // F12 (???)
+ {
+ // F12 - reload current map (devmaps mode)
+
+ if (netgame)
+ {
+ return false;
+ }
+ if (gamekeydown[key_speed])
+ { // Monsters ON
+ nomonsters = false;
+ }
+ if (gamekeydown[key_strafe])
+ { // Monsters OFF
+ nomonsters = true;
+ }
+ G_DeferedInitNew(gameskill, gameepisode, gamemap);
+ P_SetMessage(&players[consoleplayer], TXT_CHEATWARP, false);
+ return true;
+ }
+ }
+
+ if (!MenuActive)
+ {
+ if (key == key_menu_activate || gamestate == GS_DEMOSCREEN || demoplayback)
+ {
+ MN_ActivateMenu();
+ return (true);
+ }
+ return (false);
+ }
+ if (!FileMenuKeySteal)
+ {
+ item = &CurrentMenu->items[CurrentItPos];
+
+ if (key == key_menu_down) // Next menu item
+ {
+ do
+ {
+ if (CurrentItPos + 1 > CurrentMenu->itemCount - 1)
+ {
+ CurrentItPos = 0;
+ }
+ else
+ {
+ CurrentItPos++;
+ }
+ }
+ while (CurrentMenu->items[CurrentItPos].type == ITT_EMPTY);
+ S_StartSound(NULL, SFX_FIGHTER_HAMMER_HITWALL);
+ return (true);
+ }
+ else if (key == key_menu_up) // Previous menu item
+ {
+ do
+ {
+ if (CurrentItPos == 0)
+ {
+ CurrentItPos = CurrentMenu->itemCount - 1;
+ }
+ else
+ {
+ CurrentItPos--;
+ }
+ }
+ while (CurrentMenu->items[CurrentItPos].type == ITT_EMPTY);
+ S_StartSound(NULL, SFX_FIGHTER_HAMMER_HITWALL);
+ return (true);
+ }
+ else if (key == key_menu_left) // Slider left
+ {
+ if (item->type == ITT_LRFUNC && item->func != NULL)
+ {
+ item->func(LEFT_DIR);
+ S_StartSound(NULL, SFX_PICKUP_KEY);
+ }
+ return (true);
+ }
+ else if (key == key_menu_right) // Slider right
+ {
+ if (item->type == ITT_LRFUNC && item->func != NULL)
+ {
+ item->func(RIGHT_DIR);
+ S_StartSound(NULL, SFX_PICKUP_KEY);
+ }
+ return (true);
+ }
+ else if (key == key_menu_forward) // Activate item (enter)
+ {
+ if (item->type == ITT_SETMENU)
+ {
+ if (item->func != NULL)
+ {
+ item->func(item->option);
+ }
+ SetMenu(item->menu);
+ }
+ else if (item->func != NULL)
+ {
+ CurrentMenu->oldItPos = CurrentItPos;
+ if (item->type == ITT_LRFUNC)
+ {
+ item->func(RIGHT_DIR);
+ }
+ else if (item->type == ITT_EFUNC)
+ {
+ item->func(item->option);
+ }
+ }
+ S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
+ return (true);
+ }
+ else if (key == key_menu_activate)
+ {
+ MN_DeactivateMenu();
+ return (true);
+ }
+ else if (key == key_menu_back)
+ {
+ S_StartSound(NULL, SFX_PICKUP_KEY);
+
+ if (CurrentMenu->prevMenu == MENU_NONE)
+ {
+ MN_DeactivateMenu();
+ }
+ else
+ {
+ SetMenu(CurrentMenu->prevMenu);
+ }
+ return (true);
+ }
+ else if (charTyped != 0)
+ {
+ for (i = 0; i < CurrentMenu->itemCount; i++)
+ {
+ if (CurrentMenu->items[i].text)
+ {
+ if (toupper(charTyped)
+ == toupper(CurrentMenu->items[i].text[0]))
+ {
+ CurrentItPos = i;
+ return (true);
+ }
+ }
+ }
+ }
+ return (false);
+ }
+ else
+ { // Editing file names
+ textBuffer = &SlotText[currentSlot][slotptr];
+ if (key == KEY_BACKSPACE)
+ {
+ if (slotptr)
+ {
+ *textBuffer-- = 0;
+ *textBuffer = ASCII_CURSOR;
+ slotptr--;
+ }
+ return (true);
+ }
+ if (key == KEY_ESCAPE)
+ {
+ memset(SlotText[currentSlot], 0, SLOTTEXTLEN + 2);
+ strcpy(SlotText[currentSlot], oldSlotText);
+ SlotStatus[currentSlot]--;
+ MN_DeactivateMenu();
+ return (true);
+ }
+ if (key == KEY_ENTER)
+ {
+ SlotText[currentSlot][slotptr] = 0; // clear the cursor
+ item = &CurrentMenu->items[CurrentItPos];
+ CurrentMenu->oldItPos = CurrentItPos;
+ if (item->type == ITT_EFUNC)
+ {
+ item->func(item->option);
+ if (item->menu != MENU_NONE)
+ {
+ SetMenu(item->menu);
+ }
+ }
+ return (true);
+ }
+ if (slotptr < SLOTTEXTLEN && key != KEY_BACKSPACE)
+ {
+ if (isalpha(charTyped))
+ {
+ *textBuffer++ = toupper(charTyped);
+ *textBuffer = ASCII_CURSOR;
+ slotptr++;
+ return (true);
+ }
+ if (isdigit(charTyped) || charTyped == ' '
+ || charTyped == ',' || charTyped == '.' || charTyped == '-'
+ || charTyped == '!')
+ {
+ *textBuffer++ = charTyped;
+ *textBuffer = ASCII_CURSOR;
+ slotptr++;
+ return (true);
+ }
+ }
+ return (true);
+ }
+ return (false);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_ActivateMenu
+//
+//---------------------------------------------------------------------------
+
+void MN_ActivateMenu(void)
+{
+ if (MenuActive)
+ {
+ return;
+ }
+ if (paused)
+ {
+ S_ResumeSound();
+ }
+ MenuActive = true;
+ FileMenuKeySteal = false;
+ MenuTime = 0;
+ CurrentMenu = &MainMenu;
+ CurrentItPos = CurrentMenu->oldItPos;
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ S_StartSound(NULL, SFX_PLATFORM_STOP);
+ slottextloaded = false; //reload the slot text, when needed
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_DeactivateMenu
+//
+//---------------------------------------------------------------------------
+
+void MN_DeactivateMenu(void)
+{
+ if (CurrentMenu != NULL)
+ {
+ CurrentMenu->oldItPos = CurrentItPos;
+ }
+ MenuActive = false;
+ if (!netgame)
+ {
+ paused = false;
+ }
+ S_StartSound(NULL, SFX_PLATFORM_STOP);
+ P_ClearMessage(&players[consoleplayer]);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_DrawInfo
+//
+//---------------------------------------------------------------------------
+
+void MN_DrawInfo(void)
+{
+ I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE));
+ memcpy(I_VideoBuffer,
+ (byte *) W_CacheLumpNum(W_GetNumForName("TITLE") + InfoType,
+ PU_CACHE), SCREENWIDTH * SCREENHEIGHT);
+// V_DrawPatch(0, 0, W_CacheLumpNum(W_GetNumForName("TITLE")+InfoType,
+// PU_CACHE));
+}
+
+
+//---------------------------------------------------------------------------
+//
+// PROC SetMenu
+//
+//---------------------------------------------------------------------------
+
+static void SetMenu(MenuType_t menu)
+{
+ CurrentMenu->oldItPos = CurrentItPos;
+ CurrentMenu = Menus[menu];
+ CurrentItPos = CurrentMenu->oldItPos;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawSlider
+//
+//---------------------------------------------------------------------------
+
+static void DrawSlider(Menu_t * menu, int item, int width, int slot)
+{
+ int x;
+ int y;
+ int x2;
+ int count;
+
+ x = menu->x + 24;
+ y = menu->y + 2 + (item * ITEM_HEIGHT);
+ V_DrawPatch(x - 32, y, W_CacheLumpName("M_SLDLT", PU_CACHE));
+ for (x2 = x, count = width; count--; x2 += 8)
+ {
+ V_DrawPatch(x2, y, W_CacheLumpName(count & 1 ? "M_SLDMD1"
+ : "M_SLDMD2", PU_CACHE));
+ }
+ V_DrawPatch(x2, y, W_CacheLumpName("M_SLDRT", PU_CACHE));
+ V_DrawPatch(x + 4 + slot * 8, y + 7,
+ W_CacheLumpName("M_SLDKB", PU_CACHE));
+}
diff --git a/src/hexen/p_acs.c b/src/hexen/p_acs.c
new file mode 100644
index 00000000..9ca9f6af
--- /dev/null
+++ b/src/hexen/p_acs.c
@@ -0,0 +1,1884 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2def.h"
+#include "m_random.h"
+#include "s_sound.h"
+#include "i_swap.h"
+#include "i_system.h"
+#include "p_local.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define SCRIPT_CONTINUE 0
+#define SCRIPT_STOP 1
+#define SCRIPT_TERMINATE 2
+#define OPEN_SCRIPTS_BASE 1000
+#define PRINT_BUFFER_SIZE 256
+#define GAME_SINGLE_PLAYER 0
+#define GAME_NET_COOPERATIVE 1
+#define GAME_NET_DEATHMATCH 2
+#define TEXTURE_TOP 0
+#define TEXTURE_MIDDLE 1
+#define TEXTURE_BOTTOM 2
+#define S_DROP ACScript->stackPtr--
+#define S_POP ACScript->stack[--ACScript->stackPtr]
+#define S_PUSH(x) ACScript->stack[ACScript->stackPtr++] = x
+
+// TYPES -------------------------------------------------------------------
+
+typedef struct
+{
+ int marker;
+ int infoOffset;
+ int code;
+} PACKEDATTR acsHeader_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void StartOpenACS(int number, int infoIndex, int *address);
+static void ScriptFinished(int number);
+static boolean TagBusy(int tag);
+static boolean AddToACSStore(int map, int number, byte * args);
+static int GetACSIndex(int number);
+static void Push(int value);
+static int Pop(void);
+static int Top(void);
+static void Drop(void);
+
+static int CmdNOP(void);
+static int CmdTerminate(void);
+static int CmdSuspend(void);
+static int CmdPushNumber(void);
+static int CmdLSpec1(void);
+static int CmdLSpec2(void);
+static int CmdLSpec3(void);
+static int CmdLSpec4(void);
+static int CmdLSpec5(void);
+static int CmdLSpec1Direct(void);
+static int CmdLSpec2Direct(void);
+static int CmdLSpec3Direct(void);
+static int CmdLSpec4Direct(void);
+static int CmdLSpec5Direct(void);
+static int CmdAdd(void);
+static int CmdSubtract(void);
+static int CmdMultiply(void);
+static int CmdDivide(void);
+static int CmdModulus(void);
+static int CmdEQ(void);
+static int CmdNE(void);
+static int CmdLT(void);
+static int CmdGT(void);
+static int CmdLE(void);
+static int CmdGE(void);
+static int CmdAssignScriptVar(void);
+static int CmdAssignMapVar(void);
+static int CmdAssignWorldVar(void);
+static int CmdPushScriptVar(void);
+static int CmdPushMapVar(void);
+static int CmdPushWorldVar(void);
+static int CmdAddScriptVar(void);
+static int CmdAddMapVar(void);
+static int CmdAddWorldVar(void);
+static int CmdSubScriptVar(void);
+static int CmdSubMapVar(void);
+static int CmdSubWorldVar(void);
+static int CmdMulScriptVar(void);
+static int CmdMulMapVar(void);
+static int CmdMulWorldVar(void);
+static int CmdDivScriptVar(void);
+static int CmdDivMapVar(void);
+static int CmdDivWorldVar(void);
+static int CmdModScriptVar(void);
+static int CmdModMapVar(void);
+static int CmdModWorldVar(void);
+static int CmdIncScriptVar(void);
+static int CmdIncMapVar(void);
+static int CmdIncWorldVar(void);
+static int CmdDecScriptVar(void);
+static int CmdDecMapVar(void);
+static int CmdDecWorldVar(void);
+static int CmdGoto(void);
+static int CmdIfGoto(void);
+static int CmdDrop(void);
+static int CmdDelay(void);
+static int CmdDelayDirect(void);
+static int CmdRandom(void);
+static int CmdRandomDirect(void);
+static int CmdThingCount(void);
+static int CmdThingCountDirect(void);
+static int CmdTagWait(void);
+static int CmdTagWaitDirect(void);
+static int CmdPolyWait(void);
+static int CmdPolyWaitDirect(void);
+static int CmdChangeFloor(void);
+static int CmdChangeFloorDirect(void);
+static int CmdChangeCeiling(void);
+static int CmdChangeCeilingDirect(void);
+static int CmdRestart(void);
+static int CmdAndLogical(void);
+static int CmdOrLogical(void);
+static int CmdAndBitwise(void);
+static int CmdOrBitwise(void);
+static int CmdEorBitwise(void);
+static int CmdNegateLogical(void);
+static int CmdLShift(void);
+static int CmdRShift(void);
+static int CmdUnaryMinus(void);
+static int CmdIfNotGoto(void);
+static int CmdLineSide(void);
+static int CmdScriptWait(void);
+static int CmdScriptWaitDirect(void);
+static int CmdClearLineSpecial(void);
+static int CmdCaseGoto(void);
+static int CmdBeginPrint(void);
+static int CmdEndPrint(void);
+static int CmdPrintString(void);
+static int CmdPrintNumber(void);
+static int CmdPrintCharacter(void);
+static int CmdPlayerCount(void);
+static int CmdGameType(void);
+static int CmdGameSkill(void);
+static int CmdTimer(void);
+static int CmdSectorSound(void);
+static int CmdAmbientSound(void);
+static int CmdSoundSequence(void);
+static int CmdSetLineTexture(void);
+static int CmdSetLineBlocking(void);
+static int CmdSetLineSpecial(void);
+static int CmdThingSound(void);
+static int CmdEndPrintBold(void);
+
+static void ThingCount(int type, int tid);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+int ACScriptCount;
+byte *ActionCodeBase;
+acsInfo_t *ACSInfo;
+int MapVars[MAX_ACS_MAP_VARS];
+int WorldVars[MAX_ACS_WORLD_VARS];
+acsstore_t ACSStore[MAX_ACS_STORE + 1]; // +1 for termination marker
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static acs_t *ACScript;
+static int *PCodePtr;
+static byte SpecArgs[8];
+static int ACStringCount;
+static char **ACStrings;
+static char PrintBuffer[PRINT_BUFFER_SIZE];
+static acs_t *NewScript;
+
+static int (*PCodeCmds[]) (void) =
+{
+CmdNOP,
+ CmdTerminate,
+ CmdSuspend,
+ CmdPushNumber,
+ CmdLSpec1,
+ CmdLSpec2,
+ CmdLSpec3,
+ CmdLSpec4,
+ CmdLSpec5,
+ CmdLSpec1Direct,
+ CmdLSpec2Direct,
+ CmdLSpec3Direct,
+ CmdLSpec4Direct,
+ CmdLSpec5Direct,
+ CmdAdd,
+ CmdSubtract,
+ CmdMultiply,
+ CmdDivide,
+ CmdModulus,
+ CmdEQ,
+ CmdNE,
+ CmdLT,
+ CmdGT,
+ CmdLE,
+ CmdGE,
+ CmdAssignScriptVar,
+ CmdAssignMapVar,
+ CmdAssignWorldVar,
+ CmdPushScriptVar,
+ CmdPushMapVar,
+ CmdPushWorldVar,
+ CmdAddScriptVar,
+ CmdAddMapVar,
+ CmdAddWorldVar,
+ CmdSubScriptVar,
+ CmdSubMapVar,
+ CmdSubWorldVar,
+ CmdMulScriptVar,
+ CmdMulMapVar,
+ CmdMulWorldVar,
+ CmdDivScriptVar,
+ CmdDivMapVar,
+ CmdDivWorldVar,
+ CmdModScriptVar,
+ CmdModMapVar,
+ CmdModWorldVar,
+ CmdIncScriptVar,
+ CmdIncMapVar,
+ CmdIncWorldVar,
+ CmdDecScriptVar,
+ CmdDecMapVar,
+ CmdDecWorldVar,
+ CmdGoto,
+ CmdIfGoto,
+ CmdDrop,
+ CmdDelay,
+ CmdDelayDirect,
+ CmdRandom,
+ CmdRandomDirect,
+ CmdThingCount,
+ CmdThingCountDirect,
+ CmdTagWait,
+ CmdTagWaitDirect,
+ CmdPolyWait,
+ CmdPolyWaitDirect,
+ CmdChangeFloor,
+ CmdChangeFloorDirect,
+ CmdChangeCeiling,
+ CmdChangeCeilingDirect,
+ CmdRestart,
+ CmdAndLogical,
+ CmdOrLogical,
+ CmdAndBitwise,
+ CmdOrBitwise,
+ CmdEorBitwise,
+ CmdNegateLogical,
+ CmdLShift,
+ CmdRShift,
+ CmdUnaryMinus,
+ CmdIfNotGoto,
+ CmdLineSide,
+ CmdScriptWait,
+ CmdScriptWaitDirect,
+ CmdClearLineSpecial,
+ CmdCaseGoto,
+ CmdBeginPrint,
+ CmdEndPrint,
+ CmdPrintString,
+ CmdPrintNumber,
+ CmdPrintCharacter,
+ CmdPlayerCount,
+ CmdGameType,
+ CmdGameSkill,
+ CmdTimer,
+ CmdSectorSound,
+ CmdAmbientSound,
+ CmdSoundSequence,
+ CmdSetLineTexture,
+ CmdSetLineBlocking,
+ CmdSetLineSpecial, CmdThingSound, CmdEndPrintBold};
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// P_LoadACScripts
+//
+//==========================================================================
+
+void P_LoadACScripts(int lump)
+{
+ int i;
+ int *buffer;
+ acsHeader_t *header;
+ acsInfo_t *info;
+
+ header = W_CacheLumpNum(lump, PU_LEVEL);
+ ActionCodeBase = (byte *) header;
+ buffer = (int *) ((byte *) header + LONG(header->infoOffset));
+
+ ACScriptCount = LONG(*buffer);
+ ++buffer;
+
+ if (ACScriptCount == 0)
+ { // Empty behavior lump
+ return;
+ }
+
+ ACSInfo = Z_Malloc(ACScriptCount * sizeof(acsInfo_t), PU_LEVEL, 0);
+ memset(ACSInfo, 0, ACScriptCount * sizeof(acsInfo_t));
+ for (i = 0, info = ACSInfo; i < ACScriptCount; i++, info++)
+ {
+ info->number = LONG(*buffer);
+ ++buffer;
+
+ info->address = (int *) ((byte *) ActionCodeBase + LONG(*buffer));
+ ++buffer;
+
+ info->argCount = LONG(*buffer);
+ ++buffer;
+
+ if (info->number >= OPEN_SCRIPTS_BASE)
+ { // Auto-activate
+ info->number -= OPEN_SCRIPTS_BASE;
+ StartOpenACS(info->number, i, info->address);
+ info->state = ASTE_RUNNING;
+ }
+ else
+ {
+ info->state = ASTE_INACTIVE;
+ }
+ }
+ ACStringCount = LONG(*buffer);
+ ++buffer;
+
+ ACStrings = Z_Malloc(ACStringCount * sizeof(char *), PU_LEVEL, NULL);
+
+ for (i=0; i<ACStringCount; ++i)
+ {
+ ACStrings[i] = (char *) ActionCodeBase + LONG(buffer[i]);
+ }
+
+ memset(MapVars, 0, sizeof(MapVars));
+}
+
+//==========================================================================
+//
+// StartOpenACS
+//
+//==========================================================================
+
+static void StartOpenACS(int number, int infoIndex, int *address)
+{
+ acs_t *script;
+
+ script = Z_Malloc(sizeof(acs_t), PU_LEVSPEC, 0);
+ memset(script, 0, sizeof(acs_t));
+ script->number = number;
+
+ // World objects are allotted 1 second for initialization
+ script->delayCount = 35;
+
+ script->infoIndex = infoIndex;
+ script->ip = address;
+ script->thinker.function = T_InterpretACS;
+ P_AddThinker(&script->thinker);
+}
+
+//==========================================================================
+//
+// P_CheckACSStore
+//
+// Scans the ACS store and executes all scripts belonging to the current
+// map.
+//
+//==========================================================================
+
+void P_CheckACSStore(void)
+{
+ acsstore_t *store;
+
+ for (store = ACSStore; store->map != 0; store++)
+ {
+ if (store->map == gamemap)
+ {
+ P_StartACS(store->script, 0, store->args, NULL, NULL, 0);
+ if (NewScript)
+ {
+ NewScript->delayCount = 35;
+ }
+ store->map = -1;
+ }
+ }
+}
+
+//==========================================================================
+//
+// P_StartACS
+//
+//==========================================================================
+
+static char ErrorMsg[128];
+
+boolean P_StartACS(int number, int map, byte * args, mobj_t * activator,
+ line_t * line, int side)
+{
+ int i;
+ acs_t *script;
+ int infoIndex;
+ aste_t *statePtr;
+
+ NewScript = NULL;
+ if (map && map != gamemap)
+ { // Add to the script store
+ return AddToACSStore(map, number, args);
+ }
+ infoIndex = GetACSIndex(number);
+ if (infoIndex == -1)
+ { // Script not found
+ //I_Error("P_StartACS: Unknown script number %d", number);
+ sprintf(ErrorMsg, "P_STARTACS ERROR: UNKNOWN SCRIPT %d", number);
+ P_SetMessage(&players[consoleplayer], ErrorMsg, true);
+ }
+ statePtr = &ACSInfo[infoIndex].state;
+ if (*statePtr == ASTE_SUSPENDED)
+ { // Resume a suspended script
+ *statePtr = ASTE_RUNNING;
+ return true;
+ }
+ if (*statePtr != ASTE_INACTIVE)
+ { // Script is already executing
+ return false;
+ }
+ script = Z_Malloc(sizeof(acs_t), PU_LEVSPEC, 0);
+ memset(script, 0, sizeof(acs_t));
+ script->number = number;
+ script->infoIndex = infoIndex;
+ script->activator = activator;
+ script->line = line;
+ script->side = side;
+ script->ip = ACSInfo[infoIndex].address;
+ script->thinker.function = T_InterpretACS;
+ for (i = 0; i < ACSInfo[infoIndex].argCount; i++)
+ {
+ script->vars[i] = args[i];
+ }
+ *statePtr = ASTE_RUNNING;
+ P_AddThinker(&script->thinker);
+ NewScript = script;
+ return true;
+}
+
+//==========================================================================
+//
+// AddToACSStore
+//
+//==========================================================================
+
+static boolean AddToACSStore(int map, int number, byte * args)
+{
+ int i;
+ int index;
+
+ index = -1;
+ for (i = 0; ACSStore[i].map != 0; i++)
+ {
+ if (ACSStore[i].script == number && ACSStore[i].map == map)
+ { // Don't allow duplicates
+ return false;
+ }
+ if (index == -1 && ACSStore[i].map == -1)
+ { // Remember first empty slot
+ index = i;
+ }
+ }
+ if (index == -1)
+ { // Append required
+ if (i == MAX_ACS_STORE)
+ {
+ I_Error("AddToACSStore: MAX_ACS_STORE (%d) exceeded.",
+ MAX_ACS_STORE);
+ }
+ index = i;
+ ACSStore[index + 1].map = 0;
+ }
+ ACSStore[index].map = map;
+ ACSStore[index].script = number;
+ memcpy(ACSStore[index].args, args, sizeof(int));
+ return true;
+}
+
+//==========================================================================
+//
+// P_StartLockedACS
+//
+//==========================================================================
+
+
+boolean P_StartLockedACS(line_t * line, byte * args, mobj_t * mo, int side)
+{
+ int i;
+ int lock;
+ byte newArgs[5];
+ char LockedBuffer[80];
+
+ extern char *TextKeyMessages[11];
+
+ lock = args[4];
+ if (!mo->player)
+ {
+ return false;
+ }
+ if (lock)
+ {
+ if (!(mo->player->keys & (1 << (lock - 1))))
+ {
+ sprintf(LockedBuffer, "YOU NEED THE %s\n",
+ TextKeyMessages[lock - 1]);
+ P_SetMessage(mo->player, LockedBuffer, true);
+ S_StartSound(mo, SFX_DOOR_LOCKED);
+ return false;
+ }
+ }
+ for (i = 0; i < 4; i++)
+ {
+ newArgs[i] = args[i];
+ }
+ newArgs[4] = 0;
+ return P_StartACS(newArgs[0], newArgs[1], &newArgs[2], mo, line, side);
+}
+
+//==========================================================================
+//
+// P_TerminateACS
+//
+//==========================================================================
+
+boolean P_TerminateACS(int number, int map)
+{
+ int infoIndex;
+
+ infoIndex = GetACSIndex(number);
+ if (infoIndex == -1)
+ { // Script not found
+ return false;
+ }
+ if (ACSInfo[infoIndex].state == ASTE_INACTIVE
+ || ACSInfo[infoIndex].state == ASTE_TERMINATING)
+ { // States that disallow termination
+ return false;
+ }
+ ACSInfo[infoIndex].state = ASTE_TERMINATING;
+ return true;
+}
+
+//==========================================================================
+//
+// P_SuspendACS
+//
+//==========================================================================
+
+boolean P_SuspendACS(int number, int map)
+{
+ int infoIndex;
+
+ infoIndex = GetACSIndex(number);
+ if (infoIndex == -1)
+ { // Script not found
+ return false;
+ }
+ if (ACSInfo[infoIndex].state == ASTE_INACTIVE
+ || ACSInfo[infoIndex].state == ASTE_SUSPENDED
+ || ACSInfo[infoIndex].state == ASTE_TERMINATING)
+ { // States that disallow suspension
+ return false;
+ }
+ ACSInfo[infoIndex].state = ASTE_SUSPENDED;
+ return true;
+}
+
+//==========================================================================
+//
+// P_Init
+//
+//==========================================================================
+
+void P_ACSInitNewGame(void)
+{
+ memset(WorldVars, 0, sizeof(WorldVars));
+ memset(ACSStore, 0, sizeof(ACSStore));
+}
+
+//==========================================================================
+//
+// T_InterpretACS
+//
+//==========================================================================
+
+void T_InterpretACS(acs_t * script)
+{
+ int cmd;
+ int action;
+
+ if (ACSInfo[script->infoIndex].state == ASTE_TERMINATING)
+ {
+ ACSInfo[script->infoIndex].state = ASTE_INACTIVE;
+ ScriptFinished(ACScript->number);
+ P_RemoveThinker(&ACScript->thinker);
+ return;
+ }
+ if (ACSInfo[script->infoIndex].state != ASTE_RUNNING)
+ {
+ return;
+ }
+ if (script->delayCount)
+ {
+ script->delayCount--;
+ return;
+ }
+ ACScript = script;
+ PCodePtr = ACScript->ip;
+
+ do
+ {
+ cmd = LONG(*PCodePtr);
+ ++PCodePtr;
+
+ action = PCodeCmds[cmd] ();
+ } while (action == SCRIPT_CONTINUE);
+
+ ACScript->ip = PCodePtr;
+
+ if (action == SCRIPT_TERMINATE)
+ {
+ ACSInfo[script->infoIndex].state = ASTE_INACTIVE;
+ ScriptFinished(ACScript->number);
+ P_RemoveThinker(&ACScript->thinker);
+ }
+}
+
+//==========================================================================
+//
+// P_TagFinished
+//
+//==========================================================================
+
+void P_TagFinished(int tag)
+{
+ int i;
+
+ if (TagBusy(tag) == true)
+ {
+ return;
+ }
+ for (i = 0; i < ACScriptCount; i++)
+ {
+ if (ACSInfo[i].state == ASTE_WAITINGFORTAG
+ && ACSInfo[i].waitValue == tag)
+ {
+ ACSInfo[i].state = ASTE_RUNNING;
+ }
+ }
+}
+
+//==========================================================================
+//
+// P_PolyobjFinished
+//
+//==========================================================================
+
+void P_PolyobjFinished(int po)
+{
+ int i;
+
+ if (PO_Busy(po) == true)
+ {
+ return;
+ }
+ for (i = 0; i < ACScriptCount; i++)
+ {
+ if (ACSInfo[i].state == ASTE_WAITINGFORPOLY
+ && ACSInfo[i].waitValue == po)
+ {
+ ACSInfo[i].state = ASTE_RUNNING;
+ }
+ }
+}
+
+//==========================================================================
+//
+// ScriptFinished
+//
+//==========================================================================
+
+static void ScriptFinished(int number)
+{
+ int i;
+
+ for (i = 0; i < ACScriptCount; i++)
+ {
+ if (ACSInfo[i].state == ASTE_WAITINGFORSCRIPT
+ && ACSInfo[i].waitValue == number)
+ {
+ ACSInfo[i].state = ASTE_RUNNING;
+ }
+ }
+}
+
+//==========================================================================
+//
+// TagBusy
+//
+//==========================================================================
+
+static boolean TagBusy(int tag)
+{
+ int sectorIndex;
+
+ sectorIndex = -1;
+ while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
+ {
+ if (sectors[sectorIndex].specialdata)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+//==========================================================================
+//
+// GetACSIndex
+//
+// Returns the index of a script number. Returns -1 if the script number
+// is not found.
+//
+//==========================================================================
+
+static int GetACSIndex(int number)
+{
+ int i;
+
+ for (i = 0; i < ACScriptCount; i++)
+ {
+ if (ACSInfo[i].number == number)
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+//==========================================================================
+//
+// Push
+//
+//==========================================================================
+
+static void Push(int value)
+{
+ ACScript->stack[ACScript->stackPtr++] = value;
+}
+
+//==========================================================================
+//
+// Pop
+//
+//==========================================================================
+
+static int Pop(void)
+{
+ return ACScript->stack[--ACScript->stackPtr];
+}
+
+//==========================================================================
+//
+// Top
+//
+//==========================================================================
+
+static int Top(void)
+{
+ return ACScript->stack[ACScript->stackPtr - 1];
+}
+
+//==========================================================================
+//
+// Drop
+//
+//==========================================================================
+
+static void Drop(void)
+{
+ ACScript->stackPtr--;
+}
+
+//==========================================================================
+//
+// P-Code Commands
+//
+//==========================================================================
+
+static int CmdNOP(void)
+{
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdTerminate(void)
+{
+ return SCRIPT_TERMINATE;
+}
+
+static int CmdSuspend(void)
+{
+ ACSInfo[ACScript->infoIndex].state = ASTE_SUSPENDED;
+ return SCRIPT_STOP;
+}
+
+static int CmdPushNumber(void)
+{
+ Push(LONG(*PCodePtr));
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec1(void)
+{
+ int special;
+
+ special = LONG(*PCodePtr);
+ ++PCodePtr;
+ SpecArgs[0] = Pop();
+ P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+ ACScript->side, ACScript->activator);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec2(void)
+{
+ int special;
+
+ special = LONG(*PCodePtr);
+ ++PCodePtr;
+ SpecArgs[1] = Pop();
+ SpecArgs[0] = Pop();
+ P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+ ACScript->side, ACScript->activator);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec3(void)
+{
+ int special;
+
+ special = LONG(*PCodePtr);
+ ++PCodePtr;
+ SpecArgs[2] = Pop();
+ SpecArgs[1] = Pop();
+ SpecArgs[0] = Pop();
+ P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+ ACScript->side, ACScript->activator);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec4(void)
+{
+ int special;
+
+ special = LONG(*PCodePtr);
+ ++PCodePtr;
+ SpecArgs[3] = Pop();
+ SpecArgs[2] = Pop();
+ SpecArgs[1] = Pop();
+ SpecArgs[0] = Pop();
+ P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+ ACScript->side, ACScript->activator);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec5(void)
+{
+ int special;
+
+ special = LONG(*PCodePtr);
+ ++PCodePtr;
+ SpecArgs[4] = Pop();
+ SpecArgs[3] = Pop();
+ SpecArgs[2] = Pop();
+ SpecArgs[1] = Pop();
+ SpecArgs[0] = Pop();
+ P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+ ACScript->side, ACScript->activator);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec1Direct(void)
+{
+ int special;
+
+ special = LONG(*PCodePtr);
+ ++PCodePtr;
+ SpecArgs[0] = LONG(*PCodePtr);
+ ++PCodePtr;
+ P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+ ACScript->side, ACScript->activator);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec2Direct(void)
+{
+ int special;
+
+ special = LONG(*PCodePtr);
+ ++PCodePtr;
+ SpecArgs[0] = LONG(*PCodePtr);
+ ++PCodePtr;
+ SpecArgs[1] = LONG(*PCodePtr);
+ ++PCodePtr;
+ P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+ ACScript->side, ACScript->activator);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec3Direct(void)
+{
+ int special;
+
+ special = LONG(*PCodePtr);
+ ++PCodePtr;
+ SpecArgs[0] = LONG(*PCodePtr);
+ ++PCodePtr;
+ SpecArgs[1] = LONG(*PCodePtr);
+ ++PCodePtr;
+ SpecArgs[2] = LONG(*PCodePtr);
+ ++PCodePtr;
+ P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+ ACScript->side, ACScript->activator);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec4Direct(void)
+{
+ int special;
+
+ special = LONG(*PCodePtr);
+ ++PCodePtr;
+ SpecArgs[0] = LONG(*PCodePtr);
+ ++PCodePtr;
+ SpecArgs[1] = LONG(*PCodePtr);
+ ++PCodePtr;
+ SpecArgs[2] = LONG(*PCodePtr);
+ ++PCodePtr;
+ SpecArgs[3] = LONG(*PCodePtr);
+ ++PCodePtr;
+ P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+ ACScript->side, ACScript->activator);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec5Direct(void)
+{
+ int special;
+
+ special = LONG(*PCodePtr);
+ ++PCodePtr;
+ SpecArgs[0] = LONG(*PCodePtr);
+ ++PCodePtr;
+ SpecArgs[1] = LONG(*PCodePtr);
+ ++PCodePtr;
+ SpecArgs[2] = LONG(*PCodePtr);
+ ++PCodePtr;
+ SpecArgs[3] = LONG(*PCodePtr);
+ ++PCodePtr;
+ SpecArgs[4] = LONG(*PCodePtr);
+ ++PCodePtr;
+ P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+ ACScript->side, ACScript->activator);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdAdd(void)
+{
+ Push(Pop() + Pop());
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdSubtract(void)
+{
+ int operand2;
+
+ operand2 = Pop();
+ Push(Pop() - operand2);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdMultiply(void)
+{
+ Push(Pop() * Pop());
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdDivide(void)
+{
+ int operand2;
+
+ operand2 = Pop();
+ Push(Pop() / operand2);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdModulus(void)
+{
+ int operand2;
+
+ operand2 = Pop();
+ Push(Pop() % operand2);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdEQ(void)
+{
+ Push(Pop() == Pop());
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdNE(void)
+{
+ Push(Pop() != Pop());
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLT(void)
+{
+ int operand2;
+
+ operand2 = Pop();
+ Push(Pop() < operand2);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdGT(void)
+{
+ int operand2;
+
+ operand2 = Pop();
+ Push(Pop() > operand2);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLE(void)
+{
+ int operand2;
+
+ operand2 = Pop();
+ Push(Pop() <= operand2);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdGE(void)
+{
+ int operand2;
+
+ operand2 = Pop();
+ Push(Pop() >= operand2);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdAssignScriptVar(void)
+{
+ ACScript->vars[LONG(*PCodePtr)] = Pop();
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdAssignMapVar(void)
+{
+ MapVars[LONG(*PCodePtr)] = Pop();
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdAssignWorldVar(void)
+{
+ WorldVars[LONG(*PCodePtr)] = Pop();
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdPushScriptVar(void)
+{
+ Push(ACScript->vars[LONG(*PCodePtr)]);
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdPushMapVar(void)
+{
+ Push(MapVars[LONG(*PCodePtr)]);
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdPushWorldVar(void)
+{
+ Push(WorldVars[LONG(*PCodePtr)]);
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdAddScriptVar(void)
+{
+ ACScript->vars[LONG(*PCodePtr)] += Pop();
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdAddMapVar(void)
+{
+ MapVars[LONG(*PCodePtr)] += Pop();
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdAddWorldVar(void)
+{
+ WorldVars[LONG(*PCodePtr)] += Pop();
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdSubScriptVar(void)
+{
+ ACScript->vars[LONG(*PCodePtr)] -= Pop();
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdSubMapVar(void)
+{
+ MapVars[LONG(*PCodePtr)] -= Pop();
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdSubWorldVar(void)
+{
+ WorldVars[LONG(*PCodePtr)] -= Pop();
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdMulScriptVar(void)
+{
+ ACScript->vars[LONG(*PCodePtr)] *= Pop();
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdMulMapVar(void)
+{
+ MapVars[LONG(*PCodePtr)] *= Pop();
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdMulWorldVar(void)
+{
+ WorldVars[LONG(*PCodePtr)] *= Pop();
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdDivScriptVar(void)
+{
+ ACScript->vars[LONG(*PCodePtr)] /= Pop();
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdDivMapVar(void)
+{
+ MapVars[LONG(*PCodePtr)] /= Pop();
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdDivWorldVar(void)
+{
+ WorldVars[LONG(*PCodePtr)] /= Pop();
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdModScriptVar(void)
+{
+ ACScript->vars[LONG(*PCodePtr)] %= Pop();
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdModMapVar(void)
+{
+ MapVars[LONG(*PCodePtr)] %= Pop();
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdModWorldVar(void)
+{
+ WorldVars[LONG(*PCodePtr)] %= Pop();
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdIncScriptVar(void)
+{
+ ++ACScript->vars[LONG(*PCodePtr)];
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdIncMapVar(void)
+{
+ ++MapVars[LONG(*PCodePtr)];
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdIncWorldVar(void)
+{
+ ++WorldVars[LONG(*PCodePtr)];
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdDecScriptVar(void)
+{
+ --ACScript->vars[LONG(*PCodePtr)];
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdDecMapVar(void)
+{
+ --MapVars[LONG(*PCodePtr)];
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdDecWorldVar(void)
+{
+ --WorldVars[LONG(*PCodePtr)];
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdGoto(void)
+{
+ PCodePtr = (int *) (ActionCodeBase + LONG(*PCodePtr));
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdIfGoto(void)
+{
+ if (Pop() != 0)
+ {
+ PCodePtr = (int *) (ActionCodeBase + LONG(*PCodePtr));
+ }
+ else
+ {
+ ++PCodePtr;
+ }
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdDrop(void)
+{
+ Drop();
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdDelay(void)
+{
+ ACScript->delayCount = Pop();
+ return SCRIPT_STOP;
+}
+
+static int CmdDelayDirect(void)
+{
+ ACScript->delayCount = LONG(*PCodePtr);
+ ++PCodePtr;
+ return SCRIPT_STOP;
+}
+
+static int CmdRandom(void)
+{
+ int low;
+ int high;
+
+ high = Pop();
+ low = Pop();
+ Push(low + (P_Random() % (high - low + 1)));
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdRandomDirect(void)
+{
+ int low;
+ int high;
+
+ low = LONG(*PCodePtr);
+ ++PCodePtr;
+ high = LONG(*PCodePtr);
+ ++PCodePtr;
+ Push(low + (P_Random() % (high - low + 1)));
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdThingCount(void)
+{
+ int tid;
+
+ tid = Pop();
+ ThingCount(Pop(), tid);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdThingCountDirect(void)
+{
+ int type;
+
+ type = LONG(*PCodePtr);
+ ++PCodePtr;
+ ThingCount(type, LONG(*PCodePtr));
+ ++PCodePtr;
+ return SCRIPT_CONTINUE;
+}
+
+static void ThingCount(int type, int tid)
+{
+ int count;
+ int searcher;
+ mobj_t *mobj;
+ mobjtype_t moType;
+ thinker_t *think;
+
+ if (!(type + tid))
+ { // Nothing to count
+ return;
+ }
+ moType = TranslateThingType[type];
+ count = 0;
+ searcher = -1;
+ if (tid)
+ { // Count TID things
+ while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
+ {
+ if (type == 0)
+ { // Just count TIDs
+ count++;
+ }
+ else if (moType == mobj->type)
+ {
+ if (mobj->flags & MF_COUNTKILL && mobj->health <= 0)
+ { // Don't count dead monsters
+ continue;
+ }
+ count++;
+ }
+ }
+ }
+ else
+ { // Count only types
+ for (think = thinkercap.next; think != &thinkercap;
+ think = think->next)
+ {
+ if (think->function != P_MobjThinker)
+ { // Not a mobj thinker
+ continue;
+ }
+ mobj = (mobj_t *) think;
+ if (mobj->type != moType)
+ { // Doesn't match
+ continue;
+ }
+ if (mobj->flags & MF_COUNTKILL && mobj->health <= 0)
+ { // Don't count dead monsters
+ continue;
+ }
+ count++;
+ }
+ }
+ Push(count);
+}
+
+static int CmdTagWait(void)
+{
+ ACSInfo[ACScript->infoIndex].waitValue = Pop();
+ ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORTAG;
+ return SCRIPT_STOP;
+}
+
+static int CmdTagWaitDirect(void)
+{
+ ACSInfo[ACScript->infoIndex].waitValue = LONG(*PCodePtr);
+ ++PCodePtr;
+ ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORTAG;
+ return SCRIPT_STOP;
+}
+
+static int CmdPolyWait(void)
+{
+ ACSInfo[ACScript->infoIndex].waitValue = Pop();
+ ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORPOLY;
+ return SCRIPT_STOP;
+}
+
+static int CmdPolyWaitDirect(void)
+{
+ ACSInfo[ACScript->infoIndex].waitValue = LONG(*PCodePtr);
+ ++PCodePtr;
+ ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORPOLY;
+ return SCRIPT_STOP;
+}
+
+static int CmdChangeFloor(void)
+{
+ int tag;
+ int flat;
+ int sectorIndex;
+
+ flat = R_FlatNumForName(ACStrings[Pop()]);
+ tag = Pop();
+ sectorIndex = -1;
+ while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
+ {
+ sectors[sectorIndex].floorpic = flat;
+ }
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdChangeFloorDirect(void)
+{
+ int tag;
+ int flat;
+ int sectorIndex;
+
+ tag = LONG(*PCodePtr);
+ ++PCodePtr;
+ flat = R_FlatNumForName(ACStrings[LONG(*PCodePtr)]);
+ ++PCodePtr;
+ sectorIndex = -1;
+ while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
+ {
+ sectors[sectorIndex].floorpic = flat;
+ }
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdChangeCeiling(void)
+{
+ int tag;
+ int flat;
+ int sectorIndex;
+
+ flat = R_FlatNumForName(ACStrings[Pop()]);
+ tag = Pop();
+ sectorIndex = -1;
+ while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
+ {
+ sectors[sectorIndex].ceilingpic = flat;
+ }
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdChangeCeilingDirect(void)
+{
+ int tag;
+ int flat;
+ int sectorIndex;
+
+ tag = LONG(*PCodePtr);
+ ++PCodePtr;
+ flat = R_FlatNumForName(ACStrings[LONG(*PCodePtr)]);
+ ++PCodePtr;
+ sectorIndex = -1;
+ while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
+ {
+ sectors[sectorIndex].ceilingpic = flat;
+ }
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdRestart(void)
+{
+ PCodePtr = ACSInfo[ACScript->infoIndex].address;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdAndLogical(void)
+{
+ Push(Pop() && Pop());
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdOrLogical(void)
+{
+ Push(Pop() || Pop());
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdAndBitwise(void)
+{
+ Push(Pop() & Pop());
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdOrBitwise(void)
+{
+ Push(Pop() | Pop());
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdEorBitwise(void)
+{
+ Push(Pop() ^ Pop());
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdNegateLogical(void)
+{
+ Push(!Pop());
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLShift(void)
+{
+ int operand2;
+
+ operand2 = Pop();
+ Push(Pop() << operand2);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdRShift(void)
+{
+ int operand2;
+
+ operand2 = Pop();
+ Push(Pop() >> operand2);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdUnaryMinus(void)
+{
+ Push(-Pop());
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdIfNotGoto(void)
+{
+ if (Pop() != 0)
+ {
+ ++PCodePtr;
+ }
+ else
+ {
+ PCodePtr = (int *) (ActionCodeBase + LONG(*PCodePtr));
+ }
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLineSide(void)
+{
+ Push(ACScript->side);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdScriptWait(void)
+{
+ ACSInfo[ACScript->infoIndex].waitValue = Pop();
+ ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORSCRIPT;
+ return SCRIPT_STOP;
+}
+
+static int CmdScriptWaitDirect(void)
+{
+ ACSInfo[ACScript->infoIndex].waitValue = LONG(*PCodePtr);
+ ++PCodePtr;
+ ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORSCRIPT;
+ return SCRIPT_STOP;
+}
+
+static int CmdClearLineSpecial(void)
+{
+ if (ACScript->line)
+ {
+ ACScript->line->special = 0;
+ }
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdCaseGoto(void)
+{
+ int value;
+
+ value = LONG(*PCodePtr);
+ ++PCodePtr;
+
+ if (Top() == value)
+ {
+ PCodePtr = (int *) (ActionCodeBase + LONG(*PCodePtr));
+ Drop();
+ }
+ else
+ {
+ ++PCodePtr;
+ }
+
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdBeginPrint(void)
+{
+ *PrintBuffer = 0;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdEndPrint(void)
+{
+ player_t *player;
+
+ if (ACScript->activator && ACScript->activator->player)
+ {
+ player = ACScript->activator->player;
+ }
+ else
+ {
+ player = &players[consoleplayer];
+ }
+ P_SetMessage(player, PrintBuffer, true);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdEndPrintBold(void)
+{
+ int i;
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ {
+ P_SetYellowMessage(&players[i], PrintBuffer, true);
+ }
+ }
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdPrintString(void)
+{
+ strcat(PrintBuffer, ACStrings[Pop()]);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdPrintNumber(void)
+{
+ char tempStr[16];
+
+ sprintf(tempStr, "%d", Pop());
+ strcat(PrintBuffer, tempStr);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdPrintCharacter(void)
+{
+ char *bufferEnd;
+
+ bufferEnd = PrintBuffer + strlen(PrintBuffer);
+ *bufferEnd++ = Pop();
+ *bufferEnd = 0;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdPlayerCount(void)
+{
+ int i;
+ int count;
+
+ count = 0;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ count += playeringame[i];
+ }
+ Push(count);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdGameType(void)
+{
+ int gametype;
+
+ if (netgame == false)
+ {
+ gametype = GAME_SINGLE_PLAYER;
+ }
+ else if (deathmatch)
+ {
+ gametype = GAME_NET_DEATHMATCH;
+ }
+ else
+ {
+ gametype = GAME_NET_COOPERATIVE;
+ }
+ Push(gametype);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdGameSkill(void)
+{
+ Push(gameskill);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdTimer(void)
+{
+ Push(leveltime);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdSectorSound(void)
+{
+ int volume;
+ mobj_t *mobj;
+
+ mobj = NULL;
+ if (ACScript->line)
+ {
+ mobj = (mobj_t *) & ACScript->line->frontsector->soundorg;
+ }
+ volume = Pop();
+ S_StartSoundAtVolume(mobj, S_GetSoundID(ACStrings[Pop()]), volume);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdThingSound(void)
+{
+ int tid;
+ int sound;
+ int volume;
+ mobj_t *mobj;
+ int searcher;
+
+ volume = Pop();
+ sound = S_GetSoundID(ACStrings[Pop()]);
+ tid = Pop();
+ searcher = -1;
+ while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
+ {
+ S_StartSoundAtVolume(mobj, sound, volume);
+ }
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdAmbientSound(void)
+{
+ int volume;
+
+ volume = Pop();
+ S_StartSoundAtVolume(NULL, S_GetSoundID(ACStrings[Pop()]), volume);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdSoundSequence(void)
+{
+ mobj_t *mobj;
+
+ mobj = NULL;
+ if (ACScript->line)
+ {
+ mobj = (mobj_t *) & ACScript->line->frontsector->soundorg;
+ }
+ SN_StartSequenceName(mobj, ACStrings[Pop()]);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdSetLineTexture(void)
+{
+ line_t *line;
+ int lineTag;
+ int side;
+ int position;
+ int texture;
+ int searcher;
+
+ texture = R_TextureNumForName(ACStrings[Pop()]);
+ position = Pop();
+ side = Pop();
+ lineTag = Pop();
+ searcher = -1;
+ while ((line = P_FindLine(lineTag, &searcher)) != NULL)
+ {
+ if (position == TEXTURE_MIDDLE)
+ {
+ sides[line->sidenum[side]].midtexture = texture;
+ }
+ else if (position == TEXTURE_BOTTOM)
+ {
+ sides[line->sidenum[side]].bottomtexture = texture;
+ }
+ else
+ { // TEXTURE_TOP
+ sides[line->sidenum[side]].toptexture = texture;
+ }
+ }
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdSetLineBlocking(void)
+{
+ line_t *line;
+ int lineTag;
+ boolean blocking;
+ int searcher;
+
+ blocking = Pop()? ML_BLOCKING : 0;
+ lineTag = Pop();
+ searcher = -1;
+ while ((line = P_FindLine(lineTag, &searcher)) != NULL)
+ {
+ line->flags = (line->flags & ~ML_BLOCKING) | blocking;
+ }
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdSetLineSpecial(void)
+{
+ line_t *line;
+ int lineTag;
+ int special, arg1, arg2, arg3, arg4, arg5;
+ int searcher;
+
+ arg5 = Pop();
+ arg4 = Pop();
+ arg3 = Pop();
+ arg2 = Pop();
+ arg1 = Pop();
+ special = Pop();
+ lineTag = Pop();
+ searcher = -1;
+ while ((line = P_FindLine(lineTag, &searcher)) != NULL)
+ {
+ line->special = special;
+ line->arg1 = arg1;
+ line->arg2 = arg2;
+ line->arg3 = arg3;
+ line->arg4 = arg4;
+ line->arg5 = arg5;
+ }
+ return SCRIPT_CONTINUE;
+}
diff --git a/src/hexen/p_anim.c b/src/hexen/p_anim.c
new file mode 100644
index 00000000..7655aef2
--- /dev/null
+++ b/src/hexen/p_anim.c
@@ -0,0 +1,488 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2def.h"
+#include "m_random.h"
+#include "i_system.h"
+#include "p_local.h"
+#include "s_sound.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define ANIM_SCRIPT_NAME "ANIMDEFS"
+#define MAX_ANIM_DEFS 20
+#define MAX_FRAME_DEFS 96
+#define ANIM_FLAT 0
+#define ANIM_TEXTURE 1
+#define SCI_FLAT "flat"
+#define SCI_TEXTURE "texture"
+#define SCI_PIC "pic"
+#define SCI_TICS "tics"
+#define SCI_RAND "rand"
+
+#define LIGHTNING_SPECIAL 198
+#define LIGHTNING_SPECIAL2 199
+#define SKYCHANGE_SPECIAL 200
+
+// TYPES -------------------------------------------------------------------
+
+typedef struct
+{
+ int index;
+ int tics;
+} frameDef_t;
+
+typedef struct
+{
+ int type;
+ int index;
+ int tics;
+ int currentFrameDef;
+ int startFrameDef;
+ int endFrameDef;
+} animDef_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void P_LightningFlash(void);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern fixed_t Sky1ColumnOffset;
+extern fixed_t Sky2ColumnOffset;
+extern boolean DoubleSky;
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+fixed_t Sky1ScrollDelta;
+fixed_t Sky2ScrollDelta;
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static animDef_t AnimDefs[MAX_ANIM_DEFS];
+static frameDef_t FrameDefs[MAX_FRAME_DEFS];
+static int AnimDefCount;
+static boolean LevelHasLightning;
+static int NextLightningFlash;
+static int LightningFlash;
+static int *LightningLightLevels;
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// P_AnimateSurfaces
+//
+//==========================================================================
+
+void P_AnimateSurfaces(void)
+{
+ int i;
+ animDef_t *ad;
+ line_t *line;
+
+ // Animate flats and textures
+ for (i = 0; i < AnimDefCount; i++)
+ {
+ ad = &AnimDefs[i];
+ ad->tics--;
+ if (ad->tics == 0)
+ {
+ if (ad->currentFrameDef == ad->endFrameDef)
+ {
+ ad->currentFrameDef = ad->startFrameDef;
+ }
+ else
+ {
+ ad->currentFrameDef++;
+ }
+ ad->tics = FrameDefs[ad->currentFrameDef].tics;
+ if (ad->tics > 255)
+ { // Random tics
+ ad->tics = (ad->tics >> 16)
+ + P_Random() % ((ad->tics & 0xff00) >> 8);
+ }
+ if (ad->type == ANIM_FLAT)
+ {
+ flattranslation[ad->index] =
+ FrameDefs[ad->currentFrameDef].index;
+ }
+ else
+ { // Texture
+ texturetranslation[ad->index] =
+ FrameDefs[ad->currentFrameDef].index;
+ }
+ }
+ }
+
+ // Update scrolling textures
+ for (i = 0; i < numlinespecials; i++)
+ {
+ line = linespeciallist[i];
+ switch (line->special)
+ {
+ case 100: // Scroll_Texture_Left
+ sides[line->sidenum[0]].textureoffset += line->arg1 << 10;
+ break;
+ case 101: // Scroll_Texture_Right
+ sides[line->sidenum[0]].textureoffset -= line->arg1 << 10;
+ break;
+ case 102: // Scroll_Texture_Up
+ sides[line->sidenum[0]].rowoffset += line->arg1 << 10;
+ break;
+ case 103: // Scroll_Texture_Down
+ sides[line->sidenum[0]].rowoffset -= line->arg1 << 10;
+ break;
+ }
+ }
+
+ // Update sky column offsets
+ Sky1ColumnOffset += Sky1ScrollDelta;
+ Sky2ColumnOffset += Sky2ScrollDelta;
+
+ if (LevelHasLightning)
+ {
+ if (!NextLightningFlash || LightningFlash)
+ {
+ P_LightningFlash();
+ }
+ else
+ {
+ NextLightningFlash--;
+ }
+ }
+}
+
+//==========================================================================
+//
+// P_LightningFlash
+//
+//==========================================================================
+
+static void P_LightningFlash(void)
+{
+ int i;
+ sector_t *tempSec;
+ int *tempLight;
+ boolean foundSec;
+ int flashLight;
+
+ if (LightningFlash)
+ {
+ LightningFlash--;
+ if (LightningFlash)
+ {
+ tempLight = LightningLightLevels;
+ tempSec = sectors;
+ for (i = 0; i < numsectors; i++, tempSec++)
+ {
+ if (tempSec->ceilingpic == skyflatnum
+ || tempSec->special == LIGHTNING_SPECIAL
+ || tempSec->special == LIGHTNING_SPECIAL2)
+ {
+ if (*tempLight < tempSec->lightlevel - 4)
+ {
+ tempSec->lightlevel -= 4;
+ }
+ tempLight++;
+ }
+ }
+ }
+ else
+ { // remove the alternate lightning flash special
+ tempLight = LightningLightLevels;
+ tempSec = sectors;
+ for (i = 0; i < numsectors; i++, tempSec++)
+ {
+ if (tempSec->ceilingpic == skyflatnum
+ || tempSec->special == LIGHTNING_SPECIAL
+ || tempSec->special == LIGHTNING_SPECIAL2)
+ {
+ tempSec->lightlevel = *tempLight;
+ tempLight++;
+ }
+ }
+ Sky1Texture = P_GetMapSky1Texture(gamemap);
+ }
+ return;
+ }
+ LightningFlash = (P_Random() & 7) + 8;
+ flashLight = 200 + (P_Random() & 31);
+ tempSec = sectors;
+ tempLight = LightningLightLevels;
+ foundSec = false;
+ for (i = 0; i < numsectors; i++, tempSec++)
+ {
+ if (tempSec->ceilingpic == skyflatnum
+ || tempSec->special == LIGHTNING_SPECIAL
+ || tempSec->special == LIGHTNING_SPECIAL2)
+ {
+ *tempLight = tempSec->lightlevel;
+ if (tempSec->special == LIGHTNING_SPECIAL)
+ {
+ tempSec->lightlevel += 64;
+ if (tempSec->lightlevel > flashLight)
+ {
+ tempSec->lightlevel = flashLight;
+ }
+ }
+ else if (tempSec->special == LIGHTNING_SPECIAL2)
+ {
+ tempSec->lightlevel += 32;
+ if (tempSec->lightlevel > flashLight)
+ {
+ tempSec->lightlevel = flashLight;
+ }
+ }
+ else
+ {
+ tempSec->lightlevel = flashLight;
+ }
+ if (tempSec->lightlevel < *tempLight)
+ {
+ tempSec->lightlevel = *tempLight;
+ }
+ tempLight++;
+ foundSec = true;
+ }
+ }
+ if (foundSec)
+ {
+ Sky1Texture = P_GetMapSky2Texture(gamemap); // set alternate sky
+ S_StartSound(NULL, SFX_THUNDER_CRASH);
+ }
+ // Calculate the next lighting flash
+ if (!NextLightningFlash)
+ {
+ if (P_Random() < 50)
+ { // Immediate Quick flash
+ NextLightningFlash = (P_Random() & 15) + 16;
+ }
+ else
+ {
+ if (P_Random() < 128 && !(leveltime & 32))
+ {
+ NextLightningFlash = ((P_Random() & 7) + 2) * 35;
+ }
+ else
+ {
+ NextLightningFlash = ((P_Random() & 15) + 5) * 35;
+ }
+ }
+ }
+}
+
+//==========================================================================
+//
+// P_ForceLightning
+//
+//==========================================================================
+
+void P_ForceLightning(void)
+{
+ NextLightningFlash = 0;
+}
+
+//==========================================================================
+//
+// P_InitLightning
+//
+//==========================================================================
+
+void P_InitLightning(void)
+{
+ int i;
+ int secCount;
+
+ if (!P_GetMapLightning(gamemap))
+ {
+ LevelHasLightning = false;
+ LightningFlash = 0;
+ return;
+ }
+ LightningFlash = 0;
+ secCount = 0;
+ for (i = 0; i < numsectors; i++)
+ {
+ if (sectors[i].ceilingpic == skyflatnum
+ || sectors[i].special == LIGHTNING_SPECIAL
+ || sectors[i].special == LIGHTNING_SPECIAL2)
+ {
+ secCount++;
+ }
+ }
+ if (secCount)
+ {
+ LevelHasLightning = true;
+ }
+ else
+ {
+ LevelHasLightning = false;
+ return;
+ }
+ LightningLightLevels = (int *) Z_Malloc(secCount * sizeof(int), PU_LEVEL,
+ NULL);
+ NextLightningFlash = ((P_Random() & 15) + 5) * 35; // don't flash at level start
+}
+
+//==========================================================================
+//
+// P_InitFTAnims
+//
+// Initialize flat and texture animation lists.
+//
+//==========================================================================
+
+void P_InitFTAnims(void)
+{
+ int base;
+ int mod;
+ int fd;
+ animDef_t *ad;
+ boolean ignore;
+ boolean done;
+
+ fd = 0;
+ ad = AnimDefs;
+ AnimDefCount = 0;
+ SC_Open(ANIM_SCRIPT_NAME);
+ while (SC_GetString())
+ {
+ if (AnimDefCount == MAX_ANIM_DEFS)
+ {
+ I_Error("P_InitFTAnims: too many AnimDefs.");
+ }
+ if (SC_Compare(SCI_FLAT))
+ {
+ ad->type = ANIM_FLAT;
+ }
+ else if (SC_Compare(SCI_TEXTURE))
+ {
+ ad->type = ANIM_TEXTURE;
+ }
+ else
+ {
+ SC_ScriptError(NULL);
+ }
+ SC_MustGetString(); // Name
+ ignore = false;
+ if (ad->type == ANIM_FLAT)
+ {
+ if (W_CheckNumForName(sc_String) == -1)
+ {
+ ignore = true;
+ }
+ else
+ {
+ ad->index = R_FlatNumForName(sc_String);
+ }
+ }
+ else
+ { // Texture
+ if (R_CheckTextureNumForName(sc_String) == -1)
+ {
+ ignore = true;
+ }
+ else
+ {
+ ad->index = R_TextureNumForName(sc_String);
+ }
+ }
+ ad->startFrameDef = fd;
+ done = false;
+ while (done == false)
+ {
+ if (SC_GetString())
+ {
+ if (SC_Compare(SCI_PIC))
+ {
+ if (fd == MAX_FRAME_DEFS)
+ {
+ I_Error("P_InitFTAnims: too many FrameDefs.");
+ }
+ SC_MustGetNumber();
+ if (ignore == false)
+ {
+ FrameDefs[fd].index = ad->index + sc_Number - 1;
+ }
+ SC_MustGetString();
+ if (SC_Compare(SCI_TICS))
+ {
+ SC_MustGetNumber();
+ if (ignore == false)
+ {
+ FrameDefs[fd].tics = sc_Number;
+ fd++;
+ }
+ }
+ else if (SC_Compare(SCI_RAND))
+ {
+ SC_MustGetNumber();
+ base = sc_Number;
+ SC_MustGetNumber();
+ if (ignore == false)
+ {
+ mod = sc_Number - base + 1;
+ FrameDefs[fd].tics = (base << 16) + (mod << 8);
+ fd++;
+ }
+ }
+ else
+ {
+ SC_ScriptError(NULL);
+ }
+ }
+ else
+ {
+ SC_UnGet();
+ done = true;
+ }
+ }
+ else
+ {
+ done = true;
+ }
+ }
+ if ((ignore == false) && (fd - ad->startFrameDef < 2))
+ {
+ I_Error("P_InitFTAnims: AnimDef has framecount < 2.");
+ }
+ if (ignore == false)
+ {
+ ad->endFrameDef = fd - 1;
+ ad->currentFrameDef = ad->endFrameDef;
+ ad->tics = 1; // Force 1st game tic to animate
+ AnimDefCount++;
+ ad++;
+ }
+ }
+ SC_Close();
+}
diff --git a/src/hexen/p_ceilng.c b/src/hexen/p_ceilng.c
new file mode 100644
index 00000000..ab13d3ac
--- /dev/null
+++ b/src/hexen/p_ceilng.c
@@ -0,0 +1,310 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#include "h2def.h"
+#include "p_local.h"
+
+//==================================================================
+//==================================================================
+//
+// 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 (res == RES_PASTDEST)
+ {
+ SN_StopSequence((mobj_t *) & ceiling->sector->soundorg);
+ switch (ceiling->type)
+ {
+ case CLEV_CRUSHANDRAISE:
+ ceiling->direction = -1;
+ ceiling->speed = ceiling->speed * 2;
+ break;
+ default:
+ P_RemoveActiveCeiling(ceiling);
+ break;
+ }
+ }
+ break;
+ case -1: // DOWN
+ res = T_MovePlane(ceiling->sector, ceiling->speed,
+ ceiling->bottomheight, ceiling->crush, 1,
+ ceiling->direction);
+ if (res == RES_PASTDEST)
+ {
+ SN_StopSequence((mobj_t *) & ceiling->sector->soundorg);
+ switch (ceiling->type)
+ {
+ case CLEV_CRUSHANDRAISE:
+ case CLEV_CRUSHRAISEANDSTAY:
+ ceiling->direction = 1;
+ ceiling->speed = ceiling->speed / 2;
+ break;
+ default:
+ P_RemoveActiveCeiling(ceiling);
+ break;
+ }
+ }
+ else if (res == RES_CRUSHED)
+ {
+ switch (ceiling->type)
+ {
+ case CLEV_CRUSHANDRAISE:
+ case CLEV_LOWERANDCRUSH:
+ case CLEV_CRUSHRAISEANDSTAY:
+ //ceiling->speed = ceiling->speed/4;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ }
+}
+
+//==================================================================
+//
+// EV_DoCeiling
+// Move a ceiling up/down and all around!
+//
+//==================================================================
+int EV_DoCeiling(line_t * line, byte * arg, ceiling_e type)
+{
+ int secnum, rtn;
+ sector_t *sec;
+ ceiling_t *ceiling;
+
+ secnum = -1;
+ rtn = 0;
+
+/* Old Ceiling stasis code
+ //
+ // Reactivate in-stasis ceilings...for certain types.
+ //
+ switch(type)
+ {
+ case CLEV_CRUSHANDRAISE:
+ P_ActivateInStasisCeiling(line);
+ default:
+ break;
+ }
+*/
+ while ((secnum = P_FindSectorFromTag(arg[0], 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 = T_MoveCeiling;
+ ceiling->sector = sec;
+ ceiling->crush = 0;
+ ceiling->speed = arg[1] * (FRACUNIT / 8);
+ switch (type)
+ {
+ case CLEV_CRUSHRAISEANDSTAY:
+ ceiling->crush = arg[2]; // arg[2] = crushing value
+ ceiling->topheight = sec->ceilingheight;
+ ceiling->bottomheight = sec->floorheight + (8 * FRACUNIT);
+ ceiling->direction = -1;
+ break;
+ case CLEV_CRUSHANDRAISE:
+ ceiling->topheight = sec->ceilingheight;
+ case CLEV_LOWERANDCRUSH:
+ ceiling->crush = arg[2]; // arg[2] = crushing value
+ case CLEV_LOWERTOFLOOR:
+ ceiling->bottomheight = sec->floorheight;
+ if (type != CLEV_LOWERTOFLOOR)
+ {
+ ceiling->bottomheight += 8 * FRACUNIT;
+ }
+ ceiling->direction = -1;
+ break;
+ case CLEV_RAISETOHIGHEST:
+ ceiling->topheight = P_FindHighestCeilingSurrounding(sec);
+ ceiling->direction = 1;
+ break;
+ case CLEV_LOWERBYVALUE:
+ ceiling->bottomheight =
+ sec->ceilingheight - arg[2] * FRACUNIT;
+ ceiling->direction = -1;
+ break;
+ case CLEV_RAISEBYVALUE:
+ ceiling->topheight = sec->ceilingheight + arg[2] * FRACUNIT;
+ ceiling->direction = 1;
+ break;
+ case CLEV_MOVETOVALUETIMES8:
+ {
+ int destHeight = arg[2] * FRACUNIT * 8;
+
+ if (arg[3])
+ {
+ destHeight = -destHeight;
+ }
+ if (sec->ceilingheight <= destHeight)
+ {
+ ceiling->direction = 1;
+ ceiling->topheight = destHeight;
+ if (sec->ceilingheight == destHeight)
+ {
+ rtn = 0;
+ }
+ }
+ else if (sec->ceilingheight > destHeight)
+ {
+ ceiling->direction = -1;
+ ceiling->bottomheight = destHeight;
+ }
+ break;
+ }
+ default:
+ rtn = 0;
+ break;
+ }
+ ceiling->tag = sec->tag;
+ ceiling->type = type;
+ P_AddActiveCeiling(ceiling);
+ if (rtn)
+ {
+ SN_StartSequence((mobj_t *) & ceiling->sector->soundorg,
+ SEQ_PLATFORM + ceiling->sector->seqType);
+ }
+ }
+ return rtn;
+}
+
+//==================================================================
+//
+// Add an active ceiling
+//
+//==================================================================
+void P_AddActiveCeiling(ceiling_t * c)
+{
+ int i;
+ for (i = 0; i < MAXCEILINGS; i++)
+ if (activeceilings[i] == NULL)
+ {
+ 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 = NULL;
+ P_RemoveThinker(&activeceilings[i]->thinker);
+ P_TagFinished(activeceilings[i]->sector->tag);
+ activeceilings[i] = NULL;
+ break;
+ }
+}
+
+#if 0
+//==================================================================
+//
+// 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->arg1) &&
+ (activeceilings[i]->direction == 0))
+ {
+ activeceilings[i]->direction = activeceilings[i]->olddirection;
+ activeceilings[i]->thinker.function = T_MoveCeiling;
+ SN_StartSequence((mobj_t *) & activeceilings[i]->sector->soundorg,
+ SEQ_PLATFORM +
+ activeceilings[i]->sector->seqType);
+ }
+}
+#endif
+
+//==================================================================
+//
+// EV_CeilingCrushStop
+// Stop a ceiling from crushing!
+//
+//==================================================================
+
+int EV_CeilingCrushStop(line_t * line, byte * args)
+{
+ int i;
+ int rtn;
+
+ rtn = 0;
+ for (i = 0; i < MAXCEILINGS; i++)
+ {
+ if (activeceilings[i] && activeceilings[i]->tag == args[0])
+ {
+ rtn = 1;
+ SN_StopSequence((mobj_t *) & activeceilings[i]->sector->soundorg);
+ activeceilings[i]->sector->specialdata = NULL;
+ P_RemoveThinker(&activeceilings[i]->thinker);
+ P_TagFinished(activeceilings[i]->sector->tag);
+ activeceilings[i] = NULL;
+ break;
+ }
+ }
+ return rtn;
+}
diff --git a/src/hexen/p_doors.c b/src/hexen/p_doors.c
new file mode 100644
index 00000000..92ccec8a
--- /dev/null
+++ b/src/hexen/p_doors.c
@@ -0,0 +1,326 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#include "h2def.h"
+#include "p_local.h"
+
+//==================================================================
+//==================================================================
+//
+// 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 DREV_NORMAL:
+ door->direction = -1; // time to go back down
+ SN_StartSequence((mobj_t *) & door->sector->soundorg,
+ SEQ_DOOR_STONE +
+ door->sector->seqType);
+ break;
+ case DREV_CLOSE30THENOPEN:
+ door->direction = 1;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 2: // INITIAL WAIT
+ if (!--door->topcountdown)
+ {
+ switch (door->type)
+ {
+ case DREV_RAISEIN5MINS:
+ door->direction = 1;
+ door->type = DREV_NORMAL;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case -1: // DOWN
+ res = T_MovePlane(door->sector, door->speed,
+ door->sector->floorheight, false, 1,
+ door->direction);
+ if (res == RES_PASTDEST)
+ {
+ SN_StopSequence((mobj_t *) & door->sector->soundorg);
+ switch (door->type)
+ {
+ case DREV_NORMAL:
+ case DREV_CLOSE:
+ door->sector->specialdata = NULL;
+ P_TagFinished(door->sector->tag);
+ P_RemoveThinker(&door->thinker); // unlink and free
+ break;
+ case DREV_CLOSE30THENOPEN:
+ door->direction = 0;
+ door->topcountdown = 35 * 30;
+ break;
+ default:
+ break;
+ }
+ }
+ else if (res == RES_CRUSHED)
+ {
+ switch (door->type)
+ {
+ case DREV_CLOSE: // DON'T GO BACK UP!
+ break;
+ default:
+ door->direction = 1;
+ break;
+ }
+ }
+ break;
+ case 1: // UP
+ res = T_MovePlane(door->sector, door->speed,
+ door->topheight, false, 1, door->direction);
+ if (res == RES_PASTDEST)
+ {
+ SN_StopSequence((mobj_t *) & door->sector->soundorg);
+ switch (door->type)
+ {
+ case DREV_NORMAL:
+ door->direction = 0; // wait at top
+ door->topcountdown = door->topwait;
+ break;
+ case DREV_CLOSE30THENOPEN:
+ case DREV_OPEN:
+ door->sector->specialdata = NULL;
+ P_TagFinished(door->sector->tag);
+ P_RemoveThinker(&door->thinker); // unlink and free
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// EV_DoDoor
+//
+// Move a door up/down
+//
+//----------------------------------------------------------------------------
+
+int EV_DoDoor(line_t * line, byte * args, vldoor_e type)
+{
+ int secnum;
+ int retcode;
+ sector_t *sec;
+ vldoor_t *door;
+ fixed_t speed;
+
+ speed = args[1] * FRACUNIT / 8;
+ secnum = -1;
+ retcode = 0;
+ while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+ {
+ sec = &sectors[secnum];
+ if (sec->specialdata)
+ {
+ continue;
+ }
+ // Add new door thinker
+ retcode = 1;
+ door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0);
+ P_AddThinker(&door->thinker);
+ sec->specialdata = door;
+ door->thinker.function = T_VerticalDoor;
+ door->sector = sec;
+ switch (type)
+ {
+ case DREV_CLOSE:
+ door->topheight = P_FindLowestCeilingSurrounding(sec);
+ door->topheight -= 4 * FRACUNIT;
+ door->direction = -1;
+ break;
+ case DREV_CLOSE30THENOPEN:
+ door->topheight = sec->ceilingheight;
+ door->direction = -1;
+ break;
+ case DREV_NORMAL:
+ case DREV_OPEN:
+ door->direction = 1;
+ door->topheight = P_FindLowestCeilingSurrounding(sec);
+ door->topheight -= 4 * FRACUNIT;
+ break;
+ default:
+ break;
+ }
+ door->type = type;
+ door->speed = speed;
+ door->topwait = args[2]; // line->arg3
+ SN_StartSequence((mobj_t *) & door->sector->soundorg,
+ SEQ_DOOR_STONE + door->sector->seqType);
+ }
+ return (retcode);
+}
+
+//==================================================================
+//
+// EV_VerticalDoor : open a door manually, no tag value
+//
+//==================================================================
+boolean EV_VerticalDoor(line_t * line, mobj_t * thing)
+{
+ sector_t *sec;
+ vldoor_t *door;
+ int side;
+
+ side = 0; // only front sides can be used
+
+ // if the sector has an active thinker, use it
+ sec = sides[line->sidenum[side ^ 1]].sector;
+ if (sec->specialdata)
+ {
+ return false;
+/*
+ door = sec->specialdata;
+ switch(line->special)
+ { // only for raise doors
+ case 12:
+ if(door->direction == -1)
+ {
+ door->direction = 1; // go back up
+ }
+ else
+ {
+ if(!thing->player)
+ { // Monsters don't close doors
+ return;
+ }
+ door->direction = -1; // start going down immediately
+ }
+ return;
+ }
+*/
+ }
+ //
+ // new door thinker
+ //
+ door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0);
+ P_AddThinker(&door->thinker);
+ sec->specialdata = door;
+ door->thinker.function = T_VerticalDoor;
+ door->sector = sec;
+ door->direction = 1;
+ switch (line->special)
+ {
+ case 11:
+ door->type = DREV_OPEN;
+ line->special = 0;
+ break;
+ case 12:
+ case 13:
+ door->type = DREV_NORMAL;
+ break;
+ default:
+ door->type = DREV_NORMAL;
+ break;
+ }
+ door->speed = line->arg2 * (FRACUNIT / 8);
+ door->topwait = line->arg3;
+
+ //
+ // find the top and bottom of the movement range
+ //
+ door->topheight = P_FindLowestCeilingSurrounding(sec);
+ door->topheight -= 4 * FRACUNIT;
+ SN_StartSequence((mobj_t *) & door->sector->soundorg,
+ SEQ_DOOR_STONE + door->sector->seqType);
+ return true;
+}
+
+//==================================================================
+//
+// 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 = T_VerticalDoor;
+ door->sector = sec;
+ door->direction = 0;
+ door->type = DREV_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 = T_VerticalDoor;
+ door->sector = sec;
+ door->direction = 2;
+ door->type = DREV_RAISEIN5MINS;
+ door->speed = VDOORSPEED;
+ door->topheight = P_FindLowestCeilingSurrounding(sec);
+ door->topheight -= 4*FRACUNIT;
+ door->topwait = VDOORWAIT;
+ door->topcountdown = 5*60*35;
+}
+*/
diff --git a/src/hexen/p_enemy.c b/src/hexen/p_enemy.c
new file mode 100644
index 00000000..da987f16
--- /dev/null
+++ b/src/hexen/p_enemy.c
@@ -0,0 +1,5390 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#include "h2def.h"
+#include "m_random.h"
+#include "i_system.h"
+#include "i_swap.h"
+#include "p_local.h"
+#include "s_sound.h"
+
+// Macros
+// Types
+// Private Data
+// External Data
+extern fixed_t FloatBobOffsets[64];
+
+
+//----------------------------------------------------------------------------
+//
+// PROC P_RecursiveSound
+//
+//----------------------------------------------------------------------------
+
+mobj_t *soundtarget;
+
+void P_RecursiveSound(sector_t * sec, int soundblocks)
+{
+ int i;
+ line_t *check;
+ sector_t *other;
+
+ // Wake up all monsters in this sector
+ if (sec->validcount == validcount
+ && sec->soundtraversed <= soundblocks + 1)
+ { // Already flooded
+ return;
+ }
+ sec->validcount = validcount;
+ sec->soundtraversed = soundblocks + 1;
+ sec->soundtarget = soundtarget;
+ for (i = 0; i < sec->linecount; i++)
+ {
+ check = sec->lines[i];
+ if (!(check->flags & ML_TWOSIDED))
+ {
+ continue;
+ }
+ P_LineOpening(check);
+ if (openrange <= 0)
+ { // Closed door
+ continue;
+ }
+ if (sides[check->sidenum[0]].sector == sec)
+ {
+ other = sides[check->sidenum[1]].sector;
+ }
+ else
+ {
+ other = sides[check->sidenum[0]].sector;
+ }
+ if (check->flags & ML_SOUNDBLOCK)
+ {
+ if (!soundblocks)
+ {
+ P_RecursiveSound(other, 1);
+ }
+ }
+ else
+ {
+ P_RecursiveSound(other, soundblocks);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_NoiseAlert
+//
+// If a monster yells at a player, it will alert other monsters to the
+// player.
+//
+//----------------------------------------------------------------------------
+
+void P_NoiseAlert(mobj_t * target, mobj_t * emmiter)
+{
+ soundtarget = target;
+ validcount++;
+ P_RecursiveSound(emmiter->subsector->sector, 0);
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_CheckMeleeRange
+//
+//----------------------------------------------------------------------------
+
+boolean P_CheckMeleeRange(mobj_t * actor)
+{
+ mobj_t *mo;
+ fixed_t dist;
+
+ if (!actor->target)
+ {
+ return (false);
+ }
+ mo = actor->target;
+ dist = P_AproxDistance(mo->x - actor->x, mo->y - actor->y);
+ if (dist >= MELEERANGE)
+ {
+ return (false);
+ }
+ if (!P_CheckSight(actor, mo))
+ {
+ return (false);
+ }
+ if (mo->z > actor->z + actor->height)
+ { // Target is higher than the attacker
+ return (false);
+ }
+ else if (actor->z > mo->z + mo->height)
+ { // Attacker is higher
+ return (false);
+ }
+ return (true);
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_CheckMeleeRange2
+//
+//----------------------------------------------------------------------------
+
+boolean P_CheckMeleeRange2(mobj_t * actor)
+{
+ mobj_t *mo;
+ fixed_t dist;
+
+ if (!actor->target)
+ {
+ return (false);
+ }
+ mo = actor->target;
+ dist = P_AproxDistance(mo->x - actor->x, mo->y - actor->y);
+ if (dist >= MELEERANGE * 2 || dist < MELEERANGE)
+ {
+ return (false);
+ }
+ if (!P_CheckSight(actor, mo))
+ {
+ return (false);
+ }
+ if (mo->z > actor->z + actor->height)
+ { // Target is higher than the attacker
+ return (false);
+ }
+ else if (actor->z > mo->z + mo->height)
+ { // Attacker is higher
+ return (false);
+ }
+ return (true);
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_CheckMissileRange
+//
+//----------------------------------------------------------------------------
+
+boolean P_CheckMissileRange(mobj_t * actor)
+{
+ fixed_t dist;
+
+ if (!P_CheckSight(actor, actor->target))
+ {
+ return (false);
+ }
+ if (actor->flags & MF_JUSTHIT)
+ { // The target just hit the enemy, so fight back!
+ actor->flags &= ~MF_JUSTHIT;
+ return (true);
+ }
+ if (actor->reactiontime)
+ { // Don't attack yet
+ return (false);
+ }
+ dist = (P_AproxDistance(actor->x - actor->target->x,
+ actor->y - actor->target->y) >> FRACBITS) - 64;
+ if (!actor->info->meleestate)
+ { // No melee attack, so fire more frequently
+ dist -= 128;
+ }
+ if (dist > 200)
+ {
+ dist = 200;
+ }
+ if (P_Random() < dist)
+ {
+ return (false);
+ }
+ return (true);
+}
+
+/*
+================
+=
+= P_Move
+=
+= Move in the current direction
+= returns false if the move is blocked
+================
+*/
+
+fixed_t xspeed[8] =
+ { FRACUNIT, 47000, 0, -47000, -FRACUNIT, -47000, 0, 47000 };
+fixed_t yspeed[8] =
+ { 0, 47000, FRACUNIT, 47000, 0, -47000, -FRACUNIT, -47000 };
+
+#define MAXSPECIALCROSS 8
+extern line_t *spechit[MAXSPECIALCROSS];
+extern int numspechit;
+
+boolean P_Move(mobj_t * actor)
+{
+ fixed_t tryx, tryy;
+ line_t *ld;
+ boolean good;
+
+ if (actor->flags2 & MF2_BLASTED)
+ return (true);
+ if (actor->movedir == DI_NODIR)
+ {
+ return (false);
+ }
+ tryx = actor->x + actor->info->speed * xspeed[actor->movedir];
+ tryy = actor->y + actor->info->speed * yspeed[actor->movedir];
+ if (!P_TryMove(actor, tryx, tryy))
+ { // open any specials
+ if (actor->flags & MF_FLOAT && floatok)
+ { // must adjust height
+ if (actor->z < tmfloorz)
+ {
+ actor->z += FLOATSPEED;
+ }
+ else
+ {
+ actor->z -= FLOATSPEED;
+ }
+ actor->flags |= MF_INFLOAT;
+ return (true);
+ }
+ if (!numspechit)
+ {
+ return false;
+ }
+ actor->movedir = DI_NODIR;
+ good = false;
+ while (numspechit--)
+ {
+ ld = spechit[numspechit];
+ // if the special isn't a door that can be opened, return false
+ if (P_ActivateLine(ld, actor, 0, SPAC_USE))
+ {
+ good = true;
+ }
+/* Old version before use/cross/impact specials were combined
+ if(P_UseSpecialLine(actor, ld))
+ {
+ good = true;
+ }
+*/
+ }
+ return (good);
+ }
+ else
+ {
+ actor->flags &= ~MF_INFLOAT;
+ }
+ if (!(actor->flags & MF_FLOAT))
+ {
+ if (actor->z > actor->floorz)
+ {
+ P_HitFloor(actor);
+ }
+ actor->z = actor->floorz;
+ }
+ return (true);
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_TryWalk
+//
+// Attempts to move actor in its current (ob->moveangle) direction.
+// If blocked by either a wall or an actor returns FALSE.
+// If move is either clear of block only by a door, returns TRUE and sets.
+// If a door is in the way, an OpenDoor call is made to start it opening.
+//
+//----------------------------------------------------------------------------
+
+boolean P_TryWalk(mobj_t * actor)
+{
+ if (!P_Move(actor))
+ {
+ return (false);
+ }
+ actor->movecount = P_Random() & 15;
+ return (true);
+}
+
+/*
+================
+=
+= P_NewChaseDir
+=
+================
+*/
+
+dirtype_t opposite[] =
+ { DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST, DI_EAST, DI_NORTHEAST,
+ DI_NORTH, DI_NORTHWEST, DI_NODIR
+};
+
+dirtype_t diags[] =
+ { DI_NORTHWEST, DI_NORTHEAST, DI_SOUTHWEST, DI_SOUTHEAST };
+
+void P_NewChaseDir(mobj_t * actor)
+{
+ fixed_t deltax, deltay;
+ dirtype_t d[3];
+ dirtype_t tdir, olddir, turnaround;
+
+ if (!actor->target)
+ I_Error("P_NewChaseDir: called with no target");
+
+ olddir = actor->movedir;
+ turnaround = opposite[olddir];
+
+ deltax = actor->target->x - actor->x;
+ deltay = actor->target->y - actor->y;
+ if (deltax > 10 * FRACUNIT)
+ d[1] = DI_EAST;
+ else if (deltax < -10 * FRACUNIT)
+ d[1] = DI_WEST;
+ else
+ d[1] = DI_NODIR;
+ if (deltay < -10 * FRACUNIT)
+ d[2] = DI_SOUTH;
+ else if (deltay > 10 * FRACUNIT)
+ d[2] = DI_NORTH;
+ else
+ d[2] = DI_NODIR;
+
+// try direct route
+ if (d[1] != DI_NODIR && d[2] != DI_NODIR)
+ {
+ actor->movedir = diags[((deltay < 0) << 1) + (deltax > 0)];
+ if (actor->movedir != turnaround && P_TryWalk(actor))
+ return;
+ }
+
+// try other directions
+ if (P_Random() > 200 || abs(deltay) > abs(deltax))
+ {
+ tdir = d[1];
+ d[1] = d[2];
+ d[2] = tdir;
+ }
+
+ if (d[1] == turnaround)
+ d[1] = DI_NODIR;
+ if (d[2] == turnaround)
+ d[2] = DI_NODIR;
+
+ if (d[1] != DI_NODIR)
+ {
+ actor->movedir = d[1];
+ if (P_TryWalk(actor))
+ return; /*either moved forward or attacked */
+ }
+
+ if (d[2] != DI_NODIR)
+ {
+ actor->movedir = d[2];
+ if (P_TryWalk(actor))
+ return;
+ }
+
+/* there is no direct path to the player, so pick another direction */
+
+ if (olddir != DI_NODIR)
+ {
+ actor->movedir = olddir;
+ if (P_TryWalk(actor))
+ return;
+ }
+
+ if (P_Random() & 1) /*randomly determine direction of search */
+ {
+ for (tdir = DI_EAST; tdir <= DI_SOUTHEAST; tdir++)
+ {
+ if (tdir != turnaround)
+ {
+ actor->movedir = tdir;
+ if (P_TryWalk(actor))
+ return;
+ }
+ }
+ }
+ else
+ {
+ for (tdir = DI_SOUTHEAST; tdir != DI_EAST-1; tdir--)
+ {
+ if (tdir != turnaround)
+ {
+ actor->movedir = tdir;
+ if (P_TryWalk(actor))
+ return;
+ }
+ }
+ }
+
+ if (turnaround != DI_NODIR)
+ {
+ actor->movedir = turnaround;
+ if (P_TryWalk(actor))
+ return;
+ }
+
+ actor->movedir = DI_NODIR; // can't move
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_LookForMonsters
+//
+//---------------------------------------------------------------------------
+
+#define MONS_LOOK_RANGE (16*64*FRACUNIT)
+#define MONS_LOOK_LIMIT 64
+
+boolean P_LookForMonsters(mobj_t * actor)
+{
+ int count;
+ mobj_t *mo;
+ thinker_t *think;
+
+ if (!P_CheckSight(players[0].mo, actor))
+ { // Player can't see monster
+ return (false);
+ }
+ count = 0;
+ for (think = thinkercap.next; think != &thinkercap; think = think->next)
+ {
+ if (think->function != P_MobjThinker)
+ { // Not a mobj thinker
+ continue;
+ }
+ mo = (mobj_t *) think;
+ if (!(mo->flags & MF_COUNTKILL) || (mo == actor) || (mo->health <= 0))
+ { // Not a valid monster
+ continue;
+ }
+ if (P_AproxDistance(actor->x - mo->x, actor->y - mo->y)
+ > MONS_LOOK_RANGE)
+ { // Out of range
+ continue;
+ }
+ if (P_Random() < 16)
+ { // Skip
+ continue;
+ }
+ if (count++ > MONS_LOOK_LIMIT)
+ { // Stop searching
+ return (false);
+ }
+ if (!P_CheckSight(actor, mo))
+ { // Out of sight
+ continue;
+ }
+ if (actor->type == MT_MINOTAUR)
+ {
+ if ((mo->type == MT_MINOTAUR) &&
+ (mo->target != actor->special1.p->mo))
+ {
+ continue;
+ }
+ }
+ // Found a target monster
+ actor->target = mo;
+ return (true);
+ }
+ return (false);
+}
+
+/*
+================
+=
+= P_LookForPlayers
+=
+= If allaround is false, only look 180 degrees in front
+= returns true if a player is targeted
+================
+*/
+
+boolean P_LookForPlayers(mobj_t * actor, boolean allaround)
+{
+ int c;
+ int stop;
+ player_t *player;
+ angle_t an;
+ fixed_t dist;
+
+ if (!netgame && players[0].health <= 0)
+ { // Single player game and player is dead, look for monsters
+ return (P_LookForMonsters(actor));
+ }
+ c = 0;
+
+ // NOTE: This behavior has been changed from the Vanilla behavior, where
+ // an infinite loop can occur if players 0-3 all quit the game. Although
+ // technically this is not what Vanilla does, fixing this is highly
+ // desirable, and having the game simply lock up is not acceptable.
+ // stop = (actor->lastlook - 1) & 3;
+ // for (;; actor->lastlook = (actor->lastlook + 1) & 3)
+
+ stop = (actor->lastlook + MAXPLAYERS - 1) % MAXPLAYERS;
+ for (;; actor->lastlook = (actor->lastlook + 1) % MAXPLAYERS)
+ {
+ if (!playeringame[actor->lastlook])
+ continue;
+
+ if (c++ == 2 || actor->lastlook == stop)
+ return false; // done looking
+
+ player = &players[actor->lastlook];
+ if (player->health <= 0)
+ continue; // dead
+ if (!P_CheckSight(actor, player->mo))
+ continue; // out of sight
+
+ if (!allaround)
+ {
+ an = R_PointToAngle2(actor->x, actor->y,
+ player->mo->x, player->mo->y) - actor->angle;
+ if (an > ANG90 && an < ANG270)
+ {
+ dist = P_AproxDistance(player->mo->x - actor->x,
+ player->mo->y - actor->y);
+ // if real close, react anyway
+ if (dist > MELEERANGE)
+ continue; // behind back
+ }
+ }
+ if (player->mo->flags & MF_SHADOW)
+ { // Player is invisible
+ if ((P_AproxDistance(player->mo->x - actor->x,
+ player->mo->y - actor->y) > 2 * MELEERANGE)
+ && P_AproxDistance(player->mo->momx, player->mo->momy)
+ < 5 * FRACUNIT)
+ { // Player is sneaking - can't detect
+ return (false);
+ }
+ if (P_Random() < 225)
+ { // Player isn't sneaking, but still didn't detect
+ return (false);
+ }
+ }
+ if (actor->type == MT_MINOTAUR)
+ {
+ if (actor->special1.p == player)
+ {
+ continue; // Don't target master
+ }
+ }
+
+ actor->target = player->mo;
+ return (true);
+ }
+ return (false);
+}
+
+/*
+===============================================================================
+
+ ACTION ROUTINES
+
+===============================================================================
+*/
+
+/*
+==============
+=
+= A_Look
+=
+= Stay in state until a player is sighted
+=
+==============
+*/
+
+void A_Look(mobj_t * actor)
+{
+ mobj_t *targ;
+
+ actor->threshold = 0; // any shot will wake up
+ targ = actor->subsector->sector->soundtarget;
+ if (targ && (targ->flags & MF_SHOOTABLE))
+ {
+ actor->target = targ;
+ if (actor->flags & MF_AMBUSH)
+ {
+ if (P_CheckSight(actor, actor->target))
+ goto seeyou;
+ }
+ else
+ goto seeyou;
+ }
+
+
+ if (!P_LookForPlayers(actor, false))
+ return;
+
+// go into chase state
+ seeyou:
+ if (actor->info->seesound)
+ {
+ int sound;
+
+ sound = actor->info->seesound;
+ if (actor->flags2 & MF2_BOSS)
+ { // Full volume
+ S_StartSound(NULL, sound);
+ }
+ else
+ {
+ S_StartSound(actor, sound);
+ }
+ }
+ P_SetMobjState(actor, actor->info->seestate);
+}
+
+
+/*
+==============
+=
+= A_Chase
+=
+= Actor has a melee attack, so it tries to close as fast as possible
+=
+==============
+*/
+
+void A_Chase(mobj_t * actor)
+{
+ int delta;
+
+ if (actor->reactiontime)
+ {
+ actor->reactiontime--;
+ }
+
+ // Modify target threshold
+ if (actor->threshold)
+ {
+ actor->threshold--;
+ }
+
+ if (gameskill == sk_nightmare)
+ { // Monsters move faster in nightmare mode
+ actor->tics -= actor->tics / 2;
+ if (actor->tics < 3)
+ {
+ actor->tics = 3;
+ }
+ }
+
+//
+// turn towards movement direction if not there yet
+//
+ if (actor->movedir < 8)
+ {
+ actor->angle &= (7 << 29);
+ delta = actor->angle - (actor->movedir << 29);
+ if (delta > 0)
+ {
+ actor->angle -= ANG90 / 2;
+ }
+ else if (delta < 0)
+ {
+ actor->angle += ANG90 / 2;
+ }
+ }
+
+ if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+ { // look for a new target
+ if (P_LookForPlayers(actor, true))
+ { // got a new target
+ return;
+ }
+ P_SetMobjState(actor, actor->info->spawnstate);
+ return;
+ }
+
+//
+// don't attack twice in a row
+//
+ if (actor->flags & MF_JUSTATTACKED)
+ {
+ actor->flags &= ~MF_JUSTATTACKED;
+ if (gameskill != sk_nightmare)
+ P_NewChaseDir(actor);
+ return;
+ }
+
+//
+// check for melee attack
+//
+ if (actor->info->meleestate && P_CheckMeleeRange(actor))
+ {
+ if (actor->info->attacksound)
+ {
+ S_StartSound(actor, actor->info->attacksound);
+ }
+ P_SetMobjState(actor, actor->info->meleestate);
+ return;
+ }
+
+//
+// check for missile attack
+//
+ if (actor->info->missilestate)
+ {
+ if (gameskill < sk_nightmare && actor->movecount)
+ goto nomissile;
+ if (!P_CheckMissileRange(actor))
+ goto nomissile;
+ P_SetMobjState(actor, actor->info->missilestate);
+ actor->flags |= MF_JUSTATTACKED;
+ return;
+ }
+ nomissile:
+
+//
+// possibly choose another target
+//
+ if (netgame && !actor->threshold && !P_CheckSight(actor, actor->target))
+ {
+ if (P_LookForPlayers(actor, true))
+ return; // got a new target
+ }
+
+//
+// chase towards player
+//
+ if (--actor->movecount < 0 || !P_Move(actor))
+ {
+ P_NewChaseDir(actor);
+ }
+
+//
+// make active sound
+//
+ if (actor->info->activesound && P_Random() < 3)
+ {
+ if (actor->type == MT_BISHOP && P_Random() < 128)
+ {
+ S_StartSound(actor, actor->info->seesound);
+ }
+ else if (actor->type == MT_PIG)
+ {
+ S_StartSound(actor, SFX_PIG_ACTIVE1 + (P_Random() & 1));
+ }
+ else if (actor->flags2 & MF2_BOSS)
+ {
+ S_StartSound(NULL, actor->info->activesound);
+ }
+ else
+ {
+ S_StartSound(actor, actor->info->activesound);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FaceTarget
+//
+//----------------------------------------------------------------------------
+
+void A_FaceTarget(mobj_t * actor)
+{
+ if (!actor->target)
+ {
+ return;
+ }
+ actor->flags &= ~MF_AMBUSH;
+ actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x,
+ actor->target->y);
+ if (actor->target->flags & MF_SHADOW)
+ { // Target is a ghost
+ actor->angle += (P_Random() - P_Random()) << 21;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_Pain
+//
+//----------------------------------------------------------------------------
+
+void A_Pain(mobj_t * actor)
+{
+ if (actor->info->painsound)
+ {
+ S_StartSound(actor, actor->info->painsound);
+ }
+}
+
+//============================================================================
+//
+// A_SetInvulnerable
+//
+//============================================================================
+
+void A_SetInvulnerable(mobj_t * actor)
+{
+ actor->flags2 |= MF2_INVULNERABLE;
+}
+
+//============================================================================
+//
+// A_UnSetInvulnerable
+//
+//============================================================================
+
+void A_UnSetInvulnerable(mobj_t * actor)
+{
+ actor->flags2 &= ~MF2_INVULNERABLE;
+}
+
+//============================================================================
+//
+// A_SetReflective
+//
+//============================================================================
+
+void A_SetReflective(mobj_t * actor)
+{
+ actor->flags2 |= MF2_REFLECTIVE;
+
+ if ((actor->type == MT_CENTAUR) || (actor->type == MT_CENTAURLEADER))
+ {
+ A_SetInvulnerable(actor);
+ }
+}
+
+//============================================================================
+//
+// A_UnSetReflective
+//
+//============================================================================
+
+void A_UnSetReflective(mobj_t * actor)
+{
+ actor->flags2 &= ~MF2_REFLECTIVE;
+
+ if ((actor->type == MT_CENTAUR) || (actor->type == MT_CENTAURLEADER))
+ {
+ A_UnSetInvulnerable(actor);
+ }
+}
+
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_UpdateMorphedMonster
+//
+// Returns true if the pig morphs.
+//
+//----------------------------------------------------------------------------
+
+boolean P_UpdateMorphedMonster(mobj_t * actor, int tics)
+{
+ mobj_t *fog;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ mobjtype_t moType;
+ mobj_t *mo;
+ mobj_t oldMonster;
+
+ actor->special1.i -= tics;
+ if (actor->special1.i > 0)
+ {
+ return (false);
+ }
+ moType = actor->special2.i;
+ switch (moType)
+ {
+ case MT_WRAITHB: // These must remain morphed
+ case MT_SERPENT:
+ case MT_SERPENTLEADER:
+ case MT_MINOTAUR:
+ return (false);
+ default:
+ break;
+ }
+ x = actor->x;
+ y = actor->y;
+ z = actor->z;
+ oldMonster = *actor; // Save pig vars
+
+ P_RemoveMobjFromTIDList(actor);
+ P_SetMobjState(actor, S_FREETARGMOBJ);
+ mo = P_SpawnMobj(x, y, z, moType);
+
+ if (P_TestMobjLocation(mo) == false)
+ { // Didn't fit
+ P_RemoveMobj(mo);
+ mo = P_SpawnMobj(x, y, z, oldMonster.type);
+ mo->angle = oldMonster.angle;
+ mo->flags = oldMonster.flags;
+ mo->health = oldMonster.health;
+ mo->target = oldMonster.target;
+ mo->special = oldMonster.special;
+ mo->special1.i = 5 * 35; // Next try in 5 seconds
+ mo->special2.i = moType;
+ mo->tid = oldMonster.tid;
+ memcpy(mo->args, oldMonster.args, 5);
+ P_InsertMobjIntoTIDList(mo, oldMonster.tid);
+ return (false);
+ }
+ mo->angle = oldMonster.angle;
+ mo->target = oldMonster.target;
+ mo->tid = oldMonster.tid;
+ mo->special = oldMonster.special;
+ memcpy(mo->args, oldMonster.args, 5);
+ P_InsertMobjIntoTIDList(mo, oldMonster.tid);
+ fog = P_SpawnMobj(x, y, z + TELEFOGHEIGHT, MT_TFOG);
+ S_StartSound(fog, SFX_TELEPORT);
+ return (true);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_PigLook
+//
+//----------------------------------------------------------------------------
+
+void A_PigLook(mobj_t * actor)
+{
+ if (P_UpdateMorphedMonster(actor, 10))
+ {
+ return;
+ }
+ A_Look(actor);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_PigChase
+//
+//----------------------------------------------------------------------------
+
+void A_PigChase(mobj_t * actor)
+{
+ if (P_UpdateMorphedMonster(actor, 3))
+ {
+ return;
+ }
+ A_Chase(actor);
+}
+
+//============================================================================
+//
+// A_PigAttack
+//
+//============================================================================
+
+void A_PigAttack(mobj_t * actor)
+{
+ if (P_UpdateMorphedMonster(actor, 18))
+ {
+ return;
+ }
+ if (!actor->target)
+ {
+ return;
+ }
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, 2 + (P_Random() & 1));
+ S_StartSound(actor, SFX_PIG_ATTACK);
+ }
+}
+
+//============================================================================
+//
+// A_PigPain
+//
+//============================================================================
+
+void A_PigPain(mobj_t * actor)
+{
+ A_Pain(actor);
+ if (actor->z <= actor->floorz)
+ {
+ actor->momz = 3.5 * FRACUNIT;
+ }
+}
+
+
+
+void FaceMovementDirection(mobj_t * actor)
+{
+ switch (actor->movedir)
+ {
+ case DI_EAST:
+ actor->angle = 0 << 24;
+ break;
+ case DI_NORTHEAST:
+ actor->angle = 32 << 24;
+ break;
+ case DI_NORTH:
+ actor->angle = 64 << 24;
+ break;
+ case DI_NORTHWEST:
+ actor->angle = 96 << 24;
+ break;
+ case DI_WEST:
+ actor->angle = 128 << 24;
+ break;
+ case DI_SOUTHWEST:
+ actor->angle = 160 << 24;
+ break;
+ case DI_SOUTH:
+ actor->angle = 192 << 24;
+ break;
+ case DI_SOUTHEAST:
+ actor->angle = 224 << 24;
+ break;
+ }
+}
+
+
+//----------------------------------------------------------------------------
+//
+// Minotaur variables
+//
+// special1 pointer to player that spawned it (mobj_t)
+// special2 internal to minotaur AI
+// args[0] args[0]-args[3] together make up minotaur start time
+// args[1] |
+// args[2] |
+// args[3] V
+// args[4] charge duration countdown
+//----------------------------------------------------------------------------
+
+void A_MinotaurFade0(mobj_t * actor)
+{
+ actor->flags &= ~MF_ALTSHADOW;
+ actor->flags |= MF_SHADOW;
+}
+
+void A_MinotaurFade1(mobj_t * actor)
+{
+ // Second level of transparency
+ actor->flags &= ~MF_SHADOW;
+ actor->flags |= MF_ALTSHADOW;
+}
+
+void A_MinotaurFade2(mobj_t * actor)
+{
+ // Make fully visible
+ actor->flags &= ~MF_SHADOW;
+ actor->flags &= ~MF_ALTSHADOW;
+}
+
+
+//----------------------------------------------------------------------------
+//
+// A_MinotaurRoam -
+//
+//
+//----------------------------------------------------------------------------
+
+void A_MinotaurLook(mobj_t * actor);
+
+void A_MinotaurRoam(mobj_t * actor)
+{
+ unsigned int *starttime = (unsigned int *) actor->args;
+
+ actor->flags &= ~MF_SHADOW; // In case pain caused him to
+ actor->flags &= ~MF_ALTSHADOW; // skip his fade in.
+
+ if ((leveltime - *starttime) >= MAULATORTICS)
+ {
+ P_DamageMobj(actor, NULL, NULL, 10000);
+ return;
+ }
+
+ if (P_Random() < 30)
+ A_MinotaurLook(actor); // adjust to closest target
+
+ if (P_Random() < 6)
+ {
+ //Choose new direction
+ actor->movedir = P_Random() % 8;
+ FaceMovementDirection(actor);
+ }
+ if (!P_Move(actor))
+ {
+ // Turn
+ if (P_Random() & 1)
+ actor->movedir = (actor->movedir + 1) % 8;
+ else
+ actor->movedir = (actor->movedir + 7) % 8;
+ FaceMovementDirection(actor);
+ }
+}
+
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MinotaurLook
+//
+// Look for enemy of player
+//----------------------------------------------------------------------------
+#define MINOTAUR_LOOK_DIST (16*54*FRACUNIT)
+
+void A_MinotaurLook(mobj_t * actor)
+{
+ mobj_t *mo = NULL;
+ player_t *player;
+ thinker_t *think;
+ fixed_t dist;
+ int i;
+ mobj_t *master = actor->special1.m;
+
+ actor->target = NULL;
+ if (deathmatch) // Quick search for players
+ {
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (!playeringame[i])
+ continue;
+ player = &players[i];
+ mo = player->mo;
+ if (mo == master)
+ continue;
+ if (mo->health <= 0)
+ continue;
+ dist = P_AproxDistance(actor->x - mo->x, actor->y - mo->y);
+ if (dist > MINOTAUR_LOOK_DIST)
+ continue;
+ actor->target = mo;
+ break;
+ }
+ }
+
+ if (!actor->target) // Near player monster search
+ {
+ if (master && (master->health > 0) && (master->player))
+ mo = P_RoughMonsterSearch(master, 20);
+ else
+ mo = P_RoughMonsterSearch(actor, 20);
+ actor->target = mo;
+ }
+
+ if (!actor->target) // Normal monster search
+ {
+ for (think = thinkercap.next; think != &thinkercap;
+ think = think->next)
+ {
+ if (think->function != P_MobjThinker)
+ continue;
+ mo = (mobj_t *) think;
+ if (!(mo->flags & MF_COUNTKILL))
+ continue;
+ if (mo->health <= 0)
+ continue;
+ if (!(mo->flags & MF_SHOOTABLE))
+ continue;
+ dist = P_AproxDistance(actor->x - mo->x, actor->y - mo->y);
+ if (dist > MINOTAUR_LOOK_DIST)
+ continue;
+ if ((mo == master) || (mo == actor))
+ continue;
+ if ((mo->type == MT_MINOTAUR) &&
+ (mo->special1.m == actor->special1.m))
+ continue;
+ actor->target = mo;
+ break; // Found mobj to attack
+ }
+ }
+
+ if (actor->target)
+ {
+ P_SetMobjStateNF(actor, S_MNTR_WALK1);
+ }
+ else
+ {
+ P_SetMobjStateNF(actor, S_MNTR_ROAM1);
+ }
+}
+
+
+
+
+void A_MinotaurChase(mobj_t * actor)
+{
+ unsigned int *starttime = (unsigned int *) actor->args;
+
+ actor->flags &= ~MF_SHADOW; // In case pain caused him to
+ actor->flags &= ~MF_ALTSHADOW; // skip his fade in.
+
+ if ((leveltime - *starttime) >= MAULATORTICS)
+ {
+ P_DamageMobj(actor, NULL, NULL, 10000);
+ return;
+ }
+
+ if (P_Random() < 30)
+ A_MinotaurLook(actor); // adjust to closest target
+
+ if (!actor->target || (actor->target->health <= 0) ||
+ !(actor->target->flags & MF_SHOOTABLE))
+ { // look for a new target
+ P_SetMobjState(actor, S_MNTR_LOOK1);
+ return;
+ }
+
+ FaceMovementDirection(actor);
+ actor->reactiontime = 0;
+
+ // Melee attack
+ if (actor->info->meleestate && P_CheckMeleeRange(actor))
+ {
+ if (actor->info->attacksound)
+ {
+ S_StartSound(actor, actor->info->attacksound);
+ }
+ P_SetMobjState(actor, actor->info->meleestate);
+ return;
+ }
+
+ // Missile attack
+ if (actor->info->missilestate && P_CheckMissileRange(actor))
+ {
+ P_SetMobjState(actor, actor->info->missilestate);
+ return;
+ }
+
+ // chase towards target
+ if (!P_Move(actor))
+ {
+ P_NewChaseDir(actor);
+ }
+
+ // Active sound
+ if (actor->info->activesound && P_Random() < 6)
+ {
+ S_StartSound(actor, actor->info->activesound);
+ }
+
+}
+
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MinotaurAtk1
+//
+// Melee attack.
+//
+//----------------------------------------------------------------------------
+
+void A_MinotaurAtk1(mobj_t * actor)
+{
+ if (!actor->target)
+ return;
+
+ S_StartSound(actor, SFX_MAULATOR_HAMMER_SWING);
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(4));
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MinotaurDecide
+//
+// Choose a missile attack.
+//
+//----------------------------------------------------------------------------
+
+#define MNTR_CHARGE_SPEED (23*FRACUNIT)
+
+void A_MinotaurDecide(mobj_t * actor)
+{
+ angle_t angle;
+ mobj_t *target = actor->target;
+ int dist;
+
+ if (!target)
+ return;
+ dist = P_AproxDistance(actor->x - target->x, actor->y - target->y);
+
+ if (target->z + target->height > actor->z
+ && target->z + target->height < actor->z + actor->height
+ && dist < 16 * 64 * FRACUNIT
+ && dist > 1 * 64 * FRACUNIT && P_Random() < 230)
+ { // Charge attack
+ // Don't call the state function right away
+ P_SetMobjStateNF(actor, S_MNTR_ATK4_1);
+ actor->flags |= MF_SKULLFLY;
+ A_FaceTarget(actor);
+ angle = actor->angle >> ANGLETOFINESHIFT;
+ actor->momx = FixedMul(MNTR_CHARGE_SPEED, finecosine[angle]);
+ actor->momy = FixedMul(MNTR_CHARGE_SPEED, finesine[angle]);
+ actor->args[4] = 35 / 2; // Charge duration
+ }
+ else if (target->z == target->floorz
+ && dist < 9 * 64 * FRACUNIT && P_Random() < 100)
+ { // Floor fire attack
+ P_SetMobjState(actor, S_MNTR_ATK3_1);
+ actor->special2.i = 0;
+ }
+ else
+ { // Swing attack
+ A_FaceTarget(actor);
+ // Don't need to call P_SetMobjState because the current state
+ // falls through to the swing attack
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MinotaurCharge
+//
+//----------------------------------------------------------------------------
+
+void A_MinotaurCharge(mobj_t * actor)
+{
+ mobj_t *puff;
+
+ if (!actor->target)
+ return;
+
+ if (actor->args[4] > 0)
+ {
+ puff = P_SpawnMobj(actor->x, actor->y, actor->z, MT_PUNCHPUFF);
+ puff->momz = 2 * FRACUNIT;
+ actor->args[4]--;
+ }
+ else
+ {
+ actor->flags &= ~MF_SKULLFLY;
+ P_SetMobjState(actor, actor->info->seestate);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MinotaurAtk2
+//
+// Swing attack.
+//
+//----------------------------------------------------------------------------
+
+void A_MinotaurAtk2(mobj_t * actor)
+{
+ mobj_t *mo;
+ angle_t angle;
+ fixed_t momz;
+
+ if (!actor->target)
+ return;
+
+ S_StartSound(actor, SFX_MAULATOR_HAMMER_SWING);
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(3));
+ return;
+ }
+ mo = P_SpawnMissile(actor, actor->target, MT_MNTRFX1);
+ if (mo)
+ {
+ //S_StartSound(mo, sfx_minat2);
+ momz = mo->momz;
+ angle = mo->angle;
+ P_SpawnMissileAngle(actor, MT_MNTRFX1, angle - (ANG45 / 8), momz);
+ P_SpawnMissileAngle(actor, MT_MNTRFX1, angle + (ANG45 / 8), momz);
+ P_SpawnMissileAngle(actor, MT_MNTRFX1, angle - (ANG45 / 16), momz);
+ P_SpawnMissileAngle(actor, MT_MNTRFX1, angle + (ANG45 / 16), momz);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MinotaurAtk3
+//
+// Floor fire attack.
+//
+//----------------------------------------------------------------------------
+
+void A_MinotaurAtk3(mobj_t * actor)
+{
+ mobj_t *mo;
+ player_t *player;
+
+ if (!actor->target)
+ {
+ return;
+ }
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(3));
+ if ((player = actor->target->player) != NULL)
+ { // Squish the player
+ player->deltaviewheight = -16 * FRACUNIT;
+ }
+ }
+ else
+ {
+ mo = P_SpawnMissile(actor, actor->target, MT_MNTRFX2);
+ if (mo != NULL)
+ {
+ S_StartSound(mo, SFX_MAULATOR_HAMMER_HIT);
+ }
+ }
+ if (P_Random() < 192 && actor->special2.i == 0)
+ {
+ P_SetMobjState(actor, S_MNTR_ATK3_4);
+ actor->special2.i = 1;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MntrFloorFire
+//
+//----------------------------------------------------------------------------
+
+void A_MntrFloorFire(mobj_t * actor)
+{
+ mobj_t *mo;
+
+ actor->z = actor->floorz;
+ mo = P_SpawnMobj(actor->x + ((P_Random() - P_Random()) << 10),
+ actor->y + ((P_Random() - P_Random()) << 10), ONFLOORZ,
+ MT_MNTRFX3);
+ mo->target = actor->target;
+ mo->momx = 1; // Force block checking
+ P_CheckMissileSpawn(mo);
+}
+
+
+//----------------------------------------------------------------------------
+//
+// PROC A_Scream
+//
+//----------------------------------------------------------------------------
+
+void A_Scream(mobj_t * actor)
+{
+ int sound;
+
+ S_StopSound(actor);
+ if (actor->player)
+ {
+ if (actor->player->morphTics)
+ {
+ S_StartSound(actor, actor->info->deathsound);
+ }
+ else
+ {
+ // Handle the different player death screams
+ if (actor->momz <= -39 * FRACUNIT)
+ { // Falling splat
+ sound = SFX_PLAYER_FALLING_SPLAT;
+ }
+ else if (actor->health > -50)
+ { // Normal death sound
+ switch (actor->player->class)
+ {
+ case PCLASS_FIGHTER:
+ sound = SFX_PLAYER_FIGHTER_NORMAL_DEATH;
+ break;
+ case PCLASS_CLERIC:
+ sound = SFX_PLAYER_CLERIC_NORMAL_DEATH;
+ break;
+ case PCLASS_MAGE:
+ sound = SFX_PLAYER_MAGE_NORMAL_DEATH;
+ break;
+ default:
+ sound = SFX_NONE;
+ break;
+ }
+ }
+ else if (actor->health > -100)
+ { // Crazy death sound
+ switch (actor->player->class)
+ {
+ case PCLASS_FIGHTER:
+ sound = SFX_PLAYER_FIGHTER_CRAZY_DEATH;
+ break;
+ case PCLASS_CLERIC:
+ sound = SFX_PLAYER_CLERIC_CRAZY_DEATH;
+ break;
+ case PCLASS_MAGE:
+ sound = SFX_PLAYER_MAGE_CRAZY_DEATH;
+ break;
+ default:
+ sound = SFX_NONE;
+ break;
+ }
+ }
+ else
+ { // Extreme death sound
+ switch (actor->player->class)
+ {
+ case PCLASS_FIGHTER:
+ sound = SFX_PLAYER_FIGHTER_EXTREME1_DEATH;
+ break;
+ case PCLASS_CLERIC:
+ sound = SFX_PLAYER_CLERIC_EXTREME1_DEATH;
+ break;
+ case PCLASS_MAGE:
+ sound = SFX_PLAYER_MAGE_EXTREME1_DEATH;
+ break;
+ default:
+ sound = SFX_NONE;
+ break;
+ }
+ sound += P_Random() % 3; // Three different extreme deaths
+ }
+ S_StartSound(actor, sound);
+ }
+ }
+ else
+ {
+ S_StartSound(actor, actor->info->deathsound);
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_DropItem
+//
+//---------------------------------------------------------------------------
+
+/*
+void P_DropItem(mobj_t *source, mobjtype_t type, int special, int chance)
+{
+ mobj_t *mo;
+
+ if(P_Random() > chance)
+ {
+ return;
+ }
+ mo = P_SpawnMobj(source->x, source->y,
+ source->z+(source->height>>1), type);
+ mo->momx = (P_Random()-P_Random())<<8;
+ mo->momy = (P_Random()-P_Random())<<8;
+ mo->momz = FRACUNIT*5+(P_Random()<<10);
+ mo->flags2 |= MF2_DROPPED;
+ mo->health = special;
+}
+*/
+
+//----------------------------------------------------------------------------
+//
+// PROC A_NoBlocking
+//
+//----------------------------------------------------------------------------
+
+void A_NoBlocking(mobj_t * actor)
+{
+ actor->flags &= ~MF_SOLID;
+
+ // Check for monsters dropping things
+/* switch(actor->type)
+ {
+ // Add the monster dropped items here
+ case MT_MUMMYLEADERGHOST:
+ P_DropItem(actor, MT_AMGWNDWIMPY, 3, 84);
+ break;
+ default:
+ break;
+ }
+*/
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_Explode
+//
+// Handles a bunch of exploding things.
+//
+//----------------------------------------------------------------------------
+
+void A_Explode(mobj_t * actor)
+{
+ int damage;
+ int distance;
+ boolean damageSelf;
+
+ damage = 128;
+ distance = 128;
+ damageSelf = true;
+ switch (actor->type)
+ {
+ case MT_FIREBOMB: // Time Bombs
+ actor->z += 32 * FRACUNIT;
+ actor->flags &= ~MF_SHADOW;
+ break;
+ case MT_MNTRFX2: // Minotaur floor fire
+ damage = 24;
+ break;
+ case MT_BISHOP: // Bishop radius death
+ damage = 25 + (P_Random() & 15);
+ break;
+ case MT_HAMMER_MISSILE: // Fighter Hammer
+ damage = 128;
+ damageSelf = false;
+ break;
+ case MT_FSWORD_MISSILE: // Fighter Runesword
+ damage = 64;
+ damageSelf = false;
+ break;
+ case MT_CIRCLEFLAME: // Cleric Flame secondary flames
+ damage = 20;
+ damageSelf = false;
+ break;
+ case MT_SORCBALL1: // Sorcerer balls
+ case MT_SORCBALL2:
+ case MT_SORCBALL3:
+ distance = 255;
+ damage = 255;
+ actor->args[0] = 1; // don't play bounce
+ break;
+ case MT_SORCFX1: // Sorcerer spell 1
+ damage = 30;
+ break;
+ case MT_SORCFX4: // Sorcerer spell 4
+ damage = 20;
+ break;
+ case MT_TREEDESTRUCTIBLE:
+ damage = 10;
+ break;
+ case MT_DRAGON_FX2:
+ damage = 80;
+ damageSelf = false;
+ break;
+ case MT_MSTAFF_FX:
+ damage = 64;
+ distance = 192;
+ damageSelf = false;
+ break;
+ case MT_MSTAFF_FX2:
+ damage = 80;
+ distance = 192;
+ damageSelf = false;
+ break;
+ case MT_POISONCLOUD:
+ damage = 4;
+ distance = 40;
+ break;
+ case MT_ZXMAS_TREE:
+ case MT_ZSHRUB2:
+ damage = 30;
+ distance = 64;
+ break;
+ default:
+ break;
+ }
+ P_RadiusAttack(actor, actor->target, damage, distance, damageSelf);
+ if (actor->z <= actor->floorz + (distance << FRACBITS)
+ && actor->type != MT_POISONCLOUD)
+ {
+ P_HitFloor(actor);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_Massacre
+//
+// Kills all monsters.
+//
+//----------------------------------------------------------------------------
+
+int P_Massacre(void)
+{
+ int count;
+ mobj_t *mo;
+ thinker_t *think;
+
+ count = 0;
+ for (think = thinkercap.next; think != &thinkercap; think = think->next)
+ {
+ if (think->function != P_MobjThinker)
+ { // Not a mobj thinker
+ continue;
+ }
+ mo = (mobj_t *) think;
+ if ((mo->flags & MF_COUNTKILL) && (mo->health > 0))
+ {
+ mo->flags2 &= ~(MF2_NONSHOOTABLE + MF2_INVULNERABLE);
+ mo->flags |= MF_SHOOTABLE;
+ P_DamageMobj(mo, NULL, NULL, 10000);
+ count++;
+ }
+ }
+ return count;
+}
+
+
+
+//----------------------------------------------------------------------------
+//
+// PROC A_SkullPop
+//
+//----------------------------------------------------------------------------
+
+void A_SkullPop(mobj_t * actor)
+{
+ mobj_t *mo;
+ player_t *player;
+
+ if (!actor->player)
+ {
+ return;
+ }
+ actor->flags &= ~MF_SOLID;
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 48 * FRACUNIT,
+ MT_BLOODYSKULL);
+ //mo->target = actor;
+ mo->momx = (P_Random() - P_Random()) << 9;
+ mo->momy = (P_Random() - P_Random()) << 9;
+ mo->momz = FRACUNIT * 2 + (P_Random() << 6);
+ // Attach player mobj to bloody skull
+ player = actor->player;
+ actor->player = NULL;
+ actor->special1.i = player->class;
+ mo->player = player;
+ mo->health = actor->health;
+ mo->angle = actor->angle;
+ player->mo = mo;
+ player->lookdir = 0;
+ player->damagecount = 32;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_CheckSkullFloor
+//
+//----------------------------------------------------------------------------
+
+void A_CheckSkullFloor(mobj_t * actor)
+{
+ if (actor->z <= actor->floorz)
+ {
+ P_SetMobjState(actor, S_BLOODYSKULLX1);
+ S_StartSound(actor, SFX_DRIP);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_CheckSkullDone
+//
+//----------------------------------------------------------------------------
+
+void A_CheckSkullDone(mobj_t * actor)
+{
+ if (actor->special2.i == 666)
+ {
+ P_SetMobjState(actor, S_BLOODYSKULLX2);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_CheckBurnGone
+//
+//----------------------------------------------------------------------------
+
+void A_CheckBurnGone(mobj_t * actor)
+{
+ if (actor->special2.i == 666)
+ {
+ P_SetMobjState(actor, S_PLAY_FDTH20);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FreeTargMobj
+//
+//----------------------------------------------------------------------------
+
+void A_FreeTargMobj(mobj_t * mo)
+{
+ mo->momx = mo->momy = mo->momz = 0;
+ mo->z = mo->ceilingz + 4 * FRACUNIT;
+ mo->flags &=
+ ~(MF_SHOOTABLE | MF_FLOAT | MF_SKULLFLY | MF_SOLID | MF_COUNTKILL);
+ mo->flags |= MF_CORPSE | MF_DROPOFF | MF_NOGRAVITY;
+ mo->flags2 &= ~(MF2_PASSMOBJ | MF2_LOGRAV);
+ mo->flags2 |= MF2_DONTDRAW;
+ mo->player = NULL;
+ mo->health = -1000; // Don't resurrect
+}
+
+
+//----------------------------------------------------------------------------
+//
+// CorpseQueue Routines
+//
+//----------------------------------------------------------------------------
+
+// Corpse queue for monsters - this should be saved out
+#define CORPSEQUEUESIZE 64
+mobj_t *corpseQueue[CORPSEQUEUESIZE];
+int corpseQueueSlot;
+
+// throw another corpse on the queue
+void A_QueueCorpse(mobj_t * actor)
+{
+ mobj_t *corpse;
+
+ if (corpseQueueSlot >= CORPSEQUEUESIZE)
+ { // Too many corpses - remove an old one
+ corpse = corpseQueue[corpseQueueSlot % CORPSEQUEUESIZE];
+ if (corpse)
+ P_RemoveMobj(corpse);
+ }
+ corpseQueue[corpseQueueSlot % CORPSEQUEUESIZE] = actor;
+ corpseQueueSlot++;
+}
+
+// Remove a mobj from the queue (for resurrection)
+void A_DeQueueCorpse(mobj_t * actor)
+{
+ int slot;
+
+ for (slot = 0; slot < CORPSEQUEUESIZE; slot++)
+ {
+ if (corpseQueue[slot] == actor)
+ {
+ corpseQueue[slot] = NULL;
+ break;
+ }
+ }
+}
+
+void P_InitCreatureCorpseQueue(boolean corpseScan)
+{
+ thinker_t *think;
+ mobj_t *mo;
+
+ // Initialize queue
+ corpseQueueSlot = 0;
+ memset(corpseQueue, 0, sizeof(mobj_t *) * CORPSEQUEUESIZE);
+
+ if (!corpseScan)
+ return;
+
+ // Search mobj list for corpses and place them in this queue
+ for (think = thinkercap.next; think != &thinkercap; think = think->next)
+ {
+ if (think->function != P_MobjThinker)
+ continue;
+ mo = (mobj_t *) think;
+ if (!(mo->flags & MF_CORPSE))
+ continue; // Must be a corpse
+ if (mo->flags & MF_ICECORPSE)
+ continue; // Not ice corpses
+ // Only corpses that call A_QueueCorpse from death routine
+ switch (mo->type)
+ {
+ case MT_CENTAUR:
+ case MT_CENTAURLEADER:
+ case MT_DEMON:
+ case MT_DEMON2:
+ case MT_WRAITH:
+ case MT_WRAITHB:
+ case MT_BISHOP:
+ case MT_ETTIN:
+ case MT_PIG:
+ case MT_CENTAUR_SHIELD:
+ case MT_CENTAUR_SWORD:
+ case MT_DEMONCHUNK1:
+ case MT_DEMONCHUNK2:
+ case MT_DEMONCHUNK3:
+ case MT_DEMONCHUNK4:
+ case MT_DEMONCHUNK5:
+ case MT_DEMON2CHUNK1:
+ case MT_DEMON2CHUNK2:
+ case MT_DEMON2CHUNK3:
+ case MT_DEMON2CHUNK4:
+ case MT_DEMON2CHUNK5:
+ case MT_FIREDEMON_SPLOTCH1:
+ case MT_FIREDEMON_SPLOTCH2:
+ A_QueueCorpse(mo); // Add corpse to queue
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+
+//----------------------------------------------------------------------------
+//
+// PROC A_AddPlayerCorpse
+//
+//----------------------------------------------------------------------------
+
+#define BODYQUESIZE 32
+mobj_t *bodyque[BODYQUESIZE];
+int bodyqueslot;
+
+void A_AddPlayerCorpse(mobj_t * actor)
+{
+ if (bodyqueslot >= BODYQUESIZE)
+ { // Too many player corpses - remove an old one
+ P_RemoveMobj(bodyque[bodyqueslot % BODYQUESIZE]);
+ }
+ bodyque[bodyqueslot % BODYQUESIZE] = actor;
+ bodyqueslot++;
+}
+
+//============================================================================
+//
+// A_SerpentUnHide
+//
+//============================================================================
+
+void A_SerpentUnHide(mobj_t * actor)
+{
+ actor->flags2 &= ~MF2_DONTDRAW;
+ actor->floorclip = 24 * FRACUNIT;
+}
+
+//============================================================================
+//
+// A_SerpentHide
+//
+//============================================================================
+
+void A_SerpentHide(mobj_t * actor)
+{
+ actor->flags2 |= MF2_DONTDRAW;
+ actor->floorclip = 0;
+}
+
+//============================================================================
+//
+// A_SerpentChase
+//
+//============================================================================
+
+void A_SerpentChase(mobj_t * actor)
+{
+ int delta;
+ int oldX, oldY, oldFloor;
+
+ if (actor->reactiontime)
+ {
+ actor->reactiontime--;
+ }
+
+ // Modify target threshold
+ if (actor->threshold)
+ {
+ actor->threshold--;
+ }
+
+ if (gameskill == sk_nightmare)
+ { // Monsters move faster in nightmare mode
+ actor->tics -= actor->tics / 2;
+ if (actor->tics < 3)
+ {
+ actor->tics = 3;
+ }
+ }
+
+//
+// turn towards movement direction if not there yet
+//
+ if (actor->movedir < 8)
+ {
+ actor->angle &= (7 << 29);
+ delta = actor->angle - (actor->movedir << 29);
+ if (delta > 0)
+ {
+ actor->angle -= ANG90 / 2;
+ }
+ else if (delta < 0)
+ {
+ actor->angle += ANG90 / 2;
+ }
+ }
+
+ if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+ { // look for a new target
+ if (P_LookForPlayers(actor, true))
+ { // got a new target
+ return;
+ }
+ P_SetMobjState(actor, actor->info->spawnstate);
+ return;
+ }
+
+//
+// don't attack twice in a row
+//
+ if (actor->flags & MF_JUSTATTACKED)
+ {
+ actor->flags &= ~MF_JUSTATTACKED;
+ if (gameskill != sk_nightmare)
+ P_NewChaseDir(actor);
+ return;
+ }
+
+//
+// check for melee attack
+//
+ if (actor->info->meleestate && P_CheckMeleeRange(actor))
+ {
+ if (actor->info->attacksound)
+ {
+ S_StartSound(actor, actor->info->attacksound);
+ }
+ P_SetMobjState(actor, actor->info->meleestate);
+ return;
+ }
+
+//
+// possibly choose another target
+//
+ if (netgame && !actor->threshold && !P_CheckSight(actor, actor->target))
+ {
+ if (P_LookForPlayers(actor, true))
+ return; // got a new target
+ }
+
+//
+// chase towards player
+//
+ oldX = actor->x;
+ oldY = actor->y;
+ oldFloor = actor->subsector->sector->floorpic;
+ if (--actor->movecount < 0 || !P_Move(actor))
+ {
+ P_NewChaseDir(actor);
+ }
+ if (actor->subsector->sector->floorpic != oldFloor)
+ {
+ P_TryMove(actor, oldX, oldY);
+ P_NewChaseDir(actor);
+ }
+
+//
+// make active sound
+//
+ if (actor->info->activesound && P_Random() < 3)
+ {
+ S_StartSound(actor, actor->info->activesound);
+ }
+}
+
+//============================================================================
+//
+// A_SerpentRaiseHump
+//
+// Raises the hump above the surface by raising the floorclip level
+//============================================================================
+
+void A_SerpentRaiseHump(mobj_t * actor)
+{
+ actor->floorclip -= 4 * FRACUNIT;
+}
+
+//============================================================================
+//
+// A_SerpentLowerHump
+//
+//============================================================================
+
+void A_SerpentLowerHump(mobj_t * actor)
+{
+ actor->floorclip += 4 * FRACUNIT;
+}
+
+//============================================================================
+//
+// A_SerpentHumpDecide
+//
+// Decided whether to hump up, or if the mobj is a serpent leader,
+// to missile attack
+//============================================================================
+
+void A_SerpentHumpDecide(mobj_t * actor)
+{
+ if (actor->type == MT_SERPENTLEADER)
+ {
+ if (P_Random() > 30)
+ {
+ return;
+ }
+ else if (P_Random() < 40)
+ { // Missile attack
+ P_SetMobjState(actor, S_SERPENT_SURFACE1);
+ return;
+ }
+ }
+ else if (P_Random() > 3)
+ {
+ return;
+ }
+ if (!P_CheckMeleeRange(actor))
+ { // The hump shouldn't occur when within melee range
+ if (actor->type == MT_SERPENTLEADER && P_Random() < 128)
+ {
+ P_SetMobjState(actor, S_SERPENT_SURFACE1);
+ }
+ else
+ {
+ P_SetMobjState(actor, S_SERPENT_HUMP1);
+ S_StartSound(actor, SFX_SERPENT_ACTIVE);
+ }
+ }
+}
+
+//============================================================================
+//
+// A_SerpentBirthScream
+//
+//============================================================================
+
+void A_SerpentBirthScream(mobj_t * actor)
+{
+ S_StartSound(actor, SFX_SERPENT_BIRTH);
+}
+
+//============================================================================
+//
+// A_SerpentDiveSound
+//
+//============================================================================
+
+void A_SerpentDiveSound(mobj_t * actor)
+{
+ S_StartSound(actor, SFX_SERPENT_ACTIVE);
+}
+
+//============================================================================
+//
+// A_SerpentWalk
+//
+// Similar to A_Chase, only has a hardcoded entering of meleestate
+//============================================================================
+
+void A_SerpentWalk(mobj_t * actor)
+{
+ int delta;
+
+ if (actor->reactiontime)
+ {
+ actor->reactiontime--;
+ }
+
+ // Modify target threshold
+ if (actor->threshold)
+ {
+ actor->threshold--;
+ }
+
+ if (gameskill == sk_nightmare)
+ { // Monsters move faster in nightmare mode
+ actor->tics -= actor->tics / 2;
+ if (actor->tics < 3)
+ {
+ actor->tics = 3;
+ }
+ }
+
+//
+// turn towards movement direction if not there yet
+//
+ if (actor->movedir < 8)
+ {
+ actor->angle &= (7 << 29);
+ delta = actor->angle - (actor->movedir << 29);
+ if (delta > 0)
+ {
+ actor->angle -= ANG90 / 2;
+ }
+ else if (delta < 0)
+ {
+ actor->angle += ANG90 / 2;
+ }
+ }
+
+ if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+ { // look for a new target
+ if (P_LookForPlayers(actor, true))
+ { // got a new target
+ return;
+ }
+ P_SetMobjState(actor, actor->info->spawnstate);
+ return;
+ }
+
+//
+// don't attack twice in a row
+//
+ if (actor->flags & MF_JUSTATTACKED)
+ {
+ actor->flags &= ~MF_JUSTATTACKED;
+ if (gameskill != sk_nightmare)
+ P_NewChaseDir(actor);
+ return;
+ }
+
+//
+// check for melee attack
+//
+ if (actor->info->meleestate && P_CheckMeleeRange(actor))
+ {
+ if (actor->info->attacksound)
+ {
+ S_StartSound(actor, actor->info->attacksound);
+ }
+ P_SetMobjState(actor, S_SERPENT_ATK1);
+ return;
+ }
+//
+// possibly choose another target
+//
+ if (netgame && !actor->threshold && !P_CheckSight(actor, actor->target))
+ {
+ if (P_LookForPlayers(actor, true))
+ return; // got a new target
+ }
+
+//
+// chase towards player
+//
+ if (--actor->movecount < 0 || !P_Move(actor))
+ {
+ P_NewChaseDir(actor);
+ }
+}
+
+//============================================================================
+//
+// A_SerpentCheckForAttack
+//
+//============================================================================
+
+void A_SerpentCheckForAttack(mobj_t * actor)
+{
+ if (!actor->target)
+ {
+ return;
+ }
+ if (actor->type == MT_SERPENTLEADER)
+ {
+ if (!P_CheckMeleeRange(actor))
+ {
+ P_SetMobjState(actor, S_SERPENT_ATK1);
+ return;
+ }
+ }
+ if (P_CheckMeleeRange2(actor))
+ {
+ P_SetMobjState(actor, S_SERPENT_WALK1);
+ }
+ else if (P_CheckMeleeRange(actor))
+ {
+ if (P_Random() < 32)
+ {
+ P_SetMobjState(actor, S_SERPENT_WALK1);
+ }
+ else
+ {
+ P_SetMobjState(actor, S_SERPENT_ATK1);
+ }
+ }
+}
+
+//============================================================================
+//
+// A_SerpentChooseAttack
+//
+//============================================================================
+
+void A_SerpentChooseAttack(mobj_t * actor)
+{
+ if (!actor->target || P_CheckMeleeRange(actor))
+ {
+ return;
+ }
+ if (actor->type == MT_SERPENTLEADER)
+ {
+ P_SetMobjState(actor, S_SERPENT_MISSILE1);
+ }
+}
+
+//============================================================================
+//
+// A_SerpentMeleeAttack
+//
+//============================================================================
+
+void A_SerpentMeleeAttack(mobj_t * actor)
+{
+ if (!actor->target)
+ {
+ return;
+ }
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(5));
+ S_StartSound(actor, SFX_SERPENT_MELEEHIT);
+ }
+ if (P_Random() < 96)
+ {
+ A_SerpentCheckForAttack(actor);
+ }
+}
+
+//============================================================================
+//
+// A_SerpentMissileAttack
+//
+//============================================================================
+
+void A_SerpentMissileAttack(mobj_t * actor)
+{
+ if (!actor->target)
+ {
+ return;
+ }
+
+ P_SpawnMissile(actor, actor->target, MT_SERPENTFX);
+}
+
+//============================================================================
+//
+// A_SerpentHeadPop
+//
+//============================================================================
+
+void A_SerpentHeadPop(mobj_t * actor)
+{
+ P_SpawnMobj(actor->x, actor->y, actor->z + 45 * FRACUNIT,
+ MT_SERPENT_HEAD);
+}
+
+//============================================================================
+//
+// A_SerpentSpawnGibs
+//
+//============================================================================
+
+void A_SerpentSpawnGibs(mobj_t * actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x + ((P_Random() - 128) << 12),
+ actor->y + ((P_Random() - 128) << 12),
+ actor->floorz + FRACUNIT, MT_SERPENT_GIB1);
+ if (mo)
+ {
+ mo->momx = (P_Random() - 128) << 6;
+ mo->momy = (P_Random() - 128) << 6;
+ mo->floorclip = 6 * FRACUNIT;
+ }
+ mo = P_SpawnMobj(actor->x + ((P_Random() - 128) << 12),
+ actor->y + ((P_Random() - 128) << 12),
+ actor->floorz + FRACUNIT, MT_SERPENT_GIB2);
+ if (mo)
+ {
+ mo->momx = (P_Random() - 128) << 6;
+ mo->momy = (P_Random() - 128) << 6;
+ mo->floorclip = 6 * FRACUNIT;
+ }
+ mo = P_SpawnMobj(actor->x + ((P_Random() - 128) << 12),
+ actor->y + ((P_Random() - 128) << 12),
+ actor->floorz + FRACUNIT, MT_SERPENT_GIB3);
+ if (mo)
+ {
+ mo->momx = (P_Random() - 128) << 6;
+ mo->momy = (P_Random() - 128) << 6;
+ mo->floorclip = 6 * FRACUNIT;
+ }
+}
+
+//============================================================================
+//
+// A_FloatGib
+//
+//============================================================================
+
+void A_FloatGib(mobj_t * actor)
+{
+ actor->floorclip -= FRACUNIT;
+}
+
+//============================================================================
+//
+// A_SinkGib
+//
+//============================================================================
+
+void A_SinkGib(mobj_t * actor)
+{
+ actor->floorclip += FRACUNIT;
+}
+
+//============================================================================
+//
+// A_DelayGib
+//
+//============================================================================
+
+void A_DelayGib(mobj_t * actor)
+{
+ actor->tics -= P_Random() >> 2;
+}
+
+//============================================================================
+//
+// A_SerpentHeadCheck
+//
+//============================================================================
+
+void A_SerpentHeadCheck(mobj_t * actor)
+{
+ if (actor->z <= actor->floorz)
+ {
+ if (P_GetThingFloorType(actor) >= FLOOR_LIQUID)
+ {
+ P_HitFloor(actor);
+ P_SetMobjState(actor, S_NULL);
+ }
+ else
+ {
+ P_SetMobjState(actor, S_SERPENT_HEAD_X1);
+ }
+ }
+}
+
+//============================================================================
+//
+// A_CentaurAttack
+//
+//============================================================================
+
+void A_CentaurAttack(mobj_t * actor)
+{
+ if (!actor->target)
+ {
+ return;
+ }
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, P_Random() % 7 + 3);
+ }
+}
+
+//============================================================================
+//
+// A_CentaurAttack2
+//
+//============================================================================
+
+void A_CentaurAttack2(mobj_t * actor)
+{
+ if (!actor->target)
+ {
+ return;
+ }
+ P_SpawnMissile(actor, actor->target, MT_CENTAUR_FX);
+ S_StartSound(actor, SFX_CENTAURLEADER_ATTACK);
+}
+
+//============================================================================
+//
+// A_CentaurDropStuff
+//
+// Spawn shield/sword sprites when the centaur pulps //============================================================================
+
+void A_CentaurDropStuff(mobj_t * actor)
+{
+ mobj_t *mo;
+ angle_t angle;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45 * FRACUNIT,
+ MT_CENTAUR_SHIELD);
+ if (mo)
+ {
+ angle = actor->angle + ANG90;
+ mo->momz = FRACUNIT * 8 + (P_Random() << 10);
+ mo->momx = FixedMul(((P_Random() - 128) << 11) + FRACUNIT,
+ finecosine[angle >> ANGLETOFINESHIFT]);
+ mo->momy = FixedMul(((P_Random() - 128) << 11) + FRACUNIT,
+ finesine[angle >> ANGLETOFINESHIFT]);
+ mo->target = actor;
+ }
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45 * FRACUNIT,
+ MT_CENTAUR_SWORD);
+ if (mo)
+ {
+ angle = actor->angle - ANG90;
+ mo->momz = FRACUNIT * 8 + (P_Random() << 10);
+ mo->momx = FixedMul(((P_Random() - 128) << 11) + FRACUNIT,
+ finecosine[angle >> ANGLETOFINESHIFT]);
+ mo->momy = FixedMul(((P_Random() - 128) << 11) + FRACUNIT,
+ finesine[angle >> ANGLETOFINESHIFT]);
+ mo->target = actor;
+ }
+}
+
+//============================================================================
+//
+// A_CentaurDefend
+//
+//============================================================================
+
+void A_CentaurDefend(mobj_t * actor)
+{
+ A_FaceTarget(actor);
+ if (P_CheckMeleeRange(actor) && P_Random() < 32)
+ {
+ A_UnSetInvulnerable(actor);
+ P_SetMobjState(actor, actor->info->meleestate);
+ }
+}
+
+//============================================================================
+//
+// A_BishopAttack
+//
+//============================================================================
+
+void A_BishopAttack(mobj_t * actor)
+{
+ if (!actor->target)
+ {
+ return;
+ }
+ S_StartSound(actor, actor->info->attacksound);
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(4));
+ return;
+ }
+ actor->special1.i = (P_Random() & 3) + 5;
+}
+
+//============================================================================
+//
+// A_BishopAttack2
+//
+// Spawns one of a string of bishop missiles
+//============================================================================
+
+void A_BishopAttack2(mobj_t * actor)
+{
+ mobj_t *mo;
+
+ if (!actor->target || !actor->special1.i)
+ {
+ actor->special1.i = 0;
+ P_SetMobjState(actor, S_BISHOP_WALK1);
+ return;
+ }
+ mo = P_SpawnMissile(actor, actor->target, MT_BISH_FX);
+ if (mo)
+ {
+ mo->special1.m = actor->target;
+ mo->special2.i = 16; // High word == x/y, Low word == z
+ }
+ actor->special1.i--;
+}
+
+//============================================================================
+//
+// A_BishopMissileWeave
+//
+//============================================================================
+
+void A_BishopMissileWeave(mobj_t * actor)
+{
+ fixed_t newX, newY;
+ int weaveXY, weaveZ;
+ int angle;
+
+ weaveXY = actor->special2.i >> 16;
+ weaveZ = actor->special2.i & 0xFFFF;
+ angle = (actor->angle + ANG90) >> ANGLETOFINESHIFT;
+ newX = actor->x - FixedMul(finecosine[angle],
+ FloatBobOffsets[weaveXY] << 1);
+ newY = actor->y - FixedMul(finesine[angle],
+ FloatBobOffsets[weaveXY] << 1);
+ weaveXY = (weaveXY + 2) & 63;
+ newX += FixedMul(finecosine[angle], FloatBobOffsets[weaveXY] << 1);
+ newY += FixedMul(finesine[angle], FloatBobOffsets[weaveXY] << 1);
+ P_TryMove(actor, newX, newY);
+ actor->z -= FloatBobOffsets[weaveZ];
+ weaveZ = (weaveZ + 2) & 63;
+ actor->z += FloatBobOffsets[weaveZ];
+ actor->special2.i = weaveZ + (weaveXY << 16);
+}
+
+//============================================================================
+//
+// A_BishopMissileSeek
+//
+//============================================================================
+
+void A_BishopMissileSeek(mobj_t * actor)
+{
+ P_SeekerMissile(actor, ANG1 * 2, ANG1 * 3);
+}
+
+//============================================================================
+//
+// A_BishopDecide
+//
+//============================================================================
+
+void A_BishopDecide(mobj_t * actor)
+{
+ if (P_Random() < 220)
+ {
+ return;
+ }
+ else
+ {
+ P_SetMobjState(actor, S_BISHOP_BLUR1);
+ }
+}
+
+//============================================================================
+//
+// A_BishopDoBlur
+//
+//============================================================================
+
+void A_BishopDoBlur(mobj_t * actor)
+{
+ actor->special1.i = (P_Random() & 3) + 3; // Random number of blurs
+ if (P_Random() < 120)
+ {
+ P_ThrustMobj(actor, actor->angle + ANG90, 11 * FRACUNIT);
+ }
+ else if (P_Random() > 125)
+ {
+ P_ThrustMobj(actor, actor->angle - ANG90, 11 * FRACUNIT);
+ }
+ else
+ { // Thrust forward
+ P_ThrustMobj(actor, actor->angle, 11 * FRACUNIT);
+ }
+ S_StartSound(actor, SFX_BISHOP_BLUR);
+}
+
+//============================================================================
+//
+// A_BishopSpawnBlur
+//
+//============================================================================
+
+void A_BishopSpawnBlur(mobj_t * actor)
+{
+ mobj_t *mo;
+
+ if (!--actor->special1.i)
+ {
+ actor->momx = 0;
+ actor->momy = 0;
+ if (P_Random() > 96)
+ {
+ P_SetMobjState(actor, S_BISHOP_WALK1);
+ }
+ else
+ {
+ P_SetMobjState(actor, S_BISHOP_ATK1);
+ }
+ }
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_BISHOPBLUR);
+ if (mo)
+ {
+ mo->angle = actor->angle;
+ }
+}
+
+//============================================================================
+//
+// A_BishopChase
+//
+//============================================================================
+
+void A_BishopChase(mobj_t * actor)
+{
+ actor->z -= FloatBobOffsets[actor->special2.i] >> 1;
+ actor->special2.i = (actor->special2.i + 4) & 63;
+ actor->z += FloatBobOffsets[actor->special2.i] >> 1;
+}
+
+//============================================================================
+//
+// A_BishopPuff
+//
+//============================================================================
+
+void A_BishopPuff(mobj_t * actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 40 * FRACUNIT,
+ MT_BISHOP_PUFF);
+ if (mo)
+ {
+ mo->momz = FRACUNIT / 2;
+ }
+}
+
+//============================================================================
+//
+// A_BishopPainBlur
+//
+//============================================================================
+
+void A_BishopPainBlur(mobj_t * actor)
+{
+ mobj_t *mo;
+
+ if (P_Random() < 64)
+ {
+ P_SetMobjState(actor, S_BISHOP_BLUR1);
+ return;
+ }
+ mo = P_SpawnMobj(actor->x + ((P_Random() - P_Random()) << 12), actor->y
+ + ((P_Random() - P_Random()) << 12),
+ actor->z + ((P_Random() - P_Random()) << 11),
+ MT_BISHOPPAINBLUR);
+ if (mo)
+ {
+ mo->angle = actor->angle;
+ }
+}
+
+//============================================================================
+//
+// DragonSeek
+//
+//============================================================================
+
+static void DragonSeek(mobj_t * actor, angle_t thresh, angle_t turnMax)
+{
+ int dir;
+ int dist;
+ angle_t delta;
+ angle_t angle;
+ mobj_t *target;
+ int search;
+ int i;
+ int bestArg;
+ angle_t bestAngle;
+ angle_t angleToSpot, angleToTarget;
+ mobj_t *mo;
+
+ target = actor->special1.m;
+ if (target == NULL)
+ {
+ return;
+ }
+ dir = P_FaceMobj(actor, target, &delta);
+ if (delta > thresh)
+ {
+ delta >>= 1;
+ if (delta > turnMax)
+ {
+ delta = turnMax;
+ }
+ }
+ if (dir)
+ { // Turn clockwise
+ actor->angle += delta;
+ }
+ else
+ { // Turn counter clockwise
+ actor->angle -= delta;
+ }
+ angle = actor->angle >> ANGLETOFINESHIFT;
+ actor->momx = FixedMul(actor->info->speed, finecosine[angle]);
+ actor->momy = FixedMul(actor->info->speed, finesine[angle]);
+ if (actor->z + actor->height < target->z
+ || target->z + target->height < actor->z)
+ {
+ dist = P_AproxDistance(target->x - actor->x, target->y - actor->y);
+ dist = dist / actor->info->speed;
+ if (dist < 1)
+ {
+ dist = 1;
+ }
+ actor->momz = (target->z - actor->z) / dist;
+ }
+ else
+ {
+ dist = P_AproxDistance(target->x - actor->x, target->y - actor->y);
+ dist = dist / actor->info->speed;
+ }
+ if (target->flags & MF_SHOOTABLE && P_Random() < 64)
+ { // attack the destination mobj if it's attackable
+ mobj_t *oldTarget;
+
+ if (abs(actor->angle - R_PointToAngle2(actor->x, actor->y,
+ target->x,
+ target->y)) < ANG45 / 2)
+ {
+ oldTarget = actor->target;
+ actor->target = target;
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(10));
+ S_StartSound(actor, SFX_DRAGON_ATTACK);
+ }
+ else if (P_Random() < 128 && P_CheckMissileRange(actor))
+ {
+ P_SpawnMissile(actor, target, MT_DRAGON_FX);
+ S_StartSound(actor, SFX_DRAGON_ATTACK);
+ }
+ actor->target = oldTarget;
+ }
+ }
+ if (dist < 4)
+ { // Hit the target thing
+ if (actor->target && P_Random() < 200)
+ {
+ bestArg = -1;
+ bestAngle = ANG_MAX;
+ angleToTarget = R_PointToAngle2(actor->x, actor->y,
+ actor->target->x,
+ actor->target->y);
+ for (i = 0; i < 5; i++)
+ {
+ if (!target->args[i])
+ {
+ continue;
+ }
+ search = -1;
+ mo = P_FindMobjFromTID(target->args[i], &search);
+ angleToSpot = R_PointToAngle2(actor->x, actor->y,
+ mo->x, mo->y);
+ if (abs(angleToSpot - angleToTarget) < bestAngle)
+ {
+ bestAngle = abs(angleToSpot - angleToTarget);
+ bestArg = i;
+ }
+ }
+ if (bestArg != -1)
+ {
+ search = -1;
+ actor->special1.m =
+ P_FindMobjFromTID(target->args[bestArg], &search);
+ }
+ }
+ else
+ {
+ do
+ {
+ i = (P_Random() >> 2) % 5;
+ }
+ while (!target->args[i]);
+ search = -1;
+ actor->special1.m =
+ P_FindMobjFromTID(target->args[i], &search);
+ }
+ }
+}
+
+//============================================================================
+//
+// A_DragonInitFlight
+//
+//============================================================================
+
+void A_DragonInitFlight(mobj_t * actor)
+{
+ int search;
+
+ search = -1;
+ do
+ { // find the first tid identical to the dragon's tid
+ actor->special1.m = P_FindMobjFromTID(actor->tid, &search);
+ if (search == -1)
+ {
+ P_SetMobjState(actor, actor->info->spawnstate);
+ return;
+ }
+ }
+ while (actor->special1.m == actor);
+ P_RemoveMobjFromTIDList(actor);
+}
+
+//============================================================================
+//
+// A_DragonFlight
+//
+//============================================================================
+
+void A_DragonFlight(mobj_t * actor)
+{
+ angle_t angle;
+
+ DragonSeek(actor, 4 * ANG1, 8 * ANG1);
+ if (actor->target)
+ {
+ if (!(actor->target->flags & MF_SHOOTABLE))
+ { // target died
+ actor->target = NULL;
+ return;
+ }
+ angle = R_PointToAngle2(actor->x, actor->y, actor->target->x,
+ actor->target->y);
+ if (abs(actor->angle - angle) < ANG45 / 2
+ && P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(8));
+ S_StartSound(actor, SFX_DRAGON_ATTACK);
+ }
+ else if (abs(actor->angle - angle) <= ANG1 * 20)
+ {
+ P_SetMobjState(actor, actor->info->missilestate);
+ S_StartSound(actor, SFX_DRAGON_ATTACK);
+ }
+ }
+ else
+ {
+ P_LookForPlayers(actor, true);
+ }
+}
+
+//============================================================================
+//
+// A_DragonFlap
+//
+//============================================================================
+
+void A_DragonFlap(mobj_t * actor)
+{
+ A_DragonFlight(actor);
+ if (P_Random() < 240)
+ {
+ S_StartSound(actor, SFX_DRAGON_WINGFLAP);
+ }
+ else
+ {
+ S_StartSound(actor, actor->info->activesound);
+ }
+}
+
+//============================================================================
+//
+// A_DragonAttack
+//
+//============================================================================
+
+void A_DragonAttack(mobj_t * actor)
+{
+ P_SpawnMissile(actor, actor->target, MT_DRAGON_FX);
+}
+
+//============================================================================
+//
+// A_DragonFX2
+//
+//============================================================================
+
+void A_DragonFX2(mobj_t * actor)
+{
+ mobj_t *mo;
+ int i;
+ int delay;
+
+ delay = 16 + (P_Random() >> 3);
+ for (i = 1 + (P_Random() & 3); i; i--)
+ {
+ mo = P_SpawnMobj(actor->x + ((P_Random() - 128) << 14),
+ actor->y + ((P_Random() - 128) << 14),
+ actor->z + ((P_Random() - 128) << 12),
+ MT_DRAGON_FX2);
+ if (mo)
+ {
+ mo->tics = delay + (P_Random() & 3) * i * 2;
+ mo->target = actor->target;
+ }
+ }
+}
+
+//============================================================================
+//
+// A_DragonPain
+//
+//============================================================================
+
+void A_DragonPain(mobj_t * actor)
+{
+ A_Pain(actor);
+ if (!actor->special1.i)
+ { // no destination spot yet
+ P_SetMobjState(actor, S_DRAGON_INIT);
+ }
+}
+
+//============================================================================
+//
+// A_DragonCheckCrash
+//
+//============================================================================
+
+void A_DragonCheckCrash(mobj_t * actor)
+{
+ if (actor->z <= actor->floorz)
+ {
+ P_SetMobjState(actor, S_DRAGON_CRASH1);
+ }
+}
+
+//============================================================================
+// Demon AI
+//============================================================================
+
+//
+// A_DemonAttack1 (melee)
+//
+void A_DemonAttack1(mobj_t * actor)
+{
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(2));
+ }
+}
+
+
+//
+// A_DemonAttack2 (missile)
+//
+void A_DemonAttack2(mobj_t * actor)
+{
+ mobj_t *mo;
+ int fireBall;
+
+ if (actor->type == MT_DEMON)
+ {
+ fireBall = MT_DEMONFX1;
+ }
+ else
+ {
+ fireBall = MT_DEMON2FX1;
+ }
+ mo = P_SpawnMissile(actor, actor->target, fireBall);
+ if (mo)
+ {
+ mo->z += 30 * FRACUNIT;
+ S_StartSound(actor, SFX_DEMON_MISSILE_FIRE);
+ }
+}
+
+//
+// A_DemonDeath
+//
+
+void A_DemonDeath(mobj_t * actor)
+{
+ mobj_t *mo;
+ angle_t angle;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45 * FRACUNIT,
+ MT_DEMONCHUNK1);
+ if (mo)
+ {
+ angle = actor->angle + ANG90;
+ mo->momz = 8 * FRACUNIT;
+ mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+ finecosine[angle >> ANGLETOFINESHIFT]);
+ mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+ finesine[angle >> ANGLETOFINESHIFT]);
+ mo->target = actor;
+ }
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45 * FRACUNIT,
+ MT_DEMONCHUNK2);
+ if (mo)
+ {
+ angle = actor->angle - ANG90;
+ mo->momz = 8 * FRACUNIT;
+ mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+ finecosine[angle >> ANGLETOFINESHIFT]);
+ mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+ finesine[angle >> ANGLETOFINESHIFT]);
+ mo->target = actor;
+ }
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45 * FRACUNIT,
+ MT_DEMONCHUNK3);
+ if (mo)
+ {
+ angle = actor->angle - ANG90;
+ mo->momz = 8 * FRACUNIT;
+ mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+ finecosine[angle >> ANGLETOFINESHIFT]);
+ mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+ finesine[angle >> ANGLETOFINESHIFT]);
+ mo->target = actor;
+ }
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45 * FRACUNIT,
+ MT_DEMONCHUNK4);
+ if (mo)
+ {
+ angle = actor->angle - ANG90;
+ mo->momz = 8 * FRACUNIT;
+ mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+ finecosine[angle >> ANGLETOFINESHIFT]);
+ mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+ finesine[angle >> ANGLETOFINESHIFT]);
+ mo->target = actor;
+ }
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45 * FRACUNIT,
+ MT_DEMONCHUNK5);
+ if (mo)
+ {
+ angle = actor->angle - ANG90;
+ mo->momz = 8 * FRACUNIT;
+ mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+ finecosine[angle >> ANGLETOFINESHIFT]);
+ mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+ finesine[angle >> ANGLETOFINESHIFT]);
+ mo->target = actor;
+ }
+}
+
+//===========================================================================
+//
+// A_Demon2Death
+//
+//===========================================================================
+
+void A_Demon2Death(mobj_t * actor)
+{
+ mobj_t *mo;
+ angle_t angle;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45 * FRACUNIT,
+ MT_DEMON2CHUNK1);
+ if (mo)
+ {
+ angle = actor->angle + ANG90;
+ mo->momz = 8 * FRACUNIT;
+ mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+ finecosine[angle >> ANGLETOFINESHIFT]);
+ mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+ finesine[angle >> ANGLETOFINESHIFT]);
+ mo->target = actor;
+ }
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45 * FRACUNIT,
+ MT_DEMON2CHUNK2);
+ if (mo)
+ {
+ angle = actor->angle - ANG90;
+ mo->momz = 8 * FRACUNIT;
+ mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+ finecosine[angle >> ANGLETOFINESHIFT]);
+ mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+ finesine[angle >> ANGLETOFINESHIFT]);
+ mo->target = actor;
+ }
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45 * FRACUNIT,
+ MT_DEMON2CHUNK3);
+ if (mo)
+ {
+ angle = actor->angle - ANG90;
+ mo->momz = 8 * FRACUNIT;
+ mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+ finecosine[angle >> ANGLETOFINESHIFT]);
+ mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+ finesine[angle >> ANGLETOFINESHIFT]);
+ mo->target = actor;
+ }
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45 * FRACUNIT,
+ MT_DEMON2CHUNK4);
+ if (mo)
+ {
+ angle = actor->angle - ANG90;
+ mo->momz = 8 * FRACUNIT;
+ mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+ finecosine[angle >> ANGLETOFINESHIFT]);
+ mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+ finesine[angle >> ANGLETOFINESHIFT]);
+ mo->target = actor;
+ }
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45 * FRACUNIT,
+ MT_DEMON2CHUNK5);
+ if (mo)
+ {
+ angle = actor->angle - ANG90;
+ mo->momz = 8 * FRACUNIT;
+ mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+ finecosine[angle >> ANGLETOFINESHIFT]);
+ mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+ finesine[angle >> ANGLETOFINESHIFT]);
+ mo->target = actor;
+ }
+}
+
+
+
+//
+// A_SinkMobj
+// Sink a mobj incrementally into the floor
+//
+
+boolean A_SinkMobj(mobj_t * actor)
+{
+ if (actor->floorclip < actor->info->height)
+ {
+ switch (actor->type)
+ {
+ case MT_THRUSTFLOOR_DOWN:
+ case MT_THRUSTFLOOR_UP:
+ actor->floorclip += 6 * FRACUNIT;
+ break;
+ default:
+ actor->floorclip += FRACUNIT;
+ break;
+ }
+ return false;
+ }
+ return true;
+}
+
+//
+// A_RaiseMobj
+// Raise a mobj incrementally from the floor to
+//
+
+boolean A_RaiseMobj(mobj_t * actor)
+{
+ int done = true;
+
+ // Raise a mobj from the ground
+ if (actor->floorclip > 0)
+ {
+ switch (actor->type)
+ {
+ case MT_WRAITHB:
+ actor->floorclip -= 2 * FRACUNIT;
+ break;
+ case MT_THRUSTFLOOR_DOWN:
+ case MT_THRUSTFLOOR_UP:
+ actor->floorclip -= actor->special2.i * FRACUNIT;
+ break;
+ default:
+ actor->floorclip -= 2 * FRACUNIT;
+ break;
+ }
+ if (actor->floorclip <= 0)
+ {
+ actor->floorclip = 0;
+ done = true;
+ }
+ else
+ {
+ done = false;
+ }
+ }
+ return done; // Reached target height
+}
+
+
+//============================================================================
+// Wraith Variables
+//
+// special1 Internal index into floatbob
+// special2
+//============================================================================
+
+//
+// A_WraithInit
+//
+
+void A_WraithInit(mobj_t * actor)
+{
+ actor->z += 48 << FRACBITS;
+ actor->special1.i = 0; // index into floatbob
+}
+
+void A_WraithRaiseInit(mobj_t * actor)
+{
+ actor->flags2 &= ~MF2_DONTDRAW;
+ actor->flags2 &= ~MF2_NONSHOOTABLE;
+ actor->flags |= MF_SHOOTABLE | MF_SOLID;
+ actor->floorclip = actor->info->height;
+}
+
+void A_WraithRaise(mobj_t * actor)
+{
+ if (A_RaiseMobj(actor))
+ {
+ // Reached it's target height
+ P_SetMobjState(actor, S_WRAITH_CHASE1);
+ }
+
+ P_SpawnDirt(actor, actor->radius);
+}
+
+
+void A_WraithMelee(mobj_t * actor)
+{
+ int amount;
+
+ // Steal health from target and give to player
+ if (P_CheckMeleeRange(actor) && (P_Random() < 220))
+ {
+ amount = HITDICE(2);
+ P_DamageMobj(actor->target, actor, actor, amount);
+ actor->health += amount;
+ }
+}
+
+void A_WraithMissile(mobj_t * actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMissile(actor, actor->target, MT_WRAITHFX1);
+ if (mo)
+ {
+ S_StartSound(actor, SFX_WRAITH_MISSILE_FIRE);
+ }
+}
+
+
+//
+// A_WraithFX2 - spawns sparkle tail of missile
+//
+
+void A_WraithFX2(mobj_t * actor)
+{
+ mobj_t *mo;
+ angle_t angle;
+ int i;
+
+ for (i = 0; i < 2; i++)
+ {
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_WRAITHFX2);
+ if (mo)
+ {
+ if (P_Random() < 128)
+ {
+ angle = actor->angle + (P_Random() << 22);
+ }
+ else
+ {
+ angle = actor->angle - (P_Random() << 22);
+ }
+ mo->momz = 0;
+ mo->momx = FixedMul((P_Random() << 7) + FRACUNIT,
+ finecosine[angle >> ANGLETOFINESHIFT]);
+ mo->momy = FixedMul((P_Random() << 7) + FRACUNIT,
+ finesine[angle >> ANGLETOFINESHIFT]);
+ mo->target = actor;
+ mo->floorclip = 10 * FRACUNIT;
+ }
+ }
+}
+
+
+// Spawn an FX3 around the actor during attacks
+void A_WraithFX3(mobj_t * actor)
+{
+ mobj_t *mo;
+ int numdropped = P_Random() % 15;
+ int i;
+
+ for (i = 0; i < numdropped; i++)
+ {
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_WRAITHFX3);
+ if (mo)
+ {
+ mo->x += (P_Random() - 128) << 11;
+ mo->y += (P_Random() - 128) << 11;
+ mo->z += (P_Random() << 10);
+ mo->target = actor;
+ }
+ }
+}
+
+// Spawn an FX4 during movement
+void A_WraithFX4(mobj_t * actor)
+{
+ mobj_t *mo;
+ int chance = P_Random();
+ int spawn4, spawn5;
+
+ if (chance < 10)
+ {
+ spawn4 = true;
+ spawn5 = false;
+ }
+ else if (chance < 20)
+ {
+ spawn4 = false;
+ spawn5 = true;
+ }
+ else if (chance < 25)
+ {
+ spawn4 = true;
+ spawn5 = true;
+ }
+ else
+ {
+ spawn4 = false;
+ spawn5 = false;
+ }
+
+ if (spawn4)
+ {
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_WRAITHFX4);
+ if (mo)
+ {
+ mo->x += (P_Random() - 128) << 12;
+ mo->y += (P_Random() - 128) << 12;
+ mo->z += (P_Random() << 10);
+ mo->target = actor;
+ }
+ }
+ if (spawn5)
+ {
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_WRAITHFX5);
+ if (mo)
+ {
+ mo->x += (P_Random() - 128) << 11;
+ mo->y += (P_Random() - 128) << 11;
+ mo->z += (P_Random() << 10);
+ mo->target = actor;
+ }
+ }
+}
+
+
+void A_WraithLook(mobj_t * actor)
+{
+// A_WraithFX4(actor); // too expensive
+ A_Look(actor);
+}
+
+
+void A_WraithChase(mobj_t * actor)
+{
+ int weaveindex = actor->special1.i;
+ actor->z += FloatBobOffsets[weaveindex];
+ actor->special1.i = (weaveindex + 2) & 63;
+// if (actor->floorclip > 0)
+// {
+// P_SetMobjState(actor, S_WRAITH_RAISE2);
+// return;
+// }
+ A_Chase(actor);
+ A_WraithFX4(actor);
+}
+
+
+
+//============================================================================
+// Ettin AI
+//============================================================================
+
+void A_EttinAttack(mobj_t * actor)
+{
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(2));
+ }
+}
+
+
+void A_DropMace(mobj_t * actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y,
+ actor->z + (actor->height >> 1), MT_ETTIN_MACE);
+ if (mo)
+ {
+ mo->momx = (P_Random() - 128) << 11;
+ mo->momy = (P_Random() - 128) << 11;
+ mo->momz = FRACUNIT * 10 + (P_Random() << 10);
+ mo->target = actor;
+ }
+}
+
+
+//============================================================================
+// Fire Demon AI
+//
+// special1 index into floatbob
+// special2 whether strafing or not
+//============================================================================
+
+void A_FiredSpawnRock(mobj_t * actor)
+{
+ mobj_t *mo;
+ int x, y, z;
+ int rtype = 0;
+
+ switch (P_Random() % 5)
+ {
+ case 0:
+ rtype = MT_FIREDEMON_FX1;
+ break;
+ case 1:
+ rtype = MT_FIREDEMON_FX2;
+ break;
+ case 2:
+ rtype = MT_FIREDEMON_FX3;
+ break;
+ case 3:
+ rtype = MT_FIREDEMON_FX4;
+ break;
+ case 4:
+ rtype = MT_FIREDEMON_FX5;
+ break;
+ }
+
+ x = actor->x + ((P_Random() - 128) << 12);
+ y = actor->y + ((P_Random() - 128) << 12);
+ z = actor->z + ((P_Random()) << 11);
+ mo = P_SpawnMobj(x, y, z, rtype);
+ if (mo)
+ {
+ mo->target = actor;
+ mo->momx = (P_Random() - 128) << 10;
+ mo->momy = (P_Random() - 128) << 10;
+ mo->momz = (P_Random() << 10);
+ mo->special1.i = 2; // Number bounces
+ }
+
+ // Initialize fire demon
+ actor->special2.i = 0;
+ actor->flags &= ~MF_JUSTATTACKED;
+}
+
+void A_FiredRocks(mobj_t * actor)
+{
+ A_FiredSpawnRock(actor);
+ A_FiredSpawnRock(actor);
+ A_FiredSpawnRock(actor);
+ A_FiredSpawnRock(actor);
+ A_FiredSpawnRock(actor);
+}
+
+void A_FiredAttack(mobj_t * actor)
+{
+ mobj_t *mo;
+ mo = P_SpawnMissile(actor, actor->target, MT_FIREDEMON_FX6);
+ if (mo)
+ S_StartSound(actor, SFX_FIRED_ATTACK);
+}
+
+void A_SmBounce(mobj_t * actor)
+{
+ // give some more momentum (x,y,&z)
+ actor->z = actor->floorz + FRACUNIT;
+ actor->momz = (2 * FRACUNIT) + (P_Random() << 10);
+ actor->momx = P_Random() % 3 << FRACBITS;
+ actor->momy = P_Random() % 3 << FRACBITS;
+}
+
+
+#define FIREDEMON_ATTACK_RANGE 64*8*FRACUNIT
+
+void A_FiredChase(mobj_t * actor)
+{
+ int weaveindex = actor->special1.i;
+ mobj_t *target = actor->target;
+ angle_t ang;
+ fixed_t dist;
+
+ if (actor->reactiontime)
+ actor->reactiontime--;
+ if (actor->threshold)
+ actor->threshold--;
+
+ // Float up and down
+ actor->z += FloatBobOffsets[weaveindex];
+ actor->special1.i = (weaveindex + 2) & 63;
+
+ // Insure it stays above certain height
+ if (actor->z < actor->floorz + (64 * FRACUNIT))
+ {
+ actor->z += 2 * FRACUNIT;
+ }
+
+ if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+ { // Invalid target
+ P_LookForPlayers(actor, true);
+ return;
+ }
+
+ // Strafe
+ if (actor->special2.i > 0)
+ {
+ actor->special2.i--;
+ }
+ else
+ {
+ actor->special2.i = 0;
+ actor->momx = actor->momy = 0;
+ dist = P_AproxDistance(actor->x - target->x, actor->y - target->y);
+ if (dist < FIREDEMON_ATTACK_RANGE)
+ {
+ if (P_Random() < 30)
+ {
+ ang =
+ R_PointToAngle2(actor->x, actor->y, target->x, target->y);
+ if (P_Random() < 128)
+ ang += ANG90;
+ else
+ ang -= ANG90;
+ ang >>= ANGLETOFINESHIFT;
+ actor->momx = FixedMul(8 * FRACUNIT, finecosine[ang]);
+ actor->momy = FixedMul(8 * FRACUNIT, finesine[ang]);
+ actor->special2.i = 3; // strafe time
+ }
+ }
+ }
+
+ FaceMovementDirection(actor);
+
+ // Normal movement
+ if (!actor->special2.i)
+ {
+ if (--actor->movecount < 0 || !P_Move(actor))
+ {
+ P_NewChaseDir(actor);
+ }
+ }
+
+ // Do missile attack
+ if (!(actor->flags & MF_JUSTATTACKED))
+ {
+ if (P_CheckMissileRange(actor) && (P_Random() < 20))
+ {
+ P_SetMobjState(actor, actor->info->missilestate);
+ actor->flags |= MF_JUSTATTACKED;
+ return;
+ }
+ }
+ else
+ {
+ actor->flags &= ~MF_JUSTATTACKED;
+ }
+
+ // make active sound
+ if (actor->info->activesound && P_Random() < 3)
+ {
+ S_StartSound(actor, actor->info->activesound);
+ }
+}
+
+void A_FiredSplotch(mobj_t * actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FIREDEMON_SPLOTCH1);
+ if (mo)
+ {
+ mo->momx = (P_Random() - 128) << 11;
+ mo->momy = (P_Random() - 128) << 11;
+ mo->momz = FRACUNIT * 3 + (P_Random() << 10);
+ }
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FIREDEMON_SPLOTCH2);
+ if (mo)
+ {
+ mo->momx = (P_Random() - 128) << 11;
+ mo->momy = (P_Random() - 128) << 11;
+ mo->momz = FRACUNIT * 3 + (P_Random() << 10);
+ }
+}
+
+
+//============================================================================
+//
+// A_IceGuyLook
+//
+//============================================================================
+
+void A_IceGuyLook(mobj_t * actor)
+{
+ fixed_t dist;
+ fixed_t an;
+
+ A_Look(actor);
+ if (P_Random() < 64)
+ {
+ dist = ((P_Random() - 128) * actor->radius) >> 7;
+ an = (actor->angle + ANG90) >> ANGLETOFINESHIFT;
+
+ P_SpawnMobj(actor->x + FixedMul(dist, finecosine[an]),
+ actor->y + FixedMul(dist, finesine[an]),
+ actor->z + 60 * FRACUNIT,
+ MT_ICEGUY_WISP1 + (P_Random() & 1));
+ }
+}
+
+//============================================================================
+//
+// A_IceGuyChase
+//
+//============================================================================
+
+void A_IceGuyChase(mobj_t * actor)
+{
+ fixed_t dist;
+ fixed_t an;
+ mobj_t *mo;
+
+ A_Chase(actor);
+ if (P_Random() < 128)
+ {
+ dist = ((P_Random() - 128) * actor->radius) >> 7;
+ an = (actor->angle + ANG90) >> ANGLETOFINESHIFT;
+
+ mo = P_SpawnMobj(actor->x + FixedMul(dist, finecosine[an]),
+ actor->y + FixedMul(dist, finesine[an]),
+ actor->z + 60 * FRACUNIT,
+ MT_ICEGUY_WISP1 + (P_Random() & 1));
+ if (mo)
+ {
+ mo->momx = actor->momx;
+ mo->momy = actor->momy;
+ mo->momz = actor->momz;
+ mo->target = actor;
+ }
+ }
+}
+
+//============================================================================
+//
+// A_IceGuyAttack
+//
+//============================================================================
+
+void A_IceGuyAttack(mobj_t * actor)
+{
+ fixed_t an;
+
+ if (!actor->target)
+ {
+ return;
+ }
+ an = (actor->angle + ANG90) >> ANGLETOFINESHIFT;
+ P_SpawnMissileXYZ(actor->x + FixedMul(actor->radius >> 1,
+ finecosine[an]),
+ actor->y + FixedMul(actor->radius >> 1, finesine[an]),
+ actor->z + 40 * FRACUNIT, actor, actor->target,
+ MT_ICEGUY_FX);
+ an = (actor->angle - ANG90) >> ANGLETOFINESHIFT;
+ P_SpawnMissileXYZ(actor->x + FixedMul(actor->radius >> 1,
+ finecosine[an]),
+ actor->y + FixedMul(actor->radius >> 1, finesine[an]),
+ actor->z + 40 * FRACUNIT, actor, actor->target,
+ MT_ICEGUY_FX);
+ S_StartSound(actor, actor->info->attacksound);
+}
+
+//============================================================================
+//
+// A_IceGuyMissilePuff
+//
+//============================================================================
+
+void A_IceGuyMissilePuff(mobj_t * actor)
+{
+ P_SpawnMobj(actor->x, actor->y, actor->z + 2 * FRACUNIT, MT_ICEFX_PUFF);
+}
+
+//============================================================================
+//
+// A_IceGuyDie
+//
+//============================================================================
+
+void A_IceGuyDie(mobj_t * actor)
+{
+ void A_FreezeDeathChunks(mobj_t * actor);
+
+ actor->momx = 0;
+ actor->momy = 0;
+ actor->momz = 0;
+ actor->height <<= 2;
+ A_FreezeDeathChunks(actor);
+}
+
+//============================================================================
+//
+// A_IceGuyMissileExplode
+//
+//============================================================================
+
+void A_IceGuyMissileExplode(mobj_t * actor)
+{
+ mobj_t *mo;
+ int i;
+
+ for (i = 0; i < 8; i++)
+ {
+ mo = P_SpawnMissileAngle(actor, MT_ICEGUY_FX2, i * ANG45,
+ -0.3 * FRACUNIT);
+ if (mo)
+ {
+ mo->target = actor->target;
+ }
+ }
+}
+
+
+
+
+
+
+
+
+
+//============================================================================
+//
+// Sorcerer stuff
+//
+// Sorcerer Variables
+// special1 Angle of ball 1 (all others relative to that)
+// special2 which ball to stop at in stop mode (MT_???)
+// args[0] Denfense time
+// args[1] Number of full rotations since stopping mode
+// args[2] Target orbit speed for acceleration/deceleration
+// args[3] Movement mode (see SORC_ macros)
+// args[4] Current ball orbit speed
+// Sorcerer Ball Variables
+// special1 Previous angle of ball (for woosh)
+// special2 Countdown of rapid fire (FX4)
+// args[0] If set, don't play the bounce sound when bouncing
+//============================================================================
+
+#define SORCBALL_INITIAL_SPEED 7
+#define SORCBALL_TERMINAL_SPEED 25
+#define SORCBALL_SPEED_ROTATIONS 5
+#define SORC_DEFENSE_TIME 255
+#define SORC_DEFENSE_HEIGHT 45
+#define BOUNCE_TIME_UNIT (35/2)
+#define SORCFX4_RAPIDFIRE_TIME (6*3) // 3 seconds
+#define SORCFX4_SPREAD_ANGLE 20
+
+#define SORC_DECELERATE 0
+#define SORC_ACCELERATE 1
+#define SORC_STOPPING 2
+#define SORC_FIRESPELL 3
+#define SORC_STOPPED 4
+#define SORC_NORMAL 5
+#define SORC_FIRING_SPELL 6
+
+#define BALL1_ANGLEOFFSET 0
+#define BALL2_ANGLEOFFSET (ANG_MAX/3)
+#define BALL3_ANGLEOFFSET ((ANG_MAX/3)*2)
+
+void A_SorcBallOrbit(mobj_t * actor);
+void A_SorcSpinBalls(mobj_t * actor);
+void A_SpeedBalls(mobj_t * actor);
+void A_SlowBalls(mobj_t * actor);
+void A_StopBalls(mobj_t * actor);
+void A_AccelBalls(mobj_t * actor);
+void A_DecelBalls(mobj_t * actor);
+void A_SorcBossAttack(mobj_t * actor);
+void A_SpawnFizzle(mobj_t * actor);
+void A_CastSorcererSpell(mobj_t * actor);
+void A_SorcUpdateBallAngle(mobj_t * actor);
+void A_BounceCheck(mobj_t * actor);
+void A_SorcFX1Seek(mobj_t * actor);
+void A_SorcOffense1(mobj_t * actor);
+void A_SorcOffense2(mobj_t * actor);
+
+
+// Spawn spinning balls above head - actor is sorcerer
+void A_SorcSpinBalls(mobj_t * actor)
+{
+ mobj_t *mo;
+ fixed_t z;
+
+ A_SlowBalls(actor);
+ actor->args[0] = 0; // Currently no defense
+ actor->args[3] = SORC_NORMAL;
+ actor->args[4] = SORCBALL_INITIAL_SPEED; // Initial orbit speed
+ actor->special1.i = ANG1;
+ z = actor->z - actor->floorclip + actor->info->height;
+
+ mo = P_SpawnMobj(actor->x, actor->y, z, MT_SORCBALL1);
+ if (mo)
+ {
+ mo->target = actor;
+ mo->special2.i = SORCFX4_RAPIDFIRE_TIME;
+ }
+ mo = P_SpawnMobj(actor->x, actor->y, z, MT_SORCBALL2);
+ if (mo)
+ mo->target = actor;
+ mo = P_SpawnMobj(actor->x, actor->y, z, MT_SORCBALL3);
+ if (mo)
+ mo->target = actor;
+}
+
+
+//
+// A_SorcBallOrbit() ==========================================
+//
+
+void A_SorcBallOrbit(mobj_t * actor)
+{
+ int x, y;
+ angle_t angle, baseangle;
+ int mode = actor->target->args[3];
+ mobj_t *parent = (mobj_t *) actor->target;
+ int dist = parent->radius - (actor->radius << 1);
+ angle_t prevangle = actor->special1.i;
+
+ if (actor->target->health <= 0)
+ P_SetMobjState(actor, actor->info->painstate);
+
+ baseangle = (angle_t) parent->special1.i;
+ switch (actor->type)
+ {
+ case MT_SORCBALL1:
+ angle = baseangle + BALL1_ANGLEOFFSET;
+ break;
+ case MT_SORCBALL2:
+ angle = baseangle + BALL2_ANGLEOFFSET;
+ break;
+ case MT_SORCBALL3:
+ angle = baseangle + BALL3_ANGLEOFFSET;
+ break;
+ default:
+ I_Error("corrupted sorcerer");
+ return;
+ }
+ actor->angle = angle;
+ angle >>= ANGLETOFINESHIFT;
+
+ switch (mode)
+ {
+ case SORC_NORMAL: // Balls rotating normally
+ A_SorcUpdateBallAngle(actor);
+ break;
+ case SORC_DECELERATE: // Balls decelerating
+ A_DecelBalls(actor);
+ A_SorcUpdateBallAngle(actor);
+ break;
+ case SORC_ACCELERATE: // Balls accelerating
+ A_AccelBalls(actor);
+ A_SorcUpdateBallAngle(actor);
+ break;
+ case SORC_STOPPING: // Balls stopping
+ if ((parent->special2.i == actor->type) &&
+ (parent->args[1] > SORCBALL_SPEED_ROTATIONS) &&
+ (abs(angle - (parent->angle >> ANGLETOFINESHIFT)) <
+ (30 << 5)))
+ {
+ // Can stop now
+ actor->target->args[3] = SORC_FIRESPELL;
+ actor->target->args[4] = 0;
+ // Set angle so ball angle == sorcerer angle
+ switch (actor->type)
+ {
+ case MT_SORCBALL1:
+ parent->special1.i = (int) (parent->angle -
+ BALL1_ANGLEOFFSET);
+ break;
+ case MT_SORCBALL2:
+ parent->special1.i = (int) (parent->angle -
+ BALL2_ANGLEOFFSET);
+ break;
+ case MT_SORCBALL3:
+ parent->special1.i = (int) (parent->angle -
+ BALL3_ANGLEOFFSET);
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ A_SorcUpdateBallAngle(actor);
+ }
+ break;
+ case SORC_FIRESPELL: // Casting spell
+ if (parent->special2.i == actor->type)
+ {
+ // Put sorcerer into special throw spell anim
+ if (parent->health > 0)
+ P_SetMobjStateNF(parent, S_SORC_ATTACK1);
+
+ if (actor->type == MT_SORCBALL1 && P_Random() < 200)
+ {
+ S_StartSound(NULL, SFX_SORCERER_SPELLCAST);
+ actor->special2.i = SORCFX4_RAPIDFIRE_TIME;
+ actor->args[4] = 128;
+ parent->args[3] = SORC_FIRING_SPELL;
+ }
+ else
+ {
+ A_CastSorcererSpell(actor);
+ parent->args[3] = SORC_STOPPED;
+ }
+ }
+ break;
+ case SORC_FIRING_SPELL:
+ if (parent->special2.i == actor->type)
+ {
+ if (actor->special2.i-- <= 0)
+ {
+ // Done rapid firing
+ parent->args[3] = SORC_STOPPED;
+ // Back to orbit balls
+ if (parent->health > 0)
+ P_SetMobjStateNF(parent, S_SORC_ATTACK4);
+ }
+ else
+ {
+ // Do rapid fire spell
+ A_SorcOffense2(actor);
+ }
+ }
+ break;
+ case SORC_STOPPED: // Balls stopped
+ default:
+ break;
+ }
+
+ if ((angle < prevangle) && (parent->args[4] == SORCBALL_TERMINAL_SPEED))
+ {
+ parent->args[1]++; // Bump rotation counter
+ // Completed full rotation - make woosh sound
+ S_StartSound(actor, SFX_SORCERER_BALLWOOSH);
+ }
+ actor->special1.i = angle; // Set previous angle
+ x = parent->x + FixedMul(dist, finecosine[angle]);
+ y = parent->y + FixedMul(dist, finesine[angle]);
+ actor->x = x;
+ actor->y = y;
+ actor->z = parent->z - parent->floorclip + parent->info->height;
+}
+
+
+//
+// Set balls to speed mode - actor is sorcerer
+//
+void A_SpeedBalls(mobj_t * actor)
+{
+ actor->args[3] = SORC_ACCELERATE; // speed mode
+ actor->args[2] = SORCBALL_TERMINAL_SPEED; // target speed
+}
+
+
+//
+// Set balls to slow mode - actor is sorcerer
+//
+void A_SlowBalls(mobj_t * actor)
+{
+ actor->args[3] = SORC_DECELERATE; // slow mode
+ actor->args[2] = SORCBALL_INITIAL_SPEED; // target speed
+}
+
+
+//
+// Instant stop when rotation gets to ball in special2
+// actor is sorcerer
+//
+void A_StopBalls(mobj_t * actor)
+{
+ int chance = P_Random();
+ actor->args[3] = SORC_STOPPING; // stopping mode
+ actor->args[1] = 0; // Reset rotation counter
+
+ if ((actor->args[0] <= 0) && (chance < 200))
+ {
+ actor->special2.i = MT_SORCBALL2; // Blue
+ }
+ else if ((actor->health < (actor->info->spawnhealth >> 1)) &&
+ (chance < 200))
+ {
+ actor->special2.i = MT_SORCBALL3; // Green
+ }
+ else
+ {
+ actor->special2.i = MT_SORCBALL1; // Yellow
+ }
+
+
+}
+
+
+//
+// Increase ball orbit speed - actor is ball
+//
+void A_AccelBalls(mobj_t * actor)
+{
+ mobj_t *sorc = actor->target;
+
+ if (sorc->args[4] < sorc->args[2])
+ {
+ sorc->args[4]++;
+ }
+ else
+ {
+ sorc->args[3] = SORC_NORMAL;
+ if (sorc->args[4] >= SORCBALL_TERMINAL_SPEED)
+ {
+ // Reached terminal velocity - stop balls
+ A_StopBalls(sorc);
+ }
+ }
+}
+
+
+// Decrease ball orbit speed - actor is ball
+void A_DecelBalls(mobj_t * actor)
+{
+ mobj_t *sorc = actor->target;
+
+ if (sorc->args[4] > sorc->args[2])
+ {
+ sorc->args[4]--;
+ }
+ else
+ {
+ sorc->args[3] = SORC_NORMAL;
+ }
+}
+
+
+// Update angle if first ball - actor is ball
+void A_SorcUpdateBallAngle(mobj_t * actor)
+{
+ if (actor->type == MT_SORCBALL1)
+ {
+ actor->target->special1.i += ANG1 * actor->target->args[4];
+ }
+}
+
+
+// actor is ball
+void A_CastSorcererSpell(mobj_t * actor)
+{
+ mobj_t *mo;
+ int spell = actor->type;
+ angle_t ang1, ang2;
+ fixed_t z;
+ mobj_t *parent = actor->target;
+
+ S_StartSound(NULL, SFX_SORCERER_SPELLCAST);
+
+ // Put sorcerer into throw spell animation
+ if (parent->health > 0)
+ P_SetMobjStateNF(parent, S_SORC_ATTACK4);
+
+ switch (spell)
+ {
+ case MT_SORCBALL1: // Offensive
+ A_SorcOffense1(actor);
+ break;
+ case MT_SORCBALL2: // Defensive
+ z = parent->z - parent->floorclip +
+ SORC_DEFENSE_HEIGHT * FRACUNIT;
+ mo = P_SpawnMobj(actor->x, actor->y, z, MT_SORCFX2);
+ parent->flags2 |= MF2_REFLECTIVE | MF2_INVULNERABLE;
+ parent->args[0] = SORC_DEFENSE_TIME;
+ if (mo)
+ mo->target = parent;
+ break;
+ case MT_SORCBALL3: // Reinforcements
+ ang1 = actor->angle - ANG45;
+ ang2 = actor->angle + ANG45;
+ if (actor->health < (actor->info->spawnhealth / 3))
+ { // Spawn 2 at a time
+ mo = P_SpawnMissileAngle(parent, MT_SORCFX3, ang1,
+ 4 * FRACUNIT);
+ if (mo)
+ mo->target = parent;
+ mo = P_SpawnMissileAngle(parent, MT_SORCFX3, ang2,
+ 4 * FRACUNIT);
+ if (mo)
+ mo->target = parent;
+ }
+ else
+ {
+ if (P_Random() < 128)
+ ang1 = ang2;
+ mo = P_SpawnMissileAngle(parent, MT_SORCFX3, ang1,
+ 4 * FRACUNIT);
+ if (mo)
+ mo->target = parent;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+void A_SpawnReinforcements(mobj_t *actor)
+{
+ mobj_t *parent = actor->target;
+ mobj_t *mo;
+ angle_t ang;
+
+ ang = ANG1 * P_Random();
+ mo = P_SpawnMissileAngle(actor, MT_SORCFX3, ang, 5*FRACUNIT);
+ if (mo) mo->target = parent;
+}
+*/
+
+// actor is ball
+void A_SorcOffense1(mobj_t * actor)
+{
+ mobj_t *mo;
+ angle_t ang1, ang2;
+ mobj_t *parent = (mobj_t *) actor->target;
+
+ ang1 = actor->angle + ANG1 * 70;
+ ang2 = actor->angle - ANG1 * 70;
+ mo = P_SpawnMissileAngle(parent, MT_SORCFX1, ang1, 0);
+ if (mo)
+ {
+ mo->target = parent;
+ mo->special1.m = parent->target;
+ mo->args[4] = BOUNCE_TIME_UNIT;
+ mo->args[3] = 15; // Bounce time in seconds
+ }
+ mo = P_SpawnMissileAngle(parent, MT_SORCFX1, ang2, 0);
+ if (mo)
+ {
+ mo->target = parent;
+ mo->special1.m = parent->target;
+ mo->args[4] = BOUNCE_TIME_UNIT;
+ mo->args[3] = 15; // Bounce time in seconds
+ }
+}
+
+
+// Actor is ball
+void A_SorcOffense2(mobj_t * actor)
+{
+ angle_t ang1;
+ mobj_t *mo;
+ int delta, index;
+ mobj_t *parent = actor->target;
+ mobj_t *dest = parent->target;
+ int dist;
+
+ index = actor->args[4] << 5;
+ actor->args[4] += 15;
+ delta = (finesine[index]) * SORCFX4_SPREAD_ANGLE;
+ delta = (delta >> FRACBITS) * ANG1;
+ ang1 = actor->angle + delta;
+ mo = P_SpawnMissileAngle(parent, MT_SORCFX4, ang1, 0);
+ if (mo)
+ {
+ mo->special2.i = 35 * 5 / 2; // 5 seconds
+ dist = P_AproxDistance(dest->x - mo->x, dest->y - mo->y);
+ dist = dist / mo->info->speed;
+ if (dist < 1)
+ dist = 1;
+ mo->momz = (dest->z - mo->z) / dist;
+ }
+}
+
+
+// Resume ball spinning
+void A_SorcBossAttack(mobj_t * actor)
+{
+ actor->args[3] = SORC_ACCELERATE;
+ actor->args[2] = SORCBALL_INITIAL_SPEED;
+}
+
+
+// spell cast magic fizzle
+void A_SpawnFizzle(mobj_t * actor)
+{
+ fixed_t x, y, z;
+ fixed_t dist = 5 * FRACUNIT;
+ angle_t angle = actor->angle >> ANGLETOFINESHIFT;
+ fixed_t speed = actor->info->speed;
+ angle_t rangle;
+ mobj_t *mo;
+ int ix;
+
+ x = actor->x + FixedMul(dist, finecosine[angle]);
+ y = actor->y + FixedMul(dist, finesine[angle]);
+ z = actor->z - actor->floorclip + (actor->height >> 1);
+ for (ix = 0; ix < 5; ix++)
+ {
+ mo = P_SpawnMobj(x, y, z, MT_SORCSPARK1);
+ if (mo)
+ {
+ rangle = angle + ((P_Random() % 5) << 1);
+ mo->momx = FixedMul(P_Random() % speed, finecosine[rangle]);
+ mo->momy = FixedMul(P_Random() % speed, finesine[rangle]);
+ mo->momz = FRACUNIT * 2;
+ }
+ }
+}
+
+
+//============================================================================
+// Yellow spell - offense
+//============================================================================
+
+void A_SorcFX1Seek(mobj_t * actor)
+{
+ A_BounceCheck(actor);
+ P_SeekerMissile(actor, ANG1 * 2, ANG1 * 6);
+}
+
+
+//============================================================================
+// Blue spell - defense
+//============================================================================
+//
+// FX2 Variables
+// special1 current angle
+// special2
+// args[0] 0 = CW, 1 = CCW
+// args[1]
+//============================================================================
+
+// Split ball in two
+void A_SorcFX2Split(mobj_t * actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SORCFX2);
+ if (mo)
+ {
+ mo->target = actor->target;
+ mo->args[0] = 0; // CW
+ mo->special1.i = actor->angle; // Set angle
+ P_SetMobjStateNF(mo, S_SORCFX2_ORBIT1);
+ }
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SORCFX2);
+ if (mo)
+ {
+ mo->target = actor->target;
+ mo->args[0] = 1; // CCW
+ mo->special1.i = actor->angle; // Set angle
+ P_SetMobjStateNF(mo, S_SORCFX2_ORBIT1);
+ }
+ P_SetMobjStateNF(actor, S_NULL);
+}
+
+
+// Orbit FX2 about sorcerer
+void A_SorcFX2Orbit(mobj_t * actor)
+{
+ angle_t angle;
+ fixed_t x, y, z;
+ mobj_t *parent = actor->target;
+ fixed_t dist = parent->info->radius;
+
+ if ((parent->health <= 0) || // Sorcerer is dead
+ (!parent->args[0])) // Time expired
+ {
+ P_SetMobjStateNF(actor, actor->info->deathstate);
+ parent->args[0] = 0;
+ parent->flags2 &= ~MF2_REFLECTIVE;
+ parent->flags2 &= ~MF2_INVULNERABLE;
+ }
+
+ if (actor->args[0] && (parent->args[0]-- <= 0)) // Time expired
+ {
+ P_SetMobjStateNF(actor, actor->info->deathstate);
+ parent->args[0] = 0;
+ parent->flags2 &= ~MF2_REFLECTIVE;
+ }
+
+ // Move to new position based on angle
+ if (actor->args[0]) // Counter clock-wise
+ {
+ actor->special1.i += ANG1 * 10;
+ angle = ((angle_t) actor->special1.i) >> ANGLETOFINESHIFT;
+ x = parent->x + FixedMul(dist, finecosine[angle]);
+ y = parent->y + FixedMul(dist, finesine[angle]);
+ z = parent->z - parent->floorclip + SORC_DEFENSE_HEIGHT * FRACUNIT;
+ z += FixedMul(15 * FRACUNIT, finecosine[angle]);
+ // Spawn trailer
+ P_SpawnMobj(x, y, z, MT_SORCFX2_T1);
+ }
+ else // Clock wise
+ {
+ actor->special1.i -= ANG1 * 10;
+ angle = ((angle_t) actor->special1.i) >> ANGLETOFINESHIFT;
+ x = parent->x + FixedMul(dist, finecosine[angle]);
+ y = parent->y + FixedMul(dist, finesine[angle]);
+ z = parent->z - parent->floorclip + SORC_DEFENSE_HEIGHT * FRACUNIT;
+ z += FixedMul(20 * FRACUNIT, finesine[angle]);
+ // Spawn trailer
+ P_SpawnMobj(x, y, z, MT_SORCFX2_T1);
+ }
+
+ actor->x = x;
+ actor->y = y;
+ actor->z = z;
+}
+
+
+
+//============================================================================
+// Green spell - spawn bishops
+//============================================================================
+
+void A_SpawnBishop(mobj_t * actor)
+{
+ mobj_t *mo;
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_BISHOP);
+ if (mo)
+ {
+ if (!P_TestMobjLocation(mo))
+ {
+ P_SetMobjState(mo, S_NULL);
+ }
+ }
+ P_SetMobjState(actor, S_NULL);
+}
+
+/*
+void A_SmokePuffEntry(mobj_t *actor)
+{
+ P_SpawnMobj(actor->x, actor->y, actor->z, MT_MNTRSMOKE);
+}
+*/
+
+void A_SmokePuffExit(mobj_t * actor)
+{
+ P_SpawnMobj(actor->x, actor->y, actor->z, MT_MNTRSMOKEEXIT);
+}
+
+void A_SorcererBishopEntry(mobj_t * actor)
+{
+ P_SpawnMobj(actor->x, actor->y, actor->z, MT_SORCFX3_EXPLOSION);
+ S_StartSound(actor, actor->info->seesound);
+}
+
+
+//============================================================================
+// FX4 - rapid fire balls
+//============================================================================
+
+void A_SorcFX4Check(mobj_t * actor)
+{
+ if (actor->special2.i-- <= 0)
+ {
+ P_SetMobjStateNF(actor, actor->info->deathstate);
+ }
+}
+
+//============================================================================
+// Ball death - spawn stuff
+//============================================================================
+
+void A_SorcBallPop(mobj_t * actor)
+{
+ S_StartSound(NULL, SFX_SORCERER_BALLPOP);
+ actor->flags &= ~MF_NOGRAVITY;
+ actor->flags2 |= MF2_LOGRAV;
+ actor->momx = ((P_Random() % 10) - 5) << FRACBITS;
+ actor->momy = ((P_Random() % 10) - 5) << FRACBITS;
+ actor->momz = (2 + (P_Random() % 3)) << FRACBITS;
+ actor->special2.i = 4 * FRACUNIT; // Initial bounce factor
+ actor->args[4] = BOUNCE_TIME_UNIT; // Bounce time unit
+ actor->args[3] = 5; // Bounce time in seconds
+}
+
+
+
+void A_BounceCheck(mobj_t * actor)
+{
+ if (actor->args[4]-- <= 0)
+ {
+ if (actor->args[3]-- <= 0)
+ {
+ P_SetMobjState(actor, actor->info->deathstate);
+ switch (actor->type)
+ {
+ case MT_SORCBALL1:
+ case MT_SORCBALL2:
+ case MT_SORCBALL3:
+ S_StartSound(NULL, SFX_SORCERER_BIGBALLEXPLODE);
+ break;
+ case MT_SORCFX1:
+ S_StartSound(NULL, SFX_SORCERER_HEADSCREAM);
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ actor->args[4] = BOUNCE_TIME_UNIT;
+ }
+ }
+}
+
+
+
+
+//============================================================================
+// Class Bosses
+//============================================================================
+#define CLASS_BOSS_STRAFE_RANGE 64*10*FRACUNIT
+
+void A_FastChase(mobj_t * actor)
+{
+ int delta;
+ fixed_t dist;
+ angle_t ang;
+ mobj_t *target;
+
+ if (actor->reactiontime)
+ {
+ actor->reactiontime--;
+ }
+
+ // Modify target threshold
+ if (actor->threshold)
+ {
+ actor->threshold--;
+ }
+
+ if (gameskill == sk_nightmare)
+ { // Monsters move faster in nightmare mode
+ actor->tics -= actor->tics / 2;
+ if (actor->tics < 3)
+ {
+ actor->tics = 3;
+ }
+ }
+
+//
+// turn towards movement direction if not there yet
+//
+ if (actor->movedir < 8)
+ {
+ actor->angle &= (7 << 29);
+ delta = actor->angle - (actor->movedir << 29);
+ if (delta > 0)
+ {
+ actor->angle -= ANG90 / 2;
+ }
+ else if (delta < 0)
+ {
+ actor->angle += ANG90 / 2;
+ }
+ }
+
+ if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+ { // look for a new target
+ if (P_LookForPlayers(actor, true))
+ { // got a new target
+ return;
+ }
+ P_SetMobjState(actor, actor->info->spawnstate);
+ return;
+ }
+
+//
+// don't attack twice in a row
+//
+ if (actor->flags & MF_JUSTATTACKED)
+ {
+ actor->flags &= ~MF_JUSTATTACKED;
+ if (gameskill != sk_nightmare)
+ P_NewChaseDir(actor);
+ return;
+ }
+
+ // Strafe
+ if (actor->special2.i > 0)
+ {
+ actor->special2.i--;
+ }
+ else
+ {
+ target = actor->target;
+ actor->special2.i = 0;
+ actor->momx = actor->momy = 0;
+ dist = P_AproxDistance(actor->x - target->x, actor->y - target->y);
+ if (dist < CLASS_BOSS_STRAFE_RANGE)
+ {
+ if (P_Random() < 100)
+ {
+ ang = R_PointToAngle2(actor->x, actor->y,
+ target->x, target->y);
+ if (P_Random() < 128)
+ ang += ANG90;
+ else
+ ang -= ANG90;
+ ang >>= ANGLETOFINESHIFT;
+ actor->momx = FixedMul(13 * FRACUNIT, finecosine[ang]);
+ actor->momy = FixedMul(13 * FRACUNIT, finesine[ang]);
+ actor->special2.i = 3; // strafe time
+ }
+ }
+ }
+
+//
+// check for missile attack
+//
+ if (actor->info->missilestate)
+ {
+ if (gameskill < sk_nightmare && actor->movecount)
+ goto nomissile;
+ if (!P_CheckMissileRange(actor))
+ goto nomissile;
+ P_SetMobjState(actor, actor->info->missilestate);
+ actor->flags |= MF_JUSTATTACKED;
+ return;
+ }
+ nomissile:
+
+//
+// possibly choose another target
+//
+ if (netgame && !actor->threshold && !P_CheckSight(actor, actor->target))
+ {
+ if (P_LookForPlayers(actor, true))
+ return; // got a new target
+ }
+
+//
+// chase towards player
+//
+ if (!actor->special2.i)
+ {
+ if (--actor->movecount < 0 || !P_Move(actor))
+ {
+ P_NewChaseDir(actor);
+ }
+ }
+}
+
+
+void A_FighterAttack(mobj_t * actor)
+{
+ extern void A_FSwordAttack2(mobj_t * actor);
+
+ if (!actor->target)
+ return;
+ A_FSwordAttack2(actor);
+}
+
+
+void A_ClericAttack(mobj_t * actor)
+{
+ extern void A_CHolyAttack3(mobj_t * actor);
+
+ if (!actor->target)
+ return;
+ A_CHolyAttack3(actor);
+}
+
+
+
+void A_MageAttack(mobj_t * actor)
+{
+ extern void A_MStaffAttack2(mobj_t * actor);
+
+ if (!actor->target)
+ return;
+ A_MStaffAttack2(actor);
+}
+
+void A_ClassBossHealth(mobj_t * actor)
+{
+ if (netgame && !deathmatch) // co-op only
+ {
+ if (!actor->special1.i)
+ {
+ actor->health *= 5;
+ actor->special1.i = true; // has been initialized
+ }
+ }
+}
+
+
+//===========================================================================
+//
+// A_CheckFloor - Checks if an object hit the floor
+//
+//===========================================================================
+
+void A_CheckFloor(mobj_t * actor)
+{
+ if (actor->z <= actor->floorz)
+ {
+ actor->z = actor->floorz;
+ actor->flags2 &= ~MF2_LOGRAV;
+ P_SetMobjState(actor, actor->info->deathstate);
+ }
+}
+
+//============================================================================
+//
+// A_FreezeDeath
+//
+//============================================================================
+
+void A_FreezeDeath(mobj_t * actor)
+{
+ actor->tics = 75 + P_Random() + P_Random();
+ actor->flags |= MF_SOLID | MF_SHOOTABLE | MF_NOBLOOD;
+ actor->flags2 |= MF2_PUSHABLE | MF2_TELESTOMP | MF2_PASSMOBJ | MF2_SLIDE;
+ actor->height <<= 2;
+ S_StartSound(actor, SFX_FREEZE_DEATH);
+
+ if (actor->player)
+ {
+ actor->player->damagecount = 0;
+ actor->player->poisoncount = 0;
+ actor->player->bonuscount = 0;
+ if (actor->player == &players[consoleplayer])
+ {
+ SB_PaletteFlash(false);
+ }
+ }
+ else if (actor->flags & MF_COUNTKILL && actor->special)
+ { // Initiate monster death actions
+ P_ExecuteLineSpecial(actor->special, actor->args, NULL, 0, actor);
+ }
+}
+
+//============================================================================
+//
+// A_IceSetTics
+//
+//============================================================================
+
+void A_IceSetTics(mobj_t * actor)
+{
+ int floor;
+
+ actor->tics = 70 + (P_Random() & 63);
+ floor = P_GetThingFloorType(actor);
+ if (floor == FLOOR_LAVA)
+ {
+ actor->tics >>= 2;
+ }
+ else if (floor == FLOOR_ICE)
+ {
+ actor->tics <<= 1;
+ }
+}
+
+//============================================================================
+//
+// A_IceCheckHeadDone
+//
+//============================================================================
+
+void A_IceCheckHeadDone(mobj_t * actor)
+{
+ if (actor->special2.i == 666)
+ {
+ P_SetMobjState(actor, S_ICECHUNK_HEAD2);
+ }
+}
+
+//============================================================================
+//
+// A_FreezeDeathChunks
+//
+//============================================================================
+
+void A_FreezeDeathChunks(mobj_t * actor)
+{
+ int i;
+ mobj_t *mo;
+
+ if (actor->momx || actor->momy || actor->momz)
+ {
+ actor->tics = 105;
+ return;
+ }
+ S_StartSound(actor, SFX_FREEZE_SHATTER);
+
+ for (i = 12 + (P_Random() & 15); i >= 0; i--)
+ {
+ mo = P_SpawnMobj(actor->x +
+ (((P_Random() - 128) * actor->radius) >> 7),
+ actor->y +
+ (((P_Random() - 128) * actor->radius) >> 7),
+ actor->z + (P_Random() * actor->height / 255),
+ MT_ICECHUNK);
+ P_SetMobjState(mo, mo->info->spawnstate + (P_Random() % 3));
+ if (mo)
+ {
+ mo->momz = FixedDiv(mo->z - actor->z, actor->height) << 2;
+ mo->momx = (P_Random() - P_Random()) << (FRACBITS - 7);
+ mo->momy = (P_Random() - P_Random()) << (FRACBITS - 7);
+ A_IceSetTics(mo); // set a random tic wait
+ }
+ }
+ for (i = 12 + (P_Random() & 15); i >= 0; i--)
+ {
+ mo = P_SpawnMobj(actor->x +
+ (((P_Random() - 128) * actor->radius) >> 7),
+ actor->y +
+ (((P_Random() - 128) * actor->radius) >> 7),
+ actor->z + (P_Random() * actor->height / 255),
+ MT_ICECHUNK);
+ P_SetMobjState(mo, mo->info->spawnstate + (P_Random() % 3));
+ if (mo)
+ {
+ mo->momz = FixedDiv(mo->z - actor->z, actor->height) << 2;
+ mo->momx = (P_Random() - P_Random()) << (FRACBITS - 7);
+ mo->momy = (P_Random() - P_Random()) << (FRACBITS - 7);
+ A_IceSetTics(mo); // set a random tic wait
+ }
+ }
+ if (actor->player)
+ { // attach the player's view to a chunk of ice
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + VIEWHEIGHT,
+ MT_ICECHUNK);
+ P_SetMobjState(mo, S_ICECHUNK_HEAD);
+ mo->momz = FixedDiv(mo->z - actor->z, actor->height) << 2;
+ mo->momx = (P_Random() - P_Random()) << (FRACBITS - 7);
+ mo->momy = (P_Random() - P_Random()) << (FRACBITS - 7);
+ mo->flags2 |= MF2_ICEDAMAGE; // used to force blue palette
+ mo->flags2 &= ~MF2_FLOORCLIP;
+ mo->player = actor->player;
+ actor->player = NULL;
+ mo->health = actor->health;
+ mo->angle = actor->angle;
+ mo->player->mo = mo;
+ mo->player->lookdir = 0;
+ }
+ P_RemoveMobjFromTIDList(actor);
+ P_SetMobjState(actor, S_FREETARGMOBJ);
+ actor->flags2 |= MF2_DONTDRAW;
+}
+
+//===========================================================================
+// Korax Variables
+// special1 last teleport destination
+// special2 set if "below half" script not yet run
+//
+// Korax Scripts (reserved)
+// 249 Tell scripts that we are below half health
+// 250-254 Control scripts
+// 255 Death script
+//
+// Korax TIDs (reserved)
+// 245 Reserved for Korax himself
+// 248 Initial teleport destination
+// 249 Teleport destination
+// 250-254 For use in respective control scripts
+// 255 For use in death script (spawn spots)
+//===========================================================================
+#define KORAX_SPIRIT_LIFETIME (5*(35/5)) // 5 seconds
+#define KORAX_COMMAND_HEIGHT (120*FRACUNIT)
+#define KORAX_COMMAND_OFFSET (27*FRACUNIT)
+
+void KoraxFire1(mobj_t * actor, int type);
+void KoraxFire2(mobj_t * actor, int type);
+void KoraxFire3(mobj_t * actor, int type);
+void KoraxFire4(mobj_t * actor, int type);
+void KoraxFire5(mobj_t * actor, int type);
+void KoraxFire6(mobj_t * actor, int type);
+void KSpiritInit(mobj_t * spirit, mobj_t * korax);
+
+#define KORAX_TID (245)
+#define KORAX_FIRST_TELEPORT_TID (248)
+#define KORAX_TELEPORT_TID (249)
+
+void A_KoraxChase(mobj_t * actor)
+{
+ mobj_t *spot;
+ int lastfound;
+ byte args[3] = { 0, 0, 0 };
+
+ if ((!actor->special2.i) &&
+ (actor->health <= (actor->info->spawnhealth / 2)))
+ {
+ lastfound = 0;
+ spot = P_FindMobjFromTID(KORAX_FIRST_TELEPORT_TID, &lastfound);
+ if (spot)
+ {
+ P_Teleport(actor, spot->x, spot->y, spot->angle, true);
+ }
+
+ P_StartACS(249, 0, args, actor, NULL, 0);
+ actor->special2.i = 1; // Don't run again
+
+ return;
+ }
+
+ if (!actor->target)
+ return;
+ if (P_Random() < 30)
+ {
+ P_SetMobjState(actor, actor->info->missilestate);
+ }
+ else if (P_Random() < 30)
+ {
+ S_StartSound(NULL, SFX_KORAX_ACTIVE);
+ }
+
+ // Teleport away
+ if (actor->health < (actor->info->spawnhealth >> 1))
+ {
+ if (P_Random() < 10)
+ {
+ lastfound = actor->special1.i;
+ spot = P_FindMobjFromTID(KORAX_TELEPORT_TID, &lastfound);
+ actor->special1.i = lastfound;
+ if (spot)
+ {
+ P_Teleport(actor, spot->x, spot->y, spot->angle, true);
+ }
+ }
+ }
+}
+
+void A_KoraxStep(mobj_t * actor)
+{
+ A_Chase(actor);
+}
+
+void A_KoraxStep2(mobj_t * actor)
+{
+ S_StartSound(NULL, SFX_KORAX_STEP);
+ A_Chase(actor);
+}
+
+void A_KoraxBonePop(mobj_t * actor)
+{
+ mobj_t *mo;
+ byte args[5];
+
+ args[0] = args[1] = args[2] = args[3] = args[4] = 0;
+
+ // Spawn 6 spirits equalangularly
+ mo = P_SpawnMissileAngle(actor, MT_KORAX_SPIRIT1, ANG60 * 0,
+ 5 * FRACUNIT);
+ if (mo)
+ KSpiritInit(mo, actor);
+ mo = P_SpawnMissileAngle(actor, MT_KORAX_SPIRIT2, ANG60 * 1,
+ 5 * FRACUNIT);
+ if (mo)
+ KSpiritInit(mo, actor);
+ mo = P_SpawnMissileAngle(actor, MT_KORAX_SPIRIT3, ANG60 * 2,
+ 5 * FRACUNIT);
+ if (mo)
+ KSpiritInit(mo, actor);
+ mo = P_SpawnMissileAngle(actor, MT_KORAX_SPIRIT4, ANG60 * 3,
+ 5 * FRACUNIT);
+ if (mo)
+ KSpiritInit(mo, actor);
+ mo = P_SpawnMissileAngle(actor, MT_KORAX_SPIRIT5, ANG60 * 4,
+ 5 * FRACUNIT);
+ if (mo)
+ KSpiritInit(mo, actor);
+ mo = P_SpawnMissileAngle(actor, MT_KORAX_SPIRIT6, ANG60 * 5,
+ 5 * FRACUNIT);
+ if (mo)
+ KSpiritInit(mo, actor);
+
+ P_StartACS(255, 0, args, actor, NULL, 0); // Death script
+}
+
+void KSpiritInit(mobj_t * spirit, mobj_t * korax)
+{
+ int i;
+ mobj_t *tail, *next;
+
+ spirit->health = KORAX_SPIRIT_LIFETIME;
+
+ spirit->special1.m = korax; // Swarm around korax
+ spirit->special2.i = 32 + (P_Random() & 7); // Float bob index
+ spirit->args[0] = 10; // initial turn value
+ spirit->args[1] = 0; // initial look angle
+
+ // Spawn a tail for spirit
+ tail = P_SpawnMobj(spirit->x, spirit->y, spirit->z, MT_HOLY_TAIL);
+ tail->special2.m = spirit; // parent
+ for (i = 1; i < 3; i++)
+ {
+ next = P_SpawnMobj(spirit->x, spirit->y, spirit->z, MT_HOLY_TAIL);
+ P_SetMobjState(next, next->info->spawnstate + 1);
+ tail->special1.m = next;
+ tail = next;
+ }
+ tail->special1.m = NULL; // last tail bit
+}
+
+void A_KoraxDecide(mobj_t * actor)
+{
+ if (P_Random() < 220)
+ {
+ P_SetMobjState(actor, S_KORAX_MISSILE1);
+ }
+ else
+ {
+ P_SetMobjState(actor, S_KORAX_COMMAND1);
+ }
+}
+
+void A_KoraxMissile(mobj_t * actor)
+{
+ int type = P_Random() % 6;
+ int sound = 0;
+
+ S_StartSound(actor, SFX_KORAX_ATTACK);
+
+ switch (type)
+ {
+ case 0:
+ type = MT_WRAITHFX1;
+ sound = SFX_WRAITH_MISSILE_FIRE;
+ break;
+ case 1:
+ type = MT_DEMONFX1;
+ sound = SFX_DEMON_MISSILE_FIRE;
+ break;
+ case 2:
+ type = MT_DEMON2FX1;
+ sound = SFX_DEMON_MISSILE_FIRE;
+ break;
+ case 3:
+ type = MT_FIREDEMON_FX6;
+ sound = SFX_FIRED_ATTACK;
+ break;
+ case 4:
+ type = MT_CENTAUR_FX;
+ sound = SFX_CENTAURLEADER_ATTACK;
+ break;
+ case 5:
+ type = MT_SERPENTFX;
+ sound = SFX_CENTAURLEADER_ATTACK;
+ break;
+ }
+
+ // Fire all 6 missiles at once
+ S_StartSound(NULL, sound);
+ KoraxFire1(actor, type);
+ KoraxFire2(actor, type);
+ KoraxFire3(actor, type);
+ KoraxFire4(actor, type);
+ KoraxFire5(actor, type);
+ KoraxFire6(actor, type);
+}
+
+
+// Call action code scripts (250-254)
+void A_KoraxCommand(mobj_t * actor)
+{
+ byte args[5];
+ fixed_t x, y, z;
+ angle_t ang;
+ int numcommands;
+
+ S_StartSound(actor, SFX_KORAX_COMMAND);
+
+ // Shoot stream of lightning to ceiling
+ ang = (actor->angle - ANG90) >> ANGLETOFINESHIFT;
+ x = actor->x + FixedMul(KORAX_COMMAND_OFFSET, finecosine[ang]);
+ y = actor->y + FixedMul(KORAX_COMMAND_OFFSET, finesine[ang]);
+ z = actor->z + KORAX_COMMAND_HEIGHT;
+ P_SpawnMobj(x, y, z, MT_KORAX_BOLT);
+
+ args[0] = args[1] = args[2] = args[3] = args[4] = 0;
+
+ if (actor->health <= (actor->info->spawnhealth >> 1))
+ {
+ numcommands = 5;
+ }
+ else
+ {
+ numcommands = 4;
+ }
+
+ switch (P_Random() % numcommands)
+ {
+ case 0:
+ P_StartACS(250, 0, args, actor, NULL, 0);
+ break;
+ case 1:
+ P_StartACS(251, 0, args, actor, NULL, 0);
+ break;
+ case 2:
+ P_StartACS(252, 0, args, actor, NULL, 0);
+ break;
+ case 3:
+ P_StartACS(253, 0, args, actor, NULL, 0);
+ break;
+ case 4:
+ P_StartACS(254, 0, args, actor, NULL, 0);
+ break;
+ }
+}
+
+
+#define KORAX_DELTAANGLE (85*ANG1)
+#define KORAX_ARM_EXTENSION_SHORT (40*FRACUNIT)
+#define KORAX_ARM_EXTENSION_LONG (55*FRACUNIT)
+
+#define KORAX_ARM1_HEIGHT (108*FRACUNIT)
+#define KORAX_ARM2_HEIGHT (82*FRACUNIT)
+#define KORAX_ARM3_HEIGHT (54*FRACUNIT)
+#define KORAX_ARM4_HEIGHT (104*FRACUNIT)
+#define KORAX_ARM5_HEIGHT (86*FRACUNIT)
+#define KORAX_ARM6_HEIGHT (53*FRACUNIT)
+
+
+// Arm projectiles
+// arm positions numbered:
+// 1 top left
+// 2 middle left
+// 3 lower left
+// 4 top right
+// 5 middle right
+// 6 lower right
+
+
+// Arm 1 projectile
+void KoraxFire1(mobj_t * actor, int type)
+{
+ angle_t ang;
+ fixed_t x, y, z;
+
+ ang = (actor->angle - KORAX_DELTAANGLE) >> ANGLETOFINESHIFT;
+ x = actor->x + FixedMul(KORAX_ARM_EXTENSION_SHORT, finecosine[ang]);
+ y = actor->y + FixedMul(KORAX_ARM_EXTENSION_SHORT, finesine[ang]);
+ z = actor->z - actor->floorclip + KORAX_ARM1_HEIGHT;
+ P_SpawnKoraxMissile(x, y, z, actor, actor->target, type);
+}
+
+
+// Arm 2 projectile
+void KoraxFire2(mobj_t * actor, int type)
+{
+ angle_t ang;
+ fixed_t x, y, z;
+
+ ang = (actor->angle - KORAX_DELTAANGLE) >> ANGLETOFINESHIFT;
+ x = actor->x + FixedMul(KORAX_ARM_EXTENSION_LONG, finecosine[ang]);
+ y = actor->y + FixedMul(KORAX_ARM_EXTENSION_LONG, finesine[ang]);
+ z = actor->z - actor->floorclip + KORAX_ARM2_HEIGHT;
+ P_SpawnKoraxMissile(x, y, z, actor, actor->target, type);
+}
+
+// Arm 3 projectile
+void KoraxFire3(mobj_t * actor, int type)
+{
+ angle_t ang;
+ fixed_t x, y, z;
+
+ ang = (actor->angle - KORAX_DELTAANGLE) >> ANGLETOFINESHIFT;
+ x = actor->x + FixedMul(KORAX_ARM_EXTENSION_LONG, finecosine[ang]);
+ y = actor->y + FixedMul(KORAX_ARM_EXTENSION_LONG, finesine[ang]);
+ z = actor->z - actor->floorclip + KORAX_ARM3_HEIGHT;
+ P_SpawnKoraxMissile(x, y, z, actor, actor->target, type);
+}
+
+// Arm 4 projectile
+void KoraxFire4(mobj_t * actor, int type)
+{
+ angle_t ang;
+ fixed_t x, y, z;
+
+ ang = (actor->angle + KORAX_DELTAANGLE) >> ANGLETOFINESHIFT;
+ x = actor->x + FixedMul(KORAX_ARM_EXTENSION_SHORT, finecosine[ang]);
+ y = actor->y + FixedMul(KORAX_ARM_EXTENSION_SHORT, finesine[ang]);
+ z = actor->z - actor->floorclip + KORAX_ARM4_HEIGHT;
+ P_SpawnKoraxMissile(x, y, z, actor, actor->target, type);
+}
+
+// Arm 5 projectile
+void KoraxFire5(mobj_t * actor, int type)
+{
+ angle_t ang;
+ fixed_t x, y, z;
+
+ ang = (actor->angle + KORAX_DELTAANGLE) >> ANGLETOFINESHIFT;
+ x = actor->x + FixedMul(KORAX_ARM_EXTENSION_LONG, finecosine[ang]);
+ y = actor->y + FixedMul(KORAX_ARM_EXTENSION_LONG, finesine[ang]);
+ z = actor->z - actor->floorclip + KORAX_ARM5_HEIGHT;
+ P_SpawnKoraxMissile(x, y, z, actor, actor->target, type);
+}
+
+// Arm 6 projectile
+void KoraxFire6(mobj_t * actor, int type)
+{
+ angle_t ang;
+ fixed_t x, y, z;
+
+ ang = (actor->angle + KORAX_DELTAANGLE) >> ANGLETOFINESHIFT;
+ x = actor->x + FixedMul(KORAX_ARM_EXTENSION_LONG, finecosine[ang]);
+ y = actor->y + FixedMul(KORAX_ARM_EXTENSION_LONG, finesine[ang]);
+ z = actor->z - actor->floorclip + KORAX_ARM6_HEIGHT;
+ P_SpawnKoraxMissile(x, y, z, actor, actor->target, type);
+}
+
+
+void A_KSpiritWeave(mobj_t * actor)
+{
+ fixed_t newX, newY;
+ int weaveXY, weaveZ;
+ int angle;
+
+ weaveXY = actor->special2.i >> 16;
+ weaveZ = actor->special2.i & 0xFFFF;
+ angle = (actor->angle + ANG90) >> ANGLETOFINESHIFT;
+ newX = actor->x - FixedMul(finecosine[angle],
+ FloatBobOffsets[weaveXY] << 2);
+ newY = actor->y - FixedMul(finesine[angle],
+ FloatBobOffsets[weaveXY] << 2);
+ weaveXY = (weaveXY + (P_Random() % 5)) & 63;
+ newX += FixedMul(finecosine[angle], FloatBobOffsets[weaveXY] << 2);
+ newY += FixedMul(finesine[angle], FloatBobOffsets[weaveXY] << 2);
+ P_TryMove(actor, newX, newY);
+ actor->z -= FloatBobOffsets[weaveZ] << 1;
+ weaveZ = (weaveZ + (P_Random() % 5)) & 63;
+ actor->z += FloatBobOffsets[weaveZ] << 1;
+ actor->special2.i = weaveZ + (weaveXY << 16);
+}
+
+void A_KSpiritSeeker(mobj_t * actor, angle_t thresh, angle_t turnMax)
+{
+ int dir;
+ int dist;
+ angle_t delta;
+ angle_t angle;
+ mobj_t *target;
+ fixed_t newZ;
+ fixed_t deltaZ;
+
+ target = actor->special1.m;
+ if (target == NULL)
+ {
+ return;
+ }
+ dir = P_FaceMobj(actor, target, &delta);
+ if (delta > thresh)
+ {
+ delta >>= 1;
+ if (delta > turnMax)
+ {
+ delta = turnMax;
+ }
+ }
+ if (dir)
+ { // Turn clockwise
+ actor->angle += delta;
+ }
+ else
+ { // Turn counter clockwise
+ actor->angle -= delta;
+ }
+ angle = actor->angle >> ANGLETOFINESHIFT;
+ actor->momx = FixedMul(actor->info->speed, finecosine[angle]);
+ actor->momy = FixedMul(actor->info->speed, finesine[angle]);
+
+ if (!(leveltime & 15)
+ || actor->z > target->z + (target->info->height)
+ || actor->z + actor->height < target->z)
+ {
+ newZ = target->z + ((P_Random() * target->info->height) >> 8);
+ deltaZ = newZ - actor->z;
+ if (abs(deltaZ) > 15 * FRACUNIT)
+ {
+ if (deltaZ > 0)
+ {
+ deltaZ = 15 * FRACUNIT;
+ }
+ else
+ {
+ deltaZ = -15 * FRACUNIT;
+ }
+ }
+ dist = P_AproxDistance(target->x - actor->x, target->y - actor->y);
+ dist = dist / actor->info->speed;
+ if (dist < 1)
+ {
+ dist = 1;
+ }
+ actor->momz = deltaZ / dist;
+ }
+ return;
+}
+
+
+void A_KSpiritRoam(mobj_t * actor)
+{
+ if (actor->health-- <= 0)
+ {
+ S_StartSound(actor, SFX_SPIRIT_DIE);
+ P_SetMobjState(actor, S_KSPIRIT_DEATH1);
+ }
+ else
+ {
+ if (actor->special1.m)
+ {
+ A_KSpiritSeeker(actor, actor->args[0] * ANG1,
+ actor->args[0] * ANG1 * 2);
+ }
+ A_KSpiritWeave(actor);
+ if (P_Random() < 50)
+ {
+ S_StartSound(NULL, SFX_SPIRIT_ACTIVE);
+ }
+ }
+}
+
+void A_KBolt(mobj_t * actor)
+{
+ // Countdown lifetime
+ if (actor->special1.i-- <= 0)
+ {
+ P_SetMobjState(actor, S_NULL);
+ }
+}
+
+
+#define KORAX_BOLT_HEIGHT 48*FRACUNIT
+#define KORAX_BOLT_LIFETIME 3
+
+void A_KBoltRaise(mobj_t * actor)
+{
+ mobj_t *mo;
+ fixed_t z;
+
+ // Spawn a child upward
+ z = actor->z + KORAX_BOLT_HEIGHT;
+
+ if ((z + KORAX_BOLT_HEIGHT) < actor->ceilingz)
+ {
+ mo = P_SpawnMobj(actor->x, actor->y, z, MT_KORAX_BOLT);
+ if (mo)
+ {
+ mo->special1.i = KORAX_BOLT_LIFETIME;
+ }
+ }
+ else
+ {
+ // Maybe cap it off here
+ }
+}
diff --git a/src/hexen/p_floor.c b/src/hexen/p_floor.c
new file mode 100644
index 00000000..40f9b934
--- /dev/null
+++ b/src/hexen/p_floor.c
@@ -0,0 +1,952 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#include "h2def.h"
+#include "i_system.h"
+#include "p_local.h"
+
+extern fixed_t FloatBobOffsets[64];
+
+//==================================================================
+//==================================================================
+//
+// FLOORS
+//
+//==================================================================
+//==================================================================
+
+//==================================================================
+//
+// Move a plane (floor or ceiling) and check for crushing
+//
+//==================================================================
+result_e T_MovePlane(sector_t * sector, fixed_t speed,
+ fixed_t dest, int crush, int floorOrCeiling,
+ int direction)
+{
+ 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 RES_CRUSHED;
+ }
+ return RES_PASTDEST;
+ }
+ else
+ {
+ lastpos = sector->floorheight;
+ sector->floorheight -= speed;
+ flag = P_ChangeSector(sector, crush);
+ if (flag == true)
+ {
+ sector->floorheight = lastpos;
+ P_ChangeSector(sector, crush);
+ return RES_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 RES_CRUSHED;
+ }
+ return RES_PASTDEST;
+ }
+ else // COULD GET CRUSHED
+ {
+ lastpos = sector->floorheight;
+ sector->floorheight += speed;
+ flag = P_ChangeSector(sector, crush);
+ if (flag == true)
+ {
+ //if (crush == true)
+ //{
+ // return RES_CRUSHED;
+ //}
+ sector->floorheight = lastpos;
+ P_ChangeSector(sector, crush);
+ return RES_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 RES_CRUSHED;
+ }
+ return RES_PASTDEST;
+ }
+ else // COULD GET CRUSHED
+ {
+ lastpos = sector->ceilingheight;
+ sector->ceilingheight -= speed;
+ flag = P_ChangeSector(sector, crush);
+ if (flag == true)
+ {
+ //if (crush == true)
+ //{
+ // return RES_CRUSHED;
+ //}
+ sector->ceilingheight = lastpos;
+ P_ChangeSector(sector, crush);
+ return RES_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 RES_CRUSHED;
+ }
+ return RES_PASTDEST;
+ }
+ else
+ {
+ lastpos = sector->ceilingheight;
+ sector->ceilingheight += speed;
+ flag = P_ChangeSector(sector, crush);
+#if 0
+ if (flag == true)
+ {
+ sector->ceilingheight = lastpos;
+ P_ChangeSector(sector, crush);
+ return RES_CRUSHED;
+ }
+#endif
+ }
+ break;
+ }
+ break;
+
+ }
+ return RES_OK;
+}
+
+//==================================================================
+//
+// MOVE A FLOOR TO IT'S DESTINATION (UP OR DOWN)
+//
+//==================================================================
+void T_MoveFloor(floormove_t * floor)
+{
+ result_e res;
+
+ if (floor->resetDelayCount)
+ {
+ floor->resetDelayCount--;
+ if (!floor->resetDelayCount)
+ {
+ floor->floordestheight = floor->resetHeight;
+ floor->direction = -floor->direction;
+ floor->resetDelay = 0;
+ floor->delayCount = 0;
+ floor->delayTotal = 0;
+ }
+ }
+ if (floor->delayCount)
+ {
+ floor->delayCount--;
+ if (!floor->delayCount && floor->textureChange)
+ {
+ floor->sector->floorpic += floor->textureChange;
+ }
+ return;
+ }
+
+ res = T_MovePlane(floor->sector, floor->speed,
+ floor->floordestheight, floor->crush, 0,
+ floor->direction);
+
+ if (floor->type == FLEV_RAISEBUILDSTEP)
+ {
+ if ((floor->direction == 1 && floor->sector->floorheight >=
+ floor->stairsDelayHeight) || (floor->direction == -1 &&
+ floor->sector->floorheight <=
+ floor->stairsDelayHeight))
+ {
+ floor->delayCount = floor->delayTotal;
+ floor->stairsDelayHeight += floor->stairsDelayHeightDelta;
+ }
+ }
+ if (res == RES_PASTDEST)
+ {
+ SN_StopSequence((mobj_t *) & floor->sector->soundorg);
+ if (floor->delayTotal)
+ {
+ floor->delayTotal = 0;
+ }
+ if (floor->resetDelay)
+ {
+// floor->resetDelayCount = floor->resetDelay;
+// floor->resetDelay = 0;
+ return;
+ }
+ floor->sector->specialdata = NULL;
+ /*
+ 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;
+ }
+ */
+ if (floor->textureChange)
+ {
+ floor->sector->floorpic -= floor->textureChange;
+ }
+ P_TagFinished(floor->sector->tag);
+ P_RemoveThinker(&floor->thinker);
+ }
+}
+
+//==================================================================
+//
+// HANDLE FLOOR TYPES
+//
+//==================================================================
+int EV_DoFloor(line_t * line, byte * args, floor_e floortype)
+{
+ int secnum;
+ int rtn;
+ sector_t *sec;
+ floormove_t *floor = NULL;
+
+ secnum = -1;
+ rtn = 0;
+ while ((secnum = P_FindSectorFromTag(args[0], 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);
+ memset(floor, 0, sizeof(*floor));
+ P_AddThinker(&floor->thinker);
+ sec->specialdata = floor;
+ floor->thinker.function = T_MoveFloor;
+ floor->type = floortype;
+ floor->crush = 0;
+ floor->speed = args[1] * (FRACUNIT / 8);
+ if (floortype == FLEV_LOWERTIMES8INSTANT ||
+ floortype == FLEV_RAISETIMES8INSTANT)
+ {
+ floor->speed = 2000 << FRACBITS;
+ }
+ switch (floortype)
+ {
+ case FLEV_LOWERFLOOR:
+ floor->direction = -1;
+ floor->sector = sec;
+ floor->floordestheight = P_FindHighestFloorSurrounding(sec);
+ break;
+ case FLEV_LOWERFLOORTOLOWEST:
+ floor->direction = -1;
+ floor->sector = sec;
+ floor->floordestheight = P_FindLowestFloorSurrounding(sec);
+ break;
+ case FLEV_LOWERFLOORBYVALUE:
+ floor->direction = -1;
+ floor->sector = sec;
+ floor->floordestheight = floor->sector->floorheight -
+ args[2] * FRACUNIT;
+ break;
+ case FLEV_LOWERTIMES8INSTANT:
+ case FLEV_LOWERBYVALUETIMES8:
+ floor->direction = -1;
+ floor->sector = sec;
+ floor->floordestheight = floor->sector->floorheight -
+ args[2] * FRACUNIT * 8;
+ break;
+ case FLEV_RAISEFLOORCRUSH:
+ floor->crush = args[2]; // arg[2] = crushing value
+ floor->direction = 1;
+ floor->sector = sec;
+ floor->floordestheight = sec->ceilingheight - 8 * FRACUNIT;
+ break;
+ case FLEV_RAISEFLOOR:
+ floor->direction = 1;
+ floor->sector = sec;
+ floor->floordestheight = P_FindLowestCeilingSurrounding(sec);
+ if (floor->floordestheight > sec->ceilingheight)
+ floor->floordestheight = sec->ceilingheight;
+ break;
+ case FLEV_RAISEFLOORTONEAREST:
+ floor->direction = 1;
+ floor->sector = sec;
+ floor->floordestheight =
+ P_FindNextHighestFloor(sec, sec->floorheight);
+ break;
+ case FLEV_RAISEFLOORBYVALUE:
+ floor->direction = 1;
+ floor->sector = sec;
+ floor->floordestheight = floor->sector->floorheight +
+ args[2] * FRACUNIT;
+ break;
+ case FLEV_RAISETIMES8INSTANT:
+ case FLEV_RAISEBYVALUETIMES8:
+ floor->direction = 1;
+ floor->sector = sec;
+ floor->floordestheight = floor->sector->floorheight +
+ args[2] * FRACUNIT * 8;
+ break;
+ case FLEV_MOVETOVALUETIMES8:
+ floor->sector = sec;
+ floor->floordestheight = args[2] * FRACUNIT * 8;
+ if (args[3])
+ {
+ floor->floordestheight = -floor->floordestheight;
+ }
+ if (floor->floordestheight > floor->sector->floorheight)
+ {
+ floor->direction = 1;
+ }
+ else if (floor->floordestheight < floor->sector->floorheight)
+ {
+ floor->direction = -1;
+ }
+ else
+ { // already at lowest position
+ rtn = 0;
+ }
+ break;
+ default:
+ rtn = 0;
+ break;
+ }
+ }
+ if (rtn)
+ {
+ SN_StartSequence((mobj_t *) & floor->sector->soundorg,
+ SEQ_PLATFORM + floor->sector->seqType);
+ }
+ return rtn;
+}
+
+//============================================================================
+//
+// EV_DoFloorAndCeiling
+//
+//============================================================================
+
+int EV_DoFloorAndCeiling(line_t * line, byte * args, boolean raise)
+{
+ boolean floor, ceiling;
+ int secnum;
+ sector_t *sec;
+
+ if (raise)
+ {
+ floor = EV_DoFloor(line, args, FLEV_RAISEFLOORBYVALUE);
+ secnum = -1;
+ while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+ {
+ sec = &sectors[secnum];
+ sec->specialdata = NULL;
+ }
+ ceiling = EV_DoCeiling(line, args, CLEV_RAISEBYVALUE);
+ }
+ else
+ {
+ floor = EV_DoFloor(line, args, FLEV_LOWERFLOORBYVALUE);
+ secnum = -1;
+ while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+ {
+ sec = &sectors[secnum];
+ sec->specialdata = NULL;
+ }
+ ceiling = EV_DoCeiling(line, args, CLEV_LOWERBYVALUE);
+ }
+ return (floor | ceiling);
+}
+
+// ===== Build Stairs Private Data =====
+
+#define STAIR_SECTOR_TYPE 26
+#define STAIR_QUEUE_SIZE 32
+
+struct
+{
+ sector_t *sector;
+ int type;
+ int height;
+} StairQueue[STAIR_QUEUE_SIZE];
+
+static int QueueHead;
+static int QueueTail;
+
+static int StepDelta;
+static int Direction;
+static int Speed;
+static int Texture;
+static int StartDelay;
+static int StartDelayDelta;
+static int TextureChange;
+static int StartHeight;
+
+//==========================================================================
+//
+// QueueStairSector
+//
+//==========================================================================
+
+static void QueueStairSector(sector_t * sec, int type, int height)
+{
+ if ((QueueTail + 1) % STAIR_QUEUE_SIZE == QueueHead)
+ {
+ I_Error("BuildStairs: Too many branches located.\n");
+ }
+ StairQueue[QueueTail].sector = sec;
+ StairQueue[QueueTail].type = type;
+ StairQueue[QueueTail].height = height;
+
+ QueueTail = (QueueTail + 1) % STAIR_QUEUE_SIZE;
+}
+
+//==========================================================================
+//
+// DequeueStairSector
+//
+//==========================================================================
+
+static sector_t *DequeueStairSector(int *type, int *height)
+{
+ sector_t *sec;
+
+ if (QueueHead == QueueTail)
+ { // queue is empty
+ return NULL;
+ }
+ *type = StairQueue[QueueHead].type;
+ *height = StairQueue[QueueHead].height;
+ sec = StairQueue[QueueHead].sector;
+ QueueHead = (QueueHead + 1) % STAIR_QUEUE_SIZE;
+
+ return sec;
+}
+
+//==========================================================================
+//
+// ProcessStairSector
+//
+//==========================================================================
+
+static void ProcessStairSector(sector_t * sec, int type, int height,
+ stairs_e stairsType, int delay, int resetDelay)
+{
+ int i;
+ sector_t *tsec;
+ floormove_t *floor;
+
+ //
+ // new floor thinker
+ //
+ height += StepDelta;
+ floor = Z_Malloc(sizeof(*floor), PU_LEVSPEC, 0);
+ memset(floor, 0, sizeof(*floor));
+ P_AddThinker(&floor->thinker);
+ sec->specialdata = floor;
+ floor->thinker.function = T_MoveFloor;
+ floor->type = FLEV_RAISEBUILDSTEP;
+ floor->direction = Direction;
+ floor->sector = sec;
+ floor->floordestheight = height;
+ switch (stairsType)
+ {
+ case STAIRS_NORMAL:
+ floor->speed = Speed;
+ if (delay)
+ {
+ floor->delayTotal = delay;
+ floor->stairsDelayHeight = sec->floorheight + StepDelta;
+ floor->stairsDelayHeightDelta = StepDelta;
+ }
+ floor->resetDelay = resetDelay;
+ floor->resetDelayCount = resetDelay;
+ floor->resetHeight = sec->floorheight;
+ break;
+ case STAIRS_SYNC:
+ floor->speed = FixedMul(Speed, FixedDiv(height - StartHeight,
+ StepDelta));
+ floor->resetDelay = delay; //arg4
+ floor->resetDelayCount = delay;
+ floor->resetHeight = sec->floorheight;
+ break;
+/*
+ case STAIRS_PHASED:
+ floor->floordestheight = sec->floorheight+StepDelta;
+ floor->speed = Speed;
+ floor->delayCount = StartDelay;
+ StartDelay += StartDelayDelta;
+ floor->textureChange = TextureChange;
+ floor->resetDelayCount = StartDelay;
+ break;
+*/
+ default:
+ break;
+ }
+ SN_StartSequence((mobj_t *) & sec->soundorg, SEQ_PLATFORM + sec->seqType);
+ //
+ // Find next sector to raise
+ // Find nearby sector with sector special equal to type
+ //
+ for (i = 0; i < sec->linecount; i++)
+ {
+ if (!((sec->lines[i])->flags & ML_TWOSIDED))
+ {
+ continue;
+ }
+ tsec = (sec->lines[i])->frontsector;
+ if (tsec->special == type + STAIR_SECTOR_TYPE && !tsec->specialdata
+ && tsec->floorpic == Texture && tsec->validcount != validcount)
+ {
+ QueueStairSector(tsec, type ^ 1, height);
+ tsec->validcount = validcount;
+ //tsec->special = 0;
+ }
+ tsec = (sec->lines[i])->backsector;
+ if (tsec->special == type + STAIR_SECTOR_TYPE && !tsec->specialdata
+ && tsec->floorpic == Texture && tsec->validcount != validcount)
+ {
+ QueueStairSector(tsec, type ^ 1, height);
+ tsec->validcount = validcount;
+ //tsec->special = 0;
+ }
+ }
+}
+
+//==================================================================
+//
+// BUILD A STAIRCASE!
+//
+// Direction is either positive or negative, denoting build stairs
+// up or down.
+//==================================================================
+
+int EV_BuildStairs(line_t * line, byte * args, int direction,
+ stairs_e stairsType)
+{
+ int secnum;
+ int height;
+ int delay;
+ int resetDelay;
+ sector_t *sec;
+ sector_t *qSec;
+ int type;
+
+ // Set global stairs variables
+ TextureChange = 0;
+ Direction = direction;
+ StepDelta = Direction * (args[2] * FRACUNIT);
+ Speed = args[1] * (FRACUNIT / 8);
+ resetDelay = args[4];
+ delay = args[3];
+ if (stairsType == STAIRS_PHASED)
+ {
+ StartDelayDelta = args[3];
+ StartDelay = StartDelayDelta;
+ resetDelay = StartDelayDelta;
+ delay = 0;
+ TextureChange = args[4];
+ }
+
+ secnum = -1;
+
+ validcount++;
+ while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+ {
+ sec = &sectors[secnum];
+
+ Texture = sec->floorpic;
+ StartHeight = sec->floorheight;
+
+ // ALREADY MOVING? IF SO, KEEP GOING...
+ if (sec->specialdata)
+ continue;
+
+ QueueStairSector(sec, 0, sec->floorheight);
+ sec->special = 0;
+ }
+ while ((qSec = DequeueStairSector(&type, &height)) != NULL)
+ {
+ ProcessStairSector(qSec, type, height, stairsType, delay, resetDelay);
+ }
+ return (1);
+}
+
+//=========================================================================
+//
+// T_BuildPillar
+//
+//=========================================================================
+
+void T_BuildPillar(pillar_t * pillar)
+{
+ result_e res1;
+ result_e res2;
+
+ // First, raise the floor
+ res1 = T_MovePlane(pillar->sector, pillar->floorSpeed, pillar->floordest, pillar->crush, 0, pillar->direction); // floorOrCeiling, direction
+ // Then, lower the ceiling
+ res2 = T_MovePlane(pillar->sector, pillar->ceilingSpeed,
+ pillar->ceilingdest, pillar->crush, 1,
+ -pillar->direction);
+ if (res1 == RES_PASTDEST && res2 == RES_PASTDEST)
+ {
+ pillar->sector->specialdata = NULL;
+ SN_StopSequence((mobj_t *) & pillar->sector->soundorg);
+ P_TagFinished(pillar->sector->tag);
+ P_RemoveThinker(&pillar->thinker);
+ }
+}
+
+//=========================================================================
+//
+// EV_BuildPillar
+//
+//=========================================================================
+
+int EV_BuildPillar(line_t * line, byte * args, boolean crush)
+{
+ int secnum;
+ sector_t *sec;
+ pillar_t *pillar;
+ int newHeight;
+ int rtn;
+
+ rtn = 0;
+ secnum = -1;
+ while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+ {
+ sec = &sectors[secnum];
+ if (sec->specialdata)
+ continue; // already moving
+ if (sec->floorheight == sec->ceilingheight)
+ { // pillar is already closed
+ continue;
+ }
+ rtn = 1;
+ if (!args[2])
+ {
+ newHeight = sec->floorheight +
+ ((sec->ceilingheight - sec->floorheight) / 2);
+ }
+ else
+ {
+ newHeight = sec->floorheight + (args[2] << FRACBITS);
+ }
+
+ pillar = Z_Malloc(sizeof(*pillar), PU_LEVSPEC, 0);
+ sec->specialdata = pillar;
+ P_AddThinker(&pillar->thinker);
+ pillar->thinker.function = T_BuildPillar;
+ pillar->sector = sec;
+ if (!args[2])
+ {
+ pillar->ceilingSpeed = pillar->floorSpeed =
+ args[1] * (FRACUNIT / 8);
+ }
+ else if (newHeight - sec->floorheight >
+ sec->ceilingheight - newHeight)
+ {
+ pillar->floorSpeed = args[1] * (FRACUNIT / 8);
+ pillar->ceilingSpeed = FixedMul(sec->ceilingheight - newHeight,
+ FixedDiv(pillar->floorSpeed,
+ newHeight -
+ sec->floorheight));
+ }
+ else
+ {
+ pillar->ceilingSpeed = args[1] * (FRACUNIT / 8);
+ pillar->floorSpeed = FixedMul(newHeight - sec->floorheight,
+ FixedDiv(pillar->ceilingSpeed,
+ sec->ceilingheight -
+ newHeight));
+ }
+ pillar->floordest = newHeight;
+ pillar->ceilingdest = newHeight;
+ pillar->direction = 1;
+ pillar->crush = crush * args[3];
+ SN_StartSequence((mobj_t *) & pillar->sector->soundorg,
+ SEQ_PLATFORM + pillar->sector->seqType);
+ }
+ return rtn;
+}
+
+//=========================================================================
+//
+// EV_OpenPillar
+//
+//=========================================================================
+
+int EV_OpenPillar(line_t * line, byte * args)
+{
+ int secnum;
+ sector_t *sec;
+ pillar_t *pillar;
+ int rtn;
+
+ rtn = 0;
+ secnum = -1;
+ while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+ {
+ sec = &sectors[secnum];
+ if (sec->specialdata)
+ continue; // already moving
+ if (sec->floorheight != sec->ceilingheight)
+ { // pillar isn't closed
+ continue;
+ }
+ rtn = 1;
+ pillar = Z_Malloc(sizeof(*pillar), PU_LEVSPEC, 0);
+ sec->specialdata = pillar;
+ P_AddThinker(&pillar->thinker);
+ pillar->thinker.function = T_BuildPillar;
+ pillar->sector = sec;
+ if (!args[2])
+ {
+ pillar->floordest = P_FindLowestFloorSurrounding(sec);
+ }
+ else
+ {
+ pillar->floordest = sec->floorheight - (args[2] << FRACBITS);
+ }
+ if (!args[3])
+ {
+ pillar->ceilingdest = P_FindHighestCeilingSurrounding(sec);
+ }
+ else
+ {
+ pillar->ceilingdest = sec->ceilingheight + (args[3] << FRACBITS);
+ }
+ if (sec->floorheight - pillar->floordest >= pillar->ceilingdest -
+ sec->ceilingheight)
+ {
+ pillar->floorSpeed = args[1] * (FRACUNIT / 8);
+ pillar->ceilingSpeed = FixedMul(sec->ceilingheight -
+ pillar->ceilingdest,
+ FixedDiv(pillar->floorSpeed,
+ pillar->floordest -
+ sec->floorheight));
+ }
+ else
+ {
+ pillar->ceilingSpeed = args[1] * (FRACUNIT / 8);
+ pillar->floorSpeed =
+ FixedMul(pillar->floordest - sec->floorheight,
+ FixedDiv(pillar->ceilingSpeed,
+ sec->ceilingheight - pillar->ceilingdest));
+ }
+ pillar->direction = -1; // open the pillar
+ SN_StartSequence((mobj_t *) & pillar->sector->soundorg,
+ SEQ_PLATFORM + pillar->sector->seqType);
+ }
+ return rtn;
+}
+
+//=========================================================================
+//
+// EV_FloorCrushStop
+//
+//=========================================================================
+
+int EV_FloorCrushStop(line_t * line, byte * args)
+{
+ thinker_t *think;
+ floormove_t *floor;
+ boolean rtn;
+
+ rtn = 0;
+ for (think = thinkercap.next; think != &thinkercap; think = think->next)
+ {
+ if (think->function != T_MoveFloor)
+ {
+ continue;
+ }
+ floor = (floormove_t *) think;
+ if (floor->type != FLEV_RAISEFLOORCRUSH)
+ {
+ continue;
+ }
+ // Completely remove the crushing floor
+ SN_StopSequence((mobj_t *) & floor->sector->soundorg);
+ floor->sector->specialdata = NULL;
+ P_TagFinished(floor->sector->tag);
+ P_RemoveThinker(&floor->thinker);
+ rtn = 1;
+ }
+ return rtn;
+}
+
+//==========================================================================
+//
+// T_FloorWaggle
+//
+//==========================================================================
+
+#define WGLSTATE_EXPAND 1
+#define WGLSTATE_STABLE 2
+#define WGLSTATE_REDUCE 3
+
+void T_FloorWaggle(floorWaggle_t * waggle)
+{
+ switch (waggle->state)
+ {
+ case WGLSTATE_EXPAND:
+ if ((waggle->scale += waggle->scaleDelta) >= waggle->targetScale)
+ {
+ waggle->scale = waggle->targetScale;
+ waggle->state = WGLSTATE_STABLE;
+ }
+ break;
+ case WGLSTATE_REDUCE:
+ if ((waggle->scale -= waggle->scaleDelta) <= 0)
+ { // Remove
+ waggle->sector->floorheight = waggle->originalHeight;
+ P_ChangeSector(waggle->sector, true);
+ waggle->sector->specialdata = NULL;
+ P_TagFinished(waggle->sector->tag);
+ P_RemoveThinker(&waggle->thinker);
+ return;
+ }
+ break;
+ case WGLSTATE_STABLE:
+ if (waggle->ticker != -1)
+ {
+ if (!--waggle->ticker)
+ {
+ waggle->state = WGLSTATE_REDUCE;
+ }
+ }
+ break;
+ }
+ waggle->accumulator += waggle->accDelta;
+ waggle->sector->floorheight = waggle->originalHeight
+ + FixedMul(FloatBobOffsets[(waggle->accumulator >> FRACBITS) & 63],
+ waggle->scale);
+ P_ChangeSector(waggle->sector, true);
+}
+
+//==========================================================================
+//
+// EV_StartFloorWaggle
+//
+//==========================================================================
+
+boolean EV_StartFloorWaggle(int tag, int height, int speed, int offset,
+ int timer)
+{
+ int sectorIndex;
+ sector_t *sector;
+ floorWaggle_t *waggle;
+ boolean retCode;
+
+ retCode = false;
+ sectorIndex = -1;
+ while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
+ {
+ sector = &sectors[sectorIndex];
+ if (sector->specialdata)
+ { // Already busy with another thinker
+ continue;
+ }
+ retCode = true;
+ waggle = Z_Malloc(sizeof(*waggle), PU_LEVSPEC, 0);
+ sector->specialdata = waggle;
+ waggle->thinker.function = T_FloorWaggle;
+ waggle->sector = sector;
+ waggle->originalHeight = sector->floorheight;
+ waggle->accumulator = offset * FRACUNIT;
+ waggle->accDelta = speed << 10;
+ waggle->scale = 0;
+ waggle->targetScale = height << 10;
+ waggle->scaleDelta = waggle->targetScale
+ / (35 + ((3 * 35) * height) / 255);
+ waggle->ticker = timer ? timer * 35 : -1;
+ waggle->state = WGLSTATE_EXPAND;
+ P_AddThinker(&waggle->thinker);
+ }
+ return retCode;
+}
diff --git a/src/hexen/p_inter.c b/src/hexen/p_inter.c
new file mode 100644
index 00000000..9e196c79
--- /dev/null
+++ b/src/hexen/p_inter.c
@@ -0,0 +1,2250 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#include "h2def.h"
+#include "m_random.h"
+#include "i_system.h"
+#include "p_local.h"
+#include "s_sound.h"
+
+#define BONUSADD 6
+
+int ArmorIncrement[NUMCLASSES][NUMARMOR] = {
+ {25 * FRACUNIT, 20 * FRACUNIT, 15 * FRACUNIT, 5 * FRACUNIT},
+ {10 * FRACUNIT, 25 * FRACUNIT, 5 * FRACUNIT, 20 * FRACUNIT},
+ {5 * FRACUNIT, 15 * FRACUNIT, 10 * FRACUNIT, 25 * FRACUNIT},
+ {0, 0, 0, 0}
+};
+
+int AutoArmorSave[NUMCLASSES] =
+ { 15 * FRACUNIT, 10 * FRACUNIT, 5 * FRACUNIT, 0 };
+
+char *TextKeyMessages[] = {
+ TXT_KEY_STEEL,
+ TXT_KEY_CAVE,
+ TXT_KEY_AXE,
+ TXT_KEY_FIRE,
+ TXT_KEY_EMERALD,
+ TXT_KEY_DUNGEON,
+ TXT_KEY_SILVER,
+ TXT_KEY_RUSTED,
+ TXT_KEY_HORN,
+ TXT_KEY_SWAMP,
+ TXT_KEY_CASTLE
+};
+
+static void SetDormantArtifact(mobj_t * arti);
+static void TryPickupArtifact(player_t * player, artitype_t artifactType,
+ mobj_t * artifact);
+static void TryPickupWeapon(player_t * player, pclass_t weaponClass,
+ weapontype_t weaponType, mobj_t * weapon,
+ char *message);
+static void TryPickupWeaponPiece(player_t * player, pclass_t matchClass,
+ int pieceValue, mobj_t * pieceMobj);
+
+//--------------------------------------------------------------------------
+//
+// PROC P_SetMessage
+//
+//--------------------------------------------------------------------------
+
+void P_SetMessage(player_t * player, char *message, boolean ultmsg)
+{
+ if ((player->ultimateMessage || !messageson) && !ultmsg)
+ {
+ return;
+ }
+ if (strlen(message) > 79)
+ {
+ strncpy(player->message, message, 80);
+ player->message[79] = 0;
+ }
+ else
+ {
+ strcpy(player->message, message);
+ }
+// strupr(player->message);
+ player->messageTics = MESSAGETICS;
+ player->yellowMessage = false;
+ if (ultmsg)
+ {
+ player->ultimateMessage = true;
+ }
+ if (player == &players[consoleplayer])
+ {
+ BorderTopRefresh = true;
+ }
+}
+
+//==========================================================================
+//
+// P_SetYellowMessage
+//
+//==========================================================================
+
+void P_SetYellowMessage(player_t * player, char *message, boolean ultmsg)
+{
+ if ((player->ultimateMessage || !messageson) && !ultmsg)
+ {
+ return;
+ }
+ if (strlen(message) > 79)
+ {
+ strncpy(player->message, message, 80);
+ player->message[79] = 0;
+ }
+ else
+ {
+ strcpy(player->message, message);
+ }
+ player->messageTics = 5 * MESSAGETICS; // Bold messages last longer
+ player->yellowMessage = true;
+ if (ultmsg)
+ {
+ player->ultimateMessage = true;
+ }
+ if (player == &players[consoleplayer])
+ {
+ BorderTopRefresh = true;
+ }
+}
+
+//==========================================================================
+//
+// P_ClearMessage
+//
+//==========================================================================
+
+void P_ClearMessage(player_t * player)
+{
+ player->messageTics = 0;
+ if (player == &players[consoleplayer])
+ {
+ BorderTopRefresh = true;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_HideSpecialThing
+//
+//----------------------------------------------------------------------------
+
+void P_HideSpecialThing(mobj_t * thing)
+{
+ thing->flags &= ~MF_SPECIAL;
+ thing->flags2 |= MF2_DONTDRAW;
+ P_SetMobjState(thing, S_HIDESPECIAL1);
+}
+
+//--------------------------------------------------------------------------
+//
+// FUNC P_GiveMana
+//
+// Returns true if the player accepted the mana, false if it was
+// refused (player has MAX_MANA).
+//
+//--------------------------------------------------------------------------
+
+boolean P_GiveMana(player_t * player, manatype_t mana, int count)
+{
+ int prevMana;
+ //weapontype_t changeWeapon;
+
+ if (mana == MANA_NONE || mana == MANA_BOTH)
+ {
+ return (false);
+ }
+ if (mana < 0 || mana > NUMMANA)
+ {
+ I_Error("P_GiveMana: bad type %i", mana);
+ }
+ if (player->mana[mana] == MAX_MANA)
+ {
+ return (false);
+ }
+ if (gameskill == sk_baby || gameskill == sk_nightmare)
+ { // extra mana in baby mode and nightmare mode
+ count += count >> 1;
+ }
+ prevMana = player->mana[mana];
+
+ player->mana[mana] += count;
+ if (player->mana[mana] > MAX_MANA)
+ {
+ player->mana[mana] = MAX_MANA;
+ }
+ if (player->class == PCLASS_FIGHTER && player->readyweapon == WP_SECOND
+ && mana == MANA_1 && prevMana <= 0)
+ {
+ P_SetPsprite(player, ps_weapon, S_FAXEREADY_G);
+ }
+ return (true);
+}
+
+//==========================================================================
+//
+// TryPickupWeapon
+//
+//==========================================================================
+
+static void TryPickupWeapon(player_t * player, pclass_t weaponClass,
+ weapontype_t weaponType, mobj_t * weapon,
+ char *message)
+{
+ boolean remove;
+ boolean gaveMana;
+ boolean gaveWeapon;
+
+ remove = true;
+ if (player->class != weaponClass)
+ { // Wrong class, but try to pick up for mana
+ if (netgame && !deathmatch)
+ { // Can't pick up weapons for other classes in coop netplay
+ return;
+ }
+ if (weaponType == WP_SECOND)
+ {
+ if (!P_GiveMana(player, MANA_1, 25))
+ {
+ return;
+ }
+ }
+ else
+ {
+ if (!P_GiveMana(player, MANA_2, 25))
+ {
+ return;
+ }
+ }
+ }
+ else if (netgame && !deathmatch)
+ { // Cooperative net-game
+ if (player->weaponowned[weaponType])
+ {
+ return;
+ }
+ player->weaponowned[weaponType] = true;
+ if (weaponType == WP_SECOND)
+ {
+ P_GiveMana(player, MANA_1, 25);
+ }
+ else
+ {
+ P_GiveMana(player, MANA_2, 25);
+ }
+ player->pendingweapon = weaponType;
+ remove = false;
+ }
+ else
+ { // Deathmatch or single player game
+ if (weaponType == WP_SECOND)
+ {
+ gaveMana = P_GiveMana(player, MANA_1, 25);
+ }
+ else
+ {
+ gaveMana = P_GiveMana(player, MANA_2, 25);
+ }
+ if (player->weaponowned[weaponType])
+ {
+ gaveWeapon = false;
+ }
+ else
+ {
+ gaveWeapon = true;
+ player->weaponowned[weaponType] = true;
+ if (weaponType > player->readyweapon)
+ { // Only switch to more powerful weapons
+ player->pendingweapon = weaponType;
+ }
+ }
+ if (!(gaveWeapon || gaveMana))
+ { // Player didn't need the weapon or any mana
+ return;
+ }
+ }
+
+ P_SetMessage(player, message, false);
+ if (weapon->special)
+ {
+ P_ExecuteLineSpecial(weapon->special, weapon->args,
+ NULL, 0, player->mo);
+ weapon->special = 0;
+ }
+
+ if (remove)
+ {
+ if (deathmatch && !(weapon->flags2 & MF2_DROPPED))
+ {
+ P_HideSpecialThing(weapon);
+ }
+ else
+ {
+ P_RemoveMobj(weapon);
+ }
+ }
+
+ player->bonuscount += BONUSADD;
+ if (player == &players[consoleplayer])
+ {
+ S_StartSound(NULL, SFX_PICKUP_WEAPON);
+ SB_PaletteFlash(false);
+ }
+}
+
+//--------------------------------------------------------------------------
+//
+// FUNC P_GiveWeapon
+//
+// Returns true if the weapon or its mana was accepted.
+//
+//--------------------------------------------------------------------------
+
+/*
+boolean P_GiveWeapon(player_t *player, pclass_t class, weapontype_t weapon)
+{
+ boolean gaveMana;
+ boolean gaveWeapon;
+
+ if(player->class != class)
+ { // player cannot use this weapon, take it anyway, and get mana
+ if(netgame && !deathmatch)
+ { // Can't pick up weapons for other classes in coop netplay
+ return false;
+ }
+ if(weapon == WP_SECOND)
+ {
+ return P_GiveMana(player, MANA_1, 25);
+ }
+ else
+ {
+ return P_GiveMana(player, MANA_2, 25);
+ }
+ }
+ if(netgame && !deathmatch)
+ { // Cooperative net-game
+ if(player->weaponowned[weapon])
+ {
+ return(false);
+ }
+ player->bonuscount += BONUSADD;
+ player->weaponowned[weapon] = true;
+ if(weapon == WP_SECOND)
+ {
+ P_GiveMana(player, MANA_1, 25);
+ }
+ else
+ {
+ P_GiveMana(player, MANA_2, 25);
+ }
+ player->pendingweapon = weapon;
+ if(player == &players[consoleplayer])
+ {
+ S_StartSound(NULL, SFX_PICKUP_WEAPON);
+ }
+ return(false);
+ }
+ if(weapon == WP_SECOND)
+ {
+ gaveMana = P_GiveMana(player, MANA_1, 25);
+ }
+ else
+ {
+ gaveMana = P_GiveMana(player, MANA_2, 25);
+ }
+ if(player->weaponowned[weapon])
+ {
+ gaveWeapon = false;
+ }
+ else
+ {
+ gaveWeapon = true;
+ player->weaponowned[weapon] = true;
+ if(weapon > player->readyweapon)
+ { // Only switch to more powerful weapons
+ player->pendingweapon = weapon;
+ }
+ }
+ return(gaveWeapon || gaveMana);
+}
+*/
+
+//===========================================================================
+//
+// P_GiveWeaponPiece
+//
+//===========================================================================
+
+/*
+boolean P_GiveWeaponPiece(player_t *player, pclass_t class, int piece)
+{
+ P_GiveMana(player, MANA_1, 20);
+ P_GiveMana(player, MANA_2, 20);
+ if(player->class != class)
+ {
+ return true;
+ }
+ else if(player->pieces&piece)
+ { // player already has that weapon piece
+ return true;
+ }
+ player->pieces |= piece;
+ if(player->pieces == 7)
+ { // player has built the fourth weapon!
+ P_GiveWeapon(player, class, WP_FOURTH);
+ S_StartSound(player->mo, SFX_WEAPON_BUILD);
+ }
+ return true;
+}
+*/
+
+//==========================================================================
+//
+// TryPickupWeaponPiece
+//
+//==========================================================================
+
+static void TryPickupWeaponPiece(player_t * player, pclass_t matchClass,
+ int pieceValue, mobj_t * pieceMobj)
+{
+ boolean remove;
+ boolean checkAssembled;
+ boolean gaveWeapon;
+ int gaveMana;
+ static char *fourthWeaponText[] = {
+ TXT_WEAPON_F4,
+ TXT_WEAPON_C4,
+ TXT_WEAPON_M4
+ };
+ static char *weaponPieceText[] = {
+ TXT_QUIETUS_PIECE,
+ TXT_WRAITHVERGE_PIECE,
+ TXT_BLOODSCOURGE_PIECE
+ };
+ static int pieceValueTrans[] = {
+ 0, // 0: never
+ WPIECE1 | WPIECE2 | WPIECE3, // WPIECE1 (1)
+ WPIECE2 | WPIECE3, // WPIECE2 (2)
+ 0, // 3: never
+ WPIECE3 // WPIECE3 (4)
+ };
+
+ remove = true;
+ checkAssembled = true;
+ gaveWeapon = false;
+ if (player->class != matchClass)
+ { // Wrong class, but try to pick up for mana
+ if (netgame && !deathmatch)
+ { // Can't pick up wrong-class weapons in coop netplay
+ return;
+ }
+ checkAssembled = false;
+ gaveMana = P_GiveMana(player, MANA_1, 20) +
+ P_GiveMana(player, MANA_2, 20);
+ if (!gaveMana)
+ { // Didn't need the mana, so don't pick it up
+ return;
+ }
+ }
+ else if (netgame && !deathmatch)
+ { // Cooperative net-game
+ if (player->pieces & pieceValue)
+ { // Already has the piece
+ return;
+ }
+ pieceValue = pieceValueTrans[pieceValue];
+ P_GiveMana(player, MANA_1, 20);
+ P_GiveMana(player, MANA_2, 20);
+ remove = false;
+ }
+ else
+ { // Deathmatch or single player game
+ gaveMana = P_GiveMana(player, MANA_1, 20) +
+ P_GiveMana(player, MANA_2, 20);
+ if (player->pieces & pieceValue)
+ { // Already has the piece, check if mana needed
+ if (!gaveMana)
+ { // Didn't need the mana, so don't pick it up
+ return;
+ }
+ checkAssembled = false;
+ }
+ }
+
+ // Pick up the weapon piece
+ if (pieceMobj->special)
+ {
+ P_ExecuteLineSpecial(pieceMobj->special, pieceMobj->args,
+ NULL, 0, player->mo);
+ pieceMobj->special = 0;
+ }
+ if (remove)
+ {
+ if (deathmatch && !(pieceMobj->flags2 & MF2_DROPPED))
+ {
+ P_HideSpecialThing(pieceMobj);
+ }
+ else
+ {
+ P_RemoveMobj(pieceMobj);
+ }
+ }
+ player->bonuscount += BONUSADD;
+ if (player == &players[consoleplayer])
+ {
+ SB_PaletteFlash(false);
+ }
+
+ // Check if fourth weapon assembled
+ if (checkAssembled)
+ {
+ player->pieces |= pieceValue;
+ if (player->pieces == (WPIECE1 | WPIECE2 | WPIECE3))
+ {
+ gaveWeapon = true;
+ player->weaponowned[WP_FOURTH] = true;
+ player->pendingweapon = WP_FOURTH;
+ }
+ }
+
+ if (gaveWeapon)
+ {
+ P_SetMessage(player, fourthWeaponText[matchClass], false);
+ // Play the build-sound full volume for all players
+ S_StartSound(NULL, SFX_WEAPON_BUILD);
+ }
+ else
+ {
+ P_SetMessage(player, weaponPieceText[matchClass], false);
+ if (player == &players[consoleplayer])
+ {
+ S_StartSound(NULL, SFX_PICKUP_WEAPON);
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_GiveBody
+//
+// Returns false if the body isn't needed at all.
+//
+//---------------------------------------------------------------------------
+
+boolean P_GiveBody(player_t * player, int num)
+{
+ int max;
+
+ max = MAXHEALTH;
+ if (player->morphTics)
+ {
+ max = MAXMORPHHEALTH;
+ }
+ if (player->health >= max)
+ {
+ return (false);
+ }
+ player->health += num;
+ if (player->health > max)
+ {
+ player->health = max;
+ }
+ player->mo->health = player->health;
+ return (true);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_GiveArmor
+//
+// Returns false if the armor is worse than the current armor.
+//
+//---------------------------------------------------------------------------
+
+boolean P_GiveArmor(player_t * player, armortype_t armortype, int amount)
+{
+ int hits;
+ int totalArmor;
+
+ extern int ArmorMax[NUMCLASSES];
+
+ if (amount == -1)
+ {
+ hits = ArmorIncrement[player->class][armortype];
+ if (player->armorpoints[armortype] >= hits)
+ {
+ return false;
+ }
+ else
+ {
+ player->armorpoints[armortype] = hits;
+ }
+ }
+ else
+ {
+ hits = amount * 5 * FRACUNIT;
+ totalArmor = player->armorpoints[ARMOR_ARMOR]
+ + player->armorpoints[ARMOR_SHIELD]
+ + player->armorpoints[ARMOR_HELMET]
+ + player->armorpoints[ARMOR_AMULET]
+ + AutoArmorSave[player->class];
+ if (totalArmor < ArmorMax[player->class] * 5 * FRACUNIT)
+ {
+ player->armorpoints[armortype] += hits;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_GiveKey
+//
+//---------------------------------------------------------------------------
+
+int P_GiveKey(player_t * player, keytype_t key)
+{
+ if (player->keys & (1 << key))
+ {
+ return false;
+ }
+ player->bonuscount += BONUSADD;
+ player->keys |= 1 << key;
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_GivePower
+//
+// Returns true if power accepted.
+//
+//---------------------------------------------------------------------------
+
+boolean P_GivePower(player_t * player, powertype_t power)
+{
+ if (power == pw_invulnerability)
+ {
+ if (player->powers[power] > BLINKTHRESHOLD)
+ { // Already have it
+ return (false);
+ }
+ player->powers[power] = INVULNTICS;
+ player->mo->flags2 |= MF2_INVULNERABLE;
+ if (player->class == PCLASS_MAGE)
+ {
+ player->mo->flags2 |= MF2_REFLECTIVE;
+ }
+ return (true);
+ }
+ if (power == pw_flight)
+ {
+ if (player->powers[power] > BLINKTHRESHOLD)
+ { // Already have it
+ return (false);
+ }
+ player->powers[power] = FLIGHTTICS;
+ player->mo->flags2 |= MF2_FLY;
+ player->mo->flags |= MF_NOGRAVITY;
+ if (player->mo->z <= player->mo->floorz)
+ {
+ player->flyheight = 10; // thrust the player in the air a bit
+ }
+ return (true);
+ }
+ if (power == pw_infrared)
+ {
+ if (player->powers[power] > BLINKTHRESHOLD)
+ { // Already have it
+ return (false);
+ }
+ player->powers[power] = INFRATICS;
+ return (true);
+ }
+ if (power == pw_speed)
+ {
+ if (player->powers[power] > BLINKTHRESHOLD)
+ { // Already have it
+ return (false);
+ }
+ player->powers[power] = SPEEDTICS;
+ return (true);
+ }
+ if (power == pw_minotaur)
+ {
+ // Doesn't matter if already have power, renew ticker
+ player->powers[power] = MAULATORTICS;
+ 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);
+}
+
+//==========================================================================
+//
+// TryPickupArtifact
+//
+//==========================================================================
+
+static void TryPickupArtifact(player_t * player, artitype_t artifactType,
+ mobj_t * artifact)
+{
+ static char *artifactMessages[NUMARTIFACTS] = {
+ NULL,
+ TXT_ARTIINVULNERABILITY,
+ TXT_ARTIHEALTH,
+ TXT_ARTISUPERHEALTH,
+ TXT_ARTIHEALINGRADIUS,
+ TXT_ARTISUMMON,
+ TXT_ARTITORCH,
+ TXT_ARTIEGG,
+ TXT_ARTIFLY,
+ TXT_ARTIBLASTRADIUS,
+ TXT_ARTIPOISONBAG,
+ TXT_ARTITELEPORTOTHER,
+ TXT_ARTISPEED,
+ TXT_ARTIBOOSTMANA,
+ TXT_ARTIBOOSTARMOR,
+ TXT_ARTITELEPORT,
+ TXT_ARTIPUZZSKULL,
+ TXT_ARTIPUZZGEMBIG,
+ TXT_ARTIPUZZGEMRED,
+ TXT_ARTIPUZZGEMGREEN1,
+ TXT_ARTIPUZZGEMGREEN2,
+ TXT_ARTIPUZZGEMBLUE1,
+ TXT_ARTIPUZZGEMBLUE2,
+ TXT_ARTIPUZZBOOK1,
+ TXT_ARTIPUZZBOOK2,
+ TXT_ARTIPUZZSKULL2,
+ TXT_ARTIPUZZFWEAPON,
+ TXT_ARTIPUZZCWEAPON,
+ TXT_ARTIPUZZMWEAPON,
+ TXT_ARTIPUZZGEAR, // All gear pickups use the same text
+ TXT_ARTIPUZZGEAR,
+ TXT_ARTIPUZZGEAR,
+ TXT_ARTIPUZZGEAR
+ };
+
+ if (P_GiveArtifact(player, artifactType, artifact))
+ {
+ if (artifact->special)
+ {
+ P_ExecuteLineSpecial(artifact->special, artifact->args,
+ NULL, 0, NULL);
+ artifact->special = 0;
+ }
+ player->bonuscount += BONUSADD;
+ if (artifactType < arti_firstpuzzitem)
+ {
+ SetDormantArtifact(artifact);
+ S_StartSound(artifact, SFX_PICKUP_ARTIFACT);
+ P_SetMessage(player, artifactMessages[artifactType], false);
+ }
+ else
+ { // Puzzle item
+ S_StartSound(NULL, SFX_PICKUP_ITEM);
+ P_SetMessage(player, artifactMessages[artifactType], true);
+ if (!netgame || deathmatch)
+ { // Remove puzzle items if not cooperative netplay
+ P_RemoveMobj(artifact);
+ }
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_GiveArtifact
+//
+// Returns true if artifact accepted.
+//
+//---------------------------------------------------------------------------
+
+boolean P_GiveArtifact(player_t * player, artitype_t arti, mobj_t * mo)
+{
+ int i;
+ int j;
+ boolean slidePointer;
+
+ slidePointer = false;
+ i = 0;
+ while (player->inventory[i].type != arti && i < player->inventorySlotNum)
+ {
+ i++;
+ }
+ if (i == player->inventorySlotNum)
+ {
+ if (arti < arti_firstpuzzitem)
+ {
+ i = 0;
+ while (player->inventory[i].type < arti_firstpuzzitem
+ && i < player->inventorySlotNum)
+ {
+ i++;
+ }
+ if (i != player->inventorySlotNum)
+ {
+ for (j = player->inventorySlotNum; j > i; j--)
+ {
+ player->inventory[j].count =
+ player->inventory[j - 1].count;
+ player->inventory[j].type = player->inventory[j - 1].type;
+ slidePointer = true;
+ }
+ }
+ }
+ player->inventory[i].count = 1;
+ player->inventory[i].type = arti;
+ player->inventorySlotNum++;
+ }
+ else
+ {
+ if (arti >= arti_firstpuzzitem && netgame && !deathmatch)
+ { // Can't carry more than 1 puzzle item in coop netplay
+ return false;
+ }
+ if (player->inventory[i].count >= 25)
+ { // Player already has 25 of this item
+ return false;
+ }
+ player->inventory[i].count++;
+ }
+ if (!player->artifactCount)
+ {
+ player->readyArtifact = arti;
+ }
+ else if (player == &players[consoleplayer] && slidePointer
+ && i <= inv_ptr)
+ {
+ inv_ptr++;
+ curpos++;
+ if (curpos > 6)
+ {
+ curpos = 6;
+ }
+ }
+ player->artifactCount++;
+ return (true);
+}
+
+//==========================================================================
+//
+// SetDormantArtifact
+//
+// Removes the MF_SPECIAL flag and initiates the artifact pickup
+// animation.
+//
+//==========================================================================
+
+static void SetDormantArtifact(mobj_t * arti)
+{
+ arti->flags &= ~MF_SPECIAL;
+ if (deathmatch && !(arti->flags2 & MF2_DROPPED))
+ {
+ if (arti->type == MT_ARTIINVULNERABILITY)
+ {
+ P_SetMobjState(arti, S_DORMANTARTI3_1);
+ }
+ else if (arti->type == MT_SUMMONMAULATOR || arti->type == MT_ARTIFLY)
+ {
+ P_SetMobjState(arti, S_DORMANTARTI2_1);
+ }
+ else
+ {
+ P_SetMobjState(arti, S_DORMANTARTI1_1);
+ }
+ }
+ else
+ { // Don't respawn
+ P_SetMobjState(arti, S_DEADARTI1);
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_RestoreArtifact
+//
+//---------------------------------------------------------------------------
+
+void A_RestoreArtifact(mobj_t * arti)
+{
+ arti->flags |= MF_SPECIAL;
+ P_SetMobjState(arti, arti->info->spawnstate);
+ S_StartSound(arti, SFX_RESPAWN);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_RestoreSpecialThing1
+//
+// Make a special thing visible again.
+//
+//---------------------------------------------------------------------------
+
+void A_RestoreSpecialThing1(mobj_t * thing)
+{
+ thing->flags2 &= ~MF2_DONTDRAW;
+ S_StartSound(thing, SFX_RESPAWN);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_RestoreSpecialThing2
+//
+//---------------------------------------------------------------------------
+
+void A_RestoreSpecialThing2(mobj_t * thing)
+{
+ thing->flags |= MF_SPECIAL;
+ P_SetMobjState(thing, thing->info->spawnstate);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_TouchSpecialThing
+//
+//---------------------------------------------------------------------------
+
+void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher)
+{
+ player_t *player;
+ fixed_t delta;
+ int sound;
+ boolean respawn;
+
+ delta = special->z - toucher->z;
+ if (delta > toucher->height || delta < -32 * FRACUNIT)
+ { // Out of reach
+ return;
+ }
+ if (toucher->health <= 0)
+ { // Toucher is dead
+ return;
+ }
+ sound = SFX_PICKUP_ITEM;
+ player = toucher->player;
+ respawn = true;
+ switch (special->sprite)
+ {
+ // Items
+ case SPR_PTN1: // Item_HealingPotion
+ if (!P_GiveBody(player, 10))
+ {
+ return;
+ }
+ P_SetMessage(player, TXT_ITEMHEALTH, false);
+ break;
+ case SPR_ARM1:
+ if (!P_GiveArmor(player, ARMOR_ARMOR, -1))
+ {
+ return;
+ }
+ P_SetMessage(player, TXT_ARMOR1, false);
+ break;
+ case SPR_ARM2:
+ if (!P_GiveArmor(player, ARMOR_SHIELD, -1))
+ {
+ return;
+ }
+ P_SetMessage(player, TXT_ARMOR2, false);
+ break;
+ case SPR_ARM3:
+ if (!P_GiveArmor(player, ARMOR_HELMET, -1))
+ {
+ return;
+ }
+ P_SetMessage(player, TXT_ARMOR3, false);
+ break;
+ case SPR_ARM4:
+ if (!P_GiveArmor(player, ARMOR_AMULET, -1))
+ {
+ return;
+ }
+ P_SetMessage(player, TXT_ARMOR4, false);
+ break;
+
+ // Keys
+ case SPR_KEY1:
+ case SPR_KEY2:
+ case SPR_KEY3:
+ case SPR_KEY4:
+ case SPR_KEY5:
+ case SPR_KEY6:
+ case SPR_KEY7:
+ case SPR_KEY8:
+ case SPR_KEY9:
+ case SPR_KEYA:
+ case SPR_KEYB:
+ if (!P_GiveKey(player, special->sprite - SPR_KEY1))
+ {
+ return;
+ }
+ P_SetMessage(player, TextKeyMessages[special->sprite - SPR_KEY1],
+ true);
+ sound = SFX_PICKUP_KEY;
+
+ // Check and process the special now in case the key doesn't
+ // get removed for coop netplay
+ if (special->special)
+ {
+ P_ExecuteLineSpecial(special->special, special->args,
+ NULL, 0, toucher);
+ special->special = 0;
+ }
+
+ if (!netgame)
+ { // Only remove keys in single player game
+ break;
+ }
+ player->bonuscount += BONUSADD;
+ if (player == &players[consoleplayer])
+ {
+ S_StartSound(NULL, sound);
+ SB_PaletteFlash(false);
+ }
+ return;
+
+ // Artifacts
+ case SPR_PTN2:
+ TryPickupArtifact(player, arti_health, special);
+ return;
+ case SPR_SOAR:
+ TryPickupArtifact(player, arti_fly, special);
+ return;
+ case SPR_INVU:
+ TryPickupArtifact(player, arti_invulnerability, special);
+ return;
+ case SPR_SUMN:
+ TryPickupArtifact(player, arti_summon, special);
+ return;
+ case SPR_PORK:
+ TryPickupArtifact(player, arti_egg, special);
+ return;
+ case SPR_SPHL:
+ TryPickupArtifact(player, arti_superhealth, special);
+ return;
+ case SPR_HRAD:
+ TryPickupArtifact(player, arti_healingradius, special);
+ return;
+ case SPR_TRCH:
+ TryPickupArtifact(player, arti_torch, special);
+ return;
+ case SPR_ATLP:
+ TryPickupArtifact(player, arti_teleport, special);
+ return;
+ case SPR_TELO:
+ TryPickupArtifact(player, arti_teleportother, special);
+ return;
+ case SPR_PSBG:
+ TryPickupArtifact(player, arti_poisonbag, special);
+ return;
+ case SPR_SPED:
+ TryPickupArtifact(player, arti_speed, special);
+ return;
+ case SPR_BMAN:
+ TryPickupArtifact(player, arti_boostmana, special);
+ return;
+ case SPR_BRAC:
+ TryPickupArtifact(player, arti_boostarmor, special);
+ return;
+ case SPR_BLST:
+ TryPickupArtifact(player, arti_blastradius, special);
+ return;
+
+ // Puzzle artifacts
+ case SPR_ASKU:
+ TryPickupArtifact(player, arti_puzzskull, special);
+ return;
+ case SPR_ABGM:
+ TryPickupArtifact(player, arti_puzzgembig, special);
+ return;
+ case SPR_AGMR:
+ TryPickupArtifact(player, arti_puzzgemred, special);
+ return;
+ case SPR_AGMG:
+ TryPickupArtifact(player, arti_puzzgemgreen1, special);
+ return;
+ case SPR_AGG2:
+ TryPickupArtifact(player, arti_puzzgemgreen2, special);
+ return;
+ case SPR_AGMB:
+ TryPickupArtifact(player, arti_puzzgemblue1, special);
+ return;
+ case SPR_AGB2:
+ TryPickupArtifact(player, arti_puzzgemblue2, special);
+ return;
+ case SPR_ABK1:
+ TryPickupArtifact(player, arti_puzzbook1, special);
+ return;
+ case SPR_ABK2:
+ TryPickupArtifact(player, arti_puzzbook2, special);
+ return;
+ case SPR_ASK2:
+ TryPickupArtifact(player, arti_puzzskull2, special);
+ return;
+ case SPR_AFWP:
+ TryPickupArtifact(player, arti_puzzfweapon, special);
+ return;
+ case SPR_ACWP:
+ TryPickupArtifact(player, arti_puzzcweapon, special);
+ return;
+ case SPR_AMWP:
+ TryPickupArtifact(player, arti_puzzmweapon, special);
+ return;
+ case SPR_AGER:
+ TryPickupArtifact(player, arti_puzzgear1, special);
+ return;
+ case SPR_AGR2:
+ TryPickupArtifact(player, arti_puzzgear2, special);
+ return;
+ case SPR_AGR3:
+ TryPickupArtifact(player, arti_puzzgear3, special);
+ return;
+ case SPR_AGR4:
+ TryPickupArtifact(player, arti_puzzgear4, special);
+ return;
+
+ // Mana
+ case SPR_MAN1:
+ if (!P_GiveMana(player, MANA_1, 15))
+ {
+ return;
+ }
+ P_SetMessage(player, TXT_MANA_1, false);
+ break;
+ case SPR_MAN2:
+ if (!P_GiveMana(player, MANA_2, 15))
+ {
+ return;
+ }
+ P_SetMessage(player, TXT_MANA_2, false);
+ break;
+ case SPR_MAN3: // Double Mana Dodecahedron
+ if (!P_GiveMana(player, MANA_1, 20))
+ {
+ if (!P_GiveMana(player, MANA_2, 20))
+ {
+ return;
+ }
+ }
+ else
+ {
+ P_GiveMana(player, MANA_2, 20);
+ }
+ P_SetMessage(player, TXT_MANA_BOTH, false);
+ break;
+
+ // 2nd and 3rd Mage Weapons
+ case SPR_WMCS: // Frost Shards
+ TryPickupWeapon(player, PCLASS_MAGE, WP_SECOND,
+ special, TXT_WEAPON_M2);
+ return;
+ case SPR_WMLG: // Arc of Death
+ TryPickupWeapon(player, PCLASS_MAGE, WP_THIRD,
+ special, TXT_WEAPON_M3);
+ return;
+
+ // 2nd and 3rd Fighter Weapons
+ case SPR_WFAX: // Timon's Axe
+ TryPickupWeapon(player, PCLASS_FIGHTER, WP_SECOND,
+ special, TXT_WEAPON_F2);
+ return;
+ case SPR_WFHM: // Hammer of Retribution
+ TryPickupWeapon(player, PCLASS_FIGHTER, WP_THIRD,
+ special, TXT_WEAPON_F3);
+ return;
+
+ // 2nd and 3rd Cleric Weapons
+ case SPR_WCSS: // Serpent Staff
+ TryPickupWeapon(player, PCLASS_CLERIC, WP_SECOND,
+ special, TXT_WEAPON_C2);
+ return;
+ case SPR_WCFM: // Firestorm
+ TryPickupWeapon(player, PCLASS_CLERIC, WP_THIRD,
+ special, TXT_WEAPON_C3);
+ return;
+
+ // Fourth Weapon Pieces
+ case SPR_WFR1:
+ TryPickupWeaponPiece(player, PCLASS_FIGHTER, WPIECE1, special);
+ return;
+ case SPR_WFR2:
+ TryPickupWeaponPiece(player, PCLASS_FIGHTER, WPIECE2, special);
+ return;
+ case SPR_WFR3:
+ TryPickupWeaponPiece(player, PCLASS_FIGHTER, WPIECE3, special);
+ return;
+ case SPR_WCH1:
+ TryPickupWeaponPiece(player, PCLASS_CLERIC, WPIECE1, special);
+ return;
+ case SPR_WCH2:
+ TryPickupWeaponPiece(player, PCLASS_CLERIC, WPIECE2, special);
+ return;
+ case SPR_WCH3:
+ TryPickupWeaponPiece(player, PCLASS_CLERIC, WPIECE3, special);
+ return;
+ case SPR_WMS1:
+ TryPickupWeaponPiece(player, PCLASS_MAGE, WPIECE1, special);
+ return;
+ case SPR_WMS2:
+ TryPickupWeaponPiece(player, PCLASS_MAGE, WPIECE2, special);
+ return;
+ case SPR_WMS3:
+ TryPickupWeaponPiece(player, PCLASS_MAGE, WPIECE3, special);
+ return;
+
+ default:
+ I_Error("P_SpecialThing: Unknown gettable thing");
+ }
+ if (special->special)
+ {
+ P_ExecuteLineSpecial(special->special, special->args, NULL,
+ 0, toucher);
+ special->special = 0;
+ }
+ if (deathmatch && respawn && !(special->flags2 & MF2_DROPPED))
+ {
+ P_HideSpecialThing(special);
+ }
+ else
+ {
+ P_RemoveMobj(special);
+ }
+ player->bonuscount += BONUSADD;
+ if (player == &players[consoleplayer])
+ {
+ S_StartSound(NULL, sound);
+ SB_PaletteFlash(false);
+ }
+}
+
+// Search thinker list for minotaur
+mobj_t *ActiveMinotaur(player_t * master)
+{
+ mobj_t *mo;
+ player_t *plr;
+ thinker_t *think;
+ unsigned int *starttime;
+
+ for (think = thinkercap.next; think != &thinkercap; think = think->next)
+ {
+ if (think->function != P_MobjThinker)
+ continue;
+ mo = (mobj_t *) think;
+ if (mo->type != MT_MINOTAUR)
+ continue;
+ if (mo->health <= 0)
+ continue;
+ if (!(mo->flags & MF_COUNTKILL))
+ continue; // for morphed minotaurs
+ if (mo->flags & MF_CORPSE)
+ continue;
+ starttime = (unsigned int *) mo->args;
+ if ((leveltime - *starttime) >= MAULATORTICS)
+ continue;
+ plr = mo->special1.m->player;
+ if (plr == master)
+ return (mo);
+ }
+ return (NULL);
+}
+
+
+//---------------------------------------------------------------------------
+//
+// PROC P_KillMobj
+//
+//---------------------------------------------------------------------------
+
+void P_KillMobj(mobj_t * source, mobj_t * target)
+{
+ int dummy;
+ mobj_t *master;
+
+ target->flags &= ~(MF_SHOOTABLE | MF_FLOAT | MF_SKULLFLY | MF_NOGRAVITY);
+ target->flags |= MF_CORPSE | MF_DROPOFF;
+ target->flags2 &= ~MF2_PASSMOBJ;
+ target->height >>= 2;
+ if ((target->flags & MF_COUNTKILL || target->type == MT_ZBELL)
+ && target->special)
+ { // Initiate monster death actions
+ if (target->type == MT_SORCBOSS)
+ {
+ dummy = 0;
+ P_StartACS(target->special, 0, (byte *) & dummy, target, NULL, 0);
+ }
+ else
+ {
+ P_ExecuteLineSpecial(target->special, target->args,
+ NULL, 0, target);
+ }
+ }
+ if (source && source->player)
+ { // Check for frag changes
+ if (target->player)
+ {
+ if (target == source)
+ { // Self-frag
+ target->player->frags[target->player - players]--;
+ if (cmdfrag && netgame
+ && source->player == &players[consoleplayer])
+ { // Send out a frag count packet
+ NET_SendFrags(source->player);
+ }
+ }
+ else
+ {
+ source->player->frags[target->player - players]++;
+ if (cmdfrag && netgame
+ && source->player == &players[consoleplayer])
+ { // Send out a frag count packet
+ NET_SendFrags(source->player);
+ }
+ }
+ }
+ }
+ if (target->player)
+ { // Player death
+ if (!source)
+ { // Self-frag
+ target->player->frags[target->player - players]--;
+ if (cmdfrag && netgame
+ && target->player == &players[consoleplayer])
+ { // Send out a frag count packet
+ NET_SendFrags(target->player);
+ }
+ }
+ target->flags &= ~MF_SOLID;
+ target->flags2 &= ~MF2_FLY;
+ target->player->powers[pw_flight] = 0;
+ target->player->playerstate = PST_DEAD;
+ P_DropWeapon(target->player);
+ if (target->flags2 & MF2_FIREDAMAGE)
+ { // Player flame death
+ switch (target->player->class)
+ {
+ case PCLASS_FIGHTER:
+ S_StartSound(target, SFX_PLAYER_FIGHTER_BURN_DEATH);
+ P_SetMobjState(target, S_PLAY_F_FDTH1);
+ return;
+ case PCLASS_CLERIC:
+ S_StartSound(target, SFX_PLAYER_CLERIC_BURN_DEATH);
+ P_SetMobjState(target, S_PLAY_C_FDTH1);
+ return;
+ case PCLASS_MAGE:
+ S_StartSound(target, SFX_PLAYER_MAGE_BURN_DEATH);
+ P_SetMobjState(target, S_PLAY_M_FDTH1);
+ return;
+ default:
+ break;
+ }
+ }
+ if (target->flags2 & MF2_ICEDAMAGE)
+ { // Player ice death
+ target->flags &= ~(7 << MF_TRANSSHIFT); //no translation
+ target->flags |= MF_ICECORPSE;
+ switch (target->player->class)
+ {
+ case PCLASS_FIGHTER:
+ P_SetMobjState(target, S_FPLAY_ICE);
+ return;
+ case PCLASS_CLERIC:
+ P_SetMobjState(target, S_CPLAY_ICE);
+ return;
+ case PCLASS_MAGE:
+ P_SetMobjState(target, S_MPLAY_ICE);
+ return;
+ case PCLASS_PIG:
+ P_SetMobjState(target, S_PIG_ICE);
+ return;
+ default:
+ break;
+ }
+ }
+ }
+ if (target->flags2 & MF2_FIREDAMAGE)
+ {
+ if (target->type == MT_FIGHTER_BOSS
+ || target->type == MT_CLERIC_BOSS || target->type == MT_MAGE_BOSS)
+ {
+ switch (target->type)
+ {
+ case MT_FIGHTER_BOSS:
+ S_StartSound(target, SFX_PLAYER_FIGHTER_BURN_DEATH);
+ P_SetMobjState(target, S_PLAY_F_FDTH1);
+ return;
+ case MT_CLERIC_BOSS:
+ S_StartSound(target, SFX_PLAYER_CLERIC_BURN_DEATH);
+ P_SetMobjState(target, S_PLAY_C_FDTH1);
+ return;
+ case MT_MAGE_BOSS:
+ S_StartSound(target, SFX_PLAYER_MAGE_BURN_DEATH);
+ P_SetMobjState(target, S_PLAY_M_FDTH1);
+ return;
+ default:
+ break;
+ }
+ }
+ else if (target->type == MT_TREEDESTRUCTIBLE)
+ {
+ P_SetMobjState(target, S_ZTREEDES_X1);
+ target->height = 24 * FRACUNIT;
+ S_StartSound(target, SFX_TREE_EXPLODE);
+ return;
+ }
+ }
+ if (target->flags2 & MF2_ICEDAMAGE)
+ {
+ target->flags |= MF_ICECORPSE;
+ switch (target->type)
+ {
+ case MT_BISHOP:
+ P_SetMobjState(target, S_BISHOP_ICE);
+ return;
+ case MT_CENTAUR:
+ case MT_CENTAURLEADER:
+ P_SetMobjState(target, S_CENTAUR_ICE);
+ return;
+ case MT_DEMON:
+ case MT_DEMON2:
+ P_SetMobjState(target, S_DEMON_ICE);
+ return;
+ case MT_SERPENT:
+ case MT_SERPENTLEADER:
+ P_SetMobjState(target, S_SERPENT_ICE);
+ return;
+ case MT_WRAITH:
+ case MT_WRAITHB:
+ P_SetMobjState(target, S_WRAITH_ICE);
+ return;
+ case MT_ETTIN:
+ P_SetMobjState(target, S_ETTIN_ICE1);
+ return;
+ case MT_FIREDEMON:
+ P_SetMobjState(target, S_FIRED_ICE1);
+ return;
+ case MT_FIGHTER_BOSS:
+ P_SetMobjState(target, S_FIGHTER_ICE);
+ return;
+ case MT_CLERIC_BOSS:
+ P_SetMobjState(target, S_CLERIC_ICE);
+ return;
+ case MT_MAGE_BOSS:
+ P_SetMobjState(target, S_MAGE_ICE);
+ return;
+ case MT_PIG:
+ P_SetMobjState(target, S_PIG_ICE);
+ return;
+ default:
+ target->flags &= ~MF_ICECORPSE;
+ break;
+ }
+ }
+
+ if (target->type == MT_MINOTAUR)
+ {
+ master = target->special1.m;
+ if (master->health > 0)
+ {
+ if (!ActiveMinotaur(master->player))
+ {
+ master->player->powers[pw_minotaur] = 0;
+ }
+ }
+ }
+ else if (target->type == MT_TREEDESTRUCTIBLE)
+ {
+ target->height = 24 * FRACUNIT;
+ }
+ if (target->health < -(target->info->spawnhealth >> 1)
+ && target->info->xdeathstate)
+ { // Extreme death
+ P_SetMobjState(target, target->info->xdeathstate);
+ }
+ else
+ { // Normal death
+ if ((target->type == MT_FIREDEMON) &&
+ (target->z <= target->floorz + 2 * FRACUNIT) &&
+ (target->info->xdeathstate))
+ {
+ // This is to fix the imps' staying in fall state
+ P_SetMobjState(target, target->info->xdeathstate);
+ }
+ else
+ {
+ P_SetMobjState(target, target->info->deathstate);
+ }
+ }
+ target->tics -= P_Random() & 3;
+// I_StartSound(&actor->r, actor->info->deathsound);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_MinotaurSlam
+//
+//---------------------------------------------------------------------------
+
+void P_MinotaurSlam(mobj_t * source, mobj_t * target)
+{
+ angle_t angle;
+ fixed_t thrust;
+
+ angle = R_PointToAngle2(source->x, source->y, target->x, target->y);
+ angle >>= ANGLETOFINESHIFT;
+ thrust = 16 * FRACUNIT + (P_Random() << 10);
+ target->momx += FixedMul(thrust, finecosine[angle]);
+ target->momy += FixedMul(thrust, finesine[angle]);
+ P_DamageMobj(target, NULL, source, HITDICE(4));
+ if (target->player)
+ {
+ target->reactiontime = 14 + (P_Random() & 7);
+ }
+ source->args[0] = 0; // Stop charging
+}
+
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_MorphPlayer
+//
+// Returns true if the player gets turned into a pig
+//
+//---------------------------------------------------------------------------
+
+boolean P_MorphPlayer(player_t * player)
+{
+ mobj_t *pmo;
+ mobj_t *fog;
+ mobj_t *beastMo;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ angle_t angle;
+ int oldFlags2;
+
+ if (player->powers[pw_invulnerability])
+ { // Immune when invulnerable
+ return (false);
+ }
+ if (player->morphTics)
+ { // Player is already a beast
+ return false;
+ }
+ pmo = player->mo;
+ x = pmo->x;
+ y = pmo->y;
+ z = pmo->z;
+ angle = pmo->angle;
+ oldFlags2 = pmo->flags2;
+ P_SetMobjState(pmo, S_FREETARGMOBJ);
+ fog = P_SpawnMobj(x, y, z + TELEFOGHEIGHT, MT_TFOG);
+ S_StartSound(fog, SFX_TELEPORT);
+ beastMo = P_SpawnMobj(x, y, z, MT_PIGPLAYER);
+ beastMo->special1.i = player->readyweapon;
+ beastMo->angle = angle;
+ beastMo->player = player;
+ player->health = beastMo->health = MAXMORPHHEALTH;
+ player->mo = beastMo;
+ memset(&player->armorpoints[0], 0, NUMARMOR * sizeof(int));
+ player->class = PCLASS_PIG;
+ if (oldFlags2 & MF2_FLY)
+ {
+ beastMo->flags2 |= MF2_FLY;
+ }
+ player->morphTics = MORPHTICS;
+ P_ActivateMorphWeapon(player);
+ return (true);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_MorphMonster
+//
+//---------------------------------------------------------------------------
+
+boolean P_MorphMonster(mobj_t * actor)
+{
+ mobj_t *master, *monster, *fog;
+ mobjtype_t moType;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ mobj_t oldMonster;
+
+ if (actor->player)
+ return (false);
+ if (!(actor->flags & MF_COUNTKILL))
+ return false;
+ if (actor->flags2 & MF2_BOSS)
+ return false;
+ moType = actor->type;
+ switch (moType)
+ {
+ case MT_PIG:
+ return (false);
+ case MT_FIGHTER_BOSS:
+ case MT_CLERIC_BOSS:
+ case MT_MAGE_BOSS:
+ return (false);
+ default:
+ break;
+ }
+
+ oldMonster = *actor;
+ x = oldMonster.x;
+ y = oldMonster.y;
+ z = oldMonster.z;
+ P_RemoveMobjFromTIDList(actor);
+ P_SetMobjState(actor, S_FREETARGMOBJ);
+ fog = P_SpawnMobj(x, y, z + TELEFOGHEIGHT, MT_TFOG);
+ S_StartSound(fog, SFX_TELEPORT);
+ monster = P_SpawnMobj(x, y, z, MT_PIG);
+ monster->special2.i = moType;
+ monster->special1.i = MORPHTICS + P_Random();
+ monster->flags |= (oldMonster.flags & MF_SHADOW);
+ monster->target = oldMonster.target;
+ monster->angle = oldMonster.angle;
+ monster->tid = oldMonster.tid;
+ monster->special = oldMonster.special;
+ P_InsertMobjIntoTIDList(monster, oldMonster.tid);
+ memcpy(monster->args, oldMonster.args, 5);
+
+ // check for turning off minotaur power for active icon
+ if (moType == MT_MINOTAUR)
+ {
+ master = oldMonster.special1.m;
+ if (master->health > 0)
+ {
+ if (!ActiveMinotaur(master->player))
+ {
+ master->player->powers[pw_minotaur] = 0;
+ }
+ }
+ }
+ return (true);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_AutoUseHealth
+//
+//---------------------------------------------------------------------------
+
+void P_AutoUseHealth(player_t * player, int saveHealth)
+{
+ int i;
+ int count;
+ int normalCount;
+ int normalSlot = 0;
+ int superCount;
+ int superSlot = 0;
+
+ normalCount = superCount = 0;
+ for (i = 0; i < player->inventorySlotNum; i++)
+ {
+ if (player->inventory[i].type == arti_health)
+ {
+ normalSlot = i;
+ normalCount = player->inventory[i].count;
+ }
+ else if (player->inventory[i].type == arti_superhealth)
+ {
+ superSlot = i;
+ superCount = player->inventory[i].count;
+ }
+ }
+ if ((gameskill == sk_baby) && (normalCount * 25 >= saveHealth))
+ { // Use quartz flasks
+ count = (saveHealth + 24) / 25;
+ for (i = 0; i < count; i++)
+ {
+ player->health += 25;
+ P_PlayerRemoveArtifact(player, normalSlot);
+ }
+ }
+ else if (superCount * 100 >= saveHealth)
+ { // Use mystic urns
+ count = (saveHealth + 99) / 100;
+ for (i = 0; i < count; i++)
+ {
+ player->health += 100;
+ P_PlayerRemoveArtifact(player, superSlot);
+ }
+ }
+ else if ((gameskill == sk_baby)
+ && (superCount * 100 + normalCount * 25 >= saveHealth))
+ { // Use mystic urns and quartz flasks
+ count = (saveHealth + 24) / 25;
+ saveHealth -= count * 25;
+ for (i = 0; i < count; i++)
+ {
+ player->health += 25;
+ P_PlayerRemoveArtifact(player, normalSlot);
+ }
+ count = (saveHealth + 99) / 100;
+ for (i = 0; i < count; i++)
+ {
+ player->health += 100;
+ P_PlayerRemoveArtifact(player, normalSlot);
+ }
+ }
+ player->mo->health = player->health;
+}
+
+/*
+=================
+=
+= P_DamageMobj
+=
+= Damages both enemies and players
+= inflictor is the thing that caused the damage
+= creature or missile, can be NULL (slime, etc)
+= source is the thing to target after taking damage
+= creature or NULL
+= Source and inflictor are the same for melee attacks
+= source can be null for barrel explosions and other environmental stuff
+==================
+*/
+
+void P_DamageMobj
+ (mobj_t * target, mobj_t * inflictor, mobj_t * source, int damage)
+{
+ unsigned ang;
+ int saved;
+ fixed_t savedPercent;
+ player_t *player;
+ mobj_t *master;
+ fixed_t thrust;
+ int temp;
+ int i;
+
+ if (!(target->flags & MF_SHOOTABLE))
+ {
+ // Shouldn't happen
+ return;
+ }
+ if (target->health <= 0)
+ {
+ if (inflictor && inflictor->flags2 & MF2_ICEDAMAGE)
+ {
+ return;
+ }
+ else if (target->flags & MF_ICECORPSE) // frozen
+ {
+ target->tics = 1;
+ target->momx = target->momy = 0;
+ }
+ return;
+ }
+ if ((target->flags2 & MF2_INVULNERABLE) && damage < 10000)
+ { // mobj is invulnerable
+ if (target->player)
+ return; // for player, no exceptions
+ if (inflictor)
+ {
+ switch (inflictor->type)
+ {
+ // These inflictors aren't foiled by invulnerability
+ case MT_HOLY_FX:
+ case MT_POISONCLOUD:
+ case MT_FIREBOMB:
+ break;
+ default:
+ return;
+ }
+ }
+ else
+ {
+ return;
+ }
+ }
+ if (target->player)
+ {
+ if (damage < 1000 && ((target->player->cheats & CF_GODMODE)
+ || target->player->powers[pw_invulnerability]))
+ {
+ return;
+ }
+ }
+ if (target->flags & MF_SKULLFLY)
+ {
+ target->momx = target->momy = target->momz = 0;
+ }
+ if (target->flags2 & MF2_DORMANT)
+ {
+ // Invulnerable, and won't wake up
+ return;
+ }
+ player = target->player;
+ if (player && gameskill == sk_baby)
+ {
+ // Take half damage in trainer mode
+ damage >>= 1;
+ }
+ // Special damage types
+ if (inflictor)
+ {
+ switch (inflictor->type)
+ {
+ case MT_EGGFX:
+ if (player)
+ {
+ P_MorphPlayer(player);
+ }
+ else
+ {
+ P_MorphMonster(target);
+ }
+ return; // Always return
+ case MT_TELOTHER_FX1:
+ case MT_TELOTHER_FX2:
+ case MT_TELOTHER_FX3:
+ case MT_TELOTHER_FX4:
+ case MT_TELOTHER_FX5:
+ if ((target->flags & MF_COUNTKILL) &&
+ (target->type != MT_SERPENT) &&
+ (target->type != MT_SERPENTLEADER) &&
+ (!(target->flags2 & MF2_BOSS)))
+ {
+ P_TeleportOther(target);
+ }
+ return;
+ case MT_MINOTAUR:
+ if (inflictor->flags & MF_SKULLFLY)
+ { // Slam only when in charge mode
+ P_MinotaurSlam(inflictor, target);
+ return;
+ }
+ break;
+ case MT_BISH_FX:
+ // Bishops are just too nasty
+ damage >>= 1;
+ break;
+ case MT_SHARDFX1:
+ switch (inflictor->special2.i)
+ {
+ case 3:
+ damage <<= 3;
+ break;
+ case 2:
+ damage <<= 2;
+ break;
+ case 1:
+ damage <<= 1;
+ break;
+ default:
+ break;
+ }
+ break;
+ case MT_CSTAFF_MISSILE:
+ // Cleric Serpent Staff does poison damage
+ if (target->player)
+ {
+ P_PoisonPlayer(target->player, source, 20);
+ damage >>= 1;
+ }
+ break;
+ case MT_ICEGUY_FX2:
+ damage >>= 1;
+ break;
+ case MT_POISONDART:
+ if (target->player)
+ {
+ P_PoisonPlayer(target->player, source, 20);
+ damage >>= 1;
+ }
+ break;
+ case MT_POISONCLOUD:
+ if (target->player)
+ {
+ if (target->player->poisoncount < 4)
+ {
+ P_PoisonDamage(target->player, source, 15 + (P_Random() & 15), false); // Don't play painsound
+ P_PoisonPlayer(target->player, source, 50);
+ S_StartSound(target, SFX_PLAYER_POISONCOUGH);
+ }
+ return;
+ }
+ else if (!(target->flags & MF_COUNTKILL))
+ { // only damage monsters/players with the poison cloud
+ return;
+ }
+ break;
+ case MT_FSWORD_MISSILE:
+ if (target->player)
+ {
+ damage -= damage >> 2;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ // Push the target unless source is using the gauntlets
+ if (inflictor && (!source || !source->player)
+ && !(inflictor->flags2 & MF2_NODMGTHRUST))
+ {
+ ang = R_PointToAngle2(inflictor->x, inflictor->y,
+ target->x, target->y);
+ //thrust = damage*(FRACUNIT>>3)*100/target->info->mass;
+ thrust = damage * (FRACUNIT >> 3) * 150 / 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)
+ {
+ savedPercent = AutoArmorSave[player->class]
+ + player->armorpoints[ARMOR_ARMOR] +
+ player->armorpoints[ARMOR_SHIELD] +
+ player->armorpoints[ARMOR_HELMET] +
+ player->armorpoints[ARMOR_AMULET];
+ if (savedPercent)
+ { // armor absorbed some damage
+ if (savedPercent > 100 * FRACUNIT)
+ {
+ savedPercent = 100 * FRACUNIT;
+ }
+ for (i = 0; i < NUMARMOR; i++)
+ {
+ if (player->armorpoints[i])
+ {
+ player->armorpoints[i] -=
+ FixedDiv(FixedMul(damage << FRACBITS,
+ ArmorIncrement[player->class][i]),
+ 300 * FRACUNIT);
+ if (player->armorpoints[i] < 2 * FRACUNIT)
+ {
+ player->armorpoints[i] = 0;
+ }
+ }
+ }
+ saved = FixedDiv(FixedMul(damage << FRACBITS, savedPercent),
+ 100 * FRACUNIT);
+ if (saved > savedPercent * 2)
+ {
+ saved = savedPercent * 2;
+ }
+ damage -= saved >> FRACBITS;
+ }
+ if (damage >= player->health
+ && ((gameskill == sk_baby) || deathmatch) && !player->morphTics)
+ { // Try to use some inventory health
+ P_AutoUseHealth(player, damage - player->health + 1);
+ }
+ 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);
+ SB_PaletteFlash(false);
+ }
+ }
+
+ //
+ // do the damage
+ //
+ target->health -= damage;
+ if (target->health <= 0)
+ { // Death
+ if (inflictor)
+ { // check for special fire damage or ice damage deaths
+ if (inflictor->flags2 & MF2_FIREDAMAGE)
+ {
+ if (player && !player->morphTics)
+ { // Check for flame death
+ if (target->health > -50 && damage > 25)
+ {
+ target->flags2 |= MF2_FIREDAMAGE;
+ }
+ }
+ else
+ {
+ target->flags2 |= MF2_FIREDAMAGE;
+ }
+ }
+ else if (inflictor->flags2 & MF2_ICEDAMAGE)
+ {
+ target->flags2 |= MF2_ICEDAMAGE;
+ }
+ }
+ if (source && (source->type == MT_MINOTAUR))
+ { // Minotaur's kills go to his master
+ master = source->special1.m;
+ // Make sure still alive and not a pointer to fighter head
+ if (master->player && (master->player->mo == master))
+ {
+ source = master;
+ }
+ }
+ if (source && (source->player) &&
+ (source->player->readyweapon == WP_FOURTH))
+ {
+ // Always extreme death from fourth weapon
+ target->health = -5000;
+ }
+ P_KillMobj(source, target);
+ return;
+ }
+ if ((P_Random() < target->info->painchance)
+ && !(target->flags & MF_SKULLFLY))
+ {
+ if (inflictor && (inflictor->type >= MT_LIGHTNING_FLOOR
+ && inflictor->type <= MT_LIGHTNING_ZAP))
+ {
+ if (P_Random() < 96)
+ {
+ target->flags |= MF_JUSTHIT; // fight back!
+ P_SetMobjState(target, target->info->painstate);
+ }
+ else
+ { // "electrocute" the target
+ target->frame |= FF_FULLBRIGHT;
+ if (target->flags & MF_COUNTKILL && P_Random() < 128
+ && !S_GetSoundPlayingInfo(target, SFX_PUPPYBEAT))
+ {
+ if ((target->type == MT_CENTAUR) ||
+ (target->type == MT_CENTAURLEADER) ||
+ (target->type == MT_ETTIN))
+ {
+ S_StartSound(target, SFX_PUPPYBEAT);
+ }
+ }
+ }
+ }
+ else
+ {
+ target->flags |= MF_JUSTHIT; // fight back!
+ P_SetMobjState(target, target->info->painstate);
+ if (inflictor && inflictor->type == MT_POISONCLOUD)
+ {
+ if (target->flags & MF_COUNTKILL && P_Random() < 128
+ && !S_GetSoundPlayingInfo(target, SFX_PUPPYBEAT))
+ {
+ if ((target->type == MT_CENTAUR) ||
+ (target->type == MT_CENTAURLEADER) ||
+ (target->type == MT_ETTIN))
+ {
+ S_StartSound(target, SFX_PUPPYBEAT);
+ }
+ }
+ }
+ }
+ }
+ target->reactiontime = 0; // we're awake now...
+ if (!target->threshold && source && !(source->flags2 & MF2_BOSS)
+ && !(target->type == MT_BISHOP) && !(target->type == MT_MINOTAUR))
+ {
+ // Target actor is not intent on another actor,
+ // so make him chase after source
+ if ((target->type == MT_CENTAUR && source->type == MT_CENTAURLEADER)
+ || (target->type == MT_CENTAURLEADER
+ && source->type == MT_CENTAUR))
+ {
+ return;
+ }
+ target->target = source;
+ target->threshold = BASETHRESHOLD;
+ if (target->state == &states[target->info->spawnstate]
+ && target->info->seestate != S_NULL)
+ {
+ P_SetMobjState(target, target->info->seestate);
+ }
+ }
+}
+
+//==========================================================================
+//
+// P_FallingDamage
+//
+//==========================================================================
+
+void P_FallingDamage(player_t * player)
+{
+ int damage;
+ int mom;
+ int dist;
+
+ mom = abs(player->mo->momz);
+ dist = FixedMul(mom, 16 * FRACUNIT / 23);
+
+ if (mom >= 63 * FRACUNIT)
+ { // automatic death
+ P_DamageMobj(player->mo, NULL, NULL, 10000);
+ return;
+ }
+ damage = ((FixedMul(dist, dist) / 10) >> FRACBITS) - 24;
+ if (player->mo->momz > -39 * FRACUNIT && damage > player->mo->health
+ && player->mo->health != 1)
+ { // No-death threshold
+ damage = player->mo->health - 1;
+ }
+ S_StartSound(player->mo, SFX_PLAYER_LAND);
+ P_DamageMobj(player->mo, NULL, NULL, damage);
+}
+
+//==========================================================================
+//
+// P_PoisonPlayer - Sets up all data concerning poisoning
+//
+//==========================================================================
+
+void P_PoisonPlayer(player_t * player, mobj_t * poisoner, int poison)
+{
+ if ((player->cheats & CF_GODMODE) || player->powers[pw_invulnerability])
+ {
+ return;
+ }
+ player->poisoncount += poison;
+ player->poisoner = poisoner;
+ if (player->poisoncount > 100)
+ {
+ player->poisoncount = 100;
+ }
+}
+
+//==========================================================================
+//
+// P_PoisonDamage - Similar to P_DamageMobj
+//
+//==========================================================================
+
+void P_PoisonDamage(player_t * player, mobj_t * source, int damage,
+ boolean playPainSound)
+{
+ mobj_t *target;
+ mobj_t *inflictor;
+
+ target = player->mo;
+ inflictor = source;
+ if (target->health <= 0)
+ {
+ return;
+ }
+ if (target->flags2 & MF2_INVULNERABLE && damage < 10000)
+ { // mobj is invulnerable
+ return;
+ }
+ if (player && gameskill == sk_baby)
+ {
+ // Take half damage in trainer mode
+ damage >>= 1;
+ }
+ if (damage < 1000 && ((player->cheats & CF_GODMODE)
+ || player->powers[pw_invulnerability]))
+ {
+ return;
+ }
+ if (damage >= player->health
+ && ((gameskill == sk_baby) || deathmatch) && !player->morphTics)
+ { // Try to use some inventory health
+ P_AutoUseHealth(player, damage - player->health + 1);
+ }
+ player->health -= damage; // mirror mobj health here for Dave
+ if (player->health < 0)
+ {
+ player->health = 0;
+ }
+ player->attacker = source;
+
+ //
+ // do the damage
+ //
+ target->health -= damage;
+ if (target->health <= 0)
+ { // Death
+ target->special1.i = damage;
+ if (player && inflictor && !player->morphTics)
+ { // Check for flame death
+ if ((inflictor->flags2 & MF2_FIREDAMAGE)
+ && (target->health > -50) && (damage > 25))
+ {
+ target->flags2 |= MF2_FIREDAMAGE;
+ }
+ if (inflictor->flags2 & MF2_ICEDAMAGE)
+ {
+ target->flags2 |= MF2_ICEDAMAGE;
+ }
+ }
+ P_KillMobj(source, target);
+ return;
+ }
+ if (!(leveltime & 63) && playPainSound)
+ {
+ P_SetMobjState(target, target->info->painstate);
+ }
+/*
+ if((P_Random() < target->info->painchance)
+ && !(target->flags&MF_SKULLFLY))
+ {
+ target->flags |= MF_JUSTHIT; // fight back!
+ P_SetMobjState(target, target->info->painstate);
+ }
+*/
+}
diff --git a/src/hexen/p_lights.c b/src/hexen/p_lights.c
new file mode 100644
index 00000000..c7e85f9b
--- /dev/null
+++ b/src/hexen/p_lights.c
@@ -0,0 +1,376 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#include "h2def.h"
+#include "m_random.h"
+#include "p_local.h"
+
+//============================================================================
+//
+// T_Light
+//
+//============================================================================
+
+void T_Light(light_t * light)
+{
+ if (light->count)
+ {
+ light->count--;
+ return;
+ }
+ switch (light->type)
+ {
+ case LITE_FADE:
+ light->sector->lightlevel =
+ ((light->sector->lightlevel << FRACBITS) +
+ light->value2) >> FRACBITS;
+ if (light->tics2 == 1)
+ {
+ if (light->sector->lightlevel >= light->value1)
+ {
+ light->sector->lightlevel = light->value1;
+ P_RemoveThinker(&light->thinker);
+ }
+ }
+ else if (light->sector->lightlevel <= light->value1)
+ {
+ light->sector->lightlevel = light->value1;
+ P_RemoveThinker(&light->thinker);
+ }
+ break;
+ case LITE_GLOW:
+ light->sector->lightlevel =
+ ((light->sector->lightlevel << FRACBITS) +
+ light->tics1) >> FRACBITS;
+ if (light->tics2 == 1)
+ {
+ if (light->sector->lightlevel >= light->value1)
+ {
+ light->sector->lightlevel = light->value1;
+ light->tics1 = -light->tics1;
+ light->tics2 = -1; // reverse direction
+ }
+ }
+ else if (light->sector->lightlevel <= light->value2)
+ {
+ light->sector->lightlevel = light->value2;
+ light->tics1 = -light->tics1;
+ light->tics2 = 1; // reverse direction
+ }
+ break;
+ case LITE_FLICKER:
+ if (light->sector->lightlevel == light->value1)
+ {
+ light->sector->lightlevel = light->value2;
+ light->count = (P_Random() & 7) + 1;
+ }
+ else
+ {
+ light->sector->lightlevel = light->value1;
+ light->count = (P_Random() & 31) + 1;
+ }
+ break;
+ case LITE_STROBE:
+ if (light->sector->lightlevel == light->value1)
+ {
+ light->sector->lightlevel = light->value2;
+ light->count = light->tics2;
+ }
+ else
+ {
+ light->sector->lightlevel = light->value1;
+ light->count = light->tics1;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+//============================================================================
+//
+// EV_SpawnLight
+//
+//============================================================================
+
+boolean EV_SpawnLight(line_t * line, byte * arg, lighttype_t type)
+{
+ light_t *light;
+ sector_t *sec;
+ int secNum;
+ int arg1, arg2, arg3, arg4;
+ boolean think;
+ boolean rtn;
+
+ /*
+ Original code; redundant considering that a byte value is always
+ in the range 0-255:
+
+ arg1 = arg[1] > 255 ? 255 : arg[1];
+ arg1 = arg1 < 0 ? 0 : arg1;
+ arg2 = arg[2] > 255 ? 255 : arg[2];
+ arg2 = arg2 < 0 ? 0 : arg2;
+ arg3 = arg[3] > 255 ? 255 : arg[3];
+ arg3 = arg3 < 0 ? 0 : arg3;
+ arg4 = arg[4] > 255 ? 255 : arg[4];
+ arg4 = arg4 < 0 ? 0 : arg4;
+ */
+
+ arg1 = arg[1];
+ arg2 = arg[2];
+ arg3 = arg[3];
+ arg4 = arg[4];
+
+ secNum = -1;
+ rtn = false;
+ think = false;
+ while ((secNum = P_FindSectorFromTag(arg[0], secNum)) >= 0)
+ {
+ think = false;
+ sec = &sectors[secNum];
+
+ light = (light_t *) Z_Malloc(sizeof(light_t), PU_LEVSPEC, 0);
+ light->type = type;
+ light->sector = sec;
+ light->count = 0;
+ rtn = true;
+ switch (type)
+ {
+ case LITE_RAISEBYVALUE:
+ sec->lightlevel += arg1;
+ if (sec->lightlevel > 255)
+ {
+ sec->lightlevel = 255;
+ }
+ break;
+ case LITE_LOWERBYVALUE:
+ sec->lightlevel -= arg1;
+ if (sec->lightlevel < 0)
+ {
+ sec->lightlevel = 0;
+ }
+ break;
+ case LITE_CHANGETOVALUE:
+ sec->lightlevel = arg1;
+ if (sec->lightlevel < 0)
+ {
+ sec->lightlevel = 0;
+ }
+ else if (sec->lightlevel > 255)
+ {
+ sec->lightlevel = 255;
+ }
+ break;
+ case LITE_FADE:
+ think = true;
+ light->value1 = arg1; // destination lightlevel
+ light->value2 = FixedDiv((arg1 - sec->lightlevel) << FRACBITS, arg2 << FRACBITS); // delta lightlevel
+ if (sec->lightlevel <= arg1)
+ {
+ light->tics2 = 1; // get brighter
+ }
+ else
+ {
+ light->tics2 = -1;
+ }
+ break;
+ case LITE_GLOW:
+ think = true;
+ light->value1 = arg1; // upper lightlevel
+ light->value2 = arg2; // lower lightlevel
+ light->tics1 = FixedDiv((arg1 - sec->lightlevel) << FRACBITS, arg3 << FRACBITS); // lightlevel delta
+ if (sec->lightlevel <= arg1)
+ {
+ light->tics2 = 1; // get brighter
+ }
+ else
+ {
+ light->tics2 = -1;
+ }
+ break;
+ case LITE_FLICKER:
+ think = true;
+ light->value1 = arg1; // upper lightlevel
+ light->value2 = arg2; // lower lightlevel
+ sec->lightlevel = light->value1;
+ light->count = (P_Random() & 64) + 1;
+ break;
+ case LITE_STROBE:
+ think = true;
+ light->value1 = arg1; // upper lightlevel
+ light->value2 = arg2; // lower lightlevel
+ light->tics1 = arg3; // upper tics
+ light->tics2 = arg4; // lower tics
+ light->count = arg3;
+ sec->lightlevel = light->value1;
+ break;
+ default:
+ rtn = false;
+ break;
+ }
+ if (think)
+ {
+ P_AddThinker(&light->thinker);
+ light->thinker.function = T_Light;
+ }
+ else
+ {
+ Z_Free(light);
+ }
+ }
+ return rtn;
+}
+
+//============================================================================
+//
+// T_Phase
+//
+//============================================================================
+
+int PhaseTable[64] = {
+ 128, 112, 96, 80, 64, 48, 32, 32,
+ 16, 16, 16, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 16, 16, 16,
+ 32, 32, 48, 64, 80, 96, 112, 128
+};
+
+void T_Phase(phase_t * phase)
+{
+ phase->index = (phase->index + 1) & 63;
+ phase->sector->lightlevel = phase->base + PhaseTable[phase->index];
+}
+
+//==========================================================================
+//
+// P_SpawnPhasedLight
+//
+//==========================================================================
+
+void P_SpawnPhasedLight(sector_t * sector, int base, int index)
+{
+ phase_t *phase;
+
+ phase = Z_Malloc(sizeof(*phase), PU_LEVSPEC, 0);
+ P_AddThinker(&phase->thinker);
+ phase->sector = sector;
+ if (index == -1)
+ { // sector->lightlevel as the index
+ phase->index = sector->lightlevel & 63;
+ }
+ else
+ {
+ phase->index = index & 63;
+ }
+ phase->base = base & 255;
+ sector->lightlevel = phase->base + PhaseTable[phase->index];
+ phase->thinker.function = T_Phase;
+
+ sector->special = 0;
+}
+
+//==========================================================================
+//
+// P_SpawnLightSequence
+//
+//==========================================================================
+
+void P_SpawnLightSequence(sector_t * sector, int indexStep)
+{
+ sector_t *sec;
+ sector_t *nextSec;
+ sector_t *tempSec;
+ int seqSpecial;
+ int i;
+ int count;
+ fixed_t index;
+ fixed_t indexDelta;
+ int base;
+
+ seqSpecial = LIGHT_SEQUENCE; // look for Light_Sequence, first
+ sec = sector;
+ count = 1;
+ do
+ {
+ nextSec = NULL;
+ sec->special = LIGHT_SEQUENCE_START; // make sure that the search doesn't back up.
+ for (i = 0; i < sec->linecount; i++)
+ {
+ tempSec = getNextSector(sec->lines[i], sec);
+ if (!tempSec)
+ {
+ continue;
+ }
+ if (tempSec->special == seqSpecial)
+ {
+ if (seqSpecial == LIGHT_SEQUENCE)
+ {
+ seqSpecial = LIGHT_SEQUENCE_ALT;
+ }
+ else
+ {
+ seqSpecial = LIGHT_SEQUENCE;
+ }
+ nextSec = tempSec;
+ count++;
+ }
+ }
+ sec = nextSec;
+ }
+ while (sec);
+
+ sec = sector;
+ count *= indexStep;
+ index = 0;
+ indexDelta = FixedDiv(64 * FRACUNIT, count * FRACUNIT);
+ base = sector->lightlevel;
+ do
+ {
+ nextSec = NULL;
+ if (sec->lightlevel)
+ {
+ base = sec->lightlevel;
+ }
+ P_SpawnPhasedLight(sec, base, index >> FRACBITS);
+ index += indexDelta;
+ for (i = 0; i < sec->linecount; i++)
+ {
+ tempSec = getNextSector(sec->lines[i], sec);
+ if (!tempSec)
+ {
+ continue;
+ }
+ if (tempSec->special == LIGHT_SEQUENCE_START)
+ {
+ nextSec = tempSec;
+ }
+ }
+ sec = nextSec;
+ }
+ while (sec);
+}
diff --git a/src/hexen/p_local.h b/src/hexen/p_local.h
new file mode 100644
index 00000000..0e61142e
--- /dev/null
+++ b/src/hexen/p_local.h
@@ -0,0 +1,387 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __P_LOCAL__
+#define __P_LOCAL__
+
+#ifndef __R_LOCAL__
+#include "r_local.h"
+#endif
+
+#define STARTREDPALS 1
+#define STARTBONUSPALS 9
+#define STARTPOISONPALS 13
+#define STARTICEPAL 21
+#define STARTHOLYPAL 22
+#define STARTSCOURGEPAL 25
+#define NUMREDPALS 8
+#define NUMBONUSPALS 4
+#define NUMPOISONPALS 8
+
+#define TOCENTER -8
+#define FLOATSPEED (FRACUNIT*4)
+
+#define MAXHEALTH 100
+#define MAXMORPHHEALTH 30
+#define VIEWHEIGHT (48*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 don't 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)
+
+typedef enum
+{
+ DI_EAST,
+ DI_NORTHEAST,
+ DI_NORTH,
+ DI_NORTHWEST,
+ DI_WEST,
+ DI_SOUTHWEST,
+ DI_SOUTH,
+ DI_SOUTHEAST,
+ DI_NODIR,
+ NUMDIRS
+} dirtype_t;
+
+#define BASETHRESHOLD 100 // follow a player exlusively for 3 seconds
+
+// ***** P_TICK *****
+
+extern thinker_t thinkercap; // both the head and tail of the thinker list
+extern int TimerGame; // tic countdown for deathmatch
+
+void P_InitThinkers(void);
+void P_AddThinker(thinker_t * thinker);
+void P_RemoveThinker(thinker_t * thinker);
+
+// ***** P_PSPR *****
+
+#define USE_MANA1 1
+#define USE_MANA2 1
+
+void P_SetPsprite(player_t * player, int position, statenum_t stnum);
+void P_SetPspriteNF(player_t * player, int position, statenum_t stnum);
+void P_SetupPsprites(player_t * curplayer);
+void P_MovePsprites(player_t * curplayer);
+void P_DropWeapon(player_t * player);
+void P_ActivateMorphWeapon(player_t * player);
+void P_PostMorphWeapon(player_t * player, weapontype_t weapon);
+
+// ***** P_USER *****
+
+extern int PStateNormal[NUMCLASSES];
+extern int PStateRun[NUMCLASSES];
+extern int PStateAttack[NUMCLASSES];
+extern int PStateAttackEnd[NUMCLASSES];
+
+void P_PlayerThink(player_t * player);
+void P_Thrust(player_t * player, angle_t angle, fixed_t move);
+void P_PlayerRemoveArtifact(player_t * player, int slot);
+void P_PlayerUseArtifact(player_t * player, artitype_t arti);
+boolean P_UseArtifact(player_t * player, artitype_t arti);
+int P_GetPlayerNum(player_t * player);
+void P_TeleportOther(mobj_t * victim);
+void ResetBlasted(mobj_t * mo);
+
+// ***** P_MOBJ *****
+
+// Any floor type >= FLOOR_LIQUID will floorclip sprites
+enum
+{
+ FLOOR_SOLID,
+ FLOOR_ICE,
+ FLOOR_LIQUID,
+ FLOOR_WATER,
+ FLOOR_LAVA,
+ FLOOR_SLUDGE
+};
+
+#define ONFLOORZ INT_MIN
+#define ONCEILINGZ INT_MAX
+#define FLOATRANDZ (INT_MAX-1)
+#define FROMCEILINGZ128 (INT_MAX-2)
+
+extern mobjtype_t PuffType;
+extern mobj_t *MissileMobj;
+
+mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type);
+void P_RemoveMobj(mobj_t * th);
+boolean P_SetMobjState(mobj_t * mobj, statenum_t state);
+boolean P_SetMobjStateNF(mobj_t * mobj, statenum_t state);
+void P_ThrustMobj(mobj_t * mo, angle_t angle, fixed_t move);
+int P_FaceMobj(mobj_t * source, mobj_t * target, angle_t * delta);
+boolean P_SeekerMissile(mobj_t * actor, angle_t thresh, angle_t turnMax);
+void P_MobjThinker(mobj_t * mobj);
+void P_BlasterMobjThinker(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);
+void P_BloodSplatter(fixed_t x, fixed_t y, fixed_t z, mobj_t * originator);
+void P_BloodSplatter2(fixed_t x, fixed_t y, fixed_t z, mobj_t * originator);
+void P_RipperBlood(mobj_t * mo);
+int P_GetThingFloorType(mobj_t * thing);
+int P_HitFloor(mobj_t * thing);
+boolean P_CheckMissileSpawn(mobj_t * missile);
+mobj_t *P_SpawnMissile(mobj_t * source, mobj_t * dest, mobjtype_t type);
+mobj_t *P_SpawnMissileXYZ(fixed_t x, fixed_t y, fixed_t z,
+ mobj_t * source, mobj_t * dest, mobjtype_t type);
+mobj_t *P_SpawnMissileAngle(mobj_t * source, mobjtype_t type,
+ angle_t angle, fixed_t momz);
+mobj_t *P_SpawnMissileAngleSpeed(mobj_t * source, mobjtype_t type,
+ angle_t angle, fixed_t momz, fixed_t speed);
+mobj_t *P_SpawnPlayerMissile(mobj_t * source, mobjtype_t type);
+mobj_t *P_SPMAngle(mobj_t * source, mobjtype_t type, angle_t angle);
+mobj_t *P_SPMAngleXYZ(mobj_t * source, fixed_t x, fixed_t y,
+ fixed_t z, mobjtype_t type, angle_t angle);
+void P_CreateTIDList(void);
+void P_RemoveMobjFromTIDList(mobj_t * mobj);
+void P_InsertMobjIntoTIDList(mobj_t * mobj, int tid);
+mobj_t *P_FindMobjFromTID(int tid, int *searchPosition);
+mobj_t *P_SpawnKoraxMissile(fixed_t x, fixed_t y, fixed_t z,
+ mobj_t * source, mobj_t * dest, mobjtype_t type);
+
+// ***** P_ENEMY *****
+
+void P_NoiseAlert(mobj_t * target, mobj_t * emmiter);
+int P_Massacre(void);
+boolean A_RaiseMobj(mobj_t * actor);
+boolean A_SinkMobj(mobj_t * actor);
+void A_NoBlocking(mobj_t * actor);
+boolean P_LookForMonsters(mobj_t * actor);
+void P_InitCreatureCorpseQueue(boolean corpseScan);
+void A_DeQueueCorpse(mobj_t * actor);
+
+
+// ***** P_MAPUTL *****
+
+typedef struct
+{
+ fixed_t x, y, dx, dy;
+} divline_t;
+
+typedef struct
+{
+ fixed_t frac; // along trace line
+ boolean isaline;
+ union
+ {
+ mobj_t *thing;
+ line_t *line;
+ } d;
+} intercept_t;
+
+#define MAXINTERCEPTS 128
+extern intercept_t intercepts[MAXINTERCEPTS], *intercept_p;
+typedef 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, openbottom, openrange;
+extern fixed_t lowfloor;
+void P_LineOpening(line_t * linedef);
+
+boolean P_BlockLinesIterator(int x, int y, boolean(*func) (line_t *));
+boolean P_BlockThingsIterator(int x, int y, boolean(*func) (mobj_t *));
+
+#define PT_ADDLINES 1
+#define PT_ADDTHINGS 2
+#define PT_EARLYOUT 4
+
+extern divline_t trace;
+boolean P_PathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2,
+ int flags, boolean(*trav) (intercept_t *));
+
+void P_UnsetThingPosition(mobj_t * thing);
+void P_SetThingPosition(mobj_t * thing);
+mobj_t *P_RoughMonsterSearch(mobj_t * mo, int distance);
+
+// ***** P_MAP *****
+
+extern boolean floatok; // if true, move would be ok if
+extern fixed_t tmfloorz, tmceilingz; // within tmfloorz - tmceilingz
+extern int tmfloorpic;
+extern mobj_t *BlockingMobj;
+
+extern line_t *ceilingline;
+boolean P_TestMobjLocation(mobj_t * mobj);
+boolean P_CheckPosition(mobj_t * thing, fixed_t x, fixed_t y);
+mobj_t *P_CheckOnmobj(mobj_t * thing);
+void P_FakeZMovement(mobj_t * mo);
+boolean P_TryMove(mobj_t * thing, fixed_t x, fixed_t y);
+boolean P_TeleportMove(mobj_t * thing, fixed_t x, fixed_t y);
+void P_SlideMove(mobj_t * mo);
+void P_BounceWall(mobj_t * mo);
+boolean P_CheckSight(mobj_t * t1, mobj_t * t2);
+void P_UseLines(player_t * player);
+boolean P_UsePuzzleItem(player_t * player, int itemType);
+void PIT_ThrustSpike(mobj_t * actor);
+
+boolean P_ChangeSector(sector_t * sector, int crunch);
+
+extern mobj_t *PuffSpawned; // true if a puff was spawned
+extern mobj_t *linetarget; // who got hit (or NULL)
+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, int distance,
+ boolean damageSource);
+
+// ***** P_SETUP *****
+
+extern byte *rejectmatrix; // for fast sight rejection
+extern short *blockmaplump; // offsets in blockmap are from here
+extern short *blockmap;
+extern int bmapwidth, bmapheight; // in mapblocks
+extern fixed_t bmaporgx, bmaporgy; // origin of block map
+extern mobj_t **blocklinks; // for thing chains
+
+// ***** P_INTER *****
+
+extern int clipmana[NUMMANA];
+
+void P_SetMessage(player_t * player, char *message, boolean ultmsg);
+void P_SetYellowMessage(player_t * player, char *message, boolean ultmsg);
+void P_ClearMessage(player_t * player);
+void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher);
+void P_DamageMobj(mobj_t * target, mobj_t * inflictor, mobj_t * source,
+ int damage);
+void P_FallingDamage(player_t * player);
+void P_PoisonPlayer(player_t * player, mobj_t * poisoner, int poison);
+void P_PoisonDamage(player_t * player, mobj_t * source, int damage,
+ boolean playPainSound);
+boolean P_GiveMana(player_t * player, manatype_t mana, int count);
+boolean P_GiveArtifact(player_t * player, artitype_t arti, mobj_t * mo);
+boolean P_GiveArmor(player_t * player, armortype_t armortype, int amount);
+boolean P_GiveBody(player_t * player, int num);
+boolean P_GivePower(player_t * player, powertype_t power);
+boolean P_MorphPlayer(player_t * player);
+
+// ***** AM_MAP *****
+
+boolean AM_Responder(event_t * ev);
+void AM_Ticker(void);
+void AM_Drawer(void);
+
+// ***** A_ACTION *****
+boolean A_LocalQuake(byte * args, mobj_t * victim);
+void P_SpawnDirt(mobj_t * actor, fixed_t radius);
+void A_BridgeRemove(mobj_t * actor);
+
+// ***** SB_BAR *****
+
+extern int SB_state;
+extern int ArtifactFlash;
+void SB_PaletteFlash(boolean forceChange);
+
+// ===== PO_MAN =====
+
+typedef enum
+{
+ PODOOR_NONE,
+ PODOOR_SLIDE,
+ PODOOR_SWING,
+} podoortype_t;
+
+typedef struct
+{
+ thinker_t thinker;
+ int polyobj;
+ int speed;
+ unsigned int dist;
+ int angle;
+ fixed_t xSpeed; // for sliding walls
+ fixed_t ySpeed;
+} polyevent_t;
+
+typedef struct
+{
+ thinker_t thinker;
+ int polyobj;
+ int speed;
+ int dist;
+ int totalDist;
+ int direction;
+ fixed_t xSpeed, ySpeed;
+ int tics;
+ int waitTics;
+ podoortype_t type;
+ boolean close;
+} polydoor_t;
+
+enum
+{
+ PO_ANCHOR_TYPE = 3000,
+ PO_SPAWN_TYPE,
+ PO_SPAWNCRUSH_TYPE
+};
+
+#define PO_LINE_START 1 // polyobj line start special
+#define PO_LINE_EXPLICIT 5
+
+extern polyobj_t *polyobjs; // list of all poly-objects on the level
+extern int po_NumPolyobjs;
+
+void T_PolyDoor(polydoor_t * pd);
+void T_RotatePoly(polyevent_t * pe);
+boolean EV_RotatePoly(line_t * line, byte * args, int direction, boolean
+ overRide);
+void T_MovePoly(polyevent_t * pe);
+boolean EV_MovePoly(line_t * line, byte * args, boolean timesEight, boolean
+ overRide);
+boolean EV_OpenPolyDoor(line_t * line, byte * args, podoortype_t type);
+
+boolean PO_MovePolyobj(int num, int x, int y);
+boolean PO_RotatePolyobj(int num, angle_t angle);
+void PO_Init(int lump);
+boolean PO_Busy(int polyobj);
+
+#include "p_spec.h"
+
+#endif // __P_LOCAL__
diff --git a/src/hexen/p_map.c b/src/hexen/p_map.c
new file mode 100644
index 00000000..ddf9c0e4
--- /dev/null
+++ b/src/hexen/p_map.c
@@ -0,0 +1,2312 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#include "h2def.h"
+#include "m_random.h"
+#include "i_system.h"
+#include "m_bbox.h"
+#include "p_local.h"
+#include "s_sound.h"
+
+static void CheckForPushSpecial(line_t * line, int side, mobj_t * mobj);
+
+/*
+===============================================================================
+
+NOTES:
+
+
+===============================================================================
+*/
+
+/*
+===============================================================================
+
+mobj_t NOTES
+
+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 it's 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 be 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 it's origin contained.
+
+A valid mobj_t is a mobj_t that has the proper subsector_t filled in for it's xy coordinates and is linked into the subsector's sector 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.
+
+
+===============================================================================
+*/
+
+fixed_t tmbbox[4];
+mobj_t *tmthing;
+mobj_t *tsthing;
+int tmflags;
+fixed_t tmx, tmy;
+
+boolean floatok; // if true, move would be ok if
+ // within tmfloorz - tmceilingz
+
+fixed_t tmfloorz, tmceilingz, tmdropoffz;
+int tmfloorpic;
+
+// keep track of the line that lowers the ceiling, so missiles don't explode
+// against sky hack walls
+line_t *ceilingline;
+
+// keep track of special lines as they are hit, but don't process them
+// until the move is proven valid
+#define MAXSPECIALCROSS 8
+line_t *spechit[MAXSPECIALCROSS];
+int numspechit;
+
+mobj_t *onmobj; // generic global onmobj...used for landing on pods/players
+mobj_t *BlockingMobj;
+
+/*
+===============================================================================
+
+ TELEPORT MOVE
+
+===============================================================================
+*/
+
+/*
+==================
+=
+= PIT_StompThing
+=
+==================
+*/
+
+boolean PIT_StompThing(mobj_t * thing)
+{
+ fixed_t blockdist;
+
+ if (!(thing->flags & MF_SHOOTABLE))
+ return true;
+
+ blockdist = thing->radius + tmthing->radius;
+ if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist)
+ return true; // didn't hit it
+
+ if (thing == tmthing)
+ return true; // don't clip against self
+
+ if (!(tmthing->flags2 & MF2_TELESTOMP))
+ { // Not allowed to stomp things
+ return (false);
+ }
+
+ P_DamageMobj(thing, tmthing, tmthing, 10000);
+
+ return true;
+}
+
+
+/*
+===================
+=
+= P_TeleportMove
+=
+===================
+*/
+
+boolean P_TeleportMove(mobj_t * thing, fixed_t x, fixed_t y)
+{
+ int xl, xh, yl, yh, bx, by;
+ subsector_t *newsubsec;
+
+//
+// kill anything occupying the position
+//
+
+ tmthing = thing;
+ tmflags = thing->flags;
+
+ tmx = x;
+ tmy = y;
+
+ tmbbox[BOXTOP] = y + tmthing->radius;
+ tmbbox[BOXBOTTOM] = y - tmthing->radius;
+ tmbbox[BOXRIGHT] = x + tmthing->radius;
+ tmbbox[BOXLEFT] = x - tmthing->radius;
+
+ newsubsec = R_PointInSubsector(x, y);
+ ceilingline = NULL;
+
+//
+// the base floor / ceiling is from the subsector that contains the
+// point. Any contacted lines the step closer together will adjust them
+//
+ tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
+ tmceilingz = newsubsec->sector->ceilingheight;
+ tmfloorpic = newsubsec->sector->floorpic;
+
+ validcount++;
+ numspechit = 0;
+
+//
+// stomp on any things contacted
+//
+ xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS) >> MAPBLOCKSHIFT;
+ xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS) >> MAPBLOCKSHIFT;
+ yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS) >> MAPBLOCKSHIFT;
+ yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS) >> MAPBLOCKSHIFT;
+
+ for (bx = xl; bx <= xh; bx++)
+ for (by = yl; by <= yh; by++)
+ if (!P_BlockThingsIterator(bx, by, PIT_StompThing))
+ return false;
+
+//
+// the move is ok, so link the thing into its new position
+//
+ P_UnsetThingPosition(thing);
+
+ thing->floorz = tmfloorz;
+ thing->ceilingz = tmceilingz;
+ thing->x = x;
+ thing->y = y;
+
+ P_SetThingPosition(thing);
+
+ return true;
+}
+
+
+boolean PIT_ThrustStompThing(mobj_t * thing)
+{
+ fixed_t blockdist;
+
+ if (!(thing->flags & MF_SHOOTABLE))
+ return true;
+
+ blockdist = thing->radius + tsthing->radius;
+ if (abs(thing->x - tsthing->x) >= blockdist ||
+ abs(thing->y - tsthing->y) >= blockdist ||
+ (thing->z > tsthing->z + tsthing->height))
+ return true; // didn't hit it
+
+ if (thing == tsthing)
+ return true; // don't clip against self
+
+ P_DamageMobj(thing, tsthing, tsthing, 10001);
+ tsthing->args[1] = 1; // Mark thrust thing as bloody
+
+ return true;
+}
+
+
+
+void PIT_ThrustSpike(mobj_t * actor)
+{
+ int xl, xh, yl, yh, bx, by;
+ int x0, x2, y0, y2;
+
+ tsthing = actor;
+
+ x0 = actor->x - actor->info->radius;
+ x2 = actor->x + actor->info->radius;
+ y0 = actor->y - actor->info->radius;
+ y2 = actor->y + actor->info->radius;
+
+ xl = (x0 - bmaporgx - MAXRADIUS) >> MAPBLOCKSHIFT;
+ xh = (x2 - bmaporgx + MAXRADIUS) >> MAPBLOCKSHIFT;
+ yl = (y0 - bmaporgy - MAXRADIUS) >> MAPBLOCKSHIFT;
+ yh = (y2 - bmaporgy + MAXRADIUS) >> MAPBLOCKSHIFT;
+
+ // stomp on any things contacted
+ for (bx = xl; bx <= xh; bx++)
+ for (by = yl; by <= yh; by++)
+ P_BlockThingsIterator(bx, by, PIT_ThrustStompThing);
+}
+
+
+
+/*
+===============================================================================
+
+ MOVEMENT ITERATOR FUNCTIONS
+
+===============================================================================
+*/
+
+/*
+==================
+=
+= PIT_CheckLine
+=
+= Adjusts tmfloorz and tmceilingz as lines are contacted
+==================
+*/
+
+boolean PIT_CheckLine(line_t * ld)
+{
+ if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT]
+ || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
+ || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM]
+ || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
+ {
+ return (true);
+ }
+ if (P_BoxOnLineSide(tmbbox, ld) != -1)
+ {
+ return (true);
+ }
+
+// a line has been hit
+/*
+=
+= The moving thing's destination position will cross the given line.
+= If this should not be allowed, return false.
+= If the line is special, keep track of it to process later if the move
+= is proven ok. NOTE: specials are NOT sorted by order, so two special lines
+= that are only 8 pixels apart could be crossed in either order.
+*/
+
+ if (!ld->backsector)
+ { // One sided line
+ if (tmthing->flags2 & MF2_BLASTED)
+ {
+ P_DamageMobj(tmthing, NULL, NULL, tmthing->info->mass >> 5);
+ }
+ CheckForPushSpecial(ld, 0, tmthing);
+ return (false);
+ }
+ if (!(tmthing->flags & MF_MISSILE))
+ {
+ if (ld->flags & ML_BLOCKING)
+ { // Explicitly blocking everything
+ if (tmthing->flags2 & MF2_BLASTED)
+ {
+ P_DamageMobj(tmthing, NULL, NULL, tmthing->info->mass >> 5);
+ }
+ CheckForPushSpecial(ld, 0, tmthing);
+ return (false);
+ }
+ if (!tmthing->player && ld->flags & ML_BLOCKMONSTERS)
+ { // Block monsters only
+ if (tmthing->flags2 & MF2_BLASTED)
+ {
+ P_DamageMobj(tmthing, NULL, NULL, tmthing->info->mass >> 5);
+ }
+ return (false);
+ }
+ }
+ P_LineOpening(ld); // set openrange, opentop, openbottom
+ // adjust floor / ceiling heights
+ if (opentop < tmceilingz)
+ {
+ tmceilingz = opentop;
+ ceilingline = ld;
+ }
+ if (openbottom > tmfloorz)
+ {
+ tmfloorz = openbottom;
+ }
+ if (lowfloor < tmdropoffz)
+ {
+ tmdropoffz = lowfloor;
+ }
+ if (ld->special)
+ { // Contacted a special line, add it to the list
+ spechit[numspechit] = ld;
+ numspechit++;
+ }
+ return (true);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC PIT_CheckThing
+//
+//---------------------------------------------------------------------------
+
+boolean PIT_CheckThing(mobj_t * thing)
+{
+ fixed_t blockdist;
+ boolean solid;
+ int damage;
+
+ if (!(thing->flags & (MF_SOLID | MF_SPECIAL | MF_SHOOTABLE)))
+ { // Can't hit thing
+ return (true);
+ }
+ blockdist = thing->radius + tmthing->radius;
+ if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist)
+ { // Didn't hit thing
+ return (true);
+ }
+ if (thing == tmthing)
+ { // Don't clip against self
+ return (true);
+ }
+ BlockingMobj = thing;
+ if (tmthing->flags2 & MF2_PASSMOBJ)
+ { // check if a mobj passed over/under another object
+ if (tmthing->type == MT_BISHOP && thing->type == MT_BISHOP)
+ { // don't let bishops fly over other bishops
+ return false;
+ }
+ if (tmthing->z >= thing->z + thing->height
+ && !(thing->flags & MF_SPECIAL))
+ {
+ return (true);
+ }
+ else if (tmthing->z + tmthing->height < thing->z
+ && !(thing->flags & MF_SPECIAL))
+ { // under thing
+ return (true);
+ }
+ }
+ // Check for skulls slamming into things
+ if (tmthing->flags & MF_SKULLFLY)
+ {
+ if (tmthing->type == MT_MINOTAUR)
+ {
+ // Slamming minotaurs shouldn't move non-creatures
+ if (!(thing->flags & MF_COUNTKILL))
+ {
+ return (false);
+ }
+ }
+ else if (tmthing->type == MT_HOLY_FX)
+ {
+ if (thing->flags & MF_SHOOTABLE && thing != tmthing->target)
+ {
+ if (netgame && !deathmatch && thing->player)
+ { // don't attack other co-op players
+ return true;
+ }
+ if (thing->flags2 & MF2_REFLECTIVE
+ && (thing->player || thing->flags2 & MF2_BOSS))
+ {
+ tmthing->special1.m = tmthing->target;
+ tmthing->target = thing;
+ return true;
+ }
+ if (thing->flags & MF_COUNTKILL || thing->player)
+ {
+ tmthing->special1.m = thing;
+ }
+ if (P_Random() < 96)
+ {
+ damage = 12;
+ if (thing->player || thing->flags2 & MF2_BOSS)
+ {
+ damage = 3;
+ // ghost burns out faster when attacking players/bosses
+ tmthing->health -= 6;
+ }
+ P_DamageMobj(thing, tmthing, tmthing->target, damage);
+ if (P_Random() < 128)
+ {
+ P_SpawnMobj(tmthing->x, tmthing->y, tmthing->z,
+ MT_HOLY_PUFF);
+ S_StartSound(tmthing, SFX_SPIRIT_ATTACK);
+ if (thing->flags & MF_COUNTKILL && P_Random() < 128
+ && !S_GetSoundPlayingInfo(thing, SFX_PUPPYBEAT))
+ {
+ if ((thing->type == MT_CENTAUR) ||
+ (thing->type == MT_CENTAURLEADER) ||
+ (thing->type == MT_ETTIN))
+ {
+ S_StartSound(thing, SFX_PUPPYBEAT);
+ }
+ }
+ }
+ }
+ if (thing->health <= 0)
+ {
+ tmthing->special1.i = 0;
+ }
+ }
+ return true;
+ }
+ damage = ((P_Random() % 8) + 1) * tmthing->damage;
+ P_DamageMobj(thing, tmthing, tmthing, damage);
+ tmthing->flags &= ~MF_SKULLFLY;
+ tmthing->momx = tmthing->momy = tmthing->momz = 0;
+ P_SetMobjState(tmthing, tmthing->info->seestate);
+ return (false);
+ }
+ // Check for blasted thing running into another
+ if (tmthing->flags2 & MF2_BLASTED && thing->flags & MF_SHOOTABLE)
+ {
+ if (!(thing->flags2 & MF2_BOSS) && (thing->flags & MF_COUNTKILL))
+ {
+ thing->momx += tmthing->momx;
+ thing->momy += tmthing->momy;
+ if ((thing->momx + thing->momy) > 3 * FRACUNIT)
+ {
+ damage = (tmthing->info->mass / 100) + 1;
+ P_DamageMobj(thing, tmthing, tmthing, damage);
+ damage = (thing->info->mass / 100) + 1;
+ P_DamageMobj(tmthing, thing, thing, damage >> 2);
+ }
+ return (false);
+ }
+ }
+ // Check for missile
+ if (tmthing->flags & MF_MISSILE)
+ {
+ // Check for a non-shootable mobj
+ if (thing->flags2 & MF2_NONSHOOTABLE)
+ {
+ return true;
+ }
+ // Check if it went over / under
+ if (tmthing->z > thing->z + thing->height)
+ { // Over thing
+ return (true);
+ }
+ if (tmthing->z + tmthing->height < thing->z)
+ { // Under thing
+ return (true);
+ }
+ if (tmthing->flags2 & MF2_FLOORBOUNCE)
+ {
+ if (tmthing->target == thing || !(thing->flags & MF_SOLID))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ if (tmthing->type == MT_LIGHTNING_FLOOR
+ || tmthing->type == MT_LIGHTNING_CEILING)
+ {
+ if (thing->flags & MF_SHOOTABLE && thing != tmthing->target)
+ {
+ if (thing->info->mass != INT_MAX)
+ {
+ thing->momx += tmthing->momx >> 4;
+ thing->momy += tmthing->momy >> 4;
+ }
+ if ((!thing->player && !(thing->flags2 & MF2_BOSS))
+ || !(leveltime & 1))
+ {
+ if (thing->type == MT_CENTAUR
+ || thing->type == MT_CENTAURLEADER)
+ { // Lightning does more damage to centaurs
+ P_DamageMobj(thing, tmthing, tmthing->target, 9);
+ }
+ else
+ {
+ P_DamageMobj(thing, tmthing, tmthing->target, 3);
+ }
+ if (!(S_GetSoundPlayingInfo(tmthing,
+ SFX_MAGE_LIGHTNING_ZAP)))
+ {
+ S_StartSound(tmthing, SFX_MAGE_LIGHTNING_ZAP);
+ }
+ if (thing->flags & MF_COUNTKILL && P_Random() < 64
+ && !S_GetSoundPlayingInfo(thing, SFX_PUPPYBEAT))
+ {
+ if ((thing->type == MT_CENTAUR) ||
+ (thing->type == MT_CENTAURLEADER) ||
+ (thing->type == MT_ETTIN))
+ {
+ S_StartSound(thing, SFX_PUPPYBEAT);
+ }
+ }
+ }
+ tmthing->health--;
+ if (tmthing->health <= 0 || thing->health <= 0)
+ {
+ return false;
+ }
+ if (tmthing->type == MT_LIGHTNING_FLOOR)
+ {
+ if (tmthing->special2.m
+ && !tmthing->special2.m->special1.m)
+ {
+ tmthing->special2.m->special1.m = thing;
+ }
+ }
+ else if (!tmthing->special1.m)
+ {
+ tmthing->special1.m = thing;
+ }
+ }
+ return true; // lightning zaps through all sprites
+ }
+ else if (tmthing->type == MT_LIGHTNING_ZAP)
+ {
+ mobj_t *lmo;
+
+ if (thing->flags & MF_SHOOTABLE && thing != tmthing->target)
+ {
+ lmo = tmthing->special2.m;
+ if (lmo)
+ {
+ if (lmo->type == MT_LIGHTNING_FLOOR)
+ {
+ if (lmo->special2.m
+ && !lmo->special2.m->special1.m)
+ {
+ lmo->special2.m->special1.m = thing;
+ }
+ }
+ else if (!lmo->special1.m)
+ {
+ lmo->special1.m = thing;
+ }
+ if (!(leveltime & 3))
+ {
+ lmo->health--;
+ }
+ }
+ }
+ }
+ else if (tmthing->type == MT_MSTAFF_FX2 && thing != tmthing->target)
+ {
+ if (!thing->player && !(thing->flags2 & MF2_BOSS))
+ {
+ switch (thing->type)
+ {
+ case MT_FIGHTER_BOSS: // these not flagged boss
+ case MT_CLERIC_BOSS: // so they can be blasted
+ case MT_MAGE_BOSS:
+ break;
+ default:
+ P_DamageMobj(thing, tmthing, tmthing->target, 10);
+ return true;
+ break;
+ }
+ }
+ }
+ if (tmthing->target && tmthing->target->type == thing->type)
+ { // Don't hit same species as originator
+ if (thing == tmthing->target)
+ { // Don't missile self
+ return (true);
+ }
+ if (!thing->player)
+ { // Hit same species as originator, explode, no damage
+ return (false);
+ }
+ }
+ if (!(thing->flags & MF_SHOOTABLE))
+ { // Didn't do any damage
+ return !(thing->flags & MF_SOLID);
+ }
+ if (tmthing->flags2 & MF2_RIP)
+ {
+ if (!(thing->flags & MF_NOBLOOD) &&
+ !(thing->flags2 & MF2_REFLECTIVE) &&
+ !(thing->flags2 & MF2_INVULNERABLE))
+ { // Ok to spawn some blood
+ P_RipperBlood(tmthing);
+ }
+ //S_StartSound(tmthing, sfx_ripslop);
+ damage = ((P_Random() & 3) + 2) * tmthing->damage;
+ P_DamageMobj(thing, tmthing, tmthing->target, damage);
+ if (thing->flags2 & MF2_PUSHABLE
+ && !(tmthing->flags2 & MF2_CANNOTPUSH))
+ { // Push thing
+ thing->momx += tmthing->momx >> 2;
+ thing->momy += tmthing->momy >> 2;
+ }
+ numspechit = 0;
+ return (true);
+ }
+ // Do damage
+ damage = ((P_Random() % 8) + 1) * tmthing->damage;
+ if (damage)
+ {
+ if (!(thing->flags & MF_NOBLOOD) &&
+ !(thing->flags2 & MF2_REFLECTIVE) &&
+ !(thing->flags2 & MF2_INVULNERABLE) &&
+ !(tmthing->type == MT_TELOTHER_FX1) &&
+ !(tmthing->type == MT_TELOTHER_FX2) &&
+ !(tmthing->type == MT_TELOTHER_FX3) &&
+ !(tmthing->type == MT_TELOTHER_FX4) &&
+ !(tmthing->type == MT_TELOTHER_FX5) && (P_Random() < 192))
+ {
+ P_BloodSplatter(tmthing->x, tmthing->y, tmthing->z, thing);
+ }
+ P_DamageMobj(thing, tmthing, tmthing->target, damage);
+ }
+ return (false);
+ }
+ if (thing->flags2 & MF2_PUSHABLE && !(tmthing->flags2 & MF2_CANNOTPUSH))
+ { // Push thing
+ thing->momx += tmthing->momx >> 2;
+ thing->momy += tmthing->momy >> 2;
+ }
+ // Check for special thing
+ if (thing->flags & MF_SPECIAL)
+ {
+ solid = thing->flags & MF_SOLID;
+ if (tmflags & MF_PICKUP)
+ { // Can be picked up by tmthing
+ P_TouchSpecialThing(thing, tmthing); // Can remove thing
+ }
+ return (!solid);
+ }
+ return (!(thing->flags & MF_SOLID));
+}
+
+//---------------------------------------------------------------------------
+//
+// PIT_CheckOnmobjZ
+//
+//---------------------------------------------------------------------------
+
+boolean PIT_CheckOnmobjZ(mobj_t * thing)
+{
+ fixed_t blockdist;
+
+ if (!(thing->flags & (MF_SOLID | MF_SPECIAL | MF_SHOOTABLE)))
+ { // Can't hit thing
+ return (true);
+ }
+ blockdist = thing->radius + tmthing->radius;
+ if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist)
+ { // Didn't hit thing
+ return (true);
+ }
+ if (thing == tmthing)
+ { // Don't clip against self
+ return (true);
+ }
+ if (tmthing->z > thing->z + thing->height)
+ {
+ return (true);
+ }
+ else if (tmthing->z + tmthing->height < thing->z)
+ { // under thing
+ return (true);
+ }
+ if (thing->flags & MF_SOLID)
+ {
+ onmobj = thing;
+ }
+ return (!(thing->flags & MF_SOLID));
+}
+
+/*
+===============================================================================
+
+ MOVEMENT CLIPPING
+
+===============================================================================
+*/
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_TestMobjLocation
+//
+// Returns true if the mobj is not blocked by anything at its current
+// location, otherwise returns false.
+//
+//----------------------------------------------------------------------------
+
+boolean P_TestMobjLocation(mobj_t * mobj)
+{
+ int flags;
+
+ flags = mobj->flags;
+ mobj->flags &= ~MF_PICKUP;
+ if (P_CheckPosition(mobj, mobj->x, mobj->y))
+ { // XY is ok, now check Z
+ mobj->flags = flags;
+ if ((mobj->z < mobj->floorz)
+ || (mobj->z + mobj->height > mobj->ceilingz))
+ { // Bad Z
+ return (false);
+ }
+ return (true);
+ }
+ mobj->flags = flags;
+ return (false);
+}
+
+/*
+==================
+=
+= P_CheckPosition
+=
+= This is purely informative, nothing is modified (except things picked up)
+
+in:
+a mobj_t (can be valid or invalid)
+a position to be checked (doesn't need to be related to the mobj_t->x,y)
+
+during:
+special things are touched if MF_PICKUP
+early out on solid lines?
+
+out:
+newsubsec
+floorz
+ceilingz
+tmdropoffz = the lowest point contacted (monsters won't move to a dropoff)
+speciallines[]
+numspeciallines
+mobj_t *BlockingMobj = pointer to thing that blocked position (NULL if not
+blocked, or blocked by a line).
+
+==================
+*/
+
+boolean P_CheckPosition(mobj_t * thing, fixed_t x, fixed_t y)
+{
+ int xl, xh, yl, yh, bx, by;
+ subsector_t *newsubsec;
+
+ tmthing = thing;
+ tmflags = thing->flags;
+
+ tmx = x;
+ tmy = y;
+
+ tmbbox[BOXTOP] = y + tmthing->radius;
+ tmbbox[BOXBOTTOM] = y - tmthing->radius;
+ tmbbox[BOXRIGHT] = x + tmthing->radius;
+ tmbbox[BOXLEFT] = x - tmthing->radius;
+
+ newsubsec = R_PointInSubsector(x, y);
+ ceilingline = NULL;
+
+//
+// the base floor / ceiling is from the subsector that contains the
+// point. Any contacted lines the step closer together will adjust them
+//
+ tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
+ tmceilingz = newsubsec->sector->ceilingheight;
+ tmfloorpic = newsubsec->sector->floorpic;
+
+ validcount++;
+ numspechit = 0;
+
+ if (tmflags & MF_NOCLIP && !(tmflags & MF_SKULLFLY))
+ {
+ return true;
+ }
+
+//
+// check things first, possibly picking things up
+// the bounding box is extended by MAXRADIUS because mobj_ts are grouped
+// into mapblocks based on their origin point, and can overlap into adjacent
+// blocks by up to MAXRADIUS units
+//
+ xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS) >> MAPBLOCKSHIFT;
+ xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS) >> MAPBLOCKSHIFT;
+ yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS) >> MAPBLOCKSHIFT;
+ yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS) >> MAPBLOCKSHIFT;
+
+ BlockingMobj = NULL;
+ for (bx = xl; bx <= xh; bx++)
+ for (by = yl; by <= yh; by++)
+ if (!P_BlockThingsIterator(bx, by, PIT_CheckThing))
+ return false;
+//
+// check lines
+//
+ if (tmflags & MF_NOCLIP)
+ {
+ return true;
+ }
+
+ BlockingMobj = NULL;
+ xl = (tmbbox[BOXLEFT] - bmaporgx) >> MAPBLOCKSHIFT;
+ xh = (tmbbox[BOXRIGHT] - bmaporgx) >> MAPBLOCKSHIFT;
+ yl = (tmbbox[BOXBOTTOM] - bmaporgy) >> MAPBLOCKSHIFT;
+ yh = (tmbbox[BOXTOP] - bmaporgy) >> MAPBLOCKSHIFT;
+
+ for (bx = xl; bx <= xh; bx++)
+ for (by = yl; by <= yh; by++)
+ if (!P_BlockLinesIterator(bx, by, PIT_CheckLine))
+ return false;
+ return true;
+}
+
+//=============================================================================
+//
+// P_CheckOnmobj(mobj_t *thing)
+//
+// Checks if the new Z position is legal
+//=============================================================================
+
+mobj_t *P_CheckOnmobj(mobj_t * thing)
+{
+ int xl, xh, yl, yh, bx, by;
+ subsector_t *newsubsec;
+ fixed_t x;
+ fixed_t y;
+ mobj_t oldmo;
+
+ x = thing->x;
+ y = thing->y;
+ tmthing = thing;
+ tmflags = thing->flags;
+ oldmo = *thing; // save the old mobj before the fake zmovement
+ P_FakeZMovement(tmthing);
+
+ tmx = x;
+ tmy = y;
+
+ tmbbox[BOXTOP] = y + tmthing->radius;
+ tmbbox[BOXBOTTOM] = y - tmthing->radius;
+ tmbbox[BOXRIGHT] = x + tmthing->radius;
+ tmbbox[BOXLEFT] = x - tmthing->radius;
+
+ newsubsec = R_PointInSubsector(x, y);
+ ceilingline = NULL;
+
+//
+// the base floor / ceiling is from the subsector that contains the
+// point. Any contacted lines the step closer together will adjust them
+//
+ tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
+ tmceilingz = newsubsec->sector->ceilingheight;
+ tmfloorpic = newsubsec->sector->floorpic;
+
+ validcount++;
+ numspechit = 0;
+
+ if (tmflags & MF_NOCLIP)
+ return NULL;
+
+//
+// check things first, possibly picking things up
+// the bounding box is extended by MAXRADIUS because mobj_ts are grouped
+// into mapblocks based on their origin point, and can overlap into adjacent
+// blocks by up to MAXRADIUS units
+//
+ xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS) >> MAPBLOCKSHIFT;
+ xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS) >> MAPBLOCKSHIFT;
+ yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS) >> MAPBLOCKSHIFT;
+ yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS) >> MAPBLOCKSHIFT;
+
+ for (bx = xl; bx <= xh; bx++)
+ for (by = yl; by <= yh; by++)
+ if (!P_BlockThingsIterator(bx, by, PIT_CheckOnmobjZ))
+ {
+ *tmthing = oldmo;
+ return onmobj;
+ }
+ *tmthing = oldmo;
+ return NULL;
+}
+
+//=============================================================================
+//
+// P_FakeZMovement
+//
+// Fake the zmovement so that we can check if a move is legal
+//=============================================================================
+
+void P_FakeZMovement(mobj_t * mo)
+{
+ int dist;
+ int delta;
+//
+// 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;
+ }
+ }
+ if (mo->player && mo->flags2 & MF2_FLY && !(mo->z <= mo->floorz)
+ && leveltime & 2)
+ {
+ mo->z += finesine[(FINEANGLES / 20 * leveltime >> 2) & FINEMASK];
+ }
+
+//
+// clip movement
+//
+ if (mo->z <= mo->floorz)
+ { // Hit the floor
+ mo->z = mo->floorz;
+ if (mo->momz < 0)
+ {
+ mo->momz = 0;
+ }
+ if (mo->flags & MF_SKULLFLY)
+ { // The skull slammed into something
+ mo->momz = -mo->momz;
+ }
+ if (mo->info->crashstate && (mo->flags & MF_CORPSE))
+ {
+ return;
+ }
+ }
+ else if (mo->flags2 & MF2_LOGRAV)
+ {
+ if (mo->momz == 0)
+ mo->momz = -(GRAVITY >> 3) * 2;
+ else
+ mo->momz -= GRAVITY >> 3;
+ }
+ 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;
+ }
+ }
+}
+
+//===========================================================================
+//
+// CheckForPushSpecial
+//
+//===========================================================================
+
+static void CheckForPushSpecial(line_t * line, int side, mobj_t * mobj)
+{
+ if (line->special)
+ {
+ if (mobj->flags2 & MF2_PUSHWALL)
+ {
+ P_ActivateLine(line, mobj, side, SPAC_PUSH);
+ }
+ else if (mobj->flags2 & MF2_IMPACT)
+ {
+ P_ActivateLine(line, mobj, side, SPAC_IMPACT);
+ }
+ }
+}
+
+/*
+===================
+=
+= P_TryMove
+=
+= Attempt to move to a new position, crossing special lines unless MF_TELEPORT
+= is set
+=
+===================
+*/
+
+boolean P_TryMove(mobj_t * thing, fixed_t x, fixed_t y)
+{
+ fixed_t oldx, oldy;
+ int side, oldside;
+ line_t *ld;
+
+ floatok = false;
+ if (!P_CheckPosition(thing, x, y))
+ { // Solid wall or thing
+ if (!BlockingMobj || BlockingMobj->player || !thing->player)
+ {
+ goto pushline;
+ }
+ else if (BlockingMobj->z + BlockingMobj->height - thing->z
+ > 24 * FRACUNIT
+ || (BlockingMobj->subsector->sector->ceilingheight
+ - (BlockingMobj->z + BlockingMobj->height) <
+ thing->height)
+ || (tmceilingz - (BlockingMobj->z + BlockingMobj->height) <
+ thing->height))
+ {
+ goto pushline;
+ }
+ }
+ if (!(thing->flags & MF_NOCLIP))
+ {
+ if (tmceilingz - tmfloorz < thing->height)
+ { // Doesn't fit
+ goto pushline;
+ }
+ floatok = true;
+ if (!(thing->flags & MF_TELEPORT)
+ && tmceilingz - thing->z < thing->height
+ && thing->type != MT_LIGHTNING_CEILING
+ && !(thing->flags2 & MF2_FLY))
+ { // mobj must lower itself to fit
+ goto pushline;
+ }
+ if (thing->flags2 & MF2_FLY)
+ {
+ if (thing->z + thing->height > tmceilingz)
+ {
+ thing->momz = -8 * FRACUNIT;
+ goto pushline;
+ }
+ else if (thing->z < tmfloorz
+ && tmfloorz - tmdropoffz > 24 * FRACUNIT)
+ {
+ thing->momz = 8 * FRACUNIT;
+ goto pushline;
+ }
+ }
+ if (!(thing->flags & MF_TELEPORT)
+ // The Minotaur floor fire (MT_MNTRFX2) can step up any amount
+ && thing->type != MT_MNTRFX2 && thing->type != MT_LIGHTNING_FLOOR
+ && tmfloorz - thing->z > 24 * FRACUNIT)
+ {
+ goto pushline;
+ }
+ if (!(thing->flags & (MF_DROPOFF | MF_FLOAT)) &&
+ (tmfloorz - tmdropoffz > 24 * FRACUNIT) &&
+ !(thing->flags2 & MF2_BLASTED))
+ { // Can't move over a dropoff unless it's been blasted
+ return (false);
+ }
+ if (thing->flags2 & MF2_CANTLEAVEFLOORPIC
+ && (tmfloorpic != thing->subsector->sector->floorpic
+ || tmfloorz - thing->z != 0))
+ { // must stay within a sector of a certain floor type
+ return false;
+ }
+ }
+
+//
+// the move is ok, so link the thing into its new position
+//
+ P_UnsetThingPosition(thing);
+
+ oldx = thing->x;
+ oldy = thing->y;
+ thing->floorz = tmfloorz;
+ thing->ceilingz = tmceilingz;
+ thing->floorpic = tmfloorpic;
+ thing->x = x;
+ thing->y = y;
+
+ P_SetThingPosition(thing);
+
+ if (thing->flags2 & MF2_FLOORCLIP)
+ {
+ if (thing->z == thing->subsector->sector->floorheight
+ && P_GetThingFloorType(thing) >= FLOOR_LIQUID)
+ {
+ thing->floorclip = 10 * FRACUNIT;
+ }
+ else
+ {
+ thing->floorclip = 0;
+ }
+ }
+
+//
+// if any special lines were hit, do the effect
+//
+ if (!(thing->flags & (MF_TELEPORT | MF_NOCLIP)))
+ {
+ while (numspechit > 0)
+ {
+ numspechit--;
+ // see if the line was crossed
+ ld = spechit[numspechit];
+ side = P_PointOnLineSide(thing->x, thing->y, ld);
+ oldside = P_PointOnLineSide(oldx, oldy, ld);
+ if (side != oldside)
+ {
+ if (ld->special)
+ {
+ if (thing->player)
+ {
+ P_ActivateLine(ld, thing, oldside, SPAC_CROSS);
+ }
+ else if (thing->flags2 & MF2_MCROSS)
+ {
+ P_ActivateLine(ld, thing, oldside, SPAC_MCROSS);
+ }
+ else if (thing->flags2 & MF2_PCROSS)
+ {
+ P_ActivateLine(ld, thing, oldside, SPAC_PCROSS);
+ }
+ }
+ }
+ }
+ }
+ return true;
+
+ pushline:
+ if (!(thing->flags & (MF_TELEPORT | MF_NOCLIP)))
+ {
+ int numSpecHitTemp;
+
+ if (tmthing->flags2 & MF2_BLASTED)
+ {
+ P_DamageMobj(tmthing, NULL, NULL, tmthing->info->mass >> 5);
+ }
+ numSpecHitTemp = numspechit;
+ while (numSpecHitTemp > 0)
+ {
+ numSpecHitTemp--;
+ // see if the line was crossed
+ ld = spechit[numSpecHitTemp];
+ side = P_PointOnLineSide(thing->x, thing->y, ld);
+ CheckForPushSpecial(ld, side, thing);
+ }
+ }
+ return false;
+}
+
+/*
+==================
+=
+= P_ThingHeightClip
+=
+= Takes a valid thing and adjusts the thing->floorz, thing->ceilingz,
+= anf possibly thing->z
+=
+= This is called for all nearby monsters whenever a sector changes height
+=
+= If the thing doesn't fit, the z will be set to the lowest value and
+= false will be returned
+==================
+*/
+
+boolean P_ThingHeightClip(mobj_t * thing)
+{
+ boolean onfloor;
+
+ onfloor = (thing->z == thing->floorz);
+
+ P_CheckPosition(thing, thing->x, thing->y);
+ // what about stranding a monster partially off an edge?
+
+ thing->floorz = tmfloorz;
+ thing->ceilingz = tmceilingz;
+ thing->floorpic = tmfloorpic;
+
+ if (onfloor)
+ { // walking monsters rise and fall with the floor
+ if ((thing->z - thing->floorz < 9 * FRACUNIT)
+ || (thing->flags & MF_NOGRAVITY))
+ {
+ thing->z = thing->floorz;
+ }
+ }
+ else
+ { // don't adjust a floating monster unless forced to
+ if (thing->z + thing->height > thing->ceilingz)
+ thing->z = thing->ceilingz - thing->height;
+ }
+
+ if (thing->ceilingz - thing->floorz < thing->height)
+ return false;
+
+ return true;
+}
+
+
+/*
+==============================================================================
+
+ SLIDE MOVE
+
+Allows the player to slide along any angled walls
+
+==============================================================================
+*/
+
+fixed_t bestslidefrac, secondslidefrac;
+line_t *bestslideline, *secondslideline;
+mobj_t *slidemo;
+
+fixed_t tmxmove, tmymove;
+
+/*
+==================
+=
+= P_HitSlideLine
+=
+= Adjusts the xmove / ymove so that the next move will slide along the wall
+==================
+*/
+
+void P_HitSlideLine(line_t * ld)
+{
+ int side;
+ angle_t lineangle, moveangle, deltaangle;
+ fixed_t movelen, newlen;
+
+
+ if (ld->slopetype == ST_HORIZONTAL)
+ {
+ tmymove = 0;
+ return;
+ }
+ if (ld->slopetype == ST_VERTICAL)
+ {
+ tmxmove = 0;
+ return;
+ }
+
+ side = P_PointOnLineSide(slidemo->x, slidemo->y, ld);
+
+ lineangle = R_PointToAngle2(0, 0, ld->dx, ld->dy);
+ if (side == 1)
+ lineangle += ANG180;
+ moveangle = R_PointToAngle2(0, 0, tmxmove, tmymove);
+ deltaangle = moveangle - lineangle;
+ if (deltaangle > ANG180)
+ deltaangle += ANG180;
+// I_Error ("SlideLine: ang>ANG180");
+
+ lineangle >>= ANGLETOFINESHIFT;
+ deltaangle >>= ANGLETOFINESHIFT;
+
+ movelen = P_AproxDistance(tmxmove, tmymove);
+ newlen = FixedMul(movelen, finecosine[deltaangle]);
+ tmxmove = FixedMul(newlen, finecosine[lineangle]);
+ tmymove = FixedMul(newlen, finesine[lineangle]);
+}
+
+/*
+==============
+=
+= PTR_SlideTraverse
+=
+==============
+*/
+
+boolean PTR_SlideTraverse(intercept_t * in)
+{
+ line_t *li;
+
+ if (!in->isaline)
+ I_Error("PTR_SlideTraverse: not a line?");
+
+ li = in->d.line;
+ if (!(li->flags & ML_TWOSIDED))
+ {
+ if (P_PointOnLineSide(slidemo->x, slidemo->y, li))
+ return true; // don't hit the back side
+ goto isblocking;
+ }
+
+ P_LineOpening(li); // set openrange, opentop, openbottom
+ if (openrange < slidemo->height)
+ goto isblocking; // doesn't fit
+
+ if (opentop - slidemo->z < slidemo->height)
+ goto isblocking; // mobj is too high
+
+ if (openbottom - slidemo->z > 24 * FRACUNIT)
+ goto isblocking; // too big a step up
+
+ return true; // this line doesn't block movement
+
+// the line does block movement, see if it is closer than best so far
+ isblocking:
+ if (in->frac < bestslidefrac)
+ {
+ secondslidefrac = bestslidefrac;
+ secondslideline = bestslideline;
+ bestslidefrac = in->frac;
+ bestslideline = li;
+ }
+
+ return false; // stop
+}
+
+
+/*
+==================
+=
+= P_SlideMove
+=
+= The momx / momy move is bad, so try to slide along a wall
+=
+= Find the first line hit, move flush to it, and slide along it
+=
+= This is a kludgy mess.
+==================
+*/
+
+void P_SlideMove(mobj_t * mo)
+{
+ fixed_t leadx, leady;
+ fixed_t trailx, traily;
+ fixed_t newx, newy;
+ int hitcount;
+
+ slidemo = mo;
+ hitcount = 0;
+ retry:
+ if (++hitcount == 3)
+ goto stairstep; // don't loop forever
+
+//
+// trace along the three leading corners
+//
+ if (mo->momx > 0)
+ {
+ leadx = mo->x + mo->radius;
+ trailx = mo->x - mo->radius;
+ }
+ else
+ {
+ leadx = mo->x - mo->radius;
+ trailx = mo->x + mo->radius;
+ }
+
+ if (mo->momy > 0)
+ {
+ leady = mo->y + mo->radius;
+ traily = mo->y - mo->radius;
+ }
+ else
+ {
+ leady = mo->y - mo->radius;
+ traily = mo->y + mo->radius;
+ }
+
+ bestslidefrac = FRACUNIT + 1;
+
+ P_PathTraverse(leadx, leady, leadx + mo->momx, leady + mo->momy,
+ PT_ADDLINES, PTR_SlideTraverse);
+ P_PathTraverse(trailx, leady, trailx + mo->momx, leady + mo->momy,
+ PT_ADDLINES, PTR_SlideTraverse);
+ P_PathTraverse(leadx, traily, leadx + mo->momx, traily + mo->momy,
+ PT_ADDLINES, PTR_SlideTraverse);
+
+//
+// move up to the wall
+//
+ if (bestslidefrac == FRACUNIT + 1)
+ { // the move must have hit the middle, so stairstep
+ stairstep:
+ if (!P_TryMove(mo, mo->x, mo->y + mo->momy))
+ {
+ P_TryMove(mo, mo->x + mo->momx, mo->y);
+ }
+ return;
+ }
+
+ bestslidefrac -= 0x800; // fudge a bit to make sure it doesn't hit
+ if (bestslidefrac > 0)
+ {
+ newx = FixedMul(mo->momx, bestslidefrac);
+ newy = FixedMul(mo->momy, bestslidefrac);
+ if (!P_TryMove(mo, mo->x + newx, mo->y + newy))
+ goto stairstep;
+ }
+
+//
+// now continue along the wall
+//
+ bestslidefrac = FRACUNIT - (bestslidefrac + 0x800); // remainder
+ if (bestslidefrac > FRACUNIT)
+ bestslidefrac = FRACUNIT;
+ if (bestslidefrac <= 0)
+ return;
+
+ tmxmove = FixedMul(mo->momx, bestslidefrac);
+ tmymove = FixedMul(mo->momy, bestslidefrac);
+
+ P_HitSlideLine(bestslideline); // clip the moves
+
+ mo->momx = tmxmove;
+ mo->momy = tmymove;
+
+ if (!P_TryMove(mo, mo->x + tmxmove, mo->y + tmymove))
+ {
+ goto retry;
+ }
+}
+
+//============================================================================
+//
+// PTR_BounceTraverse
+//
+//============================================================================
+
+boolean PTR_BounceTraverse(intercept_t * in)
+{
+ line_t *li;
+
+ if (!in->isaline)
+ I_Error("PTR_BounceTraverse: not a line?");
+
+ li = in->d.line;
+ if (!(li->flags & ML_TWOSIDED))
+ {
+ if (P_PointOnLineSide(slidemo->x, slidemo->y, li))
+ return true; // don't hit the back side
+ goto bounceblocking;
+ }
+
+ P_LineOpening(li); // set openrange, opentop, openbottom
+ if (openrange < slidemo->height)
+ goto bounceblocking; // doesn't fit
+
+ if (opentop - slidemo->z < slidemo->height)
+ goto bounceblocking; // mobj is too high
+ return true; // this line doesn't block movement
+
+// the line does block movement, see if it is closer than best so far
+ bounceblocking:
+ if (in->frac < bestslidefrac)
+ {
+ secondslidefrac = bestslidefrac;
+ secondslideline = bestslideline;
+ bestslidefrac = in->frac;
+ bestslideline = li;
+ }
+ return false; // stop
+}
+
+//============================================================================
+//
+// P_BounceWall
+//
+//============================================================================
+
+void P_BounceWall(mobj_t * mo)
+{
+ fixed_t leadx, leady;
+ int side;
+ angle_t lineangle, moveangle, deltaangle;
+ fixed_t movelen;
+
+ slidemo = mo;
+
+//
+// trace along the three leading corners
+//
+ if (mo->momx > 0)
+ {
+ leadx = mo->x + mo->radius;
+ }
+ else
+ {
+ leadx = mo->x - mo->radius;
+ }
+ if (mo->momy > 0)
+ {
+ leady = mo->y + mo->radius;
+ }
+ else
+ {
+ leady = mo->y - mo->radius;
+ }
+ bestslidefrac = FRACUNIT + 1;
+ P_PathTraverse(leadx, leady, leadx + mo->momx, leady + mo->momy,
+ PT_ADDLINES, PTR_BounceTraverse);
+
+ side = P_PointOnLineSide(mo->x, mo->y, bestslideline);
+ lineangle = R_PointToAngle2(0, 0, bestslideline->dx, bestslideline->dy);
+ if (side == 1)
+ lineangle += ANG180;
+ moveangle = R_PointToAngle2(0, 0, mo->momx, mo->momy);
+ deltaangle = (2 * lineangle) - moveangle;
+// if (deltaangle > ANG180)
+// deltaangle += ANG180;
+// I_Error ("SlideLine: ang>ANG180");
+
+ lineangle >>= ANGLETOFINESHIFT;
+ deltaangle >>= ANGLETOFINESHIFT;
+
+ movelen = P_AproxDistance(mo->momx, mo->momy);
+ movelen = FixedMul(movelen, 0.75 * FRACUNIT); // friction
+ if (movelen < FRACUNIT)
+ movelen = 2 * FRACUNIT;
+ mo->momx = FixedMul(movelen, finecosine[deltaangle]);
+ mo->momy = FixedMul(movelen, finesine[deltaangle]);
+}
+
+
+/*
+==============================================================================
+
+ P_LineAttack
+
+==============================================================================
+*/
+
+
+mobj_t *PuffSpawned;
+mobj_t *linetarget; // who got hit (or NULL)
+mobj_t *shootthing;
+fixed_t shootz; // height if not aiming up or down
+ // ???: use slope for monsters?
+int la_damage;
+fixed_t attackrange;
+
+fixed_t aimslope;
+
+extern fixed_t topslope, bottomslope; // slopes to top and bottom of target
+
+/*
+===============================================================================
+=
+= PTR_AimTraverse
+=
+= Sets linetaget and aimslope when a target is aimed at
+===============================================================================
+*/
+
+boolean PTR_AimTraverse(intercept_t * in)
+{
+ line_t *li;
+ mobj_t *th;
+ fixed_t slope, thingtopslope, thingbottomslope;
+ fixed_t dist;
+
+ if (in->isaline)
+ {
+ li = in->d.line;
+ if (!(li->flags & ML_TWOSIDED))
+ return false; // stop
+//
+// crosses a two sided line
+// a two sided line will restrict the possible target ranges
+ P_LineOpening(li);
+
+ if (openbottom >= opentop)
+ return false; // stop
+
+ dist = FixedMul(attackrange, in->frac);
+
+ if (li->frontsector->floorheight != li->backsector->floorheight)
+ {
+ slope = FixedDiv(openbottom - shootz, dist);
+ if (slope > bottomslope)
+ bottomslope = slope;
+ }
+
+ if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
+ {
+ slope = FixedDiv(opentop - shootz, dist);
+ if (slope < topslope)
+ topslope = slope;
+ }
+
+ if (topslope <= bottomslope)
+ return false; // stop
+
+ return true; // shot continues
+ }
+
+//
+// shoot a thing
+//
+ th = in->d.thing;
+ if (th == shootthing)
+ return true; // can't shoot self
+ if (!(th->flags & MF_SHOOTABLE))
+ { // corpse or something
+ return true;
+ }
+ if (th->player && netgame && !deathmatch)
+ { // don't aim at fellow co-op players
+ return true;
+ }
+
+// check angles to see if the thing can be aimed at
+
+ dist = FixedMul(attackrange, in->frac);
+ thingtopslope = FixedDiv(th->z + th->height - shootz, dist);
+ if (thingtopslope < bottomslope)
+ return true; // shot over the thing
+ thingbottomslope = FixedDiv(th->z - shootz, dist);
+ if (thingbottomslope > topslope)
+ return true; // shot under the thing
+
+//
+// this thing can be hit!
+//
+ if (thingtopslope > topslope)
+ thingtopslope = topslope;
+ if (thingbottomslope < bottomslope)
+ thingbottomslope = bottomslope;
+
+ aimslope = (thingtopslope + thingbottomslope) / 2;
+ linetarget = th;
+
+ return false; // don't go any farther
+}
+
+
+/*
+==============================================================================
+=
+= PTR_ShootTraverse
+=
+==============================================================================
+*/
+
+boolean PTR_ShootTraverse(intercept_t * in)
+{
+ fixed_t x, y, z;
+ fixed_t frac;
+ line_t *li;
+ mobj_t *th;
+ fixed_t slope;
+ fixed_t dist;
+ fixed_t thingtopslope, thingbottomslope;
+
+ extern mobj_t LavaInflictor;
+
+ if (in->isaline)
+ {
+ li = in->d.line;
+ if (li->special)
+ {
+ P_ActivateLine(li, shootthing, 0, SPAC_IMPACT);
+// P_ShootSpecialLine (shootthing, li);
+ }
+ if (!(li->flags & ML_TWOSIDED))
+ goto hitline;
+
+//
+// crosses a two sided line
+//
+ P_LineOpening(li);
+
+ dist = FixedMul(attackrange, in->frac);
+
+ if (li->frontsector->floorheight != li->backsector->floorheight)
+ {
+ slope = FixedDiv(openbottom - shootz, dist);
+ if (slope > aimslope)
+ goto hitline;
+ }
+
+ if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
+ {
+ slope = FixedDiv(opentop - shootz, dist);
+ if (slope < aimslope)
+ goto hitline;
+ }
+
+ return true; // shot continues
+//
+// hit line
+//
+ hitline:
+ // position a bit closer
+ frac = in->frac - FixedDiv(4 * FRACUNIT, attackrange);
+ x = trace.x + FixedMul(trace.dx, frac);
+ y = trace.y + FixedMul(trace.dy, frac);
+ z = shootz + FixedMul(aimslope, FixedMul(frac, attackrange));
+
+ if (li->frontsector->ceilingpic == skyflatnum)
+ {
+ if (z > li->frontsector->ceilingheight)
+ return false; // don't shoot the sky!
+ if (li->backsector && li->backsector->ceilingpic == skyflatnum)
+ return false; // it's a sky hack wall
+ }
+
+ P_SpawnPuff(x, y, z);
+ return false; // don't go any farther
+ }
+
+//
+// shoot a thing
+//
+ th = in->d.thing;
+ if (th == shootthing)
+ return true; // can't shoot self
+ if (!(th->flags & MF_SHOOTABLE))
+ return true; // corpse or something
+
+//
+// check for physical attacks on a ghost
+//
+/* FIX: Impliment Heretic 2 weapons here
+ if(th->flags&MF_SHADOW && shootthing->player->readyweapon == wp_staff)
+ {
+ return(true);
+ }
+*/
+
+// check angles to see if the thing can be aimed at
+ dist = FixedMul(attackrange, in->frac);
+ thingtopslope = FixedDiv(th->z + th->height - shootz, dist);
+ if (thingtopslope < aimslope)
+ return true; // shot over the thing
+ thingbottomslope = FixedDiv(th->z - shootz, dist);
+ if (thingbottomslope > aimslope)
+ return true; // shot under the thing
+
+//
+// hit thing
+//
+ // position a bit closer
+ frac = in->frac - FixedDiv(10 * FRACUNIT, attackrange);
+ x = trace.x + FixedMul(trace.dx, frac);
+ y = trace.y + FixedMul(trace.dy, frac);
+ z = shootz + FixedMul(aimslope, FixedMul(frac, attackrange));
+ P_SpawnPuff(x, y, z);
+ if (la_damage)
+ {
+ if (!(in->d.thing->flags & MF_NOBLOOD) &&
+ !(in->d.thing->flags2 & MF2_INVULNERABLE))
+ {
+ if (PuffType == MT_AXEPUFF || PuffType == MT_AXEPUFF_GLOW)
+ {
+ P_BloodSplatter2(x, y, z, in->d.thing);
+ }
+ if (P_Random() < 192)
+ {
+ P_BloodSplatter(x, y, z, in->d.thing);
+ }
+ }
+ if (PuffType == MT_FLAMEPUFF2)
+ { // Cleric FlameStrike does fire damage
+ P_DamageMobj(th, &LavaInflictor, shootthing, la_damage);
+ }
+ else
+ {
+ P_DamageMobj(th, shootthing, shootthing, la_damage);
+ }
+ }
+ return (false); // don't go any farther
+}
+
+/*
+=================
+=
+= P_AimLineAttack
+=
+=================
+*/
+
+fixed_t P_AimLineAttack(mobj_t * t1, angle_t angle, fixed_t distance)
+{
+ fixed_t x2, y2;
+
+ angle >>= ANGLETOFINESHIFT;
+ shootthing = t1;
+ x2 = t1->x + (distance >> FRACBITS) * finecosine[angle];
+ y2 = t1->y + (distance >> FRACBITS) * finesine[angle];
+ shootz = t1->z + (t1->height >> 1) + 8 * FRACUNIT;
+ topslope = 100 * FRACUNIT / 160; // can't shoot outside view angles
+ bottomslope = -100 * FRACUNIT / 160;
+ attackrange = distance;
+ linetarget = NULL;
+
+ P_PathTraverse(t1->x, t1->y, x2, y2, PT_ADDLINES | PT_ADDTHINGS,
+ PTR_AimTraverse);
+
+ if (linetarget)
+ return aimslope;
+ return 0;
+}
+
+
+
+/*
+=================
+=
+= P_LineAttack
+=
+= if damage == 0, it is just a test trace that will leave linetarget set
+=
+=================
+*/
+
+void P_LineAttack(mobj_t * t1, angle_t angle, fixed_t distance, fixed_t slope,
+ int damage)
+{
+ fixed_t x2, y2;
+
+ angle >>= ANGLETOFINESHIFT;
+ shootthing = t1;
+ la_damage = damage;
+ x2 = t1->x + (distance >> FRACBITS) * finecosine[angle];
+ y2 = t1->y + (distance >> FRACBITS) * finesine[angle];
+ shootz = t1->z + (t1->height >> 1) + 8 * FRACUNIT;
+ shootz -= t1->floorclip;
+ attackrange = distance;
+ aimslope = slope;
+
+ if (P_PathTraverse(t1->x, t1->y, x2, y2, PT_ADDLINES | PT_ADDTHINGS,
+ PTR_ShootTraverse))
+ {
+ switch (PuffType)
+ {
+ case MT_PUNCHPUFF:
+ S_StartSound(t1, SFX_FIGHTER_PUNCH_MISS);
+ break;
+ case MT_HAMMERPUFF:
+ case MT_AXEPUFF:
+ case MT_AXEPUFF_GLOW:
+ S_StartSound(t1, SFX_FIGHTER_HAMMER_MISS);
+ break;
+ case MT_FLAMEPUFF:
+ P_SpawnPuff(x2, y2, shootz + FixedMul(slope, distance));
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/*
+==============================================================================
+
+ USE LINES
+
+==============================================================================
+*/
+
+mobj_t *usething;
+
+boolean PTR_UseTraverse(intercept_t * in)
+{
+ int sound;
+ fixed_t pheight;
+
+ if (!in->d.line->special)
+ {
+ P_LineOpening(in->d.line);
+ if (openrange <= 0)
+ {
+ if (usething->player)
+ {
+ switch (usething->player->class)
+ {
+ case PCLASS_FIGHTER:
+ sound = SFX_PLAYER_FIGHTER_FAILED_USE;
+ break;
+ case PCLASS_CLERIC:
+ sound = SFX_PLAYER_CLERIC_FAILED_USE;
+ break;
+ case PCLASS_MAGE:
+ sound = SFX_PLAYER_MAGE_FAILED_USE;
+ break;
+ case PCLASS_PIG:
+ sound = SFX_PIG_ACTIVE1;
+ break;
+ default:
+ sound = SFX_NONE;
+ break;
+ }
+ S_StartSound(usething, sound);
+ }
+ return false; // can't use through a wall
+ }
+ if (usething->player)
+ {
+ pheight = usething->z + (usething->height / 2);
+ if ((opentop < pheight) || (openbottom > pheight))
+ {
+ switch (usething->player->class)
+ {
+ case PCLASS_FIGHTER:
+ sound = SFX_PLAYER_FIGHTER_FAILED_USE;
+ break;
+ case PCLASS_CLERIC:
+ sound = SFX_PLAYER_CLERIC_FAILED_USE;
+ break;
+ case PCLASS_MAGE:
+ sound = SFX_PLAYER_MAGE_FAILED_USE;
+ break;
+ case PCLASS_PIG:
+ sound = SFX_PIG_ACTIVE1;
+ break;
+ default:
+ sound = SFX_NONE;
+ break;
+ }
+ S_StartSound(usething, sound);
+ }
+ }
+ return true; // not a special line, but keep checking
+ }
+
+ if (P_PointOnLineSide(usething->x, usething->y, in->d.line) == 1)
+ return false; // don't use back sides
+
+// P_UseSpecialLine (usething, in->d.line);
+ P_ActivateLine(in->d.line, usething, 0, SPAC_USE);
+
+ return false; // can't use for than one special line in a row
+}
+
+
+/*
+================
+=
+= P_UseLines
+=
+= Looks for special lines in front of the player to activate
+================
+*/
+
+void P_UseLines(player_t * player)
+{
+ int angle;
+ fixed_t x1, y1, x2, y2;
+
+ usething = player->mo;
+
+ angle = player->mo->angle >> ANGLETOFINESHIFT;
+ x1 = player->mo->x;
+ y1 = player->mo->y;
+ x2 = x1 + (USERANGE >> FRACBITS) * finecosine[angle];
+ y2 = y1 + (USERANGE >> FRACBITS) * finesine[angle];
+
+ P_PathTraverse(x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse);
+}
+
+//==========================================================================
+//
+// PTR_PuzzleItemTraverse
+//
+//==========================================================================
+
+#define USE_PUZZLE_ITEM_SPECIAL 129
+
+static mobj_t *PuzzleItemUser;
+static int PuzzleItemType;
+static boolean PuzzleActivated;
+
+boolean PTR_PuzzleItemTraverse(intercept_t * in)
+{
+ mobj_t *mobj;
+ int sound;
+
+ if (in->isaline)
+ { // Check line
+ if (in->d.line->special != USE_PUZZLE_ITEM_SPECIAL)
+ {
+ P_LineOpening(in->d.line);
+ if (openrange <= 0)
+ {
+ sound = SFX_NONE;
+ if (PuzzleItemUser->player)
+ {
+ switch (PuzzleItemUser->player->class)
+ {
+ case PCLASS_FIGHTER:
+ sound = SFX_PUZZLE_FAIL_FIGHTER;
+ break;
+ case PCLASS_CLERIC:
+ sound = SFX_PUZZLE_FAIL_CLERIC;
+ break;
+ case PCLASS_MAGE:
+ sound = SFX_PUZZLE_FAIL_MAGE;
+ break;
+ default:
+ sound = SFX_NONE;
+ break;
+ }
+ }
+ S_StartSound(PuzzleItemUser, sound);
+ return false; // can't use through a wall
+ }
+ return true; // Continue searching
+ }
+ if (P_PointOnLineSide(PuzzleItemUser->x, PuzzleItemUser->y,
+ in->d.line) == 1)
+ { // Don't use back sides
+ return false;
+ }
+ if (PuzzleItemType != in->d.line->arg1)
+ { // Item type doesn't match
+ return false;
+ }
+ P_StartACS(in->d.line->arg2, 0, &in->d.line->arg3,
+ PuzzleItemUser, in->d.line, 0);
+ in->d.line->special = 0;
+ PuzzleActivated = true;
+ return false; // Stop searching
+ }
+ // Check thing
+ mobj = in->d.thing;
+ if (mobj->special != USE_PUZZLE_ITEM_SPECIAL)
+ { // Wrong special
+ return true;
+ }
+ if (PuzzleItemType != mobj->args[0])
+ { // Item type doesn't match
+ return true;
+ }
+ P_StartACS(mobj->args[1], 0, &mobj->args[2], PuzzleItemUser, NULL, 0);
+ mobj->special = 0;
+ PuzzleActivated = true;
+ return false; // Stop searching
+}
+
+//==========================================================================
+//
+// P_UsePuzzleItem
+//
+// Returns true if the puzzle item was used on a line or a thing.
+//
+//==========================================================================
+
+boolean P_UsePuzzleItem(player_t * player, int itemType)
+{
+ int angle;
+ fixed_t x1, y1, x2, y2;
+
+ PuzzleItemType = itemType;
+ PuzzleItemUser = player->mo;
+ PuzzleActivated = false;
+ angle = player->mo->angle >> ANGLETOFINESHIFT;
+ x1 = player->mo->x;
+ y1 = player->mo->y;
+ x2 = x1 + (USERANGE >> FRACBITS) * finecosine[angle];
+ y2 = y1 + (USERANGE >> FRACBITS) * finesine[angle];
+ P_PathTraverse(x1, y1, x2, y2, PT_ADDLINES | PT_ADDTHINGS,
+ PTR_PuzzleItemTraverse);
+ return PuzzleActivated;
+}
+
+/*
+==============================================================================
+
+ RADIUS ATTACK
+
+==============================================================================
+*/
+
+mobj_t *bombsource;
+mobj_t *bombspot;
+int bombdamage;
+int bombdistance;
+boolean DamageSource;
+
+/*
+=================
+=
+= PIT_RadiusAttack
+=
+= Source is the creature that casued the explosion at spot
+=================
+*/
+
+boolean PIT_RadiusAttack(mobj_t * thing)
+{
+ fixed_t dx, dy, dist;
+ int damage;
+
+ if (!(thing->flags & MF_SHOOTABLE))
+ {
+ return true;
+ }
+// if(thing->flags2&MF2_BOSS)
+// { // Bosses take no damage from PIT_RadiusAttack
+// return(true);
+// }
+ if (!DamageSource && thing == bombsource)
+ { // don't damage the source of the explosion
+ return true;
+ }
+ if (abs((thing->z - bombspot->z) >> FRACBITS) > 2 * bombdistance)
+ { // too high/low
+ return true;
+ }
+ dx = abs(thing->x - bombspot->x);
+ dy = abs(thing->y - bombspot->y);
+ dist = dx > dy ? dx : dy;
+ dist = (dist - thing->radius) >> FRACBITS;
+ if (dist < 0)
+ {
+ dist = 0;
+ }
+ if (dist >= bombdistance)
+ { // Out of range
+ return true;
+ }
+ if (P_CheckSight(thing, bombspot))
+ { // OK to damage, target is in direct path
+ damage = (bombdamage * (bombdistance - dist) / bombdistance) + 1;
+ if (thing->player)
+ {
+ damage >>= 2;
+ }
+ P_DamageMobj(thing, bombspot, bombsource, damage);
+ }
+ return (true);
+}
+
+/*
+=================
+=
+= P_RadiusAttack
+=
+= Source is the creature that caused the explosion at spot
+=================
+*/
+
+void P_RadiusAttack(mobj_t * spot, mobj_t * source, int damage, int distance,
+ boolean damageSource)
+{
+ int x, y, xl, xh, yl, yh;
+ fixed_t dist;
+
+ dist = (distance + MAXRADIUS) << FRACBITS;
+ yh = (spot->y + dist - bmaporgy) >> MAPBLOCKSHIFT;
+ yl = (spot->y - dist - bmaporgy) >> MAPBLOCKSHIFT;
+ xh = (spot->x + dist - bmaporgx) >> MAPBLOCKSHIFT;
+ xl = (spot->x - dist - bmaporgx) >> MAPBLOCKSHIFT;
+ bombspot = spot;
+ bombsource = source;
+ bombdamage = damage;
+ bombdistance = distance;
+ DamageSource = damageSource;
+ for (y = yl; y <= yh; y++)
+ {
+ for (x = xl; x <= xh; x++)
+ {
+ P_BlockThingsIterator(x, y, PIT_RadiusAttack);
+ }
+ }
+}
+
+/*
+==============================================================================
+
+ SECTOR HEIGHT CHANGING
+
+= After modifying a sectors floor or ceiling height, call this
+= routine to adjust the positions of all things that touch the
+= sector.
+=
+= If anything doesn't fit anymore, true will be returned.
+= If crunch is true, they will take damage as they are being crushed
+= If Crunch is false, you should set the sector height back the way it
+= was and call P_ChangeSector again to undo the changes
+==============================================================================
+*/
+
+int crushchange;
+boolean nofit;
+
+/*
+===============
+=
+= PIT_ChangeSector
+=
+===============
+*/
+
+boolean PIT_ChangeSector(mobj_t * thing)
+{
+ mobj_t *mo;
+
+ if (P_ThingHeightClip(thing))
+ return true; // keep checking
+
+ // crunch bodies to giblets
+ if ((thing->flags & MF_CORPSE) && (thing->health <= 0))
+ {
+ if (thing->flags & MF_NOBLOOD)
+ {
+ P_RemoveMobj(thing);
+ }
+ else
+ {
+ if (thing->state != &states[S_GIBS1])
+ {
+ P_SetMobjState(thing, S_GIBS1);
+ thing->height = 0;
+ thing->radius = 0;
+ S_StartSound(thing, SFX_PLAYER_FALLING_SPLAT);
+ }
+ }
+ return true; // keep checking
+ }
+
+ // crunch dropped items
+ if (thing->flags2 & MF2_DROPPED)
+ {
+ P_RemoveMobj(thing);
+ return true; // keep checking
+ }
+
+ if (!(thing->flags & MF_SHOOTABLE))
+ return true; // assume it is bloody gibs or something
+
+ nofit = true;
+ if (crushchange && !(leveltime & 3))
+ {
+ P_DamageMobj(thing, NULL, NULL, crushchange);
+ // spray blood in a random direction
+ if ((!(thing->flags & MF_NOBLOOD)) &&
+ (!(thing->flags2 & MF2_INVULNERABLE)))
+ {
+ mo = P_SpawnMobj(thing->x, thing->y, thing->z + thing->height / 2,
+ MT_BLOOD);
+ mo->momx = (P_Random() - P_Random()) << 12;
+ mo->momy = (P_Random() - P_Random()) << 12;
+ }
+ }
+
+ return true; // keep checking (crush other things)
+}
+
+/*
+===============
+=
+= P_ChangeSector
+=
+===============
+*/
+
+boolean P_ChangeSector(sector_t * sector, int crunch)
+{
+ int x, y;
+
+ nofit = false;
+ crushchange = crunch;
+
+// recheck heights for all things near the moving sector
+
+ for (x = sector->blockbox[BOXLEFT]; x <= sector->blockbox[BOXRIGHT]; x++)
+ for (y = sector->blockbox[BOXBOTTOM]; y <= sector->blockbox[BOXTOP];
+ y++)
+ P_BlockThingsIterator(x, y, PIT_ChangeSector);
+
+
+ return nofit;
+}
diff --git a/src/hexen/p_maputl.c b/src/hexen/p_maputl.c
new file mode 100644
index 00000000..f7790540
--- /dev/null
+++ b/src/hexen/p_maputl.c
@@ -0,0 +1,1078 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#include "h2def.h"
+#include "i_system.h"
+#include "m_bbox.h"
+#include "p_local.h"
+
+static mobj_t *RoughBlockCheck(mobj_t * mo, int index);
+
+/*
+===================
+=
+= P_AproxDistance
+=
+= Gives an estimation of distance (not exact)
+=
+===================
+*/
+
+fixed_t P_AproxDistance(fixed_t dx, fixed_t dy)
+{
+ dx = abs(dx);
+ dy = 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, dy;
+ fixed_t left, 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 = 0, p2 = 0;
+
+ 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, dy;
+ fixed_t left, 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)
+{
+#if 1
+ fixed_t frac, num, 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;
+#else
+ float frac, num, den, v1x, v1y, v1dx, v1dy, v2x, v2y, v2dx, v2dy;
+
+ v1x = (float) v1->x / FRACUNIT;
+ v1y = (float) v1->y / FRACUNIT;
+ v1dx = (float) v1->dx / FRACUNIT;
+ v1dy = (float) v1->dy / FRACUNIT;
+ v2x = (float) v2->x / FRACUNIT;
+ v2y = (float) v2->y / FRACUNIT;
+ v2dx = (float) v2->dx / FRACUNIT;
+ v2dy = (float) v2->dy / FRACUNIT;
+
+ den = v1dy * v2dx - v1dx * v2dy;
+ if (den == 0)
+ return 0; // parallel
+ num = (v1x - v2x) * v1dy + (v2y - v1y) * v1dx;
+ frac = num / den;
+
+ return frac * FRACUNIT;
+#endif
+}
+
+/*
+==================
+=
+= P_LineOpening
+=
+= Sets opentop and openbottom to the window through a two sided line
+= OPTIMIZE: keep this precalculated
+==================
+*/
+
+fixed_t opentop, openbottom, openrange;
+fixed_t lowfloor;
+
+void P_LineOpening(line_t * linedef)
+{
+ sector_t *front, *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;
+ tmfloorpic = front->floorpic;
+ }
+ else
+ {
+ openbottom = back->floorheight;
+ lowfloor = front->floorheight;
+ tmfloorpic = back->floorpic;
+ }
+
+ openrange = opentop - openbottom;
+}
+
+/*
+===============================================================================
+
+ THING POSITION SETTING
+
+===============================================================================
+*/
+
+/*
+===================
+=
+= P_UnsetThingPosition
+=
+= Unlinks a thing from block map and sectors
+=
+===================
+*/
+
+void P_UnsetThingPosition(mobj_t * thing)
+{
+ int blockx, 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, 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 = NULL;
+ 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 = NULL;
+ thing->bnext = *link;
+ if (*link)
+ (*link)->bprev = thing;
+ *link = thing;
+ }
+ else
+ { // thing is off the map
+ thing->bnext = thing->bprev = NULL;
+ }
+ }
+}
+
+
+
+/*
+===============================================================================
+
+ BLOCK MAP ITERATORS
+
+For each line/thing in the given mapblock, call the passed 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
+===================
+*/
+
+boolean P_BlockLinesIterator(int x, int y, boolean(*func) (line_t *))
+{
+ int offset;
+ short *list;
+ line_t *ld;
+
+ int i;
+ polyblock_t *polyLink;
+ seg_t **tempSeg;
+ extern polyblock_t **PolyBlockMap;
+
+ if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight)
+ return true;
+ offset = y * bmapwidth + x;
+
+ polyLink = PolyBlockMap[offset];
+ while (polyLink)
+ {
+ if (polyLink->polyobj)
+ {
+ if (polyLink->polyobj->validcount != validcount)
+ {
+ polyLink->polyobj->validcount = validcount;
+ tempSeg = polyLink->polyobj->segs;
+ for (i = 0; i < polyLink->polyobj->numsegs; i++, tempSeg++)
+ {
+ if ((*tempSeg)->linedef->validcount == validcount)
+ {
+ continue;
+ }
+ (*tempSeg)->linedef->validcount = validcount;
+ if (!func((*tempSeg)->linedef))
+ {
+ return false;
+ }
+ }
+ }
+ }
+ polyLink = polyLink->next;
+ }
+
+ 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
+=
+==================
+*/
+
+boolean P_BlockThingsIterator(int x, int y, 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
+
+===============================================================================
+*/
+
+intercept_t intercepts[MAXINTERCEPTS], *intercept_p;
+
+divline_t trace;
+boolean earlyout;
+int ptflags;
+
+/*
+==================
+=
+= 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
+==================
+*/
+
+boolean PIT_AddLineIntercepts(line_t * ld)
+{
+ int s1, 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
+=
+==================
+*/
+
+boolean PIT_AddThingIntercepts(mobj_t * thing)
+{
+ fixed_t x1, y1, x2, y2;
+ int s1, s2;
+ 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
+====================
+*/
+
+boolean P_TraverseIntercepts(traverser_t func, fixed_t maxfrac)
+{
+ int count;
+ fixed_t dist;
+ intercept_t *scan, *in;
+
+ count = intercept_p - intercepts;
+ in = 0; // shut up compiler warning
+
+ while (count--)
+ {
+ dist = INT_MAX;
+ 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
+ { // don't check these yet, ther 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 = INT_MAX;
+ }
+
+ 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
+==================
+*/
+
+boolean P_PathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2,
+ int flags, boolean(*trav) (intercept_t *))
+{
+ fixed_t xt1, yt1, xt2, yt2;
+ fixed_t xstep, ystep;
+ fixed_t partial;
+ fixed_t xintercept, yintercept;
+ int mapx, mapy, mapxstep, 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, abs(x2 - x1));
+ }
+ else if (xt2 < xt1)
+ {
+ mapxstep = -1;
+ partial = (x1 >> MAPBTOFRAC) & (FRACUNIT - 1);
+ ystep = FixedDiv(y2 - y1, 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, abs(y2 - y1));
+ }
+ else if (yt2 < yt1)
+ {
+ mapystep = -1;
+ partial = (y1 >> MAPBTOFRAC) & (FRACUNIT - 1);
+ xstep = FixedDiv(x2 - x1, 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);
+}
+
+//===========================================================================
+//
+// P_RoughMonsterSearch
+//
+// Searches though the surrounding mapblocks for monsters/players
+// distance is in MAPBLOCKUNITS
+//===========================================================================
+
+mobj_t *P_RoughMonsterSearch(mobj_t * mo, int distance)
+{
+ int blockX;
+ int blockY;
+ int startX, startY;
+ int blockIndex;
+ int firstStop;
+ int secondStop;
+ int thirdStop;
+ int finalStop;
+ int count;
+ mobj_t *target;
+
+ startX = (mo->x - bmaporgx) >> MAPBLOCKSHIFT;
+ startY = (mo->y - bmaporgy) >> MAPBLOCKSHIFT;
+
+ if (startX >= 0 && startX < bmapwidth && startY >= 0
+ && startY < bmapheight)
+ {
+ target = RoughBlockCheck(mo, startY * bmapwidth + startX);
+ if (target != NULL)
+ { // found a target right away
+ return target;
+ }
+ }
+ for (count = 1; count <= distance; count++)
+ {
+ blockX = startX - count;
+ blockY = startY - count;
+
+ if (blockY < 0)
+ {
+ blockY = 0;
+ }
+ else if (blockY >= bmapheight)
+ {
+ blockY = bmapheight - 1;
+ }
+ if (blockX < 0)
+ {
+ blockX = 0;
+ }
+ else if (blockX >= bmapwidth)
+ {
+ blockX = bmapwidth - 1;
+ }
+ blockIndex = blockY * bmapwidth + blockX;
+ firstStop = startX + count;
+ if (firstStop < 0)
+ {
+ continue;
+ }
+ if (firstStop >= bmapwidth)
+ {
+ firstStop = bmapwidth - 1;
+ }
+ secondStop = startY + count;
+ if (secondStop < 0)
+ {
+ continue;
+ }
+ if (secondStop >= bmapheight)
+ {
+ secondStop = bmapheight - 1;
+ }
+ thirdStop = secondStop * bmapwidth + blockX;
+ secondStop = secondStop * bmapwidth + firstStop;
+ firstStop += blockY * bmapwidth;
+ finalStop = blockIndex;
+
+ // Trace the first block section (along the top)
+ for (; blockIndex <= firstStop; blockIndex++)
+ {
+ target = RoughBlockCheck(mo, blockIndex);
+ if (target != NULL)
+ {
+ return target;
+ }
+ }
+ // Trace the second block section (right edge)
+ for (blockIndex--; blockIndex <= secondStop; blockIndex += bmapwidth)
+ {
+ target = RoughBlockCheck(mo, blockIndex);
+ if (target != NULL)
+ {
+ return target;
+ }
+ }
+ // Trace the third block section (bottom edge)
+ for (blockIndex -= bmapwidth; blockIndex >= thirdStop; blockIndex--)
+ {
+ target = RoughBlockCheck(mo, blockIndex);
+ if (target != NULL)
+ {
+ return target;
+ }
+ }
+ // Trace the final block section (left edge)
+ for (blockIndex++; blockIndex > finalStop; blockIndex -= bmapwidth)
+ {
+ target = RoughBlockCheck(mo, blockIndex);
+ if (target != NULL)
+ {
+ return target;
+ }
+ }
+ }
+ return NULL;
+}
+
+//===========================================================================
+//
+// RoughBlockCheck
+//
+//===========================================================================
+
+static mobj_t *RoughBlockCheck(mobj_t * mo, int index)
+{
+ mobj_t *link;
+ mobj_t *master;
+ angle_t angle;
+
+ link = blocklinks[index];
+ while (link)
+ {
+ if (mo->player) // Minotaur looking around player
+ {
+ if ((link->flags & MF_COUNTKILL) ||
+ (link->player && (link != mo)))
+ {
+ if (!(link->flags & MF_SHOOTABLE))
+ {
+ link = link->bnext;
+ continue;
+ }
+ if (link->flags2 & MF2_DORMANT)
+ {
+ link = link->bnext;
+ continue;
+ }
+ if ((link->type == MT_MINOTAUR) &&
+ (link->special1.m == mo))
+ {
+ link = link->bnext;
+ continue;
+ }
+ if (netgame && !deathmatch && link->player)
+ {
+ link = link->bnext;
+ continue;
+ }
+ if (P_CheckSight(mo, link))
+ {
+ return link;
+ }
+ }
+ link = link->bnext;
+ }
+ else if (mo->type == MT_MINOTAUR) // looking around minotaur
+ {
+ master = mo->special1.m;
+ if ((link->flags & MF_COUNTKILL) ||
+ (link->player && (link != master)))
+ {
+ if (!(link->flags & MF_SHOOTABLE))
+ {
+ link = link->bnext;
+ continue;
+ }
+ if (link->flags2 & MF2_DORMANT)
+ {
+ link = link->bnext;
+ continue;
+ }
+ if ((link->type == MT_MINOTAUR) &&
+ (link->special1.m == mo->special1.m))
+ {
+ link = link->bnext;
+ continue;
+ }
+ if (netgame && !deathmatch && link->player)
+ {
+ link = link->bnext;
+ continue;
+ }
+ if (P_CheckSight(mo, link))
+ {
+ return link;
+ }
+ }
+ link = link->bnext;
+ }
+ else if (mo->type == MT_MSTAFF_FX2) // bloodscourge
+ {
+ if ((link->flags & MF_COUNTKILL ||
+ (link->player && link != mo->target))
+ && !(link->flags2 & MF2_DORMANT))
+ {
+ if (!(link->flags & MF_SHOOTABLE))
+ {
+ link = link->bnext;
+ continue;
+ }
+ if (netgame && !deathmatch && link->player)
+ {
+ link = link->bnext;
+ continue;
+ }
+ else if (P_CheckSight(mo, link))
+ {
+ master = mo->target;
+ angle = R_PointToAngle2(master->x, master->y,
+ link->x, link->y) - master->angle;
+ angle >>= 24;
+ if (angle > 226 || angle < 30)
+ {
+ return link;
+ }
+ }
+ }
+ link = link->bnext;
+ }
+ else // spirits
+ {
+ if ((link->flags & MF_COUNTKILL ||
+ (link->player && link != mo->target))
+ && !(link->flags2 & MF2_DORMANT))
+ {
+ if (!(link->flags & MF_SHOOTABLE))
+ {
+ link = link->bnext;
+ continue;
+ }
+ if (netgame && !deathmatch && link->player)
+ {
+ link = link->bnext;
+ continue;
+ }
+ if (link == mo->target)
+ {
+ link = link->bnext;
+ continue;
+ }
+ else if (P_CheckSight(mo, link))
+ {
+ return link;
+ }
+ }
+ link = link->bnext;
+ }
+ }
+ return NULL;
+}
diff --git a/src/hexen/p_mobj.c b/src/hexen/p_mobj.c
new file mode 100644
index 00000000..f716ad4d
--- /dev/null
+++ b/src/hexen/p_mobj.c
@@ -0,0 +1,2474 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2def.h"
+#include "m_random.h"
+#include "i_system.h"
+#include "p_local.h"
+#include "s_sound.h"
+#include "sounds.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define MAX_TID_COUNT 200
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+void G_PlayerReborn(int player);
+void P_MarkAsLeaving(mobj_t * corpse);
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+void P_SpawnMapThing(mapthing_t * mthing);
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void PlayerLandedOnThing(mobj_t * mo, mobj_t * onmobj);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern mobj_t LavaInflictor;
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+mobjtype_t PuffType;
+mobj_t *MissileMobj;
+
+fixed_t FloatBobOffsets[64] = {
+ 0, 51389, 102283, 152192,
+ 200636, 247147, 291278, 332604,
+ 370727, 405280, 435929, 462380,
+ 484378, 501712, 514213, 521763,
+ 524287, 521763, 514213, 501712,
+ 484378, 462380, 435929, 405280,
+ 370727, 332604, 291278, 247147,
+ 200636, 152192, 102283, 51389,
+ -1, -51390, -102284, -152193,
+ -200637, -247148, -291279, -332605,
+ -370728, -405281, -435930, -462381,
+ -484380, -501713, -514215, -521764,
+ -524288, -521764, -514214, -501713,
+ -484379, -462381, -435930, -405280,
+ -370728, -332605, -291279, -247148,
+ -200637, -152193, -102284, -51389
+};
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static int TIDList[MAX_TID_COUNT + 1]; // +1 for termination marker
+static mobj_t *TIDMobj[MAX_TID_COUNT];
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// P_SetMobjState
+//
+// Returns true if the mobj is still present.
+//
+//==========================================================================
+
+boolean P_SetMobjState(mobj_t * mobj, statenum_t state)
+{
+ state_t *st;
+
+ if (state == S_NULL)
+ { // Remove mobj
+ 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;
+ if (st->action)
+ { // Call action function
+ st->action(mobj);
+ }
+ return (true);
+}
+
+//==========================================================================
+//
+// P_SetMobjStateNF
+//
+// Same as P_SetMobjState, but does not call the state function.
+//
+//==========================================================================
+
+boolean P_SetMobjStateNF(mobj_t * mobj, statenum_t state)
+{
+ state_t *st;
+
+ if (state == S_NULL)
+ { // Remove mobj
+ 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;
+ return (true);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC 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;
+ mo->flags &= ~MF_MISSILE;
+
+ switch (mo->type)
+ {
+ case MT_SORCBALL1:
+ case MT_SORCBALL2:
+ case MT_SORCBALL3:
+ S_StartSound(NULL, SFX_SORCERER_BIGBALLEXPLODE);
+ break;
+ case MT_SORCFX1:
+ S_StartSound(NULL, SFX_SORCERER_HEADSCREAM);
+ break;
+ default:
+ if (mo->info->deathsound)
+ {
+ S_StartSound(mo, mo->info->deathsound);
+ }
+ break;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_FloorBounceMissile
+//
+//----------------------------------------------------------------------------
+
+void P_FloorBounceMissile(mobj_t * mo)
+{
+ if (P_HitFloor(mo) >= FLOOR_LIQUID)
+ {
+ switch (mo->type)
+ {
+ case MT_SORCFX1:
+ case MT_SORCBALL1:
+ case MT_SORCBALL2:
+ case MT_SORCBALL3:
+ break;
+ default:
+ P_RemoveMobj(mo);
+ return;
+ }
+ }
+ switch (mo->type)
+ {
+ case MT_SORCFX1:
+ mo->momz = -mo->momz; // no energy absorbed
+ break;
+ case MT_SGSHARD1:
+ case MT_SGSHARD2:
+ case MT_SGSHARD3:
+ case MT_SGSHARD4:
+ case MT_SGSHARD5:
+ case MT_SGSHARD6:
+ case MT_SGSHARD7:
+ case MT_SGSHARD8:
+ case MT_SGSHARD9:
+ case MT_SGSHARD0:
+ mo->momz = FixedMul(mo->momz, -0.3 * FRACUNIT);
+ if (abs(mo->momz) < (FRACUNIT / 2))
+ {
+ P_SetMobjState(mo, S_NULL);
+ return;
+ }
+ break;
+ default:
+ mo->momz = FixedMul(mo->momz, -0.7 * FRACUNIT);
+ break;
+ }
+ mo->momx = 2 * mo->momx / 3;
+ mo->momy = 2 * mo->momy / 3;
+ if (mo->info->seesound)
+ {
+ switch (mo->type)
+ {
+ case MT_SORCBALL1:
+ case MT_SORCBALL2:
+ case MT_SORCBALL3:
+ if (!mo->args[0])
+ S_StartSound(mo, mo->info->seesound);
+ break;
+ default:
+ S_StartSound(mo, mo->info->seesound);
+ break;
+ }
+ S_StartSound(mo, mo->info->seesound);
+ }
+// P_SetMobjState(mo, mobjinfo[mo->type].deathstate);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_ThrustMobj
+//
+//----------------------------------------------------------------------------
+
+void P_ThrustMobj(mobj_t * mo, angle_t angle, fixed_t move)
+{
+ angle >>= ANGLETOFINESHIFT;
+ mo->momx += FixedMul(move, finecosine[angle]);
+ mo->momy += FixedMul(move, finesine[angle]);
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_FaceMobj
+//
+// Returns 1 if 'source' needs to turn clockwise, or 0 if 'source' needs
+// to turn counter clockwise. 'delta' is set to the amount 'source'
+// needs to turn.
+//
+//----------------------------------------------------------------------------
+
+int P_FaceMobj(mobj_t * source, mobj_t * target, angle_t * delta)
+{
+ angle_t diff;
+ angle_t angle1;
+ angle_t angle2;
+
+ angle1 = source->angle;
+ angle2 = R_PointToAngle2(source->x, source->y, target->x, target->y);
+ if (angle2 > angle1)
+ {
+ diff = angle2 - angle1;
+ if (diff > ANG180)
+ {
+ *delta = ANG_MAX - diff;
+ return (0);
+ }
+ else
+ {
+ *delta = diff;
+ return (1);
+ }
+ }
+ else
+ {
+ diff = angle1 - angle2;
+ if (diff > ANG180)
+ {
+ *delta = ANG_MAX - diff;
+ return (1);
+ }
+ else
+ {
+ *delta = diff;
+ return (0);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+//
+// The missile special1 field must be mobj_t *target. Returns true if
+// target was tracked, false if not.
+//
+//----------------------------------------------------------------------------
+
+boolean P_SeekerMissile(mobj_t * actor, angle_t thresh, angle_t turnMax)
+{
+ int dir;
+ int dist;
+ angle_t delta;
+ angle_t angle;
+ mobj_t *target;
+
+ target = actor->special1.m;
+ if (target == NULL)
+ {
+ return (false);
+ }
+ if (!(target->flags & MF_SHOOTABLE))
+ { // Target died
+ actor->special1.m = NULL;
+ return (false);
+ }
+ dir = P_FaceMobj(actor, target, &delta);
+ if (delta > thresh)
+ {
+ delta >>= 1;
+ if (delta > turnMax)
+ {
+ delta = turnMax;
+ }
+ }
+ if (dir)
+ { // Turn clockwise
+ actor->angle += delta;
+ }
+ else
+ { // Turn counter clockwise
+ actor->angle -= delta;
+ }
+ angle = actor->angle >> ANGLETOFINESHIFT;
+ actor->momx = FixedMul(actor->info->speed, finecosine[angle]);
+ actor->momy = FixedMul(actor->info->speed, finesine[angle]);
+ if (actor->z + actor->height < target->z
+ || target->z + target->height < actor->z)
+ { // Need to seek vertically
+ dist = P_AproxDistance(target->x - actor->x, target->y - actor->y);
+ dist = dist / actor->info->speed;
+ if (dist < 1)
+ {
+ dist = 1;
+ }
+ actor->momz = (target->z + (target->height >> 1)
+ - (actor->z + (actor->height >> 1))) / dist;
+ }
+ return (true);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_XYMovement
+//
+//----------------------------------------------------------------------------
+
+#define STOPSPEED 0x1000
+#define FRICTION_NORMAL 0xe800
+#define FRICTION_LOW 0xf900
+#define FRICTION_FLY 0xeb00
+
+void P_XYMovement(mobj_t * mo)
+{
+ fixed_t ptryx, ptryy;
+ player_t *player;
+ fixed_t xmove, ymove;
+ int special;
+ angle_t angle;
+ static int windTab[3] = { 2048 * 5, 2048 * 10, 2048 * 25 };
+
+ if (!mo->momx && !mo->momy)
+ {
+ if (mo->flags & MF_SKULLFLY)
+ { // A flying mobj slammed into something
+ mo->flags &= ~MF_SKULLFLY;
+ mo->momx = mo->momy = mo->momz = 0;
+ P_SetMobjState(mo, mo->info->seestate);
+ }
+ return;
+ }
+ special = mo->subsector->sector->special;
+ if (mo->flags2 & MF2_WINDTHRUST)
+ {
+ switch (special)
+ {
+ case 40:
+ case 41:
+ case 42: // Wind_East
+ P_ThrustMobj(mo, 0, windTab[special - 40]);
+ break;
+ case 43:
+ case 44:
+ case 45: // Wind_North
+ P_ThrustMobj(mo, ANG90, windTab[special - 43]);
+ break;
+ case 46:
+ case 47:
+ case 48: // Wind_South
+ P_ThrustMobj(mo, ANG270, windTab[special - 46]);
+ break;
+ case 49:
+ case 50:
+ case 51: // Wind_West
+ P_ThrustMobj(mo, ANG180, windTab[special - 49]);
+ break;
+ }
+ }
+ 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->flags2 & MF2_SLIDE)
+ { // Try to slide along it
+ if (BlockingMobj == NULL)
+ { // Slide against wall
+ P_SlideMove(mo);
+ }
+ else
+ { // Slide against mobj
+ //if(P_TryMove(mo, mo->x, mo->y+mo->momy))
+ if (P_TryMove(mo, mo->x, ptryy))
+ {
+ mo->momx = 0;
+ }
+ //else if(P_TryMove(mo, mo->x+mo->momx, mo->y))
+ else if (P_TryMove(mo, ptryx, mo->y))
+ {
+ mo->momy = 0;
+ }
+ else
+ {
+ mo->momx = mo->momy = 0;
+ }
+ }
+ }
+ else if (mo->flags & MF_MISSILE)
+ {
+ if (mo->flags2 & MF2_FLOORBOUNCE)
+ {
+ if (BlockingMobj)
+ {
+ if ((BlockingMobj->flags2 & MF2_REFLECTIVE) ||
+ ((!BlockingMobj->player) &&
+ (!(BlockingMobj->flags & MF_COUNTKILL))))
+ {
+ fixed_t speed;
+
+ angle = R_PointToAngle2(BlockingMobj->x,
+ BlockingMobj->y, mo->x,
+ mo->y) +
+ ANG1 * ((P_Random() % 16) - 8);
+ speed = P_AproxDistance(mo->momx, mo->momy);
+ speed = FixedMul(speed, 0.75 * FRACUNIT);
+ mo->angle = angle;
+ angle >>= ANGLETOFINESHIFT;
+ mo->momx = FixedMul(speed, finecosine[angle]);
+ mo->momy = FixedMul(speed, finesine[angle]);
+ if (mo->info->seesound)
+ {
+ S_StartSound(mo, mo->info->seesound);
+ }
+ return;
+ }
+ else
+ { // Struck a player/creature
+ P_ExplodeMissile(mo);
+ }
+ }
+ else
+ { // Struck a wall
+ P_BounceWall(mo);
+ switch (mo->type)
+ {
+ case MT_SORCBALL1:
+ case MT_SORCBALL2:
+ case MT_SORCBALL3:
+ case MT_SORCFX1:
+ break;
+ default:
+ if (mo->info->seesound)
+ {
+ S_StartSound(mo, mo->info->seesound);
+ }
+ break;
+ }
+ return;
+ }
+ }
+ if (BlockingMobj && (BlockingMobj->flags2 & MF2_REFLECTIVE))
+ {
+ angle = R_PointToAngle2(BlockingMobj->x,
+ BlockingMobj->y, mo->x, mo->y);
+
+ // Change angle for delflection/reflection
+ switch (BlockingMobj->type)
+ {
+ case MT_CENTAUR:
+ case MT_CENTAURLEADER:
+ if (abs(angle - BlockingMobj->angle) >> 24 > 45)
+ goto explode;
+ if (mo->type == MT_HOLY_FX)
+ goto explode;
+ // Drop through to sorcerer full reflection
+ case MT_SORCBOSS:
+ // Deflection
+ if (P_Random() < 128)
+ angle += ANG45;
+ else
+ angle -= ANG45;
+ break;
+ default:
+ // Reflection
+ angle += ANG1 * ((P_Random() % 16) - 8);
+ break;
+ }
+
+ // Reflect the missile along angle
+ mo->angle = angle;
+ angle >>= ANGLETOFINESHIFT;
+ mo->momx =
+ FixedMul(mo->info->speed >> 1, finecosine[angle]);
+ mo->momy =
+ FixedMul(mo->info->speed >> 1, finesine[angle]);
+// mo->momz = -mo->momz;
+ if (mo->flags2 & MF2_SEEKERMISSILE)
+ {
+ mo->special1.m = mo->target;
+ }
+ mo->target = BlockingMobj;
+ return;
+ }
+ explode:
+ // Explode a missile
+ if (ceilingline && ceilingline->backsector
+ && ceilingline->backsector->ceilingpic == skyflatnum)
+ { // Hack to prevent missiles exploding against the sky
+ if (mo->type == MT_BLOODYSKULL)
+ {
+ mo->momx = mo->momy = 0;
+ mo->momz = -FRACUNIT;
+ }
+ else if (mo->type == MT_HOLY_FX)
+ {
+ P_ExplodeMissile(mo);
+ }
+ else
+ {
+ P_RemoveMobj(mo);
+ }
+ return;
+ }
+ P_ExplodeMissile(mo);
+ }
+ //else if(mo->info->crashstate)
+ //{
+ // mo->momx = mo->momy = 0;
+ // P_SetMobjState(mo, mo->info->crashstate);
+ // return;
+ //}
+ else
+ {
+ mo->momx = mo->momy = 0;
+ }
+ }
+ }
+ while (xmove || ymove);
+
+ // Friction
+
+ 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))
+ { // No friction for missiles
+ return;
+ }
+ if (mo->z > mo->floorz && !(mo->flags2 & MF2_FLY)
+ && !(mo->flags2 & MF2_ONMOBJ))
+ { // No friction when falling
+ if (mo->type != MT_BLASTEFFECT)
+ return;
+ }
+ if (mo->flags & MF_CORPSE)
+ { // Don't 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)
+ {
+ if ((unsigned) ((player->mo->state - states)
+ - PStateRun[player->class]) < 4)
+ {
+ P_SetMobjState(player->mo, PStateNormal[player->class]);
+ }
+ }
+ mo->momx = 0;
+ mo->momy = 0;
+ }
+ else
+ {
+ if (mo->flags2 & MF2_FLY && !(mo->z <= mo->floorz)
+ && !(mo->flags2 & MF2_ONMOBJ))
+ {
+ mo->momx = FixedMul(mo->momx, FRICTION_FLY);
+ mo->momy = FixedMul(mo->momy, FRICTION_FLY);
+ }
+ else if (P_GetThingFloorType(mo) == FLOOR_ICE)
+ {
+ mo->momx = FixedMul(mo->momx, FRICTION_LOW);
+ mo->momy = FixedMul(mo->momy, FRICTION_LOW);
+ }
+ else
+ {
+ mo->momx = FixedMul(mo->momx, FRICTION_NORMAL);
+ mo->momy = FixedMul(mo->momy, FRICTION_NORMAL);
+ }
+ }
+}
+
+
+// Move this to p_inter ***
+void P_MonsterFallingDamage(mobj_t * mo)
+{
+ int damage;
+ int mom;
+
+ mom = abs(mo->momz);
+ if (mom > 35 * FRACUNIT)
+ { // automatic death
+ damage = 10000;
+ }
+ else
+ {
+ damage = ((mom - (23 * FRACUNIT)) * 6) >> FRACBITS;
+ }
+ damage = 10000; // always kill 'em
+ P_DamageMobj(mo, NULL, NULL, damage);
+}
+
+
+
+/*
+===============
+=
+= P_ZMovement
+=
+===============
+*/
+
+void P_ZMovement(mobj_t * mo)
+{
+ int dist;
+ int 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;
+ }
+ }
+ if (mo->player && mo->flags2 & MF2_FLY && !(mo->z <= mo->floorz)
+ && leveltime & 2)
+ {
+ mo->z += finesine[(FINEANGLES / 20 * leveltime >> 2) & FINEMASK];
+ }
+
+//
+// clip movement
+//
+ if (mo->z <= mo->floorz)
+ { // Hit the floor
+ if (mo->flags & MF_MISSILE)
+ {
+ mo->z = mo->floorz;
+ if (mo->flags2 & MF2_FLOORBOUNCE)
+ {
+ P_FloorBounceMissile(mo);
+ return;
+ }
+ else if (mo->type == MT_HOLY_FX)
+ { // The spirit struck the ground
+ mo->momz = 0;
+ P_HitFloor(mo);
+ return;
+ }
+ else if (mo->type == MT_MNTRFX2 || mo->type == MT_LIGHTNING_FLOOR)
+ { // Minotaur floor fire can go up steps
+ return;
+ }
+ else
+ {
+ P_HitFloor(mo);
+ P_ExplodeMissile(mo);
+ return;
+ }
+ }
+ if (mo->flags & MF_COUNTKILL) // Blasted mobj falling
+ {
+ if (mo->momz < -(23 * FRACUNIT))
+ {
+ P_MonsterFallingDamage(mo);
+ }
+ }
+ if (mo->z - mo->momz > mo->floorz)
+ { // Spawn splashes, etc.
+ P_HitFloor(mo);
+ }
+ mo->z = mo->floorz;
+ if (mo->momz < 0)
+ {
+ if (mo->flags2 & MF2_ICEDAMAGE && mo->momz < -GRAVITY * 8)
+ {
+ mo->tics = 1;
+ mo->momx = 0;
+ mo->momy = 0;
+ mo->momz = 0;
+ return;
+ }
+ if (mo->player)
+ {
+ mo->player->jumpTics = 7; // delay any jumping for a short time
+ if (mo->momz < -GRAVITY * 8 && !(mo->flags2 & MF2_FLY))
+ { // squat down
+ mo->player->deltaviewheight = mo->momz >> 3;
+ if (mo->momz < -23 * FRACUNIT)
+ {
+ P_FallingDamage(mo->player);
+ P_NoiseAlert(mo, mo);
+ }
+ else if (mo->momz < -GRAVITY * 12
+ && !mo->player->morphTics)
+ {
+ S_StartSound(mo, SFX_PLAYER_LAND);
+ switch (mo->player->class)
+ {
+ case PCLASS_FIGHTER:
+ S_StartSound(mo, SFX_PLAYER_FIGHTER_GRUNT);
+ break;
+ case PCLASS_CLERIC:
+ S_StartSound(mo, SFX_PLAYER_CLERIC_GRUNT);
+ break;
+ case PCLASS_MAGE:
+ S_StartSound(mo, SFX_PLAYER_MAGE_GRUNT);
+ break;
+ default:
+ break;
+ }
+ }
+ else if ((P_GetThingFloorType(mo) < FLOOR_LIQUID) &&
+ (!mo->player->morphTics))
+ {
+ S_StartSound(mo, SFX_PLAYER_LAND);
+ }
+ // haleyjd: removed externdriver crap
+ mo->player->centering = true;
+ }
+ }
+ else if (mo->type >= MT_POTTERY1 && mo->type <= MT_POTTERY3)
+ {
+ P_DamageMobj(mo, NULL, NULL, 25);
+ }
+ else if (mo->flags & MF_COUNTKILL)
+ {
+ if (mo->momz < -23 * FRACUNIT)
+ {
+ // Doesn't get here
+ }
+ }
+ mo->momz = 0;
+ }
+ if (mo->flags & MF_SKULLFLY)
+ { // The skull slammed into something
+ mo->momz = -mo->momz;
+ }
+ if (mo->info->crashstate &&
+ (mo->flags & MF_CORPSE) && !(mo->flags2 & MF2_ICEDAMAGE))
+ {
+ P_SetMobjState(mo, mo->info->crashstate);
+ return;
+ }
+ }
+ else if (mo->flags2 & MF2_LOGRAV)
+ {
+ if (mo->momz == 0)
+ mo->momz = -(GRAVITY >> 3) * 2;
+ else
+ mo->momz -= GRAVITY >> 3;
+ }
+ 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->flags2 & MF2_FLOORBOUNCE)
+ {
+ // Maybe reverse momentum here for ceiling bounce
+ // Currently won't happen
+
+ if (mo->info->seesound)
+ {
+ S_StartSound(mo, mo->info->seesound);
+ }
+ return;
+ }
+ if (mo->flags & MF_SKULLFLY)
+ { // the skull slammed into something
+ mo->momz = -mo->momz;
+ }
+ if (mo->flags & MF_MISSILE)
+ {
+ if (mo->type == MT_LIGHTNING_CEILING)
+ {
+ return;
+ }
+ if (mo->subsector->sector->ceilingpic == skyflatnum)
+ {
+ if (mo->type == MT_BLOODYSKULL)
+ {
+ mo->momx = mo->momy = 0;
+ mo->momz = -FRACUNIT;
+ }
+ else if (mo->type == MT_HOLY_FX)
+ {
+ P_ExplodeMissile(mo);
+ }
+ else
+ {
+ P_RemoveMobj(mo);
+ }
+ return;
+ }
+ P_ExplodeMissile(mo);
+ return;
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_BlasterMobjThinker
+//
+//
+//----------------------------------------------------------------------------
+
+void P_BlasterMobjThinker(mobj_t * mobj)
+{
+ int i;
+ fixed_t xfrac;
+ fixed_t yfrac;
+ fixed_t zfrac;
+ fixed_t z;
+ boolean changexy;
+ mobj_t *mo;
+
+ // Handle movement
+ if (mobj->momx || mobj->momy || (mobj->z != mobj->floorz) || mobj->momz)
+ {
+ xfrac = mobj->momx >> 3;
+ yfrac = mobj->momy >> 3;
+ zfrac = mobj->momz >> 3;
+ changexy = xfrac || yfrac;
+ for (i = 0; i < 8; i++)
+ {
+ if (changexy)
+ {
+ if (!P_TryMove(mobj, mobj->x + xfrac, mobj->y + yfrac))
+ { // Blocked move
+ P_ExplodeMissile(mobj);
+ return;
+ }
+ }
+ mobj->z += zfrac;
+ if (mobj->z <= mobj->floorz)
+ { // Hit the floor
+ mobj->z = mobj->floorz;
+ P_HitFloor(mobj);
+ P_ExplodeMissile(mobj);
+ return;
+ }
+ if (mobj->z + mobj->height > mobj->ceilingz)
+ { // Hit the ceiling
+ mobj->z = mobj->ceilingz - mobj->height;
+ P_ExplodeMissile(mobj);
+ return;
+ }
+ if (changexy)
+ {
+ if (mobj->type == MT_MWAND_MISSILE && (P_Random() < 128))
+ {
+ z = mobj->z - 8 * FRACUNIT;
+ if (z < mobj->floorz)
+ {
+ z = mobj->floorz;
+ }
+ P_SpawnMobj(mobj->x, mobj->y, z, MT_MWANDSMOKE);
+ }
+ else if (!--mobj->special1.i)
+ {
+ mobj->special1.i = 4;
+ z = mobj->z - 12 * FRACUNIT;
+ if (z < mobj->floorz)
+ {
+ z = mobj->floorz;
+ }
+ mo = P_SpawnMobj(mobj->x, mobj->y, z, MT_CFLAMEFLOOR);
+ if (mo)
+ {
+ mo->angle = mobj->angle;
+ }
+ }
+ }
+ }
+ }
+ // Advance the state
+ if (mobj->tics != -1)
+ {
+ mobj->tics--;
+ while (!mobj->tics)
+ {
+ if (!P_SetMobjState(mobj, mobj->state->nextstate))
+ { // mobj was removed
+ return;
+ }
+ }
+ }
+}
+
+//===========================================================================
+//
+// PlayerLandedOnThing
+//
+//===========================================================================
+
+static void PlayerLandedOnThing(mobj_t * mo, mobj_t * onmobj)
+{
+ mo->player->deltaviewheight = mo->momz >> 3;
+ if (mo->momz < -23 * FRACUNIT)
+ {
+ P_FallingDamage(mo->player);
+ P_NoiseAlert(mo, mo);
+ }
+ else if (mo->momz < -GRAVITY * 12 && !mo->player->morphTics)
+ {
+ S_StartSound(mo, SFX_PLAYER_LAND);
+ switch (mo->player->class)
+ {
+ case PCLASS_FIGHTER:
+ S_StartSound(mo, SFX_PLAYER_FIGHTER_GRUNT);
+ break;
+ case PCLASS_CLERIC:
+ S_StartSound(mo, SFX_PLAYER_CLERIC_GRUNT);
+ break;
+ case PCLASS_MAGE:
+ S_StartSound(mo, SFX_PLAYER_MAGE_GRUNT);
+ break;
+ default:
+ break;
+ }
+ }
+ else if (!mo->player->morphTics)
+ {
+ S_StartSound(mo, SFX_PLAYER_LAND);
+ }
+ // haleyjd: removed externdriver crap
+ mo->player->centering = true;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_MobjThinker
+//
+//----------------------------------------------------------------------------
+
+void P_MobjThinker(mobj_t * mobj)
+{
+ mobj_t *onmo;
+/*
+ // Reset to not blasted when momentums are gone
+ if((mobj->flags2&MF2_BLASTED) && (!(mobj->momx)) && (!(mobj->momy)))
+ ResetBlasted(mobj);
+*/
+ // Handle X and Y momentums
+ BlockingMobj = NULL;
+ if (mobj->momx || mobj->momy || (mobj->flags & MF_SKULLFLY))
+ {
+ P_XYMovement(mobj);
+ if (mobj->thinker.function == (think_t) - 1)
+ { // mobj was removed
+ return;
+ }
+ }
+ else if (mobj->flags2 & MF2_BLASTED)
+ { // Reset to not blasted when momentums are gone
+ ResetBlasted(mobj);
+ }
+ if (mobj->flags2 & MF2_FLOATBOB)
+ { // Floating item bobbing motion (special1 is height)
+ mobj->z = mobj->floorz +
+ mobj->special1.i + FloatBobOffsets[(mobj->health++) & 63];
+ }
+ else if ((mobj->z != mobj->floorz) || mobj->momz || BlockingMobj)
+ { // Handle Z momentum and gravity
+ if (mobj->flags2 & MF2_PASSMOBJ)
+ {
+ if (!(onmo = P_CheckOnmobj(mobj)))
+ {
+ P_ZMovement(mobj);
+ if (mobj->player && mobj->flags & MF2_ONMOBJ)
+ {
+ mobj->flags2 &= ~MF2_ONMOBJ;
+ }
+ }
+ else
+ {
+ if (mobj->player)
+ {
+ if (mobj->momz < -GRAVITY * 8
+ && !(mobj->flags2 & MF2_FLY))
+ {
+ PlayerLandedOnThing(mobj, onmo);
+ }
+ if (onmo->z + onmo->height - mobj->z <= 24 * FRACUNIT)
+ {
+ mobj->player->viewheight -= onmo->z + onmo->height
+ - mobj->z;
+ mobj->player->deltaviewheight =
+ (VIEWHEIGHT - mobj->player->viewheight) >> 3;
+ mobj->z = onmo->z + onmo->height;
+ mobj->flags2 |= MF2_ONMOBJ;
+ mobj->momz = 0;
+ }
+ else
+ { // hit the bottom of the blocking mobj
+ mobj->momz = 0;
+ }
+ }
+/* Landing on another player, and mimicking his movements
+ if(mobj->player && onmo->player)
+ {
+ mobj->momx = onmo->momx;
+ mobj->momy = onmo->momy;
+ if(onmo->z < onmo->floorz)
+ {
+ mobj->z += onmo->floorz-onmo->z;
+ if(onmo->player)
+ {
+ onmo->player->viewheight -= onmo->floorz-onmo->z;
+ onmo->player->deltaviewheight = (VIEWHEIGHT-
+ onmo->player->viewheight)>>3;
+ }
+ onmo->z = onmo->floorz;
+ }
+ }
+*/
+ }
+ }
+ else
+ {
+ P_ZMovement(mobj);
+ }
+ if (mobj->thinker.function == (think_t) - 1)
+ { // mobj was removed
+ return;
+ }
+ }
+
+ // Cycle through states, calling action functions at transitions
+ if (mobj->tics != -1)
+ {
+ mobj->tics--;
+ // you can cycle through multiple states in a tic
+ while (!mobj->tics)
+ {
+ if (!P_SetMobjState(mobj, mobj->state->nextstate))
+ { // mobj was removed
+ return;
+ }
+ }
+ }
+}
+
+//==========================================================================
+//
+// 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;
+ fixed_t space;
+
+ mobj = Z_Malloc(sizeof(*mobj), PU_LEVEL, NULL);
+ 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->flags2 = info->flags2;
+ mobj->damage = info->damage;
+ mobj->health = info->spawnhealth;
+ if (gameskill != sk_nightmare)
+ {
+ mobj->reactiontime = info->reactiontime;
+ }
+ mobj->lastlook = P_Random() % MAXPLAYERS;
+
+ // Set the state, but do not use P_SetMobjState, because action
+ // routines can't be called yet. If the spawnstate has an action
+ // routine, it will not be called.
+ 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 if (z == FLOATRANDZ)
+ {
+ space = ((mobj->ceilingz) - (mobj->info->height)) - mobj->floorz;
+ if (space > 48 * FRACUNIT)
+ {
+ space -= 40 * FRACUNIT;
+ mobj->z =
+ ((space * P_Random()) >> 8) + mobj->floorz + 40 * FRACUNIT;
+ }
+ else
+ {
+ mobj->z = mobj->floorz;
+ }
+ }
+ else if (mobj->flags2 & MF2_FLOATBOB)
+ {
+ mobj->z = mobj->floorz + z; // artifact z passed in as height
+ }
+ else
+ {
+ mobj->z = z;
+ }
+ if (mobj->flags2 & MF2_FLOORCLIP
+ && P_GetThingFloorType(mobj) >= FLOOR_LIQUID
+ && mobj->z == mobj->subsector->sector->floorheight)
+ {
+ mobj->floorclip = 10 * FRACUNIT;
+ }
+ else
+ {
+ mobj->floorclip = 0;
+ }
+
+ mobj->thinker.function = P_MobjThinker;
+ P_AddThinker(&mobj->thinker);
+ return (mobj);
+}
+
+//==========================================================================
+//
+// P_RemoveMobj
+//
+//==========================================================================
+
+void P_RemoveMobj(mobj_t * mobj)
+{
+ // Remove from creature queue
+ if (mobj->flags & MF_COUNTKILL && mobj->flags & MF_CORPSE)
+ {
+ A_DeQueueCorpse(mobj);
+ }
+
+ if (mobj->tid)
+ { // Remove from TID list
+ P_RemoveMobjFromTIDList(mobj);
+ }
+
+ // Unlink from sector and block lists
+ P_UnsetThingPosition(mobj);
+
+ // Stop any playing sound
+ S_StopSound(mobj);
+
+ // Free block
+ P_RemoveThinker((thinker_t *) mobj);
+}
+
+//==========================================================================
+//
+// 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, y, z;
+ mobj_t *mobj;
+
+ if (mthing->type - 1 >= MAXPLAYERS || !playeringame[mthing->type - 1])
+ { // Not playing
+ 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;
+ if (randomclass && deathmatch)
+ {
+ p->class = P_Random() % 3;
+ if (p->class == PlayerClass[mthing->type - 1])
+ {
+ p->class = (p->class + 1) % 3;
+ }
+ PlayerClass[mthing->type - 1] = p->class;
+ SB_SetClassData();
+ }
+ else
+ {
+ p->class = PlayerClass[mthing->type - 1];
+ }
+ switch (p->class)
+ {
+ case PCLASS_FIGHTER:
+ mobj = P_SpawnMobj(x, y, z, MT_PLAYER_FIGHTER);
+ break;
+ case PCLASS_CLERIC:
+ mobj = P_SpawnMobj(x, y, z, MT_PLAYER_CLERIC);
+ break;
+ case PCLASS_MAGE:
+ mobj = P_SpawnMobj(x, y, z, MT_PLAYER_MAGE);
+ break;
+ default:
+ I_Error("P_SpawnPlayer: Unknown class type");
+ return;
+ }
+
+ // Set translation table data
+ if (p->class == PCLASS_FIGHTER
+ && (mthing->type == 1 || mthing->type == 3))
+ {
+ // The first type should be blue, and the third should be the
+ // Fighter's original gold color
+ if (mthing->type == 1)
+ {
+ mobj->flags |= 2 << MF_TRANSSHIFT;
+ }
+ }
+ else if (mthing->type > 1)
+ { // Set color translation bits for player sprites
+ 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_ClearMessage(p);
+ p->damagecount = 0;
+ p->bonuscount = 0;
+ p->poisoncount = 0;
+ p->morphTics = 0;
+ p->extralight = 0;
+ p->fixedcolormap = 0;
+ p->viewheight = VIEWHEIGHT;
+ P_SetupPsprites(p);
+ if (deathmatch)
+ { // Give all keys in death match mode
+ p->keys = 2047;
+ }
+}
+
+//==========================================================================
+//
+// P_SpawnMapThing
+//
+// The fields of the mapthing should already be in host byte order.
+//
+//==========================================================================
+
+void P_SpawnMapThing(mapthing_t * mthing)
+{
+ int i;
+ unsigned int spawnMask;
+ mobj_t *mobj;
+ fixed_t x, y, z;
+ static unsigned int classFlags[] = {
+ MTF_FIGHTER,
+ MTF_CLERIC,
+ MTF_MAGE
+ };
+
+ // Count deathmatch start positions
+ if (mthing->type == 11)
+ {
+ if (deathmatch_p < &deathmatchstarts[MAXDEATHMATCHSTARTS])
+ {
+ memcpy(deathmatch_p, mthing, sizeof(*mthing));
+ deathmatch_p++;
+ }
+ return;
+ }
+ if (mthing->type == PO_ANCHOR_TYPE)
+ { // Polyobj Anchor Pt.
+ return;
+ }
+ else if (mthing->type == PO_SPAWN_TYPE
+ || mthing->type == PO_SPAWNCRUSH_TYPE)
+ { // Polyobj Anchor Pt.
+ po_NumPolyobjs++;
+ return;
+ }
+
+ // Check for player starts 1 to 4
+ if (mthing->type <= 4)
+ {
+ playerstarts[mthing->arg1][mthing->type - 1] = *mthing;
+ if (!deathmatch && !mthing->arg1)
+ {
+ P_SpawnPlayer(mthing);
+ }
+ return;
+ }
+ // Check for player starts 5 to 8
+ if (mthing->type >= 9100 && mthing->type <= 9103)
+ {
+ mapthing_t *player_start;
+ int player;
+
+ player = 4 + mthing->type - 9100;
+
+ player_start = &playerstarts[mthing->arg1][player];
+ memcpy(player_start, mthing, sizeof(mapthing_t));
+ player_start->type = player + 1;
+
+ if (!deathmatch && !player_start->arg1)
+ {
+ P_SpawnPlayer(player_start);
+ }
+ return;
+ }
+
+ if (mthing->type >= 1400 && mthing->type < 1410)
+ {
+ R_PointInSubsector(mthing->x << FRACBITS,
+ mthing->y << FRACBITS)->sector->seqType =
+ mthing->type - 1400;
+ return;
+ }
+
+ // Check current game type with spawn flags
+ if (netgame == false)
+ {
+ spawnMask = MTF_GSINGLE;
+ }
+ else if (deathmatch)
+ {
+ spawnMask = MTF_GDEATHMATCH;
+ }
+ else
+ {
+ spawnMask = MTF_GCOOP;
+ }
+ if (!(mthing->options & spawnMask))
+ {
+ return;
+ }
+
+ // Check current skill with spawn flags
+ if (gameskill == sk_baby || gameskill == sk_easy)
+ {
+ spawnMask = MTF_EASY;
+ }
+ else if (gameskill == sk_hard || gameskill == sk_nightmare)
+ {
+ spawnMask = MTF_HARD;
+ }
+ else
+ {
+ spawnMask = MTF_NORMAL;
+ }
+ if (!(mthing->options & spawnMask))
+ {
+ return;
+ }
+
+ // Check current character classes with spawn flags
+ if (netgame == false)
+ { // Single player
+ if ((mthing->options & classFlags[PlayerClass[0]]) == 0)
+ { // Not for current class
+ return;
+ }
+ }
+ else if (deathmatch == false)
+ { // Cooperative
+ spawnMask = 0;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ {
+ spawnMask |= classFlags[PlayerClass[i]];
+ }
+ }
+ if ((mthing->options & spawnMask) == 0)
+ {
+ return;
+ }
+ }
+
+ // Find which type to spawn
+ for (i = 0; i < NUMMOBJTYPES; i++)
+ {
+ if (mthing->type == mobjinfo[i].doomednum)
+ {
+ break;
+ }
+ }
+
+ if (i == NUMMOBJTYPES)
+ { // Can't find thing type
+ I_Error("P_SpawnMapThing: Unknown type %i at (%i, %i)",
+ mthing->type, mthing->x, mthing->y);
+ }
+
+ // Don't spawn keys and players in deathmatch
+ if (deathmatch && mobjinfo[i].flags & MF_NOTDMATCH)
+ {
+ return;
+ }
+
+ // Don't spawn monsters if -nomonsters
+ if (nomonsters && (mobjinfo[i].flags & MF_COUNTKILL))
+ {
+ return;
+ }
+
+ x = mthing->x << FRACBITS;
+ y = mthing->y << FRACBITS;
+ if (mobjinfo[i].flags & MF_SPAWNCEILING)
+ {
+ z = ONCEILINGZ;
+ }
+ else if (mobjinfo[i].flags2 & MF2_SPAWNFLOAT)
+ {
+ z = FLOATRANDZ;
+ }
+ else if (mobjinfo[i].flags2 & MF2_FLOATBOB)
+ {
+ z = mthing->height << FRACBITS;
+ }
+ else
+ {
+ z = ONFLOORZ;
+ }
+ switch (i)
+ { // Special stuff
+ case MT_ZLYNCHED_NOHEART:
+ P_SpawnMobj(x, y, ONFLOORZ, MT_BLOODPOOL);
+ break;
+ default:
+ break;
+ }
+ mobj = P_SpawnMobj(x, y, z, i);
+ if (z == ONFLOORZ)
+ {
+ mobj->z += mthing->height << FRACBITS;
+ }
+ else if (z == ONCEILINGZ)
+ {
+ mobj->z -= mthing->height << FRACBITS;
+ }
+ mobj->tid = mthing->tid;
+ mobj->special = mthing->special;
+ mobj->args[0] = mthing->arg1;
+ mobj->args[1] = mthing->arg2;
+ mobj->args[2] = mthing->arg3;
+ mobj->args[3] = mthing->arg4;
+ mobj->args[4] = mthing->arg5;
+ if (mobj->flags2 & MF2_FLOATBOB)
+ { // Seed random starting index for bobbing motion
+ mobj->health = P_Random();
+ mobj->special1.i = mthing->height << FRACBITS;
+ }
+ if (mobj->tics > 0)
+ {
+ mobj->tics = 1 + (P_Random() % mobj->tics);
+ }
+// if(mobj->flags&MF_COUNTITEM)
+// {
+// totalitems++;
+// }
+ if (mobj->flags & MF_COUNTKILL)
+ {
+ // Quantize angle to 45 degree increments
+ mobj->angle = ANG45 * (mthing->angle / 45);
+ }
+ else
+ {
+ // Scale angle correctly (source is 0..359)
+ mobj->angle = ((mthing->angle << 8) / 360) << 24;
+ }
+ if (mthing->options & MTF_AMBUSH)
+ {
+ mobj->flags |= MF_AMBUSH;
+ }
+ if (mthing->options & MTF_DORMANT)
+ {
+ mobj->flags2 |= MF2_DORMANT;
+ if (mobj->type == MT_ICEGUY)
+ {
+ P_SetMobjState(mobj, S_ICEGUY_DORMANT);
+ }
+ mobj->tics = -1;
+ }
+}
+
+//==========================================================================
+//
+// P_CreateTIDList
+//
+//==========================================================================
+
+void P_CreateTIDList(void)
+{
+ int i;
+ mobj_t *mobj;
+ thinker_t *t;
+
+ i = 0;
+ for (t = thinkercap.next; t != &thinkercap; t = t->next)
+ { // Search all current thinkers
+ if (t->function != P_MobjThinker)
+ { // Not a mobj thinker
+ continue;
+ }
+ mobj = (mobj_t *) t;
+ if (mobj->tid != 0)
+ { // Add to list
+ if (i == MAX_TID_COUNT)
+ {
+ I_Error("P_CreateTIDList: MAX_TID_COUNT (%d) exceeded.",
+ MAX_TID_COUNT);
+ }
+ TIDList[i] = mobj->tid;
+ TIDMobj[i++] = mobj;
+ }
+ }
+ // Add termination marker
+ TIDList[i] = 0;
+}
+
+//==========================================================================
+//
+// P_InsertMobjIntoTIDList
+//
+//==========================================================================
+
+void P_InsertMobjIntoTIDList(mobj_t * mobj, int tid)
+{
+ int i;
+ int index;
+
+ index = -1;
+ for (i = 0; TIDList[i] != 0; i++)
+ {
+ if (TIDList[i] == -1)
+ { // Found empty slot
+ index = i;
+ break;
+ }
+ }
+ if (index == -1)
+ { // Append required
+ if (i == MAX_TID_COUNT)
+ {
+ I_Error("P_InsertMobjIntoTIDList: MAX_TID_COUNT (%d)"
+ "exceeded.", MAX_TID_COUNT);
+ }
+ index = i;
+ TIDList[index + 1] = 0;
+ }
+ mobj->tid = tid;
+ TIDList[index] = tid;
+ TIDMobj[index] = mobj;
+}
+
+//==========================================================================
+//
+// P_RemoveMobjFromTIDList
+//
+//==========================================================================
+
+void P_RemoveMobjFromTIDList(mobj_t * mobj)
+{
+ int i;
+
+ for (i = 0; TIDList[i] != 0; i++)
+ {
+ if (TIDMobj[i] == mobj)
+ {
+ TIDList[i] = -1;
+ TIDMobj[i] = NULL;
+ mobj->tid = 0;
+ return;
+ }
+ }
+ mobj->tid = 0;
+}
+
+//==========================================================================
+//
+// P_FindMobjFromTID
+//
+//==========================================================================
+
+mobj_t *P_FindMobjFromTID(int tid, int *searchPosition)
+{
+ int i;
+
+ for (i = *searchPosition + 1; TIDList[i] != 0; i++)
+ {
+ if (TIDList[i] == tid)
+ {
+ *searchPosition = i;
+ return TIDMobj[i];
+ }
+ }
+ *searchPosition = -1;
+ return NULL;
+}
+
+/*
+===============================================================================
+
+ GAME SPAWN FUNCTIONS
+
+===============================================================================
+*/
+
+//---------------------------------------------------------------------------
+//
+// PROC P_SpawnPuff
+//
+//---------------------------------------------------------------------------
+
+extern fixed_t attackrange;
+
+void P_SpawnPuff(fixed_t x, fixed_t y, fixed_t z)
+{
+ mobj_t *puff;
+
+ z += ((P_Random() - P_Random()) << 10);
+ puff = P_SpawnMobj(x, y, z, PuffType);
+ if (linetarget && puff->info->seesound)
+ { // Hit thing sound
+ S_StartSound(puff, puff->info->seesound);
+ }
+ else if (puff->info->attacksound)
+ {
+ S_StartSound(puff, puff->info->attacksound);
+ }
+ switch (PuffType)
+ {
+ case MT_PUNCHPUFF:
+ puff->momz = FRACUNIT;
+ break;
+ case MT_HAMMERPUFF:
+ puff->momz = .8 * FRACUNIT;
+ break;
+ default:
+ break;
+ }
+ PuffSpawned = puff;
+}
+
+/*
+================
+=
+= 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 (damage <= 12 && damage >= 9)
+ P_SetMobjState (th,S_BLOOD2);
+ else if (damage < 9)
+ P_SetMobjState (th,S_BLOOD3);
+}
+*/
+
+//---------------------------------------------------------------------------
+//
+// PROC P_BloodSplatter
+//
+//---------------------------------------------------------------------------
+
+void P_BloodSplatter(fixed_t x, fixed_t y, fixed_t z, mobj_t * originator)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(x, y, z, MT_BLOODSPLATTER);
+ mo->target = originator;
+ mo->momx = (P_Random() - P_Random()) << 10;
+ mo->momy = (P_Random() - P_Random()) << 10;
+ mo->momz = 3 * FRACUNIT;
+}
+
+//===========================================================================
+//
+// P_BloodSplatter2
+//
+//===========================================================================
+
+void P_BloodSplatter2(fixed_t x, fixed_t y, fixed_t z, mobj_t * originator)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(x + ((P_Random() - 128) << 11),
+ y + ((P_Random() - 128) << 11), z, MT_AXEBLOOD);
+ mo->target = originator;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_RipperBlood
+//
+//---------------------------------------------------------------------------
+
+void P_RipperBlood(mobj_t * mo)
+{
+ mobj_t *th;
+ fixed_t x, y, z;
+
+ x = mo->x + ((P_Random() - P_Random()) << 12);
+ y = mo->y + ((P_Random() - P_Random()) << 12);
+ z = mo->z + ((P_Random() - P_Random()) << 12);
+ th = P_SpawnMobj(x, y, z, MT_BLOOD);
+// th->flags |= MF_NOGRAVITY;
+ th->momx = mo->momx >> 1;
+ th->momy = mo->momy >> 1;
+ th->tics += P_Random() & 3;
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_GetThingFloorType
+//
+//---------------------------------------------------------------------------
+
+int P_GetThingFloorType(mobj_t * thing)
+{
+ if (thing->floorpic)
+ {
+ return (TerrainTypes[thing->floorpic]);
+ }
+ else
+ {
+ return (TerrainTypes[thing->subsector->sector->floorpic]);
+ }
+/*
+ if(thing->subsector->sector->floorpic
+ == W_GetNumForName("FLTWAWA1")-firstflat)
+ {
+ return(FLOOR_WATER);
+ }
+ else
+ {
+ return(FLOOR_SOLID);
+ }
+*/
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_HitFloor
+//
+//---------------------------------------------------------------------------
+#define SMALLSPLASHCLIP 12<<FRACBITS;
+
+int P_HitFloor(mobj_t * thing)
+{
+ mobj_t *mo;
+ int smallsplash = false;
+
+ if (thing->floorz != thing->subsector->sector->floorheight)
+ { // don't splash if landing on the edge above water/lava/etc....
+ return (FLOOR_SOLID);
+ }
+
+ // Things that don't splash go here
+ switch (thing->type)
+ {
+ case MT_LEAF1:
+ case MT_LEAF2:
+// case MT_BLOOD: // I set these to low mass -- pm
+// case MT_BLOODSPLATTER:
+ case MT_SPLASH:
+ case MT_SLUDGECHUNK:
+ return (FLOOR_SOLID);
+ default:
+ break;
+ }
+
+ // Small splash for small masses
+ if (thing->info->mass < 10)
+ smallsplash = true;
+
+ switch (P_GetThingFloorType(thing))
+ {
+ case FLOOR_WATER:
+ if (smallsplash)
+ {
+ mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SPLASHBASE);
+ if (mo)
+ mo->floorclip += SMALLSPLASHCLIP;
+ S_StartSound(mo, SFX_AMBIENT10); // small drip
+ }
+ else
+ {
+ mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SPLASH);
+ mo->target = thing;
+ mo->momx = (P_Random() - P_Random()) << 8;
+ mo->momy = (P_Random() - P_Random()) << 8;
+ mo->momz = 2 * FRACUNIT + (P_Random() << 8);
+ mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SPLASHBASE);
+ if (thing->player)
+ P_NoiseAlert(thing, thing);
+ S_StartSound(mo, SFX_WATER_SPLASH);
+ }
+ return (FLOOR_WATER);
+ case FLOOR_LAVA:
+ if (smallsplash)
+ {
+ mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_LAVASPLASH);
+ if (mo)
+ mo->floorclip += SMALLSPLASHCLIP;
+ }
+ else
+ {
+ mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_LAVASMOKE);
+ mo->momz = FRACUNIT + (P_Random() << 7);
+ mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_LAVASPLASH);
+ if (thing->player)
+ P_NoiseAlert(thing, thing);
+ }
+ S_StartSound(mo, SFX_LAVA_SIZZLE);
+ if (thing->player && leveltime & 31)
+ {
+ P_DamageMobj(thing, &LavaInflictor, NULL, 5);
+ }
+ return (FLOOR_LAVA);
+ case FLOOR_SLUDGE:
+ if (smallsplash)
+ {
+ mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ,
+ MT_SLUDGESPLASH);
+ if (mo)
+ mo->floorclip += SMALLSPLASHCLIP;
+ }
+ else
+ {
+ mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ,
+ MT_SLUDGECHUNK);
+ mo->target = thing;
+ mo->momx = (P_Random() - P_Random()) << 8;
+ mo->momy = (P_Random() - P_Random()) << 8;
+ mo->momz = FRACUNIT + (P_Random() << 8);
+ mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ,
+ MT_SLUDGESPLASH);
+ if (thing->player)
+ P_NoiseAlert(thing, thing);
+ }
+ S_StartSound(mo, SFX_SLUDGE_GLOOP);
+ return (FLOOR_SLUDGE);
+ }
+ return (FLOOR_SOLID);
+}
+
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_CheckMissileSpawn
+//
+// Returns true if the missile is at a valid spawn point, otherwise
+// explodes it and returns false.
+//
+//---------------------------------------------------------------------------
+
+boolean P_CheckMissileSpawn(mobj_t * missile)
+{
+ //missile->tics -= P_Random()&3;
+
+ // move a little forward so an angle can be computed if it
+ // immediately explodes
+ missile->x += (missile->momx >> 1);
+ missile->y += (missile->momy >> 1);
+ missile->z += (missile->momz >> 1);
+ if (!P_TryMove(missile, missile->x, missile->y))
+ {
+ P_ExplodeMissile(missile);
+ return (false);
+ }
+ return (true);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_SpawnMissile
+//
+// Returns NULL if the missile exploded immediately, otherwise returns
+// a mobj_t pointer to the missile.
+//
+//---------------------------------------------------------------------------
+
+mobj_t *P_SpawnMissile(mobj_t * source, mobj_t * dest, mobjtype_t type)
+{
+ fixed_t z;
+ mobj_t *th;
+ angle_t an;
+ int dist;
+
+ switch (type)
+ {
+ case MT_MNTRFX1: // Minotaur swing attack missile
+ z = source->z + 40 * FRACUNIT;
+ break;
+ case MT_MNTRFX2: // Minotaur floor fire missile
+ z = ONFLOORZ + source->floorclip;
+ break;
+ case MT_CENTAUR_FX:
+ z = source->z + 45 * FRACUNIT;
+ break;
+ case MT_ICEGUY_FX:
+ z = source->z + 40 * FRACUNIT;
+ break;
+ case MT_HOLY_MISSILE:
+ z = source->z + 40 * FRACUNIT;
+ break;
+ default:
+ z = source->z + 32 * FRACUNIT;
+ break;
+ }
+ z -= source->floorclip;
+ th = P_SpawnMobj(source->x, source->y, z, type);
+ if (th->info->seesound)
+ {
+ S_StartSound(th, th->info->seesound);
+ }
+ th->target = source; // Originator
+ an = R_PointToAngle2(source->x, source->y, dest->x, dest->y);
+ if (dest->flags & MF_SHADOW)
+ { // Invisible target
+ an += (P_Random() - P_Random()) << 21;
+ }
+ 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;
+ return (P_CheckMissileSpawn(th) ? th : NULL);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_SpawnMissileXYZ
+//
+// Returns NULL if the missile exploded immediately, otherwise returns
+// a mobj_t pointer to the missile.
+//
+//---------------------------------------------------------------------------
+
+mobj_t *P_SpawnMissileXYZ(fixed_t x, fixed_t y, fixed_t z,
+ mobj_t * source, mobj_t * dest, mobjtype_t type)
+{
+ mobj_t *th;
+ angle_t an;
+ int dist;
+
+ z -= source->floorclip;
+ th = P_SpawnMobj(x, y, z, type);
+ if (th->info->seesound)
+ {
+ S_StartSound(th, th->info->seesound);
+ }
+ th->target = source; // Originator
+ an = R_PointToAngle2(source->x, source->y, dest->x, dest->y);
+ if (dest->flags & MF_SHADOW)
+ { // Invisible target
+ an += (P_Random() - P_Random()) << 21;
+ }
+ 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;
+ return (P_CheckMissileSpawn(th) ? th : NULL);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_SpawnMissileAngle
+//
+// Returns NULL if the missile exploded immediately, otherwise returns
+// a mobj_t pointer to the missile.
+//
+//---------------------------------------------------------------------------
+
+mobj_t *P_SpawnMissileAngle(mobj_t * source, mobjtype_t type,
+ angle_t angle, fixed_t momz)
+{
+ fixed_t z;
+ mobj_t *mo;
+
+ switch (type)
+ {
+ case MT_MNTRFX1: // Minotaur swing attack missile
+ z = source->z + 40 * FRACUNIT;
+ break;
+ case MT_MNTRFX2: // Minotaur floor fire missile
+ z = ONFLOORZ + source->floorclip;
+ break;
+ case MT_ICEGUY_FX2: // Secondary Projectiles of the Ice Guy
+ z = source->z + 3 * FRACUNIT;
+ break;
+ case MT_MSTAFF_FX2:
+ z = source->z + 40 * FRACUNIT;
+ break;
+ default:
+ z = source->z + 32 * FRACUNIT;
+ break;
+ }
+ z -= source->floorclip;
+ mo = P_SpawnMobj(source->x, source->y, z, type);
+ if (mo->info->seesound)
+ {
+ S_StartSound(mo, mo->info->seesound);
+ }
+ mo->target = source; // Originator
+ mo->angle = angle;
+ angle >>= ANGLETOFINESHIFT;
+ mo->momx = FixedMul(mo->info->speed, finecosine[angle]);
+ mo->momy = FixedMul(mo->info->speed, finesine[angle]);
+ mo->momz = momz;
+ return (P_CheckMissileSpawn(mo) ? mo : NULL);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_SpawnMissileAngleSpeed
+//
+// Returns NULL if the missile exploded immediately, otherwise returns
+// a mobj_t pointer to the missile.
+//
+//---------------------------------------------------------------------------
+
+mobj_t *P_SpawnMissileAngleSpeed(mobj_t * source, mobjtype_t type,
+ angle_t angle, fixed_t momz, fixed_t speed)
+{
+ fixed_t z;
+ mobj_t *mo;
+
+ z = source->z;
+ z -= source->floorclip;
+ mo = P_SpawnMobj(source->x, source->y, z, type);
+ if (mo->info->seesound)
+ {
+ //S_StartSound(mo, mo->info->seesound);
+ }
+ mo->target = source; // Originator
+ mo->angle = angle;
+ angle >>= ANGLETOFINESHIFT;
+ mo->momx = FixedMul(speed, finecosine[angle]);
+ mo->momy = FixedMul(speed, finesine[angle]);
+ mo->momz = momz;
+ return (P_CheckMissileSpawn(mo) ? mo : NULL);
+}
+
+
+
+/*
+================
+=
+= P_SpawnPlayerMissile
+=
+= Tries to aim at a nearby monster
+================
+*/
+
+mobj_t *P_SpawnPlayerMissile(mobj_t * source, mobjtype_t type)
+{
+ angle_t an;
+ fixed_t x, y, z, slope;
+
+ // Try to find a target
+ 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 = ((source->player->lookdir) << FRACBITS) / 173;
+ }
+ }
+ x = source->x;
+ y = source->y;
+ if (type == MT_LIGHTNING_FLOOR)
+ {
+ z = ONFLOORZ;
+ slope = 0;
+ }
+ else if (type == MT_LIGHTNING_CEILING)
+ {
+ z = ONCEILINGZ;
+ slope = 0;
+ }
+ else
+ {
+ z = source->z + 4 * 8 * FRACUNIT +
+ ((source->player->lookdir) << FRACBITS) / 173;
+ z -= source->floorclip;
+ }
+ MissileMobj = P_SpawnMobj(x, y, z, type);
+ if (MissileMobj->info->seesound)
+ {
+ //S_StartSound(MissileMobj, MissileMobj->info->seesound);
+ }
+ MissileMobj->target = source;
+ MissileMobj->angle = an;
+ MissileMobj->momx = FixedMul(MissileMobj->info->speed,
+ finecosine[an >> ANGLETOFINESHIFT]);
+ MissileMobj->momy = FixedMul(MissileMobj->info->speed,
+ finesine[an >> ANGLETOFINESHIFT]);
+ MissileMobj->momz = FixedMul(MissileMobj->info->speed, slope);
+ if (MissileMobj->type == MT_MWAND_MISSILE
+ || MissileMobj->type == MT_CFLAME_MISSILE)
+ { // Ultra-fast ripper spawning missile
+ MissileMobj->x += (MissileMobj->momx >> 3);
+ MissileMobj->y += (MissileMobj->momy >> 3);
+ MissileMobj->z += (MissileMobj->momz >> 3);
+ }
+ else
+ { // Normal missile
+ MissileMobj->x += (MissileMobj->momx >> 1);
+ MissileMobj->y += (MissileMobj->momy >> 1);
+ MissileMobj->z += (MissileMobj->momz >> 1);
+ }
+ if (!P_TryMove(MissileMobj, MissileMobj->x, MissileMobj->y))
+ { // Exploded immediately
+ P_ExplodeMissile(MissileMobj);
+ return (NULL);
+ }
+ return (MissileMobj);
+}
+
+
+//----------------------------------------------------------------------------
+//
+// P_SpawnPlayerMinotaur -
+//
+// Special missile that has larger blocking than player
+//----------------------------------------------------------------------------
+
+/*
+mobj_t *P_SpawnPlayerMinotaur(mobj_t *source, mobjtype_t type)
+{
+ angle_t an;
+ fixed_t x, y, z;
+ fixed_t dist=0 *FRACUNIT;
+
+ an = source->angle;
+ x = source->x + FixedMul(dist, finecosine[an>>ANGLETOFINESHIFT]);
+ y = source->y + FixedMul(dist, finesine[an>>ANGLETOFINESHIFT]);
+ z = source->z + 4*8*FRACUNIT+((source->player->lookdir)<<FRACBITS)/173;
+ z -= source->floorclip;
+ MissileMobj = P_SpawnMobj(x, y, z, type);
+ if(MissileMobj->info->seesound)
+ {
+ //S_StartSound(MissileMobj, MissileMobj->info->seesound);
+ }
+ MissileMobj->target = source;
+ MissileMobj->angle = an;
+ MissileMobj->momx = FixedMul(MissileMobj->info->speed,
+ finecosine[an>>ANGLETOFINESHIFT]);
+ MissileMobj->momy = FixedMul(MissileMobj->info->speed,
+ finesine[an>>ANGLETOFINESHIFT]);
+ MissileMobj->momz = 0;
+
+// MissileMobj->x += (MissileMobj->momx>>3);
+// MissileMobj->y += (MissileMobj->momy>>3);
+// MissileMobj->z += (MissileMobj->momz>>3);
+
+ if(!P_TryMove(MissileMobj, MissileMobj->x, MissileMobj->y))
+ { // Wouln't fit
+
+ return(NULL);
+ }
+ return(MissileMobj);
+}
+*/
+
+//---------------------------------------------------------------------------
+//
+// PROC P_SPMAngle
+//
+//---------------------------------------------------------------------------
+
+mobj_t *P_SPMAngle(mobj_t * source, mobjtype_t type, angle_t angle)
+{
+ mobj_t *th;
+ angle_t an;
+ fixed_t x, y, z, slope;
+
+//
+// see which target is to be aimed at
+//
+ an = 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 = angle;
+ slope = ((source->player->lookdir) << FRACBITS) / 173;
+ }
+ }
+ x = source->x;
+ y = source->y;
+ z = source->z + 4 * 8 * FRACUNIT +
+ ((source->player->lookdir) << FRACBITS) / 173;
+ z -= source->floorclip;
+ 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);
+ return (P_CheckMissileSpawn(th) ? th : NULL);
+}
+
+//===========================================================================
+//
+// P_SPMAngleXYZ
+//
+//===========================================================================
+
+mobj_t *P_SPMAngleXYZ(mobj_t * source, fixed_t x, fixed_t y,
+ fixed_t z, mobjtype_t type, angle_t angle)
+{
+ mobj_t *th;
+ angle_t an;
+ fixed_t slope;
+
+//
+// see which target is to be aimed at
+//
+ an = 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 = angle;
+ slope = ((source->player->lookdir) << FRACBITS) / 173;
+ }
+ }
+ z += 4 * 8 * FRACUNIT + ((source->player->lookdir) << FRACBITS) / 173;
+ z -= source->floorclip;
+ 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);
+ return (P_CheckMissileSpawn(th) ? th : NULL);
+}
+
+mobj_t *P_SpawnKoraxMissile(fixed_t x, fixed_t y, fixed_t z,
+ mobj_t * source, mobj_t * dest, mobjtype_t type)
+{
+ mobj_t *th;
+ angle_t an;
+ int dist;
+
+ z -= source->floorclip;
+ th = P_SpawnMobj(x, y, z, type);
+ if (th->info->seesound)
+ {
+ S_StartSound(th, th->info->seesound);
+ }
+ th->target = source; // Originator
+ an = R_PointToAngle2(x, y, dest->x, dest->y);
+ if (dest->flags & MF_SHADOW)
+ { // Invisible target
+ an += (P_Random() - P_Random()) << 21;
+ }
+ 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 - x, dest->y - y);
+ dist = dist / th->info->speed;
+ if (dist < 1)
+ {
+ dist = 1;
+ }
+ th->momz = (dest->z - z + (30 * FRACUNIT)) / dist;
+ return (P_CheckMissileSpawn(th) ? th : NULL);
+}
diff --git a/src/hexen/p_plats.c b/src/hexen/p_plats.c
new file mode 100644
index 00000000..62f35055
--- /dev/null
+++ b/src/hexen/p_plats.c
@@ -0,0 +1,284 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#include "h2def.h"
+#include "m_random.h"
+#include "i_system.h"
+#include "p_local.h"
+
+plat_t *activeplats[MAXPLATS];
+
+//==================================================================
+//
+// Move a plat up and down
+//
+//==================================================================
+void T_PlatRaise(plat_t * plat)
+{
+ result_e res;
+
+ switch (plat->status)
+ {
+ case PLAT_UP:
+ res = T_MovePlane(plat->sector, plat->speed,
+ plat->high, plat->crush, 0, 1);
+ if (res == RES_CRUSHED && (!plat->crush))
+ {
+ plat->count = plat->wait;
+ plat->status = PLAT_DOWN;
+ SN_StartSequence((mobj_t *) & plat->sector->soundorg,
+ SEQ_PLATFORM + plat->sector->seqType);
+ }
+ else if (res == RES_PASTDEST)
+ {
+ plat->count = plat->wait;
+ plat->status = PLAT_WAITING;
+ SN_StopSequence((mobj_t *) & plat->sector->soundorg);
+ switch (plat->type)
+ {
+ case PLAT_DOWNWAITUPSTAY:
+ case PLAT_DOWNBYVALUEWAITUPSTAY:
+ P_RemoveActivePlat(plat);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case PLAT_DOWN:
+ res =
+ T_MovePlane(plat->sector, plat->speed, plat->low, false, 0,
+ -1);
+ if (res == RES_PASTDEST)
+ {
+ plat->count = plat->wait;
+ plat->status = PLAT_WAITING;
+ switch (plat->type)
+ {
+ case PLAT_UPWAITDOWNSTAY:
+ case PLAT_UPBYVALUEWAITDOWNSTAY:
+ P_RemoveActivePlat(plat);
+ break;
+ default:
+ break;
+ }
+ SN_StopSequence((mobj_t *) & plat->sector->soundorg);
+ }
+ break;
+ case PLAT_WAITING:
+ if (!--plat->count)
+ {
+ if (plat->sector->floorheight == plat->low)
+ plat->status = PLAT_UP;
+ else
+ plat->status = PLAT_DOWN;
+ SN_StartSequence((mobj_t *) & plat->sector->soundorg,
+ SEQ_PLATFORM + plat->sector->seqType);
+ }
+// case PLAT_IN_STASIS:
+// break;
+ }
+}
+
+//==================================================================
+//
+// Do Platforms
+// "amount" is only used for SOME platforms.
+//
+//==================================================================
+int EV_DoPlat(line_t * line, byte * args, 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 PLAT_PERPETUALRAISE:
+ P_ActivateInStasis(args[0]);
+ break;
+ default:
+ break;
+ }
+*/
+
+ while ((secnum = P_FindSectorFromTag(args[0], 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 = T_PlatRaise;
+ plat->crush = false;
+ plat->tag = args[0];
+ plat->speed = args[1] * (FRACUNIT / 8);
+ switch (type)
+ {
+ case PLAT_DOWNWAITUPSTAY:
+ plat->low = P_FindLowestFloorSurrounding(sec) + 8 * FRACUNIT;
+ if (plat->low > sec->floorheight)
+ plat->low = sec->floorheight;
+ plat->high = sec->floorheight;
+ plat->wait = args[2];
+ plat->status = PLAT_DOWN;
+ break;
+ case PLAT_DOWNBYVALUEWAITUPSTAY:
+ plat->low = sec->floorheight - args[3] * 8 * FRACUNIT;
+ if (plat->low > sec->floorheight)
+ plat->low = sec->floorheight;
+ plat->high = sec->floorheight;
+ plat->wait = args[2];
+ plat->status = PLAT_DOWN;
+ break;
+ case PLAT_UPWAITDOWNSTAY:
+ plat->high = P_FindHighestFloorSurrounding(sec);
+ if (plat->high < sec->floorheight)
+ plat->high = sec->floorheight;
+ plat->low = sec->floorheight;
+ plat->wait = args[2];
+ plat->status = PLAT_UP;
+ break;
+ case PLAT_UPBYVALUEWAITDOWNSTAY:
+ plat->high = sec->floorheight + args[3] * 8 * FRACUNIT;
+ if (plat->high < sec->floorheight)
+ plat->high = sec->floorheight;
+ plat->low = sec->floorheight;
+ plat->wait = args[2];
+ plat->status = PLAT_UP;
+ break;
+ case PLAT_PERPETUALRAISE:
+ plat->low = P_FindLowestFloorSurrounding(sec) + 8 * FRACUNIT;
+ 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 = args[2];
+ plat->status = P_Random() & 1;
+ break;
+ }
+ P_AddActivePlat(plat);
+ SN_StartSequence((mobj_t *) & sec->soundorg,
+ SEQ_PLATFORM + sec->seqType);
+ }
+ return rtn;
+}
+
+#if 0
+void P_ActivateInStasis(int tag)
+{
+ int i;
+
+ for (i = 0; i < MAXPLATS; i++)
+ if (activeplats[i] &&
+ (activeplats[i])->tag == tag &&
+ (activeplats[i])->status == PLAT_IN_STASIS)
+ {
+ (activeplats[i])->status = (activeplats[i])->oldstatus;
+ (activeplats[i])->thinker.function = T_PlatRaise;
+ }
+}
+#endif
+
+void EV_StopPlat(line_t * line, byte * args)
+{
+ int i;
+
+ for (i = 0; i < MAXPLATS; i++)
+ {
+ activeplats[i]->tag = args[0];
+
+ if (activeplats[i]->tag != 0)
+ {
+ activeplats[i]->sector->specialdata = NULL;
+ P_TagFinished(activeplats[i]->sector->tag);
+ P_RemoveThinker(&activeplats[i]->thinker);
+ activeplats[i] = NULL;
+
+ return;
+ }
+ }
+
+/*
+ int j;
+
+ for (j = 0;j < MAXPLATS;j++)
+ {
+ if (activeplats[j] && ((activeplats[j])->status != PLAT_IN_STASIS) &&
+ ((activeplats[j])->tag == args[0]))
+ {
+ (activeplats[j])->oldstatus = (activeplats[j])->status;
+ (activeplats[j])->status = PLAT_IN_STASIS;
+ (activeplats[j])->thinker.function = NULL;
+ SN_StopSequence((mobj_t *)&(activeplats[j])->sector->soundorg);
+ }
+ }
+*/
+}
+
+void P_AddActivePlat(plat_t * plat)
+{
+ int i;
+ for (i = 0; i < MAXPLATS; i++)
+ if (activeplats[i] == NULL)
+ {
+ activeplats[i] = plat;
+ return;
+ }
+ I_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 = NULL;
+ P_TagFinished(plat->sector->tag);
+ P_RemoveThinker(&(activeplats[i])->thinker);
+ activeplats[i] = NULL;
+ return;
+ }
+ I_Error("P_RemoveActivePlat: can't find plat!");
+}
diff --git a/src/hexen/p_pspr.c b/src/hexen/p_pspr.c
new file mode 100644
index 00000000..7617e3f0
--- /dev/null
+++ b/src/hexen/p_pspr.c
@@ -0,0 +1,2477 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2def.h"
+#include "m_random.h"
+#include "p_local.h"
+#include "s_sound.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define LOWERSPEED FRACUNIT*6
+#define RAISESPEED FRACUNIT*6
+#define WEAPONBOTTOM 128*FRACUNIT
+#define WEAPONTOP 32*FRACUNIT
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+extern void P_ExplodeMissile(mobj_t * mo);
+extern void A_UnHideThing(mobj_t * actor);
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern fixed_t FloatBobOffsets[64];
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+fixed_t bulletslope;
+
+weaponinfo_t WeaponInfo[NUMWEAPONS][NUMCLASSES] = {
+ { // First Weapons
+ { // Fighter First Weapon - Punch
+ MANA_NONE, // mana
+ S_PUNCHUP, // upstate
+ S_PUNCHDOWN, // downstate
+ S_PUNCHREADY, // readystate
+ S_PUNCHATK1_1, // atkstate
+ S_PUNCHATK1_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Cleric First Weapon - Mace
+ MANA_NONE, // mana
+ S_CMACEUP, // upstate
+ S_CMACEDOWN, // downstate
+ S_CMACEREADY, // readystate
+ S_CMACEATK_1, // atkstate
+ S_CMACEATK_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Mage First Weapon - Wand
+ MANA_NONE,
+ S_MWANDUP,
+ S_MWANDDOWN,
+ S_MWANDREADY,
+ S_MWANDATK_1,
+ S_MWANDATK_1,
+ S_NULL},
+ { // Pig - Snout
+ MANA_NONE, // mana
+ S_SNOUTUP, // upstate
+ S_SNOUTDOWN, // downstate
+ S_SNOUTREADY, // readystate
+ S_SNOUTATK1, // atkstate
+ S_SNOUTATK1, // holdatkstate
+ S_NULL // flashstate
+ }
+ },
+ { // Second Weapons
+ { // Fighter - Axe
+ MANA_NONE, // mana
+ S_FAXEUP, // upstate
+ S_FAXEDOWN, // downstate
+ S_FAXEREADY, // readystate
+ S_FAXEATK_1, // atkstate
+ S_FAXEATK_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Cleric - Serpent Staff
+ MANA_1, // mana
+ S_CSTAFFUP, // upstate
+ S_CSTAFFDOWN, // downstate
+ S_CSTAFFREADY, // readystate
+ S_CSTAFFATK_1, // atkstate
+ S_CSTAFFATK_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Mage - Cone of shards
+ MANA_1, // mana
+ S_CONEUP, // upstate
+ S_CONEDOWN, // downstate
+ S_CONEREADY, // readystate
+ S_CONEATK1_1, // atkstate
+ S_CONEATK1_3, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Pig - Snout
+ MANA_NONE, // mana
+ S_SNOUTUP, // upstate
+ S_SNOUTDOWN, // downstate
+ S_SNOUTREADY, // readystate
+ S_SNOUTATK1, // atkstate
+ S_SNOUTATK1, // holdatkstate
+ S_NULL // flashstate
+ }
+ },
+ { // Third Weapons
+ { // Fighter - Hammer
+ MANA_NONE, // mana
+ S_FHAMMERUP, // upstate
+ S_FHAMMERDOWN, // downstate
+ S_FHAMMERREADY, // readystate
+ S_FHAMMERATK_1, // atkstate
+ S_FHAMMERATK_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Cleric - Flame Strike
+ MANA_2, // mana
+ S_CFLAMEUP, // upstate
+ S_CFLAMEDOWN, // downstate
+ S_CFLAMEREADY1, // readystate
+ S_CFLAMEATK_1, // atkstate
+ S_CFLAMEATK_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Mage - Lightning
+ MANA_2, // mana
+ S_MLIGHTNINGUP, // upstate
+ S_MLIGHTNINGDOWN, // downstate
+ S_MLIGHTNINGREADY, // readystate
+ S_MLIGHTNINGATK_1, // atkstate
+ S_MLIGHTNINGATK_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Pig - Snout
+ MANA_NONE, // mana
+ S_SNOUTUP, // upstate
+ S_SNOUTDOWN, // downstate
+ S_SNOUTREADY, // readystate
+ S_SNOUTATK1, // atkstate
+ S_SNOUTATK1, // holdatkstate
+ S_NULL // flashstate
+ }
+ },
+ { // Fourth Weapons
+ { // Fighter - Rune Sword
+ MANA_BOTH, // mana
+ S_FSWORDUP, // upstate
+ S_FSWORDDOWN, // downstate
+ S_FSWORDREADY, // readystate
+ S_FSWORDATK_1, // atkstate
+ S_FSWORDATK_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Cleric - Holy Symbol
+ MANA_BOTH, // mana
+ S_CHOLYUP, // upstate
+ S_CHOLYDOWN, // downstate
+ S_CHOLYREADY, // readystate
+ S_CHOLYATK_1, // atkstate
+ S_CHOLYATK_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Mage - Staff
+ MANA_BOTH, // mana
+ S_MSTAFFUP, // upstate
+ S_MSTAFFDOWN, // downstate
+ S_MSTAFFREADY, // readystate
+ S_MSTAFFATK_1, // atkstate
+ S_MSTAFFATK_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Pig - Snout
+ MANA_NONE, // mana
+ S_SNOUTUP, // upstate
+ S_SNOUTDOWN, // downstate
+ S_SNOUTREADY, // readystate
+ S_SNOUTATK1, // atkstate
+ S_SNOUTATK1, // holdatkstate
+ S_NULL // flashstate
+ }
+ }
+};
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static int WeaponManaUse[NUMCLASSES][NUMWEAPONS] = {
+ {0, 2, 3, 14},
+ {0, 1, 4, 18},
+ {0, 3, 5, 15},
+ {0, 0, 0, 0}
+};
+
+// CODE --------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+//
+// PROC 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 = NULL;
+ break;
+ }
+ state = &states[stnum];
+ psp->state = state;
+ psp->tics = state->tics; // could be 0
+ if (state->misc1)
+ { // Set coordinates.
+ psp->sx = state->misc1 << FRACBITS;
+ }
+ if (state->misc2)
+ {
+ psp->sy = state->misc2 << FRACBITS;
+ }
+ if (state->action)
+ { // Call action routine.
+ state->action(player, psp);
+ if (!psp->state)
+ {
+ break;
+ }
+ }
+ stnum = psp->state->nextstate;
+ }
+ while (!psp->tics); // An initial state of 0 could cycle through.
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_SetPspriteNF
+//
+// Identical to P_SetPsprite, without calling the action function
+//---------------------------------------------------------------------------
+
+void P_SetPspriteNF(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 = NULL;
+ break;
+ }
+ state = &states[stnum];
+ psp->state = state;
+ psp->tics = state->tics; // could be 0
+ if (state->misc1)
+ { // Set coordinates.
+ psp->sx = state->misc1 << FRACBITS;
+ }
+ if (state->misc2)
+ {
+ psp->sy = state->misc2 << FRACBITS;
+ }
+ stnum = psp->state->nextstate;
+ }
+ while (!psp->tics); // An initial state of 0 could cycle through.
+}
+
+/*
+=================
+=
+= P_CalcSwing
+=
+=================
+*/
+
+/*
+fixed_t swingx, swingy;
+void P_CalcSwing (player_t *player)
+{
+ fixed_t swing;
+ int angle;
+
+// OPTIMIZE: tablify this
+
+ swing = player->bob;
+
+ angle = (FINEANGLES/70*leveltime)&FINEMASK;
+ swingx = FixedMul ( swing, finesine[angle]);
+
+ angle = (FINEANGLES/70*leveltime+FINEANGLES/2)&FINEMASK;
+ swingy = -FixedMul ( swingx, finesine[angle]);
+}
+*/
+
+//---------------------------------------------------------------------------
+//
+// PROC P_ActivateMorphWeapon
+//
+//---------------------------------------------------------------------------
+
+void P_ActivateMorphWeapon(player_t * player)
+{
+ player->pendingweapon = WP_NOCHANGE;
+ player->psprites[ps_weapon].sy = WEAPONTOP;
+ player->readyweapon = WP_FIRST; // Snout is the first weapon
+ P_SetPsprite(player, ps_weapon, S_SNOUTREADY);
+}
+
+
+//---------------------------------------------------------------------------
+//
+// PROC P_PostMorphWeapon
+//
+//---------------------------------------------------------------------------
+
+void P_PostMorphWeapon(player_t * player, weapontype_t weapon)
+{
+ player->pendingweapon = WP_NOCHANGE;
+ player->readyweapon = weapon;
+ player->psprites[ps_weapon].sy = WEAPONBOTTOM;
+ P_SetPsprite(player, ps_weapon,
+ WeaponInfo[weapon][player->class].upstate);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_BringUpWeapon
+//
+// Starts bringing the pending weapon up from the bottom of the screen.
+//
+//---------------------------------------------------------------------------
+
+void P_BringUpWeapon(player_t * player)
+{
+ statenum_t new;
+
+ if (player->pendingweapon == WP_NOCHANGE)
+ {
+ player->pendingweapon = player->readyweapon;
+ }
+ if (player->class == PCLASS_FIGHTER && player->pendingweapon == WP_SECOND
+ && player->mana[MANA_1])
+ {
+ new = S_FAXEUP_G;
+ }
+ else
+ {
+ new = WeaponInfo[player->pendingweapon][player->class].upstate;
+ }
+ player->pendingweapon = WP_NOCHANGE;
+ player->psprites[ps_weapon].sy = WEAPONBOTTOM;
+ P_SetPsprite(player, ps_weapon, new);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_CheckMana
+//
+// Returns true if there is enough mana to shoot. If not, selects the
+// next weapon to use.
+//
+//---------------------------------------------------------------------------
+
+boolean P_CheckMana(player_t * player)
+{
+ manatype_t mana;
+ int count;
+
+ mana = WeaponInfo[player->readyweapon][player->class].mana;
+ count = WeaponManaUse[player->class][player->readyweapon];
+ if (mana == MANA_BOTH)
+ {
+ if (player->mana[MANA_1] >= count && player->mana[MANA_2] >= count)
+ {
+ return true;
+ }
+ }
+ else if (mana == MANA_NONE || player->mana[mana] >= count)
+ {
+ return (true);
+ }
+ // out of mana, pick a weapon to change to
+ do
+ {
+ if (player->weaponowned[WP_THIRD]
+ && player->mana[MANA_2] >= WeaponManaUse[player->class][WP_THIRD])
+ {
+ player->pendingweapon = WP_THIRD;
+ }
+ else if (player->weaponowned[WP_SECOND]
+ && player->mana[MANA_1] >=
+ WeaponManaUse[player->class][WP_SECOND])
+ {
+ player->pendingweapon = WP_SECOND;
+ }
+ else if (player->weaponowned[WP_FOURTH]
+ && player->mana[MANA_1] >=
+ WeaponManaUse[player->class][WP_FOURTH]
+ && player->mana[MANA_2] >=
+ WeaponManaUse[player->class][WP_FOURTH])
+ {
+ player->pendingweapon = WP_FOURTH;
+ }
+ else
+ {
+ player->pendingweapon = WP_FIRST;
+ }
+ }
+ while (player->pendingweapon == WP_NOCHANGE);
+ P_SetPsprite(player, ps_weapon,
+ WeaponInfo[player->readyweapon][player->class].downstate);
+ return (false);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_FireWeapon
+//
+//---------------------------------------------------------------------------
+
+void P_FireWeapon(player_t * player)
+{
+ statenum_t attackState;
+
+ if (!P_CheckMana(player))
+ {
+ return;
+ }
+ P_SetMobjState(player->mo, PStateAttack[player->class]); // S_PLAY_ATK1);
+ if (player->class == PCLASS_FIGHTER && player->readyweapon == WP_SECOND
+ && player->mana[MANA_1] > 0)
+ { // Glowing axe
+ attackState = S_FAXEATK_G1;
+ }
+ else
+ {
+ attackState = player->refire ?
+ WeaponInfo[player->readyweapon][player->class].holdatkstate
+ : WeaponInfo[player->readyweapon][player->class].atkstate;
+ }
+ P_SetPsprite(player, ps_weapon, attackState);
+ P_NoiseAlert(player->mo, player->mo);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_DropWeapon
+//
+// The player died, so put the weapon away.
+//
+//---------------------------------------------------------------------------
+
+void P_DropWeapon(player_t * player)
+{
+ P_SetPsprite(player, ps_weapon,
+ WeaponInfo[player->readyweapon][player->class].downstate);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_WeaponReady
+//
+// The player can fire the weapon or change to another weapon at this time.
+//
+//---------------------------------------------------------------------------
+
+void A_WeaponReady(player_t * player, pspdef_t * psp)
+{
+ int angle;
+
+ // Change player from attack state
+ if (player->mo->state >= &states[PStateAttack[player->class]]
+ && player->mo->state <= &states[PStateAttackEnd[player->class]])
+ {
+ P_SetMobjState(player->mo, PStateNormal[player->class]);
+ }
+ // Put the weapon away if the player has a pending weapon or has
+ // died.
+ if (player->pendingweapon != WP_NOCHANGE || !player->health)
+ {
+ P_SetPsprite(player, ps_weapon,
+ WeaponInfo[player->readyweapon][player->class].
+ downstate);
+ return;
+ }
+
+ // Check for fire.
+ if (player->cmd.buttons & BT_ATTACK)
+ {
+ player->attackdown = true;
+ P_FireWeapon(player);
+ return;
+ }
+ else
+ {
+ player->attackdown = false;
+ }
+
+ if (!player->morphTics)
+ {
+ // 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]);
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_ReFire
+//
+// The player can re fire the weapon without lowering it entirely.
+//
+//---------------------------------------------------------------------------
+
+void A_ReFire(player_t * player, pspdef_t * psp)
+{
+ if ((player->cmd.buttons & BT_ATTACK)
+ && player->pendingweapon == WP_NOCHANGE && player->health)
+ {
+ player->refire++;
+ P_FireWeapon(player);
+ }
+ else
+ {
+ player->refire = 0;
+ P_CheckMana(player);
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_Lower
+//
+//---------------------------------------------------------------------------
+
+void A_Lower(player_t * player, pspdef_t * psp)
+{
+ if (player->morphTics)
+ {
+ psp->sy = WEAPONBOTTOM;
+ }
+ else
+ {
+ psp->sy += LOWERSPEED;
+ }
+ if (psp->sy < WEAPONBOTTOM)
+ { // Not lowered all the way yet
+ return;
+ }
+ if (player->playerstate == PST_DEAD)
+ { // Player is dead, so don't bring up a pending weapon
+ psp->sy = WEAPONBOTTOM;
+ return;
+ }
+ 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);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_Raise
+//
+//---------------------------------------------------------------------------
+
+void A_Raise(player_t * player, pspdef_t * psp)
+{
+ psp->sy -= RAISESPEED;
+ if (psp->sy > WEAPONTOP)
+ { // Not raised all the way yet
+ return;
+ }
+ psp->sy = WEAPONTOP;
+ if (player->class == PCLASS_FIGHTER && player->readyweapon == WP_SECOND
+ && player->mana[MANA_1])
+ {
+ P_SetPsprite(player, ps_weapon, S_FAXEREADY_G);
+ }
+ else
+ {
+ P_SetPsprite(player, ps_weapon,
+ WeaponInfo[player->readyweapon][player->class].
+ readystate);
+ }
+}
+
+/*
+===============
+=
+= 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);
+ }
+ if (!linetarget)
+ {
+ an += 1<<26;
+ bulletslope = (mo->player->lookdir<<FRACBITS)/173;
+ }
+ }
+}
+*/
+
+//
+// WEAPON ATTACKS
+//
+
+//============================================================================
+//
+// AdjustPlayerAngle
+//
+//============================================================================
+
+#define MAX_ANGADJUST (5*ANG1)
+
+void AdjustPlayerAngle(mobj_t * pmo)
+{
+ angle_t angle;
+ int difference;
+
+ angle = R_PointToAngle2(pmo->x, pmo->y, linetarget->x, linetarget->y);
+ difference = (int) angle - (int) pmo->angle;
+ if (abs(difference) > MAX_ANGADJUST)
+ {
+ pmo->angle += difference > 0 ? MAX_ANGADJUST : -MAX_ANGADJUST;
+ }
+ else
+ {
+ pmo->angle = angle;
+ }
+}
+
+//============================================================================
+//
+// A_SnoutAttack
+//
+//============================================================================
+
+void A_SnoutAttack(player_t * player, pspdef_t * psp)
+{
+ angle_t angle;
+ int damage;
+ int slope;
+
+ damage = 3 + (P_Random() & 3);
+ angle = player->mo->angle;
+ slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
+ PuffType = MT_SNOUTPUFF;
+ PuffSpawned = NULL;
+ P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
+ S_StartSound(player->mo, SFX_PIG_ACTIVE1 + (P_Random() & 1));
+ if (linetarget)
+ {
+ AdjustPlayerAngle(player->mo);
+// player->mo->angle = R_PointToAngle2(player->mo->x,
+// player->mo->y, linetarget->x, linetarget->y);
+ if (PuffSpawned)
+ { // Bit something
+ S_StartSound(player->mo, SFX_PIG_ATTACK);
+ }
+ }
+}
+
+//============================================================================
+//
+// A_FHammerAttack
+//
+//============================================================================
+
+#define HAMMER_RANGE (MELEERANGE+MELEERANGE/2)
+
+void A_FHammerAttack(player_t * player, pspdef_t * psp)
+{
+ angle_t angle;
+ mobj_t *pmo = player->mo;
+ int damage;
+ fixed_t power;
+ int slope;
+ int i;
+
+ damage = 60 + (P_Random() & 63);
+ power = 10 * FRACUNIT;
+ PuffType = MT_HAMMERPUFF;
+ for (i = 0; i < 16; i++)
+ {
+ angle = pmo->angle + i * (ANG45 / 32);
+ slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE);
+ if (linetarget)
+ {
+ P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage);
+ AdjustPlayerAngle(pmo);
+ if (linetarget->flags & MF_COUNTKILL || linetarget->player)
+ {
+ P_ThrustMobj(linetarget, angle, power);
+ }
+ pmo->special1.i = false; // Don't throw a hammer
+ goto hammerdone;
+ }
+ angle = pmo->angle - i * (ANG45 / 32);
+ slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE);
+ if (linetarget)
+ {
+ P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage);
+ AdjustPlayerAngle(pmo);
+ if (linetarget->flags & MF_COUNTKILL || linetarget->player)
+ {
+ P_ThrustMobj(linetarget, angle, power);
+ }
+ pmo->special1.i = false; // Don't throw a hammer
+ goto hammerdone;
+ }
+ }
+ // didn't find any targets in meleerange, so set to throw out a hammer
+ PuffSpawned = NULL;
+ angle = pmo->angle;
+ slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE);
+ P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage);
+ if (PuffSpawned)
+ {
+ pmo->special1.i = false;
+ }
+ else
+ {
+ pmo->special1.i = true;
+ }
+ hammerdone:
+ if (player->mana[MANA_2] <
+ WeaponManaUse[player->class][player->readyweapon])
+ { // Don't spawn a hammer if the player doesn't have enough mana
+ pmo->special1.i = false;
+ }
+ return;
+}
+
+//============================================================================
+//
+// A_FHammerThrow
+//
+//============================================================================
+
+void A_FHammerThrow(player_t * player, pspdef_t * psp)
+{
+ mobj_t *mo;
+
+ if (!player->mo->special1.i)
+ {
+ return;
+ }
+ player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
+ mo = P_SpawnPlayerMissile(player->mo, MT_HAMMER_MISSILE);
+ if (mo)
+ {
+ mo->special1.i = 0;
+ }
+}
+
+//============================================================================
+//
+// A_FSwordAttack
+//
+//============================================================================
+
+void A_FSwordAttack(player_t * player, pspdef_t * psp)
+{
+ mobj_t *pmo;
+
+ player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
+ player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
+ pmo = player->mo;
+ P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z - 10 * FRACUNIT,
+ MT_FSWORD_MISSILE, pmo->angle + ANG45 / 4);
+ P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z - 5 * FRACUNIT,
+ MT_FSWORD_MISSILE, pmo->angle + ANG45 / 8);
+ P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z, MT_FSWORD_MISSILE, pmo->angle);
+ P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z + 5 * FRACUNIT,
+ MT_FSWORD_MISSILE, pmo->angle - ANG45 / 8);
+ P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z + 10 * FRACUNIT,
+ MT_FSWORD_MISSILE, pmo->angle - ANG45 / 4);
+ S_StartSound(pmo, SFX_FIGHTER_SWORD_FIRE);
+}
+
+//============================================================================
+//
+// A_FSwordAttack2
+//
+//============================================================================
+
+void A_FSwordAttack2(mobj_t * actor)
+{
+ angle_t angle = actor->angle;
+
+ P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE, angle + ANG45 / 4, 0);
+ P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE, angle + ANG45 / 8, 0);
+ P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE, angle, 0);
+ P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE, angle - ANG45 / 8, 0);
+ P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE, angle - ANG45 / 4, 0);
+ S_StartSound(actor, SFX_FIGHTER_SWORD_FIRE);
+}
+
+//============================================================================
+//
+// A_FSwordFlames
+//
+//============================================================================
+
+void A_FSwordFlames(mobj_t * actor)
+{
+ int i;
+
+ for (i = 1 + (P_Random() & 3); i; i--)
+ {
+ P_SpawnMobj(actor->x + ((P_Random() - 128) << 12), actor->y
+ + ((P_Random() - 128) << 12),
+ actor->z + ((P_Random() - 128) << 11), MT_FSWORD_FLAME);
+ }
+}
+
+//============================================================================
+//
+// A_MWandAttack
+//
+//============================================================================
+
+void A_MWandAttack(player_t * player, pspdef_t * psp)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnPlayerMissile(player->mo, MT_MWAND_MISSILE);
+ if (mo)
+ {
+ mo->thinker.function = P_BlasterMobjThinker;
+ }
+ S_StartSound(player->mo, SFX_MAGE_WAND_FIRE);
+}
+
+// ===== Mage Lightning Weapon =====
+
+//============================================================================
+//
+// A_LightningReady
+//
+//============================================================================
+
+void A_LightningReady(player_t * player, pspdef_t * psp)
+{
+ A_WeaponReady(player, psp);
+ if (P_Random() < 160)
+ {
+ S_StartSound(player->mo, SFX_MAGE_LIGHTNING_READY);
+ }
+}
+
+//============================================================================
+//
+// A_LightningClip
+//
+//============================================================================
+
+#define ZAGSPEED FRACUNIT
+
+void A_LightningClip(mobj_t * actor)
+{
+ mobj_t *cMo;
+ mobj_t *target = NULL;
+ int zigZag;
+
+ if (actor->type == MT_LIGHTNING_FLOOR)
+ {
+ actor->z = actor->floorz;
+ target = actor->special2.m->special1.m;
+ }
+ else if (actor->type == MT_LIGHTNING_CEILING)
+ {
+ actor->z = actor->ceilingz - actor->height;
+ target = actor->special1.m;
+ }
+ if (actor->type == MT_LIGHTNING_FLOOR)
+ { // floor lightning zig-zags, and forces the ceiling lightning to mimic
+ cMo = actor->special2.m;
+ zigZag = P_Random();
+ if ((zigZag > 128 && actor->special1.i < 2) || actor->special1.i < -2)
+ {
+ P_ThrustMobj(actor, actor->angle + ANG90, ZAGSPEED);
+ if (cMo)
+ {
+ P_ThrustMobj(cMo, actor->angle + ANG90, ZAGSPEED);
+ }
+ actor->special1.i++;
+ }
+ else
+ {
+ P_ThrustMobj(actor, actor->angle - ANG90, ZAGSPEED);
+ if (cMo)
+ {
+ P_ThrustMobj(cMo, cMo->angle - ANG90, ZAGSPEED);
+ }
+ actor->special1.i--;
+ }
+ }
+ if (target)
+ {
+ if (target->health <= 0)
+ {
+ P_ExplodeMissile(actor);
+ }
+ else
+ {
+ actor->angle = R_PointToAngle2(actor->x, actor->y, target->x,
+ target->y);
+ actor->momx = 0;
+ actor->momy = 0;
+ P_ThrustMobj(actor, actor->angle, actor->info->speed >> 1);
+ }
+ }
+}
+
+//============================================================================
+//
+// A_LightningZap
+//
+//============================================================================
+
+void A_LightningZap(mobj_t * actor)
+{
+ mobj_t *mo;
+ fixed_t deltaZ;
+
+ A_LightningClip(actor);
+
+ actor->health -= 8;
+ if (actor->health <= 0)
+ {
+ P_SetMobjState(actor, actor->info->deathstate);
+ return;
+ }
+ if (actor->type == MT_LIGHTNING_FLOOR)
+ {
+ deltaZ = 10 * FRACUNIT;
+ }
+ else
+ {
+ deltaZ = -10 * FRACUNIT;
+ }
+ mo = P_SpawnMobj(actor->x + ((P_Random() - 128) * actor->radius / 256),
+ actor->y + ((P_Random() - 128) * actor->radius / 256),
+ actor->z + deltaZ, MT_LIGHTNING_ZAP);
+ if (mo)
+ {
+ mo->special2.m = actor;
+ mo->momx = actor->momx;
+ mo->momy = actor->momy;
+ mo->target = actor->target;
+ if (actor->type == MT_LIGHTNING_FLOOR)
+ {
+ mo->momz = 20 * FRACUNIT;
+ }
+ else
+ {
+ mo->momz = -20 * FRACUNIT;
+ }
+ }
+/*
+ mo = P_SpawnMobj(actor->x+((P_Random()-128)*actor->radius/256),
+ actor->y+((P_Random()-128)*actor->radius/256),
+ actor->z+deltaZ, MT_LIGHTNING_ZAP);
+ if(mo)
+ {
+ mo->special2.m = actor;
+ mo->momx = actor->momx;
+ mo->momy = actor->momy;
+ mo->target = actor->target;
+ if(actor->type == MT_LIGHTNING_FLOOR)
+ {
+ mo->momz = 16*FRACUNIT;
+ }
+ else
+ {
+ mo->momz = -16*FRACUNIT;
+ }
+ }
+*/
+ if (actor->type == MT_LIGHTNING_FLOOR && P_Random() < 160)
+ {
+ S_StartSound(actor, SFX_MAGE_LIGHTNING_CONTINUOUS);
+ }
+}
+
+//============================================================================
+//
+// A_MLightningAttack2
+//
+//============================================================================
+
+void A_MLightningAttack2(mobj_t * actor)
+{
+ mobj_t *fmo, *cmo;
+
+ fmo = P_SpawnPlayerMissile(actor, MT_LIGHTNING_FLOOR);
+ cmo = P_SpawnPlayerMissile(actor, MT_LIGHTNING_CEILING);
+ if (fmo)
+ {
+ fmo->special1.m = NULL;
+ fmo->special2.m = cmo;
+ A_LightningZap(fmo);
+ }
+ if (cmo)
+ {
+ cmo->special1.m = NULL; // mobj that it will track
+ cmo->special2.m = fmo;
+ A_LightningZap(cmo);
+ }
+ S_StartSound(actor, SFX_MAGE_LIGHTNING_FIRE);
+}
+
+//============================================================================
+//
+// A_MLightningAttack
+//
+//============================================================================
+
+void A_MLightningAttack(player_t * player, pspdef_t * psp)
+{
+ A_MLightningAttack2(player->mo);
+ player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
+}
+
+//============================================================================
+//
+// A_ZapMimic
+//
+//============================================================================
+
+void A_ZapMimic(mobj_t * actor)
+{
+ mobj_t *mo;
+
+ mo = actor->special2.m;
+ if (mo)
+ {
+ if (mo->state >= &states[mo->info->deathstate]
+ || mo->state == &states[S_FREETARGMOBJ])
+ {
+ P_ExplodeMissile(actor);
+ }
+ else
+ {
+ actor->momx = mo->momx;
+ actor->momy = mo->momy;
+ }
+ }
+}
+
+//============================================================================
+//
+// A_LastZap
+//
+//============================================================================
+
+void A_LastZap(mobj_t * actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_LIGHTNING_ZAP);
+ if (mo)
+ {
+ P_SetMobjState(mo, S_LIGHTNING_ZAP_X1);
+ mo->momz = 40 * FRACUNIT;
+ }
+}
+
+//============================================================================
+//
+// A_LightningRemove
+//
+//============================================================================
+
+void A_LightningRemove(mobj_t * actor)
+{
+ mobj_t *mo;
+
+ mo = actor->special2.m;
+ if (mo)
+ {
+ mo->special2.m = NULL;
+ P_ExplodeMissile(mo);
+ }
+}
+
+
+//============================================================================
+//
+// MStaffSpawn
+//
+//============================================================================
+void MStaffSpawn(mobj_t * pmo, angle_t angle)
+{
+ mobj_t *mo;
+
+ mo = P_SPMAngle(pmo, MT_MSTAFF_FX2, angle);
+ if (mo)
+ {
+ mo->target = pmo;
+ mo->special1.m = P_RoughMonsterSearch(mo, 10);
+ }
+}
+
+//============================================================================
+//
+// A_MStaffAttack
+//
+//============================================================================
+
+void A_MStaffAttack(player_t * player, pspdef_t * psp)
+{
+ angle_t angle;
+ mobj_t *pmo;
+
+ player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
+ player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
+ pmo = player->mo;
+ angle = pmo->angle;
+
+ MStaffSpawn(pmo, angle);
+ MStaffSpawn(pmo, angle - ANG1 * 5);
+ MStaffSpawn(pmo, angle + ANG1 * 5);
+ S_StartSound(player->mo, SFX_MAGE_STAFF_FIRE);
+ if (player == &players[consoleplayer])
+ {
+ player->damagecount = 0;
+ player->bonuscount = 0;
+ I_SetPalette((byte *) W_CacheLumpNum(W_GetNumForName("playpal"),
+ PU_CACHE) +
+ STARTSCOURGEPAL * 768);
+ }
+}
+
+//============================================================================
+//
+// A_MStaffPalette
+//
+//============================================================================
+
+void A_MStaffPalette(player_t * player, pspdef_t * psp)
+{
+ int pal;
+
+ if (player == &players[consoleplayer])
+ {
+ pal = STARTSCOURGEPAL + psp->state - (&states[S_MSTAFFATK_2]);
+ if (pal == STARTSCOURGEPAL + 3)
+ { // reset back to original playpal
+ pal = 0;
+ }
+ I_SetPalette((byte *) W_CacheLumpNum(W_GetNumForName("playpal"),
+ PU_CACHE) + pal * 768);
+ }
+}
+
+//============================================================================
+//
+// A_MStaffWeave
+//
+//============================================================================
+
+void A_MStaffWeave(mobj_t * actor)
+{
+ fixed_t newX, newY;
+ int weaveXY, weaveZ;
+ int angle;
+
+ weaveXY = actor->special2.i >> 16;
+ weaveZ = actor->special2.i & 0xFFFF;
+ angle = (actor->angle + ANG90) >> ANGLETOFINESHIFT;
+ newX = actor->x - FixedMul(finecosine[angle],
+ FloatBobOffsets[weaveXY] << 2);
+ newY = actor->y - FixedMul(finesine[angle],
+ FloatBobOffsets[weaveXY] << 2);
+ weaveXY = (weaveXY + 6) & 63;
+ newX += FixedMul(finecosine[angle], FloatBobOffsets[weaveXY] << 2);
+ newY += FixedMul(finesine[angle], FloatBobOffsets[weaveXY] << 2);
+ P_TryMove(actor, newX, newY);
+ actor->z -= FloatBobOffsets[weaveZ] << 1;
+ weaveZ = (weaveZ + 3) & 63;
+ actor->z += FloatBobOffsets[weaveZ] << 1;
+ if (actor->z <= actor->floorz)
+ {
+ actor->z = actor->floorz + FRACUNIT;
+ }
+ actor->special2.i = weaveZ + (weaveXY << 16);
+}
+
+
+//============================================================================
+//
+// A_MStaffTrack
+//
+//============================================================================
+
+void A_MStaffTrack(mobj_t * actor)
+{
+ if ((actor->special1.m == NULL) && (P_Random() < 50))
+ {
+ actor->special1.m = P_RoughMonsterSearch(actor, 10);
+ }
+ P_SeekerMissile(actor, ANG1 * 2, ANG1 * 10);
+}
+
+
+//============================================================================
+//
+// MStaffSpawn2 - for use by mage class boss
+//
+//============================================================================
+
+void MStaffSpawn2(mobj_t * actor, angle_t angle)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMissileAngle(actor, MT_MSTAFF_FX2, angle, 0);
+ if (mo)
+ {
+ mo->target = actor;
+ mo->special1.m = P_RoughMonsterSearch(mo, 10);
+ }
+}
+
+//============================================================================
+//
+// A_MStaffAttack2 - for use by mage class boss
+//
+//============================================================================
+
+void A_MStaffAttack2(mobj_t * actor)
+{
+ angle_t angle;
+ angle = actor->angle;
+ MStaffSpawn2(actor, angle);
+ MStaffSpawn2(actor, angle - ANG1 * 5);
+ MStaffSpawn2(actor, angle + ANG1 * 5);
+ S_StartSound(actor, SFX_MAGE_STAFF_FIRE);
+}
+
+//============================================================================
+//
+// A_FPunchAttack
+//
+//============================================================================
+
+void A_FPunchAttack(player_t * player, pspdef_t * psp)
+{
+ angle_t angle;
+ int damage;
+ int slope;
+ mobj_t *pmo = player->mo;
+ fixed_t power;
+ int i;
+
+ damage = 40 + (P_Random() & 15);
+ power = 2 * FRACUNIT;
+ PuffType = MT_PUNCHPUFF;
+ for (i = 0; i < 16; i++)
+ {
+ angle = pmo->angle + i * (ANG45 / 16);
+ slope = P_AimLineAttack(pmo, angle, 2 * MELEERANGE);
+ if (linetarget)
+ {
+ player->mo->special1.i++;
+ if (pmo->special1.i == 3)
+ {
+ damage <<= 1;
+ power = 6 * FRACUNIT;
+ PuffType = MT_HAMMERPUFF;
+ }
+ P_LineAttack(pmo, angle, 2 * MELEERANGE, slope, damage);
+ if (linetarget->flags & MF_COUNTKILL || linetarget->player)
+ {
+ P_ThrustMobj(linetarget, angle, power);
+ }
+ AdjustPlayerAngle(pmo);
+ goto punchdone;
+ }
+ angle = pmo->angle - i * (ANG45 / 16);
+ slope = P_AimLineAttack(pmo, angle, 2 * MELEERANGE);
+ if (linetarget)
+ {
+ pmo->special1.i++;
+ if (pmo->special1.i == 3)
+ {
+ damage <<= 1;
+ power = 6 * FRACUNIT;
+ PuffType = MT_HAMMERPUFF;
+ }
+ P_LineAttack(pmo, angle, 2 * MELEERANGE, slope, damage);
+ if (linetarget->flags & MF_COUNTKILL || linetarget->player)
+ {
+ P_ThrustMobj(linetarget, angle, power);
+ }
+ AdjustPlayerAngle(pmo);
+ goto punchdone;
+ }
+ }
+ // didn't find any creatures, so try to strike any walls
+ pmo->special1.i = 0;
+
+ angle = pmo->angle;
+ slope = P_AimLineAttack(pmo, angle, MELEERANGE);
+ P_LineAttack(pmo, angle, MELEERANGE, slope, damage);
+
+ punchdone:
+ if (pmo->special1.i == 3)
+ {
+ pmo->special1.i = 0;
+ P_SetPsprite(player, ps_weapon, S_PUNCHATK2_1);
+ S_StartSound(pmo, SFX_FIGHTER_GRUNT);
+ }
+ return;
+}
+
+//============================================================================
+//
+// A_FAxeAttack
+//
+//============================================================================
+
+#define AXERANGE 2.25*MELEERANGE
+
+void A_FAxeAttack(player_t * player, pspdef_t * psp)
+{
+ angle_t angle;
+ mobj_t *pmo = player->mo;
+ fixed_t power;
+ int damage;
+ int slope;
+ int i;
+ int useMana;
+
+ damage = 40 + (P_Random() & 15) + (P_Random() & 7);
+ power = 0;
+ if (player->mana[MANA_1] > 0)
+ {
+ damage <<= 1;
+ power = 6 * FRACUNIT;
+ PuffType = MT_AXEPUFF_GLOW;
+ useMana = 1;
+ }
+ else
+ {
+ PuffType = MT_AXEPUFF;
+ useMana = 0;
+ }
+ for (i = 0; i < 16; i++)
+ {
+ angle = pmo->angle + i * (ANG45 / 16);
+ slope = P_AimLineAttack(pmo, angle, AXERANGE);
+ if (linetarget)
+ {
+ P_LineAttack(pmo, angle, AXERANGE, slope, damage);
+ if (linetarget->flags & MF_COUNTKILL || linetarget->player)
+ {
+ P_ThrustMobj(linetarget, angle, power);
+ }
+ AdjustPlayerAngle(pmo);
+ useMana++;
+ goto axedone;
+ }
+ angle = pmo->angle - i * (ANG45 / 16);
+ slope = P_AimLineAttack(pmo, angle, AXERANGE);
+ if (linetarget)
+ {
+ P_LineAttack(pmo, angle, AXERANGE, slope, damage);
+ if (linetarget->flags & MF_COUNTKILL)
+ {
+ P_ThrustMobj(linetarget, angle, power);
+ }
+ AdjustPlayerAngle(pmo);
+ useMana++;
+ goto axedone;
+ }
+ }
+ // didn't find any creatures, so try to strike any walls
+ pmo->special1.m = NULL;
+
+ angle = pmo->angle;
+ slope = P_AimLineAttack(pmo, angle, MELEERANGE);
+ P_LineAttack(pmo, angle, MELEERANGE, slope, damage);
+
+ axedone:
+ if (useMana == 2)
+ {
+ player->mana[MANA_1] -=
+ WeaponManaUse[player->class][player->readyweapon];
+ if (player->mana[MANA_1] <= 0)
+ {
+ P_SetPsprite(player, ps_weapon, S_FAXEATK_5);
+ }
+ }
+ return;
+}
+
+//===========================================================================
+//
+// A_CMaceAttack
+//
+//===========================================================================
+
+void A_CMaceAttack(player_t * player, pspdef_t * psp)
+{
+ angle_t angle;
+ int damage;
+ int slope;
+ int i;
+
+ damage = 25 + (P_Random() & 15);
+ PuffType = MT_HAMMERPUFF;
+ for (i = 0; i < 16; i++)
+ {
+ angle = player->mo->angle + i * (ANG45 / 16);
+ slope = P_AimLineAttack(player->mo, angle, 2 * MELEERANGE);
+ if (linetarget)
+ {
+ P_LineAttack(player->mo, angle, 2 * MELEERANGE, slope, damage);
+ AdjustPlayerAngle(player->mo);
+// player->mo->angle = R_PointToAngle2(player->mo->x,
+// player->mo->y, linetarget->x, linetarget->y);
+ goto macedone;
+ }
+ angle = player->mo->angle - i * (ANG45 / 16);
+ slope = P_AimLineAttack(player->mo, angle, 2 * MELEERANGE);
+ if (linetarget)
+ {
+ P_LineAttack(player->mo, angle, 2 * MELEERANGE, slope, damage);
+ AdjustPlayerAngle(player->mo);
+// player->mo->angle = R_PointToAngle2(player->mo->x,
+// player->mo->y, linetarget->x, linetarget->y);
+ goto macedone;
+ }
+ }
+ // didn't find any creatures, so try to strike any walls
+ player->mo->special1.m = NULL;
+
+ angle = player->mo->angle;
+ slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
+ P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
+ macedone:
+ return;
+}
+
+//============================================================================
+//
+// A_CStaffCheck
+//
+//============================================================================
+
+void A_CStaffCheck(player_t * player, pspdef_t * psp)
+{
+ mobj_t *pmo;
+ int damage;
+ int newLife;
+ angle_t angle;
+ int slope;
+ int i;
+
+ pmo = player->mo;
+ damage = 20 + (P_Random() & 15);
+ PuffType = MT_CSTAFFPUFF;
+ for (i = 0; i < 3; i++)
+ {
+ angle = pmo->angle + i * (ANG45 / 16);
+ slope = P_AimLineAttack(pmo, angle, 1.5 * MELEERANGE);
+ if (linetarget)
+ {
+ P_LineAttack(pmo, angle, 1.5 * MELEERANGE, slope, damage);
+ pmo->angle = R_PointToAngle2(pmo->x, pmo->y,
+ linetarget->x, linetarget->y);
+ if ((linetarget->player || linetarget->flags & MF_COUNTKILL)
+ && (!(linetarget->flags2 & (MF2_DORMANT + MF2_INVULNERABLE))))
+ {
+ newLife = player->health + (damage >> 3);
+ newLife = newLife > 100 ? 100 : newLife;
+ pmo->health = player->health = newLife;
+ P_SetPsprite(player, ps_weapon, S_CSTAFFATK2_1);
+ }
+ player->mana[MANA_1] -=
+ WeaponManaUse[player->class][player->readyweapon];
+ break;
+ }
+ angle = pmo->angle - i * (ANG45 / 16);
+ slope = P_AimLineAttack(player->mo, angle, 1.5 * MELEERANGE);
+ if (linetarget)
+ {
+ P_LineAttack(pmo, angle, 1.5 * MELEERANGE, slope, damage);
+ pmo->angle = R_PointToAngle2(pmo->x, pmo->y,
+ linetarget->x, linetarget->y);
+ if (linetarget->player || linetarget->flags & MF_COUNTKILL)
+ {
+ newLife = player->health + (damage >> 4);
+ newLife = newLife > 100 ? 100 : newLife;
+ pmo->health = player->health = newLife;
+ P_SetPsprite(player, ps_weapon, S_CSTAFFATK2_1);
+ }
+ player->mana[MANA_1] -=
+ WeaponManaUse[player->class][player->readyweapon];
+ break;
+ }
+ }
+}
+
+//============================================================================
+//
+// A_CStaffAttack
+//
+//============================================================================
+
+void A_CStaffAttack(player_t * player, pspdef_t * psp)
+{
+ mobj_t *mo;
+ mobj_t *pmo;
+
+ player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
+ pmo = player->mo;
+ mo = P_SPMAngle(pmo, MT_CSTAFF_MISSILE, pmo->angle - (ANG45 / 15));
+ if (mo)
+ {
+ mo->special2.i = 32;
+ }
+ mo = P_SPMAngle(pmo, MT_CSTAFF_MISSILE, pmo->angle + (ANG45 / 15));
+ if (mo)
+ {
+ mo->special2.i = 0;
+ }
+ S_StartSound(player->mo, SFX_CLERIC_CSTAFF_FIRE);
+}
+
+//============================================================================
+//
+// A_CStaffMissileSlither
+//
+//============================================================================
+
+void A_CStaffMissileSlither(mobj_t * actor)
+{
+ fixed_t newX, newY;
+ int weaveXY;
+ int angle;
+
+ weaveXY = actor->special2.i;
+ angle = (actor->angle + ANG90) >> ANGLETOFINESHIFT;
+ newX = actor->x - FixedMul(finecosine[angle], FloatBobOffsets[weaveXY]);
+ newY = actor->y - FixedMul(finesine[angle], FloatBobOffsets[weaveXY]);
+ weaveXY = (weaveXY + 3) & 63;
+ newX += FixedMul(finecosine[angle], FloatBobOffsets[weaveXY]);
+ newY += FixedMul(finesine[angle], FloatBobOffsets[weaveXY]);
+ P_TryMove(actor, newX, newY);
+ actor->special2.i = weaveXY;
+}
+
+//============================================================================
+//
+// A_CStaffInitBlink
+//
+//============================================================================
+
+void A_CStaffInitBlink(player_t * player, pspdef_t * psp)
+{
+ player->mo->special1.i = (P_Random() >> 1) + 20;
+}
+
+//============================================================================
+//
+// A_CStaffCheckBlink
+//
+//============================================================================
+
+void A_CStaffCheckBlink(player_t * player, pspdef_t * psp)
+{
+ if (!--player->mo->special1.i)
+ {
+ P_SetPsprite(player, ps_weapon, S_CSTAFFBLINK1);
+ player->mo->special1.i = (P_Random() + 50) >> 2;
+ }
+}
+
+//============================================================================
+//
+// A_CFlameAttack
+//
+//============================================================================
+
+#define FLAMESPEED (0.45*FRACUNIT)
+#define CFLAMERANGE (12*64*FRACUNIT)
+
+void A_CFlameAttack(player_t * player, pspdef_t * psp)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnPlayerMissile(player->mo, MT_CFLAME_MISSILE);
+ if (mo)
+ {
+ mo->thinker.function = P_BlasterMobjThinker;
+ mo->special1.i = 2;
+ }
+
+ player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
+ S_StartSound(player->mo, SFX_CLERIC_FLAME_FIRE);
+}
+
+//============================================================================
+//
+// A_CFlamePuff
+//
+//============================================================================
+
+void A_CFlamePuff(mobj_t * actor)
+{
+ A_UnHideThing(actor);
+ actor->momx = 0;
+ actor->momy = 0;
+ actor->momz = 0;
+ S_StartSound(actor, SFX_CLERIC_FLAME_EXPLODE);
+}
+
+//============================================================================
+//
+// A_CFlameMissile
+//
+//============================================================================
+
+void A_CFlameMissile(mobj_t * actor)
+{
+ int i;
+ int an;
+ fixed_t dist;
+ mobj_t *mo;
+
+ A_UnHideThing(actor);
+ S_StartSound(actor, SFX_CLERIC_FLAME_EXPLODE);
+ if (BlockingMobj && BlockingMobj->flags & MF_SHOOTABLE)
+ { // Hit something, so spawn the flame circle around the thing
+ dist = BlockingMobj->radius + 18 * FRACUNIT;
+ for (i = 0; i < 4; i++)
+ {
+ an = (i * ANG45) >> ANGLETOFINESHIFT;
+ mo = P_SpawnMobj(BlockingMobj->x + FixedMul(dist, finecosine[an]),
+ BlockingMobj->y + FixedMul(dist, finesine[an]),
+ BlockingMobj->z + 5 * FRACUNIT, MT_CIRCLEFLAME);
+ if (mo)
+ {
+ mo->angle = an << ANGLETOFINESHIFT;
+ mo->target = actor->target;
+ mo->momx = mo->special1.i =
+ FixedMul(FLAMESPEED, finecosine[an]);
+ mo->momy = mo->special2.i = FixedMul(FLAMESPEED, finesine[an]);
+ mo->tics -= P_Random() & 3;
+ }
+ mo = P_SpawnMobj(BlockingMobj->x - FixedMul(dist, finecosine[an]),
+ BlockingMobj->y - FixedMul(dist, finesine[an]),
+ BlockingMobj->z + 5 * FRACUNIT, MT_CIRCLEFLAME);
+ if (mo)
+ {
+ mo->angle = ANG180 + (an << ANGLETOFINESHIFT);
+ mo->target = actor->target;
+ mo->momx = mo->special1.i = FixedMul(-FLAMESPEED,
+ finecosine[an]);
+ mo->momy = mo->special2.i = FixedMul(-FLAMESPEED, finesine[an]);
+ mo->tics -= P_Random() & 3;
+ }
+ }
+ P_SetMobjState(actor, S_FLAMEPUFF2_1);
+ }
+}
+
+/*
+void A_CFlameAttack(player_t *player, pspdef_t *psp)
+{
+ mobj_t *pmo;
+ angle_t angle;
+ int damage;
+ int i;
+ int an, an90;
+ fixed_t dist;
+ mobj_t *mo;
+
+ pmo = player->mo;
+ P_BulletSlope(pmo);
+ damage = 25+HITDICE(3);
+ angle = pmo->angle;
+ if(player->refire)
+ {
+ angle += (P_Random()-P_Random())<<17;
+ }
+ P_AimLineAttack(pmo, angle, CFLAMERANGE); // Correctly set linetarget
+ if(!linetarget)
+ {
+ angle += ANG1*2;
+ P_AimLineAttack(pmo, angle, CFLAMERANGE);
+ if(!linetarget)
+ {
+ angle -= ANG1*4;
+ P_AimLineAttack(pmo, angle, CFLAMERANGE);
+ if(!linetarget)
+ {
+ angle += ANG1*2;
+ }
+ }
+ }
+ if(linetarget)
+ {
+ PuffType = MT_FLAMEPUFF2;
+ }
+ else
+ {
+ PuffType = MT_FLAMEPUFF;
+ }
+ P_LineAttack(pmo, angle, CFLAMERANGE, bulletslope, damage);
+ if(linetarget)
+ { // Hit something, so spawn the flame circle around the thing
+ dist = linetarget->radius+18*FRACUNIT;
+ for(i = 0; i < 4; i++)
+ {
+ an = (i*ANG45)>>ANGLETOFINESHIFT;
+ an90 = (i*ANG45+ANG90)>>ANGLETOFINESHIFT;
+ mo = P_SpawnMobj(linetarget->x+FixedMul(dist, finecosine[an]),
+ linetarget->y+FixedMul(dist, finesine[an]),
+ linetarget->z+5*FRACUNIT, MT_CIRCLEFLAME);
+ if(mo)
+ {
+ mo->angle = an<<ANGLETOFINESHIFT;
+ mo->target = pmo;
+ mo->momx = mo->special1.i = FixedMul(FLAMESPEED, finecosine[an]);
+ mo->momy = mo->special2.i = FixedMul(FLAMESPEED, finesine[an]);
+ mo->tics -= P_Random()&3;
+ }
+ mo = P_SpawnMobj(linetarget->x-FixedMul(dist, finecosine[an]),
+ linetarget->y-FixedMul(dist, finesine[an]),
+ linetarget->z+5*FRACUNIT, MT_CIRCLEFLAME);
+ if(mo)
+ {
+ mo->angle = ANG180+(an<<ANGLETOFINESHIFT);
+ mo->target = pmo;
+ mo->momx = mo->special1.i = FixedMul(-FLAMESPEED,
+ finecosine[an]);
+ mo->momy = mo->special2.i = FixedMul(-FLAMESPEED, finesine[an]);
+ mo->tics -= P_Random()&3;
+ }
+ }
+ }
+// Create a line of flames from the player to the flame puff
+ CFlameCreateFlames(player->mo);
+
+ player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
+ S_StartSound(player->mo, SFX_CLERIC_FLAME_FIRE);
+}
+*/
+
+//============================================================================
+//
+// A_CFlameRotate
+//
+//============================================================================
+
+#define FLAMEROTSPEED 2*FRACUNIT
+
+void A_CFlameRotate(mobj_t * actor)
+{
+ int an;
+
+ an = (actor->angle + ANG90) >> ANGLETOFINESHIFT;
+ actor->momx = actor->special1.i + FixedMul(FLAMEROTSPEED, finecosine[an]);
+ actor->momy = actor->special2.i + FixedMul(FLAMEROTSPEED, finesine[an]);
+ actor->angle += ANG90 / 15;
+}
+
+
+//============================================================================
+//
+// A_CHolyAttack3
+//
+// Spawns the spirits
+//============================================================================
+
+void A_CHolyAttack3(mobj_t * actor)
+{
+ P_SpawnMissile(actor, actor->target, MT_HOLY_MISSILE);
+ S_StartSound(actor, SFX_CHOLY_FIRE);
+}
+
+
+//============================================================================
+//
+// A_CHolyAttack2
+//
+// Spawns the spirits
+//============================================================================
+
+void A_CHolyAttack2(mobj_t * actor)
+{
+ int j;
+ int i;
+ mobj_t *mo;
+ mobj_t *tail, *next;
+
+ for (j = 0; j < 4; j++)
+ {
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_HOLY_FX);
+ if (!mo)
+ {
+ continue;
+ }
+ switch (j)
+ { // float bob index
+ case 0:
+ mo->special2.i = P_Random() & 7; // upper-left
+ break;
+ case 1:
+ mo->special2.i = 32 + (P_Random() & 7); // upper-right
+ break;
+ case 2:
+ mo->special2.i = (32 + (P_Random() & 7)) << 16; // lower-left
+ break;
+ case 3:
+ mo->special2.i =
+ ((32 + (P_Random() & 7)) << 16) + 32 + (P_Random() & 7);
+ break;
+ }
+ mo->z = actor->z;
+ mo->angle = actor->angle + (ANG45 + ANG45 / 2) - ANG45 * j;
+ P_ThrustMobj(mo, mo->angle, mo->info->speed);
+ mo->target = actor->target;
+ mo->args[0] = 10; // initial turn value
+ mo->args[1] = 0; // initial look angle
+ if (deathmatch)
+ { // Ghosts last slightly less longer in DeathMatch
+ mo->health = 85;
+ }
+ if (linetarget)
+ {
+ mo->special1.m = linetarget;
+ mo->flags |= MF_NOCLIP | MF_SKULLFLY;
+ mo->flags &= ~MF_MISSILE;
+ }
+ tail = P_SpawnMobj(mo->x, mo->y, mo->z, MT_HOLY_TAIL);
+ tail->special2.m = mo; // parent
+ for (i = 1; i < 3; i++)
+ {
+ next = P_SpawnMobj(mo->x, mo->y, mo->z, MT_HOLY_TAIL);
+ P_SetMobjState(next, next->info->spawnstate + 1);
+ tail->special1.m = next;
+ tail = next;
+ }
+ tail->special1.m = NULL; // last tail bit
+ }
+}
+
+//============================================================================
+//
+// A_CHolyAttack
+//
+//============================================================================
+
+void A_CHolyAttack(player_t * player, pspdef_t * psp)
+{
+ player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
+ player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
+ P_SpawnPlayerMissile(player->mo, MT_HOLY_MISSILE);
+ if (player == &players[consoleplayer])
+ {
+ player->damagecount = 0;
+ player->bonuscount = 0;
+ I_SetPalette((byte *) W_CacheLumpNum(W_GetNumForName("playpal"),
+ PU_CACHE) + STARTHOLYPAL * 768);
+ }
+ S_StartSound(player->mo, SFX_CHOLY_FIRE);
+}
+
+//============================================================================
+//
+// A_CHolyPalette
+//
+//============================================================================
+
+void A_CHolyPalette(player_t * player, pspdef_t * psp)
+{
+ int pal;
+
+ if (player == &players[consoleplayer])
+ {
+ pal = STARTHOLYPAL + psp->state - (&states[S_CHOLYATK_6]);
+ if (pal == STARTHOLYPAL + 3)
+ { // reset back to original playpal
+ pal = 0;
+ }
+ I_SetPalette((byte *) W_CacheLumpNum(W_GetNumForName("playpal"),
+ PU_CACHE) + pal * 768);
+ }
+}
+
+//============================================================================
+//
+// CHolyFindTarget
+//
+//============================================================================
+
+static void CHolyFindTarget(mobj_t * actor)
+{
+ mobj_t *target;
+
+ target = P_RoughMonsterSearch(actor, 6);
+ if (target != NULL)
+ {
+ actor->special1.m = target;
+ actor->flags |= MF_NOCLIP | MF_SKULLFLY;
+ actor->flags &= ~MF_MISSILE;
+ }
+}
+
+//============================================================================
+//
+// CHolySeekerMissile
+//
+// Similar to P_SeekerMissile, but seeks to a random Z on the target
+//============================================================================
+
+static void CHolySeekerMissile(mobj_t * actor, angle_t thresh,
+ angle_t turnMax)
+{
+ int dir;
+ int dist;
+ angle_t delta;
+ angle_t angle;
+ mobj_t *target;
+ fixed_t newZ;
+ fixed_t deltaZ;
+
+ target = actor->special1.m;
+ if (target == NULL)
+ {
+ return;
+ }
+ if (!(target->flags & MF_SHOOTABLE)
+ || (!(target->flags & MF_COUNTKILL) && !target->player))
+ { // Target died/target isn't a player or creature
+ actor->special1.m = NULL;
+ actor->flags &= ~(MF_NOCLIP | MF_SKULLFLY);
+ actor->flags |= MF_MISSILE;
+ CHolyFindTarget(actor);
+ return;
+ }
+ dir = P_FaceMobj(actor, target, &delta);
+ if (delta > thresh)
+ {
+ delta >>= 1;
+ if (delta > turnMax)
+ {
+ delta = turnMax;
+ }
+ }
+ if (dir)
+ { // Turn clockwise
+ actor->angle += delta;
+ }
+ else
+ { // Turn counter clockwise
+ actor->angle -= delta;
+ }
+ angle = actor->angle >> ANGLETOFINESHIFT;
+ actor->momx = FixedMul(actor->info->speed, finecosine[angle]);
+ actor->momy = FixedMul(actor->info->speed, finesine[angle]);
+ if (!(leveltime & 15)
+ || actor->z > target->z + (target->height)
+ || actor->z + actor->height < target->z)
+ {
+ newZ = target->z + ((P_Random() * target->height) >> 8);
+ deltaZ = newZ - actor->z;
+ if (abs(deltaZ) > 15 * FRACUNIT)
+ {
+ if (deltaZ > 0)
+ {
+ deltaZ = 15 * FRACUNIT;
+ }
+ else
+ {
+ deltaZ = -15 * FRACUNIT;
+ }
+ }
+ dist = P_AproxDistance(target->x - actor->x, target->y - actor->y);
+ dist = dist / actor->info->speed;
+ if (dist < 1)
+ {
+ dist = 1;
+ }
+ actor->momz = deltaZ / dist;
+ }
+ return;
+}
+
+//============================================================================
+//
+// A_CHolyWeave
+//
+//============================================================================
+
+static void CHolyWeave(mobj_t * actor)
+{
+ fixed_t newX, newY;
+ int weaveXY, weaveZ;
+ int angle;
+
+ weaveXY = actor->special2.i >> 16;
+ weaveZ = actor->special2.i & 0xFFFF;
+ angle = (actor->angle + ANG90) >> ANGLETOFINESHIFT;
+ newX = actor->x - FixedMul(finecosine[angle],
+ FloatBobOffsets[weaveXY] << 2);
+ newY = actor->y - FixedMul(finesine[angle],
+ FloatBobOffsets[weaveXY] << 2);
+ weaveXY = (weaveXY + (P_Random() % 5)) & 63;
+ newX += FixedMul(finecosine[angle], FloatBobOffsets[weaveXY] << 2);
+ newY += FixedMul(finesine[angle], FloatBobOffsets[weaveXY] << 2);
+ P_TryMove(actor, newX, newY);
+ actor->z -= FloatBobOffsets[weaveZ] << 1;
+ weaveZ = (weaveZ + (P_Random() % 5)) & 63;
+ actor->z += FloatBobOffsets[weaveZ] << 1;
+ actor->special2.i = weaveZ + (weaveXY << 16);
+}
+
+//============================================================================
+//
+// A_CHolySeek
+//
+//============================================================================
+
+void A_CHolySeek(mobj_t * actor)
+{
+ actor->health--;
+ if (actor->health <= 0)
+ {
+ actor->momx >>= 2;
+ actor->momy >>= 2;
+ actor->momz = 0;
+ P_SetMobjState(actor, actor->info->deathstate);
+ actor->tics -= P_Random() & 3;
+ return;
+ }
+ if (actor->special1.m)
+ {
+ CHolySeekerMissile(actor, actor->args[0] * ANG1,
+ actor->args[0] * ANG1 * 2);
+ if (!((leveltime + 7) & 15))
+ {
+ actor->args[0] = 5 + (P_Random() / 20);
+ }
+ }
+ CHolyWeave(actor);
+}
+
+//============================================================================
+//
+// CHolyTailFollow
+//
+//============================================================================
+
+static void CHolyTailFollow(mobj_t * actor, fixed_t dist)
+{
+ mobj_t *child;
+ int an;
+ fixed_t oldDistance, newDistance;
+
+ child = actor->special1.m;
+ if (child)
+ {
+ an = R_PointToAngle2(actor->x, actor->y, child->x,
+ child->y) >> ANGLETOFINESHIFT;
+ oldDistance =
+ P_AproxDistance(child->x - actor->x, child->y - actor->y);
+ if (P_TryMove
+ (child, actor->x + FixedMul(dist, finecosine[an]),
+ actor->y + FixedMul(dist, finesine[an])))
+ {
+ newDistance = P_AproxDistance(child->x - actor->x,
+ child->y - actor->y) - FRACUNIT;
+ if (oldDistance < FRACUNIT)
+ {
+ if (child->z < actor->z)
+ {
+ child->z = actor->z - dist;
+ }
+ else
+ {
+ child->z = actor->z + dist;
+ }
+ }
+ else
+ {
+ child->z = actor->z + FixedMul(FixedDiv(newDistance,
+ oldDistance),
+ child->z - actor->z);
+ }
+ }
+ CHolyTailFollow(child, dist - FRACUNIT);
+ }
+}
+
+//============================================================================
+//
+// CHolyTailRemove
+//
+//============================================================================
+
+static void CHolyTailRemove(mobj_t * actor)
+{
+ mobj_t *child;
+
+ child = actor->special1.m;
+ if (child)
+ {
+ CHolyTailRemove(child);
+ }
+ P_RemoveMobj(actor);
+}
+
+//============================================================================
+//
+// A_CHolyTail
+//
+//============================================================================
+
+void A_CHolyTail(mobj_t * actor)
+{
+ mobj_t *parent;
+
+ parent = actor->special2.m;
+
+ if (parent)
+ {
+ if (parent->state >= &states[parent->info->deathstate])
+ { // Ghost removed, so remove all tail parts
+ CHolyTailRemove(actor);
+ return;
+ }
+ else if (P_TryMove(actor, parent->x - FixedMul(14 * FRACUNIT,
+ finecosine[parent->
+ angle >>
+ ANGLETOFINESHIFT]),
+ parent->y - FixedMul(14 * FRACUNIT,
+ finesine[parent->
+ angle >>
+ ANGLETOFINESHIFT])))
+ {
+ actor->z = parent->z - 5 * FRACUNIT;
+ }
+ CHolyTailFollow(actor, 10 * FRACUNIT);
+ }
+}
+
+//============================================================================
+//
+// A_CHolyCheckScream
+//
+//============================================================================
+
+void A_CHolyCheckScream(mobj_t * actor)
+{
+ A_CHolySeek(actor);
+ if (P_Random() < 20)
+ {
+ S_StartSound(actor, SFX_SPIRIT_ACTIVE);
+ }
+ if (!actor->special1.m)
+ {
+ CHolyFindTarget(actor);
+ }
+}
+
+//============================================================================
+//
+// A_CHolySpawnPuff
+//
+//============================================================================
+
+void A_CHolySpawnPuff(mobj_t * actor)
+{
+ P_SpawnMobj(actor->x, actor->y, actor->z, MT_HOLY_MISSILE_PUFF);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FireConePL1
+//
+//----------------------------------------------------------------------------
+
+#define SHARDSPAWN_LEFT 1
+#define SHARDSPAWN_RIGHT 2
+#define SHARDSPAWN_UP 4
+#define SHARDSPAWN_DOWN 8
+
+void A_FireConePL1(player_t * player, pspdef_t * psp)
+{
+ angle_t angle;
+ int damage;
+ int i;
+ mobj_t *pmo, *mo;
+ int conedone = false;
+
+ pmo = player->mo;
+ player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
+ S_StartSound(pmo, SFX_MAGE_SHARDS_FIRE);
+
+ damage = 90 + (P_Random() & 15);
+ for (i = 0; i < 16; i++)
+ {
+ angle = pmo->angle + i * (ANG45 / 16);
+ P_AimLineAttack(pmo, angle, MELEERANGE);
+ if (linetarget)
+ {
+ pmo->flags2 |= MF2_ICEDAMAGE;
+ P_DamageMobj(linetarget, pmo, pmo, damage);
+ pmo->flags2 &= ~MF2_ICEDAMAGE;
+ conedone = true;
+ break;
+ }
+ }
+
+ // didn't find any creatures, so fire projectiles
+ if (!conedone)
+ {
+ mo = P_SpawnPlayerMissile(pmo, MT_SHARDFX1);
+ if (mo)
+ {
+ mo->special1.i = SHARDSPAWN_LEFT | SHARDSPAWN_DOWN | SHARDSPAWN_UP
+ | SHARDSPAWN_RIGHT;
+ mo->special2.i = 3; // Set sperm count (levels of reproductivity)
+ mo->target = pmo;
+ mo->args[0] = 3; // Mark Initial shard as super damage
+ }
+ }
+}
+
+void A_ShedShard(mobj_t * actor)
+{
+ mobj_t *mo;
+ int spawndir = actor->special1.i;
+ int spermcount = actor->special2.i;
+
+ if (spermcount <= 0)
+ return; // No sperm left
+ actor->special2.i = 0;
+ spermcount--;
+
+ // every so many calls, spawn a new missile in it's set directions
+ if (spawndir & SHARDSPAWN_LEFT)
+ {
+ mo = P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1,
+ actor->angle + (ANG45 / 9), 0,
+ (20 + 2 * spermcount) << FRACBITS);
+ if (mo)
+ {
+ mo->special1.i = SHARDSPAWN_LEFT;
+ mo->special2.i = spermcount;
+ mo->momz = actor->momz;
+ mo->target = actor->target;
+ mo->args[0] = (spermcount == 3) ? 2 : 0;
+ }
+ }
+ if (spawndir & SHARDSPAWN_RIGHT)
+ {
+ mo = P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1,
+ actor->angle - (ANG45 / 9), 0,
+ (20 + 2 * spermcount) << FRACBITS);
+ if (mo)
+ {
+ mo->special1.i = SHARDSPAWN_RIGHT;
+ mo->special2.i = spermcount;
+ mo->momz = actor->momz;
+ mo->target = actor->target;
+ mo->args[0] = (spermcount == 3) ? 2 : 0;
+ }
+ }
+ if (spawndir & SHARDSPAWN_UP)
+ {
+ mo = P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle,
+ 0, (15 + 2 * spermcount) << FRACBITS);
+ if (mo)
+ {
+ mo->momz = actor->momz;
+ mo->z += 8 * FRACUNIT;
+ if (spermcount & 1) // Every other reproduction
+ mo->special1.i =
+ SHARDSPAWN_UP | SHARDSPAWN_LEFT | SHARDSPAWN_RIGHT;
+ else
+ mo->special1.i = SHARDSPAWN_UP;
+ mo->special2.i = spermcount;
+ mo->target = actor->target;
+ mo->args[0] = (spermcount == 3) ? 2 : 0;
+ }
+ }
+ if (spawndir & SHARDSPAWN_DOWN)
+ {
+ mo = P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle,
+ 0, (15 + 2 * spermcount) << FRACBITS);
+ if (mo)
+ {
+ mo->momz = actor->momz;
+ mo->z -= 4 * FRACUNIT;
+ if (spermcount & 1) // Every other reproduction
+ mo->special1.i =
+ SHARDSPAWN_DOWN | SHARDSPAWN_LEFT | SHARDSPAWN_RIGHT;
+ else
+ mo->special1.i = SHARDSPAWN_DOWN;
+ mo->special2.i = spermcount;
+ mo->target = actor->target;
+ mo->args[0] = (spermcount == 3) ? 2 : 0;
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_HideInCeiling
+//
+//----------------------------------------------------------------------------
+
+/*
+void A_HideInCeiling(mobj_t *actor)
+{
+ actor->z = actor->ceilingz+4*FRACUNIT;
+}
+*/
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FloatPuff
+//
+//----------------------------------------------------------------------------
+
+/*
+void A_FloatPuff(mobj_t *puff)
+{
+ puff->momz += 1.8*FRACUNIT;
+}
+*/
+
+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;
+}
+*/
+
+//------------------------------------------------------------------------
+//
+// PROC 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 = NULL;
+ }
+ // Spawn the ready weapon
+ player->pendingweapon = player->readyweapon;
+ P_BringUpWeapon(player);
+}
+
+//------------------------------------------------------------------------
+//
+// PROC 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++)
+ {
+ if ((state = psp->state) != 0) // a null state means not active
+ {
+ // drop tic count and possibly change state
+ if (psp->tics != -1) // a -1 tic count never changes
+ {
+ 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;
+}
diff --git a/src/hexen/p_setup.c b/src/hexen/p_setup.c
new file mode 100644
index 00000000..1d7c943a
--- /dev/null
+++ b/src/hexen/p_setup.c
@@ -0,0 +1,1227 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+// HEADER FILES ------------------------------------------------------------
+
+#include <math.h>
+#include <stdlib.h>
+#include "h2def.h"
+#include "i_system.h"
+#include "m_argv.h"
+#include "m_bbox.h"
+#include "i_swap.h"
+#include "s_sound.h"
+#include "p_local.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define MAPINFO_SCRIPT_NAME "MAPINFO"
+#define MCMD_SKY1 1
+#define MCMD_SKY2 2
+#define MCMD_LIGHTNING 3
+#define MCMD_FADETABLE 4
+#define MCMD_DOUBLESKY 5
+#define MCMD_CLUSTER 6
+#define MCMD_WARPTRANS 7
+#define MCMD_NEXT 8
+#define MCMD_CDTRACK 9
+#define MCMD_CD_STARTTRACK 10
+#define MCMD_CD_END1TRACK 11
+#define MCMD_CD_END2TRACK 12
+#define MCMD_CD_END3TRACK 13
+#define MCMD_CD_INTERTRACK 14
+#define MCMD_CD_TITLETRACK 15
+
+#define UNKNOWN_MAP_NAME "DEVELOPMENT MAP"
+#define DEFAULT_SKY_NAME "SKY1"
+#define DEFAULT_SONG_LUMP "DEFSONG"
+#define DEFAULT_FADE_TABLE "COLORMAP"
+
+// TYPES -------------------------------------------------------------------
+
+typedef struct mapInfo_s mapInfo_t;
+struct mapInfo_s
+{
+ short cluster;
+ short warpTrans;
+ short nextMap;
+ short cdTrack;
+ char name[32];
+ short sky1Texture;
+ short sky2Texture;
+ fixed_t sky1ScrollDelta;
+ fixed_t sky2ScrollDelta;
+ boolean doubleSky;
+ boolean lightning;
+ int fadetable;
+ char songLump[10];
+};
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+void P_SpawnMapThing(mapthing_t * mthing);
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static int QualifyMap(int map);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+int MapCount;
+mapthing_t deathmatchstarts[MAXDEATHMATCHSTARTS], *deathmatch_p;
+mapthing_t playerstarts[MAX_PLAYER_STARTS][MAXPLAYERS];
+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;
+short *blockmaplump; // offsets in blockmap are from here
+short *blockmap;
+int bmapwidth, bmapheight; // in mapblocks
+fixed_t bmaporgx, bmaporgy; // origin of block map
+mobj_t **blocklinks; // for thing chains
+byte *rejectmatrix; // for fast sight rejection
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static mapInfo_t MapInfo[99];
+static char *MapCmdNames[] = {
+ "SKY1",
+ "SKY2",
+ "DOUBLESKY",
+ "LIGHTNING",
+ "FADETABLE",
+ "CLUSTER",
+ "WARPTRANS",
+ "NEXT",
+ "CDTRACK",
+ "CD_START_TRACK",
+ "CD_END1_TRACK",
+ "CD_END2_TRACK",
+ "CD_END3_TRACK",
+ "CD_INTERMISSION_TRACK",
+ "CD_TITLE_TRACK",
+ NULL
+};
+static int MapCmdIDs[] = {
+ MCMD_SKY1,
+ MCMD_SKY2,
+ MCMD_DOUBLESKY,
+ MCMD_LIGHTNING,
+ MCMD_FADETABLE,
+ MCMD_CLUSTER,
+ MCMD_WARPTRANS,
+ MCMD_NEXT,
+ MCMD_CDTRACK,
+ MCMD_CD_STARTTRACK,
+ MCMD_CD_END1TRACK,
+ MCMD_CD_END2TRACK,
+ MCMD_CD_END3TRACK,
+ MCMD_CD_INTERTRACK,
+ MCMD_CD_TITLETRACK
+};
+
+static int cd_NonLevelTracks[6]; // Non-level specific song cd track numbers
+
+// CODE --------------------------------------------------------------------
+
+/*
+=================
+=
+= P_LoadVertexes
+=
+=================
+*/
+
+void P_LoadVertexes(int lump)
+{
+ byte *data;
+ int i;
+ mapvertex_t *ml;
+ vertex_t *li;
+
+ numvertexes = W_LumpLength(lump) / sizeof(mapvertex_t);
+ vertexes = Z_Malloc(numvertexes * sizeof(vertex_t), PU_LEVEL, 0);
+ data = W_CacheLumpNum(lump, PU_STATIC);
+
+ ml = (mapvertex_t *) data;
+ li = vertexes;
+ for (i = 0; i < numvertexes; i++, li++, ml++)
+ {
+ li->x = SHORT(ml->x) << FRACBITS;
+ li->y = SHORT(ml->y) << FRACBITS;
+ }
+
+ W_ReleaseLumpNum(lump);
+}
+
+
+/*
+=================
+=
+= P_LoadSegs
+=
+=================
+*/
+
+void P_LoadSegs(int lump)
+{
+ byte *data;
+ int i;
+ mapseg_t *ml;
+ seg_t *li;
+ line_t *ldef;
+ int linedef, side;
+
+ numsegs = W_LumpLength(lump) / sizeof(mapseg_t);
+ segs = Z_Malloc(numsegs * sizeof(seg_t), PU_LEVEL, 0);
+ 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;
+ }
+
+ W_ReleaseLumpNum(lump);
+}
+
+
+/*
+=================
+=
+= 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;
+ 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);
+ }
+
+ W_ReleaseLumpNum(lump);
+}
+
+
+/*
+=================
+=
+= 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);
+ 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 = NULL;
+ ss->seqType = SEQTYPE_STONE; // default seqType
+ }
+ W_ReleaseLumpNum(lump);
+}
+
+
+/*
+=================
+=
+= P_LoadNodes
+=
+=================
+*/
+
+void P_LoadNodes(int lump)
+{
+ byte *data;
+ int i, j, 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;
+ }
+ }
+ W_ReleaseLumpNum(lump);
+}
+
+//==========================================================================
+//
+// P_LoadThings
+//
+//==========================================================================
+
+void P_LoadThings(int lump)
+{
+ byte *data;
+ int i;
+ mapthing_t spawnthing;
+ mapthing_t *mt;
+ int numthings;
+ int playerCount;
+ int deathSpotsCount;
+
+ data = W_CacheLumpNum(lump, PU_STATIC);
+ numthings = W_LumpLength(lump) / sizeof(mapthing_t);
+
+ mt = (mapthing_t *) data;
+ for (i = 0; i < numthings; i++, mt++)
+ {
+ spawnthing.tid = SHORT(mt->tid);
+ spawnthing.x = SHORT(mt->x);
+ spawnthing.y = SHORT(mt->y);
+ spawnthing.height = SHORT(mt->height);
+ spawnthing.angle = SHORT(mt->angle);
+ spawnthing.type = SHORT(mt->type);
+ spawnthing.options = SHORT(mt->options);
+
+ spawnthing.special = mt->special;
+ spawnthing.arg1 = mt->arg1;
+ spawnthing.arg2 = mt->arg2;
+ spawnthing.arg3 = mt->arg3;
+ spawnthing.arg4 = mt->arg4;
+ spawnthing.arg5 = mt->arg5;
+
+ P_SpawnMapThing(&spawnthing);
+ }
+ P_CreateTIDList();
+ P_InitCreatureCorpseQueue(false); // false = do NOT scan for corpses
+ W_ReleaseLumpNum(lump);
+
+ if (!deathmatch)
+ { // Don't need to check deathmatch spots
+ return;
+ }
+ playerCount = 0;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ playerCount += playeringame[i];
+ }
+ deathSpotsCount = deathmatch_p - deathmatchstarts;
+ if (deathSpotsCount < playerCount)
+ {
+ I_Error("P_LoadThings: Player count (%d) exceeds deathmatch "
+ "spots (%d)", playerCount, deathSpotsCount);
+ }
+}
+
+/*
+=================
+=
+= P_LoadLineDefs
+=
+=================
+*/
+
+void P_LoadLineDefs(int lump)
+{
+ byte *data;
+ int i;
+ maplinedef_t *mld;
+ line_t *ld;
+ vertex_t *v1, *v2;
+
+ numlines = W_LumpLength(lump) / sizeof(maplinedef_t);
+ lines = Z_Malloc(numlines * sizeof(line_t), PU_LEVEL, 0);
+ 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);
+
+ // Old line special info ...
+ //ld->special = SHORT(mld->special);
+ //ld->tag = SHORT(mld->tag);
+
+ // New line special info ...
+ ld->special = mld->special;
+ ld->arg1 = mld->arg1;
+ ld->arg2 = mld->arg2;
+ ld->arg3 = mld->arg3;
+ ld->arg4 = mld->arg4;
+ ld->arg5 = mld->arg5;
+
+ 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;
+ }
+
+ W_ReleaseLumpNum(lump);
+}
+
+
+/*
+=================
+=
+= 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);
+ 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)];
+ }
+ W_ReleaseLumpNum(lump);
+}
+
+/*
+=================
+=
+= P_LoadBlockMap
+=
+=================
+*/
+
+void P_LoadBlockMap(int lump)
+{
+ int i, count;
+ int lumplen;
+
+ lumplen = W_LumpLength(lump);
+
+ blockmaplump = Z_Malloc(lumplen, PU_LEVEL, NULL);
+ W_ReadLump(lump, blockmaplump);
+ blockmap = blockmaplump + 4;
+
+ // Swap all short integers to native byte ordering:
+
+ count = lumplen / 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);
+ 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, j, 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("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
+=
+=================
+*/
+
+// haleyjd FIXME: CDMUSIC
+#ifdef __WATCOMC__
+extern boolean i_CDMusic;
+#endif
+
+void P_SetupLevel(int episode, int map, int playermask, skill_t skill)
+{
+ int i;
+ int parm;
+ char lumpname[9];
+ int lumpnum;
+ mobj_t *mobj;
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ players[i].killcount = players[i].secretcount
+ = players[i].itemcount = 0;
+ }
+ players[consoleplayer].viewz = 1; // will be set by player think
+
+
+ // haleyjd FIXME: CDMUSIC
+#ifdef __WATCOMC__
+ if (i_CDMusic == false)
+ {
+ S_StartSongName("chess", true); // Waiting-for-level-load song
+ }
+#endif
+
+ Z_FreeTags(PU_LEVEL, PU_PURGELEVEL - 1);
+
+ P_InitThinkers();
+ leveltime = 0;
+
+ sprintf(lumpname, "MAP%02d", map);
+ lumpnum = W_GetNumForName(lumpname);
+ //
+ // Begin processing map lumps
+ // 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;
+ po_NumPolyobjs = 0;
+ deathmatch_p = deathmatchstarts;
+ P_LoadThings(lumpnum + ML_THINGS);
+ PO_Init(lumpnum + ML_THINGS); // Initialize the polyobjs
+ P_LoadACScripts(lumpnum + ML_BEHAVIOR); // ACS object code
+ //
+ // End of map lump processing
+ //
+
+ // If deathmatch, randomly spawn the active players
+ TimerGame = 0;
+ if (deathmatch)
+ {
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ { // must give a player spot before deathmatchspawn
+ mobj = P_SpawnMobj(playerstarts[0][i].x << 16,
+ playerstarts[0][i].y << 16, 0,
+ MT_PLAYER_FIGHTER);
+ players[i].mo = mobj;
+ G_DeathMatchSpawnPlayer(i);
+ P_RemoveMobj(mobj);
+ }
+ }
+ parm = M_CheckParm("-timer");
+ if (parm && parm < myargc - 1)
+ {
+ TimerGame = atoi(myargv[parm + 1]) * 35 * 60;
+ }
+ }
+
+// set up world state
+ P_SpawnSpecials();
+
+// build subsector connect matrix
+// P_ConnectSubsectors ();
+
+// Load colormap and set the fullbright flag
+ i = P_GetMapFadeTable(gamemap);
+ W_ReadLump(i, colormaps);
+ if (i == W_GetNumForName("COLORMAP"))
+ {
+ LevelUseFullBright = true;
+ }
+ else
+ { // Probably fog ... don't use fullbright sprites
+ LevelUseFullBright = false;
+ }
+
+// preload graphics
+ if (precache)
+ R_PrecacheLevel();
+
+ // Check if the level is a lightning level
+ P_InitLightning();
+
+ S_StopAllSound();
+ SN_StopAllSequences();
+ S_StartSong(gamemap, true);
+
+//printf ("free memory: 0x%x\n", Z_FreeMemory());
+
+}
+
+//==========================================================================
+//
+// InitMapInfo
+//
+//==========================================================================
+
+static void InitMapInfo(void)
+{
+ int map;
+ int mapMax;
+ int mcmdValue;
+ mapInfo_t *info;
+ char songMulch[10];
+
+ mapMax = 1;
+
+ // Put defaults into MapInfo[0]
+ info = MapInfo;
+ info->cluster = 0;
+ info->warpTrans = 0;
+ info->nextMap = 1; // Always go to map 1 if not specified
+ info->cdTrack = 1;
+ info->sky1Texture = R_TextureNumForName(DEFAULT_SKY_NAME);
+ info->sky2Texture = info->sky1Texture;
+ info->sky1ScrollDelta = 0;
+ info->sky2ScrollDelta = 0;
+ info->doubleSky = false;
+ info->lightning = false;
+ info->fadetable = W_GetNumForName(DEFAULT_FADE_TABLE);
+ strcpy(info->name, UNKNOWN_MAP_NAME);
+
+// strcpy(info->songLump, DEFAULT_SONG_LUMP);
+ SC_Open(MAPINFO_SCRIPT_NAME);
+ while (SC_GetString())
+ {
+ if (SC_Compare("MAP") == false)
+ {
+ SC_ScriptError(NULL);
+ }
+ SC_MustGetNumber();
+ if (sc_Number < 1 || sc_Number > 99)
+ { //
+ SC_ScriptError(NULL);
+ }
+ map = sc_Number;
+
+ info = &MapInfo[map];
+
+ // Save song lump name
+ strcpy(songMulch, info->songLump);
+
+ // Copy defaults to current map definition
+ memcpy(info, &MapInfo[0], sizeof(*info));
+
+ // Restore song lump name
+ strcpy(info->songLump, songMulch);
+
+ // The warp translation defaults to the map number
+ info->warpTrans = map;
+
+ // Map name must follow the number
+ SC_MustGetString();
+ strcpy(info->name, sc_String);
+
+ // Process optional tokens
+ while (SC_GetString())
+ {
+ if (SC_Compare("MAP"))
+ { // Start next map definition
+ SC_UnGet();
+ break;
+ }
+ mcmdValue = MapCmdIDs[SC_MustMatchString(MapCmdNames)];
+ switch (mcmdValue)
+ {
+ case MCMD_CLUSTER:
+ SC_MustGetNumber();
+ info->cluster = sc_Number;
+ break;
+ case MCMD_WARPTRANS:
+ SC_MustGetNumber();
+ info->warpTrans = sc_Number;
+ break;
+ case MCMD_NEXT:
+ SC_MustGetNumber();
+ info->nextMap = sc_Number;
+ break;
+ case MCMD_CDTRACK:
+ SC_MustGetNumber();
+ info->cdTrack = sc_Number;
+ break;
+ case MCMD_SKY1:
+ SC_MustGetString();
+ info->sky1Texture = R_TextureNumForName(sc_String);
+ SC_MustGetNumber();
+ info->sky1ScrollDelta = sc_Number << 8;
+ break;
+ case MCMD_SKY2:
+ SC_MustGetString();
+ info->sky2Texture = R_TextureNumForName(sc_String);
+ SC_MustGetNumber();
+ info->sky2ScrollDelta = sc_Number << 8;
+ break;
+ case MCMD_DOUBLESKY:
+ info->doubleSky = true;
+ break;
+ case MCMD_LIGHTNING:
+ info->lightning = true;
+ break;
+ case MCMD_FADETABLE:
+ SC_MustGetString();
+ info->fadetable = W_GetNumForName(sc_String);
+ break;
+ case MCMD_CD_STARTTRACK:
+ case MCMD_CD_END1TRACK:
+ case MCMD_CD_END2TRACK:
+ case MCMD_CD_END3TRACK:
+ case MCMD_CD_INTERTRACK:
+ case MCMD_CD_TITLETRACK:
+ SC_MustGetNumber();
+ cd_NonLevelTracks[mcmdValue - MCMD_CD_STARTTRACK] =
+ sc_Number;
+ break;
+ }
+ }
+ mapMax = map > mapMax ? map : mapMax;
+ }
+ SC_Close();
+ MapCount = mapMax;
+}
+
+//==========================================================================
+//
+// P_GetMapCluster
+//
+//==========================================================================
+
+int P_GetMapCluster(int map)
+{
+ return MapInfo[QualifyMap(map)].cluster;
+}
+
+//==========================================================================
+//
+// P_GetMapCDTrack
+//
+//==========================================================================
+
+int P_GetMapCDTrack(int map)
+{
+ return MapInfo[QualifyMap(map)].cdTrack;
+}
+
+//==========================================================================
+//
+// P_GetMapWarpTrans
+//
+//==========================================================================
+
+int P_GetMapWarpTrans(int map)
+{
+ return MapInfo[QualifyMap(map)].warpTrans;
+}
+
+//==========================================================================
+//
+// P_GetMapNextMap
+//
+//==========================================================================
+
+int P_GetMapNextMap(int map)
+{
+ return MapInfo[QualifyMap(map)].nextMap;
+}
+
+//==========================================================================
+//
+// P_TranslateMap
+//
+// Returns the actual map number given a warp map number.
+//
+//==========================================================================
+
+int P_TranslateMap(int map)
+{
+ int i;
+
+ for (i = 1; i < 99; i++) // Make this a macro
+ {
+ if (MapInfo[i].warpTrans == map)
+ {
+ return i;
+ }
+ }
+ // Not found
+ return -1;
+}
+
+//==========================================================================
+//
+// P_GetMapSky1Texture
+//
+//==========================================================================
+
+int P_GetMapSky1Texture(int map)
+{
+ return MapInfo[QualifyMap(map)].sky1Texture;
+}
+
+//==========================================================================
+//
+// P_GetMapSky2Texture
+//
+//==========================================================================
+
+int P_GetMapSky2Texture(int map)
+{
+ return MapInfo[QualifyMap(map)].sky2Texture;
+}
+
+//==========================================================================
+//
+// P_GetMapName
+//
+//==========================================================================
+
+char *P_GetMapName(int map)
+{
+ return MapInfo[QualifyMap(map)].name;
+}
+
+//==========================================================================
+//
+// P_GetMapSky1ScrollDelta
+//
+//==========================================================================
+
+fixed_t P_GetMapSky1ScrollDelta(int map)
+{
+ return MapInfo[QualifyMap(map)].sky1ScrollDelta;
+}
+
+//==========================================================================
+//
+// P_GetMapSky2ScrollDelta
+//
+//==========================================================================
+
+fixed_t P_GetMapSky2ScrollDelta(int map)
+{
+ return MapInfo[QualifyMap(map)].sky2ScrollDelta;
+}
+
+//==========================================================================
+//
+// P_GetMapDoubleSky
+//
+//==========================================================================
+
+boolean P_GetMapDoubleSky(int map)
+{
+ return MapInfo[QualifyMap(map)].doubleSky;
+}
+
+//==========================================================================
+//
+// P_GetMapLightning
+//
+//==========================================================================
+
+boolean P_GetMapLightning(int map)
+{
+ return MapInfo[QualifyMap(map)].lightning;
+}
+
+//==========================================================================
+//
+// P_GetMapFadeTable
+//
+//==========================================================================
+
+boolean P_GetMapFadeTable(int map)
+{
+ return MapInfo[QualifyMap(map)].fadetable;
+}
+
+//==========================================================================
+//
+// P_GetMapSongLump
+//
+//==========================================================================
+
+char *P_GetMapSongLump(int map)
+{
+ if (!strcasecmp(MapInfo[QualifyMap(map)].songLump, DEFAULT_SONG_LUMP))
+ {
+ return NULL;
+ }
+ else
+ {
+ return MapInfo[QualifyMap(map)].songLump;
+ }
+}
+
+//==========================================================================
+//
+// P_PutMapSongLump
+//
+//==========================================================================
+
+void P_PutMapSongLump(int map, char *lumpName)
+{
+ if (map < 1 || map > MapCount)
+ {
+ return;
+ }
+ strcpy(MapInfo[map].songLump, lumpName);
+}
+
+//==========================================================================
+//
+// P_GetCDStartTrack
+//
+//==========================================================================
+
+int P_GetCDStartTrack(void)
+{
+ return cd_NonLevelTracks[MCMD_CD_STARTTRACK - MCMD_CD_STARTTRACK];
+}
+
+//==========================================================================
+//
+// P_GetCDEnd1Track
+//
+//==========================================================================
+
+int P_GetCDEnd1Track(void)
+{
+ return cd_NonLevelTracks[MCMD_CD_END1TRACK - MCMD_CD_STARTTRACK];
+}
+
+//==========================================================================
+//
+// P_GetCDEnd2Track
+//
+//==========================================================================
+
+int P_GetCDEnd2Track(void)
+{
+ return cd_NonLevelTracks[MCMD_CD_END2TRACK - MCMD_CD_STARTTRACK];
+}
+
+//==========================================================================
+//
+// P_GetCDEnd3Track
+//
+//==========================================================================
+
+int P_GetCDEnd3Track(void)
+{
+ return cd_NonLevelTracks[MCMD_CD_END3TRACK - MCMD_CD_STARTTRACK];
+}
+
+//==========================================================================
+//
+// P_GetCDIntermissionTrack
+//
+//==========================================================================
+
+int P_GetCDIntermissionTrack(void)
+{
+ return cd_NonLevelTracks[MCMD_CD_INTERTRACK - MCMD_CD_STARTTRACK];
+}
+
+//==========================================================================
+//
+// P_GetCDTitleTrack
+//
+//==========================================================================
+
+int P_GetCDTitleTrack(void)
+{
+ return cd_NonLevelTracks[MCMD_CD_TITLETRACK - MCMD_CD_STARTTRACK];
+}
+
+//==========================================================================
+//
+// QualifyMap
+//
+//==========================================================================
+
+static int QualifyMap(int map)
+{
+ return (map < 1 || map > MapCount) ? 0 : map;
+}
+
+//==========================================================================
+//
+// P_Init
+//
+//==========================================================================
+
+void P_Init(void)
+{
+ InitMapInfo();
+ P_InitSwitchList();
+ P_InitFTAnims(); // Init flat and texture animations
+ P_InitTerrainTypes();
+ P_InitLava();
+ R_InitSprites(sprnames);
+}
+
+
+// Special early initializer needed to start sound before R_Init()
+void InitMapMusicInfo(void)
+{
+ int i;
+
+ for (i = 0; i < 99; i++)
+ {
+ strcpy(MapInfo[i].songLump, DEFAULT_SONG_LUMP);
+ }
+ MapCount = 98;
+}
+
+/*
+void My_Debug(void)
+{
+ int i;
+
+ printf("My debug stuff ----------------------\n");
+ printf("gamemap=%d\n",gamemap);
+ for (i=0; i<10; i++)
+ {
+ printf("i=%d songlump=%s\n",i,MapInfo[i].songLump);
+ }
+}
+*/
diff --git a/src/hexen/p_sight.c b/src/hexen/p_sight.c
new file mode 100644
index 00000000..273ca3e0
--- /dev/null
+++ b/src/hexen/p_sight.c
@@ -0,0 +1,407 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#include "h2def.h"
+#include "p_local.h"
+
+/*
+==============================================================================
+
+ P_CheckSight
+
+This uses specialized forms of the maputils routines for optimized performance
+
+==============================================================================
+*/
+
+fixed_t sightzstart; // eye z of looker
+fixed_t topslope, bottomslope; // slopes to top and bottom of target
+
+int sightcounts[3];
+
+/*
+==============
+=
+= PTR_SightTraverse
+=
+==============
+*/
+
+boolean PTR_SightTraverse(intercept_t * in)
+{
+ line_t *li;
+ fixed_t slope;
+
+ li = in->d.line;
+
+//
+// crosses a two sided line
+//
+ P_LineOpening(li);
+
+ if (openbottom >= opentop) // quick test for totally closed doors
+ return false; // stop
+
+ if (li->frontsector->floorheight != li->backsector->floorheight)
+ {
+ slope = FixedDiv(openbottom - sightzstart, in->frac);
+ if (slope > bottomslope)
+ bottomslope = slope;
+ }
+
+ if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
+ {
+ slope = FixedDiv(opentop - sightzstart, in->frac);
+ if (slope < topslope)
+ topslope = slope;
+ }
+
+ if (topslope <= bottomslope)
+ return false; // stop
+
+ return true; // keep going
+}
+
+
+
+/*
+==================
+=
+= P_SightBlockLinesIterator
+=
+===================
+*/
+
+boolean P_SightBlockLinesIterator(int x, int y)
+{
+ int offset;
+ short *list;
+ line_t *ld;
+ int s1, s2;
+ divline_t dl;
+
+ polyblock_t *polyLink;
+ seg_t **segList;
+ int i;
+ extern polyblock_t **PolyBlockMap;
+
+ offset = y * bmapwidth + x;
+
+ polyLink = PolyBlockMap[offset];
+ while (polyLink)
+ {
+ if (polyLink->polyobj)
+ { // only check non-empty links
+ if (polyLink->polyobj->validcount != validcount)
+ {
+ segList = polyLink->polyobj->segs;
+ for (i = 0; i < polyLink->polyobj->numsegs; i++, segList++)
+ {
+ ld = (*segList)->linedef;
+ if (ld->validcount == validcount)
+ {
+ continue;
+ }
+ ld->validcount = validcount;
+ s1 = P_PointOnDivlineSide(ld->v1->x, ld->v1->y, &trace);
+ s2 = P_PointOnDivlineSide(ld->v2->x, ld->v2->y, &trace);
+ if (s1 == s2)
+ continue; // line isn't crossed
+ P_MakeDivline(ld, &dl);
+ s1 = P_PointOnDivlineSide(trace.x, trace.y, &dl);
+ s2 = P_PointOnDivlineSide(trace.x + trace.dx,
+ trace.y + trace.dy, &dl);
+ if (s1 == s2)
+ continue; // line isn't crossed
+
+ // try to early out the check
+ if (!ld->backsector)
+ return false; // stop checking
+
+ // store the line for later intersection testing
+ intercept_p->d.line = ld;
+ intercept_p++;
+ }
+ polyLink->polyobj->validcount = validcount;
+ }
+ }
+ polyLink = polyLink->next;
+ }
+
+ 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;
+
+ s1 = P_PointOnDivlineSide(ld->v1->x, ld->v1->y, &trace);
+ s2 = P_PointOnDivlineSide(ld->v2->x, ld->v2->y, &trace);
+ if (s1 == s2)
+ continue; // line isn't crossed
+ P_MakeDivline(ld, &dl);
+ s1 = P_PointOnDivlineSide(trace.x, trace.y, &dl);
+ s2 = P_PointOnDivlineSide(trace.x + trace.dx, trace.y + trace.dy,
+ &dl);
+ if (s1 == s2)
+ continue; // line isn't crossed
+
+ // try to early out the check
+ if (!ld->backsector)
+ return false; // stop checking
+
+ // store the line for later intersection testing
+ intercept_p->d.line = ld;
+ intercept_p++;
+
+ }
+
+ return true; // everything was checked
+}
+
+/*
+====================
+=
+= P_SightTraverseIntercepts
+=
+= Returns true if the traverser function returns true for all lines
+====================
+*/
+
+boolean P_SightTraverseIntercepts(void)
+{
+ int count;
+ fixed_t dist;
+ intercept_t *scan, *in;
+ divline_t dl;
+
+ count = intercept_p - intercepts;
+//
+// calculate intercept distance
+//
+ for (scan = intercepts; scan < intercept_p; scan++)
+ {
+ P_MakeDivline(scan->d.line, &dl);
+ scan->frac = P_InterceptVector(&trace, &dl);
+ }
+
+//
+// go through in order
+//
+ in = 0; // shut up compiler warning
+
+ while (count--)
+ {
+ dist = INT_MAX;
+ for (scan = intercepts; scan < intercept_p; scan++)
+ if (scan->frac < dist)
+ {
+ dist = scan->frac;
+ in = scan;
+ }
+
+ if (!PTR_SightTraverse(in))
+ return false; // don't bother going farther
+ in->frac = INT_MAX;
+ }
+
+ return true; // everything was traversed
+}
+
+
+
+/*
+==================
+=
+= P_SightPathTraverse
+=
+= 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
+==================
+*/
+
+boolean P_SightPathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)
+{
+ fixed_t xt1, yt1, xt2, yt2;
+ fixed_t xstep, ystep;
+ fixed_t partial;
+ fixed_t xintercept, yintercept;
+ int mapx, mapy, mapxstep, mapystep;
+ int count;
+
+ 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;
+
+// points should never be out of bounds, but check once instead of
+// each block
+ if (xt1 < 0 || yt1 < 0 || xt1 >= bmapwidth || yt1 >= bmapheight
+ || xt2 < 0 || yt2 < 0 || xt2 >= bmapwidth || yt2 >= bmapheight)
+ return false;
+
+ if (xt2 > xt1)
+ {
+ mapxstep = 1;
+ partial = FRACUNIT - ((x1 >> MAPBTOFRAC) & (FRACUNIT - 1));
+ ystep = FixedDiv(y2 - y1, abs(x2 - x1));
+ }
+ else if (xt2 < xt1)
+ {
+ mapxstep = -1;
+ partial = (x1 >> MAPBTOFRAC) & (FRACUNIT - 1);
+ ystep = FixedDiv(y2 - y1, 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, abs(y2 - y1));
+ }
+ else if (yt2 < yt1)
+ {
+ mapystep = -1;
+ partial = (y1 >> MAPBTOFRAC) & (FRACUNIT - 1);
+ xstep = FixedDiv(x2 - x1, 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 (!P_SightBlockLinesIterator(mapx, mapy))
+ {
+ sightcounts[1]++;
+ 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;
+ }
+
+ }
+
+
+//
+// couldn't early out, so go through the sorted list
+//
+ sightcounts[2]++;
+
+ return P_SightTraverseIntercepts();
+}
+
+
+
+/*
+=====================
+=
+= P_CheckSight
+=
+= Returns true if a straight line between t1 and t2 is unobstructed
+= look from eyes of t1 to any part of t2
+=
+=====================
+*/
+
+boolean P_CheckSight(mobj_t * t1, mobj_t * t2)
+{
+ int s1, s2;
+ int pnum, bytenum, bitnum;
+
+//
+// check for trivial rejection
+//
+ s1 = (t1->subsector->sector - sectors);
+ s2 = (t2->subsector->sector - sectors);
+ pnum = s1 * numsectors + s2;
+ bytenum = pnum >> 3;
+ bitnum = 1 << (pnum & 7);
+
+ if (rejectmatrix[bytenum] & bitnum)
+ {
+ sightcounts[0]++;
+ return false; // can't possibly be connected
+ }
+
+//
+// check precisely
+//
+ sightzstart = t1->z + t1->height - (t1->height >> 2);
+ topslope = (t2->z + t2->height) - sightzstart;
+ bottomslope = (t2->z) - sightzstart;
+
+ return P_SightPathTraverse(t1->x, t1->y, t2->x, t2->y);
+}
diff --git a/src/hexen/p_spec.c b/src/hexen/p_spec.c
new file mode 100644
index 00000000..03c98cbc
--- /dev/null
+++ b/src/hexen/p_spec.c
@@ -0,0 +1,1199 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2def.h"
+#include "i_system.h"
+#include "p_local.h"
+#include "s_sound.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define MAX_TAGGED_LINES 64
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static boolean CheckedLockedDoor(mobj_t * mo, byte lock);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+int *TerrainTypes;
+struct
+{
+ char *name;
+ int type;
+} TerrainTypeDefs[] =
+{
+ {
+ "X_005", FLOOR_WATER},
+ {
+ "X_001", FLOOR_LAVA},
+ {
+ "X_009", FLOOR_SLUDGE},
+ {
+ "F_033", FLOOR_ICE},
+ {
+ "END", -1}
+};
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static struct
+{
+ line_t *line;
+ int lineTag;
+} TaggedLines[MAX_TAGGED_LINES];
+static int TaggedLineCount;
+
+mobj_t LavaInflictor;
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// P_InitLava
+//
+//==========================================================================
+
+void P_InitLava(void)
+{
+ memset(&LavaInflictor, 0, sizeof(mobj_t));
+ LavaInflictor.type = MT_CIRCLEFLAME;
+ LavaInflictor.flags2 = MF2_FIREDAMAGE | MF2_NODMGTHRUST;
+}
+
+//==========================================================================
+//
+// P_InitTerrainTypes
+//
+//==========================================================================
+
+void P_InitTerrainTypes(void)
+{
+ int i;
+ int lump;
+ int size;
+
+ size = (numflats + 1) * sizeof(int);
+ TerrainTypes = Z_Malloc(size, PU_STATIC, 0);
+ memset(TerrainTypes, 0, size);
+ for (i = 0; TerrainTypeDefs[i].type != -1; i++)
+ {
+ lump = W_CheckNumForName(TerrainTypeDefs[i].name);
+ if (lump != -1)
+ {
+ TerrainTypes[lump - firstflat] = TerrainTypeDefs[i].type;
+ }
+ }
+}
+
+//==========================================================================
+//
+// getSide
+//
+// Will return a side_t* given the number of the current sector, the
+// line number, and the side (0/1) that you want.
+//
+//==========================================================================
+
+/*
+side_t *getSide(int currentSector, int line, int side)
+{
+ return &sides[ (sectors[currentSector].lines[line])->sidenum[side] ];
+}
+*/
+
+//==========================================================================
+//
+// getSector
+//
+// Will return a sector_t* given the number of the current sector, the
+// line number, and the side (0/1) that you want.
+//
+//==========================================================================
+
+/*
+sector_t *getSector(int currentSector, int line, int side)
+{
+ return sides[ (sectors[currentSector].lines[line])->sidenum[side] ].sector;
+}
+*/
+
+//==========================================================================
+//
+// twoSided
+//
+// Given the sector number and the line number, will tell you whether
+// the line is two-sided or not.
+//
+//==========================================================================
+
+/*
+int twoSided(int sector, int line)
+{
+ return (sectors[sector].lines[line])->flags & ML_TWOSIDED;
+}
+*/
+
+//==================================================================
+//
+// Return sector_t * of sector next to current. NULL if not two-sided line
+//
+//==================================================================
+sector_t *getNextSector(line_t * line, sector_t * sec)
+{
+ if (!(line->flags & ML_TWOSIDED))
+ return NULL;
+
+ if (line->frontsector == sec)
+ return line->backsector;
+
+ return line->frontsector;
+}
+
+//==================================================================
+//
+// FIND LOWEST FLOOR HEIGHT IN SURROUNDING SECTORS
+//
+//==================================================================
+fixed_t P_FindLowestFloorSurrounding(sector_t * sec)
+{
+ int i;
+ line_t *check;
+ sector_t *other;
+ fixed_t floor = sec->floorheight;
+
+ for (i = 0; i < sec->linecount; i++)
+ {
+ check = sec->lines[i];
+ other = getNextSector(check, sec);
+ if (!other)
+ continue;
+ if (other->floorheight < floor)
+ floor = other->floorheight;
+ }
+ return floor;
+}
+
+//==================================================================
+//
+// FIND HIGHEST FLOOR HEIGHT IN SURROUNDING SECTORS
+//
+//==================================================================
+fixed_t P_FindHighestFloorSurrounding(sector_t * sec)
+{
+ int i;
+ line_t *check;
+ sector_t *other;
+ fixed_t floor = -500 * FRACUNIT;
+
+ for (i = 0; i < sec->linecount; i++)
+ {
+ check = sec->lines[i];
+ other = getNextSector(check, sec);
+ if (!other)
+ continue;
+ if (other->floorheight > floor)
+ floor = other->floorheight;
+ }
+ return floor;
+}
+
+//==================================================================
+//
+// FIND NEXT HIGHEST FLOOR IN SURROUNDING SECTORS
+//
+//==================================================================
+fixed_t P_FindNextHighestFloor(sector_t * sec, int currentheight)
+{
+ int i;
+ int h;
+ int min;
+ line_t *check;
+ sector_t *other;
+ fixed_t height = currentheight;
+ fixed_t heightlist[20]; // 20 adjoining sectors max!
+
+ heightlist[0] = 0;
+
+ for (i = 0, h = 0; i < sec->linecount; i++)
+ {
+ check = sec->lines[i];
+ other = getNextSector(check, sec);
+ if (!other)
+ continue;
+ if (other->floorheight > height)
+ heightlist[h++] = other->floorheight;
+ }
+
+ //
+ // Find lowest height in list
+ //
+ min = heightlist[0];
+ for (i = 1; i < h; i++)
+ if (heightlist[i] < min)
+ min = heightlist[i];
+
+ return min;
+}
+
+//==================================================================
+//
+// FIND LOWEST CEILING IN THE SURROUNDING SECTORS
+//
+//==================================================================
+fixed_t P_FindLowestCeilingSurrounding(sector_t * sec)
+{
+ int i;
+ line_t *check;
+ sector_t *other;
+ fixed_t height = INT_MAX;
+
+ for (i = 0; i < sec->linecount; i++)
+ {
+ check = sec->lines[i];
+ other = getNextSector(check, sec);
+ if (!other)
+ continue;
+ if (other->ceilingheight < height)
+ height = other->ceilingheight;
+ }
+ return height;
+}
+
+//==================================================================
+//
+// FIND HIGHEST CEILING IN THE SURROUNDING SECTORS
+//
+//==================================================================
+fixed_t P_FindHighestCeilingSurrounding(sector_t * sec)
+{
+ int i;
+ line_t *check;
+ sector_t *other;
+ fixed_t height = 0;
+
+ for (i = 0; i < sec->linecount; i++)
+ {
+ check = sec->lines[i];
+ other = getNextSector(check, sec);
+ if (!other)
+ continue;
+ if (other->ceilingheight > height)
+ height = other->ceilingheight;
+ }
+ return height;
+}
+
+//==================================================================
+//
+// RETURN NEXT SECTOR # THAT LINE TAG REFERS TO
+//
+//==================================================================
+
+/*
+int P_FindSectorFromLineTag(line_t *line,int start)
+{
+ int i;
+
+ for (i=start+1;i<numsectors;i++)
+ if (sectors[i].tag == line->arg1)
+ return i;
+ return -1;
+}
+*/
+
+//=========================================================================
+//
+// P_FindSectorFromTag
+//
+//=========================================================================
+
+int P_FindSectorFromTag(int tag, int start)
+{
+ int i;
+
+ for (i = start + 1; i < numsectors; i++)
+ {
+ if (sectors[i].tag == tag)
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+//==================================================================
+//
+// Find minimum light from an adjacent sector
+//
+//==================================================================
+
+/*
+int P_FindMinSurroundingLight(sector_t *sector,int max)
+{
+ int i;
+ int min;
+ line_t *line;
+ sector_t *check;
+
+ min = max;
+ for (i=0 ; i < sector->linecount ; i++)
+ {
+ line = sector->lines[i];
+ check = getNextSector(line,sector);
+ if (!check)
+ continue;
+ if (check->lightlevel < min)
+ min = check->lightlevel;
+ }
+ return min;
+}
+*/
+
+//=========================================================================
+//
+// EV_SectorSoundChange
+//
+//=========================================================================
+
+boolean EV_SectorSoundChange(byte * args)
+{
+ int secNum;
+ boolean rtn;
+
+ if (!args[0])
+ {
+ return false;
+ }
+ secNum = -1;
+ rtn = false;
+ while ((secNum = P_FindSectorFromTag(args[0], secNum)) >= 0)
+ {
+ sectors[secNum].seqType = args[1];
+ rtn = true;
+ }
+ return rtn;
+}
+
+//============================================================================
+//
+// CheckedLockedDoor
+//
+//============================================================================
+
+static boolean CheckedLockedDoor(mobj_t * mo, byte lock)
+{
+ extern char *TextKeyMessages[11];
+ char LockedBuffer[80];
+
+ if (!mo->player)
+ {
+ return false;
+ }
+ if (!lock)
+ {
+ return true;
+ }
+ if (!(mo->player->keys & (1 << (lock - 1))))
+ {
+ sprintf(LockedBuffer, "YOU NEED THE %s\n", TextKeyMessages[lock - 1]);
+ P_SetMessage(mo->player, LockedBuffer, true);
+ S_StartSound(mo, SFX_DOOR_LOCKED);
+ return false;
+ }
+ return true;
+}
+
+
+//==========================================================================
+//
+// EV_LineSearchForPuzzleItem
+//
+//==========================================================================
+
+boolean EV_LineSearchForPuzzleItem(line_t * line, byte * args, mobj_t * mo)
+{
+ player_t *player;
+ int i;
+ artitype_t type, arti;
+
+ if (!mo)
+ return false;
+ player = mo->player;
+ if (!player)
+ return false;
+
+ // Search player's inventory for puzzle items
+ for (i = 0; i < player->artifactCount; i++)
+ {
+ arti = player->inventory[i].type;
+ type = arti - arti_firstpuzzitem;
+ if (type < 0)
+ continue;
+ if (type == line->arg1)
+ {
+ // A puzzle item was found for the line
+ if (P_UseArtifact(player, arti))
+ {
+ // A puzzle item was found for the line
+ P_PlayerRemoveArtifact(player, i);
+ if (player == &players[consoleplayer])
+ {
+ if (arti < arti_firstpuzzitem)
+ {
+ S_StartSound(NULL, SFX_ARTIFACT_USE);
+ }
+ else
+ {
+ S_StartSound(NULL, SFX_PUZZLE_SUCCESS);
+ }
+ ArtifactFlash = 4;
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+
+/*
+==============================================================================
+
+ EVENTS
+
+Events are operations triggered by using, crossing, or shooting special lines, or by timed thinkers
+
+==============================================================================
+*/
+//============================================================================
+//
+// P_ExecuteLineSpecial
+//
+//============================================================================
+
+boolean P_ExecuteLineSpecial(int special, byte * args, line_t * line,
+ int side, mobj_t * mo)
+{
+ boolean buttonSuccess;
+
+ buttonSuccess = false;
+ switch (special)
+ {
+ case 1: // Poly Start Line
+ break;
+ case 2: // Poly Rotate Left
+ buttonSuccess = EV_RotatePoly(line, args, 1, false);
+ break;
+ case 3: // Poly Rotate Right
+ buttonSuccess = EV_RotatePoly(line, args, -1, false);
+ break;
+ case 4: // Poly Move
+ buttonSuccess = EV_MovePoly(line, args, false, false);
+ break;
+ case 5: // Poly Explicit Line: Only used in initialization
+ break;
+ case 6: // Poly Move Times 8
+ buttonSuccess = EV_MovePoly(line, args, true, false);
+ break;
+ case 7: // Poly Door Swing
+ buttonSuccess = EV_OpenPolyDoor(line, args, PODOOR_SWING);
+ break;
+ case 8: // Poly Door Slide
+ buttonSuccess = EV_OpenPolyDoor(line, args, PODOOR_SLIDE);
+ break;
+ case 10: // Door Close
+ buttonSuccess = EV_DoDoor(line, args, DREV_CLOSE);
+ break;
+ case 11: // Door Open
+ if (!args[0])
+ {
+ buttonSuccess = EV_VerticalDoor(line, mo);
+ }
+ else
+ {
+ buttonSuccess = EV_DoDoor(line, args, DREV_OPEN);
+ }
+ break;
+ case 12: // Door Raise
+ if (!args[0])
+ {
+ buttonSuccess = EV_VerticalDoor(line, mo);
+ }
+ else
+ {
+ buttonSuccess = EV_DoDoor(line, args, DREV_NORMAL);
+ }
+ break;
+ case 13: // Door Locked_Raise
+ if (CheckedLockedDoor(mo, args[3]))
+ {
+ if (!args[0])
+ {
+ buttonSuccess = EV_VerticalDoor(line, mo);
+ }
+ else
+ {
+ buttonSuccess = EV_DoDoor(line, args, DREV_NORMAL);
+ }
+ }
+ break;
+ case 20: // Floor Lower by Value
+ buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERFLOORBYVALUE);
+ break;
+ case 21: // Floor Lower to Lowest
+ buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERFLOORTOLOWEST);
+ break;
+ case 22: // Floor Lower to Nearest
+ buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERFLOOR);
+ break;
+ case 23: // Floor Raise by Value
+ buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOORBYVALUE);
+ break;
+ case 24: // Floor Raise to Highest
+ buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOOR);
+ break;
+ case 25: // Floor Raise to Nearest
+ buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOORTONEAREST);
+ break;
+ case 26: // Stairs Build Down Normal
+ buttonSuccess = EV_BuildStairs(line, args, -1, STAIRS_NORMAL);
+ break;
+ case 27: // Build Stairs Up Normal
+ buttonSuccess = EV_BuildStairs(line, args, 1, STAIRS_NORMAL);
+ break;
+ case 28: // Floor Raise and Crush
+ buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOORCRUSH);
+ break;
+ case 29: // Build Pillar (no crushing)
+ buttonSuccess = EV_BuildPillar(line, args, false);
+ break;
+ case 30: // Open Pillar
+ buttonSuccess = EV_OpenPillar(line, args);
+ break;
+ case 31: // Stairs Build Down Sync
+ buttonSuccess = EV_BuildStairs(line, args, -1, STAIRS_SYNC);
+ break;
+ case 32: // Build Stairs Up Sync
+ buttonSuccess = EV_BuildStairs(line, args, 1, STAIRS_SYNC);
+ break;
+ case 35: // Raise Floor by Value Times 8
+ buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEBYVALUETIMES8);
+ break;
+ case 36: // Lower Floor by Value Times 8
+ buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERBYVALUETIMES8);
+ break;
+ case 40: // Ceiling Lower by Value
+ buttonSuccess = EV_DoCeiling(line, args, CLEV_LOWERBYVALUE);
+ break;
+ case 41: // Ceiling Raise by Value
+ buttonSuccess = EV_DoCeiling(line, args, CLEV_RAISEBYVALUE);
+ break;
+ case 42: // Ceiling Crush and Raise
+ buttonSuccess = EV_DoCeiling(line, args, CLEV_CRUSHANDRAISE);
+ break;
+ case 43: // Ceiling Lower and Crush
+ buttonSuccess = EV_DoCeiling(line, args, CLEV_LOWERANDCRUSH);
+ break;
+ case 44: // Ceiling Crush Stop
+ buttonSuccess = EV_CeilingCrushStop(line, args);
+ break;
+ case 45: // Ceiling Crush Raise and Stay
+ buttonSuccess = EV_DoCeiling(line, args, CLEV_CRUSHRAISEANDSTAY);
+ break;
+ case 46: // Floor Crush Stop
+ buttonSuccess = EV_FloorCrushStop(line, args);
+ break;
+ case 60: // Plat Perpetual Raise
+ buttonSuccess = EV_DoPlat(line, args, PLAT_PERPETUALRAISE, 0);
+ break;
+ case 61: // Plat Stop
+ EV_StopPlat(line, args);
+ break;
+ case 62: // Plat Down-Wait-Up-Stay
+ buttonSuccess = EV_DoPlat(line, args, PLAT_DOWNWAITUPSTAY, 0);
+ break;
+ case 63: // Plat Down-by-Value*8-Wait-Up-Stay
+ buttonSuccess = EV_DoPlat(line, args, PLAT_DOWNBYVALUEWAITUPSTAY,
+ 0);
+ break;
+ case 64: // Plat Up-Wait-Down-Stay
+ buttonSuccess = EV_DoPlat(line, args, PLAT_UPWAITDOWNSTAY, 0);
+ break;
+ case 65: // Plat Up-by-Value*8-Wait-Down-Stay
+ buttonSuccess = EV_DoPlat(line, args, PLAT_UPBYVALUEWAITDOWNSTAY,
+ 0);
+ break;
+ case 66: // Floor Lower Instant * 8
+ buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERTIMES8INSTANT);
+ break;
+ case 67: // Floor Raise Instant * 8
+ buttonSuccess = EV_DoFloor(line, args, FLEV_RAISETIMES8INSTANT);
+ break;
+ case 68: // Floor Move to Value * 8
+ buttonSuccess = EV_DoFloor(line, args, FLEV_MOVETOVALUETIMES8);
+ break;
+ case 69: // Ceiling Move to Value * 8
+ buttonSuccess = EV_DoCeiling(line, args, CLEV_MOVETOVALUETIMES8);
+ break;
+ case 70: // Teleport
+ if (side == 0)
+ { // Only teleport when crossing the front side of a line
+ buttonSuccess = EV_Teleport(args[0], mo, true);
+ }
+ break;
+ case 71: // Teleport, no fog
+ if (side == 0)
+ { // Only teleport when crossing the front side of a line
+ buttonSuccess = EV_Teleport(args[0], mo, false);
+ }
+ break;
+ case 72: // Thrust Mobj
+ if (!side) // Only thrust on side 0
+ {
+ P_ThrustMobj(mo, args[0] * (ANG90 / 64),
+ args[1] << FRACBITS);
+ buttonSuccess = 1;
+ }
+ break;
+ case 73: // Damage Mobj
+ if (args[0])
+ {
+ P_DamageMobj(mo, NULL, NULL, args[0]);
+ }
+ else
+ { // If arg1 is zero, then guarantee a kill
+ P_DamageMobj(mo, NULL, NULL, 10000);
+ }
+ buttonSuccess = 1;
+ break;
+ case 74: // Teleport_NewMap
+ if (side == 0)
+ { // Only teleport when crossing the front side of a line
+ if (!(mo && mo->player && mo->player->playerstate == PST_DEAD)) // Players must be alive to teleport
+ {
+ G_Completed(args[0], args[1]);
+ buttonSuccess = true;
+ }
+ }
+ break;
+ case 75: // Teleport_EndGame
+ if (side == 0)
+ { // Only teleport when crossing the front side of a line
+ if (!(mo && mo->player && mo->player->playerstate == PST_DEAD)) // Players must be alive to teleport
+ {
+ buttonSuccess = true;
+ if (deathmatch)
+ { // Winning in deathmatch just goes back to map 1
+ G_Completed(1, 0);
+ }
+ else
+ { // Passing -1, -1 to G_Completed() starts the Finale
+ G_Completed(-1, -1);
+ }
+ }
+ }
+ break;
+ case 80: // ACS_Execute
+ buttonSuccess =
+ P_StartACS(args[0], args[1], &args[2], mo, line, side);
+ break;
+ case 81: // ACS_Suspend
+ buttonSuccess = P_SuspendACS(args[0], args[1]);
+ break;
+ case 82: // ACS_Terminate
+ buttonSuccess = P_TerminateACS(args[0], args[1]);
+ break;
+ case 83: // ACS_LockedExecute
+ buttonSuccess = P_StartLockedACS(line, args, mo, side);
+ break;
+ case 90: // Poly Rotate Left Override
+ buttonSuccess = EV_RotatePoly(line, args, 1, true);
+ break;
+ case 91: // Poly Rotate Right Override
+ buttonSuccess = EV_RotatePoly(line, args, -1, true);
+ break;
+ case 92: // Poly Move Override
+ buttonSuccess = EV_MovePoly(line, args, false, true);
+ break;
+ case 93: // Poly Move Times 8 Override
+ buttonSuccess = EV_MovePoly(line, args, true, true);
+ break;
+ case 94: // Build Pillar Crush
+ buttonSuccess = EV_BuildPillar(line, args, true);
+ break;
+ case 95: // Lower Floor and Ceiling
+ buttonSuccess = EV_DoFloorAndCeiling(line, args, false);
+ break;
+ case 96: // Raise Floor and Ceiling
+ buttonSuccess = EV_DoFloorAndCeiling(line, args, true);
+ break;
+ case 109: // Force Lightning
+ buttonSuccess = true;
+ P_ForceLightning();
+ break;
+ case 110: // Light Raise by Value
+ buttonSuccess = EV_SpawnLight(line, args, LITE_RAISEBYVALUE);
+ break;
+ case 111: // Light Lower by Value
+ buttonSuccess = EV_SpawnLight(line, args, LITE_LOWERBYVALUE);
+ break;
+ case 112: // Light Change to Value
+ buttonSuccess = EV_SpawnLight(line, args, LITE_CHANGETOVALUE);
+ break;
+ case 113: // Light Fade
+ buttonSuccess = EV_SpawnLight(line, args, LITE_FADE);
+ break;
+ case 114: // Light Glow
+ buttonSuccess = EV_SpawnLight(line, args, LITE_GLOW);
+ break;
+ case 115: // Light Flicker
+ buttonSuccess = EV_SpawnLight(line, args, LITE_FLICKER);
+ break;
+ case 116: // Light Strobe
+ buttonSuccess = EV_SpawnLight(line, args, LITE_STROBE);
+ break;
+ case 120: // Quake Tremor
+ buttonSuccess = A_LocalQuake(args, mo);
+ break;
+ case 129: // UsePuzzleItem
+ buttonSuccess = EV_LineSearchForPuzzleItem(line, args, mo);
+ break;
+ case 130: // Thing_Activate
+ buttonSuccess = EV_ThingActivate(args[0]);
+ break;
+ case 131: // Thing_Deactivate
+ buttonSuccess = EV_ThingDeactivate(args[0]);
+ break;
+ case 132: // Thing_Remove
+ buttonSuccess = EV_ThingRemove(args[0]);
+ break;
+ case 133: // Thing_Destroy
+ buttonSuccess = EV_ThingDestroy(args[0]);
+ break;
+ case 134: // Thing_Projectile
+ buttonSuccess = EV_ThingProjectile(args, 0);
+ break;
+ case 135: // Thing_Spawn
+ buttonSuccess = EV_ThingSpawn(args, 1);
+ break;
+ case 136: // Thing_ProjectileGravity
+ buttonSuccess = EV_ThingProjectile(args, 1);
+ break;
+ case 137: // Thing_SpawnNoFog
+ buttonSuccess = EV_ThingSpawn(args, 0);
+ break;
+ case 138: // Floor_Waggle
+ buttonSuccess = EV_StartFloorWaggle(args[0], args[1],
+ args[2], args[3], args[4]);
+ break;
+ case 140: // Sector_SoundChange
+ buttonSuccess = EV_SectorSoundChange(args);
+ break;
+
+ // Line specials only processed during level initialization
+ // 100: Scroll_Texture_Left
+ // 101: Scroll_Texture_Right
+ // 102: Scroll_Texture_Up
+ // 103: Scroll_Texture_Down
+ // 121: Line_SetIdentification
+
+ // Inert Line specials
+ default:
+ break;
+ }
+ return buttonSuccess;
+}
+
+//============================================================================
+//
+// P_ActivateLine
+//
+//============================================================================
+
+boolean P_ActivateLine(line_t * line, mobj_t * mo, int side,
+ int activationType)
+{
+ int lineActivation;
+ boolean repeat;
+ boolean buttonSuccess;
+
+ lineActivation = GET_SPAC(line->flags);
+ if (lineActivation != activationType)
+ {
+ return false;
+ }
+ if (!mo->player && !(mo->flags & MF_MISSILE))
+ {
+ if (lineActivation != SPAC_MCROSS)
+ { // currently, monsters can only activate the MCROSS activation type
+ return false;
+ }
+ if (line->flags & ML_SECRET)
+ return false; // never open secret doors
+ }
+ repeat = line->flags & ML_REPEAT_SPECIAL;
+ buttonSuccess = false;
+
+ buttonSuccess = P_ExecuteLineSpecial(line->special, &line->arg1, line,
+ side, mo);
+ if (!repeat && buttonSuccess)
+ { // clear the special on non-retriggerable lines
+ line->special = 0;
+ }
+ if ((lineActivation == SPAC_USE || lineActivation == SPAC_IMPACT)
+ && buttonSuccess)
+ {
+ P_ChangeSwitchTexture(line, repeat);
+ }
+ return true;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_PlayerInSpecialSector
+//
+// Called every tic frame that the player origin is in a special sector.
+//
+//----------------------------------------------------------------------------
+
+void P_PlayerInSpecialSector(player_t * player)
+{
+ sector_t *sector;
+ static int pushTab[3] = {
+ 2048 * 5,
+ 2048 * 10,
+ 2048 * 25
+ };
+
+ sector = player->mo->subsector->sector;
+ if (player->mo->z != sector->floorheight)
+ { // Player is not touching the floor
+ return;
+ }
+ switch (sector->special)
+ {
+ case 9: // SecretArea
+ player->secretcount++;
+ sector->special = 0;
+ break;
+
+ case 201:
+ case 202:
+ case 203: // Scroll_North_xxx
+ P_Thrust(player, ANG90, pushTab[sector->special - 201]);
+ break;
+ case 204:
+ case 205:
+ case 206: // Scroll_East_xxx
+ P_Thrust(player, 0, pushTab[sector->special - 204]);
+ break;
+ case 207:
+ case 208:
+ case 209: // Scroll_South_xxx
+ P_Thrust(player, ANG270, pushTab[sector->special - 207]);
+ break;
+ case 210:
+ case 211:
+ case 212: // Scroll_West_xxx
+ P_Thrust(player, ANG180, pushTab[sector->special - 210]);
+ break;
+ case 213:
+ case 214:
+ case 215: // Scroll_NorthWest_xxx
+ P_Thrust(player, ANG90 + ANG45, pushTab[sector->special - 213]);
+ break;
+ case 216:
+ case 217:
+ case 218: // Scroll_NorthEast_xxx
+ P_Thrust(player, ANG45, pushTab[sector->special - 216]);
+ break;
+ case 219:
+ case 220:
+ case 221: // Scroll_SouthEast_xxx
+ P_Thrust(player, ANG270 + ANG45, pushTab[sector->special - 219]);
+ break;
+ case 222:
+ case 223:
+ case 224: // Scroll_SouthWest_xxx
+ P_Thrust(player, ANG180 + ANG45, pushTab[sector->special - 222]);
+ break;
+
+ case 40:
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 45:
+ case 46:
+ case 47:
+ case 48:
+ case 49:
+ case 50:
+ case 51:
+ // Wind specials are handled in (P_mobj):P_XYMovement
+ break;
+
+ case 26: // Stairs_Special1
+ case 27: // Stairs_Special2
+ // Used in (P_floor):ProcessStairSector
+ break;
+
+ case 198: // Lightning Special
+ case 199: // Lightning Flash special
+ case 200: // Sky2
+ // Used in (R_plane):R_Drawplanes
+ break;
+ default:
+ I_Error("P_PlayerInSpecialSector: "
+ "unknown special %i", sector->special);
+ }
+}
+
+//============================================================================
+//
+// P_PlayerOnSpecialFlat
+//
+//============================================================================
+
+void P_PlayerOnSpecialFlat(player_t * player, int floorType)
+{
+ if (player->mo->z != player->mo->floorz)
+ { // Player is not touching the floor
+ return;
+ }
+ switch (floorType)
+ {
+ case FLOOR_LAVA:
+ if (!(leveltime & 31))
+ {
+ P_DamageMobj(player->mo, &LavaInflictor, NULL, 10);
+ S_StartSound(player->mo, SFX_LAVA_SIZZLE);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_UpdateSpecials
+//
+//----------------------------------------------------------------------------
+
+void P_UpdateSpecials(void)
+{
+ int i;
+
+ // Handle buttons
+ for (i = 0; i < MAXBUTTONS; i++)
+ {
+ if (buttonlist[i].btimer)
+ {
+ buttonlist[i].btimer--;
+ if (!buttonlist[i].btimer)
+ {
+ switch (buttonlist[i].where)
+ {
+ case SWTCH_TOP:
+ sides[buttonlist[i].line->sidenum[0]].toptexture =
+ buttonlist[i].btexture;
+ break;
+ case SWTCH_MIDDLE:
+ sides[buttonlist[i].line->sidenum[0]].midtexture =
+ buttonlist[i].btexture;
+ break;
+ case SWTCH_BOTTOM:
+ sides[buttonlist[i].line->sidenum[0]].bottomtexture =
+ buttonlist[i].btexture;
+ break;
+ }
+ //S_StartSound((mobj_t *)&buttonlist[i].soundorg, sfx_switch);
+ memset(&buttonlist[i], 0, sizeof(button_t));
+ }
+ }
+ }
+}
+
+/*
+==============================================================================
+
+ SPECIAL SPAWNING
+
+==============================================================================
+*/
+/*
+================================================================================
+= P_SpawnSpecials
+=
+= After the map has been loaded, scan for specials that
+= spawn thinkers
+=
+===============================================================================
+*/
+
+short numlinespecials;
+line_t *linespeciallist[MAXLINEANIMS];
+
+void P_SpawnSpecials(void)
+{
+ sector_t *sector;
+ int i;
+
+ //
+ // Init special SECTORs
+ //
+ sector = sectors;
+ for (i = 0; i < numsectors; i++, sector++)
+ {
+ if (!sector->special)
+ continue;
+ switch (sector->special)
+ {
+ case 1: // Phased light
+ // Hardcoded base, use sector->lightlevel as the index
+ P_SpawnPhasedLight(sector, 80, -1);
+ break;
+ case 2: // Phased light sequence start
+ P_SpawnLightSequence(sector, 1);
+ break;
+ // Specials 3 & 4 are used by the phased light sequences
+
+ /*
+ case 1: // FLICKERING LIGHTS
+ P_SpawnLightFlash (sector);
+ break;
+ case 2: // STROBE FAST
+ P_SpawnStrobeFlash(sector,FASTDARK,0);
+ break;
+ case 3: // STROBE SLOW
+ P_SpawnStrobeFlash(sector,SLOWDARK,0);
+ break;
+ case 4: // STROBE FAST/DEATH SLIME
+ P_SpawnStrobeFlash(sector,FASTDARK,0);
+ sector->special = 4;
+ break;
+ case 8: // GLOWING LIGHT
+ P_SpawnGlowingLight(sector);
+ break;
+ case 9: // SECRET SECTOR
+ totalsecret++;
+ break;
+ case 10: // DOOR CLOSE IN 30 SECONDS
+ P_SpawnDoorCloseIn30 (sector);
+ break;
+ case 12: // SYNC STROBE SLOW
+ P_SpawnStrobeFlash (sector, SLOWDARK, 1);
+ break;
+ case 13: // SYNC STROBE FAST
+ P_SpawnStrobeFlash (sector, FASTDARK, 1);
+ break;
+ case 14: // DOOR RAISE IN 5 MINUTES
+ P_SpawnDoorRaiseIn5Mins (sector, i);
+ break;
+ */
+ }
+ }
+
+
+ //
+ // Init line EFFECTs
+ //
+ numlinespecials = 0;
+ TaggedLineCount = 0;
+ for (i = 0; i < numlines; i++)
+ {
+ switch (lines[i].special)
+ {
+ case 100: // Scroll_Texture_Left
+ case 101: // Scroll_Texture_Right
+ case 102: // Scroll_Texture_Up
+ case 103: // Scroll_Texture_Down
+ linespeciallist[numlinespecials] = &lines[i];
+ numlinespecials++;
+ break;
+ case 121: // Line_SetIdentification
+ if (lines[i].arg1)
+ {
+ if (TaggedLineCount == MAX_TAGGED_LINES)
+ {
+ I_Error("P_SpawnSpecials: MAX_TAGGED_LINES "
+ "(%d) exceeded.", MAX_TAGGED_LINES);
+ }
+ TaggedLines[TaggedLineCount].line = &lines[i];
+ TaggedLines[TaggedLineCount++].lineTag = lines[i].arg1;
+ }
+ lines[i].special = 0;
+ break;
+ }
+ }
+
+ //
+ // Init other misc stuff
+ //
+ for (i = 0; i < MAXCEILINGS; i++)
+ activeceilings[i] = NULL;
+ for (i = 0; i < MAXPLATS; i++)
+ activeplats[i] = NULL;
+ for (i = 0; i < MAXBUTTONS; i++)
+ memset(&buttonlist[i], 0, sizeof(button_t));
+
+ // Initialize flat and texture animations
+ P_InitFTAnims();
+}
+
+//==========================================================================
+//
+// P_FindLine
+//
+//==========================================================================
+
+line_t *P_FindLine(int lineTag, int *searchPosition)
+{
+ int i;
+
+ for (i = *searchPosition + 1; i < TaggedLineCount; i++)
+ {
+ if (TaggedLines[i].lineTag == lineTag)
+ {
+ *searchPosition = i;
+ return TaggedLines[i].line;
+ }
+ }
+ *searchPosition = -1;
+ return NULL;
+}
diff --git a/src/hexen/p_spec.h b/src/hexen/p_spec.h
new file mode 100644
index 00000000..f2c4691c
--- /dev/null
+++ b/src/hexen/p_spec.h
@@ -0,0 +1,578 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+extern int *TerrainTypes;
+
+//
+// scrolling line specials
+//
+
+#define MAXLINEANIMS 64
+extern short numlinespecials;
+extern line_t *linespeciallist[MAXLINEANIMS];
+
+// Define values for map objects
+#define MO_TELEPORTMAN 14
+
+// at game start
+void P_InitTerrainTypes(void);
+void P_InitLava(void);
+
+// at map load
+void P_SpawnSpecials(void);
+
+// every tic
+void P_UpdateSpecials(void);
+
+// when needed
+boolean P_ExecuteLineSpecial(int special, byte * args, line_t * line,
+ int side, mobj_t * mo);
+boolean P_ActivateLine(line_t * ld, mobj_t * mo, int side,
+ int activationType);
+//boolean P_UseSpecialLine ( mobj_t *thing, line_t *line);
+//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);
+void P_PlayerOnSpecialFlat(player_t * player, int floorType);
+
+//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_FindSectorFromTag(int tag, int start);
+//int P_FindMinSurroundingLight(sector_t *sector,int max);
+sector_t *getNextSector(line_t * line, sector_t * sec);
+line_t *P_FindLine(int lineTag, int *searchPosition);
+
+//
+// SPECIAL
+//
+//int EV_DoDonut(line_t *line);
+
+//-------------------------------
+// P_anim.c
+//-------------------------------
+
+void P_AnimateSurfaces(void);
+void P_InitFTAnims(void);
+void P_InitLightning(void);
+void P_ForceLightning(void);
+
+/*
+===============================================================================
+
+ P_LIGHTS
+
+===============================================================================
+*/
+
+typedef enum
+{
+ LITE_RAISEBYVALUE,
+ LITE_LOWERBYVALUE,
+ LITE_CHANGETOVALUE,
+ LITE_FADE,
+ LITE_GLOW,
+ LITE_FLICKER,
+ LITE_STROBE
+} lighttype_t;
+
+typedef struct
+{
+ thinker_t thinker;
+ sector_t *sector;
+ lighttype_t type;
+ int value1;
+ int value2;
+ int tics1;
+ int tics2;
+ int count;
+} light_t;
+
+typedef struct
+{
+ thinker_t thinker;
+ sector_t *sector;
+ int index;
+ int base;
+} phase_t;
+
+#define LIGHT_SEQUENCE_START 2
+#define LIGHT_SEQUENCE 3
+#define LIGHT_SEQUENCE_ALT 4
+
+void T_Phase(phase_t * phase);
+void T_Light(light_t * light);
+void P_SpawnPhasedLight(sector_t * sector, int base, int index);
+void P_SpawnLightSequence(sector_t * sector, int indexStep);
+boolean EV_SpawnLight(line_t * line, byte * arg, lighttype_t type);
+
+#if 0
+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;
+
+typedef struct
+{
+ thinker_t thinker;
+ sector_t *sector;
+ int index;
+ int base;
+} phase_t;
+
+#define GLOWSPEED 8
+#define STROBEBRIGHT 5
+#define FASTDARK 15
+#define SLOWDARK 35
+
+#define LIGHT_SEQUENCE_START 2
+#define LIGHT_SEQUENCE 3
+#define LIGHT_SEQUENCE_ALT 4
+
+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);
+void T_Phase(phase_t * phase);
+void P_SpawnPhasedLight(sector_t * sector, int base, int index);
+void P_SpawnLightSequence(sector_t * sector, int indexStep);
+#endif
+
+/*
+===============================================================================
+
+ P_SWITCH
+
+===============================================================================
+*/
+typedef struct
+{
+ char name1[9];
+ char name2[9];
+ int soundID;
+} switchlist_t;
+
+typedef enum
+{
+ SWTCH_TOP,
+ SWTCH_MIDDLE,
+ SWTCH_BOTTOM
+} bwhere_e;
+
+typedef struct
+{
+ line_t *line;
+ bwhere_e where;
+ int btexture;
+ int btimer;
+ mobj_t *soundorg;
+} button_t;
+
+#define MAXSWITCHES 50 // max # of wall switches in a level
+#define MAXBUTTONS 16 // 4 players, 4 buttons each at once, max.
+#define BUTTONTIME 35 // 1 second
+
+extern button_t buttonlist[MAXBUTTONS];
+
+void P_ChangeSwitchTexture(line_t * line, int useAgain);
+void P_InitSwitchList(void);
+
+/*
+===============================================================================
+
+ P_PLATS
+
+===============================================================================
+*/
+
+typedef enum
+{
+ PLAT_UP,
+ PLAT_DOWN,
+ PLAT_WAITING,
+// PLAT_IN_STASIS
+} plat_e;
+
+typedef enum
+{
+ PLAT_PERPETUALRAISE,
+ PLAT_DOWNWAITUPSTAY,
+ PLAT_DOWNBYVALUEWAITUPSTAY,
+ PLAT_UPWAITDOWNSTAY,
+ PLAT_UPBYVALUEWAITDOWNSTAY,
+ //PLAT_RAISEANDCHANGE,
+ //PLAT_RAISETONEARESTANDCHANGE
+} 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;
+ int 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, byte * args, plattype_e type, int amount);
+void P_AddActivePlat(plat_t * plat);
+void P_RemoveActivePlat(plat_t * plat);
+void EV_StopPlat(line_t * line, byte * args);
+
+/*
+===============================================================================
+
+ P_DOORS
+
+===============================================================================
+*/
+typedef enum
+{
+ DREV_NORMAL,
+ DREV_CLOSE30THENOPEN,
+ DREV_CLOSE,
+ DREV_OPEN,
+ DREV_RAISEIN5MINS,
+} vldoor_e;
+
+typedef struct
+{
+ thinker_t thinker;
+ sector_t *sector;
+ vldoor_e type;
+ fixed_t topheight;
+ fixed_t speed;
+ int direction; // 1 = up, 0 = waiting at top, -1 = down
+ int topwait; // tics to wait at the top (keep in case a door going down is reset)
+ int topcountdown; // when it reaches 0, start going down
+} vldoor_t;
+
+#define VDOORSPEED FRACUNIT*2
+#define VDOORWAIT 150
+
+boolean EV_VerticalDoor(line_t * line, mobj_t * thing);
+int EV_DoDoor(line_t * line, byte * args, vldoor_e type);
+void T_VerticalDoor(vldoor_t * door);
+//void P_SpawnDoorCloseIn30(sector_t *sec);
+//void P_SpawnDoorRaiseIn5Mins(sector_t *sec, int secnum);
+
+/*
+===============================================================================
+
+ P_CEILNG
+
+===============================================================================
+*/
+typedef enum
+{
+ CLEV_LOWERTOFLOOR,
+ CLEV_RAISETOHIGHEST,
+ CLEV_LOWERANDCRUSH,
+ CLEV_CRUSHANDRAISE,
+ CLEV_LOWERBYVALUE,
+ CLEV_RAISEBYVALUE,
+ CLEV_CRUSHRAISEANDSTAY,
+ CLEV_MOVETOVALUETIMES8
+} ceiling_e;
+
+typedef struct
+{
+ thinker_t thinker;
+ sector_t *sector;
+ ceiling_e type;
+ fixed_t bottomheight, topheight;
+ fixed_t speed;
+ int crush;
+ int direction; // 1 = up, 0 = waiting, -1 = down
+ int tag; // ID
+ int olddirection;
+} ceiling_t;
+
+#define CEILSPEED FRACUNIT
+#define CEILWAIT 150
+#define MAXCEILINGS 30
+
+extern ceiling_t *activeceilings[MAXCEILINGS];
+
+int EV_DoCeiling(line_t * line, byte * args, 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, byte * args);
+
+/*
+===============================================================================
+
+ P_FLOOR
+
+===============================================================================
+*/
+typedef enum
+{
+ FLEV_LOWERFLOOR, // lower floor to highest surrounding floor
+ FLEV_LOWERFLOORTOLOWEST, // lower floor to lowest surrounding floor
+ FLEV_LOWERFLOORBYVALUE,
+ FLEV_RAISEFLOOR, // raise floor to lowest surrounding CEILING
+ FLEV_RAISEFLOORTONEAREST, // raise floor to next highest surrounding floor
+ FLEV_RAISEFLOORBYVALUE,
+ FLEV_RAISEFLOORCRUSH,
+ FLEV_RAISEBUILDSTEP, // One step of a staircase
+ FLEV_RAISEBYVALUETIMES8,
+ FLEV_LOWERBYVALUETIMES8,
+ FLEV_LOWERTIMES8INSTANT,
+ FLEV_RAISETIMES8INSTANT,
+ FLEV_MOVETOVALUETIMES8
+} floor_e;
+
+typedef struct
+{
+ thinker_t thinker;
+ sector_t *sector;
+ floor_e type;
+ int crush;
+ int direction;
+ int newspecial;
+ short texture;
+ fixed_t floordestheight;
+ fixed_t speed;
+ int delayCount;
+ int delayTotal;
+ fixed_t stairsDelayHeight;
+ fixed_t stairsDelayHeightDelta;
+ fixed_t resetHeight;
+ short resetDelay;
+ short resetDelayCount;
+ byte textureChange;
+} floormove_t;
+
+typedef struct
+{
+ thinker_t thinker;
+ sector_t *sector;
+ int ceilingSpeed;
+ int floorSpeed;
+ int floordest;
+ int ceilingdest;
+ int direction;
+ int crush;
+} pillar_t;
+
+typedef struct
+{
+ thinker_t thinker;
+ sector_t *sector;
+ fixed_t originalHeight;
+ fixed_t accumulator;
+ fixed_t accDelta;
+ fixed_t targetScale;
+ fixed_t scale;
+ fixed_t scaleDelta;
+ int ticker;
+ int state;
+} floorWaggle_t;
+
+#define FLOORSPEED FRACUNIT
+
+typedef enum
+{
+ RES_OK,
+ RES_CRUSHED,
+ RES_PASTDEST
+} result_e;
+
+typedef enum
+{
+ STAIRS_NORMAL,
+ STAIRS_SYNC,
+ STAIRS_PHASED
+} stairs_e;
+
+result_e T_MovePlane(sector_t * sector, fixed_t speed,
+ fixed_t dest, int crush, int floorOrCeiling,
+ int direction);
+
+int EV_BuildStairs(line_t * line, byte * args, int direction, stairs_e type);
+int EV_DoFloor(line_t * line, byte * args, floor_e floortype);
+void T_MoveFloor(floormove_t * floor);
+void T_BuildPillar(pillar_t * pillar);
+void T_FloorWaggle(floorWaggle_t * waggle);
+int EV_BuildPillar(line_t * line, byte * args, boolean crush);
+int EV_OpenPillar(line_t * line, byte * args);
+int EV_DoFloorAndCeiling(line_t * line, byte * args, boolean raise);
+int EV_FloorCrushStop(line_t * line, byte * args);
+boolean EV_StartFloorWaggle(int tag, int height, int speed, int offset,
+ int timer);
+
+//--------------------------------------------------------------------------
+//
+// p_telept
+//
+//--------------------------------------------------------------------------
+
+boolean P_Teleport(mobj_t * thing, fixed_t x, fixed_t y, angle_t angle,
+ boolean useFog);
+boolean EV_Teleport(int tid, mobj_t * thing, boolean fog);
+
+//--------------------------------------------------------------------------
+//
+// p_acs
+//
+//--------------------------------------------------------------------------
+
+#define MAX_ACS_SCRIPT_VARS 10
+#define MAX_ACS_MAP_VARS 32
+#define MAX_ACS_WORLD_VARS 64
+#define ACS_STACK_DEPTH 32
+#define MAX_ACS_STORE 20
+
+typedef enum
+{
+ ASTE_INACTIVE,
+ ASTE_RUNNING,
+ ASTE_SUSPENDED,
+ ASTE_WAITINGFORTAG,
+ ASTE_WAITINGFORPOLY,
+ ASTE_WAITINGFORSCRIPT,
+ ASTE_TERMINATING
+} aste_t;
+
+typedef struct acs_s acs_t;
+typedef struct acsInfo_s acsInfo_t;
+
+struct acsInfo_s
+{
+ int number;
+ int *address;
+ int argCount;
+ aste_t state;
+ int waitValue;
+};
+
+struct acs_s
+{
+ thinker_t thinker;
+ mobj_t *activator;
+ line_t *line;
+ int side;
+ int number;
+ int infoIndex;
+ int delayCount;
+ int stack[ACS_STACK_DEPTH];
+ int stackPtr;
+ int vars[MAX_ACS_SCRIPT_VARS];
+ int *ip;
+};
+
+typedef struct
+{
+ int map; // Target map
+ int script; // Script number on target map
+ byte args[4]; // Padded to 4 for alignment
+} acsstore_t;
+
+void P_LoadACScripts(int lump);
+boolean P_StartACS(int number, int map, byte * args, mobj_t * activator,
+ line_t * line, int side);
+boolean P_StartLockedACS(line_t * line, byte * args, mobj_t * mo, int side);
+boolean P_TerminateACS(int number, int map);
+boolean P_SuspendACS(int number, int map);
+void T_InterpretACS(acs_t * script);
+void P_TagFinished(int tag);
+void P_PolyobjFinished(int po);
+void P_ACSInitNewGame(void);
+void P_CheckACSStore(void);
+
+extern int ACScriptCount;
+extern byte *ActionCodeBase;
+extern acsInfo_t *ACSInfo;
+extern int MapVars[MAX_ACS_MAP_VARS];
+extern int WorldVars[MAX_ACS_WORLD_VARS];
+extern acsstore_t ACSStore[MAX_ACS_STORE + 1]; // +1 for termination marker
+
+//--------------------------------------------------------------------------
+//
+// p_things
+//
+//--------------------------------------------------------------------------
+
+extern mobjtype_t TranslateThingType[];
+
+boolean EV_ThingProjectile(byte * args, boolean gravity);
+boolean EV_ThingSpawn(byte * args, boolean fog);
+boolean EV_ThingActivate(int tid);
+boolean EV_ThingDeactivate(int tid);
+boolean EV_ThingRemove(int tid);
+boolean EV_ThingDestroy(int tid);
diff --git a/src/hexen/p_switch.c b/src/hexen/p_switch.c
new file mode 100644
index 00000000..bed0a252
--- /dev/null
+++ b/src/hexen/p_switch.c
@@ -0,0 +1,159 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#include "h2def.h"
+#include "i_system.h"
+#include "p_local.h"
+#include "s_sound.h"
+
+//==================================================================
+//
+// CHANGE THE TEXTURE OF A WALL SWITCH TO ITS OPPOSITE
+//
+//==================================================================
+switchlist_t alphSwitchList[] = {
+ {"SW_1_UP", "SW_1_DN", SFX_SWITCH1},
+ {"SW_2_UP", "SW_2_DN", SFX_SWITCH1},
+ {"VALVE1", "VALVE2", SFX_VALVE_TURN},
+ {"SW51_OFF", "SW51_ON", SFX_SWITCH2},
+ {"SW52_OFF", "SW52_ON", SFX_SWITCH2},
+ {"SW53_UP", "SW53_DN", SFX_ROPE_PULL},
+ {"PUZZLE5", "PUZZLE9", SFX_SWITCH1},
+ {"PUZZLE6", "PUZZLE10", SFX_SWITCH1},
+ {"PUZZLE7", "PUZZLE11", SFX_SWITCH1},
+ {"PUZZLE8", "PUZZLE12", SFX_SWITCH1},
+ {"\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;
+
+ for (index = 0, i = 0; i < MAXSWITCHES; i++)
+ {
+ if (!alphSwitchList[i].soundID)
+ {
+ numswitches = index / 2;
+ switchlist[index] = -1;
+ break;
+ }
+ 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;
+
+ 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("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;
+
+ texTop = sides[line->sidenum[0]].toptexture;
+ texMid = sides[line->sidenum[0]].midtexture;
+ texBot = sides[line->sidenum[0]].bottomtexture;
+
+ for (i = 0; i < numswitches * 2; i++)
+ {
+ if (switchlist[i] == texTop)
+ {
+ S_StartSound((mobj_t *) & line->frontsector->soundorg,
+ alphSwitchList[i / 2].soundID);
+ sides[line->sidenum[0]].toptexture = switchlist[i ^ 1];
+ if (useAgain)
+ {
+ P_StartButton(line, SWTCH_TOP, switchlist[i], BUTTONTIME);
+ }
+ return;
+ }
+ else if (switchlist[i] == texMid)
+ {
+ S_StartSound((mobj_t *) & line->frontsector->soundorg,
+ alphSwitchList[i / 2].soundID);
+ sides[line->sidenum[0]].midtexture = switchlist[i ^ 1];
+ if (useAgain)
+ {
+ P_StartButton(line, SWTCH_MIDDLE, switchlist[i], BUTTONTIME);
+ }
+ return;
+ }
+ else if (switchlist[i] == texBot)
+ {
+ S_StartSound((mobj_t *) & line->frontsector->soundorg,
+ alphSwitchList[i / 2].soundID);
+ sides[line->sidenum[0]].bottomtexture = switchlist[i ^ 1];
+ if (useAgain)
+ {
+ P_StartButton(line, SWTCH_BOTTOM, switchlist[i], BUTTONTIME);
+ }
+ return;
+ }
+ }
+}
diff --git a/src/hexen/p_telept.c b/src/hexen/p_telept.c
new file mode 100644
index 00000000..1e29b469
--- /dev/null
+++ b/src/hexen/p_telept.c
@@ -0,0 +1,198 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2def.h"
+#include "m_random.h"
+#include "i_system.h"
+#include "p_local.h"
+#include "s_sound.h"
+
+// MACROS ------------------------------------------------------------------
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// P_Teleport
+//
+//==========================================================================
+
+boolean P_Teleport(mobj_t * thing, fixed_t x, fixed_t y, angle_t angle,
+ boolean useFog)
+{
+ fixed_t oldx;
+ fixed_t oldy;
+ fixed_t oldz;
+ fixed_t aboveFloor;
+ fixed_t fogDelta;
+ player_t *player;
+ unsigned an;
+ mobj_t *fog;
+
+ oldx = thing->x;
+ oldy = thing->y;
+ oldz = thing->z;
+ aboveFloor = thing->z - thing->floorz;
+ if (!P_TeleportMove(thing, x, y))
+ {
+ return false;
+ }
+ if (thing->player)
+ {
+ player = thing->player;
+ if (player->powers[pw_flight] && aboveFloor)
+ {
+ thing->z = thing->floorz + aboveFloor;
+ if (thing->z + thing->height > thing->ceilingz)
+ {
+ thing->z = thing->ceilingz - thing->height;
+ }
+ player->viewz = thing->z + player->viewheight;
+ }
+ else
+ {
+ thing->z = thing->floorz;
+ player->viewz = thing->z + player->viewheight;
+ if (useFog)
+ {
+ player->lookdir = 0;
+ }
+ }
+ }
+ else if (thing->flags & MF_MISSILE)
+ {
+ thing->z = thing->floorz + aboveFloor;
+ if (thing->z + thing->height > thing->ceilingz)
+ {
+ thing->z = thing->ceilingz - thing->height;
+ }
+ }
+ else
+ {
+ thing->z = thing->floorz;
+ }
+ // Spawn teleport fog at source and destination
+ if (useFog)
+ {
+ fogDelta = thing->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT;
+ fog = P_SpawnMobj(oldx, oldy, oldz + fogDelta, MT_TFOG);
+ S_StartSound(fog, SFX_TELEPORT);
+ an = angle >> ANGLETOFINESHIFT;
+ fog = P_SpawnMobj(x + 20 * finecosine[an],
+ y + 20 * finesine[an], thing->z + fogDelta,
+ MT_TFOG);
+ S_StartSound(fog, SFX_TELEPORT);
+ if (thing->player && !thing->player->powers[pw_speed])
+ { // Freeze player for about .5 sec
+ thing->reactiontime = 18;
+ }
+ thing->angle = angle;
+ }
+ if (thing->flags2 & MF2_FLOORCLIP)
+ {
+ if (thing->z == thing->subsector->sector->floorheight
+ && P_GetThingFloorType(thing) > FLOOR_SOLID)
+ {
+ thing->floorclip = 10 * FRACUNIT;
+ }
+ else
+ {
+ thing->floorclip = 0;
+ }
+ }
+ if (thing->flags & MF_MISSILE)
+ {
+ angle >>= ANGLETOFINESHIFT;
+ thing->momx = FixedMul(thing->info->speed, finecosine[angle]);
+ thing->momy = FixedMul(thing->info->speed, finesine[angle]);
+ }
+ else if (useFog) // no fog doesn't alter the player's momentums
+ {
+ thing->momx = thing->momy = thing->momz = 0;
+ }
+ return true;
+}
+
+//==========================================================================
+//
+// EV_Teleport
+//
+//==========================================================================
+
+boolean EV_Teleport(int tid, mobj_t * thing, boolean fog)
+{
+ int i;
+ int count;
+ mobj_t *mo;
+ int searcher;
+
+ if (!thing)
+ { // Teleport function called with an invalid mobj
+ return false;
+ }
+ if (thing->flags2 & MF2_NOTELEPORT)
+ {
+ return false;
+ }
+ count = 0;
+ searcher = -1;
+ while (P_FindMobjFromTID(tid, &searcher) != NULL)
+ {
+ count++;
+ }
+ if (count == 0)
+ {
+ return false;
+ }
+ count = 1 + (P_Random() % count);
+ searcher = -1;
+ mo = NULL;
+
+ for (i = 0; i < count; i++)
+ {
+ mo = P_FindMobjFromTID(tid, &searcher);
+ }
+ if (mo == NULL)
+ {
+ I_Error("Can't find teleport mapspot\n");
+ }
+ return P_Teleport(thing, mo->x, mo->y, mo->angle, fog);
+}
diff --git a/src/hexen/p_things.c b/src/hexen/p_things.c
new file mode 100644
index 00000000..5e137100
--- /dev/null
+++ b/src/hexen/p_things.c
@@ -0,0 +1,545 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2def.h"
+#include "p_local.h"
+#include "s_sound.h"
+
+// MACROS ------------------------------------------------------------------
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static boolean ActivateThing(mobj_t * mobj);
+static boolean DeactivateThing(mobj_t * mobj);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+mobjtype_t TranslateThingType[] = {
+ MT_MAPSPOT, // T_NONE
+ MT_CENTAUR, // T_CENTAUR
+ MT_CENTAURLEADER, // T_CENTAURLEADER
+ MT_DEMON, // T_DEMON
+ MT_ETTIN, // T_ETTIN
+ MT_FIREDEMON, // T_FIREGARGOYLE
+ MT_SERPENT, // T_WATERLURKER
+ MT_SERPENTLEADER, // T_WATERLURKERLEADER
+ MT_WRAITH, // T_WRAITH
+ MT_WRAITHB, // T_WRAITHBURIED
+ MT_FIREBALL1, // T_FIREBALL1
+ MT_MANA1, // T_MANA1
+ MT_MANA2, // T_MANA2
+ MT_SPEEDBOOTS, // T_ITEMBOOTS
+ MT_ARTIEGG, // T_ITEMEGG
+ MT_ARTIFLY, // T_ITEMFLIGHT
+ MT_SUMMONMAULATOR, // T_ITEMSUMMON
+ MT_TELEPORTOTHER, // T_ITEMTPORTOTHER
+ MT_ARTITELEPORT, // T_ITEMTELEPORT
+ MT_BISHOP, // T_BISHOP
+ MT_ICEGUY, // T_ICEGOLEM
+ MT_BRIDGE, // T_BRIDGE
+ MT_BOOSTARMOR, // T_DRAGONSKINBRACERS
+ MT_HEALINGBOTTLE, // T_ITEMHEALTHPOTION
+ MT_HEALTHFLASK, // T_ITEMHEALTHFLASK
+ MT_ARTISUPERHEAL, // T_ITEMHEALTHFULL
+ MT_BOOSTMANA, // T_ITEMBOOSTMANA
+ MT_FW_AXE, // T_FIGHTERAXE
+ MT_FW_HAMMER, // T_FIGHTERHAMMER
+ MT_FW_SWORD1, // T_FIGHTERSWORD1
+ MT_FW_SWORD2, // T_FIGHTERSWORD2
+ MT_FW_SWORD3, // T_FIGHTERSWORD3
+ MT_CW_SERPSTAFF, // T_CLERICSTAFF
+ MT_CW_HOLY1, // T_CLERICHOLY1
+ MT_CW_HOLY2, // T_CLERICHOLY2
+ MT_CW_HOLY3, // T_CLERICHOLY3
+ MT_MW_CONE, // T_MAGESHARDS
+ MT_MW_STAFF1, // T_MAGESTAFF1
+ MT_MW_STAFF2, // T_MAGESTAFF2
+ MT_MW_STAFF3, // T_MAGESTAFF3
+ MT_EGGFX, // T_MORPHBLAST
+ MT_ROCK1, // T_ROCK1
+ MT_ROCK2, // T_ROCK2
+ MT_ROCK3, // T_ROCK3
+ MT_DIRT1, // T_DIRT1
+ MT_DIRT2, // T_DIRT2
+ MT_DIRT3, // T_DIRT3
+ MT_DIRT4, // T_DIRT4
+ MT_DIRT5, // T_DIRT5
+ MT_DIRT6, // T_DIRT6
+ MT_ARROW, // T_ARROW
+ MT_DART, // T_DART
+ MT_POISONDART, // T_POISONDART
+ MT_RIPPERBALL, // T_RIPPERBALL
+ MT_SGSHARD1, // T_STAINEDGLASS1
+ MT_SGSHARD2, // T_STAINEDGLASS2
+ MT_SGSHARD3, // T_STAINEDGLASS3
+ MT_SGSHARD4, // T_STAINEDGLASS4
+ MT_SGSHARD5, // T_STAINEDGLASS5
+ MT_SGSHARD6, // T_STAINEDGLASS6
+ MT_SGSHARD7, // T_STAINEDGLASS7
+ MT_SGSHARD8, // T_STAINEDGLASS8
+ MT_SGSHARD9, // T_STAINEDGLASS9
+ MT_SGSHARD0, // T_STAINEDGLASS0
+ MT_PROJECTILE_BLADE, // T_BLADE
+ MT_ICESHARD, // T_ICESHARD
+ MT_FLAME_SMALL, // T_FLAME_SMALL
+ MT_FLAME_LARGE, // T_FLAME_LARGE
+ MT_ARMOR_1, // T_MESHARMOR
+ MT_ARMOR_2, // T_FALCONSHIELD
+ MT_ARMOR_3, // T_PLATINUMHELM
+ MT_ARMOR_4, // T_AMULETOFWARDING
+ MT_ARTIPOISONBAG, // T_ITEMFLECHETTE
+ MT_ARTITORCH, // T_ITEMTORCH
+ MT_BLASTRADIUS, // T_ITEMREPULSION
+ MT_MANA3, // T_MANA3
+ MT_ARTIPUZZSKULL, // T_PUZZSKULL
+ MT_ARTIPUZZGEMBIG, // T_PUZZGEMBIG
+ MT_ARTIPUZZGEMRED, // T_PUZZGEMRED
+ MT_ARTIPUZZGEMGREEN1, // T_PUZZGEMGREEN1
+ MT_ARTIPUZZGEMGREEN2, // T_PUZZGEMGREEN2
+ MT_ARTIPUZZGEMBLUE1, // T_PUZZGEMBLUE1
+ MT_ARTIPUZZGEMBLUE2, // T_PUZZGEMBLUE2
+ MT_ARTIPUZZBOOK1, // T_PUZZBOOK1
+ MT_ARTIPUZZBOOK2, // T_PUZZBOOK2
+ MT_KEY1, // T_METALKEY
+ MT_KEY2, // T_SMALLMETALKEY
+ MT_KEY3, // T_AXEKEY
+ MT_KEY4, // T_FIREKEY
+ MT_KEY5, // T_GREENKEY
+ MT_KEY6, // T_MACEKEY
+ MT_KEY7, // T_SILVERKEY
+ MT_KEY8, // T_RUSTYKEY
+ MT_KEY9, // T_HORNKEY
+ MT_KEYA, // T_SERPENTKEY
+ MT_WATER_DRIP, // T_WATERDRIP
+ MT_FLAME_SMALL_TEMP, // T_TEMPSMALLFLAME
+ MT_FLAME_SMALL, // T_PERMSMALLFLAME
+ MT_FLAME_LARGE_TEMP, // T_TEMPLARGEFLAME
+ MT_FLAME_LARGE, // T_PERMLARGEFLAME
+ MT_DEMON_MASH, // T_DEMON_MASH
+ MT_DEMON2_MASH, // T_DEMON2_MASH
+ MT_ETTIN_MASH, // T_ETTIN_MASH
+ MT_CENTAUR_MASH, // T_CENTAUR_MASH
+ MT_THRUSTFLOOR_UP, // T_THRUSTSPIKEUP
+ MT_THRUSTFLOOR_DOWN, // T_THRUSTSPIKEDOWN
+ MT_WRAITHFX4, // T_FLESH_DRIP1
+ MT_WRAITHFX5, // T_FLESH_DRIP2
+ MT_WRAITHFX2 // T_SPARK_DRIP
+};
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// EV_ThingProjectile
+//
+//==========================================================================
+
+boolean EV_ThingProjectile(byte * args, boolean gravity)
+{
+ int tid;
+ angle_t angle;
+ int fineAngle;
+ fixed_t speed;
+ fixed_t vspeed;
+ mobjtype_t moType;
+ mobj_t *mobj;
+ mobj_t *newMobj;
+ int searcher;
+ boolean success;
+
+ success = false;
+ searcher = -1;
+ tid = args[0];
+ moType = TranslateThingType[args[1]];
+ if (nomonsters && (mobjinfo[moType].flags & MF_COUNTKILL))
+ { // Don't spawn monsters if -nomonsters
+ return false;
+ }
+ angle = (int) args[2] << 24;
+ fineAngle = angle >> ANGLETOFINESHIFT;
+ speed = (int) args[3] << 13;
+ vspeed = (int) args[4] << 13;
+ while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
+ {
+ newMobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, moType);
+ if (newMobj->info->seesound)
+ {
+ S_StartSound(newMobj, newMobj->info->seesound);
+ }
+ newMobj->target = mobj; // Originator
+ newMobj->angle = angle;
+ newMobj->momx = FixedMul(speed, finecosine[fineAngle]);
+ newMobj->momy = FixedMul(speed, finesine[fineAngle]);
+ newMobj->momz = vspeed;
+ newMobj->flags2 |= MF2_DROPPED; // Don't respawn
+ if (gravity == true)
+ {
+ newMobj->flags &= ~MF_NOGRAVITY;
+ newMobj->flags2 |= MF2_LOGRAV;
+ }
+ if (P_CheckMissileSpawn(newMobj) == true)
+ {
+ success = true;
+ }
+ }
+ return success;
+}
+
+//==========================================================================
+//
+// EV_ThingSpawn
+//
+//==========================================================================
+
+boolean EV_ThingSpawn(byte * args, boolean fog)
+{
+ int tid;
+ angle_t angle;
+ mobj_t *mobj;
+ mobj_t *newMobj;
+ mobj_t *fogMobj;
+ mobjtype_t moType;
+ int searcher;
+ boolean success;
+ fixed_t z;
+
+ success = false;
+ searcher = -1;
+ tid = args[0];
+ moType = TranslateThingType[args[1]];
+ if (nomonsters && (mobjinfo[moType].flags & MF_COUNTKILL))
+ { // Don't spawn monsters if -nomonsters
+ return false;
+ }
+ angle = (int) args[2] << 24;
+ while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
+ {
+ if (mobjinfo[moType].flags2 & MF2_FLOATBOB)
+ {
+ z = mobj->z - mobj->floorz;
+ }
+ else
+ {
+ z = mobj->z;
+ }
+ newMobj = P_SpawnMobj(mobj->x, mobj->y, z, moType);
+ if (P_TestMobjLocation(newMobj) == false)
+ { // Didn't fit
+ P_RemoveMobj(newMobj);
+ }
+ else
+ {
+ newMobj->angle = angle;
+ if (fog == true)
+ {
+ fogMobj = P_SpawnMobj(mobj->x, mobj->y,
+ mobj->z + TELEFOGHEIGHT, MT_TFOG);
+ S_StartSound(fogMobj, SFX_TELEPORT);
+ }
+ newMobj->flags2 |= MF2_DROPPED; // Don't respawn
+ if (newMobj->flags2 & MF2_FLOATBOB)
+ {
+ newMobj->special1.i = newMobj->z - newMobj->floorz;
+ }
+ success = true;
+ }
+ }
+ return success;
+}
+
+//==========================================================================
+//
+// EV_ThingActivate
+//
+//==========================================================================
+
+boolean EV_ThingActivate(int tid)
+{
+ mobj_t *mobj;
+ int searcher;
+ boolean success;
+
+ success = false;
+ searcher = -1;
+ while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
+ {
+ if (ActivateThing(mobj) == true)
+ {
+ success = true;
+ }
+ }
+ return success;
+}
+
+//==========================================================================
+//
+// EV_ThingDeactivate
+//
+//==========================================================================
+
+boolean EV_ThingDeactivate(int tid)
+{
+ mobj_t *mobj;
+ int searcher;
+ boolean success;
+
+ success = false;
+ searcher = -1;
+ while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
+ {
+ if (DeactivateThing(mobj) == true)
+ {
+ success = true;
+ }
+ }
+ return success;
+}
+
+//==========================================================================
+//
+// EV_ThingRemove
+//
+//==========================================================================
+
+boolean EV_ThingRemove(int tid)
+{
+ mobj_t *mobj;
+ int searcher;
+ boolean success;
+
+ success = false;
+ searcher = -1;
+ while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
+ {
+ if (mobj->type == MT_BRIDGE)
+ {
+ A_BridgeRemove(mobj);
+ return true;
+ }
+ P_RemoveMobj(mobj);
+ success = true;
+ }
+ return success;
+}
+
+//==========================================================================
+//
+// EV_ThingDestroy
+//
+//==========================================================================
+
+boolean EV_ThingDestroy(int tid)
+{
+ mobj_t *mobj;
+ int searcher;
+ boolean success;
+
+ success = false;
+ searcher = -1;
+ while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
+ {
+ if (mobj->flags & MF_SHOOTABLE)
+ {
+ P_DamageMobj(mobj, NULL, NULL, 10000);
+ success = true;
+ }
+ }
+ return success;
+}
+
+//==========================================================================
+//
+// EV_ThingMove
+//
+// arg[0] = tid
+// arg[1] = speed
+// arg[2] = angle (255 = use mobj angle)
+// arg[3] = distance (pixels>>2)
+//
+//==========================================================================
+
+/*
+boolean EV_ThingMove(byte *args)
+{
+ return false;
+}
+*/
+
+//==========================================================================
+//
+// ActivateThing
+//
+//==========================================================================
+
+static boolean ActivateThing(mobj_t * mobj)
+{
+ if (mobj->flags & MF_COUNTKILL)
+ { // Monster
+ if (mobj->flags2 & MF2_DORMANT)
+ {
+ mobj->flags2 &= ~MF2_DORMANT;
+ mobj->tics = 1;
+ return true;
+ }
+ return false;
+ }
+ switch (mobj->type)
+ {
+ case MT_ZTWINEDTORCH:
+ case MT_ZTWINEDTORCH_UNLIT:
+ P_SetMobjState(mobj, S_ZTWINEDTORCH_1);
+ S_StartSound(mobj, SFX_IGNITE);
+ break;
+ case MT_ZWALLTORCH:
+ case MT_ZWALLTORCH_UNLIT:
+ P_SetMobjState(mobj, S_ZWALLTORCH1);
+ S_StartSound(mobj, SFX_IGNITE);
+ break;
+ case MT_ZGEMPEDESTAL:
+ P_SetMobjState(mobj, S_ZGEMPEDESTAL2);
+ break;
+ case MT_ZWINGEDSTATUENOSKULL:
+ P_SetMobjState(mobj, S_ZWINGEDSTATUENOSKULL2);
+ break;
+ case MT_THRUSTFLOOR_UP:
+ case MT_THRUSTFLOOR_DOWN:
+ if (mobj->args[0] == 0)
+ {
+ S_StartSound(mobj, SFX_THRUSTSPIKE_LOWER);
+ mobj->flags2 &= ~MF2_DONTDRAW;
+ if (mobj->args[1])
+ P_SetMobjState(mobj, S_BTHRUSTRAISE1);
+ else
+ P_SetMobjState(mobj, S_THRUSTRAISE1);
+ }
+ break;
+ case MT_ZFIREBULL:
+ case MT_ZFIREBULL_UNLIT:
+ P_SetMobjState(mobj, S_ZFIREBULL_BIRTH);
+ S_StartSound(mobj, SFX_IGNITE);
+ break;
+ case MT_ZBELL:
+ if (mobj->health > 0)
+ {
+ P_DamageMobj(mobj, NULL, NULL, 10); // 'ring' the bell
+ }
+ break;
+ case MT_ZCAULDRON:
+ case MT_ZCAULDRON_UNLIT:
+ P_SetMobjState(mobj, S_ZCAULDRON1);
+ S_StartSound(mobj, SFX_IGNITE);
+ break;
+ case MT_FLAME_SMALL:
+ S_StartSound(mobj, SFX_IGNITE);
+ P_SetMobjState(mobj, S_FLAME_SMALL1);
+ break;
+ case MT_FLAME_LARGE:
+ S_StartSound(mobj, SFX_IGNITE);
+ P_SetMobjState(mobj, S_FLAME_LARGE1);
+ break;
+ case MT_BAT_SPAWNER:
+ P_SetMobjState(mobj, S_SPAWNBATS1);
+ break;
+ default:
+ return false;
+ break;
+ }
+ return true;
+}
+
+//==========================================================================
+//
+// DeactivateThing
+//
+//==========================================================================
+
+static boolean DeactivateThing(mobj_t * mobj)
+{
+ if (mobj->flags & MF_COUNTKILL)
+ { // Monster
+ if (!(mobj->flags2 & MF2_DORMANT))
+ {
+ mobj->flags2 |= MF2_DORMANT;
+ mobj->tics = -1;
+ return true;
+ }
+ return false;
+ }
+ switch (mobj->type)
+ {
+ case MT_ZTWINEDTORCH:
+ case MT_ZTWINEDTORCH_UNLIT:
+ P_SetMobjState(mobj, S_ZTWINEDTORCH_UNLIT);
+ break;
+ case MT_ZWALLTORCH:
+ case MT_ZWALLTORCH_UNLIT:
+ P_SetMobjState(mobj, S_ZWALLTORCH_U);
+ break;
+ case MT_THRUSTFLOOR_UP:
+ case MT_THRUSTFLOOR_DOWN:
+ if (mobj->args[0] == 1)
+ {
+ S_StartSound(mobj, SFX_THRUSTSPIKE_RAISE);
+ if (mobj->args[1])
+ P_SetMobjState(mobj, S_BTHRUSTLOWER);
+ else
+ P_SetMobjState(mobj, S_THRUSTLOWER);
+ }
+ break;
+ case MT_ZFIREBULL:
+ case MT_ZFIREBULL_UNLIT:
+ P_SetMobjState(mobj, S_ZFIREBULL_DEATH);
+ break;
+ case MT_ZCAULDRON:
+ case MT_ZCAULDRON_UNLIT:
+ P_SetMobjState(mobj, S_ZCAULDRON_U);
+ break;
+ case MT_FLAME_SMALL:
+ P_SetMobjState(mobj, S_FLAME_SDORM1);
+ break;
+ case MT_FLAME_LARGE:
+ P_SetMobjState(mobj, S_FLAME_LDORM1);
+ break;
+ case MT_BAT_SPAWNER:
+ P_SetMobjState(mobj, S_SPAWNBATS_OFF);
+ break;
+ default:
+ return false;
+ break;
+ }
+ return true;
+}
diff --git a/src/hexen/p_tick.c b/src/hexen/p_tick.c
new file mode 100644
index 00000000..ad261981
--- /dev/null
+++ b/src/hexen/p_tick.c
@@ -0,0 +1,155 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2def.h"
+#include "p_local.h"
+
+// MACROS ------------------------------------------------------------------
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void RunThinkers(void);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+int leveltime;
+int TimerGame;
+thinker_t thinkercap; // The head and tail of the thinker list
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// P_Ticker
+//
+//==========================================================================
+
+void P_Ticker(void)
+{
+ int i;
+
+ if (paused)
+ {
+ return;
+ }
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ {
+ P_PlayerThink(&players[i]);
+ }
+ }
+ if (TimerGame)
+ {
+ if (!--TimerGame)
+ {
+ G_Completed(P_TranslateMap(P_GetMapNextMap(gamemap)), 0);
+ }
+ }
+ RunThinkers();
+ P_UpdateSpecials();
+ P_AnimateSurfaces();
+ leveltime++;
+}
+
+//==========================================================================
+//
+// RunThinkers
+//
+//==========================================================================
+
+static void RunThinkers(void)
+{
+ thinker_t *currentthinker;
+
+ currentthinker = thinkercap.next;
+ while (currentthinker != &thinkercap)
+ {
+ if (currentthinker->function == (think_t) - 1)
+ { // Time to remove it
+ currentthinker->next->prev = currentthinker->prev;
+ currentthinker->prev->next = currentthinker->next;
+ Z_Free(currentthinker);
+ }
+ else if (currentthinker->function)
+ {
+ currentthinker->function(currentthinker);
+ }
+ currentthinker = currentthinker->next;
+ }
+}
+
+//==========================================================================
+//
+// 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)
+{
+ thinker->function = (think_t) - 1;
+}
diff --git a/src/hexen/p_user.c b/src/hexen/p_user.c
new file mode 100644
index 00000000..17c96a47
--- /dev/null
+++ b/src/hexen/p_user.c
@@ -0,0 +1,1652 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#include "h2def.h"
+#include "m_random.h"
+#include "i_system.h"
+#include "p_local.h"
+#include "s_sound.h"
+
+void P_PlayerNextArtifact(player_t * player);
+
+// Macros
+
+#define MAXBOB 0x100000 // 16 pixels of bob
+
+// Data
+
+boolean onground;
+int newtorch; // used in the torch flicker effect.
+int newtorchdelta;
+
+int PStateNormal[NUMCLASSES] = {
+ S_FPLAY,
+ S_CPLAY,
+ S_MPLAY,
+ S_PIGPLAY
+};
+
+int PStateRun[NUMCLASSES] = {
+ S_FPLAY_RUN1,
+ S_CPLAY_RUN1,
+ S_MPLAY_RUN1,
+ S_PIGPLAY_RUN1
+};
+
+int PStateAttack[NUMCLASSES] = {
+ S_FPLAY_ATK1,
+ S_CPLAY_ATK1,
+ S_MPLAY_ATK1,
+ S_PIGPLAY_ATK1
+};
+
+int PStateAttackEnd[NUMCLASSES] = {
+ S_FPLAY_ATK2,
+ S_CPLAY_ATK3,
+ S_MPLAY_ATK2,
+ S_PIGPLAY_ATK1
+};
+
+int ArmorMax[NUMCLASSES] = { 20, 18, 16, 1 };
+
+/*
+==================
+=
+= P_Thrust
+=
+= moves the given origin along a given angle
+=
+==================
+*/
+
+void P_Thrust(player_t * player, angle_t angle, fixed_t move)
+{
+ angle >>= ANGLETOFINESHIFT;
+ if (player->powers[pw_flight] && !(player->mo->z <= player->mo->floorz))
+ {
+ player->mo->momx += FixedMul(move, finecosine[angle]);
+ player->mo->momy += FixedMul(move, finesine[angle]);
+ }
+ else if (P_GetThingFloorType(player->mo) == FLOOR_ICE) // Friction_Low
+ {
+ player->mo->momx += FixedMul(move >> 1, finecosine[angle]);
+ player->mo->momy += FixedMul(move >> 1, finesine[angle]);
+ }
+ else
+ {
+ 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
+
+ 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->mo->flags2 & MF2_FLY && !onground)
+ {
+ player->bob = FRACUNIT / 2;
+ }
+
+ if ((player->cheats & CF_NOMOMENTUM))
+ {
+ 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;
+ }
+ }
+
+ if (player->morphTics)
+ {
+ player->viewz = player->mo->z + player->viewheight - (20 * FRACUNIT);
+ }
+ else
+ {
+ player->viewz = player->mo->z + player->viewheight + bob;
+ }
+ if (player->mo->floorclip && player->playerstate != PST_DEAD
+ && player->mo->z <= player->mo->floorz)
+ {
+ player->viewz -= player->mo->floorclip;
+ }
+ if (player->viewz > player->mo->ceilingz - 4 * FRACUNIT)
+ {
+ player->viewz = player->mo->ceilingz - 4 * FRACUNIT;
+ }
+ if (player->viewz < player->mo->floorz + 4 * FRACUNIT)
+ {
+ player->viewz = player->mo->floorz + 4 * FRACUNIT;
+ }
+}
+
+/*
+=================
+=
+= P_MovePlayer
+=
+=================
+*/
+
+void P_MovePlayer(player_t * player)
+{
+ int look;
+ int fly;
+ ticcmd_t *cmd;
+
+ cmd = &player->cmd;
+ player->mo->angle += (cmd->angleturn << 16);
+
+ onground = (player->mo->z <= player->mo->floorz
+ || (player->mo->flags2 & MF2_ONMOBJ));
+
+ if (cmd->forwardmove)
+ {
+ if (onground || player->mo->flags2 & MF2_FLY)
+ {
+ P_Thrust(player, player->mo->angle, cmd->forwardmove * 2048);
+ }
+ else
+ {
+ P_Thrust(player, player->mo->angle, FRACUNIT >> 8);
+ }
+ }
+ if (cmd->sidemove)
+ {
+ if (onground || player->mo->flags2 & MF2_FLY)
+ {
+ P_Thrust(player, player->mo->angle - ANG90, cmd->sidemove * 2048);
+ }
+ else
+ {
+ P_Thrust(player, player->mo->angle, FRACUNIT >> 8);
+ }
+ }
+ if (cmd->forwardmove || cmd->sidemove)
+ {
+ if (player->mo->state == &states[PStateNormal[player->class]])
+ {
+ P_SetMobjState(player->mo, PStateRun[player->class]);
+ }
+ }
+
+ look = cmd->lookfly & 15;
+ if (look > 7)
+ {
+ look -= 16;
+ }
+ if (look)
+ {
+ if (look == TOCENTER)
+ {
+ player->centering = true;
+ }
+ else
+ {
+ player->lookdir += 5 * look;
+ if (player->lookdir > 90 || player->lookdir < -110)
+ {
+ player->lookdir -= 5 * look;
+ }
+ }
+ }
+ if (player->centering)
+ {
+ if (player->lookdir > 0)
+ {
+ player->lookdir -= 8;
+ }
+ else if (player->lookdir < 0)
+ {
+ player->lookdir += 8;
+ }
+ if (abs(player->lookdir) < 8)
+ {
+ player->lookdir = 0;
+ player->centering = false;
+ }
+ }
+ fly = cmd->lookfly >> 4;
+ if (fly > 7)
+ {
+ fly -= 16;
+ }
+ if (fly && player->powers[pw_flight])
+ {
+ if (fly != TOCENTER)
+ {
+ player->flyheight = fly * 2;
+ if (!(player->mo->flags2 & MF2_FLY))
+ {
+ player->mo->flags2 |= MF2_FLY;
+ player->mo->flags |= MF_NOGRAVITY;
+ if (player->mo->momz <= -39 * FRACUNIT)
+ { // stop falling scream
+ S_StopSound(player->mo);
+ }
+ }
+ }
+ else
+ {
+ player->mo->flags2 &= ~MF2_FLY;
+ player->mo->flags &= ~MF_NOGRAVITY;
+ }
+ }
+ else if (fly > 0)
+ {
+ P_PlayerUseArtifact(player, arti_fly);
+ }
+ if (player->mo->flags2 & MF2_FLY)
+ {
+ player->mo->momz = player->flyheight * FRACUNIT;
+ if (player->flyheight)
+ {
+ player->flyheight /= 2;
+ }
+ }
+}
+
+//==========================================================================
+//
+// P_DeathThink
+//
+//==========================================================================
+
+void P_DeathThink(player_t * player)
+{
+ int dir;
+ angle_t delta;
+ int lookDelta;
+
+ P_MovePsprites(player);
+
+ onground = (player->mo->z <= player->mo->floorz);
+ if (player->mo->type == MT_BLOODYSKULL || player->mo->type == MT_ICECHUNK)
+ { // Flying bloody skull or flying ice chunk
+ player->viewheight = 6 * FRACUNIT;
+ player->deltaviewheight = 0;
+ //player->damagecount = 20;
+ if (onground)
+ {
+ if (player->lookdir < 60)
+ {
+ lookDelta = (60 - player->lookdir) / 8;
+ if (lookDelta < 1 && (leveltime & 1))
+ {
+ lookDelta = 1;
+ }
+ else if (lookDelta > 6)
+ {
+ lookDelta = 6;
+ }
+ player->lookdir += lookDelta;
+ }
+ }
+ }
+ else if (!(player->mo->flags2 & MF2_ICEDAMAGE))
+ { // Fall to ground (if not frozen)
+ player->deltaviewheight = 0;
+ if (player->viewheight > 6 * FRACUNIT)
+ {
+ player->viewheight -= FRACUNIT;
+ }
+ if (player->viewheight < 6 * FRACUNIT)
+ {
+ player->viewheight = 6 * FRACUNIT;
+ }
+ if (player->lookdir > 0)
+ {
+ player->lookdir -= 6;
+ }
+ else if (player->lookdir < 0)
+ {
+ player->lookdir += 6;
+ }
+ if (abs(player->lookdir) < 6)
+ {
+ player->lookdir = 0;
+ }
+ }
+ P_CalcHeight(player);
+
+ if (player->attacker && player->attacker != player->mo)
+ { // Watch killer
+ dir = P_FaceMobj(player->mo, player->attacker, &delta);
+ if (delta < ANG1 * 10)
+ { // Looking at killer, so fade damage and poison counters
+ if (player->damagecount)
+ {
+ player->damagecount--;
+ }
+ if (player->poisoncount)
+ {
+ player->poisoncount--;
+ }
+ }
+ delta = delta / 8;
+ if (delta > ANG1 * 5)
+ {
+ delta = ANG1 * 5;
+ }
+ if (dir)
+ { // Turn clockwise
+ player->mo->angle += delta;
+ }
+ else
+ { // Turn counter clockwise
+ player->mo->angle -= delta;
+ }
+ }
+ else if (player->damagecount || player->poisoncount)
+ {
+ if (player->damagecount)
+ {
+ player->damagecount--;
+ }
+ else
+ {
+ player->poisoncount--;
+ }
+ }
+
+ if (player->cmd.buttons & BT_USE)
+ {
+ if (player == &players[consoleplayer])
+ {
+ I_SetPalette((byte *) W_CacheLumpName("PLAYPAL", PU_CACHE));
+ inv_ptr = 0;
+ curpos = 0;
+ newtorch = 0;
+ newtorchdelta = 0;
+ }
+ player->playerstate = PST_REBORN;
+ player->mo->special1.i = player->class;
+ if (player->mo->special1.i > 2)
+ {
+ player->mo->special1.i = 0;
+ }
+ // Let the mobj know the player has entered the reborn state. Some
+ // mobjs need to know when it's ok to remove themselves.
+ player->mo->special2.i = 666;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_MorphPlayerThink
+//
+//----------------------------------------------------------------------------
+
+void P_MorphPlayerThink(player_t * player)
+{
+ mobj_t *pmo;
+
+ if (player->morphTics & 15)
+ {
+ return;
+ }
+ pmo = player->mo;
+ if (!(pmo->momx + pmo->momy) && P_Random() < 64)
+ { // Snout sniff
+ P_SetPspriteNF(player, ps_weapon, S_SNOUTATK2);
+ S_StartSound(pmo, SFX_PIG_ACTIVE1); // snort
+ return;
+ }
+ if (P_Random() < 48)
+ {
+ if (P_Random() < 128)
+ {
+ S_StartSound(pmo, SFX_PIG_ACTIVE1);
+ }
+ else
+ {
+ S_StartSound(pmo, SFX_PIG_ACTIVE2);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_GetPlayerNum
+//
+//----------------------------------------------------------------------------
+
+int P_GetPlayerNum(player_t * player)
+{
+ int i;
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (player == &players[i])
+ {
+ return (i);
+ }
+ }
+ return (0);
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_UndoPlayerMorph
+//
+//----------------------------------------------------------------------------
+
+boolean P_UndoPlayerMorph(player_t * player)
+{
+ mobj_t *fog;
+ mobj_t *mo;
+ mobj_t *pmo;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ angle_t angle;
+ int playerNum;
+ weapontype_t weapon;
+ int oldFlags;
+ int oldFlags2;
+ int oldBeast;
+
+ pmo = player->mo;
+ x = pmo->x;
+ y = pmo->y;
+ z = pmo->z;
+ angle = pmo->angle;
+ weapon = pmo->special1.i;
+ oldFlags = pmo->flags;
+ oldFlags2 = pmo->flags2;
+ oldBeast = pmo->type;
+ P_SetMobjState(pmo, S_FREETARGMOBJ);
+ playerNum = P_GetPlayerNum(player);
+ switch (PlayerClass[playerNum])
+ {
+ case PCLASS_FIGHTER:
+ mo = P_SpawnMobj(x, y, z, MT_PLAYER_FIGHTER);
+ break;
+ case PCLASS_CLERIC:
+ mo = P_SpawnMobj(x, y, z, MT_PLAYER_CLERIC);
+ break;
+ case PCLASS_MAGE:
+ mo = P_SpawnMobj(x, y, z, MT_PLAYER_MAGE);
+ break;
+ default:
+ I_Error("P_UndoPlayerMorph: Unknown player class %d\n",
+ player->class);
+ return false;
+ }
+ if (P_TestMobjLocation(mo) == false)
+ { // Didn't fit
+ P_RemoveMobj(mo);
+ mo = P_SpawnMobj(x, y, z, oldBeast);
+ mo->angle = angle;
+ mo->health = player->health;
+ mo->special1.i = weapon;
+ mo->player = player;
+ mo->flags = oldFlags;
+ mo->flags2 = oldFlags2;
+ player->mo = mo;
+ player->morphTics = 2 * 35;
+ return (false);
+ }
+ if (player->class == PCLASS_FIGHTER)
+ {
+ // The first type should be blue, and the third should be the
+ // Fighter's original gold color
+ if (playerNum == 0)
+ {
+ mo->flags |= 2 << MF_TRANSSHIFT;
+ }
+ else if (playerNum != 2)
+ {
+ mo->flags |= playerNum << MF_TRANSSHIFT;
+ }
+ }
+ else if (playerNum)
+ { // Set color translation bits for player sprites
+ mo->flags |= playerNum << MF_TRANSSHIFT;
+ }
+ mo->angle = angle;
+ mo->player = player;
+ mo->reactiontime = 18;
+ if (oldFlags2 & MF2_FLY)
+ {
+ mo->flags2 |= MF2_FLY;
+ mo->flags |= MF_NOGRAVITY;
+ }
+ player->morphTics = 0;
+ player->health = mo->health = MAXHEALTH;
+ player->mo = mo;
+ player->class = PlayerClass[playerNum];
+ angle >>= ANGLETOFINESHIFT;
+ fog = P_SpawnMobj(x + 20 * finecosine[angle],
+ y + 20 * finesine[angle], z + TELEFOGHEIGHT, MT_TFOG);
+ S_StartSound(fog, SFX_TELEPORT);
+ P_PostMorphWeapon(player, weapon);
+ return (true);
+}
+
+
+//----------------------------------------------------------------------------
+//
+// PROC P_PlayerThink
+//
+//----------------------------------------------------------------------------
+
+void P_PlayerThink(player_t * player)
+{
+ ticcmd_t *cmd;
+ weapontype_t newweapon;
+ int floorType;
+ mobj_t *pmo;
+
+ // No-clip cheat
+ if (player->cheats & CF_NOCLIP)
+ {
+ player->mo->flags |= MF_NOCLIP;
+ }
+ else
+ {
+ player->mo->flags &= ~MF_NOCLIP;
+ }
+ cmd = &player->cmd;
+ if (player->mo->flags & MF_JUSTATTACKED)
+ { // Gauntlets attack auto forward motion
+ cmd->angleturn = 0;
+ cmd->forwardmove = 0xc800 / 512;
+ cmd->sidemove = 0;
+ player->mo->flags &= ~MF_JUSTATTACKED;
+ }
+// messageTics is above the rest of the counters so that messages will
+// go away, even in death.
+ player->messageTics--; // Can go negative
+ if (!player->messageTics || player->messageTics == -1)
+ { // Refresh the screen when a message goes away
+ player->ultimateMessage = false; // clear out any chat messages.
+ player->yellowMessage = false;
+ if (player == &players[consoleplayer])
+ {
+ BorderTopRefresh = true;
+ }
+ }
+ player->worldTimer++;
+ if (player->playerstate == PST_DEAD)
+ {
+ P_DeathThink(player);
+ return;
+ }
+ if (player->jumpTics)
+ {
+ player->jumpTics--;
+ }
+ if (player->morphTics)
+ {
+ P_MorphPlayerThink(player);
+ }
+ // Handle movement
+ if (player->mo->reactiontime)
+ { // Player is frozen
+ player->mo->reactiontime--;
+ }
+ else
+ {
+ P_MovePlayer(player);
+ pmo = player->mo;
+ if (player->powers[pw_speed] && !(leveltime & 1)
+ && P_AproxDistance(pmo->momx, pmo->momy) > 12 * FRACUNIT)
+ {
+ mobj_t *speedMo;
+ int playerNum;
+
+ speedMo = P_SpawnMobj(pmo->x, pmo->y, pmo->z, MT_PLAYER_SPEED);
+ if (speedMo)
+ {
+ speedMo->angle = pmo->angle;
+ playerNum = P_GetPlayerNum(player);
+ if (player->class == PCLASS_FIGHTER)
+ {
+ // The first type should be blue, and the
+ // third should be the Fighter's original gold color
+ if (playerNum == 0)
+ {
+ speedMo->flags |= 2 << MF_TRANSSHIFT;
+ }
+ else if (playerNum != 2)
+ {
+ speedMo->flags |= playerNum << MF_TRANSSHIFT;
+ }
+ }
+ else if (playerNum)
+ { // Set color translation bits for player sprites
+ speedMo->flags |= playerNum << MF_TRANSSHIFT;
+ }
+ speedMo->target = pmo;
+ speedMo->special1.i = player->class;
+ if (speedMo->special1.i > 2)
+ {
+ speedMo->special1.i = 0;
+ }
+ speedMo->sprite = pmo->sprite;
+ speedMo->floorclip = pmo->floorclip;
+ if (player == &players[consoleplayer])
+ {
+ speedMo->flags2 |= MF2_DONTDRAW;
+ }
+ }
+ }
+ }
+ P_CalcHeight(player);
+ if (player->mo->subsector->sector->special)
+ {
+ P_PlayerInSpecialSector(player);
+ }
+ if ((floorType = P_GetThingFloorType(player->mo)) != FLOOR_SOLID)
+ {
+ P_PlayerOnSpecialFlat(player, floorType);
+ }
+ switch (player->class)
+ {
+ case PCLASS_FIGHTER:
+ if (player->mo->momz <= -35 * FRACUNIT
+ && player->mo->momz >= -40 * FRACUNIT && !player->morphTics
+ && !S_GetSoundPlayingInfo(player->mo,
+ SFX_PLAYER_FIGHTER_FALLING_SCREAM))
+ {
+ S_StartSound(player->mo, SFX_PLAYER_FIGHTER_FALLING_SCREAM);
+ }
+ break;
+ case PCLASS_CLERIC:
+ if (player->mo->momz <= -35 * FRACUNIT
+ && player->mo->momz >= -40 * FRACUNIT && !player->morphTics
+ && !S_GetSoundPlayingInfo(player->mo,
+ SFX_PLAYER_CLERIC_FALLING_SCREAM))
+ {
+ S_StartSound(player->mo, SFX_PLAYER_CLERIC_FALLING_SCREAM);
+ }
+ break;
+ case PCLASS_MAGE:
+ if (player->mo->momz <= -35 * FRACUNIT
+ && player->mo->momz >= -40 * FRACUNIT && !player->morphTics
+ && !S_GetSoundPlayingInfo(player->mo,
+ SFX_PLAYER_MAGE_FALLING_SCREAM))
+ {
+ S_StartSound(player->mo, SFX_PLAYER_MAGE_FALLING_SCREAM);
+ }
+ break;
+ default:
+ break;
+ }
+ if (cmd->arti)
+ { // Use an artifact
+ if ((cmd->arti & AFLAG_JUMP) && onground && !player->jumpTics)
+ {
+ if (player->morphTics)
+ {
+ player->mo->momz = 6 * FRACUNIT;
+ }
+ else
+ {
+ player->mo->momz = 9 * FRACUNIT;
+ }
+ player->mo->flags2 &= ~MF2_ONMOBJ;
+ player->jumpTics = 18;
+ }
+ else if (cmd->arti & AFLAG_SUICIDE)
+ {
+ P_DamageMobj(player->mo, NULL, NULL, 10000);
+ }
+ if (cmd->arti == NUMARTIFACTS)
+ { // use one of each artifact (except puzzle artifacts)
+ int i;
+
+ for (i = 1; i < arti_firstpuzzitem; i++)
+ {
+ P_PlayerUseArtifact(player, i);
+ }
+ }
+ else
+ {
+ P_PlayerUseArtifact(player, cmd->arti & AFLAG_MASK);
+ }
+ }
+ // Check for weapon change
+ if (cmd->buttons & BT_SPECIAL)
+ { // A special event has no other buttons
+ cmd->buttons = 0;
+ }
+ if (cmd->buttons & BT_CHANGE && !player->morphTics)
+ {
+ // The actual changing of the weapon is done when the weapon
+ // psprite can do it (A_WeaponReady), so it doesn't happen in
+ // the middle of an attack.
+ newweapon = (cmd->buttons & BT_WEAPONMASK) >> BT_WEAPONSHIFT;
+ if (player->weaponowned[newweapon]
+ && newweapon != player->readyweapon)
+ {
+ player->pendingweapon = newweapon;
+ }
+ }
+ // Check for use
+ if (cmd->buttons & BT_USE)
+ {
+ if (!player->usedown)
+ {
+ P_UseLines(player);
+ player->usedown = true;
+ }
+ }
+ else
+ {
+ player->usedown = false;
+ }
+ // Morph counter
+ if (player->morphTics)
+ {
+ if (!--player->morphTics)
+ { // Attempt to undo the pig
+ P_UndoPlayerMorph(player);
+ }
+ }
+ // Cycle psprites
+ P_MovePsprites(player);
+ // Other Counters
+ if (player->powers[pw_invulnerability])
+ {
+ if (player->class == PCLASS_CLERIC)
+ {
+ if (!(leveltime & 7) && player->mo->flags & MF_SHADOW
+ && !(player->mo->flags2 & MF2_DONTDRAW))
+ {
+ player->mo->flags &= ~MF_SHADOW;
+ if (!(player->mo->flags & MF_ALTSHADOW))
+ {
+ player->mo->flags2 |= MF2_DONTDRAW | MF2_NONSHOOTABLE;
+ }
+ }
+ if (!(leveltime & 31))
+ {
+ if (player->mo->flags2 & MF2_DONTDRAW)
+ {
+ if (!(player->mo->flags & MF_SHADOW))
+ {
+ player->mo->flags |= MF_SHADOW | MF_ALTSHADOW;
+ }
+ else
+ {
+ player->mo->flags2 &=
+ ~(MF2_DONTDRAW | MF2_NONSHOOTABLE);
+ }
+ }
+ else
+ {
+ player->mo->flags |= MF_SHADOW;
+ player->mo->flags &= ~MF_ALTSHADOW;
+ }
+ }
+ }
+ if (!(--player->powers[pw_invulnerability]))
+ {
+ player->mo->flags2 &= ~(MF2_INVULNERABLE | MF2_REFLECTIVE);
+ if (player->class == PCLASS_CLERIC)
+ {
+ player->mo->flags2 &= ~(MF2_DONTDRAW | MF2_NONSHOOTABLE);
+ player->mo->flags &= ~(MF_SHADOW | MF_ALTSHADOW);
+ }
+ }
+ }
+ if (player->powers[pw_minotaur])
+ {
+ player->powers[pw_minotaur]--;
+ }
+ if (player->powers[pw_infrared])
+ {
+ player->powers[pw_infrared]--;
+ }
+ if (player->powers[pw_flight] && netgame)
+ {
+ if (!--player->powers[pw_flight])
+ {
+ if (player->mo->z != player->mo->floorz)
+ {
+ // haleyjd: removed externdriver crap
+ player->centering = true;
+ }
+ player->mo->flags2 &= ~MF2_FLY;
+ player->mo->flags &= ~MF_NOGRAVITY;
+ BorderTopRefresh = true; //make sure the sprite's cleared out
+ }
+ }
+ if (player->powers[pw_speed])
+ {
+ player->powers[pw_speed]--;
+ }
+ if (player->damagecount)
+ {
+ player->damagecount--;
+ }
+ if (player->bonuscount)
+ {
+ player->bonuscount--;
+ }
+ if (player->poisoncount && !(leveltime & 15))
+ {
+ player->poisoncount -= 5;
+ if (player->poisoncount < 0)
+ {
+ player->poisoncount = 0;
+ }
+ P_PoisonDamage(player, player->poisoner, 1, true);
+ }
+ // Colormaps
+// if(player->powers[pw_invulnerability])
+// {
+// if(player->powers[pw_invulnerability] > BLINKTHRESHOLD
+// || (player->powers[pw_invulnerability]&8))
+// {
+// player->fixedcolormap = INVERSECOLORMAP;
+// }
+// else
+// {
+// player->fixedcolormap = 0;
+// }
+// }
+// else
+ if (player->powers[pw_infrared])
+ {
+ if (player->powers[pw_infrared] <= BLINKTHRESHOLD)
+ {
+ if (player->powers[pw_infrared] & 8)
+ {
+ player->fixedcolormap = 0;
+ }
+ else
+ {
+ player->fixedcolormap = 1;
+ }
+ }
+ else if (!(leveltime & 16) && player == &players[consoleplayer])
+ {
+ if (newtorch)
+ {
+ if (player->fixedcolormap + newtorchdelta > 7
+ || player->fixedcolormap + newtorchdelta < 1
+ || newtorch == player->fixedcolormap)
+ {
+ newtorch = 0;
+ }
+ else
+ {
+ player->fixedcolormap += newtorchdelta;
+ }
+ }
+ else
+ {
+ newtorch = (M_Random() & 7) + 1;
+ newtorchdelta = (newtorch == player->fixedcolormap) ?
+ 0 : ((newtorch > player->fixedcolormap) ? 1 : -1);
+ }
+ }
+ }
+ else
+ {
+ player->fixedcolormap = 0;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_ArtiTele
+//
+//----------------------------------------------------------------------------
+
+void P_ArtiTele(player_t * player)
+{
+ int i;
+ int selections;
+ fixed_t destX;
+ fixed_t destY;
+ angle_t destAngle;
+
+ if (deathmatch)
+ {
+ selections = deathmatch_p - deathmatchstarts;
+ i = P_Random() % selections;
+ destX = deathmatchstarts[i].x << FRACBITS;
+ destY = deathmatchstarts[i].y << FRACBITS;
+ destAngle = ANG45 * (deathmatchstarts[i].angle / 45);
+ }
+ else
+ {
+ destX = playerstarts[0][0].x << FRACBITS;
+ destY = playerstarts[0][0].y << FRACBITS;
+ destAngle = ANG45 * (playerstarts[0][0].angle / 45);
+ }
+ P_Teleport(player->mo, destX, destY, destAngle, true);
+ if (player->morphTics)
+ { // Teleporting away will undo any morph effects (pig)
+ P_UndoPlayerMorph(player);
+ }
+ //S_StartSound(NULL, sfx_wpnup); // Full volume laugh
+}
+
+
+//----------------------------------------------------------------------------
+//
+// PROC P_ArtiTeleportOther
+//
+//----------------------------------------------------------------------------
+
+void P_ArtiTeleportOther(player_t * player)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnPlayerMissile(player->mo, MT_TELOTHER_FX1);
+ if (mo)
+ {
+ mo->target = player->mo;
+ }
+}
+
+
+void P_TeleportToPlayerStarts(mobj_t * victim)
+{
+ int i, selections = 0;
+ fixed_t destX, destY;
+ angle_t destAngle;
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (!playeringame[i])
+ continue;
+ selections++;
+ }
+ i = P_Random() % selections;
+ destX = playerstarts[0][i].x << FRACBITS;
+ destY = playerstarts[0][i].y << FRACBITS;
+ destAngle = ANG45 * (playerstarts[0][i].angle / 45);
+ P_Teleport(victim, destX, destY, destAngle, true);
+ //S_StartSound(NULL, sfx_wpnup); // Full volume laugh
+}
+
+void P_TeleportToDeathmatchStarts(mobj_t * victim)
+{
+ int i, selections;
+ fixed_t destX, destY;
+ angle_t destAngle;
+
+ selections = deathmatch_p - deathmatchstarts;
+ if (selections)
+ {
+ i = P_Random() % selections;
+ destX = deathmatchstarts[i].x << FRACBITS;
+ destY = deathmatchstarts[i].y << FRACBITS;
+ destAngle = ANG45 * (deathmatchstarts[i].angle / 45);
+ P_Teleport(victim, destX, destY, destAngle, true);
+ //S_StartSound(NULL, sfx_wpnup); // Full volume laugh
+ }
+ else
+ {
+ P_TeleportToPlayerStarts(victim);
+ }
+}
+
+
+
+//----------------------------------------------------------------------------
+//
+// PROC P_TeleportOther
+//
+//----------------------------------------------------------------------------
+void P_TeleportOther(mobj_t * victim)
+{
+ if (victim->player)
+ {
+ if (deathmatch)
+ P_TeleportToDeathmatchStarts(victim);
+ else
+ P_TeleportToPlayerStarts(victim);
+ }
+ else
+ {
+ // If death action, run it upon teleport
+ if (victim->flags & MF_COUNTKILL && victim->special)
+ {
+ P_RemoveMobjFromTIDList(victim);
+ P_ExecuteLineSpecial(victim->special, victim->args,
+ NULL, 0, victim);
+ victim->special = 0;
+ }
+
+ // Send all monsters to deathmatch spots
+ P_TeleportToDeathmatchStarts(victim);
+ }
+}
+
+
+
+#define BLAST_RADIUS_DIST 255*FRACUNIT
+#define BLAST_SPEED 20*FRACUNIT
+#define BLAST_FULLSTRENGTH 255
+
+void ResetBlasted(mobj_t * mo)
+{
+ mo->flags2 &= ~MF2_BLASTED;
+ if (!(mo->flags & MF_ICECORPSE))
+ {
+ mo->flags2 &= ~MF2_SLIDE;
+ }
+}
+
+void P_BlastMobj(mobj_t * source, mobj_t * victim, fixed_t strength)
+{
+ angle_t angle, ang;
+ mobj_t *mo;
+ fixed_t x, y, z;
+
+ angle = R_PointToAngle2(source->x, source->y, victim->x, victim->y);
+ angle >>= ANGLETOFINESHIFT;
+ if (strength < BLAST_FULLSTRENGTH)
+ {
+ victim->momx = FixedMul(strength, finecosine[angle]);
+ victim->momy = FixedMul(strength, finesine[angle]);
+ if (victim->player)
+ {
+ // Players handled automatically
+ }
+ else
+ {
+ victim->flags2 |= MF2_SLIDE;
+ victim->flags2 |= MF2_BLASTED;
+ }
+ }
+ else // full strength blast from artifact
+ {
+ if (victim->flags & MF_MISSILE)
+ {
+ switch (victim->type)
+ {
+ case MT_SORCBALL1: // don't blast sorcerer balls
+ case MT_SORCBALL2:
+ case MT_SORCBALL3:
+ return;
+ break;
+ case MT_MSTAFF_FX2: // Reflect to originator
+ victim->special1.m = victim->target;
+ victim->target = source;
+ break;
+ default:
+ break;
+ }
+ }
+ if (victim->type == MT_HOLY_FX)
+ {
+ if (victim->special1.m == source)
+ {
+ victim->special1.m = victim->target;
+ victim->target = source;
+ }
+ }
+ victim->momx = FixedMul(BLAST_SPEED, finecosine[angle]);
+ victim->momy = FixedMul(BLAST_SPEED, finesine[angle]);
+
+ // Spawn blast puff
+ ang = R_PointToAngle2(victim->x, victim->y, source->x, source->y);
+ ang >>= ANGLETOFINESHIFT;
+ x = victim->x + FixedMul(victim->radius + FRACUNIT, finecosine[ang]);
+ y = victim->y + FixedMul(victim->radius + FRACUNIT, finesine[ang]);
+ z = victim->z - victim->floorclip + (victim->height >> 1);
+ mo = P_SpawnMobj(x, y, z, MT_BLASTEFFECT);
+ if (mo)
+ {
+ mo->momx = victim->momx;
+ mo->momy = victim->momy;
+ }
+
+ if (victim->flags & MF_MISSILE)
+ {
+ victim->momz = 8 * FRACUNIT;
+ mo->momz = victim->momz;
+ }
+ else
+ {
+ victim->momz = (1000 / victim->info->mass) << FRACBITS;
+ }
+ if (victim->player)
+ {
+ // Players handled automatically
+ }
+ else
+ {
+ victim->flags2 |= MF2_SLIDE;
+ victim->flags2 |= MF2_BLASTED;
+ }
+ }
+}
+
+
+// Blast all mobj things away
+void P_BlastRadius(player_t * player)
+{
+ mobj_t *mo;
+ mobj_t *pmo = player->mo;
+ thinker_t *think;
+ fixed_t dist;
+
+ S_StartSound(pmo, SFX_ARTIFACT_BLAST);
+ P_NoiseAlert(player->mo, player->mo);
+
+ for (think = thinkercap.next; think != &thinkercap; think = think->next)
+ {
+ if (think->function != P_MobjThinker)
+ { // Not a mobj thinker
+ continue;
+ }
+ mo = (mobj_t *) think;
+ if ((mo == pmo) || (mo->flags2 & MF2_BOSS))
+ { // Not a valid monster
+ continue;
+ }
+ if ((mo->type == MT_POISONCLOUD) || // poison cloud
+ (mo->type == MT_HOLY_FX) || // holy fx
+ (mo->flags & MF_ICECORPSE)) // frozen corpse
+ {
+ // Let these special cases go
+ }
+ else if ((mo->flags & MF_COUNTKILL) && (mo->health <= 0))
+ {
+ continue;
+ }
+ else if (!(mo->flags & MF_COUNTKILL) &&
+ !(mo->player) && !(mo->flags & MF_MISSILE))
+ { // Must be monster, player, or missile
+ continue;
+ }
+ if (mo->flags2 & MF2_DORMANT)
+ {
+ continue; // no dormant creatures
+ }
+ if ((mo->type == MT_WRAITHB) && (mo->flags2 & MF2_DONTDRAW))
+ {
+ continue; // no underground wraiths
+ }
+ if ((mo->type == MT_SPLASHBASE) || (mo->type == MT_SPLASH))
+ {
+ continue;
+ }
+ if (mo->type == MT_SERPENT || mo->type == MT_SERPENTLEADER)
+ {
+ continue;
+ }
+ dist = P_AproxDistance(pmo->x - mo->x, pmo->y - mo->y);
+ if (dist > BLAST_RADIUS_DIST)
+ { // Out of range
+ continue;
+ }
+ P_BlastMobj(pmo, mo, BLAST_FULLSTRENGTH);
+ }
+}
+
+
+#define HEAL_RADIUS_DIST 255*FRACUNIT
+
+// Do class specific effect for everyone in radius
+boolean P_HealRadius(player_t * player)
+{
+ mobj_t *mo;
+ mobj_t *pmo = player->mo;
+ thinker_t *think;
+ fixed_t dist;
+ int effective = false;
+ int amount;
+
+ for (think = thinkercap.next; think != &thinkercap; think = think->next)
+ {
+ if (think->function != P_MobjThinker)
+ { // Not a mobj thinker
+ continue;
+ }
+ mo = (mobj_t *) think;
+
+ if (!mo->player)
+ continue;
+ if (mo->health <= 0)
+ continue;
+ dist = P_AproxDistance(pmo->x - mo->x, pmo->y - mo->y);
+ if (dist > HEAL_RADIUS_DIST)
+ { // Out of range
+ continue;
+ }
+
+ switch (player->class)
+ {
+ case PCLASS_FIGHTER: // Radius armor boost
+ if ((P_GiveArmor(mo->player, ARMOR_ARMOR, 1)) ||
+ (P_GiveArmor(mo->player, ARMOR_SHIELD, 1)) ||
+ (P_GiveArmor(mo->player, ARMOR_HELMET, 1)) ||
+ (P_GiveArmor(mo->player, ARMOR_AMULET, 1)))
+ {
+ effective = true;
+ S_StartSound(mo, SFX_MYSTICINCANT);
+ }
+ break;
+ case PCLASS_CLERIC: // Radius heal
+ amount = 50 + (P_Random() % 50);
+ if (P_GiveBody(mo->player, amount))
+ {
+ effective = true;
+ S_StartSound(mo, SFX_MYSTICINCANT);
+ }
+ break;
+ case PCLASS_MAGE: // Radius mana boost
+ amount = 50 + (P_Random() % 50);
+ if ((P_GiveMana(mo->player, MANA_1, amount)) ||
+ (P_GiveMana(mo->player, MANA_2, amount)))
+ {
+ effective = true;
+ S_StartSound(mo, SFX_MYSTICINCANT);
+ }
+ break;
+ case PCLASS_PIG:
+ default:
+ break;
+ }
+ }
+ return (effective);
+}
+
+
+//----------------------------------------------------------------------------
+//
+// PROC P_PlayerNextArtifact
+//
+//----------------------------------------------------------------------------
+
+void P_PlayerNextArtifact(player_t * player)
+{
+ if (player == &players[consoleplayer])
+ {
+ inv_ptr--;
+ if (inv_ptr < 6)
+ {
+ curpos--;
+ if (curpos < 0)
+ {
+ curpos = 0;
+ }
+ }
+ if (inv_ptr < 0)
+ {
+ inv_ptr = player->inventorySlotNum - 1;
+ if (inv_ptr < 6)
+ {
+ curpos = inv_ptr;
+ }
+ else
+ {
+ curpos = 6;
+ }
+ }
+ player->readyArtifact = player->inventory[inv_ptr].type;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_PlayerRemoveArtifact
+//
+//----------------------------------------------------------------------------
+
+void P_PlayerRemoveArtifact(player_t * player, int slot)
+{
+ int i;
+
+ player->artifactCount--;
+ if (!(--player->inventory[slot].count))
+ { // Used last of a type - compact the artifact list
+ player->readyArtifact = arti_none;
+ player->inventory[slot].type = arti_none;
+ for (i = slot + 1; i < player->inventorySlotNum; i++)
+ {
+ player->inventory[i - 1] = player->inventory[i];
+ }
+ player->inventorySlotNum--;
+ if (player == &players[consoleplayer])
+ { // Set position markers and get next readyArtifact
+ inv_ptr--;
+ if (inv_ptr < 6)
+ {
+ curpos--;
+ if (curpos < 0)
+ {
+ curpos = 0;
+ }
+ }
+ if (inv_ptr >= player->inventorySlotNum)
+ {
+ inv_ptr = player->inventorySlotNum - 1;
+ }
+ if (inv_ptr < 0)
+ {
+ inv_ptr = 0;
+ }
+ player->readyArtifact = player->inventory[inv_ptr].type;
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_PlayerUseArtifact
+//
+//----------------------------------------------------------------------------
+
+void P_PlayerUseArtifact(player_t * player, artitype_t arti)
+{
+ int i;
+
+ for (i = 0; i < player->inventorySlotNum; i++)
+ {
+ if (player->inventory[i].type == arti)
+ { // Found match - try to use
+ if (P_UseArtifact(player, arti))
+ { // Artifact was used - remove it from inventory
+ P_PlayerRemoveArtifact(player, i);
+ if (player == &players[consoleplayer])
+ {
+ if (arti < arti_firstpuzzitem)
+ {
+ S_StartSound(NULL, SFX_ARTIFACT_USE);
+ }
+ else
+ {
+ S_StartSound(NULL, SFX_PUZZLE_SUCCESS);
+ }
+ ArtifactFlash = 4;
+ }
+ }
+ else if (arti < arti_firstpuzzitem)
+ { // Unable to use artifact, advance pointer
+ P_PlayerNextArtifact(player);
+ }
+ break;
+ }
+ }
+}
+
+//==========================================================================
+//
+// P_UseArtifact
+//
+// Returns true if the artifact was used.
+//
+//==========================================================================
+
+boolean P_UseArtifact(player_t * player, artitype_t arti)
+{
+ mobj_t *mo;
+ angle_t angle;
+ int i;
+ int count;
+
+ switch (arti)
+ {
+ case arti_invulnerability:
+ if (!P_GivePower(player, pw_invulnerability))
+ {
+ return (false);
+ }
+ break;
+ case arti_health:
+ if (!P_GiveBody(player, 25))
+ {
+ return (false);
+ }
+ break;
+ case arti_superhealth:
+ if (!P_GiveBody(player, 100))
+ {
+ return (false);
+ }
+ break;
+ case arti_healingradius:
+ if (!P_HealRadius(player))
+ {
+ return (false);
+ }
+ break;
+ case arti_torch:
+ if (!P_GivePower(player, pw_infrared))
+ {
+ return (false);
+ }
+ break;
+ case arti_egg:
+ mo = player->mo;
+ P_SpawnPlayerMissile(mo, MT_EGGFX);
+ P_SPMAngle(mo, MT_EGGFX, mo->angle - (ANG45 / 6));
+ P_SPMAngle(mo, MT_EGGFX, mo->angle + (ANG45 / 6));
+ P_SPMAngle(mo, MT_EGGFX, mo->angle - (ANG45 / 3));
+ P_SPMAngle(mo, MT_EGGFX, mo->angle + (ANG45 / 3));
+ break;
+ case arti_fly:
+ if (!P_GivePower(player, pw_flight))
+ {
+ return (false);
+ }
+ if (player->mo->momz <= -35 * FRACUNIT)
+ { // stop falling scream
+ S_StopSound(player->mo);
+ }
+ break;
+ case arti_summon:
+ mo = P_SpawnPlayerMissile(player->mo, MT_SUMMON_FX);
+ if (mo)
+ {
+ mo->target = player->mo;
+ mo->special1.m = (player->mo);
+ mo->momz = 5 * FRACUNIT;
+ }
+ break;
+ case arti_teleport:
+ P_ArtiTele(player);
+ break;
+ case arti_teleportother:
+ P_ArtiTeleportOther(player);
+ break;
+ case arti_poisonbag:
+ angle = player->mo->angle >> ANGLETOFINESHIFT;
+ if (player->class == PCLASS_CLERIC)
+ {
+ mo = P_SpawnMobj(player->mo->x + 16 * finecosine[angle],
+ player->mo->y + 24 * finesine[angle],
+ player->mo->z - player->mo->floorclip +
+ 8 * FRACUNIT, MT_POISONBAG);
+ if (mo)
+ {
+ mo->target = player->mo;
+ }
+ }
+ else if (player->class == PCLASS_MAGE)
+ {
+ mo = P_SpawnMobj(player->mo->x + 16 * finecosine[angle],
+ player->mo->y + 24 * finesine[angle],
+ player->mo->z - player->mo->floorclip +
+ 8 * FRACUNIT, MT_FIREBOMB);
+ if (mo)
+ {
+ mo->target = player->mo;
+ }
+ }
+ else // PCLASS_FIGHTER, obviously (also pig, not so obviously)
+ {
+ mo = P_SpawnMobj(player->mo->x, player->mo->y,
+ player->mo->z - player->mo->floorclip +
+ 35 * FRACUNIT, MT_THROWINGBOMB);
+ if (mo)
+ {
+ mo->angle =
+ player->mo->angle + (((P_Random() & 7) - 4) << 24);
+ mo->momz =
+ 4 * FRACUNIT + ((player->lookdir) << (FRACBITS - 4));
+ mo->z += player->lookdir << (FRACBITS - 4);
+ P_ThrustMobj(mo, mo->angle, mo->info->speed);
+ mo->momx += player->mo->momx >> 1;
+ mo->momy += player->mo->momy >> 1;
+ mo->target = player->mo;
+ mo->tics -= P_Random() & 3;
+ P_CheckMissileSpawn(mo);
+ }
+ }
+ break;
+ case arti_speed:
+ if (!P_GivePower(player, pw_speed))
+ {
+ return (false);
+ }
+ break;
+ case arti_boostmana:
+ if (!P_GiveMana(player, MANA_1, MAX_MANA))
+ {
+ if (!P_GiveMana(player, MANA_2, MAX_MANA))
+ {
+ return false;
+ }
+
+ }
+ else
+ {
+ P_GiveMana(player, MANA_2, MAX_MANA);
+ }
+ break;
+ case arti_boostarmor:
+ count = 0;
+
+ for (i = 0; i < NUMARMOR; i++)
+ {
+ count += P_GiveArmor(player, i, 1); // 1 point per armor type
+ }
+ if (!count)
+ {
+ return false;
+ }
+ break;
+ case arti_blastradius:
+ P_BlastRadius(player);
+ break;
+
+ case arti_puzzskull:
+ case arti_puzzgembig:
+ case arti_puzzgemred:
+ case arti_puzzgemgreen1:
+ case arti_puzzgemgreen2:
+ case arti_puzzgemblue1:
+ case arti_puzzgemblue2:
+ case arti_puzzbook1:
+ case arti_puzzbook2:
+ case arti_puzzskull2:
+ case arti_puzzfweapon:
+ case arti_puzzcweapon:
+ case arti_puzzmweapon:
+ case arti_puzzgear1:
+ case arti_puzzgear2:
+ case arti_puzzgear3:
+ case arti_puzzgear4:
+ if (P_UsePuzzleItem(player, arti - arti_firstpuzzitem))
+ {
+ return true;
+ }
+ else
+ {
+ P_SetYellowMessage(player, TXT_USEPUZZLEFAILED, false);
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+//============================================================================
+//
+// A_SpeedFade
+//
+//============================================================================
+
+void A_SpeedFade(mobj_t * actor)
+{
+ actor->flags |= MF_SHADOW;
+ actor->flags &= ~MF_ALTSHADOW;
+ actor->sprite = actor->target->sprite;
+}
diff --git a/src/hexen/po_man.c b/src/hexen/po_man.c
new file mode 100644
index 00000000..196f20d3
--- /dev/null
+++ b/src/hexen/po_man.c
@@ -0,0 +1,1509 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2def.h"
+#include "i_system.h"
+#include "m_bbox.h"
+#include "i_swap.h"
+#include "p_local.h"
+#include "r_local.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define PO_MAXPOLYSEGS 64
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static polyobj_t *GetPolyobj(int polyNum);
+static int GetPolyobjMirror(int poly);
+static void ThrustMobj(mobj_t * mobj, seg_t * seg, polyobj_t * po);
+static void UpdateSegBBox(seg_t * seg);
+static void RotatePt(int an, fixed_t * x, fixed_t * y, fixed_t startSpotX,
+ fixed_t startSpotY);
+static void UnLinkPolyobj(polyobj_t * po);
+static void LinkPolyobj(polyobj_t * po);
+static boolean CheckMobjBlocking(seg_t * seg, polyobj_t * po);
+static void InitBlockMap(void);
+static void IterFindPolySegs(int x, int y, seg_t ** segList);
+static void SpawnPolyobj(int index, int tag, boolean crush);
+static void TranslateToStartSpot(int tag, int originX, int originY);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+polyblock_t **PolyBlockMap;
+polyobj_t *polyobjs; // list of all poly-objects on the level
+int po_NumPolyobjs;
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static int PolySegCount;
+static fixed_t PolyStartX;
+static fixed_t PolyStartY;
+
+// CODE --------------------------------------------------------------------
+
+// ===== Polyobj Event Code =====
+
+//==========================================================================
+//
+// T_RotatePoly
+//
+//==========================================================================
+
+void T_RotatePoly(polyevent_t * pe)
+{
+ int absSpeed;
+ polyobj_t *poly;
+
+ if (PO_RotatePolyobj(pe->polyobj, pe->speed))
+ {
+ absSpeed = abs(pe->speed);
+
+ if (pe->dist == -1)
+ { // perpetual polyobj
+ return;
+ }
+ pe->dist -= absSpeed;
+ if (pe->dist <= 0)
+ {
+ poly = GetPolyobj(pe->polyobj);
+ if (poly->specialdata == pe)
+ {
+ poly->specialdata = NULL;
+ }
+ SN_StopSequence((mobj_t *) & poly->startSpot);
+ P_PolyobjFinished(poly->tag);
+ P_RemoveThinker(&pe->thinker);
+ }
+ if (pe->dist < absSpeed)
+ {
+ pe->speed = pe->dist * (pe->speed < 0 ? -1 : 1);
+ }
+ }
+}
+
+//==========================================================================
+//
+// EV_RotatePoly
+//
+//==========================================================================
+
+boolean EV_RotatePoly(line_t * line, byte * args, int direction, boolean
+ overRide)
+{
+ int mirror;
+ int polyNum;
+ polyevent_t *pe;
+ polyobj_t *poly;
+
+ polyNum = args[0];
+ poly = GetPolyobj(polyNum);
+ if (poly != NULL)
+ {
+ if (poly->specialdata && !overRide)
+ { // poly is already moving
+ return false;
+ }
+ }
+ else
+ {
+ I_Error("EV_RotatePoly: Invalid polyobj num: %d\n", polyNum);
+ }
+ pe = Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, 0);
+ P_AddThinker(&pe->thinker);
+ pe->thinker.function = T_RotatePoly;
+ pe->polyobj = polyNum;
+ if (args[2])
+ {
+ if (args[2] == 255)
+ {
+ pe->dist = -1;
+ }
+ else
+ {
+ pe->dist = args[2] * (ANG90 / 64); // Angle
+ }
+ }
+ else
+ {
+ pe->dist = ANG_MAX - 1;
+ }
+ pe->speed = (args[1] * direction * (ANG90 / 64)) >> 3;
+ poly->specialdata = pe;
+ SN_StartSequence((mobj_t *) & poly->startSpot, SEQ_DOOR_STONE +
+ poly->seqType);
+
+ while ((mirror = GetPolyobjMirror(polyNum)) != 0)
+ {
+ poly = GetPolyobj(mirror);
+ if (poly && poly->specialdata && !overRide)
+ { // mirroring poly is already in motion
+ break;
+ }
+ pe = Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, 0);
+ P_AddThinker(&pe->thinker);
+ pe->thinker.function = T_RotatePoly;
+ poly->specialdata = pe;
+ pe->polyobj = mirror;
+ if (args[2])
+ {
+ if (args[2] == 255)
+ {
+ pe->dist = -1;
+ }
+ else
+ {
+ pe->dist = args[2] * (ANG90 / 64); // Angle
+ }
+ }
+ else
+ {
+ pe->dist = ANG_MAX - 1;
+ }
+ poly = GetPolyobj(polyNum);
+ if (poly != NULL)
+ {
+ poly->specialdata = pe;
+ }
+ else
+ {
+ I_Error("EV_RotatePoly: Invalid polyobj num: %d\n", polyNum);
+ }
+ direction = -direction;
+ pe->speed = (args[1] * direction * (ANG90 / 64)) >> 3;
+ polyNum = mirror;
+ SN_StartSequence((mobj_t *) & poly->startSpot, SEQ_DOOR_STONE +
+ poly->seqType);
+ }
+ return true;
+}
+
+//==========================================================================
+//
+// T_MovePoly
+//
+//==========================================================================
+
+void T_MovePoly(polyevent_t * pe)
+{
+ int absSpeed;
+ polyobj_t *poly;
+
+ if (PO_MovePolyobj(pe->polyobj, pe->xSpeed, pe->ySpeed))
+ {
+ absSpeed = abs(pe->speed);
+ pe->dist -= absSpeed;
+ if (pe->dist <= 0)
+ {
+ poly = GetPolyobj(pe->polyobj);
+ if (poly->specialdata == pe)
+ {
+ poly->specialdata = NULL;
+ }
+ SN_StopSequence((mobj_t *) & poly->startSpot);
+ P_PolyobjFinished(poly->tag);
+ P_RemoveThinker(&pe->thinker);
+ }
+ if (pe->dist < absSpeed)
+ {
+ pe->speed = pe->dist * (pe->speed < 0 ? -1 : 1);
+ pe->xSpeed = FixedMul(pe->speed, finecosine[pe->angle]);
+ pe->ySpeed = FixedMul(pe->speed, finesine[pe->angle]);
+ }
+ }
+}
+
+//==========================================================================
+//
+// EV_MovePoly
+//
+//==========================================================================
+
+boolean EV_MovePoly(line_t * line, byte * args, boolean timesEight, boolean
+ overRide)
+{
+ int mirror;
+ int polyNum;
+ polyevent_t *pe;
+ polyobj_t *poly;
+ angle_t an;
+
+ polyNum = args[0];
+ poly = GetPolyobj(polyNum);
+ if (poly != NULL)
+ {
+ if (poly->specialdata && !overRide)
+ { // poly is already moving
+ return false;
+ }
+ }
+ else
+ {
+ I_Error("EV_MovePoly: Invalid polyobj num: %d\n", polyNum);
+ }
+ pe = Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, 0);
+ P_AddThinker(&pe->thinker);
+ pe->thinker.function = T_MovePoly;
+ pe->polyobj = polyNum;
+ if (timesEight)
+ {
+ pe->dist = args[3] * 8 * FRACUNIT;
+ }
+ else
+ {
+ pe->dist = args[3] * FRACUNIT; // Distance
+ }
+ pe->speed = args[1] * (FRACUNIT / 8);
+ poly->specialdata = pe;
+
+ an = args[2] * (ANG90 / 64);
+
+ pe->angle = an >> ANGLETOFINESHIFT;
+ pe->xSpeed = FixedMul(pe->speed, finecosine[pe->angle]);
+ pe->ySpeed = FixedMul(pe->speed, finesine[pe->angle]);
+ SN_StartSequence((mobj_t *) & poly->startSpot, SEQ_DOOR_STONE +
+ poly->seqType);
+
+ while ((mirror = GetPolyobjMirror(polyNum)) != 0)
+ {
+ poly = GetPolyobj(mirror);
+ if (poly && poly->specialdata && !overRide)
+ { // mirroring poly is already in motion
+ break;
+ }
+ pe = Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, 0);
+ P_AddThinker(&pe->thinker);
+ pe->thinker.function = T_MovePoly;
+ pe->polyobj = mirror;
+ poly->specialdata = pe;
+ if (timesEight)
+ {
+ pe->dist = args[3] * 8 * FRACUNIT;
+ }
+ else
+ {
+ pe->dist = args[3] * FRACUNIT; // Distance
+ }
+ pe->speed = args[1] * (FRACUNIT / 8);
+ an = an + ANG180; // reverse the angle
+ pe->angle = an >> ANGLETOFINESHIFT;
+ pe->xSpeed = FixedMul(pe->speed, finecosine[pe->angle]);
+ pe->ySpeed = FixedMul(pe->speed, finesine[pe->angle]);
+ polyNum = mirror;
+ SN_StartSequence((mobj_t *) & poly->startSpot, SEQ_DOOR_STONE +
+ poly->seqType);
+ }
+ return true;
+}
+
+//==========================================================================
+//
+// T_PolyDoor
+//
+//==========================================================================
+
+void T_PolyDoor(polydoor_t * pd)
+{
+ int absSpeed;
+ polyobj_t *poly;
+
+ if (pd->tics)
+ {
+ if (!--pd->tics)
+ {
+ poly = GetPolyobj(pd->polyobj);
+ SN_StartSequence((mobj_t *) & poly->startSpot, SEQ_DOOR_STONE +
+ poly->seqType);
+ }
+ return;
+ }
+ switch (pd->type)
+ {
+ case PODOOR_SLIDE:
+ if (PO_MovePolyobj(pd->polyobj, pd->xSpeed, pd->ySpeed))
+ {
+ absSpeed = abs(pd->speed);
+ pd->dist -= absSpeed;
+ if (pd->dist <= 0)
+ {
+ poly = GetPolyobj(pd->polyobj);
+ SN_StopSequence((mobj_t *) & poly->startSpot);
+ if (!pd->close)
+ {
+ pd->dist = pd->totalDist;
+ pd->close = true;
+ pd->tics = pd->waitTics;
+ pd->direction = (ANG_MAX >> ANGLETOFINESHIFT) -
+ pd->direction;
+ pd->xSpeed = -pd->xSpeed;
+ pd->ySpeed = -pd->ySpeed;
+ }
+ else
+ {
+ if (poly->specialdata == pd)
+ {
+ poly->specialdata = NULL;
+ }
+ P_PolyobjFinished(poly->tag);
+ P_RemoveThinker(&pd->thinker);
+ }
+ }
+ }
+ else
+ {
+ poly = GetPolyobj(pd->polyobj);
+ if (poly->crush || !pd->close)
+ { // continue moving if the poly is a crusher, or is opening
+ return;
+ }
+ else
+ { // open back up
+ pd->dist = pd->totalDist - pd->dist;
+ pd->direction = (ANG_MAX >> ANGLETOFINESHIFT) -
+ pd->direction;
+ pd->xSpeed = -pd->xSpeed;
+ pd->ySpeed = -pd->ySpeed;
+ pd->close = false;
+ SN_StartSequence((mobj_t *) & poly->startSpot,
+ SEQ_DOOR_STONE + poly->seqType);
+ }
+ }
+ break;
+ case PODOOR_SWING:
+ if (PO_RotatePolyobj(pd->polyobj, pd->speed))
+ {
+ absSpeed = abs(pd->speed);
+ if (pd->dist == -1)
+ { // perpetual polyobj
+ return;
+ }
+ pd->dist -= absSpeed;
+ if (pd->dist <= 0)
+ {
+ poly = GetPolyobj(pd->polyobj);
+ SN_StopSequence((mobj_t *) & poly->startSpot);
+ if (!pd->close)
+ {
+ pd->dist = pd->totalDist;
+ pd->close = true;
+ pd->tics = pd->waitTics;
+ pd->speed = -pd->speed;
+ }
+ else
+ {
+ if (poly->specialdata == pd)
+ {
+ poly->specialdata = NULL;
+ }
+ P_PolyobjFinished(poly->tag);
+ P_RemoveThinker(&pd->thinker);
+ }
+ }
+ }
+ else
+ {
+ poly = GetPolyobj(pd->polyobj);
+ if (poly->crush || !pd->close)
+ { // continue moving if the poly is a crusher, or is opening
+ return;
+ }
+ else
+ { // open back up and rewait
+ pd->dist = pd->totalDist - pd->dist;
+ pd->speed = -pd->speed;
+ pd->close = false;
+ SN_StartSequence((mobj_t *) & poly->startSpot,
+ SEQ_DOOR_STONE + poly->seqType);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+//==========================================================================
+//
+// EV_OpenPolyDoor
+//
+//==========================================================================
+
+boolean EV_OpenPolyDoor(line_t * line, byte * args, podoortype_t type)
+{
+ int mirror;
+ int polyNum;
+ polydoor_t *pd;
+ polyobj_t *poly;
+ angle_t an = 0;
+
+ polyNum = args[0];
+ poly = GetPolyobj(polyNum);
+ if (poly != NULL)
+ {
+ if (poly->specialdata)
+ { // poly is already moving
+ return false;
+ }
+ }
+ else
+ {
+ I_Error("EV_OpenPolyDoor: Invalid polyobj num: %d\n", polyNum);
+ }
+ pd = Z_Malloc(sizeof(polydoor_t), PU_LEVSPEC, 0);
+ memset(pd, 0, sizeof(polydoor_t));
+ P_AddThinker(&pd->thinker);
+ pd->thinker.function = T_PolyDoor;
+ pd->type = type;
+ pd->polyobj = polyNum;
+ if (type == PODOOR_SLIDE)
+ {
+ pd->waitTics = args[4];
+ pd->speed = args[1] * (FRACUNIT / 8);
+ pd->totalDist = args[3] * FRACUNIT; // Distance
+ pd->dist = pd->totalDist;
+ an = args[2] * (ANG90 / 64);
+ pd->direction = an >> ANGLETOFINESHIFT;
+ pd->xSpeed = FixedMul(pd->speed, finecosine[pd->direction]);
+ pd->ySpeed = FixedMul(pd->speed, finesine[pd->direction]);
+ SN_StartSequence((mobj_t *) & poly->startSpot, SEQ_DOOR_STONE +
+ poly->seqType);
+ }
+ else if (type == PODOOR_SWING)
+ {
+ pd->waitTics = args[3];
+ pd->direction = 1; // ADD: PODOOR_SWINGL, PODOOR_SWINGR
+ pd->speed = (args[1] * pd->direction * (ANG90 / 64)) >> 3;
+ pd->totalDist = args[2] * (ANG90 / 64);
+ pd->dist = pd->totalDist;
+ SN_StartSequence((mobj_t *) & poly->startSpot, SEQ_DOOR_STONE +
+ poly->seqType);
+ }
+
+ poly->specialdata = pd;
+
+ while ((mirror = GetPolyobjMirror(polyNum)) != 0)
+ {
+ poly = GetPolyobj(mirror);
+ if (poly && poly->specialdata)
+ { // mirroring poly is already in motion
+ break;
+ }
+ pd = Z_Malloc(sizeof(polydoor_t), PU_LEVSPEC, 0);
+ memset(pd, 0, sizeof(polydoor_t));
+ P_AddThinker(&pd->thinker);
+ pd->thinker.function = T_PolyDoor;
+ pd->polyobj = mirror;
+ pd->type = type;
+ poly->specialdata = pd;
+ if (type == PODOOR_SLIDE)
+ {
+ pd->waitTics = args[4];
+ pd->speed = args[1] * (FRACUNIT / 8);
+ pd->totalDist = args[3] * FRACUNIT; // Distance
+ pd->dist = pd->totalDist;
+ an = an + ANG180; // reverse the angle
+ pd->direction = an >> ANGLETOFINESHIFT;
+ pd->xSpeed = FixedMul(pd->speed, finecosine[pd->direction]);
+ pd->ySpeed = FixedMul(pd->speed, finesine[pd->direction]);
+ SN_StartSequence((mobj_t *) & poly->startSpot, SEQ_DOOR_STONE +
+ poly->seqType);
+ }
+ else if (type == PODOOR_SWING)
+ {
+ pd->waitTics = args[3];
+ pd->direction = -1; // ADD: same as above
+ pd->speed = (args[1] * pd->direction * (ANG90 / 64)) >> 3;
+ pd->totalDist = args[2] * (ANG90 / 64);
+ pd->dist = pd->totalDist;
+ SN_StartSequence((mobj_t *) & poly->startSpot, SEQ_DOOR_STONE +
+ poly->seqType);
+ }
+ polyNum = mirror;
+ }
+ return true;
+}
+
+// ===== Higher Level Poly Interface code =====
+
+//==========================================================================
+//
+// GetPolyobj
+//
+//==========================================================================
+
+static polyobj_t *GetPolyobj(int polyNum)
+{
+ int i;
+
+ for (i = 0; i < po_NumPolyobjs; i++)
+ {
+ if (polyobjs[i].tag == polyNum)
+ {
+ return &polyobjs[i];
+ }
+ }
+ return NULL;
+}
+
+//==========================================================================
+//
+// GetPolyobjMirror
+//
+//==========================================================================
+
+static int GetPolyobjMirror(int poly)
+{
+ int i;
+
+ for (i = 0; i < po_NumPolyobjs; i++)
+ {
+ if (polyobjs[i].tag == poly)
+ {
+ return ((*polyobjs[i].segs)->linedef->arg2);
+ }
+ }
+ return 0;
+}
+
+//==========================================================================
+//
+// ThrustMobj
+//
+//==========================================================================
+
+static void ThrustMobj(mobj_t * mobj, seg_t * seg, polyobj_t * po)
+{
+ int thrustAngle;
+ int thrustX;
+ int thrustY;
+ polyevent_t *pe;
+
+ int force;
+
+ if (!(mobj->flags & MF_SHOOTABLE) && !mobj->player)
+ {
+ return;
+ }
+ thrustAngle = (seg->angle - ANG90) >> ANGLETOFINESHIFT;
+
+ pe = po->specialdata;
+ if (pe)
+ {
+ if (pe->thinker.function == T_RotatePoly)
+ {
+ force = pe->speed >> 8;
+ }
+ else
+ {
+ force = pe->speed >> 3;
+ }
+ if (force < FRACUNIT)
+ {
+ force = FRACUNIT;
+ }
+ else if (force > 4 * FRACUNIT)
+ {
+ force = 4 * FRACUNIT;
+ }
+ }
+ else
+ {
+ force = FRACUNIT;
+ }
+
+ thrustX = FixedMul(force, finecosine[thrustAngle]);
+ thrustY = FixedMul(force, finesine[thrustAngle]);
+ mobj->momx += thrustX;
+ mobj->momy += thrustY;
+ if (po->crush)
+ {
+ if (!P_CheckPosition(mobj, mobj->x + thrustX, mobj->y + thrustY))
+ {
+ P_DamageMobj(mobj, NULL, NULL, 3);
+ }
+ }
+}
+
+//==========================================================================
+//
+// UpdateSegBBox
+//
+//==========================================================================
+
+static void UpdateSegBBox(seg_t * seg)
+{
+ line_t *line;
+
+ line = seg->linedef;
+
+ if (seg->v1->x < seg->v2->x)
+ {
+ line->bbox[BOXLEFT] = seg->v1->x;
+ line->bbox[BOXRIGHT] = seg->v2->x;
+ }
+ else
+ {
+ line->bbox[BOXLEFT] = seg->v2->x;
+ line->bbox[BOXRIGHT] = seg->v1->x;
+ }
+ if (seg->v1->y < seg->v2->y)
+ {
+ line->bbox[BOXBOTTOM] = seg->v1->y;
+ line->bbox[BOXTOP] = seg->v2->y;
+ }
+ else
+ {
+ line->bbox[BOXBOTTOM] = seg->v2->y;
+ line->bbox[BOXTOP] = seg->v1->y;
+ }
+
+ // Update the line's slopetype
+ line->dx = line->v2->x - line->v1->x;
+ line->dy = line->v2->y - line->v1->y;
+ if (!line->dx)
+ {
+ line->slopetype = ST_VERTICAL;
+ }
+ else if (!line->dy)
+ {
+ line->slopetype = ST_HORIZONTAL;
+ }
+ else
+ {
+ if (FixedDiv(line->dy, line->dx) > 0)
+ {
+ line->slopetype = ST_POSITIVE;
+ }
+ else
+ {
+ line->slopetype = ST_NEGATIVE;
+ }
+ }
+}
+
+//==========================================================================
+//
+// PO_MovePolyobj
+//
+//==========================================================================
+
+boolean PO_MovePolyobj(int num, int x, int y)
+{
+ int count;
+ seg_t **segList;
+ seg_t **veryTempSeg;
+ polyobj_t *po;
+ vertex_t *prevPts;
+ boolean blocked;
+
+ if (!(po = GetPolyobj(num)))
+ {
+ I_Error("PO_MovePolyobj: Invalid polyobj number: %d\n", num);
+ }
+
+ UnLinkPolyobj(po);
+
+ segList = po->segs;
+ prevPts = po->prevPts;
+ blocked = false;
+
+ validcount++;
+ for (count = po->numsegs; count; count--, segList++, prevPts++)
+ {
+ if ((*segList)->linedef->validcount != validcount)
+ {
+ (*segList)->linedef->bbox[BOXTOP] += y;
+ (*segList)->linedef->bbox[BOXBOTTOM] += y;
+ (*segList)->linedef->bbox[BOXLEFT] += x;
+ (*segList)->linedef->bbox[BOXRIGHT] += x;
+ (*segList)->linedef->validcount = validcount;
+ }
+ for (veryTempSeg = po->segs; veryTempSeg != segList; veryTempSeg++)
+ {
+ if ((*veryTempSeg)->v1 == (*segList)->v1)
+ {
+ break;
+ }
+ }
+ if (veryTempSeg == segList)
+ {
+ (*segList)->v1->x += x;
+ (*segList)->v1->y += y;
+ }
+ (*prevPts).x += x; // previous points are unique for each seg
+ (*prevPts).y += y;
+ }
+ segList = po->segs;
+ for (count = po->numsegs; count; count--, segList++)
+ {
+ if (CheckMobjBlocking(*segList, po))
+ {
+ blocked = true;
+ }
+ }
+ if (blocked)
+ {
+ count = po->numsegs;
+ segList = po->segs;
+ prevPts = po->prevPts;
+ validcount++;
+ while (count--)
+ {
+ if ((*segList)->linedef->validcount != validcount)
+ {
+ (*segList)->linedef->bbox[BOXTOP] -= y;
+ (*segList)->linedef->bbox[BOXBOTTOM] -= y;
+ (*segList)->linedef->bbox[BOXLEFT] -= x;
+ (*segList)->linedef->bbox[BOXRIGHT] -= x;
+ (*segList)->linedef->validcount = validcount;
+ }
+ for (veryTempSeg = po->segs; veryTempSeg != segList;
+ veryTempSeg++)
+ {
+ if ((*veryTempSeg)->v1 == (*segList)->v1)
+ {
+ break;
+ }
+ }
+ if (veryTempSeg == segList)
+ {
+ (*segList)->v1->x -= x;
+ (*segList)->v1->y -= y;
+ }
+ (*prevPts).x -= x;
+ (*prevPts).y -= y;
+ segList++;
+ prevPts++;
+ }
+ LinkPolyobj(po);
+ return false;
+ }
+ po->startSpot.x += x;
+ po->startSpot.y += y;
+ LinkPolyobj(po);
+ return true;
+}
+
+//==========================================================================
+//
+// RotatePt
+//
+//==========================================================================
+
+static void RotatePt(int an, fixed_t * x, fixed_t * y, fixed_t startSpotX,
+ fixed_t startSpotY)
+{
+ fixed_t trx, try;
+ fixed_t gxt, gyt;
+
+ trx = *x;
+ try = *y;
+
+ gxt = FixedMul(trx, finecosine[an]);
+ gyt = FixedMul(try, finesine[an]);
+ *x = (gxt - gyt) + startSpotX;
+
+ gxt = FixedMul(trx, finesine[an]);
+ gyt = FixedMul(try, finecosine[an]);
+ *y = (gyt + gxt) + startSpotY;
+}
+
+//==========================================================================
+//
+// PO_RotatePolyobj
+//
+//==========================================================================
+
+boolean PO_RotatePolyobj(int num, angle_t angle)
+{
+ int count;
+ seg_t **segList;
+ vertex_t *originalPts;
+ vertex_t *prevPts;
+ int an;
+ polyobj_t *po;
+ boolean blocked;
+
+ if (!(po = GetPolyobj(num)))
+ {
+ I_Error("PO_RotatePolyobj: Invalid polyobj number: %d\n", num);
+ }
+ an = (po->angle + angle) >> ANGLETOFINESHIFT;
+
+ UnLinkPolyobj(po);
+
+ segList = po->segs;
+ originalPts = po->originalPts;
+ prevPts = po->prevPts;
+
+ for (count = po->numsegs; count; count--, segList++, originalPts++,
+ prevPts++)
+ {
+ prevPts->x = (*segList)->v1->x;
+ prevPts->y = (*segList)->v1->y;
+ (*segList)->v1->x = originalPts->x;
+ (*segList)->v1->y = originalPts->y;
+ RotatePt(an, &(*segList)->v1->x, &(*segList)->v1->y, po->startSpot.x,
+ po->startSpot.y);
+ }
+ segList = po->segs;
+ blocked = false;
+ validcount++;
+ for (count = po->numsegs; count; count--, segList++)
+ {
+ if (CheckMobjBlocking(*segList, po))
+ {
+ blocked = true;
+ }
+ if ((*segList)->linedef->validcount != validcount)
+ {
+ UpdateSegBBox(*segList);
+ (*segList)->linedef->validcount = validcount;
+ }
+ (*segList)->angle += angle;
+ }
+ if (blocked)
+ {
+ segList = po->segs;
+ prevPts = po->prevPts;
+ for (count = po->numsegs; count; count--, segList++, prevPts++)
+ {
+ (*segList)->v1->x = prevPts->x;
+ (*segList)->v1->y = prevPts->y;
+ }
+ segList = po->segs;
+ validcount++;
+ for (count = po->numsegs; count; count--, segList++, prevPts++)
+ {
+ if ((*segList)->linedef->validcount != validcount)
+ {
+ UpdateSegBBox(*segList);
+ (*segList)->linedef->validcount = validcount;
+ }
+ (*segList)->angle -= angle;
+ }
+ LinkPolyobj(po);
+ return false;
+ }
+ po->angle += angle;
+ LinkPolyobj(po);
+ return true;
+}
+
+//==========================================================================
+//
+// UnLinkPolyobj
+//
+//==========================================================================
+
+static void UnLinkPolyobj(polyobj_t * po)
+{
+ polyblock_t *link;
+ int i, j;
+ int index;
+
+ // remove the polyobj from each blockmap section
+ for (j = po->bbox[BOXBOTTOM]; j <= po->bbox[BOXTOP]; j++)
+ {
+ index = j * bmapwidth;
+ for (i = po->bbox[BOXLEFT]; i <= po->bbox[BOXRIGHT]; i++)
+ {
+ if (i >= 0 && i < bmapwidth && j >= 0 && j < bmapheight)
+ {
+ link = PolyBlockMap[index + i];
+ while (link != NULL && link->polyobj != po)
+ {
+ link = link->next;
+ }
+ if (link == NULL)
+ { // polyobj not located in the link cell
+ continue;
+ }
+ link->polyobj = NULL;
+ }
+ }
+ }
+}
+
+//==========================================================================
+//
+// LinkPolyobj
+//
+//==========================================================================
+
+static void LinkPolyobj(polyobj_t * po)
+{
+ int leftX, rightX;
+ int topY, bottomY;
+ seg_t **tempSeg;
+ polyblock_t **link;
+ polyblock_t *tempLink;
+ int i, j;
+
+ // calculate the polyobj bbox
+ tempSeg = po->segs;
+ rightX = leftX = (*tempSeg)->v1->x;
+ topY = bottomY = (*tempSeg)->v1->y;
+
+ for (i = 0; i < po->numsegs; i++, tempSeg++)
+ {
+ if ((*tempSeg)->v1->x > rightX)
+ {
+ rightX = (*tempSeg)->v1->x;
+ }
+ if ((*tempSeg)->v1->x < leftX)
+ {
+ leftX = (*tempSeg)->v1->x;
+ }
+ if ((*tempSeg)->v1->y > topY)
+ {
+ topY = (*tempSeg)->v1->y;
+ }
+ if ((*tempSeg)->v1->y < bottomY)
+ {
+ bottomY = (*tempSeg)->v1->y;
+ }
+ }
+ po->bbox[BOXRIGHT] = (rightX - bmaporgx) >> MAPBLOCKSHIFT;
+ po->bbox[BOXLEFT] = (leftX - bmaporgx) >> MAPBLOCKSHIFT;
+ po->bbox[BOXTOP] = (topY - bmaporgy) >> MAPBLOCKSHIFT;
+ po->bbox[BOXBOTTOM] = (bottomY - bmaporgy) >> MAPBLOCKSHIFT;
+ // add the polyobj to each blockmap section
+ for (j = po->bbox[BOXBOTTOM] * bmapwidth;
+ j <= po->bbox[BOXTOP] * bmapwidth; j += bmapwidth)
+ {
+ for (i = po->bbox[BOXLEFT]; i <= po->bbox[BOXRIGHT]; i++)
+ {
+ if (i >= 0 && i < bmapwidth && j >= 0
+ && j < bmapheight * bmapwidth)
+ {
+ link = &PolyBlockMap[j + i];
+ if (!(*link))
+ { // Create a new link at the current block cell
+ *link = Z_Malloc(sizeof(polyblock_t), PU_LEVEL, 0);
+ (*link)->next = NULL;
+ (*link)->prev = NULL;
+ (*link)->polyobj = po;
+ continue;
+ }
+ else
+ {
+ tempLink = *link;
+ while (tempLink->next != NULL
+ && tempLink->polyobj != NULL)
+ {
+ tempLink = tempLink->next;
+ }
+ }
+ if (tempLink->polyobj == NULL)
+ {
+ tempLink->polyobj = po;
+ continue;
+ }
+ else
+ {
+ tempLink->next = Z_Malloc(sizeof(polyblock_t),
+ PU_LEVEL, 0);
+ tempLink->next->next = NULL;
+ tempLink->next->prev = tempLink;
+ tempLink->next->polyobj = po;
+ }
+ }
+ // else, don't link the polyobj, since it's off the map
+ }
+ }
+}
+
+//==========================================================================
+//
+// CheckMobjBlocking
+//
+//==========================================================================
+
+static boolean CheckMobjBlocking(seg_t * seg, polyobj_t * po)
+{
+ mobj_t *mobj;
+ int i, j;
+ int left, right, top, bottom;
+ int tmbbox[4];
+ line_t *ld;
+ boolean blocked;
+
+ ld = seg->linedef;
+
+ top = (ld->bbox[BOXTOP] - bmaporgy + MAXRADIUS) >> MAPBLOCKSHIFT;
+ bottom = (ld->bbox[BOXBOTTOM] - bmaporgy - MAXRADIUS) >> MAPBLOCKSHIFT;
+ left = (ld->bbox[BOXLEFT] - bmaporgx - MAXRADIUS) >> MAPBLOCKSHIFT;
+ right = (ld->bbox[BOXRIGHT] - bmaporgx + MAXRADIUS) >> MAPBLOCKSHIFT;
+
+ blocked = false;
+
+ bottom = bottom < 0 ? 0 : bottom;
+ bottom = bottom >= bmapheight ? bmapheight - 1 : bottom;
+ top = top < 0 ? 0 : top;
+ top = top >= bmapheight ? bmapheight - 1 : top;
+ left = left < 0 ? 0 : left;
+ left = left >= bmapwidth ? bmapwidth - 1 : left;
+ right = right < 0 ? 0 : right;
+ right = right >= bmapwidth ? bmapwidth - 1 : right;
+
+ for (j = bottom * bmapwidth; j <= top * bmapwidth; j += bmapwidth)
+ {
+ for (i = left; i <= right; i++)
+ {
+ for (mobj = blocklinks[j + i]; mobj; mobj = mobj->bnext)
+ {
+ if (mobj->flags & MF_SOLID || mobj->player)
+ {
+ tmbbox[BOXTOP] = mobj->y + mobj->radius;
+ tmbbox[BOXBOTTOM] = mobj->y - mobj->radius;
+ tmbbox[BOXLEFT] = mobj->x - mobj->radius;
+ tmbbox[BOXRIGHT] = mobj->x + mobj->radius;
+
+ if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT]
+ || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
+ || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM]
+ || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
+ {
+ continue;
+ }
+ if (P_BoxOnLineSide(tmbbox, ld) != -1)
+ {
+ continue;
+ }
+ ThrustMobj(mobj, seg, po);
+ blocked = true;
+ }
+ }
+ }
+ }
+ return blocked;
+}
+
+//==========================================================================
+//
+// InitBlockMap
+//
+//==========================================================================
+
+static void InitBlockMap(void)
+{
+ int i;
+ int j;
+ seg_t **segList;
+ int leftX, rightX;
+ int topY, bottomY;
+
+ PolyBlockMap = Z_Malloc(bmapwidth * bmapheight * sizeof(polyblock_t *),
+ PU_LEVEL, 0);
+ memset(PolyBlockMap, 0, bmapwidth * bmapheight * sizeof(polyblock_t *));
+
+ for (i = 0; i < po_NumPolyobjs; i++)
+ {
+ LinkPolyobj(&polyobjs[i]);
+
+ // calculate a rough area
+ // right now, working like shit...gotta fix this...
+ segList = polyobjs[i].segs;
+ leftX = rightX = (*segList)->v1->x;
+ topY = bottomY = (*segList)->v1->y;
+ for (j = 0; j < polyobjs[i].numsegs; j++, segList++)
+ {
+ if ((*segList)->v1->x < leftX)
+ {
+ leftX = (*segList)->v1->x;
+ }
+ if ((*segList)->v1->x > rightX)
+ {
+ rightX = (*segList)->v1->x;
+ }
+ if ((*segList)->v1->y < bottomY)
+ {
+ bottomY = (*segList)->v1->y;
+ }
+ if ((*segList)->v1->y > topY)
+ {
+ topY = (*segList)->v1->y;
+ }
+ }
+// area = ((rightX >> FRACBITS) - (leftX >> FRACBITS)) *
+// ((topY >> FRACBITS) - (bottomY >> FRACBITS));
+
+// fprintf(stdaux, "Area of Polyobj[%d]: %d\n", polyobjs[i].tag, area);
+// fprintf(stdaux, "\t[%d]\n[%d]\t\t[%d]\n\t[%d]\n", topY>>FRACBITS,
+// leftX>>FRACBITS,
+// rightX>>FRACBITS, bottomY>>FRACBITS);
+ }
+}
+
+//==========================================================================
+//
+// IterFindPolySegs
+//
+// Passing NULL for segList will cause IterFindPolySegs to
+// count the number of segs in the polyobj
+//==========================================================================
+
+static void IterFindPolySegs(int x, int y, seg_t ** segList)
+{
+ int i;
+
+ if (x == PolyStartX && y == PolyStartY)
+ {
+ return;
+ }
+ for (i = 0; i < numsegs; i++)
+ {
+ if (segs[i].v1->x == x && segs[i].v1->y == y)
+ {
+ if (!segList)
+ {
+ PolySegCount++;
+ }
+ else
+ {
+ *segList++ = &segs[i];
+ }
+ IterFindPolySegs(segs[i].v2->x, segs[i].v2->y, segList);
+ return;
+ }
+ }
+ I_Error("IterFindPolySegs: Non-closed Polyobj located.\n");
+}
+
+
+//==========================================================================
+//
+// SpawnPolyobj
+//
+//==========================================================================
+
+static void SpawnPolyobj(int index, int tag, boolean crush)
+{
+ int i;
+ int j;
+ int psIndex;
+ int psIndexOld;
+ seg_t *polySegList[PO_MAXPOLYSEGS];
+
+ for (i = 0; i < numsegs; i++)
+ {
+ if (segs[i].linedef->special == PO_LINE_START &&
+ segs[i].linedef->arg1 == tag)
+ {
+ if (polyobjs[index].segs)
+ {
+ I_Error("SpawnPolyobj: Polyobj %d already spawned.\n", tag);
+ }
+ segs[i].linedef->special = 0;
+ segs[i].linedef->arg1 = 0;
+ PolySegCount = 1;
+ PolyStartX = segs[i].v1->x;
+ PolyStartY = segs[i].v1->y;
+ IterFindPolySegs(segs[i].v2->x, segs[i].v2->y, NULL);
+
+ polyobjs[index].numsegs = PolySegCount;
+ polyobjs[index].segs = Z_Malloc(PolySegCount * sizeof(seg_t *),
+ PU_LEVEL, 0);
+ *(polyobjs[index].segs) = &segs[i]; // insert the first seg
+ IterFindPolySegs(segs[i].v2->x, segs[i].v2->y,
+ polyobjs[index].segs + 1);
+ polyobjs[index].crush = crush;
+ polyobjs[index].tag = tag;
+ polyobjs[index].seqType = segs[i].linedef->arg3;
+ if (polyobjs[index].seqType < 0
+ || polyobjs[index].seqType >= SEQTYPE_NUMSEQ)
+ {
+ polyobjs[index].seqType = 0;
+ }
+ break;
+ }
+ }
+ if (!polyobjs[index].segs)
+ { // didn't find a polyobj through PO_LINE_START
+ psIndex = 0;
+ polyobjs[index].numsegs = 0;
+ for (j = 1; j < PO_MAXPOLYSEGS; j++)
+ {
+ psIndexOld = psIndex;
+ for (i = 0; i < numsegs; i++)
+ {
+ if (segs[i].linedef->special == PO_LINE_EXPLICIT &&
+ segs[i].linedef->arg1 == tag)
+ {
+ if (!segs[i].linedef->arg2)
+ {
+ I_Error
+ ("SpawnPolyobj: Explicit line missing order number (probably %d) in poly %d.\n",
+ j + 1, tag);
+ }
+ if (segs[i].linedef->arg2 == j)
+ {
+ polySegList[psIndex] = &segs[i];
+ polyobjs[index].numsegs++;
+ psIndex++;
+ if (psIndex > PO_MAXPOLYSEGS)
+ {
+ I_Error
+ ("SpawnPolyobj: psIndex > PO_MAXPOLYSEGS\n");
+ }
+ }
+ }
+ }
+ // Clear out any specials for these segs...we cannot clear them out
+ // in the above loop, since we aren't guaranteed one seg per
+ // linedef.
+ for (i = 0; i < numsegs; i++)
+ {
+ if (segs[i].linedef->special == PO_LINE_EXPLICIT &&
+ segs[i].linedef->arg1 == tag
+ && segs[i].linedef->arg2 == j)
+ {
+ segs[i].linedef->special = 0;
+ segs[i].linedef->arg1 = 0;
+ }
+ }
+ if (psIndex == psIndexOld)
+ { // Check if an explicit line order has been skipped
+ // A line has been skipped if there are any more explicit
+ // lines with the current tag value
+ for (i = 0; i < numsegs; i++)
+ {
+ if (segs[i].linedef->special == PO_LINE_EXPLICIT &&
+ segs[i].linedef->arg1 == tag)
+ {
+ I_Error
+ ("SpawnPolyobj: Missing explicit line %d for poly %d\n",
+ j, tag);
+ }
+ }
+ }
+ }
+ if (polyobjs[index].numsegs)
+ {
+ PolySegCount = polyobjs[index].numsegs; // PolySegCount used globally
+ polyobjs[index].crush = crush;
+ polyobjs[index].tag = tag;
+ polyobjs[index].segs = Z_Malloc(polyobjs[index].numsegs
+ * sizeof(seg_t *), PU_LEVEL, 0);
+ for (i = 0; i < polyobjs[index].numsegs; i++)
+ {
+ polyobjs[index].segs[i] = polySegList[i];
+ }
+ polyobjs[index].seqType = (*polyobjs[index].segs)->linedef->arg4;
+ }
+ // Next, change the polyobjs first line to point to a mirror
+ // if it exists
+ (*polyobjs[index].segs)->linedef->arg2 =
+ (*polyobjs[index].segs)->linedef->arg3;
+ }
+}
+
+//==========================================================================
+//
+// TranslateToStartSpot
+//
+//==========================================================================
+
+static void TranslateToStartSpot(int tag, int originX, int originY)
+{
+ seg_t **tempSeg;
+ seg_t **veryTempSeg;
+ vertex_t *tempPt;
+ subsector_t *sub;
+ polyobj_t *po;
+ int deltaX;
+ int deltaY;
+ vertex_t avg; // used to find a polyobj's center, and hence subsector
+ int i;
+
+ po = NULL;
+ for (i = 0; i < po_NumPolyobjs; i++)
+ {
+ if (polyobjs[i].tag == tag)
+ {
+ po = &polyobjs[i];
+ break;
+ }
+ }
+ if (!po)
+ { // didn't match the tag with a polyobj tag
+ I_Error("TranslateToStartSpot: Unable to match polyobj tag: %d\n",
+ tag);
+ }
+ if (po->segs == NULL)
+ {
+ I_Error
+ ("TranslateToStartSpot: Anchor point located without a StartSpot point: %d\n",
+ tag);
+ }
+ po->originalPts = Z_Malloc(po->numsegs * sizeof(vertex_t), PU_LEVEL, 0);
+ po->prevPts = Z_Malloc(po->numsegs * sizeof(vertex_t), PU_LEVEL, 0);
+ deltaX = originX - po->startSpot.x;
+ deltaY = originY - po->startSpot.y;
+
+ tempSeg = po->segs;
+ tempPt = po->originalPts;
+ avg.x = 0;
+ avg.y = 0;
+
+ validcount++;
+ for (i = 0; i < po->numsegs; i++, tempSeg++, tempPt++)
+ {
+ if ((*tempSeg)->linedef->validcount != validcount)
+ {
+ (*tempSeg)->linedef->bbox[BOXTOP] -= deltaY;
+ (*tempSeg)->linedef->bbox[BOXBOTTOM] -= deltaY;
+ (*tempSeg)->linedef->bbox[BOXLEFT] -= deltaX;
+ (*tempSeg)->linedef->bbox[BOXRIGHT] -= deltaX;
+ (*tempSeg)->linedef->validcount = validcount;
+ }
+ for (veryTempSeg = po->segs; veryTempSeg != tempSeg; veryTempSeg++)
+ {
+ if ((*veryTempSeg)->v1 == (*tempSeg)->v1)
+ {
+ break;
+ }
+ }
+ if (veryTempSeg == tempSeg)
+ { // the point hasn't been translated, yet
+ (*tempSeg)->v1->x -= deltaX;
+ (*tempSeg)->v1->y -= deltaY;
+ }
+ avg.x += (*tempSeg)->v1->x >> FRACBITS;
+ avg.y += (*tempSeg)->v1->y >> FRACBITS;
+ // the original Pts are based off the startSpot Pt, and are
+ // unique to each seg, not each linedef
+ tempPt->x = (*tempSeg)->v1->x - po->startSpot.x;
+ tempPt->y = (*tempSeg)->v1->y - po->startSpot.y;
+ }
+ avg.x /= po->numsegs;
+ avg.y /= po->numsegs;
+ sub = R_PointInSubsector(avg.x << FRACBITS, avg.y << FRACBITS);
+ if (sub->poly != NULL)
+ {
+ I_Error
+ ("PO_TranslateToStartSpot: Multiple polyobjs in a single subsector.\n");
+ }
+ sub->poly = po;
+}
+
+//==========================================================================
+//
+// PO_Init
+//
+//==========================================================================
+
+void PO_Init(int lump)
+{
+ byte *data;
+ int i;
+ mapthing_t spawnthing;
+ mapthing_t *mt;
+ int numthings;
+ int polyIndex;
+
+ polyobjs = Z_Malloc(po_NumPolyobjs * sizeof(polyobj_t), PU_LEVEL, 0);
+ memset(polyobjs, 0, po_NumPolyobjs * sizeof(polyobj_t));
+
+ data = W_CacheLumpNum(lump, PU_STATIC);
+ numthings = W_LumpLength(lump) / sizeof(mapthing_t);
+ mt = (mapthing_t *) data;
+ polyIndex = 0; // index polyobj number
+ // Find the startSpot points, and spawn each polyobj
+ for (i = 0; i < numthings; i++, mt++)
+ {
+ spawnthing.x = SHORT(mt->x);
+ spawnthing.y = SHORT(mt->y);
+ spawnthing.angle = SHORT(mt->angle);
+ spawnthing.type = SHORT(mt->type);
+
+ // 3001 = no crush, 3002 = crushing
+ if (spawnthing.type == PO_SPAWN_TYPE
+ || spawnthing.type == PO_SPAWNCRUSH_TYPE)
+ { // Polyobj StartSpot Pt.
+ polyobjs[polyIndex].startSpot.x = spawnthing.x << FRACBITS;
+ polyobjs[polyIndex].startSpot.y = spawnthing.y << FRACBITS;
+ SpawnPolyobj(polyIndex, spawnthing.angle,
+ (spawnthing.type == PO_SPAWNCRUSH_TYPE));
+ polyIndex++;
+ }
+ }
+ mt = (mapthing_t *) data;
+ for (i = 0; i < numthings; i++, mt++)
+ {
+ spawnthing.x = SHORT(mt->x);
+ spawnthing.y = SHORT(mt->y);
+ spawnthing.angle = SHORT(mt->angle);
+ spawnthing.type = SHORT(mt->type);
+ if (spawnthing.type == PO_ANCHOR_TYPE)
+ { // Polyobj Anchor Pt.
+ TranslateToStartSpot(spawnthing.angle,
+ spawnthing.x << FRACBITS,
+ spawnthing.y << FRACBITS);
+ }
+ }
+ W_ReleaseLumpNum(lump);
+ // check for a startspot without an anchor point
+ for (i = 0; i < po_NumPolyobjs; i++)
+ {
+ if (!polyobjs[i].originalPts)
+ {
+ I_Error
+ ("PO_Init: StartSpot located without an Anchor point: %d\n",
+ polyobjs[i].tag);
+ }
+ }
+ InitBlockMap();
+}
+
+//==========================================================================
+//
+// PO_Busy
+//
+//==========================================================================
+
+boolean PO_Busy(int polyobj)
+{
+ polyobj_t *poly;
+
+ poly = GetPolyobj(polyobj);
+ if (!poly->specialdata)
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
diff --git a/src/hexen/r_bsp.c b/src/hexen/r_bsp.c
new file mode 100644
index 00000000..6f65e1a4
--- /dev/null
+++ b/src/hexen/r_bsp.c
@@ -0,0 +1,505 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#include "h2def.h"
+#include "i_system.h"
+#include "m_bbox.h"
+#include "r_local.h"
+
+seg_t *curline;
+side_t *sidedef;
+line_t *linedef;
+sector_t *frontsector, *backsector;
+
+drawseg_t drawsegs[MAXDRAWSEGS], *ds_p;
+
+void R_StoreWallRange(int start, int stop);
+
+/*
+====================
+=
+= R_ClearDrawSegs
+=
+====================
+*/
+
+void R_ClearDrawSegs(void)
+{
+ ds_p = drawsegs;
+}
+
+//=============================================================================
+
+
+/*
+===============================================================================
+=
+= ClipWallSegment
+=
+= Clips the given range of columns and includes it in the new clip list
+===============================================================================
+*/
+
+typedef struct
+{
+ int first, last;
+} cliprange_t;
+
+#define MAXSEGS 32
+
+cliprange_t solidsegs[MAXSEGS], *newend; // newend is one past the last valid seg
+
+
+void R_ClipSolidWallSegment(int first, int last)
+{
+ cliprange_t *next, *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);
+ start->first = first; // adjust the clip size
+ }
+
+ if (last <= start->last)
+ return; // bottom contained in start
+
+ 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
+ start->last = next->last; // adjust the clip size
+ goto crunch;
+ }
+ }
+
+ // there is a fragment after *next
+ R_StoreWallRange(next->last + 1, last);
+ start->last = last; // adjust the clip size
+
+
+// remove start+1 to next from the clip list,
+// because start now covers their area
+ crunch:
+ if (next == start)
+ return; // post just extended past the bottom of one post
+
+ 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
+===============================================================================
+*/
+
+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);
+ }
+
+ if (last <= start->last)
+ return; // bottom contained in start
+
+ 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, x2;
+ angle_t angle1, angle2, span, 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;
+ if (span >= ANG180)
+ return; // back side
+
+ rw_angle1 = angle1; // global angle needed by segcalc
+ angle1 -= viewangle;
+ angle2 -= viewangle;
+
+ tspan = angle1 + clipangle;
+ if (tspan > 2 * clipangle)
+ {
+ tspan -= 2 * clipangle;
+ if (tspan >= span)
+ return; // totally off the left edge
+ angle1 = clipangle;
+ }
+ tspan = clipangle - angle2;
+ if (tspan > 2 * clipangle)
+ {
+ tspan -= 2 * clipangle;
+ if (tspan >= span)
+ return; // totally off the left edge
+ angle2 = -clipangle;
+ }
+
+//
+// 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];
+ if (x1 == x2)
+ return; // does not cross a pixel
+
+ backsector = line->backsector;
+
+ if (!backsector)
+ goto clipsolid; // single sided line
+
+ if (backsector->ceilingheight <= frontsector->floorheight
+ || backsector->floorheight >= frontsector->ceilingheight)
+ goto clipsolid; // closed door
+
+ if (backsector->ceilingheight != frontsector->ceilingheight
+ || backsector->floorheight != frontsector->floorheight)
+ goto clippass; // window
+
+// reject empty lines used for triggers and special events
+ if (backsector->ceilingpic == frontsector->ceilingpic
+ && backsector->floorpic == frontsector->floorpic
+ && backsector->lightlevel == frontsector->lightlevel
+ && backsector->special == frontsector->special
+ && curline->sidedef->midtexture == 0)
+ return;
+
+ clippass:
+ R_ClipPassWallSegment(x1, x2 - 1);
+ return;
+
+ clipsolid:
+ R_ClipSolidWallSegment(x1, x2 - 1);
+}
+
+//============================================================================
+
+
+/*
+===============================================================================
+=
+= R_CheckBBox
+=
+= Returns true if some part of the bbox might be visible
+=
+===============================================================================
+*/
+
+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}
+};
+
+
+boolean R_CheckBBox(fixed_t * bspcoord)
+{
+ int boxx, boxy, boxpos;
+ fixed_t x1, y1, x2, y2;
+ angle_t angle1, angle2, span, tspan;
+ cliprange_t *start;
+ int sx1, 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;
+ if (span >= ANG180)
+ return true; // sitting on a line
+ tspan = angle1 + clipangle;
+ if (tspan > 2 * clipangle)
+ {
+ tspan -= 2 * clipangle;
+ if (tspan >= span)
+ return false; // totally off the left edge
+ angle1 = clipangle;
+ }
+ tspan = clipangle - angle2;
+ if (tspan > 2 * clipangle)
+ {
+ tspan -= 2 * clipangle;
+ if (tspan >= span)
+ return false; // totally off the left edge
+ angle2 = -clipangle;
+ }
+
+
+// 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];
+ if (sx1 == sx2)
+ return false; // does not cross a pixel
+ sx2--;
+
+ start = solidsegs;
+ while (start->last < sx2)
+ start++;
+ if (sx1 >= start->first && sx2 <= start->last)
+ return false; // the clippost contains the new span
+
+ return true;
+}
+
+
+/*
+================
+=
+= R_Subsector
+=
+= Draw one or more segments
+================
+*/
+
+void R_Subsector(int num)
+{
+ int count;
+ seg_t *line;
+ subsector_t *sub;
+ int polyCount;
+ seg_t **polySeg;
+
+#ifdef RANGECHECK
+ if (num >= numsubsectors)
+ I_Error("R_Subsector: ss %i with numss = %i", num, numsubsectors);
+#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,
+ frontsector->special);
+ }
+ else
+ {
+ floorplane = NULL;
+ }
+
+ if (frontsector->ceilingheight > viewz
+ || frontsector->ceilingpic == skyflatnum)
+ {
+ ceilingplane = R_FindPlane(frontsector->ceilingheight,
+ frontsector->ceilingpic,
+ frontsector->lightlevel, 0);
+ }
+ else
+ {
+ ceilingplane = NULL;
+ }
+
+ R_AddSprites(frontsector);
+ if (sub->poly)
+ { // Render the polyobj in the subsector first
+ polyCount = sub->poly->numsegs;
+ polySeg = sub->poly->segs;
+ while (polyCount--)
+ {
+ R_AddLine(*polySeg++);
+ }
+ }
+ while (count--)
+ {
+ R_AddLine(line);
+ line++;
+ }
+}
+
+
+/*
+===============================================================================
+=
+= RenderBSPNode
+=
+===============================================================================
+*/
+
+void R_RenderBSPNode(int bspnum)
+{
+ node_t *bsp;
+ int side;
+
+ 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);
+
+ R_RenderBSPNode(bsp->children[side]); // recursively divide front space
+
+ if (R_CheckBBox(bsp->bbox[side ^ 1])) // possibly divide back space
+ R_RenderBSPNode(bsp->children[side ^ 1]);
+}
diff --git a/src/hexen/r_data.c b/src/hexen/r_data.c
new file mode 100644
index 00000000..0565c891
--- /dev/null
+++ b/src/hexen/r_data.c
@@ -0,0 +1,706 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#include "h2def.h"
+#include "i_system.h"
+#include "i_swap.h"
+#include "r_local.h"
+#include "p_local.h"
+
+typedef struct
+{
+ int originx; // block origin (allways UL), which has allready
+ int originy; // accounted for the patch's internal origin
+ int patch;
+} texpatch_t;
+
+// a maptexturedef_t describes a rectangular texture, which is composed of one
+// or more mappatch_t structures that arrange graphic patches
+typedef struct
+{
+ char name[8]; // for switch changing, etc
+ short width;
+ short height;
+ short patchcount;
+ texpatch_t patches[1]; // [patchcount] drawn back to front
+ // into the cached texture
+} texture_t;
+
+
+
+int firstflat, lastflat, numflats;
+int firstpatch, lastpatch, numpatches;
+int firstspritelump, lastspritelump, numspritelumps;
+
+int numtextures;
+texture_t **textures;
+int *texturewidthmask;
+fixed_t *textureheight; // needed for texture pegging
+int *texturecompositesize;
+short **texturecolumnlump;
+unsigned short **texturecolumnofs;
+byte **texturecomposite;
+
+int *flattranslation; // for global animation
+int *texturetranslation; // for global animation
+
+fixed_t *spritewidth; // needed for pre rendering
+fixed_t *spriteoffset;
+fixed_t *spritetopoffset;
+
+lighttable_t *colormaps;
+
+
+/*
+==============================================================================
+
+ MAPTEXTURE_T CACHING
+
+when a texture is first needed, it counts the number of composite columns
+required in the texture and allocates space for a column directory and any
+new columns. The directory will simply point inside other patches if there
+is only one patch in a given column, but any columns with multiple patches
+will have new column_ts generated.
+
+==============================================================================
+*/
+
+/*
+===================
+=
+= R_DrawColumnInCache
+=
+= Clip and draw a column from a patch into a cached post
+=
+===================
+*/
+
+void R_DrawColumnInCache(column_t * patch, byte * cache, int originy,
+ int cacheheight)
+{
+ int count, position;
+ byte *source;
+
+ while (patch->topdelta != 0xff)
+ {
+ source = (byte *) patch + 3;
+ count = patch->length;
+ position = originy + patch->topdelta;
+ if (position < 0)
+ {
+ count += position;
+ position = 0;
+ }
+ if (position + count > cacheheight)
+ count = cacheheight - position;
+ if (count > 0)
+ memcpy(cache + position, source, count);
+
+ patch = (column_t *) ((byte *) patch + patch->length + 4);
+ }
+}
+
+
+/*
+===================
+=
+= R_GenerateComposite
+=
+===================
+*/
+
+void R_GenerateComposite(int texnum)
+{
+ byte *block;
+ texture_t *texture;
+ texpatch_t *patch;
+ patch_t *realpatch;
+ int x, x1, x2;
+ int i;
+ column_t *patchcol;
+ short *collump;
+ unsigned short *colofs;
+
+ texture = textures[texnum];
+ block = Z_Malloc(texturecompositesize[texnum], PU_STATIC,
+ &texturecomposite[texnum]);
+ collump = texturecolumnlump[texnum];
+ colofs = texturecolumnofs[texnum];
+
+//
+// composite the columns together
+//
+ patch = texture->patches;
+
+ for (i = 0, patch = texture->patches; i < texture->patchcount;
+ i++, patch++)
+ {
+ realpatch = W_CacheLumpNum(patch->patch, PU_CACHE);
+ x1 = patch->originx;
+ x2 = x1 + SHORT(realpatch->width);
+
+ if (x1 < 0)
+ x = 0;
+ else
+ x = x1;
+ if (x2 > texture->width)
+ x2 = texture->width;
+
+ for (; x < x2; x++)
+ {
+ if (collump[x] >= 0)
+ continue; // column does not have multiple patches
+ patchcol = (column_t *) ((byte *) realpatch +
+ LONG(realpatch->columnofs[x - x1]));
+ R_DrawColumnInCache(patchcol, block + colofs[x], patch->originy,
+ texture->height);
+ }
+
+ }
+
+// now that the texture has been built, it is purgable
+ Z_ChangeTag(block, PU_CACHE);
+}
+
+
+/*
+===================
+=
+= R_GenerateLookup
+=
+===================
+*/
+
+void R_GenerateLookup(int texnum)
+{
+ texture_t *texture;
+ byte *patchcount; // [texture->width]
+ texpatch_t *patch;
+ patch_t *realpatch;
+ int x, x1, x2;
+ int i;
+ short *collump;
+ unsigned short *colofs;
+
+ texture = textures[texnum];
+
+ texturecomposite[texnum] = 0; // composited not created yet
+ texturecompositesize[texnum] = 0;
+ collump = texturecolumnlump[texnum];
+ colofs = texturecolumnofs[texnum];
+
+//
+// count the number of columns that are covered by more than one patch
+// fill in the lump / offset, so columns with only a single patch are
+// all done
+//
+ patchcount = (byte *) Z_Malloc(texture->width, PU_STATIC, &patchcount);
+ memset(patchcount, 0, texture->width);
+ patch = texture->patches;
+
+ for (i = 0, patch = texture->patches; i < texture->patchcount;
+ i++, patch++)
+ {
+ realpatch = W_CacheLumpNum(patch->patch, PU_CACHE);
+ x1 = patch->originx;
+ x2 = x1 + SHORT(realpatch->width);
+ if (x1 < 0)
+ x = 0;
+ else
+ x = x1;
+ if (x2 > texture->width)
+ x2 = texture->width;
+ for (; x < x2; x++)
+ {
+ patchcount[x]++;
+ collump[x] = patch->patch;
+ colofs[x] = LONG(realpatch->columnofs[x - x1]) + 3;
+ }
+ }
+
+ for (x = 0; x < texture->width; x++)
+ {
+ if (!patchcount[x])
+ {
+ ST_Message("R_GenerateLookup: column without a patch (%s)\n",
+ texture->name);
+ return;
+ }
+// I_Error ("R_GenerateLookup: column without a patch");
+ if (patchcount[x] > 1)
+ {
+ collump[x] = -1; // use the cached block
+ colofs[x] = texturecompositesize[texnum];
+ if (texturecompositesize[texnum] > 0x10000 - texture->height)
+ I_Error("R_GenerateLookup: texture %i is >64k", texnum);
+ texturecompositesize[texnum] += texture->height;
+ }
+ }
+
+ Z_Free(patchcount);
+}
+
+
+/*
+================
+=
+= R_GetColumn
+=
+================
+*/
+
+byte *R_GetColumn(int tex, int col)
+{
+ int lump, ofs;
+
+ col &= texturewidthmask[tex];
+ lump = texturecolumnlump[tex][col];
+ ofs = texturecolumnofs[tex][col];
+ if (lump > 0)
+ return (byte *) W_CacheLumpNum(lump, PU_CACHE) + ofs;
+ if (!texturecomposite[tex])
+ R_GenerateComposite(tex);
+ return texturecomposite[tex] + ofs;
+}
+
+
+/*
+==================
+=
+= R_InitTextures
+=
+= Initializes the texture list with the textures from the world map
+=
+==================
+*/
+
+void R_InitTextures(void)
+{
+ maptexture_t *mtexture;
+ texture_t *texture;
+ mappatch_t *mpatch;
+ texpatch_t *patch;
+ int i, j;
+ int *maptex, *maptex2, *maptex1;
+ char name[9], *names, *name_p;
+ int *patchlookup;
+ int totalwidth;
+ int nummappatches;
+ int offset, maxoff, maxoff2;
+ int numtextures1, numtextures2;
+ int *directory;
+
+//
+// load the patch names from pnames.lmp
+//
+ name[8] = 0;
+ names = W_CacheLumpName("PNAMES", PU_STATIC);
+ nummappatches = LONG(*((int *) names));
+ name_p = names + 4;
+ patchlookup = Z_Malloc(nummappatches * sizeof(*patchlookup), PU_STATIC, NULL);
+ for (i = 0; i < nummappatches; i++)
+ {
+ strncpy(name, name_p + i * 8, 8);
+ patchlookup[i] = W_CheckNumForName(name);
+ }
+ W_ReleaseLumpName("PNAMES");
+
+//
+// load the map texture definitions from textures.lmp
+//
+ maptex = maptex1 = W_CacheLumpName("TEXTURE1", PU_STATIC);
+ numtextures1 = LONG(*maptex);
+ maxoff = W_LumpLength(W_GetNumForName("TEXTURE1"));
+ directory = maptex + 1;
+
+ if (W_CheckNumForName("TEXTURE2") != -1)
+ {
+ maptex2 = W_CacheLumpName("TEXTURE2", PU_STATIC);
+ numtextures2 = LONG(*maptex2);
+ maxoff2 = W_LumpLength(W_GetNumForName("TEXTURE2"));
+ }
+ else
+ {
+ maptex2 = NULL;
+ numtextures2 = 0;
+ maxoff2 = 0;
+ }
+ numtextures = numtextures1 + numtextures2;
+
+ textures = Z_Malloc(numtextures * sizeof(texture_t *), PU_STATIC, 0);
+ texturecolumnlump = Z_Malloc(numtextures * sizeof(short *), PU_STATIC, 0);
+ texturecolumnofs = Z_Malloc(numtextures * sizeof(short *), PU_STATIC, 0);
+ texturecomposite = Z_Malloc(numtextures * sizeof(byte *), PU_STATIC, 0);
+ texturecompositesize = Z_Malloc(numtextures * sizeof(int), PU_STATIC, 0);
+ texturewidthmask = Z_Malloc(numtextures * sizeof(int), PU_STATIC, 0);
+ textureheight = Z_Malloc(numtextures * sizeof(fixed_t), PU_STATIC, 0);
+
+ totalwidth = 0;
+
+ for (i = 0; i < numtextures; i++, directory++)
+ {
+ if (i == numtextures1)
+ { // start looking in second texture file
+ maptex = maptex2;
+ maxoff = maxoff2;
+ directory = maptex + 1;
+ }
+
+ offset = LONG(*directory);
+ if (offset > maxoff)
+ I_Error("R_InitTextures: bad texture directory");
+ mtexture = (maptexture_t *) ((byte *) maptex + offset);
+ texture = textures[i] = Z_Malloc(sizeof(texture_t)
+ +
+ sizeof(texpatch_t) *
+ (SHORT(mtexture->patchcount) - 1),
+ PU_STATIC, 0);
+ texture->width = SHORT(mtexture->width);
+ texture->height = SHORT(mtexture->height);
+ texture->patchcount = SHORT(mtexture->patchcount);
+ memcpy(texture->name, mtexture->name, sizeof(texture->name));
+ mpatch = &mtexture->patches[0];
+ patch = &texture->patches[0];
+ for (j = 0; j < texture->patchcount; j++, mpatch++, patch++)
+ {
+ patch->originx = SHORT(mpatch->originx);
+ patch->originy = SHORT(mpatch->originy);
+ patch->patch = patchlookup[SHORT(mpatch->patch)];
+ if (patch->patch == -1)
+ I_Error("R_InitTextures: Missing patch in texture %s",
+ texture->name);
+ }
+ texturecolumnlump[i] = Z_Malloc(texture->width * sizeof(short), PU_STATIC, 0);
+ texturecolumnofs[i] = Z_Malloc(texture->width * sizeof(short), PU_STATIC, 0);
+ j = 1;
+ while (j * 2 <= texture->width)
+ j <<= 1;
+ texturewidthmask[i] = j - 1;
+ textureheight[i] = texture->height << FRACBITS;
+
+ totalwidth += texture->width;
+ }
+
+ Z_Free(patchlookup);
+
+ W_ReleaseLumpName("TEXTURE1");
+ if (maptex2)
+ W_ReleaseLumpName("TEXTURE2");
+
+//
+// precalculate whatever possible
+//
+ for (i = 0; i < numtextures; i++)
+ {
+ R_GenerateLookup(i);
+ if (!(i & 31))
+ ST_Progress();
+ }
+
+//
+// translation table for global animation
+//
+ texturetranslation = Z_Malloc((numtextures + 1) * sizeof(int), PU_STATIC, 0);
+ for (i = 0; i < numtextures; i++)
+ texturetranslation[i] = i;
+}
+
+
+/*
+================
+=
+= R_InitFlats
+=
+=================
+*/
+
+void R_InitFlats(void)
+{
+ int i;
+
+ firstflat = W_GetNumForName("F_START") + 1;
+ lastflat = W_GetNumForName("F_END") - 1;
+ numflats = lastflat - firstflat + 1;
+
+// translation table for global animation
+ flattranslation = Z_Malloc((numflats + 1) * sizeof(int), PU_STATIC, 0);
+ for (i = 0; i < numflats; i++)
+ flattranslation[i] = i;
+}
+
+
+/*
+================
+=
+= R_InitSpriteLumps
+=
+= Finds the width and hoffset of all sprites in the wad, so the sprite doesn't
+= need to be cached just for the header during rendering
+=================
+*/
+
+void R_InitSpriteLumps(void)
+{
+ int i;
+ patch_t *patch;
+
+ firstspritelump = W_GetNumForName("S_START") + 1;
+ lastspritelump = W_GetNumForName("S_END") - 1;
+ numspritelumps = lastspritelump - firstspritelump + 1;
+ spritewidth = Z_Malloc(numspritelumps * sizeof(fixed_t), PU_STATIC, 0);
+ spriteoffset = Z_Malloc(numspritelumps * sizeof(fixed_t), PU_STATIC, 0);
+ spritetopoffset = Z_Malloc(numspritelumps * sizeof(fixed_t), PU_STATIC, 0);
+
+ for (i = 0; i < numspritelumps; i++)
+ {
+ if (!(i & 127))
+ ST_Progress();
+ patch = W_CacheLumpNum(firstspritelump + i, PU_CACHE);
+ spritewidth[i] = SHORT(patch->width) << FRACBITS;
+ spriteoffset[i] = SHORT(patch->leftoffset) << FRACBITS;
+ spritetopoffset[i] = SHORT(patch->topoffset) << FRACBITS;
+ }
+}
+
+
+/*
+================
+=
+= R_InitColormaps
+=
+=================
+*/
+
+void R_InitColormaps(void)
+{
+ int lump, length;
+//
+// load in the light tables
+// 256 byte align tables
+//
+ lump = W_GetNumForName("COLORMAP");
+ length = W_LumpLength(lump);
+ colormaps = Z_Malloc(length, PU_STATIC, 0);
+ W_ReadLump(lump, colormaps);
+}
+
+
+/*
+================
+=
+= R_InitData
+=
+= Locates all the lumps that will be used by all views
+= Must be called after W_Init
+=================
+*/
+
+void R_InitData(void)
+{
+ R_InitTextures();
+ R_InitFlats();
+ R_InitSpriteLumps();
+ R_InitColormaps();
+}
+
+//=============================================================================
+
+/*
+================
+=
+= R_FlatNumForName
+=
+================
+*/
+
+int R_FlatNumForName(char *name)
+{
+ int i;
+ char namet[9];
+
+ i = W_CheckNumForName(name);
+ if (i == -1)
+ {
+ namet[8] = 0;
+ memcpy(namet, name, 8);
+ I_Error("R_FlatNumForName: %s not found", namet);
+ }
+ return i - firstflat;
+}
+
+
+/*
+================
+=
+= R_CheckTextureNumForName
+=
+================
+*/
+
+int R_CheckTextureNumForName(char *name)
+{
+ int i;
+
+ if (name[0] == '-') // no texture marker
+ return 0;
+
+ for (i = 0; i < numtextures; i++)
+ if (!strncasecmp(textures[i]->name, name, 8))
+ return i;
+
+ return -1;
+}
+
+
+/*
+================
+=
+= R_TextureNumForName
+=
+================
+*/
+
+int R_TextureNumForName(char *name)
+{
+ int i;
+ //char namet[9];
+
+ i = R_CheckTextureNumForName(name);
+ if (i == -1)
+ I_Error("R_TextureNumForName: %s not found", name);
+
+ return i;
+}
+
+
+/*
+=================
+=
+= R_PrecacheLevel
+=
+= Preloads all relevent graphics for the level
+=================
+*/
+
+int flatmemory, texturememory, spritememory;
+
+void R_PrecacheLevel(void)
+{
+ char *flatpresent;
+ char *texturepresent;
+ char *spritepresent;
+ int i, j, k, lump;
+ texture_t *texture;
+ thinker_t *th;
+ spriteframe_t *sf;
+
+ if (demoplayback)
+ return;
+
+//
+// precache flats
+//
+ flatpresent = Z_Malloc(numflats, PU_STATIC, NULL);
+ memset(flatpresent, 0, numflats);
+ for (i = 0; i < numsectors; i++)
+ {
+ flatpresent[sectors[i].floorpic] = 1;
+ flatpresent[sectors[i].ceilingpic] = 1;
+ }
+
+ flatmemory = 0;
+ for (i = 0; i < numflats; i++)
+ if (flatpresent[i])
+ {
+ lump = firstflat + i;
+ flatmemory += lumpinfo[lump].size;
+ W_CacheLumpNum(lump, PU_CACHE);
+ }
+
+ Z_Free(flatpresent);
+
+//
+// precache textures
+//
+ texturepresent = Z_Malloc(numtextures, PU_STATIC, NULL);
+ memset(texturepresent, 0, numtextures);
+
+ for (i = 0; i < numsides; i++)
+ {
+ texturepresent[sides[i].toptexture] = 1;
+ texturepresent[sides[i].midtexture] = 1;
+ texturepresent[sides[i].bottomtexture] = 1;
+ }
+
+ texturepresent[Sky1Texture] = 1;
+ texturepresent[Sky2Texture] = 1;
+
+ texturememory = 0;
+ for (i = 0; i < numtextures; i++)
+ {
+ if (!texturepresent[i])
+ continue;
+ texture = textures[i];
+ for (j = 0; j < texture->patchcount; j++)
+ {
+ lump = texture->patches[j].patch;
+ texturememory += lumpinfo[lump].size;
+ W_CacheLumpNum(lump, PU_CACHE);
+ }
+ }
+
+ Z_Free(texturepresent);
+
+//
+// precache sprites
+//
+ spritepresent = Z_Malloc(numsprites, PU_STATIC, NULL);
+ memset(spritepresent, 0, numsprites);
+
+ for (th = thinkercap.next; th != &thinkercap; th = th->next)
+ {
+ if (th->function == P_MobjThinker)
+ spritepresent[((mobj_t *) th)->sprite] = 1;
+ }
+
+ spritememory = 0;
+ for (i = 0; i < numsprites; i++)
+ {
+ if (!spritepresent[i])
+ continue;
+ for (j = 0; j < sprites[i].numframes; j++)
+ {
+ sf = &sprites[i].spriteframes[j];
+ for (k = 0; k < 8; k++)
+ {
+ lump = firstspritelump + sf->lump[k];
+ spritememory += lumpinfo[lump].size;
+ W_CacheLumpNum(lump, PU_CACHE);
+ }
+ }
+ }
+
+ Z_Free(spritepresent);
+}
diff --git a/src/hexen/r_draw.c b/src/hexen/r_draw.c
new file mode 100644
index 00000000..a4bb2403
--- /dev/null
+++ b/src/hexen/r_draw.c
@@ -0,0 +1,566 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#include "h2def.h"
+#include "i_system.h"
+#include "i_video.h"
+#include "r_local.h"
+#include "v_video.h"
+
+/*
+
+All drawing to the view buffer is accomplished in this file. The other refresh
+files only know about ccordinates, not the architecture of the frame buffer.
+
+*/
+
+byte *viewimage;
+int viewwidth, scaledviewwidth, viewheight, viewwindowx, viewwindowy;
+byte *ylookup[MAXHEIGHT];
+int columnofs[MAXWIDTH];
+//byte translations[3][256]; // color tables for different players
+
+/*
+==================
+=
+= R_DrawColumn
+=
+= Source is the top of the column to scale
+=
+==================
+*/
+
+lighttable_t *dc_colormap;
+int dc_x;
+int dc_yl;
+int dc_yh;
+fixed_t dc_iscale;
+fixed_t dc_texturemid;
+byte *dc_source; // first pixel in a column (possibly virtual)
+
+int dccount; // just for profiling
+
+void R_DrawColumn(void)
+{
+ int count;
+ byte *dest;
+ fixed_t frac, fracstep;
+
+ count = dc_yh - dc_yl;
+ if (count < 0)
+ return;
+
+#ifdef RANGECHECK
+ if ((unsigned) dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+ I_Error("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ fracstep = dc_iscale;
+ frac = dc_texturemid + (dc_yl - centery) * fracstep;
+
+ do
+ {
+ *dest = dc_colormap[dc_source[(frac >> FRACBITS) & 127]];
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ }
+ while (count--);
+}
+
+void R_DrawColumnLow(void)
+{
+ int count;
+ byte *dest;
+ fixed_t frac, fracstep;
+
+ count = dc_yh - dc_yl;
+ if (count < 0)
+ return;
+
+#ifdef RANGECHECK
+ if ((unsigned) dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+ I_Error("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
+// dccount++;
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ fracstep = dc_iscale;
+ frac = dc_texturemid + (dc_yl - centery) * fracstep;
+
+ do
+ {
+ *dest = dc_colormap[dc_source[(frac >> FRACBITS) & 127]];
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ }
+ while (count--);
+}
+
+void R_DrawTLColumn(void)
+{
+ int count;
+ byte *dest;
+ fixed_t frac, fracstep;
+
+ if (!dc_yl)
+ dc_yl = 1;
+ if (dc_yh == viewheight - 1)
+ dc_yh = viewheight - 2;
+
+ count = dc_yh - dc_yl;
+ if (count < 0)
+ return;
+
+#ifdef RANGECHECK
+ if ((unsigned) dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+ I_Error("R_DrawTLColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ fracstep = dc_iscale;
+ frac = dc_texturemid + (dc_yl - centery) * fracstep;
+
+ do
+ {
+ *dest = tinttable[*dest +
+ (dc_colormap[dc_source[(frac >> FRACBITS) & 127]] <<
+ 8)];
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ }
+ while (count--);
+}
+
+//============================================================================
+//
+// R_DrawAltTLColumn
+//
+//============================================================================
+
+void R_DrawAltTLColumn(void)
+{
+ int count;
+ byte *dest;
+ fixed_t frac, fracstep;
+
+ if (!dc_yl)
+ dc_yl = 1;
+ if (dc_yh == viewheight - 1)
+ dc_yh = viewheight - 2;
+
+ count = dc_yh - dc_yl;
+ if (count < 0)
+ return;
+
+#ifdef RANGECHECK
+ if ((unsigned) dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+ I_Error("R_DrawAltTLColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ fracstep = dc_iscale;
+ frac = dc_texturemid + (dc_yl - centery) * fracstep;
+
+ do
+ {
+ *dest = tinttable[((*dest) << 8)
+ + dc_colormap[dc_source[(frac >> FRACBITS) & 127]]];
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ }
+ while (count--);
+}
+
+/*
+========================
+=
+= R_DrawTranslatedColumn
+=
+========================
+*/
+
+byte *dc_translation;
+byte *translationtables;
+
+void R_DrawTranslatedColumn(void)
+{
+ int count;
+ byte *dest;
+ fixed_t frac, fracstep;
+
+ count = dc_yh - dc_yl;
+ if (count < 0)
+ return;
+
+#ifdef RANGECHECK
+ if ((unsigned) dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+ I_Error("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ fracstep = dc_iscale;
+ frac = dc_texturemid + (dc_yl - centery) * fracstep;
+
+ do
+ {
+ *dest = dc_colormap[dc_translation[dc_source[frac >> FRACBITS]]];
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ }
+ while (count--);
+}
+
+//============================================================================
+//
+// R_DrawTranslatedTLColumn
+//
+//============================================================================
+
+void R_DrawTranslatedTLColumn(void)
+{
+ int count;
+ byte *dest;
+ fixed_t frac, fracstep;
+
+ count = dc_yh - dc_yl;
+ if (count < 0)
+ return;
+
+#ifdef RANGECHECK
+ if ((unsigned) dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+ I_Error("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ fracstep = dc_iscale;
+ frac = dc_texturemid + (dc_yl - centery) * fracstep;
+
+ do
+ {
+ *dest = tinttable[((*dest) << 8)
+ +
+ dc_colormap[dc_translation
+ [dc_source[frac >> FRACBITS]]]];
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ }
+ while (count--);
+}
+
+//============================================================================
+//
+// R_DrawTranslatedAltTLColumn
+//
+//============================================================================
+
+/*
+void R_DrawTranslatedAltTLColumn (void)
+{
+ int count;
+ byte *dest;
+ fixed_t frac, fracstep;
+
+ count = dc_yh - dc_yl;
+ if (count < 0)
+ return;
+
+#ifdef RANGECHECK
+ if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+ I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ fracstep = dc_iscale;
+ frac = dc_texturemid + (dc_yl-centery)*fracstep;
+
+ do
+ {
+ *dest = tinttable[*dest
+ +(dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]]<<8)];
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ } while (count--);
+}
+*/
+
+//--------------------------------------------------------------------------
+//
+// PROC R_InitTranslationTables
+//
+//--------------------------------------------------------------------------
+
+void R_InitTranslationTables(void)
+{
+ int i;
+ byte *transLump;
+ int lumpnum;
+
+ V_LoadTintTable();
+
+ // Allocate translation tables
+ translationtables = Z_Malloc(256 * 3 * (MAXPLAYERS - 1), PU_STATIC, 0);
+
+ for (i = 0; i < 3 * (MAXPLAYERS - 1); i++)
+ {
+ lumpnum = W_GetNumForName("trantbl0") + i;
+ transLump = W_CacheLumpNum(lumpnum, PU_STATIC);
+ memcpy(translationtables + i * 256, transLump, 256);
+ W_ReleaseLumpNum(lumpnum);
+ }
+}
+
+/*
+================
+=
+= R_DrawSpan
+=
+================
+*/
+
+int ds_y;
+int ds_x1;
+int ds_x2;
+lighttable_t *ds_colormap;
+fixed_t ds_xfrac;
+fixed_t ds_yfrac;
+fixed_t ds_xstep;
+fixed_t ds_ystep;
+byte *ds_source; // start of a 64*64 tile image
+
+int dscount; // just for profiling
+
+void R_DrawSpan(void)
+{
+ fixed_t xfrac, yfrac;
+ byte *dest;
+ int count, spot;
+
+#ifdef RANGECHECK
+ if (ds_x2 < ds_x1 || ds_x1 < 0 || ds_x2 >= SCREENWIDTH
+ || (unsigned) ds_y > SCREENHEIGHT)
+ I_Error("R_DrawSpan: %i to %i at %i", ds_x1, ds_x2, ds_y);
+// dscount++;
+#endif
+
+ xfrac = ds_xfrac;
+ yfrac = ds_yfrac;
+
+ dest = ylookup[ds_y] + columnofs[ds_x1];
+ count = ds_x2 - ds_x1;
+ do
+ {
+ spot = ((yfrac >> (16 - 6)) & (63 * 64)) + ((xfrac >> 16) & 63);
+ *dest++ = ds_colormap[ds_source[spot]];
+ xfrac += ds_xstep;
+ yfrac += ds_ystep;
+ }
+ while (count--);
+}
+
+void R_DrawSpanLow(void)
+{
+ fixed_t xfrac, yfrac;
+ byte *dest;
+ int count, spot;
+
+#ifdef RANGECHECK
+ if (ds_x2 < ds_x1 || ds_x1 < 0 || ds_x2 >= SCREENWIDTH
+ || (unsigned) ds_y > SCREENHEIGHT)
+ I_Error("R_DrawSpan: %i to %i at %i", ds_x1, ds_x2, ds_y);
+// dscount++;
+#endif
+
+ xfrac = ds_xfrac;
+ yfrac = ds_yfrac;
+
+ dest = ylookup[ds_y] + columnofs[ds_x1];
+ count = ds_x2 - ds_x1;
+ do
+ {
+ spot = ((yfrac >> (16 - 6)) & (63 * 64)) + ((xfrac >> 16) & 63);
+ *dest++ = ds_colormap[ds_source[spot]];
+ xfrac += ds_xstep;
+ yfrac += ds_ystep;
+ }
+ while (count--);
+}
+
+
+
+/*
+================
+=
+= R_InitBuffer
+=
+=================
+*/
+
+void R_InitBuffer(int width, int height)
+{
+ int i;
+
+ viewwindowx = (SCREENWIDTH - width) >> 1;
+ for (i = 0; i < width; i++)
+ columnofs[i] = viewwindowx + i;
+ if (width == SCREENWIDTH)
+ viewwindowy = 0;
+ else
+ viewwindowy = (SCREENHEIGHT - SBARHEIGHT - height) >> 1;
+ for (i = 0; i < height; i++)
+ ylookup[i] = I_VideoBuffer + (i + viewwindowy) * SCREENWIDTH;
+}
+
+
+/*
+==================
+=
+= R_DrawViewBorder
+=
+= Draws the border around the view for different size windows
+==================
+*/
+
+boolean BorderNeedRefresh;
+
+void R_DrawViewBorder(void)
+{
+ byte *src, *dest;
+ int x, y;
+
+ if (scaledviewwidth == SCREENWIDTH)
+ return;
+
+ src = W_CacheLumpName("F_022", PU_CACHE);
+ dest = I_VideoBuffer;
+
+ for (y = 0; y < SCREENHEIGHT - SBARHEIGHT; y++)
+ {
+ for (x = 0; x < SCREENWIDTH / 64; x++)
+ {
+ memcpy(dest, src + ((y & 63) << 6), 64);
+ dest += 64;
+ }
+ if (SCREENWIDTH & 63)
+ {
+ memcpy(dest, src + ((y & 63) << 6), SCREENWIDTH & 63);
+ dest += (SCREENWIDTH & 63);
+ }
+ }
+ for (x = viewwindowx; x < viewwindowx + viewwidth; x += 16)
+ {
+ V_DrawPatch(x, viewwindowy - 4, W_CacheLumpName("bordt", PU_CACHE));
+ V_DrawPatch(x, viewwindowy + viewheight, W_CacheLumpName("bordb",
+ PU_CACHE));
+ }
+ for (y = viewwindowy; y < viewwindowy + viewheight; y += 16)
+ {
+ V_DrawPatch(viewwindowx - 4, y, W_CacheLumpName("bordl", PU_CACHE));
+ V_DrawPatch(viewwindowx + viewwidth, y, W_CacheLumpName("bordr",
+ PU_CACHE));
+ }
+ V_DrawPatch(viewwindowx - 4, viewwindowy - 4, W_CacheLumpName("bordtl",
+ PU_CACHE));
+ V_DrawPatch(viewwindowx + viewwidth, viewwindowy - 4,
+ W_CacheLumpName("bordtr", PU_CACHE));
+ V_DrawPatch(viewwindowx + viewwidth, viewwindowy + viewheight,
+ W_CacheLumpName("bordbr", PU_CACHE));
+ V_DrawPatch(viewwindowx - 4, viewwindowy + viewheight,
+ W_CacheLumpName("bordbl", PU_CACHE));
+}
+
+/*
+==================
+=
+= R_DrawTopBorder
+=
+= Draws the top border around the view for different size windows
+==================
+*/
+
+boolean BorderTopRefresh;
+
+void R_DrawTopBorder(void)
+{
+ byte *src, *dest;
+ int x, y;
+
+ if (scaledviewwidth == SCREENWIDTH)
+ return;
+
+/* if(gamemode == shareware)
+ {
+ src = W_CacheLumpName ("FLOOR04", PU_CACHE);
+ }
+ else
+ {
+ src = W_CacheLumpName ("FLAT513", PU_CACHE);
+ }
+*/
+ src = W_CacheLumpName("F_022", PU_CACHE);
+ dest = I_VideoBuffer;
+
+ for (y = 0; y < 34; y++)
+ {
+ for (x = 0; x < SCREENWIDTH / 64; x++)
+ {
+ memcpy(dest, src + ((y & 63) << 6), 64);
+ dest += 64;
+ }
+ if (SCREENWIDTH & 63)
+ {
+ memcpy(dest, src + ((y & 63) << 6), SCREENWIDTH & 63);
+ dest += (SCREENWIDTH & 63);
+ }
+ }
+ if (viewwindowy < 35)
+ {
+ for (x = viewwindowx; x < viewwindowx + viewwidth; x += 16)
+ {
+ V_DrawPatch(x, viewwindowy - 4,
+ W_CacheLumpName("bordt", PU_CACHE));
+ }
+ V_DrawPatch(viewwindowx - 4, viewwindowy, W_CacheLumpName("bordl",
+ PU_CACHE));
+ V_DrawPatch(viewwindowx + viewwidth, viewwindowy,
+ W_CacheLumpName("bordr", PU_CACHE));
+ V_DrawPatch(viewwindowx - 4, viewwindowy + 16,
+ W_CacheLumpName("bordl", PU_CACHE));
+ V_DrawPatch(viewwindowx + viewwidth, viewwindowy + 16,
+ W_CacheLumpName("bordr", PU_CACHE));
+
+ V_DrawPatch(viewwindowx - 4, viewwindowy - 4,
+ W_CacheLumpName("bordtl", PU_CACHE));
+ V_DrawPatch(viewwindowx + viewwidth, viewwindowy - 4,
+ W_CacheLumpName("bordtr", PU_CACHE));
+ }
+}
diff --git a/src/hexen/r_local.h b/src/hexen/r_local.h
new file mode 100644
index 00000000..8e34ea63
--- /dev/null
+++ b/src/hexen/r_local.h
@@ -0,0 +1,552 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __R_LOCAL__
+#define __R_LOCAL__
+
+#include "i_video.h"
+
+#define ANGLETOSKYSHIFT 22 // sky map is 256*128*4 maps
+
+#define BASEYCENTER 100
+
+#define MAXWIDTH 1120
+#define MAXHEIGHT 832
+
+#define PI 3.141592657
+
+#define CENTERY (SCREENHEIGHT/2)
+
+#define MINZ (FRACUNIT*4)
+
+#define FIELDOFVIEW 2048 // fineangles in the SCREENWIDTH wide window
+
+//
+// lighting constants
+//
+#define LIGHTLEVELS 16
+#define LIGHTSEGSHIFT 4
+#define MAXLIGHTSCALE 48
+#define LIGHTSCALESHIFT 12
+#define MAXLIGHTZ 128
+#define LIGHTZSHIFT 20
+#define NUMCOLORMAPS 32 // number of diminishing
+#define INVERSECOLORMAP 32
+
+/*
+==============================================================================
+
+ INTERNAL MAP TYPES
+
+==============================================================================
+*/
+
+//================ used by play and refresh
+
+typedef struct
+{
+ fixed_t x, y;
+} vertex_t;
+
+struct line_s;
+
+typedef struct
+{
+ fixed_t floorheight, ceilingheight;
+ short floorpic, ceilingpic;
+ short lightlevel;
+ short special, tag;
+
+ int soundtraversed; // 0 = untraversed, 1,2 = sndlines -1
+ mobj_t *soundtarget; // thing that made a sound (or null)
+ seqtype_t seqType; // stone, metal, heavy, etc...
+
+ int blockbox[4]; // mapblock bounding box for height changes
+ degenmobj_t soundorg; // for any sounds played by the sector
+ int validcount; // if == validcount, already checked
+ mobj_t *thinglist; // list of mobjs in sector
+ void *specialdata; // thinker_t for reversable actions
+ int linecount;
+ struct line_s **lines; // [linecount] size
+} sector_t;
+
+typedef struct
+{
+ fixed_t textureoffset; // add this to the calculated texture col
+ fixed_t rowoffset; // add this to the calculated texture top
+ short toptexture, bottomtexture, midtexture;
+ sector_t *sector;
+} side_t;
+
+typedef enum
+{
+ ST_HORIZONTAL,
+ ST_VERTICAL,
+ ST_POSITIVE,
+ ST_NEGATIVE
+} slopetype_t;
+
+/*
+typedef struct line_s
+{
+ vertex_t *v1, *v2;
+ fixed_t dx,dy; // v2 - v1 for side checking
+ short flags;
+ short special, tag;
+ short sidenum[2]; // sidenum[1] will be -1 if one sided
+ fixed_t bbox[4];
+ slopetype_t slopetype; // to aid move clipping
+ sector_t *frontsector, *backsector;
+ int validcount; // if == validcount, already checked
+ void *specialdata; // thinker_t for reversable actions
+} line_t;
+*/
+
+typedef struct line_s
+{
+ vertex_t *v1;
+ vertex_t *v2;
+ fixed_t dx;
+ fixed_t dy;
+ short flags;
+ byte special;
+ byte arg1;
+ byte arg2;
+ byte arg3;
+ byte arg4;
+ byte arg5;
+ short sidenum[2];
+ fixed_t bbox[4];
+ slopetype_t slopetype;
+ sector_t *frontsector;
+ sector_t *backsector;
+ int validcount;
+ void *specialdata;
+} line_t;
+
+typedef struct
+{
+ vertex_t *v1, *v2;
+ fixed_t offset;
+ angle_t angle;
+ side_t *sidedef;
+ line_t *linedef;
+ sector_t *frontsector;
+ sector_t *backsector; // NULL for one sided lines
+} seg_t;
+
+// ===== Polyobj data =====
+typedef struct
+{
+ int numsegs;
+ seg_t **segs;
+ degenmobj_t startSpot;
+ vertex_t *originalPts; // used as the base for the rotations
+ vertex_t *prevPts; // use to restore the old point values
+ angle_t angle;
+ int tag; // reference tag assigned in HereticEd
+ int bbox[4];
+ int validcount;
+ boolean crush; // should the polyobj attempt to crush mobjs?
+ int seqType;
+ fixed_t size; // polyobj size (area of POLY_AREAUNIT == size of FRACUNIT)
+ void *specialdata; // pointer a thinker, if the poly is moving
+} polyobj_t;
+
+typedef struct polyblock_s
+{
+ polyobj_t *polyobj;
+ struct polyblock_s *prev;
+ struct polyblock_s *next;
+} polyblock_t;
+
+typedef struct subsector_s
+{
+ sector_t *sector;
+ short numlines;
+ short firstline;
+ polyobj_t *poly;
+} subsector_t;
+
+typedef struct
+{
+ fixed_t x, y, dx, dy; // partition line
+ fixed_t bbox[2][4]; // bounding box for each child
+ unsigned short children[2]; // if NF_SUBSECTOR its a subsector
+} node_t;
+
+
+/*
+==============================================================================
+
+ OTHER TYPES
+
+==============================================================================
+*/
+
+typedef byte lighttable_t; // this could be wider for >8 bit display
+
+#define MAXVISPLANES 160
+#define MAXOPENINGS SCREENWIDTH*64
+
+typedef struct
+{
+ fixed_t height;
+ int picnum;
+ int lightlevel;
+ int special;
+ int minx, maxx;
+ byte pad1; // leave pads for [minx-1]/[maxx+1]
+ byte top[SCREENWIDTH];
+ byte pad2;
+ byte pad3;
+ byte bottom[SCREENWIDTH];
+ byte pad4;
+} visplane_t;
+
+typedef struct drawseg_s
+{
+ seg_t *curline;
+ int x1, x2;
+ fixed_t scale1, scale2, scalestep;
+ int silhouette; // 0=none, 1=bottom, 2=top, 3=both
+ fixed_t bsilheight; // don't clip sprites above this
+ fixed_t tsilheight; // don't clip sprites below this
+// pointers to lists for sprite clipping
+ short *sprtopclip; // adjusted so [x1] is first value
+ short *sprbottomclip; // adjusted so [x1] is first value
+ short *maskedtexturecol; // adjusted so [x1] is first value
+} drawseg_t;
+
+#define SIL_NONE 0
+#define SIL_BOTTOM 1
+#define SIL_TOP 2
+#define SIL_BOTH 3
+
+#define MAXDRAWSEGS 256
+
+// A vissprite_t is a thing that will be drawn during a refresh
+typedef struct vissprite_s
+{
+ struct vissprite_s *prev, *next;
+ int x1, x2;
+ fixed_t gx, gy; // for line side calculation
+ fixed_t gz, gzt; // global bottom / top for silhouette clipping
+ fixed_t startfrac; // horizontal position of x1
+ fixed_t scale;
+ fixed_t xiscale; // negative if flipped
+ fixed_t texturemid;
+ int patch;
+ lighttable_t *colormap;
+ int mobjflags; // for color translation and shadow draw
+ boolean psprite; // true if psprite
+ int class; // player class (used in translation)
+ fixed_t floorclip;
+} vissprite_t;
+
+
+extern visplane_t *floorplane, *ceilingplane;
+
+// Sprites are patches with a special naming convention so they can be
+// recognized by R_InitSprites. The sprite and frame specified by a
+// thing_t is range checked at run time.
+// a sprite is a patch_t that is assumed to represent a three dimensional
+// object and may have multiple rotations pre drawn. Horizontal flipping
+// is used to save space. Some sprites will only have one picture used
+// for all views.
+
+typedef struct
+{
+ boolean rotate; // if false use 0 for any position
+ short lump[8]; // lump to use for view angles 0-7
+ byte flip[8]; // flip (1 = flip) to use for view angles 0-7
+} spriteframe_t;
+
+typedef struct
+{
+ int numframes;
+ spriteframe_t *spriteframes;
+} spritedef_t;
+
+extern spritedef_t *sprites;
+extern int numsprites;
+
+//=============================================================================
+
+extern int numvertexes;
+extern vertex_t *vertexes;
+
+extern int numsegs;
+extern seg_t *segs;
+
+extern int numsectors;
+extern sector_t *sectors;
+
+extern int numsubsectors;
+extern subsector_t *subsectors;
+
+extern int numnodes;
+extern node_t *nodes;
+
+extern int numlines;
+extern line_t *lines;
+
+extern int numsides;
+extern side_t *sides;
+
+
+
+extern fixed_t viewx, viewy, viewz;
+extern angle_t viewangle;
+extern player_t *viewplayer;
+
+
+extern angle_t clipangle;
+
+extern int viewangletox[FINEANGLES / 2];
+extern angle_t xtoviewangle[SCREENWIDTH + 1];
+
+extern fixed_t rw_distance;
+extern angle_t rw_normalangle;
+
+//
+// R_main.c
+//
+extern int screenblocks;
+extern int viewwidth, viewheight, viewwindowx, viewwindowy;
+extern int scaledviewwidth;
+extern int centerx, centery;
+extern int flyheight;
+extern fixed_t centerxfrac;
+extern fixed_t centeryfrac;
+extern fixed_t projection;
+
+extern int validcount;
+
+extern int sscount, linecount, loopcount;
+extern lighttable_t *scalelight[LIGHTLEVELS][MAXLIGHTSCALE];
+extern lighttable_t *scalelightfixed[MAXLIGHTSCALE];
+extern lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ];
+
+extern int extralight;
+extern lighttable_t *fixedcolormap;
+
+extern fixed_t viewcos, viewsin;
+
+extern int detailshift; // 0 = high, 1 = low
+
+extern void (*colfunc) (void);
+extern void (*basecolfunc) (void);
+extern void (*tlcolfunc) (void);
+extern void (*spanfunc) (void);
+
+int R_PointOnSide(fixed_t x, fixed_t y, node_t * node);
+int R_PointOnSegSide(fixed_t x, fixed_t y, seg_t * line);
+angle_t R_PointToAngle(fixed_t x, fixed_t y);
+angle_t R_PointToAngle2(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2);
+fixed_t R_PointToDist(fixed_t x, fixed_t y);
+fixed_t R_ScaleFromGlobalAngle(angle_t visangle);
+subsector_t *R_PointInSubsector(fixed_t x, fixed_t y);
+//void R_AddPointToBox (int x, int y, fixed_t *box);
+
+
+//
+// R_bsp.c
+//
+extern seg_t *curline;
+extern side_t *sidedef;
+extern line_t *linedef;
+extern sector_t *frontsector, *backsector;
+
+extern int rw_x;
+extern int rw_stopx;
+
+extern boolean segtextured;
+extern boolean markfloor; // false if the back side is the same plane
+extern boolean markceiling;
+extern boolean skymap;
+
+extern drawseg_t drawsegs[MAXDRAWSEGS], *ds_p;
+
+extern lighttable_t **hscalelight, **vscalelight, **dscalelight;
+
+typedef void (*drawfunc_t) (int start, int stop);
+void R_ClearClipSegs(void);
+
+void R_ClearDrawSegs(void);
+void R_InitSkyMap(void);
+void R_RenderBSPNode(int bspnum);
+
+//
+// R_segs.c
+//
+extern int rw_angle1; // angle to line origin
+extern int TransTextureStart;
+extern int TransTextureEnd;
+
+void R_RenderMaskedSegRange(drawseg_t * ds, int x1, int x2);
+
+//
+// R_plane.c
+//
+typedef void (*planefunction_t) (int top, int bottom);
+extern planefunction_t floorfunc, ceilingfunc;
+
+extern int skyflatnum;
+
+extern short openings[MAXOPENINGS], *lastopening;
+
+extern short floorclip[SCREENWIDTH];
+extern short ceilingclip[SCREENWIDTH];
+
+extern fixed_t yslope[SCREENHEIGHT];
+extern fixed_t distscale[SCREENWIDTH];
+
+void R_InitPlanes(void);
+void R_ClearPlanes(void);
+void R_MapPlane(int y, int x1, int x2);
+void R_MakeSpans(int x, int t1, int b1, int t2, int b2);
+void R_DrawPlanes(void);
+
+visplane_t *R_FindPlane(fixed_t height, int picnum, int lightlevel,
+ int special);
+visplane_t *R_CheckPlane(visplane_t * pl, int start, int stop);
+
+
+//
+// R_debug.m
+//
+extern int drawbsp;
+
+void RD_OpenMapWindow(void);
+void RD_ClearMapWindow(void);
+void RD_DisplayLine(int x1, int y1, int x2, int y2, float gray);
+void RD_DrawNodeLine(node_t * node);
+void RD_DrawLineCheck(seg_t * line);
+void RD_DrawLine(seg_t * line);
+void RD_DrawBBox(fixed_t * bbox);
+
+
+//
+// R_data.c
+//
+extern fixed_t *textureheight; // needed for texture pegging
+extern fixed_t *spritewidth; // needed for pre rendering (fracs)
+extern fixed_t *spriteoffset;
+extern fixed_t *spritetopoffset;
+extern lighttable_t *colormaps;
+extern int firstflat;
+extern int numflats;
+
+extern int *flattranslation; // for global animation
+extern int *texturetranslation; // for global animation
+
+extern int firstspritelump, lastspritelump, numspritelumps;
+extern boolean LevelUseFullBright;
+
+byte *R_GetColumn(int tex, int col);
+void R_InitData(void);
+void R_PrecacheLevel(void);
+
+
+//
+// R_things.c
+//
+#define MAXVISSPRITES 192
+
+extern vissprite_t vissprites[MAXVISSPRITES], *vissprite_p;
+extern vissprite_t vsprsortedhead;
+
+// constant arrays used for psprite clipping and initializing clipping
+extern short negonearray[SCREENWIDTH];
+extern short screenheightarray[SCREENWIDTH];
+
+// vars for R_DrawMaskedColumn
+extern short *mfloorclip;
+extern short *mceilingclip;
+extern fixed_t spryscale;
+extern fixed_t sprtopscreen;
+extern fixed_t sprbotscreen;
+
+extern fixed_t pspritescale, pspriteiscale;
+
+
+void R_DrawMaskedColumn(column_t * column, signed int baseclip);
+
+
+void R_SortVisSprites(void);
+
+void R_AddSprites(sector_t * sec);
+void R_AddPSprites(void);
+void R_DrawSprites(void);
+void R_InitSprites(char **namelist);
+void R_ClearSprites(void);
+void R_DrawMasked(void);
+void R_ClipVisSprite(vissprite_t * vis, int xl, int xh);
+
+//=============================================================================
+//
+// R_draw.c
+//
+//=============================================================================
+
+extern lighttable_t *dc_colormap;
+extern int dc_x;
+extern int dc_yl;
+extern int dc_yh;
+extern fixed_t dc_iscale;
+extern fixed_t dc_texturemid;
+extern byte *dc_source; // first pixel in a column
+
+void R_DrawColumn(void);
+void R_DrawColumnLow(void);
+void R_DrawTLColumn(void);
+void R_DrawTLColumnLow(void);
+void R_DrawTranslatedColumn(void);
+void R_DrawTranslatedTLColumn(void);
+void R_DrawTranslatedColumnLow(void);
+void R_DrawAltTLColumn(void);
+//void R_DrawTranslatedAltTLColumn(void);
+
+extern int ds_y;
+extern int ds_x1;
+extern int ds_x2;
+extern lighttable_t *ds_colormap;
+extern fixed_t ds_xfrac;
+extern fixed_t ds_yfrac;
+extern fixed_t ds_xstep;
+extern fixed_t ds_ystep;
+extern byte *ds_source; // start of a 64*64 tile image
+
+extern byte *translationtables;
+extern byte *dc_translation;
+
+void R_DrawSpan(void);
+void R_DrawSpanLow(void);
+
+void R_InitBuffer(int width, int height);
+void R_InitTranslationTables(void);
+
+#endif // __R_LOCAL__
diff --git a/src/hexen/r_main.c b/src/hexen/r_main.c
new file mode 100644
index 00000000..48e21ab2
--- /dev/null
+++ b/src/hexen/r_main.c
@@ -0,0 +1,839 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#include <math.h>
+#include "m_random.h"
+#include "h2def.h"
+#include "m_bbox.h"
+#include "r_local.h"
+
+int viewangleoffset;
+
+// haleyjd: removed WATCOMC
+
+int validcount = 1; // increment every time a check is made
+
+lighttable_t *fixedcolormap;
+extern lighttable_t **walllights;
+
+int centerx, centery;
+fixed_t centerxfrac, centeryfrac;
+fixed_t projection;
+
+int framecount; // just for profiling purposes
+
+int sscount, linecount, loopcount;
+
+fixed_t viewx, viewy, viewz;
+angle_t viewangle;
+fixed_t viewcos, viewsin;
+player_t *viewplayer;
+
+int detailshift; // 0 = high, 1 = low
+
+//
+// precalculated math tables
+//
+angle_t clipangle;
+
+// The viewangletox[viewangle + FINEANGLES/4] lookup maps the visible view
+// angles to screen X coordinates, flattening the arc to a flat projection
+// plane. There will be many angles mapped to the same X.
+int viewangletox[FINEANGLES / 2];
+
+// The xtoviewangleangle[] table maps a screen pixel to the lowest viewangle
+// that maps back to x ranges from clipangle to -clipangle
+angle_t xtoviewangle[SCREENWIDTH + 1];
+
+lighttable_t *scalelight[LIGHTLEVELS][MAXLIGHTSCALE];
+lighttable_t *scalelightfixed[MAXLIGHTSCALE];
+lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ];
+
+int extralight; // bumped light from gun blasts
+
+void (*colfunc) (void);
+void (*basecolfunc) (void);
+void (*tlcolfunc) (void);
+void (*transcolfunc) (void);
+void (*spanfunc) (void);
+
+/*
+===================
+=
+= R_AddPointToBox
+=
+===================
+*/
+
+/*
+void R_AddPointToBox (int x, int y, fixed_t *box)
+{
+ if (x< box[BOXLEFT])
+ box[BOXLEFT] = x;
+ if (x> box[BOXRIGHT])
+ box[BOXRIGHT] = x;
+ if (y< box[BOXBOTTOM])
+ box[BOXBOTTOM] = y;
+ if (y> box[BOXTOP])
+ box[BOXTOP] = y;
+}
+*/
+
+
+/*
+===============================================================================
+=
+= R_PointOnSide
+=
+= Returns side 0 (front) or 1 (back)
+===============================================================================
+*/
+
+int R_PointOnSide(fixed_t x, fixed_t y, node_t * node)
+{
+ fixed_t dx, dy;
+ fixed_t left, right;
+
+ if (!node->dx)
+ {
+ if (x <= node->x)
+ return node->dy > 0;
+ return node->dy < 0;
+ }
+ if (!node->dy)
+ {
+ if (y <= node->y)
+ return node->dx < 0;
+ return node->dx > 0;
+ }
+
+ dx = (x - node->x);
+ dy = (y - node->y);
+
+// try to quickly decide by looking at sign bits
+ if ((node->dy ^ node->dx ^ dx ^ dy) & 0x80000000)
+ {
+ if ((node->dy ^ dx) & 0x80000000)
+ return 1; // (left is negative)
+ return 0;
+ }
+
+ left = FixedMul(node->dy >> FRACBITS, dx);
+ right = FixedMul(dy, node->dx >> FRACBITS);
+
+ if (right < left)
+ return 0; // front side
+ return 1; // back side
+}
+
+
+int R_PointOnSegSide(fixed_t x, fixed_t y, seg_t * line)
+{
+ fixed_t lx, ly;
+ fixed_t ldx, ldy;
+ fixed_t dx, dy;
+ fixed_t left, right;
+
+ lx = line->v1->x;
+ ly = line->v1->y;
+
+ ldx = line->v2->x - lx;
+ ldy = line->v2->y - ly;
+
+ if (!ldx)
+ {
+ if (x <= lx)
+ return ldy > 0;
+ return ldy < 0;
+ }
+ if (!ldy)
+ {
+ if (y <= ly)
+ return ldx < 0;
+ return ldx > 0;
+ }
+
+ dx = (x - lx);
+ dy = (y - ly);
+
+// try to quickly decide by looking at sign bits
+ if ((ldy ^ ldx ^ dx ^ dy) & 0x80000000)
+ {
+ if ((ldy ^ dx) & 0x80000000)
+ return 1; // (left is negative)
+ return 0;
+ }
+
+ left = FixedMul(ldy >> FRACBITS, dx);
+ right = FixedMul(dy, ldx >> FRACBITS);
+
+ if (right < left)
+ return 0; // front side
+ return 1; // back side
+}
+
+
+/*
+===============================================================================
+=
+= R_PointToAngle
+=
+===============================================================================
+*/
+
+#define DBITS (FRACBITS-SLOPEBITS)
+
+angle_t R_PointToAngle(fixed_t x, fixed_t y)
+{
+ x -= viewx;
+ y -= viewy;
+ if ((!x) && (!y))
+ return 0;
+ if (x >= 0)
+ { // x >=0
+ if (y >= 0)
+ { // y>= 0
+ if (x > y)
+ return tantoangle[SlopeDiv(y, x)]; // octant 0
+ else
+ return ANG90 - 1 - tantoangle[SlopeDiv(x, y)]; // octant 1
+ }
+ else
+ { // y<0
+ y = -y;
+ if (x > y)
+ return -tantoangle[SlopeDiv(y, x)]; // octant 8
+ else
+ return ANG270 + tantoangle[SlopeDiv(x, y)]; // octant 7
+ }
+ }
+ else
+ { // x<0
+ x = -x;
+ if (y >= 0)
+ { // y>= 0
+ if (x > y)
+ return ANG180 - 1 - tantoangle[SlopeDiv(y, x)]; // octant 3
+ else
+ return ANG90 + tantoangle[SlopeDiv(x, y)]; // octant 2
+ }
+ else
+ { // y<0
+ y = -y;
+ if (x > y)
+ return ANG180 + tantoangle[SlopeDiv(y, x)]; // octant 4
+ else
+ return ANG270 - 1 - tantoangle[SlopeDiv(x, y)]; // octant 5
+ }
+ }
+
+ return 0;
+}
+
+
+angle_t R_PointToAngle2(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)
+{
+ viewx = x1;
+ viewy = y1;
+ return R_PointToAngle(x2, y2);
+}
+
+
+fixed_t R_PointToDist(fixed_t x, fixed_t y)
+{
+ int angle;
+ fixed_t dx, dy, temp;
+ fixed_t dist;
+
+ dx = abs(x - viewx);
+ dy = abs(y - viewy);
+
+ if (dy > dx)
+ {
+ temp = dx;
+ dx = dy;
+ dy = temp;
+ }
+
+ angle =
+ (tantoangle[FixedDiv(dy, dx) >> DBITS] + ANG90) >> ANGLETOFINESHIFT;
+
+ dist = FixedDiv(dx, finesine[angle]); // use as cosine
+
+ return dist;
+}
+
+
+
+/*
+=================
+=
+= R_InitPointToAngle
+=
+=================
+*/
+
+void R_InitPointToAngle(void)
+{
+// now getting from tables.c
+#if 0
+ int i;
+ long t;
+ float f;
+//
+// slope (tangent) to angle lookup
+//
+ for (i = 0; i <= SLOPERANGE; i++)
+ {
+ f = atan((float) i / SLOPERANGE) / (3.141592657 * 2);
+ t = 0xffffffff * f;
+ tantoangle[i] = t;
+ }
+#endif
+}
+
+//=============================================================================
+
+/*
+================
+=
+= R_ScaleFromGlobalAngle
+=
+= Returns the texture mapping scale for the current line at the given angle
+= rw_distance must be calculated first
+================
+*/
+
+fixed_t R_ScaleFromGlobalAngle(angle_t visangle)
+{
+ fixed_t scale;
+ int anglea, angleb;
+ int sinea, sineb;
+ fixed_t num, den;
+
+#if 0
+ {
+ fixed_t dist, z;
+ fixed_t sinv, cosv;
+
+ sinv = finesine[(visangle - rw_normalangle) >> ANGLETOFINESHIFT];
+ dist = FixedDiv(rw_distance, sinv);
+ cosv = finecosine[(viewangle - visangle) >> ANGLETOFINESHIFT];
+ z = abs(FixedMul(dist, cosv));
+ scale = FixedDiv(projection, z);
+ return scale;
+ }
+#endif
+
+ anglea = ANG90 + (visangle - viewangle);
+ angleb = ANG90 + (visangle - rw_normalangle);
+// bothe sines are allways positive
+ sinea = finesine[anglea >> ANGLETOFINESHIFT];
+ sineb = finesine[angleb >> ANGLETOFINESHIFT];
+ num = FixedMul(projection, sineb) << detailshift;
+ den = FixedMul(rw_distance, sinea);
+ if (den > num >> 16)
+ {
+ scale = FixedDiv(num, den);
+ if (scale > 64 * FRACUNIT)
+ scale = 64 * FRACUNIT;
+ else if (scale < 256)
+ scale = 256;
+ }
+ else
+ scale = 64 * FRACUNIT;
+
+ return scale;
+}
+
+
+
+/*
+=================
+=
+= R_InitTables
+=
+=================
+*/
+
+void R_InitTables(void)
+{
+// now getting from tables.c
+#if 0
+ int i;
+ float a, fv;
+ int t;
+
+//
+// viewangle tangent table
+//
+ for (i = 0; i < FINEANGLES / 2; i++)
+ {
+ a = (i - FINEANGLES / 4 + 0.5) * PI * 2 / FINEANGLES;
+ fv = FRACUNIT * tan(a);
+ t = fv;
+ finetangent[i] = t;
+ }
+
+//
+// finesine table
+//
+ for (i = 0; i < 5 * FINEANGLES / 4; i++)
+ {
+// OPTIMIZE: mirror...
+ a = (i + 0.5) * PI * 2 / FINEANGLES;
+ t = FRACUNIT * sin(a);
+ finesine[i] = t;
+ }
+#endif
+
+}
+
+
+/*
+=================
+=
+= R_InitTextureMapping
+=
+=================
+*/
+
+void R_InitTextureMapping(void)
+{
+ int i;
+ int x;
+ int t;
+ fixed_t focallength;
+
+
+//
+// use tangent table to generate viewangletox
+// viewangletox will give the next greatest x after the view angle
+//
+ // calc focallength so FIELDOFVIEW angles covers SCREENWIDTH
+ focallength =
+ FixedDiv(centerxfrac, finetangent[FINEANGLES / 4 + FIELDOFVIEW / 2]);
+
+ for (i = 0; i < FINEANGLES / 2; i++)
+ {
+ if (finetangent[i] > FRACUNIT * 2)
+ t = -1;
+ else if (finetangent[i] < -FRACUNIT * 2)
+ t = viewwidth + 1;
+ else
+ {
+ t = FixedMul(finetangent[i], focallength);
+ t = (centerxfrac - t + FRACUNIT - 1) >> FRACBITS;
+ if (t < -1)
+ t = -1;
+ else if (t > viewwidth + 1)
+ t = viewwidth + 1;
+ }
+ viewangletox[i] = t;
+ }
+
+//
+// scan viewangletox[] to generate xtoviewangleangle[]
+//
+// xtoviewangle will give the smallest view angle that maps to x
+ for (x = 0; x <= viewwidth; x++)
+ {
+ i = 0;
+ while (viewangletox[i] > x)
+ i++;
+ xtoviewangle[x] = (i << ANGLETOFINESHIFT) - ANG90;
+ }
+
+//
+// take out the fencepost cases from viewangletox
+//
+ for (i = 0; i < FINEANGLES / 2; i++)
+ {
+ t = FixedMul(finetangent[i], focallength);
+ t = centerx - t;
+ if (viewangletox[i] == -1)
+ viewangletox[i] = 0;
+ else if (viewangletox[i] == viewwidth + 1)
+ viewangletox[i] = viewwidth;
+ }
+
+ clipangle = xtoviewangle[0];
+}
+
+//=============================================================================
+
+/*
+====================
+=
+= R_InitLightTables
+=
+= Only inits the zlight table, because the scalelight table changes
+= with view size
+=
+====================
+*/
+
+#define DISTMAP 2
+
+void R_InitLightTables(void)
+{
+ int i, j, level, startmap;
+ int scale;
+
+//
+// Calculate the light levels to use for each level / distance combination
+//
+ for (i = 0; i < LIGHTLEVELS; i++)
+ {
+ startmap = ((LIGHTLEVELS - 1 - i) * 2) * NUMCOLORMAPS / LIGHTLEVELS;
+ for (j = 0; j < MAXLIGHTZ; j++)
+ {
+ scale =
+ FixedDiv((SCREENWIDTH / 2 * FRACUNIT),
+ (j + 1) << LIGHTZSHIFT);
+ scale >>= LIGHTSCALESHIFT;
+ level = startmap - scale / DISTMAP;
+ if (level < 0)
+ level = 0;
+ if (level >= NUMCOLORMAPS)
+ level = NUMCOLORMAPS - 1;
+ zlight[i][j] = colormaps + level * 256;
+ }
+ }
+}
+
+
+/*
+==============
+=
+= R_SetViewSize
+=
+= Don't really change anything here, because i might be in the middle of
+= a refresh. The change will take effect next refresh.
+=
+==============
+*/
+
+boolean setsizeneeded;
+int setblocks, setdetail;
+
+void R_SetViewSize(int blocks, int detail)
+{
+ setsizeneeded = true;
+ setblocks = blocks;
+ setdetail = detail;
+}
+
+/*
+==============
+=
+= R_ExecuteSetViewSize
+=
+==============
+*/
+
+void R_ExecuteSetViewSize(void)
+{
+ fixed_t cosadj, dy;
+ int i, j, level, startmap;
+
+ setsizeneeded = false;
+
+ if (setblocks == 11)
+ {
+ scaledviewwidth = SCREENWIDTH;
+ viewheight = SCREENHEIGHT;
+ }
+ else
+ {
+ scaledviewwidth = setblocks * 32;
+ viewheight = (setblocks * 161 / 10);
+ }
+
+ detailshift = setdetail;
+ viewwidth = scaledviewwidth >> detailshift;
+
+ centery = viewheight / 2;
+ centerx = viewwidth / 2;
+ centerxfrac = centerx << FRACBITS;
+ centeryfrac = centery << FRACBITS;
+ projection = centerxfrac;
+
+ if (!detailshift)
+ {
+ colfunc = basecolfunc = R_DrawColumn;
+ tlcolfunc = R_DrawTLColumn;
+ transcolfunc = R_DrawTranslatedColumn;
+ spanfunc = R_DrawSpan;
+ }
+ else
+ {
+ colfunc = basecolfunc = R_DrawColumnLow;
+ tlcolfunc = R_DrawTLColumn;
+ transcolfunc = R_DrawTranslatedColumn;
+ spanfunc = R_DrawSpanLow;
+ }
+
+ R_InitBuffer(scaledviewwidth, viewheight);
+
+ R_InitTextureMapping();
+
+//
+// psprite scales
+//
+ pspritescale = FRACUNIT * viewwidth / SCREENWIDTH;
+ pspriteiscale = FRACUNIT * SCREENWIDTH / viewwidth;
+
+//
+// thing clipping
+//
+ for (i = 0; i < viewwidth; i++)
+ screenheightarray[i] = viewheight;
+
+//
+// planes
+//
+ for (i = 0; i < viewheight; i++)
+ {
+ dy = ((i - viewheight / 2) << FRACBITS) + FRACUNIT / 2;
+ dy = abs(dy);
+ yslope[i] = FixedDiv((viewwidth << detailshift) / 2 * FRACUNIT, dy);
+ }
+
+ for (i = 0; i < viewwidth; i++)
+ {
+ cosadj = abs(finecosine[xtoviewangle[i] >> ANGLETOFINESHIFT]);
+ distscale[i] = FixedDiv(FRACUNIT, cosadj);
+ }
+
+//
+// Calculate the light levels to use for each level / scale combination
+//
+ for (i = 0; i < LIGHTLEVELS; i++)
+ {
+ startmap = ((LIGHTLEVELS - 1 - i) * 2) * NUMCOLORMAPS / LIGHTLEVELS;
+ for (j = 0; j < MAXLIGHTSCALE; j++)
+ {
+ level =
+ startmap -
+ j * SCREENWIDTH / (viewwidth << detailshift) / DISTMAP;
+ if (level < 0)
+ level = 0;
+ if (level >= NUMCOLORMAPS)
+ level = NUMCOLORMAPS - 1;
+ scalelight[i][j] = colormaps + level * 256;
+ }
+ }
+
+//
+// draw the border
+//
+ R_DrawViewBorder(); // erase old menu stuff
+}
+
+
+/*
+==============
+=
+= R_Init
+=
+==============
+*/
+
+int detailLevel;
+int screenblocks = 10;
+
+void R_Init(void)
+{
+ R_InitData();
+ R_InitPointToAngle();
+ R_InitTables();
+ // viewwidth / viewheight / detailLevel are set by the defaults
+ R_SetViewSize(screenblocks, detailLevel);
+ R_InitPlanes();
+ R_InitLightTables();
+ R_InitSkyMap();
+ R_InitTranslationTables();
+ framecount = 0;
+}
+
+/*
+==============
+=
+= R_PointInSubsector
+=
+==============
+*/
+
+subsector_t *R_PointInSubsector(fixed_t x, fixed_t y)
+{
+ node_t *node;
+ int side, nodenum;
+
+ if (!numnodes) // single subsector is a special case
+ return subsectors;
+
+ nodenum = numnodes - 1;
+
+ while (!(nodenum & NF_SUBSECTOR))
+ {
+ node = &nodes[nodenum];
+ side = R_PointOnSide(x, y, node);
+ nodenum = node->children[side];
+ }
+
+ return &subsectors[nodenum & ~NF_SUBSECTOR];
+
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC R_SetupFrame
+//
+//----------------------------------------------------------------------------
+
+void R_SetupFrame(player_t * player)
+{
+ int i;
+ int tableAngle;
+ int tempCentery;
+ int intensity;
+
+ //drawbsp = 1;
+ viewplayer = player;
+ // haleyjd: removed WATCOMC
+ // haleyjd FIXME: viewangleoffset handling?
+ viewangle = player->mo->angle + viewangleoffset;
+ tableAngle = viewangle >> ANGLETOFINESHIFT;
+ viewx = player->mo->x;
+ viewy = player->mo->y;
+
+ if (localQuakeHappening[displayplayer] && !paused)
+ {
+ intensity = localQuakeHappening[displayplayer];
+ viewx += ((M_Random() % (intensity << 2))
+ - (intensity << 1)) << FRACBITS;
+ viewy += ((M_Random() % (intensity << 2))
+ - (intensity << 1)) << FRACBITS;
+ }
+
+ extralight = player->extralight;
+ viewz = player->viewz;
+
+ tempCentery = viewheight / 2 + (player->lookdir) * screenblocks / 10;
+ if (centery != tempCentery)
+ {
+ centery = tempCentery;
+ centeryfrac = centery << FRACBITS;
+ for (i = 0; i < viewheight; i++)
+ {
+ yslope[i] = FixedDiv((viewwidth << detailshift) / 2 * FRACUNIT,
+ abs(((i - centery) << FRACBITS) +
+ FRACUNIT / 2));
+ }
+ }
+ viewsin = finesine[tableAngle];
+ viewcos = finecosine[tableAngle];
+ sscount = 0;
+ if (player->fixedcolormap)
+ {
+ fixedcolormap = colormaps + player->fixedcolormap
+ * 256 * sizeof(lighttable_t);
+ walllights = scalelightfixed;
+ for (i = 0; i < MAXLIGHTSCALE; i++)
+ {
+ scalelightfixed[i] = fixedcolormap;
+ }
+ }
+ else
+ {
+ fixedcolormap = 0;
+ }
+ framecount++;
+ validcount++;
+ if (BorderNeedRefresh)
+ {
+ if (setblocks < 10)
+ {
+ R_DrawViewBorder();
+ }
+ BorderNeedRefresh = false;
+ BorderTopRefresh = false;
+ UpdateState |= I_FULLSCRN;
+ }
+ if (BorderTopRefresh)
+ {
+ if (setblocks < 10)
+ {
+ R_DrawTopBorder();
+ }
+ BorderTopRefresh = false;
+ UpdateState |= I_MESSAGES;
+ }
+
+#if 0
+ {
+ static int frame;
+ memset(screen, frame, SCREENWIDTH * SCREENHEIGHT);
+ frame++;
+ }
+#endif
+}
+
+/*
+==============
+=
+= R_RenderView
+=
+==============
+*/
+
+void R_RenderPlayerView(player_t * player)
+{
+ R_SetupFrame(player);
+ R_ClearClipSegs();
+ R_ClearDrawSegs();
+ R_ClearPlanes();
+ R_ClearSprites();
+ NetUpdate(); // check for new console commands
+
+ // Make displayed player invisible locally
+ if (localQuakeHappening[displayplayer] && gamestate == GS_LEVEL)
+ {
+ players[displayplayer].mo->flags2 |= MF2_DONTDRAW;
+ R_RenderBSPNode(numnodes - 1); // head node is the last node output
+ players[displayplayer].mo->flags2 &= ~MF2_DONTDRAW;
+ }
+ else
+ {
+ R_RenderBSPNode(numnodes - 1); // head node is the last node output
+ }
+
+ NetUpdate(); // check for new console commands
+ R_DrawPlanes();
+ NetUpdate(); // check for new console commands
+ R_DrawMasked();
+ NetUpdate(); // check for new console commands
+}
diff --git a/src/hexen/r_plane.c b/src/hexen/r_plane.c
new file mode 100644
index 00000000..5c140ad5
--- /dev/null
+++ b/src/hexen/r_plane.c
@@ -0,0 +1,590 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2def.h"
+#include "i_system.h"
+#include "r_local.h"
+
+// MACROS ------------------------------------------------------------------
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern fixed_t Sky1ScrollDelta;
+extern fixed_t Sky2ScrollDelta;
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+int Sky1Texture;
+int Sky2Texture;
+fixed_t Sky1ColumnOffset;
+fixed_t Sky2ColumnOffset;
+int skyflatnum;
+int skytexturemid;
+fixed_t skyiscale;
+boolean DoubleSky;
+planefunction_t floorfunc, ceilingfunc;
+
+// Opening
+visplane_t visplanes[MAXVISPLANES], *lastvisplane;
+visplane_t *floorplane, *ceilingplane;
+short openings[MAXOPENINGS], *lastopening;
+
+// Clip values are the solid pixel bounding the range.
+// floorclip start out SCREENHEIGHT
+// ceilingclip starts out -1
+short floorclip[SCREENWIDTH];
+short ceilingclip[SCREENWIDTH];
+
+// spanstart holds the start of a plane span, initialized to 0
+int spanstart[SCREENHEIGHT];
+int spanstop[SCREENHEIGHT];
+
+// Texture mapping
+lighttable_t **planezlight;
+fixed_t planeheight;
+fixed_t yslope[SCREENHEIGHT];
+fixed_t distscale[SCREENWIDTH];
+fixed_t basexscale, baseyscale;
+fixed_t cachedheight[SCREENHEIGHT];
+fixed_t cacheddistance[SCREENHEIGHT];
+fixed_t cachedxstep[SCREENHEIGHT];
+fixed_t cachedystep[SCREENHEIGHT];
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// R_InitSky
+//
+// Called at level load.
+//
+//==========================================================================
+
+void R_InitSky(int map)
+{
+ Sky1Texture = P_GetMapSky1Texture(map);
+ Sky2Texture = P_GetMapSky2Texture(map);
+ Sky1ScrollDelta = P_GetMapSky1ScrollDelta(map);
+ Sky2ScrollDelta = P_GetMapSky2ScrollDelta(map);
+ Sky1ColumnOffset = 0;
+ Sky2ColumnOffset = 0;
+ DoubleSky = P_GetMapDoubleSky(map);
+}
+
+//==========================================================================
+//
+// R_InitSkyMap
+//
+// Called whenever the view size changes.
+//
+//==========================================================================
+
+void R_InitSkyMap(void)
+{
+ skyflatnum = R_FlatNumForName("F_SKY");
+ skytexturemid = 200 * FRACUNIT;
+ skyiscale = FRACUNIT;
+}
+
+//==========================================================================
+//
+// R_InitPlanes
+//
+// Called at game startup.
+//
+//==========================================================================
+
+void R_InitPlanes(void)
+{
+}
+
+//==========================================================================
+//
+// R_MapPlane
+//
+// Globals used: planeheight, ds_source, basexscale, baseyscale,
+// viewx, viewy.
+//
+//==========================================================================
+
+void R_MapPlane(int y, int x1, int x2)
+{
+ angle_t angle;
+ fixed_t distance, length;
+ unsigned index;
+
+#ifdef RANGECHECK
+ if (x2 < x1 || x1 < 0 || x2 >= viewwidth || (unsigned) y > viewheight)
+ {
+ I_Error("R_MapPlane: %i, %i at %i", x1, x2, y);
+ }
+#endif
+
+ if (planeheight != cachedheight[y])
+ {
+ cachedheight[y] = planeheight;
+ distance = cacheddistance[y] = FixedMul(planeheight, yslope[y]);
+ ds_xstep = cachedxstep[y] = FixedMul(distance, basexscale);
+ ds_ystep = cachedystep[y] = FixedMul(distance, baseyscale);
+ }
+ else
+ {
+ distance = cacheddistance[y];
+ ds_xstep = cachedxstep[y];
+ ds_ystep = cachedystep[y];
+ }
+
+ length = FixedMul(distance, distscale[x1]);
+ angle = (viewangle + xtoviewangle[x1]) >> ANGLETOFINESHIFT;
+ ds_xfrac = viewx + FixedMul(finecosine[angle], length);
+ ds_yfrac = -viewy - FixedMul(finesine[angle], length);
+
+ if (fixedcolormap)
+ {
+ ds_colormap = fixedcolormap;
+ }
+ else
+ {
+ index = distance >> LIGHTZSHIFT;
+ if (index >= MAXLIGHTZ)
+ {
+ index = MAXLIGHTZ - 1;
+ }
+ ds_colormap = planezlight[index];
+ }
+
+ ds_y = y;
+ ds_x1 = x1;
+ ds_x2 = x2;
+
+ spanfunc(); // High or low detail
+}
+
+//==========================================================================
+//
+// R_ClearPlanes
+//
+// Called at the beginning of each frame.
+//
+//==========================================================================
+
+void R_ClearPlanes(void)
+{
+ int i;
+ angle_t angle;
+
+ // Opening / clipping determination
+ for (i = 0; i < viewwidth; i++)
+ {
+ floorclip[i] = viewheight;
+ ceilingclip[i] = -1;
+ }
+
+ lastvisplane = visplanes;
+ lastopening = openings;
+
+ // Texture calculation
+ memset(cachedheight, 0, sizeof(cachedheight));
+ angle = (viewangle - ANG90) >> ANGLETOFINESHIFT; // left to right mapping
+ // Scale will be unit scale at SCREENWIDTH/2 distance
+ basexscale = FixedDiv(finecosine[angle], centerxfrac);
+ baseyscale = -FixedDiv(finesine[angle], centerxfrac);
+}
+
+//==========================================================================
+//
+// R_FindPlane
+//
+//==========================================================================
+
+visplane_t *R_FindPlane(fixed_t height, int picnum,
+ int lightlevel, int special)
+{
+ visplane_t *check;
+
+ if (special < 150)
+ { // Don't let low specials affect search
+ special = 0;
+ }
+
+ if (picnum == skyflatnum)
+ { // All skies map together
+ height = 0;
+ lightlevel = 0;
+ }
+
+ for (check = visplanes; check < lastvisplane; check++)
+ {
+ if (height == check->height
+ && picnum == check->picnum
+ && lightlevel == check->lightlevel && special == check->special)
+ break;
+ }
+
+ if (check < lastvisplane)
+ {
+ return (check);
+ }
+
+ if (lastvisplane - visplanes == MAXVISPLANES)
+ {
+ I_Error("R_FindPlane: no more visplanes");
+ }
+
+ lastvisplane++;
+ check->height = height;
+ check->picnum = picnum;
+ check->lightlevel = lightlevel;
+ check->special = special;
+ check->minx = SCREENWIDTH;
+ check->maxx = -1;
+ memset(check->top, 0xff, sizeof(check->top));
+ return (check);
+}
+
+//==========================================================================
+//
+// R_CheckPlane
+//
+//==========================================================================
+
+visplane_t *R_CheckPlane(visplane_t * pl, int start, int stop)
+{
+ int intrl, intrh;
+ int unionl, unionh;
+ int x;
+
+ if (start < pl->minx)
+ {
+ intrl = pl->minx;
+ unionl = start;
+ }
+ else
+ {
+ unionl = pl->minx;
+ intrl = start;
+ }
+ if (stop > pl->maxx)
+ {
+ intrh = pl->maxx;
+ unionh = stop;
+ }
+ else
+ {
+ unionh = pl->maxx;
+ intrh = stop;
+ }
+
+ for (x = intrl; x <= intrh; x++)
+ {
+ if (pl->top[x] != 0xff)
+ {
+ break;
+ }
+ }
+
+ if (x > intrh)
+ {
+ pl->minx = unionl;
+ pl->maxx = unionh;
+ return pl; // use the same visplane
+ }
+
+ // Make a new visplane
+ lastvisplane->height = pl->height;
+ lastvisplane->picnum = pl->picnum;
+ lastvisplane->lightlevel = pl->lightlevel;
+ lastvisplane->special = pl->special;
+ pl = lastvisplane++;
+ pl->minx = start;
+ pl->maxx = stop;
+ memset(pl->top, 0xff, sizeof(pl->top));
+
+ return pl;
+}
+
+//==========================================================================
+//
+// R_MakeSpans
+//
+//==========================================================================
+
+void R_MakeSpans(int x, int t1, int b1, int t2, int b2)
+{
+ while (t1 < t2 && t1 <= b1)
+ {
+ R_MapPlane(t1, spanstart[t1], x - 1);
+ t1++;
+ }
+ while (b1 > b2 && b1 >= t1)
+ {
+ R_MapPlane(b1, spanstart[b1], x - 1);
+ b1--;
+ }
+ while (t2 < t1 && t2 <= b2)
+ {
+ spanstart[t2] = x;
+ t2++;
+ }
+ while (b2 > b1 && b2 >= t2)
+ {
+ spanstart[b2] = x;
+ b2--;
+ }
+}
+
+//==========================================================================
+//
+// R_DrawPlanes
+//
+//==========================================================================
+
+#define SKYTEXTUREMIDSHIFTED 200
+
+void R_DrawPlanes(void)
+{
+ visplane_t *pl;
+ int light;
+ int x, stop;
+ int angle;
+ byte *tempSource;
+ byte *source;
+ byte *source2;
+ byte *dest;
+ int count;
+ int offset;
+ int skyTexture;
+ int offset2;
+ int skyTexture2;
+ int scrollOffset;
+
+ extern byte *ylookup[MAXHEIGHT];
+ extern int columnofs[MAXWIDTH];
+
+#ifdef RANGECHECK
+ if (ds_p - drawsegs > MAXDRAWSEGS)
+ {
+ I_Error("R_DrawPlanes: drawsegs overflow (%i)", ds_p - drawsegs);
+ }
+ if (lastvisplane - visplanes > MAXVISPLANES)
+ {
+ I_Error("R_DrawPlanes: visplane overflow (%i)",
+ lastvisplane - visplanes);
+ }
+ if (lastopening - openings > MAXOPENINGS)
+ {
+ I_Error("R_DrawPlanes: opening overflow (%i)",
+ lastopening - openings);
+ }
+#endif
+
+ for (pl = visplanes; pl < lastvisplane; pl++)
+ {
+ if (pl->minx > pl->maxx)
+ {
+ continue;
+ }
+ if (pl->picnum == skyflatnum)
+ { // Sky flat
+ if (DoubleSky)
+ { // Render 2 layers, sky 1 in front
+ offset = Sky1ColumnOffset >> 16;
+ skyTexture = texturetranslation[Sky1Texture];
+ offset2 = Sky2ColumnOffset >> 16;
+ skyTexture2 = texturetranslation[Sky2Texture];
+ for (x = pl->minx; x <= pl->maxx; x++)
+ {
+ dc_yl = pl->top[x];
+ dc_yh = pl->bottom[x];
+ if (dc_yl <= dc_yh)
+ {
+ count = dc_yh - dc_yl;
+ if (count < 0)
+ {
+ return;
+ }
+ angle = (viewangle + xtoviewangle[x])
+ >> ANGLETOSKYSHIFT;
+ source = R_GetColumn(skyTexture, angle + offset)
+ + SKYTEXTUREMIDSHIFTED + (dc_yl - centery);
+ source2 = R_GetColumn(skyTexture2, angle + offset2)
+ + SKYTEXTUREMIDSHIFTED + (dc_yl - centery);
+ dest = ylookup[dc_yl] + columnofs[x];
+ do
+ {
+ if (*source)
+ {
+ *dest = *source++;
+ source2++;
+ }
+ else
+ {
+ *dest = *source2++;
+ source++;
+ }
+ dest += SCREENWIDTH;
+ }
+ while (count--);
+ }
+ }
+ continue; // Next visplane
+ }
+ else
+ { // Render single layer
+ if (pl->special == 200)
+ { // Use sky 2
+ offset = Sky2ColumnOffset >> 16;
+ skyTexture = texturetranslation[Sky2Texture];
+ }
+ else
+ { // Use sky 1
+ offset = Sky1ColumnOffset >> 16;
+ skyTexture = texturetranslation[Sky1Texture];
+ }
+ for (x = pl->minx; x <= pl->maxx; x++)
+ {
+ dc_yl = pl->top[x];
+ dc_yh = pl->bottom[x];
+ if (dc_yl <= dc_yh)
+ {
+ count = dc_yh - dc_yl;
+ if (count < 0)
+ {
+ return;
+ }
+ angle = (viewangle + xtoviewangle[x])
+ >> ANGLETOSKYSHIFT;
+ source = R_GetColumn(skyTexture, angle + offset)
+ + SKYTEXTUREMIDSHIFTED + (dc_yl - centery);
+ dest = ylookup[dc_yl] + columnofs[x];
+ do
+ {
+ *dest = *source++;
+ dest += SCREENWIDTH;
+ }
+ while (count--);
+ }
+ }
+ continue; // Next visplane
+ }
+ }
+ // Regular flat
+ tempSource = W_CacheLumpNum(firstflat +
+ flattranslation[pl->picnum], PU_STATIC);
+ scrollOffset = leveltime >> 1 & 63;
+ switch (pl->special)
+ { // Handle scrolling flats
+ case 201:
+ case 202:
+ case 203: // Scroll_North_xxx
+ ds_source = tempSource + ((scrollOffset
+ << (pl->special - 201) & 63) << 6);
+ break;
+ case 204:
+ case 205:
+ case 206: // Scroll_East_xxx
+ ds_source = tempSource + ((63 - scrollOffset)
+ << (pl->special - 204) & 63);
+ break;
+ case 207:
+ case 208:
+ case 209: // Scroll_South_xxx
+ ds_source = tempSource + (((63 - scrollOffset)
+ << (pl->special - 207) & 63) << 6);
+ break;
+ case 210:
+ case 211:
+ case 212: // Scroll_West_xxx
+ ds_source = tempSource + (scrollOffset
+ << (pl->special - 210) & 63);
+ break;
+ case 213:
+ case 214:
+ case 215: // Scroll_NorthWest_xxx
+ ds_source = tempSource + (scrollOffset
+ << (pl->special - 213) & 63) +
+ ((scrollOffset << (pl->special - 213) & 63) << 6);
+ break;
+ case 216:
+ case 217:
+ case 218: // Scroll_NorthEast_xxx
+ ds_source = tempSource + ((63 - scrollOffset)
+ << (pl->special - 216) & 63) +
+ ((scrollOffset << (pl->special - 216) & 63) << 6);
+ break;
+ case 219:
+ case 220:
+ case 221: // Scroll_SouthEast_xxx
+ ds_source = tempSource + ((63 - scrollOffset)
+ << (pl->special - 219) & 63) +
+ (((63 - scrollOffset) << (pl->special - 219) & 63) << 6);
+ break;
+ case 222:
+ case 223:
+ case 224: // Scroll_SouthWest_xxx
+ ds_source = tempSource + (scrollOffset
+ << (pl->special - 222) & 63) +
+ (((63 - scrollOffset) << (pl->special - 222) & 63) << 6);
+ break;
+ default:
+ ds_source = tempSource;
+ break;
+ }
+ planeheight = abs(pl->height - viewz);
+ light = (pl->lightlevel >> LIGHTSEGSHIFT) + extralight;
+ if (light >= LIGHTLEVELS)
+ {
+ light = LIGHTLEVELS - 1;
+ }
+ if (light < 0)
+ {
+ light = 0;
+ }
+ planezlight = zlight[light];
+
+ pl->top[pl->maxx + 1] = 0xff;
+ pl->top[pl->minx - 1] = 0xff;
+
+ stop = pl->maxx + 1;
+ for (x = pl->minx; x <= stop; x++)
+ {
+ R_MakeSpans(x, pl->top[x - 1], pl->bottom[x - 1],
+ pl->top[x], pl->bottom[x]);
+ }
+ W_ReleaseLumpNum(firstflat + flattranslation[pl->picnum]);
+ }
+}
diff --git a/src/hexen/r_segs.c b/src/hexen/r_segs.c
new file mode 100644
index 00000000..5d179bd7
--- /dev/null
+++ b/src/hexen/r_segs.c
@@ -0,0 +1,662 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#include "h2def.h"
+#include "i_system.h"
+#include "r_local.h"
+
+// OPTIMIZE: closed two sided lines as single sided
+
+boolean segtextured; // true if any of the segs textures might be vis
+boolean markfloor; // false if the back side is the same plane
+boolean markceiling;
+boolean maskedtexture;
+int toptexture, bottomtexture, midtexture;
+
+
+angle_t rw_normalangle;
+int rw_angle1; // angle to line origin
+
+//
+// wall
+//
+int rw_x;
+int rw_stopx;
+angle_t rw_centerangle;
+fixed_t rw_offset;
+fixed_t rw_distance;
+fixed_t rw_scale;
+fixed_t rw_scalestep;
+fixed_t rw_midtexturemid;
+fixed_t rw_toptexturemid;
+fixed_t rw_bottomtexturemid;
+
+int worldtop, worldbottom, worldhigh, worldlow;
+
+fixed_t pixhigh, pixlow;
+fixed_t pixhighstep, pixlowstep;
+fixed_t topfrac, topstep;
+fixed_t bottomfrac, bottomstep;
+
+
+lighttable_t **walllights;
+
+short *maskedtexturecol;
+
+/*
+================
+=
+= R_RenderMaskedSegRange
+=
+================
+*/
+
+void R_RenderMaskedSegRange(drawseg_t * ds, int x1, int x2)
+{
+ unsigned index;
+ column_t *col;
+ int lightnum;
+ int texnum;
+
+//
+// calculate light table
+// use different light tables for horizontal / vertical / diagonal
+// OPTIMIZE: get rid of LIGHTSEGSHIFT globally
+ curline = ds->curline;
+ frontsector = curline->frontsector;
+ backsector = curline->backsector;
+ texnum = texturetranslation[curline->sidedef->midtexture];
+
+ lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT) + extralight;
+ //if (curline->v1->y == curline->v2->y)
+ // lightnum--;
+ //else if (curline->v1->x == curline->v2->x)
+ // lightnum++;
+ //if (lightnum < 0)
+ // walllights = scalelight[0];
+ if (lightnum >= LIGHTLEVELS)
+ walllights = scalelight[LIGHTLEVELS - 1];
+ else
+ walllights = scalelight[lightnum];
+
+ maskedtexturecol = ds->maskedtexturecol;
+
+ rw_scalestep = ds->scalestep;
+ spryscale = ds->scale1 + (x1 - ds->x1) * rw_scalestep;
+ mfloorclip = ds->sprbottomclip;
+ mceilingclip = ds->sprtopclip;
+
+//
+// find positioning
+//
+ if (curline->linedef->flags & ML_DONTPEGBOTTOM)
+ {
+ dc_texturemid = frontsector->floorheight > backsector->floorheight
+ ? frontsector->floorheight : backsector->floorheight;
+ dc_texturemid = dc_texturemid + textureheight[texnum] - viewz;
+ }
+ else
+ {
+ dc_texturemid = frontsector->ceilingheight < backsector->ceilingheight
+ ? frontsector->ceilingheight : backsector->ceilingheight;
+ dc_texturemid = dc_texturemid - viewz;
+ }
+ dc_texturemid += curline->sidedef->rowoffset;
+
+ if (fixedcolormap)
+ dc_colormap = fixedcolormap;
+//
+// draw the columns
+//
+ for (dc_x = x1; dc_x <= x2; dc_x++)
+ {
+ // calculate lighting
+ if (maskedtexturecol[dc_x] != SHRT_MAX)
+ {
+ if (!fixedcolormap)
+ {
+ index = spryscale >> LIGHTSCALESHIFT;
+ if (index >= MAXLIGHTSCALE)
+ index = MAXLIGHTSCALE - 1;
+ dc_colormap = walllights[index];
+ }
+
+ sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale);
+ dc_iscale = 0xffffffffu / (unsigned) spryscale;
+
+ //
+ // draw the texture
+ //
+ col = (column_t *) ((byte *)
+ R_GetColumn(texnum,
+ maskedtexturecol[dc_x]) - 3);
+
+ R_DrawMaskedColumn(col, -1);
+ maskedtexturecol[dc_x] = SHRT_MAX;
+ }
+ spryscale += rw_scalestep;
+ }
+
+}
+
+/*
+================
+=
+= R_RenderSegLoop
+=
+= Draws zero, one, or two textures (and possibly a masked texture) for walls
+= Can draw or mark the starting pixel of floor and ceiling textures
+=
+= CALLED: CORE LOOPING ROUTINE
+================
+*/
+
+#define HEIGHTBITS 12
+#define HEIGHTUNIT (1<<HEIGHTBITS)
+
+void R_RenderSegLoop(void)
+{
+ angle_t angle;
+ unsigned index;
+ int yl, yh, mid;
+ fixed_t texturecolumn;
+ int top, bottom;
+
+ texturecolumn = 0; // shut up compiler warning
+
+ for (; rw_x < rw_stopx; rw_x++)
+ {
+//
+// mark floor / ceiling areas
+//
+ yl = (topfrac + HEIGHTUNIT - 1) >> HEIGHTBITS;
+ if (yl < ceilingclip[rw_x] + 1)
+ yl = ceilingclip[rw_x] + 1; // no space above wall
+ if (markceiling)
+ {
+ top = ceilingclip[rw_x] + 1;
+ bottom = yl - 1;
+ if (bottom >= floorclip[rw_x])
+ bottom = floorclip[rw_x] - 1;
+ if (top <= bottom)
+ {
+ ceilingplane->top[rw_x] = top;
+ ceilingplane->bottom[rw_x] = bottom;
+ }
+ }
+
+ yh = bottomfrac >> HEIGHTBITS;
+ if (yh >= floorclip[rw_x])
+ yh = floorclip[rw_x] - 1;
+ if (markfloor)
+ {
+ top = yh + 1;
+ bottom = floorclip[rw_x] - 1;
+ if (top <= ceilingclip[rw_x])
+ top = ceilingclip[rw_x] + 1;
+ if (top <= bottom)
+ {
+ floorplane->top[rw_x] = top;
+ floorplane->bottom[rw_x] = bottom;
+ }
+ }
+
+//
+// texturecolumn and lighting are independent of wall tiers
+//
+ if (segtextured)
+ {
+ // calculate texture offset
+ angle = (rw_centerangle + xtoviewangle[rw_x]) >> ANGLETOFINESHIFT;
+ texturecolumn =
+ rw_offset - FixedMul(finetangent[angle], rw_distance);
+ texturecolumn >>= FRACBITS;
+ // calculate lighting
+ index = rw_scale >> LIGHTSCALESHIFT;
+ if (index >= MAXLIGHTSCALE)
+ index = MAXLIGHTSCALE - 1;
+ dc_colormap = walllights[index];
+ dc_x = rw_x;
+ dc_iscale = 0xffffffffu / (unsigned) rw_scale;
+ }
+
+//
+// draw the wall tiers
+//
+ if (midtexture)
+ { // single sided line
+ dc_yl = yl;
+ dc_yh = yh;
+ dc_texturemid = rw_midtexturemid;
+ dc_source = R_GetColumn(midtexture, texturecolumn);
+ colfunc();
+ ceilingclip[rw_x] = viewheight;
+ floorclip[rw_x] = -1;
+ }
+ else
+ { // two sided line
+ if (toptexture)
+ { // top wall
+ mid = pixhigh >> HEIGHTBITS;
+ pixhigh += pixhighstep;
+ if (mid >= floorclip[rw_x])
+ mid = floorclip[rw_x] - 1;
+ if (mid >= yl)
+ {
+ dc_yl = yl;
+ dc_yh = mid;
+ dc_texturemid = rw_toptexturemid;
+ dc_source = R_GetColumn(toptexture, texturecolumn);
+ colfunc();
+ ceilingclip[rw_x] = mid;
+ }
+ else
+ ceilingclip[rw_x] = yl - 1;
+ }
+ else
+ { // no top wall
+ if (markceiling)
+ ceilingclip[rw_x] = yl - 1;
+ }
+
+ if (bottomtexture)
+ { // bottom wall
+ mid = (pixlow + HEIGHTUNIT - 1) >> HEIGHTBITS;
+ pixlow += pixlowstep;
+ if (mid <= ceilingclip[rw_x])
+ mid = ceilingclip[rw_x] + 1; // no space above wall
+ if (mid <= yh)
+ {
+ dc_yl = mid;
+ dc_yh = yh;
+ dc_texturemid = rw_bottomtexturemid;
+ dc_source = R_GetColumn(bottomtexture, texturecolumn);
+ colfunc();
+ floorclip[rw_x] = mid;
+ }
+ else
+ floorclip[rw_x] = yh + 1;
+ }
+ else
+ { // no bottom wall
+ if (markfloor)
+ floorclip[rw_x] = yh + 1;
+ }
+
+ if (maskedtexture)
+ { // save texturecol for backdrawing of masked mid texture
+ maskedtexturecol[rw_x] = texturecolumn;
+ }
+ }
+
+ rw_scale += rw_scalestep;
+ topfrac += topstep;
+ bottomfrac += bottomstep;
+ }
+
+}
+
+
+
+/*
+=====================
+=
+= R_StoreWallRange
+=
+= A wall segment will be drawn between start and stop pixels (inclusive)
+=
+======================
+*/
+
+void R_StoreWallRange(int start, int stop)
+{
+ fixed_t hyp;
+ fixed_t sineval;
+ angle_t distangle, offsetangle;
+ fixed_t vtop;
+ int lightnum;
+
+ if (ds_p == &drawsegs[MAXDRAWSEGS])
+ return; // don't overflow and crash
+
+#ifdef RANGECHECK
+ if (start >= viewwidth || start > stop)
+ I_Error("Bad R_RenderWallRange: %i to %i", start, stop);
+#endif
+
+ sidedef = curline->sidedef;
+ linedef = curline->linedef;
+
+// mark the segment as visible for auto map
+ linedef->flags |= ML_MAPPED;
+
+//
+// calculate rw_distance for scale calculation
+//
+ rw_normalangle = curline->angle + ANG90;
+ offsetangle = abs(rw_normalangle - rw_angle1);
+ if (offsetangle > ANG90)
+ offsetangle = ANG90;
+ distangle = ANG90 - offsetangle;
+ hyp = R_PointToDist(curline->v1->x, curline->v1->y);
+ sineval = finesine[distangle >> ANGLETOFINESHIFT];
+ rw_distance = FixedMul(hyp, sineval);
+
+
+ ds_p->x1 = rw_x = start;
+ ds_p->x2 = stop;
+ ds_p->curline = curline;
+ rw_stopx = stop + 1;
+
+//
+// calculate scale at both ends and step
+//
+ ds_p->scale1 = rw_scale =
+ R_ScaleFromGlobalAngle(viewangle + xtoviewangle[start]);
+ if (stop > start)
+ {
+ ds_p->scale2 = R_ScaleFromGlobalAngle(viewangle + xtoviewangle[stop]);
+ ds_p->scalestep = rw_scalestep =
+ (ds_p->scale2 - rw_scale) / (stop - start);
+ }
+ else
+ {
+ //
+ // try to fix the stretched line bug
+ //
+#if 0
+ if (rw_distance < FRACUNIT / 2)
+ {
+ fixed_t trx, try;
+ fixed_t gxt, gyt;
+
+ trx = curline->v1->x - viewx;
+ try = curline->v1->y - viewy;
+
+ gxt = FixedMul(trx, viewcos);
+ gyt = -FixedMul(try, viewsin);
+ ds_p->scale1 = FixedDiv(projection, gxt - gyt);
+ }
+#endif
+ ds_p->scale2 = ds_p->scale1;
+ }
+
+
+//
+// calculate texture boundaries and decide if floor / ceiling marks
+// are needed
+//
+ worldtop = frontsector->ceilingheight - viewz;
+ worldbottom = frontsector->floorheight - viewz;
+
+ midtexture = toptexture = bottomtexture = maskedtexture = 0;
+ ds_p->maskedtexturecol = NULL;
+
+ if (!backsector)
+ {
+//
+// single sided line
+//
+ midtexture = texturetranslation[sidedef->midtexture];
+ // a single sided line is terminal, so it must mark ends
+ markfloor = markceiling = true;
+ if (linedef->flags & ML_DONTPEGBOTTOM)
+ {
+ vtop = frontsector->floorheight +
+ textureheight[sidedef->midtexture];
+ rw_midtexturemid = vtop - viewz; // bottom of texture at bottom
+ }
+ else
+ rw_midtexturemid = worldtop; // top of texture at top
+ rw_midtexturemid += sidedef->rowoffset;
+ ds_p->silhouette = SIL_BOTH;
+ ds_p->sprtopclip = screenheightarray;
+ ds_p->sprbottomclip = negonearray;
+ ds_p->bsilheight = INT_MAX;
+ ds_p->tsilheight = INT_MIN;
+ }
+ else
+ {
+//
+// two sided line
+//
+ ds_p->sprtopclip = ds_p->sprbottomclip = NULL;
+ ds_p->silhouette = 0;
+ if (frontsector->floorheight > backsector->floorheight)
+ {
+ ds_p->silhouette = SIL_BOTTOM;
+ ds_p->bsilheight = frontsector->floorheight;
+ }
+ else if (backsector->floorheight > viewz)
+ {
+ ds_p->silhouette = SIL_BOTTOM;
+ ds_p->bsilheight = INT_MAX;
+// ds_p->sprbottomclip = negonearray;
+ }
+ if (frontsector->ceilingheight < backsector->ceilingheight)
+ {
+ ds_p->silhouette |= SIL_TOP;
+ ds_p->tsilheight = frontsector->ceilingheight;
+ }
+ else if (backsector->ceilingheight < viewz)
+ {
+ ds_p->silhouette |= SIL_TOP;
+ ds_p->tsilheight = INT_MIN;
+// ds_p->sprtopclip = screenheightarray;
+ }
+
+ if (backsector->ceilingheight <= frontsector->floorheight)
+ {
+ ds_p->sprbottomclip = negonearray;
+ ds_p->bsilheight = INT_MAX;
+ ds_p->silhouette |= SIL_BOTTOM;
+ }
+ if (backsector->floorheight >= frontsector->ceilingheight)
+ {
+ ds_p->sprtopclip = screenheightarray;
+ ds_p->tsilheight = INT_MIN;
+ ds_p->silhouette |= SIL_TOP;
+ }
+ worldhigh = backsector->ceilingheight - viewz;
+ worldlow = backsector->floorheight - viewz;
+
+ // hack to allow height changes in outdoor areas
+ if (frontsector->ceilingpic == skyflatnum
+ && backsector->ceilingpic == skyflatnum)
+ worldtop = worldhigh;
+
+ if (worldlow != worldbottom
+ || backsector->floorpic != frontsector->floorpic
+ || backsector->lightlevel != frontsector->lightlevel
+ || backsector->special != frontsector->special)
+ markfloor = true;
+ else
+ markfloor = false; // same plane on both sides
+
+ if (worldhigh != worldtop
+ || backsector->ceilingpic != frontsector->ceilingpic
+ || backsector->lightlevel != frontsector->lightlevel)
+ markceiling = true;
+ else
+ markceiling = false; // same plane on both sides
+
+ if (backsector->ceilingheight <= frontsector->floorheight
+ || backsector->floorheight >= frontsector->ceilingheight)
+ markceiling = markfloor = true; // closed door
+
+ if (worldhigh < worldtop)
+ { // top texture
+ toptexture = texturetranslation[sidedef->toptexture];
+ if (linedef->flags & ML_DONTPEGTOP)
+ rw_toptexturemid = worldtop; // top of texture at top
+ else
+ {
+ vtop = backsector->ceilingheight +
+ textureheight[sidedef->toptexture];
+ rw_toptexturemid = vtop - viewz; // bottom of texture
+ }
+ }
+ if (worldlow > worldbottom)
+ { // bottom texture
+ bottomtexture = texturetranslation[sidedef->bottomtexture];
+ if (linedef->flags & ML_DONTPEGBOTTOM)
+ { // bottom of texture at bottom
+ rw_bottomtexturemid = worldtop; // top of texture at top
+ }
+ else // top of texture at top
+ rw_bottomtexturemid = worldlow;
+ }
+ rw_toptexturemid += sidedef->rowoffset;
+ rw_bottomtexturemid += sidedef->rowoffset;
+
+ //
+ // allocate space for masked texture tables
+ //
+ if (sidedef->midtexture)
+ { // masked midtexture
+ maskedtexture = true;
+ ds_p->maskedtexturecol = maskedtexturecol = lastopening - rw_x;
+ lastopening += rw_stopx - rw_x;
+ }
+ }
+
+//
+// calculate rw_offset (only needed for textured lines)
+//
+ segtextured = midtexture | toptexture | bottomtexture | maskedtexture;
+
+ if (segtextured)
+ {
+ offsetangle = rw_normalangle - rw_angle1;
+ if (offsetangle > ANG180)
+ offsetangle = -offsetangle;
+ if (offsetangle > ANG90)
+ offsetangle = ANG90;
+ sineval = finesine[offsetangle >> ANGLETOFINESHIFT];
+ rw_offset = FixedMul(hyp, sineval);
+ if (rw_normalangle - rw_angle1 < ANG180)
+ rw_offset = -rw_offset;
+ rw_offset += sidedef->textureoffset + curline->offset;
+ rw_centerangle = ANG90 + viewangle - rw_normalangle;
+
+ //
+ // calculate light table
+ // use different light tables for horizontal / vertical / diagonal
+ // OPTIMIZE: get rid of LIGHTSEGSHIFT globally
+ if (!fixedcolormap)
+ {
+ lightnum =
+ (frontsector->lightlevel >> LIGHTSEGSHIFT) + extralight;
+ //if (curline->v1->y == curline->v2->y)
+ // lightnum--;
+ //else if (curline->v1->x == curline->v2->x)
+ // lightnum++;
+ //if (lightnum < 0)
+ // walllights = scalelight[0];
+ if (lightnum >= LIGHTLEVELS)
+ walllights = scalelight[LIGHTLEVELS - 1];
+ else
+ walllights = scalelight[lightnum];
+ }
+ }
+
+
+//
+// if a floor / ceiling plane is on the wrong side of the view plane
+// it is definately invisible and doesn't need to be marked
+//
+ if (frontsector->floorheight >= viewz)
+ markfloor = false; // above view plane
+ if (frontsector->ceilingheight <= viewz
+ && frontsector->ceilingpic != skyflatnum)
+ markceiling = false; // below view plane
+
+//
+// calculate incremental stepping values for texture edges
+//
+ worldtop >>= 4;
+ worldbottom >>= 4;
+
+ topstep = -FixedMul(rw_scalestep, worldtop);
+ topfrac = (centeryfrac >> 4) - FixedMul(worldtop, rw_scale);
+
+ bottomstep = -FixedMul(rw_scalestep, worldbottom);
+ bottomfrac = (centeryfrac >> 4) - FixedMul(worldbottom, rw_scale);
+
+ if (backsector)
+ {
+ worldhigh >>= 4;
+ worldlow >>= 4;
+
+ if (worldhigh < worldtop)
+ {
+ pixhigh = (centeryfrac >> 4) - FixedMul(worldhigh, rw_scale);
+ pixhighstep = -FixedMul(rw_scalestep, worldhigh);
+ }
+ if (worldlow > worldbottom)
+ {
+ pixlow = (centeryfrac >> 4) - FixedMul(worldlow, rw_scale);
+ pixlowstep = -FixedMul(rw_scalestep, worldlow);
+ }
+ }
+
+//
+// render it
+//
+ if (markceiling)
+ ceilingplane = R_CheckPlane(ceilingplane, rw_x, rw_stopx - 1);
+ if (markfloor)
+ floorplane = R_CheckPlane(floorplane, rw_x, rw_stopx - 1);
+
+ R_RenderSegLoop();
+
+//
+// save sprite clipping info
+//
+ if (((ds_p->silhouette & SIL_TOP) || maskedtexture) && !ds_p->sprtopclip)
+ {
+ memcpy(lastopening, ceilingclip + start, 2 * (rw_stopx - start));
+ ds_p->sprtopclip = lastopening - start;
+ lastopening += rw_stopx - start;
+ }
+ if (((ds_p->silhouette & SIL_BOTTOM) || maskedtexture)
+ && !ds_p->sprbottomclip)
+ {
+ memcpy(lastopening, floorclip + start, 2 * (rw_stopx - start));
+ ds_p->sprbottomclip = lastopening - start;
+ lastopening += rw_stopx - start;
+ }
+ if (maskedtexture && !(ds_p->silhouette & SIL_TOP))
+ {
+ ds_p->silhouette |= SIL_TOP;
+ ds_p->tsilheight = INT_MIN;
+ }
+ if (maskedtexture && !(ds_p->silhouette & SIL_BOTTOM))
+ {
+ ds_p->silhouette |= SIL_BOTTOM;
+ ds_p->bsilheight = INT_MAX;
+ }
+ ds_p++;
+}
diff --git a/src/hexen/r_things.c b/src/hexen/r_things.c
new file mode 100644
index 00000000..6cc0c6a5
--- /dev/null
+++ b/src/hexen/r_things.c
@@ -0,0 +1,1051 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "h2def.h"
+#include "i_system.h"
+#include "i_swap.h"
+#include "r_local.h"
+
+//void R_DrawTranslatedAltTLColumn(void);
+
+typedef struct
+{
+ int x1, x2;
+
+ int column;
+ int topclip;
+ int bottomclip;
+} maskdraw_t;
+
+/*
+
+Sprite rotation 0 is facing the viewer, rotation 1 is one angle turn CLOCKWISE around the axis.
+This is not the same as the angle, which increases counter clockwise
+(protractor). There was a lot of stuff grabbed wrong, so I changed it...
+
+*/
+
+
+fixed_t pspritescale, pspriteiscale;
+
+lighttable_t **spritelights;
+
+// constant arrays used for psprite clipping and initializing clipping
+short negonearray[SCREENWIDTH];
+short screenheightarray[SCREENWIDTH];
+
+boolean LevelUseFullBright;
+/*
+===============================================================================
+
+ INITIALIZATION FUNCTIONS
+
+===============================================================================
+*/
+
+// variables used to look up and range check thing_t sprites patches
+spritedef_t *sprites;
+int numsprites;
+
+spriteframe_t sprtemp[30];
+int maxframe;
+char *spritename;
+
+
+
+/*
+=================
+=
+= R_InstallSpriteLump
+=
+= Local function for R_InitSprites
+=================
+*/
+
+void R_InstallSpriteLump(int lump, unsigned frame, unsigned rotation,
+ boolean flipped)
+{
+ int r;
+
+ if (frame >= 30 || rotation > 8)
+ I_Error("R_InstallSpriteLump: Bad frame characters in lump %i", lump);
+
+ if ((int) frame > maxframe)
+ maxframe = frame;
+
+ if (rotation == 0)
+ {
+// the lump should be used for all rotations
+ if (sprtemp[frame].rotate == false)
+ I_Error("R_InitSprites: Sprite %s frame %c has multip rot=0 lump",
+ spritename, 'A' + frame);
+ if (sprtemp[frame].rotate == true)
+ I_Error
+ ("R_InitSprites: Sprite %s frame %c has rotations and a rot=0 lump",
+ spritename, 'A' + frame);
+
+ sprtemp[frame].rotate = false;
+ for (r = 0; r < 8; r++)
+ {
+ sprtemp[frame].lump[r] = lump - firstspritelump;
+ sprtemp[frame].flip[r] = (byte) flipped;
+ }
+ return;
+ }
+
+// the lump is only used for one rotation
+ if (sprtemp[frame].rotate == false)
+ I_Error
+ ("R_InitSprites: Sprite %s frame %c has rotations and a rot=0 lump",
+ spritename, 'A' + frame);
+
+ sprtemp[frame].rotate = true;
+
+ rotation--; // make 0 based
+ if (sprtemp[frame].lump[rotation] != -1)
+ I_Error
+ ("R_InitSprites: Sprite %s : %c : %c has two lumps mapped to it",
+ spritename, 'A' + frame, '1' + rotation);
+
+ sprtemp[frame].lump[rotation] = lump - firstspritelump;
+ sprtemp[frame].flip[rotation] = (byte) flipped;
+}
+
+/*
+=================
+=
+= R_InitSpriteDefs
+=
+= Pass a null terminated list of sprite names (4 chars exactly) to be used
+= Builds the sprite rotation matrixes to account for horizontally flipped
+= sprites. Will report an error if the lumps are inconsistant
+=Only called at startup
+=
+= Sprite lump names are 4 characters for the actor, a letter for the frame,
+= and a number for the rotation, A sprite that is flippable will have an
+= additional letter/number appended. The rotation character can be 0 to
+= signify no rotations
+=================
+*/
+
+void R_InitSpriteDefs(char **namelist)
+{
+ char **check;
+ int i, l, frame, rotation;
+ int start, end;
+
+// count the number of sprite names
+ check = namelist;
+ while (*check != NULL)
+ check++;
+ numsprites = check - namelist;
+
+ if (!numsprites)
+ return;
+
+ sprites = Z_Malloc(numsprites * sizeof(*sprites), PU_STATIC, NULL);
+
+ start = firstspritelump - 1;
+ end = lastspritelump + 1;
+
+// scan all the lump names for each of the names, noting the highest
+// frame letter
+// Just compare 4 characters as ints
+ for (i = 0; i < numsprites; i++)
+ {
+ spritename = namelist[i];
+ memset(sprtemp, -1, sizeof(sprtemp));
+
+ maxframe = -1;
+
+ //
+ // scan the lumps, filling in the frames for whatever is found
+ //
+ for (l = start + 1; l < end; l++)
+ if (!strncmp(lumpinfo[l].name, namelist[i], 4))
+ {
+ frame = lumpinfo[l].name[4] - 'A';
+ rotation = lumpinfo[l].name[5] - '0';
+ R_InstallSpriteLump(l, frame, rotation, false);
+ if (lumpinfo[l].name[6])
+ {
+ frame = lumpinfo[l].name[6] - 'A';
+ rotation = lumpinfo[l].name[7] - '0';
+ R_InstallSpriteLump(l, frame, rotation, true);
+ }
+ }
+
+ //
+ // check the frames that were found for completeness
+ //
+ if (maxframe == -1)
+ {
+ //continue;
+ sprites[i].numframes = 0;
+ if (gamemode == shareware)
+ continue;
+ I_Error("R_InitSprites: No lumps found for sprite %s",
+ namelist[i]);
+ }
+
+ maxframe++;
+ for (frame = 0; frame < maxframe; frame++)
+ {
+ switch ((int) sprtemp[frame].rotate)
+ {
+ case -1: // no rotations were found for that frame at all
+ I_Error("R_InitSprites: No patches found for %s frame %c",
+ namelist[i], frame + 'A');
+ case 0: // only the first rotation is needed
+ break;
+
+ case 1: // must have all 8 frames
+ for (rotation = 0; rotation < 8; rotation++)
+ if (sprtemp[frame].lump[rotation] == -1)
+ I_Error
+ ("R_InitSprites: Sprite %s frame %c is missing rotations",
+ namelist[i], frame + 'A');
+ }
+ }
+
+ //
+ // allocate space for the frames present and copy sprtemp to it
+ //
+ sprites[i].numframes = maxframe;
+ sprites[i].spriteframes =
+ Z_Malloc(maxframe * sizeof(spriteframe_t), PU_STATIC, NULL);
+ memcpy(sprites[i].spriteframes, sprtemp,
+ maxframe * sizeof(spriteframe_t));
+ }
+
+}
+
+
+/*
+===============================================================================
+
+ GAME FUNCTIONS
+
+===============================================================================
+*/
+
+vissprite_t vissprites[MAXVISSPRITES], *vissprite_p;
+int newvissprite;
+
+
+/*
+===================
+=
+= R_InitSprites
+=
+= Called at program start
+===================
+*/
+
+void R_InitSprites(char **namelist)
+{
+ int i;
+
+ for (i = 0; i < SCREENWIDTH; i++)
+ {
+ negonearray[i] = -1;
+ }
+
+ R_InitSpriteDefs(namelist);
+}
+
+
+/*
+===================
+=
+= R_ClearSprites
+=
+= Called at frame start
+===================
+*/
+
+void R_ClearSprites(void)
+{
+ vissprite_p = vissprites;
+}
+
+
+/*
+===================
+=
+= R_NewVisSprite
+=
+===================
+*/
+
+vissprite_t overflowsprite;
+
+vissprite_t *R_NewVisSprite(void)
+{
+ if (vissprite_p == &vissprites[MAXVISSPRITES])
+ return &overflowsprite;
+ vissprite_p++;
+ return vissprite_p - 1;
+}
+
+
+/*
+================
+=
+= R_DrawMaskedColumn
+=
+= Used for sprites and masked mid textures
+================
+*/
+
+short *mfloorclip;
+short *mceilingclip;
+fixed_t spryscale;
+fixed_t sprtopscreen;
+fixed_t sprbotscreen;
+
+void R_DrawMaskedColumn(column_t * column, signed int baseclip)
+{
+ int topscreen, bottomscreen;
+ fixed_t basetexturemid;
+
+ basetexturemid = dc_texturemid;
+
+ for (; column->topdelta != 0xff;)
+ {
+// calculate unclipped screen coordinates for post
+ topscreen = sprtopscreen + spryscale * column->topdelta;
+ bottomscreen = topscreen + spryscale * column->length;
+ dc_yl = (topscreen + FRACUNIT - 1) >> FRACBITS;
+ dc_yh = (bottomscreen - 1) >> FRACBITS;
+
+ if (dc_yh >= mfloorclip[dc_x])
+ dc_yh = mfloorclip[dc_x] - 1;
+ if (dc_yl <= mceilingclip[dc_x])
+ dc_yl = mceilingclip[dc_x] + 1;
+
+ if (dc_yh >= baseclip && baseclip != -1)
+ dc_yh = baseclip;
+
+ if (dc_yl <= dc_yh)
+ {
+ dc_source = (byte *) column + 3;
+ dc_texturemid = basetexturemid - (column->topdelta << FRACBITS);
+// dc_source = (byte *)column + 3 - column->topdelta;
+ colfunc(); // either R_DrawColumn or R_DrawTLColumn
+ }
+ column = (column_t *) ((byte *) column + column->length + 4);
+ }
+
+ dc_texturemid = basetexturemid;
+}
+
+
+/*
+================
+=
+= R_DrawVisSprite
+=
+= mfloorclip and mceilingclip should also be set
+================
+*/
+
+void R_DrawVisSprite(vissprite_t * vis, int x1, int x2)
+{
+ column_t *column;
+ int texturecolumn;
+ fixed_t frac;
+ patch_t *patch;
+ fixed_t baseclip;
+
+
+ patch = W_CacheLumpNum(vis->patch + firstspritelump, PU_CACHE);
+
+ dc_colormap = vis->colormap;
+
+// if(!dc_colormap)
+// colfunc = tlcolfunc; // NULL colormap = shadow draw
+
+ if (vis->mobjflags & (MF_SHADOW | MF_ALTSHADOW))
+ {
+ if (vis->mobjflags & MF_TRANSLATION)
+ {
+ colfunc = R_DrawTranslatedTLColumn;
+ dc_translation = translationtables - 256
+ + vis->class * ((MAXPLAYERS - 1) * 256) +
+ ((vis->mobjflags & MF_TRANSLATION) >> (MF_TRANSSHIFT - 8));
+ }
+ else if (vis->mobjflags & MF_SHADOW)
+ { // Draw using shadow column function
+ colfunc = tlcolfunc;
+ }
+ else
+ {
+ colfunc = R_DrawAltTLColumn;
+ }
+ }
+ else if (vis->mobjflags & MF_TRANSLATION)
+ {
+ // Draw using translated column function
+ colfunc = R_DrawTranslatedColumn;
+ dc_translation = translationtables - 256
+ + vis->class * ((MAXPLAYERS - 1) * 256) +
+ ((vis->mobjflags & MF_TRANSLATION) >> (MF_TRANSSHIFT - 8));
+ }
+
+ dc_iscale = abs(vis->xiscale) >> detailshift;
+ dc_texturemid = vis->texturemid;
+ frac = vis->startfrac;
+ spryscale = vis->scale;
+
+ sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale);
+
+ // check to see if vissprite is a weapon
+ if (vis->psprite)
+ {
+ dc_texturemid += FixedMul(((centery - viewheight / 2) << FRACBITS),
+ vis->xiscale);
+ sprtopscreen += (viewheight / 2 - centery) << FRACBITS;
+ }
+
+ if (vis->floorclip && !vis->psprite)
+ {
+ sprbotscreen = sprtopscreen + FixedMul(patch->height << FRACBITS,
+ spryscale);
+ baseclip = (sprbotscreen - FixedMul(vis->floorclip,
+ spryscale)) >> FRACBITS;
+ }
+ else
+ {
+ baseclip = -1;
+ }
+
+ for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, frac += vis->xiscale)
+ {
+ texturecolumn = frac >> FRACBITS;
+#ifdef RANGECHECK
+ if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width))
+ I_Error("R_DrawSpriteRange: bad texturecolumn");
+#endif
+ column = (column_t *) ((byte *) patch +
+ LONG(patch->columnofs[texturecolumn]));
+ R_DrawMaskedColumn(column, baseclip);
+ }
+
+ colfunc = basecolfunc;
+}
+
+
+
+/*
+===================
+=
+= R_ProjectSprite
+=
+= Generates a vissprite for a thing if it might be visible
+=
+===================
+*/
+
+void R_ProjectSprite(mobj_t * thing)
+{
+ fixed_t trx, try;
+ fixed_t gxt, gyt;
+ fixed_t tx, tz;
+ fixed_t xscale;
+ int x1, x2;
+ spritedef_t *sprdef;
+ spriteframe_t *sprframe;
+ int lump;
+ unsigned rot;
+ boolean flip;
+ int index;
+ vissprite_t *vis;
+ angle_t ang;
+ fixed_t iscale;
+
+ if (thing->flags2 & MF2_DONTDRAW)
+ { // Never make a vissprite when MF2_DONTDRAW is flagged.
+ return;
+ }
+
+//
+// transform the origin point
+//
+ trx = thing->x - viewx;
+ try = thing->y - viewy;
+
+ gxt = FixedMul(trx, viewcos);
+ gyt = -FixedMul(try, viewsin);
+ tz = gxt - gyt;
+
+ if (tz < MINZ)
+ return; // thing is behind view plane
+ xscale = FixedDiv(projection, tz);
+
+ gxt = -FixedMul(trx, viewsin);
+ gyt = FixedMul(try, viewcos);
+ tx = -(gyt + gxt);
+
+ if (abs(tx) > (tz << 2))
+ return; // too far off the side
+
+//
+// decide which patch to use for sprite reletive to player
+//
+#ifdef RANGECHECK
+ if ((unsigned) thing->sprite >= numsprites)
+ I_Error("R_ProjectSprite: invalid sprite number %i ", thing->sprite);
+#endif
+ sprdef = &sprites[thing->sprite];
+#ifdef RANGECHECK
+ if ((thing->frame & FF_FRAMEMASK) >= sprdef->numframes)
+ I_Error("R_ProjectSprite: invalid sprite frame %i : %i ",
+ thing->sprite, thing->frame);
+#endif
+ sprframe = &sprdef->spriteframes[thing->frame & FF_FRAMEMASK];
+
+ if (sprframe->rotate)
+ { // choose a different rotation based on player view
+ ang = R_PointToAngle(thing->x, thing->y);
+ rot = (ang - thing->angle + (unsigned) (ANG45 / 2) * 9) >> 29;
+ lump = sprframe->lump[rot];
+ flip = (boolean) sprframe->flip[rot];
+ }
+ else
+ { // use single rotation for all views
+ lump = sprframe->lump[0];
+ flip = (boolean) sprframe->flip[0];
+ }
+
+//
+// calculate edges of the shape
+//
+ tx -= spriteoffset[lump];
+ x1 = (centerxfrac + FixedMul(tx, xscale)) >> FRACBITS;
+ if (x1 > viewwidth)
+ return; // off the right side
+ tx += spritewidth[lump];
+ x2 = ((centerxfrac + FixedMul(tx, xscale)) >> FRACBITS) - 1;
+ if (x2 < 0)
+ return; // off the left side
+
+
+//
+// store information in a vissprite
+//
+ vis = R_NewVisSprite();
+ vis->mobjflags = thing->flags;
+ vis->psprite = false;
+ vis->scale = xscale << detailshift;
+ vis->gx = thing->x;
+ vis->gy = thing->y;
+ vis->gz = thing->z;
+ vis->gzt = thing->z + spritetopoffset[lump];
+ if (thing->flags & MF_TRANSLATION)
+ {
+ if (thing->player)
+ {
+ vis->class = thing->player->class;
+ }
+ else
+ {
+ vis->class = thing->special1.i;
+ }
+ if (vis->class > 2)
+ {
+ vis->class = 0;
+ }
+ }
+ // foot clipping
+ vis->floorclip = thing->floorclip;
+ vis->texturemid = vis->gzt - viewz - vis->floorclip;
+
+ vis->x1 = x1 < 0 ? 0 : x1;
+ vis->x2 = x2 >= viewwidth ? viewwidth - 1 : x2;
+ iscale = FixedDiv(FRACUNIT, xscale);
+ if (flip)
+ {
+ vis->startfrac = spritewidth[lump] - 1;
+ vis->xiscale = -iscale;
+ }
+ else
+ {
+ vis->startfrac = 0;
+ vis->xiscale = iscale;
+ }
+ if (vis->x1 > x1)
+ vis->startfrac += vis->xiscale * (vis->x1 - x1);
+ vis->patch = lump;
+//
+// get light level
+//
+
+// if (thing->flags & MF_SHADOW)
+// vis->colormap = NULL; // shadow draw
+// else ...
+
+ if (fixedcolormap)
+ vis->colormap = fixedcolormap; // fixed map
+ else if (LevelUseFullBright && thing->frame & FF_FULLBRIGHT)
+ vis->colormap = colormaps; // full bright
+ else
+ { // diminished light
+ index = xscale >> (LIGHTSCALESHIFT - detailshift);
+ if (index >= MAXLIGHTSCALE)
+ index = MAXLIGHTSCALE - 1;
+ vis->colormap = spritelights[index];
+ }
+}
+
+
+
+
+/*
+========================
+=
+= R_AddSprites
+=
+========================
+*/
+
+void R_AddSprites(sector_t * sec)
+{
+ mobj_t *thing;
+ int lightnum;
+
+ if (sec->validcount == validcount)
+ return; // already added
+
+ sec->validcount = validcount;
+
+ lightnum = (sec->lightlevel >> LIGHTSEGSHIFT) + extralight;
+ if (lightnum < 0)
+ spritelights = scalelight[0];
+ else if (lightnum >= LIGHTLEVELS)
+ spritelights = scalelight[LIGHTLEVELS - 1];
+ else
+ spritelights = scalelight[lightnum];
+
+
+ for (thing = sec->thinglist; thing; thing = thing->snext)
+ R_ProjectSprite(thing);
+}
+
+
+/*
+========================
+=
+= R_DrawPSprite
+=
+========================
+*/
+
+// Y-adjustment values for full screen (4 weapons)
+int PSpriteSY[NUMCLASSES][NUMWEAPONS] = {
+ {0, -12 * FRACUNIT, -10 * FRACUNIT, 10 * FRACUNIT}, // Fighter
+ {-8 * FRACUNIT, 10 * FRACUNIT, 10 * FRACUNIT, 0}, // Cleric
+ {9 * FRACUNIT, 20 * FRACUNIT, 20 * FRACUNIT, 20 * FRACUNIT}, // Mage
+ {10 * FRACUNIT, 10 * FRACUNIT, 10 * FRACUNIT, 10 * FRACUNIT} // Pig
+};
+
+void R_DrawPSprite(pspdef_t * psp)
+{
+ fixed_t tx;
+ int x1, x2;
+ spritedef_t *sprdef;
+ spriteframe_t *sprframe;
+ int lump;
+ boolean flip;
+ vissprite_t *vis, avis;
+
+ int tempangle;
+
+//
+// decide which patch to use
+//
+#ifdef RANGECHECK
+ if ((unsigned) psp->state->sprite >= numsprites)
+ I_Error("R_ProjectSprite: invalid sprite number %i ",
+ psp->state->sprite);
+#endif
+ sprdef = &sprites[psp->state->sprite];
+#ifdef RANGECHECK
+ if ((psp->state->frame & FF_FRAMEMASK) >= sprdef->numframes)
+ I_Error("R_ProjectSprite: invalid sprite frame %i : %i ",
+ psp->state->sprite, psp->state->frame);
+#endif
+ sprframe = &sprdef->spriteframes[psp->state->frame & FF_FRAMEMASK];
+
+ lump = sprframe->lump[0];
+ flip = (boolean) sprframe->flip[0];
+
+//
+// calculate edges of the shape
+//
+ tx = psp->sx - 160 * FRACUNIT;
+
+ tx -= spriteoffset[lump];
+ if (viewangleoffset)
+ {
+ tempangle =
+ ((centerxfrac / 1024) * (viewangleoffset >> ANGLETOFINESHIFT));
+ }
+ else
+ {
+ tempangle = 0;
+ }
+ x1 = (centerxfrac + FixedMul(tx, pspritescale) + tempangle) >> FRACBITS;
+ if (x1 > viewwidth)
+ return; // off the right side
+ tx += spritewidth[lump];
+ x2 = ((centerxfrac + FixedMul(tx, pspritescale) +
+ tempangle) >> FRACBITS) - 1;
+ if (x2 < 0)
+ return; // off the left side
+
+//
+// store information in a vissprite
+//
+ vis = &avis;
+ vis->mobjflags = 0;
+ vis->class = 0;
+ vis->psprite = true;
+ vis->texturemid = (BASEYCENTER << FRACBITS) + FRACUNIT / 2
+ - (psp->sy - spritetopoffset[lump]);
+ if (viewheight == SCREENHEIGHT)
+ {
+ vis->texturemid -= PSpriteSY[viewplayer->class]
+ [players[consoleplayer].readyweapon];
+ }
+ vis->x1 = x1 < 0 ? 0 : x1;
+ vis->x2 = x2 >= viewwidth ? viewwidth - 1 : x2;
+ vis->scale = pspritescale << detailshift;
+ if (flip)
+ {
+ vis->xiscale = -pspriteiscale;
+ vis->startfrac = spritewidth[lump] - 1;
+ }
+ else
+ {
+ vis->xiscale = pspriteiscale;
+ vis->startfrac = 0;
+ }
+ if (vis->x1 > x1)
+ vis->startfrac += vis->xiscale * (vis->x1 - x1);
+ vis->patch = lump;
+
+ if (viewplayer->powers[pw_invulnerability] && viewplayer->class
+ == PCLASS_CLERIC)
+ {
+ vis->colormap = spritelights[MAXLIGHTSCALE - 1];
+ if (viewplayer->powers[pw_invulnerability] > 4 * 32)
+ {
+ if (viewplayer->mo->flags2 & MF2_DONTDRAW)
+ { // don't draw the psprite
+ vis->mobjflags |= MF_SHADOW;
+ }
+ else if (viewplayer->mo->flags & MF_SHADOW)
+ {
+ vis->mobjflags |= MF_ALTSHADOW;
+ }
+ }
+ else if (viewplayer->powers[pw_invulnerability] & 8)
+ {
+ vis->mobjflags |= MF_SHADOW;
+ }
+ }
+ else if (fixedcolormap)
+ {
+ // Fixed color
+ vis->colormap = fixedcolormap;
+ }
+ else if (psp->state->frame & FF_FULLBRIGHT)
+ {
+ // Full bright
+ vis->colormap = colormaps;
+ }
+ else
+ {
+ // local light
+ vis->colormap = spritelights[MAXLIGHTSCALE - 1];
+ }
+ R_DrawVisSprite(vis, vis->x1, vis->x2);
+}
+
+/*
+========================
+=
+= R_DrawPlayerSprites
+=
+========================
+*/
+
+void R_DrawPlayerSprites(void)
+{
+ int i, lightnum;
+ pspdef_t *psp;
+
+//
+// get light level
+//
+ lightnum =
+ (viewplayer->mo->subsector->sector->lightlevel >> LIGHTSEGSHIFT) +
+ extralight;
+ if (lightnum < 0)
+ spritelights = scalelight[0];
+ else if (lightnum >= LIGHTLEVELS)
+ spritelights = scalelight[LIGHTLEVELS - 1];
+ else
+ spritelights = scalelight[lightnum];
+//
+// clip to screen bounds
+//
+ mfloorclip = screenheightarray;
+ mceilingclip = negonearray;
+
+//
+// add all active psprites
+//
+ for (i = 0, psp = viewplayer->psprites; i < NUMPSPRITES; i++, psp++)
+ if (psp->state)
+ R_DrawPSprite(psp);
+
+}
+
+
+/*
+========================
+=
+= R_SortVisSprites
+=
+========================
+*/
+
+vissprite_t vsprsortedhead;
+
+void R_SortVisSprites(void)
+{
+ int i, count;
+ vissprite_t *ds, *best;
+ vissprite_t unsorted;
+ fixed_t bestscale;
+
+ count = vissprite_p - vissprites;
+
+ unsorted.next = unsorted.prev = &unsorted;
+ if (!count)
+ return;
+
+ for (ds = vissprites; ds < vissprite_p; ds++)
+ {
+ ds->next = ds + 1;
+ ds->prev = ds - 1;
+ }
+ vissprites[0].prev = &unsorted;
+ unsorted.next = &vissprites[0];
+ (vissprite_p - 1)->next = &unsorted;
+ unsorted.prev = vissprite_p - 1;
+
+//
+// pull the vissprites out by scale
+//
+ best = 0; // shut up the compiler warning
+ vsprsortedhead.next = vsprsortedhead.prev = &vsprsortedhead;
+ for (i = 0; i < count; i++)
+ {
+ bestscale = INT_MAX;
+ for (ds = unsorted.next; ds != &unsorted; ds = ds->next)
+ {
+ if (ds->scale < bestscale)
+ {
+ bestscale = ds->scale;
+ best = ds;
+ }
+ }
+ best->next->prev = best->prev;
+ best->prev->next = best->next;
+ best->next = &vsprsortedhead;
+ best->prev = vsprsortedhead.prev;
+ vsprsortedhead.prev->next = best;
+ vsprsortedhead.prev = best;
+ }
+}
+
+
+
+/*
+========================
+=
+= R_DrawSprite
+=
+========================
+*/
+
+void R_DrawSprite(vissprite_t * spr)
+{
+ drawseg_t *ds;
+ short clipbot[SCREENWIDTH], cliptop[SCREENWIDTH];
+ int x, r1, r2;
+ fixed_t scale, lowscale;
+ int silhouette;
+
+ for (x = spr->x1; x <= spr->x2; x++)
+ clipbot[x] = cliptop[x] = -2;
+
+//
+// scan drawsegs from end to start for obscuring segs
+// the first drawseg that has a greater scale is the clip seg
+//
+ for (ds = ds_p - 1; ds >= drawsegs; ds--)
+ {
+ //
+ // determine if the drawseg obscures the sprite
+ //
+ if (ds->x1 > spr->x2 || ds->x2 < spr->x1 ||
+ (!ds->silhouette && !ds->maskedtexturecol))
+ continue; // doesn't cover sprite
+
+ r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1;
+ r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2;
+ if (ds->scale1 > ds->scale2)
+ {
+ lowscale = ds->scale2;
+ scale = ds->scale1;
+ }
+ else
+ {
+ lowscale = ds->scale1;
+ scale = ds->scale2;
+ }
+
+ if (scale < spr->scale || (lowscale < spr->scale
+ && !R_PointOnSegSide(spr->gx, spr->gy,
+ ds->curline)))
+ {
+ if (ds->maskedtexturecol) // masked mid texture
+ R_RenderMaskedSegRange(ds, r1, r2);
+ continue; // seg is behind sprite
+ }
+
+//
+// clip this piece of the sprite
+//
+ silhouette = ds->silhouette;
+ if (spr->gz >= ds->bsilheight)
+ silhouette &= ~SIL_BOTTOM;
+ if (spr->gzt <= ds->tsilheight)
+ silhouette &= ~SIL_TOP;
+
+ if (silhouette == 1)
+ { // bottom sil
+ for (x = r1; x <= r2; x++)
+ if (clipbot[x] == -2)
+ clipbot[x] = ds->sprbottomclip[x];
+ }
+ else if (silhouette == 2)
+ { // top sil
+ for (x = r1; x <= r2; x++)
+ if (cliptop[x] == -2)
+ cliptop[x] = ds->sprtopclip[x];
+ }
+ else if (silhouette == 3)
+ { // both
+ for (x = r1; x <= r2; x++)
+ {
+ if (clipbot[x] == -2)
+ clipbot[x] = ds->sprbottomclip[x];
+ if (cliptop[x] == -2)
+ cliptop[x] = ds->sprtopclip[x];
+ }
+ }
+
+ }
+
+//
+// all clipping has been performed, so draw the sprite
+//
+
+// check for unclipped columns
+ for (x = spr->x1; x <= spr->x2; x++)
+ {
+ if (clipbot[x] == -2)
+ clipbot[x] = viewheight;
+ if (cliptop[x] == -2)
+ cliptop[x] = -1;
+ }
+
+ mfloorclip = clipbot;
+ mceilingclip = cliptop;
+ R_DrawVisSprite(spr, spr->x1, spr->x2);
+}
+
+
+/*
+========================
+=
+= R_DrawMasked
+=
+========================
+*/
+
+void R_DrawMasked(void)
+{
+ vissprite_t *spr;
+ drawseg_t *ds;
+
+ R_SortVisSprites();
+
+ if (vissprite_p > vissprites)
+ {
+ // draw all vissprites back to front
+
+ for (spr = vsprsortedhead.next; spr != &vsprsortedhead;
+ spr = spr->next)
+ R_DrawSprite(spr);
+ }
+
+//
+// render any remaining masked mid textures
+//
+ for (ds = ds_p - 1; ds >= drawsegs; ds--)
+ if (ds->maskedtexturecol)
+ R_RenderMaskedSegRange(ds, ds->x1, ds->x2);
+
+//
+// draw the psprites on top of everything
+//
+// Added for the sideviewing with an external device
+ if (viewangleoffset <= 1024 << ANGLETOFINESHIFT || viewangleoffset >=
+ -1024 << ANGLETOFINESHIFT)
+ { // don't draw on side views
+ R_DrawPlayerSprites();
+ }
+
+// if (!viewangleoffset) // don't draw on side views
+// R_DrawPlayerSprites ();
+}
diff --git a/src/hexen/s_sound.c b/src/hexen/s_sound.c
new file mode 100644
index 00000000..438d4679
--- /dev/null
+++ b/src/hexen/s_sound.c
@@ -0,0 +1,939 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+#include "h2def.h"
+#include "m_random.h"
+#include "i_cdmus.h"
+#include "i_sound.h"
+#include "i_system.h"
+#include "m_argv.h"
+#include "m_misc.h"
+#include "r_local.h"
+#include "p_local.h" // for P_AproxDistance
+#include "sounds.h"
+#include "s_sound.h"
+
+#define PRIORITY_MAX_ADJUST 10
+#define DIST_ADJUST (MAX_SND_DIST/PRIORITY_MAX_ADJUST)
+
+#define DEFAULT_ARCHIVEPATH "o:\\sound\\archive\\"
+
+void S_ShutDown(void);
+
+boolean i_CDMusic;
+int i_CDTrack;
+int i_CDCurrentTrack;
+int i_CDMusicLength;
+int oldTic;
+
+/*
+===============================================================================
+
+ MUSIC & SFX API
+
+===============================================================================
+*/
+
+//static channel_t channel[MAX_CHANNELS];
+
+//static int rs; //the current registered song.
+//int mus_song = -1;
+//int mus_lumpnum;
+//void *mus_sndptr;
+//byte *soundCurve;
+
+extern sfxinfo_t S_sfx[];
+extern musicinfo_t S_music[];
+
+static channel_t Channel[MAX_CHANNELS];
+static void *RegisteredSong; //the current registered song.
+static boolean MusicPaused;
+static int Mus_Song = -1;
+static byte *Mus_SndPtr;
+static byte *SoundCurve;
+
+int snd_MaxVolume = 10; // maximum volume for sound
+int snd_MusicVolume = 10; // maximum volume for music
+int snd_Channels = 16;
+
+// int AmbChan;
+
+//==========================================================================
+//
+// S_Start
+//
+//==========================================================================
+
+void S_Start(void)
+{
+ S_StopAllSound();
+ S_StartSong(gamemap, true);
+}
+
+//==========================================================================
+//
+// S_StartSong
+//
+//==========================================================================
+
+void S_StartSong(int song, boolean loop)
+{
+ char *songLump;
+ int lumpnum;
+ int length;
+ int track;
+
+ if (i_CDMusic)
+ { // Play a CD track, instead
+ if (i_CDTrack)
+ { // Default to the player-chosen track
+ track = i_CDTrack;
+ }
+ else
+ {
+ track = P_GetMapCDTrack(gamemap);
+ }
+ if (track == i_CDCurrentTrack && i_CDMusicLength > 0)
+ {
+ return;
+ }
+ if (!I_CDMusPlay(track))
+ {
+ if (loop)
+ {
+ i_CDMusicLength = 35 * I_CDMusTrackLength(track);
+ oldTic = gametic;
+ }
+ else
+ {
+ i_CDMusicLength = -1;
+ }
+ i_CDCurrentTrack = track;
+ }
+ }
+ else
+ {
+ if (song == Mus_Song)
+ { // don't replay an old song
+ return;
+ }
+ if (RegisteredSong)
+ {
+ I_StopSong();
+ I_UnRegisterSong(RegisteredSong);
+ RegisteredSong = 0;
+ }
+ songLump = P_GetMapSongLump(song);
+ if (!songLump)
+ {
+ return;
+ }
+
+ lumpnum = W_GetNumForName(songLump);
+ Mus_SndPtr = W_CacheLumpNum(lumpnum, PU_STATIC);
+ length = W_LumpLength(lumpnum);
+
+ RegisteredSong = I_RegisterSong(Mus_SndPtr, length);
+ I_PlaySong(RegisteredSong, loop);
+ Mus_Song = song;
+
+ W_ReleaseLumpNum(lumpnum);
+ }
+}
+
+//==========================================================================
+//
+// S_StartSongName
+//
+//==========================================================================
+
+void S_StartSongName(char *songLump, boolean loop)
+{
+ int lumpnum;
+ int cdTrack;
+ int length;
+
+ if (!songLump)
+ {
+ return;
+ }
+ if (i_CDMusic)
+ {
+ cdTrack = 0;
+
+ if (!strcmp(songLump, "hexen"))
+ {
+ cdTrack = P_GetCDTitleTrack();
+ }
+ else if (!strcmp(songLump, "hub"))
+ {
+ cdTrack = P_GetCDIntermissionTrack();
+ }
+ else if (!strcmp(songLump, "hall"))
+ {
+ cdTrack = P_GetCDEnd1Track();
+ }
+ else if (!strcmp(songLump, "orb"))
+ {
+ cdTrack = P_GetCDEnd2Track();
+ }
+ else if (!strcmp(songLump, "chess") && !i_CDTrack)
+ {
+ cdTrack = P_GetCDEnd3Track();
+ }
+/* Uncomment this, if Kevin writes a specific song for startup
+ else if(!strcmp(songLump, "start"))
+ {
+ cdTrack = P_GetCDStartTrack();
+ }
+*/
+ if (!cdTrack || (cdTrack == i_CDCurrentTrack && i_CDMusicLength > 0))
+ {
+ return;
+ }
+ if (!I_CDMusPlay(cdTrack))
+ {
+ if (loop)
+ {
+ i_CDMusicLength = 35 * I_CDMusTrackLength(cdTrack);
+ oldTic = gametic;
+ }
+ else
+ {
+ i_CDMusicLength = -1;
+ }
+ i_CDCurrentTrack = cdTrack;
+ i_CDTrack = false;
+ }
+ }
+ else
+ {
+ if (RegisteredSong)
+ {
+ I_StopSong();
+ I_UnRegisterSong(RegisteredSong);
+ RegisteredSong = NULL;
+ }
+
+ lumpnum = W_GetNumForName(songLump);
+ Mus_SndPtr = W_CacheLumpNum(lumpnum, PU_MUSIC);
+ length = W_LumpLength(lumpnum);
+
+ RegisteredSong = I_RegisterSong(Mus_SndPtr, length);
+ I_PlaySong(RegisteredSong, loop);
+ W_ReleaseLumpNum(lumpnum);
+ Mus_Song = -1;
+ }
+}
+
+//==========================================================================
+//
+// S_GetSoundID
+//
+//==========================================================================
+
+int S_GetSoundID(char *name)
+{
+ int i;
+
+ for (i = 0; i < NUMSFX; i++)
+ {
+ if (!strcmp(S_sfx[i].tagname, name))
+ {
+ return i;
+ }
+ }
+ return 0;
+}
+
+//==========================================================================
+//
+// S_StartSound
+//
+//==========================================================================
+
+void S_StartSound(mobj_t * origin, int sound_id)
+{
+ S_StartSoundAtVolume(origin, sound_id, 127);
+}
+
+static mobj_t *GetSoundListener(void)
+{
+ static degenmobj_t dummy_listener;
+
+ // If we are at the title screen, the console player doesn't have an
+ // object yet, so return a pointer to a static dummy listener instead.
+
+ if (players[displayplayer].mo != NULL)
+ {
+ return players[displayplayer].mo;
+ }
+ else
+ {
+ dummy_listener.x = 0;
+ dummy_listener.y = 0;
+ dummy_listener.z = 0;
+
+ return (mobj_t *) &dummy_listener;
+ }
+}
+
+//==========================================================================
+//
+// S_StartSoundAtVolume
+//
+//==========================================================================
+
+void S_StartSoundAtVolume(mobj_t * origin, int sound_id, int volume)
+{
+ mobj_t *listener;
+ int dist, vol;
+ int i;
+ int priority;
+ int sep;
+ int angle;
+ int absx;
+ int absy;
+
+ static int sndcount = 0;
+ int chan;
+
+ if (sound_id == 0 || snd_MaxVolume == 0)
+ return;
+
+ listener = GetSoundListener();
+
+ if (origin == NULL)
+ {
+ origin = listener;
+ }
+ if (volume == 0)
+ {
+ return;
+ }
+
+ // calculate the distance before other stuff so that we can throw out
+ // sounds that are beyond the hearing range.
+ absx = abs(origin->x - listener->x);
+ absy = abs(origin->y - listener->y);
+ dist = absx + absy - (absx > absy ? absy >> 1 : absx >> 1);
+ dist >>= FRACBITS;
+ if (dist >= MAX_SND_DIST)
+ {
+ return; // sound is beyond the hearing range...
+ }
+ if (dist < 0)
+ {
+ dist = 0;
+ }
+ priority = S_sfx[sound_id].priority;
+ priority *= (PRIORITY_MAX_ADJUST - (dist / DIST_ADJUST));
+ #if 0
+ // TODO
+ if (!S_StopSoundID(sound_id, priority))
+ {
+ return; // other sounds have greater priority
+ }
+ #endif
+ for (i = 0; i < snd_Channels; i++)
+ {
+ if (origin->player)
+ {
+ i = snd_Channels;
+ break; // let the player have more than one sound.
+ }
+ if (origin == Channel[i].mo)
+ { // only allow other mobjs one sound
+ S_StopSound(Channel[i].mo);
+ break;
+ }
+ }
+ if (i >= snd_Channels)
+ {
+ for (i = 0; i < snd_Channels; i++)
+ {
+ if (Channel[i].mo == NULL)
+ {
+ break;
+ }
+ }
+ if (i >= snd_Channels)
+ {
+ // look for a lower priority sound to replace.
+ sndcount++;
+ if (sndcount >= snd_Channels)
+ {
+ sndcount = 0;
+ }
+ for (chan = 0; chan < snd_Channels; chan++)
+ {
+ i = (sndcount + chan) % snd_Channels;
+ if (priority >= Channel[i].priority)
+ {
+ chan = -1; //denote that sound should be replaced.
+ break;
+ }
+ }
+ if (chan != -1)
+ {
+ return; //no free channels.
+ }
+ else //replace the lower priority sound.
+ {
+ if (Channel[i].handle)
+ {
+ if (I_SoundIsPlaying(Channel[i].handle))
+ {
+ I_StopSound(Channel[i].handle);
+ }
+ if (S_sfx[Channel[i].sound_id].usefulness > 0)
+ {
+ S_sfx[Channel[i].sound_id].usefulness--;
+ }
+ }
+ }
+ }
+ }
+
+ Channel[i].mo = origin;
+
+ vol = (SoundCurve[dist] * (snd_MaxVolume * 8) * volume) >> 14;
+ if (origin == listener)
+ {
+ sep = 128;
+// vol = (volume*(snd_MaxVolume+1)*8)>>7;
+ }
+ else
+ {
+ angle = R_PointToAngle2(listener->x,
+ listener->y,
+ Channel[i].mo->x, Channel[i].mo->y);
+ angle = (angle - viewangle) >> 24;
+ sep = angle * 2 - 128;
+ if (sep < 64)
+ sep = -sep;
+ if (sep > 192)
+ sep = 512 - sep;
+// vol = SoundCurve[dist];
+ }
+
+#if 0
+// TODO
+ if (S_sfx[sound_id].changePitch)
+ {
+ Channel[i].pitch = (byte) (127 + (M_Random() & 7) - (M_Random() & 7));
+ }
+ else
+ {
+ Channel[i].pitch = 127;
+ }
+#endif
+ if (S_sfx[sound_id].lumpnum == 0)
+ {
+ S_sfx[sound_id].lumpnum = I_GetSfxLumpNum(&S_sfx[sound_id]);
+ }
+
+ Channel[i].handle = I_StartSound(&S_sfx[sound_id],
+ i,
+ vol,
+ sep /* , Channel[i].pitch] */);
+ Channel[i].sound_id = sound_id;
+ Channel[i].priority = priority;
+ Channel[i].volume = volume;
+ if (S_sfx[sound_id].usefulness < 0)
+ {
+ S_sfx[sound_id].usefulness = 1;
+ }
+ else
+ {
+ S_sfx[sound_id].usefulness++;
+ }
+}
+
+//==========================================================================
+//
+// S_StopSoundID
+//
+//==========================================================================
+
+boolean S_StopSoundID(int sound_id, int priority)
+{
+ int i;
+ int lp; //least priority
+ int found;
+
+ if (S_sfx[sound_id].numchannels == -1)
+ {
+ return (true);
+ }
+ lp = -1; //denote the argument sound_id
+ found = 0;
+ for (i = 0; i < snd_Channels; i++)
+ {
+ if (Channel[i].sound_id == sound_id && Channel[i].mo)
+ {
+ found++; //found one. Now, should we replace it??
+ if (priority >= Channel[i].priority)
+ { // if we're gonna kill one, then this'll be it
+ lp = i;
+ priority = Channel[i].priority;
+ }
+ }
+ }
+ if (found < S_sfx[sound_id].numchannels)
+ {
+ return (true);
+ }
+ else if (lp == -1)
+ {
+ return (false); // don't replace any sounds
+ }
+ if (Channel[lp].handle)
+ {
+ if (I_SoundIsPlaying(Channel[lp].handle))
+ {
+ I_StopSound(Channel[lp].handle);
+ }
+ if (S_sfx[Channel[lp].sound_id].usefulness > 0)
+ {
+ S_sfx[Channel[lp].sound_id].usefulness--;
+ }
+ Channel[lp].mo = NULL;
+ }
+ return (true);
+}
+
+//==========================================================================
+//
+// S_StopSound
+//
+//==========================================================================
+
+void S_StopSound(mobj_t * origin)
+{
+ int i;
+
+ for (i = 0; i < snd_Channels; i++)
+ {
+ if (Channel[i].mo == origin)
+ {
+ I_StopSound(Channel[i].handle);
+ if (S_sfx[Channel[i].sound_id].usefulness > 0)
+ {
+ S_sfx[Channel[i].sound_id].usefulness--;
+ }
+ Channel[i].handle = 0;
+ Channel[i].mo = NULL;
+ }
+ }
+}
+
+//==========================================================================
+//
+// S_StopAllSound
+//
+//==========================================================================
+
+void S_StopAllSound(void)
+{
+ int i;
+
+ //stop all sounds
+ for (i = 0; i < snd_Channels; i++)
+ {
+ if (Channel[i].handle)
+ {
+ S_StopSound(Channel[i].mo);
+ }
+ }
+ memset(Channel, 0, 8 * sizeof(channel_t));
+}
+
+//==========================================================================
+//
+// S_SoundLink
+//
+//==========================================================================
+
+void S_SoundLink(mobj_t * oldactor, mobj_t * newactor)
+{
+ int i;
+
+ for (i = 0; i < snd_Channels; i++)
+ {
+ if (Channel[i].mo == oldactor)
+ Channel[i].mo = newactor;
+ }
+}
+
+//==========================================================================
+//
+// S_PauseSound
+//
+//==========================================================================
+
+void S_PauseSound(void)
+{
+ if (i_CDMusic)
+ {
+ I_CDMusStop();
+ }
+ else
+ {
+ I_PauseSong();
+ }
+}
+
+//==========================================================================
+//
+// S_ResumeSound
+//
+//==========================================================================
+
+void S_ResumeSound(void)
+{
+ if (i_CDMusic)
+ {
+ I_CDMusResume();
+ }
+ else
+ {
+ I_ResumeSong();
+ }
+}
+
+//==========================================================================
+//
+// S_UpdateSounds
+//
+//==========================================================================
+
+void S_UpdateSounds(mobj_t * listener)
+{
+ int i, dist, vol;
+ int angle;
+ int sep;
+ int priority;
+ int absx;
+ int absy;
+
+#ifdef CDMUSIC
+ if (i_CDMusic)
+ {
+ I_UpdateCDMusic();
+ }
+#endif
+ if (snd_MaxVolume == 0)
+ {
+ return;
+ }
+
+ // Update any Sequences
+ SN_UpdateActiveSequences();
+
+ for (i = 0; i < snd_Channels; i++)
+ {
+ if (!Channel[i].handle || S_sfx[Channel[i].sound_id].usefulness == -1)
+ {
+ continue;
+ }
+ if (!I_SoundIsPlaying(Channel[i].handle))
+ {
+ if (S_sfx[Channel[i].sound_id].usefulness > 0)
+ {
+ S_sfx[Channel[i].sound_id].usefulness--;
+ }
+ Channel[i].handle = 0;
+ Channel[i].mo = NULL;
+ Channel[i].sound_id = 0;
+ }
+ if (Channel[i].mo == NULL || Channel[i].sound_id == 0
+ || Channel[i].mo == listener || listener == NULL)
+ {
+ continue;
+ }
+ else
+ {
+ absx = abs(Channel[i].mo->x - listener->x);
+ absy = abs(Channel[i].mo->y - listener->y);
+ dist = absx + absy - (absx > absy ? absy >> 1 : absx >> 1);
+ dist >>= FRACBITS;
+
+ if (dist >= MAX_SND_DIST)
+ {
+ S_StopSound(Channel[i].mo);
+ continue;
+ }
+ if (dist < 0)
+ {
+ dist = 0;
+ }
+ //vol = SoundCurve[dist];
+ vol =
+ (SoundCurve[dist] * (snd_MaxVolume * 8) *
+ Channel[i].volume) >> 14;
+ if (Channel[i].mo == listener)
+ {
+ sep = 128;
+ }
+ else
+ {
+ angle = R_PointToAngle2(listener->x, listener->y,
+ Channel[i].mo->x, Channel[i].mo->y);
+ angle = (angle - viewangle) >> 24;
+ sep = angle * 2 - 128;
+ if (sep < 64)
+ sep = -sep;
+ if (sep > 192)
+ sep = 512 - sep;
+ }
+ I_UpdateSoundParams(i, vol, sep /*, Channel[i].pitch */);
+ priority = S_sfx[Channel[i].sound_id].priority;
+ priority *= PRIORITY_MAX_ADJUST - (dist / DIST_ADJUST);
+ Channel[i].priority = priority;
+ }
+ }
+}
+
+//==========================================================================
+//
+// S_Init
+//
+//==========================================================================
+
+void S_Init(void)
+{
+ SoundCurve = W_CacheLumpName("SNDCURVE", PU_STATIC);
+// SoundCurve = Z_Malloc(MAX_SND_DIST, PU_STATIC, NULL);
+
+ I_InitSound(false);
+
+ if (snd_Channels > 8)
+ {
+ snd_Channels = 8;
+ }
+ I_SetMusicVolume(snd_MusicVolume * 8);
+
+ I_AtExit(S_ShutDown, true);
+
+#ifdef CDMUSIC
+//TODO
+ // Attempt to setup CD music
+ if (snd_MusicDevice == snd_CDMUSIC)
+ {
+ ST_Message(" Attempting to initialize CD Music: ");
+ if (!cdrom)
+ {
+ i_CDMusic = (I_CDMusInit() != -1);
+ }
+ else
+ { // The user is trying to use the cdrom for both game and music
+ i_CDMusic = false;
+ }
+ if (i_CDMusic)
+ {
+ ST_Message("initialized.\n");
+ }
+ else
+ {
+ ST_Message("failed.\n");
+ }
+ }
+#endif
+}
+
+//==========================================================================
+//
+// S_GetChannelInfo
+//
+//==========================================================================
+
+void S_GetChannelInfo(SoundInfo_t * s)
+{
+ int i;
+ ChanInfo_t *c;
+
+ s->channelCount = snd_Channels;
+ s->musicVolume = snd_MusicVolume;
+ s->soundVolume = snd_MaxVolume;
+ for (i = 0; i < snd_Channels; i++)
+ {
+ c = &s->chan[i];
+ c->id = Channel[i].sound_id;
+ c->priority = Channel[i].priority;
+ c->name = S_sfx[c->id].name;
+ c->mo = Channel[i].mo;
+
+ if (c->mo != NULL)
+ {
+ c->distance = P_AproxDistance(c->mo->x - viewx, c->mo->y - viewy)
+ >> FRACBITS;
+ }
+ else
+ {
+ c->distance = 0;
+ }
+ }
+}
+
+//==========================================================================
+//
+// S_GetSoundPlayingInfo
+//
+//==========================================================================
+
+boolean S_GetSoundPlayingInfo(mobj_t * mobj, int sound_id)
+{
+ int i;
+
+ for (i = 0; i < snd_Channels; i++)
+ {
+ if (Channel[i].sound_id == sound_id && Channel[i].mo == mobj)
+ {
+ if (I_SoundIsPlaying(Channel[i].handle))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+//==========================================================================
+//
+// S_SetMusicVolume
+//
+//==========================================================================
+
+void S_SetMusicVolume(void)
+{
+ if (i_CDMusic)
+ {
+ I_CDMusSetVolume(snd_MusicVolume * 16); // 0-255
+ }
+ else
+ {
+ I_SetMusicVolume(snd_MusicVolume * 8);
+ }
+ if (snd_MusicVolume == 0)
+ {
+ if (!i_CDMusic)
+ {
+ I_PauseSong();
+ }
+ MusicPaused = true;
+ }
+ else if (MusicPaused)
+ {
+ if (!i_CDMusic)
+ {
+ I_ResumeSong();
+ }
+ MusicPaused = false;
+ }
+}
+
+//==========================================================================
+//
+// S_ShutDown
+//
+//==========================================================================
+
+void S_ShutDown(void)
+{
+ I_StopSong();
+ I_UnRegisterSong(RegisteredSong);
+ I_ShutdownSound();
+ if (i_CDMusic)
+ {
+ I_CDMusStop();
+ }
+}
+
+//==========================================================================
+//
+// S_InitScript
+//
+//==========================================================================
+
+void S_InitScript(void)
+{
+ int i;
+
+ SC_OpenLump("sndinfo");
+
+ while (SC_GetString())
+ {
+ if (*sc_String == '$')
+ {
+ if (!strcasecmp(sc_String, "$ARCHIVEPATH"))
+ {
+ SC_MustGetString();
+ }
+ else if (!strcasecmp(sc_String, "$MAP"))
+ {
+ SC_MustGetNumber();
+ SC_MustGetString();
+ if (sc_Number)
+ {
+ P_PutMapSongLump(sc_Number, sc_String);
+ }
+ }
+ continue;
+ }
+ else
+ {
+ for (i = 0; i < NUMSFX; i++)
+ {
+ if (!strcmp(S_sfx[i].tagname, sc_String))
+ {
+ SC_MustGetString();
+ if (*sc_String != '?')
+ {
+ strcpy(S_sfx[i].name, sc_String);
+ }
+ else
+ {
+ strcpy(S_sfx[i].name, "default");
+ }
+ break;
+ }
+ }
+ if (i == NUMSFX)
+ {
+ SC_MustGetString();
+ }
+ }
+ }
+ SC_Close();
+
+ for (i = 0; i < NUMSFX; i++)
+ {
+ if (!strcmp(S_sfx[i].name, ""))
+ {
+ strcpy(S_sfx[i].name, "default");
+ }
+ }
+}
+
diff --git a/src/hexen/s_sound.h b/src/hexen/s_sound.h
new file mode 100644
index 00000000..b66a513e
--- /dev/null
+++ b/src/hexen/s_sound.h
@@ -0,0 +1,99 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __S_SOUND__
+#define __S_SOUND__
+
+/*
+typedef struct
+{
+ char name[8];
+ int p1;
+} musicinfo_t;
+*/
+
+/*
+typedef struct sfxinfo_s
+{
+ char tagName[32];
+ char lumpname[12]; // Only need 9 bytes, but padded out to be dword aligned
+ //struct sfxinfo_s *link; // Make alias for another sound
+ int priority; // Higher priority takes precendence
+ int usefulness; // Determines when a sound should be cached out
+ void *snd_ptr;
+ int lumpnum;
+ int numchannels; // total number of channels a sound type may occupy
+ boolean changePitch;
+} sfxinfo_t;
+*/
+
+typedef struct
+{
+ mobj_t *mo;
+ int sound_id;
+ int handle;
+ int volume;
+ int pitch;
+ int priority;
+} channel_t;
+
+typedef struct
+{
+ int id;
+ unsigned short priority;
+ char *name;
+ mobj_t *mo;
+ int distance;
+} ChanInfo_t;
+
+typedef struct
+{
+ int channelCount;
+ int musicVolume;
+ int soundVolume;
+ ChanInfo_t chan[8];
+} SoundInfo_t;
+
+extern int snd_MaxVolume;
+extern int snd_MusicVolume;
+extern int snd_Channels;
+
+void S_Start(void);
+void S_StartSound(mobj_t * origin, int sound_id);
+int S_GetSoundID(char *name);
+void S_StartSoundAtVolume(mobj_t * origin, int sound_id, int volume);
+void S_StopSound(mobj_t * origin);
+void S_StopAllSound(void);
+void S_PauseSound(void);
+void S_ResumeSound(void);
+void S_UpdateSounds(mobj_t * listener);
+void S_StartSong(int song, boolean loop);
+void S_StartSongName(char *songLump, boolean loop);
+void S_Init(void);
+void S_GetChannelInfo(SoundInfo_t * s);
+void S_SetMusicVolume(void);
+boolean S_GetSoundPlayingInfo(mobj_t * mobj, int sound_id);
+
+#endif
diff --git a/src/hexen/sb_bar.c b/src/hexen/sb_bar.c
new file mode 100644
index 00000000..bcaa40be
--- /dev/null
+++ b/src/hexen/sb_bar.c
@@ -0,0 +1,1997 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2def.h"
+#include "i_video.h"
+#include "m_bbox.h"
+#include "m_cheat.h"
+#include "m_misc.h"
+#include "p_local.h"
+#include "s_sound.h"
+#include "v_video.h"
+
+#include "i_sound.h" // For CD stuff
+
+// TYPES -------------------------------------------------------------------
+
+typedef struct Cheat_s
+{
+ void (*func) (player_t * player, struct Cheat_s * cheat);
+ cheatseq_t *seq;
+} Cheat_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void DrawSoundInfo(void);
+static void DrINumber(signed int val, int x, int y);
+static void DrRedINumber(signed int val, int x, int y);
+static void DrBNumber(signed int val, int x, int y);
+static void DrawCommonBar(void);
+static void DrawMainBar(void);
+static void DrawInventoryBar(void);
+static void DrawKeyBar(void);
+static void DrawWeaponPieces(void);
+static void DrawFullScreenStuff(void);
+static void DrawAnimatedIcons(void);
+static boolean HandleCheats(byte key);
+static boolean CheatAddKey(Cheat_t * cheat, byte key, boolean * eat);
+static void CheatGodFunc(player_t * player, Cheat_t * cheat);
+static void CheatNoClipFunc(player_t * player, Cheat_t * cheat);
+static void CheatWeaponsFunc(player_t * player, Cheat_t * cheat);
+static void CheatHealthFunc(player_t * player, Cheat_t * cheat);
+static void CheatKeysFunc(player_t * player, Cheat_t * cheat);
+static void CheatSoundFunc(player_t * player, Cheat_t * cheat);
+static void CheatTickerFunc(player_t * player, Cheat_t * cheat);
+static void CheatArtifactAllFunc(player_t * player, Cheat_t * cheat);
+static void CheatPuzzleFunc(player_t * player, Cheat_t * cheat);
+static void CheatWarpFunc(player_t * player, Cheat_t * cheat);
+static void CheatPigFunc(player_t * player, Cheat_t * cheat);
+static void CheatMassacreFunc(player_t * player, Cheat_t * cheat);
+static void CheatIDKFAFunc(player_t * player, Cheat_t * cheat);
+static void CheatQuickenFunc1(player_t * player, Cheat_t * cheat);
+static void CheatQuickenFunc2(player_t * player, Cheat_t * cheat);
+static void CheatQuickenFunc3(player_t * player, Cheat_t * cheat);
+static void CheatClassFunc1(player_t * player, Cheat_t * cheat);
+static void CheatClassFunc2(player_t * player, Cheat_t * cheat);
+static void CheatInitFunc(player_t * player, Cheat_t * cheat);
+static void CheatVersionFunc(player_t * player, Cheat_t * cheat);
+static void CheatDebugFunc(player_t * player, Cheat_t * cheat);
+static void CheatScriptFunc1(player_t * player, Cheat_t * cheat);
+static void CheatScriptFunc2(player_t * player, Cheat_t * cheat);
+static void CheatScriptFunc3(player_t * player, Cheat_t * cheat);
+static void CheatRevealFunc(player_t * player, Cheat_t * cheat);
+static void CheatTrackFunc1(player_t * player, Cheat_t * cheat);
+static void CheatTrackFunc2(player_t * player, Cheat_t * cheat);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern int ArmorIncrement[NUMCLASSES][NUMARMOR];
+extern int AutoArmorSave[NUMCLASSES];
+
+// haleyjd FIXME: CDMUSIC
+#ifdef __WATCOMC__
+extern boolean i_CDMusic;
+extern int i_CDMusicLength;
+extern int i_CDTrack;
+extern int i_CDCurrentTrack;
+extern int oldTic;
+#endif
+
+// PUBLIC DATA DECLARATIONS ------------------------------------------------
+
+boolean DebugSound; // Debug flag for displaying sound info
+boolean inventory;
+int curpos;
+int inv_ptr;
+int ArtifactFlash;
+
+// haleyjd FIXME: CDMUSIC
+#ifndef __WATCOMC__
+boolean i_CDMusic; // in Watcom, defined in i_ibm
+#endif
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static int DisplayTicker = 0;
+static int HealthMarker;
+//static int ChainWiggle;
+static player_t *CPlayer;
+static int SpinFlylump;
+static int SpinMinotaurLump;
+static int SpinSpeedLump;
+static int SpinDefenseLump;
+
+static int FontBNumBase;
+static int PlayPalette;
+
+static patch_t *PatchH2BAR;
+static patch_t *PatchH2TOP;
+static patch_t *PatchLFEDGE;
+static patch_t *PatchRTEDGE;
+static patch_t *PatchARMCLEAR;
+static patch_t *PatchARTICLEAR;
+static patch_t *PatchMANACLEAR;
+static patch_t *PatchKILLS;
+static patch_t *PatchMANAVIAL1;
+static patch_t *PatchMANAVIAL2;
+static patch_t *PatchMANAVIALDIM1;
+static patch_t *PatchMANAVIALDIM2;
+static patch_t *PatchMANADIM1;
+static patch_t *PatchMANADIM2;
+static patch_t *PatchMANABRIGHT1;
+static patch_t *PatchMANABRIGHT2;
+static patch_t *PatchCHAIN;
+static patch_t *PatchSTATBAR;
+static patch_t *PatchKEYBAR;
+static patch_t *PatchLIFEGEM;
+static patch_t *PatchSELECTBOX;
+static patch_t *PatchINumbers[10];
+static patch_t *PatchNEGATIVE;
+static patch_t *PatchSmNumbers[10];
+static patch_t *PatchINVBAR;
+static patch_t *PatchWEAPONSLOT;
+static patch_t *PatchWEAPONFULL;
+static patch_t *PatchPIECE1;
+static patch_t *PatchPIECE2;
+static patch_t *PatchPIECE3;
+static patch_t *PatchINVLFGEM1;
+static patch_t *PatchINVLFGEM2;
+static patch_t *PatchINVRTGEM1;
+static patch_t *PatchINVRTGEM2;
+
+// Toggle god mode
+cheatseq_t CheatGodSeq = CHEAT("satan", 0);
+
+// Toggle no clipping mode
+cheatseq_t CheatNoClipSeq = CHEAT("casper", 0);
+
+// Get all weapons and mana
+cheatseq_t CheatWeaponsSeq = CHEAT("nra", 0);
+
+// Get full health
+cheatseq_t CheatHealthSeq = CHEAT("clubmed", 0);
+
+// Get all keys
+cheatseq_t CheatKeysSeq = CHEAT("locksmith", 0);
+
+// Toggle sound debug info
+cheatseq_t CheatSoundSeq = CHEAT("noise", 0);
+
+// Toggle ticker
+cheatseq_t CheatTickerSeq = CHEAT("ticker", 0);
+
+// Get all artifacts
+cheatseq_t CheatArtifactAllSeq = CHEAT("indiana", 0);
+
+// Get all puzzle pieces
+cheatseq_t CheatPuzzleSeq = CHEAT("sherlock", 0);
+
+// Warp to new level
+cheatseq_t CheatWarpSeq = CHEAT("visit", 2);
+
+// Become a pig
+cheatseq_t CheatPigSeq = CHEAT("deliverance", 0);
+
+// Kill all monsters
+cheatseq_t CheatMassacreSeq = CHEAT("butcher", 0);
+
+cheatseq_t CheatIDKFASeq = CHEAT("conan", 0);
+
+cheatseq_t CheatQuickenSeq1 = CHEAT("martek", 0);
+
+cheatseq_t CheatQuickenSeq2 = CHEAT("martekmartek", 0);
+
+cheatseq_t CheatQuickenSeq3 = CHEAT("martekmartekmartek", 0);
+
+// New class
+cheatseq_t CheatClass1Seq = CHEAT("shadowcaster", 0);
+
+cheatseq_t CheatClass2Seq = CHEAT("shadowcaster", 1);
+
+cheatseq_t CheatInitSeq = CHEAT("init", 0);
+
+cheatseq_t CheatVersionSeq = CHEAT("mrjones", 0);
+
+cheatseq_t CheatDebugSeq = CHEAT("where", 0);
+
+cheatseq_t CheatScriptSeq1 = CHEAT("puke", 0);
+
+cheatseq_t CheatScriptSeq2 = CHEAT("puke", 1);
+
+cheatseq_t CheatScriptSeq3 = CHEAT("puke", 2);
+
+cheatseq_t CheatRevealSeq = CHEAT("mapsco", 0);
+
+cheatseq_t CheatTrackSeq1 = CHEAT("`", 0);
+
+cheatseq_t CheatTrackSeq2 = CHEAT("`", 2);
+
+static Cheat_t Cheats[] = {
+ {CheatTrackFunc1, &CheatTrackSeq1},
+ {CheatTrackFunc2, &CheatTrackSeq2},
+ {CheatGodFunc, &CheatGodSeq},
+ {CheatNoClipFunc, &CheatNoClipSeq},
+ {CheatWeaponsFunc, &CheatWeaponsSeq},
+ {CheatHealthFunc, &CheatHealthSeq},
+ {CheatKeysFunc, &CheatKeysSeq},
+ {CheatSoundFunc, &CheatSoundSeq},
+ {CheatTickerFunc, &CheatTickerSeq},
+ {CheatArtifactAllFunc, &CheatArtifactAllSeq},
+ {CheatPuzzleFunc, &CheatPuzzleSeq},
+ {CheatWarpFunc, &CheatWarpSeq},
+ {CheatPigFunc, &CheatPigSeq},
+ {CheatMassacreFunc, &CheatMassacreSeq},
+ {CheatIDKFAFunc, &CheatIDKFASeq},
+ {CheatQuickenFunc1, &CheatQuickenSeq1},
+ {CheatQuickenFunc2, &CheatQuickenSeq2},
+ {CheatQuickenFunc3, &CheatQuickenSeq3},
+ {CheatClassFunc1, &CheatClass1Seq},
+ {CheatClassFunc2, &CheatClass2Seq},
+ {CheatInitFunc, &CheatInitSeq},
+ {CheatVersionFunc, &CheatVersionSeq},
+ {CheatDebugFunc, &CheatDebugSeq},
+ {CheatScriptFunc1, &CheatScriptSeq1},
+ {CheatScriptFunc2, &CheatScriptSeq2},
+ {CheatScriptFunc3, &CheatScriptSeq3},
+ {CheatRevealFunc, &CheatRevealSeq},
+};
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// SB_Init
+//
+//==========================================================================
+
+void SB_Init(void)
+{
+ int i;
+ int startLump;
+
+ PatchH2BAR = W_CacheLumpName("H2BAR", PU_STATIC);
+ PatchH2TOP = W_CacheLumpName("H2TOP", PU_STATIC);
+ PatchINVBAR = W_CacheLumpName("INVBAR", PU_STATIC);
+ PatchLFEDGE = W_CacheLumpName("LFEDGE", PU_STATIC);
+ PatchRTEDGE = W_CacheLumpName("RTEDGE", PU_STATIC);
+ PatchSTATBAR = W_CacheLumpName("STATBAR", PU_STATIC);
+ PatchKEYBAR = W_CacheLumpName("KEYBAR", PU_STATIC);
+ PatchSELECTBOX = W_CacheLumpName("SELECTBOX", PU_STATIC);
+ PatchARTICLEAR = W_CacheLumpName("ARTICLS", PU_STATIC);
+ PatchARMCLEAR = W_CacheLumpName("ARMCLS", PU_STATIC);
+ PatchMANACLEAR = W_CacheLumpName("MANACLS", PU_STATIC);
+ PatchMANAVIAL1 = W_CacheLumpName("MANAVL1", PU_STATIC);
+ PatchMANAVIAL2 = W_CacheLumpName("MANAVL2", PU_STATIC);
+ PatchMANAVIALDIM1 = W_CacheLumpName("MANAVL1D", PU_STATIC);
+ PatchMANAVIALDIM2 = W_CacheLumpName("MANAVL2D", PU_STATIC);
+ PatchMANADIM1 = W_CacheLumpName("MANADIM1", PU_STATIC);
+ PatchMANADIM2 = W_CacheLumpName("MANADIM2", PU_STATIC);
+ PatchMANABRIGHT1 = W_CacheLumpName("MANABRT1", PU_STATIC);
+ PatchMANABRIGHT2 = W_CacheLumpName("MANABRT2", PU_STATIC);
+ PatchINVLFGEM1 = W_CacheLumpName("invgeml1", PU_STATIC);
+ PatchINVLFGEM2 = W_CacheLumpName("invgeml2", PU_STATIC);
+ PatchINVRTGEM1 = W_CacheLumpName("invgemr1", PU_STATIC);
+ PatchINVRTGEM2 = W_CacheLumpName("invgemr2", PU_STATIC);
+
+// PatchCHAINBACK = W_CacheLumpName("CHAINBACK", PU_STATIC);
+ startLump = W_GetNumForName("IN0");
+ for (i = 0; i < 10; i++)
+ {
+ PatchINumbers[i] = W_CacheLumpNum(startLump + i, PU_STATIC);
+ }
+ PatchNEGATIVE = W_CacheLumpName("NEGNUM", PU_STATIC);
+ FontBNumBase = W_GetNumForName("FONTB16");
+ startLump = W_GetNumForName("SMALLIN0");
+ for (i = 0; i < 10; i++)
+ {
+ PatchSmNumbers[i] = W_CacheLumpNum(startLump + i, PU_STATIC);
+ }
+ PlayPalette = W_GetNumForName("PLAYPAL");
+ SpinFlylump = W_GetNumForName("SPFLY0");
+ SpinMinotaurLump = W_GetNumForName("SPMINO0");
+ SpinSpeedLump = W_GetNumForName("SPBOOT0");
+ SpinDefenseLump = W_GetNumForName("SPSHLD0");
+
+ if (deathmatch)
+ {
+ PatchKILLS = W_CacheLumpName("KILLS", PU_STATIC);
+ }
+ SB_SetClassData();
+}
+
+//==========================================================================
+//
+// SB_SetClassData
+//
+//==========================================================================
+
+void SB_SetClassData(void)
+{
+ int class;
+
+ class = PlayerClass[consoleplayer]; // original player class (not pig)
+ PatchWEAPONSLOT = W_CacheLumpNum(W_GetNumForName("wpslot0")
+ + class, PU_STATIC);
+ PatchWEAPONFULL = W_CacheLumpNum(W_GetNumForName("wpfull0")
+ + class, PU_STATIC);
+ PatchPIECE1 = W_CacheLumpNum(W_GetNumForName("wpiecef1")
+ + class, PU_STATIC);
+ PatchPIECE2 = W_CacheLumpNum(W_GetNumForName("wpiecef2")
+ + class, PU_STATIC);
+ PatchPIECE3 = W_CacheLumpNum(W_GetNumForName("wpiecef3")
+ + class, PU_STATIC);
+ PatchCHAIN = W_CacheLumpNum(W_GetNumForName("chain") + class, PU_STATIC);
+ if (!netgame)
+ { // single player game uses red life gem (the second gem)
+ PatchLIFEGEM = W_CacheLumpNum(W_GetNumForName("lifegem")
+ + MAXPLAYERS * class + 1, PU_STATIC);
+ }
+ else
+ {
+ PatchLIFEGEM = W_CacheLumpNum(W_GetNumForName("lifegem")
+ + MAXPLAYERS * class + consoleplayer,
+ PU_STATIC);
+ }
+ SB_state = -1;
+ UpdateState |= I_FULLSCRN;
+}
+
+//==========================================================================
+//
+// SB_Ticker
+//
+//==========================================================================
+
+void SB_Ticker(void)
+{
+ int delta;
+ int curHealth;
+
+ curHealth = players[consoleplayer].mo->health;
+ if (curHealth < 0)
+ {
+ curHealth = 0;
+ }
+ if (curHealth < HealthMarker)
+ {
+ delta = (HealthMarker - curHealth) >> 2;
+ if (delta < 1)
+ {
+ delta = 1;
+ }
+ else if (delta > 6)
+ {
+ delta = 6;
+ }
+ HealthMarker -= delta;
+ }
+ else if (curHealth > HealthMarker)
+ {
+ delta = (curHealth - HealthMarker) >> 2;
+ if (delta < 1)
+ {
+ delta = 1;
+ }
+ else if (delta > 6)
+ {
+ delta = 6;
+ }
+ HealthMarker += delta;
+ }
+}
+
+//==========================================================================
+//
+// DrINumber
+//
+// Draws a three digit number.
+//
+//==========================================================================
+
+static void DrINumber(signed int val, int x, int y)
+{
+ patch_t *patch;
+ int oldval;
+
+ oldval = val;
+ if (val < 0)
+ {
+ val = -val;
+ if (val > 99)
+ {
+ val = 99;
+ }
+ if (val > 9)
+ {
+ patch = PatchINumbers[val / 10];
+ V_DrawPatch(x + 8, y, patch);
+ V_DrawPatch(x, y, PatchNEGATIVE);
+ }
+ else
+ {
+ V_DrawPatch(x + 8, y, PatchNEGATIVE);
+ }
+ val = val % 10;
+ patch = PatchINumbers[val];
+ V_DrawPatch(x + 16, y, patch);
+ return;
+ }
+ if (val > 99)
+ {
+ patch = PatchINumbers[val / 100];
+ V_DrawPatch(x, y, patch);
+ }
+ val = val % 100;
+ if (val > 9 || oldval > 99)
+ {
+ patch = PatchINumbers[val / 10];
+ V_DrawPatch(x + 8, y, patch);
+ }
+ val = val % 10;
+ patch = PatchINumbers[val];
+ V_DrawPatch(x + 16, y, patch);
+}
+
+//==========================================================================
+//
+// DrRedINumber
+//
+// Draws a three digit number using the red font
+//
+//==========================================================================
+
+static void DrRedINumber(signed int val, int x, int y)
+{
+ patch_t *patch;
+ int oldval;
+
+ oldval = val;
+ if (val < 0)
+ {
+ val = 0;
+ }
+ if (val > 99)
+ {
+ patch =
+ W_CacheLumpNum(W_GetNumForName("inred0") + val / 100, PU_CACHE);
+ V_DrawPatch(x, y, patch);
+ }
+ val = val % 100;
+ if (val > 9 || oldval > 99)
+ {
+ patch =
+ W_CacheLumpNum(W_GetNumForName("inred0") + val / 10, PU_CACHE);
+ V_DrawPatch(x + 8, y, patch);
+ }
+ val = val % 10;
+ patch = W_CacheLumpNum(W_GetNumForName("inred0") + val, PU_CACHE);
+ V_DrawPatch(x + 16, y, patch);
+}
+
+//==========================================================================
+//
+// DrBNumber
+//
+// Draws a three digit number using FontB
+//
+//==========================================================================
+
+static void DrBNumber(signed int val, int x, int y)
+{
+ patch_t *patch;
+ int xpos;
+ int oldval;
+
+ oldval = val;
+ xpos = x;
+ if (val < 0)
+ {
+ val = 0;
+ }
+ if (val > 99)
+ {
+ patch = W_CacheLumpNum(FontBNumBase + val / 100, PU_CACHE);
+ V_DrawShadowedPatch(xpos + 6 - patch->width / 2, y, patch);
+ }
+ val = val % 100;
+ xpos += 12;
+ if (val > 9 || oldval > 99)
+ {
+ patch = W_CacheLumpNum(FontBNumBase + val / 10, PU_CACHE);
+ V_DrawShadowedPatch(xpos + 6 - patch->width / 2, y, patch);
+ }
+ val = val % 10;
+ xpos += 12;
+ patch = W_CacheLumpNum(FontBNumBase + val, PU_CACHE);
+ V_DrawShadowedPatch(xpos + 6 - patch->width / 2, y, patch);
+}
+
+//==========================================================================
+//
+// DrSmallNumber
+//
+// Draws a small two digit number.
+//
+//==========================================================================
+
+static void DrSmallNumber(int val, int x, int y)
+{
+ patch_t *patch;
+
+ if (val <= 0)
+ {
+ return;
+ }
+ if (val > 999)
+ {
+ val %= 1000;
+ }
+ if (val > 99)
+ {
+ patch = PatchSmNumbers[val / 100];
+ V_DrawPatch(x, y, patch);
+ patch = PatchSmNumbers[(val % 100) / 10];
+ V_DrawPatch(x + 4, y, patch);
+ }
+ else if (val > 9)
+ {
+ patch = PatchSmNumbers[val / 10];
+ V_DrawPatch(x + 4, y, patch);
+ }
+ val %= 10;
+ patch = PatchSmNumbers[val];
+ V_DrawPatch(x + 8, y, patch);
+}
+
+/*
+//==========================================================================
+//
+// ShadeLine
+//
+//==========================================================================
+
+static void ShadeLine(int x, int y, int height, int shade)
+{
+ byte *dest;
+ byte *shades;
+
+ shades = colormaps+9*256+shade*2*256;
+ dest = I_VideoBuffer+y*SCREENWIDTH+x;
+ while(height--)
+ {
+ *(dest) = *(shades+*dest);
+ dest += SCREENWIDTH;
+ }
+}
+
+//==========================================================================
+//
+// ShadeChain
+//
+//==========================================================================
+
+static void ShadeChain(void)
+{
+ int i;
+
+ for(i = 0; i < 16; i++)
+ {
+ ShadeLine(277+i, 190, 10, i/2);
+ ShadeLine(19+i, 190, 10, 7-(i/2));
+ }
+}
+*/
+
+//==========================================================================
+//
+// DrawSoundInfo
+//
+// Displays sound debugging information.
+//
+//==========================================================================
+
+static void DrawSoundInfo(void)
+{
+ int i;
+ SoundInfo_t s;
+ ChanInfo_t *c;
+ char text[32];
+ int x;
+ int y;
+ int xPos[7] = { 1, 75, 112, 156, 200, 230, 260 };
+
+ if (leveltime & 16)
+ {
+ MN_DrTextA("*** SOUND DEBUG INFO ***", xPos[0], 20);
+ }
+ S_GetChannelInfo(&s);
+ if (s.channelCount == 0)
+ {
+ return;
+ }
+ x = 0;
+ MN_DrTextA("NAME", xPos[x++], 30);
+ MN_DrTextA("MO.T", xPos[x++], 30);
+ MN_DrTextA("MO.X", xPos[x++], 30);
+ MN_DrTextA("MO.Y", xPos[x++], 30);
+ MN_DrTextA("ID", xPos[x++], 30);
+ MN_DrTextA("PRI", xPos[x++], 30);
+ MN_DrTextA("DIST", xPos[x++], 30);
+ for (i = 0; i < s.channelCount; i++)
+ {
+ c = &s.chan[i];
+ x = 0;
+ y = 40 + i * 10;
+ if (c->mo == NULL)
+ { // Channel is unused
+ MN_DrTextA("------", xPos[0], y);
+ continue;
+ }
+ sprintf(text, "%s", c->name);
+ M_ForceUppercase(text);
+ MN_DrTextA(text, xPos[x++], y);
+ sprintf(text, "%d", c->mo->type);
+ MN_DrTextA(text, xPos[x++], y);
+ sprintf(text, "%d", c->mo->x >> FRACBITS);
+ MN_DrTextA(text, xPos[x++], y);
+ sprintf(text, "%d", c->mo->y >> FRACBITS);
+ MN_DrTextA(text, xPos[x++], y);
+ sprintf(text, "%d", (int) c->id);
+ MN_DrTextA(text, xPos[x++], y);
+ sprintf(text, "%d", c->priority);
+ MN_DrTextA(text, xPos[x++], y);
+ sprintf(text, "%d", c->distance);
+ MN_DrTextA(text, xPos[x++], y);
+ }
+ UpdateState |= I_FULLSCRN;
+ BorderNeedRefresh = true;
+}
+
+//==========================================================================
+//
+// SB_Drawer
+//
+//==========================================================================
+
+char patcharti[][10] = {
+ {"ARTIBOX"}, // none
+ {"ARTIINVU"}, // invulnerability
+ {"ARTIPTN2"}, // health
+ {"ARTISPHL"}, // superhealth
+ {"ARTIHRAD"}, // healing radius
+ {"ARTISUMN"}, // summon maulator
+ {"ARTITRCH"}, // torch
+ {"ARTIPORK"}, // egg
+ {"ARTISOAR"}, // fly
+ {"ARTIBLST"}, // blast radius
+ {"ARTIPSBG"}, // poison bag
+ {"ARTITELO"}, // teleport other
+ {"ARTISPED"}, // speed
+ {"ARTIBMAN"}, // boost mana
+ {"ARTIBRAC"}, // boost armor
+ {"ARTIATLP"}, // teleport
+ {"ARTISKLL"}, // arti_puzzskull
+ {"ARTIBGEM"}, // arti_puzzgembig
+ {"ARTIGEMR"}, // arti_puzzgemred
+ {"ARTIGEMG"}, // arti_puzzgemgreen1
+ {"ARTIGMG2"}, // arti_puzzgemgreen2
+ {"ARTIGEMB"}, // arti_puzzgemblue1
+ {"ARTIGMB2"}, // arti_puzzgemblue2
+ {"ARTIBOK1"}, // arti_puzzbook1
+ {"ARTIBOK2"}, // arti_puzzbook2
+ {"ARTISKL2"}, // arti_puzzskull2
+ {"ARTIFWEP"}, // arti_puzzfweapon
+ {"ARTICWEP"}, // arti_puzzcweapon
+ {"ARTIMWEP"}, // arti_puzzmweapon
+ {"ARTIGEAR"}, // arti_puzzgear1
+ {"ARTIGER2"}, // arti_puzzgear2
+ {"ARTIGER3"}, // arti_puzzgear3
+ {"ARTIGER4"}, // arti_puzzgear4
+};
+
+int SB_state = -1;
+static int oldarti = 0;
+static int oldartiCount = 0;
+static int oldfrags = -9999;
+static int oldmana1 = -1;
+static int oldmana2 = -1;
+static int oldarmor = -1;
+static int oldhealth = -1;
+static int oldlife = -1;
+static int oldpieces = -1;
+static int oldweapon = -1;
+static int oldkeys = -1;
+
+extern boolean automapactive;
+
+void SB_Drawer(void)
+{
+ // Sound info debug stuff
+ if (DebugSound == true)
+ {
+ DrawSoundInfo();
+ }
+ CPlayer = &players[consoleplayer];
+ if (viewheight == SCREENHEIGHT && !automapactive)
+ {
+ DrawFullScreenStuff();
+ SB_state = -1;
+ }
+ else
+ {
+ if (SB_state == -1)
+ {
+ V_DrawPatch(0, 134, PatchH2BAR);
+ oldhealth = -1;
+ }
+ DrawCommonBar();
+ if (!inventory)
+ {
+ if (SB_state != 0)
+ {
+ // Main interface
+ if (!automapactive)
+ {
+ V_DrawPatch(38, 162, PatchSTATBAR);
+ }
+ else
+ {
+ V_DrawPatch(38, 162, PatchKEYBAR);
+ }
+ oldarti = 0;
+ oldmana1 = -1;
+ oldmana2 = -1;
+ oldarmor = -1;
+ oldpieces = -1;
+ oldfrags = -9999; //can't use -1, 'cuz of negative frags
+ oldlife = -1;
+ oldweapon = -1;
+ oldkeys = -1;
+ }
+ if (!automapactive)
+ {
+ DrawMainBar();
+ }
+ else
+ {
+ DrawKeyBar();
+ }
+ SB_state = 0;
+ }
+ else
+ {
+ DrawInventoryBar();
+ SB_state = 1;
+ }
+ }
+ SB_PaletteFlash(false);
+ DrawAnimatedIcons();
+}
+
+//==========================================================================
+//
+// DrawAnimatedIcons
+//
+//==========================================================================
+
+static void DrawAnimatedIcons(void)
+{
+ int frame;
+ static boolean hitCenterFrame;
+
+ // Wings of wrath
+ if (CPlayer->powers[pw_flight])
+ {
+ if (CPlayer->powers[pw_flight] > BLINKTHRESHOLD
+ || !(CPlayer->powers[pw_flight] & 16))
+ {
+ frame = (leveltime / 3) & 15;
+ if (CPlayer->mo->flags2 & MF2_FLY)
+ {
+ if (hitCenterFrame && (frame != 15 && frame != 0))
+ {
+ V_DrawPatch(20, 19, W_CacheLumpNum(SpinFlylump + 15,
+ PU_CACHE));
+ }
+ else
+ {
+ V_DrawPatch(20, 19, W_CacheLumpNum(SpinFlylump + frame,
+ PU_CACHE));
+ hitCenterFrame = false;
+ }
+ }
+ else
+ {
+ if (!hitCenterFrame && (frame != 15 && frame != 0))
+ {
+ V_DrawPatch(20, 19, W_CacheLumpNum(SpinFlylump + frame,
+ PU_CACHE));
+ hitCenterFrame = false;
+ }
+ else
+ {
+ V_DrawPatch(20, 19, W_CacheLumpNum(SpinFlylump + 15,
+ PU_CACHE));
+ hitCenterFrame = true;
+ }
+ }
+ }
+ BorderTopRefresh = true;
+ UpdateState |= I_MESSAGES;
+ }
+
+ // Speed Boots
+ if (CPlayer->powers[pw_speed])
+ {
+ if (CPlayer->powers[pw_speed] > BLINKTHRESHOLD
+ || !(CPlayer->powers[pw_speed] & 16))
+ {
+ frame = (leveltime / 3) & 15;
+ V_DrawPatch(60, 19, W_CacheLumpNum(SpinSpeedLump + frame,
+ PU_CACHE));
+ }
+ BorderTopRefresh = true;
+ UpdateState |= I_MESSAGES;
+ }
+
+ // Defensive power
+ if (CPlayer->powers[pw_invulnerability])
+ {
+ if (CPlayer->powers[pw_invulnerability] > BLINKTHRESHOLD
+ || !(CPlayer->powers[pw_invulnerability] & 16))
+ {
+ frame = (leveltime / 3) & 15;
+ V_DrawPatch(260, 19, W_CacheLumpNum(SpinDefenseLump + frame,
+ PU_CACHE));
+ }
+ BorderTopRefresh = true;
+ UpdateState |= I_MESSAGES;
+ }
+
+ // Minotaur Active
+ if (CPlayer->powers[pw_minotaur])
+ {
+ if (CPlayer->powers[pw_minotaur] > BLINKTHRESHOLD
+ || !(CPlayer->powers[pw_minotaur] & 16))
+ {
+ frame = (leveltime / 3) & 15;
+ V_DrawPatch(300, 19, W_CacheLumpNum(SpinMinotaurLump + frame,
+ PU_CACHE));
+ }
+ BorderTopRefresh = true;
+ UpdateState |= I_MESSAGES;
+ }
+}
+
+//==========================================================================
+//
+// SB_PaletteFlash
+//
+// Sets the new palette based upon the current values of
+// consoleplayer->damagecount and consoleplayer->bonuscount.
+//
+//==========================================================================
+
+void SB_PaletteFlash(boolean forceChange)
+{
+ static int sb_palette = 0;
+ int palette;
+ byte *pal;
+
+ if (forceChange)
+ {
+ sb_palette = -1;
+ }
+ if (gamestate == GS_LEVEL)
+ {
+ CPlayer = &players[consoleplayer];
+ if (CPlayer->poisoncount)
+ {
+ palette = 0;
+ palette = (CPlayer->poisoncount + 7) >> 3;
+ if (palette >= NUMPOISONPALS)
+ {
+ palette = NUMPOISONPALS - 1;
+ }
+ palette += STARTPOISONPALS;
+ }
+ else if (CPlayer->damagecount)
+ {
+ palette = (CPlayer->damagecount + 7) >> 3;
+ if (palette >= NUMREDPALS)
+ {
+ palette = NUMREDPALS - 1;
+ }
+ palette += STARTREDPALS;
+ }
+ else if (CPlayer->bonuscount)
+ {
+ palette = (CPlayer->bonuscount + 7) >> 3;
+ if (palette >= NUMBONUSPALS)
+ {
+ palette = NUMBONUSPALS - 1;
+ }
+ palette += STARTBONUSPALS;
+ }
+ else if (CPlayer->mo->flags2 & MF2_ICEDAMAGE)
+ { // Frozen player
+ palette = STARTICEPAL;
+ }
+ else
+ {
+ palette = 0;
+ }
+ }
+ else
+ {
+ palette = 0;
+ }
+ if (palette != sb_palette)
+ {
+ sb_palette = palette;
+ pal = (byte *) W_CacheLumpNum(PlayPalette, PU_CACHE) + palette * 768;
+ I_SetPalette(pal);
+ }
+}
+
+//==========================================================================
+//
+// DrawCommonBar
+//
+//==========================================================================
+
+void DrawCommonBar(void)
+{
+ int healthPos;
+
+ V_DrawPatch(0, 134, PatchH2TOP);
+
+ if (oldhealth != HealthMarker)
+ {
+ oldhealth = HealthMarker;
+ healthPos = HealthMarker;
+ if (healthPos < 0)
+ {
+ healthPos = 0;
+ }
+ if (healthPos > 100)
+ {
+ healthPos = 100;
+ }
+ V_DrawPatch(28 + (((healthPos * 196) / 100) % 9), 193, PatchCHAIN);
+ V_DrawPatch(7 + ((healthPos * 11) / 5), 193, PatchLIFEGEM);
+ V_DrawPatch(0, 193, PatchLFEDGE);
+ V_DrawPatch(277, 193, PatchRTEDGE);
+// ShadeChain();
+ UpdateState |= I_STATBAR;
+ }
+}
+
+//==========================================================================
+//
+// DrawMainBar
+//
+//==========================================================================
+
+void DrawMainBar(void)
+{
+ int i;
+ int temp;
+ patch_t *manaPatch1, *manaPatch2;
+ patch_t *manaVialPatch1, *manaVialPatch2;
+
+ manaPatch1 = NULL;
+ manaPatch2 = NULL;
+ manaVialPatch1 = NULL;
+ manaVialPatch2 = NULL;
+
+ // Ready artifact
+ if (ArtifactFlash)
+ {
+ V_DrawPatch(144, 160, PatchARTICLEAR);
+ V_DrawPatch(148, 164, W_CacheLumpNum(W_GetNumForName("useartia")
+ + ArtifactFlash - 1, PU_CACHE));
+ ArtifactFlash--;
+ oldarti = -1; // so that the correct artifact fills in after the flash
+ UpdateState |= I_STATBAR;
+ }
+ else if (oldarti != CPlayer->readyArtifact
+ || oldartiCount != CPlayer->inventory[inv_ptr].count)
+ {
+ V_DrawPatch(144, 160, PatchARTICLEAR);
+ if (CPlayer->readyArtifact > 0)
+ {
+ V_DrawPatch(143, 163,
+ W_CacheLumpName(patcharti[CPlayer->readyArtifact],
+ PU_CACHE));
+ if (CPlayer->inventory[inv_ptr].count > 1)
+ {
+ DrSmallNumber(CPlayer->inventory[inv_ptr].count, 162, 184);
+ }
+ }
+ oldarti = CPlayer->readyArtifact;
+ oldartiCount = CPlayer->inventory[inv_ptr].count;
+ UpdateState |= I_STATBAR;
+ }
+
+ // Frags
+ if (deathmatch)
+ {
+ temp = 0;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ temp += CPlayer->frags[i];
+ }
+ if (temp != oldfrags)
+ {
+ V_DrawPatch(38, 162, PatchKILLS);
+ DrINumber(temp, 40, 176);
+ oldfrags = temp;
+ UpdateState |= I_STATBAR;
+ }
+ }
+ else
+ {
+ temp = HealthMarker;
+ if (temp < 0)
+ {
+ temp = 0;
+ }
+ else if (temp > 100)
+ {
+ temp = 100;
+ }
+ if (oldlife != temp)
+ {
+ oldlife = temp;
+ V_DrawPatch(41, 178, PatchARMCLEAR);
+ if (temp >= 25)
+ {
+ DrINumber(temp, 40, 176);
+ }
+ else
+ {
+ DrRedINumber(temp, 40, 176);
+ }
+ UpdateState |= I_STATBAR;
+ }
+ }
+ // Mana
+ temp = CPlayer->mana[0];
+ if (oldmana1 != temp)
+ {
+ V_DrawPatch(77, 178, PatchMANACLEAR);
+ DrSmallNumber(temp, 79, 181);
+ manaVialPatch1 = (patch_t *) 1; // force a vial update
+ if (temp == 0)
+ { // Draw Dim Mana icon
+ manaPatch1 = PatchMANADIM1;
+ }
+ else if (oldmana1 == 0)
+ {
+ manaPatch1 = PatchMANABRIGHT1;
+ }
+ oldmana1 = temp;
+ UpdateState |= I_STATBAR;
+ }
+ temp = CPlayer->mana[1];
+ if (oldmana2 != temp)
+ {
+ V_DrawPatch(109, 178, PatchMANACLEAR);
+ DrSmallNumber(temp, 111, 181);
+ manaVialPatch1 = (patch_t *) 1; // force a vial update
+ if (temp == 0)
+ { // Draw Dim Mana icon
+ manaPatch2 = PatchMANADIM2;
+ }
+ else if (oldmana2 == 0)
+ {
+ manaPatch2 = PatchMANABRIGHT2;
+ }
+ oldmana2 = temp;
+ UpdateState |= I_STATBAR;
+ }
+ if (oldweapon != CPlayer->readyweapon || manaPatch1 || manaPatch2
+ || manaVialPatch1)
+ { // Update mana graphics based upon mana count/weapon type
+ if (CPlayer->readyweapon == WP_FIRST)
+ {
+ manaPatch1 = PatchMANADIM1;
+ manaPatch2 = PatchMANADIM2;
+ manaVialPatch1 = PatchMANAVIALDIM1;
+ manaVialPatch2 = PatchMANAVIALDIM2;
+ }
+ else if (CPlayer->readyweapon == WP_SECOND)
+ {
+ if (!manaPatch1)
+ {
+ manaPatch1 = PatchMANABRIGHT1;
+ }
+ manaVialPatch1 = PatchMANAVIAL1;
+ manaPatch2 = PatchMANADIM2;
+ manaVialPatch2 = PatchMANAVIALDIM2;
+ }
+ else if (CPlayer->readyweapon == WP_THIRD)
+ {
+ manaPatch1 = PatchMANADIM1;
+ manaVialPatch1 = PatchMANAVIALDIM1;
+ if (!manaPatch2)
+ {
+ manaPatch2 = PatchMANABRIGHT2;
+ }
+ manaVialPatch2 = PatchMANAVIAL2;
+ }
+ else
+ {
+ manaVialPatch1 = PatchMANAVIAL1;
+ manaVialPatch2 = PatchMANAVIAL2;
+ if (!manaPatch1)
+ {
+ manaPatch1 = PatchMANABRIGHT1;
+ }
+ if (!manaPatch2)
+ {
+ manaPatch2 = PatchMANABRIGHT2;
+ }
+ }
+ V_DrawPatch(77, 164, manaPatch1);
+ V_DrawPatch(110, 164, manaPatch2);
+ V_DrawPatch(94, 164, manaVialPatch1);
+ for (i = 165; i < 187 - (22 * CPlayer->mana[0]) / MAX_MANA; i++)
+ {
+ I_VideoBuffer[i * SCREENWIDTH + 95] = 0;
+ I_VideoBuffer[i * SCREENWIDTH + 96] = 0;
+ I_VideoBuffer[i * SCREENWIDTH + 97] = 0;
+ }
+ V_DrawPatch(102, 164, manaVialPatch2);
+ for (i = 165; i < 187 - (22 * CPlayer->mana[1]) / MAX_MANA; i++)
+ {
+ I_VideoBuffer[i * SCREENWIDTH + 103] = 0;
+ I_VideoBuffer[i * SCREENWIDTH + 104] = 0;
+ I_VideoBuffer[i * SCREENWIDTH + 105] = 0;
+ }
+ oldweapon = CPlayer->readyweapon;
+ UpdateState |= I_STATBAR;
+ }
+ // Armor
+ temp = AutoArmorSave[CPlayer->class]
+ + CPlayer->armorpoints[ARMOR_ARMOR] +
+ CPlayer->armorpoints[ARMOR_SHIELD] +
+ CPlayer->armorpoints[ARMOR_HELMET] +
+ CPlayer->armorpoints[ARMOR_AMULET];
+ if (oldarmor != temp)
+ {
+ oldarmor = temp;
+ V_DrawPatch(255, 178, PatchARMCLEAR);
+ DrINumber(FixedDiv(temp, 5 * FRACUNIT) >> FRACBITS, 250, 176);
+ UpdateState |= I_STATBAR;
+ }
+ // Weapon Pieces
+ if (oldpieces != CPlayer->pieces)
+ {
+ DrawWeaponPieces();
+ oldpieces = CPlayer->pieces;
+ UpdateState |= I_STATBAR;
+ }
+}
+
+//==========================================================================
+//
+// DrawInventoryBar
+//
+//==========================================================================
+
+void DrawInventoryBar(void)
+{
+ int i;
+ int x;
+
+ x = inv_ptr - curpos;
+ UpdateState |= I_STATBAR;
+ V_DrawPatch(38, 162, PatchINVBAR);
+ for (i = 0; i < 7; i++)
+ {
+ //V_DrawPatch(50+i*31, 160, W_CacheLumpName("ARTIBOX", PU_CACHE));
+ if (CPlayer->inventorySlotNum > x + i
+ && CPlayer->inventory[x + i].type != arti_none)
+ {
+ V_DrawPatch(50 + i * 31, 163,
+ W_CacheLumpName(patcharti
+ [CPlayer->inventory[x + i].type],
+ PU_CACHE));
+ if (CPlayer->inventory[x + i].count > 1)
+ {
+ DrSmallNumber(CPlayer->inventory[x + i].count, 68 + i * 31,
+ 185);
+ }
+ }
+ }
+ V_DrawPatch(50 + curpos * 31, 163, PatchSELECTBOX);
+ if (x != 0)
+ {
+ V_DrawPatch(42, 163, !(leveltime & 4) ? PatchINVLFGEM1 :
+ PatchINVLFGEM2);
+ }
+ if (CPlayer->inventorySlotNum - x > 7)
+ {
+ V_DrawPatch(269, 163, !(leveltime & 4) ? PatchINVRTGEM1 :
+ PatchINVRTGEM2);
+ }
+}
+
+//==========================================================================
+//
+// DrawKeyBar
+//
+//==========================================================================
+
+void DrawKeyBar(void)
+{
+ int i;
+ int xPosition;
+ int temp;
+
+ if (oldkeys != CPlayer->keys)
+ {
+ xPosition = 46;
+ for (i = 0; i < NUMKEYS && xPosition <= 126; i++)
+ {
+ if (CPlayer->keys & (1 << i))
+ {
+ V_DrawPatch(xPosition, 164,
+ W_CacheLumpNum(W_GetNumForName("keyslot1") + i,
+ PU_CACHE));
+ xPosition += 20;
+ }
+ }
+ oldkeys = CPlayer->keys;
+ UpdateState |= I_STATBAR;
+ }
+ temp = AutoArmorSave[CPlayer->class]
+ + CPlayer->armorpoints[ARMOR_ARMOR] +
+ CPlayer->armorpoints[ARMOR_SHIELD] +
+ CPlayer->armorpoints[ARMOR_HELMET] +
+ CPlayer->armorpoints[ARMOR_AMULET];
+ if (oldarmor != temp)
+ {
+ for (i = 0; i < NUMARMOR; i++)
+ {
+ if (!CPlayer->armorpoints[i])
+ {
+ continue;
+ }
+ if (CPlayer->armorpoints[i] <=
+ (ArmorIncrement[CPlayer->class][i] >> 2))
+ {
+ V_DrawTLPatch(150 + 31 * i, 164,
+ W_CacheLumpNum(W_GetNumForName("armslot1") +
+ i, PU_CACHE));
+ }
+ else if (CPlayer->armorpoints[i] <=
+ (ArmorIncrement[CPlayer->class][i] >> 1))
+ {
+ V_DrawAltTLPatch(150 + 31 * i, 164,
+ W_CacheLumpNum(W_GetNumForName("armslot1")
+ + i, PU_CACHE));
+ }
+ else
+ {
+ V_DrawPatch(150 + 31 * i, 164,
+ W_CacheLumpNum(W_GetNumForName("armslot1") + i,
+ PU_CACHE));
+ }
+ }
+ oldarmor = temp;
+ UpdateState |= I_STATBAR;
+ }
+}
+
+//==========================================================================
+//
+// DrawWeaponPieces
+//
+//==========================================================================
+
+static int PieceX[NUMCLASSES][3] = {
+ {190, 225, 234},
+ {190, 212, 225},
+ {190, 205, 224},
+ {0, 0, 0} // Pig is never used
+};
+
+static void DrawWeaponPieces(void)
+{
+ if (CPlayer->pieces == 7)
+ {
+ V_DrawPatch(190, 162, PatchWEAPONFULL);
+ return;
+ }
+ V_DrawPatch(190, 162, PatchWEAPONSLOT);
+ if (CPlayer->pieces & WPIECE1)
+ {
+ V_DrawPatch(PieceX[PlayerClass[consoleplayer]][0], 162, PatchPIECE1);
+ }
+ if (CPlayer->pieces & WPIECE2)
+ {
+ V_DrawPatch(PieceX[PlayerClass[consoleplayer]][1], 162, PatchPIECE2);
+ }
+ if (CPlayer->pieces & WPIECE3)
+ {
+ V_DrawPatch(PieceX[PlayerClass[consoleplayer]][2], 162, PatchPIECE3);
+ }
+}
+
+//==========================================================================
+//
+// DrawFullScreenStuff
+//
+//==========================================================================
+
+void DrawFullScreenStuff(void)
+{
+ int i;
+ int x;
+ int temp;
+
+ UpdateState |= I_FULLSCRN;
+ if (CPlayer->mo->health > 0)
+ {
+ DrBNumber(CPlayer->mo->health, 5, 180);
+ }
+ else
+ {
+ DrBNumber(0, 5, 180);
+ }
+ if (deathmatch)
+ {
+ temp = 0;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ {
+ temp += CPlayer->frags[i];
+ }
+ }
+ DrINumber(temp, 45, 185);
+ }
+ if (!inventory)
+ {
+ if (CPlayer->readyArtifact > 0)
+ {
+ V_DrawTLPatch(286, 170, W_CacheLumpName("ARTIBOX", PU_CACHE));
+ V_DrawPatch(284, 169,
+ W_CacheLumpName(patcharti[CPlayer->readyArtifact],
+ PU_CACHE));
+ if (CPlayer->inventory[inv_ptr].count > 1)
+ {
+ DrSmallNumber(CPlayer->inventory[inv_ptr].count, 302, 192);
+ }
+ }
+ }
+ else
+ {
+ x = inv_ptr - curpos;
+ for (i = 0; i < 7; i++)
+ {
+ V_DrawTLPatch(50 + i * 31, 168, W_CacheLumpName("ARTIBOX",
+ PU_CACHE));
+ if (CPlayer->inventorySlotNum > x + i
+ && CPlayer->inventory[x + i].type != arti_none)
+ {
+ V_DrawPatch(49 + i * 31, 167,
+ W_CacheLumpName(patcharti
+ [CPlayer->inventory[x + i].type],
+ PU_CACHE));
+ if (CPlayer->inventory[x + i].count > 1)
+ {
+ DrSmallNumber(CPlayer->inventory[x + i].count,
+ 66 + i * 31, 188);
+ }
+ }
+ }
+ V_DrawPatch(50 + curpos * 31, 167, PatchSELECTBOX);
+ if (x != 0)
+ {
+ V_DrawPatch(40, 167, !(leveltime & 4) ? PatchINVLFGEM1 :
+ PatchINVLFGEM2);
+ }
+ if (CPlayer->inventorySlotNum - x > 7)
+ {
+ V_DrawPatch(268, 167, !(leveltime & 4) ?
+ PatchINVRTGEM1 : PatchINVRTGEM2);
+ }
+ }
+}
+
+
+//==========================================================================
+//
+// Draw_TeleportIcon
+//
+//==========================================================================
+void Draw_TeleportIcon(void)
+{
+ patch_t *patch;
+ patch = W_CacheLumpNum(W_GetNumForName("teleicon"), PU_CACHE);
+ V_DrawPatch(100, 68, patch);
+ UpdateState |= I_FULLSCRN;
+ I_FinishUpdate();
+ UpdateState |= I_FULLSCRN;
+}
+
+//==========================================================================
+//
+// Draw_SaveIcon
+//
+//==========================================================================
+void Draw_SaveIcon(void)
+{
+ patch_t *patch;
+ patch = W_CacheLumpNum(W_GetNumForName("saveicon"), PU_CACHE);
+ V_DrawPatch(100, 68, patch);
+ UpdateState |= I_FULLSCRN;
+ I_FinishUpdate();
+ UpdateState |= I_FULLSCRN;
+}
+
+//==========================================================================
+//
+// Draw_LoadIcon
+//
+//==========================================================================
+void Draw_LoadIcon(void)
+{
+ patch_t *patch;
+ patch = W_CacheLumpNum(W_GetNumForName("loadicon"), PU_CACHE);
+ V_DrawPatch(100, 68, patch);
+ UpdateState |= I_FULLSCRN;
+ I_FinishUpdate();
+ UpdateState |= I_FULLSCRN;
+}
+
+
+
+//==========================================================================
+//
+// SB_Responder
+//
+//==========================================================================
+
+boolean SB_Responder(event_t * event)
+{
+ if (event->type == ev_keydown)
+ {
+ if (HandleCheats(event->data1))
+ { // Need to eat the key
+ return (true);
+ }
+ }
+ return (false);
+}
+
+//==========================================================================
+//
+// HandleCheats
+//
+// Returns true if the caller should eat the key.
+//
+//==========================================================================
+
+static boolean HandleCheats(byte key)
+{
+ int i;
+ boolean eat;
+
+ if (gameskill == sk_nightmare)
+ { // Can't cheat in nightmare mode
+ return (false);
+ }
+ else if (netgame)
+ { // change CD track is the only cheat available in deathmatch
+ eat = false;
+ if (i_CDMusic)
+ {
+ if (CheatAddKey(&Cheats[0], key, &eat))
+ {
+ Cheats[0].func(&players[consoleplayer], &Cheats[0]);
+ S_StartSound(NULL, SFX_PLATFORM_STOP);
+ }
+ if (CheatAddKey(&Cheats[1], key, &eat))
+ {
+ Cheats[1].func(&players[consoleplayer], &Cheats[1]);
+ S_StartSound(NULL, SFX_PLATFORM_STOP);
+ }
+ }
+ return eat;
+ }
+ if (players[consoleplayer].health <= 0)
+ { // Dead players can't cheat
+ return (false);
+ }
+ eat = false;
+ for (i = 0; i<arrlen(Cheats); ++i)
+ {
+ if (CheatAddKey(&Cheats[i], key, &eat))
+ {
+ Cheats[i].func(&players[consoleplayer], &Cheats[i]);
+ S_StartSound(NULL, SFX_PLATFORM_STOP);
+ }
+ }
+ return (eat);
+}
+
+//==========================================================================
+//
+// CheatAddkey
+//
+// Returns true if the added key completed the cheat, false otherwise.
+//
+//==========================================================================
+
+static boolean CheatAddKey(Cheat_t * cheat, byte key, boolean * eat)
+{
+/*
+ if (!cheat->pos)
+ {
+ cheat->pos = cheat->sequence;
+ cheat->currentArg = 0;
+ }
+ if (*cheat->pos == 0)
+ {
+ *eat = true;
+ cheat->args[cheat->currentArg++] = key;
+ cheat->pos++;
+ }
+ else if (CheatLookup[key] == *cheat->pos)
+ {
+ cheat->pos++;
+ }
+ else
+ {
+ cheat->pos = cheat->sequence;
+ cheat->currentArg = 0;
+ }
+ if (*cheat->pos == 0xff)
+ {
+ cheat->pos = cheat->sequence;
+ cheat->currentArg = 0;
+ return (true);
+ }
+ return (false);
+ */
+
+ *eat = cht_CheckCheat(cheat->seq, key);
+
+ return *eat;
+}
+
+//==========================================================================
+//
+// CHEAT FUNCTIONS
+//
+//==========================================================================
+
+static void CheatGodFunc(player_t * player, Cheat_t * cheat)
+{
+ player->cheats ^= CF_GODMODE;
+ if (player->cheats & CF_GODMODE)
+ {
+ P_SetMessage(player, TXT_CHEATGODON, true);
+ }
+ else
+ {
+ P_SetMessage(player, TXT_CHEATGODOFF, true);
+ }
+ SB_state = -1;
+}
+
+static void CheatNoClipFunc(player_t * player, Cheat_t * cheat)
+{
+ player->cheats ^= CF_NOCLIP;
+ if (player->cheats & CF_NOCLIP)
+ {
+ P_SetMessage(player, TXT_CHEATNOCLIPON, true);
+ }
+ else
+ {
+ P_SetMessage(player, TXT_CHEATNOCLIPOFF, true);
+ }
+}
+
+static void CheatWeaponsFunc(player_t * player, Cheat_t * cheat)
+{
+ int i;
+ //extern boolean *WeaponInShareware;
+
+ for (i = 0; i < NUMARMOR; i++)
+ {
+ player->armorpoints[i] = ArmorIncrement[player->class][i];
+ }
+ for (i = 0; i < NUMWEAPONS; i++)
+ {
+ player->weaponowned[i] = true;
+ }
+ for (i = 0; i < NUMMANA; i++)
+ {
+ player->mana[i] = MAX_MANA;
+ }
+ P_SetMessage(player, TXT_CHEATWEAPONS, true);
+}
+
+static void CheatHealthFunc(player_t * player, Cheat_t * cheat)
+{
+ if (player->morphTics)
+ {
+ player->health = player->mo->health = MAXMORPHHEALTH;
+ }
+ else
+ {
+ player->health = player->mo->health = MAXHEALTH;
+ }
+ P_SetMessage(player, TXT_CHEATHEALTH, true);
+}
+
+static void CheatKeysFunc(player_t * player, Cheat_t * cheat)
+{
+ player->keys = 2047;
+ P_SetMessage(player, TXT_CHEATKEYS, true);
+}
+
+static void CheatSoundFunc(player_t * player, Cheat_t * cheat)
+{
+ DebugSound = !DebugSound;
+ if (DebugSound)
+ {
+ P_SetMessage(player, TXT_CHEATSOUNDON, true);
+ }
+ else
+ {
+ P_SetMessage(player, TXT_CHEATSOUNDOFF, true);
+ }
+}
+
+static void CheatTickerFunc(player_t * player, Cheat_t * cheat)
+{
+ DisplayTicker = !DisplayTicker;
+ if (DisplayTicker)
+ {
+ P_SetMessage(player, TXT_CHEATTICKERON, true);
+ }
+ else
+ {
+ P_SetMessage(player, TXT_CHEATTICKEROFF, true);
+ }
+
+ I_DisplayFPSDots(DisplayTicker);
+}
+
+static void CheatArtifactAllFunc(player_t * player, Cheat_t * cheat)
+{
+ int i;
+ int j;
+
+ for (i = arti_none + 1; i < arti_firstpuzzitem; i++)
+ {
+ for (j = 0; j < 25; j++)
+ {
+ P_GiveArtifact(player, i, NULL);
+ }
+ }
+ P_SetMessage(player, TXT_CHEATARTIFACTS3, true);
+}
+
+static void CheatPuzzleFunc(player_t * player, Cheat_t * cheat)
+{
+ int i;
+
+ for (i = arti_firstpuzzitem; i < NUMARTIFACTS; i++)
+ {
+ P_GiveArtifact(player, i, NULL);
+ }
+ P_SetMessage(player, TXT_CHEATARTIFACTS3, true);
+}
+
+static void CheatInitFunc(player_t * player, Cheat_t * cheat)
+{
+ G_DeferedInitNew(gameskill, gameepisode, gamemap);
+ P_SetMessage(player, TXT_CHEATWARP, true);
+}
+
+static void CheatWarpFunc(player_t * player, Cheat_t * cheat)
+{
+ int tens;
+ int ones;
+ int map;
+ char mapName[9];
+ char args[2];
+
+ cht_GetParam(cheat->seq, args);
+
+ tens = args[0] - '0';
+ ones = args[1] - '0';
+ if (tens < 0 || tens > 9 || ones < 0 || ones > 9)
+ { // Bad map
+ P_SetMessage(player, TXT_CHEATBADINPUT, true);
+ return;
+ }
+ map = P_TranslateMap((args[0] - '0') * 10 + args[1] - '0');
+ if (map == -1)
+ { // Not found
+ P_SetMessage(player, TXT_CHEATNOMAP, true);
+ return;
+ }
+ if (map == gamemap)
+ { // Don't try to teleport to current map
+ P_SetMessage(player, TXT_CHEATBADINPUT, true);
+ return;
+ }
+ sprintf(mapName, "MAP%02d", map);
+ if (W_CheckNumForName(mapName) == -1)
+ { // Can't find
+ P_SetMessage(player, TXT_CHEATNOMAP, true);
+ return;
+ }
+ P_SetMessage(player, TXT_CHEATWARP, true);
+ G_TeleportNewMap(map, 0);
+}
+
+static void CheatPigFunc(player_t * player, Cheat_t * cheat)
+{
+ extern boolean P_UndoPlayerMorph(player_t * player);
+
+ if (player->morphTics)
+ {
+ P_UndoPlayerMorph(player);
+ }
+ else
+ {
+ P_MorphPlayer(player);
+ }
+ P_SetMessage(player, "SQUEAL!!", true);
+}
+
+static void CheatMassacreFunc(player_t * player, Cheat_t * cheat)
+{
+ int count;
+ char buffer[80];
+
+ count = P_Massacre();
+ sprintf(buffer, "%d MONSTERS KILLED\n", count);
+ P_SetMessage(player, buffer, true);
+}
+
+static void CheatIDKFAFunc(player_t * player, Cheat_t * cheat)
+{
+ int i;
+ if (player->morphTics)
+ {
+ return;
+ }
+ for (i = 1; i < NUMWEAPONS; i++)
+ {
+ player->weaponowned[i] = false;
+ }
+
+ // In the original code, NUMWEAPONS was 8. So the writes to weaponowned
+ // overflowed the array. We must set the following fields to zero as
+ // well:
+
+ player->mana[0] = 0;
+ player->mana[1] = 0;
+ player->attackdown = 0;
+ player->usedown = 0;
+
+ player->pendingweapon = WP_FIRST;
+ P_SetMessage(player, TXT_CHEATIDKFA, true);
+}
+
+static void CheatQuickenFunc1(player_t * player, Cheat_t * cheat)
+{
+ P_SetMessage(player, "TRYING TO CHEAT? THAT'S ONE....", true);
+}
+
+static void CheatQuickenFunc2(player_t * player, Cheat_t * cheat)
+{
+ P_SetMessage(player, "THAT'S TWO....", true);
+}
+
+static void CheatQuickenFunc3(player_t * player, Cheat_t * cheat)
+{
+ P_DamageMobj(player->mo, NULL, player->mo, 10000);
+ P_SetMessage(player, "THAT'S THREE! TIME TO DIE.", true);
+}
+
+static void CheatClassFunc1(player_t * player, Cheat_t * cheat)
+{
+ P_SetMessage(player, "ENTER NEW PLAYER CLASS (0 - 2)", true);
+}
+
+static void CheatClassFunc2(player_t * player, Cheat_t * cheat)
+{
+ int i;
+ int class;
+ char args[2];
+
+ cht_GetParam(cheat->seq, args);
+
+ if (player->morphTics)
+ { // don't change class if the player is morphed
+ return;
+ }
+ class = args[0] - '0';
+ if (class > 2 || class < 0)
+ {
+ P_SetMessage(player, "INVALID PLAYER CLASS", true);
+ return;
+ }
+ player->class = class;
+ for (i = 0; i < NUMARMOR; i++)
+ {
+ player->armorpoints[i] = 0;
+ }
+ PlayerClass[consoleplayer] = class;
+ P_PostMorphWeapon(player, WP_FIRST);
+ SB_SetClassData();
+ SB_state = -1;
+ UpdateState |= I_FULLSCRN;
+}
+
+static void CheatVersionFunc(player_t * player, Cheat_t * cheat)
+{
+ P_SetMessage(player, HEXEN_VERSIONTEXT, true);
+}
+
+static void CheatDebugFunc(player_t * player, Cheat_t * cheat)
+{
+ char textBuffer[50];
+ sprintf(textBuffer, "MAP %d (%d) X:%5d Y:%5d Z:%5d",
+ P_GetMapWarpTrans(gamemap),
+ gamemap,
+ player->mo->x >> FRACBITS,
+ player->mo->y >> FRACBITS, player->mo->z >> FRACBITS);
+ P_SetMessage(player, textBuffer, true);
+}
+
+static void CheatScriptFunc1(player_t * player, Cheat_t * cheat)
+{
+ P_SetMessage(player, "RUN WHICH SCRIPT(01-99)?", true);
+}
+
+static void CheatScriptFunc2(player_t * player, Cheat_t * cheat)
+{
+ P_SetMessage(player, "RUN WHICH SCRIPT(01-99)?", true);
+}
+
+static void CheatScriptFunc3(player_t * player, Cheat_t * cheat)
+{
+ int script;
+ byte script_args[3];
+ int tens, ones;
+ char textBuffer[40];
+ char args[2];
+
+ cht_GetParam(cheat->seq, args);
+
+ tens = args[0] - '0';
+ ones = args[1] - '0';
+ script = tens * 10 + ones;
+ if (script < 1)
+ return;
+ if (script > 99)
+ return;
+ script_args[0] = script_args[1] = script_args[2] = 0;
+
+ if (P_StartACS(script, 0, script_args, player->mo, NULL, 0))
+ {
+ sprintf(textBuffer, "RUNNING SCRIPT %.2d", script);
+ P_SetMessage(player, textBuffer, true);
+ }
+}
+
+extern int cheating;
+
+static void CheatRevealFunc(player_t * player, Cheat_t * cheat)
+{
+ cheating = (cheating + 1) % 3;
+}
+
+//===========================================================================
+//
+// CheatTrackFunc1
+//
+//===========================================================================
+
+static void CheatTrackFunc1(player_t * player, Cheat_t * cheat)
+{
+ // haleyjd FIXME: CDMUSIC
+#ifdef __WATCOMC__
+ char buffer[80];
+
+ if (!i_CDMusic)
+ {
+ return;
+ }
+ if (I_CDMusInit() == -1)
+ {
+ P_SetMessage(player, "ERROR INITIALIZING CD", true);
+ }
+ sprintf(buffer, "ENTER DESIRED CD TRACK (%.2d - %.2d):\n",
+ I_CDMusFirstTrack(), I_CDMusLastTrack());
+ P_SetMessage(player, buffer, true);
+#endif
+}
+
+//===========================================================================
+//
+// CheatTrackFunc2
+//
+//===========================================================================
+
+static void CheatTrackFunc2(player_t * player, Cheat_t * cheat)
+{
+ // haleyjd FIXME: CDMUSIC
+#ifdef __WATCOMC__
+ char buffer[80];
+ int track;
+ char args[2];
+
+ cht_GetParam(cheat->seq, args);
+
+ if (!i_CDMusic)
+ {
+ return;
+ }
+ track = (args[0] - '0') * 10 + (args[1] - '0');
+ if (track < I_CDMusFirstTrack() || track > I_CDMusLastTrack())
+ {
+ P_SetMessage(player, "INVALID TRACK NUMBER\n", true);
+ return;
+ }
+ if (track == i_CDCurrentTrack)
+ {
+ return;
+ }
+ if (I_CDMusPlay(track))
+ {
+ sprintf(buffer, "ERROR WHILE TRYING TO PLAY CD TRACK: %.2d\n", track);
+ P_SetMessage(player, buffer, true);
+ }
+ else
+ { // No error encountered while attempting to play the track
+ sprintf(buffer, "PLAYING TRACK: %.2d\n", track);
+ P_SetMessage(player, buffer, true);
+ i_CDMusicLength = 35 * I_CDMusTrackLength(track);
+ oldTic = gametic;
+ i_CDTrack = track;
+ i_CDCurrentTrack = track;
+ }
+#endif
+}
diff --git a/src/hexen/sc_man.c b/src/hexen/sc_man.c
new file mode 100644
index 00000000..833d7e1e
--- /dev/null
+++ b/src/hexen/sc_man.c
@@ -0,0 +1,478 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+// HEADER FILES ------------------------------------------------------------
+
+#include <string.h>
+#include <stdlib.h>
+#include "h2def.h"
+#include "i_system.h"
+#include "m_misc.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define MAX_STRING_SIZE 64
+#define ASCII_COMMENT (';')
+#define ASCII_QUOTE (34)
+#define LUMP_SCRIPT 1
+#define FILE_ZONE_SCRIPT 2
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void CheckOpen(void);
+static void OpenScript(char *name, int type);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+char *sc_String;
+int sc_Number;
+int sc_Line;
+boolean sc_End;
+boolean sc_Crossed;
+boolean sc_FileScripts = false;
+char *sc_ScriptsDir = "";
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static char ScriptName[16];
+static char *ScriptBuffer;
+static char *ScriptPtr;
+static char *ScriptEndPtr;
+static char StringBuffer[MAX_STRING_SIZE];
+static int ScriptLumpNum;
+static boolean ScriptOpen = false;
+static int ScriptSize;
+static boolean AlreadyGot = false;
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// SC_Open
+//
+//==========================================================================
+
+void SC_Open(char *name)
+{
+ char fileName[128];
+
+ if (sc_FileScripts == true)
+ {
+ sprintf(fileName, "%s%s.txt", sc_ScriptsDir, name);
+ SC_OpenFile(fileName);
+ }
+ else
+ {
+ SC_OpenLump(name);
+ }
+}
+
+//==========================================================================
+//
+// SC_OpenLump
+//
+// Loads a script (from the WAD files) and prepares it for parsing.
+//
+//==========================================================================
+
+void SC_OpenLump(char *name)
+{
+ OpenScript(name, LUMP_SCRIPT);
+}
+
+//==========================================================================
+//
+// SC_OpenFile
+//
+// Loads a script (from a file) and prepares it for parsing. Uses the
+// zone memory allocator for memory allocation and de-allocation.
+//
+//==========================================================================
+
+void SC_OpenFile(char *name)
+{
+ OpenScript(name, FILE_ZONE_SCRIPT);
+}
+
+//==========================================================================
+//
+// OpenScript
+//
+//==========================================================================
+
+static void OpenScript(char *name, int type)
+{
+ SC_Close();
+ if (type == LUMP_SCRIPT)
+ { // Lump script
+ ScriptLumpNum = W_GetNumForName(name);
+ ScriptBuffer = (char *) W_CacheLumpNum(ScriptLumpNum, PU_STATIC);
+ ScriptSize = W_LumpLength(ScriptLumpNum);
+ strcpy(ScriptName, name);
+ }
+ else if (type == FILE_ZONE_SCRIPT)
+ { // File script - zone
+ ScriptLumpNum = -1;
+ ScriptSize = M_ReadFile(name, (byte **) & ScriptBuffer);
+ M_ExtractFileBase(name, ScriptName);
+ }
+ ScriptPtr = ScriptBuffer;
+ ScriptEndPtr = ScriptPtr + ScriptSize;
+ sc_Line = 1;
+ sc_End = false;
+ ScriptOpen = true;
+ sc_String = StringBuffer;
+ AlreadyGot = false;
+}
+
+//==========================================================================
+//
+// SC_Close
+//
+//==========================================================================
+
+void SC_Close(void)
+{
+ if (ScriptOpen)
+ {
+ if (ScriptLumpNum >= 0)
+ {
+ W_ReleaseLumpNum(ScriptLumpNum);
+ }
+ else
+ {
+ Z_Free(ScriptBuffer);
+ }
+ ScriptOpen = false;
+ }
+}
+
+//==========================================================================
+//
+// SC_GetString
+//
+//==========================================================================
+
+boolean SC_GetString(void)
+{
+ char *text;
+ boolean foundToken;
+
+ CheckOpen();
+ if (AlreadyGot)
+ {
+ AlreadyGot = false;
+ return true;
+ }
+ foundToken = false;
+ sc_Crossed = false;
+ if (ScriptPtr >= ScriptEndPtr)
+ {
+ sc_End = true;
+ return false;
+ }
+ while (foundToken == false)
+ {
+ while (*ScriptPtr <= 32)
+ {
+ if (ScriptPtr >= ScriptEndPtr)
+ {
+ sc_End = true;
+ return false;
+ }
+ if (*ScriptPtr++ == '\n')
+ {
+ sc_Line++;
+ sc_Crossed = true;
+ }
+ }
+ if (ScriptPtr >= ScriptEndPtr)
+ {
+ sc_End = true;
+ return false;
+ }
+ if (*ScriptPtr != ASCII_COMMENT)
+ { // Found a token
+ foundToken = true;
+ }
+ else
+ { // Skip comment
+ while (*ScriptPtr++ != '\n')
+ {
+ if (ScriptPtr >= ScriptEndPtr)
+ {
+ sc_End = true;
+ return false;
+ }
+ }
+ sc_Line++;
+ sc_Crossed = true;
+ }
+ }
+ text = sc_String;
+ if (*ScriptPtr == ASCII_QUOTE)
+ { // Quoted string
+ ScriptPtr++;
+ while (*ScriptPtr != ASCII_QUOTE)
+ {
+ *text++ = *ScriptPtr++;
+ if (ScriptPtr == ScriptEndPtr
+ || text == &sc_String[MAX_STRING_SIZE - 1])
+ {
+ break;
+ }
+ }
+ ScriptPtr++;
+ }
+ else
+ { // Normal string
+ while ((*ScriptPtr > 32) && (*ScriptPtr != ASCII_COMMENT))
+ {
+ *text++ = *ScriptPtr++;
+ if (ScriptPtr == ScriptEndPtr
+ || text == &sc_String[MAX_STRING_SIZE - 1])
+ {
+ break;
+ }
+ }
+ }
+ *text = 0;
+ return true;
+}
+
+//==========================================================================
+//
+// SC_MustGetString
+//
+//==========================================================================
+
+void SC_MustGetString(void)
+{
+ if (SC_GetString() == false)
+ {
+ SC_ScriptError("Missing string.");
+ }
+}
+
+//==========================================================================
+//
+// SC_MustGetStringName
+//
+//==========================================================================
+
+void SC_MustGetStringName(char *name)
+{
+ SC_MustGetString();
+ if (SC_Compare(name) == false)
+ {
+ SC_ScriptError(NULL);
+ }
+}
+
+//==========================================================================
+//
+// SC_GetNumber
+//
+//==========================================================================
+
+boolean SC_GetNumber(void)
+{
+ char *stopper;
+
+ CheckOpen();
+ if (SC_GetString())
+ {
+ sc_Number = strtol(sc_String, &stopper, 0);
+ if (*stopper != 0)
+ {
+ I_Error("SC_GetNumber: Bad numeric constant \"%s\".\n"
+ "Script %s, Line %d", sc_String, ScriptName, sc_Line);
+ }
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+//==========================================================================
+//
+// SC_MustGetNumber
+//
+//==========================================================================
+
+void SC_MustGetNumber(void)
+{
+ if (SC_GetNumber() == false)
+ {
+ SC_ScriptError("Missing integer.");
+ }
+}
+
+//==========================================================================
+//
+// SC_UnGet
+//
+// Assumes there is a valid string in sc_String.
+//
+//==========================================================================
+
+void SC_UnGet(void)
+{
+ AlreadyGot = true;
+}
+
+//==========================================================================
+//
+// SC_Check
+//
+// Returns true if another token is on the current line.
+//
+//==========================================================================
+
+/*
+boolean SC_Check(void)
+{
+ char *text;
+
+ CheckOpen();
+ text = ScriptPtr;
+ if(text >= ScriptEndPtr)
+ {
+ return false;
+ }
+ while(*text <= 32)
+ {
+ if(*text == '\n')
+ {
+ return false;
+ }
+ text++;
+ if(text == ScriptEndPtr)
+ {
+ return false;
+ }
+ }
+ if(*text == ASCII_COMMENT)
+ {
+ return false;
+ }
+ return true;
+}
+*/
+
+//==========================================================================
+//
+// SC_MatchString
+//
+// Returns the index of the first match to sc_String from the passed
+// array of strings, or -1 if not found.
+//
+//==========================================================================
+
+int SC_MatchString(char **strings)
+{
+ int i;
+
+ for (i = 0; *strings != NULL; i++)
+ {
+ if (SC_Compare(*strings++))
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+//==========================================================================
+//
+// SC_MustMatchString
+//
+//==========================================================================
+
+int SC_MustMatchString(char **strings)
+{
+ int i;
+
+ i = SC_MatchString(strings);
+ if (i == -1)
+ {
+ SC_ScriptError(NULL);
+ }
+ return i;
+}
+
+//==========================================================================
+//
+// SC_Compare
+//
+//==========================================================================
+
+boolean SC_Compare(char *text)
+{
+ if (strcasecmp(text, sc_String) == 0)
+ {
+ return true;
+ }
+ return false;
+}
+
+//==========================================================================
+//
+// SC_ScriptError
+//
+//==========================================================================
+
+void SC_ScriptError(char *message)
+{
+ if (message == NULL)
+ {
+ message = "Bad syntax.";
+ }
+ I_Error("Script error, \"%s\" line %d: %s", ScriptName, sc_Line, message);
+}
+
+//==========================================================================
+//
+// CheckOpen
+//
+//==========================================================================
+
+static void CheckOpen(void)
+{
+ if (ScriptOpen == false)
+ {
+ I_Error("SC_ call before SC_Open().");
+ }
+}
diff --git a/src/hexen/sn_sonix.c b/src/hexen/sn_sonix.c
new file mode 100644
index 00000000..8ec3a2d7
--- /dev/null
+++ b/src/hexen/sn_sonix.c
@@ -0,0 +1,544 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+// HEADER FILES ------------------------------------------------------------
+
+#include <string.h>
+#include "m_random.h"
+#include "h2def.h"
+#include "i_system.h"
+#include "i_sound.h"
+#include "s_sound.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define SS_MAX_SCRIPTS 64
+#define SS_TEMPBUFFER_SIZE 1024
+#define SS_SEQUENCE_NAME_LENGTH 32
+
+#define SS_SCRIPT_NAME "SNDSEQ"
+#define SS_STRING_PLAY "play"
+#define SS_STRING_PLAYUNTILDONE "playuntildone"
+#define SS_STRING_PLAYTIME "playtime"
+#define SS_STRING_PLAYREPEAT "playrepeat"
+#define SS_STRING_DELAY "delay"
+#define SS_STRING_DELAYRAND "delayrand"
+#define SS_STRING_VOLUME "volume"
+#define SS_STRING_END "end"
+#define SS_STRING_STOPSOUND "stopsound"
+
+// TYPES -------------------------------------------------------------------
+
+typedef enum
+{
+ SS_CMD_NONE,
+ SS_CMD_PLAY,
+ SS_CMD_WAITUNTILDONE, // used by PLAYUNTILDONE
+ SS_CMD_PLAYTIME,
+ SS_CMD_PLAYREPEAT,
+ SS_CMD_DELAY,
+ SS_CMD_DELAYRAND,
+ SS_CMD_VOLUME,
+ SS_CMD_STOPSOUND,
+ SS_CMD_END
+} sscmds_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void VerifySequencePtr(int *base, int *ptr);
+static int GetSoundOffset(char *name);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern sfxinfo_t S_sfx[];
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static struct
+{
+ char name[SS_SEQUENCE_NAME_LENGTH];
+ int scriptNum;
+ int stopSound;
+} SequenceTranslate[SEQ_NUMSEQ] =
+{
+ {
+ "Platform", 0, 0},
+ {
+ "Platform", 0, 0}, // a 'heavy' platform is just a platform
+ {
+ "PlatformMetal", 0, 0},
+ {
+ "Platform", 0, 0}, // same with a 'creak' platform
+ {
+ "Silence", 0, 0},
+ {
+ "Lava", 0, 0},
+ {
+ "Water", 0, 0},
+ {
+ "Ice", 0, 0},
+ {
+ "Earth", 0, 0},
+ {
+ "PlatformMetal2", 0, 0},
+ {
+ "DoorNormal", 0, 0},
+ {
+ "DoorHeavy", 0, 0},
+ {
+ "DoorMetal", 0, 0},
+ {
+ "DoorCreak", 0, 0},
+ {
+ "Silence", 0, 0},
+ {
+ "Lava", 0, 0},
+ {
+ "Water", 0, 0},
+ {
+ "Ice", 0, 0},
+ {
+ "Earth", 0, 0},
+ {
+ "DoorMetal2", 0, 0},
+ {
+ "Wind", 0, 0}
+};
+
+static int *SequenceData[SS_MAX_SCRIPTS];
+
+int ActiveSequences;
+seqnode_t *SequenceListHead;
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// VerifySequencePtr
+//
+// Verifies the integrity of the temporary ptr, and ensures that the ptr
+// isn't exceeding the size of the temporary buffer
+//==========================================================================
+
+static void VerifySequencePtr(int *base, int *ptr)
+{
+ if (ptr - base > SS_TEMPBUFFER_SIZE)
+ {
+ I_Error("VerifySequencePtr: tempPtr >= %d\n", SS_TEMPBUFFER_SIZE);
+ }
+}
+
+//==========================================================================
+//
+// GetSoundOffset
+//
+//==========================================================================
+
+static int GetSoundOffset(char *name)
+{
+ int i;
+
+ for (i = 0; i < NUMSFX; i++)
+ {
+ if (!strcasecmp(name, S_sfx[i].tagname))
+ {
+ return i;
+ }
+ }
+ SC_ScriptError("GetSoundOffset: Unknown sound name\n");
+ return 0;
+}
+
+//==========================================================================
+//
+// SN_InitSequenceScript
+//
+//==========================================================================
+
+void SN_InitSequenceScript(void)
+{
+ int i, j;
+ int inSequence;
+ int *tempDataStart = NULL;
+ int *tempDataPtr = NULL;
+
+ inSequence = -1;
+ ActiveSequences = 0;
+ for (i = 0; i < SS_MAX_SCRIPTS; i++)
+ {
+ SequenceData[i] = NULL;
+ }
+ SC_Open(SS_SCRIPT_NAME);
+ while (SC_GetString())
+ {
+ if (*sc_String == ':')
+ {
+ if (inSequence != -1)
+ {
+ SC_ScriptError("SN_InitSequenceScript: Nested Script Error");
+ }
+ tempDataStart = (int *) Z_Malloc(SS_TEMPBUFFER_SIZE,
+ PU_STATIC, NULL);
+ memset(tempDataStart, 0, SS_TEMPBUFFER_SIZE);
+ tempDataPtr = tempDataStart;
+ for (i = 0; i < SS_MAX_SCRIPTS; i++)
+ {
+ if (SequenceData[i] == NULL)
+ {
+ break;
+ }
+ }
+ if (i == SS_MAX_SCRIPTS)
+ {
+ I_Error("Number of SS Scripts >= SS_MAX_SCRIPTS");
+ }
+ for (j = 0; j < SEQ_NUMSEQ; j++)
+ {
+ if (!strcasecmp(SequenceTranslate[j].name, sc_String + 1))
+ {
+ SequenceTranslate[j].scriptNum = i;
+ inSequence = j;
+ break;
+ }
+ }
+ continue; // parse the next command
+ }
+ if (inSequence == -1)
+ {
+ continue;
+ }
+ if (SC_Compare(SS_STRING_PLAYUNTILDONE))
+ {
+ VerifySequencePtr(tempDataStart, tempDataPtr);
+ SC_MustGetString();
+ *tempDataPtr++ = SS_CMD_PLAY;
+ *tempDataPtr++ = GetSoundOffset(sc_String);
+ *tempDataPtr++ = SS_CMD_WAITUNTILDONE;
+ }
+ else if (SC_Compare(SS_STRING_PLAY))
+ {
+ VerifySequencePtr(tempDataStart, tempDataPtr);
+ SC_MustGetString();
+ *tempDataPtr++ = SS_CMD_PLAY;
+ *tempDataPtr++ = GetSoundOffset(sc_String);
+ }
+ else if (SC_Compare(SS_STRING_PLAYTIME))
+ {
+ VerifySequencePtr(tempDataStart, tempDataPtr);
+ SC_MustGetString();
+ *tempDataPtr++ = SS_CMD_PLAY;
+ *tempDataPtr++ = GetSoundOffset(sc_String);
+ SC_MustGetNumber();
+ *tempDataPtr++ = SS_CMD_DELAY;
+ *tempDataPtr++ = sc_Number;
+ }
+ else if (SC_Compare(SS_STRING_PLAYREPEAT))
+ {
+ VerifySequencePtr(tempDataStart, tempDataPtr);
+ SC_MustGetString();
+ *tempDataPtr++ = SS_CMD_PLAYREPEAT;
+ *tempDataPtr++ = GetSoundOffset(sc_String);
+ }
+ else if (SC_Compare(SS_STRING_DELAY))
+ {
+ VerifySequencePtr(tempDataStart, tempDataPtr);
+ *tempDataPtr++ = SS_CMD_DELAY;
+ SC_MustGetNumber();
+ *tempDataPtr++ = sc_Number;
+ }
+ else if (SC_Compare(SS_STRING_DELAYRAND))
+ {
+ VerifySequencePtr(tempDataStart, tempDataPtr);
+ *tempDataPtr++ = SS_CMD_DELAYRAND;
+ SC_MustGetNumber();
+ *tempDataPtr++ = sc_Number;
+ SC_MustGetNumber();
+ *tempDataPtr++ = sc_Number;
+ }
+ else if (SC_Compare(SS_STRING_VOLUME))
+ {
+ VerifySequencePtr(tempDataStart, tempDataPtr);
+ *tempDataPtr++ = SS_CMD_VOLUME;
+ SC_MustGetNumber();
+ *tempDataPtr++ = sc_Number;
+ }
+ else if (SC_Compare(SS_STRING_END))
+ {
+ int dataSize;
+
+ *tempDataPtr++ = SS_CMD_END;
+ dataSize = (tempDataPtr - tempDataStart) * sizeof(int);
+ SequenceData[i] = (int *) Z_Malloc(dataSize, PU_STATIC, NULL);
+ memcpy(SequenceData[i], tempDataStart, dataSize);
+ Z_Free(tempDataStart);
+ inSequence = -1;
+ }
+ else if (SC_Compare(SS_STRING_STOPSOUND))
+ {
+ SC_MustGetString();
+ SequenceTranslate[inSequence].stopSound =
+ GetSoundOffset(sc_String);
+ *tempDataPtr++ = SS_CMD_STOPSOUND;
+ }
+ else
+ {
+ SC_ScriptError("SN_InitSequenceScript: Unknown commmand.\n");
+ }
+ }
+}
+
+//==========================================================================
+//
+// SN_StartSequence
+//
+//==========================================================================
+
+void SN_StartSequence(mobj_t * mobj, int sequence)
+{
+ seqnode_t *node;
+
+ SN_StopSequence(mobj); // Stop any previous sequence
+ node = (seqnode_t *) Z_Malloc(sizeof(seqnode_t), PU_STATIC, NULL);
+ node->sequencePtr = SequenceData[SequenceTranslate[sequence].scriptNum];
+ node->sequence = sequence;
+ node->mobj = mobj;
+ node->delayTics = 0;
+ node->stopSound = SequenceTranslate[sequence].stopSound;
+ node->volume = 127; // Start at max volume
+
+ if (!SequenceListHead)
+ {
+ SequenceListHead = node;
+ node->next = node->prev = NULL;
+ }
+ else
+ {
+ SequenceListHead->prev = node;
+ node->next = SequenceListHead;
+ node->prev = NULL;
+ SequenceListHead = node;
+ }
+ ActiveSequences++;
+ return;
+}
+
+//==========================================================================
+//
+// SN_StartSequenceName
+//
+//==========================================================================
+
+void SN_StartSequenceName(mobj_t * mobj, char *name)
+{
+ int i;
+
+ for (i = 0; i < SEQ_NUMSEQ; i++)
+ {
+ if (!strcmp(name, SequenceTranslate[i].name))
+ {
+ SN_StartSequence(mobj, i);
+ return;
+ }
+ }
+}
+
+//==========================================================================
+//
+// SN_StopSequence
+//
+//==========================================================================
+
+void SN_StopSequence(mobj_t * mobj)
+{
+ seqnode_t *node;
+
+ for (node = SequenceListHead; node; node = node->next)
+ {
+ if (node->mobj == mobj)
+ {
+ S_StopSound(mobj);
+ if (node->stopSound)
+ {
+ S_StartSoundAtVolume(mobj, node->stopSound, node->volume);
+ }
+ if (SequenceListHead == node)
+ {
+ SequenceListHead = node->next;
+ }
+ if (node->prev)
+ {
+ node->prev->next = node->next;
+ }
+ if (node->next)
+ {
+ node->next->prev = node->prev;
+ }
+ Z_Free(node);
+ ActiveSequences--;
+ }
+ }
+}
+
+//==========================================================================
+//
+// SN_UpdateActiveSequences
+//
+//==========================================================================
+
+void SN_UpdateActiveSequences(void)
+{
+ seqnode_t *node;
+ boolean sndPlaying;
+
+ if (!ActiveSequences || paused)
+ { // No sequences currently playing/game is paused
+ return;
+ }
+ for (node = SequenceListHead; node; node = node->next)
+ {
+ if (node->delayTics)
+ {
+ node->delayTics--;
+ continue;
+ }
+ sndPlaying = S_GetSoundPlayingInfo(node->mobj, node->currentSoundID);
+ switch (*node->sequencePtr)
+ {
+ case SS_CMD_PLAY:
+ if (!sndPlaying)
+ {
+ node->currentSoundID = *(node->sequencePtr + 1);
+ S_StartSoundAtVolume(node->mobj, node->currentSoundID,
+ node->volume);
+ }
+ node->sequencePtr += 2;
+ break;
+ case SS_CMD_WAITUNTILDONE:
+ if (!sndPlaying)
+ {
+ node->sequencePtr++;
+ node->currentSoundID = 0;
+ }
+ break;
+ case SS_CMD_PLAYREPEAT:
+ if (!sndPlaying)
+ {
+ node->currentSoundID = *(node->sequencePtr + 1);
+ S_StartSoundAtVolume(node->mobj, node->currentSoundID,
+ node->volume);
+ }
+ break;
+ case SS_CMD_DELAY:
+ node->delayTics = *(node->sequencePtr + 1);
+ node->sequencePtr += 2;
+ node->currentSoundID = 0;
+ break;
+ case SS_CMD_DELAYRAND:
+ node->delayTics = *(node->sequencePtr + 1) +
+ M_Random() % (*(node->sequencePtr + 2) -
+ *(node->sequencePtr + 1));
+ node->sequencePtr += 2;
+ node->currentSoundID = 0;
+ break;
+ case SS_CMD_VOLUME:
+ node->volume = (127 * (*(node->sequencePtr + 1))) / 100;
+ node->sequencePtr += 2;
+ break;
+ case SS_CMD_STOPSOUND:
+ // Wait until something else stops the sequence
+ break;
+ case SS_CMD_END:
+ SN_StopSequence(node->mobj);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+//==========================================================================
+//
+// SN_StopAllSequences
+//
+//==========================================================================
+
+void SN_StopAllSequences(void)
+{
+ seqnode_t *node;
+
+ for (node = SequenceListHead; node; node = node->next)
+ {
+ node->stopSound = 0; // don't play any stop sounds
+ SN_StopSequence(node->mobj);
+ }
+}
+
+//==========================================================================
+//
+// SN_GetSequenceOffset
+//
+//==========================================================================
+
+int SN_GetSequenceOffset(int sequence, int *sequencePtr)
+{
+ return (sequencePtr -
+ SequenceData[SequenceTranslate[sequence].scriptNum]);
+}
+
+//==========================================================================
+//
+// SN_ChangeNodeData
+//
+// nodeNum zero is the first node
+//==========================================================================
+
+void SN_ChangeNodeData(int nodeNum, int seqOffset, int delayTics, int volume,
+ int currentSoundID)
+{
+ int i;
+ seqnode_t *node;
+
+ i = 0;
+ node = SequenceListHead;
+ while (node && i < nodeNum)
+ {
+ node = node->next;
+ i++;
+ }
+ if (!node)
+ { // reach the end of the list before finding the nodeNum-th node
+ return;
+ }
+ node->delayTics = delayTics;
+ node->volume = volume;
+ node->sequencePtr += seqOffset;
+ node->currentSoundID = currentSoundID;
+}
diff --git a/src/hexen/sounds.c b/src/hexen/sounds.c
new file mode 100644
index 00000000..144fdeaa
--- /dev/null
+++ b/src/hexen/sounds.c
@@ -0,0 +1,321 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#include "h2def.h"
+#include "sounds.h"
+
+// Music info
+
+/*
+musicinfo_t S_music[] =
+{
+ { "MUS_E1M1", 0 }, // 1-1
+ { "MUS_E1M2", 0 },
+ { "MUS_E1M3", 0 },
+ { "MUS_E1M4", 0 },
+ { "MUS_E1M5", 0 },
+ { "MUS_E1M6", 0 },
+ { "MUS_E1M7", 0 },
+ { "MUS_E1M8", 0 },
+ { "MUS_E1M9", 0 },
+ { "MUS_E2M1", 0 }, // 2-1
+ { "MUS_E2M2", 0 },
+ { "MUS_E2M3", 0 },
+ { "MUS_E2M4", 0 },
+ { "MUS_E1M4", 0 },
+ { "MUS_E2M6", 0 },
+ { "MUS_E2M7", 0 },
+ { "MUS_E2M8", 0 },
+ { "MUS_E2M9", 0 },
+ { "MUS_E1M1", 0 }, // 3-1
+ { "MUS_E3M2", 0 },
+ { "MUS_E3M3", 0 },
+ { "MUS_E1M6", 0 },
+ { "MUS_E1M3", 0 },
+ { "MUS_E1M2", 0 },
+ { "MUS_E1M5", 0 },
+ { "MUS_E1M9", 0 },
+ { "MUS_E2M6", 0 },
+ { "MUS_E1M6", 0 }, // 4-1
+ { "MUS_TITL", 0 },
+ { "MUS_INTR", 0 },
+ { "MUS_CPTD", 0 }
+};
+*/
+
+// Sound info
+
+#define SOUND(name, priority, numchannels, pitchshift) \
+ { name, "", priority, NULL, pitchshift, 0, -1, 0, numchannels, NULL }
+
+sfxinfo_t S_sfx[] = {
+ // tagname, lumpname, priority, usefulness, snd_ptr, lumpnum, numchannels,
+ // pitchshift
+ SOUND("", 0, 0, 0),
+ SOUND("PlayerFighterNormalDeath", 256, 2, 1),
+ SOUND("PlayerFighterCrazyDeath", 256, 2, 1),
+ SOUND("PlayerFighterExtreme1Death", 256, 2, 1),
+ SOUND("PlayerFighterExtreme2Death", 256, 2, 1),
+ SOUND("PlayerFighterExtreme3Death", 256, 2, 1),
+ SOUND("PlayerFighterBurnDeath", 256, 2, 1),
+ SOUND("PlayerClericNormalDeath", 256, 2, 1),
+ SOUND("PlayerClericCrazyDeath", 256, 2, 1),
+ SOUND("PlayerClericExtreme1Death", 256, 2, 1),
+ SOUND("PlayerClericExtreme2Death", 256, 2, 1),
+ SOUND("PlayerClericExtreme3Death", 256, 2, 1),
+ SOUND("PlayerClericBurnDeath", 256, 2, 1),
+ SOUND("PlayerMageNormalDeath", 256, 2, 0),
+ SOUND("PlayerMageCrazyDeath", 256, 2, 0),
+ SOUND("PlayerMageExtreme1Death", 256, 2, 0),
+ SOUND("PlayerMageExtreme2Death", 256, 2, 0),
+ SOUND("PlayerMageExtreme3Death", 256, 2, 0),
+ SOUND("PlayerMageBurnDeath", 256, 2, 0),
+ SOUND("PlayerFighterPain", 256, 2, 1),
+ SOUND("PlayerClericPain", 256, 2, 1),
+ SOUND("PlayerMagePain", 256, 2, 0),
+ SOUND("PlayerFighterGrunt", 256, 2, 1),
+ SOUND("PlayerClericGrunt", 256, 2, 1),
+ SOUND("PlayerMageGrunt", 256, 2, 0),
+ SOUND("PlayerLand", 32, 2, 1),
+ SOUND("PlayerPoisonCough", 256, 2, 1),
+ SOUND("PlayerFighterFallingScream", 256, 2, 1),
+ SOUND("PlayerClericFallingScream", 256, 2, 1),
+ SOUND("PlayerMageFallingScream", 256, 2, 0),
+ SOUND("PlayerFallingSplat", 256, 2, 1),
+ SOUND("PlayerFighterFailedUse", 256, 1, 1),
+ SOUND("PlayerClericFailedUse", 256, 1, 1),
+ SOUND("PlayerMageFailedUse", 256, 1, 0),
+ SOUND("PlatformStart", 36, 2, 1),
+ SOUND("PlatformStartMetal", 36, 2, 1),
+ SOUND("PlatformStop", 40, 2, 1),
+ SOUND("StoneMove", 32, 2, 1),
+ SOUND("MetalMove", 32, 2, 1),
+ SOUND("DoorOpen", 36, 2, 1),
+ SOUND("DoorLocked", 36, 2, 1),
+ SOUND("DoorOpenMetal", 36, 2, 1),
+ SOUND("DoorCloseMetal", 36, 2, 1),
+ SOUND("DoorCloseLight", 36, 2, 1),
+ SOUND("DoorCloseHeavy", 36, 2, 1),
+ SOUND("DoorCreak", 36, 2, 1),
+ SOUND("PickupWeapon", 36, 2, 0),
+ SOUND("PickupArtifact", 36, 2, 1),
+ SOUND("PickupKey", 36, 2, 1),
+ SOUND("PickupItem", 36, 2, 1),
+ SOUND("PickupPiece", 36, 2, 0),
+ SOUND("WeaponBuild", 36, 2, 0),
+ SOUND("UseArtifact", 36, 2, 1),
+ SOUND("BlastRadius", 36, 2, 1),
+ SOUND("Teleport", 256, 2, 1),
+ SOUND("ThunderCrash", 30, 2, 1),
+ SOUND("FighterPunchMiss", 80, 2, 1),
+ SOUND("FighterPunchHitThing", 80, 2, 1),
+ SOUND("FighterPunchHitWall", 80, 2, 1),
+ SOUND("FighterGrunt", 80, 2, 1),
+ SOUND("FighterAxeHitThing", 80, 2, 1),
+ SOUND("FighterHammerMiss", 80, 2, 1),
+ SOUND("FighterHammerHitThing", 80, 2, 1),
+ SOUND("FighterHammerHitWall", 80, 2, 1),
+ SOUND("FighterHammerContinuous", 32, 2, 1),
+ SOUND("FighterHammerExplode", 80, 2, 1),
+ SOUND("FighterSwordFire", 80, 2, 1),
+ SOUND("FighterSwordExplode", 80, 2, 1),
+ SOUND("ClericCStaffFire", 80, 2, 1),
+ SOUND("ClericCStaffExplode", 40, 2, 1),
+ SOUND("ClericCStaffHitThing", 80, 2, 1),
+ SOUND("ClericFlameFire", 80, 2, 1),
+ SOUND("ClericFlameExplode", 80, 2, 1),
+ SOUND("ClericFlameCircle", 80, 2, 1),
+ SOUND("MageWandFire", 80, 2, 1),
+ SOUND("MageLightningFire", 80, 2, 1),
+ SOUND("MageLightningZap", 32, 2, 1),
+ SOUND("MageLightningContinuous", 32, 2, 1),
+ SOUND("MageLightningReady", 30, 2, 1),
+ SOUND("MageShardsFire", 80, 2, 1),
+ SOUND("MageShardsExplode", 36, 2, 1),
+ SOUND("MageStaffFire", 80, 2, 1),
+ SOUND("MageStaffExplode", 40, 2, 1),
+ SOUND("Switch1", 32, 2, 1),
+ SOUND("Switch2", 32, 2, 1),
+ SOUND("SerpentSight", 32, 2, 1),
+ SOUND("SerpentActive", 32, 2, 1),
+ SOUND("SerpentPain", 32, 2, 1),
+ SOUND("SerpentAttack", 32, 2, 1),
+ SOUND("SerpentMeleeHit", 32, 2, 1),
+ SOUND("SerpentDeath", 40, 2, 1),
+ SOUND("SerpentBirth", 32, 2, 1),
+ SOUND("SerpentFXContinuous", 32, 2, 1),
+ SOUND("SerpentFXHit", 32, 2, 1),
+ SOUND("PotteryExplode", 32, 2, 1),
+ SOUND("Drip", 32, 2, 1),
+ SOUND("CentaurSight", 32, 2, 1),
+ SOUND("CentaurActive", 32, 2, 1),
+ SOUND("CentaurPain", 32, 2, 1),
+ SOUND("CentaurAttack", 32, 2, 1),
+ SOUND("CentaurDeath", 40, 2, 1),
+ SOUND("CentaurLeaderAttack", 32, 2, 1),
+ SOUND("CentaurMissileExplode", 32, 2, 1),
+ SOUND("Wind", 1, 2, 1),
+ SOUND("BishopSight", 32, 2, 1),
+ SOUND("BishopActive", 32, 2, 1),
+ SOUND("BishopPain", 32, 2, 1),
+ SOUND("BishopAttack", 32, 2, 1),
+ SOUND("BishopDeath", 40, 2, 1),
+ SOUND("BishopMissileExplode", 32, 2, 1),
+ SOUND("BishopBlur", 32, 2, 1),
+ SOUND("DemonSight", 32, 2, 1),
+ SOUND("DemonActive", 32, 2, 1),
+ SOUND("DemonPain", 32, 2, 1),
+ SOUND("DemonAttack", 32, 2, 1),
+ SOUND("DemonMissileFire", 32, 2, 1),
+ SOUND("DemonMissileExplode", 32, 2, 1),
+ SOUND("DemonDeath", 40, 2, 1),
+ SOUND("WraithSight", 32, 2, 1),
+ SOUND("WraithActive", 32, 2, 1),
+ SOUND("WraithPain", 32, 2, 1),
+ SOUND("WraithAttack", 32, 2, 1),
+ SOUND("WraithMissileFire", 32, 2, 1),
+ SOUND("WraithMissileExplode", 32, 2, 1),
+ SOUND("WraithDeath", 40, 2, 1),
+ SOUND("PigActive1", 32, 2, 1),
+ SOUND("PigActive2", 32, 2, 1),
+ SOUND("PigPain", 32, 2, 1),
+ SOUND("PigAttack", 32, 2, 1),
+ SOUND("PigDeath", 40, 2, 1),
+ SOUND("MaulatorSight", 32, 2, 1),
+ SOUND("MaulatorActive", 32, 2, 1),
+ SOUND("MaulatorPain", 32, 2, 1),
+ SOUND("MaulatorHamSwing", 32, 2, 1),
+ SOUND("MaulatorHamHit", 32, 2, 1),
+ SOUND("MaulatorMissileHit", 32, 2, 1),
+ SOUND("MaulatorDeath", 40, 2, 1),
+ SOUND("FreezeDeath", 40, 2, 1),
+ SOUND("FreezeShatter", 40, 2, 1),
+ SOUND("EttinSight", 32, 2, 1),
+ SOUND("EttinActive", 32, 2, 1),
+ SOUND("EttinPain", 32, 2, 1),
+ SOUND("EttinAttack", 32, 2, 1),
+ SOUND("EttinDeath", 40, 2, 1),
+ SOUND("FireDemonSpawn", 32, 2, 1),
+ SOUND("FireDemonActive", 32, 2, 1),
+ SOUND("FireDemonPain", 32, 2, 1),
+ SOUND("FireDemonAttack", 32, 2, 1),
+ SOUND("FireDemonMissileHit", 32, 2, 1),
+ SOUND("FireDemonDeath", 40, 2, 1),
+ SOUND("IceGuySight", 32, 2, 1),
+ SOUND("IceGuyActive", 32, 2, 1),
+ SOUND("IceGuyAttack", 32, 2, 1),
+ SOUND("IceGuyMissileExplode", 32, 2, 1),
+ SOUND("SorcererSight", 256, 2, 1),
+ SOUND("SorcererActive", 256, 2, 1),
+ SOUND("SorcererPain", 256, 2, 1),
+ SOUND("SorcererSpellCast", 256, 2, 1),
+ SOUND("SorcererBallWoosh", 256, 4, 1),
+ SOUND("SorcererDeathScream", 256, 2, 1),
+ SOUND("SorcererBishopSpawn", 80, 2, 1),
+ SOUND("SorcererBallPop", 80, 2, 1),
+ SOUND("SorcererBallBounce", 80, 3, 1),
+ SOUND("SorcererBallExplode", 80, 3, 1),
+ SOUND("SorcererBigBallExplode", 80, 3, 1),
+ SOUND("SorcererHeadScream", 256, 2, 1),
+ SOUND("DragonSight", 64, 2, 1),
+ SOUND("DragonActive", 64, 2, 1),
+ SOUND("DragonWingflap", 64, 2, 1),
+ SOUND("DragonAttack", 64, 2, 1),
+ SOUND("DragonPain", 64, 2, 1),
+ SOUND("DragonDeath", 64, 2, 1),
+ SOUND("DragonFireballExplode", 32, 2, 1),
+ SOUND("KoraxSight", 256, 2, 1),
+ SOUND("KoraxActive", 256, 2, 1),
+ SOUND("KoraxPain", 256, 2, 1),
+ SOUND("KoraxAttack", 256, 2, 1),
+ SOUND("KoraxCommand", 256, 2, 1),
+ SOUND("KoraxDeath", 256, 2, 1),
+ SOUND("KoraxStep", 128, 2, 1),
+ SOUND("ThrustSpikeRaise", 32, 2, 1),
+ SOUND("ThrustSpikeLower", 32, 2, 1),
+ SOUND("GlassShatter", 32, 2, 1),
+ SOUND("FlechetteBounce", 32, 2, 1),
+ SOUND("FlechetteExplode", 32, 2, 1),
+ SOUND("LavaMove", 36, 2, 1),
+ SOUND("WaterMove", 36, 2, 1),
+ SOUND("IceStartMove", 36, 2, 1),
+ SOUND("EarthStartMove", 36, 2, 1),
+ SOUND("WaterSplash", 32, 2, 1),
+ SOUND("LavaSizzle", 32, 2, 1),
+ SOUND("SludgeGloop", 32, 2, 1),
+ SOUND("HolySymbolFire", 64, 2, 1),
+ SOUND("SpiritActive", 32, 2, 1),
+ SOUND("SpiritAttack", 32, 2, 1),
+ SOUND("SpiritDie", 32, 2, 1),
+ SOUND("ValveTurn", 36, 2, 1),
+ SOUND("RopePull", 36, 2, 1),
+ SOUND("FlyBuzz", 20, 2, 1),
+ SOUND("Ignite", 32, 2, 1),
+ SOUND("PuzzleSuccess", 256, 2, 1),
+ SOUND("PuzzleFailFighter", 256, 2, 1),
+ SOUND("PuzzleFailCleric", 256, 2, 1),
+ SOUND("PuzzleFailMage", 256, 2, 1),
+ SOUND("Earthquake", 32, 2, 1),
+ SOUND("BellRing", 32, 2, 0),
+ SOUND("TreeBreak", 32, 2, 1),
+ SOUND("TreeExplode", 32, 2, 1),
+ SOUND("SuitofArmorBreak", 32, 2, 1),
+ SOUND("PoisonShroomPain", 20, 2, 1),
+ SOUND("PoisonShroomDeath", 32, 2, 1),
+ SOUND("Ambient1", 1, 1, 1),
+ SOUND("Ambient2", 1, 1, 1),
+ SOUND("Ambient3", 1, 1, 1),
+ SOUND("Ambient4", 1, 1, 1),
+ SOUND("Ambient5", 1, 1, 1),
+ SOUND("Ambient6", 1, 1, 1),
+ SOUND("Ambient7", 1, 1, 1),
+ SOUND("Ambient8", 1, 1, 1),
+ SOUND("Ambient9", 1, 1, 1),
+ SOUND("Ambient10", 1, 1, 1),
+ SOUND("Ambient11", 1, 1, 1),
+ SOUND("Ambient12", 1, 1, 1),
+ SOUND("Ambient13", 1, 1, 1),
+ SOUND("Ambient14", 1, 1, 1),
+ SOUND("Ambient15", 1, 1, 1),
+ SOUND("StartupTick", 32, 2, 1),
+ SOUND("SwitchOtherLevel", 32, 2, 1),
+ SOUND("Respawn", 32, 2, 1),
+ SOUND("KoraxVoiceGreetings", 512, 2, 1),
+ SOUND("KoraxVoiceReady", 512, 2, 1),
+ SOUND("KoraxVoiceBlood", 512, 2, 1),
+ SOUND("KoraxVoiceGame", 512, 2, 1),
+ SOUND("KoraxVoiceBoard", 512, 2, 1),
+ SOUND("KoraxVoiceWorship", 512, 2, 1),
+ SOUND("KoraxVoiceMaybe", 512, 2, 1),
+ SOUND("KoraxVoiceStrong", 512, 2, 1),
+ SOUND("KoraxVoiceFace", 512, 2, 1),
+ SOUND("BatScream", 32, 2, 1),
+ SOUND("Chat", 512, 2, 1),
+ SOUND("MenuMove", 32, 2, 1),
+ SOUND("ClockTick", 32, 2, 1),
+ SOUND("Fireball", 32, 2, 1),
+ SOUND("PuppyBeat", 30, 2, 1),
+ SOUND("MysticIncant", 32, 4, 1),
+};
diff --git a/src/hexen/sounds.h b/src/hexen/sounds.h
new file mode 100644
index 00000000..fd154aaa
--- /dev/null
+++ b/src/hexen/sounds.h
@@ -0,0 +1,324 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __SOUNDSH__
+#define __SOUNDSH__
+
+#include "i_sound.h"
+
+#define MAX_SND_DIST 2025
+#define MAX_CHANNELS 16
+
+// Music identifiers
+
+typedef enum
+{
+ mus_e1m1,
+ mus_e1m2,
+ mus_e1m3,
+ mus_e1m4,
+ mus_e1m5,
+ mus_e1m6,
+ mus_e1m7,
+ mus_e1m8,
+ mus_e1m9,
+ mus_e2m1,
+ mus_e2m2,
+ mus_e2m3,
+ mus_e2m4,
+ mus_e2m5,
+ mus_e2m6,
+ mus_e2m7,
+ mus_e2m8,
+ mus_e2m9,
+ mus_e3m1,
+ mus_e3m2,
+ mus_e3m3,
+ mus_e3m4,
+ mus_e3m5,
+ mus_e3m6,
+ mus_e3m7,
+ mus_e3m8,
+ mus_e3m9,
+ mus_e4m1,
+ mus_titl,
+ mus_intr,
+ mus_cptd,
+ NUMMUSIC
+} musicenum_t;
+
+// Sound identifiers
+
+typedef enum
+{
+ SFX_NONE,
+ SFX_PLAYER_FIGHTER_NORMAL_DEATH, // class specific death screams
+ SFX_PLAYER_FIGHTER_CRAZY_DEATH,
+ SFX_PLAYER_FIGHTER_EXTREME1_DEATH,
+ SFX_PLAYER_FIGHTER_EXTREME2_DEATH,
+ SFX_PLAYER_FIGHTER_EXTREME3_DEATH,
+ SFX_PLAYER_FIGHTER_BURN_DEATH,
+ SFX_PLAYER_CLERIC_NORMAL_DEATH,
+ SFX_PLAYER_CLERIC_CRAZY_DEATH,
+ SFX_PLAYER_CLERIC_EXTREME1_DEATH,
+ SFX_PLAYER_CLERIC_EXTREME2_DEATH,
+ SFX_PLAYER_CLERIC_EXTREME3_DEATH,
+ SFX_PLAYER_CLERIC_BURN_DEATH,
+ SFX_PLAYER_MAGE_NORMAL_DEATH,
+ SFX_PLAYER_MAGE_CRAZY_DEATH,
+ SFX_PLAYER_MAGE_EXTREME1_DEATH,
+ SFX_PLAYER_MAGE_EXTREME2_DEATH,
+ SFX_PLAYER_MAGE_EXTREME3_DEATH,
+ SFX_PLAYER_MAGE_BURN_DEATH,
+ SFX_PLAYER_FIGHTER_PAIN,
+ SFX_PLAYER_CLERIC_PAIN,
+ SFX_PLAYER_MAGE_PAIN,
+ SFX_PLAYER_FIGHTER_GRUNT,
+ SFX_PLAYER_CLERIC_GRUNT,
+ SFX_PLAYER_MAGE_GRUNT,
+ SFX_PLAYER_LAND,
+ SFX_PLAYER_POISONCOUGH,
+ SFX_PLAYER_FIGHTER_FALLING_SCREAM, // class specific falling screams
+ SFX_PLAYER_CLERIC_FALLING_SCREAM,
+ SFX_PLAYER_MAGE_FALLING_SCREAM,
+ SFX_PLAYER_FALLING_SPLAT,
+ SFX_PLAYER_FIGHTER_FAILED_USE,
+ SFX_PLAYER_CLERIC_FAILED_USE,
+ SFX_PLAYER_MAGE_FAILED_USE,
+ SFX_PLATFORM_START,
+ SFX_PLATFORM_STARTMETAL,
+ SFX_PLATFORM_STOP,
+ SFX_STONE_MOVE,
+ SFX_METAL_MOVE,
+ SFX_DOOR_OPEN,
+ SFX_DOOR_LOCKED,
+ SFX_DOOR_METAL_OPEN,
+ SFX_DOOR_METAL_CLOSE,
+ SFX_DOOR_LIGHT_CLOSE,
+ SFX_DOOR_HEAVY_CLOSE,
+ SFX_DOOR_CREAK,
+ SFX_PICKUP_WEAPON,
+ SFX_PICKUP_ARTIFACT,
+ SFX_PICKUP_KEY,
+ SFX_PICKUP_ITEM,
+ SFX_PICKUP_PIECE,
+ SFX_WEAPON_BUILD,
+ SFX_ARTIFACT_USE,
+ SFX_ARTIFACT_BLAST,
+ SFX_TELEPORT,
+ SFX_THUNDER_CRASH,
+ SFX_FIGHTER_PUNCH_MISS,
+ SFX_FIGHTER_PUNCH_HITTHING,
+ SFX_FIGHTER_PUNCH_HITWALL,
+ SFX_FIGHTER_GRUNT,
+ SFX_FIGHTER_AXE_HITTHING,
+ SFX_FIGHTER_HAMMER_MISS,
+ SFX_FIGHTER_HAMMER_HITTHING,
+ SFX_FIGHTER_HAMMER_HITWALL,
+ SFX_FIGHTER_HAMMER_CONTINUOUS,
+ SFX_FIGHTER_HAMMER_EXPLODE,
+ SFX_FIGHTER_SWORD_FIRE,
+ SFX_FIGHTER_SWORD_EXPLODE,
+ SFX_CLERIC_CSTAFF_FIRE,
+ SFX_CLERIC_CSTAFF_EXPLODE,
+ SFX_CLERIC_CSTAFF_HITTHING,
+ SFX_CLERIC_FLAME_FIRE,
+ SFX_CLERIC_FLAME_EXPLODE,
+ SFX_CLERIC_FLAME_CIRCLE,
+ SFX_MAGE_WAND_FIRE,
+ SFX_MAGE_LIGHTNING_FIRE,
+ SFX_MAGE_LIGHTNING_ZAP,
+ SFX_MAGE_LIGHTNING_CONTINUOUS,
+ SFX_MAGE_LIGHTNING_READY,
+ SFX_MAGE_SHARDS_FIRE,
+ SFX_MAGE_SHARDS_EXPLODE,
+ SFX_MAGE_STAFF_FIRE,
+ SFX_MAGE_STAFF_EXPLODE,
+ SFX_SWITCH1,
+ SFX_SWITCH2,
+ SFX_SERPENT_SIGHT,
+ SFX_SERPENT_ACTIVE,
+ SFX_SERPENT_PAIN,
+ SFX_SERPENT_ATTACK,
+ SFX_SERPENT_MELEEHIT,
+ SFX_SERPENT_DEATH,
+ SFX_SERPENT_BIRTH,
+ SFX_SERPENTFX_CONTINUOUS,
+ SFX_SERPENTFX_HIT,
+ SFX_POTTERY_EXPLODE,
+ SFX_DRIP,
+ SFX_CENTAUR_SIGHT,
+ SFX_CENTAUR_ACTIVE,
+ SFX_CENTAUR_PAIN,
+ SFX_CENTAUR_ATTACK,
+ SFX_CENTAUR_DEATH,
+ SFX_CENTAURLEADER_ATTACK,
+ SFX_CENTAUR_MISSILE_EXPLODE,
+ SFX_WIND,
+ SFX_BISHOP_SIGHT,
+ SFX_BISHOP_ACTIVE,
+ SFX_BISHOP_PAIN,
+ SFX_BISHOP_ATTACK,
+ SFX_BISHOP_DEATH,
+ SFX_BISHOP_MISSILE_EXPLODE,
+ SFX_BISHOP_BLUR,
+ SFX_DEMON_SIGHT,
+ SFX_DEMON_ACTIVE,
+ SFX_DEMON_PAIN,
+ SFX_DEMON_ATTACK,
+ SFX_DEMON_MISSILE_FIRE,
+ SFX_DEMON_MISSILE_EXPLODE,
+ SFX_DEMON_DEATH,
+ SFX_WRAITH_SIGHT,
+ SFX_WRAITH_ACTIVE,
+ SFX_WRAITH_PAIN,
+ SFX_WRAITH_ATTACK,
+ SFX_WRAITH_MISSILE_FIRE,
+ SFX_WRAITH_MISSILE_EXPLODE,
+ SFX_WRAITH_DEATH,
+ SFX_PIG_ACTIVE1,
+ SFX_PIG_ACTIVE2,
+ SFX_PIG_PAIN,
+ SFX_PIG_ATTACK,
+ SFX_PIG_DEATH,
+ SFX_MAULATOR_SIGHT,
+ SFX_MAULATOR_ACTIVE,
+ SFX_MAULATOR_PAIN,
+ SFX_MAULATOR_HAMMER_SWING,
+ SFX_MAULATOR_HAMMER_HIT,
+ SFX_MAULATOR_MISSILE_HIT,
+ SFX_MAULATOR_DEATH,
+ SFX_FREEZE_DEATH,
+ SFX_FREEZE_SHATTER,
+ SFX_ETTIN_SIGHT,
+ SFX_ETTIN_ACTIVE,
+ SFX_ETTIN_PAIN,
+ SFX_ETTIN_ATTACK,
+ SFX_ETTIN_DEATH,
+ SFX_FIRED_SPAWN,
+ SFX_FIRED_ACTIVE,
+ SFX_FIRED_PAIN,
+ SFX_FIRED_ATTACK,
+ SFX_FIRED_MISSILE_HIT,
+ SFX_FIRED_DEATH,
+ SFX_ICEGUY_SIGHT,
+ SFX_ICEGUY_ACTIVE,
+ SFX_ICEGUY_ATTACK,
+ SFX_ICEGUY_FX_EXPLODE,
+ SFX_SORCERER_SIGHT,
+ SFX_SORCERER_ACTIVE,
+ SFX_SORCERER_PAIN,
+ SFX_SORCERER_SPELLCAST,
+ SFX_SORCERER_BALLWOOSH,
+ SFX_SORCERER_DEATHSCREAM,
+ SFX_SORCERER_BISHOPSPAWN,
+ SFX_SORCERER_BALLPOP,
+ SFX_SORCERER_BALLBOUNCE,
+ SFX_SORCERER_BALLEXPLODE,
+ SFX_SORCERER_BIGBALLEXPLODE,
+ SFX_SORCERER_HEADSCREAM,
+ SFX_DRAGON_SIGHT,
+ SFX_DRAGON_ACTIVE,
+ SFX_DRAGON_WINGFLAP,
+ SFX_DRAGON_ATTACK,
+ SFX_DRAGON_PAIN,
+ SFX_DRAGON_DEATH,
+ SFX_DRAGON_FIREBALL_EXPLODE,
+ SFX_KORAX_SIGHT,
+ SFX_KORAX_ACTIVE,
+ SFX_KORAX_PAIN,
+ SFX_KORAX_ATTACK,
+ SFX_KORAX_COMMAND,
+ SFX_KORAX_DEATH,
+ SFX_KORAX_STEP,
+ SFX_THRUSTSPIKE_RAISE,
+ SFX_THRUSTSPIKE_LOWER,
+ SFX_STAINEDGLASS_SHATTER,
+ SFX_FLECHETTE_BOUNCE,
+ SFX_FLECHETTE_EXPLODE,
+ SFX_LAVA_MOVE,
+ SFX_WATER_MOVE,
+ SFX_ICE_STARTMOVE,
+ SFX_EARTH_STARTMOVE,
+ SFX_WATER_SPLASH,
+ SFX_LAVA_SIZZLE,
+ SFX_SLUDGE_GLOOP,
+ SFX_CHOLY_FIRE,
+ SFX_SPIRIT_ACTIVE,
+ SFX_SPIRIT_ATTACK,
+ SFX_SPIRIT_DIE,
+ SFX_VALVE_TURN,
+ SFX_ROPE_PULL,
+ SFX_FLY_BUZZ,
+ SFX_IGNITE,
+ SFX_PUZZLE_SUCCESS,
+ SFX_PUZZLE_FAIL_FIGHTER,
+ SFX_PUZZLE_FAIL_CLERIC,
+ SFX_PUZZLE_FAIL_MAGE,
+ SFX_EARTHQUAKE,
+ SFX_BELLRING,
+ SFX_TREE_BREAK,
+ SFX_TREE_EXPLODE,
+ SFX_SUITOFARMOR_BREAK,
+ SFX_POISONSHROOM_PAIN,
+ SFX_POISONSHROOM_DEATH,
+ SFX_AMBIENT1,
+ SFX_AMBIENT2,
+ SFX_AMBIENT3,
+ SFX_AMBIENT4,
+ SFX_AMBIENT5,
+ SFX_AMBIENT6,
+ SFX_AMBIENT7,
+ SFX_AMBIENT8,
+ SFX_AMBIENT9,
+ SFX_AMBIENT10,
+ SFX_AMBIENT11,
+ SFX_AMBIENT12,
+ SFX_AMBIENT13,
+ SFX_AMBIENT14,
+ SFX_AMBIENT15,
+ SFX_STARTUP_TICK,
+ SFX_SWITCH_OTHERLEVEL,
+ SFX_RESPAWN,
+ SFX_KORAX_VOICE_1,
+ SFX_KORAX_VOICE_2,
+ SFX_KORAX_VOICE_3,
+ SFX_KORAX_VOICE_4,
+ SFX_KORAX_VOICE_5,
+ SFX_KORAX_VOICE_6,
+ SFX_KORAX_VOICE_7,
+ SFX_KORAX_VOICE_8,
+ SFX_KORAX_VOICE_9,
+ SFX_BAT_SCREAM,
+ SFX_CHAT,
+ SFX_MENU_MOVE,
+ SFX_CLOCK_TICK,
+ SFX_FIREBALL,
+ SFX_PUPPYBEAT,
+ SFX_MYSTICINCANT,
+ NUMSFX
+} sfxenum_t;
+
+#endif
diff --git a/src/hexen/st_start.c b/src/hexen/st_start.c
new file mode 100644
index 00000000..391e26a6
--- /dev/null
+++ b/src/hexen/st_start.c
@@ -0,0 +1,316 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+
+// HEADER FILES ------------------------------------------------------------
+
+#include <stdarg.h>
+
+#include "config.h"
+
+#include "h2def.h"
+#include "i_system.h"
+#include "i_videohr.h"
+#include "s_sound.h"
+#include "st_start.h"
+
+
+// MACROS ------------------------------------------------------------------
+#define ST_MAX_NOTCHES 32
+#define ST_NOTCH_WIDTH 16
+#define ST_NOTCH_HEIGHT 23
+#define ST_PROGRESS_X 64 // Start of notches x screen pos.
+#define ST_PROGRESS_Y 441 // Start of notches y screen pos.
+
+#define ST_NETPROGRESS_X 288
+#define ST_NETPROGRESS_Y 32
+#define ST_NETNOTCH_WIDTH 8
+#define ST_NETNOTCH_HEIGHT 16
+#define ST_MAX_NETNOTCHES 8
+
+byte *ST_LoadScreen(void);
+void ST_UpdateNotches(int notchPosition);
+void ST_UpdateNetNotches(int notchPosition);
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+static const byte *bitmap = NULL;
+int graphical_startup = 1;
+static boolean using_graphical_startup;
+
+static const byte notchTable[] = {
+ // plane 0
+ 0x00, 0x80, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40,
+ 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x03, 0xC0,
+ 0x0F, 0x90, 0x1B, 0x68, 0x3D, 0xBC, 0x3F, 0xFC, 0x20, 0x08, 0x20, 0x08,
+ 0x2F, 0xD8, 0x37, 0xD8, 0x37, 0xF8, 0x1F, 0xF8, 0x1C, 0x50,
+
+ // plane 1
+ 0x00, 0x80, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x02, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0xA0,
+ 0x30, 0x6C, 0x24, 0x94, 0x42, 0x4A, 0x60, 0x0E, 0x60, 0x06, 0x7F, 0xF6,
+ 0x7F, 0xF6, 0x7F, 0xF6, 0x5E, 0xF6, 0x38, 0x16, 0x23, 0xAC,
+
+ // plane 2
+ 0x00, 0x80, 0x01, 0x80, 0x01, 0x80, 0x00, 0x00, 0x02, 0x40, 0x02, 0x40,
+ 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x03, 0xE0,
+ 0x30, 0x6C, 0x24, 0x94, 0x52, 0x6A, 0x7F, 0xFE, 0x60, 0x0E, 0x60, 0x0E,
+ 0x6F, 0xD6, 0x77, 0xD6, 0x56, 0xF6, 0x38, 0x36, 0x23, 0xAC,
+
+ // plane 3
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
+ 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0x80, 0x02, 0x40,
+ 0x0F, 0x90, 0x1B, 0x68, 0x3D, 0xB4, 0x1F, 0xF0, 0x1F, 0xF8, 0x1F, 0xF8,
+ 0x10, 0x28, 0x08, 0x28, 0x29, 0x08, 0x07, 0xE8, 0x1C, 0x50
+};
+
+
+// Red Network Progress notches
+static const byte netnotchTable[] = {
+ // plane 0
+ 0x80, 0x50, 0xD0, 0xf0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xD0, 0xF0, 0xC0,
+ 0x70, 0x50, 0x80, 0x60,
+
+ // plane 1
+ 0x60, 0xE0, 0xE0, 0xA0, 0xA0, 0xA0, 0xE0, 0xA0, 0xA0, 0xA0, 0xE0, 0xA0,
+ 0xA0, 0xE0, 0x60, 0x00,
+
+ // plane 2
+ 0x80, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00,
+ 0x10, 0x10, 0x80, 0x60,
+
+ // plane 3
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+// CODE --------------------------------------------------------------------
+
+
+
+//--------------------------------------------------------------------------
+//
+// Startup Screen Functions
+//
+//--------------------------------------------------------------------------
+
+
+//==========================================================================
+//
+// ST_Init - Do the startup screen
+//
+//==========================================================================
+
+void ST_Init(void)
+{
+ byte *pal;
+ byte *buffer;
+
+ using_graphical_startup = false;
+
+ if (graphical_startup && !debugmode && !testcontrols)
+ {
+ I_SetWindowTitleHR("Hexen startup - " PACKAGE_STRING);
+
+ // Set 640x480x16 mode
+ if (I_SetVideoModeHR())
+ {
+ using_graphical_startup = true;
+
+ S_StartSongName("orb", true);
+
+ I_ClearScreenHR();
+ I_InitPaletteHR();
+ I_BlackPaletteHR();
+
+ // Load graphic
+ buffer = ST_LoadScreen();
+ pal = buffer;
+ bitmap = buffer + 16 * 3;
+
+ I_SlamHR(bitmap);
+ I_FadeToPaletteHR(pal);
+ Z_Free(buffer);
+ }
+ }
+}
+
+void ST_Done(void)
+{
+ if (using_graphical_startup)
+ {
+ I_ClearScreenHR();
+ I_UnsetVideoModeHR();
+ }
+}
+
+
+//==========================================================================
+//
+// ST_UpdateNotches
+//
+//==========================================================================
+
+void ST_UpdateNotches(int notchPosition)
+{
+ int x = ST_PROGRESS_X + notchPosition * ST_NOTCH_WIDTH;
+ int y = ST_PROGRESS_Y;
+ I_SlamBlockHR(x, y, ST_NOTCH_WIDTH, ST_NOTCH_HEIGHT, notchTable);
+}
+
+
+//==========================================================================
+//
+// ST_UpdateNetNotches - indicates network progress
+//
+//==========================================================================
+
+void ST_UpdateNetNotches(int notchPosition)
+{
+ int x = ST_NETPROGRESS_X + notchPosition * ST_NETNOTCH_WIDTH;
+ int y = ST_NETPROGRESS_Y;
+ I_SlamBlockHR(x, y, ST_NETNOTCH_WIDTH, ST_NETNOTCH_HEIGHT, netnotchTable);
+}
+
+
+//==========================================================================
+//
+// ST_Progress - increments progress indicator
+//
+//==========================================================================
+
+void ST_Progress(void)
+{
+ // haleyjd FIXME: any way to get input here? SDL event loop?
+#ifdef __WATCOMC__
+ // Check for ESC press -- during startup all events eaten here
+ I_StartupReadKeys();
+#endif
+
+ if (using_graphical_startup)
+ {
+ static int notchPosition = 0;
+
+ if (notchPosition < ST_MAX_NOTCHES)
+ {
+ ST_UpdateNotches(notchPosition);
+ S_StartSound(NULL, SFX_STARTUP_TICK);
+ //I_Sleep(1000);
+ notchPosition++;
+ }
+ }
+
+ printf(".");
+}
+
+
+//==========================================================================
+//
+// ST_NetProgress - indicates network progress
+//
+//==========================================================================
+
+void ST_NetProgress(void)
+{
+ printf("*");
+
+ if (using_graphical_startup)
+ {
+ static int netnotchPosition = 0;
+
+ if (netnotchPosition < ST_MAX_NETNOTCHES)
+ {
+ ST_UpdateNetNotches(netnotchPosition);
+ S_StartSound(NULL, SFX_DRIP);
+ netnotchPosition++;
+ }
+ }
+}
+
+
+//==========================================================================
+//
+// ST_NetDone - net progress complete
+//
+//==========================================================================
+void ST_NetDone(void)
+{
+ if (using_graphical_startup)
+ {
+ S_StartSound(NULL, SFX_PICKUP_WEAPON);
+ }
+}
+
+
+//==========================================================================
+//
+// ST_Message - gives debug message
+//
+//==========================================================================
+
+void ST_Message(char *message, ...)
+{
+ va_list argptr;
+
+ va_start(argptr, message);
+ vprintf(message, argptr);
+ va_end(argptr);
+}
+
+//==========================================================================
+//
+// ST_RealMessage - gives user message
+//
+//==========================================================================
+
+void ST_RealMessage(char *message, ...)
+{
+ va_list argptr;
+
+ va_start(argptr, message);
+ vprintf(message, argptr);
+ va_end(argptr);
+}
+
+
+
+//==========================================================================
+//
+// ST_LoadScreen - loads startup graphic
+//
+//==========================================================================
+
+
+byte *ST_LoadScreen(void)
+{
+ int length, lump;
+ byte *buffer;
+
+ lump = W_GetNumForName("STARTUP");
+ length = W_LumpLength(lump);
+ buffer = (byte *) Z_Malloc(length, PU_STATIC, NULL);
+ W_ReadLump(lump, buffer);
+ return (buffer);
+}
+
diff --git a/src/hexen/st_start.h b/src/hexen/st_start.h
new file mode 100644
index 00000000..be938b74
--- /dev/null
+++ b/src/hexen/st_start.h
@@ -0,0 +1,47 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef STSTART_H
+#define STSTART_H
+
+// HEADER FILES ------------------------------------------------------------
+
+// MACROS ------------------------------------------------------------------
+
+// TYPES -------------------------------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+extern void ST_Init(void);
+extern void ST_Done(void);
+extern void ST_Message(char *message, ...);
+extern void ST_RealMessage(char *message, ...);
+extern void ST_Progress(void);
+extern void ST_NetProgress(void);
+extern void ST_NetDone(void);
+
+// PUBLIC DATA DECLARATIONS ------------------------------------------------
+
+extern int graphical_startup;
+
+#endif
diff --git a/src/hexen/sv_save.c b/src/hexen/sv_save.c
new file mode 100644
index 00000000..9dc8fc5d
--- /dev/null
+++ b/src/hexen/sv_save.c
@@ -0,0 +1,1768 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2def.h"
+#include "i_system.h"
+#include "m_misc.h"
+#include "i_swap.h"
+#include "p_local.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define MAX_TARGET_PLAYERS 512
+#define MOBJ_NULL -1
+#define MOBJ_XX_PLAYER -2
+#define GET_BYTE (*SavePtr.b++)
+#define GET_WORD (*SavePtr.w++)
+#define GET_LONG (*SavePtr.l++)
+#define MAX_MAPS 99
+#define BASE_SLOT 6
+#define REBORN_SLOT 7
+#define REBORN_DESCRIPTION "TEMP GAME"
+#define MAX_THINKER_SIZE 256
+
+// TYPES -------------------------------------------------------------------
+
+typedef enum
+{
+ ASEG_GAME_HEADER = 101,
+ ASEG_MAP_HEADER,
+ ASEG_WORLD,
+ ASEG_POLYOBJS,
+ ASEG_MOBJS,
+ ASEG_THINKERS,
+ ASEG_SCRIPTS,
+ ASEG_PLAYERS,
+ ASEG_SOUNDS,
+ ASEG_MISC,
+ ASEG_END
+} gameArchiveSegment_t;
+
+typedef enum
+{
+ TC_NULL,
+ TC_MOVE_CEILING,
+ TC_VERTICAL_DOOR,
+ TC_MOVE_FLOOR,
+ TC_PLAT_RAISE,
+ TC_INTERPRET_ACS,
+ TC_FLOOR_WAGGLE,
+ TC_LIGHT,
+ TC_PHASE,
+ TC_BUILD_PILLAR,
+ TC_ROTATE_POLY,
+ TC_MOVE_POLY,
+ TC_POLY_DOOR
+} thinkClass_t;
+
+typedef struct
+{
+ thinkClass_t tClass;
+ think_t thinkerFunc;
+ void (*mangleFunc) ();
+ void (*restoreFunc) ();
+ size_t size;
+} thinkInfo_t;
+
+typedef struct
+{
+ thinker_t thinker;
+ sector_t *sector;
+} ssthinker_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+void P_SpawnPlayer(mapthing_t * mthing);
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void ArchiveWorld(void);
+static void UnarchiveWorld(void);
+static void ArchivePolyobjs(void);
+static void UnarchivePolyobjs(void);
+static void ArchiveMobjs(void);
+static void UnarchiveMobjs(void);
+static void ArchiveThinkers(void);
+static void UnarchiveThinkers(void);
+static void ArchiveScripts(void);
+static void UnarchiveScripts(void);
+static void ArchivePlayers(void);
+static void UnarchivePlayers(void);
+static void ArchiveSounds(void);
+static void UnarchiveSounds(void);
+static void ArchiveMisc(void);
+static void UnarchiveMisc(void);
+static void SetMobjArchiveNums(void);
+static void RemoveAllThinkers(void);
+static void MangleMobj(mobj_t * mobj);
+static void RestoreMobj(mobj_t * mobj);
+static int GetMobjNum(mobj_t * mobj);
+static void SetMobjPtr(int *archiveNum);
+static void MangleSSThinker(ssthinker_t * sst);
+static void RestoreSSThinker(ssthinker_t * sst);
+static void RestoreSSThinkerNoSD(ssthinker_t * sst);
+static void MangleScript(acs_t * script);
+static void RestoreScript(acs_t * script);
+static void RestorePlatRaise(plat_t * plat);
+static void RestoreMoveCeiling(ceiling_t * ceiling);
+static void AssertSegment(gameArchiveSegment_t segType);
+static void ClearSaveSlot(int slot);
+static void CopySaveSlot(int sourceSlot, int destSlot);
+static void CopyFile(char *sourceName, char *destName);
+static boolean ExistingFile(char *name);
+static void OpenStreamOut(char *fileName);
+static void CloseStreamOut(void);
+static void StreamOutBuffer(void *buffer, int size);
+static void StreamOutByte(byte val);
+static void StreamOutWord(unsigned short val);
+static void StreamOutLong(unsigned int val);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+#define DEFAULT_SAVEPATH "hexndata/"
+
+char *SavePath = DEFAULT_SAVEPATH;
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static int MobjCount;
+static mobj_t **MobjList;
+static int **TargetPlayerAddrs;
+static int TargetPlayerCount;
+static byte *SaveBuffer;
+static boolean SavingPlayers;
+static union
+{
+ byte *b;
+ short *w;
+ int *l;
+} SavePtr;
+static FILE *SavingFP;
+
+// This list has been prioritized using frequency estimates
+static thinkInfo_t ThinkerInfo[] = {
+ {
+ TC_MOVE_FLOOR,
+ T_MoveFloor,
+ MangleSSThinker,
+ RestoreSSThinker,
+ sizeof(floormove_t)}
+ ,
+ {
+ TC_PLAT_RAISE,
+ T_PlatRaise,
+ MangleSSThinker,
+ RestorePlatRaise,
+ sizeof(plat_t)}
+ ,
+ {
+ TC_MOVE_CEILING,
+ T_MoveCeiling,
+ MangleSSThinker,
+ RestoreMoveCeiling,
+ sizeof(ceiling_t)}
+ ,
+ {
+ TC_LIGHT,
+ T_Light,
+ MangleSSThinker,
+ RestoreSSThinkerNoSD,
+ sizeof(light_t)}
+ ,
+ {
+ TC_VERTICAL_DOOR,
+ T_VerticalDoor,
+ MangleSSThinker,
+ RestoreSSThinker,
+ sizeof(vldoor_t)}
+ ,
+ {
+ TC_PHASE,
+ T_Phase,
+ MangleSSThinker,
+ RestoreSSThinkerNoSD,
+ sizeof(phase_t)}
+ ,
+ {
+ TC_INTERPRET_ACS,
+ T_InterpretACS,
+ MangleScript,
+ RestoreScript,
+ sizeof(acs_t)}
+ ,
+ {
+ TC_ROTATE_POLY,
+ T_RotatePoly,
+ NULL,
+ NULL,
+ sizeof(polyevent_t)}
+ ,
+ {
+ TC_BUILD_PILLAR,
+ T_BuildPillar,
+ MangleSSThinker,
+ RestoreSSThinker,
+ sizeof(pillar_t)}
+ ,
+ {
+ TC_MOVE_POLY,
+ T_MovePoly,
+ NULL,
+ NULL,
+ sizeof(polyevent_t)}
+ ,
+ {
+ TC_POLY_DOOR,
+ T_PolyDoor,
+ NULL,
+ NULL,
+ sizeof(polydoor_t)}
+ ,
+ {
+ TC_FLOOR_WAGGLE,
+ T_FloorWaggle,
+ MangleSSThinker,
+ RestoreSSThinker,
+ sizeof(floorWaggle_t)}
+ ,
+ { // Terminator
+ TC_NULL, NULL, NULL, NULL, 0}
+};
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// SV_SaveGame
+//
+//==========================================================================
+
+void SV_SaveGame(int slot, char *description)
+{
+ char fileName[100];
+ char versionText[HXS_VERSION_TEXT_LENGTH];
+
+ // Open the output file
+ sprintf(fileName, "%shex6.hxs", SavePath);
+ OpenStreamOut(fileName);
+
+ // Write game save description
+ StreamOutBuffer(description, HXS_DESCRIPTION_LENGTH);
+
+ // Write version info
+ memset(versionText, 0, HXS_VERSION_TEXT_LENGTH);
+ strcpy(versionText, HXS_VERSION_TEXT);
+ StreamOutBuffer(versionText, HXS_VERSION_TEXT_LENGTH);
+
+ // Place a header marker
+ StreamOutLong(ASEG_GAME_HEADER);
+
+ // Write current map and difficulty
+ StreamOutByte(gamemap);
+ StreamOutByte(gameskill);
+
+ // Write global script info
+ StreamOutBuffer(WorldVars, sizeof(WorldVars));
+ StreamOutBuffer(ACSStore, sizeof(ACSStore));
+
+ ArchivePlayers();
+
+ // Place a termination marker
+ StreamOutLong(ASEG_END);
+
+ // Close the output file
+ CloseStreamOut();
+
+ // Save out the current map
+ SV_SaveMap(true); // true = save player info
+
+ // Clear all save files at destination slot
+ ClearSaveSlot(slot);
+
+ // Copy base slot to destination slot
+ CopySaveSlot(BASE_SLOT, slot);
+}
+
+//==========================================================================
+//
+// SV_SaveMap
+//
+//==========================================================================
+
+void SV_SaveMap(boolean savePlayers)
+{
+ char fileName[100];
+
+ SavingPlayers = savePlayers;
+
+ // Open the output file
+ sprintf(fileName, "%shex6%02d.hxs", SavePath, gamemap);
+ OpenStreamOut(fileName);
+
+ // Place a header marker
+ StreamOutLong(ASEG_MAP_HEADER);
+
+ // Write the level timer
+ StreamOutLong(leveltime);
+
+ // Set the mobj archive numbers
+ SetMobjArchiveNums();
+
+ ArchiveWorld();
+ ArchivePolyobjs();
+ ArchiveMobjs();
+ ArchiveThinkers();
+ ArchiveScripts();
+ ArchiveSounds();
+ ArchiveMisc();
+
+ // Place a termination marker
+ StreamOutLong(ASEG_END);
+
+ // Close the output file
+ CloseStreamOut();
+}
+
+//==========================================================================
+//
+// SV_LoadGame
+//
+//==========================================================================
+
+void SV_LoadGame(int slot)
+{
+ int i;
+ char fileName[100];
+ player_t playerBackup[MAXPLAYERS];
+ mobj_t *mobj;
+
+ // Copy all needed save files to the base slot
+ if (slot != BASE_SLOT)
+ {
+ ClearSaveSlot(BASE_SLOT);
+ CopySaveSlot(slot, BASE_SLOT);
+ }
+
+ // Create the name
+ sprintf(fileName, "%shex6.hxs", SavePath);
+
+ // Load the file
+ M_ReadFile(fileName, &SaveBuffer);
+
+ // Set the save pointer and skip the description field
+ SavePtr.b = SaveBuffer + HXS_DESCRIPTION_LENGTH;
+
+ // Check the version text
+ if (strcmp((char *) SavePtr.b, HXS_VERSION_TEXT))
+ { // Bad version
+ return;
+ }
+ SavePtr.b += HXS_VERSION_TEXT_LENGTH;
+
+ AssertSegment(ASEG_GAME_HEADER);
+
+ gameepisode = 1;
+ gamemap = GET_BYTE;
+ gameskill = GET_BYTE;
+
+ // Read global script info
+ memcpy(WorldVars, SavePtr.b, sizeof(WorldVars));
+ SavePtr.b += sizeof(WorldVars);
+ memcpy(ACSStore, SavePtr.b, sizeof(ACSStore));
+ SavePtr.b += sizeof(ACSStore);
+
+ // Read the player structures
+ UnarchivePlayers();
+
+ AssertSegment(ASEG_END);
+
+ Z_Free(SaveBuffer);
+
+ // Save player structs
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ playerBackup[i] = players[i];
+ }
+
+ // Load the current map
+ SV_LoadMap();
+
+ // Don't need the player mobj relocation info for load game
+ Z_Free(TargetPlayerAddrs);
+
+ // Restore player structs
+ inv_ptr = 0;
+ curpos = 0;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ mobj = players[i].mo;
+ players[i] = playerBackup[i];
+ players[i].mo = mobj;
+ if (i == consoleplayer)
+ {
+ players[i].readyArtifact = players[i].inventory[inv_ptr].type;
+ }
+ }
+}
+
+//==========================================================================
+//
+// SV_UpdateRebornSlot
+//
+// Copies the base slot to the reborn slot.
+//
+//==========================================================================
+
+void SV_UpdateRebornSlot(void)
+{
+ ClearSaveSlot(REBORN_SLOT);
+ CopySaveSlot(BASE_SLOT, REBORN_SLOT);
+}
+
+//==========================================================================
+//
+// SV_ClearRebornSlot
+//
+//==========================================================================
+
+void SV_ClearRebornSlot(void)
+{
+ ClearSaveSlot(REBORN_SLOT);
+}
+
+//==========================================================================
+//
+// SV_MapTeleport
+//
+//==========================================================================
+
+void SV_MapTeleport(int map, int position)
+{
+ int i;
+ int j;
+ char fileName[100];
+ player_t playerBackup[MAXPLAYERS];
+ mobj_t *targetPlayerMobj;
+ mobj_t *mobj;
+ int inventoryPtr;
+ int currentInvPos;
+ boolean rClass;
+ boolean playerWasReborn;
+ boolean oldWeaponowned[NUMWEAPONS];
+ int oldKeys = 0;
+ int oldPieces = 0;
+ int bestWeapon;
+
+ if (!deathmatch)
+ {
+ if (P_GetMapCluster(gamemap) == P_GetMapCluster(map))
+ { // Same cluster - save map without saving player mobjs
+ SV_SaveMap(false);
+ }
+ else
+ { // Entering new cluster - clear base slot
+ ClearSaveSlot(BASE_SLOT);
+ }
+ }
+
+ // Store player structs for later
+ rClass = randomclass;
+ randomclass = false;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ playerBackup[i] = players[i];
+ }
+
+ // Save some globals that get trashed during the load
+ inventoryPtr = inv_ptr;
+ currentInvPos = curpos;
+
+ // Only SV_LoadMap() uses TargetPlayerAddrs, so it's NULLed here
+ // for the following check (player mobj redirection)
+ TargetPlayerAddrs = NULL;
+
+ gamemap = map;
+ sprintf(fileName, "%shex6%02d.hxs", SavePath, gamemap);
+ if (!deathmatch && ExistingFile(fileName))
+ { // Unarchive map
+ SV_LoadMap();
+ }
+ else
+ { // New map
+ G_InitNew(gameskill, gameepisode, gamemap);
+
+ // Destroy all freshly spawned players
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ {
+ P_RemoveMobj(players[i].mo);
+ }
+ }
+ }
+
+ // Restore player structs
+ targetPlayerMobj = NULL;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (!playeringame[i])
+ {
+ continue;
+ }
+ players[i] = playerBackup[i];
+ P_ClearMessage(&players[i]);
+ players[i].attacker = NULL;
+ players[i].poisoner = NULL;
+
+ if (netgame)
+ {
+ if (players[i].playerstate == PST_DEAD)
+ { // In a network game, force all players to be alive
+ players[i].playerstate = PST_REBORN;
+ }
+ if (!deathmatch)
+ { // Cooperative net-play, retain keys and weapons
+ oldKeys = players[i].keys;
+ oldPieces = players[i].pieces;
+ for (j = 0; j < NUMWEAPONS; j++)
+ {
+ oldWeaponowned[j] = players[i].weaponowned[j];
+ }
+ }
+ }
+ playerWasReborn = (players[i].playerstate == PST_REBORN);
+ if (deathmatch)
+ {
+ memset(players[i].frags, 0, sizeof(players[i].frags));
+ mobj = P_SpawnMobj(playerstarts[0][i].x << 16,
+ playerstarts[0][i].y << 16, 0,
+ MT_PLAYER_FIGHTER);
+ players[i].mo = mobj;
+ G_DeathMatchSpawnPlayer(i);
+ P_RemoveMobj(mobj);
+ }
+ else
+ {
+ P_SpawnPlayer(&playerstarts[position][i]);
+ }
+
+ if (playerWasReborn && netgame && !deathmatch)
+ { // Restore keys and weapons when reborn in co-op
+ players[i].keys = oldKeys;
+ players[i].pieces = oldPieces;
+ for (bestWeapon = 0, j = 0; j < NUMWEAPONS; j++)
+ {
+ if (oldWeaponowned[j])
+ {
+ bestWeapon = j;
+ players[i].weaponowned[j] = true;
+ }
+ }
+ players[i].mana[MANA_1] = 25;
+ players[i].mana[MANA_2] = 25;
+ if (bestWeapon)
+ { // Bring up the best weapon
+ players[i].pendingweapon = bestWeapon;
+ }
+ }
+
+ if (targetPlayerMobj == NULL)
+ { // The poor sap
+ targetPlayerMobj = players[i].mo;
+ }
+ }
+ randomclass = rClass;
+
+ // Redirect anything targeting a player mobj
+ if (TargetPlayerAddrs)
+ {
+ for (i = 0; i < TargetPlayerCount; i++)
+ {
+ *TargetPlayerAddrs[i] = (int) targetPlayerMobj;
+ }
+ Z_Free(TargetPlayerAddrs);
+ }
+
+ // Destroy all things touching players
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ {
+ P_TeleportMove(players[i].mo, players[i].mo->x, players[i].mo->y);
+ }
+ }
+
+ // Restore trashed globals
+ inv_ptr = inventoryPtr;
+ curpos = currentInvPos;
+
+ // Launch waiting scripts
+ if (!deathmatch)
+ {
+ P_CheckACSStore();
+ }
+
+ // For single play, save immediately into the reborn slot
+ if (!netgame)
+ {
+ SV_SaveGame(REBORN_SLOT, REBORN_DESCRIPTION);
+ }
+}
+
+//==========================================================================
+//
+// SV_GetRebornSlot
+//
+//==========================================================================
+
+int SV_GetRebornSlot(void)
+{
+ return (REBORN_SLOT);
+}
+
+//==========================================================================
+//
+// SV_RebornSlotAvailable
+//
+// Returns true if the reborn slot is available.
+//
+//==========================================================================
+
+boolean SV_RebornSlotAvailable(void)
+{
+ char fileName[100];
+
+ sprintf(fileName, "%shex%d.hxs", SavePath, REBORN_SLOT);
+ return ExistingFile(fileName);
+}
+
+//==========================================================================
+//
+// SV_LoadMap
+//
+//==========================================================================
+
+void SV_LoadMap(void)
+{
+ char fileName[100];
+
+ // Load a base level
+ G_InitNew(gameskill, gameepisode, gamemap);
+
+ // Remove all thinkers
+ RemoveAllThinkers();
+
+ // Create the name
+ sprintf(fileName, "%shex6%02d.hxs", SavePath, gamemap);
+
+ // Load the file
+ M_ReadFile(fileName, &SaveBuffer);
+ SavePtr.b = SaveBuffer;
+
+ AssertSegment(ASEG_MAP_HEADER);
+
+ // Read the level timer
+ leveltime = GET_LONG;
+
+ UnarchiveWorld();
+ UnarchivePolyobjs();
+ UnarchiveMobjs();
+ UnarchiveThinkers();
+ UnarchiveScripts();
+ UnarchiveSounds();
+ UnarchiveMisc();
+
+ AssertSegment(ASEG_END);
+
+ // Free mobj list and save buffer
+ Z_Free(MobjList);
+ Z_Free(SaveBuffer);
+}
+
+//==========================================================================
+//
+// SV_InitBaseSlot
+//
+//==========================================================================
+
+void SV_InitBaseSlot(void)
+{
+ ClearSaveSlot(BASE_SLOT);
+}
+
+//==========================================================================
+//
+// ArchivePlayers
+//
+//==========================================================================
+
+static void ArchivePlayers(void)
+{
+ int i;
+ int j;
+ player_t tempPlayer;
+
+ StreamOutLong(ASEG_PLAYERS);
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ StreamOutByte(playeringame[i]);
+ }
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (!playeringame[i])
+ {
+ continue;
+ }
+ StreamOutByte(PlayerClass[i]);
+ tempPlayer = players[i];
+ for (j = 0; j < NUMPSPRITES; j++)
+ {
+ if (tempPlayer.psprites[j].state)
+ {
+ tempPlayer.psprites[j].state =
+ (state_t *) (tempPlayer.psprites[j].state - states);
+ }
+ }
+ StreamOutBuffer(&tempPlayer, sizeof(player_t));
+ }
+}
+
+//==========================================================================
+//
+// UnarchivePlayers
+//
+//==========================================================================
+
+static void UnarchivePlayers(void)
+{
+ int i, j;
+
+ AssertSegment(ASEG_PLAYERS);
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ playeringame[i] = GET_BYTE;
+ }
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (!playeringame[i])
+ {
+ continue;
+ }
+ PlayerClass[i] = GET_BYTE;
+ memcpy(&players[i], SavePtr.b, sizeof(player_t));
+ SavePtr.b += sizeof(player_t);
+ players[i].mo = NULL; // Will be set when unarc thinker
+ P_ClearMessage(&players[i]);
+ players[i].attacker = NULL;
+ players[i].poisoner = NULL;
+ for (j = 0; j < NUMPSPRITES; j++)
+ {
+ if (players[i].psprites[j].state)
+ {
+ players[i].psprites[j].state =
+ &states[(int) players[i].psprites[j].state];
+ }
+ }
+ }
+}
+
+//==========================================================================
+//
+// ArchiveWorld
+//
+//==========================================================================
+
+static void ArchiveWorld(void)
+{
+ int i;
+ int j;
+ sector_t *sec;
+ line_t *li;
+ side_t *si;
+
+ StreamOutLong(ASEG_WORLD);
+ for (i = 0, sec = sectors; i < numsectors; i++, sec++)
+ {
+ StreamOutWord(sec->floorheight >> FRACBITS);
+ StreamOutWord(sec->ceilingheight >> FRACBITS);
+ StreamOutWord(sec->floorpic);
+ StreamOutWord(sec->ceilingpic);
+ StreamOutWord(sec->lightlevel);
+ StreamOutWord(sec->special);
+ StreamOutWord(sec->tag);
+ StreamOutWord(sec->seqType);
+ }
+ for (i = 0, li = lines; i < numlines; i++, li++)
+ {
+ StreamOutWord(li->flags);
+ StreamOutByte(li->special);
+ StreamOutByte(li->arg1);
+ StreamOutByte(li->arg2);
+ StreamOutByte(li->arg3);
+ StreamOutByte(li->arg4);
+ StreamOutByte(li->arg5);
+ for (j = 0; j < 2; j++)
+ {
+ if (li->sidenum[j] == -1)
+ {
+ continue;
+ }
+ si = &sides[li->sidenum[j]];
+ StreamOutWord(si->textureoffset >> FRACBITS);
+ StreamOutWord(si->rowoffset >> FRACBITS);
+ StreamOutWord(si->toptexture);
+ StreamOutWord(si->bottomtexture);
+ StreamOutWord(si->midtexture);
+ }
+ }
+}
+
+//==========================================================================
+//
+// UnarchiveWorld
+//
+//==========================================================================
+
+static void UnarchiveWorld(void)
+{
+ int i;
+ int j;
+ sector_t *sec;
+ line_t *li;
+ side_t *si;
+
+ AssertSegment(ASEG_WORLD);
+ for (i = 0, sec = sectors; i < numsectors; i++, sec++)
+ {
+ sec->floorheight = GET_WORD << FRACBITS;
+ sec->ceilingheight = GET_WORD << FRACBITS;
+ sec->floorpic = GET_WORD;
+ sec->ceilingpic = GET_WORD;
+ sec->lightlevel = GET_WORD;
+ sec->special = GET_WORD;
+ sec->tag = GET_WORD;
+ sec->seqType = GET_WORD;
+ sec->specialdata = 0;
+ sec->soundtarget = 0;
+ }
+ for (i = 0, li = lines; i < numlines; i++, li++)
+ {
+ li->flags = GET_WORD;
+ li->special = GET_BYTE;
+ li->arg1 = GET_BYTE;
+ li->arg2 = GET_BYTE;
+ li->arg3 = GET_BYTE;
+ li->arg4 = GET_BYTE;
+ li->arg5 = GET_BYTE;
+ for (j = 0; j < 2; j++)
+ {
+ if (li->sidenum[j] == -1)
+ {
+ continue;
+ }
+ si = &sides[li->sidenum[j]];
+ si->textureoffset = GET_WORD << FRACBITS;
+ si->rowoffset = GET_WORD << FRACBITS;
+ si->toptexture = GET_WORD;
+ si->bottomtexture = GET_WORD;
+ si->midtexture = GET_WORD;
+ }
+ }
+}
+
+//==========================================================================
+//
+// SetMobjArchiveNums
+//
+// Sets the archive numbers in all mobj structs. Also sets the MobjCount
+// global. Ignores player mobjs if SavingPlayers is false.
+//
+//==========================================================================
+
+static void SetMobjArchiveNums(void)
+{
+ mobj_t *mobj;
+ thinker_t *thinker;
+
+ MobjCount = 0;
+ for (thinker = thinkercap.next; thinker != &thinkercap;
+ thinker = thinker->next)
+ {
+ if (thinker->function == P_MobjThinker)
+ {
+ mobj = (mobj_t *) thinker;
+ if (mobj->player && !SavingPlayers)
+ { // Skipping player mobjs
+ continue;
+ }
+ mobj->archiveNum = MobjCount++;
+ }
+ }
+}
+
+//==========================================================================
+//
+// ArchiveMobjs
+//
+//==========================================================================
+
+static void ArchiveMobjs(void)
+{
+ int count;
+ thinker_t *thinker;
+ mobj_t tempMobj;
+
+ StreamOutLong(ASEG_MOBJS);
+ StreamOutLong(MobjCount);
+ count = 0;
+ for (thinker = thinkercap.next; thinker != &thinkercap;
+ thinker = thinker->next)
+ {
+ if (thinker->function != P_MobjThinker)
+ { // Not a mobj thinker
+ continue;
+ }
+ if (((mobj_t *) thinker)->player && !SavingPlayers)
+ { // Skipping player mobjs
+ continue;
+ }
+ count++;
+ memcpy(&tempMobj, thinker, sizeof(mobj_t));
+ MangleMobj(&tempMobj);
+ StreamOutBuffer(&tempMobj, sizeof(mobj_t));
+ }
+ if (count != MobjCount)
+ {
+ I_Error("ArchiveMobjs: bad mobj count");
+ }
+}
+
+//==========================================================================
+//
+// UnarchiveMobjs
+//
+//==========================================================================
+
+static void UnarchiveMobjs(void)
+{
+ int i;
+ mobj_t *mobj;
+
+ AssertSegment(ASEG_MOBJS);
+ TargetPlayerAddrs = Z_Malloc(MAX_TARGET_PLAYERS * sizeof(int *),
+ PU_STATIC, NULL);
+ TargetPlayerCount = 0;
+ MobjCount = GET_LONG;
+ MobjList = Z_Malloc(MobjCount * sizeof(mobj_t *), PU_STATIC, NULL);
+ for (i = 0; i < MobjCount; i++)
+ {
+ MobjList[i] = Z_Malloc(sizeof(mobj_t), PU_LEVEL, NULL);
+ }
+ for (i = 0; i < MobjCount; i++)
+ {
+ mobj = MobjList[i];
+ memcpy(mobj, SavePtr.b, sizeof(mobj_t));
+ SavePtr.b += sizeof(mobj_t);
+ mobj->thinker.function = P_MobjThinker;
+ RestoreMobj(mobj);
+ P_AddThinker(&mobj->thinker);
+ }
+ P_CreateTIDList();
+ P_InitCreatureCorpseQueue(true); // true = scan for corpses
+}
+
+//==========================================================================
+//
+// MangleMobj
+//
+//==========================================================================
+
+static void MangleMobj(mobj_t * mobj)
+{
+ boolean corpse;
+
+ corpse = mobj->flags & MF_CORPSE;
+ mobj->state = (state_t *) (mobj->state - states);
+ if (mobj->player)
+ {
+ mobj->player = (player_t *) ((mobj->player - players) + 1);
+ }
+ if (corpse)
+ {
+ mobj->target = (mobj_t *) MOBJ_NULL;
+ }
+ else
+ {
+ mobj->target = (mobj_t *) GetMobjNum(mobj->target);
+ }
+ switch (mobj->type)
+ {
+ // Just special1
+ case MT_BISH_FX:
+ case MT_HOLY_FX:
+ case MT_DRAGON:
+ case MT_THRUSTFLOOR_UP:
+ case MT_THRUSTFLOOR_DOWN:
+ case MT_MINOTAUR:
+ case MT_SORCFX1:
+ case MT_MSTAFF_FX2:
+ if (corpse)
+ {
+ mobj->special1.m = MOBJ_NULL;
+ }
+ else
+ {
+ mobj->special1.m = GetMobjNum(mobj->special1.m);
+ }
+ break;
+
+ // Just special2
+ case MT_LIGHTNING_FLOOR:
+ case MT_LIGHTNING_ZAP:
+ if (corpse)
+ {
+ mobj->special2.m = MOBJ_NULL;
+ }
+ else
+ {
+ mobj->special2.m = GetMobjNum(mobj->special2.m);
+ }
+ break;
+
+ // Both special1 and special2
+ case MT_HOLY_TAIL:
+ case MT_LIGHTNING_CEILING:
+ if (corpse)
+ {
+ mobj->special1.m = MOBJ_NULL;
+ mobj->special2.m = MOBJ_NULL;
+ }
+ else
+ {
+ mobj->special1.m = GetMobjNum(mobj->special1.m);
+ mobj->special2.m = GetMobjNum(mobj->special2.m);
+ }
+ break;
+
+ // Miscellaneous
+ case MT_KORAX:
+ mobj->special1.i = 0; // Searching index
+ break;
+
+ default:
+ break;
+ }
+}
+
+//==========================================================================
+//
+// GetMobjNum
+//
+//==========================================================================
+
+static int GetMobjNum(mobj_t * mobj)
+{
+ if (mobj == NULL)
+ {
+ return MOBJ_NULL;
+ }
+ if (mobj->player && !SavingPlayers)
+ {
+ return MOBJ_XX_PLAYER;
+ }
+ return mobj->archiveNum;
+}
+
+//==========================================================================
+//
+// RestoreMobj
+//
+//==========================================================================
+
+static void RestoreMobj(mobj_t * mobj)
+{
+ mobj->state = &states[(int) mobj->state];
+ if (mobj->player)
+ {
+ mobj->player = &players[(int) 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;
+ SetMobjPtr((int *) &mobj->target);
+ switch (mobj->type)
+ {
+ // Just special1
+ case MT_BISH_FX:
+ case MT_HOLY_FX:
+ case MT_DRAGON:
+ case MT_THRUSTFLOOR_UP:
+ case MT_THRUSTFLOOR_DOWN:
+ case MT_MINOTAUR:
+ case MT_SORCFX1:
+ SetMobjPtr(&mobj->special1.i);
+ break;
+
+ // Just special2
+ case MT_LIGHTNING_FLOOR:
+ case MT_LIGHTNING_ZAP:
+ SetMobjPtr(&mobj->special2.i);
+ break;
+
+ // Both special1 and special2
+ case MT_HOLY_TAIL:
+ case MT_LIGHTNING_CEILING:
+ SetMobjPtr(&mobj->special1.i);
+ SetMobjPtr(&mobj->special2.i);
+ break;
+
+ default:
+ break;
+ }
+}
+
+//==========================================================================
+//
+// SetMobjPtr
+//
+//==========================================================================
+
+static void SetMobjPtr(int *archiveNum)
+{
+ if (*archiveNum == MOBJ_NULL)
+ {
+ *archiveNum = 0;
+ return;
+ }
+ if (*archiveNum == MOBJ_XX_PLAYER)
+ {
+ if (TargetPlayerCount == MAX_TARGET_PLAYERS)
+ {
+ I_Error("RestoreMobj: exceeded MAX_TARGET_PLAYERS");
+ }
+ TargetPlayerAddrs[TargetPlayerCount++] = archiveNum;
+ *archiveNum = 0;
+ return;
+ }
+ *archiveNum = (int) MobjList[*archiveNum];
+}
+
+//==========================================================================
+//
+// ArchiveThinkers
+//
+//==========================================================================
+
+static void ArchiveThinkers(void)
+{
+ thinker_t *thinker;
+ thinkInfo_t *info;
+ byte buffer[MAX_THINKER_SIZE];
+
+ StreamOutLong(ASEG_THINKERS);
+ for (thinker = thinkercap.next; thinker != &thinkercap;
+ thinker = thinker->next)
+ {
+ for (info = ThinkerInfo; info->tClass != TC_NULL; info++)
+ {
+ if (thinker->function == info->thinkerFunc)
+ {
+ StreamOutByte(info->tClass);
+ memcpy(buffer, thinker, info->size);
+ if (info->mangleFunc)
+ {
+ info->mangleFunc(buffer);
+ }
+ StreamOutBuffer(buffer, info->size);
+ break;
+ }
+ }
+ }
+ // Add a termination marker
+ StreamOutByte(TC_NULL);
+}
+
+//==========================================================================
+//
+// UnarchiveThinkers
+//
+//==========================================================================
+
+static void UnarchiveThinkers(void)
+{
+ int tClass;
+ thinker_t *thinker;
+ thinkInfo_t *info;
+
+ AssertSegment(ASEG_THINKERS);
+ while ((tClass = GET_BYTE) != TC_NULL)
+ {
+ for (info = ThinkerInfo; info->tClass != TC_NULL; info++)
+ {
+ if (tClass == info->tClass)
+ {
+ thinker = Z_Malloc(info->size, PU_LEVEL, NULL);
+ memcpy(thinker, SavePtr.b, info->size);
+ SavePtr.b += info->size;
+ thinker->function = info->thinkerFunc;
+ if (info->restoreFunc)
+ {
+ info->restoreFunc(thinker);
+ }
+ P_AddThinker(thinker);
+ break;
+ }
+ }
+ if (info->tClass == TC_NULL)
+ {
+ I_Error("UnarchiveThinkers: Unknown tClass %d in "
+ "savegame", tClass);
+ }
+ }
+}
+
+//==========================================================================
+//
+// MangleSSThinker
+//
+//==========================================================================
+
+static void MangleSSThinker(ssthinker_t * sst)
+{
+ sst->sector = (sector_t *) (sst->sector - sectors);
+}
+
+//==========================================================================
+//
+// RestoreSSThinker
+//
+//==========================================================================
+
+static void RestoreSSThinker(ssthinker_t * sst)
+{
+ sst->sector = &sectors[(int) sst->sector];
+ sst->sector->specialdata = sst->thinker.function;
+}
+
+//==========================================================================
+//
+// RestoreSSThinkerNoSD
+//
+//==========================================================================
+
+static void RestoreSSThinkerNoSD(ssthinker_t * sst)
+{
+ sst->sector = &sectors[(int) sst->sector];
+}
+
+//==========================================================================
+//
+// MangleScript
+//
+//==========================================================================
+
+static void MangleScript(acs_t * script)
+{
+ script->ip = (int *) ((int) (script->ip) - (int) ActionCodeBase);
+ script->line = script->line ?
+ (line_t *) (script->line - lines) : (line_t *) - 1;
+ script->activator = (mobj_t *) GetMobjNum(script->activator);
+}
+
+//==========================================================================
+//
+// RestoreScript
+//
+//==========================================================================
+
+static void RestoreScript(acs_t * script)
+{
+ script->ip = (int *) (ActionCodeBase + (int) script->ip);
+ if ((int) script->line == -1)
+ {
+ script->line = NULL;
+ }
+ else
+ {
+ script->line = &lines[(int) script->line];
+ }
+ SetMobjPtr((int *) &script->activator);
+}
+
+//==========================================================================
+//
+// RestorePlatRaise
+//
+//==========================================================================
+
+static void RestorePlatRaise(plat_t * plat)
+{
+ plat->sector = &sectors[(int) plat->sector];
+ plat->sector->specialdata = T_PlatRaise;
+ P_AddActivePlat(plat);
+}
+
+//==========================================================================
+//
+// RestoreMoveCeiling
+//
+//==========================================================================
+
+static void RestoreMoveCeiling(ceiling_t * ceiling)
+{
+ ceiling->sector = &sectors[(int) ceiling->sector];
+ ceiling->sector->specialdata = T_MoveCeiling;
+ P_AddActiveCeiling(ceiling);
+}
+
+//==========================================================================
+//
+// ArchiveScripts
+//
+//==========================================================================
+
+static void ArchiveScripts(void)
+{
+ int i;
+
+ StreamOutLong(ASEG_SCRIPTS);
+ for (i = 0; i < ACScriptCount; i++)
+ {
+ StreamOutWord(ACSInfo[i].state);
+ StreamOutWord(ACSInfo[i].waitValue);
+ }
+ StreamOutBuffer(MapVars, sizeof(MapVars));
+}
+
+//==========================================================================
+//
+// UnarchiveScripts
+//
+//==========================================================================
+
+static void UnarchiveScripts(void)
+{
+ int i;
+
+ AssertSegment(ASEG_SCRIPTS);
+ for (i = 0; i < ACScriptCount; i++)
+ {
+ ACSInfo[i].state = GET_WORD;
+ ACSInfo[i].waitValue = GET_WORD;
+ }
+ memcpy(MapVars, SavePtr.b, sizeof(MapVars));
+ SavePtr.b += sizeof(MapVars);
+}
+
+//==========================================================================
+//
+// ArchiveMisc
+//
+//==========================================================================
+
+static void ArchiveMisc(void)
+{
+ int ix;
+
+ StreamOutLong(ASEG_MISC);
+ for (ix = 0; ix < MAXPLAYERS; ix++)
+ {
+ StreamOutLong(localQuakeHappening[ix]);
+ }
+}
+
+//==========================================================================
+//
+// UnarchiveMisc
+//
+//==========================================================================
+
+static void UnarchiveMisc(void)
+{
+ int ix;
+
+ AssertSegment(ASEG_MISC);
+ for (ix = 0; ix < MAXPLAYERS; ix++)
+ {
+ localQuakeHappening[ix] = GET_LONG;
+ }
+}
+
+//==========================================================================
+//
+// RemoveAllThinkers
+//
+//==========================================================================
+
+static void RemoveAllThinkers(void)
+{
+ thinker_t *thinker;
+ thinker_t *nextThinker;
+
+ thinker = thinkercap.next;
+ while (thinker != &thinkercap)
+ {
+ nextThinker = thinker->next;
+ if (thinker->function == P_MobjThinker)
+ {
+ P_RemoveMobj((mobj_t *) thinker);
+ }
+ else
+ {
+ Z_Free(thinker);
+ }
+ thinker = nextThinker;
+ }
+ P_InitThinkers();
+}
+
+//==========================================================================
+//
+// ArchiveSounds
+//
+//==========================================================================
+
+static void ArchiveSounds(void)
+{
+ seqnode_t *node;
+ sector_t *sec;
+ int difference;
+ int i;
+
+ StreamOutLong(ASEG_SOUNDS);
+
+ // Save the sound sequences
+ StreamOutLong(ActiveSequences);
+ for (node = SequenceListHead; node; node = node->next)
+ {
+ StreamOutLong(node->sequence);
+ StreamOutLong(node->delayTics);
+ StreamOutLong(node->volume);
+ StreamOutLong(SN_GetSequenceOffset(node->sequence,
+ node->sequencePtr));
+ StreamOutLong(node->currentSoundID);
+ for (i = 0; i < po_NumPolyobjs; i++)
+ {
+ if (node->mobj == (mobj_t *) & polyobjs[i].startSpot)
+ {
+ break;
+ }
+ }
+ if (i == po_NumPolyobjs)
+ { // Sound is attached to a sector, not a polyobj
+ sec = R_PointInSubsector(node->mobj->x, node->mobj->y)->sector;
+ difference = (int) ((byte *) sec
+ - (byte *) & sectors[0]) / sizeof(sector_t);
+ StreamOutLong(0); // 0 -- sector sound origin
+ }
+ else
+ {
+ StreamOutLong(1); // 1 -- polyobj sound origin
+ difference = i;
+ }
+ StreamOutLong(difference);
+ }
+}
+
+//==========================================================================
+//
+// UnarchiveSounds
+//
+//==========================================================================
+
+static void UnarchiveSounds(void)
+{
+ int i;
+ int numSequences;
+ int sequence;
+ int delayTics;
+ int volume;
+ int seqOffset;
+ int soundID;
+ int polySnd;
+ int secNum;
+ mobj_t *sndMobj;
+
+ AssertSegment(ASEG_SOUNDS);
+
+ // Reload and restart all sound sequences
+ numSequences = GET_LONG;
+ i = 0;
+ while (i < numSequences)
+ {
+ sequence = GET_LONG;
+ delayTics = GET_LONG;
+ volume = GET_LONG;
+ seqOffset = GET_LONG;
+
+ soundID = GET_LONG;
+ polySnd = GET_LONG;
+ secNum = GET_LONG;
+ if (!polySnd)
+ {
+ sndMobj = (mobj_t *) & sectors[secNum].soundorg;
+ }
+ else
+ {
+ sndMobj = (mobj_t *) & polyobjs[secNum].startSpot;
+ }
+ SN_StartSequence(sndMobj, sequence);
+ SN_ChangeNodeData(i, seqOffset, delayTics, volume, soundID);
+ i++;
+ }
+}
+
+//==========================================================================
+//
+// ArchivePolyobjs
+//
+//==========================================================================
+
+static void ArchivePolyobjs(void)
+{
+ int i;
+
+ StreamOutLong(ASEG_POLYOBJS);
+ StreamOutLong(po_NumPolyobjs);
+ for (i = 0; i < po_NumPolyobjs; i++)
+ {
+ StreamOutLong(polyobjs[i].tag);
+ StreamOutLong(polyobjs[i].angle);
+ StreamOutLong(polyobjs[i].startSpot.x);
+ StreamOutLong(polyobjs[i].startSpot.y);
+ }
+}
+
+//==========================================================================
+//
+// UnarchivePolyobjs
+//
+//==========================================================================
+
+static void UnarchivePolyobjs(void)
+{
+ int i;
+ fixed_t deltaX;
+ fixed_t deltaY;
+
+ AssertSegment(ASEG_POLYOBJS);
+ if (GET_LONG != po_NumPolyobjs)
+ {
+ I_Error("UnarchivePolyobjs: Bad polyobj count");
+ }
+ for (i = 0; i < po_NumPolyobjs; i++)
+ {
+ if (GET_LONG != polyobjs[i].tag)
+ {
+ I_Error("UnarchivePolyobjs: Invalid polyobj tag");
+ }
+ PO_RotatePolyobj(polyobjs[i].tag, (angle_t) GET_LONG);
+ deltaX = GET_LONG - polyobjs[i].startSpot.x;
+ deltaY = GET_LONG - polyobjs[i].startSpot.y;
+ PO_MovePolyobj(polyobjs[i].tag, deltaX, deltaY);
+ }
+}
+
+//==========================================================================
+//
+// AssertSegment
+//
+//==========================================================================
+
+static void AssertSegment(gameArchiveSegment_t segType)
+{
+ if (GET_LONG != segType)
+ {
+ I_Error("Corrupt save game: Segment [%d] failed alignment check",
+ segType);
+ }
+}
+
+//==========================================================================
+//
+// ClearSaveSlot
+//
+// Deletes all save game files associated with a slot number.
+//
+//==========================================================================
+
+static void ClearSaveSlot(int slot)
+{
+ int i;
+ char fileName[100];
+
+ for (i = 0; i < MAX_MAPS; i++)
+ {
+ sprintf(fileName, "%shex%d%02d.hxs", SavePath, slot, i);
+ remove(fileName);
+ }
+ sprintf(fileName, "%shex%d.hxs", SavePath, slot);
+ remove(fileName);
+}
+
+//==========================================================================
+//
+// CopySaveSlot
+//
+// Copies all the save game files from one slot to another.
+//
+//==========================================================================
+
+static void CopySaveSlot(int sourceSlot, int destSlot)
+{
+ int i;
+ char sourceName[100];
+ char destName[100];
+
+ for (i = 0; i < MAX_MAPS; i++)
+ {
+ sprintf(sourceName, "%shex%d%02d.hxs", SavePath, sourceSlot, i);
+ if (ExistingFile(sourceName))
+ {
+ sprintf(destName, "%shex%d%02d.hxs", SavePath, destSlot, i);
+ CopyFile(sourceName, destName);
+ }
+ }
+ sprintf(sourceName, "%shex%d.hxs", SavePath, sourceSlot);
+ if (ExistingFile(sourceName))
+ {
+ sprintf(destName, "%shex%d.hxs", SavePath, destSlot);
+ CopyFile(sourceName, destName);
+ }
+}
+
+//==========================================================================
+//
+// CopyFile
+//
+//==========================================================================
+
+static void CopyFile(char *sourceName, char *destName)
+{
+ int length;
+ byte *buffer;
+
+ length = M_ReadFile(sourceName, &buffer);
+ M_WriteFile(destName, buffer, length);
+ Z_Free(buffer);
+}
+
+//==========================================================================
+//
+// ExistingFile
+//
+//==========================================================================
+
+static boolean ExistingFile(char *name)
+{
+ FILE *fp;
+
+ if ((fp = fopen(name, "rb")) != NULL)
+ {
+ fclose(fp);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+//==========================================================================
+//
+// OpenStreamOut
+//
+//==========================================================================
+
+static void OpenStreamOut(char *fileName)
+{
+ SavingFP = fopen(fileName, "wb");
+}
+
+//==========================================================================
+//
+// CloseStreamOut
+//
+//==========================================================================
+
+static void CloseStreamOut(void)
+{
+ if (SavingFP)
+ {
+ fclose(SavingFP);
+ }
+}
+
+//==========================================================================
+//
+// StreamOutBuffer
+//
+//==========================================================================
+
+static void StreamOutBuffer(void *buffer, int size)
+{
+ fwrite(buffer, size, 1, SavingFP);
+}
+
+//==========================================================================
+//
+// StreamOutByte
+//
+//==========================================================================
+
+static void StreamOutByte(byte val)
+{
+ fwrite(&val, sizeof(byte), 1, SavingFP);
+}
+
+//==========================================================================
+//
+// StreamOutWord
+//
+//==========================================================================
+
+static void StreamOutWord(unsigned short val)
+{
+ fwrite(&val, sizeof(unsigned short), 1, SavingFP);
+}
+
+//==========================================================================
+//
+// StreamOutLong
+//
+//==========================================================================
+
+static void StreamOutLong(unsigned int val)
+{
+ fwrite(&val, sizeof(int), 1, SavingFP);
+}
diff --git a/src/hexen/textdefs.h b/src/hexen/textdefs.h
new file mode 100644
index 00000000..76f15c06
--- /dev/null
+++ b/src/hexen/textdefs.h
@@ -0,0 +1,180 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+// MN_menu.c ---------------------------------------------------------------
+
+#define PRESSKEY "press a key."
+#define PRESSYN "press y or n."
+#define TXT_PAUSED "PAUSED"
+#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 NEWGAME "you can't start a new game\n"\
+ "while in a network game.\n\n"PRESSKEY
+#define MSGOFF "Messages OFF"
+#define MSGON "Messages 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 to dos.)"
+#define TXT_GAMMA_LEVEL_OFF "GAMMA CORRECTION OFF"
+#define TXT_GAMMA_LEVEL_1 "GAMMA CORRECTION LEVEL 1"
+#define TXT_GAMMA_LEVEL_2 "GAMMA CORRECTION LEVEL 2"
+#define TXT_GAMMA_LEVEL_3 "GAMMA CORRECTION LEVEL 3"
+#define TXT_GAMMA_LEVEL_4 "GAMMA CORRECTION LEVEL 4"
+#define EMPTYSTRING "empty slot"
+
+// P_inter.c ---------------------------------------------------------------
+
+// Mana
+
+#define TXT_MANA_1 "BLUE MANA"
+#define TXT_MANA_2 "GREEN MANA"
+#define TXT_MANA_BOTH "COMBINED MANA"
+
+// Keys
+
+#define TXT_KEY_STEEL "STEEL KEY"
+#define TXT_KEY_CAVE "CAVE KEY"
+#define TXT_KEY_AXE "AXE KEY"
+#define TXT_KEY_FIRE "FIRE KEY"
+#define TXT_KEY_EMERALD "EMERALD KEY"
+#define TXT_KEY_DUNGEON "DUNGEON KEY"
+#define TXT_KEY_SILVER "SILVER KEY"
+#define TXT_KEY_RUSTED "RUSTED KEY"
+#define TXT_KEY_HORN "HORN KEY"
+#define TXT_KEY_SWAMP "SWAMP KEY"
+#define TXT_KEY_CASTLE "CASTLE KEY"
+
+// Artifacts
+
+#define TXT_ARTIINVULNERABILITY "ICON OF THE DEFENDER"
+#define TXT_ARTIHEALTH "QUARTZ FLASK"
+#define TXT_ARTISUPERHEALTH "MYSTIC URN"
+#define TXT_ARTISUMMON "DARK SERVANT"
+#define TXT_ARTITORCH "TORCH"
+#define TXT_ARTIEGG "PORKALATOR"
+#define TXT_ARTIFLY "WINGS OF WRATH"
+#define TXT_ARTITELEPORT "CHAOS DEVICE"
+#define TXT_ARTIPOISONBAG "FLECHETTE"
+#define TXT_ARTITELEPORTOTHER "BANISHMENT DEVICE"
+#define TXT_ARTISPEED "BOOTS OF SPEED"
+#define TXT_ARTIBOOSTMANA "KRATER OF MIGHT"
+#define TXT_ARTIBOOSTARMOR "DRAGONSKIN BRACERS"
+#define TXT_ARTIBLASTRADIUS "DISC OF REPULSION"
+#define TXT_ARTIHEALINGRADIUS "MYSTIC AMBIT INCANT"
+
+// Puzzle artifacts
+
+#define TXT_ARTIPUZZSKULL "YORICK'S SKULL"
+#define TXT_ARTIPUZZGEMBIG "HEART OF D'SPARIL"
+#define TXT_ARTIPUZZGEMRED "RUBY PLANET"
+#define TXT_ARTIPUZZGEMGREEN1 "EMERALD PLANET"
+#define TXT_ARTIPUZZGEMGREEN2 "EMERALD PLANET"
+#define TXT_ARTIPUZZGEMBLUE1 "SAPPHIRE PLANET"
+#define TXT_ARTIPUZZGEMBLUE2 "SAPPHIRE PLANET"
+#define TXT_ARTIPUZZBOOK1 "DAEMON CODEX"
+#define TXT_ARTIPUZZBOOK2 "LIBER OSCURA"
+#define TXT_ARTIPUZZSKULL2 "FLAME MASK"
+#define TXT_ARTIPUZZFWEAPON "GLAIVE SEAL"
+#define TXT_ARTIPUZZCWEAPON "HOLY RELIC"
+#define TXT_ARTIPUZZMWEAPON "SIGIL OF THE MAGUS"
+#define TXT_ARTIPUZZGEAR "CLOCK GEAR"
+#define TXT_USEPUZZLEFAILED "YOU CANNOT USE THIS HERE"
+
+// Items
+
+#define TXT_ITEMHEALTH "CRYSTAL VIAL"
+#define TXT_ITEMBAGOFHOLDING "BAG OF HOLDING"
+#define TXT_ITEMSHIELD1 "SILVER SHIELD"
+#define TXT_ITEMSHIELD2 "ENCHANTED SHIELD"
+#define TXT_ITEMSUPERMAP "MAP SCROLL"
+#define TXT_ARMOR1 "MESH ARMOR"
+#define TXT_ARMOR2 "FALCON SHIELD"
+#define TXT_ARMOR3 "PLATINUM HELMET"
+#define TXT_ARMOR4 "AMULET OF WARDING"
+
+// Weapons
+
+#define TXT_WEAPON_F2 "TIMON'S AXE"
+#define TXT_WEAPON_F3 "HAMMER OF RETRIBUTION"
+#define TXT_WEAPON_F4 "QUIETUS ASSEMBLED"
+#define TXT_WEAPON_C2 "SERPENT STAFF"
+#define TXT_WEAPON_C3 "FIRESTORM"
+#define TXT_WEAPON_C4 "WRAITHVERGE ASSEMBLED"
+#define TXT_WEAPON_M2 "FROST SHARDS"
+#define TXT_WEAPON_M3 "ARC OF DEATH"
+#define TXT_WEAPON_M4 "BLOODSCOURGE ASSEMBLED"
+#define TXT_QUIETUS_PIECE "SEGMENT OF QUIETUS"
+#define TXT_WRAITHVERGE_PIECE "SEGMENT OF WRAITHVERGE"
+#define TXT_BLOODSCOURGE_PIECE "SEGMENT OF BLOODSCOURGE"
+
+// SB_bar.c ----------------------------------------------------------------
+
+#define TXT_CHEATGODON "GOD MODE ON"
+#define TXT_CHEATGODOFF "GOD MODE OFF"
+#define TXT_CHEATNOCLIPON "NO CLIPPING ON"
+#define TXT_CHEATNOCLIPOFF "NO CLIPPING OFF"
+#define TXT_CHEATWEAPONS "ALL WEAPONS"
+#define TXT_CHEATHEALTH "FULL HEALTH"
+#define TXT_CHEATKEYS "ALL KEYS"
+#define TXT_CHEATSOUNDON "SOUND DEBUG ON"
+#define TXT_CHEATSOUNDOFF "SOUND DEBUG OFF"
+#define TXT_CHEATTICKERON "TICKER ON"
+#define TXT_CHEATTICKEROFF "TICKER OFF"
+#define TXT_CHEATARTIFACTS3 "ALL ARTIFACTS"
+#define TXT_CHEATARTIFACTSFAIL "BAD INPUT"
+#define TXT_CHEATWARP "LEVEL WARP"
+#define TXT_CHEATSCREENSHOT "SCREENSHOT"
+#define TXT_CHEATIDDQD "TRYING TO CHEAT, EH? NOW YOU DIE!"
+#define TXT_CHEATIDKFA "CHEATER - YOU DON'T DESERVE WEAPONS"
+#define TXT_CHEATBADINPUT "BAD INPUT"
+#define TXT_CHEATNOMAP "CAN'T FIND MAP"
+
+// G_game.c ----------------------------------------------------------------
+
+#define TXT_GAMESAVED "GAME SAVED"
+
+// M_misc.c ----------------------------------------------------------------
+
+#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"
+
+// AM_map.c ----------------------------------------------------------------
+
+#define AMSTR_FOLLOWON "FOLLOW MODE ON"
+#define AMSTR_FOLLOWOFF "FOLLOW MODE OFF"
diff --git a/src/hexen/xddefs.h b/src/hexen/xddefs.h
new file mode 100644
index 00000000..ff7f2a93
--- /dev/null
+++ b/src/hexen/xddefs.h
@@ -0,0 +1,197 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __XDDEFS__
+#define __XDDEFS__
+
+#include "doomtype.h"
+#include "v_patch.h"
+
+//--------------------------------------------------------------------------
+//
+// Map level types
+//
+//--------------------------------------------------------------------------
+
+// lump order in a map wad
+enum
+{
+ ML_LABEL,
+ ML_THINGS,
+ ML_LINEDEFS,
+ ML_SIDEDEFS,
+ ML_VERTEXES,
+ ML_SEGS,
+ ML_SSECTORS,
+ ML_NODES,
+ ML_SECTORS,
+ ML_REJECT,
+ ML_BLOCKMAP,
+ ML_BEHAVIOR
+};
+
+typedef struct
+{
+ short x;
+ short y;
+} PACKEDATTR mapvertex_t;
+
+typedef struct
+{
+ short textureoffset;
+ short rowoffset;
+ char toptexture[8];
+ char bottomtexture[8];
+ char midtexture[8];
+ short sector; // on viewer's side
+} PACKEDATTR mapsidedef_t;
+
+typedef struct
+{
+ short v1;
+ short v2;
+ short flags;
+ byte special;
+ byte arg1;
+ byte arg2;
+ byte arg3;
+ byte arg4;
+ byte arg5;
+ short sidenum[2]; // sidenum[1] will be -1 if one sided
+} PACKEDATTR maplinedef_t;
+
+#define ML_BLOCKING 0x0001
+#define ML_BLOCKMONSTERS 0x0002
+#define ML_TWOSIDED 0x0004
+#define ML_DONTPEGTOP 0x0008
+#define ML_DONTPEGBOTTOM 0x0010
+#define ML_SECRET 0x0020 // don't map as two sided: IT'S A SECRET!
+#define ML_SOUNDBLOCK 0x0040 // don't let sound cross two of these
+#define ML_DONTDRAW 0x0080 // don't draw on the automap
+#define ML_MAPPED 0x0100 // set if already drawn in automap
+#define ML_REPEAT_SPECIAL 0x0200 // special is repeatable
+#define ML_SPAC_SHIFT 10
+#define ML_SPAC_MASK 0x1c00
+#define GET_SPAC(flags) ((flags&ML_SPAC_MASK)>>ML_SPAC_SHIFT)
+
+// Special activation types
+#define SPAC_CROSS 0 // when player crosses line
+#define SPAC_USE 1 // when player uses line
+#define SPAC_MCROSS 2 // when monster crosses line
+#define SPAC_IMPACT 3 // when projectile hits line
+#define SPAC_PUSH 4 // when player/monster pushes line
+#define SPAC_PCROSS 5 // when projectile crosses line
+
+typedef struct
+{
+ short floorheight;
+ short ceilingheight;
+ char floorpic[8];
+ char ceilingpic[8];
+ short lightlevel;
+ short special;
+ short tag;
+} PACKEDATTR mapsector_t;
+
+typedef struct
+{
+ short numsegs;
+ short firstseg; // segs are stored sequentially
+} PACKEDATTR mapsubsector_t;
+
+typedef struct
+{
+ short v1;
+ short v2;
+ short angle;
+ short linedef;
+ short side;
+ short offset;
+} PACKEDATTR mapseg_t;
+
+#define NF_SUBSECTOR 0x8000
+typedef struct
+{
+ short x, y, dx, dy; // partition line
+ short bbox[2][4]; // bounding box for each child
+ unsigned short children[2]; // if NF_SUBSECTOR its a subsector
+} PACKEDATTR mapnode_t;
+
+typedef struct
+{
+ short tid;
+ short x;
+ short y;
+ short height;
+ short angle;
+ short type;
+ short options;
+ byte special;
+ byte arg1;
+ byte arg2;
+ byte arg3;
+ byte arg4;
+ byte arg5;
+} PACKEDATTR mapthing_t;
+
+#define MTF_EASY 1
+#define MTF_NORMAL 2
+#define MTF_HARD 4
+#define MTF_AMBUSH 8
+#define MTF_DORMANT 16
+#define MTF_FIGHTER 32
+#define MTF_CLERIC 64
+#define MTF_MAGE 128
+#define MTF_GSINGLE 256
+#define MTF_GCOOP 512
+#define MTF_GDEATHMATCH 1024
+
+//--------------------------------------------------------------------------
+//
+// Texture definition
+//
+//--------------------------------------------------------------------------
+
+typedef struct
+{
+ short originx;
+ short originy;
+ short patch;
+ short stepdir;
+ short colormap;
+} PACKEDATTR mappatch_t;
+
+typedef struct
+{
+ char name[8];
+ boolean masked;
+ short width;
+ short height;
+ int obsolete;
+ short patchcount;
+ mappatch_t patches[1];
+} PACKEDATTR maptexture_t;
+
+#endif // __XDDEFS__
diff --git a/src/i_cdmus.c b/src/i_cdmus.c
new file mode 100644
index 00000000..94ac47c6
--- /dev/null
+++ b/src/i_cdmus.c
@@ -0,0 +1,182 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// SDL implementation of the Hexen CD interface.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+
+#include "SDL.h"
+#include "SDL_cdrom.h"
+
+#include "doomtype.h"
+
+#include "i_cdmus.h"
+
+static SDL_CD *cd_handle = NULL;
+
+int cd_Error;
+
+int I_CDMusInit(void)
+{
+ int drive_num = 0;
+
+ // TODO: config variable to control CDROM to use.
+
+ cd_handle = SDL_CDOpen(drive_num);
+
+ if (cd_handle == NULL)
+ {
+ fprintf(stderr, "I_CDMusInit: Failed to open CD-ROM drive.\n");
+ cd_Error = 1;
+ return -1;
+ }
+
+ if (!CD_INDRIVE(cd_handle->status))
+ {
+ fprintf(stderr, "I_CDMusInit: '%s': no CD in drive.\n",
+ SDL_CDName(drive_num));
+ cd_Error = 1;
+ return -1;
+ }
+
+ cd_Error = 0;
+
+ return 0;
+}
+
+int I_CDMusPlay(int track)
+{
+ int result;
+
+ if (cd_handle == NULL)
+ {
+ cd_Error = 1;
+ return -1;
+ }
+
+ // Play one track
+ // Track is indexed from 1.
+
+ result = SDL_CDPlayTracks(cd_handle, track - 1, 0, 1, 0);
+
+ cd_Error = 0;
+ return result;
+}
+
+int I_CDMusStop(void)
+{
+ int result;
+
+ result = SDL_CDStop(cd_handle);
+
+ cd_Error = 0;
+
+ return result;
+}
+
+int I_CDMusResume(void)
+{
+ int result;
+
+ result = SDL_CDResume(cd_handle);
+
+ cd_Error = 0;
+
+ return result;
+}
+
+int I_CDMusSetVolume(int volume)
+{
+ /* Not supported yet */
+
+ cd_Error = 0;
+
+ return 0;
+}
+
+int I_CDMusFirstTrack(void)
+{
+ int i;
+
+ if (cd_handle == NULL)
+ {
+ cd_Error = 1;
+ return -1;
+ }
+
+ // Find the first audio track.
+
+ for (i=0; i<cd_handle->numtracks; ++i)
+ {
+ if (cd_handle->track[i].type == SDL_AUDIO_TRACK)
+ {
+ cd_Error = 0;
+
+ // Tracks are indexed from 1.
+ return i + 1;
+ }
+ }
+
+ /* Don't know? */
+
+ cd_Error = 1;
+
+ return -1;
+}
+
+int I_CDMusLastTrack(void)
+{
+ if (cd_handle == NULL)
+ {
+ cd_Error = 1;
+ return -1;
+ }
+
+ cd_Error = 0;
+
+ return cd_handle->numtracks;
+}
+
+int I_CDMusTrackLength(int track_num)
+{
+ SDL_CDtrack *track;
+
+ if (cd_handle == NULL || track_num < 1 || track_num > cd_handle->numtracks)
+ {
+ cd_Error = 1;
+ return -1;
+ }
+
+ // Track number is indexed from 1.
+
+ track = &cd_handle->track[track_num - 1];
+
+ // Round up to the next second
+
+ cd_Error = 0;
+
+ return (track->length + CD_FPS - 1) / CD_FPS;
+}
+
diff --git a/src/i_cdmus.h b/src/i_cdmus.h
new file mode 100644
index 00000000..3915a986
--- /dev/null
+++ b/src/i_cdmus.h
@@ -0,0 +1,48 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+// i_cdmus.h
+
+#ifndef __ICDMUS__
+#define __ICDMUS__
+
+#define CDERR_NOTINSTALLED 10 // MSCDEX not installed
+#define CDERR_NOAUDIOSUPPORT 11 // CD-ROM Doesn't support audio
+#define CDERR_NOAUDIOTRACKS 12 // Current CD has no audio tracks
+#define CDERR_BADDRIVE 20 // Bad drive number
+#define CDERR_BADTRACK 21 // Bad track number
+#define CDERR_IOCTLBUFFMEM 22 // Not enough low memory for IOCTL
+#define CDERR_DEVREQBASE 100 // DevReq errors
+
+extern int cd_Error;
+
+int I_CDMusInit(void);
+int I_CDMusPlay(int track);
+int I_CDMusStop(void);
+int I_CDMusResume(void);
+int I_CDMusSetVolume(int volume);
+int I_CDMusFirstTrack(void);
+int I_CDMusLastTrack(void);
+int I_CDMusTrackLength(int track);
+
+#endif
diff --git a/src/i_endoom.c b/src/i_endoom.c
new file mode 100644
index 00000000..09c2d2d2
--- /dev/null
+++ b/src/i_endoom.c
@@ -0,0 +1,82 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005-8 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Exit text-mode ENDOOM screen.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <string.h>
+
+#include "doomtype.h"
+#include "i_video.h"
+
+#include "txt_main.h"
+
+#define ENDOOM_W 80
+#define ENDOOM_H 25
+
+//
+// Displays the text mode ending screen after the game quits
+//
+
+void I_Endoom(byte *endoom_data)
+{
+ unsigned char *screendata;
+ int y;
+ int indent;
+
+ // Set up text mode screen
+
+ TXT_Init();
+
+ // Write the data to the screen memory
+
+ screendata = TXT_GetScreenData();
+
+ indent = (ENDOOM_W - TXT_SCREEN_W) / 2;
+
+ for (y=0; y<TXT_SCREEN_H; ++y)
+ {
+ memcpy(screendata + (y * TXT_SCREEN_W * 2),
+ endoom_data + (y * ENDOOM_W + indent) * 2,
+ TXT_SCREEN_W * 2);
+ }
+
+ // Wait for a keypress
+
+ while (true)
+ {
+ TXT_UpdateScreen();
+
+ if (TXT_GetChar() > 0)
+ {
+ break;
+ }
+
+ TXT_Sleep(0);
+ }
+
+ // Shut down text mode screen
+
+ TXT_Shutdown();
+}
+
diff --git a/src/i_endoom.h b/src/i_endoom.h
new file mode 100644
index 00000000..b4fa34dd
--- /dev/null
+++ b/src/i_endoom.h
@@ -0,0 +1,37 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Exit text-mode ENDOOM screen.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __I_ENDOOM__
+#define __I_ENDOOM__
+
+// Display the Endoom screen on shutdown. Pass a pointer to the
+// ENDOOM lump.
+
+void I_Endoom(byte *data);
+
+#endif
+
diff --git a/src/i_joystick.c b/src/i_joystick.c
index d48e8409..7767c19d 100644
--- a/src/i_joystick.c
+++ b/src/i_joystick.c
@@ -31,12 +31,12 @@
#include <stdio.h>
#include <string.h>
-#include "doomdef.h"
#include "doomtype.h"
#include "d_event.h"
-#include "d_main.h"
#include "i_joystick.h"
+#include "m_config.h"
+
// When an axis is within the dead zone, it is set to zero.
// This is 5% of the full range:
@@ -48,23 +48,23 @@ static SDL_Joystick *joystick = NULL;
// Standard default.cfg Joystick enable/disable
-extern int usejoystick;
+static int usejoystick = 0;
// Joystick to use, as an SDL joystick index:
-int joystick_index = -1;
+static int joystick_index = -1;
// Which joystick axis to use for horizontal movement, and whether to
// invert the direction:
-int joystick_x_axis = 0;
-int joystick_x_invert = 0;
+static int joystick_x_axis = 0;
+static int joystick_x_invert = 0;
// Which joystick axis to use for vertical movement, and whether to
// invert the direction:
-int joystick_y_axis = 1;
-int joystick_y_invert = 0;
+static int joystick_y_axis = 1;
+static int joystick_y_invert = 0;
void I_InitJoystick(void)
{
@@ -186,3 +186,13 @@ void I_UpdateJoystick(void)
}
}
+void I_BindJoystickVariables(void)
+{
+ M_BindVariable("use_joystick", &usejoystick);
+ M_BindVariable("joystick_index", &joystick_index);
+ M_BindVariable("joystick_x_axis", &joystick_x_axis);
+ M_BindVariable("joystick_y_axis", &joystick_y_axis);
+ M_BindVariable("joystick_x_invert", &joystick_x_invert);
+ M_BindVariable("joystick_y_invert", &joystick_y_invert);
+}
+
diff --git a/src/i_joystick.h b/src/i_joystick.h
index bedf5437..98cd218b 100644
--- a/src/i_joystick.h
+++ b/src/i_joystick.h
@@ -27,15 +27,11 @@
#ifndef __I_JOYSTICK__
#define __I_JOYSTICK__
-extern int joystick_index;
-extern int joystick_x_axis;
-extern int joystick_x_invert;
-extern int joystick_y_axis;
-extern int joystick_y_invert;
-
void I_InitJoystick(void);
void I_ShutdownJoystick(void);
void I_UpdateJoystick(void);
+void I_BindJoystickVariables(void);
+
#endif /* #ifndef __I_JOYSTICK__ */
diff --git a/src/i_main.c b/src/i_main.c
index cdfb531a..fdfa3cbc 100644
--- a/src/i_main.c
+++ b/src/i_main.c
@@ -24,15 +24,23 @@
//
//-----------------------------------------------------------------------------
-
#include "config.h"
+#include <stdio.h>
+
#include "SDL.h"
-#include "doomdef.h"
+#include "doomtype.h"
#include "i_system.h"
#include "m_argv.h"
-#include "d_main.h"
+
+//
+// D_DoomMain()
+// Not a globally visible function, just included for source reference,
+// calls all startup code, parses command line options.
+//
+
+void D_DoomMain (void);
#if defined(_WIN32_WCE)
@@ -71,7 +79,6 @@ static void LockCPUAffinity(void)
fprintf(stderr, "Failed to load kernel32.dll\n");
return;
}
-
// Find the SetProcessAffinityMask function.
SetAffinity = (SetAffinityFunc)GetProcAddress(kernel32_dll, "SetProcessAffinityMask");
@@ -147,6 +154,8 @@ int main(int argc, char **argv)
LockCPUAffinity();
+ M_FindResponseFile();
+
// start doom
D_DoomMain ();
diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c
index d2116ddb..3d309715 100644
--- a/src/i_oplmusic.c
+++ b/src/i_oplmusic.c
@@ -29,14 +29,13 @@
#include <stdlib.h>
#include <string.h>
-#include "doomdef.h"
#include "memio.h"
#include "mus2mid.h"
#include "deh_main.h"
+#include "i_sound.h"
#include "i_swap.h"
#include "m_misc.h"
-#include "s_sound.h"
#include "w_wad.h"
#include "z_zone.h"
@@ -1209,7 +1208,7 @@ static void StartTrack(midi_file_t *file, unsigned int track_num)
// Start playing a mid
-static void I_OPL_PlaySong(void *handle, int looping)
+static void I_OPL_PlaySong(void *handle, boolean looping)
{
midi_file_t *file;
unsigned int i;
diff --git a/src/i_pcsound.c b/src/i_pcsound.c
index dce7f2b6..907aeb54 100644
--- a/src/i_pcsound.c
+++ b/src/i_pcsound.c
@@ -24,13 +24,12 @@
//-----------------------------------------------------------------------------
#include "SDL.h"
+#include <string.h>
-#include "doomdef.h"
#include "doomtype.h"
-#include "deh_main.h"
-#include "s_sound.h"
-#include "sounds.h"
+#include "deh_str.h"
+#include "i_sound.h"
#include "w_wad.h"
#include "z_zone.h"
@@ -40,6 +39,7 @@
static boolean pcs_initialized = false;
static SDL_mutex *sound_lock;
+static boolean use_sfx_prefix;
static uint8_t *current_sound_lump = NULL;
static uint8_t *current_sound_pos = NULL;
@@ -103,7 +103,7 @@ static void PCSCallbackFunc(int *duration, int *freq)
SDL_UnlockMutex(sound_lock);
}
-static boolean CachePCSLump(int sound_id)
+static boolean CachePCSLump(sfxinfo_t *sfxinfo)
{
int lumplen;
int headerlen;
@@ -118,8 +118,8 @@ static boolean CachePCSLump(int sound_id)
// Load from WAD
- current_sound_lump = W_CacheLumpNum(S_sfx[sound_id].lumpnum, PU_STATIC);
- lumplen = W_LumpLength(S_sfx[sound_id].lumpnum);
+ current_sound_lump = W_CacheLumpNum(sfxinfo->lumpnum, PU_STATIC);
+ lumplen = W_LumpLength(sfxinfo->lumpnum);
// Read header
@@ -139,12 +139,39 @@ static boolean CachePCSLump(int sound_id)
current_sound_remaining = headerlen;
current_sound_pos = current_sound_lump + 4;
- current_sound_lump_num = S_sfx[sound_id].lumpnum;
+ current_sound_lump_num = sfxinfo->lumpnum;
return true;
}
-static int I_PCS_StartSound(int id,
+// These Doom PC speaker sounds are not played - this can be seen in the
+// Heretic source code, where there are remnants of this left over
+// from Doom.
+
+static boolean IsDisabledSound(sfxinfo_t *sfxinfo)
+{
+ int i;
+ const char *disabled_sounds[] = {
+ "posact",
+ "bgact",
+ "dmact",
+ "dmpain",
+ "popain",
+ "sawidl",
+ };
+
+ for (i=0; i<arrlen(disabled_sounds); ++i)
+ {
+ if (!strcmp(sfxinfo->name, disabled_sounds[i]))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static int I_PCS_StartSound(sfxinfo_t *sfxinfo,
int channel,
int vol,
int sep)
@@ -156,12 +183,7 @@ static int I_PCS_StartSound(int id,
return -1;
}
- // These PC speaker sounds are not played - this can be seen in the
- // Heretic source code, where there are remnants of this left over
- // from Doom.
-
- if (id == sfx_posact || id == sfx_bgact || id == sfx_dmact
- || id == sfx_dmpain || id == sfx_popain || id == sfx_sawidl)
+ if (IsDisabledSound(sfxinfo))
{
return -1;
}
@@ -171,7 +193,7 @@ static int I_PCS_StartSound(int id,
return -1;
}
- result = CachePCSLump(id);
+ result = CachePCSLump(sfxinfo);
if (result)
{
@@ -221,8 +243,15 @@ static int I_PCS_GetSfxLumpNum(sfxinfo_t* sfx)
{
char namebuf[9];
- sprintf(namebuf, "dp%s", DEH_String(sfx->name));
-
+ if (use_sfx_prefix)
+ {
+ sprintf(namebuf, "dp%s", DEH_String(sfx->name));
+ }
+ else
+ {
+ strcpy(namebuf, DEH_String(sfx->name));
+ }
+
return W_GetNumForName(namebuf);
}
@@ -242,8 +271,10 @@ static boolean I_PCS_SoundIsPlaying(int handle)
return current_sound_lump != NULL && current_sound_remaining > 0;
}
-static boolean I_PCS_InitSound(void)
+static boolean I_PCS_InitSound(boolean _use_sfx_prefix)
{
+ use_sfx_prefix = _use_sfx_prefix;
+
// Use the sample rate from the configuration file
PCSound_SetSampleRate(snd_samplerate);
diff --git a/src/i_scale.c b/src/i_scale.c
index 8cecb1f8..6d03d708 100644
--- a/src/i_scale.c
+++ b/src/i_scale.c
@@ -26,7 +26,10 @@
//
//-----------------------------------------------------------------------------
-#include "doomdef.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
#include "doomtype.h"
#include "i_video.h"
@@ -37,7 +40,7 @@
#define inline __inline
#endif
-// Should be screens[0]
+// Should be I_VideoBuffer
static byte *src_buffer;
diff --git a/src/i_sdlmusic.c b/src/i_sdlmusic.c
index 4aa89add..79755890 100644
--- a/src/i_sdlmusic.c
+++ b/src/i_sdlmusic.c
@@ -27,16 +27,18 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "SDL.h"
#include "SDL_mixer.h"
-#include "doomdef.h"
+#include "doomtype.h"
#include "memio.h"
#include "mus2mid.h"
-#include "deh_main.h"
+#include "deh_str.h"
+#include "gusconf.h"
+#include "i_sound.h"
#include "m_misc.h"
-#include "s_sound.h"
#include "w_wad.h"
#include "z_zone.h"
@@ -52,10 +54,94 @@ static boolean sdl_was_initialized = false;
static boolean musicpaused = false;
static int current_music_volume;
+char *timidity_cfg_path = "";
+
+static char *temp_timidity_cfg = NULL;
+
+// If the temp_timidity_cfg config variable is set, generate a "wrapper"
+// config file for Timidity to point to the actual config file. This
+// is needed to inject a "dir" command so that the patches are read
+// relative to the actual config file.
+
+static boolean WriteWrapperTimidityConfig(char *write_path)
+{
+ char *p, *path;
+ FILE *fstream;
+
+ if (!strcmp(timidity_cfg_path, ""))
+ {
+ return false;
+ }
+
+ fstream = fopen(write_path, "w");
+
+ if (fstream == NULL)
+ {
+ return false;
+ }
+
+ p = strrchr(timidity_cfg_path, DIR_SEPARATOR);
+ if (p != NULL)
+ {
+ path = strdup(timidity_cfg_path);
+ path[p - timidity_cfg_path] = '\0';
+ fprintf(fstream, "dir %s\n", path);
+ free(path);
+ }
+
+ fprintf(fstream, "source %s\n", timidity_cfg_path);
+ fclose(fstream);
+
+ return true;
+}
+
+void I_InitTimidityConfig(void)
+{
+ char *env_string;
+ boolean success;
+
+ temp_timidity_cfg = M_TempFile("timidity.cfg");
+
+ if (snd_musicdevice == SNDDEVICE_GUS)
+ {
+ success = GUS_WriteConfig(temp_timidity_cfg);
+ }
+ else
+ {
+ success = WriteWrapperTimidityConfig(temp_timidity_cfg);
+ }
+
+ // Set the TIMIDITY_CFG environment variable to point to the temporary
+ // config file.
+
+ if (success)
+ {
+ env_string = malloc(strlen(temp_timidity_cfg) + 15);
+ sprintf(env_string, "TIMIDITY_CFG=%s", temp_timidity_cfg);
+ putenv(env_string);
+ }
+ else
+ {
+ Z_Free(temp_timidity_cfg);
+ temp_timidity_cfg = NULL;
+ }
+}
+
+// Remove the temporary config file generated by I_InitTimidityConfig().
+
+static void RemoveTimidityConfig(void)
+{
+ if (temp_timidity_cfg != NULL)
+ {
+ remove(temp_timidity_cfg);
+ Z_Free(temp_timidity_cfg);
+ }
+}
+
// Shutdown music
static void I_SDL_ShutdownMusic(void)
-{
+{
if (music_initialized)
{
Mix_HaltMusic();
@@ -106,29 +192,37 @@ static boolean I_SDL_InitMusic(void)
// If SDL_mixer is not initialized, we have to initialize it
// and have the responsibility to shut it down later on.
- if (!SDLIsInitialized())
+ if (SDLIsInitialized())
+ {
+ music_initialized = true;
+ }
+ else
{
if (SDL_Init(SDL_INIT_AUDIO) < 0)
{
fprintf(stderr, "Unable to set up sound.\n");
- return false;
}
-
- if (Mix_OpenAudio(snd_samplerate, AUDIO_S16SYS, 2, 1024) < 0)
+ else if (Mix_OpenAudio(snd_samplerate, AUDIO_S16SYS, 2, 1024) < 0)
{
- fprintf(stderr, "Error initializing SDL_mixer: %s\n", Mix_GetError());
+ fprintf(stderr, "Error initializing SDL_mixer: %s\n",
+ Mix_GetError());
SDL_QuitSubSystem(SDL_INIT_AUDIO);
- return false;
}
+ else
+ {
+ SDL_PauseAudio(0);
- SDL_PauseAudio(0);
-
- sdl_was_initialized = true;
+ sdl_was_initialized = true;
+ music_initialized = true;
+ }
}
- music_initialized = true;
+ // Once initialization is complete, the temporary Timidity config
+ // file can be removed.
- return true;
+ RemoveTimidityConfig();
+
+ return music_initialized;
}
//
@@ -164,7 +258,7 @@ static void I_SDL_SetMusicVolume(int volume)
// Start playing a mid
-static void I_SDL_PlaySong(void *handle, int looping)
+static void I_SDL_PlaySong(void *handle, boolean looping)
{
Mix_Music *music = (Mix_Music *) handle;
int loops;
diff --git a/src/i_sdlsound.c b/src/i_sdlsound.c
index 14a5147f..4169a921 100644
--- a/src/i_sdlsound.c
+++ b/src/i_sdlsound.c
@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
//
// Copyright(C) 1993-1996 Id Software, Inc.
-// Copyright(C) 2005 Simon Howard
+// Copyright(C) 2005-8 Simon Howard
// Copyright(C) 2008 David Flater
//
// This program is free software; you can redistribute it and/or
@@ -29,8 +29,8 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <assert.h>
-#include <math.h>
#include "SDL.h"
#include "SDL_mixer.h"
@@ -38,69 +38,264 @@
#include <samplerate.h>
#endif
-#include "deh_main.h"
+#include "deh_str.h"
+#include "i_sound.h"
#include "i_system.h"
#include "i_swap.h"
-#include "s_sound.h"
#include "m_argv.h"
#include "w_wad.h"
#include "z_zone.h"
-#include "doomdef.h"
+#include "doomtype.h"
#define LOW_PASS_FILTER
//#define DEBUG_DUMP_WAVS
#define MAX_SOUND_SLICE_TIME 70 /* ms */
#define NUM_CHANNELS 16
+typedef struct allocated_sound_s allocated_sound_t;
+
+struct allocated_sound_s
+{
+ sfxinfo_t *sfxinfo;
+ Mix_Chunk chunk;
+ int use_count;
+ allocated_sound_t *prev, *next;
+};
+
static boolean setpanning_workaround = false;
static boolean sound_initialized = false;
-static Mix_Chunk sound_chunks[NUMSFX];
-static int channels_playing[NUM_CHANNELS];
+static sfxinfo_t *channels_playing[NUM_CHANNELS];
static int mixer_freq;
static Uint16 mixer_format;
static int mixer_channels;
+static boolean use_sfx_prefix;
+static boolean (*ExpandSoundData)(sfxinfo_t *sfxinfo,
+ byte *data,
+ int samplerate,
+ int length) = NULL;
+
+// Doubly-linked list of allocated sounds.
+// When a sound is played, it is moved to the head, so that the oldest
+// sounds not used recently are at the tail.
+
+static allocated_sound_t *allocated_sounds_head = NULL;
+static allocated_sound_t *allocated_sounds_tail = NULL;
+static int allocated_sounds_size = 0;
int use_libsamplerate = 0;
-// When a sound stops, check if it is still playing. If it is not,
-// we can mark the sound data as CACHE to be freed back for other
-// means.
+// Hook a sound into the linked list at the head.
-static void ReleaseSoundOnChannel(int channel)
+static void AllocatedSoundLink(allocated_sound_t *snd)
{
- int i;
- int id = channels_playing[channel];
+ snd->prev = NULL;
+
+ snd->next = allocated_sounds_head;
+ allocated_sounds_head = snd;
- if (!id)
+ if (allocated_sounds_tail == NULL)
{
- return;
+ allocated_sounds_tail = snd;
+ }
+ else
+ {
+ snd->next->prev = snd;
}
+}
- channels_playing[channel] = sfx_None;
-
-#ifdef HAVE_LIBSAMPLERATE
- // Don't allow precached sounds to be swapped out.
- if (use_libsamplerate)
+// Unlink a sound from the linked list.
+
+static void AllocatedSoundUnlink(allocated_sound_t *snd)
+{
+ if (snd->prev == NULL)
+ {
+ allocated_sounds_head = snd->next;
+ }
+ else
+ {
+ snd->prev->next = snd->next;
+ }
+
+ if (snd->next == NULL)
+ {
+ allocated_sounds_tail = snd->prev;
+ }
+ else
+ {
+ snd->next->prev = snd->prev;
+ }
+}
+
+static void FreeAllocatedSound(allocated_sound_t *snd)
+{
+ // Unlink from linked list.
+
+ AllocatedSoundUnlink(snd);
+
+ // Unlink from higher-level code.
+
+ snd->sfxinfo->driver_data = NULL;
+
+ // Keep track of the amount of allocated sound data:
+
+ allocated_sounds_size -= snd->chunk.alen;
+
+ free(snd);
+}
+
+// Search from the tail backwards along the allocated sounds list, find
+// and free a sound that is not in use, to free up memory. Return true
+// for success.
+
+static boolean FindAndFreeSound(void)
+{
+ allocated_sound_t *snd;
+
+ snd = allocated_sounds_tail;
+
+ while (snd != NULL)
+ {
+ if (snd->use_count == 0)
+ {
+ FreeAllocatedSound(snd);
+ return true;
+ }
+
+ snd = snd->prev;
+ }
+
+ // No available sounds to free...
+
+ return false;
+}
+
+// Enforce SFX cache size limit. We are just about to allocate "len"
+// bytes on the heap for a new sound effect, so free up some space
+// so that we keep allocated_sounds_size < snd_cachesize
+
+static void ReserveCacheSpace(size_t len)
+{
+ if (snd_cachesize <= 0)
+ {
return;
-#endif
+ }
- for (i=0; i<NUM_CHANNELS; ++i)
+ // Keep freeing sound effects that aren't currently being played,
+ // until there is enough space for the new sound.
+
+ while (allocated_sounds_size + len > snd_cachesize)
{
- // Playing on this channel? if so, don't release.
+ // Free a sound. If there is nothing more to free, stop.
- if (channels_playing[i] == id)
- return;
+ if (!FindAndFreeSound())
+ {
+ break;
+ }
+ }
+}
+
+// Allocate a block for a new sound effect.
+
+static Mix_Chunk *AllocateSound(sfxinfo_t *sfxinfo, size_t len)
+{
+ allocated_sound_t *snd;
+
+ // Keep allocated sounds within the cache size.
+
+ ReserveCacheSpace(len);
+
+ // Allocate the sound structure and data. The data will immediately
+ // follow the structure, which acts as a header.
+
+ do
+ {
+ snd = malloc(sizeof(allocated_sound_t) + len);
+
+ // Out of memory? Try to free an old sound, then loop round
+ // and try again.
+
+ if (snd == NULL && !FindAndFreeSound())
+ {
+ return NULL;
+ }
+
+ } while (snd == NULL);
+
+ // Skip past the chunk structure for the audio buffer
+
+ snd->chunk.abuf = (byte *) (snd + 1);
+ snd->chunk.alen = len;
+ snd->chunk.allocated = 1;
+ snd->chunk.volume = MIX_MAX_VOLUME;
+
+ snd->sfxinfo = sfxinfo;
+ snd->use_count = 0;
+
+ // driver_data pointer points to the allocated_sound structure.
+
+ sfxinfo->driver_data = snd;
+
+ // Keep track of how much memory all these cached sounds are using...
+
+ allocated_sounds_size += len;
+
+ AllocatedSoundLink(snd);
+
+ return &snd->chunk;
+}
+
+// Lock a sound, to indicate that it may not be freed.
+
+static void LockAllocatedSound(allocated_sound_t *snd)
+{
+ // Increase use count, to stop the sound being freed.
+
+ ++snd->use_count;
+
+ //printf("++ %s: Use count=%i\n", snd->sfxinfo->name, snd->use_count);
+
+ // When we use a sound, re-link it into the list at the head, so
+ // that the oldest sounds fall to the end of the list for freeing.
+
+ AllocatedSoundUnlink(snd);
+ AllocatedSoundLink(snd);
+}
+
+// Unlock a sound to indicate that it may now be freed.
+
+static void UnlockAllocatedSound(allocated_sound_t *snd)
+{
+ if (snd->use_count <= 0)
+ {
+ I_Error("Sound effect released more times than it was locked...");
}
- // Not used on any channel, and can be safely released
-
- Z_ChangeTag(sound_chunks[id].abuf, PU_CACHE);
+ --snd->use_count;
+
+ //printf("-- %s: Use count=%i\n", snd->sfxinfo->name, snd->use_count);
}
+// When a sound stops, check if it is still playing. If it is not,
+// we can mark the sound data as CACHE to be freed back for other
+// means.
+
+static void ReleaseSoundOnChannel(int channel)
+{
+ sfxinfo_t *sfxinfo = channels_playing[channel];
+
+ if (sfxinfo == NULL)
+ {
+ return;
+ }
+
+ channels_playing[channel] = NULL;
+
+ UnlockAllocatedSound(sfxinfo->driver_data);
+}
#ifdef HAVE_LIBSAMPLERATE
@@ -131,6 +326,122 @@ static int SRC_ConversionMode(void)
}
}
+// libsamplerate-based generic sound expansion function for any sample rate
+// unsigned 8 bits --> signed 16 bits
+// mono --> stereo
+// samplerate --> mixer_freq
+// Returns number of clipped samples.
+// DWF 2008-02-10 with cleanups by Simon Howard.
+
+static boolean ExpandSoundData_SRC(sfxinfo_t *sfxinfo,
+ byte *data,
+ int samplerate,
+ int length)
+{
+ SRC_DATA src_data;
+ uint32_t i, abuf_index=0, clipped=0;
+ uint32_t alen;
+ int retn;
+ int16_t *expanded;
+ Mix_Chunk *chunk;
+
+ src_data.input_frames = length;
+ src_data.data_in = malloc(length * sizeof(float));
+ src_data.src_ratio = (double)mixer_freq / samplerate;
+
+ // We include some extra space here in case of rounding-up.
+ src_data.output_frames = src_data.src_ratio * length + (mixer_freq / 4);
+ src_data.data_out = malloc(src_data.output_frames * sizeof(float));
+
+ assert(src_data.data_in != NULL && src_data.data_out != NULL);
+
+ // Convert input data to floats
+
+ for (i=0; i<length; ++i)
+ {
+ // Unclear whether 128 should be interpreted as "zero" or whether a
+ // symmetrical range should be assumed. The following assumes a
+ // symmetrical range.
+ src_data.data_in[i] = data[i] / 127.5 - 1;
+ }
+
+ // Do the sound conversion
+
+ retn = src_simple(&src_data, SRC_ConversionMode(), 1);
+ assert(retn == 0);
+
+ // Allocate the new chunk.
+
+ alen = src_data.output_frames_gen * 4;
+
+ chunk = AllocateSound(sfxinfo, src_data.output_frames_gen * 4);
+
+ if (chunk == NULL)
+ {
+ return false;
+ }
+
+ expanded = (int16_t *) chunk->abuf;
+
+ // Convert the result back into 16-bit integers.
+
+ for (i=0; i<src_data.output_frames_gen; ++i)
+ {
+ // libsamplerate does not limit itself to the -1.0 .. 1.0 range on
+ // output, so a multiplier less than INT16_MAX (32767) is required
+ // to avoid overflows or clipping. However, the smaller the
+ // multiplier, the quieter the sound effects get, and the more you
+ // have to turn down the music to keep it in balance.
+
+ // 22265 is the largest multiplier that can be used to resample all
+ // of the Vanilla DOOM sound effects to 48 kHz without clipping
+ // using SRC_SINC_BEST_QUALITY. It is close enough (only slightly
+ // too conservative) for SRC_SINC_MEDIUM_QUALITY and
+ // SRC_SINC_FASTEST. PWADs with interestingly different sound
+ // effects or target rates other than 48 kHz might still result in
+ // clipping--I don't know if there's a limit to it.
+
+ // As the number of clipped samples increases, the signal is
+ // gradually overtaken by noise, with the loudest parts going first.
+ // However, a moderate amount of clipping is often tolerated in the
+ // quest for the loudest possible sound overall. The results of
+ // using INT16_MAX as the multiplier are not all that bad, but
+ // artifacts are noticeable during the loudest parts.
+
+ float cvtval_f = src_data.data_out[i] * 22265;
+ int32_t cvtval_i = cvtval_f + (cvtval_f < 0 ? -0.5 : 0.5);
+
+ // Asymmetrical sound worries me, so we won't use -32768.
+ if (cvtval_i < -INT16_MAX)
+ {
+ cvtval_i = -INT16_MAX;
+ ++clipped;
+ }
+ else if (cvtval_i > INT16_MAX)
+ {
+ cvtval_i = INT16_MAX;
+ ++clipped;
+ }
+
+ // Left and right channels
+
+ expanded[abuf_index++] = cvtval_i;
+ expanded[abuf_index++] = cvtval_i;
+ }
+
+ free(src_data.data_in);
+ free(src_data.data_out);
+
+ if (clipped > 0)
+ {
+ fprintf(stderr, "Sound '%s': clipped %u samples (%0.2f %%)\n",
+ sfxinfo->name, clipped,
+ 400.0 * clipped / chunk->alen);
+ }
+
+ return true;
+}
+
#endif
static boolean ConvertibleRatio(int freq1, int freq2)
@@ -213,13 +524,15 @@ static void WriteWAV(char *filename, byte *data,
#endif
// Generic sound expansion function for any sample rate.
+// Returns number of clipped samples (always 0).
-static void ExpandSoundData_SDL(byte *data,
- int samplerate,
- uint32_t length,
- Mix_Chunk *destination)
+static boolean ExpandSoundData_SDL(sfxinfo_t *sfxinfo,
+ byte *data,
+ int samplerate,
+ int length)
{
SDL_AudioCVT convertor;
+ Mix_Chunk *chunk;
uint32_t expanded_length;
// Calculate the length of the expanded version of the sample.
@@ -229,9 +542,15 @@ static void ExpandSoundData_SDL(byte *data,
// Double up twice: 8 -> 16 bit and mono -> stereo
expanded_length *= 4;
- destination->alen = expanded_length;
- destination->abuf
- = Z_Malloc(expanded_length, PU_STATIC, &destination->abuf);
+
+ // Allocate a chunk in which to expand the sound
+
+ chunk = AllocateSound(sfxinfo, expanded_length);
+
+ if (chunk == NULL)
+ {
+ return false;
+ }
// If we can, use the standard / optimized SDL conversion routines.
@@ -241,7 +560,7 @@ static void ExpandSoundData_SDL(byte *data,
AUDIO_U8, 1, samplerate,
mixer_format, mixer_channels, mixer_freq))
{
- convertor.buf = destination->abuf;
+ convertor.buf = chunk->abuf;
convertor.len = length;
memcpy(convertor.buf, data, length);
@@ -249,7 +568,7 @@ static void ExpandSoundData_SDL(byte *data,
}
else
{
- Sint16 *expanded = (Sint16 *) destination->abuf;
+ Sint16 *expanded = (Sint16 *) chunk->abuf;
int expanded_length;
int expand_ratio;
int i;
@@ -310,54 +629,44 @@ static void ExpandSoundData_SDL(byte *data,
}
#endif /* #ifdef LOW_PASS_FILTER */
}
+
+ return true;
}
+// Load and convert a sound effect
+// Returns true if successful
-// Load and validate a sound effect lump.
-// Preconditions:
-// S_sfx[sound].lumpnum has been set
-// Postconditions if sound is valid:
-// returns true
-// starred parameters are set, with data_ref pointing to start of sound
-// caller is responsible for releasing the identified lump
-// Postconditions if sound is invalid:
-// returns false
-// starred parameters are garbage
-// lump already released
-
-static boolean LoadSoundLump(int sound,
- int *lumpnum,
- int *samplerate,
- uint32_t *length,
- byte **data_ref)
+static boolean CacheSFX(sfxinfo_t *sfxinfo)
{
- int lumplen;
+ int lumpnum;
+ unsigned int lumplen;
+ int samplerate;
+ unsigned int length;
byte *data;
- // Load the sound
+ // need to load the sound
- *lumpnum = S_sfx[sound].lumpnum;
- *data_ref = W_CacheLumpNum(*lumpnum, PU_STATIC);
- lumplen = W_LumpLength(*lumpnum);
- data = *data_ref;
+ lumpnum = sfxinfo->lumpnum;
+ data = W_CacheLumpNum(lumpnum, PU_STATIC);
+ lumplen = W_LumpLength(lumpnum);
- // Ensure this is a valid sound
+ // Check the header, and ensure this is a valid sound
- if (lumplen < 8 || data[0] != 0x03 || data[1] != 0x00)
+ if (lumplen < 8
+ || data[0] != 0x03 || data[1] != 0x00)
{
- // Invalid sound
- W_ReleaseLumpNum(*lumpnum);
- return false;
+ // Invalid sound
+
+ return false;
}
// 16 bit sample rate field, 32 bit length field
- *samplerate = (data[3] << 8) | data[2];
- *length = (data[7] << 24) | (data[6] << 16) | (data[5] << 8) | data[4];
+ samplerate = (data[3] << 8) | data[2];
+ length = (data[7] << 24) | (data[6] << 16) | (data[5] << 8) | data[4];
- // If the header specifies that the length of the sound is
- // greater than the length of the lump itself, this is an invalid
- // sound lump.
+ // If the header specifies that the length of the sound is greater than
+ // the length of the lump itself, this is an invalid sound lump
// We also discard sound lumps that are less than 49 samples long,
// as this is how DMX behaves - although the actual cut-off length
@@ -365,52 +674,23 @@ static boolean LoadSoundLump(int sound,
// further investigation to better understand the correct
// behavior.
- if (*length > lumplen - 8 || *length <= 48)
+ if (length > lumplen - 8 || length <= 48)
{
- W_ReleaseLumpNum(*lumpnum);
- return false;
+ return false;
}
- // Prune header
- *data_ref += 8;
-
// The DMX sound library seems to skip the first 16 and last 16
// bytes of the lump - reason unknown.
- *data_ref += 16;
- *length -= 32;
-
- return true;
-}
-
-
-// Load and convert a sound effect
-// Returns true if successful
-
-static boolean CacheSFX_SDL(int sound)
-{
- int lumpnum;
- int samplerate;
- uint32_t length;
- byte *data;
-
-#ifdef HAVE_LIBSAMPLERATE
- assert(!use_libsamplerate); // Should be using I_PrecacheSounds_SRC instead
-#endif
-
- if (!LoadSoundLump(sound, &lumpnum, &samplerate, &length, &data))
- return false;
+ data += 16;
+ length -= 32;
// Sample rate conversion
- // sound_chunks[sound].alen and abuf are determined by ExpandSoundData.
-
- sound_chunks[sound].allocated = 1;
- sound_chunks[sound].volume = MIX_MAX_VOLUME;
- ExpandSoundData_SDL(data,
- samplerate,
- length,
- &sound_chunks[sound]);
+ if (!ExpandSoundData(sfxinfo, data + 8, samplerate, length))
+ {
+ return false;
+ }
#ifdef DEBUG_DUMP_WAVS
{
@@ -429,196 +709,106 @@ static boolean CacheSFX_SDL(int sound)
return true;
}
+static void GetSfxLumpName(sfxinfo_t *sfx, char *buf)
+{
+ // Linked sfx lumps? Get the lump number for the sound linked to.
+
+ if (sfx->link != NULL)
+ {
+ sfx = sfx->link;
+ }
+
+ // Doom adds a DS* prefix to sound lumps; Heretic and Hexen don't
+ // do this.
+
+ if (use_sfx_prefix)
+ {
+ sprintf(buf, "ds%s", DEH_String(sfx->name));
+ }
+ else
+ {
+ strcpy(buf, DEH_String(sfx->name));
+ }
+}
#ifdef HAVE_LIBSAMPLERATE
-// Preload and resample all sound effects with libsamplerate.
+// Preload all the sound effects - stops nasty ingame freezes
-static void I_PrecacheSounds_SRC(void)
+static void I_SDL_PrecacheSounds(sfxinfo_t *sounds, int num_sounds)
{
char namebuf[9];
- uint32_t sound_i, sample_i;
- boolean good_sound[NUMSFX];
- float *resampled_sound[NUMSFX];
- uint32_t resampled_sound_length[NUMSFX];
- float norm_factor;
- float max_amp = 0;
- unsigned int zone_size;
-
- assert(use_libsamplerate);
+ int i;
- zone_size = Z_ZoneSize();
+ // Don't need to precache the sounds unless we are using libsamplerate.
- if (zone_size < 32 * 1024 * 1024)
+ if (use_libsamplerate == 0)
{
- fprintf(stderr,
- "WARNING: low memory. Heap size is only %d MiB.\n"
- "WARNING: use_libsamplerate needs more heap!\n"
- "WARNING: put -mb 64 on the command line to avoid "
- "\"Error: Z_Malloc: failed on allocation of X bytes\" !\n",
- zone_size / (1024 * 1024));
+ return;
}
- printf("I_PrecacheSounds_SRC: Precaching all sound effects..");
-
- // Pass 1: resample all sounds and determine maximum amplitude.
+ printf("I_SDL_PrecacheSounds: Precaching all sound effects..");
- for (sound_i=sfx_pistol; sound_i<NUMSFX; ++sound_i)
+ for (i=0; i<num_sounds; ++i)
{
- good_sound[sound_i] = false;
-
- if ((sound_i % 6) == 0)
+ if ((i % 6) == 0)
{
printf(".");
fflush(stdout);
}
- sprintf(namebuf, "ds%s", DEH_String(S_sfx[sound_i].name));
- S_sfx[sound_i].lumpnum = W_CheckNumForName(namebuf);
- if (S_sfx[sound_i].lumpnum != -1)
- {
- int lumpnum;
- int samplerate;
- uint32_t length;
- byte *data;
- double of_temp;
- int retn;
- float *rsound;
- uint32_t rlen;
- SRC_DATA src_data;
-
- if (!LoadSoundLump(sound_i, &lumpnum, &samplerate, &length, &data))
- continue;
-
- assert(length <= LONG_MAX);
- src_data.input_frames = length;
- src_data.data_in = malloc(length * sizeof(float));
- src_data.src_ratio = (double)mixer_freq / samplerate;
-
- // mixer_freq / 4 adds a quarter-second safety margin.
-
- of_temp = src_data.src_ratio * length + (mixer_freq / 4);
- assert(of_temp <= LONG_MAX);
- src_data.output_frames = of_temp;
- src_data.data_out = malloc(src_data.output_frames * sizeof(float));
- assert(src_data.data_in != NULL && src_data.data_out != NULL);
-
- // Convert input data to floats
-
- for (sample_i=0; sample_i<length; ++sample_i)
- {
- // Unclear whether 128 should be interpreted as "zero" or
- // whether a symmetrical range should be assumed. The
- // following assumes a symmetrical range.
-
- src_data.data_in[sample_i] = data[sample_i] / 127.5 - 1;
- }
-
- // don't need the original lump any more
-
- W_ReleaseLumpNum(lumpnum);
-
- // Resample
-
- retn = src_simple(&src_data, SRC_ConversionMode(), 1);
- assert(retn == 0);
- assert(src_data.output_frames_gen > 0);
- resampled_sound[sound_i] = src_data.data_out;
- resampled_sound_length[sound_i] = src_data.output_frames_gen;
- free(src_data.data_in);
- good_sound[sound_i] = true;
-
- // Track maximum amplitude for later normalization
-
- rsound = resampled_sound[sound_i];
- rlen = resampled_sound_length[sound_i];
- for (sample_i=0; sample_i<rlen; ++sample_i)
- {
- float fabs_amp = fabsf(rsound[sample_i]);
- if (fabs_amp > max_amp)
- max_amp = fabs_amp;
- }
- }
- }
-
- // Pass 2: normalize and convert to signed 16-bit stereo.
+ GetSfxLumpName(&sounds[i], namebuf);
- if (max_amp <= 0)
- max_amp = 1;
- norm_factor = INT16_MAX / max_amp;
+ sounds[i].lumpnum = W_CheckNumForName(namebuf);
- for (sound_i=sfx_pistol; sound_i<NUMSFX; ++sound_i)
- {
- if (good_sound[sound_i])
+ if (sounds[i].lumpnum != -1)
{
- uint32_t rlen = resampled_sound_length[sound_i];
- int16_t *expanded;
- uint32_t abuf_index;
- float *rsound;
-
- sound_chunks[sound_i].allocated = 1;
- sound_chunks[sound_i].volume = MIX_MAX_VOLUME;
- sound_chunks[sound_i].alen = rlen * 4;
- sound_chunks[sound_i].abuf = Z_Malloc(sound_chunks[sound_i].alen,
- PU_STATIC,
- &sound_chunks[sound_i].abuf);
- expanded = (int16_t *) sound_chunks[sound_i].abuf;
- abuf_index=0;
-
- rsound = resampled_sound[sound_i];
- for (sample_i=0; sample_i<rlen; ++sample_i)
- {
- float cvtval_f = norm_factor * rsound[sample_i];
- int16_t cvtval_i = cvtval_f + (cvtval_f < 0 ? -0.5 : 0.5);
-
- // Left and right channels
-
- expanded[abuf_index++] = cvtval_i;
- expanded[abuf_index++] = cvtval_i;
- }
- free(rsound);
+ CacheSFX(&sounds[i]);
}
}
- printf(" norm factor = %f\n", norm_factor);
+ printf("\n");
+}
+
+#else
+
+static void I_SDL_PrecacheSounds(sfxinfo_t *sounds, int num_sounds)
+{
+ // no-op
}
#endif
+// Load a SFX chunk into memory and ensure that it is locked.
-static Mix_Chunk *GetSFXChunk(int sound_id)
+static boolean LockSound(sfxinfo_t *sfxinfo)
{
- if (sound_chunks[sound_id].abuf == NULL)
- {
-#ifdef HAVE_LIBSAMPLERATE
- if (use_libsamplerate != 0)
- return NULL; /* If valid, it should have been precached */
-#endif
- if (!CacheSFX_SDL(sound_id))
- return NULL;
- }
- else
+ // If the sound isn't loaded, load it now
+
+ if (sfxinfo->driver_data == NULL)
{
- // don't free the sound while it is playing!
-
- Z_ChangeTag(sound_chunks[sound_id].abuf, PU_STATIC);
+ if (!CacheSFX(sfxinfo))
+ {
+ return false;
+ }
}
- return &sound_chunks[sound_id];
-}
+ LockAllocatedSound(sfxinfo->driver_data);
+ return true;
+}
//
// Retrieve the raw data lump index
// for a given SFX name.
//
-static int I_SDL_GetSfxLumpNum(sfxinfo_t* sfx)
+static int I_SDL_GetSfxLumpNum(sfxinfo_t *sfx)
{
char namebuf[9];
- sprintf(namebuf, "ds%s", DEH_String(sfx->name));
-
+ GetSfxLumpName(sfx, namebuf);
+
return W_GetNumForName(namebuf);
}
@@ -634,6 +824,11 @@ static void I_SDL_UpdateSoundParams(int handle, int vol, int sep)
left = ((254 - sep) * vol) / 127;
right = ((sep) * vol) / 127;
+ if (left < 0) left = 0;
+ else if ( left > 255) left = 255;
+ if (right < 0) right = 0;
+ else if (right > 255) right = 255;
+
// SDL_mixer version 1.2.8 and earlier has a bug in the Mix_SetPanning
// function. A workaround is to call Mix_UnregisterAllEffects for
// the channel before calling it. This is undesirable as it may lead
@@ -660,9 +855,9 @@ static void I_SDL_UpdateSoundParams(int handle, int vol, int sep)
// is set, but currently not used by mixing.
//
-static int I_SDL_StartSound(int id, int channel, int vol, int sep)
+static int I_SDL_StartSound(sfxinfo_t *sfxinfo, int channel, int vol, int sep)
{
- Mix_Chunk *chunk;
+ allocated_sound_t *snd;
if (!sound_initialized)
{
@@ -676,18 +871,18 @@ static int I_SDL_StartSound(int id, int channel, int vol, int sep)
// Get the sound data
- chunk = GetSFXChunk(id);
-
- if (chunk == NULL)
+ if (!LockSound(sfxinfo))
{
- return -1;
+ return -1;
}
+ snd = sfxinfo->driver_data;
+
// play sound
- Mix_PlayChannelTimed(channel, chunk, 0, -1);
+ Mix_PlayChannelTimed(channel, &snd->chunk, 0, -1);
- channels_playing[channel] = id;
+ channels_playing[channel] = sfxinfo;
// set separation, etc.
@@ -784,20 +979,17 @@ static int GetSliceSize(void)
return 1024;
}
-static boolean I_SDL_InitSound(void)
-{
+static boolean I_SDL_InitSound(boolean _use_sfx_prefix)
+{
int i;
-
- // No sounds yet
- for (i=0; i<NUMSFX; ++i)
- {
- sound_chunks[i].abuf = NULL;
- }
+ use_sfx_prefix = _use_sfx_prefix;
+
+ // No sounds yet
for (i=0; i<NUM_CHANNELS; ++i)
{
- channels_playing[i] = sfx_None;
+ channels_playing[i] = NULL;
}
if (SDL_Init(SDL_INIT_AUDIO) < 0)
@@ -808,10 +1000,12 @@ static boolean I_SDL_InitSound(void)
if (Mix_OpenAudio(snd_samplerate, AUDIO_S16SYS, 2, GetSliceSize()) < 0)
{
- fprintf(stderr, "Error initializing SDL_mixer: %s\n", Mix_GetError());
+ fprintf(stderr, "Error initialising SDL_mixer: %s\n", Mix_GetError());
return false;
}
+ ExpandSoundData = ExpandSoundData_SDL;
+
Mix_QuerySpec(&mixer_freq, &mixer_format, &mixer_channels);
#ifdef HAVE_LIBSAMPLERATE
@@ -823,7 +1017,7 @@ static boolean I_SDL_InitSound(void)
use_libsamplerate);
}
- I_PrecacheSounds_SRC();
+ ExpandSoundData = ExpandSoundData_SRC;
}
#else
if (use_libsamplerate != 0)
@@ -891,5 +1085,6 @@ sound_module_t sound_sdl_module =
I_SDL_StartSound,
I_SDL_StopSound,
I_SDL_SoundIsPlaying,
+ I_SDL_PrecacheSounds,
};
diff --git a/src/i_sound.c b/src/i_sound.c
new file mode 100644
index 00000000..47cae682
--- /dev/null
+++ b/src/i_sound.c
@@ -0,0 +1,464 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION: none
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "SDL_mixer.h"
+
+#include "config.h"
+#include "doomfeatures.h"
+#include "doomtype.h"
+
+#include "gusconf.h"
+#include "i_sound.h"
+#include "i_video.h"
+#include "m_argv.h"
+#include "m_config.h"
+
+// Sound sample rate to use for digital output (Hz)
+
+int snd_samplerate = 44100;
+
+// Maximum number of bytes to dedicate to allocated sound effects.
+// (Default: 64MB)
+
+int snd_cachesize = 64 * 1024 * 1024;
+
+// Low-level sound and music modules we are using
+
+static sound_module_t *sound_module;
+static music_module_t *music_module;
+
+int snd_musicdevice = SNDDEVICE_GENMIDI;
+int snd_sfxdevice = SNDDEVICE_SB;
+
+// Sound modules
+
+extern void I_InitTimidityConfig(void);
+extern sound_module_t sound_sdl_module;
+extern sound_module_t sound_pcsound_module;
+extern music_module_t music_sdl_module;
+extern music_module_t music_opl_module;
+
+// For OPL module:
+
+extern int opl_io_port;
+
+// For native music module:
+
+extern char *timidity_cfg_path;
+
+// DOS-specific options: These are unused but should be maintained
+// so that the config file can be shared between chocolate
+// doom and doom.exe
+
+static int snd_sbport = 0;
+static int snd_sbirq = 0;
+static int snd_sbdma = 0;
+static int snd_mport = 0;
+
+// Compiled-in sound modules:
+
+static sound_module_t *sound_modules[] =
+{
+#ifdef FEATURE_SOUND
+ &sound_sdl_module,
+ &sound_pcsound_module,
+#endif
+ NULL,
+};
+
+// Compiled-in music modules:
+
+static music_module_t *music_modules[] =
+{
+#ifdef FEATURE_SOUND
+ &music_sdl_module,
+ &music_opl_module,
+#endif
+ NULL,
+};
+
+// Check if a sound device is in the given list of devices
+
+static boolean SndDeviceInList(snddevice_t device, snddevice_t *list,
+ int len)
+{
+ int i;
+
+ for (i=0; i<len; ++i)
+ {
+ if (device == list[i])
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Find and initialize a sound_module_t appropriate for the setting
+// in snd_sfxdevice.
+
+static void InitSfxModule(boolean use_sfx_prefix)
+{
+ int i;
+
+ sound_module = NULL;
+
+ for (i=0; sound_modules[i] != NULL; ++i)
+ {
+ // Is the sfx device in the list of devices supported by
+ // this module?
+
+ if (SndDeviceInList(snd_sfxdevice,
+ sound_modules[i]->sound_devices,
+ sound_modules[i]->num_sound_devices))
+ {
+ // Initialize the module
+
+ if (sound_modules[i]->Init(use_sfx_prefix))
+ {
+ sound_module = sound_modules[i];
+ return;
+ }
+ }
+ }
+}
+
+// Initialize music according to snd_musicdevice.
+
+static void InitMusicModule(void)
+{
+ int i;
+
+ music_module = NULL;
+
+ for (i=0; music_modules[i] != NULL; ++i)
+ {
+ // Is the music device in the list of devices supported
+ // by this module?
+
+ if (SndDeviceInList(snd_musicdevice,
+ music_modules[i]->sound_devices,
+ music_modules[i]->num_sound_devices))
+ {
+ // Initialize the module
+
+ if (music_modules[i]->Init())
+ {
+ music_module = music_modules[i];
+ return;
+ }
+ }
+ }
+}
+
+//
+// Initializes sound stuff, including volume
+// Sets channels, SFX and music volume,
+// allocates channel buffer, sets S_sfx lookup.
+//
+
+void I_InitSound(boolean use_sfx_prefix)
+{
+ boolean nosound, nosfx, nomusic;
+
+ //!
+ // @vanilla
+ //
+ // Disable all sound output.
+ //
+
+ nosound = M_CheckParm("-nosound") > 0;
+
+ //!
+ // @vanilla
+ //
+ // Disable sound effects.
+ //
+
+ nosfx = M_CheckParm("-nosfx") > 0;
+
+ //!
+ // @vanilla
+ //
+ // Disable music.
+ //
+
+ nomusic = M_CheckParm("-nomusic") > 0;
+
+ // Initialize the sound and music subsystems.
+
+ if (!nosound && !screensaver_mode)
+ {
+ // This is kind of a hack. If native MIDI is enabled, set up
+ // the TIMIDITY_CFG environment variable here before SDL_mixer
+ // is opened.
+
+ if (!nomusic
+ && (snd_musicdevice == SNDDEVICE_GENMIDI
+ || snd_musicdevice == SNDDEVICE_GUS))
+ {
+ I_InitTimidityConfig();
+ }
+
+ if (!nosfx)
+ {
+ InitSfxModule(use_sfx_prefix);
+ }
+
+ if (!nomusic)
+ {
+ InitMusicModule();
+ }
+ }
+}
+
+void I_ShutdownSound(void)
+{
+ if (sound_module != NULL)
+ {
+ sound_module->Shutdown();
+ }
+
+ if (music_module != NULL)
+ {
+ music_module->Shutdown();
+ }
+}
+
+int I_GetSfxLumpNum(sfxinfo_t *sfxinfo)
+{
+ if (sound_module != NULL)
+ {
+ return sound_module->GetSfxLumpNum(sfxinfo);
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+void I_UpdateSound(void)
+{
+ if (sound_module != NULL)
+ {
+ sound_module->Update();
+ }
+}
+
+static void CheckVolumeSeparation(int *sep, int *vol)
+{
+ if (*sep < 0)
+ {
+ *sep = 0;
+ }
+ else if (*sep > 254)
+ {
+ *sep = 254;
+ }
+
+ if (*vol < 0)
+ {
+ *vol = 0;
+ }
+ else if (*vol > 127)
+ {
+ *vol = 127;
+ }
+}
+
+void I_UpdateSoundParams(int channel, int vol, int sep)
+{
+ if (sound_module != NULL)
+ {
+ CheckVolumeSeparation(&vol, &sep);
+ sound_module->UpdateSoundParams(channel, vol, sep);
+ }
+}
+
+int I_StartSound(sfxinfo_t *sfxinfo, int channel, int vol, int sep)
+{
+ if (sound_module != NULL)
+ {
+ CheckVolumeSeparation(&vol, &sep);
+ return sound_module->StartSound(sfxinfo, channel, vol, sep);
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+void I_StopSound(int channel)
+{
+ if (sound_module != NULL)
+ {
+ sound_module->StopSound(channel);
+ }
+}
+
+boolean I_SoundIsPlaying(int channel)
+{
+ if (sound_module != NULL)
+ {
+ return sound_module->SoundIsPlaying(channel);
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void I_PrecacheSounds(sfxinfo_t *sounds, int num_sounds)
+{
+ if (sound_module != NULL && sound_module->CacheSounds != NULL)
+ {
+ sound_module->CacheSounds(sounds, num_sounds);
+ }
+}
+
+void I_InitMusic(void)
+{
+}
+
+void I_ShutdownMusic(void)
+{
+
+}
+
+void I_SetMusicVolume(int volume)
+{
+ if (music_module != NULL)
+ {
+ music_module->SetMusicVolume(volume);
+ }
+}
+
+void I_PauseSong(void)
+{
+ if (music_module != NULL)
+ {
+ music_module->PauseMusic();
+ }
+}
+
+void I_ResumeSong(void)
+{
+ if (music_module != NULL)
+ {
+ music_module->ResumeMusic();
+ }
+}
+
+void *I_RegisterSong(void *data, int len)
+{
+ if (music_module != NULL)
+ {
+ return music_module->RegisterSong(data, len);
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+void I_UnRegisterSong(void *handle)
+{
+ if (music_module != NULL)
+ {
+ music_module->UnRegisterSong(handle);
+ }
+}
+
+void I_PlaySong(void *handle, boolean looping)
+{
+ if (music_module != NULL)
+ {
+ music_module->PlaySong(handle, looping);
+ }
+}
+
+void I_StopSong(void)
+{
+ if (music_module != NULL)
+ {
+ music_module->StopSong();
+ }
+}
+
+boolean I_MusicIsPlaying(void)
+{
+ if (music_module != NULL)
+ {
+ return music_module->MusicIsPlaying();
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void I_BindSoundVariables(void)
+{
+ extern int use_libsamplerate;
+
+ M_BindVariable("snd_musicdevice", &snd_musicdevice);
+ M_BindVariable("snd_sfxdevice", &snd_sfxdevice);
+ M_BindVariable("snd_sbport", &snd_sbport);
+ M_BindVariable("snd_sbirq", &snd_sbirq);
+ M_BindVariable("snd_sbdma", &snd_sbdma);
+ M_BindVariable("snd_mport", &snd_mport);
+ M_BindVariable("snd_samplerate", &snd_samplerate);
+ M_BindVariable("snd_cachesize", &snd_cachesize);
+ M_BindVariable("opl_io_port", &opl_io_port);
+
+ M_BindVariable("timidity_cfg_path", &timidity_cfg_path);
+ M_BindVariable("gus_patch_path", &gus_patch_path);
+ M_BindVariable("gus_ram_kb", &gus_ram_kb);
+
+#ifdef FEATURE_SOUND
+ M_BindVariable("use_libsamplerate", &use_libsamplerate);
+#endif
+
+ // Before SDL_mixer version 1.2.11, MIDI music caused the game
+ // to crash when it looped. If this is an old SDL_mixer version,
+ // disable MIDI.
+
+#ifdef __MACOSX__
+ {
+ const SDL_version *v = Mix_Linked_Version();
+
+ if (SDL_VERSIONNUM(v->major, v->minor, v->patch)
+ < SDL_VERSIONNUM(1, 2, 11))
+ {
+ snd_musicdevice = SNDDEVICE_NONE;
+ }
+ }
+#endif
+}
+
diff --git a/src/s_sound.h b/src/i_sound.h
index b8d0e766..e4062959 100644
--- a/src/s_sound.h
+++ b/src/i_sound.h
@@ -25,11 +25,73 @@
//-----------------------------------------------------------------------------
-#ifndef __S_SOUND__
-#define __S_SOUND__
+#ifndef __I_SOUND__
+#define __I_SOUND__
-#include "p_mobj.h"
-#include "sounds.h"
+#include "doomtype.h"
+
+
+//
+// SoundFX struct.
+//
+typedef struct sfxinfo_struct sfxinfo_t;
+
+struct sfxinfo_struct
+{
+ // tag name, used for hexen.
+ char *tagname;
+
+ // lump name. If we are running with use_sfx_prefix=true, a
+ // 'DS' (or 'DP' for PC speaker sounds) is prepended to this.
+
+ char name[9];
+
+ // Sfx priority
+ int priority;
+
+ // referenced sound if a link
+ sfxinfo_t *link;
+
+ // pitch if a link
+ int pitch;
+
+ // volume if a link
+ int volume;
+
+ // this is checked every second to see if sound
+ // can be thrown out (if 0, then decrement, if -1,
+ // then throw out, if > 0, then it is in use)
+ int usefulness;
+
+ // lump number of sfx
+ int lumpnum;
+
+ // Maximum number of channels that the sound can be played on
+ // (Heretic)
+ int numchannels;
+
+ // data used by the low level code
+ void *driver_data;
+};
+
+//
+// MusicInfo struct.
+//
+typedef struct
+{
+ // up to 6-character name
+ char *name;
+
+ // lump number of music
+ int lumpnum;
+
+ // music data
+ void *data;
+
+ // music handle once registered
+ void *handle;
+
+} musicinfo_t;
typedef enum
{
@@ -43,6 +105,7 @@ typedef enum
SNDDEVICE_SOUNDCANVAS = 7,
SNDDEVICE_GENMIDI = 8,
SNDDEVICE_AWE32 = 9,
+ SNDDEVICE_CD = 10,
} snddevice_t;
// Interface for sound modules
@@ -54,10 +117,10 @@ typedef struct
snddevice_t *sound_devices;
int num_sound_devices;
- // Initialize sound module
- // Returns true if successfully initialized
+ // Initialise sound module
+ // Returns true if successfully initialised
- boolean (*Init)(void);
+ boolean (*Init)(boolean use_sfx_prefix);
// Shutdown sound module
@@ -78,7 +141,7 @@ typedef struct
// Start a sound on a given channel. Returns the channel id
// or -1 on failure.
- int (*StartSound)(int id, int channel, int vol, int sep);
+ int (*StartSound)(sfxinfo_t *sfxinfo, int channel, int vol, int sep);
// Stop the sound playing on the given channel.
@@ -88,8 +151,22 @@ typedef struct
boolean (*SoundIsPlaying)(int channel);
+ // Called on startup to precache sound effects (if necessary)
+
+ void (*CacheSounds)(sfxinfo_t *sounds, int num_sounds);
+
} sound_module_t;
+void I_InitSound(boolean use_sfx_prefix);
+void I_ShutdownSound(void);
+int I_GetSfxLumpNum(sfxinfo_t *sfxinfo);
+void I_UpdateSound(void);
+void I_UpdateSoundParams(int channel, int vol, int sep);
+int I_StartSound(sfxinfo_t *sfxinfo, int channel, int vol, int sep);
+void I_StopSound(int channel);
+boolean I_SoundIsPlaying(int channel);
+void I_PrecacheSounds(sfxinfo_t *sounds, int num_sounds);
+
// Interface for music modules
typedef struct
@@ -99,7 +176,7 @@ typedef struct
snddevice_t *sound_devices;
int num_sound_devices;
- // Initialize the music subsystem
+ // Initialise the music subsystem
boolean (*Init)(void);
@@ -130,7 +207,7 @@ typedef struct
// Play the song
- void (*PlaySong)(void *handle, int looping);
+ void (*PlaySong)(void *handle, boolean looping);
// Stop playing the current song.
@@ -141,70 +218,23 @@ typedef struct
boolean (*MusicIsPlaying)(void);
} music_module_t;
+void I_InitMusic(void);
+void I_ShutdownMusic(void);
+void I_SetMusicVolume(int volume);
+void I_PauseSong(void);
+void I_ResumeSong(void);
+void *I_RegisterSong(void *data, int len);
+void I_UnRegisterSong(void *handle);
+void I_PlaySong(void *handle, boolean looping);
+void I_StopSong(void);
+boolean I_MusicIsPlaying(void);
+
extern int snd_sfxdevice;
extern int snd_musicdevice;
extern int snd_samplerate;
+extern int snd_cachesize;
-//
-// Initializes sound stuff, including volume
-// Sets channels, SFX and music volume,
-// allocates channel buffer, sets S_sfx lookup.
-//
-
-void S_Init(int sfxVolume, int musicVolume);
-
-
-// Shut down sound
-
-void S_Shutdown(void);
-
-
-
-//
-// Per level startup code.
-// Kills playing sounds at start of level,
-// determines music if any, changes music.
-//
-
-void S_Start(void);
-
-//
-// Start sound for thing at <origin>
-// using <sound_id> from sounds.h
-//
-
-void S_StartSound(void *origin, int sound_id);
-
-// Stop sound for thing at <origin>
-void S_StopSound(mobj_t *origin);
-
-
-// Start music using <music_id> from sounds.h
-void S_StartMusic(int music_id);
-
-// Start music using <music_id> from sounds.h,
-// and set whether looping
-void S_ChangeMusic(int music_id, int looping);
-
-// query if music is playing
-boolean S_MusicPlaying(void);
-
-// Stops the music fer sure.
-void S_StopMusic(void);
-
-// Stop and resume music, during game PAUSE.
-void S_PauseSound(void);
-void S_ResumeSound(void);
-
-
-//
-// Updates music & sounds
-//
-void S_UpdateSounds(mobj_t *listener);
-
-void S_SetMusicVolume(int volume);
-void S_SetSfxVolume(int volume);
-
+void I_BindSoundVariables(void);
#endif
diff --git a/src/i_system.c b/src/i_system.c
index 65ca8854..328fd9f5 100644
--- a/src/i_system.c
+++ b/src/i_system.c
@@ -38,25 +38,21 @@
#include <unistd.h>
#endif
+#include "SDL.h"
+
#include "config.h"
-#include "deh_main.h"
-#include "doomdef.h"
-#include "doomstat.h"
+#include "deh_str.h"
+#include "doomtype.h"
#include "m_argv.h"
#include "m_config.h"
#include "m_misc.h"
#include "i_joystick.h"
+#include "i_sound.h"
#include "i_timer.h"
#include "i_video.h"
-#include "s_sound.h"
-
-#include "d_net.h"
-#include "g_game.h"
#include "i_system.h"
-#include "txt_main.h"
-
#include "w_wad.h"
#include "z_zone.h"
@@ -68,7 +64,29 @@
#define DEFAULT_RAM 16 /* MiB */
#define MIN_RAM 4 /* MiB */
-int show_endoom = 1;
+
+typedef struct atexit_listentry_s atexit_listentry_t;
+
+struct atexit_listentry_s
+{
+ atexit_func_t func;
+ boolean run_on_error;
+ atexit_listentry_t *next;
+};
+
+static atexit_listentry_t *exit_funcs = NULL;
+
+void I_AtExit(atexit_func_t func, boolean run_on_error)
+{
+ atexit_listentry_t *entry;
+
+ entry = malloc(sizeof(*entry));
+
+ entry->func = func;
+ entry->run_on_error = run_on_error;
+ entry->next = exit_funcs;
+ exit_funcs = entry;
+}
// Tactile feedback function, probably used for the Logitech Cyberman
@@ -198,7 +216,45 @@ byte *I_ZoneBase (int *size)
return zonemem;
}
-//
+void I_PrintBanner(char *msg)
+{
+ int i;
+ int spaces = 35 - (strlen(msg) / 2);
+
+ for (i=0; i<spaces; ++i)
+ putchar(' ');
+
+ puts(msg);
+}
+
+void I_PrintDivider(void)
+{
+ int i;
+
+ for (i=0; i<75; ++i)
+ {
+ putchar('=');
+ }
+
+ putchar('\n');
+}
+
+void I_PrintStartupBanner(char *gamedescription)
+{
+ I_PrintDivider();
+ I_PrintBanner(gamedescription);
+ I_PrintDivider();
+
+ printf(
+ " " PACKAGE_NAME " is free software, covered by the GNU General Public\n"
+ " License. There is NO warranty; not even for MERCHANTABILITY or FITNESS\n"
+ " FOR A PARTICULAR PURPOSE. You are welcome to change and distribute\n"
+ " copies under certain conditions. See the source for more information.\n");
+
+ I_PrintDivider();
+}
+
+//
// I_ConsoleStdout
//
// Returns true if stdout is a real console, false if it is a file
@@ -217,69 +273,20 @@ boolean I_ConsoleStdout(void)
//
// I_Init
//
+/*
void I_Init (void)
{
I_CheckIsScreensaver();
I_InitTimer();
I_InitJoystick();
}
-
-#define ENDOOM_W 80
-#define ENDOOM_H 25
-
-//
-// Displays the text mode ending screen after the game quits
-//
-
-void I_Endoom(void)
+void I_BindVariables(void)
{
- unsigned char *endoom_data;
- unsigned char *screendata;
- int y;
- int indent;
-
- endoom_data = W_CacheLumpName(DEH_String("ENDOOM"), PU_STATIC);
-
- // Set up text mode screen
-
- TXT_Init();
-
- // Make sure the new window has the right title and icon
-
- I_SetWindowCaption();
- I_SetWindowIcon();
-
- // Write the data to the screen memory
-
- screendata = TXT_GetScreenData();
-
- indent = (ENDOOM_W - TXT_SCREEN_W) / 2;
-
- for (y=0; y<TXT_SCREEN_H; ++y)
- {
- memcpy(screendata + (y * TXT_SCREEN_W * 2),
- endoom_data + (y * ENDOOM_W + indent) * 2,
- TXT_SCREEN_W * 2);
- }
-
- // Wait for a keypress
-
- while (true)
- {
- TXT_UpdateScreen();
-
- if (TXT_GetChar() > 0)
- {
- break;
- }
-
- TXT_Sleep(0);
- }
-
- // Shut down text mode screen
-
- TXT_Shutdown();
+ I_BindVideoVariables();
+ I_BindJoystickVariables();
+ I_BindSoundVariables();
}
+*/
//
// I_Quit
@@ -287,40 +294,32 @@ void I_Endoom(void)
void I_Quit (void)
{
- D_QuitNetGame ();
- G_CheckDemoStatus();
- S_Shutdown();
+ atexit_listentry_t *entry;
- if (!screensaver_mode)
- {
- M_SaveDefaults ();
- }
-
- I_ShutdownGraphics();
+ // Run through all exit functions
+
+ entry = exit_funcs;
- if (show_endoom && !testcontrols && !screensaver_mode)
+ while (entry != NULL)
{
- I_Endoom();
+ entry->func();
+ entry = entry->next;
}
exit(0);
}
-void I_WaitVBL(int count)
-{
- I_Sleep((count * 1000) / 70);
-}
-
//
// I_Error
//
-extern boolean demorecording;
static boolean already_quitting = false;
void I_Error (char *error, ...)
{
- va_list argptr;
+ va_list argptr;
+ atexit_listentry_t *entry;
+ boolean exit_gui_popup;
if (already_quitting)
{
@@ -342,17 +341,24 @@ void I_Error (char *error, ...)
// Shutdown. Here might be other errors.
- if (demorecording)
+ entry = exit_funcs;
+
+ while (entry != NULL)
{
- G_CheckDemoStatus();
+ if (entry->run_on_error)
+ {
+ entry->func();
+ }
+
+ entry = entry->next;
}
- D_QuitNetGame ();
- I_ShutdownGraphics();
- S_Shutdown();
-
+ exit_gui_popup = !M_ParmExists("-nogui");
+
#ifdef _WIN32
// On Windows, pop up a dialog box with the error message.
+
+ if (exit_gui_popup)
{
char msgbuf[512];
wchar_t wmsgbuf[512];
@@ -371,7 +377,7 @@ void I_Error (char *error, ...)
#endif
#ifdef __MACOSX__
- if (!I_ConsoleStdout())
+ if (exit_gui_popup && !I_ConsoleStdout())
{
CFStringRef message;
char msgbuf[512];
diff --git a/src/i_system.h b/src/i_system.h
index 06e7f662..195895bb 100644
--- a/src/i_system.h
+++ b/src/i_system.h
@@ -32,6 +32,7 @@
#include "d_event.h"
+typedef void (*atexit_func_t)(void);
// Called by DoomMain.
void I_Init (void);
@@ -44,23 +45,6 @@ byte* I_ZoneBase (int *size);
boolean I_ConsoleStdout(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.
@@ -76,17 +60,33 @@ ticcmd_t* I_BaseTiccmd (void);
// 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_Error (char *error, ...);
void I_Tactile (int on, int off, int total);
+boolean I_GetMemoryValue(unsigned int offset, void *value, int size);
-void I_Error (char *error, ...);
+// Schedule a function to be called when the program exits.
+// If run_if_error is true, the function is called if the exit
+// is due to an error (I_Error)
-boolean I_GetMemoryValue(unsigned int offset, void *value, int size);
+void I_AtExit(atexit_func_t func, boolean run_if_error);
+
+// Add all system-specific config file variable bindings.
+
+void I_BindVariables(void);
+
+// Print startup banner copyright message.
+
+void I_PrintStartupBanner(char *gamedescription);
+
+// Print a centered text banner displaying the given string.
+
+void I_PrintBanner(char *text);
+
+// Print a dividing line for startup banners.
+
+void I_PrintDivider(void);
#endif
diff --git a/src/i_timer.c b/src/i_timer.c
index 48be83be..d2c455e9 100644
--- a/src/i_timer.c
+++ b/src/i_timer.c
@@ -27,7 +27,7 @@
#include "SDL.h"
#include "i_timer.h"
-#include "doomdef.h"
+#include "doomtype.h"
//
// I_GetTime
@@ -73,6 +73,11 @@ void I_Sleep(int ms)
SDL_Delay(ms);
}
+void I_WaitVBL(int count)
+{
+ I_Sleep((count * 1000) / 70);
+}
+
void I_InitTimer(void)
{
diff --git a/src/i_timer.h b/src/i_timer.h
index d90094c8..56810468 100644
--- a/src/i_timer.h
+++ b/src/i_timer.h
@@ -28,6 +28,8 @@
#ifndef __I_TIMER__
#define __I_TIMER__
+#define TICRATE 35
+
// Called by D_DoomLoop,
// returns current time in tics.
int I_GetTime (void);
@@ -41,5 +43,8 @@ void I_Sleep(int ms);
// Initialize timer
void I_InitTimer(void);
+// Wait for vertical retrace or pause a bit.
+void I_WaitVBL(int count);
+
#endif
diff --git a/src/i_video.c b/src/i_video.c
index fdde7766..bf8ab77b 100644
--- a/src/i_video.c
+++ b/src/i_video.c
@@ -29,14 +29,19 @@
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
+#include <string.h>
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
#include "icon.c"
#include "config.h"
-#include "deh_main.h"
-#include "doomdef.h"
-#include "doomstat.h"
-#include "d_main.h"
+#include "deh_str.h"
+#include "doomtype.h"
+#include "doomkeys.h"
#include "i_joystick.h"
#include "i_system.h"
#include "i_swap.h"
@@ -44,12 +49,55 @@
#include "i_video.h"
#include "i_scale.h"
#include "m_argv.h"
-#include "s_sound.h"
-#include "sounds.h"
+#include "m_config.h"
+#include "tables.h"
#include "v_video.h"
#include "w_wad.h"
#include "z_zone.h"
+// Lookup table for mapping ASCII characters to their equivalent when
+// shift is pressed on an American layout keyboard:
+
+static const char 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
+};
+
+
#define LOADING_DISK_W 16
#define LOADING_DISK_H 16
@@ -84,15 +132,22 @@ static screen_mode_t *screen_modes_corrected[] = {
&mode_squash_5x,
};
-extern void M_QuitDOOM();
-extern boolean advancedemo;
-
// SDL video driver name
char *video_driver = "";
+// Window position:
+
+static char *window_position = "";
+
+// SDL surface for the screen.
+
static SDL_Surface *screen;
+// Window title
+
+static char *window_title = "";
+
// Intermediate 8-bit buffer that we draw to instead of 'screen'.
// This is used when we are rendering in 32-bit screen mode.
// When in a real 8-bit screen mode, screenbuffer == screen.
@@ -111,13 +166,19 @@ static boolean initialized = false;
// disable mouse?
static boolean nomouse = false;
-extern int usemouse;
+int usemouse = 1;
// Bit mask of mouse button state.
static unsigned int mouse_button_state = 0;
-// if true, screens[0] is screen->pixel
+// Disallow mouse and joystick movement to cause forward/backward
+// motion. Specified with the '-novert' command line parameter.
+// This is an int to allow saving to config file
+
+int novert = 0;
+
+// if true, I_VideoBuffer is screen->pixels
static boolean native_surface;
@@ -133,7 +194,7 @@ int screen_bpp = 8;
// Automatically adjust video settings if the selected mode is
// not a valid video mode.
-int autoadjust_video_settings = 1;
+static int autoadjust_video_settings = 1;
// Run in full screen mode? (int type for config code)
@@ -146,17 +207,40 @@ int aspect_ratio_correct = true;
// Time to wait for the screen to settle on startup before starting the
// game (ms)
-int startup_delay = 1000;
+static int startup_delay = 1000;
// Grab the mouse? (int type for config code)
-int grabmouse = true;
+static int grabmouse = true;
+
+// The screen buffer; this is modified to draw things to the screen
+
+byte *I_VideoBuffer = NULL;
+
+// If true, game is running as a screensaver
+
+boolean screensaver_mode = false;
// Flag indicating whether the screen is currently visible:
// when the screen isnt visible, don't render the screen
boolean screenvisible;
+// If true, we display dots at the bottom of the screen to
+// indicate FPS.
+
+static boolean display_fps_dots;
+
+// If this is true, the screen is rendered but not blitted to the
+// video buffer.
+
+static boolean noblit;
+
+// Callback function to invoke to determine whether to grab the
+// mouse pointer.
+
+static grabmouse_callback_t grabmouse_callback = NULL;
+
// disk image data and background overwritten by the disk to be
// restored by EndRead
@@ -184,6 +268,10 @@ static unsigned int last_resize_time;
int vanilla_keyboard_mapping = true;
+// Is the shift key currently down?
+
+static int shiftdown = 0;
+
// Mouse acceleration
//
// This emulates some of the behavior of DOS mouse drivers by increasing
@@ -196,6 +284,10 @@ int vanilla_keyboard_mapping = true;
float mouse_acceleration = 2.0;
int mouse_threshold = 10;
+// Gamma correction level to use
+
+int usegamma = 0;
+
static void ApplyWindowResize(unsigned int w, unsigned int h);
static boolean MouseShouldBeGrabbed()
@@ -232,26 +324,36 @@ static boolean MouseShouldBeGrabbed()
if (!usemouse || nomouse)
return false;
- // Drone players don't need mouse focus
-
- if (drone)
- return false;
-
// if we specify not to grab the mouse, never grab
if (!grabmouse)
return false;
- // when menu is active or game is paused, release the mouse
+ // Invoke the grabmouse callback function to determine whether
+ // the mouse should be grabbed
- if (menuactive || paused)
- return false;
+ if (grabmouse_callback != NULL)
+ {
+ return grabmouse_callback();
+ }
+ else
+ {
+ return true;
+ }
- // only grab mouse when playing levels (but not demos)
+#endif /* #ifndef _WIN32_WCE */
+}
- return (gamestate == GS_LEVEL) && !demoplayback && !advancedemo;
+void I_SetGrabMouseCallback(grabmouse_callback_t func)
+{
+ grabmouse_callback = func;
+}
-#endif /* #ifndef _WIN32_WCE */
+// Set the variable controlling FPS dots.
+
+void I_DisplayFPSDots(boolean dots_on)
+{
+ display_fps_dots = dots_on;
}
// Update the value of window_focused when we get a focus event
@@ -307,13 +409,12 @@ static void SetShowCursor(boolean show)
}
}
-static void LoadDiskImage(void)
+void I_EnableLoadingDisk(void)
{
patch_t *disk;
+ byte *tmpbuf;
char *disk_name;
int y;
- int xoffset = SCREENWIDTH - LOADING_DISK_W;
- int yoffset = SCREENHEIGHT - LOADING_DISK_H;
char buf[20];
SDL_VideoDriverName(buf, 15);
@@ -334,11 +435,14 @@ static void LoadDiskImage(void)
disk = W_CacheLumpName(disk_name, PU_STATIC);
+ // Draw the patch into a temporary buffer
+
+ tmpbuf = Z_Malloc(SCREENWIDTH * (disk->height + 1), PU_STATIC, NULL);
+ V_UseBuffer(tmpbuf);
+
// Draw the disk to the screen:
- V_DrawPatch(SCREENWIDTH - LOADING_DISK_W,
- SCREENHEIGHT - LOADING_DISK_H,
- 0, disk);
+ V_DrawPatch(0, 0, disk);
disk_image = Z_Malloc(LOADING_DISK_W * LOADING_DISK_H, PU_STATIC, NULL);
saved_background = Z_Malloc(LOADING_DISK_W * LOADING_DISK_H, PU_STATIC, NULL);
@@ -346,11 +450,16 @@ static void LoadDiskImage(void)
for (y=0; y<LOADING_DISK_H; ++y)
{
memcpy(disk_image + LOADING_DISK_W * y,
- screens[0] + SCREENWIDTH * (y + yoffset) + xoffset,
+ tmpbuf + SCREENWIDTH * y,
LOADING_DISK_W);
}
+ // All done - free the screen buffer and restore the normal
+ // video buffer.
+
W_ReleaseLumpName(disk_name);
+ V_RestoreBuffer();
+ Z_Free(tmpbuf);
}
//
@@ -540,6 +649,74 @@ static int AccelerateMouse(int val)
}
}
+// Get the equivalent ASCII (Unicode?) character for a keypress.
+
+static int GetTypedChar(SDL_Event *event)
+{
+ int key;
+
+ // If Vanilla keyboard mapping enabled, the keyboard
+ // scan code is used to give the character typed.
+ // This does not change depending on keyboard layout.
+ // If you have a German keyboard, pressing 'z' will
+ // give 'y', for example. It is desirable to be able
+ // to fix this so that people with non-standard
+ // keyboard mappings can type properly. If vanilla
+ // mode is disabled, use the properly translated
+ // version.
+
+ if (vanilla_keyboard_mapping)
+ {
+ key = TranslateKey(&event->key.keysym);
+
+ // Is shift held down? If so, perform a translation.
+
+ if (shiftdown > 0)
+ {
+ if (key >= 0 && key < arrlen(shiftxform))
+ {
+ key = shiftxform[key];
+ }
+ else
+ {
+ key = 0;
+ }
+ }
+
+ return key;
+ }
+ else
+ {
+ // Unicode value, from key layout.
+
+ return tolower(event->key.keysym.unicode);
+ }
+}
+
+static void UpdateShiftStatus(SDL_Event *event)
+{
+ int change;
+
+ if (event->type == SDL_KEYDOWN)
+ {
+ change = 1;
+ }
+ else if (event->type == SDL_KEYUP)
+ {
+ change = -1;
+ }
+ else
+ {
+ return;
+ }
+
+ if (event->key.keysym.sym == SDLK_LSHIFT
+ || event->key.keysym.sym == SDLK_RSHIFT)
+ {
+ shiftdown += change;
+ }
+}
+
void I_GetEvent(void)
{
SDL_Event sdlevent;
@@ -568,32 +745,18 @@ void I_GetEvent(void)
I_Quit();
}
+ UpdateShiftStatus(&sdlevent);
+
// process event
switch (sdlevent.type)
{
case SDL_KEYDOWN:
+ // data1 has the key pressed, data2 has the character
+ // (shift-translated, etc)
event.type = ev_keydown;
event.data1 = TranslateKey(&sdlevent.key.keysym);
-
- // If Vanilla keyboard mapping enabled, the keyboard
- // scan code is used to give the character typed.
- // This does not change depending on keyboard layout.
- // If you have a German keyboard, pressing 'z' will
- // give 'y', for example. It is desirable to be able
- // to fix this so that people with non-standard
- // keyboard mappings can type properly. If vanilla
- // mode is disabled, use the properly translated
- // version.
-
- if (vanilla_keyboard_mapping)
- {
- event.data2 = event.data1;
- }
- else
- {
- event.data2 = tolower(sdlevent.key.keysym.unicode);
- }
+ event.data2 = GetTypedChar(&sdlevent);
if (event.data1 != 0)
{
@@ -636,9 +799,8 @@ void I_GetEvent(void)
break;
case SDL_QUIT:
- // bring up the "quit doom?" prompt
- S_StartSound(NULL,sfx_swtchn);
- M_QuitDOOM(0);
+ event.type = ev_quit;
+ D_PostEvent(&event);
break;
case SDL_ACTIVEEVENT:
@@ -703,7 +865,15 @@ static void I_ReadMouse(void)
ev.type = ev_mouse;
ev.data1 = mouse_button_state;
ev.data2 = AccelerateMouse(x);
- ev.data3 = -AccelerateMouse(y);
+
+ if (!novert)
+ {
+ ev.data3 = -AccelerateMouse(y);
+ }
+ else
+ {
+ ev.data3 = 0;
+ }
D_PostEvent(&ev);
}
@@ -792,7 +962,7 @@ static boolean BlitArea(int x1, int y1, int x2, int y2)
if (SDL_LockSurface(screenbuffer) >= 0)
{
- I_InitScale(screens[0],
+ I_InitScale(I_VideoBuffer,
(byte *) screenbuffer->pixels
+ (y_offset * screenbuffer->pitch)
+ x_offset,
@@ -832,7 +1002,7 @@ static void UpdateRect(int x1, int y1, int x2, int y2)
void I_BeginRead(void)
{
- byte *screenloc = screens[0]
+ byte *screenloc = I_VideoBuffer
+ (SCREENHEIGHT - LOADING_DISK_H) * SCREENWIDTH
+ (SCREENWIDTH - LOADING_DISK_W);
int y;
@@ -860,7 +1030,7 @@ void I_BeginRead(void)
void I_EndRead(void)
{
- byte *screenloc = screens[0]
+ byte *screenloc = I_VideoBuffer
+ (SCREENHEIGHT - LOADING_DISK_H) * SCREENWIDTH
+ (SCREENWIDTH - LOADING_DISK_W);
int y;
@@ -915,19 +1085,18 @@ void I_FinishUpdate (void)
return;
// draws little dots on the bottom of the screen
- if (devparm)
- {
+ if (display_fps_dots)
+ {
i = I_GetTime();
tics = i - lasttic;
lasttic = i;
if (tics > 20) tics = 20;
for (i=0 ; i<tics*2 ; i+=4)
- screens[0][ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0xff;
+ I_VideoBuffer[ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0xff;
for ( ; i<20*4 ; i+=4)
- screens[0][ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0x0;
-
+ I_VideoBuffer[ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0x0;
}
// draw to screen
@@ -972,7 +1141,7 @@ void I_FinishUpdate (void)
//
void I_ReadScreen (byte* scr)
{
- memcpy (scr, screens[0], SCREENWIDTH*SCREENHEIGHT);
+ memcpy(scr, I_VideoBuffer, SCREENWIDTH*SCREENHEIGHT);
}
@@ -996,17 +1165,57 @@ void I_SetPalette (byte *doompalette)
palette_to_set = true;
}
+// Given an RGB value, find the closest matching palette index.
+
+int I_GetPaletteIndex(int r, int g, int b)
+{
+ int best, best_diff, diff;
+ int i;
+
+ best = 0; best_diff = INT_MAX;
+
+ for (i = 0; i < 256; ++i)
+ {
+ diff = (r - palette[i].r) * (r - palette[i].r)
+ + (g - palette[i].g) * (g - palette[i].g)
+ + (b - palette[i].b) * (b - palette[i].b);
+
+ if (diff < best_diff)
+ {
+ best = i;
+ best_diff = diff;
+ }
+
+ if (diff == 0)
+ {
+ break;
+ }
+ }
+
+ return best;
+}
+
//
-// Set the window caption
+// Set the window title
+//
+
+void I_SetWindowTitle(char *title)
+{
+ window_title = title;
+}
+
+//
+// Call the SDL function to set the window title, based on
+// the title set with I_SetWindowTitle.
//
-void I_SetWindowCaption(void)
+static void I_InitWindowTitle(void)
{
char *buf;
- buf = Z_Malloc(strlen(gamedescription) + strlen(PACKAGE_STRING) + 10,
+ buf = Z_Malloc(strlen(window_title) + strlen(PACKAGE_STRING) + 5,
PU_STATIC, NULL);
- sprintf(buf, "%s - %s", gamedescription, PACKAGE_STRING);
+ sprintf(buf, "%s - %s", window_title, PACKAGE_STRING);
SDL_WM_SetCaption(buf, NULL);
@@ -1015,7 +1224,7 @@ void I_SetWindowCaption(void)
// Set the application icon
-void I_SetWindowIcon(void)
+static void I_InitWindowIcon(void)
{
SDL_Surface *surface;
Uint8 *mask;
@@ -1405,11 +1614,19 @@ static void SetScaleFactor(int factor)
}
}
-static void CheckCommandLine(void)
+void I_GraphicsCheckCommandLine(void)
{
int i;
//!
+ // @vanilla
+ //
+ // Disable blitting the screen.
+ //
+
+ noblit = M_CheckParm ("-noblit");
+
+ //!
// @category video
//
// Grab the mouse when running in windowed mode.
@@ -1571,6 +1788,28 @@ static void CheckCommandLine(void)
{
SetScaleFactor(3);
}
+
+ //!
+ // @category video
+ //
+ // Disable vertical mouse movement.
+ //
+
+ if (M_CheckParm("-novert"))
+ {
+ novert = true;
+ }
+
+ //!
+ // @category video
+ //
+ // Enable vertical mouse movement.
+ //
+
+ if (M_CheckParm("-nonovert"))
+ {
+ novert = false;
+ }
}
// Check if we have been invoked as a screensaver by xscreensaver.
@@ -1648,6 +1887,27 @@ static void SetSDLVideoDriver(void)
#endif
}
+static void SetWindowPositionVars(void)
+{
+ char buf[64];
+ int x, y;
+
+ if (window_position == NULL || !strcmp(window_position, ""))
+ {
+ return;
+ }
+
+ if (!strcmp(window_position, "center"))
+ {
+ putenv("SDL_VIDEO_CENTERED=1");
+ }
+ else if (sscanf(window_position, "%i,%i", &x, &y) == 2)
+ {
+ sprintf(buf, "SDL_VIDEO_WINDOW_POS=%i,%i", x, y);
+ putenv(buf);
+ }
+}
+
static char *WindowBoxType(screen_mode_t *mode, int w, int h)
{
if (mode->width != w && mode->height != h)
@@ -1819,22 +2079,19 @@ void I_InitGraphics(void)
}
SetSDLVideoDriver();
+ SetWindowPositionVars();
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
I_Error("Failed to initialize video: %s", SDL_GetError());
}
- // Check for command-line video-related parameters.
-
- CheckCommandLine();
-
// Set up title and icon. Windows cares about the ordering; this
// has to be done before the call to SDL_SetVideoMode.
- I_SetWindowCaption();
+ I_InitWindowTitle();
#if !SDL_VERSION_ATLEAST(1, 3, 0)
- I_SetWindowIcon();
+ I_InitWindowIcon();
#endif
//
@@ -1920,23 +2177,21 @@ void I_InitGraphics(void)
if (native_surface)
{
- screens[0] = (unsigned char *) screen->pixels;
+ I_VideoBuffer = (unsigned char *) screen->pixels;
- screens[0] += (screen->h - SCREENHEIGHT) / 2;
+ I_VideoBuffer += (screen->h - SCREENHEIGHT) / 2;
}
else
{
- screens[0] = (unsigned char *) Z_Malloc (SCREENWIDTH * SCREENHEIGHT,
- PU_STATIC, NULL);
+ I_VideoBuffer = (unsigned char *) Z_Malloc (SCREENWIDTH * SCREENHEIGHT,
+ PU_STATIC, NULL);
}
- // "Loading from disk" icon
-
- LoadDiskImage();
+ V_RestoreBuffer();
// Clear the screen to black.
- memset(screens[0], 0, SCREENWIDTH * SCREENHEIGHT);
+ memset(I_VideoBuffer, 0, SCREENWIDTH * SCREENHEIGHT);
// We need SDL to give us translated versions of keys as well
@@ -1958,5 +2213,52 @@ void I_InitGraphics(void)
}
initialized = true;
+
+ // Call I_ShutdownGraphics on quit
+
+ I_AtExit(I_ShutdownGraphics, true);
}
+// Bind all variables controlling video options into the configuration
+// file system.
+
+void I_BindVideoVariables(void)
+{
+ M_BindVariable("use_mouse", &usemouse);
+ M_BindVariable("autoadjust_video_settings", &autoadjust_video_settings);
+ M_BindVariable("fullscreen", &fullscreen);
+ M_BindVariable("aspect_ratio_correct", &aspect_ratio_correct);
+ M_BindVariable("startup_delay", &startup_delay);
+ M_BindVariable("screen_width", &screen_width);
+ M_BindVariable("screen_height", &screen_height);
+ M_BindVariable("screen_bpp", &screen_bpp);
+ M_BindVariable("grabmouse", &grabmouse);
+ M_BindVariable("mouse_acceleration", &mouse_acceleration);
+ M_BindVariable("mouse_threshold", &mouse_threshold);
+ M_BindVariable("video_driver", &video_driver);
+ M_BindVariable("window_position", &window_position);
+ M_BindVariable("usegamma", &usegamma);
+ M_BindVariable("vanilla_keyboard_mapping", &vanilla_keyboard_mapping);
+ M_BindVariable("novert", &novert);
+
+ // Windows Vista or later? Set screen color depth to
+ // 32 bits per pixel, as 8-bit palettized screen modes
+ // don't work properly in recent versions.
+
+#if defined(_WIN32) && !defined(_WIN32_WCE)
+ {
+ OSVERSIONINFOEX version_info;
+
+ ZeroMemory(&version_info, sizeof(OSVERSIONINFOEX));
+ version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+
+ GetVersionEx((OSVERSIONINFO *) &version_info);
+
+ if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT
+ && version_info.dwMajorVersion >= 6)
+ {
+ screen_bpp = 32;
+ }
+ }
+#endif
+}
diff --git a/src/i_video.h b/src/i_video.h
index 44fe1cd2..7cc45dc9 100644
--- a/src/i_video.h
+++ b/src/i_video.h
@@ -30,73 +30,106 @@
#include "doomtype.h"
+// Screen width and height.
+
+#define SCREENWIDTH 320
+#define SCREENHEIGHT 200
+
+// Screen width used for "squash" scale functions
+
+#define SCREENWIDTH_4_3 256
+
+// Screen height used for "stretch" scale functions.
+
+#define SCREENHEIGHT_4_3 240
+
#define MAX_MOUSE_BUTTONS 8
typedef struct
{
- // Screen width and height
+ // Screen width and height
- int width;
- int height;
+ int width;
+ int height;
- // Initialisation function to call when using this mode.
- // Called with a pointer to the Doom palette.
- //
- // If NULL, no init function is called.
+ // Initialisation function to call when using this mode.
+ // Called with a pointer to the Doom palette.
+ //
+ // If NULL, no init function is called.
- void (*InitMode)(byte *palette);
-
- // Function to call to draw the screen from the source buffer.
- // Return true if draw was successful.
+ void (*InitMode)(byte *palette);
+
+ // Function to call to draw the screen from the source buffer.
+ // Return true if draw was successful.
- boolean (*DrawScreen)(int x1, int y1, int x2, int y2);
+ boolean (*DrawScreen)(int x1, int y1, int x2, int y2);
- // If true, this is a "poor quality" mode. The autoadjust
- // code should always attempt to use a different mode to this
- // mode in fullscreen.
+ // If true, this is a "poor quality" mode. The autoadjust
+ // code should always attempt to use a different mode to this
+ // mode in fullscreen.
- boolean poor_quality;
+ boolean poor_quality;
} screen_mode_t;
+typedef boolean (*grabmouse_callback_t)(void);
+
// Called by D_DoomMain,
// determines the hardware configuration
// and sets up the video mode
void I_InitGraphics (void);
+void I_GraphicsCheckCommandLine(void);
void I_ShutdownGraphics(void);
// Takes full 8 bit values.
void I_SetPalette (byte* palette);
+int I_GetPaletteIndex(int r, int g, int b);
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);
-void I_SetWindowCaption(void);
-void I_SetWindowIcon(void);
+void I_SetWindowTitle(char *title);
void I_CheckIsScreensaver(void);
+void I_SetGrabMouseCallback(grabmouse_callback_t func);
+
+void I_DisplayFPSDots(boolean dots_on);
+void I_BindVideoVariables(void);
+
+// Called before processing any tics in a frame (just after displaying a frame).
+// Time consuming syncronous operations are performed here (joystick reading).
+
+void I_StartFrame (void);
+
+// Called before processing each tic in a frame.
+// Quick syncronous operations are performed here.
+
+void I_StartTic (void);
+
+// Enable the loading disk image displayed when reading from disk.
+
+void I_EnableLoadingDisk(void);
extern char *video_driver;
-extern int autoadjust_video_settings;
extern boolean screenvisible;
-extern int screen_width, screen_height;
-extern int screen_bpp;
-extern int fullscreen;
-extern int aspect_ratio_correct;
-extern int grabmouse;
+
extern float mouse_acceleration;
extern int mouse_threshold;
-extern int startup_delay;
extern int vanilla_keyboard_mapping;
+extern boolean screensaver_mode;
+extern int usegamma;
+extern byte *I_VideoBuffer;
-#endif
+extern int screen_width;
+extern int screen_height;
+extern int screen_bpp;
+extern int fullscreen;
+extern int aspect_ratio_correct;
+#endif
diff --git a/src/i_videohr.c b/src/i_videohr.c
new file mode 100644
index 00000000..94fc5309
--- /dev/null
+++ b/src/i_videohr.c
@@ -0,0 +1,222 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// SDL emulation of VGA 640x480x4 planar video mode,
+// for Hexen startup loading screen.
+//
+//-----------------------------------------------------------------------------
+
+#include "SDL.h"
+#include "string.h"
+
+#include "doomtype.h"
+#include "i_timer.h"
+
+// Palette fade-in takes two seconds
+
+#define FADE_TIME 2000
+
+#define HR_SCREENWIDTH 640
+#define HR_SCREENHEIGHT 480
+
+static SDL_Surface *hr_surface = NULL;
+static char *window_title = "";
+
+boolean I_SetVideoModeHR(void)
+{
+ Uint32 flags;
+
+ if (SDL_Init(SDL_INIT_VIDEO) < 0)
+ {
+ return false;
+ }
+
+ SDL_WM_SetCaption(window_title, NULL);
+
+ flags = SDL_SWSURFACE | SDL_HWPALETTE | SDL_DOUBLEBUF;
+
+ hr_surface = SDL_SetVideoMode(HR_SCREENWIDTH, HR_SCREENHEIGHT, 8, flags);
+
+ if (hr_surface == NULL)
+ {
+ SDL_QuitSubSystem(SDL_INIT_VIDEO);
+ return false;
+ }
+
+ return true;
+}
+
+void I_SetWindowTitleHR(char *title)
+{
+ window_title = title;
+}
+
+void I_UnsetVideoModeHR(void)
+{
+ if (hr_surface != NULL)
+ {
+ SDL_QuitSubSystem(SDL_INIT_VIDEO);
+ hr_surface = NULL;
+ }
+}
+
+void I_ClearScreenHR(void)
+{
+ SDL_Rect area = { 0, 0, HR_SCREENWIDTH, HR_SCREENHEIGHT };
+
+ SDL_FillRect(hr_surface, &area, 0);
+}
+
+void I_SlamBlockHR(int x, int y, int w, int h, const byte *src)
+{
+ const byte *srcptrs[4];
+ byte srcbits[4];
+ byte *dest;
+ int x1, y1;
+ int i;
+ int bit;
+
+ // Set up source pointers to read from source buffer - each 4-bit
+ // pixel has its bits split into four sub-buffers
+
+ for (i=0; i<4; ++i)
+ {
+ srcptrs[i] = src + (i * w * h / 8);
+ }
+
+ if (SDL_LockSurface(hr_surface) < 0)
+ {
+ return;
+ }
+
+ // Draw each pixel
+
+ bit = 0;
+
+ for (y1=y; y1<y+h; ++y1)
+ {
+ dest = ((byte *) hr_surface->pixels) + y1 * hr_surface->pitch + x;
+
+ for (x1=x; x1<x+w; ++x1)
+ {
+ // Get the bits for this pixel
+ // For each bit, find the byte containing it, shift down
+ // and mask out the specific bit wanted.
+
+ for (i=0; i<4; ++i)
+ {
+ srcbits[i] = (srcptrs[i][bit / 8] >> (7 - (bit % 8))) & 0x1;
+ }
+
+ // Reassemble the pixel value
+
+ *dest = (srcbits[0] << 0)
+ | (srcbits[1] << 1)
+ | (srcbits[2] << 2)
+ | (srcbits[3] << 3);
+
+ // Next pixel!
+
+ ++dest;
+ ++bit;
+ }
+ }
+
+ SDL_UnlockSurface(hr_surface);
+
+ // Update the region we drew.
+
+ //SDL_UpdateRect(hr_surface, x, y, w, h);
+ SDL_Flip(hr_surface);
+}
+
+void I_SlamHR(const byte *buffer)
+{
+ I_SlamBlockHR(0, 0, HR_SCREENWIDTH, HR_SCREENHEIGHT, buffer);
+}
+
+void I_InitPaletteHR(void)
+{
+ // ...
+}
+
+void I_SetPaletteHR(const byte *palette)
+{
+ SDL_Color sdlpal[16];
+ int i;
+
+ for (i=0; i<16; ++i)
+ {
+ sdlpal[i].r = palette[i * 3 + 0] * 4;
+ sdlpal[i].g = palette[i * 3 + 1] * 4;
+ sdlpal[i].b = palette[i * 3 + 2] * 4;
+ }
+
+ SDL_SetColors(hr_surface, sdlpal, 0, 16);
+}
+
+void I_FadeToPaletteHR(const byte *palette)
+{
+ byte tmppal[16 * 3];
+ int starttime;
+ int elapsed;
+ int i;
+
+ starttime = I_GetTimeMS();
+
+ for (;;)
+ {
+ elapsed = I_GetTimeMS() - starttime;
+
+ if (elapsed >= FADE_TIME)
+ {
+ break;
+ }
+
+ // Generate the fake palette
+
+ for (i=0; i<16 * 3; ++i)
+ {
+ tmppal[i] = (palette[i] * elapsed) / FADE_TIME;
+ }
+
+ I_SetPaletteHR(tmppal);
+ SDL_Flip(hr_surface);
+
+ // Sleep a bit
+
+ I_Sleep(10);
+ }
+
+ // Set the final palette
+
+ I_SetPaletteHR(palette);
+}
+
+void I_BlackPaletteHR(void)
+{
+ byte blackpal[16 * 3];
+
+ memset(blackpal, 0, sizeof(blackpal));
+
+ I_SetPaletteHR(blackpal);
+}
+
diff --git a/src/i_videohr.h b/src/i_videohr.h
new file mode 100644
index 00000000..5de5158f
--- /dev/null
+++ b/src/i_videohr.h
@@ -0,0 +1,42 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// SDL emulation of VGA 640x480x4 planar video mode,
+// for Hexen startup loading screen.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef I_VIDEOHR_H
+#define I_VIDEOHR_H
+
+boolean I_SetVideoModeHR(void);
+void I_UnsetVideoModeHR(void);
+void I_SetWindowTitleHR(char *title);
+void I_ClearScreenHR(void);
+void I_SlamBlockHR(int x, int y, int w, int h, const byte *src);
+void I_SlamHR(const byte *buffer);
+void I_InitPaletteHR(void);
+void I_SetPaletteHR(const byte *palette);
+void I_FadeToPaletteHR(const byte *palette);
+void I_BlackPaletteHR(void);
+
+#endif /* #ifndef I_VIDEOHR_H */
+
diff --git a/src/m_argv.c b/src/m_argv.c
index 4d321bbc..2a126c4b 100644
--- a/src/m_argv.c
+++ b/src/m_argv.c
@@ -29,9 +29,10 @@
#include <stdlib.h>
#include <string.h>
-#include "doomdef.h"
+#include "doomtype.h"
#include "i_system.h"
#include "m_misc.h"
+#include "m_argv.h" // haleyjd 20110212: warning fix
int myargc;
char** myargv;
@@ -60,13 +61,25 @@ int M_CheckParmWithArgs(char *check, int num_args)
return 0;
}
+//
+// M_ParmExists
+//
+// Returns true if the given parameter exists in the program's command
+// line arguments, false if not.
+//
+
+boolean M_ParmExists(char *check)
+{
+ return M_CheckParm(check) != 0;
+}
+
int M_CheckParm(char *check)
{
return M_CheckParmWithArgs(check, 0);
}
#define MAXARGVS 100
-
+
static void LoadResponseFile(int argv_index)
{
FILE *handle;
@@ -95,14 +108,23 @@ static void LoadResponseFile(int argv_index)
// Read in the entire file
// Allocate one byte extra - this is in case there is an argument
- // at the end of the response file, in which case a '\0' will be
+ // at the end of the response file, in which case a '\0' will be
// needed.
file = malloc(size + 1);
- if (fread(file, 1, size, handle) < size)
+ i = 0;
+
+ while (i < size)
{
- I_Error("Failed to read entire response file");
+ k = fread(file + i, 1, size - i, handle);
+
+ if (k < 0)
+ {
+ I_Error("Failed to read full contents of '%s'", response_filename);
+ }
+
+ i += k;
}
fclose(handle);
@@ -120,7 +142,7 @@ static void LoadResponseFile(int argv_index)
newargv[i] = myargv[i];
++newargc;
}
-
+
infile = file;
k = 0;
@@ -131,7 +153,7 @@ static void LoadResponseFile(int argv_index)
while(k < size && isspace(infile[k]))
{
++k;
- }
+ }
if (k >= size)
{
@@ -142,7 +164,7 @@ static void LoadResponseFile(int argv_index)
// the contents as a single argument. This allows long filenames
// to be specified.
- if (infile[k] == '\"')
+ if (infile[k] == '\"')
{
// Skip the first character(")
++k;
@@ -156,9 +178,9 @@ static void LoadResponseFile(int argv_index)
++k;
}
- if (k >= size || infile[k] == '\n')
+ if (k >= size || infile[k] == '\n')
{
- I_Error("Quotes unclosed in response file '%s'",
+ I_Error("Quotes unclosed in response file '%s'",
response_filename);
}
@@ -184,7 +206,7 @@ static void LoadResponseFile(int argv_index)
++k;
}
- }
+ }
// Add arguments following the response file argument
@@ -227,3 +249,21 @@ void M_FindResponseFile(void)
}
}
+// Return the name of the executable used to start the program:
+
+char *M_GetExecutableName(void)
+{
+ char *sep;
+
+ sep = strrchr(myargv[0], DIR_SEPARATOR);
+
+ if (sep == NULL)
+ {
+ return myargv[0];
+ }
+ else
+ {
+ return sep + 1;
+ }
+}
+
diff --git a/src/m_argv.h b/src/m_argv.h
index f5b26f94..2fb76a2a 100644
--- a/src/m_argv.h
+++ b/src/m_argv.h
@@ -28,6 +28,8 @@
#ifndef __M_ARGV__
#define __M_ARGV__
+#include "doomtype.h"
+
//
// MISC
//
@@ -44,4 +46,12 @@ int M_CheckParmWithArgs(char *check, int num_args);
void M_FindResponseFile(void);
+// Parameter has been specified?
+
+boolean M_ParmExists(char *check);
+
+// Get name of executable used to run this program:
+
+char *M_GetExecutableName(void);
+
#endif
diff --git a/src/m_config.c b/src/m_config.c
index d0fd5185..8f1a2aa4 100644
--- a/src/m_config.c
+++ b/src/m_config.c
@@ -2,6 +2,7 @@
//-----------------------------------------------------------------------------
//
// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
// Copyright(C) 2005 Simon Howard
//
// This program is free software; you can redistribute it and/or
@@ -19,7 +20,6 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
-//
// DESCRIPTION:
// Configuration file interface.
//
@@ -28,46 +28,20 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <ctype.h>
#include <errno.h>
-#ifdef _WIN32
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#endif
-
-#include "SDL_mixer.h"
-
#include "config.h"
-#include "deh_main.h"
-#include "doomdef.h"
-#include "doomfeatures.h"
-
-#include "z_zone.h"
-
-#include "m_menu.h"
-#include "m_argv.h"
-#include "net_client.h"
-#include "w_wad.h"
-
-#include "i_joystick.h"
-#include "i_swap.h"
+#include "doomtype.h"
+#include "doomkeys.h"
+#include "doomfeatures.h"
#include "i_system.h"
-#include "i_video.h"
-#include "s_sound.h"
-#include "v_video.h"
-
-#include "hu_stuff.h"
-
-// State.
-#include "doomstat.h"
-
-// Data.
-#include "dstrings.h"
-
+#include "m_argv.h"
#include "m_misc.h"
+#include "z_zone.h"
//
// DEFAULTS
@@ -76,144 +50,12 @@
// Location where all configuration data is stored -
// default.cfg, savegames, etc.
-char * configdir;
-
-
-int usemouse = 1;
-int usejoystick = 0;
-
-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 key_pause;
-
-// Menu control keys:
-
-extern int key_menu_activate;
-extern int key_menu_up;
-extern int key_menu_down;
-extern int key_menu_left;
-extern int key_menu_right;
-extern int key_menu_back;
-extern int key_menu_forward;
-extern int key_menu_confirm;
-extern int key_menu_abort;
-
-// Keyboard shortcuts:
-
-extern int key_menu_help;
-extern int key_menu_save;
-extern int key_menu_load;
-extern int key_menu_volume;
-extern int key_menu_detail;
-extern int key_menu_qsave;
-extern int key_menu_endgame;
-extern int key_menu_messages;
-extern int key_menu_qload;
-extern int key_menu_quit;
-extern int key_menu_gamma;
-extern int key_spy;
-
-extern int key_menu_incscreen;
-extern int key_menu_decscreen;
-
-extern int key_map_north;
-extern int key_map_south;
-extern int key_map_east;
-extern int key_map_west;
-extern int key_map_zoomin;
-extern int key_map_zoomout;
-extern int key_map_toggle;
-extern int key_map_maxzoom;
-extern int key_map_follow;
-extern int key_map_grid;
-extern int key_map_mark;
-extern int key_map_clearmark;
-
-extern int key_weapon1;
-extern int key_weapon2;
-extern int key_weapon3;
-extern int key_weapon4;
-extern int key_weapon5;
-extern int key_weapon6;
-extern int key_weapon7;
-extern int key_weapon8;
-extern int key_prevweapon;
-extern int key_nextweapon;
-
-extern int key_message_refresh;
-extern int key_demo_quit;
-
-extern int key_multi_msg;
-extern int key_multi_msgplayer[];
-
-extern int mousebfire;
-extern int mousebstrafe;
-extern int mousebforward;
-
-extern int mousebstrafeleft;
-extern int mousebstraferight;
-extern int mousebbackward;
-extern int mousebuse;
-
-extern int mousebprevweapon;
-extern int mousebnextweapon;
-
-extern int dclick_use;
-
-extern int joybfire;
-extern int joybstrafe;
-extern int joybuse;
-extern int joybspeed;
-extern int joybstrafeleft;
-extern int joybstraferight;
-
-extern int joybprevweapon;
-extern int joybnextweapon;
-
-extern int viewwidth;
-extern int viewheight;
-
-extern int mouseSensitivity;
-extern int showMessages;
-
-// machine-independent sound params
-extern int numChannels;
-
-
-extern char* chat_macros[];
-
-extern int show_endoom;
-extern int vanilla_savegame_limit;
-extern int vanilla_demo_limit;
-
-extern int snd_musicdevice;
-extern int snd_sfxdevice;
-extern int snd_samplerate;
-extern int opl_io_port;
-
-// controls whether to use libsamplerate for sample rate conversions
-
-extern int use_libsamplerate;
-
-// dos specific options: these are unused but should be maintained
-// so that the config file can be shared between chocolate
-// doom and doom.exe
-
-static int snd_sbport = 0;
-static int snd_sbirq = 0;
-static int snd_sbdma = 0;
-static int snd_mport = 0;
+char *configdir;
+
+// Default filenames for configuration files.
+
+static char *default_main_config;
+static char *default_extra_config;
typedef enum
{
@@ -227,10 +69,10 @@ typedef enum
typedef struct
{
// Name of the variable
- char * name;
+ char *name;
// Pointer to the location in memory of the variable
- void * location;
+ void *location;
// Type of the variable
default_type_t type;
@@ -238,118 +80,325 @@ typedef struct
// If this is a key value, the original integer scancode we read from
// the config file before translating it to the internal key value.
// If zero, we didn't read this value from a config file.
- int untranslated;
+ int untranslated;
// The value we translated the scancode into when we read the
// config file on startup. If the variable value is different from
// this, it has been changed and needs to be converted; otherwise,
// use the 'untranslated' value.
- int original_translated;
+ int original_translated;
+
+ // If true, this config variable has been bound to a variable
+ // and is being used.
+ boolean bound;
} default_t;
typedef struct
{
default_t *defaults;
- int numdefaults;
- char *filename;
+ int numdefaults;
+ char *filename;
} default_collection_t;
-#define CONFIG_VARIABLE_GENERIC(name, variable, type) \
- { #name, &variable, type, 0, 0 }
+#define CONFIG_VARIABLE_GENERIC(name, type) \
+ { #name, NULL, type, 0, 0, false }
-#define CONFIG_VARIABLE_KEY(name, variable) \
- CONFIG_VARIABLE_GENERIC(name, variable, DEFAULT_KEY)
-#define CONFIG_VARIABLE_INT(name, variable) \
- CONFIG_VARIABLE_GENERIC(name, variable, DEFAULT_INT)
-#define CONFIG_VARIABLE_INT_HEX(name, variable) \
- CONFIG_VARIABLE_GENERIC(name, variable, DEFAULT_INT_HEX)
-#define CONFIG_VARIABLE_FLOAT(name, variable) \
- CONFIG_VARIABLE_GENERIC(name, variable, DEFAULT_FLOAT)
-#define CONFIG_VARIABLE_STRING(name, variable) \
- CONFIG_VARIABLE_GENERIC(name, variable, DEFAULT_STRING)
+#define CONFIG_VARIABLE_KEY(name) \
+ CONFIG_VARIABLE_GENERIC(name, DEFAULT_KEY)
+#define CONFIG_VARIABLE_INT(name) \
+ CONFIG_VARIABLE_GENERIC(name, DEFAULT_INT)
+#define CONFIG_VARIABLE_INT_HEX(name) \
+ CONFIG_VARIABLE_GENERIC(name, DEFAULT_INT_HEX)
+#define CONFIG_VARIABLE_FLOAT(name) \
+ CONFIG_VARIABLE_GENERIC(name, DEFAULT_FLOAT)
+#define CONFIG_VARIABLE_STRING(name) \
+ CONFIG_VARIABLE_GENERIC(name, DEFAULT_STRING)
-//! @begin_config_file default.cfg
+//! @begin_config_file default
static default_t doom_defaults_list[] =
{
- //!
+ //!
// Mouse sensitivity. This value is used to multiply input mouse
// movement to control the effect of moving the mouse.
//
- // The "normal" maximum value available for this through the
+ // The "normal" maximum value available for this through the
// in-game options menu is 9. A value of 31 or greater will cause
// the game to crash when entering the options menu.
//
- CONFIG_VARIABLE_INT(mouse_sensitivity, mouseSensitivity),
+ CONFIG_VARIABLE_INT(mouse_sensitivity),
//!
// Volume of sound effects, range 0-15.
//
- CONFIG_VARIABLE_INT(sfx_volume, sfxVolume),
+ CONFIG_VARIABLE_INT(sfx_volume),
//!
// Volume of in-game music, range 0-15.
//
- CONFIG_VARIABLE_INT(music_volume, musicVolume),
+ CONFIG_VARIABLE_INT(music_volume),
//!
+ // @game strife
+ //
+ // If non-zero, dialogue text is displayed over characters' pictures
+ // when engaging actors who have voices.
+ //
+
+ CONFIG_VARIABLE_INT(show_talk),
+
+ //!
+ // @game strife
+ //
+ // Volume of voice sound effects, range 0-15.
+ //
+
+ CONFIG_VARIABLE_INT(voice_volume),
+
+ //!
+ // @game doom
+ //
// If non-zero, messages are displayed on the heads-up display
// in the game ("picked up a clip", etc). If zero, these messages
// are not displayed.
//
- CONFIG_VARIABLE_INT(show_messages, showMessages),
+ CONFIG_VARIABLE_INT(show_messages),
- //!
+ //!
// Keyboard key to turn right.
//
- CONFIG_VARIABLE_KEY(key_right, key_right),
+ CONFIG_VARIABLE_KEY(key_right),
//!
// Keyboard key to turn left.
//
- CONFIG_VARIABLE_KEY(key_left, key_left),
+ CONFIG_VARIABLE_KEY(key_left),
//!
// Keyboard key to move forward.
//
- CONFIG_VARIABLE_KEY(key_up, key_up),
+ CONFIG_VARIABLE_KEY(key_up),
//!
// Keyboard key to move backward.
//
- CONFIG_VARIABLE_KEY(key_down, key_down),
+ CONFIG_VARIABLE_KEY(key_down),
//!
// Keyboard key to strafe left.
//
- CONFIG_VARIABLE_KEY(key_strafeleft, key_strafeleft),
+ CONFIG_VARIABLE_KEY(key_strafeleft),
//!
// Keyboard key to strafe right.
//
- CONFIG_VARIABLE_KEY(key_straferight, key_straferight),
+ CONFIG_VARIABLE_KEY(key_straferight),
+
+ //!
+ // @game strife
+ //
+ // Keyboard key to use health.
+ //
+
+ CONFIG_VARIABLE_KEY(key_useHealth),
+
+ //!
+ // @game hexen
+ //
+ // Keyboard key to jump.
+ //
+
+ CONFIG_VARIABLE_KEY(key_jump),
+
+ //!
+ // @game heretic hexen
+ //
+ // Keyboard key to fly upward.
+ //
+
+ CONFIG_VARIABLE_KEY(key_flyup),
+
+ //!
+ // @game heretic hexen
+ //
+ // Keyboard key to fly downwards.
+ //
+
+ CONFIG_VARIABLE_KEY(key_flydown),
+
+ //!
+ // @game heretic hexen
+ //
+ // Keyboard key to center flying.
+ //
+
+ CONFIG_VARIABLE_KEY(key_flycenter),
+
+ //!
+ // @game heretic hexen
+ //
+ // Keyboard key to look up.
+ //
+
+ CONFIG_VARIABLE_KEY(key_lookup),
+
+ //!
+ // @game heretic hexen
+ //
+ // Keyboard key to look down.
+ //
+
+ CONFIG_VARIABLE_KEY(key_lookdown),
+
+ //!
+ // @game heretic hexen
+ //
+ // Keyboard key to center the view.
+ //
+
+ CONFIG_VARIABLE_KEY(key_lookcenter),
+
+ //!
+ // @game strife
+ //
+ // Keyboard key to query inventory.
+ //
+
+ CONFIG_VARIABLE_KEY(key_invquery),
+
+ //!
+ // @game strife
+ //
+ // Keyboard key to display mission objective.
+ //
+
+ CONFIG_VARIABLE_KEY(key_mission),
+
+ //!
+ // @game strife
+ //
+ // Keyboard key to display inventory popup.
+ //
+
+ CONFIG_VARIABLE_KEY(key_invPop),
+
+ //!
+ // @game strife
+ //
+ // Keyboard key to display keys popup.
+ //
+
+ CONFIG_VARIABLE_KEY(key_invKey),
+
+ //!
+ // @game strife
+ //
+ // Keyboard key to jump to start of inventory.
+ //
+
+ CONFIG_VARIABLE_KEY(key_invHome),
+
+ //!
+ // @game strife
+ //
+ // Keyboard key to jump to end of inventory.
+ //
+
+ CONFIG_VARIABLE_KEY(key_invEnd),
+
+ //!
+ // @game heretic hexen
+ //
+ // Keyboard key to scroll left in the inventory.
+ //
+
+ CONFIG_VARIABLE_KEY(key_invleft),
+
+ //!
+ // @game heretic hexen
+ //
+ // Keyboard key to scroll right in the inventory.
+ //
+
+ CONFIG_VARIABLE_KEY(key_invright),
+
+ //!
+ // @game strife
+ //
+ // Keyboard key to scroll left in the inventory.
+ //
+
+ CONFIG_VARIABLE_KEY(key_invLeft),
+
+ //!
+ // @game strife
+ //
+ // Keyboard key to scroll right in the inventory.
+ //
+
+ CONFIG_VARIABLE_KEY(key_invRight),
+
+ //!
+ // @game heretic hexen
+ //
+ // Keyboard key to use the current item in the inventory.
+ //
+
+ CONFIG_VARIABLE_KEY(key_useartifact),
+
+ //!
+ // @game strife
+ //
+ // Keyboard key to use inventory item.
+ //
+
+ CONFIG_VARIABLE_KEY(key_invUse),
+
+ //!
+ // @game strife
+ //
+ // Keyboard key to drop an inventory item.
+ //
+
+ CONFIG_VARIABLE_KEY(key_invDrop),
+
+ //!
+ // @game strife
+ //
+ // Keyboard key to look up.
+ //
+
+ CONFIG_VARIABLE_KEY(key_lookUp),
+
+ //!
+ // @game strife
+ //
+ // Keyboard key to look down.
+ //
+
+ CONFIG_VARIABLE_KEY(key_lookDown),
//!
// Keyboard key to fire the currently selected weapon.
//
- CONFIG_VARIABLE_KEY(key_fire, key_fire),
+ CONFIG_VARIABLE_KEY(key_fire),
//!
// Keyboard key to "use" an object, eg. a door or switch.
//
- CONFIG_VARIABLE_KEY(key_use, key_use),
+ CONFIG_VARIABLE_KEY(key_use),
//!
// Keyboard key to turn on strafing. When held down, pressing the
@@ -357,63 +406,71 @@ static default_t doom_defaults_list[] =
// right instead.
//
- CONFIG_VARIABLE_KEY(key_strafe, key_strafe),
+ CONFIG_VARIABLE_KEY(key_strafe),
//!
// Keyboard key to make the player run.
//
- CONFIG_VARIABLE_KEY(key_speed, key_speed),
+ CONFIG_VARIABLE_KEY(key_speed),
//!
// If non-zero, mouse input is enabled. If zero, mouse input is
// disabled.
//
- CONFIG_VARIABLE_INT(use_mouse, usemouse),
+ CONFIG_VARIABLE_INT(use_mouse),
//!
// Mouse button to fire the currently selected weapon.
//
- CONFIG_VARIABLE_INT(mouseb_fire, mousebfire),
+ CONFIG_VARIABLE_INT(mouseb_fire),
//!
// Mouse button to turn on strafing. When held down, the player
// will strafe left and right instead of turning left and right.
//
- CONFIG_VARIABLE_INT(mouseb_strafe, mousebstrafe),
+ CONFIG_VARIABLE_INT(mouseb_strafe),
//!
// Mouse button to move forward.
//
- CONFIG_VARIABLE_INT(mouseb_forward, mousebforward),
+ CONFIG_VARIABLE_INT(mouseb_forward),
+
+ //!
+ // @game hexen strife
+ //
+ // Mouse button to jump.
+ //
+
+ CONFIG_VARIABLE_INT(mouseb_jump),
//!
// If non-zero, joystick input is enabled.
//
- CONFIG_VARIABLE_INT(use_joystick, usejoystick),
+ CONFIG_VARIABLE_INT(use_joystick),
//!
// Joystick button to fire the current weapon.
//
- CONFIG_VARIABLE_INT(joyb_fire, joybfire),
+ CONFIG_VARIABLE_INT(joyb_fire),
//!
// Joystick button to fire the current weapon.
//
- CONFIG_VARIABLE_INT(joyb_strafe, joybstrafe),
+ CONFIG_VARIABLE_INT(joyb_strafe),
//!
// Joystick button to "use" an object, eg. a door or switch.
//
- CONFIG_VARIABLE_INT(joyb_use, joybuse),
+ CONFIG_VARIABLE_INT(joyb_use),
//!
// Joystick button to make the player run.
@@ -421,181 +478,254 @@ static default_t doom_defaults_list[] =
// If this has a value of 20 or greater, the player will always run.
//
- CONFIG_VARIABLE_INT(joyb_speed, joybspeed),
+ CONFIG_VARIABLE_INT(joyb_speed),
+
+ //!
+ // @game hexen strife
+ //
+ // Joystick button to jump.
+ //
+
+ CONFIG_VARIABLE_INT(joyb_jump),
+
+ //!
+ // @game doom heretic hexen
+ //
+ // Screen size, range 3-11.
+ //
+ // A value of 11 gives a full-screen view with the status bar not
+ // displayed. A value of 10 gives a full-screen view with the
+ // status bar displayed.
+ //
+
+ CONFIG_VARIABLE_INT(screenblocks),
//!
+ // @game strife
+ //
// Screen size, range 3-11.
//
- // A value of 11 gives a full-screen view with the status bar not
+ // A value of 11 gives a full-screen view with the status bar not
// displayed. A value of 10 gives a full-screen view with the
// status bar displayed.
//
- CONFIG_VARIABLE_INT(screenblocks, screenblocks),
+ CONFIG_VARIABLE_INT(screensize),
//!
+ // @game doom
+ //
// Screen detail. Zero gives normal "high detail" mode, while
// a non-zero value gives "low detail" mode.
//
- CONFIG_VARIABLE_INT(detaillevel, detailLevel),
+ CONFIG_VARIABLE_INT(detaillevel),
//!
// Number of sounds that will be played simultaneously.
//
- CONFIG_VARIABLE_INT(snd_channels, numChannels),
+ CONFIG_VARIABLE_INT(snd_channels),
//!
// Music output device. A non-zero value gives MIDI sound output,
// while a value of zero disables music.
//
- CONFIG_VARIABLE_INT(snd_musicdevice, snd_musicdevice),
+ CONFIG_VARIABLE_INT(snd_musicdevice),
//!
- // Sound effects device. A value of zero disables in-game sound
- // effects, a value of 1 enables PC speaker sound effects, while
- // a value in the range 2-9 enables the "normal" digital sound
+ // Sound effects device. A value of zero disables in-game sound
+ // effects, a value of 1 enables PC speaker sound effects, while
+ // a value in the range 2-9 enables the "normal" digital sound
// effects.
//
- CONFIG_VARIABLE_INT(snd_sfxdevice, snd_sfxdevice),
+ CONFIG_VARIABLE_INT(snd_sfxdevice),
//!
// SoundBlaster I/O port. Unused.
//
- CONFIG_VARIABLE_INT(snd_sbport, snd_sbport),
+ CONFIG_VARIABLE_INT(snd_sbport),
//!
// SoundBlaster IRQ. Unused.
//
- CONFIG_VARIABLE_INT(snd_sbirq, snd_sbirq),
+ CONFIG_VARIABLE_INT(snd_sbirq),
//!
// SoundBlaster DMA channel. Unused.
//
- CONFIG_VARIABLE_INT(snd_sbdma, snd_sbdma),
+ CONFIG_VARIABLE_INT(snd_sbdma),
//!
// Output port to use for OPL MIDI playback. Unused.
//
- CONFIG_VARIABLE_INT(snd_mport, snd_mport),
+ CONFIG_VARIABLE_INT(snd_mport),
//!
- // Gamma correction level. A value of zero disables gamma
+ // Gamma correction level. A value of zero disables gamma
// correction, while a value in the range 1-4 gives increasing
// levels of gamma correction.
//
- CONFIG_VARIABLE_INT(usegamma, usegamma),
+ CONFIG_VARIABLE_INT(usegamma),
+
+ //!
+ // @game hexen
+ //
+ // Directory in which to store savegames.
+ //
+
+ CONFIG_VARIABLE_STRING(savedir),
+
+ //!
+ // @game hexen
+ //
+ // Controls whether messages are displayed in the heads-up display.
+ // If this has a non-zero value, messages are displayed.
+ //
+
+ CONFIG_VARIABLE_INT(messageson),
+
+ //!
+ // @game strife
+ //
+ // Name of background flat used by view border.
+ //
+
+ CONFIG_VARIABLE_STRING(back_flat),
+
+ //!
+ // @game strife
+ //
+ // Multiplayer nickname (?).
+ //
+
+ CONFIG_VARIABLE_STRING(nickname),
//!
// Multiplayer chat macro: message to send when alt+0 is pressed.
//
- CONFIG_VARIABLE_STRING(chatmacro0, chat_macros[0]),
+ CONFIG_VARIABLE_STRING(chatmacro0),
//!
// Multiplayer chat macro: message to send when alt+1 is pressed.
//
- CONFIG_VARIABLE_STRING(chatmacro1, chat_macros[1]),
+ CONFIG_VARIABLE_STRING(chatmacro1),
//!
// Multiplayer chat macro: message to send when alt+2 is pressed.
//
- CONFIG_VARIABLE_STRING(chatmacro2, chat_macros[2]),
+ CONFIG_VARIABLE_STRING(chatmacro2),
//!
// Multiplayer chat macro: message to send when alt+3 is pressed.
//
- CONFIG_VARIABLE_STRING(chatmacro3, chat_macros[3]),
+ CONFIG_VARIABLE_STRING(chatmacro3),
//!
// Multiplayer chat macro: message to send when alt+4 is pressed.
//
- CONFIG_VARIABLE_STRING(chatmacro4, chat_macros[4]),
+ CONFIG_VARIABLE_STRING(chatmacro4),
//!
// Multiplayer chat macro: message to send when alt+5 is pressed.
//
- CONFIG_VARIABLE_STRING(chatmacro5, chat_macros[5]),
+ CONFIG_VARIABLE_STRING(chatmacro5),
//!
// Multiplayer chat macro: message to send when alt+6 is pressed.
//
- CONFIG_VARIABLE_STRING(chatmacro6, chat_macros[6]),
+ CONFIG_VARIABLE_STRING(chatmacro6),
//!
// Multiplayer chat macro: message to send when alt+7 is pressed.
//
- CONFIG_VARIABLE_STRING(chatmacro7, chat_macros[7]),
+ CONFIG_VARIABLE_STRING(chatmacro7),
//!
// Multiplayer chat macro: message to send when alt+8 is pressed.
//
- CONFIG_VARIABLE_STRING(chatmacro8, chat_macros[8]),
+ CONFIG_VARIABLE_STRING(chatmacro8),
//!
// Multiplayer chat macro: message to send when alt+9 is pressed.
//
- CONFIG_VARIABLE_STRING(chatmacro9, chat_macros[9]),
+ CONFIG_VARIABLE_STRING(chatmacro9),
+
+ //!
+ // @game strife
+ //
+ // Serial port number to use for SERSETUP.EXE (unused).
+ //
+
+ CONFIG_VARIABLE_INT(comport),
};
-static default_collection_t doom_defaults =
+static default_collection_t doom_defaults =
{
doom_defaults_list,
arrlen(doom_defaults_list),
NULL,
};
-//! @begin_config_file chocolate-doom.cfg
+//! @begin_config_file extended
-static default_t extra_defaults_list[] =
+static default_t extra_defaults_list[] =
{
//!
- // If non-zero, video settings will be autoadjusted to a valid
+ // @game heretic hexen strife
+ //
+ // If non-zero, display the graphical startup screen.
+ //
+
+ CONFIG_VARIABLE_INT(graphical_startup),
+
+ //!
+ // If non-zero, video settings will be autoadjusted to a valid
// configuration when the screen_width and screen_height variables
// do not match any valid configuration.
//
- CONFIG_VARIABLE_INT(autoadjust_video_settings, autoadjust_video_settings),
+ CONFIG_VARIABLE_INT(autoadjust_video_settings),
//!
// If non-zero, the game will run in full screen mode. If zero,
// the game will run in a window.
//
- CONFIG_VARIABLE_INT(fullscreen, fullscreen),
+ CONFIG_VARIABLE_INT(fullscreen),
//!
// If non-zero, the screen will be stretched vertically to display
// correctly on a square pixel video mode.
//
- CONFIG_VARIABLE_INT(aspect_ratio_correct, aspect_ratio_correct),
+ CONFIG_VARIABLE_INT(aspect_ratio_correct),
//!
// Number of milliseconds to wait on startup after the video mode
- // has been set, before the game will start. This allows the
- // screen to settle on some monitors that do not display an image
+ // has been set, before the game will start. This allows the
+ // screen to settle on some monitors that do not display an image
// for a brief interval after changing video modes.
//
- CONFIG_VARIABLE_INT(startup_delay, startup_delay),
+ CONFIG_VARIABLE_INT(startup_delay),
//!
// Screen width in pixels. If running in full screen mode, this is
@@ -604,7 +734,7 @@ static default_t extra_defaults_list[] =
// will run.
//
- CONFIG_VARIABLE_INT(screen_width, screen_width),
+ CONFIG_VARIABLE_INT(screen_width),
//!
// Screen height in pixels. If running in full screen mode, this is
@@ -613,13 +743,13 @@ static default_t extra_defaults_list[] =
// will run.
//
- CONFIG_VARIABLE_INT(screen_height, screen_height),
+ CONFIG_VARIABLE_INT(screen_height),
//!
// Color depth of the screen, in bits.
//
- CONFIG_VARIABLE_INT(screen_bpp, screen_bpp),
+ CONFIG_VARIABLE_INT(screen_bpp),
//!
// If this is non-zero, the mouse will be "grabbed" when running
@@ -627,15 +757,15 @@ static default_t extra_defaults_list[] =
// When running full screen, this has no effect.
//
- CONFIG_VARIABLE_INT(grabmouse, grabmouse),
+ CONFIG_VARIABLE_INT(grabmouse),
//!
- // If non-zero, all vertical mouse movement is ignored. This
+ // If non-zero, all vertical mouse movement is ignored. This
// emulates the behavior of the "novert" tool available under DOS
// that performs the same function.
//
- CONFIG_VARIABLE_INT(novert, novert),
+ CONFIG_VARIABLE_INT(novert),
//!
// Mouse acceleration factor. When the speed of mouse movement
@@ -643,7 +773,7 @@ static default_t extra_defaults_list[] =
// multiplied by this value.
//
- CONFIG_VARIABLE_FLOAT(mouse_acceleration, mouse_acceleration),
+ CONFIG_VARIABLE_FLOAT(mouse_acceleration),
//!
// Mouse acceleration threshold. When the speed of mouse movement
@@ -651,70 +781,91 @@ static default_t extra_defaults_list[] =
// acceleration factor (mouse_acceleration).
//
- CONFIG_VARIABLE_INT(mouse_threshold, mouse_threshold),
+ CONFIG_VARIABLE_INT(mouse_threshold),
//!
// Sound output sample rate, in Hz. Typical values to use are
// 11025, 22050, 44100 and 48000.
//
- CONFIG_VARIABLE_INT(snd_samplerate, snd_samplerate),
+ CONFIG_VARIABLE_INT(snd_samplerate),
+
+ //!
+ // Maximum number of bytes to allocate for caching converted sound
+ // effects in memory. If set to zero, there is no limit applied.
+ //
+
+ CONFIG_VARIABLE_INT(snd_cachesize),
//!
// The I/O port to use to access the OPL chip. Only relevant when
// using native OPL music playback.
//
- CONFIG_VARIABLE_INT_HEX(opl_io_port, opl_io_port),
+ CONFIG_VARIABLE_INT_HEX(opl_io_port),
//!
- // If non-zero, the ENDOOM screen is displayed when exiting the
- // game. If zero, the ENDOOM screen is not displayed.
+ // @game doom heretic strife
+ //
+ // If non-zero, the ENDOOM text screen is displayed when exiting the
+ // game. If zero, the ENDOOM screen is not displayed.
//
- CONFIG_VARIABLE_INT(show_endoom, show_endoom),
+ CONFIG_VARIABLE_INT(show_endoom),
//!
- // If non-zero, the Vanilla savegame limit is enforced; if the
+ // @game doom strife
+ //
+ // If non-zero, the Vanilla savegame limit is enforced; if the
// savegame exceeds 180224 bytes in size, the game will exit with
// an error. If this has a value of zero, there is no limit to
// the size of savegames.
//
- CONFIG_VARIABLE_INT(vanilla_savegame_limit, vanilla_savegame_limit),
+ CONFIG_VARIABLE_INT(vanilla_savegame_limit),
//!
- // If non-zero, the Vanilla demo size limit is enforced; the game
+ // @game doom strife
+ //
+ // If non-zero, the Vanilla demo size limit is enforced; the game
// exits with an error when a demo exceeds the demo size limit
// (128KiB by default). If this has a value of zero, there is no
// limit to the size of demos.
//
- CONFIG_VARIABLE_INT(vanilla_demo_limit, vanilla_demo_limit),
+ CONFIG_VARIABLE_INT(vanilla_demo_limit),
//!
// If non-zero, the game behaves like Vanilla Doom, always assuming
- // an American keyboard mapping. If this has a value of zero, the
+ // an American keyboard mapping. If this has a value of zero, the
// native keyboard mapping of the keyboard is used.
//
- CONFIG_VARIABLE_INT(vanilla_keyboard_mapping, vanilla_keyboard_mapping),
+ CONFIG_VARIABLE_INT(vanilla_keyboard_mapping),
//!
// Name of the SDL video driver to use. If this is an empty string,
// the default video driver is used.
//
- CONFIG_VARIABLE_STRING(video_driver, video_driver),
+ CONFIG_VARIABLE_STRING(video_driver),
+
+ //!
+ // Position of the window on the screen when running in windowed
+ // mode. Accepted values are: "" (empty string) - don't care,
+ // "center" - place window at center of screen, "x,y" - place
+ // window at the specified coordinates.
+
+ CONFIG_VARIABLE_STRING(window_position),
#ifdef FEATURE_MULTIPLAYER
//!
- // Name to use in network games for identification. This is only
+ // Name to use in network games for identification. This is only
// used on the "waiting" screen while waiting for the game to start.
//
- CONFIG_VARIABLE_STRING(player_name, net_player_name),
+ CONFIG_VARIABLE_STRING(player_name),
#endif
@@ -723,98 +874,98 @@ static default_t extra_defaults_list[] =
// value ('-1') indicates that no joystick is configured.
//
- CONFIG_VARIABLE_INT(joystick_index, joystick_index),
+ CONFIG_VARIABLE_INT(joystick_index),
//!
// Joystick axis to use to for horizontal (X) movement.
//
- CONFIG_VARIABLE_INT(joystick_x_axis, joystick_x_axis),
+ CONFIG_VARIABLE_INT(joystick_x_axis),
//!
// If non-zero, movement on the horizontal joystick axis is inverted.
//
- CONFIG_VARIABLE_INT(joystick_x_invert, joystick_x_invert),
+ CONFIG_VARIABLE_INT(joystick_x_invert),
//!
// Joystick axis to use to for vertical (Y) movement.
//
- CONFIG_VARIABLE_INT(joystick_y_axis, joystick_y_axis),
+ CONFIG_VARIABLE_INT(joystick_y_axis),
//!
// If non-zero, movement on the vertical joystick axis is inverted.
//
- CONFIG_VARIABLE_INT(joystick_y_invert, joystick_y_invert),
+ CONFIG_VARIABLE_INT(joystick_y_invert),
//!
// Joystick button to strafe left.
//
- CONFIG_VARIABLE_INT(joyb_strafeleft, joybstrafeleft),
+ CONFIG_VARIABLE_INT(joyb_strafeleft),
//!
// Joystick button to strafe right.
//
- CONFIG_VARIABLE_INT(joyb_straferight, joybstraferight),
+ CONFIG_VARIABLE_INT(joyb_straferight),
//!
// Joystick button to cycle to the previous weapon.
//
- CONFIG_VARIABLE_INT(joyb_prevweapon, joybprevweapon),
+ CONFIG_VARIABLE_INT(joyb_prevweapon),
//!
// Joystick button to cycle to the next weapon.
//
- CONFIG_VARIABLE_INT(joyb_nextweapon, joybnextweapon),
+ CONFIG_VARIABLE_INT(joyb_nextweapon),
//!
// Mouse button to strafe left.
//
- CONFIG_VARIABLE_INT(mouseb_strafeleft, mousebstrafeleft),
+ CONFIG_VARIABLE_INT(mouseb_strafeleft),
//!
// Mouse button to strafe right.
//
- CONFIG_VARIABLE_INT(mouseb_straferight, mousebstraferight),
+ CONFIG_VARIABLE_INT(mouseb_straferight),
//!
// Mouse button to "use" an object, eg. a door or switch.
//
- CONFIG_VARIABLE_INT(mouseb_use, mousebuse),
+ CONFIG_VARIABLE_INT(mouseb_use),
//!
// Mouse button to move backwards.
//
- CONFIG_VARIABLE_INT(mouseb_backward, mousebbackward),
+ CONFIG_VARIABLE_INT(mouseb_backward),
//!
// Mouse button to cycle to the previous weapon.
//
- CONFIG_VARIABLE_INT(mouseb_prevweapon, mousebprevweapon),
+ CONFIG_VARIABLE_INT(mouseb_prevweapon),
//!
// Mouse button to cycle to the next weapon.
//
- CONFIG_VARIABLE_INT(mouseb_nextweapon, mousebnextweapon),
+ CONFIG_VARIABLE_INT(mouseb_nextweapon),
//!
// If non-zero, double-clicking a mouse button acts like pressing
// the "use" key to use an object in-game, eg. a door or switch.
//
- CONFIG_VARIABLE_INT(dclick_use, dclick_use),
+ CONFIG_VARIABLE_INT(dclick_use),
#ifdef FEATURE_SOUND
@@ -823,15 +974,38 @@ static default_t extra_defaults_list[] =
// sample rate conversions of sound effects. Support for this
// must be compiled into the program.
//
- // If zero, libsamplerate support is disabled. If non-zero,
+ // If zero, libsamplerate support is disabled. If non-zero,
// libsamplerate is enabled. Increasing values roughly correspond
- // to higher quality conversion; the higher the quality, the
- // slower the conversion process. Linear conversion = 1;
+ // to higher quality conversion; the higher the quality, the
+ // slower the conversion process. Linear conversion = 1;
// Zero order hold = 2; Fast Sinc filter = 3; Medium quality
// Sinc filter = 4; High quality Sinc filter = 5.
//
- CONFIG_VARIABLE_INT(use_libsamplerate, use_libsamplerate),
+ CONFIG_VARIABLE_INT(use_libsamplerate),
+
+ //!
+ // Full path to a Timidity configuration file to use for MIDI
+ // playback. The file will be evaluated from the directory where
+ // it is evaluated, so there is no need to add "dir" commands
+ // into it.
+ //
+
+ CONFIG_VARIABLE_STRING(timidity_cfg_path),
+
+ //!
+ // Path to GUS patch files to use when operating in GUS emulation
+ // mode.
+ //
+
+ CONFIG_VARIABLE_STRING(gus_patch_path),
+
+ //!
+ // Number of kilobytes of RAM to use in GUS emulation mode. Valid
+ // values are 256, 512, 768 or 1024.
+ //
+
+ CONFIG_VARIABLE_INT(gus_ram_kb),
#endif
@@ -839,319 +1013,351 @@ static default_t extra_defaults_list[] =
// Key to pause or unpause the game.
//
- CONFIG_VARIABLE_KEY(key_pause, key_pause),
+ CONFIG_VARIABLE_KEY(key_pause),
//!
// Key that activates the menu when pressed.
//
- CONFIG_VARIABLE_KEY(key_menu_activate, key_menu_activate),
+ CONFIG_VARIABLE_KEY(key_menu_activate),
//!
// Key that moves the cursor up on the menu.
//
- CONFIG_VARIABLE_KEY(key_menu_up, key_menu_up),
+ CONFIG_VARIABLE_KEY(key_menu_up),
//!
// Key that moves the cursor down on the menu.
//
- CONFIG_VARIABLE_KEY(key_menu_down, key_menu_down),
+ CONFIG_VARIABLE_KEY(key_menu_down),
//!
// Key that moves the currently selected slider on the menu left.
//
- CONFIG_VARIABLE_KEY(key_menu_left, key_menu_left),
+ CONFIG_VARIABLE_KEY(key_menu_left),
//!
// Key that moves the currently selected slider on the menu right.
//
- CONFIG_VARIABLE_KEY(key_menu_right, key_menu_right),
+ CONFIG_VARIABLE_KEY(key_menu_right),
//!
// Key to go back to the previous menu.
//
- CONFIG_VARIABLE_KEY(key_menu_back, key_menu_back),
+ CONFIG_VARIABLE_KEY(key_menu_back),
//!
// Key to activate the currently selected menu item.
//
- CONFIG_VARIABLE_KEY(key_menu_forward, key_menu_forward),
+ CONFIG_VARIABLE_KEY(key_menu_forward),
//!
// Key to answer 'yes' to a question in the menu.
//
- CONFIG_VARIABLE_KEY(key_menu_confirm, key_menu_confirm),
+ CONFIG_VARIABLE_KEY(key_menu_confirm),
//!
// Key to answer 'no' to a question in the menu.
//
- CONFIG_VARIABLE_KEY(key_menu_abort, key_menu_abort),
+ CONFIG_VARIABLE_KEY(key_menu_abort),
//!
// Keyboard shortcut to bring up the help screen.
//
- CONFIG_VARIABLE_KEY(key_menu_help, key_menu_help),
+ CONFIG_VARIABLE_KEY(key_menu_help),
//!
// Keyboard shortcut to bring up the save game menu.
//
- CONFIG_VARIABLE_KEY(key_menu_save, key_menu_save),
+ CONFIG_VARIABLE_KEY(key_menu_save),
//!
// Keyboard shortcut to bring up the load game menu.
//
- CONFIG_VARIABLE_KEY(key_menu_load, key_menu_load),
+ CONFIG_VARIABLE_KEY(key_menu_load),
//!
// Keyboard shortcut to bring up the sound volume menu.
//
- CONFIG_VARIABLE_KEY(key_menu_volume, key_menu_volume),
+ CONFIG_VARIABLE_KEY(key_menu_volume),
//!
// Keyboard shortcut to toggle the detail level.
//
- CONFIG_VARIABLE_KEY(key_menu_detail, key_menu_detail),
+ CONFIG_VARIABLE_KEY(key_menu_detail),
//!
// Keyboard shortcut to quicksave the current game.
//
- CONFIG_VARIABLE_KEY(key_menu_qsave, key_menu_qsave),
+ CONFIG_VARIABLE_KEY(key_menu_qsave),
//!
// Keyboard shortcut to end the game.
//
- CONFIG_VARIABLE_KEY(key_menu_endgame, key_menu_endgame),
+ CONFIG_VARIABLE_KEY(key_menu_endgame),
//!
// Keyboard shortcut to toggle heads-up messages.
//
- CONFIG_VARIABLE_KEY(key_menu_messages, key_menu_messages),
+ CONFIG_VARIABLE_KEY(key_menu_messages),
//!
// Keyboard shortcut to load the last quicksave.
//
- CONFIG_VARIABLE_KEY(key_menu_qload, key_menu_qload),
+ CONFIG_VARIABLE_KEY(key_menu_qload),
//!
// Keyboard shortcut to quit the game.
//
- CONFIG_VARIABLE_KEY(key_menu_quit, key_menu_quit),
+ CONFIG_VARIABLE_KEY(key_menu_quit),
//!
// Keyboard shortcut to toggle the gamma correction level.
//
- CONFIG_VARIABLE_KEY(key_menu_gamma, key_menu_gamma),
+ CONFIG_VARIABLE_KEY(key_menu_gamma),
//!
// Keyboard shortcut to switch view in multiplayer.
//
- CONFIG_VARIABLE_KEY(key_spy, key_spy),
+ CONFIG_VARIABLE_KEY(key_spy),
//!
// Keyboard shortcut to increase the screen size.
//
- CONFIG_VARIABLE_KEY(key_menu_incscreen, key_menu_incscreen),
+ CONFIG_VARIABLE_KEY(key_menu_incscreen),
//!
// Keyboard shortcut to decrease the screen size.
//
- CONFIG_VARIABLE_KEY(key_menu_decscreen, key_menu_decscreen),
+ CONFIG_VARIABLE_KEY(key_menu_decscreen),
//!
// Key to toggle the map view.
//
- CONFIG_VARIABLE_KEY(key_map_toggle, key_map_toggle),
+ CONFIG_VARIABLE_KEY(key_map_toggle),
//!
// Key to pan north when in the map view.
//
- CONFIG_VARIABLE_KEY(key_map_north, key_map_north),
+ CONFIG_VARIABLE_KEY(key_map_north),
//!
// Key to pan south when in the map view.
//
- CONFIG_VARIABLE_KEY(key_map_south, key_map_south),
+ CONFIG_VARIABLE_KEY(key_map_south),
//!
// Key to pan east when in the map view.
//
- CONFIG_VARIABLE_KEY(key_map_east, key_map_east),
+ CONFIG_VARIABLE_KEY(key_map_east),
//!
// Key to pan west when in the map view.
//
- CONFIG_VARIABLE_KEY(key_map_west, key_map_west),
+ CONFIG_VARIABLE_KEY(key_map_west),
//!
// Key to zoom in when in the map view.
//
- CONFIG_VARIABLE_KEY(key_map_zoomin, key_map_zoomin),
+ CONFIG_VARIABLE_KEY(key_map_zoomin),
//!
// Key to zoom out when in the map view.
//
- CONFIG_VARIABLE_KEY(key_map_zoomout, key_map_zoomout),
+ CONFIG_VARIABLE_KEY(key_map_zoomout),
//!
// Key to zoom out the maximum amount when in the map view.
//
- CONFIG_VARIABLE_KEY(key_map_maxzoom, key_map_maxzoom),
+ CONFIG_VARIABLE_KEY(key_map_maxzoom),
//!
// Key to toggle follow mode when in the map view.
//
- CONFIG_VARIABLE_KEY(key_map_follow, key_map_follow),
+ CONFIG_VARIABLE_KEY(key_map_follow),
//!
// Key to toggle the grid display when in the map view.
//
- CONFIG_VARIABLE_KEY(key_map_grid, key_map_grid),
+ CONFIG_VARIABLE_KEY(key_map_grid),
//!
// Key to set a mark when in the map view.
//
- CONFIG_VARIABLE_KEY(key_map_mark, key_map_mark),
+ CONFIG_VARIABLE_KEY(key_map_mark),
//!
// Key to clear all marks when in the map view.
//
- CONFIG_VARIABLE_KEY(key_map_clearmark, key_map_clearmark),
+ CONFIG_VARIABLE_KEY(key_map_clearmark),
//!
// Key to select weapon 1.
//
- CONFIG_VARIABLE_KEY(key_weapon1, key_weapon1),
+ CONFIG_VARIABLE_KEY(key_weapon1),
//!
// Key to select weapon 2.
//
- CONFIG_VARIABLE_KEY(key_weapon2, key_weapon2),
+ CONFIG_VARIABLE_KEY(key_weapon2),
//!
// Key to select weapon 3.
//
- CONFIG_VARIABLE_KEY(key_weapon3, key_weapon3),
+ CONFIG_VARIABLE_KEY(key_weapon3),
//!
// Key to select weapon 4.
//
- CONFIG_VARIABLE_KEY(key_weapon4, key_weapon4),
+ CONFIG_VARIABLE_KEY(key_weapon4),
//!
// Key to select weapon 5.
//
- CONFIG_VARIABLE_KEY(key_weapon5, key_weapon5),
+ CONFIG_VARIABLE_KEY(key_weapon5),
//!
// Key to select weapon 6.
//
- CONFIG_VARIABLE_KEY(key_weapon6, key_weapon6),
+ CONFIG_VARIABLE_KEY(key_weapon6),
//!
// Key to select weapon 7.
//
- CONFIG_VARIABLE_KEY(key_weapon7, key_weapon7),
+ CONFIG_VARIABLE_KEY(key_weapon7),
//!
// Key to select weapon 8.
//
- CONFIG_VARIABLE_KEY(key_weapon8, key_weapon8),
+ CONFIG_VARIABLE_KEY(key_weapon8),
//!
// Key to cycle to the previous weapon.
//
- CONFIG_VARIABLE_KEY(key_prevweapon, key_prevweapon),
+ CONFIG_VARIABLE_KEY(key_prevweapon),
//!
// Key to cycle to the next weapon.
//
- CONFIG_VARIABLE_KEY(key_nextweapon, key_nextweapon),
+ CONFIG_VARIABLE_KEY(key_nextweapon),
//!
// Key to re-display last message.
//
- CONFIG_VARIABLE_KEY(key_message_refresh, key_message_refresh),
+ CONFIG_VARIABLE_KEY(key_message_refresh),
//!
// Key to quit the game when recording a demo.
//
- CONFIG_VARIABLE_KEY(key_demo_quit, key_demo_quit),
+ CONFIG_VARIABLE_KEY(key_demo_quit),
//!
// Key to send a message during multiplayer games.
//
- CONFIG_VARIABLE_KEY(key_multi_msg, key_multi_msg),
+ CONFIG_VARIABLE_KEY(key_multi_msg),
+
+ //!
+ // Key to send a message to player 1 during multiplayer games.
+ //
+
+ CONFIG_VARIABLE_KEY(key_multi_msgplayer1),
+
+ //!
+ // Key to send a message to player 2 during multiplayer games.
+ //
+
+ CONFIG_VARIABLE_KEY(key_multi_msgplayer2),
+
+ //!
+ // Key to send a message to player 3 during multiplayer games.
+ //
+
+ CONFIG_VARIABLE_KEY(key_multi_msgplayer3),
+
+ //!
+ // Key to send a message to player 4 during multiplayer games.
+ //
+
+ CONFIG_VARIABLE_KEY(key_multi_msgplayer4),
//!
- // Key to send a message to the green player during multiplayer games.
+ // @game hexen strife
+ //
+ // Key to send a message to player 5 during multiplayer games.
//
- CONFIG_VARIABLE_KEY(key_multi_msgplayer1, key_multi_msgplayer[0]),
+ CONFIG_VARIABLE_KEY(key_multi_msgplayer5),
//!
- // Key to send a message to the indigo player during multiplayer games.
+ // @game hexen strife
+ //
+ // Key to send a message to player 6 during multiplayer games.
//
- CONFIG_VARIABLE_KEY(key_multi_msgplayer2, key_multi_msgplayer[1]),
+ CONFIG_VARIABLE_KEY(key_multi_msgplayer6),
//!
- // Key to send a message to the brown player during multiplayer games.
+ // @game hexen strife
+ //
+ // Key to send a message to player 7 during multiplayer games.
//
- CONFIG_VARIABLE_KEY(key_multi_msgplayer3, key_multi_msgplayer[2]),
+ CONFIG_VARIABLE_KEY(key_multi_msgplayer7),
//!
- // Key to send a message to the red player during multiplayer games.
+ // @game hexen strife
+ //
+ // Key to send a message to player 8 during multiplayer games.
//
- CONFIG_VARIABLE_KEY(key_multi_msgplayer4, key_multi_msgplayer[3]),
+ CONFIG_VARIABLE_KEY(key_multi_msgplayer8),
};
static default_collection_t extra_defaults =
@@ -1161,6 +1367,23 @@ static default_collection_t extra_defaults =
NULL,
};
+// Search a collection for a variable
+
+static default_t *SearchCollection(default_collection_t *collection, char *name)
+{
+ int i;
+
+ for (i=0; i<collection->numdefaults; ++i)
+ {
+ if (!strcmp(name, collection->defaults[i].name))
+ {
+ return &collection->defaults[i];
+ }
+ }
+
+ return NULL;
+}
+
static const int scantokey[128] =
{
0 , 27, '1', '2', '3', '4', '5', '6',
@@ -1198,6 +1421,13 @@ static void SaveDefaultCollection(default_collection_t *collection)
{
int chars_written;
+ // Ignore unbound variables
+
+ if (!defaults[i].bound)
+ {
+ continue;
+ }
+
// Print the name and line up all values at 30 characters
chars_written = fprintf(f, "%s ", defaults[i].name);
@@ -1294,18 +1524,20 @@ static int ParseIntParameter(char *strparm)
static void LoadDefaultCollection(default_collection_t *collection)
{
- default_t *defaults = collection->defaults;
- int i;
- FILE* f;
- char defname[80];
- char strparm[100];
+ default_t *def;
+ FILE *f;
+ char defname[80];
+ char strparm[100];
+ char *s;
+ int intparm;
// read the file in, overriding any set defaults
f = fopen(collection->filename, "r");
- if (!f)
+ if (f == NULL)
{
- // File not opened, but don't complain
+ // File not opened, but don't complain.
+ // It's probably just the first time they ran the game.
return;
}
@@ -1329,67 +1561,68 @@ static void LoadDefaultCollection(default_collection_t *collection)
// Find the setting in the list
- for (i=0; i<collection->numdefaults; ++i)
+ def = SearchCollection(collection, defname);
+
+ if (def == NULL || !def->bound)
{
- default_t *def = &collection->defaults[i];
- char *s;
- int intparm;
-
- if (strcmp(defname, def->name) != 0)
- {
- // not this one
- continue;
- }
-
- // parameter found
-
- switch (def->type)
- {
- case DEFAULT_STRING:
- s = strdup(strparm + 1);
- s[strlen(s) - 1] = '\0';
- * (char **) def->location = s;
- break;
-
- case DEFAULT_INT:
- case DEFAULT_INT_HEX:
- * (int *) def->location = ParseIntParameter(strparm);
- break;
-
- case DEFAULT_KEY:
-
- // translate scancodes read from config
- // file (save the old value in untranslated)
-
- intparm = ParseIntParameter(strparm);
- defaults[i].untranslated = intparm;
- if (intparm >= 0 && intparm < 128)
- {
- intparm = scantokey[intparm];
- }
- else
- {
- intparm = 0;
- }
+ // Unknown variable? Unbound variables are also treated
+ // as unknown.
+
+ continue;
+ }
+
+ // parameter found
+
+ switch (def->type)
+ {
+ case DEFAULT_STRING:
+ s = strdup(strparm + 1);
+ s[strlen(s) - 1] = '\0';
+ * (char **) def->location = s;
+ break;
+
+ case DEFAULT_INT:
+ case DEFAULT_INT_HEX:
+ * (int *) def->location = ParseIntParameter(strparm);
+ break;
+
+ case DEFAULT_KEY:
- defaults[i].original_translated = intparm;
- * (int *) def->location = intparm;
- break;
+ // translate scancodes read from config
+ // file (save the old value in untranslated)
- case DEFAULT_FLOAT:
- * (float *) def->location = (float) atof(strparm);
- break;
- }
+ intparm = ParseIntParameter(strparm);
+ def->untranslated = intparm;
+ if (intparm >= 0 && intparm < 128)
+ {
+ intparm = scantokey[intparm];
+ }
+ else
+ {
+ intparm = 0;
+ }
- // finish
+ def->original_translated = intparm;
+ * (int *) def->location = intparm;
+ break;
- break;
+ case DEFAULT_FLOAT:
+ * (float *) def->location = (float) atof(strparm);
+ break;
}
}
fclose (f);
}
+// Set the default filenames to use for configuration files.
+
+void M_SetConfigFilenames(char *main_config, char *extra_config)
+{
+ default_main_config = main_config;
+ default_extra_config = extra_config;
+}
+
//
// M_SaveDefaults
//
@@ -1400,6 +1633,30 @@ void M_SaveDefaults (void)
SaveDefaultCollection(&extra_defaults);
}
+//
+// Save defaults to alternate filenames
+//
+
+void M_SaveDefaultsAlternate(char *main, char *extra)
+{
+ char *orig_main;
+ char *orig_extra;
+
+ // Temporarily change the filenames
+
+ orig_main = doom_defaults.filename;
+ orig_extra = extra_defaults.filename;
+
+ doom_defaults.filename = main;
+ extra_defaults.filename = extra;
+
+ M_SaveDefaults();
+
+ // Restore normal filenames
+
+ doom_defaults.filename = orig_main;
+ extra_defaults.filename = orig_extra;
+}
//
// M_LoadDefaults
@@ -1415,8 +1672,8 @@ void M_LoadDefaults (void)
// @arg <file>
// @vanilla
//
- // Load configuration from the specified file, instead of
- // default.cfg.
+ // Load configuration from the specified file. The default
+ // configuration file (for Doom) is named default.cfg.
//
i = M_CheckParmWithArgs("-config", 1);
@@ -1428,8 +1685,9 @@ void M_LoadDefaults (void)
}
else
{
- doom_defaults.filename = malloc(strlen(configdir) + 20);
- sprintf(doom_defaults.filename, "%sdefault.cfg", configdir);
+ doom_defaults.filename
+ = malloc(strlen(configdir) + strlen(default_main_config) + 1);
+ sprintf(doom_defaults.filename, "%s%s", configdir, default_main_config);
}
printf("saving config in %s\n", doom_defaults.filename);
@@ -1437,8 +1695,8 @@ void M_LoadDefaults (void)
//!
// @arg <file>
//
- // Load extra configuration from the specified file, instead
- // of chocolate-doom.cfg.
+ // Load extra configuration from the specified file. The default
+ // configuration file for Doom is named chocolate-doom.cfg.
//
i = M_CheckParmWithArgs("-extraconfig", 1);
@@ -1452,23 +1710,58 @@ void M_LoadDefaults (void)
else
{
extra_defaults.filename
- = malloc(strlen(configdir) + strlen(PROGRAM_PREFIX) + 15);
- sprintf(extra_defaults.filename, "%s%sdoom.cfg",
- configdir, PROGRAM_PREFIX);
+ = malloc(strlen(configdir) + strlen(default_extra_config) + 1);
+ sprintf(extra_defaults.filename, "%s%s",
+ configdir, default_extra_config);
}
LoadDefaultCollection(&doom_defaults);
LoadDefaultCollection(&extra_defaults);
}
-//
-// SetConfigDir:
+// Get a configuration file variable by its name
+
+static default_t *GetDefaultForName(char *name)
+{
+ default_t *result;
+
+ // Try the main list and the extras
+
+ result = SearchCollection(&doom_defaults, name);
+
+ if (result == NULL)
+ {
+ result = SearchCollection(&extra_defaults, name);
+ }
+
+ // Not found? Internal error.
+
+ if (result == NULL)
+ {
+ I_Error("Unknown configuration variable: '%s'", name);
+ }
+
+ return result;
+}
+
//
-// Sets the location of the configuration directory, where configuration
-// files are stored - default.cfg, chocolate-doom.cfg, savegames, etc.
+// Bind a variable to a given configuration file variable, by name.
//
-void M_SetConfigDir(void)
+void M_BindVariable(char *name, void *location)
+{
+ default_t *variable;
+
+ variable = GetDefaultForName(name);
+
+ variable->location = location;
+ variable->bound = true;
+}
+
+// Get the path to the default configuration dir to use, if NULL
+// is passed to M_SetConfigDir.
+
+static char *GetDefaultConfigDir(void)
{
#if !defined(_WIN32) || defined(_WIN32_WCE)
@@ -1477,6 +1770,7 @@ void M_SetConfigDir(void)
// save in the current directory.
char *homedir;
+ char *result;
homedir = getenv("HOME");
@@ -1485,149 +1779,84 @@ void M_SetConfigDir(void)
// put all configuration in a config directory off the
// homedir
- configdir = malloc(strlen(homedir) + strlen(PACKAGE_TARNAME) + 5);
+ result = malloc(strlen(homedir) + strlen(PACKAGE_TARNAME) + 5);
- sprintf(configdir, "%s%c.%s%c", homedir, DIR_SEPARATOR,
- PACKAGE_TARNAME, DIR_SEPARATOR);
+ sprintf(result, "%s%c.%s%c", homedir, DIR_SEPARATOR,
+ PACKAGE_TARNAME, DIR_SEPARATOR);
- // make the directory if it doesnt already exist
-
- M_MakeDirectory(configdir);
+ return result;
}
else
#endif /* #ifndef _WIN32 */
{
-#if defined(_WIN32) && !defined(_WIN32_WCE)
- //!
- // @platform windows
- // @vanilla
- //
- // Save configuration data and savegames in c:\doomdata,
- // allowing play from CD.
- //
-
- if (M_CheckParm("-cdrom") > 0)
- {
- printf(D_CDROM);
- configdir = strdup("c:\\doomdata\\");
-
- M_MakeDirectory(configdir);
- }
- else
-#endif
- {
- configdir = strdup("");
- }
+ return strdup("");
}
}
-#ifdef _WIN32_WCE
+//
+// SetConfigDir:
+//
+// Sets the location of the configuration directory, where configuration
+// files are stored - default.cfg, chocolate-doom.cfg, savegames, etc.
+//
-static int SystemHasKeyboard(void)
+void M_SetConfigDir(char *dir)
{
- HKEY key;
- DWORD valtype;
- DWORD valsize;
- DWORD result;
-
- if (RegOpenKeyExW(HKEY_CURRENT_USER,
- L"\\Software\\Microsoft\\Shell", 0,
- KEY_READ, &key) != ERROR_SUCCESS)
+ // Use the directory that was passed, or find the default.
+
+ if (dir != NULL)
{
- return 0;
+ configdir = dir;
}
-
- valtype = REG_SZ;
- valsize = sizeof(DWORD);
-
- if (RegQueryValueExW(key, L"HasKeyboard", NULL, &valtype,
- (LPBYTE) &result, &valsize) != ERROR_SUCCESS)
+ else
{
- result = 0;
+ configdir = GetDefaultConfigDir();
}
- // Close the key
-
- RegCloseKey(key);
-
- return result;
-}
-
-//
-// Apply custom defaults for Windows CE.
-//
-
-static void M_ApplyWindowsCEDefaults(void)
-{
- // If the system doesn't have a keyboard, patch the default
- // configuration to use the hardware keys.
-
- if (!SystemHasKeyboard())
+ if (strcmp(configdir, "") != 0)
{
- key_use = KEY_F1;
- key_fire = KEY_F2;
- key_menu_activate = KEY_F3;
- key_map_toggle = KEY_F4;
-
- key_menu_help = 0;
- key_menu_save = 0;
- key_menu_load = 0;
- key_menu_volume = 0;
-
- key_menu_confirm = KEY_ENTER;
- key_menu_back = KEY_F2;
- key_menu_abort = KEY_F2;
+ printf("Using %s for configuration and saves\n", configdir);
}
-}
-#endif
+ // Make the directory if it doesn't already exist:
+
+ M_MakeDirectory(configdir);
+}
//
-// Apply custom patches to the default values depending on the
-// platform we are running on.
+// Calculate the path to the directory to use to store save games.
+// Creates the directory as necessary.
//
-void M_ApplyPlatformDefaults(void)
+char *M_GetSaveGameDir(char *iwadname)
{
-#ifdef _WIN32_WCE
- M_ApplyWindowsCEDefaults();
-#endif
+ char *savegamedir;
- // Before SDL_mixer version 1.2.11, MIDI music caused the game
- // to crash when it looped. If this is an old SDL_mixer version,
- // disable MIDI.
+ // If not "doing" a configuration directory (Windows), don't "do"
+ // a savegame directory, either.
-#ifdef __MACOSX__
+ if (!strcmp(configdir, ""))
{
- const SDL_version *v = Mix_Linked_Version();
-
- if (SDL_VERSIONNUM(v->major, v->minor, v->patch)
- < SDL_VERSIONNUM(1, 2, 11))
- {
- snd_musicdevice = SNDDEVICE_NONE;
- }
+ savegamedir = strdup("");
}
-#endif
+ else
+ {
+ // ~/.chocolate-doom/savegames/
- // Windows Vista or later? Set screen color depth to
- // 32 bits per pixel, as 8-bit palettized screen modes
- // don't work properly in recent versions.
+ savegamedir = malloc(strlen(configdir) + 30);
+ sprintf(savegamedir, "%ssavegames%c", configdir,
+ DIR_SEPARATOR);
-#if defined(_WIN32) && !defined(_WIN32_WCE)
- {
- OSVERSIONINFOEX version_info;
+ M_MakeDirectory(savegamedir);
- ZeroMemory(&version_info, sizeof(OSVERSIONINFOEX));
- version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+ // eg. ~/.chocolate-doom/savegames/doom2.wad/
- GetVersionEx((OSVERSIONINFO *) &version_info);
+ sprintf(savegamedir + strlen(savegamedir), "%s%c",
+ iwadname, DIR_SEPARATOR);
- if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT
- && version_info.dwMajorVersion >= 6)
- {
- screen_bpp = 32;
- }
+ M_MakeDirectory(savegamedir);
}
-#endif
+
+ return savegamedir;
}
diff --git a/src/m_config.h b/src/m_config.h
index ff11e6d6..999b50ae 100644
--- a/src/m_config.h
+++ b/src/m_config.h
@@ -30,8 +30,11 @@
void M_LoadDefaults(void);
void M_SaveDefaults(void);
-void M_SetConfigDir(void);
-void M_ApplyPlatformDefaults(void);
+void M_SaveDefaultsAlternate(char *main, char *extra);
+void M_SetConfigDir(char *dir);
+void M_BindVariable(char *name, void *variable);
+void M_SetConfigFilenames(char *main_config, char *extra_config);
+char *M_GetSaveGameDir(char *iwadname);
extern char *configdir;
diff --git a/src/m_controls.c b/src/m_controls.c
new file mode 100644
index 00000000..409f26bf
--- /dev/null
+++ b/src/m_controls.c
@@ -0,0 +1,448 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2005-8 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+
+#include "doomtype.h"
+#include "doomkeys.h"
+
+#include "m_config.h"
+
+//
+// Keyboard controls
+//
+
+int key_right = KEY_RIGHTARROW;
+int key_left = KEY_LEFTARROW;
+
+int key_up = KEY_UPARROW;
+int key_down = KEY_DOWNARROW;
+int key_strafeleft = ',';
+int key_straferight = '.';
+int key_fire = KEY_RCTRL;
+int key_use = ' ';
+int key_strafe = KEY_RALT;
+int key_speed = KEY_RSHIFT;
+
+//
+// Heretic keyboard controls
+//
+
+int key_flyup = KEY_PGUP;
+int key_flydown = KEY_INS;
+int key_flycenter = KEY_HOME;
+
+int key_lookup = KEY_PGDN;
+int key_lookdown = KEY_DEL;
+int key_lookcenter = KEY_END;
+
+int key_invleft = '[';
+int key_invright = ']';
+int key_useartifact = KEY_ENTER;
+
+//
+// Hexen key controls
+//
+
+int key_jump = '/';
+
+//
+// Strife key controls
+//
+// haleyjd 09/01/10
+//
+
+// Note: Strife also uses key_invleft, key_invright, key_jump, key_lookup, and
+// key_lookdown, but with different default values.
+
+int key_usehealth = 'h';
+int key_invquery = 'q';
+int key_mission = 'w';
+int key_invpop = 'z';
+int key_invkey = 'k';
+int key_invhome = KEY_HOME;
+int key_invend = KEY_END;
+int key_invuse = KEY_ENTER;
+int key_invdrop = KEY_BACKSPACE;
+
+
+//
+// Mouse controls
+//
+
+int mousebfire = 0;
+int mousebstrafe = 1;
+int mousebforward = 2;
+
+int mousebjump = -1;
+
+int mousebstrafeleft = -1;
+int mousebstraferight = -1;
+int mousebbackward = -1;
+int mousebuse = -1;
+
+int mousebprevweapon = -1;
+int mousebnextweapon = -1;
+
+
+int key_message_refresh = KEY_ENTER;
+int key_pause = KEY_PAUSE;
+int key_demo_quit = 'q';
+int key_spy = KEY_F12;
+
+// Multiplayer chat keys:
+
+int key_multi_msg = 't';
+int key_multi_msgplayer[8];
+
+// Weapon selection keys:
+
+int key_weapon1 = '1';
+int key_weapon2 = '2';
+int key_weapon3 = '3';
+int key_weapon4 = '4';
+int key_weapon5 = '5';
+int key_weapon6 = '6';
+int key_weapon7 = '7';
+int key_weapon8 = '8';
+int key_prevweapon = 0;
+int key_nextweapon = 0;
+
+// Map control keys:
+
+int key_map_north = KEY_UPARROW;
+int key_map_south = KEY_DOWNARROW;
+int key_map_east = KEY_RIGHTARROW;
+int key_map_west = KEY_LEFTARROW;
+int key_map_zoomin = '=';
+int key_map_zoomout = '-';
+int key_map_toggle = KEY_TAB;
+int key_map_maxzoom = '0';
+int key_map_follow = 'f';
+int key_map_grid = 'g';
+int key_map_mark = 'm';
+int key_map_clearmark = 'c';
+
+// menu keys:
+
+int key_menu_activate = KEY_ESCAPE;
+int key_menu_up = KEY_UPARROW;
+int key_menu_down = KEY_DOWNARROW;
+int key_menu_left = KEY_LEFTARROW;
+int key_menu_right = KEY_RIGHTARROW;
+int key_menu_back = KEY_BACKSPACE;
+int key_menu_forward = KEY_ENTER;
+int key_menu_confirm = 'y';
+int key_menu_abort = 'n';
+
+int key_menu_help = KEY_F1;
+int key_menu_save = KEY_F2;
+int key_menu_load = KEY_F3;
+int key_menu_volume = KEY_F4;
+int key_menu_detail = KEY_F5;
+int key_menu_qsave = KEY_F6;
+int key_menu_endgame = KEY_F7;
+int key_menu_messages = KEY_F8;
+int key_menu_qload = KEY_F9;
+int key_menu_quit = KEY_F10;
+int key_menu_gamma = KEY_F11;
+
+int key_menu_incscreen = KEY_EQUALS;
+int key_menu_decscreen = KEY_MINUS;
+
+//
+// Joystick controls
+//
+
+int joybfire = 0;
+int joybstrafe = 1;
+int joybuse = 3;
+int joybspeed = 2;
+
+int joybstrafeleft = -1;
+int joybstraferight = -1;
+
+int joybjump = -1;
+
+int joybprevweapon = -1;
+int joybnextweapon = -1;
+
+// Control whether if a mouse button is double clicked, it acts like
+// "use" has been pressed
+
+int dclick_use = 1;
+
+//
+// Bind all of the common controls used by Doom and all other games.
+//
+
+void M_BindBaseControls(void)
+{
+ M_BindVariable("key_right", &key_right),
+ M_BindVariable("key_left", &key_left),
+ M_BindVariable("key_up", &key_up),
+ M_BindVariable("key_down", &key_down),
+ M_BindVariable("key_strafeleft", &key_strafeleft),
+ M_BindVariable("key_straferight", &key_straferight),
+ M_BindVariable("key_fire", &key_fire),
+ M_BindVariable("key_use", &key_use),
+ M_BindVariable("key_strafe", &key_strafe),
+ M_BindVariable("key_speed", &key_speed),
+
+ M_BindVariable("mouseb_fire", &mousebfire),
+ M_BindVariable("mouseb_strafe", &mousebstrafe),
+ M_BindVariable("mouseb_forward", &mousebforward),
+
+ M_BindVariable("joyb_fire", &joybfire),
+ M_BindVariable("joyb_strafe", &joybstrafe),
+ M_BindVariable("joyb_use", &joybuse),
+ M_BindVariable("joyb_speed", &joybspeed),
+
+ // Extra controls that are not in the Vanilla versions:
+
+ M_BindVariable("joyb_strafeleft", &joybstrafeleft);
+ M_BindVariable("joyb_straferight", &joybstraferight);
+ M_BindVariable("mouseb_strafeleft", &mousebstrafeleft);
+ M_BindVariable("mouseb_straferight", &mousebstraferight);
+ M_BindVariable("mouseb_use", &mousebuse);
+ M_BindVariable("mouseb_backward", &mousebbackward);
+ M_BindVariable("dclick_use", &dclick_use);
+ M_BindVariable("key_pause", &key_pause);
+ M_BindVariable("key_message_refresh", &key_message_refresh);
+}
+
+void M_BindHereticControls(void)
+{
+ M_BindVariable("key_flyup", &key_flyup);
+ M_BindVariable("key_flydown", &key_flydown);
+ M_BindVariable("key_flycenter", &key_flycenter);
+
+ M_BindVariable("key_lookup", &key_lookup);
+ M_BindVariable("key_lookdown", &key_lookdown);
+ M_BindVariable("key_lookcenter", &key_lookcenter);
+
+ M_BindVariable("key_invleft", &key_invleft);
+ M_BindVariable("key_invright", &key_invright);
+ M_BindVariable("key_useartifact", &key_useartifact);
+}
+
+void M_BindHexenControls(void)
+{
+ M_BindVariable("key_jump", &key_jump);
+ M_BindVariable("mouseb_jump", &mousebjump);
+ M_BindVariable("joyb_jump", &joybjump);
+}
+
+void M_BindStrifeControls(void)
+{
+ // These are shared with all games, but have different defaults:
+ key_message_refresh = '/';
+
+ // These keys are shared with Heretic/Hexen but have different defaults:
+ key_jump = 'a';
+ key_lookup = KEY_PGUP;
+ key_lookdown = KEY_PGDN;
+ key_invleft = KEY_INS;
+ key_invright = KEY_DEL;
+
+ M_BindVariable("key_jump", &key_jump);
+ M_BindVariable("key_lookUp", &key_lookup);
+ M_BindVariable("key_lookDown", &key_lookdown);
+ M_BindVariable("key_invLeft", &key_invleft);
+ M_BindVariable("key_invRight", &key_invright);
+
+ // Custom Strife-only Keys:
+ M_BindVariable("key_useHealth", &key_usehealth);
+ M_BindVariable("key_invquery", &key_invquery);
+ M_BindVariable("key_mission", &key_mission);
+ M_BindVariable("key_invPop", &key_invpop);
+ M_BindVariable("key_invKey", &key_invkey);
+ M_BindVariable("key_invHome", &key_invhome);
+ M_BindVariable("key_invEnd", &key_invend);
+ M_BindVariable("key_invUse", &key_invuse);
+ M_BindVariable("key_invDrop", &key_invdrop);
+
+ // Strife also supports jump on mouse and joystick, and in the exact same
+ // manner as Hexen!
+ M_BindVariable("mouseb_jump", &mousebjump);
+ M_BindVariable("joyb_jump", &joybjump);
+}
+
+void M_BindWeaponControls(void)
+{
+ M_BindVariable("key_weapon1", &key_weapon1);
+ M_BindVariable("key_weapon2", &key_weapon2);
+ M_BindVariable("key_weapon3", &key_weapon3);
+ M_BindVariable("key_weapon4", &key_weapon4);
+ M_BindVariable("key_weapon5", &key_weapon5);
+ M_BindVariable("key_weapon6", &key_weapon6);
+ M_BindVariable("key_weapon7", &key_weapon7);
+ M_BindVariable("key_weapon8", &key_weapon8);
+
+ M_BindVariable("key_prevweapon", &key_prevweapon);
+ M_BindVariable("key_nextweapon", &key_nextweapon);
+
+ M_BindVariable("joyb_prevweapon", &joybprevweapon);
+ M_BindVariable("joyb_nextweapon", &joybnextweapon);
+
+ M_BindVariable("mouseb_prevweapon", &mousebprevweapon);
+ M_BindVariable("mouseb_nextweapon", &mousebnextweapon);
+}
+
+void M_BindMapControls(void)
+{
+ M_BindVariable("key_map_north", &key_map_north);
+ M_BindVariable("key_map_south", &key_map_south);
+ M_BindVariable("key_map_east", &key_map_east);
+ M_BindVariable("key_map_west", &key_map_west);
+ M_BindVariable("key_map_zoomin", &key_map_zoomin);
+ M_BindVariable("key_map_zoomout", &key_map_zoomout);
+ M_BindVariable("key_map_toggle", &key_map_toggle);
+ M_BindVariable("key_map_maxzoom", &key_map_maxzoom);
+ M_BindVariable("key_map_follow", &key_map_follow);
+ M_BindVariable("key_map_grid", &key_map_grid);
+ M_BindVariable("key_map_mark", &key_map_mark);
+ M_BindVariable("key_map_clearmark", &key_map_clearmark);
+}
+
+void M_BindMenuControls(void)
+{
+ M_BindVariable("key_menu_activate", &key_menu_activate);
+ M_BindVariable("key_menu_up", &key_menu_up);
+ M_BindVariable("key_menu_down", &key_menu_down);
+ M_BindVariable("key_menu_left", &key_menu_left);
+ M_BindVariable("key_menu_right", &key_menu_right);
+ M_BindVariable("key_menu_back", &key_menu_back);
+ M_BindVariable("key_menu_forward", &key_menu_forward);
+ M_BindVariable("key_menu_confirm", &key_menu_confirm);
+ M_BindVariable("key_menu_abort", &key_menu_abort);
+
+ M_BindVariable("key_menu_help", &key_menu_help);
+ M_BindVariable("key_menu_save", &key_menu_save);
+ M_BindVariable("key_menu_load", &key_menu_load);
+ M_BindVariable("key_menu_volume", &key_menu_volume);
+ M_BindVariable("key_menu_detail", &key_menu_detail);
+ M_BindVariable("key_menu_qsave", &key_menu_qsave);
+ M_BindVariable("key_menu_endgame", &key_menu_endgame);
+ M_BindVariable("key_menu_messages", &key_menu_messages);
+ M_BindVariable("key_menu_qload", &key_menu_qload);
+ M_BindVariable("key_menu_quit", &key_menu_quit);
+ M_BindVariable("key_menu_gamma", &key_menu_gamma);
+
+ M_BindVariable("key_menu_incscreen", &key_menu_incscreen);
+ M_BindVariable("key_menu_decscreen", &key_menu_decscreen);
+ M_BindVariable("key_demo_quit", &key_demo_quit);
+ M_BindVariable("key_spy", &key_spy);
+}
+
+void M_BindChatControls(unsigned int num_players)
+{
+ char name[32]; // haleyjd: 20 not large enough - Thank you, come again!
+ unsigned int i; // haleyjd: signedness conflict
+
+ M_BindVariable("key_multi_msg", &key_multi_msg);
+
+ for (i=0; i<num_players; ++i)
+ {
+ sprintf(name, "key_multi_msgplayer%i", i + 1);
+ M_BindVariable(name, &key_multi_msgplayer[i]);
+ }
+}
+
+#ifdef _WIN32_WCE
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+static int SystemHasKeyboard(void)
+{
+ HKEY key;
+ DWORD valtype;
+ DWORD valsize;
+ DWORD result;
+
+ if (RegOpenKeyExW(HKEY_CURRENT_USER,
+ L"\\Software\\Microsoft\\Shell", 0,
+ KEY_READ, &key) != ERROR_SUCCESS)
+ {
+ return 0;
+ }
+
+ valtype = REG_SZ;
+ valsize = sizeof(DWORD);
+
+ if (RegQueryValueExW(key, L"HasKeyboard", NULL, &valtype,
+ (LPBYTE) &result, &valsize) != ERROR_SUCCESS)
+ {
+ result = 0;
+ }
+
+ // Close the key
+
+ RegCloseKey(key);
+
+ return result;
+}
+
+//
+// Apply custom defaults for Windows CE.
+//
+
+static void M_ApplyWindowsCEDefaults(void)
+{
+ // If the system doesn't have a keyboard, patch the default
+ // configuration to use the hardware keys.
+
+ if (!SystemHasKeyboard())
+ {
+ key_use = KEY_F1;
+ key_fire = KEY_F2;
+ key_menu_activate = KEY_F3;
+ key_map_toggle = KEY_F4;
+
+ key_menu_help = 0;
+ key_menu_save = 0;
+ key_menu_load = 0;
+ key_menu_volume = 0;
+
+ key_menu_confirm = KEY_ENTER;
+ key_menu_back = KEY_F2;
+ key_menu_abort = KEY_F2;
+ }
+}
+
+#endif
+
+//
+// Apply custom patches to the default values depending on the
+// platform we are running on.
+//
+
+void M_ApplyPlatformDefaults(void)
+{
+#ifdef _WIN32_WCE
+ M_ApplyWindowsCEDefaults();
+#endif
+}
+
diff --git a/setup/keyboard.h b/src/m_controls.h
index 73510861..75bd9355 100644
--- a/setup/keyboard.h
+++ b/src/m_controls.h
@@ -1,7 +1,9 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
-// Copyright(C) 2006 Simon Howard
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2005-8 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -18,12 +20,14 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
+//-----------------------------------------------------------------------------
-#ifndef SETUP_KEYBOARD_H
-#define SETUP_KEYBOARD_H
-
-extern int key_left;
+#ifndef __M_CONTROLS_H__
+#define __M_CONTROLS_H__
+
extern int key_right;
+extern int key_left;
+
extern int key_up;
extern int key_down;
extern int key_strafeleft;
@@ -32,17 +36,64 @@ extern int key_fire;
extern int key_use;
extern int key_strafe;
extern int key_speed;
-extern int joybspeed;
-extern int vanilla_keyboard_mapping;
-extern int key_pause;
+extern int key_jump;
+
+extern int key_flyup;
+extern int key_flydown;
+extern int key_flycenter;
+extern int key_lookup;
+extern int key_lookdown;
+extern int key_lookcenter;
+extern int key_invleft;
+extern int key_invright;
+extern int key_useartifact;
+
+// villsa [STRIFE] strife keys
+extern int key_usehealth;
+extern int key_invquery;
+extern int key_mission;
+extern int key_invpop;
+extern int key_invkey;
+extern int key_invhome;
+extern int key_invend;
+extern int key_invuse;
+extern int key_invdrop;
-// Multiplayer messages:
+extern int key_message_refresh;
+extern int key_pause;
extern int key_multi_msg;
-extern int key_multi_msgplayer[];
+extern int key_multi_msgplayer[8];
+
+extern int key_weapon1;
+extern int key_weapon2;
+extern int key_weapon3;
+extern int key_weapon4;
+extern int key_weapon5;
+extern int key_weapon6;
+extern int key_weapon7;
+extern int key_weapon8;
-// Menu keys:
+extern int key_demo_quit;
+extern int key_spy;
+extern int key_prevweapon;
+extern int key_nextweapon;
+
+extern int key_map_north;
+extern int key_map_south;
+extern int key_map_east;
+extern int key_map_west;
+extern int key_map_zoomin;
+extern int key_map_zoomout;
+extern int key_map_toggle;
+extern int key_map_maxzoom;
+extern int key_map_follow;
+extern int key_map_grid;
+extern int key_map_mark;
+extern int key_map_clearmark;
+
+// menu keys:
extern int key_menu_activate;
extern int key_menu_up;
@@ -65,43 +116,49 @@ extern int key_menu_messages;
extern int key_menu_qload;
extern int key_menu_quit;
extern int key_menu_gamma;
-extern int key_spy;
extern int key_menu_incscreen;
extern int key_menu_decscreen;
-// Automap keys:
+extern int mousebfire;
+extern int mousebstrafe;
+extern int mousebforward;
-extern int key_map_north;
-extern int key_map_south;
-extern int key_map_east;
-extern int key_map_west;
-extern int key_map_zoomin;
-extern int key_map_zoomout;
-extern int key_map_toggle;
-extern int key_map_maxzoom;
-extern int key_map_follow;
-extern int key_map_grid;
-extern int key_map_mark;
-extern int key_map_clearmark;
+extern int mousebjump;
-// Weapon keys:
+extern int mousebstrafeleft;
+extern int mousebstraferight;
+extern int mousebbackward;
+extern int mousebuse;
-extern int key_weapon1;
-extern int key_weapon2;
-extern int key_weapon3;
-extern int key_weapon4;
-extern int key_weapon5;
-extern int key_weapon6;
-extern int key_weapon7;
-extern int key_weapon8;
-extern int key_prevweapon;
-extern int key_nextweapon;
+extern int mousebprevweapon;
+extern int mousebnextweapon;
-extern int key_message_refresh;
-extern int key_demo_quit;
+extern int joybfire;
+extern int joybstrafe;
+extern int joybuse;
+extern int joybspeed;
+
+extern int joybjump;
+
+extern int joybstrafeleft;
+extern int joybstraferight;
+
+extern int joybprevweapon;
+extern int joybnextweapon;
+
+extern int dclick_use;
+
+void M_BindBaseControls(void);
+void M_BindHereticControls(void);
+void M_BindHexenControls(void);
+void M_BindStrifeControls(void);
+void M_BindWeaponControls(void);
+void M_BindMapControls(void);
+void M_BindMenuControls(void);
+void M_BindChatControls(unsigned int num_players);
-void ConfigKeyboard(void);
+void M_ApplyPlatformDefaults(void);
-#endif /* #ifndef SETUP_KEYBOARD_H */
+#endif /* #ifndef __M_CONTROLS_H__ */
diff --git a/src/m_misc.c b/src/m_misc.c
index 31c87898..47aea8b9 100644
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -2,6 +2,7 @@
//-----------------------------------------------------------------------------
//
// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
// Copyright(C) 2005 Simon Howard
//
// This program is free software; you can redistribute it and/or
@@ -27,6 +28,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <ctype.h>
#include <errno.h>
@@ -42,10 +44,9 @@
#include <sys/types.h>
#endif
-#include "doomdef.h"
-#include "doomstat.h"
+#include "doomtype.h"
-#include "deh_main.h"
+#include "deh_str.h"
#include "i_swap.h"
#include "i_system.h"
@@ -206,6 +207,95 @@ boolean M_StrToInt(const char *str, int *result)
|| sscanf(str, " %d", result) == 1;
}
+void M_ExtractFileBase(char *path, char *dest)
+{
+ char *src;
+ char *filename;
+ int length;
+
+ src = path + strlen(path) - 1;
+
+ // back up until a \ or the start
+ while (src != path && *(src - 1) != DIR_SEPARATOR)
+ {
+ src--;
+ }
+
+ filename = src;
+
+ // Copy up to eight characters
+ // Note: Vanilla Doom exits with an error if a filename is specified
+ // with a base of more than eight characters. To remove the 8.3
+ // filename limit, instead we simply truncate the name.
+
+ length = 0;
+ memset(dest, 0, 8);
+
+ while (*src != '\0' && *src != '.')
+ {
+ if (length >= 8)
+ {
+ printf("Warning: Truncated '%s' lump name to '%.8s'.\n",
+ filename, dest);
+ break;
+ }
+
+ dest[length++] = toupper((int)*src++);
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC M_ForceUppercase
+//
+// Change string to uppercase.
+//
+//---------------------------------------------------------------------------
+
+void M_ForceUppercase(char *text)
+{
+ char *p;
+
+ for (p = text; *p != '\0'; ++p)
+ {
+ *p = toupper(*p);
+ }
+}
+
+//
+// M_StrCaseStr
+//
+// Case-insensitive version of strstr()
+//
+
+char *M_StrCaseStr(char *haystack, char *needle)
+{
+ unsigned int haystack_len;
+ unsigned int needle_len;
+ unsigned int len;
+ unsigned int i;
+
+ haystack_len = strlen(haystack);
+ needle_len = strlen(needle);
+
+ if (haystack_len < needle_len)
+ {
+ return NULL;
+ }
+
+ len = haystack_len - needle_len;
+
+ for (i = 0; i <= len; ++i)
+ {
+ if (!strncasecmp(haystack + i, needle, needle_len))
+ {
+ return haystack + i;
+ }
+ }
+
+ return NULL;
+}
+
#ifdef _WIN32
char *M_OEMToUTF8(const char *oem)
diff --git a/src/m_misc.h b/src/m_misc.h
index 6c2da4b1..ac5b5164 100644
--- a/src/m_misc.h
+++ b/src/m_misc.h
@@ -40,6 +40,9 @@ char *M_TempFile(char *s);
boolean M_FileExists(char *file);
long M_FileLength(FILE *handle);
boolean M_StrToInt(const char *str, int *result);
+void M_ExtractFileBase(char *path, char *dest);
+void M_ForceUppercase(char *text);
+char *M_StrCaseStr(char *haystack, char *needle);
char *M_OEMToUTF8(const char *ansi);
#endif
diff --git a/src/midifile.c b/src/midifile.c
index bd935ca1..e9af051c 100644
--- a/src/midifile.c
+++ b/src/midifile.c
@@ -28,7 +28,6 @@
#include <string.h>
#include <assert.h>
-#include "doomdef.h"
#include "doomtype.h"
#include "i_swap.h"
#include "midifile.h"
@@ -37,6 +36,11 @@
#define TRACK_CHUNK_ID "MTrk"
#define MAX_BUFFER_SIZE 0x10000
+// haleyjd 09/09/10: packing required
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif
+
typedef struct
{
byte chunk_id[4];
@@ -51,6 +55,11 @@ typedef struct
unsigned short time_division;
} PACKEDATTR midi_header_t;
+// haleyjd 09/09/10: packing off.
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif
+
typedef struct
{
// Length in bytes:
diff --git a/src/mus2mid.c b/src/mus2mid.c
index 6b8b4f5c..739037e1 100644
--- a/src/mus2mid.c
+++ b/src/mus2mid.c
@@ -25,7 +25,6 @@
#include <stdio.h>
-#include "doomdef.h"
#include "doomtype.h"
#include "i_swap.h"
@@ -692,3 +691,46 @@ boolean mus2mid(MEMFILE *musinput, MEMFILE *midioutput)
return false;
}
+#ifdef STANDALONE
+
+#include "m_misc.h"
+#include "z_zone.h"
+
+int main(int argc, char *argv[])
+{
+ MEMFILE *src, *dst;
+ byte *infile;
+ long infile_len;
+ void *outfile;
+ size_t outfile_len;
+
+ if (argc != 3)
+ {
+ printf("Usage: %s <musfile> <midfile>\n", argv[0]);
+ exit(-1);
+ }
+
+ Z_Init();
+
+ infile_len = M_ReadFile(argv[1], &infile);
+
+ src = mem_fopen_read(infile, infile_len);
+ dst = mem_fopen_write();
+
+ if (mus2mid(src, dst))
+ {
+ fprintf(stderr, "mus2mid() failed\n");
+ exit(-1);
+ }
+
+ // Write result to output file:
+
+ mem_get_buf(dst, &outfile, &outfile_len);
+
+ M_WriteFile(argv[2], outfile, outfile_len);
+
+ return 0;
+}
+
+#endif
+
diff --git a/src/net_client.c b/src/net_client.c
index 24fb7f6c..43e28441 100644
--- a/src/net_client.c
+++ b/src/net_client.c
@@ -22,17 +22,19 @@
//
#include <ctype.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "config.h"
-#include "doomdef.h"
-#include "doomstat.h"
+#include "doomtype.h"
#include "deh_main.h"
-#include "g_game.h"
+#include "deh_str.h"
#include "i_system.h"
#include "i_timer.h"
#include "m_argv.h"
+#include "m_fixed.h"
+#include "m_config.h"
#include "m_misc.h"
#include "net_client.h"
#include "net_common.h"
@@ -45,6 +47,8 @@
#include "w_checksum.h"
#include "w_wad.h"
+extern void D_ReceiveTic(ticcmd_t *ticcmds, boolean *playeringame);
+
typedef enum
{
// waiting for the game to start
@@ -103,6 +107,10 @@ static net_clientstate_t client_state;
static net_addr_t *server_addr;
static net_context_t *client_context;
+// game settings, as received from the server when the game started
+
+static net_gamesettings_t settings;
+
// true if the client code is in use
boolean net_client_connected;
@@ -111,36 +119,7 @@ boolean net_client_connected;
boolean net_client_received_wait_data;
-// if true, this client is the controller of the game
-
-boolean net_client_controller = false;
-
-// Number of clients currently connected to the server
-
-unsigned int net_clients_in_game;
-
-// Number of drone players connected to the server
-
-unsigned int net_drones_in_game;
-
-// Names of all players
-
-char net_player_addresses[MAXPLAYERS][MAXPLAYERNAME];
-char net_player_names[MAXPLAYERS][MAXPLAYERNAME];
-
-// SHA1 checksums of the wad directory and dehacked data that the server
-// has sent to us.
-
-sha1_digest_t net_server_wad_sha1sum;
-sha1_digest_t net_server_deh_sha1sum;
-
-// Is the server a freedoom game?
-
-unsigned int net_server_is_freedoom;
-
-// Player number
-
-int net_player_number;
+net_waitdata_t net_client_wait_data;
// Waiting for the game to start?
@@ -150,6 +129,10 @@ boolean net_waiting_for_start = false;
char *net_player_name = NULL;
+// Connected but not participating in the game (observer)
+
+boolean drone = false;
+
// The last ticcmd constructed
static ticcmd_t last_ticcmd;
@@ -160,7 +143,7 @@ static net_server_send_t send_queue[BACKUPTICS];
// Receive window
-static ticcmd_t recvwindow_cmd_base[MAXPLAYERS];
+static ticcmd_t recvwindow_cmd_base[NET_MAXPLAYERS];
static int recvwindow_start;
static net_server_recv_t recvwindow[BACKUPTICS];
@@ -185,53 +168,11 @@ static fixed_t average_latency;
#define NET_CL_ExpandTicNum(b) NET_ExpandTicNum(recvwindow_start, (b))
-// Called when a player leaves the game
-
-static void NET_CL_PlayerQuitGame(player_t *player)
-{
- static char exitmsg[80];
-
- // Do this the same way as Vanilla Doom does, to allow dehacked
- // replacements of this message
-
- strncpy(exitmsg, DEH_String("Player 1 left the game"), sizeof(exitmsg));
- exitmsg[sizeof(exitmsg) - 1] = '\0';
-
- exitmsg[7] += player - players;
-
- players[consoleplayer].message = exitmsg;
-
- // TODO: check if it is sensible to do this:
-
- if (demorecording)
- {
- G_CheckDemoStatus ();
- }
-}
-
// Called when we become disconnected from the server
static void NET_CL_Disconnected(void)
{
- int i;
-
- // In drone mode, the game cannot continue once disconnected.
-
- if (drone)
- {
- I_Error("Disconnected from server in drone mode.");
- }
-
- // disconnected from server
-
- players[consoleplayer].message = "Disconnected from server";
- printf("Disconnected from server.\n");
-
- for (i=0; i<MAXPLAYERS; ++i)
- {
- if (i != consoleplayer)
- playeringame[i] = false;
- }
+ D_ReceiveTic(NULL, NULL);
}
// Expand a net_full_ticcmd_t, applying the diffs in cmd->cmds as
@@ -239,7 +180,8 @@ static void NET_CL_Disconnected(void)
// the d_net.c structures (netcmds/nettics) and save the new ticcmd
// back into recvwindow_cmd_base.
-static void NET_CL_ExpandFullTiccmd(net_full_ticcmd_t *cmd, unsigned int seq)
+static void NET_CL_ExpandFullTiccmd(net_full_ticcmd_t *cmd, unsigned int seq,
+ ticcmd_t *ticcmds)
{
int latency;
fixed_t adjustment;
@@ -299,40 +241,27 @@ static void NET_CL_ExpandFullTiccmd(net_full_ticcmd_t *cmd, unsigned int seq)
// Expand tic diffs for all players
- for (i=0; i<MAXPLAYERS; ++i)
+ for (i=0; i<NET_MAXPLAYERS; ++i)
{
- if (i == consoleplayer && !drone)
+ if (i == settings.consoleplayer && !drone)
{
continue;
}
- if (playeringame[i] && !cmd->playeringame[i])
- {
- NET_CL_PlayerQuitGame(&players[i]);
- }
-
- playeringame[i] = cmd->playeringame[i];
-
- if (playeringame[i])
+ if (cmd->playeringame[i])
{
net_ticdiff_t *diff;
- ticcmd_t ticcmd;
diff = &cmd->cmds[i];
// Use the ticcmd diff to patch the previous ticcmd to
// the new ticcmd
- NET_TiccmdPatch(&recvwindow_cmd_base[i], diff, &ticcmd);
-
- // Save in d_net.c structures
-
- netcmds[i][nettics[i] % BACKUPTICS] = ticcmd;
- ++nettics[i];
+ NET_TiccmdPatch(&recvwindow_cmd_base[i], diff, &ticcmds[i]);
// Store a copy for next time
- recvwindow_cmd_base[i] = ticcmd;
+ recvwindow_cmd_base[i] = ticcmds[i];
}
}
}
@@ -341,11 +270,15 @@ static void NET_CL_ExpandFullTiccmd(net_full_ticcmd_t *cmd, unsigned int seq)
static void NET_CL_AdvanceWindow(void)
{
+ ticcmd_t ticcmds[NET_MAXPLAYERS];
+
while (recvwindow[0].active)
{
// Expand tic diff data into d_net.c structures
- NET_CL_ExpandFullTiccmd(&recvwindow[0].cmd, recvwindow_start);
+ NET_CL_ExpandFullTiccmd(&recvwindow[0].cmd, recvwindow_start,
+ ticcmds);
+ D_ReceiveTic(ticcmds, recvwindow[0].cmd.playeringame);
// Advance the window
@@ -373,66 +306,9 @@ static void NET_CL_Shutdown(void)
}
}
-void NET_CL_StartGame(void)
+void NET_CL_StartGame(net_gamesettings_t *settings)
{
net_packet_t *packet;
- net_gamesettings_t settings;
- int i;
-
- // Fill in game settings structure with appropriate parameters
- // for the new game
-
- settings.deathmatch = deathmatch;
- settings.episode = startepisode;
- settings.map = startmap;
- settings.skill = startskill;
- settings.loadgame = startloadgame;
- settings.gameversion = gameversion;
- settings.nomonsters = nomonsters;
- settings.fast_monsters = fastparm;
- settings.respawn_monsters = respawnparm;
- settings.timelimit = timelimit;
-
- //!
- // @category net
- //
- // Use original game sync code.
- //
-
- if (M_CheckParm("-oldsync") > 0)
- settings.new_sync = 0;
- else
- settings.new_sync = 1;
-
- //!
- // @category net
- // @arg <n>
- //
- // Send n extra tics in every packet as insurance against dropped
- // packets.
- //
-
- i = M_CheckParmWithArgs("-extratics", 1);
-
- if (i > 0)
- settings.extratics = atoi(myargv[i+1]);
- else
- settings.extratics = 1;
-
- //!
- // @category net
- // @arg <n>
- //
- // Reduce the resolution of the game by a factor of n, reducing
- // the amount of network bandwidth needed.
- //
-
- i = M_CheckParmWithArgs("-dup", 1);
-
- if (i > 0)
- settings.ticdup = atoi(myargv[i+1]);
- else
- settings.ticdup = 1;
// Start from a ticcmd of all zeros
@@ -443,7 +319,7 @@ void NET_CL_StartGame(void)
packet = NET_Conn_NewReliable(&client_connection,
NET_PACKET_TYPE_GAMESTART);
- NET_WriteSettings(packet, &settings);
+ NET_WriteSettings(packet, settings);
}
static void NET_CL_SendGameDataACK(void)
@@ -453,7 +329,7 @@ static void NET_CL_SendGameDataACK(void)
packet = NET_NewPacket(10);
NET_WriteInt16(packet, NET_PACKET_TYPE_GAMEDATA_ACK);
- NET_WriteInt8(packet, (gametic / ticdup) & 0xff);
+ NET_WriteInt8(packet, recvwindow_start & 0xff);
NET_Conn_SendPacket(&client_connection, packet);
@@ -485,7 +361,7 @@ static void NET_CL_SendTics(int start, int end)
// Write the start tic and number of tics. Send only the low byte
// of start - it can be inferred by the server.
- NET_WriteInt8(packet, (gametic / ticdup) & 0xff);
+ NET_WriteInt8(packet, recvwindow_start & 0xff);
NET_WriteInt8(packet, start & 0xff);
NET_WriteInt8(packet, end - start + 1);
@@ -499,7 +375,7 @@ static void NET_CL_SendTics(int start, int end)
NET_WriteInt16(packet, average_latency / FRACUNIT);
- NET_WriteTiccmdDiff(packet, &sendobj->cmd, lowres_turn);
+ NET_WriteTiccmdDiff(packet, &sendobj->cmd, settings.lowres_turn);
}
// Send the packet
@@ -539,7 +415,7 @@ void NET_CL_SendTiccmd(ticcmd_t *ticcmd, int maketic)
// Send to server.
- starttic = maketic - extratics;
+ starttic = maketic - settings.extratics;
endtic = maketic;
if (starttic < 0)
@@ -552,92 +428,38 @@ void NET_CL_SendTiccmd(ticcmd_t *ticcmd, int maketic)
static void NET_CL_ParseWaitingData(net_packet_t *packet)
{
- unsigned int num_players;
- unsigned int num_drones;
- unsigned int is_controller;
- signed int player_number;
- char *player_names[MAXPLAYERS];
- char *player_addr[MAXPLAYERS];
- sha1_digest_t wad_sha1sum, deh_sha1sum;
- unsigned int server_is_freedoom;
- size_t i;
+ net_waitdata_t wait_data;
- if (!NET_ReadInt8(packet, &num_players)
- || !NET_ReadInt8(packet, &num_drones)
- || !NET_ReadInt8(packet, &is_controller)
- || !NET_ReadSInt8(packet, &player_number))
+ if (!NET_ReadWaitData(packet, &wait_data))
{
- // invalid packet
-
+ // Invalid packet?
return;
}
- if (num_players > MAXPLAYERS)
+ if (wait_data.num_players > wait_data.max_players
+ || wait_data.max_players > NET_MAXPLAYERS)
{
// insane data
return;
}
- if ((player_number >= 0 && drone)
- || (player_number < 0 && !drone)
- || (player_number >= (signed int) num_players))
+ if ((wait_data.consoleplayer >= 0 && drone)
+ || (wait_data.consoleplayer < 0 && !drone)
+ || (wait_data.consoleplayer >= wait_data.num_players))
{
// Invalid player number
return;
}
-
- // Read the player names
-
- for (i=0; i<num_players; ++i)
- {
- player_names[i] = NET_ReadString(packet);
- player_addr[i] = NET_ReadString(packet);
-
- if (player_names[i] == NULL || player_addr[i] == NULL)
- {
- return;
- }
- }
-
- if (!NET_ReadSHA1Sum(packet, wad_sha1sum)
- || !NET_ReadSHA1Sum(packet, deh_sha1sum)
- || !NET_ReadInt8(packet, &server_is_freedoom))
- {
- return;
- }
-
- net_clients_in_game = num_players;
- net_drones_in_game = num_drones;
- net_client_controller = is_controller != 0;
- net_player_number = player_number;
-
- for (i=0; i<num_players; ++i)
- {
- strncpy(net_player_names[i], player_names[i], MAXPLAYERNAME);
- net_player_names[i][MAXPLAYERNAME-1] = '\0';
- strncpy(net_player_addresses[i], player_addr[i], MAXPLAYERNAME);
- net_player_addresses[i][MAXPLAYERNAME-1] = '\0';
- }
-
- memcpy(net_server_wad_sha1sum, wad_sha1sum, sizeof(sha1_digest_t));
- memcpy(net_server_deh_sha1sum, deh_sha1sum, sizeof(sha1_digest_t));
- net_server_is_freedoom = server_is_freedoom;
+ memcpy(&net_client_wait_data, &wait_data, sizeof(net_waitdata_t));
net_client_received_wait_data = true;
}
static void NET_CL_ParseGameStart(net_packet_t *packet)
{
- net_gamesettings_t settings;
- unsigned int num_players;
- signed int player_number;
- unsigned int i;
-
- if (!NET_ReadInt8(packet, &num_players)
- || !NET_ReadSInt8(packet, &player_number)
- || !NET_ReadSettings(packet, &settings))
+ if (!NET_ReadSettings(packet, &settings))
{
return;
}
@@ -647,14 +469,15 @@ static void NET_CL_ParseGameStart(net_packet_t *packet)
return;
}
- if (num_players > MAXPLAYERS || player_number >= (signed int) num_players)
+ if (settings.num_players > NET_MAXPLAYERS
+ || settings.consoleplayer >= (signed int) settings.num_players)
{
// insane values
return;
}
- if ((drone && player_number >= 0)
- || (!drone && player_number < 0))
+ if ((drone && settings.consoleplayer >= 0)
+ || (!drone && settings.consoleplayer < 0))
{
// Invalid player number: must be positive for real players,
// negative for drones
@@ -662,49 +485,8 @@ static void NET_CL_ParseGameStart(net_packet_t *packet)
return;
}
- // Start the game
-
- if (!drone)
- {
- consoleplayer = player_number;
- }
- else
- {
- consoleplayer = 0;
- }
-
- for (i=0; i<MAXPLAYERS; ++i)
- {
- playeringame[i] = i < num_players;
- }
-
client_state = CLIENT_STATE_IN_GAME;
- deathmatch = settings.deathmatch;
- ticdup = settings.ticdup;
- extratics = settings.extratics;
- startepisode = settings.episode;
- startmap = settings.map;
- startskill = settings.skill;
- startloadgame = settings.loadgame;
- lowres_turn = settings.lowres_turn;
- nomonsters = settings.nomonsters;
- fastparm = settings.fast_monsters;
- respawnparm = settings.respawn_monsters;
- net_cl_new_sync = settings.new_sync != 0;
- timelimit = settings.timelimit;
-
- if (net_cl_new_sync == false)
- {
- printf("Syncing netgames like Vanilla Doom.\n");
- }
-
- if (lowres_turn)
- {
- printf("NOTE: Turning resolution is reduced; this is probably "
- "because there is a client recording a Vanilla demo.\n");
- }
-
// Clear the receive window
memset(recvwindow, 0, sizeof(recvwindow));
@@ -714,9 +496,6 @@ static void NET_CL_ParseGameStart(net_packet_t *packet)
// Clear the send queue
memset(&send_queue, 0x00, sizeof(send_queue));
-
- netgame = true;
- autostart = true;
}
static void NET_CL_SendResendRequest(int start, int end)
@@ -863,7 +642,7 @@ static void NET_CL_ParseGameData(net_packet_t *packet)
index = seq - recvwindow_start + i;
- if (!NET_ReadFullTiccmd(packet, &cmd, lowres_turn))
+ if (!NET_ReadFullTiccmd(packet, &cmd, settings.lowres_turn))
{
return;
}
@@ -1104,7 +883,7 @@ void NET_CL_Run(void)
}
}
-static void NET_CL_SendSYN(void)
+static void NET_CL_SendSYN(net_connect_data_t *data)
{
net_packet_t *packet;
@@ -1112,13 +891,7 @@ static void NET_CL_SendSYN(void)
NET_WriteInt16(packet, NET_PACKET_TYPE_SYN);
NET_WriteInt32(packet, NET_MAGIC_NUMBER);
NET_WriteString(packet, PACKAGE_STRING);
- NET_WriteInt16(packet, gamemode);
- NET_WriteInt16(packet, gamemission);
- NET_WriteInt8(packet, lowres_turn);
- NET_WriteInt8(packet, drone);
- NET_WriteSHA1Sum(packet, net_local_wad_sha1sum);
- NET_WriteSHA1Sum(packet, net_local_deh_sha1sum);
- NET_WriteInt8(packet, net_local_is_freedoom);
+ NET_WriteConnectData(packet, data);
NET_WriteString(packet, net_player_name);
NET_Conn_SendPacket(&client_connection, packet);
NET_FreePacket(packet);
@@ -1126,34 +899,22 @@ static void NET_CL_SendSYN(void)
// connect to a server
-boolean NET_CL_Connect(net_addr_t *addr)
+boolean NET_CL_Connect(net_addr_t *addr, net_connect_data_t *data)
{
int start_time;
int last_send_time;
server_addr = addr;
- // Are we recording a demo? Possibly set lowres turn mode
-
- if (M_CheckParm("-record") > 0 && M_CheckParm("-longtics") == 0)
- {
- lowres_turn = true;
- }
-
- // Read checksums of our WAD directory and dehacked information
-
- W_Checksum(net_local_wad_sha1sum);
- DEH_Checksum(net_local_deh_sha1sum);
-
- // Are we playing with the Freedoom IWAD?
-
- net_local_is_freedoom = W_CheckNumForName("FREEDOOM") >= 0;
+ memcpy(net_local_wad_sha1sum, data->wad_sha1sum, sizeof(sha1_digest_t));
+ memcpy(net_local_deh_sha1sum, data->deh_sha1sum, sizeof(sha1_digest_t));
+ net_local_is_freedoom = data->is_freedoom;
// create a new network I/O context and add just the
// necessary module
client_context = NET_NewContext();
-
+
// initialize module for client mode
if (!addr->module->InitClient())
@@ -1183,7 +944,7 @@ boolean NET_CL_Connect(net_addr_t *addr)
if (nowtime - last_send_time > 1000 || last_send_time < 0)
{
- NET_CL_SendSYN();
+ NET_CL_SendSYN(data);
last_send_time = nowtime;
}
@@ -1197,7 +958,7 @@ boolean NET_CL_Connect(net_addr_t *addr)
// run client code
NET_CL_Run();
-
+
// run the server, just incase we are doing a loopback
// connect
@@ -1213,6 +974,7 @@ boolean NET_CL_Connect(net_addr_t *addr)
// connected ok!
client_state = CLIENT_STATE_WAITING_START;
+ drone = data->drone;
return true;
}
@@ -1221,9 +983,23 @@ boolean NET_CL_Connect(net_addr_t *addr)
// failed to connect
NET_CL_Shutdown();
-
+
+ return false;
+ }
+}
+
+// read game settings received from server
+
+boolean NET_CL_GetSettings(net_gamesettings_t *_settings)
+{
+ if (client_state != CLIENT_STATE_IN_GAME)
+ {
return false;
}
+
+ memcpy(_settings, &settings, sizeof(net_gamesettings_t));
+
+ return true;
}
// disconnect from the server
@@ -1294,3 +1070,7 @@ void NET_Init(void)
NET_CL_Init();
}
+void NET_BindVariables(void)
+{
+ M_BindVariable("player_name", &net_player_name);
+}
diff --git a/src/net_client.h b/src/net_client.h
index a752b747..3914849d 100644
--- a/src/net_client.h
+++ b/src/net_client.h
@@ -24,31 +24,26 @@
#ifndef NET_CLIENT_H
#define NET_CLIENT_H
-#include "doomdef.h"
#include "doomtype.h"
#include "d_ticcmd.h"
#include "sha1.h"
#include "net_defs.h"
-#define MAXPLAYERNAME 30
-
-boolean NET_CL_Connect(net_addr_t *addr);
+boolean NET_CL_Connect(net_addr_t *addr, net_connect_data_t *data);
void NET_CL_Disconnect(void);
void NET_CL_Run(void);
void NET_CL_Init(void);
-void NET_CL_StartGame();
+void NET_CL_StartGame(net_gamesettings_t *settings);
void NET_CL_SendTiccmd(ticcmd_t *ticcmd, int maketic);
+boolean NET_CL_GetSettings(net_gamesettings_t *_settings);
void NET_Init(void);
+void NET_BindVariables(void);
+
extern boolean net_client_connected;
extern boolean net_client_received_wait_data;
-extern boolean net_client_controller;
-extern unsigned int net_clients_in_game;
-extern unsigned int net_drones_in_game;
+extern net_waitdata_t net_client_wait_data;
extern boolean net_waiting_for_start;
-extern char net_player_names[MAXPLAYERS][MAXPLAYERNAME];
-extern char net_player_addresses[MAXPLAYERS][MAXPLAYERNAME];
-extern int net_player_number;
extern char *net_player_name;
extern sha1_digest_t net_server_wad_sha1sum;
@@ -58,6 +53,6 @@ extern sha1_digest_t net_local_wad_sha1sum;
extern sha1_digest_t net_local_deh_sha1sum;
extern unsigned int net_local_is_freedoom;
+extern boolean drone;
#endif /* #ifndef NET_CLIENT_H */
-
diff --git a/src/net_common.c b/src/net_common.c
index da3d7fd5..f25cc73d 100644
--- a/src/net_common.c
+++ b/src/net_common.c
@@ -21,15 +21,17 @@
// Common code shared between the client and server
//
-#include <ctype.h>
+#include <stdio.h>
#include <stdlib.h>
-#include "doomdef.h"
+#include "doomtype.h"
+#include "d_mode.h"
#include "i_timer.h"
#include "net_common.h"
#include "net_io.h"
#include "net_packet.h"
+#include "net_structrw.h"
// connections time out after 10 seconds
@@ -511,44 +513,6 @@ unsigned int NET_ExpandTicNum(unsigned int relative, unsigned int b)
return result;
}
-// "Safe" version of puts, for displaying messages received from the
-// network.
-
-void NET_SafePuts(char *s)
-{
- char *p;
-
- // Do not do a straight "puts" of the string, as this could be
- // dangerous (sending control codes to terminals can do all
- // kinds of things)
-
- for (p=s; *p; ++p)
- {
- if (isprint(*p))
- putchar(*p);
- }
-
- putchar('\n');
-}
-
-// Check that a gamemode+gamemission received over the network is valid.
-
-boolean NET_ValidGameMode(GameMode_t mode, GameMission_t mission)
-{
- if (mode == shareware || mode == registered || mode == retail)
- {
- return true;
- }
- else if (mode == commercial)
- {
- return mission == doom2 || mission == pack_tnt || mission == pack_plut;
- }
- else
- {
- return false;
- }
-}
-
// Check that game settings are valid
boolean NET_ValidGameSettings(GameMode_t mode, GameMission_t mission,
@@ -566,7 +530,7 @@ boolean NET_ValidGameSettings(GameMode_t mode, GameMission_t mission,
if (settings->skill < sk_noitems || settings->skill > sk_nightmare)
return false;
- if (settings->gameversion < exe_doom_1_9 || settings->gameversion > exe_chex)
+ if (!D_ValidGameVersion(mission, settings->gameversion))
return false;
if (mode == shareware || mode == retail || mode == registered)
diff --git a/src/net_common.h b/src/net_common.h
index 885ee44d..96e9a648 100644
--- a/src/net_common.h
+++ b/src/net_common.h
@@ -24,6 +24,7 @@
#ifndef NET_COMMON_H
#define NET_COMMON_H
+#include "d_mode.h"
#include "net_defs.h"
#include "net_packet.h"
@@ -109,10 +110,7 @@ net_packet_t *NET_Conn_NewReliable(net_connection_t *conn, int packet_type);
// Other miscellaneous common functions
-void NET_SafePuts(char *msg);
unsigned int NET_ExpandTicNum(unsigned int relative, unsigned int b);
-
-boolean NET_ValidGameMode(GameMode_t mode, GameMission_t mission);
boolean NET_ValidGameSettings(GameMode_t mode, GameMission_t mission,
net_gamesettings_t *settings);
diff --git a/src/net_dedicated.c b/src/net_dedicated.c
index 82909210..d8e50731 100644
--- a/src/net_dedicated.c
+++ b/src/net_dedicated.c
@@ -23,6 +23,9 @@
// Dedicated server code.
//
+#include <stdio.h>
+#include <stdlib.h>
+
#include "doomtype.h"
#include "i_system.h"
diff --git a/src/net_defs.h b/src/net_defs.h
index c2d4d561..ba50f48e 100644
--- a/src/net_defs.h
+++ b/src/net_defs.h
@@ -26,9 +26,31 @@
#ifndef NET_DEFS_H
#define NET_DEFS_H
-#include "doomdef.h"
+#include <stdio.h>
+
#include "doomtype.h"
#include "d_ticcmd.h"
+#include "sha1.h"
+
+// Absolute maximum number of "nodes" in the game. This is different to
+// NET_MAXPLAYERS, as there may be observers that are not participating
+// (eg. left/right monitors)
+
+#define MAXNETNODES 16
+
+// The maximum number of players, multiplayer/networking.
+// This is the maximum supported by the networking code; individual games
+// have their own values for MAXPLAYERS that can be smaller.
+
+#define NET_MAXPLAYERS 8
+
+// Maximum length of a player's name.
+
+#define MAXPLAYERNAME 30
+
+// Networking and tick handling related.
+
+#define BACKUPTICS 128
typedef struct _net_module_s net_module_t;
typedef struct _net_packet_s net_packet_t;
@@ -127,6 +149,24 @@ typedef enum
NET_MASTER_PACKET_TYPE_SIGN_END_RESPONSE,
} net_master_packet_type_t;
+// Settings specified when the client connects to the server.
+
+typedef struct
+{
+ int gamemode;
+ int gamemission;
+ int lowres_turn;
+ int drone;
+ int max_players;
+ int is_freedoom;
+ sha1_digest_t wad_sha1sum;
+ sha1_digest_t deh_sha1sum;
+ int player_class;
+} net_connect_data_t;
+
+// Game settings sent by client to server when initiating game start,
+// and received from the server by clients when the game starts.
+
typedef struct
{
int ticdup;
@@ -143,6 +183,17 @@ typedef struct
int new_sync;
int timelimit;
int loadgame;
+
+ // These fields are only used by the server when sending a game
+ // start message:
+
+ int num_players;
+ int consoleplayer;
+
+ // Hexen player classes:
+
+ int player_classes[NET_MAXPLAYERS];
+
} net_gamesettings_t;
#define NET_TICDIFF_FORWARD (1 << 0)
@@ -151,6 +202,8 @@ typedef struct
#define NET_TICDIFF_BUTTONS (1 << 3)
#define NET_TICDIFF_CONSISTANCY (1 << 4)
#define NET_TICDIFF_CHATCHAR (1 << 5)
+#define NET_TICDIFF_RAVEN (1 << 6)
+#define NET_TICDIFF_STRIFE (1 << 7)
typedef struct
{
@@ -164,8 +217,8 @@ typedef struct
{
signed int latency;
unsigned int seq;
- boolean playeringame[MAXPLAYERS];
- net_ticdiff_t cmds[MAXPLAYERS];
+ boolean playeringame[NET_MAXPLAYERS];
+ net_ticdiff_t cmds[NET_MAXPLAYERS];
} net_full_ticcmd_t;
// Data sent in response to server queries
@@ -181,5 +234,20 @@ typedef struct
char *description;
} net_querydata_t;
-#endif /* #ifndef NET_DEFS_H */
+// Data sent by the server while waiting for the game to start.
+typedef struct
+{
+ int num_players;
+ int num_drones;
+ int max_players;
+ int is_controller;
+ int consoleplayer;
+ char player_names[NET_MAXPLAYERS][MAXPLAYERNAME];
+ char player_addrs[NET_MAXPLAYERS][MAXPLAYERNAME];
+ sha1_digest_t wad_sha1sum;
+ sha1_digest_t deh_sha1sum;
+ int is_freedoom;
+} net_waitdata_t;
+
+#endif /* #ifndef NET_DEFS_H */
diff --git a/src/net_gui.c b/src/net_gui.c
index 0ff9e55b..14d0d943 100644
--- a/src/net_gui.c
+++ b/src/net_gui.c
@@ -24,11 +24,12 @@
// start the game.
//
+#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "config.h"
-#include "doomstat.h"
+#include "doomkeys.h"
#include "i_system.h"
#include "i_timer.h"
@@ -41,8 +42,9 @@
#include "textscreen.h"
static txt_window_t *window;
-static txt_label_t *player_labels[MAXPLAYERS];
-static txt_label_t *ip_labels[MAXPLAYERS];
+static int old_max_players;
+static txt_label_t *player_labels[NET_MAXPLAYERS];
+static txt_label_t *ip_labels[NET_MAXPLAYERS];
static txt_label_t *drone_label;
static boolean had_warning;
@@ -52,23 +54,38 @@ static void EscapePressed(TXT_UNCAST_ARG(widget), void *unused)
I_Quit();
}
-static void StartGame(TXT_UNCAST_ARG(widget), void *unused)
+static void StartGame(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(settings))
{
- NET_CL_StartGame();
+ TXT_CAST_ARG(net_gamesettings_t, settings);
+
+ NET_CL_StartGame(settings);
}
-static void BuildGUI(void)
+static void OpenWaitDialog(void)
{
- char buf[50];
- txt_table_t *table;
txt_window_action_t *cancel;
- int i;
-
- had_warning = false;
TXT_SetDesktopTitle(PACKAGE_STRING);
-
+
window = TXT_NewWindow("Waiting for game start...");
+
+ TXT_AddWidget(window, TXT_NewLabel("\nPlease wait...\n\n"));
+
+ cancel = TXT_NewWindowAction(KEY_ESCAPE, "Cancel");
+ TXT_SignalConnect(cancel, "pressed", EscapePressed, NULL);
+
+ TXT_SetWindowAction(window, TXT_HORIZ_LEFT, cancel);
+
+ old_max_players = 0;
+}
+
+static void BuildWindow(void)
+{
+ char buf[50];
+ txt_table_t *table;
+ int i;
+
+ TXT_ClearTable(window);
table = TXT_NewTable(3);
TXT_AddWidget(window, table);
@@ -79,8 +96,8 @@ static void BuildGUI(void)
TXT_AddWidget(table, TXT_NewStrut(17, 1));
// Player labels
-
- for (i=0; i<MAXPLAYERS; ++i)
+
+ for (i = 0; i < net_client_wait_data.max_players; ++i)
{
sprintf(buf, " %i. ", i + 1);
TXT_AddWidget(table, TXT_NewLabel(buf));
@@ -93,24 +110,35 @@ static void BuildGUI(void)
drone_label = TXT_NewLabel("");
TXT_AddWidget(window, drone_label);
-
- cancel = TXT_NewWindowAction(KEY_ESCAPE, "Cancel");
- TXT_SignalConnect(cancel, "pressed", EscapePressed, NULL);
-
- TXT_SetWindowAction(window, TXT_HORIZ_LEFT, cancel);
}
-static void UpdateGUI(void)
+static void UpdateGUI(net_gamesettings_t *settings)
{
txt_window_action_t *startgame;
char buf[50];
unsigned int i;
- for (i=0; i<MAXPLAYERS; ++i)
+ // If the value of max_players changes, we must rebuild the
+ // contents of the window. This includes when the first
+ // waiting data packet is received.
+
+ if (net_client_received_wait_data)
+ {
+ if (net_client_wait_data.max_players != old_max_players)
+ {
+ BuildWindow();
+ }
+ }
+ else
+ {
+ return;
+ }
+
+ for (i = 0; i < net_client_wait_data.max_players; ++i)
{
txt_color_t color = TXT_COLOR_BRIGHT_WHITE;
- if ((signed) i == net_player_number)
+ if ((signed) i == net_client_wait_data.consoleplayer)
{
color = TXT_COLOR_YELLOW;
}
@@ -118,10 +146,12 @@ static void UpdateGUI(void)
TXT_SetFGColor(player_labels[i], color);
TXT_SetFGColor(ip_labels[i], color);
- if (i < net_clients_in_game)
+ if (i < net_client_wait_data.num_players)
{
- TXT_SetLabel(player_labels[i], net_player_names[i]);
- TXT_SetLabel(ip_labels[i], net_player_addresses[i]);
+ TXT_SetLabel(player_labels[i],
+ net_client_wait_data.player_names[i]);
+ TXT_SetLabel(ip_labels[i],
+ net_client_wait_data.player_addrs[i]);
}
else
{
@@ -130,9 +160,10 @@ static void UpdateGUI(void)
}
}
- if (net_drones_in_game > 0)
+ if (net_client_wait_data.num_drones > 0)
{
- sprintf(buf, " (+%i observer clients)", net_drones_in_game);
+ sprintf(buf, " (+%i observer clients)",
+ net_client_wait_data.num_drones);
TXT_SetLabel(drone_label, buf);
}
else
@@ -140,10 +171,10 @@ static void UpdateGUI(void)
TXT_SetLabel(drone_label, "");
}
- if (net_client_controller)
+ if (net_client_wait_data.is_controller)
{
startgame = TXT_NewWindowAction(' ', "Start game");
- TXT_SignalConnect(startgame, "pressed", StartGame, NULL);
+ TXT_SignalConnect(startgame, "pressed", StartGame, settings);
}
else
{
@@ -178,11 +209,13 @@ static void CheckSHA1Sums(void)
return;
}
- correct_wad = memcmp(net_local_wad_sha1sum, net_server_wad_sha1sum,
+ correct_wad = memcmp(net_local_wad_sha1sum,
+ net_client_wait_data.wad_sha1sum,
sizeof(sha1_digest_t)) == 0;
- correct_deh = memcmp(net_local_deh_sha1sum, net_server_deh_sha1sum,
+ correct_deh = memcmp(net_local_deh_sha1sum,
+ net_client_wait_data.deh_sha1sum,
sizeof(sha1_digest_t)) == 0;
- same_freedoom = net_server_is_freedoom == net_local_is_freedoom;
+ same_freedoom = net_client_wait_data.is_freedoom == net_local_is_freedoom;
if (correct_wad && correct_deh && same_freedoom)
{
@@ -193,7 +226,7 @@ static void CheckSHA1Sums(void)
{
printf("Warning: WAD SHA1 does not match server:\n");
PrintSHA1Digest("Local", net_local_wad_sha1sum);
- PrintSHA1Digest("Server", net_server_wad_sha1sum);
+ PrintSHA1Digest("Server", net_client_wait_data.wad_sha1sum);
}
if (!same_freedoom)
@@ -201,14 +234,14 @@ static void CheckSHA1Sums(void)
printf("Warning: Mixing Freedoom with non-Freedoom\n");
printf("Local: %i Server: %i\n",
net_local_is_freedoom,
- net_server_is_freedoom);
+ net_client_wait_data.is_freedoom);
}
if (!correct_deh)
{
printf("Warning: Dehacked SHA1 does not match server:\n");
PrintSHA1Digest("Local", net_local_deh_sha1sum);
- PrintSHA1Digest("Server", net_server_deh_sha1sum);
+ PrintSHA1Digest("Server", net_client_wait_data.deh_sha1sum);
}
window = TXT_NewWindow("WARNING");
@@ -258,7 +291,7 @@ static void CheckSHA1Sums(void)
had_warning = true;
}
-void NET_WaitForStart(void)
+void NET_WaitForStart(net_gamesettings_t *settings)
{
if (!TXT_Init())
{
@@ -266,14 +299,15 @@ void NET_WaitForStart(void)
exit(-1);
}
- I_SetWindowCaption();
- I_SetWindowIcon();
+ I_SetWindowTitle("Waiting for game start");
+ //I_SetWindowIcon();
- BuildGUI();
+ OpenWaitDialog();
+ had_warning = false;
while (net_waiting_for_start)
{
- UpdateGUI();
+ UpdateGUI(settings);
CheckSHA1Sums();
TXT_DispatchEvents();
@@ -292,4 +326,3 @@ void NET_WaitForStart(void)
TXT_Shutdown();
}
-
diff --git a/src/net_gui.h b/src/net_gui.h
index fdcc81be..9d40b0d0 100644
--- a/src/net_gui.h
+++ b/src/net_gui.h
@@ -30,7 +30,7 @@
#include "doomtype.h"
-extern void NET_WaitForStart();
+extern void NET_WaitForStart(net_gamesettings_t *settings);
#endif /* #ifndef NET_GUI_H */
diff --git a/src/net_io.c b/src/net_io.c
index 1d576618..19c21a12 100644
--- a/src/net_io.c
+++ b/src/net_io.c
@@ -24,6 +24,8 @@
//
//-----------------------------------------------------------------------------
+#include <stdio.h>
+
#include "i_system.h"
#include "net_defs.h"
#include "net_io.h"
diff --git a/src/net_loop.c b/src/net_loop.c
index b8387794..acdc2cb6 100644
--- a/src/net_loop.c
+++ b/src/net_loop.c
@@ -26,7 +26,7 @@
#include <stdio.h>
#include <stdlib.h>
-#include "doomdef.h"
+#include "doomtype.h"
#include "i_system.h"
#include "net_defs.h"
#include "net_loop.h"
diff --git a/src/net_query.c b/src/net_query.c
index 475fa98f..392ee022 100644
--- a/src/net_query.c
+++ b/src/net_query.c
@@ -22,8 +22,10 @@
// Querying servers to find their current status.
//
+#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
+#include <string.h>
#include "i_system.h"
#include "i_timer.h"
@@ -532,10 +534,14 @@ static void NET_Query_QueryLoop(net_query_callback_t callback, void *user_data)
void NET_Query_Init(void)
{
- query_context = NET_NewContext();
- NET_AddModule(query_context, &net_sdl_module);
- net_sdl_module.InitClient();
+ if (query_context == NULL)
+ {
+ query_context = NET_NewContext();
+ NET_AddModule(query_context, &net_sdl_module);
+ net_sdl_module.InitClient();
+ }
+ free(targets);
targets = NULL;
num_targets = 0;
@@ -646,23 +652,35 @@ static void formatted_printf(int wide, char *s, ...)
static char *GameDescription(GameMode_t mode, GameMission_t mission)
{
- switch (mode)
- {
- case shareware:
- return "shareware";
- case registered:
- return "registered";
- case retail:
- return "ultimate";
- case commercial:
- if (mission == doom2)
- return "doom2";
- else if (mission == pack_tnt)
- return "tnt";
- else if (mission == pack_plut)
- return "plutonia";
+ switch (mission)
+ {
+ case doom:
+ if (mode == shareware)
+ return "swdoom";
+ else if (mode == registered)
+ return "regdoom";
+ else if (mode == retail)
+ return "ultdoom";
+ else
+ return "doom";
+ case doom2:
+ return "doom2";
+ case pack_tnt:
+ return "tnt";
+ case pack_plut:
+ return "plutonia";
+ case pack_chex:
+ return "chex";
+ case pack_hacx:
+ return "hacx";
+ case heretic:
+ return "heretic";
+ case hexen:
+ return "hexen";
+ case strife:
+ return "strife";
default:
- return "unknown";
+ return "?";
}
}
diff --git a/src/net_sdl.c b/src/net_sdl.c
index 2f7eaa6f..de86172f 100644
--- a/src/net_sdl.c
+++ b/src/net_sdl.c
@@ -27,7 +27,7 @@
#include <string.h>
#include <stdio.h>
-#include "doomdef.h"
+#include "doomtype.h"
#include "i_system.h"
#include "m_argv.h"
#include "net_defs.h"
diff --git a/src/net_server.c b/src/net_server.c
index 189e824f..585f0eac 100644
--- a/src/net_server.c
+++ b/src/net_server.c
@@ -21,14 +21,15 @@
// Network server code
//
+#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include "config.h"
-#include "doomdef.h"
-#include "doomstat.h"
+#include "doomtype.h"
+#include "d_mode.h"
#include "i_system.h"
#include "i_timer.h"
@@ -96,6 +97,10 @@ typedef struct
unsigned int acknowledged;
+ // Value of max_players specified by the client on connect.
+
+ int max_players;
+
// Observer: receives data but does not participate in the game.
boolean drone;
@@ -109,6 +114,10 @@ typedef struct
unsigned int is_freedoom;
+ // Player class (for Hexen)
+
+ int player_class;
+
} net_client_t;
// structure used for the recv window
@@ -135,7 +144,7 @@ typedef struct
static net_server_state_t server_state;
static boolean server_initialized = false;
static net_client_t clients[MAXNETNODES];
-static net_client_t *sv_players[MAXPLAYERS];
+static net_client_t *sv_players[NET_MAXPLAYERS];
static net_context_t *server_context;
static unsigned int sv_gamemode;
static unsigned int sv_gamemission;
@@ -150,7 +159,7 @@ static unsigned int master_resolve_time;
// receive window
static unsigned int recvwindow_start;
-static net_client_recv_t recvwindow[BACKUPTICS][MAXPLAYERS];
+static net_client_recv_t recvwindow[BACKUPTICS][NET_MAXPLAYERS];
#define NET_SV_ExpandTicNum(b) NET_ExpandTicNum(recvwindow_start, (b))
@@ -239,7 +248,7 @@ static void NET_SV_AssignPlayers(void)
}
}
- for (; pl<MAXPLAYERS; ++pl)
+ for (; pl<NET_MAXPLAYERS; ++pl)
{
sv_players[pl] = NULL;
}
@@ -254,7 +263,7 @@ static int NET_SV_NumPlayers(void)
result = 0;
- for (i=0; i<MAXPLAYERS; ++i)
+ for (i=0; i<NET_MAXPLAYERS; ++i)
{
if (sv_players[i] != NULL && ClientConnected(sv_players[i]))
{
@@ -265,6 +274,23 @@ static int NET_SV_NumPlayers(void)
return result;
}
+// Returns the maximum number of players that can play.
+
+static int NET_SV_MaxPlayers(void)
+{
+ int i;
+
+ for (i = 0; i < MAXNETNODES; ++i)
+ {
+ if (ClientConnected(&clients[i]))
+ {
+ return clients[i].max_players;
+ }
+ }
+
+ return NET_MAXPLAYERS;
+}
+
// Returns the number of drones currently connected.
static int NET_SV_NumDrones(void)
@@ -354,7 +380,7 @@ static void NET_SV_AdvanceWindow(void)
should_advance = true;
- for (i=0; i<MAXPLAYERS; ++i)
+ for (i=0; i<NET_MAXPLAYERS; ++i)
{
if (sv_players[i] == NULL || !ClientConnected(sv_players[i]))
{
@@ -477,11 +503,7 @@ static void NET_SV_ParseSYN(net_packet_t *packet,
net_addr_t *addr)
{
unsigned int magic;
- unsigned int cl_gamemode, cl_gamemission;
- unsigned int cl_recording_lowres;
- unsigned int cl_drone;
- unsigned int is_freedoom;
- sha1_digest_t deh_sha1sum, wad_sha1sum;
+ net_connect_data_t data;
char *player_name;
char *client_version;
int i;
@@ -531,18 +553,19 @@ static void NET_SV_ParseSYN(net_packet_t *packet,
// read the game mode and mission
- if (!NET_ReadInt16(packet, &cl_gamemode)
- || !NET_ReadInt16(packet, &cl_gamemission)
- || !NET_ReadInt8(packet, &cl_recording_lowres)
- || !NET_ReadInt8(packet, &cl_drone)
- || !NET_ReadSHA1Sum(packet, wad_sha1sum)
- || !NET_ReadSHA1Sum(packet, deh_sha1sum)
- || !NET_ReadInt8(packet, &is_freedoom))
+ if (!NET_ReadConnectData(packet, &data))
+ {
+ return;
+ }
+
+ if (!D_ValidGameMode(data.gamemission, data.gamemode))
{
return;
}
- if (!NET_ValidGameMode(cl_gamemode, cl_gamemission))
+ // Check max_players value. This must be in a sensible range.
+
+ if (data.max_players > NET_MAXPLAYERS)
{
return;
}
@@ -609,7 +632,7 @@ static void NET_SV_ParseSYN(net_packet_t *packet,
NET_SV_AssignPlayers();
num_players = NET_SV_NumPlayers();
- if ((!cl_drone && num_players >= MAXPLAYERS)
+ if ((!data.drone && num_players >= NET_SV_MaxPlayers())
|| NET_SV_NumClients() >= MAXNETNODES)
{
NET_SV_SendReject(addr, "Server is full!");
@@ -622,33 +645,35 @@ static void NET_SV_ParseSYN(net_packet_t *packet,
// Adopt the game mode and mission of the first connecting client
- if (num_players == 0 && !cl_drone)
+ if (num_players == 0 && !data.drone)
{
- sv_gamemode = cl_gamemode;
- sv_gamemission = cl_gamemission;
+ sv_gamemode = data.gamemode;
+ sv_gamemission = data.gamemission;
}
// Save the SHA1 checksums
- memcpy(client->wad_sha1sum, wad_sha1sum, sizeof(sha1_digest_t));
- memcpy(client->deh_sha1sum, deh_sha1sum, sizeof(sha1_digest_t));
- client->is_freedoom = is_freedoom;
+ memcpy(client->wad_sha1sum, data.wad_sha1sum, sizeof(sha1_digest_t));
+ memcpy(client->deh_sha1sum, data.deh_sha1sum, sizeof(sha1_digest_t));
+ client->is_freedoom = data.is_freedoom;
+ client->max_players = data.max_players;
// Check the connecting client is playing the same game as all
// the other clients
- if (cl_gamemode != sv_gamemode || cl_gamemission != sv_gamemission)
+ if (data.gamemode != sv_gamemode || data.gamemission != sv_gamemission)
{
NET_SV_SendReject(addr, "You are playing the wrong game!");
return;
}
-
+
// Activate, initialize connection
NET_SV_InitNewClient(client, addr, player_name);
- client->recording_lowres = cl_recording_lowres;
- client->drone = cl_drone;
+ client->recording_lowres = data.lowres_turn;
+ client->drone = data.drone;
+ client->player_class = data.player_class;
}
if (client->connection.state == NET_CONN_STATE_WAITING_ACK)
@@ -703,7 +728,7 @@ static void NET_SV_ParseGameStart(net_packet_t *packet, net_client_t *client)
settings.lowres_turn = false;
- for (i=0; i<MAXPLAYERS; ++i)
+ for (i=0; i<NET_MAXPLAYERS; ++i)
{
if (sv_players[i] != NULL && sv_players[i]->recording_lowres)
{
@@ -711,6 +736,22 @@ static void NET_SV_ParseGameStart(net_packet_t *packet, net_client_t *client)
}
}
+ settings.num_players = NET_SV_NumPlayers();
+
+ // Copy player classes:
+
+ for (i = 0; i < NET_MAXPLAYERS; ++i)
+ {
+ if (sv_players[i] != NULL)
+ {
+ settings.player_classes[i] = sv_players[i]->player_class;
+ }
+ else
+ {
+ settings.player_classes[i] = 0;
+ }
+ }
+
nowtime = I_GetTimeMS();
// Send start packets to each connected node
@@ -725,8 +766,8 @@ static void NET_SV_ParseGameStart(net_packet_t *packet, net_client_t *client)
startpacket = NET_Conn_NewReliable(&clients[i].connection,
NET_PACKET_TYPE_GAMESTART);
- NET_WriteInt8(startpacket, NET_SV_NumPlayers());
- NET_WriteInt8(startpacket, clients[i].player_number);
+ settings.consoleplayer = clients[i].player_number;
+
NET_WriteSettings(startpacket, &settings);
}
@@ -1113,7 +1154,7 @@ void NET_SV_SendQueryResponse(net_addr_t *addr)
// Number of players/maximum players
querydata.num_players = NET_SV_NumPlayers();
- querydata.max_players = MAXPLAYERS;
+ querydata.max_players = NET_SV_MaxPlayers();
// Game mode/mission
@@ -1227,71 +1268,58 @@ static void NET_SV_Packet(net_packet_t *packet, net_addr_t *addr)
static void NET_SV_SendWaitingData(net_client_t *client)
{
+ net_waitdata_t wait_data;
net_packet_t *packet;
net_client_t *controller;
- int num_players;
int i;
NET_SV_AssignPlayers();
controller = NET_SV_Controller();
- num_players = NET_SV_NumPlayers();
+ wait_data.num_players = NET_SV_NumPlayers();
+ wait_data.num_drones = NET_SV_NumDrones();
+ wait_data.max_players = NET_SV_MaxPlayers();
+ wait_data.is_controller = (client == controller);
+ wait_data.consoleplayer = client->player_number;
- // time to send the client another status packet
-
- packet = NET_NewPacket(10);
- NET_WriteInt16(packet, NET_PACKET_TYPE_WAITING_DATA);
-
- // include the number of players waiting
-
- NET_WriteInt8(packet, num_players);
-
- // send the number of drone clients
-
- NET_WriteInt8(packet, NET_SV_NumDrones());
-
- // indicate whether the client is the controller
-
- NET_WriteInt8(packet, client == controller);
-
- // send the player number of this client
-
- NET_WriteInt8(packet, client->player_number);
-
- // send the addresses of all players
+ // Send the WAD and dehacked checksums of the controlling client.
+ // If no controller found (?), send the details that the client
+ // is expecting anyway.
- for (i=0; i<num_players; ++i)
+ if (controller != NULL)
{
- char *addr;
-
- // name
+ controller = client;
+ }
- NET_WriteString(packet, sv_players[i]->name);
+ memcpy(&wait_data.wad_sha1sum, &controller->wad_sha1sum,
+ sizeof(sha1_digest_t));
+ memcpy(&wait_data.deh_sha1sum, &controller->deh_sha1sum,
+ sizeof(sha1_digest_t));
+ wait_data.is_freedoom = controller->is_freedoom;
- // address
+ // set name and address of each player:
- addr = NET_AddrToString(sv_players[i]->addr);
+ for (i = 0; i < wait_data.num_players; ++i)
+ {
+ strncpy(wait_data.player_names[i],
+ sv_players[i]->name,
+ MAXPLAYERNAME);
+ wait_data.player_names[i][MAXPLAYERNAME-1] = '\0';
- NET_WriteString(packet, addr);
+ strncpy(wait_data.player_addrs[i],
+ NET_AddrToString(sv_players[i]->addr),
+ MAXPLAYERNAME);
+ wait_data.player_addrs[i][MAXPLAYERNAME-1] = '\0';
}
- // Send the WAD and dehacked checksums of the controlling client.
+ // Construct packet:
- if (controller != NULL)
- {
- NET_WriteSHA1Sum(packet, controller->wad_sha1sum);
- NET_WriteSHA1Sum(packet, controller->deh_sha1sum);
- NET_WriteInt8(packet, controller->is_freedoom);
- }
- else
- {
- NET_WriteSHA1Sum(packet, client->wad_sha1sum);
- NET_WriteSHA1Sum(packet, client->deh_sha1sum);
- NET_WriteInt8(packet, client->is_freedoom);
- }
+ packet = NET_NewPacket(10);
+ NET_WriteInt16(packet, NET_PACKET_TYPE_WAITING_DATA);
+ NET_WriteWaitData(packet, &wait_data);
- // send packet to client and free
+ // Send packet to client and free
NET_Conn_SendPacket(&client->connection, packet);
NET_FreePacket(packet);
@@ -1301,6 +1329,7 @@ static void NET_SV_PumpSendQueue(net_client_t *client)
{
net_full_ticcmd_t cmd;
int recv_index;
+ int num_players;
int i;
int starttic, endtic;
@@ -1324,7 +1353,9 @@ static void NET_SV_PumpSendQueue(net_client_t *client)
// Check if we can generate a new entry for the send queue
// using the data in recvwindow.
- for (i=0; i<MAXPLAYERS; ++i)
+ num_players = 0;
+
+ for (i=0; i<NET_MAXPLAYERS; ++i)
{
if (sv_players[i] == client)
{
@@ -1345,6 +1376,19 @@ static void NET_SV_PumpSendQueue(net_client_t *client)
return;
}
+
+ ++num_players;
+ }
+
+ // If this is a game with only a single player in it, we might
+ // be sending a ticcmd set containing 0 ticcmds. This is fine;
+ // however, there's nothing to stop the game running on ahead
+ // and never stopping. Don't let the server get too far ahead
+ // of the client.
+
+ if (num_players == 0 && client->sendseq > recvwindow_start + 10)
+ {
+ return;
}
//printf("SV: have complete ticcmd for %i\n", client->sendseq);
@@ -1357,7 +1401,7 @@ static void NET_SV_PumpSendQueue(net_client_t *client)
cmd.latency = 0;
- for (i=0; i<MAXPLAYERS; ++i)
+ for (i=0; i<NET_MAXPLAYERS; ++i)
{
net_client_recv_t *recvobj;
@@ -1670,7 +1714,7 @@ void NET_SV_Run(void)
{
NET_SV_AdvanceWindow();
- for (i=0; i<MAXPLAYERS; ++i)
+ for (i=0; i<NET_MAXPLAYERS; ++i)
{
if (sv_players[i] != NULL && ClientConnected(sv_players[i]))
{
@@ -1740,4 +1784,3 @@ void NET_SV_Shutdown(void)
I_Sleep(1);
}
}
-
diff --git a/src/net_structrw.c b/src/net_structrw.c
index 818766e4..8f6f8d57 100644
--- a/src/net_structrw.c
+++ b/src/net_structrw.c
@@ -21,16 +21,46 @@
// Reading and writing various structures into packets
//
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
-#include "doomdef.h"
+#include "doomtype.h"
#include "net_packet.h"
#include "net_structrw.h"
+void NET_WriteConnectData(net_packet_t *packet, net_connect_data_t *data)
+{
+ NET_WriteInt8(packet, data->gamemode);
+ NET_WriteInt8(packet, data->gamemission);
+ NET_WriteInt8(packet, data->lowres_turn);
+ NET_WriteInt8(packet, data->drone);
+ NET_WriteInt8(packet, data->max_players);
+ NET_WriteInt8(packet, data->is_freedoom);
+ NET_WriteSHA1Sum(packet, data->wad_sha1sum);
+ NET_WriteSHA1Sum(packet, data->deh_sha1sum);
+ NET_WriteInt8(packet, data->player_class);
+}
+
+boolean NET_ReadConnectData(net_packet_t *packet, net_connect_data_t *data)
+{
+ return NET_ReadInt8(packet, (unsigned int *) &data->gamemode)
+ && NET_ReadInt8(packet, (unsigned int *) &data->gamemission)
+ && NET_ReadInt8(packet, (unsigned int *) &data->lowres_turn)
+ && NET_ReadInt8(packet, (unsigned int *) &data->drone)
+ && NET_ReadInt8(packet, (unsigned int *) &data->max_players)
+ && NET_ReadInt8(packet, (unsigned int *) &data->is_freedoom)
+ && NET_ReadSHA1Sum(packet, data->wad_sha1sum)
+ && NET_ReadSHA1Sum(packet, data->deh_sha1sum)
+ && NET_ReadInt8(packet, (unsigned int *) &data->player_class);
+}
+
void NET_WriteSettings(net_packet_t *packet, net_gamesettings_t *settings)
{
+ int i;
+
NET_WriteInt8(packet, settings->ticdup);
NET_WriteInt8(packet, settings->extratics);
NET_WriteInt8(packet, settings->deathmatch);
@@ -45,24 +75,52 @@ void NET_WriteSettings(net_packet_t *packet, net_gamesettings_t *settings)
NET_WriteInt8(packet, settings->new_sync);
NET_WriteInt32(packet, settings->timelimit);
NET_WriteInt8(packet, settings->loadgame);
+ NET_WriteInt8(packet, settings->num_players);
+ NET_WriteInt8(packet, settings->consoleplayer);
+
+ for (i = 0; i < settings->num_players; ++i)
+ {
+ NET_WriteInt8(packet, settings->player_classes[i]);
+ }
}
boolean NET_ReadSettings(net_packet_t *packet, net_gamesettings_t *settings)
{
- return NET_ReadInt8(packet, (unsigned int *) &settings->ticdup)
- && NET_ReadInt8(packet, (unsigned int *) &settings->extratics)
- && NET_ReadInt8(packet, (unsigned int *) &settings->deathmatch)
- && NET_ReadInt8(packet, (unsigned int *) &settings->nomonsters)
- && NET_ReadInt8(packet, (unsigned int *) &settings->fast_monsters)
- && NET_ReadInt8(packet, (unsigned int *) &settings->respawn_monsters)
- && NET_ReadInt8(packet, (unsigned int *) &settings->episode)
- && NET_ReadInt8(packet, (unsigned int *) &settings->map)
- && NET_ReadSInt8(packet, &settings->skill)
- && NET_ReadInt8(packet, (unsigned int *) &settings->gameversion)
- && NET_ReadInt8(packet, (unsigned int *) &settings->lowres_turn)
- && NET_ReadInt8(packet, (unsigned int *) &settings->new_sync)
- && NET_ReadInt32(packet, (unsigned int *) &settings->timelimit)
- && NET_ReadSInt8(packet, (signed int *) &settings->loadgame);
+ boolean success;
+ int i;
+
+ success = NET_ReadInt8(packet, (unsigned int *) &settings->ticdup)
+ && NET_ReadInt8(packet, (unsigned int *) &settings->extratics)
+ && NET_ReadInt8(packet, (unsigned int *) &settings->deathmatch)
+ && NET_ReadInt8(packet, (unsigned int *) &settings->nomonsters)
+ && NET_ReadInt8(packet, (unsigned int *) &settings->fast_monsters)
+ && NET_ReadInt8(packet, (unsigned int *) &settings->respawn_monsters)
+ && NET_ReadInt8(packet, (unsigned int *) &settings->episode)
+ && NET_ReadInt8(packet, (unsigned int *) &settings->map)
+ && NET_ReadSInt8(packet, &settings->skill)
+ && NET_ReadInt8(packet, (unsigned int *) &settings->gameversion)
+ && NET_ReadInt8(packet, (unsigned int *) &settings->lowres_turn)
+ && NET_ReadInt8(packet, (unsigned int *) &settings->new_sync)
+ && NET_ReadInt32(packet, (unsigned int *) &settings->timelimit)
+ && NET_ReadSInt8(packet, (signed int *) &settings->loadgame)
+ && NET_ReadInt8(packet, (unsigned int *) &settings->num_players)
+ && NET_ReadSInt8(packet, (signed int *) &settings->consoleplayer);
+
+ if (!success)
+ {
+ return false;
+ }
+
+ for (i = 0; i < settings->num_players; ++i)
+ {
+ if (!NET_ReadInt8(packet,
+ (unsigned int *) &settings->player_classes[i]))
+ {
+ return false;
+ }
+ }
+
+ return true;
}
boolean NET_ReadQueryData(net_packet_t *packet, net_querydata_t *query)
@@ -131,6 +189,16 @@ void NET_WriteTiccmdDiff(net_packet_t *packet, net_ticdiff_t *diff,
NET_WriteInt8(packet, diff->cmd.consistancy);
if (diff->diff & NET_TICDIFF_CHATCHAR)
NET_WriteInt8(packet, diff->cmd.chatchar);
+ if (diff->diff & NET_TICDIFF_RAVEN)
+ {
+ NET_WriteInt8(packet, diff->cmd.lookfly);
+ NET_WriteInt8(packet, diff->cmd.arti);
+ }
+ if (diff->diff & NET_TICDIFF_STRIFE)
+ {
+ NET_WriteInt8(packet, diff->cmd.buttons2);
+ NET_WriteInt8(packet, diff->cmd.inventory);
+ }
}
boolean NET_ReadTiccmdDiff(net_packet_t *packet, net_ticdiff_t *diff,
@@ -197,6 +265,28 @@ boolean NET_ReadTiccmdDiff(net_packet_t *packet, net_ticdiff_t *diff,
diff->cmd.chatchar = val;
}
+ if (diff->diff & NET_TICDIFF_RAVEN)
+ {
+ if (!NET_ReadInt8(packet, &val))
+ return false;
+ diff->cmd.lookfly = val;
+
+ if (!NET_ReadInt8(packet, &val))
+ return false;
+ diff->cmd.arti = val;
+ }
+
+ if (diff->diff & NET_TICDIFF_STRIFE)
+ {
+ if (!NET_ReadInt8(packet, &val))
+ return false;
+ diff->cmd.buttons2 = val;
+
+ if (!NET_ReadInt8(packet, &val))
+ return false;
+ diff->cmd.inventory = val;
+ }
+
return true;
}
@@ -217,6 +307,16 @@ void NET_TiccmdDiff(ticcmd_t *tic1, ticcmd_t *tic2, net_ticdiff_t *diff)
diff->diff |= NET_TICDIFF_CONSISTANCY;
if (tic2->chatchar != 0)
diff->diff |= NET_TICDIFF_CHATCHAR;
+
+ // Heretic/Hexen-specific
+
+ if (tic1->lookfly != tic2->lookfly || tic2->arti != 0)
+ diff->diff |= NET_TICDIFF_RAVEN;
+
+ // Strife-specific
+
+ if (tic1->buttons2 != tic2->buttons2 || tic2->inventory != 0)
+ diff->diff |= NET_TICDIFF_STRIFE;
}
void NET_TiccmdPatch(ticcmd_t *src, net_ticdiff_t *diff, ticcmd_t *dest)
@@ -240,6 +340,30 @@ void NET_TiccmdPatch(ticcmd_t *src, net_ticdiff_t *diff, ticcmd_t *dest)
dest->chatchar = diff->cmd.chatchar;
else
dest->chatchar = 0;
+
+ // Heretic/Hexen specific:
+
+ if (diff->diff & NET_TICDIFF_RAVEN)
+ {
+ dest->lookfly = diff->cmd.lookfly;
+ dest->arti = diff->cmd.arti;
+ }
+ else
+ {
+ dest->arti = 0;
+ }
+
+ // Strife-specific:
+
+ if (diff->diff & NET_TICDIFF_STRIFE)
+ {
+ dest->buttons2 = diff->cmd.buttons2;
+ dest->inventory = diff->cmd.inventory;
+ }
+ else
+ {
+ dest->inventory = 0;
+ }
}
//
@@ -265,14 +389,14 @@ boolean NET_ReadFullTiccmd(net_packet_t *packet, net_full_ticcmd_t *cmd, boolean
return false;
}
- for (i=0; i<MAXPLAYERS; ++i)
+ for (i=0; i<NET_MAXPLAYERS; ++i)
{
cmd->playeringame[i] = (bitfield & (1 << i)) != 0;
}
// Read cmds
- for (i=0; i<MAXPLAYERS; ++i)
+ for (i=0; i<NET_MAXPLAYERS; ++i)
{
if (cmd->playeringame[i])
{
@@ -300,7 +424,7 @@ void NET_WriteFullTiccmd(net_packet_t *packet, net_full_ticcmd_t *cmd, boolean l
bitfield = 0;
- for (i=0; i<MAXPLAYERS; ++i)
+ for (i=0; i<NET_MAXPLAYERS; ++i)
{
if (cmd->playeringame[i])
{
@@ -312,7 +436,7 @@ void NET_WriteFullTiccmd(net_packet_t *packet, net_full_ticcmd_t *cmd, boolean l
// Write player ticcmds
- for (i=0; i<MAXPLAYERS; ++i)
+ for (i=0; i<NET_MAXPLAYERS; ++i)
{
if (cmd->playeringame[i])
{
@@ -321,6 +445,67 @@ void NET_WriteFullTiccmd(net_packet_t *packet, net_full_ticcmd_t *cmd, boolean l
}
}
+void NET_WriteWaitData(net_packet_t *packet, net_waitdata_t *data)
+{
+ int i;
+
+ NET_WriteInt8(packet, data->num_players);
+ NET_WriteInt8(packet, data->num_drones);
+ NET_WriteInt8(packet, data->max_players);
+ NET_WriteInt8(packet, data->is_controller);
+ NET_WriteInt8(packet, data->consoleplayer);
+
+ for (i = 0; i < data->num_players && i < NET_MAXPLAYERS; ++i)
+ {
+ NET_WriteString(packet, data->player_names[i]);
+ NET_WriteString(packet, data->player_addrs[i]);
+ }
+
+ NET_WriteSHA1Sum(packet, data->wad_sha1sum);
+ NET_WriteSHA1Sum(packet, data->deh_sha1sum);
+ NET_WriteInt8(packet, data->is_freedoom);
+}
+
+boolean NET_ReadWaitData(net_packet_t *packet, net_waitdata_t *data)
+{
+ int i;
+ char *s;
+
+ if (!NET_ReadInt8(packet, (unsigned int *) &data->num_players)
+ || !NET_ReadInt8(packet, (unsigned int *) &data->num_drones)
+ || !NET_ReadInt8(packet, (unsigned int *) &data->max_players)
+ || !NET_ReadInt8(packet, (unsigned int *) &data->is_controller)
+ || !NET_ReadSInt8(packet, &data->consoleplayer))
+ {
+ return false;
+ }
+
+ for (i = 0; i < data->num_players && i < NET_MAXPLAYERS; ++i)
+ {
+ s = NET_ReadString(packet);
+
+ if (s == NULL || strlen(s) >= MAXPLAYERNAME)
+ {
+ return false;
+ }
+
+ strcpy(data->player_names[i], s);
+
+ s = NET_ReadString(packet);
+
+ if (s == NULL || strlen(s) >= MAXPLAYERNAME)
+ {
+ return false;
+ }
+
+ strcpy(data->player_addrs[i], s);
+ }
+
+ return NET_ReadSHA1Sum(packet, data->wad_sha1sum)
+ && NET_ReadSHA1Sum(packet, data->deh_sha1sum)
+ && NET_ReadInt8(packet, (unsigned int *) &data->is_freedoom);
+}
+
static boolean NET_ReadBlob(net_packet_t *packet, uint8_t *buf, size_t len)
{
unsigned int b;
@@ -369,3 +554,22 @@ void NET_WritePRNGSeed(net_packet_t *packet, prng_seed_t seed)
NET_WriteBlob(packet, seed, sizeof(prng_seed_t));
}
+// "Safe" version of puts, for displaying messages received from the
+// network.
+
+void NET_SafePuts(char *s)
+{
+ char *p;
+
+ // Do not do a straight "puts" of the string, as this could be
+ // dangerous (sending control codes to terminals can do all
+ // kinds of things)
+
+ for (p=s; *p; ++p)
+ {
+ if (isprint(*p))
+ putchar(*p);
+ }
+
+ putchar('\n');
+}
diff --git a/src/net_structrw.h b/src/net_structrw.h
index 23bd67a1..3d446841 100644
--- a/src/net_structrw.h
+++ b/src/net_structrw.h
@@ -27,6 +27,9 @@
#include "net_defs.h"
#include "net_packet.h"
+void NET_WriteConnectData(net_packet_t *packet, net_connect_data_t *data);
+boolean NET_ReadConnectData(net_packet_t *packet, net_connect_data_t *data);
+
extern void NET_WriteSettings(net_packet_t *packet, net_gamesettings_t *settings);
extern boolean NET_ReadSettings(net_packet_t *packet, net_gamesettings_t *settings);
@@ -44,8 +47,12 @@ void NET_WriteFullTiccmd(net_packet_t *packet, net_full_ticcmd_t *cmd, boolean l
boolean NET_ReadSHA1Sum(net_packet_t *packet, sha1_digest_t digest);
void NET_WriteSHA1Sum(net_packet_t *packet, sha1_digest_t digest);
+void NET_WriteWaitData(net_packet_t *packet, net_waitdata_t *data);
+boolean NET_ReadWaitData(net_packet_t *packet, net_waitdata_t *data);
+
+void NET_SafePuts(char *msg);
+
boolean NET_ReadPRNGSeed(net_packet_t *packet, prng_seed_t seed);
void NET_WritePRNGSeed(net_packet_t *packet, prng_seed_t seed);
#endif /* #ifndef NET_STRUCTRW_H */
-
diff --git a/src/resource.rc.in b/src/resource.rc.in
index 537b4410..f8b64331 100644
--- a/src/resource.rc.in
+++ b/src/resource.rc.in
@@ -9,7 +9,7 @@ FILETYPE 1
{
BLOCK "040904E4"
{
- VALUE "FileVersion", "@PACKAGE_VERSION@"
+ VALUE "FileVersion", "@PACKAGE_VERSION@.0"
VALUE "FileDescription", "@PACKAGE_STRING@"
VALUE "InternalName", "@PACKAGE_TARNAME@"
VALUE "CompanyName", "@PACKAGE_BUGREPORT@"
diff --git a/setup/setup-res.rc.in b/src/setup-res.rc.in
index 2bc3106c..6a351354 100644
--- a/setup/setup-res.rc.in
+++ b/src/setup-res.rc.in
@@ -1,6 +1,6 @@
1 ICON "../data/setup.ico"
-1 24 MOVEABLE PURE "setup-manifest.xml"
+CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "setup/setup-manifest.xml"
1 VERSIONINFO
PRODUCTVERSION @WINDOWS_RC_VERSION@
@@ -11,7 +11,7 @@ FILETYPE 1
{
BLOCK "040904E4"
{
- VALUE "FileVersion", "@PACKAGE_VERSION@"
+ VALUE "FileVersion", "@PACKAGE_VERSION@.0"
VALUE "FileDescription", "@PACKAGE_STRING@ Setup"
VALUE "InternalName", "@PACKAGE_TARNAME@"
VALUE "CompanyName", "@PACKAGE_BUGREPORT@"
diff --git a/setup/.gitignore b/src/setup/.gitignore
index ff78f4c5..f41d11c7 100644
--- a/setup/.gitignore
+++ b/src/setup/.gitignore
@@ -2,10 +2,6 @@ Makefile.in
Makefile
.deps
setup-manifest.xml
-setup.desktop
-*-setup
-*-setup.desktop
*.rc
-*.exe
tags
TAGS
diff --git a/setup/Makefile.am b/src/setup/Makefile.am
index 9263a3a8..f58c6294 100644
--- a/setup/Makefile.am
+++ b/src/setup/Makefile.am
@@ -1,18 +1,19 @@
gamesdir = $(prefix)/games
-AM_CFLAGS = -I../textscreen -I../src @SDLMIXER_CFLAGS@
+AM_CFLAGS = @SDL_CFLAGS@ \
+ @SDLMIXER_CFLAGS@ \
+ -I$(top_builddir)/textscreen -I..
-games_PROGRAMS = @PROGRAM_PREFIX@setup
+noinst_LIBRARIES = libsetup.a
SOURCE_FILES = \
compatibility.c compatibility.h \
- configfile.c configfile.h \
display.c display.h \
joystick.c joystick.h \
keyboard.c keyboard.h \
- m_argv.c m_argv.h \
mainmenu.c \
+ mode.c mode.h \
mouse.c mouse.h \
multiplayer.c multiplayer.h \
sound.c sound.h \
@@ -21,36 +22,21 @@ SOURCE_FILES = \
txt_keyinput.c txt_keyinput.h \
txt_mouseinput.c txt_mouseinput.h
+libsetup_a_SOURCES = $(SOURCE_FILES)
+
EXTRA_DIST= \
setup_icon.c
-if HAVE_WINDRES
-@PROGRAM_PREFIX@setup_SOURCES=$(SOURCE_FILES) setup-res.rc
-else
-@PROGRAM_PREFIX@setup_SOURCES=$(SOURCE_FILES)
-endif
-
-@PROGRAM_PREFIX@setup_LDADD = \
- ../wince/libc_wince.a \
- ../textscreen/libtextscreen.a \
- @SDLMIXER_LIBS@ \
- @LDFLAGS@
-
appdir = $(prefix)/share/applications
app_DATA = @PROGRAM_PREFIX@setup.desktop
@PROGRAM_PREFIX@setup.desktop : setup.desktop
cp setup.desktop $@
-.rc.o:
- $(WINDRES) $^ -o $@
-%.o : %.rc
- $(WINDRES) $^ -o $@
-
if HAVE_PYTHON
-setup_icon.c : ../data/setup8.ico
- ../data/convert-icon ../data/setup8.ico $@
+setup_icon.c : $(top_builddir)/data/setup8.ico
+ $(top_builddir)/data/convert-icon $^ $@
endif
diff --git a/setup/compatibility.c b/src/setup/compatibility.c
index bebf5a87..35b09580 100644
--- a/setup/compatibility.c
+++ b/src/setup/compatibility.c
@@ -23,7 +23,9 @@
#include <stdlib.h>
+#include "m_config.h"
#include "textscreen.h"
+#include "mode.h"
#include "compatibility.h"
@@ -44,3 +46,12 @@ void CompatibilitySettings(void)
NULL);
}
+void BindCompatibilityVariables(void)
+{
+ if (gamemission == doom || gamemission == strife)
+ {
+ M_BindVariable("vanilla_savegame_limit", &vanilla_savegame_limit);
+ M_BindVariable("vanilla_demo_limit", &vanilla_demo_limit);
+ }
+}
+
diff --git a/setup/compatibility.h b/src/setup/compatibility.h
index 1d46b174..41c6ecd1 100644
--- a/setup/compatibility.h
+++ b/src/setup/compatibility.h
@@ -22,10 +22,10 @@
#ifndef SETUP_COMPATIBILITY_H
#define SETUP_COMPATIBILITY_H
+void CompatibilitySettings(void);
+void BindCompatibilityVariables(void);
+
extern int vanilla_savegame_limit;
extern int vanilla_demo_limit;
-void CompatibilitySettings(void);
-
#endif /* #ifndef SETUP_COMPATIBILITY_H */
-
diff --git a/setup/display.c b/src/setup/display.c
index f15b2b06..d22cc67b 100644
--- a/setup/display.c
+++ b/src/setup/display.c
@@ -19,13 +19,21 @@
// 02111-1307, USA.
//
+#include <stdlib.h>
#include <string.h>
#ifdef _WIN32_WCE
#include "libc_wince.h"
#endif
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
#include "textscreen.h"
+#include "m_config.h"
+#include "mode.h"
#include "display.h"
@@ -93,14 +101,18 @@ static int num_screen_modes_fullscreen;
static int vidmode = 0;
-char *video_driver = "";
-int autoadjust_video_settings = 1;
-int aspect_ratio_correct = 1;
-int fullscreen = 1;
-int screen_width = 320;
-int screen_height = 200;
-int screen_bpp = 8;
-int startup_delay = 1000;
+static char *video_driver = "";
+static char *window_position = "";
+static int autoadjust_video_settings = 1;
+static int aspect_ratio_correct = 1;
+static int fullscreen = 1;
+static int screen_width = 320;
+static int screen_height = 200;
+static int screen_bpp = 8;
+static int startup_delay = 1000;
+static int usegamma = 0;
+
+int graphical_startup = 1;
int show_endoom = 1;
// These are the last screen width/height values that were chosen by the
@@ -594,9 +606,21 @@ static void AdvancedDisplayConfig(TXT_UNCAST_ARG(widget),
TXT_AddWidgets(window,
ar_checkbox = TXT_NewCheckBox("Fix aspect ratio",
&aspect_ratio_correct),
- TXT_NewCheckBox("Show ENDOOM screen on exit", &show_endoom),
NULL);
+ if (gamemission == heretic || gamemission == hexen || gamemission == strife)
+ {
+ TXT_AddWidget(window,
+ TXT_NewCheckBox("Graphical startup", &graphical_startup));
+ }
+
+ if (gamemission == doom || gamemission == heretic || gamemission == strife)
+ {
+ TXT_AddWidget(window,
+ TXT_NewCheckBox("Show ENDOOM screen on exit",
+ &show_endoom));
+ }
+
TXT_SignalConnect(ar_checkbox, "changed", GenerateModesTable, modes_table);
// On Windows, there is an extra control to change between
@@ -757,3 +781,49 @@ void ConfigDisplay(void)
AdvancedDisplayConfig, modes_table);
}
+void BindDisplayVariables(void)
+{
+ M_BindVariable("autoadjust_video_settings", &autoadjust_video_settings);
+ M_BindVariable("aspect_ratio_correct", &aspect_ratio_correct);
+ M_BindVariable("fullscreen", &fullscreen);
+ M_BindVariable("screen_width", &screen_width);
+ M_BindVariable("screen_height", &screen_height);
+ M_BindVariable("screen_bpp", &screen_bpp);
+ M_BindVariable("startup_delay", &startup_delay);
+ M_BindVariable("video_driver", &video_driver);
+ M_BindVariable("window_position", &window_position);
+ M_BindVariable("usegamma", &usegamma);
+
+
+ if (gamemission == doom || gamemission == heretic
+ || gamemission == strife)
+ {
+ M_BindVariable("show_endoom", &show_endoom);
+ }
+
+ if (gamemission == heretic || gamemission == hexen || gamemission == strife)
+ {
+ M_BindVariable("graphical_startup", &graphical_startup);
+ }
+
+ // Windows Vista or later? Set screen color depth to
+ // 32 bits per pixel, as 8-bit palettized screen modes
+ // don't work properly in recent versions.
+
+#if defined(_WIN32) && !defined(_WIN32_WCE)
+ {
+ OSVERSIONINFOEX version_info;
+
+ ZeroMemory(&version_info, sizeof(OSVERSIONINFOEX));
+ version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+
+ GetVersionEx((OSVERSIONINFO *) &version_info);
+
+ if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT
+ && version_info.dwMajorVersion >= 6)
+ {
+ screen_bpp = 32;
+ }
+ }
+#endif
+}
diff --git a/setup/display.h b/src/setup/display.h
index 2419e807..a5c0c8bf 100644
--- a/setup/display.h
+++ b/src/setup/display.h
@@ -22,17 +22,11 @@
#ifndef SETUP_DISPLAY_H
#define SETUP_DISPLAY_H
-extern int autoadjust_video_settings;
-extern int aspect_ratio_correct;
-extern int fullscreen;
-extern int screen_width, screen_height;
-extern int screen_bpp;
-extern int startup_delay;
-extern int show_endoom;
-extern char *video_driver;
-
void ConfigDisplay(void);
void SetDisplayDriver(void);
+void BindDisplayVariables(void);
-#endif /* #ifndef SETUP_DISPLAY_H */
+extern int show_endoom;
+extern int graphical_startup;
+#endif /* #ifndef SETUP_DISPLAY_H */
diff --git a/setup/execute.c b/src/setup/execute.c
index 69442b5d..96a14fae 100644
--- a/setup/execute.c
+++ b/src/setup/execute.c
@@ -48,23 +48,10 @@
#include "textscreen.h"
#include "config.h"
-#include "configfile.h"
#include "execute.h"
+#include "mode.h"
#include "m_argv.h"
-
-#ifdef _WIN32
-#define DOOM_BINARY PACKAGE_TARNAME ".exe"
-#else
-#define DOOM_BINARY PACKAGE_TARNAME
-#endif
-
-#ifdef _WIN32
-#define DIR_SEPARATOR '\\'
-#define PATH_SEPARATOR ';'
-#else
-#define DIR_SEPARATOR '/'
-#define PATH_SEPARATOR ':'
-#endif
+#include "m_config.h"
struct execute_context_s
{
@@ -365,7 +352,7 @@ int ExecuteDoom(execute_context_t *context)
// Run Doom
- result = ExecuteCommand(DOOM_BINARY, response_file_arg);
+ result = ExecuteCommand(GetExecutableName(), response_file_arg);
free(response_file_arg);
@@ -383,14 +370,10 @@ static void TestCallback(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(data))
char *main_cfg;
char *extra_cfg;
txt_window_t *testwindow;
- txt_label_t *label;
-
- testwindow = TXT_NewWindow("Starting Doom");
- label = TXT_NewLabel("Starting Doom to test the\n"
- "settings. Please wait.");
- TXT_SetWidgetAlign(label, TXT_HORIZ_CENTER);
- TXT_AddWidget(testwindow, label);
+ testwindow = TXT_MessageBox("Starting Doom",
+ "Starting Doom to test the\n"
+ "settings. Please wait.");
TXT_DrawDesktop();
// Save temporary configuration files with the current configuration
@@ -398,8 +381,7 @@ static void TestCallback(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(data))
main_cfg = TempFile("tmp.cfg");
extra_cfg = TempFile("extratmp.cfg");
- M_SaveMainDefaults(main_cfg);
- M_SaveExtraDefaults(extra_cfg);
+ M_SaveDefaultsAlternate(main_cfg, extra_cfg);
// Run with the -testcontrols parameter
@@ -429,26 +411,3 @@ txt_window_action_t *TestConfigAction(void)
return test_action;
}
-// Invokes Doom to find which IWADs are installed.
-// This is a cheap hack to avoid duplication of the complicated install
-// path searching code inside Doom.
-
-int FindInstalledIWADs(void)
-{
- execute_context_t *context;
- int result;
-
- context = NewExecuteContext();
- AddCmdLineParameter(context, "-findiwads");
- result = ExecuteDoom(context);
-
- if (result < 0)
- {
- return 0;
- }
- else
- {
- return result;
- }
-}
-
diff --git a/setup/execute.h b/src/setup/execute.h
index 25f1f10a..25f1f10a 100644
--- a/setup/execute.h
+++ b/src/setup/execute.h
diff --git a/setup/joystick.c b/src/setup/joystick.c
index 5d2dfd68..064ff99d 100644
--- a/setup/joystick.c
+++ b/src/setup/joystick.c
@@ -19,14 +19,18 @@
// 02111-1307, USA.
//
+#include <stdio.h>
#include <stdlib.h>
#include "doomtype.h"
+#include "m_config.h"
+#include "m_controls.h"
#include "textscreen.h"
-#include "txt_joybinput.h"
#include "execute.h"
#include "joystick.h"
+#include "mode.h"
+#include "txt_joybinput.h"
typedef enum
{
@@ -41,18 +45,7 @@ static int joystick_initted = 0;
// Joystick enable/disable
-int usejoystick = 0;
-
-// Button mappings
-
-int joybfire = 0;
-int joybstrafe = 1;
-int joybuse = 3;
-int joybspeed = 2;
-int joybstrafeleft = -1;
-int joybstraferight = -1;
-int joybprevweapon = -1;
-int joybnextweapon = -1;
+static int usejoystick = 0;
// Joystick to use, as an SDL joystick index:
@@ -61,20 +54,20 @@ int joystick_index = -1;
// Which joystick axis to use for horizontal movement, and whether to
// invert the direction:
-int joystick_x_axis = 0;
-int joystick_x_invert = 0;
+static int joystick_x_axis = 0;
+static int joystick_x_invert = 0;
// Which joystick axis to use for vertical movement, and whether to
// invert the direction:
-int joystick_y_axis = 1;
-int joystick_y_invert = 0;
+static int joystick_y_axis = 1;
+static int joystick_y_invert = 0;
static txt_button_t *joystick_button;
static int *all_joystick_buttons[] = {
&joybstraferight, &joybstrafeleft, &joybfire, &joybspeed,
- &joybuse, &joybstrafe, &joybprevweapon, &joybnextweapon
+ &joybuse, &joybstrafe, &joybprevweapon, &joybnextweapon, &joybjump
};
//
@@ -277,19 +270,9 @@ static int CalibrationEventCallback(SDL_Event *event, void *user_data)
static void NoJoystick(void)
{
- txt_window_t *window;
-
- window = TXT_NewWindow(NULL);
-
- TXT_AddWidget(window,
- TXT_NewLabel("No joysticks could be opened.\n\n"
- "Try configuring your joystick from within\n"
- "your OS first."));
-
- TXT_SetWindowAction(window, TXT_HORIZ_LEFT, NULL);
- TXT_SetWindowAction(window, TXT_HORIZ_CENTER,
- TXT_NewWindowEscapeAction(window));
- TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, NULL);
+ TXT_MessageBox(NULL, "No joysticks could be opened.\n\n"
+ "Try configuring your joystick from within\n"
+ "your OS first.");
joystick_index = -1;
SetJoystickButtonLabel();
@@ -417,7 +400,7 @@ void ConfigJoystick(void)
TXT_SetColumnWidths(button_table, 20, 15);
- AddJoystickControl(button_table, "Fire", &joybfire);
+ AddJoystickControl(button_table, "Fire/Attack", &joybfire);
AddJoystickControl(button_table, "Use", &joybuse);
// High values of joybspeed are used to activate the "always run mode"
@@ -436,6 +419,11 @@ void ConfigJoystick(void)
AddJoystickControl(button_table, "Previous weapon", &joybprevweapon);
AddJoystickControl(button_table, "Next weapon", &joybnextweapon);
+ if (gamemission == hexen || gamemission == strife)
+ {
+ AddJoystickControl(button_table, "Jump", &joybjump);
+ }
+
TXT_SignalConnect(joystick_button, "pressed", CalibrateJoystick, NULL);
TXT_SignalConnect(window, "closed", JoystickWindowClosed, NULL);
@@ -444,3 +432,13 @@ void ConfigJoystick(void)
SetJoystickButtonLabel();
}
+void BindJoystickVariables(void)
+{
+ M_BindVariable("use_joystick", &usejoystick);
+ M_BindVariable("joystick_index", &joystick_index);
+ M_BindVariable("joystick_x_axis", &joystick_x_axis);
+ M_BindVariable("joystick_y_axis", &joystick_y_axis);
+ M_BindVariable("joystick_x_invert", &joystick_x_invert);
+ M_BindVariable("joystick_y_invert", &joystick_y_invert);
+}
+
diff --git a/setup/joystick.h b/src/setup/joystick.h
index 5d3973c5..b6dd09b9 100644
--- a/setup/joystick.h
+++ b/src/setup/joystick.h
@@ -22,23 +22,10 @@
#ifndef SETUP_JOYSTICK_H
#define SETUP_JOYSTICK_H
-extern int usejoystick;
-extern int joybfire;
-extern int joybstrafe;
-extern int joybuse;
-extern int joybspeed;
-extern int joybstrafeleft;
-extern int joybstraferight;
-extern int joybprevweapon;
-extern int joybnextweapon;
-
extern int joystick_index;
-extern int joystick_x_axis;
-extern int joystick_x_invert;
-extern int joystick_y_axis;
-extern int joystick_y_invert;
void ConfigJoystick(void);
+void BindJoystickVariables(void);
#endif /* #ifndef SETUP_JOYSTICK_H */
diff --git a/setup/keyboard.c b/src/setup/keyboard.c
index 81976f85..feceaa78 100644
--- a/setup/keyboard.c
+++ b/src/setup/keyboard.c
@@ -21,84 +21,16 @@
#include "textscreen.h"
#include "doomtype.h"
+#include "m_config.h"
+#include "m_controls.h"
#include "execute.h"
#include "txt_keyinput.h"
+#include "mode.h"
#include "joystick.h"
#include "keyboard.h"
-int key_left = KEY_LEFTARROW;
-int key_right = KEY_RIGHTARROW;
-int key_up = KEY_UPARROW;
-int key_down = KEY_DOWNARROW;
-int key_strafeleft = ',';
-int key_straferight = '.';
-int key_fire = KEY_RCTRL;
-int key_use = ' ';
-int key_strafe = KEY_RALT;
-int key_speed = KEY_RSHIFT;
-
-int key_pause = KEY_PAUSE;
-
-// Menu keys:
-
-int key_menu_activate = KEY_ESCAPE;
-int key_menu_up = KEY_UPARROW;
-int key_menu_down = KEY_DOWNARROW;
-int key_menu_left = KEY_LEFTARROW;
-int key_menu_right = KEY_RIGHTARROW;
-int key_menu_back = KEY_BACKSPACE;
-int key_menu_forward = KEY_ENTER;
-int key_menu_confirm = 'y';
-int key_menu_abort = 'n';
-
-int key_menu_help = KEY_F1;
-int key_menu_save = KEY_F2;
-int key_menu_load = KEY_F3;
-int key_menu_volume = KEY_F4;
-int key_menu_detail = KEY_F5;
-int key_menu_qsave = KEY_F6;
-int key_menu_endgame = KEY_F7;
-int key_menu_messages = KEY_F8;
-int key_menu_qload = KEY_F9;
-int key_menu_quit = KEY_F10;
-int key_menu_gamma = KEY_F11;
-int key_spy = KEY_F12;
-
-int key_menu_incscreen = KEY_EQUALS;
-int key_menu_decscreen = KEY_MINUS;
-
-int key_map_north = KEY_UPARROW;
-int key_map_south = KEY_DOWNARROW;
-int key_map_east = KEY_RIGHTARROW;
-int key_map_west = KEY_LEFTARROW;
-int key_map_zoomin = '=';
-int key_map_zoomout = '-';
-int key_map_toggle = KEY_TAB;
-int key_map_maxzoom = '0';
-int key_map_follow = 'f';
-int key_map_grid = 'g';
-int key_map_mark = 'm';
-int key_map_clearmark = 'c';
-
-int key_weapon1 = '1';
-int key_weapon2 = '2';
-int key_weapon3 = '3';
-int key_weapon4 = '4';
-int key_weapon5 = '5';
-int key_weapon6 = '6';
-int key_weapon7 = '7';
-int key_weapon8 = '8';
-int key_prevweapon = 0;
-int key_nextweapon = 0;
-
-int key_message_refresh = KEY_ENTER;
-int key_demo_quit = 'q';
-
-int key_multi_msg = 't';
-int key_multi_msgplayer[] = { 'g', 'i', 'b', 'r' };
-
int vanilla_keyboard_mapping = 1;
static int always_run = 0;
@@ -107,8 +39,13 @@ static int always_run = 0;
static int *controls[] = { &key_left, &key_right, &key_up, &key_down,
&key_strafeleft, &key_straferight, &key_fire,
- &key_use, &key_strafe, &key_speed,
- &key_pause,
+ &key_use, &key_strafe, &key_speed, &key_jump,
+ &key_flyup, &key_flydown, &key_flycenter,
+ &key_lookup, &key_lookdown, &key_lookcenter,
+ &key_invleft, &key_invright, &key_invquery,
+ &key_invuse, &key_invpop, &key_invkey,
+ &key_invhome, &key_invend, &key_invdrop,
+ &key_useartifact, &key_pause, &key_usehealth,
&key_weapon1, &key_weapon2, &key_weapon3,
&key_weapon4, &key_weapon5, &key_weapon6,
&key_weapon7, &key_weapon8,
@@ -219,38 +156,109 @@ static void AddKeyControl(txt_table_t *table, char *name, int *var)
TXT_SignalConnect(key_input, "set", KeySetCallback, var);
}
-static void OtherKeysDialog(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused))
+static void AddSectionLabel(txt_table_t *table, char *title, boolean add_space)
+{
+ char buf[64];
+
+ if (add_space)
+ {
+ TXT_AddWidgets(table, TXT_NewStrut(0, 1), TXT_NewStrut(0, 1),
+ NULL);
+ }
+
+ sprintf(buf, " - %s - ", title);
+
+ TXT_AddWidgets(table, TXT_NewLabel(buf), TXT_NewStrut(0, 0),
+ NULL);
+}
+static void ConfigExtraKeys(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused))
{
txt_window_t *window;
- txt_table_t *table;
txt_scrollpane_t *scrollpane;
+ txt_table_t *table;
+ boolean extra_keys = gamemission == heretic
+ || gamemission == hexen
+ || gamemission == strife;
- window = TXT_NewWindow("Other keys");
+ window = TXT_NewWindow("Extra keyboard controls");
table = TXT_NewTable(2);
- TXT_SetColumnWidths(table, 25, 10);
+ TXT_SetColumnWidths(table, 20, 9);
- TXT_AddWidgets(table, TXT_NewLabel(" - Weapons - "),
- TXT_NewStrut(0, 0),
- NULL);
+ if (extra_keys)
+ {
+ // When we have extra controls, a scrollable pane must be used.
+
+ scrollpane = TXT_NewScrollPane(0, 13, table);
+ TXT_AddWidget(window, scrollpane);
+
+ AddSectionLabel(table, "View", false);
+
+ AddKeyControl(table, "Look up", &key_lookup);
+ AddKeyControl(table, "Look down", &key_lookdown);
+ AddKeyControl(table, "Center view", &key_lookcenter);
- AddKeyControl(table, "Weapon 1", &key_weapon1);
- AddKeyControl(table, "Weapon 2", &key_weapon2);
- AddKeyControl(table, "Weapon 3", &key_weapon3);
- AddKeyControl(table, "Weapon 4", &key_weapon4);
- AddKeyControl(table, "Weapon 5", &key_weapon5);
- AddKeyControl(table, "Weapon 6", &key_weapon6);
- AddKeyControl(table, "Weapon 7", &key_weapon7);
- AddKeyControl(table, "Weapon 8", &key_weapon8);
+ AddSectionLabel(table, "Flying", true);
+
+ AddKeyControl(table, "Fly up", &key_flyup);
+ AddKeyControl(table, "Fly down", &key_flydown);
+ AddKeyControl(table, "Fly center", &key_flycenter);
+
+ AddSectionLabel(table, "Inventory", true);
+
+ AddKeyControl(table, "Inventory left", &key_invleft);
+ AddKeyControl(table, "Inventory right", &key_invright);
+
+ if (gamemission == strife)
+ {
+ AddKeyControl(table, "Home", &key_invhome);
+ AddKeyControl(table, "End", &key_invend);
+ AddKeyControl(table, "Query", &key_invquery);
+ AddKeyControl(table, "Drop", &key_invdrop);
+ AddKeyControl(table, "Show weapons", &key_invpop);
+ AddKeyControl(table, "Show mission", &key_mission);
+ AddKeyControl(table, "Show keys", &key_invkey);
+ AddKeyControl(table, "Use", &key_invuse);
+ AddKeyControl(table, "Use health", &key_usehealth);
+ }
+ else
+ {
+ AddKeyControl(table, "Use artifact", &key_useartifact);
+ }
+ }
+ else
+ {
+ TXT_AddWidget(window, table);
+ }
+
+ AddSectionLabel(table, "Weapons", extra_keys);
+
+ AddKeyControl(table, "Weapon 1", &key_weapon1);
+ AddKeyControl(table, "Weapon 2", &key_weapon2);
+ AddKeyControl(table, "Weapon 3", &key_weapon3);
+ AddKeyControl(table, "Weapon 4", &key_weapon4);
+ AddKeyControl(table, "Weapon 5", &key_weapon5);
+ AddKeyControl(table, "Weapon 6", &key_weapon6);
+ AddKeyControl(table, "Weapon 7", &key_weapon7);
+ AddKeyControl(table, "Weapon 8", &key_weapon8);
AddKeyControl(table, "Previous weapon", &key_prevweapon);
AddKeyControl(table, "Next weapon", &key_nextweapon);
+}
- TXT_AddWidgets(table, TXT_NewStrut(0, 1),
- TXT_NewStrut(0, 1),
- TXT_NewLabel(" - Menu navigation - "),
- TXT_NewStrut(0, 0),
- NULL);
+static void OtherKeysDialog(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused))
+{
+ txt_window_t *window;
+ txt_table_t *table;
+ txt_scrollpane_t *scrollpane;
+
+ window = TXT_NewWindow("Other keys");
+
+ table = TXT_NewTable(2);
+
+ TXT_SetColumnWidths(table, 25, 9);
+
+ AddSectionLabel(table, "Menu navigation", false);
AddKeyControl(table, "Activate menu", &key_menu_activate);
AddKeyControl(table, "Move cursor up", &key_menu_up);
@@ -262,11 +270,7 @@ static void OtherKeysDialog(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused))
AddKeyControl(table, "Confirm action", &key_menu_confirm);
AddKeyControl(table, "Cancel action", &key_menu_abort);
- TXT_AddWidgets(table, TXT_NewStrut(0, 1),
- TXT_NewStrut(0, 1),
- TXT_NewLabel(" - Shortcut keys - "),
- TXT_NewStrut(0, 0),
- NULL);
+ AddSectionLabel(table, "Shortcut keys", true);
AddKeyControl(table, "Pause game", &key_pause);
AddKeyControl(table, "Help screen", &key_menu_help);
@@ -288,24 +292,7 @@ static void OtherKeysDialog(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused))
AddKeyControl(table, "Display last message", &key_message_refresh);
AddKeyControl(table, "Finish recording demo", &key_demo_quit);
- TXT_AddWidgets(table, TXT_NewStrut(0, 1),
- TXT_NewStrut(0, 1),
- TXT_NewLabel(" - Multiplayer - "),
- TXT_NewStrut(0, 0),
- NULL);
-
- AddKeyControl(table, "Send message", &key_multi_msg);
- AddKeyControl(table, "- to green", &key_multi_msgplayer[0]);
- AddKeyControl(table, "- to indigo", &key_multi_msgplayer[1]);
- AddKeyControl(table, "- to brown", &key_multi_msgplayer[2]);
- AddKeyControl(table, "- to red", &key_multi_msgplayer[3]);
-
- TXT_AddWidgets(table, TXT_NewStrut(0, 1),
- TXT_NewStrut(0, 1),
- TXT_NewLabel(" - Map - "),
- TXT_NewStrut(0, 0),
- NULL);
-
+ AddSectionLabel(table, "Map", true);
AddKeyControl(table, "Toggle map", &key_map_toggle);
AddKeyControl(table, "Zoom in", &key_map_zoomin);
AddKeyControl(table, "Zoom out", &key_map_zoomout);
@@ -319,7 +306,23 @@ static void OtherKeysDialog(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused))
AddKeyControl(table, "Mark location", &key_map_mark);
AddKeyControl(table, "Clear all marks", &key_map_clearmark);
- scrollpane = TXT_NewScrollPane(0, 12, table);
+ AddSectionLabel(table, "Multiplayer", true);
+
+ AddKeyControl(table, "Send message", &key_multi_msg);
+ AddKeyControl(table, "- to player 1", &key_multi_msgplayer[0]);
+ AddKeyControl(table, "- to player 2", &key_multi_msgplayer[1]);
+ AddKeyControl(table, "- to player 3", &key_multi_msgplayer[2]);
+ AddKeyControl(table, "- to player 4", &key_multi_msgplayer[3]);
+
+ if (gamemission == hexen || gamemission == strife)
+ {
+ AddKeyControl(table, "- to player 5", &key_multi_msgplayer[4]);
+ AddKeyControl(table, "- to player 6", &key_multi_msgplayer[5]);
+ AddKeyControl(table, "- to player 7", &key_multi_msgplayer[6]);
+ AddKeyControl(table, "- to player 8", &key_multi_msgplayer[7]);
+ }
+
+ scrollpane = TXT_NewScrollPane(0, 13, table);
TXT_AddWidget(window, scrollpane);
}
@@ -329,6 +332,7 @@ void ConfigKeyboard(void)
txt_window_t *window;
txt_table_t *movement_table;
txt_table_t *action_table;
+ txt_table_t *dialogs_table;
txt_checkbox_t *run_control;
always_run = joybspeed >= 20;
@@ -341,17 +345,15 @@ void ConfigKeyboard(void)
TXT_NewSeparator("Action"),
action_table = TXT_NewTable(4),
- TXT_NewButton2("Other keys...", OtherKeysDialog, NULL),
- NULL);
+ dialogs_table = TXT_NewTable(2),
- TXT_AddWidgets(window,
TXT_NewSeparator("Misc."),
run_control = TXT_NewCheckBox("Always run", &always_run),
TXT_NewInvertedCheckBox("Use native keyboard mapping",
&vanilla_keyboard_mapping),
NULL);
- TXT_SetColumnWidths(movement_table, 15, 4, 15, 4);
+ TXT_SetColumnWidths(movement_table, 15, 8, 15, 8);
TXT_SignalConnect(run_control, "changed", UpdateJoybSpeed, NULL);
@@ -364,11 +366,30 @@ void ConfigKeyboard(void)
AddKeyControl(movement_table, "Turn Right", &key_right);
AddKeyControl(movement_table, " Strafe On", &key_strafe);
- TXT_SetColumnWidths(action_table, 15, 4, 15, 4);
+ if (gamemission == hexen || gamemission == strife)
+ {
+ AddKeyControl(movement_table, "Jump", &key_jump);
+ }
+
+ TXT_SetColumnWidths(action_table, 15, 8, 15, 8);
AddKeyControl(action_table, "Fire/Attack", &key_fire);
AddKeyControl(action_table, " Use", &key_use);
+ // Other key bindings are stored in separate sub-dialogs:
+
+ TXT_SetColumnWidths(dialogs_table, 24, 24);
+
+ TXT_AddWidgets(dialogs_table,
+ TXT_NewButton2("More controls...", ConfigExtraKeys, NULL),
+ TXT_NewButton2("Other keys...", OtherKeysDialog, NULL),
+ NULL);
+
TXT_SetWindowAction(window, TXT_HORIZ_CENTER, TestConfigAction());
+
}
+void BindKeyboardVariables(void)
+{
+ M_BindVariable("vanilla_keyboard_mapping", &vanilla_keyboard_mapping);
+}
diff --git a/src/setup/keyboard.h b/src/setup/keyboard.h
new file mode 100644
index 00000000..5ca4bac6
--- /dev/null
+++ b/src/setup/keyboard.h
@@ -0,0 +1,30 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2006 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+
+#ifndef SETUP_KEYBOARD_H
+#define SETUP_KEYBOARD_H
+
+void ConfigKeyboard(void);
+void BindKeyboardVariables(void);
+
+extern int vanilla_keyboard_mapping;
+
+#endif /* #ifndef SETUP_KEYBOARD_H */
diff --git a/setup/mainmenu.c b/src/setup/mainmenu.c
index a3dfafed..be4b0999 100644
--- a/setup/mainmenu.c
+++ b/src/setup/mainmenu.c
@@ -32,10 +32,12 @@
#include "execute.h"
-#include "configfile.h"
#include "m_argv.h"
+#include "m_config.h"
+#include "m_controls.h"
#include "setup_icon.c"
+#include "mode.h"
#include "compatibility.h"
#include "display.h"
@@ -62,13 +64,37 @@ static void SensibleDefaults(void)
key_down = 's';
key_strafeleft = 'a';
key_straferight = 'd';
- mousebprevweapon = 4;
+ key_jump = '/';
+ key_lookup = KEY_PGUP;
+ key_lookdown = KEY_PGDN;
+ key_lookcenter = KEY_HOME;
+ key_flyup = KEY_INS;
+ key_flydown = KEY_DEL;
+ key_flycenter = KEY_END;
+ key_prevweapon = ',';
+ key_nextweapon = '.';
+ key_invleft = '[';
+ key_invright = ']';
+ key_message_refresh = '\'';
+ key_mission = 'i'; // Strife keys
+ key_invpop = 'o';
+ key_invkey = 'p';
+ key_multi_msgplayer[0] = 'g';
+ key_multi_msgplayer[1] = 'h';
+ key_multi_msgplayer[2] = 'j';
+ key_multi_msgplayer[3] = 'k';
+ key_multi_msgplayer[4] = 'v';
+ key_multi_msgplayer[5] = 'b';
+ key_multi_msgplayer[6] = 'n';
+ key_multi_msgplayer[7] = 'm';
+ mousebprevweapon = 4; // Scroll wheel = weapon cycle
mousebnextweapon = 3;
snd_musicdevice = 3;
- joybspeed = 29;
+ joybspeed = 29; // Always run
vanilla_savegame_limit = 0;
vanilla_keyboard_mapping = 0;
vanilla_demo_limit = 0;
+ graphical_startup = 0;
show_endoom = 0;
dclick_use = 0;
novert = 1;
@@ -85,9 +111,7 @@ static int MainMenuKeyPress(txt_window_t *window, int key, void *user_data)
SensibleDefaults();
cheat_sequence_index = 0;
- window = TXT_NewWindow(NULL);
- TXT_AddWidget(window, TXT_NewLabel(" \x01 "));
- TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, NULL);
+ window = TXT_MessageBox(NULL, " \x01 ");
return 1;
}
@@ -158,6 +182,32 @@ static void LaunchDoom(void *unused1, void *unused2)
exit(0);
}
+static txt_button_t *GetLaunchButton(void)
+{
+ char *label;
+
+ switch (gamemission)
+ {
+ case doom:
+ label = "Save parameters and launch DOOM";
+ break;
+ case heretic:
+ label = "Save parameters and launch Heretic";
+ break;
+ case hexen:
+ label = "Save parameters and launch Hexen";
+ break;
+ case strife:
+ label = "Save parameters and launch STRIFE!";
+ break;
+ default:
+ label = "Save parameters and launch game";
+ break;
+ }
+
+ return TXT_NewButton2(label, LaunchDoom, NULL);
+}
+
void MainMenu(void)
{
txt_window_t *window;
@@ -169,17 +219,31 @@ void MainMenu(void)
TXT_AddWidgets(window,
TXT_NewButton2("Configure Display",
(TxtWidgetSignalFunc) ConfigDisplay, NULL),
- TXT_NewButton2("Configure Joystick",
- (TxtWidgetSignalFunc) ConfigJoystick, NULL),
+ TXT_NewButton2("Configure Sound",
+ (TxtWidgetSignalFunc) ConfigSound, NULL),
TXT_NewButton2("Configure Keyboard",
(TxtWidgetSignalFunc) ConfigKeyboard, NULL),
TXT_NewButton2("Configure Mouse",
(TxtWidgetSignalFunc) ConfigMouse, NULL),
- TXT_NewButton2("Configure Sound",
- (TxtWidgetSignalFunc) ConfigSound, NULL),
- TXT_NewButton2("Compatibility",
- (TxtWidgetSignalFunc) CompatibilitySettings, NULL),
- TXT_NewButton2("Save parameters and launch DOOM", LaunchDoom, NULL),
+ TXT_NewButton2("Configure Joystick",
+ (TxtWidgetSignalFunc) ConfigJoystick, NULL),
+ NULL);
+
+ // The compatibility window is only appropriate for Doom/Strife.
+
+ if (gamemission == doom || gamemission == strife)
+ {
+ txt_button_t *button;
+
+ button = TXT_NewButton2("Compatibility",
+ (TxtWidgetSignalFunc) CompatibilitySettings,
+ NULL);
+
+ TXT_AddWidget(window, button);
+ }
+
+ TXT_AddWidgets(window,
+ GetLaunchButton(),
TXT_NewStrut(0, 1),
TXT_NewButton2("Start a Network Game",
(TxtWidgetSignalFunc) StartMultiGame, NULL),
@@ -206,12 +270,12 @@ void MainMenu(void)
static void InitConfig(void)
{
- M_ApplyPlatformDefaults();
+ M_SetConfigDir(NULL);
+ InitBindings();
SetChatMacroDefaults();
SetPlayerNameDefault();
- M_SetConfigDir();
M_LoadDefaults();
}
@@ -288,28 +352,19 @@ void RestartTextscreen(void)
static void RunGUI(void)
{
InitTextscreen();
- MainMenu();
TXT_GUIMainLoop();
}
-int main(int argc, char *argv[])
+static void MissionSet(void)
{
- myargc = argc;
- myargv = argv;
-
-#ifdef _WIN32_WCE
-
- // Windows CE has no environment, but SDL provides an implementation.
- // Populate the environment with the values we normally find.
-
- PopulateEnvironment();
+ InitConfig();
+ MainMenu();
+}
-#endif
+void D_DoomMain(void)
+{
+ SetupMission(MissionSet);
- InitConfig();
RunGUI();
-
- return 0;
}
-
diff --git a/src/setup/mode.c b/src/setup/mode.c
new file mode 100644
index 00000000..88924ad8
--- /dev/null
+++ b/src/setup/mode.c
@@ -0,0 +1,381 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2006 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "doomtype.h"
+
+#include "config.h"
+#include "textscreen.h"
+
+#include "doomtype.h"
+#include "d_mode.h"
+#include "d_iwad.h"
+#include "i_system.h"
+#include "m_argv.h"
+#include "m_config.h"
+#include "m_controls.h"
+
+#include "compatibility.h"
+#include "display.h"
+#include "joystick.h"
+#include "keyboard.h"
+#include "mouse.h"
+#include "multiplayer.h"
+#include "sound.h"
+
+#include "mode.h"
+
+GameMission_t gamemission;
+static iwad_t **iwads;
+
+typedef struct
+{
+ char *label;
+ GameMission_t mission;
+ int mask;
+ char *name;
+ char *config_file;
+ char *extra_config_file;
+ char *executable;
+} mission_config_t;
+
+// Default mission to fall back on, if no IWADs are found at all:
+
+#define DEFAULT_MISSION (&mission_configs[0])
+
+static mission_config_t mission_configs[] =
+{
+ {
+ "Doom",
+ doom,
+ IWAD_MASK_DOOM,
+ "doom",
+ "default.cfg",
+ PROGRAM_PREFIX "doom.cfg",
+ PROGRAM_PREFIX "doom"
+ },
+ {
+ "Heretic",
+ heretic,
+ IWAD_MASK_HERETIC,
+ "heretic",
+ "heretic.cfg",
+ PROGRAM_PREFIX "heretic.cfg",
+ PROGRAM_PREFIX "heretic"
+ },
+ {
+ "Hexen",
+ hexen,
+ IWAD_MASK_HEXEN,
+ "hexen",
+ "hexen.cfg",
+ PROGRAM_PREFIX "hexen.cfg",
+ PROGRAM_PREFIX "hexen"
+ },
+ {
+ "Strife",
+ strife,
+ IWAD_MASK_STRIFE,
+ "strife",
+ "strife.cfg",
+ PROGRAM_PREFIX "strife.cfg",
+ PROGRAM_PREFIX "strife"
+ }
+};
+
+static GameSelectCallback game_selected_callback;
+
+// Miscellaneous variables that aren't used in setup.
+
+static int showMessages = 1;
+static int screenblocks = 9;
+static int detailLevel = 0;
+static char *savedir = NULL;
+static char *executable = NULL;
+static char *back_flat = "F_PAVE01";
+static int comport = 0;
+static char *nickname = NULL;
+
+static void BindMiscVariables(void)
+{
+ if (gamemission == doom)
+ {
+ M_BindVariable("detaillevel", &detailLevel);
+ M_BindVariable("show_messages", &showMessages);
+ }
+
+ if (gamemission == hexen)
+ {
+ M_BindVariable("savedir", &savedir);
+ M_BindVariable("messageson", &showMessages);
+
+ // Hexen has a variable to control the savegame directory
+ // that is used.
+
+ savedir = M_GetSaveGameDir("hexen.wad");
+
+ // On Windows, hexndata\ is the default.
+
+ if (!strcmp(savedir, ""))
+ {
+ free(savedir);
+ savedir = malloc(10);
+ sprintf(savedir, "hexndata%c", DIR_SEPARATOR);
+ }
+ }
+
+ if (gamemission == strife)
+ {
+ M_BindVariable("back_flat", &back_flat);
+ M_BindVariable("screensize" , &screenblocks);
+ M_BindVariable("comport", &comport);
+ M_BindVariable("nickname", &nickname);
+ }
+ else
+ {
+ M_BindVariable("screenblocks", &screenblocks);
+ }
+
+}
+
+//
+// Initialise all configuration file bindings.
+//
+
+void InitBindings(void)
+{
+ M_ApplyPlatformDefaults();
+
+ // Keyboard, mouse, joystick controls
+
+ M_BindBaseControls();
+ M_BindWeaponControls();
+ M_BindMapControls();
+ M_BindMenuControls();
+
+ if (gamemission == heretic || gamemission == hexen)
+ {
+ M_BindHereticControls();
+ }
+
+ if (gamemission == hexen)
+ {
+ M_BindHexenControls();
+ }
+
+ if (gamemission == strife)
+ {
+ M_BindStrifeControls();
+ }
+
+ // All other variables
+
+ BindCompatibilityVariables();
+ BindDisplayVariables();
+ BindJoystickVariables();
+ BindKeyboardVariables();
+ BindMouseVariables();
+ BindSoundVariables();
+ BindMiscVariables();
+ BindMultiplayerVariables();
+}
+
+// Set the name of the executable program to run the game:
+
+static void SetExecutable(mission_config_t *config)
+{
+ char *extension;
+
+ free(executable);
+
+#ifdef _WIN32
+ extension = ".exe";
+#else
+ extension = "";
+#endif
+
+ executable = malloc(strlen(config->executable) + 5);
+ sprintf(executable, "%s%s", config->executable, extension);
+}
+
+static void SetMission(mission_config_t *config)
+{
+ iwads = D_FindAllIWADs(config->mask);
+ gamemission = config->mission;
+ SetExecutable(config);
+ M_SetConfigFilenames(config->config_file, config->extra_config_file);
+}
+
+static mission_config_t *GetMissionForName(char *name)
+{
+ int i;
+
+ for (i=0; i<arrlen(mission_configs); ++i)
+ {
+ if (!strcmp(mission_configs[i].name, name))
+ {
+ return &mission_configs[i];
+ }
+ }
+
+ return NULL;
+}
+
+// Check the name of the executable. If it contains one of the game
+// names (eg. chocolate-hexen-setup.exe) then use that game.
+
+static boolean CheckExecutableName(GameSelectCallback callback)
+{
+ mission_config_t *config;
+ char *exe_name;
+ int i;
+
+ exe_name = M_GetExecutableName();
+
+ for (i=0; i<arrlen(mission_configs); ++i)
+ {
+ config = &mission_configs[i];
+
+ if (strstr(exe_name, config->name) != NULL)
+ {
+ SetMission(config);
+ callback();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void GameSelected(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(config))
+{
+ TXT_CAST_ARG(mission_config_t, config);
+
+ SetMission(config);
+ game_selected_callback();
+}
+
+static void OpenGameSelectDialog(GameSelectCallback callback)
+{
+ mission_config_t *mission = NULL;
+ txt_window_t *window;
+ iwad_t **iwads;
+ int num_games;
+ int i;
+
+ window = TXT_NewWindow("Select game");
+
+ TXT_AddWidget(window, TXT_NewLabel("Select a game to configure:\n"));
+ num_games = 0;
+
+ // Add a button for each game.
+
+ for (i=0; i<arrlen(mission_configs); ++i)
+ {
+ // Do we have any IWADs for this game installed?
+ // If so, add a button.
+
+ iwads = D_FindAllIWADs(mission_configs[i].mask);
+
+ if (iwads[0] != NULL)
+ {
+ mission = &mission_configs[i];
+ TXT_AddWidget(window, TXT_NewButton2(mission_configs[i].label,
+ GameSelected,
+ &mission_configs[i]));
+ ++num_games;
+ }
+
+ free(iwads);
+ }
+
+ TXT_AddWidget(window, TXT_NewStrut(0, 1));
+
+ // No IWADs found at all? Fall back to doom, then.
+
+ if (num_games == 0)
+ {
+ TXT_CloseWindow(window);
+ SetMission(DEFAULT_MISSION);
+ callback();
+ return;
+ }
+
+ // Only one game? Use that game, and don't bother with a dialog.
+
+ if (num_games == 1)
+ {
+ TXT_CloseWindow(window);
+ SetMission(mission);
+ callback();
+ return;
+ }
+
+ game_selected_callback = callback;
+}
+
+void SetupMission(GameSelectCallback callback)
+{
+ mission_config_t *config;
+ char *mission_name;
+ int p;
+
+ //!
+ // @arg <game>
+ //
+ // Specify the game to configure the settings for. Valid
+ // values are 'doom', 'heretic' and 'hexen'.
+ //
+
+ p = M_CheckParm("-game");
+
+ if (p > 0)
+ {
+ mission_name = myargv[p + 1];
+
+ config = GetMissionForName(mission_name);
+
+ if (config == NULL)
+ {
+ I_Error("Invalid parameter - '%s'", mission_name);
+ }
+
+ SetMission(config);
+ callback();
+ }
+ else if (!CheckExecutableName(callback))
+ {
+ OpenGameSelectDialog(callback);
+ }
+}
+
+char *GetExecutableName(void)
+{
+ return executable;
+}
+
+iwad_t **GetIwads(void)
+{
+ return iwads;
+}
+
diff --git a/src/setup/mode.h b/src/setup/mode.h
new file mode 100644
index 00000000..44046c38
--- /dev/null
+++ b/src/setup/mode.h
@@ -0,0 +1,37 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+
+#ifndef SETUP_MODE_H
+#define SETUP_MODE_H
+
+#include "d_mode.h"
+#include "d_iwad.h"
+
+typedef void (*GameSelectCallback)(void);
+extern GameMission_t gamemission;
+
+void SetupMission(GameSelectCallback callback);
+void InitBindings(void);
+char *GetExecutableName(void);
+iwad_t **GetIwads(void);
+
+#endif /* #ifndef SETUP_MODE_H */
+
diff --git a/setup/mouse.c b/src/setup/mouse.c
index 7931e79e..76ded3dd 100644
--- a/setup/mouse.c
+++ b/src/setup/mouse.c
@@ -23,31 +23,23 @@
#include "textscreen.h"
#include "doomtype.h"
+#include "m_config.h"
+#include "m_controls.h"
#include "execute.h"
#include "txt_mouseinput.h"
+#include "mode.h"
#include "mouse.h"
-int usemouse = 1;
+static int usemouse = 1;
+
+static int mouseSensitivity = 5;
+static float mouse_acceleration = 2.0;
+static int mouse_threshold = 10;
+static int grabmouse = 1;
int novert = 0;
-int mouseSensitivity = 5;
-float mouse_acceleration = 2.0;
-int mouse_threshold = 10;
-int grabmouse = 1;
-
-int mousebfire = 0;
-int mousebforward = 2;
-int mousebstrafe = 1;
-int mousebstrafeleft = -1;
-int mousebstraferight = -1;
-int mousebbackward = -1;
-int mousebuse = -1;
-int mousebprevweapon = -1;
-int mousebnextweapon = -1;
-
-int dclick_use = 1;
static int *all_mouse_buttons[] = {
&mousebfire,
@@ -57,6 +49,7 @@ static int *all_mouse_buttons[] = {
&mousebstraferight,
&mousebbackward,
&mousebuse,
+ &mousebjump,
&mousebprevweapon,
&mousebnextweapon
};
@@ -108,6 +101,12 @@ static void ConfigExtraButtons(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused))
AddMouseControl(buttons_table, "Use", &mousebuse);
AddMouseControl(buttons_table, "Strafe left", &mousebstrafeleft);
AddMouseControl(buttons_table, "Strafe right", &mousebstraferight);
+
+ if (gamemission == hexen)
+ {
+ AddMouseControl(buttons_table, "Jump", &mousebjump);
+ }
+
AddMouseControl(buttons_table, "Previous weapon", &mousebprevweapon);
AddMouseControl(buttons_table, "Next weapon", &mousebnextweapon);
}
@@ -117,7 +116,6 @@ void ConfigMouse(void)
txt_window_t *window;
txt_table_t *motion_table;
txt_table_t *buttons_table;
- txt_button_t *more_buttons;
window = TXT_NewWindow("Mouse configuration");
@@ -135,8 +133,9 @@ void ConfigMouse(void)
TXT_NewSeparator("Buttons"),
buttons_table = TXT_NewTable(2),
- more_buttons = TXT_NewButton("More buttons..."),
-
+ TXT_NewButton2("More controls...",
+ ConfigExtraButtons,
+ NULL),
NULL);
TXT_SetColumnWidths(motion_table, 27, 5);
@@ -152,12 +151,19 @@ void ConfigMouse(void)
TXT_SetColumnWidths(buttons_table, 27, 5);
+ AddMouseControl(buttons_table, "Fire/Attack", &mousebfire);
AddMouseControl(buttons_table, "Move forward", &mousebforward);
AddMouseControl(buttons_table, "Strafe on", &mousebstrafe);
- AddMouseControl(buttons_table, "Fire weapon", &mousebfire);
TXT_SetWindowAction(window, TXT_HORIZ_CENTER, TestConfigAction());
-
- TXT_SignalConnect(more_buttons, "pressed", ConfigExtraButtons, NULL);
}
+void BindMouseVariables(void)
+{
+ M_BindVariable("use_mouse", &usemouse);
+ M_BindVariable("novert", &novert);
+ M_BindVariable("mouse_sensitivity", &mouseSensitivity);
+ M_BindVariable("mouse_acceleration", &mouse_acceleration);
+ M_BindVariable("mouse_threshold", &mouse_threshold);
+ M_BindVariable("grabmouse", &grabmouse);
+}
diff --git a/setup/mouse.h b/src/setup/mouse.h
index 48270caa..70def18a 100644
--- a/setup/mouse.h
+++ b/src/setup/mouse.h
@@ -22,26 +22,9 @@
#ifndef SETUP_MOUSE_H
#define SETUP_MOUSE_H
-extern int usemouse;
-
-extern int novert;
-extern int mouseSensitivity;
-extern float mouse_acceleration;
-extern int mouse_threshold;
-extern int grabmouse;
-extern int mousebfire;
-extern int mousebforward;
-extern int mousebstrafe;
-extern int mousebstrafeleft;
-extern int mousebstraferight;
-extern int mousebbackward;
-extern int mousebuse;
-extern int dclick_use;
-extern int mousebprevweapon;
-extern int mousebnextweapon;
-
void ConfigMouse(void);
+void BindMouseVariables(void);
+extern int novert;
#endif /* #ifndef SETUP_MOUSE_H */
-
diff --git a/setup/multiplayer.c b/src/setup/multiplayer.c
index d2a38b1b..eac9d550 100644
--- a/setup/multiplayer.c
+++ b/src/setup/multiplayer.c
@@ -18,55 +18,47 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "d_englsh.h"
-#include "textscreen.h"
#include "doomtype.h"
+#include "doomfeatures.h"
-#include "configfile.h"
+#include "textscreen.h"
-#include "execute.h"
+#include "d_iwad.h"
+#include "m_config.h"
+#include "m_misc.h"
+#include "doom/d_englsh.h"
+#include "m_controls.h"
#include "multiplayer.h"
+#include "mode.h"
+#include "execute.h"
+
+#include "net_io.h"
+#include "net_query.h"
#define NUM_WADS 10
#define NUM_EXTRA_PARAMS 10
-typedef struct
-{
- char *filename;
- char *description;
- int mask;
-} iwad_t;
-
typedef enum
{
- WARP_DOOM1,
- WARP_DOOM2,
+ WARP_ExMy,
+ WARP_MAPxy,
} warptype_t;
-typedef enum
-{
- JOIN_AUTO_LAN,
- JOIN_ADDRESS,
-} jointype_t;
+// Fallback IWAD if none are found to be installed
-static iwad_t iwads[] =
-{
- { "doom.wad", "Doom", IWAD_DOOM },
- { "doom2.wad", "Doom 2", IWAD_DOOM2 },
- { "tnt.wad", "Final Doom: TNT", IWAD_TNT },
- { "plutonia.wad", "Final Doom: Plutonia", IWAD_PLUTONIA },
- { "doom1.wad", "Doom shareware", IWAD_DOOM1 },
- { "chex.wad", "Chex Quest", IWAD_CHEX },
-};
+static iwad_t fallback_iwad = { "doom2.wad", doom2, commercial, "Doom II" };
+static iwad_t *fallback_iwad_list[2] = { &fallback_iwad, NULL };
// Array of IWADs found to be installed
-static char *found_iwads[6];
+static iwad_t **found_iwads;
+static char *iwad_labels[8];
// Index of the currently selected IWAD
@@ -76,43 +68,66 @@ static int found_iwad_selected;
static char *iwadfile;
-static char *skills[] =
+static char *wad_extensions[] = { "wad", "lmp", "deh", NULL };
+
+static char *doom_skills[] =
{
- "I'm too young to die.",
- "Hey, not too rough.",
- "Hurt me plenty.",
- "Ultra-Violence.",
- "NIGHTMARE!",
+ "I'm too young to die.", "Hey, not too rough.", "Hurt me plenty.",
+ "Ultra-Violence.", "NIGHTMARE!",
};
-static char *chex_skills[] =
+static char *chex_skills[] =
{
- "Easy does it",
- "Not so sticky",
- "Gobs of goo",
- "Extreme ooze",
+ "Easy does it", "Not so sticky", "Gobs of goo", "Extreme ooze",
"SUPER SLIMEY!"
};
-static char *gamemodes[] =
+static char *heretic_skills[] =
{
- "Co-operative",
- "Deathmatch",
- "Deathmatch 2.0",
+ "Thou needeth a wet-nurse", "Yellowbellies-R-us", "Bringest them oneth",
+ "Thou art a smite-meister", "Black plague possesses thee"
};
-static char *wad_extensions[] = { "wad", "lmp", "deh", NULL };
+static char *hexen_fighter_skills[] =
+{
+ "Squire", "Knight", "Warrior", "Berserker", "Titan"
+};
+
+static char *hexen_cleric_skills[] =
+{
+ "Altar boy", "Acolyte", "Priest", "Cardinal", "Pope"
+};
+
+static char *hexen_mage_skills[] =
+{
+ "Apprentice", "Enchanter", "Sorceror", "Warlock", "Archimage"
+};
-char *net_player_name;
-char *chat_macros[10];
+static char *strife_skills[] =
+{
+ "Training", "Rookie", "Veteran", "Elite", "Bloodbath"
+};
-static int jointype = JOIN_ADDRESS;
+static char *character_classes[] = { "Fighter", "Cleric", "Mage" };
+
+static char *gamemodes[] = { "Co-operative", "Deathmatch", "Deathmatch 2.0" };
+
+static char *strife_gamemodes[] =
+{
+ "Normal deathmatch",
+ "Items respawn", // (altdeath)
+};
+
+static char *net_player_name;
+static char *chat_macros[10];
static char *wads[NUM_WADS];
static char *extra_params[NUM_EXTRA_PARAMS];
+static int character_class = 0;
static int skill = 2;
static int nomonsters = 0;
static int deathmatch = 0;
+static int strife_altdeath = 0;
static int fast = 0;
static int respawn = 0;
static int udpport = 2342;
@@ -121,7 +136,7 @@ static int privateserver = 0;
static txt_dropdown_list_t *skillbutton;
static txt_button_t *warpbutton;
-static warptype_t warptype = WARP_DOOM2;
+static warptype_t warptype = WARP_MAPxy;
static int warpepisode = 1;
static int warpmap = 1;
@@ -129,29 +144,23 @@ static int warpmap = 1;
static char *connect_address = NULL;
+static txt_window_t *query_window;
+static int query_servers_found;
+
// Find an IWAD from its description
-static iwad_t *GetIWADForDescription(char *description)
+static iwad_t *GetCurrentIWAD(void)
{
- unsigned int i;
-
- for (i=0; i<arrlen(iwads); ++i)
- {
- if (!strcmp(iwads[i].description, description))
- {
- return &iwads[i];
- }
- }
-
- return NULL;
+ return found_iwads[found_iwad_selected];
}
-static iwad_t *GetCurrentIWAD(void)
+// Is the currently selected IWAD the Chex Quest chex.wad?
+
+static boolean IsChexQuest(iwad_t *iwad)
{
- return GetIWADForDescription(found_iwads[found_iwad_selected]);
+ return !strcmp(iwad->name, "chex.wad");
}
-
static void AddWADs(execute_context_t *exec)
{
int have_wads = 0;
@@ -210,6 +219,11 @@ static void StartGame(int multiplayer)
AddIWADParameter(exec);
AddCmdLineParameter(exec, "-skill %i", skill + 1);
+ if (gamemission == hexen)
+ {
+ AddCmdLineParameter(exec, "-class %i", character_class);
+ }
+
if (nomonsters)
{
AddCmdLineParameter(exec, "-nomonsters");
@@ -225,12 +239,12 @@ static void StartGame(int multiplayer)
AddCmdLineParameter(exec, "-respawn");
}
- if (warptype == WARP_DOOM1)
+ if (warptype == WARP_ExMy)
{
// TODO: select IWAD based on warp type
AddCmdLineParameter(exec, "-warp %i %i", warpepisode, warpmap);
}
- else if (warptype == WARP_DOOM2)
+ else if (warptype == WARP_MAPxy)
{
AddCmdLineParameter(exec, "-warp %i", warpmap);
}
@@ -246,7 +260,7 @@ static void StartGame(int multiplayer)
{
AddCmdLineParameter(exec, "-deathmatch");
}
- else if (deathmatch == 2)
+ else if (deathmatch == 2 || strife_altdeath != 0)
{
AddCmdLineParameter(exec, "-altdeath");
}
@@ -288,11 +302,11 @@ static void UpdateWarpButton(void)
{
char buf[10];
- if (warptype == WARP_DOOM1)
+ if (warptype == WARP_ExMy)
{
sprintf(buf, "E%iM%i", warpepisode, warpmap);
}
- else if (warptype == WARP_DOOM2)
+ else if (warptype == WARP_MAPxy)
{
sprintf(buf, "MAP%02i", warpmap);
}
@@ -304,17 +318,43 @@ static void UpdateSkillButton(void)
{
iwad_t *iwad = GetCurrentIWAD();
- if (iwad->mask == IWAD_CHEX)
+ if (IsChexQuest(iwad))
{
skillbutton->values = chex_skills;
}
- else
+ else switch(gamemission)
{
- skillbutton->values = skills;
+ default:
+ case doom:
+ skillbutton->values = doom_skills;
+ break;
+
+ case heretic:
+ skillbutton->values = heretic_skills;
+ break;
+
+ case hexen:
+ if (character_class == 0)
+ {
+ skillbutton->values = hexen_fighter_skills;
+ }
+ else if (character_class == 2)
+ {
+ skillbutton->values = hexen_cleric_skills;
+ }
+ else
+ {
+ skillbutton->values = hexen_mage_skills;
+ }
+ break;
+
+ case strife:
+ skillbutton->values = strife_skills;
+ break;
}
}
-static void SetDoom1Warp(TXT_UNCAST_ARG(widget), void *val)
+static void SetExMyWarp(TXT_UNCAST_ARG(widget), void *val)
{
int l;
@@ -326,7 +366,7 @@ static void SetDoom1Warp(TXT_UNCAST_ARG(widget), void *val)
UpdateWarpButton();
}
-static void SetDoom2Warp(TXT_UNCAST_ARG(widget), void *val)
+static void SetMAPxyWarp(TXT_UNCAST_ARG(widget), void *val)
{
int l;
@@ -341,7 +381,7 @@ static void CloseLevelSelectDialog(TXT_UNCAST_ARG(button), TXT_UNCAST_ARG(window
{
TXT_CAST_ARG(txt_window_t, window);
- TXT_CloseWindow(window);
+ TXT_CloseWindow(window);
}
static void LevelSelectDialog(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(user_data))
@@ -351,68 +391,72 @@ static void LevelSelectDialog(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(user_data))
txt_button_t *button;
iwad_t *iwad;
char buf[10];
+ int episodes;
int x, y;
int l;
int i;
window = TXT_NewWindow("Select level");
+ iwad = GetCurrentIWAD();
- table = TXT_NewTable(4);
-
- TXT_AddWidget(window, table);
-
- if (warptype == WARP_DOOM1)
+ if (warptype == WARP_ExMy)
{
+ episodes = D_GetNumEpisodes(iwad->mission, iwad->mode);
+ table = TXT_NewTable(episodes);
+
// ExMy levels
-
- iwad = GetCurrentIWAD();
- for (i=0; i<4 * 9; ++i)
+ for (y=1; y<10; ++y)
{
- x = (i % 4) + 1;
- y = (i / 4) + 1;
-
- // chex.wad only has E1M1-E1M5.
-
- if (iwad->mask == IWAD_CHEX && (x > 1 || y > 5))
- {
- continue;
- }
-
- // doom1.wad only has E1
-
- if (iwad->mask == IWAD_DOOM1 && x > 1)
- {
- continue;
- }
-
- sprintf(buf, " E%iM%i ", x, y);
- button = TXT_NewButton(buf);
- TXT_SignalConnect(button, "pressed",
- SetDoom1Warp, (void *) (x * 10 + y));
- TXT_SignalConnect(button, "pressed",
- CloseLevelSelectDialog, window);
- TXT_AddWidget(table, button);
-
- if (warpepisode == x && warpmap == y)
+ for (x=1; x<=episodes; ++x)
{
- TXT_SelectWidget(table, button);
+ if (IsChexQuest(iwad) && (x > 1 || y > 5))
+ {
+ continue;
+ }
+
+ if (!D_ValidEpisodeMap(iwad->mission, iwad->mode, x, y))
+ {
+ TXT_AddWidget(table, NULL);
+ continue;
+ }
+
+ sprintf(buf, " E%iM%i ", x, y);
+ button = TXT_NewButton(buf);
+ TXT_SignalConnect(button, "pressed",
+ SetExMyWarp, (void *) (x * 10 + y));
+ TXT_SignalConnect(button, "pressed",
+ CloseLevelSelectDialog, window);
+ TXT_AddWidget(table, button);
+
+ if (warpepisode == x && warpmap == y)
+ {
+ TXT_SelectWidget(table, button);
+ }
}
}
}
else
{
- for (i=0; i<32; ++i)
+ table = TXT_NewTable(4);
+
+ for (i=0; i<40; ++i)
{
x = i % 4;
y = i / 4;
- l = x * 8 + y + 1;
-
+ l = x * 10 + y + 1;
+
+ if (!D_ValidEpisodeMap(iwad->mission, iwad->mode, 1, l))
+ {
+ TXT_AddWidget(table, NULL);
+ continue;
+ }
+
sprintf(buf, " MAP%02i ", l);
button = TXT_NewButton(buf);
TXT_SignalConnect(button, "pressed",
- SetDoom2Warp, (void *) l);
+ SetMAPxyWarp, (void *) l);
TXT_SignalConnect(button, "pressed",
CloseLevelSelectDialog, window);
TXT_AddWidget(table, button);
@@ -423,6 +467,8 @@ static void LevelSelectDialog(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(user_data))
}
}
}
+
+ TXT_AddWidget(window, table);
}
static void IWADSelected(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused))
@@ -435,7 +481,7 @@ static void IWADSelected(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused))
// Update iwadfile
- iwadfile = iwad->filename;
+ iwadfile = iwad->name;
}
// Called when the IWAD button is changed, to update warptype.
@@ -444,20 +490,20 @@ static void UpdateWarpType(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused))
{
warptype_t new_warptype;
iwad_t *iwad;
-
+
// Get the selected IWAD
- iwad = GetIWADForDescription(found_iwads[found_iwad_selected]);
+ iwad = GetCurrentIWAD();
// Find the new warp type
- if (iwad->mask & (IWAD_DOOM | IWAD_DOOM1 | IWAD_CHEX))
+ if (D_IsEpisodeMap(iwad->mission))
{
- new_warptype = WARP_DOOM1;
+ new_warptype = WARP_ExMy;
}
else
{
- new_warptype = WARP_DOOM2;
+ new_warptype = WARP_MAPxy;
}
// Reset to E1M1 / MAP01 when the warp type is changed.
@@ -478,25 +524,21 @@ static txt_widget_t *IWADSelector(void)
{
txt_dropdown_list_t *dropdown;
txt_widget_t *result;
- int installed_iwads;
int num_iwads;
unsigned int i;
// Find out what WADs are installed
- installed_iwads = FindInstalledIWADs();
+ found_iwads = GetIwads();
// Build a list of the descriptions for all installed IWADs
num_iwads = 0;
- for (i=0; i<arrlen(iwads); ++i)
+ for (i=0; found_iwads[i] != NULL; ++i)
{
- if (installed_iwads & iwads[i].mask)
- {
- found_iwads[num_iwads] = iwads[i].description;
- ++num_iwads;
- }
+ iwad_labels[i] = found_iwads[i]->description;
+ ++num_iwads;
}
// If no IWADs are found, provide Doom 2 as an option, but
@@ -504,7 +546,7 @@ static txt_widget_t *IWADSelector(void)
if (num_iwads == 0)
{
- found_iwads[0] = "Doom 2";
+ found_iwads = fallback_iwad_list;
num_iwads = 1;
}
@@ -514,14 +556,14 @@ static txt_widget_t *IWADSelector(void)
{
// We have only one IWAD. Show as a label.
- result = (txt_widget_t *) TXT_NewLabel(found_iwads[0]);
+ result = (txt_widget_t *) TXT_NewLabel(found_iwads[0]->description);
}
else
{
// Dropdown list allowing IWAD to be selected.
dropdown = TXT_NewDropdownList(&found_iwad_selected,
- found_iwads, num_iwads);
+ iwad_labels, num_iwads);
TXT_SignalConnect(dropdown, "changed", IWADSelected, NULL);
@@ -600,6 +642,29 @@ static txt_window_action_t *WadWindowAction(void)
return action;
}
+static txt_dropdown_list_t *GameTypeDropdown(void)
+{
+ switch (gamemission)
+ {
+ case doom:
+ default:
+ return TXT_NewDropdownList(&deathmatch, gamemodes, 3);
+
+ // Heretic and Hexen don't support Deathmatch II:
+
+ case heretic:
+ case hexen:
+ return TXT_NewDropdownList(&deathmatch, gamemodes, 2);
+
+ // Strife supports both deathmatch modes, but doesn't support
+ // multiplayer co-op. Use a different variable to indicate whether
+ // to use altdeath or not.
+
+ case strife:
+ return TXT_NewDropdownList(&strife_altdeath, strife_gamemodes, 2);
+ }
+}
+
// "Start game" menu. This is used for the start server window
// and the single player warp menu. The parameters specify
// the window title and whether to display multiplayer options.
@@ -625,14 +690,31 @@ static void StartGameMenu(char *window_title, int multiplayer)
TXT_SetWindowAction(window, TXT_HORIZ_CENTER, WadWindowAction());
TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, StartGameAction(multiplayer));
-
+
TXT_SetColumnWidths(gameopt_table, 12, 6);
TXT_AddWidgets(gameopt_table,
TXT_NewLabel("Game"),
iwad_selector = IWADSelector(),
+ NULL);
+
+ if (gamemission == hexen)
+ {
+ txt_dropdown_list_t *cc_dropdown;
+ TXT_AddWidgets(gameopt_table,
+ TXT_NewLabel("Character class "),
+ cc_dropdown = TXT_NewDropdownList(&character_class,
+ character_classes, 3),
+ NULL);
+
+ // Update skill level dropdown when the character class is changed:
+
+ TXT_SignalConnect(cc_dropdown, "changed", UpdateWarpType, NULL);
+ }
+
+ TXT_AddWidgets(gameopt_table,
TXT_NewLabel("Skill"),
- skillbutton = TXT_NewDropdownList(&skill, skills, 5),
+ skillbutton = TXT_NewDropdownList(&skill, doom_skills, 5),
TXT_NewLabel("Level warp"),
warpbutton = TXT_NewButton2("????", LevelSelectDialog, NULL),
NULL);
@@ -641,7 +723,7 @@ static void StartGameMenu(char *window_title, int multiplayer)
{
TXT_AddWidgets(gameopt_table,
TXT_NewLabel("Game type"),
- TXT_NewDropdownList(&deathmatch, gamemodes, 3),
+ GameTypeDropdown(),
TXT_NewLabel("Time limit"),
TXT_NewHorizBox(TXT_NewIntInputBox(&timer, 2),
TXT_NewLabel("minutes"),
@@ -686,13 +768,11 @@ static void DoJoinGame(void *unused1, void *unused2)
exec = NewExecuteContext();
- if (jointype == JOIN_ADDRESS)
- {
- AddCmdLineParameter(exec, "-connect %s", connect_address);
- }
- else if (jointype == JOIN_AUTO_LAN)
+ AddCmdLineParameter(exec, "-connect %s", connect_address);
+
+ if (gamemission == hexen)
{
- AddCmdLineParameter(exec, "-autojoin");
+ AddCmdLineParameter(exec, "-class %i", character_class);
}
// Extra parameters come first, so that they can be used to override
@@ -723,11 +803,136 @@ static txt_window_action_t *JoinGameAction(void)
return action;
}
-// When an address is entered, select "address" mode.
+static void SelectQueryAddress(TXT_UNCAST_ARG(button),
+ TXT_UNCAST_ARG(querydata))
+{
+ TXT_CAST_ARG(txt_button_t, button);
+ TXT_CAST_ARG(net_querydata_t, querydata);
+ int i;
+
+ if (querydata->server_state != 0)
+ {
+ TXT_MessageBox("Cannot connect to server",
+ "Gameplay is already in progress\n"
+ "on this server.");
+ return;
+ }
+
+ // Set address to connect to:
+
+ free(connect_address);
+ connect_address = strdup(button->label);
+
+ // Auto-choose IWAD if there is already a player connected.
+
+ if (querydata->num_players > 0)
+ {
+ for (i = 0; found_iwads[i] != NULL; ++i)
+ {
+ if (found_iwads[i]->mode == querydata->gamemode
+ && found_iwads[i]->mission == querydata->gamemission)
+ {
+ found_iwad_selected = i;
+ break;
+ }
+ }
+
+ if (found_iwads[i] == NULL)
+ {
+ TXT_MessageBox(NULL,
+ "The game on this server seems to be:\n"
+ "\n"
+ " %s\n"
+ "\n"
+ "but the IWAD file %s is not found!\n"
+ "Without the required IWAD file, it may not be\n"
+ "possible to join this game.",
+ D_SuggestGameName(querydata->gamemission,
+ querydata->gamemode),
+ D_SuggestIWADName(querydata->gamemission,
+ querydata->gamemode));
+ }
+ }
+
+ // Finished with search.
+
+ TXT_CloseWindow(query_window);
+}
+
+static void QueryResponseCallback(net_addr_t *addr,
+ net_querydata_t *querydata,
+ unsigned int ping_time,
+ TXT_UNCAST_ARG(results_table))
+{
+ TXT_CAST_ARG(txt_table_t, results_table);
+ char ping_time_str[16];
+ char description[47];
+
+ sprintf(ping_time_str, "%ims", ping_time);
+ strncpy(description, querydata->description, 46);
+ description[46] = '\0';
+
+ TXT_AddWidgets(results_table,
+ TXT_NewLabel(ping_time_str),
+ TXT_NewButton2(NET_AddrToString(addr),
+ SelectQueryAddress, querydata),
+ TXT_NewLabel(description),
+ NULL);
+
+ ++query_servers_found;
+}
+
+static void QueryPeriodicCallback(TXT_UNCAST_ARG(results_table))
+{
+ TXT_CAST_ARG(txt_table_t, results_table);
+
+ if (!NET_Query_Poll(QueryResponseCallback, results_table))
+ {
+ TXT_SetPeriodicCallback(NULL, NULL, 0);
+
+ if (query_servers_found == 0)
+ {
+ TXT_AddWidget(results_table, NULL);
+ TXT_AddWidget(results_table, TXT_NewLabel("No servers found."));
+ }
+ }
+}
+
+static void QueryWindowClosed(TXT_UNCAST_ARG(window), void *unused)
+{
+ TXT_SetPeriodicCallback(NULL, NULL, 0);
+}
+
+static void ServerQueryWindow(char *title)
+{
+ txt_table_t *results_table;
+
+ query_servers_found = 0;
+
+ query_window = TXT_NewWindow(title);
+
+ TXT_AddWidget(query_window,
+ TXT_NewScrollPane(70, 10,
+ results_table = TXT_NewTable(3)));
+
+ TXT_SetColumnWidths(results_table, 7, 16, 46);
+ TXT_SetPeriodicCallback(QueryPeriodicCallback, results_table, 1);
+
+ TXT_SignalConnect(query_window, "closed", QueryWindowClosed, NULL);
+}
+
+static void FindInternetServer(TXT_UNCAST_ARG(widget),
+ TXT_UNCAST_ARG(user_data))
+{
+ NET_StartMasterQuery();
+ ServerQueryWindow("Find internet server");
+}
-static void SelectAddressJoin(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused))
+static void FindLANServer(TXT_UNCAST_ARG(widget),
+ TXT_UNCAST_ARG(user_data))
{
- jointype = JOIN_ADDRESS;
+ NET_StartLANQuery();
+ ServerQueryWindow("Find LAN server");
}
void JoinMultiGame(void)
@@ -742,7 +947,7 @@ void JoinMultiGame(void)
TXT_AddWidgets(window,
gameopt_table = TXT_NewTable(2),
TXT_NewSeparator("Server"),
- serveropt_table = TXT_NewTable(2),
+ serveropt_table = TXT_NewTable(1),
TXT_NewStrut(0, 1),
TXT_NewButton2("Add extra parameters...", OpenExtraParamsWindow, NULL),
NULL);
@@ -754,15 +959,26 @@ void JoinMultiGame(void)
IWADSelector(),
NULL);
+ if (gamemission == hexen)
+ {
+ TXT_AddWidgets(gameopt_table,
+ TXT_NewLabel("Character class "),
+ TXT_NewDropdownList(&character_class,
+ character_classes, 3),
+ NULL);
+ }
+
TXT_AddWidgets(serveropt_table,
- TXT_NewRadioButton("Connect to address:",
- &jointype, JOIN_ADDRESS),
- address_box = TXT_NewInputBox(&connect_address, 30),
- TXT_NewRadioButton("Auto-join LAN game",
- &jointype, JOIN_AUTO_LAN),
+ TXT_NewHorizBox(
+ TXT_NewLabel("Connect to address: "),
+ address_box = TXT_NewInputBox(&connect_address, 30),
+ NULL),
+ TXT_NewButton2("Find server on Internet...",
+ FindInternetServer, NULL),
+ TXT_NewButton2("Find server on local network...",
+ FindLANServer, NULL),
NULL);
- TXT_SignalConnect(address_box, "changed", SelectAddressJoin, NULL);
TXT_SelectWidget(window, address_box);
TXT_SetWindowAction(window, TXT_HORIZ_CENTER, WadWindowAction());
@@ -797,38 +1013,16 @@ void SetChatMacroDefaults(void)
}
}
-#ifdef _WIN32
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-
-char *M_OEMToUTF8(const char *oem)
-{
- unsigned int len = strlen(oem) + 1;
- wchar_t *tmp;
- char *result;
-
- tmp = malloc(len * sizeof(wchar_t));
- MultiByteToWideChar(CP_OEMCP, 0, oem, len, tmp, len);
- result = malloc(len * 4);
- WideCharToMultiByte(CP_UTF8, 0, tmp, len, result, len * 4, NULL, NULL);
- free(tmp);
-
- return result;
-}
-
-#endif
-
void SetPlayerNameDefault(void)
{
if (net_player_name == NULL)
{
- net_player_name = getenv("USER");
+ net_player_name = strdup(getenv("USER"));
}
if (net_player_name == NULL)
{
- net_player_name = getenv("USERNAME");
+ net_player_name = strdup(getenv("USERNAME"));
}
// On Windows, environment variables are in OEM codepage
@@ -843,7 +1037,7 @@ void SetPlayerNameDefault(void)
if (net_player_name == NULL)
{
- net_player_name = "player";
+ net_player_name = strdup("player");
}
}
@@ -884,3 +1078,53 @@ void MultiplayerConfig(void)
TXT_AddWidget(window, table);
}
+void BindMultiplayerVariables(void)
+{
+ char buf[15];
+ int i;
+
+#ifdef FEATURE_MULTIPLAYER
+ M_BindVariable("player_name", &net_player_name);
+#endif
+
+ for (i=0; i<10; ++i)
+ {
+ sprintf(buf, "chatmacro%i", i);
+ M_BindVariable(buf, &chat_macros[i]);
+ }
+
+ switch (gamemission)
+ {
+ case doom:
+ M_BindChatControls(4);
+ key_multi_msgplayer[0] = 'g';
+ key_multi_msgplayer[1] = 'i';
+ key_multi_msgplayer[2] = 'b';
+ key_multi_msgplayer[3] = 'r';
+ break;
+
+ case heretic:
+ M_BindChatControls(4);
+ key_multi_msgplayer[0] = 'g';
+ key_multi_msgplayer[1] = 'y';
+ key_multi_msgplayer[2] = 'r';
+ key_multi_msgplayer[3] = 'b';
+ break;
+
+ case hexen:
+ M_BindChatControls(8);
+ key_multi_msgplayer[0] = 'b';
+ key_multi_msgplayer[1] = 'r';
+ key_multi_msgplayer[2] = 'y';
+ key_multi_msgplayer[3] = 'g';
+ key_multi_msgplayer[4] = 'j';
+ key_multi_msgplayer[5] = 'w';
+ key_multi_msgplayer[6] = 'h';
+ key_multi_msgplayer[7] = 'p';
+ break;
+
+ default:
+ break;
+ }
+}
+
diff --git a/setup/multiplayer.h b/src/setup/multiplayer.h
index bc88318c..afc8a2a8 100644
--- a/setup/multiplayer.h
+++ b/src/setup/multiplayer.h
@@ -22,9 +22,6 @@
#ifndef SETUP_MULTIPLAYER_H
#define SETUP_MULTIPLAYER_H
-extern char *net_player_name;
-extern char *chat_macros[10];
-
void StartMultiGame(void);
void WarpMenu(void);
void JoinMultiGame(void);
@@ -33,5 +30,7 @@ void MultiplayerConfig(void);
void SetChatMacroDefaults(void);
void SetPlayerNameDefault(void);
+void BindMultiplayerVariables(void);
+
#endif /* #ifndef SETUP_MULTIPLAYER_H */
diff --git a/setup/setup-manifest.xml.in b/src/setup/setup-manifest.xml.in
index ff879263..ff879263 100644
--- a/setup/setup-manifest.xml.in
+++ b/src/setup/setup-manifest.xml.in
diff --git a/setup/setup.desktop.in b/src/setup/setup.desktop.in
index 79fb38be..79fb38be 100644
--- a/setup/setup.desktop.in
+++ b/src/setup/setup.desktop.in
diff --git a/setup/setup_icon.c b/src/setup/setup_icon.c
index 1c18c56f..1c18c56f 100644
--- a/setup/setup_icon.c
+++ b/src/setup/setup_icon.c
diff --git a/src/setup/sound.c b/src/setup/sound.c
new file mode 100644
index 00000000..af7e5dc1
--- /dev/null
+++ b/src/setup/sound.c
@@ -0,0 +1,292 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2006 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+
+// Sound control menu
+
+#include <stdlib.h>
+
+#include "SDL_mixer.h"
+
+#include "textscreen.h"
+#include "m_config.h"
+
+#include "mode.h"
+#include "sound.h"
+
+typedef enum
+{
+ SFXMODE_DISABLED,
+ SFXMODE_DIGITAL,
+ SFXMODE_PCSPEAKER,
+ NUM_SFXMODES
+} sfxmode_t;
+
+static char *sfxmode_strings[] =
+{
+ "Disabled",
+ "Digital",
+ "PC speaker"
+};
+
+typedef enum
+{
+ MUSICMODE_DISABLED,
+ MUSICMODE_OPL,
+ MUSICMODE_NATIVE,
+ MUSICMODE_CD,
+ NUM_MUSICMODES
+} musicmode_t;
+
+static char *musicmode_strings[] =
+{
+ "Disabled",
+ "OPL (Adlib/SB)",
+ "Native MIDI",
+ "CD audio"
+};
+
+// Config file variables:
+
+int snd_sfxdevice = SNDDEVICE_SB;
+int snd_musicdevice = SNDDEVICE_GENMIDI;
+int snd_samplerate = 44100;
+int opl_io_port = 0x388;
+int snd_cachesize = 64 * 1024 * 1024;
+
+static int numChannels = 8;
+static int sfxVolume = 15;
+static int musicVolume = 15;
+static int voiceVolume = 15;
+static int show_talk = 0;
+static int use_libsamplerate = 0;
+
+static char *timidity_cfg_path = "";
+static char *gus_patch_path = "";
+static unsigned int gus_ram_kb = 1024;
+
+// DOS specific variables: these are unused but should be maintained
+// so that the config file can be shared between chocolate
+// doom and doom.exe
+
+static int snd_sbport = 0;
+static int snd_sbirq = 0;
+static int snd_sbdma = 0;
+static int snd_mport = 0;
+
+// GUI variables:
+
+static int snd_sfxmode;
+static int snd_musicmode;
+
+static void UpdateSndDevices(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(data))
+{
+ switch (snd_sfxmode)
+ {
+ case SFXMODE_DISABLED:
+ snd_sfxdevice = SNDDEVICE_NONE;
+ break;
+ case SFXMODE_PCSPEAKER:
+ snd_sfxdevice = SNDDEVICE_PCSPEAKER;
+ break;
+ case SFXMODE_DIGITAL:
+ snd_sfxdevice = SNDDEVICE_SB;
+ break;
+ }
+
+ switch (snd_musicmode)
+ {
+ case MUSICMODE_DISABLED:
+ snd_musicdevice = SNDDEVICE_NONE;
+ break;
+ case MUSICMODE_NATIVE:
+ snd_musicdevice = SNDDEVICE_GENMIDI;
+ break;
+ case MUSICMODE_OPL:
+ snd_musicdevice = SNDDEVICE_SB;
+ break;
+ case MUSICMODE_CD:
+ break;
+ }
+}
+
+void ConfigSound(void)
+{
+ txt_window_t *window;
+ txt_table_t *sfx_table;
+ txt_table_t *music_table;
+ txt_dropdown_list_t *sfx_mode_control;
+ txt_dropdown_list_t *music_mode_control;
+ int num_sfx_modes, num_music_modes;
+
+ // Work out what sfx mode we are currently using:
+
+ if (snd_sfxdevice == SNDDEVICE_PCSPEAKER)
+ {
+ snd_sfxmode = SFXMODE_PCSPEAKER;
+ }
+ else if (snd_sfxdevice >= SNDDEVICE_SB)
+ {
+ snd_sfxmode = SFXMODE_DIGITAL;
+ }
+ else
+ {
+ snd_sfxmode = SFXMODE_DISABLED;
+ }
+
+ // Is music enabled?
+
+ if (snd_musicdevice == SNDDEVICE_GENMIDI)
+ {
+ snd_musicmode = MUSICMODE_NATIVE;
+ }
+ else if (snd_musicmode == SNDDEVICE_CD)
+ {
+ snd_musicmode = MUSICMODE_CD;
+ }
+ else if (snd_musicdevice == SNDDEVICE_SB
+ || snd_musicdevice == SNDDEVICE_ADLIB
+ || snd_musicdevice == SNDDEVICE_AWE32)
+ {
+ snd_musicmode = MUSICMODE_OPL;
+ }
+ else
+ {
+ snd_musicmode = MUSICMODE_DISABLED;
+ }
+
+ // Doom has PC speaker sound effects, but others do not:
+
+ if (gamemission == doom)
+ {
+ num_sfx_modes = NUM_SFXMODES;
+ }
+ else
+ {
+ num_sfx_modes = NUM_SFXMODES - 1;
+ }
+
+ // Hexen has CD audio; others do not.
+
+ if (gamemission == hexen)
+ {
+ num_music_modes = NUM_MUSICMODES;
+ }
+ else
+ {
+ num_music_modes = NUM_MUSICMODES - 1;
+ }
+
+ // Build the window
+
+ window = TXT_NewWindow("Sound configuration");
+
+ TXT_AddWidgets(window,
+ TXT_NewSeparator("Sound effects"),
+ sfx_table = TXT_NewTable(2),
+ NULL);
+
+ TXT_SetColumnWidths(sfx_table, 20, 14);
+
+ TXT_AddWidgets(sfx_table,
+ TXT_NewLabel("Sound effects"),
+ sfx_mode_control = TXT_NewDropdownList(&snd_sfxmode,
+ sfxmode_strings,
+ num_sfx_modes),
+ TXT_NewLabel("Sound channels"),
+ TXT_NewSpinControl(&numChannels, 1, 8),
+ TXT_NewLabel("SFX volume"),
+ TXT_NewSpinControl(&sfxVolume, 0, 15),
+ NULL);
+
+ if (gamemission == strife)
+ {
+ TXT_AddWidgets(sfx_table,
+ TXT_NewLabel("Voice volume"),
+ TXT_NewSpinControl(&voiceVolume, 0, 15),
+ NULL);
+ TXT_AddWidget(window,
+ TXT_NewCheckBox("Show text with voices", &show_talk));
+ }
+
+ TXT_AddWidgets(window,
+ TXT_NewSeparator("Music"),
+ music_table = TXT_NewTable(2),
+ NULL);
+
+ TXT_SetColumnWidths(music_table, 20, 14);
+
+ TXT_AddWidgets(music_table,
+ TXT_NewLabel("Music"),
+ music_mode_control = TXT_NewDropdownList(&snd_musicmode,
+ musicmode_strings,
+ num_music_modes),
+ TXT_NewLabel("Music volume"),
+ TXT_NewSpinControl(&musicVolume, 0, 15),
+ NULL);
+
+ TXT_SignalConnect(sfx_mode_control, "changed", UpdateSndDevices, NULL);
+ TXT_SignalConnect(music_mode_control, "changed", UpdateSndDevices, NULL);
+}
+
+void BindSoundVariables(void)
+{
+ M_BindVariable("snd_sfxdevice", &snd_sfxdevice);
+ M_BindVariable("snd_musicdevice", &snd_musicdevice);
+ M_BindVariable("snd_channels", &numChannels);
+ M_BindVariable("sfx_volume", &sfxVolume);
+ M_BindVariable("music_volume", &musicVolume);
+ M_BindVariable("snd_samplerate", &snd_samplerate);
+ M_BindVariable("use_libsamplerate", &use_libsamplerate);
+ M_BindVariable("timidity_cfg_path", &timidity_cfg_path);
+ M_BindVariable("gus_patch_path", &gus_patch_path);
+ M_BindVariable("gus_ram_kb", &gus_ram_kb);
+
+ M_BindVariable("snd_sbport", &snd_sbport);
+ M_BindVariable("snd_sbirq", &snd_sbirq);
+ M_BindVariable("snd_sbdma", &snd_sbdma);
+ M_BindVariable("snd_mport", &snd_mport);
+
+ M_BindVariable("snd_cachesize", &snd_cachesize);
+ M_BindVariable("opl_io_port", &opl_io_port);
+
+ if (gamemission == strife)
+ {
+ M_BindVariable("voice_volume", &voiceVolume);
+ M_BindVariable("show_talk", &show_talk);
+ }
+
+ // Before SDL_mixer version 1.2.11, MIDI music caused the game
+ // to crash when it looped. If this is an old SDL_mixer version,
+ // disable MIDI.
+
+#ifdef __MACOSX__
+ {
+ const SDL_version *v = Mix_Linked_Version();
+
+ if (SDL_VERSIONNUM(v->major, v->minor, v->patch)
+ < SDL_VERSIONNUM(1, 2, 11))
+ {
+ snd_musicdevice = SNDDEVICE_NONE;
+ }
+ }
+#endif
+}
+
diff --git a/src/setup/sound.h b/src/setup/sound.h
new file mode 100644
index 00000000..b41c1b4b
--- /dev/null
+++ b/src/setup/sound.h
@@ -0,0 +1,30 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2006 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+
+#ifndef SETUP_SOUND_H
+#define SETUP_SOUND_H
+
+#include "i_sound.h"
+
+void ConfigSound(void);
+void BindSoundVariables(void);
+
+#endif /* #ifndef SETUP_SOUND_H */
diff --git a/setup/txt_joybinput.c b/src/setup/txt_joybinput.c
index fb4015b6..3e033df9 100644
--- a/setup/txt_joybinput.c
+++ b/src/setup/txt_joybinput.c
@@ -76,22 +76,12 @@ static void PromptWindowClosed(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(joystick))
static void OpenErrorWindow(void)
{
- txt_window_t *window;
-
- window = TXT_NewWindow(NULL);
-
- TXT_AddWidget(window, TXT_NewLabel("Please configure a joystick first!"));
-
- TXT_SetWindowAction(window, TXT_HORIZ_LEFT, NULL);
- TXT_SetWindowAction(window, TXT_HORIZ_CENTER,
- TXT_NewWindowEscapeAction(window));
- TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, NULL);
+ TXT_MessageBox(NULL, "Please configure a joystick first!");
}
static void OpenPromptWindow(txt_joystick_input_t *joystick_input)
{
txt_window_t *window;
- txt_label_t *label;
SDL_Joystick *joystick;
// Silently update when the shift button is held down.
@@ -115,16 +105,8 @@ static void OpenPromptWindow(txt_joystick_input_t *joystick_input)
// Open the prompt window
- window = TXT_NewWindow(NULL);
- TXT_SetWindowAction(window, TXT_HORIZ_LEFT, NULL);
- TXT_SetWindowAction(window, TXT_HORIZ_CENTER,
- TXT_NewWindowAbortAction(window));
- TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, NULL);
-
- label = TXT_NewLabel("Press the new joystick button...");
+ window = TXT_MessageBox(NULL, "Press the new joystick button...");
- TXT_AddWidget(window, label);
- TXT_SetWidgetAlign(label, TXT_HORIZ_CENTER);
TXT_SDL_SetEventCallback(EventCallback, joystick_input);
TXT_SignalConnect(window, "closed", PromptWindowClosed, joystick);
joystick_input->prompt_window = window;
diff --git a/setup/txt_joybinput.h b/src/setup/txt_joybinput.h
index 69ec4a1f..69ec4a1f 100644
--- a/setup/txt_joybinput.h
+++ b/src/setup/txt_joybinput.h
diff --git a/setup/txt_keyinput.c b/src/setup/txt_keyinput.c
index 19b0d56e..55889dbc 100644
--- a/setup/txt_keyinput.c
+++ b/src/setup/txt_keyinput.c
@@ -70,22 +70,12 @@ static void ReleaseGrab(TXT_UNCAST_ARG(window), TXT_UNCAST_ARG(unused))
static void OpenPromptWindow(txt_key_input_t *key_input)
{
txt_window_t *window;
- txt_label_t *label;
// Silently update when the shift button is held down.
key_input->check_conflicts = !TXT_GetModifierState(TXT_MOD_SHIFT);
- window = TXT_NewWindow(NULL);
- TXT_SetWindowAction(window, TXT_HORIZ_LEFT, NULL);
- TXT_SetWindowAction(window, TXT_HORIZ_CENTER,
- TXT_NewWindowAbortAction(window));
- TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, NULL);
-
- label = TXT_NewLabel("Press the new key...");
-
- TXT_AddWidget(window, label);
- TXT_SetWidgetAlign(label, TXT_HORIZ_CENTER);
+ window = TXT_MessageBox(NULL, "Press the new key...");
TXT_SetKeyListener(window, KeyPressCallback, key_input);
diff --git a/setup/txt_keyinput.h b/src/setup/txt_keyinput.h
index 5df0b2e3..5df0b2e3 100644
--- a/setup/txt_keyinput.h
+++ b/src/setup/txt_keyinput.h
diff --git a/setup/txt_mouseinput.c b/src/setup/txt_mouseinput.c
index 30102b45..6eee78cd 100644
--- a/setup/txt_mouseinput.c
+++ b/src/setup/txt_mouseinput.c
@@ -56,21 +56,11 @@ static int MousePressCallback(txt_window_t *window,
static void OpenPromptWindow(txt_mouse_input_t *mouse_input)
{
txt_window_t *window;
- txt_label_t *label;
// Silently update when the shift key is held down.
mouse_input->check_conflicts = !TXT_GetModifierState(TXT_MOD_SHIFT);
- window = TXT_NewWindow(NULL);
- TXT_SetWindowAction(window, TXT_HORIZ_LEFT, NULL);
- TXT_SetWindowAction(window, TXT_HORIZ_CENTER,
- TXT_NewWindowAbortAction(window));
- TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, NULL);
-
- label = TXT_NewLabel("Press the new mouse button...");
-
- TXT_AddWidget(window, label);
- TXT_SetWidgetAlign(label, TXT_HORIZ_CENTER);
+ window = TXT_MessageBox(NULL, "Press the new mouse button...");
TXT_SetMouseListener(window, MousePressCallback, mouse_input);
}
diff --git a/setup/txt_mouseinput.h b/src/setup/txt_mouseinput.h
index ef3ec2aa..ef3ec2aa 100644
--- a/setup/txt_mouseinput.h
+++ b/src/setup/txt_mouseinput.h
diff --git a/src/sounds.c b/src/sounds.c
deleted file mode 100644
index 6f315023..00000000
--- a/src/sounds.c
+++ /dev/null
@@ -1,230 +0,0 @@
-// Emacs style mode select -*- C++ -*-
-//-----------------------------------------------------------------------------
-//
-// Copyright(C) 1993-1996 Id Software, Inc.
-// Copyright(C) 2005 Simon Howard
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-// 02111-1307, USA.
-//
-// DESCRIPTION:
-// Created by a sound utility.
-// Kept as a sample, DOOM2 sounds.
-//
-//-----------------------------------------------------------------------------
-
-
-#include <stdlib.h>
-
-
-#include "doomtype.h"
-#include "sounds.h"
-
-//
-// Information about all the music
-//
-
-musicinfo_t S_music[] =
-{
- { NULL, 0, 0, 0 },
- { "e1m1", 0, 0, 0 },
- { "e1m2", 0, 0, 0 },
- { "e1m3", 0, 0, 0 },
- { "e1m4", 0, 0, 0 },
- { "e1m5", 0, 0, 0 },
- { "e1m6", 0, 0, 0 },
- { "e1m7", 0, 0, 0 },
- { "e1m8", 0, 0, 0 },
- { "e1m9", 0, 0, 0 },
- { "e2m1", 0, 0, 0 },
- { "e2m2", 0, 0, 0 },
- { "e2m3", 0, 0, 0 },
- { "e2m4", 0, 0, 0 },
- { "e2m5", 0, 0, 0 },
- { "e2m6", 0, 0, 0 },
- { "e2m7", 0, 0, 0 },
- { "e2m8", 0, 0, 0 },
- { "e2m9", 0, 0, 0 },
- { "e3m1", 0, 0, 0 },
- { "e3m2", 0, 0, 0 },
- { "e3m3", 0, 0, 0 },
- { "e3m4", 0, 0, 0 },
- { "e3m5", 0, 0, 0 },
- { "e3m6", 0, 0, 0 },
- { "e3m7", 0, 0, 0 },
- { "e3m8", 0, 0, 0 },
- { "e3m9", 0, 0, 0 },
- { "inter", 0, 0, 0 },
- { "intro", 0, 0, 0 },
- { "bunny", 0, 0, 0 },
- { "victor", 0, 0, 0 },
- { "introa", 0, 0, 0 },
- { "runnin", 0, 0, 0 },
- { "stalks", 0, 0, 0 },
- { "countd", 0, 0, 0 },
- { "betwee", 0, 0, 0 },
- { "doom", 0, 0, 0 },
- { "the_da", 0, 0, 0 },
- { "shawn", 0, 0, 0 },
- { "ddtblu", 0, 0, 0 },
- { "in_cit", 0, 0, 0 },
- { "dead", 0, 0, 0 },
- { "stlks2", 0, 0, 0 },
- { "theda2", 0, 0, 0 },
- { "doom2", 0, 0, 0 },
- { "ddtbl2", 0, 0, 0 },
- { "runni2", 0, 0, 0 },
- { "dead2", 0, 0, 0 },
- { "stlks3", 0, 0, 0 },
- { "romero", 0, 0, 0 },
- { "shawn2", 0, 0, 0 },
- { "messag", 0, 0, 0 },
- { "count2", 0, 0, 0 },
- { "ddtbl3", 0, 0, 0 },
- { "ampie", 0, 0, 0 },
- { "theda3", 0, 0, 0 },
- { "adrian", 0, 0, 0 },
- { "messg2", 0, 0, 0 },
- { "romer2", 0, 0, 0 },
- { "tense", 0, 0, 0 },
- { "shawn3", 0, 0, 0 },
- { "openin", 0, 0, 0 },
- { "evil", 0, 0, 0 },
- { "ultima", 0, 0, 0 },
- { "read_m", 0, 0, 0 },
- { "dm2ttl", 0, 0, 0 },
- { "dm2int", 0, 0, 0 }
-};
-
-
-//
-// Information about all the sfx
-//
-
-sfxinfo_t S_sfx[] =
-{
- // S_sfx[0] needs to be a dummy for odd reasons.
- { "none", false, 0, 0, -1, -1, 0, 0, 0 },
-
- { "pistol", false, 64, 0, -1, -1, 0, 0, 0 },
- { "shotgn", false, 64, 0, -1, -1, 0, 0, 0 },
- { "sgcock", false, 64, 0, -1, -1, 0, 0, 0 },
- { "dshtgn", false, 64, 0, -1, -1, 0, 0, 0 },
- { "dbopn", false, 64, 0, -1, -1, 0, 0, 0 },
- { "dbcls", false, 64, 0, -1, -1, 0, 0, 0 },
- { "dbload", false, 64, 0, -1, -1, 0, 0, 0 },
- { "plasma", false, 64, 0, -1, -1, 0, 0, 0 },
- { "bfg", false, 64, 0, -1, -1, 0, 0, 0 },
- { "sawup", false, 64, 0, -1, -1, 0, 0, 0 },
- { "sawidl", false, 118, 0, -1, -1, 0, 0, 0 },
- { "sawful", false, 64, 0, -1, -1, 0, 0, 0 },
- { "sawhit", false, 64, 0, -1, -1, 0, 0, 0 },
- { "rlaunc", false, 64, 0, -1, -1, 0, 0, 0 },
- { "rxplod", false, 70, 0, -1, -1, 0, 0, 0 },
- { "firsht", false, 70, 0, -1, -1, 0, 0, 0 },
- { "firxpl", false, 70, 0, -1, -1, 0, 0, 0 },
- { "pstart", false, 100, 0, -1, -1, 0, 0, 0 },
- { "pstop", false, 100, 0, -1, -1, 0, 0, 0 },
- { "doropn", false, 100, 0, -1, -1, 0, 0, 0 },
- { "dorcls", false, 100, 0, -1, -1, 0, 0, 0 },
- { "stnmov", false, 119, 0, -1, -1, 0, 0, 0 },
- { "swtchn", false, 78, 0, -1, -1, 0, 0, 0 },
- { "swtchx", false, 78, 0, -1, -1, 0, 0, 0 },
- { "plpain", false, 96, 0, -1, -1, 0, 0, 0 },
- { "dmpain", false, 96, 0, -1, -1, 0, 0, 0 },
- { "popain", false, 96, 0, -1, -1, 0, 0, 0 },
- { "vipain", false, 96, 0, -1, -1, 0, 0, 0 },
- { "mnpain", false, 96, 0, -1, -1, 0, 0, 0 },
- { "pepain", false, 96, 0, -1, -1, 0, 0, 0 },
- { "slop", false, 78, 0, -1, -1, 0, 0, 0 },
- { "itemup", true, 78, 0, -1, -1, 0, 0, 0 },
- { "wpnup", true, 78, 0, -1, -1, 0, 0, 0 },
- { "oof", false, 96, 0, -1, -1, 0, 0, 0 },
- { "telept", false, 32, 0, -1, -1, 0, 0, 0 },
- { "posit1", true, 98, 0, -1, -1, 0, 0, 0 },
- { "posit2", true, 98, 0, -1, -1, 0, 0, 0 },
- { "posit3", true, 98, 0, -1, -1, 0, 0, 0 },
- { "bgsit1", true, 98, 0, -1, -1, 0, 0, 0 },
- { "bgsit2", true, 98, 0, -1, -1, 0, 0, 0 },
- { "sgtsit", true, 98, 0, -1, -1, 0, 0, 0 },
- { "cacsit", true, 98, 0, -1, -1, 0, 0, 0 },
- { "brssit", true, 94, 0, -1, -1, 0, 0, 0 },
- { "cybsit", true, 92, 0, -1, -1, 0, 0, 0 },
- { "spisit", true, 90, 0, -1, -1, 0, 0, 0 },
- { "bspsit", true, 90, 0, -1, -1, 0, 0, 0 },
- { "kntsit", true, 90, 0, -1, -1, 0, 0, 0 },
- { "vilsit", true, 90, 0, -1, -1, 0, 0, 0 },
- { "mansit", true, 90, 0, -1, -1, 0, 0, 0 },
- { "pesit", true, 90, 0, -1, -1, 0, 0, 0 },
- { "sklatk", false, 70, 0, -1, -1, 0, 0, 0 },
- { "sgtatk", false, 70, 0, -1, -1, 0, 0, 0 },
- { "skepch", false, 70, 0, -1, -1, 0, 0, 0 },
- { "vilatk", false, 70, 0, -1, -1, 0, 0, 0 },
- { "claw", false, 70, 0, -1, -1, 0, 0, 0 },
- { "skeswg", false, 70, 0, -1, -1, 0, 0, 0 },
- { "pldeth", false, 32, 0, -1, -1, 0, 0, 0 },
- { "pdiehi", false, 32, 0, -1, -1, 0, 0, 0 },
- { "podth1", false, 70, 0, -1, -1, 0, 0, 0 },
- { "podth2", false, 70, 0, -1, -1, 0, 0, 0 },
- { "podth3", false, 70, 0, -1, -1, 0, 0, 0 },
- { "bgdth1", false, 70, 0, -1, -1, 0, 0, 0 },
- { "bgdth2", false, 70, 0, -1, -1, 0, 0, 0 },
- { "sgtdth", false, 70, 0, -1, -1, 0, 0, 0 },
- { "cacdth", false, 70, 0, -1, -1, 0, 0, 0 },
- { "skldth", false, 70, 0, -1, -1, 0, 0, 0 },
- { "brsdth", false, 32, 0, -1, -1, 0, 0, 0 },
- { "cybdth", false, 32, 0, -1, -1, 0, 0, 0 },
- { "spidth", false, 32, 0, -1, -1, 0, 0, 0 },
- { "bspdth", false, 32, 0, -1, -1, 0, 0, 0 },
- { "vildth", false, 32, 0, -1, -1, 0, 0, 0 },
- { "kntdth", false, 32, 0, -1, -1, 0, 0, 0 },
- { "pedth", false, 32, 0, -1, -1, 0, 0, 0 },
- { "skedth", false, 32, 0, -1, -1, 0, 0, 0 },
- { "posact", true, 120, 0, -1, -1, 0, 0, 0 },
- { "bgact", true, 120, 0, -1, -1, 0, 0, 0 },
- { "dmact", true, 120, 0, -1, -1, 0, 0, 0 },
- { "bspact", true, 100, 0, -1, -1, 0, 0, 0 },
- { "bspwlk", true, 100, 0, -1, -1, 0, 0, 0 },
- { "vilact", true, 100, 0, -1, -1, 0, 0, 0 },
- { "noway", false, 78, 0, -1, -1, 0, 0, 0 },
- { "barexp", false, 60, 0, -1, -1, 0, 0, 0 },
- { "punch", false, 64, 0, -1, -1, 0, 0, 0 },
- { "hoof", false, 70, 0, -1, -1, 0, 0, 0 },
- { "metal", false, 70, 0, -1, -1, 0, 0, 0 },
- { "chgun", false, 64, &S_sfx[sfx_pistol], 150, 0, 0, 0, 0 },
- { "tink", false, 60, 0, -1, -1, 0, 0, 0 },
- { "bdopn", false, 100, 0, -1, -1, 0, 0, 0 },
- { "bdcls", false, 100, 0, -1, -1, 0, 0, 0 },
- { "itmbk", false, 100, 0, -1, -1, 0, 0, 0 },
- { "flame", false, 32, 0, -1, -1, 0, 0, 0 },
- { "flamst", false, 32, 0, -1, -1, 0, 0, 0 },
- { "getpow", false, 60, 0, -1, -1, 0, 0, 0 },
- { "bospit", false, 70, 0, -1, -1, 0, 0, 0 },
- { "boscub", false, 70, 0, -1, -1, 0, 0, 0 },
- { "bossit", false, 70, 0, -1, -1, 0, 0, 0 },
- { "bospn", false, 70, 0, -1, -1, 0, 0, 0 },
- { "bosdth", false, 70, 0, -1, -1, 0, 0, 0 },
- { "manatk", false, 70, 0, -1, -1, 0, 0, 0 },
- { "mandth", false, 70, 0, -1, -1, 0, 0, 0 },
- { "sssit", false, 70, 0, -1, -1, 0, 0, 0 },
- { "ssdth", false, 70, 0, -1, -1, 0, 0, 0 },
- { "keenpn", false, 70, 0, -1, -1, 0, 0, 0 },
- { "keendt", false, 70, 0, -1, -1, 0, 0, 0 },
- { "skeact", false, 70, 0, -1, -1, 0, 0, 0 },
- { "skesit", false, 70, 0, -1, -1, 0, 0, 0 },
- { "skeatk", false, 70, 0, -1, -1, 0, 0, 0 },
- { "radio", false, 60, 0, -1, -1, 0, 0, 0 }
-};
-
diff --git a/src/strife/.gitignore b/src/strife/.gitignore
new file mode 100644
index 00000000..d4e88e5a
--- /dev/null
+++ b/src/strife/.gitignore
@@ -0,0 +1,5 @@
+Makefile
+Makefile.in
+.deps
+tags
+TAGS
diff --git a/src/strife/Makefile.am b/src/strife/Makefile.am
new file mode 100644
index 00000000..df1f7bb0
--- /dev/null
+++ b/src/strife/Makefile.am
@@ -0,0 +1,78 @@
+AM_CFLAGS = -I.. @SDL_CFLAGS@ @SDLMIXER_CFLAGS@ @SDLNET_CFLAGS@
+
+noinst_LIBRARIES=libstrife.a
+
+SOURCE_FILES= \
+am_map.c am_map.h \
+ d_englsh.h \
+d_items.c d_items.h \
+d_main.c d_main.h \
+d_net.c \
+ doomdata.h \
+doomdef.c doomdef.h \
+doomstat.c doomstat.h \
+ d_player.h \
+dstrings.c dstrings.h \
+ d_textur.h \
+ d_think.h \
+f_finale.c f_finale.h \
+f_wipe.c f_wipe.h \
+g_game.c g_game.h \
+hu_lib.c hu_lib.h \
+hu_stuff.c hu_stuff.h \
+info.c info.h \
+m_menu.c m_menu.h \
+m_random.c m_random.h \
+m_saves.c m_saves.h \
+p_ceilng.c \
+p_dialog.c p_dialog.h \
+p_doors.c \
+p_enemy.c \
+p_floor.c \
+p_inter.c p_inter.h \
+p_lights.c \
+ p_local.h \
+p_map.c \
+p_maputl.c \
+p_mobj.c p_mobj.h \
+p_plats.c \
+p_pspr.c p_pspr.h \
+p_saveg.c p_saveg.h \
+p_setup.c p_setup.h \
+p_sight.c \
+p_spec.c p_spec.h \
+p_switch.c \
+p_telept.c \
+p_tick.c p_tick.h \
+p_user.c \
+r_bsp.c r_bsp.h \
+r_data.c r_data.h \
+ r_defs.h \
+r_draw.c r_draw.h \
+ r_local.h \
+r_main.c r_main.h \
+r_plane.c r_plane.h \
+r_segs.c r_segs.h \
+r_sky.c r_sky.h \
+ r_state.h \
+r_things.c r_things.h \
+s_sound.c s_sound.h \
+sounds.c sounds.h \
+st_lib.c st_lib.h \
+st_stuff.c st_stuff.h \
+wi_stuff.c wi_stuff.h
+
+FEATURE_DEHACKED_SOURCE_FILES = \
+deh_ammo.c \
+deh_cheat.c \
+deh_strife.c \
+deh_frame.c \
+deh_misc.c deh_misc.h \
+deh_ptr.c \
+deh_sound.c \
+deh_thing.c \
+deh_weapon.c
+
+libstrife_a_SOURCES = $(SOURCE_FILES) \
+ $(FEATURE_DEHACKED_SOURCE_FILES)
+
diff --git a/src/strife/am_map.c b/src/strife/am_map.c
new file mode 100644
index 00000000..e942e3ac
--- /dev/null
+++ b/src/strife/am_map.c
@@ -0,0 +1,1391 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//
+// DESCRIPTION: the automap code
+//
+//-----------------------------------------------------------------------------
+
+
+#include <stdio.h>
+
+#include "deh_main.h"
+
+#include "z_zone.h"
+#include "doomkeys.h"
+#include "doomdef.h"
+#include "st_stuff.h"
+#include "p_local.h"
+#include "w_wad.h"
+
+#include "m_cheat.h"
+#include "m_controls.h"
+#include "i_system.h"
+
+// Needs access to LFB.
+#include "v_video.h"
+
+// State.
+#include "doomstat.h"
+#include "r_state.h"
+
+// Data.
+#include "dstrings.h"
+
+#include "am_map.h"
+
+
+// Automap colors
+#define BACKGROUND 240 // haleyjd [STRIFE]
+#define WALLCOLORS 5 // villsa [STRIFE]
+#define WALLRANGE 16
+#define TSWALLCOLORS 16
+#define FDWALLCOLORS 122 // villsa [STRIFE]
+#define CDWALLCOLORS 116
+#define CTWALLCOLORS 19 // villsa [STRIFE]
+#define SPWALLCOLORS 243 // villsa [STRIFE]
+#define THINGCOLORS 233 // villsa [STRIFE]
+#define MISSILECOLORS 227 // villsa [STRIFE]
+#define SHOOTABLECOLORS 235 // villsa [STRIFE]
+
+// drawing stuff
+
+#define AM_NUMMARKPOINTS 10
+
+// scale on entry
+#define INITSCALEMTOF (.2*FRACUNIT)
+// how much the automap moves window per tic in frame-buffer coordinates
+// moves 140 pixels in 1 second
+#define F_PANINC 4
+// how much zoom-in per tic
+// goes to 2x in 1 second
+#define M_ZOOMIN ((int) (1.02*FRACUNIT))
+// how much zoom-out per tic
+// pulls out to 0.5x in 1 second
+#define M_ZOOMOUT ((int) (FRACUNIT/1.02))
+
+// translates between frame-buffer and map distances
+#define FTOM(x) FixedMul(((x)<<16),scale_ftom)
+#define MTOF(x) (FixedMul((x),scale_mtof)>>16)
+// translates between frame-buffer and map coordinates
+#define CXMTOF(x) (f_x + MTOF((x)-m_x))
+#define CYMTOF(y) (f_y + (f_h - MTOF((y)-m_y)))
+
+// the following is crap
+#define LINE_NEVERSEE ML_DONTDRAW
+
+typedef struct
+{
+ int x, y;
+} fpoint_t;
+
+typedef struct
+{
+ fpoint_t a, b;
+} fline_t;
+
+typedef struct
+{
+ fixed_t x,y;
+} mpoint_t;
+
+typedef struct
+{
+ mpoint_t a, b;
+} mline_t;
+
+typedef struct
+{
+ fixed_t slp, islp;
+} islope_t;
+
+
+
+//
+// The vector graphics for the automap.
+// A line drawing of the player pointing right,
+// starting from the middle.
+//
+#define R ((8*PLAYERRADIUS)/7)
+mline_t player_arrow[] = {
+ { { -R+R/8, 0 }, { R, 0 } }, // -----
+ { { R, 0 }, { R-R/2, R/4 } }, // ----->
+ { { R, 0 }, { R-R/2, -R/4 } },
+ { { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >---->
+ { { -R+R/8, 0 }, { -R-R/8, -R/4 } },
+ { { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>--->
+ { { -R+3*R/8, 0 }, { -R+R/8, -R/4 } }
+};
+#undef R
+
+#define R ((8*PLAYERRADIUS)/7)
+mline_t cheat_player_arrow[] = {
+ { { -R+R/8, 0 }, { R, 0 } }, // -----
+ { { R, 0 }, { R-R/2, R/6 } }, // ----->
+ { { R, 0 }, { R-R/2, -R/6 } },
+ { { -R+R/8, 0 }, { -R-R/8, R/6 } }, // >----->
+ { { -R+R/8, 0 }, { -R-R/8, -R/6 } },
+ { { -R+3*R/8, 0 }, { -R+R/8, R/6 } }, // >>----->
+ { { -R+3*R/8, 0 }, { -R+R/8, -R/6 } },
+ { { -R/2, 0 }, { -R/2, -R/6 } }, // >>-d--->
+ { { -R/2, -R/6 }, { -R/2+R/6, -R/6 } },
+ { { -R/2+R/6, -R/6 }, { -R/2+R/6, R/4 } },
+ { { -R/6, 0 }, { -R/6, -R/6 } }, // >>-dd-->
+ { { -R/6, -R/6 }, { 0, -R/6 } },
+ { { 0, -R/6 }, { 0, R/4 } },
+ { { R/6, R/4 }, { R/6, -R/7 } }, // >>-ddt->
+ { { R/6, -R/7 }, { R/6+R/32, -R/7-R/32 } },
+ { { R/6+R/32, -R/7-R/32 }, { R/6+R/10, -R/7 } }
+};
+#undef R
+
+#define R (FRACUNIT)
+mline_t triangle_guy[] = {
+ { { (fixed_t)(-.867*R), (fixed_t)(-.5*R) }, { (fixed_t)(.867*R ), (fixed_t)(-.5*R) } },
+ { { (fixed_t)(.867*R ), (fixed_t)(-.5*R) }, { (fixed_t)(0 ), (fixed_t)(R ) } },
+ { { (fixed_t)(0 ), (fixed_t)(R ) }, { (fixed_t)(-.867*R), (fixed_t)(-.5*R) } }
+};
+#undef R
+
+#define R (FRACUNIT)
+mline_t thintriangle_guy[] = {
+ { { (fixed_t)(-.5*R), (fixed_t)(-.7*R) }, { (fixed_t)(R ), (fixed_t)(0 ) } },
+ { { (fixed_t)(R ), (fixed_t)(0 ) }, { (fixed_t)(-.5*R), (fixed_t)(.7*R ) } },
+ { { (fixed_t)(-.5*R), (fixed_t)(.7*R ) }, { (fixed_t)(-.5*R), (fixed_t)(-.7*R) } }
+};
+#undef R
+
+
+
+
+static int cheating = 0;
+static int grid = 0;
+
+static int leveljuststarted = 1; // kluge until AM_LevelInit() is called
+
+boolean automapactive = false;
+static int finit_width = SCREENWIDTH;
+static int finit_height = SCREENHEIGHT - 32;
+
+// location of window on screen
+static int f_x;
+static int f_y;
+
+// size of window on screen
+static int f_w;
+static int f_h;
+
+static int lightlev; // used for funky strobing effect
+static byte* fb; // pseudo-frame buffer
+static int amclock;
+
+static mpoint_t m_paninc; // how far the window pans each tic (map coords)
+static fixed_t mtof_zoommul; // how far the window zooms in each tic (map coords)
+static fixed_t ftom_zoommul; // how far the window zooms in each tic (fb coords)
+
+static fixed_t m_x, m_y; // LL x,y where the window is on the map (map coords)
+static fixed_t m_x2, m_y2; // UR x,y where the window is on the map (map coords)
+
+//
+// width/height of window on map (map coords)
+//
+static fixed_t m_w;
+static fixed_t m_h;
+
+// based on level size
+static fixed_t min_x;
+static fixed_t min_y;
+static fixed_t max_x;
+static fixed_t max_y;
+
+static fixed_t max_w; // max_x-min_x,
+static fixed_t max_h; // max_y-min_y
+
+// based on player size
+static fixed_t min_w;
+static fixed_t min_h;
+
+
+static fixed_t min_scale_mtof; // used to tell when to stop zooming out
+static fixed_t max_scale_mtof; // used to tell when to stop zooming in
+
+// old stuff for recovery later
+static fixed_t old_m_w, old_m_h;
+static fixed_t old_m_x, old_m_y;
+
+// old location used by the Follower routine
+static mpoint_t f_oldloc;
+
+// used by MTOF to scale from map-to-frame-buffer coords
+static fixed_t scale_mtof = (fixed_t)INITSCALEMTOF;
+// used by FTOM to scale from frame-buffer-to-map coords (=1/scale_mtof)
+static fixed_t scale_ftom;
+
+static player_t *plr; // the player represented by an arrow
+
+static patch_t *marknums[10]; // numbers used for marking by the automap
+static mpoint_t markpoints[AM_NUMMARKPOINTS]; // where the points are
+static int markpointnum = 0; // next point to be assigned
+static int mapmarknum = 0; // villsa [STRIFE] unused but this was meant to be used for objective based markers
+static int followplayer = 1; // specifies whether to follow the player around
+
+cheatseq_t cheat_amap = CHEAT("topo", 0); // villsa [STRIFE]
+
+static boolean stopped = true;
+
+
+// Calculates the slope and slope according to the x-axis of a line
+// segment in map coordinates (with the upright y-axis n' all) so
+// that it can be used with the brain-dead drawing stuff.
+
+void
+AM_getIslope
+( mline_t* ml,
+ islope_t* is )
+{
+ int dx, dy;
+
+ dy = ml->a.y - ml->b.y;
+ dx = ml->b.x - ml->a.x;
+ if (!dy) is->islp = (dx<0?-INT_MAX:INT_MAX);
+ else is->islp = FixedDiv(dx, dy);
+ if (!dx) is->slp = (dy<0?-INT_MAX:INT_MAX);
+ else is->slp = FixedDiv(dy, dx);
+
+}
+
+//
+//
+//
+void AM_activateNewScale(void)
+{
+ m_x += m_w/2;
+ m_y += m_h/2;
+ m_w = FTOM(f_w);
+ m_h = FTOM(f_h);
+ m_x -= m_w/2;
+ m_y -= m_h/2;
+ m_x2 = m_x + m_w;
+ m_y2 = m_y + m_h;
+}
+
+//
+//
+//
+void AM_saveScaleAndLoc(void)
+{
+ old_m_x = m_x;
+ old_m_y = m_y;
+ old_m_w = m_w;
+ old_m_h = m_h;
+}
+
+//
+//
+//
+void AM_restoreScaleAndLoc(void)
+{
+
+ m_w = old_m_w;
+ m_h = old_m_h;
+ if (!followplayer)
+ {
+ m_x = old_m_x;
+ m_y = old_m_y;
+ } else {
+ m_x = plr->mo->x - m_w/2;
+ m_y = plr->mo->y - m_h/2;
+ }
+ m_x2 = m_x + m_w;
+ m_y2 = m_y + m_h;
+
+ // Change the scaling multipliers
+ scale_mtof = FixedDiv(f_w<<FRACBITS, m_w);
+ scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+}
+
+//
+// adds a marker at the current location
+//
+void AM_addMark(void)
+{
+ markpoints[markpointnum].x = m_x + m_w/2;
+ markpoints[markpointnum].y = m_y + m_h/2;
+ markpointnum = (markpointnum + 1) % AM_NUMMARKPOINTS;
+
+}
+
+//
+// Determines bounding box of all vertices,
+// sets global variables controlling zoom range.
+//
+void AM_findMinMaxBoundaries(void)
+{
+ int i;
+ fixed_t a;
+ fixed_t b;
+
+ min_x = min_y = INT_MAX;
+ max_x = max_y = -INT_MAX;
+
+ for (i=0;i<numvertexes;i++)
+ {
+ if (vertexes[i].x < min_x)
+ min_x = vertexes[i].x;
+ else if (vertexes[i].x > max_x)
+ max_x = vertexes[i].x;
+
+ if (vertexes[i].y < min_y)
+ min_y = vertexes[i].y;
+ else if (vertexes[i].y > max_y)
+ max_y = vertexes[i].y;
+ }
+
+ max_w = max_x - min_x;
+ max_h = max_y - min_y;
+
+ min_w = 2*PLAYERRADIUS; // const? never changed?
+ min_h = 2*PLAYERRADIUS;
+
+ a = FixedDiv(f_w<<FRACBITS, max_w);
+ b = FixedDiv(f_h<<FRACBITS, max_h);
+
+ min_scale_mtof = a < b ? a : b;
+ max_scale_mtof = FixedDiv(f_h<<FRACBITS, 2*PLAYERRADIUS);
+
+}
+
+
+//
+//
+//
+void AM_changeWindowLoc(void)
+{
+ if (m_paninc.x || m_paninc.y)
+ {
+ followplayer = 0;
+ f_oldloc.x = INT_MAX;
+ }
+
+ m_x += m_paninc.x;
+ m_y += m_paninc.y;
+
+ if (m_x + m_w/2 > max_x)
+ m_x = max_x - m_w/2;
+ else if (m_x + m_w/2 < min_x)
+ m_x = min_x - m_w/2;
+
+ if (m_y + m_h/2 > max_y)
+ m_y = max_y - m_h/2;
+ else if (m_y + m_h/2 < min_y)
+ m_y = min_y - m_h/2;
+
+ m_x2 = m_x + m_w;
+ m_y2 = m_y + m_h;
+}
+
+
+//
+//
+//
+void AM_initVariables(void)
+{
+ int pnum;
+ static event_t st_notify = { ev_keyup, AM_MSGENTERED, 0, 0 };
+
+ automapactive = true;
+ fb = I_VideoBuffer;
+
+ f_oldloc.x = INT_MAX;
+ amclock = 0;
+ lightlev = 0;
+
+ m_paninc.x = m_paninc.y = 0;
+ ftom_zoommul = FRACUNIT;
+ mtof_zoommul = FRACUNIT;
+
+ m_w = FTOM(f_w);
+ m_h = FTOM(f_h);
+
+ // find player to center on initially
+ if (playeringame[consoleplayer])
+ {
+ plr = &players[consoleplayer];
+ }
+ else
+ {
+ plr = &players[0];
+
+ for (pnum=0;pnum<MAXPLAYERS;pnum++)
+ {
+ if (playeringame[pnum])
+ {
+ plr = &players[pnum];
+ break;
+ }
+ }
+ }
+
+ m_x = plr->mo->x - m_w/2;
+ m_y = plr->mo->y - m_h/2;
+ AM_changeWindowLoc();
+
+ // for saving & restoring
+ old_m_x = m_x;
+ old_m_y = m_y;
+ old_m_w = m_w;
+ old_m_h = m_h;
+
+ // inform the status bar of the change
+ ST_Responder(&st_notify);
+
+}
+
+//
+// AM_loadPics
+//
+// haleyjd 08/27/10: [STRIFE] Changed marknums to PLMNUM%d
+//
+void AM_loadPics(void)
+{
+ int i;
+ char namebuf[9];
+
+ for (i=0;i<10;i++)
+ {
+ DEH_snprintf(namebuf, 9, "PLMNUM%d", i);
+ marknums[i] = W_CacheLumpName(namebuf, PU_STATIC);
+ }
+
+}
+
+void AM_unloadPics(void)
+{
+ int i;
+ char namebuf[9];
+
+ for (i=0;i<10;i++)
+ {
+ DEH_snprintf(namebuf, 9, "PLMNUM%d", i);
+ W_ReleaseLumpName(namebuf);
+ }
+}
+
+void AM_clearMarks(void)
+{
+ int i;
+
+ for (i=0;i<AM_NUMMARKPOINTS;i++)
+ markpoints[i].x = -1; // means empty
+ markpointnum = 0;
+}
+
+//
+// should be called at the start of every level
+// right now, i figure it out myself
+//
+void AM_LevelInit(void)
+{
+ leveljuststarted = 0;
+
+ f_x = f_y = 0;
+ f_w = finit_width;
+ f_h = finit_height;
+
+ AM_clearMarks();
+
+ AM_findMinMaxBoundaries();
+ scale_mtof = FixedDiv(min_scale_mtof, (int) (0.7*FRACUNIT));
+ if (scale_mtof > max_scale_mtof)
+ scale_mtof = min_scale_mtof;
+ scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+}
+
+
+
+
+//
+//
+//
+void AM_Stop (void)
+{
+ static event_t st_notify = { 0, ev_keyup, AM_MSGEXITED, 0 };
+
+ AM_unloadPics();
+ automapactive = false;
+ ST_Responder(&st_notify);
+ stopped = true;
+}
+
+//
+//
+//
+void AM_Start (void)
+{
+ static int lastlevel = -1;
+ //static int lastepisode = -1;
+
+ if (!stopped) AM_Stop();
+ stopped = false;
+ if (lastlevel != gamemap /*|| lastepisode != gameepisode*/)
+ {
+ AM_LevelInit();
+ lastlevel = gamemap;
+ //lastepisode = gameepisode;
+ }
+ AM_initVariables();
+ AM_loadPics();
+}
+
+//
+// set the window scale to the maximum size
+//
+void AM_minOutWindowScale(void)
+{
+ scale_mtof = min_scale_mtof;
+ scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+ AM_activateNewScale();
+}
+
+//
+// set the window scale to the minimum size
+//
+void AM_maxOutWindowScale(void)
+{
+ scale_mtof = max_scale_mtof;
+ scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+ AM_activateNewScale();
+}
+
+
+//
+// Handle events (user inputs) in automap mode
+//
+boolean
+AM_Responder
+( event_t* ev )
+{
+
+ int rc;
+ static int bigstate=0;
+ static char buffer[20];
+ int key;
+
+ rc = false;
+
+ if (!automapactive)
+ {
+ if (ev->type == ev_keydown && ev->data1 == key_map_toggle)
+ {
+ AM_Start ();
+ viewactive = false;
+ rc = true;
+ }
+ }
+ else if (ev->type == ev_keydown)
+ {
+ rc = true;
+ key = ev->data1;
+
+ if (key == key_map_east) // pan right
+ {
+ if (!followplayer) m_paninc.x = FTOM(F_PANINC);
+ else rc = false;
+ }
+ else if (key == key_map_west) // pan left
+ {
+ if (!followplayer) m_paninc.x = -FTOM(F_PANINC);
+ else rc = false;
+ }
+ else if (key == key_map_north) // pan up
+ {
+ if (!followplayer) m_paninc.y = FTOM(F_PANINC);
+ else rc = false;
+ }
+ else if (key == key_map_south) // pan down
+ {
+ if (!followplayer) m_paninc.y = -FTOM(F_PANINC);
+ else rc = false;
+ }
+ else if (key == key_map_zoomout) // zoom out
+ {
+ mtof_zoommul = M_ZOOMOUT;
+ ftom_zoommul = M_ZOOMIN;
+ }
+ else if (key == key_map_zoomin) // zoom in
+ {
+ mtof_zoommul = M_ZOOMIN;
+ ftom_zoommul = M_ZOOMOUT;
+ }
+ else if (key == key_map_toggle)
+ {
+ bigstate = 0;
+ viewactive = true;
+ AM_Stop ();
+ }
+ else if (key == key_map_maxzoom)
+ {
+ bigstate = !bigstate;
+ if (bigstate)
+ {
+ AM_saveScaleAndLoc();
+ AM_minOutWindowScale();
+ }
+ else AM_restoreScaleAndLoc();
+ }
+ else if (key == key_map_follow)
+ {
+ followplayer = !followplayer;
+ f_oldloc.x = INT_MAX;
+ if (followplayer)
+ plr->message = DEH_String(AMSTR_FOLLOWON);
+ else
+ plr->message = DEH_String(AMSTR_FOLLOWOFF);
+ }
+ else if (key == key_map_grid)
+ {
+ grid = !grid;
+ if (grid)
+ plr->message = DEH_String(AMSTR_GRIDON);
+ else
+ plr->message = DEH_String(AMSTR_GRIDOFF);
+ }
+ else if (key == key_map_mark)
+ {
+ sprintf(buffer, "%s %d", DEH_String(AMSTR_MARKEDSPOT), markpointnum);
+ plr->message = buffer;
+ AM_addMark();
+ }
+ else if (key == key_map_clearmark)
+ {
+ AM_clearMarks();
+ plr->message = DEH_String(AMSTR_MARKSCLEARED);
+ }
+ else
+ {
+ rc = false;
+ }
+
+ if (!deathmatch && cht_CheckCheat(&cheat_amap, ev->data2))
+ {
+ rc = false;
+ cheating = (cheating+1) % 3;
+ }
+ }
+ else if (ev->type == ev_keyup)
+ {
+ rc = false;
+ key = ev->data1;
+
+ if (key == key_map_east)
+ {
+ if (!followplayer) m_paninc.x = 0;
+ }
+ else if (key == key_map_west)
+ {
+ if (!followplayer) m_paninc.x = 0;
+ }
+ else if (key == key_map_north)
+ {
+ if (!followplayer) m_paninc.y = 0;
+ }
+ else if (key == key_map_south)
+ {
+ if (!followplayer) m_paninc.y = 0;
+ }
+ else if (key == key_map_zoomout || key == key_map_zoomin)
+ {
+ mtof_zoommul = FRACUNIT;
+ ftom_zoommul = FRACUNIT;
+ }
+ }
+
+ return rc;
+
+}
+
+
+//
+// Zooming
+//
+void AM_changeWindowScale(void)
+{
+
+ // Change the scaling multipliers
+ scale_mtof = FixedMul(scale_mtof, mtof_zoommul);
+ scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+
+ if (scale_mtof < min_scale_mtof)
+ AM_minOutWindowScale();
+ else if (scale_mtof > max_scale_mtof)
+ AM_maxOutWindowScale();
+ else
+ AM_activateNewScale();
+}
+
+
+//
+//
+//
+void AM_doFollowPlayer(void)
+{
+
+ if (f_oldloc.x != plr->mo->x || f_oldloc.y != plr->mo->y)
+ {
+ m_x = FTOM(MTOF(plr->mo->x)) - m_w/2;
+ m_y = FTOM(MTOF(plr->mo->y)) - m_h/2;
+ m_x2 = m_x + m_w;
+ m_y2 = m_y + m_h;
+ f_oldloc.x = plr->mo->x;
+ f_oldloc.y = plr->mo->y;
+
+ // m_x = FTOM(MTOF(plr->mo->x - m_w/2));
+ // m_y = FTOM(MTOF(plr->mo->y - m_h/2));
+ // m_x = plr->mo->x - m_w/2;
+ // m_y = plr->mo->y - m_h/2;
+
+ }
+
+}
+
+//
+//
+//
+void AM_updateLightLev(void)
+{
+ static int nexttic = 0;
+ //static int litelevels[] = { 0, 3, 5, 6, 6, 7, 7, 7 };
+ static int litelevels[] = { 0, 4, 7, 10, 12, 14, 15, 15 };
+ static int litelevelscnt = 0;
+
+ // Change light level
+ if (amclock>nexttic)
+ {
+ lightlev = litelevels[litelevelscnt++];
+ if (litelevelscnt == arrlen(litelevels)) litelevelscnt = 0;
+ nexttic = amclock + 6 - (amclock % 6);
+ }
+
+}
+
+
+//
+// Updates on Game Tick
+//
+void AM_Ticker (void)
+{
+
+ if (!automapactive)
+ return;
+
+ amclock++;
+
+ if (followplayer)
+ AM_doFollowPlayer();
+
+ // Change the zoom if necessary
+ if (ftom_zoommul != FRACUNIT)
+ AM_changeWindowScale();
+
+ // Change x,y location
+ if (m_paninc.x || m_paninc.y)
+ AM_changeWindowLoc();
+
+ // Update light level
+ // AM_updateLightLev();
+
+}
+
+
+//
+// Clear automap frame buffer.
+//
+void AM_clearFB(int color)
+{
+ memset(fb, color, f_w*f_h);
+}
+
+
+//
+// Automap clipping of lines.
+//
+// Based on Cohen-Sutherland clipping algorithm but with a slightly
+// faster reject and precalculated slopes. If the speed is needed,
+// use a hash algorithm to handle the common cases.
+//
+boolean
+AM_clipMline
+( mline_t* ml,
+ fline_t* fl )
+{
+ enum
+ {
+ LEFT =1,
+ RIGHT =2,
+ BOTTOM =4,
+ TOP =8
+ };
+
+ register int outcode1 = 0;
+ register int outcode2 = 0;
+ register int outside;
+
+ fpoint_t tmp;
+ int dx;
+ int dy;
+
+
+#define DOOUTCODE(oc, mx, my) \
+ (oc) = 0; \
+ if ((my) < 0) (oc) |= TOP; \
+ else if ((my) >= f_h) (oc) |= BOTTOM; \
+ if ((mx) < 0) (oc) |= LEFT; \
+ else if ((mx) >= f_w) (oc) |= RIGHT;
+
+
+ // do trivial rejects and outcodes
+ if (ml->a.y > m_y2)
+ outcode1 = TOP;
+ else if (ml->a.y < m_y)
+ outcode1 = BOTTOM;
+
+ if (ml->b.y > m_y2)
+ outcode2 = TOP;
+ else if (ml->b.y < m_y)
+ outcode2 = BOTTOM;
+
+ if (outcode1 & outcode2)
+ return false; // trivially outside
+
+ if (ml->a.x < m_x)
+ outcode1 |= LEFT;
+ else if (ml->a.x > m_x2)
+ outcode1 |= RIGHT;
+
+ if (ml->b.x < m_x)
+ outcode2 |= LEFT;
+ else if (ml->b.x > m_x2)
+ outcode2 |= RIGHT;
+
+ if (outcode1 & outcode2)
+ return false; // trivially outside
+
+ // transform to frame-buffer coordinates.
+ fl->a.x = CXMTOF(ml->a.x);
+ fl->a.y = CYMTOF(ml->a.y);
+ fl->b.x = CXMTOF(ml->b.x);
+ fl->b.y = CYMTOF(ml->b.y);
+
+ DOOUTCODE(outcode1, fl->a.x, fl->a.y);
+ DOOUTCODE(outcode2, fl->b.x, fl->b.y);
+
+ if (outcode1 & outcode2)
+ return false;
+
+ while (outcode1 | outcode2)
+ {
+ // may be partially inside box
+ // find an outside point
+ if (outcode1)
+ outside = outcode1;
+ else
+ outside = outcode2;
+
+ // clip to each side
+ if (outside & TOP)
+ {
+ dy = fl->a.y - fl->b.y;
+ dx = fl->b.x - fl->a.x;
+ tmp.x = fl->a.x + (dx*(fl->a.y))/dy;
+ tmp.y = 0;
+ }
+ else if (outside & BOTTOM)
+ {
+ dy = fl->a.y - fl->b.y;
+ dx = fl->b.x - fl->a.x;
+ tmp.x = fl->a.x + (dx*(fl->a.y-f_h))/dy;
+ tmp.y = f_h-1;
+ }
+ else if (outside & RIGHT)
+ {
+ dy = fl->b.y - fl->a.y;
+ dx = fl->b.x - fl->a.x;
+ tmp.y = fl->a.y + (dy*(f_w-1 - fl->a.x))/dx;
+ tmp.x = f_w-1;
+ }
+ else if (outside & LEFT)
+ {
+ dy = fl->b.y - fl->a.y;
+ dx = fl->b.x - fl->a.x;
+ tmp.y = fl->a.y + (dy*(-fl->a.x))/dx;
+ tmp.x = 0;
+ }
+ else
+ {
+ tmp.x = 0;
+ tmp.y = 0;
+ }
+
+ if (outside == outcode1)
+ {
+ fl->a = tmp;
+ DOOUTCODE(outcode1, fl->a.x, fl->a.y);
+ }
+ else
+ {
+ fl->b = tmp;
+ DOOUTCODE(outcode2, fl->b.x, fl->b.y);
+ }
+
+ if (outcode1 & outcode2)
+ return false; // trivially outside
+ }
+
+ return true;
+}
+#undef DOOUTCODE
+
+
+//
+// Classic Bresenham w/ whatever optimizations needed for speed
+//
+void
+AM_drawFline
+( fline_t* fl,
+ int color )
+{
+ register int x;
+ register int y;
+ register int dx;
+ register int dy;
+ register int sx;
+ register int sy;
+ register int ax;
+ register int ay;
+ register int d;
+
+ static int fuck = 0;
+
+ // For debugging only
+ if ( fl->a.x < 0 || fl->a.x >= f_w
+ || fl->a.y < 0 || fl->a.y >= f_h
+ || fl->b.x < 0 || fl->b.x >= f_w
+ || fl->b.y < 0 || fl->b.y >= f_h)
+ {
+ DEH_fprintf(stderr, "fuck %d \r", fuck++);
+ return;
+ }
+
+#define PUTDOT(xx,yy,cc) fb[(yy)*f_w+(xx)]=(cc)
+
+ dx = fl->b.x - fl->a.x;
+ ax = 2 * (dx<0 ? -dx : dx);
+ sx = dx<0 ? -1 : 1;
+
+ dy = fl->b.y - fl->a.y;
+ ay = 2 * (dy<0 ? -dy : dy);
+ sy = dy<0 ? -1 : 1;
+
+ x = fl->a.x;
+ y = fl->a.y;
+
+ if (ax > ay)
+ {
+ d = ay - ax/2;
+ while (1)
+ {
+ PUTDOT(x,y,color);
+ if (x == fl->b.x) return;
+ if (d>=0)
+ {
+ y += sy;
+ d -= ax;
+ }
+ x += sx;
+ d += ay;
+ }
+ }
+ else
+ {
+ d = ax - ay/2;
+ while (1)
+ {
+ PUTDOT(x, y, color);
+ if (y == fl->b.y) return;
+ if (d >= 0)
+ {
+ x += sx;
+ d -= ay;
+ }
+ y += sy;
+ d += ax;
+ }
+ }
+}
+
+
+//
+// Clip lines, draw visible part sof lines.
+//
+void
+AM_drawMline
+( mline_t* ml,
+ int color )
+{
+ static fline_t fl;
+
+ if (AM_clipMline(ml, &fl))
+ AM_drawFline(&fl, color); // draws it on frame buffer using fb coords
+}
+
+
+
+//
+// Draws flat (floor/ceiling tile) aligned grid lines.
+//
+/*void AM_drawGrid(int color)
+{
+ fixed_t x, y;
+ fixed_t start, end;
+ mline_t ml;
+
+ // Figure out start of vertical gridlines
+ start = m_x;
+ if ((start-bmaporgx)%(MAPBLOCKUNITS<<FRACBITS))
+ start += (MAPBLOCKUNITS<<FRACBITS)
+ - ((start-bmaporgx)%(MAPBLOCKUNITS<<FRACBITS));
+ end = m_x + m_w;
+
+ // draw vertical gridlines
+ ml.a.y = m_y;
+ ml.b.y = m_y+m_h;
+ for (x=start; x<end; x+=(MAPBLOCKUNITS<<FRACBITS))
+ {
+ ml.a.x = x;
+ ml.b.x = x;
+ AM_drawMline(&ml, color);
+ }
+
+ // Figure out start of horizontal gridlines
+ start = m_y;
+ if ((start-bmaporgy)%(MAPBLOCKUNITS<<FRACBITS))
+ start += (MAPBLOCKUNITS<<FRACBITS)
+ - ((start-bmaporgy)%(MAPBLOCKUNITS<<FRACBITS));
+ end = m_y + m_h;
+
+ // draw horizontal gridlines
+ ml.a.x = m_x;
+ ml.b.x = m_x + m_w;
+ for (y=start; y<end; y+=(MAPBLOCKUNITS<<FRACBITS))
+ {
+ ml.a.y = y;
+ ml.b.y = y;
+ AM_drawMline(&ml, color);
+ }
+
+}*/
+
+//
+// Determines visible lines, draws them.
+// This is LineDef based, not LineSeg based.
+//
+void AM_drawWalls(void)
+{
+ int i;
+ line_t* line;
+ static mline_t l;
+
+ for(i = 0; i < numlines; i++)
+ {
+ line = &lines[i];
+
+ l.a.x = line->v1->x;
+ l.a.y = line->v1->y;
+ l.b.x = line->v2->x;
+ l.b.y = line->v2->y;
+
+ if(cheating || (line->flags & ML_MAPPED))
+ {
+ if((line->flags & LINE_NEVERSEE) && !cheating)
+ continue;
+
+ // villsa [STRIFE]
+ if(line->special == 145 || line->special == 186)
+ {
+ AM_drawMline(&l, SPWALLCOLORS);
+ }
+ // villsa [STRIFE] lightlev is unused here
+ else if(!line->backsector)
+ {
+ AM_drawMline(&l, WALLCOLORS);
+ }
+ else
+ {
+ if(line->special == 39)
+ { // teleporters
+ AM_drawMline(&l, WALLCOLORS+WALLRANGE/2);
+ }
+ else if (line->flags & ML_SECRET) // secret door
+ {
+ // villsa [STRIFE] just draw the wall as is!
+ AM_drawMline(&l, WALLCOLORS);
+ }
+ else if(line->backsector->floorheight != line->frontsector->floorheight)
+ {
+ AM_drawMline(&l, FDWALLCOLORS); // floor level change
+ }
+ else if(line->backsector->ceilingheight != line->frontsector->ceilingheight)
+ {
+ AM_drawMline(&l, CDWALLCOLORS); // ceiling level change
+ }
+ else if (cheating)
+ {
+ AM_drawMline(&l, TSWALLCOLORS);
+ }
+ }
+ }
+ // villsa [STRIFE] show all of the map on map 15
+ else if(plr->powers[pw_allmap] || gamemap == 15)
+ {
+ if(!(line->flags & LINE_NEVERSEE))
+ AM_drawMline(&l, CTWALLCOLORS);
+ }
+ }
+}
+
+
+//
+// Rotation in 2D.
+// Used to rotate player arrow line character.
+//
+void
+AM_rotate
+( fixed_t* x,
+ fixed_t* y,
+ angle_t a )
+{
+ fixed_t tmpx;
+
+ tmpx =
+ FixedMul(*x,finecosine[a>>ANGLETOFINESHIFT])
+ - FixedMul(*y,finesine[a>>ANGLETOFINESHIFT]);
+
+ *y =
+ FixedMul(*x,finesine[a>>ANGLETOFINESHIFT])
+ + FixedMul(*y,finecosine[a>>ANGLETOFINESHIFT]);
+
+ *x = tmpx;
+}
+
+void
+AM_drawLineCharacter
+( mline_t* lineguy,
+ int lineguylines,
+ fixed_t scale,
+ angle_t angle,
+ int color,
+ fixed_t x,
+ fixed_t y )
+{
+ int i;
+ mline_t l;
+
+ for (i=0;i<lineguylines;i++)
+ {
+ l.a.x = lineguy[i].a.x;
+ l.a.y = lineguy[i].a.y;
+
+ if (scale)
+ {
+ l.a.x = FixedMul(scale, l.a.x);
+ l.a.y = FixedMul(scale, l.a.y);
+ }
+
+ if (angle)
+ AM_rotate(&l.a.x, &l.a.y, angle);
+
+ l.a.x += x;
+ l.a.y += y;
+
+ l.b.x = lineguy[i].b.x;
+ l.b.y = lineguy[i].b.y;
+
+ if (scale)
+ {
+ l.b.x = FixedMul(scale, l.b.x);
+ l.b.y = FixedMul(scale, l.b.y);
+ }
+
+ if (angle)
+ AM_rotate(&l.b.x, &l.b.y, angle);
+
+ l.b.x += x;
+ l.b.y += y;
+
+ AM_drawMline(&l, color);
+ }
+}
+
+void AM_drawPlayers(void)
+{
+ int i;
+ player_t* p;
+ // villsa [STRIFE] updated array
+ static int their_colors[] = { 0x80, 0x40, 0xB0, 0x10, 0x30, 0x50, 0xA0, 0x60, 0x90 };
+ int their_color = -1;
+ int color;
+
+ if (!netgame)
+ {
+ // villsa [STRIFE] don't draw cheating player arrow.
+ // Player arrow is yellow instead of white
+ AM_drawLineCharacter
+ (player_arrow, arrlen(player_arrow), 0, plr->mo->angle,
+ 224, plr->mo->x, plr->mo->y);
+ return;
+ }
+
+ for(i = 0; i < MAXPLAYERS; i++)
+ {
+ their_color++;
+ p = &players[i];
+
+ // villsa [STRIFE] check for gameskill??
+ if((gameskill && deathmatch && !singledemo) && p != plr)
+ continue;
+
+ if(!playeringame[i])
+ continue;
+
+ // villsa [STRIFE] change to 27
+ if(p->powers[pw_invisibility])
+ color = 27; // *close* to black
+ else
+ color = their_colors[their_color];
+
+ AM_drawLineCharacter
+ (player_arrow, arrlen(player_arrow), 0, p->mo->angle,
+ color, p->mo->x, p->mo->y);
+ }
+
+}
+
+//
+// AM_drawThings
+//
+// villsa [STRIFE] no arguments
+//
+void AM_drawThings(void)
+{
+ int i;
+ mobj_t* t;
+ int colors;
+ fixed_t radius;
+
+ // villsa [STRIFE] almost re-written
+ // specific things can have different radius, color and appearence
+ for(i = 0; i < numsectors; i++)
+ {
+ t = sectors[i].thinglist;
+ while(t)
+ {
+ radius = t->radius;
+
+ if(t->flags & (MF_MISSILE|MF_SPECIAL))
+ {
+ colors = MISSILECOLORS;
+ }
+ else if(t->flags & MF_COUNTKILL)
+ {
+ colors = SHOOTABLECOLORS;
+ }
+ else
+ {
+ colors = THINGCOLORS;
+ radius = (16<<FRACBITS);
+ }
+
+ AM_drawLineCharacter (thintriangle_guy, arrlen(thintriangle_guy),
+ radius, t->angle, colors, t->x, t->y);
+
+ t = t->snext;
+ }
+ }
+}
+
+//
+// AM_drawMarks
+//
+void AM_drawMarks(void)
+{
+ int i, fx, fy, w, h;
+
+ for(i = 0; i < AM_NUMMARKPOINTS; i++)
+ {
+ if(markpoints[i].x != -1)
+ {
+ // w = SHORT(marknums[i]->width);
+ // h = SHORT(marknums[i]->height);
+ w = 5; // because something's wrong with the wad, i guess
+ h = 6; // because something's wrong with the wad, i guess
+ fx = CXMTOF(markpoints[i].x);
+ fy = CYMTOF(markpoints[i].y);
+ if(fx >= f_x && fx <= f_w - w && fy >= f_y && fy <= f_h - h)
+ {
+ // villsa [STRIFE]
+ if(i >= mapmarknum)
+ V_DrawPatch(fx, fy, marknums[i]);
+ }
+ }
+ }
+
+}
+
+// villsa [STRIFE] unused
+/*void AM_drawCrosshair(int color)
+{
+ fb[(f_w*(f_h+1))/2] = color; // single point for now
+}*/
+
+void AM_Drawer (void)
+{
+ if (!automapactive) return;
+
+ AM_clearFB(BACKGROUND);
+
+ // villsa [STRIFE] not used
+ /*if(grid)
+ AM_drawGrid(GRIDCOLORS);*/
+
+ AM_drawWalls();
+ AM_drawPlayers();
+
+ // villsa [STRIFE] draw things when map powerup is enabled
+ if(cheating == 2 || plr->powers[pw_allmap] > 1)
+ AM_drawThings();
+
+ // villsa [STRIFE] not used
+ //AM_drawCrosshair(XHAIRCOLORS);
+
+ AM_drawMarks();
+ V_MarkRect(f_x, f_y, f_w, f_h);
+
+}
diff --git a/src/d_net.h b/src/strife/am_map.h
index e5980a9b..af390d1b 100644
--- a/src/d_net.h
+++ b/src/strife/am_map.h
@@ -20,38 +20,38 @@
// 02111-1307, USA.
//
// DESCRIPTION:
-// Networking stuff.
+// AutoMap module.
//
//-----------------------------------------------------------------------------
+#ifndef __AMMAP_H__
+#define __AMMAP_H__
-#ifndef __D_NET__
-#define __D_NET__
+#include "d_event.h"
+#include "m_cheat.h"
-#include "d_player.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))
-#define MAXNETNODES 8
-// Networking and tick handling related.
-#define BACKUPTICS 128
+// Called by main loop.
+boolean AM_Responder (event_t* ev);
-extern int extratics;
+// Called by main loop.
+void AM_Ticker (void);
-// Create any new ticcmds and broadcast to other players.
-void NetUpdate (void);
+// Called by main loop,
+// called instead of view drawer if automap active.
+void AM_Drawer (void);
-// Broadcasts special packets to other players
-// to notify of game exit
-void D_QuitNetGame (void);
+// Called to force the automap to quit
+// if the level is completed while it is up.
+void AM_Stop (void);
-//? how many ticks to run?
-void TryRunTics (void);
-// Called at start of game loop to initialize timers
-void D_StartGameLoop(void);
+extern cheatseq_t cheat_amap;
-extern boolean drone;
-extern boolean net_cl_new_sync;
#endif
-
diff --git a/src/strife/d_englsh.h b/src/strife/d_englsh.h
new file mode 100644
index 00000000..6d615194
--- /dev/null
+++ b/src/strife/d_englsh.h
@@ -0,0 +1,600 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// 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: Accessing strife.cd\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?"
+// [STRIFE] modified:
+#define LOADNET "you can't load while in a net game!\n\n"PRESSKEY
+#define QLOADNET "you can't quickload during a netgame!\n\n"PRESSKEY
+// [STRIFE] modified:
+#define QSAVESPOT "you haven't picked a\nquicksave slot yet!\n\n"PRESSKEY
+// [STRIFE] modified:
+#define SAVEDEAD "you're not playing a game\n\n"PRESSKEY
+#define QSPROMPT "quicksave over your game named\n\n'%s'?\n\n"PRESSYN
+// [STRIFE] modified:
+#define QLPROMPT "do you want to quickload\n\n'%s'?\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 NETEND "you can't end a netgame!\n\n"PRESSKEY
+#define ENDGAME "are you sure you want\nto end the game?\n\n"PRESSYN
+
+// haleyjd 09/11/10: [STRIFE] No "to dos." on this
+#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]"
+
+// haleyjd 08/31/10: [STRIFE] Strife map names
+
+#define HUSTR_1 "AREA 1: sanctuary"
+#define HUSTR_2 "AREA 2: town"
+#define HUSTR_3 "AREA 3: front base"
+#define HUSTR_4 "AREA 4: power station"
+#define HUSTR_5 "AREA 5: prison"
+#define HUSTR_6 "AREA 6: sewers"
+#define HUSTR_7 "AREA 7: castle"
+#define HUSTR_8 "AREA 8: Audience Chamber"
+#define HUSTR_9 "AREA 9: Castle: Programmer's Keep"
+
+#define HUSTR_10 "AREA 10: New Front Base"
+#define HUSTR_11 "AREA 11: Borderlands"
+#define HUSTR_12 "AREA 12: the temple of the oracle"
+#define HUSTR_13 "AREA 13: Catacombs"
+#define HUSTR_14 "AREA 14: mines"
+#define HUSTR_15 "AREA 15: Fortress: Administration"
+#define HUSTR_16 "AREA 16: Fortress: Bishop's Tower"
+#define HUSTR_17 "AREA 17: Fortress: The Bailey"
+#define HUSTR_18 "AREA 18: Fortress: Stores"
+#define HUSTR_19 "AREA 19: Fortress: Security Complex"
+
+#define HUSTR_20 "AREA 20: Factory: Receiving"
+#define HUSTR_21 "AREA 21: Factory: Manufacturing"
+#define HUSTR_22 "AREA 22: Factory: Forge"
+#define HUSTR_23 "AREA 23: Order Commons"
+#define HUSTR_24 "AREA 24: Factory: Conversion Chapel"
+#define HUSTR_25 "AREA 25: Catacombs: Ruined Temple"
+#define HUSTR_26 "AREA 26: proving grounds"
+#define HUSTR_27 "AREA 27: The Lab"
+#define HUSTR_28 "AREA 28: Alien Ship"
+#define HUSTR_29 "AREA 29: Entity"
+
+#define HUSTR_30 "AREA 30: Abandoned Front Base"
+#define HUSTR_31 "AREA 31: Training Facility"
+
+#define HUSTR_32 "AREA 1: Sanctuary"
+#define HUSTR_33 "AREA 2: Town"
+#define HUSTR_34 "AREA 3: Movement Base"
+
+// haleyjd 20110219: [STRIFE] replaced all with Strife chat macros:
+#define HUSTR_CHATMACRO1 "Fucker!"
+#define HUSTR_CHATMACRO2 "--SPLAT-- Instant wall art."
+#define HUSTR_CHATMACRO3 "That had to hurt!"
+#define HUSTR_CHATMACRO4 "Smackings!"
+#define HUSTR_CHATMACRO5 "Gib-O-Matic baby."
+#define HUSTR_CHATMACRO6 "Burn! Yah! Yah!"
+#define HUSTR_CHATMACRO7 "Buh-Bye!"
+#define HUSTR_CHATMACRO8 "Sizzle chest!"
+#define HUSTR_CHATMACRO9 "That sucked!"
+#define HUSTR_CHATMACRO0 "Mommy?"
+
+#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 "You're Invincible!" // [STRIFE]
+#define STSTR_DQDOFF "You're a looney!" // [STRIFE]
+
+#define STSTR_KFAADDED "Very Happy Ammo Added"
+#define STSTR_FAADDED "Ammo Added" // [STRIFE]
+
+#define STSTR_NCON "No Clipping Mode ON"
+#define STSTR_NCOFF "No Clipping Mode OFF"
+
+#define STSTR_BEHOLD "Bzrk, Inviso, Mask, Health, Pack, Stats" // [STRIFE]
+#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
diff --git a/src/strife/d_items.c b/src/strife/d_items.c
new file mode 100644
index 00000000..66bec442
--- /dev/null
+++ b/src/strife/d_items.c
@@ -0,0 +1,167 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+//
+//-----------------------------------------------------------------------------
+
+
+// We are referring to sprite numbers.
+#include "info.h"
+
+#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
+//
+
+// villsa [STRIFE]
+weaponinfo_t weaponinfo[NUMWEAPONS] =
+{
+ {
+ // fist
+ am_noammo,
+ S_PNCH_03,
+ S_PNCH_02,
+ S_PNCH_01,
+ S_PNCH_04,
+ S_NULL,
+ 1
+ },
+ {
+ // electric bow
+ am_elecbolts,
+ S_XBOW_02,
+ S_XBOW_01,
+ S_XBOW_00,
+ S_XBOW_03,
+ S_NULL,
+ 1
+ },
+ {
+ // rifle
+ am_bullets,
+ S_RIFG_02,
+ S_RIFG_01,
+ S_RIFG_00,
+ S_RIFF_00,
+ S_NULL,
+ 1
+ },
+ {
+ // missile launcher
+ am_missiles,
+ S_MMIS_02,
+ S_MMIS_01,
+ S_MMIS_00,
+ S_MMIS_03,
+ S_NULL,
+ 0
+ },
+ {
+ // grenade launcher
+ am_hegrenades,
+ S_GREN_02,
+ S_GREN_01,
+ S_GREN_00,
+ S_GREN_03,
+ S_GREF_00,
+ 0
+ },
+ {
+ // flame thrower
+ am_cell,
+ S_FLMT_03,
+ S_FLMT_02,
+ S_FLMT_00,
+ S_FLMF_00,
+ S_NULL,
+ 1
+ },
+ {
+ // mauler
+ am_cell,
+ S_BLST_05,
+ S_BLST_04,
+ S_BLST_00,
+ S_BLSF_00,
+ S_NULL,
+ 0
+ },
+ {
+ // sigil
+ am_noammo,
+ S_SIGH_06,
+ S_SIGH_05,
+ S_SIGH_00,
+ S_SIGH_07,
+ S_SIGF_00,
+ 0
+ },
+ {
+ // poison bow
+ am_poisonbolts,
+ S_XBOW_15,
+ S_XBOW_14,
+ S_XBOW_13,
+ S_XBOW_16,
+ S_NULL,
+ 1
+ },
+ {
+ // wp grenade launcher
+ am_wpgrenades,
+ S_GREN_10,
+ S_GREN_09,
+ S_GREN_08,
+ S_GREN_11,
+ S_GREF_03,
+ 0
+ },
+ {
+ // torpedo
+ am_cell,
+ S_BLST_18,
+ S_BLST_17,
+ S_BLST_13,
+ S_BLST_19,
+ S_NULL,
+ 0
+ },
+};
+
+
+
+
+
+
+
+
diff --git a/src/strife/d_items.h b/src/strife/d_items.h
new file mode 100644
index 00000000..91731982
--- /dev/null
+++ b/src/strife/d_items.h
@@ -0,0 +1,50 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// 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;
+ boolean availabledemo; // villsa [STRIFE]
+
+} weaponinfo_t;
+
+extern weaponinfo_t weaponinfo[NUMWEAPONS];
+
+#endif
diff --git a/src/strife/d_main.c b/src/strife/d_main.c
new file mode 100644
index 00000000..ad69f1d4
--- /dev/null
+++ b/src/strife/d_main.c
@@ -0,0 +1,2000 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// DOOM main program (D_DoomMain) and game loop (D_DoomLoop),
+// plus functions to determine game mode (shareware, registered),
+// parse command line parameters, configure game parameters (turbo),
+// and call the startup functions.
+//
+//-----------------------------------------------------------------------------
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+#include "deh_main.h"
+#include "doomdef.h"
+#include "doomstat.h"
+
+#include "dstrings.h"
+#include "doomfeatures.h"
+#include "sounds.h"
+
+#include "d_iwad.h"
+
+#include "z_zone.h"
+#include "w_main.h"
+#include "w_wad.h"
+#include "s_sound.h"
+#include "v_video.h"
+
+#include "f_finale.h"
+#include "f_wipe.h"
+
+#include "m_argv.h"
+#include "m_config.h"
+#include "m_controls.h"
+#include "m_misc.h"
+#include "m_menu.h"
+#include "m_saves.h" // haleyjd [STRIFE]
+#include "p_saveg.h"
+#include "p_dialog.h" // haleyjd [STRIFE]
+
+#include "i_endoom.h"
+#include "i_joystick.h"
+#include "i_system.h"
+#include "i_timer.h"
+#include "i_video.h"
+#include "i_swap.h"
+
+#include "g_game.h"
+
+#include "hu_stuff.h"
+#include "wi_stuff.h"
+#include "st_stuff.h"
+#include "am_map.h"
+#include "net_client.h"
+#include "net_dedicated.h"
+#include "net_query.h"
+
+#include "p_setup.h"
+#include "r_local.h"
+
+#include "d_main.h"
+
+// Size of startup splash screen window.
+
+#define INTRO_SCREEN_W 640
+#define INTRO_SCREEN_H 480
+
+//
+// D-DoomLoop()
+// Not a globally visible function,
+// just included for source reference,
+// called by D_DoomMain, never exits.
+// Manages timing and IO,
+// calls all ?_Responder, ?_Ticker, and ?_Drawer,
+// calls I_GetTime, I_StartFrame, and I_StartTic
+//
+void D_DoomLoop (void);
+
+static boolean D_AddFile(char *filename);
+
+// Location where savegames are stored
+
+char * savegamedir;
+
+// location of IWAD and WAD files
+
+char * iwadfile;
+
+
+boolean devparm; // started game with -devparm
+boolean nomonsters; // checkparm of -nomonsters
+boolean respawnparm; // checkparm of -respawn
+boolean fastparm; // checkparm of -fast
+boolean flipparm; // [STRIFE] haleyjd 20110629: checkparm of -flip
+
+boolean showintro = true; // [STRIFE] checkparm of -nograph, disables intro
+
+
+//extern int soundVolume;
+//extern int sfxVolume;
+//extern int musicVolume;
+
+extern boolean inhelpscreens;
+
+skill_t startskill;
+int startepisode;
+int startmap;
+boolean autostart;
+int startloadgame;
+
+boolean advancedemo;
+
+// villsa [STRIFE] workparm variable (similar to devparm?)
+boolean workparm = false;
+
+// villsa [STRIFE] stonecold cheat variable
+boolean stonecold = false;
+
+// haleyjd 09/11/10: [STRIFE] Game type variables
+boolean isregistered;
+boolean isdemoversion;
+
+// Store demo, do not accept any inputs
+// haleyjd [STRIFE] Unused.
+//boolean storedemo;
+
+
+char wadfile[1024]; // primary wad file
+char mapdir[1024]; // directory of development maps
+
+int show_endoom = 1;
+int graphical_startup = 1;
+
+// fraggle 06/03/11 [STRIFE]: Unused config variable, preserved
+// for compatibility:
+
+static int comport = 0;
+
+// fraggle 06/03/11 [STRIFE]: Multiplayer nickname?
+
+static char *nickname = NULL;
+
+void D_CheckNetGame (void);
+
+
+//
+// D_ProcessEvents
+// Send all the events of the given timestamp down the responder chain
+//
+void D_ProcessEvents (void)
+{
+ event_t* ev;
+
+ // haleyjd 08/22/2010: [STRIFE] there is no such thing as a "store demo"
+ // version of Strife
+
+ // IF STORE DEMO, DO NOT ACCEPT INPUT
+ //if (storedemo)
+ // return;
+
+ while ((ev = D_PopEvent()) != NULL)
+ {
+ if (M_Responder (ev))
+ continue; // menu ate the event
+ G_Responder (ev);
+ }
+}
+
+
+
+
+//
+// D_Display
+// draw current display, possibly wiping it from the previous
+//
+// wipegamestate can be set to -1 to force a wipe on the next draw
+//
+// haleyjd 08/23/10: [STRIFE]:
+// * Changes to eliminate intermission and change timing of screenwipe
+// * 20100901: Added ST_DrawExternal and popupactivestate static variable
+// * 20110206: Start wipegamestate at GS_UNKNOWN (STRIFE-TODO: rename?)
+//
+gamestate_t wipegamestate = GS_UNKNOWN;
+extern boolean setsizeneeded;
+//extern int showMessages; [STRIFE] no such variable
+void R_ExecuteSetViewSize (void);
+
+void D_Display (void)
+{
+ static boolean viewactivestate = false;
+ static boolean menuactivestate = false;
+ static boolean inhelpscreensstate = false;
+ static boolean popupactivestate = false; // [STRIFE]
+ static boolean fullscreen = false;
+ static gamestate_t oldgamestate = -1;
+ static int borderdrawcount;
+ int nowtime;
+ int tics;
+ int wipestart;
+ int y;
+ boolean done;
+ boolean wipe;
+ boolean redrawsbar;
+
+ if (nodrawers)
+ return; // for comparative timing / profiling
+
+ redrawsbar = false;
+
+ // change the view size if needed
+ if (setsizeneeded)
+ {
+ R_ExecuteSetViewSize ();
+ oldgamestate = -1; // force background redraw
+ borderdrawcount = 3;
+ }
+
+ // save the current screen if about to wipe
+ if (gamestate != wipegamestate)
+ {
+ wipe = true;
+ wipe_StartScreen(0, 0, SCREENWIDTH, SCREENHEIGHT);
+ }
+ else
+ wipe = false;
+
+ if (gamestate == GS_LEVEL && gametic)
+ HU_Erase();
+
+ // do buffered drawing
+ switch (gamestate)
+ {
+ case GS_LEVEL:
+ if (!gametic)
+ break;
+ if (automapactive)
+ AM_Drawer ();
+ if (wipe || (viewheight != 200 && fullscreen) )
+ redrawsbar = true;
+ // haleyjd 08/29/10: [STRIFE] Always redraw sbar if menu is/was active
+ if (menuactivestate || (inhelpscreensstate && !inhelpscreens))
+ redrawsbar = true; // just put away the help screen
+ ST_Drawer (viewheight == 200, redrawsbar );
+ fullscreen = viewheight == 200;
+ break;
+
+ // haleyjd 08/23/2010: [STRIFE] No intermission
+ /*
+ case GS_INTERMISSION:
+ WI_Drawer ();
+ break;
+ */
+
+ case GS_FINALE:
+ F_Drawer ();
+ break;
+
+ case GS_DEMOSCREEN:
+ D_PageDrawer ();
+ break;
+
+ default:
+ break;
+ }
+
+ // draw buffered stuff to screen
+ I_UpdateNoBlit ();
+
+ // draw the view directly
+ if (gamestate == GS_LEVEL && !automapactive && gametic)
+ R_RenderPlayerView (&players[displayplayer]);
+
+ // clean up border stuff
+ if (gamestate != oldgamestate && gamestate != GS_LEVEL)
+ I_SetPalette (W_CacheLumpName (DEH_String("PLAYPAL"),PU_CACHE));
+
+ // see if the border needs to be initially drawn
+ if (gamestate == GS_LEVEL && oldgamestate != GS_LEVEL)
+ {
+ viewactivestate = false; // view was not active
+ R_FillBackScreen (); // draw the pattern into the back screen
+ }
+
+ // see if the border needs to be updated to the screen
+ if (gamestate == GS_LEVEL && !automapactive && scaledviewwidth != 320)
+ {
+ if (menuactive || menuactivestate || !viewactivestate)
+ {
+ borderdrawcount = 3;
+ popupactivestate = false;
+ }
+ if (borderdrawcount)
+ {
+ R_DrawViewBorder (); // erase old menu stuff
+ borderdrawcount--;
+ }
+
+ }
+
+ if (testcontrols)
+ {
+ // Box showing current mouse speed
+
+ V_DrawMouseSpeedBox(testcontrols_mousespeed);
+ }
+
+ menuactivestate = menuactive;
+ viewactivestate = viewactive;
+ inhelpscreensstate = inhelpscreens;
+ oldgamestate = wipegamestate = gamestate;
+
+ // haleyjd 20120208: [STRIFE] Rogue moved this down to below border drawing
+ if (gamestate == GS_LEVEL && gametic)
+ {
+ HU_Drawer ();
+ if(ST_DrawExternal())
+ popupactivestate = true;
+ else if(popupactivestate)
+ {
+ popupactivestate = false;
+ menuactivestate = 1;
+ }
+ }
+
+ // draw pause pic
+ if (paused)
+ {
+ if (automapactive)
+ y = 4;
+ else
+ y = viewwindowy+4;
+ V_DrawPatchDirect(viewwindowx + (scaledviewwidth - 68) / 2, y,
+ W_CacheLumpName (DEH_String("M_PAUSE"), PU_CACHE));
+ }
+
+
+ // menus go directly to the screen
+ M_Drawer (); // menu is drawn even on top of everything
+ NetUpdate (); // send out any new accumulation
+
+
+ // normal update
+ if (!wipe)
+ {
+ I_FinishUpdate (); // page flip or blit buffer
+ return;
+ }
+
+ // wipe update
+ wipe_EndScreen(0, 0, SCREENWIDTH, SCREENHEIGHT);
+
+ wipestart = I_GetTime () - 1;
+
+ do
+ {
+ do
+ {
+ nowtime = I_GetTime ();
+ tics = nowtime - wipestart;
+ I_Sleep(1);
+ } while (tics < 3); // haleyjd 08/23/2010: [STRIFE] Changed from == 0 to < 3
+
+ // haleyjd 08/26/10: [STRIFE] Changed to use ColorXForm wipe.
+ wipestart = nowtime;
+ done = wipe_ScreenWipe(wipe_ColorXForm
+ , 0, 0, SCREENWIDTH, SCREENHEIGHT, tics);
+ I_UpdateNoBlit ();
+ M_Drawer (); // menu is drawn even on top of wipes
+ I_FinishUpdate (); // page flip or blit buffer
+ } while (!done);
+}
+
+//
+// Add configuration file variable bindings.
+//
+
+void D_BindVariables(void)
+{
+ int i;
+
+ M_ApplyPlatformDefaults();
+
+ I_BindVideoVariables();
+ I_BindJoystickVariables();
+ I_BindSoundVariables();
+
+ M_BindBaseControls();
+ M_BindWeaponControls();
+ M_BindMapControls();
+ M_BindMenuControls();
+ M_BindStrifeControls(); // haleyjd 09/01/10: [STRIFE]
+ M_BindChatControls(MAXPLAYERS);
+
+ key_multi_msgplayer[0] = HUSTR_KEYGREEN;
+ key_multi_msgplayer[1] = HUSTR_KEYINDIGO;
+ key_multi_msgplayer[2] = HUSTR_KEYBROWN;
+ key_multi_msgplayer[3] = HUSTR_KEYRED;
+
+#ifdef FEATURE_MULTIPLAYER
+ NET_BindVariables();
+#endif
+
+ // haleyjd 08/29/10: [STRIFE]
+ // * Added voice volume
+ // * Added back flat
+ // * Removed show_messages
+ // * Added show_talk
+ // fraggle 03/06/10: [STRIFE]
+ // * Removed detailLevel
+ // * screenblocks -> screensize
+ // * Added nickname, comport
+
+ M_BindVariable("mouse_sensitivity", &mouseSensitivity);
+ M_BindVariable("sfx_volume", &sfxVolume);
+ M_BindVariable("music_volume", &musicVolume);
+ M_BindVariable("voice_volume", &voiceVolume);
+ M_BindVariable("show_talk", &dialogshowtext);
+ M_BindVariable("screensize", &screenblocks);
+ M_BindVariable("snd_channels", &snd_channels);
+ M_BindVariable("vanilla_savegame_limit", &vanilla_savegame_limit);
+ M_BindVariable("vanilla_demo_limit", &vanilla_demo_limit);
+ M_BindVariable("show_endoom", &show_endoom);
+ M_BindVariable("back_flat", &back_flat);
+ M_BindVariable("graphical_startup", &graphical_startup);
+
+ M_BindVariable("nickname", &nickname);
+ M_BindVariable("comport", &comport);
+
+ // Multiplayer chat macros
+
+ for (i=0; i<10; ++i)
+ {
+ char buf[12];
+
+ sprintf(buf, "chatmacro%i", i);
+ M_BindVariable(buf, &chat_macros[i]);
+ }
+}
+
+//
+// D_GrabMouseCallback
+//
+// Called to determine whether to grab the mouse pointer
+//
+
+boolean D_GrabMouseCallback(void)
+{
+ // Drone players don't need mouse focus
+
+ if (drone)
+ return false;
+
+ // when menu is active or game is paused, release the mouse
+
+ if (menuactive || paused)
+ return false;
+
+ // only grab mouse when playing levels (but not demos)
+
+ return (gamestate == GS_LEVEL) && !demoplayback;
+}
+
+//
+// D_DoomLoop
+//
+// haleyjd 08/23/10: [STRIFE] Verified unmodified.
+//
+void D_DoomLoop (void)
+{
+ if (demorecording)
+ G_BeginRecording ();
+
+ TryRunTics();
+
+ I_SetWindowTitle(gamedescription);
+ I_InitGraphics();
+
+ I_EnableLoadingDisk();
+ I_SetGrabMouseCallback(D_GrabMouseCallback);
+
+ V_RestoreBuffer();
+ R_ExecuteSetViewSize();
+
+ D_StartGameLoop();
+
+ if (testcontrols)
+ {
+ wipegamestate = gamestate;
+ }
+
+ while (1)
+ {
+ // frame syncronous IO operations
+ I_StartFrame ();
+
+ // process one or more tics
+ TryRunTics (); // will run at least one tic
+
+ S_UpdateSounds (players[consoleplayer].mo);// move positional sounds
+
+ // Update display, next frame, with current state.
+ if (screenvisible)
+ D_Display ();
+ }
+}
+
+
+
+//
+// DEMO LOOP
+//
+int demosequence;
+int pagetic;
+char *pagename;
+
+
+//
+// D_PageTicker
+// Handles timing for warped projection
+//
+// haleyjd 08/22/2010: [STRIFE] verified unmodified
+//
+void D_PageTicker (void)
+{
+ if (--pagetic < 0)
+ D_AdvanceDemo ();
+}
+
+
+
+//
+// D_PageDrawer
+//
+// haleyjd 08/22/2010: [STRIFE] verified unmodified
+//
+void D_PageDrawer (void)
+{
+ V_DrawPatch (0, 0, W_CacheLumpName(pagename, PU_CACHE));
+}
+
+
+//
+// D_AdvanceDemo
+// Called after each demo or intro demosequence finishes
+//
+// haleyjd 08/22/2010: [STRIFE] verified unmodified
+//
+void D_AdvanceDemo (void)
+{
+ advancedemo = true;
+}
+
+
+//
+// This cycles through the demo sequences.
+// FIXME - version dependend demo numbers?
+//
+// [STRIFE] Modified for the opening slideshow and the exit screen
+//
+void D_DoAdvanceDemo (void)
+{
+ players[consoleplayer].playerstate = PST_LIVE; // not reborn
+ advancedemo = false;
+ usergame = false; // no save / end game here
+ paused = false;
+ gameaction = ga_nothing;
+
+ // villsa 09/12/10: [STRIFE] converted pagetics to ticrate
+ switch (demosequence)
+ {
+ case -5: // exit the game
+ I_Quit();
+ return;
+ case -4: // show exit screen
+ menuactive = false;
+ pagetic = 3*TICRATE;
+ gamestate = GS_DEMOSCREEN;
+ pagename = DEH_String("PANEL7");
+ S_StartMusic(mus_fast);
+ if(isdemoversion)
+ demosequence = -3; // show Velocity logo
+ else
+ demosequence = -5; // exit
+ return;
+ case -3: // show Velocity logo for demo version
+ pagetic = 6*TICRATE;
+ gamestate = GS_DEMOSCREEN;
+ pagename = DEH_String("vellogo");
+ demosequence = -5; // exit
+ return;
+ case -2: // title screen
+ pagetic = 6*TICRATE;
+ gamestate = GS_DEMOSCREEN;
+ pagename = DEH_String("TITLEPIC");
+ S_StartMusic(mus_logo);
+ demosequence = -1; // start intro cinematic
+ return;
+ case -1: // start of intro cinematic
+ pagetic = 10;
+ gamestate = GS_DEMOSCREEN;
+ pagename = DEH_String("PANEL0");
+ S_StartSound(NULL, sfx_rb2act);
+ wipegamestate = -1;
+ break;
+ case 0: // Rogue logo
+ pagetic = 4*TICRATE;
+ gamestate = GS_DEMOSCREEN;
+ pagename = DEH_String("RGELOGO");
+ wipegamestate = -1;
+ break;
+ case 1:
+ pagetic = 7*TICRATE; // The comet struck our planet without
+ gamestate = GS_DEMOSCREEN; // warning.We lost our paradise in a
+ pagename = DEH_String("PANEL1"); // single, violent stroke.
+ I_StartVoice(DEH_String("pro1"));
+ S_StartMusic(mus_intro);
+ break;
+ case 2:
+ pagetic = 9*TICRATE; // The impact released a virus which
+ gamestate = GS_DEMOSCREEN; // swept through the land and killed
+ pagename = DEH_String("PANEL2"); // millions. They turned out to be
+ I_StartVoice(DEH_String("pro2")); // the lucky ones...
+ break;
+ case 3:
+ pagetic = 12*TICRATE; // For those that did not die became
+ gamestate = GS_DEMOSCREEN; // mutations of humanity. Some became
+ pagename = DEH_String("PANEL3"); // fanatics who heard the voice of a
+ I_StartVoice(DEH_String("pro3")); // malignant God in their heads, and
+ break; // called themselves the Order.
+ case 4:
+ pagetic = 11*TICRATE; // Those of us who were deaf to this
+ pagename = DEH_String("PANEL4"); // voice suffer horribly and are
+ gamestate = GS_DEMOSCREEN; // forced to serve these ruthless
+ I_StartVoice(DEH_String("pro4")); // psychotics, who wield weapons more
+ break; // powerful than anything we can muster.
+ case 5:
+ pagetic = 10*TICRATE; // They destroy our women and children,
+ gamestate = GS_DEMOSCREEN; // so that we must hide them underground,
+ pagename = DEH_String("PANEL5"); // and live like animals in constant
+ I_StartVoice(DEH_String("pro5")); // fear for our lives.
+ break;
+ case 6: // But there are whispers of discontent.
+ pagetic = 16*TICRATE; // If we organize, can we defeat our
+ gamestate = GS_DEMOSCREEN; // masters? Weapons are being stolen,
+ pagename = DEH_String("PANEL6"); // soldiers are being trained. A
+ I_StartVoice(DEH_String("pro6")); // Movement is born! Born of lifelong
+ break; // STRIFE!
+ case 7: // titlepic again - unused...
+ pagetic = 9*TICRATE;
+ gamestate = GS_DEMOSCREEN;
+ pagename = DEH_String("TITLEPIC");
+ wipegamestate = -1;
+ break;
+ case 8: // demo
+ ClearTmp();
+ pagetic = 9*TICRATE;
+ G_DeferedPlayDemo(DEH_String("demo1"));
+ break;
+ case 9: // velocity logo? - unused...
+ pagetic = 6*TICRATE;
+ gamestate = GS_DEMOSCREEN;
+ pagename = DEH_String("vellogo");
+ wipegamestate = -1;
+ break;
+ case 10: // credits
+ gamestate = GS_DEMOSCREEN;
+ pagetic = 12*TICRATE;
+ pagename = DEH_String("CREDIT");
+ wipegamestate = -1;
+ break;
+ default:
+ break;
+ }
+
+ ++demosequence;
+
+ if(demosequence > 11)
+ demosequence = -2;
+ if(demosequence == 7 || demosequence == 9)
+ ++demosequence;
+}
+
+
+
+//
+// D_StartTitle
+//
+// [STRIFE]
+// haleyjd 09/11/10: Small modifications for new demo sequence.
+//
+void D_StartTitle (void)
+{
+ gamestate = GS_DEMOSCREEN;
+ gameaction = ga_nothing;
+ demosequence = -2;
+ D_AdvanceDemo ();
+}
+
+//
+// D_QuitGame
+//
+// [STRIFE] New function
+// haleyjd 09/11/10: Sets up the quit game snippet powered by the
+// demo sequence.
+//
+void D_QuitGame(void)
+{
+ gameaction = ga_nothing;
+ demosequence = -4;
+ D_AdvanceDemo();
+}
+
+// Strings for dehacked replacements of the startup banner
+//
+// These are from the original source: some of them are perhaps
+// not used in any dehacked patches
+
+static char *banners[] =
+{
+ // strife1.wad:
+
+ " "
+ "STRIFE: Quest for the Sigil v1.2"
+ " "
+};
+
+//
+// Get game name: if the startup banner has been replaced, use that.
+// Otherwise, use the name given
+//
+
+static char *GetGameName(char *gamename)
+{
+ size_t i;
+ char *deh_sub;
+
+ for (i=0; i<arrlen(banners); ++i)
+ {
+ // Has the banner been replaced?
+
+ deh_sub = DEH_String(banners[i]);
+
+ if (deh_sub != banners[i])
+ {
+ // Has been replaced
+ // We need to expand via printf to include the Doom version
+ // number
+ // We also need to cut off spaces to get the basic name
+
+ gamename = Z_Malloc(strlen(deh_sub) + 10, PU_STATIC, 0);
+ sprintf(gamename, deh_sub, STRIFE_VERSION / 100, STRIFE_VERSION % 100);
+
+ while (gamename[0] != '\0' && isspace(gamename[0]))
+ strcpy(gamename, gamename+1);
+
+ while (gamename[0] != '\0' && isspace(gamename[strlen(gamename)-1]))
+ gamename[strlen(gamename) - 1] = '\0';
+
+ return gamename;
+ }
+ }
+
+ return gamename;
+}
+
+//
+// Find out what version of Doom is playing.
+//
+
+void D_IdentifyVersion(void)
+{
+ // gamemission is set up by the D_FindIWAD function. But if
+ // we specify '-iwad', we have to identify using
+ // IdentifyIWADByName. However, if the iwad does not match
+ // any known IWAD name, we may have a dilemma. Try to
+ // identify by its contents.
+
+ // STRIFE-TODO: some elaborate checks? for now we assume...
+ // The logic in strife1.exe is simple:
+ // * if strife1.wad is found, set isregistered = true
+ // * if strife0.wad is found, set isdemoversion = true
+
+ // Make sure gamemode is set up correctly
+ gamemode = commercial;
+ gamemission = strife;
+ isregistered = true;
+
+ // Load voices.wad
+ if(isregistered)
+ {
+ char *name = D_FindWADByName("voices.wad");
+
+ if(!name) // not found?
+ {
+ int p;
+
+ // haleyjd STRIFE-FIXME: Temporary?
+ // If -iwad was used, check and see if voices.wad exists on the
+ // same filepath.
+ if((p = M_CheckParm("-iwad")) && p < myargc - 1)
+ {
+ char *iwad = myargv[p + 1];
+ size_t len = strlen(iwad) + 24;
+ char *filename = malloc(len);
+ char sepchar;
+
+ // how the heck is Choco surviving without this routine?
+ sepchar = M_GetFilePath(iwad, filename, len);
+ filename[strlen(filename)] = sepchar;
+ strcat(filename, "voices.wad");
+
+ if(!M_FileExists(filename))
+ disable_voices = 1;
+ else
+ name = filename; // STRIFE-FIXME: memory leak!!
+ }
+ else
+ disable_voices = 1;
+ }
+
+ if(disable_voices) // voices disabled?
+ {
+ if(devparm)
+ printf("Voices disabled\n");
+ return;
+ }
+
+ D_AddFile(name);
+ }
+}
+
+#if 0
+//
+// DoTimeBomb
+//
+// haleyjd 08/23/2010: [STRIFE] New function
+// Code with no xrefs; probably left over from a private alpha or beta.
+// Translated here because it explains what the SERIAL lump was meant to do.
+//
+void DoTimeBomb(void)
+{
+ dosdate_t date;
+ char *serial;
+ int serialnum;
+ int serial_year;
+ int serial_month;
+
+ serial = W_CacheLumpName("serial", PU_CACHE);
+ serialnum = atoi(serial);
+
+ // Rogue, much like Governor Mourel, were lousy liars. These deceptive
+ // error messages are pretty low :P
+ dos_getdate(&date);
+ if(date.year > 1996 || date.day > 15 && date.month > 4)
+ I_Error("Data error! Corrupted WAD File!");
+ serial_year = serialnum / 10000;
+ serial_month = serialnum / 100 - 100 * serial_year;
+ if(date.year < serial_year ||
+ date.day < serialnum - 100 * serial_month - 10000 * serial_year &&
+ date.month < serial_month)
+ I_Error("Bad wadfile");
+}
+#endif
+
+// Set the gamedescription string
+
+void D_SetGameDescription(void)
+{
+ gamedescription = GetGameName("Strife: Quest for the Sigil");
+}
+
+// print title for every printed line
+char title[128];
+
+static boolean D_AddFile(char *filename)
+{
+ wad_file_t *handle;
+
+ printf(" adding %s\n", filename);
+ handle = W_AddFile(filename);
+
+ return handle != NULL;
+}
+
+// Copyright message banners
+// Some dehacked mods replace these. These are only displayed if they are
+// replaced by dehacked.
+// haleyjd 08/22/2010: [STRIFE] altered to match strings from binary
+static char *copyright_banners[] =
+{
+ "===========================================================================\n"
+ "ATTENTION: This version of STRIFE has extra files added to it.\n"
+ " You will not receive technical support for modified games.\n"
+ "===========================================================================\n",
+
+ "===========================================================================\n"
+ " This version is NOT SHAREWARE, do not distribute!\n"
+ " Please report software piracy to the SPA: 1-800-388-PIR8\n"
+ "===========================================================================\n",
+
+ "===========================================================================\n"
+ " Shareware!\n"
+ "===========================================================================\n"
+};
+
+// Prints a message only if it has been modified by dehacked.
+
+void PrintDehackedBanners(void)
+{
+ size_t i;
+
+ for (i=0; i<arrlen(copyright_banners); ++i)
+ {
+ char *deh_s;
+
+ deh_s = DEH_String(copyright_banners[i]);
+
+ if (deh_s != copyright_banners[i])
+ {
+ printf("%s", deh_s);
+
+ // Make sure the modified banner always ends in a newline character.
+ // If it doesn't, add a newline. This fixes av.wad.
+
+ if (deh_s[strlen(deh_s) - 1] != '\n')
+ {
+ printf("\n");
+ }
+ }
+ }
+}
+
+static struct
+{
+ char *description;
+ char *cmdline;
+ GameVersion_t version;
+} gameversions[] = {
+ { "Strife 1.2", "1.2", exe_strife_1_2 },
+ { "Strife 1.31", "1.31", exe_strife_1_31 },
+ { NULL, NULL, 0 }
+};
+
+// Initialize the game version
+
+static void InitGameVersion(void)
+{
+ int p;
+ int i;
+
+ // haleyjd: we support emulating either the 1.2 or the 1.31 versions of
+ // Strife, which are the most significant. 1.2 is the most mature version
+ // that still has the single saveslot restriction, whereas 1.31 is the
+ // final revision. The differences between the two are barely worth
+ // mentioning aside from that main one.
+
+ //!
+ // @arg <version>
+ // @category compat
+ //
+ // Emulate a specific version of Doom. Valid values are "1.2" and "1.31".
+ //
+
+ p = M_CheckParmWithArgs("-gameversion", 1);
+
+ if (p)
+ {
+ for (i=0; gameversions[i].description != NULL; ++i)
+ {
+ if (!strcmp(myargv[p+1], gameversions[i].cmdline))
+ {
+ gameversion = gameversions[i].version;
+ break;
+ }
+ }
+
+ if (gameversions[i].description == NULL)
+ {
+ printf("Supported game versions:\n");
+
+ for (i=0; gameversions[i].description != NULL; ++i)
+ {
+ printf("\t%s (%s)\n", gameversions[i].cmdline,
+ gameversions[i].description);
+ }
+
+ I_Error("Unknown game version '%s'", myargv[p+1]);
+ }
+ }
+ else
+ {
+ gameversion = exe_strife_1_31;
+ }
+}
+
+void PrintGameVersion(void)
+{
+ int i;
+
+ for (i=0; gameversions[i].description != NULL; ++i)
+ {
+ if (gameversions[i].version == gameversion)
+ {
+ printf("Emulating the behavior of the "
+ "'%s' executable.\n", gameversions[i].description);
+ break;
+ }
+ }
+}
+
+// Function called at exit to display the ENDOOM screen
+
+static void D_Endoom(void)
+{
+ byte *endoom;
+
+ // Don't show ENDOOM if we have it disabled, or we're running
+ // in screensaver or control test mode.
+
+ if (!show_endoom || screensaver_mode || testcontrols)
+ {
+ return;
+ }
+
+ // haleyjd 08/27/10: [STRIFE] ENDOOM -> ENDSTRF
+ endoom = W_CacheLumpName(DEH_String("ENDSTRF"), PU_STATIC);
+
+ I_Endoom(endoom);
+}
+
+//=============================================================================
+//
+// haleyjd: Chocolate Strife Specifics
+//
+// None of the code in here is from the original executable, but is needed for
+// other reasons.
+
+//
+// D_PatchClipCallback
+//
+// haleyjd 08/28/10: Clip patches to the framebuffer without errors.
+// Returns false if V_DrawPatch should return without drawing.
+//
+boolean D_PatchClipCallback(patch_t *patch, int x, int y)
+{
+ // note that offsets were already accounted for in V_DrawPatch
+ return (x >= 0 && y >= 0
+ && x + SHORT(patch->width) <= SCREENWIDTH
+ && y + SHORT(patch->height) <= SCREENHEIGHT);
+}
+
+//
+// D_InitChocoStrife
+//
+// haleyjd 08/28/10: Take care of some Strife-specific initialization
+// that is necessitated by Chocolate Doom issues, such as setting global
+// callbacks.
+//
+static void D_InitChocoStrife(void)
+{
+ // set the V_DrawPatch clipping callback
+ V_SetPatchClipCallback(D_PatchClipCallback);
+}
+
+
+//
+// STRIFE Graphical Intro Sequence
+//
+
+#define MAXINTROPROGRESS 69
+
+static int introprogress; // track the progress of the intro
+
+static byte *rawgfx_startup0; // raw linear gfx for intro
+static byte *rawgfx_startp[4];
+static byte *rawgfx_startlz[2];
+static byte *rawgfx_startbot;
+
+//
+// D_IntroBackground
+//
+// [STRIFE] New function
+// haleyjd 20110206: Strife only drew this once, but for supporting double-
+// buffered or page-flipped surfaces it is best to redraw the entire screen
+// every frame.
+//
+static void D_IntroBackground(void)
+{
+ patch_t *panel0;
+
+ if(!showintro)
+ return;
+
+ // Slam up PANEL0 to fill the background entirely (wasn't needed in vanilla)
+ panel0 = W_CacheLumpName("PANEL0", PU_CACHE);
+ V_DrawPatch(0, 0, panel0);
+
+ // Strife cleared the screen somewhere in the low-level code between the
+ // intro and the titlescreen, so this is to take care of that and get
+ // proper fade-in behavior on the titlescreen
+ if(introprogress >= MAXINTROPROGRESS)
+ {
+ I_FinishUpdate();
+ return;
+ }
+
+ // Draw a 95-pixel rect from STARTUP0 starting at y=57 to (0,41) on the
+ // screen (this was a memcpy directly to 0xA3340 in low DOS memory)
+ V_DrawBlock(0, 41, 320, 95, rawgfx_startup0 + (320*57));
+}
+
+//
+// D_InitIntroSequence
+//
+// [STRIFE] New function
+// haleyjd 20110206: Initialize the graphical introduction sequence
+//
+
+static int saved_screen_width, saved_screen_height;
+static int saved_fullscreen, saved_aspect_ratio_correct;
+
+static void D_InitIntroSequence(void)
+{
+ if(showintro)
+ {
+ // Intro splash screen runs in a window. We must save the actual
+ // display settings, and temporarily overwrite them with the
+ // windowed-mode settings. The real settings will be restored
+ // when the intro screen finishes.
+
+ // INTRO-FIXME:
+ // This is causing problems on Windows, including interruption of the
+ // sound playing. I would like to see this changed back to how it worked
+ // before once the netcode can function along with it.
+ // -haleyjd
+
+ saved_screen_width = screen_width;
+ saved_screen_height = screen_height;
+ saved_aspect_ratio_correct = aspect_ratio_correct;
+ saved_fullscreen = fullscreen;
+
+ // If the game display settings are to run in a small window, it
+ // makes no sense to switch to a larger window for the splash
+ // screen, so use the configured settings.
+
+ // INTRO-FIXME: how does this make sense?
+ // If I have an 800x600 game window (in windowed mode), then I expect an
+ // 800x600 intro too,
+ // and indeed the code below is capable of drawing at any resolution.
+ // Either the logic is off or I simply totally disagree with the original
+ // motivation that lead to limiting it to 640x480.
+ // -haleyjd
+
+ if (fullscreen
+ || screen_width > INTRO_SCREEN_W || screen_height > INTRO_SCREEN_H)
+ {
+ screen_width = INTRO_SCREEN_W;
+ screen_height = INTRO_SCREEN_H;
+ aspect_ratio_correct = 1;
+ }
+
+ fullscreen = 0;
+
+ // In vanilla Strife, Mode 13h was initialized directly in D_DoomMain.
+ // We have to be a little more courteous of the low-level code here.
+ I_SetWindowTitle(gamedescription);
+ I_InitGraphics();
+ V_RestoreBuffer(); // make the V_ routines work
+
+ // Load all graphics
+ rawgfx_startup0 = W_CacheLumpName("STARTUP0", PU_STATIC);
+ rawgfx_startp[0] = W_CacheLumpName("STRTPA1", PU_STATIC);
+ rawgfx_startp[1] = W_CacheLumpName("STRTPB1", PU_STATIC);
+ rawgfx_startp[2] = W_CacheLumpName("STRTPC1", PU_STATIC);
+ rawgfx_startp[3] = W_CacheLumpName("STRTPD1", PU_STATIC);
+ rawgfx_startlz[0] = W_CacheLumpName("STRTLZ1", PU_STATIC);
+ rawgfx_startlz[1] = W_CacheLumpName("STRTLZ2", PU_STATIC);
+ rawgfx_startbot = W_CacheLumpName("STRTBOT", PU_STATIC);
+
+ // Draw the background
+ D_IntroBackground();
+ }
+ /*
+ // STRIFE-FIXME: This was actually displayed on a special textmode
+ // screen with ANSI color codes... would require use of textlib to
+ // emulate properly...
+ else
+ {
+ puts(DEH_String("Conversation ON"));
+ puts(DEH_String("Rogue Entertainment"));
+ puts(DEH_String("and"));
+ puts(DEH_String("Velocity Games"));
+ puts(DEH_String("present"));
+ puts(DEH_String("S T R I F E"));
+ puts(DEH_String("Loading..."));
+ }
+ */
+}
+
+// End of intro splash screen.
+
+static void D_FinishIntroSequence(void)
+{
+ if (showintro)
+ {
+ I_ShutdownGraphics();
+
+ // Restore display settings to the actual ones.
+
+ screen_width = saved_screen_width;
+ screen_height = saved_screen_height;
+ fullscreen = saved_fullscreen;
+ aspect_ratio_correct = saved_aspect_ratio_correct;
+ }
+}
+
+//
+// D_DrawIntroSequence
+//
+// [STRIFE] New function
+// haleyjd 20110206: Refresh the intro sequence
+//
+static void D_DrawIntroSequence(void)
+{
+ int laserpos;
+ int robotpos;
+
+ if(!showintro)
+ return;
+
+ D_IntroBackground(); // haleyjd: refresh the background
+
+ // Laser position
+ laserpos = (200 * introprogress / MAXINTROPROGRESS) + 60;
+
+ // BUG: (?) Due to this clip, the laser never even comes close to
+ // touching the peasant; confirmed with vanilla. This MAY have been
+ // intentional, for effect, however, since no death frames are shown
+ // either... kind of a black-out death.
+ if(laserpos > 200)
+ laserpos = 200;
+
+ // Draw the laser
+ // Blitted 16 bytes for 16 rows starting at 705280 + laserpos
+ // (705280 - 0xA0000) / 320 == 156
+ V_DrawBlock(laserpos, 156, 16, 16, rawgfx_startlz[laserpos % 2]);
+
+ // Robot position
+ robotpos = laserpos % 5 - 2;
+
+ // Draw the robot
+ // Blitted 48 bytes for 48 rows starting at 699534 + (320*robotpos)
+ // 699534 - 0xA0000 == 44174, which % 320 == 14, / 320 == 138
+ V_DrawBlock(14, 138 + robotpos, 48, 48, rawgfx_startbot);
+
+ // Draw the peasant
+ // Blitted 32 bytes for 64 rows starting at 699142
+ // 699142 - 0xA0000 == 43782, which % 320 == 262, / 320 == 136
+ V_DrawBlock(262, 136, 32, 64, rawgfx_startp[laserpos % 4]);
+
+ I_FinishUpdate();
+}
+
+//
+// D_IntroTick
+//
+// Advance the intro sequence
+//
+void D_IntroTick(void)
+{
+ static boolean didsound = false; // haleyjd 20120209
+
+ if(devparm)
+ return;
+
+ ++introprogress;
+ if(introprogress >= MAXINTROPROGRESS)
+ {
+ D_IntroBackground(); // haleyjd: clear the bg anyway
+
+ // haleyjd 20120209: This isn't 100% true to vanilla because vanilla
+ // would play this sound a half-dozen times. BUT, in vanilla, for
+ // whatever reason, under DMX, playing the same sound multiple times
+ // doesn't add up violently like it does under SDL_mixer. This means
+ // that without this one-time limitation, the sound is far too loud.
+ if(!didsound)
+ {
+ S_StartSound(NULL, sfx_psdtha);
+ didsound = true;
+ }
+ }
+ else
+ D_DrawIntroSequence();
+}
+
+//
+// End Chocolate Strife Specifics
+//
+//=============================================================================
+
+//
+// D_DoomMain
+//
+void D_DoomMain (void)
+{
+ int p;
+ char file[256];
+ char demolumpname[9];
+
+ I_AtExit(D_Endoom, false);
+
+ // haleyjd 20110206 [STRIFE]: -nograph parameter
+
+ //!
+ // @vanilla
+ //
+ // Disable graphical introduction sequence
+ //
+
+ if (M_ParmExists("-nograph"))
+ showintro = false;
+
+ // Undocumented:
+ // Invoked by setup to test the controls.
+
+ if (M_ParmExists("-testcontrols"))
+ {
+ testcontrols = true;
+ showintro = false;
+ }
+
+ // haleyjd 20110206: Moved up -devparm for max visibility
+
+ //!
+ // @vanilla
+ //
+ // Developer mode. F1 saves a screenshot in the current working
+ // directory.
+ //
+
+ devparm = M_CheckParm ("-devparm");
+
+ // print banner
+
+ I_PrintBanner(PACKAGE_STRING);
+
+ //DEH_printf("Z_Init: Init zone memory allocation daemon. \n"); [STRIFE] removed
+ Z_Init ();
+
+#ifdef FEATURE_MULTIPLAYER
+ //!
+ // @category net
+ //
+ // Start a dedicated server, routing packets but not participating
+ // in the game itself.
+ //
+
+ if (M_CheckParm("-dedicated") > 0)
+ {
+ printf("Dedicated server mode.\n");
+ NET_DedicatedServer();
+
+ // Never returns
+ }
+
+ //!
+ // @category net
+ //
+ // Query the Internet master server for a global list of active
+ // servers.
+ //
+
+ if (M_CheckParm("-search"))
+ {
+ NET_MasterQuery();
+ exit(0);
+ }
+
+ //!
+ // @arg <address>
+ // @category net
+ //
+ // Query the status of the server running on the given IP
+ // address.
+ //
+
+ p = M_CheckParmWithArgs("-query", 1);
+
+ if (p)
+ {
+ NET_QueryAddress(myargv[p+1]);
+ exit(0);
+ }
+
+ //!
+ // @category net
+ //
+ // Search the local LAN for running servers.
+ //
+
+ if (M_CheckParm("-localsearch"))
+ {
+ NET_LANQuery();
+ exit(0);
+ }
+
+#endif
+
+#ifdef FEATURE_DEHACKED
+ if(devparm)
+ printf("DEH_Init: Init Dehacked support.\n");
+ DEH_Init();
+#endif
+
+ iwadfile = D_FindIWAD(IWAD_MASK_STRIFE, &gamemission);
+
+ // None found?
+
+ if (iwadfile == NULL)
+ {
+ I_Error("Game mode indeterminate. No IWAD file was found. Try\n"
+ "specifying one with the '-iwad' command line parameter.\n");
+ }
+
+ modifiedgame = false;
+
+ //!
+ // @vanilla
+ //
+ // Disable monsters.
+ //
+
+ nomonsters = M_CheckParm ("-nomonsters");
+
+ //!
+ // Sets Rogue playtesting mode (godmode, noclip toggled by backspace)
+ //
+
+ workparm = M_CheckParm ("-work");
+
+ //!
+ // Attemps to flip player gun sprites, but is broken.
+ //
+
+ flipparm = M_CheckParm ("-flip");
+
+ //!
+ // @vanilla
+ //
+ // Monsters respawn after being killed.
+ //
+
+ respawnparm = M_CheckParm ("-respawn");
+
+ //!
+ // @vanilla
+ //
+ // Monsters move faster.
+ //
+
+ fastparm = M_CheckParm ("-fast");
+
+ I_DisplayFPSDots(devparm);
+
+ // haleyjd 20110206 [STRIFE]: -devparm implies -nograph
+ if(devparm)
+ showintro = false;
+
+ // Note: Vanilla Strife does not understand the -deathmatch command
+ // line parameter. deathmatch=1 is the default behavior when
+ // playing a netgame.
+
+ //!
+ // @category net
+ // @vanilla
+ //
+ // Start a deathmatch game. Weapons do not stay in place and
+ // all items respawn after 30 seconds.
+ //
+
+ if (M_CheckParm ("-altdeath"))
+ deathmatch = 2;
+
+ if (devparm)
+ DEH_printf(D_DEVSTR);
+
+ // find which dir to use for config files
+
+#ifdef _WIN32
+
+ //!
+ // @platform windows
+ // @vanilla
+ //
+ // Save configuration data and savegames in c:\doomdata,
+ // allowing play from CD.
+ //
+
+ if (M_CheckParm("-cdrom") > 0)
+ {
+ printf(D_CDROM);
+
+ // haleyjd 08/22/2010: [STRIFE] Use strife.cd folder for -cdrom
+ M_SetConfigDir("c:\\strife.cd\\");
+ }
+ else
+#endif
+ {
+ // Auto-detect the configuration dir.
+
+ M_SetConfigDir(NULL);
+ }
+
+ //!
+ // @arg <x>
+ // @vanilla
+ //
+ // Turbo mode. The player's speed is multiplied by x%. If unspecified,
+ // x defaults to 200. Values are rounded up to 10 and down to 400.
+ //
+
+ if ( (p=M_CheckParm ("-turbo")) )
+ {
+ int scale = 200;
+ extern int forwardmove[2];
+ extern int sidemove[2];
+
+ if (p<myargc-1)
+ scale = atoi (myargv[p+1]);
+ if (scale < 10)
+ scale = 10;
+ if (scale > 400)
+ scale = 400;
+ DEH_printf("turbo scale: %i%%\n", scale);
+ forwardmove[0] = forwardmove[0]*scale/100;
+ forwardmove[1] = forwardmove[1]*scale/100;
+ sidemove[0] = sidemove[0]*scale/100;
+ sidemove[1] = sidemove[1]*scale/100;
+ }
+
+ // init subsystems
+ // DEH_printf("V_Init: allocate screens.\n"); [STRIFE] removed
+ V_Init ();
+
+ // Load configuration files before initialising other subsystems.
+ // haleyjd 08/22/2010: [STRIFE] - use strife.cfg
+ // DEH_printf("M_LoadDefaults: Load system defaults.\n"); [STRIFE] removed
+ M_SetConfigFilenames("strife.cfg", PROGRAM_PREFIX "strife.cfg");
+ D_BindVariables();
+ M_LoadDefaults();
+
+ if (!graphical_startup)
+ {
+ showintro = false;
+ }
+
+ // Save configuration at exit.
+ I_AtExit(M_SaveDefaults, false);
+
+ if(devparm) // [STRIFE] Devparm only
+ DEH_printf("W_Init: Init WADfiles.\n");
+ D_AddFile(iwadfile);
+ modifiedgame = W_ParseCommandLine();
+
+ // [STRIFE] serial number output
+ if(devparm)
+ {
+ char msgbuf[80];
+ char *serial = W_CacheLumpName("SERIAL", PU_CACHE);
+ int serialnum = atoi(serial);
+
+ DEH_snprintf(msgbuf, sizeof(msgbuf), "Wad Serial Number: %d:", serialnum);
+ printf("%s\n", msgbuf);
+ }
+
+ // add any files specified on the command line with -file wadfile
+ // to the wad list
+ //
+
+ // Debug:
+// W_PrintDirectory();
+
+ //!
+ // @arg <demo>
+ // @category demo
+ // @vanilla
+ //
+ // Play back the demo named demo.lmp.
+ //
+
+ p = M_CheckParmWithArgs ("-playdemo", 1);
+
+ if (!p)
+ {
+ //!
+ // @arg <demo>
+ // @category demo
+ // @vanilla
+ //
+ // Play back the demo named demo.lmp, determining the framerate
+ // of the screen.
+ //
+ p = M_CheckParmWithArgs("-timedemo", 1);
+
+ }
+
+ if (p)
+ {
+ if (!strcasecmp(myargv[p+1] + strlen(myargv[p+1]) - 4, ".lmp"))
+ {
+ strcpy(file, myargv[p + 1]);
+ }
+ else
+ {
+ sprintf (file,"%s.lmp", myargv[p+1]);
+ }
+
+ if (D_AddFile (file))
+ {
+ strncpy(demolumpname, lumpinfo[numlumps - 1].name, 8);
+ demolumpname[8] = '\0';
+
+ printf("Playing demo %s.\n", file);
+ }
+ else
+ {
+ // If file failed to load, still continue trying to play
+ // the demo in the same way as Vanilla Doom. This makes
+ // tricks like "-playdemo demo1" possible.
+
+ strncpy(demolumpname, myargv[p + 1], 8);
+ demolumpname[8] = '\0';
+ }
+
+ }
+
+ I_AtExit((atexit_func_t) G_CheckDemoStatus, true);
+
+ // Generate the WAD hash table. Speed things up a bit.
+
+ W_GenerateHashTable();
+
+ D_IdentifyVersion();
+ InitGameVersion();
+ D_SetGameDescription();
+ savegamedir = M_GetSaveGameDir("strife1.wad");
+
+ // haleyjd 20110210: Create Strife hub save folders
+ M_CreateSaveDirs(savegamedir);
+
+ I_GraphicsCheckCommandLine();
+
+ // haleyjd 20110206 [STRIFE] Startup the introduction sequence
+ D_InitIntroSequence();
+
+ // haleyjd 20110924: moved S_Init up to here
+ if(devparm) // [STRIFE]
+ DEH_printf("S_Init: Setting up sound.\n");
+ S_Init (sfxVolume * 8, musicVolume * 8, voiceVolume * 8); // [STRIFE]: voice
+ D_IntroTick(); // [STRIFE]
+
+ // Check for -file in shareware
+ if (modifiedgame)
+ {
+ // These are the lumps that will be checked in IWAD,
+ // if any one is not present, execution will be aborted.
+ // haleyjd 08/22/2010: [STRIFE] Check for Strife lumps.
+ char name[3][8]=
+ {
+ "map23", "map30", "ROB3E1"
+ };
+ int i;
+
+ // haleyjd 08/22/2010: [STRIFE] Changed string to match binary
+ // STRIFE-FIXME: Needs to test isdemoversion variable
+ if ( gamemode == shareware)
+ I_Error(DEH_String("\nYou cannot -file with the demo "
+ "version. You must buy the real game!"));
+
+ // Check for fake IWAD with right name,
+ // but w/o all the lumps of the registered version.
+ // STRIFE-FIXME: Needs to test isregistered variable
+ if (gamemode == registered)
+ for (i = 0; i < 3; i++)
+ if (W_CheckNumForName(name[i])<0)
+ I_Error(DEH_String("\nThis is not the registered version."));
+ }
+
+ D_IntroTick(); // [STRIFE]
+
+ // get skill / episode / map from parms
+ startskill = sk_medium;
+ startepisode = 1;
+ startmap = 1;
+ autostart = false;
+
+ //!
+ // @arg <skill>
+ // @vanilla
+ //
+ // Set the game skill, 1-5 (1: easiest, 5: hardest). A skill of
+ // 0 disables all monsters.
+ //
+
+ p = M_CheckParmWithArgs("-skill", 1);
+
+ if (p)
+ {
+ startskill = myargv[p+1][0]-'1';
+ autostart = true;
+ }
+
+ //!
+ // @arg <n>
+ // @vanilla
+ //
+ // Start playing on episode n (1-4)
+ //
+
+ p = M_CheckParmWithArgs("-episode", 1);
+
+ if (p)
+ {
+ startepisode = myargv[p+1][0]-'0';
+ startmap = 1;
+ autostart = true;
+ }
+
+ timelimit = 0;
+
+ //!
+ // @arg <n>
+ // @category net
+ // @vanilla
+ //
+ // For multiplayer games: exit each level after n minutes.
+ //
+
+ p = M_CheckParmWithArgs("-timer", 1);
+
+ if (p)
+ {
+ timelimit = atoi(myargv[p+1]);
+ printf("timer: %i\n", timelimit);
+ }
+
+ //!
+ // @category net
+ // @vanilla
+ //
+ // Austin Virtual Gaming: end levels after 20 minutes.
+ //
+
+ p = M_CheckParm ("-avg");
+
+ if (p)
+ {
+ timelimit = 20;
+ }
+
+ //!
+ // @arg [<x> <y> | <xy>]
+ // @vanilla
+ //
+ // Start a game immediately, warping to ExMy (Doom 1) or MAPxy
+ // (Doom 2)
+ //
+
+ p = M_CheckParmWithArgs("-warp", 1);
+
+ if (p)
+ {
+ if (gamemode == commercial)
+ startmap = atoi (myargv[p+1]);
+ else
+ {
+ startepisode = myargv[p+1][0]-'0';
+
+ if (p + 2 < myargc)
+ {
+ startmap = myargv[p+2][0]-'0';
+ }
+ else
+ {
+ startmap = 1;
+ }
+ }
+ autostart = true;
+ }
+
+ if (testcontrols)
+ {
+ startepisode = 1;
+ startmap = 3;
+ autostart = true;
+ }
+
+ // Check for load game parameter
+ // We do this here and save the slot number, so that the network code
+ // can override it or send the load slot to other players.
+
+ //!
+ // @arg <s>
+ // @vanilla
+ //
+ // Load the game in slot s.
+ //
+
+ p = M_CheckParmWithArgs("-loadgame", 1);
+
+ if (p)
+ {
+ startloadgame = atoi(myargv[p+1]);
+ }
+ else
+ {
+ // Not loading a game
+ startloadgame = -1;
+ }
+
+ if (W_CheckNumForName("SS_START") >= 0
+ || W_CheckNumForName("FF_END") >= 0)
+ {
+ I_PrintDivider();
+ printf(" WARNING: The loaded WAD file contains modified sprites or\n"
+ " floor textures. You may want to use the '-merge' command\n"
+ " line option instead of '-file'.\n");
+ }
+
+ I_PrintStartupBanner(gamedescription);
+ PrintDehackedBanners();
+
+ // haleyjd 08/28/10: Init Choco Strife stuff.
+ D_InitChocoStrife();
+
+ // haleyjd 08/22/2010: [STRIFE] Modified string to match binary
+ if(devparm) // [STRIFE]
+ DEH_printf("R_Init: Loading Graphics - ");
+ R_Init ();
+ D_IntroTick(); // [STRIFE]
+
+ if(devparm) // [STRIFE]
+ DEH_printf("\nP_Init: Init Playloop state.\n");
+ P_Init ();
+ D_IntroTick(); // [STRIFE]
+
+ if(devparm) // [STRIFE]
+ DEH_printf("I_Init: Setting up machine state.\n");
+ I_CheckIsScreensaver();
+ I_InitTimer();
+ I_InitJoystick();
+ D_IntroTick(); // [STRIFE]
+
+#ifdef FEATURE_MULTIPLAYER
+ if(devparm) // [STRIFE]
+ printf ("NET_Init: Init network subsystem.\n");
+ NET_Init ();
+#endif
+ D_IntroTick(); // [STRIFE]
+
+ if(devparm) // [STRIFE]
+ DEH_printf("M_Init: Init Menu.\n");
+ M_Init ();
+ D_IntroTick(); // [STRIFE]
+
+ // haleyjd 20110924: Moved S_Init up.
+ D_IntroTick();
+
+ // haleyjd 20110220: This stuff was done in I_StartupSound in vanilla, but
+ // we'll do it here instead so we don't have to modify the low-level shared
+ // code with Strife-specific stuff.
+ if(disable_voices || M_CheckParm("-novoice"))
+ {
+ dialogshowtext = disable_voices = 1;
+ }
+ if(devparm)
+ DEH_printf(" Play voices = %d\n", disable_voices == 0);
+
+ // [STRIFE]: This has been rearranged. These intro ticks occur
+ // further down in Vanilla Strife; however, we have to finish
+ // the intro sequence here so that netgame startup can begin.
+ // The original calls to D_IntroTick() are commented-out below.
+
+ // INTRO-FIXME: Great in theory but it makes the intro end too quickly.
+ // -haleyjd
+
+ D_IntroTick();
+ D_IntroTick();
+ D_IntroTick();
+ D_IntroTick();
+ D_IntroTick();
+ D_IntroTick();
+ D_IntroTick();
+
+ D_FinishIntroSequence();
+
+ if(devparm) // [STRIFE]
+ DEH_printf("D_CheckNetGame: Checking network game status.\n");
+ D_CheckNetGame ();
+
+ PrintGameVersion();
+
+ if(devparm)
+ DEH_printf("HU_Init: Setting up heads up display.\n");
+ HU_Init ();
+ //D_IntroTick(); // [STRIFE]
+
+ if(devparm)
+ DEH_printf("ST_Init: Init status bar.\n");
+ ST_Init ();
+ //D_IntroTick(); // [STRIFE]
+
+ // haleyjd [STRIFE] -statcopy used to be here...
+ //D_IntroTick(); // [STRIFE]
+
+ // If Doom II without a MAP01 lump, this is a store demo.
+ // Moved this here so that MAP01 isn't constantly looked up
+ // in the main loop.
+ // haleyjd 08/23/2010: [STRIFE] There is no storedemo version of Strife
+ /*
+ if (gamemode == commercial && W_CheckNumForName("map01") < 0)
+ storedemo = true;
+ */
+
+ //!
+ // @arg <x>
+ // @category demo
+ // @vanilla
+ //
+ // Record a demo named x.lmp.
+ //
+
+ p = M_CheckParmWithArgs("-record", 1);
+
+ if (p)
+ {
+ G_RecordDemo (myargv[p+1]);
+ autostart = true;
+ }
+ //D_IntroTick(); // [STRIFE]
+
+ p = M_CheckParmWithArgs("-playdemo", 1);
+ if (p)
+ {
+ singledemo = true; // quit after one demo
+ G_DeferedPlayDemo (demolumpname);
+ D_DoomLoop (); // never returns
+ }
+ //D_IntroTick(); // [STRIFE]
+
+ p = M_CheckParmWithArgs("-timedemo", 1);
+ if (p)
+ {
+ G_TimeDemo (demolumpname);
+ D_DoomLoop (); // never returns
+ }
+ //D_IntroTick(); // [STRIFE]
+
+ if (startloadgame >= 0)
+ {
+ // [STRIFE]: different, for hubs
+ M_LoadSelect(startloadgame);
+ }
+ //D_IntroTick(); // [STRIFE]
+
+
+ if (gameaction != ga_loadgame )
+ {
+ if (autostart || netgame)
+ G_InitNew (startskill, startmap);
+ else
+ D_StartTitle (); // start up intro loop
+ }
+
+ D_DoomLoop (); // never returns
+}
diff --git a/src/strife/d_main.h b/src/strife/d_main.h
new file mode 100644
index 00000000..2909cd29
--- /dev/null
+++ b/src/strife/d_main.h
@@ -0,0 +1,64 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// System specific interface stuff.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __D_MAIN__
+#define __D_MAIN__
+
+#include "doomdef.h"
+
+
+
+
+// Read events from all input devices
+
+void D_ProcessEvents (void);
+
+
+//
+// BASE LEVEL
+//
+void D_PageTicker (void);
+void D_PageDrawer (void);
+void D_AdvanceDemo (void);
+void D_DoAdvanceDemo (void);
+void D_StartTitle (void);
+void D_QuitGame (void); // [STRIFE]
+
+void D_IntroTick(void); // [STRIFE]
+
+//
+// GLOBAL VARIABLES
+//
+
+extern gameaction_t gameaction;
+extern boolean isregistered; // villsa [STRIFE]
+extern boolean isdemoversion; // haleyjd [STRIFE]
+extern boolean stonecold; // villsa [STRIFE]
+extern boolean workparm; // villsa [STRIFE]
+
+#endif
+
diff --git a/src/strife/d_net.c b/src/strife/d_net.c
new file mode 100644
index 00000000..a3f5513c
--- /dev/null
+++ b/src/strife/d_net.c
@@ -0,0 +1,316 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// DOOM Network game communication and protocol,
+// all OS independend parts.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdlib.h>
+
+#include "doomfeatures.h"
+
+#include "d_main.h"
+#include "m_argv.h"
+#include "m_menu.h"
+#include "i_system.h"
+#include "i_timer.h"
+#include "i_video.h"
+#include "g_game.h"
+#include "doomdef.h"
+#include "doomstat.h"
+#include "w_checksum.h"
+
+#include "deh_main.h"
+
+#include "d_loop.h"
+
+ticcmd_t *netcmds;
+
+// Called when a player leaves the game
+
+static void PlayerQuitGame(player_t *player)
+{
+ static char exitmsg[80];
+ unsigned int player_num;
+
+ player_num = player - players;
+
+ // Do this the same way as Vanilla Doom does, to allow dehacked
+ // replacements of this message
+
+ strncpy(exitmsg, DEH_String("Player 1 left the game"), sizeof(exitmsg));
+ exitmsg[sizeof(exitmsg) - 1] = '\0';
+
+ exitmsg[7] += player_num;
+
+ playeringame[player_num] = false;
+ players[consoleplayer].message = exitmsg;
+
+ // TODO: check if it is sensible to do this:
+
+ if (demorecording)
+ {
+ G_CheckDemoStatus ();
+ }
+}
+
+static void RunTic(ticcmd_t *cmds, boolean *ingame)
+{
+ extern boolean advancedemo;
+ unsigned int i;
+
+ // Check for player quits.
+
+ for (i = 0; i < MAXPLAYERS; ++i)
+ {
+ if (!demoplayback && playeringame[i] && !ingame[i])
+ {
+ PlayerQuitGame(&players[i]);
+ }
+ }
+
+ netcmds = cmds;
+
+ // check that there are players in the game. if not, we cannot
+ // run a tic.
+
+ if (advancedemo)
+ D_DoAdvanceDemo ();
+
+ M_Ticker();
+ G_Ticker();
+}
+
+static void NullMenuTicker()
+{
+ // no-op.
+}
+
+static loop_interface_t strife_loop_interface = {
+ D_ProcessEvents,
+ G_BuildTiccmd,
+ RunTic,
+ NullMenuTicker
+};
+
+
+// Load game settings from the specified structure and
+// set global variables.
+
+static void LoadGameSettings(net_gamesettings_t *settings,
+ net_connect_data_t *connect_data)
+{
+ unsigned int i;
+
+ deathmatch = settings->deathmatch;
+ ticdup = settings->ticdup;
+ startepisode = settings->episode;
+ startmap = settings->map;
+ startskill = settings->skill;
+ startloadgame = settings->loadgame;
+ lowres_turn = settings->lowres_turn;
+ nomonsters = settings->nomonsters;
+ fastparm = settings->fast_monsters;
+ respawnparm = settings->respawn_monsters;
+ timelimit = settings->timelimit;
+
+ if (lowres_turn)
+ {
+ printf("NOTE: Turning resolution is reduced; this is probably "
+ "because there is a client recording a Vanilla demo.\n");
+ }
+
+ if (!connect_data->drone)
+ {
+ consoleplayer = settings->consoleplayer;
+ }
+ else
+ {
+ consoleplayer = 0;
+ }
+
+ for (i=0; i<MAXPLAYERS; ++i)
+ {
+ playeringame[i] = i < settings->num_players;
+ }
+}
+
+// Save the game settings from global variables to the specified
+// game settings structure.
+
+static void SaveGameSettings(net_gamesettings_t *settings,
+ net_connect_data_t *connect_data)
+{
+ // Fill in game settings structure with appropriate parameters
+ // for the new game
+
+ settings->deathmatch = deathmatch;
+ settings->episode = startepisode;
+ settings->map = startmap;
+ settings->skill = startskill;
+ settings->loadgame = startloadgame;
+ settings->gameversion = gameversion;
+ settings->nomonsters = nomonsters;
+ settings->fast_monsters = fastparm;
+ settings->respawn_monsters = respawnparm;
+ settings->timelimit = timelimit;
+
+ settings->lowres_turn = M_CheckParm("-record") > 0
+ && M_CheckParm("-longtics") == 0;
+
+ connect_data->drone = false;
+ connect_data->max_players = MAXPLAYERS;
+
+ //!
+ // @category net
+ //
+ // Run as the left screen in three screen mode.
+ //
+
+ if (M_CheckParm("-left") > 0)
+ {
+ viewangleoffset = ANG90;
+ connect_data->drone = true;
+ }
+
+ //!
+ // @category net
+ //
+ // Run as the right screen in three screen mode.
+ //
+
+ if (M_CheckParm("-right") > 0)
+ {
+ viewangleoffset = ANG270;
+ connect_data->drone = true;
+ }
+
+ //
+ // Connect data
+ //
+
+ // Game type fields:
+
+ connect_data->gamemode = gamemode;
+ connect_data->gamemission = gamemission;
+
+ // Are we recording a demo? Possibly set lowres turn mode
+
+ connect_data->lowres_turn = settings->lowres_turn;
+
+ // Read checksums of our WAD directory and dehacked information
+
+ W_Checksum(connect_data->wad_sha1sum);
+ DEH_Checksum(connect_data->deh_sha1sum);
+
+ connect_data->is_freedoom = 0;
+}
+
+void D_InitSinglePlayerGame(net_gamesettings_t *settings)
+{
+ // default values for single player
+
+ settings->consoleplayer = 0;
+ settings->num_players = 1;
+
+ netgame = false;
+
+ //!
+ // @category net
+ //
+ // Start the game playing as though in a netgame with a single
+ // player. This can also be used to play back single player netgame
+ // demos.
+ //
+
+ if (M_CheckParm("-solo-net") > 0)
+ {
+ netgame = true;
+ }
+}
+
+//
+// D_CheckNetGame
+// Works out player numbers among the net participants
+//
+void D_CheckNetGame (void)
+{
+ net_connect_data_t connect_data;
+ net_gamesettings_t settings;
+
+ D_RegisterLoopCallbacks(&strife_loop_interface);
+
+ // Call D_QuitNetGame on exit
+
+ I_AtExit(D_QuitNetGame, true);
+
+ SaveGameSettings(&settings, &connect_data);
+
+ if (D_InitNetGame(&connect_data, &settings))
+ {
+ netgame = true;
+ autostart = true;
+ }
+ else
+ {
+ D_InitSinglePlayerGame(&settings);
+ }
+
+ LoadGameSettings(&settings, &connect_data);
+
+ // Strife games are always deathmatch, though -altdeath is
+ // supported for respawning items.
+
+ if (netgame && deathmatch == 0)
+ {
+ deathmatch = 1;
+ }
+
+ DEH_printf("startmap: %i, skill: %i, enemies: %i, random: %i\n",
+ startmap, startskill, !nomonsters, 0 /* ??? */);
+
+
+ DEH_printf("player %i of %i (%i nodes)\n",
+ consoleplayer+1, settings.num_players, settings.num_players);
+
+ // Show players here; the server might have specified a time limit
+
+ if (timelimit > 0 && deathmatch)
+ {
+ // Gross hack to work like Vanilla:
+
+ if (timelimit == 20 && M_CheckParm("-avg"))
+ {
+ DEH_printf("Austin Virtual Gaming: Levels will end "
+ "after 20 minutes\n");
+ }
+ else
+ {
+ DEH_printf("Levels will end after %d minute", timelimit);
+ if (timelimit > 1)
+ printf("s");
+ printf(".\n");
+ }
+ }
+}
+
diff --git a/src/strife/d_player.h b/src/strife/d_player.h
new file mode 100644
index 00000000..fc4554fa
--- /dev/null
+++ b/src/strife/d_player.h
@@ -0,0 +1,257 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// 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"
+
+#include "net_defs.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,
+ // villsa [STRIFE] new cheat
+ // set when on fire and disable inventory
+ CF_ONFIRE = 8,
+ // villsa [STRIFE] new cheat
+ // auto-use medkits
+ CF_AUTOHEALTH = 16
+
+} cheat_t;
+
+// haleyjd 08/30/10: [STRIFE]
+// Player Inventory Item Structure
+typedef struct inventory_s
+{
+ int sprite; // a sprite number
+ int type; // a thing type
+ int amount; // amount being carried
+} inventory_t;
+
+#define NUMINVENTORY 32
+
+//
+// Extended player object info: player_t
+//
+// haleyjd 08/30/10: [STRIFE]
+// * Transformed to match binary structure layout.
+//
+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;
+ short armorpoints; // [STRIFE] Changed to short
+ // Armor type is 0-2.
+ short armortype; // [STRIFE] Changed to short
+
+ // Power ups. invinc and invis are tic counters.
+ int powers[NUMPOWERS];
+
+ // [STRIFE] Additions:
+ int sigiltype; // Type of Sigil carried
+ int nukagecount; // Nukage exposure counter
+ int questflags; // Quest bit flags
+ int pitch; // Up/down look angle
+ boolean centerview; // True if view should be centered
+ inventory_t inventory[NUMINVENTORY]; // Player inventory items
+ boolean st_update; // If true, update status bar
+ short numinventory; // Num. active inventory items
+ short inventorycursor; // Selected inventory item
+ short accuracy; // Accuracy stat
+ short stamina; // Stamina stat
+
+ boolean cards[NUMCARDS];
+ boolean backpack;
+
+ // True if button down last tic.
+ int attackdown;
+ int usedown;
+ int inventorydown; // [STRIFE] Use inventory item
+
+ // Frags, kills of other players.
+ int frags[MAXPLAYERS];
+ weapontype_t readyweapon;
+
+ // Is wp_nochange if not changing.
+ weapontype_t pendingweapon;
+
+ boolean weaponowned[NUMWEAPONS];
+ int ammo[NUMAMMO];
+ int maxammo[NUMAMMO];
+
+ // Bit flags, for cheats and debug.
+ // See cheat_t, above.
+ int cheats;
+
+ // Refired shots are less accurate.
+ int refire;
+
+ // For intermission stats.
+ short killcount; // [STRIFE] Changed to short
+ //int itemcount; // [STRIFE] Eliminated these.
+ //int secretcount;
+
+ // Hint messages.
+ char* message;
+
+ // For screen flashing (red or bright).
+ int damagecount;
+ int bonuscount;
+
+ // Who did damage (NULL 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; [STRIFE] no such? or did it become the below?
+
+ // [STRIFE] For use of teleport beacons
+ short allegiance;
+
+ // Overlay view sprites (gun, etc).
+ pspdef_t psprites[NUMPSPRITES];
+
+ // [STRIFE] Inefficient means of tracking automap state on all maps
+ boolean mapstate[40];
+
+ // True if secret level has been done.
+ //boolean didsecret; [STRIFE] Removed this.
+
+} player_t;
+
+
+//
+// INTERMISSION
+// Structure passed e.g. to WI_Start(wb)
+//
+typedef struct
+{
+ 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
+ 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
diff --git a/src/strife/d_textur.h b/src/strife/d_textur.h
new file mode 100644
index 00000000..084a5b1b
--- /dev/null
+++ b/src/strife/d_textur.h
@@ -0,0 +1,51 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// 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
diff --git a/src/strife/d_think.h b/src/strife/d_think.h
new file mode 100644
index 00000000..1405230d
--- /dev/null
+++ b/src/strife/d_think.h
@@ -0,0 +1,76 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// 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_v acv;
+ actionf_p1 acp1;
+ 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
diff --git a/src/strife/deh_ammo.c b/src/strife/deh_ammo.c
new file mode 100644
index 00000000..952d8df3
--- /dev/null
+++ b/src/strife/deh_ammo.c
@@ -0,0 +1,112 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// Parses "Ammo" sections in dehacked files
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "doomdef.h"
+#include "doomtype.h"
+#include "deh_defs.h"
+#include "deh_io.h"
+#include "deh_main.h"
+#include "p_local.h"
+
+static void *DEH_AmmoStart(deh_context_t *context, char *line)
+{
+ int ammo_number = 0;
+
+ if (sscanf(line, "Ammo %i", &ammo_number) != 1)
+ {
+ DEH_Warning(context, "Parse error on section start");
+ return NULL;
+ }
+
+ if (ammo_number < 0 || ammo_number >= NUMAMMO)
+ {
+ DEH_Warning(context, "Invalid ammo number: %i", ammo_number);
+ return NULL;
+ }
+
+ return &maxammo[ammo_number];
+}
+
+static void DEH_AmmoParseLine(deh_context_t *context, char *line, void *tag)
+{
+ char *variable_name, *value;
+ int ivalue;
+ int ammo_number;
+
+ if (tag == NULL)
+ return;
+
+ ammo_number = ((int *) tag) - maxammo;
+
+ // Parse the assignment
+
+ if (!DEH_ParseAssignment(line, &variable_name, &value))
+ {
+ // Failed to parse
+
+ DEH_Warning(context, "Failed to parse assignment");
+ return;
+ }
+
+ ivalue = atoi(value);
+
+ // maxammo
+
+ if (!strcasecmp(variable_name, "Per ammo"))
+ clipammo[ammo_number] = ivalue;
+ else if (!strcasecmp(variable_name, "Max ammo"))
+ maxammo[ammo_number] = ivalue;
+ else
+ {
+ DEH_Warning(context, "Field named '%s' not found", variable_name);
+ }
+}
+
+static void DEH_AmmoSHA1Hash(sha1_context_t *context)
+{
+ int i;
+
+ for (i=0; i<NUMAMMO; ++i)
+ {
+ SHA1_UpdateInt32(context, clipammo[i]);
+ SHA1_UpdateInt32(context, maxammo[i]);
+ }
+}
+
+deh_section_t deh_section_ammo =
+{
+ "Ammo",
+ NULL,
+ DEH_AmmoStart,
+ DEH_AmmoParseLine,
+ NULL,
+ DEH_AmmoSHA1Hash,
+};
+
diff --git a/src/strife/deh_cheat.c b/src/strife/deh_cheat.c
new file mode 100644
index 00000000..9d3d453d
--- /dev/null
+++ b/src/strife/deh_cheat.c
@@ -0,0 +1,157 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// Parses "Cheat" sections in dehacked files
+//
+//-----------------------------------------------------------------------------
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "doomtype.h"
+
+#include "deh_defs.h"
+#include "deh_io.h"
+#include "deh_main.h"
+#include "am_map.h"
+#include "st_stuff.h"
+
+typedef struct
+{
+ char *name;
+ cheatseq_t *seq;
+} deh_cheat_t;
+
+static deh_cheat_t allcheats[] =
+{
+ // haleyjd 20110224: filled in all cheats
+ {"Change music", &cheat_mus },
+ {"Level Warp", &cheat_clev },
+ {"Stealth Boots", &cheat_stealth },
+ {"Sigil piece", &cheat_lego },
+ {"FPS", &cheat_mypos },
+ {"TeleportMapSpot", &cheat_scoot },
+ {"Gold&StatTokens", &cheat_midas },
+ {"God mode", &cheat_god },
+ {"Keys", &cheat_keys },
+ {"Weapons & Ammo", &cheat_ammo },
+ {"Massacre", &cheat_nuke },
+ {"No Clipping", &cheat_noclip },
+ {"Berserk", &cheat_powerup[0] },
+ {"Invisibility", &cheat_powerup[1] },
+ {"Enviro Suit", &cheat_powerup[2] },
+ {"Health", &cheat_powerup[3] },
+ {"Backpack", &cheat_powerup[4] },
+ // STRIFE-FIXME/TODO: Does SeHackEd not support PUMPUP{S,T,nil}, or "DOTS" ?
+};
+
+static deh_cheat_t *FindCheatByName(char *name)
+{
+ size_t i;
+
+ for (i=0; i<arrlen(allcheats); ++i)
+ {
+ if (!strcasecmp(allcheats[i].name, name))
+ return &allcheats[i];
+ }
+
+ return NULL;
+}
+
+static void *DEH_CheatStart(deh_context_t *context, char *line)
+{
+ return NULL;
+}
+
+static void DEH_CheatParseLine(deh_context_t *context, char *line, void *tag)
+{
+ deh_cheat_t *cheat;
+ char *variable_name;
+ char *value;
+ unsigned char *unsvalue;
+ unsigned int i;
+
+ if (!DEH_ParseAssignment(line, &variable_name, &value))
+ {
+ // Failed to parse
+
+ DEH_Warning(context, "Failed to parse assignment");
+ return;
+ }
+
+ unsvalue = (unsigned char *) value;
+
+ cheat = FindCheatByName(variable_name);
+
+ if (cheat == NULL)
+ {
+ DEH_Warning(context, "Unknown cheat '%s'", variable_name);
+ return;
+ }
+
+ // write the value into the cheat sequence
+
+ i = 0;
+
+ while (unsvalue[i] != 0 && unsvalue[i] != 0xff)
+ {
+ // If the cheat length exceeds the Vanilla limit, stop. This
+ // does not apply if we have the limit turned off.
+
+ if (!deh_allow_long_cheats && i >= cheat->seq->sequence_len)
+ {
+ DEH_Warning(context, "Cheat sequence longer than supported by "
+ "Vanilla dehacked");
+ break;
+ }
+
+ if (deh_apply_cheats)
+ {
+ cheat->seq->sequence[i] = unsvalue[i];
+ }
+ ++i;
+
+ // Absolute limit - don't exceed
+
+ if (i >= MAX_CHEAT_LEN - cheat->seq->parameter_chars)
+ {
+ DEH_Error(context, "Cheat sequence too long!");
+ return;
+ }
+ }
+
+ if (deh_apply_cheats)
+ {
+ cheat->seq->sequence[i] = '\0';
+ }
+}
+
+deh_section_t deh_section_cheat =
+{
+ "Cheat",
+ NULL,
+ DEH_CheatStart,
+ DEH_CheatParseLine,
+ NULL,
+ NULL,
+};
+
diff --git a/src/strife/deh_frame.c b/src/strife/deh_frame.c
new file mode 100644
index 00000000..dc68fde5
--- /dev/null
+++ b/src/strife/deh_frame.c
@@ -0,0 +1,168 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// Parses "Frame" sections in dehacked files
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "doomtype.h"
+#include "d_items.h"
+#include "info.h"
+
+#include "deh_defs.h"
+#include "deh_io.h"
+#include "deh_main.h"
+#include "deh_mapping.h"
+
+DEH_BEGIN_MAPPING(state_mapping, state_t)
+ DEH_MAPPING("Sprite number", sprite)
+ DEH_MAPPING("Sprite subnumber", frame)
+ DEH_MAPPING("Duration", tics)
+ DEH_MAPPING("Next frame", nextstate)
+ DEH_UNSUPPORTED_MAPPING("Action pointer")
+DEH_END_MAPPING
+
+static void *DEH_FrameStart(deh_context_t *context, char *line)
+{
+ int frame_number = 0;
+ state_t *state;
+
+ if (sscanf(line, "Frame %i", &frame_number) != 1)
+ {
+ DEH_Warning(context, "Parse error on section start");
+ return NULL;
+ }
+
+ if (frame_number < 0 || frame_number >= NUMSTATES)
+ {
+ DEH_Warning(context, "Invalid frame number: %i", frame_number);
+ return NULL;
+ }
+
+ if (frame_number >= DEH_VANILLA_NUMSTATES)
+ {
+ DEH_Warning(context, "Attempt to modify frame %i: this will cause "
+ "problems in Vanilla dehacked.", frame_number);
+ }
+
+ state = &states[frame_number];
+
+ return state;
+}
+
+// Simulate a frame overflow: Doom has 967 frames in the states[] array, but
+// DOS dehacked internally only allocates memory for 966. As a result,
+// attempts to set frame 966 (the last frame) will overflow the dehacked
+// array and overwrite the weaponinfo[] array instead.
+//
+// This is noticable in Batman Doom where it is impossible to switch weapons
+// away from the fist once selected.
+
+static void DEH_FrameOverflow(deh_context_t *context, char *varname, int value)
+{
+ if (!strcasecmp(varname, "Duration"))
+ {
+ weaponinfo[0].ammo = value;
+ }
+ else if (!strcasecmp(varname, "Codep frame"))
+ {
+ weaponinfo[0].upstate = value;
+ }
+ else if (!strcasecmp(varname, "Next frame"))
+ {
+ weaponinfo[0].downstate = value;
+ }
+ else if (!strcasecmp(varname, "Unknown 1"))
+ {
+ weaponinfo[0].readystate = value;
+ }
+ else if (!strcasecmp(varname, "Unknown 2"))
+ {
+ weaponinfo[0].atkstate = value;
+ }
+ else
+ {
+ DEH_Error(context, "Unable to simulate frame overflow: field '%s'",
+ varname);
+ }
+}
+
+static void DEH_FrameParseLine(deh_context_t *context, char *line, void *tag)
+{
+ state_t *state;
+ char *variable_name, *value;
+ int ivalue;
+
+ if (tag == NULL)
+ return;
+
+ state = (state_t *) tag;
+
+ // Parse the assignment
+
+ if (!DEH_ParseAssignment(line, &variable_name, &value))
+ {
+ // Failed to parse
+
+ DEH_Warning(context, "Failed to parse assignment");
+ return;
+ }
+
+ // all values are integers
+
+ ivalue = atoi(value);
+
+ if (state == &states[NUMSTATES - 1])
+ {
+ DEH_FrameOverflow(context, variable_name, ivalue);
+ }
+ else
+ {
+ // set the appropriate field
+
+ DEH_SetMapping(context, &state_mapping, state, variable_name, ivalue);
+ }
+}
+
+static void DEH_FrameSHA1Sum(sha1_context_t *context)
+{
+ int i;
+
+ for (i=0; i<NUMSTATES; ++i)
+ {
+ DEH_StructSHA1Sum(context, &state_mapping, &states[i]);
+ }
+}
+
+deh_section_t deh_section_frame =
+{
+ "Frame",
+ NULL,
+ DEH_FrameStart,
+ DEH_FrameParseLine,
+ NULL,
+ DEH_FrameSHA1Sum,
+};
+
diff --git a/src/strife/deh_misc.c b/src/strife/deh_misc.c
new file mode 100644
index 00000000..aaebbadd
--- /dev/null
+++ b/src/strife/deh_misc.c
@@ -0,0 +1,237 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// Parses "Misc" sections in dehacked files
+//
+//-----------------------------------------------------------------------------
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "doomtype.h"
+#include "deh_defs.h"
+#include "deh_io.h"
+#include "deh_main.h"
+#include "deh_misc.h"
+
+// Dehacked: "Initial Health"
+// This is the initial health a player has when starting anew.
+// See G_PlayerReborn in g_game.c
+
+int deh_initial_health = DEH_DEFAULT_INITIAL_HEALTH;
+
+// Dehacked: "Initial bullets"
+// This is the number of bullets the player has when starting anew.
+// See G_PlayerReborn in g_game.c
+
+int deh_initial_bullets = DEH_DEFAULT_INITIAL_BULLETS;
+
+// Dehacked: "Max Health"
+// This is the maximum health that can be reached using medikits
+// alone. See P_TouchSpecialThing in p_inter.c
+
+int deh_max_health = DEH_DEFAULT_MAX_HEALTH;
+
+// Dehacked: "Max Armor"
+// This is the maximum armor which can be reached by picking up
+// armor helmets. See P_TouchSpecialThing in p_inter.c
+
+int deh_max_armor = DEH_DEFAULT_MAX_ARMOR;
+
+// Dehacked: "Green Armor Class"
+// This is the armor class that is given when picking up the green
+// armor or an armor helmet. See P_TouchSpecialThing in p_inter.c
+//
+// DOS dehacked only modifies the behavior of the green armor shirt,
+// the armor class set by armor helmets is not affected.
+
+int deh_green_armor_class = DEH_DEFAULT_GREEN_ARMOR_CLASS;
+
+// Dehacked: "Blue Armor Class"
+// This is the armor class that is given when picking up the blue
+// armor or a megasphere. See P_TouchSpecialThing in p_inter.c
+//
+// DOS dehacked only modifies the MegaArmor behavior and not
+// the MegaSphere, which always gives armor type 2.
+
+int deh_blue_armor_class = DEH_DEFAULT_BLUE_ARMOR_CLASS;
+
+// Dehacked: "Max soulsphere"
+// The maximum health which can be reached by picking up the
+// soulsphere. See P_TouchSpecialThing in p_inter.c
+
+int deh_max_soulsphere = DEH_DEFAULT_MAX_SOULSPHERE;
+
+// Dehacked: "Soulsphere health"
+// The amount of health bonus that picking up a soulsphere
+// gives. See P_TouchSpecialThing in p_inter.c
+
+int deh_soulsphere_health = DEH_DEFAULT_SOULSPHERE_HEALTH;
+
+// Dehacked: "Megasphere health"
+// This is what the health is set to after picking up a
+// megasphere. See P_TouchSpecialThing in p_inter.c
+
+int deh_megasphere_health = DEH_DEFAULT_MEGASPHERE_HEALTH;
+
+// Dehacked: "God mode health"
+// This is what the health value is set to when cheating using
+// the IDDQD god mode cheat. See ST_Responder in st_stuff.c
+
+int deh_god_mode_health = DEH_DEFAULT_GOD_MODE_HEALTH;
+
+// Dehacked: "IDFA Armor"
+// This is what the armor is set to when using the IDFA cheat.
+// See ST_Responder in st_stuff.c
+
+int deh_idfa_armor = DEH_DEFAULT_IDFA_ARMOR;
+
+// Dehacked: "IDFA Armor Class"
+// This is what the armor class is set to when using the IDFA cheat.
+// See ST_Responder in st_stuff.c
+
+int deh_idfa_armor_class = DEH_DEFAULT_IDFA_ARMOR_CLASS;
+
+// Dehacked: "IDKFA Armor"
+// This is what the armor is set to when using the IDKFA cheat.
+// See ST_Responder in st_stuff.c
+
+int deh_idkfa_armor = DEH_DEFAULT_IDKFA_ARMOR;
+
+// Dehacked: "IDKFA Armor Class"
+// This is what the armor class is set to when using the IDKFA cheat.
+// See ST_Responder in st_stuff.c
+
+int deh_idkfa_armor_class = DEH_DEFAULT_IDKFA_ARMOR_CLASS;
+
+// Dehacked: "BFG Cells/Shot"
+// This is the number of CELLs firing the BFG uses up.
+// See P_CheckAmmo and A_FireBFG in p_pspr.c
+
+int deh_bfg_cells_per_shot = DEH_DEFAULT_BFG_CELLS_PER_SHOT;
+
+// Dehacked: "Monsters infight"
+// This controls whether monsters can harm other monsters of the same
+// species. For example, whether an imp fireball will damage other
+// imps. The value of this in dehacked patches is weird - '202' means
+// off, while '221' means on.
+//
+// See PIT_CheckThing in p_map.c
+
+int deh_species_infighting = DEH_DEFAULT_SPECIES_INFIGHTING;
+
+static struct
+{
+ char *deh_name;
+ int *value;
+} misc_settings[] = {
+ {"Initial Health", &deh_initial_health},
+ {"Initial Bullets", &deh_initial_bullets},
+ {"Max Health", &deh_max_health},
+ {"Max Armor", &deh_max_armor},
+ {"LeatherArmorClass", &deh_green_armor_class},
+ {"Metal Armor Class", &deh_blue_armor_class},
+ {"Max Soulsphere", &deh_max_soulsphere},
+ {"Soulsphere Health", &deh_soulsphere_health},
+ {"Megasphere Health", &deh_megasphere_health},
+ {"God Mode Health", &deh_god_mode_health},
+ {"IDFA Armor", &deh_idfa_armor},
+ {"IDFA Armor Class", &deh_idfa_armor_class},
+ {"IDKFA Armor", &deh_idkfa_armor},
+ {"IDKFA Armor Class", &deh_idkfa_armor_class},
+ {"Mauler Cells/Shot", &deh_bfg_cells_per_shot},
+};
+
+static void *DEH_MiscStart(deh_context_t *context, char *line)
+{
+ return NULL;
+}
+
+static void DEH_MiscParseLine(deh_context_t *context, char *line, void *tag)
+{
+ char *variable_name, *value;
+ int ivalue;
+ size_t i;
+
+ if (!DEH_ParseAssignment(line, &variable_name, &value))
+ {
+ // Failed to parse
+
+ DEH_Warning(context, "Failed to parse assignment");
+ return;
+ }
+
+ ivalue = atoi(value);
+
+ if (!strcasecmp(variable_name, "Monsters Infight"))
+ {
+ // See notes above.
+
+ if (ivalue == 202)
+ {
+ deh_species_infighting = 0;
+ }
+ else if (ivalue == 221)
+ {
+ deh_species_infighting = 1;
+ }
+ else
+ {
+ DEH_Warning(context,
+ "Invalid value for 'Monsters Infight': %i", ivalue);
+ }
+
+ return;
+ }
+
+ for (i=0; i<arrlen(misc_settings); ++i)
+ {
+ if (!strcasecmp(variable_name, misc_settings[i].deh_name))
+ {
+ *misc_settings[i].value = ivalue;
+ return;
+ }
+ }
+
+ DEH_Warning(context, "Unknown Misc variable '%s'", variable_name);
+}
+
+static void DEH_MiscSHA1Sum(sha1_context_t *context)
+{
+ unsigned int i;
+
+ for (i=0; i<arrlen(misc_settings); ++i)
+ {
+ SHA1_UpdateInt32(context, *misc_settings[i].value);
+ }
+}
+
+deh_section_t deh_section_misc =
+{
+ "Misc",
+ NULL,
+ DEH_MiscStart,
+ DEH_MiscParseLine,
+ NULL,
+ DEH_MiscSHA1Sum,
+};
+
diff --git a/src/strife/deh_misc.h b/src/strife/deh_misc.h
new file mode 100644
index 00000000..a589b104
--- /dev/null
+++ b/src/strife/deh_misc.h
@@ -0,0 +1,92 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// Parses "Misc" sections in dehacked files
+//
+//-----------------------------------------------------------------------------
+
+#ifndef DEH_MISC_H
+#define DEH_MISC_H
+
+#include "doomfeatures.h"
+
+#define DEH_DEFAULT_INITIAL_HEALTH 100
+#define DEH_DEFAULT_INITIAL_BULLETS 50
+#define DEH_DEFAULT_MAX_HEALTH 200
+#define DEH_DEFAULT_MAX_ARMOR 200
+#define DEH_DEFAULT_GREEN_ARMOR_CLASS 1
+#define DEH_DEFAULT_BLUE_ARMOR_CLASS 2
+#define DEH_DEFAULT_MAX_SOULSPHERE 200
+#define DEH_DEFAULT_SOULSPHERE_HEALTH 100
+#define DEH_DEFAULT_MEGASPHERE_HEALTH 200
+#define DEH_DEFAULT_GOD_MODE_HEALTH 100
+#define DEH_DEFAULT_IDFA_ARMOR 200
+#define DEH_DEFAULT_IDFA_ARMOR_CLASS 2
+#define DEH_DEFAULT_IDKFA_ARMOR 200
+#define DEH_DEFAULT_IDKFA_ARMOR_CLASS 2
+#define DEH_DEFAULT_BFG_CELLS_PER_SHOT 40
+#define DEH_DEFAULT_SPECIES_INFIGHTING 0
+
+#ifdef FEATURE_DEHACKED
+
+extern int deh_initial_health;
+extern int deh_initial_bullets;
+extern int deh_max_health;
+extern int deh_max_armor;
+extern int deh_green_armor_class;
+extern int deh_blue_armor_class;
+extern int deh_max_soulsphere;
+extern int deh_soulsphere_health;
+extern int deh_megasphere_health;
+extern int deh_god_mode_health;
+extern int deh_idfa_armor;
+extern int deh_idfa_armor_class;
+extern int deh_idkfa_armor;
+extern int deh_idkfa_armor_class;
+extern int deh_bfg_cells_per_shot;
+extern int deh_species_infighting;
+
+#else
+
+// If dehacked is disabled, hard coded values
+
+#define deh_initial_health DEH_DEFAULT_INITIAL_HEALTH
+#define deh_initial_bullets DEH_DEFAULT_INITIAL_BULLETS
+#define deh_max_health DEH_DEFAULT_MAX_HEALTH
+#define deh_max_armor DEH_DEFAULT_MAX_ARMOR
+#define deh_green_armor_class DEH_DEFAULT_GREEN_ARMOR_CLASS
+#define deh_blue_armor_class DEH_DEFAULT_BLUE_ARMOR_CLASS
+#define deh_max_soulsphere DEH_DEFAULT_MAX_SOULSPHERE
+#define deh_soulsphere_health DEH_DEFAULT_SOULSPHERE_HEALTH
+#define deh_megasphere_health DEH_DEFAULT_MEGASPHERE_HEALTH
+#define deh_god_mode_health DEH_DEFAULT_GOD_MODE_HEALTH
+#define deh_idfa_armor DEH_DEFAULT_IDFA_ARMOR
+#define deh_idfa_armor_class DEH_DEFAULT_IDFA_ARMOR_CLASS
+#define deh_idkfa_armor DEH_DEFAULT_IDKFA_ARMOR
+#define deh_idkfa_armor_class DEH_DEFAULT_IDKFA_ARMOR_CLASS
+#define deh_bfg_cells_per_shot DEH_DEFAULT_BFG_CELLS_PER_SHOT
+#define deh_species_infighting DEH_DEFAULT_SPECIES_INFIGHTING
+
+#endif
+
+#endif /* #ifndef DEH_MISC_H */
+
diff --git a/src/strife/deh_ptr.c b/src/strife/deh_ptr.c
new file mode 100644
index 00000000..0d1764c9
--- /dev/null
+++ b/src/strife/deh_ptr.c
@@ -0,0 +1,151 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// Parses Action Pointer entries in dehacked files
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "doomtype.h"
+#include "info.h"
+
+#include "deh_defs.h"
+#include "deh_io.h"
+#include "deh_main.h"
+
+static actionf_t codeptrs[NUMSTATES];
+
+static int CodePointerIndex(actionf_t *ptr)
+{
+ int i;
+
+ for (i=0; i<NUMSTATES; ++i)
+ {
+ if (!memcmp(&codeptrs[i], ptr, sizeof(actionf_t)))
+ {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+static void DEH_PointerInit(void)
+{
+ int i;
+
+ // Initialize list of dehacked pointers
+
+ for (i=0; i<NUMSTATES; ++i)
+ codeptrs[i] = states[i].action;
+}
+
+static void *DEH_PointerStart(deh_context_t *context, char *line)
+{
+ int frame_number = 0;
+
+ // FIXME: can the third argument here be something other than "Frame"
+ // or are we ok?
+
+ if (sscanf(line, "Pointer %*i (%*s %i)", &frame_number) != 1)
+ {
+ DEH_Warning(context, "Parse error on section start");
+ return NULL;
+ }
+
+ if (frame_number < 0 || frame_number >= NUMSTATES)
+ {
+ DEH_Warning(context, "Invalid frame number: %i", frame_number);
+ return NULL;
+ }
+
+ return &states[frame_number];
+}
+
+static void DEH_PointerParseLine(deh_context_t *context, char *line, void *tag)
+{
+ state_t *state;
+ char *variable_name, *value;
+ int ivalue;
+
+ if (tag == NULL)
+ return;
+
+ state = (state_t *) tag;
+
+ // Parse the assignment
+
+ if (!DEH_ParseAssignment(line, &variable_name, &value))
+ {
+ // Failed to parse
+ DEH_Warning(context, "Failed to parse assignment");
+ return;
+ }
+
+// printf("Set %s to %s for state\n", variable_name, value);
+
+ // all values are integers
+
+ ivalue = atoi(value);
+
+ // set the appropriate field
+
+ if (!strcasecmp(variable_name, "Codep frame"))
+ {
+ if (ivalue < 0 || ivalue >= NUMSTATES)
+ {
+ DEH_Warning(context, "Invalid state '%i'", ivalue);
+ }
+ else
+ {
+ state->action = codeptrs[ivalue];
+ }
+ }
+ else
+ {
+ DEH_Warning(context, "Unknown variable name '%s'", variable_name);
+ }
+}
+
+static void DEH_PointerSHA1Sum(sha1_context_t *context)
+{
+ int i;
+
+ for (i=0; i<NUMSTATES; ++i)
+ {
+ SHA1_UpdateInt32(context, CodePointerIndex(&states[i].action));
+ }
+}
+
+deh_section_t deh_section_pointer =
+{
+ "Pointer",
+ DEH_PointerInit,
+ DEH_PointerStart,
+ DEH_PointerParseLine,
+ NULL,
+ DEH_PointerSHA1Sum,
+};
+
diff --git a/src/strife/deh_sound.c b/src/strife/deh_sound.c
new file mode 100644
index 00000000..251cdccb
--- /dev/null
+++ b/src/strife/deh_sound.c
@@ -0,0 +1,112 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// Parses "Sound" sections in dehacked files
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "doomfeatures.h"
+#include "doomtype.h"
+#include "deh_defs.h"
+#include "deh_main.h"
+#include "deh_mapping.h"
+#include "sounds.h"
+
+DEH_BEGIN_MAPPING(sound_mapping, sfxinfo_t)
+ DEH_UNSUPPORTED_MAPPING("Offset")
+ DEH_UNSUPPORTED_MAPPING("Zero/One")
+ DEH_MAPPING("Value", priority)
+ DEH_MAPPING("Zero 1", link)
+ DEH_MAPPING("Zero 2", pitch)
+ DEH_MAPPING("Zero 3", volume)
+ DEH_UNSUPPORTED_MAPPING("Zero 4")
+ DEH_MAPPING("Neg. One 1", usefulness)
+ DEH_MAPPING("Neg. One 2", lumpnum)
+DEH_END_MAPPING
+
+static void *DEH_SoundStart(deh_context_t *context, char *line)
+{
+ int sound_number = 0;
+
+ if (sscanf(line, "Sound %i", &sound_number) != 1)
+ {
+ DEH_Warning(context, "Parse error on section start");
+ return NULL;
+ }
+
+ if (sound_number < 0 || sound_number >= NUMSFX)
+ {
+ DEH_Warning(context, "Invalid sound number: %i", sound_number);
+ return NULL;
+ }
+
+ if (sound_number >= DEH_VANILLA_NUMSFX)
+ {
+ DEH_Warning(context, "Attempt to modify SFX %i. This will cause "
+ "problems in Vanilla dehacked.", sound_number);
+ }
+
+ return &S_sfx[sound_number];
+}
+
+static void DEH_SoundParseLine(deh_context_t *context, char *line, void *tag)
+{
+ sfxinfo_t *sfx;
+ char *variable_name, *value;
+ int ivalue;
+
+ if (tag == NULL)
+ return;
+
+ sfx = (sfxinfo_t *) tag;
+
+ // Parse the assignment
+
+ if (!DEH_ParseAssignment(line, &variable_name, &value))
+ {
+ // Failed to parse
+ DEH_Warning(context, "Failed to parse assignment");
+ return;
+ }
+
+ // all values are integers
+
+ ivalue = atoi(value);
+
+ // Set the field value
+
+ DEH_SetMapping(context, &sound_mapping, sfx, variable_name, ivalue);
+}
+
+deh_section_t deh_section_sound =
+{
+ "Sound",
+ NULL,
+ DEH_SoundStart,
+ DEH_SoundParseLine,
+ NULL,
+ NULL,
+};
+
diff --git a/src/strife/deh_strife.c b/src/strife/deh_strife.c
new file mode 100644
index 00000000..bda411c0
--- /dev/null
+++ b/src/strife/deh_strife.c
@@ -0,0 +1,74 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// Top-level dehacked definitions for Strife dehacked (sehacked)
+//
+//-----------------------------------------------------------------------------
+
+#include <stdlib.h>
+#include "deh_defs.h"
+#include "deh_main.h"
+
+char *deh_signatures[] =
+{
+ "Patch File for SeHackEd v0.4",
+ "Patch File for SeHackEd v0.3",
+ NULL
+};
+
+// deh_ammo.c:
+extern deh_section_t deh_section_ammo;
+// deh_cheat.c:
+extern deh_section_t deh_section_cheat;
+// deh_frame.c:
+extern deh_section_t deh_section_frame;
+// deh_misc.c:
+extern deh_section_t deh_section_misc;
+// deh_ptr.c:
+extern deh_section_t deh_section_pointer;
+// deh_sound.c
+extern deh_section_t deh_section_sound;
+// deh_text.c:
+extern deh_section_t deh_section_text;
+// deh_thing.c:
+extern deh_section_t deh_section_thing;
+// deh_weapon.c:
+extern deh_section_t deh_section_weapon;
+
+//
+// List of section types:
+//
+
+deh_section_t *deh_section_types[] =
+{
+ &deh_section_ammo,
+ &deh_section_cheat,
+ &deh_section_frame,
+ &deh_section_misc,
+ &deh_section_pointer,
+ &deh_section_sound,
+ &deh_section_text,
+ &deh_section_thing,
+ &deh_section_weapon,
+ NULL
+};
+
diff --git a/src/strife/deh_thing.c b/src/strife/deh_thing.c
new file mode 100644
index 00000000..a1c1f94d
--- /dev/null
+++ b/src/strife/deh_thing.c
@@ -0,0 +1,141 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// Parses "Thing" sections in dehacked files
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "doomtype.h"
+
+#include "deh_defs.h"
+#include "deh_main.h"
+#include "deh_mapping.h"
+
+#include "info.h"
+
+DEH_BEGIN_MAPPING(thing_mapping, mobjinfo_t)
+ DEH_MAPPING("ID #", doomednum)
+ DEH_MAPPING("Initial frame", spawnstate)
+ DEH_MAPPING("Hit points", spawnhealth)
+ DEH_MAPPING("First moving frame", seestate)
+ DEH_MAPPING("Alert sound", seesound)
+ DEH_MAPPING("Reaction time", reactiontime)
+ DEH_MAPPING("Attack sound", attacksound)
+ DEH_MAPPING("Injury frame", painstate)
+ DEH_MAPPING("Pain chance", painchance)
+ DEH_MAPPING("Pain sound", painsound)
+ DEH_MAPPING("Close attack frame", meleestate)
+ DEH_MAPPING("Far attack frame", missilestate)
+ DEH_MAPPING("Crash frame", crashstate)
+ DEH_MAPPING("Death frame", deathstate)
+ DEH_MAPPING("Exploding frame", xdeathstate)
+ DEH_MAPPING("Death sound", deathsound)
+ DEH_MAPPING("Speed", speed)
+ DEH_MAPPING("Width", radius)
+ DEH_MAPPING("Height", height)
+ DEH_MAPPING("Mass", mass)
+ DEH_MAPPING("Missile damage", damage)
+ DEH_MAPPING("Action sound", activesound)
+ DEH_MAPPING("Bits", flags)
+ DEH_UNSUPPORTED_MAPPING("Name pointer")
+DEH_END_MAPPING
+
+static void *DEH_ThingStart(deh_context_t *context, char *line)
+{
+ int thing_number = 0;
+ mobjinfo_t *mobj;
+
+ if (sscanf(line, "Thing %i", &thing_number) != 1)
+ {
+ DEH_Warning(context, "Parse error on section start");
+ return NULL;
+ }
+
+ // dehacked files are indexed from 1
+ --thing_number;
+
+ if (thing_number < 0 || thing_number >= NUMMOBJTYPES)
+ {
+ DEH_Warning(context, "Invalid thing number: %i", thing_number);
+ return NULL;
+ }
+
+ mobj = &mobjinfo[thing_number];
+
+ return mobj;
+}
+
+static void DEH_ThingParseLine(deh_context_t *context, char *line, void *tag)
+{
+ mobjinfo_t *mobj;
+ char *variable_name, *value;
+ int ivalue;
+
+ if (tag == NULL)
+ return;
+
+ mobj = (mobjinfo_t *) tag;
+
+ // Parse the assignment
+
+ if (!DEH_ParseAssignment(line, &variable_name, &value))
+ {
+ // Failed to parse
+
+ DEH_Warning(context, "Failed to parse assignment");
+ return;
+ }
+
+// printf("Set %s to %s for mobj\n", variable_name, value);
+
+ // all values are integers
+
+ ivalue = atoi(value);
+
+ // Set the field value
+
+ DEH_SetMapping(context, &thing_mapping, mobj, variable_name, ivalue);
+}
+
+static void DEH_ThingSHA1Sum(sha1_context_t *context)
+{
+ int i;
+
+ for (i=0; i<NUMMOBJTYPES; ++i)
+ {
+ DEH_StructSHA1Sum(context, &thing_mapping, &mobjinfo[i]);
+ }
+}
+
+deh_section_t deh_section_thing =
+{
+ "Thing",
+ NULL,
+ DEH_ThingStart,
+ DEH_ThingParseLine,
+ NULL,
+ DEH_ThingSHA1Sum,
+};
+
diff --git a/src/strife/deh_weapon.c b/src/strife/deh_weapon.c
new file mode 100644
index 00000000..67cbe5b6
--- /dev/null
+++ b/src/strife/deh_weapon.c
@@ -0,0 +1,111 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// Parses "Weapon" sections in dehacked files
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "doomtype.h"
+
+#include "d_items.h"
+
+#include "deh_defs.h"
+#include "deh_main.h"
+#include "deh_mapping.h"
+
+DEH_BEGIN_MAPPING(weapon_mapping, weaponinfo_t)
+ DEH_MAPPING("Ammo type", ammo)
+ DEH_MAPPING("Deselect frame", upstate)
+ DEH_MAPPING("Select frame", downstate)
+ DEH_MAPPING("Bobbing frame", readystate)
+ DEH_MAPPING("Shooting frame", atkstate)
+ DEH_MAPPING("Firing frame", flashstate)
+ DEH_UNSUPPORTED_MAPPING("? Unknown")
+DEH_END_MAPPING
+
+static void *DEH_WeaponStart(deh_context_t *context, char *line)
+{
+ int weapon_number = 0;
+
+ if (sscanf(line, "Weapon %i", &weapon_number) != 1)
+ {
+ DEH_Warning(context, "Parse error on section start");
+ return NULL;
+ }
+
+ if (weapon_number < 0 || weapon_number >= NUMWEAPONS)
+ {
+ DEH_Warning(context, "Invalid weapon number: %i", weapon_number);
+ return NULL;
+ }
+
+ return &weaponinfo[weapon_number];
+}
+
+static void DEH_WeaponParseLine(deh_context_t *context, char *line, void *tag)
+{
+ char *variable_name, *value;
+ weaponinfo_t *weapon;
+ int ivalue;
+
+ if (tag == NULL)
+ return;
+
+ weapon = (weaponinfo_t *) tag;
+
+ if (!DEH_ParseAssignment(line, &variable_name, &value))
+ {
+ // Failed to parse
+
+ DEH_Warning(context, "Failed to parse assignment");
+ return;
+ }
+
+ ivalue = atoi(value);
+
+ DEH_SetMapping(context, &weapon_mapping, weapon, variable_name, ivalue);
+}
+
+static void DEH_WeaponSHA1Sum(sha1_context_t *context)
+{
+ int i;
+
+ for (i=0; i<NUMWEAPONS ;++i)
+ {
+ DEH_StructSHA1Sum(context, &weapon_mapping, &weaponinfo[i]);
+ }
+}
+
+deh_section_t deh_section_weapon =
+{
+ "Weapon",
+ NULL,
+ DEH_WeaponStart,
+ DEH_WeaponParseLine,
+ NULL,
+ DEH_WeaponSHA1Sum,
+};
+
diff --git a/src/strife/doomdata.h b/src/strife/doomdata.h
new file mode 100644
index 00000000..db57a539
--- /dev/null
+++ b/src/strife/doomdata.h
@@ -0,0 +1,233 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// 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;
+} PACKEDATTR 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;
+} PACKEDATTR 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];
+} PACKEDATTR 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
+
+// villsa [STRIFE] jump over rails?
+#define ML_JUMPOVER 512
+
+// villsa [STRIFE] block flying things
+#define ML_BLOCKFLOATERS 1024
+
+// villsa [STRIFE] TODO - 25% or 75% transcluency?
+#define ML_TRANSPARENT1 2048
+
+// villsa [STRIFE] TODO - 25% or 75% transcluency?
+#define ML_TRANSPARENT2 4096
+
+
+
+
+// Sector definition, from editing.
+typedef struct
+{
+ short floorheight;
+ short ceilingheight;
+ char floorpic[8];
+ char ceilingpic[8];
+ short lightlevel;
+ short special;
+ short tag;
+} PACKEDATTR mapsector_t;
+
+// SubSector, as generated by BSP.
+typedef struct
+{
+ short numsegs;
+ // Index of first one, segs are stored sequentially.
+ short firstseg;
+} PACKEDATTR 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;
+} PACKEDATTR 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];
+
+} PACKEDATTR 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;
+} PACKEDATTR mapthing_t;
+
+
+
+
+
+#endif // __DOOMDATA__
diff --git a/src/strife/doomdef.c b/src/strife/doomdef.c
new file mode 100644
index 00000000..1ad48525
--- /dev/null
+++ b/src/strife/doomdef.c
@@ -0,0 +1,36 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// DoomDef - basic defines for DOOM, e.g. Version, game mode
+// and skill level, and display parameters.
+//
+//-----------------------------------------------------------------------------
+
+
+
+#include "doomdef.h"
+
+// Location for any defines turned variables.
+
+// None.
+
+
diff --git a/src/strife/doomdef.h b/src/strife/doomdef.h
new file mode 100644
index 00000000..d48b41ee
--- /dev/null
+++ b/src/strife/doomdef.h
@@ -0,0 +1,299 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Internally used data structures for virtually everything,
+// lots of other stuff.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef __DOOMDEF__
+#define __DOOMDEF__
+
+#include <stdio.h>
+#include <string.h>
+
+#include "doomtype.h"
+#include "i_timer.h"
+#include "d_mode.h"
+
+//
+// Global parameters/defines.
+//
+// DOOM version
+//
+// haleyjd 09/28/10: Replaced with Strife version
+#define STRIFE_VERSION 101
+
+// Version code for cph's longtics hack ("v1.91")
+#define DOOM_191_VERSION 111
+
+
+// Maximum players for Strife:
+#define MAXPLAYERS 8
+
+// If rangecheck is undefined,
+// most parameter validation debugging code will not be compiled
+#define RANGECHECK
+
+// 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_UNKNOWN,
+ GS_FINALE,
+ GS_DEMOSCREEN,
+} gamestate_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;
+
+//
+// Difficulty/skill settings/filters.
+//
+
+// Skill flags.
+#define MTF_EASY 1
+#define MTF_NORMAL 2
+#define MTF_HARD 4
+// villsa [STRIFE] standing monsters
+#define MTF_STAND 8
+// villsa [STRIFE] don't spawn in single player
+#define MTF_NOTSINGLE 16
+// Deaf monsters/do not react to sound.
+#define MTF_AMBUSH 32
+// villsa [STRIFE] friendly to players
+#define MTF_FRIEND 64
+// villsa [STRIFE] TODO - identify
+#define MTF_UNKNOWN1 128
+// villsa [STRIFE] thing is translucent - STRIFE-TODO: But how much?
+#define MTF_TRANSLUCENT 256
+// villsa [STRIFE] thing is more - or less? - translucent - STRIFE-TODO
+#define MTF_MVIS 512
+// villsa [STRIFE] TODO - identify
+#define MTF_UNKNOWN2 1024
+
+
+
+//
+// Key cards.
+//
+// villsa [STRIFE]
+typedef enum
+{
+ key_BaseKey, // 0
+ key_GovsKey, // 1
+ key_Passcard, // 2
+ key_IDCard, // 3
+ key_PrisonKey, // 4
+ key_SeveredHand, // 5
+ key_Power1Key, // 6
+ key_Power2Key, // 7
+ key_Power3Key, // 8
+ key_GoldKey, // 9
+ key_IDBadge, // 10
+ key_SilverKey, // 11
+ key_OracleKey, // 12
+ key_MilitaryID, // 13
+ key_OrderKey, // 14
+ key_WarehouseKey, // 15
+ key_BrassKey, // 16
+ key_RedCrystalKey, // 17
+ key_BlueCrystalKey, // 18
+ key_ChapelKey, // 19
+ key_CatacombKey, // 20
+ key_SecurityKey, // 21
+ key_CoreKey, // 22
+ key_MaulerKey, // 23
+ key_FactoryKey, // 24
+ key_MineKey, // 25
+ key_NewKey5, // 26
+
+ NUMCARDS // 27
+} card_t;
+
+
+
+// The defined weapons,
+// including a marker indicating
+// user has not changed weapon.
+// villsa [STRIFE]
+typedef enum
+{
+ wp_fist,
+ wp_elecbow,
+ wp_rifle,
+ wp_missile,
+ wp_hegrenade,
+ wp_flame,
+ wp_mauler,
+ wp_sigil,
+ wp_poisonbow,
+ wp_wpgrenade,
+ wp_torpedo,
+
+ NUMWEAPONS,
+
+ // No pending weapon change.
+ wp_nochange
+
+} weapontype_t;
+
+
+// Ammunition types defined.
+typedef enum
+{
+ am_bullets,
+ am_elecbolts,
+ am_poisonbolts,
+ am_cell,
+ am_missiles,
+ am_hegrenades,
+ am_wpgrenades,
+
+ NUMAMMO,
+
+ am_noammo // unlimited ammo
+
+} ammotype_t;
+
+
+// Power up artifacts.
+// villsa [STRIFE]
+typedef enum
+{
+ pw_strength,
+ pw_invisibility,
+ pw_ironfeet,
+ pw_allmap,
+ pw_communicator,
+ pw_targeter,
+ NUMPOWERS
+
+} powertype_t;
+
+// villsa [STRIFE]
+// quest numbers
+typedef enum
+{ // Hex Watcom Name player_t offset
+ tk_quest1, // 0x00000001 questflags & 1 0x4D
+ tk_quest2, // 0x00000002 questflags & 2
+ tk_quest3, // 0x00000004 questflags & 4
+ tk_quest4, // 0x00000008 questflags & 8
+ tk_quest5, // 0x00000010 questflags & 10h
+ tk_quest6, // 0x00000020 questflags & 20h
+ tk_quest7, // 0x00000040 questflags & 40h
+ tk_quest8, // 0x00000080 questflags & 80h
+ tk_quest9, // 0x00000100 BYTE1(questflags) & 1 0x4E
+ tk_quest10, // 0x00000200 BYTE1(questflags) & 2
+ tk_quest11, // 0x00000400 BYTE1(questflags) & 4
+ tk_quest12, // 0x00000800 BYTE1(questflags) & 8
+ tk_quest13, // 0x00001000 BYTE1(questflags) & 10h
+ tk_quest14, // 0x00002000 BYTE1(questflags) & 20h
+ tk_quest15, // 0x00004000 BYTE1(questflags) & 40h
+ tk_quest16, // 0x00008000 BYTE1(questflags) & 80h
+ tk_quest17, // 0x00010000 BYTE2(questflags) & 1 0x4F
+ tk_quest18, // 0x00020000 BYTE2(questflags) & 2
+ tk_quest19, // 0x00040000 BYTE2(questflags) & 4
+ tk_quest20, // 0x00080000 BYTE2(questflags) & 8
+ tk_quest21, // 0x00100000 BYTE2(questflags) & 10h
+ tk_quest22, // 0x00200000 BYTE2(questflags) & 20h
+ tk_quest23, // 0x00400000 BYTE2(questflags) & 40h
+ tk_quest24, // 0x00800000 BYTE2(questflags) & 80h
+ tk_quest25, // 0x01000000 BYTE3(questflags) & 1 0x50
+ tk_quest26, // 0x02000000 BYTE3(questflags) & 2
+ tk_quest27, // 0x04000000 BYTE3(questflags) & 4
+ tk_quest28, // 0x08000000 BYTE3(questflags) & 8
+ tk_quest29, // 0x10000000 BYTE3(questflags) & 10h
+ tk_quest30, // 0x20000000 BYTE3(questflags) & 20h
+ tk_quest31, // 0x40000000 BYTE3(questflags) & 40h
+ tk_quest32, // most likely unused
+ tk_numquests
+} questtype_t;
+
+// haleyjd 09/12/10: [STRIFE]
+// flag values for each quest.
+enum
+{ // Name Flag from bitnum Purpose, if known
+ QF_QUEST1 = (1 << tk_quest1), // Obtained Beldin's ring
+ QF_QUEST2 = (1 << tk_quest2), // Stole the Chalice
+ QF_QUEST3 = (1 << tk_quest3), // Permission to visit Irale (visited Macil)
+ QF_QUEST4 = (1 << tk_quest4), // Accepted Gov. Mourel's "messy" chore
+ QF_QUEST5 = (1 << tk_quest5), // Accepted Gov. Mourel's "bloody" chore
+ QF_QUEST6 = (1 << tk_quest6), // Destroyed the Power Coupling
+ QF_QUEST7 = (1 << tk_quest7), // Killed Blue Acolytes ("Scanning Team")
+ QF_QUEST8 = (1 << tk_quest8), // Unused; formerly, picked up Broken Coupling
+ QF_QUEST9 = (1 << tk_quest9), // Obtained Derwin's ear
+ QF_QUEST10 = (1 << tk_quest10), // Obtained Prison Pass
+ QF_QUEST11 = (1 << tk_quest11), // Obtained Prison Key
+ QF_QUEST12 = (1 << tk_quest12), // Obtained Judge Wolenick's hand
+ QF_QUEST13 = (1 << tk_quest13), // Freed the Prisoners
+ QF_QUEST14 = (1 << tk_quest14), // Destroyed the Power Crystal
+ QF_QUEST15 = (1 << tk_quest15), // Obtained Guard Uniform
+ QF_QUEST16 = (1 << tk_quest16), // Destroyed the Gate Mechanism
+ QF_QUEST17 = (1 << tk_quest17), // Heard Macil's story about the Sigil (MAP10)
+ QF_QUEST18 = (1 << tk_quest18), // Obtained Oracle Pass
+ QF_QUEST19 = (1 << tk_quest19),
+ QF_QUEST20 = (1 << tk_quest20),
+ QF_QUEST21 = (1 << tk_quest21), // Killed Bishop
+ QF_QUEST22 = (1 << tk_quest22), // Killed Oracle with QUEST21 set
+ QF_QUEST23 = (1 << tk_quest23), // Killed Oracle (always given)
+ QF_QUEST24 = (1 << tk_quest24), // Killed Macil
+ QF_QUEST25 = (1 << tk_quest25), // Destroyed the Converter
+ QF_QUEST26 = (1 << tk_quest26), // Killed Loremaster
+ QF_QUEST27 = (1 << tk_quest27), // Destroyed the Computer (checked for good ending)
+ QF_QUEST28 = (1 << tk_quest28), // Obtained Catacomb Key (checked by line type 228)
+ QF_QUEST29 = (1 << tk_quest29), // Destroyed the Mines Transmitter
+ QF_QUEST30 = (1 << tk_quest30),
+ QF_QUEST31 = (1 << tk_quest31),
+ QF_QUEST32 = (1 << tk_quest32), // Unused; BUG: Broken Coupling accidentally sets it.
+
+ QF_ALLQUESTS = (QF_QUEST31 + (QF_QUEST31 - 1)) // does not include bit 32!
+};
+
+//
+// Power up durations,
+// how many seconds till expiration,
+// assuming TICRATE is 35 ticks/second.
+//
+typedef enum
+{
+ INVISTICS = (55*TICRATE), // villsa [STRIFE] changed from 60 to 55
+ IRONTICS = (80*TICRATE), // villsa [STRIFE] changed from 60 to 80
+ PMUPTICS = (80*TICRATE), // villsa [STRIFE]
+ TARGTICS = (160*TICRATE),// villsa [STRIFE]
+
+} powerduration_t;
+
+#endif // __DOOMDEF__
diff --git a/src/strife/doomstat.c b/src/strife/doomstat.c
new file mode 100644
index 00000000..df1c34ab
--- /dev/null
+++ b/src/strife/doomstat.c
@@ -0,0 +1,43 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Put all global tate variables here.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+
+#include "doomstat.h"
+
+
+// Game Mode - identify IWAD as shareware, retail etc.
+GameMode_t gamemode = indetermined;
+GameMission_t gamemission = doom;
+GameVersion_t gameversion = exe_strife_1_31;
+char *gamedescription;
+
+// Set if homebrew PWAD stuff has been added.
+boolean modifiedgame;
+
+
+
+
diff --git a/src/strife/doomstat.h b/src/strife/doomstat.h
new file mode 100644
index 00000000..1d2d191d
--- /dev/null
+++ b/src/strife/doomstat.h
@@ -0,0 +1,286 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// 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_loop.h"
+
+// We need the playr data structure as well.
+#include "d_player.h"
+
+// Game mode/mission
+#include "d_mode.h"
+
+#include "net_defs.h"
+
+
+
+// ------------------------
+// Command line parameters.
+//
+extern boolean nomonsters; // checkparm of -nomonsters
+extern boolean respawnparm; // checkparm of -respawn
+extern boolean fastparm; // checkparm of -fast
+extern boolean flipparm; // [STRIFE] checkparm of -flip
+
+extern boolean devparm; // DEBUG: launched with -devparm
+
+
+// -----------------------------------------------------
+// Game Mode - identify IWAD as shareware, retail etc.
+//
+extern GameMode_t gamemode;
+extern GameMission_t gamemission;
+extern GameVersion_t gameversion;
+extern char *gamedescription;
+
+// Set if homebrew PWAD stuff has been added.
+extern boolean modifiedgame;
+
+
+// -------------------------------------------
+// Selected skill type, map etc.
+//
+
+// Defaults for menu, methinks.
+extern skill_t startskill;
+extern int startepisode;
+extern int startmap;
+
+// Savegame slot to load on startup. This is the value provided to
+// the -loadgame option. If this has not been provided, this is -1.
+
+extern int startloadgame;
+
+extern boolean autostart;
+
+// Selected by user.
+extern skill_t gameskill;
+extern int gameepisode;
+extern int gamemap;
+
+// If non-zero, exit the level after this number of minutes
+extern int timelimit;
+
+// Nightmare mode flag, single player.
+extern boolean respawnmonsters;
+
+// Netgame? Only true if >1 player.
+extern boolean netgame;
+
+// Flag: true only if started as net deathmatch.
+// An enum might handle altdeath/cooperative better.
+extern 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.
+
+// From m_menu.c:
+// Sound FX volume has default, 0 - 15
+// Music volume has default, 0 - 15
+// These are multiplied by 8.
+extern int sfxVolume;
+extern int musicVolume;
+extern int voiceVolume; // haleyjd 08/29/10: [STRIFE]
+
+// 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 boolean statusbaractive;
+
+extern boolean automapactive; // In AutoMap mode?
+extern boolean menuactive; // Menu overlayed?
+extern boolean menupause; // haleyjd 08/29/10: [STRIFE]
+extern int menupausetime; // haleyjd 09/04/10: [STRIFE]
+extern boolean menuindialog; // haleyjd: ditto
+extern boolean paused; // Game Pause?
+
+
+extern boolean viewactive;
+
+extern boolean nodrawers;
+
+extern boolean testcontrols;
+extern int testcontrols_mousespeed;
+
+
+
+
+// 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; [STRIFE] unused
+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 boolean usergame;
+
+//?
+extern boolean demoplayback;
+extern boolean demorecording;
+extern int mouse_fire_countdown; // villsa [STRIFE]
+
+// Round angleturn in ticcmds to the nearest 256. This is used when
+// recording Vanilla demos in netgames.
+
+extern boolean lowres_turn;
+
+// Quit after playing a demo from cmdline.
+extern 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.
+
+
+// Bookkeeping on players - state.
+extern player_t players[MAXPLAYERS];
+
+// Alive? Disconnected?
+extern 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];
+
+// haleyjd 08/24/10: [STRIFE] rift spots
+#define MAXRIFTSPOTS 16
+extern mapthing_t riftSpots[MAXRIFTSPOTS];
+
+// Intermission stats.
+// Parameters for world map / intermission.
+extern wbstartstruct_t wminfo;
+
+
+
+
+
+
+//-----------------------------------------
+// Internal parameters, used for engine.
+//
+
+// File handling stuff.
+extern char * savegamedir;
+extern char basedefault[1024];
+
+// if true, load all graphics at level load
+extern boolean precache;
+
+
+// wipegamestate can be set to -1
+// to force a wipe on the next draw
+extern gamestate_t wipegamestate;
+
+extern int mouseSensitivity;
+
+//extern int bodyqueslot; [STRIFE] unused
+
+
+
+// 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).
+
+
+extern int rndindex;
+
+extern ticcmd_t *netcmds;
+
+
+
+#endif
diff --git a/src/strife/dstrings.c b/src/strife/dstrings.c
new file mode 100644
index 00000000..01a438ae
--- /dev/null
+++ b/src/strife/dstrings.c
@@ -0,0 +1,81 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Globally defined strings.
+//
+//-----------------------------------------------------------------------------
+
+
+
+#include "dstrings.h"
+
+char *doom1_endmsg[] =
+{
+ "are you sure you want to\nquit this great game?",
+ "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.",
+};
+
+char *doom2_endmsg[] =
+{
+ // QuitDOOM II messages
+ "are you sure you want to\nquit this great game?",
+ "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.",
+};
+
+#if 0
+
+// UNUSED messages included in the source release
+
+char* endmsg[] =
+{
+ // DOOM1
+ QUITMSG,
+ // 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."
+};
+
+#endif
+
+
+
+
diff --git a/src/strife/dstrings.h b/src/strife/dstrings.h
new file mode 100644
index 00000000..d47fc1af
--- /dev/null
+++ b/src/strife/dstrings.h
@@ -0,0 +1,49 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//
+// DESCRIPTION:
+// DOOM strings, by language.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __DSTRINGS__
+#define __DSTRINGS__
+
+
+// All important printed strings.
+
+#include "d_englsh.h"
+
+// Misc. other strings.
+#define SAVEGAMENAME "doomsav"
+
+
+// QuitDOOM messages
+// 8 per each game type
+#define NUM_QUITMESSAGES 8
+
+extern char *doom1_endmsg[];
+extern char *doom2_endmsg[];
+
+
+#endif
diff --git a/src/strife/f_finale.c b/src/strife/f_finale.c
new file mode 100644
index 00000000..fff2aa9f
--- /dev/null
+++ b/src/strife/f_finale.c
@@ -0,0 +1,1056 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+// Copyright(C) 2010 James Haley, Samuel Villarreal
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Game completion, final screen animation.
+//
+// [STRIFE] Module marked finished 2010-09-13 22:56
+//
+//-----------------------------------------------------------------------------
+
+
+#include <stdio.h>
+#include <ctype.h>
+
+// Functions.
+#include "deh_main.h"
+#include "i_system.h"
+#include "i_swap.h"
+#include "z_zone.h"
+#include "v_video.h"
+#include "w_wad.h"
+#include "s_sound.h"
+
+// Data.
+#include "d_main.h"
+#include "dstrings.h"
+#include "sounds.h"
+
+#include "doomstat.h"
+#include "r_state.h"
+
+#include "p_dialog.h" // [STRIFE]
+
+typedef enum
+{
+ F_STAGE_TEXT,
+ F_STAGE_ARTSCREEN,
+ F_STAGE_CAST,
+} finalestage_t;
+
+// ?
+//#include "doomstat.h"
+//#include "r_local.h"
+//#include "f_finale.h"
+
+// Stage of animation:
+finalestage_t finalestage;
+
+unsigned int finalecount;
+
+// haleyjd 09/12/10: [STRIFE] Slideshow variables
+char *slideshow_panel;
+unsigned int slideshow_tics;
+int slideshow_state;
+
+// haleyjd 09/13/10: [STRIFE] All this is unused.
+/*
+#define TEXTSPEED 3
+#define TEXTWAIT 250
+
+typedef struct
+{
+ GameMission_t mission;
+ int episode, level;
+ char *background;
+ char *text;
+} textscreen_t;
+
+static textscreen_t textscreens[] =
+{
+ { doom, 1, 8, "FLOOR4_8", E1TEXT},
+ { doom, 2, 8, "SFLR6_1", E2TEXT},
+ { doom, 3, 8, "MFLR8_4", E3TEXT},
+ { doom, 4, 8, "MFLR8_3", E4TEXT},
+
+ { doom2, 1, 6, "SLIME16", C1TEXT},
+ { doom2, 1, 11, "RROCK14", C2TEXT},
+ { doom2, 1, 20, "RROCK07", C3TEXT},
+ { doom2, 1, 30, "RROCK17", C4TEXT},
+ { doom2, 1, 15, "RROCK13", C5TEXT},
+ { doom2, 1, 31, "RROCK19", C6TEXT},
+
+ { pack_tnt, 1, 6, "SLIME16", T1TEXT},
+ { pack_tnt, 1, 11, "RROCK14", T2TEXT},
+ { pack_tnt, 1, 20, "RROCK07", T3TEXT},
+ { pack_tnt, 1, 30, "RROCK17", T4TEXT},
+ { pack_tnt, 1, 15, "RROCK13", T5TEXT},
+ { pack_tnt, 1, 31, "RROCK19", T6TEXT},
+
+ { pack_plut, 1, 6, "SLIME16", P1TEXT},
+ { pack_plut, 1, 11, "RROCK14", P2TEXT},
+ { pack_plut, 1, 20, "RROCK07", P3TEXT},
+ { pack_plut, 1, 30, "RROCK17", P4TEXT},
+ { pack_plut, 1, 15, "RROCK13", P5TEXT},
+ { pack_plut, 1, 31, "RROCK19", P6TEXT},
+};
+
+char* finaletext;
+char* finaleflat;
+*/
+
+void F_StartCast (void);
+void F_CastTicker (void);
+boolean F_CastResponder (event_t *ev);
+void F_CastDrawer (void);
+
+// [STRIFE] - Slideshow states enumeration
+enum
+{
+ // Exit states
+ SLIDE_EXITHACK = -99, // Hacky exit - start a new dialog
+ SLIDE_HACKHACK = -9, // Bizarre unused state
+ SLIDE_EXIT = -1, // Exit to next finale state
+ SLIDE_CHOCO = -2, // haleyjd: This state is Choco-specific... see below.
+
+ // Unknown
+ SLIDE_UNKNOWN = 0, // Dunno what it's for, possibly unused
+
+ // MAP03 - Macil's Programmer exposition
+ SLIDE_PROGRAMMER1 = 1,
+ SLIDE_PROGRAMMER2,
+ SLIDE_PROGRAMMER3,
+ SLIDE_PROGRAMMER4, // Next state = -99
+
+ // MAP10 - Macil's Sigil exposition
+ SLIDE_SIGIL1 = 5,
+ SLIDE_SIGIL2,
+ SLIDE_SIGIL3,
+ SLIDE_SIGIL4, // Next state = -99
+
+ // MAP29 - Endings
+ // Good Ending
+ SLIDE_GOODEND1 = 10,
+ SLIDE_GOODEND2,
+ SLIDE_GOODEND3,
+ SLIDE_GOODEND4, // Next state = -1
+
+ // Bad Ending
+ SLIDE_BADEND1 = 14,
+ SLIDE_BADEND2,
+ SLIDE_BADEND3, // Next state = -1
+
+ // Blah Ending
+ SLIDE_BLAHEND1 = 17,
+ SLIDE_BLAHEND2,
+ SLIDE_BLAHEND3, // Next state = -1
+
+ // Demo Ending - haleyjd 20130301: v1.31 only
+ SLIDE_DEMOEND1 = 25,
+ SLIDE_DEMOEND2 // Next state = -1
+};
+
+//
+// F_StartFinale
+//
+// [STRIFE]
+// haleyjd 09/13/10: Modified to drive slideshow sequences.
+//
+void F_StartFinale (void)
+{
+#if 0
+ // haleyjd 20111006: see below...
+ patch_t *panel;
+#endif
+
+ gameaction = ga_nothing;
+ gamestate = GS_FINALE;
+ viewactive = false;
+ automapactive = false;
+ wipegamestate = -1; // [STRIFE]
+
+ // [STRIFE] Setup the slide show
+ slideshow_panel = DEH_String("PANEL0");
+
+ // haleyjd 20111006: These two lines of code *are* in vanilla Strife;
+ // however, there, they were completely inconsequential due to the dirty
+ // rects system. No intervening V_MarkRect call means PANEL0 was never
+ // drawn to the framebuffer. In Chocolate Strife, however, with no such
+ // system in place, this only manages to fuck up the fade-out that is
+ // supposed to happen at the beginning of all finales. So, don't do it!
+#if 0
+ panel = (patch_t *)W_CacheLumpName(slideshow_panel, PU_CACHE);
+ V_DrawPatch(0, 0, panel);
+#endif
+
+ switch(gamemap)
+ {
+ case 3: // Macil's exposition on the Programmer
+ slideshow_state = SLIDE_PROGRAMMER1;
+ break;
+ case 9: // Super hack for death of Programmer
+ slideshow_state = SLIDE_EXITHACK;
+ break;
+ case 10: // Macil's exposition on the Sigil
+ slideshow_state = SLIDE_SIGIL1;
+ break;
+ case 29: // Endings
+ if(!netgame)
+ {
+ if(players[0].health <= 0) // Bad ending
+ slideshow_state = SLIDE_BADEND1; // - Humanity goes extinct
+ else
+ {
+ if((players[0].questflags & QF_QUEST25) && // Converter destroyed
+ (players[0].questflags & QF_QUEST27)) // Computer destroyed (wtf?!)
+ {
+ // Good ending - You get the hot babe.
+ slideshow_state = SLIDE_GOODEND1;
+ }
+ else
+ {
+ // Blah ending - You win the battle, but fail at life.
+ slideshow_state = SLIDE_BLAHEND1;
+ }
+ }
+ }
+ break;
+ case 34: // For the demo version ending
+ slideshow_state = SLIDE_EXIT;
+
+ // haleyjd 20130301: Somebody noticed the demo levels were missing the
+ // ending they used to have in the demo version EXE, I guess. But the
+ // weird thing is, this will only trigger if you run with strife0.wad,
+ // and no released version thereof actually works with the 1.31 EXE
+ // due to differing dialog formats... was there to be an updated demo
+ // that never got released?!
+ if(gameversion == exe_strife_1_31 && isdemoversion)
+ slideshow_state = SLIDE_DEMOEND1;
+ break;
+ }
+
+ S_ChangeMusic(mus_dark, 1);
+ slideshow_tics = 7;
+ finalestage = F_STAGE_TEXT;
+ finalecount = 0;
+}
+
+//
+// F_Responder
+//
+// [STRIFE] Verified unmodified
+//
+boolean F_Responder (event_t *event)
+{
+ if (finalestage == F_STAGE_CAST)
+ return F_CastResponder (event);
+
+ return false;
+}
+
+//
+// F_WaitTicker
+//
+// [STRIFE] New function
+// haleyjd 09/13/10: This is called from G_Ticker if gamestate is 1, but we
+// have no idea for what it's supposed to be. It is unused.
+//
+void F_WaitTicker(void)
+{
+ if(++finalecount >= 250)
+ {
+ gamestate = GS_FINALE;
+ finalestage = 0;
+ finalecount = 0;
+ }
+}
+
+//
+// F_DoSlideShow
+//
+// [STRIFE] New function
+// haleyjd 09/13/10: Handles slideshow states. Begging to be tabulated!
+//
+static void F_DoSlideShow(void)
+{
+ patch_t *patch;
+
+ switch(slideshow_state)
+ {
+ case SLIDE_UNKNOWN: // state #0, seems to be unused
+ slideshow_tics = 700;
+ slideshow_state = SLIDE_EXIT;
+ // falls through into state 1, so above is pointless? ...
+
+ case SLIDE_PROGRAMMER1: // state #1
+ slideshow_panel = DEH_String("SS2F1");
+ I_StartVoice(DEH_String("MAC10"));
+ slideshow_state = SLIDE_PROGRAMMER2;
+ slideshow_tics = 315;
+ break;
+ case SLIDE_PROGRAMMER2: // state #2
+ slideshow_panel = DEH_String("SS2F2");
+ I_StartVoice(DEH_String("MAC11"));
+ slideshow_state = SLIDE_PROGRAMMER3;
+ slideshow_tics = 350;
+ break;
+ case SLIDE_PROGRAMMER3: // state #3
+ slideshow_panel = DEH_String("SS2F3");
+ I_StartVoice(DEH_String("MAC12"));
+ slideshow_state = SLIDE_PROGRAMMER4;
+ slideshow_tics = 420;
+ break;
+ case SLIDE_PROGRAMMER4: // state #4
+ slideshow_panel = DEH_String("SS2F4");
+ I_StartVoice(DEH_String("MAC13"));
+ slideshow_state = SLIDE_EXITHACK; // End of slides
+ slideshow_tics = 595;
+ break;
+
+ case SLIDE_SIGIL1: // state #5
+ slideshow_panel = DEH_String("SS3F1");
+ I_StartVoice(DEH_String("MAC16"));
+ slideshow_state = SLIDE_SIGIL2;
+ slideshow_tics = 350;
+ break;
+ case SLIDE_SIGIL2: // state #6
+ slideshow_panel = DEH_String("SS3F2");
+ I_StartVoice(DEH_String("MAC17"));
+ slideshow_state = SLIDE_SIGIL3;
+ slideshow_tics = 420;
+ break;
+ case SLIDE_SIGIL3: // state #7
+ slideshow_panel = DEH_String("SS3F3");
+ I_StartVoice(DEH_String("MAC18"));
+ slideshow_tics = 420;
+ slideshow_state = SLIDE_SIGIL4;
+ break;
+ case SLIDE_SIGIL4: // state #8
+ slideshow_panel = DEH_String("SS3F4");
+ I_StartVoice(DEH_String("MAC19"));
+ slideshow_tics = 385;
+ slideshow_state = SLIDE_EXITHACK; // End of slides
+ break;
+
+ case SLIDE_GOODEND1: // state #10
+ slideshow_panel = DEH_String("SS4F1");
+ S_StartMusic(mus_happy);
+ I_StartVoice(DEH_String("RIE01"));
+ slideshow_state = SLIDE_GOODEND2;
+ slideshow_tics = 455;
+ break;
+ case SLIDE_GOODEND2: // state #11
+ slideshow_panel = DEH_String("SS4F2");
+ I_StartVoice(DEH_String("BBX01"));
+ slideshow_state = SLIDE_GOODEND3;
+ slideshow_tics = 385;
+ break;
+ case SLIDE_GOODEND3: // state #12
+ slideshow_panel = DEH_String("SS4F3");
+ I_StartVoice(DEH_String("BBX02"));
+ slideshow_state = SLIDE_GOODEND4;
+ slideshow_tics = 490;
+ break;
+ case SLIDE_GOODEND4: // state #13
+ slideshow_panel = DEH_String("SS4F4");
+ slideshow_state = SLIDE_EXIT; // Go to end credits
+ slideshow_tics = 980;
+ break;
+
+ case SLIDE_BADEND1: // state #14
+ S_StartMusic(mus_sad);
+ slideshow_panel = DEH_String("SS5F1");
+ I_StartVoice(DEH_String("SS501b"));
+ slideshow_state = SLIDE_BADEND2;
+ slideshow_tics = 385;
+ break;
+ case SLIDE_BADEND2: // state #15
+ slideshow_panel = DEH_String("SS5F2");
+ I_StartVoice(DEH_String("SS502b"));
+ slideshow_state = SLIDE_BADEND3;
+ slideshow_tics = 350;
+ break;
+ case SLIDE_BADEND3: // state #16
+ slideshow_panel = DEH_String("SS5F3");
+ I_StartVoice(DEH_String("SS503b"));
+ slideshow_state = SLIDE_EXIT; // Go to end credits
+ slideshow_tics = 385;
+ break;
+
+ case SLIDE_BLAHEND1: // state #17
+ S_StartMusic(mus_end);
+ slideshow_panel = DEH_String("SS6F1");
+ I_StartVoice(DEH_String("SS601A"));
+ slideshow_state = SLIDE_BLAHEND2;
+ slideshow_tics = 280;
+ break;
+ case SLIDE_BLAHEND2: // state #18
+ S_StartMusic(mus_end);
+ slideshow_panel = DEH_String("SS6F2");
+ I_StartVoice(DEH_String("SS602A"));
+ slideshow_state = SLIDE_BLAHEND3;
+ slideshow_tics = 280;
+ break;
+ case SLIDE_BLAHEND3: // state #19
+ S_StartMusic(mus_end);
+ slideshow_panel = DEH_String("SS6F3");
+ I_StartVoice(DEH_String("SS603A"));
+ slideshow_state = SLIDE_EXIT; // Go to credits
+ slideshow_tics = 315;
+ break;
+
+ case SLIDE_DEMOEND1: // state #25 - only exists in 1.31
+ slideshow_panel = DEH_String("PANEL7");
+ slideshow_tics = 175;
+ slideshow_state = SLIDE_DEMOEND2;
+ break;
+ case SLIDE_DEMOEND2: // state #26 - ditto
+ slideshow_panel = DEH_String("VELLOGO");
+ slideshow_tics = 175;
+ slideshow_state = SLIDE_EXIT; // Go to end credits
+ break;
+
+ case SLIDE_EXITHACK: // state -99: super hack state
+ gamestate = GS_LEVEL;
+ P_DialogStartP1();
+ break;
+ case SLIDE_HACKHACK: // state -9: unknown bizarre unused state
+ S_StartSound(NULL, sfx_rifle);
+ slideshow_tics = 3150;
+ break;
+ case SLIDE_EXIT: // state -1: proceed to next finale stage
+ finalecount = 0;
+ finalestage = F_STAGE_ARTSCREEN;
+ wipegamestate = -1;
+ S_StartMusic(mus_fast);
+ // haleyjd 20130301: The ONLY glitch fixed in 1.31 of Strife
+ // *would* be something this insignificant, of course!
+ if(gameversion != exe_strife_1_31)
+ slideshow_state = SLIDE_CHOCO; // haleyjd: see below...
+ break;
+ case SLIDE_CHOCO:
+ // haleyjd 09/14/10: This wouldn't be necessary except that Choco
+ // doesn't support the V_MarkRect dirty rectangles system. This
+ // just so happens to have hidden the fact that the ending
+ // does a screenfade every ~19 seconds due to remaining stuck in
+ // SLIDE_EXIT state above, UNLESS the menus were active - the
+ // V_MarkRect calls in the menu system cause it to be visible.
+ // This means that in order to get the same behavior as the vanilla
+ // EXE, I need different code. So, come to this state and only set
+ // wipegamestate if menuactive is true.
+ finalecount = 0;
+ finalestage = F_STAGE_ARTSCREEN;
+ if(menuactive)
+ wipegamestate = -1;
+ S_StartMusic(mus_fast);
+ slideshow_state = SLIDE_CHOCO; // remain here.
+ break;
+ default:
+ break;
+ }
+
+ finalecount = 0;
+ if(gameversion != exe_strife_1_31) // See above. This was removed in 1.31.
+ {
+ patch = (patch_t *)W_CacheLumpName(DEH_String("PANEL0"), PU_CACHE);
+ V_DrawPatch(0, 0, patch);
+ }
+}
+
+//
+// F_Ticker
+//
+// [STRIFE] Modifications for new finales
+// haleyjd 09/13/10: Calls F_DoSlideShow
+//
+void F_Ticker (void)
+{
+ size_t i;
+
+ // check for skipping
+ if (finalecount > 50) // [STRIFE] No commercial check
+ {
+ // go on to the next level
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ if (players[i].cmd.buttons)
+ break;
+
+ if (i < MAXPLAYERS)
+ finalecount = slideshow_tics; // [STRIFE]
+ }
+
+ // advance animation
+ finalecount++;
+
+ if (finalestage == F_STAGE_CAST)
+ F_CastTicker ();
+ else if(finalecount > slideshow_tics) // [STRIFE] Advance slideshow
+ F_DoSlideShow();
+
+ // [STRIFE]: Rest is unused
+ /*
+ if ( gamemode == commercial)
+ return;
+
+ if (finalestage == F_STAGE_TEXT
+ && finalecount>strlen (finaletext)*TEXTSPEED + TEXTWAIT)
+ {
+ finalecount = 0;
+ finalestage = F_STAGE_ARTSCREEN;
+ wipegamestate = -1; // force a wipe
+ if (gameepisode == 3)
+ S_StartMusic (mus_logo);
+ }
+ */
+}
+
+// haleyjd 09/13/10: Not present in Strife: Cast drawing functions
+
+#include "hu_stuff.h"
+extern patch_t *hu_font[HU_FONTSIZE];
+
+/*
+//
+// F_TextWrite
+//
+void F_TextWrite (void)
+{
+ byte* src;
+ byte* dest;
+
+ int x,y,w;
+ signed 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 = I_VideoBuffer;
+
+ for (y=0 ; y<SCREENHEIGHT ; y++)
+ {
+ for (x=0 ; x<SCREENWIDTH/64 ; x++)
+ {
+ memcpy (dest, src+((y&63)<<6), 64);
+ dest += 64;
+ }
+ if (SCREENWIDTH&63)
+ {
+ 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 = ((signed int) 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 = 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, hu_font[c]);
+ cx+=w;
+ }
+
+}
+*/
+
+//
+// Final DOOM 2 animation
+// Casting by id Software.
+// in order of appearance
+//
+typedef struct
+{
+ int isindemo; // [STRIFE] Changed from name, which is in mobjinfo
+ mobjtype_t type;
+} castinfo_t;
+
+// haleyjd: [STRIFE] A new cast order was defined, however it is unused in any
+// of the released versions of Strife, even including the demo version :(
+castinfo_t castorder[] = {
+ { 1, MT_PLAYER },
+ { 1, MT_BEGGAR1 },
+ { 1, MT_PEASANT2_A },
+ { 1, MT_REBEL1 },
+ { 1, MT_GUARD1 },
+ { 1, MT_CRUSADER },
+ { 1, MT_RLEADER2 },
+ { 0, MT_SENTINEL },
+ { 0, MT_STALKER },
+ { 0, MT_PROGRAMMER },
+ { 0, MT_REAVER },
+ { 0, MT_PGUARD },
+ { 0, MT_INQUISITOR },
+ { 0, MT_PRIEST },
+ { 0, MT_SPECTRE_A },
+ { 0, MT_BISHOP },
+ { 0, MT_ENTITY },
+ { 1, NUMMOBJTYPES }
+};
+
+int castnum;
+int casttics;
+state_t* caststate;
+boolean castdeath;
+int castframes;
+int castonmelee;
+boolean castattacking;
+
+//
+// F_StartCast
+//
+// haleyjd 09/13/10: [STRIFE] Heavily modified, yet unused.
+// Evidence suggests this was meant to be started from a menu item.
+// See m_menu.c for more info.
+//
+void F_StartCast (void)
+{
+ usergame = false;
+ gameaction = ga_nothing;
+ viewactive = false;
+ automapactive = false;
+ castnum = 0;
+ gamestate = GS_FINALE;
+ caststate = &states[mobjinfo[castorder[castnum].type].seestate];
+ casttics = caststate->tics;
+ if(casttics > 50)
+ casttics = 50;
+ wipegamestate = -1; // force a screen wipe
+ castdeath = false;
+ finalestage = F_STAGE_CAST;
+ castframes = 0;
+ castonmelee = 0;
+ castattacking = false;
+}
+
+
+//
+// F_CastTicker
+//
+// [STRIFE] Heavily modified, but unused.
+// haleyjd 09/13/10: Yeah, I bothered translating this even though it isn't
+// going to be seen, in part because I hope some Strife port or another will
+// pick it up and finish it, adding it as the optional menu item it was
+// meant to be, or just adding it as part of the ending sequence.
+//
+void F_CastTicker (void)
+{
+ int st;
+
+ 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 (isdemoversion)
+ {
+ // [STRIFE] Demo version had a shorter cast
+ if(!castorder[castnum].isindemo)
+ castnum = 0;
+ }
+ // [STRIFE] Break on type == NUMMOBJTYPES rather than name == NULL
+ if (castorder[castnum].type == NUMMOBJTYPES)
+ castnum = 0;
+ if (mobjinfo[castorder[castnum].type].seesound)
+ S_StartSound (NULL, mobjinfo[castorder[castnum].type].seesound);
+ caststate = &states[mobjinfo[castorder[castnum].type].seestate];
+ castframes = 0;
+ }
+ else
+ {
+ int sfx = 0;
+
+ // just advance to next state in animation
+ if (caststate == &states[S_PLAY_05]) // villsa [STRIFE] - updated
+ goto stopattack; // Oh, gross hack!
+ st = caststate->nextstate;
+ caststate = &states[st];
+ castframes++;
+
+ if (st != mobjinfo[castorder[castnum].type].meleestate &&
+ st != mobjinfo[castorder[castnum].type].missilestate)
+ {
+ if (st == S_PLAY_05)
+ sfx = sfx_rifle;
+ else
+ sfx = 0;
+ }
+ else
+ sfx = mobjinfo[castorder[castnum].type].attacksound;
+
+ if (sfx)
+ S_StartSound (NULL, sfx);
+ }
+
+ if (!castdeath && 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 > 50) // [STRIFE] Cap tics
+ casttics = 50;
+ else if (casttics == -1)
+ casttics = 15;
+}
+
+
+//
+// F_CastResponder
+//
+// [STRIFE] This still exists in Strife but is never used.
+// It was used at some point in development, however, as they made
+// numerous modifications to the cast call system.
+//
+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;
+ if(casttics > 50) // [STRIFE] Upper bound on casttics
+ casttics = 50;
+ castframes = 0;
+ castattacking = false;
+ if (mobjinfo[castorder[castnum].type].deathsound)
+ S_StartSound (NULL, mobjinfo[castorder[castnum].type].deathsound);
+
+ return true;
+}
+
+//
+// F_CastPrint
+//
+// [STRIFE] Verified unmodified, and unused.
+//
+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 = 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 = toupper(c) - HU_FONTSTART;
+ if (c < 0 || c> HU_FONTSIZE)
+ {
+ cx += 4;
+ continue;
+ }
+
+ w = SHORT (hu_font[c]->width);
+ V_DrawPatch(cx, 180, hu_font[c]);
+ cx+=w;
+ }
+
+}
+
+// haleyjd 09/13/10: [STRIFE] Unfortunately they removed whatever was
+// partway finished of this function from the binary, as there is no
+// trace of it. This means we cannot know for sure what the cast call
+// would have looked like. :(
+/*
+//
+// F_CastDrawer
+//
+void F_CastDrawer (void)
+{
+ spritedef_t* sprdef;
+ spriteframe_t* sprframe;
+ int lump;
+ boolean flip;
+ patch_t* patch;
+
+ // erase the entire screen to a background
+ V_DrawPatch (0, 0, W_CacheLumpName (DEH_String("BOSSBACK"), PU_CACHE));
+
+ F_CastPrint (DEH_String(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 = (boolean)sprframe->flip[0];
+
+ patch = W_CacheLumpNum (lump+firstspritelump, PU_CACHE);
+ if (flip)
+ V_DrawPatchFlipped(160, 170, patch);
+ else
+ V_DrawPatch(160, 170, patch);
+}
+*/
+
+#ifdef STRIFE_DEMO_CODE
+//
+// F_DrawPatchCol
+//
+// [STRIFE] Verified unmodified, but not present in 1.2
+// It WAS present in the demo version, however...
+//
+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 = I_VideoBuffer + 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 );
+ }
+}
+#endif
+
+//
+// F_DrawMap34End
+//
+// [STRIFE] Modified from F_BunnyScroll
+// * In 1.2 and up this just causes a weird black screen.
+// * In the demo version, it was an actual scroll between two screens.
+// I have implemented both code segments, though only the black screen
+// one will currently be used, as full demo version support isn't looking
+// likely right now.
+//
+void F_DrawMap34End (void)
+{
+ signed int scrolled;
+ int x;
+ patch_t* p1;
+ patch_t* p2;
+
+ p1 = W_CacheLumpName (DEH_String("credit"), PU_LEVEL);
+ p2 = W_CacheLumpName (DEH_String("vellogo"), PU_LEVEL);
+
+ V_MarkRect (0, 0, SCREENWIDTH, SCREENHEIGHT);
+
+
+ scrolled = (320 - ((signed int) finalecount-430)/2);
+ if (scrolled > 320)
+ scrolled = 320;
+ if (scrolled < 0)
+ scrolled = 0;
+
+#ifdef STRIFE_DEMO_CODE
+ for ( x=0 ; x<SCREENWIDTH ; x++)
+ {
+ if (x+scrolled < 320)
+ F_DrawPatchCol (x, p1, x+scrolled);
+ else
+ F_DrawPatchCol (x, p2, x+scrolled - 320);
+ }
+#else
+ // wtf this is supposed to do, I have no idea!
+ x = 1;
+ do
+ {
+ x += 11;
+ }
+ while(x < 320);
+#endif
+}
+
+// haleyjd 09/13/10: [STRIFE] Unused.
+/*
+static void F_ArtScreenDrawer(void)
+{
+ char *lumpname;
+
+ if (gameepisode == 3)
+ {
+ F_BunnyScroll();
+ }
+ else
+ {
+ switch (gameepisode)
+ {
+ case 1:
+ if (gamemode == retail)
+ {
+ lumpname = "CREDIT";
+ }
+ else
+ {
+ lumpname = "HELP2";
+ }
+ break;
+ case 2:
+ lumpname = "VICTORY2";
+ break;
+ case 4:
+ lumpname = "ENDPIC";
+ break;
+ default:
+ return;
+ }
+
+ lumpname = DEH_String(lumpname);
+
+ V_DrawPatch (0, 0, W_CacheLumpName(lumpname, PU_CACHE));
+ }
+}
+*/
+
+//
+// F_Drawer
+//
+// [STRIFE]
+// haleyjd 09/13/10: Modified for slideshow, demo version, etc.
+//
+void F_Drawer (void)
+{
+ switch (finalestage)
+ {
+ case F_STAGE_CAST:
+ // Cast didn't have a drawer in any released version
+ //F_CastDrawer();
+ break;
+ case F_STAGE_TEXT:
+ // Draw slideshow panel
+ {
+ patch_t *slide = W_CacheLumpName(slideshow_panel, PU_CACHE);
+ V_DrawPatch(0, 0, slide);
+ }
+ break;
+ case F_STAGE_ARTSCREEN:
+ if(gamemap <= 29)
+ {
+ // draw credits
+ patch_t *credits = W_CacheLumpName(DEH_String("CREDIT"), PU_CACHE);
+ V_DrawPatch(0, 0, credits);
+ }
+ else if(gamemap == 34)
+ {
+ // demo version - does nothing meaningful in the final version
+ F_DrawMap34End();
+ }
+ break;
+ }
+}
+
diff --git a/src/strife/f_finale.h b/src/strife/f_finale.h
new file mode 100644
index 00000000..d803a885
--- /dev/null
+++ b/src/strife/f_finale.h
@@ -0,0 +1,56 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+//
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __F_FINALE__
+#define __F_FINALE__
+
+
+#include "doomtype.h"
+#include "d_event.h"
+//
+// FINALE
+//
+
+// Called by main loop.
+boolean F_Responder (event_t* ev);
+
+// Called by main loop.
+void F_Ticker (void);
+
+// haleyjd: [STRIFE] Called from G_Ticker as well...
+void F_WaitTicker(void);
+
+// Called by main loop.
+void F_Drawer (void);
+
+
+void F_StartFinale (void);
+
+
+
+
+#endif
diff --git a/src/strife/f_wipe.c b/src/strife/f_wipe.c
new file mode 100644
index 00000000..2d2ac3bd
--- /dev/null
+++ b/src/strife/f_wipe.c
@@ -0,0 +1,300 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Mission begin melt/wipe screen special effect.
+//
+//-----------------------------------------------------------------------------
+
+#include <string.h>
+
+#include "z_zone.h"
+#include "i_video.h"
+#include "v_video.h"
+#include "m_random.h"
+
+#include "doomtype.h"
+
+#include "r_defs.h" // haleyjd [STRIFE]
+#include "r_draw.h"
+
+#include "f_wipe.h"
+
+//
+// SCREEN WIPE PACKAGE
+//
+
+// when zero, stop the wipe
+static boolean go = 0;
+
+static byte* wipe_scr_start;
+static byte* wipe_scr_end;
+static byte* wipe_scr;
+
+
+void
+wipe_shittyColMajorXform
+( short* array,
+ int width,
+ int height )
+{
+ int x;
+ int y;
+ short* dest;
+
+ dest = (short*) Z_Malloc(width*height*2, PU_STATIC, 0);
+
+ for(y=0;y<height;y++)
+ for(x=0;x<width;x++)
+ dest[x*height+y] = array[y*width+x];
+
+ memcpy(array, dest, width*height*2);
+
+ Z_Free(dest);
+
+}
+
+// haleyjd 08/26/10: [STRIFE] Verified unmodified.
+int
+wipe_initColorXForm
+( int width,
+ int height,
+ int ticks )
+{
+ memcpy(wipe_scr, wipe_scr_start, width*height);
+ return 0;
+}
+
+//
+// wipe_doColorXForm
+//
+// haleyjd 08/26/10: [STRIFE]
+// * Rogue modified the unused ColorXForm wipe in-place in order to implement
+// their distinctive crossfade wipe.
+//
+int
+wipe_doColorXForm
+( int width,
+ int height,
+ int ticks )
+{
+ byte *cur_screen = wipe_scr;
+ byte *end_screen = wipe_scr_end;
+ int pix = width*height;
+ int i;
+ boolean changed = false;
+
+ for(i = pix; i > 0; i--)
+ {
+ if(*cur_screen != *end_screen)
+ {
+ changed = true;
+ *cur_screen = xlatab[(*cur_screen << 8) + *end_screen];
+ }
+ ++cur_screen;
+ ++end_screen;
+ }
+
+ return !changed;
+}
+
+// haleyjd 08/26/10: [STRIFE] Verified unmodified.
+int
+wipe_exitColorXForm
+( int width,
+ int height,
+ int ticks )
+{
+ return 0;
+}
+
+
+static int* y;
+
+int
+wipe_initMelt
+( int width,
+ int height,
+ int ticks )
+{
+ int i, r;
+
+ // copy start screen to main screen
+ 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;
+ 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);
+ Z_Free(wipe_scr_start);
+ Z_Free(wipe_scr_end);
+ return 0;
+}
+
+// haleyjd 08/26/10: [STRIFE] Verified unmodified.
+int
+wipe_StartScreen
+( int x,
+ int y,
+ int width,
+ int height )
+{
+ wipe_scr_start = Z_Malloc(SCREENWIDTH * SCREENHEIGHT, PU_STATIC, NULL);
+ I_ReadScreen(wipe_scr_start);
+ return 0;
+}
+
+// haleyjd 08/26/10: [STRIFE] Verified unmodified.
+int
+wipe_EndScreen
+( int x,
+ int y,
+ int width,
+ int height )
+{
+ wipe_scr_end = Z_Malloc(SCREENWIDTH * SCREENHEIGHT, PU_STATIC, NULL);
+ I_ReadScreen(wipe_scr_end);
+ V_DrawBlock(x, y, width, height, wipe_scr_start); // restore start scr.
+ return 0;
+}
+
+// haleyjd 08/26/10: [STRIFE] Verified unmodified.
+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
+ };
+
+ // initial stuff
+ if (!go)
+ {
+ go = 1;
+ // haleyjd 20110629 [STRIFE]: We *must* use a temp buffer here.
+ wipe_scr = (byte *) Z_Malloc(width*height, PU_STATIC, 0); // DEBUG
+ //wipe_scr = I_VideoBuffer;
+ (*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);
+
+ // haleyjd 20110629 [STRIFE]: Copy temp buffer to the real screen.
+ V_DrawBlock(x, y, width, height, wipe_scr);
+
+ // final stuff
+ if (rc)
+ {
+ go = 0;
+ (*wipes[wipeno*3+2])(width, height, ticks);
+ }
+
+ return !go;
+}
+
diff --git a/src/strife/f_wipe.h b/src/strife/f_wipe.h
new file mode 100644
index 00000000..3f2e73af
--- /dev/null
+++ b/src/strife/f_wipe.h
@@ -0,0 +1,71 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Mission start screen wipe/melt, special effects.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __F_WIPE_H__
+#define __F_WIPE_H__
+
+//
+// SCREEN WIPE PACKAGE
+//
+
+enum
+{
+ // [STRIFE]: ColorXForm reimplemented as a proper crossfade
+ 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
diff --git a/src/strife/g_game.c b/src/strife/g_game.c
new file mode 100644
index 00000000..e295b858
--- /dev/null
+++ b/src/strife/g_game.c
@@ -0,0 +1,2456 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION: none
+//
+//-----------------------------------------------------------------------------
+
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "doomdef.h"
+#include "doomkeys.h"
+#include "doomstat.h"
+
+#include "deh_main.h"
+#include "deh_misc.h"
+#include "z_zone.h"
+#include "f_finale.h"
+#include "m_argv.h"
+#include "m_controls.h"
+#include "m_misc.h"
+#include "m_menu.h"
+#include "m_saves.h" // STRIFE
+#include "m_random.h"
+#include "i_system.h"
+#include "i_timer.h"
+#include "i_video.h"
+#include "p_setup.h"
+#include "p_saveg.h"
+#include "p_tick.h"
+#include "d_main.h"
+#include "wi_stuff.h"
+#include "hu_stuff.h"
+#include "st_stuff.h"
+#include "am_map.h"
+
+// Needs access to LFB.
+#include "v_video.h"
+
+#include "w_wad.h"
+
+#include "p_local.h"
+
+#include "s_sound.h"
+
+// Data.
+#include "dstrings.h"
+#include "sounds.h"
+
+// SKY handling - still the wrong place.
+#include "r_data.h"
+#include "r_sky.h"
+
+#include "p_dialog.h" // villsa [STRIFE]
+
+#include "g_game.h"
+
+
+#define SAVEGAMESIZE 0x2c000
+
+void G_ReadDemoTiccmd (ticcmd_t* cmd);
+void G_WriteDemoTiccmd (ticcmd_t* cmd);
+void G_PlayerReborn (int player);
+
+void G_DoReborn (int playernum);
+
+void G_DoLoadLevel (void);
+void G_DoNewGame (void);
+void G_DoPlayDemo (void);
+void G_DoCompleted (void);
+void G_DoVictory (void);
+void G_DoWorldDone (void);
+void G_DoSaveGame (char *path);
+
+// Gamestate the last time G_Ticker was called.
+
+gamestate_t oldgamestate;
+
+gameaction_t gameaction;
+gamestate_t gamestate;
+skill_t gameskill = 2; // [STRIFE] Default value set to 2.
+boolean respawnmonsters;
+//int gameepisode;
+int gamemap;
+
+// haleyjd 08/24/10: [STRIFE] New variables
+int destmap; // current destination map when exiting
+int riftdest; // destination spot for player
+angle_t riftangle; // player angle saved during exit
+
+// If non-zero, exit the level after this number of minutes.
+
+int timelimit;
+
+boolean paused;
+boolean sendpause; // send a pause event next tic
+boolean sendsave; // send a save event next tic
+boolean usergame; // ok to save / end game
+
+boolean timingdemo; // if true, exit with report on completion
+boolean nodrawers; // for comparative timing purposes
+int starttime; // for comparative timing purposes
+
+boolean viewactive;
+
+boolean deathmatch; // only if started as net death
+boolean netgame; // only true if packets are broadcast
+boolean playeringame[MAXPLAYERS];
+player_t players[MAXPLAYERS];
+
+boolean turbodetected[MAXPLAYERS];
+
+int consoleplayer; // player taking events and displaying
+int displayplayer; // view being displayed
+int gametic;
+int levelstarttic; // gametic at level start
+int totalkills, /*totalitems,*/ totalsecret; // for intermission
+
+char *demoname;
+boolean demorecording;
+boolean longtics; // cph's doom 1.91 longtics hack
+boolean lowres_turn; // low resolution turning for longtics
+boolean demoplayback;
+boolean netdemo;
+byte* demobuffer;
+byte* demo_p;
+byte* demoend;
+boolean singledemo; // quit after playing a demo from cmdline
+
+boolean precache = true; // if true, load all graphics at start
+
+boolean testcontrols = false; // Invoked by setup to test controls
+
+wbstartstruct_t wminfo; // parms for world map / intermission
+
+byte consistancy[MAXPLAYERS][BACKUPTICS];
+
+#define MAXPLMOVE (forwardmove[1])
+
+#define TURBOTHRESHOLD 0x32
+
+fixed_t forwardmove[2] = {0x19, 0x32};
+fixed_t sidemove[2] = {0x18, 0x28};
+fixed_t angleturn[3] = {640, 1280, 320}; // + slow turn
+
+int mouse_fire_countdown = 0; // villsa [STRIFE]
+
+static int *weapon_keys[] = {
+ &key_weapon1,
+ &key_weapon2,
+ &key_weapon3,
+ &key_weapon4,
+ &key_weapon5,
+ &key_weapon6,
+ &key_weapon7,
+ &key_weapon8
+};
+
+// Set to -1 or +1 to switch to the previous or next weapon.
+
+static int next_weapon = 0;
+
+// Used for prev/next weapon keys.
+// STRIFE-TODO: Check this table makes sense.
+
+static const struct
+{
+ weapontype_t weapon;
+ weapontype_t weapon_num;
+} weapon_order_table[] = {
+ { wp_fist, wp_fist },
+ { wp_poisonbow, wp_elecbow },
+ { wp_elecbow, wp_elecbow },
+ { wp_rifle, wp_rifle },
+ { wp_missile, wp_missile },
+ { wp_wpgrenade, wp_hegrenade },
+ { wp_hegrenade, wp_hegrenade },
+ { wp_flame, wp_flame },
+ { wp_torpedo, wp_mauler },
+ { wp_mauler, wp_mauler },
+ { wp_sigil, wp_sigil },
+};
+
+#define SLOWTURNTICS 6
+
+#define NUMKEYS 256
+#define MAX_JOY_BUTTONS 20
+
+static boolean gamekeydown[NUMKEYS];
+static int turnheld; // for accelerative turning
+
+static boolean mousearray[MAX_MOUSE_BUTTONS + 1];
+static boolean *mousebuttons = &mousearray[1]; // allow [-1]
+
+// mouse values are used once
+int mousex;
+int mousey;
+
+static int dclicktime;
+static boolean dclickstate;
+static int dclicks;
+static int dclicktime2;
+static boolean dclickstate2;
+static int dclicks2;
+
+// joystick values are repeated
+static int joyxmove;
+static int joyymove;
+static boolean joyarray[MAX_JOY_BUTTONS + 1];
+static boolean *joybuttons = &joyarray[1]; // allow [-1]
+
+static int savegameslot = 6; // [STRIFE] initialized to 6
+static char savedescription[32];
+
+int testcontrols_mousespeed;
+
+#define BODYQUESIZE 32
+
+mobj_t* bodyque[BODYQUESIZE];
+//int bodyqueslot; [STRIFE] unused
+
+int vanilla_savegame_limit = 1;
+int vanilla_demo_limit = 1;
+
+
+int G_CmdChecksum (ticcmd_t* cmd)
+{
+ size_t i;
+ int sum = 0;
+
+ for (i=0 ; i< sizeof(*cmd)/4 - 1 ; i++)
+ sum += ((int *)cmd)[i];
+
+ return sum;
+}
+
+static boolean WeaponSelectable(weapontype_t weapon)
+{
+ player_t *player;
+
+ player = &players[consoleplayer];
+
+ // Can't select a weapon if we don't own it.
+
+ if (!player->weaponowned[weapon])
+ {
+ return false;
+ }
+
+ // Can't use registered-only weapons in demo mode:
+
+ if (isdemoversion && !weaponinfo[weapon].availabledemo)
+ {
+ return false;
+ }
+
+ // Special rules for switching to alternate versions of weapons.
+ // These must match the weapon-switching rules in P_PlayerThink()
+
+ if (weapon == wp_torpedo
+ && player->ammo[weaponinfo[am_cell].ammo] < 30)
+ {
+ return false;
+ }
+
+ if (player->ammo[weaponinfo[weapon].ammo] == 0)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+static int G_NextWeapon(int direction)
+{
+ weapontype_t weapon;
+ int i;
+
+ // Find index in the table.
+
+ if (players[consoleplayer].pendingweapon == wp_nochange)
+ {
+ weapon = players[consoleplayer].readyweapon;
+ }
+ else
+ {
+ weapon = players[consoleplayer].pendingweapon;
+ }
+
+ for (i=0; i<arrlen(weapon_order_table); ++i)
+ {
+ if (weapon_order_table[i].weapon == weapon)
+ {
+ break;
+ }
+ }
+
+ // Switch weapon.
+
+ do
+ {
+ i += direction;
+ i = (i + arrlen(weapon_order_table)) % arrlen(weapon_order_table);
+ } while (!WeaponSelectable(weapon_order_table[i].weapon));
+
+ return weapon_order_table[i].weapon_num;
+}
+
+//
+// G_BuildTiccmd
+// Builds a ticcmd from all of the available inputs
+// or reads it from the demo buffer.
+// If recording a demo, write it out
+//
+void G_BuildTiccmd (ticcmd_t* cmd, int maketic)
+{
+ int i;
+ boolean strafe;
+ boolean bstrafe;
+ int speed;
+ int tspeed;
+ int forward;
+ int side;
+
+ memset(cmd, 0, sizeof(ticcmd_t));
+
+ cmd->consistancy =
+ consistancy[consoleplayer][maketic%BACKUPTICS];
+
+ // villsa [STRIFE] look up key
+ if(gamekeydown[key_lookup])
+ cmd->buttons2 |= BT2_LOOKUP;
+
+ // villsa [STRIFE] look down key
+ if(gamekeydown[key_lookdown])
+ cmd->buttons2 |= BT2_LOOKDOWN;
+
+ // villsa [STRIFE] inventory use key
+ if(gamekeydown[key_invuse])
+ {
+ player_t* player = &players[consoleplayer];
+ if(player->numinventory > 0)
+ {
+ cmd->buttons2 |= BT2_INVUSE;
+ cmd->inventory = player->inventory[player->inventorycursor].sprite;
+ }
+ }
+
+ // villsa [STRIFE] inventory drop key
+ if(gamekeydown[key_invdrop])
+ {
+ player_t* player = &players[consoleplayer];
+ if(player->numinventory > 0)
+ {
+ cmd->buttons2 |= BT2_INVDROP;
+ cmd->inventory = player->inventory[player->inventorycursor].sprite;
+ }
+ }
+
+ // villsa [STRIFE] use medkit
+ if(gamekeydown[key_usehealth])
+ cmd->buttons2 |= BT2_HEALTH;
+
+
+
+ strafe = gamekeydown[key_strafe] || mousebuttons[mousebstrafe]
+ || joybuttons[joybstrafe];
+
+ // fraggle: support the old "joyb_speed = 31" hack which
+ // allowed an autorun effect
+
+ speed = key_speed >= NUMKEYS
+ || joybspeed >= MAX_JOY_BUTTONS
+ || gamekeydown[key_speed]
+ || joybuttons[joybspeed];
+
+ forward = side = 0;
+
+ // villsa [STRIFE] running causes centerview to occur
+ if(speed)
+ cmd->buttons2 |= BT2_CENTERVIEW;
+
+ // villsa [STRIFE] disable running if low on health
+ if (players[consoleplayer].health <= 15)
+ speed = 0;
+
+ // use two stage accelerative turning
+ // on the keyboard and joystick
+ if (joyxmove < 0
+ || joyxmove > 0
+ || gamekeydown[key_right]
+ || gamekeydown[key_left])
+ turnheld += ticdup;
+ else
+ turnheld = 0;
+
+ if (turnheld < SLOWTURNTICS)
+ tspeed = 2; // slow turn
+ else
+ tspeed = speed;
+
+ // let movement keys cancel each other out
+ if (strafe)
+ {
+ if (gamekeydown[key_right])
+ {
+ // fprintf(stderr, "strafe right\n");
+ side += sidemove[speed];
+ }
+ if (gamekeydown[key_left])
+ {
+ // fprintf(stderr, "strafe left\n");
+ side -= sidemove[speed];
+ }
+ if (joyxmove > 0)
+ side += sidemove[speed];
+ if (joyxmove < 0)
+ side -= sidemove[speed];
+
+ }
+ else
+ {
+ if (gamekeydown[key_right])
+ cmd->angleturn -= angleturn[tspeed];
+ if (gamekeydown[key_left])
+ cmd->angleturn += angleturn[tspeed];
+ if (joyxmove > 0)
+ cmd->angleturn -= angleturn[tspeed];
+ if (joyxmove < 0)
+ cmd->angleturn += angleturn[tspeed];
+ }
+
+ if (gamekeydown[key_up])
+ {
+ // fprintf(stderr, "up\n");
+ forward += forwardmove[speed];
+ }
+ if (gamekeydown[key_down])
+ {
+ // fprintf(stderr, "down\n");
+ forward -= forwardmove[speed];
+ }
+
+ if (joyymove < 0)
+ forward += forwardmove[speed];
+ if (joyymove > 0)
+ forward -= forwardmove[speed];
+
+ if (gamekeydown[key_strafeleft]
+ || joybuttons[joybstrafeleft]
+ || mousebuttons[mousebstrafeleft])
+ {
+ side -= sidemove[speed];
+ }
+
+ if (gamekeydown[key_straferight]
+ || joybuttons[joybstraferight]
+ || mousebuttons[mousebstraferight])
+ {
+ side += sidemove[speed];
+ }
+
+ // buttons
+ cmd->chatchar = HU_dequeueChatChar();
+
+ // villsa [STRIFE] - add mouse button support for jump
+ if(gamekeydown[key_jump] || mousebuttons[mousebjump])
+ cmd->buttons2 |= BT2_JUMP;
+
+ // villsa [STRIFE]: Moved mousebuttons[mousebfire] to below
+ if (gamekeydown[key_fire] || joybuttons[joybfire])
+ cmd->buttons |= BT_ATTACK;
+
+ // villsa [STRIFE]
+ if(mousebuttons[mousebfire])
+ {
+ if(mouse_fire_countdown <= 0)
+ cmd->buttons |= BT_ATTACK;
+ else
+ --mouse_fire_countdown;
+ }
+
+ if (gamekeydown[key_use]
+ || joybuttons[joybuse]
+ || mousebuttons[mousebuse])
+ {
+ cmd->buttons |= BT_USE;
+ // clear double clicks if hit use button
+ dclicks = 0;
+ }
+
+ // If the previous or next weapon button is pressed, the
+ // next_weapon variable is set to change weapons when
+ // we generate a ticcmd. Choose a new weapon.
+
+ if (next_weapon != 0)
+ {
+ i = G_NextWeapon(next_weapon);
+ cmd->buttons |= BT_CHANGE;
+ cmd->buttons |= i << BT_WEAPONSHIFT;
+ next_weapon = 0;
+ }
+ else
+ {
+ // Check weapon keys.
+
+ for (i=0; i<arrlen(weapon_keys); ++i)
+ {
+ int key = *weapon_keys[i];
+
+ if (gamekeydown[key])
+ {
+ cmd->buttons |= BT_CHANGE;
+ cmd->buttons |= i<<BT_WEAPONSHIFT;
+ break;
+ }
+ }
+ }
+
+ // mouse
+ if (mousebuttons[mousebforward])
+ {
+ forward += forwardmove[speed];
+ }
+ if (mousebuttons[mousebbackward])
+ {
+ forward -= forwardmove[speed];
+ }
+
+ if (dclick_use)
+ {
+ // forward double click
+ if (mousebuttons[mousebforward] != dclickstate && dclicktime > 1 )
+ {
+ dclickstate = mousebuttons[mousebforward];
+ if (dclickstate)
+ dclicks++;
+ if (dclicks == 2)
+ {
+ cmd->buttons |= BT_USE;
+ dclicks = 0;
+ }
+ else
+ dclicktime = 0;
+ }
+ else
+ {
+ dclicktime += ticdup;
+ if (dclicktime > 20)
+ {
+ dclicks = 0;
+ dclickstate = 0;
+ }
+ }
+
+ // strafe double click
+ bstrafe =
+ mousebuttons[mousebstrafe]
+ || joybuttons[joybstrafe];
+ if (bstrafe != dclickstate2 && dclicktime2 > 1 )
+ {
+ dclickstate2 = bstrafe;
+ if (dclickstate2)
+ dclicks2++;
+ if (dclicks2 == 2)
+ {
+ cmd->buttons |= BT_USE;
+ dclicks2 = 0;
+ }
+ else
+ dclicktime2 = 0;
+ }
+ else
+ {
+ dclicktime2 += ticdup;
+ if (dclicktime2 > 20)
+ {
+ dclicks2 = 0;
+ dclickstate2 = 0;
+ }
+ }
+ }
+
+ forward += mousey;
+
+ if (strafe)
+ side += mousex*2;
+ else
+ cmd->angleturn -= mousex*0x8;
+
+ if (mousex == 0)
+ {
+ // No movement in the previous frame
+
+ testcontrols_mousespeed = 0;
+ }
+
+ mousex = mousey = 0;
+
+ if (forward > MAXPLMOVE)
+ forward = MAXPLMOVE;
+ else if (forward < -MAXPLMOVE)
+ forward = -MAXPLMOVE;
+ if (side > MAXPLMOVE)
+ side = MAXPLMOVE;
+ else if (side < -MAXPLMOVE)
+ side = -MAXPLMOVE;
+
+ cmd->forwardmove += forward;
+ cmd->sidemove += side;
+
+ // special buttons
+ if (sendpause)
+ {
+ sendpause = false;
+ cmd->buttons = BT_SPECIAL | BTS_PAUSE;
+ }
+
+ if (sendsave)
+ {
+ sendsave = false;
+ cmd->buttons = BT_SPECIAL | BTS_SAVEGAME | (savegameslot<<BTS_SAVESHIFT);
+ }
+
+ // low-res turning
+
+ if (lowres_turn)
+ {
+ static signed short carry = 0;
+ signed short desired_angleturn;
+
+ desired_angleturn = cmd->angleturn + carry;
+
+ // round angleturn to the nearest 256 unit boundary
+ // for recording demos with single byte values for turn
+
+ cmd->angleturn = (desired_angleturn + 128) & 0xff00;
+
+ // Carry forward the error from the reduced resolution to the
+ // next tic, so that successive small movements can accumulate.
+
+ carry = desired_angleturn - cmd->angleturn;
+ }
+}
+
+
+//
+// G_DoLoadLevel
+//
+void G_DoLoadLevel (void)
+{
+ int i;
+
+ // haleyjd 10/03/10: [STRIFE] This is not done here.
+ //skyflatnum = R_FlatNumForName(DEH_String(SKYFLATNAME));
+
+ levelstarttic = gametic; // for time calculation
+
+ if (wipegamestate == GS_LEVEL)
+ wipegamestate = -1; // force a wipe
+
+ gamestate = GS_LEVEL;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ turbodetected[i] = false;
+
+ // haleyjd 20110204 [STRIFE]: PST_REBORN if players[i].health <= 0
+ if (playeringame[i] && (players[i].playerstate == PST_DEAD || players[i].health <= 0))
+ players[i].playerstate = PST_REBORN;
+ memset (players[i].frags,0,sizeof(players[i].frags));
+ }
+
+ P_SetupLevel (gamemap, 0, gameskill);
+ displayplayer = consoleplayer; // view the guy you are playing
+ starttime = I_GetTime(); // haleyjd 20110204 [STRIFE]
+ gameaction = ga_nothing;
+ Z_CheckHeap ();
+
+ // clear cmd building stuff
+
+ memset (gamekeydown, 0, sizeof(gamekeydown));
+ joyxmove = joyymove = 0;
+ mousex = mousey = 0;
+ sendpause = sendsave = paused = false;
+ memset (mousebuttons, 0, sizeof(mousebuttons));
+ memset (joybuttons, 0, sizeof(joybuttons));
+
+ if (testcontrols)
+ {
+ players[consoleplayer].message = "Press escape to quit.";
+ }
+
+ P_DialogLoad(); // villsa [STRIFE]
+}
+
+static void SetJoyButtons(unsigned int buttons_mask)
+{
+ int i;
+
+ for (i=0; i<MAX_JOY_BUTTONS; ++i)
+ {
+ int button_on = (buttons_mask & (1 << i)) != 0;
+
+ // Detect button press:
+
+ if (!joybuttons[i] && button_on)
+ {
+ // Weapon cycling:
+
+ if (i == joybprevweapon)
+ {
+ next_weapon = -1;
+ }
+ else if (i == joybnextweapon)
+ {
+ next_weapon = 1;
+ }
+ }
+
+ joybuttons[i] = button_on;
+ }
+}
+
+static void SetMouseButtons(unsigned int buttons_mask)
+{
+ int i;
+
+ for (i=0; i<MAX_MOUSE_BUTTONS; ++i)
+ {
+ unsigned int button_on = (buttons_mask & (1 << i)) != 0;
+
+ // Detect button press:
+
+ if (!mousebuttons[i] && button_on)
+ {
+ if (i == mousebprevweapon)
+ {
+ next_weapon = -1;
+ }
+ else if (i == mousebnextweapon)
+ {
+ next_weapon = 1;
+ }
+ }
+
+ mousebuttons[i] = button_on;
+ }
+}
+
+//
+// G_Responder
+// Get info needed to make ticcmd_ts for the players.
+//
+boolean G_Responder (event_t* ev)
+{
+ // allow spy mode changes even during the demo
+ if (gamestate == GS_LEVEL && ev->type == ev_keydown
+ && ev->data1 == key_spy && (singledemo || !gameskill) ) // [STRIFE]: o_O
+ {
+ // spy mode
+ do
+ {
+ displayplayer++;
+ if (displayplayer == MAXPLAYERS)
+ displayplayer = 0;
+ } while (!playeringame[displayplayer] && displayplayer != consoleplayer);
+ return true;
+ }
+
+ // any other key pops up menu if in demos
+ if (gameaction == ga_nothing && !singledemo &&
+ (demoplayback || gamestate == GS_DEMOSCREEN)
+ )
+ {
+ if (ev->type == ev_keydown ||
+ (ev->type == ev_mouse && ev->data1) ||
+ (ev->type == ev_joystick && ev->data1) )
+ {
+ if(devparm && ev->data1 == 'g')
+ D_PageTicker(); // [STRIFE]: wat? o_O
+ else
+ M_StartControlPanel ();
+ return true;
+ }
+ return false;
+ }
+
+ if (gamestate == GS_LEVEL)
+ {
+#if 0
+ if (devparm && ev->type == ev_keydown && ev->data1 == ';')
+ {
+ G_DeathMatchSpawnPlayer (0);
+ return true;
+ }
+#endif
+ if (HU_Responder (ev))
+ return true; // chat ate the event
+ if (ST_Responder (ev))
+ return true; // status window ate it
+ if (AM_Responder (ev))
+ return true; // automap ate it
+ }
+
+ if (gamestate == GS_FINALE)
+ {
+ if (F_Responder (ev))
+ return true; // finale ate the event
+ }
+
+ if (testcontrols && ev->type == ev_mouse)
+ {
+ // If we are invoked by setup to test the controls, save the
+ // mouse speed so that we can display it on-screen.
+ // Perform a low pass filter on this so that the thermometer
+ // appears to move smoothly.
+
+ testcontrols_mousespeed = abs(ev->data2);
+ }
+
+ // If the next/previous weapon keys are pressed, set the next_weapon
+ // variable to change weapons when the next ticcmd is generated.
+
+ if (ev->type == ev_keydown && ev->data1 == key_prevweapon)
+ {
+ next_weapon = -1;
+ }
+ else if (ev->type == ev_keydown && ev->data1 == key_nextweapon)
+ {
+ next_weapon = 1;
+ }
+
+ switch (ev->type)
+ {
+ case ev_keydown:
+ if (ev->data1 == key_pause)
+ {
+ sendpause = true;
+ }
+ else if (ev->data1 <NUMKEYS)
+ {
+ gamekeydown[ev->data1] = true;
+ }
+
+ return true; // eat key down events
+
+ case ev_keyup:
+ if (ev->data1 <NUMKEYS)
+ gamekeydown[ev->data1] = false;
+ return false; // always let key up events filter down
+
+ case ev_mouse:
+ SetMouseButtons(ev->data1);
+ mousex = ev->data2*(mouseSensitivity+5)/10;
+ mousey = ev->data3*(mouseSensitivity+5)/10;
+ return true; // eat events
+
+ case ev_joystick:
+ SetJoyButtons(ev->data1);
+ joyxmove = ev->data2;
+ joyymove = ev->data3;
+ return true; // eat events
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+//
+// G_Ticker
+// Make ticcmd_ts for the players.
+//
+void G_Ticker (void)
+{
+ int i;
+ int buf;
+ ticcmd_t* cmd;
+
+ // do player reborns if needed
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ if (playeringame[i] && players[i].playerstate == PST_REBORN)
+ G_DoReborn (i);
+
+ // do things to change the game state
+ while (gameaction != ga_nothing)
+ {
+ switch (gameaction)
+ {
+ case ga_loadlevel:
+ G_DoLoadLevel ();
+ break;
+ case ga_newgame:
+ G_DoNewGame ();
+ break;
+ case ga_loadgame:
+ G_DoLoadGame(true);
+ M_SaveMoveHereToMap(); // [STRIFE]
+ M_ReadMisObj();
+ break;
+ case ga_savegame:
+ M_SaveMoveMapToHere(); // [STRIFE]
+ M_SaveMisObj(savepath);
+ G_DoSaveGame(savepath);
+ break;
+ case ga_playdemo:
+ G_DoPlayDemo ();
+ break;
+ case ga_completed:
+ G_DoCompleted ();
+ break;
+ case ga_victory:
+ F_StartFinale ();
+ break;
+ case ga_worlddone:
+ G_DoWorldDone ();
+ break;
+ case ga_screenshot:
+ V_ScreenShot("STRIFE%02i.pcx"); // [STRIFE] file name, message
+ players[consoleplayer].message = DEH_String("STRIFE by Rogue entertainment");
+ gameaction = ga_nothing;
+ break;
+ case ga_nothing:
+ break;
+ }
+ }
+
+ // get commands, check consistancy,
+ // and build new consistancy check
+ buf = (gametic/ticdup)%BACKUPTICS;
+
+ // STRIFE-TODO: pnameprefixes bullcrap
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (playeringame[i])
+ {
+ cmd = &players[i].cmd;
+
+ memcpy (cmd, &netcmds[i], sizeof(ticcmd_t));
+
+ if (demoplayback)
+ G_ReadDemoTiccmd (cmd);
+ if (demorecording)
+ G_WriteDemoTiccmd (cmd);
+
+ // check for turbo cheats
+
+ // check ~ 4 seconds whether to display the turbo message.
+ // store if the turbo threshold was exceeded in any tics
+ // over the past 4 seconds. offset the checking period
+ // for each player so messages are not displayed at the
+ // same time.
+
+ if (cmd->forwardmove > TURBOTHRESHOLD)
+ {
+ turbodetected[i] = true;
+ }
+
+ if ((gametic & 31) == 0
+ && ((gametic >> 5) % MAXPLAYERS) == i
+ && turbodetected[i])
+ {
+ static char turbomessage[80];
+ extern char *player_names[4];
+ sprintf (turbomessage, "%s is turbo!",player_names[i]);
+ players[consoleplayer].message = turbomessage;
+ turbodetected[i] = false;
+ }
+
+ if (netgame && !netdemo && !(gametic%ticdup) )
+ {
+ if (gametic > BACKUPTICS
+ && consistancy[i][buf] != cmd->consistancy)
+ {
+ I_Error ("consistency failure (%i should be %i)",
+ cmd->consistancy, consistancy[i][buf]);
+ }
+ if (players[i].mo)
+ consistancy[i][buf] = players[i].mo->x;
+ else
+ consistancy[i][buf] = rndindex;
+ }
+ }
+ }
+
+ // check for special buttons
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (playeringame[i])
+ {
+ if (players[i].cmd.buttons & BT_SPECIAL)
+ {
+ switch (players[i].cmd.buttons & BT_SPECIALMASK)
+ {
+ case BTS_PAUSE:
+ paused ^= 1;
+ if (paused)
+ S_PauseSound ();
+ else
+ S_ResumeSound ();
+ break;
+
+ case BTS_SAVEGAME:
+ if (!character_name[0]) // [STRIFE]
+ strcpy (character_name, "NET GAME");
+ savegameslot =
+ (players[i].cmd.buttons & BTS_SAVEMASK)>>BTS_SAVESHIFT;
+ gameaction = ga_savegame;
+ break;
+ }
+ }
+ }
+ }
+
+ // Have we just finished displaying an intermission screen?
+ // haleyjd 08/23/10: [STRIFE] No intermission.
+ /*
+ if (oldgamestate == GS_INTERMISSION && gamestate != GS_INTERMISSION)
+ {
+ WI_End();
+ }
+ */
+
+ oldgamestate = gamestate;
+
+ // do main actions
+ switch (gamestate)
+ {
+ case GS_LEVEL:
+ P_Ticker ();
+ ST_Ticker ();
+ AM_Ticker ();
+ HU_Ticker ();
+ break;
+
+ // haleyjd 08/23/10: [STRIFE] No intermission.
+ /*
+ case GS_INTERMISSION:
+ WI_Ticker ();
+ break;
+ */
+ case GS_UNKNOWN: // STRIFE-TODO: What is this? is it ever used??
+ F_WaitTicker();
+ break;
+
+ case GS_FINALE:
+ F_Ticker ();
+ break;
+
+ case GS_DEMOSCREEN:
+ D_PageTicker ();
+ break;
+ }
+}
+
+
+//
+// PLAYER STRUCTURE FUNCTIONS
+// also see P_SpawnPlayer in P_Things
+//
+
+//
+// G_InitPlayer
+// Called at the start.
+// Called by the game initialization functions.
+//
+// [STRIFE] No such function.
+/*
+void G_InitPlayer (int player)
+{
+ player_t* p;
+
+ // set up the saved info
+ p = &players[player];
+
+ // clear everything else to defaults
+ G_PlayerReborn (player);
+
+}
+*/
+
+
+//
+// G_PlayerFinishLevel
+// Can when a player completes a level.
+//
+// [STRIFE] No such function. The equivalent to this logic was moved into
+// G_DoCompleted.
+/*
+void G_PlayerFinishLevel (int player)
+{
+ player_t* p;
+
+ p = &players[player];
+
+ memset (p->powers, 0, sizeof (p->powers));
+ memset (p->cards, 0, sizeof (p->cards));
+ p->mo->flags &= ~MF_SHADOW; // cancel invisibility
+ p->extralight = 0; // cancel gun flashes
+ p->fixedcolormap = 0; // cancel ir gogles
+ p->damagecount = 0; // no palette changes
+ p->bonuscount = 0;
+}
+*/
+
+//
+// G_PlayerReborn
+// Called after a player dies
+// almost everything is cleared and initialized
+//
+// [STRIFE] Small changes for allegiance, inventory, health auto-use, and
+// mission objective.
+//
+void G_PlayerReborn (int player)
+{
+ player_t* p;
+ int i;
+ int frags[MAXPLAYERS];
+ int killcount;
+ int allegiance;
+
+ killcount = players[player].killcount;
+ allegiance = players[player].allegiance; // [STRIFE]
+
+ memcpy(frags,players[player].frags,sizeof(frags));
+
+ p = &players[player];
+ memset (p, 0, sizeof(*p));
+
+ memcpy(p->frags, frags, sizeof(p->frags));
+
+ p->usedown = true; // don't do anything immediately
+ p->attackdown = true;
+ p->inventorydown = true; // villsa [STRIFE]
+ p->playerstate = PST_LIVE;
+ p->health = deh_initial_health; // Use dehacked value
+ p->readyweapon = wp_fist; // villsa [STRIFE] default to fists
+ p->pendingweapon = wp_fist; // villsa [STRIFE] default to fists
+ p->weaponowned[wp_fist] = true; // villsa [STRIFE] default to fists
+ p->cheats |= CF_AUTOHEALTH; // villsa [STRIFE]
+ p->killcount = killcount;
+ p->allegiance = allegiance; // villsa [STRIFE]
+ p->centerview = true; // villsa [STRIFE]
+
+ for(i = 0; i < NUMAMMO; i++)
+ p->maxammo[i] = maxammo[i];
+
+ // [STRIFE] clear inventory
+ for(i = 0; i < 32; i++)
+ p->inventory[i].type = NUMMOBJTYPES;
+
+ // villsa [STRIFE]: Default objective
+ strncpy(mission_objective, DEH_String("Find help"), OBJECTIVE_LEN);
+}
+
+//
+// G_CheckSpot
+// Returns false if the player cannot be respawned
+// at the given mapthing_t spot
+// because something is occupying it
+//
+// [STRIFE] Changed to eliminate body queue and an odd error message was added.
+//
+void P_SpawnPlayer (mapthing_t* mthing);
+
+boolean
+G_CheckSpot
+( int playernum,
+ mapthing_t* mthing )
+{
+ fixed_t x;
+ fixed_t y;
+ subsector_t* ss;
+ unsigned an;
+ mobj_t* mo;
+ int i;
+
+ if (!players[playernum].mo)
+ {
+ // [STRIFE] weird error message added here:
+ if(leveltime > 0)
+ players[playernum].message = DEH_String("you didn't have a body!");
+
+ // first spawn of level, before corpses
+ for (i=0 ; i<playernum ; i++)
+ if (players[i].mo->x == mthing->x << FRACBITS
+ && players[i].mo->y == mthing->y << FRACBITS)
+ return false;
+ return true;
+ }
+
+ x = mthing->x << FRACBITS;
+ y = mthing->y << FRACBITS;
+
+ if (!P_CheckPosition (players[playernum].mo, x, y) )
+ return false;
+
+ // flush an old corpse if needed
+ // [STRIFE] player corpses remove themselves after a short time, so
+ // evidently this wasn't needed.
+ /*
+ if (bodyqueslot >= BODYQUESIZE)
+ P_RemoveMobj (bodyque[bodyqueslot%BODYQUESIZE]);
+ bodyque[bodyqueslot%BODYQUESIZE] = players[playernum].mo;
+ bodyqueslot++;
+ */
+
+ // spawn a teleport fog
+ ss = R_PointInSubsector (x,y);
+ an = ( ANG45 * (((unsigned int) mthing->angle)/45) ) >> ANGLETOFINESHIFT;
+
+ mo = P_SpawnMobj (x+20*finecosine[an], y+20*finesine[an]
+ , ss->sector->floorheight
+ , MT_TFOG);
+
+ if (players[consoleplayer].viewz != 1)
+ S_StartSound (mo, sfx_telept); // don't start sound on first frame
+
+ return true;
+}
+
+
+//
+// G_DeathMatchSpawnPlayer
+// Spawns a player at one of the random death match spots
+// called at level load and each death
+//
+// [STRIFE] Verified unmodified
+//
+void G_DeathMatchSpawnPlayer (int playernum)
+{
+ int i,j;
+ int selections;
+
+ selections = deathmatch_p - deathmatchstarts;
+ if (selections < 4)
+ I_Error ("Only %i deathmatch spots, 4 required", selections);
+
+ for (j=0 ; j<20 ; j++)
+ {
+ i = P_Random() % selections;
+ if (G_CheckSpot (playernum, &deathmatchstarts[i]) )
+ {
+ deathmatchstarts[i].type = playernum+1;
+ P_SpawnPlayer (&deathmatchstarts[i]);
+ return;
+ }
+ }
+
+ // no good spot, so the player will probably get stuck
+ P_SpawnPlayer (&playerstarts[playernum]);
+}
+
+//
+// G_LoadPath
+//
+// haleyjd 10/03/10: [STRIFE] New function
+// Sets loadpath based on the map and "savepathtemp"
+//
+void G_LoadPath(int map)
+{
+ char mapbuf[33];
+
+ memset(mapbuf, 0, sizeof(mapbuf));
+ sprintf(mapbuf, "%d", map);
+
+ // haleyjd: free if already set, and use M_SafeFilePath
+ if(loadpath)
+ Z_Free(loadpath);
+ loadpath = M_SafeFilePath(savepathtemp, mapbuf);
+}
+
+//
+// G_DoReborn
+//
+void G_DoReborn (int playernum)
+{
+ int i;
+
+ if (!netgame)
+ {
+ // reload the level from scratch
+ // [STRIFE] Reborn level load
+ G_LoadPath(gamemap);
+ gameaction = ga_loadgame;
+ }
+ else
+ {
+ // respawn at the start
+
+ // first dissasociate the corpse
+ // [STRIFE] Checks for NULL first
+ if(players[playernum].mo)
+ players[playernum].mo->player = NULL;
+
+ // spawn at random spot if in death match
+ if (deathmatch)
+ {
+ G_DeathMatchSpawnPlayer (playernum);
+ return;
+ }
+
+ if (G_CheckSpot (playernum, &playerstarts[playernum]) )
+ {
+ P_SpawnPlayer (&playerstarts[playernum]);
+ return;
+ }
+
+ // try to spawn at one of the other players spots
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (G_CheckSpot (playernum, &playerstarts[i]) )
+ {
+ playerstarts[i].type = playernum+1; // fake as other player
+ P_SpawnPlayer (&playerstarts[i]);
+ playerstarts[i].type = i+1; // restore
+ return;
+ }
+ // he's going to be inside something. Too bad.
+ }
+ P_SpawnPlayer (&playerstarts[playernum]);
+ }
+}
+
+//
+// G_ScreenShot
+//
+// [STRIFE] Verified unmodified
+//
+void G_ScreenShot (void)
+{
+ gameaction = ga_screenshot;
+}
+
+// haleyjd 08/23/2010: [STRIFE] Removed par times.
+
+//
+// G_DoCompleted
+//
+//boolean secretexit;
+extern char* pagename;
+
+//
+// G_RiftExitLevel
+//
+// haleyjd 08/24/10: [STRIFE] New function
+// * Called from some exit linedefs to exit to a specific riftspot in the
+// given destination map.
+//
+void G_RiftExitLevel(int map, int spot, angle_t angle)
+{
+ gameaction = ga_completed;
+
+ // special handling for post-Sigil map changes
+ if(players[0].weaponowned[wp_sigil])
+ {
+ if(map == 3) // Front Base -> Abandoned Front Base
+ map = 30;
+ if(map == 7) // Castle -> New Front Base
+ map = 10;
+ }
+
+ // no rifting in deathmatch games
+ if(deathmatch)
+ spot = 0;
+
+ riftangle = angle;
+ riftdest = spot;
+ destmap = map;
+}
+
+//
+// G_Exit2
+//
+// haleyjd 10/03/10: [STRIFE] New function.
+// No xrefs to this, doesn't seem to be used. Could have gotten inlined
+// somewhere but I haven't seen it.
+//
+void G_Exit2(int dest, angle_t angle)
+{
+ riftdest = dest;
+ gameaction = ga_completed;
+ riftangle = angle;
+ destmap = gamemap;
+}
+
+//
+// G_ExitLevel
+//
+// haleyjd 08/24/10: [STRIFE]:
+// * Default to next map in numeric order; init destmap and riftdest.
+//
+void G_ExitLevel (int dest)
+{
+ if(dest == 0)
+ dest = gamemap + 1;
+ destmap = dest;
+ riftdest = 0;
+ gameaction = ga_completed;
+}
+
+/*
+// haleyjd 08/23/2010: [STRIFE] No secret exits in Strife.
+// Here's for the german edition.
+void G_SecretExitLevel (void)
+{
+ // IF NO WOLF3D LEVELS, NO SECRET EXIT!
+ if ( (gamemode == commercial)
+ && (W_CheckNumForName("map31")<0))
+ secretexit = false;
+ else
+ secretexit = true;
+ gameaction = ga_completed;
+}
+*/
+
+//
+// G_StartFinale
+//
+// haleyjd 09/21/10: [STRIFE] New function.
+// This replaced G_SecretExitLevel in Strife. I don't know that it's actually
+// used anywhere in the game, but it *is* usable in mods via linetype 124,
+// W1 Start Finale.
+//
+void G_StartFinale(void)
+{
+ gameaction = ga_victory;
+}
+
+//
+// G_DoCompleted
+//
+// haleyjd 08/23/10: [STRIFE]:
+// * Removed G_PlayerFinishLevel and just sets some powerup states.
+// * Removed Chex, as not relevant to Strife.
+// * Removed DOOM level transfer logic
+// * Removed intermission code.
+// * Added setting gameaction to ga_worlddone.
+//
+void G_DoCompleted (void)
+{
+ int i;
+
+ // deal with powerup states
+ for(i = 0; i < MAXPLAYERS; i++)
+ {
+ if(playeringame[i])
+ {
+ // [STRIFE] restore pw_allmap power from mapstate cache
+ if(destmap < 40)
+ players[i].powers[pw_allmap] = players[i].mapstate[destmap];
+
+ // Shadowarmor doesn't persist between maps in netgames
+ if(netgame)
+ players[i].powers[pw_invisibility] = 0;
+ }
+ }
+
+ stonecold = false; // villsa [STRIFE]
+
+ if (automapactive)
+ AM_Stop ();
+
+ // [STRIFE] HUB SAVE
+ if(!deathmatch)
+ G_DoSaveGame(savepathtemp);
+
+ gameaction = ga_worlddone;
+}
+
+
+// haleyjd 08/24/10: [STRIFE] No secret exits.
+/*
+//
+// G_WorldDone
+//
+void G_WorldDone (void)
+{
+ gameaction = ga_worlddone;
+
+ if (secretexit)
+ players[consoleplayer].didsecret = true;
+
+ if ( gamemode == commercial )
+ {
+ switch (gamemap)
+ {
+ case 15:
+ case 31:
+ if (!secretexit)
+ break;
+ case 6:
+ case 11:
+ case 20:
+ case 30:
+ F_StartFinale ();
+ break;
+ }
+ }
+}
+*/
+
+//
+// G_RiftPlayer
+//
+// haleyjd 08/24/10: [STRIFE] New function
+// Teleports the player to the appropriate rift spot.
+//
+void G_RiftPlayer(void)
+{
+ if(riftdest)
+ {
+ P_TeleportMove(players[0].mo,
+ riftSpots[riftdest - 1].x << FRACBITS,
+ riftSpots[riftdest - 1].y << FRACBITS);
+ players[0].mo->angle = riftangle;
+ players[0].mo->health = players[0].health;
+ }
+}
+
+//
+// G_RiftCheat
+//
+// haleyjd 08/24/10: [STRIFE] New function
+// Called from the cheat code to jump to a rift spot.
+//
+boolean G_RiftCheat(int riftSpotNum)
+{
+ return P_TeleportMove(players[0].mo,
+ riftSpots[riftSpotNum - 1].x << FRACBITS,
+ riftSpots[riftSpotNum - 1].y << FRACBITS);
+}
+
+//
+// G_DoWorldDone
+//
+// haleyjd 08/24/10: [STRIFE] Added destmap -> gamemap set.
+//
+void G_DoWorldDone (void)
+{
+ int temp_leveltime = leveltime;
+ boolean temp_shadow = false;
+ boolean temp_mvis = false;
+
+ gamestate = GS_LEVEL;
+ gamemap = destmap;
+
+ // [STRIFE] HUB LOAD
+ G_LoadPath(destmap);
+ if (!deathmatch)
+ {
+ // Remember Shadowarmor across hub loads
+ if(players[0].mo->flags & MF_SHADOW)
+ temp_shadow = true;
+ if(players[0].mo->flags & MF_MVIS)
+ temp_mvis = true;
+ }
+ G_DoLoadGame(false);
+
+ // [STRIFE] leveltime carries over between maps
+ leveltime = temp_leveltime;
+
+ if(!deathmatch)
+ {
+ // [STRIFE]: transfer saved powerups
+ players[0].mo->flags &= ~(MF_SHADOW|MF_MVIS);
+ if(temp_shadow)
+ players[0].mo->flags |= MF_SHADOW;
+ if(temp_mvis)
+ players[0].mo->flags |= MF_MVIS;
+
+ // [STRIFE] HUB SAVE
+ G_RiftPlayer();
+ G_DoSaveGame(savepathtemp);
+ M_SaveMisObj(savepathtemp);
+ }
+
+ gameaction = ga_nothing;
+ viewactive = true;
+}
+
+//
+// G_DoWorldDone2
+//
+// haleyjd 10/03/10: [STRIFE] New function. No xrefs; unused.
+//
+void G_DoWorldDone2(void)
+{
+ gamestate = GS_LEVEL;
+ gameaction = ga_nothing;
+ viewactive = true;
+}
+
+//
+// G_ReadCurrent
+//
+// haleyjd 10/03/10: [STRIFE] New function.
+// Reads the "CURRENT" file from the given path and then sets it to
+// gamemap.
+//
+void G_ReadCurrent(const char *path)
+{
+ char *temppath = NULL;
+ byte *buffer = NULL;
+
+ temppath = M_SafeFilePath(path, "\\current");
+
+ if(M_ReadFile(temppath, &buffer) <= 0)
+ gameaction = ga_newgame;
+ else
+ {
+ // haleyjd 20110211: do endian-correct read
+ gamemap = (((int)buffer[0]) |
+ ((int)buffer[1] << 8) |
+ ((int)buffer[2] << 16) |
+ ((int)buffer[3] << 24));
+ gameaction = ga_loadgame;
+ Z_Free(buffer);
+ }
+
+ Z_Free(temppath);
+
+ G_LoadPath(gamemap);
+}
+
+//
+// G_InitFromSavegame
+// Can be called by the startup code or the menu task.
+//
+extern boolean setsizeneeded;
+void R_ExecuteSetViewSize (void);
+
+char savename[256];
+
+// [STRIFE]: No such function, at least in v1.2
+// STRIFE-TODO: Does this come back in v1.31?
+/*
+void G_LoadGame (char* name)
+{
+ strcpy (savename, name);
+ gameaction = ga_loadgame;
+}
+*/
+
+// haleyjd 09/28/10: [STRIFE] VERSIONSIZE == 8
+#define VERSIONSIZE 8
+
+void G_DoLoadGame (boolean userload)
+{
+ int savedleveltime;
+
+ gameaction = ga_nothing;
+
+ save_stream = fopen(loadpath, "rb");
+
+ // [STRIFE] If the file does not exist, G_DoLoadLevel is called.
+ if (save_stream == NULL)
+ {
+ G_DoLoadLevel();
+ return;
+ }
+
+ savegame_error = false;
+
+ if (!P_ReadSaveGameHeader())
+ {
+ fclose(save_stream);
+ return;
+ }
+
+ // haleyjd: A comment would be good here, fraggle...
+ // Evidently this is a Choco-ism, necessitated by reading the savegame
+ // header *before* calling G_DoLoadLevel.
+ savedleveltime = leveltime;
+
+ // load a base level
+
+ // STRIFE-TODO: ????
+ if(userload)
+ G_InitNew(gameskill, gamemap);
+ else
+ G_DoLoadLevel();
+
+ leveltime = savedleveltime;
+
+ // dearchive all the modifications
+ // [STRIFE] some portions of player_t are not overwritten when loading
+ // between hub levels
+ P_UnArchivePlayers (userload);
+ P_UnArchiveWorld ();
+ P_UnArchiveThinkers ();
+ P_UnArchiveSpecials ();
+
+ if (!P_ReadSaveGameEOF())
+ I_Error ("Bad savegame");
+
+ fclose(save_stream);
+
+ if (setsizeneeded)
+ R_ExecuteSetViewSize ();
+
+ // draw the pattern into the back screen
+ R_FillBackScreen ();
+}
+
+//
+// G_WriteSaveName
+//
+// haleyjd 2010103: [STRIFE] New function
+//
+// Writes the character name to the NAME file.
+//
+boolean G_WriteSaveName(int slot, const char *charname)
+{
+ //char savedir[16];
+ char *tmpname;
+ boolean retval;
+
+ savegameslot = slot;
+
+ // haleyjd: removed special -cdrom treatment, as I believe it is taken
+ // care of automatically via using Choco's savegamedir setting.
+
+ // haleyjd: free previous path, if any, and allocate new one using
+ // M_SafeFilePath routine, which isn't limited to 128 characters.
+ if(savepathtemp)
+ Z_Free(savepathtemp);
+ savepathtemp = M_SafeFilePath(savegamedir, "strfsav6.ssg");
+
+ // haleyjd: as above.
+ if(savepath)
+ Z_Free(savepath);
+ savepath = M_SafeFilePath(savegamedir, M_MakeStrifeSaveDir(savegameslot, ""));
+
+ // haleyjd: memset full character_name for safety
+ memset(character_name, 0, CHARACTER_NAME_LEN);
+ strcpy(character_name, charname);
+
+ // haleyjd: use M_SafeFilePath
+ tmpname = M_SafeFilePath(savepathtemp, "name");
+
+ // Write the "name" file under the directory
+ retval = M_WriteFile(tmpname, character_name, 32);
+
+ Z_Free(tmpname);
+
+ return retval;
+}
+
+//
+// G_SaveGame
+// Called by the menu task.
+// Description is a 24 byte text string
+//
+// [STRIFE] No such function, at least in v1.2
+// STRIFE-TODO: Does this make a comeback in v1.31?
+/*
+void
+G_SaveGame
+( int slot,
+ char* description )
+{
+ savegameslot = slot;
+ strcpy (savedescription, description);
+ sendsave = true;
+}
+*/
+
+void G_DoSaveGame (char *path)
+{
+ char *current_path;
+ char *savegame_file;
+ char *temp_savegame_file;
+ byte gamemapbytes[4];
+ char gamemapstr[33];
+
+ temp_savegame_file = P_TempSaveGameFile();
+
+ // [STRIFE] custom save file path logic
+ memset(gamemapstr, 0, sizeof(gamemapstr));
+ sprintf(gamemapstr, "%d", gamemap);
+ savegame_file = M_SafeFilePath(path, gamemapstr);
+
+ // [STRIFE] write the "current" file, which tells which hub map
+ // the save slot is currently on.
+ current_path = M_SafeFilePath(path, "current");
+ // haleyjd: endian-agnostic IO
+ gamemapbytes[0] = (byte)( gamemap & 0xff);
+ gamemapbytes[1] = (byte)((gamemap >> 8) & 0xff);
+ gamemapbytes[2] = (byte)((gamemap >> 16) & 0xff);
+ gamemapbytes[3] = (byte)((gamemap >> 24) & 0xff);
+ M_WriteFile(current_path, gamemapbytes, 4);
+ Z_Free(current_path);
+
+ // Open the savegame file for writing. We write to a temporary file
+ // and then rename it at the end if it was successfully written.
+ // This prevents an existing savegame from being overwritten by
+ // a corrupted one, or if a savegame buffer overrun occurs.
+
+ save_stream = fopen(temp_savegame_file, "wb");
+
+ if (save_stream == NULL)
+ {
+ return;
+ }
+
+ savegame_error = false;
+
+ P_WriteSaveGameHeader(savedescription);
+
+ P_ArchivePlayers ();
+ P_ArchiveWorld ();
+ P_ArchiveThinkers ();
+ P_ArchiveSpecials ();
+
+ P_WriteSaveGameEOF();
+
+ // Enforce the same savegame size limit as in Vanilla Doom,
+ // except if the vanilla_savegame_limit setting is turned off.
+ // [STRIFE]: Verified subject to same limit.
+
+ if (vanilla_savegame_limit && ftell(save_stream) > SAVEGAMESIZE)
+ {
+ I_Error ("Savegame buffer overrun");
+ }
+
+ // Finish up, close the savegame file.
+
+ fclose(save_stream);
+
+ // Now rename the temporary savegame file to the actual savegame
+ // file, overwriting the old savegame if there was one there.
+
+ remove(savegame_file);
+ rename(temp_savegame_file, savegame_file);
+
+ // haleyjd: free the savegame_file path
+ Z_Free(savegame_file);
+
+ gameaction = ga_nothing;
+ //strcpy(savedescription, "");
+
+ // [STRIFE]: custom message logic
+ if(!strcmp(path, savepath))
+ {
+ sprintf(savename, "%s saved.", character_name);
+ players[consoleplayer].message = savename;
+ }
+
+ // draw the pattern into the back screen
+ R_FillBackScreen ();
+}
+
+
+//
+skill_t d_skill;
+//int d_episode; [STRIFE] No such thing as episodes in Strife
+int d_map;
+
+//
+// G_DeferedInitNew
+//
+// Can be called by the startup code or the menu task,
+// consoleplayer, displayplayer, playeringame[] should be set.
+//
+// haleyjd 09/22/10: [STRIFE] Removed episode parameter
+//
+void G_DeferedInitNew(skill_t skill, int map)
+{
+ d_skill = skill;
+ d_map = map;
+ gameaction = ga_newgame;
+}
+
+//
+// G_DoNewGame
+//
+// [STRIFE] Code added to turn off the stonecold effect.
+// Someone also removed the nomonsters reset...
+//
+void G_DoNewGame (void)
+{
+ demoplayback = false;
+ netdemo = false;
+ netgame = false;
+ deathmatch = false;
+ playeringame[1] = playeringame[2] = playeringame[3] = 0;
+ respawnparm = false;
+ fastparm = false;
+ stonecold = false; // villsa [STRIFE]
+ //nomonsters = false; [STRIFE] not set here!?!
+ consoleplayer = 0;
+ G_InitNew (d_skill, d_map);
+ gameaction = ga_nothing;
+}
+
+//
+// G_InitNew
+//
+// haleyjd 08/24/10: [STRIFE]:
+// * Added riftdest initialization
+// * Removed episode parameter
+//
+void
+G_InitNew
+( skill_t skill,
+ int map )
+{
+ char *skytexturename;
+ int i;
+
+ if (paused)
+ {
+ paused = false;
+ S_ResumeSound ();
+ }
+
+ if (skill > sk_nightmare)
+ skill = sk_nightmare;
+
+ // [STRIFE] Removed episode nonsense and gamemap clipping
+
+ M_ClearRandom ();
+
+ if (skill == sk_nightmare || respawnparm )
+ respawnmonsters = true;
+ else
+ respawnmonsters = false;
+
+ // [STRIFE] Strife skill level mobjinfo/states tweaking
+ // BUG: None of this code runs properly when loading save games, so
+ // basically it's impossible to play any skill level properly unless
+ // you never quit and reload from the command line.
+ if(!skill && gameskill)
+ {
+ // Setting to Baby skill... make things easier.
+
+ // Acolytes walk, attack, and feel pain slower
+ for(i = S_AGRD_13; i <= S_AGRD_23; i++)
+ states[i].tics *= 2;
+
+ // Reavers attack slower
+ for(i = S_ROB1_10; i <= S_ROB1_15; i++)
+ states[i].tics *= 2;
+
+ // Turrets attack slower
+ for(i = S_TURT_02; i <= S_TURT_03; i++)
+ states[i].tics *= 2;
+
+ // Crusaders attack and feel pain slower
+ for(i = S_ROB2_09; i <= S_ROB2_19; i++)
+ states[i].tics *= 2;
+
+ // Stalkers think, walk, and attack slower
+ for(i = S_SPID_03; i <= S_SPID_10; i++)
+ states[i].tics *= 2;
+
+ // The Bishop's homing missiles are faster (what?? BUG?)
+ mobjinfo[MT_SEEKMISSILE].speed *= 2;
+ }
+ if(skill && !gameskill)
+ {
+ // Setting a higher skill when previously on baby... make things normal
+
+ // Acolytes
+ for(i = S_AGRD_13; i <= S_AGRD_23; i++)
+ states[i].tics >>= 1;
+
+ // Reavers
+ for(i = S_ROB1_10; i <= S_ROB1_15; i++)
+ states[i].tics >>= 1;
+
+ // Turrets
+ for(i = S_TURT_02; i <= S_TURT_03; i++)
+ states[i].tics >>= 1;
+
+ // Crusaders
+ for(i = S_ROB2_09; i <= S_ROB2_19; i++)
+ states[i].tics >>= 1;
+
+ // Stalkers
+ for(i = S_SPID_03; i <= S_SPID_10; i++)
+ states[i].tics >>= 1;
+
+ // The Bishop's homing missiles - again, seemingly backward.
+ mobjinfo[MT_SEEKMISSILE].speed >>= 1;
+ }
+ if(fastparm || (skill == sk_nightmare && skill != gameskill))
+ {
+ // BLOODBATH! Make some things super-aggressive.
+
+ // Acolytes walk, attack, and feel pain twice as fast
+ // (This makes just getting out of the first room almost impossible)
+ for(i = S_AGRD_13; i <= S_AGRD_23; i++)
+ states[i].tics >>= 1;
+
+ // Bishop's homing missiles again get SLOWER and not faster o_O
+ mobjinfo[MT_SEEKMISSILE].speed >>= 1;
+ }
+ else if(skill != sk_nightmare && gameskill == sk_nightmare)
+ {
+ // Setting back to an ordinary skill after being on Bloodbath?
+ // Put stuff back to normal.
+
+ // Acolytes
+ for(i = S_AGRD_13; i <= S_AGRD_23; i++)
+ states[i].tics *= 2;
+
+ // Bishop's homing missiles
+ mobjinfo[MT_SEEKMISSILE].speed *= 2;
+ }
+
+ // force players to be initialized upon first level load
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ players[i].playerstate = PST_REBORN;
+
+ usergame = true; // will be set false if a demo
+ paused = false;
+ demoplayback = false;
+ automapactive = false;
+ viewactive = true;
+ //gameepisode = episode; [STRIFE] no episodes
+ gamemap = map;
+ gameskill = skill;
+ riftdest = 0; // haleyjd 08/24/10: [STRIFE] init riftdest to zero on new game
+
+ // Set the sky to use.
+ //
+ // Note: This IS broken, but it is how Vanilla Doom behaves.
+ // See http://doom.wikia.com/wiki/Sky_never_changes_in_Doom_II.
+ //
+ // Because we set the sky here at the start of a game, not at the
+ // start of a level, the sky texture never changes unless we
+ // restore from a saved game. This was fixed before the Doom
+ // source release, but this IS the way Vanilla DOS Doom behaves.
+
+ // [STRIFE] Strife skies (of which there are but two)
+ if(gamemap >= 9 && gamemap < 32)
+ skytexturename = "skymnt01";
+ else
+ skytexturename = "skymnt02";
+
+ skytexturename = DEH_String(skytexturename);
+
+ skytexture = R_TextureNumForName(skytexturename);
+
+ // [STRIFE] HUBS
+ G_LoadPath(gamemap);
+ G_DoLoadLevel();
+}
+
+
+//
+// DEMO RECORDING
+//
+#define DEMOMARKER 0x80
+
+//
+// G_ReadDemoTiccmd
+//
+// [STRIFE] Modified for Strife ticcmd_t
+//
+void G_ReadDemoTiccmd (ticcmd_t* cmd)
+{
+ if (*demo_p == DEMOMARKER)
+ {
+ // end of demo data stream
+ G_CheckDemoStatus ();
+ return;
+ }
+ cmd->forwardmove = ((signed char)*demo_p++);
+ cmd->sidemove = ((signed char)*demo_p++);
+ cmd->angleturn = ((unsigned char) *demo_p++)<<8;
+ cmd->buttons = (unsigned char)*demo_p++;
+ cmd->buttons2 = (unsigned char)*demo_p++; // [STRIFE]
+ cmd->inventory = (int)*demo_p++; // [STRIFE]
+}
+
+// Increase the size of the demo buffer to allow unlimited demos
+
+static void IncreaseDemoBuffer(void)
+{
+ int current_length;
+ byte *new_demobuffer;
+ byte *new_demop;
+ int new_length;
+
+ // Find the current size
+
+ current_length = demoend - demobuffer;
+
+ // Generate a new buffer twice the size
+ new_length = current_length * 2;
+
+ new_demobuffer = Z_Malloc(new_length, PU_STATIC, 0);
+ new_demop = new_demobuffer + (demo_p - demobuffer);
+
+ // Copy over the old data
+
+ memcpy(new_demobuffer, demobuffer, current_length);
+
+ // Free the old buffer and point the demo pointers at the new buffer.
+
+ Z_Free(demobuffer);
+
+ demobuffer = new_demobuffer;
+ demo_p = new_demop;
+ demoend = demobuffer + new_length;
+}
+
+//
+// G_WriteDemoTiccmd
+//
+// [STRIFE] Modified for Strife ticcmd_t.
+//
+void G_WriteDemoTiccmd (ticcmd_t* cmd)
+{
+ byte *demo_start;
+
+ if (gamekeydown[key_demo_quit]) // press q to end demo recording
+ G_CheckDemoStatus ();
+
+ demo_start = demo_p;
+
+ *demo_p++ = cmd->forwardmove;
+ *demo_p++ = cmd->sidemove;
+ *demo_p++ = cmd->angleturn >> 8;
+ *demo_p++ = cmd->buttons;
+ *demo_p++ = cmd->buttons2; // [STRIFE]
+ *demo_p++ = (byte)(cmd->inventory & 0xff); // [STRIFE]
+
+ // reset demo pointer back
+ demo_p = demo_start;
+
+ if (demo_p > demoend - 16)
+ {
+ if (vanilla_demo_limit)
+ {
+ // no more space
+ G_CheckDemoStatus ();
+ return;
+ }
+ else
+ {
+ // Vanilla demo limit disabled: unlimited
+ // demo lengths!
+
+ IncreaseDemoBuffer();
+ }
+ }
+
+ G_ReadDemoTiccmd (cmd); // make SURE it is exactly the same
+}
+
+
+
+//
+// G_RecordDemo
+//
+// [STRIFE] Verified unmodified
+//
+void G_RecordDemo (char* name)
+{
+ int i;
+ int maxsize;
+
+ usergame = false;
+ demoname = Z_Malloc(strlen(name) + 5, PU_STATIC, NULL);
+ sprintf(demoname, "%s.lmp", name);
+ maxsize = 0x20000;
+
+ //!
+ // @arg <size>
+ // @category demo
+ // @vanilla
+ //
+ // Specify the demo buffer size (KiB)
+ //
+
+ i = M_CheckParmWithArgs("-maxdemo", 1);
+ if (i)
+ maxsize = atoi(myargv[i+1])*1024;
+ demobuffer = Z_Malloc (maxsize,PU_STATIC,NULL);
+ demoend = demobuffer + maxsize;
+
+ demorecording = true;
+}
+
+
+void G_BeginRecording (void)
+{
+ int i;
+
+ //
+ // @category demo
+ //
+ // Record a high resolution "Doom 1.91" demo.
+ //
+
+ // STRIFE-TODO: if somebody makes a "Strife Plus", we could add this.
+ /*
+ longtics = M_CheckParm("-longtics") != 0;
+ */
+ longtics = false;
+
+ // If not recording a longtics demo, record in low res
+ lowres_turn = !longtics;
+
+ demo_p = demobuffer;
+
+ // Save the right version code for this demo
+ *demo_p++ = STRIFE_VERSION;
+
+ *demo_p++ = gameskill;
+ //*demo_p++ = gameepisode; [STRIFE] Doesn't have episodes.
+ *demo_p++ = gamemap;
+ *demo_p++ = deathmatch;
+ *demo_p++ = respawnparm;
+ *demo_p++ = fastparm;
+ *demo_p++ = nomonsters;
+ *demo_p++ = consoleplayer;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ *demo_p++ = playeringame[i];
+}
+
+
+//
+// G_PlayDemo
+//
+
+char* defdemoname;
+
+//
+// G_DeferedPlayDemo
+//
+// [STRIFE] Verified unmodified
+//
+void G_DeferedPlayDemo (char* name)
+{
+ defdemoname = name;
+ gameaction = ga_playdemo;
+}
+
+// Generate a string describing a demo version
+// [STRIFE] Modified to handle the one and only Strife demo version.
+static char *DemoVersionDescription(int version)
+{
+ static char resultbuf[16];
+
+ // [STRIFE] All versions of Strife 1.1 and later use 101 as their
+ // internal version number. Brilliant, huh? So we can't discern much
+ // here.
+
+ switch (version)
+ {
+ case 100:
+ return "v1.0"; // v1.0 would be the ancient demo version
+ default:
+ break;
+ }
+
+ // Unknown version. Who knows?
+ sprintf(resultbuf, "%i.%i (unknown)", version / 100, version % 100);
+
+ return resultbuf;
+}
+
+//
+// G_DoPlayDemo
+//
+// [STRIFE] Modified for Strife demo format.
+//
+void G_DoPlayDemo (void)
+{
+ skill_t skill;
+ int i, map;
+ int demoversion;
+
+ gameaction = ga_nothing;
+ demobuffer = demo_p = W_CacheLumpName (defdemoname, PU_STATIC);
+
+ demoversion = *demo_p++;
+
+ if (demoversion == STRIFE_VERSION)
+ {
+ longtics = false;
+ }
+ /* STRIFE-TODO: Not until/unless somebody makes a Strife-Plus :P
+ else if (demoversion == DOOM_191_VERSION)
+ {
+ // demo recorded with cph's modified "v1.91" doom exe
+ longtics = true;
+ }
+ */
+ else
+ {
+ char *message = "Demo is from a different game version!\n"
+ "(read %i, should be %i)\n"
+ "\n"
+ "*** You may need to upgrade your version "
+ "of Strife to v1.1 or later. ***\n"
+ " See: http://doomworld.com/files/patches.shtml\n"
+ " This appears to be %s.";
+
+ I_Error(message, demoversion, STRIFE_VERSION,
+ DemoVersionDescription(demoversion));
+ }
+
+ skill = *demo_p++;
+ //episode = *demo_p++; [STRIFE] No episodes
+ map = *demo_p++;
+ deathmatch = *demo_p++;
+ respawnparm = *demo_p++;
+ fastparm = *demo_p++;
+ nomonsters = *demo_p++;
+ consoleplayer = *demo_p++;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ playeringame[i] = *demo_p++;
+
+ //!
+ // @category demo
+ //
+ // Play back a demo recorded in a netgame with a single player.
+ //
+
+ if (playeringame[1] || M_CheckParm("-solo-net") > 0
+ || M_CheckParm("-netdemo") > 0)
+ {
+ netgame = true;
+ netdemo = true;
+ }
+
+ // don't spend a lot of time in loadlevel
+ precache = false;
+ G_InitNew(skill, map);
+ precache = true;
+
+ // [STRIFE] not here...
+ //starttime = I_GetTime ();
+
+ usergame = false;
+ demoplayback = true;
+}
+
+//
+// G_TimeDemo
+//
+// [STRIFE] Verified unmodified
+//
+void G_TimeDemo (char* name)
+{
+ //!
+ // @vanilla
+ //
+ // Disable rendering the screen entirely.
+ //
+
+ nodrawers = M_CheckParm ("-nodraw");
+
+ timingdemo = true;
+ singletics = true;
+
+ defdemoname = name;
+ gameaction = ga_playdemo;
+}
+
+
+/*
+===================
+=
+= G_CheckDemoStatus
+=
+= Called after a death or level completion to allow demos to be cleaned up
+= Returns true if a new demo loop action will take place
+===================
+*/
+//
+// [STRIFE] Verified unmodified
+//
+boolean G_CheckDemoStatus (void)
+{
+ int endtime;
+
+ if (timingdemo)
+ {
+ float fps;
+ int realtics;
+
+ endtime = I_GetTime ();
+ realtics = endtime - starttime;
+ fps = ((float) gametic * TICRATE) / realtics;
+
+ // Prevent recursive calls
+ timingdemo = false;
+ demoplayback = false;
+
+ I_Error ("timed %i gametics in %i realtics (%f fps)",
+ gametic, realtics, fps);
+ }
+
+ if (demoplayback)
+ {
+ W_ReleaseLumpName(defdemoname);
+ demoplayback = false;
+ netdemo = false;
+ netgame = false;
+ deathmatch = false;
+ playeringame[1] = playeringame[2] = playeringame[3] = 0;
+ respawnparm = false;
+ fastparm = false;
+ nomonsters = false;
+ consoleplayer = 0;
+
+ if (singledemo)
+ I_Quit ();
+ else
+ D_AdvanceDemo ();
+
+ return true;
+ }
+
+ if (demorecording)
+ {
+ *demo_p++ = DEMOMARKER;
+ M_WriteFile (demoname, demobuffer, demo_p - demobuffer);
+ Z_Free (demobuffer);
+ demorecording = false;
+ I_Error ("Demo %s recorded", demoname);
+ }
+
+ return false;
+}
diff --git a/src/strife/g_game.h b/src/strife/g_game.h
new file mode 100644
index 00000000..61b2d5de
--- /dev/null
+++ b/src/strife/g_game.h
@@ -0,0 +1,97 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Duh.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __G_GAME__
+#define __G_GAME__
+
+#include "doomdef.h"
+#include "d_event.h"
+#include "d_ticcmd.h"
+#include "tables.h"
+
+//
+// GAME
+//
+void G_DeathMatchSpawnPlayer (int playernum);
+
+// [STRIFE] Removed episode parameter
+void G_InitNew (skill_t skill, 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
+// [STRIFE] Removed episode parameter
+void G_DeferedInitNew (skill_t skill, 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 (boolean userload);
+
+// 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_PlayDemo (char* name);
+void G_TimeDemo (char* name);
+boolean G_CheckDemoStatus (void);
+
+void G_RiftExitLevel(int map, int spot, angle_t angle); // [STRIFE]
+void G_ExitLevel (int dest);
+//void G_SecretExitLevel (void);
+
+void G_StartFinale(void); // [STRIFE]
+
+//void G_WorldDone (void);
+
+boolean G_RiftCheat(int riftSpotNum); // [STRIFE]
+
+// Read current data from inputs and build a player movement command.
+
+void G_BuildTiccmd (ticcmd_t *cmd, int maketic);
+
+void G_Ticker (void);
+boolean G_Responder (event_t* ev);
+
+void G_ScreenShot (void);
+
+void G_DrawMouseSpeedBox(void);
+
+// [STRIFE]
+boolean G_WriteSaveName(int slot, const char *charname);
+void G_ReadCurrent(const char *path);
+
+extern int vanilla_savegame_limit;
+extern int vanilla_demo_limit;
+#endif
diff --git a/src/strife/hu_lib.c b/src/strife/hu_lib.c
new file mode 100644
index 00000000..38ab644a
--- /dev/null
+++ b/src/strife/hu_lib.c
@@ -0,0 +1,482 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION: heads-up text and input code
+//
+//-----------------------------------------------------------------------------
+
+
+#include <ctype.h>
+
+#include "doomdef.h"
+#include "doomkeys.h"
+
+#include "v_video.h"
+#include "i_swap.h"
+
+#include "hu_lib.h"
+#include "r_local.h"
+#include "r_draw.h"
+#include "hu_stuff.h" // [STRIFE]
+
+// boolean : whether the screen is always erased
+#define noterased viewwindowx
+
+extern boolean automapactive; // in AM_map.c
+
+extern boolean D_PatchClipCallback(patch_t *patch, int x, int y); // [STRIFE]
+
+//
+// HUlib_drawYellowText
+//
+// haleyjd 20100918: [STRIFE] New function.
+//
+void HUlib_drawYellowText(int x, int y, char *text)
+{
+ int start_x = x;
+ char *rover = text;
+ char c;
+
+ while((c = *rover++))
+ {
+ if(c == '\n')
+ {
+ x = start_x;
+ y += 12;
+ continue;
+ }
+
+ // haleyjd 20110213: found MORE code ignored/misinterpreted by Hex-Rays:
+ // Underscores are replaced by spaces.
+ if(c == '_')
+ c = ' ';
+ else if (c == ' ' && x == start_x) // skip spaces at the start of a line
+ continue;
+
+ c = toupper(c) - HU_FONTSTART;
+
+ if(c >= 0 && c < HU_FONTSIZE)
+ {
+ patch_t *patch = yfont[(int) c];
+ int width = SHORT(patch->width);
+
+ if(x + width <= (SCREENWIDTH - 20))
+ {
+ // haleyjd: STRIFE-TODO: bit different than the exe... for now
+ if(!D_PatchClipCallback(patch, x + SHORT(patch->leftoffset),
+ y + SHORT(patch->topoffset)))
+ return;
+ V_DrawPatchDirect(x, y, patch);
+ x = x + width;
+ }
+ else
+ {
+ x = start_x;
+ --rover;
+ y += 12;
+ }
+ }
+ else
+ {
+ x += 4;
+ }
+ }
+}
+
+//
+// HUlib_init
+//
+// [STRIFE] Verified unmodified.
+//
+void HUlib_init(void)
+{
+}
+
+//
+// HUlib_clearTextLine
+//
+// [STRIFE] Verified unmodified.
+//
+void HUlib_clearTextLine(hu_textline_t* t)
+{
+ t->len = 0;
+ t->l[0] = 0;
+ t->needsupdate = true;
+}
+
+//
+// HUlib_initTextLine
+//
+// [STRIFE] Verified unmodified
+//
+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);
+}
+
+//
+// HUlib_addCharToTextLine
+//
+// [STRIFE] Verified unmodified.
+//
+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;
+ }
+}
+
+//
+// HUlib_delCharFromTextLine
+//
+// [STRIFE] Verified unmodified.
+//
+boolean HUlib_delCharFromTextLine(hu_textline_t* t)
+{
+ if (!t->len) return false;
+ else
+ {
+ t->l[--t->len] = 0;
+ t->needsupdate = 4;
+ return true;
+ }
+}
+
+//
+// HUlib_drawTextLine
+//
+// haleyjd 09/18/10: [STRIFE] Modified to not draw underscores in text.
+//
+void
+HUlib_drawTextLine
+( hu_textline_t* l,
+ 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 = toupper(l->l[i]);
+ if (c != ' ' && c >= l->sc && c < '_') // [STRIFE]: Underscores excluded
+ {
+ w = SHORT(l->f[c - l->sc]->width);
+ if (x+w > SCREENWIDTH)
+ break;
+ V_DrawPatchDirect(x, l->y, 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, l->f['_' - l->sc]);
+ }
+}
+
+//
+// HUlib_eraseTextLine
+//
+// sorta called by HU_Erase and just better darn get things straight
+//
+// [STRIFE] Verified unmodified.
+//
+void HUlib_eraseTextLine(hu_textline_t* l)
+{
+ int lh;
+ int y;
+ int yoffset;
+
+ // 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
+ }
+ }
+ }
+
+ if (l->needsupdate) l->needsupdate--;
+}
+
+//
+// HUlib_initSText
+//
+// [STRIFE] Verified unmodified.
+//
+void
+HUlib_initSText
+( hu_stext_t* s,
+ int x,
+ int y,
+ int h,
+ patch_t** font,
+ int startchar,
+ 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);
+ }
+}
+
+//
+// HUlib_addLineToSText
+//
+// [STRIFE] Verified unmodified.
+//
+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;
+}
+
+//
+// HUlib_addMessageToSText
+//
+// [STRIFE] Verified unmodified.
+//
+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++));
+}
+
+//
+// HUlib_drawSText
+//
+// [STRIFE] Verified unmodified.
+//
+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
+ }
+}
+
+//
+// HUlib_eraseSText
+//
+// [STRIFE] Verified unmodified.
+//
+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;
+}
+
+//
+// HUlib_initIText
+//
+// [STRIFE] Verified unmodified.
+//
+void
+HUlib_initIText
+( hu_itext_t* it,
+ int x,
+ int y,
+ patch_t** font,
+ int startchar,
+ 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
+// [STRIFE] Verified unmodified.
+void HUlib_delCharFromIText(hu_itext_t* it)
+{
+ if (it->l.len != it->lm)
+ HUlib_delCharFromTextLine(&it->l);
+}
+
+// [STRIFE] Verified unmodified.
+void HUlib_eraseLineFromIText(hu_itext_t* it)
+{
+ while (it->lm != it->l.len)
+ HUlib_delCharFromTextLine(&it->l);
+}
+
+// Resets left margin as well
+// [STRIFE] Verified unmodified.
+void HUlib_resetIText(hu_itext_t* it)
+{
+ it->lm = 0;
+ HUlib_clearTextLine(&it->l);
+}
+
+//
+// HUlib_addPrefixToIText
+//
+// [STRIFE] Verified unmodified.
+//
+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
+// [STRIFE] Verified unmodified.
+boolean
+HUlib_keyInIText
+( hu_itext_t* it,
+ unsigned char ch )
+{
+ ch = toupper(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
+}
+
+//
+// HUlib_drawIText
+//
+// [STRIFE] Verified unmodified.
+//
+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
+}
+
+//
+// HUlib_eraseIText
+//
+// [STRIFE] Verified unmodified.
+//
+void HUlib_eraseIText(hu_itext_t* it)
+{
+ if (it->laston && !*it->on)
+ it->l.needsupdate = 4;
+ HUlib_eraseTextLine(&it->l);
+ it->laston = *it->on;
+}
+
diff --git a/src/strife/hu_lib.h b/src/strife/hu_lib.h
new file mode 100644
index 00000000..2a087800
--- /dev/null
+++ b/src/strife/hu_lib.h
@@ -0,0 +1,193 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION: none
+//
+//-----------------------------------------------------------------------------
+
+#ifndef __HULIB__
+#define __HULIB__
+
+// We are referring to patches.
+#include "r_defs.h"
+
+// 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 boolean stating whether to update window
+ boolean* on;
+ 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 boolean stating whether to update window
+ boolean* on;
+ 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
+boolean HUlib_addCharToTextLine(hu_textline_t *t, char ch);
+
+// returns success
+boolean HUlib_delCharFromTextLine(hu_textline_t *t);
+
+// draws tline
+void HUlib_drawTextLine(hu_textline_t *l, boolean drawcursor);
+
+// erases text line
+void HUlib_eraseTextLine(hu_textline_t *l);
+
+// villsa [STRIFE]
+void HUlib_drawYellowText(int x, int y, char *text);
+
+
+//
+// Scrolling Text window widget routines
+//
+
+// ?
+void
+HUlib_initSText
+( hu_stext_t* s,
+ int x,
+ int y,
+ int h,
+ patch_t** font,
+ int startchar,
+ 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,
+ 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
+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
diff --git a/src/strife/hu_stuff.c b/src/strife/hu_stuff.c
new file mode 100644
index 00000000..eae9d166
--- /dev/null
+++ b/src/strife/hu_stuff.c
@@ -0,0 +1,666 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION: Heads-up displays
+//
+//-----------------------------------------------------------------------------
+
+
+#include <ctype.h>
+
+#include "doomdef.h"
+#include "doomkeys.h"
+
+#include "z_zone.h"
+
+#include "deh_main.h"
+#include "i_swap.h"
+#include "i_video.h"
+
+#include "hu_stuff.h"
+#include "hu_lib.h"
+#include "m_controls.h"
+#include "w_wad.h"
+
+#include "s_sound.h"
+
+#include "doomstat.h"
+
+// Data.
+#include "dstrings.h"
+#include "sounds.h"
+
+//
+// Locally used constants, shortcuts.
+//
+#define HU_TITLE (mapnames[gamemap-1])
+#define HU_TITLEHEIGHT 1
+#define HU_TITLEX 0
+
+// haleyjd 09/01/10: [STRIFE] 167 -> 160 to move up level name
+#define HU_TITLEY (160 - 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
+
+char *chat_macros[10] =
+{
+ HUSTR_CHATMACRO0,
+ HUSTR_CHATMACRO1,
+ HUSTR_CHATMACRO2,
+ HUSTR_CHATMACRO3,
+ HUSTR_CHATMACRO4,
+ HUSTR_CHATMACRO5,
+ HUSTR_CHATMACRO6,
+ HUSTR_CHATMACRO7,
+ HUSTR_CHATMACRO8,
+ HUSTR_CHATMACRO9
+};
+
+// villsa [STRIFE]
+char pnameprefixes[8][16] =
+{
+ "1: ",
+ "2: ",
+ "3: ",
+ "4: ",
+ "5: ",
+ "6: ",
+ "7: ",
+ "8: "
+};
+
+char* player_names[] =
+{
+ HUSTR_PLRGREEN,
+ HUSTR_PLRINDIGO,
+ HUSTR_PLRBROWN,
+ HUSTR_PLRRED
+};
+
+char chat_char; // remove later.
+static player_t* plr;
+patch_t* hu_font[HU_FONTSIZE];
+patch_t* yfont[HU_FONTSIZE]; // haleyjd 09/18/10: [STRIFE]
+static hu_textline_t w_title;
+boolean chat_on;
+static hu_itext_t w_chat;
+static boolean always_off = false;
+static char chat_dest[MAXPLAYERS];
+static hu_itext_t w_inputbuffer[MAXPLAYERS];
+
+static boolean message_on;
+boolean message_dontfuckwithme;
+static boolean message_nottobefuckedwith;
+
+static hu_stext_t w_message;
+static int message_counter;
+
+//extern int showMessages; [STRIFE] no such variable
+
+static boolean headsupactive = false;
+
+static char * nickname; // haleyjd 09/18/10: [STRIFE]
+
+//
+// Builtin map names.
+// The actual names can be found in DStrings.h.
+//
+
+// haleyjd 08/31/10: [STRIFE] Changed for Strife level names.
+// List of names for levels.
+
+char *mapnames[] =
+{
+ // Strife map names
+
+ // First "episode" - Quest to destroy the Order's Castle
+ HUSTR_1,
+ HUSTR_2,
+ HUSTR_3,
+ HUSTR_4,
+ HUSTR_5,
+ HUSTR_6,
+ HUSTR_7,
+ HUSTR_8,
+ HUSTR_9,
+
+ // Second "episode" - Kill the Bishop and Make a Choice
+ HUSTR_10,
+ HUSTR_11,
+ HUSTR_12,
+ HUSTR_13,
+ HUSTR_14,
+ HUSTR_15,
+ HUSTR_16,
+ HUSTR_17,
+ HUSTR_18,
+ HUSTR_19,
+
+ // Third "episode" - Shut down Factory, kill Loremaster and Entity
+ HUSTR_20,
+ HUSTR_21,
+ HUSTR_22,
+ HUSTR_23,
+ HUSTR_24,
+ HUSTR_25,
+ HUSTR_26,
+ HUSTR_27,
+ HUSTR_28,
+ HUSTR_29,
+
+ // "Secret" levels - Abandoned Base and Training Facility
+ HUSTR_30,
+ HUSTR_31,
+
+ // Demo version maps
+ HUSTR_32,
+ HUSTR_33,
+ HUSTR_34
+};
+
+//
+// HU_Init
+//
+// haleyjd 09/18/10: [STRIFE]
+// * Modified to load yfont along with hu_font.
+//
+void HU_Init(void)
+{
+ int i;
+ int j;
+ char buffer[9];
+
+ // load the heads-up font
+ j = HU_FONTSTART;
+ for (i=0;i<HU_FONTSIZE;i++)
+ {
+ DEH_snprintf(buffer, 9, "STCFN%.3d", j++);
+ hu_font[i] = (patch_t *) W_CacheLumpName(buffer, PU_STATIC);
+
+ // haleyjd 09/18/10: load yfont as well; and yes, this is exactly
+ // how Rogue did it :P
+ buffer[2] = 'B';
+ yfont[i] = (patch_t *) W_CacheLumpName(buffer, PU_STATIC);
+ }
+}
+
+//
+// HU_Stop
+//
+// [STRIFE] Verified unmodified.
+//
+void HU_Stop(void)
+{
+ headsupactive = false;
+}
+
+//
+// HU_Start
+//
+// haleyjd 09/18/10: [STRIFE] Added a hack for nickname at the end.
+//
+void HU_Start(void)
+{
+ int i;
+ char* s;
+
+ // haleyjd 20120211: [STRIFE] not called here.
+ //if (headsupactive)
+ // HU_Stop();
+
+ // haleyjd 20120211: [STRIFE] moved up
+ // create the map title widget
+ HUlib_initTextLine(&w_title,
+ HU_TITLEX, HU_TITLEY,
+ hu_font,
+ HU_FONTSTART);
+
+ // haleyjd 08/31/10: [STRIFE] Get proper map name.
+ s = HU_TITLE;
+
+ // [STRIFE] Removed Chex Quest stuff.
+
+ // dehacked substitution to get modified level name
+ s = DEH_String(s);
+
+ while (*s)
+ HUlib_addCharToTextLine(&w_title, *(s++));
+
+ // haleyjd 20120211: [STRIFE] check for headsupactive
+ if(!headsupactive)
+ {
+ 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 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;
+
+ // haleyjd 09/18/10: [STRIFE] nickname weirdness.
+
+ // STRIFE-TODO: This shit crashes the game.
+ /*
+ if(nickname != pnameprefixes[consoleplayer])
+ {
+ if(*nickname)
+ {
+ DEH_printf("have one\n");
+ nickname = pnameprefixes[consoleplayer];
+ }
+ }
+ */
+ }
+}
+
+//
+// HU_Drawer
+//
+// [STRIFE] Verified unmodified.
+//
+void HU_Drawer(void)
+{
+ HUlib_drawSText(&w_message);
+ HUlib_drawIText(&w_chat);
+ if (automapactive)
+ HUlib_drawTextLine(&w_title, false);
+}
+
+//
+// HU_Erase
+//
+// [STRIFE] Verified unmodified.
+//
+void HU_Erase(void)
+{
+ HUlib_eraseSText(&w_message);
+ HUlib_eraseIText(&w_chat);
+ HUlib_eraseTextLine(&w_title);
+}
+
+//
+// HU_addMessage
+//
+// haleyjd 09/18/10: [STRIFE] New function
+// See if you can tell whether or not I had trouble with this :P
+// Looks to be extremely buggy, hackish, and error-prone.
+//
+// <Markov> This is definitely not the best that Rogue had to offer. Markov.
+//
+// Fastcall Registers: edx ebx
+// Temp Registers: esi edi
+void HU_addMessage(char *prefix, char *message)
+{
+ char c; // eax
+ int width = 0; // edx
+ char *rover1; // ebx (in first loop)
+ char *rover2; // ecx (in second loop)
+ char *bufptr; // ebx (in second loop)
+ char buffer[HU_MAXLINELENGTH+2]; // esp+52h
+
+ // Loop 1: Total up width of prefix.
+ rover1 = prefix;
+ if(rover1)
+ {
+ while((c = *rover1))
+ {
+ c = toupper(c) - HU_FONTSTART;
+ ++rover1;
+
+ if(c < 0 || c >= HU_FONTSIZE)
+ width += 4;
+ else
+ width += SHORT(hu_font[(int) c]->width);
+ }
+ }
+
+ // Loop 2: Copy as much of message into buffer as will fit on screen
+ bufptr = buffer;
+ rover2 = message;
+ while((c = *rover2))
+ {
+ if((c == ' ' || c == '-') && width > 285)
+ break;
+
+ *bufptr = c;
+ ++bufptr; // BUG: No check for overflow.
+ ++rover2;
+ c = toupper(c);
+
+ if(c == ' ' || c < '!' || c >= '_')
+ width += 4;
+ else
+ {
+ c -= HU_FONTSTART;
+ width += SHORT(hu_font[(int) c]->width);
+ }
+ }
+
+ // Too big to fit?
+ // BUG: doesn't consider by how much it's over.
+ if(width > 320)
+ {
+ // backup a char... hell if I know why.
+ --bufptr;
+ --rover2;
+ }
+
+ // rover2 is not at the end?
+ if((c = *rover2))
+ {
+ // if not ON a space...
+ if(c != ' ')
+ {
+ // back up both pointers til one is found.
+ // BUG: no check against LHS of buffer. Hurr!
+ while(*bufptr != ' ')
+ {
+ --bufptr;
+ --rover2;
+ }
+ }
+ }
+
+ *bufptr = '\0';
+
+ // Add two message lines.
+ HUlib_addMessageToSText(&w_message, prefix, buffer);
+ HUlib_addMessageToSText(&w_message, NULL, rover2);
+}
+
+//
+// HU_Ticker
+//
+// haleyjd 09/18/10: [STRIFE] Changes to split up message into two lines,
+// and support for player names (STRIFE-TODO: unfinished!)
+//
+void HU_Ticker(void)
+{
+ int i, rc;
+ char c;
+ //char *prefix; STRIFE-TODO
+
+ // tick down message counter if message is up
+ if (message_counter && !--message_counter)
+ {
+ message_on = false;
+ message_nottobefuckedwith = false;
+ }
+
+ // haleyjd 20110219: [STRIFE] this condition was removed
+ //if (showMessages || message_dontfuckwithme)
+ //{
+ // display message if necessary
+ if ((plr->message && !message_nottobefuckedwith)
+ || (plr->message && message_dontfuckwithme))
+ {
+ //HUlib_addMessageToSText(&w_message, 0, plr->message);
+ HU_addMessage(NULL, plr->message); // haleyjd [STRIFE]
+ 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
+ {
+ 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))
+ {
+ // STRIFE-TODO: there is interaction with the player
+ // name prefixes array here...
+ HU_addMessage(DEH_String(player_names[i]),
+ w_inputbuffer[i].l.l);
+
+ message_nottobefuckedwith = true;
+ message_on = true;
+ message_counter = HU_MSGTIMEOUT;
+ S_StartSound(0, sfx_radio);
+ }
+ HUlib_resetIText(&w_inputbuffer[i]);
+ }
+ }
+ players[i].cmd.chatchar = 0;
+ }
+ }
+ }
+}
+
+#define QUEUESIZE 128
+
+static char chatchars[QUEUESIZE];
+static int head = 0;
+static int tail = 0;
+
+//
+// HU_queueChatChar
+//
+// haleyjd 09/18/10: [STRIFE]
+// * No message is given if a chat queue overflow occurs.
+//
+void HU_queueChatChar(char c)
+{
+ chatchars[head] = c;
+ if (((head + 1) & (QUEUESIZE-1)) != tail)
+ {
+ head = (head + 1) & (QUEUESIZE-1);
+ }
+}
+
+//
+// HU_dequeueChatChar
+//
+// [STRIFE] Verified unmodified.
+//
+char HU_dequeueChatChar(void)
+{
+ char c;
+
+ if (head != tail)
+ {
+ c = chatchars[tail];
+ tail = (tail + 1) & (QUEUESIZE-1);
+ }
+ else
+ {
+ c = 0;
+ }
+
+ return c;
+}
+
+//
+// HU_Responder
+//
+// haleyjd 09/18/10: [STRIFE]
+// * Mostly unmodified, except:
+// - The default value of key_message_refresh is changed. That is handled
+// elsewhere in Choco, however.
+// - There is support for setting the player name through the chat
+// mechanism. This is a STRIFE-TODO.
+//
+boolean HU_Responder(event_t *ev)
+{
+ static char lastmessage[HU_MAXLINELENGTH+1];
+ char* macromessage;
+ boolean eatkey = false;
+ static boolean altdown = false;
+ unsigned char c;
+ int i;
+ int numplayers;
+
+ static int num_nobrainers = 0;
+
+ numplayers = 0;
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ numplayers += playeringame[i];
+
+ if (ev->data1 == KEY_RSHIFT)
+ {
+ 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 == key_message_refresh)
+ {
+ message_on = true;
+ message_counter = HU_MSGTIMEOUT;
+ eatkey = true;
+ }
+ else if (netgame && ev->data2 == key_multi_msg)
+ {
+ eatkey = chat_on = true;
+ HUlib_resetIText(&w_chat);
+ HU_queueChatChar(HU_BROADCAST);
+ }
+ else if (netgame && numplayers > 2)
+ {
+ // STRIFE-TODO: support for setting player names
+
+ for (i=0; i<MAXPLAYERS ; i++)
+ {
+ if (ev->data2 == key_multi_msgplayer[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 = DEH_String(HUSTR_TALKTOSELF1);
+ else if (num_nobrainers < 6)
+ plr->message = DEH_String(HUSTR_TALKTOSELF2);
+ else if (num_nobrainers < 9)
+ plr->message = DEH_String(HUSTR_TALKTOSELF3);
+ else if (num_nobrainers < 32)
+ plr->message = DEH_String(HUSTR_TALKTOSELF4);
+ else
+ plr->message = DEH_String(HUSTR_TALKTOSELF5);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ c = ev->data2;
+ // send a macro
+ if (altdown)
+ {
+ c = c - '0';
+ if (c > 9)
+ return false;
+ // fprintf(stderr, "got here\n");
+ 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;
+ strcpy(lastmessage, chat_macros[c]);
+ plr->message = lastmessage;
+ eatkey = true;
+ }
+ else
+ {
+ eatkey = HUlib_keyInIText(&w_chat, c);
+ if (eatkey)
+ {
+ // static unsigned char buf[20]; // DEBUG
+ HU_queueChatChar(c);
+
+ // sprintf(buf, "KEY: %d => %d", ev->data1, c);
+ // plr->message = buf;
+ }
+ if (c == KEY_ENTER)
+ {
+ chat_on = false;
+ if (w_chat.l.len)
+ {
+ strcpy(lastmessage, w_chat.l.l);
+ plr->message = lastmessage;
+ }
+ }
+ else if (c == KEY_ESCAPE)
+ chat_on = false;
+ }
+ }
+
+ return eatkey;
+}
diff --git a/src/strife/hu_stuff.h b/src/strife/hu_stuff.h
new file mode 100644
index 00000000..e245a42c
--- /dev/null
+++ b/src/strife/hu_stuff.h
@@ -0,0 +1,75 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION: Head up display
+//
+//-----------------------------------------------------------------------------
+
+#ifndef __HU_STUFF_H__
+#define __HU_STUFF_H__
+
+#include "d_event.h"
+#include "v_patch.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 9 // haleyjd [STRIFE] Changed 5 -> 9
+
+#define HU_MSGX 0
+#define HU_MSGY (SHORT(hu_font[0]->height) + 1) // [STRIFE]: DOOM bug fix
+#define HU_MSGWIDTH 64 // in characters
+#define HU_MSGHEIGHT 2 // in lines
+
+#define HU_MSGTIMEOUT (8*TICRATE) // haleyjd [STRIFE] Doubled message timeout
+
+
+//
+// HEADS UP TEXT
+//
+
+void HU_Init(void);
+void HU_Start(void);
+
+boolean HU_Responder(event_t* ev);
+
+void HU_Ticker(void);
+void HU_Drawer(void);
+char HU_dequeueChatChar(void);
+void HU_Erase(void);
+
+extern char *chat_macros[10];
+extern char pnameprefixes[8][16]; // villsa [STRIFE]
+
+// haleyjd [STRIFE] externalized:
+extern char *mapnames[];
+
+// [STRIFE]
+extern patch_t* yfont[HU_FONTSIZE]; // haleyjd 09/18/10: [STRIFE]
+
+#endif
+
diff --git a/src/strife/info.c b/src/strife/info.c
new file mode 100644
index 00000000..0d829f79
--- /dev/null
+++ b/src/strife/info.c
@@ -0,0 +1,11049 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Thing frame/state LUT,
+// generated by multigen utilitiy.
+// This one is the original DOOM version, preserved.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+
+// Data.
+#include "sounds.h"
+#include "m_fixed.h"
+
+#include "info.h"
+
+#include "p_mobj.h"
+
+// villsa [STRIFE]
+char *sprnames[NUMSPRITES+1] =
+{
+ "PLAY", "PNCH", "WAVE", "RBPY", "TRGT", "XBOW", "MMIS", "RIFG",
+ "RIFF", "FLMT", "FLMF", "BLST", "BLSF", "GREN", "GREF", "SIGH",
+ "SIGF", "POW1", "POW2", "POW3", "ZAP1", "SPRY", "BLOD", "PUFY",
+ "SHT1", "SHT2", "GRIN", "GRAP", "UBAM", "BNG2", "BNG4", "BNG3",
+ "FLBE", "XPRK", "OCLW", "CCLW", "TEND", "MICR", "MISS", "AROW",
+ "ARWP", "TORP", "THIT", "TWAV", "MISL", "TFOG", "IFOG", "SHRD",
+ "RGIB", "MRYS", "MRNO", "MRST", "MRLK", "MRBD", "MRPN", "MRGT",
+ "BURN", "DISR", "PEAS", "GIBS", "AGRD", "ARMR", "SACR", "TNK1",
+ "TNK2", "TNK3", "TNK4", "TNK5", "TNK6", "NEAL", "BEGR", "HMN1",
+ "LEDR", "LEAD", "ROB1", "PGRD", "ROB2", "MLDR", "ORCL", "PRST",
+ "PDED", "ALN1", "AL1P", "NODE", "MTHD", "MNAM", "MNAL", "MDTH",
+ "NEST", "PODD", "ZAP6", "ZOT3", "ZAP7", "ZOT1", "ZAP5", "ZOT2",
+ "SEWR", "SPID", "ROB3", "RBB3", "PRGR", "BASE", "FRBL", "KLAX",
+ "TURT", "BALL", "PSTN", "SECR", "TARG", "RING", "EARS", "COMM",
+ "BOOM", "RATT", "HOGN", "DEAD", "SBAN", "BOTR", "HATR", "TOPR",
+ "COUP", "BUBB", "BUBF", "BUBC", "ASPR", "SPDL", "TOKN", "OTOK",
+ "HELT", "GUNT", "FULL", "MEAT", "JUNK", "FFOT", "DIE1", "BEAC",
+ "ARM1", "ARM2", "BARW", "BART", "LAMP", "LANT", "BARL", "BOWL",
+ "BRAZ", "TRCH", "LTRH", "LMPC", "LOGS", "TRHO", "WATR", "MUGG",
+ "FUSL", "CRD1", "CRD2", "TPAS", "KY1G", "KY2S", "KY3B", "HAND",
+ "CRYS", "PRIS", "PWR1", "PWR2", "PWR3", "ORAC", "GYID", "FUBR",
+ "WARE", "RCRY", "BCRY", "CHAP", "TUNL", "BLTK", "SECK", "MINE",
+ "REBL", "PROC", "ANKH", "GOID", "STMP", "MDKT", "COIN", "CRED",
+ "SACK", "CHST", "SHD1", "MASK", "UNIF", "OFIC", "PMAP", "PMUP",
+ "BLIT", "BBOX", "MSSL", "ROKT", "BRY1", "CPAC", "PQRL", "XQRL",
+ "GRN1", "GRN2", "BKPK", "RELC", "RIFL", "FLAM", "BFLM", "MMSL",
+ "TRPD", "GRND", "CBOW", "SIGL", "LITE", "CNDL", "CLBR", "LITS",
+ "LITB", "LITG", "ROK1", "ROK2", "ROK3", "ROK4", "LOGG", "RUB1",
+ "RUB2", "RUB3", "RUB4", "RUB5", "RUB6", "RUB7", "RUB8", "CHAN",
+ "STAT", "DSTA", "CRAB", "CAGE", "TREE", "TRE1", "BUSH", "SHRB",
+ "STAK", "BAR1", "VASE", "STOL", "POT1", "TUB1", "ANVL", "TLMP",
+ "TRAY", "APOW", "AFED", "DRIP", "CDRP", "SPLH", "WTFT", "HERT",
+ "TELP", "MONI", "STEL", "STLA", "STLE", "HUGE", "STLG", NULL
+};
+
+
+// Doesn't work with g++, needs actionf_p1
+// villsa [STRIFE]
+void A_Look();
+void A_RandomWalk();
+void A_FriendLook();
+void A_Listen();
+void A_Chase();
+void A_FaceTarget();
+void A_PeasantPunch();
+void A_ReaverAttack();
+void A_BulletAttack();
+void A_CheckTargetVisible();
+void A_SentinelAttack();
+void A_StalkerThink();
+void A_StalkerSetLook();
+void A_StalkerDrop();
+void A_StalkerScratch();
+void A_FloatWeave();
+void A_RobotMelee();
+void A_TemplarMauler();
+void A_CrusaderAttack();
+void A_CrusaderLeft();
+void A_CrusaderRight();
+void A_CheckTargetVisible2();
+void A_InqFlyCheck();
+void A_InqGrenade();
+void A_InqTakeOff();
+void A_InqFly();
+void A_FireSigilWeapon();
+void A_ProgrammerAttack();
+void A_Sigil_A_Action();
+void A_SpectreEAttack();
+void A_SpectreCAttack();
+void A_AlertSpectreC();
+void A_Sigil_E_Action();
+void A_SigilTrail();
+void A_SpectreDAttack();
+void A_FireSigilEOffshoot();
+void A_ShadowOff();
+void A_ModifyVisibility();
+void A_ShadowOn();
+void A_SetTLOptions();
+void A_BossMeleeAtk();
+void A_BishopAttack();
+void A_FireHookShot();
+void A_FireChainShot();
+void A_MissileSmoke();
+void A_SpawnSparkPuff();
+void A_Tracer();
+void A_ProgrammerMelee();
+void A_Scream();
+void A_XScream();
+void A_Pain();
+void A_PeasantCrash();
+void A_Fall();
+void A_HideZombie();
+void A_MerchantPain();
+void A_ProgrammerDie();
+void A_InqTossArm();
+void A_SpawnSpectreB();
+void A_SpawnSpectreD();
+void A_SpawnSpectreE();
+void A_SpawnEntity();
+void A_EntityDeath();
+void A_SpawnZombie();
+void A_ZombieInSpecialSector();
+void A_CrystalExplode();
+void A_QuestMsg();
+void A_ExtraLightOff();
+void A_CrystalRadiusAtk();
+void A_DeathExplode5();
+void A_DeathExplode1();
+void A_DeathExplode2();
+void A_DeathExplode3();
+void A_RaiseAlarm();
+void A_MissileTick();
+void A_SpawnGrenadeFire();
+void A_NodeChunk();
+void A_HeadChunk();
+void A_BurnSpread();
+void A_AcolyteSpecial();
+void A_BossDeath();
+void A_InqChase();
+void A_StalkerChase();
+void A_PlayerScream();
+void A_TeleportBeacon();
+void A_BodyParts();
+void A_ClaxonBlare();
+void A_ActiveSound();
+void A_ClearSoundTarget();
+void A_DropBurnFlesh();
+void A_FlameDeath();
+void A_ClearForceField();
+void A_WeaponReady();
+void A_ReFire();
+void A_CheckReload();
+void A_Lower();
+void A_Raise();
+void A_GunFlash();
+void A_Punch();
+void A_FireFlameThrower();
+void A_FireMissile();
+void A_FireMauler2();
+void A_FireGrenade();
+void A_FireElectricBolt();
+void A_FirePoisonBolt();
+void A_FireRifle();
+void A_FireMauler1();
+void A_SigilSound();
+void A_FireSigil();
+void A_GunFlashThinker();
+void A_Light0();
+void A_Light1();
+void A_Light2();
+void A_SigilShock();
+void A_TorpedoExplode();
+void A_MaulerSound();
+
+// villsa [STRIFE]
+state_t states[NUMSTATES] =
+{
+
+/*S_NULL*/ { SPR_PLAY, 0, -1, { NULL }, S_NULL }, //00
+/*S_PNCH_00*/ { SPR_PNCH, 0, 0, { A_Light0 }, S_NULL }, //01
+/*S_WAVE_00*/ { SPR_WAVE, 32768, 3, { NULL }, S_WAVE_01 }, //02
+/*S_WAVE_01*/ { SPR_WAVE, 32769, 3, { NULL }, S_WAVE_02 }, //03
+/*S_WAVE_02*/ { SPR_WAVE, 32770, 3, { NULL }, S_WAVE_03 }, //04
+/*S_WAVE_03*/ { SPR_WAVE, 32771, 3, { NULL }, S_WAVE_00 }, //05
+/*S_RBPY_00*/ { SPR_RBPY, 32768, 3, { NULL }, S_RBPY_01 }, //06
+/*S_RBPY_01*/ { SPR_RBPY, 32769, 3, { NULL }, S_RBPY_02 }, //07
+/*S_RBPY_02*/ { SPR_RBPY, 32770, 3, { NULL }, S_RBPY_03 }, //08
+/*S_RBPY_03*/ { SPR_RBPY, 32771, 3, { NULL }, S_RBPY_00 }, //09
+/*S_TRGT_00*/ { SPR_TRGT, 0, -1, { NULL }, S_NULL }, //10
+/*S_TRGT_01*/ { SPR_TRGT, 1, -1, { NULL }, S_NULL }, //11
+/*S_TRGT_02*/ { SPR_TRGT, 2, -1, { NULL }, S_NULL }, //12
+/*S_PNCH_01*/ { SPR_PNCH, 0, 1, { A_WeaponReady }, S_PNCH_01 }, //13
+/*S_PNCH_02*/ { SPR_PNCH, 0, 1, { A_Lower }, S_PNCH_02 }, //14
+/*S_PNCH_03*/ { SPR_PNCH, 0, 1, { A_Raise }, S_PNCH_03 }, //15
+/*S_PNCH_04*/ { SPR_PNCH, 1, 4, { NULL }, S_PNCH_05 }, //16
+/*S_PNCH_05*/ { SPR_PNCH, 2, 4, { A_Punch }, S_PNCH_06 }, //17
+/*S_PNCH_06*/ { SPR_PNCH, 3, 5, { NULL }, S_PNCH_07 }, //18
+/*S_PNCH_07*/ { SPR_PNCH, 2, 4, { NULL }, S_PNCH_08 }, //19
+/*S_PNCH_08*/ { SPR_PNCH, 1, 5, { A_ReFire }, S_PNCH_01 }, //20
+/*S_XBOW_00*/ { SPR_XBOW, 0, 1, { A_WeaponReady }, S_XBOW_00 }, //21
+/*S_XBOW_01*/ { SPR_XBOW, 0, 1, { A_Lower }, S_XBOW_01 }, //22
+/*S_XBOW_02*/ { SPR_XBOW, 0, 1, { A_Raise }, S_XBOW_02 }, //23
+/*S_XBOW_03*/ { SPR_XBOW, 0, 3, { A_GunFlashThinker }, S_XBOW_04 }, //24
+/*S_XBOW_04*/ { SPR_XBOW, 1, 6, { A_FireElectricBolt }, S_XBOW_05 }, //25
+/*S_XBOW_05*/ { SPR_XBOW, 2, 4, { NULL }, S_XBOW_06 }, //26
+/*S_XBOW_06*/ { SPR_XBOW, 3, 6, { NULL }, S_XBOW_07 }, //27
+/*S_XBOW_07*/ { SPR_XBOW, 4, 3, { NULL }, S_XBOW_08 }, //28
+/*S_XBOW_08*/ { SPR_XBOW, 5, 5, { NULL }, S_XBOW_09 }, //29
+/*S_XBOW_09*/ { SPR_XBOW, 6, 5, { A_CheckReload }, S_XBOW_00 }, //30
+/*S_XBOW_10*/ { SPR_XBOW, 10, 5, { NULL }, S_XBOW_11 }, //31
+/*S_XBOW_11*/ { SPR_XBOW, 11, 5, { NULL }, S_XBOW_12 }, //32
+/*S_XBOW_12*/ { SPR_XBOW, 12, 5, { NULL }, S_XBOW_10 }, //33
+/*S_XBOW_13*/ { SPR_XBOW, 7, 1, { A_WeaponReady }, S_XBOW_13 }, //34
+/*S_XBOW_14*/ { SPR_XBOW, 7, 1, { A_Lower }, S_XBOW_14 }, //35
+/*S_XBOW_15*/ { SPR_XBOW, 7, 1, { A_Raise }, S_XBOW_15 }, //36
+/*S_XBOW_16*/ { SPR_XBOW, 7, 3, { NULL }, S_XBOW_17 }, //37
+/*S_XBOW_17*/ { SPR_XBOW, 1, 6, { A_FirePoisonBolt }, S_XBOW_18 }, //38
+/*S_XBOW_18*/ { SPR_XBOW, 2, 4, { NULL }, S_XBOW_19 }, //39
+/*S_XBOW_19*/ { SPR_XBOW, 3, 6, { NULL }, S_XBOW_20 }, //40
+/*S_XBOW_20*/ { SPR_XBOW, 4, 3, { NULL }, S_XBOW_21 }, //41
+/*S_XBOW_21*/ { SPR_XBOW, 8, 5, { NULL }, S_XBOW_22 }, //42
+/*S_XBOW_22*/ { SPR_XBOW, 9, 5, { A_CheckReload }, S_XBOW_13 }, //43
+/*S_MMIS_00*/ { SPR_MMIS, 0, 1, { A_WeaponReady }, S_MMIS_00 }, //44
+/*S_MMIS_01*/ { SPR_MMIS, 0, 1, { A_Lower }, S_MMIS_01 }, //45
+/*S_MMIS_02*/ { SPR_MMIS, 0, 1, { A_Raise }, S_MMIS_02 }, //46
+/*S_MMIS_03*/ { SPR_MMIS, 0, 4, { A_FireMissile }, S_MMIS_04 }, //47
+/*S_MMIS_04*/ { SPR_MMIS, 1, 4, { A_Light1 }, S_MMIS_05 }, //48
+/*S_MMIS_05*/ { SPR_MMIS, 32770, 5, { NULL }, S_MMIS_06 }, //49
+/*S_MMIS_06*/ { SPR_MMIS, 32771, 2, { A_Light2 }, S_MMIS_07 }, //50
+/*S_MMIS_07*/ { SPR_MMIS, 32772, 2, { NULL }, S_MMIS_08 }, //51
+/*S_MMIS_08*/ { SPR_MMIS, 32773, 2, { A_Light0 }, S_MMIS_09 }, //52
+/*S_MMIS_09*/ { SPR_MMIS, 5, 0, { A_ReFire }, S_MMIS_00 }, //53
+/*S_RIFG_00*/ { SPR_RIFG, 0, 1, { A_WeaponReady }, S_RIFG_00 }, //54
+/*S_RIFG_01*/ { SPR_RIFG, 1, 1, { A_Lower }, S_RIFG_01 }, //55
+/*S_RIFG_02*/ { SPR_RIFG, 0, 1, { A_Raise }, S_RIFG_02 }, //56
+/*S_RIFF_00*/ { SPR_RIFF, 0, 3, { A_FireRifle }, S_RIFF_01 }, //57
+/*S_RIFF_01*/ { SPR_RIFF, 1, 3, { A_FireRifle }, S_RIFG_03 }, //58
+/*S_RIFG_03*/ { SPR_RIFG, 3, 3, { A_FireRifle }, S_RIFG_04 }, //59
+/*S_RIFG_04*/ { SPR_RIFG, 2, 0, { A_ReFire }, S_RIFG_05 }, //60
+/*S_RIFG_05*/ { SPR_RIFG, 1, 2, { NULL }, S_RIFG_00 }, //61
+/*S_FLMT_00*/ { SPR_FLMT, 0, 3, { A_WeaponReady }, S_FLMT_01 }, //62
+/*S_FLMT_01*/ { SPR_FLMT, 1, 3, { A_WeaponReady }, S_FLMT_00 }, //63
+/*S_FLMT_02*/ { SPR_FLMT, 0, 1, { A_Lower }, S_FLMT_02 }, //64
+/*S_FLMT_03*/ { SPR_FLMT, 0, 1, { A_Raise }, S_FLMT_03 }, //65
+/*S_FLMF_00*/ { SPR_FLMF, 0, 2, { A_FireFlameThrower }, S_FLMF_01 }, //66
+/*S_FLMF_01*/ { SPR_FLMF, 1, 3, { A_ReFire }, S_FLMT_00 }, //67
+/*S_BLST_00*/ { SPR_BLST, 5, 6, { A_WeaponReady }, S_BLST_01 }, //68
+/*S_BLST_01*/ { SPR_BLST, 6, 6, { A_WeaponReady }, S_BLST_02 }, //69
+/*S_BLST_02*/ { SPR_BLST, 7, 6, { A_WeaponReady }, S_BLST_03 }, //70
+/*S_BLST_03*/ { SPR_BLST, 0, 6, { A_WeaponReady }, S_BLST_00 }, //71
+/*S_BLST_04*/ { SPR_BLST, 0, 1, { A_Lower }, S_BLST_04 }, //72
+/*S_BLST_05*/ { SPR_BLST, 0, 1, { A_Raise }, S_BLST_05 }, //73
+/*S_BLSF_00*/ { SPR_BLSF, 32768, 5, { A_FireMauler1 }, S_BLST_06 }, //74
+/*S_BLST_06*/ { SPR_BLST, 32769, 3, { A_Light1 }, S_BLST_07 }, //75
+/*S_BLST_07*/ { SPR_BLST, 2, 2, { A_Light2 }, S_BLST_08 }, //76
+/*S_BLST_08*/ { SPR_BLST, 3, 2, { NULL }, S_BLST_09 }, //77
+/*S_BLST_09*/ { SPR_BLST, 4, 2, { NULL }, S_BLST_10 }, //78
+/*S_BLST_10*/ { SPR_BLST, 0, 7, { A_Light0 }, S_BLST_11 }, //79
+/*S_BLST_11*/ { SPR_BLST, 7, 7, { NULL }, S_BLST_12 }, //80
+/*S_BLST_12*/ { SPR_BLST, 6, 7, { A_CheckReload }, S_BLST_00 }, //81
+/*S_BLST_13*/ { SPR_BLST, 8, 7, { A_WeaponReady }, S_BLST_14 }, //82
+/*S_BLST_14*/ { SPR_BLST, 9, 7, { A_WeaponReady }, S_BLST_15 }, //83
+/*S_BLST_15*/ { SPR_BLST, 10, 7, { A_WeaponReady }, S_BLST_16 }, //84
+/*S_BLST_16*/ { SPR_BLST, 11, 7, { A_WeaponReady }, S_BLST_13 }, //85
+/*S_BLST_17*/ { SPR_BLST, 8, 1, { A_Lower }, S_BLST_17 }, //86
+/*S_BLST_18*/ { SPR_BLST, 8, 1, { A_Raise }, S_BLST_18 }, //87
+/*S_BLST_19*/ { SPR_BLST, 8, 20, { A_MaulerSound }, S_BLST_20 }, //88
+/*S_BLST_20*/ { SPR_BLST, 9, 10, { A_Light1 }, S_BLSF_01 }, //89
+/*S_BLSF_01*/ { SPR_BLSF, 32768, 10, { A_FireMauler2 }, S_BLST_21 }, //90
+/*S_BLST_21*/ { SPR_BLST, 32769, 3, { A_Light2 }, S_BLST_22 }, //91
+/*S_BLST_22*/ { SPR_BLST, 2, 2, { NULL }, S_BLST_23 }, //92
+/*S_BLST_23*/ { SPR_BLST, 3, 2, { A_Light0 }, S_BLST_24 }, //93
+/*S_BLST_24*/ { SPR_BLST, 4, 2, { A_ReFire }, S_BLST_13 }, //94
+/*S_GREN_00*/ { SPR_GREN, 0, 1, { A_WeaponReady }, S_GREN_00 }, //95
+/*S_GREN_01*/ { SPR_GREN, 0, 1, { A_Lower }, S_GREN_01 }, //96
+/*S_GREN_02*/ { SPR_GREN, 0, 1, { A_Raise }, S_GREN_02 }, //97
+/*S_GREN_03*/ { SPR_GREN, 0, 5, { A_FireGrenade }, S_GREN_04 }, //98
+/*S_GREN_04*/ { SPR_GREN, 1, 10, { NULL }, S_GREN_05 }, //99
+/*S_GREN_05*/ { SPR_GREN, 0, 5, { A_FireGrenade }, S_GREN_06 }, //100
+/*S_GREN_06*/ { SPR_GREN, 2, 10, { NULL }, S_GREN_07 }, //101
+/*S_GREN_07*/ { SPR_GREN, 0, 0, { A_ReFire }, S_GREN_00 }, //102
+/*S_GREF_00*/ { SPR_GREF, 32768, 5, { A_Light1 }, S_PNCH_00 }, //103
+/*S_GREF_01*/ { SPR_GREF, 0, 10, { A_Light0 }, S_PNCH_00 }, //104
+/*S_GREF_02*/ { SPR_GREF, 32769, 5, { A_Light2 }, S_PNCH_00 }, //105
+/*S_GREN_08*/ { SPR_GREN, 3, 1, { A_WeaponReady }, S_GREN_08 }, //106
+/*S_GREN_09*/ { SPR_GREN, 3, 1, { A_Lower }, S_GREN_09 }, //107
+/*S_GREN_10*/ { SPR_GREN, 3, 1, { A_Raise }, S_GREN_10 }, //108
+/*S_GREN_11*/ { SPR_GREN, 3, 5, { A_FireGrenade }, S_GREN_12 }, //109
+/*S_GREN_12*/ { SPR_GREN, 4, 10, { NULL }, S_GREN_13 }, //110
+/*S_GREN_13*/ { SPR_GREN, 3, 5, { A_FireGrenade }, S_GREN_14 }, //111
+/*S_GREN_14*/ { SPR_GREN, 5, 10, { NULL }, S_GREN_15 }, //112
+/*S_GREN_15*/ { SPR_GREN, 0, 0, { A_ReFire }, S_GREN_08 }, //113
+/*S_GREF_03*/ { SPR_GREF, 32770, 5, { A_Light1 }, S_PNCH_00 }, //114
+/*S_GREF_04*/ { SPR_GREF, 2, 10, { A_Light0 }, S_PNCH_00 }, //115
+/*S_GREF_05*/ { SPR_GREF, 32771, 5, { A_Light2 }, S_PNCH_00 }, //116
+/*S_SIGH_00*/ { SPR_SIGH, 32768, 1, { A_WeaponReady }, S_SIGH_00 }, //117
+/*S_SIGH_01*/ { SPR_SIGH, 32769, -1, { NULL }, S_NULL }, //118
+/*S_SIGH_02*/ { SPR_SIGH, 32770, -1, { NULL }, S_NULL }, //119
+/*S_SIGH_03*/ { SPR_SIGH, 32771, -1, { NULL }, S_NULL }, //120
+/*S_SIGH_04*/ { SPR_SIGH, 32772, -1, { NULL }, S_NULL }, //121
+/*S_SIGH_05*/ { SPR_SIGH, 32768, 1, { A_Lower }, S_SIGH_05 }, //122
+/*S_SIGH_06*/ { SPR_SIGH, 32768, 1, { A_Raise }, S_SIGH_06 }, //123
+/*S_SIGH_07*/ { SPR_SIGH, 32768, 18, { A_SigilSound }, S_SIGH_08 }, //124
+/*S_SIGH_08*/ { SPR_SIGH, 32768, 3, { A_GunFlash }, S_SIGH_09 }, //125
+/*S_SIGH_09*/ { SPR_SIGH, 0, 10, { A_FireSigil }, S_SIGH_10 }, //126
+/*S_SIGH_10*/ { SPR_SIGH, 0, 5, { A_GunFlashThinker }, S_SIGH_00 }, //127
+/*S_SIGF_00*/ { SPR_SIGF, 32768, 4, { A_Light2 }, S_SIGF_01 }, //128
+/*S_SIGF_01*/ { SPR_SIGF, 32769, 6, { A_SigilShock }, S_SIGF_02 }, //129
+/*S_SIGF_02*/ { SPR_SIGF, 32770, 4, { A_Light1 }, S_PNCH_00 }, //130
+/*S_POW1_00*/ { SPR_POW1, 0, 4, { NULL }, S_POW1_01 }, //131
+/*S_POW1_01*/ { SPR_POW1, 1, 4, { NULL }, S_POW1_02 }, //132
+/*S_POW1_02*/ { SPR_POW1, 2, 4, { NULL }, S_POW1_03 }, //133
+/*S_POW1_03*/ { SPR_POW1, 3, 4, { NULL }, S_POW1_04 }, //134
+/*S_POW1_04*/ { SPR_POW1, 4, 4, { NULL }, S_NULL }, //135
+/*S_POW1_05*/ { SPR_POW1, 5, 4, { NULL }, S_POW1_06 }, //136
+/*S_POW1_06*/ { SPR_POW1, 6, 4, { NULL }, S_POW1_07 }, //137
+/*S_POW1_07*/ { SPR_POW1, 7, 4, { NULL }, S_POW1_08 }, //138
+/*S_POW1_08*/ { SPR_POW1, 8, 4, { NULL }, S_POW1_09 }, //139
+/*S_POW1_09*/ { SPR_POW1, 9, 4, { NULL }, S_NULL }, //140
+/*S_POW2_00*/ { SPR_POW2, 0, 4, { NULL }, S_POW2_01 }, //141
+/*S_POW2_01*/ { SPR_POW2, 1, 4, { NULL }, S_POW2_02 }, //142
+/*S_POW2_02*/ { SPR_POW2, 2, 4, { NULL }, S_POW2_03 }, //143
+/*S_POW2_03*/ { SPR_POW2, 3, 4, { NULL }, S_NULL }, //144
+/*S_POW3_00*/ { SPR_POW3, 0, 3, { NULL }, S_POW3_01 }, //145
+/*S_POW3_01*/ { SPR_POW3, 1, 3, { NULL }, S_POW3_02 }, //146
+/*S_POW3_02*/ { SPR_POW3, 2, 3, { NULL }, S_POW3_03 }, //147
+/*S_POW3_03*/ { SPR_POW3, 3, 3, { NULL }, S_POW3_04 }, //148
+/*S_POW3_04*/ { SPR_POW3, 4, 3, { NULL }, S_POW3_05 }, //149
+/*S_POW3_05*/ { SPR_POW3, 5, 3, { NULL }, S_POW3_06 }, //150
+/*S_POW3_06*/ { SPR_POW3, 6, 3, { NULL }, S_POW3_07 }, //151
+/*S_POW3_07*/ { SPR_POW3, 7, 3, { NULL }, S_NULL }, //152
+/*S_ZAP1_00*/ { SPR_ZAP1, 1, 3, { A_DeathExplode3 }, S_ZAP1_02 }, //153
+/*S_ZAP1_01*/ { SPR_ZAP1, 0, 3, { A_RaiseAlarm }, S_ZAP1_02 }, //154
+/*S_ZAP1_02*/ { SPR_ZAP1, 1, 3, { NULL }, S_ZAP1_03 }, //155
+/*S_ZAP1_03*/ { SPR_ZAP1, 2, 3, { NULL }, S_ZAP1_04 }, //156
+/*S_ZAP1_04*/ { SPR_ZAP1, 3, 3, { NULL }, S_ZAP1_05 }, //157
+/*S_ZAP1_05*/ { SPR_ZAP1, 4, 3, { NULL }, S_ZAP1_06 }, //158
+/*S_ZAP1_06*/ { SPR_ZAP1, 5, 3, { NULL }, S_ZAP1_07 }, //159
+/*S_ZAP1_07*/ { SPR_ZAP1, 4, 3, { NULL }, S_ZAP1_08 }, //160
+/*S_ZAP1_08*/ { SPR_ZAP1, 3, 2, { NULL }, S_ZAP1_09 }, //161
+/*S_ZAP1_09*/ { SPR_ZAP1, 2, 2, { NULL }, S_ZAP1_10 }, //162
+/*S_ZAP1_10*/ { SPR_ZAP1, 1, 2, { NULL }, S_ZAP1_11 }, //163
+/*S_ZAP1_11*/ { SPR_ZAP1, 0, 1, { NULL }, S_NULL }, //164
+/*S_SPRY_00*/ { SPR_SPRY, 0, 3, { NULL }, S_SPRY_01 }, //165
+/*S_SPRY_01*/ { SPR_SPRY, 1, 3, { NULL }, S_SPRY_02 }, //166
+/*S_SPRY_02*/ { SPR_SPRY, 2, 3, { NULL }, S_SPRY_03 }, //167
+/*S_SPRY_03*/ { SPR_SPRY, 3, 3, { NULL }, S_SPRY_04 }, //168
+/*S_SPRY_04*/ { SPR_SPRY, 4, 3, { NULL }, S_SPRY_05 }, //169
+/*S_SPRY_05*/ { SPR_SPRY, 5, 3, { NULL }, S_SPRY_06 }, //170
+/*S_SPRY_06*/ { SPR_SPRY, 6, 2, { NULL }, S_NULL }, //171
+/*S_BLOD_00*/ { SPR_BLOD, 2, 8, { NULL }, S_BLOD_01 }, //172
+/*S_BLOD_01*/ { SPR_BLOD, 1, 8, { NULL }, S_BLOD_02 }, //173
+/*S_BLOD_02*/ { SPR_BLOD, 0, 8, { NULL }, S_NULL }, //174
+/*S_PUFY_00*/ { SPR_PUFY, 32768, 4, { NULL }, S_PUFY_01 }, //175
+/*S_PUFY_01*/ { SPR_PUFY, 1, 4, { NULL }, S_PUFY_02 }, //176
+/*S_PUFY_02*/ { SPR_PUFY, 2, 4, { NULL }, S_PUFY_03 }, //177
+/*S_PUFY_03*/ { SPR_PUFY, 3, 4, { NULL }, S_NULL }, //178
+/*S_SHT1_00*/ { SPR_SHT1, 0, 4, { NULL }, S_SHT1_01 }, //179
+/*S_SHT1_01*/ { SPR_SHT1, 1, 4, { NULL }, S_SHT1_00 }, //180
+/*S_SHT2_00*/ { SPR_SHT2, 0, 5, { NULL }, S_SHT2_01 }, //181
+/*S_SHT2_01*/ { SPR_SHT2, 1, 5, { NULL }, S_POW1_00 }, //182
+/*S_GRIN_00*/ { SPR_GRIN, 0, 3, { A_MissileTick }, S_GRIN_01 }, //183
+/*S_GRIN_01*/ { SPR_GRIN, 1, 3, { A_MissileTick }, S_GRIN_00 }, //184
+/*S_GRAP_00*/ { SPR_GRAP, 0, 3, { A_MissileTick }, S_GRAP_01 }, //185
+/*S_GRAP_01*/ { SPR_GRAP, 1, 3, { A_MissileTick }, S_GRAP_00 }, //186
+/*S_UBAM_00*/ { SPR_UBAM, 0, 3, { A_MissileTick }, S_UBAM_01 }, //187
+/*S_UBAM_01*/ { SPR_UBAM, 1, 3, { A_MissileTick }, S_UBAM_00 }, //188
+/*S_BNG2_00*/ { SPR_BNG2, 32768, 4, { A_DeathExplode5 }, S_BNG2_01 }, //189
+/*S_BNG2_01*/ { SPR_BNG2, 32769, 4, { NULL }, S_BNG2_02 }, //190
+/*S_BNG2_02*/ { SPR_BNG2, 32770, 4, { NULL }, S_BNG2_03 }, //191
+/*S_BNG2_03*/ { SPR_BNG2, 32771, 4, { NULL }, S_BNG2_04 }, //192
+/*S_BNG2_04*/ { SPR_BNG2, 32772, 4, { NULL }, S_BNG2_05 }, //193
+/*S_BNG2_05*/ { SPR_BNG2, 32773, 4, { NULL }, S_BNG2_06 }, //194
+/*S_BNG2_06*/ { SPR_BNG2, 32774, 4, { NULL }, S_BNG2_07 }, //195
+/*S_BNG2_07*/ { SPR_BNG2, 32775, 4, { NULL }, S_BNG2_08 }, //196
+/*S_BNG2_08*/ { SPR_BNG2, 32776, 4, { NULL }, S_NULL }, //197
+/*S_BNG4_00*/ { SPR_BNG4, 32768, 2, { A_DeathExplode5 }, S_BNG4_01 }, //198
+/*S_BNG4_01*/ { SPR_BNG4, 32769, 3, { NULL }, S_BNG4_02 }, //199
+/*S_BNG4_02*/ { SPR_BNG4, 32770, 3, { NULL }, S_BNG4_03 }, //200
+/*S_BNG4_03*/ { SPR_BNG4, 32771, 3, { NULL }, S_BNG4_04 }, //201
+/*S_BNG4_04*/ { SPR_BNG4, 32772, 3, { NULL }, S_BNG4_05 }, //202
+/*S_BNG4_05*/ { SPR_BNG4, 32773, 3, { NULL }, S_BNG4_06 }, //203
+/*S_BNG4_06*/ { SPR_BNG4, 32774, 3, { NULL }, S_BNG4_07 }, //204
+/*S_BNG4_07*/ { SPR_BNG4, 32775, 3, { NULL }, S_BNG4_08 }, //205
+/*S_BNG4_08*/ { SPR_BNG4, 32776, 3, { NULL }, S_BNG4_09 }, //206
+/*S_BNG4_09*/ { SPR_BNG4, 32777, 3, { NULL }, S_BNG4_10 }, //207
+/*S_BNG4_10*/ { SPR_BNG4, 32778, 3, { NULL }, S_BNG4_11 }, //208
+/*S_BNG4_11*/ { SPR_BNG4, 32779, 3, { NULL }, S_BNG4_12 }, //209
+/*S_BNG4_12*/ { SPR_BNG4, 32780, 3, { NULL }, S_BNG4_13 }, //210
+/*S_BNG4_13*/ { SPR_BNG4, 32781, 3, { NULL }, S_NULL }, //211
+/*S_BNG3_00*/ { SPR_BNG3, 32768, 3, { A_DeathExplode5 }, S_BNG3_01 }, //212
+/*S_BNG3_01*/ { SPR_BNG3, 32769, 3, { NULL }, S_BNG3_02 }, //213
+/*S_BNG3_02*/ { SPR_BNG3, 32770, 3, { NULL }, S_BNG3_03 }, //214
+/*S_BNG3_03*/ { SPR_BNG3, 32771, 3, { NULL }, S_BNG3_04 }, //215
+/*S_BNG3_04*/ { SPR_BNG3, 32772, 3, { NULL }, S_BNG3_05 }, //216
+/*S_BNG3_05*/ { SPR_BNG3, 32773, 3, { NULL }, S_BNG3_06 }, //217
+/*S_BNG3_06*/ { SPR_BNG3, 32774, 3, { NULL }, S_BNG3_07 }, //218
+/*S_BNG3_07*/ { SPR_BNG3, 32775, 3, { NULL }, S_NULL }, //219
+/*S_BNG3_08*/ { SPR_BNG3, 0, 1, { A_SpawnGrenadeFire }, S_NULL }, //220
+/*S_BNG3_09*/ { SPR_BNG3, 32769, 2, { A_DeathExplode1 }, S_BNG3_10 }, //221
+/*S_BNG3_10*/ { SPR_BNG3, 32770, 2, { A_MissileTick }, S_FLBE_00 }, //222
+/*S_FLBE_00*/ { SPR_FLBE, 32768, 2, { A_BurnSpread }, S_FLBE_01 }, //223
+/*S_FLBE_01*/ { SPR_FLBE, 32769, 2, { A_MissileTick }, S_FLBE_02 }, //224
+/*S_FLBE_02*/ { SPR_FLBE, 32770, 2, { A_DeathExplode1 }, S_FLBE_03 }, //225
+/*S_FLBE_03*/ { SPR_FLBE, 32771, 3, { A_MissileTick }, S_FLBE_04 }, //226
+/*S_FLBE_04*/ { SPR_FLBE, 32772, 3, { A_DeathExplode1 }, S_FLBE_05 }, //227
+/*S_FLBE_05*/ { SPR_FLBE, 32773, 3, { A_MissileTick }, S_FLBE_06 }, //228
+/*S_FLBE_06*/ { SPR_FLBE, 32774, 3, { A_BurnSpread }, S_FLBE_03 }, //229
+/*S_FLBE_07*/ { SPR_FLBE, 32775, 2, { NULL }, S_FLBE_08 }, //230
+/*S_FLBE_08*/ { SPR_FLBE, 32776, 2, { A_BurnSpread }, S_FLBE_09 }, //231
+/*S_FLBE_09*/ { SPR_FLBE, 32777, 2, { NULL }, S_FLBE_10 }, //232
+/*S_FLBE_10*/ { SPR_FLBE, 32778, 2, { NULL }, S_NULL }, //233
+/*S_XPRK_00*/ { SPR_XPRK, 0, 1, { A_ClearForceField }, S_NULL }, //234
+/*S_OCLW_00*/ { SPR_OCLW, 0, 2, { A_FireChainShot }, S_OCLW_00 }, //235
+/*S_CCLW_00*/ { SPR_CCLW, 0, 6, { NULL }, S_NULL }, //236
+/*S_TEND_00*/ { SPR_TEND, 0, 20, { NULL }, S_NULL }, //237
+/*S_MICR_00*/ { SPR_MICR, 32768, 6, { A_MissileSmoke }, S_MICR_00 }, //238
+/*S_MISS_00*/ { SPR_MISS, 32768, 4, { A_MissileSmoke }, S_MISS_01 }, //239
+/*S_MISS_01*/ { SPR_MISS, 32769, 3, { A_Tracer }, S_MISS_00 }, //240
+/*S_AROW_00*/ { SPR_AROW, 0, 10, { A_ActiveSound }, S_AROW_00 }, //241
+/*S_ARWP_00*/ { SPR_ARWP, 0, 10, { A_ActiveSound }, S_ARWP_00 }, //242
+/*S_AROW_01*/ { SPR_AROW, 0, 1, { NULL }, S_NULL }, //243
+/*S_TORP_00*/ { SPR_TORP, 32768, 4, { NULL }, S_TORP_01 }, //244
+/*S_TORP_01*/ { SPR_TORP, 32769, 4, { NULL }, S_TORP_02 }, //245
+/*S_TORP_02*/ { SPR_TORP, 32770, 4, { NULL }, S_TORP_03 }, //246
+/*S_TORP_03*/ { SPR_TORP, 32771, 4, { NULL }, S_TORP_00 }, //247
+/*S_THIT_00*/ { SPR_THIT, 32768, 8, { NULL }, S_THIT_01 }, //248
+/*S_THIT_01*/ { SPR_THIT, 32769, 8, { NULL }, S_THIT_02 }, //249
+/*S_THIT_02*/ { SPR_THIT, 32770, 8, { A_TorpedoExplode }, S_THIT_03 }, //250
+/*S_THIT_03*/ { SPR_THIT, 32771, 8, { NULL }, S_THIT_04 }, //251
+/*S_THIT_04*/ { SPR_THIT, 32772, 8, { NULL }, S_NULL }, //252
+/*S_TWAV_00*/ { SPR_TWAV, 32768, 9, { NULL }, S_TWAV_01 }, //253
+/*S_TWAV_01*/ { SPR_TWAV, 32769, 9, { NULL }, S_TWAV_02 }, //254
+/*S_TWAV_02*/ { SPR_TWAV, 32770, 9, { NULL }, S_NULL }, //255
+/*S_MISL_00*/ { SPR_MISL, 32768, 5, { NULL }, S_MISL_02 }, //256
+/*S_MISL_01*/ { SPR_MISL, 32768, 5, { A_DeathExplode2 }, S_MISL_02 }, //257
+/*S_MISL_02*/ { SPR_MISL, 32769, 5, { NULL }, S_MISL_03 }, //258
+/*S_MISL_03*/ { SPR_MISL, 32770, 4, { NULL }, S_MISL_04 }, //259
+/*S_MISL_04*/ { SPR_MISL, 32771, 2, { NULL }, S_MISL_05 }, //260
+/*S_MISL_05*/ { SPR_MISL, 32772, 2, { NULL }, S_MISL_06 }, //261
+/*S_MISL_06*/ { SPR_MISL, 32773, 2, { NULL }, S_MISL_07 }, //262
+/*S_MISL_07*/ { SPR_MISL, 32774, 2, { NULL }, S_NULL }, //263
+/*S_TFOG_00*/ { SPR_TFOG, 32768, 6, { NULL }, S_TFOG_01 }, //264
+/*S_TFOG_01*/ { SPR_TFOG, 32769, 6, { NULL }, S_TFOG_02 }, //265
+/*S_TFOG_02*/ { SPR_TFOG, 32770, 6, { NULL }, S_TFOG_03 }, //266
+/*S_TFOG_03*/ { SPR_TFOG, 32771, 6, { NULL }, S_TFOG_04 }, //267
+/*S_TFOG_04*/ { SPR_TFOG, 32772, 6, { NULL }, S_TFOG_05 }, //268
+/*S_TFOG_05*/ { SPR_TFOG, 32773, 6, { NULL }, S_TFOG_06 }, //269
+/*S_TFOG_06*/ { SPR_TFOG, 32772, 6, { NULL }, S_TFOG_07 }, //270
+/*S_TFOG_07*/ { SPR_TFOG, 32771, 6, { NULL }, S_TFOG_08 }, //271
+/*S_TFOG_08*/ { SPR_TFOG, 32770, 6, { NULL }, S_TFOG_09 }, //272
+/*S_TFOG_09*/ { SPR_TFOG, 32769, 6, { NULL }, S_NULL }, //273
+/*S_IFOG_00*/ { SPR_IFOG, 32768, 6, { NULL }, S_IFOG_01 }, //274
+/*S_IFOG_01*/ { SPR_IFOG, 32769, 6, { NULL }, S_IFOG_02 }, //275
+/*S_IFOG_02*/ { SPR_IFOG, 32768, 6, { NULL }, S_IFOG_03 }, //276
+/*S_IFOG_03*/ { SPR_IFOG, 32769, 6, { NULL }, S_IFOG_04 }, //277
+/*S_IFOG_04*/ { SPR_IFOG, 32770, 6, { NULL }, S_IFOG_05 }, //278
+/*S_IFOG_05*/ { SPR_IFOG, 32771, 6, { NULL }, S_IFOG_06 }, //279
+/*S_IFOG_06*/ { SPR_IFOG, 32772, 6, { NULL }, S_NULL }, //280
+/*S_SHRD_00*/ { SPR_SHRD, 0, 128, { NULL }, S_NULL }, //281
+/*S_SHRD_01*/ { SPR_SHRD, 1, 128, { NULL }, S_NULL }, //282
+/*S_SHRD_02*/ { SPR_SHRD, 2, 128, { NULL }, S_NULL }, //283
+/*S_SHRD_03*/ { SPR_SHRD, 3, 128, { NULL }, S_NULL }, //284
+/*S_SHRD_04*/ { SPR_SHRD, 4, 128, { NULL }, S_NULL }, //285
+/*S_SHRD_05*/ { SPR_SHRD, 5, 128, { NULL }, S_NULL }, //286
+/*S_PLAY_00*/ { SPR_PLAY, 0, -1, { NULL }, S_NULL }, //287
+/*S_PLAY_01*/ { SPR_PLAY, 0, 4, { NULL }, S_PLAY_02 }, //288
+/*S_PLAY_02*/ { SPR_PLAY, 1, 4, { NULL }, S_PLAY_03 }, //289
+/*S_PLAY_03*/ { SPR_PLAY, 2, 4, { NULL }, S_PLAY_04 }, //290
+/*S_PLAY_04*/ { SPR_PLAY, 3, 4, { NULL }, S_PLAY_01 }, //291
+/*S_PLAY_05*/ { SPR_PLAY, 4, 12, { NULL }, S_PLAY_00 }, //292
+/*S_PLAY_06*/ { SPR_PLAY, 5, 6, { NULL }, S_PLAY_05 }, //293
+/*S_PLAY_07*/ { SPR_PLAY, 16, 4, { A_Pain }, S_PLAY_08 }, //294
+/*S_PLAY_08*/ { SPR_PLAY, 16, 4, { NULL }, S_PLAY_00 }, //295
+/*S_PLAY_09*/ { SPR_PLAY, 6, 4, { NULL }, S_PLAY_10 }, //296
+/*S_PLAY_10*/ { SPR_PLAY, 7, 3, { A_PlayerScream }, S_PLAY_11 }, //297
+/*S_PLAY_11*/ { SPR_PLAY, 8, 3, { A_Fall }, S_PLAY_12 }, //298
+/*S_PLAY_12*/ { SPR_PLAY, 9, 4, { NULL }, S_PLAY_13 }, //299
+/*S_PLAY_13*/ { SPR_PLAY, 10, 4, { NULL }, S_PLAY_14 }, //300
+/*S_PLAY_14*/ { SPR_PLAY, 11, 4, { NULL }, S_PLAY_15 }, //301
+/*S_PLAY_15*/ { SPR_PLAY, 12, 4, { NULL }, S_PLAY_16 }, //302
+/*S_PLAY_16*/ { SPR_PLAY, 13, 4, { NULL }, S_PLAY_17 }, //303
+/*S_PLAY_17*/ { SPR_PLAY, 14, 4, { NULL }, S_PLAY_18 }, //304
+/*S_PLAY_18*/ { SPR_PLAY, 15, 700, { NULL }, S_RGIB_07 }, //305
+/*S_RGIB_00*/ { SPR_RGIB, 0, 5, { A_BodyParts }, S_RGIB_01 }, //306
+/*S_RGIB_01*/ { SPR_RGIB, 1, 5, { A_XScream }, S_RGIB_02 }, //307
+/*S_RGIB_02*/ { SPR_RGIB, 2, 5, { A_Fall }, S_RGIB_03 }, //308
+/*S_RGIB_03*/ { SPR_RGIB, 3, 5, { A_BodyParts }, S_RGIB_04 }, //309
+/*S_RGIB_04*/ { SPR_RGIB, 4, 5, { A_BodyParts }, S_RGIB_05 }, //310
+/*S_RGIB_05*/ { SPR_RGIB, 5, 5, { A_BodyParts }, S_RGIB_06 }, //311
+/*S_RGIB_06*/ { SPR_RGIB, 6, 5, { A_BodyParts }, S_RGIB_07 }, //312
+/*S_RGIB_07*/ { SPR_RGIB, 7, 1400, { NULL }, S_NULL }, //313
+/*S_MRYS_00*/ { SPR_MRYS, 0, 30, { NULL }, S_MRST_00 }, //314
+/*S_MRNO_00*/ { SPR_MRNO, 0, 6, { NULL }, S_MRNO_01 }, //315
+/*S_MRNO_01*/ { SPR_MRNO, 1, 6, { NULL }, S_MRNO_02 }, //316
+/*S_MRNO_02*/ { SPR_MRNO, 2, 10, { NULL }, S_MRNO_03 }, //317
+/*S_MRNO_03*/ { SPR_MRNO, 1, 6, { NULL }, S_MRNO_04 }, //318
+/*S_MRNO_04*/ { SPR_MRNO, 0, 6, { NULL }, S_MRST_00 }, //319
+/*S_MRST_00*/ { SPR_MRST, 0, 10, { A_FriendLook }, S_MRST_00 }, //320
+/*S_MRLK_00*/ { SPR_MRLK, 0, 30, { A_ActiveSound }, S_MRST_00 }, //321
+/*S_MRLK_01*/ { SPR_MRLK, 1, 30, { NULL }, S_MRST_00 }, //322
+/*S_MRBD_00*/ { SPR_MRBD, 0, 4, { NULL }, S_MRBD_01 }, //323
+/*S_MRBD_01*/ { SPR_MRBD, 1, 4, { NULL }, S_MRBD_02 }, //324
+/*S_MRBD_02*/ { SPR_MRBD, 2, 4, { NULL }, S_MRBD_03 }, //325
+/*S_MRBD_03*/ { SPR_MRBD, 3, 4, { NULL }, S_MRBD_04 }, //326
+/*S_MRBD_04*/ { SPR_MRBD, 4, 4, { NULL }, S_MRBD_05 }, //327
+/*S_MRBD_05*/ { SPR_MRBD, 3, 4, { NULL }, S_MRBD_06 }, //328
+/*S_MRBD_06*/ { SPR_MRBD, 2, 4, { NULL }, S_MRBD_07 }, //329
+/*S_MRBD_07*/ { SPR_MRBD, 1, 4, { NULL }, S_MRBD_08 }, //330
+/*S_MRBD_08*/ { SPR_MRBD, 0, 5, { NULL }, S_MRBD_09 }, //331
+/*S_MRBD_09*/ { SPR_MRBD, 5, 6, { NULL }, S_MRST_00 }, //332
+/*S_MRPN_00*/ { SPR_MRPN, 0, 3, { NULL }, S_MRPN_01 }, //333
+/*S_MRPN_01*/ { SPR_MRPN, 1, 3, { A_Pain }, S_MRPN_02 }, //334
+/*S_MRPN_02*/ { SPR_MRPN, 2, 3, { NULL }, S_MRPN_03 }, //335
+/*S_MRPN_03*/ { SPR_MRPN, 3, 9, { A_MerchantPain }, S_MRPN_04 }, //336
+/*S_MRPN_04*/ { SPR_MRPN, 2, 4, { NULL }, S_MRPN_05 }, //337
+/*S_MRPN_05*/ { SPR_MRPN, 1, 3, { NULL }, S_MRPN_06 }, //338
+/*S_MRPN_06*/ { SPR_MRPN, 0, 3, { A_ClearSoundTarget }, S_MRST_00 }, //339
+/*S_MRGT_00*/ { SPR_MRGT, 0, 5, { NULL }, S_MRGT_01 }, //340
+/*S_MRGT_01*/ { SPR_MRGT, 1, 5, { NULL }, S_MRGT_02 }, //341
+/*S_MRGT_02*/ { SPR_MRGT, 2, 5, { NULL }, S_MRGT_03 }, //342
+/*S_MRGT_03*/ { SPR_MRGT, 3, 5, { NULL }, S_MRGT_04 }, //343
+/*S_MRGT_04*/ { SPR_MRGT, 4, 5, { NULL }, S_MRGT_05 }, //344
+/*S_MRGT_05*/ { SPR_MRGT, 5, 5, { NULL }, S_MRGT_06 }, //345
+/*S_MRGT_06*/ { SPR_MRGT, 6, 5, { NULL }, S_MRGT_07 }, //346
+/*S_MRGT_07*/ { SPR_MRGT, 7, 5, { NULL }, S_MRGT_08 }, //347
+/*S_MRGT_08*/ { SPR_MRGT, 8, 5, { NULL }, S_MRST_00 }, //348
+/*S_BURN_00*/ { SPR_BURN, 0, 3, { A_Scream }, S_BURN_01 }, //349
+/*S_BURN_01*/ { SPR_BURN, 1, 3, { A_DropBurnFlesh }, S_BURN_02 }, //350
+/*S_BURN_02*/ { SPR_BURN, 2, 3, { A_RandomWalk }, S_BURN_03 }, //351
+/*S_BURN_03*/ { SPR_BURN, 3, 3, { A_Fall }, S_BURN_04 }, //352
+/*S_BURN_04*/ { SPR_BURN, 4, 5, { A_DropBurnFlesh }, S_BURN_05 }, //353
+/*S_BURN_05*/ { SPR_BURN, 5, 5, { A_RandomWalk }, S_BURN_06 }, //354
+/*S_BURN_06*/ { SPR_BURN, 6, 5, { A_RandomWalk }, S_BURN_07 }, //355
+/*S_BURN_07*/ { SPR_BURN, 7, 5, { A_RandomWalk }, S_BURN_08 }, //356
+/*S_BURN_08*/ { SPR_BURN, 8, 5, { A_DropBurnFlesh }, S_BURN_09 }, //357
+/*S_BURN_09*/ { SPR_BURN, 9, 5, { A_RandomWalk }, S_BURN_10 }, //358
+/*S_BURN_10*/ { SPR_BURN, 10, 5, { A_RandomWalk }, S_BURN_11 }, //359
+/*S_BURN_11*/ { SPR_BURN, 11, 5, { A_RandomWalk }, S_BURN_12 }, //360
+/*S_BURN_12*/ { SPR_BURN, 12, 3, { A_DropBurnFlesh }, S_BURN_13 }, //361
+/*S_BURN_13*/ { SPR_BURN, 13, 3, { NULL }, S_BURN_14 }, //362
+/*S_BURN_14*/ { SPR_BURN, 14, 5, { NULL }, S_BURN_15 }, //363
+/*S_BURN_15*/ { SPR_BURN, 15, 5, { NULL }, S_BURN_16 }, //364
+/*S_BURN_16*/ { SPR_BURN, 16, 5, { NULL }, S_BURN_17 }, //365
+/*S_BURN_17*/ { SPR_BURN, 15, 5, { NULL }, S_BURN_18 }, //366
+/*S_BURN_18*/ { SPR_BURN, 16, 5, { NULL }, S_BURN_19 }, //367
+/*S_BURN_19*/ { SPR_BURN, 17, 7, { NULL }, S_BURN_20 }, //368
+/*S_BURN_20*/ { SPR_BURN, 18, 7, { NULL }, S_BURN_21 }, //369
+/*S_BURN_21*/ { SPR_BURN, 19, 7, { NULL }, S_BURN_22 }, //370
+/*S_BURN_22*/ { SPR_BURN, 20, 7, { NULL }, S_BURN_23 }, //371
+/*S_BURN_23*/ { SPR_BURN, 21, 700, { A_PeasantCrash }, S_NULL }, //372
+/*S_DISR_00*/ { SPR_DISR, 0, 5, { NULL }, S_DISR_01 }, //373
+/*S_DISR_01*/ { SPR_DISR, 1, 5, { NULL }, S_DISR_02 }, //374
+/*S_DISR_02*/ { SPR_DISR, 2, 5, { NULL }, S_DISR_03 }, //375
+/*S_DISR_03*/ { SPR_DISR, 3, 5, { A_Fall }, S_DISR_04 }, //376
+/*S_DISR_04*/ { SPR_DISR, 4, 5, { NULL }, S_DISR_05 }, //377
+/*S_DISR_05*/ { SPR_DISR, 5, 5, { NULL }, S_DISR_06 }, //378
+/*S_DISR_06*/ { SPR_DISR, 6, 4, { NULL }, S_DISR_07 }, //379
+/*S_DISR_07*/ { SPR_DISR, 7, 4, { NULL }, S_DISR_08 }, //380
+/*S_DISR_08*/ { SPR_DISR, 8, 4, { NULL }, S_DISR_09 }, //381
+/*S_DISR_09*/ { SPR_DISR, 9, 4, { NULL }, S_MEAT_03 }, //382
+/*S_PEAS_00*/ { SPR_PEAS, 0, 10, { A_FriendLook }, S_PEAS_00 }, //383
+/*S_PEAS_01*/ { SPR_PEAS, 0, 5, { A_RandomWalk }, S_PEAS_02 }, //384
+/*S_PEAS_02*/ { SPR_PEAS, 0, 5, { A_RandomWalk }, S_PEAS_03 }, //385
+/*S_PEAS_03*/ { SPR_PEAS, 1, 5, { A_RandomWalk }, S_PEAS_04 }, //386
+/*S_PEAS_04*/ { SPR_PEAS, 1, 5, { A_RandomWalk }, S_PEAS_05 }, //387
+/*S_PEAS_05*/ { SPR_PEAS, 2, 5, { A_RandomWalk }, S_PEAS_06 }, //388
+/*S_PEAS_06*/ { SPR_PEAS, 2, 5, { A_RandomWalk }, S_PEAS_07 }, //389
+/*S_PEAS_07*/ { SPR_PEAS, 3, 5, { A_RandomWalk }, S_PEAS_08 }, //390
+/*S_PEAS_08*/ { SPR_PEAS, 3, 5, { A_RandomWalk }, S_PEAS_00 }, //391
+/*S_PEAS_09*/ { SPR_PEAS, 4, 10, { A_FaceTarget }, S_PEAS_10 }, //392
+/*S_PEAS_10*/ { SPR_PEAS, 5, 8, { A_PeasantPunch }, S_PEAS_11 }, //393
+/*S_PEAS_11*/ { SPR_PEAS, 4, 8, { NULL }, S_PEAS_01 }, //394
+/*S_PEAS_12*/ { SPR_PEAS, 14, 3, { NULL }, S_PEAS_13 }, //395
+/*S_PEAS_13*/ { SPR_PEAS, 14, 3, { A_Pain }, S_PEAS_09 }, //396
+/*S_PEAS_14*/ { SPR_PEAS, 6, 5, { NULL }, S_PEAS_15 }, //397
+/*S_PEAS_15*/ { SPR_PEAS, 7, 10, { A_PeasantCrash }, S_PEAS_16 }, //398
+/*S_PEAS_16*/ { SPR_PEAS, 8, 6, { NULL }, S_PEAS_15 }, //399
+/*S_PEAS_17*/ { SPR_PEAS, 6, 5, { NULL }, S_PEAS_18 }, //400
+/*S_PEAS_18*/ { SPR_PEAS, 7, 5, { A_Scream }, S_PEAS_19 }, //401
+/*S_PEAS_19*/ { SPR_PEAS, 8, 6, { NULL }, S_PEAS_20 }, //402
+/*S_PEAS_20*/ { SPR_PEAS, 9, 5, { A_Fall }, S_PEAS_21 }, //403
+/*S_PEAS_21*/ { SPR_PEAS, 10, 5, { NULL }, S_PEAS_22 }, //404
+/*S_PEAS_22*/ { SPR_PEAS, 11, 6, { NULL }, S_PEAS_23 }, //405
+/*S_PEAS_23*/ { SPR_PEAS, 12, 8, { NULL }, S_PEAS_24 }, //406
+/*S_PEAS_24*/ { SPR_PEAS, 13, 1400, { NULL }, S_GIBS_08 }, //407
+/*S_GIBS_00*/ { SPR_GIBS, 12, 5, { A_BodyParts }, S_GIBS_01 }, //408
+/*S_GIBS_01*/ { SPR_GIBS, 13, 5, { A_XScream }, S_GIBS_02 }, //409
+/*S_GIBS_02*/ { SPR_GIBS, 14, 5, { A_Fall }, S_GIBS_03 }, //410
+/*S_GIBS_03*/ { SPR_GIBS, 15, 4, { A_BodyParts }, S_GIBS_04 }, //411
+/*S_GIBS_04*/ { SPR_GIBS, 16, 4, { A_BodyParts }, S_GIBS_05 }, //412
+/*S_GIBS_05*/ { SPR_GIBS, 17, 4, { A_BodyParts }, S_GIBS_06 }, //413
+/*S_GIBS_06*/ { SPR_GIBS, 18, 4, { A_BodyParts }, S_GIBS_07 }, //414
+/*S_GIBS_07*/ { SPR_GIBS, 19, 4, { NULL }, S_GIBS_08 }, //415
+/*S_GIBS_08*/ { SPR_GIBS, 20, 5, { NULL }, S_GIBS_09 }, //416
+/*S_GIBS_09*/ { SPR_GIBS, 21, 1400, { NULL }, S_NULL }, //417
+/*S_PEAS_25*/ { SPR_PEAS, 0, 5, { A_ZombieInSpecialSector }, S_PEAS_25 }, //418
+/*S_AGRD_00*/ { SPR_AGRD, 0, 5, { A_ZombieInSpecialSector }, S_AGRD_00 }, //419
+/*S_ARMR_00*/ { SPR_ARMR, 0, -1, { NULL }, S_NULL }, //420
+/*S_ARMR_01*/ { SPR_ARMR, 0, -1, { A_HideZombie }, S_NULL }, //421
+/*S_PLAY_19*/ { SPR_PLAY, 0, 175, { A_SpawnZombie }, S_PLAY_19 }, //422
+/*S_SACR_00*/ { SPR_SACR, 0, -1, { NULL }, S_NULL }, //423
+/*S_TNK1_00*/ { SPR_TNK1, 0, 15, { NULL }, S_TNK1_01 }, //424
+/*S_TNK1_01*/ { SPR_TNK1, 1, 11, { NULL }, S_TNK1_02 }, //425
+/*S_TNK1_02*/ { SPR_TNK1, 2, 40, { NULL }, S_TNK1_00 }, //426
+/*S_TNK2_00*/ { SPR_TNK2, 0, 15, { NULL }, S_TNK2_01 }, //427
+/*S_TNK2_01*/ { SPR_TNK2, 1, 11, { NULL }, S_TNK2_02 }, //428
+/*S_TNK2_02*/ { SPR_TNK2, 2, 40, { NULL }, S_TNK2_00 }, //429
+/*S_TNK3_00*/ { SPR_TNK3, 0, 15, { NULL }, S_TNK3_01 }, //430
+/*S_TNK3_01*/ { SPR_TNK3, 1, 11, { NULL }, S_TNK3_02 }, //431
+/*S_TNK3_02*/ { SPR_TNK3, 2, 40, { NULL }, S_TNK3_00 }, //432
+/*S_TNK4_00*/ { SPR_TNK4, 0, 15, { NULL }, S_TNK4_01 }, //433
+/*S_TNK4_01*/ { SPR_TNK4, 1, 11, { NULL }, S_TNK4_02 }, //434
+/*S_TNK4_02*/ { SPR_TNK4, 2, 40, { NULL }, S_TNK4_00 }, //435
+/*S_TNK5_00*/ { SPR_TNK5, 0, 15, { NULL }, S_TNK5_01 }, //436
+/*S_TNK5_01*/ { SPR_TNK5, 1, 11, { NULL }, S_TNK5_02 }, //437
+/*S_TNK5_02*/ { SPR_TNK5, 2, 40, { NULL }, S_TNK5_00 }, //438
+/*S_TNK6_00*/ { SPR_TNK6, 0, 15, { NULL }, S_TNK6_01 }, //439
+/*S_TNK6_01*/ { SPR_TNK6, 1, 11, { NULL }, S_TNK6_02 }, //440
+/*S_TNK6_02*/ { SPR_TNK6, 2, 40, { NULL }, S_TNK6_00 }, //441
+/*S_NEAL_00*/ { SPR_NEAL, 0, 15, { A_ActiveSound }, S_NEAL_01 }, //442
+/*S_NEAL_01*/ { SPR_NEAL, 1, 40, { A_ActiveSound }, S_NEAL_00 }, //443
+/*S_NEAL_02*/ { SPR_NEAL, 2, 5, { A_ShadowOn }, S_NEAL_03 }, //444
+/*S_NEAL_03*/ { SPR_NEAL, 1, 4, { A_Pain }, S_NEAL_04 }, //445
+/*S_NEAL_04*/ { SPR_NEAL, 2, 5, { A_ShadowOff }, S_NEAL_00 }, //446
+/*S_NEAL_05*/ { SPR_NEAL, 1, 6, { NULL }, S_NEAL_06 }, //447
+/*S_NEAL_06*/ { SPR_NEAL, 2, 13, { A_PeasantCrash }, S_NEAL_05 }, //448
+/*S_NEAL_07*/ { SPR_NEAL, 3, 5, { NULL }, S_NEAL_08 }, //449
+/*S_NEAL_08*/ { SPR_NEAL, 4, 5, { A_Scream }, S_NEAL_09 }, //450
+/*S_NEAL_09*/ { SPR_NEAL, 5, 6, { NULL }, S_NEAL_10 }, //451
+/*S_NEAL_10*/ { SPR_NEAL, 6, 5, { A_Fall }, S_NEAL_11 }, //452
+/*S_NEAL_11*/ { SPR_NEAL, 7, 5, { NULL }, S_NEAL_12 }, //453
+/*S_NEAL_12*/ { SPR_NEAL, 8, 6, { NULL }, S_NEAL_13 }, //454
+/*S_NEAL_13*/ { SPR_NEAL, 9, -1, { NULL }, S_NULL }, //455
+/*S_BEGR_00*/ { SPR_BEGR, 0, 10, { A_Look }, S_BEGR_00 }, //456
+/*S_BEGR_01*/ { SPR_BEGR, 0, 4, { A_RandomWalk }, S_BEGR_02 }, //457
+/*S_BEGR_02*/ { SPR_BEGR, 0, 4, { A_RandomWalk }, S_BEGR_03 }, //458
+/*S_BEGR_03*/ { SPR_BEGR, 1, 4, { A_RandomWalk }, S_BEGR_04 }, //459
+/*S_BEGR_04*/ { SPR_BEGR, 1, 4, { A_RandomWalk }, S_BEGR_05 }, //460
+/*S_BEGR_05*/ { SPR_BEGR, 2, 4, { A_RandomWalk }, S_BEGR_06 }, //461
+/*S_BEGR_06*/ { SPR_BEGR, 2, 4, { A_RandomWalk }, S_BEGR_01 }, //462
+/*S_BEGR_07*/ { SPR_BEGR, 3, 8, { NULL }, S_BEGR_08 }, //463
+/*S_BEGR_08*/ { SPR_BEGR, 4, 8, { A_PeasantPunch }, S_BEGR_09 }, //464
+/*S_BEGR_09*/ { SPR_BEGR, 4, 1, { A_Chase }, S_BEGR_10 }, //465
+/*S_BEGR_10*/ { SPR_BEGR, 3, 8, { A_CheckTargetVisible }, S_BEGR_07 }, //466
+/*S_BEGR_11*/ { SPR_BEGR, 0, 3, { A_Pain }, S_BEGR_12 }, //467
+/*S_BEGR_12*/ { SPR_BEGR, 0, 3, { A_Chase }, S_BEGR_07 }, //468
+/*S_BEGR_13*/ { SPR_BEGR, 5, 4, { NULL }, S_BEGR_14 }, //469
+/*S_BEGR_14*/ { SPR_BEGR, 6, 4, { A_Scream }, S_BEGR_15 }, //470
+/*S_BEGR_15*/ { SPR_BEGR, 7, 4, { NULL }, S_BEGR_16 }, //471
+/*S_BEGR_16*/ { SPR_BEGR, 8, 4, { A_Fall }, S_BEGR_17 }, //472
+/*S_BEGR_17*/ { SPR_BEGR, 9, 4, { NULL }, S_BEGR_18 }, //473
+/*S_BEGR_18*/ { SPR_BEGR, 10, 4, { NULL }, S_BEGR_19 }, //474
+/*S_BEGR_19*/ { SPR_BEGR, 11, 4, { NULL }, S_BEGR_20 }, //475
+/*S_BEGR_20*/ { SPR_BEGR, 12, 4, { NULL }, S_BEGR_21 }, //476
+/*S_BEGR_21*/ { SPR_BEGR, 13, -1, { NULL }, S_NULL }, //477
+/*S_BEGR_22*/ { SPR_BEGR, 5, 5, { A_BodyParts }, S_GIBS_01 }, //478
+/*S_HMN1_00*/ { SPR_HMN1, 15, 5, { A_FriendLook }, S_HMN1_00 }, //479
+/*S_HMN1_01*/ { SPR_HMN1, 16, 8, { NULL }, S_HMN1_00 }, //480
+/*S_HMN1_02*/ { SPR_HMN1, 17, 8, { NULL }, S_HMN1_00 }, //481
+/*S_HMN1_03*/ { SPR_HMN1, 0, 6, { A_RandomWalk }, S_HMN1_04 }, //482
+/*S_HMN1_04*/ { SPR_HMN1, 1, 6, { A_RandomWalk }, S_HMN1_05 }, //483
+/*S_HMN1_05*/ { SPR_HMN1, 2, 6, { A_RandomWalk }, S_HMN1_06 }, //484
+/*S_HMN1_06*/ { SPR_HMN1, 3, 6, { A_RandomWalk }, S_HMN1_07 }, //485
+/*S_HMN1_07*/ { SPR_HMN1, 0, 6, { A_RandomWalk }, S_HMN1_08 }, //486
+/*S_HMN1_08*/ { SPR_HMN1, 1, 6, { A_RandomWalk }, S_HMN1_09 }, //487
+/*S_HMN1_09*/ { SPR_HMN1, 2, 6, { A_RandomWalk }, S_HMN1_10 }, //488
+/*S_HMN1_10*/ { SPR_HMN1, 3, 6, { A_RandomWalk }, S_HMN1_00 }, //489
+/*S_HMN1_11*/ { SPR_HMN1, 0, 3, { A_Chase }, S_HMN1_12 }, //490
+/*S_HMN1_12*/ { SPR_HMN1, 0, 3, { A_Chase }, S_HMN1_13 }, //491
+/*S_HMN1_13*/ { SPR_HMN1, 1, 3, { A_Chase }, S_HMN1_14 }, //492
+/*S_HMN1_14*/ { SPR_HMN1, 1, 3, { A_Chase }, S_HMN1_15 }, //493
+/*S_HMN1_15*/ { SPR_HMN1, 2, 3, { A_Chase }, S_HMN1_16 }, //494
+/*S_HMN1_16*/ { SPR_HMN1, 2, 3, { A_Chase }, S_HMN1_17 }, //495
+/*S_HMN1_17*/ { SPR_HMN1, 3, 3, { A_Chase }, S_HMN1_18 }, //496
+/*S_HMN1_18*/ { SPR_HMN1, 3, 3, { A_Chase }, S_HMN1_11 }, //497
+/*S_HMN1_19*/ { SPR_HMN1, 4, 10, { A_FaceTarget }, S_HMN1_20 }, //498
+/*S_HMN1_20*/ { SPR_HMN1, 32773, 10, { A_BulletAttack }, S_HMN1_21 }, //499
+/*S_HMN1_21*/ { SPR_HMN1, 4, 10, { A_BulletAttack }, S_HMN1_11 }, //500
+/*S_HMN1_22*/ { SPR_HMN1, 14, 3, { NULL }, S_HMN1_23 }, //501
+/*S_HMN1_23*/ { SPR_HMN1, 14, 3, { A_Pain }, S_HMN1_11 }, //502
+/*S_HMN1_24*/ { SPR_HMN1, 6, 5, { NULL }, S_HMN1_25 }, //503
+/*S_HMN1_25*/ { SPR_HMN1, 7, 5, { A_Scream }, S_HMN1_26 }, //504
+/*S_HMN1_26*/ { SPR_HMN1, 8, 3, { A_Fall }, S_HMN1_27 }, //505
+/*S_HMN1_27*/ { SPR_HMN1, 9, 4, { NULL }, S_HMN1_28 }, //506
+/*S_HMN1_28*/ { SPR_HMN1, 10, 3, { NULL }, S_HMN1_29 }, //507
+/*S_HMN1_29*/ { SPR_HMN1, 11, 3, { NULL }, S_HMN1_30 }, //508
+/*S_HMN1_30*/ { SPR_HMN1, 12, 3, { NULL }, S_HMN1_31 }, //509
+/*S_HMN1_31*/ { SPR_HMN1, 13, -1, { NULL }, S_NULL }, //510
+/*S_RGIB_08*/ { SPR_RGIB, 0, 4, { A_BodyParts }, S_RGIB_09 }, //511
+/*S_RGIB_09*/ { SPR_RGIB, 1, 4, { A_XScream }, S_RGIB_10 }, //512
+/*S_RGIB_10*/ { SPR_RGIB, 2, 3, { A_Fall }, S_RGIB_11 }, //513
+/*S_RGIB_11*/ { SPR_RGIB, 3, 3, { A_BodyParts }, S_RGIB_12 }, //514
+/*S_RGIB_12*/ { SPR_RGIB, 4, 3, { A_BodyParts }, S_RGIB_13 }, //515
+/*S_RGIB_13*/ { SPR_RGIB, 5, 3, { A_BodyParts }, S_RGIB_14 }, //516
+/*S_RGIB_14*/ { SPR_RGIB, 6, 3, { NULL }, S_RGIB_15 }, //517
+/*S_RGIB_15*/ { SPR_RGIB, 7, 1400, { NULL }, S_NULL }, //518
+/*S_LEDR_00*/ { SPR_LEDR, 2, 5, { A_FriendLook }, S_LEDR_00 }, //519
+/*S_LEDR_01*/ { SPR_LEDR, 0, 8, { NULL }, S_LEDR_00 }, //520
+/*S_LEDR_02*/ { SPR_LEDR, 1, 8, { NULL }, S_LEDR_00 }, //521
+/*S_LEAD_00*/ { SPR_LEAD, 0, 6, { A_RandomWalk }, S_LEAD_01 }, //522
+/*S_LEAD_01*/ { SPR_LEAD, 1, 6, { A_RandomWalk }, S_LEAD_02 }, //523
+/*S_LEAD_02*/ { SPR_LEAD, 2, 6, { A_RandomWalk }, S_LEAD_03 }, //524
+/*S_LEAD_03*/ { SPR_LEAD, 3, 6, { A_RandomWalk }, S_LEDR_00 }, //525
+/*S_LEAD_04*/ { SPR_LEAD, 0, 3, { A_Chase }, S_LEAD_05 }, //526
+/*S_LEAD_05*/ { SPR_LEAD, 0, 3, { A_Chase }, S_LEAD_06 }, //527
+/*S_LEAD_06*/ { SPR_LEAD, 1, 3, { A_Chase }, S_LEAD_07 }, //528
+/*S_LEAD_07*/ { SPR_LEAD, 1, 3, { A_Chase }, S_LEAD_08 }, //529
+/*S_LEAD_08*/ { SPR_LEAD, 2, 3, { A_Chase }, S_LEAD_09 }, //530
+/*S_LEAD_09*/ { SPR_LEAD, 2, 3, { A_Chase }, S_LEAD_10 }, //531
+/*S_LEAD_10*/ { SPR_LEAD, 3, 3, { A_Chase }, S_LEAD_11 }, //532
+/*S_LEAD_11*/ { SPR_LEAD, 3, 3, { A_Chase }, S_LEAD_04 }, //533
+/*S_LEAD_12*/ { SPR_LEAD, 4, 2, { A_FaceTarget }, S_LEAD_13 }, //534
+/*S_LEAD_13*/ { SPR_LEAD, 32773, 2, { A_BulletAttack }, S_LEAD_14 }, //535
+/*S_LEAD_14*/ { SPR_LEAD, 4, 1, { A_CheckTargetVisible }, S_LEAD_12 }, //536
+/*S_LEAD_15*/ { SPR_LEAD, 24, 3, { NULL }, S_LEAD_16 }, //537
+/*S_LEAD_16*/ { SPR_LEAD, 24, 3, { A_Pain }, S_LEAD_04 }, //538
+/*S_LEAD_17*/ { SPR_LEAD, 4, 4, { A_FaceTarget }, S_LEAD_18 }, //539
+/*S_LEAD_18*/ { SPR_LEAD, 32773, 4, { A_BulletAttack }, S_LEAD_19 }, //540
+/*S_LEAD_19*/ { SPR_LEAD, 4, 2, { A_CheckTargetVisible }, S_LEAD_17 }, //541
+/*S_LEAD_20*/ { SPR_LEAD, 6, 5, { NULL }, S_LEAD_21 }, //542
+/*S_LEAD_21*/ { SPR_LEAD, 7, 5, { A_Scream }, S_LEAD_22 }, //543
+/*S_LEAD_22*/ { SPR_LEAD, 8, 4, { NULL }, S_LEAD_23 }, //544
+/*S_LEAD_23*/ { SPR_LEAD, 9, 4, { NULL }, S_LEAD_24 }, //545
+/*S_LEAD_24*/ { SPR_LEAD, 10, 3, { NULL }, S_LEAD_25 }, //546
+/*S_LEAD_25*/ { SPR_LEAD, 11, 3, { A_Fall }, S_LEAD_26 }, //547
+/*S_LEAD_26*/ { SPR_LEAD, 12, 3, { NULL }, S_LEAD_27 }, //548
+/*S_LEAD_27*/ { SPR_LEAD, 13, 3, { NULL }, S_LEAD_28 }, //549
+/*S_LEAD_28*/ { SPR_LEAD, 14, 3, { NULL }, S_LEAD_29 }, //550
+/*S_LEAD_29*/ { SPR_LEAD, 15, 3, { NULL }, S_LEAD_30 }, //551
+/*S_LEAD_30*/ { SPR_LEAD, 16, 3, { NULL }, S_LEAD_31 }, //552
+/*S_LEAD_31*/ { SPR_LEAD, 17, 3, { NULL }, S_LEAD_32 }, //553
+/*S_LEAD_32*/ { SPR_LEAD, 18, 3, { NULL }, S_LEAD_33 }, //554
+/*S_LEAD_33*/ { SPR_LEAD, 19, 3, { NULL }, S_LEAD_34 }, //555
+/*S_LEAD_34*/ { SPR_LEAD, 20, 3, { NULL }, S_LEAD_35 }, //556
+/*S_LEAD_35*/ { SPR_LEAD, 21, 3, { NULL }, S_LEAD_36 }, //557
+/*S_LEAD_36*/ { SPR_LEAD, 22, 3, { A_SpawnSpectreD }, S_LEAD_37 }, //558
+/*S_LEAD_37*/ { SPR_LEAD, 23, -1, { NULL }, S_NULL }, //559
+/*S_PUFY_04*/ { SPR_PUFY, 1, 4, { NULL }, S_PUFY_05 }, //560
+/*S_PUFY_05*/ { SPR_PUFY, 2, 4, { NULL }, S_PUFY_06 }, //561
+/*S_PUFY_06*/ { SPR_PUFY, 1, 4, { NULL }, S_PUFY_07 }, //562
+/*S_PUFY_07*/ { SPR_PUFY, 2, 4, { NULL }, S_PUFY_08 }, //563
+/*S_PUFY_08*/ { SPR_PUFY, 3, 4, { NULL }, S_NULL }, //564
+/*S_MICR_01*/ { SPR_MICR, 32768, 2, { A_Tracer }, S_MICR_02 }, //565
+/*S_MICR_02*/ { SPR_MICR, 32768, 2, { A_Tracer }, S_MICR_01 }, //566
+/*S_ROB1_00*/ { SPR_ROB1, 0, 10, { A_Look }, S_ROB1_01 }, //567
+/*S_ROB1_01*/ { SPR_ROB1, 0, 10, { A_Look }, S_ROB1_00 }, //568
+/*S_ROB1_02*/ { SPR_ROB1, 1, 3, { A_Chase }, S_ROB1_03 }, //569
+/*S_ROB1_03*/ { SPR_ROB1, 1, 3, { A_Chase }, S_ROB1_04 }, //570
+/*S_ROB1_04*/ { SPR_ROB1, 2, 3, { A_Chase }, S_ROB1_05 }, //571
+/*S_ROB1_05*/ { SPR_ROB1, 2, 3, { A_Chase }, S_ROB1_06 }, //572
+/*S_ROB1_06*/ { SPR_ROB1, 3, 3, { A_Chase }, S_ROB1_07 }, //573
+/*S_ROB1_07*/ { SPR_ROB1, 3, 3, { A_Chase }, S_ROB1_08 }, //574
+/*S_ROB1_08*/ { SPR_ROB1, 4, 3, { A_Chase }, S_ROB1_09 }, //575
+/*S_ROB1_09*/ { SPR_ROB1, 4, 3, { A_Chase }, S_ROB1_02 }, //576
+/*S_ROB1_10*/ { SPR_ROB1, 7, 6, { A_FaceTarget }, S_ROB1_11 }, //577
+/*S_ROB1_11*/ { SPR_ROB1, 8, 8, { A_RobotMelee }, S_ROB1_12 }, //578
+/*S_ROB1_12*/ { SPR_ROB1, 7, 6, { NULL }, S_ROB1_02 }, //579
+/*S_ROB1_13*/ { SPR_ROB1, 5, 8, { A_FaceTarget }, S_ROB1_14 }, //580
+/*S_ROB1_14*/ { SPR_ROB1, 32774, 11, { A_ReaverAttack }, S_ROB1_02 }, //581
+/*S_ROB1_15*/ { SPR_ROB1, 0, 2, { NULL }, S_ROB1_16 }, //582
+/*S_ROB1_16*/ { SPR_ROB1, 0, 2, { A_Pain }, S_ROB1_02 }, //583
+/*S_ROB1_17*/ { SPR_ROB1, 32777, 6, { NULL }, S_ROB1_18 }, //584
+/*S_ROB1_18*/ { SPR_ROB1, 32778, 6, { A_Scream }, S_ROB1_19 }, //585
+/*S_ROB1_19*/ { SPR_ROB1, 32779, 5, { NULL }, S_ROB1_20 }, //586
+/*S_ROB1_20*/ { SPR_ROB1, 32780, 5, { A_Fall }, S_ROB1_21 }, //587
+/*S_ROB1_21*/ { SPR_ROB1, 32781, 5, { NULL }, S_ROB1_22 }, //588
+/*S_ROB1_22*/ { SPR_ROB1, 32782, 5, { NULL }, S_ROB1_23 }, //589
+/*S_ROB1_23*/ { SPR_ROB1, 32783, 5, { NULL }, S_ROB1_24 }, //590
+/*S_ROB1_24*/ { SPR_ROB1, 32784, 6, { A_DeathExplode3 }, S_ROB1_25 }, //591
+/*S_ROB1_25*/ { SPR_ROB1, 17, -1, { NULL }, S_NULL }, //592
+/*S_ROB1_26*/ { SPR_ROB1, 32779, 5, { A_BodyParts }, S_ROB1_27 }, //593
+/*S_ROB1_27*/ { SPR_ROB1, 32780, 5, { A_XScream }, S_ROB1_28 }, //594
+/*S_ROB1_28*/ { SPR_ROB1, 32781, 5, { A_BodyParts }, S_ROB1_29 }, //595
+/*S_ROB1_29*/ { SPR_ROB1, 32782, 5, { A_Fall }, S_ROB1_30 }, //596
+/*S_ROB1_30*/ { SPR_ROB1, 32783, 5, { A_BodyParts }, S_ROB1_31 }, //597
+/*S_ROB1_31*/ { SPR_ROB1, 32784, 5, { A_DeathExplode3 }, S_ROB1_32 }, //598
+/*S_ROB1_32*/ { SPR_ROB1, 17, -1, { NULL }, S_NULL }, //599
+/*S_AGRD_01*/ { SPR_AGRD, 0, 5, { A_FriendLook }, S_AGRD_01 }, //600
+/*S_AGRD_02*/ { SPR_AGRD, 1, 8, { A_ShadowOff }, S_AGRD_01 }, //601
+/*S_AGRD_03*/ { SPR_AGRD, 3, 8, { NULL }, S_AGRD_01 }, //602
+/*S_AGRD_04*/ { SPR_AGRD, 0, 5, { A_RandomWalk }, S_AGRD_05 }, //603
+/*S_AGRD_05*/ { SPR_AGRD, 1, 5, { A_RandomWalk }, S_AGRD_06 }, //604
+/*S_AGRD_06*/ { SPR_AGRD, 2, 5, { A_RandomWalk }, S_AGRD_07 }, //605
+/*S_AGRD_07*/ { SPR_AGRD, 3, 5, { A_RandomWalk }, S_AGRD_08 }, //606
+/*S_AGRD_08*/ { SPR_AGRD, 0, 5, { A_RandomWalk }, S_AGRD_09 }, //607
+/*S_AGRD_09*/ { SPR_AGRD, 1, 5, { A_RandomWalk }, S_AGRD_10 }, //608
+/*S_AGRD_10*/ { SPR_AGRD, 2, 5, { A_RandomWalk }, S_AGRD_11 }, //609
+/*S_AGRD_11*/ { SPR_AGRD, 3, 5, { A_RandomWalk }, S_AGRD_01 }, //610
+/*S_AGRD_12*/ { SPR_AGRD, 0, 6, { A_ModifyVisibility }, S_AGRD_14 }, //611
+/*S_AGRD_13*/ { SPR_AGRD, 0, 6, { A_SetTLOptions }, S_AGRD_14 }, //612
+/*S_AGRD_14*/ { SPR_AGRD, 1, 6, { A_Chase }, S_AGRD_15 }, //613
+/*S_AGRD_15*/ { SPR_AGRD, 2, 6, { A_Chase }, S_AGRD_16 }, //614
+/*S_AGRD_16*/ { SPR_AGRD, 3, 6, { A_Chase }, S_AGRD_13 }, //615
+/*S_AGRD_17*/ { SPR_AGRD, 4, 8, { A_FaceTarget }, S_AGRD_18 }, //616
+/*S_AGRD_18*/ { SPR_AGRD, 5, 4, { A_BulletAttack }, S_AGRD_19 }, //617
+/*S_AGRD_19*/ { SPR_AGRD, 4, 4, { A_BulletAttack }, S_AGRD_20 }, //618
+/*S_AGRD_20*/ { SPR_AGRD, 5, 6, { A_BulletAttack }, S_AGRD_13 }, //619
+/*S_AGRD_21*/ { SPR_AGRD, 14, 0, { A_ShadowOn }, S_AGRD_22 }, //620
+/*S_AGRD_22*/ { SPR_AGRD, 14, 8, { A_Pain }, S_AGRD_12 }, //621
+/*S_AGRD_23*/ { SPR_AGRD, 14, 8, { A_Pain }, S_AGRD_13 }, //622
+/*S_AGRD_24*/ { SPR_AGRD, 6, 4, { NULL }, S_AGRD_25 }, //623
+/*S_AGRD_25*/ { SPR_AGRD, 7, 4, { A_Scream }, S_AGRD_26 }, //624
+/*S_AGRD_26*/ { SPR_AGRD, 8, 4, { NULL }, S_AGRD_27 }, //625
+/*S_AGRD_27*/ { SPR_AGRD, 9, 3, { NULL }, S_AGRD_28 }, //626
+/*S_AGRD_28*/ { SPR_AGRD, 10, 3, { A_Fall }, S_AGRD_29 }, //627
+/*S_AGRD_29*/ { SPR_AGRD, 11, 3, { NULL }, S_AGRD_30 }, //628
+/*S_AGRD_30*/ { SPR_AGRD, 12, 3, { A_AcolyteSpecial }, S_AGRD_31 }, //629
+/*S_AGRD_31*/ { SPR_AGRD, 13, 1400, { NULL }, S_GIBS_20 }, //630
+/*S_GIBS_10*/ { SPR_GIBS, 0, 5, { A_Fall }, S_GIBS_11 }, //631
+/*S_GIBS_11*/ { SPR_GIBS, 1, 5, { A_BodyParts }, S_GIBS_12 }, //632
+/*S_GIBS_12*/ { SPR_GIBS, 2, 5, { A_BodyParts }, S_GIBS_13 }, //633
+/*S_GIBS_13*/ { SPR_GIBS, 3, 4, { A_BodyParts }, S_GIBS_14 }, //634
+/*S_GIBS_14*/ { SPR_GIBS, 4, 4, { A_XScream }, S_GIBS_15 }, //635
+/*S_GIBS_15*/ { SPR_GIBS, 5, 4, { A_BodyParts }, S_GIBS_16 }, //636
+/*S_GIBS_16*/ { SPR_GIBS, 6, 4, { NULL }, S_GIBS_17 }, //637
+/*S_GIBS_17*/ { SPR_GIBS, 7, 4, { NULL }, S_GIBS_18 }, //638
+/*S_GIBS_18*/ { SPR_GIBS, 8, 5, { NULL }, S_GIBS_19 }, //639
+/*S_GIBS_19*/ { SPR_GIBS, 9, 5, { A_AcolyteSpecial }, S_GIBS_20 }, //640
+/*S_GIBS_20*/ { SPR_GIBS, 10, 5, { NULL }, S_GIBS_21 }, //641
+/*S_GIBS_21*/ { SPR_GIBS, 11, 1400, { NULL }, S_NULL }, //642
+/*S_PGRD_00*/ { SPR_PGRD, 0, 5, { A_FriendLook }, S_PGRD_00 }, //643
+/*S_PGRD_01*/ { SPR_PGRD, 1, 10, { NULL }, S_PGRD_00 }, //644
+/*S_PGRD_02*/ { SPR_PGRD, 2, 10, { NULL }, S_PGRD_00 }, //645
+/*S_PGRD_03*/ { SPR_PGRD, 1, 10, { A_RandomWalk }, S_PGRD_00 }, //646
+/*S_PGRD_04*/ { SPR_PGRD, 0, 3, { A_Chase }, S_PGRD_05 }, //647
+/*S_PGRD_05*/ { SPR_PGRD, 0, 3, { A_Chase }, S_PGRD_06 }, //648
+/*S_PGRD_06*/ { SPR_PGRD, 1, 3, { A_Chase }, S_PGRD_07 }, //649
+/*S_PGRD_07*/ { SPR_PGRD, 1, 3, { A_Chase }, S_PGRD_08 }, //650
+/*S_PGRD_08*/ { SPR_PGRD, 2, 3, { A_Chase }, S_PGRD_09 }, //651
+/*S_PGRD_09*/ { SPR_PGRD, 2, 3, { A_Chase }, S_PGRD_10 }, //652
+/*S_PGRD_10*/ { SPR_PGRD, 3, 3, { A_Chase }, S_PGRD_11 }, //653
+/*S_PGRD_11*/ { SPR_PGRD, 3, 3, { A_Chase }, S_PGRD_04 }, //654
+/*S_PGRD_12*/ { SPR_PGRD, 4, 8, { A_FaceTarget }, S_PGRD_13 }, //655
+/*S_PGRD_13*/ { SPR_PGRD, 5, 8, { A_RobotMelee }, S_PGRD_04 }, //656
+/*S_PGRD_14*/ { SPR_PGRD, 32774, 8, { A_FaceTarget }, S_PGRD_15 }, //657
+/*S_PGRD_15*/ { SPR_PGRD, 32775, 8, { A_TemplarMauler }, S_PGRD_04 }, //658
+/*S_PGRD_16*/ { SPR_PGRD, 0, 2, { NULL }, S_PGRD_17 }, //659
+/*S_PGRD_17*/ { SPR_PGRD, 0, 2, { A_Pain }, S_PGRD_04 }, //660
+/*S_PGRD_18*/ { SPR_PGRD, 32776, 4, { A_BodyParts }, S_PGRD_19 }, //661
+/*S_PGRD_19*/ { SPR_PGRD, 32777, 4, { A_Scream }, S_PGRD_20 }, //662
+/*S_PGRD_20*/ { SPR_PGRD, 32778, 4, { A_BodyParts }, S_PGRD_21 }, //663
+/*S_PGRD_21*/ { SPR_PGRD, 32779, 4, { A_Fall }, S_PGRD_22 }, //664
+/*S_PGRD_22*/ { SPR_PGRD, 32780, 4, { NULL }, S_PGRD_23 }, //665
+/*S_PGRD_23*/ { SPR_PGRD, 32781, 4, { NULL }, S_PGRD_24 }, //666
+/*S_PGRD_24*/ { SPR_PGRD, 14, 4, { A_BodyParts }, S_PGRD_25 }, //667
+/*S_PGRD_25*/ { SPR_PGRD, 15, 4, { NULL }, S_PGRD_26 }, //668
+/*S_PGRD_26*/ { SPR_PGRD, 16, 4, { NULL }, S_PGRD_27 }, //669
+/*S_PGRD_27*/ { SPR_PGRD, 17, 4, { NULL }, S_PGRD_28 }, //670
+/*S_PGRD_28*/ { SPR_PGRD, 18, 3, { NULL }, S_PGRD_29 }, //671
+/*S_PGRD_29*/ { SPR_PGRD, 19, 3, { NULL }, S_PGRD_30 }, //672
+/*S_PGRD_30*/ { SPR_PGRD, 20, 3, { NULL }, S_PGRD_31 }, //673
+/*S_PGRD_31*/ { SPR_PGRD, 21, 3, { NULL }, S_PGRD_32 }, //674
+/*S_PGRD_32*/ { SPR_PGRD, 22, 3, { NULL }, S_PGRD_33 }, //675
+/*S_PGRD_33*/ { SPR_PGRD, 23, 3, { NULL }, S_PGRD_34 }, //676
+/*S_PGRD_34*/ { SPR_PGRD, 24, 3, { NULL }, S_PGRD_35 }, //677
+/*S_PGRD_35*/ { SPR_PGRD, 25, 3, { NULL }, S_PGRD_36 }, //678
+/*S_PGRD_36*/ { SPR_PGRD, 26, 3, { NULL }, S_PGRD_37 }, //679
+/*S_PGRD_37*/ { SPR_PGRD, 27, -1, { NULL }, S_NULL }, //680
+/*S_ROB2_00*/ { SPR_ROB2, 16, 10, { A_Look }, S_ROB2_00 }, //681
+/*S_ROB2_01*/ { SPR_ROB2, 0, 3, { A_Chase }, S_ROB2_02 }, //682
+/*S_ROB2_02*/ { SPR_ROB2, 0, 3, { A_Chase }, S_ROB2_03 }, //683
+/*S_ROB2_03*/ { SPR_ROB2, 1, 3, { A_Chase }, S_ROB2_04 }, //684
+/*S_ROB2_04*/ { SPR_ROB2, 1, 3, { A_Chase }, S_ROB2_05 }, //685
+/*S_ROB2_05*/ { SPR_ROB2, 2, 3, { A_Chase }, S_ROB2_06 }, //686
+/*S_ROB2_06*/ { SPR_ROB2, 2, 3, { A_Chase }, S_ROB2_07 }, //687
+/*S_ROB2_07*/ { SPR_ROB2, 3, 3, { A_Chase }, S_ROB2_08 }, //688
+/*S_ROB2_08*/ { SPR_ROB2, 3, 3, { A_Chase }, S_ROB2_01 }, //689
+/*S_ROB2_09*/ { SPR_ROB2, 4, 3, { A_FaceTarget }, S_ROB2_10 }, //690
+/*S_ROB2_10*/ { SPR_ROB2, 32773, 2, { A_CrusaderAttack }, S_ROB2_11 }, //691
+/*S_ROB2_11*/ { SPR_ROB2, 32772, 2, { A_CrusaderLeft }, S_ROB2_12 }, //692
+/*S_ROB2_12*/ { SPR_ROB2, 32773, 3, { A_CrusaderLeft }, S_ROB2_13 }, //693
+/*S_ROB2_13*/ { SPR_ROB2, 32772, 2, { A_CrusaderLeft }, S_ROB2_14 }, //694
+/*S_ROB2_14*/ { SPR_ROB2, 32773, 2, { A_CrusaderLeft }, S_ROB2_15 }, //695
+/*S_ROB2_15*/ { SPR_ROB2, 32772, 2, { A_CrusaderRight }, S_ROB2_16 }, //696
+/*S_ROB2_16*/ { SPR_ROB2, 32773, 2, { A_CrusaderRight }, S_ROB2_17 }, //697
+/*S_ROB2_17*/ { SPR_ROB2, 32772, 2, { A_CrusaderRight }, S_ROB2_18 }, //698
+/*S_ROB2_18*/ { SPR_ROB2, 5, 2, { A_CheckTargetVisible2 }, S_ROB2_09 }, //699
+/*S_ROB2_19*/ { SPR_ROB2, 3, 1, { A_Pain }, S_ROB2_01 }, //700
+/*S_ROB2_20*/ { SPR_ROB2, 6, 3, { A_Scream }, S_ROB2_21 }, //701
+/*S_ROB2_21*/ { SPR_ROB2, 7, 5, { A_BodyParts }, S_ROB2_22 }, //702
+/*S_ROB2_22*/ { SPR_ROB2, 32776, 4, { A_BodyParts }, S_ROB2_23 }, //703
+/*S_ROB2_23*/ { SPR_ROB2, 32777, 4, { A_DeathExplode2 }, S_ROB2_24 }, //704
+/*S_ROB2_24*/ { SPR_ROB2, 32778, 4, { A_Fall }, S_ROB2_25 }, //705
+/*S_ROB2_25*/ { SPR_ROB2, 11, 4, { A_DeathExplode2 }, S_ROB2_26 }, //706
+/*S_ROB2_26*/ { SPR_ROB2, 12, 4, { A_BodyParts }, S_ROB2_27 }, //707
+/*S_ROB2_27*/ { SPR_ROB2, 13, 4, { A_BodyParts }, S_ROB2_28 }, //708
+/*S_ROB2_28*/ { SPR_ROB2, 14, 4, { A_DeathExplode2 }, S_ROB2_29 }, //709
+/*S_ROB2_29*/ { SPR_ROB2, 15, -1, { A_BossDeath }, S_NULL }, //710
+/*S_MLDR_00*/ { SPR_MLDR, 0, 10, { A_Look }, S_MLDR_00 }, //711
+/*S_MLDR_01*/ { SPR_MLDR, 0, 3, { A_Chase }, S_MLDR_02 }, //712
+/*S_MLDR_02*/ { SPR_MLDR, 0, 3, { A_Chase }, S_MLDR_03 }, //713
+/*S_MLDR_03*/ { SPR_MLDR, 1, 3, { A_Chase }, S_MLDR_04 }, //714
+/*S_MLDR_04*/ { SPR_MLDR, 1, 3, { A_Chase }, S_MLDR_05 }, //715
+/*S_MLDR_05*/ { SPR_MLDR, 2, 3, { A_Chase }, S_MLDR_06 }, //716
+/*S_MLDR_06*/ { SPR_MLDR, 2, 3, { A_Chase }, S_MLDR_07 }, //717
+/*S_MLDR_07*/ { SPR_MLDR, 3, 3, { A_Chase }, S_MLDR_08 }, //718
+/*S_MLDR_08*/ { SPR_MLDR, 3, 3, { A_Chase }, S_MLDR_01 }, //719
+/*S_MLDR_09*/ { SPR_MLDR, 4, 3, { A_FaceTarget }, S_MLDR_10 }, //720
+/*S_MLDR_10*/ { SPR_MLDR, 32773, 2, { A_BishopAttack }, S_MLDR_01 }, //721
+/*S_MLDR_11*/ { SPR_MLDR, 3, 1, { A_Pain }, S_MLDR_01 }, //722
+/*S_MLDR_12*/ { SPR_MLDR, 32774, 3, { NULL }, S_MLDR_13 }, //723
+/*S_MLDR_13*/ { SPR_MLDR, 32775, 5, { A_Scream }, S_MLDR_14 }, //724
+/*S_MLDR_14*/ { SPR_MLDR, 32776, 4, { A_BodyParts }, S_MLDR_15 }, //725
+/*S_MLDR_15*/ { SPR_MLDR, 32777, 4, { A_DeathExplode2 }, S_MLDR_16 }, //726
+/*S_MLDR_16*/ { SPR_MLDR, 32778, 4, { NULL }, S_MLDR_17 }, //727
+/*S_MLDR_17*/ { SPR_MLDR, 32779, 4, { NULL }, S_MLDR_18 }, //728
+/*S_MLDR_18*/ { SPR_MLDR, 32780, 4, { A_Fall }, S_MLDR_19 }, //729
+/*S_MLDR_19*/ { SPR_MLDR, 32781, 4, { NULL }, S_MLDR_20 }, //730
+/*S_MLDR_20*/ { SPR_MLDR, 32782, 4, { A_BodyParts }, S_MLDR_21 }, //731
+/*S_MLDR_21*/ { SPR_MLDR, 32783, 4, { NULL }, S_MLDR_22 }, //732
+/*S_MLDR_22*/ { SPR_MLDR, 32784, 4, { A_BodyParts }, S_MLDR_23 }, //733
+/*S_MLDR_23*/ { SPR_MLDR, 32785, 4, { NULL }, S_MLDR_24 }, //734
+/*S_MLDR_24*/ { SPR_MLDR, 32786, 4, { A_BodyParts }, S_MLDR_25 }, //735
+/*S_MLDR_25*/ { SPR_MLDR, 32787, 4, { NULL }, S_MLDR_26 }, //736
+/*S_MLDR_26*/ { SPR_MLDR, 32788, 4, { A_BodyParts }, S_MLDR_27 }, //737
+/*S_MLDR_27*/ { SPR_MLDR, 21, 4, { A_SpawnSpectreB }, S_NULL }, //738
+/*S_ORCL_00*/ { SPR_ORCL, 0, -1, { NULL }, S_NULL }, //739
+/*S_ORCL_01*/ { SPR_ORCL, 1, 5, { NULL }, S_ORCL_02 }, //740
+/*S_ORCL_02*/ { SPR_ORCL, 2, 5, { NULL }, S_ORCL_03 }, //741
+/*S_ORCL_03*/ { SPR_ORCL, 3, 5, { NULL }, S_ORCL_04 }, //742
+/*S_ORCL_04*/ { SPR_ORCL, 4, 5, { NULL }, S_ORCL_05 }, //743
+/*S_ORCL_05*/ { SPR_ORCL, 5, 5, { NULL }, S_ORCL_06 }, //744
+/*S_ORCL_06*/ { SPR_ORCL, 6, 5, { NULL }, S_ORCL_07 }, //745
+/*S_ORCL_07*/ { SPR_ORCL, 7, 5, { NULL }, S_ORCL_08 }, //746
+/*S_ORCL_08*/ { SPR_ORCL, 8, 5, { NULL }, S_ORCL_09 }, //747
+/*S_ORCL_09*/ { SPR_ORCL, 9, 5, { NULL }, S_ORCL_10 }, //748
+/*S_ORCL_10*/ { SPR_ORCL, 10, 5, { NULL }, S_ORCL_11 }, //749
+/*S_ORCL_11*/ { SPR_ORCL, 11, 5, { A_Fall }, S_ORCL_12 }, //750
+/*S_ORCL_12*/ { SPR_ORCL, 12, 5, { NULL }, S_ORCL_13 }, //751
+/*S_ORCL_13*/ { SPR_ORCL, 13, 5, { A_AlertSpectreC }, S_ORCL_14 }, //752
+/*S_ORCL_14*/ { SPR_ORCL, 14, 5, { NULL }, S_ORCL_15 }, //753
+/*S_ORCL_15*/ { SPR_ORCL, 15, 5, { NULL }, S_ORCL_16 }, //754
+/*S_ORCL_16*/ { SPR_ORCL, 16, -1, { NULL }, S_NULL }, //755
+/*S_PRST_00*/ { SPR_PRST, 0, 10, { A_Look }, S_PRST_01 }, //756
+/*S_PRST_01*/ { SPR_PRST, 1, 10, { A_FloatWeave }, S_PRST_00 }, //757
+/*S_PRST_02*/ { SPR_PRST, 0, 4, { A_Chase }, S_PRST_03 }, //758
+/*S_PRST_03*/ { SPR_PRST, 0, 4, { A_FloatWeave }, S_PRST_04 }, //759
+/*S_PRST_04*/ { SPR_PRST, 1, 4, { A_Chase }, S_PRST_05 }, //760
+/*S_PRST_05*/ { SPR_PRST, 1, 4, { A_FloatWeave }, S_PRST_06 }, //761
+/*S_PRST_06*/ { SPR_PRST, 2, 4, { A_Chase }, S_PRST_07 }, //762
+/*S_PRST_07*/ { SPR_PRST, 2, 4, { A_FloatWeave }, S_PRST_08 }, //763
+/*S_PRST_08*/ { SPR_PRST, 3, 4, { A_Chase }, S_PRST_09 }, //764
+/*S_PRST_09*/ { SPR_PRST, 3, 4, { A_FloatWeave }, S_PRST_02 }, //765
+/*S_PRST_10*/ { SPR_PRST, 4, 4, { A_FaceTarget }, S_PRST_11 }, //766
+/*S_PRST_11*/ { SPR_PRST, 5, 4, { A_BossMeleeAtk }, S_PRST_12 }, //767
+/*S_PRST_12*/ { SPR_PRST, 4, 4, { A_FloatWeave }, S_PRST_02 }, //768
+/*S_PRST_13*/ { SPR_PRST, 4, 4, { A_FaceTarget }, S_PRST_14 }, //769
+/*S_PRST_14*/ { SPR_PRST, 5, 4, { A_FireHookShot }, S_PRST_15 }, //770
+/*S_PRST_15*/ { SPR_PRST, 4, 4, { A_FloatWeave }, S_PRST_02 }, //771
+/*S_PDED_00*/ { SPR_PDED, 0, 6, { NULL }, S_PDED_01 }, //772
+/*S_PDED_01*/ { SPR_PDED, 1, 6, { A_Scream }, S_PDED_02 }, //773
+/*S_PDED_02*/ { SPR_PDED, 2, 6, { NULL }, S_PDED_03 }, //774
+/*S_PDED_03*/ { SPR_PDED, 3, 6, { A_Fall }, S_PDED_04 }, //775
+/*S_PDED_04*/ { SPR_PDED, 4, 6, { NULL }, S_PDED_05 }, //776
+/*S_PDED_05*/ { SPR_PDED, 5, 5, { NULL }, S_PDED_06 }, //777
+/*S_PDED_06*/ { SPR_PDED, 6, 5, { NULL }, S_PDED_07 }, //778
+/*S_PDED_07*/ { SPR_PDED, 7, 5, { NULL }, S_PDED_08 }, //779
+/*S_PDED_08*/ { SPR_PDED, 8, 5, { NULL }, S_PDED_09 }, //780
+/*S_PDED_09*/ { SPR_PDED, 9, 5, { NULL }, S_PDED_10 }, //781
+/*S_PDED_10*/ { SPR_PDED, 8, 5, { NULL }, S_PDED_11 }, //782
+/*S_PDED_11*/ { SPR_PDED, 9, 5, { NULL }, S_PDED_12 }, //783
+/*S_PDED_12*/ { SPR_PDED, 8, 5, { NULL }, S_PDED_14 }, //784
+/*S_PDED_13*/ { SPR_PDED, 9, 5, { NULL }, S_PDED_14 }, //785
+/*S_PDED_14*/ { SPR_PDED, 10, 5, { NULL }, S_PDED_15 }, //786
+/*S_PDED_15*/ { SPR_PDED, 11, 5, { NULL }, S_PDED_16 }, //787
+/*S_PDED_16*/ { SPR_PDED, 12, 4, { NULL }, S_PDED_17 }, //788
+/*S_PDED_17*/ { SPR_PDED, 13, 4, { NULL }, S_PDED_18 }, //789
+/*S_PDED_18*/ { SPR_PDED, 14, 4, { NULL }, S_PDED_19 }, //790
+/*S_PDED_19*/ { SPR_PDED, 15, 4, { NULL }, S_PDED_20 }, //791
+/*S_PDED_20*/ { SPR_PDED, 16, 4, { A_SpawnSpectreE }, S_PDED_21 }, //792
+/*S_PDED_21*/ { SPR_PDED, 17, 4, { NULL }, S_PDED_22 }, //793
+/*S_PDED_22*/ { SPR_PDED, 18, 4, { NULL }, S_PDED_23 }, //794
+/*S_PDED_23*/ { SPR_PDED, 19, -1, { NULL }, S_NULL }, //795
+/*S_ALN1_00*/ { SPR_ALN1, 0, 10, { A_Look }, S_ALN1_01 }, //796
+/*S_ALN1_01*/ { SPR_ALN1, 1, 10, { A_FloatWeave }, S_ALN1_00 }, //797
+/*S_ALN1_02*/ { SPR_ALN1, 32768, 4, { A_Chase }, S_ALN1_03 }, //798
+/*S_ALN1_03*/ { SPR_ALN1, 32769, 4, { A_Chase }, S_ALN1_04 }, //799
+/*S_ALN1_04*/ { SPR_ALN1, 32770, 4, { A_FloatWeave }, S_ALN1_05 }, //800
+/*S_ALN1_05*/ { SPR_ALN1, 32771, 4, { A_Chase }, S_ALN1_06 }, //801
+/*S_ALN1_06*/ { SPR_ALN1, 32772, 4, { A_Chase }, S_ALN1_07 }, //802
+/*S_ALN1_07*/ { SPR_ALN1, 32773, 4, { A_Chase }, S_ALN1_08 }, //803
+/*S_ALN1_08*/ { SPR_ALN1, 32774, 4, { A_FloatWeave }, S_ALN1_09 }, //804
+/*S_ALN1_09*/ { SPR_ALN1, 32775, 4, { A_Chase }, S_ALN1_10 }, //805
+/*S_ALN1_10*/ { SPR_ALN1, 32776, 4, { A_Chase }, S_ALN1_11 }, //806
+/*S_ALN1_11*/ { SPR_ALN1, 32777, 4, { A_Chase }, S_ALN1_12 }, //807
+/*S_ALN1_12*/ { SPR_ALN1, 32778, 4, { A_FloatWeave }, S_ALN1_02 }, //808
+/*S_ALN1_13*/ { SPR_ALN1, 32777, 4, { A_FaceTarget }, S_ALN1_14 }, //809
+/*S_ALN1_14*/ { SPR_ALN1, 32776, 4, { A_BossMeleeAtk }, S_ALN1_15 }, //810
+/*S_ALN1_15*/ { SPR_ALN1, 32775, 4, { NULL }, S_ALN1_04 }, //811
+/*S_ALN1_16*/ { SPR_ALN1, 32777, 4, { A_FaceTarget }, S_ALN1_17 }, //812
+/*S_ALN1_17*/ { SPR_ALN1, 32776, 4, { A_ProgrammerAttack }, S_ALN1_18 }, //813
+/*S_ALN1_18*/ { SPR_ALN1, 32775, 4, { NULL }, S_ALN1_12 }, //814
+/*S_ALN1_19*/ { SPR_ALN1, 9, 2, { A_Pain }, S_ALN1_08 }, //815
+/*S_AL1P_00*/ { SPR_AL1P, 32768, 6, { A_NodeChunk }, S_AL1P_01 }, //816
+/*S_AL1P_01*/ { SPR_AL1P, 32769, 6, { A_Scream }, S_AL1P_02 }, //817
+/*S_AL1P_02*/ { SPR_AL1P, 32770, 6, { A_NodeChunk }, S_AL1P_03 }, //818
+/*S_AL1P_03*/ { SPR_AL1P, 32771, 6, { NULL }, S_AL1P_04 }, //819
+/*S_AL1P_04*/ { SPR_AL1P, 32772, 6, { NULL }, S_AL1P_05 }, //820
+/*S_AL1P_05*/ { SPR_AL1P, 32773, 6, { A_NodeChunk }, S_AL1P_06 }, //821
+/*S_AL1P_06*/ { SPR_AL1P, 32774, 6, { NULL }, S_AL1P_07 }, //822
+/*S_AL1P_07*/ { SPR_AL1P, 32775, 6, { A_NodeChunk }, S_AL1P_08 }, //823
+/*S_AL1P_08*/ { SPR_AL1P, 32776, 6, { NULL }, S_AL1P_09 }, //824
+/*S_AL1P_09*/ { SPR_AL1P, 32777, 6, { NULL }, S_AL1P_10 }, //825
+/*S_AL1P_10*/ { SPR_AL1P, 32778, 6, { NULL }, S_AL1P_11 }, //826
+/*S_AL1P_11*/ { SPR_AL1P, 32779, 5, { NULL }, S_AL1P_12 }, //827
+/*S_AL1P_12*/ { SPR_AL1P, 32780, 5, { NULL }, S_AL1P_13 }, //828
+/*S_AL1P_13*/ { SPR_AL1P, 32781, 5, { A_HeadChunk }, S_AL1P_14 }, //829
+/*S_AL1P_14*/ { SPR_AL1P, 32782, 5, { NULL }, S_AL1P_15 }, //830
+/*S_AL1P_15*/ { SPR_AL1P, 32783, 5, { NULL }, S_AL1P_16 }, //831
+/*S_AL1P_16*/ { SPR_AL1P, 32784, 5, { NULL }, S_AL1P_17 }, //832
+/*S_AL1P_17*/ { SPR_AL1P, 32785, 5, { A_BossDeath }, S_NULL }, //833
+/*S_NODE_00*/ { SPR_NODE, 32768, 6, { NULL }, S_NODE_01 }, //834
+/*S_NODE_01*/ { SPR_NODE, 32769, 6, { NULL }, S_NODE_02 }, //835
+/*S_NODE_02*/ { SPR_NODE, 32770, 6, { NULL }, S_NODE_03 }, //836
+/*S_NODE_03*/ { SPR_NODE, 32771, 6, { NULL }, S_NODE_04 }, //837
+/*S_NODE_04*/ { SPR_NODE, 32772, 6, { NULL }, S_NODE_05 }, //838
+/*S_NODE_05*/ { SPR_NODE, 32773, 6, { NULL }, S_NODE_06 }, //839
+/*S_NODE_06*/ { SPR_NODE, 32774, 6, { NULL }, S_NULL }, //840
+/*S_MTHD_00*/ { SPR_MTHD, 32768, 5, { NULL }, S_MTHD_01 }, //841
+/*S_MTHD_01*/ { SPR_MTHD, 32769, 5, { NULL }, S_MTHD_02 }, //842
+/*S_MTHD_02*/ { SPR_MTHD, 32770, 5, { NULL }, S_MTHD_03 }, //843
+/*S_MTHD_03*/ { SPR_MTHD, 32771, 5, { NULL }, S_MTHD_04 }, //844
+/*S_MTHD_04*/ { SPR_MTHD, 32772, 5, { NULL }, S_MTHD_05 }, //845
+/*S_MTHD_05*/ { SPR_MTHD, 32773, 5, { NULL }, S_MTHD_06 }, //846
+/*S_MTHD_06*/ { SPR_MTHD, 32774, 5, { NULL }, S_MTHD_07 }, //847
+/*S_MTHD_07*/ { SPR_MTHD, 32775, 5, { NULL }, S_MTHD_08 }, //848
+/*S_MTHD_08*/ { SPR_MTHD, 32776, 5, { NULL }, S_MTHD_09 }, //849
+/*S_MTHD_09*/ { SPR_MTHD, 32777, 5, { NULL }, S_MTHD_10 }, //850
+/*S_MTHD_10*/ { SPR_MTHD, 32778, 5, { NULL }, S_NULL }, //851
+/*S_ALN1_20*/ { SPR_ALN1, 5, 4, { A_FaceTarget }, S_ALN1_21 }, //852
+/*S_ALN1_21*/ { SPR_ALN1, 8, 4, { A_FireSigilEOffshoot }, S_ALN1_22 }, //853
+/*S_ALN1_22*/ { SPR_ALN1, 4, 4, { NULL }, S_ALN1_12 }, //854
+/*S_ALN1_23*/ { SPR_ALN1, 0, 5, { A_FloatWeave }, S_ALN1_24 }, //855
+/*S_ALN1_24*/ { SPR_ALN1, 1, 5, { A_FloatWeave }, S_ALN1_25 }, //856
+/*S_ALN1_25*/ { SPR_ALN1, 2, 5, { A_FloatWeave }, S_ALN1_26 }, //857
+/*S_ALN1_26*/ { SPR_ALN1, 3, 5, { A_FloatWeave }, S_ALN1_27 }, //858
+/*S_ALN1_27*/ { SPR_ALN1, 4, 5, { A_FloatWeave }, S_ALN1_28 }, //859
+/*S_ALN1_28*/ { SPR_ALN1, 5, 5, { A_FloatWeave }, S_ALN1_29 }, //860
+/*S_ALN1_29*/ { SPR_ALN1, 6, 5, { A_FloatWeave }, S_ALN1_30 }, //861
+/*S_ALN1_30*/ { SPR_ALN1, 7, 5, { A_FloatWeave }, S_ALN1_31 }, //862
+/*S_ALN1_31*/ { SPR_ALN1, 8, 5, { A_FloatWeave }, S_ALN1_32 }, //863
+/*S_ALN1_32*/ { SPR_ALN1, 9, 5, { A_FloatWeave }, S_ALN1_33 }, //864
+/*S_ALN1_33*/ { SPR_ALN1, 10, 5, { A_FloatWeave }, S_ALN1_23 }, //865
+/*S_ALN1_34*/ { SPR_ALN1, 0, 5, { A_Chase }, S_ALN1_35 }, //866
+/*S_ALN1_35*/ { SPR_ALN1, 1, 5, { A_Chase }, S_ALN1_36 }, //867
+/*S_ALN1_36*/ { SPR_ALN1, 2, 5, { A_FloatWeave }, S_ALN1_37 }, //868
+/*S_ALN1_37*/ { SPR_ALN1, 3, 5, { A_Chase }, S_ALN1_38 }, //869
+/*S_ALN1_38*/ { SPR_ALN1, 4, 5, { A_Chase }, S_ALN1_39 }, //870
+/*S_ALN1_39*/ { SPR_ALN1, 5, 5, { A_Chase }, S_ALN1_40 }, //871
+/*S_ALN1_40*/ { SPR_ALN1, 6, 5, { A_FloatWeave }, S_ALN1_41 }, //872
+/*S_ALN1_41*/ { SPR_ALN1, 7, 5, { A_Chase }, S_ALN1_42 }, //873
+/*S_ALN1_42*/ { SPR_ALN1, 8, 5, { A_Chase }, S_ALN1_43 }, //874
+/*S_ALN1_43*/ { SPR_ALN1, 9, 5, { A_Chase }, S_ALN1_44 }, //875
+/*S_ALN1_44*/ { SPR_ALN1, 10, 5, { A_FloatWeave }, S_ALN1_34 }, //876
+/*S_ALN1_45*/ { SPR_ALN1, 9, 4, { A_FaceTarget }, S_ALN1_46 }, //877
+/*S_ALN1_46*/ { SPR_ALN1, 8, 4, { A_BossMeleeAtk }, S_ALN1_47 }, //878
+/*S_ALN1_47*/ { SPR_ALN1, 2, 4, { NULL }, S_ALN1_36 }, //879
+/*S_ALN1_48*/ { SPR_ALN1, 5, 4, { A_FaceTarget }, S_ALN1_49 }, //880
+/*S_ALN1_49*/ { SPR_ALN1, 8, 4, { A_SpectreCAttack }, S_ALN1_50 }, //881
+/*S_ALN1_50*/ { SPR_ALN1, 4, 4, { NULL }, S_ALN1_44 }, //882
+/*S_ALN1_51*/ { SPR_ALN1, 9, 2, { A_Pain }, S_ALN1_40 }, //883
+/*S_ALN1_52*/ { SPR_ALN1, 5, 4, { A_FaceTarget }, S_ALN1_53 }, //884
+/*S_ALN1_53*/ { SPR_ALN1, 8, 4, { A_SpectreDAttack }, S_ALN1_54 }, //885
+/*S_ALN1_54*/ { SPR_ALN1, 4, 4, { NULL }, S_ALN1_12 }, //886
+/*S_ALN1_55*/ { SPR_ALN1, 5, 4, { A_FaceTarget }, S_ALN1_56 }, //887
+/*S_ALN1_56*/ { SPR_ALN1, 8, 4, { A_SpectreEAttack }, S_ALN1_57 }, //888
+/*S_ALN1_57*/ { SPR_ALN1, 4, 4, { NULL }, S_ALN1_12 }, //889
+/*S_MNAM_00*/ { SPR_MNAM, 0, 100, { A_FloatWeave }, S_MNAM_01 }, //890
+/*S_MNAM_01*/ { SPR_MNAM, 32769, 60, { A_FloatWeave }, S_MNAM_02 }, //891
+/*S_MNAM_02*/ { SPR_MNAM, 32770, 4, { A_FloatWeave }, S_MNAM_03 }, //892
+/*S_MNAM_03*/ { SPR_MNAM, 32771, 4, { A_FloatWeave }, S_MNAM_04 }, //893
+/*S_MNAM_04*/ { SPR_MNAM, 32772, 4, { A_FloatWeave }, S_MNAM_05 }, //894
+/*S_MNAM_05*/ { SPR_MNAM, 32773, 4, { A_FloatWeave }, S_MNAM_06 }, //895
+/*S_MNAM_06*/ { SPR_MNAM, 32774, 4, { A_FloatWeave }, S_MNAM_07 }, //896
+/*S_MNAM_07*/ { SPR_MNAM, 32775, 4, { A_FloatWeave }, S_MNAM_08 }, //897
+/*S_MNAM_08*/ { SPR_MNAM, 32776, 4, { A_FloatWeave }, S_MNAM_09 }, //898
+/*S_MNAM_09*/ { SPR_MNAM, 32777, 4, { A_FloatWeave }, S_MNAM_10 }, //899
+/*S_MNAM_10*/ { SPR_MNAM, 32778, 4, { A_FloatWeave }, S_MNAM_11 }, //900
+/*S_MNAM_11*/ { SPR_MNAM, 32779, 4, { A_FloatWeave }, S_MNAL_00 }, //901
+/*S_MNAL_00*/ { SPR_MNAL, 32768, 4, { A_Look }, S_MNAL_01 }, //902
+/*S_MNAL_01*/ { SPR_MNAL, 32769, 4, { A_FloatWeave }, S_MNAL_00 }, //903
+/*S_MNAL_02*/ { SPR_MNAL, 32768, 4, { A_Chase }, S_MNAL_03 }, //904
+/*S_MNAL_03*/ { SPR_MNAL, 32769, 4, { A_Chase }, S_MNAL_04 }, //905
+/*S_MNAL_04*/ { SPR_MNAL, 32770, 4, { A_FloatWeave }, S_MNAL_05 }, //906
+/*S_MNAL_05*/ { SPR_MNAL, 32771, 4, { A_Chase }, S_MNAL_06 }, //907
+/*S_MNAL_06*/ { SPR_MNAL, 32772, 4, { A_Chase }, S_MNAL_07 }, //908
+/*S_MNAL_07*/ { SPR_MNAL, 32773, 4, { A_Chase }, S_MNAL_08 }, //909
+/*S_MNAL_08*/ { SPR_MNAL, 32774, 4, { A_FloatWeave }, S_MNAL_09 }, //910
+/*S_MNAL_09*/ { SPR_MNAL, 32775, 4, { A_Chase }, S_MNAL_10 }, //911
+/*S_MNAL_10*/ { SPR_MNAL, 32776, 4, { A_Chase }, S_MNAL_11 }, //912
+/*S_MNAL_11*/ { SPR_MNAL, 32777, 4, { A_Chase }, S_MNAL_12 }, //913
+/*S_MNAL_12*/ { SPR_MNAL, 32778, 4, { A_FloatWeave }, S_MNAL_02 }, //914
+/*S_MNAL_13*/ { SPR_MNAL, 32777, 4, { A_FaceTarget }, S_MNAL_14 }, //915
+/*S_MNAL_14*/ { SPR_MNAL, 32776, 4, { A_BossMeleeAtk }, S_MNAL_15 }, //916
+/*S_MNAL_15*/ { SPR_MNAL, 32770, 4, { NULL }, S_MNAL_04 }, //917
+/*S_MNAL_16*/ { SPR_MNAL, 32773, 4, { A_FaceTarget }, S_MNAL_17 }, //918
+/*S_MNAL_17*/ { SPR_MNAL, 32776, 4, { A_FireSigilWeapon }, S_MNAL_18 }, //919
+/*S_MNAL_18*/ { SPR_MNAL, 32772, 4, { NULL }, S_MNAL_12 }, //920
+/*S_MNAL_19*/ { SPR_MNAL, 32777, 2, { A_Pain }, S_MNAL_08 }, //921
+/*S_MNAL_20*/ { SPR_MNAL, 32779, 7, { A_NodeChunk }, S_MNAL_21 }, //922
+/*S_MNAL_21*/ { SPR_MNAL, 32780, 7, { A_Scream }, S_MNAL_22 }, //923
+/*S_MNAL_22*/ { SPR_MNAL, 32781, 7, { A_NodeChunk }, S_MNAL_23 }, //924
+/*S_MNAL_23*/ { SPR_MNAL, 32782, 7, { A_NodeChunk }, S_MNAL_24 }, //925
+/*S_MNAL_24*/ { SPR_MNAL, 32783, 7, { A_HeadChunk }, S_MNAL_25 }, //926
+/*S_MNAL_25*/ { SPR_MNAL, 32784, 64, { A_NodeChunk }, S_MNAL_26 }, //927
+/*S_MNAL_26*/ { SPR_MNAL, 32784, 6, { A_EntityDeath }, S_NULL }, //928
+/*S_MNAL_27*/ { SPR_MNAL, 32785, 10, { A_Look }, S_MNAL_27 }, //929
+/*S_MNAL_28*/ { SPR_MNAL, 32785, 5, { A_FloatWeave }, S_MNAL_29 }, //930
+/*S_MNAL_29*/ { SPR_MNAL, 32786, 5, { A_Chase }, S_MNAL_30 }, //931
+/*S_MNAL_30*/ { SPR_MNAL, 32787, 5, { A_Chase }, S_MNAL_31 }, //932
+/*S_MNAL_31*/ { SPR_MNAL, 32788, 5, { A_FloatWeave }, S_MNAL_32 }, //933
+/*S_MNAL_32*/ { SPR_MNAL, 32789, 5, { A_Chase }, S_MNAL_33 }, //934
+/*S_MNAL_33*/ { SPR_MNAL, 32790, 5, { A_FloatWeave }, S_MNAL_28 }, //935
+/*S_MNAL_34*/ { SPR_MNAL, 32786, 4, { A_FaceTarget }, S_MNAL_35 }, //936
+/*S_MNAL_35*/ { SPR_MNAL, 32785, 4, { A_BossMeleeAtk }, S_MNAL_36 }, //937
+/*S_MNAL_36*/ { SPR_MNAL, 32787, 4, { A_FloatWeave }, S_MNAL_29 }, //938
+/*S_MNAL_37*/ { SPR_MNAL, 32790, 4, { A_FaceTarget }, S_MNAL_38 }, //939
+/*S_MNAL_38*/ { SPR_MNAL, 32788, 4, { A_FireSigilEOffshoot }, S_MNAL_39 }, //940
+/*S_MNAL_39*/ { SPR_MNAL, 32789, 4, { A_FloatWeave }, S_MNAL_32 }, //941
+/*S_MNAL_40*/ { SPR_MNAL, 32785, 2, { A_Pain }, S_MNAL_28 }, //942
+/*S_MDTH_00*/ { SPR_MDTH, 32768, 3, { A_Scream }, S_MDTH_01 }, //943
+/*S_MDTH_01*/ { SPR_MDTH, 32769, 3, { A_BodyParts }, S_MDTH_02 }, //944
+/*S_MDTH_02*/ { SPR_MDTH, 32770, 3, { A_Fall }, S_MDTH_03 }, //945
+/*S_MDTH_03*/ { SPR_MDTH, 32771, 3, { A_BodyParts }, S_MDTH_04 }, //946
+/*S_MDTH_04*/ { SPR_MDTH, 32772, 3, { A_BodyParts }, S_MDTH_05 }, //947
+/*S_MDTH_05*/ { SPR_MDTH, 32773, 3, { A_BodyParts }, S_MDTH_06 }, //948
+/*S_MDTH_06*/ { SPR_MDTH, 32774, 3, { A_BodyParts }, S_MDTH_07 }, //949
+/*S_MDTH_07*/ { SPR_MDTH, 32775, 3, { A_BodyParts }, S_MDTH_08 }, //950
+/*S_MDTH_08*/ { SPR_MDTH, 32776, 3, { A_BodyParts }, S_MDTH_09 }, //951
+/*S_MDTH_09*/ { SPR_MDTH, 32777, 3, { A_BodyParts }, S_MDTH_10 }, //952
+/*S_MDTH_10*/ { SPR_MDTH, 32778, 3, { A_BodyParts }, S_MDTH_11 }, //953
+/*S_MDTH_11*/ { SPR_MDTH, 32779, 3, { A_BodyParts }, S_MDTH_12 }, //954
+/*S_MDTH_12*/ { SPR_MDTH, 32780, 3, { A_BodyParts }, S_MDTH_13 }, //955
+/*S_MDTH_13*/ { SPR_MDTH, 32781, 3, { A_BodyParts }, S_MDTH_14 }, //956
+/*S_MDTH_14*/ { SPR_MDTH, 32782, 3, { A_BossDeath }, S_NULL }, //957
+/*S_NEST_00*/ { SPR_NEST, 0, -1, { NULL }, S_NULL }, //958
+/*S_PODD_00*/ { SPR_PODD, 0, 60, { A_Look }, S_PODD_00 }, //959
+/*S_PODD_01*/ { SPR_PODD, 0, 360, { NULL }, S_PODD_02 }, //960
+/*S_PODD_02*/ { SPR_PODD, 1, 9, { A_Fall }, S_PODD_03 }, //961
+/*S_PODD_03*/ { SPR_PODD, 2, 9, { NULL }, S_PODD_04 }, //962
+/*S_PODD_04*/ { SPR_PODD, 3, 9, { A_SpawnEntity }, S_PODD_05 }, //963
+/*S_PODD_05*/ { SPR_PODD, 4, -1, { NULL }, S_NULL }, //964
+/*S_ZAP6_00*/ { SPR_ZAP6, 32768, 4, { NULL }, S_ZAP6_01 }, //965
+/*S_ZAP6_01*/ { SPR_ZAP6, 32769, 4, { A_SigilTrail }, S_ZAP6_02 }, //966
+/*S_ZAP6_02*/ { SPR_ZAP6, 32770, 4, { A_SigilTrail }, S_ZAP6_00 }, //967
+/*S_ZOT3_00*/ { SPR_ZOT3, 32768, 4, { NULL }, S_ZOT3_01 }, //968
+/*S_ZOT3_01*/ { SPR_ZOT3, 32769, 4, { NULL }, S_ZOT3_02 }, //969
+/*S_ZOT3_02*/ { SPR_ZOT3, 32770, 4, { NULL }, S_ZOT3_03 }, //970
+/*S_ZOT3_03*/ { SPR_ZOT3, 32771, 4, { NULL }, S_ZOT3_04 }, //971
+/*S_ZOT3_04*/ { SPR_ZOT3, 32772, 4, { NULL }, S_ZOT3_00 }, //972
+/*S_ZAP6_03*/ { SPR_ZAP6, 32768, 5, { NULL }, S_ZAP6_04 }, //973
+/*S_ZAP6_04*/ { SPR_ZAP6, 32769, 5, { NULL }, S_ZAP6_05 }, //974
+/*S_ZAP6_05*/ { SPR_ZAP6, 32770, 5, { NULL }, S_NULL }, //975
+/*S_ZAP7_00*/ { SPR_ZAP7, 32768, 4, { A_Sigil_E_Action }, S_ZAP7_01 }, //976
+/*S_ZAP7_01*/ { SPR_ZAP7, 32769, 4, { A_Sigil_E_Action }, S_ZAP7_02 }, //977
+/*S_ZAP7_02*/ { SPR_ZAP7, 32770, 6, { A_Sigil_E_Action }, S_ZAP7_03 }, //978
+/*S_ZAP7_03*/ { SPR_ZAP7, 32771, 6, { A_Sigil_E_Action }, S_ZAP7_04 }, //979
+/*S_ZAP7_04*/ { SPR_ZAP7, 32772, 6, { A_Sigil_E_Action }, S_ZAP7_00 }, //980
+/*S_ZOT1_00*/ { SPR_ZOT1, 32768, 4, { NULL }, S_ZOT1_01 }, //981
+/*S_ZOT1_01*/ { SPR_ZOT1, 32769, 4, { NULL }, S_ZOT1_02 }, //982
+/*S_ZOT1_02*/ { SPR_ZOT1, 32770, 6, { NULL }, S_ZOT1_03 }, //983
+/*S_ZOT1_03*/ { SPR_ZOT1, 32771, 6, { NULL }, S_ZOT1_04 }, //984
+/*S_ZOT1_04*/ { SPR_ZOT1, 32771, 6, { NULL }, S_ZOT1_00 }, //985
+/*S_ZAP5_00*/ { SPR_ZAP5, 32768, 4, { A_MissileTick }, S_ZAP5_01 }, //986
+/*S_ZAP5_01*/ { SPR_ZAP5, 32769, 4, { A_Sigil_A_Action }, S_ZAP5_02 }, //987
+/*S_ZAP5_02*/ { SPR_ZAP5, 32770, 4, { A_MissileTick }, S_ZAP5_03 }, //988
+/*S_ZAP5_03*/ { SPR_ZAP5, 32771, 4, { A_MissileTick }, S_ZAP5_00 }, //989
+/*S_ZOT2_00*/ { SPR_ZOT2, 32768, 4, { A_Tracer }, S_ZOT2_01 }, //990
+/*S_ZOT2_01*/ { SPR_ZOT2, 32769, 4, { A_Tracer }, S_ZOT2_02 }, //991
+/*S_ZOT2_02*/ { SPR_ZOT2, 32770, 6, { A_Tracer }, S_ZOT2_03 }, //992
+/*S_ZOT2_03*/ { SPR_ZOT2, 32771, 6, { A_Tracer }, S_ZOT2_04 }, //993
+/*S_ZOT2_04*/ { SPR_ZOT2, 32772, 5, { A_Tracer }, S_ZOT2_00 }, //994
+/*S_SEWR_00*/ { SPR_SEWR, 0, 10, { A_Look }, S_SEWR_00 }, //995
+/*S_SEWR_01*/ { SPR_SEWR, 0, 6, { A_FloatWeave }, S_SEWR_02 }, //996
+/*S_SEWR_02*/ { SPR_SEWR, 0, 6, { A_Chase }, S_SEWR_01 }, //997
+/*S_SEWR_03*/ { SPR_SEWR, 1, 4, { A_FaceTarget }, S_SEWR_04 }, //998
+/*S_SEWR_04*/ { SPR_SEWR, 32770, 8, { A_SentinelAttack }, S_SEWR_05 }, //999
+/*S_SEWR_05*/ { SPR_SEWR, 32770, 4, { A_CheckTargetVisible }, S_SEWR_04 }, //1000
+/*S_SEWR_06*/ { SPR_SEWR, 3, 5, { A_Pain }, S_SEWR_05 }, //1001
+/*S_SEWR_07*/ { SPR_SEWR, 3, 7, { A_Fall }, S_SEWR_08 }, //1002
+/*S_SEWR_08*/ { SPR_SEWR, 32772, 8, { A_BodyParts }, S_SEWR_09 }, //1003
+/*S_SEWR_09*/ { SPR_SEWR, 32773, 5, { A_Scream }, S_SEWR_10 }, //1004
+/*S_SEWR_10*/ { SPR_SEWR, 32774, 4, { A_BodyParts }, S_SEWR_11 }, //1005
+/*S_SEWR_11*/ { SPR_SEWR, 32775, 4, { A_BodyParts }, S_SEWR_12 }, //1006
+/*S_SEWR_12*/ { SPR_SEWR, 8, 4, { NULL }, S_SEWR_13 }, //1007
+/*S_SEWR_13*/ { SPR_SEWR, 9, 5, { NULL }, S_NULL }, //1008
+/*S_SPID_00*/ { SPR_SPID, 0, 1, { A_StalkerSetLook }, S_SPID_00 }, //1009
+/*S_SPID_01*/ { SPR_SPID, 0, 10, { A_Look }, S_SPID_01 }, //1010
+/*S_SPID_02*/ { SPR_SPID, 9, 10, { A_Look }, S_SPID_02 }, //1011
+/*S_SPID_03*/ { SPR_SPID, 0, 1, { A_StalkerThink }, S_SPID_04 }, //1012
+/*S_SPID_04*/ { SPR_SPID, 0, 3, { A_Chase }, S_SPID_05 }, //1013
+/*S_SPID_05*/ { SPR_SPID, 1, 3, { A_Chase }, S_SPID_06 }, //1014
+/*S_SPID_06*/ { SPR_SPID, 1, 3, { A_Chase }, S_SPID_07 }, //1015
+/*S_SPID_07*/ { SPR_SPID, 2, 3, { A_StalkerChase }, S_SPID_08 }, //1016
+/*S_SPID_08*/ { SPR_SPID, 2, 3, { A_Chase }, S_SPID_03 }, //1017
+/*S_SPID_09*/ { SPR_SPID, 9, 3, { A_FaceTarget }, S_SPID_10 }, //1018
+/*S_SPID_10*/ { SPR_SPID, 10, 3, { A_StalkerScratch }, S_SPID_18 }, //1019
+/*S_SPID_11*/ { SPR_SPID, 2, 2, { A_StalkerDrop }, S_SPID_12 }, //1020
+/*S_SPID_12*/ { SPR_SPID, 8, 3, { NULL }, S_SPID_13 }, //1021
+/*S_SPID_13*/ { SPR_SPID, 7, 3, { NULL }, S_SPID_14 }, //1022
+/*S_SPID_14*/ { SPR_SPID, 6, 3, { NULL }, S_SPID_15 }, //1023
+/*S_SPID_15*/ { SPR_SPID, 5, 3, { NULL }, S_SPID_16 }, //1024
+/*S_SPID_16*/ { SPR_SPID, 4, 3, { NULL }, S_SPID_17 }, //1025
+/*S_SPID_17*/ { SPR_SPID, 3, 3, { NULL }, S_SPID_09 }, //1026
+/*S_SPID_18*/ { SPR_SPID, 9, 3, { A_StalkerChase }, S_SPID_19 }, //1027
+/*S_SPID_19*/ { SPR_SPID, 9, 3, { A_Chase }, S_SPID_20 }, //1028
+/*S_SPID_20*/ { SPR_SPID, 10, 3, { A_Chase }, S_SPID_21 }, //1029
+/*S_SPID_21*/ { SPR_SPID, 10, 3, { A_Chase }, S_SPID_22 }, //1030
+/*S_SPID_22*/ { SPR_SPID, 11, 3, { A_StalkerChase }, S_SPID_23 }, //1031
+/*S_SPID_23*/ { SPR_SPID, 11, 3, { A_Chase }, S_SPID_18 }, //1032
+/*S_SPID_24*/ { SPR_SPID, 11, 1, { A_Pain }, S_SPID_03 }, //1033
+/*S_SPID_25*/ { SPR_SPID, 14, 4, { NULL }, S_SPID_26 }, //1034
+/*S_SPID_26*/ { SPR_SPID, 15, 4, { A_Scream }, S_SPID_27 }, //1035
+/*S_SPID_27*/ { SPR_SPID, 16, 4, { NULL }, S_SPID_28 }, //1036
+/*S_SPID_28*/ { SPR_SPID, 17, 4, { NULL }, S_SPID_29 }, //1037
+/*S_SPID_29*/ { SPR_SPID, 18, 4, { NULL }, S_SPID_30 }, //1038
+/*S_SPID_30*/ { SPR_SPID, 19, 4, { NULL }, S_SPID_31 }, //1039
+/*S_SPID_31*/ { SPR_SPID, 20, 4, { A_Fall }, S_SPID_32 }, //1040
+/*S_SPID_32*/ { SPR_SPID, 21, 4, { NULL }, S_SPID_33 }, //1041
+/*S_SPID_33*/ { SPR_SPID, 22, 4, { NULL }, S_SPID_34 }, //1042
+/*S_SPID_34*/ { SPR_SPID, 32791, 4, { NULL }, S_SPID_35 }, //1043
+/*S_SPID_35*/ { SPR_SPID, 32792, 4, { NULL }, S_SPID_36 }, //1044
+/*S_SPID_36*/ { SPR_SPID, 32793, 4, { NULL }, S_SPID_37 }, //1045
+/*S_SPID_37*/ { SPR_SPID, 32794, 4, { NULL }, S_NULL }, //1046
+/*S_ROB3_00*/ { SPR_ROB3, 0, 10, { A_Look }, S_ROB3_01 }, //1047
+/*S_ROB3_01*/ { SPR_ROB3, 1, 10, { A_Look }, S_ROB3_00 }, //1048
+/*S_ROB3_02*/ { SPR_ROB3, 1, 3, { A_InqChase }, S_ROB3_03 }, //1049
+/*S_ROB3_03*/ { SPR_ROB3, 1, 3, { A_Chase }, S_ROB3_04 }, //1050
+/*S_ROB3_04*/ { SPR_ROB3, 2, 4, { A_Chase }, S_ROB3_05 }, //1051
+/*S_ROB3_05*/ { SPR_ROB3, 2, 4, { A_Chase }, S_ROB3_06 }, //1052
+/*S_ROB3_06*/ { SPR_ROB3, 3, 4, { A_Chase }, S_ROB3_07 }, //1053
+/*S_ROB3_07*/ { SPR_ROB3, 3, 4, { A_Chase }, S_ROB3_08 }, //1054
+/*S_ROB3_08*/ { SPR_ROB3, 4, 3, { A_InqChase }, S_ROB3_09 }, //1055
+/*S_ROB3_09*/ { SPR_ROB3, 4, 3, { A_InqFlyCheck }, S_ROB3_02 }, //1056
+/*S_ROB3_10*/ { SPR_ROB3, 0, 2, { A_InqFlyCheck }, S_ROB3_11 }, //1057
+/*S_ROB3_11*/ { SPR_ROB3, 5, 6, { A_FaceTarget }, S_ROB3_12 }, //1058
+/*S_ROB3_12*/ { SPR_ROB3, 32774, 8, { A_ReaverAttack }, S_ROB3_13 }, //1059
+/*S_ROB3_13*/ { SPR_ROB3, 6, 8, { A_ReaverAttack }, S_ROB3_02 }, //1060
+/*S_ROB3_14*/ { SPR_ROB3, 10, 12, { A_FaceTarget }, S_ROB3_15 }, //1061
+/*S_ROB3_15*/ { SPR_ROB3, 32777, 6, { A_InqGrenade }, S_ROB3_16 }, //1062
+/*S_ROB3_16*/ { SPR_ROB3, 10, 12, { NULL }, S_ROB3_02 }, //1063
+/*S_ROB3_17*/ { SPR_ROB3, 32775, 8, { A_InqTakeOff }, S_ROB3_18 }, //1064
+/*S_ROB3_18*/ { SPR_ROB3, 32776, 4, { A_InqFly }, S_ROB3_19 }, //1065
+/*S_ROB3_19*/ { SPR_ROB3, 32775, 4, { A_InqFly }, S_ROB3_18 }, //1066
+/*S_ROB3_20*/ { SPR_ROB3, 11, 4, { A_BodyParts }, S_ROB3_21 }, //1067
+/*S_ROB3_21*/ { SPR_ROB3, 12, 4, { A_Scream }, S_ROB3_22 }, //1068
+/*S_ROB3_22*/ { SPR_ROB3, 13, 4, { A_BodyParts }, S_ROB3_23 }, //1069
+/*S_ROB3_23*/ { SPR_ROB3, 32782, 4, { A_DeathExplode1 }, S_ROB3_24 }, //1070
+/*S_ROB3_24*/ { SPR_ROB3, 32783, 4, { A_BodyParts }, S_ROB3_25 }, //1071
+/*S_ROB3_25*/ { SPR_ROB3, 32784, 4, { A_Fall }, S_ROB3_26 }, //1072
+/*S_ROB3_26*/ { SPR_ROB3, 17, 4, { A_BodyParts }, S_ROB3_27 }, //1073
+/*S_ROB3_27*/ { SPR_ROB3, 18, 4, { A_BodyParts }, S_ROB3_28 }, //1074
+/*S_ROB3_28*/ { SPR_ROB3, 19, 4, { A_BodyParts }, S_ROB3_29 }, //1075
+/*S_ROB3_29*/ { SPR_ROB3, 20, 4, { A_BodyParts }, S_ROB3_30 }, //1076
+/*S_ROB3_30*/ { SPR_ROB3, 21, 4, { A_BodyParts }, S_ROB3_31 }, //1077
+/*S_ROB3_31*/ { SPR_ROB3, 32790, 4, { A_DeathExplode1 }, S_ROB3_32 }, //1078
+/*S_ROB3_32*/ { SPR_ROB3, 32791, 4, { A_BodyParts }, S_ROB3_33 }, //1079
+/*S_ROB3_33*/ { SPR_ROB3, 32792, 4, { A_BodyParts }, S_ROB3_34 }, //1080
+/*S_ROB3_34*/ { SPR_ROB3, 25, 4, { A_BodyParts }, S_ROB3_35 }, //1081
+/*S_ROB3_35*/ { SPR_ROB3, 26, 4, { A_BodyParts }, S_ROB3_36 }, //1082
+/*S_ROB3_36*/ { SPR_ROB3, 27, 3, { A_BodyParts }, S_ROB3_37 }, //1083
+/*S_ROB3_37*/ { SPR_ROB3, 32796, 3, { A_DeathExplode1 }, S_RBB3_00 }, //1084
+/*S_RBB3_00*/ { SPR_RBB3, 32768, 3, { A_InqTossArm }, S_RBB3_01 }, //1085
+/*S_RBB3_01*/ { SPR_RBB3, 32769, 3, { A_BodyParts }, S_RBB3_02 }, //1086
+/*S_RBB3_02*/ { SPR_RBB3, 2, 3, { A_BodyParts }, S_RBB3_03 }, //1087
+/*S_RBB3_03*/ { SPR_RBB3, 3, 3, { A_BodyParts }, S_RBB3_04 }, //1088
+/*S_RBB3_04*/ { SPR_RBB3, 4, -1, { A_BossDeath }, S_NULL }, //1089
+/*S_RBB3_05*/ { SPR_RBB3, 32773, 5, { NULL }, S_RBB3_06 }, //1090
+/*S_RBB3_06*/ { SPR_RBB3, 32774, 5, { NULL }, S_RBB3_07 }, //1091
+/*S_RBB3_07*/ { SPR_RBB3, 7, -1, { NULL }, S_NULL }, //1092
+/*S_PRGR_00*/ { SPR_PRGR, 0, 5, { A_Look }, S_PRGR_01 }, //1093
+/*S_PRGR_01*/ { SPR_PRGR, 0, 1, { A_FloatWeave }, S_PRGR_00 }, //1094
+/*S_PRGR_02*/ { SPR_PRGR, 0, 160, { A_FloatWeave }, S_PRGR_03 }, //1095
+/*S_PRGR_03*/ { SPR_PRGR, 1, 5, { A_FloatWeave }, S_PRGR_04 }, //1096
+/*S_PRGR_04*/ { SPR_PRGR, 2, 5, { A_FloatWeave }, S_PRGR_05 }, //1097
+/*S_PRGR_05*/ { SPR_PRGR, 3, 5, { A_FloatWeave }, S_PRGR_06 }, //1098
+/*S_PRGR_06*/ { SPR_PRGR, 4, 2, { A_FloatWeave }, S_PRGR_07 }, //1099
+/*S_PRGR_07*/ { SPR_PRGR, 5, 2, { A_FloatWeave }, S_PRGR_08 }, //1100
+/*S_PRGR_08*/ { SPR_PRGR, 4, 3, { A_Chase }, S_PRGR_09 }, //1101
+/*S_PRGR_09*/ { SPR_PRGR, 5, 3, { A_Chase }, S_PRGR_06 }, //1102
+/*S_PRGR_10*/ { SPR_PRGR, 4, 2, { A_FloatWeave }, S_PRGR_11 }, //1103
+/*S_PRGR_11*/ { SPR_PRGR, 5, 3, { A_FloatWeave }, S_PRGR_12 }, //1104
+/*S_PRGR_12*/ { SPR_PRGR, 4, 3, { A_FaceTarget }, S_PRGR_13 }, //1105
+/*S_PRGR_13*/ { SPR_PRGR, 5, 4, { A_ProgrammerMelee }, S_PRGR_06 }, //1106
+/*S_PRGR_14*/ { SPR_PRGR, 6, 5, { A_FaceTarget }, S_PRGR_15 }, //1107
+/*S_PRGR_15*/ { SPR_PRGR, 7, 5, { A_FloatWeave }, S_PRGR_16 }, //1108
+/*S_PRGR_16*/ { SPR_PRGR, 32776, 5, { A_FaceTarget }, S_PRGR_17 }, //1109
+/*S_PRGR_17*/ { SPR_PRGR, 32777, 5, { A_ProgrammerAttack }, S_PRGR_06 }, //1110
+/*S_PRGR_18*/ { SPR_PRGR, 10, 5, { A_Pain }, S_PRGR_19 }, //1111
+/*S_PRGR_19*/ { SPR_PRGR, 11, 5, { A_FloatWeave }, S_PRGR_06 }, //1112
+/*S_PRGR_20*/ { SPR_PRGR, 32779, 7, { A_BodyParts }, S_PRGR_21 }, //1113
+/*S_PRGR_21*/ { SPR_PRGR, 32780, 7, { A_Scream }, S_PRGR_22 }, //1114
+/*S_PRGR_22*/ { SPR_PRGR, 32781, 7, { A_BodyParts }, S_PRGR_23 }, //1115
+/*S_PRGR_23*/ { SPR_PRGR, 32782, 7, { A_Fall }, S_PRGR_24 }, //1116
+/*S_PRGR_24*/ { SPR_PRGR, 32783, 7, { A_BodyParts }, S_PRGR_25 }, //1117
+/*S_PRGR_25*/ { SPR_PRGR, 32784, 7, { A_ProgrammerDie }, S_PRGR_26 }, //1118
+/*S_PRGR_26*/ { SPR_PRGR, 32785, 7, { NULL }, S_PRGR_27 }, //1119
+/*S_PRGR_27*/ { SPR_PRGR, 32786, 6, { NULL }, S_PRGR_28 }, //1120
+/*S_PRGR_28*/ { SPR_PRGR, 32787, 5, { NULL }, S_PRGR_29 }, //1121
+/*S_PRGR_29*/ { SPR_PRGR, 32788, 5, { NULL }, S_PRGR_30 }, //1122
+/*S_PRGR_30*/ { SPR_PRGR, 32789, 5, { NULL }, S_PRGR_31 }, //1123
+/*S_PRGR_31*/ { SPR_PRGR, 32790, 5, { NULL }, S_PRGR_32 }, //1124
+/*S_PRGR_32*/ { SPR_PRGR, 32791, 32, { NULL }, S_PRGR_33 }, //1125
+/*S_PRGR_33*/ { SPR_PRGR, 32791, -1, { A_BossDeath }, S_NULL }, //1126
+/*S_BASE_00*/ { SPR_BASE, 32768, 5, { A_DeathExplode3 }, S_BASE_01 }, //1127
+/*S_BASE_01*/ { SPR_BASE, 32769, 5, { NULL }, S_BASE_02 }, //1128
+/*S_BASE_02*/ { SPR_BASE, 32770, 5, { NULL }, S_BASE_03 }, //1129
+/*S_BASE_03*/ { SPR_BASE, 32771, 5, { NULL }, S_BASE_04 }, //1130
+/*S_BASE_04*/ { SPR_BASE, 4, 5, { NULL }, S_BASE_05 }, //1131
+/*S_BASE_05*/ { SPR_BASE, 5, 5, { NULL }, S_BASE_06 }, //1132
+/*S_BASE_06*/ { SPR_BASE, 6, 5, { NULL }, S_BASE_07 }, //1133
+/*S_BASE_07*/ { SPR_BASE, 7, -1, { NULL }, S_NULL }, //1134
+/*S_FRBL_00*/ { SPR_FRBL, 32768, 3, { NULL }, S_FRBL_01 }, //1135
+/*S_FRBL_01*/ { SPR_FRBL, 32769, 3, { NULL }, S_FRBL_02 }, //1136
+/*S_FRBL_02*/ { SPR_FRBL, 32770, 3, { A_MissileTick }, S_FRBL_00 }, //1137
+/*S_FRBL_03*/ { SPR_FRBL, 32771, 5, { A_FlameDeath }, S_FRBL_04 }, //1138
+/*S_FRBL_04*/ { SPR_FRBL, 32772, 5, { NULL }, S_FRBL_05 }, //1139
+/*S_FRBL_05*/ { SPR_FRBL, 32773, 5, { NULL }, S_FRBL_06 }, //1140
+/*S_FRBL_06*/ { SPR_FRBL, 32774, 5, { NULL }, S_FRBL_07 }, //1141
+/*S_FRBL_07*/ { SPR_FRBL, 32775, 5, { NULL }, S_FRBL_08 }, //1142
+/*S_FRBL_08*/ { SPR_FRBL, 32776, 5, { NULL }, S_NULL }, //1143
+/*S_KLAX_00*/ { SPR_KLAX, 0, 5, { A_Listen }, S_KLAX_00 }, //1144
+/*S_KLAX_01*/ { SPR_KLAX, 1, 6, { A_ClaxonBlare }, S_KLAX_02 }, //1145
+/*S_KLAX_02*/ { SPR_KLAX, 2, 60, { NULL }, S_KLAX_01 }, //1146
+/*S_TURT_00*/ { SPR_TURT, 0, 5, { A_Listen }, S_TURT_00 }, //1147
+/*S_TURT_01*/ { SPR_TURT, 0, 2, { A_Chase }, S_TURT_01 }, //1148
+/*S_TURT_02*/ { SPR_TURT, 1, 4, { A_BulletAttack }, S_TURT_03 }, //1149
+/*S_TURT_03*/ { SPR_TURT, 3, 3, { A_CheckTargetVisible }, S_TURT_04 }, //1150
+/*S_TURT_04*/ { SPR_TURT, 0, 4, { A_CheckTargetVisible }, S_TURT_02 }, //1151
+/*S_BALL_00*/ { SPR_BALL, 32768, 6, { NULL }, S_BALL_01 }, //1152
+/*S_BALL_01*/ { SPR_BALL, 32769, 6, { NULL }, S_BALL_02 }, //1153
+/*S_BALL_02*/ { SPR_BALL, 32770, 6, { NULL }, S_BALL_03 }, //1154
+/*S_BALL_03*/ { SPR_BALL, 32771, 6, { NULL }, S_BALL_04 }, //1155
+/*S_BALL_04*/ { SPR_BALL, 32772, 6, { NULL }, S_TURT_05 }, //1156
+/*S_TURT_05*/ { SPR_TURT, 2, -1, { NULL }, S_NULL }, //1157
+/*S_PSTN_00*/ { SPR_PSTN, 0, 8, { NULL }, S_PSTN_01 }, //1158
+/*S_PSTN_01*/ { SPR_PSTN, 1, 8, { NULL }, S_PSTN_00 }, //1159
+/*S_PSTN_02*/ { SPR_PSTN, 32768, 4, { A_Scream }, S_PSTN_03 }, //1160
+/*S_PSTN_03*/ { SPR_PSTN, 32769, 4, { A_Fall }, S_PSTN_04 }, //1161
+/*S_PSTN_04*/ { SPR_PSTN, 32770, 4, { A_QuestMsg }, S_PSTN_05 }, //1162
+/*S_PSTN_05*/ { SPR_PSTN, 32771, 4, { A_SpawnSparkPuff }, S_PSTN_06 }, //1163
+/*S_PSTN_06*/ { SPR_PSTN, 32772, 4, { A_BodyParts }, S_PSTN_07 }, //1164
+/*S_PSTN_07*/ { SPR_PSTN, 32773, 4, { NULL }, S_PSTN_08 }, //1165
+/*S_PSTN_08*/ { SPR_PSTN, 32774, 4, { A_SpawnSparkPuff }, S_PSTN_09 }, //1166
+/*S_PSTN_09*/ { SPR_PSTN, 7, 4, { NULL }, S_PSTN_10 }, //1167
+/*S_PSTN_10*/ { SPR_PSTN, 8, -1, { NULL }, S_NULL }, //1168
+/*S_SECR_00*/ { SPR_SECR, 32768, 4, { NULL }, S_SECR_01 }, //1169
+/*S_SECR_01*/ { SPR_SECR, 32769, 4, { NULL }, S_SECR_02 }, //1170
+/*S_SECR_02*/ { SPR_SECR, 32770, 4, { NULL }, S_SECR_03 }, //1171
+/*S_SECR_03*/ { SPR_SECR, 32771, 4, { NULL }, S_SECR_00 }, //1172
+/*S_SECR_04*/ { SPR_SECR, 32772, 5, { A_SpawnSparkPuff }, S_SECR_05 }, //1173
+/*S_SECR_05*/ { SPR_SECR, 32773, 5, { A_Fall }, S_SECR_06 }, //1174
+/*S_SECR_06*/ { SPR_SECR, 32774, 5, { A_QuestMsg }, S_SECR_07 }, //1175
+/*S_SECR_07*/ { SPR_SECR, 32775, 5, { A_BodyParts }, S_SECR_08 }, //1176
+/*S_SECR_08*/ { SPR_SECR, 32776, 5, { A_SpawnSparkPuff }, S_SECR_09 }, //1177
+/*S_SECR_09*/ { SPR_SECR, 9, 5, { NULL }, S_SECR_10 }, //1178
+/*S_SECR_10*/ { SPR_SECR, 10, 5, { A_SpawnSparkPuff }, S_SECR_11 }, //1179
+/*S_SECR_11*/ { SPR_SECR, 11, 5, { NULL }, S_SECR_12 }, //1180
+/*S_SECR_12*/ { SPR_SECR, 12, 5, { A_SpawnSparkPuff }, S_SECR_13 }, //1181
+/*S_SECR_13*/ { SPR_SECR, 13, 5, { NULL }, S_SECR_14 }, //1182
+/*S_SECR_14*/ { SPR_SECR, 14, 5, { A_SpawnSparkPuff }, S_SECR_15 }, //1183
+/*S_SECR_15*/ { SPR_SECR, 15, -1, { NULL }, S_NULL }, //1184
+/*S_XPRK_01*/ { SPR_XPRK, 0, -1, { NULL }, S_NULL }, //1185
+/*S_XPRK_02*/ { SPR_XPRK, 0, 1, { A_ClearForceField }, S_BNG3_00 }, //1186
+/*S_TARG_00*/ { SPR_TARG, 0, -1, { NULL }, S_NULL }, //1187
+/*S_RING_00*/ { SPR_RING, 0, -1, { NULL }, S_NULL }, //1188
+/*S_EARS_00*/ { SPR_EARS, 0, -1, { NULL }, S_NULL }, //1189
+/*S_COMM_00*/ { SPR_COMM, 0, -1, { NULL }, S_NULL }, //1190
+/*S_BOOM_00*/ { SPR_BOOM, 32768, 1, { A_CrystalRadiusAtk }, S_BOOM_01 }, //1191
+/*S_BOOM_01*/ { SPR_BOOM, 32769, 3, { A_QuestMsg }, S_BOOM_02 }, //1192
+/*S_BOOM_02*/ { SPR_BOOM, 32770, 2, { A_CrystalExplode }, S_BOOM_03 }, //1193
+/*S_BOOM_03*/ { SPR_BOOM, 32771, 3, { A_SpawnSparkPuff }, S_BOOM_04 }, //1194
+/*S_BOOM_04*/ { SPR_BOOM, 32772, 3, { NULL }, S_BOOM_05 }, //1195
+/*S_BOOM_05*/ { SPR_BOOM, 32773, 3, { NULL }, S_BOOM_06 }, //1196
+/*S_BOOM_06*/ { SPR_BOOM, 32774, 3, { A_SpawnSparkPuff }, S_BOOM_07 }, //1197
+/*S_BOOM_07*/ { SPR_BOOM, 32775, 1, { A_CrystalRadiusAtk }, S_BOOM_08 }, //1198
+/*S_BOOM_08*/ { SPR_BOOM, 32776, 3, { NULL }, S_BOOM_09 }, //1199
+/*S_BOOM_09*/ { SPR_BOOM, 32777, 3, { A_SpawnSparkPuff }, S_BOOM_10 }, //1200
+/*S_BOOM_10*/ { SPR_BOOM, 32778, 3, { A_SpawnSparkPuff }, S_BOOM_11 }, //1201
+/*S_BOOM_11*/ { SPR_BOOM, 32779, 3, { A_SpawnSparkPuff }, S_BOOM_12 }, //1202
+/*S_BOOM_12*/ { SPR_BOOM, 32780, 3, { NULL }, S_BOOM_13 }, //1203
+/*S_BOOM_13*/ { SPR_BOOM, 32781, 3, { NULL }, S_BOOM_14 }, //1204
+/*S_BOOM_14*/ { SPR_BOOM, 32782, 3, { A_SpawnSparkPuff }, S_BOOM_15 }, //1205
+/*S_BOOM_15*/ { SPR_BOOM, 32783, 3, { NULL }, S_BOOM_16 }, //1206
+/*S_BOOM_16*/ { SPR_BOOM, 32784, 3, { NULL }, S_BOOM_17 }, //1207
+/*S_BOOM_17*/ { SPR_BOOM, 32785, 3, { NULL }, S_BOOM_18 }, //1208
+/*S_BOOM_18*/ { SPR_BOOM, 32786, 3, { NULL }, S_BOOM_19 }, //1209
+/*S_BOOM_19*/ { SPR_BOOM, 32787, 3, { NULL }, S_BOOM_20 }, //1210
+/*S_BOOM_20*/ { SPR_BOOM, 32788, 3, { A_ExtraLightOff }, S_BOOM_21 }, //1211
+/*S_BOOM_21*/ { SPR_BOOM, 32789, 3, { NULL }, S_BOOM_22 }, //1212
+/*S_BOOM_22*/ { SPR_BOOM, 32790, 3, { NULL }, S_BOOM_23 }, //1213
+/*S_BOOM_23*/ { SPR_BOOM, 32791, 3, { NULL }, S_BOOM_24 }, //1214
+/*S_BOOM_24*/ { SPR_BOOM, 32792, 3, { NULL }, S_NULL }, //1215
+/*S_RATT_00*/ { SPR_RATT, 0, 10, { A_Look }, S_RATT_00 }, //1216
+/*S_RATT_01*/ { SPR_RATT, 0, 4, { A_Chase }, S_RATT_02 }, //1217
+/*S_RATT_02*/ { SPR_RATT, 0, 4, { A_Chase }, S_RATT_03 }, //1218
+/*S_RATT_03*/ { SPR_RATT, 1, 4, { A_Chase }, S_RATT_04 }, //1219
+/*S_RATT_04*/ { SPR_RATT, 1, 4, { A_Chase }, S_RATT_01 }, //1220
+/*S_RATT_05*/ { SPR_RATT, 0, 8, { A_RandomWalk }, S_RATT_06 }, //1221
+/*S_RATT_06*/ { SPR_RATT, 1, 4, { A_RandomWalk }, S_RATT_01 }, //1222
+/*S_HOGN_00*/ { SPR_HOGN, 0, 2, { A_ZombieInSpecialSector }, S_HOGN_00 }, //1223
+/*S_HOGN_01*/ { SPR_HOGN, 1, 1, { A_ZombieInSpecialSector }, S_HOGN_02 }, //1224
+/*S_HOGN_02*/ { SPR_HOGN, 2, 1, { A_Pain }, S_HOGN_00 }, //1225
+/*S_DEAD_00*/ { SPR_DEAD, 0, -1, { NULL }, S_NULL }, //1226
+/*S_SBAN_00*/ { SPR_SBAN, 0, -1, { NULL }, S_NULL }, //1227
+/*S_BOTR_00*/ { SPR_BOTR, 0, -1, { NULL }, S_NULL }, //1228
+/*S_HATR_00*/ { SPR_HATR, 0, -1, { NULL }, S_NULL }, //1229
+/*S_TOPR_00*/ { SPR_TOPR, 0, -1, { NULL }, S_NULL }, //1230
+/*S_COUP_00*/ { SPR_COUP, 0, 5, { NULL }, S_COUP_01 }, //1231
+/*S_COUP_01*/ { SPR_COUP, 1, 5, { NULL }, S_COUP_00 }, //1232
+/*S_COUP_02*/ { SPR_COUP, 2, -1, { NULL }, S_COUP_01 }, //1233
+/*S_BUBB_00*/ { SPR_BUBB, 0, 4, { A_ActiveSound }, S_BUBB_00 }, //1234
+/*S_BUBF_00*/ { SPR_BUBF, 0, 4, { A_ActiveSound }, S_BUBF_00 }, //1235
+/*S_BUBC_00*/ { SPR_BUBC, 0, 4, { A_ActiveSound }, S_BUBC_00 }, //1236
+/*S_ASPR_00*/ { SPR_ASPR, 0, 4, { A_ActiveSound }, S_ASPR_00 }, //1237
+/*S_SPDL_00*/ { SPR_SPDL, 0, 5, { A_ActiveSound }, S_SPDL_01 }, //1238
+/*S_SPDL_01*/ { SPR_SPDL, 1, 5, { A_ActiveSound }, S_SPDL_02 }, //1239
+/*S_SPDL_02*/ { SPR_SPDL, 2, 5, { A_ActiveSound }, S_SPDL_00 }, //1240
+/*S_TOKN_00*/ { SPR_TOKN, 0, -1, { NULL }, S_NULL }, //1241
+/*S_OTOK_00*/ { SPR_OTOK, 0, -1, { NULL }, S_NULL }, //1242
+/*S_HELT_00*/ { SPR_HELT, 0, -1, { NULL }, S_NULL }, //1243
+/*S_GUNT_00*/ { SPR_GUNT, 0, -1, { NULL }, S_NULL }, //1244
+/*S_FULL_00*/ { SPR_FULL, 0, 35, { NULL }, S_FULL_01 }, //1245
+/*S_FULL_01*/ { SPR_FULL, 1, 35, { NULL }, S_FULL_00 }, //1246
+/*S_MEAT_00*/ { SPR_MEAT, 0, 700, { NULL }, S_NULL }, //1247
+/*S_MEAT_01*/ { SPR_MEAT, 1, 700, { NULL }, S_NULL }, //1248
+/*S_MEAT_02*/ { SPR_MEAT, 2, 700, { NULL }, S_NULL }, //1249
+/*S_MEAT_03*/ { SPR_MEAT, 3, 700, { NULL }, S_NULL }, //1250
+/*S_MEAT_04*/ { SPR_MEAT, 4, 700, { NULL }, S_NULL }, //1251
+/*S_MEAT_05*/ { SPR_MEAT, 5, 700, { NULL }, S_NULL }, //1252
+/*S_MEAT_06*/ { SPR_MEAT, 6, 700, { NULL }, S_NULL }, //1253
+/*S_MEAT_07*/ { SPR_MEAT, 7, 700, { NULL }, S_NULL }, //1254
+/*S_MEAT_08*/ { SPR_MEAT, 8, 700, { NULL }, S_NULL }, //1255
+/*S_MEAT_09*/ { SPR_MEAT, 9, 700, { NULL }, S_NULL }, //1256
+/*S_MEAT_10*/ { SPR_MEAT, 10, 700, { NULL }, S_NULL }, //1257
+/*S_MEAT_11*/ { SPR_MEAT, 11, 700, { NULL }, S_NULL }, //1258
+/*S_MEAT_12*/ { SPR_MEAT, 12, 700, { NULL }, S_NULL }, //1259
+/*S_MEAT_13*/ { SPR_MEAT, 13, 700, { NULL }, S_NULL }, //1260
+/*S_MEAT_14*/ { SPR_MEAT, 14, 700, { NULL }, S_NULL }, //1261
+/*S_MEAT_15*/ { SPR_MEAT, 15, 700, { NULL }, S_NULL }, //1262
+/*S_MEAT_16*/ { SPR_MEAT, 16, 700, { NULL }, S_NULL }, //1263
+/*S_MEAT_17*/ { SPR_MEAT, 17, 700, { NULL }, S_NULL }, //1264
+/*S_MEAT_18*/ { SPR_MEAT, 18, 700, { NULL }, S_NULL }, //1265
+/*S_MEAT_19*/ { SPR_MEAT, 19, 700, { NULL }, S_NULL }, //1266
+/*S_JUNK_00*/ { SPR_JUNK, 0, 700, { NULL }, S_NULL }, //1267
+/*S_JUNK_01*/ { SPR_JUNK, 1, 700, { NULL }, S_NULL }, //1268
+/*S_JUNK_02*/ { SPR_JUNK, 2, 700, { NULL }, S_NULL }, //1269
+/*S_JUNK_03*/ { SPR_JUNK, 3, 700, { NULL }, S_NULL }, //1270
+/*S_JUNK_04*/ { SPR_JUNK, 4, 700, { NULL }, S_NULL }, //1271
+/*S_JUNK_05*/ { SPR_JUNK, 5, 700, { NULL }, S_NULL }, //1272
+/*S_JUNK_06*/ { SPR_JUNK, 6, 700, { NULL }, S_NULL }, //1273
+/*S_JUNK_07*/ { SPR_JUNK, 7, 700, { NULL }, S_NULL }, //1274
+/*S_JUNK_08*/ { SPR_JUNK, 8, 700, { NULL }, S_NULL }, //1275
+/*S_JUNK_09*/ { SPR_JUNK, 9, 700, { NULL }, S_NULL }, //1276
+/*S_JUNK_10*/ { SPR_JUNK, 10, 700, { NULL }, S_NULL }, //1277
+/*S_JUNK_11*/ { SPR_JUNK, 11, 700, { NULL }, S_NULL }, //1278
+/*S_JUNK_12*/ { SPR_JUNK, 12, 700, { NULL }, S_NULL }, //1279
+/*S_JUNK_13*/ { SPR_JUNK, 13, 700, { NULL }, S_NULL }, //1280
+/*S_JUNK_14*/ { SPR_JUNK, 14, 700, { NULL }, S_NULL }, //1281
+/*S_JUNK_15*/ { SPR_JUNK, 15, 700, { NULL }, S_NULL }, //1282
+/*S_JUNK_16*/ { SPR_JUNK, 16, 700, { NULL }, S_NULL }, //1283
+/*S_JUNK_17*/ { SPR_JUNK, 17, 700, { NULL }, S_NULL }, //1284
+/*S_JUNK_18*/ { SPR_JUNK, 18, 700, { NULL }, S_NULL }, //1285
+/*S_JUNK_19*/ { SPR_JUNK, 19, 700, { NULL }, S_NULL }, //1286
+/*S_FFOT_00*/ { SPR_FFOT, 0, 9, { NULL }, S_FFOT_01 }, //1287
+/*S_FFOT_01*/ { SPR_FFOT, 1, 9, { NULL }, S_FFOT_02 }, //1288
+/*S_FFOT_02*/ { SPR_FFOT, 2, 9, { NULL }, S_FFOT_03 }, //1289
+/*S_FFOT_03*/ { SPR_FFOT, 3, 9, { NULL }, S_NULL }, //1290
+/*S_DIE1_00*/ { SPR_DIE1, 0, -1, { NULL }, S_NULL }, //1291
+/*S_BEAC_00*/ { SPR_BEAC, 0, -1, { NULL }, S_NULL }, //1292
+/*S_BEAC_01*/ { SPR_BEAC, 0, 30, { NULL }, S_BEAC_02 }, //1293
+/*S_BEAC_02*/ { SPR_BEAC, 0, 160, { A_TeleportBeacon }, S_BEAC_01 }, //1294
+/*S_ARM1_00*/ { SPR_ARM1, 0, -1, { NULL }, S_NULL }, //1295
+/*S_ARM2_00*/ { SPR_ARM2, 0, -1, { NULL }, S_NULL }, //1296
+/*S_BARW_00*/ { SPR_BARW, 0, -1, { NULL }, S_NULL }, //1297
+/*S_BARW_01*/ { SPR_BARW, 1, 2, { A_Scream }, S_BARW_02 }, //1298
+/*S_BARW_02*/ { SPR_BARW, 2, 2, { NULL }, S_BARW_03 }, //1299
+/*S_BARW_03*/ { SPR_BARW, 3, 2, { A_Fall }, S_BARW_04 }, //1300
+/*S_BARW_04*/ { SPR_BARW, 4, 2, { NULL }, S_BARW_05 }, //1301
+/*S_BARW_05*/ { SPR_BARW, 5, 2, { NULL }, S_BARW_06 }, //1302
+/*S_BARW_06*/ { SPR_BARW, 6, 2, { NULL }, S_BARW_07 }, //1303
+/*S_BARW_07*/ { SPR_BARW, 7, -1, { NULL }, S_NULL }, //1304
+/*S_BART_00*/ { SPR_BART, 0, -1, { NULL }, S_NULL }, //1305
+/*S_BART_01*/ { SPR_BART, 32769, 2, { A_Scream }, S_BART_02 }, //1306
+/*S_BART_02*/ { SPR_BART, 32770, 2, { NULL }, S_BART_03 }, //1307
+/*S_BART_03*/ { SPR_BART, 32771, 2, { NULL }, S_BART_04 }, //1308
+/*S_BART_04*/ { SPR_BART, 32772, 2, { A_Fall }, S_BART_05 }, //1309
+/*S_BART_05*/ { SPR_BART, 32773, 2, { A_DeathExplode2 }, S_BART_06 }, //1310
+/*S_BART_06*/ { SPR_BART, 32774, 2, { NULL }, S_BART_07 }, //1311
+/*S_BART_07*/ { SPR_BART, 32775, 2, { NULL }, S_BART_08 }, //1312
+/*S_BART_08*/ { SPR_BART, 32776, 2, { NULL }, S_BART_09 }, //1313
+/*S_BART_09*/ { SPR_BART, 32777, 3, { NULL }, S_BART_10 }, //1314
+/*S_BART_10*/ { SPR_BART, 32778, 3, { NULL }, S_BART_11 }, //1315
+/*S_BART_11*/ { SPR_BART, 11, -1, { NULL }, S_NULL }, //1316
+/*S_LAMP_00*/ { SPR_LAMP, 0, -1, { NULL }, S_NULL }, //1317
+/*S_LANT_00*/ { SPR_LANT, 0, -1, { NULL }, S_NULL }, //1318
+/*S_BARL_00*/ { SPR_BARL, 32768, 4, { NULL }, S_BARL_01 }, //1319
+/*S_BARL_01*/ { SPR_BARL, 32769, 4, { NULL }, S_BARL_02 }, //1320
+/*S_BARL_02*/ { SPR_BARL, 32770, 4, { NULL }, S_BARL_03 }, //1321
+/*S_BARL_03*/ { SPR_BARL, 32771, 4, { NULL }, S_BARL_00 }, //1322
+/*S_BOWL_00*/ { SPR_BOWL, 32768, 4, { A_ActiveSound }, S_BOWL_01 }, //1323
+/*S_BOWL_01*/ { SPR_BOWL, 32769, 4, { NULL }, S_BOWL_02 }, //1324
+/*S_BOWL_02*/ { SPR_BOWL, 32770, 4, { NULL }, S_BOWL_03 }, //1325
+/*S_BOWL_03*/ { SPR_BOWL, 32771, 4, { NULL }, S_BOWL_00 }, //1326
+/*S_BRAZ_00*/ { SPR_BRAZ, 32768, 4, { A_ActiveSound }, S_BRAZ_01 }, //1327
+/*S_BRAZ_01*/ { SPR_BRAZ, 32769, 4, { NULL }, S_BRAZ_02 }, //1328
+/*S_BRAZ_02*/ { SPR_BRAZ, 32770, 4, { NULL }, S_BRAZ_03 }, //1329
+/*S_BRAZ_03*/ { SPR_BRAZ, 32771, 4, { NULL }, S_BRAZ_00 }, //1330
+/*S_TRCH_00*/ { SPR_TRCH, 32768, 4, { A_ActiveSound }, S_TRCH_01 }, //1331
+/*S_TRCH_01*/ { SPR_TRCH, 32769, 4, { NULL }, S_TRCH_02 }, //1332
+/*S_TRCH_02*/ { SPR_TRCH, 32770, 4, { NULL }, S_TRCH_03 }, //1333
+/*S_TRCH_03*/ { SPR_TRCH, 32771, 4, { NULL }, S_TRCH_00 }, //1334
+/*S_LTRH_00*/ { SPR_LTRH, 32768, 4, { NULL }, S_LTRH_01 }, //1335
+/*S_LTRH_01*/ { SPR_LTRH, 32769, 4, { NULL }, S_LTRH_02 }, //1336
+/*S_LTRH_02*/ { SPR_LTRH, 32770, 4, { NULL }, S_LTRH_03 }, //1337
+/*S_LTRH_03*/ { SPR_LTRH, 32771, 4, { NULL }, S_LTRH_00 }, //1338
+/*S_LMPC_00*/ { SPR_LMPC, 32768, 4, { A_ActiveSound }, S_LMPC_01 }, //1339
+/*S_LMPC_01*/ { SPR_LMPC, 32769, 4, { NULL }, S_LMPC_02 }, //1340
+/*S_LMPC_02*/ { SPR_LMPC, 32770, 4, { NULL }, S_LMPC_03 }, //1341
+/*S_LMPC_03*/ { SPR_LMPC, 32771, 4, { NULL }, S_LMPC_00 }, //1342
+/*S_LOGS_00*/ { SPR_LOGS, 32768, 4, { A_ActiveSound }, S_LOGS_01 }, //1343
+/*S_LOGS_01*/ { SPR_LOGS, 32769, 4, { NULL }, S_LOGS_02 }, //1344
+/*S_LOGS_02*/ { SPR_LOGS, 32770, 4, { NULL }, S_LOGS_03 }, //1345
+/*S_LOGS_03*/ { SPR_LOGS, 32771, 4, { NULL }, S_LOGS_00 }, //1346
+/*S_TRHO_00*/ { SPR_TRHO, 0, -1, { NULL }, S_NULL }, //1347
+/*S_WATR_00*/ { SPR_WATR, 0, -1, { NULL }, S_NULL }, //1348
+/*S_MUGG_00*/ { SPR_MUGG, 0, -1, { NULL }, S_NULL }, //1349
+/*S_FUSL_00*/ { SPR_FUSL, 0, -1, { NULL }, S_NULL }, //1350
+/*S_CRD1_00*/ { SPR_CRD1, 0, -1, { NULL }, S_NULL }, //1351
+/*S_CRD2_00*/ { SPR_CRD2, 0, -1, { NULL }, S_NULL }, //1352
+/*S_TPAS_00*/ { SPR_TPAS, 0, -1, { NULL }, S_NULL }, //1353
+/*S_KY1G_00*/ { SPR_KY1G, 0, -1, { NULL }, S_NULL }, //1354
+/*S_KY2S_00*/ { SPR_KY2S, 0, -1, { NULL }, S_NULL }, //1355
+/*S_KY3B_00*/ { SPR_KY3B, 0, -1, { NULL }, S_NULL }, //1356
+/*S_HAND_00*/ { SPR_HAND, 0, -1, { NULL }, S_NULL }, //1357
+/*S_CRYS_00*/ { SPR_CRYS, 0, 16, { A_ActiveSound }, S_CRYS_01 }, //1358
+/*S_CRYS_01*/ { SPR_CRYS, 1, 5, { A_ActiveSound }, S_CRYS_02 }, //1359
+/*S_CRYS_02*/ { SPR_CRYS, 2, 4, { A_ActiveSound }, S_CRYS_03 }, //1360
+/*S_CRYS_03*/ { SPR_CRYS, 3, 4, { A_ActiveSound }, S_CRYS_04 }, //1361
+/*S_CRYS_04*/ { SPR_CRYS, 4, 4, { A_ActiveSound }, S_CRYS_05 }, //1362
+/*S_CRYS_05*/ { SPR_CRYS, 5, 4, { A_ActiveSound }, S_CRYS_00 }, //1363
+/*S_PRIS_00*/ { SPR_PRIS, 0, -1, { NULL }, S_NULL }, //1364
+/*S_PWR1_00*/ { SPR_PWR1, 0, -1, { NULL }, S_NULL }, //1365
+/*S_PWR2_00*/ { SPR_PWR2, 0, -1, { NULL }, S_NULL }, //1366
+/*S_PWR3_00*/ { SPR_PWR3, 0, -1, { NULL }, S_NULL }, //1367
+/*S_ORAC_00*/ { SPR_ORAC, 0, -1, { NULL }, S_NULL }, //1368
+/*S_GYID_00*/ { SPR_GYID, 0, -1, { NULL }, S_NULL }, //1369
+/*S_FUBR_00*/ { SPR_FUBR, 0, -1, { NULL }, S_NULL }, //1370
+/*S_WARE_00*/ { SPR_WARE, 0, -1, { NULL }, S_NULL }, //1371
+/*S_RCRY_00*/ { SPR_RCRY, 32768, -1, { NULL }, S_NULL }, //1372
+/*S_BCRY_00*/ { SPR_BCRY, 32768, -1, { NULL }, S_NULL }, //1373
+/*S_CHAP_00*/ { SPR_CHAP, 0, -1, { NULL }, S_NULL }, //1374
+/*S_TUNL_00*/ { SPR_TUNL, 0, -1, { NULL }, S_NULL }, //1375
+/*S_BLTK_00*/ { SPR_BLTK, 0, -1, { NULL }, S_NULL }, //1376
+/*S_SECK_00*/ { SPR_SECK, 0, -1, { NULL }, S_NULL }, //1377
+/*S_MINE_00*/ { SPR_MINE, 0, -1, { NULL }, S_NULL }, //1378
+/*S_REBL_00*/ { SPR_REBL, 0, -1, { NULL }, S_NULL }, //1379
+/*S_PROC_00*/ { SPR_PROC, 0, -1, { NULL }, S_NULL }, //1380
+/*S_ANKH_00*/ { SPR_ANKH, 0, -1, { NULL }, S_NULL }, //1381
+/*S_GOID_00*/ { SPR_GOID, 0, -1, { NULL }, S_NULL }, //1382
+/*S_STMP_00*/ { SPR_STMP, 0, -1, { NULL }, S_NULL }, //1383
+/*S_MDKT_00*/ { SPR_MDKT, 0, -1, { NULL }, S_NULL }, //1384
+/*S_COIN_00*/ { SPR_COIN, 0, -1, { NULL }, S_NULL }, //1385
+/*S_CRED_00*/ { SPR_CRED, 0, -1, { NULL }, S_NULL }, //1386
+/*S_SACK_00*/ { SPR_SACK, 0, -1, { NULL }, S_NULL }, //1387
+/*S_CHST_00*/ { SPR_CHST, 0, -1, { NULL }, S_NULL }, //1388
+/*S_SHD1_00*/ { SPR_SHD1, 0, 17, { A_ShadowOff }, S_SHD1_01 }, //1389
+/*S_SHD1_01*/ { SPR_SHD1, 0, 17, { A_ModifyVisibility }, S_SHD1_02 }, //1390
+/*S_SHD1_02*/ { SPR_SHD1, 0, 17, { A_ShadowOn }, S_SHD1_03 }, //1391
+/*S_SHD1_03*/ { SPR_SHD1, 0, 17, { A_ModifyVisibility }, S_SHD1_00 }, //1392
+/*S_MASK_00*/ { SPR_MASK, 0, -1, { NULL }, S_NULL }, //1393
+/*S_UNIF_00*/ { SPR_UNIF, 0, -1, { NULL }, S_NULL }, //1394
+/*S_OFIC_00*/ { SPR_OFIC, 0, -1, { NULL }, S_NULL }, //1395
+/*S_PMAP_00*/ { SPR_PMAP, 32768, 6, { NULL }, S_PMAP_01 }, //1396
+/*S_PMAP_01*/ { SPR_PMAP, 32769, 6, { NULL }, S_PMAP_00 }, //1397
+/*S_PMUP_00*/ { SPR_PMUP, 32768, 6, { NULL }, S_PMUP_01 }, //1398
+/*S_PMUP_01*/ { SPR_PMUP, 32769, 6, { NULL }, S_PMUP_00 }, //1399
+/*S_BLIT_00*/ { SPR_BLIT, 0, -1, { NULL }, S_NULL }, //1400
+/*S_BBOX_00*/ { SPR_BBOX, 0, -1, { NULL }, S_NULL }, //1401
+/*S_MSSL_00*/ { SPR_MSSL, 0, -1, { NULL }, S_NULL }, //1402
+/*S_ROKT_00*/ { SPR_ROKT, 0, -1, { NULL }, S_NULL }, //1403
+/*S_BRY1_00*/ { SPR_BRY1, 0, 6, { NULL }, S_BRY1_01 }, //1404
+/*S_BRY1_01*/ { SPR_BRY1, 1, 6, { NULL }, S_BRY1_00 }, //1405
+/*S_CPAC_00*/ { SPR_CPAC, 0, 6, { NULL }, S_CPAC_01 }, //1406
+/*S_CPAC_01*/ { SPR_CPAC, 1, 6, { NULL }, S_CPAC_00 }, //1407
+/*S_PQRL_00*/ { SPR_PQRL, 0, -1, { NULL }, S_NULL }, //1408
+/*S_XQRL_00*/ { SPR_XQRL, 0, -1, { NULL }, S_NULL }, //1409
+/*S_GRN1_00*/ { SPR_GRN1, 0, -1, { NULL }, S_NULL }, //1410
+/*S_GRN2_00*/ { SPR_GRN2, 0, -1, { NULL }, S_NULL }, //1411
+/*S_BKPK_00*/ { SPR_BKPK, 0, -1, { NULL }, S_NULL }, //1412
+/*S_RELC_00*/ { SPR_RELC, 32768, -1, { NULL }, S_NULL }, //1413
+/*S_RIFL_00*/ { SPR_RIFL, 0, -1, { NULL }, S_NULL }, //1414
+/*S_RIFL_01*/ { SPR_RIFL, 1, -1, { NULL }, S_NULL }, //1415
+/*S_FLAM_00*/ { SPR_FLAM, 0, -1, { NULL }, S_NULL }, //1416
+/*S_BFLM_00*/ { SPR_BFLM, 0, -1, { NULL }, S_NULL }, //1417
+/*S_MMSL_00*/ { SPR_MMSL, 0, -1, { NULL }, S_NULL }, //1418
+/*S_TRPD_00*/ { SPR_TRPD, 0, -1, { NULL }, S_NULL }, //1419
+/*S_GRND_00*/ { SPR_GRND, 0, -1, { NULL }, S_NULL }, //1420
+/*S_CBOW_00*/ { SPR_CBOW, 0, -1, { NULL }, S_NULL }, //1421
+/*S_SIGL_00*/ { SPR_SIGL, 0, -1, { NULL }, S_NULL }, //1422
+/*S_SIGL_01*/ { SPR_SIGL, 1, -1, { NULL }, S_NULL }, //1423
+/*S_SIGL_02*/ { SPR_SIGL, 2, -1, { NULL }, S_NULL }, //1424
+/*S_SIGL_03*/ { SPR_SIGL, 3, -1, { NULL }, S_NULL }, //1425
+/*S_SIGL_04*/ { SPR_SIGL, 4, -1, { NULL }, S_NULL }, //1426
+/*S_LITE_00*/ { SPR_LITE, 32768, -1, { NULL }, S_NULL }, //1427
+/*S_CNDL_00*/ { SPR_CNDL, 32768, -1, { NULL }, S_NULL }, //1428
+/*S_CLBR_00*/ { SPR_CLBR, 32768, -1, { NULL }, S_NULL }, //1429
+/*S_LITS_00*/ { SPR_LITS, 32768, -1, { NULL }, S_NULL }, //1430
+/*S_LITB_00*/ { SPR_LITB, 32768, -1, { NULL }, S_NULL }, //1431
+/*S_LITG_00*/ { SPR_LITG, 32768, -1, { NULL }, S_NULL }, //1432
+/*S_ROK1_00*/ { SPR_ROK1, 0, -1, { NULL }, S_NULL }, //1433
+/*S_ROK2_00*/ { SPR_ROK2, 0, -1, { NULL }, S_NULL }, //1434
+/*S_ROK3_00*/ { SPR_ROK3, 0, -1, { NULL }, S_NULL }, //1435
+/*S_ROK4_00*/ { SPR_ROK4, 0, -1, { NULL }, S_NULL }, //1436
+/*S_LOGG_00*/ { SPR_LOGG, 0, 5, { A_ActiveSound }, S_LOGG_01 }, //1437
+/*S_LOGG_01*/ { SPR_LOGG, 1, 5, { A_ActiveSound }, S_LOGG_02 }, //1438
+/*S_LOGG_02*/ { SPR_LOGG, 2, 5, { A_ActiveSound }, S_LOGG_03 }, //1439
+/*S_LOGG_03*/ { SPR_LOGG, 3, 5, { A_ActiveSound }, S_LOGG_00 }, //1440
+/*S_RUB1_00*/ { SPR_RUB1, 0, -1, { NULL }, S_NULL }, //1441
+/*S_RUB2_00*/ { SPR_RUB2, 0, -1, { NULL }, S_NULL }, //1442
+/*S_RUB3_00*/ { SPR_RUB3, 0, -1, { NULL }, S_NULL }, //1443
+/*S_RUB4_00*/ { SPR_RUB4, 0, -1, { NULL }, S_NULL }, //1444
+/*S_RUB5_00*/ { SPR_RUB5, 0, -1, { NULL }, S_NULL }, //1445
+/*S_RUB6_00*/ { SPR_RUB6, 0, -1, { NULL }, S_NULL }, //1446
+/*S_RUB7_00*/ { SPR_RUB7, 0, -1, { NULL }, S_NULL }, //1447
+/*S_RUB8_00*/ { SPR_RUB8, 0, -1, { NULL }, S_NULL }, //1448
+/*S_CHAN_00*/ { SPR_CHAN, 0, -1, { NULL }, S_NULL }, //1449
+/*S_STAT_00*/ { SPR_STAT, 0, -1, { NULL }, S_NULL }, //1450
+/*S_DSTA_00*/ { SPR_DSTA, 0, -1, { NULL }, S_NULL }, //1451
+/*S_CRAB_00*/ { SPR_CRAB, 0, -1, { NULL }, S_NULL }, //1452
+/*S_CAGE_00*/ { SPR_CAGE, 0, -1, { NULL }, S_NULL }, //1453
+/*S_TREE_00*/ { SPR_TREE, 0, -1, { NULL }, S_NULL }, //1454
+/*S_TREE_01*/ { SPR_TREE, 1, -1, { NULL }, S_NULL }, //1455
+/*S_TREE_02*/ { SPR_TREE, 2, -1, { NULL }, S_NULL }, //1456
+/*S_TRE1_00*/ { SPR_TRE1, 0, -1, { NULL }, S_NULL }, //1457
+/*S_BUSH_00*/ { SPR_BUSH, 0, -1, { NULL }, S_NULL }, //1458
+/*S_SHRB_00*/ { SPR_SHRB, 0, -1, { NULL }, S_NULL }, //1459
+/*S_STAK_00*/ { SPR_STAK, 0, -1, { NULL }, S_NULL }, //1460
+/*S_BAR1_00*/ { SPR_BAR1, 0, -1, { NULL }, S_NULL }, //1461
+/*S_VASE_00*/ { SPR_VASE, 0, -1, { NULL }, S_NULL }, //1462
+/*S_VASE_01*/ { SPR_VASE, 1, -1, { NULL }, S_NULL }, //1463
+/*S_STOL_00*/ { SPR_STOL, 0, -1, { NULL }, S_NULL }, //1464
+/*S_POT1_00*/ { SPR_POT1, 0, -1, { NULL }, S_NULL }, //1465
+/*S_TUB1_00*/ { SPR_TUB1, 0, -1, { NULL }, S_NULL }, //1466
+/*S_ANVL_00*/ { SPR_ANVL, 0, -1, { NULL }, S_NULL }, //1467
+/*S_TLMP_00*/ { SPR_TLMP, 0, -1, { NULL }, S_NULL }, //1468
+/*S_TLMP_01*/ { SPR_TLMP, 1, -1, { NULL }, S_NULL }, //1469
+/*S_TRAY_00*/ { SPR_TRAY, 0, -1, { NULL }, S_NULL }, //1470
+/*S_APOW_00*/ { SPR_APOW, 0, 4, { A_ActiveSound }, S_APOW_00 }, //1471
+/*S_AFED_00*/ { SPR_AFED, 0, -1, { NULL }, S_NULL }, //1472
+/*S_DRIP_00*/ { SPR_DRIP, 0, 6, { A_ActiveSound }, S_DRIP_01 }, //1473
+/*S_DRIP_01*/ { SPR_DRIP, 1, 4, { NULL }, S_DRIP_02 }, //1474
+/*S_DRIP_02*/ { SPR_DRIP, 2, 4, { NULL }, S_DRIP_03 }, //1475
+/*S_DRIP_03*/ { SPR_DRIP, 3, 4, { A_ActiveSound }, S_DRIP_04 }, //1476
+/*S_DRIP_04*/ { SPR_DRIP, 4, 4, { NULL }, S_DRIP_05 }, //1477
+/*S_DRIP_05*/ { SPR_DRIP, 5, 4, { NULL }, S_DRIP_06 }, //1478
+/*S_DRIP_06*/ { SPR_DRIP, 6, 4, { A_ActiveSound }, S_DRIP_07 }, //1479
+/*S_DRIP_07*/ { SPR_DRIP, 7, 4, { NULL }, S_DRIP_00 }, //1480
+/*S_CDRP_00*/ { SPR_CDRP, 0, 10, { NULL }, S_CDRP_01 }, //1481
+/*S_CDRP_01*/ { SPR_CDRP, 1, 8, { NULL }, S_CDRP_02 }, //1482
+/*S_CDRP_02*/ { SPR_CDRP, 2, 8, { NULL }, S_CDRP_03 }, //1483
+/*S_CDRP_03*/ { SPR_CDRP, 3, 8, { NULL }, S_CDRP_00 }, //1484
+/*S_SPLH_00*/ { SPR_SPLH, 0, 4, { NULL }, S_SPLH_01 }, //1485
+/*S_SPLH_01*/ { SPR_SPLH, 1, 4, { NULL }, S_SPLH_02 }, //1486
+/*S_SPLH_02*/ { SPR_SPLH, 2, 4, { NULL }, S_SPLH_03 }, //1487
+/*S_SPLH_03*/ { SPR_SPLH, 3, 8, { NULL }, S_SPLH_04 }, //1488
+/*S_SPLH_04*/ { SPR_SPLH, 4, 4, { NULL }, S_SPLH_05 }, //1489
+/*S_SPLH_05*/ { SPR_SPLH, 5, 4, { NULL }, S_SPLH_06 }, //1490
+/*S_SPLH_06*/ { SPR_SPLH, 6, 4, { NULL }, S_SPLH_07 }, //1491
+/*S_SPLH_07*/ { SPR_SPLH, 7, 4, { A_ActiveSound }, S_SPLH_00 }, //1492
+/*S_WTFT_00*/ { SPR_WTFT, 0, 4, { NULL }, S_WTFT_01 }, //1493
+/*S_WTFT_01*/ { SPR_WTFT, 1, 4, { NULL }, S_WTFT_02 }, //1494
+/*S_WTFT_02*/ { SPR_WTFT, 2, 4, { NULL }, S_WTFT_03 }, //1495
+/*S_WTFT_03*/ { SPR_WTFT, 3, 4, { A_ActiveSound }, S_WTFT_00 }, //1496
+/*S_HERT_00*/ { SPR_HERT, 32768, 4, { NULL }, S_HERT_01 }, //1497
+/*S_HERT_01*/ { SPR_HERT, 32769, 4, { NULL }, S_HERT_02 }, //1498
+/*S_HERT_02*/ { SPR_HERT, 32770, 4, { NULL }, S_HERT_00 }, //1499
+/*S_TELP_00*/ { SPR_TELP, 32768, 3, { NULL }, S_TELP_01 }, //1500
+/*S_TELP_01*/ { SPR_TELP, 32769, 3, { NULL }, S_TELP_02 }, //1501
+/*S_TELP_02*/ { SPR_TELP, 32770, 3, { NULL }, S_TELP_03 }, //1502
+/*S_TELP_03*/ { SPR_TELP, 32771, 3, { NULL }, S_TELP_00 }, //1503
+/*S_MONI_00*/ { SPR_MONI, 0, -1, { NULL }, S_NULL }, //1504
+/*S_STEL_00*/ { SPR_STEL, 0, -1, { NULL }, S_NULL }, //1505
+/*S_STLA_00*/ { SPR_STLA, 0, -1, { NULL }, S_NULL }, //1506
+/*S_STLE_00*/ { SPR_STLE, 0, -1, { NULL }, S_NULL }, //1507
+/*S_HUGE_00*/ { SPR_HUGE, 0, 4, { NULL }, S_HUGE_01 }, //1508
+/*S_HUGE_01*/ { SPR_HUGE, 1, 5, { NULL }, S_HUGE_02 }, //1509
+/*S_HUGE_02*/ { SPR_HUGE, 2, 5, { NULL }, S_HUGE_03 }, //1510
+/*S_HUGE_03*/ { SPR_HUGE, 3, 5, { NULL }, S_HUGE_00 }, //1511
+/*S_STLG_00*/ { SPR_STLG, 0, -1, { NULL }, S_NULL }, //1512
+/*S_STLG_01*/ { SPR_STLG, 1, -1, { NULL }, S_NULL }, //1513
+/*S_STLG_02*/ { SPR_STLG, 2, -1, { NULL }, S_NULL }, //1514
+/*S_STLG_03*/ { SPR_STLG, 3, -1, { NULL }, S_NULL }, //1515
+/*S_STLG_04*/ { SPR_STLG, 4, -1, { NULL }, S_NULL }, //1516
+/*S_STLG_05*/ { SPR_STLG, 5, -1, { NULL }, S_NULL }, //1517
+};
+
+
+// villsa [STRIFE]
+mobjinfo_t mobjinfo[NUMMOBJTYPES] =
+{
+ { /*MT_FIELDGUARD*/
+ 25, //doomednum
+ S_TOKN_00, //spawnstate
+ 10, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_XPRK_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 2*FRACUNIT, //radius
+ 1*FRACUNIT, //height
+ 10000, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SHOOTABLE|MF_NOSECTOR|MF_NODIALOG, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PLAYER*/
+ -1, //doomednum
+ S_PLAY_00, //spawnstate
+ 100, //spawnhealth
+ S_PLAY_01, //seestate
+ sfx_None, //seesound
+ 0, //reactiontime
+ sfx_None, //attacksound
+ S_PLAY_07, //painstate
+ 255, //painchance
+ sfx_plpain, //painsound
+ S_NULL, //meleestate
+ S_PLAY_05, //missilestate
+ S_NULL, //crashstate
+ S_PLAY_09, //deathstate
+ S_RGIB_00, //xdeathstate
+ sfx_pldeth, //deathsound
+ 0, //speed
+ 18*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_NOTDMATCH|MF_ALLY, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SHOPKEEPER_W*/
+ 116, //doomednum
+ S_MRST_00, //spawnstate
+ 10000000, //spawnhealth
+ S_MRPN_00, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_MRPN_00, //painstate
+ 150, //painchance
+ sfx_pespna, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 5000, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NOTDMATCH, //flags
+ "Weapon_Smith", //namepointer
+ },
+
+ { /*MT_SHOPKEEPER_B*/
+ 72, //doomednum
+ S_MRST_00, //spawnstate
+ 10000000, //spawnhealth
+ S_MRPN_00, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_MRPN_00, //painstate
+ 150, //painchance
+ sfx_ambbar, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 5000, //mass
+ 0, //damage
+ sfx_ambppl, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NOTDMATCH|MF_COLORSWAP1|MF_COLORSWAP3, //flags
+ "Bar_Keep", //namepointer
+ },
+
+ { /*MT_SHOPKEEPER_A*/
+ 73, //doomednum
+ S_MRST_00, //spawnstate
+ 10000000, //spawnhealth
+ S_MRPN_00, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_MRPN_00, //painstate
+ 150, //painchance
+ sfx_pespna, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 5000, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NOTDMATCH|MF_COLORSWAP2|MF_COLORSWAP3, //flags
+ "Armorer", //namepointer
+ },
+
+ { /*MT_SHOPKEEPER_M*/
+ 74, //doomednum
+ S_MRST_00, //spawnstate
+ 10000000, //spawnhealth
+ S_MRPN_00, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_MRPN_00, //painstate
+ 150, //painchance
+ sfx_pespna, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 50000, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NOTDMATCH|MF_COLORSWAP1|MF_COLORSWAP2
+ |MF_COLORSWAP3, //flags
+ "Medic", //namepointer
+ },
+
+ { /*MT_PEASANT2_A*/
+ 3004, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 4, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT2_B*/
+ 130, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 5, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT2_C*/
+ 131, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 5, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT5_A*/
+ 65, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 7, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT5_B*/
+ 132, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 7, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT5_C*/
+ 133, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 7, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT4_A*/
+ 66, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1
+ |MF_COLORSWAP2, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT4_B*/
+ 134, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1
+ |MF_COLORSWAP2, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT4_C*/
+ 135, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1
+ |MF_COLORSWAP2, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT6_A*/
+ 67, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP2, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT6_B*/
+ 136, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 7, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP2, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT6_C*/
+ 137, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP2, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT3_A*/
+ 172, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP3, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT3_B*/
+ 173, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP3, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT3_C*/
+ 174, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP3, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT8_A*/
+ 175, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP2
+ |MF_COLORSWAP3, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT8_B*/
+ 176, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP2
+ |MF_COLORSWAP3, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT8_C*/
+ 177, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP2
+ |MF_COLORSWAP3, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT7_A*/
+ 178, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1
+ |MF_COLORSWAP3, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT7_B*/
+ 179, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1
+ |MF_COLORSWAP3, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT7_C*/
+ 180, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1
+ |MF_COLORSWAP3, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT1*/
+ 181, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1
+ |MF_COLORSWAP2|MF_COLORSWAP3, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_ZOMBIE*/
+ 169, //doomednum
+ S_PEAS_25, //spawnstate
+ 31, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_AGRD_00, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_GIBS_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_psdtha, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_COLORSWAP1, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_BECOMING*/
+ 201, //doomednum
+ S_ARMR_00, //spawnstate
+ 61, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_ARMR_01, //painstate
+ 255, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_GIBS_10, //deathstate
+ S_NULL, //xdeathstate
+ sfx_psdtha, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_ZOMBIESPAWNER*/
+ 170, //doomednum
+ S_PLAY_19, //spawnstate
+ 20, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_telept, //activesound
+ MF_SHOOTABLE|MF_NOSECTOR, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_HUGE_TANK_1*/
+ 209, //doomednum
+ S_TNK1_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 192*FRACUNIT, //height
+ 50000, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_HUGE_TANK_2*/
+ 210, //doomednum
+ S_TNK2_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 192*FRACUNIT, //height
+ 50000, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_HUGE_TANK_3*/
+ 211, //doomednum
+ S_TNK3_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 192*FRACUNIT, //height
+ 50000, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TANK_4*/
+ 213, //doomednum
+ S_TNK4_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 50000, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TANK_5*/
+ 214, //doomednum
+ S_TNK5_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 50000, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TANK_6*/
+ 229, //doomednum
+ S_TNK6_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 50000, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_KNEELING_GUY*/
+ 204, //doomednum
+ S_NEAL_00, //spawnstate
+ 51, //spawnhealth
+ S_NEAL_00, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NEAL_02, //painstate
+ 255, //painchance
+ sfx_static, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NEAL_05, //crashstate
+ S_NEAL_07, //deathstate
+ S_NULL, //xdeathstate
+ sfx_static, //deathsound
+ 0, //speed
+ 6*FRACUNIT, //radius
+ 6*FRACUNIT, //height
+ 50000, //mass
+ 0, //damage
+ sfx_chant, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NODIALOG|MF_NOBLOOD|MF_COUNTKILL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_BEGGAR1*/
+ 141, //doomednum
+ S_BEGR_00, //spawnstate
+ 20, //spawnhealth
+ S_BEGR_01, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_BEGR_11, //painstate
+ 250, //painchance
+ sfx_pespna, //painsound
+ S_BEGR_07, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_BEGR_13, //deathstate
+ S_BEGR_22, //xdeathstate
+ sfx_psdtha, //deathsound
+ 3, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL, //flags
+ "Beggar", //namepointer
+ },
+
+ { /*MT_BEGGAR2*/
+ 155, //doomednum
+ S_BEGR_00, //spawnstate
+ 20, //spawnhealth
+ S_BEGR_01, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_BEGR_11, //painstate
+ 250, //painchance
+ sfx_pespna, //painsound
+ S_BEGR_07, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_BEGR_13, //deathstate
+ S_BEGR_22, //xdeathstate
+ sfx_psdtha, //deathsound
+ 3, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL, //flags
+ "Beggar", //namepointer
+ },
+
+ { /*MT_BEGGAR3*/
+ 156, //doomednum
+ S_BEGR_00, //spawnstate
+ 20, //spawnhealth
+ S_BEGR_01, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_BEGR_11, //painstate
+ 250, //painchance
+ sfx_pespna, //painsound
+ S_BEGR_07, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_BEGR_13, //deathstate
+ S_BEGR_22, //xdeathstate
+ sfx_psdtha, //deathsound
+ 3, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL, //flags
+ "Beggar", //namepointer
+ },
+
+ { /*MT_BEGGAR4*/
+ 157, //doomednum
+ S_BEGR_00, //spawnstate
+ 20, //spawnhealth
+ S_BEGR_01, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_BEGR_11, //painstate
+ 250, //painchance
+ sfx_pespna, //painsound
+ S_BEGR_07, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_BEGR_13, //deathstate
+ S_BEGR_22, //xdeathstate
+ sfx_psdtha, //deathsound
+ 3, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL, //flags
+ "Beggar", //namepointer
+ },
+
+ { /*MT_BEGGAR5*/
+ 158, //doomednum
+ S_BEGR_00, //spawnstate
+ 20, //spawnhealth
+ S_BEGR_01, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_BEGR_11, //painstate
+ 250, //painchance
+ sfx_pespna, //painsound
+ S_BEGR_07, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_BEGR_13, //deathstate
+ S_BEGR_22, //xdeathstate
+ sfx_psdtha, //deathsound
+ 3, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL, //flags
+ "Beggar", //namepointer
+ },
+
+ { /*MT_REBEL1*/
+ 9, //doomednum
+ S_HMN1_00, //spawnstate
+ 60, //spawnhealth
+ S_HMN1_11, //seestate
+ sfx_wpnup, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_HMN1_22, //painstate
+ 250, //painchance
+ sfx_pespna, //painsound
+ S_NULL, //meleestate
+ S_HMN1_19, //missilestate
+ S_NULL, //crashstate
+ S_HMN1_24, //deathstate
+ S_RGIB_08, //xdeathstate
+ sfx_rebdth, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_ALLY, //flags
+ "Rebel", //namepointer
+ },
+
+ { /*MT_REBEL2*/
+ 144, //doomednum
+ S_HMN1_00, //spawnstate
+ 60, //spawnhealth
+ S_HMN1_11, //seestate
+ sfx_wpnup, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_HMN1_22, //painstate
+ 250, //painchance
+ sfx_pespna, //painsound
+ S_NULL, //meleestate
+ S_HMN1_19, //missilestate
+ S_NULL, //crashstate
+ S_HMN1_24, //deathstate
+ S_RGIB_08, //xdeathstate
+ sfx_rebdth, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_ALLY, //flags
+ "Rebel", //namepointer
+ },
+
+ { /*MT_REBEL3*/
+ 145, //doomednum
+ S_HMN1_00, //spawnstate
+ 60, //spawnhealth
+ S_HMN1_11, //seestate
+ sfx_wpnup, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_HMN1_22, //painstate
+ 250, //painchance
+ sfx_pespna, //painsound
+ S_NULL, //meleestate
+ S_HMN1_19, //missilestate
+ S_NULL, //crashstate
+ S_HMN1_24, //deathstate
+ S_RGIB_08, //xdeathstate
+ sfx_rebdth, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_ALLY, //flags
+ "Rebel", //namepointer
+ },
+
+ { /*MT_REBEL4*/
+ 149, //doomednum
+ S_HMN1_00, //spawnstate
+ 60, //spawnhealth
+ S_HMN1_11, //seestate
+ sfx_wpnup, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_HMN1_22, //painstate
+ 250, //painchance
+ sfx_pespna, //painsound
+ S_NULL, //meleestate
+ S_HMN1_19, //missilestate
+ S_NULL, //crashstate
+ S_HMN1_24, //deathstate
+ S_RGIB_08, //xdeathstate
+ sfx_rebdth, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_ALLY, //flags
+ "Rebel", //namepointer
+ },
+
+ { /*MT_REBEL5*/
+ 150, //doomednum
+ S_HMN1_00, //spawnstate
+ 60, //spawnhealth
+ S_HMN1_11, //seestate
+ sfx_wpnup, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_HMN1_22, //painstate
+ 250, //painchance
+ sfx_pespna, //painsound
+ S_NULL, //meleestate
+ S_HMN1_19, //missilestate
+ S_NULL, //crashstate
+ S_HMN1_24, //deathstate
+ S_RGIB_08, //xdeathstate
+ sfx_rebdth, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_ALLY, //flags
+ "Rebel", //namepointer
+ },
+
+ { /*MT_REBEL6*/
+ 151, //doomednum
+ S_HMN1_00, //spawnstate
+ 60, //spawnhealth
+ S_HMN1_11, //seestate
+ sfx_wpnup, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_HMN1_22, //painstate
+ 250, //painchance
+ sfx_pespna, //painsound
+ S_NULL, //meleestate
+ S_HMN1_19, //missilestate
+ S_NULL, //crashstate
+ S_HMN1_24, //deathstate
+ S_RGIB_08, //xdeathstate
+ sfx_rebdth, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_ALLY, //flags
+ "Rebel", //namepointer
+ },
+
+ { /*MT_RLEADER*/
+ 64, //doomednum
+ S_LEDR_00, //spawnstate
+ 95, //spawnhealth
+ S_LEAD_04, //seestate
+ sfx_agrsee, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_LEAD_15, //painstate
+ 250, //painchance
+ sfx_pespna, //painsound
+ S_NULL, //meleestate
+ S_LEAD_12, //missilestate
+ S_NULL, //crashstate
+ S_LEAD_04, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_NOTDMATCH, //flags
+ "MACIL", //namepointer
+ },
+
+ { /*MT_RLEADER2*/
+ 200, //doomednum
+ S_LEDR_00, //spawnstate
+ 95, //spawnhealth
+ S_LEAD_04, //seestate
+ sfx_agrsee, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_LEAD_15, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_NULL, //meleestate
+ S_LEAD_17, //missilestate
+ S_NULL, //crashstate
+ S_LEAD_20, //deathstate
+ S_LEAD_20, //xdeathstate
+ sfx_slop, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_NOTDMATCH|MF_SPECTRAL, //flags
+ "MACIL", //namepointer
+ },
+
+ { /*MT_MISSILESMOKE*/
+ -1, //doomednum
+ S_PUFY_04, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_rflite, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_REAVER*/
+ 3001, //doomednum
+ S_ROB1_00, //spawnstate
+ 150, //spawnhealth
+ S_ROB1_02, //seestate
+ sfx_revsee, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_ROB1_15, //painstate
+ 128, //painchance
+ sfx_reavpn, //painsound
+ S_ROB1_10, //meleestate
+ S_ROB1_13, //missilestate
+ S_NULL, //crashstate
+ S_ROB1_17, //deathstate
+ S_ROB1_26, //xdeathstate
+ sfx_revdth, //deathsound
+ 12, //speed
+ 20*FRACUNIT, //radius
+ 60*FRACUNIT, //height
+ 500, //mass
+ 0, //damage
+ sfx_revact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NODIALOG|MF_NOBLOOD|MF_COUNTKILL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_GUARD1*/
+ 3002, //doomednum
+ S_AGRD_01, //spawnstate
+ 70, //spawnhealth
+ S_AGRD_13, //seestate
+ sfx_agrsee, //seesound
+ 8, //reactiontime
+ sfx_rifle, //attacksound
+ S_AGRD_23, //painstate
+ 150, //painchance
+ sfx_agrdpn, //painsound
+ S_NULL, //meleestate
+ S_AGRD_17, //missilestate
+ S_NULL, //crashstate
+ S_AGRD_24, //deathstate
+ S_GIBS_10, //xdeathstate
+ sfx_agrdth, //deathsound
+ 7, //speed
+ 24*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 400, //mass
+ 0, //damage
+ sfx_agrac1, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, //flags
+ "ACOLYTE", //namepointer
+ },
+
+ { /*MT_GUARD2*/
+ 142, //doomednum
+ S_AGRD_01, //spawnstate
+ 70, //spawnhealth
+ S_AGRD_13, //seestate
+ sfx_agrsee, //seesound
+ 8, //reactiontime
+ sfx_rifle, //attacksound
+ S_AGRD_23, //painstate
+ 150, //painchance
+ sfx_agrdpn, //painsound
+ S_NULL, //meleestate
+ S_AGRD_17, //missilestate
+ S_NULL, //crashstate
+ S_AGRD_24, //deathstate
+ S_GIBS_10, //xdeathstate
+ sfx_agrdth, //deathsound
+ 7, //speed
+ 24*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 400, //mass
+ 0, //damage
+ sfx_agrac2, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_COLORSWAP1, //flags
+ "ACOLYTE", //namepointer
+ },
+
+ { /*MT_GUARD3*/
+ 143, //doomednum
+ S_AGRD_01, //spawnstate
+ 70, //spawnhealth
+ S_AGRD_13, //seestate
+ sfx_agrsee, //seesound
+ 8, //reactiontime
+ sfx_rifle, //attacksound
+ S_AGRD_23, //painstate
+ 150, //painchance
+ sfx_agrdpn, //painsound
+ S_NULL, //meleestate
+ S_AGRD_17, //missilestate
+ S_NULL, //crashstate
+ S_AGRD_24, //deathstate
+ S_GIBS_10, //xdeathstate
+ sfx_agrdth, //deathsound
+ 7, //speed
+ 24*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 400, //mass
+ 0, //damage
+ sfx_agrac3, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_COLORSWAP2, //flags
+ "ACOLYTE", //namepointer
+ },
+
+ { /*MT_GUARD4*/
+ 146, //doomednum
+ S_AGRD_01, //spawnstate
+ 70, //spawnhealth
+ S_AGRD_13, //seestate
+ sfx_agrsee, //seesound
+ 8, //reactiontime
+ sfx_rifle, //attacksound
+ S_AGRD_23, //painstate
+ 150, //painchance
+ sfx_agrdpn, //painsound
+ S_NULL, //meleestate
+ S_AGRD_17, //missilestate
+ S_NULL, //crashstate
+ S_AGRD_24, //deathstate
+ S_GIBS_10, //xdeathstate
+ sfx_agrdth, //deathsound
+ 7, //speed
+ 24*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 400, //mass
+ 0, //damage
+ sfx_agrac1, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_COLORSWAP1|MF_COLORSWAP2, //flags
+ "ACOLYTE", //namepointer
+ },
+
+ { /*MT_GUARD5*/
+ 147, //doomednum
+ S_AGRD_01, //spawnstate
+ 70, //spawnhealth
+ S_AGRD_13, //seestate
+ sfx_agrsee, //seesound
+ 8, //reactiontime
+ sfx_rifle, //attacksound
+ S_AGRD_23, //painstate
+ 150, //painchance
+ sfx_agrdpn, //painsound
+ S_NULL, //meleestate
+ S_AGRD_17, //missilestate
+ S_NULL, //crashstate
+ S_AGRD_24, //deathstate
+ S_GIBS_10, //xdeathstate
+ sfx_agrdth, //deathsound
+ 7, //speed
+ 24*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 400, //mass
+ 0, //damage
+ sfx_agrac2, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_COLORSWAP3, //flags
+ "ACOLYTE", //namepointer
+ },
+
+ { /*MT_GUARD6*/
+ 148, //doomednum
+ S_AGRD_01, //spawnstate
+ 70, //spawnhealth
+ S_AGRD_13, //seestate
+ sfx_agrsee, //seesound
+ 8, //reactiontime
+ sfx_rifle, //attacksound
+ S_AGRD_23, //painstate
+ 150, //painchance
+ sfx_agrdpn, //painsound
+ S_NULL, //meleestate
+ S_AGRD_17, //missilestate
+ S_NULL, //crashstate
+ S_AGRD_24, //deathstate
+ S_GIBS_10, //xdeathstate
+ sfx_agrdth, //deathsound
+ 7, //speed
+ 24*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 400, //mass
+ 0, //damage
+ sfx_agrac3, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_COLORSWAP1|MF_COLORSWAP3, //flags
+ "ACOLYTE", //namepointer
+ },
+
+ { /*MT_GUARD7*/
+ 232, //doomednum
+ S_AGRD_01, //spawnstate
+ 60, //spawnhealth
+ S_AGRD_13, //seestate
+ sfx_agrsee, //seesound
+ 8, //reactiontime
+ sfx_rifle, //attacksound
+ S_AGRD_23, //painstate
+ 150, //painchance
+ sfx_agrdpn, //painsound
+ S_NULL, //meleestate
+ S_AGRD_17, //missilestate
+ S_NULL, //crashstate
+ S_AGRD_24, //deathstate
+ S_GIBS_10, //xdeathstate
+ sfx_agrdth, //deathsound
+ 7, //speed
+ 24*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 400, //mass
+ 0, //damage
+ sfx_agrac3, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_COLORSWAP2|MF_COLORSWAP3, //flags
+ "ACOLYTE", //namepointer
+ },
+
+ { /*MT_GUARD8*/
+ 231, //doomednum
+ S_AGRD_01, //spawnstate
+ 60, //spawnhealth
+ S_AGRD_13, //seestate
+ sfx_agrsee, //seesound
+ 8, //reactiontime
+ sfx_rifle, //attacksound
+ S_AGRD_23, //painstate
+ 150, //painchance
+ sfx_agrdpn, //painsound
+ S_NULL, //meleestate
+ S_AGRD_17, //missilestate
+ S_NULL, //crashstate
+ S_AGRD_24, //deathstate
+ S_GIBS_10, //xdeathstate
+ sfx_agrdth, //deathsound
+ 7, //speed
+ 24*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 400, //mass
+ 0, //damage
+ sfx_agrac3, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_COLORSWAP1|MF_COLORSWAP2
+ |MF_COLORSWAP3, //flags
+ "ACOLYTE", //namepointer
+ },
+
+ { /*MT_SHADOWGUARD*/
+ 58, //doomednum
+ S_AGRD_01, //spawnstate
+ 70, //spawnhealth
+ S_AGRD_12, //seestate
+ sfx_agrsee, //seesound
+ 8, //reactiontime
+ sfx_rifle, //attacksound
+ S_AGRD_21, //painstate
+ 150, //painchance
+ sfx_agrdpn, //painsound
+ S_NULL, //meleestate
+ S_AGRD_17, //missilestate
+ S_NULL, //crashstate
+ S_AGRD_24, //deathstate
+ S_GIBS_10, //xdeathstate
+ sfx_agrdth, //deathsound
+ 7, //speed
+ 24*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 400, //mass
+ 0, //damage
+ sfx_agrac2, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, //flags
+ "ACOLYTE", //namepointer
+ },
+
+ { /*MT_PGUARD*/
+ 3003, //doomednum
+ S_PGRD_00, //spawnstate
+ 300, //spawnhealth
+ S_PGRD_04, //seestate
+ sfx_pgrsee, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_PGRD_16, //painstate
+ 100, //painchance
+ sfx_pgrdpn, //painsound
+ S_PGRD_12, //meleestate
+ S_PGRD_14, //missilestate
+ S_NULL, //crashstate
+ S_PGRD_18, //deathstate
+ S_NULL, //xdeathstate
+ sfx_pgrdth, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 60*FRACUNIT, //height
+ 500, //mass
+ 0, //damage
+ sfx_pgract, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD|MF_COUNTKILL, //flags
+ "TEMPLAR", //namepointer
+ },
+
+ { /*MT_CRUSADER*/
+ 3005, //doomednum
+ S_ROB2_00, //spawnstate
+ 400, //spawnhealth
+ S_ROB2_01, //seestate
+ sfx_rb2see, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_ROB2_19, //painstate
+ 128, //painchance
+ sfx_rb2pn, //painsound
+ S_NULL, //meleestate
+ S_ROB2_09, //missilestate
+ S_NULL, //crashstate
+ S_ROB2_20, //deathstate
+ S_NULL, //xdeathstate
+ sfx_rb2dth, //deathsound
+ 8, //speed
+ 40*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 400, //mass
+ 0, //damage
+ sfx_rb2act, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NODIALOG|MF_NOBLOOD|MF_COUNTKILL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_BISHOP*/
+ 187, //doomednum
+ S_MLDR_00, //spawnstate
+ 500, //spawnhealth
+ S_MLDR_01, //seestate
+ sfx_rb2see, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_MLDR_11, //painstate
+ 128, //painchance
+ sfx_rb2pn, //painsound
+ S_NULL, //meleestate
+ S_MLDR_09, //missilestate
+ S_NULL, //crashstate
+ S_MLDR_12, //deathstate
+ S_NULL, //xdeathstate
+ sfx_pgrdth, //deathsound
+ 8, //speed
+ 40*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 500, //mass
+ 0, //damage
+ sfx_rb2act, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NODIALOG|MF_NOBLOOD|MF_COUNTKILL
+ |MF_NOTDMATCH, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_ORACLE*/
+ 199, //doomednum
+ S_ORCL_00, //spawnstate
+ 1, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_ORCL_01, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 15*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD|MF_COUNTKILL|MF_NOTDMATCH, //flags
+ "ORACLE", //namepointer
+ },
+
+ { /*MT_PRIEST*/
+ 12, //doomednum
+ S_PRST_00, //spawnstate
+ 800, //spawnhealth
+ S_PRST_02, //seestate
+ sfx_lorsee, //seesound
+ 8, //reactiontime
+ sfx_revbld, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_lorpn, //painsound
+ S_PRST_10, //meleestate
+ S_PRST_13, //missilestate
+ S_NULL, //crashstate
+ S_PDED_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_slop, //deathsound
+ 10, //speed
+ 15*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_tend, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST|MF_FLOAT
+ |MF_NODIALOG|MF_NOBLOOD|MF_COUNTKILL|MF_NOTDMATCH, //flags
+ "PRIEST", //namepointer
+ },
+
+ { /*MT_SPECTRE_A*/
+ 129, //doomednum
+ S_ALN1_00, //spawnstate
+ 1000, //spawnhealth
+ S_ALN1_02, //seestate
+ sfx_alnsee, //seesound
+ 8, //reactiontime
+ sfx_revbld, //attacksound
+ S_ALN1_19, //painstate
+ 250, //painchance
+ sfx_alnpn, //painsound
+ S_ALN1_13, //meleestate
+ S_ALN1_16, //missilestate
+ S_NULL, //crashstate
+ S_AL1P_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_alndth, //deathsound
+ 12, //speed
+ 64*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 1000, //mass
+ 0, //damage
+ sfx_alnact, //activesound
+ MF_SPECIAL|MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST
+ |MF_FLOAT|MF_NODIALOG|MF_SHADOW|MF_COUNTKILL|MF_NOTDMATCH
+ |MF_MVIS|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_NODE*/
+ -1, //doomednum
+ S_NODE_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOCLIP|MF_NOTDMATCH, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SPECTREHEAD*/
+ -1, //doomednum
+ S_MTHD_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOCLIP|MF_NOTDMATCH, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SPECTRE_B*/
+ 75, //doomednum
+ S_ALN1_00, //spawnstate
+ 1200, //spawnhealth
+ S_ALN1_02, //seestate
+ sfx_alnsee, //seesound
+ 8, //reactiontime
+ sfx_revbld, //attacksound
+ S_ALN1_19, //painstate
+ 50, //painchance
+ sfx_alnpn, //painsound
+ S_ALN1_13, //meleestate
+ S_ALN1_20, //missilestate
+ S_NULL, //crashstate
+ S_AL1P_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_alndth, //deathsound
+ 12, //speed
+ 24*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 1000, //mass
+ 0, //damage
+ sfx_alnact, //activesound
+ MF_SPECIAL|MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST
+ |MF_FLOAT|MF_NODIALOG|MF_SHADOW|MF_COUNTKILL|MF_NOTDMATCH
+ |MF_MVIS|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SPECTRE_C*/
+ 76, //doomednum
+ S_ALN1_23, //spawnstate
+ 1500, //spawnhealth
+ S_ALN1_34, //seestate
+ sfx_alnsee, //seesound
+ 8, //reactiontime
+ sfx_revbld, //attacksound
+ S_ALN1_51, //painstate
+ 50, //painchance
+ sfx_alnpn, //painsound
+ S_ALN1_45, //meleestate
+ S_ALN1_48, //missilestate
+ S_NULL, //crashstate
+ S_AL1P_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_alndth, //deathsound
+ 12, //speed
+ 24*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 1000, //mass
+ 0, //damage
+ sfx_alnact, //activesound
+ MF_SPECIAL|MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST
+ |MF_FLOAT|MF_NODIALOG|MF_SHADOW|MF_COUNTKILL|MF_NOTDMATCH
+ |MF_MVIS|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SPECTRE_D*/
+ 167, //doomednum
+ S_ALN1_00, //spawnstate
+ 1700, //spawnhealth
+ S_ALN1_02, //seestate
+ sfx_alnsee, //seesound
+ 8, //reactiontime
+ sfx_revbld, //attacksound
+ S_ALN1_19, //painstate
+ 50, //painchance
+ sfx_alnpn, //painsound
+ S_ALN1_13, //meleestate
+ S_ALN1_52, //missilestate
+ S_NULL, //crashstate
+ S_AL1P_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_alndth, //deathsound
+ 12, //speed
+ 24*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 1000, //mass
+ 0, //damage
+ sfx_alnact, //activesound
+ MF_SPECIAL|MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST
+ |MF_FLOAT|MF_NODIALOG|MF_SHADOW|MF_COUNTKILL|MF_NOTDMATCH
+ |MF_MVIS|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SPECTRE_E*/
+ 168, //doomednum
+ S_ALN1_00, //spawnstate
+ 2000, //spawnhealth
+ S_ALN1_02, //seestate
+ sfx_alnsee, //seesound
+ 8, //reactiontime
+ sfx_revbld, //attacksound
+ S_ALN1_19, //painstate
+ 50, //painchance
+ sfx_alnpn, //painsound
+ S_ALN1_13, //meleestate
+ S_ALN1_55, //missilestate
+ S_NULL, //crashstate
+ S_AL1P_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_alndth, //deathsound
+ 12, //speed
+ 24*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 1000, //mass
+ 0, //damage
+ sfx_alnact, //activesound
+ MF_SPECIAL|MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST
+ |MF_FLOAT|MF_NODIALOG|MF_SHADOW|MF_COUNTKILL|MF_NOTDMATCH
+ |MF_MVIS|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_ENTITY*/
+ 128, //doomednum
+ S_MNAM_00, //spawnstate
+ 2500, //spawnhealth
+ S_MNAL_02, //seestate
+ sfx_mnalse, //seesound
+ 8, //reactiontime
+ sfx_revbld, //attacksound
+ S_MNAL_19, //painstate
+ 255, //painchance
+ sfx_alnpn, //painsound
+ S_MNAL_13, //meleestate
+ S_MNAL_16, //missilestate
+ S_NULL, //crashstate
+ S_MNAL_20, //deathstate
+ S_NULL, //xdeathstate
+ sfx_mnaldt, //deathsound
+ 13, //speed
+ 130*FRACUNIT, //radius
+ 200*FRACUNIT, //height
+ 1000, //mass
+ 0, //damage
+ sfx_alnact, //activesound
+ MF_SPECIAL|MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST
+ |MF_FLOAT|MF_NODIALOG|MF_SHADOW|MF_COUNTKILL|MF_NOTDMATCH
+ |MF_MVIS|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SUBENTITY*/
+ -1, //doomednum
+ S_MNAL_27, //spawnstate
+ 990, //spawnhealth
+ S_MNAL_28, //seestate
+ sfx_alnsee, //seesound
+ 8, //reactiontime
+ sfx_revbld, //attacksound
+ S_MNAL_40, //painstate
+ 255, //painchance
+ sfx_alnpn, //painsound
+ S_MNAL_34, //meleestate
+ S_MNAL_37, //missilestate
+ S_NULL, //crashstate
+ S_MDTH_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_alndth, //deathsound
+ 14, //speed
+ 130*FRACUNIT, //radius
+ 200*FRACUNIT, //height
+ 1000, //mass
+ 0, //damage
+ sfx_alnact, //activesound
+ MF_SPECIAL|MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST
+ |MF_FLOAT|MF_NODIALOG|MF_SHADOW|MF_COUNTKILL|MF_NOTDMATCH
+ |MF_MVIS|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_NEST*/
+ 26, //doomednum
+ S_NEST_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 84*FRACUNIT, //radius
+ 47*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_NOTDMATCH, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_POD*/
+ 198, //doomednum
+ S_PODD_00, //spawnstate
+ 1000, //spawnhealth
+ S_PODD_01, //seestate
+ sfx_slop, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 25*FRACUNIT, //radius
+ 91*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_NOTDMATCH, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SIGIL_B_SHOT*/
+ -1, //doomednum
+ S_ZAP6_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_sigil, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_ZAP1_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_sglhit, //deathsound
+ 30*FRACUNIT, //speed
+ 8*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 70, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SIGIL_SB_SHOT*/
+ -1, //doomednum
+ S_ZAP6_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_sigil, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_ZAP1_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_sglhit, //deathsound
+ 30*FRACUNIT, //speed
+ 8*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 20, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SIGIL_C_SHOT*/
+ -1, //doomednum
+ S_ZOT3_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_sigil, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_ZAP1_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_sglhit, //deathsound
+ 30*FRACUNIT, //speed
+ 8*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 70, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SIGIL_SC_SHOT*/
+ -1, //doomednum
+ S_ZOT3_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_sigil, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_ZAP1_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_sglhit, //deathsound
+ 30*FRACUNIT, //speed
+ 8*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 20, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SIGIL_E_OFFSHOOT*/
+ -1, //doomednum
+ S_ZAP6_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_sigil, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_ZAP1_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_sglhit, //deathsound
+ 30*FRACUNIT, //speed
+ 8*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 10, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SIGIL_TRAIL*/
+ -1, //doomednum
+ S_ZAP6_03, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SIGIL_E_SHOT*/
+ -1, //doomednum
+ S_ZAP7_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_sigil, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_ZAP1_02, //deathstate
+ S_NULL, //xdeathstate
+ sfx_sglhit, //deathsound
+ 18*FRACUNIT, //speed
+ 20*FRACUNIT, //radius
+ 40*FRACUNIT, //height
+ 100, //mass
+ 130, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SIGIL_SE_SHOT*/
+ -1, //doomednum
+ S_ZAP7_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_sigil, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_ZAP1_02, //deathstate
+ S_NULL, //xdeathstate
+ sfx_sglhit, //deathsound
+ 18*FRACUNIT, //speed
+ 20*FRACUNIT, //radius
+ 40*FRACUNIT, //height
+ 100, //mass
+ 30, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SIGIL_A_ZAP_LEFT*/
+ -1, //doomednum
+ S_ZOT1_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_sigil, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_ZAP1_06, //deathstate
+ S_NULL, //xdeathstate
+ sfx_sglhit, //deathsound
+ 22*FRACUNIT, //speed
+ 8*FRACUNIT, //radius
+ 24*FRACUNIT, //height
+ 100, //mass
+ 100, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SIGIL_A_ZAP_RIGHT*/
+ -1, //doomednum
+ S_ZOT1_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_sigil, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_ZAP1_06, //deathstate
+ S_NULL, //xdeathstate
+ sfx_sglhit, //deathsound
+ 22*FRACUNIT, //speed
+ 8*FRACUNIT, //radius
+ 24*FRACUNIT, //height
+ 100, //mass
+ 50, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SIGIL_A_GROUND*/
+ -1, //doomednum
+ S_ZAP5_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 70, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_ZAP1_01, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 18*FRACUNIT, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_SHADOW, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SIGIL_D_SHOT*/
+ -1, //doomednum
+ S_ZOT2_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_sigil, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_ZAP1_01, //deathstate
+ S_NULL, //xdeathstate
+ sfx_sglhit, //deathsound
+ 28*FRACUNIT, //speed
+ 8*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 120, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SIGIL_SD_SHOT*/
+ -1, //doomednum
+ S_ZOT2_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_sigil, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_ZAP1_01, //deathstate
+ S_NULL, //xdeathstate
+ sfx_sglhit, //deathsound
+ 28*FRACUNIT, //speed
+ 8*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 60, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SENTINEL*/
+ 3006, //doomednum
+ S_SEWR_00, //spawnstate
+ 100, //spawnhealth
+ S_SEWR_01, //seestate
+ sfx_sntsee, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_SEWR_06, //painstate
+ 255, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_SEWR_03, //missilestate
+ S_NULL, //crashstate
+ S_SEWR_07, //deathstate
+ S_NULL, //xdeathstate
+ sfx_sntdth, //deathsound
+ 7, //speed
+ 23*FRACUNIT, //radius
+ 53*FRACUNIT, //height
+ 300, //mass
+ 0, //damage
+ sfx_sntact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_SPAWNCEILING|MF_NOGRAVITY|MF_GIVEQUEST
+ |MF_FLOAT|MF_NODIALOG|MF_NOBLOOD|MF_COUNTKILL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_STALKER*/
+ 186, //doomednum
+ S_SPID_00, //spawnstate
+ 80, //spawnhealth
+ S_SPID_03, //seestate
+ sfx_spisit, //seesound
+ 8, //reactiontime
+ sfx_spdatk, //attacksound
+ S_SPID_24, //painstate
+ 40, //painchance
+ sfx_spdatk, //painsound
+ S_SPID_09, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_SPID_25, //deathstate
+ S_NULL, //xdeathstate
+ sfx_spidth, //deathsound
+ 16, //speed
+ 31*FRACUNIT, //radius
+ 25*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_spisit, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_SPAWNCEILING|MF_NOGRAVITY|MF_DROPOFF
+ |MF_NODIALOG|MF_NOBLOOD|MF_COUNTKILL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_INQUISITOR*/
+ 16, //doomednum
+ S_ROB3_00, //spawnstate
+ 1000, //spawnhealth
+ S_ROB3_02, //seestate
+ sfx_inqsee, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_ROB3_10, //missilestate
+ S_NULL, //crashstate
+ S_ROB3_20, //deathstate
+ S_NULL, //xdeathstate
+ sfx_inqdth, //deathsound
+ 12, //speed
+ 40*FRACUNIT, //radius
+ 110*FRACUNIT, //height
+ 1000, //mass
+ 0, //damage
+ sfx_inqact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_NOBLOOD|MF_COUNTKILL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_INQARM*/
+ -1, //doomednum
+ S_RBB3_05, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 25, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOCLIP|MF_NOBLOOD, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PROGRAMMER*/
+ 71, //doomednum
+ S_PRGR_00, //spawnstate
+ 1100, //spawnhealth
+ S_PRGR_02, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_revbld, //attacksound
+ S_PRGR_18, //painstate
+ 50, //painchance
+ sfx_prgpn, //painsound
+ S_PRGR_10, //meleestate
+ S_PRGR_14, //missilestate
+ S_NULL, //crashstate
+ S_PRGR_20, //deathstate
+ S_NULL, //xdeathstate
+ sfx_rb2dth, //deathsound
+ 26, //speed
+ 45*FRACUNIT, //radius
+ 60*FRACUNIT, //height
+ 800, //mass
+ 4, //damage
+ sfx_progac, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST|MF_FLOAT
+ |MF_NOBLOOD|MF_COUNTKILL|MF_NOTDMATCH, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PROGRAMMERBASE*/
+ -1, //doomednum
+ S_BASE_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOCLIP|MF_NOBLOOD, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_HOOKSHOT*/
+ -1, //doomednum
+ S_OCLW_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_chain, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_CCLW_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 20*FRACUNIT, //speed
+ 10*FRACUNIT, //radius
+ 14*FRACUNIT, //height
+ 100, //mass
+ 2, //damage
+ sfx_swish, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_CHAINSHOT*/
+ -1, //doomednum
+ S_TEND_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_tend, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MINIMISSLE*/
+ -1, //doomednum
+ S_MICR_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_rlaunc, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_MISL_01, //deathstate
+ S_NULL, //xdeathstate
+ sfx_mislht, //deathsound
+ 20*FRACUNIT, //speed
+ 10*FRACUNIT, //radius
+ 14*FRACUNIT, //height
+ 100, //mass
+ 10, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_C_MISSILE*/
+ -1, //doomednum
+ S_MICR_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_rlaunc, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_MISL_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_mislht, //deathsound
+ 20*FRACUNIT, //speed
+ 10*FRACUNIT, //radius
+ 14*FRACUNIT, //height
+ 100, //mass
+ 7, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SEEKMISSILE*/
+ -1, //doomednum
+ S_MISS_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_rlaunc, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_MISL_01, //deathstate
+ S_NULL, //xdeathstate
+ sfx_mislht, //deathsound
+ 20*FRACUNIT, //speed
+ 10*FRACUNIT, //radius
+ 14*FRACUNIT, //height
+ 100, //mass
+ 10, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_ELECARROW*/
+ -1, //doomednum
+ S_AROW_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_swish, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_ZAP1_01, //deathstate
+ S_NULL, //xdeathstate
+ sfx_firxpl, //deathsound
+ 30*FRACUNIT, //speed
+ 10*FRACUNIT, //radius
+ 10*FRACUNIT, //height
+ 100, //mass
+ 10, //damage
+ sfx_swish, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_POISARROW*/
+ -1, //doomednum
+ S_ARWP_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_swish, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_AROW_01, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 30*FRACUNIT, //speed
+ 10*FRACUNIT, //radius
+ 10*FRACUNIT, //height
+ 100, //mass
+ 500, //damage
+ sfx_swish, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_R_LASER*/
+ -1, //doomednum
+ S_SHT1_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_POW1_09, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 40*FRACUNIT, //speed
+ 10*FRACUNIT, //radius
+ 8*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_L_LASER*/
+ -1, //doomednum
+ S_SHT1_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_plasma, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_POW1_05, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 40*FRACUNIT, //speed
+ 10*FRACUNIT, //radius
+ 8*FRACUNIT, //height
+ 100, //mass
+ 1, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_HEGRENADE*/
+ -1, //doomednum
+ S_GRAP_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_phoot, //seesound
+ 30, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_BNG4_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_explod, //deathsound
+ 15*FRACUNIT, //speed
+ 13*FRACUNIT, //radius
+ 13*FRACUNIT, //height
+ 20, //mass
+ 1, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PGRENADE*/
+ -1, //doomednum
+ S_GRIN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_phoot, //seesound
+ 40, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_BNG3_08, //deathstate
+ S_NULL, //xdeathstate
+ sfx_explod, //deathsound
+ 15*FRACUNIT, //speed
+ 13*FRACUNIT, //radius
+ 13*FRACUNIT, //height
+ 20, //mass
+ 1, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_INQGRENADE*/
+ -1, //doomednum
+ S_UBAM_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_phoot, //seesound
+ 15, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_BNG2_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_explod, //deathsound
+ 25*FRACUNIT, //speed
+ 13*FRACUNIT, //radius
+ 13*FRACUNIT, //height
+ 15, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PFLAME*/
+ -1, //doomednum
+ S_BNG3_09, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 120, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_FLBE_07, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TORPEDO*/
+ -1, //doomednum
+ S_TORP_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_protfl, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_THIT_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_explod, //deathsound
+ 20*FRACUNIT, //speed
+ 13*FRACUNIT, //radius
+ 8*FRACUNIT, //height
+ 100, //mass
+ 1, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TORPEDOSPREAD*/
+ -1, //doomednum
+ S_TWAV_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_TWAV_02, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 35*FRACUNIT, //speed
+ 13*FRACUNIT, //radius
+ 13*FRACUNIT, //height
+ 100, //mass
+ 10, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SFIREBALL*/
+ -1, //doomednum
+ S_FRBL_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_flburn, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_FRBL_03, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 15*FRACUNIT, //speed
+ 8*FRACUNIT, //radius
+ 11*FRACUNIT, //height
+ 10, //mass
+ 4, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_C_FLAME*/
+ -1, //doomednum
+ S_FRBL_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_flburn, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_FRBL_03, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 35*FRACUNIT, //speed
+ 8*FRACUNIT, //radius
+ 11*FRACUNIT, //height
+ 50, //mass
+ 1, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_STRIFEPUFF3*/
+ -1, //doomednum
+ S_SHT2_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_STRIFEPUFF*/
+ -1, //doomednum
+ S_PUFY_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SPARKPUFF*/
+ -1, //doomednum
+ S_POW3_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_BLOOD_DEATH*/
+ -1, //doomednum
+ S_SPRY_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TFOG*/
+ -1, //doomednum
+ S_TFOG_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_IFOG*/
+ -1, //doomednum
+ S_IFOG_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TELEPORTMAN*/
+ 14, //doomednum
+ S_NULL, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOSECTOR|MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_01*/
+ 24, //doomednum
+ S_KLAX_00, //spawnstate
+ 1000, //spawnhealth
+ S_KLAX_01, //seestate
+ sfx_None, //seesound
+ 60, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_STAND|MF_SPAWNCEILING|MF_NOGRAVITY, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TURRET*/
+ 27, //doomednum
+ S_TURT_00, //spawnstate
+ 125, //spawnhealth
+ S_TURT_01, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_TURT_02, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_TURT_02, //missilestate
+ S_NULL, //crashstate
+ S_BALL_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_mislht, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 10000000, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SHOOTABLE|MF_STAND|MF_SPAWNCEILING|MF_NOGRAVITY|MF_NOBLOOD
+ |MF_COUNTKILL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_GATE*/
+ 45, //doomednum
+ S_PSTN_00, //spawnstate
+ 100, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_PSTN_02, //deathstate
+ S_NULL, //xdeathstate
+ sfx_explod, //deathsound
+ 16, //speed
+ 20*FRACUNIT, //radius
+ 76*FRACUNIT, //height
+ 10000000, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_GIVEQUEST|MF_NODIALOG|MF_NOBLOOD, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_COMPUTER*/
+ 182, //doomednum
+ S_SECR_00, //spawnstate
+ 80, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_SECR_04, //deathstate
+ S_NULL, //xdeathstate
+ sfx_explod, //deathsound
+ 27, //speed
+ 26*FRACUNIT, //radius
+ 128*FRACUNIT, //height
+ 100000, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_GIVEQUEST|MF_NODIALOG|MF_NOBLOOD, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_INV_MED1*/
+ 2011, //doomednum
+ S_STMP_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 20, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "Med_patch", //namepointer
+ },
+
+ { /*MT_INV_MED2*/
+ 2012, //doomednum
+ S_MDKT_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 15, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "Medical_kit", //namepointer
+ },
+
+ { /*MT_INV_MED3*/
+ 83, //doomednum
+ S_FULL_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 5, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "Surgery_Kit", //namepointer
+ },
+
+ { /*MT_DEGNINORE*/
+ 59, //doomednum
+ S_XPRK_01, //spawnstate
+ 10, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_XPRK_02, //deathstate
+ S_NULL, //xdeathstate
+ sfx_explod, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 10, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_SOLID|MF_SHOOTABLE|MF_NODIALOG|MF_NOBLOOD, //flags
+ "Degnin_Ore", //namepointer
+ },
+
+ { /*MT_INV_ARMOR2*/
+ 2019, //doomednum
+ S_ARM1_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 3, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "Metal_Armor", //namepointer
+ },
+
+ { /*MT_INV_ARMOR1*/
+ 2018, //doomednum
+ S_ARM2_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 5, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "Leather_Armor", //namepointer
+ },
+
+ { /*MT_MISC_22*/
+ 2014, //doomednum
+ S_WATR_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_11*/
+ 164, //doomednum
+ S_MUGG_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_KEY_BASE*/
+ 230, //doomednum
+ S_FUSL_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_NOTDMATCH, //flags
+ "Base_Key", //namepointer
+ },
+
+ { /*MT_GOVSKEY*/
+ -1, //doomednum
+ S_REBL_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_NOTDMATCH, //flags
+ "Govs_Key", //namepointer
+ },
+
+ { /*MT_KEY_TRAVEL*/
+ 185, //doomednum
+ S_TPAS_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_NOTDMATCH, //flags
+ "Passcard", //namepointer
+ },
+
+ { /*MT_KEY_ID_BLUE*/
+ 184, //doomednum
+ S_CRD1_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_NOTDMATCH, //flags
+ "ID_Badge", //namepointer
+ },
+
+ { /*MT_PRISONKEY*/
+ -1, //doomednum
+ S_PRIS_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 11, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_GIVEQUEST|MF_NOTDMATCH, //flags
+ "Prison_Key", //namepointer
+ },
+
+ { /*MT_KEY_HAND*/
+ 91, //doomednum
+ S_HAND_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 12, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_GIVEQUEST|MF_NOTDMATCH, //flags
+ "Severed_Hand", //namepointer
+ },
+
+ { /*MT_POWER1KEY*/
+ -1, //doomednum
+ S_PWR1_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_NOTDMATCH, //flags
+ "Power1_Key", //namepointer
+ },
+
+ { /*MT_POWER2KEY*/
+ -1, //doomednum
+ S_PWR2_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_NOTDMATCH, //flags
+ "Power2_Key", //namepointer
+ },
+
+ { /*MT_POWER3KEY*/
+ -1, //doomednum
+ S_PWR3_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_NOTDMATCH, //flags
+ "Power3_Key", //namepointer
+ },
+
+ { /*MT_KEY_GOLD*/
+ 40, //doomednum
+ S_KY1G_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_NOTDMATCH, //flags
+ "Gold_Key", //namepointer
+ },
+
+ { /*MT_KEY_ID_GOLD*/
+ 13, //doomednum
+ S_CRD2_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_NOTDMATCH, //flags
+ "ID_Card", //namepointer
+ },
+
+ { /*MT_KEY_SILVER*/
+ 38, //doomednum
+ S_KY2S_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_NOTDMATCH, //flags
+ "Silver_Key", //namepointer
+ },
+
+ { /*MT_KEY_ORACLE*/
+ 61, //doomednum
+ S_ORAC_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_NOTDMATCH, //flags
+ "Oracle_Key", //namepointer
+ },
+
+ { /*MT_MILITARYID*/
+ -1, //doomednum
+ S_GYID_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_NOTDMATCH, //flags
+ "Military_ID", //namepointer
+ },
+
+ { /*MT_KEY_ORDER*/
+ 86, //doomednum
+ S_FUBR_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_NOTDMATCH, //flags
+ "Order_Key", //namepointer
+ },
+
+ { /*MT_KEY_WAREHOUSE*/
+ 166, //doomednum
+ S_WARE_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_NOTDMATCH, //flags
+ "Warehouse_Key", //namepointer
+ },
+
+ { /*MT_KEY_BRASS*/
+ 39, //doomednum
+ S_KY3B_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_NOTDMATCH, //flags
+ "Brass_Key", //namepointer
+ },
+
+ { /*MT_KEY_RED_CRYSTAL*/
+ 192, //doomednum
+ S_RCRY_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_NOTDMATCH, //flags
+ "Red_Crystal_Key", //namepointer
+ },
+
+ { /*MT_KEY_BLUE_CRYSTAL*/
+ 193, //doomednum
+ S_BCRY_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_NOTDMATCH, //flags
+ "Blue_Crystal_Key", //namepointer
+ },
+
+ { /*MT_KEY_CHAPEL*/
+ 195, //doomednum
+ S_CHAP_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_NOTDMATCH, //flags
+ "Chapel_Key", //namepointer
+ },
+
+ { /*MT_CATACOMBKEY*/
+ -1, //doomednum
+ S_TUNL_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 28, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_GIVEQUEST|MF_NOTDMATCH, //flags
+ "Catacomb_Key", //namepointer
+ },
+
+ { /*MT_SECURITYKEY*/
+ -1, //doomednum
+ S_SECK_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_NOTDMATCH, //flags
+ "Security_Key", //namepointer
+ },
+
+ { /*MT_KEY_CORE*/
+ 236, //doomednum
+ S_GOID_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_NOTDMATCH, //flags
+ "Core_Key", //namepointer
+ },
+
+ { /*MT_KEY_MAULER*/
+ 233, //doomednum
+ S_BLTK_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_NOTDMATCH, //flags
+ "Mauler_Key", //namepointer
+ },
+
+ { /*MT_KEY_FACTORY*/
+ 234, //doomednum
+ S_PROC_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_NOTDMATCH, //flags
+ "Factory_Key", //namepointer
+ },
+
+ { /*MT_KEY_MINE*/
+ 235, //doomednum
+ S_MINE_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_NOTDMATCH, //flags
+ "MINE_KEY", //namepointer
+ },
+
+ { /*MT_NEWKEY5*/
+ -1, //doomednum
+ S_BLTK_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_NOTDMATCH, //flags
+ "New_Key5", //namepointer
+ },
+
+ { /*MT_INV_SHADOWARMOR*/
+ 2024, //doomednum
+ S_SHD1_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 2, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "Shadow_armor", //namepointer
+ },
+
+ { /*MT_INV_SUIT*/
+ 2025, //doomednum
+ S_MASK_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 5, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "Environmental_Suit", //namepointer
+ },
+
+ { /*MT_QUEST_UNIFORM*/
+ 90, //doomednum
+ S_UNIF_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 15, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_GIVEQUEST, //flags
+ "Guard_Uniform", //namepointer
+ },
+
+ { /*MT_QUEST_GUARD_UNIFORM*/
+ 52, //doomednum
+ S_OFIC_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_NOTDMATCH, //flags
+ "Officer's_Uniform", //namepointer
+ },
+
+ { /*MT_INV_SUPERMAP*/
+ 2026, //doomednum
+ S_PMAP_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "map", //namepointer
+ },
+
+ { /*MT_INV_RADAR*/
+ 2027, //doomednum
+ S_PMUP_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 1, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "scanner", //namepointer
+ },
+
+ { /*MT_BEACON*/
+ 10, //doomednum
+ S_BEAC_00, //spawnstate
+ 5, //spawnhealth
+ S_BEAC_01, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 3, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_DROPPED, //flags
+ "Teleporter_Beacon", //namepointer
+ },
+
+ { /*MT_INV_TARGETER*/
+ 207, //doomednum
+ S_TARG_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 5, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "Targeter", //namepointer
+ },
+
+ { /*MT_MONY_1*/
+ 93, //doomednum
+ S_COIN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 2147483647, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_DROPPED|MF_NOTDMATCH, //flags
+ "coin", //namepointer
+ },
+
+ { /*MT_MONY_10*/
+ 138, //doomednum
+ S_CRED_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_DROPPED|MF_NOTDMATCH, //flags
+ "10_gold", //namepointer
+ },
+
+ { /*MT_MONY_25*/
+ 139, //doomednum
+ S_SACK_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_DROPPED|MF_NOTDMATCH, //flags
+ "25_gold", //namepointer
+ },
+
+ { /*MT_MONY_50*/
+ 140, //doomednum
+ S_CHST_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_DROPPED|MF_NOTDMATCH, //flags
+ "50_gold", //namepointer
+ },
+
+ { /*MT_MONY_300*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 3, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_GIVEQUEST|MF_DROPPED, //flags
+ "300_gold", //namepointer
+ },
+
+ { /*MT_TOKEN_RING*/
+ -1, //doomednum
+ S_RING_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 1, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_GIVEQUEST|MF_NOTDMATCH, //flags
+ "ring", //namepointer
+ },
+
+ { /*MT_INV_CHALICE*/
+ 205, //doomednum
+ S_RELC_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 2, //speed
+ 10*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_GIVEQUEST|MF_DROPPED, //flags
+ "Offering_Chalice", //namepointer
+ },
+
+ { /*MT_TOKEN_EAR*/
+ -1, //doomednum
+ S_EARS_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 9, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_GIVEQUEST, //flags
+ "ear", //namepointer
+ },
+
+ { /*MT_INV_COMMUNICATOR*/
+ 206, //doomednum
+ S_COMM_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_NOTDMATCH, //flags
+ "Communicator", //namepointer
+ },
+
+ { /*MT_AGREN*/
+ 152, //doomednum
+ S_GRN1_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "HE-Grenade_Rounds", //namepointer
+ },
+
+ { /*MT_APGREN*/
+ 153, //doomednum
+ S_GRN2_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "Phosphorus-Grenade_Rounds", //namepointer
+ },
+
+ { /*MT_ACLIP*/
+ 2007, //doomednum
+ S_BLIT_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "clip_of_bullets", //namepointer
+ },
+
+ { /*MT_AAMMOBOX*/
+ 2048, //doomednum
+ S_BBOX_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "ammo", //namepointer
+ },
+
+ { /*MT_AMINI*/
+ 2010, //doomednum
+ S_MSSL_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "mini_missiles", //namepointer
+ },
+
+ { /*MT_AMINIBOX*/
+ 2046, //doomednum
+ S_ROKT_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "crate_of_missiles", //namepointer
+ },
+
+ { /*MT_ACELL*/
+ 2047, //doomednum
+ S_BRY1_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "energy_pod", //namepointer
+ },
+
+ { /*MT_APCELL*/
+ 17, //doomednum
+ S_CPAC_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "energy_pack", //namepointer
+ },
+
+ { /*MT_APAROW*/
+ 115, //doomednum
+ S_PQRL_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "poison_bolts", //namepointer
+ },
+
+ { /*MT_AAROW*/
+ 114, //doomednum
+ S_XQRL_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "electric_bolts", //namepointer
+ },
+
+ { /*MT_INV_SATCHEL*/
+ 183, //doomednum
+ S_BKPK_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "ammo_satchel", //namepointer
+ },
+
+ { /*MT_PULSE*/
+ 2002, //doomednum
+ S_RIFL_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "assault_gun", //namepointer
+ },
+
+ { /*MT_RIFLESTAND*/
+ 2006, //doomednum
+ S_RIFL_01, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "assault_gun", //namepointer
+ },
+
+ { /*MT_FLAMETHROWER*/
+ 2005, //doomednum
+ S_FLAM_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "flame_thrower", //namepointer
+ },
+
+ { /*MT_TOKEN_FLAME_THROWER_PARTS*/
+ -1, //doomednum
+ S_BFLM_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "flame_thrower_parts", //namepointer
+ },
+
+ { /*MT_MISSILELAUNCHER*/
+ 2003, //doomednum
+ S_MMSL_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "mini_missile_launcher", //namepointer
+ },
+
+ { /*MT_BLASTER*/
+ 2004, //doomednum
+ S_TRPD_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "mauler", //namepointer
+ },
+
+ { /*MT_CROSSBOW*/
+ 2001, //doomednum
+ S_CBOW_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "crossbow", //namepointer
+ },
+
+ { /*MT_GRENADELAUNCHER*/
+ 154, //doomednum
+ S_GRND_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "Grenade_launcher", //namepointer
+ },
+
+ { /*MT_SIGIL_A*/
+ 77, //doomednum
+ S_SIGL_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "SIGIL", //namepointer
+ },
+
+ { /*MT_SIGIL_B*/
+ 78, //doomednum
+ S_SIGL_01, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "SIGIL", //namepointer
+ },
+
+ { /*MT_SIGIL_C*/
+ 79, //doomednum
+ S_SIGL_02, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "SIGIL", //namepointer
+ },
+
+ { /*MT_SIGIL_D*/
+ 80, //doomednum
+ S_SIGL_03, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "SIGIL", //namepointer
+ },
+
+ { /*MT_SIGIL_E*/
+ 81, //doomednum
+ S_SIGL_04, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "SIGIL", //namepointer
+ },
+
+ { /*MT_POWER_CRYSTAL*/
+ 92, //doomednum
+ S_CRYS_00, //spawnstate
+ 50, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_BOOM_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_explod, //deathsound
+ 14, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 99999999, //mass
+ 0, //damage
+ sfx_reactr, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST|MF_NOBLOOD, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_RAT*/
+ 85, //doomednum
+ S_RATT_00, //spawnstate
+ 5, //spawnhealth
+ S_RATT_01, //seestate
+ sfx_ratact, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_RATT_05, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_MEAT_16, //deathstate
+ S_NULL, //xdeathstate
+ sfx_ratact, //deathsound
+ 13, //speed
+ 10*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_ratact, //activesound
+ MF_NODIALOG|MF_NOBLOOD|MF_COUNTKILL, //flags
+ "rat_buddy", //namepointer
+ },
+
+ { /*MT_MISC_05*/
+ 82, //doomednum
+ S_BARW_00, //spawnstate
+ 10, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_BARW_01, //deathstate
+ S_NULL, //xdeathstate
+ sfx_wbrldt, //deathsound
+ 0, //speed
+ 10*FRACUNIT, //radius
+ 32*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NODIALOG|MF_NOBLOOD, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_06*/
+ 94, //doomednum
+ S_BART_00, //spawnstate
+ 30, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_BART_01, //deathstate
+ S_NULL, //xdeathstate
+ sfx_barexp, //deathsound
+ 0, //speed
+ 10*FRACUNIT, //radius
+ 32*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NODIALOG|MF_NOBLOOD, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_15*/
+ 208, //doomednum
+ S_HOGN_00, //spawnstate
+ 99999999, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_HOGN_01, //painstate
+ 255, //painchance
+ sfx_mtalht, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 10*FRACUNIT, //radius
+ 72*FRACUNIT, //height
+ 9999999, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NODIALOG|MF_NOBLOOD, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT14*/
+ 95, //doomednum
+ S_LITS_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 4*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT13*/
+ 96, //doomednum
+ S_LITB_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 4*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT12*/
+ 97, //doomednum
+ S_LITG_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 4*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT18*/
+ 2028, //doomednum
+ S_LITE_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PILLAR2*/
+ 48, //doomednum
+ S_MONI_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 128*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PILLAR3*/
+ 54, //doomednum
+ S_STEL_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 128*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PILLAR4*/
+ 55, //doomednum
+ S_STLA_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 80*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PILLAR5*/
+ 56, //doomednum
+ S_STLE_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 40*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PILLAR6*/
+ 57, //doomednum
+ S_HUGE_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 24*FRACUNIT, //radius
+ 192*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PILLAR7*/
+ 227, //doomednum
+ S_APOW_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 24*FRACUNIT, //radius
+ 192*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_amaln2, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_CAVE2*/
+ 98, //doomednum
+ S_STLG_02, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 54*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_CAVE3*/
+ 161, //doomednum
+ S_STLG_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 40*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_CAVE4*/
+ 160, //doomednum
+ S_STLG_01, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 40*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_CAVE6*/
+ 159, //doomednum
+ S_STLG_03, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 128*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_CAVE7*/
+ 162, //doomednum
+ S_STLG_04, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 128*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_CAVE5*/
+ 163, //doomednum
+ S_STLG_05, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 25*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT2*/
+ 34, //doomednum
+ S_CNDL_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT3*/
+ 35, //doomednum
+ S_CLBR_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 40*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_03*/
+ 103, //doomednum
+ S_DRIP_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_wdrip, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_13*/
+ 104, //doomednum
+ S_SPLH_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_wfall, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_02*/
+ 53, //doomednum
+ S_CDRP_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 1*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_SPAWNCEILING|MF_NOGRAVITY, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_07*/
+ 112, //doomednum
+ S_WTFT_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_wsplsh, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_BIO2*/
+ 113, //doomednum
+ S_HERT_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TELEPORTSTAND*/
+ 23, //doomednum
+ S_TELP_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_SHADOW, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_DEADTHING1*/
+ 22, //doomednum
+ S_ROB2_28, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_DEADTHING2*/
+ 15, //doomednum
+ S_PLAY_18, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_DEADTHING3*/
+ 18, //doomednum
+ S_PEAS_24, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_DEADTHING4*/
+ 21, //doomednum
+ S_AGRD_31, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_DEADTHING5*/
+ 20, //doomednum
+ S_ROB1_25, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_DEADTHING6*/
+ 19, //doomednum
+ S_HMN1_31, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_BIO1*/
+ 212, //doomednum
+ S_SACR_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_GIBS*/
+ 54, //doomednum
+ S_DEAD_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_04*/
+ 70, //doomednum
+ S_BARL_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 48*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT11*/
+ 105, //doomednum
+ S_BOWL_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_smfire, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT10*/
+ 106, //doomednum
+ S_BRAZ_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 10*FRACUNIT, //radius
+ 32*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_smfire, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT9*/
+ 107, //doomednum
+ S_TRCH_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 0*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_smfire, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT8*/
+ 108, //doomednum
+ S_TRHO_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 0*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_14*/
+ 109, //doomednum
+ S_CHAN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 93*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_SPAWNCEILING|MF_NOGRAVITY, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT1*/
+ 28, //doomednum
+ S_CAGE_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 3*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_SPAWNCEILING|MF_NOGRAVITY, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PILLAR8*/
+ 110, //doomednum
+ S_STAT_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PILLAR9*/
+ 44, //doomednum
+ S_DSTA_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT15*/
+ 111, //doomednum
+ S_LTRH_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 4*FRACUNIT, //radius
+ 72*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT4*/
+ 43, //doomednum
+ S_LAMP_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 3*FRACUNIT, //radius
+ 80*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT5*/
+ 46, //doomednum
+ S_LANT_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 3*FRACUNIT, //radius
+ 80*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_ROCK1*/
+ 99, //doomednum
+ S_ROK1_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_ROCK2*/
+ 100, //doomednum
+ S_ROK2_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_ROCK3*/
+ 101, //doomednum
+ S_ROK3_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_ROCK4*/
+ 102, //doomednum
+ S_ROK4_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TREE7*/
+ 215, //doomednum
+ S_LOGG_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_wriver, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_RUBBLE1*/
+ 29, //doomednum
+ S_RUB1_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOCLIP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_RUBBLE2*/
+ 30, //doomednum
+ S_RUB2_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOCLIP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_RUBBLE3*/
+ 31, //doomednum
+ S_RUB3_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOCLIP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_RUBBLE4*/
+ 32, //doomednum
+ S_RUB4_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOCLIP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_RUBBLE5*/
+ 36, //doomednum
+ S_RUB5_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOCLIP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_RUBBLE6*/
+ 37, //doomednum
+ S_RUB6_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOCLIP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_RUBBLE7*/
+ 41, //doomednum
+ S_RUB7_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOCLIP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_RUBBLE8*/
+ 42, //doomednum
+ S_RUB8_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOCLIP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_08*/
+ 117, //doomednum
+ S_CRAB_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT6*/
+ 47, //doomednum
+ S_LMPC_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 10*FRACUNIT, //radius
+ 72*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_smfire, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT7*/
+ 50, //doomednum
+ S_LOGS_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 10*FRACUNIT, //radius
+ 80*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_smfire, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TREE2*/
+ 51, //doomednum
+ S_TREE_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 15*FRACUNIT, //radius
+ 109*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TREE3*/
+ 202, //doomednum
+ S_TREE_01, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 15*FRACUNIT, //radius
+ 109*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TREE4*/
+ 203, //doomednum
+ S_TREE_02, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 15*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TREE1*/
+ 33, //doomednum
+ S_TRE1_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 15*FRACUNIT, //radius
+ 80*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TREE6*/
+ 60, //doomednum
+ S_BUSH_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 15*FRACUNIT, //radius
+ 40*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TREE5*/
+ 62, //doomednum
+ S_SHRB_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_CAVE1*/
+ 63, //doomednum
+ S_STAK_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PILLAR1*/
+ 69, //doomednum
+ S_BAR1_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 128*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_10*/
+ 165, //doomednum
+ S_VASE_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 12*FRACUNIT, //radius
+ 24*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_09*/
+ 188, //doomednum
+ S_VASE_01, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 12*FRACUNIT, //radius
+ 32*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_17*/
+ 189, //doomednum
+ S_STOL_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 6*FRACUNIT, //radius
+ 24*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_18*/
+ 190, //doomednum
+ S_POT1_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_19*/
+ 191, //doomednum
+ S_TUB1_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_20*/
+ 194, //doomednum
+ S_ANVL_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 32*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT16*/
+ 196, //doomednum
+ S_TLMP_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 11*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT17*/
+ 197, //doomednum
+ S_TLMP_01, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 8*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_21*/
+ 68, //doomednum
+ S_TRAY_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 24*FRACUNIT, //radius
+ 40*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_12*/
+ 228, //doomednum
+ S_AFED_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 12*FRACUNIT, //radius
+ 24*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_26*/
+ 216, //doomednum
+ S_SBAN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 24*FRACUNIT, //radius
+ 96*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_23*/
+ 217, //doomednum
+ S_BOTR_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_24*/
+ 218, //doomednum
+ S_HATR_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_25*/
+ 219, //doomednum
+ S_TOPR_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_COUPLING*/
+ 220, //doomednum
+ S_COUP_00, //spawnstate
+ 40, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 6, //speed
+ 17*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 999999, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_GIVEQUEST|MF_NODIALOG|MF_DROPPED
+ |MF_NOBLOOD|MF_NOTDMATCH, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_COUPLING_BROKEN*/
+ 226, //doomednum
+ S_COUP_02, //spawnstate
+ 40, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 512*FRACUNIT, //speed
+ 16*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 1, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_GIVEQUEST|MF_DROPPED, //flags
+ "BROKEN_POWER_COUPLING", //namepointer
+ },
+
+ { /*MT_PILLAR10*/
+ 221, //doomednum
+ S_BUBB_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 128*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_amaln5, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PILLAR11*/
+ 222, //doomednum
+ S_BUBF_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 72*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_amaln6, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PILLAR12*/
+ 223, //doomednum
+ S_BUBF_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 72*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_amaln4, //activesound
+ MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PILLAR13*/
+ 224, //doomednum
+ S_ASPR_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 128*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_amaln3, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT19*/
+ 225, //doomednum
+ S_SPDL_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 32*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_amaln1, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MEAT*/
+ -1, //doomednum
+ S_MEAT_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOCLIP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_JUNK*/
+ -1, //doomednum
+ S_JUNK_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOCLIP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_BURNDROP*/
+ -1, //doomednum
+ S_FFOT_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOCLIP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_AMMO*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "Ammo", //namepointer
+ },
+
+ { /*MT_TOKEN_HEALTH*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "Health", //namepointer
+ },
+
+ { /*MT_TOKEN*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "info", //namepointer
+ },
+
+ { /*MT_TOKEN_ALARM*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "alarm", //namepointer
+ },
+
+ { /*MT_TOKEN_DOOR1*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_SHOPCLOSE*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_PRISON_PASS*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 10, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_GIVEQUEST, //flags
+ "Prison_pass", //namepointer
+ },
+
+ { /*MT_TOKEN_DOOR3*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_STAMINA*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_NEW_ACCURACY*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_REPORT*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "report", //namepointer
+ },
+
+ { /*MT_TOKEN_TOUGHNESS*/
+ -1, //doomednum
+ S_HELT_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "Toughness", //namepointer
+ },
+
+ { /*MT_TOKEN_ACCURACY*/
+ -1, //doomednum
+ S_GUNT_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "Accuracy", //namepointer
+ },
+
+ { /*MT_TOKEN_ORACLE_PASS*/
+ -1, //doomednum
+ S_OTOK_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 18, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_GIVEQUEST, //flags
+ "Oracle_Pass", //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST1*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST2*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST3*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST4*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ "quest4", //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST5*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ "quest5", //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST6*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ "quest6", //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST7*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST8*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST9*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST10*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST11*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST12*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST13*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_CRYSTAL*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ "You've_Blown_Up_the_Crystal", //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST15*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_GATEQUEST*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ "You've_Blown_Up_the_Gates", //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST17*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST18*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST19*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST20*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_BISHOP*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ "You_Killed_the_Bishop!", //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST22*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_ORACLE*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ "You've_Killed_The_Oracle!", //namepointer
+ },
+
+ { /*MT_TOKEN_MACIL*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ "You_Killed_Macil!", //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST25*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_LOREMASTER*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ "You've_Killed_The_Loremaster!", //namepointer
+ },
+
+ { /*MT_SECRQUEST*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ "You've_Blown_Up_the_Computer", //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST28*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST29*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST30*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST31*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ 0, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SLIDESHOW*/
+ -1, //doomednum
+ S_TOKN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ NULL, //namepointer
+ },
+
+};
+
+
+
diff --git a/src/strife/info.h b/src/strife/info.h
new file mode 100644
index 00000000..dce91e00
--- /dev/null
+++ b/src/strife/info.h
@@ -0,0 +1,2227 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Thing frame/state LUT,
+// generated by multigen utilitiy.
+// This one is the original DOOM version, preserved.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef __INFO__
+#define __INFO__
+
+// Needed for action function pointer handling.
+#include "d_think.h"
+
+// villsa [STRIFE]
+typedef enum
+{
+ SPR_PLAY, // 0
+ SPR_PNCH, // 1
+ SPR_WAVE, // 2
+ SPR_RBPY, // 3
+ SPR_TRGT, // 4
+ SPR_XBOW, // 5
+ SPR_MMIS, // 6
+ SPR_RIFG, // 7
+ SPR_RIFF, // 8
+ SPR_FLMT, // 9
+ SPR_FLMF, // 10
+ SPR_BLST, // 11
+ SPR_BLSF, // 12
+ SPR_GREN, // 13
+ SPR_GREF, // 14
+ SPR_SIGH, // 15
+ SPR_SIGF, // 16
+ SPR_POW1, // 17
+ SPR_POW2, // 18
+ SPR_POW3, // 19
+ SPR_ZAP1, // 20
+ SPR_SPRY, // 21
+ SPR_BLOD, // 22
+ SPR_PUFY, // 23
+ SPR_SHT1, // 24
+ SPR_SHT2, // 25
+ SPR_GRIN, // 26
+ SPR_GRAP, // 27
+ SPR_UBAM, // 28
+ SPR_BNG2, // 29
+ SPR_BNG4, // 30
+ SPR_BNG3, // 31
+ SPR_FLBE, // 32
+ SPR_XPRK, // 33
+ SPR_OCLW, // 34
+ SPR_CCLW, // 35
+ SPR_TEND, // 36
+ SPR_MICR, // 37
+ SPR_MISS, // 38
+ SPR_AROW, // 39
+ SPR_ARWP, // 40
+ SPR_TORP, // 41
+ SPR_THIT, // 42
+ SPR_TWAV, // 43
+ SPR_MISL, // 44
+ SPR_TFOG, // 45
+ SPR_IFOG, // 46
+ SPR_SHRD, // 47
+ SPR_RGIB, // 48
+ SPR_MRYS, // 49
+ SPR_MRNO, // 50
+ SPR_MRST, // 51
+ SPR_MRLK, // 52
+ SPR_MRBD, // 53
+ SPR_MRPN, // 54
+ SPR_MRGT, // 55
+ SPR_BURN, // 56
+ SPR_DISR, // 57
+ SPR_PEAS, // 58
+ SPR_GIBS, // 59
+ SPR_AGRD, // 60
+ SPR_ARMR, // 61
+ SPR_SACR, // 62
+ SPR_TNK1, // 63
+ SPR_TNK2, // 64
+ SPR_TNK3, // 65
+ SPR_TNK4, // 66
+ SPR_TNK5, // 67
+ SPR_TNK6, // 68
+ SPR_NEAL, // 69
+ SPR_BEGR, // 70
+ SPR_HMN1, // 71
+ SPR_LEDR, // 72
+ SPR_LEAD, // 73
+ SPR_ROB1, // 74
+ SPR_PGRD, // 75
+ SPR_ROB2, // 76
+ SPR_MLDR, // 77
+ SPR_ORCL, // 78
+ SPR_PRST, // 79
+ SPR_PDED, // 80
+ SPR_ALN1, // 81
+ SPR_AL1P, // 82
+ SPR_NODE, // 83
+ SPR_MTHD, // 84
+ SPR_MNAM, // 85
+ SPR_MNAL, // 86
+ SPR_MDTH, // 87
+ SPR_NEST, // 88
+ SPR_PODD, // 89
+ SPR_ZAP6, // 90
+ SPR_ZOT3, // 91
+ SPR_ZAP7, // 92
+ SPR_ZOT1, // 93
+ SPR_ZAP5, // 94
+ SPR_ZOT2, // 95
+ SPR_SEWR, // 96
+ SPR_SPID, // 97
+ SPR_ROB3, // 98
+ SPR_RBB3, // 99
+ SPR_PRGR, // 100
+ SPR_BASE, //
+ SPR_FRBL, //
+ SPR_KLAX, //
+ SPR_TURT, //
+ SPR_BALL, // 105
+ SPR_PSTN, //
+ SPR_SECR, //
+ SPR_TARG, //
+ SPR_RING, //
+ SPR_EARS, // 110
+ SPR_COMM, //
+ SPR_BOOM, //
+ SPR_RATT, //
+ SPR_HOGN, //
+ SPR_DEAD, // 115
+ SPR_SBAN, //
+ SPR_BOTR, //
+ SPR_HATR, //
+ SPR_TOPR, //
+ SPR_COUP, // 120
+ SPR_BUBB, //
+ SPR_BUBF, //
+ SPR_BUBC, //
+ SPR_ASPR, //
+ SPR_SPDL, // 125
+ SPR_TOKN, //
+ SPR_OTOK, //
+ SPR_HELT, //
+ SPR_GUNT, //
+ SPR_FULL, // 130
+ SPR_MEAT, //
+ SPR_JUNK, //
+ SPR_FFOT, //
+ SPR_DIE1, //
+ SPR_BEAC, // 135
+ SPR_ARM1, //
+ SPR_ARM2, //
+ SPR_BARW, //
+ SPR_BART, //
+ SPR_LAMP, // 140
+ SPR_LANT, //
+ SPR_BARL, //
+ SPR_BOWL, //
+ SPR_BRAZ, //
+ SPR_TRCH, // 145
+ SPR_LTRH, //
+ SPR_LMPC, //
+ SPR_LOGS, //
+ SPR_TRHO, //
+ SPR_WATR, // 150
+ SPR_MUGG, //
+ SPR_FUSL, //
+ SPR_CRD1, //
+ SPR_CRD2, //
+ SPR_TPAS, // 155
+ SPR_KY1G, //
+ SPR_KY2S, //
+ SPR_KY3B, //
+ SPR_HAND, //
+ SPR_CRYS, // 160
+ SPR_PRIS, //
+ SPR_PWR1, //
+ SPR_PWR2, //
+ SPR_PWR3, //
+ SPR_ORAC, // 165
+ SPR_GYID, //
+ SPR_FUBR, //
+ SPR_WARE, //
+ SPR_RCRY, //
+ SPR_BCRY, // 170
+ SPR_CHAP, //
+ SPR_TUNL, //
+ SPR_BLTK, //
+ SPR_SECK, //
+ SPR_MINE, // 175
+ SPR_REBL, //
+ SPR_PROC, //
+ SPR_ANKH, //
+ SPR_GOID, //
+ SPR_STMP, // 180
+ SPR_MDKT, //
+ SPR_COIN, //
+ SPR_CRED, //
+ SPR_SACK, //
+ SPR_CHST, // 185
+ SPR_SHD1, //
+ SPR_MASK, //
+ SPR_UNIF, //
+ SPR_OFIC, //
+ SPR_PMAP, // 190
+ SPR_PMUP, //
+ SPR_BLIT, //
+ SPR_BBOX, //
+ SPR_MSSL, //
+ SPR_ROKT, // 195
+ SPR_BRY1, //
+ SPR_CPAC, //
+ SPR_PQRL, //
+ SPR_XQRL, //
+ SPR_GRN1, // 200
+ SPR_GRN2, //
+ SPR_BKPK, //
+ SPR_RELC, //
+ SPR_RIFL, //
+ SPR_FLAM, // 205
+ SPR_BFLM, //
+ SPR_MMSL, //
+ SPR_TRPD, //
+ SPR_GRND, //
+ SPR_CBOW, // 210
+ SPR_SIGL, //
+ SPR_LITE, //
+ SPR_CNDL, //
+ SPR_CLBR, //
+ SPR_LITS, // 215
+ SPR_LITB, //
+ SPR_LITG, //
+ SPR_ROK1, //
+ SPR_ROK2, //
+ SPR_ROK3, // 220
+ SPR_ROK4, //
+ SPR_LOGG, //
+ SPR_RUB1, //
+ SPR_RUB2, //
+ SPR_RUB3, // 225
+ SPR_RUB4, //
+ SPR_RUB5, //
+ SPR_RUB6, //
+ SPR_RUB7, //
+ SPR_RUB8, // 230
+ SPR_CHAN, //
+ SPR_STAT, //
+ SPR_DSTA, //
+ SPR_CRAB, //
+ SPR_CAGE, // 235
+ SPR_TREE, //
+ SPR_TRE1, //
+ SPR_BUSH, //
+ SPR_SHRB, //
+ SPR_STAK, // 240
+ SPR_BAR1, //
+ SPR_VASE, //
+ SPR_STOL, //
+ SPR_POT1, //
+ SPR_TUB1, // 245
+ SPR_ANVL, //
+ SPR_TLMP, //
+ SPR_TRAY, //
+ SPR_APOW, //
+ SPR_AFED, // 250
+ SPR_DRIP, //
+ SPR_CDRP, //
+ SPR_SPLH, //
+ SPR_WTFT, //
+ SPR_HERT, //
+ SPR_TELP, //
+ SPR_MONI, //
+ SPR_STEL, //
+ SPR_STLA, //
+ SPR_STLE, // 260
+ SPR_HUGE, // 261
+ SPR_STLG, // 262
+ NUMSPRITES
+
+} spritenum_t;
+
+// villsa [STRIFE]
+typedef enum
+{
+ S_NULL, // 00
+ S_PNCH_00, // 01
+ S_WAVE_00, // 02
+ S_WAVE_01, // 03
+ S_WAVE_02, // 04
+ S_WAVE_03, // 05
+ S_RBPY_00, // 06
+ S_RBPY_01, // 07
+ S_RBPY_02, // 08
+ S_RBPY_03, // 09
+ S_TRGT_00, // 10
+ S_TRGT_01, // 11
+ S_TRGT_02, // 12
+ S_PNCH_01, // 13
+ S_PNCH_02, // 14
+ S_PNCH_03, // 15
+ S_PNCH_04, // 16
+ S_PNCH_05, // 17
+ S_PNCH_06, // 18
+ S_PNCH_07, // 19
+ S_PNCH_08, // 20
+ S_XBOW_00, // 21
+ S_XBOW_01, // 22
+ S_XBOW_02, // 23
+ S_XBOW_03, // 24
+ S_XBOW_04, // 25
+ S_XBOW_05, // 26
+ S_XBOW_06, // 27
+ S_XBOW_07, // 28
+ S_XBOW_08, // 29
+ S_XBOW_09, // 30
+ S_XBOW_10, // 31
+ S_XBOW_11, // 32
+ S_XBOW_12, // 33
+ S_XBOW_13, // 34
+ S_XBOW_14, // 35
+ S_XBOW_15, // 36
+ S_XBOW_16, // 37
+ S_XBOW_17, // 38
+ S_XBOW_18, // 39
+ S_XBOW_19, // 40
+ S_XBOW_20, // 41
+ S_XBOW_21, // 42
+ S_XBOW_22, // 43
+ S_MMIS_00, // 44
+ S_MMIS_01, // 45
+ S_MMIS_02, // 46
+ S_MMIS_03, // 47
+ S_MMIS_04, // 48
+ S_MMIS_05, // 49
+ S_MMIS_06, // 50
+ S_MMIS_07, // 51
+ S_MMIS_08, // 52
+ S_MMIS_09, // 53
+ S_RIFG_00, // 54
+ S_RIFG_01, // 55
+ S_RIFG_02, // 56
+ S_RIFF_00, // 57
+ S_RIFF_01, // 58
+ S_RIFG_03, // 59
+ S_RIFG_04, // 60
+ S_RIFG_05, // 61
+ S_FLMT_00, // 62
+ S_FLMT_01, // 63
+ S_FLMT_02, // 64
+ S_FLMT_03, // 65
+ S_FLMF_00, // 66
+ S_FLMF_01, // 67
+ S_BLST_00, // 68
+ S_BLST_01, // 69
+ S_BLST_02, // 70
+ S_BLST_03, // 71
+ S_BLST_04, // 72
+ S_BLST_05, // 73
+ S_BLSF_00, // 74
+ S_BLST_06, // 75
+ S_BLST_07, // 76
+ S_BLST_08, // 77
+ S_BLST_09, // 78
+ S_BLST_10, // 79
+ S_BLST_11, // 80
+ S_BLST_12, // 81
+ S_BLST_13, // 82
+ S_BLST_14, // 83
+ S_BLST_15, // 84
+ S_BLST_16, // 85
+ S_BLST_17, // 86
+ S_BLST_18, // 87
+ S_BLST_19, // 88
+ S_BLST_20, // 89
+ S_BLSF_01, // 90
+ S_BLST_21, // 91
+ S_BLST_22, // 92
+ S_BLST_23, // 93
+ S_BLST_24, // 94
+ S_GREN_00, // 95
+ S_GREN_01, // 96
+ S_GREN_02, // 97
+ S_GREN_03, // 98
+ S_GREN_04, // 99
+ S_GREN_05, // 100
+ S_GREN_06, // 101
+ S_GREN_07, // 102
+ S_GREF_00, // 103
+ S_GREF_01, // 104
+ S_GREF_02, // 105
+ S_GREN_08, // 106
+ S_GREN_09, // 107
+ S_GREN_10, // 108
+ S_GREN_11, // 109
+ S_GREN_12, // 110
+ S_GREN_13, // 111
+ S_GREN_14, // 112
+ S_GREN_15, // 113
+ S_GREF_03, // 114
+ S_GREF_04, // 115
+ S_GREF_05, // 116
+ S_SIGH_00, // 117
+ S_SIGH_01, // 118
+ S_SIGH_02, // 119
+ S_SIGH_03, // 120
+ S_SIGH_04, // 121
+ S_SIGH_05, // 122
+ S_SIGH_06, // 123
+ S_SIGH_07, // 124
+ S_SIGH_08, // 125
+ S_SIGH_09, // 126
+ S_SIGH_10, // 127
+ S_SIGF_00, // 128
+ S_SIGF_01, // 129
+ S_SIGF_02, // 130
+ S_POW1_00, // 131
+ S_POW1_01, // 132
+ S_POW1_02, // 133
+ S_POW1_03, // 134
+ S_POW1_04, // 135
+ S_POW1_05, // 136
+ S_POW1_06, // 137
+ S_POW1_07, // 138
+ S_POW1_08, // 139
+ S_POW1_09, // 140
+ S_POW2_00, // 141
+ S_POW2_01, // 142
+ S_POW2_02, // 143
+ S_POW2_03, // 144
+ S_POW3_00, // 145
+ S_POW3_01, // 146
+ S_POW3_02, // 147
+ S_POW3_03, // 148
+ S_POW3_04, // 149
+ S_POW3_05, // 150
+ S_POW3_06, // 151
+ S_POW3_07, // 152
+ S_ZAP1_00, // 153
+ S_ZAP1_01, // 154
+ S_ZAP1_02, // 155
+ S_ZAP1_03, // 156
+ S_ZAP1_04, // 157
+ S_ZAP1_05, // 158
+ S_ZAP1_06, // 159
+ S_ZAP1_07, // 160
+ S_ZAP1_08, // 161
+ S_ZAP1_09, // 162
+ S_ZAP1_10, // 163
+ S_ZAP1_11, // 164
+ S_SPRY_00, // 165
+ S_SPRY_01, // 166
+ S_SPRY_02, // 167
+ S_SPRY_03, // 168
+ S_SPRY_04, // 169
+ S_SPRY_05, // 170
+ S_SPRY_06, // 171
+ S_BLOD_00, // 172
+ S_BLOD_01, // 173
+ S_BLOD_02, // 174
+ S_PUFY_00, // 175
+ S_PUFY_01, // 176
+ S_PUFY_02, // 177
+ S_PUFY_03, // 178
+ S_SHT1_00, // 179
+ S_SHT1_01, // 180
+ S_SHT2_00, // 181
+ S_SHT2_01, // 182
+ S_GRIN_00, // 183
+ S_GRIN_01, // 184
+ S_GRAP_00, // 185
+ S_GRAP_01, // 186
+ S_UBAM_00, // 187
+ S_UBAM_01, // 188
+ S_BNG2_00, // 189
+ S_BNG2_01, // 190
+ S_BNG2_02, // 191
+ S_BNG2_03, // 192
+ S_BNG2_04, // 193
+ S_BNG2_05, // 194
+ S_BNG2_06, // 195
+ S_BNG2_07, // 196
+ S_BNG2_08, // 197
+ S_BNG4_00, // 198
+ S_BNG4_01, // 199
+ S_BNG4_02, // 200
+ S_BNG4_03, // 201
+ S_BNG4_04, // 202
+ S_BNG4_05, // 203
+ S_BNG4_06, // 204
+ S_BNG4_07, // 205
+ S_BNG4_08, // 206
+ S_BNG4_09, // 207
+ S_BNG4_10, // 208
+ S_BNG4_11, // 209
+ S_BNG4_12, // 210
+ S_BNG4_13, // 211
+ S_BNG3_00, // 212
+ S_BNG3_01, // 213
+ S_BNG3_02, // 214
+ S_BNG3_03, // 215
+ S_BNG3_04, // 216
+ S_BNG3_05, // 217
+ S_BNG3_06, // 218
+ S_BNG3_07, // 219
+ S_BNG3_08, // 220
+ S_BNG3_09, // 221
+ S_BNG3_10, // 222
+ S_FLBE_00, // 223
+ S_FLBE_01, // 224
+ S_FLBE_02, // 225
+ S_FLBE_03, // 226
+ S_FLBE_04, // 227
+ S_FLBE_05, // 228
+ S_FLBE_06, // 229
+ S_FLBE_07, // 230
+ S_FLBE_08, // 231
+ S_FLBE_09, // 232
+ S_FLBE_10, // 233
+ S_XPRK_00, // 234
+ S_OCLW_00, // 235
+ S_CCLW_00, // 236
+ S_TEND_00, // 237
+ S_MICR_00, // 238
+ S_MISS_00, // 239
+ S_MISS_01, // 240
+ S_AROW_00, // 241
+ S_ARWP_00, // 242
+ S_AROW_01, // 243
+ S_TORP_00, // 244
+ S_TORP_01, // 245
+ S_TORP_02, // 246
+ S_TORP_03, // 247
+ S_THIT_00, // 248
+ S_THIT_01, // 249
+ S_THIT_02, // 250
+ S_THIT_03, // 251
+ S_THIT_04, // 252
+ S_TWAV_00, // 253
+ S_TWAV_01, // 254
+ S_TWAV_02, // 255
+ S_MISL_00, // 256
+ S_MISL_01, // 257
+ S_MISL_02, // 258
+ S_MISL_03, // 259
+ S_MISL_04, // 260
+ S_MISL_05, // 261
+ S_MISL_06, // 262
+ S_MISL_07, // 263
+ S_TFOG_00, // 264
+ S_TFOG_01, // 265
+ S_TFOG_02, // 266
+ S_TFOG_03, // 267
+ S_TFOG_04, // 268
+ S_TFOG_05, // 269
+ S_TFOG_06, // 270
+ S_TFOG_07, // 271
+ S_TFOG_08, // 272
+ S_TFOG_09, // 273
+ S_IFOG_00, // 274
+ S_IFOG_01, // 275
+ S_IFOG_02, // 276
+ S_IFOG_03, // 277
+ S_IFOG_04, // 278
+ S_IFOG_05, // 279
+ S_IFOG_06, // 280
+ S_SHRD_00, // 281
+ S_SHRD_01, // 282
+ S_SHRD_02, // 283
+ S_SHRD_03, // 284
+ S_SHRD_04, // 285
+ S_SHRD_05, // 286
+ S_PLAY_00, // 287
+ S_PLAY_01, // 288
+ S_PLAY_02, // 289
+ S_PLAY_03, // 290
+ S_PLAY_04, // 291
+ S_PLAY_05, // 292
+ S_PLAY_06, // 293
+ S_PLAY_07, // 294
+ S_PLAY_08, // 295
+ S_PLAY_09, // 296
+ S_PLAY_10, // 297
+ S_PLAY_11, // 298
+ S_PLAY_12, // 299
+ S_PLAY_13, // 300
+ S_PLAY_14, // 301
+ S_PLAY_15, // 302
+ S_PLAY_16, // 303
+ S_PLAY_17, // 304
+ S_PLAY_18, // 305
+ S_RGIB_00, // 306
+ S_RGIB_01, // 307
+ S_RGIB_02, // 308
+ S_RGIB_03, // 309
+ S_RGIB_04, // 310
+ S_RGIB_05, // 311
+ S_RGIB_06, // 312
+ S_RGIB_07, // 313
+ S_MRYS_00, // 314
+ S_MRNO_00, // 315
+ S_MRNO_01, // 316
+ S_MRNO_02, // 317
+ S_MRNO_03, // 318
+ S_MRNO_04, // 319
+ S_MRST_00, // 320
+ S_MRLK_00, // 321
+ S_MRLK_01, // 322
+ S_MRBD_00, // 323
+ S_MRBD_01, // 324
+ S_MRBD_02, // 325
+ S_MRBD_03, // 326
+ S_MRBD_04, // 327
+ S_MRBD_05, // 328
+ S_MRBD_06, // 329
+ S_MRBD_07, // 330
+ S_MRBD_08, // 331
+ S_MRBD_09, // 332
+ S_MRPN_00, // 333
+ S_MRPN_01, // 334
+ S_MRPN_02, // 335
+ S_MRPN_03, // 336
+ S_MRPN_04, // 337
+ S_MRPN_05, // 338
+ S_MRPN_06, // 339
+ S_MRGT_00, // 340
+ S_MRGT_01, // 341
+ S_MRGT_02, // 342
+ S_MRGT_03, // 343
+ S_MRGT_04, // 344
+ S_MRGT_05, // 345
+ S_MRGT_06, // 346
+ S_MRGT_07, // 347
+ S_MRGT_08, // 348
+ S_BURN_00, // 349
+ S_BURN_01, // 350
+ S_BURN_02, // 351
+ S_BURN_03, // 352
+ S_BURN_04, // 353
+ S_BURN_05, // 354
+ S_BURN_06, // 355
+ S_BURN_07, // 356
+ S_BURN_08, // 357
+ S_BURN_09, // 358
+ S_BURN_10, // 359
+ S_BURN_11, // 360
+ S_BURN_12, // 361
+ S_BURN_13, // 362
+ S_BURN_14, // 363
+ S_BURN_15, // 364
+ S_BURN_16, // 365
+ S_BURN_17, // 366
+ S_BURN_18, // 367
+ S_BURN_19, // 368
+ S_BURN_20, // 369
+ S_BURN_21, // 370
+ S_BURN_22, // 371
+ S_BURN_23, // 372
+ S_DISR_00, // 373
+ S_DISR_01, // 374
+ S_DISR_02, // 375
+ S_DISR_03, // 376
+ S_DISR_04, // 377
+ S_DISR_05, // 378
+ S_DISR_06, // 379
+ S_DISR_07, // 380
+ S_DISR_08, // 381
+ S_DISR_09, // 382
+ S_PEAS_00, // 383
+ S_PEAS_01, // 384
+ S_PEAS_02, // 385
+ S_PEAS_03, // 386
+ S_PEAS_04, // 387
+ S_PEAS_05, // 388
+ S_PEAS_06, // 389
+ S_PEAS_07, // 390
+ S_PEAS_08, // 391
+ S_PEAS_09, // 392
+ S_PEAS_10, // 393
+ S_PEAS_11, // 394
+ S_PEAS_12, // 395
+ S_PEAS_13, // 396
+ S_PEAS_14, // 397
+ S_PEAS_15, // 398
+ S_PEAS_16, // 399
+ S_PEAS_17, // 400
+ S_PEAS_18, // 401
+ S_PEAS_19, // 402
+ S_PEAS_20, // 403
+ S_PEAS_21, // 404
+ S_PEAS_22, // 405
+ S_PEAS_23, // 406
+ S_PEAS_24, // 407
+ S_GIBS_00, // 408
+ S_GIBS_01, // 409
+ S_GIBS_02, // 410
+ S_GIBS_03, // 411
+ S_GIBS_04, // 412
+ S_GIBS_05, // 413
+ S_GIBS_06, // 414
+ S_GIBS_07, // 415
+ S_GIBS_08, // 416
+ S_GIBS_09, // 417
+ S_PEAS_25, // 418
+ S_AGRD_00, // 419
+ S_ARMR_00, // 420
+ S_ARMR_01, // 421
+ S_PLAY_19, // 422
+ S_SACR_00, // 423
+ S_TNK1_00, // 424
+ S_TNK1_01, // 425
+ S_TNK1_02, // 426
+ S_TNK2_00, // 427
+ S_TNK2_01, // 428
+ S_TNK2_02, // 429
+ S_TNK3_00, // 430
+ S_TNK3_01, // 431
+ S_TNK3_02, // 432
+ S_TNK4_00, // 433
+ S_TNK4_01, // 434
+ S_TNK4_02, // 435
+ S_TNK5_00, // 436
+ S_TNK5_01, // 437
+ S_TNK5_02, // 438
+ S_TNK6_00, // 439
+ S_TNK6_01, // 440
+ S_TNK6_02, // 441
+ S_NEAL_00, // 442
+ S_NEAL_01, // 443
+ S_NEAL_02, // 444
+ S_NEAL_03, // 445
+ S_NEAL_04, // 446
+ S_NEAL_05, // 447
+ S_NEAL_06, // 448
+ S_NEAL_07, // 449
+ S_NEAL_08, // 450
+ S_NEAL_09, // 451
+ S_NEAL_10, // 452
+ S_NEAL_11, // 453
+ S_NEAL_12, // 454
+ S_NEAL_13, // 455
+ S_BEGR_00, // 456
+ S_BEGR_01, // 457
+ S_BEGR_02, // 458
+ S_BEGR_03, // 459
+ S_BEGR_04, // 460
+ S_BEGR_05, // 461
+ S_BEGR_06, // 462
+ S_BEGR_07, // 463
+ S_BEGR_08, // 464
+ S_BEGR_09, // 465
+ S_BEGR_10, // 466
+ S_BEGR_11, // 467
+ S_BEGR_12, // 468
+ S_BEGR_13, // 469
+ S_BEGR_14, // 470
+ S_BEGR_15, // 471
+ S_BEGR_16, // 472
+ S_BEGR_17, // 473
+ S_BEGR_18, // 474
+ S_BEGR_19, // 475
+ S_BEGR_20, // 476
+ S_BEGR_21, // 477
+ S_BEGR_22, // 478
+ S_HMN1_00, // 479
+ S_HMN1_01, // 480
+ S_HMN1_02, // 481
+ S_HMN1_03, // 482
+ S_HMN1_04, // 483
+ S_HMN1_05, // 484
+ S_HMN1_06, // 485
+ S_HMN1_07, // 486
+ S_HMN1_08, // 487
+ S_HMN1_09, // 488
+ S_HMN1_10, // 489
+ S_HMN1_11, // 490
+ S_HMN1_12, // 491
+ S_HMN1_13, // 492
+ S_HMN1_14, // 493
+ S_HMN1_15, // 494
+ S_HMN1_16, // 495
+ S_HMN1_17, // 496
+ S_HMN1_18, // 497
+ S_HMN1_19, // 498
+ S_HMN1_20, // 499
+ S_HMN1_21, // 500
+ S_HMN1_22, // 501
+ S_HMN1_23, // 502
+ S_HMN1_24, // 503
+ S_HMN1_25, // 504
+ S_HMN1_26, // 505
+ S_HMN1_27, // 506
+ S_HMN1_28, // 507
+ S_HMN1_29, // 508
+ S_HMN1_30, // 509
+ S_HMN1_31, // 510
+ S_RGIB_08, // 511
+ S_RGIB_09, // 512
+ S_RGIB_10, // 513
+ S_RGIB_11, // 514
+ S_RGIB_12, // 515
+ S_RGIB_13, // 516
+ S_RGIB_14, // 517
+ S_RGIB_15, // 518
+ S_LEDR_00, // 519
+ S_LEDR_01, // 520
+ S_LEDR_02, // 521
+ S_LEAD_00, // 522
+ S_LEAD_01, // 523
+ S_LEAD_02, // 524
+ S_LEAD_03, // 525
+ S_LEAD_04, // 526
+ S_LEAD_05, // 527
+ S_LEAD_06, // 528
+ S_LEAD_07, // 529
+ S_LEAD_08, // 530
+ S_LEAD_09, // 531
+ S_LEAD_10, // 532
+ S_LEAD_11, // 533
+ S_LEAD_12, // 534
+ S_LEAD_13, // 535
+ S_LEAD_14, // 536
+ S_LEAD_15, // 537
+ S_LEAD_16, // 538
+ S_LEAD_17, // 539
+ S_LEAD_18, // 540
+ S_LEAD_19, // 541
+ S_LEAD_20, // 542
+ S_LEAD_21, // 543
+ S_LEAD_22, // 544
+ S_LEAD_23, // 545
+ S_LEAD_24, // 546
+ S_LEAD_25, // 547
+ S_LEAD_26, // 548
+ S_LEAD_27, // 549
+ S_LEAD_28, // 550
+ S_LEAD_29, // 551
+ S_LEAD_30, // 552
+ S_LEAD_31, // 553
+ S_LEAD_32, // 554
+ S_LEAD_33, // 555
+ S_LEAD_34, // 556
+ S_LEAD_35, // 557
+ S_LEAD_36, // 558
+ S_LEAD_37, // 559
+ S_PUFY_04, // 560
+ S_PUFY_05, // 561
+ S_PUFY_06, // 562
+ S_PUFY_07, // 563
+ S_PUFY_08, // 564
+ S_MICR_01, // 565
+ S_MICR_02, // 566
+ S_ROB1_00, // 567
+ S_ROB1_01, // 568
+ S_ROB1_02, // 569
+ S_ROB1_03, // 570
+ S_ROB1_04, // 571
+ S_ROB1_05, // 572
+ S_ROB1_06, // 573
+ S_ROB1_07, // 574
+ S_ROB1_08, // 575
+ S_ROB1_09, // 576
+ S_ROB1_10, // 577
+ S_ROB1_11, // 578
+ S_ROB1_12, // 579
+ S_ROB1_13, // 580
+ S_ROB1_14, // 581
+ S_ROB1_15, // 582
+ S_ROB1_16, // 583
+ S_ROB1_17, // 584
+ S_ROB1_18, // 585
+ S_ROB1_19, // 586
+ S_ROB1_20, // 587
+ S_ROB1_21, // 588
+ S_ROB1_22, // 589
+ S_ROB1_23, // 590
+ S_ROB1_24, // 591
+ S_ROB1_25, // 592
+ S_ROB1_26, // 593
+ S_ROB1_27, // 594
+ S_ROB1_28, // 595
+ S_ROB1_29, // 596
+ S_ROB1_30, // 597
+ S_ROB1_31, // 598
+ S_ROB1_32, // 599
+ S_AGRD_01, // 600
+ S_AGRD_02, // 601
+ S_AGRD_03, // 602
+ S_AGRD_04, // 603
+ S_AGRD_05, // 604
+ S_AGRD_06, // 605
+ S_AGRD_07, // 606
+ S_AGRD_08, // 607
+ S_AGRD_09, // 608
+ S_AGRD_10, // 609
+ S_AGRD_11, // 610
+ S_AGRD_12, // 611
+ S_AGRD_13, // 612
+ S_AGRD_14, // 613
+ S_AGRD_15, // 614
+ S_AGRD_16, // 615
+ S_AGRD_17, // 616
+ S_AGRD_18, // 617
+ S_AGRD_19, // 618
+ S_AGRD_20, // 619
+ S_AGRD_21, // 620
+ S_AGRD_22, // 621
+ S_AGRD_23, // 622
+ S_AGRD_24, // 623
+ S_AGRD_25, // 624
+ S_AGRD_26, // 625
+ S_AGRD_27, // 626
+ S_AGRD_28, // 627
+ S_AGRD_29, // 628
+ S_AGRD_30, // 629
+ S_AGRD_31, // 630
+ S_GIBS_10, // 631
+ S_GIBS_11, // 632
+ S_GIBS_12, // 633
+ S_GIBS_13, // 634
+ S_GIBS_14, // 635
+ S_GIBS_15, // 636
+ S_GIBS_16, // 637
+ S_GIBS_17, // 638
+ S_GIBS_18, // 639
+ S_GIBS_19, // 640
+ S_GIBS_20, // 641
+ S_GIBS_21, // 642
+ S_PGRD_00, // 643
+ S_PGRD_01, // 644
+ S_PGRD_02, // 645
+ S_PGRD_03, // 646
+ S_PGRD_04, // 647
+ S_PGRD_05, // 648
+ S_PGRD_06, // 649
+ S_PGRD_07, // 650
+ S_PGRD_08, // 651
+ S_PGRD_09, // 652
+ S_PGRD_10, // 653
+ S_PGRD_11, // 654
+ S_PGRD_12, // 655
+ S_PGRD_13, // 656
+ S_PGRD_14, // 657
+ S_PGRD_15, // 658
+ S_PGRD_16, // 659
+ S_PGRD_17, // 660
+ S_PGRD_18, // 661
+ S_PGRD_19, // 662
+ S_PGRD_20, // 663
+ S_PGRD_21, // 664
+ S_PGRD_22, // 665
+ S_PGRD_23, // 666
+ S_PGRD_24, // 667
+ S_PGRD_25, // 668
+ S_PGRD_26, // 669
+ S_PGRD_27, // 670
+ S_PGRD_28, // 671
+ S_PGRD_29, // 672
+ S_PGRD_30, // 673
+ S_PGRD_31, // 674
+ S_PGRD_32, // 675
+ S_PGRD_33, // 676
+ S_PGRD_34, // 677
+ S_PGRD_35, // 678
+ S_PGRD_36, // 679
+ S_PGRD_37, // 680
+ S_ROB2_00, // 681
+ S_ROB2_01, // 682
+ S_ROB2_02, // 683
+ S_ROB2_03, // 684
+ S_ROB2_04, // 685
+ S_ROB2_05, // 686
+ S_ROB2_06, // 687
+ S_ROB2_07, // 688
+ S_ROB2_08, // 689
+ S_ROB2_09, // 690
+ S_ROB2_10, // 691
+ S_ROB2_11, // 692
+ S_ROB2_12, // 693
+ S_ROB2_13, // 694
+ S_ROB2_14, // 695
+ S_ROB2_15, // 696
+ S_ROB2_16, // 697
+ S_ROB2_17, // 698
+ S_ROB2_18, // 699
+ S_ROB2_19, // 700
+ S_ROB2_20, // 701
+ S_ROB2_21, // 702
+ S_ROB2_22, // 703
+ S_ROB2_23, // 704
+ S_ROB2_24, // 705
+ S_ROB2_25, // 706
+ S_ROB2_26, // 707
+ S_ROB2_27, // 708
+ S_ROB2_28, // 709
+ S_ROB2_29, // 710
+ S_MLDR_00, // 711
+ S_MLDR_01, // 712
+ S_MLDR_02, // 713
+ S_MLDR_03, // 714
+ S_MLDR_04, // 715
+ S_MLDR_05, // 716
+ S_MLDR_06, // 717
+ S_MLDR_07, // 718
+ S_MLDR_08, // 719
+ S_MLDR_09, // 720
+ S_MLDR_10, // 721
+ S_MLDR_11, // 722
+ S_MLDR_12, // 723
+ S_MLDR_13, // 724
+ S_MLDR_14, // 725
+ S_MLDR_15, // 726
+ S_MLDR_16, // 727
+ S_MLDR_17, // 728
+ S_MLDR_18, // 729
+ S_MLDR_19, // 730
+ S_MLDR_20, // 731
+ S_MLDR_21, // 732
+ S_MLDR_22, // 733
+ S_MLDR_23, // 734
+ S_MLDR_24, // 735
+ S_MLDR_25, // 736
+ S_MLDR_26, // 737
+ S_MLDR_27, // 738
+ S_ORCL_00, // 739
+ S_ORCL_01, // 740
+ S_ORCL_02, // 741
+ S_ORCL_03, // 742
+ S_ORCL_04, // 743
+ S_ORCL_05, // 744
+ S_ORCL_06, // 745
+ S_ORCL_07, // 746
+ S_ORCL_08, // 747
+ S_ORCL_09, // 748
+ S_ORCL_10, // 749
+ S_ORCL_11, // 750
+ S_ORCL_12, // 751
+ S_ORCL_13, // 752
+ S_ORCL_14, // 753
+ S_ORCL_15, // 754
+ S_ORCL_16, // 755
+ S_PRST_00, // 756
+ S_PRST_01, // 757
+ S_PRST_02, // 758
+ S_PRST_03, // 759
+ S_PRST_04, // 760
+ S_PRST_05, // 761
+ S_PRST_06, // 762
+ S_PRST_07, // 763
+ S_PRST_08, // 764
+ S_PRST_09, // 765
+ S_PRST_10, // 766
+ S_PRST_11, // 767
+ S_PRST_12, // 768
+ S_PRST_13, // 769
+ S_PRST_14, // 770
+ S_PRST_15, // 771
+ S_PDED_00, // 772
+ S_PDED_01, // 773
+ S_PDED_02, // 774
+ S_PDED_03, // 775
+ S_PDED_04, // 776
+ S_PDED_05, // 777
+ S_PDED_06, // 778
+ S_PDED_07, // 779
+ S_PDED_08, // 780
+ S_PDED_09, // 781
+ S_PDED_10, // 782
+ S_PDED_11, // 783
+ S_PDED_12, // 784
+ S_PDED_13, // 785
+ S_PDED_14, // 786
+ S_PDED_15, // 787
+ S_PDED_16, // 788
+ S_PDED_17, // 789
+ S_PDED_18, // 790
+ S_PDED_19, // 791
+ S_PDED_20, // 792
+ S_PDED_21, // 793
+ S_PDED_22, // 794
+ S_PDED_23, // 795
+ S_ALN1_00, // 796
+ S_ALN1_01, // 797
+ S_ALN1_02, // 798
+ S_ALN1_03, // 799
+ S_ALN1_04, // 800
+ S_ALN1_05, // 801
+ S_ALN1_06, // 802
+ S_ALN1_07, // 803
+ S_ALN1_08, // 804
+ S_ALN1_09, // 805
+ S_ALN1_10, // 806
+ S_ALN1_11, // 807
+ S_ALN1_12, // 808
+ S_ALN1_13, // 809
+ S_ALN1_14, // 810
+ S_ALN1_15, // 811
+ S_ALN1_16, // 812
+ S_ALN1_17, // 813
+ S_ALN1_18, // 814
+ S_ALN1_19, // 815
+ S_AL1P_00, // 816
+ S_AL1P_01, // 817
+ S_AL1P_02, // 818
+ S_AL1P_03, // 819
+ S_AL1P_04, // 820
+ S_AL1P_05, // 821
+ S_AL1P_06, // 822
+ S_AL1P_07, // 823
+ S_AL1P_08, // 824
+ S_AL1P_09, // 825
+ S_AL1P_10, // 826
+ S_AL1P_11, // 827
+ S_AL1P_12, // 828
+ S_AL1P_13, // 829
+ S_AL1P_14, // 830
+ S_AL1P_15, // 831
+ S_AL1P_16, // 832
+ S_AL1P_17, // 833
+ S_NODE_00, // 834
+ S_NODE_01, // 835
+ S_NODE_02, // 836
+ S_NODE_03, // 837
+ S_NODE_04, // 838
+ S_NODE_05, // 839
+ S_NODE_06, // 840
+ S_MTHD_00, // 841
+ S_MTHD_01, // 842
+ S_MTHD_02, // 843
+ S_MTHD_03, // 844
+ S_MTHD_04, // 845
+ S_MTHD_05, // 846
+ S_MTHD_06, // 847
+ S_MTHD_07, // 848
+ S_MTHD_08, // 849
+ S_MTHD_09, // 850
+ S_MTHD_10, // 851
+ S_ALN1_20, // 852
+ S_ALN1_21, // 853
+ S_ALN1_22, // 854
+ S_ALN1_23, // 855
+ S_ALN1_24, // 856
+ S_ALN1_25, // 857
+ S_ALN1_26, // 858
+ S_ALN1_27, // 859
+ S_ALN1_28, // 860
+ S_ALN1_29, // 861
+ S_ALN1_30, // 862
+ S_ALN1_31, // 863
+ S_ALN1_32, // 864
+ S_ALN1_33, // 865
+ S_ALN1_34, // 866
+ S_ALN1_35, // 867
+ S_ALN1_36, // 868
+ S_ALN1_37, // 869
+ S_ALN1_38, // 870
+ S_ALN1_39, // 871
+ S_ALN1_40, // 872
+ S_ALN1_41, // 873
+ S_ALN1_42, // 874
+ S_ALN1_43, // 875
+ S_ALN1_44, // 876
+ S_ALN1_45, // 877
+ S_ALN1_46, // 878
+ S_ALN1_47, // 879
+ S_ALN1_48, // 880
+ S_ALN1_49, // 881
+ S_ALN1_50, // 882
+ S_ALN1_51, // 883
+ S_ALN1_52, // 884
+ S_ALN1_53, // 885
+ S_ALN1_54, // 886
+ S_ALN1_55, // 887
+ S_ALN1_56, // 888
+ S_ALN1_57, // 889
+ S_MNAM_00, // 890
+ S_MNAM_01, // 891
+ S_MNAM_02, // 892
+ S_MNAM_03, // 893
+ S_MNAM_04, // 894
+ S_MNAM_05, // 895
+ S_MNAM_06, // 896
+ S_MNAM_07, // 897
+ S_MNAM_08, // 898
+ S_MNAM_09, // 899
+ S_MNAM_10, // 900
+ S_MNAM_11, // 901
+ S_MNAL_00, // 902
+ S_MNAL_01, // 903
+ S_MNAL_02, // 904
+ S_MNAL_03, // 905
+ S_MNAL_04, // 906
+ S_MNAL_05, // 907
+ S_MNAL_06, // 908
+ S_MNAL_07, // 909
+ S_MNAL_08, // 910
+ S_MNAL_09, // 911
+ S_MNAL_10, // 912
+ S_MNAL_11, // 913
+ S_MNAL_12, // 914
+ S_MNAL_13, // 915
+ S_MNAL_14, // 916
+ S_MNAL_15, // 917
+ S_MNAL_16, // 918
+ S_MNAL_17, // 919
+ S_MNAL_18, // 920
+ S_MNAL_19, // 921
+ S_MNAL_20, // 922
+ S_MNAL_21, // 923
+ S_MNAL_22, // 924
+ S_MNAL_23, // 925
+ S_MNAL_24, // 926
+ S_MNAL_25, // 927
+ S_MNAL_26, // 928
+ S_MNAL_27, // 929
+ S_MNAL_28, // 930
+ S_MNAL_29, // 931
+ S_MNAL_30, // 932
+ S_MNAL_31, // 933
+ S_MNAL_32, // 934
+ S_MNAL_33, // 935
+ S_MNAL_34, // 936
+ S_MNAL_35, // 937
+ S_MNAL_36, // 938
+ S_MNAL_37, // 939
+ S_MNAL_38, // 940
+ S_MNAL_39, // 941
+ S_MNAL_40, // 942
+ S_MDTH_00, // 943
+ S_MDTH_01, // 944
+ S_MDTH_02, // 945
+ S_MDTH_03, // 946
+ S_MDTH_04, // 947
+ S_MDTH_05, // 948
+ S_MDTH_06, // 949
+ S_MDTH_07, // 950
+ S_MDTH_08, // 951
+ S_MDTH_09, // 952
+ S_MDTH_10, // 953
+ S_MDTH_11, // 954
+ S_MDTH_12, // 955
+ S_MDTH_13, // 956
+ S_MDTH_14, // 957
+ S_NEST_00, // 958
+ S_PODD_00, // 959
+ S_PODD_01, // 960
+ S_PODD_02, // 961
+ S_PODD_03, // 962
+ S_PODD_04, // 963
+ S_PODD_05, // 964
+ S_ZAP6_00, // 965
+ S_ZAP6_01, // 966
+ S_ZAP6_02, // 967
+ S_ZOT3_00, // 968
+ S_ZOT3_01, // 969
+ S_ZOT3_02, // 970
+ S_ZOT3_03, // 971
+ S_ZOT3_04, // 972
+ S_ZAP6_03, // 973
+ S_ZAP6_04, // 974
+ S_ZAP6_05, // 975
+ S_ZAP7_00, // 976
+ S_ZAP7_01, // 977
+ S_ZAP7_02, // 978
+ S_ZAP7_03, // 979
+ S_ZAP7_04, // 980
+ S_ZOT1_00, // 981
+ S_ZOT1_01, // 982
+ S_ZOT1_02, // 983
+ S_ZOT1_03, // 984
+ S_ZOT1_04, // 985
+ S_ZAP5_00, // 986
+ S_ZAP5_01, // 987
+ S_ZAP5_02, // 988
+ S_ZAP5_03, // 989
+ S_ZOT2_00, // 990
+ S_ZOT2_01, // 991
+ S_ZOT2_02, // 992
+ S_ZOT2_03, // 993
+ S_ZOT2_04, // 994
+ S_SEWR_00, // 995
+ S_SEWR_01, // 996
+ S_SEWR_02, // 997
+ S_SEWR_03, // 998
+ S_SEWR_04, // 999
+ S_SEWR_05, // 1000
+ S_SEWR_06, // 1001
+ S_SEWR_07, // 1002
+ S_SEWR_08, // 1003
+ S_SEWR_09, // 1004
+ S_SEWR_10, // 1005
+ S_SEWR_11, // 1006
+ S_SEWR_12, // 1007
+ S_SEWR_13, // 1008
+ S_SPID_00, // 1009
+ S_SPID_01, // 1010
+ S_SPID_02, // 1011
+ S_SPID_03, // 1012
+ S_SPID_04, // 1013
+ S_SPID_05, // 1014
+ S_SPID_06, // 1015
+ S_SPID_07, // 1016
+ S_SPID_08, // 1017
+ S_SPID_09, // 1018
+ S_SPID_10, // 1019
+ S_SPID_11, // 1020
+ S_SPID_12, // 1021
+ S_SPID_13, // 1022
+ S_SPID_14, // 1023
+ S_SPID_15, // 1024
+ S_SPID_16, // 1025
+ S_SPID_17, // 1026
+ S_SPID_18, // 1027
+ S_SPID_19, // 1028
+ S_SPID_20, // 1029
+ S_SPID_21, // 1030
+ S_SPID_22, // 1031
+ S_SPID_23, // 1032
+ S_SPID_24, // 1033
+ S_SPID_25, // 1034
+ S_SPID_26, // 1035
+ S_SPID_27, // 1036
+ S_SPID_28, // 1037
+ S_SPID_29, // 1038
+ S_SPID_30, // 1039
+ S_SPID_31, // 1040
+ S_SPID_32, // 1041
+ S_SPID_33, // 1042
+ S_SPID_34, // 1043
+ S_SPID_35, // 1044
+ S_SPID_36, // 1045
+ S_SPID_37, // 1046
+ S_ROB3_00, // 1047
+ S_ROB3_01, // 1048
+ S_ROB3_02, // 1049
+ S_ROB3_03, // 1050
+ S_ROB3_04, // 1051
+ S_ROB3_05, // 1052
+ S_ROB3_06, // 1053
+ S_ROB3_07, // 1054
+ S_ROB3_08, // 1055
+ S_ROB3_09, // 1056
+ S_ROB3_10, // 1057
+ S_ROB3_11, // 1058
+ S_ROB3_12, // 1059
+ S_ROB3_13, // 1060
+ S_ROB3_14, // 1061
+ S_ROB3_15, // 1062
+ S_ROB3_16, // 1063
+ S_ROB3_17, // 1064
+ S_ROB3_18, // 1065
+ S_ROB3_19, // 1066
+ S_ROB3_20, // 1067
+ S_ROB3_21, // 1068
+ S_ROB3_22, // 1069
+ S_ROB3_23, // 1070
+ S_ROB3_24, // 1071
+ S_ROB3_25, // 1072
+ S_ROB3_26, // 1073
+ S_ROB3_27, // 1074
+ S_ROB3_28, // 1075
+ S_ROB3_29, // 1076
+ S_ROB3_30, // 1077
+ S_ROB3_31, // 1078
+ S_ROB3_32, // 1079
+ S_ROB3_33, // 1080
+ S_ROB3_34, // 1081
+ S_ROB3_35, // 1082
+ S_ROB3_36, // 1083
+ S_ROB3_37, // 1084
+ S_RBB3_00, // 1085
+ S_RBB3_01, // 1086
+ S_RBB3_02, // 1087
+ S_RBB3_03, // 1088
+ S_RBB3_04, // 1089
+ S_RBB3_05, // 1090
+ S_RBB3_06, // 1091
+ S_RBB3_07, // 1092
+ S_PRGR_00, // 1093
+ S_PRGR_01, // 1094
+ S_PRGR_02, // 1095
+ S_PRGR_03, // 1096
+ S_PRGR_04, // 1097
+ S_PRGR_05, // 1098
+ S_PRGR_06, // 1099
+ S_PRGR_07, // 1100
+ S_PRGR_08, // 1101
+ S_PRGR_09, // 1102
+ S_PRGR_10, // 1103
+ S_PRGR_11, // 1104
+ S_PRGR_12, // 1105
+ S_PRGR_13, // 1106
+ S_PRGR_14, // 1107
+ S_PRGR_15, // 1108
+ S_PRGR_16, // 1109
+ S_PRGR_17, // 1110
+ S_PRGR_18, // 1111
+ S_PRGR_19, // 1112
+ S_PRGR_20, // 1113
+ S_PRGR_21, // 1114
+ S_PRGR_22, // 1115
+ S_PRGR_23, // 1116
+ S_PRGR_24, // 1117
+ S_PRGR_25, // 1118
+ S_PRGR_26, // 1119
+ S_PRGR_27, // 1120
+ S_PRGR_28, // 1121
+ S_PRGR_29, // 1122
+ S_PRGR_30, // 1123
+ S_PRGR_31, // 1124
+ S_PRGR_32, // 1125
+ S_PRGR_33, // 1126
+ S_BASE_00, // 1127
+ S_BASE_01, // 1128
+ S_BASE_02, // 1129
+ S_BASE_03, // 1130
+ S_BASE_04, // 1131
+ S_BASE_05, // 1132
+ S_BASE_06, // 1133
+ S_BASE_07, // 1134
+ S_FRBL_00, // 1135
+ S_FRBL_01, // 1136
+ S_FRBL_02, // 1137
+ S_FRBL_03, // 1138
+ S_FRBL_04, // 1139
+ S_FRBL_05, // 1140
+ S_FRBL_06, // 1141
+ S_FRBL_07, // 1142
+ S_FRBL_08, // 1143
+ S_KLAX_00, // 1144
+ S_KLAX_01, // 1145
+ S_KLAX_02, // 1146
+ S_TURT_00, // 1147
+ S_TURT_01, // 1148
+ S_TURT_02, // 1149
+ S_TURT_03, // 1150
+ S_TURT_04, // 1151
+ S_BALL_00, // 1152
+ S_BALL_01, // 1153
+ S_BALL_02, // 1154
+ S_BALL_03, // 1155
+ S_BALL_04, // 1156
+ S_TURT_05, // 1157
+ S_PSTN_00, // 1158
+ S_PSTN_01, // 1159
+ S_PSTN_02, // 1160
+ S_PSTN_03, // 1161
+ S_PSTN_04, // 1162
+ S_PSTN_05, // 1163
+ S_PSTN_06, // 1164
+ S_PSTN_07, // 1165
+ S_PSTN_08, // 1166
+ S_PSTN_09, // 1167
+ S_PSTN_10, // 1168
+ S_SECR_00, // 1169
+ S_SECR_01, // 1170
+ S_SECR_02, // 1171
+ S_SECR_03, // 1172
+ S_SECR_04, // 1173
+ S_SECR_05, // 1174
+ S_SECR_06, // 1175
+ S_SECR_07, // 1176
+ S_SECR_08, // 1177
+ S_SECR_09, // 1178
+ S_SECR_10, // 1179
+ S_SECR_11, // 1180
+ S_SECR_12, // 1181
+ S_SECR_13, // 1182
+ S_SECR_14, // 1183
+ S_SECR_15, // 1184
+ S_XPRK_01, // 1185
+ S_XPRK_02, // 1186
+ S_TARG_00, // 1187
+ S_RING_00, // 1188
+ S_EARS_00, // 1189
+ S_COMM_00, // 1190
+ S_BOOM_00, // 1191
+ S_BOOM_01, // 1192
+ S_BOOM_02, // 1193
+ S_BOOM_03, // 1194
+ S_BOOM_04, // 1195
+ S_BOOM_05, // 1196
+ S_BOOM_06, // 1197
+ S_BOOM_07, // 1198
+ S_BOOM_08, // 1199
+ S_BOOM_09, // 1200
+ S_BOOM_10, // 1201
+ S_BOOM_11, // 1202
+ S_BOOM_12, // 1203
+ S_BOOM_13, // 1204
+ S_BOOM_14, // 1205
+ S_BOOM_15, // 1206
+ S_BOOM_16, // 1207
+ S_BOOM_17, // 1208
+ S_BOOM_18, // 1209
+ S_BOOM_19, // 1210
+ S_BOOM_20, // 1211
+ S_BOOM_21, // 1212
+ S_BOOM_22, // 1213
+ S_BOOM_23, // 1214
+ S_BOOM_24, // 1215
+ S_RATT_00, // 1216
+ S_RATT_01, // 1217
+ S_RATT_02, // 1218
+ S_RATT_03, // 1219
+ S_RATT_04, // 1220
+ S_RATT_05, // 1221
+ S_RATT_06, // 1222
+ S_HOGN_00, // 1223
+ S_HOGN_01, // 1224
+ S_HOGN_02, // 1225
+ S_DEAD_00, // 1226
+ S_SBAN_00, // 1227
+ S_BOTR_00, // 1228
+ S_HATR_00, // 1229
+ S_TOPR_00, // 1230
+ S_COUP_00, // 1231
+ S_COUP_01, // 1232
+ S_COUP_02, // 1233
+ S_BUBB_00, // 1234
+ S_BUBF_00, // 1235
+ S_BUBC_00, // 1236
+ S_ASPR_00, // 1237
+ S_SPDL_00, // 1238
+ S_SPDL_01, // 1239
+ S_SPDL_02, // 1240
+ S_TOKN_00, // 1241
+ S_OTOK_00, // 1242
+ S_HELT_00, // 1243
+ S_GUNT_00, // 1244
+ S_FULL_00, // 1245
+ S_FULL_01, // 1246
+ S_MEAT_00, // 1247
+ S_MEAT_01, // 1248
+ S_MEAT_02, // 1249
+ S_MEAT_03, // 1250
+ S_MEAT_04, // 1251
+ S_MEAT_05, // 1252
+ S_MEAT_06, // 1253
+ S_MEAT_07, // 1254
+ S_MEAT_08, // 1255
+ S_MEAT_09, // 1256
+ S_MEAT_10, // 1257
+ S_MEAT_11, // 1258
+ S_MEAT_12, // 1259
+ S_MEAT_13, // 1260
+ S_MEAT_14, // 1261
+ S_MEAT_15, // 1262
+ S_MEAT_16, // 1263
+ S_MEAT_17, // 1264
+ S_MEAT_18, // 1265
+ S_MEAT_19, // 1266
+ S_JUNK_00, // 1267
+ S_JUNK_01, // 1268
+ S_JUNK_02, // 1269
+ S_JUNK_03, // 1270
+ S_JUNK_04, // 1271
+ S_JUNK_05, // 1272
+ S_JUNK_06, // 1273
+ S_JUNK_07, // 1274
+ S_JUNK_08, // 1275
+ S_JUNK_09, // 1276
+ S_JUNK_10, // 1277
+ S_JUNK_11, // 1278
+ S_JUNK_12, // 1279
+ S_JUNK_13, // 1280
+ S_JUNK_14, // 1281
+ S_JUNK_15, // 1282
+ S_JUNK_16, // 1283
+ S_JUNK_17, // 1284
+ S_JUNK_18, // 1285
+ S_JUNK_19, // 1286
+ S_FFOT_00, // 1287
+ S_FFOT_01, // 1288
+ S_FFOT_02, // 1289
+ S_FFOT_03, // 1290
+ S_DIE1_00, // 1291
+ S_BEAC_00, // 1292
+ S_BEAC_01, // 1293
+ S_BEAC_02, // 1294
+ S_ARM1_00, // 1295
+ S_ARM2_00, // 1296
+ S_BARW_00, // 1297
+ S_BARW_01, // 1298
+ S_BARW_02, // 1299
+ S_BARW_03, // 1300
+ S_BARW_04, // 1301
+ S_BARW_05, // 1302
+ S_BARW_06, // 1303
+ S_BARW_07, // 1304
+ S_BART_00, // 1305
+ S_BART_01, // 1306
+ S_BART_02, // 1307
+ S_BART_03, // 1308
+ S_BART_04, // 1309
+ S_BART_05, // 1310
+ S_BART_06, // 1311
+ S_BART_07, // 1312
+ S_BART_08, // 1313
+ S_BART_09, // 1314
+ S_BART_10, // 1315
+ S_BART_11, // 1316
+ S_LAMP_00, // 1317
+ S_LANT_00, // 1318
+ S_BARL_00, // 1319
+ S_BARL_01, // 1320
+ S_BARL_02, // 1321
+ S_BARL_03, // 1322
+ S_BOWL_00, // 1323
+ S_BOWL_01, // 1324
+ S_BOWL_02, // 1325
+ S_BOWL_03, // 1326
+ S_BRAZ_00, // 1327
+ S_BRAZ_01, // 1328
+ S_BRAZ_02, // 1329
+ S_BRAZ_03, // 1330
+ S_TRCH_00, // 1331
+ S_TRCH_01, // 1332
+ S_TRCH_02, // 1333
+ S_TRCH_03, // 1334
+ S_LTRH_00, // 1335
+ S_LTRH_01, // 1336
+ S_LTRH_02, // 1337
+ S_LTRH_03, // 1338
+ S_LMPC_00, // 1339
+ S_LMPC_01, // 1340
+ S_LMPC_02, // 1341
+ S_LMPC_03, // 1342
+ S_LOGS_00, // 1343
+ S_LOGS_01, // 1344
+ S_LOGS_02, // 1345
+ S_LOGS_03, // 1346
+ S_TRHO_00, // 1347
+ S_WATR_00, // 1348
+ S_MUGG_00, // 1349
+ S_FUSL_00, // 1350
+ S_CRD1_00, // 1351
+ S_CRD2_00, // 1352
+ S_TPAS_00, // 1353
+ S_KY1G_00, // 1354
+ S_KY2S_00, // 1355
+ S_KY3B_00, // 1356
+ S_HAND_00, // 1357
+ S_CRYS_00, // 1358
+ S_CRYS_01, // 1359
+ S_CRYS_02, // 1360
+ S_CRYS_03, // 1361
+ S_CRYS_04, // 1362
+ S_CRYS_05, // 1363
+ S_PRIS_00, // 1364
+ S_PWR1_00, // 1365
+ S_PWR2_00, // 1366
+ S_PWR3_00, // 1367
+ S_ORAC_00, // 1368
+ S_GYID_00, // 1369
+ S_FUBR_00, // 1370
+ S_WARE_00, // 1371
+ S_RCRY_00, // 1372
+ S_BCRY_00, // 1373
+ S_CHAP_00, // 1374
+ S_TUNL_00, // 1375
+ S_BLTK_00, // 1376
+ S_SECK_00, // 1377
+ S_MINE_00, // 1378
+ S_REBL_00, // 1379
+ S_PROC_00, // 1380
+ S_ANKH_00, // 1381
+ S_GOID_00, // 1382
+ S_STMP_00, // 1383
+ S_MDKT_00, // 1384
+ S_COIN_00, // 1385
+ S_CRED_00, // 1386
+ S_SACK_00, // 1387
+ S_CHST_00, // 1388
+ S_SHD1_00, // 1389
+ S_SHD1_01, // 1390
+ S_SHD1_02, // 1391
+ S_SHD1_03, // 1392
+ S_MASK_00, // 1393
+ S_UNIF_00, // 1394
+ S_OFIC_00, // 1395
+ S_PMAP_00, // 1396
+ S_PMAP_01, // 1397
+ S_PMUP_00, // 1398
+ S_PMUP_01, // 1399
+ S_BLIT_00, // 1400
+ S_BBOX_00, // 1401
+ S_MSSL_00, // 1402
+ S_ROKT_00, // 1403
+ S_BRY1_00, // 1404
+ S_BRY1_01, // 1405
+ S_CPAC_00, // 1406
+ S_CPAC_01, // 1407
+ S_PQRL_00, // 1408
+ S_XQRL_00, // 1409
+ S_GRN1_00, // 1410
+ S_GRN2_00, // 1411
+ S_BKPK_00, // 1412
+ S_RELC_00, // 1413
+ S_RIFL_00, // 1414
+ S_RIFL_01, // 1415
+ S_FLAM_00, // 1416
+ S_BFLM_00, // 1417
+ S_MMSL_00, // 1418
+ S_TRPD_00, // 1419
+ S_GRND_00, // 1420
+ S_CBOW_00, // 1421
+ S_SIGL_00, // 1422
+ S_SIGL_01, // 1423
+ S_SIGL_02, // 1424
+ S_SIGL_03, // 1425
+ S_SIGL_04, // 1426
+ S_LITE_00, // 1427
+ S_CNDL_00, // 1428
+ S_CLBR_00, // 1429
+ S_LITS_00, // 1430
+ S_LITB_00, // 1431
+ S_LITG_00, // 1432
+ S_ROK1_00, // 1433
+ S_ROK2_00, // 1434
+ S_ROK3_00, // 1435
+ S_ROK4_00, // 1436
+ S_LOGG_00, // 1437
+ S_LOGG_01, // 1438
+ S_LOGG_02, // 1439
+ S_LOGG_03, // 1440
+ S_RUB1_00, // 1441
+ S_RUB2_00, // 1442
+ S_RUB3_00, // 1443
+ S_RUB4_00, // 1444
+ S_RUB5_00, // 1445
+ S_RUB6_00, // 1446
+ S_RUB7_00, // 1447
+ S_RUB8_00, // 1448
+ S_CHAN_00, // 1449
+ S_STAT_00, // 1450
+ S_DSTA_00, // 1451
+ S_CRAB_00, // 1452
+ S_CAGE_00, // 1453
+ S_TREE_00, // 1454
+ S_TREE_01, // 1455
+ S_TREE_02, // 1456
+ S_TRE1_00, // 1457
+ S_BUSH_00, // 1458
+ S_SHRB_00, // 1459
+ S_STAK_00, // 1460
+ S_BAR1_00, // 1461
+ S_VASE_00, // 1462
+ S_VASE_01, // 1463
+ S_STOL_00, // 1464
+ S_POT1_00, // 1465
+ S_TUB1_00, // 1466
+ S_ANVL_00, // 1467
+ S_TLMP_00, // 1468
+ S_TLMP_01, // 1469
+ S_TRAY_00, // 1470
+ S_APOW_00, // 1471
+ S_AFED_00, // 1472
+ S_DRIP_00, // 1473
+ S_DRIP_01, // 1474
+ S_DRIP_02, // 1475
+ S_DRIP_03, // 1476
+ S_DRIP_04, // 1477
+ S_DRIP_05, // 1478
+ S_DRIP_06, // 1479
+ S_DRIP_07, // 1480
+ S_CDRP_00, // 1481
+ S_CDRP_01, // 1482
+ S_CDRP_02, // 1483
+ S_CDRP_03, // 1484
+ S_SPLH_00, // 1485
+ S_SPLH_01, // 1486
+ S_SPLH_02, // 1487
+ S_SPLH_03, // 1488
+ S_SPLH_04, // 1489
+ S_SPLH_05, // 1490
+ S_SPLH_06, // 1491
+ S_SPLH_07, // 1492
+ S_WTFT_00, // 1493
+ S_WTFT_01, // 1494
+ S_WTFT_02, // 1495
+ S_WTFT_03, // 1496
+ S_HERT_00, // 1497
+ S_HERT_01, // 1498
+ S_HERT_02, // 1499
+ S_TELP_00, // 1500
+ S_TELP_01, // 1501
+ S_TELP_02, // 1502
+ S_TELP_03, // 1503
+ S_MONI_00, // 1504
+ S_STEL_00, // 1505
+ S_STLA_00, // 1506
+ S_STLE_00, // 1507
+ S_HUGE_00, // 1508
+ S_HUGE_01, // 1509
+ S_HUGE_02, // 1510
+ S_HUGE_03, // 1511
+ S_STLG_00, // 1512
+ S_STLG_01, // 1513
+ S_STLG_02, // 1514
+ S_STLG_03, // 1515
+ S_STLG_04, // 1516
+ S_STLG_05, // 1517
+ NUMSTATES
+
+} statenum_t;
+
+
+typedef struct
+{
+ spritenum_t sprite;
+ int frame;
+ int tics;
+ // void (*action) ();
+ actionf_t action;
+ statenum_t nextstate;
+ //int misc1; // villsa [STRIFE] unused
+ //int misc2; // villsa [STRIFE] unused
+} state_t;
+
+extern state_t states[NUMSTATES];
+extern char *sprnames[];
+
+typedef enum
+{
+ MT_FIELDGUARD, //000
+ MT_PLAYER, //001
+ MT_SHOPKEEPER_W, //002
+ MT_SHOPKEEPER_B, //003
+ MT_SHOPKEEPER_A, //004
+ MT_SHOPKEEPER_M, //005
+ MT_PEASANT2_A, //006
+ MT_PEASANT2_B, //007
+ MT_PEASANT2_C, //008
+ MT_PEASANT5_A, //009
+ MT_PEASANT5_B, //010
+ MT_PEASANT5_C, //011
+ MT_PEASANT4_A, //012
+ MT_PEASANT4_B, //013
+ MT_PEASANT4_C, //014
+ MT_PEASANT6_A, //015
+ MT_PEASANT6_B, //016
+ MT_PEASANT6_C, //017
+ MT_PEASANT3_A, //018
+ MT_PEASANT3_B, //019
+ MT_PEASANT3_C, //020
+ MT_PEASANT8_A, //021
+ MT_PEASANT8_B, //022
+ MT_PEASANT8_C, //023
+ MT_PEASANT7_A, //024
+ MT_PEASANT7_B, //025
+ MT_PEASANT7_C, //026
+ MT_PEASANT1, //027
+ MT_ZOMBIE, //028
+ MT_BECOMING, //029
+ MT_ZOMBIESPAWNER, //030
+ MT_HUGE_TANK_1, //031
+ MT_HUGE_TANK_2, //032
+ MT_HUGE_TANK_3, //033
+ MT_TANK_4, //034
+ MT_TANK_5, //035
+ MT_TANK_6, //036
+ MT_KNEELING_GUY, //037
+ MT_BEGGAR1, //038
+ MT_BEGGAR2, //039
+ MT_BEGGAR3, //040
+ MT_BEGGAR4, //041
+ MT_BEGGAR5, //042
+ MT_REBEL1, //043
+ MT_REBEL2, //044
+ MT_REBEL3, //045
+ MT_REBEL4, //046
+ MT_REBEL5, //047
+ MT_REBEL6, //048
+ MT_RLEADER, //049
+ MT_RLEADER2, //050
+ MT_MISSILESMOKE, //051
+ MT_REAVER, //052
+ MT_GUARD1, //053
+ MT_GUARD2, //054
+ MT_GUARD3, //055
+ MT_GUARD4, //056
+ MT_GUARD5, //057
+ MT_GUARD6, //058
+ MT_GUARD7, //059
+ MT_GUARD8, //060
+ MT_SHADOWGUARD, //061
+ MT_PGUARD, //062
+ MT_CRUSADER, //063
+ MT_BISHOP, //064
+ MT_ORACLE, //065
+ MT_PRIEST, //066
+ MT_SPECTRE_A, //067
+ MT_NODE, //068
+ MT_SPECTREHEAD, //069
+ MT_SPECTRE_B, //070
+ MT_SPECTRE_C, //071
+ MT_SPECTRE_D, //072
+ MT_SPECTRE_E, //073
+ MT_ENTITY, //074
+ MT_SUBENTITY, //075
+ MT_NEST, //076
+ MT_POD, //077
+ MT_SIGIL_B_SHOT, //078
+ MT_SIGIL_SB_SHOT, //079
+ MT_SIGIL_C_SHOT, //080
+ MT_SIGIL_SC_SHOT, //081
+ MT_SIGIL_E_OFFSHOOT, //082
+ MT_SIGIL_TRAIL, //083
+ MT_SIGIL_E_SHOT, //084
+ MT_SIGIL_SE_SHOT, //085
+ MT_SIGIL_A_ZAP_LEFT, //086
+ MT_SIGIL_A_ZAP_RIGHT, //087
+ MT_SIGIL_A_GROUND, //088
+ MT_SIGIL_D_SHOT, //089
+ MT_SIGIL_SD_SHOT, //090
+ MT_SENTINEL, //091
+ MT_STALKER, //092
+ MT_INQUISITOR, //093
+ MT_INQARM, //094
+ MT_PROGRAMMER, //095
+ MT_PROGRAMMERBASE, //096
+ MT_HOOKSHOT, //097
+ MT_CHAINSHOT, //098
+ MT_MINIMISSLE, //099
+ MT_C_MISSILE, //100
+ MT_SEEKMISSILE, //101
+ MT_ELECARROW, //102
+ MT_POISARROW, //103
+ MT_R_LASER, //104
+ MT_L_LASER, //105
+ MT_HEGRENADE, //106
+ MT_PGRENADE, //107
+ MT_INQGRENADE, //108
+ MT_PFLAME, //109
+ MT_TORPEDO, //110
+ MT_TORPEDOSPREAD, //111
+ MT_SFIREBALL, //112
+ MT_C_FLAME, //113
+ MT_STRIFEPUFF3, //114
+ MT_STRIFEPUFF, //115
+ MT_SPARKPUFF, //116
+ MT_BLOOD_DEATH, //117
+ MT_TFOG, //118
+ MT_IFOG, //119
+ MT_TELEPORTMAN, //120
+ MT_MISC_01, //121
+ MT_TURRET, //122
+ MT_GATE, //123
+ MT_COMPUTER, //124
+ MT_INV_MED1, //125
+ MT_INV_MED2, //126
+ MT_INV_MED3, //127
+ MT_DEGNINORE, //128
+ MT_INV_ARMOR2, //129
+ MT_INV_ARMOR1, //130
+ MT_MISC_22, //131
+ MT_MISC_11, //132
+ MT_KEY_BASE, //133
+ MT_GOVSKEY, //134
+ MT_KEY_TRAVEL, //135
+ MT_KEY_ID_BLUE, //136
+ MT_PRISONKEY, //137
+ MT_KEY_HAND, //138
+ MT_POWER1KEY, //139
+ MT_POWER2KEY, //140
+ MT_POWER3KEY, //141
+ MT_KEY_GOLD, //142
+ MT_KEY_ID_GOLD, //143
+ MT_KEY_SILVER, //144
+ MT_KEY_ORACLE, //145
+ MT_MILITARYID, //146
+ MT_KEY_ORDER, //147
+ MT_KEY_WAREHOUSE, //148
+ MT_KEY_BRASS, //149
+ MT_KEY_RED_CRYSTAL, //150
+ MT_KEY_BLUE_CRYSTAL, //151
+ MT_KEY_CHAPEL, //152
+ MT_CATACOMBKEY, //153
+ MT_SECURITYKEY, //154
+ MT_KEY_CORE, //155
+ MT_KEY_MAULER, //156
+ MT_KEY_FACTORY, //157
+ MT_KEY_MINE, //158
+ MT_NEWKEY5, //159
+ MT_INV_SHADOWARMOR, //160
+ MT_INV_SUIT, //161
+ MT_QUEST_UNIFORM, //162
+ MT_QUEST_GUARD_UNIFORM, //163
+ MT_INV_SUPERMAP, //164
+ MT_INV_RADAR, //165
+ MT_BEACON, //166
+ MT_INV_TARGETER, //167
+ MT_MONY_1, //168
+ MT_MONY_10, //169
+ MT_MONY_25, //170
+ MT_MONY_50, //171
+ MT_MONY_300, //172
+ MT_TOKEN_RING, //173
+ MT_INV_CHALICE, //174
+ MT_TOKEN_EAR, //175
+ MT_INV_COMMUNICATOR, //176
+ MT_AGREN, //177
+ MT_APGREN, //178
+ MT_ACLIP, //179
+ MT_AAMMOBOX, //180
+ MT_AMINI, //181
+ MT_AMINIBOX, //182
+ MT_ACELL, //183
+ MT_APCELL, //184
+ MT_APAROW, //185
+ MT_AAROW, //186
+ MT_INV_SATCHEL, //187
+ MT_PULSE, //188
+ MT_RIFLESTAND, //189
+ MT_FLAMETHROWER, //190
+ MT_TOKEN_FLAME_THROWER_PARTS, //191
+ MT_MISSILELAUNCHER, //192
+ MT_BLASTER, //193
+ MT_CROSSBOW, //194
+ MT_GRENADELAUNCHER, //195
+ MT_SIGIL_A, //196
+ MT_SIGIL_B, //197
+ MT_SIGIL_C, //198
+ MT_SIGIL_D, //199
+ MT_SIGIL_E, //200
+ MT_POWER_CRYSTAL, //201
+ MT_RAT, //202
+ MT_MISC_05, //203
+ MT_MISC_06, //204
+ MT_MISC_15, //205
+ MT_LIGHT14, //206
+ MT_LIGHT13, //207
+ MT_LIGHT12, //208
+ MT_LIGHT18, //209
+ MT_PILLAR2, //210
+ MT_PILLAR3, //211
+ MT_PILLAR4, //212
+ MT_PILLAR5, //213
+ MT_PILLAR6, //214
+ MT_PILLAR7, //215
+ MT_CAVE2, //216
+ MT_CAVE3, //217
+ MT_CAVE4, //218
+ MT_CAVE6, //219
+ MT_CAVE7, //220
+ MT_CAVE5, //221
+ MT_LIGHT2, //222
+ MT_LIGHT3, //223
+ MT_MISC_03, //224
+ MT_MISC_13, //225
+ MT_MISC_02, //226
+ MT_MISC_07, //227
+ MT_BIO2, //228
+ MT_TELEPORTSTAND, //229
+ MT_DEADTHING1, //230
+ MT_DEADTHING2, //231
+ MT_DEADTHING3, //232
+ MT_DEADTHING4, //233
+ MT_DEADTHING5, //234
+ MT_DEADTHING6, //235
+ MT_BIO1, //236
+ MT_GIBS, //237
+ MT_MISC_04, //238
+ MT_LIGHT11, //239
+ MT_LIGHT10, //240
+ MT_LIGHT9, //241
+ MT_LIGHT8, //242
+ MT_MISC_14, //243
+ MT_LIGHT1, //244
+ MT_PILLAR8, //245
+ MT_PILLAR9, //246
+ MT_LIGHT15, //247
+ MT_LIGHT4, //248
+ MT_LIGHT5, //249
+ MT_ROCK1, //250
+ MT_ROCK2, //251
+ MT_ROCK3, //252
+ MT_ROCK4, //253
+ MT_TREE7, //254
+ MT_RUBBLE1, //255
+ MT_RUBBLE2, //256
+ MT_RUBBLE3, //257
+ MT_RUBBLE4, //258
+ MT_RUBBLE5, //259
+ MT_RUBBLE6, //260
+ MT_RUBBLE7, //261
+ MT_RUBBLE8, //262
+ MT_MISC_08, //263
+ MT_LIGHT6, //264
+ MT_LIGHT7, //265
+ MT_TREE2, //266
+ MT_TREE3, //267
+ MT_TREE4, //268
+ MT_TREE1, //269
+ MT_TREE6, //270
+ MT_TREE5, //271
+ MT_CAVE1, //272
+ MT_PILLAR1, //273
+ MT_MISC_10, //274
+ MT_MISC_09, //275
+ MT_MISC_17, //276
+ MT_MISC_18, //277
+ MT_MISC_19, //278
+ MT_MISC_20, //279
+ MT_LIGHT16, //280
+ MT_LIGHT17, //281
+ MT_MISC_21, //282
+ MT_MISC_12, //283
+ MT_MISC_26, //284
+ MT_MISC_23, //285
+ MT_MISC_24, //286
+ MT_MISC_25, //287
+ MT_COUPLING, //288
+ MT_COUPLING_BROKEN, //289
+ MT_PILLAR10, //290
+ MT_PILLAR11, //291
+ MT_PILLAR12, //292
+ MT_PILLAR13, //293
+ MT_LIGHT19, //294
+ MT_MEAT, //295
+ MT_JUNK, //296
+ MT_BURNDROP, //297
+ MT_TOKEN_AMMO, //298
+ MT_TOKEN_HEALTH, //299
+ MT_TOKEN, //300
+ MT_TOKEN_ALARM, //301
+ MT_TOKEN_DOOR1, //302
+ MT_TOKEN_SHOPCLOSE, //303
+ MT_TOKEN_PRISON_PASS, //304
+ MT_TOKEN_DOOR3, //305
+ MT_TOKEN_STAMINA, //306
+ MT_TOKEN_NEW_ACCURACY, //307
+ MT_TOKEN_REPORT, //308
+ MT_TOKEN_TOUGHNESS, //309
+ MT_TOKEN_ACCURACY, //310
+ MT_TOKEN_ORACLE_PASS, //311
+ MT_TOKEN_QUEST1, //312
+ MT_TOKEN_QUEST2, //313
+ MT_TOKEN_QUEST3, //314
+ MT_TOKEN_QUEST4, //315
+ MT_TOKEN_QUEST5, //316
+ MT_TOKEN_QUEST6, //317
+ MT_TOKEN_QUEST7, //318
+ MT_TOKEN_QUEST8, //319
+ MT_TOKEN_QUEST9, //320
+ MT_TOKEN_QUEST10, //321
+ MT_TOKEN_QUEST11, //322
+ MT_TOKEN_QUEST12, //323
+ MT_TOKEN_QUEST13, //324
+ MT_TOKEN_CRYSTAL, //325
+ MT_TOKEN_QUEST15, //326
+ MT_GATEQUEST, //327
+ MT_TOKEN_QUEST17, //328
+ MT_TOKEN_QUEST18, //329
+ MT_TOKEN_QUEST19, //330
+ MT_TOKEN_QUEST20, //331
+ MT_TOKEN_BISHOP, //332
+ MT_TOKEN_QUEST22, //333
+ MT_TOKEN_ORACLE, //334
+ MT_TOKEN_MACIL, //335
+ MT_TOKEN_QUEST25, //336
+ MT_TOKEN_LOREMASTER, //337
+ MT_SECRQUEST, //338
+ MT_TOKEN_QUEST28, //339
+ MT_TOKEN_QUEST29, //340
+ MT_TOKEN_QUEST30, //341
+ MT_TOKEN_QUEST31, //342
+ MT_SLIDESHOW, //343
+ NUMMOBJTYPES
+
+} mobjtype_t;
+
+// villsa [STRIFE] updated mobjinfo struct
+typedef struct
+{
+ int doomednum;
+ int spawnstate;
+ int spawnhealth;
+ int seestate;
+ int seesound;
+ int reactiontime;
+ int attacksound;
+ int painstate;
+ int painchance;
+ int painsound;
+ int meleestate;
+ int missilestate;
+ int crashstate;
+ int deathstate;
+ int xdeathstate;
+ int deathsound;
+ int speed;
+ int radius;
+ int height;
+ int mass;
+ int damage;
+ int activesound;
+ int flags;
+ char* name;
+} mobjinfo_t;
+
+extern mobjinfo_t mobjinfo[NUMMOBJTYPES];
+
+#endif
diff --git a/src/strife/m_menu.c b/src/strife/m_menu.c
new file mode 100644
index 00000000..a4d1b0a7
--- /dev/null
+++ b/src/strife/m_menu.c
@@ -0,0 +1,2377 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// DOOM selection menu, options, episode etc.
+// Sliders and icons. Kinda widget stuff.
+//
+//-----------------------------------------------------------------------------
+
+
+#include <stdlib.h>
+#include <ctype.h>
+
+
+#include "doomdef.h"
+#include "doomkeys.h"
+#include "dstrings.h"
+
+#include "d_main.h"
+#include "deh_main.h"
+
+#include "i_swap.h"
+#include "i_system.h"
+#include "i_timer.h"
+#include "i_video.h"
+#include "z_zone.h"
+#include "v_video.h"
+#include "w_wad.h"
+
+#include "r_local.h"
+
+
+#include "hu_stuff.h"
+
+#include "g_game.h"
+
+#include "m_argv.h"
+#include "m_controls.h"
+#include "m_saves.h" // [STRIFE]
+#include "p_saveg.h"
+
+#include "s_sound.h"
+
+#include "doomstat.h"
+
+// Data.
+#include "sounds.h"
+
+#include "m_menu.h"
+#include "p_dialog.h"
+
+
+extern void M_QuitStrife(int);
+
+extern patch_t* hu_font[HU_FONTSIZE];
+extern boolean message_dontfuckwithme;
+
+extern boolean chat_on; // in heads-up code
+extern boolean sendsave; // [STRIFE]
+
+//
+// defaulted values
+//
+int mouseSensitivity = 5;
+
+// [STRIFE]: removed this entirely
+// Show messages has default, 0 = off, 1 = on
+//int showMessages = 1;
+
+
+// Blocky mode, has default, 0 = high, 1 = normal
+int detailLevel = 0;
+int screenblocks = 9;
+
+// temp for screenblocks (0-9)
+int screenSize;
+
+// -1 = no quicksave slot picked!
+int quickSaveSlot;
+
+ // 1 = message to be printed
+int messageToPrint;
+// ...and here is the message string!
+char* messageString;
+
+// message x & y
+int messx;
+int messy;
+int messageLastMenuActive;
+
+// timed message = no input from user
+boolean messageNeedsInput;
+
+void (*messageRoutine)(int response);
+
+char gammamsg[5][26] =
+{
+ GAMMALVL0,
+ GAMMALVL1,
+ GAMMALVL2,
+ GAMMALVL3,
+ GAMMALVL4
+};
+
+// we are going to be entering a savegame string
+int saveStringEnter;
+int saveSlot; // which slot to save in
+int saveCharIndex; // which char we're editing
+// old save description before edit
+char saveOldString[SAVESTRINGSIZE];
+
+boolean inhelpscreens;
+boolean menuactive;
+boolean menupause; // haleyjd 08/29/10: [STRIFE] New global
+int menupausetime; // haleyjd 09/04/10: [STRIFE] New global
+boolean menuindialog; // haleyjd 09/04/10: ditto
+
+// haleyjd 08/27/10: [STRIFE] SKULLXOFF == -28, LINEHEIGHT == 19
+#define CURSORXOFF -28
+#define LINEHEIGHT 19
+
+extern boolean sendpause;
+char savegamestrings[10][SAVESTRINGSIZE];
+
+char endstring[160];
+
+// haleyjd 09/04/10: [STRIFE] Moved menuitem / menu structures into header
+// because they are needed externally by the dialog engine.
+
+// haleyjd 08/27/10: [STRIFE] skull* stuff changed to cursor* stuff
+short itemOn; // menu item skull is on
+short cursorAnimCounter; // skull animation counter
+short whichCursor; // which skull to draw
+
+// graphic name of cursors
+// haleyjd 08/27/10: [STRIFE] M_SKULL* -> M_CURS*
+char *cursorName[8] = {"M_CURS1", "M_CURS2", "M_CURS3", "M_CURS4",
+ "M_CURS5", "M_CURS6", "M_CURS7", "M_CURS8" };
+
+// haleyjd 20110210 [STRIFE]: skill level for menus
+int menuskill;
+
+// current menudef
+menu_t* currentMenu;
+
+// haleyjd 03/01/13: [STRIFE] v1.31-only:
+// Keeps track of whether the save game menu is being used to name a new
+// character slot, or to just save the current game. In the v1.31 disassembly
+// this was the new dword_8632C variable.
+boolean namingCharacter;
+
+//
+// PROTOTYPES
+//
+void M_NewGame(int choice);
+void M_Episode(int choice);
+void M_ChooseSkill(int choice);
+void M_LoadGame(int choice);
+void M_SaveGame(int choice);
+void M_Options(int choice);
+void M_EndGame(int choice);
+void M_ReadThis(int choice);
+void M_ReadThis2(int choice);
+void M_ReadThis3(int choice); // [STRIFE]
+
+//void M_ChangeMessages(int choice); [STRIFE]
+void M_ChangeSensitivity(int choice);
+void M_SfxVol(int choice);
+void M_VoiceVol(int choice); // [STRIFE]
+void M_MusicVol(int choice);
+void M_SizeDisplay(int choice);
+void M_StartGame(int choice);
+void M_Sound(int choice);
+
+//void M_FinishReadThis(int choice); - [STRIFE] unused
+void M_SaveSelect(int choice);
+void M_ReadSaveStrings(void);
+void M_QuickSave(void);
+void M_QuickLoad(void);
+
+void M_DrawMainMenu(void);
+void M_DrawReadThis1(void);
+void M_DrawReadThis2(void);
+void M_DrawReadThis3(void); // [STRIFE]
+void M_DrawNewGame(void);
+void M_DrawEpisode(void);
+void M_DrawOptions(void);
+void M_DrawSound(void);
+void M_DrawLoad(void);
+void M_DrawSave(void);
+
+void M_DrawSaveLoadBorder(int x,int y);
+void M_SetupNextMenu(menu_t *menudef);
+void M_DrawThermo(int x,int y,int thermWidth,int thermDot);
+void M_DrawEmptyCell(menu_t *menu,int item);
+void M_DrawSelCell(menu_t *menu,int item);
+int M_StringWidth(char *string);
+int M_StringHeight(char *string);
+void M_StartMessage(char *string,void *routine,boolean input);
+void M_StopMessage(void);
+
+
+
+
+//
+// DOOM MENU
+//
+enum
+{
+ newgame = 0,
+ options,
+ loadgame,
+ savegame,
+ readthis,
+ quitdoom,
+ main_end
+} main_e;
+
+menuitem_t MainMenu[]=
+{
+ {1,"M_NGAME",M_NewGame,'n'},
+ {1,"M_OPTION",M_Options,'o'},
+ {1,"M_LOADG",M_LoadGame,'l'},
+ {1,"M_SAVEG",M_SaveGame,'s'},
+ // Another hickup with Special edition.
+ {1,"M_RDTHIS",M_ReadThis,'h'}, // haleyjd 08/28/10: 'r' -> 'h'
+ {1,"M_QUITG",M_QuitStrife,'q'}
+};
+
+menu_t MainDef =
+{
+ main_end,
+ NULL,
+ MainMenu,
+ M_DrawMainMenu,
+ 97,45, // haleyjd 08/28/10: [STRIFE] changed y coord
+ 0
+};
+
+
+//
+// EPISODE SELECT
+//
+/*
+enum
+{
+ ep1,
+ ep2,
+ ep3,
+ ep4,
+ ep_end
+} episodes_e;
+
+menuitem_t EpisodeMenu[]=
+{
+ {1,"M_EPI1", M_Episode,'k'},
+ {1,"M_EPI2", M_Episode,'t'},
+ {1,"M_EPI3", M_Episode,'i'},
+ {1,"M_EPI4", M_Episode,'t'}
+};
+
+menu_t EpiDef =
+{
+ ep_end, // # of menu items
+ &MainDef, // previous menu
+ EpisodeMenu, // menuitem_t ->
+ M_DrawEpisode, // drawing routine ->
+ 48,63, // x,y
+ ep1 // lastOn
+};
+*/
+
+//
+// NEW GAME
+//
+enum
+{
+ killthings,
+ toorough,
+ hurtme,
+ violence,
+ nightmare,
+ newg_end
+} newgame_e;
+
+menuitem_t NewGameMenu[]=
+{
+ // haleyjd 08/28/10: [STRIFE] changed all shortcut letters
+ {1,"M_JKILL", M_ChooseSkill, 't'},
+ {1,"M_ROUGH", M_ChooseSkill, 'r'},
+ {1,"M_HURT", M_ChooseSkill, 'v'},
+ {1,"M_ULTRA", M_ChooseSkill, 'e'},
+ {1,"M_NMARE", M_ChooseSkill, 'b'}
+};
+
+menu_t NewDef =
+{
+ newg_end, // # of menu items
+ &MainDef, // previous menu - haleyjd [STRIFE] changed to MainDef
+ NewGameMenu, // menuitem_t ->
+ M_DrawNewGame, // drawing routine ->
+ 48,63, // x,y
+ toorough // lastOn - haleyjd [STRIFE]: default to skill 1
+};
+
+//
+// OPTIONS MENU
+//
+enum
+{
+ // haleyjd 08/28/10: [STRIFE] Removed messages, mouse sens., detail.
+ endgame,
+ scrnsize,
+ option_empty1,
+ soundvol,
+ opt_end
+} options_e;
+
+menuitem_t OptionsMenu[]=
+{
+ // haleyjd 08/28/10: [STRIFE] Removed messages, mouse sens., detail.
+ {1,"M_ENDGAM", M_EndGame,'e'},
+ {2,"M_SCRNSZ", M_SizeDisplay,'s'},
+ {-1,"",0,'\0'},
+ {1,"M_SVOL", M_Sound,'s'}
+};
+
+menu_t OptionsDef =
+{
+ opt_end,
+ &MainDef,
+ OptionsMenu,
+ M_DrawOptions,
+ 60,37,
+ 0
+};
+
+//
+// Read This! MENU 1 & 2 & [STRIFE] 3
+//
+enum
+{
+ rdthsempty1,
+ read1_end
+} read_e;
+
+menuitem_t ReadMenu1[] =
+{
+ {1,"",M_ReadThis2,0}
+};
+
+menu_t ReadDef1 =
+{
+ read1_end,
+ &MainDef,
+ ReadMenu1,
+ M_DrawReadThis1,
+ 280,185,
+ 0
+};
+
+enum
+{
+ rdthsempty2,
+ read2_end
+} read_e2;
+
+menuitem_t ReadMenu2[]=
+{
+ {1,"",M_ReadThis3,0} // haleyjd 08/28/10: [STRIFE] Go to ReadThis3
+};
+
+menu_t ReadDef2 =
+{
+ read2_end,
+ &ReadDef1,
+ ReadMenu2,
+ M_DrawReadThis2,
+ 250,185, // haleyjd 08/28/10: [STRIFE] changed coords
+ 0
+};
+
+// haleyjd 08/28/10: Added Read This! menu 3
+enum
+{
+ rdthsempty3,
+ read3_end
+} read_e3;
+
+menuitem_t ReadMenu3[]=
+{
+ {1,"",M_ClearMenus,0}
+};
+
+menu_t ReadDef3 =
+{
+ read3_end,
+ &ReadDef2,
+ ReadMenu3,
+ M_DrawReadThis3,
+ 250, 185,
+ 0
+};
+
+//
+// SOUND VOLUME MENU
+//
+enum
+{
+ sfx_vol,
+ sfx_empty1,
+ music_vol,
+ sfx_empty2,
+ voice_vol,
+ sfx_empty3,
+ sfx_mouse,
+ sfx_empty4,
+ sound_end
+} sound_e;
+
+// haleyjd 08/29/10:
+// [STRIFE]
+// * Added voice volume
+// * Moved mouse sensitivity here (who knows why...)
+menuitem_t SoundMenu[]=
+{
+ {2,"M_SFXVOL",M_SfxVol,'s'},
+ {-1,"",0,'\0'},
+ {2,"M_MUSVOL",M_MusicVol,'m'},
+ {-1,"",0,'\0'},
+ {2,"M_VOIVOL",M_VoiceVol,'v'},
+ {-1,"",0,'\0'},
+ {2,"M_MSENS",M_ChangeSensitivity,'m'},
+ {-1,"",0,'\0'}
+};
+
+menu_t SoundDef =
+{
+ sound_end,
+ &OptionsDef,
+ SoundMenu,
+ M_DrawSound,
+ 80,35, // [STRIFE] changed y coord 64 -> 35
+ 0
+};
+
+//
+// LOAD GAME MENU
+//
+enum
+{
+ load1,
+ load2,
+ load3,
+ load4,
+ load5,
+ load6,
+ load_end
+} load_e;
+
+menuitem_t LoadMenu[]=
+{
+ {1,"", M_LoadSelect,'1'},
+ {1,"", M_LoadSelect,'2'},
+ {1,"", M_LoadSelect,'3'},
+ {1,"", M_LoadSelect,'4'},
+ {1,"", M_LoadSelect,'5'},
+ {1,"", M_LoadSelect,'6'}
+};
+
+menu_t LoadDef =
+{
+ load_end,
+ &MainDef,
+ LoadMenu,
+ M_DrawLoad,
+ 80,54,
+ 0
+};
+
+//
+// SAVE GAME MENU
+//
+menuitem_t SaveMenu[]=
+{
+ {1,"", M_SaveSelect,'1'},
+ {1,"", M_SaveSelect,'2'},
+ {1,"", M_SaveSelect,'3'},
+ {1,"", M_SaveSelect,'4'},
+ {1,"", M_SaveSelect,'5'},
+ {1,"", M_SaveSelect,'6'}
+};
+
+menu_t SaveDef =
+{
+ load_end,
+ &MainDef,
+ SaveMenu,
+ M_DrawSave,
+ 80,54,
+ 0
+};
+
+void M_DrawNameChar(void);
+
+//
+// NAME CHARACTER MENU
+//
+// [STRIFE]
+// haleyjd 20110210: New "Name Your Character" Menu
+//
+menu_t NameCharDef =
+{
+ load_end,
+ &NewDef,
+ SaveMenu,
+ M_DrawNameChar,
+ 80,54,
+ 0
+};
+
+
+//
+// M_ReadSaveStrings
+// read the strings from the savegame files
+//
+// [STRIFE]
+// haleyjd 20110210: Rewritten to read "name" file in each slot directory
+//
+void M_ReadSaveStrings(void)
+{
+ FILE *handle;
+ int i;
+ char *fname = NULL;
+
+ for(i = 0; i < load_end; i++)
+ {
+ if(fname)
+ Z_Free(fname);
+ fname = M_SafeFilePath(savegamedir, M_MakeStrifeSaveDir(i, "\\name"));
+
+ handle = fopen(fname, "rb");
+ if(handle == NULL)
+ {
+ strcpy(savegamestrings[i], EMPTYSTRING);
+ LoadMenu[i].status = 0;
+ continue;
+ }
+ fread(savegamestrings[i], 1, SAVESTRINGSIZE, handle);
+ fclose(handle);
+ LoadMenu[i].status = 1;
+ }
+
+ if(fname)
+ Z_Free(fname);
+}
+
+//
+// M_DrawNameChar
+//
+// haleyjd 09/22/10: [STRIFE] New function
+// Handler for drawing the "Name Your Character" menu.
+//
+void M_DrawNameChar(void)
+{
+ int i;
+
+ M_WriteText(72, 28, DEH_String("Name Your Character"));
+
+ for (i = 0;i < load_end; i++)
+ {
+ M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i);
+ M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]);
+ }
+
+ if (saveStringEnter)
+ {
+ i = M_StringWidth(savegamestrings[quickSaveSlot]);
+ M_WriteText(LoadDef.x + i,LoadDef.y+LINEHEIGHT*quickSaveSlot,"_");
+ }
+}
+
+//
+// M_DoNameChar
+//
+// haleyjd 09/22/10: [STRIFE] New function
+// Handler for items in the "Name Your Character" menu.
+//
+void M_DoNameChar(int choice)
+{
+ int map;
+
+ // 20130301: clear naming character flag for 1.31 save logic
+ if(gameversion == exe_strife_1_31)
+ namingCharacter = false;
+ sendsave = 1;
+ ClearTmp();
+ G_WriteSaveName(choice, savegamestrings[choice]);
+ quickSaveSlot = choice;
+ SaveDef.lastOn = choice;
+ ClearSlot();
+ FromCurr();
+
+ if(isdemoversion)
+ map = 33;
+ else
+ map = 2;
+
+ G_DeferedInitNew(menuskill, map);
+ M_ClearMenus(0);
+}
+
+//
+// M_LoadGame & Cie.
+//
+void M_DrawLoad(void)
+{
+ int i;
+
+ V_DrawPatchDirect(72, 28,
+ W_CacheLumpName(DEH_String("M_LOADG"), PU_CACHE));
+
+ for (i = 0;i < load_end; i++)
+ {
+ M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i);
+ M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]);
+ }
+}
+
+
+
+//
+// Draw border for the savegame description
+//
+void M_DrawSaveLoadBorder(int x,int y)
+{
+ int i;
+
+ V_DrawPatchDirect(x - 8, y + 7,
+ W_CacheLumpName(DEH_String("M_LSLEFT"), PU_CACHE));
+
+ for (i = 0;i < 24;i++)
+ {
+ V_DrawPatchDirect(x, y + 7,
+ W_CacheLumpName(DEH_String("M_LSCNTR"), PU_CACHE));
+ x += 8;
+ }
+
+ V_DrawPatchDirect(x, y + 7,
+ W_CacheLumpName(DEH_String("M_LSRGHT"), PU_CACHE));
+}
+
+
+
+//
+// User wants to load this game
+//
+void M_LoadSelect(int choice)
+{
+ // [STRIFE]: completely rewritten
+ char *name = NULL;
+
+ G_WriteSaveName(choice, savegamestrings[choice]);
+ ToCurr();
+
+ // use safe & portable filepath concatenation for Choco
+ name = M_SafeFilePath(savegamedir, M_MakeStrifeSaveDir(choice, ""));
+
+ G_ReadCurrent(name);
+ quickSaveSlot = choice;
+ M_ClearMenus(0);
+
+ Z_Free(name);
+}
+
+//
+// Selected from DOOM menu
+//
+// [STRIFE] Verified unmodified
+//
+void M_LoadGame (int choice)
+{
+ if (netgame)
+ {
+ M_StartMessage(DEH_String(LOADNET), NULL, false);
+ return;
+ }
+
+ M_SetupNextMenu(&LoadDef);
+ M_ReadSaveStrings();
+}
+
+
+//
+// M_SaveGame & Cie.
+//
+void M_DrawSave(void)
+{
+ int i;
+
+ V_DrawPatchDirect(72, 28, W_CacheLumpName(DEH_String("M_SAVEG"), PU_CACHE));
+ for (i = 0;i < load_end; i++)
+ {
+ M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i);
+ M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]);
+ }
+
+ if (saveStringEnter)
+ {
+ i = M_StringWidth(savegamestrings[quickSaveSlot]);
+ M_WriteText(LoadDef.x + i,LoadDef.y+LINEHEIGHT*quickSaveSlot,"_");
+ }
+}
+
+//
+// M_Responder calls this when user is finished
+//
+void M_DoSave(int slot)
+{
+ // [STRIFE]: completely rewritten
+ if(slot >= 0)
+ {
+ sendsave = 1;
+ G_WriteSaveName(slot, savegamestrings[slot]);
+ M_ClearMenus(0);
+ quickSaveSlot = slot;
+ FromCurr();
+ }
+ else
+ M_StartMessage(DEH_String(QSAVESPOT), NULL, false);
+}
+
+//
+// User wants to save. Start string input for M_Responder
+//
+void M_SaveSelect(int choice)
+{
+ // we are going to be intercepting all chars
+ saveStringEnter = 1;
+
+ // [STRIFE]
+ quickSaveSlot = choice;
+ //saveSlot = choice;
+
+ strcpy(saveOldString,savegamestrings[choice]);
+ if (!strcmp(savegamestrings[choice],EMPTYSTRING))
+ savegamestrings[choice][0] = 0;
+ saveCharIndex = strlen(savegamestrings[choice]);
+}
+
+//
+// Selected from DOOM menu
+//
+void M_SaveGame (int choice)
+{
+ // [STRIFE]
+ if (netgame)
+ {
+ // haleyjd 20110211: Hooray for Rogue's awesome multiplayer support...
+ M_StartMessage(DEH_String("You can't save a netgame"), NULL, false);
+ return;
+ }
+ if (!usergame)
+ {
+ M_StartMessage(DEH_String(SAVEDEAD),NULL,false);
+ return;
+ }
+
+ if (gamestate != GS_LEVEL)
+ return;
+
+ // [STRIFE]
+ if(gameversion == exe_strife_1_31)
+ {
+ // haleyjd 20130301: in 1.31, we can choose a slot again.
+ M_SetupNextMenu(&SaveDef);
+ M_ReadSaveStrings();
+ }
+ else
+ {
+ // In 1.2 and lower, you save over your character slot exclusively
+ M_ReadSaveStrings();
+ M_DoSave(quickSaveSlot);
+ }
+}
+
+
+
+//
+// M_QuickSave
+//
+char tempstring[80];
+
+void M_QuickSaveResponse(int key)
+{
+ if (key == key_menu_confirm)
+ {
+ M_DoSave(quickSaveSlot);
+ S_StartSound(NULL, sfx_mtalht); // [STRIFE] sound
+ }
+}
+
+void M_QuickSave(void)
+{
+ if (netgame)
+ {
+ // haleyjd 20110211 [STRIFE]: More fun...
+ M_StartMessage(DEH_String("You can't save a netgame"), NULL, false);
+ return;
+ }
+
+ if (!usergame)
+ {
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+
+ if (gamestate != GS_LEVEL)
+ return;
+
+ if (quickSaveSlot < 0)
+ {
+ M_StartControlPanel();
+ M_ReadSaveStrings();
+ M_SetupNextMenu(&SaveDef);
+ quickSaveSlot = -2; // means to pick a slot now
+ return;
+ }
+ DEH_snprintf(tempstring, 80, QSPROMPT, savegamestrings[quickSaveSlot]);
+ M_StartMessage(tempstring,M_QuickSaveResponse,true);
+}
+
+
+
+//
+// M_QuickLoadResponse
+//
+void M_QuickLoadResponse(int key)
+{
+ if (key == key_menu_confirm)
+ {
+ M_LoadSelect(quickSaveSlot);
+ S_StartSound(NULL, sfx_mtalht); // [STRIFE] sound
+ }
+}
+
+//
+// M_QuickLoad
+//
+// [STRIFE] Verified unmodified
+//
+void M_QuickLoad(void)
+{
+ if (netgame)
+ {
+ M_StartMessage(DEH_String(QLOADNET),NULL,false);
+ return;
+ }
+
+ if (quickSaveSlot < 0)
+ {
+ M_StartMessage(DEH_String(QSAVESPOT),NULL,false);
+ return;
+ }
+ DEH_snprintf(tempstring, 80, QLPROMPT, savegamestrings[quickSaveSlot]);
+ M_StartMessage(tempstring,M_QuickLoadResponse,true);
+}
+
+
+
+
+//
+// Read This Menus
+// Had a "quick hack to fix romero bug"
+// haleyjd 08/28/10: [STRIFE] Draw HELP1, unconditionally.
+//
+void M_DrawReadThis1(void)
+{
+ inhelpscreens = true;
+
+ V_DrawPatchDirect (0, 0, W_CacheLumpName(DEH_String("HELP1"), PU_CACHE));
+}
+
+
+
+//
+// Read This Menus
+// haleyjd 08/28/10: [STRIFE] Not optional, draws HELP2
+//
+void M_DrawReadThis2(void)
+{
+ inhelpscreens = true;
+
+ V_DrawPatchDirect(0, 0, W_CacheLumpName(DEH_String("HELP2"), PU_CACHE));
+}
+
+
+//
+// Read This Menus
+// haleyjd 08/28/10: [STRIFE] New function to draw HELP3.
+//
+void M_DrawReadThis3(void)
+{
+ inhelpscreens = true;
+
+ V_DrawPatchDirect(0, 0, W_CacheLumpName(DEH_String("HELP3"), PU_CACHE));
+}
+
+//
+// Change Sfx & Music volumes
+//
+// haleyjd 08/29/10: [STRIFE]
+// * Changed title graphic coordinates
+// * Added voice volume and sensitivity sliders
+//
+void M_DrawSound(void)
+{
+ V_DrawPatchDirect (100, 10, W_CacheLumpName(DEH_String("M_SVOL"), PU_CACHE));
+
+ M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(sfx_vol+1),
+ 16,sfxVolume);
+
+ M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(music_vol+1),
+ 16,musicVolume);
+
+ M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(voice_vol+1),
+ 16,voiceVolume);
+
+ M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(sfx_mouse+1),
+ 16,mouseSensitivity);
+}
+
+void M_Sound(int choice)
+{
+ M_SetupNextMenu(&SoundDef);
+}
+
+void M_SfxVol(int choice)
+{
+ switch(choice)
+ {
+ case 0:
+ if (sfxVolume)
+ sfxVolume--;
+ break;
+ case 1:
+ if (sfxVolume < 15)
+ sfxVolume++;
+ break;
+ }
+
+ S_SetSfxVolume(sfxVolume * 8);
+}
+
+//
+// M_VoiceVol
+//
+// haleyjd 08/29/10: [STRIFE] New function
+// Sets voice volume level.
+//
+void M_VoiceVol(int choice)
+{
+ switch(choice)
+ {
+ case 0:
+ if (voiceVolume)
+ voiceVolume--;
+ break;
+ case 1:
+ if (voiceVolume < 15)
+ voiceVolume++;
+ break;
+ }
+
+ S_SetVoiceVolume(voiceVolume * 8);
+}
+
+void M_MusicVol(int choice)
+{
+ switch(choice)
+ {
+ case 0:
+ if (musicVolume)
+ musicVolume--;
+ break;
+ case 1:
+ if (musicVolume < 15)
+ musicVolume++;
+ break;
+ }
+
+ S_SetMusicVolume(musicVolume * 8);
+}
+
+
+
+
+//
+// M_DrawMainMenu
+//
+// haleyjd 08/27/10: [STRIFE] Changed x coordinate; M_DOOM -> M_STRIFE
+//
+void M_DrawMainMenu(void)
+{
+ V_DrawPatchDirect(84, 2,
+ W_CacheLumpName(DEH_String("M_STRIFE"), PU_CACHE));
+}
+
+
+
+
+//
+// M_NewGame
+//
+// haleyjd 08/31/10: [STRIFE] Changed M_NEWG -> M_NGAME
+//
+void M_DrawNewGame(void)
+{
+ V_DrawPatchDirect(96, 14, W_CacheLumpName(DEH_String("M_NGAME"), PU_CACHE));
+ V_DrawPatchDirect(54, 38, W_CacheLumpName(DEH_String("M_SKILL"), PU_CACHE));
+}
+
+void M_NewGame(int choice)
+{
+ if (netgame && !demoplayback)
+ {
+ M_StartMessage(DEH_String(NEWGAME),NULL,false);
+ return;
+ }
+ // haleyjd 09/07/10: [STRIFE] Removed Chex Quest and DOOM gamemodes
+ if(gameversion == exe_strife_1_31)
+ namingCharacter = true; // for 1.31 save logic
+ M_SetupNextMenu(&NewDef);
+}
+
+
+//
+// M_Episode
+//
+
+// haleyjd: [STRIFE] Unused
+/*
+int epi;
+
+void M_DrawEpisode(void)
+{
+ V_DrawPatchDirect(54, 38, W_CacheLumpName(DEH_String("M_EPISOD"), PU_CACHE));
+}
+
+void M_VerifyNightmare(int key)
+{
+ if (key != key_menu_confirm)
+ return;
+
+ G_DeferedInitNew(nightmare, 1);
+ M_ClearMenus (0);
+}
+*/
+
+void M_ChooseSkill(int choice)
+{
+ // haleyjd 09/07/10: Removed nightmare confirmation
+ // [STRIFE]: start "Name Your Character" menu
+ menuskill = choice;
+ currentMenu = &NameCharDef;
+ itemOn = NameCharDef.lastOn;
+ M_ReadSaveStrings();
+}
+
+/*
+// haleyjd [STRIFE] Unused
+void M_Episode(int choice)
+{
+ if ( (gamemode == shareware)
+ && choice)
+ {
+ M_StartMessage(DEH_String(SWSTRING),NULL,false);
+ M_SetupNextMenu(&ReadDef1);
+ return;
+ }
+
+ // Yet another hack...
+ if ( (gamemode == registered)
+ && (choice > 2))
+ {
+ fprintf( stderr,
+ "M_Episode: 4th episode requires UltimateDOOM\n");
+ choice = 0;
+ }
+
+ epi = choice;
+ M_SetupNextMenu(&NewDef);
+}
+*/
+
+
+//
+// M_Options
+//
+char detailNames[2][9] = {"M_GDHIGH","M_GDLOW"};
+char msgNames[2][9] = {"M_MSGOFF","M_MSGON"};
+
+
+void M_DrawOptions(void)
+{
+ // haleyjd 08/27/10: [STRIFE] M_OPTTTL -> M_OPTION
+ V_DrawPatchDirect(108, 15,
+ W_CacheLumpName(DEH_String("M_OPTION"), PU_CACHE));
+
+ // haleyjd 08/26/10: [STRIFE] Removed messages, sensitivity, detail.
+
+ M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(scrnsize+1),
+ 9,screenSize);
+}
+
+void M_Options(int choice)
+{
+ M_SetupNextMenu(&OptionsDef);
+}
+
+//
+// M_AutoUseHealth
+//
+// [STRIFE] New function
+// haleyjd 20110211: toggle autouse health state
+//
+void M_AutoUseHealth(void)
+{
+ if(!netgame && usergame)
+ {
+ players[consoleplayer].cheats ^= CF_AUTOHEALTH;
+
+ if(players[consoleplayer].cheats & CF_AUTOHEALTH)
+ players[consoleplayer].message = DEH_String("Auto use health ON");
+ else
+ players[consoleplayer].message = DEH_String("Auto use health OFF");
+ }
+}
+
+//
+// M_ChangeShowText
+//
+// [STRIFE] New function
+//
+void M_ChangeShowText(void)
+{
+ dialogshowtext ^= true;
+
+ if(dialogshowtext)
+ players[consoleplayer].message = DEH_String("Conversation Text On");
+ else
+ players[consoleplayer].message = DEH_String("Conversation Text Off");
+}
+
+//
+// Toggle messages on/off
+//
+// [STRIFE] Messages cannot be disabled in Strife
+/*
+void M_ChangeMessages(int choice)
+{
+ // warning: unused parameter `int choice'
+ choice = 0;
+ showMessages = 1 - showMessages;
+
+ if (!showMessages)
+ players[consoleplayer].message = DEH_String(MSGOFF);
+ else
+ players[consoleplayer].message = DEH_String(MSGON);
+
+ message_dontfuckwithme = true;
+}
+*/
+
+
+//
+// M_EndGame
+//
+void M_EndGameResponse(int key)
+{
+ if (key != key_menu_confirm)
+ return;
+
+ currentMenu->lastOn = itemOn;
+ M_ClearMenus (0);
+ D_StartTitle ();
+}
+
+void M_EndGame(int choice)
+{
+ choice = 0;
+ if (!usergame)
+ {
+ S_StartSound(NULL,sfx_oof);
+ return;
+ }
+
+ if (netgame)
+ {
+ M_StartMessage(DEH_String(NETEND),NULL,false);
+ return;
+ }
+
+ M_StartMessage(DEH_String(ENDGAME),M_EndGameResponse,true);
+}
+
+
+
+
+//
+// M_ReadThis
+//
+void M_ReadThis(int choice)
+{
+ choice = 0;
+ M_SetupNextMenu(&ReadDef1);
+}
+
+//
+// M_ReadThis2
+//
+// haleyjd 08/28/10: [STRIFE] Eliminated DOOM stuff.
+//
+void M_ReadThis2(int choice)
+{
+ choice = 0;
+ M_SetupNextMenu(&ReadDef2);
+}
+
+//
+// M_ReadThis3
+//
+// haleyjd 08/28/10: [STRIFE] New function.
+//
+void M_ReadThis3(int choice)
+{
+ choice = 0;
+ M_SetupNextMenu(&ReadDef3);
+}
+
+/*
+// haleyjd 08/28/10: [STRIFE] Not used.
+void M_FinishReadThis(int choice)
+{
+ choice = 0;
+ M_SetupNextMenu(&MainDef);
+}
+*/
+
+#if 0
+extern void F_StartCast(void);
+
+//
+// M_CheckStartCast
+//
+// [STRIFE] New but unused function. Was going to start a cast
+// call from within the menu system... not functional even in
+// the earliest demo version.
+//
+void M_CheckStartCast()
+{
+ if(usergame)
+ {
+ M_StartMessage(DEH_String("You have to end your game first."), NULL, false);
+ return;
+ }
+
+ F_StartCast();
+ M_ClearMenus(0);
+}
+#endif
+
+//
+// M_QuitResponse
+//
+// haleyjd 09/11/10: [STRIFE] Modifications to start up endgame
+// demosequence.
+//
+void M_QuitResponse(int key)
+{
+ char buffer[20];
+
+ if (key != key_menu_confirm)
+ return;
+
+ if(netgame)
+ I_Quit();
+ else
+ {
+ DEH_snprintf(buffer, sizeof(buffer), "qfmrm%i", gametic % 8 + 1);
+ I_StartVoice(buffer);
+ D_QuitGame();
+ }
+}
+
+/*
+// haleyjd 09/11/10: [STRIFE] Unused
+static char *M_SelectEndMessage(void)
+{
+}
+*/
+
+//
+// M_QuitStrife
+//
+// [STRIFE] Renamed from M_QuitDOOM
+// haleyjd 09/11/10: No randomized text message; that's taken care of
+// by the randomized voice message after confirmation.
+//
+void M_QuitStrife(int choice)
+{
+ DEH_snprintf(endstring, sizeof(endstring),
+ "Do you really want to leave?\n\n" DOSY);
+
+ M_StartMessage(endstring, M_QuitResponse, true);
+}
+
+
+
+
+void M_ChangeSensitivity(int choice)
+{
+ switch(choice)
+ {
+ case 0:
+ if (mouseSensitivity)
+ mouseSensitivity--;
+ break;
+ case 1:
+ if (mouseSensitivity < 9)
+ mouseSensitivity++;
+ break;
+ }
+}
+
+/*
+// haleyjd [STRIFE] Unused
+void M_ChangeDetail(int choice)
+{
+ choice = 0;
+ detailLevel = 1 - detailLevel;
+
+ R_SetViewSize (screenblocks, detailLevel);
+
+ if (!detailLevel)
+ players[consoleplayer].message = DEH_String(DETAILHI);
+ else
+ players[consoleplayer].message = DEH_String(DETAILLO);
+}
+*/
+
+// [STRIFE] Verified unmodified
+void M_SizeDisplay(int choice)
+{
+ switch(choice)
+ {
+ case 0:
+ if (screenSize > 0)
+ {
+ screenblocks--;
+ screenSize--;
+ }
+ break;
+ case 1:
+ if (screenSize < 8)
+ {
+ screenblocks++;
+ screenSize++;
+ }
+ break;
+ }
+
+ R_SetViewSize (screenblocks, detailLevel);
+}
+
+
+
+
+//
+// Menu Functions
+//
+
+//
+// M_DrawThermo
+//
+// haleyjd 08/28/10: [STRIFE] Changes to some patch coordinates.
+//
+void
+M_DrawThermo
+( int x,
+ int y,
+ int thermWidth,
+ int thermDot )
+{
+ int xx;
+ int yy; // [STRIFE] Needs a temp y coordinate variable
+ int i;
+
+ xx = x;
+ yy = y + 6; // [STRIFE] +6 to y coordinate
+ V_DrawPatchDirect(xx, yy, W_CacheLumpName(DEH_String("M_THERML"), PU_CACHE));
+ xx += 8;
+ for (i=0;i<thermWidth;i++)
+ {
+ V_DrawPatchDirect(xx, yy, W_CacheLumpName(DEH_String("M_THERMM"), PU_CACHE));
+ xx += 8;
+ }
+ V_DrawPatchDirect(xx, yy, W_CacheLumpName(DEH_String("M_THERMR"), PU_CACHE));
+
+ // [STRIFE] +2 to initial y coordinate
+ V_DrawPatchDirect((x + 8) + thermDot * 8, y + 2,
+ W_CacheLumpName(DEH_String("M_THERMO"), PU_CACHE));
+}
+
+
+// haleyjd: These are from DOOM v0.5 and the prebeta! They drew those ugly red &
+// blue checkboxes... preserved for historical interest, as not in Strife.
+void
+M_DrawEmptyCell
+( menu_t* menu,
+ int item )
+{
+ V_DrawPatchDirect(menu->x - 10, menu->y + item * LINEHEIGHT - 1,
+ W_CacheLumpName(DEH_String("M_CELL1"), PU_CACHE));
+}
+
+void
+M_DrawSelCell
+( menu_t* menu,
+ int item )
+{
+ V_DrawPatchDirect(menu->x - 10, menu->y + item * LINEHEIGHT - 1,
+ W_CacheLumpName(DEH_String("M_CELL2"), PU_CACHE));
+}
+
+
+void
+M_StartMessage
+( char* string,
+ void* routine,
+ boolean input )
+{
+ messageLastMenuActive = menuactive;
+ messageToPrint = 1;
+ messageString = string;
+ messageRoutine = routine;
+ messageNeedsInput = input;
+ menuactive = true;
+ return;
+}
+
+
+
+void M_StopMessage(void)
+{
+ menuactive = messageLastMenuActive;
+ messageToPrint = 0;
+}
+
+
+
+//
+// Find string width from hu_font chars
+//
+int M_StringWidth(char* string)
+{
+ size_t i;
+ int w = 0;
+ int c;
+
+ for (i = 0;i < strlen(string);i++)
+ {
+ c = toupper(string[i]) - HU_FONTSTART;
+ if (c < 0 || c >= HU_FONTSIZE)
+ w += 4;
+ else
+ w += SHORT (hu_font[c]->width);
+ }
+
+ return w;
+}
+
+
+
+//
+// Find string height from hu_font chars
+//
+int M_StringHeight(char* string)
+{
+ size_t i;
+ int h;
+ int height = SHORT(hu_font[0]->height);
+
+ h = height;
+ for (i = 0;i < strlen(string);i++)
+ if (string[i] == '\n')
+ h += height;
+
+ return h;
+}
+
+
+//
+// M_WriteText
+//
+// Write a string using the hu_font
+// haleyjd 09/04/10: [STRIFE]
+// * Rogue made a lot of changes to this for the dialog system.
+//
+int
+M_WriteText
+( int x,
+ int y,
+ const char* string) // haleyjd: made const for safety w/dialog engine
+{
+ int w;
+ const char* ch;
+ int c;
+ int cx;
+ int cy;
+
+ ch = string;
+ cx = x;
+ cy = y;
+
+ while(1)
+ {
+ c = *ch++;
+ if (!c)
+ break;
+
+ // haleyjd 09/04/10: [STRIFE] Don't draw spaces at the start of lines.
+ if(c == ' ' && cx == x)
+ continue;
+
+ if (c == '\n')
+ {
+ cx = x;
+ cy += 11; // haleyjd 09/04/10: [STRIFE]: Changed 12 -> 11
+ continue;
+ }
+
+ c = toupper(c) - HU_FONTSTART;
+ if (c < 0 || c>= HU_FONTSIZE)
+ {
+ cx += 4;
+ continue;
+ }
+
+ w = SHORT (hu_font[c]->width);
+
+ // haleyjd 09/04/10: [STRIFE] Different linebreak handling
+ if (cx + w > SCREENWIDTH - 20)
+ {
+ cx = x;
+ cy += 11;
+ --ch;
+ }
+ else
+ {
+ V_DrawPatchDirect(cx, cy, hu_font[c]);
+ cx += w;
+ }
+ }
+
+ // [STRIFE] Return final y coordinate.
+ return cy + 12;
+}
+
+//
+// M_DialogDimMsg
+//
+// [STRIFE] New function
+// haleyjd 09/04/10: Painstakingly transformed from the assembly code, as the
+// decompiler could not touch it. Redimensions a string to fit on screen, leaving
+// at least a 20 pixel margin on the right side. The string passed in must be
+// writable.
+//
+void M_DialogDimMsg(int x, int y, char *str, boolean useyfont)
+{
+ int rightbound = (SCREENWIDTH - 20) - x;
+ patch_t **fontarray; // ebp
+ int linewidth = 0; // esi
+ int i = 0; // edx
+ char *message = str; // edi
+ char bl; // bl
+
+ if(useyfont)
+ fontarray = yfont;
+ else
+ fontarray = hu_font;
+
+ bl = toupper(*message);
+
+ if(!bl)
+ return;
+
+ // outer loop - run to end of string
+ do
+ {
+ if(bl != '\n')
+ {
+ int charwidth; // eax
+ int tempwidth; // ecx
+
+ if(bl < HU_FONTSTART || bl > HU_FONTEND)
+ charwidth = 4;
+ else
+ charwidth = SHORT(fontarray[bl - HU_FONTSTART]->width);
+
+ tempwidth = linewidth + charwidth;
+
+ // Test if the line still fits within the boundary...
+ if(tempwidth >= rightbound)
+ {
+ // Doesn't fit...
+ char *tempptr = &message[i]; // ebx
+ char al; // al
+
+ // inner loop - run backward til a space (or the start of the
+ // string) is found, subtracting width off the current line.
+ // BUG: shouldn't we stop at a previous '\n' too?
+ while(*tempptr != ' ' && i > 0)
+ {
+ tempptr--;
+ // BUG: they didn't add the first char to linewidth yet...
+ linewidth -= charwidth;
+ i--;
+ al = toupper(*tempptr);
+ if(al < HU_FONTSTART || al > HU_FONTEND)
+ charwidth = 4;
+ else
+ charwidth = SHORT(fontarray[al - HU_FONTSTART]->width);
+ }
+ // Replace the space with a linebreak.
+ // BUG: what if i is zero? ... infinite loop time!
+ message[i] = '\n';
+ linewidth = 0;
+ }
+ else
+ {
+ // The line does fit.
+ // Spaces at the start of a line don't count though.
+ if(!(bl == ' ' && linewidth == 0))
+ linewidth += charwidth;
+ }
+ }
+ else
+ linewidth = 0; // '\n' seen, so reset the line width
+ }
+ while((bl = toupper(message[++i])) != 0); // step to the next character
+}
+
+
+//
+// CONTROL PANEL
+//
+
+//
+// M_Responder
+//
+boolean M_Responder (event_t* ev)
+{
+ int ch;
+ int key;
+ int i;
+ static int joywait = 0;
+ static int mousewait = 0;
+ static int mousey = 0;
+ static int lasty = 0;
+ static int mousex = 0;
+ static int lastx = 0;
+
+ // In testcontrols mode, none of the function keys should do anything
+ // - the only key is escape to quit.
+
+ if (testcontrols)
+ {
+ if (ev->type == ev_quit
+ || (ev->type == ev_keydown
+ && (ev->data1 == key_menu_activate || ev->data1 == key_menu_quit)))
+ {
+ I_Quit();
+ return true;
+ }
+
+ return false;
+ }
+
+ // "close" button pressed on window?
+ if (ev->type == ev_quit)
+ {
+ // First click on close button = bring up quit confirm message.
+ // Second click on close button = confirm quit
+
+ if (menuactive && messageToPrint && messageRoutine == M_QuitResponse)
+ {
+ M_QuitResponse(key_menu_confirm);
+ }
+ else
+ {
+ S_StartSound(NULL, sfx_swtchn);
+ M_QuitStrife(0);
+ }
+
+ return true;
+ }
+
+ // key is the key pressed, ch is the actual character typed
+
+ ch = 0;
+ key = -1;
+
+ if (ev->type == ev_joystick && joywait < I_GetTime())
+ {
+ if (ev->data3 < 0)
+ {
+ key = key_menu_up;
+ joywait = I_GetTime() + 5;
+ }
+ else if (ev->data3 > 0)
+ {
+ key = key_menu_down;
+ joywait = I_GetTime() + 5;
+ }
+
+ if (ev->data2 < 0)
+ {
+ key = key_menu_left;
+ joywait = I_GetTime() + 2;
+ }
+ else if (ev->data2 > 0)
+ {
+ key = key_menu_right;
+ joywait = I_GetTime() + 2;
+ }
+
+ if (ev->data1&1)
+ {
+ key = key_menu_forward;
+ joywait = I_GetTime() + 5;
+ }
+ if (ev->data1&2)
+ {
+ key = key_menu_back;
+ joywait = I_GetTime() + 5;
+ }
+ }
+ else
+ {
+ if (ev->type == ev_mouse && mousewait < I_GetTime())
+ {
+ mousey += ev->data3;
+ if (mousey < lasty-30)
+ {
+ key = key_menu_down;
+ mousewait = I_GetTime() + 5;
+ mousey = lasty -= 30;
+ }
+ else if (mousey > lasty+30)
+ {
+ key = key_menu_up;
+ mousewait = I_GetTime() + 5;
+ mousey = lasty += 30;
+ }
+
+ mousex += ev->data2;
+ if (mousex < lastx-30)
+ {
+ key = key_menu_left;
+ mousewait = I_GetTime() + 5;
+ mousex = lastx -= 30;
+ }
+ else if (mousex > lastx+30)
+ {
+ key = key_menu_right;
+ mousewait = I_GetTime() + 5;
+ mousex = lastx += 30;
+ }
+
+ if (ev->data1&1)
+ {
+ key = key_menu_forward;
+ mousewait = I_GetTime() + 15;
+ mouse_fire_countdown = 5; // villsa [STRIFE]
+ }
+
+ if (ev->data1&2)
+ {
+ key = key_menu_back;
+ mousewait = I_GetTime() + 15;
+ }
+ }
+ else
+ {
+ if (ev->type == ev_keydown)
+ {
+ key = ev->data1;
+ ch = ev->data2;
+ }
+ }
+ }
+
+ if (key == -1)
+ return false;
+
+ // Save Game string input
+ if (saveStringEnter)
+ {
+ switch(key)
+ {
+ case KEY_BACKSPACE:
+ if (saveCharIndex > 0)
+ {
+ saveCharIndex--;
+ savegamestrings[quickSaveSlot][saveCharIndex] = 0;
+ }
+ break;
+
+ case KEY_ESCAPE:
+ saveStringEnter = 0;
+ strcpy(&savegamestrings[quickSaveSlot][0],saveOldString);
+ break;
+
+ case KEY_ENTER:
+ // [STRIFE]
+ saveStringEnter = 0;
+ if(gameversion == exe_strife_1_31 && !namingCharacter)
+ {
+ // In 1.31, we can be here as a result of normal saving again,
+ // whereas in 1.2 this only ever happens when naming your
+ // character to begin a new game.
+ M_DoSave(quickSaveSlot);
+ return true;
+ }
+ if (savegamestrings[quickSaveSlot][0])
+ M_DoNameChar(quickSaveSlot);
+ break;
+
+ default:
+ // Entering a character - use the 'ch' value, not the key
+
+ ch = toupper(ch);
+
+ if (ch != ' '
+ && (ch - HU_FONTSTART < 0 || ch - HU_FONTSTART >= HU_FONTSIZE))
+ {
+ break;
+ }
+
+ if (ch >= 32 && ch <= 127 &&
+ saveCharIndex < SAVESTRINGSIZE-1 &&
+ M_StringWidth(savegamestrings[quickSaveSlot]) <
+ (SAVESTRINGSIZE-2)*8)
+ {
+ savegamestrings[quickSaveSlot][saveCharIndex++] = ch;
+ savegamestrings[quickSaveSlot][saveCharIndex] = 0;
+ }
+ break;
+ }
+ return true;
+ }
+
+ // Take care of any messages that need input
+ if (messageToPrint)
+ {
+ if (messageNeedsInput)
+ {
+ if (key != ' ' && key != KEY_ESCAPE
+ && key != key_menu_confirm && key != key_menu_abort)
+ {
+ return false;
+ }
+ }
+
+ menuactive = messageLastMenuActive;
+ messageToPrint = 0;
+ if (messageRoutine)
+ messageRoutine(key);
+
+ menupause = false; // [STRIFE] unpause
+ menuactive = false;
+ S_StartSound(NULL, sfx_mtalht); // [STRIFE] sound
+ return true;
+ }
+
+ // [STRIFE]:
+ // * In v1.2 this is moved to F9 (quickload)
+ // * In v1.31 it is moved to F12 with DM spy, and quicksave
+ // functionality is restored separate from normal saving
+ /*
+ if (devparm && key == key_menu_help)
+ {
+ G_ScreenShot ();
+ return true;
+ }
+ */
+
+ // F-Keys
+ if (!menuactive)
+ {
+ if (key == key_menu_decscreen) // Screen size down
+ {
+ if (automapactive || chat_on)
+ return false;
+ M_SizeDisplay(0);
+ S_StartSound(NULL, sfx_stnmov);
+ return true;
+ }
+ else if (key == key_menu_incscreen) // Screen size up
+ {
+ if (automapactive || chat_on)
+ return false;
+ M_SizeDisplay(1);
+ S_StartSound(NULL, sfx_stnmov);
+ return true;
+ }
+ else if (key == key_menu_help) // Help key
+ {
+ M_StartControlPanel ();
+ // haleyjd 08/29/10: [STRIFE] always ReadDef1
+ currentMenu = &ReadDef1;
+
+ itemOn = 0;
+ S_StartSound(NULL, sfx_swtchn);
+ return true;
+ }
+ else if (key == key_menu_save) // Save
+ {
+ // [STRIFE]: Hub saves
+ if(gameversion == exe_strife_1_31)
+ namingCharacter = false; // just saving normally, in 1.31
+
+ if(netgame || players[consoleplayer].health <= 0 ||
+ players[consoleplayer].cheats & CF_ONFIRE)
+ {
+ S_StartSound(NULL, sfx_oof);
+ }
+ else
+ {
+ M_StartControlPanel();
+ S_StartSound(NULL, sfx_swtchn);
+ M_SaveGame(0);
+ }
+ return true;
+ }
+ else if (key == key_menu_load) // Load
+ {
+ // [STRIFE]: Hub saves
+ if(gameversion == exe_strife_1_31)
+ {
+ // 1.31: normal save loading
+ namingCharacter = false;
+ M_StartControlPanel();
+ M_LoadGame(0);
+ S_StartSound(NULL, sfx_swtchn);
+ }
+ else
+ {
+ // Pre 1.31: quickload only
+ S_StartSound(NULL, sfx_swtchn);
+ M_QuickLoad();
+ }
+ return true;
+ }
+ else if (key == key_menu_volume) // Sound Volume
+ {
+ M_StartControlPanel ();
+ currentMenu = &SoundDef;
+ itemOn = sfx_vol;
+ S_StartSound(NULL, sfx_swtchn);
+ return true;
+ }
+ else if (key == key_menu_detail) // Detail toggle
+ {
+ //M_ChangeDetail(0);
+ M_AutoUseHealth(); // [STRIFE]
+ S_StartSound(NULL, sfx_swtchn);
+ return true;
+ }
+ else if (key == key_menu_qsave) // Quicksave
+ {
+ // [STRIFE]: Hub saves
+ if(gameversion == exe_strife_1_31)
+ namingCharacter = false; // for 1.31 save changes
+
+ if(netgame || players[consoleplayer].health <= 0 ||
+ players[consoleplayer].cheats & CF_ONFIRE)
+ {
+ S_StartSound(NULL, sfx_oof);
+ }
+ else
+ {
+ S_StartSound(NULL, sfx_swtchn);
+ M_QuickSave();
+ }
+ return true;
+ }
+ else if (key == key_menu_endgame) // End game
+ {
+ S_StartSound(NULL, sfx_swtchn);
+ M_EndGame(0);
+ return true;
+ }
+ else if (key == key_menu_messages) // Toggle messages
+ {
+ //M_ChangeMessages(0);
+ M_ChangeShowText(); // [STRIFE]
+ S_StartSound(NULL, sfx_swtchn);
+ return true;
+ }
+ else if (key == key_menu_qload) // Quickload
+ {
+ // [STRIFE]
+ // * v1.2: takes a screenshot
+ // * v1.31: does quickload again
+ if(gameversion == exe_strife_1_31)
+ {
+ namingCharacter = false;
+ S_StartSound(NULL, sfx_swtchn);
+ M_QuickLoad();
+ }
+ else
+ G_ScreenShot();
+ return true;
+ }
+ else if (key == key_menu_quit) // Quit DOOM
+ {
+ S_StartSound(NULL, sfx_swtchn);
+ M_QuitStrife(0);
+ return true;
+ }
+ else if (key == key_menu_gamma) // gamma toggle
+ {
+ usegamma++;
+ if (usegamma > 4)
+ usegamma = 0;
+ players[consoleplayer].message = DEH_String(gammamsg[usegamma]);
+ I_SetPalette (W_CacheLumpName (DEH_String("PLAYPAL"),PU_CACHE));
+ return true;
+ }
+ else if(gameversion == exe_strife_1_31 && key == key_spy)
+ {
+ // haleyjd 20130301: 1.31 moved screenshots to F12.
+ G_ScreenShot();
+ return true;
+ }
+ }
+
+ // Pop-up menu?
+ if (!menuactive)
+ {
+ if (key == key_menu_activate)
+ {
+ M_StartControlPanel ();
+ S_StartSound(NULL, sfx_swtchn);
+ return true;
+ }
+ return false;
+ }
+
+
+ // Keys usable within menu
+
+ if (key == key_menu_down)
+ {
+ // Move down to next item
+
+ do
+ {
+ if (itemOn+1 > currentMenu->numitems-1)
+ itemOn = 0;
+ else itemOn++;
+ S_StartSound(NULL, sfx_pstop);
+ } while(currentMenu->menuitems[itemOn].status==-1);
+
+ return true;
+ }
+ else if (key == key_menu_up)
+ {
+ // Move back up to previous item
+
+ do
+ {
+ if (!itemOn)
+ itemOn = currentMenu->numitems-1;
+ else itemOn--;
+ S_StartSound(NULL, sfx_pstop);
+ } while(currentMenu->menuitems[itemOn].status==-1);
+
+ return true;
+ }
+ else if (key == key_menu_left)
+ {
+ // Slide slider left
+
+ if (currentMenu->menuitems[itemOn].routine &&
+ currentMenu->menuitems[itemOn].status == 2)
+ {
+ S_StartSound(NULL, sfx_stnmov);
+ currentMenu->menuitems[itemOn].routine(0);
+ }
+ return true;
+ }
+ else if (key == key_menu_right)
+ {
+ // Slide slider right
+
+ if (currentMenu->menuitems[itemOn].routine &&
+ currentMenu->menuitems[itemOn].status == 2)
+ {
+ S_StartSound(NULL, sfx_stnmov);
+ currentMenu->menuitems[itemOn].routine(1);
+ }
+ return true;
+ }
+ else if (key == key_menu_forward)
+ {
+ // Activate menu item
+
+ if (currentMenu->menuitems[itemOn].routine &&
+ currentMenu->menuitems[itemOn].status)
+ {
+ currentMenu->lastOn = itemOn;
+ if (currentMenu->menuitems[itemOn].status == 2)
+ {
+ currentMenu->menuitems[itemOn].routine(1); // right arrow
+ S_StartSound(NULL, sfx_stnmov);
+ }
+ else
+ {
+ currentMenu->menuitems[itemOn].routine(itemOn);
+ //S_StartSound(NULL, sfx_swish); [STRIFE] No sound is played here.
+ }
+ }
+ return true;
+ }
+ else if (key == key_menu_activate)
+ {
+ // Deactivate menu
+ if(gameversion == exe_strife_1_31) // [STRIFE]: 1.31 saving
+ namingCharacter = false;
+
+ if(menuindialog) // [STRIFE] - Get out of dialog engine semi-gracefully
+ P_DialogDoChoice(-1);
+
+ currentMenu->lastOn = itemOn;
+ M_ClearMenus (0);
+ S_StartSound(NULL, sfx_mtalht); // villsa [STRIFE]: sounds
+ return true;
+ }
+ else if (key == key_menu_back)
+ {
+ // Go back to previous menu
+
+ currentMenu->lastOn = itemOn;
+ if (currentMenu->prevMenu)
+ {
+ currentMenu = currentMenu->prevMenu;
+ itemOn = currentMenu->lastOn;
+ S_StartSound(NULL, sfx_swtchn);
+ }
+ return true;
+ }
+ else if (ch != 0)
+ {
+ // Keyboard shortcut?
+
+ for (i = itemOn+1;i < currentMenu->numitems;i++)
+ {
+ if (currentMenu->menuitems[i].alphaKey == ch)
+ {
+ itemOn = i;
+ S_StartSound(NULL, sfx_pstop);
+ return true;
+ }
+ }
+
+ for (i = 0;i <= itemOn;i++)
+ {
+ if (currentMenu->menuitems[i].alphaKey == ch)
+ {
+ itemOn = i;
+ S_StartSound(NULL, sfx_pstop);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+
+
+//
+// M_StartControlPanel
+//
+void M_StartControlPanel (void)
+{
+ // intro might call this repeatedly
+ if (menuactive)
+ return;
+
+ menuactive = 1;
+ menupause = true;
+ currentMenu = &MainDef; // JDC
+ itemOn = currentMenu->lastOn; // JDC
+}
+
+
+//
+// M_Drawer
+// Called after the view has been rendered,
+// but before it has been blitted.
+//
+void M_Drawer (void)
+{
+ static short x;
+ static short y;
+ unsigned int i;
+ unsigned int max;
+ char string[80];
+ char *name;
+ int start;
+
+ inhelpscreens = false;
+
+ // Horiz. & Vertically center string and print it.
+ if (messageToPrint)
+ {
+ start = 0;
+ y = 100 - M_StringHeight(messageString) / 2;
+ while (messageString[start] != '\0')
+ {
+ int foundnewline = 0;
+
+ for (i = 0; i < strlen(messageString + start); i++)
+ if (messageString[start + i] == '\n')
+ {
+ memset(string, 0, sizeof(string));
+ strncpy(string, messageString + start, i);
+ foundnewline = 1;
+ start += i + 1;
+ break;
+ }
+
+ if (!foundnewline)
+ {
+ strcpy(string, messageString + start);
+ start += strlen(string);
+ }
+
+ x = 160 - M_StringWidth(string) / 2;
+ M_WriteText(x, y, string);
+ y += SHORT(hu_font[0]->height);
+ }
+
+ return;
+ }
+
+ if (!menuactive)
+ return;
+
+ if (currentMenu->routine)
+ currentMenu->routine(); // call Draw routine
+
+ // DRAW MENU
+ x = currentMenu->x;
+ y = currentMenu->y;
+ max = currentMenu->numitems;
+
+ for (i=0;i<max;i++)
+ {
+ name = DEH_String(currentMenu->menuitems[i].name);
+
+ if (name[0])
+ {
+ V_DrawPatchDirect (x, y, W_CacheLumpName(name, PU_CACHE));
+ }
+ y += LINEHEIGHT;
+ }
+
+
+ // haleyjd 08/27/10: [STRIFE] Adjust to draw spinning Sigil
+ // DRAW SIGIL
+ V_DrawPatchDirect(x + CURSORXOFF, currentMenu->y - 5 + itemOn*LINEHEIGHT,
+ W_CacheLumpName(DEH_String(cursorName[whichCursor]),
+ PU_CACHE));
+
+}
+
+
+//
+// M_ClearMenus
+//
+// haleyjd 08/28/10: [STRIFE] Added an int param so this can be called by menus.
+// 09/08/10: Added menupause.
+//
+void M_ClearMenus (int choice)
+{
+ choice = 0; // haleyjd: for no warning; not from decompilation.
+ menuactive = 0;
+ menupause = 0;
+}
+
+
+
+
+//
+// M_SetupNextMenu
+//
+void M_SetupNextMenu(menu_t *menudef)
+{
+ currentMenu = menudef;
+ itemOn = currentMenu->lastOn;
+}
+
+
+//
+// M_Ticker
+//
+// haleyjd 08/27/10: [STRIFE] Rewritten for Sigil cursor
+//
+void M_Ticker (void)
+{
+ if (--cursorAnimCounter <= 0)
+ {
+ whichCursor = (whichCursor + 1) % 8;
+ cursorAnimCounter = 5;
+ }
+}
+
+
+//
+// M_Init
+//
+// haleyjd 08/27/10: [STRIFE] Removed DOOM gamemode stuff
+//
+void M_Init (void)
+{
+ currentMenu = &MainDef;
+ menuactive = 0;
+ itemOn = currentMenu->lastOn;
+ whichCursor = 0;
+ cursorAnimCounter = 10;
+ screenSize = screenblocks - 3;
+ messageToPrint = 0;
+ messageString = NULL;
+ messageLastMenuActive = menuactive; // STRIFE-FIXME: assigns 0 here...
+ quickSaveSlot = -1;
+
+ // [STRIFE]: Initialize savegame paths and clear temporary directory
+ G_WriteSaveName(5, "ME");
+ ClearTmp();
+
+ // Here we could catch other version dependencies,
+ // like HELP1/2, and four episodes.
+}
+
diff --git a/src/strife/m_menu.h b/src/strife/m_menu.h
new file mode 100644
index 00000000..cc437384
--- /dev/null
+++ b/src/strife/m_menu.h
@@ -0,0 +1,109 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Menu widget stuff, episode selection and such.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __M_MENU__
+#define __M_MENU__
+
+#include "d_event.h"
+
+//
+// MENU TYPEDEFS
+//
+
+// haleyjd 09/04/10: [STRIFE] Made external
+
+typedef struct
+{
+ // 0 = no cursor here, 1 = ok, 2 = arrows ok
+ short status;
+
+ char name[10];
+
+ // choice = menu item #.
+ // if status = 2,
+ // choice=0:leftarrow,1:rightarrow
+ void (*routine)(int choice);
+
+ // hotkey in menu
+ char alphaKey;
+} menuitem_t;
+
+typedef struct menu_s
+{
+ short numitems; // # of menu items
+ struct menu_s* prevMenu; // previous menu
+ menuitem_t* menuitems; // menu items
+ void (*routine)(); // draw routine
+ short x;
+ short y; // x,y of menu
+ short lastOn; // last item user was on in menu
+} menu_t;
+
+extern menu_t* currentMenu; // villsa [STRIFE] made external
+extern short itemOn;
+
+//
+// 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.
+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);
+
+// haleyjd 09/04/10: Externalized. Draws menu text.
+int M_WriteText(int x, int y, const char *string);
+
+// haleyjd 09/04/10: [STRIFE] New function.
+void M_DialogDimMsg(int x, int y, char *str, boolean useyfont);
+
+// haleyjd [STRIFE] Externalized
+void M_ClearMenus (int choice);
+void M_LoadSelect(int choice);
+
+extern int detailLevel;
+extern int screenblocks;
+
+#endif
diff --git a/src/strife/m_random.c b/src/strife/m_random.c
new file mode 100644
index 00000000..b7e6aa05
--- /dev/null
+++ b/src/strife/m_random.c
@@ -0,0 +1,88 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Random number LUT.
+//
+//-----------------------------------------------------------------------------
+
+
+#include <time.h>
+
+#include "m_random.h"
+
+//
+// M_Random
+// Returns a 0-255 number
+//
+
+static const 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];
+}
+
+//
+// M_ClearRandom
+//
+// haleyjd 20110204 [STRIFE]: No "seeding" of M_Random index
+//
+void M_ClearRandom (void)
+{
+ prndindex = 0;
+ rndindex = 0;
+}
+
+
+
+
diff --git a/setup/configfile.h b/src/strife/m_random.h
index 3ef2cf9b..be778362 100644
--- a/setup/configfile.h
+++ b/src/strife/m_random.h
@@ -25,20 +25,23 @@
//-----------------------------------------------------------------------------
-#ifndef __SETUP_CONFIG__
-#define __SETUP_CONFIG__
+#ifndef __M_RANDOM__
+#define __M_RANDOM__
-extern char *configdir;
-void M_LoadDefaults (void);
-void M_SaveDefaults (void);
+#include "doomtype.h"
-void M_SetConfigDir(void);
-void M_SaveMainDefaults(char *filename);
-void M_SaveExtraDefaults(char *filename);
-void M_ApplyPlatformDefaults(void);
+// Returns a number from 0 to 255,
+// from a lookup table.
+int M_Random (void);
-#endif
+// As M_Random, but used only by the play simulation.
+int P_Random (void);
+
+// Fix randoms for demos.
+void M_ClearRandom (void);
+
+#endif
diff --git a/src/strife/m_saves.c b/src/strife/m_saves.c
new file mode 100644
index 00000000..a4068c4f
--- /dev/null
+++ b/src/strife/m_saves.c
@@ -0,0 +1,538 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2010 James Haley, Samuel Villarreal
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+//
+// [STRIFE] New Module
+//
+// Strife Hub Saving Code
+//
+//-----------------------------------------------------------------------------
+
+// For GNU C and POSIX targets, dirent.h should be available. Otherwise, for
+// Visual C++, we need to include the win_opendir module.
+#if defined(_MSC_VER)
+#include <win_opendir.h>
+#elif defined(__GNUC__) || defined(POSIX)
+#include <dirent.h>
+#else
+#error Need an include for dirent.h!
+#endif
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "z_zone.h"
+#include "i_system.h"
+#include "d_player.h"
+#include "deh_str.h"
+#include "doomstat.h"
+#include "m_misc.h"
+#include "m_saves.h"
+#include "p_dialog.h"
+
+//
+// File Paths
+//
+// Strife maintains multiple file paths related to savegames.
+//
+char *savepath; // The actual path of the selected saveslot
+char *savepathtemp; // The path of the temporary saveslot (strfsav6.ssg)
+char *loadpath; // Path used while loading the game
+
+char character_name[CHARACTER_NAME_LEN]; // Name of "character" for saveslot
+
+//
+// ClearTmp
+//
+// Clear the temporary save directory
+//
+void ClearTmp(void)
+{
+ DIR *sp2dir = NULL;
+ struct dirent *f = NULL;
+
+ if(savepathtemp == NULL)
+ I_Error("you fucked up savedir man!");
+
+ if(!(sp2dir = opendir(savepathtemp)))
+ I_Error("ClearTmp: Couldn't open dir %s", savepathtemp);
+
+ while((f = readdir(sp2dir)))
+ {
+ char *filepath = NULL;
+
+ // haleyjd: skip "." and ".." without assuming they're the
+ // first two entries like the original code did.
+ if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
+ continue;
+
+ // haleyjd: use M_SafeFilePath, not sprintf
+ filepath = M_SafeFilePath(savepathtemp, f->d_name);
+ remove(filepath);
+
+ Z_Free(filepath);
+ }
+
+ closedir(sp2dir);
+}
+
+//
+// ClearSlot
+//
+// Clear a single save slot folder
+//
+void ClearSlot(void)
+{
+ DIR *spdir = NULL;
+ struct dirent *f = NULL;
+
+ if(savepath == NULL)
+ I_Error("userdir is fucked up man!");
+
+ if(!(spdir = opendir(savepath)))
+ I_Error("ClearSlot: Couldn't open dir %s", savepath);
+
+ while((f = readdir(spdir)))
+ {
+ char *filepath = NULL;
+
+ if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
+ continue;
+
+ // haleyjd: use M_SafeFilePath, not sprintf
+ filepath = M_SafeFilePath(savepath, f->d_name);
+ remove(filepath);
+
+ Z_Free(filepath);
+ }
+
+ closedir(spdir);
+}
+
+//
+// FromCurr
+//
+// Copying files from savepathtemp to savepath
+//
+void FromCurr(void)
+{
+ DIR *sp2dir = NULL;
+ struct dirent *f = NULL;
+
+ if(!(sp2dir = opendir(savepathtemp)))
+ I_Error("FromCurr: Couldn't open dir %s", savepathtemp);
+
+ while((f = readdir(sp2dir)))
+ {
+ byte *filebuffer = NULL;
+ int filelen = 0;
+ char *srcfilename = NULL;
+ char *dstfilename = NULL;
+
+ // haleyjd: skip "." and ".." without assuming they're the
+ // first two entries like the original code did.
+ if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
+ continue;
+
+ // haleyjd: use M_SafeFilePath, NOT sprintf.
+ srcfilename = M_SafeFilePath(savepathtemp, f->d_name);
+ dstfilename = M_SafeFilePath(savepath, f->d_name);
+
+ filelen = M_ReadFile(srcfilename, &filebuffer);
+ M_WriteFile(dstfilename, filebuffer, filelen);
+
+ Z_Free(filebuffer);
+ Z_Free(srcfilename);
+ Z_Free(dstfilename);
+ }
+
+ closedir(sp2dir);
+}
+
+//
+// ToCurr
+//
+// Copying files from savepath to savepathtemp
+//
+void ToCurr(void)
+{
+ DIR *spdir = NULL;
+ struct dirent *f = NULL;
+
+ ClearTmp();
+
+ // BUG: Rogue copypasta'd this error message, which is why we don't know
+ // the real original name of this function.
+ if(!(spdir = opendir(savepath)))
+ I_Error("ClearSlot: Couldn't open dir %s", savepath);
+
+ while((f = readdir(spdir)))
+ {
+ byte *filebuffer = NULL;
+ int filelen = 0;
+ char *srcfilename = NULL;
+ char *dstfilename = NULL;
+
+ if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
+ continue;
+
+ // haleyjd: use M_SafeFilePath, NOT sprintf.
+ srcfilename = M_SafeFilePath(savepath, f->d_name);
+ dstfilename = M_SafeFilePath(savepathtemp, f->d_name);
+
+ filelen = M_ReadFile(srcfilename, &filebuffer);
+ M_WriteFile(dstfilename, filebuffer, filelen);
+
+ Z_Free(filebuffer);
+ Z_Free(srcfilename);
+ Z_Free(dstfilename);
+ }
+
+ closedir(spdir);
+}
+
+//
+// M_SaveMoveMapToHere
+//
+// Moves a map to the "HERE" save.
+//
+void M_SaveMoveMapToHere(void)
+{
+ char *mapsave = NULL;
+ char *heresave = NULL;
+ char tmpnum[33];
+
+ // haleyjd: no itoa available...
+ memset(tmpnum, 0, sizeof(tmpnum));
+ sprintf(tmpnum, "%d", gamemap);
+
+ // haleyjd: use M_SafeFilePath, not sprintf
+ mapsave = M_SafeFilePath(savepath, tmpnum);
+ heresave = M_SafeFilePath(savepath, "here");
+
+ // haleyjd: use M_FileExists, not access
+ if(M_FileExists(mapsave))
+ {
+ remove(heresave);
+ rename(mapsave, heresave);
+ }
+
+ Z_Free(mapsave);
+ Z_Free(heresave);
+}
+
+//
+// M_SaveMoveHereToMap
+//
+// Moves the "HERE" save to a map.
+//
+void M_SaveMoveHereToMap(void)
+{
+ char *mapsave = NULL;
+ char *heresave = NULL;
+ char tmpnum[33];
+
+ // haleyjd: no itoa available...
+ memset(tmpnum, 0, sizeof(tmpnum));
+ sprintf(tmpnum, "%d", gamemap);
+
+ mapsave = M_SafeFilePath(savepathtemp, tmpnum);
+ heresave = M_SafeFilePath(savepathtemp, "here");
+
+ if(M_FileExists(heresave))
+ {
+ remove(mapsave);
+ rename(heresave, mapsave);
+ }
+
+ Z_Free(mapsave);
+ Z_Free(heresave);
+}
+
+//
+// M_SaveMisObj
+//
+// Writes the mission objective into the MIS_OBJ file.
+//
+boolean M_SaveMisObj(const char *path)
+{
+ boolean result;
+ char *destpath = NULL;
+
+ // haleyjd 20110210: use M_SafeFilePath, not sprintf
+ destpath = M_SafeFilePath(path, "mis_obj");
+ result = M_WriteFile(destpath, mission_objective, OBJECTIVE_LEN);
+
+ Z_Free(destpath);
+ return result;
+}
+
+//
+// M_ReadMisObj
+//
+// Reads the mission objective from the MIS_OBJ file.
+//
+void M_ReadMisObj(void)
+{
+ FILE *f = NULL;
+ char *srcpath = NULL;
+
+ // haleyjd: use M_SafeFilePath, not sprintf
+ srcpath = M_SafeFilePath(savepathtemp, "mis_obj");
+
+ if((f = fopen(srcpath, "rb")))
+ {
+ fread(mission_objective, 1, OBJECTIVE_LEN, f);
+ fclose(f);
+ }
+
+ Z_Free(srcpath);
+}
+
+//=============================================================================
+//
+// Original Routines
+//
+// haleyjd - None of the below code is derived from Strife itself, but has been
+// adapted or created in order to provide secure, portable filepath handling
+// for the purposes of savegame support. This is partially needed to allow for
+// differences in Choco due to it being multiplatform. The rest exists because
+// I cannot stand programming in an impoverished ANSI C environment that
+// calls sprintf on fixed-size buffers. :P
+//
+
+//
+// M_Calloc
+//
+// haleyjd 20110210 - original routine
+// Because Choco doesn't have Z_Calloc O_o
+//
+void *M_Calloc(size_t n1, size_t n2)
+{
+ return (n1 *= n2) ? memset(Z_Malloc(n1, PU_STATIC, NULL), 0, n1) : NULL;
+}
+
+//
+// M_StringAlloc
+//
+// haleyjd: This routine takes any number of strings and a number of extra
+// characters, calculates their combined length, and calls Z_Alloca to create
+// a temporary buffer of that size. This is extremely useful for allocation of
+// file paths, and is used extensively in d_main.c. The pointer returned is
+// to a temporary Z_Alloca buffer, which lives until the next main loop
+// iteration, so don't cache it. Note that this idiom is not possible with the
+// normal non-standard alloca function, which allocates stack space.
+//
+// [STRIFE] - haleyjd 20110210
+// This routine is taken from the Eternity Engine and adapted to do without
+// Z_Alloca. I need secure string concatenation for filepath handling. The
+// only difference from use in EE is that the pointer returned in *str must
+// be manually freed.
+//
+int M_StringAlloc(char **str, int numstrs, size_t extra, const char *str1, ...)
+{
+ va_list args;
+ size_t len = extra;
+
+ if(numstrs < 1)
+ I_Error("M_StringAlloc: invalid input\n");
+
+ len += strlen(str1);
+
+ --numstrs;
+
+ if(numstrs != 0)
+ {
+ va_start(args, str1);
+
+ while(numstrs != 0)
+ {
+ const char *argstr = va_arg(args, const char *);
+
+ len += strlen(argstr);
+
+ --numstrs;
+ }
+
+ va_end(args);
+ }
+
+ ++len;
+
+ *str = (char *)(M_Calloc(1, len));
+
+ return len;
+}
+
+//
+// M_NormalizeSlashes
+//
+// Remove trailing slashes, translate backslashes to slashes
+// The string to normalize is passed and returned in str
+//
+// killough 11/98: rewritten
+//
+// [STRIFE] - haleyjd 20110210: Borrowed from Eternity and adapted to respect
+// the DIR_SEPARATOR define used by Choco Doom. This routine originated in
+// BOOM.
+//
+void M_NormalizeSlashes(char *str)
+{
+ char *p;
+
+ // Convert all slashes/backslashes to DIR_SEPARATOR
+ for(p = str; *p; p++)
+ {
+ if((*p == '/' || *p == '\\') && *p != DIR_SEPARATOR)
+ *p = DIR_SEPARATOR;
+ }
+
+ // Remove trailing slashes
+ while(p > str && *--p == DIR_SEPARATOR)
+ *p = 0;
+
+ // Collapse multiple slashes
+ for(p = str; (*str++ = *p); )
+ if(*p++ == DIR_SEPARATOR)
+ while(*p == DIR_SEPARATOR)
+ p++;
+}
+
+//
+// M_SafeFilePath
+//
+// haleyjd 20110210 - original routine.
+// This routine performs safe, portable concatenation of a base file path
+// with another path component or file name. The returned string is Z_Malloc'd
+// and should be freed when it has exhausted its usefulness.
+//
+char *M_SafeFilePath(const char *basepath, const char *newcomponent)
+{
+ int newstrlen = 0;
+ char *newstr = NULL;
+
+ if (!strcmp(basepath, ""))
+ {
+ basepath = ".";
+ }
+
+ // Always throw in a slash. M_NormalizeSlashes will remove it in the case
+ // that either basepath or newcomponent includes a redundant slash at the
+ // end or beginning respectively.
+ newstrlen = M_StringAlloc(&newstr, 3, 1, basepath, "/", newcomponent);
+ snprintf(newstr, newstrlen, "%s/%s", basepath, newcomponent);
+ M_NormalizeSlashes(newstr);
+
+ return newstr;
+}
+
+//
+// M_CreateSaveDirs
+//
+// haleyjd 20110210: Vanilla Strife went tits-up if it didn't have the full set
+// of save folders which were created externally by the installer. fraggle says
+// that's no good for Choco purposes, and I agree, so this routine will create
+// the full set of folders under the configured savegamedir.
+//
+void M_CreateSaveDirs(const char *savedir)
+{
+ int i;
+
+ for(i = 0; i < 7; i++)
+ {
+ char *compositedir;
+
+ // compose the full path by concatenating with savedir
+ compositedir = M_SafeFilePath(savedir, M_MakeStrifeSaveDir(i, ""));
+
+ M_MakeDirectory(compositedir);
+
+ Z_Free(compositedir);
+ }
+}
+
+//
+// M_MakeStrifeSaveDir
+//
+// haleyjd 20110211: Convenience routine
+//
+char *M_MakeStrifeSaveDir(int slotnum, const char *extra)
+{
+ static char tmpbuffer[32];
+
+ memset(tmpbuffer, 0, sizeof(tmpbuffer));
+ sprintf(tmpbuffer, "strfsav%d.ssg%s", slotnum, extra);
+
+ return tmpbuffer;
+}
+
+//
+// M_GetFilePath
+//
+// haleyjd: STRIFE-FIXME: Temporary?
+// Code borrowed from Eternity, and modified to return separator char
+//
+char M_GetFilePath(const char *fn, char *dest, size_t len)
+{
+ boolean found_slash = false;
+ char *p;
+ char sepchar = '\0';
+
+ memset(dest, 0, len);
+
+ p = dest + len - 1;
+
+ strncpy(dest, fn, len);
+
+ while(p >= dest)
+ {
+ if(*p == '/' || *p == '\\')
+ {
+ sepchar = *p;
+ found_slash = true; // mark that the path ended with a slash
+ *p = '\0';
+ break;
+ }
+ *p = '\0';
+ p--;
+ }
+
+ // haleyjd: in the case that no slash was ever found, yet the
+ // path string is empty, we are dealing with a file local to the
+ // working directory. The proper path to return for such a string is
+ // not "", but ".", since the format strings add a slash now. When
+ // the string is empty but a slash WAS found, we really do want to
+ // return the empty string, since the path is relative to the root.
+ if(!found_slash && *dest == '\0')
+ *dest = '.';
+
+ // if a separator is not found, default to forward, because Windows
+ // supports that too.
+ if(sepchar == '\0')
+ sepchar = '/';
+
+ return sepchar;
+}
+
+// EOF
+
+
diff --git a/src/strife/m_saves.h b/src/strife/m_saves.h
new file mode 100644
index 00000000..59941850
--- /dev/null
+++ b/src/strife/m_saves.h
@@ -0,0 +1,64 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2010 James Haley, Samuel Villareal
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+//
+// [STRIFE] New Module
+//
+// Strife Hub Saving Code
+//
+//-----------------------------------------------------------------------------
+
+#ifndef M_SAVES_H__
+#define M_SAVES_H__
+
+#define CHARACTER_NAME_LEN 32
+
+extern char *savepath;
+extern char *savepathtemp;
+extern char *loadpath;
+extern char character_name[CHARACTER_NAME_LEN];
+
+// Strife Savegame Functions
+void ClearTmp(void);
+void ClearSlot(void);
+void FromCurr(void);
+void ToCurr(void);
+void M_SaveMoveMapToHere(void);
+void M_SaveMoveHereToMap(void);
+
+boolean M_SaveMisObj(const char *path);
+void M_ReadMisObj(void);
+
+// Custom Utilities for Filepath Handling
+void *M_Calloc(size_t n1, size_t n2);
+void M_NormalizeSlashes(char *str);
+int M_StringAlloc(char **str, int numstrs, size_t extra, const char *str1, ...);
+char *M_SafeFilePath(const char *basepath, const char *newcomponent);
+char M_GetFilePath(const char *fn, char *dest, size_t len);
+char *M_MakeStrifeSaveDir(int slotnum, const char *extra);
+void M_CreateSaveDirs(const char *savedir);
+
+#endif
+
+// EOF
+
+
diff --git a/src/strife/p_ceilng.c b/src/strife/p_ceilng.c
new file mode 100644
index 00000000..fce4dce2
--- /dev/null
+++ b/src/strife/p_ceilng.c
@@ -0,0 +1,351 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION: Ceiling aninmation (lowering, crushing, raising)
+//
+//-----------------------------------------------------------------------------
+
+
+
+#include "z_zone.h"
+#include "doomdef.h"
+#include "p_local.h"
+
+#include "s_sound.h"
+
+// State.
+#include "doomstat.h"
+#include "r_state.h"
+
+// Data.
+#include "sounds.h"
+
+//
+// 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(&ceiling->sector->soundorg, sfx_stnmov);
+ // ?
+ break;
+ }
+ }
+
+ if (res == pastdest)
+ {
+ switch(ceiling->type)
+ {
+ case raiseToHighest:
+ P_RemoveActiveCeiling(ceiling);
+ break;
+
+ case silentCrushAndRaise:
+ S_StartSound(&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(&ceiling->sector->soundorg, sfx_stnmov);
+ }
+ }
+
+ if (res == pastdest)
+ {
+ switch(ceiling->type)
+ {
+ case silentCrushAndRaise:
+ S_StartSound(&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!
+//
+// haleyjd 10/04/10: [STRIFE] Changes:
+// * Fast crushers were made 2x as fast.
+// * lowerAndCrush was apparently "fixed" to actually crush, and was also
+// altered to lower all the way to the floor rather than remain 8 above.
+// * silentCrushAndRaise and crushAndRaise no longer crush.
+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:
+ // [STRIFE]: Speed of fast crushers increased by 2x!
+ ceiling->crush = true;
+ ceiling->topheight = sec->ceilingheight;
+ ceiling->bottomheight = sec->floorheight + (8*FRACUNIT);
+ ceiling->direction = -1;
+ ceiling->speed = CEILSPEED * 4; // [STRIFE] Was CEILSPEED * 2
+ break;
+
+ case lowerAndCrush:
+ // [STRIFE] lowerAndCrush doesn't seem to have crushed in DOOM,
+ // but it was certainly made to do so in Strife! It is also
+ // changed to lower all the way to the floor.
+ ceiling->crush = 1;
+ ceiling->direction = -1;
+ ceiling->speed = CEILSPEED;
+ ceiling->bottomheight = sec->floorheight;
+ break;
+
+ case silentCrushAndRaise:
+ case crushAndRaise:
+ // [STRIFE] haleyjd 20130209: Turns out these types do NOT crush
+ // in Strife... yeah, that makes a lot of sense. Thanks to Gez for
+ // having detected this difference.
+ //ceiling->crush = true;
+ ceiling->topheight = sec->ceilingheight;
+
+ 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] == NULL)
+ {
+ 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 = NULL;
+ P_RemoveThinker (&activeceilings[i]->thinker);
+ activeceilings[i] = NULL;
+ 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)NULL;
+ activeceilings[i]->direction = 0; // in-stasis
+ rtn = 1;
+ }
+ }
+
+
+ return rtn;
+}
diff --git a/src/strife/p_dialog.c b/src/strife/p_dialog.c
new file mode 100644
index 00000000..070288aa
--- /dev/null
+++ b/src/strife/p_dialog.c
@@ -0,0 +1,1420 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2010 James Haley, Samuel Villarreal
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+//
+// [STRIFE] New Module
+//
+// Dialog Engine for Strife
+//
+//-----------------------------------------------------------------------------
+
+#include <stdlib.h>
+
+#include "z_zone.h"
+#include "w_wad.h"
+#include "deh_str.h"
+#include "d_main.h"
+#include "d_mode.h"
+#include "d_player.h"
+#include "doomstat.h"
+#include "m_random.h"
+#include "m_menu.h"
+#include "r_main.h"
+#include "v_video.h"
+#include "p_local.h"
+#include "sounds.h"
+#include "p_dialog.h"
+#include "s_sound.h"
+#include "p_local.h"
+#include "p_inter.h"
+
+//
+// Defines and Macros
+//
+
+// haleyjd: size of the original Strife mapdialog_t structure.
+#define ORIG_MAPDIALOG_SIZE 0x5EC
+
+#define DIALOG_INT(field, ptr) \
+ field = ((int)ptr[0] | \
+ ((int)ptr[1] << 8) | \
+ ((int)ptr[2] << 16) | \
+ ((int)ptr[3] << 24)); \
+ ptr += 4;
+
+#define DIALOG_STR(field, ptr, len) \
+ memcpy(field, ptr, len); \
+ ptr += len;
+
+//
+// Globals
+//
+
+// This can be toggled at runtime to determine if the full dialog messages
+// are subtitled on screen or not. Defaults to off.
+int dialogshowtext = false;
+
+// The global mission objective buffer. This gets written to and read from file,
+// and is set by dialogs and line actions.
+char mission_objective[OBJECTIVE_LEN];
+
+//
+// Static Globals
+//
+
+// True if SCRIPT00 is loaded.
+static boolean script0loaded;
+
+// Number of dialogs defined in the current level's script.
+static int numleveldialogs;
+
+// The actual level dialogs. This didn't exist in Strife, but is new to account
+// for structure alignment/packing concerns, given that Chocolate Doom is
+// multiplatform.
+static mapdialog_t *leveldialogs;
+
+// The actual script00 dialogs. As above.
+static mapdialog_t *script0dialogs;
+
+// Number of dialogs defined in the SCRIPT00 lump.
+static int numscript0dialogs;
+
+// The player engaged in dialog. This is always player 1, though, since Rogue
+// never completed the ability to use dialog outside of single-player mode.
+static player_t *dialogplayer;
+
+// The object to which the player is speaking.
+static mobj_t *dialogtalker;
+
+// The talker's current angle
+static angle_t dialogtalkerangle;
+
+// The currently active mapdialog object.
+static mapdialog_t *currentdialog;
+
+// Text at the end of the choices
+static char dialoglastmsgbuffer[48];
+
+// Item to display to player when picked up or recieved
+static char pickupstring[46];
+
+// Health based on gameskill given by the front's medic
+static const int healthamounts[] = { -100 , -75, -50, -50, -100 };
+
+//=============================================================================
+//
+// Dialog State Sets
+//
+// These are used to animate certain actors in response to what happens in
+// their dialog sequences.
+//
+
+typedef struct dialogstateset_s
+{
+ mobjtype_t type; // the type of object
+ statenum_t greet; // greeting state, for start of dialog
+ statenum_t yes; // "yes" state, for an affirmative response
+ statenum_t no; // "no" state, when you don't have the right items
+} dialogstateset_t;
+
+static dialogstateset_t dialogstatesets[] =
+{
+ { MT_PLAYER, S_NULL, S_NULL, S_NULL },
+ { MT_SHOPKEEPER_W, S_MRGT_00, S_MRYS_00, S_MRNO_00 },
+ { MT_SHOPKEEPER_B, S_MRGT_00, S_MRYS_00, S_MRNO_00 },
+ { MT_SHOPKEEPER_A, S_MRGT_00, S_MRYS_00, S_MRNO_00 },
+ { MT_SHOPKEEPER_M, S_MRGT_00, S_MRYS_00, S_MRNO_00 }
+};
+
+// Rogue stored this in a static global rather than making it a define...
+static int numdialogstatesets = arrlen(dialogstatesets);
+
+// Current dialog talker state
+static dialogstateset_t *dialogtalkerstates;
+
+//=============================================================================
+//
+// Random Messages
+//
+// Rogue hard-coded these so they wouldn't have to repeat them several times
+// in the SCRIPT00 lump, apparently.
+//
+
+#define MAXRNDMESSAGES 10
+
+typedef struct rndmessage_s
+{
+ const char *type_name;
+ int nummessages;
+ char *messages[MAXRNDMESSAGES];
+} rndmessage_t;
+
+static rndmessage_t rndMessages[] =
+{
+ // Peasants
+ {
+ "PEASANT",
+ 10,
+ {
+ "PLEASE DON'T HURT ME.",
+
+ "IF YOU'RE LOOKING TO HURT ME, I'M \n"
+ "NOT REALLY WORTH THE EFFORT.",
+
+ "I DON'T KNOW ANYTHING.",
+
+ "GO AWAY OR I'LL CALL THE GUARDS!",
+
+ "I WISH SOMETIMES THAT ALL THESE \n"
+ "REBELS WOULD JUST LEARN THEIR \n"
+ "PLACE AND STOP THIS NONSENSE.",
+
+ "JUST LEAVE ME ALONE, OK?",
+
+ "I'M NOT SURE, BUT SOMETIMES I THINK \n"
+ "THAT I KNOW SOME OF THE ACOLYTES.",
+
+ "THE ORDER'S GOT EVERYTHING AROUND HERE PRETTY WELL LOCKED UP TIGHT.",
+
+ "THERE'S NO WAY THAT THIS IS JUST A \n"
+ "SECURITY FORCE.",
+
+ "I'VE HEARD THAT THE ORDER IS REALLY \n"
+ "NERVOUS ABOUT THE FRONT'S \n"
+ "ACTIONS AROUND HERE."
+ }
+ },
+ // Rebel
+ {
+ "REBEL",
+ 10,
+ {
+ "THERE'S NO WAY THE ORDER WILL \n"
+ "STAND AGAINST US.",
+
+ "WE'RE ALMOST READY TO STRIKE. \n"
+ "MACIL'S PLANS ARE FALLING IN PLACE.",
+
+ "WE'RE ALL BEHIND YOU, DON'T WORRY.",
+
+ "DON'T GET TOO CLOSE TO ANY OF THOSE BIG ROBOTS. THEY'LL MELT YOU DOWN \n"
+ "FOR SCRAP!",
+
+ "THE DAY OF OUR GLORY WILL SOON \n"
+ "COME, AND THOSE WHO OPPOSE US WILL \n"
+ "BE CRUSHED!",
+
+ "DON'T GET TOO COMFORTABLE. WE'VE \n"
+ "STILL GOT OUR WORK CUT OUT FOR US.",
+
+ "MACIL SAYS THAT YOU'RE THE NEW \n"
+ "HOPE. BEAR THAT IN MIND.",
+
+ "ONCE WE'VE TAKEN THESE CHARLATANS DOWN, WE'LL BE ABLE TO REBUILD THIS "
+ "WORLD AS IT SHOULD BE.",
+
+ "REMEMBER THAT YOU AREN'T FIGHTING \n"
+ "JUST FOR YOURSELF, BUT FOR \n"
+ "EVERYONE HERE AND OUTSIDE.",
+
+ "AS LONG AS ONE OF US STILL STANDS, \n"
+ "WE WILL WIN."
+ }
+ },
+ // Acolyte
+ {
+ "AGUARD",
+ 10,
+ {
+ "MOVE ALONG, PEASANT.",
+
+ "FOLLOW THE TRUE FAITH, ONLY THEN \n"
+ "WILL YOU BEGIN TO UNDERSTAND.",
+
+ "ONLY THROUGH DEATH CAN ONE BE \n"
+ "TRULY REBORN.",
+
+ "I'M NOT INTERESTED IN YOUR USELESS \n"
+ "DRIVEL.",
+
+ "IF I HAD WANTED TO TALK TO YOU I \n"
+ "WOULD HAVE TOLD YOU SO.",
+
+ "GO AND ANNOY SOMEONE ELSE!",
+
+ "KEEP MOVING!",
+
+ "IF THE ALARM GOES OFF, JUST STAY OUT OF OUR WAY!",
+
+ "THE ORDER WILL CLEANSE THE WORLD \n"
+ "AND USHER IT INTO THE NEW ERA.",
+
+ "PROBLEM? NO, I THOUGHT NOT.",
+ }
+ },
+ // Beggar
+ {
+ "BEGGAR",
+ 10,
+ {
+ "ALMS FOR THE POOR?",
+
+ "WHAT ARE YOU LOOKING AT, SURFACER?",
+
+ "YOU WOULDN'T HAVE ANY EXTRA FOOD, WOULD YOU?",
+
+ "YOU SURFACE PEOPLE WILL NEVER \n"
+ " "
+ " UNDERSTAND US.",
+
+ "HA, THE GUARDS CAN'T FIND US. THOSE \n"
+ "IDIOTS DON'T EVEN KNOW WE EXIST.",
+
+ "ONE DAY EVERYONE BUT THOSE WHO SERVE THE ORDER WILL BE FORCED TO "
+ " JOIN US.",
+
+ "STARE NOW, BUT YOU KNOW THAT THIS WILL BE YOUR OWN FACE ONE DAY.",
+
+ // Note: "NOTHING THING" is an authentic typo
+ "THERE'S NOTHING THING MORE \n"
+ "ANNOYING THAN A SURFACER WITH AN ATTITUDE!",
+
+ "THE ORDER WILL MAKE SHORT WORK OF YOUR PATHETIC FRONT.",
+
+ "WATCH YOURSELF SURFACER. WE KNOW OUR ENEMIES!"
+ }
+ },
+ // Templar
+ {
+ "PGUARD",
+ 10,
+ {
+ "WE ARE THE HANDS OF FATE. TO EARN \n"
+ "OUR WRATH IS TO FIND OBLIVION!",
+
+ "THE ORDER WILL CLEANSE THE WORLD \n"
+ "OF THE WEAK AND CORRUPT!",
+
+ "OBEY THE WILL OF THE MASTERS!",
+
+ "LONG LIFE TO THE BROTHERS OF THE \n"
+ "ORDER!",
+
+ "FREE WILL IS AN ILLUSION THAT BINDS \n"
+ "THE WEAK MINDED.",
+
+ "POWER IS THE PATH TO GLORY. TO \n"
+ "FOLLOW THE ORDER IS TO WALK THAT \n"
+ "PATH!",
+
+ "TAKE YOUR PLACE AMONG THE \n"
+ "RIGHTEOUS, JOIN US!",
+
+ "THE ORDER PROTECTS ITS OWN.",
+
+ "ACOLYTES? THEY HAVE YET TO SEE THE FULL GLORY OF THE ORDER.",
+
+ "IF THERE IS ANY HONOR INSIDE THAT \n"
+ "PATHETIC SHELL OF A BODY, \n"
+ "YOU'LL ENTER INTO THE ARMS OF THE \n"
+ "ORDER."
+ }
+ }
+};
+
+// And again, this could have been a define, but was a variable.
+static int numrndmessages = arrlen(rndMessages);
+
+//=============================================================================
+//
+// Dialog Menu Structure
+//
+// The Strife dialog system is actually just a serious abuse of the DOOM menu
+// engine. Hence why it doesn't work in multiplayer games or during demo
+// recording.
+//
+
+#define NUMDIALOGMENUITEMS 6
+
+static void P_DialogDrawer(void);
+
+static menuitem_t dialogmenuitems[] =
+{
+ { 1, "", P_DialogDoChoice, '1' }, // These items are loaded dynamically
+ { 1, "", P_DialogDoChoice, '2' },
+ { 1, "", P_DialogDoChoice, '3' },
+ { 1, "", P_DialogDoChoice, '4' },
+ { 1, "", P_DialogDoChoice, '5' },
+ { 1, "", P_DialogDoChoice, '6' } // Item 6 is always the dismissal item
+};
+
+static menu_t dialogmenu =
+{
+ NUMDIALOGMENUITEMS,
+ NULL,
+ dialogmenuitems,
+ P_DialogDrawer,
+ 42,
+ 75,
+ 0
+};
+
+// Lump number of the dialog background picture, if any.
+static int dialogbgpiclumpnum;
+
+// Name of current speaking character.
+static char *dialogname;
+
+// Current dialog text.
+static const char *dialogtext;
+
+//=============================================================================
+//
+// Routines
+//
+
+//
+// P_ParseDialogLump
+//
+// haleyjd 09/02/10: This is an original function added to parse out the
+// dialogs from the dialog lump rather than reading them raw from the lump
+// pointer. This avoids problems with structure packing.
+//
+static void P_ParseDialogLump(byte *lump, mapdialog_t **dialogs,
+ int numdialogs, int tag)
+{
+ int i;
+ byte *rover = lump;
+
+ *dialogs = Z_Malloc(numdialogs * sizeof(mapdialog_t), tag, NULL);
+
+ for(i = 0; i < numdialogs; i++)
+ {
+ int j;
+ mapdialog_t *curdialog = &((*dialogs)[i]);
+
+ DIALOG_INT(curdialog->speakerid, rover);
+ DIALOG_INT(curdialog->dropitem, rover);
+ DIALOG_INT(curdialog->checkitem[0], rover);
+ DIALOG_INT(curdialog->checkitem[1], rover);
+ DIALOG_INT(curdialog->checkitem[2], rover);
+ DIALOG_INT(curdialog->jumptoconv, rover);
+ DIALOG_STR(curdialog->name, rover, MDLG_NAMELEN);
+ DIALOG_STR(curdialog->voice, rover, MDLG_LUMPLEN);
+ DIALOG_STR(curdialog->backpic, rover, MDLG_LUMPLEN);
+ DIALOG_STR(curdialog->text, rover, MDLG_TEXTLEN);
+
+ // copy choices
+ for(j = 0; j < 5; j++)
+ {
+ mapdlgchoice_t *curchoice = &(curdialog->choices[j]);
+ DIALOG_INT(curchoice->giveitem, rover);
+ DIALOG_INT(curchoice->needitems[0], rover);
+ DIALOG_INT(curchoice->needitems[1], rover);
+ DIALOG_INT(curchoice->needitems[2], rover);
+ DIALOG_INT(curchoice->needamounts[0], rover);
+ DIALOG_INT(curchoice->needamounts[1], rover);
+ DIALOG_INT(curchoice->needamounts[2], rover);
+ DIALOG_STR(curchoice->text, rover, MDLG_CHOICELEN);
+ DIALOG_STR(curchoice->textok, rover, MDLG_MSGLEN);
+ DIALOG_INT(curchoice->next, rover);
+ DIALOG_INT(curchoice->objective, rover);
+ DIALOG_STR(curchoice->textno, rover, MDLG_MSGLEN);
+ }
+ }
+}
+
+//
+// P_DialogLoad
+//
+// [STRIFE] New function
+// haleyjd 09/02/10: Loads the dialog script for the current map. Also loads
+// SCRIPT00 if it has not yet been loaded.
+//
+void P_DialogLoad(void)
+{
+ char lumpname[9];
+ int lumpnum;
+
+ // load the SCRIPTxy lump corresponding to MAPxy, if it exists.
+ DEH_snprintf(lumpname, sizeof(lumpname), "script%02d", gamemap);
+ if((lumpnum = W_CheckNumForName(lumpname)) == -1)
+ numleveldialogs = 0;
+ else
+ {
+ byte *leveldialogptr = W_CacheLumpNum(lumpnum, PU_STATIC);
+ numleveldialogs = W_LumpLength(lumpnum) / ORIG_MAPDIALOG_SIZE;
+ P_ParseDialogLump(leveldialogptr, &leveldialogs, numleveldialogs,
+ PU_LEVEL);
+ Z_Free(leveldialogptr); // haleyjd: free the original lump
+ }
+
+ // also load SCRIPT00 if it has not been loaded yet
+ if(!script0loaded)
+ {
+ byte *script0ptr;
+
+ script0loaded = true;
+ // BUG: Rogue should have used W_GetNumForName here...
+ lumpnum = W_CheckNumForName(DEH_String("script00"));
+ script0ptr = W_CacheLumpNum(lumpnum, PU_STATIC);
+ numscript0dialogs = W_LumpLength(lumpnum) / ORIG_MAPDIALOG_SIZE;
+ P_ParseDialogLump(script0ptr, &script0dialogs, numscript0dialogs,
+ PU_STATIC);
+ Z_Free(script0ptr); // haleyjd: free the original lump
+ }
+}
+
+//
+// P_PlayerHasItem
+//
+// [STRIFE] New function
+// haleyjd 09/02/10: Checks for inventory items, quest flags, etc. for dialogs.
+// Returns the amount possessed, or 0 if none.
+//
+int P_PlayerHasItem(player_t *player, mobjtype_t type)
+{
+ int i;
+
+ if(type > 0)
+ {
+ // check keys
+ if(type >= MT_KEY_BASE && type < MT_INV_SHADOWARMOR)
+ return (player->cards[type - MT_KEY_BASE]);
+
+ // check sigil pieces
+ if(type >= MT_SIGIL_A && type <= MT_SIGIL_E)
+ return (type - MT_SIGIL_A <= player->sigiltype);
+
+ // check quest tokens
+ if(type >= MT_TOKEN_QUEST1 && type <= MT_TOKEN_QUEST31)
+ return (player->questflags & (1 << (type - MT_TOKEN_QUEST1)));
+
+ // check inventory
+ for(i = 0; i < 32; i++)
+ {
+ if(type == player->inventory[i].type)
+ return player->inventory[i].amount;
+ }
+ }
+ return 0;
+}
+
+//
+// P_DialogFind
+//
+// [STRIFE] New function
+// haleyjd 09/03/10: Looks for a dialog definition matching the given
+// Script ID # for an mobj.
+//
+mapdialog_t *P_DialogFind(mobjtype_t type, int jumptoconv)
+{
+ int i;
+
+ // check the map-specific dialogs first
+ for(i = 0; i < numleveldialogs; i++)
+ {
+ if(type == leveldialogs[i].speakerid)
+ {
+ if(jumptoconv <= 1)
+ return &leveldialogs[i];
+ else
+ --jumptoconv;
+ }
+ }
+
+ // check SCRIPT00 dialogs next
+ for(i = 0; i < numscript0dialogs; i++)
+ {
+ if(type == script0dialogs[i].speakerid)
+ return &script0dialogs[i];
+ }
+
+ // the default dialog is script 0 in the SCRIPT00 lump.
+ return &script0dialogs[0];
+}
+
+//
+// P_DialogGetStates
+//
+// [STRIFE] New function
+// haleyjd 09/03/10: Find the set of special dialog states (greetings, yes, no)
+// for a particular thing type.
+//
+static dialogstateset_t *P_DialogGetStates(mobjtype_t type)
+{
+ int i;
+
+ // look for a match by type
+ for(i = 0; i < numdialogstatesets; i++)
+ {
+ if(type == dialogstatesets[i].type)
+ return &dialogstatesets[i];
+ }
+
+ // return the default 0 record if no match.
+ return &dialogstatesets[0];
+}
+
+//
+// P_DialogGetMsg
+//
+// [STRIFE] New function
+// haleyjd 09/03/10: Redirects dialog messages when the script indicates that
+// the actor should use a random message stored in the executable instead.
+//
+static const char *P_DialogGetMsg(const char *message)
+{
+ // if the message starts with "RANDOM"...
+ if(!strncasecmp(message, DEH_String("RANDOM"), 6))
+ {
+ int i;
+ const char *nameloc = message + 7;
+
+ // look for a match in rndMessages for the string starting
+ // 7 chars after "RANDOM_"
+ for(i = 0; i < numrndmessages; i++)
+ {
+ if(!strncasecmp(nameloc, rndMessages[i].type_name, 4))
+ {
+ // found a match, so return a random message
+ int rnd = M_Random();
+ int nummessages = rndMessages[i].nummessages;
+ return DEH_String(rndMessages[i].messages[rnd % nummessages]);
+ }
+ }
+ }
+
+ // otherwise, just return the message passed in.
+ return message;
+}
+
+//
+// P_GiveInventoryItem
+//
+// [STRIFE] New function
+// haleyjd 09/03/10: Give an inventory item to the player, if possible.
+// villsa 09/09/10: Fleshed out routine
+//
+boolean P_GiveInventoryItem(player_t *player, int sprnum, mobjtype_t type)
+{
+ int curinv = 0;
+ int i;
+ boolean ok = false;
+ mobjtype_t item = 0;
+ inventory_t* invtail;
+
+ // repaint the status bar due to inventory changing
+ player->st_update = true;
+
+ while(1)
+ {
+ // inventory is full
+ if(curinv > player->numinventory)
+ return true;
+
+ item = player->inventory[curinv].type;
+ if(type < item)
+ {
+ if(curinv != MAXINVENTORYSLOTS)
+ {
+ // villsa - sort inventory item if needed
+ invtail = &player->inventory[player->numinventory - 1];
+ if(player->numinventory >= (curinv + 1))
+ {
+ for(i = player->numinventory; i >= (curinv + 1); --i)
+ {
+ invtail[1].sprite = invtail[0].sprite;
+ invtail[1].type = invtail[0].type;
+ invtail[1].amount = invtail[0].amount;
+
+ invtail--;
+ }
+ }
+
+ // villsa - add inventory item
+ player->inventory[curinv].amount = 1;
+ player->inventory[curinv].sprite = sprnum;
+ player->inventory[curinv].type = type;
+
+ // sort cursor if needed
+ if(player->numinventory)
+ {
+ if(curinv <= player->inventorycursor)
+ player->inventorycursor++;
+ }
+
+ player->numinventory++;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ if(type == item)
+ break;
+
+ curinv++;
+ }
+
+ // check amount of inventory item by using the mass from mobjinfo
+ if(player->inventory[curinv].amount < mobjinfo[item].mass)
+ {
+ player->inventory[curinv].amount++;
+ ok = true;
+ }
+ else
+ ok = false;
+
+ return ok;
+}
+
+//
+// P_GiveItemToPlayer
+//
+// [STRIFE] New function
+// haleyjd 09/03/10: Sorts out how to give something to the player.
+// Not strictly just for inventory items.
+// villsa 09/09/10: Fleshed out function
+//
+boolean P_GiveItemToPlayer(player_t *player, int sprnum, mobjtype_t type)
+{
+ int i = 0;
+ line_t junk;
+ int sound = sfx_itemup; // haleyjd 09/21/10: different sounds for items
+
+ // set quest if mf_givequest flag is set
+ if(mobjinfo[type].flags & MF_GIVEQUEST)
+ player->questflags |= 1 << (mobjinfo[type].speed - 1);
+
+ // check for keys
+ if(type >= MT_KEY_BASE && type <= MT_NEWKEY5)
+ {
+ P_GiveCard(player, type - MT_KEY_BASE);
+ return true;
+ }
+
+ // check for quest tokens
+ if(type >= MT_TOKEN_QUEST1 && type <= MT_TOKEN_QUEST31)
+ {
+ if(mobjinfo[type].name)
+ {
+ strncpy(pickupstring, DEH_String(mobjinfo[type].name), 39);
+ player->message = pickupstring;
+ }
+ player->questflags |= 1 << (type - MT_TOKEN_QUEST1);
+
+ if(player == &players[consoleplayer])
+ S_StartSound(NULL, sound);
+ return true;
+ }
+
+ // haleyjd 09/22/10: Refactored to give sprites higher priority than
+ // mobjtypes and to implement missing logic.
+ switch(sprnum)
+ {
+ case SPR_HELT: // This is given only by the "DONNYTRUMP" cheat (aka Midas)
+ P_GiveInventoryItem(player, SPR_HELT, MT_TOKEN_TOUGHNESS);
+ P_GiveInventoryItem(player, SPR_GUNT, MT_TOKEN_ACCURACY);
+
+ // [STRIFE] Bizarre...
+ for(i = 0; i < 5 * player->accuracy + 300; i++)
+ P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+ break;
+
+ case SPR_ARM1: // Armor 1
+ if(!P_GiveArmor(player, -2))
+ P_GiveInventoryItem(player, sprnum, type);
+ break;
+
+ case SPR_ARM2: // Armor 2
+ if(!P_GiveArmor(player, -1))
+ P_GiveInventoryItem(player, sprnum, type);
+ break;
+
+ case SPR_COIN: // 1 Gold
+ P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+ break;
+
+ case SPR_CRED: // 10 Gold
+ for(i = 0; i < 10; i++)
+ P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+ break;
+
+ case SPR_SACK: // 25 gold
+ for(i = 0; i < 25; i++)
+ P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+ break;
+
+ case SPR_CHST: // 50 gold
+ for(i = 0; i < 50; i++)
+ P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+
+ case SPR_BBOX: // Box of Bullets
+ if(!P_GiveAmmo(player, am_bullets, 5))
+ return false;
+ break;
+
+ case SPR_BLIT: // Bullet Clip
+ if(!P_GiveAmmo(player, am_bullets, 1))
+ return false;
+ break;
+
+ case SPR_PMAP: // Map powerup
+ if(!P_GivePower(player, pw_allmap))
+ return false;
+ sound = sfx_yeah; // bluh-doop!
+ break;
+
+ case SPR_COMM: // Communicator
+ if(!P_GivePower(player, pw_communicator))
+ return false;
+ sound = sfx_yeah; // bluh-doop!
+ break;
+
+ case SPR_MSSL: // Mini-missile
+ if(!P_GiveAmmo(player, am_missiles, 1))
+ return false;
+ break;
+
+ case SPR_ROKT: // Crate of missiles
+ if(!P_GiveAmmo(player, am_missiles, 5))
+ return false;
+ break;
+
+ case SPR_BRY1: // Battery cell
+ if(!P_GiveAmmo(player, am_cell, 1))
+ return false;
+ break;
+
+ case SPR_CPAC: // Cell pack
+ if(!P_GiveAmmo(player, am_cell, 5))
+ return false;
+ break;
+
+ case SPR_PQRL: // Poison bolts
+ if(!P_GiveAmmo(player, am_poisonbolts, 5))
+ return false;
+ break;
+
+ case SPR_XQRL: // Electric bolts
+ if(!P_GiveAmmo(player, am_elecbolts, 5))
+ return false;
+ break;
+
+ case SPR_GRN1: // HE Grenades
+ if(!P_GiveAmmo(player, am_hegrenades, 1))
+ return false;
+ break;
+
+ case SPR_GRN2: // WP Grenades
+ if(!P_GiveAmmo(player, am_wpgrenades, 1))
+ return false;
+ break;
+
+ case SPR_BKPK: // Backpack (aka Ammo Satchel)
+ 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);
+ break;
+
+ case SPR_RIFL: // Assault Rifle
+ if(player->weaponowned[wp_rifle])
+ return false;
+
+ if(!P_GiveWeapon(player, wp_rifle, false))
+ return false;
+
+ sound = sfx_wpnup; // SHK-CHK!
+ break;
+
+ case SPR_FLAM: // Flamethrower
+ if(player->weaponowned[wp_flame])
+ return false;
+
+ if(!P_GiveWeapon(player, wp_flame, false))
+ return false;
+
+ sound = sfx_wpnup; // SHK-CHK!
+ break;
+
+ case SPR_MMSL: // Mini-missile Launcher
+ if(player->weaponowned[wp_missile])
+ return false;
+
+ if(!P_GiveWeapon(player, wp_missile, false))
+ return false;
+
+ sound = sfx_wpnup; // SHK-CHK!
+ break;
+
+ case SPR_TRPD: // Mauler
+ if(player->weaponowned[wp_mauler])
+ return false;
+
+ if(!P_GiveWeapon(player, wp_mauler, false))
+ return false;
+
+ sound = sfx_wpnup; // SHK-CHK!
+ break;
+
+ case SPR_CBOW: // Here's a crossbow. Just aim straight, and *SPLAT!*
+ if(player->weaponowned[wp_elecbow])
+ return false;
+
+ if(!P_GiveWeapon(player, wp_elecbow, false))
+ return false;
+
+ sound = sfx_wpnup; // SHK-CHK!
+ break;
+
+ case SPR_TOKN: // Miscellaneous items - These are determined by thingtype.
+ switch(type)
+ {
+ case MT_KEY_HAND: // Severed hand
+ P_GiveCard(player, key_SeveredHand);
+ break;
+
+ case MT_MONY_300: // 300 Gold (this is the only way to get it, in fact)
+ for(i = 0; i < 300; i++)
+ P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+ break;
+
+ case MT_TOKEN_AMMO: // Ammo token - you get this from the Weapons Trainer
+ if(player->ammo[am_bullets] >= 50)
+ return false;
+
+ player->ammo[am_bullets] = 50;
+ break;
+
+ case MT_TOKEN_HEALTH: // Health token - from the Front's doctor
+ if(!P_GiveBody(player, healthamounts[gameskill]))
+ return false;
+ break;
+
+ case MT_TOKEN_ALARM: // Alarm token - particularly from the Oracle.
+ P_NoiseAlert(player->mo, player->mo);
+ A_AlertSpectreC(dialogtalker); // BUG: assumes in a dialog o_O
+ break;
+
+ case MT_TOKEN_DOOR1: // Door special 1
+ junk.tag = 222;
+ EV_DoDoor(&junk, open);
+ break;
+
+ case MT_TOKEN_PRISON_PASS: // Door special 1 - Prison pass
+ junk.tag = 223;
+ EV_DoDoor(&junk, open);
+ if(gamemap == 2) // If on Tarnhill, give Prison pass object
+ P_GiveInventoryItem(player, sprnum, type);
+ break;
+
+ case MT_TOKEN_SHOPCLOSE: // Door special 3 - "Shop close" - unused?
+ junk.tag = 222;
+ EV_DoDoor(&junk, close);
+ break;
+
+ case MT_TOKEN_DOOR3: // Door special 4 (or 3? :P )
+ junk.tag = 224;
+ EV_DoDoor(&junk, close);
+ break;
+
+ case MT_TOKEN_STAMINA: // Stamina upgrade
+ if(player->stamina >= 100)
+ return false;
+
+ player->stamina += 10;
+ P_GiveBody(player, 200); // full healing
+ break;
+
+ case MT_TOKEN_NEW_ACCURACY: // Accuracy upgrade
+ if(player->accuracy >= 100)
+ return false;
+
+ player->accuracy += 10;
+ break;
+
+ case MT_SLIDESHOW: // Slideshow (start a finale)
+ gameaction = ga_victory;
+ if(gamemap == 10)
+ P_GiveItemToPlayer(player, SPR_TOKN, MT_TOKEN_QUEST17);
+ break;
+
+ default: // The default is to just give it as an inventory item.
+ P_GiveInventoryItem(player, sprnum, type);
+ break;
+ }
+ break;
+
+ default: // The ultimate default: Give it as an inventory item.
+ if(!P_GiveInventoryItem(player, sprnum, type))
+ return false;
+ break;
+ }
+
+ // Play sound.
+ if(player == &players[consoleplayer])
+ S_StartSound(NULL, sound);
+
+ return true;
+}
+
+//
+// P_TakeDialogItem
+//
+// [STRIFE] New function
+// haleyjd 09/03/10: Removes needed items from the player's inventory.
+//
+static void P_TakeDialogItem(player_t *player, int type, int amount)
+{
+ int i;
+
+ if(amount <= 0)
+ return;
+
+ for(i = 0; i < player->numinventory; i++)
+ {
+ // find a matching item
+ if(type != player->inventory[i].type)
+ continue;
+
+ // if there is none left...
+ if((player->inventory[i].amount -= amount) < 1)
+ {
+ // ...shift everything above it down
+ int j;
+
+ // BUG: They should have stopped at j < numinventory. This
+ // seems to implicitly assume that numinventory is always at
+ // least one less than the max # of slots, otherwise it
+ // pulls in data from the following player_t fields:
+ // st_update, numinventory, inventorycursor, accuracy, stamina
+ for(j = i + 1; j <= player->numinventory; j++)
+ {
+ inventory_t *item1 = &(player->inventory[j - 1]);
+ inventory_t *item2 = &(player->inventory[j]);
+
+ *item1 = *item2;
+ }
+
+ // blank the topmost slot
+ // BUG: This will overwrite the aforementioned fields if
+ // numinventory is equal to the number of slots!
+ // STRIFE-TODO: Overflow emulation?
+ player->inventory[player->numinventory].type = NUMMOBJTYPES;
+ player->inventory[player->numinventory].sprite = -1;
+ player->numinventory--;
+
+ // update cursor position
+ if(player->inventorycursor >= player->numinventory)
+ {
+ if(player->inventorycursor)
+ player->inventorycursor--;
+ }
+ } // end if
+
+ return; // done!
+
+ } // end for
+}
+
+//
+// P_DialogDrawer
+//
+// This function is set as the drawer callback for the dialog menu.
+//
+static void P_DialogDrawer(void)
+{
+ angle_t angle;
+ int y;
+ int i;
+ int height;
+ int finaly;
+ char choicetext[64];
+ char choicetext2[64];
+
+ // Run down bonuscount faster than usual so that flashes from being given
+ // items are less obvious.
+ if(dialogplayer->bonuscount)
+ {
+ dialogplayer->bonuscount -= 3;
+ if(dialogplayer->bonuscount < 0)
+ dialogplayer->bonuscount = 0;
+ }
+
+ angle = R_PointToAngle2(dialogplayer->mo->x,
+ dialogplayer->mo->y,
+ dialogtalker->x,
+ dialogtalker->y);
+ angle -= dialogplayer->mo->angle;
+
+ // Dismiss the dialog if the player is out of alignment, or the thing he was
+ // talking to is now engaged in battle.
+ if ((angle > ANG45 && angle < (ANG270+ANG45))
+ || (dialogtalker->flags & MF_NODIALOG) != 0)
+ {
+ P_DialogDoChoice(dialogmenu.numitems - 1);
+ }
+
+ dialogtalker->reactiontime = 2;
+
+ // draw background
+ if(dialogbgpiclumpnum != -1)
+ {
+ patch_t *patch = W_CacheLumpNum(dialogbgpiclumpnum, PU_CACHE);
+ V_DrawPatchDirect(0, 0, patch);
+ }
+
+ // if there's a valid background pic, delay drawing the rest of the menu
+ // for a while; otherwise, it will appear immediately
+ if(dialogbgpiclumpnum == -1 || menupausetime <= gametic)
+ {
+ if(menuindialog)
+ {
+ // time to pause the game?
+ if(menupausetime + 3 < gametic)
+ menupause = true;
+ }
+
+ // draw character name
+ M_WriteText(12, 18, dialogname);
+ y = 28;
+
+ // show text (optional for dialogs with voices)
+ if(dialogshowtext || currentdialog->voice[0] == '\0')
+ y = M_WriteText(20, 28, dialogtext);
+
+ height = 20 * dialogmenu.numitems;
+
+ finaly = 175 - height; // preferred height
+ if(y > finaly)
+ finaly = 199 - height; // height it will bump down to if necessary.
+
+ // draw divider
+ M_WriteText(42, finaly - 6, DEH_String("______________________________"));
+
+ dialogmenu.y = finaly + 6;
+ y = 0;
+
+ // draw the menu items
+ for(i = 0; i < dialogmenu.numitems - 1; i++)
+ {
+ DEH_snprintf(choicetext, sizeof(choicetext),
+ "%d) %s", i + 1, currentdialog->choices[i].text);
+
+ // alternate text for items that need money
+ if(currentdialog->choices[i].needamounts[0] > 0)
+ {
+ // haleyjd 20120401: necessary to avoid undefined behavior:
+ strcpy(choicetext2, choicetext);
+ DEH_snprintf(choicetext, sizeof(choicetext),
+ "%s for %d",
+ choicetext2,
+ currentdialog->choices[i].needamounts[0]);
+ }
+
+ M_WriteText(dialogmenu.x, dialogmenu.y + 3 + y, choicetext);
+ y += 19;
+ }
+
+ // draw the final item for dismissing the dialog
+ M_WriteText(dialogmenu.x, 19 * i + dialogmenu.y + 3, dialoglastmsgbuffer);
+ }
+}
+
+//
+// P_DialogDoChoice
+//
+// [STRIFE] New function
+// haleyjd 09/05/10: Handles making a choice in a dialog. Installed as the
+// callback for all items in the dialogmenu structure.
+//
+void P_DialogDoChoice(int choice)
+{
+ int i = 0, nextdialog = 0;
+ boolean candochoice = true;
+ char *message = NULL;
+ mapdlgchoice_t *currentchoice;
+
+ if(choice == -1)
+ choice = dialogmenu.numitems - 1;
+
+ currentchoice = &(currentdialog->choices[choice]);
+
+ I_StartVoice(NULL); // STRIFE-TODO: verify (should stop previous voice I believe)
+
+ // villsa 09/08/10: converted into for loop
+ for(i = 0; i < MDLG_MAXITEMS; i++)
+ {
+ if(P_PlayerHasItem(dialogplayer, currentchoice->needitems[i]) <
+ currentchoice->needamounts[i])
+ {
+ candochoice = false; // nope, missing something
+ }
+ }
+
+ if(choice != dialogmenu.numitems - 1 && candochoice)
+ {
+ int item;
+
+ message = currentchoice->textok;
+ if(dialogtalkerstates->yes)
+ P_SetMobjState(dialogtalker, dialogtalkerstates->yes);
+
+ item = currentchoice->giveitem;
+ if(item < 0 ||
+ P_GiveItemToPlayer(dialogplayer,
+ states[mobjinfo[item].spawnstate].sprite,
+ item))
+ {
+ // if successful, take needed items
+ int count = 0;
+ // villsa 09/08/10: converted into for loop
+ for(count = 0; count < MDLG_MAXITEMS; count++)
+ {
+ P_TakeDialogItem(dialogplayer,
+ currentchoice->needitems[count],
+ currentchoice->needamounts[count]);
+ }
+ }
+ else
+ message = DEH_String("You seem to have enough!");
+
+ // store next dialog into the talking actor
+ nextdialog = currentchoice->next;
+ if(nextdialog != 0)
+ dialogtalker->miscdata = (byte)(abs(nextdialog));
+ }
+ else
+ {
+ // not successful
+ message = currentchoice->textno;
+ if(dialogtalkerstates->no)
+ P_SetMobjState(dialogtalker, dialogtalkerstates->no);
+ }
+
+ if(choice != dialogmenu.numitems - 1)
+ {
+ int objective;
+ char *objlump;
+
+ if((objective = currentchoice->objective))
+ {
+ DEH_snprintf(mission_objective, OBJECTIVE_LEN, "log%i", objective);
+ objlump = W_CacheLumpName(mission_objective, PU_CACHE);
+ strncpy(mission_objective, objlump, OBJECTIVE_LEN);
+ }
+ // haleyjd 20130301: v1.31 hack: if first char of message is a period,
+ // clear the player's message. Is this actually used anywhere?
+ if(gameversion == exe_strife_1_31 && message[0] == '.')
+ message = NULL;
+ dialogplayer->message = message;
+ }
+
+ dialogtalker->angle = dialogtalkerangle;
+ dialogplayer->st_update = true;
+ M_ClearMenus(0);
+
+ if(nextdialog >= 0 || gameaction == ga_victory) // Macil hack
+ menuindialog = false;
+ else
+ P_DialogStart(dialogplayer);
+}
+
+//
+// P_DialogStartP1
+//
+// [STRIFE] New function
+// haleyjd 09/13/10: This is a hack used by the finale system.
+//
+void P_DialogStartP1(void)
+{
+ P_DialogStart(&players[0]);
+}
+
+//
+// P_DialogStart
+//
+// villsa [STRIFE] New function
+//
+void P_DialogStart(player_t *player)
+{
+ int i = 0;
+ int pic;
+ int rnd = 0;
+ char* byetext;
+ int jumptoconv;
+
+ if(menuactive || netgame)
+ return;
+
+ // are we facing towards our NPC?
+ P_AimLineAttack(player->mo, player->mo->angle, (128*FRACUNIT));
+ if(!linetarget)
+ {
+ P_AimLineAttack(player->mo, player->mo->angle + (ANG90/16), (128*FRACUNIT));
+ if(!linetarget)
+ P_AimLineAttack(player->mo, player->mo->angle - (ANG90/16), (128*FRACUNIT));
+ }
+
+ if(!linetarget)
+ return;
+
+ // already in combat, can't talk to it
+ if(linetarget->flags & MF_NODIALOG)
+ return;
+
+ // set pointer to the character talking
+ dialogtalker = linetarget;
+
+ // play a sound
+ if(player == &players[consoleplayer])
+ S_StartSound(0, sfx_radio);
+
+ linetarget->target = player->mo; // target the player
+ dialogtalker->reactiontime = 2; // set reactiontime
+ dialogtalkerangle = dialogtalker->angle; // remember original angle
+
+ // face talker towards player
+ A_FaceTarget(dialogtalker);
+
+ // face towards NPC's direction
+ player->mo->angle = R_PointToAngle2(player->mo->x,
+ player->mo->y,
+ dialogtalker->x,
+ dialogtalker->y);
+ // set pointer to player talking
+ dialogplayer = player;
+
+ // haleyjd 09/08/10: get any stored dialog state from this object
+ jumptoconv = linetarget->miscdata;
+
+ // check item requirements
+ while(1)
+ {
+ int i = 0;
+ currentdialog = P_DialogFind(linetarget->type, jumptoconv);
+
+ // dialog's jumptoconv equal to 0? There's nothing to jump to.
+ if(currentdialog->jumptoconv == 0)
+ break;
+
+ // villsa 09/08/10: converted into for loop
+ for(i = 0; i < MDLG_MAXITEMS; i++)
+ {
+ // if the item is non-zero, the player must have at least one in his
+ // or her inventory
+ if(currentdialog->checkitem[i] != 0 &&
+ P_PlayerHasItem(dialogplayer, currentdialog->checkitem[i]) < 1)
+ break;
+ }
+
+ if(i < MDLG_MAXITEMS) // didn't find them all? this is our dialog!
+ break;
+
+ jumptoconv = currentdialog->jumptoconv;
+ }
+
+ M_DialogDimMsg(20, 28, currentdialog->text, false);
+ dialogtext = P_DialogGetMsg(currentdialog->text);
+
+ // get states
+ dialogtalkerstates = P_DialogGetStates(linetarget->type);
+
+ // have talker greet the player
+ if(dialogtalkerstates->greet)
+ P_SetMobjState(dialogtalker, dialogtalkerstates->greet);
+
+ // get talker's name
+ if(currentdialog->name[0])
+ dialogname = currentdialog->name;
+ else
+ {
+ // use a fallback:
+ if(mobjinfo[linetarget->type].name)
+ dialogname = DEH_String(mobjinfo[linetarget->type].name); // mobjtype name
+ else
+ dialogname = DEH_String("Person"); // default name - like Joe in Doom 3 :P
+ }
+
+ // setup number of choices to choose from
+ for(i = 0; i < MDLG_MAXCHOICES; i++)
+ {
+ if(!currentdialog->choices[i].giveitem)
+ break;
+ }
+
+ // set number of choices to menu
+ dialogmenu.numitems = i + 1;
+
+ rnd = M_Random() % 3;
+
+ // setup dialog menu
+ M_StartControlPanel();
+ menupause = false;
+ menuindialog = true;
+ menupausetime = gametic + 17;
+ currentMenu = &dialogmenu;
+
+ if(i >= dialogmenu.lastOn)
+ itemOn = dialogmenu.lastOn;
+ else
+ itemOn = 0;
+
+ // get backdrop
+ pic = W_CheckNumForName(currentdialog->backpic);
+ dialogbgpiclumpnum = pic;
+ if(pic != -1)
+ V_DrawPatchDirect(0, 0, W_CacheLumpNum(pic, PU_CACHE));
+
+ // get voice
+ I_StartVoice(currentdialog->voice);
+
+ // get bye text
+ switch(rnd)
+ {
+ case 2:
+ byetext = DEH_String("BYE!");
+ break;
+ case 1:
+ byetext = DEH_String("Thanks, Bye!");
+ break;
+ default:
+ case 0:
+ byetext = DEH_String("See you later!");
+ break;
+ }
+
+ DEH_snprintf(dialoglastmsgbuffer, sizeof(dialoglastmsgbuffer),
+ "%d) %s", i + 1, byetext);
+}
+
+// EOF
+
+
diff --git a/src/strife/p_dialog.h b/src/strife/p_dialog.h
new file mode 100644
index 00000000..7463490b
--- /dev/null
+++ b/src/strife/p_dialog.h
@@ -0,0 +1,108 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1996 Rogue Entertainment / Velocity, Inc.
+// Copyright(C) 2010 James Haley, Samuel Villareal
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+//
+// [STRIFE] New Module
+//
+// Dialog Engine for Strife
+//
+//-----------------------------------------------------------------------------
+
+#ifndef P_DIALOG_H__
+#define P_DIALOG_H__
+
+#define OBJECTIVE_LEN 300
+
+#define MAXINVENTORYSLOTS 30
+
+#define MDLG_CHOICELEN 32
+#define MDLG_MSGLEN 80
+#define MDLG_NAMELEN 16
+#define MDLG_LUMPLEN 8
+#define MDLG_TEXTLEN 320
+#define MDLG_MAXCHOICES 5
+#define MDLG_MAXITEMS 3
+
+extern char mission_objective[OBJECTIVE_LEN];
+
+extern int dialogshowtext;
+
+// villsa - convenient macro for giving objective logs to player
+#define GiveObjective(x, minlumpnum) \
+do { \
+ int obj_ln = W_CheckNumForName(DEH_String(x)); \
+ if(obj_ln > minlumpnum) \
+ strncpy(mission_objective, W_CacheLumpNum(obj_ln, PU_CACHE), OBJECTIVE_LEN);\
+} while(0)
+
+// haleyjd - voice and objective in one
+#define GiveVoiceObjective(voice, log, minlumpnum) \
+do { \
+ int obj_ln = W_CheckNumForName(DEH_String(log)); \
+ I_StartVoice(DEH_String(voice)); \
+ if(obj_ln > minlumpnum) \
+ strncpy(mission_objective, W_CacheLumpNum(obj_ln, PU_CACHE), OBJECTIVE_LEN);\
+} while(0)
+
+typedef struct mapdlgchoice_s
+{
+ int giveitem; // item given when successful
+ int needitems[MDLG_MAXITEMS]; // item needed for success
+ int needamounts[MDLG_MAXITEMS]; // amount of items needed
+ char text[MDLG_CHOICELEN]; // normal text
+ char textok[MDLG_MSGLEN]; // message given on success
+ int next; // next dialog?
+ int objective; // ???
+ char textno[MDLG_MSGLEN]; // message given on failure
+} mapdlgchoice_t;
+
+typedef struct mapdialog_s
+{
+ int speakerid; // script ID# for mobjtype that will use this dialog
+ int dropitem; // item to drop if that thingtype is killed
+ int checkitem[MDLG_MAXITEMS]; // item(s) needed to see this dialog
+ int jumptoconv; // conversation to jump to when... ?
+ char name[MDLG_NAMELEN]; // name of speaker
+ char voice[MDLG_LUMPLEN]; // voice file to play
+ char backpic[MDLG_LUMPLEN]; // backdrop pic for character, if any
+ char text[MDLG_TEXTLEN]; // main message text
+
+ // options that this dialog gives the player
+ mapdlgchoice_t choices[MDLG_MAXCHOICES];
+} mapdialog_t;
+
+void P_DialogLoad(void);
+void P_DialogStart(player_t *player);
+void P_DialogDoChoice(int choice);
+boolean P_GiveItemToPlayer(player_t *player, int sprnum, mobjtype_t type);
+boolean P_GiveInventoryItem(player_t *player, int sprnum, mobjtype_t type);
+boolean P_UseInventoryItem(player_t* player, int item);
+void P_DialogStartP1(void);
+mapdialog_t* P_DialogFind(mobjtype_t type, int jumptoconv);
+int P_PlayerHasItem(player_t *player, mobjtype_t type);
+
+#endif
+
+// EOF
+
+
diff --git a/src/strife/p_doors.c b/src/strife/p_doors.c
new file mode 100644
index 00000000..e85d9d7d
--- /dev/null
+++ b/src/strife/p_doors.c
@@ -0,0 +1,1378 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION: Door animation code (opening/closing)
+//
+//-----------------------------------------------------------------------------
+
+
+
+#include "z_zone.h"
+#include "doomdef.h"
+#include "deh_main.h"
+#include "p_local.h"
+
+#include "s_sound.h"
+
+
+// State.
+#include "doomstat.h"
+#include "r_state.h"
+
+// Data.
+#include "dstrings.h"
+#include "sounds.h"
+
+// [STRIFE]
+#include "p_dialog.h"
+#include "i_system.h"
+
+
+//
+// VERTICAL DOORS
+//
+
+//
+// T_VerticalDoor
+//
+void T_VerticalDoor(vldoor_t* door)
+{
+ result_e res1;
+ result_e res2;
+
+ switch(door->direction)
+ {
+ case 0:
+ // WAITING
+ if (!--door->topcountdown)
+ {
+ switch(door->type)
+ {
+ case blazeRaise:
+ door->direction = -1; // time to go back down
+ S_StartSound(&door->sector->soundorg, sfx_bdcls);
+ break;
+
+ case normal:
+ door->direction = -1; // time to go back down
+ // villsa [STRIFE] closesound added
+ S_StartSound(&door->sector->soundorg, door->closesound);
+ break;
+
+ // villsa [STRIFE]
+ case shopClose:
+ door->direction = 1;
+ door->speed = (2*FRACUNIT);
+ S_StartSound(&door->sector->soundorg, door->opensound);
+ break;
+
+ case close30ThenOpen:
+ door->direction = 1;
+
+ // villsa [STRIFE] opensound added
+ S_StartSound(&door->sector->soundorg, door->opensound);
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case 2:
+ // INITIAL WAIT
+ if (!--door->topcountdown)
+ {
+ switch(door->type)
+ {
+ case raiseIn5Mins:
+ door->direction = 1;
+ door->type = normal;
+
+ // villsa [STRIFE] opensound added
+ S_StartSound(&door->sector->soundorg, door->opensound);
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ // villsa [STRIFE]
+ case -2:
+ // SPLIT
+ res1 = T_MovePlane(door->sector, door->speed, door->topheight, 0, 1, 1);
+ res2 = T_MovePlane(door->sector, door->speed, door->topwait, 0, 0, -1);
+
+ if(res1 == pastdest && res2 == pastdest)
+ {
+ door->sector->specialdata = NULL;
+ P_RemoveThinker(&door->thinker); // unlink and free
+ }
+
+ break;
+
+ case -1:
+ // DOWN
+ res1 = T_MovePlane(door->sector, door->speed, door->sector->floorheight, false, 1, door->direction);
+ if(res1 == pastdest)
+ {
+ switch(door->type)
+ {
+ case normal:
+ case close:
+ case blazeRaise:
+ case blazeClose:
+ door->sector->specialdata = NULL;
+ P_RemoveThinker (&door->thinker); // unlink and free
+ // villsa [STRIFE] no sounds
+ break;
+
+ case close30ThenOpen:
+ door->direction = 0;
+ door->topcountdown = TICRATE*30;
+ break;
+
+ // villsa [STRIFE]
+ case shopClose:
+ door->direction = 0;
+ door->topcountdown = TICRATE*120;
+ break;
+
+ default:
+ break;
+ }
+ }
+ else if(res1 == crushed)
+ {
+ switch(door->type)
+ {
+ case blazeClose:
+ case close: // DO NOT GO BACK UP!
+ case shopClose: // villsa [STRIFE]
+ break;
+
+ default:
+ door->direction = 1;
+ // villsa [STRIFE] opensound added
+ S_StartSound(&door->sector->soundorg, door->opensound);
+ break;
+ }
+ }
+ break;
+
+ case 1:
+ // UP
+ res1 = T_MovePlane(door->sector,
+ door->speed,
+ door->topheight,
+ false,1,door->direction);
+
+ if(res1 == pastdest)
+ {
+ switch(door->type)
+ {
+ case blazeRaise:
+ case normal:
+ door->direction = 0; // wait at top
+ door->topcountdown = door->topwait;
+ break;
+
+ case close30ThenOpen:
+ case blazeOpen:
+ case open:
+ case shopClose: // villsa [STRIFE]
+ door->sector->specialdata = NULL;
+ P_RemoveThinker (&door->thinker); // unlink and free
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+ }
+}
+
+
+//
+// EV_DoLockedDoor
+// Move a locked door up/down
+//
+// [STRIFE] This game has a crap load of keys. And this function doesn't even
+// deal with all of them...
+//
+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:
+ case 133:
+ if(!p->cards[key_IDCard])
+ {
+ p->message = DEH_String("You need an id card");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 134:
+ case 135:
+ if(!p->cards[key_IDBadge])
+ {
+ p->message = DEH_String("You need an id badge");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 136:
+ case 137:
+ if(!p->cards[key_Passcard])
+ {
+ p->message = DEH_String("You need a pass card");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 151:
+ case 164:
+ if(!p->cards[key_GoldKey])
+ {
+ p->message = DEH_String("You need a gold key");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 153:
+ case 163:
+ if(!p->cards[key_SilverKey])
+ {
+ p->message = DEH_String("You need a silver key");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 152:
+ case 162:
+ if(!p->cards[key_BrassKey])
+ {
+ p->message = DEH_String("You need a brass key");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 167:
+ case 168:
+ if(!p->cards[key_SeveredHand])
+ {
+ p->message = DEH_String("Hand print not on file");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 171:
+ if(!p->cards[key_PrisonKey])
+ {
+ p->message = DEH_String("You don't have the key to the prison");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 172:
+ if(!p->cards[key_Power1Key])
+ {
+ p->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 173:
+ if(!p->cards[key_Power2Key])
+ {
+ p->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 176:
+ if(!p->cards[key_Power3Key])
+ {
+ p->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 189:
+ if(!p->cards[key_OracleKey])
+ {
+ p->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 191:
+ if(!p->cards[key_MilitaryID])
+ {
+ p->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 192:
+ if(!p->cards[key_WarehouseKey])
+ {
+ p->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 223:
+ if(!p->cards[key_MineKey])
+ {
+ p->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+ }
+
+ return EV_DoDoor(line,type);
+}
+
+
+//
+// EV_DoDoor
+//
+
+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;
+ R_SoundNumForDoor(door); // villsa [STRIFE] set door sounds
+
+ switch(type)
+ {
+ // villsa [STRIFE] new door type
+ case splitOpen:
+ door->direction = -2;
+ door->topheight = P_FindLowestCeilingSurrounding(sec);
+ door->topheight -= 4*FRACUNIT;
+ door->speed = FRACUNIT;
+ // yes, it using topwait to get the floor height
+ door->topwait = P_FindLowestFloorSurrounding(sec);
+ if(door->topheight == sec->ceilingheight)
+ continue;
+
+ S_StartSound(&sec->soundorg, door->opensound);
+ break;
+
+ // villsa [STRIFE] new door type
+ case splitRaiseNearest:
+ door->direction = -2;
+ door->topheight = P_FindLowestCeilingSurrounding(sec);
+ door->topheight -= 4*FRACUNIT;
+ door->speed = FRACUNIT;
+ // yes, it using topwait to get the floor height
+ door->topwait = P_FindHighestFloorSurrounding(sec);
+ if(door->topheight == sec->ceilingheight)
+ continue;
+
+ S_StartSound(&sec->soundorg, door->opensound);
+ break;
+
+ case blazeClose:
+ case shopClose: // villsa [STRIFE]
+ door->topheight = P_FindLowestCeilingSurrounding(sec);
+ door->topheight -= 4*FRACUNIT;
+ door->direction = -1;
+ door->speed = VDOORSPEED * 4;
+ S_StartSound(&door->sector->soundorg, sfx_bdcls);
+ break;
+
+ case close:
+ door->topheight = P_FindLowestCeilingSurrounding(sec);
+ door->topheight -= 4*FRACUNIT;
+ door->direction = -1;
+
+ // villsa [STRIFE] set door sounds
+ S_StartSound(&door->sector->soundorg, door->opensound);
+ break;
+
+ case close30ThenOpen:
+ door->topheight = sec->ceilingheight;
+ door->direction = -1;
+
+ // villsa [STRIFE] set door sounds
+ S_StartSound(&door->sector->soundorg, door->closesound);
+ 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(&door->sector->soundorg, sfx_bdopn);
+ break;
+
+ case normal:
+ case open:
+ door->direction = 1;
+ door->topheight = P_FindLowestCeilingSurrounding(sec);
+ door->topheight -= 4*FRACUNIT;
+
+ if(door->topheight != sec->ceilingheight)
+ S_StartSound(&door->sector->soundorg, door->opensound);
+ break;
+
+ default:
+ break;
+ }
+
+ }
+ return rtn;
+}
+
+//
+// EV_ClearForceFields
+//
+// villsa [STRIFE] new function
+//
+boolean EV_ClearForceFields(line_t* line)
+{
+ int secnum;
+ sector_t* sec;
+ int i;
+ line_t* secline;
+ boolean ret = false;
+
+ secnum = -1;
+
+ while((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
+ {
+ sec = &sectors[secnum];
+
+ line->special = 0;
+ ret = true;
+
+ // haleyjd 09/18/10: fixed to continue w/linecount == 0, not return
+ for(i = 0; i < sec->linecount; i++)
+ {
+ secline = sec->lines[i];
+ if(!(secline->flags & ML_TWOSIDED))
+ continue;
+ if(secline->special != 148)
+ continue;
+
+ secline->flags &= ~ML_BLOCKING;
+ secline->special = 0;
+ sides[secline->sidenum[0]].midtexture = 0;
+ sides[secline->sidenum[1]].midtexture = 0;
+ }
+ }
+
+ return ret;
+}
+
+
+//
+// EV_VerticalDoor : open a door manually, no tag value
+//
+// [STRIFE] Tons of new door types were added.
+//
+void EV_VerticalDoor(line_t* line, mobj_t* thing)
+{
+ player_t* player;
+ sector_t* sec;
+ vldoor_t* door;
+ int side;
+
+ side = 0; // only front sides can be used
+
+ // Check for locks
+ player = thing->player;
+
+ // haleyjd 09/15/10: [STRIFE] myriad checks here...
+ switch(line->special)
+ {
+ case 26: // DR ID Card door
+ case 32: // D1 ID Card door
+ if(!player->cards[key_IDCard])
+ {
+ player->message = DEH_String("You need an id card to open this door");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 27: // DR Pass Card door
+ case 34: // D1 Pass Card door
+ if(!player->cards[key_Passcard])
+ {
+ player->message = DEH_String("You need a pass card key to open this door");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 28: // DR ID Badge door
+ case 33: // D1 ID Badge door
+ if(!player->cards[key_IDBadge])
+ {
+ player->message = DEH_String("You need an id badge to open this door");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 156: // D1 brass key door
+ case 161: // DR brass key door
+ if(!player->cards[key_BrassKey])
+ {
+ player->message = DEH_String("You need a brass key");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 157: // D1 silver key door
+ case 160: // DR silver key door
+ if(!player->cards[key_SilverKey])
+ {
+ player->message = DEH_String("You need a silver key");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 158: // D1 gold key door
+ case 159: // DR gold key door
+ if(!player->cards[key_GoldKey])
+ {
+ player->message = DEH_String("You need a gold key");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ // villsa [STRIFE] added 09/15/10
+ case 165:
+ player->message = DEH_String("That doesn't seem to work");
+ S_StartSound(NULL, sfx_oof);
+ return;
+
+ case 166: // DR Hand Print door
+ if(!player->cards[key_SeveredHand])
+ {
+ player->message = DEH_String("Hand print not on file");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 169: // DR Base key door
+ if(!player->cards[key_BaseKey])
+ {
+ player->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 170: // DR Gov's Key door
+ if(!player->cards[key_GovsKey])
+ {
+ player->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 190: // DR Order Key door
+ if(!player->cards[key_OrderKey])
+ {
+ player->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 205: // DR "Only in retail"
+ player->message = DEH_String("THIS AREA IS ONLY AVAILABLE IN THE "
+ "RETAIL VERSION OF STRIFE");
+ S_StartSound(NULL, sfx_oof);
+ return;
+
+ case 213: // DR Chalice door
+ if(!P_PlayerHasItem(player, MT_INV_CHALICE))
+ {
+ player->message = DEH_String("You need the chalice!");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 217: // DR Core Key door
+ if(!player->cards[key_CoreKey])
+ {
+ player->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 221: // DR Mauler Key door
+ if(!player->cards[key_MaulerKey])
+ {
+ player->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 224: // DR Chapel Key door
+ if(!player->cards[key_ChapelKey])
+ {
+ player->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 225: // DR Catacomb Key door
+ if(!player->cards[key_CatacombKey])
+ {
+ player->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 232: // DR Oracle Pass door
+ if(!(player->questflags & QF_QUEST18))
+ {
+ player->message = DEH_String("You need the Oracle Pass!");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // if the sector has an active thinker, use it
+ sec = sides[ line->sidenum[side^1]] .sector;
+
+ if (sec->specialdata)
+ {
+ door = sec->specialdata;
+ // [STRIFE] Adjusted to handle linetypes handled here by Strife.
+ // BUG: Not all door types are checked here. This means that certain
+ // door lines are allowed to fall through and start a new thinker on the
+ // sector! This is why some doors can become jammed in Strife - stuck in
+ // midair, or unable to be opened at all. Multiple thinkers will fight
+ // over how to move the door. They should have added a default return if
+ // they weren't going to handle this unconditionally...
+ switch(line->special)
+ {
+ case 1: // ONLY FOR "RAISE" DOORS, NOT "OPEN"s
+ case 26:
+ case 27:
+ case 28:
+ case 117:
+ case 159: // villsa
+ case 160: // haleyjd
+ case 161: // villsa
+ case 166: // villsa
+ case 169: // villsa
+ case 170: // villsa
+ case 190: // villsa
+ case 213: // villsa
+ case 232: // villsa
+ if(door->direction == -1)
+ door->direction = 1; // go back up
+ else
+ {
+ if (!thing->player)
+ return;
+
+ // When is a door not a door?
+ // In Vanilla, door->direction is set, even though
+ // "specialdata" might not actually point at a door.
+
+ if (door->thinker.function.acp1 == (actionf_p1) T_VerticalDoor)
+ {
+ door->direction = -1; // start going down immediately
+ }
+ else if (door->thinker.function.acp1 == (actionf_p1) T_PlatRaise)
+ {
+ // Erm, this is a plat, not a door.
+ // This notably causes a problem in ep1-0500.lmp where
+ // a plat and a door are cross-referenced; the door
+ // doesn't open on 64-bit.
+ // The direction field in vldoor_t corresponds to the wait
+ // field in plat_t. Let's set that to -1 instead.
+
+ plat_t *plat;
+
+ plat = (plat_t *) door;
+ plat->wait = -1;
+ }
+ else
+ {
+ // This isn't a door OR a plat. Now we're in trouble.
+
+ fprintf(stderr, "EV_VerticalDoor: Tried to close "
+ "something that wasn't a door.\n");
+
+ // Try closing it anyway. At least it will work on 32-bit
+ // machines.
+
+ door->direction = -1;
+ }
+ }
+ return;
+ default:
+ break;
+ }
+ }
+
+ // haleyjd 09/15/10: [STRIFE] Removed DOOM door sounds
+
+ // 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;
+ R_SoundNumForDoor(door); // haleyjd 09/15/10: [STRIFE] Get door sounds
+
+ // for proper sound - [STRIFE] - verified complete
+ switch(line->special)
+ {
+ case 117: // BLAZING DOOR RAISE
+ case 118: // BLAZING DOOR OPEN
+ S_StartSound(&sec->soundorg, sfx_bdopn);
+ break;
+
+ default: // NORMAL DOOR SOUND
+ S_StartSound(&sec->soundorg, door->opensound);
+ break;
+ }
+
+ // haleyjd: [STRIFE] - verified all.
+ switch(line->special)
+ {
+ case 1:
+ case 26:
+ case 27:
+ case 28:
+ door->type = normal;
+ break;
+
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 156: // villsa [STRIFE]
+ case 157: // villsa [STRIFE]
+ case 158: // villsa [STRIFE]
+ door->type = 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;
+
+ default:
+ // haleyjd: [STRIFE] pretty important to have this here!
+ door->type = normal;
+ 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 = normal;
+ door->speed = VDOORSPEED;
+ door->topcountdown = 30 * TICRATE;
+}
+
+//
+// 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 * TICRATE;
+}
+
+
+// villsa [STRIFE] resurrected sliding doors
+//
+
+//
+// villsa [STRIFE]
+//
+// Sliding door name information
+//
+static slidename_t slideFrameNames[MAXSLIDEDOORS] =
+{
+ // SIGLDR
+ {
+ "SIGLDR01", // frame1
+ "SIGLDR02", // frame2
+ "SIGLDR03", // frame3
+ "SIGLDR04", // frame4
+ "SIGLDR05", // frame5
+ "SIGLDR06", // frame6
+ "SIGLDR07", // frame7
+ "SIGLDR08" // frame8
+ },
+ // DORSTN
+ {
+ "DORSTN01", // frame1
+ "DORSTN02", // frame2
+ "DORSTN03", // frame3
+ "DORSTN04", // frame4
+ "DORSTN05", // frame5
+ "DORSTN06", // frame6
+ "DORSTN07", // frame7
+ "DORSTN08" // frame8
+ },
+
+ // DORQTR
+ {
+ "DORQTR01", // frame1
+ "DORQTR02", // frame2
+ "DORQTR03", // frame3
+ "DORQTR04", // frame4
+ "DORQTR05", // frame5
+ "DORQTR06", // frame6
+ "DORQTR07", // frame7
+ "DORQTR08" // frame8
+ },
+
+ // DORCRG
+ {
+ "DORCRG01", // frame1
+ "DORCRG02", // frame2
+ "DORCRG03", // frame3
+ "DORCRG04", // frame4
+ "DORCRG05", // frame5
+ "DORCRG06", // frame6
+ "DORCRG07", // frame7
+ "DORCRG08" // frame8
+ },
+
+ // DORCHN
+ {
+ "DORCHN01", // frame1
+ "DORCHN02", // frame2
+ "DORCHN03", // frame3
+ "DORCHN04", // frame4
+ "DORCHN05", // frame5
+ "DORCHN06", // frame6
+ "DORCHN07", // frame7
+ "DORCHN08" // frame8
+ },
+
+ // DORIRS
+ {
+ "DORIRS01", // frame1
+ "DORIRS02", // frame2
+ "DORIRS03", // frame3
+ "DORIRS04", // frame4
+ "DORIRS05", // frame5
+ "DORIRS06", // frame6
+ "DORIRS07", // frame7
+ "DORIRS08" // frame8
+ },
+
+ // DORALN
+ {
+ "DORALN01", // frame1
+ "DORALN02", // frame2
+ "DORALN03", // frame3
+ "DORALN04", // frame4
+ "DORALN05", // frame5
+ "DORALN06", // frame6
+ "DORALN07", // frame7
+ "DORALN08" // frame8
+ },
+
+ {"\0","\0","\0","\0","\0","\0","\0","\0"}
+};
+
+//
+// villsa [STRIFE]
+//
+// Sliding door open sounds
+//
+static sfxenum_t slideOpenSounds[MAXSLIDEDOORS] =
+{
+ sfx_drlmto, sfx_drston, sfx_airlck, sfx_drsmto,
+ sfx_drchno, sfx_airlck, sfx_airlck, sfx_None
+};
+
+//
+// villsa [STRIFE]
+//
+// Sliding door close sounds
+//
+static sfxenum_t slideCloseSounds[MAXSLIDEDOORS] =
+{
+ sfx_drlmtc, sfx_drston, sfx_airlck, sfx_drsmtc,
+ sfx_drchnc, sfx_airlck, sfx_airlck, sfx_None
+};
+
+slideframe_t slideFrames[MAXSLIDEDOORS];
+
+//
+// P_InitSlidingDoorFrames
+//
+// villsa [STRIFE] resurrected
+//
+void P_InitSlidingDoorFrames(void)
+{
+ int i;
+ int f1;
+ int f2;
+ int f3;
+ int f4;
+
+ memset(slideFrames, 0, sizeof(slideframe_t) * MAXSLIDEDOORS);
+
+ for(i = 0; i < MAXSLIDEDOORS; i++)
+ {
+ if(!slideFrameNames[i].frame1[0])
+ break;
+
+ f1 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame1));
+ f2 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame2));
+ f3 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame3));
+ f4 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame4));
+
+ slideFrames[i].frames[0] = f1;
+ slideFrames[i].frames[1] = f2;
+ slideFrames[i].frames[2] = f3;
+ slideFrames[i].frames[3] = f4;
+
+ f1 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame5));
+ f2 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame6));
+ f3 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame7));
+ f4 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame8));
+
+ slideFrames[i].frames[4] = f1;
+ slideFrames[i].frames[5] = f2;
+ slideFrames[i].frames[6] = f3;
+ slideFrames[i].frames[7] = f4;
+ }
+}
+
+
+//
+// P_FindSlidingDoorType
+//
+// Return index into "slideFrames" array
+// for which door type to use
+//
+// villsa [STRIFE] resurrected
+//
+int P_FindSlidingDoorType(line_t* line)
+{
+ int i;
+ int val;
+
+ for(i = 0; i < MAXSLIDEDOORS-1; i++)
+ {
+ val = sides[line->sidenum[0]].toptexture;
+ if(val == slideFrames[i].frames[0])
+ return i;
+ }
+
+ return -1;
+}
+
+//
+// T_SlidingDoor
+//
+// villsa [STRIFE] resurrected
+//
+void T_SlidingDoor(slidedoor_t* door)
+{
+ sector_t* sec;
+
+ sec = door->frontsector;
+
+ switch(door->status)
+ {
+ case sd_opening:
+ if(!door->timer--)
+ {
+ if(++door->frame == SNUMFRAMES)
+ {
+ // IF DOOR IS DONE OPENING...
+ door->line1->flags &= ~ML_BLOCKING;
+ door->line2->flags &= ~ML_BLOCKING;
+
+ if(door->type == sdt_openOnly)
+ {
+ door->frontsector->specialdata = NULL;
+ P_RemoveThinker (&door->thinker);
+ return;
+ }
+
+ door->timer = SDOORWAIT;
+ door->status = sd_waiting;
+ }
+ else
+ {
+ // IF DOOR NEEDS TO ANIMATE TO NEXT FRAME...
+ door->timer = SWAITTICS;
+
+ sides[door->line2->sidenum[0]].midtexture =
+ slideFrames[door->whichDoorIndex].frames[door->frame];
+
+ sides[door->line2->sidenum[1]].midtexture =
+ slideFrames[door->whichDoorIndex].frames[door->frame];
+
+ sides[door->line1->sidenum[0]].midtexture =
+ slideFrames[door->whichDoorIndex].frames[door->frame];
+
+ sides[door->line1->sidenum[1]].midtexture =
+ slideFrames[door->whichDoorIndex].frames[door->frame];
+ }
+ }
+
+ return;
+
+ case sd_waiting:
+ // IF DOOR IS DONE WAITING...
+ if(!door->timer--)
+ {
+ fixed_t speed;
+ fixed_t cheight;
+
+ sec = door->frontsector;
+
+ // CAN DOOR CLOSE?
+ if(sec->thinglist != NULL)
+ {
+ door->timer = SDOORWAIT;
+ return;
+ }
+ else
+ {
+
+ cheight = sec->ceilingheight;
+ speed = cheight - sec->floorheight - (10*FRACUNIT);
+
+ // something blocking it?
+ if(T_MovePlane(sec, speed, sec->floorheight, 0, 1, -1) == crushed)
+ {
+ door->timer = SDOORWAIT;
+ return;
+ }
+ else
+ {
+ // Instantly move plane
+ T_MovePlane(sec, (128*FRACUNIT), cheight, 0, 1, 1);
+
+ // turn line blocking back on
+ door->line1->flags |= ML_BLOCKING;
+ door->line2->flags |= ML_BLOCKING;
+
+ // play close sound
+ S_StartSound(&sec->soundorg, slideCloseSounds[door->whichDoorIndex]);
+
+ door->status = sd_closing;
+ door->timer = SWAITTICS;
+ }
+ }
+ }
+
+ return;
+
+ case sd_closing:
+ if (!door->timer--)
+ {
+ if(--door->frame < 0)
+ {
+ // IF DOOR IS DONE CLOSING...
+ T_MovePlane(sec, (128*FRACUNIT), sec->floorheight, 0, 1, -1);
+ door->frontsector->specialdata = NULL;
+ P_RemoveThinker (&door->thinker);
+ return;
+ }
+ else
+ {
+ // IF DOOR NEEDS TO ANIMATE TO NEXT FRAME...
+ door->timer = SWAITTICS;
+
+ sides[door->line2->sidenum[0]].midtexture =
+ slideFrames[door->whichDoorIndex].frames[door->frame];
+
+ sides[door->line2->sidenum[1]].midtexture =
+ slideFrames[door->whichDoorIndex].frames[door->frame];
+
+ sides[door->line1->sidenum[0]].midtexture =
+ slideFrames[door->whichDoorIndex].frames[door->frame];
+
+ sides[door->line1->sidenum[1]].midtexture =
+ slideFrames[door->whichDoorIndex].frames[door->frame];
+ }
+ }
+
+ return;
+ }
+}
+
+//
+// EV_RemoteSlidingDoor
+//
+// villsa [STRIFE] new function
+//
+int EV_RemoteSlidingDoor(line_t* line, mobj_t* thing)
+{
+ int secnum;
+ sector_t* sec;
+ int i;
+ int rtn;
+ line_t* secline;
+
+ secnum = -1;
+ rtn = 0;
+
+ while((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
+ {
+ sec = &sectors[secnum];
+ if(sec->specialdata)
+ continue;
+
+ for(i = 0; i < 4; i++)
+ {
+ secline = sec->lines[i];
+
+ if(P_FindSlidingDoorType(secline) < 0)
+ continue;
+
+ EV_SlidingDoor(secline, thing);
+ rtn = 1;
+ }
+ }
+
+ return rtn;
+}
+
+
+//
+// EV_SlidingDoor
+//
+// villsa [STRIFE]
+//
+void EV_SlidingDoor(line_t* line, mobj_t* thing)
+{
+ sector_t* sec;
+ slidedoor_t* door;
+ int i;
+ line_t* secline;
+
+ // Make sure door isn't already being animated
+ sec = sides[line->sidenum[1]].sector;
+ door = NULL;
+ if(sec->specialdata)
+ {
+ if (!thing->player)
+ return;
+
+ door = sec->specialdata;
+ if(door->type == sdt_openAndClose)
+ {
+ if(door->status == sd_waiting)
+ {
+ door->status = sd_closing;
+ door->timer = SWAITTICS; // villsa [STRIFE]
+ }
+ }
+ else
+ return;
+ }
+
+ // Init sliding door vars
+ if(!door)
+ {
+ door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0);
+ P_AddThinker (&door->thinker);
+
+ sec->specialdata = door;
+
+ door->type = sdt_openAndClose;
+ door->status = sd_opening;
+ door->whichDoorIndex = P_FindSlidingDoorType(line);
+
+ // villsa [STRIFE] different error message
+ if(door->whichDoorIndex < 0)
+ I_Error(DEH_String("EV_SlidingDoor: Textures are not defined for sliding door!"));
+
+ sides[line->sidenum[0]].midtexture = sides[line->sidenum[0]].toptexture;
+
+ // villsa [STRIFE]
+ door->line1 = line;
+ door->line2 = line;
+
+ // villsa [STRIFE] this loop assumes that the sliding door is made up
+ // of only four linedefs!
+ for(i = 0; i < 4; i++)
+ {
+ secline = sec->lines[i];
+ if(secline != line)
+ {
+ side_t* side1;
+ side_t* side2;
+
+ side1 = &sides[secline->sidenum[0]];
+ side2 = &sides[line->sidenum[0]];
+
+ if(side1->toptexture == side2->toptexture)
+ door->line2 = secline;
+ }
+ }
+
+ door->thinker.function.acp1 = (actionf_p1)T_SlidingDoor;
+ door->timer = SWAITTICS;
+ door->frontsector = sec;
+ door->frame = 0;
+
+ // villsa [STRIFE] preset flags
+ door->line1->flags |= ML_BLOCKING;
+ door->line2->flags |= ML_BLOCKING;
+
+ // villsa [STRIFE] set the closing sector
+ T_MovePlane(
+ door->frontsector,
+ (128*FRACUNIT),
+ P_FindLowestCeilingSurrounding(door->frontsector),
+ 0,
+ 1,
+ 1);
+
+ // villsa [STRIFE] play open sound
+ S_StartSound(&door->frontsector->soundorg, slideOpenSounds[door->whichDoorIndex]);
+ }
+}
+
diff --git a/src/strife/p_enemy.c b/src/strife/p_enemy.c
new file mode 100644
index 00000000..684d6b27
--- /dev/null
+++ b/src/strife/p_enemy.c
@@ -0,0 +1,3373 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Enemy thinking, AI.
+// Action Pointer Functions
+// that are associated with states/frames.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "m_random.h"
+#include "i_system.h"
+#include "doomdef.h"
+#include "p_local.h"
+#include "s_sound.h"
+#include "g_game.h"
+#include "z_zone.h" // villsa [STRIFE]
+
+// State.
+#include "doomstat.h"
+#include "r_state.h"
+
+// Data.
+#include "sounds.h"
+
+// [STRIFE] Dialog / Inventory
+#include "p_dialog.h"
+#include "deh_str.h"
+#include "w_wad.h"
+#include "f_finale.h"
+#include "p_inter.h"
+
+// Forward Declarations:
+void A_RandomWalk(mobj_t *);
+void A_ProgrammerAttack(mobj_t* actor);
+void A_FireSigilEOffshoot(mobj_t *actor);
+void A_SpectreCAttack(mobj_t *actor);
+void A_SpectreDAttack(mobj_t *actor);
+void A_SpectreEAttack(mobj_t *actor);
+
+void P_ThrustMobj(mobj_t *actor, angle_t angle, fixed_t force);
+
+typedef enum
+{
+ DI_EAST,
+ DI_NORTHEAST,
+ DI_NORTH,
+ DI_NORTHWEST,
+ DI_WEST,
+ DI_SOUTHWEST,
+ DI_SOUTH,
+ DI_SOUTHEAST,
+ DI_NODIR,
+ NUMDIRS
+
+} dirtype_t;
+
+
+//
+// P_NewChaseDir related LUT.
+//
+dirtype_t opposite[] =
+{
+ DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST,
+ DI_EAST, DI_NORTHEAST, DI_NORTH, DI_NORTHWEST, DI_NODIR
+};
+
+dirtype_t diags[] =
+{
+ DI_NORTHWEST, DI_NORTHEAST, DI_SOUTHWEST, DI_SOUTHEAST
+};
+
+
+
+
+
+void A_Fall (mobj_t *actor);
+
+
+//
+// ENEMY THINKING
+// Enemies are allways spawned
+// with targetplayer = -1, threshold = 0
+// Most monsters are spawned unaware of all players,
+// but some can be made preaware
+//
+
+
+//
+// Called by P_NoiseAlert.
+// Recursively traverse adjacent sectors,
+// sound blocking lines cut off traversal.
+//
+// haleyjd 09/05/10: [STRIFE] Verified unmodified
+//
+
+mobj_t* soundtarget;
+
+void
+P_RecursiveSound
+( sector_t* sec,
+ int soundblocks )
+{
+ int i;
+ line_t* check;
+ sector_t* other;
+
+ // wake up all monsters in this sector
+ if (sec->validcount == validcount
+ && sec->soundtraversed <= soundblocks+1)
+ {
+ return; // already flooded
+ }
+
+ sec->validcount = validcount;
+ sec->soundtraversed = soundblocks+1;
+ sec->soundtarget = soundtarget;
+
+ for (i=0 ;i<sec->linecount ; i++)
+ {
+ check = sec->lines[i];
+ if (! (check->flags & ML_TWOSIDED) )
+ continue;
+
+ P_LineOpening (check);
+
+ if (openrange <= 0)
+ continue; // closed door
+
+ if ( sides[ check->sidenum[0] ].sector == sec)
+ other = sides[ check->sidenum[1] ] .sector;
+ else
+ other = sides[ check->sidenum[0] ].sector;
+
+ if (check->flags & ML_SOUNDBLOCK)
+ {
+ if (!soundblocks)
+ P_RecursiveSound (other, 1);
+ }
+ else
+ P_RecursiveSound (other, soundblocks);
+ }
+}
+
+
+
+//
+// P_NoiseAlert
+// If a monster yells at a player,
+// it will alert other monsters to the player.
+//
+// haleyjd 09/05/10: [STRIFE] Verified unmodified
+//
+void
+P_NoiseAlert
+( mobj_t* target,
+ mobj_t* emmiter )
+{
+ soundtarget = target;
+ validcount++;
+ P_RecursiveSound (emmiter->subsector->sector, 0);
+}
+
+//
+// P_WakeUpThing
+//
+// villsa [STRIFE] New function
+// Wakes up an mobj.nearby when somebody has been punched.
+//
+static void P_WakeUpThing(mobj_t* puncher, mobj_t* bystander)
+{
+ if(!(bystander->flags & MF_NODIALOG))
+ {
+ bystander->target = puncher;
+ if(bystander->info->seesound)
+ S_StartSound(bystander, bystander->info->seesound);
+ P_SetMobjState(bystander, bystander->info->seestate);
+ }
+}
+
+//
+// P_DoPunchAlert
+//
+// villsa [STRIFE] New function (by Quasar ;)
+// Wake up buddies nearby when the player thinks he's gotten too clever
+// with the punch dagger. Walks sector links.
+//
+void P_DoPunchAlert(mobj_t *puncher, mobj_t *punchee)
+{
+ mobj_t *rover;
+
+ // don't bother with this crap if we're already on alert
+ if(punchee->subsector->sector->soundtarget)
+ return;
+
+ // gotta still be alive to call for help
+ if(punchee->health <= 0)
+ return;
+
+ // has to be something you can wake up and kill too
+ if(!(punchee->flags & MF_COUNTKILL) || punchee->flags & MF_NODIALOG)
+ return;
+
+ // make the punchee hurt - haleyjd 09/05/10: Fixed to use painstate.
+ punchee->target = puncher;
+ P_SetMobjState(punchee, punchee->info->painstate);
+
+ // wake up everybody nearby
+
+ // scan forward on sector list
+ for(rover = punchee->snext; rover; rover = rover->snext)
+ {
+ // we only wake up certain thing types (Acolytes and Templars?)
+ if(rover->health > 0 && rover->type >= MT_GUARD1 && rover->type <= MT_PGUARD &&
+ (P_CheckSight(rover, puncher) || P_CheckSight(rover, punchee)))
+ {
+ P_WakeUpThing(puncher, rover);
+ rover->flags |= MF_NODIALOG;
+ }
+ }
+
+ // scan backward on sector list
+ for(rover = punchee->sprev; rover; rover = rover->sprev)
+ {
+ // we only wake up certain thing types (Acolytes and Templars?)
+ if(rover->health > 0 && rover->type >= MT_GUARD1 && rover->type <= MT_PGUARD &&
+ (P_CheckSight(rover, puncher) || P_CheckSight(rover, punchee)))
+ {
+ P_WakeUpThing(puncher, rover);
+ rover->flags |= MF_NODIALOG;
+ }
+ }
+}
+
+
+
+
+//
+// P_CheckMeleeRange
+//
+// [STRIFE] Minor change to meleerange.
+//
+boolean P_CheckMeleeRange(mobj_t* actor)
+{
+ mobj_t* pl;
+ fixed_t dist;
+
+ if(!actor->target)
+ return false;
+
+ pl = actor->target;
+ if(actor->z + 3 * actor->height / 2 < pl->z) // villsa [STRIFE]
+ return false;
+
+ dist = P_AproxDistance(pl->x - actor->x, pl->y - actor->y);
+
+ if(dist >= MELEERANGE - 20*FRACUNIT + pl->info->radius)
+ return false;
+
+ if(!P_CheckSight (actor, actor->target))
+ return false;
+
+ return true;
+}
+
+//
+// P_CheckMissileRange
+//
+// [STRIFE]
+// Changes to eliminate DOOM-specific code and to allow for
+// varying attack ranges for Strife monsters, as well as a general tweak
+// to considered distance for all monsters.
+//
+boolean P_CheckMissileRange(mobj_t* actor)
+{
+ fixed_t dist;
+
+ if(!P_CheckSight(actor, actor->target))
+ return false;
+
+ if(actor->flags & MF_JUSTHIT)
+ {
+ // the target just hit the enemy,
+ // so fight back!
+ actor->flags &= ~MF_JUSTHIT;
+ return true;
+ }
+
+ if(actor->reactiontime)
+ return false; // do not attack yet
+
+ // OPTIMIZE: get this from a global checksight
+ dist = P_AproxDistance(actor->x-actor->target->x,
+ actor->y-actor->target->y) - 64*FRACUNIT;
+
+ if (!actor->info->meleestate)
+ dist -= 128*FRACUNIT; // no melee attack, so fire more
+
+ dist >>= 16;
+
+ // villsa [STRIFE] checks for acolytes
+ // haleyjd 09/05/10: Repaired to match disassembly: Was including
+ // SHADOWGUARD in the wrong case, was missing MT_SENTINEL entirely.
+ // Structure of ASM also indicates this was probably a switch
+ // statement turned into a cascading if/else by the compiler.
+ switch(actor->type)
+ {
+ case MT_GUARD1:
+ case MT_GUARD2:
+ case MT_GUARD3:
+ case MT_GUARD4:
+ case MT_GUARD5:
+ case MT_GUARD6:
+ // oddly, not all Acolytes are included here...
+ dist >>= 4;
+ break;
+ case MT_SHADOWGUARD:
+ case MT_CRUSADER:
+ case MT_SENTINEL:
+ dist >>= 1;
+ break;
+ default:
+ break;
+ }
+
+ // villsa [STRIFE] changed to 150
+ if (dist > 150)
+ dist = 150;
+
+ // haleyjd 20100910: Hex-Rays was leaving this out completely:
+ if (actor->type == MT_CRUSADER && dist > 120)
+ dist = 120;
+
+ // haleyjd 20110224 [STRIFE]: reversed predicate
+ return (dist < P_Random());
+}
+
+//
+// P_CheckRobotRange
+//
+// villsa [STRIFE] New function
+//
+boolean P_CheckRobotRange(mobj_t *actor)
+{
+ fixed_t dist;
+
+ if(!P_CheckSight(actor, actor->target))
+ return false;
+
+ if(actor->reactiontime)
+ return false; // do not attack yet
+
+ dist = (P_AproxDistance(actor->x-actor->target->x,
+ actor->y-actor->target->y) - 64*FRACUNIT) >> FRACBITS;
+
+ return (dist < 200);
+}
+
+
+//
+// P_Move
+// Move in the current direction,
+// returns false if the move is blocked.
+//
+// [STRIFE]
+// villsa/haleyjd 09/05/10: Modified for terrain types and 3D object
+// clipping. Below constants are verified to be unmodified:
+//
+fixed_t xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000};
+fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000};
+
+#define MAXSPECIALCROSS 8
+
+extern line_t* spechit[MAXSPECIALCROSS];
+extern int numspechit;
+
+boolean P_Move (mobj_t* actor)
+{
+ fixed_t tryx;
+ fixed_t tryy;
+
+ line_t* ld;
+
+ // warning: 'catch', 'throw', and 'try'
+ // are all C++ reserved words
+ boolean try_ok;
+ boolean good;
+
+ if (actor->movedir == DI_NODIR)
+ return false;
+
+ if ((unsigned)actor->movedir >= 8)
+ I_Error ("Weird actor->movedir!");
+
+ tryx = actor->x + actor->info->speed*xspeed[actor->movedir];
+ tryy = actor->y + actor->info->speed*yspeed[actor->movedir];
+
+ try_ok = P_TryMove (actor, tryx, tryy);
+
+ if (!try_ok)
+ {
+ // open any specials
+ if (actor->flags & MF_FLOAT && floatok)
+ {
+ // must adjust height
+ if (actor->z < tmfloorz)
+ actor->z += FLOATSPEED; // [STRIFE] Note FLOATSPEED == 5*FRACUNIT
+ else
+ actor->z -= FLOATSPEED;
+
+ actor->flags |= MF_INFLOAT;
+ return true;
+ }
+
+ if (!numspechit)
+ return false;
+
+ actor->movedir = DI_NODIR;
+ good = false;
+ while (numspechit--)
+ {
+ ld = spechit[numspechit];
+ // if the special is not a door
+ // that can be opened,
+ // return false
+ if (P_UseSpecialLine (actor, ld,0))
+ good = true;
+ }
+ return good;
+ }
+ else
+ {
+ actor->flags &= ~(MF_INFLOAT|MF_FEETCLIPPED); // villsa [STRIFE]
+
+ // villsa [STRIFE]
+ if(P_GetTerrainType(actor) != FLOOR_SOLID)
+ actor->flags |= MF_FEETCLIPPED;
+ }
+
+
+ // villsa [STRIFE] Removed pulling non-floating actors down to the ground.
+ // (haleyjd 09/05/10: Verified)
+ /*if (! (actor->flags & MF_FLOAT) )
+ actor->z = actor->floorz;*/
+
+ return true;
+}
+
+
+//
+// TryWalk
+// Attempts to move actor on
+// in its current (ob->moveangle) direction.
+// If blocked by either a wall or an actor
+// returns FALSE
+// If move is either clear or blocked only by a door,
+// returns TRUE and sets...
+// If a door is in the way,
+// an OpenDoor call is made to start it opening.
+//
+// haleyjd 09/05/10: [STRIFE] Verified unmodified.
+//
+boolean P_TryWalk (mobj_t* actor)
+{
+ if (!P_Move (actor))
+ {
+ return false;
+ }
+
+ actor->movecount = P_Random()&15;
+ return true;
+}
+
+
+
+//
+// P_NewChaseDir
+//
+
+void P_NewChaseDir(mobj_t* actor)
+{
+ fixed_t deltax;
+ fixed_t deltay;
+
+ dirtype_t d[3];
+
+ int tdir;
+ dirtype_t olddir;
+
+ dirtype_t turnaround;
+
+ // villsa [STRIFE] don't bomb out and instead set spawnstate
+ if(!actor->target)
+ {
+ //I_Error("P_NewChaseDir: called with no target");
+ P_SetMobjState(actor, actor->info->spawnstate);
+ return;
+ }
+
+ olddir = actor->movedir;
+ turnaround=opposite[olddir];
+
+ deltax = actor->target->x - actor->x;
+ deltay = actor->target->y - actor->y;
+
+ if (deltax>10*FRACUNIT)
+ d[1]= DI_EAST;
+ else if (deltax<-10*FRACUNIT)
+ d[1]= DI_WEST;
+ else
+ d[1]=DI_NODIR;
+
+ if (deltay<-10*FRACUNIT)
+ d[2]= DI_SOUTH;
+ else if (deltay>10*FRACUNIT)
+ d[2]= DI_NORTH;
+ else
+ d[2]=DI_NODIR;
+
+ // try direct route
+ if (d[1] != DI_NODIR
+ && d[2] != DI_NODIR)
+ {
+ actor->movedir = diags[((deltay<0)<<1)+(deltax>0)];
+ if (actor->movedir != (int) turnaround && P_TryWalk(actor))
+ return;
+ }
+
+ // try other directions
+ if (P_Random() > 200
+ || abs(deltay)>abs(deltax))
+ {
+ tdir=d[1];
+ d[1]=d[2];
+ d[2]=tdir;
+ }
+
+ if (d[1]==turnaround)
+ d[1]=DI_NODIR;
+ if (d[2]==turnaround)
+ d[2]=DI_NODIR;
+
+ if (d[1]!=DI_NODIR)
+ {
+ actor->movedir = d[1];
+ if (P_TryWalk(actor))
+ {
+ // either moved forward or attacked
+ return;
+ }
+ }
+
+ if (d[2]!=DI_NODIR)
+ {
+ actor->movedir =d[2];
+
+ if (P_TryWalk(actor))
+ return;
+ }
+
+ // there is no direct path to the player,
+ // so pick another direction.
+ if (olddir!=DI_NODIR)
+ {
+ actor->movedir =olddir;
+
+ if (P_TryWalk(actor))
+ return;
+ }
+
+ // randomly determine direction of search
+ if (P_Random()&1)
+ {
+ for ( tdir=DI_EAST;
+ tdir<=DI_SOUTHEAST;
+ tdir++ )
+ {
+ if (tdir != (int) turnaround)
+ {
+ actor->movedir =tdir;
+
+ if ( P_TryWalk(actor) )
+ return;
+ }
+ }
+ }
+ else
+ {
+ for ( tdir=DI_SOUTHEAST;
+ tdir != (DI_EAST-1);
+ tdir-- )
+ {
+ if (tdir != (int) turnaround)
+ {
+ actor->movedir = tdir;
+
+ if ( P_TryWalk(actor) )
+ return;
+ }
+ }
+ }
+
+ if (turnaround != DI_NODIR)
+ {
+ actor->movedir =turnaround;
+ if ( P_TryWalk(actor) )
+ return;
+ }
+
+ actor->movedir = DI_NODIR; // can not move
+}
+
+//
+// P_NewRandomDir
+//
+// villsa [STRIFE] new function
+//
+// haleyjd: Almost identical to the tail-end of P_NewChaseDir, this function
+// finds a purely random direction for an object to walk. Called from
+// A_RandomWalk.
+//
+// Shockingly similar to the RandomWalk pointer in Eternity :)
+//
+void P_NewRandomDir(mobj_t* actor)
+{
+ int dir = 0;
+ int omovedir = opposite[actor->movedir]; // haleyjd 20110223: nerfed this...
+
+ // randomly determine direction of search
+ if(P_Random() & 1)
+ {
+ // Try all non-reversal directions forward, first
+ for(dir = 0; dir < DI_NODIR; dir++)
+ {
+ if(dir != omovedir)
+ {
+ actor->movedir = dir;
+ if(P_Random() & 1)
+ {
+ if(P_TryWalk(actor))
+ break;
+ }
+ }
+ }
+
+ // haleyjd 20110223: logic missing entirely:
+ // failed all non-reversal directions? try reversing
+ if(dir > DI_SOUTHEAST)
+ {
+ if(omovedir == DI_NODIR)
+ {
+ actor->movedir = DI_NODIR;
+ return;
+ }
+ actor->movedir = omovedir;
+ if(P_TryWalk(actor))
+ return;
+ else
+ {
+ actor->movedir = DI_NODIR;
+ return;
+ }
+ }
+ }
+ else
+ {
+ // Try directions one at a time in backward order
+ dir = DI_SOUTHEAST;
+ while(1)
+ {
+ // haleyjd 09/05/10: missing random code.
+ if(dir != omovedir)
+ {
+ actor->movedir = dir;
+
+ // villsa 09/06/10: un-inlined code
+ if(P_TryWalk(actor))
+ return;
+ }
+
+ // Ran out of non-reversal directions to try? Reverse.
+ if(--dir == -1)
+ {
+ if(omovedir == DI_NODIR)
+ {
+ actor->movedir = DI_NODIR;
+ return;
+ }
+ actor->movedir = omovedir;
+ // villsa 09/06/10: un-inlined code
+ if(P_TryWalk(actor))
+ return;
+ else
+ {
+ actor->movedir = DI_NODIR;
+ return;
+ }
+ } // end if(--dir == -1)
+ } // end while(1)
+ } // end else
+}
+
+// haleyjd 09/05/10: Needed below.
+extern void P_BulletSlope (mobj_t *mo);
+
+//
+// P_LookForPlayers
+//
+// If allaround is false, only look 180 degrees in front.
+// Returns true if a player is targeted.
+//
+// [STRIFE]
+// haleyjd 09/05/10: Modifications to support friendly units.
+//
+boolean
+P_LookForPlayers
+( mobj_t* actor,
+ boolean allaround )
+{
+ int c;
+ int stop;
+ player_t* player;
+ angle_t an;
+ fixed_t dist;
+ mobj_t * master = players[actor->miscdata].mo;
+
+ // haleyjd 09/05/10: handle Allies
+ if(actor->flags & MF_ALLY)
+ {
+ // Deathmatch: support team behavior for Rebels.
+ if(netgame)
+ {
+ // Rebels adopt the allied player's target if it is not of the same
+ // allegiance. Other allies do it unconditionally.
+ if(master && master->target &&
+ (master->target->type != MT_REBEL1 ||
+ master->target->miscdata != actor->miscdata))
+ {
+ actor->target = master->target;
+ }
+ else
+ {
+ // haleyjd 09/06/10: Note that this sets actor->target in Strife!
+ P_BulletSlope(actor);
+
+ // Clear target if nothing is visible, or if the target is a
+ // friendly Rebel or the allied player.
+ if (linetarget == NULL
+ || (actor->target->type == MT_REBEL1
+ && actor->target->miscdata == actor->miscdata)
+ || actor->target == master)
+ {
+ actor->target = NULL;
+ return false;
+ }
+ }
+ }
+ else
+ {
+ // Single-player: Adopt any non-allied player target.
+ if(master && master->target && !(master->target->flags & MF_ALLY))
+ {
+ actor->target = master->target;
+ return true;
+ }
+
+ // haleyjd 09/06/10: Note that this sets actor->target in Strife!
+ P_BulletSlope(actor);
+
+ // Clear target if nothing is visible, or if the target is an ally.
+ if(!linetarget || actor->target->flags & MF_ALLY)
+ {
+ actor->target = NULL;
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ c = 0;
+
+ // NOTE: This behavior has been changed from the Vanilla behavior, where
+ // an infinite loop can occur if players 0-3 all quit the game. Although
+ // technically this is not what Vanilla does, fixing this is highly
+ // desirable, and having the game simply lock up is not acceptable.
+ // stop = (actor->lastlook - 1) & 3;
+ // for (;; actor->lastlook = (actor->lastlook + 1) & 3)
+
+ stop = (actor->lastlook + MAXPLAYERS - 1) % MAXPLAYERS;
+
+ for ( ; ; actor->lastlook = (actor->lastlook + 1) % MAXPLAYERS)
+ {
+ if (!playeringame[actor->lastlook])
+ continue;
+
+ if (c++ == 2
+ || actor->lastlook == stop)
+ {
+ // done looking
+ return false;
+ }
+
+ player = &players[actor->lastlook];
+
+ if (player->health <= 0)
+ continue; // dead
+
+ if (!P_CheckSight (actor, player->mo))
+ continue; // out of sight
+
+ if (!allaround)
+ {
+ an = R_PointToAngle2(actor->x,
+ actor->y,
+ player->mo->x,
+ player->mo->y) - actor->angle;
+
+ if (an > ANG90 && an < ANG270)
+ {
+ dist = P_AproxDistance (player->mo->x - actor->x,
+ player->mo->y - actor->y);
+ // if real close, react anyway
+ if (dist > MELEERANGE)
+ continue; // behind back
+ }
+ }
+
+ actor->target = player->mo;
+ return true;
+ }
+
+ return false;
+}
+
+// haleyjd 09/05/10: [STRIFE] Removed A_KeenDie
+
+//
+// ACTION ROUTINES
+//
+
+//
+// A_Look
+// Stay in state until a player is sighted.
+//
+// [STRIFE]
+// haleyjd 09/05/10: Adjusted for allies, Inquisitors, etc.
+//
+void A_Look (mobj_t* actor)
+{
+ mobj_t* targ;
+
+ actor->threshold = 0; // any shot will wake up
+ targ = actor->subsector->sector->soundtarget;
+
+ if (targ
+ && (targ->flags & MF_SHOOTABLE) )
+ {
+ // [STRIFE] Allies wander when they call this.
+ if(actor->flags & MF_ALLY)
+ A_RandomWalk(actor);
+ else
+ {
+ actor->target = targ;
+
+ if ( actor->flags & MF_AMBUSH )
+ {
+ if (P_CheckSight (actor, actor->target))
+ goto seeyou;
+ }
+ else
+ goto seeyou;
+ }
+ }
+
+ // haleyjd 09/05/10: This is bizarre, as Rogue keeps using the GIVEQUEST flag
+ // as a parameter to control allaround look behavior. Did they just run out of
+ // flags, or what?
+ // STRIFE-TODO: Needs serious verification.
+ if (!P_LookForPlayers (actor, actor->flags & MF_GIVEQUEST) )
+ return;
+
+ // go into chase state
+seeyou:
+ if (actor->info->seesound)
+ {
+ int sound = actor->info->seesound;
+ mobj_t * emitter = actor;
+
+ // [STRIFE] Removed DOOM random sounds.
+
+ // [STRIFE] Only Inquisitors roar loudly here.
+ if (actor->type == MT_INQUISITOR)
+ emitter = NULL;
+
+ S_StartSound (emitter, sound);
+ }
+
+ // [STRIFE] Set threshold (kinda odd as it's still set to 0 above...)
+ actor->threshold = 20;
+
+ P_SetMobjState (actor, actor->info->seestate);
+}
+
+//
+// A_RandomWalk
+//
+// [STRIFE] New function.
+// haleyjd 09/05/10: Action routine used to meander about.
+//
+void A_RandomWalk(mobj_t* actor)
+{
+ // Standing actors do not wander.
+ if(actor->flags & MF_STAND)
+ return;
+
+ if(actor->reactiontime)
+ actor->reactiontime--; // count down reaction time
+ else
+ {
+ // turn to a new angle
+ if(actor->movedir < DI_NODIR)
+ {
+ int delta;
+
+ actor->angle &= (7 << 29);
+ delta = actor->angle - (actor->movedir << 29);
+
+ if(delta < 0)
+ actor->angle += ANG90/2;
+ else if(delta > 0)
+ actor->angle -= ANG90/2;
+ }
+
+ // try moving
+ if(--actor->movecount < 0 || !P_Move(actor))
+ {
+ P_NewRandomDir(actor);
+ actor->movecount += 5;
+ }
+ }
+}
+
+//
+// A_FriendLook
+//
+// [STRIFE] New function
+// haleyjd 09/05/10: Action function used mostly by mundane characters such as
+// peasants.
+//
+void A_FriendLook(mobj_t* actor)
+{
+ mobj_t *soundtarget = actor->subsector->sector->soundtarget;
+
+ actor->threshold = 0;
+
+ if(soundtarget && soundtarget->flags & MF_SHOOTABLE)
+ {
+ // Handle allies, except on maps 3 and 34 (Front Base/Movement Base)
+ if((actor->flags & MF_ALLY) == (soundtarget->flags & MF_ALLY) &&
+ gamemap != 3 && gamemap != 34)
+ {
+ // STRIFE-TODO: Needs serious verification.
+ if(P_LookForPlayers(actor, actor->flags & MF_GIVEQUEST))
+ {
+ P_SetMobjState(actor, actor->info->seestate);
+ actor->flags |= MF_NODIALOG;
+ return;
+ }
+ }
+ else
+ {
+ actor->target = soundtarget;
+
+ if(!(actor->flags & MF_AMBUSH) || P_CheckSight(actor, actor->target))
+ {
+ actor->threshold = 10;
+ P_SetMobjState(actor, actor->info->seestate);
+ return;
+ }
+ }
+ }
+
+ // do some idle animation
+ if(P_Random() < 30)
+ {
+ int t = P_Random();
+ P_SetMobjState(actor, (t & 1) + actor->info->spawnstate + 1);
+ }
+
+ // wander around a bit
+ if(!(actor->flags & MF_STAND) && P_Random() < 40)
+ P_SetMobjState(actor, actor->info->spawnstate + 3);
+}
+
+//
+// A_Listen
+//
+// [STRIFE] New function
+// haleyjd 09/05/10: Action routine used to strictly listen for a target.
+//
+void A_Listen(mobj_t* actor)
+{
+ mobj_t *soundtarget;
+
+ actor->threshold = 0;
+
+ soundtarget = actor->subsector->sector->soundtarget;
+
+ if(soundtarget && (soundtarget->flags & MF_SHOOTABLE))
+ {
+ if((actor->flags & MF_ALLY) != (soundtarget->flags & MF_ALLY))
+ {
+ actor->target = soundtarget;
+
+ if(!(actor->flags & MF_AMBUSH) || P_CheckSight(actor, actor->target))
+ {
+ if(actor->info->seesound)
+ S_StartSound(actor, actor->info->seesound);
+
+ actor->threshold = 10;
+
+ P_SetMobjState(actor, actor->info->seestate);
+ }
+ }
+ }
+}
+
+
+//
+// A_Chase
+// Actor has a melee attack,
+// so it tries to close as fast as possible
+//
+// haleyjd 09/05/10: [STRIFE] Various minor changes
+//
+void A_Chase (mobj_t* actor)
+{
+ int delta;
+
+ if (actor->reactiontime)
+ actor->reactiontime--;
+
+ // modify target threshold
+ if (actor->threshold)
+ {
+ // haleyjd 20110204 [STRIFE]: No health <= 0 check here!
+ if (actor->target)
+ actor->threshold--;
+ else
+ actor->threshold = 0;
+ }
+
+ // turn towards movement direction if not there yet
+ if (actor->movedir < 8)
+ {
+ actor->angle &= (7<<29);
+ delta = actor->angle - (actor->movedir << 29);
+
+ if (delta > 0)
+ actor->angle -= ANG90/2;
+ else if (delta < 0)
+ actor->angle += ANG90/2;
+ }
+
+ if (!actor->target
+ || !(actor->target->flags&MF_SHOOTABLE))
+ {
+ // look for a new target
+ if (P_LookForPlayers(actor, true))
+ return; // got a new target
+
+ P_SetMobjState (actor, actor->info->spawnstate);
+ return;
+ }
+
+ // do not attack twice in a row
+ if (actor->flags & MF_JUSTATTACKED)
+ {
+ actor->flags &= ~MF_JUSTATTACKED;
+ // [STRIFE] Checks only against fastparm, not gameskill == 5
+ if (!fastparm)
+ P_NewChaseDir (actor);
+ return;
+ }
+
+ // check for melee attack
+ if (actor->info->meleestate
+ && P_CheckMeleeRange (actor))
+ {
+ if (actor->info->attacksound)
+ S_StartSound (actor, actor->info->attacksound);
+
+ P_SetMobjState (actor, actor->info->meleestate);
+ return;
+ }
+
+ // check for missile attack
+ if (actor->info->missilestate)
+ {
+ // [STRIFE] Checks only fastparm.
+ if (!fastparm && actor->movecount)
+ {
+ goto nomissile;
+ }
+
+ if (!P_CheckMissileRange (actor))
+ goto nomissile;
+
+ P_SetMobjState (actor, actor->info->missilestate);
+
+ // [STRIFE] Add NODIALOG flag to disable dialog
+ actor->flags |= (MF_NODIALOG|MF_JUSTATTACKED);
+ return;
+ }
+
+ // ?
+nomissile:
+ // possibly choose another target
+ if (netgame
+ && !actor->threshold
+ && !P_CheckSight (actor, actor->target) )
+ {
+ if (P_LookForPlayers(actor, true))
+ return; // got a new target
+ }
+
+ // chase towards player
+ if (--actor->movecount<0
+ || !P_Move (actor))
+ {
+ P_NewChaseDir (actor);
+ }
+
+ // [STRIFE] Changes to active sound behavior:
+ // * Significantly more frequent
+ // * Acolytes have randomized wandering sounds
+
+ // make active sound
+ if (actor->info->activesound && P_Random () < 38)
+ {
+ if(actor->info->activesound >= sfx_agrac1 &&
+ actor->info->activesound <= sfx_agrac4)
+ {
+ S_StartSound(actor, sfx_agrac1 + P_Random() % 4);
+ }
+ else
+ S_StartSound(actor, actor->info->activesound);
+ }
+}
+
+
+//
+// A_FaceTarget
+//
+// [STRIFE]
+// haleyjd 09/05/10: Handling for visibility-modifying flags.
+//
+void A_FaceTarget (mobj_t* actor)
+{
+ if (!actor->target)
+ return;
+
+ actor->flags &= ~MF_AMBUSH;
+
+ actor->angle = R_PointToAngle2 (actor->x,
+ actor->y,
+ actor->target->x,
+ actor->target->y);
+
+ if(actor->target->flags & MF_SHADOW)
+ {
+ // [STRIFE] increased SHADOW inaccuracy by a power of 2
+ int t = P_Random();
+ actor->angle += (t - P_Random()) << 22;
+ }
+ else if(actor->target->flags & MF_MVIS)
+ {
+ // [STRIFE] MVIS gives even worse aiming!
+ int t = P_Random();
+ actor->angle += (t - P_Random()) << 23;
+ }
+}
+
+//
+// A_PeasantPunch
+//
+// [STRIFE] New function
+// haleyjd 09/05/10: Attack used by Peasants as a one-time retaliation
+// when the player or a monster injures them. Weak doesn't begin to
+// describe it :P
+//
+void A_PeasantPunch(mobj_t* actor)
+{
+ if(!actor->target)
+ return;
+
+ A_FaceTarget(actor);
+ if(P_CheckMeleeRange(actor))
+ P_DamageMobj(actor->target, actor, actor, 2 * (P_Random() % 5) + 2);
+}
+
+//
+// A_ReaverAttack
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action routine used by Reavers to fire bullets.
+// Also apparently used by Inquistors, though they don't seem to use
+// it too often, as they're content to blow your face off with their
+// HE grenades instead.
+//
+void A_ReaverAttack(mobj_t* actor)
+{
+ int i = 0;
+ fixed_t slope;
+
+ if(!actor->target)
+ return;
+
+ S_StartSound(actor, sfx_reavat);
+ A_FaceTarget(actor);
+
+ slope = P_AimLineAttack(actor, actor->angle, 2048*FRACUNIT);
+
+ do
+ {
+ int t = P_Random();
+ angle_t shootangle = actor->angle + ((t - P_Random()) << 20);
+ int damage = (P_Random() & 7) + 1;
+
+ P_LineAttack(actor, shootangle, 2048*FRACUNIT, slope, damage);
+ ++i;
+ }
+ while(i < 3);
+}
+
+//
+// A_BulletAttack
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function for generic bullet attacks. Used by
+// a lot of different characters, including Acolytes, Rebels, and Macil.
+//
+void A_BulletAttack(mobj_t* actor)
+{
+ int t, damage;
+ fixed_t slope;
+ angle_t shootangle;
+
+ if(!actor->target)
+ return;
+
+ S_StartSound(actor, sfx_rifle);
+ A_FaceTarget(actor);
+
+ slope = P_AimLineAttack(actor, actor->angle, 2048*FRACUNIT);
+ t = P_Random();
+ shootangle = ((t - P_Random()) << 19) + actor->angle;
+ damage = 3 * (P_Random() % 5 + 1);
+
+ P_LineAttack(actor, shootangle, 2048*FRACUNIT, slope, damage);
+}
+
+//
+// A_CheckTargetVisible
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action routine which sets a thing back to its
+// seestate at random, or if it cannot see its target, or its target
+// is dead. Used by diverse actors.
+//
+void A_CheckTargetVisible(mobj_t* actor)
+{
+ A_FaceTarget(actor);
+
+ if(P_Random() >= 30)
+ {
+ mobj_t *target = actor->target;
+
+ if(!target || target->health <= 0 || !P_CheckSight(actor, target) ||
+ P_Random() < 40)
+ {
+ P_SetMobjState(actor, actor->info->seestate);
+ }
+ }
+}
+
+//
+// A_SentinelAttack
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function implementing the Sentinel's laser attack
+// villsa 09/06/10 implemented
+//
+void A_SentinelAttack(mobj_t* actor)
+{
+ mobj_t* mo;
+ mobj_t* mo2;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ angle_t an;
+ int i;
+
+ mo = P_SpawnFacingMissile(actor, actor->target, MT_L_LASER);
+ an = actor->angle >> ANGLETOFINESHIFT;
+
+ if(mo->momy | mo->momx) // villsa - fixed typo (yes, they actually used '|' instead of'||')
+ {
+ for(i = 8; i > 1; i--)
+ {
+ x = mo->x + FixedMul(mobjinfo[MT_L_LASER].radius * i, finecosine[an]);
+ y = mo->y + FixedMul(mobjinfo[MT_L_LASER].radius * i, finesine[an]);
+ z = mo->z + i * (mo->momz >> 2);
+ mo2 = P_SpawnMobj(x, y, z, MT_R_LASER);
+ mo2->target = actor;
+ mo2->momx = mo->momx;
+ mo2->momy = mo->momy;
+ mo2->momz = mo->momz;
+ P_CheckMissileSpawn(mo2);
+ }
+ }
+
+ mo->z += mo->momz >> 2;
+}
+
+//
+// A_StalkerThink
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function to drive Stalker logic.
+//
+void A_StalkerThink(mobj_t* actor)
+{
+ statenum_t statenum;
+
+ if(actor->flags & MF_NOGRAVITY)
+ {
+ if(actor->ceilingz - actor->info->height <= actor->z)
+ return;
+ statenum = S_SPID_11; // 1020
+ }
+ else
+ statenum = S_SPID_18; // 1027
+
+ P_SetMobjState(actor, statenum);
+}
+
+//
+// A_StalkerSetLook
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function to marshall transitions to the
+// Stalker's spawnstate.
+//
+void A_StalkerSetLook(mobj_t* actor)
+{
+ statenum_t statenum;
+
+ if(!actor) // weird; totally unnecessary.
+ return;
+
+ if(actor->flags & MF_NOGRAVITY)
+ {
+ if(actor->state->nextstate == S_SPID_01) // 1010
+ return;
+ statenum = S_SPID_01; // 1010
+ }
+ else
+ {
+ if(actor->state->nextstate == S_SPID_02) // 1011
+ return;
+ statenum = S_SPID_02; // 1011
+ }
+
+ P_SetMobjState(actor, statenum);
+}
+
+//
+// A_StalkerDrop
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Dead simple: removes NOGRAVITY status.
+//
+void A_StalkerDrop(mobj_t* actor)
+{
+ actor->flags &= ~MF_NOGRAVITY;
+}
+
+//
+// A_StalkerScratch
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function for Stalker's attack.
+//
+void A_StalkerScratch(mobj_t* actor)
+{
+ if(actor->flags & MF_NOGRAVITY)
+ {
+ // Drop him down before he can attack
+ P_SetMobjState(actor, S_SPID_11); // 1020
+ return;
+ }
+
+ if(!actor->target)
+ return;
+
+ A_FaceTarget(actor);
+ if(P_CheckMeleeRange(actor))
+ P_DamageMobj(actor->target, actor, actor, 2 * (P_Random() % 8) + 2);
+}
+
+//
+// A_FloatWeave
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function which is responsible for floating
+// actors' constant upward and downward movement. Probably a really bad
+// idea in retrospect given how dodgy the 3D clipping implementation is.
+//
+void A_FloatWeave(mobj_t* actor)
+{
+ fixed_t height;
+ fixed_t z;
+
+ if(actor->threshold)
+ return;
+
+ if(actor->flags & MF_INFLOAT)
+ return;
+
+ height = actor->info->height; // v2
+ z = actor->floorz + 96*FRACUNIT; // v1
+
+ if ( z > actor->ceilingz - height - 16*FRACUNIT )
+ z = actor->ceilingz - height - 16*FRACUNIT;
+
+ if ( z >= actor->z )
+ actor->momz += FRACUNIT;
+ else
+ actor->momz -= FRACUNIT;
+
+ if ( z == actor->z )
+ actor->threshold = 4;
+ else
+ actor->threshold = 8;
+}
+
+//
+// A_RobotMelee
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function for Reaver and Templar melee attacks.
+//
+void A_RobotMelee(mobj_t* actor)
+{
+ if(!actor->target)
+ return;
+
+ A_FaceTarget(actor);
+ if(P_CheckMeleeRange(actor))
+ {
+ S_StartSound(actor, sfx_revbld);
+ P_DamageMobj(actor->target, actor, actor, 3 * (P_Random() % 8 + 1));
+ }
+}
+
+//
+// A_TemplarMauler
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Exactly what it sounds like. Kicks your ass.
+//
+void A_TemplarMauler(mobj_t* actor)
+{
+ int i, t;
+ int angle;
+ int bangle;
+ int damage;
+ int slope;
+
+ if(!actor->target)
+ return;
+
+ S_StartSound(actor, sfx_pgrdat);
+ A_FaceTarget(actor);
+ bangle = actor->angle;
+ slope = P_AimLineAttack(actor, bangle, 2048*FRACUNIT);
+
+ for(i = 0; i < 10; i++)
+ {
+ // haleyjd 09/06/10: Very carefully preserved order of P_Random calls
+ damage = (P_Random() & 4) * 2;
+ t = P_Random();
+ angle = bangle + ((t - P_Random()) << 19);
+ t = P_Random();
+ slope = ((t - P_Random()) << 5) + slope;
+ P_LineAttack(actor, angle, 2112*FRACUNIT, slope, damage);
+ }
+}
+
+//
+// A_CrusaderAttack
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Action function for the Crusader's Flamethrower.
+// Very similar to the player's flamethrower, seeing how it was ripped
+// off a Crusader by the Rat People ;)
+//
+void A_CrusaderAttack(mobj_t* actor)
+{
+ if(!actor->target)
+ return;
+
+ actor->z += (8*FRACUNIT);
+
+ if(P_CheckRobotRange(actor))
+ {
+ A_FaceTarget(actor);
+ actor->angle -= (ANG90 / 8);
+ P_SpawnFacingMissile(actor, actor->target, MT_C_FLAME);
+ }
+ else if(P_CheckMissileRange(actor))
+ {
+ A_FaceTarget(actor);
+ actor->z += (16*FRACUNIT);
+ P_SpawnFacingMissile(actor, actor->target, MT_C_MISSILE);
+
+ actor->angle -= (ANG45 / 32);
+ actor->z -= (16*FRACUNIT);
+ P_SpawnFacingMissile(actor, actor->target, MT_C_MISSILE);
+
+ actor->angle += (ANG45 / 16);
+ P_SpawnFacingMissile(actor, actor->target, MT_C_MISSILE);
+
+ P_SetMobjState(actor, actor->info->seestate);
+ actor->reactiontime += 15;
+ }
+ else
+ P_SetMobjState(actor, actor->info->seestate);
+
+ actor->z -= (8*FRACUNIT);
+}
+
+//
+// A_CrusaderLeft
+//
+// villsa [STRIFE] new codepointer
+//
+void A_CrusaderLeft(mobj_t* actor)
+{
+ mobj_t* mo;
+
+ actor->angle += (ANG90 / 16);
+ mo = P_SpawnFacingMissile(actor, actor->target, MT_C_FLAME);
+ mo->momz = FRACUNIT;
+ mo->z += (16*FRACUNIT);
+
+}
+
+//
+// A_CrusaderRight
+//
+// villsa [STRIFE] new codepointer
+//
+void A_CrusaderRight(mobj_t* actor)
+{
+ mobj_t* mo;
+
+ actor->angle -= (ANG90 / 16);
+ mo = P_SpawnFacingMissile(actor, actor->target, MT_C_FLAME);
+ mo->momz = FRACUNIT;
+ mo->z += (16*FRACUNIT);
+}
+
+//
+// A_CheckTargetVisible2
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Mostly the same as CheckTargetVisible, except without
+// the randomness.
+//
+void A_CheckTargetVisible2(mobj_t* actor)
+{
+ if(!actor->target || actor->target->health <= 0 ||
+ !P_CheckSight(actor, actor->target))
+ {
+ P_SetMobjState(actor, actor->info->seestate);
+ }
+}
+
+//
+// A_InqFlyCheck
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function to check if an Inquisitor wishes
+// to take to flight.
+//
+void A_InqFlyCheck(mobj_t* actor)
+{
+ if(!actor->target)
+ return;
+
+ A_FaceTarget(actor);
+
+ // if not in "robot" range, shoot grenades.
+ if(!P_CheckRobotRange(actor))
+ P_SetMobjState(actor, S_ROB3_14); // 1061
+
+ if(actor->z != actor->target->z)
+ {
+ // Take off all zig!
+ if(actor->z + actor->height + 54*FRACUNIT < actor->ceilingz)
+ P_SetMobjState(actor, S_ROB3_17); // 1064
+ }
+}
+
+//
+// A_InqGrenade
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Inquisitor grenade attack action routine.
+//
+void A_InqGrenade(mobj_t* actor)
+{
+ mobj_t* mo;
+
+ if(!actor->target)
+ return;
+
+ A_FaceTarget(actor);
+
+ actor->z += MAXRADIUS;
+
+ // grenade 1
+ actor->angle -= (ANG45 / 32);
+ mo = P_SpawnFacingMissile(actor, actor->target, MT_INQGRENADE);
+ mo->momz += (9*FRACUNIT);
+
+ // grenade 2
+ actor->angle += (ANG45 / 16);
+ mo = P_SpawnFacingMissile(actor, actor->target, MT_INQGRENADE);
+ mo->momz += (16*FRACUNIT);
+
+ actor->z -= MAXRADIUS;
+}
+
+//
+// A_InqTakeOff
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Makes an Inquisitor start flying.
+//
+void A_InqTakeOff(mobj_t* actor)
+{
+ angle_t an;
+ fixed_t speed = actor->info->speed * (2 * FRACUNIT / 3);
+ fixed_t dist;
+
+ if(!actor->target)
+ return;
+
+ S_StartSound(actor, sfx_inqjmp);
+
+ actor->z += 64 * FRACUNIT;
+
+ A_FaceTarget(actor);
+
+ an = actor->angle >> ANGLETOFINESHIFT;
+
+ actor->momx = FixedMul(finecosine[an], speed);
+ actor->momy = FixedMul(finesine[an], speed);
+
+ dist = P_AproxDistance(actor->target->x - actor->x,
+ actor->target->y - actor->y);
+
+ dist /= speed;
+ if(dist < 1)
+ dist = 1;
+
+ actor->momz = (actor->target->z - actor->z) / dist;
+ actor->reactiontime = 60;
+ actor->flags |= MF_NOGRAVITY;
+}
+
+//
+// A_InqFly
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Handles an Inquisitor in flight.
+//
+void A_InqFly(mobj_t* actor)
+{
+ if(!(leveltime & 7))
+ S_StartSound(actor, sfx_inqjmp);
+
+ if(--actor->reactiontime < 0 || !actor->momx || !actor->momy ||
+ actor->z <= actor->floorz)
+ {
+ // Come in for a landing.
+ P_SetMobjState(actor, actor->info->seestate);
+ actor->reactiontime = 0;
+ actor->flags &= ~MF_NOGRAVITY;
+ }
+}
+
+//
+// A_FireSigilWeapon
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function for the Entity's attack.
+//
+void A_FireSigilWeapon(mobj_t* actor)
+{
+ int choice = P_Random() % 5;
+
+ // STRIFE-TODO: Needs verification. This switch is just weird.
+ switch(choice)
+ {
+ case 0:
+ A_ProgrammerAttack(actor);
+ break;
+ // ain't not seen no case 1, bub...
+ case 2:
+ A_FireSigilEOffshoot(actor);
+ break;
+ case 3:
+ A_SpectreCAttack(actor);
+ break;
+ case 4:
+ A_SpectreDAttack(actor);
+ break;
+ case 5: // BUG: never used? wtf were they thinking?
+ A_SpectreEAttack(actor);
+ break;
+ default:
+ break;
+ }
+}
+
+//
+// A_ProgrammerAttack
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function for the Programmer's main
+// attack; equivalent to the player's first Sigil.
+//
+void A_ProgrammerAttack(mobj_t* actor)
+{
+ mobj_t *mo;
+
+ if(!actor->target)
+ return;
+
+ mo = P_SpawnMobj(actor->target->x, actor->target->y, ONFLOORZ,
+ MT_SIGIL_A_GROUND);
+ mo->threshold = 25;
+ mo->target = actor;
+ mo->health = -2;
+ mo->tracer = actor->target;
+}
+
+//
+// A_Sigil_A_Action
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Called by MT_SIGIL_A_GROUND to zot anyone nearby with
+// corny looking lightning bolts.
+//
+void A_Sigil_A_Action(mobj_t* actor)
+{
+ int t, x, y, type;
+ mobj_t *mo;
+
+ if(actor->threshold)
+ actor->threshold--;
+
+ t = P_Random();
+ actor->momx += ((t & 3) - (P_Random() & 3)) << FRACBITS;
+ t = P_Random();
+ actor->momy += ((t & 3) - (P_Random() & 3)) << FRACBITS;
+
+ t = P_Random();
+ x = 50*FRACUNIT * ((t & 3) - (P_Random() & 3)) + actor->x;
+ t = P_Random();
+ y = 50*FRACUNIT * ((t & 3) - (P_Random() & 3)) + actor->y;
+
+ if(actor->threshold <= 25)
+ type = MT_SIGIL_A_ZAP_LEFT;
+ else
+ type = MT_SIGIL_A_ZAP_RIGHT;
+
+ mo = P_SpawnMobj(x, y, ONCEILINGZ, type);
+ mo->momz = -18 * FRACUNIT;
+ mo->target = actor->target;
+ mo->health = actor->health;
+
+ mo = P_SpawnMobj(actor->x, actor->y, ONCEILINGZ, MT_SIGIL_A_ZAP_RIGHT);
+ mo->momz = -18 * FRACUNIT;
+ mo->target = actor->target;
+ mo->health = actor->health;
+}
+
+//
+// A_SpectreEAttack
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function for the Loremaster's Spectre.
+// Equivalent to the player's final Sigil attack.
+//
+void A_SpectreEAttack(mobj_t* actor)
+{
+ mobj_t *mo;
+
+ if(!actor->target)
+ return;
+
+ mo = P_SpawnMissile(actor, actor->target, MT_SIGIL_SE_SHOT);
+ mo->health = -2;
+}
+
+//
+// A_SpectreCAttack
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Action routine for the Oracle's Spectre. Equivalent to the player's
+// third Sigil attack.
+//
+void A_SpectreCAttack(mobj_t* actor)
+{
+ mobj_t* mo;
+ int i;
+
+ if(!actor->target)
+ return;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + (32*FRACUNIT), MT_SIGIL_A_ZAP_RIGHT);
+ mo->momz = -(18*FRACUNIT);
+ mo->target = actor;
+ mo->health = -2;
+ mo->tracer = actor->target;
+
+ actor->angle -= ANG90;
+ for(i = 0; i < 20; i++)
+ {
+ actor->angle += (ANG90 / 10);
+ mo = P_SpawnMortar(actor, MT_SIGIL_C_SHOT);
+ mo->health = -2;
+ mo->z = actor->z + (32*FRACUNIT);
+ }
+ actor->angle -= ANG90;
+}
+
+//
+// A_AlertSpectreC
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function called by the Oracle when it is
+// killed. Finds an MT_SPECTRE_C anywhere on the map and awakens it.
+//
+void A_AlertSpectreC(mobj_t* actor)
+{
+ thinker_t *th;
+
+ for(th = thinkercap.next; th != &thinkercap; th = th->next)
+ {
+ if(th->function.acp1 == (actionf_p1)P_MobjThinker)
+ {
+ mobj_t *mo = (mobj_t *)th;
+
+ if(mo->type == MT_SPECTRE_C)
+ {
+ P_SetMobjState(mo, mo->info->seestate);
+ mo->target = actor->target;
+ return;
+ }
+ }
+ }
+}
+
+//
+// A_Sigil_E_Action
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Action routine for Sigil "E" shots. Spawns the room-filling
+// lightning bolts that seem to often do almost nothing.
+//
+void A_Sigil_E_Action(mobj_t* actor)
+{
+ actor->angle += ANG90;
+ P_SpawnMortar(actor, MT_SIGIL_E_OFFSHOOT);
+
+ actor->angle -= ANG180;
+ P_SpawnMortar(actor, MT_SIGIL_E_OFFSHOOT);
+
+ actor->angle += ANG90;
+ P_SpawnMortar(actor, MT_SIGIL_E_OFFSHOOT);
+
+}
+
+//
+// A_SigilTrail
+//
+// villsa [STRIFE] new codepointer
+//
+void A_SigilTrail(mobj_t* actor)
+{
+ mobj_t* mo;
+
+ mo = P_SpawnMobj(actor->x - actor->momx,
+ actor->y - actor->momy,
+ actor->z, MT_SIGIL_TRAIL);
+
+ mo->angle = actor->angle;
+ mo->health = actor->health;
+
+}
+
+//
+// A_SpectreDAttack
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function for Macil's Spectre.
+// Equivalent of the player's fourth Sigil attack.
+//
+void A_SpectreDAttack(mobj_t* actor)
+{
+ mobj_t *mo;
+
+ if(!actor->target)
+ return;
+
+ mo = P_SpawnMissile(actor, actor->target, MT_SIGIL_SD_SHOT);
+ mo->health = -2;
+ mo->tracer = actor->target;
+}
+
+//
+// A_FireSigilEOffshoot
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function to fire part of a Sigil E
+// attack. Used at least by the Entity.
+//
+void A_FireSigilEOffshoot(mobj_t* actor)
+{
+ mobj_t *mo;
+
+ if(!actor->target)
+ return;
+
+ mo = P_SpawnMissile(actor, actor->target, MT_SIGIL_E_OFFSHOOT);
+ mo->health = -2;
+}
+
+//
+// A_ShadowOff
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Disables SHADOW and MVIS flags.
+//
+void A_ShadowOff(mobj_t* actor)
+{
+ actor->flags &= ~(MF_SHADOW|MF_MVIS);
+}
+
+//
+// A_ModifyVisibility
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Turns on SHADOW, and turns off MVIS.
+//
+void A_ModifyVisibility(mobj_t* actor)
+{
+ actor->flags |= MF_SHADOW;
+ actor->flags &= ~MF_MVIS;
+}
+
+//
+// A_ShadowOn
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Turns on SHADOW and MVIS.
+//
+void A_ShadowOn(mobj_t* actor)
+{
+ actor->flags |= (MF_SHADOW|MF_MVIS);
+}
+
+//
+// A_SetTLOptions
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Sets SHADOW and/or MVIS based on the thing's spawnpoint options.
+//
+void A_SetTLOptions(mobj_t* actor)
+{
+ if(actor->spawnpoint.options & MTF_TRANSLUCENT)
+ actor->flags |= MF_SHADOW;
+ if(actor->spawnpoint.options & MTF_MVIS)
+ actor->flags |= MF_MVIS;
+}
+
+//
+// A_BossMeleeAtk
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Gratuitous melee attack used by multiple boss characters,
+// just for the sake of having one. It's not like anybody in their right
+// mind would get close to any of the maniacs that use this ;)
+//
+void A_BossMeleeAtk(mobj_t* actor)
+{
+ if(!actor->target)
+ return;
+
+ P_DamageMobj(actor->target, actor, actor, 10 * (P_Random() & 9));
+}
+
+//
+// A_BishopAttack
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Bishop's homing missile attack.
+//
+void A_BishopAttack(mobj_t* actor)
+{
+ mobj_t* mo;
+
+ if(!actor->target)
+ return;
+
+ actor->z += MAXRADIUS;
+
+ mo = P_SpawnMissile(actor, actor->target, MT_SEEKMISSILE);
+ mo->tracer = actor->target;
+
+ actor->z -= MAXRADIUS;
+}
+
+//
+// A_FireHookShot
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Action function for the Loremaster's hookshot attack.
+//
+void A_FireHookShot(mobj_t* actor)
+{
+ if(!actor->target)
+ return;
+
+ P_SpawnMissile(actor, actor->target, MT_HOOKSHOT);
+}
+
+//
+// A_FireChainShot
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Action function for the hookshot projectile. Spawns echoes
+// to create a chain-like appearance.
+//
+void A_FireChainShot(mobj_t* actor)
+{
+ S_StartSound(actor, sfx_tend);
+
+ P_SpawnMobj(actor->x, actor->y, actor->z, MT_CHAINSHOT); // haleyjd: fixed type
+
+ P_SpawnMobj(actor->x - (actor->momx >> 1),
+ actor->y - (actor->momy >> 1),
+ actor->z, MT_CHAINSHOT);
+
+ P_SpawnMobj(actor->x - actor->momx,
+ actor->y - actor->momy,
+ actor->z, MT_CHAINSHOT);
+}
+
+//
+// A_MissileSmoke
+//
+// villsa [STRIFE] new codepointer
+//
+void A_MissileSmoke(mobj_t* actor)
+{
+ mobj_t* mo;
+
+ S_StartSound(actor, sfx_rflite);
+ P_SpawnPuff(actor->x, actor->y, actor->z);
+ mo = P_SpawnMobj(actor->x - actor->momx,
+ actor->y - actor->momy,
+ actor->z, MT_MISSILESMOKE);
+
+ mo->momz = FRACUNIT;
+}
+
+//
+// A_SpawnSparkPuff
+//
+// villsa [STRIFE] new codepointer
+//
+void A_SpawnSparkPuff(mobj_t* actor)
+{
+ int r;
+ mobj_t* mo;
+ fixed_t x;
+ fixed_t y;
+
+ r = P_Random();
+ x = (10*FRACUNIT) * ((r & 3) - (P_Random() & 3)) + actor->x;
+ r = P_Random();
+ y = (10*FRACUNIT) * ((r & 3) - (P_Random() & 3)) + actor->y;
+
+ mo = P_SpawnMobj(x, y, actor->z, MT_SPARKPUFF);
+ P_SetMobjState(mo, S_BNG4_01); // 199
+ mo->momz = FRACUNIT;
+}
+
+
+// haleyjd 09/05/10: [STRIFE] Removed:
+// A_PosAttack, A_SPosAttack, A_CPosAttack, A_CPosRefire, A_SpidRefire,
+// A_BspiAttack, A_TroopAttack, A_SargAttack, A_HeadAttack, A_CyberAttack,
+// A_BruisAttack, A_SkelMissile
+
+
+int TRACEANGLE = 0xE000000; // villsa [STRIFE] changed from 0xC000000 to 0xE000000
+
+//
+// A_Tracer
+//
+void A_Tracer (mobj_t* actor)
+{
+ angle_t exact;
+ fixed_t dist;
+ fixed_t slope;
+ mobj_t* dest;
+ //mobj_t* th;
+
+ // villsa [STRIFE] removed all randomization and puff code
+
+ // adjust direction
+ dest = actor->tracer;
+
+ if(!dest || dest->health <= 0)
+ return;
+
+ // change angle
+ exact = R_PointToAngle2(actor->x, actor->y, dest->x, dest->y);
+
+ if(exact != actor->angle)
+ {
+ // villsa [STRIFE] slightly different algorithm
+ if(exact - actor->angle <= 0x80000000)
+ {
+ actor->angle += TRACEANGLE;
+ if(exact - actor->angle > 0x80000000)
+ actor->angle = exact;
+ }
+ else
+ {
+ actor->angle -= TRACEANGLE;
+ if (exact - actor->angle < 0x80000000)
+ actor->angle = exact;
+ }
+ }
+
+ exact = actor->angle>>ANGLETOFINESHIFT;
+ actor->momx = FixedMul (actor->info->speed, finecosine[exact]);
+ actor->momy = FixedMul (actor->info->speed, finesine[exact]);
+
+ // change slope
+ dist = P_AproxDistance (dest->x - actor->x,
+ dest->y - actor->y);
+
+ dist = dist / actor->info->speed;
+
+ if (dist < 1)
+ dist = 1;
+ slope = (dest->z+40*FRACUNIT - actor->z) / dist;
+
+ if (slope < actor->momz)
+ actor->momz -= FRACUNIT/8;
+ else
+ actor->momz += FRACUNIT/8;
+}
+
+//
+// A_ProgrammerMelee
+//
+// villsa [STRIFE] new codepointer
+// 09/08/10: Melee attack for the Programmer.
+// haleyjd - fixed damage formula
+//
+void A_ProgrammerMelee(mobj_t* actor)
+{
+ if(!actor->target)
+ return;
+
+ A_FaceTarget(actor);
+ if(P_CheckMeleeRange(actor))
+ {
+ int damage = 8 * (P_Random() % 10 + 1);
+
+ S_StartSound(actor, sfx_mtalht);
+ P_DamageMobj(actor->target, actor, actor, damage);
+ }
+
+}
+
+// haleyjd 09/05/10: [STRIFE] Removed:
+// A_SkelWhoosh, A_SkelFist, PIT_VileCheck, A_VileChase, A_VileStart,
+// A_StartFire, A_FireCrackle, A_Fire, A_VileTarget, A_VileAttack
+// A_FatRaise, A_FatAttack1, A_FatAttack2, A_FatAttack3, A_SkullAttack,
+// A_PainShootSkull, A_PainAttack, A_PainDie
+
+//
+// A_Scream
+//
+// villsa [STRIFE]
+// * Has no random death sounds, so play deathsound directly
+// * Full-volume roars for the Entity and Inquisitor.
+//
+void A_Scream(mobj_t* actor)
+{
+ if(!actor->info->deathsound)
+ return;
+
+ // Check for bosses.
+ if(actor->type == MT_ENTITY || actor->type == MT_INQUISITOR)
+ S_StartSound(NULL, actor->info->deathsound); // full volume
+ else
+ S_StartSound(actor, actor->info->deathsound);
+}
+
+//
+// A_XScream
+//
+// villsa [STRIFE]
+// * Robots will play deathsound while non-robots play the slop sfx
+//
+void A_XScream(mobj_t* actor)
+{
+ int sound;
+
+ if(actor->flags & MF_NOBLOOD && actor->info->deathsound)
+ sound = actor->info->deathsound;
+ else
+ sound = sfx_slop;
+
+ S_StartSound(actor, sound);
+}
+
+//
+// A_Pain
+//
+// villsa [STRIFE]
+// * Play random peasant sounds; otherwise play painsound directly
+//
+void A_Pain(mobj_t* actor)
+{
+ int sound = actor->info->painsound;
+
+ if(sound)
+ {
+ if(sound >= sfx_pespna && sound <= sfx_pespnd)
+ sound = sfx_pespna + (P_Random() % 4);
+
+ S_StartSound(actor, sound);
+ }
+}
+
+//
+// A_PeasantCrash
+//
+// villsa [STRIFE] new codepointer
+// 09/08/10: Called from Peasant's "crash" state (not to be confused with
+// Heretic crash states), which is invoked when the Peasant has taken
+// critical but sub-fatal damage. It will "bleed out" the rest of its
+// health by calling this function repeatedly.
+//
+void A_PeasantCrash(mobj_t* actor)
+{
+ // Set NODIALOG, because you probably wouldn't feel like talking either
+ // if somebody just stabbed you in the gut with a punch dagger...
+ actor->flags |= MF_NODIALOG;
+
+ if(!(P_Random() % 5))
+ {
+ A_Pain(actor); // inlined in asm
+ actor->health--;
+ }
+
+ if(actor->health <= 0)
+ P_KillMobj(actor->target, actor);
+}
+
+//
+// A_Fall
+//
+// [STRIFE]
+// * Set NODIALOG, and clear NOGRAVITY and SHADOW
+//
+void A_Fall (mobj_t *actor)
+{
+ // villsa [STRIFE] set NODIALOG flag to stop dialog
+ actor->flags |= MF_NODIALOG;
+
+ // actor is on ground, it can be walked over
+ // villsa [STRIFE] remove nogravity/shadow flags as well
+ actor->flags &= ~(MF_SOLID|MF_NOGRAVITY|MF_SHADOW);
+}
+
+//
+// A_HideZombie
+//
+// villsa [STRIFE] new codepointer
+// Used by the "Becoming" Acolytes on the Loremaster's level.
+//
+void A_HideZombie(mobj_t* actor)
+{
+ line_t junk;
+
+ junk.tag = 999;
+ EV_DoDoor(&junk, blazeClose);
+
+ if(actor->target && actor->target->player)
+ P_NoiseAlert(actor->target, actor); // inlined in asm
+}
+
+//
+// A_MerchantPain
+//
+// villsa [STRIFE] new codepointer
+// 09/08/10: Pain pointer for merchant characters. They close up shop for
+// a while and set off the alarm.
+//
+void A_MerchantPain(mobj_t* actor)
+{
+ line_t junk;
+
+ junk.tag = 999;
+ EV_DoDoor(&junk, shopClose);
+
+ if(actor->target && actor->target->player)
+ P_NoiseAlert(actor->target, actor); // inlined in asm
+}
+
+// haleyjd 09/05/10: Removed unused CheckBossEnd Choco routine.
+
+// haleyjd 09/05/10: [STRIFE] Removed:
+// A_Hoof, A_Metal, A_BabyMetal, A_OpenShotgun2, A_LoadShotgun2,
+// A_CloseShotgun2, A_BrainAwake, A_BrainPain, A_BrainScream, A_BrainExplode,
+// A_BrainDie, A_BrainSpit, A_SpawnSound, A_SpawnFly
+
+//
+// A_ProgrammerDie
+//
+// villsa [STRIFE] new codepointer
+// 09/08/10: Action routine for the Programmer's grisly death. Spawns the
+// separate mechanical base object and sends it flying off in some random
+// direction.
+//
+void A_ProgrammerDie(mobj_t* actor)
+{
+ int r;
+ angle_t an;
+ mobj_t* mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 24*FRACUNIT, MT_PROGRAMMERBASE);
+
+ // haleyjd 20110223: fix add w/ANG180
+ r = P_Random();
+ an = ((r - P_Random()) << 22) + actor->angle + ANG180;
+ mo->angle = an;
+
+ P_ThrustMobj(mo, an, mo->info->speed); // inlined in asm
+
+ mo->momz = P_Random() << 9;
+}
+
+//
+// A_InqTossArm
+//
+// villsa [STRIFE] new codepointer
+// 09/08/10: Inquisitor death action. Spawns an arm and tosses it.
+//
+void A_InqTossArm(mobj_t* actor)
+{
+ int r;
+ angle_t an;
+ mobj_t* mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + (24*FRACUNIT), MT_INQARM);
+
+ r = P_Random();
+ an = ((r - P_Random()) << 22) + actor->angle - ANG90;
+ mo->angle = an;
+
+ P_ThrustMobj(mo, an, mo->info->speed); // inlined in asm
+
+ mo->momz = P_Random() << 10;
+}
+
+//
+// A_SpawnSpectreA
+//
+// villsa [STRIFE] new codepointer (unused)
+// 09/08/10: Spawns Spectre A. Or would, if anything actually used this.
+// This is evidence that the Programmer's spectre, which appears in the
+// Catacombs in the final version, was originally meant to be spawned
+// after his death.
+//
+void A_SpawnSpectreA(mobj_t* actor)
+{
+ mobj_t* mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SPECTRE_A);
+ mo->momz = P_Random() << 9;
+}
+
+//
+// A_SpawnSpectreB
+//
+// villsa [STRIFE] new codepointer
+// 09/08/10: Action function to spawn the Bishop's spectre.
+//
+void A_SpawnSpectreB(mobj_t* actor)
+{
+ mobj_t* mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SPECTRE_B);
+ mo->momz = P_Random() << 9;
+}
+
+//
+// A_SpawnSpectreC
+//
+// villsa [STRIFE] new codepointer (unused)
+// 09/08/10: Action function to spawn the Oracle's spectre. Also
+// unused, because the Oracle's spectre is already present on the
+// map and is awakened on his death. Also left over from the
+// unreleased beta (and demo) versions.
+//
+void A_SpawnSpectreC(mobj_t* actor)
+{
+ mobj_t* mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SPECTRE_C);
+ mo->momz = P_Random() << 9;
+}
+
+//
+// A_SpawnSpectreD
+//
+// villsa [STRIFE] new codepointer
+// 09/08/10: Action function to spawn Macil's Spectre.
+//
+void A_SpawnSpectreD(mobj_t* actor)
+{
+ mobj_t* mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SPECTRE_D);
+ mo->momz = P_Random() << 9;
+}
+
+//
+// A_SpawnSpectreE
+//
+// villsa [STRIFE] new codepointer
+// 09/08/10: Action function to spawn the Loremaster's Spectre.
+//
+void A_SpawnSpectreE(mobj_t* actor)
+{
+ mobj_t* mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SPECTRE_E);
+ mo->momz = P_Random() << 9;
+}
+
+// [STRIFE] New statics - Remember the Entity's spawning position.
+static fixed_t entity_pos_x = 0;
+static fixed_t entity_pos_y = 0;
+static fixed_t entity_pos_z = 0;
+
+//
+// A_SpawnEntity
+//
+// villsa [STRIFE] new codepointer
+// 09/08/10: You will fall on your knees before the True God, the One Light.
+//
+void A_SpawnEntity(mobj_t* actor)
+{
+ mobj_t* mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 70*FRACUNIT, MT_ENTITY);
+ mo->momz = 5*FRACUNIT;
+
+ entity_pos_x = mo->x;
+ entity_pos_y = mo->y;
+ entity_pos_z = mo->z;
+}
+
+//
+// P_ThrustMobj
+//
+// villsa [STRIFE] new function
+// Thrusts an thing in a specified force/direction
+// Beware! This is inlined everywhere in the asm
+//
+void P_ThrustMobj(mobj_t *actor, angle_t angle, fixed_t force)
+{
+ angle_t an = angle >> ANGLETOFINESHIFT;
+ actor->momx += FixedMul(finecosine[an], force);
+ actor->momy += FixedMul(finesine[an], force);
+}
+
+//
+// A_EntityDeath
+//
+// [STRIFE]
+// haleyjd 09/08/10: The death of the Entity's spectre brings forth
+// three subentities, which are significantly less dangerous on their
+// own but threatening together.
+//
+void A_EntityDeath(mobj_t* actor)
+{
+ mobj_t *subentity;
+ angle_t an;
+ fixed_t dist;
+
+ dist = 2 * mobjinfo[MT_SUBENTITY].radius;
+
+ // Subentity One
+ an = actor->angle >> ANGLETOFINESHIFT;
+ subentity = P_SpawnMobj(FixedMul(finecosine[an], dist) + entity_pos_x,
+ FixedMul(finesine[an], dist) + entity_pos_y,
+ entity_pos_z, MT_SUBENTITY);
+ subentity->target = actor->target;
+ A_FaceTarget(subentity);
+ P_ThrustMobj(subentity, subentity->angle, 625 << 13);
+
+ // Subentity Two
+ an = (actor->angle + ANG90) >> ANGLETOFINESHIFT;
+ subentity = P_SpawnMobj(FixedMul(finecosine[an], dist) + entity_pos_x,
+ FixedMul(finesine[an], dist) + entity_pos_y,
+ entity_pos_z, MT_SUBENTITY);
+ subentity->target = actor->target;
+ P_ThrustMobj(subentity, actor->angle + ANG90, 4);
+ A_FaceTarget(subentity);
+
+ // Subentity Three
+ an = (actor->angle - ANG90) >> ANGLETOFINESHIFT;
+ subentity = P_SpawnMobj(FixedMul(finecosine[an], dist) + entity_pos_x,
+ FixedMul(finesine[an], dist) + entity_pos_y,
+ entity_pos_z, MT_SUBENTITY);
+ subentity->target = actor->target;
+ P_ThrustMobj(subentity, actor->angle - ANG90, 4);
+ A_FaceTarget(subentity);
+}
+
+//
+// A_SpawnZombie
+//
+// villsa [STRIFE] new codepointer
+//
+void A_SpawnZombie(mobj_t* actor)
+{
+ P_SpawnMobj(actor->x, actor->y, actor->z, MT_ZOMBIE);
+}
+
+//
+// A_ZombieInSpecialSector
+//
+// villsa [STRIFE] new codepointer
+//
+void A_ZombieInSpecialSector(mobj_t* actor)
+{
+ sector_t* sector;
+ fixed_t force;
+ angle_t angle;
+ int tagval;
+
+ sector = actor->subsector->sector;
+ if(actor->z != sector->floorheight)
+ return;
+
+ if(sector->special <= 15)
+ P_DamageMobj(actor, NULL, NULL, 999);
+ else if(sector->special == 18)
+ {
+ tagval = sector->tag - 100;
+ force = (tagval % 10) << 12;
+ angle = (tagval / 10) << 29;
+ P_ThrustMobj(actor, angle, force); // inlined in asm
+ }
+}
+
+//
+// A_CrystalExplode
+//
+// villsa [STRIFE] new codepointer
+// Throws out debris from the Power Crystal and sets its sector floorheight
+// to the lowest surrounding floor (this is maybe the only time a direct
+// level-changing action is done by an object in this fashion in any of
+// the DOOM engine games... they usually call a line special instead)
+//
+void A_CrystalExplode(mobj_t* actor)
+{
+ sector_t* sector;
+ mobj_t* rubble;
+ int i;
+ int r;
+
+ sector = actor->subsector->sector;
+ sector->lightlevel = 0;
+ sector->floorheight = P_FindLowestFloorSurrounding(sector);
+
+ // spawn rubble
+ for(i = 0; i < 8; i++)
+ {
+ rubble = P_SpawnMobj(actor->x, actor->y, actor->z, MT_RUBBLE1 + i);
+ r = P_Random();
+ rubble->momx = ((r & 0x0f) - (P_Random() & 7)) << FRACBITS;
+ r = P_Random();
+ rubble->momy = ((r & 7) - (P_Random() & 7)) << FRACBITS;
+ rubble->momz = ((P_Random() & 3) << FRACBITS) + (7*FRACUNIT);
+ }
+}
+
+// [STRIFE] New static global - buffer used for various player messages.
+static char pmsgbuffer[80];
+
+//
+// P_FreePrisoners
+//
+// haleyjd 09/08/10: [STRIFE] New function
+// * Called when the prisoners get freed, obviously. Gives a
+// message and awards quest token 13.
+//
+void P_FreePrisoners(void)
+{
+ int i;
+
+ DEH_snprintf(pmsgbuffer, sizeof(pmsgbuffer), "You've freed the prisoners!");
+
+ for(i = 0; i < MAXPLAYERS; i++)
+ {
+ P_GiveItemToPlayer(&players[i], SPR_TOKN, MT_TOKEN_QUEST13);
+ players[i].message = pmsgbuffer;
+ }
+}
+
+//
+// P_DestroyConverter
+//
+// haleyjd 09/08/10: [STRIFE] New function
+// * Called when the converter is shut down in the factory.
+// Gives several items and a message.
+//
+void P_DestroyConverter(void)
+{
+ int i;
+
+ DEH_snprintf(pmsgbuffer, sizeof(pmsgbuffer), "You've destroyed the Converter!");
+
+ for(i = 0; i < MAXPLAYERS; i++)
+ {
+ P_GiveItemToPlayer(&players[i], SPR_TOKN, MT_TOKEN_QUEST25);
+ P_GiveItemToPlayer(&players[i], SPR_TOKN, MT_TOKEN_STAMINA);
+ P_GiveItemToPlayer(&players[i], SPR_TOKN, MT_TOKEN_NEW_ACCURACY);
+ players[i].message = pmsgbuffer;
+ }
+}
+
+//
+// A_QuestMsg
+//
+// villsa [STRIFE] new codepointer
+// Displays text based on quest item's name
+// Quest item is based on actor's speed
+//
+void A_QuestMsg(mobj_t* actor)
+{
+ char* name;
+ int quest;
+ int i;
+
+ // get name
+ name = DEH_String(mobjinfo[(MT_TOKEN_QUEST1 - 1) + actor->info->speed].name);
+ strcpy(pmsgbuffer, name); // inlined in asm
+
+ // give quest and display message to players
+ for(i = 0; i < MAXPLAYERS; i++)
+ {
+ quest = 1 << (actor->info->speed - 1);
+ players[i].message = pmsgbuffer;
+ players[i].questflags |= quest;
+ }
+}
+
+//
+// A_ExtraLightOff
+//
+// villsa [STRIFE] new codepointer
+// 09/08/10: Called by the Power Crystal to turn off the extended
+// flash of light caused by its explosion.
+//
+void A_ExtraLightOff(mobj_t* actor)
+{
+ if(!actor->target)
+ return;
+
+ if(!actor->target->player)
+ return;
+
+ actor->target->player->extralight = 0;
+}
+
+//
+// A_CrystalRadiusAtk
+//
+// villsa [STRIFE] new codepointer
+// 09/08/10: Called by the power crystal when it dies.
+//
+void A_CrystalRadiusAtk(mobj_t* actor)
+{
+ P_RadiusAttack(actor, actor->target, 512);
+
+ if(!(actor->target && actor->target->player))
+ return;
+
+ // set extralight to 5 for near full-bright
+ actor->target->player->extralight = 5;
+}
+
+//
+// A_DeathExplode5
+//
+// villsa [STRIFE] new codepointer
+//
+void A_DeathExplode5(mobj_t* actor)
+{
+ P_RadiusAttack(actor, actor->target, 192);
+ if(actor->target && actor->target->player)
+ P_NoiseAlert(actor->target, actor); // inlined in asm
+}
+
+//
+// A_DeathExplode1
+//
+// villsa [STRIFE] new codepointer
+//
+void A_DeathExplode1(mobj_t* actor)
+{
+ P_RadiusAttack(actor, actor->target, 128);
+ if(actor->target && actor->target->player)
+ P_NoiseAlert(actor->target, actor); // inlined in asm
+}
+
+//
+// A_DeathExplode2
+//
+// villsa [STRIFE] new codepointer
+//
+void A_DeathExplode2(mobj_t* actor)
+{
+ P_RadiusAttack(actor, actor->target, 64);
+ if(actor->target && actor->target->player)
+ P_NoiseAlert(actor->target, actor); // inlined in asm
+}
+
+//
+// A_DeathExplode3
+//
+// villsa [STRIFE] new codepointer
+//
+void A_DeathExplode3(mobj_t* actor)
+{
+ P_RadiusAttack(actor, actor->target, 32);
+ if(actor->target && actor->target->player)
+ P_NoiseAlert(actor->target, actor); // inlined in asm
+}
+
+//
+// A_RaiseAlarm
+//
+// villsa [STRIFE] new codepointer
+// 09/08/10: Set off the infamous alarm. This is just a noise alert.
+//
+void A_RaiseAlarm(mobj_t* actor)
+{
+ if(actor->target && actor->target->player)
+ P_NoiseAlert(actor->target, actor); // inlined in asm
+}
+
+//
+// A_MissileTick
+// villsa [STRIFE] - new codepointer
+//
+void A_MissileTick(mobj_t* actor)
+{
+ if(--actor->reactiontime <= 0)
+ {
+ P_ExplodeMissile(actor);
+ actor->flags &= ~MF_MISSILE;
+ }
+}
+
+//
+// A_SpawnGrenadeFire
+// villsa [STRIFE] - new codepointer
+//
+void A_SpawnGrenadeFire(mobj_t* actor)
+{
+ P_SpawnMobj(actor->x, actor->y, actor->z, MT_PFLAME);
+}
+
+//
+// A_NodeChunk
+//
+// villsa [STRIFE] - new codepointer
+// Throw out "nodes" from a spectral entity
+//
+void A_NodeChunk(mobj_t* actor)
+{
+ int r;
+ mobj_t* mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 10*FRACUNIT, MT_NODE);
+ r = P_Random();
+ mo->momx = ((r & 0x0f) - (P_Random() & 7)) << FRACBITS;
+ r = P_Random();
+ mo->momy = ((r & 7) - (P_Random() & 0x0f)) << FRACBITS;
+ mo->momz = (P_Random() & 0x0f) << FRACBITS;
+}
+
+//
+// A_HeadChunk
+//
+// villsa [STRIFE] - new codepointer
+// Throw out the little "eye"-like object from a spectral entity when it dies.
+//
+void A_HeadChunk(mobj_t* actor)
+{
+ int r;
+ mobj_t* mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 10*FRACUNIT, MT_SPECTREHEAD);
+ r = P_Random();
+ mo->momx = ((r & 7) - (P_Random() & 0x0f)) << FRACBITS;
+ r = P_Random();
+ mo->momy = ((r & 0x0f) - (P_Random() & 7)) << FRACBITS;
+ mo->momz = (P_Random() & 7) << FRACBITS;
+}
+
+//
+// A_BurnSpread
+// villsa [STRIFE] - new codepointer
+//
+void A_BurnSpread(mobj_t* actor)
+{
+ int t;
+ mobj_t* mo;
+ fixed_t x;
+ fixed_t y;
+
+ actor->momz -= (8*FRACUNIT);
+
+ t = P_Random();
+ actor->momx += ((t & 3) - (P_Random() & 3)) << FRACBITS;
+ t = P_Random();
+ actor->momy += ((t & 3) - (P_Random() & 3)) << FRACBITS;
+
+ S_StartSound(actor, sfx_lgfire);
+
+ if(actor->flags & MF_DROPPED)
+ return; // not the parent
+
+ // haleyjd 20110223: match order of calls in binary
+ y = actor->y + (((P_Random() + 12) & 31) << FRACBITS);
+ x = actor->x + (((P_Random() + 12) & 31) << FRACBITS);
+
+ // spawn child
+ mo = P_SpawnMobj(x, y, actor->z + (4*FRACUNIT), MT_PFLAME);
+
+ t = P_Random();
+ mo->momx += ((t & 7) - (P_Random() & 7)) << FRACBITS;
+ t = P_Random();
+ mo->momy += ((t & 7) - (P_Random() & 7)) << FRACBITS;
+ mo->momz -= FRACUNIT;
+ mo->flags |= MF_DROPPED;
+ mo->reactiontime = (P_Random() & 3) + 2;
+}
+
+//
+// A_BossDeath
+//
+// Possibly trigger special effects
+// if on first boss level
+//
+// haleyjd 09/17/10: [STRIFE]
+// * Modified to handle all Strife bosses.
+//
+void A_BossDeath (mobj_t* actor)
+{
+ int i;
+ thinker_t *th;
+ line_t junk;
+
+ // only the following types can be a boss:
+ switch(actor->type)
+ {
+ case MT_CRUSADER:
+ case MT_SPECTRE_A:
+ case MT_SPECTRE_B:
+ case MT_SPECTRE_C:
+ case MT_SPECTRE_D:
+ case MT_SPECTRE_E:
+ case MT_SUBENTITY:
+ case MT_PROGRAMMER:
+ break;
+ default:
+ return;
+ }
+
+ // check for a living player
+ for(i = 0; i < MAXPLAYERS; i++)
+ {
+ if(playeringame[i] && players[i].health > 0)
+ break;
+ }
+ if(i == MAXPLAYERS)
+ return; // everybody's dead.
+
+ // check for a still living boss
+ for(th = thinkercap.next; th != &thinkercap; th = th->next)
+ {
+ if(th->function.acp1 == (actionf_p1) P_MobjThinker)
+ {
+ mobj_t *mo = (mobj_t *)th;
+
+ if(mo != actor && mo->type == actor->type && mo->health > 0)
+ return; // one is still alive.
+ }
+ }
+
+ // Victory!
+ switch(actor->type)
+ {
+ case MT_CRUSADER:
+ junk.tag = 667;
+ EV_DoFloor(&junk, lowerFloorToLowest);
+ break;
+
+ case MT_SPECTRE_A:
+ GiveVoiceObjective("VOC95", "LOG95", 0);
+ junk.tag = 999;
+ EV_DoFloor(&junk, lowerFloorToLowest);
+ break;
+
+ case MT_SPECTRE_B:
+ P_GiveItemToPlayer(&players[0], SPR_TOKN, MT_TOKEN_BISHOP);
+ GiveVoiceObjective("VOC74", "LOG74", 0);
+ break;
+
+ case MT_SPECTRE_C:
+ // Look for an MT_ORACLE - this is for in case the player awakened the
+ // Oracle's spectre without killing the Oracle, which is possible by
+ // looking up to max and firing the Sigil at it. If this were not done,
+ // a serious sequence break possibility would arise where one could
+ // kill both the Oracle AND Macil, possibly throwing the game out of
+ // sorts entirely. Too bad they thought of it ;) However this also
+ // causes a bug sometimes! The Oracle, in its death state, sets the
+ // Spectre C back to its seestate. If the Spectre C is already dead,
+ // it becomes an undead ghost monster. Then it's a REAL spectre ;)
+ for(th = thinkercap.next; th != &thinkercap; th = th->next)
+ {
+ if(th->function.acp1 == (actionf_p1) P_MobjThinker)
+ {
+ mobj_t *mo = (mobj_t *)th;
+
+ // KILL ALL ORACLES! RAWWR!
+ if(mo != actor && mo->type == MT_ORACLE && mo->health > 0)
+ P_KillMobj(actor, mo);
+ }
+ }
+ P_GiveItemToPlayer(&players[0], SPR_TOKN, MT_TOKEN_ORACLE);
+
+ // Bishop is dead? - verify.
+ if(players[0].questflags & QF_QUEST21)
+ P_GiveItemToPlayer(&players[0], SPR_TOKN, MT_TOKEN_QUEST22);
+
+ // Macil is dead?
+ if(players[0].questflags & QF_QUEST24)
+ {
+ // Loremaster is dead?
+ if(players[0].questflags & QF_QUEST26)
+ {
+ // We wield the complete sigil, blahblah
+ GiveVoiceObjective("VOC85", "LOG85", 0);
+ }
+ }
+ else
+ {
+ // So much for prognostication!
+ GiveVoiceObjective("VOC87", "LOG87", 0);
+ }
+ junk.tag = 222; // Open the exit door again;
+ EV_DoDoor(&junk, open); // Note this is NOT the Loremaster door...
+ break;
+
+ case MT_SPECTRE_D:
+ P_GiveItemToPlayer(&players[0], SPR_TOKN, MT_TOKEN_MACIL);
+ if(players[0].questflags & QF_QUEST25) // Destroyed converter?
+ GiveVoiceObjective("VOC106", "LOG106", 0);
+ else
+ GiveVoiceObjective("VOC79", "LOG79", 0);
+ break;
+
+ case MT_SPECTRE_E:
+ P_GiveItemToPlayer(&players[0], SPR_TOKN, MT_TOKEN_LOREMASTER);
+ if(!netgame)
+ {
+ P_GiveItemToPlayer(&players[0], SPR_TOKN, MT_TOKEN_STAMINA);
+ P_GiveItemToPlayer(&players[0], SPR_TOKN, MT_TOKEN_NEW_ACCURACY);
+ }
+ if(players[0].sigiltype == 4)
+ GiveVoiceObjective("VOC85", "LOG85", 0);
+ else
+ GiveVoiceObjective("VOC83", "LOG83", 0);
+ junk.tag = 666;
+ EV_DoFloor(&junk, lowerFloorToLowest);
+ break;
+
+ case MT_SUBENTITY:
+ F_StartFinale();
+ break;
+
+ case MT_PROGRAMMER:
+ F_StartFinale();
+ G_ExitLevel(0);
+ break;
+
+ default:
+ // Real classy, Rogue.
+ if(actor->type)
+ I_Error("Error: Unconnected BossDeath id %d", actor->type);
+ break;
+ }
+}
+
+//
+// A_AcolyteSpecial
+//
+// villsa [STRIFE] - new codepointer
+// Awards quest #7 when all the Blue Acolytes are killed in Tarnhill
+//
+void A_AcolyteSpecial(mobj_t* actor)
+{
+ int i;
+ thinker_t* th;
+
+ if(actor->type != MT_GUARD8)
+ return; // must be MT_GUARD8
+
+ for(i = 0; i < MAXPLAYERS; i++)
+ {
+ if(playeringame[i] && players[i].health > 0)
+ break;
+ }
+
+ if(i == 8)
+ return;
+
+ for(th = thinkercap.next; th != &thinkercap; th = th->next)
+ {
+ if(th->function.acp1 == (actionf_p1) P_MobjThinker)
+ {
+ mobj_t *mo = (mobj_t *)th;
+
+ // Found a living MT_GUARD8?
+ if(mo != actor && mo->type == actor->type && mo->health > 0)
+ return;
+ }
+ }
+
+ // All MT_GUARD8 are dead, give quest token #7 to all players
+ for(i = 0; i < MAXPLAYERS; i++)
+ P_GiveItemToPlayer(&players[i], SPR_TOKN, MT_TOKEN_QUEST7);
+
+ // play voice, give objective
+ GiveVoiceObjective("VOC14", "LOG14", 0);
+}
+
+//
+// A_InqChase
+// villsa [STRIFE] - new codepointer
+//
+void A_InqChase(mobj_t* actor)
+{
+ S_StartSound(actor, sfx_inqact);
+ A_Chase(actor);
+}
+
+//
+// A_StalkerChase
+// villsa [STRIFE] - new codepointer
+//
+void A_StalkerChase(mobj_t* actor)
+{
+ S_StartSound(actor, sfx_spdwlk);
+ A_Chase(actor);
+}
+
+//
+// A_PlayerScream
+//
+// [STRIFE]
+// * Modified to eliminate gamemode check and to use Strife sound.
+//
+void A_PlayerScream (mobj_t* mo)
+{
+ // Default death sound.
+ int sound = sfx_pldeth;
+
+ // villsa [STRIFE] don't check for gamemode
+ if(mo->health < -50)
+ {
+ // IF THE PLAYER DIES
+ // LESS THAN -50% WITHOUT GIBBING
+ sound = sfx_plxdth; // villsa [STRIFE] different sound
+ }
+
+ S_StartSound (mo, sound);
+}
+
+//
+// A_TeleportBeacon
+//
+// villsa [STRIFE] - new codepointer
+//
+void A_TeleportBeacon(mobj_t* actor)
+{
+ mobj_t* mobj;
+ mobj_t* fog;
+ fixed_t fog_x;
+ fixed_t fog_y;
+
+ if(actor->target != players[actor->miscdata].mo)
+ actor->target = players[actor->miscdata].mo;
+
+ mobj = P_SpawnMobj(actor->x, actor->y, ONFLOORZ, MT_REBEL1);
+
+ if(!P_TryMove(mobj, mobj->x, mobj->y))
+ {
+ // Rebel is probably stuck in something.. too bad
+ P_RemoveMobj(mobj);
+ return;
+ }
+
+ // beacon no longer solid
+ actor->flags &= ~MF_SOLID;
+
+ // set color and flags
+ mobj->flags |= ((actor->miscdata << MF_TRANSSHIFT) | MF_NODIALOG);
+ mobj->target = NULL;
+
+ // double Rebel's health in deathmatch mode
+ if(deathmatch)
+ mobj->health <<= 1;
+
+ if(actor->target)
+ {
+ mobj_t* targ = actor->target->target;
+
+ if(targ)
+ {
+ if(targ->type != MT_REBEL1 || targ->miscdata != mobj->miscdata)
+ mobj->target = targ;
+ }
+ }
+
+ P_SetMobjState(mobj, mobj->info->seestate);
+ mobj->angle = actor->angle;
+
+ fog_x = mobj->x + FixedMul(20*FRACUNIT, finecosine[actor->angle>>ANGLETOFINESHIFT]);
+ fog_y = mobj->y + FixedMul(20*FRACUNIT, finesine[actor->angle>>ANGLETOFINESHIFT]);
+
+ fog = P_SpawnMobj(fog_x, fog_y, mobj->z, MT_TFOG);
+ S_StartSound(fog, sfx_telept);
+
+ if(--actor->health < 0)
+ P_RemoveMobj(actor);
+}
+
+//
+// A_BodyParts
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Spawns gibs when organic actors get splattered, or junk
+// when robots explode.
+//
+void A_BodyParts(mobj_t* actor)
+{
+ mobjtype_t type;
+ mobj_t* mo;
+ angle_t an;
+
+ if(actor->flags & MF_NOBLOOD) // Robots are flagged NOBLOOD
+ type = MT_JUNK;
+ else
+ type = MT_MEAT;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + (24*FRACUNIT), type);
+ P_SetMobjState(mo, mo->info->spawnstate + (P_Random() % 19));
+
+ an = (P_Random() << 13) / 255;
+ mo->angle = an << ANGLETOFINESHIFT;
+
+ mo->momx = FixedMul(finecosine[an], (P_Random() & 0x0f) << FRACBITS);
+ mo->momy = FixedMul(finesine[an], (P_Random() & 0x0f) << FRACBITS);
+ mo->momz = (P_Random() & 0x0f) << FRACBITS;
+}
+
+//
+// A_ClaxonBlare
+//
+// [STRIFE] New function
+// haleyjd 09/08/10: The ever-dreadful Strife alarm!
+//
+void A_ClaxonBlare(mobj_t* actor)
+{
+ // Timer ran down?
+ if(--actor->reactiontime < 0)
+ {
+ // reset to initial state
+ actor->target = NULL;
+ actor->reactiontime = actor->info->reactiontime;
+
+ // listen for more noise
+ A_Listen(actor);
+
+ // If we heard something, stay on for a while,
+ // otherwise return to spawnstate.
+ if(actor->target)
+ actor->reactiontime = 50;
+ else
+ P_SetMobjState(actor, actor->info->spawnstate);
+ }
+
+ // When almost ran down, clear the soundtarget so it doesn't
+ // retrigger the alarm.
+ // Also, play the harsh, grating claxon.
+ if(actor->reactiontime == 2)
+ actor->subsector->sector->soundtarget = NULL;
+ else if(actor->reactiontime > 50)
+ S_StartSound(actor, sfx_alarm);
+}
+
+//
+// A_ActiveSound
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Plays an object's active sound periodically.
+//
+void A_ActiveSound(mobj_t* actor)
+{
+ if(actor->info->activesound)
+ {
+ if(!(leveltime & 7)) // haleyjd: added parens
+ S_StartSound(actor, actor->info->activesound);
+ }
+}
+
+//
+// A_ClearSoundTarget
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Clears the actor's sector soundtarget, so that the actor
+// will not be continually alerted/awakened ad infinitum. Used by
+// shopkeepers.
+//
+void A_ClearSoundTarget(mobj_t* actor)
+{
+ actor->subsector->sector->soundtarget = NULL;
+}
+
+//
+// A_DropBurnFlesh
+//
+// villsa [STRIFE] new codepointer
+//
+void A_DropBurnFlesh(mobj_t* actor)
+{
+ mobj_t* mo;
+ mobjtype_t type;
+
+ type = actor->type;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + (24*FRACUNIT), MT_BURNDROP);
+ mo->momz = -FRACUNIT;
+
+ actor->type = MT_SFIREBALL;
+ P_RadiusAttack(actor, actor, 64);
+ actor->type = type;
+}
+
+//
+// A_FlameDeath
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Death animation for flamethrower fireballs.
+//
+void A_FlameDeath(mobj_t* actor)
+{
+ actor->flags |= MF_NOGRAVITY;
+ actor->momz = (P_Random() & 3) << FRACBITS;
+}
+
+//
+// A_ClearForceField
+//
+// villsa [STRIFE] new codepointer
+// check for all matching lines in the sector
+// and disable blocking/midtextures
+//
+void A_ClearForceField(mobj_t* actor)
+{
+ int i;
+ sector_t *sec;
+ line_t *secline;
+
+ actor->flags &= ~(MF_SOLID|MF_SPECIAL);
+ sec = actor->subsector->sector;
+
+ if(!sec->linecount)
+ return;
+
+ for(i = 0; i < sec->linecount; i++)
+ {
+ secline = sec->lines[i];
+ // BUG: will crash if 1S line has TWOSIDED flag!
+ if(!(secline->flags & ML_TWOSIDED))
+ continue;
+ if(secline->special != 148)
+ continue;
+
+ secline->flags &= ~ML_BLOCKING;
+ secline->special = 0;
+ sides[secline->sidenum[0]].midtexture = 0;
+ sides[secline->sidenum[1]].midtexture = 0;
+ }
+}
+
diff --git a/src/strife/p_floor.c b/src/strife/p_floor.c
new file mode 100644
index 00000000..31f2a7cf
--- /dev/null
+++ b/src/strife/p_floor.c
@@ -0,0 +1,590 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Floor animation: raising stairs.
+//
+//-----------------------------------------------------------------------------
+
+
+
+#include "z_zone.h"
+#include "doomdef.h"
+#include "p_local.h"
+
+#include "s_sound.h"
+
+// State.
+#include "doomstat.h"
+#include "r_state.h"
+// Data.
+#include "sounds.h"
+
+
+//
+// FLOORS
+//
+
+//
+// Move a plane (floor or ceiling) and check for crushing
+//
+// [STRIFE] Various changes were made to remove calls to P_ChangeSector when
+// P_ChangeSector returns true.
+//
+result_e
+T_MovePlane
+( sector_t* sector,
+ fixed_t speed,
+ fixed_t dest,
+ boolean crush,
+ int floorOrCeiling,
+ int direction )
+{
+ boolean flag;
+ fixed_t lastpos;
+
+ switch(floorOrCeiling)
+ {
+ case 0:
+ // FLOOR
+ switch(direction)
+ {
+ case -1:
+ // DOWN
+ if (sector->floorheight - speed < dest)
+ {
+ // villsa [STRIFE] unused
+ //lastpos = sector->floorheight;
+ sector->floorheight = dest;
+ flag = P_ChangeSector(sector,crush);
+
+ // villsa [STRIFE] unused
+ /*if (flag == true)
+ {
+ sector->floorheight =lastpos;
+ P_ChangeSector(sector,crush);
+ //return crushed;
+ }*/
+ return pastdest;
+ }
+ else
+ {
+ // villsa [STRIFE] unused
+ //lastpos = sector->floorheight;
+ sector->floorheight -= speed;
+ flag = P_ChangeSector(sector,crush);
+
+ // villsa [STRIFE] unused
+ /*if (flag == true)
+ {
+ sector->floorheight = lastpos;
+ P_ChangeSector(sector,crush);
+ return crushed;
+ }*/
+ return ok;
+ }
+ 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)
+ {
+ // haleyjd 20130210: Bug fix - Strife DOES do this.
+ if (crush == true)
+ return crushed;
+ sector->floorheight = lastpos;
+ P_ChangeSector(sector,crush);
+ return crushed;
+ }
+ else
+ return ok;
+ }
+ 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)
+ {
+ // villsa [STRIFE] unused
+ //lastpos = sector->ceilingheight;
+ sector->ceilingheight = dest;
+
+ // villsa [STRIFE] unused
+ //flag = P_ChangeSector(sector,crush);
+ /*if (flag == true)
+ {
+ sector->ceilingheight = lastpos;
+ P_ChangeSector(sector,crush);
+ //return crushed;
+ }*/
+ return pastdest;
+ }
+ else
+ {
+ // villsa [STRIFE] unused
+ //lastpos = sector->ceilingheight;
+ sector->ceilingheight += speed;
+
+ // villsa [STRIFE] unused
+ //flag = P_ChangeSector(sector,crush);
+ return ok;
+ }
+ 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(&floor->sector->soundorg, sfx_stnmov);
+
+ if (res == pastdest)
+ {
+ floor->sector->specialdata = NULL;
+
+ 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(&floor->sector->soundorg, sfx_pstop);
+ }
+
+}
+
+//
+// HANDLE FLOOR TYPES
+//
+// haleyjd 09/16/2010: [STRIFE] Modifications to floortypes:
+// * raiseFloor24 was changed into raiseFloor64
+// * turboLower does not appear to adjust the floor height (STRIFE-TODO: verify)
+// * raiseFloor512AndChange type was added.
+//
+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: // [STRIFE] verified unmodified
+ floor->direction = -1;
+ floor->sector = sec;
+ floor->speed = FLOORSPEED;
+ floor->floordestheight =
+ P_FindHighestFloorSurrounding(sec);
+ break;
+
+ case lowerFloorToLowest: // [STRIFE] verified unmodified
+ floor->direction = -1;
+ floor->sector = sec;
+ floor->speed = FLOORSPEED;
+ floor->floordestheight =
+ P_FindLowestFloorSurrounding(sec);
+ break;
+
+ case turboLower: // [STRIFE] Modified: does not += 8
+ 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: // [STRIFE] verified unmodified
+ 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: // [STRIFE] verified unmodified
+ floor->direction = 1;
+ floor->sector = sec;
+ floor->speed = FLOORSPEED*4;
+ floor->floordestheight =
+ P_FindNextHighestFloor(sec,sec->floorheight);
+ break;
+
+ case raiseFloorToNearest: // [STRIFE] verified unmodified
+ floor->direction = 1;
+ floor->sector = sec;
+ floor->speed = FLOORSPEED;
+ floor->floordestheight =
+ P_FindNextHighestFloor(sec,sec->floorheight);
+ break;
+
+ case raiseFloor64: // [STRIFE] modified from raiseFloor24!
+ floor->direction = 1;
+ floor->sector = sec;
+ floor->speed = FLOORSPEED;
+ floor->floordestheight = floor->sector->floorheight +
+ 64 * FRACUNIT; // [STRIFE]
+ break;
+
+ case raiseFloor512: // [STRIFE] verified unmodified
+ floor->direction = 1;
+ floor->sector = sec;
+ floor->speed = FLOORSPEED;
+ floor->floordestheight = floor->sector->floorheight +
+ 512 * FRACUNIT;
+ break;
+
+ case raiseFloor24AndChange: // [STRIFE] verified unmodified
+ 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 raiseFloor512AndChange: // [STRIFE] New floor type
+ floor->direction = 1;
+ floor->sector = sec;
+ floor->speed = FLOORSPEED;
+ floor->floordestheight = floor->sector->floorheight +
+ 512 * FRACUNIT;
+ sec->floorpic = line->frontsector->floorpic;
+ sec->special = line->frontsector->special;
+ break;
+
+ case raiseToTexture: // [STRIFE] verified unmodified
+ {
+ int minsize = INT_MAX;
+ 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: // [STRIFE] verified unmodified
+ 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;
+
+ // Either Watcom or Rogue moved the switch out of the loop below, probably
+ // because it was a loop invariant, and put the default values in the
+ // initializers here. I cannot be bothered to figure it out without doing
+ // this myself :P
+ fixed_t stairsize = 8*FRACUNIT;
+ fixed_t speed = FLOORSPEED;
+ int direction = 1;
+
+ switch(type)
+ {
+ case build8: // [STRIFE] Verified unmodified.
+ speed = FLOORSPEED/4;
+ break;
+ case turbo16: // [STRIFE] Verified unmodified.
+ speed = FLOORSPEED*4;
+ stairsize = 16*FRACUNIT;
+ break;
+ case buildDown16: // [STRIFE] New stair type
+ stairsize = -16*FRACUNIT;
+ direction = -1;
+ break;
+ }
+
+ 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;
+ 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 = tsec-sectors;
+
+ if (secnum != newsecnum)
+ continue;
+
+ tsec = (sec->lines[i])->backsector;
+ newsecnum = 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 = direction; // [STRIFE]: for buildDown16
+ floor->sector = sec;
+ floor->speed = speed;
+ floor->floordestheight = height;
+ ok = 1;
+ break;
+ }
+ } while(ok);
+ }
+ return rtn;
+}
+
diff --git a/src/strife/p_inter.c b/src/strife/p_inter.c
new file mode 100644
index 00000000..bd56cbed
--- /dev/null
+++ b/src/strife/p_inter.c
@@ -0,0 +1,1408 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Handling interactions (i.e., collisions).
+//
+//-----------------------------------------------------------------------------
+
+// Data.
+#include "doomdef.h"
+#include "dstrings.h"
+#include "sounds.h"
+#include "deh_main.h"
+#include "deh_misc.h"
+#include "doomstat.h"
+#include "m_random.h"
+#include "i_system.h"
+#include "am_map.h"
+#include "p_local.h"
+#include "p_dialog.h" // villsa [STRIFE]
+#include "s_sound.h"
+#include "p_inter.h"
+
+#include "hu_stuff.h" // villsa [STRIFE]
+#include "z_zone.h" // villsa [STRIFE]
+
+// haleyjd [STRIFE]
+#include "w_wad.h"
+#include "p_pspr.h"
+#include "p_dialog.h"
+#include "f_finale.h"
+
+
+#define BONUSADD 6
+
+
+// a weapon is found with two clip loads,
+// a big item has five clip loads
+// villsa [STRIFE] updated arrays
+int maxammo[NUMAMMO] = { 250, 50, 25, 400, 100, 30, 16 };
+int clipammo[NUMAMMO] = { 10, 4, 2, 20, 4, 6, 4 };
+
+
+//
+// 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
+//
+// [STRIFE] Modified for Strife ammo types
+//
+boolean P_GiveAmmo(player_t* player, ammotype_t ammo, int num)
+{
+ int oldammo;
+
+ if(ammo == am_noammo)
+ return false;
+
+ if(ammo > NUMAMMO)
+ I_Error ("P_GiveAmmo: bad type %i", ammo);
+
+ 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.
+
+ // villsa [STRIFE] ammo update
+ // where's the check for grenades? - haleyjd: verified no switch to grenades
+ // haleyjd 10/03/10: don't change to electric bow when picking up poison
+ // arrows.
+ if(!player->readyweapon)
+ {
+ switch(ammo)
+ {
+ case am_bullets:
+ if(player->weaponowned[wp_rifle])
+ player->pendingweapon = wp_rifle;
+ break;
+
+ case am_elecbolts:
+ if(player->weaponowned[wp_elecbow])
+ player->pendingweapon = wp_elecbow;
+ break;
+
+ case am_cell:
+ if(player->weaponowned[wp_mauler])
+ player->pendingweapon = wp_mauler;
+ break;
+
+ case am_missiles:
+ if(player->weaponowned[wp_missile])
+ player->pendingweapon = wp_missile;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return true;
+}
+
+
+//
+// P_GiveWeapon
+// The weapon name may have a MF_DROPPED flag ored in.
+//
+// villsa [STRIFE] some stuff has been changed/moved around
+//
+boolean P_GiveWeapon(player_t* player, weapontype_t weapon, boolean dropped)
+{
+ boolean gaveammo;
+ boolean gaveweapon;
+
+ // villsa [STRIFE] new code for giving alternate version
+ // of the weapon to player
+ if(player->weaponowned[weapon])
+ gaveweapon = false;
+ else
+ {
+ gaveweapon = true;
+ player->weaponowned[weapon] = true;
+
+ // Alternate "sister" weapons that you also get as a bonus:
+ switch(weapon)
+ {
+ case wp_elecbow:
+ player->weaponowned[wp_poisonbow] = true;
+ break;
+
+ case wp_hegrenade:
+ player->weaponowned[wp_wpgrenade] = true;
+ break;
+
+ case wp_mauler:
+ player->weaponowned[wp_torpedo] = true;
+ break;
+
+ default:
+ break;
+ }
+
+ // check for the standard weapons only
+ if(weapon > player->readyweapon && weapon <= wp_sigil)
+ player->pendingweapon = weapon;
+
+ }
+
+ if(netgame && (deathmatch != 2) && !dropped)
+ {
+ // leave placed weapons forever on net games
+ if(!gaveweapon)
+ 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);
+
+ if(player == &players[consoleplayer])
+ S_StartSound (NULL, 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;
+
+ return(gaveweapon || gaveammo);
+}
+
+
+
+//
+// P_GiveBody
+// Returns false if the body isn't needed at all
+//
+// villsa [STRIFE] a lot of changes have been added for stamina
+//
+boolean P_GiveBody(player_t* player, int num)
+{
+ int maxhealth;
+ int healing;
+
+ maxhealth = MAXHEALTH + player->stamina;
+
+ if(num >= 0) // haleyjd 20100923: fixed to give proper amount of health
+ {
+ mobj_t *mo; // haleyjd 20110225: needed below...
+
+ // any healing to do?
+ if(player->health >= maxhealth)
+ return false;
+
+ // give, and cap to maxhealth
+ player->health += num;
+ if(player->health >= maxhealth)
+ player->health = maxhealth;
+
+ // Set mo->health for consistency.
+ // haleyjd 20110225: Seems Strife can call this on a NULL player->mo
+ // when giving items to players that are not in the game...
+ mo = P_SubstNullMobj(player->mo);
+ mo->health = player->health;
+ }
+ else
+ {
+ // [STRIFE] handle healing from the Front's medic
+ // The amount the player's health will be set to scales up with stamina
+ // increases.
+ // Ex 1: On the wimpiest skill level, -100 is sent in. This restores
+ // full health no matter what your stamina.
+ // (100*100)/100 = 100
+ // (200*100)/100 = 200
+ // Ex 2: On the most stringent skill levels, -50 is sent in. This will
+ // restore at most half of your health.
+ // (100*50)/100 = 50
+ // (200*50)/100 = 100
+ healing = (-num * maxhealth) / MAXHEALTH;
+
+ // This is also the "threshold" of healing. You need less health than
+ // the amount that will be restored in order to get any benefit.
+ // So on the easiest skill you will always be fully healed.
+ // On the hardest skill you must have less than 50 health, and will
+ // only recover to 50 (assuming base stamina stat)
+ if(player->health >= healing)
+ return false;
+
+ // Set health. BUG: Oddly, mo->health is NOT set here...
+ player->health = healing;
+ }
+
+ return true;
+}
+
+
+
+//
+// P_GiveArmor
+// Returns false if the armor is worse
+// than the current armor.
+//
+// [STRIFE] Modified for Strife armor items
+//
+boolean P_GiveArmor(player_t* player, int armortype)
+{
+ int hits;
+
+ // villsa [STRIFE]
+ if(armortype < 0)
+ {
+ if(player->armorpoints)
+ return false;
+
+ armortype = -armortype;
+ }
+
+ hits = armortype * 100;
+ if(player->armorpoints >= hits)
+ return false; // don't pick up
+
+ player->armortype = armortype;
+ player->armorpoints = hits;
+
+ return true;
+}
+
+
+
+//
+// P_GiveCard
+//
+// [STRIFE] Modified to use larger bonuscount
+//
+boolean P_GiveCard(player_t* player, card_t card)
+{
+ if (player->cards[card])
+ return false;
+
+ // villsa [STRIFE] multiply by 2
+ player->bonuscount = BONUSADD * 2;
+ player->cards[card] = true;
+
+ return true;
+}
+
+
+//
+// P_GivePower
+//
+// [STRIFE] Modifications for new powerups
+//
+boolean P_GivePower(player_t* player, powertype_t power)
+{
+ // haleyjd 09/14/10: [STRIFE] moved to top, exception for Shadow Armor
+ if(player->powers[power] && power != pw_invisibility)
+ return false; // already got it
+
+ // if giving pw_invisibility and player already has MVIS, no can do.
+ if(power == pw_invisibility && (player->mo->flags & MF_MVIS))
+ return false;
+
+ // villsa [STRIFE]
+ if(power == pw_targeter)
+ {
+ player->powers[power] = TARGTICS;
+ P_SetPsprite(player, ps_targcenter, S_TRGT_00); // 10
+ P_SetPsprite(player, ps_targleft, S_TRGT_01); // 11
+ P_SetPsprite(player, ps_targright, S_TRGT_02); // 12
+
+ player->psprites[ps_targcenter].sx = (160*FRACUNIT);
+ player->psprites[ps_targleft ].sy = (100*FRACUNIT);
+ player->psprites[ps_targcenter].sy = (100*FRACUNIT);
+ player->psprites[ps_targright ].sy = (100*FRACUNIT);
+ return true;
+ }
+
+ if(power == pw_invisibility)
+ {
+ // if player already had this power...
+ if(player->powers[power])
+ {
+ // remove SHADOW, give MVIS.
+ player->mo->flags &= ~MF_SHADOW;
+ player->mo->flags |= MF_MVIS;
+ }
+ else // give SHADOW
+ player->mo->flags |= MF_SHADOW;
+
+ // set tics if giving shadow, or renew them if MVIS.
+ player->powers[power] = INVISTICS;
+
+ 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;
+ }
+
+ // villsa [STRIFE]
+ if(power == pw_allmap)
+ {
+ // remember in mapstate
+ if(gamemap < 40)
+ player->mapstate[gamemap] = true;
+
+ player->powers[power] = 1;
+ return true;
+ }
+
+ // villsa [STRIFE]
+ if(power == pw_communicator)
+ {
+ player->powers[power] = 1;
+ return true;
+ }
+
+ // default behavior:
+ player->powers[power] = 1;
+ return true;
+}
+
+
+// villsa [STRIFE]
+static char pickupmsg[80];
+
+//
+// P_TouchSpecialThing
+//
+// [STRIFE] Rewritten for Strife collectables.
+//
+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)
+ return; // out of reach
+
+ sound = sfx_itemup;
+ player = toucher->player;
+
+ // Dead thing touching.
+ // Can happen with a sliding player corpse.
+ if(toucher->health <= 0)
+ return;
+
+ // villsa [STRIFE] damage toucher if special is spectral
+ // haleyjd 09/21/10: corrected to test for SPECTRE thingtypes specifically
+ switch(special->type)
+ {
+ case MT_SPECTRE_A:
+ case MT_SPECTRE_B:
+ case MT_SPECTRE_C:
+ case MT_SPECTRE_D:
+ case MT_SPECTRE_E:
+ case MT_ENTITY:
+ case MT_SUBENTITY:
+ P_DamageMobj(toucher, NULL, NULL, 5);
+ return;
+ default:
+ break;
+ }
+
+ // villsa [STRIFE]
+ pickupmsg[0] = 0;
+
+ // Identify by sprite.
+ // villsa [STRIFE] new items
+ switch(special->sprite)
+ {
+ // bullets
+ case SPR_BLIT: // haleyjd: fixed missing MF_DROPPED check
+ if(!P_GiveAmmo(player, am_bullets, !(special->flags & MF_DROPPED)))
+ return;
+ break;
+
+ // box of bullets
+ case SPR_BBOX:
+ if(!P_GiveAmmo(player, am_bullets, 5))
+ return;
+ break;
+
+ // missile
+ case SPR_ROKT:
+ if(!P_GiveAmmo(player, am_missiles, 1))
+ return;
+ break;
+
+ // box of missiles
+ case SPR_MSSL:
+ if(!P_GiveAmmo(player, am_missiles, 5))
+ return;
+ break;
+
+ // battery
+ case SPR_BRY1:
+ if(!P_GiveAmmo(player, am_cell, 1))
+ return;
+ break;
+
+ // cell pack
+ case SPR_CPAC:
+ if(!P_GiveAmmo(player, am_cell, 5))
+ return;
+ break;
+
+ // poison bolts
+ case SPR_PQRL:
+ if(!P_GiveAmmo(player, am_poisonbolts, 5))
+ return;
+ break;
+
+ // electric bolts
+ case SPR_XQRL:
+ if(!P_GiveAmmo(player, am_elecbolts, 5))
+ return;
+ break;
+
+ // he grenades
+ case SPR_GRN1:
+ if(!P_GiveAmmo(player, am_hegrenades, 1))
+ return;
+ break;
+
+ // wp grenades
+ case SPR_GRN2:
+ if(!P_GiveAmmo(player, am_wpgrenades, 1))
+ return;
+ break;
+
+ // rifle
+ case SPR_RIFL:
+ if(!P_GiveWeapon(player, wp_rifle, special->flags & MF_DROPPED))
+ return;
+ sound = sfx_wpnup; // haleyjd: SHK-CHK!
+ break;
+
+ // flame thrower
+ case SPR_FLAM:
+ if(!P_GiveWeapon(player, wp_flame, false))
+ return;
+ // haleyjd: gives extra ammo.
+ P_GiveAmmo(player, am_cell, 3);
+ sound = sfx_wpnup; // haleyjd: SHK-CHK!
+ break;
+
+ // missile launcher
+ case SPR_MMSL:
+ if(!P_GiveWeapon(player, wp_missile, false))
+ return;
+ sound = sfx_wpnup; // haleyjd: SHK-CHK!
+ break;
+
+ // grenade launcher
+ case SPR_GRND:
+ if(!P_GiveWeapon(player, wp_hegrenade, special->flags & MF_DROPPED))
+ return;
+ sound = sfx_wpnup; // haleyjd: SHK-CHK!
+ break;
+
+ // mauler
+ case SPR_TRPD:
+ if(!P_GiveWeapon(player, wp_mauler, false))
+ return;
+ sound = sfx_wpnup; // haleyjd: SHK-CHK!
+ break;
+
+ // electric bolt crossbow
+ case SPR_CBOW:
+ if(!P_GiveWeapon(player, wp_elecbow, special->flags & MF_DROPPED))
+ return;
+ sound = sfx_wpnup; // haleyjd: SHK-CHK!
+ break;
+
+ // haleyjd 09/21/10: missed case: THE SIGIL!
+ case SPR_SIGL:
+ if(!P_GiveWeapon(player, wp_sigil, special->flags & MF_DROPPED))
+ {
+ player->sigiltype = special->frame;
+ return;
+ }
+
+ if(netgame)
+ player->sigiltype = 4;
+
+ player->pendingweapon = wp_sigil;
+ player->st_update = true;
+ if(deathmatch)
+ return;
+ sound = sfx_wpnup;
+ break;
+
+ // backpack
+ case SPR_BKPK:
+ 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);
+ break;
+
+ // 1 Gold
+ case SPR_COIN:
+ P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+ break;
+
+ // 10 Gold
+ case SPR_CRED:
+ for(i = 0; i < 10; i++)
+ P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+ break;
+
+ // 25 Gold
+ case SPR_SACK:
+ // haleyjd 09/21/10: missed code: if a SPR_SACK object has negative
+ // health, it will give that much gold - STRIFE-TODO: verify
+ if(special->health < 0)
+ {
+ for(i = special->health; i != 0; i++)
+ P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+ }
+ else
+ {
+ for(i = 0; i < 25; i++)
+ P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+ }
+ break;
+
+ // 50 Gold
+ case SPR_CHST:
+ for(i = 0; i < 50; i++)
+ P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+ break;
+
+ // Leather Armor
+ case SPR_ARM1:
+ if(!P_GiveArmor(player, -2))
+ if(!P_GiveInventoryItem(player, special->sprite, special->type))
+ pickupmsg[0] = '!';
+ break;
+
+ // Metal Armor
+ case SPR_ARM2:
+ if(!P_GiveArmor(player, -1))
+ if(!P_GiveInventoryItem(player, special->sprite, special->type))
+ pickupmsg[0] = '!';
+ break;
+
+ // All-map powerup
+ case SPR_PMAP:
+ if(!P_GivePower(player, pw_allmap))
+ return;
+ sound = sfx_yeah;
+ break;
+
+ // The Comm Unit - because you need Blackbird whining in your ear the
+ // whole time and telling you how lost she is :P
+ case SPR_COMM:
+ if(!P_GivePower(player, pw_communicator))
+ return;
+ sound = sfx_yeah;
+ break;
+
+ // haleyjd 09/21/10: missed case - Shadow Armor; though, I do not know why
+ // this has a case distinct from generic inventory items... Maybe it started
+ // out as an auto-use-if-possible item much like regular armor...
+ case SPR_SHD1:
+ if(!P_GiveInventoryItem(player, SPR_SHD1, special->type))
+ pickupmsg[0] = '!';
+ break;
+
+ // villsa [STRIFE] check default items
+ case SPR_TOKN:
+ default:
+ if(special->type >= MT_KEY_BASE && special->type <= MT_NEWKEY5)
+ {
+ // haleyjd 09/21/10: Strife player still picks up keys that
+ // he has already found. (break, not return)
+ if(!P_GiveCard(player, special->type - MT_KEY_BASE))
+ break;
+ }
+ else
+ {
+ if(!P_GiveInventoryItem(player, special->sprite, special->type))
+ pickupmsg[0] = '!';
+ }
+ break;
+ }
+
+ // villsa [STRIFE] set message
+ if(!pickupmsg[0])
+ {
+ if(special->info->name)
+ {
+ DEH_snprintf(pickupmsg, sizeof(pickupmsg),
+ "You picked up the %s.", DEH_String(special->info->name));
+ }
+ else
+ DEH_snprintf(pickupmsg, sizeof(pickupmsg), "You picked up the item.");
+ }
+ // use the first character to indicate that the player is full on items
+ else if(pickupmsg[0] == '!')
+ {
+ DEH_snprintf(pickupmsg, sizeof(pickupmsg), "You cannot hold any more.");
+ player->message = pickupmsg;
+ return;
+ }
+
+ if(special->flags & MF_GIVEQUEST)
+ {
+ // [STRIFE]: Award quest flag based on the thing's speed. Quest 8 was
+ // apparently at some point given by the Broken Power Coupling, which is
+ // why they don't want to award it if you have Quest 6 (which is
+ // acquired by destroying the Front's working power coupling). BUT, the
+ // broken coupling object's speed is NOT 8... it is 512*FRACUNIT. For
+ // strict portability beyond the x86, we need to AND the operand by 31.
+ if(special->info->speed != 8 || !(player->questflags & QF_QUEST6))
+ player->questflags |= 1 << ((special->info->speed - 1) & 31);
+ }
+
+
+ // haleyjd 08/30/10: [STRIFE] No itemcount
+ //if (special->flags & MF_COUNTITEM)
+ // player->itemcount++;
+
+ P_RemoveMobj(special);
+ player->message = pickupmsg;
+ player->bonuscount += BONUSADD;
+
+ if(player == &players[consoleplayer])
+ S_StartSound(NULL, sound);
+}
+
+// villsa [STRIFE]
+static char plrkilledmsg[80];
+
+//
+// KillMobj
+//
+// [STRIFE] Major modifications for drop types, no tic randomization, etc.
+//
+void P_KillMobj(mobj_t* source, mobj_t* target)
+{
+ mobjtype_t item;
+ mobj_t* mo;
+ line_t junk;
+ int i;
+
+ // villsa [STRIFE] corpse and dropoff are removed, but why when these two flags
+ // are set a few lines later? watcom nonsense perhaps?
+ target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_BOUNCE|MF_CORPSE|MF_DROPOFF);
+
+ // villsa [STRIFE] unused
+ /*
+ if (target->type != MT_SKULL)
+ target->flags &= ~MF_NOGRAVITY;
+ */
+
+ target->flags |= MF_CORPSE|MF_DROPOFF;
+ target->height = FRACUNIT; // villsa [STRIFE] set to fracunit instead of >>= 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]++;
+
+ // villsa [STRIFE] new messages when fragging players
+ DEH_snprintf(plrkilledmsg, sizeof(plrkilledmsg),
+ "%s killed %s",
+ pnameprefixes[source->player->mo->miscdata],
+ pnameprefixes[target->player->mo->miscdata]);
+
+ if(netgame)
+ players[consoleplayer].message = plrkilledmsg;
+ }
+ }
+ 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]++;
+
+ if(gamemap == 29 && !netgame)
+ {
+ // haleyjd 09/13/10: [STRIFE] Give player the bad ending.
+ F_StartFinale();
+ return;
+ }
+
+ // villsa [STRIFE] spit out inventory items when killed
+ if(netgame)
+ {
+ int amount = 0;
+ mobj_t* loot;
+ int r = 0;
+
+ while(1)
+ {
+ if(target->player->inventory[0].amount <= 0)
+ break;
+
+ item = target->player->inventory[0].type;
+ if(item == MT_MONY_1)
+ {
+ loot = P_SpawnMobj(target->x, target->y,
+ target->z + (24*FRACUNIT), MT_MONY_25);
+
+ // [STRIFE] TODO - what the hell is it doing here?
+ loot->health = target->player->inventory[0].amount;
+ loot->health = -target->player->inventory[0].amount;
+
+ amount = target->player->inventory[0].amount;
+ }
+ else
+ {
+ loot = P_SpawnMobj(target->x, target->y,
+ target->z + (24*FRACUNIT), item);
+ amount = 1;
+ }
+
+ P_RemoveInventoryItem(target->player, 0, amount);
+ r = P_Random();
+ loot->momx += ((r & 7) - (P_Random() & 7)) << FRACBITS;
+ loot->momy += ((P_Random() & 7) + 1) << FRACBITS;
+ loot->flags |= MF_DROPPED;
+ }
+ }
+
+ target->flags &= ~MF_SOLID;
+ target->player->playerstate = PST_DEAD;
+ target->player->mo->momz = 5*FRACUNIT; // [STRIFE]: small hop!
+ P_DropWeapon(target->player);
+
+ if(target->player == &players[consoleplayer]
+ && automapactive)
+ {
+ // don't die in auto map,
+ // switch view prior to dying
+ AM_Stop ();
+ }
+
+ }
+
+ // villsa [STRIFE] some modifications to setting states
+ if(target->state != &states[S_BURN_23])
+ {
+ if(target->health == -6666)
+ P_SetMobjState(target, S_DISR_00); // 373
+ else
+ {
+ if(target->health < -target->info->spawnhealth
+ && target->info->xdeathstate)
+ P_SetMobjState(target, target->info->xdeathstate);
+ else
+ P_SetMobjState(target, target->info->deathstate);
+ }
+ }
+
+ // villsa [STRIFE] no death tics randomization
+
+ // Drop stuff.
+ // villsa [STRIFE] get item from dialog target
+ item = P_DialogFind(target->type, target->miscdata)->dropitem;
+
+ if(!item)
+ {
+ // villsa [STRIFE] drop default items
+ switch(target->type)
+ {
+ case MT_ORACLE:
+ item = MT_MEAT;
+ break;
+
+ case MT_PROGRAMMER:
+ item = MT_SIGIL_A;
+ break;
+
+ case MT_PRIEST:
+ item = MT_JUNK;
+ break;
+
+ case MT_BISHOP:
+ item = MT_AMINIBOX;
+ break;
+
+ case MT_PGUARD:
+ case MT_CRUSADER:
+ item = MT_ACELL;
+ break;
+
+ case MT_RLEADER:
+ item = MT_AAMMOBOX;
+ break;
+
+ case MT_GUARD1:
+ case MT_REBEL1:
+ case MT_SHADOWGUARD:
+ item = MT_ACLIP;
+ break;
+
+ case MT_SPECTRE_B:
+ item = MT_SIGIL_B;
+ break;
+
+ case MT_SPECTRE_C:
+ item = MT_SIGIL_C;
+ break;
+
+ case MT_SPECTRE_D:
+ item = MT_SIGIL_D;
+ break;
+
+ case MT_SPECTRE_E:
+ item = MT_SIGIL_E;
+ break;
+
+ case MT_COUPLING:
+ junk.tag = 225;
+ EV_DoDoor(&junk, close);
+
+ junk.tag = 44;
+ EV_DoFloor(&junk, lowerFloor);
+
+ GiveVoiceObjective("VOC13", "LOG13", 0);
+
+ item = MT_COUPLING_BROKEN;
+ players[0].questflags |= (1 << (mobjinfo[MT_COUPLING].speed - 1));
+ break;
+
+ default:
+ return;
+ }
+ }
+
+ // handle special case for scripted target's dropped item
+ switch(item)
+ {
+ case MT_TOKEN_SHOPCLOSE:
+ junk.tag = 222;
+ EV_DoDoor(&junk, close);
+ P_NoiseAlert(players[0].mo, players[0].mo);
+
+ sprintf(plrkilledmsg, "%s", DEH_String("You're dead! You set off the alarm."));
+ if(!deathmatch)
+ players[consoleplayer].message = plrkilledmsg;
+
+ return;
+
+ case MT_TOKEN_PRISON_PASS:
+ junk.tag = 223;
+ EV_DoDoor(&junk, open);
+ return;
+
+ case MT_TOKEN_DOOR3:
+ junk.tag = 224;
+ EV_DoDoor(&junk, open);
+ return;
+
+ case MT_SIGIL_A:
+ case MT_SIGIL_B:
+ case MT_SIGIL_C:
+ case MT_SIGIL_D:
+ case MT_SIGIL_E:
+ for(i = 0; i < MAXPLAYERS; i++)
+ {
+ if(!P_GiveWeapon(&players[i], wp_sigil, false))
+ {
+ if(players[i].sigiltype++ > 4)
+ players[i].sigiltype = 4;
+ }
+
+ // haleyjd 20110225: fixed these two assignments which Watcom munged
+ // up in the assembly by pre-incrementing the pointer into players[]
+ players[i].st_update = true;
+ players[i].pendingweapon = wp_sigil;
+ }
+ return;
+
+ case MT_TOKEN_ALARM:
+ P_NoiseAlert(players[0].mo, players[0].mo);
+
+ sprintf(plrkilledmsg, "%s", DEH_String("You Fool! You've set off the alarm"));
+ if(!deathmatch)
+ players[consoleplayer].message = plrkilledmsg;
+ return;
+
+ default:
+ break;
+ }
+
+ // villsa [STRIFE] toss out item
+ if(!deathmatch || !(mobjinfo[item].flags & MF_NOTDMATCH))
+ {
+ int r;
+
+ mo = P_SpawnMobj(target->x, target->y, target->z + (24*FRACUNIT), item);
+ r = P_Random();
+ mo->momx += ((r & 7) - (P_Random() & 7)) << FRACBITS;
+ r = P_Random();
+ mo->momy += ((r & 7) - (P_Random() & 7)) << FRACBITS;
+ mo->flags |= (MF_SPECIAL|MF_DROPPED); // special versions of items
+ }
+}
+
+//
+// P_IsMobjBoss
+//
+// villsa [STRIFE] new function
+//
+static boolean P_IsMobjBoss(mobjtype_t type)
+{
+ switch(type)
+ {
+ case MT_PROGRAMMER:
+ case MT_BISHOP:
+ case MT_RLEADER:
+ case MT_ORACLE:
+ case MT_PRIEST:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+
+//
+// P_DamageMobj
+// Damages both enemies and players
+// "inflictor" is the thing that caused the damage
+// creature or missile, can be NULL (slime, etc)
+// "source" is the thing to target after taking damage
+// creature or NULL
+// Source and inflictor are the same for melee attacks.
+// Source can be NULL for slime, barrel explosions
+// and other environmental stuff.
+//
+// [STRIFE] Extensive changes for spectrals, fire damage, disintegration, and
+// a plethora of mobjtype-specific hacks.
+//
+void P_DamageMobj(mobj_t* target, mobj_t* inflictor, mobj_t* source, int damage)
+{
+ angle_t 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;
+
+ player = target->player;
+
+ // villsa [STRIFE] unused - skullfly check (removed)
+
+ // villsa [STRIFE] handle spectral stuff
+ // notes on projectile health:
+ // -2 == enemy spectral projectile
+ // -1 == player spectral projectile
+
+ // haleyjd 20110203: refactored completely
+ if(inflictor && (inflictor->flags & MF_SPECTRAL))
+ {
+ // players aren't damaged by their own (or others???) sigils
+ // STRIFE-TODO: verify in deathmatch
+ if(target->type == MT_PLAYER && inflictor->health == -1)
+ return;
+ // enemies aren't damaged by enemy sigil attacks
+ if((target->flags & MF_SPECTRAL) && inflictor->health == -2)
+ return;
+ // Macil2, Oracle, and Spectre C cannot be damaged by Sigil A
+ switch(target->type)
+ {
+ case MT_RLEADER2:
+ case MT_ORACLE:
+ case MT_SPECTRE_C:
+ // haleyjd: added source->player validity check for safety...
+ if(source->player && source->player->sigiltype < 1)
+ return;
+ default:
+ break;
+ }
+ }
+
+ // villsa [STRIFE] new checks for various actors
+ if(inflictor)
+ {
+ // Fire damage inflictors
+ if(inflictor->type == MT_SFIREBALL ||
+ inflictor->type == MT_C_FLAME ||
+ inflictor->type == MT_PFLAME)
+ {
+ temp = damage / 2;
+
+ if(P_IsMobjBoss(target->type))
+ damage /= 2;
+ else if(inflictor->type == MT_PFLAME)
+ {
+ damage /= 2;
+ // robots take very little damage
+ if(target->flags & MF_NOBLOOD)
+ damage = temp / 2;
+ }
+ }
+ else
+ {
+ switch(inflictor->type)
+ {
+ case MT_HOOKSHOT:
+ // haleyjd 20110203: should use source, not inflictor
+ ang = R_PointToAngle2(
+ target->x,
+ target->y,
+ source->x,
+ source->y) >> ANGLETOFINESHIFT;
+
+ target->momx += FixedMul(finecosine[ang], (12750*FRACUNIT) / target->info->mass);
+ target->momy += FixedMul(finesine[ang], (12750*FRACUNIT) / target->info->mass);
+ target->reactiontime += 10;
+
+ temp = P_AproxDistance(target->x - source->x, target->y - source->y);
+ temp /= target->info->mass;
+
+ if(temp < 1)
+ temp = 1;
+
+ target->momz = (source->z - target->z) / temp;
+ break;
+
+ case MT_POISARROW:
+ // don't affect robots
+ if(target->flags & MF_NOBLOOD)
+ return;
+
+ // instant kill
+ damage = target->health + 10;
+ break;
+
+ default:
+ // Spectral retaliation, though this may in fact be unreachable
+ // since non-spectral inflictors are mostly filtered out.
+ if(target->flags & MF_SPECTRAL
+ && !(inflictor->flags & MF_SPECTRAL))
+ {
+ P_SetMobjState(target, target->info->missilestate);
+ return; // take no damage
+ }
+ break;
+ }
+ }
+ }
+
+ // villsa [STRIFE] special cases for shopkeepers and macil
+ if((target->type >= MT_SHOPKEEPER_W && target->type <= MT_SHOPKEEPER_M)
+ || target->type == MT_RLEADER)
+ {
+ if(source)
+ target->target = source;
+
+ P_SetMobjState(target, target->info->painstate);
+ return;
+ }
+
+ // villsa [STRIFE] handle fieldguard damage
+ if(target->type == MT_FIELDGUARD)
+ {
+ // degnin ores are only allowed to damage the fieldguard
+ if(!inflictor || inflictor->type != MT_DEGNINORE)
+ return;
+
+ damage = target->health;
+ }
+
+ 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_flame))
+ {
+ 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.
+ // villsa [STRIFE] removed pw_invulnerability check
+ if(damage < 1000 && (player->cheats & CF_GODMODE))
+ return;
+
+ // villsa [STRIFE] flame attacks don't damage player if wearing envirosuit
+ if(player->powers[pw_ironfeet] && inflictor)
+ {
+ if(inflictor->type == MT_SFIREBALL ||
+ inflictor->type == MT_C_FLAME ||
+ inflictor->type == MT_PFLAME)
+ {
+ damage = 0;
+ }
+ }
+
+ 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;
+
+ // villsa [STRIFE]
+ P_UseInventoryItem(player, SPR_ARM1);
+ P_UseInventoryItem(player, SPR_ARM2);
+ }
+ player->armorpoints -= saved;
+ damage -= saved;
+ }
+ player->health -= damage; // mirror mobj health here for Dave
+
+ // [STRIFE] haleyjd 20130302: bug fix - this is *not* capped here.
+ //if(player->health < 0)
+ // player->health = 0;
+
+ player->attacker = source;
+ player->damagecount += damage; // add damage after armor / invuln
+
+ // haleyjd 20110203 [STRIFE]: target->target set here
+ if(target != source)
+ target->target = source;
+
+ 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;
+
+ // villsa [STRIFE] auto use medkits
+ if(player && player->health < 50)
+ {
+ if(deathmatch || player->cheats & CF_AUTOHEALTH)
+ {
+ while(player->health < 50 && P_UseInventoryItem(player, SPR_MDKT));
+ while(player->health < 50 && P_UseInventoryItem(player, SPR_STMP));
+ }
+ }
+
+
+ if(target->health <= 0)
+ {
+ // villsa [STRIFE] grenades hurt... OUCH
+ if(inflictor && inflictor->type == MT_HEGRENADE)
+ target->health = -target->info->spawnhealth;
+ else if(!(target->flags & MF_NOBLOOD))
+ {
+ // villsa [STRIFE] disintegration death
+ if(inflictor &&
+ (inflictor->type == MT_STRIFEPUFF3 ||
+ inflictor->type == MT_L_LASER ||
+ inflictor->type == MT_TORPEDO ||
+ inflictor->type == MT_TORPEDOSPREAD))
+ {
+ S_StartSound(target, sfx_dsrptr);
+ target->health = -6666;
+ }
+ }
+
+ // villsa [STRIFE] flame death stuff
+ if(!(target->flags & MF_NOBLOOD)
+ && inflictor
+ && (inflictor->type == MT_SFIREBALL ||
+ inflictor->type == MT_C_FLAME ||
+ inflictor->type == MT_PFLAME))
+ {
+ target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SHADOW|MF_MVIS);
+ if(target->player)
+ {
+ target->player->cheats |= CF_ONFIRE;
+ target->player->powers[pw_communicator] = false;
+ target->player->readyweapon = 0;
+ P_SetPsprite(target->player, ps_weapon, S_WAVE_00); // 02
+ P_SetPsprite(target->player, ps_flash, S_NULL);
+ }
+
+ P_SetMobjState(target, S_BURN_00); // 349
+ S_StartSound(target, sfx_burnme);
+
+ return;
+ }
+
+ P_KillMobj(source, target);
+ return;
+ }
+
+ // villsa [STRIFE] set crash state
+ if(target->health <= 6 && target->info->crashstate)
+ {
+ P_SetMobjState(target, target->info->crashstate);
+ return;
+ }
+
+ if(damage)
+ {
+ // villsa [STRIFE] removed unused skullfly flag
+ if(P_Random() < target->info->painchance)
+ {
+ target->flags |= MF_JUSTHIT; // fight back!
+ P_SetMobjState (target, target->info->painstate);
+ }
+ }
+
+ target->reactiontime = 0; // we're awake now...
+
+ // villsa [STRIFE] new checks for thing types
+ if (target->type != MT_PROGRAMMER
+ && (!target->threshold || target->type == MT_ENTITY)
+ && source && source != target
+ && source->type != MT_ENTITY
+ && ((source->flags & MF_ALLY) != (target->flags & MF_ALLY)))
+ {
+ // 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);
+ }
+}
+
diff --git a/src/strife/p_inter.h b/src/strife/p_inter.h
new file mode 100644
index 00000000..1ddf4498
--- /dev/null
+++ b/src/strife/p_inter.h
@@ -0,0 +1,40 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+//
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __P_INTER__
+#define __P_INTER__
+
+// haleyjd [STRIFE]: Multiple externals added
+boolean P_GiveCard(player_t* player, card_t card);
+boolean P_GiveBody(player_t* player, int num);
+boolean P_GiveArmor(player_t* player, int armortype);
+boolean P_GivePower(player_t* player, powertype_t power);
+boolean P_GiveAmmo(player_t* player, ammotype_t ammo, int num);
+boolean P_GiveWeapon(player_t* player, weapontype_t weapon, boolean dropped);
+void P_KillMobj(mobj_t* source, mobj_t* target);
+
+#endif
diff --git a/src/strife/p_lights.c b/src/strife/p_lights.c
new file mode 100644
index 00000000..1b5e1d8c
--- /dev/null
+++ b/src/strife/p_lights.c
@@ -0,0 +1,380 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Handle Sector base lighting effects.
+// Muzzle flash?
+//
+//-----------------------------------------------------------------------------
+
+
+
+#include "z_zone.h"
+#include "m_random.h"
+
+#include "doomdef.h"
+#include "p_local.h"
+
+
+// State.
+#include "r_state.h"
+
+//
+// FIRELIGHT FLICKER
+//
+
+//
+// T_FireFlicker
+//
+// [STRIFE]
+// haleyjd 2011023: Changes to amount and duration of flicker
+//
+void T_FireFlicker (fireflicker_t* flick)
+{
+ int amount;
+
+ if (--flick->count)
+ return;
+
+ amount = (P_Random() & 3) * 8; // [STRIFE] 16 -> 8
+
+ if (flick->sector->lightlevel - amount < flick->minlight)
+ flick->sector->lightlevel = flick->minlight;
+ else
+ flick->sector->lightlevel = flick->maxlight - amount;
+
+ // [STRIFE] flicker count made random!
+ flick->count = (P_Random() & 3) + 1;
+}
+
+
+
+//
+// P_SpawnFireFlicker
+//
+// [STRIFE]
+// haleyjd 2011023: Changes to minimum light level and initial duration
+//
+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 = sector->lightlevel - 32; // [STRIFE] changed from min surrounding+16
+ flick->count = 2; // [STRIFE]: Initial count 4 -> 2
+}
+
+
+
+//
+// BROKEN LIGHT FLASHING
+//
+
+
+//
+// T_LightFlash
+// Do flashing lights.
+//
+// [STRIFE] Verified unmodified
+//
+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
+//
+// [STRIFE] Verified unmodified
+//
+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
+//
+// [STRIFE] Verified unmodified
+//
+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
+//
+// [STRIFE] Verified unmodified
+//
+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)
+//
+// [STRIFE] Verified unmodified
+//
+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
+//
+// [STRIFE] Verified unmodified
+//
+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
+//
+// [STRIFE] Verified unmodified
+//
+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
+//
+// [STRIFE] Verified unmodified
+//
+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;
+ }
+}
+
+//
+// [STRIFE] Verified unmodified
+//
+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;
+}
+
diff --git a/src/strife/p_local.h b/src/strife/p_local.h
new file mode 100644
index 00000000..096b8b6c
--- /dev/null
+++ b/src/strife/p_local.h
@@ -0,0 +1,309 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Play functions, animation, global header.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __P_LOCAL__
+#define __P_LOCAL__
+
+#ifndef __R_LOCAL__
+#include "r_local.h"
+#endif
+
+#define FLOATSPEED (FRACUNIT*5) // villsa [STRIFE] change to 5 (was 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 PLAYERMELEERANGE (80*FRACUNIT) // haleyjd [STRIFE] New constant
+#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
+//
+
+// haleyjd 09/15/10: externalized
+#define INVERSECOLORMAP 32
+
+void P_PlayerThink (player_t* player);
+// haleyjd 08/30/10: [STRIFE] Needed externally
+void P_Thrust (player_t* player, angle_t angle, fixed_t move);
+// villsa [STRIFE]
+char* P_RemoveInventoryItem(player_t *player, int slot, int amount);
+
+
+//
+// P_MOBJ
+//
+#define ONFLOORZ INT_MIN
+#define ONCEILINGZ INT_MAX
+
+// 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);
+mobj_t* P_SubstNullMobj (mobj_t* th);
+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);
+mobj_t* P_SpawnSparkPuff(fixed_t x, fixed_t y, fixed_t z); // villsa [STRIFE]
+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);
+mobj_t* P_SpawnFacingMissile(mobj_t* source, mobj_t* target, mobjtype_t type); // villsa [STRIFE]
+mobj_t* P_SpawnPlayerMissile(mobj_t* source, mobjtype_t type);
+mobj_t* P_SpawnMortar(mobj_t *source, mobjtype_t type); // villsa [STRIFE]
+void P_ExplodeMissile (mobj_t* mo); // villsa [STRIFE]
+
+
+//
+// P_ENEMY
+//
+void P_NoiseAlert (mobj_t* target, mobj_t* emmiter);
+void P_DoPunchAlert(mobj_t *puncher, mobj_t *punchee); // villsa [STRIFE]
+void A_BodyParts(mobj_t *actor); // haleyjd: [STRIFE]
+void A_AlertSpectreC(mobj_t* actor);
+void A_FaceTarget (mobj_t* actor);
+void P_FreePrisoners(void);
+void P_DestroyConverter(void);
+
+//
+// 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
+ boolean isaline;
+ union {
+ mobj_t* thing;
+ line_t* line;
+ } d;
+} intercept_t;
+
+// Extended MAXINTERCEPTS, to allow for intercepts overrun emulation.
+
+#define MAXINTERCEPTS_ORIGINAL 128
+#define MAXINTERCEPTS (MAXINTERCEPTS_ORIGINAL + 61)
+
+extern intercept_t intercepts[MAXINTERCEPTS];
+extern intercept_t* intercept_p;
+
+typedef 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);
+
+boolean P_BlockLinesIterator (int x, int y, boolean(*func)(line_t*) );
+boolean P_BlockThingsIterator (int x, int y, boolean(*func)(mobj_t*) );
+
+#define PT_ADDLINES 1
+#define PT_ADDTHINGS 2
+#define PT_EARLYOUT 4
+
+extern divline_t trace;
+
+boolean
+P_PathTraverse
+( fixed_t x1,
+ fixed_t y1,
+ fixed_t x2,
+ fixed_t y2,
+ int flags,
+ 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 boolean floatok;
+extern fixed_t tmfloorz;
+extern fixed_t tmceilingz;
+
+extern line_t *ceilingline;
+extern line_t *blockingline; // [STRIFE] New global
+
+boolean P_CheckPosition (mobj_t *thing, fixed_t x, fixed_t y);
+boolean P_TryMove (mobj_t* thing, fixed_t x, fixed_t y);
+boolean P_CheckPositionZ(mobj_t* thing, fixed_t z); // villsa [STRIFE]
+boolean P_TeleportMove (mobj_t* thing, fixed_t x, fixed_t y);
+void P_SlideMove (mobj_t* mo);
+boolean P_CheckSight (mobj_t* t1, mobj_t* t2);
+void P_UseLines (player_t* player);
+
+boolean P_ChangeSector (sector_t* sector, boolean crunch);
+
+extern mobj_t* linetarget; // who got hit (or NULL)
+
+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__
diff --git a/src/strife/p_map.c b/src/strife/p_map.c
new file mode 100644
index 00000000..322e479b
--- /dev/null
+++ b/src/strife/p_map.c
@@ -0,0 +1,1655 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard, Andrey Budko
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Movement, collision handling.
+// Shooting and aiming.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "deh_misc.h"
+
+#include "m_bbox.h"
+#include "m_random.h"
+#include "i_system.h"
+
+#include "doomdef.h"
+#include "m_argv.h"
+#include "m_misc.h"
+#include "p_local.h"
+
+#include "s_sound.h"
+
+// State.
+#include "doomstat.h"
+#include "r_state.h"
+// Data.
+#include "sounds.h"
+
+// Spechit overrun magic value.
+//
+// This is the value used by PrBoom-plus. I think the value below is
+// actually better and works with more demos. However, I think
+// it's better for the spechits emulation to be compatible with
+// PrBoom-plus, at least so that the big spechits emulation list
+// on Doomworld can also be used with Chocolate Doom.
+
+#define DEFAULT_SPECHIT_MAGIC 0x01C09C98
+
+// This is from a post by myk on the Doomworld forums,
+// outputted from entryway's spechit_magic generator for
+// s205n546.lmp. The _exact_ value of this isn't too
+// important; as long as it is in the right general
+// range, it will usually work. Otherwise, we can use
+// the generator (hacked doom2.exe) and provide it
+// with -spechit.
+
+//#define DEFAULT_SPECHIT_MAGIC 0x84f968e8
+
+
+fixed_t tmbbox[4];
+mobj_t* tmthing;
+int tmflags;
+fixed_t tmx;
+fixed_t tmy;
+
+
+// If "floatok" true, move would be ok
+// if within "tmfloorz - tmceilingz".
+boolean floatok;
+
+fixed_t tmfloorz;
+fixed_t tmceilingz;
+fixed_t tmdropoffz;
+
+// keep track of the line that lowers the ceiling,
+// so missiles don't explode against sky hack walls
+line_t* ceilingline;
+
+// haleyjd 20110203: [STRIFE] New global
+// "blockingline" tracks the linedef responsible for blocking motion of an mobj
+// for purposes of doing impact special activation by missiles. Suspiciously
+// similar to the solution used by Raven in Heretic and Hexen.
+line_t *blockingline;
+
+// keep track of special lines as they are hit,
+// but don't process them until the move is proven valid
+
+// fraggle: I have increased the size of this buffer. In the original Doom,
+// overrunning past this limit caused other bits of memory to be overwritten,
+// affecting demo playback. However, in doing so, the limit was still
+// exceeded. So we have to support more than 8 specials.
+//
+// We keep the original limit, to detect what variables in memory were
+// overwritten (see SpechitOverrun())
+
+#define MAXSPECIALCROSS 20
+#define MAXSPECIALCROSS_ORIGINAL 8
+
+line_t* spechit[MAXSPECIALCROSS];
+int numspechit;
+
+
+
+//
+// TELEPORT MOVE
+//
+
+//
+// PIT_StompThing
+//
+// [STRIFE] haleyjd 09/15/10: Modified so monsters can telestomp.
+//
+boolean PIT_StompThing (mobj_t* thing)
+{
+ fixed_t blockdist;
+
+ if (!(thing->flags & MF_SHOOTABLE) )
+ return true;
+
+ blockdist = thing->radius + tmthing->radius;
+
+ if ( abs(thing->x - tmx) >= blockdist
+ || abs(thing->y - tmy) >= blockdist )
+ {
+ // didn't hit it
+ return true;
+ }
+
+ // don't clip against self
+ if (thing == tmthing)
+ return true;
+
+ // [STRIFE] monsters DO stomp things, on all levels
+ // Basically, one thing involved must be a player.
+ // Monsters can telefrag players, and players can telefrag monsters, but
+ // monsters cannot telefrag other monsters.
+ if (!(tmthing->player || thing->player))
+ return false;
+
+ P_DamageMobj (thing, tmthing, tmthing, 10000);
+
+ return true;
+}
+
+
+//
+// P_TeleportMove
+//
+// [STRIFE]
+// haleyjd 09/15/10: Modified to set thing z position.
+//
+boolean P_TeleportMove(mobj_t* thing, fixed_t x, fixed_t y)
+{
+ int xl;
+ int xh;
+ int yl;
+ int yh;
+ int bx;
+ int by;
+
+ subsector_t* newsubsec;
+
+ // kill anything occupying the position
+ tmthing = thing;
+ tmflags = thing->flags;
+
+ tmx = x;
+ tmy = y;
+
+ tmbbox[BOXTOP] = y + tmthing->radius;
+ tmbbox[BOXBOTTOM] = y - tmthing->radius;
+ tmbbox[BOXRIGHT] = x + tmthing->radius;
+ tmbbox[BOXLEFT] = x - tmthing->radius;
+
+ newsubsec = R_PointInSubsector (x,y);
+ ceilingline = NULL;
+
+ // The base floor/ceiling is from the subsector
+ // that contains the point.
+ // Any contacted lines the step closer together
+ // will adjust them.
+ tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
+ tmceilingz = newsubsec->sector->ceilingheight;
+
+ validcount++;
+ numspechit = 0;
+
+ // stomp on any things contacted
+ xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
+ xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
+ yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
+ yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
+
+ for (bx=xl ; bx<=xh ; bx++)
+ for (by=yl ; by<=yh ; by++)
+ if (!P_BlockThingsIterator(bx,by,PIT_StompThing))
+ return false;
+
+ // the move is ok,
+ // so link the thing into its new position
+ P_UnsetThingPosition (thing);
+
+ thing->floorz = tmfloorz;
+ thing->ceilingz = tmceilingz;
+ thing->x = x;
+ thing->y = y;
+ thing->z = tmfloorz; // haleyjd 09/15/10: [STRIFE] Rogue added a z-set here
+
+ P_SetThingPosition (thing);
+
+ return true;
+}
+
+
+//
+// MOVEMENT ITERATOR FUNCTIONS
+//
+
+static void SpechitOverrun(line_t *ld);
+
+//
+// PIT_CheckLine
+// Adjusts tmfloorz and tmceilingz as lines are contacted
+//
+boolean PIT_CheckLine (line_t* ld)
+{
+ if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT]
+ || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
+ || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM]
+ || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP] )
+ return true;
+
+ if (P_BoxOnLineSide (tmbbox, ld) != -1)
+ return true;
+
+ // A line has been hit
+
+ // The moving thing's destination position will cross
+ // the given line.
+ // If this should not be allowed, return false.
+ // If the line is special, keep track of it
+ // to process later if the move is proven ok.
+ // NOTE: specials are NOT sorted by order,
+ // so two special lines that are only 8 pixels apart
+ // could be crossed in either order.
+
+ if (!ld->backsector)
+ return false; // one sided line
+
+ if (!(tmthing->flags & MF_MISSILE) )
+ {
+ // villsa [STRIFE] include jumpover flag
+ if ( ld->flags & ML_BLOCKING &&
+ (!(ld->flags & ML_JUMPOVER) || tmfloorz + (32*FRACUNIT) > tmthing->z) )
+ return false; // explicitly blocking everything
+
+ // villsa [STRIFE] exclude floaters from blockmonster lines
+ if ( !tmthing->player && (ld->flags & ML_BLOCKMONSTERS) &&
+ !(tmthing->flags & MF_FLOAT))
+ return false; // block monsters only
+
+ // villsa [STRIFE]
+ if ( ld->flags & ML_BLOCKFLOATERS && tmthing->flags & MF_FLOAT )
+ return false; // block floaters only
+ }
+
+ // set openrange, opentop, openbottom
+ P_LineOpening (ld);
+
+ // adjust floor / ceiling heights
+ if (opentop < tmceilingz)
+ {
+ tmceilingz = opentop;
+ ceilingline = ld;
+ }
+
+ if (openbottom > tmfloorz)
+ tmfloorz = openbottom;
+
+ if (lowfloor < tmdropoffz)
+ tmdropoffz = lowfloor;
+
+ // if contacted a special line, add it to the list
+ if (ld->special)
+ {
+ spechit[numspechit] = ld;
+ numspechit++;
+
+ // fraggle: spechits overrun emulation code from prboom-plus
+ if (numspechit > MAXSPECIALCROSS_ORIGINAL)
+ {
+ SpechitOverrun(ld);
+ }
+ }
+
+ return true;
+}
+
+//
+// PIT_CheckThing
+//
+boolean PIT_CheckThing (mobj_t* thing)
+{
+ fixed_t blockdist;
+ boolean solid;
+ int damage;
+
+ if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_SHOOTABLE) ))
+ return true;
+
+ // don't clip against self
+ if (thing == tmthing)
+ return true;
+
+ blockdist = thing->radius + tmthing->radius;
+
+ if ( abs(thing->x - tmx) >= blockdist
+ || abs(thing->y - tmy) >= blockdist )
+ {
+ // didn't hit it
+ return true;
+ }
+
+ // villsa [STRIFE] see if it went over / under
+ if(thing->height + thing->z < tmthing->z)
+ return true; // overhead
+
+ // villsa [STRIFE] see if it went over / under
+ if (tmthing->z + tmthing->height < thing->z)
+ return true; // underneath
+
+ // villsa [STRIFE] unused
+ // check for skulls slamming into things (removed)
+
+ // missiles can hit other things
+ if (tmthing->flags & MF_MISSILE)
+ {
+ // villsa [STRIFE] code to check over/under clipping moved to the beginning of the
+ // function, so that it applies to everything.
+
+ // villsa [STRIFE] updated to strife version
+ if (tmthing->target && (tmthing->target->type == thing->type))
+ {
+ // Don't hit same species as originator.
+ if (thing == tmthing->target)
+ return true;
+
+ // sdh: Add deh_species_infighting here. We can override the
+ // "monsters of the same species cant hurt each other" behavior
+ // through dehacked patches
+
+ if (thing->type != MT_PLAYER && !deh_species_infighting)
+ {
+ // Explode, but do no damage.
+ // Let players missile other players.
+ return false;
+ }
+ }
+
+ if (!(thing->flags & MF_SHOOTABLE))
+ {
+ // didn't do any damage
+ return !(thing->flags & MF_SOLID);
+ }
+
+ // haleyjd 09/01/10: [STRIFE] Spectral check:
+ // Missiles cannot hit SPECTRAL entities unless the missiles are also
+ // flagged as SPECTRAL.
+ if (thing->flags & MF_SPECTRAL && !(tmthing->flags & MF_SPECTRAL))
+ return true; // keep going
+
+ // damage / explode
+ // haleyjd 09/01/10: [STRIFE] Modified missile damage formula
+ damage = ((P_Random()&3)+1)*tmthing->info->damage;
+ P_DamageMobj (thing, tmthing, tmthing->target, damage);
+
+ // don't traverse any more
+ return false;
+ }
+
+ // check for special pickup
+ if (thing->flags & MF_SPECIAL)
+ {
+ solid = thing->flags&MF_SOLID;
+ if (tmthing->player) // villsa [STRIFE] no longer checks MF_PICKUP flag
+ {
+ // can remove thing
+ P_TouchSpecialThing (thing, tmthing);
+ }
+ return !solid;
+ }
+
+ return !(thing->flags & MF_SOLID);
+}
+
+
+//
+// MOVEMENT CLIPPING
+//
+
+//
+// P_CheckPosition
+// This is purely informative, nothing is modified
+// (except things picked up).
+//
+// in:
+// a mobj_t (can be valid or invalid)
+// a position to be checked
+// (doesn't need to be related to the mobj_t->x,y)
+//
+// during:
+// special things are touched if MF_PICKUP
+// early out on solid lines?
+//
+// out:
+// newsubsec
+// floorz
+// ceilingz
+// tmdropoffz
+// the lowest point contacted
+// (monsters won't move to a dropoff)
+// speciallines[]
+// numspeciallines
+//
+// haleyjd 20110203:
+// [STRIFE] Modified to clear blockingline in advance of P_BlockLinesIterator
+//
+boolean
+P_CheckPosition
+( mobj_t* thing,
+ fixed_t x,
+ fixed_t y )
+{
+ int xl;
+ int xh;
+ int yl;
+ int yh;
+ int bx;
+ int by;
+ subsector_t* newsubsec;
+
+ tmthing = thing;
+ tmflags = thing->flags;
+
+ tmx = x;
+ tmy = y;
+
+ tmbbox[BOXTOP] = y + tmthing->radius;
+ tmbbox[BOXBOTTOM] = y - tmthing->radius;
+ tmbbox[BOXRIGHT] = x + tmthing->radius;
+ tmbbox[BOXLEFT] = x - tmthing->radius;
+
+ newsubsec = R_PointInSubsector (x,y);
+
+ // [STRIFE] clear blockingline (see P_XYMovement, P_BlockLinesIterator)
+ blockingline = NULL;
+ ceilingline = NULL;
+
+ // The base floor / ceiling is from the subsector
+ // that contains the point.
+ // Any contacted lines the step closer together
+ // will adjust them.
+ tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
+ tmceilingz = newsubsec->sector->ceilingheight;
+
+ validcount++;
+ numspechit = 0;
+
+ if ( tmflags & MF_NOCLIP )
+ return true;
+
+ // Check things first, possibly picking things up.
+ // The bounding box is extended by MAXRADIUS
+ // because mobj_ts are grouped into mapblocks
+ // based on their origin point, and can overlap
+ // into adjacent blocks by up to MAXRADIUS units.
+ xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
+ xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
+ yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
+ yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
+
+ for (bx=xl ; bx<=xh ; bx++)
+ for (by=yl ; by<=yh ; by++)
+ if (!P_BlockThingsIterator(bx,by,PIT_CheckThing))
+ return false;
+
+ // check lines
+ xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT;
+ xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT;
+ yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT;
+ yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT;
+
+ for (bx=xl ; bx<=xh ; bx++)
+ for (by=yl ; by<=yh ; by++)
+ if (!P_BlockLinesIterator (bx,by,PIT_CheckLine))
+ return false;
+
+ return true;
+}
+
+
+//
+// P_TryMove
+// Attempt to move to a new position,
+// crossing special lines unless MF_TELEPORT is set.
+//
+boolean
+P_TryMove
+( mobj_t* thing,
+ fixed_t x,
+ fixed_t y )
+{
+ fixed_t oldx;
+ fixed_t oldy;
+ int side;
+ int oldside;
+ line_t* ld;
+
+ floatok = false;
+ if (!P_CheckPosition (thing, x, y))
+ return false; // solid wall or thing
+
+ if ( !(thing->flags & MF_NOCLIP) )
+ {
+ if (tmceilingz - tmfloorz < thing->height)
+ return false; // doesn't fit
+
+ floatok = true;
+
+ // villsa [STRIFE] Removed MF_TELEPORT
+ if (tmceilingz - thing->z < thing->height)
+ return false; // mobj must lower itself to fit
+
+ // villsa [STRIFE] non-robots are limited to 16 unit step height
+ if ((thing->flags & MF_NOBLOOD) == 0 && tmfloorz - thing->z > (16*FRACUNIT))
+ return false;
+ if (tmfloorz - thing->z > 24*FRACUNIT)
+ return false; // too big a step up
+
+ // villsa [STRIFE] special case for missiles
+ if((thing->flags & MF_MISSILE) && tmfloorz - thing->z > 4*FRACUNIT)
+ return false;
+
+ // haleyjd 20110204 [STRIFE]: dropoff height changed 24 -> 32
+ if ( !(thing->flags&(MF_DROPOFF|MF_FLOAT))
+ && tmfloorz - tmdropoffz > 32*FRACUNIT )
+ return false; // don't stand over a dropoff
+ }
+
+ // the move is ok,
+ // so link the thing into its new position
+ P_UnsetThingPosition (thing);
+
+ oldx = thing->x;
+ oldy = thing->y;
+ thing->floorz = tmfloorz;
+ thing->ceilingz = tmceilingz;
+ thing->x = x;
+ thing->y = y;
+
+ P_SetThingPosition (thing);
+
+ // if any special lines were hit, do the effect
+ if (! (thing->flags&MF_NOCLIP) ) // villsa [STRIFE] MF_TELEPORT not used
+ {
+ while (numspechit--)
+ {
+ // see if the line was crossed
+ ld = spechit[numspechit];
+ side = P_PointOnLineSide (thing->x, thing->y, ld);
+ oldside = P_PointOnLineSide (oldx, oldy, ld);
+ if (side != oldside)
+ {
+ if (ld->special)
+ P_CrossSpecialLine (ld-lines, oldside, thing);
+ }
+ }
+ }
+
+ return true;
+}
+
+//
+// P_CheckPositionZ
+//
+// villsa [STRIFE] new function
+// Check colliding things on top of one another; ie., 3D Object Clipping
+//
+boolean P_CheckPositionZ(mobj_t* thing, fixed_t height)
+{
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ int xl;
+ int xh;
+ int yl;
+ int yh;
+ int bx;
+ int by;
+ subsector_t* newsubsec;
+
+ x = thing->x;
+ y = thing->y;
+ z = thing->z;
+
+ thing->z = height;
+
+ tmthing = thing;
+ tmflags = thing->flags;
+ tmx = x;
+ tmy = y;
+
+ tmbbox[BOXTOP] = y + tmthing->radius;
+ tmbbox[BOXBOTTOM] = y - tmthing->radius;
+ tmbbox[BOXRIGHT] = x + tmthing->radius;
+ tmbbox[BOXLEFT] = x - tmthing->radius;
+
+ ceilingline = 0;
+ newsubsec = thing->subsector;
+
+ // The base floor / ceiling is from the subsector
+ // that contains the point.
+ // Any contacted lines the step closer together
+ // will adjust them.
+
+ tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
+ tmceilingz = newsubsec->sector->ceilingheight;
+
+ if(tmflags & MF_NOCLIP)
+ return true;
+
+ // Check things first, possibly picking things up.
+ // The bounding box is extended by MAXRADIUS
+ // because mobj_ts are grouped into mapblocks
+ // based on their origin point, and can overlap
+ // into adjacent blocks by up to MAXRADIUS units.
+
+ xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
+ xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
+ yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
+ yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
+
+ for(bx = xl; bx <= xh; bx++)
+ {
+ for(by = yl; by <= yh; by++)
+ {
+ if(!P_BlockThingsIterator(bx, by, PIT_CheckThing))
+ {
+ tmthing->z = z;
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+
+//
+// P_ThingHeightClip
+// Takes a valid thing and adjusts the thing->floorz,
+// thing->ceilingz, and possibly thing->z.
+// This is called for all nearby monsters
+// whenever a sector changes height.
+// If the thing doesn't fit,
+// the z will be set to the lowest value
+// and false will be returned.
+//
+// [STRIFE] Verified unmodified
+//
+boolean P_ThingHeightClip (mobj_t* thing)
+{
+ boolean onfloor;
+
+ onfloor = (thing->z == thing->floorz);
+
+ P_CheckPosition (thing, thing->x, thing->y);
+ // what about stranding a monster partially off an edge?
+
+ thing->floorz = tmfloorz;
+ thing->ceilingz = tmceilingz;
+
+ if (onfloor)
+ {
+ // walking monsters rise and fall with the floor
+ thing->z = thing->floorz;
+ }
+ else
+ {
+ // don't adjust a floating monster unless forced to
+ if (thing->z+thing->height > thing->ceilingz)
+ thing->z = thing->ceilingz - thing->height;
+ }
+
+ if (thing->ceilingz - thing->floorz < thing->height)
+ return false;
+
+ return true;
+}
+
+
+
+//
+// SLIDE MOVE
+// Allows the player to slide along any angled walls.
+//
+fixed_t bestslidefrac;
+fixed_t secondslidefrac;
+
+line_t* bestslideline;
+line_t* secondslideline;
+
+mobj_t* slidemo;
+
+fixed_t tmxmove;
+fixed_t tmymove;
+
+
+
+//
+// P_HitSlideLine
+// Adjusts the xmove / ymove
+// so that the next move will slide along the wall.
+//
+// [STRIFE] Verified unmodified
+//
+void P_HitSlideLine (line_t* ld)
+{
+ int side;
+
+ angle_t lineangle;
+ angle_t moveangle;
+ angle_t deltaangle;
+
+ fixed_t movelen;
+ fixed_t newlen;
+
+
+ if (ld->slopetype == ST_HORIZONTAL)
+ {
+ tmymove = 0;
+ return;
+ }
+
+ if (ld->slopetype == ST_VERTICAL)
+ {
+ tmxmove = 0;
+ return;
+ }
+
+ side = P_PointOnLineSide (slidemo->x, slidemo->y, ld);
+
+ lineangle = R_PointToAngle2 (0,0, ld->dx, ld->dy);
+
+ if (side == 1)
+ lineangle += ANG180;
+
+ moveangle = R_PointToAngle2 (0,0, tmxmove, tmymove);
+ deltaangle = moveangle-lineangle;
+
+ if (deltaangle > ANG180)
+ deltaangle += ANG180;
+ // I_Error ("SlideLine: ang>ANG180");
+
+ lineangle >>= ANGLETOFINESHIFT;
+ deltaangle >>= ANGLETOFINESHIFT;
+
+ movelen = P_AproxDistance (tmxmove, tmymove);
+ newlen = FixedMul (movelen, finecosine[deltaangle]);
+
+ tmxmove = FixedMul (newlen, finecosine[lineangle]);
+ tmymove = FixedMul (newlen, finesine[lineangle]);
+}
+
+
+//
+// PTR_SlideTraverse
+//
+// [STRIFE] Modified for smaller step-up height
+//
+boolean PTR_SlideTraverse (intercept_t* in)
+{
+ line_t* li;
+
+ if (!in->isaline)
+ I_Error ("PTR_SlideTraverse: not a line?");
+
+ li = in->d.line;
+
+ if ( ! (li->flags & ML_TWOSIDED) )
+ {
+ if (P_PointOnLineSide (slidemo->x, slidemo->y, li))
+ {
+ // don't hit the back side
+ return true;
+ }
+ goto isblocking;
+ }
+
+ // set openrange, opentop, openbottom
+ P_LineOpening (li);
+
+ if (openrange < slidemo->height)
+ goto isblocking; // doesn't fit
+
+ if (opentop - slidemo->z < slidemo->height)
+ goto isblocking; // mobj is too high
+
+ // villsa [STRIFE] change from 24 to 16
+ if (openbottom - slidemo->z > 16*FRACUNIT )
+ goto isblocking; // too big a step up
+
+ // this line doesn't block movement
+ return true;
+
+ // the line does block movement,
+ // see if it is closer than best so far
+isblocking:
+ if (in->frac < bestslidefrac)
+ {
+ secondslidefrac = bestslidefrac;
+ secondslideline = bestslideline;
+ bestslidefrac = in->frac;
+ bestslideline = li;
+ }
+
+ return false; // stop
+}
+
+
+
+//
+// P_SlideMove
+// The momx / momy move is bad, so try to slide
+// along a wall.
+// Find the first line hit, move flush to it,
+// and slide along it
+//
+// This is a kludgy mess.
+//
+// [STRIFE] Verified unmodified
+//
+void P_SlideMove (mobj_t* mo)
+{
+ fixed_t leadx;
+ fixed_t leady;
+ fixed_t trailx;
+ fixed_t traily;
+ fixed_t newx;
+ fixed_t newy;
+ int hitcount;
+
+ slidemo = mo;
+ hitcount = 0;
+
+retry:
+ if (++hitcount == 3)
+ goto stairstep; // don't loop forever
+
+ // trace along the three leading corners
+ if (mo->momx > 0)
+ {
+ leadx = mo->x + mo->radius;
+ trailx = mo->x - mo->radius;
+ }
+ else
+ {
+ leadx = mo->x - mo->radius;
+ trailx = mo->x + mo->radius;
+ }
+
+ if (mo->momy > 0)
+ {
+ leady = mo->y + mo->radius;
+ traily = mo->y - mo->radius;
+ }
+ else
+ {
+ leady = mo->y - mo->radius;
+ traily = mo->y + mo->radius;
+ }
+
+ bestslidefrac = FRACUNIT+1;
+
+ P_PathTraverse ( leadx, leady, leadx+mo->momx, leady+mo->momy,
+ PT_ADDLINES, PTR_SlideTraverse );
+ P_PathTraverse ( trailx, leady, trailx+mo->momx, leady+mo->momy,
+ PT_ADDLINES, PTR_SlideTraverse );
+ P_PathTraverse ( leadx, traily, leadx+mo->momx, traily+mo->momy,
+ PT_ADDLINES, PTR_SlideTraverse );
+
+ // move up to the wall
+ if (bestslidefrac == FRACUNIT+1)
+ {
+ // the move most have hit the middle, so stairstep
+stairstep:
+ if (!P_TryMove (mo, mo->x, mo->y + mo->momy))
+ P_TryMove (mo, mo->x + mo->momx, mo->y);
+ return;
+ }
+
+ // fudge a bit to make sure it doesn't hit
+ bestslidefrac -= 0x800;
+ if (bestslidefrac > 0)
+ {
+ newx = FixedMul (mo->momx, bestslidefrac);
+ newy = FixedMul (mo->momy, bestslidefrac);
+
+ if (!P_TryMove (mo, mo->x+newx, mo->y+newy))
+ goto stairstep;
+ }
+
+ // Now continue along the wall.
+ // First calculate remainder.
+ bestslidefrac = FRACUNIT-(bestslidefrac+0x800);
+
+ if (bestslidefrac > FRACUNIT)
+ bestslidefrac = FRACUNIT;
+
+ if (bestslidefrac <= 0)
+ return;
+
+ tmxmove = FixedMul (mo->momx, bestslidefrac);
+ tmymove = FixedMul (mo->momy, bestslidefrac);
+
+ P_HitSlideLine (bestslideline); // clip the moves
+
+ mo->momx = tmxmove;
+ mo->momy = tmymove;
+
+ if (!P_TryMove (mo, mo->x+tmxmove, mo->y+tmymove))
+ {
+ goto retry;
+ }
+}
+
+
+//
+// P_LineAttack
+//
+mobj_t* linetarget; // who got hit (or NULL)
+mobj_t* shootthing;
+
+// Height if not aiming up or down
+// ???: use slope for monsters?
+fixed_t shootz;
+
+int la_damage;
+fixed_t attackrange;
+
+fixed_t aimslope;
+
+// slopes to top and bottom of target
+extern fixed_t topslope;
+extern fixed_t bottomslope;
+
+
+//
+// PTR_AimTraverse
+// Sets linetaget and aimslope when a target is aimed at.
+//
+// [STRIFE] Verified unmodified
+//
+boolean
+PTR_AimTraverse (intercept_t* in)
+{
+ line_t* li;
+ mobj_t* th;
+ fixed_t slope;
+ fixed_t thingtopslope;
+ fixed_t thingbottomslope;
+ fixed_t dist;
+
+ if (in->isaline)
+ {
+ li = in->d.line;
+
+ if ( !(li->flags & ML_TWOSIDED) )
+ return false; // stop
+
+ // Crosses a two sided line.
+ // A two sided line will restrict
+ // the possible target ranges.
+ P_LineOpening (li);
+
+ if (openbottom >= opentop)
+ return false; // stop
+
+ dist = FixedMul (attackrange, in->frac);
+
+ // Return false if there is no back sector. This should never
+ // be the case if the line is two-sided; however, some WADs
+ // (eg. ottawau.wad) use this as an "impassible glass" trick
+ // and rely on Vanilla Doom's (unintentional) support for this.
+
+ if (li->backsector == NULL)
+ {
+ return false;
+ }
+
+ if (li->frontsector->floorheight != li->backsector->floorheight)
+ {
+ slope = FixedDiv (openbottom - shootz , dist);
+ if (slope > bottomslope)
+ bottomslope = slope;
+ }
+
+ if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
+ {
+ slope = FixedDiv (opentop - shootz , dist);
+ if (slope < topslope)
+ topslope = slope;
+ }
+
+ if (topslope <= bottomslope)
+ return false; // stop
+
+ return true; // shot continues
+ }
+
+ // shoot a thing
+ th = in->d.thing;
+ if (th == shootthing)
+ return true; // can't shoot self
+
+ if (!(th->flags&MF_SHOOTABLE))
+ return true; // corpse or something
+
+ // check angles to see if the thing can be aimed at
+ dist = FixedMul (attackrange, in->frac);
+ thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
+
+ if (thingtopslope < bottomslope)
+ return true; // shot over the thing
+
+ thingbottomslope = FixedDiv (th->z - shootz, dist);
+
+ if (thingbottomslope > topslope)
+ return true; // shot under the thing
+
+ // this thing can be hit!
+ if (thingtopslope > topslope)
+ thingtopslope = topslope;
+
+ if (thingbottomslope < bottomslope)
+ thingbottomslope = bottomslope;
+
+ aimslope = (thingtopslope+thingbottomslope)/2;
+ linetarget = th;
+
+ return false; // don't go any farther
+}
+
+
+//
+// PTR_ShootTraverse
+//
+// [STRIFE] Changes for Spectres and Mauler puff/damage inflictor
+//
+boolean PTR_ShootTraverse (intercept_t* in)
+{
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ fixed_t frac;
+
+ line_t* li;
+
+ mobj_t* th;
+ mobj_t* th2; // villsa [STRIFE]
+
+ fixed_t slope;
+ fixed_t dist;
+ fixed_t thingtopslope;
+ fixed_t thingbottomslope;
+
+ if (in->isaline)
+ {
+ li = in->d.line;
+
+ if (li->special)
+ P_ShootSpecialLine (shootthing, li);
+
+ if ( !(li->flags & ML_TWOSIDED) )
+ goto hitline;
+
+ // crosses a two sided line
+ P_LineOpening (li);
+
+ dist = FixedMul (attackrange, in->frac);
+
+ // Check if backsector is NULL. See comment in PTR_AimTraverse.
+
+ if (li->backsector == NULL)
+ {
+ goto hitline;
+ }
+
+ if (li->frontsector->floorheight != li->backsector->floorheight)
+ {
+ slope = FixedDiv (openbottom - shootz , dist);
+ if (slope > aimslope)
+ goto hitline;
+ }
+
+ if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
+ {
+ slope = FixedDiv (opentop - shootz , dist);
+ if (slope < aimslope)
+ goto hitline;
+ }
+
+ // shot continues
+ return true;
+
+
+ // hit line
+hitline:
+ // position a bit closer
+ frac = in->frac - FixedDiv (4*FRACUNIT,attackrange);
+ x = trace.x + FixedMul (trace.dx, frac);
+ y = trace.y + FixedMul (trace.dy, frac);
+ z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange));
+
+ if (li->frontsector->ceilingpic == skyflatnum)
+ {
+ // don't shoot the sky!
+ if (z > li->frontsector->ceilingheight)
+ return false;
+
+ // it's a sky hack wall
+ if (li->backsector && li->backsector->ceilingpic == skyflatnum)
+ return false;
+ }
+
+ // villsa [STRIFE]
+ if(la_damage > 0)
+ {
+ // villsa [STRIFE] Test against Mauler attack range
+ if(attackrange != 2112*FRACUNIT)
+ P_SpawnPuff(x, y, z); // Spawn bullet puffs.
+ else
+ P_SpawnMobj(x, y, z, MT_STRIFEPUFF3);
+ }
+
+ // don't go any farther
+ return false;
+ }
+
+ // shoot a thing
+ th = in->d.thing;
+ if (th == shootthing)
+ return true; // can't shoot self
+
+ if (!(th->flags&MF_SHOOTABLE))
+ return true; // corpse or something
+
+ // haleyjd 09/18/10: [STRIFE] Corrected - not MVIS, but SPECTRAL.
+ if(th->flags & MF_SPECTRAL)
+ return true; // is a spectral entity
+
+ // check angles to see if the thing can be aimed at
+ dist = FixedMul (attackrange, in->frac);
+ thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
+
+ if (thingtopslope < aimslope)
+ return true; // shot over the thing
+
+ thingbottomslope = FixedDiv (th->z - shootz, dist);
+
+ if (thingbottomslope > aimslope)
+ return true; // shot under the thing
+
+ // hit thing
+ // position a bit closer
+ frac = in->frac - FixedDiv (10*FRACUNIT,attackrange);
+
+ x = trace.x + FixedMul (trace.dx, frac);
+ y = trace.y + FixedMul (trace.dy, frac);
+ z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange));
+
+ // villsa [STRIFE] Check for Mauler attack range
+ if(attackrange == 2112*FRACUNIT)
+ {
+ th2 = P_SpawnMobj(x, y, z, MT_STRIFEPUFF3);
+ th2->momz = -FRACUNIT;
+ P_DamageMobj(th, th2, shootthing, la_damage);
+ return false;
+ }
+
+ // villsa [STRIFE] disabled check for damage
+ //if (la_damage)
+ P_DamageMobj (th, shootthing, shootthing, la_damage);
+
+ // Spawn bullet puffs or blod spots,
+ // depending on target type.
+ if (in->d.thing->flags & MF_NOBLOOD)
+ P_SpawnSparkPuff(x, y, z); // villsa [STRIFE] call spark puff function instead
+ else
+ P_SpawnBlood (x,y,z, la_damage);
+
+ // don't go any farther
+ return false;
+
+}
+
+
+//
+// P_AimLineAttack
+//
+// [STRIFE] Modified to support player->pitch
+//
+fixed_t
+P_AimLineAttack
+( mobj_t* t1,
+ angle_t angle,
+ fixed_t distance )
+{
+ fixed_t x2;
+ fixed_t y2;
+
+ t1 = P_SubstNullMobj(t1);
+
+ angle >>= ANGLETOFINESHIFT;
+ shootthing = t1;
+
+ x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
+ y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
+ shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
+
+ // can't shoot outside view angles
+ topslope = 100*FRACUNIT/160;
+ bottomslope = -100*FRACUNIT/160;
+
+ attackrange = distance;
+ linetarget = NULL;
+
+ P_PathTraverse ( t1->x, t1->y,
+ x2, y2,
+ PT_ADDLINES|PT_ADDTHINGS,
+ PTR_AimTraverse );
+
+ if (linetarget)
+ return aimslope;
+ else // villsa [STRIFE] checks for player pitch
+ {
+ if(t1->player)
+ return (t1->player->pitch << FRACBITS) / 160;
+ }
+
+ return 0;
+}
+
+
+//
+// P_LineAttack
+// If damage == 0, it is just a test trace
+// that will leave linetarget set.
+//
+// [STRIFE] Modified to check lines only if damage <= 0 (see P_RadiusAttack)
+//
+void
+P_LineAttack
+( mobj_t* t1,
+ angle_t angle,
+ fixed_t distance,
+ fixed_t slope,
+ int damage )
+{
+ fixed_t x2;
+ fixed_t y2;
+ int traverseflags;
+
+ angle >>= ANGLETOFINESHIFT;
+ shootthing = t1;
+ la_damage = damage;
+ x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
+ y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
+ shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
+ attackrange = distance;
+ aimslope = slope;
+
+ // villsa [STRIFE] test lines only if damage is <= 0
+ if(damage >= 1)
+ traverseflags = (PT_ADDLINES|PT_ADDTHINGS);
+ else
+ traverseflags = PT_ADDLINES;
+
+ P_PathTraverse(t1->x, t1->y,
+ x2, y2,
+ traverseflags,
+ PTR_ShootTraverse);
+}
+
+
+
+//
+// USE LINES
+//
+// [STRIFE] Verified unmodified
+//
+mobj_t* usething;
+
+boolean PTR_UseTraverse (intercept_t* in)
+{
+ int side;
+
+ if (!in->d.line->special)
+ {
+ P_LineOpening (in->d.line);
+ if (openrange <= 0)
+ {
+ S_StartSound (usething, sfx_noway);
+
+ // can't use through a wall
+ return false;
+ }
+ // not a special line, but keep checking
+ return true ;
+ }
+
+ side = 0;
+ if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1)
+ side = 1;
+
+ // return false; // don't use back side
+
+ P_UseSpecialLine (usething, in->d.line, side);
+
+ // can't use for than one special line in a row
+ return false;
+}
+
+
+//
+// P_UseLines
+// Looks for special lines in front of the player to activate.
+//
+// [STRIFE] Verified unmodified
+//
+void P_UseLines (player_t* player)
+{
+ int angle;
+ fixed_t x1;
+ fixed_t y1;
+ fixed_t x2;
+ fixed_t y2;
+
+ usething = player->mo;
+
+ angle = player->mo->angle >> ANGLETOFINESHIFT;
+
+ x1 = player->mo->x;
+ y1 = player->mo->y;
+ x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle];
+ y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle];
+
+ P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse );
+}
+
+
+//
+// RADIUS ATTACK
+//
+mobj_t* bombsource;
+mobj_t* bombspot;
+int bombdamage;
+
+
+//
+// PIT_RadiusAttack
+// "bombsource" is the creature
+// that caused the explosion at "bombspot".
+//
+// [STRIFE] Modified for Spectral and Inquisitor exclusions
+//
+boolean PIT_RadiusAttack (mobj_t* thing)
+{
+ fixed_t dx;
+ fixed_t dy;
+ fixed_t dist;
+
+ if (!(thing->flags & MF_SHOOTABLE))
+ return true;
+
+ // haleyjd 10/04/10: Spectrals are not damaged by blast radii
+ if(thing->flags & MF_SPECTRAL)
+ return true;
+
+ // Boss spider and cyborg
+ // take no damage from concussion.
+ // villsa [STRIFE] unused
+ // - haleyjd: INQUISITOR
+
+ if(thing->type == MT_INQUISITOR)
+ return true;
+
+ dx = abs(thing->x - bombspot->x);
+ dy = abs(thing->y - bombspot->y);
+
+ dist = dx>dy ? dx : dy;
+ dist = (dist - thing->radius) >> FRACBITS;
+
+ if (dist < 0)
+ dist = 0;
+
+ if (dist >= bombdamage)
+ return true; // out of range
+
+ if ( P_CheckSight (thing, bombspot) )
+ {
+ // must be in direct path
+ P_DamageMobj (thing, bombspot, bombsource, bombdamage - dist);
+ }
+
+ return true;
+}
+
+
+//
+// P_RadiusAttack
+// Source is the creature that caused the explosion at spot.
+//
+// [STRIFE] Modified to emit "test" tracers which can shatter glass screens
+// and windows.
+//
+void
+P_RadiusAttack
+( mobj_t* spot,
+ mobj_t* source,
+ int damage )
+{
+ int x;
+ int y;
+
+ int xl;
+ int xh;
+ int yl;
+ int yh;
+
+ fixed_t dist;
+
+ dist = (damage+MAXRADIUS)<<FRACBITS;
+ yh = (spot->y + dist - bmaporgy)>>MAPBLOCKSHIFT;
+ yl = (spot->y - dist - bmaporgy)>>MAPBLOCKSHIFT;
+ xh = (spot->x + dist - bmaporgx)>>MAPBLOCKSHIFT;
+ xl = (spot->x - dist - bmaporgx)>>MAPBLOCKSHIFT;
+ bombspot = spot;
+ bombsource = source;
+ bombdamage = damage;
+
+ for (y=yl ; y<=yh ; y++)
+ for (x=xl ; x<=xh ; x++)
+ P_BlockThingsIterator (x, y, PIT_RadiusAttack );
+
+ // villsa [STRIFE] Send out 0 damage tracers to shatter nearby glass.
+ spot->z += 32*FRACUNIT;
+ P_LineAttack(spot, 0, dist, 1, 0);
+ P_LineAttack(spot, ANG90, dist, 1, 0);
+ P_LineAttack(spot, ANG180, dist, 1, 0);
+ P_LineAttack(spot, ANG270, dist, 1, 0);
+ spot->z -= 32*FRACUNIT;
+}
+
+
+
+//
+// SECTOR HEIGHT CHANGING
+// After modifying a sectors floor or ceiling height,
+// call this routine to adjust the positions
+// of all things that touch the sector.
+//
+// If anything doesn't fit anymore, true will be returned.
+// If crunch is true, they will take damage
+// as they are being crushed.
+// If Crunch is false, you should set the sector height back
+// the way it was and call P_ChangeSector again
+// to undo the changes.
+//
+boolean crushchange;
+boolean nofit;
+
+
+//
+// PIT_ChangeSector
+//
+// [STRIFE] Changes to crushing behavior
+//
+boolean PIT_ChangeSector (mobj_t* thing)
+{
+ mobj_t* mo;
+
+ if (P_ThingHeightClip (thing))
+ {
+ // keep checking
+ return true;
+ }
+
+ // crunch bodies to giblets
+ if (thing->health <= 0)
+ {
+ // villsa [STRIFE] do something with the player
+ if(thing->player && thing->subsector->sector->specialdata)
+ {
+ nofit = true;
+ return false;
+ }
+ //P_SetMobjState (thing, S_GIBS); // villsa [STRIFE] unused
+
+ A_BodyParts(thing); // villsa [STRIFE] spit out meat/junk stuff
+ thing->flags &= ~MF_SOLID;
+ thing->height = 0;
+ thing->radius = 0;
+
+ // keep checking
+ return true;
+ }
+
+ // crunch dropped items
+ if (thing->flags & MF_DROPPED)
+ {
+ P_RemoveMobj (thing);
+
+ // keep checking
+ return true;
+ }
+
+ if (! (thing->flags & MF_SHOOTABLE) )
+ {
+ // assume it is bloody gibs or something
+ return true;
+ }
+
+ nofit = true;
+
+ if (crushchange && !(leveltime&3) )
+ {
+ int t;
+ S_StartSound(thing, sfx_pcrush); // villsa [STRIFE]
+ P_DamageMobj(thing,NULL,NULL,10);
+
+ // spray blood in a random direction
+ mo = P_SpawnMobj (thing->x,
+ thing->y,
+ thing->z + thing->height/2, MT_BLOOD_DEATH);
+
+ t = P_Random();
+ mo->momx = (t - P_Random ()) << 12;
+ t = P_Random();
+ mo->momy = (t - P_Random ()) << 12;
+ }
+
+ // keep checking (crush other things)
+ return true;
+}
+
+
+
+//
+// P_ChangeSector
+//
+// [STRIFE] Verified unmodified
+//
+boolean
+P_ChangeSector
+( sector_t* sector,
+ boolean crunch )
+{
+ int x;
+ int y;
+
+ nofit = false;
+ crushchange = crunch;
+
+ // re-check heights for all things near the moving sector
+ for (x=sector->blockbox[BOXLEFT] ; x<= sector->blockbox[BOXRIGHT] ; x++)
+ for (y=sector->blockbox[BOXBOTTOM];y<= sector->blockbox[BOXTOP] ; y++)
+ P_BlockThingsIterator (x, y, PIT_ChangeSector);
+
+ return nofit;
+}
+
+// Code to emulate the behavior of Vanilla Doom when encountering an overrun
+// of the spechit array. This is by Andrey Budko (e6y) and comes from his
+// PrBoom plus port. A big thanks to Andrey for this.
+
+static void SpechitOverrun(line_t *ld)
+{
+ static unsigned int baseaddr = 0;
+ unsigned int addr;
+
+ if (baseaddr == 0)
+ {
+ int p;
+
+ // This is the first time we have had an overrun. Work out
+ // what base address we are going to use.
+ // Allow a spechit value to be specified on the command line.
+
+ //!
+ // @category compat
+ // @arg <n>
+ //
+ // Use the specified magic value when emulating spechit overruns.
+ //
+
+ p = M_CheckParmWithArgs("-spechit", 1);
+
+ if (p > 0)
+ {
+ M_StrToInt(myargv[p+1], (int *) &baseaddr);
+ }
+ else
+ {
+ baseaddr = DEFAULT_SPECHIT_MAGIC;
+ }
+ }
+
+ // Calculate address used in doom2.exe
+
+ addr = baseaddr + (ld - lines) * 0x3E;
+
+ switch(numspechit)
+ {
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ tmbbox[numspechit-9] = addr;
+ break;
+ case 13:
+ nofit = addr; // haleyjd 20110204: nofit/crushchange are in opposite
+ break; // order in the Strife binary.
+ case 14:
+ crushchange = addr;
+ break;
+ default:
+ fprintf(stderr, "SpechitOverrun: Warning: unable to emulate"
+ "an overrun where numspechit=%i\n",
+ numspechit);
+ break;
+ }
+}
+
diff --git a/src/strife/p_maputl.c b/src/strife/p_maputl.c
new file mode 100644
index 00000000..ee8485ca
--- /dev/null
+++ b/src/strife/p_maputl.c
@@ -0,0 +1,1061 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+// Copyright(C) 2005, 2006 Andrey Budko
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// 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 <stdlib.h>
+
+
+#include "m_bbox.h"
+
+#include "doomdef.h"
+#include "doomstat.h"
+#include "p_local.h"
+
+
+// State.
+#include "r_state.h"
+
+//
+// P_AproxDistance
+// Gives an estimation of distance (not exact)
+//
+// [STRIFE] Verified unmodified
+//
+fixed_t
+P_AproxDistance
+( fixed_t dx,
+ fixed_t dy )
+{
+ dx = abs(dx);
+ dy = abs(dy);
+ if (dx < dy)
+ return dx+dy-(dx>>1);
+ return dx+dy-(dy>>1);
+}
+
+
+//
+// P_PointOnLineSide
+// Returns 0 or 1
+//
+// [STRIFE] Verified unmodified
+//
+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.
+//
+// [STRIFE] Verified unmodified
+//
+int
+P_BoxOnLineSide
+( fixed_t* tmbox,
+ line_t* ld )
+{
+ int p1 = 0;
+ int p2 = 0;
+
+ 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.
+//
+// [STRIFE] Verified unmodified
+//
+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.
+//
+// [STRIFE] Verified unmodified
+//
+fixed_t
+P_InterceptVector
+( divline_t* v2,
+ divline_t* v1 )
+{
+#if 1
+ 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;
+#else // UNUSED, float debug.
+ float frac;
+ float num;
+ float den;
+ float v1x;
+ float v1y;
+ float v1dx;
+ float v1dy;
+ float v2x;
+ float v2y;
+ float v2dx;
+ float v2dy;
+
+ v1x = (float)v1->x/FRACUNIT;
+ v1y = (float)v1->y/FRACUNIT;
+ v1dx = (float)v1->dx/FRACUNIT;
+ v1dy = (float)v1->dy/FRACUNIT;
+ v2x = (float)v2->x/FRACUNIT;
+ v2y = (float)v2->y/FRACUNIT;
+ v2dx = (float)v2->dx/FRACUNIT;
+ v2dy = (float)v2->dy/FRACUNIT;
+
+ den = v1dy*v2dx - v1dx*v2dy;
+
+ if (den == 0)
+ return 0; // parallel
+
+ num = (v1x - v2x)*v1dy + (v2y - v1y)*v1dx;
+ frac = num / den;
+
+ return frac*FRACUNIT;
+#endif
+}
+
+
+//
+// P_LineOpening
+// Sets opentop and openbottom to the window
+// through a two sided line.
+// OPTIMIZE: keep this precalculated
+//
+// [STRIFE] Verified unmodified
+//
+fixed_t opentop;
+fixed_t openbottom;
+fixed_t openrange;
+fixed_t lowfloor;
+
+
+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.
+//
+// [STRIFE] Verified unmodified
+//
+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
+//
+// [STRIFE] Verified unmodified
+//
+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 = NULL;
+ 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 = NULL;
+ thing->bnext = *link;
+ if (*link)
+ (*link)->bprev = thing;
+
+ *link = thing;
+ }
+ else
+ {
+ // thing is off the map
+ thing->bnext = thing->bprev = NULL;
+ }
+ }
+}
+
+
+
+//
+// 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.
+//
+// haleyjd 20110203:
+// [STRIFE] Modified to track blockingline
+//
+boolean
+P_BlockLinesIterator
+( int x,
+ int y,
+ 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];
+
+ // [STRIFE]: set blockingline (see P_XYMovement @ p_mobj.c)
+ blockingline = ld;
+
+ 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
+//
+// [STRIFE] Verified unmodified
+//
+boolean
+P_BlockThingsIterator
+( int x,
+ int y,
+ 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
+//
+intercept_t intercepts[MAXINTERCEPTS];
+intercept_t* intercept_p;
+
+divline_t trace;
+boolean earlyout;
+int ptflags;
+
+static void InterceptsOverrun(int num_intercepts, intercept_t *intercept);
+
+//
+// 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.
+//
+// haleyjd 20110204 [STRIFE]: Added Rogue's fix for intercepts overflows
+//
+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++;
+
+ // haleyjd 20110204 [STRIFE]
+ // Evidently Rogue had trouble with intercepts overflows during
+ // development, as they added this check here which will stop adding
+ // intercepts if the array would be overflown.
+ if(intercept_p <= &intercepts[MAXINTERCEPTS_ORIGINAL-2])
+ return true; // continue
+ else
+ return false;
+
+ // [STRIFE] Not needed?
+ //InterceptsOverrun(intercept_p - intercepts, intercept_p);
+}
+
+
+
+//
+// PIT_AddThingIntercepts
+//
+boolean PIT_AddThingIntercepts (mobj_t* thing)
+{
+ fixed_t x1;
+ fixed_t y1;
+ fixed_t x2;
+ fixed_t y2;
+
+ int s1;
+ int s2;
+
+ 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++;
+
+ // haleyjd 20110204 [STRIFE]: As above, protection against intercepts
+ // overflows, courtesy of Rogue Software.
+ if(intercept_p <= &intercepts[MAXINTERCEPTS_ORIGINAL-2])
+ return true; // keep going
+ else
+ return false;
+
+ // haleyjd [STRIFE]: Not needed?
+ //InterceptsOverrun(intercept_p - intercepts, intercept_p);
+}
+
+
+//
+// P_TraverseIntercepts
+// Returns true if the traverser function returns true
+// for all lines.
+//
+// [STRIFE] Verified unmodified.
+//
+boolean
+P_TraverseIntercepts
+( traverser_t func,
+ fixed_t maxfrac )
+{
+ int count;
+ fixed_t dist;
+ intercept_t* scan;
+ intercept_t* in;
+
+ count = intercept_p - intercepts;
+
+ in = 0; // shut up compiler warning
+
+ while (count--)
+ {
+ dist = INT_MAX;
+ 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 = INT_MAX;
+ }
+
+ return true; // everything was traversed
+}
+
+extern fixed_t bulletslope;
+
+// Intercepts Overrun emulation, from PrBoom-plus.
+// Thanks to Andrey Budko (entryway) for researching this and his
+// implementation of Intercepts Overrun emulation in PrBoom-plus
+// which this is based on.
+
+typedef struct
+{
+ int len;
+ void *addr;
+ boolean int16_array;
+} intercepts_overrun_t;
+
+// Intercepts memory table. This is where various variables are located
+// in memory in Vanilla Doom. When the intercepts table overflows, we
+// need to write to them.
+//
+// Almost all of the values to overwrite are 32-bit integers, except for
+// playerstarts, which is effectively an array of 16-bit integers and
+// must be treated differently.
+
+// haleyjd 20110204: NB: This array has *not* been updated for Strife,
+// because Strife has protection against intercepts overflows. The memory
+// layout of the 1.2 and 1.31 EXEs is radically different with respect
+// to this area of the BSS segment, so it would have to be redone entirely
+// if it were needed.
+
+static intercepts_overrun_t intercepts_overrun[] =
+{
+ {4, NULL, false},
+ {4, NULL, /* &earlyout, */ false},
+ {4, NULL, /* &intercept_p, */ false},
+ {4, &lowfloor, false},
+ {4, &openbottom, false},
+ {4, &opentop, false},
+ {4, &openrange, false},
+ {4, NULL, false},
+ {120, NULL, /* &activeplats, */ false},
+ {8, NULL, false},
+ {4, &bulletslope, false},
+ {4, NULL, /* &swingx, */ false},
+ {4, NULL, /* &swingy, */ false},
+ {4, NULL, false},
+ {40, &playerstarts, true},
+ {4, NULL, /* &blocklinks, */ false},
+ {4, &bmapwidth, false},
+ {4, NULL, /* &blockmap, */ false},
+ {4, &bmaporgx, false},
+ {4, &bmaporgy, false},
+ {4, NULL, /* &blockmaplump, */ false},
+ {4, &bmapheight, false},
+ {0, NULL, false},
+};
+
+// Overwrite a specific memory location with a value.
+
+static void InterceptsMemoryOverrun(int location, int value)
+{
+ int i, offset;
+ int index;
+ void *addr;
+
+ i = 0;
+ offset = 0;
+
+ // Search down the array until we find the right entry
+
+ while (intercepts_overrun[i].len != 0)
+ {
+ if (offset + intercepts_overrun[i].len > location)
+ {
+ addr = intercepts_overrun[i].addr;
+
+ // Write the value to the memory location.
+ // 16-bit and 32-bit values are written differently.
+
+ if (addr != NULL)
+ {
+ if (intercepts_overrun[i].int16_array)
+ {
+ index = (location - offset) / 2;
+ ((short *) addr)[index] = value & 0xffff;
+ ((short *) addr)[index + 1] = (value >> 16) & 0xffff;
+ }
+ else
+ {
+ index = (location - offset) / 4;
+ ((int *) addr)[index] = value;
+ }
+ }
+
+ break;
+ }
+
+ offset += intercepts_overrun[i].len;
+ ++i;
+ }
+}
+
+// Emulate overruns of the intercepts[] array.
+
+static void InterceptsOverrun(int num_intercepts, intercept_t *intercept)
+{
+ int location;
+
+ if (num_intercepts <= MAXINTERCEPTS_ORIGINAL)
+ {
+ // No overrun
+
+ return;
+ }
+
+ location = (num_intercepts - MAXINTERCEPTS_ORIGINAL - 1) * 12;
+
+ // Overwrite memory that is overwritten in Vanilla Doom, using
+ // the values from the intercept structure.
+ //
+ // Note: the ->d.{thing,line} member should really have its
+ // address translated into the correct address value for
+ // Vanilla Doom.
+
+ InterceptsMemoryOverrun(location, intercept->frac);
+ InterceptsMemoryOverrun(location + 4, intercept->isaline);
+ InterceptsMemoryOverrun(location + 8, (int) intercept->d.thing);
+}
+
+
+//
+// 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.
+//
+// [STRIFE] Verified unmodified
+//
+boolean
+P_PathTraverse
+( fixed_t x1,
+ fixed_t y1,
+ fixed_t x2,
+ fixed_t y2,
+ int flags,
+ 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,abs(x2-x1));
+ }
+ else if (xt2 < xt1)
+ {
+ mapxstep = -1;
+ partial = (x1>>MAPBTOFRAC)&(FRACUNIT-1);
+ ystep = FixedDiv (y2-y1,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,abs(y2-y1));
+ }
+ else if (yt2 < yt1)
+ {
+ mapystep = -1;
+ partial = (y1>>MAPBTOFRAC)&(FRACUNIT-1);
+ xstep = FixedDiv (x2-x1,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 );
+}
+
+
+
diff --git a/src/strife/p_mobj.c b/src/strife/p_mobj.c
new file mode 100644
index 00000000..53d12f9c
--- /dev/null
+++ b/src/strife/p_mobj.c
@@ -0,0 +1,1352 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Moving object handling. Spawn functions.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.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"
+#include "d_main.h" // villsa [STRIFE]
+
+extern line_t *spechit[]; // haleyjd:
+extern int numspechit; // [STRIFE] - needed in P_XYMovement
+
+
+void G_PlayerReborn (int player);
+void P_SpawnMapThing (mapthing_t* mthing);
+
+
+//
+// P_SetMobjState
+// Returns true if the mobj is still present.
+//
+// [STRIFE] Verified unmodified
+//
+int test;
+
+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
+//
+// [STRIFE] Removed randomization of deathstate tics
+//
+void P_ExplodeMissile (mobj_t* mo)
+{
+ mo->momx = mo->momy = mo->momz = 0;
+
+ P_SetMobjState (mo, mobjinfo[mo->type].deathstate);
+
+ // villsa [STRIFE] removed tics randomization
+
+ mo->flags &= ~MF_MISSILE;
+
+ if (mo->info->deathsound)
+ S_StartSound (mo, mo->info->deathsound);
+}
+
+
+//
+// P_XYMovement
+//
+// [STRIFE] Modifications for:
+// * No SKULLFLY logic (replaced by BOUNCE flag)
+// * Missiles can activate G1/GR line types
+// * Player walking logic
+// * Air friction for players
+//
+#define STOPSPEED 0x1000
+#define FRICTION 0xe800
+#define AIRFRICTION 0xfff0 // [STRIFE]
+
+void P_XYMovement (mobj_t* mo)
+{
+ fixed_t ptryx;
+ fixed_t ptryy;
+ player_t* player;
+ fixed_t xmove;
+ fixed_t ymove;
+
+ // villsa [STRIFE] unused
+ /*
+ 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);
+ }
+ // villsa [STRIFE] check for bouncy missiles
+ else if(mo->flags & MF_BOUNCE)
+ {
+ mo->momx >>= 3;
+ mo->momy >>= 3;
+
+ if (P_TryMove(mo, mo->x - xmove, ymove + mo->y))
+ mo->momy = -mo->momy;
+ else
+ mo->momx = -mo->momx;
+
+ xmove = 0;
+ ymove = 0;
+ }
+ else if (mo->flags & MF_MISSILE)
+ {
+ // haley 20110203: [STRIFE]
+ // This modification allows missiles to activate shoot specials.
+ // *** BUG: In vanilla Strife the second condition is simply
+ // if(numspechit). However, numspechit can be negative, and
+ // when it is, this accesses spechit[-2]. This always causes the
+ // DOS exe to read from NULL, and the 'special' value there (in
+ // DOS 6.22 at least) is 0x70, which does nothing.
+ if(blockingline && blockingline->special)
+ P_ShootSpecialLine(mo, blockingline);
+ if(numspechit > 0)
+ P_ShootSpecialLine(mo, spechit[numspechit-1]);
+
+ // 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;
+ }
+
+ // villsa [STRIFE] replace skullfly flag with MF_BOUNCE
+ if (mo->flags & (MF_MISSILE | MF_BOUNCE) )
+ return; // no friction for missiles ever
+
+ // haleyjd 20110224: [STRIFE] players experience friction even in the air,
+ // although less than when on the ground. With this fix, the 1.2-and-up
+ // IWAD demo is now in sync!
+ if (mo->z > mo->floorz)
+ {
+ if(player)
+ {
+ mo->momx = FixedMul (mo->momx, AIRFRICTION);
+ mo->momy = FixedMul (mo->momy, AIRFRICTION);
+ }
+ 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
+ // villsa [STRIFE]: different player state (haleyjd - verified 20110202)
+ if ( player&&(unsigned)((player->mo->state - states) - S_PLAY_01) < 4)
+ P_SetMobjState (player->mo, S_PLAY_00);
+
+ mo->momx = 0;
+ mo->momy = 0;
+ }
+ else
+ {
+ mo->momx = FixedMul (mo->momx, FRICTION);
+ mo->momy = FixedMul (mo->momy, FRICTION);
+ }
+}
+
+//
+// P_ZMovement
+//
+// [STRIFE] Modifications for:
+// * 3D Object Clipping
+// * Different momz handling
+// * No SKULLFLY logic (replaced with BOUNCE)
+// * Missiles don't hit sky flats
+//
+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
+ // villsa [STRIFE] check for things standing on top of other things
+ if(!P_CheckPositionZ(mo, mo->z + mo->momz))
+ {
+ if(mo->momz >= 0)
+ mo->ceilingz = mo->height + mo->z;
+ else
+ mo->floorz = mo->z;
+ }
+
+ //mo->z += mo->momz; // villsa [STRIFE] unused
+
+ if ( mo->flags & MF_FLOAT
+ && mo->target)
+ {
+ // float down towards target if too close
+ if ( /*!(mo->flags & MF_SKULLFLY) // villsa [STRIFE] unused
+ &&*/ !(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
+
+ if (mo->flags & MF_BOUNCE)
+ {
+ // the skull slammed into something
+ // villsa [STRIFE] affect reactiontime
+ // momz is also shifted by 1
+ mo->momz = -mo->momz >> 1;
+ mo->reactiontime >>= 1;
+
+ // villsa [STRIFE] get terrain type
+ if(P_GetTerrainType(mo) != FLOOR_SOLID)
+ mo->flags &= ~MF_BOUNCE;
+ }
+
+ 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;
+
+ // villsa [STRIFE] fall damage
+ // haleyjd 09/18/10: Repaired calculation
+ if(mo->momz < -20*FRACUNIT)
+ P_DamageMobj(mo, NULL, mo, mo->momz / -25000);
+
+ // haleyjd 20110224: *Any* fall centers your view, not just
+ // damaging falls (moved outside the above if).
+ mo->player->centerview = 1;
+ S_StartSound (mo, sfx_oof);
+ }
+ mo->momz = 0;
+ }
+ mo->z = mo->floorz;
+
+
+ // cph 2001/05/26 -
+ // See lost soul bouncing comment above. We need this here for bug
+ // compatibility with original Doom2 v1.9 - if a soul is charging and
+ // hit by a raising floor this incorrectly reverses its Y momentum.
+ //
+
+ // villsa [STRIFE] unused
+ /*
+ if (!correct_lost_soul_bounce && mo->flags & MF_SKULLFLY)
+ mo->momz = -mo->momz;
+ */
+
+ // villsa [STRIFE] also check for MF_BOUNCE
+ if ( (mo->flags & MF_MISSILE)
+ && !(mo->flags & (MF_NOCLIP|MF_BOUNCE)) )
+ {
+ P_ExplodeMissile (mo);
+ }
+ }
+ else // haleyjd 20110224: else here, not else if - Strife change or what?
+ {
+ if (! (mo->flags & MF_NOGRAVITY) )
+ {
+ if (mo->momz == 0)
+ mo->momz = -GRAVITY*2;
+ else
+ mo->momz -= GRAVITY;
+ }
+
+ if (mo->z + mo->height > mo->ceilingz)
+ {
+ // villsa [STRIFE] replace skullfly flag with MF_BOUNCE
+ if (mo->flags & MF_BOUNCE)
+ {
+ // villsa [STRIFE] affect reactiontime
+ // momz is also shifted by 1
+ mo->momz = -mo->momz >> 1;
+ mo->reactiontime >>= 1;
+ }
+
+ // hit the ceiling
+ if (mo->momz > 0)
+ mo->momz = 0;
+
+ mo->z = mo->ceilingz - mo->height;
+
+ // villsa [STRIFE] also check for MF_BOUNCE
+ if ( (mo->flags & MF_MISSILE)
+ && !(mo->flags & (MF_NOCLIP|MF_BOUNCE)) )
+ {
+ // villsa [STRIFE] check against skies
+ if(mo->subsector->sector->ceilingpic == skyflatnum)
+ P_RemoveMobj(mo);
+ else
+ P_ExplodeMissile (mo);
+ }
+ }
+ }
+}
+
+
+
+//
+// P_NightmareRespawn
+//
+// [STRIFE] Modifications for:
+// * Destination fog z coordinate
+// * Restoration of all Strife mapthing flags
+//
+void
+P_NightmareRespawn (mobj_t* mobj)
+{
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ 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);
+
+ // haleyjd [STRIFE]: Uses ONFLOORZ instead of ss->sector->floorheight
+ mo = P_SpawnMobj (x, y, ONFLOORZ , 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;
+ if (mthing->options & MTF_STAND) // [STRIFE] Standing mode, for NPCs
+ mobj->flags |= MF_STAND;
+ if (mthing->options & MTF_FRIEND) // [STRIFE] Allies
+ mobj->flags |= MF_ALLY;
+ if (mthing->options & MTF_TRANSLUCENT) // [STRIFE] Translucent object
+ mobj->flags |= MF_SHADOW;
+ if (mthing->options & MTF_MVIS) // [STRIFE] Alt. Translucency
+ mobj->flags |= MF_MVIS;
+
+ mo->reactiontime = 18;
+
+ // remove the old monster,
+ P_RemoveMobj (mobj);
+}
+
+
+//
+// P_MobjThinker
+//
+// [STRIFE] Modified for:
+// * Terrain effects
+// * Stonecold cheat
+// * Altered skill 5 respawn behavior
+//
+void P_MobjThinker (mobj_t* mobj)
+{
+ // momentum movement
+ if (mobj->momx
+ || mobj->momy
+ /*|| (mobj->flags&MF_SKULLFLY)*/ ) // villsa [STRIFE] unused
+ {
+ P_XYMovement (mobj);
+
+ // FIXME: decent NOP/NULL/Nil function pointer please.
+ if (mobj->thinker.function.acv == (actionf_v) (-1))
+ return; // mobj was removed
+
+ // villsa [STRIFE] terrain clipping
+ if(P_GetTerrainType(mobj) == FLOOR_SOLID)
+ mobj->flags &= ~MF_FEETCLIPPED;
+ else
+ mobj->flags |= MF_FEETCLIPPED;
+
+ }
+ if ( (mobj->z != mobj->floorz && !(mobj->flags & MF_NOGRAVITY)) // villsa [STRIFE]
+ || mobj->momz )
+ {
+ P_ZMovement (mobj);
+
+ // FIXME: decent NOP/NULL/Nil function pointer please.
+ if (mobj->thinker.function.acv == (actionf_v) (-1))
+ return; // mobj was removed
+
+ // villsa [STRIFE] terrain clipping and sounds
+ if(P_GetTerrainType(mobj) == FLOOR_SOLID)
+ mobj->flags &= ~MF_FEETCLIPPED;
+ else
+ {
+ S_StartSound(mobj, sfx_wsplsh);
+ mobj->flags |= MF_FEETCLIPPED;
+ }
+
+ }
+
+
+ // cycle through states,
+ // calling action functions at transitions
+ if (mobj->tics != -1)
+ {
+ mobj->tics--;
+
+ // villsa [STRIFE] stonecold cheat
+ if(stonecold)
+ {
+ if(mobj->flags & MF_COUNTKILL)
+ P_DamageMobj(mobj, mobj, mobj, 10);
+ }
+
+ // 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++;
+
+ // haleyjd [STRIFE]: respawn time increased from 12 to 16
+ if (mobj->movecount < 16*TICRATE)
+ return;
+
+ if ( leveltime&31 )
+ return;
+
+ if (P_Random () > 4)
+ return;
+
+ // haleyjd [STRIFE]: NOTDMATCH things don't respawn
+ if(mobj->flags & MF_NOTDMATCH)
+ return;
+
+ P_NightmareRespawn (mobj);
+ }
+}
+
+
+//
+// P_SpawnMobj
+//
+// [STRIFE] Modifications to reactiontime and for terrain types.
+//
+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, NULL);
+ 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;
+
+ // haleyjd 09/25/10: [STRIFE] Doesn't do this; messes up flamethrower
+ // and a lot of other stuff using reactiontime as a counter.
+ //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;
+
+ // villsa [STRIFE]
+ if(P_GetTerrainType(mobj) != FLOOR_SOLID)
+ mobj->flags |= MF_FEETCLIPPED;
+
+ }
+ 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
+//
+// [STRIFE] Modifications for item respawn timing
+//
+mapthing_t itemrespawnque[ITEMQUESIZE];
+int itemrespawntime[ITEMQUESIZE];
+int iquehead;
+int iquetail;
+
+void P_RemoveMobj (mobj_t* mobj)
+{
+ // villsa [STRIFE] removed invuln/invis. sphere exceptions
+ if ((mobj->flags & MF_SPECIAL)
+ && !(mobj->flags & MF_DROPPED))
+ {
+ itemrespawnque[iquehead] = mobj->spawnpoint;
+ itemrespawntime[iquehead] = leveltime + 30*TICRATE; // [STRIFE]
+ iquehead = (iquehead+1)&(ITEMQUESIZE-1);
+
+ // [STRIFE] FIXME/TODO: - haleyjd 20110629
+ // -random parameter affects the behavior of respawning items here.
+ // However, this requires addition of randomparm to the transmission
+ // of variables during netgame initialization, and the netcode is not
+ // functional yet - so, I haven't added this yet!
+
+ // 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
+//
+// [STRIFE] modification to item respawn time handling
+//
+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;
+
+ // haleyjd [STRIFE]: 30 second wait is not accounted for here, see above.
+ if (leveltime < itemrespawntime[iquetail])
+ 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.
+//
+// [STRIFE] Modifications for:
+// * stonecold cheat, -workparm
+// * default inventory/questflags
+//
+void P_SpawnPlayer(mapthing_t* mthing)
+{
+ player_t* p;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ mobj_t* mobj;
+
+ if(mthing->type == 0)
+ return;
+
+ // 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 = NULL;
+ p->damagecount = 0;
+ p->bonuscount = 0;
+ p->extralight = 0;
+ p->fixedcolormap = 0;
+ p->viewheight = VIEWHEIGHT;
+
+ // setup gun psprite
+ P_SetupPsprites(p);
+
+ // villsa [STRIFE]
+ stonecold = false;
+
+ // villsa [STRIFE] what a nasty hack...
+ if(gamemap == 10)
+ p->weaponowned[wp_sigil] = true;
+
+ // villsa [STRIFE] instead of just giving cards in deathmatch mode, also
+ // set accuracy to 50 and give all quest flags
+ if(deathmatch)
+ {
+ int i;
+
+ p->accuracy = 50;
+ p->questflags = QF_ALLQUESTS; // 0x7fffffff
+
+ for(i = 0; i < NUMCARDS; i++)
+ p->cards[i] = true;
+ }
+
+ // villsa [STRIFE] set godmode?
+ if(workparm)
+ p->cheats |= CF_GODMODE;
+
+ 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.
+//
+// [STRIFE] Modifications for:
+// * No Lost Souls, item count
+// * New mapthing_t flag bits
+// * 8-player support
+//
+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])
+ {
+ memcpy (deathmatch_p, mthing, sizeof(*mthing));
+ deathmatch_p++;
+ }
+ return;
+ }
+
+ if (mthing->type <= 0)
+ {
+ // Thing type 0 is actually "player -1 start".
+ // For some reason, Vanilla Doom accepts/ignores this.
+
+ return;
+ }
+
+ // check for players specially
+ // haleyjd 20120209: [STRIFE] 8 player starts
+ if (mthing->type <= 8)
+ {
+ // 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 ("P_SpawnMapThing: Unknown type %i at (%i, %i)",
+ mthing->type,
+ mthing->x, mthing->y);
+
+ // don't spawn keycards and players in deathmatch
+ if (deathmatch && mobjinfo[i].flags & MF_NOTDMATCH)
+ return;
+
+ // don't spawn any monsters if -nomonsters
+ // villsa [STRIFE] Removed MT_SKULL
+ if (nomonsters && (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++;
+
+ // villsa [STRIFE] unused
+ /*
+ if (mobj->flags & MF_COUNTITEM)
+ totalitems++;
+ */
+
+ mobj->angle = ANG45 * (mthing->angle/45);
+ if (mthing->options & MTF_AMBUSH)
+ mobj->flags |= MF_AMBUSH;
+ if (mthing->options & MTF_STAND) // [STRIFE] Standing mode, for NPCs
+ mobj->flags |= MF_STAND;
+ if (mthing->options & MTF_FRIEND) // [STRIFE] Allies
+ mobj->flags |= MF_ALLY;
+ if (mthing->options & MTF_TRANSLUCENT) // [STRIFE] Translucent object
+ mobj->flags |= MF_SHADOW;
+ if (mthing->options & MTF_MVIS) // [STRIFE] Alt. Translucency
+ mobj->flags |= MF_MVIS;
+}
+
+
+
+//
+// GAME SPAWN FUNCTIONS
+//
+
+
+//
+// P_SpawnPuff
+//
+// [STRIFE] Modifications for:
+// * No spawn tics randomization
+// * Player melee behavior
+//
+extern fixed_t attackrange;
+
+void
+P_SpawnPuff
+( fixed_t x,
+ fixed_t y,
+ fixed_t z )
+{
+ mobj_t* th;
+ int t;
+
+ t = P_Random();
+ z += ((t - P_Random()) << 10);
+
+ // [STRIFE] removed momz and tics randomization
+
+ th = P_SpawnMobj(x, y, z, MT_STRIFEPUFF); // [STRIFE]: new type
+
+ // don't make punches spark on the wall
+ // [STRIFE] Use a separate melee attack range for the player
+ if(attackrange == PLAYERMELEERANGE)
+ P_SetMobjState(th, S_POW2_00); // 141
+
+ // villsa [STRIFE] unused
+ /*
+ if (th->tics < 1)
+ th->tics = 1;
+ */
+}
+
+//
+// P_SpawnSparkPuff
+//
+// villsa [STRIFE] new function
+//
+mobj_t* P_SpawnSparkPuff(fixed_t x, fixed_t y, fixed_t z)
+{
+ int t = P_Random();
+ return P_SpawnMobj(x, y, ((t - P_Random()) << 10) + z, MT_SPARKPUFF);
+}
+
+//
+// P_SpawnBlood
+//
+// [STRIFE] Modifications for:
+// * No spawn tics randomization
+// * Different damage ranges for state setting
+//
+void
+P_SpawnBlood
+( fixed_t x,
+ fixed_t y,
+ fixed_t z,
+ int damage )
+{
+ mobj_t* th;
+ int temp;
+
+ temp = P_Random();
+ z += (temp - P_Random()) << 10;
+ th = P_SpawnMobj(x, y, z, MT_BLOOD_DEATH);
+ th->momz = FRACUNIT*2;
+
+ // villsa [STRIFE]: removed tics randomization
+
+ // villsa [STRIFE] different checks for damage range
+ if(damage >= 10 && damage <= 13)
+ P_SetMobjState(th, S_BLOD_00);
+ else if(damage >= 7 && damage < 10)
+ P_SetMobjState(th, S_BLOD_01);
+ else if(damage < 7)
+ P_SetMobjState(th, S_BLOD_02);
+}
+
+
+
+//
+// P_CheckMissileSpawn
+// Moves the missile forward a bit
+// and possibly explodes it right there.
+//
+// [STRIFE] Modifications for:
+// * No spawn tics randomization
+//
+void P_CheckMissileSpawn (mobj_t* th)
+{
+ // villsa [STRIFE] removed tics randomization
+
+ // 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);
+}
+
+// Certain functions assume that a mobj_t pointer is non-NULL,
+// causing a crash in some situations where it is NULL. Vanilla
+// Doom did not crash because of the lack of proper memory
+// protection. This function substitutes NULL pointers for
+// pointers to a dummy mobj, to avoid a crash.
+
+mobj_t *P_SubstNullMobj(mobj_t *mobj)
+{
+ if (mobj == NULL)
+ {
+ static mobj_t dummy_mobj;
+
+ dummy_mobj.x = 0;
+ dummy_mobj.y = 0;
+ dummy_mobj.z = 0;
+ dummy_mobj.flags = 0;
+
+ mobj = &dummy_mobj;
+ }
+
+ return mobj;
+}
+
+//
+// P_SpawnMissile
+//
+// [STRIFE] Added MVIS inaccuracy
+//
+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)
+ {
+ int t = P_Random(); // haleyjd 20110223: remove order-of-evaluation dependencies
+ an += (t - P_Random()) << 21;
+ }
+ // villsa [STRIFE] check for heavily transparent things
+ else if(dest->flags & MF_MVIS)
+ {
+ int t = P_Random();
+ an += (t - P_Random()) << 22;
+ }
+
+ 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_SpawnFacingMissile
+//
+// villsa [STRIFE] new function
+// Spawn a missile based on source's angle
+//
+mobj_t* P_SpawnFacingMissile(mobj_t* source, mobj_t* target, mobjtype_t type)
+{
+ mobj_t* th;
+ angle_t an;
+ fixed_t dist;
+
+ th = P_SpawnMobj(source->x, source->y, source->z + (32*FRACUNIT), type);
+
+ if(th->info->seesound)
+ S_StartSound(th, th->info->seesound);
+
+ th->target = source; // where it came from
+ th->angle = source->angle; // haleyjd 09/06/10: fix0red
+ an = th->angle;
+
+ // fuzzy player
+ if (target->flags & MF_SHADOW)
+ {
+ int t = P_Random();
+ an += (t - P_Random()) << 21;
+ }
+ // villsa [STRIFE] check for heavily transparent things
+ else if(target->flags & MF_MVIS)
+ {
+ int t = P_Random();
+ an += (t - P_Random()) << 22;
+ }
+
+ an >>= ANGLETOFINESHIFT;
+ th->momx = FixedMul (th->info->speed, finecosine[an]);
+ th->momy = FixedMul (th->info->speed, finesine[an]);
+
+ dist = P_AproxDistance (target->x - source->x, target->y - source->y);
+ dist = dist / th->info->speed;
+
+ if(dist < 1)
+ dist = 1;
+
+ th->momz = (target->z - source->z) / dist;
+ P_CheckMissileSpawn (th);
+
+ return th;
+}
+
+//
+// P_SpawnPlayerMissile
+//
+// Tries to aim at a nearby monster
+// villsa [STRIFE] now returns a mobj
+// * Also modified to allow up/down look, and to account for foot-clipping
+// by liquid terrain.
+//
+mobj_t* 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;
+
+ // haleyjd 09/21/10: [STRIFE] Removed, for look up/down support.
+ //slope = 0;
+ }
+ }
+
+ // villsa [STRIFE]
+ if(linetarget)
+ source->target = linetarget;
+
+ x = source->x;
+ y = source->y;
+
+ // villsa [STRIFE]
+ if(!(source->flags & MF_FEETCLIPPED))
+ z = source->z + 32*FRACUNIT;
+ else
+ z = source->z + 22*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);
+
+ return th;
+}
+
+//
+// P_SpawnMortar
+//
+// villsa [STRIFE] new function
+// Spawn a high-arcing ballistic projectile
+//
+mobj_t* P_SpawnMortar(mobj_t *source, mobjtype_t type)
+{
+ mobj_t* th;
+ angle_t an;
+ fixed_t slope;
+
+ an = source->angle;
+
+ th = P_SpawnMobj(source->x, source->y, source->z, type);
+ th->target = source;
+ th->angle = an;
+ an >>= ANGLETOFINESHIFT;
+
+ // haleyjd 20110203: corrected order of function calls
+ th->momx = FixedMul(th->info->speed, finecosine[an]);
+ th->momy = FixedMul(th->info->speed, finesine[an]);
+
+ P_CheckMissileSpawn(th);
+
+ slope = P_AimLineAttack(source, source->angle, 1024*FRACUNIT);
+ th->momz = FixedMul(th->info->speed, slope);
+
+ return th;
+}
diff --git a/src/strife/p_mobj.h b/src/strife/p_mobj.h
new file mode 100644
index 00000000..0e482311
--- /dev/null
+++ b/src/strife/p_mobj.h
@@ -0,0 +1,338 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// 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,
+
+ // villsa [STRIFE] Stand around until alerted
+ MF_STAND = 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,
+
+ // villsa [STRIFE] For players, count as quest item
+ MF_GIVEQUEST = 0x800,
+
+ // Player cheat. ???
+ MF_NOCLIP = 0x1000,
+
+ // villsa [STRIFE] are feet clipped into water/slude floor?
+ MF_FEETCLIPPED = 0x2000,
+
+ // Allow moves to any height, no gravity.
+ // For active floaters, e.g. cacodemons, pain elementals.
+ MF_FLOAT = 0x4000,
+
+ // villsa [STRIFE] can NPC talk?
+ MF_NODIALOG = 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,
+
+ // Not to be activated by sound, deaf monster.
+ MF_AMBUSH = 0x800000,
+
+ // villsa [STRIFE] flag used for bouncing projectiles
+ MF_BOUNCE = 0x1000000,
+
+ // Don't spawn this object
+ // in death match mode (e.g. key cards).
+ MF_NOTDMATCH = 0x2000000,
+
+ // villsa [STRIFE] friendly towards player with matching flag
+ MF_ALLY = 0x4000000,
+
+ // villsa [STRIFE] 75% or 25% transparency? -- NEEDS VERIFICATION
+ MF_MVIS = 0x8000000,
+
+ // villsa [STRIFE] color translation
+ MF_COLORSWAP1 = 0x10000000,
+
+ // villsa [STRIFE] color translation
+ MF_COLORSWAP2 = 0x20000000,
+
+ // villsa [STRIFE] color translation
+ MF_COLORSWAP3 = 0x40000000,
+
+ // villsa [STRIFE] spectral entity, only damaged by spectral missiles
+ MF_SPECTRAL = 0x80000000,
+
+ // Player sprites in multiplayer modes are modified
+ // using an internal color lookup table for re-indexing.
+ // haleyjd 09/06/10: redid for Strife translations
+ MF_TRANSLATION = (MF_COLORSWAP1|MF_COLORSWAP2|MF_COLORSWAP3),
+
+ // Turns 0x10000000 into 0x01 to get a translation index.
+ // villsa [STRIFE] change from 26 to 28
+ MF_TRANSSHIFT = 28
+
+} mobjflag_t;
+
+
+// Map Object definition.
+//
+// [STRIFE]: Amazingly, only one modification was made to mobj_t over DOOM
+// 1.666, and that was the addition of the single-byte allegiance field for
+// tracking with which player friendly monsters are allied.
+//
+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 NULL),
+ // 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;
+
+ // [STRIFE] haleyjd 09/05/10:
+ // * In multiplayer this stores allegiance, for friends and teleport beacons
+ // * In single-player this tracks dialog state.
+ byte miscdata;
+
+} mobj_t;
+
+// haleyjd [STRIFE] Exported
+void P_CheckMissileSpawn (mobj_t* th);
+
+#endif
diff --git a/src/strife/p_plats.c b/src/strife/p_plats.c
new file mode 100644
index 00000000..51424760
--- /dev/null
+++ b/src/strife/p_plats.c
@@ -0,0 +1,362 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Plats (i.e. elevator platforms) code, raising/lowering.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+
+#include "i_system.h"
+#include "z_zone.h"
+#include "m_random.h"
+
+#include "doomdef.h"
+#include "p_local.h"
+
+#include "s_sound.h"
+
+// State.
+#include "doomstat.h"
+#include "r_state.h"
+
+// Data.
+#include "sounds.h"
+
+
+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(&plat->sector->soundorg, sfx_stnmov);
+ }
+
+ // villsa [STRIFE]
+ if(plat->type == slowDWUS)
+ {
+ if(!(leveltime&7))
+ S_StartSound(&plat->sector->soundorg, sfx_stnmov);
+ }
+
+
+ if(res == crushed && (!plat->crush))
+ {
+ plat->count = plat->wait;
+ plat->status = down;
+ S_StartSound(&plat->sector->soundorg, sfx_pstart);
+ }
+ else
+ {
+ if(res == pastdest)
+ {
+ plat->count = plat->wait;
+ plat->status = waiting;
+ S_StartSound(&plat->sector->soundorg, sfx_pstop);
+
+ switch(plat->type)
+ {
+ case blazeDWUS:
+ case downWaitUpStay:
+ case raiseAndChange:
+ case slowDWUS: // villsa [STRIFE]
+ case raiseToNearestAndChange:
+ P_RemoveActivePlat(plat);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ break;
+
+ case down:
+ res = T_MovePlane(plat->sector, plat->speed, plat->low, false, 0, -1);
+
+ // villsa [STRIFE]
+ if(plat->type == slowDWUS)
+ {
+ if(!(leveltime&7))
+ S_StartSound(&plat->sector->soundorg, sfx_stnmov);
+ }
+
+ if(res == pastdest)
+ {
+ plat->count = plat->wait;
+ plat->status = waiting;
+ S_StartSound(&plat->sector->soundorg,sfx_pstop);
+
+ // villsa [STRIFE]
+ if(plat->type == upWaitDownStay)
+ P_RemoveActivePlat(plat);
+ }
+ break;
+
+ case waiting:
+ if(!--plat->count)
+ {
+ if(plat->sector->floorheight == plat->low)
+ plat->status = up;
+ else
+ plat->status = down;
+ S_StartSound(&plat->sector->soundorg,sfx_pstart);
+ }
+
+ case in_stasis:
+ break;
+ }
+}
+
+
+//
+// EV_DoPlat
+//
+// 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(&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(&sec->soundorg, sfx_stnmov);
+ break;
+
+ // villsa [STRIFE]
+ case upWaitDownStay:
+ plat->speed = PLATSPEED * 4;
+ plat->high = P_FindNextHighestFloor(sec, sec->floorheight);
+ plat->low = sec->floorheight;
+ plat->wait = TICRATE * PLATWAIT;
+ plat->status = up;
+ S_StartSound(&sec->soundorg, sfx_pstart);
+ 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 = TICRATE * PLATWAIT;
+ plat->status = down;
+ S_StartSound(&sec->soundorg, sfx_pstart);
+ break;
+
+ // villsa [STRIFE]
+ case slowDWUS:
+ plat->speed = PLATSPEED;
+ plat->low = P_FindLowestFloorSurrounding(sec);
+
+ if(plat->low > sec->floorheight)
+ plat->low = sec->floorheight;
+
+ plat->high = sec->floorheight;
+ plat->wait = TICRATE * (PLATWAIT * 10);
+ plat->status = down;
+ S_StartSound(&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 = TICRATE * PLATWAIT;
+ plat->status = down;
+ S_StartSound(&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 = TICRATE * PLATWAIT;
+ plat->status = P_Random() & 1;
+
+ S_StartSound(&sec->soundorg, sfx_pstart);
+ break;
+ }
+
+ P_AddActivePlat(plat);
+ }
+ return rtn;
+}
+
+
+//
+// P_ActivateInStasis
+//
+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;
+ }
+}
+
+//
+// EV_StopPlat
+//
+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)NULL;
+ }
+}
+
+//
+// P_AddActivePlat
+//
+void P_AddActivePlat(plat_t* plat)
+{
+ int i;
+
+ for(i = 0; i < MAXPLATS; i++)
+ if (activeplats[i] == NULL)
+ {
+ activeplats[i] = plat;
+ return;
+ }
+
+ I_Error("P_AddActivePlat: no more plats!");
+}
+
+//
+// P_RemoveActivePlat
+//
+void P_RemoveActivePlat(plat_t* plat)
+{
+ int i;
+ for(i = 0; i < MAXPLATS; i++)
+ if(plat == activeplats[i])
+ {
+ (activeplats[i])->sector->specialdata = NULL;
+ P_RemoveThinker(&(activeplats[i])->thinker);
+ activeplats[i] = NULL;
+
+ return;
+ }
+
+ I_Error("P_RemoveActivePlat: can't find plat!");
+}
diff --git a/src/strife/p_pspr.c b/src/strife/p_pspr.c
new file mode 100644
index 00000000..80c53afd
--- /dev/null
+++ b/src/strife/p_pspr.c
@@ -0,0 +1,1012 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Weapon sprite animation, weapon objects.
+// Action functions for weapons.
+//
+//-----------------------------------------------------------------------------
+
+
+#include "doomdef.h"
+#include "d_event.h"
+
+#include "deh_misc.h"
+
+#include "m_random.h"
+#include "p_local.h"
+#include "s_sound.h"
+
+// State.
+#include "doomstat.h"
+
+// Data.
+#include "sounds.h"
+
+#include "p_pspr.h"
+
+#define LOWERSPEED FRACUNIT*6
+#define RAISESPEED FRACUNIT*6
+
+#define WEAPONBOTTOM 128*FRACUNIT
+#define WEAPONTOP 32*FRACUNIT
+
+
+
+//
+// P_SetPsprite
+//
+// [STRIFE]
+// villsa: Removed psprite sx, sy modification via misc1/2
+//
+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 = NULL;
+ break;
+ }
+
+ state = &states[stnum];
+ psp->state = state;
+ psp->tics = state->tics; // could be 0
+
+ // villsa [STRIFE] unused
+ /*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
+}
+
+// haleyjd 09/06/10: [STRIFE] Removed P_CalcSwing
+
+//
+// P_BringUpWeapon
+// Starts bringing the pending weapon up
+// from the bottom of the screen.
+// Uses player
+//
+// villsa [STRIFE] Modifications for Strife weapons
+//
+void P_BringUpWeapon (player_t* player)
+{
+ statenum_t newstate;
+
+ if (player->pendingweapon == wp_nochange)
+ player->pendingweapon = player->readyweapon;
+
+ if (player->pendingweapon == wp_flame)
+ S_StartSound (player->mo, sfx_flidl); // villsa [STRIFE] flame sounds
+
+ newstate = weaponinfo[player->pendingweapon].upstate;
+
+ player->psprites[ps_weapon].sy = WEAPONBOTTOM;
+ P_SetPsprite (player, ps_weapon, newstate);
+
+ // villsa [STRIFE] set various flash states
+ if(player->pendingweapon == wp_elecbow)
+ P_SetPsprite(player, ps_flash, S_XBOW_10); // 31
+ else if(player->pendingweapon == wp_sigil && player->sigiltype)
+ P_SetPsprite(player, ps_flash, S_SIGH_00 + player->sigiltype); // 117
+ else
+ P_SetPsprite(player, ps_flash, S_NULL);
+
+ player->pendingweapon = wp_nochange;
+}
+
+//
+// P_CheckAmmo
+// Returns true if there is enough ammo to shoot.
+// If not, selects the next weapon to use.
+//
+// villsa [STRIFE] Changes to handle Strife weapons
+//
+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_torpedo)
+ count = 30;
+ else if (player->readyweapon == wp_mauler)
+ count = 20;
+ 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.
+
+ // villsa [STRIFE] new weapon preferences
+ if (player->weaponowned[wp_mauler] && player->ammo[am_cell] >= 20)
+ player->pendingweapon = wp_mauler;
+
+ else if(player->weaponowned[wp_rifle] && player->ammo[am_bullets])
+ player->pendingweapon = wp_rifle;
+
+ else if (player->weaponowned[wp_elecbow] && player->ammo[am_elecbolts])
+ player->pendingweapon = wp_elecbow;
+
+ else if (player->weaponowned[wp_missile] && player->ammo[am_missiles])
+ player->pendingweapon = wp_missile;
+
+ else if (player->weaponowned[wp_flame] && player->ammo[am_cell])
+ player->pendingweapon = wp_flame;
+
+ else if (player->weaponowned[wp_hegrenade] && player->ammo[am_hegrenades])
+ player->pendingweapon = wp_hegrenade;
+
+ else if (player->weaponowned[wp_poisonbow] && player->ammo[am_poisonbolts])
+ player->pendingweapon = wp_poisonbow;
+
+ else if (player->weaponowned[wp_wpgrenade] && player->ammo[am_wpgrenades])
+ player->pendingweapon = wp_wpgrenade;
+
+ // BUG: This will *never* be selected for an automatic switch because the
+ // normal Mauler is higher priority and uses less ammo.
+ else if (player->weaponowned[wp_torpedo] && player->ammo[am_cell] >= 30)
+ player->pendingweapon = wp_torpedo;
+
+ else
+ player->pendingweapon = wp_fist;
+
+
+ // Now set appropriate weapon overlay.
+ P_SetPsprite(player, ps_weapon, weaponinfo[player->readyweapon].downstate);
+
+ return false;
+}
+
+
+//
+// P_FireWeapon.
+//
+// villsa [STRIFE] Changes for player state and weapons
+//
+void P_FireWeapon (player_t* player)
+{
+ statenum_t newstate;
+
+ if (!P_CheckAmmo (player))
+ return;
+
+ P_SetMobjState (player->mo, S_PLAY_05); // 292
+ newstate = weaponinfo[player->readyweapon].atkstate;
+ P_SetPsprite (player, ps_weapon, newstate);
+
+ // villsa [STRIFE] exclude these weapons from causing noise
+ if(player->readyweapon > wp_elecbow && player->readyweapon != wp_poisonbow)
+ P_NoiseAlert (player->mo, player->mo);
+}
+
+
+
+//
+// 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_05] || // 292
+ player->mo->state == &states[S_PLAY_06]) // 293
+ {
+ P_SetMobjState (player->mo, S_PLAY_00); // 287
+ }
+
+ // villsa [STRIFE] check for wp_flame instead of chainsaw
+ // haleyjd 09/06/10: fixed state (00 rather than 01)
+ if (player->readyweapon == wp_flame
+ && psp->state == &states[S_FLMT_00]) // 62
+ {
+ S_StartSound (player->mo, sfx_flidl);
+ }
+
+ // 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 torpedo do not auto fire
+ if (player->cmd.buttons & BT_ATTACK)
+ {
+ if ( !player->attackdown
+ || (player->readyweapon != wp_missile
+ && player->readyweapon != wp_torpedo)) // villsa [STRIFE] replace bfg with torpedo
+ {
+ 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);
+ }
+}
+
+//
+// A_CheckReload
+//
+void A_CheckReload(player_t* player, pspdef_t* psp)
+{
+ P_CheckAmmo(player);
+
+ // villsa [STRIFE] set animating sprite for crossbow
+ if(player->readyweapon == wp_elecbow)
+ P_SetPsprite(player, player->readyweapon, S_XBOW_10);
+}
+
+
+
+//
+// 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_06);
+ 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;
+ int sound;
+ int stamina;
+ int t;
+
+ // villsa [STRIFE] new damage formula
+ // haleyjd 09/19/10: seriously corrected...
+ stamina = player->stamina;
+ damage = (P_Random() & ((stamina/10) + 7)) * ((stamina/10) + 2);
+
+ if(player->powers[pw_strength])
+ damage *= 10;
+
+ angle = player->mo->angle;
+ t = P_Random();
+ angle += (t - P_Random()) << 18;
+ slope = P_AimLineAttack (player->mo, angle, PLAYERMELEERANGE);
+ P_LineAttack (player->mo, angle, PLAYERMELEERANGE, slope, damage);
+
+ // turn to face target
+ if(linetarget)
+ {
+ // villsa [STRIFE] check for non-flesh types
+ if(linetarget->flags & MF_NOBLOOD)
+ sound = sfx_mtalht;
+ else
+ sound = sfx_meatht;
+
+ S_StartSound (player->mo, sound);
+ player->mo->angle = R_PointToAngle2 (player->mo->x,
+ player->mo->y,
+ linetarget->x,
+ linetarget->y);
+
+ // villsa [STRIFE] apply flag
+ player->mo->flags |= MF_JUSTATTACKED;
+
+ // villsa [STRIFE] do punch alert routine
+ P_DoPunchAlert(player->mo, linetarget);
+ }
+ else
+ S_StartSound (player->mo, sfx_swish);
+}
+
+
+//
+// A_FireFlameThrower
+//
+// villsa [STRIFE] new codepointer
+//
+void A_FireFlameThrower(player_t* player, pspdef_t* psp)
+{
+ mobj_t* mo;
+ int t;
+
+ P_SetMobjState(player->mo, S_PLAY_06);
+ player->ammo[weaponinfo[player->readyweapon].ammo]--;
+ t = P_Random();
+ player->mo->angle += (t - P_Random()) << 18;
+
+ mo = P_SpawnPlayerMissile(player->mo, MT_SFIREBALL);
+ mo->momz += (5*FRACUNIT);
+}
+
+//
+// A_FireMissile
+//
+// villsa [STRIFE] completly new compared to the original
+//
+void A_FireMissile(player_t* player, pspdef_t* psp)
+{
+ angle_t an;
+ int t;
+
+ // haleyjd 09/19/10: I previously missed an add op that meant it should be
+ // accuracy * 5, not 4. Checks out with other sources.
+ an = player->mo->angle;
+ t = P_Random();
+ player->mo->angle += (t - P_Random()) << (19 - (player->accuracy * 5 / 100));
+ P_SetMobjState(player->mo, S_PLAY_06);
+ player->ammo[weaponinfo[player->readyweapon].ammo]--;
+ P_SpawnPlayerMissile(player->mo, MT_MINIMISSLE);
+ player->mo->angle = an;
+}
+
+//
+// A_FireMauler2
+//
+// villsa [STRIFE] - new codepointer
+//
+void A_FireMauler2(player_t* player, pspdef_t* pspr)
+{
+ P_SetMobjState(player->mo, S_PLAY_06);
+ P_DamageMobj(player->mo, player->mo, NULL, 20);
+ player->ammo[weaponinfo[player->readyweapon].ammo] -= 30;
+ P_SpawnPlayerMissile(player->mo, MT_TORPEDO);
+ P_Thrust(player, player->mo->angle + ANG180, 512000);
+}
+
+//
+// A_FireGrenade
+//
+// villsa [STRIFE] - new codepointer
+//
+void A_FireGrenade(player_t* player, pspdef_t* pspr)
+{
+ mobjtype_t type;
+ mobj_t* mo;
+ state_t* st1;
+ state_t* st2;
+ angle_t an;
+ fixed_t radius;
+
+ // decide on what type of grenade to spawn
+ if(player->readyweapon == wp_hegrenade)
+ {
+ type = MT_HEGRENADE;
+ }
+ else if(player->readyweapon == wp_wpgrenade)
+ {
+ type = MT_PGRENADE;
+ }
+ else
+ {
+ type = MT_HEGRENADE;
+ fprintf(stderr, "Warning: A_FireGrenade used on wrong weapon!\n");
+ }
+
+ player->ammo[weaponinfo[player->readyweapon].ammo]--;
+
+ // set flash frame
+ st1 = &states[(pspr->state - states) + weaponinfo[player->readyweapon].flashstate];
+ st2 = &states[weaponinfo[player->readyweapon].atkstate];
+ P_SetPsprite(player, ps_flash, st1 - st2);
+
+ player->mo->z += 32*FRACUNIT; // ugh
+ mo = P_SpawnMortar(player->mo, type);
+ player->mo->z -= 32*FRACUNIT; // ugh
+
+ // change momz based on player's pitch
+ mo->momz = FixedMul((player->pitch<<FRACBITS) / 160, mo->info->speed) + (8*FRACUNIT);
+ S_StartSound(mo, mo->info->seesound);
+
+ radius = mobjinfo[type].radius + player->mo->info->radius;
+ an = (player->mo->angle >> ANGLETOFINESHIFT);
+
+ mo->x += FixedMul(finecosine[an], radius + (4*FRACUNIT));
+ mo->y += FixedMul(finesine[an], radius + (4*FRACUNIT));
+
+ // shoot grenade from left or right side?
+ if(&states[weaponinfo[player->readyweapon].atkstate] == pspr->state)
+ an = (player->mo->angle - ANG90) >> ANGLETOFINESHIFT;
+ else
+ an = (player->mo->angle + ANG90) >> ANGLETOFINESHIFT;
+
+ mo->x += FixedMul((15*FRACUNIT), finecosine[an]);
+ mo->y += FixedMul((15*FRACUNIT), finesine[an]);
+
+ // set bounce flag
+ mo->flags |= MF_BOUNCE;
+}
+
+//
+// A_FireElectricBolt
+// villsa [STRIFE] - new codepointer
+//
+
+void A_FireElectricBolt(player_t* player, pspdef_t* pspr)
+{
+ angle_t an = player->mo->angle;
+ int t;
+
+ // haleyjd 09/19/10: Use 5 mul on accuracy here as well
+ t = P_Random();
+ player->mo->angle += (t - P_Random()) << (18 - (player->accuracy * 5 / 100));
+ player->ammo[weaponinfo[player->readyweapon].ammo]--;
+ P_SpawnPlayerMissile(player->mo, MT_ELECARROW);
+ player->mo->angle = an;
+ S_StartSound(player->mo, sfx_xbow);
+}
+
+//
+// A_FirePoisonBolt
+// villsa [STRIFE] - new codepointer
+//
+
+void A_FirePoisonBolt(player_t* player, pspdef_t* pspr)
+{
+ angle_t an = player->mo->angle;
+ int t;
+
+ // haleyjd 09/19/10: Use 5 mul on accuracy here as well
+ t = P_Random();
+ player->mo->angle += (t - P_Random()) << (18 - (player->accuracy * 5 / 100));
+ player->ammo[weaponinfo[player->readyweapon].ammo]--;
+ P_SpawnPlayerMissile(player->mo, MT_POISARROW);
+ player->mo->angle = an;
+ S_StartSound(player->mo, sfx_xbow);
+}
+
+//
+// P_BulletSlope
+// Sets a slope so a near miss is at aproximately
+// the height of the intended target
+//
+// haleyjd 09/06/10 [STRIFE] Modified with a little target hack...
+//
+fixed_t bulletslope;
+
+
+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);
+ }
+ }
+
+ // haleyjd 09/06/10: [STRIFE] Somebody added this here, and without it, you
+ // will get spurious crashing in routines such as P_LookForPlayers!
+ if(linetarget)
+ mo->target = linetarget;
+}
+
+
+//
+// P_GunShot
+//
+// [STRIFE] Modifications to support accuracy.
+//
+void
+P_GunShot
+( mobj_t* mo,
+ boolean accurate )
+{
+ angle_t angle;
+ int damage;
+
+ angle = mo->angle;
+
+ // villsa [STRIFE] apply player accuracy
+ // haleyjd 09/18/10: made some corrections: use 5x accuracy;
+ // eliminated order-of-evaluation dependency
+ if (!accurate)
+ {
+ int t = P_Random();
+ angle += (t - P_Random()) << (20 - ((mo->player->accuracy * 5) / 100));
+ }
+
+ // haleyjd 09/18/10 [STRIFE] corrected damage formula and moved down to
+ // preserve proper P_Random call order.
+ damage = 4 * (P_Random() % 3 + 1);
+
+ P_LineAttack (mo, angle, MISSILERANGE, bulletslope, damage);
+}
+
+//
+// A_FireRifle
+//
+// villsa [STRIFE] - new codepointer
+//
+void A_FireRifle(player_t* player, pspdef_t* pspr)
+{
+ S_StartSound(player->mo, sfx_rifle);
+
+ if(player->ammo[weaponinfo[player->readyweapon].ammo])
+ {
+ P_SetMobjState(player->mo, S_PLAY_06); // 293
+ player->ammo[weaponinfo[player->readyweapon].ammo]--;
+ P_BulletSlope(player->mo);
+ P_GunShot(player->mo, !player->refire);
+ }
+}
+
+//
+// A_FireMauler1
+//
+// villsa [STRIFE] - new codepointer
+//
+void A_FireMauler1(player_t* player, pspdef_t* pspr)
+{
+ int i;
+ angle_t angle;
+ int damage;
+
+ // haleyjd 09/18/10: Corrected ammo check to use >=
+ if(player->ammo[weaponinfo[player->readyweapon].ammo] >= 20)
+ {
+ player->ammo[weaponinfo[player->readyweapon].ammo] -= 20;
+ P_BulletSlope(player->mo);
+ S_StartSound(player->mo, sfx_pgrdat);
+
+ for(i = 0; i < 20; i++)
+ {
+ int t;
+ damage = 5*(P_Random ()%3+1);
+ angle = player->mo->angle;
+ t = P_Random();
+ angle += (t - P_Random()) << 19;
+ t = P_Random();
+ P_LineAttack(player->mo, angle, 2112*FRACUNIT,
+ bulletslope + ((t - P_Random())<<5), damage);
+ }
+ }
+}
+
+//
+// A_SigilSound
+//
+// villsa [STRIFE] - new codepointer
+//
+void A_SigilSound(player_t* player, pspdef_t* pspr)
+{
+ S_StartSound(player->mo, sfx_siglup);
+ player->extralight = 2;
+
+}
+
+//
+// A_FireSigil
+//
+// villsa [STRIFE] - new codepointer
+//
+void A_FireSigil(player_t* player, pspdef_t* pspr)
+{
+ mobj_t* mo;
+ angle_t an;
+ int i;
+
+ // keep info on armor because sigil does piercing damage
+ i = player->armortype;
+ player->armortype = 0;
+
+ // BUG: setting inflictor causes firing the Sigil to always push the player
+ // toward the east, no matter what direction he is facing.
+ P_DamageMobj(player->mo, player->mo, NULL, 4 * (player->sigiltype + 1));
+
+ // restore armor
+ player->armortype = i;
+
+ S_StartSound(player->mo, sfx_siglup);
+
+ switch(player->sigiltype)
+ {
+ // falling lightning bolts from the sky
+ case 0:
+ P_BulletSlope(player->mo);
+ if(linetarget)
+ {
+ // haleyjd 09/18/10: corrected z coordinate
+ mo = P_SpawnMobj(linetarget->x, linetarget->y, ONFLOORZ,
+ MT_SIGIL_A_GROUND);
+ mo->tracer = linetarget;
+ }
+ else
+ {
+ an = player->mo->angle>>ANGLETOFINESHIFT;
+ mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z,
+ MT_SIGIL_A_GROUND);
+ mo->momx += FixedMul((28*FRACUNIT), finecosine[an]);
+ mo->momy += FixedMul((28*FRACUNIT), finesine[an]);
+ }
+ mo->health = -1;
+ mo->target = player->mo;
+ break;
+
+ // simple projectile
+ case 1:
+ P_SpawnPlayerMissile(player->mo, MT_SIGIL_B_SHOT)->health = -1;
+ break;
+
+ // spread shot
+ case 2:
+ player->mo->angle -= ANG90; // starting at 270...
+ for(i = 0; i < 20; i++) // increment by 1/10 of 90, 20 times.
+ {
+ player->mo->angle += (ANG90 / 10);
+ mo = P_SpawnMortar(player->mo, MT_SIGIL_C_SHOT);
+ mo->health = -1;
+ mo->z = player->mo->z + (32*FRACUNIT);
+ }
+ player->mo->angle -= ANG90; // subtract off the extra 90
+ break;
+
+ // tracer attack
+ case 3:
+ P_BulletSlope(player->mo);
+ if(linetarget)
+ {
+ mo = P_SpawnPlayerMissile(player->mo, MT_SIGIL_D_SHOT);
+ mo->tracer = linetarget;
+ }
+ else
+ {
+ an = player->mo->angle >> ANGLETOFINESHIFT;
+ mo = P_SpawnPlayerMissile(player->mo, MT_SIGIL_D_SHOT);
+ mo->momx += FixedMul(mo->info->speed, finecosine[an]);
+ mo->momy += FixedMul(mo->info->speed, finesine[an]);
+ }
+ mo->health = -1;
+ break;
+
+ // mega blast
+ case 4:
+ mo = P_SpawnPlayerMissile(player->mo, MT_SIGIL_E_SHOT);
+ mo->health = -1;
+ if(!linetarget)
+ {
+ an = player->pitch >> ANGLETOFINESHIFT;
+ mo->momz += FixedMul(finesine[an], mo->info->speed);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+//
+// A_GunFlashThinker
+//
+// villsa [STRIFE] - new codepointer
+//
+void A_GunFlashThinker(player_t* player, pspdef_t* pspr)
+{
+ if(player->readyweapon == wp_sigil && player->sigiltype)
+ P_SetPsprite(player, ps_flash, S_SIGH_00 + player->sigiltype);
+ else
+ P_SetPsprite(player, ps_flash, S_NULL);
+
+}
+
+
+//
+// ?
+//
+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_SigilShock
+//
+// villsa [STRIFE] - new codepointer
+//
+void A_SigilShock (player_t *player, pspdef_t *psp)
+{
+ player->extralight = -3;
+}
+
+//
+// A_TorpedoExplode
+//
+// villsa [STRIFE] - new codepointer
+//
+void A_TorpedoExplode(mobj_t* actor)
+{
+ int i;
+
+ actor->angle -= ANG180;
+
+ for(i = 0; i < 80; i++)
+ {
+ actor->angle += (ANG90 / 20);
+ P_SpawnMortar(actor, MT_TORPEDOSPREAD)->target = actor->target;
+ }
+}
+
+//
+// A_MaulerSound
+//
+// villsa [STRIFE] - new codepointer
+//
+void A_MaulerSound(player_t *player, pspdef_t *psp)
+{
+ int t;
+ S_StartSound(player->mo, sfx_proton);
+ t = P_Random();
+ psp->sx += (t - P_Random()) << 10;
+ t = P_Random();
+ psp->sy += (t - P_Random()) << 10;
+
+}
+
+
+//
+// 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 = NULL;
+
+ // 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;
+
+ // villsa [STRIFE] extra stuff for targeter
+ player->psprites[ps_targleft].sx =
+ (160*FRACUNIT) - ((100 - player->accuracy) << FRACBITS);
+
+ player->psprites[ps_targright].sx =
+ ((100 - player->accuracy) << FRACBITS) + (160*FRACUNIT);
+}
+
+
diff --git a/src/strife/p_pspr.h b/src/strife/p_pspr.h
new file mode 100644
index 00000000..64341b15
--- /dev/null
+++ b/src/strife/p_pspr.h
@@ -0,0 +1,87 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// 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,
+ ps_targcenter, // villsa [STRIFE]
+ ps_targleft, // villsa [STRIFE]
+ ps_targright, // villsa [STRIFE]
+ NUMPSPRITES
+
+} psprnum_t;
+
+typedef struct
+{
+ state_t* state; // a NULL state means not active
+ int tics;
+ fixed_t sx;
+ fixed_t sy;
+
+} pspdef_t;
+
+typedef struct player_s *playerptr;
+
+// haleyjd [STRIFE] Exported
+void P_SetPsprite(playerptr player, int position, statenum_t stnum);
+
+#endif
diff --git a/src/strife/p_saveg.c b/src/strife/p_saveg.c
new file mode 100644
index 00000000..bc014de9
--- /dev/null
+++ b/src/strife/p_saveg.c
@@ -0,0 +1,2215 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Archiving: SaveGame I/O.
+//
+//-----------------------------------------------------------------------------
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "dstrings.h"
+#include "deh_main.h"
+#include "i_system.h"
+#include "z_zone.h"
+#include "p_local.h"
+#include "p_saveg.h"
+
+// State.
+#include "doomstat.h"
+#include "r_state.h"
+
+#define SAVEGAME_EOF 0x1d
+
+// haleyjd 09/28/10: [STRIFE] VERSIONSIZE == 8
+#define VERSIONSIZE 8
+
+FILE *save_stream;
+int savegamelength;
+boolean savegame_error;
+
+// Get the filename of a temporary file to write the savegame to. After
+// the file has been successfully saved, it will be renamed to the
+// real file.
+
+char *P_TempSaveGameFile(void)
+{
+ static char *filename = NULL;
+
+ if (filename == NULL)
+ {
+ filename = malloc(strlen(savegamedir) + 32);
+ }
+
+ sprintf(filename, "%stemp.dsg", savegamedir);
+
+ return filename;
+}
+
+// Get the filename of the save game file to use for the specified slot.
+
+char *P_SaveGameFile(int slot)
+{
+ static char *filename = NULL;
+ char basename[32];
+
+ if (filename == NULL)
+ {
+ filename = malloc(strlen(savegamedir) + 32);
+ }
+
+ DEH_snprintf(basename, 32, SAVEGAMENAME "%d.dsg", slot);
+
+ sprintf(filename, "%s%s", savegamedir, basename);
+
+ return filename;
+}
+
+// Endian-safe integer read/write functions
+
+static byte saveg_read8(void)
+{
+ byte result;
+
+ if (fread(&result, 1, 1, save_stream) < 1)
+ {
+ if (!savegame_error)
+ {
+ fprintf(stderr, "saveg_read8: Unexpected end of file while "
+ "reading save game\n");
+
+ savegame_error = true;
+ }
+ }
+
+ return result;
+}
+
+static void saveg_write8(byte value)
+{
+ if (fwrite(&value, 1, 1, save_stream) < 1)
+ {
+ if (!savegame_error)
+ {
+ fprintf(stderr, "saveg_write8: Error while writing save game\n");
+
+ savegame_error = true;
+ }
+ }
+}
+
+static short saveg_read16(void)
+{
+ int result;
+
+ result = saveg_read8();
+ result |= saveg_read8() << 8;
+
+ return result;
+}
+
+static void saveg_write16(short value)
+{
+ saveg_write8(value & 0xff);
+ saveg_write8((value >> 8) & 0xff);
+}
+
+static int saveg_read32(void)
+{
+ int result;
+
+ result = saveg_read8();
+ result |= saveg_read8() << 8;
+ result |= saveg_read8() << 16;
+ result |= saveg_read8() << 24;
+
+ return result;
+}
+
+static void saveg_write32(int value)
+{
+ saveg_write8(value & 0xff);
+ saveg_write8((value >> 8) & 0xff);
+ saveg_write8((value >> 16) & 0xff);
+ saveg_write8((value >> 24) & 0xff);
+}
+
+// Pad to 4-byte boundaries
+
+static void saveg_read_pad(void)
+{
+ unsigned long pos;
+ int padding;
+ int i;
+
+ pos = ftell(save_stream);
+
+ padding = (4 - (pos & 3)) & 3;
+
+ for (i=0; i<padding; ++i)
+ {
+ saveg_read8();
+ }
+}
+
+static void saveg_write_pad(void)
+{
+ unsigned long pos;
+ int padding;
+ int i;
+
+ pos = ftell(save_stream);
+
+ padding = (4 - (pos & 3)) & 3;
+
+ for (i=0; i<padding; ++i)
+ {
+ saveg_write8(0);
+ }
+}
+
+
+// Pointers
+
+static void *saveg_readp(void)
+{
+ return (void *) saveg_read32();
+}
+
+static void saveg_writep(void *p)
+{
+ saveg_write32((int) p);
+}
+
+// Enum values are 32-bit integers.
+
+#define saveg_read_enum saveg_read32
+#define saveg_write_enum saveg_write32
+
+//
+// Structure read/write functions
+//
+
+//
+// mapthing_t
+//
+
+static void saveg_read_mapthing_t(mapthing_t *str)
+{
+ // short x;
+ str->x = saveg_read16();
+
+ // short y;
+ str->y = saveg_read16();
+
+ // short angle;
+ str->angle = saveg_read16();
+
+ // short type;
+ str->type = saveg_read16();
+
+ // short options;
+ str->options = saveg_read16();
+}
+
+static void saveg_write_mapthing_t(mapthing_t *str)
+{
+ // short x;
+ saveg_write16(str->x);
+
+ // short y;
+ saveg_write16(str->y);
+
+ // short angle;
+ saveg_write16(str->angle);
+
+ // short type;
+ saveg_write16(str->type);
+
+ // short options;
+ saveg_write16(str->options);
+}
+
+//
+// actionf_t
+//
+
+static void saveg_read_actionf_t(actionf_t *str)
+{
+ // actionf_p1 acp1;
+ str->acp1 = saveg_readp();
+}
+
+static void saveg_write_actionf_t(actionf_t *str)
+{
+ // actionf_p1 acp1;
+ saveg_writep(str->acp1);
+}
+
+//
+// think_t
+//
+// This is just an actionf_t.
+//
+
+#define saveg_read_think_t saveg_read_actionf_t
+#define saveg_write_think_t saveg_write_actionf_t
+
+//
+// thinker_t
+//
+
+static void saveg_read_thinker_t(thinker_t *str)
+{
+ // struct thinker_s* prev;
+ str->prev = saveg_readp();
+
+ // struct thinker_s* next;
+ str->next = saveg_readp();
+
+ // think_t function;
+ saveg_read_think_t(&str->function);
+}
+
+static void saveg_write_thinker_t(thinker_t *str)
+{
+ // struct thinker_s* prev;
+ saveg_writep(str->prev);
+
+ // struct thinker_s* next;
+ saveg_writep(str->next);
+
+ // think_t function;
+ saveg_write_think_t(&str->function);
+}
+
+//
+// mobj_t
+//
+// haleyjd 09/28/10: [STRIFE] Changed to match Strife binary mobj_t structure.
+//
+
+static void saveg_read_mobj_t(mobj_t *str)
+{
+ int pl;
+
+ // thinker_t thinker;
+ saveg_read_thinker_t(&str->thinker);
+
+ // fixed_t x;
+ str->x = saveg_read32();
+
+ // fixed_t y;
+ str->y = saveg_read32();
+
+ // fixed_t z;
+ str->z = saveg_read32();
+
+ // struct mobj_s* snext;
+ str->snext = saveg_readp();
+
+ // struct mobj_s* sprev;
+ str->sprev = saveg_readp();
+
+ // angle_t angle;
+ str->angle = saveg_read32();
+
+ // spritenum_t sprite;
+ str->sprite = saveg_read_enum();
+
+ // int frame;
+ str->frame = saveg_read32();
+
+ // struct mobj_s* bnext;
+ str->bnext = saveg_readp();
+
+ // struct mobj_s* bprev;
+ str->bprev = saveg_readp();
+
+ // struct subsector_s* subsector;
+ str->subsector = saveg_readp();
+
+ // fixed_t floorz;
+ str->floorz = saveg_read32();
+
+ // fixed_t ceilingz;
+ str->ceilingz = saveg_read32();
+
+ // fixed_t radius;
+ str->radius = saveg_read32();
+
+ // fixed_t height;
+ str->height = saveg_read32();
+
+ // fixed_t momx;
+ str->momx = saveg_read32();
+
+ // fixed_t momy;
+ str->momy = saveg_read32();
+
+ // fixed_t momz;
+ str->momz = saveg_read32();
+
+ // int validcount;
+ str->validcount = saveg_read32();
+
+ // mobjtype_t type;
+ str->type = saveg_read_enum();
+
+ // mobjinfo_t* info;
+ str->info = saveg_readp();
+
+ // int tics;
+ str->tics = saveg_read32();
+
+ // state_t* state;
+ str->state = &states[saveg_read32()];
+
+ // int flags;
+ str->flags = saveg_read32();
+
+ // int health;
+ str->health = saveg_read32();
+
+ // int movedir;
+ str->movedir = saveg_read32();
+
+ // int movecount;
+ str->movecount = saveg_read32();
+
+ // struct mobj_s* target;
+ str->target = saveg_readp();
+
+ // int reactiontime;
+ str->reactiontime = saveg_read32();
+
+ // int threshold;
+ str->threshold = saveg_read32();
+
+ // struct player_s* player;
+ pl = saveg_read32();
+
+ if (pl > 0)
+ {
+ str->player = &players[pl - 1];
+ str->player->mo = str;
+ }
+ else
+ {
+ str->player = NULL;
+ }
+
+ // int lastlook;
+ str->lastlook = saveg_read32();
+
+ // mapthing_t spawnpoint;
+ saveg_read_mapthing_t(&str->spawnpoint);
+
+ // struct mobj_s* tracer;
+ str->tracer = saveg_readp();
+
+ // byte miscdata;
+ str->miscdata = saveg_read8(); // [STRIFE] Only change to mobj_t.
+}
+
+static void saveg_write_mobj_t(mobj_t *str)
+{
+ // thinker_t thinker;
+ saveg_write_thinker_t(&str->thinker);
+
+ // fixed_t x;
+ saveg_write32(str->x);
+
+ // fixed_t y;
+ saveg_write32(str->y);
+
+ // fixed_t z;
+ saveg_write32(str->z);
+
+ // struct mobj_s* snext;
+ saveg_writep(str->snext);
+
+ // struct mobj_s* sprev;
+ saveg_writep(str->sprev);
+
+ // angle_t angle;
+ saveg_write32(str->angle);
+
+ // spritenum_t sprite;
+ saveg_write_enum(str->sprite);
+
+ // int frame;
+ saveg_write32(str->frame);
+
+ // struct mobj_s* bnext;
+ saveg_writep(str->bnext);
+
+ // struct mobj_s* bprev;
+ saveg_writep(str->bprev);
+
+ // struct subsector_s* subsector;
+ saveg_writep(str->subsector);
+
+ // fixed_t floorz;
+ saveg_write32(str->floorz);
+
+ // fixed_t ceilingz;
+ saveg_write32(str->ceilingz);
+
+ // fixed_t radius;
+ saveg_write32(str->radius);
+
+ // fixed_t height;
+ saveg_write32(str->height);
+
+ // fixed_t momx;
+ saveg_write32(str->momx);
+
+ // fixed_t momy;
+ saveg_write32(str->momy);
+
+ // fixed_t momz;
+ saveg_write32(str->momz);
+
+ // int validcount;
+ saveg_write32(str->validcount);
+
+ // mobjtype_t type;
+ saveg_write_enum(str->type);
+
+ // mobjinfo_t* info;
+ saveg_writep(str->info);
+
+ // int tics;
+ saveg_write32(str->tics);
+
+ // state_t* state;
+ saveg_write32(str->state - states);
+
+ // int flags;
+ saveg_write32(str->flags);
+
+ // int health;
+ saveg_write32(str->health);
+
+ // int movedir;
+ saveg_write32(str->movedir);
+
+ // int movecount;
+ saveg_write32(str->movecount);
+
+ // struct mobj_s* target;
+ saveg_writep(str->target);
+
+ // int reactiontime;
+ saveg_write32(str->reactiontime);
+
+ // int threshold;
+ saveg_write32(str->threshold);
+
+ // struct player_s* player;
+ if (str->player)
+ {
+ saveg_write32(str->player - players + 1);
+ }
+ else
+ {
+ saveg_write32(0);
+ }
+
+ // int lastlook;
+ saveg_write32(str->lastlook);
+
+ // mapthing_t spawnpoint;
+ saveg_write_mapthing_t(&str->spawnpoint);
+
+ // struct mobj_s* tracer;
+ saveg_writep(str->tracer);
+
+ // byte miscdata;
+ saveg_write8(str->miscdata); // [STRIFE] Only change to mobj_t.
+}
+
+
+//
+// ticcmd_t
+//
+// haleyjd 09/28/10: [STRIFE] Modified for Strife binary ticcmd_t structure.
+//
+
+static void saveg_read_ticcmd_t(ticcmd_t *str)
+{
+ // signed char forwardmove;
+ str->forwardmove = saveg_read8();
+
+ // signed char sidemove;
+ str->sidemove = saveg_read8();
+
+ // short angleturn;
+ str->angleturn = saveg_read16();
+
+ // short consistancy;
+ // STRIFE-FIXME: throwing away top byte of consistancy until
+ // the true Strife ticcmd_t structure is available.
+ str->consistancy = (byte)saveg_read16();
+
+ // byte chatchar;
+ str->chatchar = saveg_read8();
+
+ // byte buttons;
+ str->buttons = saveg_read8();
+
+ // byte buttons2;
+ str->buttons2 = saveg_read8(); // [STRIFE]
+
+ // int inventory;
+ str->inventory = saveg_read32(); // [STRIFE]
+}
+
+static void saveg_write_ticcmd_t(ticcmd_t *str)
+{
+ // signed char forwardmove;
+ saveg_write8(str->forwardmove);
+
+ // signed char sidemove;
+ saveg_write8(str->sidemove);
+
+ // short angleturn;
+ saveg_write16(str->angleturn);
+
+ // short consistancy;
+ saveg_write16(str->consistancy);
+
+ // byte chatchar;
+ saveg_write8(str->chatchar);
+
+ // byte buttons;
+ saveg_write8(str->buttons);
+
+ // byte buttons2;
+ saveg_write8(str->buttons2); // [STRIFE]
+
+ // int inventory;
+ saveg_write32(str->inventory); // [STRIFE]
+}
+
+//
+// pspdef_t
+//
+
+static void saveg_read_pspdef_t(pspdef_t *str)
+{
+ int state;
+
+ // state_t* state;
+ state = saveg_read32();
+
+ if (state > 0)
+ {
+ str->state = &states[state];
+ }
+ else
+ {
+ str->state = NULL;
+ }
+
+ // int tics;
+ str->tics = saveg_read32();
+
+ // fixed_t sx;
+ str->sx = saveg_read32();
+
+ // fixed_t sy;
+ str->sy = saveg_read32();
+}
+
+static void saveg_write_pspdef_t(pspdef_t *str)
+{
+ // state_t* state;
+ if (str->state)
+ {
+ saveg_write32(str->state - states);
+ }
+ else
+ {
+ saveg_write32(0);
+ }
+
+ // int tics;
+ saveg_write32(str->tics);
+
+ // fixed_t sx;
+ saveg_write32(str->sx);
+
+ // fixed_t sy;
+ saveg_write32(str->sy);
+}
+
+//
+// inventory_t
+//
+// haleyjd 09/28/10: [STRIFE] handle inventory input/output
+//
+
+static void saveg_read_inventory_t(inventory_t *str)
+{
+ //int sprite;
+ str->sprite = saveg_read32();
+
+ //int type;
+ str->type = saveg_read32();
+
+ //int amount;
+ str->amount = saveg_read32();
+}
+
+static void saveg_write_inventory_t(inventory_t *str)
+{
+ saveg_write32(str->sprite);
+ saveg_write32(str->type);
+ saveg_write32(str->amount);
+}
+
+//
+// player_t
+//
+// haleyjd 09/28/10: [STRIFE] Modified for Strife binary player_t structure.
+//
+
+static void saveg_read_player_t(player_t *str)
+{
+ int i;
+
+ // mobj_t* mo;
+ str->mo = saveg_readp();
+
+ // playerstate_t playerstate;
+ str->playerstate = saveg_read_enum();
+
+ // ticcmd_t cmd;
+ saveg_read_ticcmd_t(&str->cmd);
+
+ // fixed_t viewz;
+ str->viewz = saveg_read32();
+
+ // fixed_t viewheight;
+ str->viewheight = saveg_read32();
+
+ // fixed_t deltaviewheight;
+ str->deltaviewheight = saveg_read32();
+
+ // fixed_t bob;
+ str->bob = saveg_read32();
+
+ // int health;
+ str->health = saveg_read32();
+
+ // int armorpoints;
+ str->armorpoints = saveg_read16(); // [STRIFE] 32 -> 16
+
+ // int armortype;
+ str->armortype = saveg_read16(); // [STRIFE] 32 -> 16
+
+ // int powers[NUMPOWERS];
+ for (i=0; i<NUMPOWERS; ++i)
+ {
+ str->powers[i] = saveg_read32();
+ }
+
+ // int sigiltype;
+ str->sigiltype = saveg_read32(); // [STRIFE]
+
+ // int nukagecount;
+ str->nukagecount = saveg_read32(); // [STRIFE]
+
+ // int questflags;
+ str->questflags = saveg_read32(); // [STRIFE]
+
+ // int pitch;
+ str->pitch = saveg_read32(); // [STRIFE]
+
+ // int centerview;
+ str->centerview = saveg_read32(); // [STRIFE]
+
+ // inventory_t inventory[NUMINVENTORY];
+ for(i = 0; i < NUMINVENTORY; i++)
+ {
+ saveg_read_inventory_t(&(str->inventory[i])); // [STRIFE]
+ }
+
+ // int st_update;
+ str->st_update = saveg_read32(); // [STRIFE]
+
+ // short numinventory;
+ str->numinventory = saveg_read16(); // [STRIFE]
+
+ // short inventorycursor;
+ str->inventorycursor = saveg_read16(); // [STRIFE]
+
+ // short accuracy;
+ str->accuracy = saveg_read16(); // [STRIFE]
+
+ // short stamina;
+ str->stamina = saveg_read16(); // [STRIFE]
+
+ // boolean cards[NUMCARDS];
+ for (i=0; i<NUMCARDS; ++i)
+ {
+ str->cards[i] = saveg_read32();
+ }
+
+ // boolean backpack;
+ str->backpack = saveg_read32();
+
+ // int attackdown;
+ str->attackdown = saveg_read32();
+
+ // int usedown;
+ str->usedown = saveg_read32();
+
+ // int inventorydown;
+ str->inventorydown = saveg_read32(); // [STRIFE]
+
+ // int frags[MAXPLAYERS];
+ for (i=0; i<MAXPLAYERS; ++i)
+ {
+ str->frags[i] = saveg_read32();
+ }
+
+ // weapontype_t readyweapon;
+ str->readyweapon = saveg_read_enum();
+
+ // weapontype_t pendingweapon;
+ str->pendingweapon = saveg_read_enum();
+
+ // boolean weaponowned[NUMWEAPONS];
+ for (i=0; i<NUMWEAPONS; ++i)
+ {
+ str->weaponowned[i] = saveg_read32();
+ }
+
+ // int ammo[NUMAMMO];
+ for (i=0; i<NUMAMMO; ++i)
+ {
+ str->ammo[i] = saveg_read32();
+ }
+
+ // int maxammo[NUMAMMO];
+ for (i=0; i<NUMAMMO; ++i)
+ {
+ str->maxammo[i] = saveg_read32();
+ }
+
+ // int cheats;
+ str->cheats = saveg_read32();
+
+ // int refire;
+ str->refire = saveg_read32();
+
+ // short killcount;
+ str->killcount = saveg_read16(); // [STRIFE] 32 -> 16
+
+ // haleyjd 08/30/10 [STRIFE] No itemcount.
+ // int itemcount;
+ //str->itemcount = saveg_read32();
+
+ // haleyjd 08/30/10 [STRIFE] No secretcount.
+ // int secretcount;
+ //str->secretcount = saveg_read32();
+
+ // char* message;
+ str->message = saveg_readp();
+
+ // int damagecount;
+ str->damagecount = saveg_read32();
+
+ // int bonuscount;
+ str->bonuscount = saveg_read32();
+
+ // mobj_t* attacker;
+ str->attacker = saveg_readp();
+
+ // int extralight;
+ str->extralight = saveg_read32();
+
+ // int fixedcolormap;
+ str->fixedcolormap = saveg_read32();
+
+ // int colormap; - [STRIFE] no such field
+ //str->colormap = saveg_read32();
+
+ // short allegiance;
+ str->allegiance = saveg_read16(); // [STRIFE]
+
+ // pspdef_t psprites[NUMPSPRITES];
+ for (i=0; i<NUMPSPRITES; ++i)
+ {
+ saveg_read_pspdef_t(&str->psprites[i]);
+ }
+
+ // int mapstate[40];
+ for(i = 0; i < 40; ++i) // [STRIFE]
+ {
+ str->mapstate[i] = saveg_read32();
+ }
+
+ // haleyjd 08/30/10: [STRIFE] No intermission, no didsecret.
+ // boolean didsecret;
+ //str->didsecret = saveg_read32();
+}
+
+static void saveg_write_player_t(player_t *str)
+{
+ int i;
+
+ // mobj_t* mo;
+ saveg_writep(str->mo);
+
+ // playerstate_t playerstate;
+ saveg_write_enum(str->playerstate);
+
+ // ticcmd_t cmd;
+ saveg_write_ticcmd_t(&str->cmd);
+
+ // fixed_t viewz;
+ saveg_write32(str->viewz);
+
+ // fixed_t viewheight;
+ saveg_write32(str->viewheight);
+
+ // fixed_t deltaviewheight;
+ saveg_write32(str->deltaviewheight);
+
+ // fixed_t bob;
+ saveg_write32(str->bob);
+
+ // int health;
+ saveg_write32(str->health);
+
+ // int armorpoints;
+ saveg_write16(str->armorpoints); // [STRIFE] 32 -> 16
+
+ // int armortype;
+ saveg_write16(str->armortype); // [STRIFE] 32 -> 16
+
+ // int powers[NUMPOWERS];
+ for (i=0; i<NUMPOWERS; ++i)
+ {
+ saveg_write32(str->powers[i]);
+ }
+
+ // int sigiltype;
+ saveg_write32(str->sigiltype); // [STRIFE]
+
+ // int nukagecount;
+ saveg_write32(str->nukagecount); // [STRIFE]
+
+ // int questflags;
+ saveg_write32(str->questflags); // [STRIFE]
+
+ // int pitch;
+ saveg_write32(str->pitch); // [STRIFE]
+
+ // int centerview;
+ saveg_write32(str->centerview); // [STRIFE]
+
+ // inventory_t inventory[NUMINVENTORY];
+ for(i = 0; i < NUMINVENTORY; ++i) // [STRIFE]
+ {
+ saveg_write_inventory_t(&str->inventory[i]);
+ }
+
+ // int st_update;
+ saveg_write32(str->st_update); // [STRIFE]
+
+ // short numinventory;
+ saveg_write16(str->numinventory); // [STRIFE]
+
+ // short inventorycursor;
+ saveg_write16(str->inventorycursor); // [STRIFE]
+
+ // short accuracy;
+ saveg_write16(str->accuracy); // [STRIFE]
+
+ // short stamina;
+ saveg_write16(str->stamina); // [STRIFE]
+
+ // boolean cards[NUMCARDS];
+ for (i=0; i<NUMCARDS; ++i)
+ {
+ saveg_write32(str->cards[i]);
+ }
+
+ // boolean backpack;
+ saveg_write32(str->backpack);
+
+ // int attackdown;
+ saveg_write32(str->attackdown);
+
+ // int usedown;
+ saveg_write32(str->usedown);
+
+ // int inventorydown;
+ saveg_write32(str->inventorydown); // [STRIFE]
+
+ // int frags[MAXPLAYERS];
+ for (i=0; i<MAXPLAYERS; ++i)
+ {
+ saveg_write32(str->frags[i]);
+ }
+
+ // weapontype_t readyweapon;
+ saveg_write_enum(str->readyweapon);
+
+ // weapontype_t pendingweapon;
+ saveg_write_enum(str->pendingweapon);
+
+ // boolean weaponowned[NUMWEAPONS];
+ for (i=0; i<NUMWEAPONS; ++i)
+ {
+ saveg_write32(str->weaponowned[i]);
+ }
+
+ // int ammo[NUMAMMO];
+ for (i=0; i<NUMAMMO; ++i)
+ {
+ saveg_write32(str->ammo[i]);
+ }
+
+ // int maxammo[NUMAMMO];
+ for (i=0; i<NUMAMMO; ++i)
+ {
+ saveg_write32(str->maxammo[i]);
+ }
+
+
+ // int cheats;
+ saveg_write32(str->cheats);
+
+ // int refire;
+ saveg_write32(str->refire);
+
+ // short killcount;
+ saveg_write16(str->killcount); // [STRIFE] 32 -> 16
+
+ // haleyjd 08/30/10 [STRIFE] No itemcount
+ // int itemcount;
+ //saveg_write32(str->itemcount);
+
+ // haleyjd 08/30/10 [STRIFE] No secretcount
+ // int secretcount;
+ //saveg_write32(str->secretcount);
+
+ // char* message;
+ saveg_writep(str->message);
+
+ // int damagecount;
+ saveg_write32(str->damagecount);
+
+ // int bonuscount;
+ saveg_write32(str->bonuscount);
+
+ // mobj_t* attacker;
+ saveg_writep(str->attacker);
+
+ // int extralight;
+ saveg_write32(str->extralight);
+
+ // int fixedcolormap;
+ saveg_write32(str->fixedcolormap);
+
+ // int colormap; [STRIFE] no such field
+ //saveg_write32(str->colormap);
+
+ // short allegiance;
+ saveg_write16(str->allegiance); // [STRIFE]
+
+ // pspdef_t psprites[NUMPSPRITES];
+ for (i=0; i<NUMPSPRITES; ++i)
+ {
+ saveg_write_pspdef_t(&str->psprites[i]);
+ }
+
+ // int mapstate[40];
+ for(i = 0; i < 40; ++i) // [STRIFE]
+ {
+ saveg_write32(str->mapstate[i]);
+ }
+
+ // haleyjd 08/30/10: [STRIFE] No intermission, no secret.
+ // boolean didsecret;
+ //saveg_write32(str->didsecret);
+}
+
+
+//
+// ceiling_t
+//
+
+static void saveg_read_ceiling_t(ceiling_t *str)
+{
+ int sector;
+
+ // thinker_t thinker;
+ saveg_read_thinker_t(&str->thinker);
+
+ // ceiling_e type;
+ str->type = saveg_read_enum();
+
+ // sector_t* sector;
+ sector = saveg_read32();
+ str->sector = &sectors[sector];
+
+ // fixed_t bottomheight;
+ str->bottomheight = saveg_read32();
+
+ // fixed_t topheight;
+ str->topheight = saveg_read32();
+
+ // fixed_t speed;
+ str->speed = saveg_read32();
+
+ // boolean crush;
+ str->crush = saveg_read32();
+
+ // int direction;
+ str->direction = saveg_read32();
+
+ // int tag;
+ str->tag = saveg_read32();
+
+ // int olddirection;
+ str->olddirection = saveg_read32();
+}
+
+static void saveg_write_ceiling_t(ceiling_t *str)
+{
+ // thinker_t thinker;
+ saveg_write_thinker_t(&str->thinker);
+
+ // ceiling_e type;
+ saveg_write_enum(str->type);
+
+ // sector_t* sector;
+ saveg_write32(str->sector - sectors);
+
+ // fixed_t bottomheight;
+ saveg_write32(str->bottomheight);
+
+ // fixed_t topheight;
+ saveg_write32(str->topheight);
+
+ // fixed_t speed;
+ saveg_write32(str->speed);
+
+ // boolean crush;
+ saveg_write32(str->crush);
+
+ // int direction;
+ saveg_write32(str->direction);
+
+ // int tag;
+ saveg_write32(str->tag);
+
+ // int olddirection;
+ saveg_write32(str->olddirection);
+}
+
+//
+// vldoor_t
+//
+// haleyjd 09/28/10: [STRIFE] Modified for Strife binary vldoor_t structure.
+//
+
+static void saveg_read_vldoor_t(vldoor_t *str)
+{
+ int sector;
+
+ // thinker_t thinker;
+ saveg_read_thinker_t(&str->thinker);
+
+ // vldoor_e type;
+ str->type = saveg_read_enum();
+
+ // sector_t* sector;
+ sector = saveg_read32();
+ str->sector = &sectors[sector];
+
+ // fixed_t topheight;
+ str->topheight = saveg_read32();
+
+ // fixed_t speed;
+ str->speed = saveg_read32();
+
+ // int direction;
+ str->direction = saveg_read32();
+
+ // int topwait;
+ str->topwait = saveg_read32();
+
+ // int topcountdown;
+ str->topcountdown = saveg_read32();
+
+ // villsa [STRIFE] new field - sound to play when opening
+ //int opensound;
+ str->opensound = saveg_read32();
+
+ // villsa [STRIFE] new field - sound to play when closing
+ //int closesound;
+ str->closesound = saveg_read32();
+}
+
+static void saveg_write_vldoor_t(vldoor_t *str)
+{
+ // thinker_t thinker;
+ saveg_write_thinker_t(&str->thinker);
+
+ // vldoor_e type;
+ saveg_write_enum(str->type);
+
+ // sector_t* sector;
+ saveg_write32(str->sector - sectors);
+
+ // fixed_t topheight;
+ saveg_write32(str->topheight);
+
+ // fixed_t speed;
+ saveg_write32(str->speed);
+
+ // int direction;
+ saveg_write32(str->direction);
+
+ // int topwait;
+ saveg_write32(str->topwait);
+
+ // int topcountdown;
+ saveg_write32(str->topcountdown);
+
+ // villsa [STRIFE] new field - sound to play when opening
+ //int opensound;
+ saveg_write32(str->opensound);
+
+ // villsa [STRIFE] new field - sound to play when closing
+ //int closesound;
+ saveg_write32(str->closesound);
+}
+
+//
+// slidedoor_t [STRIFE]: new thinker type
+//
+
+static void saveg_read_slidedoor_t(slidedoor_t *str)
+{
+ int sector;
+ int line;
+
+ // thinker_t thinker;
+ saveg_read_thinker_t(&str->thinker);
+
+ // sdt_e type;
+ str->type = saveg_read_enum();
+
+ // line_t *line1;
+ line = saveg_read32();
+ str->line1 = &lines[line];
+
+ // line_t *line2;
+ line = saveg_read32();
+ str->line2 = &lines[line];
+
+ // int frame;
+ str->frame = saveg_read32();
+
+ // int whichDoorIndex;
+ str->whichDoorIndex = saveg_read32();
+
+ // int timer;
+ str->timer = saveg_read32();
+
+ // sector_t *frontsector;
+ sector = saveg_read32();
+ str->frontsector = &sectors[sector];
+
+ // sd_e status;
+ str->status = saveg_read_enum();
+}
+
+static void saveg_write_slidedoor_t(slidedoor_t *str)
+{
+ // thinker_t thinker;
+ saveg_write_thinker_t(&str->thinker);
+
+ // sdt_e type;
+ saveg_write_enum(str->type);
+
+ // line_t *line1;
+ saveg_write32(str->line1 - lines);
+
+ // line_t *line2;
+ saveg_write32(str->line2 - lines);
+
+ // int frame;
+ saveg_write32(str->frame);
+
+ // int whichDoorIndex;
+ saveg_write32(str->whichDoorIndex);
+
+ // int timer;
+ saveg_write32(str->timer);
+
+ // sector_t *frontsector;
+ saveg_write32(str->frontsector - sectors);
+
+ // sd_e status;
+ saveg_write_enum(str->status);
+}
+
+//
+// floormove_t
+//
+
+static void saveg_read_floormove_t(floormove_t *str)
+{
+ int sector;
+
+ // thinker_t thinker;
+ saveg_read_thinker_t(&str->thinker);
+
+ // floor_e type;
+ str->type = saveg_read_enum();
+
+ // boolean crush;
+ str->crush = saveg_read32();
+
+ // sector_t* sector;
+ sector = saveg_read32();
+ str->sector = &sectors[sector];
+
+ // int direction;
+ str->direction = saveg_read32();
+
+ // int newspecial;
+ str->newspecial = saveg_read32();
+
+ // short texture;
+ str->texture = saveg_read16();
+
+ // fixed_t floordestheight;
+ str->floordestheight = saveg_read32();
+
+ // fixed_t speed;
+ str->speed = saveg_read32();
+}
+
+static void saveg_write_floormove_t(floormove_t *str)
+{
+ // thinker_t thinker;
+ saveg_write_thinker_t(&str->thinker);
+
+ // floor_e type;
+ saveg_write_enum(str->type);
+
+ // boolean crush;
+ saveg_write32(str->crush);
+
+ // sector_t* sector;
+ saveg_write32(str->sector - sectors);
+
+ // int direction;
+ saveg_write32(str->direction);
+
+ // int newspecial;
+ saveg_write32(str->newspecial);
+
+ // short texture;
+ saveg_write16(str->texture);
+
+ // fixed_t floordestheight;
+ saveg_write32(str->floordestheight);
+
+ // fixed_t speed;
+ saveg_write32(str->speed);
+}
+
+//
+// plat_t
+//
+
+static void saveg_read_plat_t(plat_t *str)
+{
+ int sector;
+
+ // thinker_t thinker;
+ saveg_read_thinker_t(&str->thinker);
+
+ // sector_t* sector;
+ sector = saveg_read32();
+ str->sector = &sectors[sector];
+
+ // fixed_t speed;
+ str->speed = saveg_read32();
+
+ // fixed_t low;
+ str->low = saveg_read32();
+
+ // fixed_t high;
+ str->high = saveg_read32();
+
+ // int wait;
+ str->wait = saveg_read32();
+
+ // int count;
+ str->count = saveg_read32();
+
+ // plat_e status;
+ str->status = saveg_read_enum();
+
+ // plat_e oldstatus;
+ str->oldstatus = saveg_read_enum();
+
+ // boolean crush;
+ str->crush = saveg_read32();
+
+ // int tag;
+ str->tag = saveg_read32();
+
+ // plattype_e type;
+ str->type = saveg_read_enum();
+}
+
+static void saveg_write_plat_t(plat_t *str)
+{
+ // thinker_t thinker;
+ saveg_write_thinker_t(&str->thinker);
+
+ // sector_t* sector;
+ saveg_write32(str->sector - sectors);
+
+ // fixed_t speed;
+ saveg_write32(str->speed);
+
+ // fixed_t low;
+ saveg_write32(str->low);
+
+ // fixed_t high;
+ saveg_write32(str->high);
+
+ // int wait;
+ saveg_write32(str->wait);
+
+ // int count;
+ saveg_write32(str->count);
+
+ // plat_e status;
+ saveg_write_enum(str->status);
+
+ // plat_e oldstatus;
+ saveg_write_enum(str->oldstatus);
+
+ // boolean crush;
+ saveg_write32(str->crush);
+
+ // int tag;
+ saveg_write32(str->tag);
+
+ // plattype_e type;
+ saveg_write_enum(str->type);
+}
+
+//
+// lightflash_t
+//
+
+static void saveg_read_lightflash_t(lightflash_t *str)
+{
+ int sector;
+
+ // thinker_t thinker;
+ saveg_read_thinker_t(&str->thinker);
+
+ // sector_t* sector;
+ sector = saveg_read32();
+ str->sector = &sectors[sector];
+
+ // int count;
+ str->count = saveg_read32();
+
+ // int maxlight;
+ str->maxlight = saveg_read32();
+
+ // int minlight;
+ str->minlight = saveg_read32();
+
+ // int maxtime;
+ str->maxtime = saveg_read32();
+
+ // int mintime;
+ str->mintime = saveg_read32();
+}
+
+static void saveg_write_lightflash_t(lightflash_t *str)
+{
+ // thinker_t thinker;
+ saveg_write_thinker_t(&str->thinker);
+
+ // sector_t* sector;
+ saveg_write32(str->sector - sectors);
+
+ // int count;
+ saveg_write32(str->count);
+
+ // int maxlight;
+ saveg_write32(str->maxlight);
+
+ // int minlight;
+ saveg_write32(str->minlight);
+
+ // int maxtime;
+ saveg_write32(str->maxtime);
+
+ // int mintime;
+ saveg_write32(str->mintime);
+}
+
+//
+// strobe_t
+//
+
+static void saveg_read_strobe_t(strobe_t *str)
+{
+ int sector;
+
+ // thinker_t thinker;
+ saveg_read_thinker_t(&str->thinker);
+
+ // sector_t* sector;
+ sector = saveg_read32();
+ str->sector = &sectors[sector];
+
+ // int count;
+ str->count = saveg_read32();
+
+ // int minlight;
+ str->minlight = saveg_read32();
+
+ // int maxlight;
+ str->maxlight = saveg_read32();
+
+ // int darktime;
+ str->darktime = saveg_read32();
+
+ // int brighttime;
+ str->brighttime = saveg_read32();
+}
+
+static void saveg_write_strobe_t(strobe_t *str)
+{
+ // thinker_t thinker;
+ saveg_write_thinker_t(&str->thinker);
+
+ // sector_t* sector;
+ saveg_write32(str->sector - sectors);
+
+ // int count;
+ saveg_write32(str->count);
+
+ // int minlight;
+ saveg_write32(str->minlight);
+
+ // int maxlight;
+ saveg_write32(str->maxlight);
+
+ // int darktime;
+ saveg_write32(str->darktime);
+
+ // int brighttime;
+ saveg_write32(str->brighttime);
+}
+
+//
+// glow_t
+//
+
+static void saveg_read_glow_t(glow_t *str)
+{
+ int sector;
+
+ // thinker_t thinker;
+ saveg_read_thinker_t(&str->thinker);
+
+ // sector_t* sector;
+ sector = saveg_read32();
+ str->sector = &sectors[sector];
+
+ // int minlight;
+ str->minlight = saveg_read32();
+
+ // int maxlight;
+ str->maxlight = saveg_read32();
+
+ // int direction;
+ str->direction = saveg_read32();
+}
+
+static void saveg_write_glow_t(glow_t *str)
+{
+ // thinker_t thinker;
+ saveg_write_thinker_t(&str->thinker);
+
+ // sector_t* sector;
+ saveg_write32(str->sector - sectors);
+
+ // int minlight;
+ saveg_write32(str->minlight);
+
+ // int maxlight;
+ saveg_write32(str->maxlight);
+
+ // int direction;
+ saveg_write32(str->direction);
+}
+
+//
+// Write the header for a savegame
+//
+// haleyjd 09/28/10: [STRIFE] numerous modifications.
+//
+
+void P_WriteSaveGameHeader(char *description)
+{
+ char name[VERSIONSIZE];
+ int i;
+
+ /*
+ [STRIFE] This is in the "NAME" file in a Strife save directory.
+ for (i=0; description[i] != '\0'; ++i)
+ saveg_write8(description[i]);
+ for (; i<SAVESTRINGSIZE; ++i)
+ saveg_write8(0);
+ */
+
+ memset (name,0,sizeof(name));
+ sprintf (name,"ver %i",STRIFE_VERSION);
+
+ for (i=0; i<VERSIONSIZE; ++i)
+ saveg_write8(name[i]);
+
+ saveg_write8(gameskill);
+
+ // [STRIFE] This information is implicit in the file being loaded.
+ //saveg_write8(gameepisode);
+ //saveg_write8(gamemap);
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ saveg_write8(playeringame[i]);
+
+ saveg_write8((leveltime >> 16) & 0xff);
+ saveg_write8((leveltime >> 8) & 0xff);
+ saveg_write8(leveltime & 0xff);
+}
+
+//
+// Read the header for a savegame
+//
+
+boolean P_ReadSaveGameHeader(void)
+{
+ int i;
+ byte a, b, c;
+ char vcheck[VERSIONSIZE];
+ char read_vcheck[VERSIONSIZE];
+
+ // skip the description field
+ /*
+ for (i=0; i<SAVESTRINGSIZE; ++i)
+ saveg_read8();
+ */
+
+ for (i=0; i<VERSIONSIZE; ++i)
+ read_vcheck[i] = saveg_read8();
+
+ memset (vcheck,0,sizeof(vcheck));
+ sprintf (vcheck,"ver %i",STRIFE_VERSION);
+ if (strcmp(read_vcheck, vcheck) != 0)
+ return false; // bad version
+
+ gameskill = saveg_read8();
+
+ // [STRIFE] This info is implicit in the file being read.
+ //gameepisode = saveg_read8();
+ //gamemap = saveg_read8();
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ playeringame[i] = saveg_read8();
+
+ // get the times
+ a = saveg_read8();
+ b = saveg_read8();
+ c = saveg_read8();
+ leveltime = (a<<16) + (b<<8) + c;
+
+ return true;
+}
+
+//
+// Read the end of file marker. Returns true if read successfully.
+//
+
+boolean P_ReadSaveGameEOF(void)
+{
+ int value;
+
+ value = saveg_read8();
+
+ return value == SAVEGAME_EOF;
+}
+
+//
+// Write the end of file marker
+//
+
+void P_WriteSaveGameEOF(void)
+{
+ saveg_write8(SAVEGAME_EOF);
+}
+
+//
+// P_ArchivePlayers
+//
+// [STRIFE] Verified unmodified.
+//
+void P_ArchivePlayers (void)
+{
+ int i;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (!playeringame[i])
+ continue;
+
+ saveg_write_pad();
+
+ saveg_write_player_t(&players[i]);
+ }
+}
+
+
+
+//
+// P_UnArchivePlayers
+//
+// [STRIFE] Verified unmodified.
+//
+void P_UnArchivePlayers (boolean userload)
+{
+ int i;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ player_t dummy;
+
+ if (!playeringame[i])
+ continue;
+
+ saveg_read_pad();
+
+ // haleyjd [STRIFE]: not exactly how vanilla did it, but this is
+ // necessary because of Choco's change to the savegame code which
+ // reads it directly from file. When not a userload, all the player_t
+ // data loaded from the save is thrown away.
+ if(userload)
+ {
+ saveg_read_player_t(&players[i]);
+ players[i].mo = NULL;
+ }
+ else
+ saveg_read_player_t(&dummy);
+
+ // will be set when unarc thinker
+ players[i].message = NULL;
+ players[i].attacker = NULL;
+ }
+}
+
+
+//
+// P_ArchiveWorld
+//
+// haleyjd 09/28/10: [STRIFE] Minor modifications.
+//
+void P_ArchiveWorld (void)
+{
+ int i;
+ int j;
+ sector_t* sec;
+ line_t* li;
+ side_t* si;
+
+ // do sectors
+ for (i=0, sec = sectors ; i<numsectors ; i++,sec++)
+ {
+ saveg_write16(sec->floorheight >> FRACBITS);
+ saveg_write16(sec->ceilingheight >> FRACBITS);
+ saveg_write16(sec->floorpic);
+ //saveg_write16(sec->ceilingpic); [STRIFE] not saved.
+ saveg_write16(sec->lightlevel);
+ saveg_write16(sec->special); // needed?
+ //saveg_write16(sec->tag); // needed? [STRIFE] not saved.
+ }
+
+
+ // do lines
+ for (i=0, li = lines ; i<numlines ; i++,li++)
+ {
+ saveg_write16(li->flags);
+ saveg_write16(li->special);
+ //saveg_write16(li->tag); [STRIFE] not saved.
+ for (j=0 ; j<2 ; j++)
+ {
+ if (li->sidenum[j] == -1)
+ continue;
+
+ si = &sides[li->sidenum[j]];
+
+ // [STRIFE] offsets not saved.
+ //saveg_write16(si->textureoffset >> FRACBITS);
+ //saveg_write16(si->rowoffset >> FRACBITS);
+ saveg_write16(si->toptexture);
+ saveg_write16(si->bottomtexture);
+ saveg_write16(si->midtexture);
+ }
+ }
+}
+
+
+
+//
+// P_UnArchiveWorld
+//
+void P_UnArchiveWorld (void)
+{
+ int i;
+ int j;
+ sector_t* sec;
+ line_t* li;
+ side_t* si;
+
+ // do sectors
+ for (i=0, sec = sectors ; i<numsectors ; i++,sec++)
+ {
+ sec->floorheight = saveg_read16() << FRACBITS;
+ sec->ceilingheight = saveg_read16() << FRACBITS;
+ sec->floorpic = saveg_read16();
+ //sec->ceilingpic = saveg_read16(); [STRIFE] not saved
+ sec->lightlevel = saveg_read16();
+ sec->special = saveg_read16(); // needed?
+ //sec->tag = saveg_read16(); // needed? [STRIFE] not saved
+ sec->specialdata = 0;
+ sec->soundtarget = 0;
+ }
+
+ // do lines
+ for (i=0, li = lines ; i<numlines ; i++,li++)
+ {
+ li->flags = saveg_read16();
+ li->special = saveg_read16();
+ //li->tag = saveg_read16(); [STRIFE] not saved
+ for (j=0 ; j<2 ; j++)
+ {
+ if (li->sidenum[j] == -1)
+ continue;
+ si = &sides[li->sidenum[j]];
+ // [STRIFE] offsets not saved.
+ //si->textureoffset = saveg_read16() << FRACBITS;
+ //si->rowoffset = saveg_read16() << FRACBITS;
+ si->toptexture = saveg_read16();
+ si->bottomtexture = saveg_read16();
+ si->midtexture = saveg_read16();
+ }
+ }
+}
+
+
+
+
+
+//
+// Thinkers
+//
+typedef enum
+{
+ tc_end,
+ tc_mobj
+
+} thinkerclass_t;
+
+
+//
+// P_ArchiveThinkers
+//
+// [STRIFE] Verified unmodified.
+//
+void P_ArchiveThinkers (void)
+{
+ thinker_t* th;
+
+ // save off the current thinkers
+ for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
+ {
+ if (th->function.acp1 == (actionf_p1)P_MobjThinker)
+ {
+ saveg_write8(tc_mobj);
+ saveg_write_pad();
+ saveg_write_mobj_t((mobj_t *) th);
+
+ continue;
+ }
+
+ // haleyjd: This may seem mysterious but in the DOOM prebeta,
+ // different types of things used different thinker functions.
+ // Those would have all been handled here and this message is
+ // probably a relic of that old system, not to mention the odd
+ // name of this function, and use of an enumeration with only
+ // two values in it.
+
+ // I_Error ("P_ArchiveThinkers: Unknown thinker function");
+ }
+
+ // add a terminating marker
+ saveg_write8(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 = saveg_read8();
+ switch (tclass)
+ {
+ case tc_end:
+ return; // end of list
+
+ case tc_mobj:
+ saveg_read_pad();
+ mobj = Z_Malloc (sizeof(*mobj), PU_LEVEL, NULL);
+ saveg_read_mobj_t(mobj);
+
+ // haleyjd 09/29/10: Strife sets the targets of non-allied creatures
+ // who had a non-NULL target at save time to players[0].mo so that
+ // they won't fall back asleep.
+ //
+ // BUG: As the player may not have been spawned yet, we could be
+ // setting monsters' targets to the mobj which was spawned by
+ // P_SetupLevel and then removed just above. Due to a subtle glitch
+ // in the DOOM engine whereby all things removed in this function
+ // are leaked until the next time P_SetupLevel is called, this is a
+ // safe operation - the call to P_InitThinkers above stops any of
+ // the objects removed, including the player's previous body, from
+ // being passed to Z_Free. One glitch relying on another!
+
+ if(mobj->target != NULL && (mobj->flags & MF_ALLY) != MF_ALLY)
+ mobj->target = players[0].mo;
+ else
+ mobj->target = NULL;
+
+ // WARNING! Strife does not seem to set tracer! I am leaving it be
+ // for now because so far no crashes have been observed, and failing
+ // to set this here will almost certainly crash Choco.
+ mobj->tracer = NULL;
+ P_SetThingPosition (mobj);
+ mobj->info = &mobjinfo[mobj->type];
+ // [STRIFE]: doesn't set these
+ //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 ("Unknown tclass %i in savegame",tclass);
+ }
+ }
+}
+
+
+//
+// P_ArchiveSpecials
+//
+enum
+{
+ tc_ceiling,
+ tc_door,
+ tc_floor,
+ tc_plat,
+ tc_flash,
+ tc_strobe,
+ tc_glow,
+ tc_slidingdoor, // [STRIFE]
+ tc_endspecials
+
+} specials_e;
+
+
+
+//
+// Things to handle:
+//
+// T_MoveCeiling, (ceiling_t: sector_t * swizzle), - active list
+// T_VerticalDoor, (vldoor_t: sector_t * swizzle),
+// T_SlidingDoor, (slidedoor_t: sector_t *, line_t * x 2 swizzle) [STRIFE]
+// 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;
+ int i;
+
+ // save off the current thinkers
+ for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
+ {
+ if (th->function.acv == (actionf_v)NULL)
+ {
+ for (i = 0; i < MAXCEILINGS;i++)
+ if (activeceilings[i] == (ceiling_t *)th)
+ break;
+
+ if (i<MAXCEILINGS)
+ {
+ saveg_write8(tc_ceiling);
+ saveg_write_pad();
+ saveg_write_ceiling_t((ceiling_t *) th);
+ }
+ continue;
+ }
+
+ if (th->function.acp1 == (actionf_p1)T_MoveCeiling)
+ {
+ saveg_write8(tc_ceiling);
+ saveg_write_pad();
+ saveg_write_ceiling_t((ceiling_t *) th);
+ continue;
+ }
+
+ if (th->function.acp1 == (actionf_p1)T_VerticalDoor)
+ {
+ saveg_write8(tc_door);
+ saveg_write_pad();
+ saveg_write_vldoor_t((vldoor_t *) th);
+ continue;
+ }
+
+ if (th->function.acp1 == (actionf_p1)T_SlidingDoor)
+ {
+ saveg_write8(tc_slidingdoor);
+ saveg_write_pad();
+ saveg_write_slidedoor_t((slidedoor_t *)th);
+ continue;
+ }
+
+ if (th->function.acp1 == (actionf_p1)T_MoveFloor)
+ {
+ saveg_write8(tc_floor);
+ saveg_write_pad();
+ saveg_write_floormove_t((floormove_t *) th);
+ continue;
+ }
+
+ if (th->function.acp1 == (actionf_p1)T_PlatRaise)
+ {
+ saveg_write8(tc_plat);
+ saveg_write_pad();
+ saveg_write_plat_t((plat_t *) th);
+ continue;
+ }
+
+ if (th->function.acp1 == (actionf_p1)T_LightFlash)
+ {
+ saveg_write8(tc_flash);
+ saveg_write_pad();
+ saveg_write_lightflash_t((lightflash_t *) th);
+ continue;
+ }
+
+ if (th->function.acp1 == (actionf_p1)T_StrobeFlash)
+ {
+ saveg_write8(tc_strobe);
+ saveg_write_pad();
+ saveg_write_strobe_t((strobe_t *) th);
+ continue;
+ }
+
+ if (th->function.acp1 == (actionf_p1)T_Glow)
+ {
+ saveg_write8(tc_glow);
+ saveg_write_pad();
+ saveg_write_glow_t((glow_t *) th);
+ continue;
+ }
+ }
+
+ // add a terminating marker
+ saveg_write8(tc_endspecials);
+}
+
+
+//
+// P_UnArchiveSpecials
+//
+void P_UnArchiveSpecials (void)
+{
+ byte tclass;
+ ceiling_t* ceiling;
+ vldoor_t* door;
+ slidedoor_t* slidedoor; // haleyjd [STRIFE]
+ floormove_t* floor;
+ plat_t* plat;
+ lightflash_t* flash;
+ strobe_t* strobe;
+ glow_t* glow;
+
+
+ // read in saved thinkers
+ while (1)
+ {
+ tclass = saveg_read8();
+
+ switch (tclass)
+ {
+ case tc_endspecials:
+ return; // end of list
+
+ case tc_ceiling:
+ saveg_read_pad();
+ ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVEL, NULL);
+ saveg_read_ceiling_t(ceiling);
+ 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:
+ saveg_read_pad();
+ door = Z_Malloc (sizeof(*door), PU_LEVEL, NULL);
+ saveg_read_vldoor_t(door);
+ door->sector->specialdata = door;
+ door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor;
+ P_AddThinker (&door->thinker);
+ break;
+
+ case tc_slidingdoor:
+ // haleyjd 09/29/10: [STRIFE] New thinker type for sliding doors
+ saveg_read_pad();
+ slidedoor = Z_Malloc(sizeof(*slidedoor), PU_LEVEL, NULL);
+ saveg_read_slidedoor_t(slidedoor);
+ slidedoor->frontsector->specialdata = slidedoor;
+ slidedoor->thinker.function.acp1 = (actionf_p1)T_SlidingDoor;
+ P_AddThinker(&slidedoor->thinker);
+ break;
+
+ case tc_floor:
+ saveg_read_pad();
+ floor = Z_Malloc (sizeof(*floor), PU_LEVEL, NULL);
+ saveg_read_floormove_t(floor);
+ floor->sector->specialdata = floor;
+ floor->thinker.function.acp1 = (actionf_p1)T_MoveFloor;
+ P_AddThinker (&floor->thinker);
+ break;
+
+ case tc_plat:
+ saveg_read_pad();
+ plat = Z_Malloc (sizeof(*plat), PU_LEVEL, NULL);
+ saveg_read_plat_t(plat);
+ 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:
+ saveg_read_pad();
+ flash = Z_Malloc (sizeof(*flash), PU_LEVEL, NULL);
+ saveg_read_lightflash_t(flash);
+ flash->thinker.function.acp1 = (actionf_p1)T_LightFlash;
+ P_AddThinker (&flash->thinker);
+ break;
+
+ case tc_strobe:
+ saveg_read_pad();
+ strobe = Z_Malloc (sizeof(*strobe), PU_LEVEL, NULL);
+ saveg_read_strobe_t(strobe);
+ strobe->thinker.function.acp1 = (actionf_p1)T_StrobeFlash;
+ P_AddThinker (&strobe->thinker);
+ break;
+
+ case tc_glow:
+ saveg_read_pad();
+ glow = Z_Malloc (sizeof(*glow), PU_LEVEL, NULL);
+ saveg_read_glow_t(glow);
+ glow->thinker.function.acp1 = (actionf_p1)T_Glow;
+ P_AddThinker (&glow->thinker);
+ break;
+
+ default:
+ I_Error ("P_UnarchiveSpecials:Unknown tclass %i "
+ "in savegame",tclass);
+ }
+ }
+}
+
diff --git a/src/strife/p_saveg.h b/src/strife/p_saveg.h
new file mode 100644
index 00000000..c0cfc666
--- /dev/null
+++ b/src/strife/p_saveg.h
@@ -0,0 +1,70 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Savegame I/O, archiving, persistence.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __P_SAVEG__
+#define __P_SAVEG__
+
+#include <stdio.h>
+
+// maximum size of a savegame description
+
+#define SAVESTRINGSIZE 24
+
+// temporary filename to use while saving.
+
+char *P_TempSaveGameFile(void);
+
+// filename to use for a savegame slot
+
+char *P_SaveGameFile(int slot);
+
+// Savegame file header read/write functions
+
+boolean P_ReadSaveGameHeader(void);
+void P_WriteSaveGameHeader(char *description);
+
+// Savegame end-of-file read/write functions
+
+boolean P_ReadSaveGameEOF(void);
+void P_WriteSaveGameEOF(void);
+
+// Persistent storage/archiving.
+// These are the load / save game routines.
+void P_ArchivePlayers (void);
+void P_UnArchivePlayers (boolean userload);
+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 FILE *save_stream;
+extern boolean savegame_error;
+
+
+#endif
diff --git a/src/strife/p_setup.c b/src/strife/p_setup.c
new file mode 100644
index 00000000..694d0185
--- /dev/null
+++ b/src/strife/p_setup.c
@@ -0,0 +1,865 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Do all the WAD I/O, get map description,
+// set up initial state and misc. LUTs.
+//
+//-----------------------------------------------------------------------------
+
+
+
+#include <math.h>
+
+#include "z_zone.h"
+
+#include "deh_main.h"
+#include "i_swap.h"
+#include "m_argv.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"
+
+
+void P_SpawnMapThing (mapthing_t* mthing);
+
+
+//
+// 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;
+
+static int totallines;
+
+// 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;
+
+
+// Maintain single and multi player starting spots.
+#define MAX_DEATHMATCH_STARTS 10
+
+mapthing_t deathmatchstarts[MAX_DEATHMATCH_STARTS];
+mapthing_t* deathmatch_p;
+mapthing_t playerstarts[MAXPLAYERS];
+
+// haleyjd 08/24/10: [STRIFE] rift spots for player spawning
+mapthing_t riftSpots[MAXRIFTSPOTS];
+
+
+
+
+//
+// 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.
+ W_ReleaseLumpNum(lump);
+}
+
+
+
+//
+// P_LoadSegs
+//
+void P_LoadSegs (int lump)
+{
+ byte* data;
+ int i;
+ mapseg_t* ml;
+ seg_t* li;
+ line_t* ldef;
+ int linedef;
+ int side;
+ int sidenum;
+
+ numsegs = W_LumpLength (lump) / sizeof(mapseg_t);
+ segs = Z_Malloc (numsegs*sizeof(seg_t),PU_LEVEL,0);
+ 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)
+ {
+ sidenum = ldef->sidenum[side ^ 1];
+
+ // If the sidenum is out of range, this may be a "glass hack"
+ // impassible window. Point at side #0 (this may not be
+ // the correct Vanilla behavior; however, it seems to work for
+ // OTTAWAU.WAD, which is the one place I've seen this trick
+ // used).
+
+ if (sidenum < 0 || sidenum >= numsides)
+ {
+ sidenum = 0;
+ }
+
+ li->backsector = sides[sidenum].sector;
+ }
+ else
+ {
+ li->backsector = 0;
+ }
+ }
+
+ W_ReleaseLumpNum(lump);
+}
+
+
+//
+// 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;
+ 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);
+ }
+
+ W_ReleaseLumpNum(lump);
+}
+
+
+
+//
+// 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);
+ 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 = NULL;
+ }
+
+ W_ReleaseLumpNum(lump);
+}
+
+
+//
+// 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;
+ }
+ }
+
+ W_ReleaseLumpNum(lump);
+}
+
+
+//
+// P_LoadThings
+//
+// haleyjd 08/24/10: [STRIFE]:
+// * Added code to record rift spots
+void P_LoadThings (int lump)
+{
+ byte *data;
+ int i;
+ mapthing_t *mt;
+ mapthing_t spawnthing;
+ int numthings;
+ 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
+ // STRIFE-TODO: replace with isregistered stuff
+ /*
+ if (gamemode != commercial)
+ {
+ switch (SHORT(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.
+ spawnthing.x = SHORT(mt->x);
+ spawnthing.y = SHORT(mt->y);
+ spawnthing.angle = SHORT(mt->angle);
+ spawnthing.type = SHORT(mt->type);
+ spawnthing.options = SHORT(mt->options);
+
+ // haleyjd 08/24/2010: Special Strife checks
+ if(spawnthing.type >= 118 && spawnthing.type < 128)
+ {
+ // initialize riftSpots
+ int riftSpotNum = spawnthing.type - 118;
+ riftSpots[riftSpotNum] = spawnthing;
+ riftSpots[riftSpotNum].type = 1;
+ }
+ else if(spawnthing.type >= 9001 && spawnthing.type < 9011)
+ {
+ // STRIFE-TODO: mystery array of 90xx objects
+ }
+ else
+ P_SpawnMapThing(&spawnthing);
+ }
+
+ W_ReleaseLumpNum(lump);
+}
+
+
+//
+// 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);
+ 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;
+ }
+
+ W_ReleaseLumpNum(lump);
+}
+
+
+//
+// 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);
+ 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)];
+ }
+
+ W_ReleaseLumpNum(lump);
+}
+
+
+//
+// P_LoadBlockMap
+//
+void P_LoadBlockMap (int lump)
+{
+ int i;
+ int count;
+ int lumplen;
+
+ lumplen = W_LumpLength(lump);
+ count = lumplen / 2;
+
+ blockmaplump = Z_Malloc(lumplen, PU_LEVEL, NULL);
+ W_ReadLump(lump, blockmaplump);
+ blockmap = blockmaplump + 4;
+
+ // Swap all short integers to native byte ordering.
+
+ for (i=0; i<count; i++)
+ {
+ blockmaplump[i] = SHORT(blockmaplump[i]);
+ }
+
+ // Read the header
+
+ 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);
+ 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;
+ 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;
+ totallines = 0;
+ for (i=0 ; i<numlines ; i++, li++)
+ {
+ totallines++;
+ li->frontsector->linecount++;
+
+ if (li->backsector && li->backsector != li->frontsector)
+ {
+ li->backsector->linecount++;
+ totallines++;
+ }
+ }
+
+ // build line tables for each sector
+ linebuffer = Z_Malloc (totallines*sizeof(line_t *), PU_LEVEL, 0);
+
+ for (i=0; i<numsectors; ++i)
+ {
+ // Assign the line buffer for this sector
+
+ sectors[i].lines = linebuffer;
+ linebuffer += sectors[i].linecount;
+
+ // Reset linecount to zero so in the next stage we can count
+ // lines into the list.
+
+ sectors[i].linecount = 0;
+ }
+
+ // Assign lines to sectors
+
+ for (i=0; i<numlines; ++i)
+ {
+ li = &lines[i];
+
+ if (li->frontsector != NULL)
+ {
+ sector = li->frontsector;
+
+ sector->lines[sector->linecount] = li;
+ ++sector->linecount;
+ }
+
+ if (li->backsector != NULL && li->frontsector != li->backsector)
+ {
+ sector = li->backsector;
+
+ sector->lines[sector->linecount] = li;
+ ++sector->linecount;
+ }
+ }
+
+ // Generate bounding boxes for sectors
+
+ sector = sectors;
+ for (i=0 ; i<numsectors ; i++, sector++)
+ {
+ M_ClearBox (bbox);
+
+ for (j=0 ; j<sector->linecount; j++)
+ {
+ li = sector->lines[j];
+
+ M_AddToBox (bbox, li->v1->x, li->v1->y);
+ M_AddToBox (bbox, li->v2->x, li->v2->y);
+ }
+
+ // 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;
+ }
+
+}
+
+// Pad the REJECT lump with extra data when the lump is too small,
+// to simulate a REJECT buffer overflow in Vanilla Doom.
+
+static void PadRejectArray(byte *array, unsigned int len)
+{
+ unsigned int i;
+ unsigned int byte_num;
+ byte *dest;
+ unsigned int padvalue;
+
+ // Values to pad the REJECT array with:
+
+ unsigned int rejectpad[4] =
+ {
+ ((totallines * 4 + 3) & ~3) + 24, // Size
+ 0, // Part of z_zone block header
+ 50, // PU_LEVEL
+ 0x1d4a11 // DOOM_CONST_ZONEID
+ };
+
+ // Copy values from rejectpad into the destination array.
+
+ dest = array;
+
+ for (i=0; i<len && i<sizeof(rejectpad); ++i)
+ {
+ byte_num = i % 4;
+ *dest = (rejectpad[i / 4] >> (byte_num * 8)) & 0xff;
+ ++dest;
+ }
+
+ // We only have a limited pad size. Print a warning if the
+ // REJECT lump is too small.
+
+ if (len > sizeof(rejectpad))
+ {
+ fprintf(stderr, "PadRejectArray: REJECT lump too short to pad! (%i > %i)\n",
+ len, sizeof(rejectpad));
+
+ // Pad remaining space with 0 (or 0xff, if specified on command line).
+
+ if (M_CheckParm("-reject_pad_with_ff"))
+ {
+ padvalue = 0xff;
+ }
+ else
+ {
+ padvalue = 0xf00;
+ }
+
+ memset(array + sizeof(rejectpad), padvalue, len - sizeof(rejectpad));
+ }
+}
+
+static void P_LoadReject(int lumpnum)
+{
+ int minlength;
+ int lumplen;
+
+ // Calculate the size that the REJECT lump *should* be.
+
+ minlength = (numsectors * numsectors + 7) / 8;
+
+ // If the lump meets the minimum length, it can be loaded directly.
+ // Otherwise, we need to allocate a buffer of the correct size
+ // and pad it with appropriate data.
+
+ lumplen = W_LumpLength(lumpnum);
+
+ if (lumplen >= minlength)
+ {
+ rejectmatrix = W_CacheLumpNum(lumpnum, PU_LEVEL);
+ }
+ else
+ {
+ rejectmatrix = Z_Malloc(minlength, PU_LEVEL, &rejectmatrix);
+ W_ReadLump(lumpnum, rejectmatrix);
+
+ PadRejectArray(rejectmatrix + lumplen, minlength - lumplen);
+ }
+}
+
+//
+// P_SetupLevel
+//
+void
+P_SetupLevel
+( int map,
+ int playermask,
+ skill_t skill)
+{
+ int i;
+ char lumpname[9];
+ int lumpnum;
+
+ // haleyjd 20110205 [STRIFE]: removed totalitems and wminfo
+ totalkills = totalsecret = 0;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ // haleyjd 20100830: [STRIFE] Removed secretcount, itemcount
+ // 20110205: [STRIFE] Initialize players.allegiance
+ players[i].allegiance = i;
+ players[i].killcount = 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 ();
+
+
+#if 0 // UNUSED
+ if (debugfile)
+ {
+ Z_FreeTags (PU_LEVEL, INT_MAX);
+ Z_FileDumpHeap (debugfile);
+ }
+ else
+#endif
+ Z_FreeTags (PU_LEVEL, PU_PURGELEVEL-1);
+
+
+ // UNUSED W_Profile ();
+ P_InitThinkers ();
+
+ // [STRIFE] Removed ExMy map support
+ if (map<10)
+ DEH_snprintf(lumpname, 9, "map0%i", map);
+ else
+ DEH_snprintf(lumpname, 9, "map%i", map);
+
+ 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);
+
+ P_GroupLines ();
+ P_LoadReject (lumpnum+ML_REJECT);
+
+ //bodyqueslot = 0; [STRIFE] unused
+ 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 = NULL;
+ G_DeathMatchSpawnPlayer (i);
+ }
+
+ }
+
+ // clear special respawning que
+ iquehead = iquetail = 0;
+
+ // set up world state
+ P_SpawnSpecials ();
+
+ // build subsector connect matrix
+ // UNUSED P_ConnectSubsectors ();
+
+ // preload graphics
+ if (precache)
+ R_PrecacheLevel ();
+
+ //printf ("free memory: 0x%x\n", Z_FreeMemory());
+}
+
+
+
+//
+// P_Init
+//
+void P_Init (void)
+{
+ P_InitSwitchList();
+ P_InitPicAnims();
+ P_InitTerrainTypes(); // villsa [STRIFE]
+ R_InitSprites(sprnames);
+}
+
+
+
diff --git a/src/strife/p_setup.h b/src/strife/p_setup.h
new file mode 100644
index 00000000..1befd7ae
--- /dev/null
+++ b/src/strife/p_setup.h
@@ -0,0 +1,45 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Setup a game, startup stuff.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __P_SETUP__
+#define __P_SETUP__
+
+
+
+
+// NOT called by W_Ticker. Fixme.
+// [STRIFE] Removed episode parameter
+void
+P_SetupLevel
+( int map,
+ int playermask,
+ skill_t skill);
+
+// Called by startup code.
+void P_Init (void);
+
+#endif
diff --git a/src/strife/p_sight.c b/src/strife/p_sight.c
new file mode 100644
index 00000000..e0b2ad3c
--- /dev/null
+++ b/src/strife/p_sight.c
@@ -0,0 +1,368 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// LineOfSight/Visibility checks, uses REJECT Lookup Table.
+//
+//-----------------------------------------------------------------------------
+
+
+
+#include "doomdef.h"
+
+#include "i_system.h"
+#include "p_local.h"
+
+// State.
+#include "r_state.h"
+
+//
+// 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).
+//
+// [STRIFE] Verified unmodified
+//
+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.
+//
+// [STRIFE] Verified unmodified
+//
+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;
+ // 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_CrossSubsector
+// Returns true
+// if strace crosses the given subsector successfully.
+//
+// [STRIFE] Verified unmodified
+//
+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 ("P_CrossSubsector: ss %i with numss = %i",
+ num,
+ numsubsectors);
+#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;
+
+ // Backsector may be NULL if this is an "impassible
+ // glass" hack line.
+
+ if (line->backsector == NULL)
+ {
+ return false;
+ }
+
+ // 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.
+//
+// [STRIFE] Verified unmodified
+//
+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.
+//
+// [STRIFE] Verified unmodified
+//
+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 = (t1->subsector->sector - sectors);
+ s2 = (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);
+}
+
+
diff --git a/src/strife/p_spec.c b/src/strife/p_spec.c
new file mode 100644
index 00000000..10a778bb
--- /dev/null
+++ b/src/strife/p_spec.c
@@ -0,0 +1,1996 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Implements special effects:
+// Texture animation, height or lighting changes
+// according to adjacent sectors, respective
+// utility functions, etc.
+// Line Tag handling. Line and Sector triggers.
+//
+//-----------------------------------------------------------------------------
+
+
+#include <stdlib.h>
+
+#include "doomdef.h"
+#include "doomstat.h"
+
+#include "deh_main.h"
+#include "i_system.h"
+#include "z_zone.h"
+#include "m_argv.h"
+#include "m_misc.h"
+#include "m_random.h"
+#include "w_wad.h"
+
+#include "r_local.h"
+#include "p_local.h"
+
+#include "g_game.h"
+
+#include "s_sound.h"
+
+// State.
+#include "r_state.h"
+
+// Data.
+#include "sounds.h"
+
+// [STRIFE]
+#include "hu_stuff.h"
+#include "p_dialog.h"
+
+
+//
+// Animating textures and planes
+// There is another anim_t used in wi_stuff, unrelated.
+//
+typedef struct
+{
+ boolean istexture;
+ int picnum;
+ int basepic;
+ int numpics;
+ int speed;
+
+} anim_t;
+
+//
+// source animation definition
+//
+typedef struct
+{
+ int istexture; // if false, it is a flat
+ char endname[9];
+ char startname[9];
+ int speed;
+} animdef_t;
+
+
+// haleyjd 08/30/10: [STRIFE] MAXANIMS raised from 32 to 40
+#define MAXANIMS 40
+
+//
+// P_InitPicAnims
+//
+
+// Floor/ceiling animation sequences,
+// defined by first and last frame,
+// i.e. the flat (64x64 tile) name to
+// be used.
+// The full animation sequence is given
+// using all the flats between the start
+// and end entry, in the order found in
+// the WAD file.
+//
+// haleyjd 08/29/10: [STRIFE] Changed animdefs.
+//
+animdef_t animdefs[] =
+{
+ { false, "F_SCANR8", "F_SCANR5", 4},
+ { false, "F_WATR03", "F_WATR01", 8},
+ { false, "F_PWATR3", "F_PWATR1", 11},
+ { false, "F_SCANR4", "F_SCANR1", 4},
+ { true, "SCAN08", "SCAN05", 4},
+ { true, "SWTRMG03", "SWTRMG01", 4},
+ { true, "SCAN04", "SCAN01", 4},
+ { true, "COMP04", "COMP01", 4},
+ { true, "COMP08", "COMP05", 6},
+ { true, "COMP12", "COMP09", 11},
+ { true, "COMP16", "COMP13", 12},
+ { true, "COMP20", "COMP17", 12},
+ { true, "COMP24", "COMP21", 12},
+ { true, "COMP28", "COMP25", 12},
+ { true, "COMP32", "COMP29", 12},
+ { true, "COMP37", "COMP33", 12},
+ { true, "COMP41", "COMP38", 12},
+ { true, "COMP49", "COMP42", 10},
+ { true, "BRKGRY16", "BRKGRY13", 10},
+ { true, "BRNSCN04", "BRNSCN01", 10},
+ { true, "CONCRT12", "CONCRT09", 11},
+ { true, "CONCRT25", "CONCRT22", 11},
+ { true, "WALPMP02", "WALPMP01", 16},
+ { true, "WALTEK17", "WALTEK16", 8},
+ { true, "FORCE04", "FORCE01", 4},
+ { true, "FORCE08", "FORCE05", 4},
+ { true, "FAN02", "FAN01", 4},
+ { false, "F_VWATR3", "P_VWATR1", 4},
+ { false, "F_HWATR3", "F_HWATR1", 4},
+ { false, "F_TELE2", "F_TELE1", 4},
+ { false, "F_FAN2", "F_FAN1", 4},
+ { false, "F_CONVY2", "F_CONVY1", 4},
+ { false, "F_RDALN4", "F_RDALN1", 4},
+ { -1, "", "", 0},
+};
+
+anim_t anims[MAXANIMS];
+anim_t* lastanim;
+
+//
+// Animating line specials
+//
+// haleyjd 08/29/10: [STRIFE] MAXLINEANIMS raised from 64 to 96
+#define MAXLINEANIMS 96
+
+extern short numlinespecials;
+extern line_t* linespeciallist[MAXLINEANIMS];
+
+
+
+void P_InitPicAnims (void)
+{
+ int i;
+
+
+ // Init animation
+ lastanim = anims;
+ for (i=0 ; animdefs[i].istexture != -1 ; i++)
+ {
+ char *startname, *endname;
+
+ startname = DEH_String(animdefs[i].startname);
+ endname = DEH_String(animdefs[i].endname);
+
+ if (animdefs[i].istexture)
+ {
+ // different episode ?
+ if (R_CheckTextureNumForName(startname) == -1)
+ continue;
+
+ lastanim->picnum = R_TextureNumForName(endname);
+ lastanim->basepic = R_TextureNumForName(startname);
+ }
+ else
+ {
+ if (W_CheckNumForName(startname) == -1)
+ continue;
+
+ lastanim->picnum = R_FlatNumForName(endname);
+ lastanim->basepic = R_FlatNumForName(startname);
+ }
+
+ lastanim->istexture = animdefs[i].istexture;
+ lastanim->numpics = lastanim->picnum - lastanim->basepic + 1;
+
+ if (lastanim->numpics < 2)
+ I_Error ("P_InitPicAnims: bad cycle from %s to %s",
+ startname, endname);
+
+ lastanim->speed = animdefs[i].speed;
+ lastanim++;
+ }
+
+}
+
+// villsa [STRIFE] terrain type definitions
+typedef struct
+{
+ char* flat;
+ int type;
+ int num;
+} terraintype_t;
+
+terraintype_t terraintypes[] =
+{
+ { "F_WATR03", FLOOR_WATER, -1 },
+ { "F_WATR02", FLOOR_WATER, -1 },
+ { "F_WATR01", FLOOR_WATER, -1 },
+ { "F_VWATR3", FLOOR_WATER, -1 },
+ { "F_VWATR2", FLOOR_WATER, -1 },
+ { "P_VWATR1", FLOOR_WATER, -1 },
+ { "F_HWATR3", FLOOR_WATER, -1 },
+ { "F_HWATR2", FLOOR_WATER, -1 },
+ { "F_HWATR1", FLOOR_WATER, -1 },
+ { "F_PWATR3", FLOOR_SLIME, -1 },
+ { "F_PWATR2", FLOOR_SLIME, -1 },
+ { "F_PWATR1", FLOOR_SLIME, -1 },
+ { "END", FLOOR_END, -1 },
+};
+
+//
+// P_GetTerrainType
+// villsa [STRIFE] new function
+//
+
+terraintype_e P_GetTerrainType(mobj_t* mobj)
+{
+ int i = 0;
+ subsector_t* ss = mobj->subsector;
+
+ if(mobj->z <= ss->sector->floorheight &&
+ terraintypes[0].type != FLOOR_END)
+ {
+ while(ss->sector->floorpic != terraintypes[i].num)
+ {
+ if(terraintypes[i+1].type == FLOOR_END)
+ return FLOOR_SOLID;
+
+ i++;
+ }
+
+ return terraintypes[i].type;
+ }
+
+ return FLOOR_SOLID;
+}
+
+//
+// P_InitTerrainTypes
+// villsa [STRIFE] new function
+// Initialize terrain types
+//
+
+void P_InitTerrainTypes(void)
+{
+ int i = 0;
+
+ if(terraintypes[0].type != FLOOR_END)
+ {
+ while(terraintypes[i].type != FLOOR_END)
+ {
+ terraintypes[i].num = R_FlatNumForName(terraintypes[i].flat);
+ i++;
+ }
+ }
+}
+
+
+
+//
+// UTILITIES
+//
+
+
+
+//
+// getSide()
+// Will return a side_t*
+// given the number of the current sector,
+// the line number, and the side (0/1) that you want.
+//
+side_t*
+getSide
+( int currentSector,
+ int line,
+ int side )
+{
+ return &sides[ (sectors[currentSector].lines[line])->sidenum[side] ];
+}
+
+
+//
+// getSector()
+// Will return a sector_t*
+// given the number of the current sector,
+// the line number and the side (0/1) that you want.
+//
+sector_t*
+getSector
+( int currentSector,
+ int line,
+ int side )
+{
+ return sides[ (sectors[currentSector].lines[line])->sidenum[side] ].sector;
+}
+
+
+//
+// twoSided()
+// Given the sector number and the line number,
+// it will tell you whether the line is two-sided or not.
+//
+int
+twoSided
+( int sector,
+ int line )
+{
+ return (sectors[sector].lines[line])->flags & ML_TWOSIDED;
+}
+
+
+
+
+//
+// getNextSector()
+// Return sector_t * of sector next to current.
+// NULL if not two-sided line
+//
+sector_t*
+getNextSector
+( line_t* line,
+ sector_t* sec )
+{
+ if (!(line->flags & ML_TWOSIDED))
+ return NULL;
+
+ if (line->frontsector == sec)
+ return line->backsector;
+
+ return line->frontsector;
+}
+
+
+
+//
+// P_FindLowestFloorSurrounding()
+// FIND LOWEST FLOOR HEIGHT IN SURROUNDING SECTORS
+//
+fixed_t P_FindLowestFloorSurrounding(sector_t* sec)
+{
+ int i;
+ line_t* check;
+ sector_t* other;
+ fixed_t floor = sec->floorheight;
+
+ for (i=0 ;i < sec->linecount ; i++)
+ {
+ check = sec->lines[i];
+ other = getNextSector(check,sec);
+
+ if (!other)
+ continue;
+
+ if (other->floorheight < floor)
+ floor = other->floorheight;
+ }
+ return floor;
+}
+
+
+
+//
+// P_FindHighestFloorSurrounding()
+// FIND HIGHEST FLOOR HEIGHT IN SURROUNDING SECTORS
+//
+fixed_t P_FindHighestFloorSurrounding(sector_t *sec)
+{
+ int i;
+ line_t* check;
+ sector_t* other;
+ fixed_t floor = -500*FRACUNIT;
+
+ for (i=0 ;i < sec->linecount ; i++)
+ {
+ check = sec->lines[i];
+ other = getNextSector(check,sec);
+
+ if (!other)
+ continue;
+
+ if (other->floorheight > floor)
+ floor = other->floorheight;
+ }
+ return floor;
+}
+
+
+
+//
+// P_FindNextHighestFloor
+// FIND NEXT HIGHEST FLOOR IN SURROUNDING SECTORS
+// Note: this should be doable w/o a fixed array.
+
+// Thanks to entryway for the Vanilla overflow emulation.
+
+// 20 adjoining sectors max!
+#define MAX_ADJOINING_SECTORS 20
+
+fixed_t
+P_FindNextHighestFloor
+( sector_t* sec,
+ int currentheight )
+{
+ int i;
+ int h;
+ int min;
+ line_t* check;
+ sector_t* other;
+ fixed_t height = currentheight;
+ fixed_t heightlist[MAX_ADJOINING_SECTORS + 2];
+
+ for (i=0, h=0; i < sec->linecount; i++)
+ {
+ check = sec->lines[i];
+ other = getNextSector(check,sec);
+
+ if (!other)
+ continue;
+
+ if (other->floorheight > height)
+ {
+ // Emulation of memory (stack) overflow
+ if (h == MAX_ADJOINING_SECTORS + 1)
+ {
+ height = other->floorheight;
+ }
+ else if (h == MAX_ADJOINING_SECTORS + 2)
+ {
+ // Fatal overflow: game crashes at 22 textures
+ I_Error("Sector with more than 22 adjoining sectors. "
+ "Vanilla will crash here");
+ }
+
+ heightlist[h++] = other->floorheight;
+ }
+ }
+
+ // Find lowest height in list
+ if (!h)
+ {
+ return currentheight;
+ }
+
+ min = heightlist[0];
+
+ // Range checking?
+ for (i = 1; i < h; i++)
+ {
+ if (heightlist[i] < min)
+ {
+ min = heightlist[i];
+ }
+ }
+
+ return min;
+}
+
+//
+// FIND LOWEST CEILING IN THE SURROUNDING SECTORS
+//
+fixed_t
+P_FindLowestCeilingSurrounding(sector_t* sec)
+{
+ int i;
+ line_t* check;
+ sector_t* other;
+ fixed_t height = INT_MAX;
+
+ for (i=0 ;i < sec->linecount ; i++)
+ {
+ check = sec->lines[i];
+ other = getNextSector(check,sec);
+
+ if (!other)
+ continue;
+
+ if (other->ceilingheight < height)
+ height = other->ceilingheight;
+ }
+ return height;
+}
+
+
+//
+// FIND HIGHEST CEILING IN THE SURROUNDING SECTORS
+//
+fixed_t P_FindHighestCeilingSurrounding(sector_t* sec)
+{
+ int i;
+ line_t* check;
+ sector_t* other;
+ fixed_t height = 0;
+
+ for (i=0 ;i < sec->linecount ; i++)
+ {
+ check = sec->lines[i];
+ other = getNextSector(check,sec);
+
+ if (!other)
+ continue;
+
+ if (other->ceilingheight > height)
+ height = other->ceilingheight;
+ }
+ return height;
+}
+
+
+
+//
+// RETURN NEXT SECTOR # THAT LINE TAG REFERS TO
+//
+int
+P_FindSectorFromLineTag
+( line_t* line,
+ int start )
+{
+ int i;
+
+ for (i=start+1;i<numsectors;i++)
+ if (sectors[i].tag == line->tag)
+ return i;
+
+ return -1;
+}
+
+
+
+
+//
+// Find minimum light from an adjacent sector
+//
+int
+P_FindMinSurroundingLight
+( sector_t* sector,
+ int max )
+{
+ int i;
+ int min;
+ line_t* line;
+ sector_t* check;
+
+ min = max;
+ for (i=0 ; i < sector->linecount ; i++)
+ {
+ line = sector->lines[i];
+ check = getNextSector(line,sector);
+
+ if (!check)
+ continue;
+
+ if (check->lightlevel < min)
+ min = check->lightlevel;
+ }
+ return min;
+}
+
+
+
+//
+// EVENTS
+// Events are operations triggered by using, crossing,
+// or shooting special lines, or by timed thinkers.
+//
+
+// [STRIFE]
+static char crosslinestr[90];
+
+//
+// P_CrossSpecialLine - TRIGGER
+// Called every time a thing origin is about
+// to cross a line with a non 0 special.
+//
+void
+P_CrossSpecialLine
+( int linenum,
+ int side,
+ mobj_t* thing )
+{
+ line_t* line;
+ side_t* sidedef; // [STRIFE]
+ int flag; // [STRIFE]
+ int ok;
+
+ line = &lines[linenum];
+
+ // haleyjd 09/21/10: corpses and missiles cannot activate any cross-over
+ // line types, *except* 182 (which is for the sake of missiles).
+ if((thing->flags & (MF_MISSILE|MF_CORPSE)) && line->special != 182)
+ return;
+
+ // Triggers that other things can activate
+ if (!thing->player)
+ {
+ // Things that should NOT trigger specials...
+ // villsa [STRIFE] unused
+ // haleyjd: removed dead switch. Strife only excludes missiles and
+ // corpses, which is handled above.
+
+ ok = 0;
+
+ // [STRIFE] Added several line types. Removed none.
+ switch(line->special)
+ {
+ case 97: // TELEPORT RETRIGGER
+ case 185: // haleyjd: [STRIFE] Silent Teleport (used for Converter)
+ case 195: // haleyjd: [STRIFE] Silent Teleport and Change Zombie
+ case 231: // haleyjd: [STRIFE] WR Teleport (Silent at Source)
+ case 125: // TELEPORT MONSTERONLY TRIGGER
+ case 126: // TELEPORT MONSTERONLY RETRIGGER
+ case 182: // haleyjd: [STRIFE] Break glass - it's a W1 type too!
+ case 10: // PLAT DOWN-WAIT-UP-STAY TRIGGER
+ case 39: // TELEPORT TRIGGER
+ case 88: // PLAT DOWN-WAIT-UP-STAY RETRIGGER
+ case 4: // RAISE DOOR
+ ok = 1;
+ break;
+ }
+ if (!ok)
+ return;
+ }
+
+
+ // Note: could use some const's here.
+ switch (line->special)
+ {
+ //
+ // TRIGGERS.
+ // All from here to RETRIGGERS.
+ //
+ case 230:
+ // haleyjd 09/21/10: [STRIFE] W1 Open Door if Quest
+ sidedef = &sides[line->sidenum[0]];
+ flag = (sidedef->rowoffset >> FRACBITS) - 1;
+
+ if(!(thing->player->questflags & (1 << flag)))
+ break;
+ // fall-through:
+ case 2:
+ // Open Door - [STRIFE] Verified unmodified.
+ EV_DoDoor(line,open);
+ line->special = 0;
+ break;
+
+ case 227:
+ // haleyjd 09/21/10: [STRIFE] W1 Close Door if Quest
+ sidedef = &sides[line->sidenum[0]];
+ flag = (sidedef->rowoffset >> FRACBITS) - 1;
+
+ if(!(thing->player->questflags & (1 << flag)))
+ break;
+ // fall-through:
+ case 3:
+ // Close Door - [STRIFE] Verified unmodified.
+ EV_DoDoor(line,close);
+ line->special = 0;
+ break;
+
+ case 4:
+ // Raise Door - [STRIFE] Verified unmodified.
+ EV_DoDoor(line,normal);
+ line->special = 0;
+ break;
+
+ case 5:
+ // Raise Floor - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,raiseFloor);
+ line->special = 0;
+ break;
+
+ case 6:
+ // Fast Ceiling Crush & Raise - [STRIFE] Verified unmodified.
+ EV_DoCeiling(line,fastCrushAndRaise);
+ line->special = 0;
+ break;
+
+ case 8:
+ // Build Stairs - [STRIFE] Verified unmodified.
+ EV_BuildStairs(line,build8);
+ line->special = 0;
+ break;
+
+ case 10:
+ // PlatDownWaitUp - [STRIFE] Verified unmodified.
+ EV_DoPlat(line,downWaitUpStay,0);
+ line->special = 0;
+ break;
+
+ case 12:
+ // Light Turn On - brightest near - [STRIFE] Verified unmodified.
+ EV_LightTurnOn(line,0);
+ line->special = 0;
+ break;
+
+ case 13:
+ // Light Turn On 255 - [STRIFE] Verified unmodified.
+ EV_LightTurnOn(line,255);
+ line->special = 0;
+ break;
+
+ case 16:
+ // Close Door 30 - [STRIFE] Verified unmodified.
+ EV_DoDoor(line,close30ThenOpen);
+ line->special = 0;
+ break;
+
+ case 17:
+ // Start Light Strobing - [STRIFE] Verified unmodified.
+ EV_StartLightStrobing(line);
+ line->special = 0;
+ break;
+
+ case 19:
+ // Lower Floor - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,lowerFloor);
+ line->special = 0;
+ break;
+
+ case 22:
+ // villsa [STRIFE] Verified unmodified.
+ // Raise floor to nearest height and change texture
+ EV_DoPlat(line,raiseToNearestAndChange,0);
+ line->special = 0;
+ break;
+
+ case 25:
+ // Ceiling Crush and Raise - [STRIFE] Verified unmodified.
+ EV_DoCeiling(line,crushAndRaise);
+ line->special = 0;
+ break;
+
+ case 30:
+ // Raise floor to shortest texture height - [STRIFE] Verified unmodified.
+ // on either side of lines.
+ EV_DoFloor(line,raiseToTexture);
+ line->special = 0;
+ break;
+
+ case 35:
+ // Lights Very Dark - [STRIFE] Verified unmodified.
+ EV_LightTurnOn(line,35);
+ line->special = 0;
+ break;
+
+ case 36:
+ // Lower Floor (TURBO) - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,turboLower);
+ line->special = 0;
+ break;
+
+ case 37:
+ // LowerAndChange - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,lowerAndChange);
+ line->special = 0;
+ break;
+
+ case 193:
+ // haleyjd 09/21/10: [STRIFE] W1 Floor Lower to Lowest if Quest
+ sidedef = &sides[line->sidenum[0]];
+ flag = (sidedef->rowoffset >> FRACBITS) - 1; // note is fixed_t
+
+ // must have the questflag indicated in the line's y offset
+ if(!(thing->player->questflags & (1 << flag)))
+ break;
+ // fall-through:
+ case 38:
+ // Lower Floor To Lowest - [STRIFE] Verified unmodified.
+ EV_DoFloor( line, lowerFloorToLowest );
+ line->special = 0;
+ break;
+
+ case 39:
+ // TELEPORT! - [STRIFE] Verified unmodified (except for 0 flags param)
+ EV_Teleport( line, side, thing, TF_NORMAL );
+ line->special = 0;
+ break;
+
+ /*case 40:
+ // RaiseCeilingLowerFloor
+ EV_DoCeiling( line, raiseToHighest );
+ EV_DoFloor( line, lowerFloorToLowest );
+ line->special = 0;
+ break;*/
+
+ case 44:
+ // Ceiling Crush - [STRIFE] Verified unmodified.
+ EV_DoCeiling( line, lowerAndCrush );
+ line->special = 0;
+ break;
+
+ case 52:
+ // EXIT! - haleyjd 09/21/10: [STRIFE] Exit to level tag/100
+ G_ExitLevel (line->tag / 100);
+ break;
+
+ case 53:
+ // Perpetual Platform Raise - [STRIFE] Verified unmodified.
+ EV_DoPlat(line,perpetualRaise,0);
+ line->special = 0;
+ break;
+
+ case 54:
+ // Platform Stop - [STRIFE] Verified unmodified.
+ EV_StopPlat(line);
+ line->special = 0;
+ break;
+
+ case 56:
+ // Raise Floor Crush - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,raiseFloorCrush);
+ line->special = 0;
+ break;
+
+ case 57:
+ // Ceiling Crush Stop - [STRIFE] Verified unmodified.
+ EV_CeilingCrushStop(line);
+ line->special = 0;
+ break;
+
+ case 58:
+ // [STRIFE] raiseFloor24 was modified into raiseFloor64
+ // Raise Floor 64
+ EV_DoFloor(line,raiseFloor64);
+ line->special = 0;
+ break;
+
+ case 59:
+ // Raise Floor 24 And Change - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,raiseFloor24AndChange);
+ line->special = 0;
+ break;
+
+ case 104:
+ // Turn lights off in sector(tag) - [STRIFE] Verified unmodified.
+ EV_TurnTagLightsOff(line);
+ line->special = 0;
+ break;
+
+ case 108:
+ // Blazing Door Raise (faster than TURBO!) - [STRIFE] Verified unmodified.
+ EV_DoDoor (line,blazeRaise);
+ line->special = 0;
+ break;
+
+ case 109:
+ // Blazing Door Open (faster than TURBO!) - [STRIFE] Verified unmodified.
+ EV_DoDoor (line,blazeOpen);
+ line->special = 0;
+ break;
+
+ case 100:
+ // Build Stairs Turbo 16 - [STRIFE] Verified unmodified.
+ EV_BuildStairs(line,turbo16);
+ line->special = 0;
+ break;
+
+ case 197:
+ // haleyjd 09/21/10: [STRIFE] Blazing Door Close if Has Sigil B
+ if(thing->player->sigiltype <= 0)
+ break;
+ // fall-through:
+ case 110:
+ // Blazing Door Close (faster than TURBO!) - [STRIFE] Verified unmodified.
+ EV_DoDoor (line,blazeClose);
+ line->special = 0;
+ break;
+
+ case 119:
+ // Raise floor to nearest surr. floor - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,raiseFloorToNearest);
+ line->special = 0;
+ break;
+
+ case 121:
+ // villsa [STRIFE] Verified unmodified.
+ // Blazing PlatDownWaitUpStay
+ EV_DoPlat(line,blazeDWUS,0);
+ line->special = 0;
+ break;
+
+ case 124:
+ // haleyjd 09/21/10: [STRIFE] W1 Start Finale
+ // Altered from G_SecretExitLevel.
+ G_StartFinale();
+ break;
+
+ case 125:
+ // TELEPORT MonsterONLY - [STRIFE] Verified unmodified
+ // (except for 0 flags parameter)
+ if (!thing->player)
+ {
+ EV_Teleport( line, side, thing, TF_NORMAL );
+ line->special = 0;
+ }
+ break;
+
+ case 130:
+ // Raise Floor Turbo - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,raiseFloorTurbo);
+ line->special = 0;
+ break;
+
+ case 141:
+ // Silent Ceiling Crush & Raise - [STRIFE] Verified unmodified.
+ EV_DoCeiling(line,silentCrushAndRaise);
+ line->special = 0;
+ break;
+
+ case 174:
+ // villsa [STRIFE] Split Open
+ EV_DoDoor(line, splitOpen);
+ line->special = 0;
+ break;
+
+ case 183:
+ // villsa [STRIFE] Split Raise Nearest
+ EV_DoDoor(line, splitRaiseNearest);
+ line->special = 0;
+ break;
+
+ case 178:
+ // haleyjd 09/24/10: [STRIFE] W1 Build Stairs Down 16
+ EV_BuildStairs(line, buildDown16);
+ line->special = 0;
+ break;
+
+ case 179:
+ // haleyjd 09/25/10: [STRIFE] W1 Ceiling Lower to Floor
+ EV_DoCeiling(line, lowerToFloor);
+ line->special = 0;
+ break;
+
+ case 182:
+ // haleyjd 09/21/10: [STRIFE] Break Glass
+ // 182 is a unique linetype in that it is both a G1 and a W1 linetype,
+ // but only missiles may activate it as a W1 type.
+ if(thing->flags & MF_MISSILE)
+ P_ChangeSwitchTexture(line, 1); // why 1? it will be cleared anyway.
+ break;
+
+ case 187:
+ // haleyjd 09/21/10: [STRIFE] W1 Clear Force Fields if Quest
+ sidedef = &sides[line->sidenum[0]];
+ flag = (sidedef->rowoffset >> FRACBITS) - 1; // note is fixed_t
+
+ // must have the questflag indicated in the line's y offset
+ if(!(thing->player->questflags & (1 << flag)))
+ break;
+
+ // Do it!
+ EV_ClearForceFields(line);
+ line->special = 0;
+ break;
+
+ case 188:
+ // haleyjd 09/21/10: [STRIFE] W1 Open Door if Quest 16 (Gate Mechanism
+ // Destroyed)
+ if(!(thing->player->questflags & QF_QUEST16))
+ break;
+ EV_DoDoor(line, open);
+ line->special = 0;
+ break;
+
+ case 196:
+ // haleyjd 09/26/10: [STRIFE] W1 Floor Lower to Lowest if Sigil Type > 0
+ if(thing->player->sigiltype > 0)
+ {
+ EV_DoFloor(line, lowerFloorToLowest);
+ line->special = 0;
+ }
+ break;
+
+ case 200:
+ // haleyjd 09/21/10: [STRIFE] W1 Open Door if Sigil Owned
+ if(!(thing->player->weaponowned[wp_sigil]))
+ break;
+ EV_DoDoor(line, open);
+ line->special = 0;
+ break;
+
+ case 201:
+ // haleyjd 09/21/10: [STRIFE] W1 Voiced Objective (First Side Only)
+ if(side == 1)
+ break;
+ // fall-through:
+ case 202:
+ // haleyjd 09/21/10: [STRIFE] W1 Voiced Objective (Tag = VOC/LOG #)
+ // must be consoleplayer
+ if(thing->player != &players[consoleplayer])
+ break;
+
+ // must have comm unit
+ if(!(thing->player->powers[pw_communicator]))
+ break;
+
+ // load voice
+ DEH_snprintf(crosslinestr, sizeof(crosslinestr), "voc%i", line->tag);
+ I_StartVoice(crosslinestr);
+
+ // load objective
+ DEH_snprintf(crosslinestr, sizeof(crosslinestr), "log%i", line->tag);
+ GiveObjective(crosslinestr, 0);
+
+ // Put up a message
+ thing->player->message = DEH_String("Incoming Message...");
+ line->special = 0;
+ break;
+
+ case 210:
+ // haleyjd 09/21/10: [STRIFE] W1 Voiced Objective if Flamethrower????
+ // I don't think this is actually used anywhere o_O
+ // must be player 1...
+ if(thing->player != &players[0])
+ break;
+
+ // must have comm unit
+ if(!(thing->player->powers[pw_communicator]))
+ break;
+
+ // must have... the flamethrower?!
+ if(!(thing->player->weaponowned[wp_flame]))
+ break;
+
+ // load voice
+ DEH_snprintf(crosslinestr, sizeof(crosslinestr), "voc%i", line->tag);
+ I_StartVoice(crosslinestr);
+
+ // load objective
+ DEH_snprintf(crosslinestr, sizeof(crosslinestr), "log%i", line->tag);
+ GiveObjective(crosslinestr, 0);
+
+ // Put up a message
+ thing->player->message = DEH_String("Incoming Message from BlackBird...");
+ line->special = 0;
+ break;
+
+ case 212:
+ // haleyjd 09/25/10: [STRIFE] W1 Floor Lower to Lowest if Have Flamethrower
+ if(thing->player->weaponowned[wp_flame])
+ {
+ EV_DoFloor(line, lowerFloorToLowest);
+ line->special = 0;
+ }
+ break;
+
+ case 215:
+ // haleyjd 09/21/10: [STRIFE] W1 Voiced Objective if Quest (Tag/100, Tag%100)
+ // must be player 1...
+ if(thing->player != &players[0])
+ break;
+
+ // must have comm unit
+ if(!(thing->player->powers[pw_communicator]))
+ break;
+
+ if(line->tag != 0)
+ {
+ // test for questflag
+ if(!(thing->player->questflags & (1 << (line->tag % 100 - 1))))
+ break;
+ }
+
+ // start voice
+ DEH_snprintf(crosslinestr, sizeof(crosslinestr), "voc%i", line->tag/100);
+ I_StartVoice(crosslinestr);
+
+ // give objective
+ DEH_snprintf(crosslinestr, sizeof(crosslinestr), "log%i", line->tag/100);
+ GiveObjective(crosslinestr, 0);
+
+ // Put up a message
+ thing->player->message = DEH_String("Incoming Message from BlackBird...");
+ line->special = 0;
+ break;
+
+ case 204:
+ // haleyjd 09/21/10: [STRIFE] W1 Change Music (unused!)
+ if(thing->player != &players[0])
+ break;
+ S_ChangeMusic(line->tag, 1);
+ line->special = 0;
+ break;
+
+ case 228:
+ // haleyjd 09/21/10: [STRIFE] W1 Entity Voice?
+ if(!(thing->player->questflags & QF_QUEST24)) // Not killed Macil???
+ break; // STRIFE-TODO: verify...
+
+ if(!(thing->player->questflags & QF_QUEST28)) // ????? STRIFE-TODO
+ I_StartVoice(DEH_String("voc128"));
+ else
+ I_StartVoice(DEH_String("voc130"));
+
+ line->special = 0;
+ break;
+
+ //
+ // RETRIGGERS. All from here till end.
+ //
+ case 72:
+ // Ceiling Crush - [STRIFE] Verified unmodified.
+ EV_DoCeiling( line, lowerAndCrush );
+ break;
+
+ case 73:
+ // Ceiling Crush and Raise - [STRIFE] Verified unmodified.
+ EV_DoCeiling(line,crushAndRaise);
+ break;
+
+ case 74:
+ // Ceiling Crush Stop - [STRIFE] Verified unmodified.
+ EV_CeilingCrushStop(line);
+ break;
+
+ case 75:
+ // Close Door - [STRIFE] Verified unmodified.
+ EV_DoDoor(line,close);
+ break;
+
+ case 76:
+ // Close Door 30 - [STRIFE] Verified unmodified.
+ EV_DoDoor(line,close30ThenOpen);
+ break;
+
+ case 77:
+ // Fast Ceiling Crush & Raise - [STRIFE] Verified unmodified.
+ EV_DoCeiling(line,fastCrushAndRaise);
+ break;
+
+ case 79:
+ // Lights Very Dark - [STRIFE] Verified unmodified.
+ EV_LightTurnOn(line,35);
+ break;
+
+ case 80:
+ // Light Turn On - brightest near - [STRIFE] Verified unmodified.
+ EV_LightTurnOn(line,0);
+ break;
+
+ case 81:
+ // Light Turn On 255 - [STRIFE] Verified unmodified.
+ EV_LightTurnOn(line,255);
+ break;
+
+ case 82:
+ // Lower Floor To Lowest - [STRIFE] Verified unmodified.
+ EV_DoFloor( line, lowerFloorToLowest );
+ break;
+
+ case 83:
+ // Lower Floor - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,lowerFloor);
+ break;
+
+ case 84:
+ // LowerAndChange - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,lowerAndChange);
+ break;
+
+ case 86:
+ // Open Door - [STRIFE] Verified unmodified.
+ EV_DoDoor(line,open);
+ break;
+
+ case 87:
+ // Perpetual Platform Raise - [STRIFE] Verified unmodified.
+ EV_DoPlat(line,perpetualRaise,0);
+ break;
+
+ case 88:
+ // PlatDownWaitUp - [STRIFE] Verified unmodified.
+ EV_DoPlat(line,downWaitUpStay,0);
+ break;
+
+ case 89:
+ // Platform Stop - [STRIFE] Verified unmodified.
+ EV_StopPlat(line);
+ break;
+
+ case 216:
+ // haleyjd 09/21/10: [STRIFE] WR Raise Door if Quest
+ sidedef = &sides[line->sidenum[0]];
+ flag = (sidedef->rowoffset >> FRACBITS) - 1; // note is fixed_t.
+
+ if(!(thing->player->questflags & (1 << flag)))
+ break;
+ // fall-through:
+ case 90:
+ // Raise Door - [STRIFE] Verified unmodified.
+ EV_DoDoor(line,normal);
+ break;
+
+ case 91:
+ // Raise Floor - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,raiseFloor);
+ break;
+
+ case 92:
+ // [STRIFE] raiseFloor24 changed to raiseFloor64
+ // Raise Floor 64
+ EV_DoFloor(line,raiseFloor64);
+ break;
+
+ case 93:
+ // Raise Floor 24 And Change - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,raiseFloor24AndChange);
+ break;
+
+ case 94:
+ // Raise Floor Crush - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,raiseFloorCrush);
+ break;
+
+ case 95:
+ // villsa [STRIFE] Verified unmodified.
+ // Raise floor to nearest height
+ // and change texture.
+ EV_DoPlat(line,raiseToNearestAndChange,0);
+ break;
+
+ case 96:
+ // Raise floor to shortest texture height - [STRIFE] Verified unmodified.
+ // on either side of lines.
+ EV_DoFloor(line,raiseToTexture);
+ break;
+
+ case 97:
+ // TELEPORT! - [STRIFE] Verified unmodified (except for 0 flags param)
+ EV_Teleport( line, side, thing, TF_NORMAL );
+ break;
+
+ case 98:
+ // Lower Floor (TURBO) - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,turboLower);
+ break;
+
+ case 105:
+ // Blazing Door Raise (faster than TURBO!) - [STRIFE] Verified unmodified.
+ EV_DoDoor (line,blazeRaise);
+ break;
+
+ case 106:
+ // Blazing Door Open (faster than TURBO!) - [STRIFE] Verified unmodified.
+ EV_DoDoor (line,blazeOpen);
+ break;
+
+ case 107:
+ // Blazing Door Close (faster than TURBO!) - [STRIFE] Verified unmodified.
+ EV_DoDoor (line,blazeClose);
+ break;
+
+ case 120:
+ // villsa [STRIFE] Verified unmodified.
+ // Blazing PlatDownWaitUpStay.
+ EV_DoPlat(line,blazeDWUS,0);
+ break;
+
+ case 126:
+ // TELEPORT MonsterONLY. - [STRIFE] Verified unmodified (except for 0 flags param)
+ if (!thing->player)
+ EV_Teleport( line, side, thing, TF_NORMAL );
+ break;
+
+ case 128:
+ // Raise To Nearest Floor - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,raiseFloorToNearest);
+ break;
+
+ case 129:
+ // Raise Floor Turbo - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,raiseFloorTurbo);
+ break;
+
+ case 186:
+ // haleyjd [STRIFE] Exit Level to Spot, First Side Only
+ if(side == 1)
+ break;
+ // fall-through:
+ case 145:
+ // haleyjd [STRIFE] Exit Level to Spot
+ thing->momx = thing->momy = thing->momz = 0;
+ {
+ int map = line->tag / 100;
+ int spot = line->tag % 100;
+
+ if(thing->player->weaponowned[wp_sigil])
+ {
+ if(map == 3)
+ map = 30;
+ else if(map == 7)
+ map = 10;
+ }
+
+ DEH_snprintf(crosslinestr, sizeof(crosslinestr),
+ "Entering%s",
+ DEH_String(mapnames[map - 1]) + 8);
+ thing->player->message = crosslinestr;
+
+ if(netgame && deathmatch)
+ {
+ if(levelTimer && levelTimeCount != 0)
+ {
+ DEH_snprintf(crosslinestr, sizeof(crosslinestr),
+ "%d min left",
+ (levelTimeCount/TICRATE)/60);
+ break;
+ }
+
+ // raise switch from floor
+ EV_DoFloor(line, raiseFloor64);
+ }
+ else
+ {
+ // normal single-player exit
+
+ // BUG: Here is the opening for a flaming player to cross past
+ // the exit line and hit a deathmatch switch ;) It's not so much
+ // that this is incorrect, as that they forgot to add such a
+ // check to the other kind of exit lines too ;)
+ if(thing->player->health <= 0)
+ break;
+
+ G_RiftExitLevel(map, spot, thing->angle);
+ }
+ }
+ break;
+
+ case 175:
+ // haleyjd 09/21/10: [STRIFE] WR Raise Alarm if < 16 Above Floor
+ if(thing->z < thing->floorz + 16 * FRACUNIT)
+ P_NoiseAlert(thing->player->mo, thing->player->mo);
+ break;
+
+ case 198:
+ // haleyjd 09/21/10: [STRIFE] WR Raise Alarm if No Guard Uniform
+ if(P_PlayerHasItem(thing->player, MT_QUEST_GUARD_UNIFORM))
+ break;
+ // fall-through:
+ case 150:
+ // haleyjd 09/21/10: [STRIFE] WR Raise Alarm
+ P_NoiseAlert(thing->player->mo, thing->player->mo);
+ break;
+
+ case 208:
+ // haleyjd 09/21/10: [STRIFE] WR Raise Alarm if Have Flamethrower
+ // O_o - this is definitely unused. Was an entire flamethrower quest
+ // cut out of the game before release?
+ if(thing->player->weaponowned[wp_flame])
+ P_NoiseAlert(thing->player->mo, thing->player->mo);
+ break;
+
+ case 206:
+ // haleyjd 09/21/10: [STRIFE] WR Raise Alarm if Have Chalice
+ // This *is* used, inside the Tavern in Tarnhill. Oddly there is also
+ // one just randomly placed outside the entrance to the Power Station.
+ if(P_PlayerHasItem(thing->player, MT_INV_CHALICE))
+ P_NoiseAlert(thing->player->mo, thing->player->mo);
+ break;
+
+ case 184:
+ // villsa [STRIFE] plat up wait down stay
+ if(EV_DoPlat(line, upWaitDownStay, 0))
+ P_ChangeSwitchTexture(line, 1); // In P_CrossSpecialLine? Copypasta error?
+ break;
+
+ case 185:
+ // haleyjd 09/21/10: [STRIFE] Silent Teleport (used for Converter)
+ EV_Teleport(line, side, thing, TF_FULLSILENCE);
+ break;
+
+ case 195:
+ // haleyjd 09/21/10: [STRIFE] Silent Teleport and Change Zombie
+ EV_Teleport(line, side, thing, TF_FULLSILENCE);
+ P_SetMobjState(thing, S_AGRD_00); // 419
+ break;
+
+ case 203:
+ // haleyjd 09/21/10: [STRIFE] WR Change Music
+ if(thing->player != &players[0])
+ break;
+ S_ChangeMusic(line->tag, 1);
+ break;
+
+ case 231:
+ // haleyjd 09/21/10: [STRIFE] WR Teleport (Silent at Source)
+ EV_Teleport(line, side, thing, TF_SRCSILENCE);
+ break;
+
+ // haleyjd 09/21/10: Moved one-time-use lines up above with the others.
+ }
+}
+
+
+
+//
+// P_ShootSpecialLine - IMPACT SPECIALS
+// Called when a thing shoots a special line.
+//
+void
+P_ShootSpecialLine
+( mobj_t* thing,
+ line_t* line )
+{
+ int ok;
+
+ // Impacts that other things can activate.
+ if (!thing->player)
+ {
+ ok = 0;
+ switch(line->special)
+ {
+ case 46: // OPEN DOOR IMPACT
+ case 182: // villsa [STRIFE] for windows
+ ok = 1;
+ break;
+ }
+ if (!ok)
+ return;
+ }
+
+ switch(line->special)
+ {
+ case 24:
+ // RAISE FLOOR - [STRIFE] Verified unmodified
+ EV_DoFloor(line,raiseFloor);
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 46:
+ // OPEN DOOR - [STRIFE] Verified unmodified.
+ EV_DoDoor(line,open);
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 47:
+ // villsa [STRIFE] Verified unmodified.
+ // RAISE FLOOR NEAR AND CHANGE
+ EV_DoPlat(line,raiseToNearestAndChange,0);
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 180:
+ // haleyjd 09/22/10: [STRIFE] G1 Raise Floor 512 & Change
+ EV_DoFloor(line, raiseFloor512AndChange);
+ P_ChangeSwitchTexture(line, 0);
+ break;
+
+ case 182:
+ // villsa [STRIFE] G1 Break Glass
+ // haleyjd: note that 182 is also a W1 type in P_CrossSpecialLine, but
+ // can only be activated in that manner by an MF_MISSILE object.
+ P_ChangeSwitchTexture(line, 0);
+ break;
+ }
+}
+
+
+
+//
+// P_PlayerInSpecialSector
+// Called every tic frame
+// that the player origin is in a special sector
+//
+// [STRIFE] Modified for new sector types and changes to old ones.
+//
+void P_PlayerInSpecialSector (player_t* player)
+{
+ sector_t* sector;
+
+ sector = player->mo->subsector->sector;
+
+ // Falling, not all the way down yet?
+ if (player->mo->z != sector->floorheight)
+ return;
+
+ // Has hitten ground.
+ switch (sector->special)
+ {
+ case 5:
+ // HELLSLIME DAMAGE
+ // [STRIFE] +2 to nukagecount
+ if(!player->powers[pw_ironfeet])
+ player->nukagecount += 2;
+ break;
+
+ case 16:
+ // [STRIFE] +4 to nukagecount
+ if(!player->powers[pw_ironfeet])
+ player->nukagecount += 4;
+ break;
+
+ case 4:
+ case 7:
+ // [STRIFE] Immediate 5 damage every 31 tics
+ if(!player->powers[pw_ironfeet])
+ if(!(leveltime & 0x1f))
+ P_DamageMobj(player->mo, NULL, NULL, 5);
+ break;
+
+ case 9:
+ // SECRET SECTOR
+ //player->secretcount++; [STRIFE] Don't have a secret count.
+ sector->special = 0;
+ if(player - players == consoleplayer)
+ S_StartSound(NULL, sfx_yeah);
+ break;
+
+ case 11:
+ // EXIT SUPER DAMAGE! (for E1M8 finale)
+ player->cheats &= ~CF_GODMODE;
+
+ if (!(leveltime&0x1f))
+ P_DamageMobj (player->mo, NULL, NULL, 20);
+
+ if (player->health <= 10)
+ G_ExitLevel(0);
+ break;
+
+ case 15:
+ // haleyjd 08/30/10: [STRIFE] "Instant" Death sector
+ P_DamageMobj(player->mo, NULL, NULL, 999);
+ break;
+
+
+ case 18:
+ // haleyjd 08/30/10: [STRIFE] Water current
+ {
+ int tagval = sector->tag - 100;
+ fixed_t force;
+ angle_t angle;
+
+ if(player->cheats & CF_NOCLIP)
+ return;
+
+ force = (tagval % 10) << 12;
+ angle = (tagval / 10) << 29;
+
+ P_Thrust(player, angle, force);
+ }
+ break;
+
+ default:
+ I_Error ("P_PlayerInSpecialSector: "
+ "unknown special %i",
+ sector->special);
+ break;
+ };
+}
+
+
+
+
+//
+// P_UpdateSpecials
+// Animate planes, scroll walls, etc.
+//
+// [STRIFE] Modifications to support multiple scrolling line types.
+//
+boolean levelTimer;
+int levelTimeCount;
+
+void P_UpdateSpecials (void)
+{
+ anim_t* anim;
+ int pic;
+ int i;
+ line_t* line;
+
+
+ // LEVEL TIMER
+ if (levelTimer == true)
+ {
+ if(levelTimeCount) // [STRIFE] Does not allow to go negative
+ levelTimeCount--;
+
+ /*
+ // [STRIFE] Not done here. Exit lines check this manually instead.
+ if (!levelTimeCount)
+ G_ExitLevel(0);
+ */
+ }
+
+ // ANIMATE FLATS AND TEXTURES GLOBALLY
+ for (anim = anims ; anim < lastanim ; anim++)
+ {
+ for (i=anim->basepic ; i<anim->basepic+anim->numpics ; i++)
+ {
+ pic = anim->basepic + ( (leveltime/anim->speed + i)%anim->numpics );
+ if (anim->istexture)
+ texturetranslation[i] = pic;
+ else
+ flattranslation[i] = pic;
+ }
+ }
+
+
+ // ANIMATE LINE SPECIALS
+ for (i = 0; i < numlinespecials; i++)
+ {
+ line = linespeciallist[i];
+ switch(line->special)
+ {
+ case 48:
+ // EFFECT FIRSTCOL SCROLL +
+ sides[line->sidenum[0]].textureoffset += FRACUNIT;
+ break;
+
+ case 142:
+ // haleyjd 09/25/10 [STRIFE] Scroll Up Slow
+ sides[line->sidenum[0]].rowoffset += FRACUNIT;
+ break;
+
+ case 143:
+ // haleyjd 09/25/10 [STRIFE] Scroll Down Fast (3 Units/Tic)
+ sides[line->sidenum[0]].rowoffset -= 3*FRACUNIT;
+ break;
+
+ case 149:
+ // haleyjd 09/25/10 [STRIFE] Scroll Down Slow
+ sides[line->sidenum[0]].rowoffset -= FRACUNIT;
+ break;
+ }
+ }
+
+
+ // DO BUTTONS
+ for (i = 0; i < MAXBUTTONS; i++)
+ if (buttonlist[i].btimer)
+ {
+ buttonlist[i].btimer--;
+ if (!buttonlist[i].btimer)
+ {
+ switch(buttonlist[i].where)
+ {
+ case top:
+ sides[buttonlist[i].line->sidenum[0]].toptexture =
+ buttonlist[i].btexture;
+ break;
+
+ case middle:
+ sides[buttonlist[i].line->sidenum[0]].midtexture =
+ buttonlist[i].btexture;
+ break;
+
+ case bottom:
+ sides[buttonlist[i].line->sidenum[0]].bottomtexture =
+ buttonlist[i].btexture;
+ break;
+ }
+ S_StartSound(&buttonlist[i].soundorg,sfx_swtchn);
+ memset(&buttonlist[i],0,sizeof(button_t));
+ }
+ }
+}
+
+
+//
+// Donut overrun emulation
+//
+// Derived from the code from PrBoom+. Thanks go to Andrey Budko (entryway)
+// as usual :-)
+//
+
+#define DONUT_FLOORHEIGHT_DEFAULT 0x00000000
+#define DONUT_FLOORPIC_DEFAULT 0x16
+
+static void DonutOverrun(fixed_t *s3_floorheight, short *s3_floorpic,
+ line_t *line, sector_t *pillar_sector)
+{
+ static int first = 1;
+ static int tmp_s3_floorheight;
+ static int tmp_s3_floorpic;
+
+ extern int numflats;
+
+ if (first)
+ {
+ int p;
+
+ // This is the first time we have had an overrun.
+ first = 0;
+
+ // Default values
+ tmp_s3_floorheight = DONUT_FLOORHEIGHT_DEFAULT;
+ tmp_s3_floorpic = DONUT_FLOORPIC_DEFAULT;
+
+ //!
+ // @category compat
+ // @arg <x> <y>
+ //
+ // Use the specified magic values when emulating behavior caused
+ // by memory overruns from improperly constructed donuts.
+ // In Vanilla Doom this can differ depending on the operating
+ // system. The default (if this option is not specified) is to
+ // emulate the behavior when running under Windows 98.
+
+ p = M_CheckParmWithArgs("-donut", 2);
+
+ if (p > 0)
+ {
+ // Dump of needed memory: (fixed_t)0000:0000 and (short)0000:0008
+ //
+ // C:\>debug
+ // -d 0:0
+ //
+ // DOS 6.22:
+ // 0000:0000 (57 92 19 00) F4 06 70 00-(16 00)
+ // DOS 7.1:
+ // 0000:0000 (9E 0F C9 00) 65 04 70 00-(16 00)
+ // Win98:
+ // 0000:0000 (00 00 00 00) 65 04 70 00-(16 00)
+ // DOSBox under XP:
+ // 0000:0000 (00 00 00 F1) ?? ?? ?? 00-(07 00)
+
+ M_StrToInt(myargv[p + 1], &tmp_s3_floorheight);
+ M_StrToInt(myargv[p + 2], &tmp_s3_floorpic);
+
+ if (tmp_s3_floorpic >= numflats)
+ {
+ fprintf(stderr,
+ "DonutOverrun: The second parameter for \"-donut\" "
+ "switch should be greater than 0 and less than number "
+ "of flats (%d). Using default value (%d) instead. \n",
+ numflats, DONUT_FLOORPIC_DEFAULT);
+ tmp_s3_floorpic = DONUT_FLOORPIC_DEFAULT;
+ }
+ }
+ }
+
+ /*
+ fprintf(stderr,
+ "Linedef: %d; Sector: %d; "
+ "New floor height: %d; New floor pic: %d\n",
+ line->iLineID, pillar_sector->iSectorID,
+ tmp_s3_floorheight >> 16, tmp_s3_floorpic);
+ */
+
+ *s3_floorheight = (fixed_t) tmp_s3_floorheight;
+ *s3_floorpic = (short) tmp_s3_floorpic;
+}
+
+
+//
+// Special Stuff that can not be categorized
+//
+int EV_DoDonut(line_t* line)
+{
+ sector_t* s1;
+ sector_t* s2;
+ sector_t* s3;
+ int secnum;
+ int rtn;
+ int i;
+ floormove_t* floor;
+ fixed_t s3_floorheight;
+ short s3_floorpic;
+
+ secnum = -1;
+ rtn = 0;
+ while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
+ {
+ s1 = &sectors[secnum];
+
+ // ALREADY MOVING? IF SO, KEEP GOING...
+ if (s1->specialdata)
+ continue;
+
+ rtn = 1;
+ s2 = getNextSector(s1->lines[0],s1);
+
+ // Vanilla Doom does not check if the linedef is one sided. The
+ // game does not crash, but reads invalid memory and causes the
+ // sector floor to move "down" to some unknown height.
+ // DOSbox prints a warning about an invalid memory access.
+ //
+ // I'm not sure exactly what invalid memory is being read. This
+ // isn't something that should be done, anyway.
+ // Just print a warning and return.
+
+ if (s2 == NULL)
+ {
+ fprintf(stderr,
+ "EV_DoDonut: linedef had no second sidedef! "
+ "Unexpected behavior may occur in Vanilla Doom. \n");
+ break;
+ }
+
+ for (i = 0; i < s2->linecount; i++)
+ {
+ s3 = s2->lines[i]->backsector;
+
+ if (s3 == s1)
+ continue;
+
+ if (s3 == NULL)
+ {
+ // e6y
+ // s3 is NULL, so
+ // s3->floorheight is an int at 0000:0000
+ // s3->floorpic is a short at 0000:0008
+ // Trying to emulate
+
+ fprintf(stderr,
+ "EV_DoDonut: WARNING: emulating buffer overrun due to "
+ "NULL back sector. "
+ "Unexpected behavior may occur in Vanilla Doom.\n");
+
+ DonutOverrun(&s3_floorheight, &s3_floorpic, line, s1);
+ }
+ else
+ {
+ s3_floorheight = s3->floorheight;
+ s3_floorpic = s3->floorpic;
+ }
+
+ // Spawn rising slime
+ floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
+ P_AddThinker (&floor->thinker);
+ s2->specialdata = floor;
+ floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor;
+ floor->type = donutRaise;
+ floor->crush = false;
+ floor->direction = 1;
+ floor->sector = s2;
+ floor->speed = FLOORSPEED / 2;
+ floor->texture = s3_floorpic;
+ floor->newspecial = 0;
+ floor->floordestheight = s3_floorheight;
+
+ // Spawn lowering donut-hole
+ floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
+ P_AddThinker (&floor->thinker);
+ s1->specialdata = floor;
+ floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor;
+ floor->type = lowerFloor;
+ floor->crush = false;
+ floor->direction = -1;
+ floor->sector = s1;
+ floor->speed = FLOORSPEED / 2;
+ floor->floordestheight = s3_floorheight;
+ break;
+ }
+ }
+ return rtn;
+}
+
+
+
+//
+// SPECIAL SPAWNING
+//
+
+//
+// P_SpawnSpecials
+// After the map has been loaded, scan for specials
+// that spawn thinkers
+//
+short numlinespecials;
+line_t* linespeciallist[MAXLINEANIMS];
+
+
+// Parses command line parameters.
+//
+// haleyjd 09/25/10: [STRIFE] Modifications for more scrolling line types and
+// for initialization of sliding door resources.
+//
+void P_SpawnSpecials (void)
+{
+ sector_t* sector;
+ int i;
+
+ // See if -TIMER was specified.
+
+ if (timelimit > 0 && deathmatch)
+ {
+ levelTimer = true;
+ levelTimeCount = timelimit * 60 * TICRATE;
+ }
+ else
+ {
+ levelTimer = false;
+ }
+
+ // Init special SECTORs - [STRIFE] Verified unmodified.
+ sector = sectors;
+ for (i=0 ; i<numsectors ; i++, sector++)
+ {
+ if (!sector->special)
+ continue;
+
+ switch (sector->special)
+ {
+ case 1:
+ // FLICKERING LIGHTS
+ P_SpawnLightFlash (sector);
+ break;
+
+ case 2:
+ // STROBE FAST
+ P_SpawnStrobeFlash(sector,FASTDARK,0);
+ break;
+
+ case 3:
+ // STROBE SLOW
+ P_SpawnStrobeFlash(sector,SLOWDARK,0);
+ break;
+
+ case 4:
+ // STROBE FAST/DEATH SLIME
+ P_SpawnStrobeFlash(sector,FASTDARK,0);
+ sector->special = 4;
+ break;
+
+ case 8:
+ // GLOWING LIGHT
+ P_SpawnGlowingLight(sector);
+ break;
+ case 9:
+ // SECRET SECTOR
+ totalsecret++;
+ break;
+
+ case 10:
+ // DOOR CLOSE IN 30 SECONDS
+ P_SpawnDoorCloseIn30 (sector);
+ break;
+
+ case 12:
+ // SYNC STROBE SLOW
+ P_SpawnStrobeFlash (sector, SLOWDARK, 1);
+ break;
+
+ case 13:
+ // SYNC STROBE FAST
+ P_SpawnStrobeFlash (sector, FASTDARK, 1);
+ break;
+
+ case 14:
+ // DOOR RAISE IN 5 MINUTES
+ P_SpawnDoorRaiseIn5Mins (sector, i);
+ break;
+
+ case 17:
+ P_SpawnFireFlicker(sector);
+ break;
+ }
+ }
+
+
+ // Init line EFFECTs
+ numlinespecials = 0;
+ for (i = 0;i < numlines; i++)
+ {
+ switch(lines[i].special)
+ {
+ case 48: // EFFECT FIRSTCOL SCROLL+
+ case 142:
+ case 143:
+ case 149:
+ linespeciallist[numlinespecials] = &lines[i];
+ numlinespecials++;
+ break;
+ }
+ }
+
+ // Init other misc stuff
+ for (i = 0;i < MAXCEILINGS;i++)
+ activeceilings[i] = NULL;
+
+ for (i = 0;i < MAXPLATS;i++)
+ activeplats[i] = NULL;
+
+ for (i = 0;i < MAXBUTTONS;i++)
+ memset(&buttonlist[i],0,sizeof(button_t));
+
+ // villsa [STRIFE]
+ P_InitSlidingDoorFrames();
+}
diff --git a/src/strife/p_spec.h b/src/strife/p_spec.h
new file mode 100644
index 00000000..7215c0b7
--- /dev/null
+++ b/src/strife/p_spec.h
@@ -0,0 +1,686 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// 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__
+
+
+//
+// End-level timer (-TIMER option)
+//
+extern boolean levelTimer;
+extern int levelTimeCount;
+
+
+// Define values for map objects
+#define MO_TELEPORTMAN 14
+
+
+// at game start
+void P_InitPicAnims (void);
+
+// villsa [STRIFE]
+typedef enum
+{
+ FLOOR_WATER = 0,
+ FLOOR_SLIME = 1,
+ FLOOR_SOLID = 2,
+ FLOOR_END = -1
+} terraintype_e;
+
+void P_InitTerrainTypes(void); // villsa [STRIFE]
+terraintype_e P_GetTerrainType(mobj_t* mobj); // villsa [STRIFE]
+
+// at map load
+void P_SpawnSpecials (void);
+
+// every tic
+void P_UpdateSpecials (void);
+
+// when needed
+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);
+boolean EV_ClearForceFields(line_t* line); // villsa [STRIFE]
+
+
+//
+// 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;
+ int sound; // villsa [STRIFE]
+
+} switchlist_t;
+
+
+typedef enum
+{
+ top,
+ middle,
+ bottom
+
+} bwhere_e;
+
+
+typedef struct
+{
+ line_t* line;
+ bwhere_e where;
+ int btexture;
+ int btimer;
+ degenmobj_t *soundorg;
+
+} button_t;
+
+
+
+
+ // max # of wall switches in a level
+#define MAXSWITCHES 80 // villsa [STRIFE] changed from 50 to 80
+
+ // 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,
+ slowDWUS, // villsa [STRIFE]
+ raiseAndChange,
+ raiseToNearestAndChange,
+ blazeDWUS,
+ upWaitDownStay // villsa [STRIFE]
+
+} 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;
+ 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
+{
+ normal,
+ close30ThenOpen,
+ close,
+ open,
+ raiseIn5Mins,
+ blazeRaise,
+ blazeOpen,
+ blazeClose,
+ shopClose, // villsa [STRIFE]
+ splitRaiseNearest, // villsa [STRIFE]
+ splitOpen // villsa [STRIFE]
+
+} 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;
+
+ // villsa [STRIFE] new field - sound to play when opening
+ int opensound;
+
+ // villsa [STRIFE] new field - sound to play when closing
+ int closesound;
+
+} 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 );
+
+
+
+// villsa [STRIFE] resurrected sliding doors
+//
+// Sliding doors...
+//
+typedef enum
+{
+ sd_opening,
+ sd_waiting,
+ sd_closing
+
+} sd_e;
+
+
+
+typedef enum
+{
+ sdt_openOnly,
+ sdt_closeOnly,
+ sdt_openAndClose
+
+} sdt_e;
+
+
+
+// villsa [STRIFE] Rogue added a second line_t in the struct
+// backsector is removed
+typedef struct
+{
+ thinker_t thinker;
+ sdt_e type;
+ line_t* line1;
+ line_t* line2;
+ int frame;
+ int whichDoorIndex;
+ int timer;
+ sector_t* frontsector;
+ sd_e status;
+
+} slidedoor_t;
+
+// villsa [STRIFE] no front/back frames
+typedef struct
+{
+ char frame1[9];
+ char frame2[9];
+ char frame3[9];
+ char frame4[9];
+ char frame5[9];
+ char frame6[9];
+ char frame7[9];
+ char frame8[9];
+
+} slidename_t;
+
+// villsa [STRIFE] no front/back frames
+typedef struct
+{
+ int frames[8];
+
+} slideframe_t;
+
+// haleyjd 09/29/10: [STRIFE] Externalized for savegames
+void T_SlidingDoor(slidedoor_t* door);
+
+
+// how many frames of animation
+#define SNUMFRAMES 8 // villsa [STRIFE] changed from 4 to 8
+
+#define SDOORWAIT TICRATE*3
+#define SWAITTICS 4
+
+// how many diff. types of anims
+#define MAXSLIDEDOORS 8 // villsa [STRIFE] changed from 5 to 8
+
+void P_InitSlidingDoorFrames(void);
+void EV_SlidingDoor(line_t* line, mobj_t* thing);
+int EV_RemoteSlidingDoor(line_t* line, mobj_t* thing);
+
+
+
+//
+// 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;
+ 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,
+
+ raiseFloor64, // [STRIFE] changed from 24 to 64
+ raiseFloor24AndChange,
+ raiseFloorCrush,
+
+ // raise to next highest floor, turbo-speed
+ raiseFloorTurbo,
+ donutRaise,
+ raiseFloor512,
+
+ // [STRIFE] New floor type - used for the coolant reactor pit
+ raiseFloor512AndChange
+
+} floor_e;
+
+
+
+
+typedef enum
+{
+ build8, // slowly build by 8
+ turbo16, // quickly build by 16
+ buildDown16 // haleyjd 09/24/10: [STRIFE] new stair type
+} stair_e;
+
+
+
+typedef struct
+{
+ thinker_t thinker;
+ floor_e type;
+ 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,
+ 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
+//
+
+// [STRIFE] Teleportation flags - teleflags
+// Not to be conflated with telefrags, though they be tangentially related ;)
+typedef enum teleflags
+{
+ TF_NOSRCSND = 0x01,
+ TF_NODSTSND = 0x02,
+ TF_NODSTFOG = 0x10,
+ TF_NOSRCFOG = 0x20,
+
+ TF_NORMAL = 0,
+ TF_DSTSILENCE = (TF_NODSTSND|TF_NODSTFOG), // 0x12 (18) (Not used)
+ TF_SRCSILENCE = (TF_NOSRCSND|TF_NOSRCFOG), // 0x21 (33)
+ TF_FULLSILENCE = (TF_SRCSILENCE|TF_DSTSILENCE) // 0x33 (51)
+
+} teleflags_e;
+
+int
+EV_Teleport
+( line_t* line,
+ int side,
+ mobj_t* thing,
+ teleflags_e flags);
+
+#endif
diff --git a/src/strife/p_switch.c b/src/strife/p_switch.c
new file mode 100644
index 00000000..bb70f890
--- /dev/null
+++ b/src/strife/p_switch.c
@@ -0,0 +1,1082 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//
+// DESCRIPTION:
+// Switches, buttons. Two-state animation. Exits.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+
+#include "i_system.h"
+#include "deh_main.h"
+#include "doomdef.h"
+#include "p_local.h"
+
+#include "g_game.h"
+#include "d_main.h" // villsa [STRIFE]
+#include "z_zone.h" // villsa [STRIFE]
+#include "w_wad.h" // villsa [STRIFE]
+#include "s_sound.h"
+#include "m_random.h" // haleyjd [STRIFE]
+#include "p_dialog.h"
+#include "p_local.h" // haleyjd [STRIFE]
+#include "m_bbox.h" // villsa [STRIFE]
+
+// Data.
+#include "sounds.h"
+
+// State.
+#include "doomstat.h"
+#include "r_state.h"
+
+//
+// CHANGE THE TEXTURE OF A WALL SWITCH TO ITS OPPOSITE
+//
+// villsa [STRIFE] new switch list
+switchlist_t alphSwitchList[] =
+{
+ { "GLASS01", "GLASS02", 1, sfx_bglass },
+ { "GLASS03", "GLASS04", 1, sfx_bglass },
+ { "GLASS05", "GLASS06", 1, sfx_bglass },
+ { "GLASS07", "GLASS08", 1, sfx_bglass },
+ { "GLASS17", "GLASS18", 1, sfx_bglass },
+ { "GLASS19", "GLASS20", 1, sfx_bglass },
+ { "SWKNOB01", "SWKNOB02", 1, sfx_swknob },
+ { "SWLITE01", "SWLITE02", 1, sfx_None },
+ { "SWCHN01", "SWCHN02", 1, sfx_pulchn },
+ { "COMP01", "COMP04B", 1, sfx_bglass },
+ { "COMP05", "COMP12B", 1, sfx_bglass },
+ { "COMP09", "COMP12B", 1, sfx_bglass },
+ { "COMP12", "COMP04B", 1, sfx_bglass },
+ { "COMP13", "COMP12B", 1, sfx_bglass },
+ { "COMP17", "COMP20B", 1, sfx_bglass },
+ { "COMP21", "COMP28B", 1, sfx_bglass },
+ { "WALTEK09", "WALTEKB1", 1, sfx_None },
+ { "WALTEK10", "WALTEKB1", 1, sfx_None },
+ { "WALTEK15", "WALTEKB1", 1, sfx_None },
+ { "SWFORC01", "SWFORC02", 1, sfx_None },
+ { "SWEXIT01", "SWEXIT02", 1, sfx_None },
+ { "DORSBK01", "DORSBK02", 1, sfx_swston },
+ { "SWSLD01", "SWSLD02", 1, sfx_None },
+ { "DORWS04", "DORWS05", 1, sfx_swbolt },
+ { "SWIRON01", "SWIRON02", 1, sfx_None },
+ { "GLASS09", "GLASS10", 2, sfx_bglass },
+ { "GLASS11", "GLASS12", 2, sfx_bglass },
+ { "GLASS13", "GLASS14", 2, sfx_bglass },
+ { "GLASS15", "GLASS16", 2, sfx_bglass },
+ { "SWFORC03", "SWFORC04", 2, sfx_None },
+ { "SWCIT01", "SWCIT02", 2, sfx_None },
+ { "SWTRMG01", "SWTRMG04", 2, sfx_None },
+ { "SWMETL01", "SWMETL02", 2, sfx_None },
+ { "SWWOOD01", "SWWOOD02", 2, sfx_None },
+ { "SWTKBL01", "SWTKBL02", 2, sfx_None },
+ { "AZWAL21", "AZWAL22", 2, sfx_None },
+ { "SWINDT01", "SWINDT02", 2, sfx_None },
+ { "SWRUST01", "SWRUST02", 2, sfx_None },
+ { "SWCHAP01", "SWCHAP02", 2, sfx_None },
+ { "SWALIN01", "SWALIN02", 2, sfx_None },
+ { "SWWALG01", "SWWALG02", 2, sfx_None },
+ { "SWWALG03", "SWWALG04", 2, sfx_None },
+ { "SWTRAM01", "SWTRAM02", 2, sfx_None },
+ { "SWTRAM03", "SWTRAM04", 2, sfx_None },
+ { "SWORC01", "SWORC02", 2, sfx_None },
+ { "SWBRIK01", "SWBRIK02", 2, sfx_None },
+ { "SWIRON03", "SWIRON04", 2, sfx_None },
+ { "SWIRON05", "SWIRON06", 2, sfx_None },
+ { "SWIRON07", "SWIRON08", 2, sfx_None },
+ { "SWCARD01", "SWCARD02", 2, sfx_keycrd },
+ { "SWSIGN01", "SWSIGN02", 2, sfx_None },
+ { "SWLEV01", "SWLEV02", 2, sfx_None },
+ { "SWLEV03", "SWLEV04", 2, sfx_None },
+ { "SWLEV05", "SWLEV06", 2, sfx_None },
+ { "SWBRN01", "SWBRN02", 2, sfx_keycrd },
+ { "SWPIP01", "SWPIP02", 2, sfx_valve },
+ { "SWPALM01", "SWPALM02", 2, sfx_swscan },
+ { "SWKNOB03", "SWKNOB04", 2, sfx_swknob },
+ { "ALTSW01", "ALTSW02", 2, sfx_None },
+ { "COMP25", "COMP28B", 2, sfx_bglass },
+ { "COMP29", "COMP20B", 2, sfx_bglass },
+ { "COMP33", "COMP50", 2, sfx_bglass },
+ { "COMP42", "COMP51", 2, sfx_bglass },
+ { "GODSCRN1", "GODSCRN2", 2, sfx_difool },
+ { "ALIEN04", "ALIEN05", 2, sfx_None },
+ { "CITADL04", "CITADL05", 2, sfx_None },
+ { "SWITE03", "SWITE04", 2, sfx_None },
+ { "SWTELP01", "SWTELP02", 2, sfx_None },
+ { "BRNSCN01", "BRNSCN05", 2, sfx_firxpl },
+ { "\0", "\0", 0, sfx_None }
+};
+
+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(isregistered)
+ episode = 2;
+ // villsa [STRIFE] unused
+ /*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(DEH_String(alphSwitchList[i].name1));
+ switchlist[index++] = R_TextureNumForName(DEH_String(alphSwitchList[i].name2));
+ }
+ }
+}
+
+
+//
+// P_StartButton
+// 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 = &line->frontsector->soundorg;
+ return;
+ }
+ }
+
+ I_Error("P_StartButton: no button slots left!");
+}
+
+
+//
+// P_SpawnBrokenGlass
+// villsa [STRIFE] new function
+//
+static void P_SpawnBrokenGlass(line_t* line)
+{
+ fixed_t x1;
+ fixed_t x2;
+ fixed_t y1;
+ fixed_t y2;
+ int i;
+ mobj_t* glass;
+ angle_t an;
+
+ x1 = (line->v2->x + line->v1->x) / 2;
+ y1 = (line->v2->y + line->v1->y) / 2;
+ x2 = ((line->frontsector->soundorg.x - x1) / 5) + x1;
+ y2 = ((line->frontsector->soundorg.y - y1) / 5) + y1;
+
+ for(i = 0; i < 7; i++)
+ {
+ glass = P_SpawnMobj(x2, y2, ONFLOORZ, MT_JUNK);
+ glass->z += (24*FRACUNIT);
+ glass->flags |= (MF_SHADOW|MF_MVIS);
+
+ P_SetMobjState(glass, P_Random() % 3 + S_SHRD_03); // 284
+
+ an = ((P_Random() << 13) / 255);
+
+ glass->angle = (an << ANGLETOFINESHIFT);
+ glass->momx = FixedMul(finecosine[an], (P_Random() & 3) << FRACBITS);
+ glass->momy = FixedMul(finesine[an], (P_Random() & 3) << FRACBITS);
+ glass->momz = (P_Random() & 7) << FRACBITS;
+ glass->tics += (P_Random() + 7) & 7;
+ }
+}
+
+
+//
+// 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;
+ boolean breakglass; // villsa [STRIFE]
+ switchlist_t* sl; // villsa [STRIFE]
+
+ breakglass = false; // villsa [STRIFE]
+
+ texTop = sides[line->sidenum[0]].toptexture;
+ texMid = sides[line->sidenum[0]].midtexture;
+ texBot = sides[line->sidenum[0]].bottomtexture;
+
+ sound = sfx_swtchn;
+
+ // villsa [STRIFE] check for linetype 182 (break glass)
+ if(line->special == 182)
+ {
+ line->flags &= ~ML_BLOCKING;
+ breakglass = true;
+
+ if(useAgain)
+ {
+ // haleyjd 09/21/10: Corrected (>> 16 == next field)
+ texTop = 0;
+ texBot = 0;
+ }
+
+ if(texMid) // haleyjd 09/21/10: Corrected (>> 16 == next field)
+ useAgain = 0;
+
+ sound = sfx_bglass;
+ }
+
+ if(!useAgain)
+ line->special = 0;
+
+ for(i = 0; i < numswitches*2; i++)
+ {
+ sl = &alphSwitchList[i / 2]; // villsa [STRIFE]
+
+ if(switchlist[i] == texTop)
+ {
+ // villsa [STRIFE] set sound
+ if(sl->sound)
+ sound = sl->sound;
+
+ S_StartSound(buttonlist->soundorg, sound);
+ sides[line->sidenum[0]].toptexture = switchlist[i^1];
+
+ if(useAgain)
+ P_StartButton(line,top,switchlist[i],BUTTONTIME);
+
+ if(breakglass)
+ P_SpawnBrokenGlass(line);
+
+ return;
+ }
+ else
+ {
+ if(switchlist[i] == texMid)
+ {
+ // villsa [STRIFE] set sound
+ if(sl->sound)
+ sound = sl->sound;
+
+ S_StartSound(buttonlist->soundorg,sound);
+ sides[line->sidenum[0]].midtexture = switchlist[i^1];
+
+ // villsa [STRIFE] affect second side of line
+ // BUG: will crash if 1S line is marked with TWOSIDED flag!
+ if(line->flags & ML_TWOSIDED)
+ sides[line->sidenum[1]].midtexture = switchlist[i^1];
+
+ if(useAgain)
+ P_StartButton(line, middle,switchlist[i],BUTTONTIME);
+
+ // villsa [STRIFE]: Mines Transmitter hack
+ if(sound == sfx_firxpl)
+ {
+ breakglass = true;
+
+ // give quest flag 29 to player
+ players[0].questflags |= QF_QUEST29;
+
+ // give stamina/accuracy items
+ if(!netgame)
+ {
+ P_GiveItemToPlayer(players, SPR_TOKN, MT_TOKEN_STAMINA);
+ P_GiveItemToPlayer(players, SPR_TOKN, MT_TOKEN_NEW_ACCURACY);
+ }
+
+ }
+
+ // villsa [STRIFE]
+ if(breakglass || sound == sfx_bglass)
+ P_SpawnBrokenGlass(line);
+
+ return;
+ }
+ else
+ {
+ if(switchlist[i] == texBot)
+ {
+ // villsa [STRIFE] set sound
+ if(sl->sound)
+ sound = sl->sound;
+
+ S_StartSound(buttonlist->soundorg,sound);
+ sides[line->sidenum[0]].bottomtexture = switchlist[i^1];
+
+ if(useAgain)
+ P_StartButton(line, bottom,switchlist[i],BUTTONTIME);
+
+ if(breakglass)
+ P_SpawnBrokenGlass(line);
+
+ return;
+ }
+ }
+ }
+ }
+}
+
+//
+// P_MoveWall
+//
+// villsa [STRIFE] New function.
+// Dynamically move a solid line. Unused in Strife
+//
+static void P_MoveWall(line_t *line, mobj_t *thing)
+{
+ vertex_t *v2;
+ vertex_t *v1;
+ fixed_t x;
+ fixed_t y;
+
+ v1 = line->v1;
+ v2 = line->v2;
+ S_StartSound(thing, sfx_stnmov);
+
+ if (line->dx)
+ {
+ if (thing->x >= v1->x)
+ {
+ v1->y -= (8 * FRACUNIT);
+ v2->y -= (8 * FRACUNIT);
+ }
+ else
+ {
+ v1->y += (8 * FRACUNIT);
+ v2->y += (8 * FRACUNIT);
+ }
+ }
+ else
+ {
+ if (thing->y >= v1->y)
+ {
+ v1->x -= (8 * FRACUNIT);
+ v2->x -= (8 * FRACUNIT);
+ }
+ else
+ {
+ v1->x += (8 * FRACUNIT);
+ v2->x += (8 * FRACUNIT);
+ }
+ }
+
+ if (v1->x >= v2->x)
+ {
+ line->bbox[BOXLEFT] = v2->x;
+ x = v1->x;
+ }
+ else
+ {
+ line->bbox[BOXLEFT] = v1->x;
+ x = v2->x;
+ }
+
+ line->bbox[BOXRIGHT] = x;
+
+ if (v1->y >= v2->y)
+ {
+ line->bbox[BOXBOTTOM] = v2->y;
+ y = v1->y;
+ }
+ else
+ {
+ line->bbox[BOXBOTTOM] = v1->y;
+ y = v2->y;
+ }
+
+ line->bbox[BOXTOP] = y;
+}
+
+// villsa [STRIFE]
+static char usemessage[92];
+
+//
+// P_UseSpecialLine
+// Called when a thing uses a special line.
+// Only the front sides of lines are usable.
+//
+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 148: // haleyjd [STRIFE]
+ break;
+
+ default:
+ return false;
+ }
+ }
+
+ // 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 31: // haleyjd [STRIFE]
+ case 144: // haleyjd [STRIFE] Manual sliding door
+ break;
+
+ default:
+ return false;
+ break;
+ }
+ }
+
+ // do something
+ switch(line->special)
+ {
+ // MANUALS
+ case 1: // Vertical Door
+ case 26: // DR ID Card
+ case 27: // DR Pass Card
+ case 28: // DR ID Badge
+ case 31: // Manual door open
+ case 32: // D1 ID Card
+ case 33: // D1 ID Badge
+ case 34: // D1 Pass Card
+ case 117: // Blazing door raise
+ case 118: // Blazing door open
+ case 156: // haleyjd [STRIFE] D1 Brass Key
+ case 157: // haleyjd [STRIFE] D1 Silver Key
+ case 158: // haleyjd [STRIFE] D1 Gold Key
+ case 159: // haleyjd [STRIFE] DR Gold Key
+ case 160: // haleyjd [STRIFE] DR Silver Key
+ case 161: // haleyjd [STRIFE] DR Brass Key
+ case 165: // villsa [STRIFE] That doesn't seem to work
+ case 166: // haleyjd [STRIFE] DR Hand Print
+ case 169: // haleyjd [STRIFE] DR Base Key
+ case 170: // haleyjd [STRIFE] DR Gov's Key
+ case 190: // haleyjd [STRIFE] DR Order Key
+ case 205: // villsa [STRIFE] Available in retail only
+ case 213: // haleyjd [STRIFE] DR Chalice
+ case 217: // haleyjd [STRIFE] DR Core Key
+ case 221: // haleyjd [STRIFE] DR Mauler Key
+ case 224: // haleyjd [STRIFE] DR Chapel Key
+ case 225: // haleyjd [STRIFE] DR Catacomb Key
+ case 232: // villsa [STRIFE] DR Oracle Pass
+ EV_VerticalDoor (line, thing);
+ break;
+
+ // haleyjd: For the sake of our sanity, I have reordered all the line
+ // specials from this point down so that they are strictly in numeric
+ // order, and not divided up in a semi-arbitrary fashion.
+
+ case 7:
+ // Build Stairs - [STRIFE] Verified unmodified
+ if (EV_BuildStairs(line,build8))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 9:
+ // Change Donut - [STRIFE] Verified unmodified
+ if (EV_DoDonut(line))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 11:
+ // Exit level - [STRIFE] Modified to take tag, etc.
+ P_ChangeSwitchTexture(line, 1);
+ if(levelTimer && levelTimeCount)
+ break;
+ G_ExitLevel(line->tag);
+ break;
+
+ case 14:
+ // Raise Floor 32 and change texture - [STRIFE] Verified unmodified
+ 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 - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line, raiseFloorToNearest))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 20:
+ // Raise Plat next highest floor and change texture - [STRIFE] Verified unmodified
+ if(EV_DoPlat(line, raiseToNearestAndChange, 0))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 21:
+ // PlatDownWaitUpStay - [STRIFE] Verified unmodified
+ if (EV_DoPlat(line, downWaitUpStay,0))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 23:
+ // Lower Floor to Lowest - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line,lowerFloorToLowest))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 29:
+ // Raise Door - [STRIFE] Verified unmodified
+ if (EV_DoDoor(line,normal))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 40:
+ // villsa [STRIFE] Split Open Door
+ if(EV_DoDoor(line, splitOpen))
+ P_ChangeSwitchTexture(line, 0);
+ break; // haleyjd
+
+ case 41:
+ // Lower Ceiling to Floor - [STRIFE] Verified unmodified
+ if (EV_DoCeiling(line,lowerToFloor))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 42:
+ // Close Door - [STRIFE] Verified unmodified
+ if (EV_DoDoor(line,close))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 43:
+ // Lower Ceiling to Floor - [STRIFE] Verified unmodified
+ if (EV_DoCeiling(line,lowerToFloor))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 45:
+ // Lower Floor to Surrounding floor height - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line,lowerFloor))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 49:
+ // Ceiling Crush And Raise - [STRIFE] Verified unmodified
+ if (EV_DoCeiling(line,crushAndRaise))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 50:
+ // Close Door - [STRIFE] Verified unmodified
+ if (EV_DoDoor(line,close))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 51:
+ // [STRIFE] Modifed into S1 Start Finale (was Secret Exit)
+ P_ChangeSwitchTexture(line,0);
+ G_StartFinale();
+ break;
+
+ case 55:
+ // Raise Floor Crush - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line,raiseFloorCrush))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 60:
+ // Lower Floor to Lowest - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line,lowerFloorToLowest))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 61:
+ // Open Door - [STRIFE] Verified unmodified
+ if (EV_DoDoor(line,open))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 62:
+ // PlatDownWaitUpStay - [STRIFE] Verified unmodified
+ if (EV_DoPlat(line, downWaitUpStay,1))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 63:
+ // Raise Door - [STRIFE] Verified unmodified
+ if (EV_DoDoor(line,normal))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 64:
+ // Raise Floor to ceiling - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line,raiseFloor))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 65:
+ // Raise Floor Crush - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line,raiseFloorCrush))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 66:
+ // Raise Floor 24 and change texture - [STRIFE] Verified unmodified
+ if (EV_DoPlat(line, raiseAndChange, 24))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 67:
+ // Raise Floor 32 and change texture - [STRIFE] Verified unmodified
+ if (EV_DoPlat(line, raiseAndChange, 32))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 68:
+ // Raise Plat to next highest floor and change texture - [STRIFE] Verified unmodified
+ if (EV_DoPlat(line, raiseToNearestAndChange, 0))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 69:
+ // Raise Floor to next highest floor - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line, raiseFloorToNearest))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 70:
+ // Turbo Lower Floor - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line,turboLower))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 71:
+ // Turbo Lower Floor - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line,turboLower))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 101:
+ // Raise Floor - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line,raiseFloor))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 102:
+ // Lower Floor to Surrounding floor height - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line,lowerFloor))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 103:
+ // Open Door - [STRIFE] Verified unmodified
+ if (EV_DoDoor(line,open))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 111:
+ // Blazing Door Raise (faster than TURBO!) - [STRIFE] Verified unmodified
+ if (EV_DoDoor (line,blazeRaise))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 112:
+ // Blazing Door Open (faster than TURBO!) - [STRIFE] Verified unmodified
+ if (EV_DoDoor (line,blazeOpen))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 113:
+ // Blazing Door Close (faster than TURBO!) - [STRIFE] Verified unmodified
+ if (EV_DoDoor (line,blazeClose))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 114:
+ // Blazing Door Raise (faster than TURBO!) - [STRIFE] Verified unmodified
+ if (EV_DoDoor (line,blazeRaise))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 115:
+ // Blazing Door Open (faster than TURBO!) - [STRIFE] Verified unmodified
+ if (EV_DoDoor (line,blazeOpen))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 116:
+ // Blazing Door Close (faster than TURBO!) - [STRIFE] Verified unmodified
+ if (EV_DoDoor (line,blazeClose))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 122:
+ // Blazing PlatDownWaitUpStay - [STRIFE] Verified unmodified
+ if(EV_DoPlat(line, blazeDWUS, 0))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 123:
+ // Blazing PlatDownWaitUpStay - [STRIFE] Verified unmodified
+ if(EV_DoPlat(line, blazeDWUS, 0))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 127:
+ // Build Stairs Turbo 16 - [STRIFE] Verified unmodified
+ if (EV_BuildStairs(line,turbo16))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 131:
+ // Raise Floor Turbo - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line,raiseFloorTurbo))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 132:
+ // Raise Floor Turbo - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line,raiseFloorTurbo))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 133: // [STRIFE] TODO - which key is it?
+ case 135: // [STRIFE] TODO - which key is it?
+ case 137: // [STRIFE] TODO - which key is it?
+ if (EV_DoLockedDoor (line,blazeOpen,thing))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 99: // [STRIFE] TODO: which key is it?
+ case 134: // [STRIFE] TODO: which key is it?
+ case 136: // [STRIFE] TODO: which key is it?
+ if (EV_DoLockedDoor (line,blazeOpen,thing))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 138:
+ // Light Turn On - [STRIFE] Verified unmodified
+ EV_LightTurnOn(line,255);
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 139:
+ // Light Turn Off - [STRIFE] Verified unmodified
+ EV_LightTurnOn(line,35);
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 140:
+ // Raise Floor 512 - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line,raiseFloor512))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 144:
+ // villsa [STRIFE] manual sliding door
+ EV_SlidingDoor(line, thing);
+ break;
+
+ case 146:
+ // haleyjd 09/24/10: [STRIFE] S1 Build Stairs Down 16 (new type)
+ if(EV_BuildStairs(line, buildDown16))
+ P_ChangeSwitchTexture(line, 0);
+ break;
+
+ case 147:
+ // haleyjd 09/24/10: [STRIFE] S1 Clear Force Fields
+ if(EV_ClearForceFields(line))
+ P_ChangeSwitchTexture(line, 0);
+ break;
+
+ case 148:
+ // haleyjd 09/16/10: [STRIFE] using forcefields hurts
+ P_DamageMobj(thing, NULL, NULL, 16);
+ P_Thrust(thing->player, thing->angle + ANG180, 125*FRACUNIT/16);
+ break;
+
+ case 151: // villsa [STRIFE] BlzOpenDoor Gold key
+ case 152: // [STRIFE] TODO: which key is it?
+ case 153: // [STRIFE] TODO: which key is it?
+ if(EV_DoLockedDoor(line, blazeOpen, thing))
+ P_ChangeSwitchTexture(line, 1);
+ break;
+
+ case 154:
+ // villsa [STRIFE] plat lower wait rise if have gold key
+ if(thing->player->cards[key_GoldKey])
+ {
+ if(EV_DoPlat(line, downWaitUpStay, 0))
+ P_ChangeSwitchTexture(line, 1);
+ }
+ else
+ {
+ thing->player->message = DEH_String("You need a gold key");
+ S_StartSound(thing, sfx_oof);
+ }
+ break;
+
+ case 155:
+ // villsa [STRIFE] raise plat wait lower
+ if(EV_DoPlat(line, upWaitDownStay, 0))
+ P_ChangeSwitchTexture(line, 1);
+ break;
+
+ case 162: // [STRIFE] TODO: which key is it?
+ case 163: // [STRIFE] TODO: which key is it?
+ case 164: // villsa [STRIFE] BlzOpenDoor Gold key
+ case 167: // [STRIFE] TODO: which key is it?
+ if(EV_DoLockedDoor(line, blazeOpen, thing))
+ P_ChangeSwitchTexture(line, 0);
+ break;
+
+ case 168: // [STRIFE] TODO: which key is it?
+ // haleyjd 09/25/10: [STRIFE] SR Blaze Open Door ???? Key
+ if(EV_DoLockedDoor(line, blazeOpen, thing))
+ P_ChangeSwitchTexture(line, 1);
+ break;
+
+ case 171: // [STRIFE] TODO: which key is it?
+ // haleyjd 09/25/10: [STRIFE] S1 Open Door ???? Key
+ if(EV_DoLockedDoor(line, open, thing))
+ P_ChangeSwitchTexture(line, 0);
+ break;
+
+ case 172: // [STRIFE] TODO: which key is it?
+ case 173: // [STRIFE] TODO: which key is it?
+ case 176: // [STRIFE] TODO: which key is it?
+ case 191: // [STRIFE] TODO: which key is it?
+ case 192: // [STRIFE] TODO: which key is it?
+ case 223: // [STRIFE] TODO: which key is it?
+ if(EV_DoLockedDoor(line, normal, thing))
+ P_ChangeSwitchTexture(line, 1);
+ break;
+
+ case 177:
+ // villsa [STRIFE] plat lower wait rise if have power3 key
+ if(thing->player->cards[key_Power3Key])
+ {
+ if(EV_DoPlat(line, downWaitUpStay, 0))
+ P_ChangeSwitchTexture(line, 1);
+ }
+ else
+ {
+ thing->player->message = DEH_String("You don't have the key");
+ S_StartSound(thing, sfx_oof);
+ }
+ break;
+
+ case 181:
+ // haleyjd 09/25/10: [STRIFE] S1 Floor Raise 512 & Change
+ if(EV_DoFloor(line, raiseFloor512AndChange))
+ P_ChangeSwitchTexture(line, 0);
+ break;
+
+ case 189: // [STRIFE] TODO: which key is it???
+ // haleyjd 09/25/10: [STRIFE] S1 Split Open Door ???? Key
+ if(EV_DoLockedDoor(line, splitOpen, thing))
+ P_ChangeSwitchTexture(line, 0);
+ break;
+
+ case 194:
+ // villsa [STRIFE] S1 Free Prisoners
+ if(EV_DoDoor(line, open))
+ {
+ P_ChangeSwitchTexture(line, 0);
+ P_FreePrisoners();
+ }
+ break;
+
+ case 199:
+ // haleyjd 09/25/10: [STRIFE] S1 Destroy Converter
+ if(EV_DoCeiling(line, lowerAndCrush))
+ {
+ P_ChangeSwitchTexture(line, 0);
+ P_DestroyConverter();
+ }
+ break;
+
+ case 207:
+ // villsa [STRIFE] SR Remote Sliding Door
+ if(EV_RemoteSlidingDoor(line, thing))
+ P_ChangeSwitchTexture(line, 1);
+ break; // haleyjd
+
+ case 209:
+ // haleyjd 09/24/10: [STRIFE] S1 Build Stairs Down 16 if Have Chalice
+ if(!P_PlayerHasItem(thing->player, MT_INV_CHALICE))
+ {
+ DEH_snprintf(usemessage, sizeof(usemessage), "You need the chalice!");
+ thing->player->message = usemessage;
+ S_StartSound(thing, sfx_oof);
+ break;
+ }
+ else if(EV_BuildStairs(line, buildDown16))
+ P_ChangeSwitchTexture(line, 0);
+ break;
+
+ case 211:
+ // villsa [STRIFE] S1 Play VOC## sound
+ if(&players[consoleplayer] == thing->player &&
+ thing->player->powers[pw_communicator])
+ {
+ DEH_snprintf(usemessage, sizeof(usemessage), "voc%i", line->tag);
+ I_StartVoice(usemessage);
+ line->special = 0;
+ }
+ break;
+
+ case 214:
+ // villsa [STRIFE] S1 slow lift lower wait up stay
+ if(EV_DoPlat(line, slowDWUS, 1))
+ P_ChangeSwitchTexture(line, 1);
+ break;
+
+ case 219:
+ // haleyjd 09/25/10: S1 Lower Floor Blue Crystal
+ if(!thing->player->cards[key_BlueCrystalKey])
+ {
+ thing->player->message = DEH_String("You need the Blue Crystal");
+ S_StartSound(thing, sfx_oof);
+ }
+ else if(EV_DoFloor(line, lowerFloor))
+ P_ChangeSwitchTexture(line, 0);
+ break;
+
+ case 220:
+ // haleyjd 09/25/10: S1 Lower Floor Red Crystal
+ if(!thing->player->cards[key_RedCrystalKey])
+ {
+ thing->player->message = DEH_String("You need the Red Crystal");
+ S_StartSound(thing, sfx_oof);
+ }
+ else if(EV_DoFloor(line, lowerFloor))
+ P_ChangeSwitchTexture(line, 0);
+ break;
+
+ case 226:
+ // villsa [STRIFE] S1 Complete Training Area
+ if(EV_DoFloor(line, lowerFloor))
+ {
+ P_GiveItemToPlayer(thing->player, SPR_TOKN, MT_TOKEN_STAMINA);
+ P_GiveItemToPlayer(thing->player, SPR_TOKN, MT_TOKEN_NEW_ACCURACY);
+ P_ChangeSwitchTexture(line, 0);
+ DEH_snprintf(usemessage, sizeof(usemessage),
+ DEH_String("Congratulations! You have completed the training area."));
+ thing->player->message = usemessage;
+ }
+ break;
+
+ case 229:
+ // villsa [STRIFE] SR Sigil Sliding Door
+ if(thing->player->sigiltype == 4)
+ {
+ if(EV_RemoteSlidingDoor(line, thing))
+ P_ChangeSwitchTexture(line, 1);
+ }
+ break; // haleyjd
+
+ case 233:
+ // villsa [STRIFE] objective given after revealing the computer
+ if(!EV_DoDoor(line, splitOpen))
+ return true;
+
+ P_ChangeSwitchTexture(line, 1);
+ GiveVoiceObjective("voc70", "log70", 0);
+
+ // haleyjd: Strife used sprintf here, not a direct set.
+ DEH_snprintf(usemessage, sizeof(usemessage),
+ "Incoming Message from BlackBird...");
+ thing->player->message = usemessage;
+
+ break;
+
+ case 234:
+ // haleyjd 09/24/10: [STRIFE] SR Raise Door if Quest 3
+ if(!(thing->player->questflags & QF_QUEST3)) // QUEST3 == Irale
+ {
+ // BUG: doesn't make sfx_oof sound like all other message-
+ // giving door types. I highly doubt this was intentional.
+ DEH_snprintf(usemessage, sizeof(usemessage),
+ "That doesn't seem to work!");
+ thing->player->message = usemessage;
+ }
+ else if(EV_DoDoor(line, normal))
+ P_ChangeSwitchTexture(line, 1);
+ break;
+
+ case 235:
+ // haleyjd 09/25/10: [STRIFE] S1 Split Open Door if Have Sigil 4
+ if(thing->player->sigiltype == 4)
+ {
+ if(EV_DoDoor(line, splitOpen))
+ P_ChangeSwitchTexture(line, 0);
+ }
+ break;
+
+ case 666:
+ // villsa [STRIFE] SR Move Wall
+ P_MoveWall(line, thing);
+ break;
+ }
+
+ return true;
+}
+
diff --git a/src/strife/p_telept.c b/src/strife/p_telept.c
new file mode 100644
index 00000000..b6928b27
--- /dev/null
+++ b/src/strife/p_telept.c
@@ -0,0 +1,160 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Teleportation.
+//
+//-----------------------------------------------------------------------------
+
+
+
+
+#include "doomdef.h"
+#include "doomstat.h"
+
+#include "s_sound.h"
+
+#include "p_local.h"
+
+
+// Data.
+#include "sounds.h"
+
+// State.
+#include "r_state.h"
+
+
+
+//
+// TELEPORTATION
+//
+// haleyjd 09/22/10: [STRIFE] Modified to take a flags parameter to control
+// silent teleportation. Rogue also removed the check for missiles, and the
+// z-set was replaced with one in P_TeleportMove.
+//
+int
+EV_Teleport
+( line_t* line,
+ int side,
+ mobj_t* thing,
+ teleflags_e flags)
+{
+ int i;
+ int tag;
+ mobj_t* m;
+ mobj_t* fog = NULL;
+ unsigned an;
+ thinker_t* thinker;
+ sector_t* sector;
+ fixed_t oldx;
+ fixed_t oldy;
+ fixed_t oldz;
+
+ // haleyjd 20110205 [STRIFE]: this is not checked here
+ // 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;
+
+ // fraggle: this was changed in final doom,
+ // problem between normal doom2 1.9 and final doom
+ //
+ // Note that although chex.exe is based on Final Doom,
+ // it does not have this quirk.
+ //
+ // haleyjd 20110205 [STRIFE] This code is *not* present,
+ // because of a z-set which Rogue added to P_TeleportMove.
+ /*
+ if (gameversion < exe_final || gameversion == exe_chex)
+ thing->z = thing->floorz;
+ */
+
+ if (thing->player)
+ thing->player->viewz = thing->z+thing->player->viewheight;
+
+ // spawn teleport fog at source and destination
+ // haleyjd 09/22/10: [STRIFE] controlled by teleport flags
+ // BUG: Behavior would be undefined if this function were passed
+ // any combination of teleflags that has the NO*FOG but not the
+ // corresponding NO*SND flag - fortunately this is never done
+ // anywhere in the code.
+ if(!(flags & TF_NOSRCFOG))
+ fog = P_SpawnMobj (oldx, oldy, oldz, MT_TFOG);
+ if(!(flags & TF_NOSRCSND))
+ S_StartSound (fog, sfx_telept);
+
+ an = m->angle >> ANGLETOFINESHIFT;
+
+ if(!(flags & TF_NODSTFOG))
+ fog = P_SpawnMobj (m->x+20*finecosine[an], m->y+20*finesine[an],
+ thing->z, MT_TFOG);
+ if(!(flags & TF_NODSTSND))
+ 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;
+}
+
diff --git a/src/strife/p_tick.c b/src/strife/p_tick.c
new file mode 100644
index 00000000..4a7ead62
--- /dev/null
+++ b/src/strife/p_tick.c
@@ -0,0 +1,165 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Archiving: SaveGame I/O.
+// Thinker, Ticker.
+//
+//-----------------------------------------------------------------------------
+
+
+#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
+//
+// [STRIFE] Verified unmodified
+//
+void P_InitThinkers (void)
+{
+ thinkercap.prev = thinkercap.next = &thinkercap;
+}
+
+
+
+
+//
+// P_AddThinker
+// Adds a new thinker at the end of the list.
+//
+// [STRIFE] Verified unmodified
+//
+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.
+//
+// [STRIFE] Verified unmodified
+//
+void P_RemoveThinker (thinker_t* thinker)
+{
+ // FIXME: NOP.
+ thinker->function.acv = (actionf_v)(-1);
+}
+
+
+
+//
+// P_AllocateThinker
+// Allocates memory and adds a new thinker at the end of the list.
+//
+void P_AllocateThinker (thinker_t* thinker)
+{
+}
+
+//
+// P_RunThinkers
+//
+// [STRIFE] Verified unmodified
+//
+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
+//
+// [STRIFE] Menu pause behavior modified
+//
+void P_Ticker (void)
+{
+ int i;
+
+ // run the tic
+ if (paused)
+ return;
+
+ // pause if in menu and at least one tic has been run
+ // haleyjd 09/08/10 [STRIFE]: menuactive -> menupause
+ if (!netgame
+ && menupause
+ && !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++;
+}
diff --git a/src/strife/p_tick.h b/src/strife/p_tick.h
new file mode 100644
index 00000000..06934bb8
--- /dev/null
+++ b/src/strife/p_tick.h
@@ -0,0 +1,41 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// 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
diff --git a/src/strife/p_user.c b/src/strife/p_user.c
new file mode 100644
index 00000000..aa2ba430
--- /dev/null
+++ b/src/strife/p_user.c
@@ -0,0 +1,922 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Player related stuff.
+// Bobbing POV/weapon, movement.
+// Pending weapon.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdlib.h>
+
+#include "doomdef.h"
+#include "d_event.h"
+#include "p_local.h"
+#include "sounds.h" // villsa [STRIFE]
+#include "p_dialog.h" // villsa [STRIFE]
+#include "d_main.h" // villsa [STRIFE]
+#include "doomstat.h"
+#include "deh_str.h" // haleyjd [STRIFE]
+#include "z_zone.h"
+#include "w_wad.h"
+#include "p_pspr.h"
+#include "m_random.h"
+#include "s_sound.h"
+#include "p_inter.h"
+
+
+
+// Index of the special effects (INVUL inverse) map.
+#define LOOKPITCHAMOUNT 6 // villsa [STRIFE]
+#define CENTERVIEWAMOUNT (LOOKPITCHAMOUNT + 2) // villsa [STRIFE]
+#define LOOKUPMAX 90 // villsa [STRIFE]
+#define LOOKDOWNMAX -110 // villsa [STRIFE]
+
+
+void P_DropInventoryItem(player_t* player, int sprite); // villsa [STRIFE]
+boolean P_ItemBehavior(player_t* player, int item); // villsa [STRIFE]
+static char useinventorymsg[44]; // villsa [STRIFE]
+
+//
+// Movement.
+//
+
+// 16 pixels of bob
+#define MAXBOB 0x100000
+
+boolean onground;
+
+
+//
+// P_Thrust
+// Moves the given origin along a given angle.
+//
+// [STRIFE] Verified unmodified
+//
+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
+//
+// [STRIFE] Some odd adjustments, and terrain view 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;
+
+ // haleyjd 20110205 [STRIFE]: No CF_NOMOMENTUM check, and Rogue also removed
+ // the dead code inside.
+ if (!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;
+
+ // villsa [STRIFE] account for terrain lowering the view
+ if(player->mo->flags & MF_FEETCLIPPED)
+ player->viewz -= 13*FRACUNIT;
+
+ if (player->viewz > player->mo->ceilingz-4*FRACUNIT)
+ player->viewz = player->mo->ceilingz-4*FRACUNIT;
+
+ // haleyjd [STRIFE]: added a floorz clip here
+ if (player->viewz < player->mo->floorz)
+ player->viewz = player->mo->floorz;
+}
+
+
+
+//
+// P_MovePlayer
+//
+// [STRIFE] Adjustments to allow air control, jumping, and up/down look.
+//
+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);
+
+ // villsa [STRIFE] allows player to climb over things by jumping
+ // haleyjd 20110205: air control thrust should be 256, not cmd->forwardmove
+ if(!onground)
+ {
+ if(cmd->forwardmove)
+ P_Thrust (player, player->mo->angle, 256);
+ }
+ else
+ {
+ // villsa [STRIFE] jump button
+ if (cmd->buttons2 & BT2_JUMP)
+ {
+ if(!player->deltaviewheight)
+ player->mo->momz += 8*FRACUNIT;
+ }
+
+ // haleyjd 20110205 [STRIFE] Either Rogue or Watcom removed the
+ // redundant "onground" checks from these if's.
+ if (cmd->forwardmove)
+ P_Thrust (player, player->mo->angle, cmd->forwardmove*2048);
+
+ if (cmd->sidemove)
+ P_Thrust (player, player->mo->angle-ANG90, cmd->sidemove*2048);
+ }
+
+ // villsa [STRIFE] player walking state set
+ if ( (cmd->forwardmove || cmd->sidemove)
+ && player->mo->state == &states[S_PLAY_00] )
+ {
+ P_SetMobjState (player->mo, S_PLAY_01);
+ }
+
+ // villsa [STRIFE] centerview button
+ if (cmd->buttons2 & BT2_CENTERVIEW)
+ player->centerview = 1;
+
+ // villsa [STRIFE] adjust player's pitch when centerviewing
+ if (player->centerview)
+ {
+ if (player->pitch <= 0)
+ {
+ if (player->pitch < 0)
+ player->pitch = player->pitch + CENTERVIEWAMOUNT;
+ }
+ else
+ {
+ player->pitch = player->pitch - CENTERVIEWAMOUNT;
+ }
+ if (abs(player->pitch) < CENTERVIEWAMOUNT)
+ {
+ player->pitch = 0;
+ player->centerview = 0;
+ }
+ }
+
+ // villsa [STRIFE] look up action
+ if (cmd->buttons2 & BT2_LOOKUP)
+ {
+ player->pitch += LOOKPITCHAMOUNT;
+ if ((player->pitch + LOOKPITCHAMOUNT) > LOOKUPMAX ||
+ (player->pitch + LOOKPITCHAMOUNT) < LOOKDOWNMAX)
+ player->pitch -= LOOKPITCHAMOUNT;
+ }
+ else
+ {
+ // villsa [STRIFE] look down action
+ if (cmd->buttons2 & BT2_LOOKDOWN)
+ {
+ player->pitch -= LOOKPITCHAMOUNT;
+ if ((player->pitch - LOOKPITCHAMOUNT) > LOOKUPMAX ||
+ (player->pitch - LOOKPITCHAMOUNT) < LOOKDOWNMAX)
+ player->pitch += LOOKPITCHAMOUNT;
+ }
+ }
+
+}
+
+
+
+//
+// P_DeathThink
+// Fall on your face when dying.
+// Decrease POV height to floor height.
+//
+// [STRIFE] Modifications for up/down look.
+//
+#define ANG5 (ANG90/18)
+
+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--;
+
+ // villsa [STRIFE]
+ if(player->pitch <= 90)
+ player->pitch = player->pitch + 3;
+
+ if(player->cmd.buttons & BT_USE)
+ player->playerstate = PST_REBORN;
+}
+
+
+
+//
+// P_PlayerThink
+//
+// [STRIFE] Massive changes/additions:
+// * NOCLIP hack removed
+// * P_DeathThink moved up
+// * Inventory use/dropping
+// * Strife weapons logic
+// * Dialog
+// * Strife powerups and nukage behavior
+// * Fire Death/Sigil Shock
+//
+void P_PlayerThink (player_t* player)
+{
+ ticcmd_t* cmd;
+ weapontype_t newweapon;
+
+ // villsa [STRIFE] unused code (see ST_Responder)
+ /*
+ // fixme: do this in the cheat code
+ if (player->cheats & CF_NOCLIP)
+ player->mo->flags |= MF_NOCLIP;
+ else
+ player->mo->flags &= ~MF_NOCLIP;
+ */
+
+ // haleyjd 20110205 [STRIFE]: P_DeathThink moved up
+ if (player->playerstate == PST_DEAD)
+ {
+ P_DeathThink (player);
+ return;
+ }
+
+ // 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;
+ }
+
+ // 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);
+
+ // villsa [STRIFE] handle inventory input
+ if(cmd->buttons2 & (BT2_HEALTH|BT2_INVUSE|BT2_INVDROP))
+ {
+ if(!player->inventorydown)
+ {
+ if(cmd->buttons2 & BT2_HEALTH)
+ P_UseInventoryItem(player, SPR_FULL);
+ else if(cmd->buttons2 & BT2_INVUSE)
+ P_UseInventoryItem(player, cmd->inventory);
+ else if(cmd->buttons2 & BT2_INVDROP)
+ {
+ P_DropInventoryItem(player, cmd->inventory);
+
+ // haleyjd 20110205: removed incorrect "else" here
+ // villsa [STRIFE]
+ if(workparm)
+ {
+ int cheat = player->cheats ^ 1;
+ player->cheats ^= CF_NOCLIP;
+
+ if(cheat & CF_NOCLIP)
+ {
+ player->message = DEH_String("No Clipping Mode ON");
+ player->mo->flags |= MF_NOCLIP;
+ }
+ else
+ {
+ player->mo->flags &= ~MF_NOCLIP;
+ player->message = DEH_String("No Clipping Mode OFF");
+ }
+ }
+ }
+ }
+
+ player->inventorydown = true;
+ }
+ else
+ player->inventorydown = false;
+
+ // 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;
+
+ // villsa [STRIFE] select poison bow
+ if(newweapon == wp_elecbow)
+ {
+ if(player->weaponowned[wp_poisonbow] && player->readyweapon == wp_elecbow)
+ {
+ if(player->ammo[weaponinfo[wp_poisonbow].ammo])
+ newweapon = wp_poisonbow;
+ }
+ }
+
+ // villsa [STRIFE] select wp grenade launcher
+ if(newweapon == wp_hegrenade)
+ {
+ if(player->weaponowned[wp_wpgrenade] && player->readyweapon == wp_hegrenade)
+ {
+ if(player->ammo[weaponinfo[wp_wpgrenade].ammo])
+ newweapon = wp_wpgrenade;
+ }
+ }
+
+ // villsa [STRIFE] select torpedo
+ if(newweapon == wp_mauler)
+ {
+ if(player->weaponowned[wp_torpedo] && player->readyweapon == wp_mauler)
+ {
+ if(player->ammo[weaponinfo[am_cell].ammo] >= 30)
+ newweapon = wp_torpedo;
+ }
+ }
+
+ if(player->weaponowned[newweapon] && newweapon != player->readyweapon)
+ {
+ // villsa [STRIFE] check weapon if in demo mode or not
+ if(weaponinfo[newweapon].availabledemo || !isdemoversion)
+ {
+ if(player->ammo[weaponinfo[newweapon].ammo])
+ player->pendingweapon = newweapon;
+ else
+ {
+ // decide between electric bow or poison arrow
+ if(newweapon == wp_elecbow &&
+ player->ammo[am_poisonbolts] &&
+ player->readyweapon != wp_poisonbow)
+ {
+ player->pendingweapon = wp_poisonbow;
+ }
+ // decide between hp grenade launcher or wp grenade launcher
+ else if(newweapon == wp_hegrenade &&
+ player->ammo[am_wpgrenades] &&
+ player->readyweapon != wp_wpgrenade)
+ {
+ player->pendingweapon = wp_wpgrenade;
+ }
+
+ // villsa [STRIFE] - no check for mauler/torpedo??
+ }
+ }
+ }
+ }
+
+ // check for use
+ if(cmd->buttons & BT_USE)
+ {
+ if(!player->usedown)
+ {
+ P_DialogStart(player); // villsa [STRIFE]
+ 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]++;
+
+ // villsa [STRIFE] targeter powerup
+ if(player->powers[pw_targeter])
+ {
+ player->powers[pw_targeter]--;
+ if(player->powers[pw_targeter] == 1)
+ {
+ P_SetPsprite(player, ps_targcenter, S_NULL);
+ P_SetPsprite(player, ps_targleft, S_NULL);
+ P_SetPsprite(player, ps_targright, S_NULL);
+ }
+ else if(player->powers[pw_targeter] - 1 < 5*TICRATE)
+ {
+ if(player->powers[pw_targeter] & 32)
+ {
+ P_SetPsprite(player, ps_targright, S_NULL);
+ P_SetPsprite(player, ps_targleft, S_TRGT_01); // 11
+ }
+ else if(player->powers[pw_targeter] & 16) // haleyjd 20110205: missing else
+ {
+ P_SetPsprite(player, ps_targright, S_TRGT_02); // 12
+ P_SetPsprite(player, ps_targleft, S_NULL);
+ }
+ }
+ }
+
+ if(player->powers[pw_invisibility])
+ {
+ // villsa [STRIFE] remove mvis flag as well
+ if(!--player->powers[pw_invisibility])
+ player->mo->flags &= ~(MF_SHADOW|MF_MVIS);
+ }
+
+ if(player->powers[pw_ironfeet])
+ {
+ player->powers[pw_ironfeet]--;
+
+ // villsa [STRIFE] gasmask sound
+ if(!(leveltime & 0x3f))
+ S_StartSound(player->mo, sfx_mask);
+ }
+
+ if(player->powers[pw_allmap] > 1)
+ player->powers[pw_allmap]--;
+
+ // haleyjd 08/30/10: [STRIFE]
+ // Nukage count keeps track of exposure to hazardous conditions over time.
+ // After accumulating 16 total seconds or more of exposure, you will take
+ // 5 damage roughly once per second until the count drops back under 560
+ // tics.
+ if(player->nukagecount)
+ {
+ player->nukagecount--;
+ if(!(leveltime & 0x1f) && player->nukagecount > 16*TICRATE)
+ P_DamageMobj(player->mo, NULL, NULL, 5);
+ }
+
+ if(player->damagecount)
+ player->damagecount--;
+
+ if(player->bonuscount)
+ player->bonuscount--;
+
+ // villsa [STRIFE] checks for extralight
+ if(player->extralight >= 0)
+ {
+ if(player->cheats & CF_ONFIRE)
+ player->fixedcolormap = 1;
+ else
+ player->fixedcolormap = 0;
+ }
+ else // Sigil shock:
+ player->fixedcolormap = INVERSECOLORMAP;
+}
+
+
+//
+// P_RemoveInventoryItem
+// villsa [STRIFE] new function
+//
+char* P_RemoveInventoryItem(player_t *player, int slot, int amount)
+{
+ mobjtype_t type;
+
+ player->inventory[slot].amount -= amount;
+ player->st_update = true;
+
+ type = player->inventory[slot].type;
+
+ if(!player->inventory[slot].amount)
+ {
+ // shift everything above it down
+ // see P_TakeDialogItem for notes on possible bugs
+ int j;
+
+ for(j = slot + 1; j <= player->numinventory; j++)
+ {
+ inventory_t *item1 = &(player->inventory[j - 1]);
+ inventory_t *item2 = &(player->inventory[j]);
+
+ *item1 = *item2;
+ }
+
+ player->inventory[player->numinventory].type = NUMMOBJTYPES;
+ player->inventory[player->numinventory].sprite = -1;
+ player->numinventory--;
+
+ // update cursor position
+ if(player->inventorycursor >= player->numinventory)
+ {
+ if(player->inventorycursor)
+ player->inventorycursor--;
+ }
+ }
+
+ return mobjinfo[type].name;
+}
+
+//
+// P_DropInventoryItem
+// villsa [STRIFE] new function
+//
+void P_DropInventoryItem(player_t* player, int sprite)
+{
+ int invslot;
+ inventory_t *item;
+ mobjtype_t type;
+ int amount;
+
+ invslot = 0;
+ amount = 1;
+
+ while(invslot < player->numinventory && sprite != player->inventory[invslot].sprite)
+ invslot++;
+
+ item = &(player->inventory[invslot]);
+ type = item->type;
+
+ if(item->amount)
+ {
+ angle_t angle;
+ fixed_t dist;
+ mobj_t* mo;
+ mobj_t* mobjitem;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ int r;
+
+ if(item->type == MT_MONY_1)
+ {
+ if(item->amount >= 50)
+ {
+ type = MT_MONY_50;
+ amount = 50;
+ }
+ else if(item->amount >= 25)
+ {
+ type = MT_MONY_25;
+ amount = 25;
+ }
+ else if(item->amount >= 10)
+ {
+ type = MT_MONY_10;
+ amount = 10;
+ }
+ }
+
+ if(type >= NUMMOBJTYPES)
+ return;
+
+ angle = player->mo->angle;
+ r = P_Random();
+ angle = (angle + ((r - P_Random()) << 18)) >> ANGLETOFINESHIFT;
+
+ if(angle < 7618 && angle >= 6718)
+ angle = 7618;
+
+ else if(angle < 5570 && angle >= 4670)
+ angle = 5570;
+
+ else if(angle < 3522 && angle >= 2622)
+ angle = 3522;
+
+ else if(angle < 1474 && angle >= 574)
+ angle = 1474;
+
+ mo = player->mo;
+ dist = mobjinfo[type].radius + mo->info->radius + (4*FRACUNIT);
+
+ x = mo->x + FixedMul(finecosine[angle], dist);
+ y = mo->y + FixedMul(finesine[angle], dist);
+ z = mo->z + (10*FRACUNIT);
+ mobjitem = P_SpawnMobj(x, y, z, type);
+ mobjitem->flags |= (MF_SPECIAL|MF_DROPPED);
+
+ if(P_CheckPosition(mobjitem, x, y))
+ {
+ mobjitem->angle = (angle << ANGLETOFINESHIFT);
+ mobjitem->momx = FixedMul(finecosine[angle], (5*FRACUNIT)) + mo->momx;
+ mobjitem->momy = FixedMul(finesine[angle], (5*FRACUNIT)) + mo->momy;
+ mobjitem->momz = FRACUNIT;
+
+ P_RemoveInventoryItem(player, invslot, amount);
+ }
+ else
+ P_RemoveMobj(mobjitem);
+ }
+}
+
+//
+// P_TossDegninOre
+// villsa [STRIFE] new function
+//
+boolean P_TossDegninOre(player_t* player)
+{
+ angle_t angle;
+ mobj_t* mo;
+ mobj_t* ore;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ fixed_t dist;
+
+ angle = player->mo->angle >> ANGLETOFINESHIFT;
+
+ if(angle < 7618 && angle >= 6718)
+ angle = 7618;
+
+ else if(angle < 5570 && angle >= 4670)
+ angle = 5570;
+
+ else if(angle < 3522 && angle >= 2622)
+ angle = 3522;
+
+ else if(angle < 1474 && angle >= 574)
+ angle = 1474;
+
+ mo = player->mo;
+ dist = mobjinfo[MT_DEGNINORE].radius + mo->info->radius + (4*FRACUNIT);
+
+ x = mo->x + FixedMul(finecosine[angle], dist);
+ y = mo->y + FixedMul(finesine[angle], dist);
+ z = mo->z + (10*FRACUNIT);
+ ore = P_SpawnMobj(x, y, z, MT_DEGNINORE);
+
+ if(P_CheckPosition(ore, x, y))
+ {
+ ore->target = mo;
+ ore->angle = (angle << ANGLETOFINESHIFT);
+ ore->momx = FixedMul(finecosine[angle], (5*FRACUNIT));
+ ore->momy = FixedMul(finesine[angle], (5*FRACUNIT));
+ ore->momz = FRACUNIT;
+ return true;
+ }
+ else
+ P_RemoveMobj(ore);
+
+ return false;
+}
+
+//
+// P_SpawnTeleportBeacon
+// villsa [STRIFE] new function
+//
+boolean P_SpawnTeleportBeacon(player_t* player)
+{
+ angle_t angle;
+ int r;
+ mobj_t* mo;
+ mobj_t* beacon;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ fixed_t dist;
+
+ angle = player->mo->angle;
+ r = P_Random();
+ angle = (angle + ((r - P_Random()) << 18)) >> ANGLETOFINESHIFT;
+
+ if(angle < 7618 && angle >= 6718)
+ angle = 7618;
+
+ else if(angle < 5570 && angle >= 4670)
+ angle = 5570;
+
+ else if(angle < 3522 && angle >= 2622)
+ angle = 3522;
+
+ else if(angle < 1474 && angle >= 574)
+ angle = 1474;
+
+ mo = player->mo;
+ dist = mobjinfo[MT_BEACON].radius + mo->info->radius + (4*FRACUNIT);
+
+ x = mo->x + FixedMul(finecosine[angle], dist);
+ y = mo->y + FixedMul(finesine[angle], dist);
+ z = mo->z + (10*FRACUNIT);
+ beacon = P_SpawnMobj(x, y, z, MT_BEACON);
+
+ if(P_CheckPosition(beacon, x, y))
+ {
+ beacon->target = mo;
+ beacon->miscdata = mo->miscdata;
+ beacon->angle = (angle << ANGLETOFINESHIFT);
+ beacon->momx = FixedMul(finecosine[angle], (5*FRACUNIT));
+ beacon->momy = FixedMul(finesine[angle], (5*FRACUNIT));
+ beacon->momz = FRACUNIT;
+ P_SetMobjState(beacon, beacon->info->seestate);
+ return true;
+ }
+ else
+ P_RemoveMobj(beacon);
+
+ return false;
+}
+
+//
+// P_UseInventoryItem
+// villsa [STRIFE] new function
+//
+boolean P_UseInventoryItem(player_t* player, int item)
+{
+ int i;
+ char* name;
+
+ if(player->cheats & CF_ONFIRE)
+ return false;
+
+ for(i = 0; i < player->numinventory; i++)
+ {
+ if(item != player->inventory[i].sprite)
+ continue;
+
+ if(!P_ItemBehavior(player, item))
+ return false;
+
+ name = P_RemoveInventoryItem(player, i, 1);
+ if(name == NULL)
+ name = "Item";
+
+ sprintf(useinventorymsg, "You used the %s.", name);
+ player->message = useinventorymsg;
+
+ if(player == &players[consoleplayer])
+ S_StartSound(NULL, sfx_itemup);
+
+ return true;
+ }
+
+ return false;
+}
+
+//
+// P_ItemBehavior
+// villsa [STRIFE] new function
+//
+boolean P_ItemBehavior(player_t* player, int item)
+{
+ switch(item)
+ {
+ case SPR_ARM1: // 136
+ return P_GiveArmor(player, 2);
+
+ case SPR_ARM2: // 137
+ return P_GiveArmor(player, 1);
+
+ case SPR_SHD1: // 186
+ return P_GivePower(player, pw_invisibility);
+
+ case SPR_MASK: // 187
+ return P_GivePower(player, pw_ironfeet);
+
+ case SPR_PMUP: // 191
+ if(!player->powers[pw_allmap])
+ {
+ player->message = "The scanner won't work without a map!";
+ return false;
+ }
+ player->powers[pw_allmap] = PMUPTICS;
+ return true; // haleyjd 20110228: repaired
+
+ case SPR_STMP: // 180
+ return P_GiveBody(player, 10);
+
+ case SPR_MDKT: // 181
+ return P_GiveBody(player, 25);
+
+ case SPR_FULL: // 130
+ return P_GiveBody(player, 200);
+
+ case SPR_BEAC: // 135
+ return P_SpawnTeleportBeacon(player);
+
+ case SPR_TARG: // 108
+ return P_GivePower(player, pw_targeter);
+ }
+
+ return false;
+}
diff --git a/src/strife/r_bsp.c b/src/strife/r_bsp.c
new file mode 100644
index 00000000..ee05156d
--- /dev/null
+++ b/src/strife/r_bsp.c
@@ -0,0 +1,581 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// BSP traversal, handling of LineSegs for rendering.
+//
+//-----------------------------------------------------------------------------
+
+
+
+
+#include "doomdef.h"
+
+#include "m_bbox.h"
+
+#include "i_system.h"
+
+#include "r_main.h"
+#include "r_plane.h"
+#include "r_things.h"
+
+// State.
+#include "doomstat.h"
+#include "r_state.h"
+
+//#include "r_local.h"
+
+
+
+seg_t* curline;
+side_t* sidedef;
+line_t* linedef;
+sector_t* frontsector;
+sector_t* backsector;
+
+drawseg_t drawsegs[MAXDRAWSEGS];
+drawseg_t* ds_p;
+
+
+void
+R_StoreWallRange
+( int start,
+ int stop );
+
+
+
+
+//
+// R_ClearDrawSegs
+//
+void R_ClearDrawSegs (void)
+{
+ ds_p = drawsegs;
+}
+
+
+
+//
+// ClipWallSegment
+// Clips the given range of columns
+// and includes it in the new clip list.
+//
+typedef struct
+{
+ int first;
+ int last;
+
+} cliprange_t;
+
+
+#define MAXSEGS 32
+
+// newend is one past the last valid seg
+cliprange_t* newend;
+cliprange_t solidsegs[MAXSEGS];
+
+
+
+
+//
+// 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;
+ angle2 = 0 - clipangle;
+ }
+
+ // 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.
+//
+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}
+};
+
+
+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;
+
+ angle2 = 0 - clipangle;
+ }
+
+
+ // 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 ("R_Subsector: ss %i with numss = %i",
+ num,
+ numsubsectors);
+#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 = NULL;
+
+ if (frontsector->ceilingheight > viewz
+ || frontsector->ceilingpic == skyflatnum)
+ {
+ ceilingplane = R_FindPlane (frontsector->ceilingheight,
+ frontsector->ceilingpic,
+ frontsector->lightlevel);
+ }
+ else
+ ceilingplane = NULL;
+
+ 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]);
+}
+
+
diff --git a/src/strife/r_bsp.h b/src/strife/r_bsp.h
new file mode 100644
index 00000000..284f9cf6
--- /dev/null
+++ b/src/strife/r_bsp.h
@@ -0,0 +1,69 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Refresh module, BSP traversal and handling.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __R_BSP__
+#define __R_BSP__
+
+
+
+extern seg_t* curline;
+extern side_t* sidedef;
+extern line_t* linedef;
+extern sector_t* frontsector;
+extern sector_t* backsector;
+
+extern int rw_x;
+extern int rw_stopx;
+
+extern boolean segtextured;
+
+// false if the back side is the same plane
+extern boolean markfloor;
+extern boolean markceiling;
+
+extern boolean skymap;
+
+extern drawseg_t drawsegs[MAXDRAWSEGS];
+extern drawseg_t* ds_p;
+
+extern lighttable_t** hscalelight;
+extern lighttable_t** vscalelight;
+extern lighttable_t** dscalelight;
+
+
+typedef void (*drawfunc_t) (int start, int stop);
+
+
+// BSP?
+void R_ClearClipSegs (void);
+void R_ClearDrawSegs (void);
+
+
+void R_RenderBSPNode (int bspnum);
+
+
+#endif
diff --git a/src/strife/r_data.c b/src/strife/r_data.c
new file mode 100644
index 00000000..b8fa5686
--- /dev/null
+++ b/src/strife/r_data.c
@@ -0,0 +1,1026 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Preparation of data for rendering,
+// generation of lookups, caching, retrieval by name.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+
+#include "d_main.h"
+#include "deh_main.h"
+#include "i_swap.h"
+#include "i_system.h"
+#include "z_zone.h"
+#include "w_wad.h"
+#include "doomdef.h"
+#include "r_local.h"
+#include "p_local.h"
+#include "doomstat.h"
+#include "r_sky.h"
+#include "r_data.h"
+#include "sounds.h" // villsa [STRIFE]
+
+//
+// Graphics.
+// DOOM graphics for walls and sprites
+// is stored in vertical runs of opaque pixels (posts).
+// A column is composed of zero or more posts,
+// a patch or sprite is composed of zero or more columns.
+//
+
+
+
+//
+// Texture definition.
+// Each texture is composed of one or more patches,
+// with patches being lumps stored in the WAD.
+// The lumps are referenced by number, and patched
+// into the rectangular texture space using origin
+// and possibly other attributes.
+//
+typedef struct
+{
+ short originx;
+ short originy;
+ short patch;
+ //short stepdir; // villsa [STRIFE] removed
+ //short colormap; // villsa [STRIFE] removed
+} PACKEDATTR mappatch_t;
+
+
+//
+// Texture definition.
+// A DOOM wall texture is a list of patches
+// which are to be combined in a predefined order.
+//
+typedef struct
+{
+ char name[8];
+ int masked;
+ short width;
+ short height;
+ //int obsolete; // villsa [STRIFE] removed
+ short patchcount;
+ mappatch_t patches[1];
+} PACKEDATTR maptexture_t;
+
+
+// A single patch from a texture definition,
+// basically a rectangular area within
+// the texture rectangle.
+typedef struct
+{
+ // Block origin (allways UL),
+ // which has allready accounted
+ // for the internal origin of the patch.
+ short originx;
+ short originy;
+ int patch;
+} texpatch_t;
+
+
+// A maptexturedef_t describes a rectangular texture,
+// which is composed of one or more mappatch_t structures
+// that arrange graphic patches.
+
+typedef struct texture_s texture_t;
+
+struct texture_s
+{
+ // Keep name for switch changing, etc.
+ char name[8];
+ short width;
+ short height;
+
+ // Index in textures list
+
+ int index;
+
+ // Next in hash table chain
+
+ texture_t *next;
+
+ // All the patches[patchcount]
+ // are drawn back to front into the cached texture.
+ short patchcount;
+ texpatch_t patches[1];
+};
+
+
+
+int firstflat;
+int lastflat;
+int numflats;
+
+int firstpatch;
+int lastpatch;
+int numpatches;
+
+int firstspritelump;
+int lastspritelump;
+int numspritelumps;
+
+int numtextures;
+texture_t** textures;
+texture_t** textures_hashtable;
+
+
+int* texturewidthmask;
+// needed for texture pegging
+fixed_t* textureheight;
+int* texturecompositesize;
+short** texturecolumnlump;
+unsigned short** texturecolumnofs;
+byte** texturecomposite;
+
+// for global animation
+int* flattranslation;
+int* texturetranslation;
+
+// needed for pre rendering
+fixed_t* spritewidth;
+fixed_t* spriteoffset;
+fixed_t* spritetopoffset;
+
+lighttable_t *colormaps;
+
+
+//
+// MAPTEXTURE_T CACHING
+// When a texture is first needed,
+// it counts the number of composite columns
+// required in the texture and allocates space
+// for a column directory and any new columns.
+// The directory will simply point inside other patches
+// if there is only one patch in a given column,
+// but any columns with multiple patches
+// will have new column_ts generated.
+//
+
+
+
+//
+// R_DrawColumnInCache
+// Clip and draw a column
+// from a patch into a cached post.
+//
+void
+R_DrawColumnInCache
+( column_t* patch,
+ byte* cache,
+ int originy,
+ int cacheheight )
+{
+ int count;
+ int position;
+ byte* source;
+
+ while (patch->topdelta != 0xff)
+ {
+ source = (byte *)patch + 3;
+ count = patch->length;
+ position = originy + patch->topdelta;
+
+ if (position < 0)
+ {
+ count += position;
+ position = 0;
+ }
+
+ if (position + count > cacheheight)
+ count = cacheheight - position;
+
+ if (count > 0)
+ memcpy (cache + position, source, count);
+
+ patch = (column_t *)( (byte *)patch + patch->length + 4);
+ }
+}
+
+
+
+//
+// R_GenerateComposite
+// Using the texture definition,
+// the composite texture is created from the patches,
+// and each column is cached.
+//
+void R_GenerateComposite (int texnum)
+{
+ byte* block;
+ texture_t* texture;
+ texpatch_t* patch;
+ patch_t* realpatch;
+ int x;
+ int x1;
+ int x2;
+ int i;
+ column_t* patchcol;
+ short* collump;
+ unsigned short* colofs;
+
+ texture = textures[texnum];
+
+ block = Z_Malloc (texturecompositesize[texnum],
+ PU_STATIC,
+ &texturecomposite[texnum]);
+
+ collump = texturecolumnlump[texnum];
+ colofs = texturecolumnofs[texnum];
+
+ // Composite the columns together.
+ patch = texture->patches;
+
+ for (i=0 , patch = texture->patches;
+ i<texture->patchcount;
+ i++, patch++)
+ {
+ realpatch = W_CacheLumpNum (patch->patch, PU_CACHE);
+ x1 = patch->originx;
+ x2 = x1 + SHORT(realpatch->width);
+
+ if (x1<0)
+ x = 0;
+ else
+ x = x1;
+
+ if (x2 > texture->width)
+ x2 = texture->width;
+
+ for ( ; x<x2 ; x++)
+ {
+ // Column does not have multiple patches?
+ if (collump[x] >= 0)
+ continue;
+
+ patchcol = (column_t *)((byte *)realpatch
+ + LONG(realpatch->columnofs[x-x1]));
+ R_DrawColumnInCache (patchcol,
+ block + colofs[x],
+ patch->originy,
+ texture->height);
+ }
+
+ }
+
+ // Now that the texture has been built in column cache,
+ // it is purgable from zone memory.
+ Z_ChangeTag (block, PU_CACHE);
+}
+
+
+
+//
+// R_GenerateLookup
+//
+void R_GenerateLookup (int texnum)
+{
+ texture_t* texture;
+ byte* patchcount; // patchcount[texture->width]
+ texpatch_t* patch;
+ patch_t* realpatch;
+ int x;
+ int x1;
+ int x2;
+ int i;
+ short* collump;
+ unsigned short* colofs;
+
+ texture = textures[texnum];
+
+ // Composited texture not created yet.
+ texturecomposite[texnum] = 0;
+
+ texturecompositesize[texnum] = 0;
+ collump = texturecolumnlump[texnum];
+ colofs = texturecolumnofs[texnum];
+
+ // Now count the number of columns
+ // that are covered by more than one patch.
+ // Fill in the lump / offset, so columns
+ // with only a single patch are all done.
+ patchcount = (byte *) Z_Malloc(texture->width, PU_STATIC, &patchcount);
+ memset (patchcount, 0, texture->width);
+ patch = texture->patches;
+
+ for (i=0 , patch = texture->patches;
+ i<texture->patchcount;
+ i++, patch++)
+ {
+ realpatch = W_CacheLumpNum (patch->patch, PU_CACHE);
+ x1 = patch->originx;
+ x2 = x1 + SHORT(realpatch->width);
+
+ if (x1 < 0)
+ x = 0;
+ else
+ x = x1;
+
+ if (x2 > texture->width)
+ x2 = texture->width;
+ for ( ; x<x2 ; x++)
+ {
+ patchcount[x]++;
+ collump[x] = patch->patch;
+ colofs[x] = LONG(realpatch->columnofs[x-x1])+3;
+ }
+ }
+
+ for (x=0 ; x<texture->width ; x++)
+ {
+ if (!patchcount[x])
+ {
+ printf ("R_GenerateLookup: column without a patch (%s)\n",
+ texture->name);
+ return;
+ }
+ // I_Error ("R_GenerateLookup: column without a patch");
+
+ if (patchcount[x] > 1)
+ {
+ // Use the cached block.
+ collump[x] = -1;
+ colofs[x] = texturecompositesize[texnum];
+
+ if (texturecompositesize[texnum] > 0x10000-texture->height)
+ {
+ I_Error ("R_GenerateLookup: texture %i is >64k",
+ texnum);
+ }
+
+ texturecompositesize[texnum] += texture->height;
+ }
+ }
+
+ Z_Free(patchcount);
+}
+
+
+
+
+//
+// R_GetColumn
+//
+byte*
+R_GetColumn
+( int tex,
+ int col )
+{
+ int lump;
+ int ofs;
+
+ col &= texturewidthmask[tex];
+ lump = texturecolumnlump[tex][col];
+ ofs = texturecolumnofs[tex][col];
+
+ if (lump > 0)
+ return (byte *)W_CacheLumpNum(lump,PU_CACHE)+ofs;
+
+ if (!texturecomposite[tex])
+ R_GenerateComposite (tex);
+
+ return texturecomposite[tex] + ofs;
+}
+
+
+static void GenerateTextureHashTable(void)
+{
+ texture_t **rover;
+ int i;
+ int key;
+
+ textures_hashtable
+ = Z_Malloc(sizeof(texture_t *) * numtextures, PU_STATIC, 0);
+
+ memset(textures_hashtable, 0, sizeof(texture_t *) * numtextures);
+
+ // Add all textures to hash table
+
+ for (i=0; i<numtextures; ++i)
+ {
+ // Store index
+
+ textures[i]->index = i;
+
+ // Vanilla Doom does a linear search of the texures array
+ // and stops at the first entry it finds. If there are two
+ // entries with the same name, the first one in the array
+ // wins. The new entry must therefore be added at the end
+ // of the hash chain, so that earlier entries win.
+
+ key = W_LumpNameHash(textures[i]->name) % numtextures;
+
+ rover = &textures_hashtable[key];
+
+ while (*rover != NULL)
+ {
+ rover = &(*rover)->next;
+ }
+
+ // Hook into hash table
+
+ textures[i]->next = NULL;
+ *rover = textures[i];
+ }
+}
+
+
+//
+// R_InitTextures
+// Initializes the texture list
+// with the textures from the world map.
+//
+void R_InitTextures (void)
+{
+ maptexture_t* mtexture;
+ texture_t* texture;
+ mappatch_t* mpatch;
+ texpatch_t* patch;
+
+ int i;
+ int j;
+
+ int* maptex;
+ int* maptex2;
+ int* maptex1;
+
+ char name[9];
+ char* names;
+ char* name_p;
+
+ int* patchlookup;
+
+ int totalwidth;
+ int nummappatches;
+ int offset;
+ int maxoff;
+ int maxoff2;
+ int numtextures1;
+ int numtextures2;
+
+ int* directory;
+
+ int temp1;
+ int temp2;
+ int temp3;
+
+
+ // Load the patch names from pnames.lmp.
+ name[8] = 0;
+ names = W_CacheLumpName (DEH_String("PNAMES"), PU_STATIC);
+ nummappatches = LONG ( *((int *)names) );
+ name_p = names+4;
+ patchlookup = Z_Malloc(nummappatches*sizeof(*patchlookup), PU_STATIC, NULL);
+
+ for (i=0 ; i<nummappatches ; i++)
+ {
+ strncpy (name,name_p+i*8, 8);
+ patchlookup[i] = W_CheckNumForName (name);
+ }
+ W_ReleaseLumpName(DEH_String("PNAMES"));
+
+ // Load the map texture definitions from textures.lmp.
+ // The data is contained in one or two lumps,
+ // TEXTURE1 for shareware, plus TEXTURE2 for commercial.
+ maptex = maptex1 = W_CacheLumpName (DEH_String("TEXTURE1"), PU_STATIC);
+ numtextures1 = LONG(*maptex);
+ maxoff = W_LumpLength (W_GetNumForName (DEH_String("TEXTURE1")));
+ directory = maptex+1;
+
+ if (W_CheckNumForName (DEH_String("TEXTURE2")) != -1)
+ {
+ maptex2 = W_CacheLumpName (DEH_String("TEXTURE2"), PU_STATIC);
+ numtextures2 = LONG(*maptex2);
+ maxoff2 = W_LumpLength (W_GetNumForName (DEH_String("TEXTURE2")));
+ }
+ else
+ {
+ maptex2 = NULL;
+ numtextures2 = 0;
+ maxoff2 = 0;
+ }
+ numtextures = numtextures1 + numtextures2;
+
+ textures = Z_Malloc (numtextures * sizeof(*textures), PU_STATIC, 0);
+ texturecolumnlump = Z_Malloc (numtextures * sizeof(*texturecolumnlump), PU_STATIC, 0);
+ texturecolumnofs = Z_Malloc (numtextures * sizeof(*texturecolumnofs), PU_STATIC, 0);
+ texturecomposite = Z_Malloc (numtextures * sizeof(*texturecomposite), PU_STATIC, 0);
+ texturecompositesize = Z_Malloc (numtextures * sizeof(*texturecompositesize), PU_STATIC, 0);
+ texturewidthmask = Z_Malloc (numtextures * sizeof(*texturewidthmask), PU_STATIC, 0);
+ textureheight = Z_Malloc (numtextures * sizeof(*textureheight), PU_STATIC, 0);
+
+ totalwidth = 0;
+
+ // Really complex printing shit...
+ temp1 = W_GetNumForName (DEH_String("S_START")); // P_???????
+ temp2 = W_GetNumForName (DEH_String("S_END")) - 1;
+ temp3 = ((temp2-temp1+63)/64) + ((numtextures+63)/64);
+
+ // If stdout is a real console, use the classic vanilla "filling
+ // up the box" effect, which uses backspace to "step back" inside
+ // the box. If stdout is a file, don't draw the box.
+
+ // haleyjd 20110206 [STRIFE]: box is in devparm only
+ if (devparm && I_ConsoleStdout())
+ {
+ printf("[");
+ for (i = 0; i < temp3 + 9; i++)
+ printf(" ");
+ printf("]");
+ for (i = 0; i < temp3 + 10; i++)
+ printf("\b");
+ }
+
+ for (i=0 ; i<numtextures ; i++, directory++)
+ {
+ if (!(i&63))
+ {
+ // [STRIFE]: tick intro if not in devparm
+ if(devparm)
+ printf (".");
+ else
+ D_IntroTick();
+ }
+
+ if (i == numtextures1)
+ {
+ // Start looking in second texture file.
+ maptex = maptex2;
+ maxoff = maxoff2;
+ directory = maptex+1;
+ }
+
+ offset = LONG(*directory);
+
+ if (offset > maxoff)
+ I_Error ("R_InitTextures: bad texture directory");
+
+ mtexture = (maptexture_t *) ( (byte *)maptex + offset);
+
+ texture = textures[i] =
+ Z_Malloc (sizeof(texture_t)
+ + sizeof(texpatch_t)*(SHORT(mtexture->patchcount)-1),
+ PU_STATIC, 0);
+
+ texture->width = SHORT(mtexture->width);
+ texture->height = SHORT(mtexture->height);
+ texture->patchcount = SHORT(mtexture->patchcount);
+
+ memcpy (texture->name, mtexture->name, sizeof(texture->name));
+ mpatch = &mtexture->patches[0];
+ patch = &texture->patches[0];
+
+ for (j=0 ; j<texture->patchcount ; j++, mpatch++, patch++)
+ {
+ patch->originx = SHORT(mpatch->originx);
+ patch->originy = SHORT(mpatch->originy);
+ patch->patch = patchlookup[SHORT(mpatch->patch)];
+ if (patch->patch == -1)
+ {
+ I_Error ("R_InitTextures: Missing patch in texture %s",
+ texture->name);
+ }
+ }
+ texturecolumnlump[i] = Z_Malloc (texture->width*sizeof(**texturecolumnlump), PU_STATIC,0);
+ texturecolumnofs[i] = Z_Malloc (texture->width*sizeof(**texturecolumnofs), PU_STATIC,0);
+
+ j = 1;
+ while (j*2 <= texture->width)
+ j<<=1;
+
+ texturewidthmask[i] = j-1;
+ textureheight[i] = texture->height<<FRACBITS;
+
+ totalwidth += texture->width;
+ }
+
+ Z_Free(patchlookup);
+
+ W_ReleaseLumpName(DEH_String("TEXTURE1"));
+ if (maptex2)
+ W_ReleaseLumpName(DEH_String("TEXTURE2"));
+
+ // Precalculate whatever possible.
+
+ for (i=0 ; i<numtextures ; i++)
+ {
+ // [STRIFE]: tick intro
+ if(!(i & 63))
+ D_IntroTick();
+ R_GenerateLookup (i);
+ }
+
+ // Create translation table for global animation.
+ texturetranslation = Z_Malloc ((numtextures+1)*sizeof(*texturetranslation), PU_STATIC, 0);
+
+ for (i=0 ; i<numtextures ; i++)
+ texturetranslation[i] = i;
+
+ GenerateTextureHashTable();
+}
+
+
+
+//
+// R_InitFlats
+//
+void R_InitFlats (void)
+{
+ int i;
+
+ firstflat = W_GetNumForName (DEH_String("F_START")) + 1;
+ lastflat = W_GetNumForName (DEH_String("F_END")) - 1;
+ numflats = lastflat - firstflat + 1;
+
+ // Create translation table for global animation.
+ flattranslation = Z_Malloc ((numflats+1)*sizeof(*flattranslation), PU_STATIC, 0);
+
+ for (i=0 ; i<numflats ; i++)
+ flattranslation[i] = i;
+}
+
+
+//
+// R_InitSpriteLumps
+// Finds the width and hoffset of all sprites in the wad,
+// so the sprite does not need to be cached completely
+// just for having the header info ready during rendering.
+//
+void R_InitSpriteLumps (void)
+{
+ int i;
+ patch_t *patch;
+
+ firstspritelump = W_GetNumForName (DEH_String("S_START")) + 1;
+ lastspritelump = W_GetNumForName (DEH_String("S_END")) - 1;
+
+ numspritelumps = lastspritelump - firstspritelump + 1;
+ spritewidth = Z_Malloc (numspritelumps*sizeof(*spritewidth), PU_STATIC, 0);
+ spriteoffset = Z_Malloc (numspritelumps*sizeof(*spriteoffset), PU_STATIC, 0);
+ spritetopoffset = Z_Malloc (numspritelumps*sizeof(*spritetopoffset), PU_STATIC, 0);
+
+ for (i=0 ; i< numspritelumps ; i++)
+ {
+ if(!(i&63))
+ {
+ // [STRIFE] tick intro if not in devparm
+ if(devparm)
+ printf (".");
+ else
+ D_IntroTick();
+ }
+
+ patch = W_CacheLumpNum (firstspritelump+i, PU_CACHE);
+ spritewidth[i] = SHORT(patch->width)<<FRACBITS;
+ spriteoffset[i] = SHORT(patch->leftoffset)<<FRACBITS;
+ spritetopoffset[i] = SHORT(patch->topoffset)<<FRACBITS;
+ }
+}
+
+
+
+//
+// R_InitColormaps
+//
+void R_InitColormaps (void)
+{
+ int lump;
+
+ // Load in the light tables, 256 byte align tables.
+ lump = W_GetNumForName(DEH_String("COLORMAP"));
+ colormaps = W_CacheLumpNum(lump, PU_STATIC);
+}
+
+
+
+//
+// R_InitData
+// Locates all the lumps
+// that will be used by all views
+// Must be called after W_Init.
+//
+void R_InitData (void)
+{
+ R_InitTextures ();
+ if(devparm)
+ printf (".");
+ else
+ D_IntroTick(); // [STRIFE] tick intro
+
+ R_InitFlats ();
+ if(devparm)
+ printf (".");
+ else
+ D_IntroTick();
+
+ R_InitSpriteLumps ();
+ if(devparm)
+ printf (".");
+ else
+ D_IntroTick();
+
+ R_InitColormaps ();
+}
+
+
+
+//
+// R_FlatNumForName
+// Retrieval, get a flat number for a flat name.
+//
+int R_FlatNumForName (char* name)
+{
+ int i;
+ char namet[9];
+
+ i = W_CheckNumForName (name);
+
+ if (i == -1)
+ {
+ namet[8] = 0;
+ memcpy (namet, name,8);
+ I_Error ("R_FlatNumForName: %s not found",namet);
+ }
+ return i - firstflat;
+}
+
+
+
+
+//
+// R_CheckTextureNumForName
+// Check whether texture is available.
+// Filter out NoTexture indicator.
+//
+int R_CheckTextureNumForName (char *name)
+{
+ texture_t *texture;
+ int key;
+
+ // "NoTexture" marker.
+ if (name[0] == '-')
+ return 0;
+
+ key = W_LumpNameHash(name) % numtextures;
+
+ texture=textures_hashtable[key];
+
+ while (texture != NULL)
+ {
+ if (!strncasecmp (texture->name, name, 8) )
+ return texture->index;
+
+ texture = texture->next;
+ }
+
+ return -1;
+}
+
+
+
+//
+// R_TextureNumForName
+// Calls R_CheckTextureNumForName,
+// aborts with error message.
+//
+int R_TextureNumForName (char* name)
+{
+ int i;
+
+ i = R_CheckTextureNumForName (name);
+
+ if (i==-1)
+ {
+ I_Error ("R_TextureNumForName: %s not found",
+ name);
+ }
+ return i;
+}
+
+//
+// R_SoundNumForDoor
+//
+// villsa [STRIFE] - new function
+// Set sounds associated with door though why
+// on earth is this function placed here?
+//
+void R_SoundNumForDoor(vldoor_t* door)
+{
+ int i;
+ sector_t *sector;
+ line_t *line;
+ texture_t *texture;
+ char name[8];
+ char c1;
+ char c2;
+
+ // set default sounds
+ door->opensound = sfx_drsmto;
+ door->closesound = sfx_drsmtc;
+
+ for(sector = door->sector, i = 0; i < sector->linecount; i++)
+ {
+ line = sector->lines[i];
+
+ if(!(line->flags & ML_TWOSIDED))
+ continue;
+
+ texture = textures[sides[line->sidenum[0]].toptexture];
+ memcpy(name, texture->name, 8);
+
+ if(strncmp(name, "DOR", 3))
+ continue;
+
+ c1 = name[3];
+ c2 = name[4];
+
+ // S type
+ if(c1 == 'S')
+ {
+ door->opensound = sfx_drston;
+ door->closesound = sfx_drston;
+ return;
+ }
+
+ // M type
+ if(c1 == 'M')
+ {
+ // L subtype
+ if(c2 == 'L')
+ {
+ door->opensound = sfx_drlmto;
+ door->closesound = sfx_drlmtc;
+ }
+ // S subtype
+ else if(c2 == 'S')
+ {
+ door->opensound = sfx_drsmto;
+ door->closesound = sfx_drsmtc;
+ }
+ return;
+ }
+ // W type
+ else if(c1 == 'W')
+ {
+ // L subtype
+ if(c2 == 'L')
+ {
+ door->opensound = sfx_drlwud;
+ door->closesound = sfx_drlwud;
+ }
+ // S subtype
+ else if(c2 == 'S')
+ {
+ door->opensound = sfx_drswud;
+ door->closesound = sfx_drswud;
+ }
+ return;
+ }
+ }
+}
+
+
+
+
+//
+// R_PrecacheLevel
+// Preloads all relevant graphics for the level.
+//
+int flatmemory;
+int texturememory;
+int spritememory;
+
+void R_PrecacheLevel (void)
+{
+ char* flatpresent;
+ char* texturepresent;
+ char* spritepresent;
+
+ int i;
+ int j;
+ int k;
+ int lump;
+
+ texture_t* texture;
+ thinker_t* th;
+ spriteframe_t* sf;
+
+ if (demoplayback)
+ return;
+
+ // Precache flats.
+ flatpresent = Z_Malloc(numflats, PU_STATIC, NULL);
+ memset (flatpresent,0,numflats);
+
+ for (i=0 ; i<numsectors ; i++)
+ {
+ flatpresent[sectors[i].floorpic] = 1;
+ flatpresent[sectors[i].ceilingpic] = 1;
+ }
+
+ flatmemory = 0;
+
+ for (i=0 ; i<numflats ; i++)
+ {
+ if (flatpresent[i])
+ {
+ lump = firstflat + i;
+ flatmemory += lumpinfo[lump].size;
+ W_CacheLumpNum(lump, PU_CACHE);
+ }
+ }
+
+ Z_Free(flatpresent);
+
+ // Precache textures.
+ texturepresent = Z_Malloc(numtextures, PU_STATIC, NULL);
+ memset (texturepresent,0, numtextures);
+
+ for (i=0 ; i<numsides ; i++)
+ {
+ texturepresent[sides[i].toptexture] = 1;
+ texturepresent[sides[i].midtexture] = 1;
+ texturepresent[sides[i].bottomtexture] = 1;
+ }
+
+ // Sky texture is always present.
+ // Note that F_SKY1 is the name used to
+ // indicate a sky floor/ceiling as a flat,
+ // while the sky texture is stored like
+ // a wall texture, with an episode dependend
+ // name.
+ texturepresent[skytexture] = 1;
+
+ texturememory = 0;
+ for (i=0 ; i<numtextures ; i++)
+ {
+ if (!texturepresent[i])
+ continue;
+
+ texture = textures[i];
+
+ for (j=0 ; j<texture->patchcount ; j++)
+ {
+ lump = texture->patches[j].patch;
+ texturememory += lumpinfo[lump].size;
+ W_CacheLumpNum(lump , PU_CACHE);
+ }
+ }
+
+ Z_Free(texturepresent);
+
+ // Precache sprites.
+ spritepresent = Z_Malloc(numsprites, PU_STATIC, NULL);
+ memset (spritepresent,0, numsprites);
+
+ for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
+ {
+ if (th->function.acp1 == (actionf_p1)P_MobjThinker)
+ spritepresent[((mobj_t *)th)->sprite] = 1;
+ }
+
+ spritememory = 0;
+ for (i=0 ; i<numsprites ; i++)
+ {
+ if (!spritepresent[i])
+ continue;
+
+ for (j=0 ; j<sprites[i].numframes ; j++)
+ {
+ sf = &sprites[i].spriteframes[j];
+ for (k=0 ; k<8 ; k++)
+ {
+ lump = firstspritelump + sf->lump[k];
+ spritememory += lumpinfo[lump].size;
+ W_CacheLumpNum(lump , PU_CACHE);
+ }
+ }
+ }
+
+ Z_Free(spritepresent);
+}
+
+
+
+
diff --git a/src/strife/r_data.h b/src/strife/r_data.h
new file mode 100644
index 00000000..c8d08179
--- /dev/null
+++ b/src/strife/r_data.h
@@ -0,0 +1,61 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Refresh module, data I/O, caching, retrieval of graphics
+// by name.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __R_DATA__
+#define __R_DATA__
+
+#include "r_defs.h"
+#include "r_state.h"
+#include "p_spec.h" // villsa [STRIFE]
+
+
+// Retrieve column data for span blitting.
+byte*
+R_GetColumn
+( int tex,
+ int col );
+
+
+// I/O, setting up the stuff.
+void R_InitData (void);
+void R_PrecacheLevel (void);
+
+
+// Retrieval.
+// Floor/ceiling opaque texture tiles,
+// lookup by name. For animation?
+int R_FlatNumForName (char* name);
+
+
+// Called by P_Ticker for switches and animations,
+// returns the texture number for the texture name.
+int R_TextureNumForName (char *name);
+int R_CheckTextureNumForName (char *name);
+void R_SoundNumForDoor(vldoor_t* door); // villsa [STRIFE]
+
+#endif
diff --git a/src/strife/r_defs.h b/src/strife/r_defs.h
new file mode 100644
index 00000000..bbd4b211
--- /dev/null
+++ b/src/strife/r_defs.h
@@ -0,0 +1,456 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Refresh/rendering module, shared data struct definitions.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __R_DEFS__
+#define __R_DEFS__
+
+
+// Screenwidth.
+#include "doomdef.h"
+
+// Some more or less basic data types
+// we depend on.
+#include "m_fixed.h"
+
+// We rely on the thinker data struct
+// to handle sound origins in sectors.
+#include "d_think.h"
+// SECTORS do store MObjs anyway.
+#include "p_mobj.h"
+
+#include "i_video.h"
+
+#include "v_patch.h"
+
+
+
+
+// Silhouette, needed for clipping Segs (mainly)
+// and sprites representing things.
+#define SIL_NONE 0
+#define SIL_BOTTOM 1
+#define SIL_TOP 2
+#define SIL_BOTH 3
+
+#define MAXDRAWSEGS 256
+
+
+
+
+
+//
+// INTERNAL MAP TYPES
+// used by play and refresh
+//
+
+//
+// Your plain vanilla vertex.
+// Note: transformed values not buffered locally,
+// like some DOOM-alikes ("wt", "WebView") did.
+//
+typedef struct
+{
+ fixed_t x;
+ fixed_t y;
+
+} vertex_t;
+
+
+// Forward of LineDefs, for Sectors.
+struct line_s;
+
+// Each sector has a degenmobj_t in its center
+// for sound origin purposes.
+// I suppose this does not handle sound from
+// moving objects (doppler), because
+// position is prolly just buffered, not
+// updated.
+typedef struct
+{
+ thinker_t thinker; // not used for anything
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+
+} degenmobj_t;
+
+//
+// The SECTORS record, at runtime.
+// Stores things/mobjs.
+//
+typedef struct
+{
+ fixed_t floorheight;
+ fixed_t ceilingheight;
+ short floorpic;
+ short ceilingpic;
+ short lightlevel;
+ short special;
+ short tag;
+
+ // 0 = untraversed, 1,2 = sndlines -1
+ int soundtraversed;
+
+ // thing that made a sound (or null)
+ mobj_t* soundtarget;
+
+ // mapblock bounding box for height changes
+ int blockbox[4];
+
+ // origin for any sounds played by the sector
+ degenmobj_t soundorg;
+
+ // if == validcount, already checked
+ int validcount;
+
+ // list of mobjs in sector
+ mobj_t* thinglist;
+
+ // thinker_t for reversable actions
+ void* specialdata;
+
+ int linecount;
+ struct line_s** lines; // [linecount] size
+
+} sector_t;
+
+
+
+
+//
+// The SideDef.
+//
+
+typedef struct
+{
+ // add this to the calculated texture column
+ fixed_t textureoffset;
+
+ // add this to the calculated texture top
+ fixed_t rowoffset;
+
+ // Texture indices.
+ // We do not maintain names here.
+ short toptexture;
+ short bottomtexture;
+ short midtexture;
+
+ // Sector the SideDef is facing.
+ sector_t* sector;
+
+} side_t;
+
+
+
+//
+// Move clipping aid for LineDefs.
+//
+typedef enum
+{
+ ST_HORIZONTAL,
+ ST_VERTICAL,
+ ST_POSITIVE,
+ ST_NEGATIVE
+
+} slopetype_t;
+
+
+
+typedef struct line_s
+{
+ // Vertices, from v1 to v2.
+ vertex_t* v1;
+ vertex_t* v2;
+
+ // Precalculated v2 - v1 for side checking.
+ fixed_t dx;
+ fixed_t dy;
+
+ // Animation related.
+ short flags;
+ short special;
+ short tag;
+
+ // Visual appearance: SideDefs.
+ // sidenum[1] will be -1 if one sided
+ short sidenum[2];
+
+ // Neat. Another bounding box, for the extent
+ // of the LineDef.
+ fixed_t bbox[4];
+
+ // To aid move clipping.
+ slopetype_t slopetype;
+
+ // Front and back sector.
+ // Note: redundant? Can be retrieved from SideDefs.
+ sector_t* frontsector;
+ sector_t* backsector;
+
+ // if == validcount, already checked
+ int validcount;
+
+ // thinker_t for reversable actions
+ void* specialdata;
+} line_t;
+
+
+
+
+//
+// A SubSector.
+// References a Sector.
+// Basically, this is a list of LineSegs,
+// indicating the visible walls that define
+// (all or some) sides of a convex BSP leaf.
+//
+typedef struct subsector_s
+{
+ sector_t* sector;
+ short numlines;
+ short firstline;
+
+} subsector_t;
+
+
+
+//
+// The LineSeg.
+//
+typedef struct
+{
+ vertex_t* v1;
+ vertex_t* v2;
+
+ fixed_t offset;
+
+ angle_t angle;
+
+ side_t* sidedef;
+ line_t* linedef;
+
+ // Sector references.
+ // Could be retrieved from linedef, too.
+ // backsector is NULL for one sided lines
+ sector_t* frontsector;
+ sector_t* backsector;
+
+} seg_t;
+
+
+
+//
+// BSP node.
+//
+typedef struct
+{
+ // Partition line.
+ fixed_t x;
+ fixed_t y;
+ fixed_t dx;
+ fixed_t dy;
+
+ // Bounding box for each child.
+ fixed_t bbox[2][4];
+
+ // If NF_SUBSECTOR its a subsector.
+ unsigned short children[2];
+
+} node_t;
+
+
+
+
+// PC direct to screen pointers
+//B UNUSED - keep till detailshift in r_draw.c resolved
+//extern byte* destview;
+//extern byte* destscreen;
+
+
+
+
+
+//
+// OTHER TYPES
+//
+
+// This could be wider for >8 bit display.
+// Indeed, true color support is posibble
+// precalculating 24bpp lightmap/colormap LUT.
+// from darkening PLAYPAL to all black.
+// Could even us emore than 32 levels.
+typedef byte lighttable_t;
+
+
+
+
+//
+// ?
+//
+typedef struct drawseg_s
+{
+ seg_t* curline;
+ int x1;
+ int x2;
+
+ fixed_t scale1;
+ fixed_t scale2;
+ fixed_t scalestep;
+
+ // 0=none, 1=bottom, 2=top, 3=both
+ int silhouette;
+
+ // do not clip sprites above this
+ fixed_t bsilheight;
+
+ // do not clip sprites below this
+ fixed_t tsilheight;
+
+ // Pointers to lists for sprite clipping,
+ // all three adjusted so [x1] is first value.
+ short* sprtopclip;
+ short* sprbottomclip;
+ short* maskedtexturecol;
+
+} drawseg_t;
+
+
+
+// A vissprite_t is a thing
+// that will be drawn during a refresh.
+// I.e. a sprite object that is partly visible.
+typedef struct vissprite_s
+{
+ // Doubly linked list.
+ struct vissprite_s* prev;
+ struct vissprite_s* next;
+
+ int x1;
+ int x2;
+
+ // for line side calculation
+ fixed_t gx;
+ fixed_t gy;
+
+ // global bottom / top for silhouette clipping
+ fixed_t gz;
+ fixed_t gzt;
+
+ // horizontal position of x1
+ fixed_t startfrac;
+
+ fixed_t scale;
+
+ // negative if flipped
+ fixed_t xiscale;
+
+ fixed_t texturemid;
+ int patch;
+
+ // for color translation and shadow draw,
+ // maxbright frames as well
+ lighttable_t* colormap;
+
+ int mobjflags;
+
+} vissprite_t;
+
+
+//
+// Sprites are patches with a special naming convention
+// so they can be recognized by R_InitSprites.
+// The base name is NNNNFx or NNNNFxFx, with
+// x indicating the rotation, x = 0, 1-7.
+// The sprite and frame specified by a thing_t
+// is range checked at run time.
+// A sprite is a patch_t that is assumed to represent
+// a three dimensional object and may have multiple
+// rotations pre drawn.
+// Horizontal flipping is used to save space,
+// thus NNNNF2F5 defines a mirrored patch.
+// Some sprites will only have one picture used
+// for all views: NNNNF0
+//
+typedef struct
+{
+ // If false use 0 for any position.
+ // Note: as eight entries are available,
+ // we might as well insert the same name eight times.
+ boolean rotate;
+
+ // Lump to use for view angles 0-7.
+ short lump[8];
+
+ // Flip bit (1 = flip) to use for view angles 0-7.
+ byte flip[8];
+
+} spriteframe_t;
+
+
+
+//
+// A sprite definition:
+// a number of animation frames.
+//
+typedef struct
+{
+ int numframes;
+ spriteframe_t* spriteframes;
+
+} spritedef_t;
+
+
+
+//
+// Now what is a visplane, anyway?
+//
+typedef struct
+{
+ fixed_t height;
+ int picnum;
+ int lightlevel;
+ int minx;
+ int maxx;
+
+ // leave pads for [minx-1]/[maxx+1]
+
+ byte pad1;
+ // Here lies the rub for all
+ // dynamic resize/change of resolution.
+ byte top[SCREENWIDTH];
+ byte pad2;
+ byte pad3;
+ // See above.
+ byte bottom[SCREENWIDTH];
+ byte pad4;
+
+} visplane_t;
+
+
+
+
+#endif
diff --git a/src/strife/r_draw.c b/src/strife/r_draw.c
new file mode 100644
index 00000000..27c44763
--- /dev/null
+++ b/src/strife/r_draw.c
@@ -0,0 +1,976 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// The actual span/column drawing functions.
+// Here find the main potential for optimization,
+// e.g. inline assembly, different algorithms.
+//
+//-----------------------------------------------------------------------------
+
+
+
+
+#include "doomdef.h"
+#include "deh_main.h"
+
+#include "i_system.h"
+#include "z_zone.h"
+#include "w_wad.h"
+
+#include "r_local.h"
+
+// Needs access to LFB (guess what).
+#include "v_video.h"
+
+// State.
+#include "doomstat.h"
+
+
+// ?
+#define MAXWIDTH 1120
+#define MAXHEIGHT 832
+
+// status bar height at bottom of screen
+// haleyjd 08/31/10: Verified unmodified.
+#define SBARHEIGHT 32
+
+//
+// All drawing to the view buffer is accomplished in this file.
+// The other refresh files only know about ccordinates,
+// not the architecture of the frame buffer.
+// Conveniently, the frame buffer is a linear one,
+// and we need only the base address,
+// and the total size == width*height*depth/8.,
+//
+
+
+byte* viewimage;
+int viewwidth;
+int scaledviewwidth;
+int viewheight;
+int viewwindowx;
+int viewwindowy;
+byte* ylookup[MAXHEIGHT];
+int columnofs[MAXWIDTH];
+
+// Color tables for different players,
+// translate a limited part to another
+// (color ramps used for suit colors).
+//
+// [STRIFE] Unused.
+//byte translations[3][256];
+
+// Backing buffer containing the bezel drawn around the screen and
+// surrounding background.
+
+static byte *background_buffer = NULL;
+
+// haleyjd 08/29/10: [STRIFE] Rogue added the ability to customize the view
+// border flat by storing it in the configuration file.
+char *back_flat = "F_PAVE01";
+
+//
+// R_DrawColumn
+// Source is the top of the column to scale.
+//
+lighttable_t* dc_colormap;
+int dc_x;
+int dc_yl;
+int dc_yh;
+fixed_t dc_iscale;
+fixed_t dc_texturemid;
+
+// first pixel in a column (possibly virtual)
+byte* dc_source;
+
+// just for profiling
+int dccount;
+
+//
+// A column is a vertical slice/span from a wall texture that,
+// given the DOOM style restrictions on the view orientation,
+// will always have constant z depth.
+// Thus a special case loop for very fast rendering can
+// be used. It has also been used with Wolfenstein 3D.
+//
+void R_DrawColumn (void)
+{
+ int count;
+ byte* dest;
+ fixed_t frac;
+ fixed_t fracstep;
+
+ count = dc_yh - dc_yl;
+
+ // Zero length, column does not exceed a pixel.
+ if (count < 0)
+ return;
+
+#ifdef RANGECHECK
+ if ((unsigned)dc_x >= SCREENWIDTH
+ || dc_yl < 0
+ || dc_yh >= SCREENHEIGHT)
+ I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
+#endif
+
+ // Framebuffer destination address.
+ // Use ylookup LUT to avoid multiply with ScreenWidth.
+ // Use columnofs LUT for subwindows?
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ // Determine scaling,
+ // which is the only mapping to be done.
+ fracstep = dc_iscale;
+ frac = dc_texturemid + (dc_yl-centery)*fracstep;
+
+ // Inner loop that does the actual texture mapping,
+ // e.g. a DDA-lile scaling.
+ // This is as fast as it gets.
+ do
+ {
+ // Re-map color indices from wall texture column
+ // using a lighting/special effects LUT.
+ *dest = dc_colormap[dc_source[(frac>>FRACBITS)&127]];
+
+ dest += SCREENWIDTH;
+ frac += fracstep;
+
+ } while (count--);
+}
+
+
+
+// UNUSED.
+// Loop unrolled.
+#if 0
+void R_DrawColumn (void)
+{
+ int count;
+ byte* source;
+ byte* dest;
+ byte* colormap;
+
+ unsigned frac;
+ unsigned fracstep;
+ unsigned fracstep2;
+ unsigned fracstep3;
+ unsigned fracstep4;
+
+ count = dc_yh - dc_yl + 1;
+
+ source = dc_source;
+ colormap = dc_colormap;
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ fracstep = dc_iscale<<9;
+ frac = (dc_texturemid + (dc_yl-centery)*dc_iscale)<<9;
+
+ fracstep2 = fracstep+fracstep;
+ fracstep3 = fracstep2+fracstep;
+ fracstep4 = fracstep3+fracstep;
+
+ while (count >= 8)
+ {
+ dest[0] = colormap[source[frac>>25]];
+ dest[SCREENWIDTH] = colormap[source[(frac+fracstep)>>25]];
+ dest[SCREENWIDTH*2] = colormap[source[(frac+fracstep2)>>25]];
+ dest[SCREENWIDTH*3] = colormap[source[(frac+fracstep3)>>25]];
+
+ frac += fracstep4;
+
+ dest[SCREENWIDTH*4] = colormap[source[frac>>25]];
+ dest[SCREENWIDTH*5] = colormap[source[(frac+fracstep)>>25]];
+ dest[SCREENWIDTH*6] = colormap[source[(frac+fracstep2)>>25]];
+ dest[SCREENWIDTH*7] = colormap[source[(frac+fracstep3)>>25]];
+
+ frac += fracstep4;
+ dest += SCREENWIDTH*8;
+ count -= 8;
+ }
+
+ while (count > 0)
+ {
+ *dest = colormap[source[frac>>25]];
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ count--;
+ }
+}
+#endif
+
+// haleyjd 09/06/10 [STRIFE] Removed low detail
+
+//
+// Spectre/Invisibility.
+//
+
+// haleyjd 09/06/10: ]STRIFE] replaced fuzzdraw with translucency.
+
+//
+// R_DrawMVisTLColumn
+//
+// villsa [STRIFE] new function
+// Replacement for R_DrawFuzzColumn
+//
+void R_DrawMVisTLColumn(void)
+{
+ int count;
+ byte* dest;
+ fixed_t frac;
+ fixed_t fracstep;
+
+ // Adjust borders. Low...
+ if (!dc_yl)
+ dc_yl = 1;
+
+ // .. and high.
+ if (dc_yh == viewheight-1)
+ dc_yh = viewheight - 2;
+
+ count = dc_yh - dc_yl;
+
+ // Zero length.
+ if (count < 0)
+ return;
+
+#ifdef RANGECHECK
+ if ((unsigned)dc_x >= SCREENWIDTH
+ || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+ {
+ I_Error ("R_DrawFuzzColumn: %i to %i at %i",
+ dc_yl, dc_yh, dc_x);
+ }
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ // Looks familiar.
+ fracstep = dc_iscale;
+ frac = dc_texturemid + (dc_yl-centery)*fracstep;
+
+ do
+ {
+ byte src = dc_colormap[dc_source[(frac>>FRACBITS)&127]];
+ byte col = xlatab[*dest + (src << 8)];
+ *dest = col;
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ } while(count--);
+}
+
+//
+// R_DrawTLColumn
+//
+// villsa [STRIFE] new function
+// Achieves a second translucency level using the same lookup table,
+// via inversion of the colors in the index computation.
+//
+void R_DrawTLColumn(void)
+{
+ int count;
+ byte* dest;
+ fixed_t frac;
+ fixed_t fracstep;
+
+ // Adjust borders. Low...
+ if (!dc_yl)
+ dc_yl = 1;
+
+ // .. and high.
+ if (dc_yh == viewheight-1)
+ dc_yh = viewheight - 2;
+
+ count = dc_yh - dc_yl;
+
+ // Zero length.
+ if (count < 0)
+ return;
+
+#ifdef RANGECHECK
+ if ((unsigned)dc_x >= SCREENWIDTH
+ || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+ {
+ I_Error ("R_DrawFuzzColumn2: %i to %i at %i",
+ dc_yl, dc_yh, dc_x);
+ }
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ // Looks familiar.
+ fracstep = dc_iscale;
+ frac = dc_texturemid + (dc_yl-centery)*fracstep;
+
+ do
+ {
+ byte src = dc_colormap[dc_source[(frac>>FRACBITS)&127]];
+ byte col = xlatab[(*dest << 8) + src];
+ *dest = col;
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ } while(count--);
+}
+
+
+
+//
+// R_DrawTranslatedColumn
+// Used to draw player sprites
+// with the green colorramp mapped to others.
+// Could be used with different translation
+// tables, e.g. the lighter colored version
+// of the BaronOfHell, the HellKnight, uses
+// identical sprites, kinda brightened up.
+//
+byte* dc_translation;
+byte* translationtables;
+
+void R_DrawTranslatedColumn (void)
+{
+ int count;
+ byte* dest;
+ fixed_t frac;
+ fixed_t fracstep;
+
+ count = dc_yh - dc_yl;
+ if (count < 0)
+ return;
+
+#ifdef RANGECHECK
+ if ((unsigned)dc_x >= SCREENWIDTH
+ || dc_yl < 0
+ || dc_yh >= SCREENHEIGHT)
+ {
+ I_Error ( "R_DrawColumn: %i to %i at %i",
+ dc_yl, dc_yh, dc_x);
+ }
+
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ // Looks familiar.
+ fracstep = dc_iscale;
+ frac = dc_texturemid + (dc_yl-centery)*fracstep;
+
+ // Here we do an additional index re-mapping.
+ do
+ {
+ // Translation tables are used
+ // to map certain colorramps to other ones,
+ // used with PLAY sprites.
+ // Thus the "green" ramp of the player 0 sprite
+ // is mapped to gray, red, black/indigo.
+ *dest = dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]];
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ } while (count--);
+}
+
+// haleyjd 09/06/10 [STRIFE] Removed low detail
+
+//
+// R_DrawTRTLColumn
+//
+// villsa [STRIFE] new function
+// Combines translucency and color translation.
+//
+void R_DrawTRTLColumn(void)
+{
+ int count;
+ byte* dest;
+ fixed_t frac;
+ fixed_t fracstep;
+
+ count = dc_yh - dc_yl;
+ if (count < 0)
+ return;
+
+#ifdef RANGECHECK
+ if ((unsigned)dc_x >= SCREENWIDTH
+ || dc_yl < 0
+ || dc_yh >= SCREENHEIGHT)
+ {
+ I_Error ( "R_DrawColumn: %i to %i at %i",
+ dc_yl, dc_yh, dc_x);
+ }
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ // Looks familiar.
+ fracstep = dc_iscale;
+ frac = dc_texturemid + (dc_yl-centery)*fracstep;
+
+ // Here we do an additional index re-mapping.
+ do
+ {
+ byte src = dc_colormap[dc_translation[dc_source[frac>>FRACBITS&127]]];
+ byte col = xlatab[(*dest << 8) + src];
+ *dest = col;
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ } while (count--);
+}
+
+
+//
+// R_InitTranslationTables
+// Creates the translation tables to map
+// the green color ramp to gray, brown, red.
+// Assumes a given structure of the PLAYPAL.
+// Could be read from a lump instead.
+//
+// haleyjd 08/26/10: [STRIFE]
+// * Added loading of XLATAB
+//
+void R_InitTranslationTables (void)
+{
+ int i;
+ byte col1, col2;
+
+ // [STRIFE] Load xlatab. Here's how Rogue did it:
+ // v7 = W_CacheLumpName("XLATAB", PU_CACHE); // note potential cache bug...
+ // HIWORD(v8) = (Z_Malloc(131072, PU_STATIC, NULL) + 65535) >> 16;
+ // LOWORD(v8) = 0; // aligning to a 64K boundary, as if this is Wolf3D.
+ // xlatab = v8;
+ // memcpy(v8, v7, 65536);
+ // As you can see, they copypasta'd id's unnecessary 64K boundary alignment
+ // from the colormap code. Since this doesn't accomplish anything, and isn't
+ // strictly portable, all we need to do is this:
+
+ // villsa [STRIFE] 09/26/10: load table through this function instead
+ V_LoadXlaTable();
+
+ // villsa [STRIFE] allocate a larger size for translation tables
+ translationtables = Z_Malloc (256*8, PU_STATIC, 0);
+
+ col1 = 0xFA;
+ col2 = 0xE0;
+
+ // villsa [STRIFE] setup all translation tables
+ for(i = 0; i < 256; i++)
+ {
+ if(i >= 0x80 && i <= 0x8f)
+ {
+ translationtables [i ] = (i & 0x0f) + 64;
+ translationtables [i+ 256] = (i & 0x0f) - 80;
+ translationtables [i+2*256] = (i & 0x0f) + 16;
+ translationtables [i+3*256] = (i & 0x0f) + 48;
+ translationtables [i+4*256] = (i & 0x0f) + 80;
+ translationtables [i+5*256] = (i & 0x0f) + 96;
+ translationtables [i+6*256] = (i & 0x0f) - 112;
+ }
+ else if(i >= 0x50 && i<= 0x5f)
+ {
+ translationtables [i ] = i;
+ translationtables [i+ 256] = i;
+ translationtables [i+2*256] = i;
+ translationtables [i+3*256] = i;
+ translationtables [i+4*256] = (i & 0x0f) + 0x80;
+ translationtables [i+5*256] = (i & 0x0f) + 16;
+ translationtables [i+6*256] = (i & 0x0f) + 64;
+ }
+ else if(i >= 0xd0 && i<= 0xdf)
+ {
+ translationtables [i ] = i;
+ translationtables [i+ 256] = i;
+ translationtables [i+2*256] = i;
+ translationtables [i+3*256] = i;
+ translationtables [i+4*256] = (i & 0x0f) - 80;
+ translationtables [i+5*256] = (i & 0x0f) + 48;
+ translationtables [i+6*256] = (i & 0x0f) + 16;
+ }
+ else if(i >= 0xc0 && i<= 0xcf)
+ {
+ translationtables [i ] = i;
+ translationtables [i+ 256] = i;
+ translationtables [i+2*256] = i;
+ translationtables [i+3*256] = i;
+ translationtables [i+4*256] = (i & 0x0f) - 96;
+ translationtables [i+5*256] = (i & 0x0f) + 32;
+ translationtables [i+6*256] = (i & 0x0f);
+ // haleyjd 20110213: missing code:
+ if(!(i & 0x0f))
+ translationtables[i+6*256] = 1;
+ }
+ else if(i >= 0xf7 && i<= 0xfb)
+ {
+ translationtables [i ] = col1;
+ translationtables [i+ 256] = i;
+ translationtables [i+2*256] = i;
+ translationtables [i+3*256] = i;
+ translationtables [i+4*256] = i;
+ translationtables [i+5*256] = i;
+ translationtables [i+6*256] = i;
+ }
+ else if(i >= 0xf1 && i<= 0xf6)
+ {
+ translationtables [i ] = (i & 0x0f) - 33;
+ translationtables [i+ 256] = i;
+ translationtables [i+2*256] = i;
+ translationtables [i+3*256] = i;
+ translationtables [i+4*256] = i;
+ translationtables [i+5*256] = i;
+ translationtables [i+6*256] = i;
+ }
+ else if(i >= 0x20 && i <= 0x3f) // haleyjd 20110213: fixed upper end
+ {
+ translationtables [i ] = col2;
+ translationtables [i+ 256] = col2;
+ translationtables [i+2*256] = (i & 0x0f) - 48;
+ translationtables [i+3*256] = (i & 0x0f) - 48;
+ translationtables [i+4*256] = col2;
+ translationtables [i+5*256] = col2;
+ translationtables [i+6*256] = col2;
+ }
+ else // Keep all other colors as is.
+ {
+ translationtables[i]=
+ translationtables[i+256]=
+ translationtables[i+2*256]=
+ translationtables[i+3*256]=
+ translationtables[i+4*256]=
+ translationtables[i+5*256]=
+ translationtables[i+6*256]=i;
+ }
+
+ ++col1;
+ ++col2;
+ }
+}
+
+
+
+
+//
+// R_DrawSpan
+// With DOOM style restrictions on view orientation,
+// the floors and ceilings consist of horizontal slices
+// or spans with constant z depth.
+// However, rotation around the world z axis is possible,
+// thus this mapping, while simpler and faster than
+// perspective correct texture mapping, has to traverse
+// the texture at an angle in all but a few cases.
+// In consequence, flats are not stored by column (like walls),
+// and the inner loop has to step in texture space u and v.
+//
+int ds_y;
+int ds_x1;
+int ds_x2;
+
+lighttable_t* ds_colormap;
+
+fixed_t ds_xfrac;
+fixed_t ds_yfrac;
+fixed_t ds_xstep;
+fixed_t ds_ystep;
+
+// start of a 64*64 tile image
+byte* ds_source;
+
+// just for profiling
+int dscount;
+
+
+//
+// Draws the actual span.
+void R_DrawSpan (void)
+{
+ unsigned int position, step;
+ byte *dest;
+ int count;
+ int spot;
+ unsigned int xtemp, ytemp;
+
+#ifdef RANGECHECK
+ if (ds_x2 < ds_x1
+ || ds_x1<0
+ || ds_x2>=SCREENWIDTH
+ || (unsigned)ds_y>SCREENHEIGHT)
+ {
+ I_Error( "R_DrawSpan: %i to %i at %i",
+ ds_x1,ds_x2,ds_y);
+ }
+// dscount++;
+#endif
+
+ // Pack position and step variables into a single 32-bit integer,
+ // with x in the top 16 bits and y in the bottom 16 bits. For
+ // each 16-bit part, the top 6 bits are the integer part and the
+ // bottom 10 bits are the fractional part of the pixel position.
+
+ position = ((ds_xfrac << 10) & 0xffff0000)
+ | ((ds_yfrac >> 6) & 0x0000ffff);
+ step = ((ds_xstep << 10) & 0xffff0000)
+ | ((ds_ystep >> 6) & 0x0000ffff);
+
+ dest = ylookup[ds_y] + columnofs[ds_x1];
+
+ // We do not check for zero spans here?
+ count = ds_x2 - ds_x1;
+
+ do
+ {
+ // Calculate current texture index in u,v.
+ ytemp = (position >> 4) & 0x0fc0;
+ xtemp = (position >> 26);
+ spot = xtemp | ytemp;
+
+ // Lookup pixel from flat texture tile,
+ // re-index using light/colormap.
+ *dest++ = ds_colormap[ds_source[spot]];
+
+ position += step;
+
+ } while (count--);
+}
+
+
+
+// UNUSED.
+// Loop unrolled by 4.
+#if 0
+void R_DrawSpan (void)
+{
+ unsigned position, step;
+
+ byte* source;
+ byte* colormap;
+ byte* dest;
+
+ unsigned count;
+ usingned spot;
+ unsigned value;
+ unsigned temp;
+ unsigned xtemp;
+ unsigned ytemp;
+
+ position = ((ds_xfrac<<10)&0xffff0000) | ((ds_yfrac>>6)&0xffff);
+ step = ((ds_xstep<<10)&0xffff0000) | ((ds_ystep>>6)&0xffff);
+
+ source = ds_source;
+ colormap = ds_colormap;
+ dest = ylookup[ds_y] + columnofs[ds_x1];
+ count = ds_x2 - ds_x1 + 1;
+
+ while (count >= 4)
+ {
+ ytemp = position>>4;
+ ytemp = ytemp & 4032;
+ xtemp = position>>26;
+ spot = xtemp | ytemp;
+ position += step;
+ dest[0] = colormap[source[spot]];
+
+ ytemp = position>>4;
+ ytemp = ytemp & 4032;
+ xtemp = position>>26;
+ spot = xtemp | ytemp;
+ position += step;
+ dest[1] = colormap[source[spot]];
+
+ ytemp = position>>4;
+ ytemp = ytemp & 4032;
+ xtemp = position>>26;
+ spot = xtemp | ytemp;
+ position += step;
+ dest[2] = colormap[source[spot]];
+
+ ytemp = position>>4;
+ ytemp = ytemp & 4032;
+ xtemp = position>>26;
+ spot = xtemp | ytemp;
+ position += step;
+ dest[3] = colormap[source[spot]];
+
+ count -= 4;
+ dest += 4;
+ }
+ while (count > 0)
+ {
+ ytemp = position>>4;
+ ytemp = ytemp & 4032;
+ xtemp = position>>26;
+ spot = xtemp | ytemp;
+ position += step;
+ *dest++ = colormap[source[spot]];
+ count--;
+ }
+}
+#endif
+
+
+//
+// Again..
+//
+void R_DrawSpanLow (void)
+{
+ unsigned int position, step;
+ unsigned int xtemp, ytemp;
+ byte *dest;
+ int count;
+ int spot;
+
+#ifdef RANGECHECK
+ if (ds_x2 < ds_x1
+ || ds_x1<0
+ || ds_x2>=SCREENWIDTH
+ || (unsigned)ds_y>SCREENHEIGHT)
+ {
+ I_Error( "R_DrawSpan: %i to %i at %i",
+ ds_x1,ds_x2,ds_y);
+ }
+// dscount++;
+#endif
+
+ position = ((ds_xfrac << 10) & 0xffff0000)
+ | ((ds_yfrac >> 6) & 0x0000ffff);
+ step = ((ds_xstep << 10) & 0xffff0000)
+ | ((ds_ystep >> 6) & 0x0000ffff);
+
+ count = (ds_x2 - ds_x1);
+
+ // Blocky mode, need to multiply by 2.
+ ds_x1 <<= 1;
+ ds_x2 <<= 1;
+
+ dest = ylookup[ds_y] + columnofs[ds_x1];
+
+ do
+ {
+ // Calculate current texture index in u,v.
+ ytemp = (position >> 4) & 0x0fc0;
+ xtemp = (position >> 26);
+ spot = xtemp | ytemp;
+
+ // Lowres/blocky mode does it twice,
+ // while scale is adjusted appropriately.
+ *dest++ = ds_colormap[ds_source[spot]];
+ *dest++ = ds_colormap[ds_source[spot]];
+
+ position += step;
+
+ } while (count--);
+}
+
+//
+// R_InitBuffer
+// Creats lookup tables that avoid
+// multiplies and other hazzles
+// for getting the framebuffer address
+// of a pixel to draw.
+//
+void
+R_InitBuffer
+( int width,
+ int height )
+{
+ int i;
+
+ // Handle resize,
+ // e.g. smaller view windows
+ // with border and/or status bar.
+ viewwindowx = (SCREENWIDTH-width) >> 1;
+
+ // Column offset. For windows.
+ for (i=0 ; i<width ; i++)
+ columnofs[i] = viewwindowx + i;
+
+ // Samw with base row offset.
+ if (width == SCREENWIDTH)
+ viewwindowy = 0;
+ else
+ viewwindowy = (SCREENHEIGHT-SBARHEIGHT-height) >> 1;
+
+ // Preclaculate all row offsets.
+ for (i=0 ; i<height ; i++)
+ ylookup[i] = I_VideoBuffer + (i+viewwindowy)*SCREENWIDTH;
+}
+
+
+
+
+//
+// R_FillBackScreen
+// Fills the back screen with a pattern
+// for variable screen sizes
+// Also draws a beveled edge.
+//
+// haleyjd 08/29/10: [STRIFE] Added support for configurable back_flat.
+//
+void R_FillBackScreen (void)
+{
+ byte* src;
+ byte* dest;
+ int x;
+ int y;
+ patch_t* patch;
+
+ char *name;
+
+ // If we are running full screen, there is no need to do any of this,
+ // and the background buffer can be freed if it was previously in use.
+
+ if (scaledviewwidth == SCREENWIDTH)
+ {
+ if (background_buffer != NULL)
+ {
+ Z_Free(background_buffer);
+ background_buffer = NULL;
+ }
+
+ return;
+ }
+
+ // Allocate the background buffer if necessary
+
+ if (background_buffer == NULL)
+ {
+ background_buffer = Z_Malloc(SCREENWIDTH * (SCREENHEIGHT - SBARHEIGHT),
+ PU_STATIC, NULL);
+ }
+
+ // haleyjd 08/29/10: [STRIFE] Use configurable back_flat
+ name = back_flat;
+
+ src = W_CacheLumpName(name, PU_CACHE);
+ dest = background_buffer;
+
+ for (y=0 ; y<SCREENHEIGHT-SBARHEIGHT ; y++)
+ {
+ for (x=0 ; x<SCREENWIDTH/64 ; x++)
+ {
+ memcpy (dest, src+((y&63)<<6), 64);
+ dest += 64;
+ }
+
+ if (SCREENWIDTH&63)
+ {
+ memcpy (dest, src+((y&63)<<6), SCREENWIDTH&63);
+ dest += (SCREENWIDTH&63);
+ }
+ }
+
+ // Draw screen and bezel; this is done to a separate screen buffer.
+
+ V_UseBuffer(background_buffer);
+
+ patch = W_CacheLumpName(DEH_String("brdr_t"),PU_CACHE);
+
+ for (x=0 ; x<scaledviewwidth ; x+=8)
+ V_DrawPatch(viewwindowx+x, viewwindowy-8, patch);
+ patch = W_CacheLumpName(DEH_String("brdr_b"),PU_CACHE);
+
+ for (x=0 ; x<scaledviewwidth ; x+=8)
+ V_DrawPatch(viewwindowx+x, viewwindowy+viewheight, patch);
+ patch = W_CacheLumpName(DEH_String("brdr_l"),PU_CACHE);
+
+ for (y=0 ; y<viewheight ; y+=8)
+ V_DrawPatch(viewwindowx-8, viewwindowy+y, patch);
+ patch = W_CacheLumpName(DEH_String("brdr_r"),PU_CACHE);
+
+ for (y=0 ; y<viewheight ; y+=8)
+ V_DrawPatch(viewwindowx+scaledviewwidth, viewwindowy+y, patch);
+
+ // Draw beveled edge.
+ V_DrawPatch(viewwindowx-8,
+ viewwindowy-8,
+ W_CacheLumpName(DEH_String("brdr_tl"),PU_CACHE));
+
+ V_DrawPatch(viewwindowx+scaledviewwidth,
+ viewwindowy-8,
+ W_CacheLumpName(DEH_String("brdr_tr"),PU_CACHE));
+
+ V_DrawPatch(viewwindowx-8,
+ viewwindowy+viewheight,
+ W_CacheLumpName(DEH_String("brdr_bl"),PU_CACHE));
+
+ V_DrawPatch(viewwindowx+scaledviewwidth,
+ viewwindowy+viewheight,
+ W_CacheLumpName(DEH_String("brdr_br"),PU_CACHE));
+
+ V_RestoreBuffer();
+}
+
+
+//
+// Copy a screen buffer.
+//
+void
+R_VideoErase
+( unsigned ofs,
+ int count )
+{
+ // LFB copy.
+ // This might not be a good idea if memcpy
+ // is not optiomal, e.g. byte by byte on
+ // a 32bit CPU, as GNU GCC/Linux libc did
+ // at one point.
+
+ if (background_buffer != NULL)
+ {
+ memcpy(I_VideoBuffer + ofs, background_buffer + ofs, count);
+ }
+}
+
+
+//
+// R_DrawViewBorder
+// Draws the border around the view
+// for different size windows?
+//
+void R_DrawViewBorder (void)
+{
+ int top;
+ int side;
+ int ofs;
+ int i;
+
+ if (scaledviewwidth == SCREENWIDTH)
+ return;
+
+ top = ((SCREENHEIGHT-SBARHEIGHT)-viewheight)/2;
+ side = (SCREENWIDTH-scaledviewwidth)/2;
+
+ // copy top and one line of left side
+ R_VideoErase (0, top*SCREENWIDTH+side);
+
+ // copy one line of right side and bottom
+ ofs = (viewheight+top)*SCREENWIDTH-side;
+ R_VideoErase (ofs, top*SCREENWIDTH+side);
+
+ // copy sides using wraparound
+ ofs = top*SCREENWIDTH + SCREENWIDTH-side;
+ side <<= 1;
+
+ for (i=1 ; i<viewheight ; i++)
+ {
+ R_VideoErase (ofs, side);
+ ofs += SCREENWIDTH;
+ }
+
+ // ?
+ V_MarkRect (0,0,SCREENWIDTH, SCREENHEIGHT-SBARHEIGHT);
+}
+
+
diff --git a/src/strife/r_draw.h b/src/strife/r_draw.h
new file mode 100644
index 00000000..aaa64711
--- /dev/null
+++ b/src/strife/r_draw.h
@@ -0,0 +1,119 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// System specific interface stuff.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __R_DRAW__
+#define __R_DRAW__
+
+
+
+
+extern lighttable_t* dc_colormap;
+extern int dc_x;
+extern int dc_yl;
+extern int dc_yh;
+extern fixed_t dc_iscale;
+extern fixed_t dc_texturemid;
+
+// first pixel in a column
+extern byte* dc_source;
+
+
+// The span blitting interface.
+// Hook in assembler or system specific BLT
+// here.
+void R_DrawColumn (void);
+void R_DrawColumnLow (void);
+
+// The Spectre/Invisibility effect.
+//void R_DrawFuzzColumn (void);
+//void R_DrawFuzzColumnLow (void);
+
+// Draw with color translation tables,
+// for player sprite rendering,
+// Green/Red/Blue/Indigo shirts.
+void R_DrawTranslatedColumn (void);
+void R_DrawTranslatedColumnLow (void);
+
+// villsa [STRIFE] - transclucent rendering
+void R_DrawTLColumn (void);
+void R_DrawMVisTLColumn (void);
+void R_DrawTRTLColumn (void);
+
+void
+R_VideoErase
+( unsigned ofs,
+ int count );
+
+extern int ds_y;
+extern int ds_x1;
+extern int ds_x2;
+
+extern lighttable_t* ds_colormap;
+
+extern fixed_t ds_xfrac;
+extern fixed_t ds_yfrac;
+extern fixed_t ds_xstep;
+extern fixed_t ds_ystep;
+
+// start of a 64*64 tile image
+extern byte* ds_source;
+
+extern byte* translationtables;
+extern byte* dc_translation;
+extern byte* xlatab; // haleyjd 08/26/10: [STRIFE]
+
+extern char *back_flat; // haleyjd 08/29/10: [STRIFE]
+
+// Span blitting for rows, floor/ceiling.
+// No Sepctre effect needed.
+void R_DrawSpan (void);
+
+// Low resolution mode, 160x200?
+void R_DrawSpanLow (void);
+
+
+void
+R_InitBuffer
+( int width,
+ int height );
+
+
+// Initialize color translation tables,
+// for player rendering etc.
+void R_InitTranslationTables (void);
+
+
+
+// Rendering function.
+void R_FillBackScreen (void);
+
+// If the view size is not full screen, draws a border around it.
+void R_DrawViewBorder (void);
+
+
+
+#endif
diff --git a/src/strife/r_local.h b/src/strife/r_local.h
new file mode 100644
index 00000000..8b97bdb0
--- /dev/null
+++ b/src/strife/r_local.h
@@ -0,0 +1,53 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Refresh (R_*) module, global header.
+// All the rendering/drawing stuff is here.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef __R_LOCAL__
+#define __R_LOCAL__
+
+// Binary Angles, sine/cosine/atan lookups.
+#include "tables.h"
+
+// Screen size related parameters.
+#include "doomdef.h"
+
+// Include the refresh/render data structs.
+#include "r_data.h"
+
+
+
+//
+// Separate header file for each module.
+//
+#include "r_main.h"
+#include "r_bsp.h"
+#include "r_segs.h"
+#include "r_plane.h"
+#include "r_data.h"
+#include "r_things.h"
+#include "r_draw.h"
+
+#endif // __R_LOCAL__
diff --git a/src/strife/r_main.c b/src/strife/r_main.c
new file mode 100644
index 00000000..cf588159
--- /dev/null
+++ b/src/strife/r_main.c
@@ -0,0 +1,953 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Rendering main loop and setup functions,
+// utility functions (BSP, geometry, trigonometry).
+// See tables.c, too.
+//
+//-----------------------------------------------------------------------------
+
+
+
+
+
+#include <stdlib.h>
+#include <math.h>
+
+
+#include "doomdef.h"
+#include "doomstat.h" // villsa [STRIFE]
+#include "d_main.h"
+
+#include "m_bbox.h"
+#include "m_menu.h"
+
+#include "r_local.h"
+#include "r_sky.h"
+
+
+
+
+
+// Fineangles in the SCREENWIDTH wide window.
+#define FIELDOFVIEW 2048
+
+
+
+int viewangleoffset;
+
+// increment every time a check is made
+int validcount = 1;
+
+
+lighttable_t* fixedcolormap;
+extern lighttable_t** walllights;
+
+int centerx;
+int centery;
+
+fixed_t centerxfrac;
+fixed_t centeryfrac;
+fixed_t projection;
+
+// just for profiling purposes
+int framecount;
+
+int sscount;
+int linecount;
+int loopcount;
+
+fixed_t viewx;
+fixed_t viewy;
+fixed_t viewz;
+
+int viewpitch; // villsa [STRIFE]
+
+angle_t viewangle;
+
+fixed_t viewcos;
+fixed_t viewsin;
+
+player_t* viewplayer;
+
+// 0 = high, 1 = low
+int detailshift;
+
+//
+// precalculated math tables
+//
+angle_t clipangle;
+
+// The viewangletox[viewangle + FINEANGLES/4] lookup
+// maps the visible view angles to screen X coordinates,
+// flattening the arc to a flat projection plane.
+// There will be many angles mapped to the same X.
+int viewangletox[FINEANGLES/2];
+
+// The xtoviewangleangle[] table maps a screen pixel
+// to the lowest viewangle that maps back to x ranges
+// from clipangle to -clipangle.
+angle_t xtoviewangle[SCREENWIDTH+1];
+
+lighttable_t* scalelight[LIGHTLEVELS][MAXLIGHTSCALE];
+lighttable_t* scalelightfixed[MAXLIGHTSCALE];
+lighttable_t* zlight[LIGHTLEVELS][MAXLIGHTZ];
+
+// bumped light from gun blasts
+int extralight;
+
+
+
+void (*colfunc) (void);
+void (*basecolfunc) (void);
+void (*fuzzcolfunc) (void);
+void (*transcolfunc) (void);
+void (*spanfunc) (void);
+
+
+
+//
+// R_AddPointToBox
+// Expand a given bbox
+// so that it encloses a given point.
+//
+void
+R_AddPointToBox
+( int x,
+ int y,
+ fixed_t* box )
+{
+ if (x< box[BOXLEFT])
+ box[BOXLEFT] = x;
+ if (x> box[BOXRIGHT])
+ box[BOXRIGHT] = x;
+ if (y< box[BOXBOTTOM])
+ box[BOXBOTTOM] = y;
+ if (y> box[BOXTOP])
+ box[BOXTOP] = y;
+}
+
+
+//
+// R_PointOnSide
+// Traverse BSP (sub) tree,
+// check point against partition plane.
+// Returns side 0 (front) or 1 (back).
+//
+int
+R_PointOnSide
+( fixed_t x,
+ fixed_t y,
+ node_t* node )
+{
+ fixed_t dx;
+ fixed_t dy;
+ fixed_t left;
+ fixed_t right;
+
+ if (!node->dx)
+ {
+ if (x <= node->x)
+ return node->dy > 0;
+
+ return node->dy < 0;
+ }
+ if (!node->dy)
+ {
+ if (y <= node->y)
+ return node->dx < 0;
+
+ return node->dx > 0;
+ }
+
+ dx = (x - node->x);
+ dy = (y - node->y);
+
+ // Try to quickly decide by looking at sign bits.
+ if ( (node->dy ^ node->dx ^ dx ^ dy)&0x80000000 )
+ {
+ if ( (node->dy ^ dx) & 0x80000000 )
+ {
+ // (left is negative)
+ return 1;
+ }
+ return 0;
+ }
+
+ left = FixedMul ( node->dy>>FRACBITS , dx );
+ right = FixedMul ( dy , node->dx>>FRACBITS );
+
+ if (right < left)
+ {
+ // front side
+ return 0;
+ }
+ // back side
+ return 1;
+}
+
+
+int
+R_PointOnSegSide
+( fixed_t x,
+ fixed_t y,
+ seg_t* line )
+{
+ fixed_t lx;
+ fixed_t ly;
+ fixed_t ldx;
+ fixed_t ldy;
+ fixed_t dx;
+ fixed_t dy;
+ fixed_t left;
+ fixed_t right;
+
+ lx = line->v1->x;
+ ly = line->v1->y;
+
+ ldx = line->v2->x - lx;
+ ldy = line->v2->y - ly;
+
+ if (!ldx)
+ {
+ if (x <= lx)
+ return ldy > 0;
+
+ return ldy < 0;
+ }
+ if (!ldy)
+ {
+ if (y <= ly)
+ return ldx < 0;
+
+ return ldx > 0;
+ }
+
+ dx = (x - lx);
+ dy = (y - ly);
+
+ // Try to quickly decide by looking at sign bits.
+ if ( (ldy ^ ldx ^ dx ^ dy)&0x80000000 )
+ {
+ if ( (ldy ^ dx) & 0x80000000 )
+ {
+ // (left is negative)
+ return 1;
+ }
+ return 0;
+ }
+
+ left = FixedMul ( ldy>>FRACBITS , dx );
+ right = FixedMul ( dy , ldx>>FRACBITS );
+
+ if (right < left)
+ {
+ // front side
+ return 0;
+ }
+ // back side
+ return 1;
+}
+
+
+//
+// R_PointToAngle
+// To get a global angle from cartesian coordinates,
+// the coordinates are flipped until they are in
+// the first octant of the coordinate system, then
+// the y (<=x) is scaled and divided by x to get a
+// tangent (slope) value which is looked up in the
+// tantoangle[] table.
+
+//
+
+
+
+
+angle_t
+R_PointToAngle
+( fixed_t x,
+ fixed_t y )
+{
+ x -= viewx;
+ y -= viewy;
+
+ if ( (!x) && (!y) )
+ return 0;
+
+ if (x>= 0)
+ {
+ // x >=0
+ if (y>= 0)
+ {
+ // y>= 0
+
+ if (x>y)
+ {
+ // octant 0
+ return tantoangle[ SlopeDiv(y,x)];
+ }
+ else
+ {
+ // octant 1
+ return ANG90-1-tantoangle[ SlopeDiv(x,y)];
+ }
+ }
+ else
+ {
+ // y<0
+ y = -y;
+
+ if (x>y)
+ {
+ // octant 8
+ return 0 - tantoangle[SlopeDiv(y,x)];
+ }
+ else
+ {
+ // octant 7
+ return ANG270+tantoangle[ SlopeDiv(x,y)];
+ }
+ }
+ }
+ else
+ {
+ // x<0
+ x = -x;
+
+ if (y>= 0)
+ {
+ // y>= 0
+ if (x>y)
+ {
+ // octant 3
+ return ANG180-1-tantoangle[ SlopeDiv(y,x)];
+ }
+ else
+ {
+ // octant 2
+ return ANG90+ tantoangle[ SlopeDiv(x,y)];
+ }
+ }
+ else
+ {
+ // y<0
+ y = -y;
+
+ if (x>y)
+ {
+ // octant 4
+ return ANG180+tantoangle[ SlopeDiv(y,x)];
+ }
+ else
+ {
+ // octant 5
+ return ANG270-1-tantoangle[ SlopeDiv(x,y)];
+ }
+ }
+ }
+ return 0;
+}
+
+
+angle_t
+R_PointToAngle2
+( fixed_t x1,
+ fixed_t y1,
+ fixed_t x2,
+ fixed_t y2 )
+{
+ viewx = x1;
+ viewy = y1;
+
+ return R_PointToAngle (x2, y2);
+}
+
+
+fixed_t
+R_PointToDist
+( fixed_t x,
+ fixed_t y )
+{
+ int angle;
+ fixed_t dx;
+ fixed_t dy;
+ fixed_t temp;
+ fixed_t dist;
+ fixed_t frac;
+
+ dx = abs(x - viewx);
+ dy = abs(y - viewy);
+
+ if (dy>dx)
+ {
+ temp = dx;
+ dx = dy;
+ dy = temp;
+ }
+
+ // Fix crashes in udm1.wad
+
+ if (dx != 0)
+ {
+ frac = FixedDiv(dy, dx);
+ }
+ else
+ {
+ frac = 0;
+ }
+
+ angle = (tantoangle[frac>>DBITS]+ANG90) >> ANGLETOFINESHIFT;
+
+ // use as cosine
+ dist = FixedDiv (dx, finesine[angle] );
+
+ return dist;
+}
+
+
+
+
+//
+// R_InitPointToAngle
+//
+void R_InitPointToAngle (void)
+{
+ // UNUSED - now getting from tables.c
+#if 0
+ int i;
+ long t;
+ float f;
+//
+// slope (tangent) to angle lookup
+//
+ for (i=0 ; i<=SLOPERANGE ; i++)
+ {
+ f = atan( (float)i/SLOPERANGE )/(3.141592657*2);
+ t = 0xffffffff*f;
+ tantoangle[i] = t;
+ }
+#endif
+}
+
+
+//
+// R_ScaleFromGlobalAngle
+// Returns the texture mapping scale
+// for the current line (horizontal span)
+// at the given angle.
+// rw_distance must be calculated first.
+//
+fixed_t R_ScaleFromGlobalAngle (angle_t visangle)
+{
+ fixed_t scale;
+ angle_t anglea;
+ angle_t angleb;
+ int sinea;
+ int sineb;
+ fixed_t num;
+ int den;
+
+ // UNUSED
+#if 0
+{
+ fixed_t dist;
+ fixed_t z;
+ fixed_t sinv;
+ fixed_t cosv;
+
+ sinv = finesine[(visangle-rw_normalangle)>>ANGLETOFINESHIFT];
+ dist = FixedDiv (rw_distance, sinv);
+ cosv = finecosine[(viewangle-visangle)>>ANGLETOFINESHIFT];
+ z = abs(FixedMul (dist, cosv));
+ scale = FixedDiv(projection, z);
+ return scale;
+}
+#endif
+
+ anglea = ANG90 + (visangle-viewangle);
+ angleb = ANG90 + (visangle-rw_normalangle);
+
+ // both sines are allways positive
+ sinea = finesine[anglea>>ANGLETOFINESHIFT];
+ sineb = finesine[angleb>>ANGLETOFINESHIFT];
+ num = FixedMul(projection,sineb)<<detailshift;
+ den = FixedMul(rw_distance,sinea);
+
+ if (den > num>>16)
+ {
+ scale = FixedDiv (num, den);
+
+ if (scale > 64*FRACUNIT)
+ scale = 64*FRACUNIT;
+ else if (scale < 256)
+ scale = 256;
+ }
+ else
+ scale = 64*FRACUNIT;
+
+ return scale;
+}
+
+
+
+//
+// R_InitTables
+//
+void R_InitTables (void)
+{
+ // UNUSED: now getting from tables.c
+#if 0
+ int i;
+ float a;
+ float fv;
+ int t;
+
+ // viewangle tangent table
+ for (i=0 ; i<FINEANGLES/2 ; i++)
+ {
+ a = (i-FINEANGLES/4+0.5)*PI*2/FINEANGLES;
+ fv = FRACUNIT*tan (a);
+ t = fv;
+ finetangent[i] = t;
+ }
+
+ // finesine table
+ for (i=0 ; i<5*FINEANGLES/4 ; i++)
+ {
+ // OPTIMIZE: mirror...
+ a = (i+0.5)*PI*2/FINEANGLES;
+ t = FRACUNIT*sin (a);
+ finesine[i] = t;
+ }
+#endif
+
+}
+
+
+
+//
+// R_InitTextureMapping
+//
+void R_InitTextureMapping (void)
+{
+ int i;
+ int x;
+ int t;
+ fixed_t focallength;
+
+ // Use tangent table to generate viewangletox:
+ // viewangletox will give the next greatest x
+ // after the view angle.
+ //
+ // Calc focallength
+ // so FIELDOFVIEW angles covers SCREENWIDTH.
+ focallength = FixedDiv (centerxfrac,
+ finetangent[FINEANGLES/4+FIELDOFVIEW/2] );
+
+ for (i=0 ; i<FINEANGLES/2 ; i++)
+ {
+ if (finetangent[i] > FRACUNIT*2)
+ t = -1;
+ else if (finetangent[i] < -FRACUNIT*2)
+ t = viewwidth+1;
+ else
+ {
+ t = FixedMul (finetangent[i], focallength);
+ t = (centerxfrac - t+FRACUNIT-1)>>FRACBITS;
+
+ if (t < -1)
+ t = -1;
+ else if (t>viewwidth+1)
+ t = viewwidth+1;
+ }
+ viewangletox[i] = t;
+ }
+
+ // Scan viewangletox[] to generate xtoviewangle[]:
+ // xtoviewangle will give the smallest view angle
+ // that maps to x.
+ for (x=0;x<=viewwidth;x++)
+ {
+ i = 0;
+ while (viewangletox[i]>x)
+ i++;
+ xtoviewangle[x] = (i<<ANGLETOFINESHIFT)-ANG90;
+ }
+
+ // Take out the fencepost cases from viewangletox.
+ for (i=0 ; i<FINEANGLES/2 ; i++)
+ {
+ t = FixedMul (finetangent[i], focallength);
+ t = centerx - t;
+
+ if (viewangletox[i] == -1)
+ viewangletox[i] = 0;
+ else if (viewangletox[i] == viewwidth+1)
+ viewangletox[i] = viewwidth;
+ }
+
+ clipangle = xtoviewangle[0];
+}
+
+
+
+//
+// R_InitLightTables
+// Only inits the zlight table,
+// because the scalelight table changes with view size.
+//
+#define DISTMAP 2
+
+void R_InitLightTables (void)
+{
+ int i;
+ int j;
+ int level;
+ int startmap;
+ int scale;
+
+ // Calculate the light levels to use
+ // for each level / distance combination.
+ for (i=0 ; i< LIGHTLEVELS ; i++)
+ {
+ startmap = ((LIGHTLEVELS-1-i)*2)*NUMCOLORMAPS/LIGHTLEVELS;
+ for (j=0 ; j<MAXLIGHTZ ; j++)
+ {
+ scale = FixedDiv ((SCREENWIDTH/2*FRACUNIT), (j+1)<<LIGHTZSHIFT);
+ scale >>= LIGHTSCALESHIFT;
+ level = startmap - scale/DISTMAP;
+
+ if (level < 0)
+ level = 0;
+
+ if (level >= NUMCOLORMAPS)
+ level = NUMCOLORMAPS-1;
+
+ zlight[i][j] = colormaps + level*256;
+ }
+ }
+}
+
+
+
+//
+// R_SetViewSize
+// Do not really change anything here,
+// because it might be in the middle of a refresh.
+// The change will take effect next refresh.
+//
+boolean setsizeneeded;
+int setblocks;
+int setdetail;
+
+
+void
+R_SetViewSize
+( int blocks,
+ int detail )
+{
+ setsizeneeded = true;
+ setblocks = blocks;
+ setdetail = detail;
+}
+
+
+//
+// R_ExecuteSetViewSize
+//
+void R_ExecuteSetViewSize (void)
+{
+ fixed_t cosadj;
+ fixed_t dy;
+ int i;
+ int j;
+ int level;
+ int startmap;
+
+ setsizeneeded = false;
+
+ if (setblocks == 11)
+ {
+ scaledviewwidth = SCREENWIDTH;
+ viewheight = SCREENHEIGHT;
+ }
+ else
+ {
+ scaledviewwidth = setblocks*32;
+ viewheight = (setblocks*168/10)&~7;
+ }
+
+ detailshift = setdetail;
+ viewwidth = scaledviewwidth>>detailshift;
+
+ // villsa [STRIFE] calculate centery from player's pitch
+ centery = (setblocks*players[consoleplayer].pitch);
+ centery = (unsigned int)(centery/10)+viewheight/2;
+
+ centerx = viewwidth/2;
+ centerxfrac = centerx<<FRACBITS;
+ centeryfrac = centery<<FRACBITS;
+ projection = centerxfrac;
+
+ //if (!detailshift) // villsa [STRIFE]
+ {
+ colfunc = basecolfunc = R_DrawColumn;
+ fuzzcolfunc = R_DrawTLColumn; // villsa [STRIFE]
+ transcolfunc = R_DrawTranslatedColumn;
+ spanfunc = R_DrawSpan;
+ }
+ // villsa [STRIFE] unused detail stuff
+ /*else
+ {
+ colfunc = basecolfunc = R_DrawColumnLow;
+ fuzzcolfunc = R_DrawFuzzColumnLow;
+ transcolfunc = R_DrawTranslatedColumnLow;
+ spanfunc = R_DrawSpanLow;
+ }*/
+
+ R_InitBuffer (scaledviewwidth, viewheight);
+
+ R_InitTextureMapping ();
+
+ // psprite scales
+ pspritescale = FRACUNIT*viewwidth/SCREENWIDTH;
+ pspriteiscale = FRACUNIT*SCREENWIDTH/viewwidth;
+
+ // thing clipping
+ for (i=0 ; i<viewwidth ; i++)
+ screenheightarray[i] = viewheight;
+
+ // planes
+ for (i=0 ; i<viewheight ; i++)
+ {
+ // haleyjd 20120208: [STRIFE] viewheight/2 -> centery, accounts for up/down look
+ dy = ((i - centery)<<FRACBITS) + FRACUNIT/2;
+ dy = abs(dy);
+ yslope[i] = FixedDiv ( (viewwidth<<detailshift)/2*FRACUNIT, dy);
+ }
+
+ for (i=0 ; i<viewwidth ; i++)
+ {
+ cosadj = abs(finecosine[xtoviewangle[i]>>ANGLETOFINESHIFT]);
+ distscale[i] = FixedDiv (FRACUNIT,cosadj);
+ }
+
+ // Calculate the light levels to use
+ // for each level / scale combination.
+ for (i=0 ; i< LIGHTLEVELS ; i++)
+ {
+ startmap = ((LIGHTLEVELS-1-i)*2)*NUMCOLORMAPS/LIGHTLEVELS;
+ for (j=0 ; j<MAXLIGHTSCALE ; j++)
+ {
+ level = startmap - j*SCREENWIDTH/(viewwidth<<detailshift)/DISTMAP;
+
+ if (level < 0)
+ level = 0;
+
+ if (level >= NUMCOLORMAPS)
+ level = NUMCOLORMAPS-1;
+
+ scalelight[i][j] = colormaps + level*256;
+ }
+ }
+}
+
+
+
+//
+// R_Init
+//
+
+
+
+void R_Init (void)
+{
+ R_InitData ();
+ if(devparm)
+ printf (".");
+ else
+ D_IntroTick(); // [STRIFE] tick intro
+
+ R_InitPointToAngle ();
+ if(devparm)
+ printf (".");
+
+ R_InitTables ();
+ // viewwidth / viewheight / detailLevel are set by the defaults
+ if(devparm)
+ printf (".");
+
+ R_SetViewSize (screenblocks, detailLevel);
+ R_InitPlanes ();
+ if(devparm)
+ printf (".");
+
+ R_InitLightTables ();
+ if(devparm)
+ printf (".");
+ else
+ D_IntroTick();
+
+ R_InitSkyMap ();
+ if(!devparm)
+ D_IntroTick();
+
+ R_InitTranslationTables ();
+ if(devparm)
+ printf (".");
+ else
+ D_IntroTick();
+
+ framecount = 0;
+}
+
+
+//
+// R_PointInSubsector
+//
+subsector_t*
+R_PointInSubsector
+( fixed_t x,
+ fixed_t y )
+{
+ node_t* node;
+ int side;
+ int nodenum;
+
+ // single subsector is a special case
+ if (!numnodes)
+ return subsectors;
+
+ nodenum = numnodes-1;
+
+ while (! (nodenum & NF_SUBSECTOR) )
+ {
+ node = &nodes[nodenum];
+ side = R_PointOnSide (x, y, node);
+ nodenum = node->children[side];
+ }
+
+ return &subsectors[nodenum & ~NF_SUBSECTOR];
+}
+
+//
+// R_SetupPitch
+// villsa [STRIFE] new function
+// Calculate centery/centeryfrac for player viewpitch
+//
+
+void R_SetupPitch(player_t* player)
+{
+ int pitchfrac;
+ int i = 0;
+
+ if(viewpitch != player->pitch)
+ {
+ viewpitch = player->pitch;
+ pitchfrac = (setblocks * player->pitch) / 10;
+ centery = pitchfrac + viewheight / 2;
+ centeryfrac = centery << FRACBITS;
+
+ for(i = 0; i < viewheight; i++)
+ {
+ yslope[i] = FixedDiv(viewwidth / 2 * FRACUNIT,
+ abs(((i - centery) << FRACBITS) + (FRACUNIT/2)));
+ }
+ }
+}
+
+
+//
+// R_SetupFrame
+//
+void R_SetupFrame (player_t* player)
+{
+ int i;
+
+ R_SetupPitch(player); // villsa [STRIFE]
+
+ viewplayer = player;
+ viewx = player->mo->x;
+ viewy = player->mo->y;
+ viewangle = player->mo->angle + viewangleoffset;
+ extralight = player->extralight;
+
+ viewz = player->viewz;
+
+ viewsin = finesine[viewangle>>ANGLETOFINESHIFT];
+ viewcos = finecosine[viewangle>>ANGLETOFINESHIFT];
+
+ sscount = 0;
+
+ if (player->fixedcolormap)
+ {
+ fixedcolormap =
+ colormaps
+ + player->fixedcolormap*256*sizeof(lighttable_t);
+
+ walllights = scalelightfixed;
+
+ for (i=0 ; i<MAXLIGHTSCALE ; i++)
+ scalelightfixed[i] = fixedcolormap;
+ }
+ else
+ fixedcolormap = 0;
+
+ framecount++;
+ validcount++;
+}
+
+
+
+//
+// R_RenderView
+//
+void R_RenderPlayerView (player_t* player)
+{
+ R_SetupFrame (player);
+
+ // Clear buffers.
+ R_ClearClipSegs ();
+ R_ClearDrawSegs ();
+ R_ClearPlanes ();
+ R_ClearSprites ();
+
+ // check for new console commands.
+ NetUpdate ();
+
+ // The head node is the last node output.
+ R_RenderBSPNode (numnodes-1);
+
+ // Check for new console commands.
+ NetUpdate ();
+
+ R_DrawPlanes ();
+
+ // Check for new console commands.
+ NetUpdate ();
+
+ R_DrawMasked ();
+
+ // Check for new console commands.
+ NetUpdate ();
+}
diff --git a/src/strife/r_main.h b/src/strife/r_main.h
new file mode 100644
index 00000000..5cb858bb
--- /dev/null
+++ b/src/strife/r_main.h
@@ -0,0 +1,168 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// System specific interface stuff.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __R_MAIN__
+#define __R_MAIN__
+
+#include "d_player.h"
+#include "r_data.h"
+
+
+
+
+//
+// POV related.
+//
+extern fixed_t viewcos;
+extern fixed_t viewsin;
+
+extern int viewwindowx;
+extern int viewwindowy;
+
+
+
+extern int centerx;
+extern int centery;
+
+extern fixed_t centerxfrac;
+extern fixed_t centeryfrac;
+extern fixed_t projection;
+
+extern int validcount;
+
+extern int linecount;
+extern int loopcount;
+
+
+//
+// Lighting LUT.
+// Used for z-depth cuing per column/row,
+// and other lighting effects (sector ambient, flash).
+//
+
+// Lighting constants.
+// Now why not 32 levels here?
+#define LIGHTLEVELS 16
+#define LIGHTSEGSHIFT 4
+
+#define MAXLIGHTSCALE 48
+#define LIGHTSCALESHIFT 12
+#define MAXLIGHTZ 128
+#define LIGHTZSHIFT 20
+
+extern lighttable_t* scalelight[LIGHTLEVELS][MAXLIGHTSCALE];
+extern lighttable_t* scalelightfixed[MAXLIGHTSCALE];
+extern lighttable_t* zlight[LIGHTLEVELS][MAXLIGHTZ];
+
+extern int extralight;
+extern lighttable_t* fixedcolormap;
+
+
+// Number of diminishing brightness levels.
+// There a 0-31, i.e. 32 LUT in the COLORMAP lump.
+#define NUMCOLORMAPS 32
+
+
+// Blocky/low detail mode.
+//B remove this?
+// 0 = high, 1 = low
+extern int detailshift;
+
+
+//
+// Function pointers to switch refresh/drawing functions.
+// Used to select shadow mode etc.
+//
+extern void (*colfunc) (void);
+extern void (*transcolfunc) (void);
+extern void (*basecolfunc) (void);
+extern void (*fuzzcolfunc) (void);
+// No shadow effects on floors.
+extern void (*spanfunc) (void);
+
+
+//
+// Utility functions.
+int
+R_PointOnSide
+( fixed_t x,
+ fixed_t y,
+ node_t* node );
+
+int
+R_PointOnSegSide
+( fixed_t x,
+ fixed_t y,
+ seg_t* line );
+
+angle_t
+R_PointToAngle
+( fixed_t x,
+ fixed_t y );
+
+angle_t
+R_PointToAngle2
+( fixed_t x1,
+ fixed_t y1,
+ fixed_t x2,
+ fixed_t y2 );
+
+fixed_t
+R_PointToDist
+( fixed_t x,
+ fixed_t y );
+
+
+fixed_t R_ScaleFromGlobalAngle (angle_t visangle);
+
+subsector_t*
+R_PointInSubsector
+( fixed_t x,
+ fixed_t y );
+
+void
+R_AddPointToBox
+( int x,
+ int y,
+ fixed_t* box );
+
+
+
+//
+// REFRESH - the actual rendering functions.
+//
+
+// Called by G_Drawer.
+void R_RenderPlayerView (player_t *player);
+
+// Called by startup code.
+void R_Init (void);
+
+// Called by M_Responder.
+void R_SetViewSize (int blocks, int detail);
+
+#endif
diff --git a/src/strife/r_plane.c b/src/strife/r_plane.c
new file mode 100644
index 00000000..fce321f0
--- /dev/null
+++ b/src/strife/r_plane.c
@@ -0,0 +1,455 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Here is a core component: drawing the floors and ceilings,
+// while maintaining a per column clipping list only.
+// Moreover, the sky areas have to be determined.
+//
+//-----------------------------------------------------------------------------
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "i_system.h"
+#include "z_zone.h"
+#include "w_wad.h"
+
+#include "doomdef.h"
+#include "doomstat.h"
+
+#include "r_local.h"
+#include "r_sky.h"
+
+
+
+planefunction_t floorfunc;
+planefunction_t ceilingfunc;
+
+//
+// opening
+//
+
+// Here comes the obnoxious "visplane".
+// haleyjd 08/29/10: [STRIFE] MAXVISPLANES increased to 200
+#define MAXVISPLANES 200
+visplane_t visplanes[MAXVISPLANES];
+visplane_t* lastvisplane;
+visplane_t* floorplane;
+visplane_t* ceilingplane;
+
+// ?
+#define MAXOPENINGS SCREENWIDTH*64
+short openings[MAXOPENINGS];
+short* lastopening;
+
+
+//
+// Clip values are the solid pixel bounding the range.
+// floorclip starts out SCREENHEIGHT
+// ceilingclip starts out -1
+//
+short floorclip[SCREENWIDTH];
+short ceilingclip[SCREENWIDTH];
+
+//
+// spanstart holds the start of a plane span
+// initialized to 0 at start
+//
+int spanstart[SCREENHEIGHT];
+int spanstop[SCREENHEIGHT];
+
+//
+// texture mapping
+//
+lighttable_t** planezlight;
+fixed_t planeheight;
+
+fixed_t yslope[SCREENHEIGHT];
+fixed_t distscale[SCREENWIDTH];
+fixed_t basexscale;
+fixed_t baseyscale;
+
+fixed_t cachedheight[SCREENHEIGHT];
+fixed_t cacheddistance[SCREENHEIGHT];
+fixed_t cachedxstep[SCREENHEIGHT];
+fixed_t cachedystep[SCREENHEIGHT];
+
+
+
+//
+// R_InitPlanes
+// Only at game startup.
+//
+void R_InitPlanes (void)
+{
+ // Doh!
+}
+
+
+//
+// R_MapPlane
+//
+// Uses global vars:
+// planeheight
+// ds_source
+// basexscale
+// baseyscale
+// viewx
+// viewy
+//
+// BASIC PRIMITIVE
+//
+void
+R_MapPlane
+( int y,
+ int x1,
+ int x2 )
+{
+ angle_t angle;
+ fixed_t distance;
+ fixed_t length;
+ unsigned index;
+
+#ifdef RANGECHECK
+ if (x2 < x1
+ || x1 < 0
+ || x2 >= viewwidth
+ || y > viewheight)
+ {
+ I_Error ("R_MapPlane: %i, %i at %i",x1,x2,y);
+ }
+#endif
+
+ if (planeheight != cachedheight[y])
+ {
+ cachedheight[y] = planeheight;
+ distance = cacheddistance[y] = FixedMul (planeheight, yslope[y]);
+ ds_xstep = cachedxstep[y] = FixedMul (distance,basexscale);
+ ds_ystep = cachedystep[y] = FixedMul (distance,baseyscale);
+ }
+ else
+ {
+ distance = cacheddistance[y];
+ ds_xstep = cachedxstep[y];
+ ds_ystep = cachedystep[y];
+ }
+
+ length = FixedMul (distance,distscale[x1]);
+ angle = (viewangle + xtoviewangle[x1])>>ANGLETOFINESHIFT;
+ ds_xfrac = viewx + FixedMul(finecosine[angle], length);
+ ds_yfrac = -viewy - FixedMul(finesine[angle], length);
+
+ if (fixedcolormap)
+ ds_colormap = fixedcolormap;
+ else
+ {
+ index = distance >> LIGHTZSHIFT;
+
+ if (index >= MAXLIGHTZ )
+ index = MAXLIGHTZ-1;
+
+ ds_colormap = planezlight[index];
+ }
+
+ ds_y = y;
+ ds_x1 = x1;
+ ds_x2 = x2;
+
+ // high or low detail
+ spanfunc ();
+}
+
+
+//
+// R_ClearPlanes
+// At begining of frame.
+//
+void R_ClearPlanes (void)
+{
+ int i;
+ angle_t angle;
+
+ // opening / clipping determination
+ for (i=0 ; i<viewwidth ; i++)
+ {
+ floorclip[i] = viewheight;
+ ceilingclip[i] = -1;
+ }
+
+ lastvisplane = visplanes;
+ lastopening = openings;
+
+ // texture calculation
+ memset (cachedheight, 0, sizeof(cachedheight));
+
+ // left to right mapping
+ angle = (viewangle-ANG90)>>ANGLETOFINESHIFT;
+
+ // scale will be unit scale at SCREENWIDTH/2 distance
+ basexscale = FixedDiv (finecosine[angle],centerxfrac);
+ baseyscale = -FixedDiv (finesine[angle],centerxfrac);
+}
+
+
+
+
+//
+// R_FindPlane
+//
+visplane_t*
+R_FindPlane
+( fixed_t height,
+ int picnum,
+ int lightlevel )
+{
+ visplane_t* check;
+
+ if (picnum == skyflatnum)
+ {
+ height = 0; // all skys map together
+ lightlevel = 0;
+ }
+
+ for (check=visplanes; check<lastvisplane; check++)
+ {
+ if (height == check->height
+ && picnum == check->picnum
+ && lightlevel == check->lightlevel)
+ {
+ break;
+ }
+ }
+
+
+ if (check < lastvisplane)
+ return check;
+
+ if (lastvisplane - visplanes == MAXVISPLANES)
+ I_Error ("R_FindPlane: no more visplanes");
+
+ lastvisplane++;
+
+ check->height = height;
+ check->picnum = picnum;
+ check->lightlevel = lightlevel;
+ check->minx = SCREENWIDTH;
+ check->maxx = -1;
+
+ memset (check->top,0xff,sizeof(check->top));
+
+ return check;
+}
+
+
+//
+// R_CheckPlane
+//
+visplane_t*
+R_CheckPlane
+( visplane_t* pl,
+ int start,
+ int stop )
+{
+ int intrl;
+ int intrh;
+ int unionl;
+ int unionh;
+ int x;
+
+ if (start < pl->minx)
+ {
+ intrl = pl->minx;
+ unionl = start;
+ }
+ else
+ {
+ unionl = pl->minx;
+ intrl = start;
+ }
+
+ if (stop > pl->maxx)
+ {
+ intrh = pl->maxx;
+ unionh = stop;
+ }
+ else
+ {
+ unionh = pl->maxx;
+ intrh = stop;
+ }
+
+ for (x=intrl ; x<= intrh ; x++)
+ if (pl->top[x] != 0xff)
+ break;
+
+ if (x > intrh)
+ {
+ pl->minx = unionl;
+ pl->maxx = unionh;
+
+ // use the same one
+ return pl;
+ }
+
+ // make a new visplane
+ lastvisplane->height = pl->height;
+ lastvisplane->picnum = pl->picnum;
+ lastvisplane->lightlevel = pl->lightlevel;
+
+ pl = lastvisplane++;
+ pl->minx = start;
+ pl->maxx = stop;
+
+ memset (pl->top,0xff,sizeof(pl->top));
+
+ return pl;
+}
+
+
+//
+// R_MakeSpans
+//
+void
+R_MakeSpans
+( int x,
+ int t1,
+ int b1,
+ int t2,
+ int b2 )
+{
+ while (t1 < t2 && t1<=b1)
+ {
+ R_MapPlane (t1,spanstart[t1],x-1);
+ t1++;
+ }
+ while (b1 > b2 && b1>=t1)
+ {
+ R_MapPlane (b1,spanstart[b1],x-1);
+ b1--;
+ }
+
+ while (t2 < t1 && t2<=b2)
+ {
+ spanstart[t2] = x;
+ t2++;
+ }
+ while (b2 > b1 && b2>=t2)
+ {
+ spanstart[b2] = x;
+ b2--;
+ }
+}
+
+
+
+//
+// R_DrawPlanes
+// At the end of each frame.
+//
+void R_DrawPlanes (void)
+{
+ visplane_t* pl;
+ int light;
+ int x;
+ int stop;
+ int angle;
+ int lumpnum;
+
+#ifdef RANGECHECK
+ if (ds_p - drawsegs > MAXDRAWSEGS)
+ I_Error ("R_DrawPlanes: drawsegs overflow (%i)",
+ ds_p - drawsegs);
+
+ if (lastvisplane - visplanes > MAXVISPLANES)
+ I_Error ("R_DrawPlanes: visplane overflow (%i)",
+ lastvisplane - visplanes);
+
+ if (lastopening - openings > MAXOPENINGS)
+ I_Error ("R_DrawPlanes: opening overflow (%i)",
+ lastopening - openings);
+#endif
+
+ for (pl = visplanes ; pl < lastvisplane ; pl++)
+ {
+ if (pl->minx > pl->maxx)
+ continue;
+
+
+ // sky flat
+ if (pl->picnum == skyflatnum)
+ {
+ dc_iscale = pspriteiscale>>detailshift;
+
+ // Sky is allways drawn full bright,
+ // i.e. colormaps[0] is used.
+ // Because of this hack, sky is not affected
+ // by INVUL inverse mapping.
+ dc_colormap = colormaps;
+ dc_texturemid = skytexturemid;
+ for (x=pl->minx ; x <= pl->maxx ; x++)
+ {
+ dc_yl = pl->top[x];
+ dc_yh = pl->bottom[x];
+
+ if (dc_yl <= dc_yh)
+ {
+ angle = (viewangle + xtoviewangle[x])>>ANGLETOSKYSHIFT;
+ dc_x = x;
+ dc_source = R_GetColumn(skytexture, angle);
+ colfunc ();
+ }
+ }
+ continue;
+ }
+
+ // regular flat
+ lumpnum = firstflat + flattranslation[pl->picnum];
+ ds_source = W_CacheLumpNum(lumpnum, PU_STATIC);
+
+ planeheight = abs(pl->height-viewz);
+ light = (pl->lightlevel >> LIGHTSEGSHIFT)+extralight;
+
+ if (light >= LIGHTLEVELS)
+ light = LIGHTLEVELS-1;
+
+ if (light < 0)
+ light = 0;
+
+ planezlight = zlight[light];
+
+ pl->top[pl->maxx+1] = 0xff;
+ pl->top[pl->minx-1] = 0xff;
+
+ stop = pl->maxx + 1;
+
+ for (x=pl->minx ; x<= stop ; x++)
+ {
+ R_MakeSpans(x,pl->top[x-1],
+ pl->bottom[x-1],
+ pl->top[x],
+ pl->bottom[x]);
+ }
+
+ W_ReleaseLumpNum(lumpnum);
+ }
+}
diff --git a/src/strife/r_plane.h b/src/strife/r_plane.h
new file mode 100644
index 00000000..2783443d
--- /dev/null
+++ b/src/strife/r_plane.h
@@ -0,0 +1,84 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Refresh, visplane stuff (floor, ceilings).
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __R_PLANE__
+#define __R_PLANE__
+
+
+#include "r_data.h"
+
+
+
+// Visplane related.
+extern short* lastopening;
+
+
+typedef void (*planefunction_t) (int top, int bottom);
+
+extern planefunction_t floorfunc;
+extern planefunction_t ceilingfunc_t;
+
+extern short floorclip[SCREENWIDTH];
+extern short ceilingclip[SCREENWIDTH];
+
+extern fixed_t yslope[SCREENHEIGHT];
+extern fixed_t distscale[SCREENWIDTH];
+
+void R_InitPlanes (void);
+void R_ClearPlanes (void);
+
+void
+R_MapPlane
+( int y,
+ int x1,
+ int x2 );
+
+void
+R_MakeSpans
+( int x,
+ int t1,
+ int b1,
+ int t2,
+ int b2 );
+
+void R_DrawPlanes (void);
+
+visplane_t*
+R_FindPlane
+( fixed_t height,
+ int picnum,
+ int lightlevel );
+
+visplane_t*
+R_CheckPlane
+( visplane_t* pl,
+ int start,
+ int stop );
+
+
+
+#endif
diff --git a/src/strife/r_segs.c b/src/strife/r_segs.c
new file mode 100644
index 00000000..ac7e3743
--- /dev/null
+++ b/src/strife/r_segs.c
@@ -0,0 +1,762 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// All the clipping: columns, horizontal spans, sky columns.
+//
+//-----------------------------------------------------------------------------
+
+
+
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "i_system.h"
+
+#include "doomdef.h"
+#include "doomstat.h"
+
+#include "r_local.h"
+#include "r_sky.h"
+
+
+// OPTIMIZE: closed two sided lines as single sided
+
+// True if any of the segs textures might be visible.
+boolean segtextured;
+
+// False if the back side is the same plane.
+boolean markfloor;
+boolean markceiling;
+
+boolean maskedtexture;
+int toptexture;
+int bottomtexture;
+int midtexture;
+
+
+angle_t rw_normalangle;
+// angle to line origin
+int rw_angle1;
+
+//
+// regular wall
+//
+int rw_x;
+int rw_stopx;
+angle_t rw_centerangle;
+fixed_t rw_offset;
+fixed_t rw_distance;
+fixed_t rw_scale;
+fixed_t rw_scalestep;
+fixed_t rw_midtexturemid;
+fixed_t rw_toptexturemid;
+fixed_t rw_bottomtexturemid;
+
+int worldtop;
+int worldbottom;
+int worldhigh;
+int worldlow;
+
+fixed_t pixhigh;
+fixed_t pixlow;
+fixed_t pixhighstep;
+fixed_t pixlowstep;
+
+fixed_t topfrac;
+fixed_t topstep;
+
+fixed_t bottomfrac;
+fixed_t bottomstep;
+
+
+lighttable_t** walllights;
+
+short* maskedtexturecol;
+
+
+
+//
+// R_RenderMaskedSegRange
+//
+void
+R_RenderMaskedSegRange
+( drawseg_t* ds,
+ int x1,
+ int x2 )
+{
+ unsigned index;
+ column_t* col;
+ int lightnum;
+ int texnum;
+
+ // Calculate light table.
+ // Use different light tables
+ // for horizontal / vertical / diagonal. Diagonal?
+ // OPTIMIZE: get rid of LIGHTSEGSHIFT globally
+ curline = ds->curline;
+ frontsector = curline->frontsector;
+ backsector = curline->backsector;
+ texnum = texturetranslation[curline->sidedef->midtexture];
+
+ lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT)+extralight;
+
+ if (curline->v1->y == curline->v2->y)
+ lightnum--;
+ else if (curline->v1->x == curline->v2->x)
+ lightnum++;
+
+ if (lightnum < 0)
+ walllights = scalelight[0];
+ else if (lightnum >= LIGHTLEVELS)
+ walllights = scalelight[LIGHTLEVELS-1];
+ else
+ walllights = scalelight[lightnum];
+
+ maskedtexturecol = ds->maskedtexturecol;
+
+ rw_scalestep = ds->scalestep;
+ spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
+ mfloorclip = ds->sprbottomclip;
+ mceilingclip = ds->sprtopclip;
+
+ // find positioning
+ if (curline->linedef->flags & ML_DONTPEGBOTTOM)
+ {
+ dc_texturemid = frontsector->floorheight > backsector->floorheight
+ ? frontsector->floorheight : backsector->floorheight;
+ dc_texturemid = dc_texturemid + textureheight[texnum] - viewz;
+ }
+ else
+ {
+ dc_texturemid =frontsector->ceilingheight<backsector->ceilingheight
+ ? frontsector->ceilingheight : backsector->ceilingheight;
+ dc_texturemid = dc_texturemid - viewz;
+ }
+ dc_texturemid += curline->sidedef->rowoffset;
+
+ if (fixedcolormap)
+ dc_colormap = fixedcolormap;
+
+ // villsa [STRIFE] render as transparent (25% or 75%?)
+ if(curline->linedef->flags & ML_TRANSPARENT1)
+ colfunc = fuzzcolfunc;
+
+ // villsa [STRIFE] render as transparent (25% or 75%?)
+ if(curline->linedef->flags & ML_TRANSPARENT2)
+ colfunc = R_DrawMVisTLColumn;
+
+ // draw the columns
+ for (dc_x = x1 ; dc_x <= x2 ; dc_x++)
+ {
+ // calculate lighting
+ if (maskedtexturecol[dc_x] != SHRT_MAX)
+ {
+ if (!fixedcolormap)
+ {
+ index = spryscale>>LIGHTSCALESHIFT;
+
+ if (index >= MAXLIGHTSCALE )
+ index = MAXLIGHTSCALE-1;
+
+ dc_colormap = walllights[index];
+ }
+
+ sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale);
+ dc_iscale = 0xffffffffu / (unsigned)spryscale;
+
+ // draw the texture
+ col = (column_t *)(
+ (byte *)R_GetColumn(texnum,maskedtexturecol[dc_x]) -3);
+
+ // villsa [STRIFE] added 0 argument
+ R_DrawMaskedColumn (col, 0);
+ maskedtexturecol[dc_x] = SHRT_MAX;
+ }
+ spryscale += rw_scalestep;
+ }
+
+ colfunc = basecolfunc; // villsa [STRIFE] reset draw routines
+
+}
+
+
+
+
+//
+// R_RenderSegLoop
+// Draws zero, one, or two textures (and possibly a masked
+// texture) for walls.
+// Can draw or mark the starting pixel of floor and ceiling
+// textures.
+// CALLED: CORE LOOPING ROUTINE.
+//
+#define HEIGHTBITS 12
+#define HEIGHTUNIT (1<<HEIGHTBITS)
+
+void R_RenderSegLoop (void)
+{
+ angle_t angle;
+ unsigned index;
+ int yl;
+ int yh;
+ int mid;
+ fixed_t texturecolumn;
+ int top;
+ int bottom;
+
+ for ( ; rw_x < rw_stopx ; rw_x++)
+ {
+ // mark floor / ceiling areas
+ yl = (topfrac+HEIGHTUNIT-1)>>HEIGHTBITS;
+
+ // no space above wall?
+ if (yl < ceilingclip[rw_x]+1)
+ yl = ceilingclip[rw_x]+1;
+
+ if (markceiling)
+ {
+ top = ceilingclip[rw_x]+1;
+ bottom = yl-1;
+
+ if (bottom >= floorclip[rw_x])
+ bottom = floorclip[rw_x]-1;
+
+ if (top <= bottom)
+ {
+ ceilingplane->top[rw_x] = top;
+ ceilingplane->bottom[rw_x] = bottom;
+ }
+ }
+
+ yh = bottomfrac>>HEIGHTBITS;
+
+ if (yh >= floorclip[rw_x])
+ yh = floorclip[rw_x]-1;
+
+ if (markfloor)
+ {
+ top = yh+1;
+ bottom = floorclip[rw_x]-1;
+ if (top <= ceilingclip[rw_x])
+ top = ceilingclip[rw_x]+1;
+ if (top <= bottom)
+ {
+ floorplane->top[rw_x] = top;
+ floorplane->bottom[rw_x] = bottom;
+ }
+ }
+
+ // texturecolumn and lighting are independent of wall tiers
+ if (segtextured)
+ {
+ // calculate texture offset
+ angle = (rw_centerangle + xtoviewangle[rw_x])>>ANGLETOFINESHIFT;
+ texturecolumn = rw_offset-FixedMul(finetangent[angle],rw_distance);
+ texturecolumn >>= FRACBITS;
+ // calculate lighting
+ index = rw_scale>>LIGHTSCALESHIFT;
+
+ if (index >= MAXLIGHTSCALE )
+ index = MAXLIGHTSCALE-1;
+
+ dc_colormap = walllights[index];
+ dc_x = rw_x;
+ dc_iscale = 0xffffffffu / (unsigned)rw_scale;
+ }
+ else
+ {
+ // purely to shut up the compiler
+
+ texturecolumn = 0;
+ }
+
+ // draw the wall tiers
+ if (midtexture)
+ {
+ // single sided line
+ dc_yl = yl;
+ dc_yh = yh;
+ dc_texturemid = rw_midtexturemid;
+ dc_source = R_GetColumn(midtexture,texturecolumn);
+ colfunc ();
+ ceilingclip[rw_x] = viewheight;
+ floorclip[rw_x] = -1;
+ }
+ else
+ {
+ // two sided line
+ if (toptexture)
+ {
+ // top wall
+ mid = pixhigh>>HEIGHTBITS;
+ pixhigh += pixhighstep;
+
+ if (mid >= floorclip[rw_x])
+ mid = floorclip[rw_x]-1;
+
+ if (mid >= yl)
+ {
+ dc_yl = yl;
+ dc_yh = mid;
+ dc_texturemid = rw_toptexturemid;
+ dc_source = R_GetColumn(toptexture,texturecolumn);
+ colfunc ();
+ ceilingclip[rw_x] = mid;
+ }
+ else
+ ceilingclip[rw_x] = yl-1;
+ }
+ else
+ {
+ // no top wall
+ if (markceiling)
+ ceilingclip[rw_x] = yl-1;
+ }
+
+ if (bottomtexture)
+ {
+ // bottom wall
+ mid = (pixlow+HEIGHTUNIT-1)>>HEIGHTBITS;
+ pixlow += pixlowstep;
+
+ // no space above wall?
+ if (mid <= ceilingclip[rw_x])
+ mid = ceilingclip[rw_x]+1;
+
+ if (mid <= yh)
+ {
+ dc_yl = mid;
+ dc_yh = yh;
+ dc_texturemid = rw_bottomtexturemid;
+ dc_source = R_GetColumn(bottomtexture,
+ texturecolumn);
+ colfunc ();
+ floorclip[rw_x] = mid;
+ }
+ else
+ floorclip[rw_x] = yh+1;
+ }
+ else
+ {
+ // no bottom wall
+ if (markfloor)
+ floorclip[rw_x] = yh+1;
+ }
+
+ if (maskedtexture)
+ {
+ // save texturecol
+ // for backdrawing of masked mid texture
+ maskedtexturecol[rw_x] = texturecolumn;
+ }
+ }
+
+ rw_scale += rw_scalestep;
+ topfrac += topstep;
+ bottomfrac += bottomstep;
+ }
+}
+
+
+
+
+//
+// R_StoreWallRange
+// A wall segment will be drawn
+// between start and stop pixels (inclusive).
+//
+void
+R_StoreWallRange
+( int start,
+ int stop )
+{
+ fixed_t hyp;
+ fixed_t sineval;
+ angle_t distangle, offsetangle;
+ fixed_t vtop;
+ int lightnum;
+
+ // don't overflow and crash
+ if (ds_p == &drawsegs[MAXDRAWSEGS])
+ return;
+
+#ifdef RANGECHECK
+ if (start >=viewwidth || start > stop)
+ I_Error ("Bad R_RenderWallRange: %i to %i", start , stop);
+#endif
+
+ sidedef = curline->sidedef;
+ linedef = curline->linedef;
+
+ // mark the segment as visible for auto map
+ linedef->flags |= ML_MAPPED;
+
+ // calculate rw_distance for scale calculation
+ rw_normalangle = curline->angle + ANG90;
+ offsetangle = abs(rw_normalangle-rw_angle1);
+
+ if (offsetangle > ANG90)
+ offsetangle = ANG90;
+
+ distangle = ANG90 - offsetangle;
+ hyp = R_PointToDist (curline->v1->x, curline->v1->y);
+ sineval = finesine[distangle>>ANGLETOFINESHIFT];
+ rw_distance = FixedMul (hyp, sineval);
+
+
+ ds_p->x1 = rw_x = start;
+ ds_p->x2 = stop;
+ ds_p->curline = curline;
+ rw_stopx = stop+1;
+
+ // calculate scale at both ends and step
+ ds_p->scale1 = rw_scale =
+ R_ScaleFromGlobalAngle (viewangle + xtoviewangle[start]);
+
+ if (stop > start )
+ {
+ ds_p->scale2 = R_ScaleFromGlobalAngle (viewangle + xtoviewangle[stop]);
+ ds_p->scalestep = rw_scalestep =
+ (ds_p->scale2 - rw_scale) / (stop-start);
+ }
+ else
+ {
+ // UNUSED: try to fix the stretched line bug
+#if 0
+ if (rw_distance < FRACUNIT/2)
+ {
+ fixed_t trx,try;
+ fixed_t gxt,gyt;
+
+ trx = curline->v1->x - viewx;
+ try = curline->v1->y - viewy;
+
+ gxt = FixedMul(trx,viewcos);
+ gyt = -FixedMul(try,viewsin);
+ ds_p->scale1 = FixedDiv(projection, gxt-gyt)<<detailshift;
+ }
+#endif
+ ds_p->scale2 = ds_p->scale1;
+ }
+
+ // calculate texture boundaries
+ // and decide if floor / ceiling marks are needed
+ worldtop = frontsector->ceilingheight - viewz;
+ worldbottom = frontsector->floorheight - viewz;
+
+ midtexture = toptexture = bottomtexture = maskedtexture = 0;
+ ds_p->maskedtexturecol = NULL;
+
+ if (!backsector)
+ {
+ // single sided line
+ midtexture = texturetranslation[sidedef->midtexture];
+ // a single sided line is terminal, so it must mark ends
+ markfloor = markceiling = true;
+ if (linedef->flags & ML_DONTPEGBOTTOM)
+ {
+ vtop = frontsector->floorheight +
+ textureheight[sidedef->midtexture];
+ // bottom of texture at bottom
+ rw_midtexturemid = vtop - viewz;
+ }
+ else
+ {
+ // top of texture at top
+ rw_midtexturemid = worldtop;
+ }
+ rw_midtexturemid += sidedef->rowoffset;
+
+ ds_p->silhouette = SIL_BOTH;
+ ds_p->sprtopclip = screenheightarray;
+ ds_p->sprbottomclip = negonearray;
+ ds_p->bsilheight = INT_MAX;
+ ds_p->tsilheight = INT_MIN;
+ }
+ else
+ {
+ // two sided line
+ ds_p->sprtopclip = ds_p->sprbottomclip = NULL;
+ ds_p->silhouette = 0;
+
+ if (frontsector->floorheight > backsector->floorheight)
+ {
+ ds_p->silhouette = SIL_BOTTOM;
+ ds_p->bsilheight = frontsector->floorheight;
+ }
+ else if (backsector->floorheight > viewz)
+ {
+ ds_p->silhouette = SIL_BOTTOM;
+ ds_p->bsilheight = INT_MAX;
+ // ds_p->sprbottomclip = negonearray;
+ }
+
+ if (frontsector->ceilingheight < backsector->ceilingheight)
+ {
+ ds_p->silhouette |= SIL_TOP;
+ ds_p->tsilheight = frontsector->ceilingheight;
+ }
+ else if (backsector->ceilingheight < viewz)
+ {
+ ds_p->silhouette |= SIL_TOP;
+ ds_p->tsilheight = INT_MIN;
+ // ds_p->sprtopclip = screenheightarray;
+ }
+
+ if (backsector->ceilingheight <= frontsector->floorheight)
+ {
+ ds_p->sprbottomclip = negonearray;
+ ds_p->bsilheight = INT_MAX;
+ ds_p->silhouette |= SIL_BOTTOM;
+ }
+
+ if (backsector->floorheight >= frontsector->ceilingheight)
+ {
+ ds_p->sprtopclip = screenheightarray;
+ ds_p->tsilheight = INT_MIN;
+ ds_p->silhouette |= SIL_TOP;
+ }
+
+ worldhigh = backsector->ceilingheight - viewz;
+ worldlow = backsector->floorheight - viewz;
+
+ // hack to allow height changes in outdoor areas
+ if (frontsector->ceilingpic == skyflatnum
+ && backsector->ceilingpic == skyflatnum)
+ {
+ worldtop = worldhigh;
+ }
+
+
+ if (worldlow != worldbottom
+ || backsector->floorpic != frontsector->floorpic
+ || backsector->lightlevel != frontsector->lightlevel)
+ {
+ markfloor = true;
+ }
+ else
+ {
+ // same plane on both sides
+ markfloor = false;
+ }
+
+
+ if (worldhigh != worldtop
+ || backsector->ceilingpic != frontsector->ceilingpic
+ || backsector->lightlevel != frontsector->lightlevel)
+ {
+ markceiling = true;
+ }
+ else
+ {
+ // same plane on both sides
+ markceiling = false;
+ }
+
+ if (backsector->ceilingheight <= frontsector->floorheight
+ || backsector->floorheight >= frontsector->ceilingheight)
+ {
+ // closed door
+ markceiling = markfloor = true;
+ }
+
+
+ if (worldhigh < worldtop)
+ {
+ // top texture
+ toptexture = texturetranslation[sidedef->toptexture];
+ if (linedef->flags & ML_DONTPEGTOP)
+ {
+ // top of texture at top
+ rw_toptexturemid = worldtop;
+ }
+ else
+ {
+ vtop =
+ backsector->ceilingheight
+ + textureheight[sidedef->toptexture];
+
+ // bottom of texture
+ rw_toptexturemid = vtop - viewz;
+ }
+ }
+ if (worldlow > worldbottom)
+ {
+ // bottom texture
+ bottomtexture = texturetranslation[sidedef->bottomtexture];
+
+ if (linedef->flags & ML_DONTPEGBOTTOM )
+ {
+ // bottom of texture at bottom
+ // top of texture at top
+ rw_bottomtexturemid = worldtop;
+ }
+ else // top of texture at top
+ rw_bottomtexturemid = worldlow;
+ }
+ rw_toptexturemid += sidedef->rowoffset;
+ rw_bottomtexturemid += sidedef->rowoffset;
+
+ // allocate space for masked texture tables
+ if (sidedef->midtexture)
+ {
+ // masked midtexture
+ maskedtexture = true;
+ ds_p->maskedtexturecol = maskedtexturecol = lastopening - rw_x;
+ lastopening += rw_stopx - rw_x;
+ }
+ }
+
+ // calculate rw_offset (only needed for textured lines)
+ segtextured = midtexture | toptexture | bottomtexture | maskedtexture;
+
+ if (segtextured)
+ {
+ offsetangle = rw_normalangle-rw_angle1;
+
+ if (offsetangle > ANG180)
+ offsetangle = 0 - offsetangle;
+
+ if (offsetangle > ANG90)
+ offsetangle = ANG90;
+
+ sineval = finesine[offsetangle >>ANGLETOFINESHIFT];
+ rw_offset = FixedMul (hyp, sineval);
+
+ if (rw_normalangle-rw_angle1 < ANG180)
+ rw_offset = -rw_offset;
+
+ rw_offset += sidedef->textureoffset + curline->offset;
+ rw_centerangle = ANG90 + viewangle - rw_normalangle;
+
+ // calculate light table
+ // use different light tables
+ // for horizontal / vertical / diagonal
+ // OPTIMIZE: get rid of LIGHTSEGSHIFT globally
+ if (!fixedcolormap)
+ {
+ lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT)+extralight;
+
+ if (curline->v1->y == curline->v2->y)
+ lightnum--;
+ else if (curline->v1->x == curline->v2->x)
+ lightnum++;
+
+ if (lightnum < 0)
+ walllights = scalelight[0];
+ else if (lightnum >= LIGHTLEVELS)
+ walllights = scalelight[LIGHTLEVELS-1];
+ else
+ walllights = scalelight[lightnum];
+ }
+ }
+
+ // if a floor / ceiling plane is on the wrong side
+ // of the view plane, it is definitely invisible
+ // and doesn't need to be marked.
+
+
+ if (frontsector->floorheight >= viewz)
+ {
+ // above view plane
+ markfloor = false;
+ }
+
+ if (frontsector->ceilingheight <= viewz
+ && frontsector->ceilingpic != skyflatnum)
+ {
+ // below view plane
+ markceiling = false;
+ }
+
+
+ // calculate incremental stepping values for texture edges
+ worldtop >>= 4;
+ worldbottom >>= 4;
+
+ topstep = -FixedMul (rw_scalestep, worldtop);
+ topfrac = (centeryfrac>>4) - FixedMul (worldtop, rw_scale);
+
+ bottomstep = -FixedMul (rw_scalestep,worldbottom);
+ bottomfrac = (centeryfrac>>4) - FixedMul (worldbottom, rw_scale);
+
+ if (backsector)
+ {
+ worldhigh >>= 4;
+ worldlow >>= 4;
+
+ if (worldhigh < worldtop)
+ {
+ pixhigh = (centeryfrac>>4) - FixedMul (worldhigh, rw_scale);
+ pixhighstep = -FixedMul (rw_scalestep,worldhigh);
+ }
+
+ if (worldlow > worldbottom)
+ {
+ pixlow = (centeryfrac>>4) - FixedMul (worldlow, rw_scale);
+ pixlowstep = -FixedMul (rw_scalestep,worldlow);
+ }
+ }
+
+ // render it
+ if (markceiling)
+ ceilingplane = R_CheckPlane (ceilingplane, rw_x, rw_stopx-1);
+
+ if (markfloor)
+ floorplane = R_CheckPlane (floorplane, rw_x, rw_stopx-1);
+
+ R_RenderSegLoop ();
+
+
+ // save sprite clipping info
+ if ( ((ds_p->silhouette & SIL_TOP) || maskedtexture)
+ && !ds_p->sprtopclip)
+ {
+ memcpy (lastopening, ceilingclip+start, 2*(rw_stopx-start));
+ ds_p->sprtopclip = lastopening - start;
+ lastopening += rw_stopx - start;
+ }
+
+ if ( ((ds_p->silhouette & SIL_BOTTOM) || maskedtexture)
+ && !ds_p->sprbottomclip)
+ {
+ memcpy (lastopening, floorclip+start, 2*(rw_stopx-start));
+ ds_p->sprbottomclip = lastopening - start;
+ lastopening += rw_stopx - start;
+ }
+
+ if (maskedtexture && !(ds_p->silhouette&SIL_TOP))
+ {
+ ds_p->silhouette |= SIL_TOP;
+ ds_p->tsilheight = INT_MIN;
+ }
+ if (maskedtexture && !(ds_p->silhouette&SIL_BOTTOM))
+ {
+ ds_p->silhouette |= SIL_BOTTOM;
+ ds_p->bsilheight = INT_MAX;
+ }
+ ds_p++;
+}
+
diff --git a/src/strife/r_segs.h b/src/strife/r_segs.h
new file mode 100644
index 00000000..197859ed
--- /dev/null
+++ b/src/strife/r_segs.h
@@ -0,0 +1,41 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Refresh module, drawing LineSegs from BSP.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __R_SEGS__
+#define __R_SEGS__
+
+
+
+
+void
+R_RenderMaskedSegRange
+( drawseg_t* ds,
+ int x1,
+ int x2 );
+
+
+#endif
diff --git a/setup/m_argv.c b/src/strife/r_sky.c
index ae9ab917..97a80257 100644
--- a/setup/m_argv.c
+++ b/src/strife/r_sky.c
@@ -3,7 +3,6 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005 Simon Howard
-// Copyright(C) 2008 "GhostlyDeath" (ghostlydeath@gmail.com)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -21,45 +20,43 @@
// 02111-1307, USA.
//
// DESCRIPTION:
+// Sky rendering. The DOOM sky is a texture map like any
+// wall, wrapping around. A 1024 columns equal 360 degrees.
+// The default sky map is 256 columns and repeats 4 times
+// on a 320 screen?
+//
//
//-----------------------------------------------------------------------------
-#include <string.h>
+// Needed for FRACUNIT.
+#include "m_fixed.h"
-int myargc;
-char** myargv;
+// Needed for Flat retrieval.
+#include "r_data.h"
-// From doomdef.h -- no need to include it all!
-#ifdef _WIN32
-#define snprintf _snprintf
-#define vsnprintf _vsnprintf
-#define strcasecmp stricmp
-#define strncasecmp strnicmp
-#else
-#include <strings.h>
-#endif
-//
-// 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 ( !strcasecmp(check, myargv[i]) )
- return i;
- }
+#include "r_sky.h"
- return 0;
-}
+//
+// sky mapping
+//
+int skyflatnum;
+int skytexture;
+int skytexturemid;
+//
+// R_InitSkyMap
+// Called whenever the view size changes.
+//
+void R_InitSkyMap (void)
+{
+ // haleyjd 10/03/10: [STRIFE] Sky is set here, not in G_DoLoadLevel.
+ // Also skytexturemid changed from 100 to 199.
+ skyflatnum = R_FlatNumForName ( SKYFLATNAME );
+ skytexturemid = 199*FRACUNIT;
+}
diff --git a/src/strife/r_sky.h b/src/strife/r_sky.h
new file mode 100644
index 00000000..8cff1349
--- /dev/null
+++ b/src/strife/r_sky.h
@@ -0,0 +1,45 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Sky rendering.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __R_SKY__
+#define __R_SKY__
+
+
+
+// SKY, store the number for name.
+#define SKYFLATNAME "F_SKY001" // villsa [STRIFE]
+
+// The sky map is 256*128*4 maps.
+#define ANGLETOSKYSHIFT 22
+
+extern int skytexture;
+extern int skytexturemid;
+
+// Called whenever the view size changes.
+void R_InitSkyMap (void);
+
+#endif
diff --git a/src/strife/r_state.h b/src/strife/r_state.h
new file mode 100644
index 00000000..535753c1
--- /dev/null
+++ b/src/strife/r_state.h
@@ -0,0 +1,135 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Refresh/render internal state variables (global).
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __R_STATE__
+#define __R_STATE__
+
+// Need data structure definitions.
+#include "d_player.h"
+#include "r_data.h"
+
+
+
+
+
+
+//
+// Refresh internal data structures,
+// for rendering.
+//
+
+// needed for texture pegging
+extern fixed_t* textureheight;
+
+// needed for pre rendering (fracs)
+extern fixed_t* spritewidth;
+
+extern fixed_t* spriteoffset;
+extern fixed_t* spritetopoffset;
+
+extern lighttable_t* colormaps;
+
+extern int viewwidth;
+extern int scaledviewwidth;
+extern int viewheight;
+
+extern int firstflat;
+
+// for global animation
+extern int* flattranslation;
+extern int* texturetranslation;
+
+
+// Sprite....
+extern int firstspritelump;
+extern int lastspritelump;
+extern int numspritelumps;
+
+
+
+//
+// Lookup tables for map data.
+//
+extern int numsprites;
+extern spritedef_t* sprites;
+
+extern int numvertexes;
+extern vertex_t* vertexes;
+
+extern int numsegs;
+extern seg_t* segs;
+
+extern int numsectors;
+extern sector_t* sectors;
+
+extern int numsubsectors;
+extern subsector_t* subsectors;
+
+extern int numnodes;
+extern node_t* nodes;
+
+extern int numlines;
+extern line_t* lines;
+
+extern int numsides;
+extern side_t* sides;
+
+
+//
+// POV data.
+//
+extern fixed_t viewx;
+extern fixed_t viewy;
+extern fixed_t viewz;
+
+extern angle_t viewangle;
+extern player_t* viewplayer;
+
+
+// ?
+extern angle_t clipangle;
+
+extern int viewangletox[FINEANGLES/2];
+extern angle_t xtoviewangle[SCREENWIDTH+1];
+//extern fixed_t finetangent[FINEANGLES/2];
+
+extern fixed_t rw_distance;
+extern angle_t rw_normalangle;
+
+
+
+// angle to line origin
+extern int rw_angle1;
+
+// Segs count?
+extern int sscount;
+
+extern visplane_t* floorplane;
+extern visplane_t* ceilingplane;
+
+
+#endif
diff --git a/src/strife/r_things.c b/src/strife/r_things.c
new file mode 100644
index 00000000..f83375e8
--- /dev/null
+++ b/src/strife/r_things.c
@@ -0,0 +1,1065 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Refresh of things, i.e. objects represented by sprites.
+//
+//-----------------------------------------------------------------------------
+
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#include "deh_main.h"
+#include "doomdef.h"
+
+#include "i_swap.h"
+#include "i_system.h"
+#include "z_zone.h"
+#include "w_wad.h"
+
+#include "r_local.h"
+
+#include "doomstat.h"
+
+// haleyjd
+#include "p_local.h"
+
+
+
+#define MINZ (FRACUNIT*4)
+#define BASEYCENTER 100
+
+//void R_DrawColumn (void);
+//void R_DrawFuzzColumn (void);
+
+
+
+typedef struct
+{
+ int x1;
+ int x2;
+
+ int column;
+ int topclip;
+ int bottomclip;
+
+} maskdraw_t;
+
+
+
+//
+// Sprite rotation 0 is facing the viewer,
+// rotation 1 is one angle turn CLOCKWISE around the axis.
+// This is not the same as the angle,
+// which increases counter clockwise (protractor).
+// There was a lot of stuff grabbed wrong, so I changed it...
+//
+fixed_t pspritescale;
+fixed_t pspriteiscale;
+
+lighttable_t** spritelights;
+
+// constant arrays
+// used for psprite clipping and initializing clipping
+short negonearray[SCREENWIDTH];
+short screenheightarray[SCREENWIDTH];
+
+
+//
+// INITIALIZATION FUNCTIONS
+//
+
+// variables used to look up
+// and range check thing_t sprites patches
+spritedef_t* sprites;
+int numsprites;
+
+spriteframe_t sprtemp[29];
+int maxframe;
+char* spritename;
+
+
+
+
+//
+// R_InstallSpriteLump
+// Local function for R_InitSprites.
+//
+void
+R_InstallSpriteLump
+( int lump,
+ unsigned frame,
+ unsigned rotation,
+ boolean flipped )
+{
+ int r;
+
+ if (frame >= 29 || rotation > 8)
+ I_Error("R_InstallSpriteLump: "
+ "Bad frame characters in lump %i", lump);
+
+ if ((int)frame > maxframe)
+ maxframe = frame;
+
+ if (rotation == 0)
+ {
+ // the lump should be used for all rotations
+ if (sprtemp[frame].rotate == false)
+ I_Error ("R_InitSprites: Sprite %s frame %c has "
+ "multip rot=0 lump", spritename, 'A'+frame);
+
+ if (sprtemp[frame].rotate == true)
+ I_Error ("R_InitSprites: Sprite %s frame %c has rotations "
+ "and a rot=0 lump", spritename, 'A'+frame);
+
+ sprtemp[frame].rotate = false;
+ for (r=0 ; r<8 ; r++)
+ {
+ sprtemp[frame].lump[r] = lump - firstspritelump;
+ sprtemp[frame].flip[r] = (byte)flipped;
+ }
+ return;
+ }
+
+ // the lump is only used for one rotation
+ if (sprtemp[frame].rotate == false)
+ I_Error ("R_InitSprites: Sprite %s frame %c has rotations "
+ "and a rot=0 lump", spritename, 'A'+frame);
+
+ sprtemp[frame].rotate = true;
+
+ // make 0 based
+ rotation--;
+ if (sprtemp[frame].lump[rotation] != -1)
+ I_Error ("R_InitSprites: Sprite %s : %c : %c "
+ "has two lumps mapped to it",
+ spritename, 'A'+frame, '1'+rotation);
+
+ sprtemp[frame].lump[rotation] = lump - firstspritelump;
+ sprtemp[frame].flip[rotation] = (byte)flipped;
+}
+
+
+
+
+//
+// R_InitSpriteDefs
+// Pass a null terminated list of sprite names
+// (4 chars exactly) to be used.
+// Builds the sprite rotation matrixes to account
+// for horizontally flipped sprites.
+// Will report an error if the lumps are inconsistant.
+// Only called at startup.
+//
+// Sprite lump names are 4 characters for the actor,
+// a letter for the frame, and a number for the rotation.
+// A sprite that is flippable will have an additional
+// letter/number appended.
+// The rotation character can be 0 to signify no rotations.
+//
+void R_InitSpriteDefs (char** namelist)
+{
+ char** check;
+ int i;
+ int l;
+ int frame;
+ int rotation;
+ int start;
+ int end;
+ int patched;
+
+ // count the number of sprite names
+ check = namelist;
+ while (*check != NULL)
+ check++;
+
+ numsprites = check-namelist;
+
+ if (!numsprites)
+ return;
+
+ sprites = Z_Malloc(numsprites *sizeof(*sprites), PU_STATIC, NULL);
+
+ start = firstspritelump-1;
+ end = lastspritelump+1;
+
+ // scan all the lump names for each of the names,
+ // noting the highest frame letter.
+ // Just compare 4 characters as ints
+ for (i=0 ; i<numsprites ; i++)
+ {
+ spritename = DEH_String(namelist[i]);
+ memset (sprtemp,-1, sizeof(sprtemp));
+
+ maxframe = -1;
+
+ // scan the lumps,
+ // filling in the frames for whatever is found
+ for (l=start+1 ; l<end ; l++)
+ {
+ if (!strncasecmp(lumpinfo[l].name, spritename, 4))
+ {
+ frame = lumpinfo[l].name[4] - 'A';
+ rotation = lumpinfo[l].name[5] - '0';
+
+ if (modifiedgame)
+ patched = W_GetNumForName (lumpinfo[l].name);
+ else
+ patched = l;
+
+ R_InstallSpriteLump (patched, frame, rotation, false);
+
+ if (lumpinfo[l].name[6])
+ {
+ frame = lumpinfo[l].name[6] - 'A';
+ rotation = lumpinfo[l].name[7] - '0';
+ R_InstallSpriteLump (l, frame, rotation, true);
+ }
+ }
+ }
+
+ // check the frames that were found for completeness
+ if (maxframe == -1)
+ {
+ sprites[i].numframes = 0;
+ continue;
+ }
+
+ maxframe++;
+
+ for (frame = 0 ; frame < maxframe ; frame++)
+ {
+ switch ((int)sprtemp[frame].rotate)
+ {
+ case -1:
+ // no rotations were found for that frame at all
+ I_Error ("R_InitSprites: No patches found "
+ "for %s frame %c", spritename, frame+'A');
+ break;
+
+ case 0:
+ // only the first rotation is needed
+ break;
+
+ case 1:
+ // must have all 8 frames
+ for (rotation=0 ; rotation<8 ; rotation++)
+ if (sprtemp[frame].lump[rotation] == -1)
+ I_Error ("R_InitSprites: Sprite %s frame %c "
+ "is missing rotations",
+ spritename, frame+'A');
+ break;
+ }
+ }
+
+ // allocate space for the frames present and copy sprtemp to it
+ sprites[i].numframes = maxframe;
+ sprites[i].spriteframes =
+ Z_Malloc (maxframe * sizeof(spriteframe_t), PU_STATIC, NULL);
+ memcpy (sprites[i].spriteframes, sprtemp, maxframe*sizeof(spriteframe_t));
+ }
+
+}
+
+
+
+
+//
+// GAME FUNCTIONS
+//
+vissprite_t vissprites[MAXVISSPRITES];
+vissprite_t* vissprite_p;
+int newvissprite;
+int sprbotscreen; // villsa [STRIFE]
+
+
+
+//
+// R_InitSprites
+// Called at program start.
+//
+void R_InitSprites (char** namelist)
+{
+ int i;
+
+ for (i=0 ; i<SCREENWIDTH ; i++)
+ {
+ negonearray[i] = -1;
+ }
+
+ R_InitSpriteDefs (namelist);
+}
+
+
+
+//
+// R_ClearSprites
+// Called at frame start.
+//
+void R_ClearSprites (void)
+{
+ vissprite_p = vissprites;
+}
+
+
+//
+// R_NewVisSprite
+//
+vissprite_t overflowsprite;
+
+vissprite_t* R_NewVisSprite (void)
+{
+ if (vissprite_p == &vissprites[MAXVISSPRITES])
+ return &overflowsprite;
+
+ vissprite_p++;
+ return vissprite_p-1;
+}
+
+
+
+//
+// R_DrawMaskedColumn
+// Used for sprites and masked mid textures.
+// Masked means: partly transparent, i.e. stored
+// in posts/runs of opaque pixels.
+//
+short* mfloorclip;
+short* mceilingclip;
+
+fixed_t spryscale;
+fixed_t sprtopscreen;
+
+//
+// R_DrawMaskedColumn
+//
+// villsa [STRIFE] new baseclip argument
+//
+void R_DrawMaskedColumn (column_t *column, int baseclip)
+{
+ int topscreen;
+ int bottomscreen;
+ fixed_t basetexturemid;
+
+ basetexturemid = dc_texturemid;
+
+ for ( ; column->topdelta != 0xff ; )
+ {
+ // calculate unclipped screen coordinates
+ // for post
+ topscreen = sprtopscreen + spryscale*column->topdelta;
+ bottomscreen = topscreen + spryscale*column->length;
+
+ dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS;
+ dc_yh = (bottomscreen-1)>>FRACBITS;
+
+ if (dc_yh >= mfloorclip[dc_x])
+ dc_yh = mfloorclip[dc_x]-1;
+ if (dc_yl <= mceilingclip[dc_x])
+ dc_yl = mceilingclip[dc_x]+1;
+
+ // villsa [STRIFE] checks for clipping
+ if(baseclip)
+ {
+ if(dc_yh > baseclip)
+ dc_yh = baseclip;
+ }
+
+ if (dc_yl <= dc_yh)
+ {
+ dc_source = (byte *)column + 3;
+ dc_texturemid = basetexturemid - (column->topdelta<<FRACBITS);
+ // dc_source = (byte *)column + 3 - column->topdelta;
+
+ // Drawn by either R_DrawColumn
+ // or (SHADOW) R_DrawFuzzColumn.
+ colfunc ();
+ }
+ column = (column_t *)( (byte *)column + column->length + 4);
+ }
+
+ dc_texturemid = basetexturemid;
+}
+
+
+
+//
+// R_DrawVisSprite
+// mfloorclip and mceilingclip should also be set.
+//
+void
+R_DrawVisSprite
+( vissprite_t* vis,
+ int x1,
+ int x2 )
+{
+ column_t* column;
+ int texturecolumn;
+ fixed_t frac;
+ patch_t* patch;
+ int clip; // villsa [STRIFE]
+ int translation; // villsa [STRIFE]
+
+ patch = W_CacheLumpNum (vis->patch+firstspritelump, PU_CACHE);
+
+ dc_colormap = vis->colormap;
+
+ // villsa [STRIFE]
+ // haleyjd 09/06/10: updated MF_TRANSLATION for Strife
+ translation = vis->mobjflags & MF_TRANSLATION;
+
+ // villsa [STRIFE] unused
+ /*if (!dc_colormap)
+ {
+ // NULL colormap = shadow draw
+ colfunc = fuzzcolfunc;
+ }*/
+
+ // villsa [STRIFE] Handle the two types of translucency
+ if(vis->mobjflags & MF_SHADOW)
+ {
+ if(!translation)
+ {
+ if(vis->mobjflags & MF_MVIS)
+ colfunc = R_DrawMVisTLColumn;
+ else
+ colfunc = fuzzcolfunc;
+ }
+ else
+ {
+ colfunc = R_DrawTRTLColumn;
+ dc_translation = translationtables - 256 + (translation >> (MF_TRANSSHIFT - 8));
+ }
+ }
+ else if (translation) // villsa [STRIFE] new translation tables
+ {
+ colfunc = transcolfunc;
+ dc_translation = translationtables - 256 + (translation >> (MF_TRANSSHIFT - 8));
+ }
+
+ dc_iscale = abs(vis->xiscale)>>detailshift;
+ dc_texturemid = vis->texturemid;
+ frac = vis->startfrac;
+ spryscale = vis->scale;
+ sprtopscreen = centeryfrac - FixedMul(dc_texturemid,spryscale);
+
+ // villsa [STRIFE] clip sprite's feet if needed
+ if(vis->mobjflags & MF_FEETCLIPPED)
+ {
+ sprbotscreen = sprtopscreen + FixedMul(spryscale, patch->height << FRACBITS);
+ clip = (sprbotscreen - FixedMul(10*FRACUNIT, spryscale)) >> FRACBITS;
+ }
+ else
+ clip = 0;
+
+ for (dc_x=vis->x1 ; dc_x<=vis->x2 ; dc_x++, frac += vis->xiscale)
+ {
+ texturecolumn = frac>>FRACBITS;
+#ifdef RANGECHECK
+ if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width))
+ I_Error ("R_DrawSpriteRange: bad texturecolumn");
+#endif
+ column = (column_t *) ((byte *)patch +
+ LONG(patch->columnofs[texturecolumn]));
+ R_DrawMaskedColumn (column, clip); // villsa [STRIFE] clip argument
+ }
+
+ colfunc = basecolfunc;
+}
+
+
+
+//
+// R_ProjectSprite
+// Generates a vissprite for a thing
+// if it might be visible.
+//
+void R_ProjectSprite (mobj_t* thing)
+{
+ fixed_t tr_x;
+ fixed_t tr_y;
+
+ fixed_t gxt;
+ fixed_t gyt;
+
+ fixed_t tx;
+ fixed_t tz;
+
+ fixed_t xscale;
+
+ int x1;
+ int x2;
+
+ spritedef_t* sprdef;
+ spriteframe_t* sprframe;
+ int lump;
+
+ unsigned rot;
+ boolean flip;
+
+ int index;
+
+ vissprite_t* vis;
+
+ angle_t ang;
+ fixed_t iscale;
+
+ // transform the origin point
+ tr_x = thing->x - viewx;
+ tr_y = thing->y - viewy;
+
+ gxt = FixedMul(tr_x,viewcos);
+ gyt = -FixedMul(tr_y,viewsin);
+
+ tz = gxt-gyt;
+
+ // thing is behind view plane?
+ if (tz < MINZ)
+ return;
+
+ xscale = FixedDiv(projection, tz);
+
+ gxt = -FixedMul(tr_x,viewsin);
+ gyt = FixedMul(tr_y,viewcos);
+ tx = -(gyt+gxt);
+
+ // too far off the side?
+ if (abs(tx)>(tz<<2))
+ return;
+
+ // decide which patch to use for sprite relative to player
+#ifdef RANGECHECK
+ if ((unsigned int) thing->sprite >= (unsigned int) numsprites)
+ I_Error ("R_ProjectSprite: invalid sprite number %i ",
+ thing->sprite);
+#endif
+ sprdef = &sprites[thing->sprite];
+#ifdef RANGECHECK
+ if ( (thing->frame&FF_FRAMEMASK) >= sprdef->numframes )
+ I_Error ("R_ProjectSprite: invalid sprite frame %i : %i ",
+ thing->sprite, thing->frame);
+#endif
+ sprframe = &sprdef->spriteframes[ thing->frame & FF_FRAMEMASK];
+
+ if (sprframe->rotate)
+ {
+ // choose a different rotation based on player view
+ ang = R_PointToAngle (thing->x, thing->y);
+ rot = (ang-thing->angle+(unsigned)(ANG45/2)*9)>>29;
+ lump = sprframe->lump[rot];
+ flip = (boolean)sprframe->flip[rot];
+ }
+ else
+ {
+ // use single rotation for all views
+ lump = sprframe->lump[0];
+ flip = (boolean)sprframe->flip[0];
+ }
+
+ // calculate edges of the shape
+ tx -= spriteoffset[lump];
+ x1 = (centerxfrac + FixedMul (tx,xscale) ) >>FRACBITS;
+
+ // off the right side?
+ if (x1 > viewwidth)
+ return;
+
+ tx += spritewidth[lump];
+ x2 = ((centerxfrac + FixedMul (tx,xscale) ) >>FRACBITS) - 1;
+
+ // off the left side
+ if (x2 < 0)
+ return;
+
+ // store information in a vissprite
+ vis = R_NewVisSprite ();
+ vis->mobjflags = thing->flags;
+ vis->scale = xscale<<detailshift;
+ vis->gx = thing->x;
+ vis->gy = thing->y;
+ vis->gz = thing->z;
+
+ // villsa [STRIFE]
+ if(thing->flags & MF_FEETCLIPPED)
+ vis->gz -= (10*FRACUNIT);
+
+ // villsa [STRIFE]
+ vis->gzt = vis->gz + spritetopoffset[lump];
+
+ vis->texturemid = vis->gzt - viewz;
+ vis->x1 = x1 < 0 ? 0 : x1;
+ vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2;
+ iscale = FixedDiv (FRACUNIT, xscale);
+
+ if (flip)
+ {
+ vis->startfrac = spritewidth[lump]-1;
+ vis->xiscale = -iscale;
+ }
+ else
+ {
+ vis->startfrac = 0;
+ vis->xiscale = iscale;
+ }
+
+ if (vis->x1 > x1)
+ vis->startfrac += vis->xiscale*(vis->x1-x1);
+ vis->patch = lump;
+
+ // get light level
+ // villsa [STRIFE] unused
+ /*if (thing->flags & MF_SHADOW)
+ {
+ // shadow draw
+ vis->colormap = NULL;
+ }
+ else */if (fixedcolormap)
+ {
+ // fixed map
+ vis->colormap = fixedcolormap;
+ }
+ else if (thing->frame & FF_FULLBRIGHT)
+ {
+ // full bright
+ vis->colormap = colormaps;
+ }
+
+ else
+ {
+ // diminished light
+ index = xscale>>(LIGHTSCALESHIFT-detailshift);
+
+ if (index >= MAXLIGHTSCALE)
+ index = MAXLIGHTSCALE-1;
+
+ vis->colormap = spritelights[index];
+ }
+}
+
+
+
+
+//
+// R_AddSprites
+// During BSP traversal, this adds sprites by sector.
+//
+void R_AddSprites (sector_t* sec)
+{
+ mobj_t* thing;
+ int lightnum;
+
+ // BSP is traversed by subsector.
+ // A sector might have been split into several
+ // subsectors during BSP building.
+ // Thus we check whether its already added.
+ if (sec->validcount == validcount)
+ return;
+
+ // Well, now it will be done.
+ sec->validcount = validcount;
+
+ lightnum = (sec->lightlevel >> LIGHTSEGSHIFT)+extralight;
+
+ if (lightnum < 0)
+ spritelights = scalelight[0];
+ else if (lightnum >= LIGHTLEVELS)
+ spritelights = scalelight[LIGHTLEVELS-1];
+ else
+ spritelights = scalelight[lightnum];
+
+ // Handle all things in sector.
+ for (thing = sec->thinglist ; thing ; thing = thing->snext)
+ R_ProjectSprite (thing);
+}
+
+
+//
+// R_DrawPSprite
+//
+void R_DrawPSprite (pspdef_t* psp)
+{
+ fixed_t tx;
+ int x1;
+ int x2;
+ spritedef_t* sprdef;
+ spriteframe_t* sprframe;
+ int lump;
+ boolean flip;
+ vissprite_t* vis;
+ vissprite_t avis;
+
+ // decide which patch to use
+#ifdef RANGECHECK
+ if ( (unsigned)psp->state->sprite >= (unsigned int) numsprites)
+ I_Error ("R_ProjectSprite: invalid sprite number %i ",
+ psp->state->sprite);
+#endif
+ sprdef = &sprites[psp->state->sprite];
+#ifdef RANGECHECK
+ if ( (psp->state->frame & FF_FRAMEMASK) >= sprdef->numframes)
+ I_Error ("R_ProjectSprite: invalid sprite frame %i : %i ",
+ psp->state->sprite, psp->state->frame);
+#endif
+ sprframe = &sprdef->spriteframes[ psp->state->frame & FF_FRAMEMASK ];
+
+ lump = sprframe->lump[0];
+ // [STRIFE] haleyjd 20110629: -flip replaces this.
+ //flip = (boolean)sprframe->flip[0];
+ flip = flipparm;
+
+ // calculate edges of the shape
+ tx = psp->sx-160*FRACUNIT;
+
+ tx -= spriteoffset[lump];
+ x1 = (centerxfrac + FixedMul (tx,pspritescale) ) >>FRACBITS;
+
+ // off the right side
+ if (x1 > viewwidth)
+ return;
+
+ tx += spritewidth[lump];
+ x2 = ((centerxfrac + FixedMul (tx, pspritescale) ) >>FRACBITS) - 1;
+
+ // off the left side
+ if (x2 < 0)
+ return;
+
+ // store information in a vissprite
+ vis = &avis;
+ vis->mobjflags = 0;
+ vis->x1 = x1 < 0 ? 0 : x1;
+ vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2;
+ vis->scale = pspritescale<<detailshift;
+
+ if (flip)
+ {
+ vis->xiscale = -pspriteiscale;
+ vis->startfrac = spritewidth[lump]-1;
+ }
+ else
+ {
+ vis->xiscale = pspriteiscale;
+ vis->startfrac = 0;
+ }
+
+ // villsa [STRIFE] calculate y offset with view pitch
+ vis->texturemid = ((BASEYCENTER<<FRACBITS)+FRACUNIT/2)-(psp->sy-spritetopoffset[lump])
+ + FixedMul(vis->xiscale, (centery-viewheight/2)<<FRACBITS);
+
+ if (vis->x1 > x1)
+ vis->startfrac += vis->xiscale*(vis->x1-x1);
+
+ vis->patch = lump;
+
+ if (viewplayer->powers[pw_invisibility] > 4*32
+ || (viewplayer->powers[pw_invisibility] & 8))
+ {
+ // shadow draw
+ vis->colormap = spritelights[MAXLIGHTSCALE-1];
+ vis->mobjflags |= MF_SHADOW;
+ }
+ else if(viewplayer->powers[pw_invisibility] & 4)
+ {
+ vis->mobjflags |= (MF_SHADOW|MF_MVIS);
+ }
+
+ // When not MVIS, or if SHADOW, behave normally:
+ if(!(viewplayer->mo->flags & MF_MVIS) || (viewplayer->mo->flags & MF_SHADOW))
+ {
+ if (fixedcolormap)
+ {
+ // fixed color
+ vis->colormap = fixedcolormap;
+ }
+ else if (psp->state->frame & FF_FULLBRIGHT)
+ {
+ // full bright
+ vis->colormap = colormaps;
+ }
+ else
+ {
+ // local light
+ vis->colormap = spritelights[MAXLIGHTSCALE-1];
+ }
+ }
+ else
+ {
+ // When MVIS, use invulnerability colormap
+ vis->colormap = colormaps + INVERSECOLORMAP * 256 * sizeof(lighttable_t);
+ }
+
+ R_DrawVisSprite (vis, vis->x1, vis->x2);
+}
+
+
+
+//
+// R_DrawPlayerSprites
+//
+void R_DrawPlayerSprites (void)
+{
+ int i;
+ int lightnum;
+ pspdef_t* psp;
+
+ // get light level
+ lightnum =
+ (viewplayer->mo->subsector->sector->lightlevel >> LIGHTSEGSHIFT)
+ +extralight;
+
+ if (lightnum < 0)
+ spritelights = scalelight[0];
+ else if (lightnum >= LIGHTLEVELS)
+ spritelights = scalelight[LIGHTLEVELS-1];
+ else
+ spritelights = scalelight[lightnum];
+
+ // clip to screen bounds
+ mfloorclip = screenheightarray;
+ mceilingclip = negonearray;
+
+ // add all active psprites
+ for (i=0, psp=viewplayer->psprites;
+ i<NUMPSPRITES;
+ i++,psp++)
+ {
+ if (psp->state)
+ R_DrawPSprite (psp);
+ }
+}
+
+
+
+
+//
+// R_SortVisSprites
+//
+vissprite_t vsprsortedhead;
+
+
+void R_SortVisSprites (void)
+{
+ int i;
+ int count;
+ vissprite_t* ds;
+ vissprite_t* best;
+ vissprite_t unsorted;
+ fixed_t bestscale;
+
+ count = vissprite_p - vissprites;
+
+ unsorted.next = unsorted.prev = &unsorted;
+
+ if (!count)
+ return;
+
+ for (ds=vissprites ; ds<vissprite_p ; ds++)
+ {
+ ds->next = ds+1;
+ ds->prev = ds-1;
+ }
+
+ vissprites[0].prev = &unsorted;
+ unsorted.next = &vissprites[0];
+ (vissprite_p-1)->next = &unsorted;
+ unsorted.prev = vissprite_p-1;
+
+ // pull the vissprites out by scale
+
+ vsprsortedhead.next = vsprsortedhead.prev = &vsprsortedhead;
+ for (i=0 ; i<count ; i++)
+ {
+ bestscale = INT_MAX;
+ best = unsorted.next;
+ for (ds=unsorted.next ; ds!= &unsorted ; ds=ds->next)
+ {
+ if (ds->scale < bestscale)
+ {
+ bestscale = ds->scale;
+ best = ds;
+ }
+ }
+ best->next->prev = best->prev;
+ best->prev->next = best->next;
+ best->next = &vsprsortedhead;
+ best->prev = vsprsortedhead.prev;
+ vsprsortedhead.prev->next = best;
+ vsprsortedhead.prev = best;
+ }
+}
+
+
+
+//
+// R_DrawSprite
+//
+void R_DrawSprite (vissprite_t* spr)
+{
+ drawseg_t* ds;
+ short clipbot[SCREENWIDTH];
+ short cliptop[SCREENWIDTH];
+ int x;
+ int r1;
+ int r2;
+ fixed_t scale;
+ fixed_t lowscale;
+ int silhouette;
+
+ for (x = spr->x1 ; x<=spr->x2 ; x++)
+ clipbot[x] = cliptop[x] = -2;
+
+ // Scan drawsegs from end to start for obscuring segs.
+ // The first drawseg that has a greater scale
+ // is the clip seg.
+ for (ds=ds_p-1 ; ds >= drawsegs ; ds--)
+ {
+ // determine if the drawseg obscures the sprite
+ if (ds->x1 > spr->x2
+ || ds->x2 < spr->x1
+ || (!ds->silhouette
+ && !ds->maskedtexturecol) )
+ {
+ // does not cover sprite
+ continue;
+ }
+
+ r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1;
+ r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2;
+
+ if (ds->scale1 > ds->scale2)
+ {
+ lowscale = ds->scale2;
+ scale = ds->scale1;
+ }
+ else
+ {
+ lowscale = ds->scale1;
+ scale = ds->scale2;
+ }
+
+ if (scale < spr->scale
+ || ( lowscale < spr->scale
+ && !R_PointOnSegSide (spr->gx, spr->gy, ds->curline) ) )
+ {
+ // masked mid texture?
+ if (ds->maskedtexturecol)
+ R_RenderMaskedSegRange (ds, r1, r2);
+ // seg is behind sprite
+ continue;
+ }
+
+
+ // clip this piece of the sprite
+ silhouette = ds->silhouette;
+
+ if (spr->gz >= ds->bsilheight)
+ silhouette &= ~SIL_BOTTOM;
+
+ if (spr->gzt <= ds->tsilheight)
+ silhouette &= ~SIL_TOP;
+
+ if (silhouette == 1)
+ {
+ // bottom sil
+ for (x=r1 ; x<=r2 ; x++)
+ if (clipbot[x] == -2)
+ clipbot[x] = ds->sprbottomclip[x];
+ }
+ else if (silhouette == 2)
+ {
+ // top sil
+ for (x=r1 ; x<=r2 ; x++)
+ if (cliptop[x] == -2)
+ cliptop[x] = ds->sprtopclip[x];
+ }
+ else if (silhouette == 3)
+ {
+ // both
+ for (x=r1 ; x<=r2 ; x++)
+ {
+ if (clipbot[x] == -2)
+ clipbot[x] = ds->sprbottomclip[x];
+ if (cliptop[x] == -2)
+ cliptop[x] = ds->sprtopclip[x];
+ }
+ }
+
+ }
+
+ // all clipping has been performed, so draw the sprite
+
+ // check for unclipped columns
+ for (x = spr->x1 ; x<=spr->x2 ; x++)
+ {
+ if (clipbot[x] == -2)
+ clipbot[x] = viewheight;
+
+ if (cliptop[x] == -2)
+ cliptop[x] = -1;
+ }
+
+ mfloorclip = clipbot;
+ mceilingclip = cliptop;
+ R_DrawVisSprite (spr, spr->x1, spr->x2);
+}
+
+
+
+
+//
+// R_DrawMasked
+//
+void R_DrawMasked (void)
+{
+ vissprite_t* spr;
+ drawseg_t* ds;
+
+ R_SortVisSprites ();
+
+ if (vissprite_p > vissprites)
+ {
+ // draw all vissprites back to front
+ for (spr = vsprsortedhead.next ;
+ spr != &vsprsortedhead ;
+ spr=spr->next)
+ {
+
+ R_DrawSprite (spr);
+ }
+ }
+
+ // render any remaining masked mid textures
+ for (ds=ds_p-1 ; ds >= drawsegs ; ds--)
+ if (ds->maskedtexturecol)
+ R_RenderMaskedSegRange (ds, ds->x1, ds->x2);
+
+ // draw the psprites on top of everything
+ // but does not draw on side views
+ if (!viewangleoffset)
+ R_DrawPlayerSprites ();
+}
+
+
+
diff --git a/src/strife/r_things.h b/src/strife/r_things.h
new file mode 100644
index 00000000..0e160f01
--- /dev/null
+++ b/src/strife/r_things.h
@@ -0,0 +1,74 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Rendering of moving objects, sprites.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __R_THINGS__
+#define __R_THINGS__
+
+
+
+#define MAXVISSPRITES 128
+
+extern vissprite_t vissprites[MAXVISSPRITES];
+extern vissprite_t* vissprite_p;
+extern vissprite_t vsprsortedhead;
+
+// Constant arrays used for psprite clipping
+// and initializing clipping.
+extern short negonearray[SCREENWIDTH];
+extern short screenheightarray[SCREENWIDTH];
+
+// vars for R_DrawMaskedColumn
+extern short* mfloorclip;
+extern short* mceilingclip;
+extern fixed_t spryscale;
+extern fixed_t sprtopscreen;
+
+extern fixed_t pspritescale;
+extern fixed_t pspriteiscale;
+
+
+// villsa [STIFE] new argument
+void R_DrawMaskedColumn (column_t *column, int baseclip);
+
+
+void R_SortVisSprites (void);
+
+void R_AddSprites (sector_t* sec);
+void R_AddPSprites (void);
+void R_DrawSprites (void);
+void R_InitSprites (char** namelist);
+void R_ClearSprites (void);
+void R_DrawMasked (void);
+
+void
+R_ClipVisSprite
+( vissprite_t* vis,
+ int xl,
+ int xh );
+
+
+#endif
diff --git a/src/strife/s_sound.c b/src/strife/s_sound.c
new file mode 100644
index 00000000..ec59f3a6
--- /dev/null
+++ b/src/strife/s_sound.c
@@ -0,0 +1,828 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION: none
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "i_sound.h"
+#include "i_system.h"
+
+#include "doomfeatures.h"
+#include "deh_str.h"
+
+#include "doomstat.h"
+#include "doomtype.h"
+
+#include "sounds.h"
+#include "s_sound.h"
+
+#include "m_random.h"
+#include "m_argv.h"
+
+#include "p_local.h"
+#include "w_wad.h"
+#include "z_zone.h"
+
+// when to clip out sounds
+// Does not fit the large outdoor areas.
+
+#define S_CLIPPING_DIST (1200 * FRACUNIT)
+
+// Distance tp origin when sounds should be maxed out.
+// This should relate to movement clipping resolution
+// (see BLOCKMAP handling).
+// In the source code release: (160*FRACUNIT). Changed back to the
+// Vanilla value of 200 (why was this changed?)
+
+#define S_CLOSE_DIST (200 * FRACUNIT)
+
+// The range over which sound attenuates
+
+#define S_ATTENUATOR ((S_CLIPPING_DIST - S_CLOSE_DIST) >> FRACBITS)
+
+// Stereo separation
+
+#define S_STEREO_SWING (96 * FRACUNIT)
+
+#define NORM_PITCH 128
+#define NORM_PRIORITY 64
+#define NORM_SEP 128
+
+typedef struct
+{
+ // sound information (if null, channel avail.)
+ sfxinfo_t *sfxinfo;
+
+ // origin of sound
+ mobj_t *origin;
+
+ // handle of the sound being played
+ int handle;
+
+} channel_t;
+
+// The set of channels available
+
+static channel_t *channels;
+
+// Maximum volume of a sound effect.
+// Internal default is max out of 0-15.
+
+int sfxVolume = 8;
+
+// Maximum volume of music.
+
+int musicVolume = 8;
+
+// haleyjd 08/29/10: [STRIFE] New global variable
+// Volume of voice channel.
+
+int voiceVolume = 15;
+
+// Internal volume level, ranging from 0-127
+
+static int snd_SfxVolume;
+
+// haleyjd 09/11/10: [STRIFE] Internal voice volume level
+
+static int snd_VoiceVolume;
+
+// Whether songs are mus_paused
+
+static boolean mus_paused;
+
+// Music currently being played
+
+static musicinfo_t *mus_playing = NULL;
+
+// Number of channels to use
+
+int snd_channels = 8;
+
+// haleyjd 09/11/10: [STRIFE] Handle of current voice channel.
+// This has been implemented at a higher level than it was implemented
+// in strife1.exe, as there it relied on a priority system which was
+// implicit in the SFX_PlayPatch API of DMX. Here we'll just ignore
+// the current voice channel when doing normal sound playing.
+
+static int i_voicehandle = -1;
+
+// haleyjd 09/11/10: [STRIFE] whether to play voices or not
+int disable_voices = 0;
+
+//
+// Initializes sound stuff, including volume
+// Sets channels, SFX and music volume,
+// allocates channel buffer, sets S_sfx lookup.
+//
+// haleyjd 09/11/10: [STRIFE] Added voice volume
+//
+void S_Init(int sfxVolume, int musicVolume, int voiceVolume)
+{
+ int i;
+
+ I_InitSound(true);
+ I_InitMusic();
+
+ I_PrecacheSounds(S_sfx, NUMSFX);
+
+ S_SetSfxVolume(sfxVolume);
+ S_SetMusicVolume(musicVolume);
+ S_SetVoiceVolume(voiceVolume);
+
+ // Allocating the internal channels for mixing
+ // (the maximum numer of sounds rendered
+ // simultaneously) within zone memory.
+ channels = Z_Malloc(snd_channels*sizeof(channel_t), PU_STATIC, 0);
+
+ // Free all channels for use
+ for (i=0 ; i<snd_channels ; i++)
+ {
+ channels[i].sfxinfo = 0;
+ }
+
+ // no sounds are playing, and they are not mus_paused
+ mus_paused = 0;
+
+ // Note that sounds have not been cached (yet).
+ for (i=1 ; i<NUMSFX ; i++)
+ {
+ S_sfx[i].lumpnum = S_sfx[i].usefulness = -1;
+ }
+
+ I_AtExit(S_Shutdown, true);
+}
+
+void S_Shutdown(void)
+{
+ I_ShutdownSound();
+ I_ShutdownMusic();
+}
+
+static void S_StopChannel(int cnum)
+{
+ int i;
+ channel_t *c;
+
+ c = &channels[cnum];
+
+ // haleyjd: [STRIFE] If stopping the voice channel, set i_voicehandle to -1
+ if (cnum == i_voicehandle)
+ i_voicehandle = -1;
+
+ if (c->sfxinfo)
+ {
+ // stop the sound playing
+
+ if (I_SoundIsPlaying(c->handle))
+ {
+ I_StopSound(c->handle);
+ }
+
+ // check to see if other channels are playing the sound
+
+ for (i=0; i<snd_channels; i++)
+ {
+ if (cnum != i && c->sfxinfo == channels[i].sfxinfo)
+ {
+ break;
+ }
+ }
+
+ // degrade usefulness of sound data
+
+ c->sfxinfo->usefulness--;
+ c->sfxinfo = NULL;
+ }
+}
+
+//
+// Per level startup code.
+// Kills playing sounds at start of level,
+// determines music if any, changes music.
+//
+// haleyjd 08/31/10: [STRIFE]
+// * Removed DOOM music handling and replaced with Strife code.
+//
+void S_Start(void)
+{
+ int cnum;
+ int mnum;
+
+ // kill all playing sounds at start of level
+ // (trust me - a good idea)
+ for (cnum=0 ; cnum<snd_channels ; cnum++)
+ {
+ if (channels[cnum].sfxinfo)
+ {
+ S_StopChannel(cnum);
+ }
+ }
+
+ // start new music for the level
+ mus_paused = 0;
+
+ // [STRIFE] Some interesting math here ;)
+ if(gamemap <= 31)
+ mnum = 1;
+ else
+ mnum = -30;
+
+ S_ChangeMusic(gamemap + mnum, true);
+}
+
+void S_StopSound(mobj_t *origin)
+{
+ int cnum;
+
+ for (cnum=0 ; cnum<snd_channels ; cnum++)
+ {
+ // haleyjd: do not stop voice here.
+ if(cnum == i_voicehandle)
+ continue;
+
+ if (channels[cnum].sfxinfo && channels[cnum].origin == origin)
+ {
+ S_StopChannel(cnum);
+ break;
+ }
+ }
+}
+
+//
+// S_GetChannel :
+// If none available, return -1. Otherwise channel #.
+//
+// haleyjd 09/11/10: [STRIFE] Added an "isvoice" parameter for supporting
+// voice playing.
+//
+static int S_GetChannel(mobj_t *origin, sfxinfo_t *sfxinfo, boolean isvoice)
+{
+ // channel number to use
+ int cnum;
+
+ channel_t* c;
+
+ // Find an open channel
+ for (cnum=0 ; cnum<snd_channels ; cnum++)
+ {
+ if (!channels[cnum].sfxinfo)
+ {
+ break;
+ }
+ else if (origin && channels[cnum].origin == origin &&
+ (isvoice || cnum != i_voicehandle)) // haleyjd
+ {
+ S_StopChannel(cnum);
+ break;
+ }
+ }
+
+ // None available
+ if (cnum == snd_channels)
+ {
+ // Look for lower priority
+ for (cnum=0 ; cnum<snd_channels ; cnum++)
+ {
+ if (channels[cnum].sfxinfo->priority >= sfxinfo->priority)
+ {
+ // haleyjd 09/11/10: [STRIFE] voice has absolute priority
+ if (isvoice || cnum != i_voicehandle)
+ break;
+ }
+ }
+
+ if (cnum == snd_channels)
+ {
+ // FUCK! No lower priority. Sorry, Charlie.
+ return -1;
+ }
+ else
+ {
+ // Otherwise, kick out lower priority.
+ S_StopChannel(cnum);
+ }
+ }
+
+ c = &channels[cnum];
+
+ // channel is decided to be cnum.
+ c->sfxinfo = sfxinfo;
+ c->origin = origin;
+
+ return cnum;
+}
+
+//
+// Changes volume and stereo-separation variables
+// from the norm of a sound effect to be played.
+// If the sound is not audible, returns a 0.
+// Otherwise, modifies parameters and returns 1.
+//
+// [STRIFE]
+// haleyjd 20110220: changed to eliminate the gamemap == 8 hack that was
+// left over from Doom 1's original boss levels. Kind of amazing that Rogue
+// was able to catch the smallest things like that.
+//
+static int S_AdjustSoundParams(mobj_t *listener, mobj_t *source,
+ int *vol, int *sep)
+{
+ fixed_t approx_dist;
+ fixed_t adx;
+ fixed_t ady;
+ angle_t angle;
+
+ // calculate the distance to sound origin
+ // and clip it if necessary
+ adx = abs(listener->x - source->x);
+ ady = abs(listener->y - source->y);
+
+ // From _GG1_ p.428. Appox. eucledian distance fast.
+ approx_dist = adx + ady - ((adx < ady ? adx : ady)>>1);
+
+ // [STRIFE] removed gamemap == 8 hack
+ if (approx_dist > S_CLIPPING_DIST)
+ {
+ return 0;
+ }
+
+ // angle of source to listener
+ angle = R_PointToAngle2(listener->x,
+ listener->y,
+ source->x,
+ source->y);
+
+ if (angle > listener->angle)
+ {
+ angle = angle - listener->angle;
+ }
+ else
+ {
+ angle = angle + (0xffffffff - listener->angle);
+ }
+
+ angle >>= ANGLETOFINESHIFT;
+
+ // stereo separation
+ *sep = 128 - (FixedMul(S_STEREO_SWING, finesine[angle]) >> FRACBITS);
+
+ // volume calculation
+ // [STRIFE] Removed gamemap == 8 hack
+ if (approx_dist < S_CLOSE_DIST)
+ {
+ *vol = snd_SfxVolume;
+ }
+ else
+ {
+ // distance effect
+ *vol = (snd_SfxVolume
+ * ((S_CLIPPING_DIST - approx_dist)>>FRACBITS))
+ / S_ATTENUATOR;
+ }
+
+ return (*vol > 0);
+}
+
+void S_StartSound(void *origin_p, int sfx_id)
+{
+ sfxinfo_t *sfx;
+ mobj_t *origin;
+ int rc;
+ int sep;
+ int cnum;
+ int volume;
+
+ origin = (mobj_t *) origin_p;
+ volume = snd_SfxVolume;
+
+ // check for bogus sound #
+ if (sfx_id < 1 || sfx_id > NUMSFX)
+ {
+ // [STRIFE]: BUG - Note: vanilla had some extremely buggy and dangerous
+ // code here that tried to print the sprite name of the object playing
+ // the bad sound. Because it invokes multiple undefined behaviors and
+ // is of basically no consequence, it has deliberately not been ported.
+ I_Error("Bad sfx #: %d", sfx_id);
+ }
+
+ sfx = &S_sfx[sfx_id];
+
+ // Initialize sound parameters
+ if (sfx->link)
+ {
+ volume += sfx->volume;
+
+ if (volume < 1)
+ {
+ return;
+ }
+
+ if (volume > snd_SfxVolume)
+ {
+ volume = snd_SfxVolume;
+ }
+ }
+
+
+ // Check to see if it is audible,
+ // and if not, modify the params
+ if (origin && origin != players[consoleplayer].mo)
+ {
+ rc = S_AdjustSoundParams(players[consoleplayer].mo,
+ origin,
+ &volume,
+ &sep);
+
+ if (origin->x == players[consoleplayer].mo->x
+ && origin->y == players[consoleplayer].mo->y)
+ {
+ sep = NORM_SEP;
+ }
+
+ if (!rc)
+ {
+ return;
+ }
+ }
+ else
+ {
+ sep = NORM_SEP;
+ }
+
+ // kill old sound [STRIFE] - nope!
+ //S_StopSound(origin);
+
+ // try to find a channel
+ cnum = S_GetChannel(origin, sfx, false); // haleyjd: not a voice.
+
+ if (cnum < 0)
+ {
+ return;
+ }
+
+ // increase the usefulness
+ if (sfx->usefulness++ < 0)
+ {
+ sfx->usefulness = 1;
+ }
+
+ if (sfx->lumpnum < 0)
+ {
+ sfx->lumpnum = I_GetSfxLumpNum(sfx);
+ }
+
+ channels[cnum].handle = I_StartSound(sfx, cnum, volume, sep);
+}
+
+
+// haleyjd 09/11/10: [STRIFE]
+// None of this was necessary in the vanilla EXE but Choco's low-level code
+// won't play nice with a temporary sfxinfo because it insists that the
+// "driver_data" member remain valid from the last time the sound was used,
+// even if it has already stopped playing. Thanks to this cuteness I get
+// to maintain a dynamic cache of sfxinfo objects!
+
+typedef struct voiceinfo_s
+{
+ sfxinfo_t sfx;
+ struct voiceinfo_s *next; // next on hash chain
+} voiceinfo_t;
+
+#define NUMVOICECHAINS 257
+
+//
+// Ripped from Eternity.
+//
+static unsigned int S_voiceHash(const char *str)
+{
+ const char *c = str;
+ unsigned int h = 0;
+
+ if(!str)
+ I_Error("S_voiceHash: cannot hash NULL string!\n");
+
+ // note: this needs to be case insensitive for lump names
+ while(*c)
+ {
+ h = 5 * h + toupper(*c);
+ ++c;
+ }
+
+ return h;
+}
+
+static voiceinfo_t *voices[NUMVOICECHAINS];
+
+//
+// S_getVoice
+//
+// Gets an entry from the voice table, if it exists. If it does not, one will be
+// created.
+//
+static voiceinfo_t *S_getVoice(const char *name, int lumpnum)
+{
+ voiceinfo_t *voice;
+ unsigned int hashkey = S_voiceHash(name) % NUMVOICECHAINS;
+
+ voice = voices[hashkey];
+
+ while(voice && strcasecmp(voice->sfx.name, name))
+ voice = voice->next;
+
+ if(!voice)
+ {
+ voice = calloc(1, sizeof(voiceinfo_t));
+
+ strncpy(voice->sfx.name, name, 8);
+ voice->sfx.priority = INT_MIN; // make highest possible priority
+ voice->sfx.pitch = -1;
+ voice->sfx.volume = -1;
+ voice->sfx.numchannels = -1;
+ voice->sfx.usefulness = -1;
+ voice->sfx.lumpnum = lumpnum;
+
+ // throw it onto the table.
+ voice->next = voices[hashkey];
+ voices[hashkey] = voice;
+ }
+
+ return voice;
+}
+
+//
+// I_StartVoice
+//
+// haleyjd 09/11/10: [STRIFE] New function
+// Note this was in i_sound.c in Strife itself, but relied on DMX-specific
+// features to ensure voice channels had absolute priority. Here we must
+// populate a fake sfxinfo_t and send the sound through some of the normal
+// routines. But in the end, it still works the same.
+//
+void I_StartVoice(const char *lumpname)
+{
+ int lumpnum;
+ voiceinfo_t *voice; // choco-specific
+ char lumpnamedup[9];
+
+ // no voices in deathmatch mode.
+ if(netgame)
+ return;
+
+ // STRIFE-TODO: checks if snd_SfxDevice == 83
+ // This is probably turning off voice if using PC speaker...
+
+ // user has disabled voices?
+ if(disable_voices)
+ return;
+
+ // have a voice playing already? stop it.
+ if(i_voicehandle >= 0)
+ S_StopChannel(i_voicehandle);
+
+ // Vanilla STRIFE appears to have stopped any current voice without
+ // starting a new one if NULL was passed in here, though I cannot
+ // find an explicit check for NULL in the assembly. Either way, it
+ // didn't crash, so do a check now:
+ if(lumpname == NULL)
+ return;
+
+ // Because of constness problems...
+ strncpy(lumpnamedup, lumpname, 9);
+ lumpnamedup[8] = '\0';
+
+ if((lumpnum = W_CheckNumForName(lumpnamedup)) != -1)
+ {
+ // haleyjd: Choco-specific: get a voice structure
+ voice = S_getVoice(lumpnamedup, lumpnum);
+
+ // get a channel for the voice
+ i_voicehandle = S_GetChannel(NULL, &voice->sfx, true);
+
+ channels[i_voicehandle].handle
+ = I_StartSound(&voice->sfx, i_voicehandle, snd_VoiceVolume, NORM_SEP);
+ }
+}
+
+//
+// Stop and resume music, during game PAUSE.
+//
+
+void S_PauseSound(void)
+{
+ if (mus_playing && !mus_paused)
+ {
+ I_PauseSong();
+ mus_paused = true;
+ }
+}
+
+void S_ResumeSound(void)
+{
+ if (mus_playing && mus_paused)
+ {
+ I_ResumeSong();
+ mus_paused = false;
+ }
+}
+
+//
+// Updates music & sounds
+//
+
+void S_UpdateSounds(mobj_t *listener)
+{
+ int audible;
+ int cnum;
+ int volume;
+ int sep;
+ sfxinfo_t* sfx;
+ channel_t* c;
+
+ I_UpdateSound();
+
+ for (cnum=0; cnum<snd_channels; cnum++)
+ {
+ c = &channels[cnum];
+ sfx = c->sfxinfo;
+
+ if (c->sfxinfo)
+ {
+ if (I_SoundIsPlaying(c->handle))
+ {
+ // initialize parameters
+ volume = snd_SfxVolume;
+ sep = NORM_SEP;
+
+ if (sfx->link)
+ {
+ volume += sfx->volume;
+ if (volume < 1)
+ {
+ S_StopChannel(cnum);
+ continue;
+ }
+ else if (volume > snd_SfxVolume)
+ {
+ volume = snd_SfxVolume;
+ }
+ }
+
+ // check non-local sounds for distance clipping
+ // or modify their params
+ if (c->origin && listener != c->origin)
+ {
+ audible = S_AdjustSoundParams(listener,
+ c->origin,
+ &volume,
+ &sep);
+
+ if (!audible)
+ {
+ S_StopChannel(cnum);
+ }
+ else
+ {
+ I_UpdateSoundParams(c->handle, volume, sep);
+ }
+ }
+ }
+ else
+ {
+ // if channel is allocated but sound has stopped,
+ // free it
+ S_StopChannel(cnum);
+ }
+ }
+ }
+}
+
+void S_SetMusicVolume(int volume)
+{
+ if (volume < 0 || volume > 127)
+ {
+ I_Error("Attempt to set music volume at %d",
+ volume);
+ }
+
+ I_SetMusicVolume(volume);
+}
+
+void S_SetSfxVolume(int volume)
+{
+ if (volume < 0 || volume > 127)
+ {
+ I_Error("Attempt to set sfx volume at %d", volume);
+ }
+
+ snd_SfxVolume = volume;
+}
+
+//
+// S_SetVoiceVolume
+//
+// haleyjd 09/11/10: [STRIFE]
+// Set the internal voice volume level.
+//
+void S_SetVoiceVolume(int volume)
+{
+ if (volume < 0 || volume > 127)
+ {
+ I_Error("Attempt to set voice volume at %d", volume);
+ }
+
+ snd_VoiceVolume = volume;
+}
+
+//
+// Starts some music with the music id found in sounds.h.
+//
+
+void S_StartMusic(int m_id)
+{
+ S_ChangeMusic(m_id, false);
+}
+
+void S_ChangeMusic(int musicnum, int looping)
+{
+ musicinfo_t *music = NULL;
+ char namebuf[9];
+ void *handle;
+
+ if (musicnum <= mus_None || musicnum >= NUMMUSIC)
+ {
+ I_Error("Bad music number %d", musicnum);
+ }
+ else
+ {
+ music = &S_music[musicnum];
+ }
+
+ if (mus_playing == music)
+ {
+ return;
+ }
+
+ // shutdown old music
+ S_StopMusic();
+
+ // get lumpnum if neccessary
+ if (!music->lumpnum)
+ {
+ sprintf(namebuf, "d_%s", DEH_String(music->name));
+ music->lumpnum = W_GetNumForName(namebuf);
+ }
+
+ music->data = W_CacheLumpNum(music->lumpnum, PU_STATIC);
+
+ handle = I_RegisterSong(music->data, W_LumpLength(music->lumpnum));
+ music->handle = handle;
+ I_PlaySong(handle, looping);
+
+ mus_playing = music;
+}
+
+boolean S_MusicPlaying(void)
+{
+ return I_MusicIsPlaying();
+}
+
+void S_StopMusic(void)
+{
+ if (mus_playing)
+ {
+ if (mus_paused)
+ {
+ I_ResumeSong();
+ }
+
+ I_StopSong();
+ I_UnRegisterSong(mus_playing->handle);
+ W_ReleaseLumpNum(mus_playing->lumpnum);
+ mus_playing->data = NULL;
+ mus_playing = NULL;
+ }
+}
+
diff --git a/src/strife/s_sound.h b/src/strife/s_sound.h
new file mode 100644
index 00000000..5e763014
--- /dev/null
+++ b/src/strife/s_sound.h
@@ -0,0 +1,103 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// The not so system specific sound interface.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __S_SOUND__
+#define __S_SOUND__
+
+#include "p_mobj.h"
+#include "sounds.h"
+
+//
+// Initializes sound stuff, including volume
+// Sets channels, SFX and music volume,
+// allocates channel buffer, sets S_sfx lookup.
+//
+
+void S_Init(int sfxVolume, int musicVolume, int voiceVolume);
+
+
+// Shut down sound
+
+void S_Shutdown(void);
+
+
+
+//
+// Per level startup code.
+// Kills playing sounds at start of level,
+// determines music if any, changes music.
+//
+
+void S_Start(void);
+
+//
+// Start sound for thing at <origin>
+// using <sound_id> from sounds.h
+//
+
+void S_StartSound(void *origin, int sound_id);
+
+// haleyjd 09/11/10: [STRIFE] Start a voice.
+void I_StartVoice(const char *lumpname);
+
+// Stop sound for thing at <origin>
+void S_StopSound(mobj_t *origin);
+
+
+// Start music using <music_id> from sounds.h
+void S_StartMusic(int music_id);
+
+// Start music using <music_id> from sounds.h,
+// and set whether looping
+void S_ChangeMusic(int music_id, int looping);
+
+// query if music is playing
+boolean S_MusicPlaying(void);
+
+// Stops the music fer sure.
+void S_StopMusic(void);
+
+// Stop and resume music, during game PAUSE.
+void S_PauseSound(void);
+void S_ResumeSound(void);
+
+
+//
+// Updates music & sounds
+//
+void S_UpdateSounds(mobj_t *listener);
+
+void S_SetMusicVolume(int volume);
+void S_SetSfxVolume(int volume);
+void S_SetVoiceVolume(int volume); // haleyjd 09/11/10: [STRIFE]
+
+extern int snd_channels;
+
+extern int disable_voices;
+
+#endif
+
diff --git a/src/strife/sounds.c b/src/strife/sounds.c
new file mode 100644
index 00000000..c87dd6d4
--- /dev/null
+++ b/src/strife/sounds.c
@@ -0,0 +1,235 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Created by a sound utility.
+// Kept as a sample, DOOM2 sounds.
+//
+//-----------------------------------------------------------------------------
+
+
+#include <stdlib.h>
+
+
+#include "doomtype.h"
+#include "sounds.h"
+
+//
+// Information about all the music
+//
+
+#define MUSIC(name) \
+ { name, 0, NULL, NULL }
+
+// villsa [STRIFE]
+musicinfo_t S_music[] =
+{
+ MUSIC(NULL),
+ MUSIC("logo"),
+ MUSIC("action"),
+ MUSIC("tavern"),
+ MUSIC("danger"),
+ MUSIC("fast"),
+ MUSIC("intro"),
+ MUSIC("darker"),
+ MUSIC("strike"),
+ MUSIC("slide"),
+ MUSIC("tribal"),
+ MUSIC("march"),
+ MUSIC("danger"),
+ MUSIC("mood"),
+ MUSIC("castle"),
+ MUSIC("darker"),
+ MUSIC("action"),
+ MUSIC("fight"),
+ MUSIC("spense"),
+ MUSIC("slide"),
+ MUSIC("strike"),
+ MUSIC("dark"),
+ MUSIC("tech"),
+ MUSIC("slide"),
+ MUSIC("drone"),
+ MUSIC("panthr"),
+ MUSIC("sad"),
+ MUSIC("instry"),
+ MUSIC("tech"),
+ MUSIC("action"),
+ MUSIC("instry"),
+ MUSIC("drone"),
+ MUSIC("fight"),
+ MUSIC("happy"),
+ MUSIC("end")
+
+
+};
+
+
+//
+// Information about all the sfx
+//
+
+#define SOUND(name, priority) \
+ { NULL, name, priority, NULL, -1, -1, 0, 0, -1, NULL }
+#define SOUND_LINK(name, priority, link_id, pitch, volume) \
+ { NULL, name, priority, &S_sfx[link_id], pitch, volume, 0, 0, -1, NULL }
+
+// villsa [STRIFE]
+sfxinfo_t S_sfx[] =
+{
+ // S_sfx[0] needs to be a dummy for odd reasons.
+ SOUND("none", 0),
+ SOUND("swish", 64),
+ SOUND("meatht", 64),
+ SOUND("mtalht", 64),
+ SOUND("wpnup", 78),
+ SOUND("rifle", 64),
+ SOUND("mislht", 64),
+ SOUND("barexp", 32),
+ SOUND("flburn", 64),
+ SOUND("flidl", 118),
+ SOUND("agrsee", 98),
+ SOUND("plpain", 96),
+ SOUND("pcrush", 96),
+ SOUND("pespna", 98),
+ SOUND("pespnb", 98),
+ SOUND("pespnc", 98),
+ SOUND("pespnd", 98),
+ SOUND("agrdpn", 98),
+ SOUND("pldeth", 32),
+ SOUND("plxdth", 32),
+ SOUND("slop", 78),
+ SOUND("rebdth", 98),
+ SOUND("agrdth", 98),
+ SOUND("lgfire", 211),
+ SOUND("smfire", 211),
+ SOUND("alarm", 210),
+ SOUND("drlmto", 98),
+ SOUND("drlmtc", 98),
+ SOUND("drsmto", 98),
+ SOUND("drsmtc", 98),
+ SOUND("drlwud", 98),
+ SOUND("drswud", 98),
+ SOUND("drston", 98),
+ SOUND("bdopn", 98),
+ SOUND("bdcls", 98),
+ SOUND("swtchn", 78),
+ SOUND("swbolt", 98),
+ SOUND("swscan", 98),
+ SOUND("yeah", 10),
+ SOUND("mask", 210),
+ SOUND("pstart", 100),
+ SOUND("pstop", 100),
+ SOUND("itemup", 78),
+ SOUND("bglass", 200),
+ SOUND("wriver", 201),
+ SOUND("wfall", 201),
+ SOUND("wdrip", 201),
+ SOUND("wsplsh", 95),
+ SOUND("rebact", 200),
+ SOUND("agrac1", 98),
+ SOUND("agrac2", 98),
+ SOUND("agrac3", 98),
+ SOUND("agrac4", 98),
+ SOUND("ambppl", 218),
+ SOUND("ambbar", 218),
+ SOUND("telept", 32),
+ SOUND("ratact", 99),
+ SOUND("itmbk", 100),
+ SOUND("xbow", 99),
+ SOUND("burnme", 95),
+ SOUND("oof", 96),
+ SOUND("wbrldt", 98),
+ SOUND("psdtha", 109),
+ SOUND("psdthb", 109),
+ SOUND("psdthc", 109),
+ SOUND("rb2pn", 96),
+ SOUND("rb2dth", 32),
+ SOUND("rb2see", 98),
+ SOUND("rb2act", 98),
+ SOUND("firxpl", 70),
+ SOUND("stnmov", 100),
+ SOUND("noway", 78),
+ SOUND("rlaunc", 64),
+ SOUND("rflite", 65),
+ SOUND("radio", 60),
+ SOUND("pulchn", 98),
+ SOUND("swknob", 98),
+ SOUND("keycrd", 98),
+ SOUND("swston", 98),
+ SOUND("sntsee", 98),
+ SOUND("sntdth", 98),
+ SOUND("sntact", 98),
+ SOUND("pgrdat", 64),
+ SOUND("pgrsee", 90),
+ SOUND("pgrdpn", 96),
+ SOUND("pgrdth", 32),
+ SOUND("pgract", 120),
+ SOUND("proton", 64),
+ SOUND("protfl", 64),
+ SOUND("plasma", 64),
+ SOUND("dsrptr", 30),
+ SOUND("reavat", 64),
+ SOUND("revbld", 64),
+ SOUND("revsee", 90),
+ SOUND("reavpn", 96),
+ SOUND("revdth", 32),
+ SOUND("revact", 120),
+ SOUND("spisit", 90),
+ SOUND("spdwlk", 65),
+ SOUND("spidth", 32),
+ SOUND("spdatk", 32),
+ SOUND("chant", 218),
+ SOUND("static", 32),
+ SOUND("chain", 70),
+ SOUND("tend", 100),
+ SOUND("phoot", 32),
+ SOUND("explod", 32),
+ SOUND("sigil", 32),
+ SOUND("sglhit", 32),
+ SOUND("siglup", 32),
+ SOUND("prgpn", 96),
+ SOUND("progac", 120),
+ SOUND("lorpn", 96),
+ SOUND("lorsee", 90),
+ SOUND("difool", 32),
+ SOUND("inqdth", 32),
+ SOUND("inqact", 98),
+ SOUND("inqsee", 90),
+ SOUND("inqjmp", 65),
+ SOUND("amaln1", 99),
+ SOUND("amaln2", 99),
+ SOUND("amaln3", 99),
+ SOUND("amaln4", 99),
+ SOUND("amaln5", 99),
+ SOUND("amaln6", 99),
+ SOUND("mnalse", 64),
+ SOUND("alnsee", 64),
+ SOUND("alnpn", 96),
+ SOUND("alnact", 120),
+ SOUND("alndth", 32),
+ SOUND("mnaldt", 32),
+ SOUND("reactr", 31),
+ SOUND("airlck", 98),
+ SOUND("drchno", 98),
+ SOUND("drchnc", 98),
+ SOUND("valve", 98)
+};
+
diff --git a/src/strife/sounds.h b/src/strife/sounds.h
new file mode 100644
index 00000000..4236a5da
--- /dev/null
+++ b/src/strife/sounds.h
@@ -0,0 +1,230 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Created by the sound utility written by Dave Taylor.
+// Kept as a sample, DOOM2 sounds. Frozen.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef __SOUNDS__
+#define __SOUNDS__
+
+#include "i_sound.h"
+
+// the complete set of sound effects
+extern sfxinfo_t S_sfx[];
+
+// the complete set of music
+extern musicinfo_t S_music[];
+
+//
+// Identifiers for all music in game.
+//
+
+// villsa [STRIFE]
+typedef enum
+{
+ mus_None,
+ mus_logo,
+ mus_action,
+ mus_tavern,
+ mus_danger,
+ mus_fast,
+ mus_intro,
+ mus_darker,
+ mus_strike,
+ mus_slide,
+ mus_tribal,
+ mus_march,
+ mus_danger2,
+ mus_mood,
+ mus_castle,
+ mus_darker2,
+ mus_action2,
+ mus_fight,
+ mus_spense,
+ mus_slide2,
+ mus_strike2,
+ mus_dark,
+ mus_tech,
+ mus_slide3,
+ mus_drone,
+ mus_panthr,
+ mus_sad,
+ mus_instry,
+ mus_tech2,
+ mus_action3,
+ mus_instry2,
+ mus_drone2,
+ mus_fight2,
+ mus_happy,
+ mus_end,
+ NUMMUSIC
+} musicenum_t;
+
+
+//
+// Identifiers for all sfx in game.
+//
+
+typedef enum
+{
+ sfx_None,
+ sfx_swish,
+ sfx_meatht,
+ sfx_mtalht,
+ sfx_wpnup,
+ sfx_rifle,
+ sfx_mislht,
+ sfx_barexp,
+ sfx_flburn,
+ sfx_flidl,
+ sfx_agrsee,
+ sfx_plpain,
+ sfx_pcrush,
+ sfx_pespna,
+ sfx_pespnb,
+ sfx_pespnc,
+ sfx_pespnd,
+ sfx_agrdpn,
+ sfx_pldeth,
+ sfx_plxdth,
+ sfx_slop,
+ sfx_rebdth,
+ sfx_agrdth,
+ sfx_lgfire,
+ sfx_smfire,
+ sfx_alarm,
+ sfx_drlmto,
+ sfx_drlmtc,
+ sfx_drsmto,
+ sfx_drsmtc,
+ sfx_drlwud,
+ sfx_drswud,
+ sfx_drston,
+ sfx_bdopn,
+ sfx_bdcls,
+ sfx_swtchn,
+ sfx_swbolt,
+ sfx_swscan,
+ sfx_yeah,
+ sfx_mask,
+ sfx_pstart,
+ sfx_pstop,
+ sfx_itemup,
+ sfx_bglass,
+ sfx_wriver,
+ sfx_wfall,
+ sfx_wdrip,
+ sfx_wsplsh,
+ sfx_rebact,
+ sfx_agrac1,
+ sfx_agrac2,
+ sfx_agrac3,
+ sfx_agrac4,
+ sfx_ambppl,
+ sfx_ambbar,
+ sfx_telept,
+ sfx_ratact,
+ sfx_itmbk,
+ sfx_xbow,
+ sfx_burnme,
+ sfx_oof,
+ sfx_wbrldt,
+ sfx_psdtha,
+ sfx_psdthb,
+ sfx_psdthc,
+ sfx_rb2pn,
+ sfx_rb2dth,
+ sfx_rb2see,
+ sfx_rb2act,
+ sfx_firxpl,
+ sfx_stnmov,
+ sfx_noway,
+ sfx_rlaunc,
+ sfx_rflite,
+ sfx_radio,
+ sfx_pulchn,
+ sfx_swknob,
+ sfx_keycrd,
+ sfx_swston,
+ sfx_sntsee,
+ sfx_sntdth,
+ sfx_sntact,
+ sfx_pgrdat,
+ sfx_pgrsee,
+ sfx_pgrdpn,
+ sfx_pgrdth,
+ sfx_pgract,
+ sfx_proton,
+ sfx_protfl,
+ sfx_plasma,
+ sfx_dsrptr,
+ sfx_reavat,
+ sfx_revbld,
+ sfx_revsee,
+ sfx_reavpn,
+ sfx_revdth,
+ sfx_revact,
+ sfx_spisit,
+ sfx_spdwlk,
+ sfx_spidth,
+ sfx_spdatk,
+ sfx_chant,
+ sfx_static,
+ sfx_chain,
+ sfx_tend,
+ sfx_phoot,
+ sfx_explod,
+ sfx_sigil,
+ sfx_sglhit,
+ sfx_siglup,
+ sfx_prgpn,
+ sfx_progac,
+ sfx_lorpn,
+ sfx_lorsee,
+ sfx_difool,
+ sfx_inqdth,
+ sfx_inqact,
+ sfx_inqsee,
+ sfx_inqjmp,
+ sfx_amaln1,
+ sfx_amaln2,
+ sfx_amaln3,
+ sfx_amaln4,
+ sfx_amaln5,
+ sfx_amaln6,
+ sfx_mnalse,
+ sfx_alnsee,
+ sfx_alnpn,
+ sfx_alnact,
+ sfx_alndth,
+ sfx_mnaldt,
+ sfx_reactr,
+ sfx_airlck,
+ sfx_drchno,
+ sfx_drchnc,
+ sfx_valve,
+ NUMSFX
+} sfxenum_t;
+
+#endif
diff --git a/src/strife/st_lib.c b/src/strife/st_lib.c
new file mode 100644
index 00000000..a0fed423
--- /dev/null
+++ b/src/strife/st_lib.c
@@ -0,0 +1,340 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// The status bar widget code.
+//
+//-----------------------------------------------------------------------------
+
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include "deh_main.h"
+#include "doomdef.h"
+
+#include "z_zone.h"
+#include "v_video.h"
+
+#include "i_swap.h"
+#include "i_system.h"
+
+#include "w_wad.h"
+
+#include "st_stuff.h"
+#include "st_lib.h"
+#include "r_local.h"
+
+
+// in AM_map.c
+extern boolean automapactive;
+
+
+
+
+//
+// Hack display negative frags.
+// Loads and store the stminus lump.
+//
+patch_t* sttminus;
+
+void STlib_init(void)
+{
+ // haleyjd 08/28/10: [STRIFE] STTMINUS -> STCFN045
+ sttminus = (patch_t *) W_CacheLumpName(DEH_String("STCFN045"), PU_STATIC);
+}
+
+
+//
+// STlib_initNum
+//
+// haleyjd 09/01/10: [STRIFE]
+// * Rogue removed the "on" member of st_number_t.
+void
+STlib_initNum
+( st_number_t* n,
+ int x,
+ int y,
+ patch_t** pl,
+ int* num,
+ int width )
+{
+ n->x = x;
+ n->y = y;
+ n->width = width;
+ n->num = num;
+ n->p = pl;
+}
+
+
+//
+// STlib_drawNum
+//
+// A fairly efficient way to draw a number
+// based on differences from the old number.
+// Note: worth the trouble?
+//
+// haleyjd 09/01/10: [STRIFE]
+// * Rogue removed the "refresh" parameter and caching code
+//
+void
+STlib_drawNum
+( st_number_t* n)
+{
+ int numdigits = n->width;
+ int num = *n->num;
+
+ int w = SHORT(n->p[0]->width) + 1; // [STRIFE] +1
+ int x = n->x;
+
+ int neg;
+
+ neg = num < 0;
+
+ if (neg)
+ {
+ if (numdigits == 2 && num < -9)
+ num = -9;
+ else if (numdigits == 3 && num < -99)
+ num = -99;
+
+ num = -num;
+ }
+
+ /* haleyjd 09/01/10: [STRIFE] Widget caching system removed by Rogue
+ // clear the area
+ x = n->x - numdigits*w;
+
+ if (n->y - ST_Y < 0)
+ I_Error("drawNum: n->y - ST_Y < 0");
+
+ V_CopyRect(x, n->y - ST_Y, st_backing_screen, w*numdigits, h, x, n->y);
+ */
+
+ // if non-number, do not draw it
+ if (num == 1994)
+ return;
+
+ x = n->x;
+
+ // in the special case of 0, you draw 0
+ if (!num)
+ V_DrawPatch(x - w, n->y, n->p[ 0 ]);
+
+ // draw the new number
+ while (num && numdigits--)
+ {
+ x -= w;
+ V_DrawPatch(x, n->y, n->p[ num % 10 ]);
+ num /= 10;
+ }
+
+ // draw a minus sign if necessary
+ if (neg)
+ V_DrawPatch(x - 8, n->y, sttminus);
+}
+
+
+//
+// STlib_drawNumPositive
+//
+// haleyjd 09/01/10: [STRIFE] New function.
+// * Mostly the same as STlib_drawNum, except doesn't draw negatives.
+//
+void
+STlib_drawNumPositive
+( st_number_t* n)
+{
+ int numdigits = n->width;
+ int num = *n->num;
+
+ int w = SHORT(n->p[0]->width) + 1; // [STRIFE] +1
+ int x = n->x;
+
+ // Don't draw negative values.
+ if (num < 0)
+ num = 0;
+
+ // if non-number, do not draw it
+ if (num == 1994)
+ return;
+
+ x = n->x;
+
+ // in the special case of 0, you draw 0
+ if (!num)
+ V_DrawPatch(x - w, n->y, n->p[ 0 ]);
+
+ // draw the new number
+ while (num && numdigits--)
+ {
+ x -= w;
+ V_DrawPatch(x, n->y, n->p[ num % 10 ]);
+ num /= 10;
+ }
+}
+
+
+// haleyjd 09/01/10: [STRIFE] All other functions were removed.
+/*
+void
+STlib_updateNum
+( st_number_t* n,
+ boolean refresh )
+{
+ if (*n->on) STlib_drawNum(n, refresh);
+}
+
+
+//
+void
+STlib_initPercent
+( st_percent_t* p,
+ int x,
+ int y,
+ patch_t** pl,
+ int* num,
+ boolean* on,
+ patch_t* percent )
+{
+ STlib_initNum(&p->n, x, y, pl, num, on, 3);
+ p->p = percent;
+}
+
+
+
+
+void
+STlib_updatePercent
+( st_percent_t* per,
+ int refresh )
+{
+ if (refresh && *per->n.on)
+ V_DrawPatch(per->n.x, per->n.y, per->p);
+
+ STlib_updateNum(&per->n, refresh);
+}
+
+
+
+void
+STlib_initMultIcon
+( st_multicon_t* i,
+ int x,
+ int y,
+ patch_t** il,
+ int* inum,
+ boolean* on )
+{
+ i->x = x;
+ i->y = y;
+ i->oldinum = -1;
+ i->inum = inum;
+ i->on = on;
+ i->p = il;
+}
+
+
+
+void
+STlib_updateMultIcon
+( st_multicon_t* mi,
+ boolean refresh )
+{
+ int w;
+ int h;
+ int x;
+ int y;
+
+ if (*mi->on
+ && (mi->oldinum != *mi->inum || refresh)
+ && (*mi->inum!=-1))
+ {
+ if (mi->oldinum != -1)
+ {
+ x = mi->x - SHORT(mi->p[mi->oldinum]->leftoffset);
+ y = mi->y - SHORT(mi->p[mi->oldinum]->topoffset);
+ w = SHORT(mi->p[mi->oldinum]->width);
+ h = SHORT(mi->p[mi->oldinum]->height);
+
+ if (y - ST_Y < 0)
+ I_Error("updateMultIcon: y - ST_Y < 0");
+
+ V_CopyRect(x, y-ST_Y, st_backing_screen, w, h, x, y);
+ }
+ V_DrawPatch(mi->x, mi->y, mi->p[*mi->inum]);
+ mi->oldinum = *mi->inum;
+ }
+}
+
+
+
+void
+STlib_initBinIcon
+( st_binicon_t* b,
+ int x,
+ int y,
+ patch_t* i,
+ boolean* val,
+ boolean* on )
+{
+ b->x = x;
+ b->y = y;
+ b->oldval = false;
+ b->val = val;
+ b->on = on;
+ b->p = i;
+}
+
+
+
+void
+STlib_updateBinIcon
+( st_binicon_t* bi,
+ boolean refresh )
+{
+ int x;
+ int y;
+ int w;
+ int h;
+
+ if (*bi->on
+ && (bi->oldval != *bi->val || refresh))
+ {
+ x = bi->x - SHORT(bi->p->leftoffset);
+ y = bi->y - SHORT(bi->p->topoffset);
+ w = SHORT(bi->p->width);
+ h = SHORT(bi->p->height);
+
+ if (y - ST_Y < 0)
+ I_Error("updateBinIcon: y - ST_Y < 0");
+
+ if (*bi->val)
+ V_DrawPatch(bi->x, bi->y, bi->p);
+ else
+ V_CopyRect(x, y-ST_Y, st_backing_screen, w, h, x, y);
+
+ bi->oldval = *bi->val;
+ }
+
+}
+*/
+
diff --git a/src/strife/st_lib.h b/src/strife/st_lib.h
new file mode 100644
index 00000000..2576233d
--- /dev/null
+++ b/src/strife/st_lib.h
@@ -0,0 +1,229 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// The status bar widget code.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef __STLIB__
+#define __STLIB__
+
+
+// We are referring to patches.
+#include "r_defs.h"
+
+//
+// Typedefs of widgets
+//
+
+// Number widget
+
+typedef struct
+{
+ // upper right-hand corner
+ // of the number (right-justified)
+ int x;
+ int y;
+
+ // max # of digits in number
+ int width;
+
+ // haleyjd 09/01/10: [STRIFE] Removed "oldnum" member
+ //int oldnum;
+
+ // pointer to current value
+ int* num;
+
+ // haleyjd 09/01/10: [STRIFE] Removed "on" member
+ // boolean* on;
+
+ // list of patches for 0-9
+ patch_t** p;
+
+ // user data
+ int data;
+
+} st_number_t;
+
+
+
+// Percent widget ("child" of number widget,
+// or, more precisely, contains a number widget.)
+typedef struct
+{
+ // number information
+ st_number_t n;
+
+ // percent sign graphic
+ patch_t* p;
+
+} st_percent_t;
+
+
+
+// Multiple Icon widget
+typedef struct
+{
+ // center-justified location of icons
+ int x;
+ int y;
+
+ // last icon number
+ int oldinum;
+
+ // pointer to current icon
+ int* inum;
+
+ // pointer to boolean stating
+ // whether to update icon
+ boolean* on;
+
+ // list of icons
+ patch_t** p;
+
+ // user data
+ int data;
+
+} st_multicon_t;
+
+
+
+
+// Binary Icon widget
+
+typedef struct
+{
+ // center-justified location of icon
+ int x;
+ int y;
+
+ // last icon value
+ boolean oldval;
+
+ // pointer to current icon status
+ boolean* val;
+
+ // pointer to boolean
+ // stating whether to update icon
+ boolean* on;
+
+
+ patch_t* p; // icon
+ int data; // user data
+
+} st_binicon_t;
+
+
+
+//
+// Widget creation, access, and update routines
+//
+
+// Initializes widget library.
+// More precisely, initialize STMINUS,
+// everything else is done somewhere else.
+//
+void STlib_init(void);
+
+
+
+// Number widget routines
+
+// haleyjd 09/01/10: [STRIFE] Removed "on" parameter.
+void
+STlib_initNum
+( st_number_t* n,
+ int x,
+ int y,
+ patch_t** pl,
+ int* num,
+ int width );
+
+// haleyjd 09/01/10: [STRIFE] Made globally visible.
+void
+STlib_drawNum
+( st_number_t* n);
+
+// haleyjd 09/01/10: [STRIFE] New function
+void
+STlib_drawNumPositive
+( st_number_t* n);
+
+/* haleyjd 09/01/10: [STRIFE] All the below were removed
+void
+STlib_updateNum
+( st_number_t* n,
+ boolean refresh );
+
+
+// Percent widget routines
+void
+STlib_initPercent
+( st_percent_t* p,
+ int x,
+ int y,
+ patch_t** pl,
+ int* num,
+ boolean* on,
+ patch_t* percent );
+
+
+void
+STlib_updatePercent
+( st_percent_t* per,
+ int refresh );
+
+
+// Multiple Icon widget routines
+void
+STlib_initMultIcon
+( st_multicon_t* mi,
+ int x,
+ int y,
+ patch_t** il,
+ int* inum,
+ boolean* on );
+
+
+void
+STlib_updateMultIcon
+( st_multicon_t* mi,
+ boolean refresh );
+
+// Binary Icon widget routines
+
+void
+STlib_initBinIcon
+( st_binicon_t* b,
+ int x,
+ int y,
+ patch_t* i,
+ boolean* val,
+ boolean* on );
+
+void
+STlib_updateBinIcon
+( st_binicon_t* bi,
+ boolean refresh );
+*/
+
+#endif
diff --git a/src/strife/st_stuff.c b/src/strife/st_stuff.c
new file mode 100644
index 00000000..3761f141
--- /dev/null
+++ b/src/strife/st_stuff.c
@@ -0,0 +1,1555 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Status bar code.
+// Does the face/direction indicator animatin.
+// Does palette indicators as well (red pain/berserk, bright pickup)
+//
+//-----------------------------------------------------------------------------
+
+
+
+#include <stdio.h>
+
+#include "i_system.h"
+#include "i_video.h"
+#include "z_zone.h"
+#include "m_random.h"
+#include "w_wad.h"
+
+#include "deh_main.h"
+#include "deh_misc.h"
+#include "doomdef.h"
+#include "doomkeys.h"
+
+#include "g_game.h"
+
+#include "st_stuff.h"
+#include "st_lib.h"
+#include "r_local.h"
+
+#include "p_local.h"
+#include "p_inter.h"
+#include "p_dialog.h" // villsa [STRIFE]
+
+#include "am_map.h"
+#include "m_cheat.h"
+#include "m_menu.h" // villsa [STRIFE]
+
+#include "s_sound.h"
+
+// Needs access to LFB.
+#include "v_video.h"
+#include "i_swap.h"
+
+// State.
+#include "doomstat.h"
+#include "d_main.h" // [STRIFE]
+
+// Data.
+#include "dstrings.h"
+#include "sounds.h"
+#include "m_controls.h"
+#include "hu_lib.h" // [STRIFE]
+#include "hu_stuff.h"
+
+//
+// STATUS BAR DATA
+//
+
+// Palette indices.
+// For damage/bonus red-/gold-shifts
+#define STARTREDPALS 1
+#define STARTBONUSPALS 9
+#define NUMREDPALS 8
+#define NUMBONUSPALS 4
+// Radiation suit, green shift.
+#define RADIATIONPAL 13
+
+// Location of status bar
+#define ST_X 0
+
+// Location and size of statistics,
+// justified according to widget type.
+// Problem is, within which space? STbar? Screen?
+// Note: this could be read in by a lump.
+// Problem is, is the stuff rendered
+// into a buffer,
+// or into the frame buffer?
+
+// AMMO number pos.
+// haleyjd 09/01/10: [STRIFE] Adjusted.
+#define ST_AMMOWIDTH 3
+#define ST_AMMOX 311
+#define ST_AMMOY 162
+
+// HEALTH number pos.
+// haleyjd 09/01/10: [STRIFE] Adjusted.
+#define ST_HEALTHWIDTH 3
+#define ST_HEALTHX 79
+#define ST_HEALTHY 162
+
+// [STRIFE]
+// Removed:
+// * Weapon pos.
+// * Frags pos.
+// * ARMOR number pos.
+// * Key icon positions.
+
+// Ammunition counter.
+// haleyjd 20110213 [STRIFE]: ammo counters for the popup widget
+#define ST_POPUPAMMOX 206
+static const int st_yforammo[NUMAMMO] = { 75, 99, 91, 139, 131, 115, 123 };
+static const int st_wforammo[NUMAMMO] = { 3, 3, 2, 3, 3, 2, 3 };
+
+// Indicate maximum ammunition.
+// Only needed because backpack exists.
+// haleyjd 20110213 [STRIFE]: maxammo counters for the popup widget
+#define ST_POPUPMAXAMMOX 239
+
+// [STRIFE]
+// Removed:
+// * Doom weapon stuff
+// * DETH title (???)
+
+// Dimensions given in characters.
+#define ST_MSGWIDTH 52
+
+// haleyjd 08/31/10: [STRIFE]
+// * Removed faces.
+// haleyjd 09/01/10:
+// * Removed DOOM pre-beta cruft.
+// * Removed deathmatch frags/arms-related stuff.
+// * Removed arms panel stuff.
+// * Removed unused widgets.
+// * Removed more faces, keyboxes, st_randomnumber
+
+// graphics are drawn to a backing screen and blitted to the real screen
+//byte *st_backing_screen; - [STRIFE]: Unused.
+
+// main player in game
+static player_t* plyr;
+
+// ST_Start() has just been called
+static boolean st_firsttime;
+
+// lump number for PLAYPAL
+static int lu_palette;
+
+// whether in automap or first-person
+static st_stateenum_t st_gamestate;
+
+// whether left-side main status bar is active
+static boolean st_statusbaron;
+
+// villsa [STRIFE]
+static boolean st_dosizedisplay = false;
+
+// haleyjd 09/01/10: [STRIFE]
+// Whether or not a popup is currently displayed
+static boolean st_displaypopup = false;
+
+// villsa [STRIFE]
+static int st_popupdisplaytics = 0;
+
+// villsa [STRIFE]
+// Whether or not show popup objective screen
+static boolean st_showobjective = false;
+
+// villsa [STRIFE]
+static boolean st_showinvpop = false;
+
+// villsa [STRIFE]
+static boolean st_showkeys = false;
+
+// villsa [STRIFE] TODO - identify variables
+static int st_keypage = -1;
+static int dword_88490 = 0;
+
+// haleyjd 09/19/10: [STRIFE] Cached player data
+static int st_lastcursorpos;
+static int st_lastammo;
+static int st_lastarmortype;
+static int st_lasthealth;
+
+// haleyjd 09/01/10: [STRIFE] sbar -> invback
+// main inventory background and other bits
+static patch_t* invback; // main bar
+static patch_t* stback; // multiplayer background
+static patch_t* invtop; // top bit
+static patch_t* invpop; // popup frame with text
+static patch_t* invpop2; // plain popup frame
+static patch_t* invpbak; // popup background w/details
+static patch_t* invpbak2; // plain popup background
+static patch_t* invcursor; // cursor
+
+// ammo/weapon/armor patches
+static patch_t* invammo[NUMAMMO]; // ammo/weapons
+static patch_t* invsigil[5]; // sigil pieces
+static patch_t* invarmor[2]; // armor icons
+
+// names for ammo patches
+static char *invammonames[NUMAMMO] =
+{
+ "I_BLIT",
+ "I_XQRL",
+ "I_PQRL",
+ "I_BRY1",
+ "I_ROKT",
+ "I_GRN1",
+ "I_GRN2"
+};
+
+// haleyjd 09/01/10: [STRIFE] Replaced tallnum, shortnum w/inv fonts
+// 0-9, green numbers
+static patch_t* invfontg[10];
+
+// 0-9, yellow numbers
+static patch_t* invfonty[10];
+
+// 3 key-cards, 3 skulls -- [STRIFE] has a lot more keys than 3 :P
+static patch_t* keys[NUMCARDS];
+
+// ready-weapon widget
+static st_number_t w_ready; // haleyjd [STRIFE]: This is still used.
+
+// haleyjd: [STRIFE] This is still used but was changed to a st_number_t.
+// health widget
+static st_number_t w_health;
+
+// ammo widgets
+static st_number_t w_ammo[NUMAMMO]; // haleyjd [STRIFE]: Still used.
+
+// max ammo widgets
+static st_number_t w_maxammo[NUMAMMO]; // haleyjd [STRIFE]: Still used.
+
+// number of frags so far in deathmatch
+static int st_fragscount;
+
+
+cheatseq_t cheat_mus = CHEAT("spin", 2); // [STRIFE]: idmus -> spin
+cheatseq_t cheat_god = CHEAT("omnipotent", 0); // [STRIFE]: iddqd -> omnipotent
+cheatseq_t cheat_ammo = CHEAT("boomstix", 0); // [STRIFE]: idfa -> boomstix
+cheatseq_t cheat_noclip = CHEAT("elvis", 0); // [STRIFE]: idclip -> elvis
+cheatseq_t cheat_clev = CHEAT("rift", 2); // [STRIFE]: idclev -> rift
+cheatseq_t cheat_mypos = CHEAT("gps", 0); // [STRIFE]: idmypos -> gps
+cheatseq_t cheat_scoot = CHEAT("scoot", 1); // [STRIFE]: new cheat scoot
+cheatseq_t cheat_nuke = CHEAT("stonecold", 0); // [STRIFE]: new cheat stonecold
+cheatseq_t cheat_keys = CHEAT("jimmy", 0); // [STRIFE]: new cheat jimmy (all keys)
+cheatseq_t cheat_stealth = CHEAT("gripper", 0); // [STRIFE]: new cheat gripper
+cheatseq_t cheat_midas = CHEAT("donnytrump", 0); // [STRIFE]: new cheat
+cheatseq_t cheat_lego = CHEAT("lego", 0); // [STRIFE]: new cheat
+cheatseq_t cheat_dev = CHEAT("dots", 0); // [STRIFE]: new cheat
+
+// haleyjd 20110224: enumeration for access to powerup cheats
+enum
+{
+ ST_PUMPUP_B,
+ ST_PUMPUP_I,
+ ST_PUMPUP_M,
+ ST_PUMPUP_H,
+ ST_PUMPUP_P,
+ ST_PUMPUP_S,
+ ST_PUMPUP_T,
+ ST_PUMPUP,
+ NUM_ST_PUMPUP
+};
+
+cheatseq_t cheat_powerup[NUM_ST_PUMPUP] = // [STRIFE]
+{
+ CHEAT("pumpupb", 0),
+ CHEAT("pumpupi", 0),
+ CHEAT("pumpupm", 0),
+ CHEAT("pumpuph", 0),
+ CHEAT("pumpupp", 0),
+ CHEAT("pumpups", 0),
+ CHEAT("pumpupt", 0),
+ CHEAT("pumpup", 0),
+};
+
+//cheatseq_t cheat_choppers = CHEAT("idchoppers", 0); [STRIFE] no such thing
+
+void M_SizeDisplay(int choice); // villsa [STRIFE]
+
+//
+// STATUS BAR CODE
+//
+void ST_Stop(void);
+
+// [STRIFE]
+static char st_msgbuf[ST_MSGWIDTH];
+
+// Respond to keyboard input events,
+// intercept cheats.
+boolean ST_Responder(event_t* ev)
+{
+ // haleyjd 09/27/10: made static to ST_Responder
+ static boolean st_keystate = false;
+ int i;
+
+ // Filter automap on/off.
+ if(ev->type == ev_keyup)
+ {
+ if((ev->data1 & 0xffff0000) == AM_MSGHEADER)
+ {
+ switch(ev->data1)
+ {
+ case AM_MSGENTERED:
+ st_gamestate = AutomapState;
+ st_firsttime = true;
+ break;
+
+ case AM_MSGEXITED:
+ st_gamestate = FirstPersonState;
+ break;
+ }
+
+ return false;
+ }
+
+ // villsa [STRIFE]
+ if(ev->data1 != key_invpop &&
+ ev->data1 != key_mission &&
+ ev->data1 != key_invkey)
+ return false;
+
+ // villsa [STRIFE]
+ if(ev->data1 == key_invpop)
+ st_showinvpop = false;
+ else
+ {
+ if(ev->data1 == key_mission)
+ st_showobjective = false;
+ else
+ {
+ if(ev->data1 == key_invkey)
+ {
+ st_showkeys = false;
+ st_keystate = false;
+ }
+ }
+ }
+
+ if(!st_showkeys && !st_showobjective && !st_showinvpop)
+ {
+ if(!st_popupdisplaytics)
+ {
+ st_displaypopup = false;
+ if(st_dosizedisplay)
+ M_SizeDisplay(true);
+
+ st_dosizedisplay = false;
+ }
+ }
+
+ return true;
+ }
+
+ // if a user keypress...
+ if(ev->type != ev_keydown)
+ return false;
+
+ // haleyjd 09/27/10: No input allowed when the player is dead
+ if(plyr->mo->health <= 0)
+ return false;
+
+ // keydown events
+ if(ev->data1 == key_invquery) // inventory query
+ {
+ inventory_t *inv = &(plyr->inventory[plyr->inventorycursor]);
+ if(inv->amount)
+ {
+ DEH_snprintf(st_msgbuf, sizeof(st_msgbuf), "%d %s",
+ inv->amount,
+ DEH_String(mobjinfo[inv->type].name));
+ plyr->message = st_msgbuf;
+ }
+ }
+
+ // villsa [STRIFE]
+ if(ev->data1 == key_invpop || ev->data1 == key_invkey || ev->data1 == key_mission)
+ {
+ if(ev->data1 == key_invkey)
+ {
+ st_showobjective = false;
+ st_showinvpop = false;
+
+ if(!st_keystate)
+ {
+ st_keystate = true;
+ if(++st_keypage > 2)
+ {
+ st_popupdisplaytics = 0;
+ st_showkeys = false;
+ st_displaypopup = false;
+ st_keypage = -1;
+ return true;
+ }
+ }
+
+ if(netgame)
+ st_popupdisplaytics = 20;
+ else
+ st_popupdisplaytics = 50;
+
+ st_showkeys = true;
+ }
+ else
+ {
+ if(ev->data1 != key_mission || netgame)
+ {
+ if(ev->data1 == key_invpop)
+ {
+ st_keypage = -1;
+ st_popupdisplaytics = false;
+ st_showkeys = false;
+ st_showobjective = false;
+ st_showinvpop = true;
+ }
+ }
+ else
+ {
+ st_showkeys = netgame;
+ st_showinvpop = netgame;
+ st_keypage = -1;
+
+ st_popupdisplaytics = ev->data2 ^ key_mission;
+
+ st_showobjective = true;
+ }
+ }
+
+ if(st_showkeys || st_showobjective || st_showinvpop)
+ {
+ st_displaypopup = true;
+ if(viewheight == SCREENHEIGHT)
+ {
+ M_SizeDisplay(false);
+ st_dosizedisplay = true;
+ }
+ }
+ }
+
+ if(ev->data1 == key_invleft) // inventory move left
+ {
+ if(plyr->inventorycursor > 0)
+ plyr->inventorycursor--;
+ return true;
+ }
+ else if(ev->data1 == key_invright)
+ {
+ if(plyr->inventorycursor < plyr->numinventory - 1)
+ plyr->inventorycursor++;
+ return true;
+ }
+ else if(ev->data1 == key_invhome)
+ {
+ plyr->inventorycursor = 0;
+ return true;
+ }
+ else if(ev->data1 == key_invend)
+ {
+ if(plyr->numinventory)
+ plyr->inventorycursor = plyr->numinventory - 1;
+ else
+ plyr->inventorycursor = 0;
+ return true;
+ }
+
+ //
+ // [STRIFE] Cheats which are allowed in netgames/demos:
+ //
+
+ // 'spin' cheat for changing music
+ if (cht_CheckCheat(&cheat_mus, ev->data2))
+ {
+ char buf[3];
+ int musnum;
+
+ plyr->message = DEH_String(STSTR_MUS);
+ cht_GetParam(&cheat_mus, buf);
+
+ musnum = (buf[0] - '0') * 10 + buf[1] - '0';
+
+ if (((buf[0]-'0')*10 + buf[1]-'0') > 35)
+ plyr->message = DEH_String(STSTR_NOMUS);
+ else
+ S_ChangeMusic(musnum, 1);
+ }
+ // [STRIFE]: "dev" cheat - "DOTS"
+ else if (cht_CheckCheat(&cheat_dev, ev->data2))
+ {
+ devparm = !devparm;
+ if (devparm)
+ plyr->message = DEH_String("devparm ON");
+ else
+ plyr->message = DEH_String("devparm OFF");
+ }
+
+ // [STRIFE] Cheats below are not allowed in netgames or demos
+ if(netgame || !usergame)
+ return false;
+
+ if (cht_CheckCheat(&cheat_god, ev->data2))
+ {
+ // 'omnipotent' cheat for toggleable god mode
+ plyr->cheats ^= CF_GODMODE;
+ if (plyr->cheats & CF_GODMODE)
+ {
+ if (plyr->mo)
+ plyr->mo->health = 100;
+
+ plyr->health = deh_god_mode_health;
+ plyr->st_update = true; // [STRIFE]
+ plyr->message = DEH_String(STSTR_DQDON);
+ }
+ else
+ {
+ plyr->st_update = true;
+ plyr->message = DEH_String(STSTR_DQDOFF);
+ }
+ }
+ else if (cht_CheckCheat(&cheat_ammo, ev->data2))
+ {
+ // [STRIFE]: "BOOMSTIX" cheat for all normal weapons
+ plyr->armorpoints = deh_idkfa_armor;
+ plyr->armortype = deh_idkfa_armor_class;
+
+ for (i = 0; i < NUMWEAPONS; i++)
+ if(!isdemoversion || weaponinfo[i].availabledemo)
+ plyr->weaponowned[i] = true;
+
+ // Takes away the Sigil, even if you already had it...
+ plyr->weaponowned[wp_sigil] = false;
+
+ for (i=0;i<NUMAMMO;i++)
+ plyr->ammo[i] = plyr->maxammo[i];
+
+ plyr->message = DEH_String(STSTR_FAADDED);
+ }
+ else if(cht_CheckCheat(&cheat_keys, ev->data2))
+ {
+ // villsa [STRIFE]: "JIMMY" cheat for all keys
+ #define FIRSTKEYSETAMOUNT 16
+
+ if(plyr->cards[FIRSTKEYSETAMOUNT - 1])
+ {
+ if(plyr->cards[NUMCARDS - 1] || isdemoversion)
+ {
+ for(i = 0; i < NUMCARDS; i++)
+ plyr->cards[i] = false;
+
+ plyr->message = DEH_String("Keys removed");
+ }
+ else
+ {
+ for(i = 0; i < NUMCARDS; i++)
+ plyr->cards[i] = true;
+
+ plyr->message = DEH_String("Cheater Keys Added");
+ }
+ }
+ else
+ {
+ for(i = 0; i < FIRSTKEYSETAMOUNT; i++)
+ plyr->cards[i] = true;
+
+ plyr->message = DEH_String("Cheater Keys Added");
+ }
+ }
+ else if (cht_CheckCheat(&cheat_noclip, ev->data2))
+ {
+ // [STRIFE] Removed idspispopd, added NOCLIP flag setting/removal
+ // Noclip cheat - "ELVIS" (hah-hah :P )
+
+ plyr->cheats ^= CF_NOCLIP;
+
+ if (plyr->cheats & CF_NOCLIP)
+ {
+ plyr->message = DEH_String(STSTR_NCON);
+ plyr->mo->flags |= MF_NOCLIP;
+ }
+ else
+ {
+ plyr->message = DEH_String(STSTR_NCOFF);
+ plyr->mo->flags &= ~MF_NOCLIP;
+ }
+ }
+ else if(cht_CheckCheat(&cheat_stealth, ev->data2))
+ {
+ // villsa [STRIFE]: "GRIPPER" cheat; nothing to do with stealth...
+ plyr->cheats ^= CF_NOMOMENTUM;
+ if(plyr->cheats & CF_NOMOMENTUM)
+ plyr->message = DEH_String("STEALTH BOOTS ON");
+ else
+ plyr->message = DEH_String("STEALTH BOOTS OFF");
+ }
+
+ for(i = 0; i < ST_PUMPUP_B + 3; ++i)
+ {
+ // [STRIFE]: Handle berserk, invisibility, and envirosuit
+ if(cht_CheckCheat(&cheat_powerup[i], ev->data2))
+ {
+ if(plyr->powers[i])
+ plyr->powers[i] = (i != 1);
+ else
+ P_GivePower(plyr, i);
+ plyr->message = DEH_String(STSTR_BEHOLDX);
+ }
+ }
+ if(cht_CheckCheat(&cheat_powerup[ST_PUMPUP_H], ev->data2))
+ {
+ // [STRIFE]: PUMPUPH gives medical inventory items
+ P_GiveItemToPlayer(plyr, SPR_STMP, MT_INV_MED1);
+ P_GiveItemToPlayer(plyr, SPR_MDKT, MT_INV_MED2);
+ P_GiveItemToPlayer(plyr, SPR_FULL, MT_INV_MED3);
+ plyr->message = DEH_String("you got the stuff!");
+ }
+ if(cht_CheckCheat(&cheat_powerup[ST_PUMPUP_P], ev->data2))
+ {
+ // [STRIFE]: PUMPUPP gives backpack
+ if(!plyr->backpack)
+ {
+ for(i = 0; i < NUMAMMO; ++i)
+ plyr->maxammo[i] = 2 * plyr->maxammo[i];
+ }
+ plyr->backpack = true;
+
+ for(i = 0; i < NUMAMMO; ++i)
+ P_GiveAmmo(plyr, i, 1);
+ plyr->message = DEH_String("you got the stuff!");
+ }
+ if(cht_CheckCheat(&cheat_powerup[ST_PUMPUP_S], ev->data2))
+ {
+ // [STRIFE]: PUMPUPS gives stamina and accuracy upgrades
+ P_GiveItemToPlayer(plyr, SPR_TOKN, MT_TOKEN_STAMINA);
+ P_GiveItemToPlayer(plyr, SPR_TOKN, MT_TOKEN_NEW_ACCURACY);
+ plyr->message = DEH_String("you got the stuff!");
+ }
+ if(cht_CheckCheat(&cheat_powerup[ST_PUMPUP_T], ev->data2))
+ {
+ // [STRIFE] PUMPUPT gives targeter
+ P_GivePower(plyr, pw_targeter);
+ plyr->message = DEH_String("you got the stuff!");
+ }
+ // [STRIFE]: PUMPUP
+ if (cht_CheckCheat(&cheat_powerup[ST_PUMPUP], ev->data2))
+ {
+ // 'behold' power-up menu
+ plyr->message = DEH_String(STSTR_BEHOLD);
+ return false;
+ }
+
+ if (cht_CheckCheat(&cheat_mypos, ev->data2))
+ {
+ // [STRIFE] 'GPS' for player position
+ static char buf[ST_MSGWIDTH];
+ sprintf(buf, "ang=0x%x;x,y=(0x%x,0x%x)",
+ players[consoleplayer].mo->angle,
+ players[consoleplayer].mo->x,
+ players[consoleplayer].mo->y);
+ plyr->message = buf;
+ }
+
+ // 'rift' change-level cheat
+ if (cht_CheckCheat(&cheat_clev, ev->data2))
+ {
+ char buf[3];
+ int map;
+
+ cht_GetParam(&cheat_clev, buf);
+
+ map = (buf[0] - '0') * 10 + buf[1] - '0';
+
+ // haleyjd 09/01/10: Removed Chex Quest stuff.
+ // haleyjd 09/15/10: Removed retail/registered/shareware stuff
+
+ // haleyjd 20130301: different bounds in v1.31
+ // Ohmygod - this is not going to work.
+ if(gameversion == exe_strife_1_31)
+ {
+ if ((isdemoversion && (map < 32 || map > 34)) ||
+ (isregistered && (map <= 0 || map > 34)))
+ return false;
+ }
+ else
+ {
+ if (map <= 0 || map > 40)
+ return false;
+ }
+
+ // So be it.
+ plyr->message = DEH_String(STSTR_CLEV);
+ G_RiftExitLevel(map, 0, plyr->mo->angle);
+ }
+ else if(cht_CheckCheat(&cheat_scoot, ev->data2))
+ {
+ char buf[3];
+ int spot;
+
+ cht_GetParam(&cheat_scoot, buf);
+
+ spot = buf[0] - '0';
+
+ // BUG: should be <= 9. Shouldn't do anything bad though...
+ if(spot <= 10)
+ {
+ plyr->message = DEH_String("Spawning to spot");
+ G_RiftCheat(spot);
+ return false;
+ }
+ }
+
+ // villsa [STRIFE]
+ if(cht_CheckCheat(&cheat_nuke, ev->data2))
+ {
+ stonecold ^= 1;
+ plyr->message = DEH_String("Kill 'em. Kill 'em All");
+ return false;
+ }
+
+ // villsa [STRIFE]
+ if(cht_CheckCheat(&cheat_midas, ev->data2))
+ {
+ plyr->message = DEH_String("YOU GOT THE MIDAS TOUCH, BABY");
+ P_GiveItemToPlayer(plyr, SPR_HELT, MT_TOKEN_TOUGHNESS);
+ }
+
+ // villsa [STRIFE]
+ // haleyjd 20110224: No sigil in demo version
+ if(!isdemoversion && cht_CheckCheat(&cheat_lego, ev->data2))
+ {
+ plyr->st_update = true;
+ if(plyr->weaponowned[wp_sigil])
+ {
+ if(++plyr->sigiltype > 4)
+ {
+ plyr->sigiltype = -1;
+ plyr->pendingweapon = wp_fist;
+ plyr->weaponowned[wp_sigil] = false;
+ }
+ }
+ else
+ {
+ plyr->weaponowned[wp_sigil] = true;
+ plyr->sigiltype = 0;
+ }
+ // BUG: This brings up a bad version of the Sigil (sigiltype -1) which
+ // causes some VERY interesting behavior, when you type LEGO for the
+ // sixth time. This shouldn't be done when taking it away, and yet it
+ // is here... verified with vanilla.
+ plyr->pendingweapon = wp_sigil;
+ }
+
+ return false;
+}
+
+
+/*
+int ST_calcPainOffset(void)
+{
+ // haleyjd 08/31/10: [STRIFE] Removed.
+}
+*/
+
+//
+// This is a not-very-pretty routine which handles
+// the face states and their timing.
+// the precedence of expressions is:
+// dead > evil grin > turned head > straight ahead
+//
+/*
+void ST_updateFaceWidget(void)
+{
+ // haleyjd 08/31/10: [STRIFE] Removed.
+}
+*/
+
+/*
+void ST_updateWidgets(void)
+{
+ // haleyjd 09/01/10: [STRIFE] Rogue merged this into ST_Ticker below.
+}
+*/
+
+//
+// ST_Ticker
+//
+// haleyjd 09/01/10: [STRIFE]
+// * Removed st_clock and st_randomnumber.
+// * Merged ST_updateWidgets here. Wasn't inlined, as doesn't exist separately
+// in the binary as inlined functions normally do.
+//
+void ST_Ticker (void)
+{
+ static int largeammo = 1994; // means "n/a"
+
+ // must redirect the pointer if the ready weapon has changed.
+ if (weaponinfo[plyr->readyweapon].ammo == am_noammo)
+ w_ready.num = &largeammo;
+ else
+ w_ready.num = &plyr->ammo[weaponinfo[plyr->readyweapon].ammo];
+
+ w_ready.data = plyr->readyweapon;
+
+ // STRIFE-TODO: Gobbledeegunk.
+ /*
+ v2 = dword_88490-- == 1; // no clue yet...
+ if(v2)
+ dword_DC7F4 = dword_DC7F0;*/
+
+ if(st_popupdisplaytics)
+ {
+ int tics = st_popupdisplaytics;
+
+ --st_popupdisplaytics;
+ if(tics == 1)
+ {
+ st_displaypopup = false;
+ st_showkeys = false;
+ st_keypage = -1;
+
+ if(st_dosizedisplay)
+ M_SizeDisplay(true); // mondo hack?
+
+ st_dosizedisplay = false;
+ }
+ }
+
+ // haleyjd 09/01/10: [STRIFE] Keys are handled on a popup
+ // haleyjd 08/31/10: [STRIFE] No face widget
+ // haleyjd 09/01/10: [STRIFE] Armor, weapons, frags, etc. handled elsewhere
+
+ // haleyjd: This is from the PRE-BETA! Left here because it amuses me ;)
+ // get rid of chat window if up because of message
+ //if (!--st_msgcounter)
+ // st_chat = st_oldchat;
+}
+
+static int st_palette = 0;
+
+//
+// ST_doPaletteStuff
+//
+// haleyjd 08/31/10: [STRIFE]
+// * Changed radsuit palette handling for Strife nukagecount.
+// * All other logic verified to be unmodified.
+//
+void ST_doPaletteStuff(void)
+{
+
+ int palette;
+ byte* pal;
+ int cnt;
+ int bzc;
+
+ cnt = plyr->damagecount;
+
+ if (plyr->powers[pw_strength])
+ {
+ // slowly fade the berzerk out
+ bzc = 12 - (plyr->powers[pw_strength]>>6);
+
+ if (bzc > cnt)
+ cnt = bzc;
+ }
+
+ if (cnt)
+ {
+ palette = (cnt+7)>>3;
+
+ if (palette >= NUMREDPALS)
+ palette = NUMREDPALS-1;
+
+ palette += STARTREDPALS;
+ }
+
+ else if (plyr->bonuscount)
+ {
+ palette = (plyr->bonuscount+7)>>3;
+
+ if (palette >= NUMBONUSPALS)
+ palette = NUMBONUSPALS-1;
+
+ palette += STARTBONUSPALS;
+ }
+ // haleyjd 08/31/10: [STRIFE] Flash green when in nukage, not when has
+ // an environment suit (a breathing sound is played to indicate that
+ // instead).
+ else if ( plyr->nukagecount > 16*TICRATE ||
+ (plyr->nukagecount & 8))
+ palette = RADIATIONPAL;
+ else
+ palette = 0;
+
+ // haleyjd 08/31/10: Removed Chex Quest
+
+ if (palette != st_palette)
+ {
+ st_palette = palette;
+ pal = (byte *) W_CacheLumpNum (lu_palette, PU_CACHE)+palette*768;
+ I_SetPalette (pal);
+ }
+
+}
+
+/*
+void ST_drawWidgets(boolean refresh)
+{
+ haleyjd 09/01/10: [STRIFE] Removed
+}
+*/
+
+//
+// ST_drawNumFontY
+//
+// haleyjd 09/19/10: [STRIFE] New function
+// Draws a small yellow number for inventory etc.
+//
+void ST_drawNumFontY(int x, int y, int num)
+{
+ if(!num)
+ V_DrawPatch(x, y, invfonty[0]);
+
+ while(num)
+ {
+ V_DrawPatch(x, y, invfonty[num % 10]);
+ x -= SHORT(invfonty[0]->width) + 1;
+ num /= 10;
+ }
+}
+
+//
+// ST_drawNumFontY2
+//
+// haleyjd 09/19/10: [STRIFE] New function
+// As above, but turns negative numbers into zero.
+//
+void ST_drawNumFontY2(int x, int y, int num)
+{
+ if(!num)
+ V_DrawPatch(x, y, invfonty[0]);
+
+ if(num < 0)
+ num = 0;
+
+ while(num)
+ {
+ V_DrawPatchDirect(x, y, invfonty[num % 10]);
+ x -= SHORT(invfonty[0]->width) + 1;
+ num /= 10;
+ }
+}
+
+//
+// ST_drawLine
+//
+// haleyjd 09/20/10: [STRIFE] New function
+// Basic horizontal line drawing routine used for the health bars.
+//
+void ST_drawLine(int x, int y, int len, int color)
+{
+ byte putcolor = (byte)(color);
+ byte *drawpos = I_VideoBuffer + y * SCREENWIDTH + x;
+ int i = 0;
+
+ while(i < len)
+ {
+ *drawpos++ = putcolor;
+ ++i;
+ }
+}
+
+//
+// ST_doRefresh
+//
+// haleyjd 09/20/10: Evidence more than suggests that Rogue moved all status bar
+// drawing down to this function.
+//
+void ST_doRefresh(void)
+{
+ // draw status bar background to off-screen buff
+ if (st_statusbaron)
+ {
+ int firstinventory, icon_x, num_x, i, numdrawn;
+
+ // haleyjd 09/19/10: No backscreen caching in Strife.
+ //V_UseBuffer(st_backing_screen);
+
+ // TODO: only sometimes drawing?
+
+ plyr->st_update = false;
+
+ // cache data
+ st_lastcursorpos = plyr->inventorycursor;
+ st_lastammo = weaponinfo[plyr->readyweapon].ammo;
+ st_lastarmortype = plyr->armortype;
+ st_lasthealth = plyr->health;
+ st_firsttime = false;
+
+ // draw main status bar
+ V_DrawPatch(ST_X, ST_Y, invback);
+
+ // draw multiplayer armor backdrop if netgame
+ if(netgame)
+ V_DrawPatch(ST_X, 173, stback);
+
+ if(plyr->inventorycursor >= 6)
+ firstinventory = plyr->inventorycursor - 5;
+ else
+ firstinventory = 0;
+
+ // Draw cursor.
+ if(plyr->numinventory)
+ {
+ V_DrawPatch(35 * (plyr->inventorycursor - firstinventory) + 42,
+ 180, invcursor);
+ }
+
+ // Draw inventory bar
+ for(num_x = 68, icon_x = 48, i = firstinventory, numdrawn = 0;
+ num_x < 278;
+ num_x += 35, icon_x += 35, i++, numdrawn++)
+ {
+ int lumpnum;
+ patch_t *patch;
+ char iconname[8];
+
+ if(plyr->numinventory <= numdrawn)
+ break;
+
+ DEH_snprintf(iconname, sizeof(iconname), "I_%s",
+ DEH_String(sprnames[plyr->inventory[i].sprite]));
+
+ lumpnum = W_CheckNumForName(iconname);
+ if(lumpnum == -1)
+ patch = W_CacheLumpName(DEH_String("STCFN063"), PU_CACHE);
+ else
+ patch = W_CacheLumpNum(lumpnum, PU_STATIC);
+
+ V_DrawPatch(icon_x, 182, patch);
+ ST_drawNumFontY(num_x, 191, plyr->inventory[i].amount);
+ }
+
+ // haleyjd 09/19/10: Draw sigil icon
+ if(plyr->weaponowned[wp_sigil])
+ V_DrawPatch(253, 175, invsigil[plyr->sigiltype]);
+
+ // haleyjd 09/19/10: Draw ammo
+ if(st_lastammo < NUMAMMO)
+ V_DrawPatch(290, 180, invammo[st_lastammo]);
+
+ // haleyjd 09/19/10: Draw armor
+ if(plyr->armortype)
+ {
+ V_DrawPatch(2, 177, invarmor[plyr->armortype - 1]);
+ ST_drawNumFontY(20, 191, plyr->armorpoints);
+ }
+
+ // haleyjd 09/20/10: Draw life bars.
+ {
+ int barlength;
+ int lifecolor1;
+ int lifecolor2;
+
+ barlength = plyr->health;
+ if(barlength > 100)
+ barlength = 200 - plyr->health;
+ barlength *= 2;
+
+ if(plyr->health < 11) // Danger, Will Robinson!
+ lifecolor1 = 64;
+ else if(plyr->health < 21) // Caution
+ lifecolor1 = 80;
+ else // All is well.
+ lifecolor1 = 96;
+
+ if(plyr->cheats & CF_GODMODE) // Gold, probably a throwback to DOOM.
+ lifecolor1 = 226;
+
+ lifecolor2 = lifecolor1 + 3;
+
+ // Draw the normal health bars
+ ST_drawLine(49, 172, barlength, lifecolor1);
+ ST_drawLine(49, 173, barlength, lifecolor2);
+ ST_drawLine(49, 175, barlength, lifecolor1);
+ ST_drawLine(49, 176, barlength, lifecolor2);
+
+ // Draw the > 100 health lines
+ if(plyr->health > 100)
+ {
+ int oldbarlength = barlength;
+ lifecolor1 = 112; // Shades of blue
+ lifecolor2 = lifecolor1 + 3;
+
+ // take up the difference not drawn by the first (<= 100) bar
+ barlength = 200 - barlength;
+
+ ST_drawLine(49 + oldbarlength, 172, barlength, lifecolor1);
+ ST_drawLine(49 + oldbarlength, 173, barlength, lifecolor2);
+ ST_drawLine(49 + oldbarlength, 175, barlength, lifecolor1);
+ ST_drawLine(49 + oldbarlength, 176, barlength, lifecolor2);
+ }
+ } // end local-scope block
+
+ // haleyjd 09/19/10: nope, not in Strife.
+ //V_RestoreBuffer();
+ //V_CopyRect(ST_X, 0, st_backing_screen, ST_WIDTH, ST_HEIGHT, ST_X, ST_Y);
+ }
+}
+
+// haleyjd [STRIFE]: Removed ST_diffDraw
+
+void ST_Drawer (boolean fullscreen, boolean refresh)
+{
+ st_statusbaron = (!fullscreen) || automapactive;
+ st_firsttime = st_firsttime || refresh;
+
+ // Do red-/gold-shifts from damage/items
+ ST_doPaletteStuff();
+
+ // If just after ST_Start(), refresh all
+ ST_doRefresh();
+ // Otherwise, update as little as possible
+ //ST_diffDraw(); [STRIFE]: nope
+}
+
+//
+// ST_drawTime
+//
+// villsa [STRIFE] New function.
+// Draws game time on pop up screen
+//
+static void ST_drawTime(int x, int y, int time)
+{
+ int hours;
+ int minutes;
+ int seconds;
+ char string[16];
+
+ // haleyjd 20110213: fixed minutes
+ hours = time / 3600;
+ minutes = (time / 60) % 60;
+ seconds = time % 60;
+
+ DEH_snprintf(string, 16, "%02d:%02d:%02d", hours, minutes, seconds);
+ HUlib_drawYellowText(x, y, string);
+}
+
+#define ST_KEYSPERPAGE 10
+#define ST_KEYS_X 20
+#define ST_KEYS_Y 63
+#define ST_KEYNAME_X 17
+#define ST_KEYNAME_Y 4
+#define ST_KEYS_YSTEP 17
+#define ST_KEYS_NUMROWS 4
+#define ST_KEYS_COL2X 160
+
+//
+// ST_drawKeysPopup
+//
+// haleyjd 20110213: [STRIFE] New function
+// This has taken the longest out of almost everything to get working properly.
+//
+static boolean ST_drawKeysPopup(void)
+{
+ int x, y, key, keycount;
+ mobjinfo_t *info;
+
+ V_DrawXlaPatch(0, 56, invpbak2);
+ V_DrawPatchDirect(0, 56, invpop2);
+
+ if(deathmatch)
+ {
+ // STRIFE-TODO: In deathmatch, the keys popup is replaced by a chart
+ // of frag counts
+ }
+ else
+ {
+ // Bounds-check page number
+ if(st_keypage < 0 || st_keypage > 2)
+ {
+ st_keypage = -1;
+ st_popupdisplaytics = 0;
+ st_displaypopup = false;
+
+ return false;
+ }
+
+ // Are there any keys to display on this page?
+ if(st_keypage > 0)
+ {
+ boolean haskeyinrange = false;
+
+ for(key = ST_KEYSPERPAGE * st_keypage, keycount = 0;
+ keycount < ST_KEYSPERPAGE && key < NUMCARDS;
+ ++key, ++keycount)
+ {
+ if(plyr->cards[key])
+ haskeyinrange = true;
+ }
+
+ if(!haskeyinrange)
+ {
+ st_displaypopup = false;
+ st_showkeys = false;
+ st_keypage = -1;
+
+ return false;
+ }
+ }
+
+ // Draw the keys for the current page
+ key = ST_KEYSPERPAGE * st_keypage;
+ keycount = 0;
+ x = ST_KEYS_X;
+ y = ST_KEYS_Y;
+ info = &mobjinfo[MT_KEY_BASE + key];
+
+ for(; keycount < ST_KEYSPERPAGE && key < NUMCARDS; ++key, ++keycount, ++info)
+ {
+ char sprname[8];
+ patch_t *patch;
+ memset(sprname, 0, sizeof(sprname));
+
+ if(plyr->cards[key])
+ {
+ // Get spawnstate sprite name and load corresponding icon
+ DEH_snprintf(sprname, sizeof(sprname), "I_%s",
+ sprnames[states[info->spawnstate].sprite]);
+ patch = W_CacheLumpName(sprname, PU_CACHE);
+ V_DrawPatchDirect(x, y, patch);
+ HUlib_drawYellowText(x + ST_KEYNAME_X, y + ST_KEYNAME_Y, info->name);
+ }
+
+ if(keycount != ST_KEYS_NUMROWS)
+ y += ST_KEYS_YSTEP;
+ else
+ {
+ x = ST_KEYS_COL2X;
+ y = ST_KEYS_Y;
+ }
+ }
+ }
+
+ return true;
+}
+
+//
+// ST_DrawExternal
+//
+// haleyjd 09/01/10: [STRIFE] New function.
+// * Draws external portions of the status bar such the top bar and popups.
+//
+boolean ST_DrawExternal(void)
+{
+ int i;
+
+ if(st_statusbaron)
+ {
+ V_DrawPatchDirect(0, 160, invtop);
+ STlib_drawNumPositive(&w_health);
+ STlib_drawNumPositive(&w_ready);
+ }
+ else
+ {
+ ammotype_t ammo;
+
+ ST_drawNumFontY2(15, 194, plyr->health);
+ ammo = weaponinfo[plyr->readyweapon].ammo;
+ if (ammo != am_noammo)
+ ST_drawNumFontY2(310, 194, plyr->ammo[ammo]);
+ }
+
+ if(!st_displaypopup)
+ return false;
+
+ // villsa [STRIFE] added 09/26/10
+ if(st_showobjective)
+ {
+ V_DrawXlaPatch(0, 56, invpbak2);
+ V_DrawPatchDirect(0, 56, invpop2);
+ M_DialogDimMsg(24, 74, mission_objective, true);
+ HUlib_drawYellowText(24, 74, mission_objective);
+ ST_drawTime(210, 64, leveltime / TICRATE);
+ }
+ else
+ {
+ int keys = 0;
+
+ // villsa [STRIFE] keys popup
+ if(st_showkeys || st_popupdisplaytics)
+ return ST_drawKeysPopup();
+
+ V_DrawXlaPatch(0, 56, invpbak);
+ V_DrawPatchDirect(0, 56, invpop);
+
+ for(i = 0; i < NUMCARDS; i++)
+ {
+ if(plyr->cards[i])
+ keys++;
+ }
+
+ ST_drawNumFontY2(261, 132, keys);
+
+ if(plyr->weaponowned[wp_elecbow])
+ {
+ V_DrawPatchDirect(38, 86,
+ W_CacheLumpName(DEH_String("CBOWA0"), PU_CACHE));
+ }
+ if(plyr->weaponowned[wp_rifle])
+ {
+ V_DrawPatchDirect(40, 107,
+ W_CacheLumpName(DEH_String("RIFLA0"), PU_CACHE));
+ }
+ if(plyr->weaponowned[wp_missile])
+ {
+ V_DrawPatchDirect(39, 131,
+ W_CacheLumpName(DEH_String("MMSLA0"), PU_CACHE));
+ }
+ if(plyr->weaponowned[wp_hegrenade])
+ {
+ V_DrawPatchDirect(78, 87,
+ W_CacheLumpName(DEH_String("GRNDA0"), PU_CACHE));
+ }
+ if(plyr->weaponowned[wp_flame])
+ {
+ V_DrawPatchDirect(80, 117,
+ W_CacheLumpName(DEH_String("FLAMA0"), PU_CACHE));
+ }
+ if(plyr->weaponowned[wp_mauler])
+ {
+ V_DrawPatchDirect(75, 142,
+ W_CacheLumpName(DEH_String("TRPDA0"), PU_CACHE));
+ }
+
+ // haleyjd 20110213: draw ammo
+ for(i = 0; i < NUMAMMO; i++)
+ {
+ STlib_drawNumPositive(&w_ammo[i]);
+ STlib_drawNumPositive(&w_maxammo[i]);
+ }
+
+ ST_drawNumFontY2(261, 84, plyr->accuracy);
+ ST_drawNumFontY2(261, 108, plyr->stamina);
+
+ if(plyr->powers[pw_communicator])
+ {
+ V_DrawPatchDirect(280, 130,
+ W_CacheLumpName(DEH_String("I_COMM"), PU_CACHE));
+ }
+ }
+
+ return true;
+}
+
+typedef void (*load_callback_t)(char *lumpname, patch_t **variable);
+
+//
+// ST_loadUnloadGraphics
+//
+// Iterates through all graphics to be loaded or unloaded, along with
+// the variable they use, invoking the specified callback function.
+//
+// [STRIFE] Altered to load all Strife status bar resources.
+//
+static void ST_loadUnloadGraphics(load_callback_t callback)
+{
+ int i;
+ char namebuf[9];
+
+ // haleyjd 09/01/10: [STRIFE]
+ // Load the numbers, green and yellow
+ for (i=0;i<10;i++)
+ {
+ DEH_snprintf(namebuf, 9, "INVFONG%d", i);
+ callback(namebuf, &invfontg[i]);
+
+ DEH_snprintf(namebuf, 9, "INVFONY%d", i);
+ callback(namebuf, &invfonty[i]);
+ }
+
+ // haleyjd 09/19/10: load Sigil patches
+ if(!isdemoversion)
+ {
+ for(i = 0; i < 5; i++)
+ {
+ DEH_snprintf(namebuf, 9, "I_SGL%d", i+1);
+ callback(namebuf, &invsigil[i]);
+ }
+ }
+
+ // load ammo patches
+ for(i = 0; i < NUMAMMO; i++)
+ callback(DEH_String(invammonames[i]), &invammo[i]);
+
+ // load armor patches
+ callback(DEH_String("I_ARM2"), &invarmor[0]);
+ callback(DEH_String("I_ARM1"), &invarmor[1]);
+
+ // haleyjd 09/19/10: [STRIFE]
+ // * No face, but there is this patch, which appears behind the armor
+ DEH_snprintf(namebuf, 9, "STBACK0%d", consoleplayer + 1);
+ if(netgame)
+ callback(namebuf, &stback);
+
+ // 09/01/10:
+ // * Removed all unused DOOM stuff (arms, numbers, %, etc).
+
+ // haleyjd 09/01/10: [STRIFE]: stbar -> invback, added new patches
+ // status bar background bits
+ callback(DEH_String("INVBACK"), &invback);
+ callback(DEH_String("INVTOP"), &invtop);
+ callback(DEH_String("INVPOP"), &invpop);
+ callback(DEH_String("INVPOP2"), &invpop2);
+ callback(DEH_String("INVPBAK"), &invpbak);
+ callback(DEH_String("INVPBAK2"), &invpbak2);
+ callback(DEH_String("INVCURS"), &invcursor);
+}
+
+static void ST_loadCallback(char *lumpname, patch_t **variable)
+{
+ *variable = W_CacheLumpName(lumpname, PU_STATIC);
+}
+
+void ST_loadGraphics(void)
+{
+ ST_loadUnloadGraphics(ST_loadCallback);
+}
+
+void ST_loadData(void)
+{
+ static int dword_8848C = 1; // STRIFE-TODO: what is the purpose of this?
+ dword_8848C = 0;
+
+ lu_palette = W_GetNumForName (DEH_String("PLAYPAL"));
+ ST_loadGraphics();
+}
+
+static void ST_unloadCallback(char *lumpname, patch_t **variable)
+{
+ W_ReleaseLumpName(lumpname);
+ *variable = NULL;
+}
+
+void ST_unloadGraphics(void)
+{
+ ST_loadUnloadGraphics(ST_unloadCallback);
+}
+
+void ST_unloadData(void)
+{
+ ST_unloadGraphics();
+}
+
+//
+// ST_initData
+//
+// haleyjd 09/01/10: [STRIFE]
+// * Removed prebeta cruft, face stuff, keyboxes, and oldwe
+//
+void ST_initData(void)
+{
+ st_firsttime = true;
+ plyr = &players[consoleplayer];
+
+ st_gamestate = FirstPersonState;
+
+ st_statusbaron = true;
+
+ st_palette = -1;
+
+ STlib_init();
+}
+
+
+
+void ST_createWidgets(void)
+{
+ int i;
+
+ // ready weapon ammo
+ STlib_initNum(&w_ready,
+ ST_AMMOX,
+ ST_AMMOY,
+ invfontg,
+ &plyr->ammo[weaponinfo[plyr->readyweapon].ammo],
+ ST_AMMOWIDTH);
+
+ // the last weapon type
+ w_ready.data = plyr->readyweapon;
+
+ // health percentage
+ STlib_initNum(&w_health,
+ ST_HEALTHX,
+ ST_HEALTHY,
+ invfontg,
+ &plyr->health,
+ ST_HEALTHWIDTH);
+
+ // haleyjd 20100831: [STRIFE]
+ // * No face.
+ // 20100901:
+ // * No arms, weaponsowned, frags, armor, keyboxes
+
+ // haleyjd 20110213: Ammo Widgets!!!
+ for(i = 0; i < NUMAMMO; i++)
+ {
+ STlib_initNum(&w_ammo[i], ST_POPUPAMMOX, st_yforammo[i],
+ invfonty, &plyr->ammo[i], st_wforammo[i]);
+
+ STlib_initNum(&w_maxammo[i], ST_POPUPMAXAMMOX, st_yforammo[i],
+ invfonty, &plyr->maxammo[i], st_wforammo[i]);
+ }
+}
+
+static boolean st_stopped = true;
+
+
+void ST_Start (void)
+{
+ if (!st_stopped)
+ ST_Stop();
+
+ ST_initData();
+ ST_createWidgets();
+ st_stopped = false;
+}
+
+void ST_Stop (void)
+{
+ if (st_stopped)
+ return;
+
+ I_SetPalette (W_CacheLumpNum (lu_palette, PU_CACHE));
+
+ st_stopped = true;
+}
+
+void ST_Init (void)
+{
+ ST_loadData();
+
+ // haleyjd 09/19/10: This is not used by Strife. More memory for voices!
+ //st_backing_screen = (byte *) Z_Malloc(ST_WIDTH * ST_HEIGHT, PU_STATIC, 0);
+}
+
diff --git a/src/strife/st_stuff.h b/src/strife/st_stuff.h
new file mode 100644
index 00000000..2bf3bbd4
--- /dev/null
+++ b/src/strife/st_stuff.h
@@ -0,0 +1,108 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Status bar code.
+// Does the face/direction indicator animatin.
+// Does palette indicators as well (red pain/berserk, bright pickup)
+//
+//-----------------------------------------------------------------------------
+
+#ifndef __STSTUFF_H__
+#define __STSTUFF_H__
+
+#include "doomtype.h"
+#include "d_event.h"
+#include "m_cheat.h"
+
+// Size of statusbar.
+// Now sensitive for scaling.
+#define ST_HEIGHT 32
+#define ST_WIDTH SCREENWIDTH
+#define ST_Y (SCREENHEIGHT - ST_HEIGHT)
+
+
+//
+// STATUS BAR
+//
+
+// Called by main loop.
+boolean ST_Responder (event_t* ev);
+
+// Called by main loop.
+void ST_Ticker (void);
+
+// Called by main loop.
+void ST_Drawer (boolean fullscreen, boolean refresh);
+
+// haleyjd 09/01/10: [STRIFE] New function.
+// Called by main loop to draw external status bar bits.
+// Returns true if a popup is drawing.
+boolean ST_DrawExternal(void);
+
+// Called when the console player is spawned on each level.
+void ST_Start (void);
+
+// Called by startup code.
+void ST_Init (void);
+
+
+
+// States for status bar code.
+typedef enum
+{
+ AutomapState,
+ FirstPersonState
+
+} st_stateenum_t;
+
+
+// States for the chat code.
+typedef enum
+{
+ StartChatState,
+ WaitDestState,
+ GetChatState
+
+} st_chatstateenum_t;
+
+
+
+extern byte *st_backing_screen;
+
+extern cheatseq_t cheat_mus; // [STRIFE]: idmus -> spin
+extern cheatseq_t cheat_god; // [STRIFE]: iddqd -> omnipotent
+extern cheatseq_t cheat_ammo; // [STRIFE]: idfa -> boomstix
+extern cheatseq_t cheat_noclip; // [STRIFE]: idclip -> elvis
+extern cheatseq_t cheat_clev; // [STRIFE]: idclev -> rift
+extern cheatseq_t cheat_mypos; // [STRIFE]: idmypos -> gps
+extern cheatseq_t cheat_scoot; // [STRIFE]: new cheat scoot
+extern cheatseq_t cheat_nuke; // [STRIFE]: new cheat stonecold
+extern cheatseq_t cheat_keys; // [STRIFE]: new cheat jimmy (all keys)
+extern cheatseq_t cheat_stealth; // [STRIFE]: new cheat gripper
+extern cheatseq_t cheat_midas; // [STRIFE]: new cheat
+extern cheatseq_t cheat_lego; // [STRIFE]: new cheat
+extern cheatseq_t cheat_dev; // [STRIFE]: new cheat
+
+extern cheatseq_t cheat_powerup[];
+
+
+#endif
diff --git a/src/strife/wi_stuff.c b/src/strife/wi_stuff.c
new file mode 100644
index 00000000..f322e31f
--- /dev/null
+++ b/src/strife/wi_stuff.c
@@ -0,0 +1,1844 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Intermission screens.
+//
+//-----------------------------------------------------------------------------
+
+// haleyjd 08/23/2010: There is no intermission in Strife
+#if 0
+#include <stdio.h>
+
+#include "z_zone.h"
+
+#include "m_random.h"
+
+#include "deh_main.h"
+#include "i_swap.h"
+#include "i_system.h"
+
+#include "w_wad.h"
+
+#include "g_game.h"
+
+#include "r_local.h"
+#include "s_sound.h"
+
+#include "doomstat.h"
+
+// Data.
+#include "sounds.h"
+
+// Needs access to LFB.
+#include "v_video.h"
+
+#include "wi_stuff.h"
+
+//
+// Data needed to add patches to full screen intermission pics.
+// Patches are statistics messages, and animations.
+// Loads of by-pixel layout and placement, offsets etc.
+//
+
+
+//
+// Different vetween registered DOOM (1994) and
+// Ultimate DOOM - Final edition (retail, 1995?).
+// This is supposedly ignored for commercial
+// release (aka DOOM II), which had 34 maps
+// in one episode. So there.
+#define NUMEPISODES 4
+#define NUMMAPS 9
+
+
+// in tics
+//U #define PAUSELEN (TICRATE*2)
+//U #define SCORESTEP 100
+//U #define ANIMPERIOD 32
+// pixel distance from "(YOU)" to "PLAYER N"
+//U #define STARDIST 10
+//U #define WK 1
+
+
+// GLOBAL LOCATIONS
+#define WI_TITLEY 2
+#define WI_SPACINGY 33
+
+// SINGPLE-PLAYER STUFF
+#define SP_STATSX 50
+#define SP_STATSY 50
+
+#define SP_TIMEX 16
+#define SP_TIMEY (SCREENHEIGHT-32)
+
+
+// NET GAME STUFF
+#define NG_STATSY 50
+#define NG_STATSX (32 + SHORT(star->width)/2 + 32*!dofrags)
+
+#define NG_SPACINGX 64
+
+
+// DEATHMATCH STUFF
+#define DM_MATRIXX 42
+#define DM_MATRIXY 68
+
+#define DM_SPACINGX 40
+
+#define DM_TOTALSX 269
+
+#define DM_KILLERSX 10
+#define DM_KILLERSY 100
+#define DM_VICTIMSX 5
+#define DM_VICTIMSY 50
+
+
+
+
+typedef enum
+{
+ ANIM_ALWAYS,
+ ANIM_RANDOM,
+ ANIM_LEVEL
+
+} animenum_t;
+
+typedef struct
+{
+ int x;
+ int y;
+
+} point_t;
+
+
+//
+// Animation.
+// There is another anim_t used in p_spec.
+//
+typedef struct
+{
+ animenum_t type;
+
+ // period in tics between animations
+ int period;
+
+ // number of animation frames
+ int nanims;
+
+ // location of animation
+ point_t loc;
+
+ // ALWAYS: n/a,
+ // RANDOM: period deviation (<256),
+ // LEVEL: level
+ int data1;
+
+ // ALWAYS: n/a,
+ // RANDOM: random base period,
+ // LEVEL: n/a
+ int data2;
+
+ // actual graphics for frames of animations
+ patch_t* p[3];
+
+ // following must be initialized to zero before use!
+
+ // next value of bcnt (used in conjunction with period)
+ int nexttic;
+
+ // last drawn animation frame
+ int lastdrawn;
+
+ // next frame number to animate
+ int ctr;
+
+ // used by RANDOM and LEVEL when animating
+ int state;
+
+} anim_t;
+
+
+static point_t lnodes[NUMEPISODES][NUMMAPS] =
+{
+ // Episode 0 World Map
+ {
+ { 185, 164 }, // location of level 0 (CJ)
+ { 148, 143 }, // location of level 1 (CJ)
+ { 69, 122 }, // location of level 2 (CJ)
+ { 209, 102 }, // location of level 3 (CJ)
+ { 116, 89 }, // location of level 4 (CJ)
+ { 166, 55 }, // location of level 5 (CJ)
+ { 71, 56 }, // location of level 6 (CJ)
+ { 135, 29 }, // location of level 7 (CJ)
+ { 71, 24 } // location of level 8 (CJ)
+ },
+
+ // Episode 1 World Map should go here
+ {
+ { 254, 25 }, // location of level 0 (CJ)
+ { 97, 50 }, // location of level 1 (CJ)
+ { 188, 64 }, // location of level 2 (CJ)
+ { 128, 78 }, // location of level 3 (CJ)
+ { 214, 92 }, // location of level 4 (CJ)
+ { 133, 130 }, // location of level 5 (CJ)
+ { 208, 136 }, // location of level 6 (CJ)
+ { 148, 140 }, // location of level 7 (CJ)
+ { 235, 158 } // location of level 8 (CJ)
+ },
+
+ // Episode 2 World Map should go here
+ {
+ { 156, 168 }, // location of level 0 (CJ)
+ { 48, 154 }, // location of level 1 (CJ)
+ { 174, 95 }, // location of level 2 (CJ)
+ { 265, 75 }, // location of level 3 (CJ)
+ { 130, 48 }, // location of level 4 (CJ)
+ { 279, 23 }, // location of level 5 (CJ)
+ { 198, 48 }, // location of level 6 (CJ)
+ { 140, 25 }, // location of level 7 (CJ)
+ { 281, 136 } // location of level 8 (CJ)
+ }
+
+};
+
+
+//
+// Animation locations for episode 0 (1).
+// Using patches saves a lot of space,
+// as they replace 320x200 full screen frames.
+//
+
+#define ANIM(type, period, nanims, x, y, nexttic) \
+ { (type), (period), (nanims), { (x), (y) }, (nexttic), \
+ 0, { NULL, NULL, NULL }, 0, 0, 0, 0 }
+
+
+static anim_t epsd0animinfo[] =
+{
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 224, 104, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 184, 160, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 112, 136, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 72, 112, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 88, 96, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 64, 48, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 192, 40, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 136, 16, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 80, 16, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 64, 24, 0),
+};
+
+static anim_t epsd1animinfo[] =
+{
+ ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 1),
+ ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 2),
+ ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 3),
+ ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 4),
+ ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 5),
+ ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 6),
+ ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 7),
+ ANIM(ANIM_LEVEL, TICRATE/3, 3, 192, 144, 8),
+ ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 8),
+};
+
+static anim_t epsd2animinfo[] =
+{
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 104, 168, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 40, 136, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 160, 96, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 104, 80, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 120, 32, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/4, 3, 40, 0, 0),
+};
+
+static int NUMANIMS[NUMEPISODES] =
+{
+ arrlen(epsd0animinfo),
+ arrlen(epsd1animinfo),
+ arrlen(epsd2animinfo),
+};
+
+static anim_t *anims[NUMEPISODES] =
+{
+ epsd0animinfo,
+ epsd1animinfo,
+ epsd2animinfo
+};
+
+
+//
+// GENERAL DATA
+//
+
+//
+// Locally used stuff.
+//
+
+// States for single-player
+#define SP_KILLS 0
+#define SP_ITEMS 2
+#define SP_SECRET 4
+#define SP_FRAGS 6
+#define SP_TIME 8
+#define SP_PAR ST_TIME
+
+#define SP_PAUSE 1
+
+// in seconds
+#define SHOWNEXTLOCDELAY 4
+//#define SHOWLASTLOCDELAY SHOWNEXTLOCDELAY
+
+
+// used to accelerate or skip a stage
+static int acceleratestage;
+
+// wbs->pnum
+static int me;
+
+ // specifies current state
+static stateenum_t state;
+
+// contains information passed into intermission
+static wbstartstruct_t* wbs;
+
+static wbplayerstruct_t* plrs; // wbs->plyr[]
+
+// used for general timing
+static int cnt;
+
+// used for timing of background animation
+static int bcnt;
+
+// signals to refresh everything for one frame
+static int firstrefresh;
+
+static int cnt_kills[MAXPLAYERS];
+static int cnt_items[MAXPLAYERS];
+static int cnt_secret[MAXPLAYERS];
+static int cnt_time;
+static int cnt_par;
+static int cnt_pause;
+
+// # of commercial levels
+static int NUMCMAPS;
+
+
+//
+// GRAPHICS
+//
+
+// You Are Here graphic
+static patch_t* yah[3] = { NULL, NULL, NULL };
+
+// splat
+static patch_t* splat[2] = { NULL, NULL };
+
+// %, : graphics
+static patch_t* percent;
+static patch_t* colon;
+
+// 0-9 graphic
+static patch_t* num[10];
+
+// minus sign
+static patch_t* wiminus;
+
+// "Finished!" graphics
+static patch_t* finished;
+
+// "Entering" graphic
+static patch_t* entering;
+
+// "secret"
+static patch_t* sp_secret;
+
+ // "Kills", "Scrt", "Items", "Frags"
+static patch_t* kills;
+static patch_t* secret;
+static patch_t* items;
+static patch_t* frags;
+
+// Time sucks.
+static patch_t* timepatch;
+static patch_t* par;
+static patch_t* sucks;
+
+// "killers", "victims"
+static patch_t* killers;
+static patch_t* victims;
+
+// "Total", your face, your dead face
+static patch_t* total;
+static patch_t* star;
+static patch_t* bstar;
+
+// "red P[1..MAXPLAYERS]"
+static patch_t* p[MAXPLAYERS];
+
+// "gray P[1..MAXPLAYERS]"
+static patch_t* bp[MAXPLAYERS];
+
+ // Name graphics of each level (centered)
+static patch_t** lnames;
+
+// Buffer storing the backdrop
+static patch_t *background;
+
+//
+// CODE
+//
+
+// slam background
+void WI_slamBackground(void)
+{
+ V_DrawPatch(0, 0, background);
+}
+
+// The ticker is used to detect keys
+// because of timing issues in netgames.
+boolean WI_Responder(event_t* ev)
+{
+ return false;
+}
+
+
+// Draws "<Levelname> Finished!"
+void WI_drawLF(void)
+{
+ int y = WI_TITLEY;
+
+ if (gamemode != commercial || wbs->last < NUMCMAPS)
+ {
+ // draw <LevelName>
+ V_DrawPatch((SCREENWIDTH - SHORT(lnames[wbs->last]->width))/2,
+ y, lnames[wbs->last]);
+
+ // draw "Finished!"
+ y += (5*SHORT(lnames[wbs->last]->height))/4;
+
+ V_DrawPatch((SCREENWIDTH - SHORT(finished->width)) / 2, y, finished);
+ }
+ else if (wbs->last == NUMCMAPS)
+ {
+ // MAP33 - nothing is displayed!
+ }
+ else if (wbs->last > NUMCMAPS)
+ {
+ // > MAP33. Doom bombs out here with a Bad V_DrawPatch error.
+ // I'm pretty sure that doom2.exe is just reading into random
+ // bits of memory at this point, but let's try to be accurate
+ // anyway. This deliberately triggers a V_DrawPatch error.
+
+ patch_t tmp = { SCREENWIDTH, SCREENHEIGHT, 1, 1,
+ { 0, 0, 0, 0, 0, 0, 0, 0 } };
+
+ V_DrawPatch(0, y, &tmp);
+ }
+}
+
+
+
+// Draws "Entering <LevelName>"
+void WI_drawEL(void)
+{
+ int y = WI_TITLEY;
+
+ // draw "Entering"
+ V_DrawPatch((SCREENWIDTH - SHORT(entering->width))/2,
+ y,
+ entering);
+
+ // draw level
+ y += (5*SHORT(lnames[wbs->next]->height))/4;
+
+ V_DrawPatch((SCREENWIDTH - SHORT(lnames[wbs->next]->width))/2,
+ y,
+ lnames[wbs->next]);
+
+}
+
+void
+WI_drawOnLnode
+( int n,
+ patch_t* c[] )
+{
+
+ int i;
+ int left;
+ int top;
+ int right;
+ int bottom;
+ boolean fits = false;
+
+ i = 0;
+ do
+ {
+ left = lnodes[wbs->epsd][n].x - SHORT(c[i]->leftoffset);
+ top = lnodes[wbs->epsd][n].y - SHORT(c[i]->topoffset);
+ right = left + SHORT(c[i]->width);
+ bottom = top + SHORT(c[i]->height);
+
+ if (left >= 0
+ && right < SCREENWIDTH
+ && top >= 0
+ && bottom < SCREENHEIGHT)
+ {
+ fits = true;
+ }
+ else
+ {
+ i++;
+ }
+ } while (!fits && i!=2 && c[i] != NULL);
+
+ if (fits && i<2)
+ {
+ V_DrawPatch(lnodes[wbs->epsd][n].x,
+ lnodes[wbs->epsd][n].y,
+ c[i]);
+ }
+ else
+ {
+ // DEBUG
+ printf("Could not place patch on level %d", n+1);
+ }
+}
+
+
+
+void WI_initAnimatedBack(void)
+{
+ int i;
+ anim_t* a;
+
+ if (gamemode == commercial)
+ return;
+
+ if (wbs->epsd > 2)
+ return;
+
+ for (i=0;i<NUMANIMS[wbs->epsd];i++)
+ {
+ a = &anims[wbs->epsd][i];
+
+ // init variables
+ a->ctr = -1;
+
+ // specify the next time to draw it
+ if (a->type == ANIM_ALWAYS)
+ a->nexttic = bcnt + 1 + (M_Random()%a->period);
+ else if (a->type == ANIM_RANDOM)
+ a->nexttic = bcnt + 1 + a->data2+(M_Random()%a->data1);
+ else if (a->type == ANIM_LEVEL)
+ a->nexttic = bcnt + 1;
+ }
+
+}
+
+void WI_updateAnimatedBack(void)
+{
+ int i;
+ anim_t* a;
+
+ if (gamemode == commercial)
+ return;
+
+ if (wbs->epsd > 2)
+ return;
+
+ for (i=0;i<NUMANIMS[wbs->epsd];i++)
+ {
+ a = &anims[wbs->epsd][i];
+
+ if (bcnt == a->nexttic)
+ {
+ switch (a->type)
+ {
+ case ANIM_ALWAYS:
+ if (++a->ctr >= a->nanims) a->ctr = 0;
+ a->nexttic = bcnt + a->period;
+ break;
+
+ case ANIM_RANDOM:
+ a->ctr++;
+ if (a->ctr == a->nanims)
+ {
+ a->ctr = -1;
+ a->nexttic = bcnt+a->data2+(M_Random()%a->data1);
+ }
+ else a->nexttic = bcnt + a->period;
+ break;
+
+ case ANIM_LEVEL:
+ // gawd-awful hack for level anims
+ if (!(state == StatCount && i == 7)
+ && wbs->next == a->data1)
+ {
+ a->ctr++;
+ if (a->ctr == a->nanims) a->ctr--;
+ a->nexttic = bcnt + a->period;
+ }
+ break;
+ }
+ }
+
+ }
+
+}
+
+void WI_drawAnimatedBack(void)
+{
+ int i;
+ anim_t* a;
+
+ if (gamemode == commercial)
+ return;
+
+ if (wbs->epsd > 2)
+ return;
+
+ for (i=0 ; i<NUMANIMS[wbs->epsd] ; i++)
+ {
+ a = &anims[wbs->epsd][i];
+
+ if (a->ctr >= 0)
+ V_DrawPatch(a->loc.x, a->loc.y, a->p[a->ctr]);
+ }
+
+}
+
+//
+// Draws a number.
+// If digits > 0, then use that many digits minimum,
+// otherwise only use as many as necessary.
+// Returns new x position.
+//
+
+int
+WI_drawNum
+( int x,
+ int y,
+ int n,
+ int digits )
+{
+
+ int fontwidth = SHORT(num[0]->width);
+ int neg;
+ int temp;
+
+ if (digits < 0)
+ {
+ if (!n)
+ {
+ // make variable-length zeros 1 digit long
+ digits = 1;
+ }
+ else
+ {
+ // figure out # of digits in #
+ digits = 0;
+ temp = n;
+
+ while (temp)
+ {
+ temp /= 10;
+ digits++;
+ }
+ }
+ }
+
+ neg = n < 0;
+ if (neg)
+ n = -n;
+
+ // if non-number, do not draw it
+ if (n == 1994)
+ return 0;
+
+ // draw the new number
+ while (digits--)
+ {
+ x -= fontwidth;
+ V_DrawPatch(x, y, num[ n % 10 ]);
+ n /= 10;
+ }
+
+ // draw a minus sign if necessary
+ if (neg)
+ V_DrawPatch(x-=8, y, wiminus);
+
+ return x;
+
+}
+
+void
+WI_drawPercent
+( int x,
+ int y,
+ int p )
+{
+ if (p < 0)
+ return;
+
+ V_DrawPatch(x, y, percent);
+ WI_drawNum(x, y, p, -1);
+}
+
+
+
+//
+// Display level completion time and par,
+// or "sucks" message if overflow.
+//
+void
+WI_drawTime
+( int x,
+ int y,
+ int t )
+{
+
+ int div;
+ int n;
+
+ if (t<0)
+ return;
+
+ if (t <= 61*59)
+ {
+ div = 1;
+
+ do
+ {
+ n = (t / div) % 60;
+ x = WI_drawNum(x, y, n, 2) - SHORT(colon->width);
+ div *= 60;
+
+ // draw
+ if (div==60 || t / div)
+ V_DrawPatch(x, y, colon);
+
+ } while (t / div);
+ }
+ else
+ {
+ // "sucks"
+ V_DrawPatch(x - SHORT(sucks->width), y, sucks);
+ }
+}
+
+
+void WI_End(void)
+{
+ void WI_unloadData(void);
+ WI_unloadData();
+}
+
+void WI_initNoState(void)
+{
+ state = NoState;
+ acceleratestage = 0;
+ cnt = 10;
+}
+
+void WI_updateNoState(void) {
+
+ WI_updateAnimatedBack();
+
+ if (!--cnt)
+ {
+ // Don't call WI_End yet. G_WorldDone doesnt immediately
+ // change gamestate, so WI_Drawer is still going to get
+ // run until that happens. If we do that after WI_End
+ // (which unloads all the graphics), we're in trouble.
+ //WI_End();
+ G_WorldDone();
+ }
+
+}
+
+static boolean snl_pointeron = false;
+
+
+void WI_initShowNextLoc(void)
+{
+ state = ShowNextLoc;
+ acceleratestage = 0;
+ cnt = SHOWNEXTLOCDELAY * TICRATE;
+
+ WI_initAnimatedBack();
+}
+
+void WI_updateShowNextLoc(void)
+{
+ WI_updateAnimatedBack();
+
+ if (!--cnt || acceleratestage)
+ WI_initNoState();
+ else
+ snl_pointeron = (cnt & 31) < 20;
+}
+
+void WI_drawShowNextLoc(void)
+{
+
+ int i;
+ int last;
+
+ WI_slamBackground();
+
+ // draw animated background
+ WI_drawAnimatedBack();
+
+ if ( gamemode != commercial)
+ {
+ if (wbs->epsd > 2)
+ {
+ WI_drawEL();
+ return;
+ }
+
+ last = (wbs->last == 8) ? wbs->next - 1 : wbs->last;
+
+ // draw a splat on taken cities.
+ for (i=0 ; i<=last ; i++)
+ WI_drawOnLnode(i, splat);
+
+ // splat the secret level?
+ if (wbs->didsecret)
+ WI_drawOnLnode(8, splat);
+
+ // draw flashing ptr
+ if (snl_pointeron)
+ WI_drawOnLnode(wbs->next, yah);
+ }
+
+ // draws which level you are entering..
+ if ( (gamemode != commercial)
+ || wbs->next != 30)
+ WI_drawEL();
+
+}
+
+void WI_drawNoState(void)
+{
+ snl_pointeron = true;
+ WI_drawShowNextLoc();
+}
+
+int WI_fragSum(int playernum)
+{
+ int i;
+ int frags = 0;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (playeringame[i]
+ && i!=playernum)
+ {
+ frags += plrs[playernum].frags[i];
+ }
+ }
+
+
+ // JDC hack - negative frags.
+ frags -= plrs[playernum].frags[playernum];
+ // UNUSED if (frags < 0)
+ // frags = 0;
+
+ return frags;
+}
+
+
+
+static int dm_state;
+static int dm_frags[MAXPLAYERS][MAXPLAYERS];
+static int dm_totals[MAXPLAYERS];
+
+
+
+void WI_initDeathmatchStats(void)
+{
+
+ int i;
+ int j;
+
+ state = StatCount;
+ acceleratestage = 0;
+ dm_state = 1;
+
+ cnt_pause = TICRATE;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (playeringame[i])
+ {
+ for (j=0 ; j<MAXPLAYERS ; j++)
+ if (playeringame[j])
+ dm_frags[i][j] = 0;
+
+ dm_totals[i] = 0;
+ }
+ }
+
+ WI_initAnimatedBack();
+}
+
+
+
+void WI_updateDeathmatchStats(void)
+{
+
+ int i;
+ int j;
+
+ boolean stillticking;
+
+ WI_updateAnimatedBack();
+
+ if (acceleratestage && dm_state != 4)
+ {
+ acceleratestage = 0;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (playeringame[i])
+ {
+ for (j=0 ; j<MAXPLAYERS ; j++)
+ if (playeringame[j])
+ dm_frags[i][j] = plrs[i].frags[j];
+
+ dm_totals[i] = WI_fragSum(i);
+ }
+ }
+
+
+ S_StartSound(0, sfx_barexp);
+ dm_state = 4;
+ }
+
+
+ if (dm_state == 2)
+ {
+ if (!(bcnt&3))
+ S_StartSound(0, sfx_pistol);
+
+ stillticking = false;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (playeringame[i])
+ {
+ for (j=0 ; j<MAXPLAYERS ; j++)
+ {
+ if (playeringame[j]
+ && dm_frags[i][j] != plrs[i].frags[j])
+ {
+ if (plrs[i].frags[j] < 0)
+ dm_frags[i][j]--;
+ else
+ dm_frags[i][j]++;
+
+ if (dm_frags[i][j] > 99)
+ dm_frags[i][j] = 99;
+
+ if (dm_frags[i][j] < -99)
+ dm_frags[i][j] = -99;
+
+ stillticking = true;
+ }
+ }
+ dm_totals[i] = WI_fragSum(i);
+
+ if (dm_totals[i] > 99)
+ dm_totals[i] = 99;
+
+ if (dm_totals[i] < -99)
+ dm_totals[i] = -99;
+ }
+
+ }
+ if (!stillticking)
+ {
+ S_StartSound(0, sfx_barexp);
+ dm_state++;
+ }
+
+ }
+ else if (dm_state == 4)
+ {
+ if (acceleratestage)
+ {
+ S_StartSound(0, sfx_slop);
+
+ if ( gamemode == commercial)
+ WI_initNoState();
+ else
+ WI_initShowNextLoc();
+ }
+ }
+ else if (dm_state & 1)
+ {
+ if (!--cnt_pause)
+ {
+ dm_state++;
+ cnt_pause = TICRATE;
+ }
+ }
+}
+
+
+
+void WI_drawDeathmatchStats(void)
+{
+
+ int i;
+ int j;
+ int x;
+ int y;
+ int w;
+
+ int lh; // line height
+
+ lh = WI_SPACINGY;
+
+ WI_slamBackground();
+
+ // draw animated background
+ WI_drawAnimatedBack();
+ WI_drawLF();
+
+ // draw stat titles (top line)
+ V_DrawPatch(DM_TOTALSX-SHORT(total->width)/2,
+ DM_MATRIXY-WI_SPACINGY+10,
+ total);
+
+ V_DrawPatch(DM_KILLERSX, DM_KILLERSY, killers);
+ V_DrawPatch(DM_VICTIMSX, DM_VICTIMSY, victims);
+
+ // draw P?
+ x = DM_MATRIXX + DM_SPACINGX;
+ y = DM_MATRIXY;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (playeringame[i])
+ {
+ V_DrawPatch(x-SHORT(p[i]->width)/2,
+ DM_MATRIXY - WI_SPACINGY,
+ p[i]);
+
+ V_DrawPatch(DM_MATRIXX-SHORT(p[i]->width)/2,
+ y,
+ p[i]);
+
+ if (i == me)
+ {
+ V_DrawPatch(x-SHORT(p[i]->width)/2,
+ DM_MATRIXY - WI_SPACINGY,
+ bstar);
+
+ V_DrawPatch(DM_MATRIXX-SHORT(p[i]->width)/2,
+ y,
+ star);
+ }
+ }
+ else
+ {
+ // V_DrawPatch(x-SHORT(bp[i]->width)/2,
+ // DM_MATRIXY - WI_SPACINGY, bp[i]);
+ // V_DrawPatch(DM_MATRIXX-SHORT(bp[i]->width)/2,
+ // y, bp[i]);
+ }
+ x += DM_SPACINGX;
+ y += WI_SPACINGY;
+ }
+
+ // draw stats
+ y = DM_MATRIXY+10;
+ w = SHORT(num[0]->width);
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ x = DM_MATRIXX + DM_SPACINGX;
+
+ if (playeringame[i])
+ {
+ for (j=0 ; j<MAXPLAYERS ; j++)
+ {
+ if (playeringame[j])
+ WI_drawNum(x+w, y, dm_frags[i][j], 2);
+
+ x += DM_SPACINGX;
+ }
+ WI_drawNum(DM_TOTALSX+w, y, dm_totals[i], 2);
+ }
+ y += WI_SPACINGY;
+ }
+}
+
+static int cnt_frags[MAXPLAYERS];
+static int dofrags;
+static int ng_state;
+
+void WI_initNetgameStats(void)
+{
+
+ int i;
+
+ state = StatCount;
+ acceleratestage = 0;
+ ng_state = 1;
+
+ cnt_pause = TICRATE;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (!playeringame[i])
+ continue;
+
+ cnt_kills[i] = cnt_items[i] = cnt_secret[i] = cnt_frags[i] = 0;
+
+ dofrags += WI_fragSum(i);
+ }
+
+ dofrags = !!dofrags;
+
+ WI_initAnimatedBack();
+}
+
+
+
+void WI_updateNetgameStats(void)
+{
+
+ int i;
+ int fsum;
+
+ boolean stillticking;
+
+ WI_updateAnimatedBack();
+
+ if (acceleratestage && ng_state != 10)
+ {
+ acceleratestage = 0;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (!playeringame[i])
+ continue;
+
+ cnt_kills[i] = (plrs[i].skills * 100) / wbs->maxkills;
+ cnt_items[i] = (plrs[i].sitems * 100) / wbs->maxitems;
+ cnt_secret[i] = (plrs[i].ssecret * 100) / wbs->maxsecret;
+
+ if (dofrags)
+ cnt_frags[i] = WI_fragSum(i);
+ }
+ S_StartSound(0, sfx_barexp);
+ ng_state = 10;
+ }
+
+ if (ng_state == 2)
+ {
+ if (!(bcnt&3))
+ S_StartSound(0, sfx_pistol);
+
+ stillticking = false;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (!playeringame[i])
+ continue;
+
+ cnt_kills[i] += 2;
+
+ if (cnt_kills[i] >= (plrs[i].skills * 100) / wbs->maxkills)
+ cnt_kills[i] = (plrs[i].skills * 100) / wbs->maxkills;
+ else
+ stillticking = true;
+ }
+
+ if (!stillticking)
+ {
+ S_StartSound(0, sfx_barexp);
+ ng_state++;
+ }
+ }
+ else if (ng_state == 4)
+ {
+ if (!(bcnt&3))
+ S_StartSound(0, sfx_pistol);
+
+ stillticking = false;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (!playeringame[i])
+ continue;
+
+ cnt_items[i] += 2;
+ if (cnt_items[i] >= (plrs[i].sitems * 100) / wbs->maxitems)
+ cnt_items[i] = (plrs[i].sitems * 100) / wbs->maxitems;
+ else
+ stillticking = true;
+ }
+ if (!stillticking)
+ {
+ S_StartSound(0, sfx_barexp);
+ ng_state++;
+ }
+ }
+ else if (ng_state == 6)
+ {
+ if (!(bcnt&3))
+ S_StartSound(0, sfx_pistol);
+
+ stillticking = false;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (!playeringame[i])
+ continue;
+
+ cnt_secret[i] += 2;
+
+ if (cnt_secret[i] >= (plrs[i].ssecret * 100) / wbs->maxsecret)
+ cnt_secret[i] = (plrs[i].ssecret * 100) / wbs->maxsecret;
+ else
+ stillticking = true;
+ }
+
+ if (!stillticking)
+ {
+ S_StartSound(0, sfx_barexp);
+ ng_state += 1 + 2*!dofrags;
+ }
+ }
+ else if (ng_state == 8)
+ {
+ if (!(bcnt&3))
+ S_StartSound(0, sfx_pistol);
+
+ stillticking = false;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (!playeringame[i])
+ continue;
+
+ cnt_frags[i] += 1;
+
+ if (cnt_frags[i] >= (fsum = WI_fragSum(i)))
+ cnt_frags[i] = fsum;
+ else
+ stillticking = true;
+ }
+
+ if (!stillticking)
+ {
+ S_StartSound(0, sfx_pldeth);
+ ng_state++;
+ }
+ }
+ else if (ng_state == 10)
+ {
+ if (acceleratestage)
+ {
+ S_StartSound(0, sfx_sgcock);
+ if ( gamemode == commercial )
+ WI_initNoState();
+ else
+ WI_initShowNextLoc();
+ }
+ }
+ else if (ng_state & 1)
+ {
+ if (!--cnt_pause)
+ {
+ ng_state++;
+ cnt_pause = TICRATE;
+ }
+ }
+}
+
+
+
+void WI_drawNetgameStats(void)
+{
+ int i;
+ int x;
+ int y;
+ int pwidth = SHORT(percent->width);
+
+ WI_slamBackground();
+
+ // draw animated background
+ WI_drawAnimatedBack();
+
+ WI_drawLF();
+
+ // draw stat titles (top line)
+ V_DrawPatch(NG_STATSX+NG_SPACINGX-SHORT(kills->width),
+ NG_STATSY, kills);
+
+ V_DrawPatch(NG_STATSX+2*NG_SPACINGX-SHORT(items->width),
+ NG_STATSY, items);
+
+ V_DrawPatch(NG_STATSX+3*NG_SPACINGX-SHORT(secret->width),
+ NG_STATSY, secret);
+
+ if (dofrags)
+ V_DrawPatch(NG_STATSX+4*NG_SPACINGX-SHORT(frags->width),
+ NG_STATSY, frags);
+
+ // draw stats
+ y = NG_STATSY + SHORT(kills->height);
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (!playeringame[i])
+ continue;
+
+ x = NG_STATSX;
+ V_DrawPatch(x-SHORT(p[i]->width), y, p[i]);
+
+ if (i == me)
+ V_DrawPatch(x-SHORT(p[i]->width), y, star);
+
+ x += NG_SPACINGX;
+ WI_drawPercent(x-pwidth, y+10, cnt_kills[i]); x += NG_SPACINGX;
+ WI_drawPercent(x-pwidth, y+10, cnt_items[i]); x += NG_SPACINGX;
+ WI_drawPercent(x-pwidth, y+10, cnt_secret[i]); x += NG_SPACINGX;
+
+ if (dofrags)
+ WI_drawNum(x, y+10, cnt_frags[i], -1);
+
+ y += WI_SPACINGY;
+ }
+
+}
+
+static int sp_state;
+
+void WI_initStats(void)
+{
+ state = StatCount;
+ acceleratestage = 0;
+ sp_state = 1;
+ cnt_kills[0] = cnt_items[0] = cnt_secret[0] = -1;
+ cnt_time = cnt_par = -1;
+ cnt_pause = TICRATE;
+
+ WI_initAnimatedBack();
+}
+
+void WI_updateStats(void)
+{
+
+ WI_updateAnimatedBack();
+
+ if (acceleratestage && sp_state != 10)
+ {
+ acceleratestage = 0;
+ cnt_kills[0] = (plrs[me].skills * 100) / wbs->maxkills;
+ cnt_items[0] = (plrs[me].sitems * 100) / wbs->maxitems;
+ cnt_secret[0] = (plrs[me].ssecret * 100) / wbs->maxsecret;
+ cnt_time = plrs[me].stime / TICRATE;
+ cnt_par = wbs->partime / TICRATE;
+ S_StartSound(0, sfx_barexp);
+ sp_state = 10;
+ }
+
+ if (sp_state == 2)
+ {
+ cnt_kills[0] += 2;
+
+ if (!(bcnt&3))
+ S_StartSound(0, sfx_pistol);
+
+ if (cnt_kills[0] >= (plrs[me].skills * 100) / wbs->maxkills)
+ {
+ cnt_kills[0] = (plrs[me].skills * 100) / wbs->maxkills;
+ S_StartSound(0, sfx_barexp);
+ sp_state++;
+ }
+ }
+ else if (sp_state == 4)
+ {
+ cnt_items[0] += 2;
+
+ if (!(bcnt&3))
+ S_StartSound(0, sfx_pistol);
+
+ if (cnt_items[0] >= (plrs[me].sitems * 100) / wbs->maxitems)
+ {
+ cnt_items[0] = (plrs[me].sitems * 100) / wbs->maxitems;
+ S_StartSound(0, sfx_barexp);
+ sp_state++;
+ }
+ }
+ else if (sp_state == 6)
+ {
+ cnt_secret[0] += 2;
+
+ if (!(bcnt&3))
+ S_StartSound(0, sfx_pistol);
+
+ if (cnt_secret[0] >= (plrs[me].ssecret * 100) / wbs->maxsecret)
+ {
+ cnt_secret[0] = (plrs[me].ssecret * 100) / wbs->maxsecret;
+ S_StartSound(0, sfx_barexp);
+ sp_state++;
+ }
+ }
+
+ else if (sp_state == 8)
+ {
+ if (!(bcnt&3))
+ S_StartSound(0, sfx_pistol);
+
+ cnt_time += 3;
+
+ if (cnt_time >= plrs[me].stime / TICRATE)
+ cnt_time = plrs[me].stime / TICRATE;
+
+ cnt_par += 3;
+
+ if (cnt_par >= wbs->partime / TICRATE)
+ {
+ cnt_par = wbs->partime / TICRATE;
+
+ if (cnt_time >= plrs[me].stime / TICRATE)
+ {
+ S_StartSound(0, sfx_barexp);
+ sp_state++;
+ }
+ }
+ }
+ else if (sp_state == 10)
+ {
+ if (acceleratestage)
+ {
+ S_StartSound(0, sfx_sgcock);
+
+ if (gamemode == commercial)
+ WI_initNoState();
+ else
+ WI_initShowNextLoc();
+ }
+ }
+ else if (sp_state & 1)
+ {
+ if (!--cnt_pause)
+ {
+ sp_state++;
+ cnt_pause = TICRATE;
+ }
+ }
+
+}
+
+void WI_drawStats(void)
+{
+ // line height
+ int lh;
+
+ lh = (3*SHORT(num[0]->height))/2;
+
+ WI_slamBackground();
+
+ // draw animated background
+ WI_drawAnimatedBack();
+
+ WI_drawLF();
+
+ V_DrawPatch(SP_STATSX, SP_STATSY, kills);
+ WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY, cnt_kills[0]);
+
+ V_DrawPatch(SP_STATSX, SP_STATSY+lh, items);
+ WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY+lh, cnt_items[0]);
+
+ V_DrawPatch(SP_STATSX, SP_STATSY+2*lh, sp_secret);
+ WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY+2*lh, cnt_secret[0]);
+
+ V_DrawPatch(SP_TIMEX, SP_TIMEY, timepatch);
+ WI_drawTime(SCREENWIDTH/2 - SP_TIMEX, SP_TIMEY, cnt_time);
+
+ if (wbs->epsd < 3)
+ {
+ V_DrawPatch(SCREENWIDTH/2 + SP_TIMEX, SP_TIMEY, par);
+ WI_drawTime(SCREENWIDTH - SP_TIMEX, SP_TIMEY, cnt_par);
+ }
+
+}
+
+void WI_checkForAccelerate(void)
+{
+ int i;
+ player_t *player;
+
+ // check for button presses to skip delays
+ for (i=0, player = players ; i<MAXPLAYERS ; i++, player++)
+ {
+ if (playeringame[i])
+ {
+ if (player->cmd.buttons & BT_ATTACK)
+ {
+ if (!player->attackdown)
+ acceleratestage = 1;
+ player->attackdown = true;
+ }
+ else
+ player->attackdown = false;
+ if (player->cmd.buttons & BT_USE)
+ {
+ if (!player->usedown)
+ acceleratestage = 1;
+ player->usedown = true;
+ }
+ else
+ player->usedown = false;
+ }
+ }
+}
+
+
+
+// Updates stuff each tick
+void WI_Ticker(void)
+{
+ // counter for general background animation
+ bcnt++;
+
+ if (bcnt == 1)
+ {
+ // intermission music
+ if ( gamemode == commercial )
+ S_ChangeMusic(mus_dm2int, true);
+ else
+ S_ChangeMusic(mus_inter, true);
+ }
+
+ WI_checkForAccelerate();
+
+ switch (state)
+ {
+ case StatCount:
+ if (deathmatch) WI_updateDeathmatchStats();
+ else if (netgame) WI_updateNetgameStats();
+ else WI_updateStats();
+ break;
+
+ case ShowNextLoc:
+ WI_updateShowNextLoc();
+ break;
+
+ case NoState:
+ WI_updateNoState();
+ break;
+ }
+
+}
+
+typedef void (*load_callback_t)(char *lumpname, patch_t **variable);
+
+// Common load/unload function. Iterates over all the graphics
+// lumps to be loaded/unloaded into memory.
+
+static void WI_loadUnloadData(load_callback_t callback)
+{
+ int i, j;
+ char name[9];
+ anim_t *a;
+
+ if (gamemode == commercial)
+ {
+ for (i=0 ; i<NUMCMAPS ; i++)
+ {
+ DEH_snprintf(name, 9, "CWILV%2.2d", i);
+ callback(name, &lnames[i]);
+ }
+ }
+ else
+ {
+ for (i=0 ; i<NUMMAPS ; i++)
+ {
+ DEH_snprintf(name, 9, "WILV%d%d", wbs->epsd, i);
+ callback(name, &lnames[i]);
+ }
+
+ // you are here
+ callback(DEH_String("WIURH0"), &yah[0]);
+
+ // you are here (alt.)
+ callback(DEH_String("WIURH1"), &yah[1]);
+
+ // splat
+ callback(DEH_String("WISPLAT"), &splat[0]);
+
+ if (wbs->epsd < 3)
+ {
+ for (j=0;j<NUMANIMS[wbs->epsd];j++)
+ {
+ a = &anims[wbs->epsd][j];
+ for (i=0;i<a->nanims;i++)
+ {
+ // MONDO HACK!
+ if (wbs->epsd != 1 || j != 8)
+ {
+ // animations
+ DEH_snprintf(name, 9, "WIA%d%.2d%.2d", wbs->epsd, j, i);
+ callback(name, &a->p[i]);
+ }
+ else
+ {
+ // HACK ALERT!
+ a->p[i] = anims[1][4].p[i];
+ }
+ }
+ }
+ }
+ }
+
+ // More hacks on minus sign.
+ callback(DEH_String("WIMINUS"), &wiminus);
+
+ for (i=0;i<10;i++)
+ {
+ // numbers 0-9
+ DEH_snprintf(name, 9, "WINUM%d", i);
+ callback(name, &num[i]);
+ }
+
+ // percent sign
+ callback(DEH_String("WIPCNT"), &percent);
+
+ // "finished"
+ callback(DEH_String("WIF"), &finished);
+
+ // "entering"
+ callback(DEH_String("WIENTER"), &entering);
+
+ // "kills"
+ callback(DEH_String("WIOSTK"), &kills);
+
+ // "scrt"
+ callback(DEH_String("WIOSTS"), &secret);
+
+ // "secret"
+ callback(DEH_String("WISCRT2"), &sp_secret);
+
+ // french wad uses WIOBJ (?)
+ if (W_CheckNumForName(DEH_String("WIOBJ")) >= 0)
+ {
+ // "items"
+ if (netgame && !deathmatch)
+ callback(DEH_String("WIOBJ"), &items);
+ else
+ callback(DEH_String("WIOSTI"), &items);
+ } else {
+ callback(DEH_String("WIOSTI"), &items);
+ }
+
+ // "frgs"
+ callback(DEH_String("WIFRGS"), &frags);
+
+ // ":"
+ callback(DEH_String("WICOLON"), &colon);
+
+ // "time"
+ callback(DEH_String("WITIME"), &timepatch);
+
+ // "sucks"
+ callback(DEH_String("WISUCKS"), &sucks);
+
+ // "par"
+ callback(DEH_String("WIPAR"), &par);
+
+ // "killers" (vertical)
+ callback(DEH_String("WIKILRS"), &killers);
+
+ // "victims" (horiz)
+ callback(DEH_String("WIVCTMS"), &victims);
+
+ // "total"
+ callback(DEH_String("WIMSTT"), &total);
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ // "1,2,3,4"
+ DEH_snprintf(name, 9, "STPB%d", i);
+ callback(name, &p[i]);
+
+ // "1,2,3,4"
+ DEH_snprintf(name, 9, "WIBP%d", i+1);
+ callback(name, &bp[i]);
+ }
+
+ // Background image
+
+ if (gamemode == commercial)
+ {
+ strncpy(name, DEH_String("INTERPIC"), 9);
+ name[8] = '\0';
+ }
+ else if (gamemode == retail && wbs->epsd == 3)
+ {
+ strncpy(name, DEH_String("INTERPIC"), 9);
+ name[8] = '\0';
+ }
+ else
+ {
+ DEH_snprintf(name, 9, "WIMAP%d", wbs->epsd);
+ }
+
+ // Draw backdrop and save to a temporary buffer
+
+ callback(name, &background);
+}
+
+static void WI_loadCallback(char *name, patch_t **variable)
+{
+ *variable = W_CacheLumpName(name, PU_STATIC);
+}
+
+void WI_loadData(void)
+{
+ if (gamemode == commercial)
+ {
+ NUMCMAPS = 32;
+ lnames = (patch_t **) Z_Malloc(sizeof(patch_t*) * NUMCMAPS,
+ PU_STATIC, NULL);
+ }
+ else
+ {
+ lnames = (patch_t **) Z_Malloc(sizeof(patch_t*) * NUMMAPS,
+ PU_STATIC, NULL);
+ }
+
+ WI_loadUnloadData(WI_loadCallback);
+
+ // These two graphics are special cased because we're sharing
+ // them with the status bar code
+
+ // your face
+ star = W_CacheLumpName(DEH_String("STFST01"), PU_STATIC);
+
+ // dead face
+ bstar = W_CacheLumpName(DEH_String("STFDEAD0"), PU_STATIC);
+}
+
+static void WI_unloadCallback(char *name, patch_t **variable)
+{
+ W_ReleaseLumpName(name);
+ *variable = NULL;
+}
+
+void WI_unloadData(void)
+{
+ WI_loadUnloadData(WI_unloadCallback);
+
+ // We do not free these lumps as they are shared with the status
+ // bar code.
+
+ // W_ReleaseLumpName("STFST01");
+ // W_ReleaseLumpName("STFDEAD0");
+}
+
+void WI_Drawer (void)
+{
+ switch (state)
+ {
+ case StatCount:
+ if (deathmatch)
+ WI_drawDeathmatchStats();
+ else if (netgame)
+ WI_drawNetgameStats();
+ else
+ WI_drawStats();
+ break;
+
+ case ShowNextLoc:
+ WI_drawShowNextLoc();
+ break;
+
+ case NoState:
+ WI_drawNoState();
+ break;
+ }
+}
+
+
+void WI_initVariables(wbstartstruct_t* wbstartstruct)
+{
+
+ wbs = wbstartstruct;
+
+#ifdef RANGECHECKING
+ if (gamemode != commercial)
+ {
+ if ( gamemode == retail )
+ RNGCHECK(wbs->epsd, 0, 3);
+ else
+ RNGCHECK(wbs->epsd, 0, 2);
+ }
+ else
+ {
+ RNGCHECK(wbs->last, 0, 8);
+ RNGCHECK(wbs->next, 0, 8);
+ }
+ RNGCHECK(wbs->pnum, 0, MAXPLAYERS);
+ RNGCHECK(wbs->pnum, 0, MAXPLAYERS);
+#endif
+
+ acceleratestage = 0;
+ cnt = bcnt = 0;
+ firstrefresh = 1;
+ me = wbs->pnum;
+ plrs = wbs->plyr;
+
+ if (!wbs->maxkills)
+ wbs->maxkills = 1;
+
+ if (!wbs->maxitems)
+ wbs->maxitems = 1;
+
+ if (!wbs->maxsecret)
+ wbs->maxsecret = 1;
+
+ if ( gamemode != retail )
+ if (wbs->epsd > 2)
+ wbs->epsd -= 3;
+}
+
+void WI_Start(wbstartstruct_t* wbstartstruct)
+{
+ WI_initVariables(wbstartstruct);
+ WI_loadData();
+
+ if (deathmatch)
+ WI_initDeathmatchStats();
+ else if (netgame)
+ WI_initNetgameStats();
+ else
+ WI_initStats();
+}
+#endif
diff --git a/src/strife/wi_stuff.h b/src/strife/wi_stuff.h
new file mode 100644
index 00000000..3ddd4950
--- /dev/null
+++ b/src/strife/wi_stuff.h
@@ -0,0 +1,59 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Intermission.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef __WI_STUFF__
+#define __WI_STUFF__
+
+// haleyjd 08/23/2010: Strife does not have an intermission
+#if 0
+//#include "v_video.h"
+
+#include "doomdef.h"
+
+// States for the intermission
+
+typedef enum
+{
+ NoState = -1,
+ StatCount,
+ ShowNextLoc,
+} stateenum_t;
+
+// Called by main loop, animate the intermission.
+void WI_Ticker (void);
+
+// Called by main loop,
+// draws the intermission directly into the screen buffer.
+void WI_Drawer (void);
+
+// Setup for an intermission screen.
+void WI_Start(wbstartstruct_t* wbstartstruct);
+
+// Shut down the intermission screen
+void WI_End(void);
+
+#endif
+#endif
diff --git a/src/tables.c b/src/tables.c
index ffafeb7e..480d1a6d 100644
--- a/src/tables.c
+++ b/src/tables.c
@@ -38,33 +38,37 @@
//
//-----------------------------------------------------------------------------
-
-
-
-
#include "tables.h"
+// to get a global angle from cartesian coordinates, the coordinates are
+// flipped until they are in the first octant of the coordinate system, then
+// the y (<=x) is scaled and divided by x to get a tangent (slope) value
+// which is looked up in the tantoangle[] table. The +1 size is to handle
+// the case when x==y without additional checking.
-
-
-int
-SlopeDiv
-( unsigned num,
- unsigned den)
+int SlopeDiv(unsigned int num, unsigned int den)
{
- unsigned ans;
+ unsigned ans;
if (den < 512)
- return SLOPERANGE;
-
- ans = (num<<3)/(den>>8);
+ {
+ return SLOPERANGE;
+ }
+ else
+ {
+ ans = (num << 3) / (den >> 8);
- return ans <= SLOPERANGE ? ans : SLOPERANGE;
+ if (ans <= SLOPERANGE)
+ {
+ return ans;
+ }
+ else
+ {
+ return SLOPERANGE;
+ }
+ }
}
-
-
-
const int finetangent[4096] =
{
-170910304,-56965752,-34178904,-24413316,-18988036,-15535599,-13145455,-11392683,
@@ -1866,7 +1870,7 @@ const int finesine[10240] =
65534,65535,65535,65535,65535,65535,65535,65535
};
-
+const fixed_t *finecosine = &finesine[FINEANGLES/4];
const angle_t tantoangle[2049] =
{
@@ -2129,3 +2133,103 @@ const angle_t tantoangle[2049] =
536870912
};
+// Now where did these came from?
+const byte gammatable[5][256] =
+{
+ {
+ 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,32,
+ 33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,
+ 49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,
+ 65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,
+ 81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,
+ 97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,
+ 113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,
+ 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
+ 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
+ 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
+ 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
+ 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
+ 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
+ 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
+ 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
+ },
+
+ {
+ 2,4,5,7,8,10,11,12,14,15,16,18,19,20,21,23,
+ 24,25,26,27,29,30,31,32,33,34,36,37,38,39,40,41,
+ 42,44,45,46,47,48,49,50,51,52,54,55,56,57,58,59,
+ 60,61,62,63,64,65,66,67,69,70,71,72,73,74,75,76,
+ 77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,
+ 93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,
+ 109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,
+ 125,126,127,128,129,129,130,131,132,133,134,135,136,137,138,139,
+ 140,141,142,143,144,145,146,147,148,148,149,150,151,152,153,154,
+ 155,156,157,158,159,160,161,162,163,163,164,165,166,167,168,169,
+ 170,171,172,173,174,175,175,176,177,178,179,180,181,182,183,184,
+ 185,186,186,187,188,189,190,191,192,193,194,195,196,196,197,198,
+ 199,200,201,202,203,204,205,205,206,207,208,209,210,211,212,213,
+ 214,214,215,216,217,218,219,220,221,222,222,223,224,225,226,227,
+ 228,229,230,230,231,232,233,234,235,236,237,237,238,239,240,241,
+ 242,243,244,245,245,246,247,248,249,250,251,252,252,253,254,255
+ },
+
+ {
+ 4,7,9,11,13,15,17,19,21,22,24,26,27,29,30,32,
+ 33,35,36,38,39,40,42,43,45,46,47,48,50,51,52,54,
+ 55,56,57,59,60,61,62,63,65,66,67,68,69,70,72,73,
+ 74,75,76,77,78,79,80,82,83,84,85,86,87,88,89,90,
+ 91,92,93,94,95,96,97,98,100,101,102,103,104,105,106,107,
+ 108,109,110,111,112,113,114,114,115,116,117,118,119,120,121,122,
+ 123,124,125,126,127,128,129,130,131,132,133,133,134,135,136,137,
+ 138,139,140,141,142,143,144,144,145,146,147,148,149,150,151,152,
+ 153,153,154,155,156,157,158,159,160,160,161,162,163,164,165,166,
+ 166,167,168,169,170,171,172,172,173,174,175,176,177,178,178,179,
+ 180,181,182,183,183,184,185,186,187,188,188,189,190,191,192,193,
+ 193,194,195,196,197,197,198,199,200,201,201,202,203,204,205,206,
+ 206,207,208,209,210,210,211,212,213,213,214,215,216,217,217,218,
+ 219,220,221,221,222,223,224,224,225,226,227,228,228,229,230,231,
+ 231,232,233,234,235,235,236,237,238,238,239,240,241,241,242,243,
+ 244,244,245,246,247,247,248,249,250,251,251,252,253,254,254,255
+ },
+
+ {
+ 8,12,16,19,22,24,27,29,31,34,36,38,40,41,43,45,
+ 47,49,50,52,53,55,57,58,60,61,63,64,65,67,68,70,
+ 71,72,74,75,76,77,79,80,81,82,84,85,86,87,88,90,
+ 91,92,93,94,95,96,98,99,100,101,102,103,104,105,106,107,
+ 108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,
+ 124,125,126,127,128,129,130,131,132,133,134,135,135,136,137,138,
+ 139,140,141,142,143,143,144,145,146,147,148,149,150,150,151,152,
+ 153,154,155,155,156,157,158,159,160,160,161,162,163,164,165,165,
+ 166,167,168,169,169,170,171,172,173,173,174,175,176,176,177,178,
+ 179,180,180,181,182,183,183,184,185,186,186,187,188,189,189,190,
+ 191,192,192,193,194,195,195,196,197,197,198,199,200,200,201,202,
+ 202,203,204,205,205,206,207,207,208,209,210,210,211,212,212,213,
+ 214,214,215,216,216,217,218,219,219,220,221,221,222,223,223,224,
+ 225,225,226,227,227,228,229,229,230,231,231,232,233,233,234,235,
+ 235,236,237,237,238,238,239,240,240,241,242,242,243,244,244,245,
+ 246,246,247,247,248,249,249,250,251,251,252,253,253,254,254,255
+ },
+
+
+ {
+ 16,23,28,32,36,39,42,45,48,50,53,55,57,60,62,64,
+ 66,68,69,71,73,75,76,78,80,81,83,84,86,87,89,90,
+ 92,93,94,96,97,98,100,101,102,103,105,106,107,108,109,110,
+ 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,128,
+ 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
+ 143,144,145,146,147,148,149,150,150,151,152,153,154,155,155,156,
+ 157,158,159,159,160,161,162,163,163,164,165,166,166,167,168,169,
+ 169,170,171,172,172,173,174,175,175,176,177,177,178,179,180,180,
+ 181,182,182,183,184,184,185,186,187,187,188,189,189,190,191,191,
+ 192,193,193,194,195,195,196,196,197,198,198,199,200,200,201,202,
+ 202,203,203,204,205,205,206,207,207,208,208,209,210,210,211,211,
+ 212,213,213,214,214,215,216,216,217,217,218,219,219,220,220,221,
+ 221,222,223,223,224,224,225,225,226,227,227,228,228,229,229,230,
+ 230,231,232,232,233,233,234,234,235,235,236,236,237,237,238,239,
+ 239,240,240,241,241,242,242,243,243,244,244,245,245,246,246,247,
+ 247,248,248,249,249,250,250,251,251,252,252,253,254,254,255,255
+ }
+};
+
diff --git a/src/tables.h b/src/tables.h
index baf785ca..f4fd1f55 100644
--- a/src/tables.h
+++ b/src/tables.h
@@ -2,6 +2,7 @@
//-----------------------------------------------------------------------------
//
// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
// Copyright(C) 2005 Simon Howard
//
// This program is free software; you can redistribute it and/or
@@ -41,7 +42,7 @@
#ifndef __TABLES__
#define __TABLES__
-
+#include "doomtype.h"
#include "m_fixed.h"
@@ -62,12 +63,24 @@ extern const fixed_t *finecosine;
// Effective size is 4096.
extern const fixed_t finetangent[FINEANGLES/2];
+// Gamma correction tables.
+extern const byte gammatable[5][256];
+
// Binary Angle Measument, BAM.
-#define ANG45 0x20000000
-#define ANG90 0x40000000
-#define ANG180 0x80000000
-#define ANG270 0xc0000000
+#define ANG45 0x20000000
+#define ANG90 0x40000000
+#define ANG180 0x80000000
+#define ANG270 0xc0000000
+#define ANG_MAX 0xffffffff
+
+#define ANG1 (ANG45 / 45)
+#define ANG60 (ANG180 / 3)
+
+// Heretic code uses this definition as though it represents one
+// degree, but it is not! This is actually ~1.40 degrees.
+
+#define ANG1_X 0x01000000
#define SLOPERANGE 2048
#define SLOPEBITS 11
@@ -84,10 +97,7 @@ extern const angle_t tantoangle[SLOPERANGE+1];
// Utility function,
// called by R_PointToAngle.
-int
-SlopeDiv
-( unsigned num,
- unsigned den);
+int SlopeDiv(unsigned int num, unsigned int den);
#endif
diff --git a/src/v_patch.h b/src/v_patch.h
new file mode 100644
index 00000000..257603f6
--- /dev/null
+++ b/src/v_patch.h
@@ -0,0 +1,58 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Refresh/rendering module, shared data struct definitions.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef V_PATCH_H
+#define V_PATCH_H
+
+// Patches.
+// A patch holds one or more columns.
+// Patches are used for sprites and all masked pictures,
+// and we compose textures from the TEXTURE1/2 lists
+// of patches.
+
+typedef struct
+{
+ short width; // bounding box size
+ short height;
+ short leftoffset; // pixels to the left of origin
+ short topoffset; // pixels below the origin
+ int columnofs[8]; // only [width] used
+ // the [0] is &columnofs[width]
+} PACKEDATTR patch_t;
+
+// posts are runs of non masked source pixels
+typedef struct
+{
+ byte topdelta; // -1 is the last post in a column
+ byte length; // length data bytes follows
+} PACKEDATTR post_t;
+
+// column_t is a list of 0 or more post_t, (byte)-1 terminated
+typedef post_t column_t;
+
+#endif
+
diff --git a/src/v_video.c b/src/v_video.c
index 82d9f357..56207d64 100644
--- a/src/v_video.c
+++ b/src/v_video.c
@@ -2,6 +2,7 @@
//-----------------------------------------------------------------------------
//
// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
// Copyright(C) 2005 Simon Howard
//
// This program is free software; you can redistribute it and/or
@@ -26,399 +27,487 @@
//
//-----------------------------------------------------------------------------
-
-
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
#include "i_system.h"
-#include "r_local.h"
-#include "doomdef.h"
-#include "doomdata.h"
+#include "doomtype.h"
-#include "deh_main.h"
-#include "m_bbox.h"
+#include "deh_str.h"
#include "i_swap.h"
#include "i_video.h"
+#include "m_bbox.h"
#include "m_misc.h"
#include "v_video.h"
#include "w_wad.h"
#include "z_zone.h"
-// Each screen is [SCREENWIDTH*SCREENHEIGHT];
-byte* screens[5];
-
-int dirtybox[4];
+// Blending table used for fuzzpatch, etc.
+// Only used in Heretic/Hexen
+byte *tinttable = NULL;
+// villsa [STRIFE] Blending table used for Strife
+byte *xlatab = NULL;
+
+// The screen buffer that the v_video.c code draws to.
+
+static byte *dest_screen = NULL;
+
+int dirtybox[4];
+
+// haleyjd 08/28/10: clipping callback function for patches.
+// This is needed for Chocolate Strife, which clips patches to the screen.
+static vpatchclipfunc_t patchclip_callback = NULL;
-// Now where did these came from?
-const byte gammatable[5][256] =
-{
- {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,32,
- 33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,
- 49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,
- 65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,
- 81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,
- 97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,
- 113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,
- 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
- 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
- 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
- 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
- 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
- 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
- 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
- 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255},
-
- {2,4,5,7,8,10,11,12,14,15,16,18,19,20,21,23,24,25,26,27,29,30,31,
- 32,33,34,36,37,38,39,40,41,42,44,45,46,47,48,49,50,51,52,54,55,
- 56,57,58,59,60,61,62,63,64,65,66,67,69,70,71,72,73,74,75,76,77,
- 78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,
- 99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,
- 115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,129,
- 130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,
- 146,147,148,148,149,150,151,152,153,154,155,156,157,158,159,160,
- 161,162,163,163,164,165,166,167,168,169,170,171,172,173,174,175,
- 175,176,177,178,179,180,181,182,183,184,185,186,186,187,188,189,
- 190,191,192,193,194,195,196,196,197,198,199,200,201,202,203,204,
- 205,205,206,207,208,209,210,211,212,213,214,214,215,216,217,218,
- 219,220,221,222,222,223,224,225,226,227,228,229,230,230,231,232,
- 233,234,235,236,237,237,238,239,240,241,242,243,244,245,245,246,
- 247,248,249,250,251,252,252,253,254,255},
-
- {4,7,9,11,13,15,17,19,21,22,24,26,27,29,30,32,33,35,36,38,39,40,42,
- 43,45,46,47,48,50,51,52,54,55,56,57,59,60,61,62,63,65,66,67,68,69,
- 70,72,73,74,75,76,77,78,79,80,82,83,84,85,86,87,88,89,90,91,92,93,
- 94,95,96,97,98,100,101,102,103,104,105,106,107,108,109,110,111,112,
- 113,114,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,
- 129,130,131,132,133,133,134,135,136,137,138,139,140,141,142,143,144,
- 144,145,146,147,148,149,150,151,152,153,153,154,155,156,157,158,159,
- 160,160,161,162,163,164,165,166,166,167,168,169,170,171,172,172,173,
- 174,175,176,177,178,178,179,180,181,182,183,183,184,185,186,187,188,
- 188,189,190,191,192,193,193,194,195,196,197,197,198,199,200,201,201,
- 202,203,204,205,206,206,207,208,209,210,210,211,212,213,213,214,215,
- 216,217,217,218,219,220,221,221,222,223,224,224,225,226,227,228,228,
- 229,230,231,231,232,233,234,235,235,236,237,238,238,239,240,241,241,
- 242,243,244,244,245,246,247,247,248,249,250,251,251,252,253,254,254,
- 255},
-
- {8,12,16,19,22,24,27,29,31,34,36,38,40,41,43,45,47,49,50,52,53,55,
- 57,58,60,61,63,64,65,67,68,70,71,72,74,75,76,77,79,80,81,82,84,85,
- 86,87,88,90,91,92,93,94,95,96,98,99,100,101,102,103,104,105,106,107,
- 108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,
- 125,126,127,128,129,130,131,132,133,134,135,135,136,137,138,139,140,
- 141,142,143,143,144,145,146,147,148,149,150,150,151,152,153,154,155,
- 155,156,157,158,159,160,160,161,162,163,164,165,165,166,167,168,169,
- 169,170,171,172,173,173,174,175,176,176,177,178,179,180,180,181,182,
- 183,183,184,185,186,186,187,188,189,189,190,191,192,192,193,194,195,
- 195,196,197,197,198,199,200,200,201,202,202,203,204,205,205,206,207,
- 207,208,209,210,210,211,212,212,213,214,214,215,216,216,217,218,219,
- 219,220,221,221,222,223,223,224,225,225,226,227,227,228,229,229,230,
- 231,231,232,233,233,234,235,235,236,237,237,238,238,239,240,240,241,
- 242,242,243,244,244,245,246,246,247,247,248,249,249,250,251,251,252,
- 253,253,254,254,255},
-
- {16,23,28,32,36,39,42,45,48,50,53,55,57,60,62,64,66,68,69,71,73,75,76,
- 78,80,81,83,84,86,87,89,90,92,93,94,96,97,98,100,101,102,103,105,106,
- 107,108,109,110,112,113,114,115,116,117,118,119,120,121,122,123,124,
- 125,126,128,128,129,130,131,132,133,134,135,136,137,138,139,140,141,
- 142,143,143,144,145,146,147,148,149,150,150,151,152,153,154,155,155,
- 156,157,158,159,159,160,161,162,163,163,164,165,166,166,167,168,169,
- 169,170,171,172,172,173,174,175,175,176,177,177,178,179,180,180,181,
- 182,182,183,184,184,185,186,187,187,188,189,189,190,191,191,192,193,
- 193,194,195,195,196,196,197,198,198,199,200,200,201,202,202,203,203,
- 204,205,205,206,207,207,208,208,209,210,210,211,211,212,213,213,214,
- 214,215,216,216,217,217,218,219,219,220,220,221,221,222,223,223,224,
- 224,225,225,226,227,227,228,228,229,229,230,230,231,232,232,233,233,
- 234,234,235,235,236,236,237,237,238,239,239,240,240,241,241,242,242,
- 243,243,244,244,245,245,246,246,247,247,248,248,249,249,250,250,251,
- 251,252,252,253,254,254,255,255}
-};
-
-
-// Gamma correction level to use
-
-int usegamma = 0;
-
//
// V_MarkRect
//
-void
-V_MarkRect
-( int x,
- int y,
- int width,
- int height )
+void V_MarkRect(int x, int y, int width, int height)
{
- M_AddToBox (dirtybox, x, y);
- M_AddToBox (dirtybox, x+width-1, y+height-1);
+ // If we are temporarily using an alternate screen, do not
+ // affect the update box.
+
+ if (dest_screen == I_VideoBuffer)
+ {
+ M_AddToBox (dirtybox, x, y);
+ M_AddToBox (dirtybox, x + width-1, y + height-1);
+ }
}
//
// V_CopyRect
//
-void
-V_CopyRect
-( int srcx,
- int srcy,
- int srcscrn,
- int width,
- int height,
- int destx,
- int desty,
- int destscrn )
+void V_CopyRect(int srcx, int srcy, byte *source,
+ int width, int height,
+ int destx, int desty)
{
- byte* src;
- byte* dest;
-
+ byte *src;
+ byte *dest;
+
#ifdef RANGECHECK
- if (srcx<0
- ||srcx+width >SCREENWIDTH
- || srcy<0
- || srcy+height>SCREENHEIGHT
- ||destx<0||destx+width >SCREENWIDTH
- || desty<0
- || desty+height>SCREENHEIGHT
- || (unsigned)srcscrn>4
- || (unsigned)destscrn>4)
+ if (srcx < 0
+ || srcx + width > SCREENWIDTH
+ || srcy < 0
+ || srcy + height > SCREENHEIGHT
+ || destx < 0
+ || destx + width > SCREENWIDTH
+ || desty < 0
+ || desty + height > SCREENHEIGHT)
{
- I_Error ("Bad V_CopyRect");
+ I_Error ("Bad V_CopyRect");
}
#endif
- V_MarkRect (destx, desty, width, height);
-
- src = screens[srcscrn]+SCREENWIDTH*srcy+srcx;
- dest = screens[destscrn]+SCREENWIDTH*desty+destx;
+
+ V_MarkRect(destx, desty, width, height);
+
+ src = source + SCREENWIDTH * srcy + srcx;
+ dest = dest_screen + SCREENWIDTH * desty + destx;
for ( ; height>0 ; height--)
{
- memcpy (dest, src, width);
- src += SCREENWIDTH;
- dest += SCREENWIDTH;
+ memcpy(dest, src, width);
+ src += SCREENWIDTH;
+ dest += SCREENWIDTH;
}
}
+//
+// V_SetPatchClipCallback
+//
+// haleyjd 08/28/10: Added for Strife support.
+// By calling this function, you can setup runtime error checking for patch
+// clipping. Strife never caused errors by drawing patches partway off-screen.
+// Some versions of vanilla DOOM also behaved differently than the default
+// implementation, so this could possibly be extended to those as well for
+// accurate emulation.
+//
+void V_SetPatchClipCallback(vpatchclipfunc_t func)
+{
+ patchclip_callback = func;
+}
//
// V_DrawPatch
// Masks a column based masked pic to the screen.
//
-void
-V_DrawPatch
-( int x,
- int y,
- int scrn,
- patch_t* patch )
+
+void V_DrawPatch(int x, int y, patch_t *patch)
{
+ int count;
+ int col;
+ column_t *column;
+ byte *desttop;
+ byte *dest;
+ byte *source;
+ int w;
+
+ y -= SHORT(patch->topoffset);
+ x -= SHORT(patch->leftoffset);
+
+ // haleyjd 08/28/10: Strife needs silent error checking here.
+ if(patchclip_callback)
+ {
+ if(!patchclip_callback(patch, x, y))
+ return;
+ }
- int count;
- int col;
- column_t* column;
- byte* desttop;
- byte* dest;
- byte* source;
- int w;
-
- y -= SHORT(patch->topoffset);
- x -= SHORT(patch->leftoffset);
-#ifdef RANGECHECK
- if (x<0
- ||x+SHORT(patch->width) >SCREENWIDTH
- || y<0
- || y+SHORT(patch->height)>SCREENHEIGHT
- || (unsigned)scrn>4)
+#ifdef RANGECHECK
+ if (x < 0
+ || x + SHORT(patch->width) > SCREENWIDTH
+ || y < 0
+ || y + SHORT(patch->height) > SCREENHEIGHT)
{
I_Error("Bad V_DrawPatch");
}
-#endif
-
- if (!scrn)
- V_MarkRect (x, y, SHORT(patch->width), SHORT(patch->height));
+#endif
+
+ V_MarkRect(x, y, SHORT(patch->width), SHORT(patch->height));
+
+ col = 0;
+ desttop = dest_screen + y * SCREENWIDTH + x;
- col = 0;
- desttop = screens[scrn]+y*SCREENWIDTH+x;
-
- w = SHORT(patch->width);
+ w = SHORT(patch->width);
for ( ; col<w ; x++, col++, desttop++)
- {
- column = (column_t *)((byte *)patch + LONG(patch->columnofs[col]));
-
- // 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 );
- }
- }
-}
-
+ {
+ column = (column_t *)((byte *)patch + LONG(patch->columnofs[col]));
+
+ // 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);
+ }
+ }
+}
+
//
-// V_DrawPatchFlipped
+// V_DrawPatchFlipped
// Masks a column based masked pic to the screen.
// Flips horizontally, e.g. to mirror face.
//
-void
-V_DrawPatchFlipped
-( int x,
- int y,
- int scrn,
- patch_t* patch )
-{
- int count;
- int col;
- column_t* column;
- byte* desttop;
- byte* dest;
- byte* source;
- int w;
-
+void V_DrawPatchFlipped(int x, int y, patch_t *patch)
+{
+ int count;
+ int col;
+ column_t *column;
+ byte *desttop;
+ byte *dest;
+ byte *source;
+ int w;
+
y -= SHORT(patch->topoffset);
x -= SHORT(patch->leftoffset);
+
+ // haleyjd 08/28/10: Strife needs silent error checking here.
+ if(patchclip_callback)
+ {
+ if(!patchclip_callback(patch, x, y))
+ return;
+ }
+
#ifdef RANGECHECK
- if (x<0
- ||x+SHORT(patch->width) >SCREENWIDTH
- || y<0
- || y+SHORT(patch->height)>SCREENHEIGHT
- || (unsigned)scrn>4)
+ if (x < 0
+ || x + SHORT(patch->width) > SCREENWIDTH
+ || y < 0
+ || y + SHORT(patch->height) > SCREENHEIGHT)
{
I_Error("Bad V_DrawPatchFlipped");
}
-#endif
-
- if (!scrn)
- V_MarkRect (x, y, SHORT(patch->width), SHORT(patch->height));
+#endif
- col = 0;
- desttop = screens[scrn]+y*SCREENWIDTH+x;
-
- w = SHORT(patch->width);
+ V_MarkRect (x, y, SHORT(patch->width), SHORT(patch->height));
+
+ col = 0;
+ desttop = dest_screen + y * SCREENWIDTH + x;
+
+ w = SHORT(patch->width);
+
+ for ( ; col<w ; x++, col++, desttop++)
+ {
+ column = (column_t *)((byte *)patch + LONG(patch->columnofs[w-1-col]));
+
+ // 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);
+ }
+ }
+}
- for ( ; col<w ; x++, col++, desttop++)
- {
- column = (column_t *)((byte *)patch + LONG(patch->columnofs[w-1-col]));
-
- // 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 );
- }
- }
-}
-
//
// V_DrawPatchDirect
// Draws directly to the screen on the pc.
//
-void
-V_DrawPatchDirect
-( int x,
- int y,
- int scrn,
- patch_t* patch )
+
+void V_DrawPatchDirect(int x, int y, patch_t *patch)
{
- V_DrawPatch (x,y,scrn, patch);
-
- /*
- int count;
- int col;
- column_t* column;
- byte* desttop;
- byte* dest;
- byte* source;
- int w;
-
- y -= SHORT(patch->topoffset);
- x -= SHORT(patch->leftoffset);
+ V_DrawPatch(x, y, patch);
+}
-#ifdef RANGECHECK
- if (x<0
- ||x+SHORT(patch->width) >SCREENWIDTH
- || y<0
- || y+SHORT(patch->height)>SCREENHEIGHT
- || (unsigned)scrn>4)
+//
+// V_DrawTLPatch
+//
+// Masks a column based translucent masked pic to the screen.
+//
+
+void V_DrawTLPatch(int x, int y, patch_t * patch)
+{
+ int count, col;
+ column_t *column;
+ byte *desttop, *dest, *source;
+ int w;
+
+ y -= SHORT(patch->topoffset);
+ x -= SHORT(patch->leftoffset);
+
+ if (x < 0
+ || x + SHORT(patch->width) > SCREENWIDTH
+ || y < 0
+ || y + SHORT(patch->height) > SCREENHEIGHT)
{
- I_Error ("Bad V_DrawPatchDirect");
+ I_Error("Bad V_DrawTLPatch");
+ }
+
+ col = 0;
+ desttop = dest_screen + y * SCREENWIDTH + x;
+
+ w = SHORT(patch->width);
+ for (; col < w; x++, col++, desttop++)
+ {
+ column = (column_t *) ((byte *) patch + LONG(patch->columnofs[col]));
+
+ // 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 = tinttable[((*dest) << 8) + *source++];
+ dest += SCREENWIDTH;
+ }
+ column = (column_t *) ((byte *) column + column->length + 4);
+ }
+ }
+}
+
+//
+// V_DrawXlaPatch
+//
+// villsa [STRIFE] Masks a column based translucent masked pic to the screen.
+//
+
+void V_DrawXlaPatch(int x, int y, patch_t * patch)
+{
+ int count, col;
+ column_t *column;
+ byte *desttop, *dest, *source;
+ int w;
+
+ y -= SHORT(patch->topoffset);
+ x -= SHORT(patch->leftoffset);
+
+ if(patchclip_callback)
+ {
+ if(!patchclip_callback(patch, x, y))
+ return;
+ }
+
+ col = 0;
+ desttop = dest_screen + y * SCREENWIDTH + x;
+
+ w = SHORT(patch->width);
+ for(; col < w; x++, col++, desttop++)
+ {
+ column = (column_t *) ((byte *) patch + LONG(patch->columnofs[col]));
+
+ // 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 = xlatab[*dest + ((*source) << 8)];
+ source++;
+ dest += SCREENWIDTH;
+ }
+ column = (column_t *) ((byte *) column + column->length + 4);
+ }
+ }
+}
+
+//
+// V_DrawAltTLPatch
+//
+// Masks a column based translucent masked pic to the screen.
+//
+
+void V_DrawAltTLPatch(int x, int y, patch_t * patch)
+{
+ int count, col;
+ column_t *column;
+ byte *desttop, *dest, *source;
+ int w;
+
+ y -= SHORT(patch->topoffset);
+ x -= SHORT(patch->leftoffset);
+
+ if (x < 0
+ || x + SHORT(patch->width) > SCREENWIDTH
+ || y < 0
+ || y + SHORT(patch->height) > SCREENHEIGHT)
+ {
+ I_Error("Bad V_DrawAltTLPatch");
}
-#endif
-
- // V_MarkRect (x, y, SHORT(patch->width), SHORT(patch->height));
- desttop = destscreen + y*SCREENWIDTH/4 + (x>>2);
-
- w = SHORT(patch->width);
- for ( col = 0 ; col<w ; col++)
- {
- outp (SC_INDEX+1,1<<(x&3));
- column = (column_t *)((byte *)patch + LONG(patch->columnofs[col]));
-
- // step through the posts in a column
-
- while (column->topdelta != 0xff )
- {
- source = (byte *)column + 3;
- dest = desttop + column->topdelta*SCREENWIDTH/4;
- count = column->length;
-
- while (count--)
- {
- *dest = *source++;
- dest += SCREENWIDTH/4;
- }
- column = (column_t *)( (byte *)column + column->length
- + 4 );
- }
- if ( ((++x)&3) == 0 )
- desttop++; // go to next byte, not next plane
- }*/
-}
-
+ col = 0;
+ desttop = dest_screen + y * SCREENWIDTH + x;
+
+ w = SHORT(patch->width);
+ for (; col < w; x++, col++, desttop++)
+ {
+ column = (column_t *) ((byte *) patch + LONG(patch->columnofs[col]));
+
+ // 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 = tinttable[((*dest) << 8) + *source++];
+ dest += SCREENWIDTH;
+ }
+ column = (column_t *) ((byte *) column + column->length + 4);
+ }
+ }
+}
+
+//
+// V_DrawShadowedPatch
+//
+// Masks a column based masked pic to the screen.
+//
+
+void V_DrawShadowedPatch(int x, int y, patch_t *patch)
+{
+ int count, col;
+ column_t *column;
+ byte *desttop, *dest, *source;
+ byte *desttop2, *dest2;
+ int w;
+
+ y -= SHORT(patch->topoffset);
+ x -= SHORT(patch->leftoffset);
+
+ if (x < 0
+ || x + SHORT(patch->width) > SCREENWIDTH
+ || y < 0
+ || y + SHORT(patch->height) > SCREENHEIGHT)
+ {
+ I_Error("Bad V_DrawShadowedPatch");
+ }
+
+ col = 0;
+ desttop = dest_screen + y * SCREENWIDTH + x;
+ desttop2 = dest_screen + (y + 2) * SCREENWIDTH + x + 2;
+
+ w = SHORT(patch->width);
+ for (; col < w; x++, col++, desttop++, desttop2++)
+ {
+ column = (column_t *) ((byte *) patch + LONG(patch->columnofs[col]));
+
+ // step through the posts in a column
+
+ while (column->topdelta != 0xff)
+ {
+ source = (byte *) column + 3;
+ dest = desttop + column->topdelta * SCREENWIDTH;
+ dest2 = desttop2 + column->topdelta * SCREENWIDTH;
+ count = column->length;
+
+ while (count--)
+ {
+ *dest2 = tinttable[((*dest2) << 8)];
+ dest2 += SCREENWIDTH;
+ *dest = *source++;
+ dest += SCREENWIDTH;
+
+ }
+ column = (column_t *) ((byte *) column + column->length + 4);
+ }
+ }
+}
+
+//
+// Load tint table from TINTTAB lump.
+//
+
+void V_LoadTintTable(void)
+{
+ tinttable = W_CacheLumpName("TINTTAB", PU_STATIC);
+}
+
+//
+// V_LoadXlaTable
+//
+// villsa [STRIFE] Load xla table from XLATAB lump.
+//
+
+void V_LoadXlaTable(void)
+{
+ xlatab = W_CacheLumpName("XLATAB", PU_STATIC);
+}
//
// V_DrawBlock
// Draw a linear block of pixels into the view buffer.
//
-void
-V_DrawBlock
-( int x,
- int y,
- int scrn,
- int width,
- int height,
- byte* src )
+
+void V_DrawBlock(int x, int y, int width, int height, byte *src)
{
- byte* dest;
-
+ byte *dest;
+
#ifdef RANGECHECK
- if (x<0
- ||x+width >SCREENWIDTH
- || y<0
- || y+height>SCREENHEIGHT
- || (unsigned)scrn>4 )
+ if (x < 0
+ || x + width >SCREENWIDTH
+ || y < 0
+ || y + height > SCREENHEIGHT)
{
I_Error ("Bad V_DrawBlock");
}
@@ -426,7 +515,7 @@ V_DrawBlock
V_MarkRect (x, y, width, height);
- dest = screens[scrn] + y*SCREENWIDTH+x;
+ dest = dest_screen + y * SCREENWIDTH + x;
while (height--)
{
@@ -435,64 +524,94 @@ V_DrawBlock
dest += SCREENWIDTH;
}
}
-
+void V_DrawFilledBox(int x, int y, int w, int h, int c)
+{
+ uint8_t *buf, *buf1;
+ int x1, y1;
+
+ buf = I_VideoBuffer + SCREENWIDTH * y + x;
-//
-// V_GetBlock
-// Gets a linear block of pixels from the view buffer.
-//
-void
-V_GetBlock
-( int x,
- int y,
- int scrn,
- int width,
- int height,
- byte* dest )
-{
- byte* src;
-
-#ifdef RANGECHECK
- if (x<0
- ||x+width >SCREENWIDTH
- || y<0
- || y+height>SCREENHEIGHT
- || (unsigned)scrn>4 )
+ for (y1 = 0; y1 < h; ++y1)
{
- I_Error ("Bad V_DrawBlock");
+ buf1 = buf;
+
+ for (x1 = 0; x1 < w; ++x1)
+ {
+ *buf1++ = c;
+ }
+
+ buf += SCREENWIDTH;
}
-#endif
-
- src = screens[scrn] + y*SCREENWIDTH+x;
+}
- while (height--)
- {
- memcpy (dest, src, width);
- src += SCREENWIDTH;
- dest += width;
- }
-}
+void V_DrawHorizLine(int x, int y, int w, int c)
+{
+ uint8_t *buf;
+ int x1;
+
+ buf = I_VideoBuffer + SCREENWIDTH * y + x;
+
+ for (x1 = 0; x1 < w; ++x1)
+ {
+ *buf++ = c;
+ }
+}
+
+void V_DrawVertLine(int x, int y, int h, int c)
+{
+ uint8_t *buf;
+ int y1;
+
+ buf = I_VideoBuffer + SCREENWIDTH * y + x;
+ for (y1 = 0; y1 < h; ++y1)
+ {
+ *buf = c;
+ buf += SCREENWIDTH;
+ }
+}
+void V_DrawBox(int x, int y, int w, int h, int c)
+{
+ V_DrawHorizLine(x, y, w, c);
+ V_DrawHorizLine(x, y+h-1, w, c);
+ V_DrawVertLine(x, y, h, c);
+ V_DrawVertLine(x+w-1, y, h, c);
+}
+//
+// Draw a "raw" screen (lump containing raw data to blit directly
+// to the screen)
+//
+
+void V_DrawRawScreen(byte *raw)
+{
+ memcpy(dest_screen, raw, SCREENWIDTH * SCREENHEIGHT);
+}
//
// V_Init
//
void V_Init (void)
{
- int i;
- byte* base;
-
- // stick these in low dos memory on PCs
+ // no-op!
+ // There used to be separate screens that could be drawn to; these are
+ // now handled in the upper layers.
+}
- base = Z_Malloc(SCREENWIDTH * SCREENHEIGHT * 4, PU_STATIC, NULL);
+// Set the buffer that the code draws to.
- for (i=0 ; i<4 ; i++)
- {
- screens[i] = base + i*SCREENWIDTH*SCREENHEIGHT;
- }
+void V_UseBuffer(byte *buffer)
+{
+ dest_screen = buffer;
+}
+
+// Restore screen buffer to the i_video screen buffer.
+
+void V_RestoreBuffer(void)
+{
+ dest_screen = I_VideoBuffer;
}
//
@@ -587,32 +706,121 @@ void WritePCXfile(char *filename, byte *data,
// V_ScreenShot
//
-void V_ScreenShot (void)
+void V_ScreenShot(char *format)
{
- int i;
- byte* linear;
- char lbmname[12];
-
- // munge planar buffer to linear
- linear = screens[2];
- I_ReadScreen (linear);
+ int i;
+ char lbmname[16]; // haleyjd 20110213: BUG FIX - 12 is too small!
// find a file name to save it to
- strcpy(lbmname,"DOOM00.pcx");
-
- for (i=0 ; i<=99 ; i++)
+
+ for (i=0; i<=99; i++)
{
- lbmname[4] = i/10 + '0';
- lbmname[5] = i%10 + '0';
- if (!M_FileExists(lbmname))
- break; // file doesn't exist
+ sprintf(lbmname, format, i);
+
+ if (!M_FileExists(lbmname))
+ {
+ break; // file doesn't exist
+ }
}
- if (i==100)
- I_Error ("V_ScreenShot: Couldn't create a PCX");
-
+
+ if (i == 100)
+ {
+ I_Error ("V_ScreenShot: Couldn't create a PCX");
+ }
+
// save the pcx file
- WritePCXfile (lbmname, linear,
- SCREENWIDTH, SCREENHEIGHT,
- W_CacheLumpName (DEH_String("PLAYPAL"), PU_CACHE));
+ WritePCXfile(lbmname, I_VideoBuffer,
+ SCREENWIDTH, SCREENHEIGHT,
+ W_CacheLumpName (DEH_String("PLAYPAL"), PU_CACHE));
+}
+
+#define MOUSE_SPEED_BOX_WIDTH 120
+#define MOUSE_SPEED_BOX_HEIGHT 9
+
+void V_DrawMouseSpeedBox(int speed)
+{
+ extern int usemouse;
+ int bgcolor, bordercolor, red, black, white, yellow;
+ int box_x, box_y;
+ int original_speed;
+ int redline_x;
+ int linelen;
+
+ // Get palette indices for colors for widget. These depend on the
+ // palette of the game being played.
+
+ bgcolor = I_GetPaletteIndex(0x77, 0x77, 0x77);
+ bordercolor = I_GetPaletteIndex(0x55, 0x55, 0x55);
+ red = I_GetPaletteIndex(0xff, 0x00, 0x00);
+ black = I_GetPaletteIndex(0x00, 0x00, 0x00);
+ yellow = I_GetPaletteIndex(0xff, 0xff, 0x00);
+ white = I_GetPaletteIndex(0xff, 0xff, 0xff);
+
+ // If the mouse is turned off or acceleration is turned off, don't
+ // draw the box at all.
+
+ if (!usemouse || fabs(mouse_acceleration - 1) < 0.01)
+ {
+ return;
+ }
+
+ // Calculate box position
+
+ box_x = SCREENWIDTH - MOUSE_SPEED_BOX_WIDTH - 10;
+ box_y = 15;
+
+ V_DrawFilledBox(box_x, box_y,
+ MOUSE_SPEED_BOX_WIDTH, MOUSE_SPEED_BOX_HEIGHT, bgcolor);
+ V_DrawBox(box_x, box_y,
+ MOUSE_SPEED_BOX_WIDTH, MOUSE_SPEED_BOX_HEIGHT, bordercolor);
+
+ // Calculate the position of the red line. This is 1/3 of the way
+ // along the box.
+
+ redline_x = MOUSE_SPEED_BOX_WIDTH / 3;
+
+ // Undo acceleration and get back the original mouse speed
+
+ if (speed < mouse_threshold)
+ {
+ original_speed = speed;
+ }
+ else
+ {
+ original_speed = speed - mouse_threshold;
+ original_speed = (int) (original_speed / mouse_acceleration);
+ original_speed += mouse_threshold;
+ }
+
+ // Calculate line length
+
+ linelen = (original_speed * redline_x) / mouse_threshold;
+
+ // Draw horizontal "thermometer"
+
+ if (linelen > MOUSE_SPEED_BOX_WIDTH - 1)
+ {
+ linelen = MOUSE_SPEED_BOX_WIDTH - 1;
+ }
+
+ V_DrawHorizLine(box_x + 1, box_y + 4, MOUSE_SPEED_BOX_WIDTH - 2, black);
+
+ if (linelen < redline_x)
+ {
+ V_DrawHorizLine(box_x + 1, box_y + MOUSE_SPEED_BOX_HEIGHT / 2,
+ linelen, white);
+ }
+ else
+ {
+ V_DrawHorizLine(box_x + 1, box_y + MOUSE_SPEED_BOX_HEIGHT / 2,
+ redline_x, white);
+ V_DrawHorizLine(box_x + redline_x, box_y + MOUSE_SPEED_BOX_HEIGHT / 2,
+ linelen - redline_x, yellow);
+ }
+
+ // Draw red line
+
+ V_DrawVertLine(box_x + redline_x, box_y + 1,
+ MOUSE_SPEED_BOX_HEIGHT - 2, red);
}
diff --git a/src/v_video.h b/src/v_video.h
index 3782b4eb..93a46552 100644
--- a/src/v_video.h
+++ b/src/v_video.h
@@ -32,10 +32,8 @@
#include "doomtype.h"
-#include "doomdef.h"
-
// Needed because we are refering to patches.
-#include "r_data.h"
+#include "v_patch.h"
//
// VIDEO
@@ -44,78 +42,75 @@
#define CENTERY (SCREENHEIGHT/2)
-// Screen 0 is the screen updated by I_Update screen.
-// Screen 1 is an extra buffer.
-
-
-
-extern byte *screens[5];
-
extern int dirtybox[4];
-extern const byte gammatable[5][256];
-extern int usegamma;
+extern byte *tinttable;
+// haleyjd 08/28/10: implemented for Strife support
+// haleyjd 08/28/10: Patch clipping callback, implemented to support Choco
+// Strife.
+typedef boolean (*vpatchclipfunc_t)(patch_t *, int, int);
+void V_SetPatchClipCallback(vpatchclipfunc_t func);
// Allocates buffer screens, call before R_Init.
void V_Init (void);
+// Draw a block from the specified source screen to the screen.
-void
-V_CopyRect
-( int srcx,
- int srcy,
- int srcscrn,
- int width,
- int height,
- int destx,
- int desty,
- int destscrn );
-
-void
-V_DrawPatch
-( int x,
- int y,
- int scrn,
- patch_t* patch);
-
-void
-V_DrawPatchDirect
-( int x,
- int y,
- int scrn,
- patch_t* patch );
+void V_CopyRect(int srcx, int srcy, byte *source,
+ int width, int height,
+ int destx, int desty);
+void V_DrawPatch(int x, int y, patch_t *patch);
+void V_DrawPatchFlipped(int x, int y, patch_t *patch);
+void V_DrawTLPatch(int x, int y, patch_t *patch);
+void V_DrawAltTLPatch(int x, int y, patch_t * patch);
+void V_DrawShadowedPatch(int x, int y, patch_t *patch);
+void V_DrawXlaPatch(int x, int y, patch_t * patch); // villsa [STRIFE]
+void V_DrawPatchDirect(int x, int y, patch_t *patch);
// Draw a linear block of pixels into the view buffer.
-void
-V_DrawBlock
-( int x,
- int y,
- int scrn,
- int width,
- int height,
- byte* src );
-
-// Reads a linear block of pixels into the view buffer.
-void
-V_GetBlock
-( int x,
- int y,
- int scrn,
- int width,
- int height,
- byte* dest );
-
-
-void
-V_MarkRect
-( int x,
- int y,
- int width,
- int height );
-
-void V_ScreenShot(void);
+
+void V_DrawBlock(int x, int y, int width, int height, byte *src);
+
+void V_MarkRect(int x, int y, int width, int height);
+
+void V_DrawFilledBox(int x, int y, int w, int h, int c);
+void V_DrawHorizLine(int x, int y, int w, int c);
+void V_DrawVertLine(int x, int y, int h, int c);
+void V_DrawBox(int x, int y, int w, int h, int c);
+
+// Draw a raw screen lump
+
+void V_DrawRawScreen(byte *raw);
+
+// Temporarily switch to using a different buffer to draw graphics, etc.
+
+void V_UseBuffer(byte *buffer);
+
+// Return to using the normal screen buffer to draw graphics.
+
+void V_RestoreBuffer(void);
+
+// Save a screenshot of the current screen to a file, named in the
+// format described in the string passed to the function, eg.
+// "DOOM%02i.pcx"
+
+void V_ScreenShot(char *format);
+
+// Load the lookup table for translucency calculations from the TINTTAB
+// lump.
+
+void V_LoadTintTable(void);
+
+// villsa [STRIFE]
+// Load the lookup table for translucency calculations from the XLATAB
+// lump.
+
+void V_LoadXlaTable(void);
+
+void V_DrawMouseSpeedBox(int speed);
#endif
+
diff --git a/src/w_file.c b/src/w_file.c
index c8682cbf..7525f203 100644
--- a/src/w_file.c
+++ b/src/w_file.c
@@ -24,9 +24,10 @@
//
//-----------------------------------------------------------------------------
+#include <stdio.h>
+
#include "config.h"
-#include "doomdef.h"
#include "doomtype.h"
#include "m_argv.h"
diff --git a/src/w_main.c b/src/w_main.c
new file mode 100644
index 00000000..ed285498
--- /dev/null
+++ b/src/w_main.c
@@ -0,0 +1,206 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2010 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Common code to parse command line, identifying WAD files to load.
+//
+//-----------------------------------------------------------------------------
+
+#include "doomfeatures.h"
+#include "d_iwad.h"
+#include "m_argv.h"
+#include "w_main.h"
+#include "w_merge.h"
+#include "w_wad.h"
+#include "z_zone.h"
+
+// Parse the command line, merging WAD files that are sppecified.
+// Returns true if at least one file was added.
+
+boolean W_ParseCommandLine(void)
+{
+ boolean modifiedgame = false;
+ int p;
+
+#ifdef FEATURE_WAD_MERGE
+
+ // Merged PWADs are loaded first, because they are supposed to be
+ // modified IWADs.
+
+ //!
+ // @arg <files>
+ // @category mod
+ //
+ // Simulates the behavior of deutex's -merge option, merging a PWAD
+ // into the main IWAD. Multiple files may be specified.
+ //
+
+ p = M_CheckParmWithArgs("-merge", 1);
+
+ if (p > 0)
+ {
+ for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
+ {
+ char *filename;
+
+ modifiedgame = true;
+
+ filename = D_TryFindWADByName(myargv[p]);
+
+ printf(" merging %s\n", filename);
+ W_MergeFile(filename);
+ }
+ }
+
+ // NWT-style merging:
+
+ // NWT's -merge option:
+
+ //!
+ // @arg <files>
+ // @category mod
+ //
+ // Simulates the behavior of NWT's -merge option. Multiple files
+ // may be specified.
+
+ p = M_CheckParmWithArgs("-nwtmerge", 1);
+
+ if (p > 0)
+ {
+ for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
+ {
+ char *filename;
+
+ modifiedgame = true;
+
+ filename = D_TryFindWADByName(myargv[p]);
+
+ printf(" performing NWT-style merge of %s\n", filename);
+ W_NWTDashMerge(filename);
+ }
+ }
+
+ // Add flats
+
+ //!
+ // @arg <files>
+ // @category mod
+ //
+ // Simulates the behavior of NWT's -af option, merging flats into
+ // the main IWAD directory. Multiple files may be specified.
+ //
+
+ p = M_CheckParmWithArgs("-af", 1);
+
+ if (p > 0)
+ {
+ for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
+ {
+ char *filename;
+
+ modifiedgame = true;
+
+ filename = D_TryFindWADByName(myargv[p]);
+
+ printf(" merging flats from %s\n", filename);
+ W_NWTMergeFile(filename, W_NWT_MERGE_FLATS);
+ }
+ }
+
+ //!
+ // @arg <files>
+ // @category mod
+ //
+ // Simulates the behavior of NWT's -as option, merging sprites
+ // into the main IWAD directory. Multiple files may be specified.
+ //
+
+ p = M_CheckParmWithArgs("-as", 1);
+
+ if (p > 0)
+ {
+ for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
+ {
+ char *filename;
+
+ modifiedgame = true;
+ filename = D_TryFindWADByName(myargv[p]);
+
+ printf(" merging sprites from %s\n", filename);
+ W_NWTMergeFile(filename, W_NWT_MERGE_SPRITES);
+ }
+ }
+
+ //!
+ // @arg <files>
+ // @category mod
+ //
+ // Equivalent to "-af <files> -as <files>".
+ //
+
+ p = M_CheckParmWithArgs("-aa", 1);
+
+ if (p > 0)
+ {
+ for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
+ {
+ char *filename;
+
+ modifiedgame = true;
+
+ filename = D_TryFindWADByName(myargv[p]);
+
+ printf(" merging sprites and flats from %s\n", filename);
+ W_NWTMergeFile(filename, W_NWT_MERGE_SPRITES | W_NWT_MERGE_FLATS);
+ }
+ }
+
+#endif
+
+ //!
+ // @arg <files>
+ // @vanilla
+ //
+ // Load the specified PWAD files.
+ //
+
+ p = M_CheckParmWithArgs ("-file", 1);
+ if (p)
+ {
+ // the parms after p are wadfile/lump names,
+ // until end of parms or another - preceded parm
+ modifiedgame = true; // homebrew levels
+ while (++p != myargc && myargv[p][0] != '-')
+ {
+ char *filename;
+
+ filename = D_TryFindWADByName(myargv[p]);
+
+ printf(" adding %s\n", filename);
+ W_AddFile(filename);
+ }
+ }
+
+// W_PrintDirectory();
+
+ return modifiedgame;
+}
+
diff --git a/src/w_main.h b/src/w_main.h
new file mode 100644
index 00000000..73047b16
--- /dev/null
+++ b/src/w_main.h
@@ -0,0 +1,32 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Common code to parse command line, identifying WAD files to load.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef W_MAIN_H
+#define W_MAIN_H
+
+boolean W_ParseCommandLine(void);
+
+#endif /* #ifndef W_MAIN_H */
+
diff --git a/src/w_merge.c b/src/w_merge.c
index 6b6ae659..027c6c2c 100644
--- a/src/w_merge.c
+++ b/src/w_merge.c
@@ -26,10 +26,12 @@
//
//-----------------------------------------------------------------------------
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
-#include "doomdef.h"
+#include "doomtype.h"
#include "i_system.h"
#include "w_merge.h"
#include "w_wad.h"
@@ -157,6 +159,31 @@ static void InitSpriteList(void)
num_sprite_frames = 0;
}
+static boolean ValidSpriteLumpName(char *name)
+{
+ if (name[0] == '\0' || name[1] == '\0'
+ || name[2] == '\0' || name[3] == '\0')
+ {
+ return false;
+ }
+
+ // First frame:
+
+ if (name[4] == '\0' || !isdigit(name[5]))
+ {
+ return false;
+ }
+
+ // Second frame (optional):
+
+ if (name[6] != '\0' && !isdigit(name[7]))
+ {
+ return false;
+ }
+
+ return true;
+}
+
// Find a sprite frame
static sprite_frame_t *FindSpriteFrame(char *name, int frame)
@@ -215,6 +242,11 @@ static boolean SpriteLumpNeeded(lumpinfo_t *lump)
int angle_num;
int i;
+ if (!ValidSpriteLumpName(lump->name))
+ {
+ return true;
+ }
+
// check the first frame
sprite = FindSpriteFrame(lump->name, lump->name[4]);
@@ -273,6 +305,11 @@ static void AddSpriteLump(lumpinfo_t *lump)
sprite_frame_t *sprite;
int angle_num;
int i;
+
+ if (!ValidSpriteLumpName(lump->name))
+ {
+ return;
+ }
// first angle
diff --git a/src/w_wad.c b/src/w_wad.c
index e93147e3..4f944fee 100644
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -32,7 +32,6 @@
#include <stdlib.h>
#include <string.h>
-#include "doomdef.h"
#include "doomtype.h"
#include "i_swap.h"
@@ -72,43 +71,6 @@ unsigned int numlumps = 0;
static lumpinfo_t **lumphash;
-static void ExtractFileBase(char *path, char *dest)
-{
- char *src;
- char *filename;
- int length;
-
- src = path + strlen(path) - 1;
-
- // back up until a \ or the start
- while (src != path && *(src - 1) != DIR_SEPARATOR)
- {
- src--;
- }
-
- filename = src;
-
- // Copy up to eight characters
- // Note: Vanilla Doom exits with an error if a filename is specified
- // with a base of more than eight characters. To remove the 8.3
- // filename limit, instead we simply truncate the name.
-
- length = 0;
- memset(dest, 0, 8);
-
- while (*src != '\0' && *src != '.')
- {
- if (length >= 8)
- {
- printf("Warning: Truncated '%s' lump name to '%.8s'.\n",
- filename, dest);
- break;
- }
-
- dest[length++] = toupper((int)*src++);
- }
-}
-
// Hash function used for lump names.
unsigned int W_LumpNameHash(const char *s)
@@ -179,7 +141,7 @@ wad_file_t *W_AddFile (char *filename)
// Name the lump after the base of the filename (without the
// extension).
- ExtractFileBase (filename, fileinfo->name);
+ M_ExtractFileBase (filename, fileinfo->name);
numlumps++;
}
else
diff --git a/src/z_native.c b/src/z_native.c
index 37bdc02a..ac618222 100644
--- a/src/z_native.c
+++ b/src/z_native.c
@@ -29,10 +29,11 @@
#include <stdlib.h>
+#include <string.h>
#include "z_zone.h"
#include "i_system.h"
-#include "doomdef.h"
+#include "doomtype.h"
#define ZONEID 0x1d4a11
diff --git a/src/z_zone.c b/src/z_zone.c
index 2877fe6e..c7425290 100644
--- a/src/z_zone.c
+++ b/src/z_zone.c
@@ -27,7 +27,7 @@
#include "z_zone.h"
#include "i_system.h"
-#include "doomdef.h"
+#include "doomtype.h"
//
diff --git a/textscreen/Makefile.am b/textscreen/Makefile.am
index 04039ac3..2c04ff0f 100644
--- a/textscreen/Makefile.am
+++ b/textscreen/Makefile.am
@@ -1,5 +1,5 @@
-AM_CFLAGS = -I../src
+AM_CFLAGS = -I$(top_builddir)/src
CTAGS_ARGS=-I TXT_UNCAST_ARG+
diff --git a/textscreen/examples/Makefile.am b/textscreen/examples/Makefile.am
index e314e7e8..efd17072 100644
--- a/textscreen/examples/Makefile.am
+++ b/textscreen/examples/Makefile.am
@@ -1,5 +1,5 @@
-AM_CFLAGS = -I.. -I../../src
+AM_CFLAGS = -I.. -I$(top_builddir)/src
noinst_PROGRAMS=guitest calculator
diff --git a/textscreen/txt_desktop.c b/textscreen/txt_desktop.c
index 2c7caa27..09589688 100644
--- a/textscreen/txt_desktop.c
+++ b/textscreen/txt_desktop.c
@@ -39,6 +39,10 @@ static txt_window_t *all_windows[MAXWINDOWS];
static int num_windows = 0;
static int main_loop_running = 0;
+static TxtIdleCallback periodic_callback = NULL;
+static void *periodic_callback_data;
+static unsigned int periodic_callback_period;
+
void TXT_AddDesktopWindow(txt_window_t *win)
{
// Previously-top window loses focus:
@@ -219,6 +223,15 @@ void TXT_DrawASCIITable(void)
TXT_UpdateScreen();
}
+void TXT_SetPeriodicCallback(TxtIdleCallback callback,
+ void *user_data,
+ unsigned int period)
+{
+ periodic_callback = callback;
+ periodic_callback_data = user_data;
+ periodic_callback_period = period;
+}
+
void TXT_GUIMainLoop(void)
{
main_loop_running = 1;
@@ -233,10 +246,20 @@ void TXT_GUIMainLoop(void)
{
TXT_ExitMainLoop();
}
-
+
TXT_DrawDesktop();
// TXT_DrawASCIITable();
- TXT_Sleep(0);
+
+ if (periodic_callback == NULL)
+ {
+ TXT_Sleep(0);
+ }
+ else
+ {
+ TXT_Sleep(periodic_callback_period);
+
+ periodic_callback(periodic_callback_data);
+ }
}
}
diff --git a/textscreen/txt_desktop.h b/textscreen/txt_desktop.h
index 8d4726e5..9e2a42c7 100644
--- a/textscreen/txt_desktop.h
+++ b/textscreen/txt_desktop.h
@@ -30,6 +30,8 @@
#include "txt_window.h"
+typedef void (*TxtIdleCallback)(void *user_data);
+
void TXT_AddDesktopWindow(txt_window_t *win);
void TXT_RemoveDesktopWindow(txt_window_t *win);
void TXT_DrawDesktop(void);
@@ -73,6 +75,21 @@ void TXT_GUIMainLoop(void);
txt_window_t *TXT_GetActiveWindow(void);
-#endif /* #ifndef TXT_DESKTOP_H */
+/**
+ * Set a callback function to be invoked periodically by the main
+ * loop code.
+ *
+ * @param callback The callback to invoke, or NULL to cancel
+ * an existing callback.
+ * @param user_data Extra data to pass to the callback.
+ * @param period Maximum time between invoking each callback.
+ * eg. a value of 200 will cause the callback
+ * to be invoked at least once every 200ms.
+ */
+
+void TXT_SetPeriodicCallback(TxtIdleCallback callback,
+ void *user_data,
+ unsigned int period);
+#endif /* #ifndef TXT_DESKTOP_H */
diff --git a/textscreen/txt_dropdown.c b/textscreen/txt_dropdown.c
index d88716b5..652c9a36 100644
--- a/textscreen/txt_dropdown.c
+++ b/textscreen/txt_dropdown.c
@@ -49,14 +49,29 @@ static int ValidSelection(txt_dropdown_list_t *list)
static int SelectorWindowY(txt_dropdown_list_t *list)
{
+ int result;
+
if (ValidSelection(list))
{
- return list->widget.y - 1 - *list->variable;
+ result = list->widget.y - 1 - *list->variable;
}
else
{
- return list->widget.y - 1 - (list->num_values / 2);
+ result = list->widget.y - 1 - (list->num_values / 2);
+ }
+
+ // Keep dropdown inside the screen.
+
+ if (result < 1)
+ {
+ result = 1;
+ }
+ else if (result + list->num_values > (TXT_SCREEN_H - 3))
+ {
+ result = TXT_SCREEN_H - list->num_values - 3;
}
+
+ return result;
}
// Called when a button in the selector window is pressed
diff --git a/textscreen/txt_scrollpane.c b/textscreen/txt_scrollpane.c
index 4f468ffe..c53f68df 100644
--- a/textscreen/txt_scrollpane.c
+++ b/textscreen/txt_scrollpane.c
@@ -158,6 +158,18 @@ static void TXT_ScrollPaneSizeCalc(TXT_UNCAST_ARG(scrollpane))
{
++scrollpane->widget.w;
}
+
+ if (scrollpane->child != NULL)
+ {
+ if (scrollpane->child->w < scrollpane->w)
+ {
+ scrollpane->child->w = scrollpane->w;
+ }
+ if (scrollpane->child->h < scrollpane->h)
+ {
+ scrollpane->child->h = scrollpane->h;
+ }
+ }
}
static void TXT_ScrollPaneDrawer(TXT_UNCAST_ARG(scrollpane))
@@ -395,10 +407,10 @@ static int TXT_ScrollPaneKeyPress(TXT_UNCAST_ARG(scrollpane), int key)
// automatically move the scroll pane to show the new
// selected item.
- if (scrollpane->child->widget_class == &txt_table_class
- && (key == KEY_UPARROW || key == KEY_DOWNARROW
+ if ((key == KEY_UPARROW || key == KEY_DOWNARROW
|| key == KEY_LEFTARROW || key == KEY_RIGHTARROW
- || key == KEY_PGUP || key == KEY_PGDN))
+ || key == KEY_PGUP || key == KEY_PGDN)
+ && scrollpane->child->widget_class == &txt_table_class)
{
if (PageSelectedWidget(scrollpane, key))
{
diff --git a/textscreen/txt_sdl.c b/textscreen/txt_sdl.c
index c51fcaf3..29f8de4c 100644
--- a/textscreen/txt_sdl.c
+++ b/textscreen/txt_sdl.c
@@ -215,15 +215,19 @@ static void ChooseFont(void)
int TXT_Init(void)
{
+ int flags;
+
if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
{
return 0;
}
+ flags = SDL_SWSURFACE | SDL_HWPALETTE | SDL_DOUBLEBUF;
+
ChooseFont();
screen = SDL_SetVideoMode(TXT_SCREEN_W * font->w,
- TXT_SCREEN_H * font->h, 8, 0);
+ TXT_SCREEN_H * font->h, 8, flags);
if (screen == NULL)
return 0;
@@ -249,6 +253,7 @@ int TXT_Init(void)
void TXT_Shutdown(void)
{
free(screendata);
+ screendata = NULL;
SDL_QuitSubSystem(SDL_INIT_VIDEO);
}
diff --git a/textscreen/txt_window.c b/textscreen/txt_window.c
index b08ac658..9ab6da9b 100644
--- a/textscreen/txt_window.c
+++ b/textscreen/txt_window.c
@@ -20,10 +20,12 @@
//
#include <stdlib.h>
+#include <stdarg.h>
#include <string.h>
#include "doomkeys.h"
+#include "txt_label.h"
#include "txt_desktop.h"
#include "txt_gui.h"
#include "txt_io.h"
@@ -502,3 +504,24 @@ void TXT_SetWindowFocus(txt_window_t *window, int focused)
TXT_SetWidgetFocus(window, focused);
}
+txt_window_t *TXT_MessageBox(char *title, char *message, ...)
+{
+ txt_window_t *window;
+ char buf[256];
+ va_list args;
+
+ va_start(args, message);
+ vsnprintf(buf, sizeof(buf), message, args);
+ va_end(args);
+
+ window = TXT_NewWindow(title);
+ TXT_AddWidget(window, TXT_NewLabel(buf));
+
+ TXT_SetWindowAction(window, TXT_HORIZ_LEFT, NULL);
+ TXT_SetWindowAction(window, TXT_HORIZ_CENTER,
+ TXT_NewWindowEscapeAction(window));
+ TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, NULL);
+
+ return window;
+}
+
diff --git a/textscreen/txt_window.h b/textscreen/txt_window.h
index e183cf6d..bfae2a9a 100644
--- a/textscreen/txt_window.h
+++ b/textscreen/txt_window.h
@@ -176,6 +176,16 @@ void TXT_SetMouseListener(txt_window_t *window,
TxtWindowMousePress mouse_listener,
void *user_data);
+/**
+ * Open a window displaying a message.
+ *
+ * @param title Title of the window.
+ * @param message The message to display in the window.
+ * @return The new window.
+ */
+
+txt_window_t *TXT_MessageBox(char *title, char *message, ...);
+
#endif /* #ifndef TXT_WINDOW_T */