mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-14 16:40:56 +00:00
- Sync 3dfloors branch with trunk.
SVN r2773 (3dfloors)
This commit is contained in:
parent
5a364ed252
commit
6322239caa
294 changed files with 26747 additions and 13274 deletions
|
@ -64,42 +64,39 @@ set( CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} ${REL_C_FLAGS}" )
|
|||
set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${REL_C_FLAGS}" )
|
||||
set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${DEB_C_FLAGS} -D_DEBUG" )
|
||||
|
||||
if( CMAKE_COMPILER_IS_GNUCXX AND PROFILE )
|
||||
set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -pg" )
|
||||
set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pg" )
|
||||
set( CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -pg" )
|
||||
set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -pg" )
|
||||
endif( CMAKE_COMPILER_IS_GNUCXX AND PROFILE )
|
||||
|
||||
if( ZLIB_FOUND )
|
||||
option(FORCE_INTERNAL_ZLIB "Use internal zlib")
|
||||
option(FORCE_INTERNAL_JPEG "Use internal jpeg")
|
||||
option(FORCE_INTERNAL_BZIP2 "Use internal bzip2")
|
||||
|
||||
if( ZLIB_FOUND AND NOT FORCE_INTERNAL_ZLIB )
|
||||
message( STATUS "Using system zlib" )
|
||||
else( ZLIB_FOUND )
|
||||
else( ZLIB_FOUND AND NOT FORCE_INTERNAL_ZLIB )
|
||||
message( STATUS "Using internal zlib" )
|
||||
add_subdirectory( zlib )
|
||||
set( ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/zlib )
|
||||
set( ZLIB_LIBRARIES z )
|
||||
set( ZLIB_LIBRARY z )
|
||||
endif( ZLIB_FOUND )
|
||||
endif( ZLIB_FOUND AND NOT FORCE_INTERNAL_ZLIB )
|
||||
|
||||
if( JPEG_FOUND )
|
||||
if( JPEG_FOUND AND NOT FORCE_INTERNAL_JPEG )
|
||||
message( STATUS "Using system jpeg library" )
|
||||
else( JPEG_FOUND )
|
||||
else( JPEG_FOUND AND NOT FORCE_INTERNAL_JPEG )
|
||||
message( STATUS "Using internal jpeg library" )
|
||||
add_subdirectory( jpeg-6b )
|
||||
set( JPEG_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/jpeg-6b )
|
||||
set( JPEG_LIBRARIES jpeg )
|
||||
set( JPEG_LIBRARY jpeg )
|
||||
endif( JPEG_FOUND )
|
||||
endif( JPEG_FOUND AND NOT FORCE_INTERNAL_JPEG )
|
||||
|
||||
if( BZIP2_FOUND )
|
||||
if( BZIP2_FOUND AND NOT FORCE_INTERNAL_BZIP2 )
|
||||
message( STATUS "Using system bzip2 library" )
|
||||
else( BZIP2_FOUND )
|
||||
else( BZIP2_FOUND AND NOT FORCE_INTERNAL_BZIP2 )
|
||||
message( STATUS "Using internal bzip2 library" )
|
||||
add_subdirectory( bzip2 )
|
||||
set( BZIP2_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/bzip2" )
|
||||
set( BZIP2_LIBRARIES bz2 )
|
||||
set( BZIP2_LIBRARY bz2 )
|
||||
endif( BZIP2_FOUND)
|
||||
endif( BZIP2_FOUND AND NOT FORCE_INTERNAL_BZIP2 )
|
||||
|
||||
set( LZMA_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/lzma/C" )
|
||||
|
||||
|
|
23
FindFluidSynth.cmake
Normal file
23
FindFluidSynth.cmake
Normal file
|
@ -0,0 +1,23 @@
|
|||
# - Find fluidsynth
|
||||
# Find the native fluidsynth includes and library
|
||||
#
|
||||
# FLUIDSYNTH_INCLUDE_DIR - where to find fluidsynth.h
|
||||
# FLUIDSYNTH_LIBRARIES - List of libraries when using fluidsynth.
|
||||
# FLUIDSYNTH_FOUND - True if fluidsynth found.
|
||||
|
||||
|
||||
IF (FLUIDSYNTH_INCLUDE_DIR AND FLUIDSYNTH_LIBRARIES)
|
||||
# Already in cache, be silent
|
||||
SET(FluidSynth_FIND_QUIETLY TRUE)
|
||||
ENDIF (FLUIDSYNTH_INCLUDE_DIR AND FLUIDSYNTH_LIBRARIES)
|
||||
|
||||
FIND_PATH(FLUIDSYNTH_INCLUDE_DIR fluidsynth.h)
|
||||
|
||||
FIND_LIBRARY(FLUIDSYNTH_LIBRARIES NAMES fluidsynth )
|
||||
MARK_AS_ADVANCED( FLUIDSYNTH_LIBRARIES FLUIDSYNTH_INCLUDE_DIR )
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set FLUIDSYNTH_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(FluidSynth DEFAULT_MSG FLUIDSYNTH_LIBRARIES FLUIDSYNTH_INCLUDE_DIR)
|
||||
|
|
@ -1 +1,3 @@
|
|||
This version of ZDoom must be compiled with any version between 4.22 and 4.28 inclusive.
|
||||
Use of the latest 4.26 is recommended though due to technical issues with 4.28.
|
||||
|
||||
|
|
|
@ -161,6 +161,9 @@ Note: All <bool> fields default to false unless mentioned otherwise.
|
|||
nofallingdamage = <bool>; // Falling damage is disabled in this sector
|
||||
dropactors = <bool>; // Actors drop with instantly moving floors (*)
|
||||
norespawn = <bool>; // Players can not respawn in this sector
|
||||
soundsequence = <string>; // The sound sequence to play when this sector moves. Placing a
|
||||
// sound sequence thing in the sector will override this property.
|
||||
hidden = <bool>; // if true this sector will not be drawn on the textured automap.
|
||||
|
||||
* Note about dropactors
|
||||
|
||||
|
@ -178,6 +181,8 @@ Note: All <bool> fields default to false unless mentioned otherwise.
|
|||
class# = <bool> // Unlike the base spec, # can range from 1-8.
|
||||
// 8 is the maximum amount of classes the class
|
||||
// menu can display.
|
||||
conversation = <int> // Assigns a conversation dialogue to this thing.
|
||||
// Parameter is the conversation ID, 0 meaning none.
|
||||
}
|
||||
|
||||
|
||||
|
@ -263,6 +268,15 @@ Changed node specifications to deprecate compression of node lump.
|
|||
1.10 25.04.2010
|
||||
Added 'playeruseback' line trigger flag.
|
||||
|
||||
1.11 07.08.2010
|
||||
Added 'soundsequnce' sector property.
|
||||
|
||||
1.12 22.08.2010
|
||||
Added 'conversation' thing property.
|
||||
|
||||
1.13 29.08.2010
|
||||
Added 'hidden' sector property.
|
||||
|
||||
===============================================================================
|
||||
EOF
|
||||
===============================================================================
|
||||
|
|
158
specs/usdf.txt
Normal file
158
specs/usdf.txt
Normal file
|
@ -0,0 +1,158 @@
|
|||
===============================================================================
|
||||
Universal Strife Dialog Format Specification v2.0 - 08/20/10
|
||||
|
||||
Written by Braden "Blzut3" Obrzut - admin@maniacsvault.net
|
||||
|
||||
Defined with input from:
|
||||
|
||||
CodeImp
|
||||
Gez
|
||||
Graf Zahl
|
||||
Quasar
|
||||
et al.
|
||||
|
||||
Copyright (c) 2010 Braden Obrzut.
|
||||
Permission is granted to copy, distribute and/or modify this document
|
||||
under the terms of the GNU Free Documentation License, Version 1.2
|
||||
or any later version published by the Free Software Foundation;
|
||||
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
|
||||
|
||||
===============================================================================
|
||||
|
||||
=======================================
|
||||
I. Grammar / Syntax
|
||||
=======================================
|
||||
|
||||
The grammar and syntax is similar to that of UDMF. A compliant UDMF parser
|
||||
should be applyable to the USDF. However, it will need to be capable of
|
||||
handling sub-blocks. Unknown sub-blocks should be skipped.
|
||||
|
||||
=======================================
|
||||
II. Implementation Semantics
|
||||
=======================================
|
||||
|
||||
------------------------------------
|
||||
II.A : Storage and Retrieval of Data
|
||||
------------------------------------
|
||||
|
||||
This is the same as in UDMF.
|
||||
|
||||
-----------------------------------
|
||||
II.B : Storage Within Archive Files
|
||||
-----------------------------------
|
||||
|
||||
There are two options for the USDF lump placement. This can either be a part
|
||||
of the UDMF lump list or standalone. If used stand alone the lump name
|
||||
DIALOGXY is used corresponding with MAPXY. For UDMF the lump shall be called
|
||||
"DIALOGUE".
|
||||
|
||||
--------------------------------
|
||||
II.C : Implementation Dependence
|
||||
--------------------------------
|
||||
|
||||
USDF also implements the namespace statement. This has all the same
|
||||
requirements as UDMF.
|
||||
|
||||
=======================================
|
||||
III. Standardized Fields
|
||||
=======================================
|
||||
|
||||
The following are required for all USDF complient implementations. Like UDMF,
|
||||
any unknown field/function should be ignored and not treated as an error.
|
||||
|
||||
NOTE: "mobj" refers to Strife's conversationIDs and not doom editor numbers or
|
||||
Hexen's spawnids. A valid mobj value is any positive integer greater
|
||||
than or equal to 1.
|
||||
|
||||
---------------------
|
||||
III.A : Conversations
|
||||
---------------------
|
||||
|
||||
Conversations are groups of pages that can be assigned to a particular object.
|
||||
Implementors should preserve the IDs to allow for dynamic reassignment through
|
||||
scripting although this is not a requirement.
|
||||
|
||||
conversation // Starts a dialog.
|
||||
{
|
||||
actor = <integer>; // mobj for this conversation's actor. If previously
|
||||
// used, this will override the previous conversation.
|
||||
|
||||
page // Starts a new page. Pages are automatically numbered starting at 0.
|
||||
{
|
||||
name = <string>; // Name that goes in the upper left hand corner
|
||||
panel = <string>; // Name of lump to render as the background.
|
||||
voice = <string>; // Narration sound lump.
|
||||
dialog = <string>; // Dialog of the page.
|
||||
drop = <integer>; // mobj for the object to drop if the actor is
|
||||
// killed.
|
||||
link = <integer>; // Page to jump to if all ifitem conditions are
|
||||
// satisified.
|
||||
|
||||
// jumps to the specified page if the player has the specified amount
|
||||
// or more of item in their inventory. This can be repeated as many
|
||||
// times as the author wants, all conditions must be met for the
|
||||
// jump to occur.
|
||||
ifitem
|
||||
{
|
||||
item = <integer>; // mobj of item to check.
|
||||
amount = <integer>; // amount required to be in inventory.
|
||||
}
|
||||
|
||||
// Choices shall be automatically numbered.
|
||||
choice
|
||||
{
|
||||
text = <string>; // Name of the choice.
|
||||
|
||||
// The amount of an item needed to successfully pick this option.
|
||||
// This can be repeated, but only the first will be shown (provided
|
||||
// diaplaycost is true). All costs must be satisfied for success.
|
||||
cost
|
||||
{
|
||||
item = <integer>; // Item that is required for this option.
|
||||
amount = <integer>; // Minimum amount of the item needed.
|
||||
}
|
||||
|
||||
displaycost = <bool>; // Weather the cost should be
|
||||
// displayed with the option.
|
||||
// If no cost is specified this should
|
||||
// be ignored.
|
||||
yesmessage = <string>; // Text to add to console when choice
|
||||
// is accepted.
|
||||
nomessage = <string>; // Text to add to console when choice
|
||||
// is denied.
|
||||
|
||||
log = <string>; // LOG entry to use on success.
|
||||
giveitem = <integer>; // Gives the specified item upon
|
||||
// success.
|
||||
// The following are the same as the special for linedefs in UDMF.
|
||||
// They are executed on success.
|
||||
special = <integer>;
|
||||
arg0 = <integer>;
|
||||
arg1 = <integer>;
|
||||
arg2 = <integer>;
|
||||
arg3 = <integer>;
|
||||
arg4 = <integer>;
|
||||
|
||||
nextpage = <integer>; // Sets the next page.
|
||||
closedialog = <bool>; // Should the dialog be closed upon
|
||||
// selecting this choice?
|
||||
// Default: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-------------------------------
|
||||
III.B : Including Other Dialogs
|
||||
-------------------------------
|
||||
|
||||
Unlike the original Strife dialog format. The lump "SCRIPT00" should not be
|
||||
included automatically. Instead the user must specify this behavior by using
|
||||
the include function, which takes the name of a lump to include. Include only
|
||||
needs to be available in the global scope and for compatibility reasons, must
|
||||
include the result of the script and not act like a preprocessor statement.
|
||||
|
||||
include = <string>;
|
||||
|
||||
===============================================================================
|
||||
EOF
|
||||
===============================================================================
|
89
specs/usdf_zdoom.txt
Normal file
89
specs/usdf_zdoom.txt
Normal file
|
@ -0,0 +1,89 @@
|
|||
===============================================================================
|
||||
ZDoom Strife Dialog Format ZDoom v1.1 - 23.08.2010
|
||||
based on Universal Strife Dialog Format v2.0
|
||||
|
||||
Copyright (c) 2010 Christoph Oelckers.
|
||||
Permission is granted to copy, distribute and/or modify this document
|
||||
under the terms of the GNU Free Documentation License, Version 1.2
|
||||
or any later version published by the Free Software Foundation;
|
||||
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
|
||||
|
||||
===============================================================================
|
||||
|
||||
=======================================
|
||||
I. Grammar / Syntax
|
||||
=======================================
|
||||
|
||||
No changes.
|
||||
|
||||
=======================================
|
||||
II. Implementation Semantics
|
||||
=======================================
|
||||
|
||||
No changes.
|
||||
|
||||
=======================================
|
||||
III. Changes to USDF spec
|
||||
=======================================
|
||||
|
||||
ZDoom Strife Dialogue format implements the USDF base specification as described with one important change:
|
||||
To take advantage of named actor classes any field specifying an actor type
|
||||
by a conversationID takes a class name instead.
|
||||
The following fields are affected by this change:
|
||||
|
||||
conversation
|
||||
{
|
||||
actor = <string>;
|
||||
|
||||
page
|
||||
{
|
||||
drop = <string>;
|
||||
ifitem
|
||||
{
|
||||
item = <string>;
|
||||
}
|
||||
|
||||
choice
|
||||
{
|
||||
cost
|
||||
{
|
||||
item = <string>;
|
||||
}
|
||||
|
||||
giveitem = <string>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
It should be noted that this change creates an incompatibility with USDF
|
||||
so technically speaking the ZDoom format is no longer 'real' USDF.
|
||||
To accomodate what is needed here this is unavoidable, unfortunately.
|
||||
Any proper USDF implementation not supporting named actor classes should
|
||||
either refuse loading dialogues with the 'ZDoom' namespace or if it does not
|
||||
outright abort on incompatible namespaces fail with a type mismatch error on
|
||||
one of the specified propeties.
|
||||
|
||||
ZDoom-format dialogues need to start with the line:
|
||||
|
||||
namespace = "ZDoom";
|
||||
|
||||
|
||||
---------------------
|
||||
III.A : Conversations
|
||||
---------------------
|
||||
|
||||
This block only lists the newly added fields. Currently ZDoom only adds one
|
||||
field to the specification:
|
||||
|
||||
conversation // Starts a dialog.
|
||||
{
|
||||
id = <int>; // assigns an ID to a dialogue. IDs are used to dynamically assign
|
||||
// dialogues to actors. For 'Strife' namespace or binary dialogues
|
||||
// the standard conversation ID ('actor' property) is used instead
|
||||
// for this purpose but since 'ZDoom' namespace requires the actor
|
||||
// to be a class name it needs a separate field for this.
|
||||
}
|
||||
|
||||
===============================================================================
|
||||
EOF
|
||||
===============================================================================
|
|
@ -6,13 +6,21 @@ endif( COMMAND cmake_policy )
|
|||
|
||||
include( CheckCXXSourceCompiles )
|
||||
include( CheckFunctionExists )
|
||||
include( CheckCXXCompilerFlag )
|
||||
include( FindPkgConfig )
|
||||
|
||||
option( NO_ASM "Disable assembly code" )
|
||||
if( CMAKE_COMPILER_IS_GNUCXX )
|
||||
option( NO_STRIP "Do not strip Release or MinSizeRel builds" )
|
||||
# At least some versions of Xcode fail if you strip with the linker
|
||||
# instead of the separate strip utility.
|
||||
if( APPLE )
|
||||
set( NO_STRIP ON )
|
||||
endif( APPLE )
|
||||
endif( CMAKE_COMPILER_IS_GNUCXX )
|
||||
|
||||
option( DYN_FLUIDSYNTH "Dynamically load fluidsynth" )
|
||||
|
||||
if( CMAKE_SIZEOF_VOID_P MATCHES "8" )
|
||||
set( X64 64 )
|
||||
endif( CMAKE_SIZEOF_VOID_P MATCHES "8" )
|
||||
|
@ -25,6 +33,10 @@ endif( CMAKE_SIZEOF_VOID_P MATCHES "8" )
|
|||
# fmodapi<version>linux[64] -or simply- fmod
|
||||
# jpeg-6b
|
||||
# ...
|
||||
# The recommended method is to put it in the zdoom tree, since its
|
||||
# headers are unversioned. Especially now that we can't work properly
|
||||
# with anything newer than 4.26.xx, you probably don't want to use
|
||||
# a system-wide version.
|
||||
|
||||
# Construct version numbers for searching for the FMOD library on Linux.
|
||||
set( MINOR_VERSIONS "50" "49" "48" "47" "46" "45" "44" "43" "42" "41"
|
||||
|
@ -32,7 +44,7 @@ set( MINOR_VERSIONS "50" "49" "48" "47" "46" "45" "44" "43" "42" "41"
|
|||
"27" "26" "25" "24" "23" "22" "21" "20" "21" "19" "18" "17" "16"
|
||||
"15" "14" "13" "12" "11" "10" "09" "08" "07" "06" "05" "04" "03"
|
||||
"02" "01" "00" )
|
||||
set( MAJOR_VERSIONS "26" "24" "22" "20" )
|
||||
set( MAJOR_VERSIONS "30" "28" "26" "24" "22" "20" )
|
||||
set( FMOD_DIR_VERSIONS ${FMOD_DIR_VERSIONS} "../fmod" )
|
||||
foreach( majver ${MAJOR_VERSIONS} )
|
||||
foreach( minver ${MINOR_VERSIONS} )
|
||||
|
@ -230,14 +242,11 @@ else( FMOD_LIBRARY )
|
|||
endif( FMOD_LIBRARY )
|
||||
|
||||
|
||||
# Search for NASM
|
||||
# Search for FluidSynth
|
||||
|
||||
if( CMAKE_SYSTEM_PROCESSOR MATCHES powerpc )
|
||||
if( NOT NO_ASM )
|
||||
message( STATUS "Disabling assembly code for PowerPC." )
|
||||
set( NO_ASM ON )
|
||||
endif( NOT NO_ASM )
|
||||
endif( CMAKE_SYSTEM_PROCESSOR MATCHES powerpc )
|
||||
include( ../FindFluidSynth.cmake )
|
||||
|
||||
# Search for NASM
|
||||
|
||||
if( NOT NO_ASM )
|
||||
if( UNIX AND X64 )
|
||||
|
@ -297,7 +306,12 @@ if( NOT NO_ASM )
|
|||
set( ASM_FLAGS )
|
||||
set( ASM_SOURCE_EXTENSION .s )
|
||||
else( X64 )
|
||||
set( ASM_FLAGS -f elf -DM_TARGET_LINUX -i${CMAKE_CURRENT_SOURCE_DIR}/ )
|
||||
if( APPLE )
|
||||
set( ASM_FLAGS -fmacho -DM_TARGET_MACHO )
|
||||
else( APPLE )
|
||||
set( ASM_FLAGS -felf -DM_TARGET_LINUX )
|
||||
endif( APPLE )
|
||||
set( ASM_FLAGS "${ASM_FLAGS}" -i${CMAKE_CURRENT_SOURCE_DIR}/ )
|
||||
set( ASM_SOURCE_EXTENSION .asm )
|
||||
endif( X64 )
|
||||
else( UNIX )
|
||||
|
@ -327,9 +341,52 @@ if( NOT NO_ASM )
|
|||
ENDMACRO( ADD_ASM_FILE )
|
||||
endif( NOT NO_ASM )
|
||||
|
||||
# Decide on SSE setup
|
||||
|
||||
set( SSE_MATTERS NO )
|
||||
|
||||
# SSE only matters on 32-bit targets. We check compiler flags to know if we can do it.
|
||||
if( CMAKE_SIZEOF_VOID_P MATCHES "4" )
|
||||
CHECK_CXX_COMPILER_FLAG( "-msse2 -mfpmath=sse" CAN_DO_MFPMATH )
|
||||
CHECK_CXX_COMPILER_FLAG( -arch:SSE2 CAN_DO_ARCHSSE2 )
|
||||
if( CAN_DO_MFPMATH )
|
||||
set( SSE1_ENABLE "-msse -mfpmath=sse" )
|
||||
set( SSE2_ENABLE "-msse2 -mfpmath=sse" )
|
||||
set( SSE_MATTERS YES )
|
||||
elseif( CAN_DO_ARCHSSE2 )
|
||||
set( SSE1_ENABLE -arch:SSE )
|
||||
set( SSE2_ENABLE -arch:SSE2 )
|
||||
set( SSE_MATTERS YES )
|
||||
endif( CAN_DO_MFPMATH )
|
||||
endif( CMAKE_SIZEOF_VOID_P MATCHES "4" )
|
||||
|
||||
if( SSE_MATTERS )
|
||||
if( WIN32 )
|
||||
set( BACKPATCH 1 CACHE BOOL "Enable backpatching." )
|
||||
else( WIN32 )
|
||||
CHECK_FUNCTION_EXISTS(mprotect HAVE_MPROTECT)
|
||||
if( HAVE_MPROTECT )
|
||||
set( BACKPATCH 1 CACHE BOOL "Enable backpatching." )
|
||||
else( HAVE_MPROTECT )
|
||||
set( BACKPATCH 0 )
|
||||
endif( HAVE_MPROTECT )
|
||||
endif( WIN32 )
|
||||
set( SSE 1 CACHE BOOL "Build SSE and SSE2 versions of key code." )
|
||||
else( SSE_MATTERS )
|
||||
set( BACKPATCH 0 )
|
||||
endif( SSE_MATTERS )
|
||||
|
||||
# Set up flags for GCC
|
||||
|
||||
if( CMAKE_COMPILER_IS_GNUCXX )
|
||||
if( PROFILE )
|
||||
set( CMAKE_C_FLinclude( FindFluidSynth.cmake )
|
||||
AGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -pg" )
|
||||
set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pg" )
|
||||
set( CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -pg" )
|
||||
set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -pg" )
|
||||
endif( PROFILE )
|
||||
|
||||
set( REL_CXX_FLAGS "-fno-rtti" )
|
||||
if( NOT PROFILE )
|
||||
set( REL_CXX_FLAGS "${REL_CXX_FLAGS} -fomit-frame-pointer" )
|
||||
|
@ -415,6 +472,12 @@ if( NOT HAS_VA_COPY )
|
|||
endif( HAS___VA_COPY )
|
||||
endif( NOT HAS_VA_COPY )
|
||||
|
||||
# Flags
|
||||
|
||||
if( BACKPATCH )
|
||||
add_definitions( -DBACKPATCH )
|
||||
endif( BACKPATCH )
|
||||
|
||||
# Update svnrevision.h
|
||||
|
||||
add_custom_target( revision_check ALL
|
||||
|
@ -424,8 +487,16 @@ add_custom_target( revision_check ALL
|
|||
|
||||
# Libraries ZDoom needs
|
||||
|
||||
message( STATUS "Fluid synth libs: ${FLUIDSYNTH_LIBRARIES}" )
|
||||
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ZLIB_LIBRARIES}" "${JPEG_LIBRARIES}" "${BZIP2_LIBRARIES}" "${FMOD_LIBRARY}" )
|
||||
include_directories( "${ZLIB_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${FMOD_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" )
|
||||
include_directories( "${ZLIB_INCLUDE_DIR}" "${FMOD_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" )
|
||||
|
||||
if( FLUIDSYNTH_FOUND )
|
||||
if( NOT DYN_FLUIDSYNTH)
|
||||
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${FLUIDSYNTH_LIBRARIES}" )
|
||||
include_directories( "${FLUIDSYNTH_INCLUDE_DIR}" )
|
||||
endif( NOT DYN_FLUIDSYNTH )
|
||||
endif( FLUIDSYNTH_FOUND )
|
||||
|
||||
# Start defining source files for ZDoom
|
||||
|
||||
|
@ -473,7 +544,7 @@ else( WIN32 )
|
|||
sdl/sdlvideo.cpp
|
||||
sdl/st_start.cpp )
|
||||
if( APPLE )
|
||||
set( SYSTEM_SOURCES ${SYSTEM_SOURCES} sdl/SDLMain.m )
|
||||
set( SYSTEM_SOURCES ${SYSTEM_SOURCES} sdl/SDLMain.m sdl/iwadpicker_cocoa.mm )
|
||||
endif( APPLE )
|
||||
endif( WIN32 )
|
||||
|
||||
|
@ -508,12 +579,23 @@ add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h
|
|||
|
||||
include_directories( ${CMAKE_CURRENT_BINARY_DIR} )
|
||||
|
||||
if( CMAKE_SYSTEM_PROCESSOR MATCHES powerpc )
|
||||
if( SSE_MATTERS )
|
||||
if( SSE )
|
||||
set( X86_SOURCES nodebuild_classify_sse2.cpp )
|
||||
set_source_files_properties( nodebuild_classify_sse2.cpp PROPERTIES COMPILE_FLAGS "${SSE2_ENABLE}" )
|
||||
else( SSE )
|
||||
add_definitions( -DDISABLE_SSE )
|
||||
endif( SSE )
|
||||
else( SSE_MATTERS )
|
||||
add_definitions( -DDISABLE_SSE )
|
||||
set( X86_SOURCES )
|
||||
set( NOT_X86 ON )
|
||||
else( CMAKE_SYSTEM_PROCESSOR MATCHES powerpc )
|
||||
set( X86_SOURCES nodebuild_classify_sse2.cpp )
|
||||
endif( CMAKE_SYSTEM_PROCESSOR MATCHES powerpc )
|
||||
endif( SSE_MATTERS )
|
||||
|
||||
if( DYN_FLUIDSYNTH )
|
||||
add_definitions( -DHAVE_FLUIDSYNTH -DDYN_FLUIDSYNTH )
|
||||
elseif( FLUIDSYNTH_FOUND )
|
||||
add_definitions( -DHAVE_FLUIDSYNTH )
|
||||
endif( DYN_FLUIDSYNTH )
|
||||
|
||||
add_executable( zdoom WIN32
|
||||
autostart.cpp
|
||||
|
@ -567,19 +649,17 @@ add_executable( zdoom WIN32
|
|||
hu_scores.cpp
|
||||
i_net.cpp
|
||||
info.cpp
|
||||
keysections.cpp
|
||||
lumpconfigfile.cpp
|
||||
m_alloc.cpp
|
||||
m_argv.cpp
|
||||
m_bbox.cpp
|
||||
m_cheat.cpp
|
||||
m_joy.cpp
|
||||
m_menu.cpp
|
||||
m_misc.cpp
|
||||
m_options.cpp
|
||||
m_png.cpp
|
||||
m_random.cpp
|
||||
md5.cpp
|
||||
mus2midi.cpp
|
||||
name.cpp
|
||||
nodebuild.cpp
|
||||
nodebuild_classify_nosse2.cpp
|
||||
|
@ -597,6 +677,7 @@ add_executable( zdoom WIN32
|
|||
p_effect.cpp
|
||||
p_enemy.cpp
|
||||
p_floor.cpp
|
||||
p_glnodes.cpp
|
||||
p_interaction.cpp
|
||||
p_lights.cpp
|
||||
p_linkedsectors.cpp
|
||||
|
@ -621,6 +702,7 @@ add_executable( zdoom WIN32
|
|||
p_tick.cpp
|
||||
p_trace.cpp
|
||||
p_udmf.cpp
|
||||
p_usdf.cpp
|
||||
p_user.cpp
|
||||
p_writemap.cpp
|
||||
p_xlat.cpp
|
||||
|
@ -705,6 +787,19 @@ add_executable( zdoom WIN32
|
|||
g_shared/sbar_mugshot.cpp
|
||||
g_shared/shared_hud.cpp
|
||||
g_shared/shared_sbar.cpp
|
||||
menu/colorpickermenu.cpp
|
||||
menu/joystickmenu.cpp
|
||||
menu/listmenu.cpp
|
||||
menu/loadsavemenu.cpp
|
||||
menu/menu.cpp
|
||||
menu/menudef.cpp
|
||||
menu/menuinput.cpp
|
||||
menu/messagebox.cpp
|
||||
menu/optionmenu.cpp
|
||||
menu/playerdisplay.cpp
|
||||
menu/playermenu.cpp
|
||||
menu/readthis.cpp
|
||||
menu/videomenu.cpp
|
||||
oplsynth/fmopl.cpp
|
||||
oplsynth/mlopl.cpp
|
||||
oplsynth/mlopl_io.cpp
|
||||
|
@ -728,13 +823,16 @@ add_executable( zdoom WIN32
|
|||
sound/music_cd.cpp
|
||||
sound/music_dumb.cpp
|
||||
sound/music_gme.cpp
|
||||
sound/music_mus_midiout.cpp
|
||||
sound/music_smf_midiout.cpp
|
||||
sound/music_hmi_midiout.cpp
|
||||
sound/music_midistream.cpp
|
||||
sound/music_midi_base.cpp
|
||||
sound/music_midi_midiout.cpp
|
||||
sound/music_midi_timidity.cpp
|
||||
sound/music_mus_midiout.cpp
|
||||
sound/music_mus_opl.cpp
|
||||
sound/music_stream.cpp
|
||||
sound/music_fluidsynth_mididevice.cpp
|
||||
sound/music_softsynth_mididevice.cpp
|
||||
sound/music_timidity_mididevice.cpp
|
||||
sound/music_win_mididevice.cpp
|
||||
textures/automaptexture.cpp
|
||||
|
@ -817,21 +915,12 @@ if( NOT WIN32 )
|
|||
COMMAND chmod +x ${CMAKE_CURRENT_BINARY_DIR}/link-make
|
||||
COMMAND /bin/sh -c ${CMAKE_CURRENT_BINARY_DIR}/link-make )
|
||||
endif( NOT WIN32 )
|
||||
|
||||
if( CMAKE_COMPILER_IS_GNUCXX )
|
||||
# GCC misoptimizes this file
|
||||
set_source_files_properties( oplsynth/fmopl.cpp PROPERTIES COMPILE_FLAGS "-fno-tree-dominator-opts -fno-tree-fre" )
|
||||
|
||||
# Compile this one file with SSE2 support.
|
||||
set_source_files_properties( nodebuild_classify_sse2.cpp PROPERTIES COMPILE_FLAGS "-msse2 -mfpmath=sse" )
|
||||
|
||||
# Need to enable intrinsics for this file.
|
||||
if( NOT NOT_X86 )
|
||||
if( SSE_MATTERS )
|
||||
set_source_files_properties( x86.cpp PROPERTIES COMPILE_FLAGS "-msse2 -mmmx" )
|
||||
endif( NOT NOT_X86 )
|
||||
endif( SSE_MATTERS )
|
||||
endif( CMAKE_COMPILER_IS_GNUCXX )
|
||||
|
||||
if( MSVC )
|
||||
# Compile this one file with SSE2 support.
|
||||
set_source_files_properties( nodebuild_classify_sse2.cpp PROPERTIES COMPILE_FLAGS "/arch:SSE2" )
|
||||
endif( MSVC )
|
||||
|
|
|
@ -57,7 +57,7 @@ DEFINE_SPECIAL(Line_SetBlocking, 55, 3, 3, 3)
|
|||
DEFINE_SPECIAL(Line_SetTextureScale, 56, 5, 5, 5)
|
||||
DEFINE_SPECIAL(Sector_SetPortal, 57, -1, -1, 5)
|
||||
DEFINE_SPECIAL(Sector_CopyScroller, 58, -1, -1, 2)
|
||||
|
||||
DEFINE_SPECIAL(Polyobj_OR_MoveToSpot, 59, 3, 3, 3)
|
||||
DEFINE_SPECIAL(Plat_PerpetualRaise, 60, 3, 3, 3)
|
||||
DEFINE_SPECIAL(Plat_Stop, 61, 1, 1, 1)
|
||||
DEFINE_SPECIAL(Plat_DownWaitUpStay, 62, 3, 3, 3)
|
||||
|
@ -77,14 +77,17 @@ DEFINE_SPECIAL(Teleport_EndGame, 75, 0, 0, 0)
|
|||
DEFINE_SPECIAL(TeleportOther, 76, 3, 3, 3)
|
||||
DEFINE_SPECIAL(TeleportGroup, 77, 5, 5, 5)
|
||||
DEFINE_SPECIAL(TeleportInSector, 78, 4, 5, 5)
|
||||
|
||||
DEFINE_SPECIAL(Thing_SetConversation, 79, 2, 2, 2)
|
||||
DEFINE_SPECIAL(ACS_Execute, 80, 1, 5, 5)
|
||||
DEFINE_SPECIAL(ACS_Suspend, 81, 2, 2, 2)
|
||||
DEFINE_SPECIAL(ACS_Terminate, 82, 2, 2, 2)
|
||||
DEFINE_SPECIAL(ACS_LockedExecute, 83, 5, 5, 5)
|
||||
DEFINE_SPECIAL(ACS_ExecuteWithResult, 84, 1, 4, 4)
|
||||
DEFINE_SPECIAL(ACS_LockedExecuteDoor, 85, 5, 5, 5)
|
||||
|
||||
DEFINE_SPECIAL(Polyobj_MoveToSpot, 86, 3, 3, 3)
|
||||
DEFINE_SPECIAL(Polyobj_Stop, 87, 1, 1, 1)
|
||||
DEFINE_SPECIAL(Polyobj_MoveTo, 88, 4, 4, 4)
|
||||
DEFINE_SPECIAL(Polyobj_OR_MoveTo, 89, 4, 4, 4)
|
||||
DEFINE_SPECIAL(Polyobj_OR_RotateLeft, 90, 3, 3, 3)
|
||||
DEFINE_SPECIAL(Polyobj_OR_RotateRight, 91, 3, 3, 3)
|
||||
DEFINE_SPECIAL(Polyobj_OR_Move, 92, 4, 4, 4)
|
||||
|
@ -111,7 +114,9 @@ DEFINE_SPECIAL(Plane_Copy, 118, -1, -1, 5)
|
|||
DEFINE_SPECIAL(Thing_Damage, 119, 2, 3, 3)
|
||||
DEFINE_SPECIAL(Radius_Quake, 120, 5, 5, 5) // Earthquake
|
||||
DEFINE_SPECIAL(Line_SetIdentification, 121, -1, -1, 5)
|
||||
|
||||
DEFINE_SPECIAL(Thing_Move, 125, 2, 3, 3)
|
||||
|
||||
DEFINE_SPECIAL(Thing_SetSpecial, 127, 5, 5, 5)
|
||||
DEFINE_SPECIAL(ThrustThingZ, 128, 4, 4, 4)
|
||||
DEFINE_SPECIAL(UsePuzzleItem, 129, 2, 5, 5)
|
||||
|
|
32
src/actor.h
32
src/actor.h
|
@ -40,6 +40,7 @@
|
|||
#include "r_blend.h"
|
||||
#include "s_sound.h"
|
||||
|
||||
struct subsector_t;
|
||||
//
|
||||
// NOTES: AActor
|
||||
//
|
||||
|
@ -320,6 +321,8 @@ enum
|
|||
MF6_SHATTERING = 0x00020000, // marks an ice corpse for forced shattering
|
||||
MF6_KILLED = 0x00040000, // Something that was killed (but not necessarily a corpse)
|
||||
MF6_BLOCKEDBYSOLIDACTORS = 0x00080000, // Blocked by solid actors, even if not solid itself
|
||||
MF6_ADDITIVEPOISONDAMAGE = 0x00100000,
|
||||
MF6_ADDITIVEPOISONDURATION = 0x00200000,
|
||||
|
||||
// --- mobj.renderflags ---
|
||||
|
||||
|
@ -505,7 +508,6 @@ enum
|
|||
AMETA_BloodColor, // colorized blood
|
||||
AMETA_GibHealth, // negative health below which this monster dies an extreme death
|
||||
AMETA_WoundHealth, // health needed to enter wound state
|
||||
AMETA_PoisonDamage, // Amount of poison damage
|
||||
AMETA_FastSpeed, // Speed in fast mode
|
||||
AMETA_RDFactor, // Radius damage factor
|
||||
AMETA_CameraHeight, // Height of camera when used as such
|
||||
|
@ -721,19 +723,26 @@ public:
|
|||
|
||||
const PClass *GetBloodType(int type = 0) const
|
||||
{
|
||||
const PClass *bloodcls;
|
||||
if (type == 0)
|
||||
{
|
||||
return PClass::FindClass((ENamedName)GetClass()->Meta.GetMetaInt(AMETA_BloodType, NAME_Blood));
|
||||
bloodcls = PClass::FindClass((ENamedName)GetClass()->Meta.GetMetaInt(AMETA_BloodType, NAME_Blood));
|
||||
}
|
||||
else if (type == 1)
|
||||
{
|
||||
return PClass::FindClass((ENamedName)GetClass()->Meta.GetMetaInt(AMETA_BloodType2, NAME_BloodSplatter));
|
||||
bloodcls = PClass::FindClass((ENamedName)GetClass()->Meta.GetMetaInt(AMETA_BloodType2, NAME_BloodSplatter));
|
||||
}
|
||||
else if (type == 2)
|
||||
{
|
||||
return PClass::FindClass((ENamedName)GetClass()->Meta.GetMetaInt(AMETA_BloodType3, NAME_AxeBlood));
|
||||
bloodcls = PClass::FindClass((ENamedName)GetClass()->Meta.GetMetaInt(AMETA_BloodType3, NAME_AxeBlood));
|
||||
}
|
||||
else return NULL;
|
||||
|
||||
if (bloodcls != NULL)
|
||||
{
|
||||
bloodcls = bloodcls->GetReplacement();
|
||||
}
|
||||
return bloodcls;
|
||||
}
|
||||
|
||||
// Calculate amount of missile damage
|
||||
|
@ -765,6 +774,7 @@ public:
|
|||
fixed_t pitch, roll;
|
||||
FBlockNode *BlockNode; // links in blocks (if needed)
|
||||
struct sector_t *Sector;
|
||||
subsector_t * subsector;
|
||||
fixed_t floorz, ceilingz; // closest together of contacted secs
|
||||
fixed_t dropoffz; // killough 11/98: the lowest floor over all contacted Sectors.
|
||||
|
||||
|
@ -843,6 +853,15 @@ public:
|
|||
AActor *BlockingMobj; // Actor that blocked the last move
|
||||
line_t *BlockingLine; // Line that blocked the last move
|
||||
|
||||
int PoisonDamage; // Damage received per tic from poison.
|
||||
int PoisonDuration; // Duration left for receiving poison damage.
|
||||
int PoisonPeriod; // How often poison damage is applied. (Every X tics.)
|
||||
|
||||
int PoisonDamageReceived; // Damage received per tic from poison.
|
||||
int PoisonDurationReceived; // Duration left for receiving poison damage.
|
||||
int PoisonPeriodReceived; // How often poison damage is applied. (Every X tics.)
|
||||
TObjPtr<AActor> Poisoner; // Last source of received poison damage.
|
||||
|
||||
// a linked list of sectors where this object appears
|
||||
struct msecnode_t *touching_sectorlist; // phares 3/14/98
|
||||
|
||||
|
@ -882,8 +901,9 @@ public:
|
|||
FState *MeleeState;
|
||||
FState *MissileState;
|
||||
|
||||
// [RH] The dialogue to show when this actor is "used."
|
||||
FStrifeDialogueNode *Conversation;
|
||||
|
||||
int ConversationRoot; // THe root of the current dialogue
|
||||
FStrifeDialogueNode *Conversation; // [RH] The dialogue to show when this actor is "used."
|
||||
|
||||
// [RH] Decal(s) this weapon/projectile generates on impact.
|
||||
FDecalBase *DecalGenerator;
|
||||
|
|
601
src/am_map.cpp
601
src/am_map.cpp
|
@ -36,6 +36,9 @@
|
|||
#include "r_translate.h"
|
||||
#include "d_event.h"
|
||||
#include "gi.h"
|
||||
#include "r_bsp.h"
|
||||
#include "p_setup.h"
|
||||
#include "c_bind.h"
|
||||
|
||||
#include "m_cheat.h"
|
||||
#include "i_system.h"
|
||||
|
@ -58,6 +61,8 @@
|
|||
|
||||
#include "am_map.h"
|
||||
#include "a_artifacts.h"
|
||||
#include "po_man.h"
|
||||
#include "a_keys.h"
|
||||
|
||||
struct AMColor
|
||||
{
|
||||
|
@ -79,7 +84,7 @@ struct AMColor
|
|||
|
||||
static AMColor Background, YourColor, WallColor, TSWallColor,
|
||||
FDWallColor, CDWallColor, ThingColor,
|
||||
ThingColor_Item, ThingColor_Monster, ThingColor_Friend,
|
||||
ThingColor_Item, ThingColor_CountItem, ThingColor_Monster, ThingColor_Friend,
|
||||
SecretWallColor, GridColor, XHairColor,
|
||||
NotSeenColor,
|
||||
LockedColor,
|
||||
|
@ -170,12 +175,27 @@ CVAR (Color, am_secretsectorcolor, 0xff00ff, CVAR_ARCHIVE);
|
|||
CVAR (Color, am_ovsecretsectorcolor,0x00ffff, CVAR_ARCHIVE);
|
||||
CVAR (Int, am_map_secrets, 1, CVAR_ARCHIVE);
|
||||
CVAR (Bool, am_drawmapback, true, CVAR_ARCHIVE);
|
||||
CVAR (Bool, am_showkeys, true, CVAR_ARCHIVE);
|
||||
CVAR (Color, am_thingcolor_friend, 0xfcfcfc, CVAR_ARCHIVE);
|
||||
CVAR (Color, am_thingcolor_monster, 0xfcfcfc, CVAR_ARCHIVE);
|
||||
CVAR (Color, am_thingcolor_item, 0xfcfcfc, CVAR_ARCHIVE);
|
||||
CVAR (Color, am_thingcolor_citem, 0xfcfcfc, CVAR_ARCHIVE);
|
||||
CVAR (Color, am_ovthingcolor_friend, 0xe88800, CVAR_ARCHIVE);
|
||||
CVAR (Color, am_ovthingcolor_monster, 0xe88800, CVAR_ARCHIVE);
|
||||
CVAR (Color, am_ovthingcolor_item, 0xe88800, CVAR_ARCHIVE);
|
||||
CVAR (Color, am_ovthingcolor_citem, 0xe88800, CVAR_ARCHIVE);
|
||||
|
||||
|
||||
static int bigstate = 0;
|
||||
static bool textured = 1; // internal toggle for texture mode
|
||||
|
||||
CUSTOM_CVAR(Bool, am_textured, false, CVAR_ARCHIVE)
|
||||
{
|
||||
textured |= self;
|
||||
}
|
||||
|
||||
CVAR(Int, am_showsubsector, -1, 0);
|
||||
|
||||
|
||||
// Disable the ML_DONTDRAW line flag if x% of all lines in a map are flagged with it
|
||||
// (To counter annoying mappers who think they are smart by making the automap unusable)
|
||||
|
@ -216,21 +236,6 @@ CUSTOM_CVAR (Int, am_showalllines, -1, 0) // This is a cheat so don't save it.
|
|||
}
|
||||
|
||||
|
||||
// drawing stuff
|
||||
#define AM_PANDOWNKEY KEY_DOWNARROW
|
||||
#define AM_PANUPKEY KEY_UPARROW
|
||||
#define AM_PANRIGHTKEY KEY_RIGHTARROW
|
||||
#define AM_PANLEFTKEY KEY_LEFTARROW
|
||||
#define AM_ZOOMINKEY KEY_EQUALS
|
||||
#define AM_ZOOMINKEY2 0x4e // DIK_ADD
|
||||
#define AM_ZOOMOUTKEY KEY_MINUS
|
||||
#define AM_ZOOMOUTKEY2 0x4a // DIK_SUBTRACT
|
||||
#define AM_GOBIGKEY 0x0b // DIK_0
|
||||
#define AM_FOLLOWKEY 'f'
|
||||
#define AM_GRIDKEY 'g'
|
||||
#define AM_MARKKEY 'm'
|
||||
#define AM_CLEARMARKKEY 'c'
|
||||
|
||||
#define AM_NUMMARKPOINTS 10
|
||||
|
||||
// player radius for automap checking
|
||||
|
@ -241,10 +246,10 @@ CUSTOM_CVAR (Int, am_showalllines, -1, 0) // This is a cheat so don't save it.
|
|||
#define F_PANINC (140/TICRATE)
|
||||
// how much zoom-in per tic
|
||||
// goes to 2x in 1 second
|
||||
#define M_ZOOMIN ((int) (1.02*MAPUNIT))
|
||||
#define M_ZOOMIN (1.02*MAPUNIT)
|
||||
// how much zoom-out per tic
|
||||
// pulls out to 0.5x in 1 second
|
||||
#define M_ZOOMOUT ((int) (MAPUNIT/1.02))
|
||||
#define M_ZOOMOUT (MAPUNIT/1.02)
|
||||
|
||||
// translates between frame-buffer and map coordinates
|
||||
#define CXMTOF(x) (MTOF((x)-m_x)/* - f_x*/)
|
||||
|
@ -292,25 +297,22 @@ mline_t player_arrow[] = {
|
|||
{ { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>--->
|
||||
{ { -R+3*R/8, 0 }, { -R+R/8, -R/4 } }
|
||||
};
|
||||
#define NUMPLYRLINES (sizeof(player_arrow)/sizeof(mline_t))
|
||||
|
||||
mline_t player_arrow_raven[] = {
|
||||
{ { -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 } }
|
||||
};
|
||||
|
||||
#undef R
|
||||
#define NUMPLYRLINES (sizeof(player_arrow)/sizeof(mline_t))
|
||||
{ { -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 } }
|
||||
};
|
||||
#define NUMPLYRLINES_RAVEN (sizeof(player_arrow_raven)/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 } }, // ----->
|
||||
|
@ -329,9 +331,9 @@ mline_t cheat_player_arrow[] = {
|
|||
{ { 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 } }
|
||||
};
|
||||
#define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow)/sizeof(mline_t))
|
||||
|
||||
#undef R
|
||||
#define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow)/sizeof(mline_t))
|
||||
|
||||
#define R (MAPUNIT)
|
||||
// [RH] Avoid lots of warnings without compiler-specific #pragmas
|
||||
|
@ -348,9 +350,37 @@ mline_t thintriangle_guy[] = {
|
|||
L (1,0, -.5,.7),
|
||||
L (-.5,.7, -.5,-.7)
|
||||
};
|
||||
#define NUMTHINTRIANGLEGUYLINES (sizeof(thintriangle_guy)/sizeof(mline_t))
|
||||
|
||||
mline_t square_guy[] = {
|
||||
L (0,1,1,0),
|
||||
L (1,0,0,-1),
|
||||
L (0,-1,-1,0),
|
||||
L (-1,0,0,1)
|
||||
};
|
||||
#define NUMSQUAREGUYLINES (sizeof(square_guy)/sizeof(mline_t))
|
||||
|
||||
#undef R
|
||||
#define R (MAPUNIT)
|
||||
|
||||
mline_t key_guy[] = {
|
||||
L (-2, 0, -1.7, -0.5),
|
||||
L (-1.7, -0.5, -1.5, -0.7),
|
||||
L (-1.5, -0.7, -0.8, -0.5),
|
||||
L (-0.8, -0.5, -0.6, 0),
|
||||
L (-0.6, 0, -0.8, 0.5),
|
||||
L (-1.5, 0.7, -0.8, 0.5),
|
||||
L (-1.7, 0.5, -1.5, 0.7),
|
||||
L (-2, 0, -1.7, 0.5),
|
||||
L (-0.6, 0, 2, 0),
|
||||
L (1.7, 0, 1.7, -1),
|
||||
L (1.5, 0, 1.5, -1),
|
||||
L (1.3, 0, 1.3, -1)
|
||||
};
|
||||
#define NUMKEYGUYLINES (sizeof(key_guy)/sizeof(mline_t))
|
||||
|
||||
#undef L
|
||||
#undef R
|
||||
#define NUMTHINTRIANGLEGUYLINES (sizeof(thintriangle_guy)/sizeof(mline_t))
|
||||
|
||||
|
||||
|
||||
|
@ -383,7 +413,7 @@ 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 float am_zoomdir;
|
||||
|
||||
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)
|
||||
|
@ -432,7 +462,69 @@ static void AM_calcMinMaxMtoF();
|
|||
void AM_rotatePoint (fixed_t *x, fixed_t *y);
|
||||
void AM_rotate (fixed_t *x, fixed_t *y, angle_t an);
|
||||
void AM_doFollowPlayer ();
|
||||
static void AM_ToggleFollowPlayer();
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// map functions
|
||||
//
|
||||
//=============================================================================
|
||||
bool AM_addMark ();
|
||||
bool AM_clearMarks ();
|
||||
void AM_saveScaleAndLoc ();
|
||||
void AM_restoreScaleAndLoc ();
|
||||
void AM_minOutWindowScale ();
|
||||
|
||||
|
||||
CCMD(am_togglefollow)
|
||||
{
|
||||
followplayer = !followplayer;
|
||||
f_oldloc.x = FIXED_MAX;
|
||||
Printf ("%s\n", GStrings(followplayer ? "AMSTR_FOLLOWON" : "AMSTR_FOLLOWOFF"));
|
||||
}
|
||||
|
||||
CCMD(am_togglegrid)
|
||||
{
|
||||
grid = !grid;
|
||||
Printf ("%s\n", GStrings(grid ? "AMSTR_GRIDON" : "AMSTR_GRIDOFF"));
|
||||
}
|
||||
|
||||
CCMD(am_toggletexture)
|
||||
{
|
||||
if (am_textured && hasglnodes)
|
||||
{
|
||||
textured = !textured;
|
||||
Printf ("%s\n", GStrings(textured ? "AMSTR_TEXON" : "AMSTR_TEXOFF"));
|
||||
}
|
||||
}
|
||||
|
||||
CCMD(am_setmark)
|
||||
{
|
||||
if (AM_addMark())
|
||||
{
|
||||
Printf ("%s %d\n", GStrings("AMSTR_MARKEDSPOT"), markpointnum);
|
||||
}
|
||||
}
|
||||
|
||||
CCMD(am_clearmarks)
|
||||
{
|
||||
if (AM_clearMarks())
|
||||
{
|
||||
Printf ("%s\n", GStrings("AMSTR_MARKSCLEARED"));
|
||||
}
|
||||
}
|
||||
|
||||
CCMD(am_gobig)
|
||||
{
|
||||
bigstate = !bigstate;
|
||||
if (bigstate)
|
||||
{
|
||||
AM_saveScaleAndLoc();
|
||||
AM_minOutWindowScale();
|
||||
}
|
||||
else
|
||||
AM_restoreScaleAndLoc();
|
||||
}
|
||||
|
||||
// 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
|
||||
|
@ -741,11 +833,19 @@ void AM_initVariables ()
|
|||
|
||||
automapactive = true;
|
||||
|
||||
// Reset AM buttons
|
||||
Button_AM_PanLeft.Reset();
|
||||
Button_AM_PanRight.Reset();
|
||||
Button_AM_PanUp.Reset();
|
||||
Button_AM_PanDown.Reset();
|
||||
Button_AM_ZoomIn.Reset();
|
||||
Button_AM_ZoomOut.Reset();
|
||||
|
||||
|
||||
f_oldloc.x = FIXED_MAX;
|
||||
amclock = 0;
|
||||
|
||||
m_paninc.x = m_paninc.y = 0;
|
||||
ftom_zoommul = MAPUNIT;
|
||||
mtof_zoommul = MAPUNIT;
|
||||
|
||||
m_w = FTOM(SCREENWIDTH);
|
||||
|
@ -813,6 +913,7 @@ static void AM_initColors (bool overlayed)
|
|||
SecretWallColor = WallColor;
|
||||
SecretSectorColor.FromCVar (am_ovsecretsectorcolor);
|
||||
ThingColor_Item.FromCVar (am_ovthingcolor_item);
|
||||
ThingColor_CountItem.FromCVar (am_ovthingcolor_citem);
|
||||
ThingColor_Friend.FromCVar (am_ovthingcolor_friend);
|
||||
ThingColor_Monster.FromCVar (am_ovthingcolor_monster);
|
||||
ThingColor.FromCVar (am_ovthingcolor);
|
||||
|
@ -836,6 +937,7 @@ static void AM_initColors (bool overlayed)
|
|||
FDWallColor.FromCVar (am_fdwallcolor);
|
||||
CDWallColor.FromCVar (am_cdwallcolor);
|
||||
ThingColor_Item.FromCVar (am_thingcolor_item);
|
||||
ThingColor_CountItem.FromCVar (am_thingcolor_citem);
|
||||
ThingColor_Friend.FromCVar (am_thingcolor_friend);
|
||||
ThingColor_Monster.FromCVar (am_thingcolor_monster);
|
||||
ThingColor.FromCVar (am_thingcolor);
|
||||
|
@ -1122,127 +1224,28 @@ void AM_ToggleMap ()
|
|||
//
|
||||
//=============================================================================
|
||||
|
||||
bool AM_Responder (event_t *ev)
|
||||
bool AM_Responder (event_t *ev, bool last)
|
||||
{
|
||||
bool rc;
|
||||
static int cheatstate = 0;
|
||||
static int bigstate = 0;
|
||||
|
||||
rc = false;
|
||||
|
||||
if (automapactive && ev->type == EV_KeyDown)
|
||||
if (automapactive && (ev->type == EV_KeyDown || ev->type == EV_KeyUp))
|
||||
{
|
||||
rc = true;
|
||||
switch (ev->data1)
|
||||
if (followplayer)
|
||||
{
|
||||
case AM_PANRIGHTKEY: // pan right
|
||||
if (!followplayer)
|
||||
m_paninc.x = FTOM(F_PANINC);
|
||||
else
|
||||
rc = false;
|
||||
break;
|
||||
case AM_PANLEFTKEY: // pan left
|
||||
if (!followplayer)
|
||||
m_paninc.x = -FTOM(F_PANINC);
|
||||
else
|
||||
rc = false;
|
||||
break;
|
||||
case AM_PANUPKEY: // pan up
|
||||
if (!followplayer)
|
||||
m_paninc.y = FTOM(F_PANINC);
|
||||
else
|
||||
rc = false;
|
||||
break;
|
||||
case AM_PANDOWNKEY: // pan down
|
||||
if (!followplayer)
|
||||
m_paninc.y = -FTOM(F_PANINC);
|
||||
else
|
||||
rc = false;
|
||||
break;
|
||||
case AM_ZOOMOUTKEY: // zoom out
|
||||
case AM_ZOOMOUTKEY2:
|
||||
mtof_zoommul = M_ZOOMOUT;
|
||||
ftom_zoommul = M_ZOOMIN;
|
||||
break;
|
||||
case AM_ZOOMINKEY: // zoom in
|
||||
case AM_ZOOMINKEY2:
|
||||
mtof_zoommul = M_ZOOMIN;
|
||||
ftom_zoommul = M_ZOOMOUT;
|
||||
break;
|
||||
case AM_GOBIGKEY:
|
||||
bigstate = !bigstate;
|
||||
if (bigstate)
|
||||
{
|
||||
AM_saveScaleAndLoc();
|
||||
AM_minOutWindowScale();
|
||||
}
|
||||
else
|
||||
AM_restoreScaleAndLoc();
|
||||
break;
|
||||
default:
|
||||
switch (ev->data2)
|
||||
{
|
||||
case AM_FOLLOWKEY:
|
||||
AM_ToggleFollowPlayer();
|
||||
break;
|
||||
case AM_GRIDKEY:
|
||||
grid = !grid;
|
||||
Printf ("%s\n", GStrings(grid ? "AMSTR_GRIDON" : "AMSTR_GRIDOFF"));
|
||||
break;
|
||||
case AM_MARKKEY:
|
||||
if (AM_addMark())
|
||||
{
|
||||
Printf ("%s %d\n", GStrings("AMSTR_MARKEDSPOT"), markpointnum);
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = false;
|
||||
}
|
||||
break;
|
||||
case AM_CLEARMARKKEY:
|
||||
if (AM_clearMarks())
|
||||
{
|
||||
Printf ("%s\n", GStrings("AMSTR_MARKSCLEARED"));
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cheatstate = 0;
|
||||
rc = false;
|
||||
}
|
||||
// check for am_pan* and ignore in follow mode
|
||||
const char *defbind = AutomapBindings.GetBind(ev->data1);
|
||||
if (!strnicmp(defbind, "+am_pan", 7)) return false;
|
||||
}
|
||||
}
|
||||
else if (ev->type == EV_KeyUp)
|
||||
{
|
||||
rc = false;
|
||||
switch (ev->data1)
|
||||
{
|
||||
case AM_PANRIGHTKEY:
|
||||
if (!followplayer) m_paninc.x = 0;
|
||||
break;
|
||||
case AM_PANLEFTKEY:
|
||||
if (!followplayer) m_paninc.x = 0;
|
||||
break;
|
||||
case AM_PANUPKEY:
|
||||
if (!followplayer) m_paninc.y = 0;
|
||||
break;
|
||||
case AM_PANDOWNKEY:
|
||||
if (!followplayer) m_paninc.y = 0;
|
||||
break;
|
||||
case AM_ZOOMOUTKEY:
|
||||
case AM_ZOOMOUTKEY2:
|
||||
case AM_ZOOMINKEY:
|
||||
case AM_ZOOMINKEY2:
|
||||
mtof_zoommul = MAPUNIT;
|
||||
ftom_zoommul = MAPUNIT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
bool res = C_DoKey(ev, &AutomapBindings, NULL);
|
||||
if (res && ev->type == EV_KeyUp && !last)
|
||||
{
|
||||
// If this is a release event we also need to check if it released a button in the main Bindings
|
||||
// so that that button does not get stuck.
|
||||
const char *defbind = Bindings.GetBind(ev->data1);
|
||||
return (defbind[0] != '+'); // Let G_Responder handle button releases
|
||||
}
|
||||
return res;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1254,6 +1257,26 @@ bool AM_Responder (event_t *ev)
|
|||
|
||||
void AM_changeWindowScale ()
|
||||
{
|
||||
int mtof_zoommul;
|
||||
|
||||
if (am_zoomdir > 0)
|
||||
{
|
||||
mtof_zoommul = int(M_ZOOMIN * am_zoomdir);
|
||||
}
|
||||
else if (am_zoomdir < 0)
|
||||
{
|
||||
mtof_zoommul = int(M_ZOOMOUT / -am_zoomdir);
|
||||
}
|
||||
else if (Button_AM_ZoomIn.bDown)
|
||||
{
|
||||
mtof_zoommul = int(M_ZOOMIN);
|
||||
}
|
||||
else if (Button_AM_ZoomOut.bDown)
|
||||
{
|
||||
mtof_zoommul = int(M_ZOOMOUT);
|
||||
}
|
||||
am_zoomdir = 0;
|
||||
|
||||
// Change the scaling multipliers
|
||||
scale_mtof = MapMul(scale_mtof, mtof_zoommul);
|
||||
scale_ftom = MapDiv(MAPUNIT, scale_mtof);
|
||||
|
@ -1264,6 +1287,13 @@ void AM_changeWindowScale ()
|
|||
AM_maxOutWindowScale();
|
||||
}
|
||||
|
||||
CCMD(am_zoom)
|
||||
{
|
||||
if (argv.argc() >= 2)
|
||||
{
|
||||
am_zoomdir = (float)atof(argv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
|
@ -1298,19 +1328,6 @@ void AM_doFollowPlayer ()
|
|||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
static void AM_ToggleFollowPlayer()
|
||||
{
|
||||
followplayer = !followplayer;
|
||||
f_oldloc.x = FIXED_MAX;
|
||||
Printf ("%s\n", GStrings(followplayer ? "AMSTR_FOLLOWON" : "AMSTR_FOLLOWOFF"));
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Updates on Game Tick
|
||||
|
@ -1325,10 +1342,20 @@ void AM_Ticker ()
|
|||
amclock++;
|
||||
|
||||
if (followplayer)
|
||||
{
|
||||
AM_doFollowPlayer();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_paninc.x = m_paninc.y = 0;
|
||||
if (Button_AM_PanLeft.bDown) m_paninc.x -= FTOM(F_PANINC);
|
||||
if (Button_AM_PanRight.bDown) m_paninc.x += FTOM(F_PANINC);
|
||||
if (Button_AM_PanUp.bDown) m_paninc.y += FTOM(F_PANINC);
|
||||
if (Button_AM_PanDown.bDown) m_paninc.y -= FTOM(F_PANINC);
|
||||
}
|
||||
|
||||
// Change the zoom if necessary
|
||||
if (ftom_zoommul != MAPUNIT)
|
||||
if (Button_AM_ZoomIn.bDown || Button_AM_ZoomOut.bDown || am_zoomdir != 0)
|
||||
AM_changeWindowScale();
|
||||
|
||||
// Change x,y location
|
||||
|
@ -1586,6 +1613,97 @@ void AM_drawGrid (const AMColor &color)
|
|||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// AM_drawSubsectors
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void AM_drawSubsectors()
|
||||
{
|
||||
static TArray<FVector2> points;
|
||||
float scale = float(scale_mtof);
|
||||
angle_t rotation;
|
||||
sector_t tempsec;
|
||||
int floorlight, ceilinglight;
|
||||
double originx, originy;
|
||||
FDynamicColormap *colormap;
|
||||
|
||||
|
||||
for (int i = 0; i < numsubsectors; ++i)
|
||||
{
|
||||
if (subsectors[i].flags & SSECF_POLYORG)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((!(subsectors[i].flags & SSECF_DRAWN) || (subsectors[i].render_sector->MoreFlags & SECF_HIDDEN)) && am_cheat == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// Fill the points array from the subsector.
|
||||
points.Resize(subsectors[i].numlines);
|
||||
for (DWORD j = 0; j < subsectors[i].numlines; ++j)
|
||||
{
|
||||
mpoint_t pt = { subsectors[i].firstline[j].v1->x >> FRACTOMAPBITS,
|
||||
subsectors[i].firstline[j].v1->y >> FRACTOMAPBITS };
|
||||
if (am_rotate == 1 || (am_rotate == 2 && viewactive))
|
||||
{
|
||||
AM_rotatePoint(&pt.x, &pt.y);
|
||||
}
|
||||
points[j].X = f_x + ((pt.x - m_x) * scale / float(1 << 24));
|
||||
points[j].Y = f_y + (f_h - (pt.y - m_y) * scale / float(1 << 24));
|
||||
}
|
||||
// For lighting and texture determination
|
||||
sector_t *sec = R_FakeFlat (subsectors[i].render_sector, &tempsec, &floorlight,
|
||||
&ceilinglight, false);
|
||||
// Find texture origin.
|
||||
mpoint_t originpt = { -sec->GetXOffset(sector_t::floor) >> FRACTOMAPBITS,
|
||||
sec->GetYOffset(sector_t::floor) >> FRACTOMAPBITS };
|
||||
rotation = 0 - sec->GetAngle(sector_t::floor);
|
||||
// Apply the floor's rotation to the texture origin.
|
||||
if (rotation != 0)
|
||||
{
|
||||
AM_rotate(&originpt.x, &originpt.y, rotation);
|
||||
}
|
||||
// Apply the automap's rotation to the texture origin.
|
||||
if (am_rotate == 1 || (am_rotate == 2 && viewactive))
|
||||
{
|
||||
rotation += ANG90 - players[consoleplayer].camera->angle;
|
||||
AM_rotatePoint(&originpt.x, &originpt.y);
|
||||
}
|
||||
originx = f_x + ((originpt.x - m_x) * scale / float(1 << 24));
|
||||
originy = f_y + (f_h - (originpt.y - m_y) * scale / float(1 << 24));
|
||||
// Coloring for the polygon
|
||||
colormap = sec->ColorMap;
|
||||
// If this subsector has not actually been seen yet (because you are cheating
|
||||
// to see it on the map), tint and desaturate it.
|
||||
if (!(subsectors[i].flags & SSECF_DRAWN))
|
||||
{
|
||||
colormap = GetSpecialLights(
|
||||
MAKERGB(
|
||||
(colormap->Color.r + 255) / 2,
|
||||
(colormap->Color.g + 200) / 2,
|
||||
(colormap->Color.b + 160) / 2),
|
||||
colormap->Fade,
|
||||
255 - (255 - colormap->Desaturate) / 4);
|
||||
floorlight = (floorlight + 200*15) / 16;
|
||||
}
|
||||
|
||||
// Draw the polygon.
|
||||
screen->FillSimplePoly(
|
||||
TexMan(sec->GetTexture(sector_t::floor)),
|
||||
&points[0], points.Size(),
|
||||
originx, originy,
|
||||
scale / (FIXED2FLOAT(sec->GetXScale(sector_t::floor)) * float(1 << MAPBITS)),
|
||||
scale / (FIXED2FLOAT(sec->GetYScale(sector_t::floor)) * float(1 << MAPBITS)),
|
||||
rotation,
|
||||
colormap,
|
||||
floorlight
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
|
@ -1614,6 +1732,80 @@ static bool AM_CheckSecret(line_t *line)
|
|||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Polyobject debug stuff
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void AM_drawSeg(seg_t *seg, const AMColor &color)
|
||||
{
|
||||
mline_t l;
|
||||
l.a.x = seg->v1->x >> FRACTOMAPBITS;
|
||||
l.a.y = seg->v1->y >> FRACTOMAPBITS;
|
||||
l.b.x = seg->v2->x >> FRACTOMAPBITS;
|
||||
l.b.y = seg->v2->y >> FRACTOMAPBITS;
|
||||
|
||||
if (am_rotate == 1 || (am_rotate == 2 && viewactive))
|
||||
{
|
||||
AM_rotatePoint (&l.a.x, &l.a.y);
|
||||
AM_rotatePoint (&l.b.x, &l.b.y);
|
||||
}
|
||||
AM_drawMline(&l, color);
|
||||
}
|
||||
|
||||
void AM_drawPolySeg(FPolySeg *seg, const AMColor &color)
|
||||
{
|
||||
mline_t l;
|
||||
l.a.x = seg->v1.x >> FRACTOMAPBITS;
|
||||
l.a.y = seg->v1.y >> FRACTOMAPBITS;
|
||||
l.b.x = seg->v2.x >> FRACTOMAPBITS;
|
||||
l.b.y = seg->v2.y >> FRACTOMAPBITS;
|
||||
|
||||
if (am_rotate == 1 || (am_rotate == 2 && viewactive))
|
||||
{
|
||||
AM_rotatePoint (&l.a.x, &l.a.y);
|
||||
AM_rotatePoint (&l.b.x, &l.b.y);
|
||||
}
|
||||
AM_drawMline(&l, color);
|
||||
}
|
||||
|
||||
void AM_showSS()
|
||||
{
|
||||
if (am_showsubsector >= 0 && am_showsubsector < numsubsectors)
|
||||
{
|
||||
AMColor yellow;
|
||||
yellow.FromRGB(255,255,0);
|
||||
AMColor red;
|
||||
red.FromRGB(255,0,0);
|
||||
|
||||
subsector_t *sub = &subsectors[am_showsubsector];
|
||||
for (unsigned int i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
AM_drawSeg(sub->firstline + i, yellow);
|
||||
}
|
||||
PO_LinkToSubsectors();
|
||||
|
||||
for (int i = 0; i <po_NumPolyobjs; i++)
|
||||
{
|
||||
FPolyObj *po = &polyobjs[i];
|
||||
FPolyNode *pnode = po->subsectorlinks;
|
||||
|
||||
while (pnode != NULL)
|
||||
{
|
||||
if (pnode->subsector == sub)
|
||||
{
|
||||
for (unsigned j = 0; j < pnode->segs.Size(); j++)
|
||||
{
|
||||
AM_drawPolySeg(&pnode->segs[j], red);
|
||||
}
|
||||
}
|
||||
pnode = pnode->snext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Determines visible lines, draws them.
|
||||
|
@ -1746,14 +1938,27 @@ void AM_drawWalls (bool allmap)
|
|||
//
|
||||
//=============================================================================
|
||||
|
||||
void AM_rotate (fixed_t *x, fixed_t *y, angle_t a)
|
||||
void AM_rotate(fixed_t *xp, fixed_t *yp, angle_t a)
|
||||
{
|
||||
fixed_t tmpx;
|
||||
static angle_t angle_saved = 0;
|
||||
static double sinrot = 0;
|
||||
static double cosrot = 1;
|
||||
|
||||
a >>= ANGLETOFINESHIFT;
|
||||
tmpx = DMulScale16 (*x,finecosine[a],*y,-finesine[a]);
|
||||
*y = DMulScale16 (*x,finesine[a],*y,finecosine[a]);
|
||||
*x = tmpx;
|
||||
if (angle_saved != a)
|
||||
{
|
||||
angle_saved = a;
|
||||
double rot = (double)a / (double)(1u << 31) * (double)M_PI;
|
||||
sinrot = sin(rot);
|
||||
cosrot = cos(rot);
|
||||
}
|
||||
|
||||
double x = FIXED2FLOAT(*xp);
|
||||
double y = FIXED2FLOAT(*yp);
|
||||
double tmpx = (x * cosrot) - (y * sinrot);
|
||||
y = (x * sinrot) + (y * cosrot);
|
||||
x = tmpx;
|
||||
*xp = FLOAT2FIXED(x);
|
||||
*yp = FLOAT2FIXED(y);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
@ -1964,11 +2169,40 @@ void AM_drawThings ()
|
|||
if (t->flags & MF_FRIENDLY || !(t->flags & MF_COUNTKILL)) color = ThingColor_Friend;
|
||||
else color = ThingColor_Monster;
|
||||
}
|
||||
else if (t->flags&MF_SPECIAL) color = ThingColor_Item;
|
||||
else if (t->flags&MF_SPECIAL)
|
||||
{
|
||||
// Find the key's own color.
|
||||
// Only works correctly if single-key locks have lower numbers than any-key locks.
|
||||
// That is the case for all default keys, however.
|
||||
if (t->IsKindOf(RUNTIME_CLASS(AKey)))
|
||||
{
|
||||
if (am_showkeys)
|
||||
{
|
||||
int P_GetMapColorForKey (AInventory * key);
|
||||
int c = P_GetMapColorForKey(static_cast<AKey *>(t));
|
||||
|
||||
AM_drawLineCharacter
|
||||
(thintriangle_guy, NUMTHINTRIANGLEGUYLINES,
|
||||
16<<MAPBITS, angle, color, p.x, p.y);
|
||||
if (c >= 0) color.FromRGB(RPART(c), GPART(c), BPART(c));
|
||||
else color = ThingColor_CountItem;
|
||||
AM_drawLineCharacter(key_guy, NUMKEYGUYLINES, 16<<MAPBITS, 0, color, p.x, p.y);
|
||||
color.Index = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
color = ThingColor_Item;
|
||||
}
|
||||
}
|
||||
else if (t->flags&MF_COUNTITEM)
|
||||
color = ThingColor_CountItem;
|
||||
else
|
||||
color = ThingColor_Item;
|
||||
}
|
||||
|
||||
if (color.Index != -1)
|
||||
{
|
||||
AM_drawLineCharacter
|
||||
(thintriangle_guy, NUMTHINTRIANGLEGUYLINES,
|
||||
16<<MAPBITS, angle, color, p.x, p.y);
|
||||
}
|
||||
|
||||
if (am_cheat >= 3)
|
||||
{
|
||||
|
@ -2093,7 +2327,11 @@ void AM_drawAuthorMarkers ()
|
|||
|
||||
while (marked != NULL)
|
||||
{
|
||||
if (mark->args[1] == 0 || (mark->args[1] == 1 && marked->Sector->MoreFlags & SECF_DRAWN))
|
||||
// Use more correct info if we have GL nodes available
|
||||
if (mark->args[1] == 0 ||
|
||||
(mark->args[1] == 1 && (hasglnodes ?
|
||||
marked->subsector->flags & SSECF_DRAWN :
|
||||
marked->Sector->MoreFlags & SECF_DRAWN)))
|
||||
{
|
||||
DrawMarker (tex, marked->x >> FRACTOMAPBITS, marked->y >> FRACTOMAPBITS, 0,
|
||||
flip, mark->scaleX, mark->scaleY, mark->Translation,
|
||||
|
@ -2152,6 +2390,9 @@ void AM_Drawer ()
|
|||
}
|
||||
AM_activateNewScale();
|
||||
|
||||
if (am_textured && hasglnodes && textured && !viewactive)
|
||||
AM_drawSubsectors();
|
||||
|
||||
if (grid)
|
||||
AM_drawGrid(GridColor);
|
||||
|
||||
|
@ -2166,6 +2407,8 @@ void AM_Drawer ()
|
|||
AM_drawCrosshair(XHairColor);
|
||||
|
||||
AM_drawMarks();
|
||||
|
||||
AM_showSS();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
|
|
@ -26,7 +26,7 @@ struct event_t;
|
|||
class FArchive;
|
||||
|
||||
// Called by main loop.
|
||||
bool AM_Responder (event_t* ev);
|
||||
bool AM_Responder (event_t* ev, bool last);
|
||||
|
||||
// Called by main loop.
|
||||
void AM_Ticker (void);
|
||||
|
|
|
@ -93,7 +93,16 @@ setupvlineasm:
|
|||
selfmod premach3a, machvsh8+6
|
||||
ret
|
||||
|
||||
%ifdef M_TARGET_MACHO
|
||||
SECTION .text align=64
|
||||
%else
|
||||
SECTION .rtext progbits alloc exec write align=64
|
||||
%endif
|
||||
|
||||
%ifdef M_TARGET_MACHO
|
||||
GLOBAL _rtext_a_start
|
||||
_rtext_a_start:
|
||||
%endif
|
||||
|
||||
;eax = xscale
|
||||
;ebx = palookupoffse
|
||||
|
@ -325,6 +334,7 @@ setupmvlineasm:
|
|||
mov ecx, dword [esp+4]
|
||||
mov byte [maskmach3a+2], cl
|
||||
mov byte [machmv13+2], cl
|
||||
|
||||
mov byte [machmv14+2], cl
|
||||
mov byte [machmv15+2], cl
|
||||
mov byte [machmv16+2], cl
|
||||
|
@ -538,3 +548,8 @@ ALIGN 16
|
|||
mvcase0: jmp beginmvlineasm4
|
||||
|
||||
align 16
|
||||
|
||||
%ifdef M_TARGET_MACHO
|
||||
GLOBAL _rtext_a_end
|
||||
_rtext_a_end:
|
||||
%endif
|
||||
|
|
|
@ -285,7 +285,16 @@ R_SetSpanSize_ASM:
|
|||
|
||||
aret: ret
|
||||
|
||||
%ifdef M_TARGET_MACHO
|
||||
SECTION .text align=64
|
||||
%else
|
||||
SECTION .rtext progbits alloc exec write align=64
|
||||
%endif
|
||||
|
||||
%ifdef M_TARGET_MACHO
|
||||
GLOBAL _rtext_tmap_start
|
||||
_rtext_tmap_start:
|
||||
%endif
|
||||
|
||||
rtext_start:
|
||||
|
||||
|
@ -300,6 +309,8 @@ GLOBAL R_DrawSpanP_ASM
|
|||
; edi: dest
|
||||
; ebp: scratch
|
||||
; esi: count
|
||||
; [esp]: xstep
|
||||
; [esp+4]: ystep
|
||||
|
||||
align 16
|
||||
|
||||
|
@ -315,6 +326,7 @@ R_DrawSpanP_ASM:
|
|||
push edi
|
||||
push ebp
|
||||
push esi
|
||||
sub esp, 8
|
||||
|
||||
mov edi,ecx
|
||||
add edi,[dc_destorg]
|
||||
|
@ -326,13 +338,13 @@ dsy1: shl edx,6
|
|||
dsy3: shr ebp,26
|
||||
xor ebx,ebx
|
||||
lea esi,[eax+1]
|
||||
mov [ds_xstep],edx
|
||||
mov [esp],edx
|
||||
mov edx,[ds_ystep]
|
||||
mov ecx,[ds_xfrac]
|
||||
dsy4: shr ecx,26
|
||||
dsm8: and edx,0xffffffc0
|
||||
or ebp,edx
|
||||
mov [ds_ystep],ebp
|
||||
mov [esp+4],ebp
|
||||
mov ebp,[ds_yfrac]
|
||||
mov edx,[ds_xfrac]
|
||||
dsy2: shl edx,6
|
||||
|
@ -346,8 +358,8 @@ dsm9: and ebp,0xffffffc0
|
|||
mov ebp,ecx
|
||||
dsx1: rol ebp,6
|
||||
dsm1: and ebp,0xfff
|
||||
add edx,[ds_xstep]
|
||||
adc ecx,[ds_ystep]
|
||||
add edx,[esp]
|
||||
adc ecx,[esp+4]
|
||||
spreada mov bl,[ebp+SPACEFILLER4]
|
||||
spmapa mov bl,[ebx+SPACEFILLER4]
|
||||
mov [edi],bl
|
||||
|
@ -358,13 +370,13 @@ dseven1 shr esi,1
|
|||
|
||||
; do two more pixels
|
||||
mov ebp,ecx
|
||||
add edx,[ds_xstep]
|
||||
adc ecx,[ds_ystep]
|
||||
add edx,[esp]
|
||||
adc ecx,[esp+4]
|
||||
dsm2: and ebp,0xfc00003f
|
||||
dsx2: rol ebp,6
|
||||
mov eax,ecx
|
||||
add edx,[ds_xstep]
|
||||
adc ecx,[ds_ystep]
|
||||
add edx,[esp]
|
||||
adc ecx,[esp+4]
|
||||
spreadb mov bl,[ebp+SPACEFILLER4] ;read texel1
|
||||
dsx3: rol eax,6
|
||||
dsm6: and eax,0xfff
|
||||
|
@ -383,13 +395,13 @@ dsrest test esi,esi
|
|||
align 16
|
||||
|
||||
dsloop mov ebp,ecx
|
||||
spstep1d add edx,[ds_xstep]
|
||||
spstep2d adc ecx,[ds_ystep]
|
||||
spstep1d add edx,[esp]
|
||||
spstep2d adc ecx,[esp+4]
|
||||
dsm3: and ebp,0xfc00003f
|
||||
dsx4: rol ebp,6
|
||||
mov eax,ecx
|
||||
spstep1e add edx,[ds_xstep]
|
||||
spstep2e adc ecx,[ds_ystep]
|
||||
spstep1e add edx,[esp]
|
||||
spstep2e adc ecx,[esp+4]
|
||||
spreadd mov bl,[ebp+SPACEFILLER4] ;read texel1
|
||||
dsx5: rol eax,6
|
||||
dsm5: and eax,0xfff
|
||||
|
@ -397,8 +409,8 @@ spmapd mov bl,[ebx+SPACEFILLER4] ;map texel1
|
|||
mov [edi],bl ;store texel1
|
||||
mov ebp,ecx
|
||||
spreade mov bl,[eax+SPACEFILLER4] ;read texel2
|
||||
spstep1f add edx,[ds_xstep]
|
||||
spstep2f adc ecx,[ds_ystep]
|
||||
spstep1f add edx,[esp]
|
||||
spstep2f adc ecx,[esp+4]
|
||||
dsm4: and ebp,0xfc00003f
|
||||
dsx6: rol ebp,6
|
||||
spmape mov bl,[ebx+SPACEFILLER4] ;map texel2
|
||||
|
@ -411,14 +423,15 @@ dsx7: rol eax,6
|
|||
dsm7: and eax,0xfff
|
||||
mov [edi-2],bl ;store texel3
|
||||
spreadg mov bl,[eax+SPACEFILLER4] ;read texel4
|
||||
spstep1g add edx,[ds_xstep]
|
||||
spstep2g adc ecx,[ds_ystep]
|
||||
spstep1g add edx,[esp]
|
||||
spstep2g adc ecx,[esp+4]
|
||||
spmapg mov bl,[ebx+SPACEFILLER4] ;map texel4
|
||||
dec esi
|
||||
mov [edi-1],bl ;store texel4
|
||||
jnz near dsloop
|
||||
|
||||
dsdone pop esi
|
||||
dsdone add esp,8
|
||||
pop esi
|
||||
pop ebp
|
||||
pop edi
|
||||
pop ebx
|
||||
|
@ -439,6 +452,8 @@ GLOBAL R_DrawSpanMaskedP_ASM
|
|||
; edi: dest
|
||||
; ebp: scratch
|
||||
; esi: count
|
||||
; [esp]: xstep
|
||||
; [esp+4]: ystep
|
||||
|
||||
align 16
|
||||
|
||||
|
@ -454,6 +469,7 @@ R_DrawSpanMaskedP_ASM:
|
|||
push edi
|
||||
push ebp
|
||||
push esi
|
||||
sub esp,8
|
||||
|
||||
mov edi,ecx
|
||||
add edi,[dc_destorg]
|
||||
|
@ -465,13 +481,13 @@ dmsy1: shl edx,6
|
|||
dmsy3: shr ebp,26
|
||||
xor ebx,ebx
|
||||
lea esi,[eax+1]
|
||||
mov [ds_xstep],edx
|
||||
mov [esp],edx
|
||||
mov edx,[ds_ystep]
|
||||
mov ecx,[ds_xfrac]
|
||||
dmsy4: shr ecx,26
|
||||
dmsm8: and edx,0xffffffc0
|
||||
or ebp,edx
|
||||
mov [ds_ystep],ebp
|
||||
mov [esp+4],ebp
|
||||
mov ebp,[ds_yfrac]
|
||||
mov edx,[ds_xfrac]
|
||||
dmsy2: shl edx,6
|
||||
|
@ -485,8 +501,8 @@ dmsm9: and ebp,0xffffffc0
|
|||
mov ebp,ecx
|
||||
dmsx1: rol ebp,6
|
||||
dmsm1: and ebp,0xfff
|
||||
add edx,[ds_xstep]
|
||||
adc ecx,[ds_ystep]
|
||||
add edx,[esp]
|
||||
adc ecx,[esp+4]
|
||||
mspreada mov bl,[ebp+SPACEFILLER4]
|
||||
cmp bl,0
|
||||
je mspskipa
|
||||
|
@ -499,13 +515,13 @@ dmseven1 shr esi,1
|
|||
|
||||
; do two more pixels
|
||||
mov ebp,ecx
|
||||
add edx,[ds_xstep]
|
||||
adc ecx,[ds_ystep]
|
||||
add edx,[esp]
|
||||
adc ecx,[esp+4]
|
||||
dmsm2: and ebp,0xfc00003f
|
||||
dmsx2: rol ebp,6
|
||||
mov eax,ecx
|
||||
add edx,[ds_xstep]
|
||||
adc ecx,[ds_ystep]
|
||||
add edx,[esp]
|
||||
adc ecx,[esp+4]
|
||||
mspreadb mov bl,[ebp+SPACEFILLER4] ;read texel1
|
||||
dmsx3: rol eax,6
|
||||
dmsm6: and eax,0xfff
|
||||
|
@ -528,13 +544,13 @@ dmsrest test esi,esi
|
|||
align 16
|
||||
|
||||
dmsloop mov ebp,ecx
|
||||
mspstep1d add edx,[ds_xstep]
|
||||
mspstep2d adc ecx,[ds_ystep]
|
||||
mspstep1d add edx,[esp]
|
||||
mspstep2d adc ecx,[esp+4]
|
||||
dmsm3: and ebp,0xfc00003f
|
||||
dmsx4: rol ebp,6
|
||||
mov eax,ecx
|
||||
mspstep1e add edx,[ds_xstep]
|
||||
mspstep2e adc ecx,[ds_ystep]
|
||||
mspstep1e add edx,[esp]
|
||||
mspstep2e adc ecx,[esp+4]
|
||||
mspreadd mov bl,[ebp+SPACEFILLER4] ;read texel1
|
||||
dmsx5: rol eax,6
|
||||
dmsm5: and eax,0xfff
|
||||
|
@ -544,8 +560,8 @@ dmsm5: and eax,0xfff
|
|||
mspmapd mov bl,[ebx+SPACEFILLER4] ;map texel1
|
||||
mov [edi],bl ;store texel1
|
||||
mspreade mov bl,[eax+SPACEFILLER4] ;read texel2
|
||||
mspstep1f add edx,[ds_xstep]
|
||||
mspstep2f adc ecx,[ds_ystep]
|
||||
mspstep1f add edx,[esp]
|
||||
mspstep2f adc ecx,[esp+4]
|
||||
dmsm4: and ebp,0xfc00003f
|
||||
dmsx6: rol ebp,6
|
||||
cmp bl,0
|
||||
|
@ -562,8 +578,8 @@ dmsm7: and eax,0xfff
|
|||
mspmapf mov bl,[ebx+SPACEFILLER4] ;map texel3
|
||||
mov [edi-2],bl ;store texel3
|
||||
mspreadg mov bl,[eax+SPACEFILLER4] ;read texel4
|
||||
mspstep1g add edx,[ds_xstep]
|
||||
mspstep2g adc ecx,[ds_ystep]
|
||||
mspstep1g add edx,[esp]
|
||||
mspstep2g adc ecx,[esp+4]
|
||||
cmp bl,0
|
||||
je mspskipg
|
||||
mspmapg mov bl,[ebx+SPACEFILLER4] ;map texel4
|
||||
|
@ -571,7 +587,8 @@ mspmapg mov bl,[ebx+SPACEFILLER4] ;map texel4
|
|||
mspskipg dec esi
|
||||
jnz near dmsloop
|
||||
|
||||
dmsdone pop esi
|
||||
dmsdone add esp,8
|
||||
pop esi
|
||||
pop ebp
|
||||
pop edi
|
||||
pop ebx
|
||||
|
@ -1738,6 +1755,10 @@ ac4nil: pop edi
|
|||
ret
|
||||
|
||||
rtext_end:
|
||||
%ifdef M_TARGET_MACHO
|
||||
GLOBAL _rtext_tmap_end
|
||||
_rtext_tmap_end:
|
||||
%endif
|
||||
align 16
|
||||
|
||||
;************************
|
||||
|
|
|
@ -216,7 +216,13 @@ SetTiltedSpanSize:
|
|||
|
||||
ret
|
||||
|
||||
%ifndef M_TARGET_MACHO
|
||||
SECTION .rtext progbits alloc exec write align=64
|
||||
%else
|
||||
SECTION .text align=64
|
||||
GLOBAL _rtext_tmap2_start
|
||||
_rtext_tmap2_start:
|
||||
%endif
|
||||
|
||||
rtext_start:
|
||||
|
||||
|
@ -628,3 +634,7 @@ fetch10 mov al,[ebp+esi+SPACEFILLER4]
|
|||
ret
|
||||
|
||||
rtext_end:
|
||||
%ifdef M_TARGET_MACHO
|
||||
GLOBAL _rtext_tmap2_end
|
||||
_rtext_tmap2_end:
|
||||
%endif
|
||||
|
|
|
@ -80,7 +80,13 @@ setupvlinetallasm:
|
|||
selfmod shifter1, shift12+6
|
||||
ret
|
||||
|
||||
%ifdef M_TARGET_MACHO
|
||||
SECTION .text align=64
|
||||
GLOBAL _rtext_tmap3_start
|
||||
_rtext_tmap3_start:
|
||||
%else
|
||||
SECTION .rtext progbits alloc exec write align=64
|
||||
%endif
|
||||
|
||||
ALIGN 16
|
||||
|
||||
|
@ -331,3 +337,8 @@ shift12: shr ecx,16
|
|||
pop ebx
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
%ifdef M_TARGET_MACHO
|
||||
GLOBAL _rtext_tmap3_end
|
||||
_rtext_tmap3_end:
|
||||
%endif
|
||||
|
|
|
@ -1,28 +1,28 @@
|
|||
#%include "valgrind.inc"
|
||||
#%include "valgrind.inc"
|
||||
|
||||
.section .text
|
||||
.section .text
|
||||
|
||||
.globl ASM_PatchPitch
|
||||
ASM_PatchPitch:
|
||||
.globl ASM_PatchPitch
|
||||
ASM_PatchPitch:
|
||||
movl dc_pitch(%rip), %ecx
|
||||
movl %ecx, pm+3(%rip)
|
||||
movl %ecx, vltpitch+3(%rip)
|
||||
# selfmod pm, vltpitch+6
|
||||
ret
|
||||
.align 16
|
||||
movl %ecx, vltpitch+3(%rip)
|
||||
# selfmod pm, vltpitch+6
|
||||
ret
|
||||
.align 16
|
||||
|
||||
.globl setupvlinetallasm
|
||||
.globl setupvlinetallasm
|
||||
setupvlinetallasm:
|
||||
movb %dil, shifter1+2(%rip)
|
||||
movb %dil, shifter2+2(%rip)
|
||||
movb %dil, shifter3+2(%rip)
|
||||
movb %dil, shifter4+2(%rip)
|
||||
# selfmod shifter1, shifter4+3
|
||||
movb %dil, shifter4+2(%rip)
|
||||
# selfmod shifter1, shifter4+3
|
||||
ret
|
||||
.align 16
|
||||
|
||||
.section .rtext,"awx"
|
||||
|
||||
.align 16
|
||||
|
||||
.section .rtext,"awx"
|
||||
|
||||
.globl vlinetallasm4
|
||||
.type vlinetallasm4,@function
|
||||
vlinetallasm4:
|
||||
|
@ -38,18 +38,18 @@ vlinetallasm4:
|
|||
subq $8, %rsp # Does the stack need to be 16-byte aligned for Linux?
|
||||
.cfi_adjust_cfa_offset 8
|
||||
|
||||
# rax = bufplce base address
|
||||
# rbx =
|
||||
# rcx = offset from rdi/count (negative)
|
||||
# edx/rdx = scratch
|
||||
# rdi = bottom of columns to write to
|
||||
# r8d-r11d = column offsets
|
||||
# r12-r15 = palookupoffse[0] - palookupoffse[4]
|
||||
# rax = bufplce base address
|
||||
# rbx =
|
||||
# rcx = offset from rdi/count (negative)
|
||||
# edx/rdx = scratch
|
||||
# rdi = bottom of columns to write to
|
||||
# r8d-r11d = column offsets
|
||||
# r12-r15 = palookupoffse[0] - palookupoffse[4]
|
||||
|
||||
movl dc_count(%rip), %ecx
|
||||
movq dc_dest(%rip), %rdi
|
||||
testl %ecx, %ecx
|
||||
jle vltepilog # count must be positive
|
||||
jle vltepilog # count must be positive
|
||||
|
||||
movq bufplce(%rip), %rax
|
||||
movq bufplce+8(%rip), %r8
|
||||
|
@ -60,14 +60,14 @@ vlinetallasm4:
|
|||
subq %rax, %r10
|
||||
movl %r8d, source2+4(%rip)
|
||||
movl %r9d, source3+4(%rip)
|
||||
movl %r10d, source4+4(%rip)
|
||||
movl %r10d, source4+4(%rip)
|
||||
|
||||
pm: imulq $320, %rcx
|
||||
pm: imulq $320, %rcx
|
||||
|
||||
movq palookupoffse(%rip), %r12
|
||||
movq palookupoffse+8(%rip), %r13
|
||||
movq palookupoffse+16(%rip), %r14
|
||||
movq palookupoffse+24(%rip), %r15
|
||||
movq palookupoffse+24(%rip), %r15
|
||||
|
||||
movl vince(%rip), %r8d
|
||||
movl vince+4(%rip), %r9d
|
||||
|
@ -76,53 +76,53 @@ pm: imulq $320, %rcx
|
|||
movl %r8d, step1+3(%rip)
|
||||
movl %r9d, step2+3(%rip)
|
||||
movl %r10d, step3+3(%rip)
|
||||
movl %r11d, step4+3(%rip)
|
||||
movl %r11d, step4+3(%rip)
|
||||
|
||||
addq %rcx, %rdi
|
||||
negq %rcx
|
||||
negq %rcx
|
||||
|
||||
movl vplce(%rip), %r8d
|
||||
movl vplce+4(%rip), %r9d
|
||||
movl vplce+8(%rip), %r10d
|
||||
movl vplce+12(%rip), %r11d
|
||||
# selfmod loopit, vltepilog
|
||||
jmp loopit
|
||||
jmp loopit
|
||||
|
||||
.align 16
|
||||
.align 16
|
||||
loopit:
|
||||
movl %r8d, %edx
|
||||
shifter1: shrl $24, %edx
|
||||
step1: addl $0x88888888, %r8d
|
||||
step1: addl $0x44444444, %r8d
|
||||
movzbl (%rax,%rdx), %edx
|
||||
movl %r9d, %ebx
|
||||
movb (%r12,%rdx), %dl
|
||||
shifter2: shrl $24, %ebx
|
||||
step2: addl $0x88888888, %r9d
|
||||
source2: movzbl 0x88888888(%rax,%rbx), %ebx
|
||||
step2: addl $0x44444444, %r9d
|
||||
source2: movzbl 0x44444444(%rax,%rbx), %ebx
|
||||
movl %r10d, %ebp
|
||||
movb (%r13,%rbx), %bl
|
||||
shifter3: shr $24, %ebp
|
||||
step3: addl $0x88888888, %r10d
|
||||
source3: movzbl 0x88888888(%rax,%rbp), %ebp
|
||||
step3: addl $0x44444444, %r10d
|
||||
source3: movzbl 0x44444444(%rax,%rbp), %ebp
|
||||
movl %r11d, %esi
|
||||
movb (%r14,%rbp), %bpl
|
||||
shifter4: shr $24, %esi
|
||||
step4: add $0x88888888, %r11d
|
||||
source4: movzbl 0x88888888(%rax,%rsi), %esi
|
||||
step4: add $0x44444444, %r11d
|
||||
source4: movzbl 0x44444444(%rax,%rsi), %esi
|
||||
movb %dl, (%rdi,%rcx)
|
||||
movb %bl, 1(%rdi,%rcx)
|
||||
movb (%r15,%rsi), %sil
|
||||
movb %bpl, 2(%rdi,%rcx)
|
||||
movb %sil, 3(%rdi,%rcx)
|
||||
|
||||
vltpitch: addq $320, %rcx
|
||||
jl loopit
|
||||
vltpitch: addq $320, %rcx
|
||||
jl loopit
|
||||
|
||||
movl %r8d, vplce(%rip)
|
||||
movl %r9d, vplce+4(%rip)
|
||||
movl %r10d, vplce+8(%rip)
|
||||
movl %r11d, vplce+12(%rip)
|
||||
|
||||
movl %r11d, vplce+12(%rip)
|
||||
|
||||
vltepilog:
|
||||
addq $8, %rsp
|
||||
.cfi_adjust_cfa_offset -8
|
||||
|
@ -137,5 +137,5 @@ vltepilog:
|
|||
ret
|
||||
.cfi_endproc
|
||||
.align 16
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#define __forceinline inline
|
||||
#if defined(__GNUC__) && !defined(__forceinline)
|
||||
#define __forceinline __inline__ __attribute__((always_inline))
|
||||
#endif
|
||||
|
||||
static __forceinline SDWORD Scale (SDWORD a, SDWORD b, SDWORD c)
|
||||
|
|
934
src/c_bind.cpp
934
src/c_bind.cpp
|
@ -47,12 +47,6 @@
|
|||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct FBinding
|
||||
{
|
||||
const char *Key;
|
||||
const char *Bind;
|
||||
};
|
||||
|
||||
/* Default keybindings for Doom (and all other games)
|
||||
*/
|
||||
static const FBinding DefBindings[] =
|
||||
|
@ -178,6 +172,29 @@ static const FBinding DefStrifeBindings[] =
|
|||
// h - use health
|
||||
};
|
||||
|
||||
static const FBinding DefAutomapBindings[] =
|
||||
{
|
||||
{ "f", "am_togglefollow" },
|
||||
{ "g", "am_togglegrid" },
|
||||
{ "p", "am_toggletexture" },
|
||||
{ "m", "am_setmark" },
|
||||
{ "c", "am_clearmarks" },
|
||||
{ "0", "am_gobig" },
|
||||
{ "rightarrow", "+am_panright" },
|
||||
{ "leftarrow", "+am_panleft" },
|
||||
{ "uparrow", "+am_panup" },
|
||||
{ "downarrow", "+am_pandown" },
|
||||
{ "-", "+am_zoomout" },
|
||||
{ "=", "+am_zoomin" },
|
||||
{ "kp-", "+am_zoomout" },
|
||||
{ "kp+", "+am_zoomin" },
|
||||
{ "mwheelup", "am_zoom 1.2" },
|
||||
{ "mwheeldown", "am_zoom -1.2" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
||||
|
||||
const char *KeyNames[NUM_KEYS] =
|
||||
{
|
||||
// This array is dependant on the particular keyboard input
|
||||
|
@ -278,11 +295,19 @@ const char *KeyNames[NUM_KEYS] =
|
|||
"pad_a", "pad_b", "pad_x", "pad_y"
|
||||
};
|
||||
|
||||
static FString Bindings[NUM_KEYS];
|
||||
static FString DoubleBindings[NUM_KEYS];
|
||||
FKeyBindings Bindings;
|
||||
FKeyBindings DoubleBindings;
|
||||
FKeyBindings AutomapBindings;
|
||||
|
||||
static unsigned int DClickTime[NUM_KEYS];
|
||||
static BYTE DClicked[(NUM_KEYS+7)/8];
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
static int GetKeyFromName (const char *name)
|
||||
{
|
||||
int i;
|
||||
|
@ -302,380 +327,15 @@ static int GetKeyFromName (const char *name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const char *KeyName (int key)
|
||||
{
|
||||
static char name[5];
|
||||
|
||||
if (KeyNames[key])
|
||||
return KeyNames[key];
|
||||
|
||||
mysnprintf (name, countof(name), "#%d", key);
|
||||
return name;
|
||||
}
|
||||
|
||||
void C_UnbindAll ()
|
||||
{
|
||||
for (int i = 0; i < NUM_KEYS; ++i)
|
||||
{
|
||||
Bindings[i] = "";
|
||||
DoubleBindings[i] = "";
|
||||
}
|
||||
}
|
||||
|
||||
CCMD (unbindall)
|
||||
{
|
||||
C_UnbindAll ();
|
||||
}
|
||||
|
||||
CCMD (unbind)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (argv.argc() > 1)
|
||||
{
|
||||
if ( (i = GetKeyFromName (argv[1])) )
|
||||
{
|
||||
Bindings[i] = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf ("Unknown key \"%s\"\n", argv[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
CCMD (bind)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (argv.argc() > 1)
|
||||
{
|
||||
i = GetKeyFromName (argv[1]);
|
||||
if (!i)
|
||||
{
|
||||
Printf ("Unknown key \"%s\"\n", argv[1]);
|
||||
return;
|
||||
}
|
||||
if (argv.argc() == 2)
|
||||
{
|
||||
Printf ("\"%s\" = \"%s\"\n", argv[1], Bindings[i].GetChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
Bindings[i] = argv[2];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf ("Current key bindings:\n");
|
||||
|
||||
for (i = 0; i < NUM_KEYS; i++)
|
||||
{
|
||||
if (!Bindings[i].IsEmpty())
|
||||
Printf ("%s \"%s\"\n", KeyName (i), Bindings[i].GetChars());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//=============================================================================
|
||||
//
|
||||
// CCMD defaultbind
|
||||
//
|
||||
// Binds a command to a key if that key is not already bound and if
|
||||
// that command is not already bound to another key.
|
||||
//
|
||||
//==========================================================================
|
||||
//=============================================================================
|
||||
|
||||
CCMD (defaultbind)
|
||||
static int GetConfigKeyFromName (const char *key)
|
||||
{
|
||||
if (argv.argc() < 3)
|
||||
{
|
||||
Printf ("Usage: defaultbind <key> <command>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
int key = GetKeyFromName (argv[1]);
|
||||
if (key == 0)
|
||||
{
|
||||
Printf ("Unknown key \"%s\"\n", argv[1]);
|
||||
return;
|
||||
}
|
||||
if (!Bindings[key].IsEmpty())
|
||||
{ // This key is already bound.
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < NUM_KEYS; ++i)
|
||||
{
|
||||
if (!Bindings[i].IsEmpty() && stricmp (Bindings[i], argv[2]) == 0)
|
||||
{ // This command is already bound to a key.
|
||||
return;
|
||||
}
|
||||
}
|
||||
// It is safe to do the bind, so do it.
|
||||
Bindings[key] = argv[2];
|
||||
}
|
||||
}
|
||||
|
||||
CCMD (undoublebind)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (argv.argc() > 1)
|
||||
{
|
||||
if ( (i = GetKeyFromName (argv[1])) )
|
||||
{
|
||||
DoubleBindings[i] = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf ("Unknown key \"%s\"\n", argv[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
CCMD (doublebind)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (argv.argc() > 1)
|
||||
{
|
||||
i = GetKeyFromName (argv[1]);
|
||||
if (!i)
|
||||
{
|
||||
Printf ("Unknown key \"%s\"\n", argv[1]);
|
||||
return;
|
||||
}
|
||||
if (argv.argc() == 2)
|
||||
{
|
||||
Printf ("\"%s\" = \"%s\"\n", argv[1], DoubleBindings[i].GetChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
DoubleBindings[i] = argv[2];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf ("Current key doublebindings:\n");
|
||||
|
||||
for (i = 0; i < NUM_KEYS; i++)
|
||||
{
|
||||
if (!DoubleBindings[i].IsEmpty())
|
||||
Printf ("%s \"%s\"\n", KeyName (i), DoubleBindings[i].GetChars());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CCMD (rebind)
|
||||
{
|
||||
FString *bindings;
|
||||
|
||||
if (key == 0)
|
||||
{
|
||||
Printf ("Rebind cannot be used from the console\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (key & KEY_DBLCLICKED)
|
||||
{
|
||||
bindings = DoubleBindings;
|
||||
key &= KEY_DBLCLICKED-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
bindings = Bindings;
|
||||
}
|
||||
|
||||
if (argv.argc() > 1)
|
||||
{
|
||||
bindings[key] = argv[1];
|
||||
}
|
||||
}
|
||||
|
||||
static void SetBinds (const FBinding *array)
|
||||
{
|
||||
while (array->Key)
|
||||
{
|
||||
C_DoBind (array->Key, array->Bind, false);
|
||||
array++;
|
||||
}
|
||||
}
|
||||
|
||||
void C_BindDefaults ()
|
||||
{
|
||||
SetBinds (DefBindings);
|
||||
|
||||
if (gameinfo.gametype & (GAME_Raven|GAME_Strife))
|
||||
{
|
||||
SetBinds (DefRavenBindings);
|
||||
}
|
||||
|
||||
if (gameinfo.gametype == GAME_Heretic)
|
||||
{
|
||||
SetBinds (DefHereticBindings);
|
||||
}
|
||||
|
||||
if (gameinfo.gametype == GAME_Hexen)
|
||||
{
|
||||
SetBinds (DefHexenBindings);
|
||||
}
|
||||
|
||||
if (gameinfo.gametype == GAME_Strife)
|
||||
{
|
||||
SetBinds (DefStrifeBindings);
|
||||
}
|
||||
}
|
||||
|
||||
CCMD(binddefaults)
|
||||
{
|
||||
C_BindDefaults ();
|
||||
}
|
||||
|
||||
void C_SetDefaultBindings ()
|
||||
{
|
||||
C_UnbindAll ();
|
||||
C_BindDefaults ();
|
||||
}
|
||||
|
||||
bool C_DoKey (event_t *ev)
|
||||
{
|
||||
FString binding;
|
||||
bool dclick;
|
||||
int dclickspot;
|
||||
BYTE dclickmask;
|
||||
|
||||
if (ev->type != EV_KeyDown && ev->type != EV_KeyUp)
|
||||
return false;
|
||||
|
||||
if ((unsigned int)ev->data1 >= NUM_KEYS)
|
||||
return false;
|
||||
|
||||
dclickspot = ev->data1 >> 3;
|
||||
dclickmask = 1 << (ev->data1 & 7);
|
||||
dclick = false;
|
||||
|
||||
// This used level.time which didn't work outside a level.
|
||||
if (DClickTime[ev->data1] > I_MSTime() && ev->type == EV_KeyDown)
|
||||
{
|
||||
// Key pressed for a double click
|
||||
binding = DoubleBindings[ev->data1];
|
||||
DClicked[dclickspot] |= dclickmask;
|
||||
dclick = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ev->type == EV_KeyDown)
|
||||
{ // Key pressed for a normal press
|
||||
binding = Bindings[ev->data1];
|
||||
DClickTime[ev->data1] = I_MSTime() + 571;
|
||||
}
|
||||
else if (DClicked[dclickspot] & dclickmask)
|
||||
{ // Key released from a double click
|
||||
binding = DoubleBindings[ev->data1];
|
||||
DClicked[dclickspot] &= ~dclickmask;
|
||||
DClickTime[ev->data1] = 0;
|
||||
dclick = true;
|
||||
}
|
||||
else
|
||||
{ // Key released from a normal press
|
||||
binding = Bindings[ev->data1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (binding.IsEmpty())
|
||||
{
|
||||
binding = Bindings[ev->data1];
|
||||
dclick = false;
|
||||
}
|
||||
|
||||
if (!binding.IsEmpty() && (chatmodeon == 0 || ev->data1 < 256))
|
||||
{
|
||||
if (ev->type == EV_KeyUp && binding[0] != '+')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
char *copy = binding.LockBuffer();
|
||||
|
||||
if (ev->type == EV_KeyUp)
|
||||
{
|
||||
copy[0] = '-';
|
||||
}
|
||||
|
||||
AddCommandString (copy, dclick ? ev->data1 | KEY_DBLCLICKED : ev->data1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *C_ConfigKeyName(int keynum)
|
||||
{
|
||||
const char *name = KeyName(keynum);
|
||||
if (name[1] == 0) // Make sure given name is config-safe
|
||||
{
|
||||
if (name[0] == '[')
|
||||
return "LeftBracket";
|
||||
else if (name[0] == ']')
|
||||
return "RightBracket";
|
||||
else if (name[0] == '=')
|
||||
return "Equals";
|
||||
else if (strcmp (name, "kp=") == 0)
|
||||
return "KP-Equals";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
// This function is first called for functions in custom key sections.
|
||||
// In this case, matchcmd is non-NULL, and only keys bound to that command
|
||||
// are stored. If a match is found, its binding is set to "\1".
|
||||
// After all custom key sections are saved, it is called one more for the
|
||||
// normal Bindings and DoubleBindings sections for this game. In this case
|
||||
// matchcmd is NULL and all keys will be stored. The config section was not
|
||||
// previously cleared, so all old bindings are still in place. If the binding
|
||||
// for a key is empty, the corresponding key in the config is removed as well.
|
||||
// If a binding is "\1", then the binding itself is cleared, but nothing
|
||||
// happens to the entry in the config.
|
||||
void C_ArchiveBindings (FConfigFile *f, bool dodouble, const char *matchcmd)
|
||||
{
|
||||
FString *bindings;
|
||||
int i;
|
||||
|
||||
bindings = dodouble ? DoubleBindings : Bindings;
|
||||
|
||||
for (i = 0; i < NUM_KEYS; i++)
|
||||
{
|
||||
if (bindings[i].IsEmpty())
|
||||
{
|
||||
if (matchcmd == NULL)
|
||||
{
|
||||
f->ClearKey(C_ConfigKeyName(i));
|
||||
}
|
||||
}
|
||||
else if (matchcmd == NULL || stricmp(bindings[i], matchcmd) == 0)
|
||||
{
|
||||
if (bindings[i][0] == '\1')
|
||||
{
|
||||
bindings[i] = "";
|
||||
continue;
|
||||
}
|
||||
f->SetValueForKey(C_ConfigKeyName(i), bindings[i]);
|
||||
if (matchcmd != NULL)
|
||||
{ // If saving a specific command, set a marker so that
|
||||
// it does not get saved in the general binding list.
|
||||
bindings[i] = "\1";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void C_DoBind (const char *key, const char *bind, bool dodouble)
|
||||
{
|
||||
int keynum = GetKeyFromName (key);
|
||||
int keynum = GetKeyFromName(key);
|
||||
if (keynum == 0)
|
||||
{
|
||||
if (stricmp (key, "LeftBracket") == 0)
|
||||
|
@ -695,32 +355,55 @@ void C_DoBind (const char *key, const char *bind, bool dodouble)
|
|||
keynum = GetKeyFromName ("kp=");
|
||||
}
|
||||
}
|
||||
if (keynum != 0)
|
||||
{
|
||||
(dodouble ? DoubleBindings : Bindings)[keynum] = bind;
|
||||
}
|
||||
return keynum;
|
||||
}
|
||||
|
||||
int C_GetKeysForCommand (char *cmd, int *first, int *second)
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
static const char *KeyName (int key)
|
||||
{
|
||||
int c, i;
|
||||
static char name[5];
|
||||
|
||||
*first = *second = c = i = 0;
|
||||
if (KeyNames[key])
|
||||
return KeyNames[key];
|
||||
|
||||
while (i < NUM_KEYS && c < 2)
|
||||
{
|
||||
if (stricmp (cmd, Bindings[i]) == 0)
|
||||
{
|
||||
if (c++ == 0)
|
||||
*first = i;
|
||||
else
|
||||
*second = i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return c;
|
||||
mysnprintf (name, countof(name), "#%d", key);
|
||||
return name;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
static const char *ConfigKeyName(int keynum)
|
||||
{
|
||||
const char *name = KeyName(keynum);
|
||||
if (name[1] == 0) // Make sure given name is config-safe
|
||||
{
|
||||
if (name[0] == '[')
|
||||
return "LeftBracket";
|
||||
else if (name[0] == ']')
|
||||
return "RightBracket";
|
||||
else if (name[0] == '=')
|
||||
return "Equals";
|
||||
else if (strcmp (name, "kp=") == 0)
|
||||
return "KP-Equals";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void C_NameKeys (char *str, int first, int second)
|
||||
{
|
||||
int c = 0;
|
||||
|
@ -744,28 +427,471 @@ void C_NameKeys (char *str, int first, int second)
|
|||
*str = '\0';
|
||||
}
|
||||
|
||||
void C_UnbindACommand (char *str)
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FKeyBindings::DoBind (const char *key, const char *bind)
|
||||
{
|
||||
int keynum = GetConfigKeyFromName (key);
|
||||
if (keynum != 0)
|
||||
{
|
||||
Binds[keynum] = bind;
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FKeyBindings::SetBinds(const FBinding *binds)
|
||||
{
|
||||
while (binds->Key)
|
||||
{
|
||||
DoBind (binds->Key, binds->Bind);
|
||||
binds++;
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FKeyBindings::UnbindAll ()
|
||||
{
|
||||
for (int i = 0; i < NUM_KEYS; ++i)
|
||||
{
|
||||
Binds[i] = "";
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FKeyBindings::UnbindKey(const char *key)
|
||||
{
|
||||
int i;
|
||||
|
||||
if ( (i = GetKeyFromName (key)) )
|
||||
{
|
||||
Binds[i] = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf ("Unknown key \"%s\"\n", key);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FKeyBindings::PerformBind(FCommandLine &argv, const char *msg)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (argv.argc() > 1)
|
||||
{
|
||||
i = GetKeyFromName (argv[1]);
|
||||
if (!i)
|
||||
{
|
||||
Printf ("Unknown key \"%s\"\n", argv[1]);
|
||||
return;
|
||||
}
|
||||
if (argv.argc() == 2)
|
||||
{
|
||||
Printf ("\"%s\" = \"%s\"\n", argv[1], Binds[i].GetChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
Binds[i] = argv[2];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf ("%s:\n", msg);
|
||||
|
||||
for (i = 0; i < NUM_KEYS; i++)
|
||||
{
|
||||
if (!Binds[i].IsEmpty())
|
||||
Printf ("%s \"%s\"\n", KeyName (i), Binds[i].GetChars());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// This function is first called for functions in custom key sections.
|
||||
// In this case, matchcmd is non-NULL, and only keys bound to that command
|
||||
// are stored. If a match is found, its binding is set to "\1".
|
||||
// After all custom key sections are saved, it is called one more for the
|
||||
// normal Bindings and DoubleBindings sections for this game. In this case
|
||||
// matchcmd is NULL and all keys will be stored. The config section was not
|
||||
// previously cleared, so all old bindings are still in place. If the binding
|
||||
// for a key is empty, the corresponding key in the config is removed as well.
|
||||
// If a binding is "\1", then the binding itself is cleared, but nothing
|
||||
// happens to the entry in the config.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FKeyBindings::ArchiveBindings(FConfigFile *f, const char *matchcmd)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_KEYS; i++)
|
||||
{
|
||||
if (!stricmp (str, Bindings[i]))
|
||||
if (Binds[i].IsEmpty())
|
||||
{
|
||||
Bindings[i] = "";
|
||||
if (matchcmd == NULL)
|
||||
{
|
||||
f->ClearKey(ConfigKeyName(i));
|
||||
}
|
||||
}
|
||||
else if (matchcmd == NULL || stricmp(Binds[i], matchcmd) == 0)
|
||||
{
|
||||
if (Binds[i][0] == '\1')
|
||||
{
|
||||
Binds[i] = "";
|
||||
continue;
|
||||
}
|
||||
f->SetValueForKey(ConfigKeyName(i), Binds[i]);
|
||||
if (matchcmd != NULL)
|
||||
{ // If saving a specific command, set a marker so that
|
||||
// it does not get saved in the general binding list.
|
||||
Binds[i] = "\1";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void C_ChangeBinding (const char *str, int newone)
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
int FKeyBindings::GetKeysForCommand (const char *cmd, int *first, int *second)
|
||||
{
|
||||
if ((unsigned int)newone < NUM_KEYS)
|
||||
int c, i;
|
||||
|
||||
*first = *second = c = i = 0;
|
||||
|
||||
while (i < NUM_KEYS && c < 2)
|
||||
{
|
||||
Bindings[newone] = str;
|
||||
if (stricmp (cmd, Binds[i]) == 0)
|
||||
{
|
||||
if (c++ == 0)
|
||||
*first = i;
|
||||
else
|
||||
*second = i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FKeyBindings::UnbindACommand (const char *str)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_KEYS; i++)
|
||||
{
|
||||
if (!stricmp (str, Binds[i]))
|
||||
{
|
||||
Binds[i] = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *C_GetBinding (int key)
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FKeyBindings::DefaultBind(const char *keyname, const char *cmd)
|
||||
{
|
||||
return (unsigned int)key < NUM_KEYS ? Bindings[key].GetChars() : NULL;
|
||||
int key = GetKeyFromName (keyname);
|
||||
if (key == 0)
|
||||
{
|
||||
Printf ("Unknown key \"%s\"\n", keyname);
|
||||
return;
|
||||
}
|
||||
if (!Binds[key].IsEmpty())
|
||||
{ // This key is already bound.
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < NUM_KEYS; ++i)
|
||||
{
|
||||
if (!Binds[i].IsEmpty() && stricmp (Binds[i], cmd) == 0)
|
||||
{ // This command is already bound to a key.
|
||||
return;
|
||||
}
|
||||
}
|
||||
// It is safe to do the bind, so do it.
|
||||
Binds[key] = cmd;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void C_UnbindAll ()
|
||||
{
|
||||
Bindings.UnbindAll();
|
||||
DoubleBindings.UnbindAll();
|
||||
AutomapBindings.UnbindAll();
|
||||
}
|
||||
|
||||
CCMD (unbindall)
|
||||
{
|
||||
C_UnbindAll ();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
CCMD (unbind)
|
||||
{
|
||||
if (argv.argc() > 1)
|
||||
{
|
||||
Bindings.UnbindKey(argv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
CCMD (undoublebind)
|
||||
{
|
||||
if (argv.argc() > 1)
|
||||
{
|
||||
DoubleBindings.UnbindKey(argv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
CCMD (unmapbind)
|
||||
{
|
||||
if (argv.argc() > 1)
|
||||
{
|
||||
AutomapBindings.UnbindKey(argv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
CCMD (bind)
|
||||
{
|
||||
Bindings.PerformBind(argv, "Current key bindings");
|
||||
}
|
||||
|
||||
CCMD (doublebind)
|
||||
{
|
||||
DoubleBindings.PerformBind(argv, "Current key doublebindings");
|
||||
}
|
||||
|
||||
CCMD (mapbind)
|
||||
{
|
||||
AutomapBindings.PerformBind(argv, "Current automap key bindings");
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// CCMD defaultbind
|
||||
//
|
||||
// Binds a command to a key if that key is not already bound and if
|
||||
// that command is not already bound to another key.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
CCMD (defaultbind)
|
||||
{
|
||||
if (argv.argc() < 3)
|
||||
{
|
||||
Printf ("Usage: defaultbind <key> <command>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
Bindings.DefaultBind(argv[1], argv[2]);
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
CCMD (rebind)
|
||||
{
|
||||
FKeyBindings *bindings;
|
||||
|
||||
if (key == 0)
|
||||
{
|
||||
Printf ("Rebind cannot be used from the console\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (key & KEY_DBLCLICKED)
|
||||
{
|
||||
bindings = &DoubleBindings;
|
||||
key &= KEY_DBLCLICKED-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
bindings = &Bindings;
|
||||
}
|
||||
|
||||
if (argv.argc() > 1)
|
||||
{
|
||||
bindings->SetBind(key, argv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void C_BindDefaults ()
|
||||
{
|
||||
Bindings.SetBinds (DefBindings);
|
||||
|
||||
if (gameinfo.gametype & (GAME_Raven|GAME_Strife))
|
||||
{
|
||||
Bindings.SetBinds (DefRavenBindings);
|
||||
}
|
||||
|
||||
if (gameinfo.gametype == GAME_Heretic)
|
||||
{
|
||||
Bindings.SetBinds (DefHereticBindings);
|
||||
}
|
||||
|
||||
if (gameinfo.gametype == GAME_Hexen)
|
||||
{
|
||||
Bindings.SetBinds (DefHexenBindings);
|
||||
}
|
||||
|
||||
if (gameinfo.gametype == GAME_Strife)
|
||||
{
|
||||
Bindings.SetBinds (DefStrifeBindings);
|
||||
}
|
||||
|
||||
AutomapBindings.SetBinds(DefAutomapBindings);
|
||||
}
|
||||
|
||||
CCMD(binddefaults)
|
||||
{
|
||||
C_BindDefaults ();
|
||||
}
|
||||
|
||||
void C_SetDefaultBindings ()
|
||||
{
|
||||
C_UnbindAll ();
|
||||
C_BindDefaults ();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool C_DoKey (event_t *ev, FKeyBindings *binds, FKeyBindings *doublebinds)
|
||||
{
|
||||
FString binding;
|
||||
bool dclick;
|
||||
int dclickspot;
|
||||
BYTE dclickmask;
|
||||
|
||||
if (ev->type != EV_KeyDown && ev->type != EV_KeyUp)
|
||||
return false;
|
||||
|
||||
if ((unsigned int)ev->data1 >= NUM_KEYS)
|
||||
return false;
|
||||
|
||||
dclickspot = ev->data1 >> 3;
|
||||
dclickmask = 1 << (ev->data1 & 7);
|
||||
dclick = false;
|
||||
|
||||
// This used level.time which didn't work outside a level.
|
||||
if (DClickTime[ev->data1] > I_MSTime() && ev->type == EV_KeyDown)
|
||||
{
|
||||
// Key pressed for a double click
|
||||
if (doublebinds != NULL) binding = doublebinds->GetBinding(ev->data1);
|
||||
DClicked[dclickspot] |= dclickmask;
|
||||
dclick = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ev->type == EV_KeyDown)
|
||||
{ // Key pressed for a normal press
|
||||
binding = binds->GetBinding(ev->data1);
|
||||
DClickTime[ev->data1] = I_MSTime() + 571;
|
||||
}
|
||||
else if (DClicked[dclickspot] & dclickmask)
|
||||
{ // Key released from a double click
|
||||
if (doublebinds != NULL) binding = doublebinds->GetBinding(ev->data1);
|
||||
DClicked[dclickspot] &= ~dclickmask;
|
||||
DClickTime[ev->data1] = 0;
|
||||
dclick = true;
|
||||
}
|
||||
else
|
||||
{ // Key released from a normal press
|
||||
binding = binds->GetBinding(ev->data1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (binding.IsEmpty())
|
||||
{
|
||||
binding = binds->GetBinding(ev->data1);
|
||||
dclick = false;
|
||||
}
|
||||
|
||||
if (!binding.IsEmpty() && (chatmodeon == 0 || ev->data1 < 256))
|
||||
{
|
||||
if (ev->type == EV_KeyUp && binding[0] != '+')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
char *copy = binding.LockBuffer();
|
||||
|
||||
if (ev->type == EV_KeyUp)
|
||||
{
|
||||
copy[0] = '-';
|
||||
}
|
||||
|
||||
AddCommandString (copy, dclick ? ev->data1 | KEY_DBLCLICKED : ev->data1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
75
src/c_bind.h
75
src/c_bind.h
|
@ -34,25 +34,80 @@
|
|||
#ifndef __C_BINDINGS_H__
|
||||
#define __C_BINDINGS_H__
|
||||
|
||||
#include "doomdef.h"
|
||||
|
||||
struct event_t;
|
||||
class FConfigFile;
|
||||
class FCommandLine;
|
||||
|
||||
bool C_DoKey (event_t *ev);
|
||||
void C_ArchiveBindings (FConfigFile *f, bool dodouble, const char *matchcmd=NULL);
|
||||
void C_NameKeys (char *str, int first, int second);
|
||||
|
||||
struct FBinding
|
||||
{
|
||||
const char *Key;
|
||||
const char *Bind;
|
||||
};
|
||||
|
||||
class FKeyBindings
|
||||
{
|
||||
FString Binds[NUM_KEYS];
|
||||
|
||||
public:
|
||||
void PerformBind(FCommandLine &argv, const char *msg);
|
||||
void SetBinds(const FBinding *binds);
|
||||
bool DoKey(event_t *ev);
|
||||
void ArchiveBindings(FConfigFile *F, const char *matchcmd = NULL);
|
||||
int GetKeysForCommand (const char *cmd, int *first, int *second);
|
||||
void UnbindACommand (const char *str);
|
||||
void UnbindAll ();
|
||||
void UnbindKey(const char *key);
|
||||
void DoBind (const char *key, const char *bind);
|
||||
void DefaultBind(const char *keyname, const char *cmd);
|
||||
|
||||
void SetBind(unsigned int key, const char *bind)
|
||||
{
|
||||
if (key < NUM_KEYS) Binds[key] = bind;
|
||||
}
|
||||
|
||||
const FString &GetBinding(unsigned int index) const
|
||||
{
|
||||
return Binds[index];
|
||||
}
|
||||
|
||||
const char *GetBind(unsigned int index) const
|
||||
{
|
||||
if (index < NUM_KEYS) return Binds[index];
|
||||
else return NULL;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
extern FKeyBindings Bindings;
|
||||
extern FKeyBindings DoubleBindings;
|
||||
extern FKeyBindings AutomapBindings;
|
||||
extern FKeyBindings MenuBindings;
|
||||
|
||||
|
||||
bool C_DoKey (event_t *ev, FKeyBindings *binds, FKeyBindings *doublebinds);
|
||||
|
||||
// Stuff used by the customize controls menu
|
||||
int C_GetKeysForCommand (char *cmd, int *first, int *second);
|
||||
void C_NameKeys (char *str, int first, int second);
|
||||
void C_UnbindACommand (char *str);
|
||||
void C_ChangeBinding (const char *str, int newone);
|
||||
void C_DoBind (const char *key, const char *bind, bool doublebind);
|
||||
void C_SetDefaultBindings ();
|
||||
void C_UnbindAll ();
|
||||
|
||||
// Returns string bound to given key (NULL if none)
|
||||
const char *C_GetBinding (int key);
|
||||
|
||||
extern const char *KeyNames[];
|
||||
|
||||
struct FKeyAction
|
||||
{
|
||||
FString mTitle;
|
||||
FString mAction;
|
||||
};
|
||||
|
||||
struct FKeySection
|
||||
{
|
||||
FString mTitle;
|
||||
FString mSection;
|
||||
TArray<FKeyAction> mActions;
|
||||
};
|
||||
extern TArray<FKeySection> KeySections;
|
||||
|
||||
#endif //__C_BINDINGS_H__
|
||||
|
|
|
@ -936,3 +936,4 @@ CCMD(currentpos)
|
|||
FIXED2FLOAT(mo->x), FIXED2FLOAT(mo->y), FIXED2FLOAT(mo->z), mo->angle/float(ANGLE_1), FIXED2FLOAT(mo->floorz), mo->Sector->sectornum, mo->Sector->lightlevel);
|
||||
}
|
||||
|
||||
|
||||
|
|
110
src/c_cvars.cpp
110
src/c_cvars.cpp
|
@ -1119,7 +1119,7 @@ void FFlagCVar::DoSet (UCVarValue value, ECVarType type)
|
|||
// exec scripts because all flags will base their changes off of the value of
|
||||
// the "master" cvar at the time the script was run, overriding any changes
|
||||
// another flag might have made to the same cvar earlier in the script.
|
||||
if ((ValueVar.Flags & CVAR_SERVERINFO) && gamestate != GS_STARTUP && !demoplayback)
|
||||
if ((ValueVar.GetFlags() & CVAR_SERVERINFO) && gamestate != GS_STARTUP && !demoplayback)
|
||||
{
|
||||
if (netgame && !players[consoleplayer].settings_controller)
|
||||
{
|
||||
|
@ -1139,6 +1139,114 @@ void FFlagCVar::DoSet (UCVarValue value, ECVarType type)
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Mask cvar implementation
|
||||
//
|
||||
// Similar to FFlagCVar but can have multiple bits
|
||||
//
|
||||
|
||||
FMaskCVar::FMaskCVar (const char *name, FIntCVar &realvar, DWORD bitval)
|
||||
: FBaseCVar (name, 0, NULL),
|
||||
ValueVar (realvar),
|
||||
BitVal (bitval)
|
||||
{
|
||||
int bit;
|
||||
|
||||
Flags &= ~CVAR_ISDEFAULT;
|
||||
|
||||
assert (bitval != 0);
|
||||
|
||||
bit = 0;
|
||||
while ((bitval & 1) == 0)
|
||||
{
|
||||
++bit;
|
||||
bitval >>= 1;
|
||||
}
|
||||
BitNum = bit;
|
||||
}
|
||||
|
||||
ECVarType FMaskCVar::GetRealType () const
|
||||
{
|
||||
return CVAR_Dummy;
|
||||
}
|
||||
|
||||
UCVarValue FMaskCVar::GetGenericRep (ECVarType type) const
|
||||
{
|
||||
return FromInt ((ValueVar & BitVal) >> BitNum, type);
|
||||
}
|
||||
|
||||
UCVarValue FMaskCVar::GetFavoriteRep (ECVarType *type) const
|
||||
{
|
||||
UCVarValue ret;
|
||||
*type = CVAR_Int;
|
||||
ret.Int = (ValueVar & BitVal) >> BitNum;
|
||||
return ret;
|
||||
}
|
||||
|
||||
UCVarValue FMaskCVar::GetGenericRepDefault (ECVarType type) const
|
||||
{
|
||||
ECVarType dummy;
|
||||
UCVarValue def;
|
||||
def = ValueVar.GetFavoriteRepDefault (&dummy);
|
||||
return FromInt ((def.Int & BitVal) >> BitNum, type);
|
||||
}
|
||||
|
||||
UCVarValue FMaskCVar::GetFavoriteRepDefault (ECVarType *type) const
|
||||
{
|
||||
ECVarType dummy;
|
||||
UCVarValue def;
|
||||
def = ValueVar.GetFavoriteRepDefault (&dummy);
|
||||
def.Int = (def.Int & BitVal) >> BitNum;
|
||||
*type = CVAR_Int;
|
||||
return def;
|
||||
}
|
||||
|
||||
void FMaskCVar::SetGenericRepDefault (UCVarValue value, ECVarType type)
|
||||
{
|
||||
int val = ToInt(value, type) << BitNum;
|
||||
ECVarType dummy;
|
||||
UCVarValue def;
|
||||
def = ValueVar.GetFavoriteRepDefault (&dummy);
|
||||
def.Int &= ~BitVal;
|
||||
def.Int |= val;
|
||||
ValueVar.SetGenericRepDefault (def, CVAR_Int);
|
||||
}
|
||||
|
||||
void FMaskCVar::DoSet (UCVarValue value, ECVarType type)
|
||||
{
|
||||
int val = ToInt(value, type) << BitNum;
|
||||
|
||||
// Server cvars that get changed by this need to use a special message, because
|
||||
// changes are not processed until the next net update. This is a problem with
|
||||
// exec scripts because all flags will base their changes off of the value of
|
||||
// the "master" cvar at the time the script was run, overriding any changes
|
||||
// another flag might have made to the same cvar earlier in the script.
|
||||
if ((ValueVar.GetFlags() & CVAR_SERVERINFO) && gamestate != GS_STARTUP && !demoplayback)
|
||||
{
|
||||
if (netgame && !players[consoleplayer].settings_controller)
|
||||
{
|
||||
Printf ("Only setting controllers can change %s\n", Name);
|
||||
return;
|
||||
}
|
||||
// Ugh...
|
||||
for(int i = 0; i < 32; i++)
|
||||
{
|
||||
if (BitVal & (1<<i))
|
||||
{
|
||||
D_SendServerFlagChange (&ValueVar, i, !!(val & (1<<i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int vval = *ValueVar;
|
||||
vval &= ~BitVal;
|
||||
vval |= val;
|
||||
ValueVar = vval;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
static int STACK_ARGS sortcvars (const void *a, const void *b)
|
||||
{
|
||||
|
|
|
@ -344,6 +344,30 @@ protected:
|
|||
int BitNum;
|
||||
};
|
||||
|
||||
class FMaskCVar : public FBaseCVar
|
||||
{
|
||||
public:
|
||||
FMaskCVar (const char *name, FIntCVar &realvar, uint32 bitval);
|
||||
|
||||
virtual ECVarType GetRealType () const;
|
||||
|
||||
virtual UCVarValue GetGenericRep (ECVarType type) const;
|
||||
virtual UCVarValue GetFavoriteRep (ECVarType *type) const;
|
||||
virtual UCVarValue GetGenericRepDefault (ECVarType type) const;
|
||||
virtual UCVarValue GetFavoriteRepDefault (ECVarType *type) const;
|
||||
virtual void SetGenericRepDefault (UCVarValue value, ECVarType type);
|
||||
|
||||
inline operator int () const { return (ValueVar & BitVal) >> BitNum; }
|
||||
inline int operator *() const { return (ValueVar & BitVal) >> BitNum; }
|
||||
|
||||
protected:
|
||||
virtual void DoSet (UCVarValue value, ECVarType type);
|
||||
|
||||
FIntCVar &ValueVar;
|
||||
uint32 BitVal;
|
||||
int BitNum;
|
||||
};
|
||||
|
||||
class FGUIDCVar : public FBaseCVar
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -119,7 +119,9 @@ FButtonStatus Button_Mlook, Button_Klook, Button_Use, Button_AltAttack,
|
|||
Button_Forward, Button_Right, Button_Left, Button_MoveDown,
|
||||
Button_MoveUp, Button_Jump, Button_ShowScores, Button_Crouch,
|
||||
Button_Zoom, Button_Reload,
|
||||
Button_User1, Button_User2, Button_User3, Button_User4;
|
||||
Button_User1, Button_User2, Button_User3, Button_User4,
|
||||
Button_AM_PanLeft, Button_AM_PanRight, Button_AM_PanDown, Button_AM_PanUp,
|
||||
Button_AM_ZoomIn, Button_AM_ZoomOut;
|
||||
|
||||
bool ParsingKeyConf;
|
||||
|
||||
|
@ -131,13 +133,16 @@ bool ParsingKeyConf;
|
|||
|
||||
FActionMap ActionMaps[] =
|
||||
{
|
||||
{ 0x0d52d67b, &Button_AM_PanLeft, "am_panleft"},
|
||||
{ 0x125f5226, &Button_User2, "user2" },
|
||||
{ 0x1eefa611, &Button_Jump, "jump" },
|
||||
{ 0x201f1c55, &Button_Right, "right" },
|
||||
{ 0x20ccc4d5, &Button_Zoom, "zoom" },
|
||||
{ 0x23a99cd7, &Button_Back, "back" },
|
||||
{ 0x41df90c2, &Button_AM_ZoomIn, "am_zoomin"},
|
||||
{ 0x426b69e7, &Button_Reload, "reload" },
|
||||
{ 0x4463f43a, &Button_LookDown, "lookdown" },
|
||||
{ 0x51f7a334, &Button_AM_ZoomOut, "am_zoomout"},
|
||||
{ 0x534c30ee, &Button_User4, "user4" },
|
||||
{ 0x5622bf42, &Button_Attack, "attack" },
|
||||
{ 0x577712d0, &Button_User1, "user1" },
|
||||
|
@ -147,12 +152,15 @@ FActionMap ActionMaps[] =
|
|||
{ 0x676885b8, &Button_AltAttack, "altattack" },
|
||||
{ 0x6fa41b84, &Button_MoveLeft, "moveleft" },
|
||||
{ 0x818f08e6, &Button_MoveRight, "moveright" },
|
||||
{ 0x8197097b, &Button_AM_PanRight, "am_panright"},
|
||||
{ 0x8d89955e, &Button_AM_PanUp, "am_panup"} ,
|
||||
{ 0xa2b62d8b, &Button_Mlook, "mlook" },
|
||||
{ 0xab2c3e71, &Button_Crouch, "crouch" },
|
||||
{ 0xb000b483, &Button_Left, "left" },
|
||||
{ 0xb62b1e49, &Button_LookUp, "lookup" },
|
||||
{ 0xb6f8fe92, &Button_User3, "user3" },
|
||||
{ 0xb7e6a54b, &Button_Strafe, "strafe" },
|
||||
{ 0xce301c81, &Button_AM_PanDown, "am_pandown"},
|
||||
{ 0xd5897c73, &Button_ShowScores, "showscores" },
|
||||
{ 0xe0ccb317, &Button_Speed, "speed" },
|
||||
{ 0xe0cfc260, &Button_Use, "use" },
|
||||
|
@ -160,6 +168,7 @@ FActionMap ActionMaps[] =
|
|||
};
|
||||
#define NUM_ACTIONS countof(ActionMaps)
|
||||
|
||||
|
||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||
|
||||
static const char *KeyConfCommands[] =
|
||||
|
|
|
@ -146,6 +146,7 @@ struct FButtonStatus
|
|||
bool PressKey (int keynum); // Returns true if this key caused the button to be pressed.
|
||||
bool ReleaseKey (int keynum); // Returns true if this key is no longer pressed.
|
||||
void ResetTriggers () { bWentDown = bWentUp = false; }
|
||||
void Reset () { bDown = bWentDown = bWentUp = false; }
|
||||
};
|
||||
|
||||
extern FButtonStatus Button_Mlook, Button_Klook, Button_Use, Button_AltAttack,
|
||||
|
@ -154,7 +155,9 @@ extern FButtonStatus Button_Mlook, Button_Klook, Button_Use, Button_AltAttack,
|
|||
Button_Forward, Button_Right, Button_Left, Button_MoveDown,
|
||||
Button_MoveUp, Button_Jump, Button_ShowScores, Button_Crouch,
|
||||
Button_Zoom, Button_Reload,
|
||||
Button_User1, Button_User2, Button_User3, Button_User4;
|
||||
Button_User1, Button_User2, Button_User3, Button_User4,
|
||||
Button_AM_PanLeft, Button_AM_PanRight, Button_AM_PanDown, Button_AM_PanUp,
|
||||
Button_AM_ZoomIn, Button_AM_ZoomOut;
|
||||
extern bool ParsingKeyConf;
|
||||
|
||||
void ResetButtonTriggers (); // Call ResetTriggers for all buttons
|
||||
|
|
171
src/cmdlib.cpp
171
src/cmdlib.cpp
|
@ -2,10 +2,14 @@
|
|||
|
||||
#ifdef _WIN32
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#if !defined(__sun)
|
||||
#include <fts.h>
|
||||
#endif
|
||||
#endif
|
||||
#include "doomtype.h"
|
||||
#include "cmdlib.h"
|
||||
|
@ -90,6 +94,23 @@ char *copystring (const char *s)
|
|||
return b;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// ncopystring
|
||||
//
|
||||
// If the string has no content, returns NULL. Otherwise, returns a copy.
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
char *ncopystring (const char *string)
|
||||
{
|
||||
if (string == NULL || string[0] == 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return copystring (string);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ReplaceString
|
||||
|
@ -868,3 +889,153 @@ FString NicePath(const char *path)
|
|||
return where;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ScanDirectory
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ScanDirectory(TArray<FFileList> &list, const char *dirpath)
|
||||
{
|
||||
struct _finddata_t fileinfo;
|
||||
intptr_t handle;
|
||||
FString dirmatch;
|
||||
|
||||
dirmatch << dirpath << "*";
|
||||
|
||||
if ((handle = _findfirst(dirmatch, &fileinfo)) == -1)
|
||||
{
|
||||
I_Error("Could not scan '%s': %s\n", dirpath, strerror(errno));
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
if (fileinfo.attrib & _A_HIDDEN)
|
||||
{
|
||||
// Skip hidden files and directories. (Prevents SVN bookkeeping
|
||||
// info from being included.)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fileinfo.attrib & _A_SUBDIR)
|
||||
{
|
||||
if (fileinfo.name[0] == '.' &&
|
||||
(fileinfo.name[1] == '\0' ||
|
||||
(fileinfo.name[1] == '.' && fileinfo.name[2] == '\0')))
|
||||
{
|
||||
// Do not record . and .. directories.
|
||||
continue;
|
||||
}
|
||||
|
||||
FFileList *fl = &list[list.Reserve(1)];
|
||||
fl->Filename << dirpath << fileinfo.name;
|
||||
fl->isDirectory = true;
|
||||
FString newdir = fl->Filename;
|
||||
newdir << "/";
|
||||
ScanDirectory(list, newdir);
|
||||
}
|
||||
else
|
||||
{
|
||||
FFileList *fl = &list[list.Reserve(1)];
|
||||
fl->Filename << dirpath << fileinfo.name;
|
||||
fl->isDirectory = false;
|
||||
}
|
||||
}
|
||||
while (_findnext(handle, &fileinfo) == 0);
|
||||
_findclose(handle);
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(__sun) || defined(linux)
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ScanDirectory
|
||||
// Solaris version
|
||||
//
|
||||
// Given NULL-terminated array of directory paths, create trees for them.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ScanDirectory(TArray<FFileList> &list, const char *dirpath)
|
||||
{
|
||||
DIR *directory = opendir(dirpath);
|
||||
if(directory == NULL)
|
||||
return;
|
||||
|
||||
struct dirent *file;
|
||||
while((file = readdir(directory)) != NULL)
|
||||
{
|
||||
if(file->d_name[0] == '.') //File is hidden or ./.. directory so ignore it.
|
||||
continue;
|
||||
|
||||
FFileList *fl = &list[list.Reserve(1)];
|
||||
fl->Filename << dirpath << file->d_name;
|
||||
|
||||
struct stat fileStat;
|
||||
stat(fl->Filename, &fileStat);
|
||||
fl->isDirectory = S_ISDIR(fileStat.st_mode);
|
||||
|
||||
if(fl->isDirectory)
|
||||
{
|
||||
FString newdir = fl->Filename;
|
||||
newdir += "/";
|
||||
ScanDirectory(list, newdir);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
closedir(directory);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ScanDirectory
|
||||
// 4.4BSD version
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ScanDirectory(TArray<FFileList> &list, const char *dirpath)
|
||||
{
|
||||
const char **argv[] = {dirpath, NULL };
|
||||
FTS *fts;
|
||||
FTSENT *ent;
|
||||
|
||||
fts = fts_open(argv, FTS_LOGICAL, NULL);
|
||||
if (fts == NULL)
|
||||
{
|
||||
I_Error("Failed to start directory traversal: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
while ((ent = fts_read(fts)) != NULL)
|
||||
{
|
||||
if (ent->fts_info == FTS_D && ent->fts_name[0] == '.')
|
||||
{
|
||||
// Skip hidden directories. (Prevents SVN bookkeeping
|
||||
// info from being included.)
|
||||
fts_set(fts, ent, FTS_SKIP);
|
||||
}
|
||||
if (ent->fts_info == FTS_D && ent->fts_level == 0)
|
||||
{
|
||||
FFileList *fl = &list[list.Reserve(1)];
|
||||
fl->Filename = ent->fts_path;
|
||||
fl->isDirectory = true;
|
||||
}
|
||||
if (ent->fts_info == FTS_F)
|
||||
{
|
||||
// We're only interested in remembering files.
|
||||
FFileList *fl = &list[list.Reserve(1)];
|
||||
fl->Filename = ent->fts_path;
|
||||
fl->isDirectory = false;
|
||||
}
|
||||
}
|
||||
fts_close(fts);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -36,6 +36,7 @@ int ParseNum (const char *str);
|
|||
bool IsNum (const char *str); // [RH] added
|
||||
|
||||
char *copystring(const char *s);
|
||||
char *ncopystring(const char *s);
|
||||
void ReplaceString (char **ptr, const char *str);
|
||||
|
||||
bool CheckWildcards (const char *pattern, const char *text);
|
||||
|
@ -53,4 +54,12 @@ void CreatePath(const char * fn);
|
|||
FString ExpandEnvVars(const char *searchpathstring);
|
||||
FString NicePath(const char *path);
|
||||
|
||||
struct FFileList
|
||||
{
|
||||
FString Filename;
|
||||
bool isDirectory;
|
||||
};
|
||||
|
||||
void ScanDirectory(TArray<FFileList> &list, const char *dirpath);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -118,6 +118,7 @@ static FCompatOption Options[] =
|
|||
{ "spritesort", COMPATF_SPRITESORT, 0 },
|
||||
{ "hitscan", COMPATF_HITSCAN, 0 },
|
||||
{ "lightlevel", COMPATF_LIGHT, 0 },
|
||||
{ "polyobj", COMPATF_POLYOBJ, 0 },
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -185,7 +186,7 @@ void ParseCompatibility()
|
|||
} while (!sc.Compare("{"));
|
||||
flags.CompatFlags = 0;
|
||||
flags.BCompatFlags = 0;
|
||||
flags.ExtCommandIndex = -1;
|
||||
flags.ExtCommandIndex = ~0u;
|
||||
while (sc.GetString())
|
||||
{
|
||||
if ((i = sc.MatchString(&Options[0].Name, sizeof(*Options))) >= 0)
|
||||
|
@ -195,7 +196,7 @@ void ParseCompatibility()
|
|||
}
|
||||
else if (sc.Compare("clearlineflags"))
|
||||
{
|
||||
if (flags.ExtCommandIndex == -1) flags.ExtCommandIndex = CompatParams.Size();
|
||||
if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size();
|
||||
CompatParams.Push(CP_CLEARFLAGS);
|
||||
sc.MustGetNumber();
|
||||
CompatParams.Push(sc.Number);
|
||||
|
@ -204,7 +205,7 @@ void ParseCompatibility()
|
|||
}
|
||||
else if (sc.Compare("setlineflags"))
|
||||
{
|
||||
if (flags.ExtCommandIndex == -1) flags.ExtCommandIndex = CompatParams.Size();
|
||||
if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size();
|
||||
CompatParams.Push(CP_SETFLAGS);
|
||||
sc.MustGetNumber();
|
||||
CompatParams.Push(sc.Number);
|
||||
|
@ -213,7 +214,7 @@ void ParseCompatibility()
|
|||
}
|
||||
else if (sc.Compare("setlinespecial"))
|
||||
{
|
||||
if (flags.ExtCommandIndex == -1) flags.ExtCommandIndex = CompatParams.Size();
|
||||
if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size();
|
||||
CompatParams.Push(CP_SETSPECIAL);
|
||||
sc.MustGetNumber();
|
||||
CompatParams.Push(sc.Number);
|
||||
|
@ -232,7 +233,7 @@ void ParseCompatibility()
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (flags.ExtCommandIndex != -1)
|
||||
if (flags.ExtCommandIndex != ~0u)
|
||||
{
|
||||
CompatParams.Push(CP_END);
|
||||
}
|
||||
|
@ -266,6 +267,19 @@ void CheckCompatibility(MapData *map)
|
|||
ib_compatflags = 0;
|
||||
ii_compatparams = -1;
|
||||
}
|
||||
else if (Wads.GetLumpFile(map->lumpnum) == 1 && (gameinfo.flags & GI_COMPATPOLY1) && Wads.CheckLumpName(map->lumpnum, "MAP36"))
|
||||
{
|
||||
ii_compatflags = COMPATF_POLYOBJ;
|
||||
ib_compatflags = 0;
|
||||
ii_compatparams = -1;
|
||||
}
|
||||
else if (Wads.GetLumpFile(map->lumpnum) == 2 && (gameinfo.flags & GI_COMPATPOLY2) && Wads.CheckLumpName(map->lumpnum, "MAP47"))
|
||||
{
|
||||
ii_compatflags = COMPATF_POLYOBJ;
|
||||
ib_compatflags = 0;
|
||||
ii_compatparams = -1;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
map->GetChecksum(md5.Bytes);
|
||||
|
|
|
@ -952,7 +952,7 @@ static int PatchThing (int thingy)
|
|||
// compatibility, the upper bits are freed, but we have conflicts between the ZDoom bits
|
||||
// and the MBF bits. The only such flag exposed to DEHSUPP, though, is STEALTH -- the others
|
||||
// are not available through mnemonics, and aren't available either through their bit value.
|
||||
// So if we find the STEALTH keyword, it's a ZDoom mod, otherwise assume assume FRIEND.
|
||||
// So if we find the STEALTH keyword, it's a ZDoom mod, otherwise assume FRIEND.
|
||||
bool zdoomflags = false;
|
||||
char *strval;
|
||||
|
||||
|
@ -2109,13 +2109,13 @@ static int PatchText (int oldSize)
|
|||
// This must be done because the map is scanned using a binary search.
|
||||
while (i > 0 && strncmp (DehSpriteMappings[i-1].Sprite, newStr, 4) > 0)
|
||||
{
|
||||
swap (DehSpriteMappings[i-1], DehSpriteMappings[i]);
|
||||
swapvalues (DehSpriteMappings[i-1], DehSpriteMappings[i]);
|
||||
--i;
|
||||
}
|
||||
while ((size_t)i < countof(DehSpriteMappings)-1 &&
|
||||
strncmp (DehSpriteMappings[i+1].Sprite, newStr, 4) < 0)
|
||||
{
|
||||
swap (DehSpriteMappings[i+1], DehSpriteMappings[i]);
|
||||
swapvalues (DehSpriteMappings[i+1], DehSpriteMappings[i]);
|
||||
++i;
|
||||
}
|
||||
break;
|
||||
|
|
39
src/d_gui.h
39
src/d_gui.h
|
@ -43,27 +43,34 @@ enum EGUIEvent
|
|||
EV_GUI_KeyRepeat, // same
|
||||
EV_GUI_KeyUp, // same
|
||||
EV_GUI_Char, // data1: translated character (for user text input), data2: alt down?
|
||||
EV_GUI_MouseMove,
|
||||
EV_GUI_LButtonDown,
|
||||
EV_GUI_LButtonUp,
|
||||
EV_GUI_LButtonDblClick,
|
||||
EV_GUI_MButtonDown,
|
||||
EV_GUI_MButtonUp,
|
||||
EV_GUI_MButtonDblClick,
|
||||
EV_GUI_RButtonDown,
|
||||
EV_GUI_RButtonUp,
|
||||
EV_GUI_RButtonDblClick,
|
||||
EV_GUI_WheelUp, // data3: shift/ctrl/alt
|
||||
EV_GUI_WheelDown, // "
|
||||
EV_GUI_WheelRight, // "
|
||||
EV_GUI_WheelLeft, // "
|
||||
EV_GUI_FirstMouseEvent,
|
||||
EV_GUI_MouseMove,
|
||||
EV_GUI_LButtonDown,
|
||||
EV_GUI_LButtonUp,
|
||||
EV_GUI_LButtonDblClick,
|
||||
EV_GUI_MButtonDown,
|
||||
EV_GUI_MButtonUp,
|
||||
EV_GUI_MButtonDblClick,
|
||||
EV_GUI_RButtonDown,
|
||||
EV_GUI_RButtonUp,
|
||||
EV_GUI_RButtonDblClick,
|
||||
EV_GUI_WheelUp, // data3: shift/ctrl/alt
|
||||
EV_GUI_WheelDown, // "
|
||||
EV_GUI_WheelRight, // "
|
||||
EV_GUI_WheelLeft, // "
|
||||
EV_GUI_BackButtonDown,
|
||||
EV_GUI_BackButtonUp,
|
||||
EV_GUI_FwdButtonDown,
|
||||
EV_GUI_FwdButtonUp,
|
||||
EV_GUI_LastMouseEvent,
|
||||
};
|
||||
|
||||
enum GUIKeyModifiers
|
||||
{
|
||||
GKM_SHIFT = 1,
|
||||
GKM_CTRL = 2,
|
||||
GKM_ALT = 4
|
||||
GKM_ALT = 4,
|
||||
GKM_LBUTTON = 8
|
||||
};
|
||||
|
||||
// Special codes for some GUI keys, including a few real ASCII codes.
|
||||
|
@ -100,7 +107,7 @@ enum ESpecialGUIKeys
|
|||
GK_ESCAPE = 27, // ASCII
|
||||
GK_FREE1 = 28,
|
||||
GK_FREE2 = 29,
|
||||
GK_FREE3 = 30,
|
||||
GK_BACK = 30, // browser back key
|
||||
GK_CESCAPE = 31 // color escape
|
||||
};
|
||||
|
||||
|
|
|
@ -60,8 +60,8 @@ const IWADInfo IWADInfos[NUM_IWAD_TYPES] =
|
|||
// banner text, autoname, fg color, bg color
|
||||
{ "Final Doom: TNT - Evilution", "TNT", MAKERGB(168,0,0), MAKERGB(168,168,168), GAME_Doom, "mapinfo/tnt.txt", GI_MAPxx | GI_COMPATSHORTTEX | GI_COMPATSTAIRS },
|
||||
{ "Final Doom: Plutonia Experiment", "Plutonia", MAKERGB(168,0,0), MAKERGB(168,168,168), GAME_Doom, "mapinfo/plutonia.txt", GI_MAPxx | GI_COMPATSHORTTEX },
|
||||
{ "Hexen: Beyond Heretic", NULL, MAKERGB(240,240,240), MAKERGB(107,44,24), GAME_Hexen, "mapinfo/hexen.txt", GI_MAPxx },
|
||||
{ "Hexen: Deathkings of the Dark Citadel", "HexenDK", MAKERGB(240,240,240), MAKERGB(139,68,9), GAME_Hexen, "mapinfo/hexen.txt", GI_MAPxx },
|
||||
{ "Hexen: Beyond Heretic", NULL, MAKERGB(240,240,240), MAKERGB(107,44,24), GAME_Hexen, "mapinfo/hexen.txt", GI_MAPxx | GI_COMPATPOLY1 },
|
||||
{ "Hexen: Deathkings of the Dark Citadel", "HexenDK", MAKERGB(240,240,240), MAKERGB(139,68,9), GAME_Hexen, "mapinfo/hexen.txt", GI_MAPxx | GI_COMPATPOLY1 | GI_COMPATPOLY2 },
|
||||
{ "Hexen: Demo Version", "HexenDemo",MAKERGB(240,240,240), MAKERGB(107,44,24), GAME_Hexen, "mapinfo/hexen.txt", GI_MAPxx | GI_SHAREWARE },
|
||||
{ "DOOM 2: Hell on Earth", "Doom2", MAKERGB(168,0,0), MAKERGB(168,168,168), GAME_Doom, "mapinfo/doom2.txt", GI_MAPxx | GI_COMPATSHORTTEX },
|
||||
{ "Heretic Shareware", NULL, MAKERGB(252,252,0), MAKERGB(168,0,0), GAME_Heretic, "mapinfo/hereticsw.txt",GI_SHAREWARE },
|
||||
|
@ -79,7 +79,7 @@ const IWADInfo IWADInfos[NUM_IWAD_TYPES] =
|
|||
{ "FreeDM", "FreeDM", MAKERGB(50,84,67), MAKERGB(198,220,209), GAME_Doom, "mapinfo/doom2.txt", GI_MAPxx },
|
||||
{ "Blasphemer", "Blasphemer",MAKERGB(115,0,0), MAKERGB(0,0,0), GAME_Heretic, "mapinfo/heretic.txt" },
|
||||
{ "Chex(R) Quest", "Chex1", MAKERGB(255,255,0), MAKERGB(0,192,0), GAME_Chex, "mapinfo/chex.txt" },
|
||||
{ "Chex(R) Quest 3", "Chex3", MAKERGB(255,255,0), MAKERGB(0,192,0), GAME_Chex, "mapinfo/chex3.txt" },
|
||||
{ "Chex(R) Quest 3", "Chex3", MAKERGB(255,255,0), MAKERGB(0,192,0), GAME_Chex, "mapinfo/chex3.txt", GI_NOTEXTCOLOR },
|
||||
{ "Action Doom 2: Urban Brawl", "UrbanBrawl",MAKERGB(168,168,0), MAKERGB(168,0,0), GAME_Doom, "mapinfo/doom2.txt", GI_MAPxx },
|
||||
{ "Harmony", "Harmony", MAKERGB(110,180,230), MAKERGB(69,79,126), GAME_Doom, "mapinfo/doom2.txt", GI_MAPxx },
|
||||
//{ "ZDoom Engine", NULL, MAKERGB(168,0,0), MAKERGB(168,168,168) },
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
#endif
|
||||
#include <float.h>
|
||||
|
||||
#ifdef unix
|
||||
#if defined(unix) || defined(__APPLE__)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
|
@ -61,7 +61,7 @@
|
|||
#include "f_wipe.h"
|
||||
#include "m_argv.h"
|
||||
#include "m_misc.h"
|
||||
#include "m_menu.h"
|
||||
#include "menu/menu.h"
|
||||
#include "c_console.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "i_system.h"
|
||||
|
@ -104,6 +104,7 @@
|
|||
#include "compatibility.h"
|
||||
#include "m_joy.h"
|
||||
#include "sc_man.h"
|
||||
#include "po_man.h"
|
||||
#include "resourcefiles/resourcefile.h"
|
||||
|
||||
EXTERN_CVAR(Bool, hud_althud)
|
||||
|
@ -200,6 +201,7 @@ gamestate_t wipegamestate = GS_DEMOSCREEN; // can be -1 to force a wipe
|
|||
bool PageBlank;
|
||||
FTexture *Page;
|
||||
FTexture *Advisory;
|
||||
bool nospriterename;
|
||||
|
||||
cycle_t FrameCycles;
|
||||
|
||||
|
@ -390,6 +392,18 @@ CVAR (Flag, sv_nofov, dmflags, DF_NO_FOV);
|
|||
CVAR (Flag, sv_noweaponspawn, dmflags, DF_NO_COOP_WEAPON_SPAWN);
|
||||
CVAR (Flag, sv_nocrouch, dmflags, DF_NO_CROUCH);
|
||||
CVAR (Flag, sv_allowcrouch, dmflags, DF_YES_CROUCH);
|
||||
CVAR (Flag, sv_cooploseinventory, dmflags, DF_COOP_LOSE_INVENTORY);
|
||||
CVAR (Flag, sv_cooplosekeys, dmflags, DF_COOP_LOSE_KEYS);
|
||||
CVAR (Flag, sv_cooploseweapons, dmflags, DF_COOP_LOSE_WEAPONS);
|
||||
CVAR (Flag, sv_cooplosearmor, dmflags, DF_COOP_LOSE_ARMOR);
|
||||
CVAR (Flag, sv_cooplosepowerups, dmflags, DF_COOP_LOSE_POWERUPS);
|
||||
CVAR (Flag, sv_cooploseammo, dmflags, DF_COOP_LOSE_AMMO);
|
||||
CVAR (Flag, sv_coophalveammo, dmflags, DF_COOP_HALVE_AMMO);
|
||||
|
||||
// Some (hopefully cleaner) interface to these settings.
|
||||
CVAR (Mask, sv_crouch, dmflags, DF_NO_CROUCH|DF_YES_CROUCH);
|
||||
CVAR (Mask, sv_jump, dmflags, DF_NO_JUMP|DF_YES_JUMP);
|
||||
CVAR (Mask, sv_fallingdamage, dmflags, DF_FORCE_FALLINGHX|DF_FORCE_FALLINGZD);
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -460,7 +474,6 @@ CVAR (Flag, sv_disallowsuicide, dmflags2, DF2_NOSUICIDE);
|
|||
CVAR (Flag, sv_noautoaim, dmflags2, DF2_NOAUTOAIM);
|
||||
CVAR (Flag, sv_dontcheckammo, dmflags2, DF2_DONTCHECKAMMO);
|
||||
CVAR (Flag, sv_killbossmonst, dmflags2, DF2_KILLBOSSMONST);
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// CVAR compatflags
|
||||
|
@ -480,7 +493,12 @@ static int GetCompatibility(int mask)
|
|||
|
||||
CUSTOM_CVAR (Int, compatflags, 0, CVAR_ARCHIVE|CVAR_SERVERINFO)
|
||||
{
|
||||
int old = i_compatflags;
|
||||
i_compatflags = GetCompatibility(self) | ii_compatflags;
|
||||
if ((old ^i_compatflags) & COMPATF_POLYOBJ)
|
||||
{
|
||||
FPolyObj::ClearAllSubsectorLinks();
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL)
|
||||
|
@ -559,6 +577,7 @@ CVAR (Flag, compat_noblockfriends,compatflags,COMPATF_NOBLOCKFRIENDS);
|
|||
CVAR (Flag, compat_spritesort, compatflags,COMPATF_SPRITESORT);
|
||||
CVAR (Flag, compat_hitscan, compatflags,COMPATF_HITSCAN);
|
||||
CVAR (Flag, compat_light, compatflags,COMPATF_LIGHT);
|
||||
CVAR (Flag, compat_polyobj, compatflags,COMPATF_POLYOBJ);
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -880,6 +899,8 @@ void D_DoomLoop ()
|
|||
// Clamp the timer to TICRATE until the playloop has been entered.
|
||||
r_NoInterpolate = true;
|
||||
|
||||
I_SetCursor(TexMan["cursor"]);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
try
|
||||
|
@ -1671,6 +1692,10 @@ static FString ParseGameInfo(TArray<FString> &pwads, const char *fn, const char
|
|||
}
|
||||
while (sc.CheckToken(','));
|
||||
}
|
||||
else if (!nextKey.CompareNoCase("NOSPRITERENAME"))
|
||||
{
|
||||
nospriterename = true;
|
||||
}
|
||||
}
|
||||
return iwad;
|
||||
}
|
||||
|
@ -2065,6 +2090,7 @@ void D_DoomMain (void)
|
|||
// [GRB] Initialize player class list
|
||||
SetupPlayerClasses ();
|
||||
|
||||
|
||||
// [RH] Load custom key and weapon settings from WADs
|
||||
D_LoadWadSettings ();
|
||||
|
||||
|
@ -2134,7 +2160,7 @@ void D_DoomMain (void)
|
|||
bglobal.spawn_tries = 0;
|
||||
bglobal.wanted_botnum = bglobal.getspawned.Size();
|
||||
|
||||
Printf ("M_Init: Init miscellaneous info.\n");
|
||||
Printf ("M_Init: Init menus.\n");
|
||||
M_Init ();
|
||||
|
||||
Printf ("P_Init: Init Playloop state.\n");
|
||||
|
@ -2287,6 +2313,14 @@ void FStartupScreen::AppendStatusLine(const char *status)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// STAT fps
|
||||
//
|
||||
// Displays statistics about rendering times
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
ADD_STAT (fps)
|
||||
{
|
||||
FString out;
|
||||
|
@ -2295,6 +2329,24 @@ ADD_STAT (fps)
|
|||
return out;
|
||||
}
|
||||
|
||||
|
||||
static double f_acc, w_acc,p_acc,m_acc;
|
||||
static int acc_c;
|
||||
|
||||
ADD_STAT (fps_accumulated)
|
||||
{
|
||||
f_acc += FrameCycles.TimeMS();
|
||||
w_acc += WallCycles.TimeMS();
|
||||
p_acc += PlaneCycles.TimeMS();
|
||||
m_acc += MaskedCycles.TimeMS();
|
||||
acc_c++;
|
||||
FString out;
|
||||
out.Format("frame=%04.1f ms walls=%04.1f ms planes=%04.1f ms masked=%04.1f ms %d counts",
|
||||
f_acc/acc_c, w_acc/acc_c, p_acc/acc_c, m_acc/acc_c, acc_c);
|
||||
Printf(PRINT_LOG, "%s\n", out.GetChars());
|
||||
return out;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// STAT wallcycles
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include <stddef.h>
|
||||
|
||||
#include "version.h"
|
||||
#include "m_menu.h"
|
||||
#include "menu/menu.h"
|
||||
#include "m_random.h"
|
||||
#include "i_system.h"
|
||||
#include "i_video.h"
|
||||
|
@ -1917,6 +1917,22 @@ BYTE *FDynamicBuffer::GetData (int *len)
|
|||
}
|
||||
|
||||
|
||||
static int KillAll(const PClass *cls)
|
||||
{
|
||||
AActor *actor;
|
||||
int killcount = 0;
|
||||
TThinkerIterator<AActor> iterator(cls);
|
||||
while ( (actor = iterator.Next ()) )
|
||||
{
|
||||
if (actor->IsA(cls))
|
||||
{
|
||||
if (!(actor->flags2 & MF2_DORMANT) && (actor->flags3 & MF3_ISMONSTER))
|
||||
killcount += actor->Massacre ();
|
||||
}
|
||||
}
|
||||
return killcount;
|
||||
|
||||
}
|
||||
// [RH] Execute a special "ticcmd". The type byte should
|
||||
// have already been read, and the stream is positioned
|
||||
// at the beginning of the command's actual data.
|
||||
|
@ -2348,22 +2364,25 @@ void Net_DoCommand (int type, BYTE **stream, int player)
|
|||
|
||||
case DEM_KILLCLASSCHEAT:
|
||||
{
|
||||
AActor *actor;
|
||||
TThinkerIterator<AActor> iterator;
|
||||
|
||||
char *classname = ReadString (stream);
|
||||
int killcount = 0;
|
||||
const PClass *cls = PClass::FindClass(classname);
|
||||
|
||||
while ( (actor = iterator.Next ()) )
|
||||
if (cls != NULL && cls->ActorInfo != NULL)
|
||||
{
|
||||
if (!stricmp (actor->GetClass ()->TypeName.GetChars (), classname))
|
||||
killcount = KillAll(cls);
|
||||
const PClass *cls_rep = cls->GetReplacement();
|
||||
if (cls != cls_rep)
|
||||
{
|
||||
if (!(actor->flags2 & MF2_DORMANT) && (actor->flags3 & MF3_ISMONSTER))
|
||||
killcount += actor->Massacre ();
|
||||
killcount += KillAll(cls_rep);
|
||||
}
|
||||
Printf ("Killed %d monsters of type %s.\n",killcount, classname);
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf ("%s is not an actor class.\n", classname);
|
||||
}
|
||||
|
||||
Printf ("Killed %d monsters of type %s.\n",killcount, classname);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ enum
|
|||
APMETA_ColorRange, // skin color range
|
||||
APMETA_InvulMode,
|
||||
APMETA_HealingRadius,
|
||||
APMETA_Portrait,
|
||||
APMETA_Hexenarmor0,
|
||||
APMETA_Hexenarmor1,
|
||||
APMETA_Hexenarmor2,
|
||||
|
|
|
@ -188,6 +188,33 @@ const char *FMetaTable::GetMetaString (DWORD id) const
|
|||
return meta != NULL ? meta->Value.String : NULL;
|
||||
}
|
||||
|
||||
CCMD (dumpactors)
|
||||
{
|
||||
const char *const filters[32] =
|
||||
{
|
||||
"0:All", "1:Doom", "2:Heretic", "3:DoomHeretic", "4:Hexen", "5:DoomHexen", "6:Raven", "7:IdRaven",
|
||||
"8:Strife", "9:DoomStrife", "10:HereticStrife", "11:DoomHereticStrife", "12:HexenStrife",
|
||||
"13:DoomHexenStrife", "14:RavenStrife", "15:NotChex", "16:Chex", "17:DoomChex", "18:HereticChex",
|
||||
"19:DoomHereticChex", "20:HexenChex", "21:DoomHexenChex", "22:RavenChex", "23:NotStrife", "24:StrifeChex",
|
||||
"25:DoomStrifeChex", "26:HereticStrifeChex", "27:NotHexen", "28:HexenStrifeChex", "29:NotHeretic",
|
||||
"30:NotDoom", "31:All",
|
||||
};
|
||||
Printf("%i object class types total\nActor\tEd Num\tSpawnID\tFilter\tSource\n", PClass::m_Types.Size());
|
||||
for (unsigned int i = 0; i < PClass::m_Types.Size(); i++)
|
||||
{
|
||||
PClass *cls = PClass::m_Types[i];
|
||||
if (cls != NULL && cls->ActorInfo != NULL)
|
||||
Printf("%s\t%i\t%i\t%s\t%s\n",
|
||||
cls->TypeName.GetChars(), cls->ActorInfo->DoomEdNum,
|
||||
cls->ActorInfo->SpawnID, filters[cls->ActorInfo->GameFilter & 31],
|
||||
cls->Meta.GetMetaString (ACMETA_Lump));
|
||||
else if (cls != NULL)
|
||||
Printf("%s\tn/a\tn/a\tn/a\tEngine (not an actor type)\n", cls->TypeName.GetChars());
|
||||
else
|
||||
Printf("Type %i is not an object class\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
CCMD (dumpclasses)
|
||||
{
|
||||
// This is by no means speed-optimized. But it's an informational console
|
||||
|
|
|
@ -71,6 +71,8 @@
|
|||
#include "r_interpolate.h"
|
||||
#include "doomstat.h"
|
||||
#include "m_argv.h"
|
||||
#include "po_man.h"
|
||||
#include "menu/menu.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
@ -297,6 +299,7 @@ static void MarkRoot()
|
|||
Mark(Args);
|
||||
Mark(screen);
|
||||
Mark(StatusBar);
|
||||
Mark(DMenu::CurrentMenu);
|
||||
DThinker::MarkRoots();
|
||||
FCanvasTextureInfo::Mark();
|
||||
Mark(DACSThinker::ActiveThinker);
|
||||
|
|
|
@ -68,7 +68,7 @@ void PClass::StaticInit ()
|
|||
// MinGW's linker is linking the object files backwards for me now...
|
||||
if (head > tail)
|
||||
{
|
||||
swap (head, tail);
|
||||
swapvalues (head, tail);
|
||||
}
|
||||
qsort (head + 1, tail - head - 1, sizeof(REGINFO), cregcmp);
|
||||
|
||||
|
@ -486,6 +486,11 @@ const PClass *PClass::NativeClass() const
|
|||
return cls;
|
||||
}
|
||||
|
||||
PClass *PClass::GetReplacement() const
|
||||
{
|
||||
return ActorInfo->GetReplacement()->Class;
|
||||
}
|
||||
|
||||
// Symbol tables ------------------------------------------------------------
|
||||
|
||||
PSymbol::~PSymbol()
|
||||
|
|
|
@ -174,6 +174,7 @@ struct PClass
|
|||
static const PClass *FindClass (ENamedName name) { return FindClass (FName (name)); }
|
||||
static const PClass *FindClass (FName name);
|
||||
const PClass *FindClassTentative (FName name); // not static!
|
||||
PClass *GetReplacement() const;
|
||||
|
||||
static TArray<PClass *> m_Types;
|
||||
static TArray<PClass *> m_RuntimeActors;
|
||||
|
|
|
@ -340,6 +340,7 @@ struct FMapThing
|
|||
DWORD flags;
|
||||
int special;
|
||||
int args[5];
|
||||
int Conversation;
|
||||
|
||||
void Serialize (FArchive &);
|
||||
};
|
||||
|
|
|
@ -329,6 +329,7 @@ enum
|
|||
COMPATF_SPRITESORT = 1 << 27, // Invert sprite sorting order for sprites of equal distance
|
||||
COMPATF_HITSCAN = 1 << 28, // Hitscans use original blockmap anf hit check code.
|
||||
COMPATF_LIGHT = 1 << 29, // Find neighboring light level like Doom
|
||||
COMPATF_POLYOBJ = 1 << 30, // Draw polyobjects the old fashioned way
|
||||
};
|
||||
|
||||
// Emulate old bugs for select maps. These are not exposed by a cvar
|
||||
|
|
|
@ -44,12 +44,6 @@
|
|||
|
||||
// Since this file is included by everything, it seems an appropriate place
|
||||
// to check the NOASM/USEASM macros.
|
||||
#if defined(__APPLE__)
|
||||
// The assembly code needs to be tweaked for Mach-O before enabled on Macs.
|
||||
#ifndef NOASM
|
||||
#define NOASM
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// There are three assembly-related macros:
|
||||
//
|
||||
|
|
|
@ -723,7 +723,7 @@ bool F_CastResponder (event_t* ev)
|
|||
if (ev->type != EV_KeyDown)
|
||||
return false;
|
||||
|
||||
const char *cmd = C_GetBinding (ev->data1);
|
||||
const char *cmd = Bindings.GetBind (ev->data1);
|
||||
|
||||
if (cmd != NULL && !stricmp (cmd, "toggleconsole"))
|
||||
return false;
|
||||
|
|
|
@ -290,6 +290,10 @@ template<> inline FArchive &operator<< <FFont> (FArchive &arc, FFont* &font)
|
|||
return SerializeFFontPtr (arc, font);
|
||||
}
|
||||
|
||||
struct FStrifeDialogueNode;
|
||||
template<> FArchive &operator<< (FArchive &arc, FStrifeDialogueNode *&node);
|
||||
|
||||
|
||||
|
||||
template<class T,class TT>
|
||||
inline FArchive &operator<< (FArchive &arc, TArray<T,TT> &self)
|
||||
|
|
|
@ -132,6 +132,8 @@ long FileReader::Seek (long offset, int origin)
|
|||
|
||||
long FileReader::Read (void *buffer, long len)
|
||||
{
|
||||
assert(len >= 0);
|
||||
if (len <= 0) return 0;
|
||||
if (FilePos + len > StartPos + Length)
|
||||
{
|
||||
len = Length - FilePos + StartPos;
|
||||
|
|
|
@ -100,52 +100,88 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePistol)
|
|||
//
|
||||
// A_Saw
|
||||
//
|
||||
enum SAW_Flags
|
||||
{
|
||||
SF_NORANDOM = 1,
|
||||
SF_RANDOMLIGHTMISS = 2,
|
||||
SF_RANDOMLIGHTHIT = 4,
|
||||
SF_NOUSEAMMOMISS = 8,
|
||||
SF_NOUSEAMMO = 16,
|
||||
};
|
||||
|
||||
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw)
|
||||
{
|
||||
angle_t angle;
|
||||
angle_t angle;
|
||||
angle_t slope;
|
||||
player_t *player;
|
||||
AActor *linetarget;
|
||||
|
||||
ACTION_PARAM_START(4);
|
||||
ACTION_PARAM_START(9);
|
||||
ACTION_PARAM_SOUND(fullsound, 0);
|
||||
ACTION_PARAM_SOUND(hitsound, 1);
|
||||
ACTION_PARAM_INT(damage, 2);
|
||||
ACTION_PARAM_CLASS(pufftype, 3);
|
||||
ACTION_PARAM_FIXED(Range, 4)
|
||||
ACTION_PARAM_FIXED(LifeSteal, 5);
|
||||
ACTION_PARAM_INT(Flags, 4);
|
||||
ACTION_PARAM_FIXED(Range, 5);
|
||||
ACTION_PARAM_ANGLE(Spread_XY, 6);
|
||||
ACTION_PARAM_ANGLE(Spread_Z, 7);
|
||||
ACTION_PARAM_FIXED(LifeSteal, 8);
|
||||
|
||||
if (NULL == (player = self->player))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (pufftype == NULL) pufftype = PClass::FindClass(NAME_BulletPuff);
|
||||
if (damage == 0) damage = 2;
|
||||
|
||||
if (!(Flags & SF_NORANDOM))
|
||||
damage *= (pr_saw()%10+1);
|
||||
|
||||
// use meleerange + 1 so the puff doesn't skip the flash (i.e. plays all states)
|
||||
if (Range == 0) Range = MELEERANGE+1;
|
||||
|
||||
angle = self->angle + (pr_saw.Random2() * (Spread_XY / 255));
|
||||
slope = P_AimLineAttack (self, angle, Range, &linetarget) + (pr_saw.Random2() * (Spread_Z / 255));
|
||||
|
||||
P_LineAttack (self, angle, Range,
|
||||
slope, damage,
|
||||
NAME_None, pufftype);
|
||||
|
||||
AWeapon *weapon = self->player->ReadyWeapon;
|
||||
if (weapon != NULL)
|
||||
if ((weapon != NULL) && !(Flags & SF_NOUSEAMMO) && !(!linetarget && (Flags & SF_NOUSEAMMOMISS)))
|
||||
{
|
||||
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
||||
return;
|
||||
}
|
||||
|
||||
if (pufftype == NULL) pufftype = PClass::FindClass(NAME_BulletPuff);
|
||||
if (damage == 0) damage = 2;
|
||||
|
||||
damage *= (pr_saw()%10+1);
|
||||
angle = self->angle;
|
||||
angle += pr_saw.Random2() << 18;
|
||||
|
||||
// use meleerange + 1 so the puff doesn't skip the flash (i.e. plays all states)
|
||||
if (Range == 0) Range = MELEERANGE+1;
|
||||
|
||||
P_LineAttack (self, angle, Range,
|
||||
P_AimLineAttack (self, angle, Range, &linetarget), damage,
|
||||
NAME_None, pufftype);
|
||||
|
||||
if (!linetarget)
|
||||
{
|
||||
if ((Flags & SF_RANDOMLIGHTMISS) && (pr_saw() > 64))
|
||||
{
|
||||
player->extralight = !player->extralight;
|
||||
}
|
||||
S_Sound (self, CHAN_WEAPON, fullsound, 1, ATTN_NORM);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Flags & SF_RANDOMLIGHTHIT)
|
||||
{
|
||||
int randVal = pr_saw();
|
||||
if (randVal < 64)
|
||||
{
|
||||
player->extralight = 0;
|
||||
}
|
||||
else if (randVal < 160)
|
||||
{
|
||||
player->extralight = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
player->extralight = 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (LifeSteal)
|
||||
P_GiveBody (self, (damage * LifeSteal) >> FRACBITS);
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
#include "f_finale.h"
|
||||
#include "m_argv.h"
|
||||
#include "m_misc.h"
|
||||
#include "m_menu.h"
|
||||
#include "menu/menu.h"
|
||||
#include "m_random.h"
|
||||
#include "m_crc32.h"
|
||||
#include "i_system.h"
|
||||
|
@ -116,18 +116,20 @@ EXTERN_CVAR (Float, con_midtime);
|
|||
//
|
||||
// CVAR displaynametags
|
||||
//
|
||||
// Selects whether to display name tags or not when changing weapons
|
||||
// Selects whether to display name tags or not when changing weapons/items
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
CUSTOM_CVAR (Bool, displaynametags, 0, CVAR_ARCHIVE)
|
||||
CUSTOM_CVAR (Int, displaynametags, 0, CVAR_ARCHIVE)
|
||||
{
|
||||
if (self != 0 && self != 1)
|
||||
if (self < 0 || self > 3)
|
||||
{
|
||||
self = 0;
|
||||
}
|
||||
}
|
||||
|
||||
CVAR(Int, nametagcolor, CR_GOLD, CVAR_ARCHIVE)
|
||||
|
||||
|
||||
gameaction_t gameaction;
|
||||
gamestate_t gamestate = GS_STARTUP;
|
||||
|
@ -322,11 +324,23 @@ CCMD (turn180)
|
|||
CCMD (weapnext)
|
||||
{
|
||||
SendItemUse = players[consoleplayer].weapons.PickNextWeapon (&players[consoleplayer]);
|
||||
// [BC] Option to display the name of the weapon being cycled to.
|
||||
if ((displaynametags & 2) && StatusBar && SmallFont && SendItemUse)
|
||||
{
|
||||
StatusBar->AttachMessage(new DHUDMessageFadeOut(SmallFont, SendItemUse->GetTag(),
|
||||
1.5f, 0.90f, 0, 0, (EColorRange)*nametagcolor, 2.f, 0.35f), MAKE_ID( 'W', 'E', 'P', 'N' ));
|
||||
}
|
||||
}
|
||||
|
||||
CCMD (weapprev)
|
||||
{
|
||||
SendItemUse = players[consoleplayer].weapons.PickPrevWeapon (&players[consoleplayer]);
|
||||
// [BC] Option to display the name of the weapon being cycled to.
|
||||
if ((displaynametags & 2) && StatusBar && SmallFont && SendItemUse)
|
||||
{
|
||||
StatusBar->AttachMessage(new DHUDMessageFadeOut(SmallFont, SendItemUse->GetTag(),
|
||||
1.5f, 0.90f, 0, 0, (EColorRange)*nametagcolor, 2.f, 0.35f), MAKE_ID( 'W', 'E', 'P', 'N' ));
|
||||
}
|
||||
}
|
||||
|
||||
CCMD (invnext)
|
||||
|
@ -354,10 +368,9 @@ CCMD (invnext)
|
|||
who->InvSel = who->Inventory;
|
||||
}
|
||||
}
|
||||
if (displaynametags && StatusBar && SmallFont
|
||||
&& gamestate == GS_LEVEL && level.time > con_midtime && who->InvSel)
|
||||
StatusBar->AttachMessage (new DHUDMessage (SmallFont, who->InvSel->GetTag(),
|
||||
2.5f, 0.375f, 0, 0, CR_YELLOW, con_midtime), MAKE_ID('S','I','N','V'));
|
||||
if ((displaynametags & 1) && StatusBar && SmallFont && who->InvSel)
|
||||
StatusBar->AttachMessage (new DHUDMessageFadeOut (SmallFont, who->InvSel->GetTag(),
|
||||
1.5f, 0.80f, 0, 0, (EColorRange)*nametagcolor, 2.f, 0.35f), MAKE_ID('S','I','N','V'));
|
||||
}
|
||||
who->player->inventorytics = 5*TICRATE;
|
||||
}
|
||||
|
@ -385,10 +398,9 @@ CCMD (invprev)
|
|||
}
|
||||
who->InvSel = item;
|
||||
}
|
||||
if (displaynametags && StatusBar && SmallFont
|
||||
&& gamestate == GS_LEVEL && level.time > con_midtime && who->InvSel)
|
||||
StatusBar->AttachMessage (new DHUDMessage (SmallFont, who->InvSel->GetTag(),
|
||||
2.5f, 0.375f, 0, 0, CR_YELLOW, con_midtime), MAKE_ID('S','I','N','V'));
|
||||
if ((displaynametags & 1) && StatusBar && SmallFont && who->InvSel)
|
||||
StatusBar->AttachMessage (new DHUDMessageFadeOut (SmallFont, who->InvSel->GetTag(),
|
||||
1.5f, 0.80f, 0, 0, (EColorRange)*nametagcolor, 2.f, 0.35f), MAKE_ID('S','I','N','V'));
|
||||
}
|
||||
who->player->inventorytics = 5*TICRATE;
|
||||
}
|
||||
|
@ -869,7 +881,7 @@ bool G_Responder (event_t *ev)
|
|||
if (gameaction == ga_nothing &&
|
||||
(demoplayback || gamestate == GS_DEMOSCREEN || gamestate == GS_TITLELEVEL))
|
||||
{
|
||||
const char *cmd = C_GetBinding (ev->data1);
|
||||
const char *cmd = Bindings.GetBind (ev->data1);
|
||||
|
||||
if (ev->type == EV_KeyDown)
|
||||
{
|
||||
|
@ -887,16 +899,17 @@ bool G_Responder (event_t *ev)
|
|||
stricmp (cmd, "bumpgamma") &&
|
||||
stricmp (cmd, "screenshot")))
|
||||
{
|
||||
M_StartControlPanel (true, true);
|
||||
M_StartControlPanel(true);
|
||||
M_SetMenu(NAME_Mainmenu, -1);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return C_DoKey (ev);
|
||||
return C_DoKey (ev, &Bindings, &DoubleBindings);
|
||||
}
|
||||
}
|
||||
if (cmd && cmd[0] == '+')
|
||||
return C_DoKey (ev);
|
||||
return C_DoKey (ev, &Bindings, &DoubleBindings);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -908,7 +921,7 @@ bool G_Responder (event_t *ev)
|
|||
{
|
||||
if (ST_Responder (ev))
|
||||
return true; // status window ate it
|
||||
if (!viewactive && AM_Responder (ev))
|
||||
if (!viewactive && AM_Responder (ev, false))
|
||||
return true; // automap ate it
|
||||
}
|
||||
else if (gamestate == GS_FINALE)
|
||||
|
@ -920,12 +933,12 @@ bool G_Responder (event_t *ev)
|
|||
switch (ev->type)
|
||||
{
|
||||
case EV_KeyDown:
|
||||
if (C_DoKey (ev))
|
||||
if (C_DoKey (ev, &Bindings, &DoubleBindings))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case EV_KeyUp:
|
||||
C_DoKey (ev);
|
||||
C_DoKey (ev, &Bindings, &DoubleBindings);
|
||||
break;
|
||||
|
||||
// [RH] mouse buttons are sent as key up/down events
|
||||
|
@ -939,7 +952,7 @@ bool G_Responder (event_t *ev)
|
|||
// the events *last* so that any bound keys get precedence.
|
||||
|
||||
if (gamestate == GS_LEVEL && viewactive)
|
||||
return AM_Responder (ev);
|
||||
return AM_Responder (ev, true);
|
||||
|
||||
return (ev->type == EV_KeyDown ||
|
||||
ev->type == EV_Mouse);
|
||||
|
@ -2050,11 +2063,11 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
|
|||
M_AppendPNGChunk (stdfile, MAKE_ID('s','n','X','t'), &next, 1);
|
||||
}
|
||||
|
||||
M_NotifyNewSave (filename.GetChars(), description, okForQuicksave);
|
||||
|
||||
M_FinishPNG (stdfile);
|
||||
fclose (stdfile);
|
||||
|
||||
M_NotifyNewSave (filename.GetChars(), description, okForQuicksave);
|
||||
|
||||
// Check whether the file is ok.
|
||||
bool success = false;
|
||||
stdfile = fopen (filename.GetChars(), "rb");
|
||||
|
|
|
@ -139,7 +139,7 @@ void P_DSparilTeleport (AActor *actor)
|
|||
DSpotState *state = DSpotState::GetSpotState();
|
||||
if (state == NULL) return;
|
||||
|
||||
spot = state->GetSpotWithMinDistance(PClass::FindClass("BossSpot"), actor->x, actor->y, 128*FRACUNIT);
|
||||
spot = state->GetSpotWithMinMaxDistance(PClass::FindClass("BossSpot"), actor->x, actor->y, 128*FRACUNIT, 0);
|
||||
if (spot == NULL) return;
|
||||
|
||||
prevX = actor->x;
|
||||
|
|
|
@ -68,7 +68,6 @@
|
|||
#include "m_png.h"
|
||||
#include "m_random.h"
|
||||
#include "version.h"
|
||||
#include "m_menu.h"
|
||||
#include "statnums.h"
|
||||
#include "sbarinfo.h"
|
||||
#include "r_translate.h"
|
||||
|
@ -78,6 +77,7 @@
|
|||
#include "d_net.h"
|
||||
#include "d_netinf.h"
|
||||
#include "v_palette.h"
|
||||
#include "menu/menu.h"
|
||||
|
||||
#include "gi.h"
|
||||
|
||||
|
@ -99,6 +99,7 @@ void STAT_WRITE(FILE *f);
|
|||
EXTERN_CVAR (Float, sv_gravity)
|
||||
EXTERN_CVAR (Float, sv_aircontrol)
|
||||
EXTERN_CVAR (Int, disableautosave)
|
||||
EXTERN_CVAR (String, playerclass)
|
||||
|
||||
#define SNAP_ID MAKE_ID('s','n','A','p')
|
||||
#define DSNP_ID MAKE_ID('d','s','N','p')
|
||||
|
@ -230,6 +231,15 @@ void G_DeferedInitNew (const char *mapname, int newskill)
|
|||
gameaction = ga_newgame2;
|
||||
}
|
||||
|
||||
void G_DeferedInitNew (FGameStartup *gs)
|
||||
{
|
||||
playerclass = gs->PlayerClass;
|
||||
d_mapname = AllEpisodes[gs->Episode].mEpisodeMap;
|
||||
d_skill = gs->Skill;
|
||||
CheckWarpTransMap (d_mapname, true);
|
||||
gameaction = ga_newgame2;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
@ -1464,8 +1474,8 @@ void G_SerializeLevel (FArchive &arc, bool hubLoad)
|
|||
P_SerializeThinkers (arc, hubLoad);
|
||||
P_SerializeWorld (arc);
|
||||
P_SerializePolyobjs (arc);
|
||||
P_SerializeSubsectors(arc);
|
||||
StatusBar->Serialize (arc);
|
||||
//SerializeInterpolations (arc);
|
||||
|
||||
arc << level.total_monsters << level.total_items << level.total_secrets;
|
||||
|
||||
|
|
|
@ -486,6 +486,8 @@ void G_InitNew (const char *mapname, bool bTitleLevel);
|
|||
// A normal game starts at map 1,
|
||||
// but a warp test can start elsewhere
|
||||
void G_DeferedInitNew (const char *mapname, int skill = -1);
|
||||
struct FGameStartup;
|
||||
void G_DeferedInitNew (FGameStartup *gs);
|
||||
|
||||
void G_ExitLevel (int position, bool keepFacing);
|
||||
void G_SecretExitLevel (int position);
|
||||
|
@ -548,7 +550,8 @@ enum ESkillProperty
|
|||
SKILLP_ACSReturn,
|
||||
SKILLP_MonsterHealth,
|
||||
SKILLP_FriendlyHealth,
|
||||
SKILLP_NoPain
|
||||
SKILLP_NoPain,
|
||||
SKILLP_ArmorFactor
|
||||
};
|
||||
int G_SkillProperty(ESkillProperty prop);
|
||||
const char * G_SkillName();
|
||||
|
@ -583,6 +586,7 @@ struct FSkillInfo
|
|||
fixed_t MonsterHealth;
|
||||
fixed_t FriendlyHealth;
|
||||
bool NoPain;
|
||||
fixed_t ArmorFactor;
|
||||
|
||||
FSkillInfo() {}
|
||||
FSkillInfo(const FSkillInfo &other)
|
||||
|
@ -601,6 +605,16 @@ struct FSkillInfo
|
|||
extern TArray<FSkillInfo> AllSkills;
|
||||
extern int DefaultSkill;
|
||||
|
||||
struct FEpisode
|
||||
{
|
||||
FString mEpisodeName;
|
||||
FString mEpisodeMap;
|
||||
FString mPicName;
|
||||
char mShortcut;
|
||||
bool mNoSkill;
|
||||
};
|
||||
|
||||
extern TArray<FEpisode> AllEpisodes;
|
||||
|
||||
|
||||
#endif //__G_LEVEL_H__
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
#include "g_level.h"
|
||||
#include "sc_man.h"
|
||||
#include "w_wad.h"
|
||||
#include "m_menu.h"
|
||||
#include "cmdlib.h"
|
||||
#include "v_video.h"
|
||||
#include "p_lnspec.h"
|
||||
|
@ -63,6 +62,8 @@ TArray<level_info_t> wadlevelinfos;
|
|||
level_info_t TheDefaultLevelInfo;
|
||||
static cluster_info_t TheDefaultClusterInfo;
|
||||
|
||||
TArray<FEpisode> AllEpisodes;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
@ -1404,6 +1405,7 @@ MapFlagHandlers[] =
|
|||
{ "compat_noblockfriends", MITYPE_COMPATFLAG, COMPATF_NOBLOCKFRIENDS},
|
||||
{ "compat_spritesort", MITYPE_COMPATFLAG, COMPATF_SPRITESORT},
|
||||
{ "compat_light", MITYPE_COMPATFLAG, COMPATF_LIGHT},
|
||||
{ "compat_polyobj", MITYPE_COMPATFLAG, COMPATF_POLYOBJ},
|
||||
{ "cd_start_track", MITYPE_EATNEXT, 0, 0 },
|
||||
{ "cd_end1_track", MITYPE_EATNEXT, 0, 0 },
|
||||
{ "cd_end2_track", MITYPE_EATNEXT, 0, 0 },
|
||||
|
@ -1654,10 +1656,10 @@ level_info_t *FMapInfoParser::ParseMapHeader(level_info_t &defaultinfo)
|
|||
|
||||
void FMapInfoParser::ParseEpisodeInfo ()
|
||||
{
|
||||
int i;
|
||||
unsigned int i;
|
||||
char map[9];
|
||||
char *pic = NULL;
|
||||
bool picisgfx = false; // Shut up, GCC!!!!
|
||||
FString pic;
|
||||
FString name;
|
||||
bool remove = false;
|
||||
char key = 0;
|
||||
bool noskill = false;
|
||||
|
@ -1696,15 +1698,13 @@ void FMapInfoParser::ParseEpisodeInfo ()
|
|||
{
|
||||
ParseAssign();
|
||||
sc.MustGetString ();
|
||||
ReplaceString (&pic, sc.String);
|
||||
picisgfx = false;
|
||||
name = sc.String;
|
||||
}
|
||||
else if (sc.Compare ("picname"))
|
||||
{
|
||||
ParseAssign();
|
||||
sc.MustGetString ();
|
||||
ReplaceString (&pic, sc.String);
|
||||
picisgfx = true;
|
||||
pic = sc.String;
|
||||
}
|
||||
else if (sc.Compare ("remove"))
|
||||
{
|
||||
|
@ -1750,9 +1750,9 @@ void FMapInfoParser::ParseEpisodeInfo ()
|
|||
}
|
||||
|
||||
|
||||
for (i = 0; i < EpiDef.numitems; ++i)
|
||||
for (i = 0; i < AllEpisodes.Size(); i++)
|
||||
{
|
||||
if (strncmp (EpisodeMaps[i], map, 8) == 0)
|
||||
if (AllEpisodes[i].mEpisodeMap.CompareNoCase(map) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -1761,50 +1761,17 @@ void FMapInfoParser::ParseEpisodeInfo ()
|
|||
if (remove)
|
||||
{
|
||||
// If the remove property is given for an episode, remove it.
|
||||
if (i < EpiDef.numitems)
|
||||
{
|
||||
if (i+1 < EpiDef.numitems)
|
||||
{
|
||||
memmove (&EpisodeMaps[i], &EpisodeMaps[i+1],
|
||||
sizeof(EpisodeMaps[0])*(EpiDef.numitems - i - 1));
|
||||
memmove (&EpisodeMenu[i], &EpisodeMenu[i+1],
|
||||
sizeof(EpisodeMenu[0])*(EpiDef.numitems - i - 1));
|
||||
memmove (&EpisodeNoSkill[i], &EpisodeNoSkill[i+1],
|
||||
sizeof(EpisodeNoSkill[0])*(EpiDef.numitems - i - 1));
|
||||
}
|
||||
EpiDef.numitems--;
|
||||
}
|
||||
AllEpisodes.Delete(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pic == NULL)
|
||||
{
|
||||
pic = copystring (map);
|
||||
picisgfx = false;
|
||||
}
|
||||
FEpisode *epi = &AllEpisodes[AllEpisodes.Reserve(1)];
|
||||
|
||||
if (i == EpiDef.numitems)
|
||||
{
|
||||
if (EpiDef.numitems == MAX_EPISODES)
|
||||
{
|
||||
i = EpiDef.numitems - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = EpiDef.numitems++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
delete[] const_cast<char *>(EpisodeMenu[i].name);
|
||||
}
|
||||
|
||||
EpisodeMenu[i].name = pic;
|
||||
EpisodeMenu[i].alphaKey = tolower(key);
|
||||
EpisodeMenu[i].fulltext = !picisgfx;
|
||||
EpisodeNoSkill[i] = noskill;
|
||||
strncpy (EpisodeMaps[i], map, 8);
|
||||
EpisodeMaps[i][8] = 0;
|
||||
epi->mEpisodeMap = map;
|
||||
epi->mEpisodeName = name;
|
||||
epi->mPicName = pic;
|
||||
epi->mShortcut = tolower(key);
|
||||
epi->mNoSkill = noskill;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1817,12 +1784,7 @@ void FMapInfoParser::ParseEpisodeInfo ()
|
|||
|
||||
void ClearEpisodes()
|
||||
{
|
||||
for (int i = 0; i < EpiDef.numitems; ++i)
|
||||
{
|
||||
delete[] const_cast<char *>(EpisodeMenu[i].name);
|
||||
EpisodeMenu[i].name = NULL;
|
||||
}
|
||||
EpiDef.numitems = 0;
|
||||
AllEpisodes.Clear();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -2003,7 +1965,7 @@ void G_ParseMapInfo (const char *basemapinfo)
|
|||
}
|
||||
EndSequences.ShrinkToFit ();
|
||||
|
||||
if (EpiDef.numitems == 0)
|
||||
if (AllEpisodes.Size() == 0)
|
||||
{
|
||||
I_FatalError ("You cannot use clearepisodes in a MAPINFO if you do not define any new episodes after it.");
|
||||
}
|
||||
|
|
|
@ -448,9 +448,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurRoam)
|
|||
{
|
||||
// Turn
|
||||
if (pr_minotaurroam() & 1)
|
||||
self->movedir = (++self->movedir)%8;
|
||||
self->movedir = (self->movedir + 1) % 8;
|
||||
else
|
||||
self->movedir = (self->movedir+7)%8;
|
||||
self->movedir = (self->movedir + 7) % 8;
|
||||
FaceMovementDirection (self);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ void A_Unblock(AActor *self, bool drop)
|
|||
|
||||
self->flags &= ~MF_SOLID;
|
||||
|
||||
// If the self has a conversation that sets an item to drop, drop that.
|
||||
// If the actor has a conversation that sets an item to drop, drop that.
|
||||
if (self->Conversation != NULL && self->Conversation->DropType != NULL)
|
||||
{
|
||||
P_DropItem (self, self->Conversation->DropType, -1, 256);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "r_data.h"
|
||||
#include "a_pickups.h"
|
||||
#include "templates.h"
|
||||
#include "g_level.h"
|
||||
|
||||
|
||||
IMPLEMENT_CLASS (AArmor)
|
||||
|
@ -84,6 +85,18 @@ bool ABasicArmor::HandlePickup (AInventory *item)
|
|||
// You shouldn't be picking up BasicArmor anyway.
|
||||
return true;
|
||||
}
|
||||
if (item->IsKindOf(RUNTIME_CLASS(ABasicArmorBonus)) && !(item->ItemFlags & IF_IGNORESKILL))
|
||||
{
|
||||
ABasicArmorBonus *armor = static_cast<ABasicArmorBonus*>(item);
|
||||
|
||||
armor->SaveAmount = FixedMul(armor->SaveAmount, G_SkillProperty(SKILLP_ArmorFactor));
|
||||
}
|
||||
else if (item->IsKindOf(RUNTIME_CLASS(ABasicArmorPickup)) && !(item->ItemFlags & IF_IGNORESKILL))
|
||||
{
|
||||
ABasicArmorPickup *armor = static_cast<ABasicArmorPickup*>(item);
|
||||
|
||||
armor->SaveAmount = FixedMul(armor->SaveAmount, G_SkillProperty(SKILLP_ArmorFactor));
|
||||
}
|
||||
if (Inventory != NULL)
|
||||
{
|
||||
return Inventory->HandlePickup (item);
|
||||
|
@ -198,10 +211,17 @@ void ABasicArmorPickup::Serialize (FArchive &arc)
|
|||
AInventory *ABasicArmorPickup::CreateCopy (AActor *other)
|
||||
{
|
||||
ABasicArmorPickup *copy = static_cast<ABasicArmorPickup *> (Super::CreateCopy (other));
|
||||
|
||||
if (!(ItemFlags & IF_IGNORESKILL))
|
||||
{
|
||||
SaveAmount = FixedMul(SaveAmount, G_SkillProperty(SKILLP_ArmorFactor));
|
||||
}
|
||||
|
||||
copy->SavePercent = SavePercent;
|
||||
copy->SaveAmount = SaveAmount;
|
||||
copy->MaxAbsorb = MaxAbsorb;
|
||||
copy->MaxFullAbsorb = MaxFullAbsorb;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
@ -272,6 +292,12 @@ void ABasicArmorBonus::Serialize (FArchive &arc)
|
|||
AInventory *ABasicArmorBonus::CreateCopy (AActor *other)
|
||||
{
|
||||
ABasicArmorBonus *copy = static_cast<ABasicArmorBonus *> (Super::CreateCopy (other));
|
||||
|
||||
if (!(ItemFlags & IF_IGNORESKILL))
|
||||
{
|
||||
SaveAmount = FixedMul(SaveAmount, G_SkillProperty(SKILLP_ArmorFactor));
|
||||
}
|
||||
|
||||
copy->SavePercent = SavePercent;
|
||||
copy->SaveAmount = SaveAmount;
|
||||
copy->MaxSaveAmount = MaxSaveAmount;
|
||||
|
@ -279,6 +305,7 @@ AInventory *ABasicArmorBonus::CreateCopy (AActor *other)
|
|||
copy->BonusMax = BonusMax;
|
||||
copy->MaxAbsorb = MaxAbsorb;
|
||||
copy->MaxFullAbsorb = MaxFullAbsorb;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
|
|
@ -1004,6 +1004,12 @@ void APowerFlight::EndEffect ()
|
|||
|
||||
bool APowerFlight::DrawPowerup (int x, int y)
|
||||
{
|
||||
// If this item got a valid icon use that instead of the default spinning wings.
|
||||
if (Icon.isValid())
|
||||
{
|
||||
return Super::DrawPowerup(x, y);
|
||||
}
|
||||
|
||||
if (EffectTics > BLINKTHRESHOLD || !(EffectTics & 16))
|
||||
{
|
||||
FTextureID picnum = TexMan.CheckForTexture ("SPFLY0", FTexture::TEX_MiscPatch);
|
||||
|
|
|
@ -72,7 +72,7 @@ void AFastProjectile::Tick ()
|
|||
tm.LastRipped = NULL; // [RH] Do rip damage each step, like Hexen
|
||||
}
|
||||
|
||||
if (!P_TryMove (this, x + xfrac,y + yfrac, true, false, tm))
|
||||
if (!P_TryMove (this, x + xfrac,y + yfrac, true, NULL, tm))
|
||||
{ // Blocked move
|
||||
if (!(flags3 & MF3_SKYEXPLODE))
|
||||
{
|
||||
|
@ -158,10 +158,13 @@ void AFastProjectile::Effect()
|
|||
if (name != NAME_None)
|
||||
{
|
||||
fixed_t hitz = z-8*FRACUNIT;
|
||||
|
||||
if (hitz < floorz)
|
||||
{
|
||||
hitz = floorz;
|
||||
}
|
||||
// Do not clip this offset to the floor.
|
||||
hitz += GetClass()->Meta.GetMetaFixed (ACMETA_MissileHeight);
|
||||
|
||||
const PClass *trail = PClass::FindClass(name);
|
||||
if (trail != NULL)
|
||||
|
|
|
@ -19,7 +19,12 @@ struct OneKey
|
|||
|
||||
bool check(AActor * owner)
|
||||
{
|
||||
return !!owner->FindInventory(key);
|
||||
// P_GetMapColorForKey() checks the key directly
|
||||
if (owner->IsKindOf (RUNTIME_CLASS(AKey)))
|
||||
return owner->IsA(key);
|
||||
// Other calls check an actor that may have a key in its inventory.
|
||||
else
|
||||
return !!owner->FindInventory(key);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -356,6 +356,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialPosition)
|
|||
self->z += FloatBobOffsets[(self->FloatBobPhase + level.maptime) & 63];
|
||||
}
|
||||
}
|
||||
self->SetOrigin (self->x, self->y, self->z);
|
||||
}
|
||||
|
||||
int AInventory::StaticLastMessageTic;
|
||||
|
@ -889,7 +890,7 @@ void AInventory::Touch (AActor *toucher)
|
|||
{
|
||||
const char * message = PickupMessage ();
|
||||
|
||||
if (toucher->CheckLocalView (consoleplayer)
|
||||
if (message != NULL && *message != 0 && toucher->CheckLocalView (consoleplayer)
|
||||
&& (StaticLastMessageTic != gametic || StaticLastMessage != message))
|
||||
{
|
||||
StaticLastMessageTic = gametic;
|
||||
|
@ -959,9 +960,7 @@ void AInventory::DoPickupSpecial (AActor *toucher)
|
|||
|
||||
const char *AInventory::PickupMessage ()
|
||||
{
|
||||
const char *message = GetClass()->Meta.GetMetaString (AIMETA_PickupMessage);
|
||||
|
||||
return message != NULL? message : "You got a pickup";
|
||||
return GetClass()->Meta.GetMetaString (AIMETA_PickupMessage);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
|
|
@ -71,7 +71,7 @@ class ARandomSpawner : public AActor
|
|||
cls = PClass::FindClass(di->Name);
|
||||
if (cls != NULL)
|
||||
{
|
||||
const PClass *rep = cls->ActorInfo->GetReplacement()->Class;
|
||||
const PClass *rep = cls->GetReplacement();
|
||||
if (rep != NULL)
|
||||
{
|
||||
cls = rep;
|
||||
|
|
|
@ -147,14 +147,20 @@ struct FSpotList
|
|||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
ASpecialSpot *GetSpotWithMinDistance(fixed_t x, fixed_t y, fixed_t distance)
|
||||
ASpecialSpot *GetSpotWithMinMaxDistance(fixed_t x, fixed_t y, fixed_t mindist, fixed_t maxdist)
|
||||
{
|
||||
if (Spots.Size() == 0) return NULL;
|
||||
int i = pr_spot() % Spots.Size();
|
||||
int initial = i;
|
||||
|
||||
while (P_AproxDistance(Spots[i]->x - x, Spots[i]->y - y) < distance)
|
||||
fixed_t distance;
|
||||
|
||||
while (true)
|
||||
{
|
||||
distance = P_AproxDistance(Spots[i]->x - x, Spots[i]->y - y);
|
||||
|
||||
if ((distance >= mindist) && ((maxdist == 0) || (distance <= maxdist))) break;
|
||||
|
||||
i = (i+1) % Spots.Size();
|
||||
if (i == initial) return NULL;
|
||||
}
|
||||
|
@ -329,10 +335,10 @@ ASpecialSpot *DSpotState::GetNextInList(const PClass *type, int skipcounter)
|
|||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
ASpecialSpot *DSpotState::GetSpotWithMinDistance(const PClass *type, fixed_t x, fixed_t y, fixed_t distance)
|
||||
ASpecialSpot *DSpotState::GetSpotWithMinMaxDistance(const PClass *type, fixed_t x, fixed_t y, fixed_t mindist, fixed_t maxdist)
|
||||
{
|
||||
FSpotList *list = FindSpotList(type);
|
||||
if (list != NULL) return list->GetSpotWithMinDistance(x, y, distance);
|
||||
if (list != NULL) return list->GetSpotWithMinMaxDistance(x, y, mindist, maxdist);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ public:
|
|||
bool RemoveSpot(ASpecialSpot *spot);
|
||||
void Serialize(FArchive &arc);
|
||||
ASpecialSpot *GetNextInList(const PClass *type, int skipcounter);
|
||||
ASpecialSpot *GetSpotWithMinDistance(const PClass *type, fixed_t x, fixed_t y, fixed_t distance);
|
||||
ASpecialSpot *GetSpotWithMinMaxDistance(const PClass *type, fixed_t x, fixed_t y, fixed_t mindist, fixed_t maxdist);
|
||||
ASpecialSpot *GetRandomSpot(const PClass *type, bool onlyonce = false);
|
||||
};
|
||||
|
||||
|
|
|
@ -933,16 +933,16 @@ void Popup::close()
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void adjustRelCenter(const SBarInfoCoordinate &x, const SBarInfoCoordinate &y, double &outX, double &outY, const double &xScale, const double &yScale)
|
||||
inline void adjustRelCenter(bool relX, bool relY, const double &x, const double &y, double &outX, double &outY, const double &xScale, const double &yScale)
|
||||
{
|
||||
if(x.RelCenter())
|
||||
outX = *x + (SCREENWIDTH/(hud_scale ? xScale*2 : 2));
|
||||
if(relX)
|
||||
outX = x + (SCREENWIDTH/(hud_scale ? xScale*2 : 2));
|
||||
else
|
||||
outX = *x;
|
||||
if(y.RelCenter())
|
||||
outY = *y + (SCREENHEIGHT/(hud_scale ? yScale*2 : 2));
|
||||
outX = x;
|
||||
if(relY)
|
||||
outY = y + (SCREENHEIGHT/(hud_scale ? yScale*2 : 2));
|
||||
else
|
||||
outY = *y;
|
||||
outY = y;
|
||||
}
|
||||
|
||||
class DSBarInfo : public DBaseStatusBar
|
||||
|
@ -1227,7 +1227,7 @@ public:
|
|||
double xScale = !hud_scale ? 1.0 : (double) CleanXfac*320.0/(double) script->resW;//(double) SCREENWIDTH/(double) script->resW;
|
||||
double yScale = !hud_scale ? 1.0 : (double) CleanYfac*200.0/(double) script->resH;//(double) SCREENHEIGHT/(double) script->resH;
|
||||
|
||||
adjustRelCenter(x, y, rx, ry, xScale, yScale);
|
||||
adjustRelCenter(x.RelCenter(), y.RelCenter(), dx, dy, rx, ry, xScale, yScale);
|
||||
|
||||
// We can't use DTA_HUDRules since it forces a width and height.
|
||||
// Translation: No high res.
|
||||
|
@ -1288,7 +1288,7 @@ public:
|
|||
}
|
||||
|
||||
if(clearDontDraw)
|
||||
screen->Clear(static_cast<int>(rcx), static_cast<int>(rcy), static_cast<int>(MIN<double>(rcr, w)), static_cast<int>(MIN<double>(rcb, h)), GPalette.BlackIndex, 0);
|
||||
screen->Clear(static_cast<int>(rcx), static_cast<int>(rcy), static_cast<int>(MIN<double>(rcr, rcx+w)), static_cast<int>(MIN<double>(rcb, rcy+h)), GPalette.BlackIndex, 0);
|
||||
else
|
||||
{
|
||||
if(alphaMap)
|
||||
|
@ -1343,13 +1343,16 @@ public:
|
|||
xScale = (double) CleanXfac*320.0/(double) script->resW;//(double) SCREENWIDTH/(double) script->resW;
|
||||
yScale = (double) CleanYfac*200.0/(double) script->resH;//(double) SCREENWIDTH/(double) script->resW;
|
||||
}
|
||||
adjustRelCenter(x, y, ax, ay, xScale, yScale);
|
||||
adjustRelCenter(x.RelCenter(), y.RelCenter(), *x, *y, ax, ay, xScale, yScale);
|
||||
}
|
||||
while(*str != '\0')
|
||||
{
|
||||
if(*str == ' ')
|
||||
{
|
||||
ax += font->GetSpaceWidth();
|
||||
if(script->spacingCharacter == '\0')
|
||||
ax += font->GetSpaceWidth();
|
||||
else
|
||||
ax += font->GetCharWidth((int) script->spacingCharacter);
|
||||
str++;
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -93,7 +93,10 @@ class CommandDrawImage : public SBarInfoCommand
|
|||
else if(sc.Compare("amulet"))
|
||||
type = HEXENARMOR_AMULET;
|
||||
else
|
||||
sc.ScriptError("Unkown armor type: '%s'", sc.String);
|
||||
{
|
||||
sc.ScriptMessage("Unkown armor type: '%s'", sc.String);
|
||||
type = HEXENARMOR_ARMOR;
|
||||
}
|
||||
sc.MustGetToken(',');
|
||||
getImage = true;
|
||||
}
|
||||
|
@ -108,9 +111,12 @@ class CommandDrawImage : public SBarInfoCommand
|
|||
const PClass* item = PClass::FindClass(sc.String);
|
||||
if(item == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(item)) //must be a kind of Inventory
|
||||
{
|
||||
sc.ScriptError("'%s' is not a type of inventory item.", sc.String);
|
||||
sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprite = ((AInventory *)GetDefaultByType(item))->Icon;
|
||||
}
|
||||
sprite = ((AInventory *)GetDefaultByType(item))->Icon;
|
||||
image = -1;
|
||||
}
|
||||
}
|
||||
|
@ -324,7 +330,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage
|
|||
const PClass* item = PClass::FindClass(sc.String);
|
||||
if(item == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(item)) //must be a kind of Inventory
|
||||
{
|
||||
sc.ScriptError("'%s' is not a type of inventory item.", sc.String);
|
||||
sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String);
|
||||
}
|
||||
GetOperation(sc, conditionalOperator[0], conditionalValue[0]);
|
||||
}
|
||||
|
@ -349,7 +355,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage
|
|||
const PClass* item = PClass::FindClass(sc.String);
|
||||
if(item == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(item)) //must be a kind of Inventory
|
||||
{
|
||||
sc.ScriptError("'%s' is not a type of inventory item.", sc.String);
|
||||
sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String);
|
||||
}
|
||||
GetOperation(sc, conditionalOperator[1], conditionalValue[1]);
|
||||
}
|
||||
|
@ -516,7 +522,7 @@ class CommandDrawString : public SBarInfoCommand
|
|||
CommandDrawString(SBarInfo *script) : SBarInfoCommand(script),
|
||||
shadow(false), shadowX(2), shadowY(2), spacing(0), font(NULL),
|
||||
translation(CR_UNTRANSLATED), cache(-1), strValue(CONSTANT),
|
||||
valueArgument(0)
|
||||
valueArgument(0), alignment (ALIGN_RIGHT)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -529,7 +535,10 @@ class CommandDrawString : public SBarInfoCommand
|
|||
sc.MustGetToken(TK_Identifier);
|
||||
font = V_GetFont(sc.String);
|
||||
if(font == NULL)
|
||||
sc.ScriptError("Unknown font '%s'.", sc.String);
|
||||
{
|
||||
sc.ScriptMessage("Unknown font '%s'.", sc.String);
|
||||
font = SmallFont;
|
||||
}
|
||||
sc.MustGetToken(',');
|
||||
translation = GetTranslation(sc);
|
||||
sc.MustGetToken(',');
|
||||
|
@ -587,6 +596,42 @@ class CommandDrawString : public SBarInfoCommand
|
|||
{
|
||||
sc.MustGetToken(TK_IntConst);
|
||||
spacing = sc.Number;
|
||||
if(sc.CheckToken(',')) //[KS] flags? flags! SIX FLAGS!
|
||||
{
|
||||
while(sc.CheckToken(TK_Identifier))
|
||||
{
|
||||
if(sc.Compare("alignment"))
|
||||
{
|
||||
sc.MustGetToken('(');
|
||||
sc.MustGetToken(TK_Identifier);
|
||||
if(sc.Compare("right"))
|
||||
alignment = ALIGN_RIGHT;
|
||||
else if(sc.Compare("left"))
|
||||
alignment = ALIGN_LEFT;
|
||||
else if(sc.Compare("center"))
|
||||
alignment = ALIGN_CENTER;
|
||||
else
|
||||
sc.ScriptError("Unknown alignment '%s'.", sc.String);
|
||||
sc.MustGetToken(')');
|
||||
}
|
||||
else if(sc.Compare("drawshadow"))
|
||||
{
|
||||
if(sc.CheckToken('('))
|
||||
{
|
||||
sc.MustGetToken(TK_IntConst);
|
||||
shadowX = sc.Number;
|
||||
sc.MustGetToken(',');
|
||||
sc.MustGetToken(TK_IntConst);
|
||||
shadowY = sc.Number;
|
||||
sc.MustGetToken(')');
|
||||
}
|
||||
shadow = true;
|
||||
}
|
||||
else
|
||||
sc.ScriptError("Unknown flag '%s'.", sc.String);
|
||||
if(!sc.CheckToken('|') && !sc.CheckToken(',')) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
sc.MustGetToken(';');
|
||||
|
||||
|
@ -682,13 +727,33 @@ class CommandDrawString : public SBarInfoCommand
|
|||
}
|
||||
}
|
||||
protected:
|
||||
enum StringAlignment
|
||||
{
|
||||
ALIGN_RIGHT,
|
||||
ALIGN_LEFT,
|
||||
ALIGN_CENTER,
|
||||
};
|
||||
|
||||
void RealignString()
|
||||
{
|
||||
x = startX;
|
||||
if(script->spacingCharacter == '\0')
|
||||
x -= static_cast<int> (font->StringWidth(str)+(spacing * str.Len()));
|
||||
else //monospaced, so just multiplay the character size
|
||||
x -= static_cast<int> ((font->GetCharWidth((int) script->spacingCharacter) + spacing) * str.Len());
|
||||
switch (alignment)
|
||||
{
|
||||
case ALIGN_LEFT:
|
||||
break;
|
||||
case ALIGN_RIGHT:
|
||||
if(script->spacingCharacter == '\0')
|
||||
x -= static_cast<int> (font->StringWidth(str)+(spacing * str.Len()));
|
||||
else //monospaced, so just multiplay the character size
|
||||
x -= static_cast<int> ((font->GetCharWidth((int) script->spacingCharacter) + spacing) * str.Len());
|
||||
break;
|
||||
case ALIGN_CENTER:
|
||||
if(script->spacingCharacter == '\0')
|
||||
x -= static_cast<int> (font->StringWidth(str)+(spacing * str.Len()) / 2);
|
||||
else
|
||||
x -= static_cast<int> ((font->GetCharWidth((int) script->spacingCharacter) + spacing) * str.Len() / 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
enum StringValueType
|
||||
|
@ -721,6 +786,7 @@ class CommandDrawString : public SBarInfoCommand
|
|||
StringValueType strValue;
|
||||
int valueArgument;
|
||||
FString str;
|
||||
StringAlignment alignment;
|
||||
|
||||
private:
|
||||
void SetStringToTag(AActor *actor)
|
||||
|
@ -763,7 +829,10 @@ class CommandDrawNumber : public CommandDrawString
|
|||
sc.MustGetToken(TK_Identifier);
|
||||
font = V_GetFont(sc.String);
|
||||
if(font == NULL)
|
||||
sc.ScriptError("Unknown font '%s'.", sc.String);
|
||||
{
|
||||
sc.ScriptMessage("Unknown font '%s'.", sc.String);
|
||||
font = SmallFont;
|
||||
}
|
||||
sc.MustGetToken(',');
|
||||
normalTranslation = GetTranslation(sc);
|
||||
sc.MustGetToken(',');
|
||||
|
@ -793,7 +862,8 @@ class CommandDrawNumber : public CommandDrawString
|
|||
inventoryItem = PClass::FindClass(sc.String);
|
||||
if(inventoryItem == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo
|
||||
{
|
||||
sc.ScriptError("'%s' is not a type of ammo.", sc.String);
|
||||
sc.ScriptMessage("'%s' is not a type of ammo.", sc.String);
|
||||
inventoryItem = RUNTIME_CLASS(AAmmo);
|
||||
}
|
||||
}
|
||||
else if(sc.Compare("ammocapacity"))
|
||||
|
@ -803,7 +873,8 @@ class CommandDrawNumber : public CommandDrawString
|
|||
inventoryItem = PClass::FindClass(sc.String);
|
||||
if(inventoryItem == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo
|
||||
{
|
||||
sc.ScriptError("'%s' is not a type of ammo.", sc.String);
|
||||
sc.ScriptMessage("'%s' is not a type of ammo.", sc.String);
|
||||
inventoryItem = RUNTIME_CLASS(AAmmo);
|
||||
}
|
||||
}
|
||||
else if(sc.Compare("frags"))
|
||||
|
@ -845,18 +916,20 @@ class CommandDrawNumber : public CommandDrawString
|
|||
value = POWERUPTIME;
|
||||
sc.MustGetToken(TK_Identifier);
|
||||
inventoryItem = PClass::FindClass(sc.String);
|
||||
if(inventoryItem == NULL || !PClass::FindClass("PowerupGiver")->IsAncestorOf(inventoryItem))
|
||||
if(inventoryItem == NULL || !RUNTIME_CLASS(APowerupGiver)->IsAncestorOf(inventoryItem))
|
||||
{
|
||||
sc.ScriptError("'%s' is not a type of PowerupGiver.", sc.String);
|
||||
sc.ScriptMessage("'%s' is not a type of PowerupGiver.", sc.String);
|
||||
inventoryItem = RUNTIME_CLASS(APowerupGiver);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value = INVENTORY;
|
||||
inventoryItem = PClass::FindClass(sc.String);
|
||||
if(inventoryItem == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(inventoryItem)) //must be a kind of ammo
|
||||
if(inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(inventoryItem)) //must be a kind of ammo
|
||||
{
|
||||
sc.ScriptError("'%s' is not a type of inventory item.", sc.String);
|
||||
sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String);
|
||||
inventoryItem = RUNTIME_CLASS(AInventory);
|
||||
}
|
||||
}
|
||||
sc.MustGetToken(',');
|
||||
|
@ -887,6 +960,20 @@ class CommandDrawNumber : public CommandDrawString
|
|||
interpolationSpeed = sc.Number;
|
||||
sc.MustGetToken(')');
|
||||
}
|
||||
else if(sc.Compare("alignment"))
|
||||
{
|
||||
sc.MustGetToken('(');
|
||||
sc.MustGetToken(TK_Identifier);
|
||||
if(sc.Compare("right"))
|
||||
alignment = ALIGN_RIGHT;
|
||||
else if(sc.Compare("left"))
|
||||
alignment = ALIGN_LEFT;
|
||||
else if(sc.Compare("center"))
|
||||
alignment = ALIGN_CENTER;
|
||||
else
|
||||
sc.ScriptError("Unknown alignment '%s'.", sc.String);
|
||||
sc.MustGetToken(')');
|
||||
}
|
||||
else
|
||||
sc.ScriptError("Unknown flag '%s'.", sc.String);
|
||||
if(!sc.CheckToken('|'))
|
||||
|
@ -1275,7 +1362,10 @@ class CommandDrawSelectedInventory : public SBarInfoCommandFlowControl, private
|
|||
{
|
||||
font = V_GetFont(sc.String);
|
||||
if(font == NULL)
|
||||
sc.ScriptError("Unknown font '%s'.", sc.String);
|
||||
{
|
||||
sc.ScriptMessage("Unknown font '%s'.", sc.String);
|
||||
font = SmallFont;
|
||||
}
|
||||
sc.MustGetToken(',');
|
||||
break;
|
||||
}
|
||||
|
@ -1757,7 +1847,10 @@ class CommandDrawInventoryBar : public SBarInfoCommand
|
|||
sc.MustGetToken(TK_Identifier);
|
||||
font = V_GetFont(sc.String);
|
||||
if(font == NULL)
|
||||
{
|
||||
sc.ScriptError("Unknown font '%s'.", sc.String);
|
||||
font = SmallFont;
|
||||
}
|
||||
|
||||
sc.MustGetToken(',');
|
||||
GetCoordinates(sc, fullScreenOffsets, x, y);
|
||||
|
@ -1991,9 +2084,12 @@ class CommandDrawBar : public SBarInfoCommand
|
|||
|
||||
FTexture *fg = statusBar->Images[foreground];
|
||||
FTexture *bg = (background != -1) ? statusBar->Images[background] : NULL;
|
||||
|
||||
|
||||
fixed_t value = drawValue;
|
||||
if(border != 0)
|
||||
{
|
||||
value = FRACUNIT - value; //invert since the new drawing method requires drawing the bg on the fg.
|
||||
|
||||
//Draw the whole foreground
|
||||
statusBar->DrawGraphic(fg, this->x, this->y, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets());
|
||||
}
|
||||
|
@ -2010,7 +2106,7 @@ class CommandDrawBar : public SBarInfoCommand
|
|||
fixed_t clip[4] = {0, 0, 0, 0};
|
||||
|
||||
fixed_t sizeOfImage = (horizontal ? fg->GetScaledWidth()-border*2 : fg->GetScaledHeight()-border*2)<<FRACBITS;
|
||||
clip[(!horizontal)|((horizontal ? !reverse : reverse)<<1)] = sizeOfImage - FixedMul(sizeOfImage, drawValue);
|
||||
clip[(!horizontal)|((horizontal ? !reverse : reverse)<<1)] = sizeOfImage - FixedMul(sizeOfImage, value);
|
||||
// Draw background
|
||||
if(border != 0)
|
||||
{
|
||||
|
@ -2040,8 +2136,11 @@ class CommandDrawBar : public SBarInfoCommand
|
|||
if(sc.CheckToken(TK_Identifier)) //comparing reference
|
||||
{
|
||||
inventoryItem = PClass::FindClass(sc.String);
|
||||
if(inventoryItem == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(inventoryItem)) //must be a kind of inventory
|
||||
sc.ScriptError("'%s' is not a type of inventory item.", sc.String);
|
||||
if(inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(inventoryItem)) //must be a kind of inventory
|
||||
{
|
||||
sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String);
|
||||
inventoryItem = RUNTIME_CLASS(AInventory);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(sc.Compare("armor"))
|
||||
|
@ -2050,8 +2149,11 @@ class CommandDrawBar : public SBarInfoCommand
|
|||
if(sc.CheckToken(TK_Identifier))
|
||||
{
|
||||
inventoryItem = PClass::FindClass(sc.String);
|
||||
if(inventoryItem == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(inventoryItem)) //must be a kind of inventory
|
||||
sc.ScriptError("'%s' is not a type of inventory item.", sc.String);
|
||||
if(inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(inventoryItem)) //must be a kind of inventory
|
||||
{
|
||||
sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String);
|
||||
inventoryItem = RUNTIME_CLASS(AInventory);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(sc.Compare("ammo1"))
|
||||
|
@ -2065,7 +2167,8 @@ class CommandDrawBar : public SBarInfoCommand
|
|||
inventoryItem = PClass::FindClass(sc.String);
|
||||
if(inventoryItem == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo
|
||||
{
|
||||
sc.ScriptError("'%s' is not a type of ammo.", sc.String);
|
||||
sc.ScriptMessage("'%s' is not a type of ammo.", sc.String);
|
||||
inventoryItem = RUNTIME_CLASS(AAmmo);
|
||||
}
|
||||
}
|
||||
else if(sc.Compare("frags"))
|
||||
|
@ -2083,9 +2186,10 @@ class CommandDrawBar : public SBarInfoCommand
|
|||
type = POWERUPTIME;
|
||||
sc.MustGetToken(TK_Identifier);
|
||||
inventoryItem = PClass::FindClass(sc.String);
|
||||
if(inventoryItem == NULL || !PClass::FindClass("PowerupGiver")->IsAncestorOf(inventoryItem))
|
||||
if(inventoryItem == NULL || !RUNTIME_CLASS(APowerupGiver)->IsAncestorOf(inventoryItem))
|
||||
{
|
||||
sc.ScriptError("'%s' is not a type of PowerupGiver.", sc.String);
|
||||
sc.ScriptMessage("'%s' is not a type of PowerupGiver.", sc.String);
|
||||
inventoryItem = RUNTIME_CLASS(APowerupGiver);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -2094,7 +2198,8 @@ class CommandDrawBar : public SBarInfoCommand
|
|||
inventoryItem = PClass::FindClass(sc.String);
|
||||
if(inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(inventoryItem))
|
||||
{
|
||||
sc.ScriptError("'%s' is not a type of inventory item.", sc.String);
|
||||
sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String);
|
||||
inventoryItem = RUNTIME_CLASS(AInventory);
|
||||
}
|
||||
}
|
||||
sc.MustGetToken(',');
|
||||
|
@ -2258,17 +2363,13 @@ class CommandDrawBar : public SBarInfoCommand
|
|||
}
|
||||
default: return;
|
||||
}
|
||||
|
||||
if(border != 0)
|
||||
value = max - value; //invert since the new drawing method requires drawing the bg on the fg.
|
||||
|
||||
if(max != 0 && value > 0)
|
||||
{
|
||||
value = (value << FRACBITS) / max;
|
||||
if(value > FRACUNIT)
|
||||
value = FRACUNIT;
|
||||
}
|
||||
else if(border != 0 && max == 0 && value <= 0)
|
||||
value = FRACUNIT;
|
||||
else
|
||||
value = 0;
|
||||
if(interpolationSpeed != 0 && (!hudChanged || level.time == 1))
|
||||
|
@ -2343,7 +2444,10 @@ class CommandIsSelected : public SBarInfoCommandFlowControl
|
|||
{
|
||||
weapon[i] = PClass::FindClass(sc.String);
|
||||
if(weapon[i] == NULL || !RUNTIME_CLASS(AWeapon)->IsAncestorOf(weapon[i]))
|
||||
sc.ScriptError("'%s' is not a type of weapon.", sc.String);
|
||||
{
|
||||
sc.ScriptMessage("'%s' is not a type of weapon.", sc.String);
|
||||
weapon[i] = RUNTIME_CLASS(AWeapon);
|
||||
}
|
||||
|
||||
if(sc.CheckToken(','))
|
||||
{
|
||||
|
@ -2445,7 +2549,10 @@ class CommandHasWeaponPiece : public SBarInfoCommandFlowControl
|
|||
sc.MustGetToken(TK_Identifier);
|
||||
weapon = PClass::FindClass(sc.String);
|
||||
if(weapon == NULL || !RUNTIME_CLASS(AWeapon)->IsAncestorOf(weapon)) //must be a weapon
|
||||
sc.ScriptError("%s is not a kind of weapon.", sc.String);
|
||||
{
|
||||
sc.ScriptMessage("%s is not a kind of weapon.", sc.String);
|
||||
weapon = RUNTIME_CLASS(AWeapon);
|
||||
}
|
||||
sc.MustGetToken(',');
|
||||
sc.MustGetToken(TK_IntConst);
|
||||
if(sc.Number < 1)
|
||||
|
@ -2634,7 +2741,10 @@ class CommandWeaponAmmo : public SBarInfoCommandFlowControl
|
|||
{
|
||||
ammo[i] = PClass::FindClass(sc.String);
|
||||
if(ammo[i] == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(ammo[i])) //must be a kind of ammo
|
||||
sc.ScriptError("'%s' is not a type of ammo.", sc.String);
|
||||
{
|
||||
sc.ScriptMessage("'%s' is not a type of ammo.", sc.String);
|
||||
ammo[i] = RUNTIME_CLASS(AAmmo);
|
||||
}
|
||||
|
||||
if(sc.CheckToken(TK_OrOr))
|
||||
{
|
||||
|
@ -2734,7 +2844,10 @@ class CommandInInventory : public SBarInfoCommandFlowControl
|
|||
{
|
||||
item[i] = PClass::FindClass(sc.String);
|
||||
if(item[i] == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item[i]))
|
||||
sc.ScriptError("'%s' is not a type of inventory item.", sc.String);
|
||||
{
|
||||
sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String);
|
||||
item[i] = RUNTIME_CLASS(AInventory);
|
||||
}
|
||||
|
||||
if (sc.CheckToken(','))
|
||||
{
|
||||
|
|
|
@ -1504,18 +1504,23 @@ void DBaseStatusBar::BlendView (float blend[4])
|
|||
if (CPlayer->bonuscount)
|
||||
{
|
||||
cnt = CPlayer->bonuscount << 3;
|
||||
AddBlend (0.8431f, 0.7333f, 0.2706f, cnt > 128 ? 0.5f : cnt / 255.f, blend);
|
||||
|
||||
AddBlend (RPART(gameinfo.pickupcolor)/255.f, GPART(gameinfo.pickupcolor)/255.f,
|
||||
BPART(gameinfo.pickupcolor)/255.f, cnt > 128 ? 0.5f : cnt / 255.f, blend);
|
||||
}
|
||||
|
||||
cnt = DamageToAlpha[MIN (113, CPlayer->damagecount)];
|
||||
|
||||
if (cnt)
|
||||
if (CPlayer->mo->DamageFade.a != 0)
|
||||
{
|
||||
if (cnt > 228)
|
||||
cnt = 228;
|
||||
cnt = DamageToAlpha[MIN (113, CPlayer->damagecount * CPlayer->mo->DamageFade.a / 255)];
|
||||
|
||||
if (cnt)
|
||||
{
|
||||
if (cnt > 228)
|
||||
cnt = 228;
|
||||
|
||||
APlayerPawn *mo = players[consoleplayer].mo;
|
||||
AddBlend (mo->DamageFade.r / 255.f, mo->DamageFade.g / 255.f, mo->DamageFade.b / 255.f, cnt / 255.f, blend);
|
||||
APlayerPawn *mo = CPlayer->mo;
|
||||
AddBlend (mo->DamageFade.r / 255.f, mo->DamageFade.g / 255.f, mo->DamageFade.b / 255.f, cnt / 255.f, blend);
|
||||
}
|
||||
}
|
||||
|
||||
// Unlike Doom, I did not have any utility source to look at to find the
|
||||
|
|
|
@ -80,6 +80,7 @@ void FMapInfoParser::ParseSkill ()
|
|||
skill.MonsterHealth = FRACUNIT;
|
||||
skill.FriendlyHealth = FRACUNIT;
|
||||
skill.NoPain = false;
|
||||
skill.ArmorFactor = FRACUNIT;
|
||||
|
||||
sc.MustGetString();
|
||||
skill.Name = sc.String;
|
||||
|
@ -249,6 +250,12 @@ void FMapInfoParser::ParseSkill ()
|
|||
{
|
||||
skill.NoPain = true;
|
||||
}
|
||||
else if (sc.Compare("ArmorFactor"))
|
||||
{
|
||||
ParseAssign();
|
||||
sc.MustGetFloat();
|
||||
skill.ArmorFactor = FLOAT2FIXED(sc.Float);
|
||||
}
|
||||
else if (sc.Compare("DefaultSkill"))
|
||||
{
|
||||
if (DefaultSkill >= 0)
|
||||
|
@ -357,7 +364,10 @@ int G_SkillProperty(ESkillProperty prop)
|
|||
return AllSkills[gameskill].FriendlyHealth;
|
||||
|
||||
case SKILLP_NoPain:
|
||||
return AllSkills[gameskill].NoPain;
|
||||
return AllSkills[gameskill].NoPain;
|
||||
|
||||
case SKILLP_ArmorFactor:
|
||||
return AllSkills[gameskill].ArmorFactor;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -435,6 +445,7 @@ FSkillInfo &FSkillInfo::operator=(const FSkillInfo &other)
|
|||
MonsterHealth = other.MonsterHealth;
|
||||
FriendlyHealth = other.FriendlyHealth;
|
||||
NoPain = other.NoPain;
|
||||
ArmorFactor = other.ArmorFactor;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
|
@ -399,29 +399,38 @@ void FGameConfigFile::DoGameSetup (const char *gamename)
|
|||
ReadCVars (0);
|
||||
}
|
||||
|
||||
strncpy (subsection, "Bindings", sublen);
|
||||
if (!SetSection (section))
|
||||
{ // Config has no bindings for the given game
|
||||
if (!bMigrating)
|
||||
{
|
||||
C_SetDefaultBindings ();
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!bMigrating)
|
||||
{
|
||||
C_UnbindAll ();
|
||||
C_SetDefaultBindings ();
|
||||
}
|
||||
|
||||
strncpy (subsection, "Bindings", sublen);
|
||||
if (SetSection (section))
|
||||
{
|
||||
Bindings.UnbindAll();
|
||||
while (NextInSection (key, value))
|
||||
{
|
||||
C_DoBind (key, value, false);
|
||||
Bindings.DoBind (key, value);
|
||||
}
|
||||
}
|
||||
|
||||
strncpy (subsection, "DoubleBindings", sublen);
|
||||
if (SetSection (section))
|
||||
{
|
||||
DoubleBindings.UnbindAll();
|
||||
while (NextInSection (key, value))
|
||||
{
|
||||
C_DoBind (key, value, true);
|
||||
DoubleBindings.DoBind (key, value);
|
||||
}
|
||||
}
|
||||
|
||||
strncpy (subsection, "AutomapBindings", sublen);
|
||||
if (SetSection (section))
|
||||
{
|
||||
AutomapBindings.UnbindAll();
|
||||
while (NextInSection (key, value))
|
||||
{
|
||||
AutomapBindings.DoBind (key, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -512,11 +521,15 @@ void FGameConfigFile::ArchiveGameData (const char *gamename)
|
|||
|
||||
strcpy (subsection, "Bindings");
|
||||
SetSection (section, true);
|
||||
C_ArchiveBindings (this, false);
|
||||
Bindings.ArchiveBindings (this);
|
||||
|
||||
strncpy (subsection, "DoubleBindings", sublen);
|
||||
SetSection (section, true);
|
||||
C_ArchiveBindings (this, true);
|
||||
DoubleBindings.ArchiveBindings (this);
|
||||
|
||||
strncpy (subsection, "AutomapBindings", sublen);
|
||||
SetSection (section, true);
|
||||
AutomapBindings.ArchiveBindings (this);
|
||||
}
|
||||
|
||||
void FGameConfigFile::ArchiveGlobalData ()
|
||||
|
|
16
src/gi.cpp
16
src/gi.cpp
|
@ -103,12 +103,11 @@ const char* GameInfoBoarders[] =
|
|||
do \
|
||||
{ \
|
||||
sc.MustGetToken(TK_StringConst); \
|
||||
if(strlen(sc.String) > length) \
|
||||
if(length > 0 && strlen(sc.String) > length) \
|
||||
{ \
|
||||
sc.ScriptError("Value for '%s' can not be longer than %d characters.", #key, length); \
|
||||
} \
|
||||
FName val = sc.String; \
|
||||
gameinfo.key.Push(val); \
|
||||
gameinfo.key[gameinfo.key.Reserve(1)] = sc.String; \
|
||||
} \
|
||||
while (sc.CheckToken(',')); \
|
||||
}
|
||||
|
@ -266,6 +265,7 @@ void FMapInfoParser::ParseGameInfo()
|
|||
GAMEINFOKEY_INT(defKickback, "defKickback")
|
||||
GAMEINFOKEY_CSTRING(SkyFlatName, "SkyFlatName", 8)
|
||||
GAMEINFOKEY_STRING(translator, "translator")
|
||||
GAMEINFOKEY_COLOR(pickupcolor, "pickupcolor")
|
||||
GAMEINFOKEY_COLOR(defaultbloodcolor, "defaultbloodcolor")
|
||||
GAMEINFOKEY_COLOR(defaultbloodparticlecolor, "defaultbloodparticlecolor")
|
||||
GAMEINFOKEY_STRING(backpacktype, "backpacktype")
|
||||
|
@ -282,6 +282,16 @@ void FMapInfoParser::ParseGameInfo()
|
|||
GAMEINFOKEY_INT(defaultdropstyle, "defaultdropstyle")
|
||||
GAMEINFOKEY_CSTRING(Endoom, "endoom", 8)
|
||||
GAMEINFOKEY_INT(player5start, "player5start")
|
||||
GAMEINFOKEY_STRINGARRAY(quitmessages, "quitmessages", 0)
|
||||
GAMEINFOKEY_STRING(mTitleColor, "menufontcolor_title")
|
||||
GAMEINFOKEY_STRING(mFontColor, "menufontcolor_label")
|
||||
GAMEINFOKEY_STRING(mFontColorValue, "menufontcolor_value")
|
||||
GAMEINFOKEY_STRING(mFontColorMore, "menufontcolor_action")
|
||||
GAMEINFOKEY_STRING(mFontColorHeader, "menufontcolor_header")
|
||||
GAMEINFOKEY_STRING(mFontColorHighlight, "menufontcolor_highlight")
|
||||
GAMEINFOKEY_STRING(mFontColorSelection, "menufontcolor_selection")
|
||||
GAMEINFOKEY_CSTRING(mBackButton, "menubackbutton", 8)
|
||||
|
||||
else
|
||||
{
|
||||
// ignore unkown keys.
|
||||
|
|
15
src/gi.h
15
src/gi.h
|
@ -43,7 +43,10 @@
|
|||
#define GI_MENUHACK_EXTENDED 0x00000004 // (Heretic)
|
||||
#define GI_TEASER2 0x00000008 // Alternate version of the Strife Teaser
|
||||
#define GI_COMPATSHORTTEX 0x00000010 // always force COMPAT_SHORTTEX for IWAD maps.
|
||||
#define GI_COMPATSTAIRS 0x00000010 // same for stairbuilding
|
||||
#define GI_COMPATSTAIRS 0x00000020 // same for stairbuilding
|
||||
#define GI_COMPATPOLY1 0x00000040 // Hexen's MAP36 needs old polyobject drawing
|
||||
#define GI_COMPATPOLY2 0x00000080 // so does HEXDD's MAP47
|
||||
#define GI_NOTEXTCOLOR 0x00000100
|
||||
|
||||
#include "gametype.h"
|
||||
|
||||
|
@ -106,6 +109,16 @@ struct gameinfo_t
|
|||
int defaultrespawntime;
|
||||
int defaultdropstyle;
|
||||
int player5start;
|
||||
DWORD pickupcolor;
|
||||
TArray<FString> quitmessages;
|
||||
FName mTitleColor;
|
||||
FName mFontColor;
|
||||
FName mFontColorValue;
|
||||
FName mFontColorMore;
|
||||
FName mFontColorHeader;
|
||||
FName mFontColorHighlight;
|
||||
FName mFontColorSelection;
|
||||
char mBackButton[9];
|
||||
|
||||
const char *GetFinalePage(unsigned int num) const;
|
||||
};
|
||||
|
|
146
src/keysections.cpp
Normal file
146
src/keysections.cpp
Normal file
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
** keysections.cpp
|
||||
** Custom key bindings
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 1998-2009 Randy Heit
|
||||
** Copyright 2010 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
#include "menu/menu.h"
|
||||
#include "g_level.h"
|
||||
#include "d_player.h"
|
||||
#include "gi.h"
|
||||
#include "c_bind.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "gameconfigfile.h"
|
||||
|
||||
TArray<FKeySection> KeySections;
|
||||
|
||||
static void LoadKeys (const char *modname, bool dbl)
|
||||
{
|
||||
char section[64];
|
||||
|
||||
if (GameNames[gameinfo.gametype] == NULL)
|
||||
return;
|
||||
|
||||
mysnprintf (section, countof(section), "%s.%s%sBindings", GameNames[gameinfo.gametype], modname,
|
||||
dbl ? ".Double" : ".");
|
||||
|
||||
FKeyBindings *bindings = dbl? &DoubleBindings : &Bindings;
|
||||
if (GameConfig->SetSection (section))
|
||||
{
|
||||
const char *key, *value;
|
||||
while (GameConfig->NextInSection (key, value))
|
||||
{
|
||||
bindings->DoBind (key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void DoSaveKeys (FConfigFile *config, const char *section, FKeySection *keysection, bool dbl)
|
||||
{
|
||||
config->SetSection (section, true);
|
||||
config->ClearCurrentSection ();
|
||||
FKeyBindings *bindings = dbl? &DoubleBindings : &Bindings;
|
||||
for (unsigned i = 0; i < keysection->mActions.Size(); ++i)
|
||||
{
|
||||
bindings->ArchiveBindings (config, keysection->mActions[i].mAction);
|
||||
}
|
||||
}
|
||||
|
||||
void M_SaveCustomKeys (FConfigFile *config, char *section, char *subsection, size_t sublen)
|
||||
{
|
||||
for (unsigned i=0; i<KeySections.Size(); i++)
|
||||
{
|
||||
mysnprintf (subsection, sublen, "%s.Bindings", KeySections[i].mSection);
|
||||
DoSaveKeys (config, section, &KeySections[i], false);
|
||||
mysnprintf (subsection, sublen, "%s.DoubleBindings", KeySections[i].mSection);
|
||||
DoSaveKeys (config, section, &KeySections[i], true);
|
||||
}
|
||||
}
|
||||
|
||||
static int CurrentKeySection = -1;
|
||||
|
||||
CCMD (addkeysection)
|
||||
{
|
||||
if (ParsingKeyConf)
|
||||
{
|
||||
if (argv.argc() != 3)
|
||||
{
|
||||
Printf ("Usage: addkeysection <menu section name> <ini name>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Limit the ini name to 32 chars
|
||||
if (strlen (argv[2]) > 32)
|
||||
argv[2][32] = 0;
|
||||
|
||||
for (unsigned i = 0; i < KeySections.Size(); i++)
|
||||
{
|
||||
if (KeySections[i].mTitle.CompareNoCase(argv[2] == 0))
|
||||
{
|
||||
CurrentKeySection = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CurrentKeySection = KeySections.Reserve(1);
|
||||
KeySections[CurrentKeySection].mTitle = argv[1];
|
||||
KeySections[CurrentKeySection].mSection = argv[2];
|
||||
// Load bindings for this section from the ini
|
||||
LoadKeys (argv[2], 0);
|
||||
LoadKeys (argv[2], 1);
|
||||
}
|
||||
}
|
||||
|
||||
CCMD (addmenukey)
|
||||
{
|
||||
if (ParsingKeyConf)
|
||||
{
|
||||
if (argv.argc() != 3)
|
||||
{
|
||||
Printf ("Usage: addmenukey <description> <command>\n");
|
||||
return;
|
||||
}
|
||||
if (CurrentKeySection == -1 || CurrentKeySection >= (int)KeySections.Size())
|
||||
{
|
||||
Printf ("You must use addkeysection first.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
FKeySection *sect = &KeySections[CurrentKeySection];
|
||||
|
||||
FKeyAction *act = §->mActions[sect->mActions.Reserve(1)];
|
||||
act->mTitle = argv[1];
|
||||
act->mAction = argv[2];
|
||||
}
|
||||
}
|
||||
|
|
@ -91,8 +91,3 @@ int FBoundingBox::BoxOnLineSide (const line_t *ld) const
|
|||
return (p1 == p2) ? p1 : -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "doomtype.h"
|
||||
|
||||
struct line_t;
|
||||
struct node_t;
|
||||
|
||||
class FBoundingBox
|
||||
{
|
||||
|
|
|
@ -754,8 +754,8 @@ void cht_Give (player_t *player, const char *name, int amount)
|
|||
// Don't give replaced weapons unless the replacement was done by Dehacked.
|
||||
if (type != RUNTIME_CLASS(AWeapon) &&
|
||||
type->IsDescendantOf (RUNTIME_CLASS(AWeapon)) &&
|
||||
(type->ActorInfo->GetReplacement() == type->ActorInfo ||
|
||||
type->ActorInfo->GetReplacement()->Class->IsDescendantOf(RUNTIME_CLASS(ADehackedPickup))))
|
||||
(type->GetReplacement() == type ||
|
||||
type->GetReplacement()->IsDescendantOf(RUNTIME_CLASS(ADehackedPickup))))
|
||||
|
||||
{
|
||||
// Give the weapon only if it belongs to the current game or
|
||||
|
|
|
@ -60,5 +60,6 @@ double Joy_RemoveDeadZone(double axisval, double deadzone, BYTE *buttons);
|
|||
void I_GetAxes(float axes[NUM_JOYAXIS]);
|
||||
void I_GetJoysticks(TArray<IJoystickConfig *> &sticks);
|
||||
IJoystickConfig *I_UpdateDeviceList();
|
||||
extern void UpdateJoystickMenu(IJoystickConfig *);
|
||||
|
||||
#endif
|
||||
|
|
4133
src/m_menu.cpp
4133
src/m_menu.cpp
File diff suppressed because it is too large
Load diff
279
src/m_menu.h
279
src/m_menu.h
|
@ -1,279 +0,0 @@
|
|||
// Emacs style mode select -*- C++ -*-
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// $Id:$
|
||||
//
|
||||
// Copyright (C) 1993-1996 by id Software, Inc.
|
||||
//
|
||||
// This source is available for distribution and/or modification
|
||||
// only under the terms of the DOOM Source Code License as
|
||||
// published by id Software. All rights reserved.
|
||||
//
|
||||
// The source is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
|
||||
// for more details.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Menu widget stuff, episode selection and such.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __M_MENU_H__
|
||||
#define __M_MENU_H__
|
||||
|
||||
#include "c_cvars.h"
|
||||
|
||||
struct event_t;
|
||||
struct menu_t;
|
||||
//
|
||||
// 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.
|
||||
bool 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);
|
||||
|
||||
void M_Deinit ();
|
||||
|
||||
// Called by intro code to force menu up upon a keypress,
|
||||
// does nothing if menu is already up.
|
||||
void M_StartControlPanel (bool makeSound, bool wantTop=false);
|
||||
|
||||
// Turns off the menu
|
||||
void M_ClearMenus ();
|
||||
|
||||
// [RH] Setup options menu
|
||||
bool M_StartOptionsMenu (void);
|
||||
|
||||
// [RH] Handle keys for options menu
|
||||
void M_OptResponder (event_t *ev);
|
||||
|
||||
// [RH] Draw options menu
|
||||
void M_OptDrawer (void);
|
||||
|
||||
// [RH] Initialize options menu
|
||||
void M_OptInit (void);
|
||||
|
||||
// [RH] Initialize the video modes menu
|
||||
void M_InitVideoModesMenu (void);
|
||||
|
||||
void M_SwitchMenu (struct menu_t *menu);
|
||||
|
||||
void M_PopMenuStack (void);
|
||||
|
||||
// [RH] Called whenever the display mode changes
|
||||
void M_RefreshModesList ();
|
||||
|
||||
void M_ActivateMenuInput ();
|
||||
void M_DeactivateMenuInput ();
|
||||
|
||||
void M_NotifyNewSave (const char *file, const char *title, bool okForQuicksave);
|
||||
|
||||
//
|
||||
// MENU TYPEDEFS
|
||||
//
|
||||
typedef enum {
|
||||
whitetext,
|
||||
redtext,
|
||||
more,
|
||||
rightmore,
|
||||
safemore,
|
||||
rsafemore,
|
||||
joymore,
|
||||
slider,
|
||||
absslider,
|
||||
inverter,
|
||||
discrete,
|
||||
discretes,
|
||||
cdiscrete,
|
||||
ediscrete,
|
||||
control,
|
||||
screenres,
|
||||
bitflag,
|
||||
bitmask,
|
||||
listelement,
|
||||
nochoice,
|
||||
numberedmore,
|
||||
colorpicker,
|
||||
intslider,
|
||||
palettegrid,
|
||||
joy_sens,
|
||||
joy_slider,
|
||||
joy_map,
|
||||
joy_inverter,
|
||||
} itemtype;
|
||||
|
||||
struct IJoystickConfig;
|
||||
void UpdateJoystickMenu(IJoystickConfig *selected);
|
||||
|
||||
// Yeargh! It's a monster!
|
||||
struct menuitem_t
|
||||
{
|
||||
itemtype type;
|
||||
const char *label;
|
||||
union {
|
||||
FBaseCVar *cvar;
|
||||
FIntCVar *intcvar;
|
||||
FGUIDCVar *guidcvar;
|
||||
FColorCVar *colorcvar;
|
||||
int selmode;
|
||||
float fval;
|
||||
int joyselection;
|
||||
} a;
|
||||
union {
|
||||
float min; /* aka numvalues aka invflag */
|
||||
float numvalues;
|
||||
float invflag;
|
||||
int key1;
|
||||
char *res1;
|
||||
int position;
|
||||
} b;
|
||||
union {
|
||||
float max;
|
||||
int key2;
|
||||
char *res2;
|
||||
void *extra;
|
||||
float discretecenter; // 1 to center or 2 to disable repeat (do I even use centered discretes?)
|
||||
} c;
|
||||
union {
|
||||
float step;
|
||||
char *res3;
|
||||
FBoolCVar *graycheck; // for drawing discrete items
|
||||
} d;
|
||||
union {
|
||||
struct value_t *values;
|
||||
struct valuestring_t *valuestrings;
|
||||
struct valueenum_t *enumvalues;
|
||||
char *command;
|
||||
void (*cfunc)(FBaseCVar *cvar, float newval);
|
||||
void (*mfunc)(void);
|
||||
void (*lfunc)(int);
|
||||
int highlight;
|
||||
int flagmask;
|
||||
int joyslidernum;
|
||||
} e;
|
||||
};
|
||||
|
||||
struct menu_t {
|
||||
const char *texttitle;
|
||||
int lastOn;
|
||||
int numitems;
|
||||
int indent;
|
||||
menuitem_t *items;
|
||||
int scrolltop;
|
||||
int scrollpos;
|
||||
int y;
|
||||
bool (*PreDraw)(void);
|
||||
bool DontDim;
|
||||
void (*EscapeHandler)(void);
|
||||
};
|
||||
|
||||
struct value_t {
|
||||
float value;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct valuestring_t {
|
||||
float value;
|
||||
FString name;
|
||||
};
|
||||
|
||||
struct valueenum_t {
|
||||
const char *value; // Value of cvar
|
||||
const char *name; // Name on menu
|
||||
};
|
||||
|
||||
struct oldmenuitem_t
|
||||
{
|
||||
// -1 = no cursor here, 1 = ok, 2 = arrows ok
|
||||
SBYTE status;
|
||||
BYTE fulltext; // [RH] Menu name is text, not a graphic
|
||||
|
||||
// hotkey in menu
|
||||
char alphaKey;
|
||||
|
||||
const char *name;
|
||||
|
||||
// choice = menu item #.
|
||||
// if status = 2,
|
||||
// choice=0:leftarrow,1:rightarrow
|
||||
void (*routine)(int choice);
|
||||
int textcolor;
|
||||
};
|
||||
|
||||
struct oldmenu_t
|
||||
{
|
||||
short numitems; // # of menu items
|
||||
oldmenuitem_t *menuitems; // menu items
|
||||
void (*routine)(void); // draw routine
|
||||
short x;
|
||||
short y; // x,y of menu
|
||||
short lastOn; // last item user was on in menu
|
||||
};
|
||||
|
||||
struct menustack_t
|
||||
{
|
||||
union {
|
||||
menu_t *newmenu;
|
||||
oldmenu_t *old;
|
||||
} menu;
|
||||
bool isNewStyle;
|
||||
bool drawSkull;
|
||||
};
|
||||
|
||||
enum EMenuKey
|
||||
{
|
||||
MKEY_Up,
|
||||
MKEY_Down,
|
||||
MKEY_Left,
|
||||
MKEY_Right,
|
||||
MKEY_PageUp,
|
||||
MKEY_PageDown,
|
||||
//----------------- Keys past here do not repeat.
|
||||
MKEY_Enter,
|
||||
MKEY_Back, // Back to previous menu
|
||||
MKEY_Clear, // Clear keybinding/flip player sprite preview
|
||||
|
||||
NUM_MKEYS
|
||||
};
|
||||
|
||||
void M_ButtonHandler(EMenuKey key, bool repeat);
|
||||
void M_OptButtonHandler(EMenuKey key, bool repeat);
|
||||
void M_DrawConText (int color, int x, int y, const char *str);
|
||||
|
||||
extern value_t YesNo[2];
|
||||
extern value_t NoYes[2];
|
||||
extern value_t OnOff[2];
|
||||
|
||||
extern menustack_t MenuStack[16];
|
||||
extern int MenuStackDepth;
|
||||
|
||||
extern bool OptionsActive;
|
||||
extern int skullAnimCounter;
|
||||
|
||||
extern menu_t *CurrentMenu;
|
||||
extern int CurrentItem;
|
||||
|
||||
#define MAX_EPISODES 8
|
||||
|
||||
extern oldmenuitem_t EpisodeMenu[MAX_EPISODES];
|
||||
extern bool EpisodeNoSkill[MAX_EPISODES];
|
||||
extern char EpisodeMaps[MAX_EPISODES][9];
|
||||
extern oldmenu_t EpiDef;
|
||||
|
||||
#endif
|
|
@ -85,8 +85,6 @@ CVAR(String, screenshot_type, "png", CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
|
|||
CVAR(String, screenshot_dir, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
|
||||
EXTERN_CVAR(Bool, longsavemessages);
|
||||
|
||||
extern void FreeKeySections();
|
||||
|
||||
static long ParseCommandLine (const char *args, int *argc, char **argv);
|
||||
|
||||
//
|
||||
|
@ -167,7 +165,7 @@ void M_FindResponseFile (void)
|
|||
int argc = 0;
|
||||
FILE *handle;
|
||||
int size;
|
||||
long argsize;
|
||||
long argsize = 0;
|
||||
int index;
|
||||
|
||||
// Any more response files after the limit will be removed from the
|
||||
|
@ -420,7 +418,6 @@ void M_LoadDefaults ()
|
|||
{
|
||||
GameConfig = new FGameConfigFile;
|
||||
GameConfig->DoGlobalSetup ();
|
||||
atterm (FreeKeySections);
|
||||
atterm (M_SaveDefaultsFinal);
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ void M_LoadDefaults ();
|
|||
bool M_SaveDefaults (const char *filename);
|
||||
void M_SaveCustomKeys (FConfigFile *config, char *section, char *subsection, size_t sublen);
|
||||
|
||||
|
||||
// Prepends ~/.zdoom to path
|
||||
FString GetUserFile (const char *path);
|
||||
|
||||
|
|
3882
src/m_options.cpp
3882
src/m_options.cpp
File diff suppressed because it is too large
Load diff
357
src/menu/colorpickermenu.cpp
Normal file
357
src/menu/colorpickermenu.cpp
Normal file
|
@ -0,0 +1,357 @@
|
|||
/*
|
||||
** colorpickermenu.cpp
|
||||
** The color picker menu
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2010 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
#include <float.h>
|
||||
|
||||
#include "menu/menu.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "w_wad.h"
|
||||
#include "sc_man.h"
|
||||
#include "v_font.h"
|
||||
#include "g_level.h"
|
||||
#include "d_player.h"
|
||||
#include "v_video.h"
|
||||
#include "gi.h"
|
||||
#include "i_system.h"
|
||||
#include "c_bind.h"
|
||||
#include "v_palette.h"
|
||||
#include "d_event.h"
|
||||
#include "d_gui.h"
|
||||
|
||||
#define NO_IMP
|
||||
#include "menu/optionmenuitems.h"
|
||||
|
||||
class DColorPickerMenu : public DOptionMenu
|
||||
{
|
||||
DECLARE_CLASS(DColorPickerMenu, DOptionMenu)
|
||||
|
||||
float mRed;
|
||||
float mGreen;
|
||||
float mBlue;
|
||||
|
||||
int mGridPosX;
|
||||
int mGridPosY;
|
||||
|
||||
int mStartItem;
|
||||
|
||||
FColorCVar *mCVar;
|
||||
|
||||
public:
|
||||
|
||||
DColorPickerMenu(DMenu *parent, const char *name, FOptionMenuDescriptor *desc, FColorCVar *cvar)
|
||||
{
|
||||
mStartItem = desc->mItems.Size();
|
||||
mRed = (float)RPART(DWORD(*cvar));
|
||||
mGreen = (float)GPART(DWORD(*cvar));
|
||||
mBlue = (float)BPART(DWORD(*cvar));
|
||||
mGridPosX = 0;
|
||||
mGridPosY = 0;
|
||||
mCVar = cvar;
|
||||
|
||||
// This menu uses some featurs that are hard to implement in an external control lump
|
||||
// so it creates its own list of menu items.
|
||||
desc->mItems.Resize(mStartItem+8);
|
||||
desc->mItems[mStartItem+0] = new FOptionMenuItemStaticText(name, false);
|
||||
desc->mItems[mStartItem+1] = new FOptionMenuItemStaticText(" ", false);
|
||||
desc->mItems[mStartItem+2] = new FOptionMenuSliderVar("Red", &mRed, 0, 255, 15, 0);
|
||||
desc->mItems[mStartItem+3] = new FOptionMenuSliderVar("Green", &mGreen, 0, 255, 15, 0);
|
||||
desc->mItems[mStartItem+4] = new FOptionMenuSliderVar("Blue", &mBlue, 0, 255, 15, 0);
|
||||
desc->mItems[mStartItem+5] = new FOptionMenuItemStaticText(" ", false);
|
||||
desc->mItems[mStartItem+6] = new FOptionMenuItemCommand("Undo changes", "undocolorpic");
|
||||
desc->mItems[mStartItem+7] = new FOptionMenuItemStaticText(" ", false);
|
||||
desc->mSelectedItem = mStartItem + 2;
|
||||
Init(parent, desc);
|
||||
desc->mIndent = 0;
|
||||
desc->CalcIndent();
|
||||
}
|
||||
|
||||
void Destroy()
|
||||
{
|
||||
if (mStartItem >= 0)
|
||||
{
|
||||
for(unsigned i=0;i<8;i++)
|
||||
{
|
||||
delete mDesc->mItems[mStartItem+i];
|
||||
mDesc->mItems.Resize(mStartItem);
|
||||
}
|
||||
UCVarValue val;
|
||||
val.Int = MAKERGB(int(mRed), int(mGreen), int(mBlue));
|
||||
if (mCVar != NULL) mCVar->SetGenericRep (val, CVAR_Int);
|
||||
mStartItem = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
mRed = (float)RPART(DWORD(*mCVar));
|
||||
mGreen = (float)GPART(DWORD(*mCVar));
|
||||
mBlue = (float)BPART(DWORD(*mCVar));
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool MenuEvent (int mkey, bool fromcontroller)
|
||||
{
|
||||
int &mSelectedItem = mDesc->mSelectedItem;
|
||||
|
||||
switch (mkey)
|
||||
{
|
||||
case MKEY_Down:
|
||||
if (mSelectedItem == mStartItem+6) // last valid item
|
||||
{
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
|
||||
mGridPosY = 0;
|
||||
// let it point to the last static item so that the super class code still has a valid item
|
||||
mSelectedItem = mStartItem+7;
|
||||
return true;
|
||||
}
|
||||
else if (mSelectedItem == mStartItem+7)
|
||||
{
|
||||
if (mGridPosY < 15)
|
||||
{
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
|
||||
mGridPosY++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case MKEY_Up:
|
||||
if (mSelectedItem == mStartItem+7)
|
||||
{
|
||||
if (mGridPosY > 0)
|
||||
{
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
|
||||
mGridPosY--;
|
||||
}
|
||||
else
|
||||
{
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
|
||||
mSelectedItem = mStartItem+6;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case MKEY_Left:
|
||||
if (mSelectedItem == mStartItem+7)
|
||||
{
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
|
||||
if (--mGridPosX < 0) mGridPosX = 15;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case MKEY_Right:
|
||||
if (mSelectedItem == mStartItem+7)
|
||||
{
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
|
||||
if (++mGridPosX > 15) mGridPosX = 0;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case MKEY_Enter:
|
||||
if (mSelectedItem == mStartItem+7)
|
||||
{
|
||||
// Choose selected palette entry
|
||||
int index = mGridPosX + mGridPosY * 16;
|
||||
mRed = GPalette.BaseColors[index].r;
|
||||
mGreen = GPalette.BaseColors[index].g;
|
||||
mBlue = GPalette.BaseColors[index].b;
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (mSelectedItem >= 0 && mSelectedItem < mStartItem+7)
|
||||
{
|
||||
if (mDesc->mItems[mDesc->mSelectedItem]->MenuEvent(mkey, fromcontroller)) return true;
|
||||
}
|
||||
return Super::MenuEvent(mkey, fromcontroller);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool MouseEvent(int type, int mx, int my)
|
||||
{
|
||||
int olditem = mDesc->mSelectedItem;
|
||||
bool res = Super::MouseEvent(type, mx, my);
|
||||
|
||||
if (mDesc->mSelectedItem == -1 || mDesc->mSelectedItem == mStartItem+7)
|
||||
{
|
||||
int y = (-mDesc->mPosition + BigFont->GetHeight() + mDesc->mItems.Size() * OptionSettings.mLinespacing) * CleanYfac_1;
|
||||
int h = (screen->GetHeight() - y) / 16;
|
||||
int fh = OptionSettings.mLinespacing * CleanYfac_1;
|
||||
int w = fh;
|
||||
int yy = y + 2 * CleanYfac_1;
|
||||
int indent = (screen->GetWidth() / 2);
|
||||
|
||||
if (h > fh) h = fh;
|
||||
else if (h < 4) return res; // no space to draw it.
|
||||
|
||||
int box_y = y - 2 * CleanYfac_1;
|
||||
int box_x = indent - 16*w;
|
||||
|
||||
if (mx >= box_x && mx < box_x + 16*w && my >= box_y && my < box_y + 16*h)
|
||||
{
|
||||
int cell_x = (mx - box_x) / w;
|
||||
int cell_y = (my - box_y) / h;
|
||||
|
||||
if (olditem != mStartItem+7 || cell_x != mGridPosX || cell_y != mGridPosY)
|
||||
{
|
||||
mGridPosX = cell_x;
|
||||
mGridPosY = cell_y;
|
||||
//S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
|
||||
}
|
||||
mDesc->mSelectedItem = mStartItem+7;
|
||||
if (type == MOUSE_Release)
|
||||
{
|
||||
MenuEvent(MKEY_Enter, true);
|
||||
if (m_use_mouse == 2) mDesc->mSelectedItem = -1;
|
||||
}
|
||||
res = true;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void Drawer()
|
||||
{
|
||||
Super::Drawer();
|
||||
|
||||
if (mCVar == NULL) return;
|
||||
int y = (-mDesc->mPosition + BigFont->GetHeight() + mDesc->mItems.Size() * OptionSettings.mLinespacing) * CleanYfac_1;
|
||||
int h = (screen->GetHeight() - y) / 16;
|
||||
int fh = OptionSettings.mLinespacing * CleanYfac_1;
|
||||
int w = fh;
|
||||
int yy = y;
|
||||
|
||||
if (h > fh) h = fh;
|
||||
else if (h < 4) return; // no space to draw it.
|
||||
|
||||
int indent = (screen->GetWidth() / 2);
|
||||
int p = 0;
|
||||
|
||||
for(int i = 0; i < 16; i++, y += h)
|
||||
{
|
||||
int box_x, box_y;
|
||||
int x1;
|
||||
|
||||
box_y = y - 2 * CleanYfac_1;
|
||||
box_x = indent - 16*w;
|
||||
for (x1 = 0; x1 < 16; ++x1, p++)
|
||||
{
|
||||
screen->Clear (box_x, box_y, box_x + w, box_y + h, p, 0);
|
||||
if ((mDesc->mSelectedItem == mStartItem+7) &&
|
||||
(/*p == CurrColorIndex ||*/ (i == mGridPosY && x1 == mGridPosX)))
|
||||
{
|
||||
int r, g, b;
|
||||
DWORD col;
|
||||
double blinky;
|
||||
if (i == mGridPosY && x1 == mGridPosX)
|
||||
{
|
||||
r = 255, g = 128, b = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
r = 200, g = 200, b = 255;
|
||||
}
|
||||
// Make sure the cursors stand out against similar colors
|
||||
// by pulsing them.
|
||||
blinky = fabs(sin(I_MSTime()/1000.0)) * 0.5 + 0.5;
|
||||
col = MAKEARGB(255,int(r*blinky),int(g*blinky),int(b*blinky));
|
||||
|
||||
screen->Clear (box_x, box_y, box_x + w, box_y + 1, -1, col);
|
||||
screen->Clear (box_x, box_y + h-1, box_x + w, box_y + h, -1, col);
|
||||
screen->Clear (box_x, box_y, box_x + 1, box_y + h, -1, col);
|
||||
screen->Clear (box_x + w - 1, box_y, box_x + w, box_y + h, -1, col);
|
||||
}
|
||||
box_x += w;
|
||||
}
|
||||
}
|
||||
y = yy;
|
||||
DWORD newColor = MAKEARGB(255, int(mRed), int(mGreen), int(mBlue));
|
||||
DWORD oldColor = DWORD(*mCVar) | 0xFF000000;
|
||||
|
||||
int x = screen->GetWidth()*2/3;
|
||||
|
||||
screen->Clear (x, y, x + 48*CleanXfac_1, y + 48*CleanYfac_1, -1, oldColor);
|
||||
screen->Clear (x + 48*CleanXfac_1, y, x + 48*2*CleanXfac_1, y + 48*CleanYfac_1, -1, newColor);
|
||||
|
||||
y += 49*CleanYfac_1;
|
||||
screen->DrawText (SmallFont, CR_GRAY, x+(24-SmallFont->StringWidth("Old")/2)*CleanXfac_1, y,
|
||||
"Old", DTA_CleanNoMove_1, true, TAG_DONE);
|
||||
screen->DrawText (SmallFont, CR_WHITE, x+(48+24-SmallFont->StringWidth("New")/2)*CleanXfac_1, y,
|
||||
"New", DTA_CleanNoMove_1, true, TAG_DONE);
|
||||
}
|
||||
};
|
||||
|
||||
IMPLEMENT_ABSTRACT_CLASS(DColorPickerMenu)
|
||||
|
||||
CCMD(undocolorpic)
|
||||
{
|
||||
if (DMenu::CurrentMenu != NULL && DMenu::CurrentMenu->IsKindOf(RUNTIME_CLASS(DColorPickerMenu)))
|
||||
{
|
||||
static_cast<DColorPickerMenu*>(DMenu::CurrentMenu)->Reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DMenu *StartPickerMenu(DMenu *parent, const char *name, FColorCVar *cvar)
|
||||
{
|
||||
FMenuDescriptor **desc = MenuDescriptors.CheckKey(NAME_Colorpickermenu);
|
||||
if (desc != NULL && (*desc)->mType == MDESC_OptionsMenu)
|
||||
{
|
||||
return new DColorPickerMenu(parent, name, (FOptionMenuDescriptor*)(*desc), cvar);
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
420
src/menu/joystickmenu.cpp
Normal file
420
src/menu/joystickmenu.cpp
Normal file
|
@ -0,0 +1,420 @@
|
|||
/*
|
||||
** joystickmenu.cpp
|
||||
** The joystick configuration menus
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2010 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include <float.h>
|
||||
|
||||
#include "menu/menu.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "w_wad.h"
|
||||
#include "sc_man.h"
|
||||
#include "v_font.h"
|
||||
#include "g_level.h"
|
||||
#include "d_player.h"
|
||||
#include "v_video.h"
|
||||
#include "gi.h"
|
||||
#include "i_system.h"
|
||||
#include "c_bind.h"
|
||||
#include "v_palette.h"
|
||||
#include "d_event.h"
|
||||
#include "d_gui.h"
|
||||
#include "i_music.h"
|
||||
#include "m_joy.h"
|
||||
|
||||
#define NO_IMP
|
||||
#include "optionmenuitems.h"
|
||||
|
||||
|
||||
static TArray<IJoystickConfig *> Joysticks;
|
||||
IJoystickConfig *SELECTED_JOYSTICK;
|
||||
|
||||
FOptionMenuDescriptor *UpdateJoystickConfigMenu(IJoystickConfig *joy);
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class FOptionMenuSliderJoySensitivity : public FOptionMenuSliderBase
|
||||
{
|
||||
public:
|
||||
FOptionMenuSliderJoySensitivity(const char *label, double min, double max, double step, int showval)
|
||||
: FOptionMenuSliderBase(label, min, max, step, showval)
|
||||
{
|
||||
}
|
||||
|
||||
double GetValue()
|
||||
{
|
||||
return SELECTED_JOYSTICK->GetSensitivity();
|
||||
}
|
||||
|
||||
void SetValue(double val)
|
||||
{
|
||||
SELECTED_JOYSTICK->SetSensitivity(float(val));
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class FOptionMenuSliderJoyScale : public FOptionMenuSliderBase
|
||||
{
|
||||
int mAxis;
|
||||
int mNeg;
|
||||
|
||||
public:
|
||||
FOptionMenuSliderJoyScale(const char *label, int axis, double min, double max, double step, int showval)
|
||||
: FOptionMenuSliderBase(label, min, max, step, showval)
|
||||
{
|
||||
mAxis = axis;
|
||||
mNeg = 1;
|
||||
}
|
||||
|
||||
double GetValue()
|
||||
{
|
||||
double d = SELECTED_JOYSTICK->GetAxisScale(mAxis);
|
||||
mNeg = d < 0? -1:1;
|
||||
return d;
|
||||
}
|
||||
|
||||
void SetValue(double val)
|
||||
{
|
||||
SELECTED_JOYSTICK->SetAxisScale(mAxis, float(val * mNeg));
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class FOptionMenuSliderJoyDeadZone : public FOptionMenuSliderBase
|
||||
{
|
||||
int mAxis;
|
||||
int mNeg;
|
||||
|
||||
public:
|
||||
FOptionMenuSliderJoyDeadZone(const char *label, int axis, double min, double max, double step, int showval)
|
||||
: FOptionMenuSliderBase(label, min, max, step, showval)
|
||||
{
|
||||
mAxis = axis;
|
||||
mNeg = 1;
|
||||
}
|
||||
|
||||
double GetValue()
|
||||
{
|
||||
double d = SELECTED_JOYSTICK->GetAxisDeadZone(mAxis);
|
||||
mNeg = d < 0? -1:1;
|
||||
return d;
|
||||
}
|
||||
|
||||
void SetValue(double val)
|
||||
{
|
||||
SELECTED_JOYSTICK->SetAxisDeadZone(mAxis, float(val * mNeg));
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class FOptionMenuItemJoyMap : public FOptionMenuItemOptionBase
|
||||
{
|
||||
int mAxis;
|
||||
public:
|
||||
|
||||
FOptionMenuItemJoyMap(const char *label, int axis, const char *values, int center)
|
||||
: FOptionMenuItemOptionBase(label, "none", values, NULL, center)
|
||||
{
|
||||
mAxis = axis;
|
||||
}
|
||||
|
||||
int GetSelection()
|
||||
{
|
||||
float f = (float)(int)SELECTED_JOYSTICK->GetAxisMap(mAxis);
|
||||
for(unsigned i=0;i<mValues->mValues.Size(); i++)
|
||||
{
|
||||
if (fabs(f - mValues->mValues[i].Value) < FLT_EPSILON)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void SetSelection(int Selection)
|
||||
{
|
||||
SELECTED_JOYSTICK->SetAxisMap(mAxis, (EJoyAxis)Selection);
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class FOptionMenuItemInverter : public FOptionMenuItemOptionBase
|
||||
{
|
||||
int mAxis;
|
||||
public:
|
||||
|
||||
FOptionMenuItemInverter(const char *label, int axis, int center)
|
||||
: FOptionMenuItemOptionBase(label, "none", "YesNo", NULL, center)
|
||||
{
|
||||
mAxis = axis;
|
||||
}
|
||||
|
||||
int GetSelection()
|
||||
{
|
||||
float f = SELECTED_JOYSTICK->GetAxisScale(mAxis);
|
||||
return f > 0? 0:1;
|
||||
}
|
||||
|
||||
void SetSelection(int Selection)
|
||||
{
|
||||
float f = fabs(SELECTED_JOYSTICK->GetAxisScale(mAxis));
|
||||
if (Selection) f*=-1;
|
||||
SELECTED_JOYSTICK->SetAxisScale(mAxis, f);
|
||||
}
|
||||
};
|
||||
|
||||
class DJoystickConfigMenu : public DOptionMenu
|
||||
{
|
||||
DECLARE_CLASS(DJoystickConfigMenu, DOptionMenu)
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(DJoystickConfigMenu)
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Executes a CCMD, action is a CCMD name
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class FOptionMenuItemJoyConfigMenu : public FOptionMenuItemSubmenu
|
||||
{
|
||||
IJoystickConfig *mJoy;
|
||||
public:
|
||||
FOptionMenuItemJoyConfigMenu(const char *label, IJoystickConfig *joy)
|
||||
: FOptionMenuItemSubmenu(label, "JoystickConfigMenu")
|
||||
{
|
||||
mJoy = joy;
|
||||
}
|
||||
|
||||
bool Activate()
|
||||
{
|
||||
UpdateJoystickConfigMenu(mJoy);
|
||||
return FOptionMenuItemSubmenu::Activate();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*=======================================
|
||||
*
|
||||
* Joystick Menu
|
||||
*
|
||||
*=======================================*/
|
||||
|
||||
FOptionMenuDescriptor *UpdateJoystickConfigMenu(IJoystickConfig *joy)
|
||||
{
|
||||
FMenuDescriptor **desc = MenuDescriptors.CheckKey(NAME_JoystickConfigMenu);
|
||||
if (desc != NULL && (*desc)->mType == MDESC_OptionsMenu)
|
||||
{
|
||||
FOptionMenuDescriptor *opt = (FOptionMenuDescriptor *)*desc;
|
||||
FOptionMenuItem *it;
|
||||
for(unsigned i=0;i<opt->mItems.Size();i++)
|
||||
{
|
||||
delete opt->mItems[i];
|
||||
opt->mItems.Clear();
|
||||
}
|
||||
opt->mTitle.Format("Configure %s", joy->GetName().GetChars());
|
||||
|
||||
if (joy == NULL)
|
||||
{
|
||||
it = new FOptionMenuItemStaticText("Invalid controller specified for menu", false);
|
||||
opt->mItems.Push(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
SELECTED_JOYSTICK = joy;
|
||||
|
||||
it = new FOptionMenuSliderJoySensitivity("Overall sensitivity", 0, 2, 0.1, 3);
|
||||
opt->mItems.Push(it);
|
||||
it = new FOptionMenuItemStaticText(" ", false);
|
||||
opt->mItems.Push(it);
|
||||
|
||||
if (joy->GetNumAxes() > 0)
|
||||
{
|
||||
it = new FOptionMenuItemStaticText("Axis Configuration", true);
|
||||
opt->mItems.Push(it);
|
||||
|
||||
for (int i = 0; i < joy->GetNumAxes(); ++i)
|
||||
{
|
||||
it = new FOptionMenuItemStaticText(" ", false);
|
||||
opt->mItems.Push(it);
|
||||
|
||||
it = new FOptionMenuItemJoyMap(joy->GetAxisName(i), i, "JoyAxisMapNames", false);
|
||||
opt->mItems.Push(it);
|
||||
it = new FOptionMenuSliderJoyScale("Overall sensitivity", i, 0, 4, 0.1, 3);
|
||||
opt->mItems.Push(it);
|
||||
it = new FOptionMenuItemInverter("Invert", i, false);
|
||||
opt->mItems.Push(it);
|
||||
it = new FOptionMenuSliderJoyDeadZone("Dead Zone", i, 0, 0.9, 0.05, 3);
|
||||
opt->mItems.Push(it);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
it = new FOptionMenuItemStaticText("No configurable axes", false);
|
||||
opt->mItems.Push(it);
|
||||
}
|
||||
}
|
||||
opt->mScrollPos = 0;
|
||||
opt->mSelectedItem = -1;
|
||||
opt->mIndent = 0;
|
||||
opt->mPosition = -25;
|
||||
opt->CalcIndent();
|
||||
return opt;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void UpdateJoystickMenu(IJoystickConfig *selected)
|
||||
{
|
||||
FMenuDescriptor **desc = MenuDescriptors.CheckKey(NAME_JoystickOptions);
|
||||
if (desc != NULL && (*desc)->mType == MDESC_OptionsMenu)
|
||||
{
|
||||
FOptionMenuDescriptor *opt = (FOptionMenuDescriptor *)*desc;
|
||||
FOptionMenuItem *it;
|
||||
for(unsigned i=0;i<opt->mItems.Size();i++)
|
||||
{
|
||||
delete opt->mItems[i];
|
||||
opt->mItems.Clear();
|
||||
}
|
||||
|
||||
int i;
|
||||
int itemnum = -1;
|
||||
|
||||
I_GetJoysticks(Joysticks);
|
||||
if ((unsigned)itemnum >= Joysticks.Size())
|
||||
{
|
||||
itemnum = Joysticks.Size() - 1;
|
||||
}
|
||||
if (selected != NULL)
|
||||
{
|
||||
for (i = 0; (unsigned)i < Joysticks.Size(); ++i)
|
||||
{
|
||||
if (Joysticks[i] == selected)
|
||||
{
|
||||
itemnum = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Todo: Block joystick for changing this one.
|
||||
it = new FOptionMenuItemOption("Enable controller support", "use_joystick", "YesNo", NULL, false);
|
||||
opt->mItems.Push(it);
|
||||
#ifdef _WIN32
|
||||
it = new FOptionMenuItemOption("Enable DirectInput controllers", "joy_dinput", "YesNo", NULL, false);
|
||||
opt->mItems.Push(it);
|
||||
it = new FOptionMenuItemOption("Enable XInput controllers", "joy_xinput", "YesNo", NULL, false);
|
||||
opt->mItems.Push(it);
|
||||
it = new FOptionMenuItemOption("Enable raw PlayStation 2 adapters", "joy_ps2raw", "YesNo", NULL, false);
|
||||
opt->mItems.Push(it);
|
||||
#endif
|
||||
|
||||
it = new FOptionMenuItemStaticText(" ", false);
|
||||
opt->mItems.Push(it);
|
||||
|
||||
if (Joysticks.Size() == 0)
|
||||
{
|
||||
it = new FOptionMenuItemStaticText("No controllers detected", false);
|
||||
opt->mItems.Push(it);
|
||||
if (!use_joystick)
|
||||
{
|
||||
it = new FOptionMenuItemStaticText("Controller support must be", false);
|
||||
opt->mItems.Push(it);
|
||||
it = new FOptionMenuItemStaticText("enabled to detect any", false);
|
||||
opt->mItems.Push(it);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
it = new FOptionMenuItemStaticText("Configure controllers:", false);
|
||||
opt->mItems.Push(it);
|
||||
|
||||
for (int i = 0; i < (int)Joysticks.Size(); ++i)
|
||||
{
|
||||
it = new FOptionMenuItemJoyConfigMenu(Joysticks[i]->GetName(), Joysticks[i]);
|
||||
opt->mItems.Push(it);
|
||||
if (i == itemnum) opt->mSelectedItem = opt->mItems.Size();
|
||||
}
|
||||
}
|
||||
if (opt->mSelectedItem >= (int)opt->mItems.Size())
|
||||
{
|
||||
opt->mSelectedItem = opt->mItems.Size() - 1;
|
||||
}
|
||||
|
||||
opt->CalcIndent();
|
||||
|
||||
// If the joystick config menu is open, close it if the device it's
|
||||
// open for is gone.
|
||||
for (i = 0; (unsigned)i < Joysticks.Size(); ++i)
|
||||
{
|
||||
if (Joysticks[i] == SELECTED_JOYSTICK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == (int)Joysticks.Size())
|
||||
{
|
||||
SELECTED_JOYSTICK = NULL;
|
||||
if (DMenu::CurrentMenu != NULL && DMenu::CurrentMenu->IsKindOf(RUNTIME_CLASS(DJoystickConfigMenu)))
|
||||
{
|
||||
DMenu::CurrentMenu->Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
511
src/menu/listmenu.cpp
Normal file
511
src/menu/listmenu.cpp
Normal file
|
@ -0,0 +1,511 @@
|
|||
/*
|
||||
** listmenu.cpp
|
||||
** A simple menu consisting of a list of items
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2010 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "v_video.h"
|
||||
#include "v_font.h"
|
||||
#include "cmdlib.h"
|
||||
#include "gstrings.h"
|
||||
#include "g_level.h"
|
||||
#include "gi.h"
|
||||
#include "d_gui.h"
|
||||
#include "d_event.h"
|
||||
#include "menu/menu.h"
|
||||
|
||||
IMPLEMENT_CLASS(DListMenu)
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
DListMenu::DListMenu(DMenu *parent, FListMenuDescriptor *desc)
|
||||
: DMenu(parent)
|
||||
{
|
||||
mDesc = desc;
|
||||
mFocusControl = NULL;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void DListMenu::Init(DMenu *parent, FListMenuDescriptor *desc)
|
||||
{
|
||||
mParentMenu = parent;
|
||||
GC::WriteBarrier(this, parent);
|
||||
mDesc = desc;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
FListMenuItem *DListMenu::GetItem(FName name)
|
||||
{
|
||||
for(unsigned i=0;i<mDesc->mItems.Size(); i++)
|
||||
{
|
||||
FName nm = mDesc->mItems[i]->GetAction(NULL);
|
||||
if (nm == name) return mDesc->mItems[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool DListMenu::Responder (event_t *ev)
|
||||
{
|
||||
if (ev->type == EV_GUI_Event)
|
||||
{
|
||||
if (ev->subtype == EV_GUI_KeyDown)
|
||||
{
|
||||
int ch = tolower (ev->data1);
|
||||
|
||||
for(unsigned i = mDesc->mSelectedItem + 1; i < mDesc->mItems.Size(); i++)
|
||||
{
|
||||
if (mDesc->mItems[i]->CheckHotkey(ch))
|
||||
{
|
||||
mDesc->mSelectedItem = i;
|
||||
S_Sound(CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < mDesc->mSelectedItem; i++)
|
||||
{
|
||||
if (mDesc->mItems[i]->CheckHotkey(ch))
|
||||
{
|
||||
mDesc->mSelectedItem = i;
|
||||
S_Sound(CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Super::Responder(ev);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool DListMenu::MenuEvent (int mkey, bool fromcontroller)
|
||||
{
|
||||
int startedAt = mDesc->mSelectedItem;
|
||||
|
||||
switch (mkey)
|
||||
{
|
||||
case MKEY_Up:
|
||||
do
|
||||
{
|
||||
if (--mDesc->mSelectedItem < 0) mDesc->mSelectedItem = mDesc->mItems.Size()-1;
|
||||
}
|
||||
while (!mDesc->mItems[mDesc->mSelectedItem]->Selectable() && mDesc->mSelectedItem != startedAt);
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
|
||||
return true;
|
||||
|
||||
case MKEY_Down:
|
||||
do
|
||||
{
|
||||
if (++mDesc->mSelectedItem >= (int)mDesc->mItems.Size()) mDesc->mSelectedItem = 0;
|
||||
}
|
||||
while (!mDesc->mItems[mDesc->mSelectedItem]->Selectable() && mDesc->mSelectedItem != startedAt);
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
|
||||
return true;
|
||||
|
||||
case MKEY_Enter:
|
||||
if (mDesc->mSelectedItem >= 0 && mDesc->mItems[mDesc->mSelectedItem]->Activate())
|
||||
{
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE);
|
||||
}
|
||||
return true;
|
||||
|
||||
default:
|
||||
return Super::MenuEvent(mkey, fromcontroller);
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool DListMenu::MouseEvent(int type, int x, int y)
|
||||
{
|
||||
int sel = -1;
|
||||
|
||||
// convert x/y from screen to virtual coordinates, according to CleanX/Yfac use in DrawTexture
|
||||
x = ((x - (screen->GetWidth() / 2)) / CleanXfac) + 160;
|
||||
y = ((y - (screen->GetHeight() / 2)) / CleanYfac) + 100;
|
||||
|
||||
if (mFocusControl != NULL)
|
||||
{
|
||||
mFocusControl->MouseEvent(type, x, y);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((mDesc->mWLeft <= 0 || x > mDesc->mWLeft) &&
|
||||
(mDesc->mWRight <= 0 || x < mDesc->mWRight))
|
||||
{
|
||||
for(unsigned i=0;i<mDesc->mItems.Size(); i++)
|
||||
{
|
||||
if (mDesc->mItems[i]->CheckCoordinate(x, y))
|
||||
{
|
||||
if (i != mDesc->mSelectedItem)
|
||||
{
|
||||
//S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
|
||||
}
|
||||
mDesc->mSelectedItem = i;
|
||||
mDesc->mItems[i]->MouseEvent(type, x, y);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mDesc->mSelectedItem = -1;
|
||||
return Super::MouseEvent(type, x, y);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void DListMenu::Ticker ()
|
||||
{
|
||||
Super::Ticker();
|
||||
for(unsigned i=0;i<mDesc->mItems.Size(); i++)
|
||||
{
|
||||
mDesc->mItems[i]->Ticker();
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void DListMenu::Drawer ()
|
||||
{
|
||||
for(unsigned i=0;i<mDesc->mItems.Size(); i++)
|
||||
{
|
||||
if (mDesc->mItems[i]->mEnabled) mDesc->mItems[i]->Drawer(mDesc->mSelectedItem == i);
|
||||
}
|
||||
if (mDesc->mSelectedItem >= 0 && mDesc->mSelectedItem < (int)mDesc->mItems.Size())
|
||||
mDesc->mItems[mDesc->mSelectedItem]->DrawSelector(mDesc->mSelectOfsX, mDesc->mSelectOfsY, mDesc->mSelector);
|
||||
Super::Drawer();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// base class for menu items
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
FListMenuItem::~FListMenuItem()
|
||||
{
|
||||
}
|
||||
|
||||
bool FListMenuItem::CheckCoordinate(int x, int y)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void FListMenuItem::Ticker()
|
||||
{
|
||||
}
|
||||
|
||||
void FListMenuItem::Drawer(bool selected)
|
||||
{
|
||||
}
|
||||
|
||||
bool FListMenuItem::Selectable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void FListMenuItem::DrawSelector(int xofs, int yofs, FTextureID tex)
|
||||
{
|
||||
if (tex.isNull())
|
||||
{
|
||||
if ((DMenu::MenuTime%8) < 6)
|
||||
{
|
||||
screen->DrawText(ConFont, OptionSettings.mFontColorSelection,
|
||||
mXpos + xofs, mYpos + yofs, "\xd", DTA_Clean, true, TAG_DONE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
screen->DrawTexture (TexMan(tex), mXpos + xofs, mYpos + yofs, DTA_Clean, true, TAG_DONE);
|
||||
}
|
||||
}
|
||||
|
||||
bool FListMenuItem::Activate()
|
||||
{
|
||||
return false; // cannot be activated
|
||||
}
|
||||
|
||||
FName FListMenuItem::GetAction(int *pparam)
|
||||
{
|
||||
return mAction;
|
||||
}
|
||||
|
||||
bool FListMenuItem::SetString(int i, const char *s)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FListMenuItem::GetString(int i, char *s, int len)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FListMenuItem::SetValue(int i, int value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FListMenuItem::GetValue(int i, int *pvalue)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void FListMenuItem::Enable(bool on)
|
||||
{
|
||||
mEnabled = on;
|
||||
}
|
||||
|
||||
bool FListMenuItem::MenuEvent(int mkey, bool fromcontroller)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FListMenuItem::MouseEvent(int type, int x, int y)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FListMenuItem::CheckHotkey(int c)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// static patch
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
FListMenuItemStaticPatch::FListMenuItemStaticPatch(int x, int y, FTextureID patch, bool centered)
|
||||
: FListMenuItem(x, y)
|
||||
{
|
||||
mTexture = patch;
|
||||
mCentered = centered;
|
||||
}
|
||||
|
||||
void FListMenuItemStaticPatch::Drawer(bool selected)
|
||||
{
|
||||
int x = mXpos;
|
||||
FTexture *tex = TexMan(mTexture);
|
||||
if (mYpos >= 0)
|
||||
{
|
||||
if (mCentered) x -= tex->GetScaledWidth()/2;
|
||||
screen->DrawTexture (tex, x, mYpos, DTA_Clean, true, TAG_DONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
int x = (mXpos - 160) * CleanXfac + (SCREENWIDTH>>1);
|
||||
if (mCentered) x -= (tex->GetScaledWidth()*CleanXfac)/2;
|
||||
screen->DrawTexture (tex, x, -mYpos*CleanYfac, DTA_CleanNoMove, true, TAG_DONE);
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// static text
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
FListMenuItemStaticText::FListMenuItemStaticText(int x, int y, const char *text, FFont *font, EColorRange color, bool centered)
|
||||
: FListMenuItem(x, y)
|
||||
{
|
||||
mText = ncopystring(text);
|
||||
mFont = font;
|
||||
mColor = color;
|
||||
mCentered = centered;
|
||||
}
|
||||
|
||||
void FListMenuItemStaticText::Drawer(bool selected)
|
||||
{
|
||||
const char *text = mText;
|
||||
if (text != NULL)
|
||||
{
|
||||
if (*text == '$') text = GStrings(text+1);
|
||||
if (mYpos >= 0)
|
||||
{
|
||||
int x = mXpos;
|
||||
if (mCentered) x -= mFont->StringWidth(text)/2;
|
||||
screen->DrawText(mFont, mColor, x, mYpos, text, DTA_Clean, true, TAG_DONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
int x = (mXpos - 160) * CleanXfac + (SCREENWIDTH>>1);
|
||||
if (mCentered) x -= (mFont->StringWidth(text)*CleanXfac)/2;
|
||||
screen->DrawText (mFont, mColor, x, -mYpos*CleanYfac, text, DTA_CleanNoMove, true, TAG_DONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FListMenuItemStaticText::~FListMenuItemStaticText()
|
||||
{
|
||||
if (mText != NULL) delete [] mText;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// base class for selectable items
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
FListMenuItemSelectable::FListMenuItemSelectable(int x, int y, int height, FName action, int param)
|
||||
: FListMenuItem(x, y, action)
|
||||
{
|
||||
mHeight = height;
|
||||
mParam = param;
|
||||
mHotkey = 0;
|
||||
}
|
||||
|
||||
bool FListMenuItemSelectable::CheckCoordinate(int x, int y)
|
||||
{
|
||||
return mEnabled && y >= mYpos && y < mYpos + mHeight; // no x check here
|
||||
}
|
||||
|
||||
bool FListMenuItemSelectable::Selectable()
|
||||
{
|
||||
return mEnabled;
|
||||
}
|
||||
|
||||
bool FListMenuItemSelectable::Activate()
|
||||
{
|
||||
M_SetMenu(mAction, mParam);
|
||||
return true;
|
||||
}
|
||||
|
||||
FName FListMenuItemSelectable::GetAction(int *pparam)
|
||||
{
|
||||
if (pparam != NULL) *pparam = mParam;
|
||||
return mAction;
|
||||
}
|
||||
|
||||
bool FListMenuItemSelectable::CheckHotkey(int c)
|
||||
{
|
||||
return c == tolower(mHotkey);
|
||||
}
|
||||
|
||||
bool FListMenuItemSelectable::MouseEvent(int type, int x, int y)
|
||||
{
|
||||
if (type == DMenu::MOUSE_Release)
|
||||
{
|
||||
if (DMenu::CurrentMenu->MenuEvent(MKEY_Enter, true))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// text item
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
FListMenuItemText::FListMenuItemText(int x, int y, int height, int hotkey, const char *text, FFont *font, EColorRange color, FName child, int param)
|
||||
: FListMenuItemSelectable(x, y, height, child, param)
|
||||
{
|
||||
mText = ncopystring(text);
|
||||
mFont = font;
|
||||
mColor = color;
|
||||
mHotkey = hotkey;
|
||||
}
|
||||
|
||||
FListMenuItemText::~FListMenuItemText()
|
||||
{
|
||||
if (mText != NULL)
|
||||
{
|
||||
delete [] mText;
|
||||
}
|
||||
}
|
||||
|
||||
void FListMenuItemText::Drawer(bool selected)
|
||||
{
|
||||
const char *text = mText;
|
||||
if (text != NULL)
|
||||
{
|
||||
if (*text == '$') text = GStrings(text+1);
|
||||
screen->DrawText(mFont, mColor, mXpos, mYpos, text, DTA_Clean, true, TAG_DONE);
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// patch item
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
FListMenuItemPatch::FListMenuItemPatch(int x, int y, int height, int hotkey, FTextureID patch, FName child, int param)
|
||||
: FListMenuItemSelectable(x, y, height, child, param)
|
||||
{
|
||||
mHotkey = hotkey;
|
||||
mTexture = patch;
|
||||
}
|
||||
|
||||
void FListMenuItemPatch::Drawer(bool selected)
|
||||
{
|
||||
screen->DrawTexture (TexMan(mTexture), mXpos, mYpos, DTA_Clean, true, TAG_DONE);
|
||||
}
|
1165
src/menu/loadsavemenu.cpp
Normal file
1165
src/menu/loadsavemenu.cpp
Normal file
File diff suppressed because it is too large
Load diff
949
src/menu/menu.cpp
Normal file
949
src/menu/menu.cpp
Normal file
|
@ -0,0 +1,949 @@
|
|||
/*
|
||||
** menu.cpp
|
||||
** Menu base class and global interface
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2010 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "doomstat.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "d_gui.h"
|
||||
#include "d_player.h"
|
||||
#include "g_level.h"
|
||||
#include "c_console.h"
|
||||
#include "c_bind.h"
|
||||
#include "s_sound.h"
|
||||
#include "p_tick.h"
|
||||
#include "g_game.h"
|
||||
#include "c_cvars.h"
|
||||
#include "d_event.h"
|
||||
#include "v_video.h"
|
||||
#include "hu_stuff.h"
|
||||
#include "gi.h"
|
||||
#include "i_input.h"
|
||||
#include "gameconfigfile.h"
|
||||
#include "gstrings.h"
|
||||
#include "r_main.h"
|
||||
#include "menu/menu.h"
|
||||
#include "textures/textures.h"
|
||||
|
||||
//
|
||||
// Todo: Move these elsewhere
|
||||
//
|
||||
CVAR (Float, mouse_sensitivity, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR (Bool, show_messages, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR (Bool, show_obituaries, true, CVAR_ARCHIVE)
|
||||
|
||||
|
||||
CVAR (Float, snd_menuvolume, 0.6f, CVAR_ARCHIVE)
|
||||
CVAR(Int, m_use_mouse, 1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR(Int, m_show_backbutton, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
|
||||
DMenu *DMenu::CurrentMenu;
|
||||
int DMenu::MenuTime;
|
||||
|
||||
FListMenuDescriptor *MainMenu;
|
||||
FGameStartup GameStartupInfo;
|
||||
EMenuState menuactive;
|
||||
bool M_DemoNoPlay;
|
||||
FButtonStatus MenuButtons[NUM_MKEYS];
|
||||
int MenuButtonTickers[NUM_MKEYS];
|
||||
bool MenuButtonOrigin[NUM_MKEYS];
|
||||
int BackbuttonTime;
|
||||
fixed_t BackbuttonAlpha;
|
||||
|
||||
|
||||
#define KEY_REPEAT_DELAY (TICRATE*5/12)
|
||||
#define KEY_REPEAT_RATE (3)
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// DMenu base class
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
IMPLEMENT_POINTY_CLASS (DMenu)
|
||||
DECLARE_POINTER(mParentMenu)
|
||||
END_POINTERS
|
||||
|
||||
DMenu::DMenu(DMenu *parent)
|
||||
{
|
||||
mParentMenu = parent;
|
||||
mMouseCapture = false;
|
||||
mBackbuttonSelected = false;
|
||||
GC::WriteBarrier(this, parent);
|
||||
}
|
||||
|
||||
bool DMenu::Responder (event_t *ev)
|
||||
{
|
||||
if (ev->type == EV_GUI_Event)
|
||||
{
|
||||
if (ev->subtype == EV_GUI_LButtonDown)
|
||||
{
|
||||
MouseEventBack(MOUSE_Click, ev->data1, ev->data2);
|
||||
if (MouseEvent(MOUSE_Click, ev->data1, ev->data2))
|
||||
{
|
||||
SetCapture();
|
||||
}
|
||||
|
||||
}
|
||||
else if (ev->subtype == EV_GUI_MouseMove)
|
||||
{
|
||||
BackbuttonTime = BACKBUTTON_TIME;
|
||||
if (mMouseCapture || m_use_mouse == 1)
|
||||
{
|
||||
MouseEventBack(MOUSE_Move, ev->data1, ev->data2);
|
||||
return MouseEvent(MOUSE_Move, ev->data1, ev->data2);
|
||||
}
|
||||
}
|
||||
else if (ev->subtype == EV_GUI_LButtonUp)
|
||||
{
|
||||
if (mMouseCapture)
|
||||
{
|
||||
ReleaseCapture();
|
||||
MouseEventBack(MOUSE_Release, ev->data1, ev->data2);
|
||||
return MouseEvent(MOUSE_Release, ev->data1, ev->data2);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool DMenu::MenuEvent (int mkey, bool fromcontroller)
|
||||
{
|
||||
switch (mkey)
|
||||
{
|
||||
case MKEY_Back:
|
||||
{
|
||||
Close();
|
||||
S_Sound (CHAN_VOICE | CHAN_UI,
|
||||
DMenu::CurrentMenu != NULL? "menu/backup" : "menu/clear", snd_menuvolume, ATTN_NONE);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void DMenu::Close ()
|
||||
{
|
||||
assert(DMenu::CurrentMenu == this);
|
||||
DMenu::CurrentMenu = mParentMenu;
|
||||
Destroy();
|
||||
if (DMenu::CurrentMenu != NULL)
|
||||
{
|
||||
GC::WriteBarrier(DMenu::CurrentMenu);
|
||||
}
|
||||
else
|
||||
{
|
||||
M_ClearMenus ();
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool DMenu::MouseEvent(int type, int x, int y)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool DMenu::MouseEventBack(int type, int x, int y)
|
||||
{
|
||||
if (m_show_backbutton >= 0)
|
||||
{
|
||||
FTexture *tex = TexMan[gameinfo.mBackButton];
|
||||
if (tex != NULL)
|
||||
{
|
||||
if (m_show_backbutton&1) x -= screen->GetWidth() - tex->GetScaledWidth() * CleanXfac;
|
||||
if (m_show_backbutton&2) y -= screen->GetHeight() - tex->GetScaledHeight() * CleanYfac;
|
||||
mBackbuttonSelected = (x >= 0 && x < tex->GetScaledWidth() * CleanXfac && y < tex->GetScaledHeight() * CleanYfac);
|
||||
if (mBackbuttonSelected && type == MOUSE_Release)
|
||||
{
|
||||
if (m_use_mouse == 2) mBackbuttonSelected = false;
|
||||
MenuEvent(MKEY_Back, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void DMenu::SetCapture()
|
||||
{
|
||||
if (!mMouseCapture)
|
||||
{
|
||||
mMouseCapture = true;
|
||||
I_SetMouseCapture();
|
||||
}
|
||||
}
|
||||
|
||||
void DMenu::ReleaseCapture()
|
||||
{
|
||||
if (mMouseCapture)
|
||||
{
|
||||
mMouseCapture = false;
|
||||
I_ReleaseMouseCapture();
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void DMenu::Ticker ()
|
||||
{
|
||||
}
|
||||
|
||||
void DMenu::Drawer ()
|
||||
{
|
||||
if (this == DMenu::CurrentMenu && BackbuttonAlpha > 0 && m_show_backbutton >= 0 && m_use_mouse)
|
||||
{
|
||||
FTexture *tex = TexMan[gameinfo.mBackButton];
|
||||
int w = tex->GetScaledWidth() * CleanXfac;
|
||||
int h = tex->GetScaledHeight() * CleanYfac;
|
||||
int x = (!(m_show_backbutton&1))? 0:screen->GetWidth() - w;
|
||||
int y = (!(m_show_backbutton&2))? 0:screen->GetHeight() - h;
|
||||
if (mBackbuttonSelected && (mMouseCapture || m_use_mouse == 1))
|
||||
{
|
||||
screen->DrawTexture(tex, x, y, DTA_CleanNoMove, true, DTA_ColorOverlay, MAKEARGB(40, 255,255,255), TAG_DONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
screen->DrawTexture(tex, x, y, DTA_CleanNoMove, true, DTA_Alpha, BackbuttonAlpha, TAG_DONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DMenu::DimAllowed()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DMenu::TranslateKeyboardEvents()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void M_StartControlPanel (bool makeSound)
|
||||
{
|
||||
// intro might call this repeatedly
|
||||
if (DMenu::CurrentMenu != NULL)
|
||||
return;
|
||||
|
||||
ResetButtonStates ();
|
||||
for (int i = 0; i < NUM_MKEYS; ++i)
|
||||
{
|
||||
MenuButtons[i].ReleaseKey(0);
|
||||
}
|
||||
|
||||
C_HideConsole (); // [RH] Make sure console goes bye bye.
|
||||
menuactive = MENU_On;
|
||||
// Pause sound effects before we play the menu switch sound.
|
||||
// That way, it won't be paused.
|
||||
P_CheckTickerPaused ();
|
||||
|
||||
if (makeSound)
|
||||
{
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", snd_menuvolume, ATTN_NONE);
|
||||
}
|
||||
BackbuttonTime = 0;
|
||||
BackbuttonAlpha = 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void M_ActivateMenu(DMenu *menu)
|
||||
{
|
||||
if (menuactive == MENU_Off) menuactive = MENU_On;
|
||||
if (DMenu::CurrentMenu != NULL) DMenu::CurrentMenu->ReleaseCapture();
|
||||
DMenu::CurrentMenu = menu;
|
||||
GC::WriteBarrier(DMenu::CurrentMenu);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void M_SetMenu(FName menu, int param)
|
||||
{
|
||||
// some menus need some special treatment
|
||||
switch (menu)
|
||||
{
|
||||
case NAME_Episodemenu:
|
||||
// sent from the player class menu
|
||||
GameStartupInfo.Skill = -1;
|
||||
GameStartupInfo.Episode = -1;
|
||||
GameStartupInfo.PlayerClass =
|
||||
param == -1? "Random" : PlayerClasses[param].Type->Meta.GetMetaString (APMETA_DisplayName);
|
||||
break;
|
||||
|
||||
case NAME_Skillmenu:
|
||||
// sent from the episode menu
|
||||
|
||||
if ((gameinfo.flags & GI_SHAREWARE) && param > 0)
|
||||
{
|
||||
// Only Doom and Heretic have multi-episode shareware versions.
|
||||
if (gameinfo.gametype == GAME_Doom)
|
||||
{
|
||||
M_StartMessage(GStrings("SWSTRING"), 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
M_StartMessage(GStrings("MNU_ONLYREGISTERED"), 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
GameStartupInfo.Episode = param;
|
||||
M_StartupSkillMenu(&GameStartupInfo); // needs player class name from class menu (later)
|
||||
break;
|
||||
|
||||
case NAME_StartgameConfirm:
|
||||
{
|
||||
// sent from the skill menu for a skill that needs to be confirmed
|
||||
GameStartupInfo.Skill = param;
|
||||
|
||||
const char *msg = AllSkills[param].MustConfirmText;
|
||||
if (*msg==0) msg = GStrings("NIGHTMARE");
|
||||
M_StartMessage (msg, 0, NAME_Startgame);
|
||||
return;
|
||||
}
|
||||
|
||||
case NAME_Startgame:
|
||||
// sent either from skill menu or confirmation screen. Skill gets only set if sent from skill menu
|
||||
// Now we can finally start the game. Ugh...
|
||||
if (GameStartupInfo.Skill == -1) GameStartupInfo.Skill = param;
|
||||
|
||||
G_DeferedInitNew (&GameStartupInfo);
|
||||
if (gamestate == GS_FULLCONSOLE)
|
||||
{
|
||||
gamestate = GS_HIDECONSOLE;
|
||||
gameaction = ga_newgame;
|
||||
}
|
||||
M_ClearMenus ();
|
||||
return;
|
||||
|
||||
case NAME_Savegamemenu:
|
||||
if (!usergame || (players[consoleplayer].health <= 0 && !multiplayer))
|
||||
{
|
||||
// cannot save outside the game.
|
||||
M_StartMessage (GStrings("SAVEDEAD"), 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// End of special checks
|
||||
|
||||
FMenuDescriptor **desc = MenuDescriptors.CheckKey(menu);
|
||||
if (desc != NULL)
|
||||
{
|
||||
if ((*desc)->mNetgameMessage.IsNotEmpty() && netgame)
|
||||
{
|
||||
M_StartMessage((*desc)->mNetgameMessage, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((*desc)->mType == MDESC_ListMenu)
|
||||
{
|
||||
FListMenuDescriptor *ld = static_cast<FListMenuDescriptor*>(*desc);
|
||||
if (ld->mAutoselect >= 0 && ld->mAutoselect < (int)ld->mItems.Size())
|
||||
{
|
||||
// recursively activate the autoselected item without ever creating this menu.
|
||||
ld->mItems[ld->mAutoselect]->Activate();
|
||||
}
|
||||
else
|
||||
{
|
||||
const PClass *cls = ld->mClass == NULL? RUNTIME_CLASS(DListMenu) : ld->mClass;
|
||||
|
||||
DListMenu *newmenu = (DListMenu *)cls->CreateNew();
|
||||
newmenu->Init(DMenu::CurrentMenu, ld);
|
||||
M_ActivateMenu(newmenu);
|
||||
}
|
||||
}
|
||||
else if ((*desc)->mType == MDESC_OptionsMenu)
|
||||
{
|
||||
FOptionMenuDescriptor *ld = static_cast<FOptionMenuDescriptor*>(*desc);
|
||||
const PClass *cls = ld->mClass == NULL? RUNTIME_CLASS(DOptionMenu) : ld->mClass;
|
||||
|
||||
DOptionMenu *newmenu = (DOptionMenu *)cls->CreateNew();
|
||||
newmenu->Init(DMenu::CurrentMenu, ld);
|
||||
M_ActivateMenu(newmenu);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
const PClass *menuclass = PClass::FindClass(menu);
|
||||
if (menuclass != NULL)
|
||||
{
|
||||
if (menuclass->IsDescendantOf(RUNTIME_CLASS(DMenu)))
|
||||
{
|
||||
DMenu *newmenu = (DMenu*)menuclass->CreateNew();
|
||||
newmenu->mParentMenu = DMenu::CurrentMenu;
|
||||
M_ActivateMenu(newmenu);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
Printf("Attempting to open menu of unknown type '%s'\n", menu.GetChars());
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool M_Responder (event_t *ev)
|
||||
{
|
||||
int ch = 0;
|
||||
bool keyup = false;
|
||||
int mkey = NUM_MKEYS;
|
||||
bool fromcontroller = true;
|
||||
|
||||
if (chatmodeon)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DMenu::CurrentMenu != NULL && menuactive != MENU_Off)
|
||||
{
|
||||
// There are a few input sources we are interested in:
|
||||
//
|
||||
// EV_KeyDown / EV_KeyUp : joysticks/gamepads/controllers
|
||||
// EV_GUI_KeyDown / EV_GUI_KeyUp : the keyboard
|
||||
// EV_GUI_Char : printable characters, which we want in string input mode
|
||||
//
|
||||
// This code previously listened for EV_GUI_KeyRepeat to handle repeating
|
||||
// in the menus, but that doesn't work with gamepads, so now we combine
|
||||
// the multiple inputs into buttons and handle the repetition manually.
|
||||
if (ev->type == EV_GUI_Event)
|
||||
{
|
||||
fromcontroller = false;
|
||||
if (ev->subtype == EV_GUI_KeyRepeat)
|
||||
{
|
||||
// We do our own key repeat handling but still want to eat the
|
||||
// OS's repeated keys.
|
||||
return true;
|
||||
}
|
||||
else if (ev->subtype == EV_GUI_BackButtonDown || ev->subtype == EV_GUI_BackButtonUp)
|
||||
{
|
||||
mkey = MKEY_Back;
|
||||
keyup = ev->subtype == EV_GUI_BackButtonUp;
|
||||
}
|
||||
else if (ev->subtype != EV_GUI_KeyDown && ev->subtype != EV_GUI_KeyUp)
|
||||
{
|
||||
// do we want mouse input?
|
||||
if (ev->subtype >= EV_GUI_FirstMouseEvent && ev->subtype <= EV_GUI_LastMouseEvent)
|
||||
{
|
||||
// FIXME: Mouse events in SDL code are mostly useless so mouse is
|
||||
// disabled until that code is fixed
|
||||
#ifdef _WIN32
|
||||
if (!m_use_mouse)
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
// pass everything else on to the current menu
|
||||
return DMenu::CurrentMenu->Responder(ev);
|
||||
}
|
||||
else if (DMenu::CurrentMenu->TranslateKeyboardEvents())
|
||||
{
|
||||
ch = ev->data1;
|
||||
keyup = ev->subtype == EV_GUI_KeyUp;
|
||||
switch (ch)
|
||||
{
|
||||
case GK_BACK: mkey = MKEY_Back; break;
|
||||
case GK_ESCAPE: mkey = MKEY_Back; break;
|
||||
case GK_RETURN: mkey = MKEY_Enter; break;
|
||||
case GK_UP: mkey = MKEY_Up; break;
|
||||
case GK_DOWN: mkey = MKEY_Down; break;
|
||||
case GK_LEFT: mkey = MKEY_Left; break;
|
||||
case GK_RIGHT: mkey = MKEY_Right; break;
|
||||
case GK_BACKSPACE: mkey = MKEY_Clear; break;
|
||||
case GK_PGUP: mkey = MKEY_PageUp; break;
|
||||
case GK_PGDN: mkey = MKEY_PageDown; break;
|
||||
default:
|
||||
if (!keyup)
|
||||
{
|
||||
return DMenu::CurrentMenu->Responder(ev);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ev->type == EV_KeyDown || ev->type == EV_KeyUp)
|
||||
{
|
||||
keyup = ev->type == EV_KeyUp;
|
||||
|
||||
ch = ev->data1;
|
||||
switch (ch)
|
||||
{
|
||||
case KEY_JOY1:
|
||||
case KEY_PAD_A:
|
||||
mkey = MKEY_Enter;
|
||||
break;
|
||||
|
||||
case KEY_JOY2:
|
||||
case KEY_PAD_B:
|
||||
mkey = MKEY_Back;
|
||||
break;
|
||||
|
||||
case KEY_JOY3:
|
||||
case KEY_PAD_X:
|
||||
mkey = MKEY_Clear;
|
||||
break;
|
||||
|
||||
case KEY_JOY5:
|
||||
case KEY_PAD_LSHOULDER:
|
||||
mkey = MKEY_PageUp;
|
||||
break;
|
||||
|
||||
case KEY_JOY6:
|
||||
case KEY_PAD_RSHOULDER:
|
||||
mkey = MKEY_PageDown;
|
||||
break;
|
||||
|
||||
case KEY_PAD_DPAD_UP:
|
||||
case KEY_PAD_LTHUMB_UP:
|
||||
case KEY_JOYAXIS1MINUS:
|
||||
case KEY_JOYPOV1_UP:
|
||||
mkey = MKEY_Up;
|
||||
break;
|
||||
|
||||
case KEY_PAD_DPAD_DOWN:
|
||||
case KEY_PAD_LTHUMB_DOWN:
|
||||
case KEY_JOYAXIS1PLUS:
|
||||
case KEY_JOYPOV1_DOWN:
|
||||
mkey = MKEY_Down;
|
||||
break;
|
||||
|
||||
case KEY_PAD_DPAD_LEFT:
|
||||
case KEY_PAD_LTHUMB_LEFT:
|
||||
case KEY_JOYAXIS2MINUS:
|
||||
case KEY_JOYPOV1_LEFT:
|
||||
mkey = MKEY_Left;
|
||||
break;
|
||||
|
||||
case KEY_PAD_DPAD_RIGHT:
|
||||
case KEY_PAD_LTHUMB_RIGHT:
|
||||
case KEY_JOYAXIS2PLUS:
|
||||
case KEY_JOYPOV1_RIGHT:
|
||||
mkey = MKEY_Right;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mkey != NUM_MKEYS)
|
||||
{
|
||||
if (keyup)
|
||||
{
|
||||
MenuButtons[mkey].ReleaseKey(ch);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
MenuButtons[mkey].PressKey(ch);
|
||||
MenuButtonOrigin[mkey] = fromcontroller;
|
||||
if (mkey <= MKEY_PageDown)
|
||||
{
|
||||
MenuButtonTickers[mkey] = KEY_REPEAT_DELAY;
|
||||
}
|
||||
DMenu::CurrentMenu->MenuEvent(mkey, fromcontroller);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return DMenu::CurrentMenu->Responder(ev) || !keyup;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ev->type == EV_KeyDown)
|
||||
{
|
||||
// Pop-up menu?
|
||||
if (ev->data1 == KEY_ESCAPE)
|
||||
{
|
||||
M_StartControlPanel(true);
|
||||
M_SetMenu(NAME_Mainmenu, -1);
|
||||
return true;
|
||||
}
|
||||
// If devparm is set, pressing F1 always takes a screenshot no matter
|
||||
// what it's bound to. (for those who don't bother to read the docs)
|
||||
if (devparm && ev->data1 == KEY_F1)
|
||||
{
|
||||
G_ScreenShot(NULL);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (ev->type == EV_GUI_Event && ev->subtype == EV_GUI_LButtonDown &&
|
||||
ConsoleState != c_down && m_use_mouse)
|
||||
{
|
||||
M_StartControlPanel(true);
|
||||
M_SetMenu(NAME_Mainmenu, -1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void M_Ticker (void)
|
||||
{
|
||||
DMenu::MenuTime++;
|
||||
if (DMenu::CurrentMenu != NULL && menuactive != MENU_Off)
|
||||
DMenu::CurrentMenu->Ticker();
|
||||
|
||||
for (int i = 0; i < NUM_MKEYS; ++i)
|
||||
{
|
||||
if (MenuButtons[i].bDown)
|
||||
{
|
||||
if (MenuButtonTickers[i] > 0 && --MenuButtonTickers[i] <= 0)
|
||||
{
|
||||
MenuButtonTickers[i] = KEY_REPEAT_RATE;
|
||||
DMenu::CurrentMenu->MenuEvent(i, MenuButtonOrigin[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (BackbuttonTime > 0)
|
||||
{
|
||||
if (BackbuttonAlpha < FRACUNIT) BackbuttonAlpha += FRACUNIT/10;
|
||||
BackbuttonTime--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (BackbuttonAlpha > 0) BackbuttonAlpha -= FRACUNIT/10;
|
||||
if (BackbuttonAlpha < 0) BackbuttonAlpha = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void M_Drawer (void)
|
||||
{
|
||||
player_t *player = &players[consoleplayer];
|
||||
AActor *camera = player->camera;
|
||||
PalEntry fade = 0;
|
||||
|
||||
if (!screen->Accel2D && camera != NULL && (gamestate == GS_LEVEL || gamestate == GS_TITLELEVEL))
|
||||
{
|
||||
if (camera->player != NULL)
|
||||
{
|
||||
player = camera->player;
|
||||
}
|
||||
fade = PalEntry (BYTE(player->BlendA*255), BYTE(player->BlendR*255), BYTE(player->BlendG*255), BYTE(player->BlendB*255));
|
||||
}
|
||||
|
||||
|
||||
if (DMenu::CurrentMenu != NULL && menuactive != MENU_Off)
|
||||
{
|
||||
if (DMenu::CurrentMenu->DimAllowed()) screen->Dim(fade);
|
||||
DMenu::CurrentMenu->Drawer();
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void M_ClearMenus ()
|
||||
{
|
||||
M_DemoNoPlay = false;
|
||||
if (DMenu::CurrentMenu != NULL)
|
||||
{
|
||||
DMenu::CurrentMenu->Destroy();
|
||||
DMenu::CurrentMenu = NULL;
|
||||
}
|
||||
BorderNeedRefresh = screen->GetPageCount ();
|
||||
menuactive = MENU_Off;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void M_Init (void)
|
||||
{
|
||||
M_ParseMenuDefs();
|
||||
M_CreateMenus();
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// [RH] Most menus can now be accessed directly
|
||||
// through console commands.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
CCMD (menu_main)
|
||||
{
|
||||
M_StartControlPanel(true);
|
||||
M_SetMenu(NAME_Mainmenu, -1);
|
||||
}
|
||||
|
||||
CCMD (menu_load)
|
||||
{ // F3
|
||||
M_StartControlPanel (true);
|
||||
M_SetMenu(NAME_Loadgamemenu, -1);
|
||||
}
|
||||
|
||||
CCMD (menu_save)
|
||||
{ // F2
|
||||
M_StartControlPanel (true);
|
||||
M_SetMenu(NAME_Savegamemenu, -1);
|
||||
}
|
||||
|
||||
CCMD (menu_help)
|
||||
{ // F1
|
||||
M_StartControlPanel (true);
|
||||
M_SetMenu(NAME_Readthismenu, -1);
|
||||
}
|
||||
|
||||
CCMD (menu_game)
|
||||
{
|
||||
M_StartControlPanel (true);
|
||||
M_SetMenu(NAME_Playerclassmenu, -1); // The playerclass menu is the first in the 'start game' chain
|
||||
}
|
||||
|
||||
CCMD (menu_options)
|
||||
{
|
||||
M_StartControlPanel (true);
|
||||
M_SetMenu(NAME_Optionsmenu, -1);
|
||||
}
|
||||
|
||||
CCMD (menu_player)
|
||||
{
|
||||
M_StartControlPanel (true);
|
||||
M_SetMenu(NAME_Playermenu, -1);
|
||||
}
|
||||
|
||||
CCMD (menu_messages)
|
||||
{
|
||||
M_StartControlPanel (true);
|
||||
M_SetMenu(NAME_MessageOptions, -1);
|
||||
}
|
||||
|
||||
CCMD (menu_automap)
|
||||
{
|
||||
M_StartControlPanel (true);
|
||||
M_SetMenu(NAME_AutomapOptions, -1);
|
||||
}
|
||||
|
||||
CCMD (menu_scoreboard)
|
||||
{
|
||||
M_StartControlPanel (true);
|
||||
M_SetMenu(NAME_ScoreboardOptions, -1);
|
||||
}
|
||||
|
||||
CCMD (menu_mapcolors)
|
||||
{
|
||||
M_StartControlPanel (true);
|
||||
M_SetMenu(NAME_MapColorMenu, -1);
|
||||
}
|
||||
|
||||
CCMD (menu_keys)
|
||||
{
|
||||
M_StartControlPanel (true);
|
||||
M_SetMenu(NAME_CustomizeControls, -1);
|
||||
}
|
||||
|
||||
CCMD (menu_gameplay)
|
||||
{
|
||||
M_StartControlPanel (true);
|
||||
M_SetMenu(NAME_GameplayOptions, -1);
|
||||
}
|
||||
|
||||
CCMD (menu_compatibility)
|
||||
{
|
||||
M_StartControlPanel (true);
|
||||
M_SetMenu(NAME_CompatibilityOptions, -1);
|
||||
}
|
||||
|
||||
CCMD (menu_mouse)
|
||||
{
|
||||
M_StartControlPanel (true);
|
||||
M_SetMenu(NAME_MouseOptions, -1);
|
||||
}
|
||||
|
||||
CCMD (menu_joystick)
|
||||
{
|
||||
M_StartControlPanel (true);
|
||||
M_SetMenu(NAME_JoystickOptions, -1);
|
||||
}
|
||||
|
||||
CCMD (menu_sound)
|
||||
{
|
||||
M_StartControlPanel (true);
|
||||
M_SetMenu(NAME_SoundOptions, -1);
|
||||
}
|
||||
|
||||
CCMD (menu_advsound)
|
||||
{
|
||||
M_StartControlPanel (true);
|
||||
M_SetMenu(NAME_AdvSoundOptions, -1);
|
||||
}
|
||||
|
||||
CCMD (menu_modreplayer)
|
||||
{
|
||||
M_StartControlPanel(true);
|
||||
M_SetMenu(NAME_ModReplayerOptions, -1);
|
||||
}
|
||||
|
||||
CCMD (menu_display)
|
||||
{
|
||||
M_StartControlPanel (true);
|
||||
M_SetMenu(NAME_VideoOptions, -1);
|
||||
}
|
||||
|
||||
CCMD (menu_video)
|
||||
{
|
||||
M_StartControlPanel (true);
|
||||
M_SetMenu(NAME_VideoModeMenu, -1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
CCMD (openmenu)
|
||||
{
|
||||
if (argv.argc() < 2)
|
||||
{
|
||||
Printf("Usage: openmenu \"menu_name\"");
|
||||
return;
|
||||
}
|
||||
M_StartControlPanel (true);
|
||||
M_SetMenu(argv[1], -1);
|
||||
}
|
||||
|
||||
//
|
||||
// Toggle messages on/off
|
||||
//
|
||||
CCMD (togglemessages)
|
||||
{
|
||||
if (show_messages)
|
||||
{
|
||||
Printf (128, "%s\n", GStrings("MSGOFF"));
|
||||
show_messages = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf (128, "%s\n", GStrings("MSGON"));
|
||||
show_messages = true;
|
||||
}
|
||||
}
|
||||
|
||||
EXTERN_CVAR (Int, screenblocks)
|
||||
|
||||
CCMD (sizedown)
|
||||
{
|
||||
screenblocks = screenblocks - 1;
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
|
||||
}
|
||||
|
||||
CCMD (sizeup)
|
||||
{
|
||||
screenblocks = screenblocks + 1;
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
|
||||
}
|
||||
|
||||
CCMD(menuconsole)
|
||||
{
|
||||
M_ClearMenus();
|
||||
C_ToggleConsole();
|
||||
}
|
||||
|
||||
CCMD(reset2defaults)
|
||||
{
|
||||
C_SetDefaultBindings ();
|
||||
C_SetCVarsToDefaults ();
|
||||
R_SetViewSize (screenblocks);
|
||||
}
|
||||
|
||||
CCMD(reset2saved)
|
||||
{
|
||||
GameConfig->DoGlobalSetup ();
|
||||
GameConfig->DoGameSetup (GameNames[gameinfo.gametype]);
|
||||
R_SetViewSize (screenblocks);
|
||||
}
|
652
src/menu/menu.h
Normal file
652
src/menu/menu.h
Normal file
|
@ -0,0 +1,652 @@
|
|||
#ifndef __M_MENU_MENU_H__
|
||||
#define __M_MENU_MENU_H__
|
||||
|
||||
|
||||
|
||||
|
||||
#include "dobject.h"
|
||||
#include "lists.h"
|
||||
#include "d_player.h"
|
||||
#include "r_translate.h"
|
||||
#include "c_cvars.h"
|
||||
#include "v_font.h"
|
||||
#include "version.h"
|
||||
#include "textures/textures.h"
|
||||
|
||||
EXTERN_CVAR(Float, snd_menuvolume)
|
||||
EXTERN_CVAR(Int, m_use_mouse);
|
||||
|
||||
|
||||
struct event_t;
|
||||
class FTexture;
|
||||
class FFont;
|
||||
enum EColorRange;
|
||||
class FPlayerClass;
|
||||
class FKeyBindings;
|
||||
|
||||
enum EMenuKey
|
||||
{
|
||||
MKEY_Up,
|
||||
MKEY_Down,
|
||||
MKEY_Left,
|
||||
MKEY_Right,
|
||||
MKEY_PageUp,
|
||||
MKEY_PageDown,
|
||||
//----------------- Keys past here do not repeat.
|
||||
MKEY_Enter,
|
||||
MKEY_Back, // Back to previous menu
|
||||
MKEY_Clear, // Clear keybinding/flip player sprite preview
|
||||
NUM_MKEYS,
|
||||
|
||||
// These are not buttons but events sent from other menus
|
||||
|
||||
MKEY_Input, // Sent when input is confirmed
|
||||
MKEY_Abort, // Input aborted
|
||||
MKEY_MBYes,
|
||||
MKEY_MBNo,
|
||||
};
|
||||
|
||||
|
||||
struct FGameStartup
|
||||
{
|
||||
const char *PlayerClass;
|
||||
int Episode;
|
||||
int Skill;
|
||||
};
|
||||
|
||||
extern FGameStartup GameStartupInfo;
|
||||
|
||||
struct FSaveGameNode : public Node
|
||||
{
|
||||
char Title[SAVESTRINGSIZE];
|
||||
FString Filename;
|
||||
bool bOldVersion;
|
||||
bool bMissingWads;
|
||||
bool bNoDelete;
|
||||
|
||||
FSaveGameNode() { bNoDelete = false; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// menu descriptor. This is created from the menu definition lump
|
||||
// Items must be inserted in the order they are cycled through with the cursor
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
enum EMenuDescriptorType
|
||||
{
|
||||
MDESC_ListMenu,
|
||||
MDESC_OptionsMenu,
|
||||
};
|
||||
|
||||
struct FMenuDescriptor
|
||||
{
|
||||
FName mMenuName;
|
||||
FString mNetgameMessage;
|
||||
int mType;
|
||||
|
||||
virtual ~FMenuDescriptor() {}
|
||||
};
|
||||
|
||||
class FListMenuItem;
|
||||
class FOptionMenuItem;
|
||||
|
||||
struct FListMenuDescriptor : public FMenuDescriptor
|
||||
{
|
||||
TDeletingArray<FListMenuItem *> mItems;
|
||||
int mSelectedItem;
|
||||
int mSelectOfsX;
|
||||
int mSelectOfsY;
|
||||
FTextureID mSelector;
|
||||
int mDisplayTop;
|
||||
int mXpos, mYpos;
|
||||
int mWLeft, mWRight;
|
||||
int mLinespacing; // needs to be stored for dynamically created menus
|
||||
int mAutoselect; // this can only be set by internal menu creation functions
|
||||
FFont *mFont;
|
||||
EColorRange mFontColor;
|
||||
EColorRange mFontColor2;
|
||||
const PClass *mClass;
|
||||
FMenuDescriptor *mRedirect; // used to redirect overlong skill and episode menus to option menu based alternatives
|
||||
};
|
||||
|
||||
struct FOptionMenuSettings
|
||||
{
|
||||
EColorRange mTitleColor;
|
||||
EColorRange mFontColor;
|
||||
EColorRange mFontColorValue;
|
||||
EColorRange mFontColorMore;
|
||||
EColorRange mFontColorHeader;
|
||||
EColorRange mFontColorHighlight;
|
||||
EColorRange mFontColorSelection;
|
||||
int mLinespacing;
|
||||
int mLabelOffset;
|
||||
};
|
||||
|
||||
struct FOptionMenuDescriptor : public FMenuDescriptor
|
||||
{
|
||||
TDeletingArray<FOptionMenuItem *> mItems;
|
||||
FString mTitle;
|
||||
int mSelectedItem;
|
||||
int mDrawTop;
|
||||
int mScrollTop;
|
||||
int mScrollPos;
|
||||
int mIndent;
|
||||
int mPosition;
|
||||
bool mDontDim;
|
||||
const PClass *mClass;
|
||||
|
||||
void CalcIndent();
|
||||
FOptionMenuItem *GetItem(FName name);
|
||||
|
||||
};
|
||||
|
||||
|
||||
typedef TMap<FName, FMenuDescriptor *> MenuDescriptorList;
|
||||
|
||||
extern FOptionMenuSettings OptionSettings;
|
||||
extern MenuDescriptorList MenuDescriptors;
|
||||
|
||||
#define CURSORSPACE (14 * CleanXfac_1)
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
struct FMenuRect
|
||||
{
|
||||
int x, y;
|
||||
int width, height;
|
||||
|
||||
void set(int _x, int _y, int _w, int _h)
|
||||
{
|
||||
x = _x;
|
||||
y = _y;
|
||||
width = _w;
|
||||
height = _h;
|
||||
}
|
||||
|
||||
bool inside(int _x, int _y)
|
||||
{
|
||||
return _x >= x && _x < x+width && _y >= y && _y < y+height;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class DMenu : public DObject
|
||||
{
|
||||
DECLARE_CLASS (DMenu, DObject)
|
||||
HAS_OBJECT_POINTERS
|
||||
|
||||
protected:
|
||||
bool mMouseCapture;
|
||||
bool mBackbuttonSelected;
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
MOUSE_Click,
|
||||
MOUSE_Move,
|
||||
MOUSE_Release
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
BACKBUTTON_TIME = 4*TICRATE
|
||||
};
|
||||
|
||||
static DMenu *CurrentMenu;
|
||||
static int MenuTime;
|
||||
|
||||
TObjPtr<DMenu> mParentMenu;
|
||||
|
||||
DMenu(DMenu *parent = NULL);
|
||||
virtual bool Responder (event_t *ev);
|
||||
virtual bool MenuEvent (int mkey, bool fromcontroller);
|
||||
virtual void Ticker ();
|
||||
virtual void Drawer ();
|
||||
virtual bool DimAllowed ();
|
||||
virtual bool TranslateKeyboardEvents();
|
||||
virtual void Close();
|
||||
virtual bool MouseEvent(int type, int x, int y);
|
||||
bool MouseEventBack(int type, int x, int y);
|
||||
void SetCapture();
|
||||
void ReleaseCapture();
|
||||
bool HasCapture()
|
||||
{
|
||||
return mMouseCapture;
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// base class for menu items
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class FListMenuItem
|
||||
{
|
||||
protected:
|
||||
int mXpos, mYpos;
|
||||
FName mAction;
|
||||
|
||||
public:
|
||||
bool mEnabled;
|
||||
|
||||
FListMenuItem(int xpos = 0, int ypos = 0, FName action = NAME_None)
|
||||
{
|
||||
mXpos = xpos;
|
||||
mYpos = ypos;
|
||||
mAction = action;
|
||||
mEnabled = true;
|
||||
}
|
||||
|
||||
virtual ~FListMenuItem();
|
||||
|
||||
virtual bool CheckCoordinate(int x, int y);
|
||||
virtual void Ticker();
|
||||
virtual void Drawer(bool selected);
|
||||
virtual bool Selectable();
|
||||
virtual bool Activate();
|
||||
virtual FName GetAction(int *pparam);
|
||||
virtual bool SetString(int i, const char *s);
|
||||
virtual bool GetString(int i, char *s, int len);
|
||||
virtual bool SetValue(int i, int value);
|
||||
virtual bool GetValue(int i, int *pvalue);
|
||||
virtual void Enable(bool on);
|
||||
virtual bool MenuEvent (int mkey, bool fromcontroller);
|
||||
virtual bool MouseEvent(int type, int x, int y);
|
||||
virtual bool CheckHotkey(int c);
|
||||
void DrawSelector(int xofs, int yofs, FTextureID tex);
|
||||
void OffsetPositionY(int ydelta) { mYpos += ydelta; }
|
||||
int GetY() { return mYpos; }
|
||||
};
|
||||
|
||||
class FListMenuItemStaticPatch : public FListMenuItem
|
||||
{
|
||||
protected:
|
||||
FTextureID mTexture;
|
||||
bool mCentered;
|
||||
|
||||
public:
|
||||
FListMenuItemStaticPatch(int x, int y, FTextureID patch, bool centered);
|
||||
void Drawer(bool selected);
|
||||
};
|
||||
|
||||
class FListMenuItemStaticText : public FListMenuItem
|
||||
{
|
||||
protected:
|
||||
const char *mText;
|
||||
FFont *mFont;
|
||||
EColorRange mColor;
|
||||
bool mCentered;
|
||||
|
||||
public:
|
||||
FListMenuItemStaticText(int x, int y, const char *text, FFont *font, EColorRange color, bool centered);
|
||||
~FListMenuItemStaticText();
|
||||
void Drawer(bool selected);
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// the player sprite window
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class FListMenuItemPlayerDisplay : public FListMenuItem
|
||||
{
|
||||
FListMenuDescriptor *mOwner;
|
||||
FTexture *mBackdrop;
|
||||
FRemapTable mRemap;
|
||||
FPlayerClass *mPlayerClass;
|
||||
FState *mPlayerState;
|
||||
int mPlayerTics;
|
||||
bool mNoportrait;
|
||||
BYTE mRotation;
|
||||
BYTE mMode; // 0: automatic (used by class selection), 1: manual (used by player setup)
|
||||
BYTE mTranslate;
|
||||
int mSkin;
|
||||
int mRandomClass;
|
||||
int mRandomTimer;
|
||||
int mClassNum;
|
||||
|
||||
void SetPlayerClass(int classnum, bool force = false);
|
||||
bool UpdatePlayerClass();
|
||||
void UpdateRandomClass();
|
||||
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
PDF_ROTATION = 0x10001,
|
||||
PDF_SKIN = 0x10002,
|
||||
PDF_CLASS = 0x10003,
|
||||
PDF_MODE = 0x10004,
|
||||
PDF_TRANSLATE = 0x10005,
|
||||
};
|
||||
|
||||
FListMenuItemPlayerDisplay(FListMenuDescriptor *menu, int x, int y, PalEntry c1, PalEntry c2, bool np, FName action);
|
||||
~FListMenuItemPlayerDisplay();
|
||||
virtual void Ticker();
|
||||
virtual void Drawer(bool selected);
|
||||
bool SetValue(int i, int value);
|
||||
};
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// selectable items
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class FListMenuItemSelectable : public FListMenuItem
|
||||
{
|
||||
protected:
|
||||
int mHotkey;
|
||||
int mHeight;
|
||||
int mParam;
|
||||
|
||||
public:
|
||||
FListMenuItemSelectable(int x, int y, int height, FName childmenu, int mParam = -1);
|
||||
bool CheckCoordinate(int x, int y);
|
||||
bool Selectable();
|
||||
bool CheckHotkey(int c);
|
||||
bool Activate();
|
||||
bool MouseEvent(int type, int x, int y);
|
||||
FName GetAction(int *pparam);
|
||||
};
|
||||
|
||||
class FListMenuItemText : public FListMenuItemSelectable
|
||||
{
|
||||
const char *mText;
|
||||
FFont *mFont;
|
||||
EColorRange mColor;
|
||||
public:
|
||||
FListMenuItemText(int x, int y, int height, int hotkey, const char *text, FFont *font, EColorRange color, FName child, int param = 0);
|
||||
~FListMenuItemText();
|
||||
void Drawer(bool selected);
|
||||
};
|
||||
|
||||
class FListMenuItemPatch : public FListMenuItemSelectable
|
||||
{
|
||||
FTextureID mTexture;
|
||||
public:
|
||||
FListMenuItemPatch(int x, int y, int height, int hotkey, FTextureID patch, FName child, int param = 0);
|
||||
void Drawer(bool selected);
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// items for the player menu
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class FPlayerNameBox : public FListMenuItemSelectable
|
||||
{
|
||||
const char *mText;
|
||||
FFont *mFont;
|
||||
EColorRange mFontColor;
|
||||
int mFrameSize;
|
||||
char mPlayerName[MAXPLAYERNAME+1];
|
||||
char mEditName[MAXPLAYERNAME+2];
|
||||
bool mEntering;
|
||||
|
||||
void DrawBorder (int x, int y, int len);
|
||||
|
||||
public:
|
||||
|
||||
FPlayerNameBox(int x, int y, int height, int frameofs, const char *text, FFont *font, EColorRange color, FName action);
|
||||
~FPlayerNameBox();
|
||||
bool SetString(int i, const char *s);
|
||||
bool GetString(int i, char *s, int len);
|
||||
void Drawer(bool selected);
|
||||
bool MenuEvent (int mkey, bool fromcontroller);
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// items for the player menu
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class FValueTextItem : public FListMenuItemSelectable
|
||||
{
|
||||
TArray<FString> mSelections;
|
||||
const char *mText;
|
||||
int mSelection;
|
||||
FFont *mFont;
|
||||
EColorRange mFontColor;
|
||||
EColorRange mFontColor2;
|
||||
|
||||
public:
|
||||
|
||||
FValueTextItem(int x, int y, int height, const char *text, FFont *font, EColorRange color, EColorRange valuecolor, FName action, FName values);
|
||||
~FValueTextItem();
|
||||
bool SetString(int i, const char *s);
|
||||
bool SetValue(int i, int value);
|
||||
bool GetValue(int i, int *pvalue);
|
||||
bool MenuEvent (int mkey, bool fromcontroller);
|
||||
void Drawer(bool selected);
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// items for the player menu
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class FSliderItem : public FListMenuItemSelectable
|
||||
{
|
||||
const char *mText;
|
||||
FFont *mFont;
|
||||
EColorRange mFontColor;
|
||||
int mMinrange, mMaxrange;
|
||||
int mStep;
|
||||
int mSelection;
|
||||
|
||||
void DrawSlider (int x, int y);
|
||||
|
||||
public:
|
||||
|
||||
FSliderItem(int x, int y, int height, const char *text, FFont *font, EColorRange color, FName action, int min, int max, int step);
|
||||
~FSliderItem();
|
||||
bool SetValue(int i, int value);
|
||||
bool GetValue(int i, int *pvalue);
|
||||
bool MenuEvent (int mkey, bool fromcontroller);
|
||||
void Drawer(bool selected);
|
||||
bool MouseEvent(int type, int x, int y);
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// list menu class runs a menu described by a FListMenuDescriptor
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class DListMenu : public DMenu
|
||||
{
|
||||
DECLARE_CLASS(DListMenu, DMenu)
|
||||
|
||||
protected:
|
||||
FListMenuDescriptor *mDesc;
|
||||
FListMenuItem *mFocusControl;
|
||||
|
||||
public:
|
||||
DListMenu(DMenu *parent = NULL, FListMenuDescriptor *desc = NULL);
|
||||
virtual void Init(DMenu *parent = NULL, FListMenuDescriptor *desc = NULL);
|
||||
FListMenuItem *GetItem(FName name);
|
||||
bool Responder (event_t *ev);
|
||||
bool MenuEvent (int mkey, bool fromcontroller);
|
||||
bool MouseEvent(int type, int x, int y);
|
||||
void Ticker ();
|
||||
void Drawer ();
|
||||
void SetFocus(FListMenuItem *fc)
|
||||
{
|
||||
mFocusControl = fc;
|
||||
}
|
||||
bool CheckFocus(FListMenuItem *fc)
|
||||
{
|
||||
return mFocusControl == fc;
|
||||
}
|
||||
void ReleaseFocus()
|
||||
{
|
||||
mFocusControl = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// base class for menu items
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class FOptionMenuItem : public FListMenuItem
|
||||
{
|
||||
protected:
|
||||
char *mLabel;
|
||||
bool mCentered;
|
||||
|
||||
void drawLabel(int indent, int y, EColorRange color, bool grayed = false);
|
||||
public:
|
||||
|
||||
FOptionMenuItem(const char *text, FName action = NAME_None, bool center = false)
|
||||
: FListMenuItem(0, 0, action)
|
||||
{
|
||||
mLabel = copystring(text);
|
||||
mCentered = center;
|
||||
}
|
||||
|
||||
~FOptionMenuItem();
|
||||
virtual bool CheckCoordinate(FOptionMenuDescriptor *desc, int x, int y);
|
||||
virtual int Draw(FOptionMenuDescriptor *desc, int y, int indent, bool selected);
|
||||
virtual bool Selectable();
|
||||
virtual int GetIndent();
|
||||
virtual bool MouseEvent(int type, int x, int y);
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
struct FOptionValues
|
||||
{
|
||||
struct Pair
|
||||
{
|
||||
double Value;
|
||||
FString TextValue;
|
||||
FString Text;
|
||||
};
|
||||
|
||||
TArray<Pair> mValues;
|
||||
};
|
||||
|
||||
typedef TMap< FName, FOptionValues* > FOptionMap;
|
||||
|
||||
extern FOptionMap OptionValues;
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Option menu class runs a menu described by a FOptionMenuDescriptor
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class DOptionMenu : public DMenu
|
||||
{
|
||||
DECLARE_CLASS(DOptionMenu, DMenu)
|
||||
|
||||
bool CanScrollUp;
|
||||
bool CanScrollDown;
|
||||
int VisBottom;
|
||||
FOptionMenuItem *mFocusControl;
|
||||
|
||||
protected:
|
||||
FOptionMenuDescriptor *mDesc;
|
||||
|
||||
public:
|
||||
FOptionMenuItem *GetItem(FName name);
|
||||
DOptionMenu(DMenu *parent = NULL, FOptionMenuDescriptor *desc = NULL);
|
||||
virtual void Init(DMenu *parent = NULL, FOptionMenuDescriptor *desc = NULL);
|
||||
bool Responder (event_t *ev);
|
||||
bool MenuEvent (int mkey, bool fromcontroller);
|
||||
bool MouseEvent(int type, int x, int y);
|
||||
void Ticker ();
|
||||
void Drawer ();
|
||||
const FOptionMenuDescriptor *GetDescriptor() const { return mDesc; }
|
||||
void SetFocus(FOptionMenuItem *fc)
|
||||
{
|
||||
mFocusControl = fc;
|
||||
}
|
||||
bool CheckFocus(FOptionMenuItem *fc)
|
||||
{
|
||||
return mFocusControl == fc;
|
||||
}
|
||||
void ReleaseFocus()
|
||||
{
|
||||
mFocusControl = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Input some text
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class DTextEnterMenu : public DMenu
|
||||
{
|
||||
DECLARE_ABSTRACT_CLASS(DTextEnterMenu, DMenu)
|
||||
|
||||
char *mEnterString;
|
||||
unsigned int mEnterSize;
|
||||
unsigned int mEnterPos;
|
||||
int mSizeMode; // 1: size is length in chars. 2: also check string width
|
||||
bool mInputGridOkay;
|
||||
|
||||
int InputGridX;
|
||||
int InputGridY;
|
||||
|
||||
public:
|
||||
|
||||
DTextEnterMenu(DMenu *parent, char *textbuffer, int maxlen, int sizemode, bool showgrid);
|
||||
|
||||
void Drawer ();
|
||||
bool MenuEvent (int mkey, bool fromcontroller);
|
||||
bool Responder(event_t *ev);
|
||||
bool TranslateKeyboardEvents();
|
||||
bool MouseEvent(int type, int x, int y);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct event_t;
|
||||
bool M_Responder (event_t *ev);
|
||||
void M_Ticker (void);
|
||||
void M_Drawer (void);
|
||||
void M_Init (void);
|
||||
void M_CreateMenus();
|
||||
void M_ActivateMenu(DMenu *menu);
|
||||
void M_ClearMenus ();
|
||||
void M_ParseMenuDefs();
|
||||
void M_StartupSkillMenu(FGameStartup *gs);
|
||||
void M_StartControlPanel (bool makeSound);
|
||||
void M_SetMenu(FName menu, int param = -1);
|
||||
void M_NotifyNewSave (const char *file, const char *title, bool okForQuicksave);
|
||||
void M_StartMessage(const char *message, int messagemode, FName action = NAME_None);
|
||||
DMenu *StartPickerMenu(DMenu *parent, const char *name, FColorCVar *cvar);
|
||||
void M_RefreshModesList ();
|
||||
void M_InitVideoModesMenu ();
|
||||
|
||||
|
||||
#endif
|
1389
src/menu/menudef.cpp
Normal file
1389
src/menu/menudef.cpp
Normal file
File diff suppressed because it is too large
Load diff
366
src/menu/menuinput.cpp
Normal file
366
src/menu/menuinput.cpp
Normal file
|
@ -0,0 +1,366 @@
|
|||
/*
|
||||
** menuinput.cpp
|
||||
** The string input code
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2001-2010 Randy Heit
|
||||
** Copyright 2010 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "menu/menu.h"
|
||||
#include "v_video.h"
|
||||
#include "c_cvars.h"
|
||||
#include "d_event.h"
|
||||
#include "d_gui.h"
|
||||
#include "v_font.h"
|
||||
#include "v_palette.h"
|
||||
|
||||
IMPLEMENT_ABSTRACT_CLASS(DTextEnterMenu)
|
||||
|
||||
#define INPUTGRID_WIDTH 13
|
||||
#define INPUTGRID_HEIGHT 5
|
||||
|
||||
// Heretic and Hexen do not, by default, come with glyphs for all of these
|
||||
// characters. Oh well. Doom and Strife do.
|
||||
static const char InputGridChars[INPUTGRID_WIDTH * INPUTGRID_HEIGHT] =
|
||||
"ABCDEFGHIJKLM"
|
||||
"NOPQRSTUVWXYZ"
|
||||
"0123456789+-="
|
||||
".,!?@'\":;[]()"
|
||||
"<>^#$%&*/_ \b";
|
||||
|
||||
|
||||
CVAR(Bool, m_showinputgrid, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
DTextEnterMenu::DTextEnterMenu(DMenu *parent, char *textbuffer, int maxlen, int sizemode, bool showgrid)
|
||||
: DMenu(parent)
|
||||
{
|
||||
mEnterString = textbuffer;
|
||||
mEnterSize = maxlen;
|
||||
mEnterPos = (unsigned)strlen(textbuffer);
|
||||
mSizeMode = sizemode;
|
||||
mInputGridOkay = showgrid || m_showinputgrid;
|
||||
if (mEnterPos > 0)
|
||||
{
|
||||
InputGridX = INPUTGRID_WIDTH - 1;
|
||||
InputGridY = INPUTGRID_HEIGHT - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we are naming a new save, don't start the cursor on "end".
|
||||
InputGridX = 0;
|
||||
InputGridY = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool DTextEnterMenu::TranslateKeyboardEvents()
|
||||
{
|
||||
return mInputGridOkay;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool DTextEnterMenu::Responder(event_t *ev)
|
||||
{
|
||||
if (ev->type == EV_GUI_Event)
|
||||
{
|
||||
// Save game and player name string input
|
||||
if (ev->subtype == EV_GUI_Char)
|
||||
{
|
||||
mInputGridOkay = false;
|
||||
if (mEnterPos < mEnterSize &&
|
||||
(mSizeMode == 2/*entering player name*/ || (size_t)SmallFont->StringWidth(mEnterString) < (mEnterSize-1)*8))
|
||||
{
|
||||
mEnterString[mEnterPos] = (char)ev->data1;
|
||||
mEnterString[++mEnterPos] = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
char ch = (char)ev->data1;
|
||||
if ((ev->subtype == EV_GUI_KeyDown || ev->subtype == EV_GUI_KeyRepeat) && ch == '\b')
|
||||
{
|
||||
if (mEnterPos > 0)
|
||||
{
|
||||
mEnterPos--;
|
||||
mEnterString[mEnterPos] = 0;
|
||||
}
|
||||
}
|
||||
else if (ev->subtype == EV_GUI_KeyDown)
|
||||
{
|
||||
if (ch == GK_ESCAPE)
|
||||
{
|
||||
DMenu *parent = mParentMenu;
|
||||
Close();
|
||||
parent->MenuEvent(MKEY_Abort, false);
|
||||
return true;
|
||||
}
|
||||
else if (ch == '\r')
|
||||
{
|
||||
if (mEnterString[0])
|
||||
{
|
||||
DMenu *parent = mParentMenu;
|
||||
Close();
|
||||
parent->MenuEvent(MKEY_Input, false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ev->subtype == EV_GUI_KeyDown || ev->subtype == EV_GUI_KeyRepeat)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return Super::Responder(ev);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool DTextEnterMenu::MouseEvent(int type, int x, int y)
|
||||
{
|
||||
const int cell_width = 18 * CleanXfac;
|
||||
const int cell_height = 12 * CleanYfac;
|
||||
const int screen_y = screen->GetHeight() - INPUTGRID_HEIGHT * cell_height;
|
||||
const int screen_x = (screen->GetWidth() - INPUTGRID_WIDTH * cell_width) / 2;
|
||||
|
||||
if (x >= screen_x && x < screen_x + INPUTGRID_WIDTH * cell_width && y >= screen_y)
|
||||
{
|
||||
InputGridX = (x - screen_x) / cell_width;
|
||||
InputGridY = (y - screen_y) / cell_height;
|
||||
if (type == DMenu::MOUSE_Release)
|
||||
{
|
||||
if (MenuEvent(MKEY_Enter, true))
|
||||
{
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE);
|
||||
if (m_use_mouse == 2) InputGridX = InputGridY = -1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
InputGridX = InputGridY = -1;
|
||||
}
|
||||
return Super::MouseEvent(type, x, y);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool DTextEnterMenu::MenuEvent (int key, bool fromcontroller)
|
||||
{
|
||||
if (key == MKEY_Back)
|
||||
{
|
||||
mParentMenu->MenuEvent(MKEY_Abort, false);
|
||||
return Super::MenuEvent(key, fromcontroller);
|
||||
}
|
||||
if (fromcontroller)
|
||||
{
|
||||
mInputGridOkay = true;
|
||||
}
|
||||
|
||||
if (mInputGridOkay)
|
||||
{
|
||||
int ch;
|
||||
|
||||
if (InputGridX == -1 || InputGridY == -1)
|
||||
{
|
||||
InputGridX = InputGridY = 0;
|
||||
}
|
||||
switch (key)
|
||||
{
|
||||
case MKEY_Down:
|
||||
InputGridY = (InputGridY + 1) % INPUTGRID_HEIGHT;
|
||||
return true;
|
||||
|
||||
case MKEY_Up:
|
||||
InputGridY = (InputGridY + INPUTGRID_HEIGHT - 1) % INPUTGRID_HEIGHT;
|
||||
return true;
|
||||
|
||||
case MKEY_Right:
|
||||
InputGridX = (InputGridX + 1) % INPUTGRID_WIDTH;
|
||||
return true;
|
||||
|
||||
case MKEY_Left:
|
||||
InputGridX = (InputGridX + INPUTGRID_WIDTH - 1) % INPUTGRID_WIDTH;
|
||||
return true;
|
||||
|
||||
case MKEY_Clear:
|
||||
if (mEnterPos > 0)
|
||||
{
|
||||
mEnterString[--mEnterPos] = 0;
|
||||
}
|
||||
return true;
|
||||
|
||||
case MKEY_Enter:
|
||||
assert(unsigned(InputGridX) < INPUTGRID_WIDTH && unsigned(InputGridY) < INPUTGRID_HEIGHT);
|
||||
if (mInputGridOkay)
|
||||
{
|
||||
ch = InputGridChars[InputGridX + InputGridY * INPUTGRID_WIDTH];
|
||||
if (ch == 0) // end
|
||||
{
|
||||
if (mEnterString[0] != '\0')
|
||||
{
|
||||
DMenu *parent = mParentMenu;
|
||||
Close();
|
||||
parent->MenuEvent(MKEY_Input, false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (ch == '\b') // bs
|
||||
{
|
||||
if (mEnterPos > 0)
|
||||
{
|
||||
mEnterString[--mEnterPos] = 0;
|
||||
}
|
||||
}
|
||||
else if (mEnterPos < mEnterSize &&
|
||||
(mSizeMode == 2/*entering player name*/ || (size_t)SmallFont->StringWidth(mEnterString) < (mEnterSize-1)*8))
|
||||
{
|
||||
mEnterString[mEnterPos] = ch;
|
||||
mEnterString[++mEnterPos] = 0;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
default:
|
||||
break; // Keep GCC quiet
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void DTextEnterMenu::Drawer ()
|
||||
{
|
||||
mParentMenu->Drawer();
|
||||
if (mInputGridOkay)
|
||||
{
|
||||
const int cell_width = 18 * CleanXfac;
|
||||
const int cell_height = 12 * CleanYfac;
|
||||
const int top_padding = cell_height / 2 - SmallFont->GetHeight() * CleanYfac / 2;
|
||||
|
||||
// Darken the background behind the character grid.
|
||||
// Unless we frame it with a border, I think it looks better to extend the
|
||||
// background across the full width of the screen.
|
||||
screen->Dim(0, 0.8f,
|
||||
0 /*screen->GetWidth()/2 - 13 * cell_width / 2*/,
|
||||
screen->GetHeight() - INPUTGRID_HEIGHT * cell_height,
|
||||
screen->GetWidth() /*13 * cell_width*/,
|
||||
INPUTGRID_HEIGHT * cell_height);
|
||||
|
||||
if (InputGridX >= 0 && InputGridY >= 0)
|
||||
{
|
||||
// Highlight the background behind the selected character.
|
||||
screen->Dim(MAKERGB(255,248,220), 0.6f,
|
||||
InputGridX * cell_width - INPUTGRID_WIDTH * cell_width / 2 + screen->GetWidth() / 2,
|
||||
InputGridY * cell_height - INPUTGRID_HEIGHT * cell_height + screen->GetHeight(),
|
||||
cell_width, cell_height);
|
||||
}
|
||||
|
||||
for (int y = 0; y < INPUTGRID_HEIGHT; ++y)
|
||||
{
|
||||
const int yy = y * cell_height - INPUTGRID_HEIGHT * cell_height + screen->GetHeight();
|
||||
for (int x = 0; x < INPUTGRID_WIDTH; ++x)
|
||||
{
|
||||
int width;
|
||||
const int xx = x * cell_width - INPUTGRID_WIDTH * cell_width / 2 + screen->GetWidth() / 2;
|
||||
const int ch = InputGridChars[y * INPUTGRID_WIDTH + x];
|
||||
FTexture *pic = SmallFont->GetChar(ch, &width);
|
||||
EColorRange color;
|
||||
FRemapTable *remap;
|
||||
|
||||
// The highlighted character is yellow; the rest are dark gray.
|
||||
color = (x == InputGridX && y == InputGridY) ? CR_YELLOW : CR_DARKGRAY;
|
||||
remap = SmallFont->GetColorTranslation(color);
|
||||
|
||||
if (pic != NULL)
|
||||
{
|
||||
// Draw a normal character.
|
||||
screen->DrawTexture(pic, xx + cell_width/2 - width*CleanXfac/2, yy + top_padding,
|
||||
DTA_Translation, remap,
|
||||
DTA_CleanNoMove, true,
|
||||
TAG_DONE);
|
||||
}
|
||||
else if (ch == ' ')
|
||||
{
|
||||
// Draw the space as a box outline. We also draw it 50% wider than it really is.
|
||||
const int x1 = xx + cell_width/2 - width * CleanXfac * 3 / 4;
|
||||
const int x2 = x1 + width * 3 * CleanXfac / 2;
|
||||
const int y1 = yy + top_padding;
|
||||
const int y2 = y1 + SmallFont->GetHeight() * CleanYfac;
|
||||
const int palentry = remap->Remap[remap->NumEntries*2/3];
|
||||
const uint32 palcolor = remap->Palette[remap->NumEntries*2/3];
|
||||
screen->Clear(x1, y1, x2, y1+CleanYfac, palentry, palcolor); // top
|
||||
screen->Clear(x1, y2, x2, y2+CleanYfac, palentry, palcolor); // bottom
|
||||
screen->Clear(x1, y1+CleanYfac, x1+CleanXfac, y2, palentry, palcolor); // left
|
||||
screen->Clear(x2-CleanXfac, y1+CleanYfac, x2, y2, palentry, palcolor); // right
|
||||
}
|
||||
else if (ch == '\b' || ch == 0)
|
||||
{
|
||||
// Draw the backspace and end "characters".
|
||||
const char *const str = ch == '\b' ? "BS" : "ED";
|
||||
screen->DrawText(SmallFont, color,
|
||||
xx + cell_width/2 - SmallFont->StringWidth(str)*CleanXfac/2,
|
||||
yy + top_padding, str, DTA_CleanNoMove, true, TAG_DONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Super::Drawer();
|
||||
}
|
733
src/menu/messagebox.cpp
Normal file
733
src/menu/messagebox.cpp
Normal file
|
@ -0,0 +1,733 @@
|
|||
/*
|
||||
** messagebox.cpp
|
||||
** Confirmation, notification screns
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2010 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "menu/menu.h"
|
||||
#include "d_event.h"
|
||||
#include "d_gui.h"
|
||||
#include "v_video.h"
|
||||
#include "v_text.h"
|
||||
#include "d_main.h"
|
||||
#include "gstrings.h"
|
||||
#include "gi.h"
|
||||
#include "i_video.h"
|
||||
#include "st_start.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "g_game.h"
|
||||
|
||||
|
||||
extern FSaveGameNode *quickSaveSlot;
|
||||
|
||||
class DMessageBoxMenu : public DMenu
|
||||
{
|
||||
DECLARE_CLASS(DMessageBoxMenu, DMenu)
|
||||
|
||||
FBrokenLines *mMessage;
|
||||
int mMessageMode;
|
||||
int messageSelection;
|
||||
int mMouseLeft, mMouseRight, mMouseY;
|
||||
FName mAction;
|
||||
|
||||
public:
|
||||
|
||||
DMessageBoxMenu(DMenu *parent = NULL, const char *message = NULL, int messagemode = 0, bool playsound = false, FName action = NAME_None);
|
||||
void Destroy();
|
||||
void Init(DMenu *parent, const char *message, int messagemode, bool playsound = false);
|
||||
void Drawer();
|
||||
bool Responder(event_t *ev);
|
||||
bool MenuEvent(int mkey, bool fromcontroller);
|
||||
bool MouseEvent(int type, int x, int y);
|
||||
void CloseSound();
|
||||
virtual void HandleResult(bool res);
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(DMessageBoxMenu)
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
DMessageBoxMenu::DMessageBoxMenu(DMenu *parent, const char *message, int messagemode, bool playsound, FName action)
|
||||
: DMenu(parent)
|
||||
{
|
||||
mAction = action;
|
||||
messageSelection = 0;
|
||||
mMouseLeft = 140;
|
||||
mMouseY = INT_MIN;
|
||||
int mr1 = 170 + SmallFont->StringWidth(GStrings["TXT_YES"]);
|
||||
int mr2 = 170 + SmallFont->StringWidth(GStrings["TXT_NO"]);
|
||||
mMouseRight = MAX(mr1, mr2);
|
||||
|
||||
Init(parent, message, messagemode, playsound);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void DMessageBoxMenu::Init(DMenu *parent, const char *message, int messagemode, bool playsound)
|
||||
{
|
||||
mParentMenu = parent;
|
||||
if (message != NULL)
|
||||
{
|
||||
if (*message == '$') message = GStrings(message+1);
|
||||
mMessage = V_BreakLines(SmallFont, 300, message);
|
||||
}
|
||||
else mMessage = NULL;
|
||||
mMessageMode = messagemode;
|
||||
if (playsound)
|
||||
{
|
||||
S_StopSound (CHAN_VOICE);
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/prompt", snd_menuvolume, ATTN_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void DMessageBoxMenu::Destroy()
|
||||
{
|
||||
if (mMessage != NULL) V_FreeBrokenLines(mMessage);
|
||||
mMessage = NULL;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void DMessageBoxMenu::CloseSound()
|
||||
{
|
||||
S_Sound (CHAN_VOICE | CHAN_UI,
|
||||
DMenu::CurrentMenu != NULL? "menu/backup" : "menu/dismiss", snd_menuvolume, ATTN_NONE);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void DMessageBoxMenu::HandleResult(bool res)
|
||||
{
|
||||
if (mParentMenu != NULL)
|
||||
{
|
||||
if (mMessageMode == 0)
|
||||
{
|
||||
if (mAction == NAME_None)
|
||||
{
|
||||
mParentMenu->MenuEvent(res? MKEY_MBYes : MKEY_MBNo, false);
|
||||
Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
Close();
|
||||
if (res) M_SetMenu(mAction, -1);
|
||||
}
|
||||
CloseSound();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void DMessageBoxMenu::Drawer ()
|
||||
{
|
||||
int i, y;
|
||||
PalEntry fade = 0;
|
||||
|
||||
int fontheight = SmallFont->GetHeight();
|
||||
//BorderNeedRefresh = screen->GetPageCount ();
|
||||
//SB_state = screen->GetPageCount ();
|
||||
|
||||
y = 100;
|
||||
|
||||
if (mMessage != NULL)
|
||||
{
|
||||
for (i = 0; mMessage[i].Width >= 0; i++)
|
||||
y -= SmallFont->GetHeight () / 2;
|
||||
|
||||
for (i = 0; mMessage[i].Width >= 0; i++)
|
||||
{
|
||||
screen->DrawText (SmallFont, CR_UNTRANSLATED, 160 - mMessage[i].Width/2, y, mMessage[i].Text,
|
||||
DTA_Clean, true, TAG_DONE);
|
||||
y += fontheight;
|
||||
}
|
||||
}
|
||||
|
||||
if (mMessageMode == 0)
|
||||
{
|
||||
y += fontheight;
|
||||
mMouseY = y;
|
||||
screen->DrawText(SmallFont,
|
||||
messageSelection == 0? OptionSettings.mFontColorSelection : OptionSettings.mFontColor,
|
||||
160, y, GStrings["TXT_YES"], DTA_Clean, true, TAG_DONE);
|
||||
screen->DrawText(SmallFont,
|
||||
messageSelection == 1? OptionSettings.mFontColorSelection : OptionSettings.mFontColor,
|
||||
160, y + fontheight + 1, GStrings["TXT_NO"], DTA_Clean, true, TAG_DONE);
|
||||
|
||||
if (messageSelection >= 0)
|
||||
{
|
||||
if ((DMenu::MenuTime%8) < 6)
|
||||
{
|
||||
screen->DrawText(ConFont, OptionSettings.mFontColorSelection,
|
||||
(150 - 160) * CleanXfac + screen->GetWidth() / 2,
|
||||
(y + (fontheight + 1) * messageSelection - 100) * CleanYfac + screen->GetHeight() / 2,
|
||||
"\xd",
|
||||
DTA_CellX, 8 * CleanXfac,
|
||||
DTA_CellY, 8 * CleanYfac,
|
||||
TAG_DONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool DMessageBoxMenu::Responder(event_t *ev)
|
||||
{
|
||||
if (ev->type == EV_GUI_Event && ev->subtype == EV_GUI_KeyDown)
|
||||
{
|
||||
if (mMessageMode == 0)
|
||||
{
|
||||
int ch = tolower(ev->data1);
|
||||
if (ch == 'n' || ch == ' ')
|
||||
{
|
||||
HandleResult(false);
|
||||
return true;
|
||||
}
|
||||
else if (ch == 'y')
|
||||
{
|
||||
HandleResult(true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (ev->type == EV_KeyDown)
|
||||
{
|
||||
Close();
|
||||
return true;
|
||||
}
|
||||
return Super::Responder(ev);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool DMessageBoxMenu::MenuEvent(int mkey, bool fromcontroller)
|
||||
{
|
||||
if (mMessageMode == 0)
|
||||
{
|
||||
if (mkey == MKEY_Up || mkey == MKEY_Down)
|
||||
{
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
|
||||
messageSelection = !messageSelection;
|
||||
return true;
|
||||
}
|
||||
else if (mkey == MKEY_Enter)
|
||||
{
|
||||
// 0 is yes, 1 is no
|
||||
HandleResult(!messageSelection);
|
||||
return true;
|
||||
}
|
||||
else if (mkey == MKEY_Back)
|
||||
{
|
||||
HandleResult(false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Close();
|
||||
CloseSound();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool DMessageBoxMenu::MouseEvent(int type, int x, int y)
|
||||
{
|
||||
if (mMessageMode == 1)
|
||||
{
|
||||
if (type == MOUSE_Click)
|
||||
{
|
||||
return MenuEvent(MKEY_Enter, true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
int sel = -1;
|
||||
int fh = SmallFont->GetHeight() + 1;
|
||||
|
||||
// convert x/y from screen to virtual coordinates, according to CleanX/Yfac use in DrawTexture
|
||||
x = ((x - (screen->GetWidth() / 2)) / CleanXfac) + 160;
|
||||
y = ((y - (screen->GetHeight() / 2)) / CleanYfac) + 100;
|
||||
|
||||
if (x >= mMouseLeft && x <= mMouseRight && y >= mMouseY && y < mMouseY + 2 * fh)
|
||||
{
|
||||
sel = y >= mMouseY + fh;
|
||||
}
|
||||
if (sel != -1 && sel != messageSelection)
|
||||
{
|
||||
//S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
|
||||
}
|
||||
messageSelection = sel;
|
||||
if (type == MOUSE_Release)
|
||||
{
|
||||
return MenuEvent(MKEY_Enter, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class DQuitMenu : public DMessageBoxMenu
|
||||
{
|
||||
DECLARE_CLASS(DQuitMenu, DMessageBoxMenu)
|
||||
|
||||
public:
|
||||
|
||||
DQuitMenu(bool playsound = false);
|
||||
virtual void HandleResult(bool res);
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(DQuitMenu)
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
DQuitMenu::DQuitMenu(bool playsound)
|
||||
{
|
||||
int messageindex = gametic % gameinfo.quitmessages.Size();
|
||||
FString EndString;
|
||||
const char *msg = gameinfo.quitmessages[messageindex];
|
||||
if (msg[0] == '$')
|
||||
{
|
||||
if (msg[1] == '*')
|
||||
{
|
||||
EndString = GStrings(msg+2);
|
||||
}
|
||||
else
|
||||
{
|
||||
EndString.Format("%s\n\n%s", GStrings(msg+1), GStrings("DOSY"));
|
||||
}
|
||||
}
|
||||
else EndString = gameinfo.quitmessages[messageindex];
|
||||
|
||||
Init(NULL, EndString, 0, playsound);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void DQuitMenu::HandleResult(bool res)
|
||||
{
|
||||
if (res)
|
||||
{
|
||||
if (!netgame)
|
||||
{
|
||||
if (gameinfo.quitSound.IsNotEmpty())
|
||||
{
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, gameinfo.quitSound, snd_menuvolume, ATTN_NONE);
|
||||
I_WaitVBL (105);
|
||||
}
|
||||
}
|
||||
ST_Endoom();
|
||||
}
|
||||
else
|
||||
{
|
||||
Close();
|
||||
CloseSound();
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
CCMD (menu_quit)
|
||||
{ // F10
|
||||
M_StartControlPanel (true);
|
||||
DMenu *newmenu = new DQuitMenu(false);
|
||||
newmenu->mParentMenu = DMenu::CurrentMenu;
|
||||
M_ActivateMenu(newmenu);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class DEndGameMenu : public DMessageBoxMenu
|
||||
{
|
||||
DECLARE_CLASS(DEndGameMenu, DMessageBoxMenu)
|
||||
|
||||
public:
|
||||
|
||||
DEndGameMenu(bool playsound = false);
|
||||
virtual void HandleResult(bool res);
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(DEndGameMenu)
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
DEndGameMenu::DEndGameMenu(bool playsound)
|
||||
{
|
||||
int messageindex = gametic % gameinfo.quitmessages.Size();
|
||||
FString EndString = gameinfo.quitmessages[messageindex];
|
||||
|
||||
if (netgame)
|
||||
{
|
||||
if(gameinfo.gametype == GAME_Chex)
|
||||
EndString = GStrings("CNETEND");
|
||||
else
|
||||
EndString = GStrings("NETEND");
|
||||
return;
|
||||
}
|
||||
|
||||
if(gameinfo.gametype == GAME_Chex)
|
||||
EndString = GStrings("CENDGAME");
|
||||
else
|
||||
EndString = GStrings("ENDGAME");
|
||||
|
||||
|
||||
Init(NULL, EndString, 0, playsound);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void DEndGameMenu::HandleResult(bool res)
|
||||
{
|
||||
if (res)
|
||||
{
|
||||
M_ClearMenus ();
|
||||
D_StartTitle ();
|
||||
}
|
||||
else
|
||||
{
|
||||
Close();
|
||||
CloseSound();
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
CCMD (menu_endgame)
|
||||
{ // F7
|
||||
if (!usergame)
|
||||
{
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/invalid", snd_menuvolume, ATTN_NONE);
|
||||
return;
|
||||
}
|
||||
|
||||
//M_StartControlPanel (true);
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", snd_menuvolume, ATTN_NONE);
|
||||
DMenu *newmenu = new DEndGameMenu(false);
|
||||
newmenu->mParentMenu = DMenu::CurrentMenu;
|
||||
M_ActivateMenu(newmenu);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class DQuickSaveMenu : public DMessageBoxMenu
|
||||
{
|
||||
DECLARE_CLASS(DQuickSaveMenu, DMessageBoxMenu)
|
||||
|
||||
public:
|
||||
|
||||
DQuickSaveMenu(bool playsound = false);
|
||||
virtual void HandleResult(bool res);
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(DQuickSaveMenu)
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
DQuickSaveMenu::DQuickSaveMenu(bool playsound)
|
||||
{
|
||||
FString tempstring;
|
||||
|
||||
if(gameinfo.gametype == GAME_Chex)
|
||||
tempstring.Format(GStrings("CQSPROMPT"), quickSaveSlot->Title);
|
||||
else
|
||||
tempstring.Format(GStrings("QSPROMPT"), quickSaveSlot->Title);
|
||||
|
||||
Init(NULL, tempstring, 0, playsound);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void DQuickSaveMenu::HandleResult(bool res)
|
||||
{
|
||||
if (res)
|
||||
{
|
||||
G_SaveGame (quickSaveSlot->Filename.GetChars(), quickSaveSlot->Title);
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE);
|
||||
M_ClearMenus();
|
||||
}
|
||||
else
|
||||
{
|
||||
Close();
|
||||
CloseSound();
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
CCMD (quicksave)
|
||||
{ // F6
|
||||
if (!usergame || (players[consoleplayer].health <= 0 && !multiplayer))
|
||||
{
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/invalid", snd_menuvolume, ATTN_NONE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gamestate != GS_LEVEL)
|
||||
return;
|
||||
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", snd_menuvolume, ATTN_NONE);
|
||||
if (quickSaveSlot == NULL)
|
||||
{
|
||||
M_StartControlPanel(false);
|
||||
M_SetMenu(NAME_Savegamemenu);
|
||||
return;
|
||||
}
|
||||
DMenu *newmenu = new DQuickSaveMenu(false);
|
||||
newmenu->mParentMenu = DMenu::CurrentMenu;
|
||||
M_ActivateMenu(newmenu);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class DQuickLoadMenu : public DMessageBoxMenu
|
||||
{
|
||||
DECLARE_CLASS(DQuickLoadMenu, DMessageBoxMenu)
|
||||
|
||||
public:
|
||||
|
||||
DQuickLoadMenu(bool playsound = false);
|
||||
virtual void HandleResult(bool res);
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(DQuickLoadMenu)
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
DQuickLoadMenu::DQuickLoadMenu(bool playsound)
|
||||
{
|
||||
FString tempstring;
|
||||
|
||||
if(gameinfo.gametype == GAME_Chex)
|
||||
tempstring.Format(GStrings("CQLPROMPT"), quickSaveSlot->Title);
|
||||
else
|
||||
tempstring.Format(GStrings("QLPROMPT"), quickSaveSlot->Title);
|
||||
|
||||
Init(NULL, tempstring, 0, playsound);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void DQuickLoadMenu::HandleResult(bool res)
|
||||
{
|
||||
if (res)
|
||||
{
|
||||
G_LoadGame (quickSaveSlot->Filename.GetChars());
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE);
|
||||
M_ClearMenus();
|
||||
}
|
||||
else
|
||||
{
|
||||
Close();
|
||||
CloseSound();
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
CCMD (quickload)
|
||||
{ // F9
|
||||
M_StartControlPanel (true);
|
||||
|
||||
if (netgame)
|
||||
{
|
||||
if(gameinfo.gametype == GAME_Chex)
|
||||
M_StartMessage (GStrings("CQLOADNET"), NULL);
|
||||
else
|
||||
M_StartMessage (GStrings("QLOADNET"), NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (quickSaveSlot == NULL)
|
||||
{
|
||||
M_StartControlPanel(false);
|
||||
// signal that whatever gets loaded should be the new quicksave
|
||||
quickSaveSlot = (FSaveGameNode *)1;
|
||||
M_SetMenu(NAME_Loadgamemenu);
|
||||
return;
|
||||
}
|
||||
DMenu *newmenu = new DQuickLoadMenu(false);
|
||||
newmenu->mParentMenu = DMenu::CurrentMenu;
|
||||
M_ActivateMenu(newmenu);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void M_StartMessage(const char *message, int messagemode, FName action)
|
||||
{
|
||||
if (DMenu::CurrentMenu == NULL)
|
||||
{
|
||||
// only play a sound if no menu was active before
|
||||
M_StartControlPanel(menuactive == MENU_Off);
|
||||
}
|
||||
DMenu *newmenu = new DMessageBoxMenu(DMenu::CurrentMenu, message, messagemode, false, action);
|
||||
newmenu->mParentMenu = DMenu::CurrentMenu;
|
||||
M_ActivateMenu(newmenu);
|
||||
}
|
||||
|
591
src/menu/optionmenu.cpp
Normal file
591
src/menu/optionmenu.cpp
Normal file
|
@ -0,0 +1,591 @@
|
|||
/*
|
||||
** optionmenu.cpp
|
||||
** Handler class for the option menus and associated items
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2010 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "v_video.h"
|
||||
#include "v_font.h"
|
||||
#include "cmdlib.h"
|
||||
#include "gstrings.h"
|
||||
#include "g_level.h"
|
||||
#include "gi.h"
|
||||
#include "v_palette.h"
|
||||
#include "d_gui.h"
|
||||
#include "d_event.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "c_console.h"
|
||||
#include "c_cvars.h"
|
||||
#include "c_bind.h"
|
||||
#include "gameconfigfile.h"
|
||||
#include "menu/menu.h"
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Draws a string in the console font, scaled to the 8x8 cells
|
||||
// used by the default console font.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void M_DrawConText (int color, int x, int y, const char *str)
|
||||
{
|
||||
int len = (int)strlen(str);
|
||||
|
||||
screen->DrawText (ConFont, color, x, y, str,
|
||||
DTA_CellX, 8 * CleanXfac_1,
|
||||
DTA_CellY, 8 * CleanYfac_1,
|
||||
TAG_DONE);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Draw a slider. Set fracdigits negative to not display the current value numerically.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void M_DrawSlider (int x, int y, double min, double max, double cur,int fracdigits)
|
||||
{
|
||||
double range;
|
||||
|
||||
range = max - min;
|
||||
double ccur = clamp(cur, min, max) - min;
|
||||
|
||||
if (CleanXfac > CleanXfac_1 || CleanXfac_1 * 320 < screen->GetWidth())
|
||||
{
|
||||
M_DrawConText(CR_WHITE, x, y, "\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12");
|
||||
M_DrawConText(CR_ORANGE, x + int((5 + ((ccur * 78) / range)) * CleanXfac_1), y, "\x13");
|
||||
|
||||
if (fracdigits >= 0)
|
||||
{
|
||||
char textbuf[16];
|
||||
mysnprintf(textbuf, countof(textbuf), "%.*f", fracdigits, cur);
|
||||
screen->DrawText(SmallFont, CR_DARKGRAY, x + (12*8 + 4) * CleanXfac_1, y, textbuf, DTA_CleanNoMove_1, true, TAG_DONE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// On 320x200 we need a shorter slider
|
||||
M_DrawConText(CR_WHITE, x, y, "\x10\x11\x11\x11\x11\x11\x12");
|
||||
M_DrawConText(CR_ORANGE, x + int((5 + ((ccur * 38) / range)) * CleanXfac_1), y, "\x13");
|
||||
|
||||
if (fracdigits >= 0)
|
||||
{
|
||||
char textbuf[16];
|
||||
mysnprintf(textbuf, countof(textbuf), "%.*f", fracdigits, cur);
|
||||
screen->DrawText(SmallFont, CR_DARKGRAY, x + (7*8 + 4) * CleanXfac_1, y, textbuf, DTA_CleanNoMove_1, true, TAG_DONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
IMPLEMENT_CLASS(DOptionMenu)
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
DOptionMenu::DOptionMenu(DMenu *parent, FOptionMenuDescriptor *desc)
|
||||
: DMenu(parent)
|
||||
{
|
||||
CanScrollUp = false;
|
||||
CanScrollDown = false;
|
||||
VisBottom = 0;
|
||||
mFocusControl = NULL;
|
||||
Init(parent, desc);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void DOptionMenu::Init(DMenu *parent, FOptionMenuDescriptor *desc)
|
||||
{
|
||||
mParentMenu = parent;
|
||||
GC::WriteBarrier(this, parent);
|
||||
mDesc = desc;
|
||||
if (mDesc != NULL && mDesc->mSelectedItem < 0)
|
||||
{
|
||||
// Go down to the first selectable item
|
||||
int i = -1;
|
||||
mDesc->mSelectedItem = -1;
|
||||
do
|
||||
{
|
||||
i++;
|
||||
}
|
||||
while (!mDesc->mItems[i]->Selectable() && i < (int)mDesc->mItems.Size());
|
||||
if (i>=0) mDesc->mSelectedItem = i;
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
FOptionMenuItem *DOptionMenu::GetItem(FName name)
|
||||
{
|
||||
for(unsigned i=0;i<mDesc->mItems.Size(); i++)
|
||||
{
|
||||
FName nm = mDesc->mItems[i]->GetAction(NULL);
|
||||
if (nm == name) return mDesc->mItems[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool DOptionMenu::Responder (event_t *ev)
|
||||
{
|
||||
if (ev->type == EV_GUI_Event)
|
||||
{
|
||||
if (ev->subtype == EV_GUI_WheelUp)
|
||||
{
|
||||
if (mDesc->mScrollPos > 0)
|
||||
{
|
||||
mDesc->mScrollPos--;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (ev->subtype == EV_GUI_WheelDown)
|
||||
{
|
||||
if (CanScrollDown)
|
||||
{
|
||||
mDesc->mScrollPos++;
|
||||
VisBottom++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return Super::Responder(ev);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool DOptionMenu::MenuEvent (int mkey, bool fromcontroller)
|
||||
{
|
||||
int startedAt = mDesc->mSelectedItem;
|
||||
|
||||
switch (mkey)
|
||||
{
|
||||
case MKEY_Up:
|
||||
do
|
||||
{
|
||||
--mDesc->mSelectedItem;
|
||||
|
||||
if (mDesc->mScrollPos > 0 &&
|
||||
mDesc->mSelectedItem == mDesc->mScrollTop + mDesc->mScrollPos)
|
||||
{
|
||||
mDesc->mScrollPos--;
|
||||
}
|
||||
|
||||
if (mDesc->mSelectedItem < 0)
|
||||
{
|
||||
// Figure out how many lines of text fit on the menu
|
||||
int y = mDesc->mPosition;
|
||||
|
||||
if (y <= 0)
|
||||
{
|
||||
if (BigFont && mDesc->mTitle.IsNotEmpty())
|
||||
{
|
||||
y = -y + BigFont->GetHeight();
|
||||
}
|
||||
else
|
||||
{
|
||||
y = -y;
|
||||
}
|
||||
}
|
||||
y *= CleanYfac_1;
|
||||
int rowheight = OptionSettings.mLinespacing * CleanYfac_1;
|
||||
int maxitems = (screen->GetHeight() - rowheight - y) / rowheight + 1;
|
||||
|
||||
mDesc->mScrollPos = MAX (0, (int)mDesc->mItems.Size() - maxitems + mDesc->mScrollTop);
|
||||
mDesc->mSelectedItem = mDesc->mItems.Size()-1;
|
||||
}
|
||||
}
|
||||
while (!mDesc->mItems[mDesc->mSelectedItem]->Selectable() && mDesc->mSelectedItem != startedAt);
|
||||
break;
|
||||
|
||||
case MKEY_Down:
|
||||
do
|
||||
{
|
||||
++mDesc->mSelectedItem;
|
||||
|
||||
if (CanScrollDown && mDesc->mSelectedItem == VisBottom)
|
||||
{
|
||||
mDesc->mScrollPos++;
|
||||
VisBottom++;
|
||||
}
|
||||
if (mDesc->mSelectedItem >= (int)mDesc->mItems.Size())
|
||||
{
|
||||
mDesc->mSelectedItem = 0;
|
||||
mDesc->mScrollPos = 0;
|
||||
}
|
||||
}
|
||||
while (!mDesc->mItems[mDesc->mSelectedItem]->Selectable() && mDesc->mSelectedItem != startedAt);
|
||||
break;
|
||||
|
||||
case MKEY_PageUp:
|
||||
if (mDesc->mScrollPos > 0)
|
||||
{
|
||||
mDesc->mScrollPos -= VisBottom - mDesc->mScrollPos - mDesc->mScrollTop;
|
||||
if (mDesc->mScrollPos < 0)
|
||||
{
|
||||
mDesc->mScrollPos = 0;
|
||||
}
|
||||
mDesc->mSelectedItem = mDesc->mScrollTop + mDesc->mScrollPos + 1;
|
||||
while (!mDesc->mItems[mDesc->mSelectedItem]->Selectable())
|
||||
{
|
||||
++mDesc->mSelectedItem;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MKEY_PageDown:
|
||||
if (CanScrollDown)
|
||||
{
|
||||
int pagesize = VisBottom - mDesc->mScrollPos - mDesc->mScrollTop;
|
||||
mDesc->mScrollPos += pagesize;
|
||||
if (mDesc->mScrollPos + mDesc->mScrollTop + pagesize > (int)mDesc->mItems.Size())
|
||||
{
|
||||
mDesc->mScrollPos = mDesc->mItems.Size() - mDesc->mScrollTop - pagesize;
|
||||
}
|
||||
mDesc->mSelectedItem = mDesc->mScrollTop + mDesc->mScrollPos;
|
||||
while (!mDesc->mItems[mDesc->mSelectedItem]->Selectable())
|
||||
{
|
||||
++mDesc->mSelectedItem;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MKEY_Enter:
|
||||
if (mDesc->mSelectedItem >= 0 && mDesc->mItems[mDesc->mSelectedItem]->Activate())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// fall through to default
|
||||
default:
|
||||
if (mDesc->mSelectedItem >= 0 &&
|
||||
mDesc->mItems[mDesc->mSelectedItem]->MenuEvent(mkey, fromcontroller)) return true;
|
||||
return Super::MenuEvent(mkey, fromcontroller);
|
||||
}
|
||||
|
||||
if (mDesc->mSelectedItem != startedAt)
|
||||
{
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool DOptionMenu::MouseEvent(int type, int x, int y)
|
||||
{
|
||||
y = (y / CleanYfac_1) - mDesc->mDrawTop;
|
||||
|
||||
if (mFocusControl)
|
||||
{
|
||||
mFocusControl->MouseEvent(type, x, y);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
int yline = (y / OptionSettings.mLinespacing);
|
||||
if (yline >= mDesc->mScrollTop)
|
||||
{
|
||||
yline += mDesc->mScrollPos;
|
||||
}
|
||||
if ((unsigned)yline < mDesc->mItems.Size() && mDesc->mItems[yline]->Selectable())
|
||||
{
|
||||
if (yline != mDesc->mSelectedItem)
|
||||
{
|
||||
mDesc->mSelectedItem = yline;
|
||||
//S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
|
||||
}
|
||||
mDesc->mItems[yline]->MouseEvent(type, x, y);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
mDesc->mSelectedItem = -1;
|
||||
return Super::MouseEvent(type, x, y);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void DOptionMenu::Ticker ()
|
||||
{
|
||||
Super::Ticker();
|
||||
for(unsigned i=0;i<mDesc->mItems.Size(); i++)
|
||||
{
|
||||
mDesc->mItems[i]->Ticker();
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void DOptionMenu::Drawer ()
|
||||
{
|
||||
int y = mDesc->mPosition;
|
||||
|
||||
if (y <= 0)
|
||||
{
|
||||
if (BigFont && mDesc->mTitle.IsNotEmpty())
|
||||
{
|
||||
const char *tt = mDesc->mTitle;
|
||||
if (*tt == '$') tt = GStrings(tt+1);
|
||||
screen->DrawText (BigFont, OptionSettings.mTitleColor,
|
||||
(screen->GetWidth() - BigFont->StringWidth(tt) * CleanXfac_1) / 2, 10*CleanYfac_1,
|
||||
tt, DTA_CleanNoMove_1, true, TAG_DONE);
|
||||
y = -y + BigFont->GetHeight();
|
||||
}
|
||||
else
|
||||
{
|
||||
y = -y;
|
||||
}
|
||||
}
|
||||
mDesc->mDrawTop = y;
|
||||
//int labelofs = OptionSettings.mLabelOffset * CleanXfac_1;
|
||||
//int cursorspace = 14 * CleanXfac_1;
|
||||
int fontheight = OptionSettings.mLinespacing * CleanYfac_1;
|
||||
y *= CleanYfac_1;
|
||||
|
||||
int indent = mDesc->mIndent;
|
||||
if (indent > 280)
|
||||
{ // kludge for the compatibility options with their extremely long labels
|
||||
if (indent + 40 <= CleanWidth_1)
|
||||
{
|
||||
indent = (screen->GetWidth() - ((indent + 40) * CleanXfac_1)) / 2 + indent * CleanXfac_1;
|
||||
}
|
||||
else
|
||||
{
|
||||
indent = screen->GetWidth() - 40 * CleanXfac_1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
indent = (indent - 160) * CleanXfac_1 + screen->GetWidth() / 2;
|
||||
}
|
||||
|
||||
int ytop = y + mDesc->mScrollTop * 8 * CleanYfac_1;
|
||||
int lastrow = screen->GetHeight() - SmallFont->GetHeight() * CleanYfac_1;
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < mDesc->mItems.Size() && y <= lastrow; i++, y += fontheight)
|
||||
{
|
||||
// Don't scroll the uppermost items
|
||||
if (i == mDesc->mScrollTop)
|
||||
{
|
||||
i += mDesc->mScrollPos;
|
||||
if (i >= mDesc->mItems.Size()) break; // skipped beyond end of menu
|
||||
}
|
||||
int cur_indent = mDesc->mItems[i]->Draw(mDesc, y, indent, mDesc->mSelectedItem == i);
|
||||
if (cur_indent >= 0 && mDesc->mSelectedItem == i && mDesc->mItems[i]->Selectable())
|
||||
{
|
||||
if (((DMenu::MenuTime%8) < 6) || DMenu::CurrentMenu != this)
|
||||
{
|
||||
M_DrawConText(OptionSettings.mFontColorSelection, cur_indent + 3 * CleanXfac_1, y-CleanYfac_1+OptionSettings.mLabelOffset, "\xd");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CanScrollUp = (mDesc->mScrollPos > 0);
|
||||
CanScrollDown = (i < mDesc->mItems.Size());
|
||||
VisBottom = i - 1;
|
||||
|
||||
if (CanScrollUp)
|
||||
{
|
||||
M_DrawConText(CR_ORANGE, 3 * CleanXfac_1, ytop + OptionSettings.mLabelOffset, "\x1a");
|
||||
}
|
||||
if (CanScrollDown)
|
||||
{
|
||||
M_DrawConText(CR_ORANGE, 3 * CleanXfac_1, y - 8*CleanYfac_1 + OptionSettings.mLabelOffset, "\x1b");
|
||||
}
|
||||
Super::Drawer();
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// base class for menu items
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
FOptionMenuItem::~FOptionMenuItem()
|
||||
{
|
||||
if (mLabel != NULL) delete [] mLabel;
|
||||
}
|
||||
|
||||
bool FOptionMenuItem::CheckCoordinate(FOptionMenuDescriptor *desc, int x, int y)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int FOptionMenuItem::Draw(FOptionMenuDescriptor *desc, int y, int indent, bool selected)
|
||||
{
|
||||
return indent;
|
||||
}
|
||||
|
||||
bool FOptionMenuItem::Selectable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FOptionMenuItem::MouseEvent(int type, int x, int y)
|
||||
{
|
||||
if (Selectable() && type == DMenu::MOUSE_Release)
|
||||
{
|
||||
return DMenu::CurrentMenu->MenuEvent(MKEY_Enter, true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int FOptionMenuItem::GetIndent()
|
||||
{
|
||||
return mCentered? 0 : SmallFont->StringWidth(mLabel);
|
||||
}
|
||||
|
||||
void FOptionMenuItem::drawLabel(int indent, int y, EColorRange color, bool grayed)
|
||||
{
|
||||
const char *label = mLabel;
|
||||
if (*label == '$') label = GStrings(label+1);
|
||||
|
||||
int overlay = grayed? MAKEARGB(96,48,0,0) : 0;
|
||||
|
||||
int x;
|
||||
int w = SmallFont->StringWidth(label) * CleanXfac_1;
|
||||
if (!mCentered) x = indent - w;
|
||||
else x = (screen->GetWidth() - w) / 2;
|
||||
screen->DrawText (SmallFont, color, x, y, label, DTA_CleanNoMove_1, true, DTA_ColorOverlay, overlay, TAG_DONE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FOptionMenuDescriptor::CalcIndent()
|
||||
{
|
||||
// calculate the menu indent
|
||||
int widest = 0, thiswidth;
|
||||
|
||||
for (unsigned i = 0; i < mItems.Size(); i++)
|
||||
{
|
||||
thiswidth = mItems[i]->GetIndent();
|
||||
if (thiswidth > widest) widest = thiswidth;
|
||||
}
|
||||
mIndent = widest + 4;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
FOptionMenuItem *FOptionMenuDescriptor::GetItem(FName name)
|
||||
{
|
||||
for(unsigned i=0;i<mItems.Size(); i++)
|
||||
{
|
||||
FName nm = mItems[i]->GetAction(NULL);
|
||||
if (nm == name) return mItems[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
class DGameplayMenu : public DOptionMenu
|
||||
{
|
||||
DECLARE_CLASS(DGameplayMenu, DOptionMenu)
|
||||
|
||||
public:
|
||||
DGameplayMenu()
|
||||
{}
|
||||
|
||||
void Drawer ()
|
||||
{
|
||||
Super::Drawer();
|
||||
|
||||
char text[64];
|
||||
mysnprintf(text, 64, "dmflags = %d dmflags2 = %d", *dmflags, *dmflags2);
|
||||
screen->DrawText (SmallFont, OptionSettings.mFontColorValue,
|
||||
(screen->GetWidth() - SmallFont->StringWidth (text) * CleanXfac_1) / 2, 0, text,
|
||||
DTA_CleanNoMove_1, true, TAG_DONE);
|
||||
}
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(DGameplayMenu)
|
||||
|
||||
class DCompatibilityMenu : public DOptionMenu
|
||||
{
|
||||
DECLARE_CLASS(DCompatibilityMenu, DOptionMenu)
|
||||
|
||||
public:
|
||||
DCompatibilityMenu()
|
||||
{}
|
||||
|
||||
void Drawer ()
|
||||
{
|
||||
Super::Drawer();
|
||||
|
||||
char text[64];
|
||||
mysnprintf(text, 64, "compatflags = %d", *compatflags);
|
||||
screen->DrawText (SmallFont, OptionSettings.mFontColorValue,
|
||||
(screen->GetWidth() - SmallFont->StringWidth (text) * CleanXfac_1) / 2, 0, text,
|
||||
DTA_CleanNoMove_1, true, TAG_DONE);
|
||||
}
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(DCompatibilityMenu)
|
916
src/menu/optionmenuitems.h
Normal file
916
src/menu/optionmenuitems.h
Normal file
|
@ -0,0 +1,916 @@
|
|||
/*
|
||||
** optionmenuitems.h
|
||||
** Control items for option menus
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2010 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
void M_DrawConText (int color, int x, int y, const char *str);
|
||||
void M_DrawSlider (int x, int y, double min, double max, double cur,int fracdigits);
|
||||
void M_SetVideoMode();
|
||||
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// opens a submenu, action is a submenu name
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class FOptionMenuItemSubmenu : public FOptionMenuItem
|
||||
{
|
||||
int mParam;
|
||||
public:
|
||||
FOptionMenuItemSubmenu(const char *label, const char *menu, int param = 0)
|
||||
: FOptionMenuItem(label, menu)
|
||||
{
|
||||
mParam = param;
|
||||
}
|
||||
|
||||
int Draw(FOptionMenuDescriptor *desc, int y, int indent, bool selected)
|
||||
{
|
||||
drawLabel(indent, y, selected? OptionSettings.mFontColorSelection : OptionSettings.mFontColorMore);
|
||||
return indent;
|
||||
}
|
||||
|
||||
bool Activate()
|
||||
{
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE);
|
||||
M_SetMenu(mAction, mParam);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Executes a CCMD, action is a CCMD name
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class FOptionMenuItemCommand : public FOptionMenuItemSubmenu
|
||||
{
|
||||
public:
|
||||
FOptionMenuItemCommand(const char *label, const char *menu)
|
||||
: FOptionMenuItemSubmenu(label, menu)
|
||||
{
|
||||
}
|
||||
|
||||
bool Activate()
|
||||
{
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE);
|
||||
C_DoCommand(mAction);
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Executes a CCMD after confirmation, action is a CCMD name
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class FOptionMenuItemSafeCommand : public FOptionMenuItemCommand
|
||||
{
|
||||
// action is a CCMD
|
||||
public:
|
||||
FOptionMenuItemSafeCommand(const char *label, const char *menu)
|
||||
: FOptionMenuItemCommand(label, menu)
|
||||
{
|
||||
}
|
||||
|
||||
bool MenuEvent (int mkey, bool fromcontroller)
|
||||
{
|
||||
if (mkey == MKEY_MBYes)
|
||||
{
|
||||
C_DoCommand(mAction);
|
||||
return true;
|
||||
}
|
||||
return FOptionMenuItemCommand::MenuEvent(mkey, fromcontroller);
|
||||
}
|
||||
|
||||
bool Activate()
|
||||
{
|
||||
M_StartMessage("Do you really want to do this?", 0);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Base class for option lists
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class FOptionMenuItemOptionBase : public FOptionMenuItem
|
||||
{
|
||||
protected:
|
||||
// action is a CVAR
|
||||
FOptionValues *mValues;
|
||||
FBaseCVar *mGrayCheck;
|
||||
int mCenter;
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
OP_VALUES = 0x11001
|
||||
};
|
||||
|
||||
FOptionMenuItemOptionBase(const char *label, const char *menu, const char *values, const char *graycheck, int center)
|
||||
: FOptionMenuItem(label, menu)
|
||||
{
|
||||
FOptionValues **opt = OptionValues.CheckKey(values);
|
||||
if (opt != NULL)
|
||||
{
|
||||
mValues = *opt;
|
||||
}
|
||||
else
|
||||
{
|
||||
mValues = NULL;
|
||||
}
|
||||
mGrayCheck = (FBoolCVar*)FindCVar(graycheck, NULL);
|
||||
mCenter = center;
|
||||
}
|
||||
|
||||
bool SetString(int i, const char *newtext)
|
||||
{
|
||||
if (i == OP_VALUES)
|
||||
{
|
||||
FOptionValues **opt = OptionValues.CheckKey(newtext);
|
||||
if (opt != NULL)
|
||||
{
|
||||
mValues = *opt;
|
||||
int s = GetSelection();
|
||||
if (s >= (int)mValues->mValues.Size()) s = 0;
|
||||
SetSelection(s); // readjust the CVAR if its value is outside the range now
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=============================================================================
|
||||
virtual int GetSelection() = 0;
|
||||
virtual void SetSelection(int Selection) = 0;
|
||||
|
||||
//=============================================================================
|
||||
int Draw(FOptionMenuDescriptor *desc, int y, int indent, bool selected)
|
||||
{
|
||||
bool grayed = mGrayCheck != NULL && !(mGrayCheck->GetGenericRep(CVAR_Bool).Bool);
|
||||
|
||||
if (mCenter)
|
||||
{
|
||||
indent = (screen->GetWidth() / 2);
|
||||
}
|
||||
drawLabel(indent, y, selected? OptionSettings.mFontColorSelection : OptionSettings.mFontColor, grayed);
|
||||
|
||||
int overlay = grayed? MAKEARGB(96,48,0,0) : 0;
|
||||
const char *text;
|
||||
int Selection = GetSelection();
|
||||
if (Selection < 0)
|
||||
{
|
||||
text = "Unknown";
|
||||
}
|
||||
else
|
||||
{
|
||||
text = mValues->mValues[Selection].Text;
|
||||
}
|
||||
screen->DrawText (SmallFont, OptionSettings.mFontColorValue, indent + CURSORSPACE, y,
|
||||
text, DTA_CleanNoMove_1, true, DTA_ColorOverlay, overlay, TAG_DONE);
|
||||
return indent;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
bool MenuEvent (int mkey, bool fromcontroller)
|
||||
{
|
||||
if (mValues->mValues.Size() > 0)
|
||||
{
|
||||
int Selection = GetSelection();
|
||||
if (mkey == MKEY_Left)
|
||||
{
|
||||
if (Selection == -1) Selection = 0;
|
||||
else if (--Selection < 0) Selection = mValues->mValues.Size()-1;
|
||||
}
|
||||
else if (mkey == MKEY_Right || mkey == MKEY_Enter)
|
||||
{
|
||||
if (++Selection >= (int)mValues->mValues.Size()) Selection = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FOptionMenuItem::MenuEvent(mkey, fromcontroller);
|
||||
}
|
||||
SetSelection(Selection);
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Selectable()
|
||||
{
|
||||
return !(mGrayCheck != NULL && !(mGrayCheck->GetGenericRep(CVAR_Bool).Bool));
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Change a CVAR, action is the CVAR name
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class FOptionMenuItemOption : public FOptionMenuItemOptionBase
|
||||
{
|
||||
// action is a CVAR
|
||||
FBaseCVar *mCVar;
|
||||
public:
|
||||
|
||||
FOptionMenuItemOption(const char *label, const char *menu, const char *values, const char *graycheck, int center)
|
||||
: FOptionMenuItemOptionBase(label, menu, values, graycheck, center)
|
||||
{
|
||||
mCVar = FindCVar(mAction, NULL);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
int GetSelection()
|
||||
{
|
||||
int Selection = -1;
|
||||
if (mValues != NULL && mCVar != NULL && mValues->mValues.Size() > 0)
|
||||
{
|
||||
if (mValues->mValues[0].TextValue.IsEmpty())
|
||||
{
|
||||
UCVarValue cv = mCVar->GetGenericRep(CVAR_Float);
|
||||
for(unsigned i=0;i<mValues->mValues.Size(); i++)
|
||||
{
|
||||
if (fabs(cv.Float - mValues->mValues[i].Value) < FLT_EPSILON)
|
||||
{
|
||||
Selection = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UCVarValue cv = mCVar->GetGenericRep(CVAR_String);
|
||||
for(unsigned i=0;i<mValues->mValues.Size(); i++)
|
||||
{
|
||||
if (mValues->mValues[i].TextValue.CompareNoCase(cv.String) == 0)
|
||||
{
|
||||
Selection = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Selection;
|
||||
}
|
||||
|
||||
void SetSelection(int Selection)
|
||||
{
|
||||
UCVarValue value;
|
||||
if (mValues != NULL && mCVar != NULL && mValues->mValues.Size() > 0)
|
||||
{
|
||||
if (mValues->mValues[0].TextValue.IsEmpty())
|
||||
{
|
||||
value.Float = (float)mValues->mValues[Selection].Value;
|
||||
mCVar->SetGenericRep (value, CVAR_Float);
|
||||
}
|
||||
else
|
||||
{
|
||||
value.String = mValues->mValues[Selection].TextValue.LockBuffer();
|
||||
mCVar->SetGenericRep (value, CVAR_String);
|
||||
mValues->mValues[Selection].TextValue.UnlockBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// This class is used to capture the key to be used as the new key binding
|
||||
// for a control item
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class DEnterKey : public DMenu
|
||||
{
|
||||
DECLARE_CLASS(DEnterKey, DMenu)
|
||||
|
||||
int *pKey;
|
||||
|
||||
public:
|
||||
DEnterKey(DMenu *parent, int *keyptr)
|
||||
: DMenu(parent)
|
||||
{
|
||||
pKey = keyptr;
|
||||
SetMenuMessage(1);
|
||||
menuactive = MENU_WaitKey; // There should be a better way to disable GUI capture...
|
||||
}
|
||||
|
||||
bool TranslateKeyboardEvents()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void SetMenuMessage(int which)
|
||||
{
|
||||
if (mParentMenu->IsKindOf(RUNTIME_CLASS(DOptionMenu)))
|
||||
{
|
||||
DOptionMenu *m = barrier_cast<DOptionMenu*>(mParentMenu);
|
||||
FListMenuItem *it = m->GetItem(NAME_Controlmessage);
|
||||
if (it != NULL)
|
||||
{
|
||||
it->SetValue(0, which);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Responder(event_t *ev)
|
||||
{
|
||||
if (ev->type == EV_KeyDown)
|
||||
{
|
||||
*pKey = ev->data1;
|
||||
menuactive = MENU_On;
|
||||
SetMenuMessage(0);
|
||||
Close();
|
||||
mParentMenu->MenuEvent((ev->data1 == KEY_ESCAPE)? MKEY_Abort : MKEY_Input, 0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Drawer()
|
||||
{
|
||||
mParentMenu->Drawer();
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef NO_IMP
|
||||
IMPLEMENT_ABSTRACT_CLASS(DEnterKey)
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// // Edit a key binding, Action is the CCMD to bind
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class FOptionMenuItemControl : public FOptionMenuItem
|
||||
{
|
||||
FKeyBindings *mBindings;
|
||||
int mInput;
|
||||
bool mWaiting;
|
||||
public:
|
||||
|
||||
FOptionMenuItemControl(const char *label, const char *menu, FKeyBindings *bindings)
|
||||
: FOptionMenuItem(label, menu)
|
||||
{
|
||||
mBindings = bindings;
|
||||
mWaiting = false;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
int Draw(FOptionMenuDescriptor *desc, int y, int indent, bool selected)
|
||||
{
|
||||
drawLabel(indent, y, mWaiting? OptionSettings.mFontColorHighlight:
|
||||
(selected? OptionSettings.mFontColorSelection : OptionSettings.mFontColor));
|
||||
|
||||
char description[64];
|
||||
int Key1, Key2;
|
||||
|
||||
mBindings->GetKeysForCommand(mAction, &Key1, &Key2);
|
||||
C_NameKeys (description, Key1, Key2);
|
||||
if (description[0])
|
||||
{
|
||||
M_DrawConText(CR_WHITE, indent + CURSORSPACE, y-1+OptionSettings.mLabelOffset, description);
|
||||
}
|
||||
else
|
||||
{
|
||||
screen->DrawText(SmallFont, CR_BLACK, indent + CURSORSPACE, y + OptionSettings.mLabelOffset, "---",
|
||||
DTA_CleanNoMove_1, true, TAG_DONE);
|
||||
}
|
||||
return indent;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
bool MenuEvent(int mkey, bool fromcontroller)
|
||||
{
|
||||
if (mkey == MKEY_Input)
|
||||
{
|
||||
mWaiting = false;
|
||||
mBindings->SetBind(mInput, mAction);
|
||||
return true;
|
||||
}
|
||||
else if (mkey == MKEY_Clear)
|
||||
{
|
||||
mBindings->UnbindACommand(mAction);
|
||||
return true;
|
||||
}
|
||||
else if (mkey == MKEY_Abort)
|
||||
{
|
||||
mWaiting = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Activate()
|
||||
{
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE);
|
||||
mWaiting = true;
|
||||
DMenu *input = new DEnterKey(DMenu::CurrentMenu, &mInput);
|
||||
M_ActivateMenu(input);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class FOptionMenuItemStaticText : public FOptionMenuItem
|
||||
{
|
||||
EColorRange mColor;
|
||||
public:
|
||||
FOptionMenuItemStaticText(const char *label, bool header)
|
||||
: FOptionMenuItem(label, NAME_None, true)
|
||||
{
|
||||
mColor = header? OptionSettings.mFontColorHeader : OptionSettings.mFontColor;
|
||||
}
|
||||
|
||||
int Draw(FOptionMenuDescriptor *desc, int y, int indent, bool selected)
|
||||
{
|
||||
drawLabel(indent, y, mColor);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool Selectable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class FOptionMenuItemStaticTextSwitchable : public FOptionMenuItem
|
||||
{
|
||||
EColorRange mColor;
|
||||
FString mAltText;
|
||||
int mCurrent;
|
||||
|
||||
public:
|
||||
FOptionMenuItemStaticTextSwitchable(const char *label, const char *label2, FName action, bool header)
|
||||
: FOptionMenuItem(label, action, true)
|
||||
{
|
||||
mColor = header? OptionSettings.mFontColorHeader : OptionSettings.mFontColor;
|
||||
mAltText = label2;
|
||||
mCurrent = 0;
|
||||
}
|
||||
|
||||
int Draw(FOptionMenuDescriptor *desc, int y, int indent, bool selected)
|
||||
{
|
||||
const char *txt = mCurrent? (const char*)mAltText : mLabel;
|
||||
int w = SmallFont->StringWidth(txt) * CleanXfac_1;
|
||||
int x = (screen->GetWidth() - w) / 2;
|
||||
screen->DrawText (SmallFont, mColor, x, y, txt, DTA_CleanNoMove_1, true, TAG_DONE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool SetValue(int i, int val)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
mCurrent = val;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SetString(int i, const char *newtext)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
mAltText = newtext;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Selectable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class FOptionMenuSliderBase : public FOptionMenuItem
|
||||
{
|
||||
// action is a CVAR
|
||||
double mMin, mMax, mStep;
|
||||
int mShowValue;
|
||||
int mDrawX;
|
||||
public:
|
||||
FOptionMenuSliderBase(const char *label, double min, double max, double step, int showval)
|
||||
: FOptionMenuItem(label, NAME_None)
|
||||
{
|
||||
mMin = min;
|
||||
mMax = max;
|
||||
mStep = step;
|
||||
mShowValue = showval;
|
||||
mDrawX = 0;
|
||||
}
|
||||
|
||||
virtual double GetValue() = 0;
|
||||
virtual void SetValue(double val) = 0;
|
||||
|
||||
//=============================================================================
|
||||
int Draw(FOptionMenuDescriptor *desc, int y, int indent, bool selected)
|
||||
{
|
||||
drawLabel(indent, y, selected? OptionSettings.mFontColorSelection : OptionSettings.mFontColor);
|
||||
mDrawX = indent + CURSORSPACE;
|
||||
M_DrawSlider (mDrawX, y + OptionSettings.mLabelOffset, mMin, mMax, GetValue(), mShowValue);
|
||||
return indent;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
bool MenuEvent (int mkey, bool fromcontroller)
|
||||
{
|
||||
double value = GetValue();
|
||||
|
||||
if (mkey == MKEY_Left)
|
||||
{
|
||||
value -= mStep;
|
||||
}
|
||||
else if (mkey == MKEY_Right)
|
||||
{
|
||||
value += mStep;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FOptionMenuItem::MenuEvent(mkey, fromcontroller);
|
||||
}
|
||||
SetValue(clamp(value, mMin, mMax));
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MouseEvent(int type, int x, int y)
|
||||
{
|
||||
DOptionMenu *lm = static_cast<DOptionMenu*>(DMenu::CurrentMenu);
|
||||
if (type != DMenu::MOUSE_Click)
|
||||
{
|
||||
if (!lm->CheckFocus(this)) return false;
|
||||
}
|
||||
if (type == DMenu::MOUSE_Release)
|
||||
{
|
||||
lm->ReleaseFocus();
|
||||
}
|
||||
|
||||
int slide_left = mDrawX+8*CleanXfac_1;
|
||||
int slide_right = slide_left + 10*8*CleanXfac_1; // 12 char cells with 8 pixels each.
|
||||
|
||||
if (type == DMenu::MOUSE_Click)
|
||||
{
|
||||
if (x < slide_left || x >= slide_right) return true;
|
||||
}
|
||||
|
||||
x = clamp(x, slide_left, slide_right);
|
||||
double v = mMin + ((x - slide_left) * (mMax - mMin)) / (slide_right - slide_left);
|
||||
if (v != GetValue())
|
||||
{
|
||||
SetValue(v);
|
||||
//S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
|
||||
}
|
||||
if (type == DMenu::MOUSE_Click)
|
||||
{
|
||||
lm->SetFocus(this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class FOptionMenuSliderCVar : public FOptionMenuSliderBase
|
||||
{
|
||||
FBaseCVar *mCVar;
|
||||
public:
|
||||
FOptionMenuSliderCVar(const char *label, const char *menu, double min, double max, double step, int showval)
|
||||
: FOptionMenuSliderBase(label, min, max, step, showval)
|
||||
{
|
||||
mCVar = FindCVar(menu, NULL);
|
||||
}
|
||||
|
||||
double GetValue()
|
||||
{
|
||||
if (mCVar != NULL)
|
||||
{
|
||||
return mCVar->GetGenericRep(CVAR_Float).Float;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SetValue(double val)
|
||||
{
|
||||
if (mCVar != NULL)
|
||||
{
|
||||
UCVarValue value;
|
||||
value.Float = (float)val;
|
||||
mCVar->SetGenericRep(value, CVAR_Float);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class FOptionMenuSliderVar : public FOptionMenuSliderBase
|
||||
{
|
||||
float *mPVal;
|
||||
public:
|
||||
|
||||
FOptionMenuSliderVar(const char *label, float *pVal, double min, double max, double step, int showval)
|
||||
: FOptionMenuSliderBase(label, min, max, step, showval)
|
||||
{
|
||||
mPVal = pVal;
|
||||
}
|
||||
|
||||
double GetValue()
|
||||
{
|
||||
return *mPVal;
|
||||
}
|
||||
|
||||
void SetValue(double val)
|
||||
{
|
||||
*mPVal = (float)val;
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// // Edit a key binding, Action is the CCMD to bind
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class FOptionMenuItemColorPicker : public FOptionMenuItem
|
||||
{
|
||||
FColorCVar *mCVar;
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
CPF_RESET = 0x20001,
|
||||
};
|
||||
|
||||
FOptionMenuItemColorPicker(const char *label, const char *menu)
|
||||
: FOptionMenuItem(label, menu)
|
||||
{
|
||||
FBaseCVar *cv = FindCVar(menu, NULL);
|
||||
if (cv->GetRealType() == CVAR_Color)
|
||||
{
|
||||
mCVar = (FColorCVar*)cv;
|
||||
}
|
||||
else mCVar = NULL;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
int Draw(FOptionMenuDescriptor *desc, int y, int indent, bool selected)
|
||||
{
|
||||
drawLabel(indent, y, selected? OptionSettings.mFontColorSelection : OptionSettings.mFontColor);
|
||||
|
||||
if (mCVar != NULL)
|
||||
{
|
||||
int box_x = indent + CURSORSPACE;
|
||||
int box_y = y + OptionSettings.mLabelOffset * CleanYfac_1 / 2;
|
||||
screen->Clear (box_x, box_y, box_x + 32*CleanXfac_1, box_y + (SmallFont->GetHeight() - 1) * CleanYfac_1,
|
||||
-1, (uint32)*mCVar | 0xff000000);
|
||||
}
|
||||
return indent;
|
||||
}
|
||||
|
||||
bool SetValue(int i, int v)
|
||||
{
|
||||
if (i == CPF_RESET && mCVar != NULL)
|
||||
{
|
||||
mCVar->ResetToDefault();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Activate()
|
||||
{
|
||||
if (mCVar != NULL)
|
||||
{
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE);
|
||||
DMenu *picker = StartPickerMenu(DMenu::CurrentMenu, mLabel, mCVar);
|
||||
if (picker != NULL)
|
||||
{
|
||||
M_ActivateMenu(picker);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class FOptionMenuScreenResolutionLine : public FOptionMenuItem
|
||||
{
|
||||
FString mResTexts[3];
|
||||
int mSelection;
|
||||
int mHighlight;
|
||||
int mMaxValid;
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
SRL_INDEX = 0x30000,
|
||||
SRL_SELECTION = 0x30003,
|
||||
SRL_HIGHLIGHT = 0x30004,
|
||||
};
|
||||
|
||||
FOptionMenuScreenResolutionLine(const char *action)
|
||||
: FOptionMenuItem("", action)
|
||||
{
|
||||
mSelection = 0;
|
||||
mHighlight = -1;
|
||||
}
|
||||
|
||||
bool SetValue(int i, int v)
|
||||
{
|
||||
if (i == SRL_SELECTION)
|
||||
{
|
||||
mSelection = v;
|
||||
return true;
|
||||
}
|
||||
else if (i == SRL_HIGHLIGHT)
|
||||
{
|
||||
mHighlight = v;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetValue(int i, int *v)
|
||||
{
|
||||
if (i == SRL_SELECTION)
|
||||
{
|
||||
*v = mSelection;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SetString(int i, const char *newtext)
|
||||
{
|
||||
if (i >= SRL_INDEX && i <= SRL_INDEX+2)
|
||||
{
|
||||
mResTexts[i-SRL_INDEX] = newtext;
|
||||
if (mResTexts[0].IsEmpty()) mMaxValid = -1;
|
||||
else if (mResTexts[1].IsEmpty()) mMaxValid = 0;
|
||||
else if (mResTexts[2].IsEmpty()) mMaxValid = 1;
|
||||
else mMaxValid = 2;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetString(int i, char *s, int len)
|
||||
{
|
||||
if (i >= SRL_INDEX && i <= SRL_INDEX+2)
|
||||
{
|
||||
strncpy(s, mResTexts[i-SRL_INDEX], len-1);
|
||||
s[len-1] = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MenuEvent (int mkey, bool fromcontroller)
|
||||
{
|
||||
if (mkey == MKEY_Left)
|
||||
{
|
||||
if (--mSelection < 0) mSelection = mMaxValid;
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
|
||||
return true;
|
||||
}
|
||||
else if (mkey == MKEY_Right)
|
||||
{
|
||||
if (++mSelection > mMaxValid) mSelection = 0;
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FOptionMenuItem::MenuEvent(mkey, fromcontroller);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MouseEvent(int type, int x, int y)
|
||||
{
|
||||
int colwidth = screen->GetWidth() / 3;
|
||||
mSelection = x / colwidth;
|
||||
return FOptionMenuItem::MouseEvent(type, x, y);
|
||||
}
|
||||
|
||||
bool Activate()
|
||||
{
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE);
|
||||
M_SetVideoMode();
|
||||
return true;
|
||||
}
|
||||
|
||||
int Draw(FOptionMenuDescriptor *desc, int y, int indent, bool selected)
|
||||
{
|
||||
int colwidth = screen->GetWidth() / 3;
|
||||
EColorRange color;
|
||||
|
||||
for (int x = 0; x < 3; x++)
|
||||
{
|
||||
if (selected && mSelection == x)
|
||||
color = OptionSettings.mFontColorSelection;
|
||||
else if (x == mHighlight)
|
||||
color = OptionSettings.mFontColorHighlight;
|
||||
else
|
||||
color = OptionSettings.mFontColorValue;
|
||||
|
||||
screen->DrawText (SmallFont, color, colwidth * x + 20 * CleanXfac_1, y, mResTexts[x], DTA_CleanNoMove_1, true, TAG_DONE);
|
||||
}
|
||||
return colwidth * mSelection + 20 * CleanXfac_1 - CURSORSPACE;
|
||||
}
|
||||
|
||||
bool Selectable()
|
||||
{
|
||||
return mMaxValid >= 0;
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef NO_IMP
|
||||
CCMD(am_restorecolors)
|
||||
{
|
||||
if (DMenu::CurrentMenu != NULL && DMenu::CurrentMenu->IsKindOf(RUNTIME_CLASS(DOptionMenu)))
|
||||
{
|
||||
DOptionMenu *m = (DOptionMenu*)DMenu::CurrentMenu;
|
||||
const FOptionMenuDescriptor *desc = m->GetDescriptor();
|
||||
// Find the color cvars by scanning the MapColors menu.
|
||||
for (unsigned i = 0; i < desc->mItems.Size(); ++i)
|
||||
{
|
||||
desc->mItems[i]->SetValue(FOptionMenuItemColorPicker::CPF_RESET, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
561
src/menu/playerdisplay.cpp
Normal file
561
src/menu/playerdisplay.cpp
Normal file
|
@ -0,0 +1,561 @@
|
|||
/*
|
||||
** playerdisplay.cpp
|
||||
** The player display for the player setup and class selection screen
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2010 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "doomstat.h"
|
||||
#include "d_player.h"
|
||||
#include "tables.h"
|
||||
#include "m_fixed.h"
|
||||
#include "templates.h"
|
||||
#include "menu/menu.h"
|
||||
#include "colormatcher.h"
|
||||
#include "textures/textures.h"
|
||||
#include "w_wad.h"
|
||||
#include "v_font.h"
|
||||
#include "v_video.h"
|
||||
#include "g_level.h"
|
||||
#include "gi.h"
|
||||
#include "r_defs.h"
|
||||
#include "r_state.h"
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Used by the player display
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
struct FBackdropTexture : public FTexture
|
||||
{
|
||||
public:
|
||||
FBackdropTexture();
|
||||
|
||||
const BYTE *GetColumn(unsigned int column, const Span **spans_out);
|
||||
const BYTE *GetPixels();
|
||||
void Unload();
|
||||
bool CheckModified();
|
||||
|
||||
protected:
|
||||
BYTE Pixels[144*160];
|
||||
static const Span DummySpan[2];
|
||||
int LastRenderTic;
|
||||
|
||||
angle_t time1, time2, time3, time4;
|
||||
angle_t t1ang, t2ang, z1ang, z2ang;
|
||||
|
||||
void Render();
|
||||
};
|
||||
|
||||
|
||||
|
||||
// A 32x32 cloud rendered with Photoshop, plus some other filters
|
||||
static BYTE pattern1[1024] =
|
||||
{
|
||||
5, 9, 7,10, 9,15, 9, 7, 8,10, 5, 3, 5, 7, 9, 8,14, 8, 4, 7, 8, 9, 5, 7,14, 7, 0, 7,13,13, 9, 6,
|
||||
2, 7, 9, 7, 7,10, 8, 8,11,10, 6, 7,10, 7, 5, 6, 6, 4, 7,13,15,16,11,15,11, 8, 0, 4,13,22,17,11,
|
||||
5, 9, 9, 7, 9,10, 4, 3, 6, 7, 8, 6, 5, 4, 2, 2, 1, 4, 6,11,15,15,14,13,17, 9, 5, 9,11,12,17,20,
|
||||
9,16, 9, 8,12,13, 7, 3, 7, 9, 5, 4, 2, 5, 5, 5, 7,11, 6, 7, 6,13,17,10,10, 9,12,17,14,12,16,15,
|
||||
15,13, 5, 3, 9,10, 4,10,12,12, 7, 9, 8, 8, 8,10, 7, 6, 5, 5, 5, 6,11, 9, 3,13,16,18,21,16,23,18,
|
||||
23,13, 0, 0, 0, 0, 0,12,18,14,15,16,13, 7, 7, 5, 9, 6, 6, 8, 4, 0, 0, 0, 0,14,19,17,14,20,21,25,
|
||||
19,20,14,13, 7, 5,13,19,14,13,17,15,14, 7, 3, 5, 6,11, 7, 7, 8, 8,10, 9, 9,18,17,15,14,15,18,16,
|
||||
16,29,24,23,18, 9,17,20,11, 5,12,15,15,12, 6, 3, 4, 6, 7,10,13,18,18,19,16,12,17,19,23,16,14,14,
|
||||
9,18,20,26,19, 5,18,18,10, 5,12,15,14,17,11, 6,11, 9,10,13,10,20,24,20,21,20,14,18,15,22,20,19,
|
||||
0, 6,16,18, 8, 7,15,18,10,13,17,17,13,11,15,11,19,12,13,10, 4,15,19,21,21,24,14, 9,17,20,24,17,
|
||||
18,17, 7, 7,16,21,22,15, 5,14,20,14,13,21,13, 8,12,14, 7, 8,11,15,13,11,16,17, 7, 5,12,17,19,14,
|
||||
25,23,17,16,23,18,15, 7, 0, 6,11, 6,11,15,11, 7,12, 7, 4,10,16,13, 7, 7,15,13, 9,15,21,14, 5, 0,
|
||||
18,22,21,21,21,22,12, 6,14,20,15, 6,10,19,13, 8, 7, 3, 7,12,14,16, 9,12,22,15,12,18,24,19,17, 9,
|
||||
0,15,18,21,17,25,14,13,19,21,21,11, 6,13,16,16,12,10,12,11,13,20,14,13,18,13, 9,15,16,25,31,20,
|
||||
5,20,24,16, 7,14,14,11,18,19,19, 6, 0, 5,11,14,17,16,19,14,15,21,19,15,14,14, 8, 0, 7,24,18,16,
|
||||
9,17,15, 7, 6,14,12, 7,14,16,11, 4, 7, 6,13,16,15,13,12,20,21,20,21,17,18,26,14, 0,13,23,21,11,
|
||||
9,12,18,11,15,21,13, 8,13,13,10, 7,13, 8, 8,19,13, 7, 4,15,19,18,14,12,14,15, 8, 6,16,22,22,15,
|
||||
9,17,14,19,15,14,15, 9,11, 9, 6, 8,14,13,13,12, 5, 0, 0, 6,12,13, 7, 7, 9, 7, 0,12,21,16,15,18,
|
||||
15,16,18,11, 6, 8,15, 9, 2, 0, 5,10,10,16, 9, 0, 4,12,15, 9,12, 9, 7, 7,12, 7, 0, 6,12, 6, 9,13,
|
||||
12,19,15,14,11, 7, 8, 9,12,10, 5, 5, 7,12,12,10,14,16,16,11, 8,12,10,12,10, 8,10,10,14,12,16,16,
|
||||
16,17,20,22,12,15,12,14,19,11, 6, 5,10,13,17,17,21,19,15, 9, 6, 9,15,18,10,10,18,14,20,15,16,17,
|
||||
11,19,19,18,19,14,17,13,12,12, 7,11,18,17,16,15,19,19,10, 2, 0, 8,15,12, 8,11,12,10,19,20,19,19,
|
||||
6,14,18,13,13,16,16,12, 5, 8,10,12,10,13,18,12, 9,10, 7, 6, 5,11, 8, 6, 7,13,16,13,10,15,20,14,
|
||||
0, 5,12,12, 4, 0, 9,16, 9,10,12, 8, 0, 9,13, 9, 0, 2, 4, 7,10, 6, 7, 3, 4,11,16,18,10,11,21,21,
|
||||
16,13,11,15, 8, 0, 5, 9, 8, 7, 6, 3, 0, 9,17, 9, 0, 0, 0, 3, 5, 4, 3, 5, 7,15,16,16,17,14,22,22,
|
||||
24,14,15,12, 9, 0, 5,10, 8, 4, 7,12,10,11,12, 7, 6, 8, 6, 5, 7, 8, 8,11,13,10,15,14,12,18,20,16,
|
||||
16,17,17,18,12, 9,12,16,10, 5, 6,20,13,15, 8, 4, 8, 9, 8, 7, 9,11,12,17,16,16,11,10, 9,10, 5, 0,
|
||||
0,14,18,18,15,16,14, 9,10, 9, 9,15,14,10, 4, 6,10, 8, 8, 7,10, 9,10,16,18,10, 0, 0, 7,12,10, 8,
|
||||
0,14,19,14, 9,11,11, 8, 8,10,15, 9,10, 7, 4,10,13, 9, 7, 5, 5, 7, 7, 7,13,13, 5, 5,14,22,18,16,
|
||||
0,10,14,10, 3, 6, 5, 6, 8, 9, 8, 9, 5, 9, 8, 9, 6, 8, 8, 8, 1, 0, 0, 0, 9,17,12,12,17,19,20,13,
|
||||
6,11,17,11, 5, 5, 8,10, 6, 5, 6, 6, 3, 7, 9, 7, 6, 8,12,10, 4, 8, 6, 6,11,16,16,15,16,17,17,16,
|
||||
11, 9,10,10, 5, 6,12,10, 5, 1, 6,10, 5, 3, 3, 5, 4, 7,15,10, 7,13, 7, 8,15,11,15,15,15, 8,11,15,
|
||||
};
|
||||
|
||||
// Just a 32x32 cloud rendered with the standard Photoshop filter
|
||||
static BYTE pattern2[1024] =
|
||||
{
|
||||
9, 9, 8, 8, 8, 8, 6, 6,13,13,11,21,19,21,23,18,23,24,19,19,24,17,18,12, 9,14, 8,12,12, 5, 8, 6,
|
||||
11,10, 6, 7, 8, 8, 9,13,10,11,17,15,23,22,23,22,20,26,27,26,17,21,20,14,12, 8,11, 8,11, 7, 8, 7,
|
||||
6, 9,13,13,10, 9,13, 7,12,13,16,19,16,20,22,25,22,25,27,22,21,23,15,10,14,14,15,13,12, 8,12, 6,
|
||||
6, 7,12,12,12,16, 9,12,12,15,16,11,21,24,19,24,23,26,28,27,26,21,14,15, 7, 7,10,15,12,11,10, 9,
|
||||
7,14,11,16,12,18,16,14,16,14,11,14,15,21,23,17,20,18,26,24,27,18,20,11,11,14,10,17,17,10, 6,10,
|
||||
13, 9,14,10,13,11,14,15,18,15,15,12,19,19,20,18,22,20,19,22,19,19,19,20,17,15,15,11,16,14,10, 8,
|
||||
13,16,12,16,17,19,17,18,15,19,14,18,15,14,15,17,21,19,23,18,23,22,18,18,17,15,15,16,12,12,15,10,
|
||||
10,12,14,10,16,11,18,15,21,20,20,17,18,19,16,19,14,20,19,14,19,25,22,21,22,24,18,12, 9, 9, 8, 6,
|
||||
10,10,13, 9,15,13,20,19,22,18,18,17,17,21,21,13,13,12,19,18,16,17,27,26,22,23,20,17,12,11, 8, 9,
|
||||
7,13,14,15,11,13,18,22,19,23,23,20,22,24,21,14,12,16,17,19,18,18,22,18,24,23,19,17,16,14, 8, 7,
|
||||
12,12, 8, 8,16,20,26,25,28,28,22,29,23,22,21,18,13,16,15,15,20,17,25,24,19,17,17,17,15,10, 8, 9,
|
||||
7,12,15,11,17,20,25,25,25,29,30,31,28,26,18,16,17,18,20,21,22,20,23,19,18,19,10,16,16,11,11, 8,
|
||||
5, 6, 8,14,14,17,17,21,27,23,27,31,27,22,23,21,19,19,21,19,20,19,17,22,13,17,12,15,10,10,12, 6,
|
||||
8, 9, 8,14,15,16,15,18,27,26,23,25,23,22,18,21,20,17,19,20,20,16,20,14,15,13,12, 8, 8, 7,11,13,
|
||||
7, 6,11,11,11,13,15,22,25,24,26,22,24,26,23,18,24,24,20,18,20,16,17,12,12,12,10, 8,11, 9, 6, 8,
|
||||
9,10, 9, 6, 5,14,16,19,17,21,26,20,23,19,19,17,20,21,26,25,23,21,17,13,12, 5,13,11, 7,12,10,12,
|
||||
6, 5, 4,10,11, 9,10,13,17,20,20,18,23,26,27,20,21,24,20,19,24,20,18,10,11, 3, 6,13, 9, 6, 8, 8,
|
||||
1, 2, 2,11,13,13,11,16,16,16,19,21,20,23,22,28,21,20,19,18,23,16,18, 7, 5, 9, 7, 6, 5,10, 8, 8,
|
||||
0, 0, 6, 9,11,15,12,12,19,18,19,26,22,24,26,30,23,22,22,16,20,19,12,12, 3, 4, 6, 5, 4, 7, 2, 4,
|
||||
2, 0, 0, 7,11, 8,14,13,15,21,26,28,25,24,27,26,23,24,22,22,15,17,12, 8,10, 7, 7, 4, 0, 5, 0, 1,
|
||||
1, 2, 0, 1, 9,14,13,10,19,24,22,29,30,28,30,30,31,23,24,19,17,14,13, 8, 8, 8, 1, 4, 0, 0, 0, 3,
|
||||
5, 2, 4, 2, 9, 8, 8, 8,18,23,20,27,30,27,31,25,28,30,28,24,24,15,11,14,10, 3, 4, 3, 0, 0, 1, 3,
|
||||
9, 3, 4, 3, 5, 6, 8,13,14,23,21,27,28,27,28,27,27,29,30,24,22,23,13,15, 8, 6, 2, 0, 4, 3, 4, 1,
|
||||
6, 5, 5, 3, 9, 3, 6,14,13,16,23,26,28,23,30,31,28,29,26,27,21,20,15,15,13, 9, 1, 0, 2, 0, 5, 8,
|
||||
8, 4, 3, 7, 2, 0,10, 7,10,14,21,21,29,28,25,27,30,28,25,24,27,22,19,13,10, 5, 0, 0, 0, 0, 0, 7,
|
||||
7, 6, 7, 0, 2, 2, 5, 6,15,11,19,24,22,29,27,31,30,30,31,28,23,18,14,14, 7, 5, 0, 0, 1, 0, 1, 0,
|
||||
5, 5, 5, 0, 0, 4, 5,11, 7,10,13,20,21,21,28,31,28,30,26,28,25,21, 9,12, 3, 3, 0, 2, 2, 2, 0, 1,
|
||||
3, 3, 0, 2, 0, 3, 5, 3,11,11,16,19,19,27,26,26,30,27,28,26,23,22,16, 6, 2, 2, 3, 2, 0, 2, 4, 0,
|
||||
0, 0, 0, 3, 3, 1, 0, 4, 5, 9,11,16,24,20,28,26,28,24,28,25,22,21,16, 5, 7, 5, 7, 3, 2, 3, 3, 6,
|
||||
0, 0, 2, 0, 2, 0, 4, 3, 8,12, 9,17,16,23,23,27,27,22,26,22,21,21,13,14, 5, 3, 7, 3, 2, 4, 6, 1,
|
||||
2, 5, 6, 4, 0, 1, 5, 8, 7, 6,15,17,22,20,24,28,23,25,20,21,18,16,13,15,13,10, 8, 5, 5, 9, 3, 7,
|
||||
7, 7, 0, 5, 1, 6, 7, 9,12, 9,12,21,22,25,24,22,23,25,24,18,24,22,17,13,10, 9,10, 9, 6,11, 6, 5,
|
||||
};
|
||||
|
||||
const FTexture::Span FBackdropTexture::DummySpan[2] = { { 0, 160 }, { 0, 0 } };
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
FBackdropTexture::FBackdropTexture()
|
||||
{
|
||||
Width = 144;
|
||||
Height = 160;
|
||||
WidthBits = 8;
|
||||
HeightBits = 8;
|
||||
WidthMask = 255;
|
||||
LastRenderTic = 0;
|
||||
|
||||
time1 = ANGLE_1*180;
|
||||
time2 = ANGLE_1*56;
|
||||
time3 = ANGLE_1*99;
|
||||
time4 = ANGLE_1*1;
|
||||
t1ang = ANGLE_90;
|
||||
t2ang = 0;
|
||||
z1ang = 0;
|
||||
z2ang = ANGLE_90/2;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool FBackdropTexture::CheckModified()
|
||||
{
|
||||
return LastRenderTic != gametic;
|
||||
}
|
||||
|
||||
void FBackdropTexture::Unload()
|
||||
{
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
const BYTE *FBackdropTexture::GetColumn(unsigned int column, const Span **spans_out)
|
||||
{
|
||||
if (LastRenderTic != gametic)
|
||||
{
|
||||
Render();
|
||||
}
|
||||
column = clamp(column, 0u, 143u);
|
||||
if (spans_out != NULL)
|
||||
{
|
||||
*spans_out = DummySpan;
|
||||
}
|
||||
return Pixels + column*160;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
const BYTE *FBackdropTexture::GetPixels()
|
||||
{
|
||||
if (LastRenderTic != gametic)
|
||||
{
|
||||
Render();
|
||||
}
|
||||
return Pixels;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// This is one plasma and two rotozoomers. I think it turned out quite awesome.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FBackdropTexture::Render()
|
||||
{
|
||||
BYTE *from;
|
||||
int width, height, pitch;
|
||||
|
||||
width = 160;
|
||||
height = 144;
|
||||
pitch = width;
|
||||
|
||||
int x, y;
|
||||
|
||||
const angle_t a1add = ANGLE_1/2;
|
||||
const angle_t a2add = ANGLE_MAX-ANGLE_1;
|
||||
const angle_t a3add = ANGLE_1*5/7;
|
||||
const angle_t a4add = ANGLE_MAX-ANGLE_1*4/3;
|
||||
|
||||
const angle_t t1add = ANGLE_MAX-ANGLE_1*2;
|
||||
const angle_t t2add = ANGLE_MAX-ANGLE_1*3+ANGLE_1/6;
|
||||
const angle_t t3add = ANGLE_1*16/7;
|
||||
const angle_t t4add = ANGLE_MAX-ANGLE_1*2/3;
|
||||
const angle_t x1add = 5<<ANGLETOFINESHIFT;
|
||||
const angle_t x2add = ANGLE_MAX-(13<<ANGLETOFINESHIFT);
|
||||
const angle_t z1add = 3<<ANGLETOFINESHIFT;
|
||||
const angle_t z2add = 4<<ANGLETOFINESHIFT;
|
||||
|
||||
angle_t a1, a2, a3, a4;
|
||||
fixed_t c1, c2, c3, c4;
|
||||
DWORD tx, ty, tc, ts;
|
||||
DWORD ux, uy, uc, us;
|
||||
DWORD ltx, lty, lux, luy;
|
||||
|
||||
from = Pixels;
|
||||
|
||||
a3 = time3;
|
||||
a4 = time4;
|
||||
|
||||
fixed_t z1 = (finecosine[z2ang>>ANGLETOFINESHIFT]>>2)+FRACUNIT/2;
|
||||
fixed_t z2 = (finecosine[z1ang>>ANGLETOFINESHIFT]>>2)+FRACUNIT*3/4;
|
||||
|
||||
tc = MulScale5 (finecosine[t1ang>>ANGLETOFINESHIFT], z1);
|
||||
ts = MulScale5 (finesine[t1ang>>ANGLETOFINESHIFT], z1);
|
||||
uc = MulScale5 (finecosine[t2ang>>ANGLETOFINESHIFT], z2);
|
||||
us = MulScale5 (finesine[t2ang>>ANGLETOFINESHIFT], z2);
|
||||
|
||||
ltx = -width/2*tc;
|
||||
lty = -width/2*ts;
|
||||
lux = -width/2*uc;
|
||||
luy = -width/2*us;
|
||||
|
||||
for (y = 0; y < height; ++y)
|
||||
{
|
||||
a1 = time1;
|
||||
a2 = time2;
|
||||
c3 = finecosine[a3>>ANGLETOFINESHIFT];
|
||||
c4 = finecosine[a4>>ANGLETOFINESHIFT];
|
||||
tx = ltx - (y-height/2)*ts;
|
||||
ty = lty + (y-height/2)*tc;
|
||||
ux = lux - (y-height/2)*us;
|
||||
uy = luy + (y-height/2)*uc;
|
||||
for (x = 0; x < width; ++x)
|
||||
{
|
||||
c1 = finecosine[a1>>ANGLETOFINESHIFT];
|
||||
c2 = finecosine[a2>>ANGLETOFINESHIFT];
|
||||
from[x] = ((c1 + c2 + c3 + c4) >> (FRACBITS+3-7)) + 128 // plasma
|
||||
+ pattern1[(tx>>27)+((ty>>22)&992)] // rotozoomer 1
|
||||
+ pattern2[(ux>>27)+((uy>>22)&992)]; // rotozoomer 2
|
||||
tx += tc;
|
||||
ty += ts;
|
||||
ux += uc;
|
||||
uy += us;
|
||||
a1 += a1add;
|
||||
a2 += a2add;
|
||||
}
|
||||
a3 += a3add;
|
||||
a4 += a4add;
|
||||
from += pitch;
|
||||
}
|
||||
|
||||
time1 += t1add;
|
||||
time2 += t2add;
|
||||
time3 += t3add;
|
||||
time4 += t4add;
|
||||
t1ang += x1add;
|
||||
t2ang += x2add;
|
||||
z1ang += z1add;
|
||||
z2ang += z2add;
|
||||
|
||||
LastRenderTic = gametic;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
FListMenuItemPlayerDisplay::FListMenuItemPlayerDisplay(FListMenuDescriptor *menu, int x, int y, PalEntry c1, PalEntry c2, bool np, FName action)
|
||||
: FListMenuItem(x, y, action)
|
||||
{
|
||||
mOwner = menu;
|
||||
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
int r = c1.r + c2.r * i / 255;
|
||||
int g = c1.g + c2.g * i / 255;
|
||||
int b = c1.b + c2.b * i / 255;
|
||||
mRemap.Remap[i] = ColorMatcher.Pick (r, g, b);
|
||||
mRemap.Palette[i] = PalEntry(255, r, g, b);
|
||||
}
|
||||
mBackdrop = new FBackdropTexture;
|
||||
mPlayerClass = NULL;
|
||||
mPlayerState = NULL;
|
||||
mNoportrait = np;
|
||||
mMode = 0;
|
||||
mRotation = 0;
|
||||
mTranslate = false;
|
||||
mSkin = 0;
|
||||
mRandomClass = 0;
|
||||
mRandomTimer = 0;
|
||||
mClassNum = -1;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
FListMenuItemPlayerDisplay::~FListMenuItemPlayerDisplay()
|
||||
{
|
||||
delete mBackdrop;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FListMenuItemPlayerDisplay::UpdateRandomClass()
|
||||
{
|
||||
if (--mRandomTimer < 0)
|
||||
{
|
||||
if (++mRandomClass >= (int)PlayerClasses.Size ()) mRandomClass = 0;
|
||||
mPlayerClass = &PlayerClasses[mRandomClass];
|
||||
mPlayerState = GetDefaultByType (mPlayerClass->Type)->SeeState;
|
||||
mPlayerTics = mPlayerState->GetTics();
|
||||
mRandomTimer = 6;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FListMenuItemPlayerDisplay::SetPlayerClass(int classnum, bool force)
|
||||
{
|
||||
if (classnum < 0 || classnum >= (int)PlayerClasses.Size ())
|
||||
{
|
||||
if (mClassNum != -1)
|
||||
{
|
||||
mClassNum = -1;
|
||||
mRandomTimer = 0;
|
||||
UpdateRandomClass();
|
||||
}
|
||||
}
|
||||
else if (mPlayerClass != &PlayerClasses[classnum] || force)
|
||||
{
|
||||
mPlayerClass = &PlayerClasses[classnum];
|
||||
mPlayerState = GetDefaultByType (mPlayerClass->Type)->SeeState;
|
||||
mPlayerTics = mPlayerState->GetTics();
|
||||
mClassNum = classnum;
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool FListMenuItemPlayerDisplay::UpdatePlayerClass()
|
||||
{
|
||||
int classnum;
|
||||
FName seltype = mOwner->mItems[mOwner->mSelectedItem]->GetAction(&classnum);
|
||||
|
||||
if (seltype != NAME_Episodemenu) return false;
|
||||
if (PlayerClasses.Size() == 0) return false;
|
||||
|
||||
SetPlayerClass(classnum);
|
||||
return true;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool FListMenuItemPlayerDisplay::SetValue(int i, int value)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case PDF_MODE:
|
||||
mMode = value;
|
||||
return true;
|
||||
|
||||
case PDF_ROTATION:
|
||||
mRotation = value;
|
||||
return true;
|
||||
|
||||
case PDF_TRANSLATE:
|
||||
mTranslate = value;
|
||||
|
||||
case PDF_CLASS:
|
||||
SetPlayerClass(value, true);
|
||||
break;
|
||||
|
||||
case PDF_SKIN:
|
||||
mSkin = value;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FListMenuItemPlayerDisplay::Ticker()
|
||||
{
|
||||
if (mClassNum < 0) UpdateRandomClass();
|
||||
|
||||
if (mPlayerState != NULL && mPlayerState->GetTics () != -1 && mPlayerState->GetNextState () != NULL)
|
||||
{
|
||||
if (--mPlayerTics <= 0)
|
||||
{
|
||||
mPlayerState = mPlayerState->GetNextState();
|
||||
mPlayerTics = mPlayerState->GetTics();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FListMenuItemPlayerDisplay::Drawer(bool selected)
|
||||
{
|
||||
if (mMode == 0 && !UpdatePlayerClass())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const char *portrait = mPlayerClass->Type->Meta.GetMetaString(APMETA_Portrait);
|
||||
|
||||
if (portrait != NULL && !mNoportrait)
|
||||
{
|
||||
FTextureID texid = TexMan.CheckForTexture(portrait, FTexture::TEX_MiscPatch);
|
||||
if (texid.isValid())
|
||||
{
|
||||
FTexture *tex = TexMan(texid);
|
||||
if (tex != NULL)
|
||||
{
|
||||
screen->DrawTexture (tex, mXpos, mYpos, DTA_Clean, true, TAG_DONE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
int x = (mXpos - 160) * CleanXfac + (SCREENWIDTH>>1);
|
||||
int y = (mYpos - 100) * CleanYfac + (SCREENHEIGHT>>1);
|
||||
|
||||
screen->DrawTexture (mBackdrop, x, y - 1,
|
||||
DTA_DestWidth, 72 * CleanXfac,
|
||||
DTA_DestHeight, 80 * CleanYfac,
|
||||
DTA_Translation, &mRemap,
|
||||
DTA_Masked, true,
|
||||
TAG_DONE);
|
||||
|
||||
V_DrawFrame (x, y, 72*CleanXfac, 80*CleanYfac-1);
|
||||
|
||||
spriteframe_t *sprframe;
|
||||
fixed_t scaleX, scaleY;
|
||||
|
||||
if (mSkin == 0)
|
||||
{
|
||||
sprframe = &SpriteFrames[sprites[mPlayerState->sprite].spriteframes + mPlayerState->GetFrame()];
|
||||
scaleX = GetDefaultByType(mPlayerClass->Type)->scaleX;
|
||||
scaleY = GetDefaultByType(mPlayerClass->Type)->scaleY;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprframe = &SpriteFrames[sprites[skins[mSkin].sprite].spriteframes + mPlayerState->GetFrame()];
|
||||
scaleX = skins[mSkin].ScaleX;
|
||||
scaleY = skins[mSkin].ScaleY;
|
||||
}
|
||||
|
||||
if (sprframe != NULL)
|
||||
{
|
||||
FTexture *tex = TexMan(sprframe->Texture[mRotation]);
|
||||
if (tex != NULL && tex->UseType != FTexture::TEX_Null)
|
||||
{
|
||||
FRemapTable *trans = NULL;
|
||||
if (mTranslate) trans = translationtables[TRANSLATION_Players](MAXPLAYERS);
|
||||
screen->DrawTexture (tex,
|
||||
x + 36*CleanXfac, y + 71*CleanYfac,
|
||||
DTA_DestWidth, MulScale16 (tex->GetWidth() * CleanXfac, scaleX),
|
||||
DTA_DestHeight, MulScale16 (tex->GetHeight() * CleanYfac, scaleY),
|
||||
DTA_Translation, trans,
|
||||
TAG_DONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
1142
src/menu/playermenu.cpp
Normal file
1142
src/menu/playermenu.cpp
Normal file
File diff suppressed because it is too large
Load diff
154
src/menu/readthis.cpp
Normal file
154
src/menu/readthis.cpp
Normal file
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
** readthis.cpp
|
||||
** Help screens
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2001-2010 Randy Heit
|
||||
** Copyright 2010 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "menu/menu.h"
|
||||
#include "v_video.h"
|
||||
#include "g_level.h"
|
||||
#include "gi.h"
|
||||
#include "textures/textures.h"
|
||||
|
||||
class DReadThisMenu : public DMenu
|
||||
{
|
||||
DECLARE_CLASS(DReadThisMenu, DMenu)
|
||||
int mScreen;
|
||||
int mInfoTic;
|
||||
|
||||
public:
|
||||
|
||||
DReadThisMenu(DMenu *parent = NULL);
|
||||
void Drawer();
|
||||
bool MenuEvent(int mkey, bool fromcontroller);
|
||||
bool DimAllowed () { return false; }
|
||||
bool MouseEvent(int type, int x, int y);
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(DReadThisMenu)
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Read This Menus
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
DReadThisMenu::DReadThisMenu(DMenu *parent)
|
||||
: DMenu(parent)
|
||||
{
|
||||
mScreen = 1;
|
||||
mInfoTic = gametic;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void DReadThisMenu::Drawer()
|
||||
{
|
||||
FTexture *tex = NULL, *prevpic = NULL;
|
||||
fixed_t alpha;
|
||||
|
||||
// Did the mapper choose a custom help page via MAPINFO?
|
||||
if ((level.info != NULL) && level.info->f1[0] != 0)
|
||||
{
|
||||
tex = TexMan.FindTexture(level.info->f1);
|
||||
mScreen = 1;
|
||||
}
|
||||
|
||||
if (tex == NULL)
|
||||
{
|
||||
tex = TexMan[gameinfo.infoPages[mScreen-1].GetChars()];
|
||||
}
|
||||
|
||||
if (mScreen > 1)
|
||||
{
|
||||
prevpic = TexMan[gameinfo.infoPages[mScreen-2].GetChars()];
|
||||
}
|
||||
|
||||
alpha = MIN<fixed_t> (Scale (gametic - mInfoTic, OPAQUE, TICRATE/3), OPAQUE);
|
||||
if (alpha < OPAQUE && prevpic != NULL)
|
||||
{
|
||||
screen->DrawTexture (prevpic, 0, 0,
|
||||
DTA_DestWidth, screen->GetWidth(),
|
||||
DTA_DestHeight, screen->GetHeight(),
|
||||
TAG_DONE);
|
||||
}
|
||||
screen->DrawTexture (tex, 0, 0,
|
||||
DTA_DestWidth, screen->GetWidth(),
|
||||
DTA_DestHeight, screen->GetHeight(),
|
||||
DTA_Alpha, alpha,
|
||||
TAG_DONE);
|
||||
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool DReadThisMenu::MenuEvent(int mkey, bool fromcontroller)
|
||||
{
|
||||
if (mkey == MKEY_Enter)
|
||||
{
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE);
|
||||
mScreen++;
|
||||
mInfoTic = gametic;
|
||||
if ((level.info != NULL && level.info->f1[0] != 0) || mScreen > int(gameinfo.infoPages.Size()))
|
||||
{
|
||||
Close();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else return Super::MenuEvent(mkey, fromcontroller);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool DReadThisMenu::MouseEvent(int type, int x, int y)
|
||||
{
|
||||
if (type == MOUSE_Click)
|
||||
{
|
||||
return MenuEvent(MKEY_Enter, true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
442
src/menu/videomenu.cpp
Normal file
442
src/menu/videomenu.cpp
Normal file
|
@ -0,0 +1,442 @@
|
|||
/*
|
||||
** videomenu.cpp
|
||||
** The video modes menu
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2001-2010 Randy Heit
|
||||
** Copyright 2010 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include <float.h>
|
||||
|
||||
#include "menu/menu.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "w_wad.h"
|
||||
#include "sc_man.h"
|
||||
#include "v_font.h"
|
||||
#include "g_level.h"
|
||||
#include "d_player.h"
|
||||
#include "v_video.h"
|
||||
#include "gi.h"
|
||||
#include "i_system.h"
|
||||
#include "c_bind.h"
|
||||
#include "v_palette.h"
|
||||
#include "d_event.h"
|
||||
#include "d_gui.h"
|
||||
#include "i_music.h"
|
||||
#include "m_joy.h"
|
||||
#include "sbar.h"
|
||||
#include "hardware.h"
|
||||
|
||||
#define NO_IMP
|
||||
#include "optionmenuitems.h"
|
||||
|
||||
|
||||
/*=======================================
|
||||
*
|
||||
* Video Modes Menu
|
||||
*
|
||||
*=======================================*/
|
||||
static void BuildModesList (int hiwidth, int hiheight, int hi_id);
|
||||
static bool GetSelectedSize (int *width, int *height);
|
||||
static void SetModesMenu (int w, int h, int bits);
|
||||
FOptionMenuDescriptor *GetVideoModeMenu();
|
||||
|
||||
extern bool setmodeneeded;
|
||||
extern int NewWidth, NewHeight, NewBits;
|
||||
extern int DisplayBits;
|
||||
|
||||
EXTERN_CVAR (Int, vid_defwidth)
|
||||
EXTERN_CVAR (Int, vid_defheight)
|
||||
EXTERN_CVAR (Int, vid_defbits)
|
||||
EXTERN_CVAR (Bool, fullscreen)
|
||||
EXTERN_CVAR (Bool, vid_tft) // Defined below
|
||||
|
||||
int testingmode; // Holds time to revert to old mode
|
||||
int OldWidth, OldHeight, OldBits;
|
||||
static FIntCVar DummyDepthCvar (NULL, 0, 0);
|
||||
static BYTE BitTranslate[32];
|
||||
|
||||
CUSTOM_CVAR (Int, menu_screenratios, 0, CVAR_ARCHIVE)
|
||||
{
|
||||
if (self < 0 || self > 4)
|
||||
{
|
||||
self = 3;
|
||||
}
|
||||
else if (self == 4 && !vid_tft)
|
||||
{
|
||||
self = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
BuildModesList (SCREENWIDTH, SCREENHEIGHT, DisplayBits);
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR (Bool, vid_tft, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
FOptionMenuDescriptor *opt = GetVideoModeMenu();
|
||||
if (opt != NULL)
|
||||
{
|
||||
FOptionMenuItem *it = opt->GetItem("menu_screenratios");
|
||||
if (it != NULL)
|
||||
{
|
||||
if (self)
|
||||
{
|
||||
it->SetString(FOptionMenuItemOptionBase::OP_VALUES, "RatiosTFT");
|
||||
}
|
||||
else
|
||||
{
|
||||
it->SetString(FOptionMenuItemOptionBase::OP_VALUES, "Ratios");
|
||||
}
|
||||
}
|
||||
}
|
||||
setsizeneeded = true;
|
||||
if (StatusBar != NULL)
|
||||
{
|
||||
StatusBar->ScreenSizeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
class DVideoModeMenu : public DOptionMenu
|
||||
{
|
||||
DECLARE_CLASS(DVideoModeMenu, DOptionMenu)
|
||||
|
||||
public:
|
||||
|
||||
DVideoModeMenu()
|
||||
{
|
||||
SetModesMenu (SCREENWIDTH, SCREENHEIGHT, DisplayBits);
|
||||
}
|
||||
|
||||
bool MenuEvent(int mkey, bool fromcontroller)
|
||||
{
|
||||
if ((mkey == MKEY_Up || mkey == MKEY_Down) && mDesc->mSelectedItem >= 0 &&
|
||||
mDesc->mSelectedItem < (int)mDesc->mItems.Size())
|
||||
{
|
||||
int sel;
|
||||
bool selected = mDesc->mItems[mDesc->mSelectedItem]->GetValue(FOptionMenuScreenResolutionLine::SRL_SELECTION, &sel);
|
||||
bool res = Super::MenuEvent(mkey, fromcontroller);
|
||||
if (selected) mDesc->mItems[mDesc->mSelectedItem]->SetValue(FOptionMenuScreenResolutionLine::SRL_SELECTION, sel);
|
||||
return res;
|
||||
}
|
||||
return Super::MenuEvent(mkey, fromcontroller);
|
||||
}
|
||||
|
||||
bool Responder(event_t *ev)
|
||||
{
|
||||
if (ev->type == EV_GUI_Event && ev->subtype == EV_GUI_KeyDown &&
|
||||
(ev->data1 == 't' || ev->data1 == 'T'))
|
||||
{
|
||||
if (!GetSelectedSize (&NewWidth, &NewHeight))
|
||||
{
|
||||
NewWidth = SCREENWIDTH;
|
||||
NewHeight = SCREENHEIGHT;
|
||||
}
|
||||
OldWidth = SCREENWIDTH;
|
||||
OldHeight = SCREENHEIGHT;
|
||||
OldBits = DisplayBits;
|
||||
NewBits = BitTranslate[DummyDepthCvar];
|
||||
setmodeneeded = true;
|
||||
testingmode = I_GetTime(false) + 5 * TICRATE;
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE);
|
||||
SetModesMenu (NewWidth, NewHeight, NewBits);
|
||||
return true;
|
||||
}
|
||||
return Super::Responder(ev);
|
||||
}
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(DVideoModeMenu)
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
FOptionMenuDescriptor *GetVideoModeMenu()
|
||||
{
|
||||
FMenuDescriptor **desc = MenuDescriptors.CheckKey(NAME_VideoModeMenu);
|
||||
if (desc != NULL && (*desc)->mType == MDESC_OptionsMenu)
|
||||
{
|
||||
return (FOptionMenuDescriptor *)*desc;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Set some stuff up for the video modes menu
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
static void BuildModesList (int hiwidth, int hiheight, int hi_bits)
|
||||
{
|
||||
char strtemp[32];
|
||||
int i, c;
|
||||
int width, height, showbits;
|
||||
bool letterbox=false;
|
||||
int ratiomatch;
|
||||
|
||||
if (menu_screenratios >= 0 && menu_screenratios <= 4 && menu_screenratios != 3)
|
||||
{
|
||||
ratiomatch = menu_screenratios;
|
||||
}
|
||||
else
|
||||
{
|
||||
ratiomatch = -1;
|
||||
}
|
||||
showbits = BitTranslate[DummyDepthCvar];
|
||||
|
||||
if (Video != NULL)
|
||||
{
|
||||
Video->StartModeIterator (showbits, screen->IsFullscreen());
|
||||
}
|
||||
|
||||
FOptionMenuDescriptor *opt = GetVideoModeMenu();
|
||||
if (opt != NULL)
|
||||
{
|
||||
for (i = NAME_res_0; i<= NAME_res_9; i++)
|
||||
{
|
||||
FOptionMenuItem *it = opt->GetItem((ENamedName)i);
|
||||
if (it != NULL)
|
||||
{
|
||||
it->SetValue(FOptionMenuScreenResolutionLine::SRL_HIGHLIGHT, -1);
|
||||
for (c = 0; c < 3; c++)
|
||||
{
|
||||
bool haveMode = false;
|
||||
|
||||
if (Video != NULL)
|
||||
{
|
||||
while ((haveMode = Video->NextMode (&width, &height, &letterbox)) &&
|
||||
(ratiomatch >= 0 && CheckRatio (width, height) != ratiomatch))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (haveMode)
|
||||
{
|
||||
if (width == hiwidth && height == hiheight)
|
||||
{
|
||||
it->SetValue(FOptionMenuScreenResolutionLine::SRL_SELECTION, c);
|
||||
it->SetValue(FOptionMenuScreenResolutionLine::SRL_HIGHLIGHT, c);
|
||||
}
|
||||
|
||||
mysnprintf (strtemp, countof(strtemp), "%dx%d%s", width, height, letterbox?TEXTCOLOR_BROWN" LB":"");
|
||||
it->SetString(FOptionMenuScreenResolutionLine::SRL_INDEX+c, strtemp);
|
||||
}
|
||||
else
|
||||
{
|
||||
it->SetString(FOptionMenuScreenResolutionLine::SRL_INDEX+c, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void M_RestoreMode ()
|
||||
{
|
||||
NewWidth = OldWidth;
|
||||
NewHeight = OldHeight;
|
||||
NewBits = OldBits;
|
||||
setmodeneeded = true;
|
||||
testingmode = 0;
|
||||
SetModesMenu (OldWidth, OldHeight, OldBits);
|
||||
}
|
||||
|
||||
void M_SetDefaultMode ()
|
||||
{
|
||||
// Make current resolution the default
|
||||
vid_defwidth = SCREENWIDTH;
|
||||
vid_defheight = SCREENHEIGHT;
|
||||
vid_defbits = DisplayBits;
|
||||
testingmode = 0;
|
||||
SetModesMenu (SCREENWIDTH, SCREENHEIGHT, DisplayBits);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void M_RefreshModesList ()
|
||||
{
|
||||
BuildModesList (SCREENWIDTH, SCREENHEIGHT, DisplayBits);
|
||||
}
|
||||
|
||||
void M_InitVideoModesMenu ()
|
||||
{
|
||||
int dummy1, dummy2;
|
||||
size_t currval = 0;
|
||||
|
||||
M_RefreshModesList();
|
||||
|
||||
for (unsigned int i = 1; i <= 32 && currval < countof(BitTranslate); i++)
|
||||
{
|
||||
Video->StartModeIterator (i, screen->IsFullscreen());
|
||||
if (Video->NextMode (&dummy1, &dummy2, NULL))
|
||||
{
|
||||
BitTranslate[currval++] = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* It doesn't look like this can be anything but DISPLAY_Both, regardless of any other settings.
|
||||
switch (Video->GetDisplayType ())
|
||||
{
|
||||
case DISPLAY_FullscreenOnly:
|
||||
case DISPLAY_WindowOnly:
|
||||
// todo: gray out fullscreen option
|
||||
default:
|
||||
break;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
static bool GetSelectedSize (int *width, int *height)
|
||||
{
|
||||
FOptionMenuDescriptor *opt = GetVideoModeMenu();
|
||||
if (opt != NULL)
|
||||
{
|
||||
int line = opt->mSelectedItem;
|
||||
int hsel;
|
||||
FOptionMenuItem *it = opt->mItems[line];
|
||||
if (it->GetValue(FOptionMenuScreenResolutionLine::SRL_SELECTION, &hsel))
|
||||
{
|
||||
char buffer[32];
|
||||
char *breakpt;
|
||||
if (it->GetString(FOptionMenuScreenResolutionLine::SRL_INDEX+hsel, buffer, sizeof(buffer)))
|
||||
{
|
||||
*width = strtol (buffer, &breakpt, 10);
|
||||
*height = strtol (breakpt+1, NULL, 10);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void M_SetVideoMode()
|
||||
{
|
||||
if (!GetSelectedSize (&NewWidth, &NewHeight))
|
||||
{
|
||||
NewWidth = SCREENWIDTH;
|
||||
NewHeight = SCREENHEIGHT;
|
||||
}
|
||||
else
|
||||
{
|
||||
testingmode = 1;
|
||||
setmodeneeded = true;
|
||||
NewBits = BitTranslate[DummyDepthCvar];
|
||||
}
|
||||
SetModesMenu (NewWidth, NewHeight, NewBits);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
static int FindBits (int bits)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 22; i++)
|
||||
{
|
||||
if (BitTranslate[i] == bits)
|
||||
return i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void SetModesMenu (int w, int h, int bits)
|
||||
{
|
||||
DummyDepthCvar = FindBits (bits);
|
||||
|
||||
FOptionMenuDescriptor *opt = GetVideoModeMenu();
|
||||
if (opt != NULL)
|
||||
{
|
||||
FOptionMenuItem *it;
|
||||
if (testingmode <= 1)
|
||||
{
|
||||
it = opt->GetItem(NAME_VMEnterText);
|
||||
if (it != NULL) it->SetValue(0, 0);
|
||||
it = opt->GetItem(NAME_VMTestText);
|
||||
if (it != NULL) it->SetValue(0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
it = opt->GetItem(NAME_VMTestText);
|
||||
if (it != NULL) it->SetValue(0, 1);
|
||||
it = opt->GetItem(NAME_VMEnterText);
|
||||
if (it != NULL)
|
||||
{
|
||||
char strtemp[64];
|
||||
mysnprintf (strtemp, countof(strtemp), "TESTING %dx%dx%d", w, h, bits);
|
||||
it->SetValue(0, 1);
|
||||
it->SetString(0, strtemp);
|
||||
}
|
||||
}
|
||||
}
|
||||
BuildModesList (w, h, bits);
|
||||
}
|
|
@ -195,9 +195,9 @@ bool ProduceMIDI (const BYTE *musBuf, int len, TArray<BYTE> &outFile)
|
|||
switch (event & 0x70)
|
||||
{
|
||||
case MUS_NOTEOFF:
|
||||
midStatus |= MIDI_NOTEOFF;
|
||||
midStatus |= MIDI_NOTEON;
|
||||
mid1 = t & 127;
|
||||
mid2 = 64;
|
||||
mid2 = 0;
|
||||
break;
|
||||
|
||||
case MUS_NOTEON:
|
||||
|
|
|
@ -75,7 +75,4 @@ typedef struct
|
|||
// WORD UsedInstruments[NumInstruments];
|
||||
} MUSHeader;
|
||||
|
||||
bool ProduceMIDI (const BYTE *musBuf, int len, TArray<BYTE> &outFile);
|
||||
bool ProduceMIDI (const BYTE *musBuf, int len, FILE *outFile);
|
||||
|
||||
#endif //__MUS2MIDI_H__
|
||||
|
|
|
@ -383,6 +383,7 @@ xx(Firstsideonly)
|
|||
xx(Transparent)
|
||||
xx(Passuse)
|
||||
xx(Repeatspecial)
|
||||
xx(Conversation)
|
||||
|
||||
xx(Playercross)
|
||||
xx(Playeruse)
|
||||
|
@ -417,6 +418,7 @@ xx(Gravity)
|
|||
xx(Lightcolor)
|
||||
xx(Fadecolor)
|
||||
xx(Desaturation)
|
||||
xx(SoundSequence)
|
||||
xx(Silent)
|
||||
xx(Nofallingdamage)
|
||||
xx(Dropactors)
|
||||
|
@ -440,5 +442,87 @@ xx(nofakecontrast)
|
|||
xx(smoothlighting)
|
||||
xx(blockprojectiles)
|
||||
xx(blockuse)
|
||||
xx(hidden)
|
||||
|
||||
xx(Renderstyle)
|
||||
|
||||
// USDF keywords
|
||||
xx(Amount)
|
||||
xx(Text)
|
||||
xx(Displaycost)
|
||||
xx(Yesmessage)
|
||||
xx(Nomessage)
|
||||
xx(Log)
|
||||
xx(Giveitem)
|
||||
xx(Nextpage)
|
||||
xx(Closedialog)
|
||||
xx(Cost)
|
||||
xx(Page)
|
||||
xx(Count)
|
||||
xx(Name)
|
||||
xx(Panel)
|
||||
xx(Dialog)
|
||||
xx(Ifitem)
|
||||
xx(Choice)
|
||||
xx(Link)
|
||||
|
||||
// Special menus
|
||||
xx(Mainmenu)
|
||||
xx(Episodemenu)
|
||||
xx(Playerclassmenu)
|
||||
xx(HexenDefaultPlayerclassmenu)
|
||||
xx(Skillmenu)
|
||||
xx(Startgame)
|
||||
xx(StartgameConfirm)
|
||||
xx(Loadgamemenu)
|
||||
xx(Savegamemenu)
|
||||
xx(Readthismenu)
|
||||
xx(Optionsmenu)
|
||||
xx(Quitmenu)
|
||||
xx(Savemenu)
|
||||
xx(Playermenu)
|
||||
|
||||
xx(Playerbox)
|
||||
xx(Team)
|
||||
xx(Color)
|
||||
xx(Red)
|
||||
xx(Green)
|
||||
xx(Blue)
|
||||
xx(Class)
|
||||
xx(Skin)
|
||||
xx(Gender)
|
||||
xx(Autoaim)
|
||||
xx(Switch)
|
||||
xx(Playerdisplay)
|
||||
xx(Controlmessage)
|
||||
xx(Crosshairs)
|
||||
xx(Colorpickermenu)
|
||||
xx(Mididevices)
|
||||
xx(CustomizeControls)
|
||||
xx(MessageOptions)
|
||||
xx(AutomapOptions)
|
||||
xx(ScoreboardOptions)
|
||||
xx(MapColorMenu)
|
||||
xx(GameplayOptions)
|
||||
xx(CompatibilityOptions)
|
||||
xx(MouseOptions)
|
||||
xx(JoystickOptions)
|
||||
xx(SoundOptions)
|
||||
xx(AdvSoundOptions)
|
||||
xx(ModReplayerOptions)
|
||||
xx(VideoOptions)
|
||||
xx(JoystickConfigMenu)
|
||||
xx(VMEnterText)
|
||||
xx(VMTestText)
|
||||
xx(VideoModeMenu)
|
||||
xx(res_0)
|
||||
xx(res_1)
|
||||
xx(res_2)
|
||||
xx(res_3)
|
||||
xx(res_4)
|
||||
xx(res_5)
|
||||
xx(res_6)
|
||||
xx(res_7)
|
||||
xx(res_8)
|
||||
xx(res_9)
|
||||
xx(AlwaysRun)
|
||||
|
|
|
@ -62,10 +62,17 @@ const int AAPreference = 16;
|
|||
#define D(x) do{}while(0)
|
||||
#endif
|
||||
|
||||
FNodeBuilder::FNodeBuilder(FLevel &level)
|
||||
: Level(level), GLNodes(false), SegsStuffed(0)
|
||||
{
|
||||
|
||||
VertexMap = NULL;
|
||||
}
|
||||
|
||||
FNodeBuilder::FNodeBuilder (FLevel &level,
|
||||
TArray<FPolyStart> &polyspots, TArray<FPolyStart> &anchors,
|
||||
bool makeGLNodes, bool enableSSE2)
|
||||
: Level(level), GLNodes(makeGLNodes), EnableSSE2(enableSSE2), SegsStuffed(0)
|
||||
bool makeGLNodes)
|
||||
: Level(level), GLNodes(makeGLNodes), SegsStuffed(0)
|
||||
{
|
||||
VertexMap = new FVertexMap (*this, Level.MinX, Level.MinY, Level.MaxX, Level.MaxY);
|
||||
FindUsedVertices (Level.Vertices, Level.NumVertices);
|
||||
|
@ -83,6 +90,33 @@ FNodeBuilder::~FNodeBuilder()
|
|||
}
|
||||
}
|
||||
|
||||
void FNodeBuilder::BuildMini(bool makeGLNodes)
|
||||
{
|
||||
GLNodes = makeGLNodes;
|
||||
GroupSegPlanesSimple();
|
||||
BuildTree();
|
||||
}
|
||||
|
||||
void FNodeBuilder::Clear()
|
||||
{
|
||||
SegsStuffed = 0;
|
||||
Nodes.Clear();
|
||||
Subsectors.Clear();
|
||||
SubsectorSets.Clear();
|
||||
Segs.Clear();
|
||||
Vertices.Clear();
|
||||
SegList.Clear();
|
||||
PlaneChecked.Clear();
|
||||
Planes.Clear();
|
||||
Touched.Clear();
|
||||
Colinear.Clear();
|
||||
SplitSharers.Clear();
|
||||
if (VertexMap == NULL)
|
||||
{
|
||||
VertexMap = new FVertexMapSimple(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void FNodeBuilder::BuildTree ()
|
||||
{
|
||||
fixed_t bbox[4];
|
||||
|
@ -90,35 +124,38 @@ void FNodeBuilder::BuildTree ()
|
|||
C_InitTicker ("Building BSP", FRACUNIT);
|
||||
HackSeg = DWORD_MAX;
|
||||
HackMate = DWORD_MAX;
|
||||
CreateNode (0, bbox);
|
||||
CreateNode (0, Segs.Size(), bbox);
|
||||
CreateSubsectorsForReal ();
|
||||
C_InitTicker (NULL, 0);
|
||||
}
|
||||
|
||||
int FNodeBuilder::CreateNode (DWORD set, fixed_t bbox[4])
|
||||
int FNodeBuilder::CreateNode (DWORD set, unsigned int count, fixed_t bbox[4])
|
||||
{
|
||||
node_t node;
|
||||
int skip, count, selstat;
|
||||
int skip, selstat;
|
||||
DWORD splitseg;
|
||||
|
||||
count = CountSegs (set);
|
||||
skip = count / MaxSegs;
|
||||
skip = int(count / MaxSegs);
|
||||
|
||||
// When building GL nodes, count may not be an exact count of the number of segs
|
||||
// in the set. That's okay, because we just use it to get a skip count, so an
|
||||
// estimate is fine.
|
||||
if ((selstat = SelectSplitter (set, node, splitseg, skip, true)) > 0 ||
|
||||
(skip > 0 && (selstat = SelectSplitter (set, node, splitseg, 1, true)) > 0) ||
|
||||
(selstat < 0 && (SelectSplitter (set, node, splitseg, skip, false) > 0 ||
|
||||
(skip > 0 && SelectSplitter (set, node, splitseg, 1, false)))) ||
|
||||
CheckSubsector (set, node, splitseg, count))
|
||||
CheckSubsector (set, node, splitseg))
|
||||
{
|
||||
// Create a normal node
|
||||
DWORD set1, set2;
|
||||
unsigned int count1, count2;
|
||||
|
||||
SplitSegs (set, node, splitseg, set1, set2);
|
||||
SplitSegs (set, node, splitseg, set1, set2, count1, count2);
|
||||
D(PrintSet (1, set1));
|
||||
D(Printf (PRINT_LOG, "(%d,%d) delta (%d,%d) from seg %d\n", node.x>>16, node.y>>16, node.dx>>16, node.dy>>16, splitseg));
|
||||
D(PrintSet (2, set2));
|
||||
node.intchildren[0] = CreateNode (set1, node.bbox[0]);
|
||||
node.intchildren[1] = CreateNode (set2, node.bbox[1]);
|
||||
node.intchildren[0] = CreateNode (set1, count1, node.bbox[0]);
|
||||
node.intchildren[1] = CreateNode (set2, count2, node.bbox[1]);
|
||||
bbox[BOXTOP] = MAX (node.bbox[0][BOXTOP], node.bbox[1][BOXTOP]);
|
||||
bbox[BOXBOTTOM] = MIN (node.bbox[0][BOXBOTTOM], node.bbox[1][BOXBOTTOM]);
|
||||
bbox[BOXLEFT] = MIN (node.bbox[0][BOXLEFT], node.bbox[1][BOXLEFT]);
|
||||
|
@ -173,17 +210,15 @@ void FNodeBuilder::CreateSubsectorsForReal ()
|
|||
subsector_t sub;
|
||||
unsigned int i;
|
||||
|
||||
sub.poly = NULL;
|
||||
sub.validcount = 0;
|
||||
sub.CenterX = 0; // Code in p_setup.cpp will set these for us later.
|
||||
sub.CenterY = 0;
|
||||
sub.sector = NULL;
|
||||
sub.polys = NULL;
|
||||
sub.BSP = NULL;
|
||||
|
||||
for (i = 0; i < SubsectorSets.Size(); ++i)
|
||||
{
|
||||
DWORD set = SubsectorSets[i];
|
||||
DWORD firstline = (DWORD)SegList.Size();
|
||||
|
||||
sub.firstline = (DWORD)SegList.Size();
|
||||
while (set != DWORD_MAX)
|
||||
{
|
||||
USegPtr ptr;
|
||||
|
@ -192,14 +227,15 @@ void FNodeBuilder::CreateSubsectorsForReal ()
|
|||
SegList.Push (ptr);
|
||||
set = ptr.SegPtr->next;
|
||||
}
|
||||
sub.numlines = (DWORD)(SegList.Size() - sub.firstline);
|
||||
sub.numlines = (DWORD)(SegList.Size() - firstline);
|
||||
sub.firstline = (seg_t *)(size_t)firstline;
|
||||
|
||||
// Sort segs by linedef for special effects
|
||||
qsort (&SegList[sub.firstline], sub.numlines, sizeof(USegPtr), SortSegs);
|
||||
qsort (&SegList[firstline], sub.numlines, sizeof(USegPtr), SortSegs);
|
||||
|
||||
// Convert seg pointers into indices
|
||||
D(Printf (PRINT_LOG, "Output subsector %d:\n", Subsectors.Size()));
|
||||
for (unsigned int i = sub.firstline; i < SegList.Size(); ++i)
|
||||
for (unsigned int i = firstline; i < SegList.Size(); ++i)
|
||||
{
|
||||
D(Printf (PRINT_LOG, " Seg %5d%c(%5d,%5d)-(%5d,%5d)\n", SegList[i].SegPtr - &Segs[0],
|
||||
SegList[i].SegPtr->linedef == -1 ? '+' : ' ',
|
||||
|
@ -273,24 +309,12 @@ int STACK_ARGS FNodeBuilder::SortSegs (const void *a, const void *b)
|
|||
}
|
||||
}
|
||||
|
||||
int FNodeBuilder::CountSegs (DWORD set) const
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
while (set != DWORD_MAX)
|
||||
{
|
||||
count++;
|
||||
set = Segs[set].next;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// Given a set of segs, checks to make sure they all belong to a single
|
||||
// sector. If so, false is returned, and they become a subsector. If not,
|
||||
// a splitter is synthesized, and true is returned to continue processing
|
||||
// down this branch of the tree.
|
||||
|
||||
bool FNodeBuilder::CheckSubsector (DWORD set, node_t &node, DWORD &splitseg, int setsize)
|
||||
bool FNodeBuilder::CheckSubsector (DWORD set, node_t &node, DWORD &splitseg)
|
||||
{
|
||||
sector_t *sec;
|
||||
DWORD seg;
|
||||
|
@ -371,7 +395,7 @@ bool FNodeBuilder::CheckSubsectorOverlappingSegs (DWORD set, node_t &node, DWORD
|
|||
{
|
||||
if (Segs[seg2].linedef == -1)
|
||||
{ // Do not put minisegs into a new subsector.
|
||||
swap (seg1, seg2);
|
||||
swapvalues (seg1, seg2);
|
||||
}
|
||||
D(Printf(PRINT_LOG, "Need to synthesize a splitter for set %d on seg %d (ov)\n", set, seg2));
|
||||
splitseg = DWORD_MAX;
|
||||
|
@ -506,7 +530,7 @@ int FNodeBuilder::Heuristic (node_t &node, DWORD set, bool honorNoSplit)
|
|||
int realSegs[2] = { 0, 0 };
|
||||
int specialSegs[2] = { 0, 0 };
|
||||
DWORD i = set;
|
||||
int sidev1, sidev2;
|
||||
int sidev[2];
|
||||
int side;
|
||||
bool splitter = false;
|
||||
unsigned int max, m2, p, q;
|
||||
|
@ -525,7 +549,7 @@ int FNodeBuilder::Heuristic (node_t &node, DWORD set, bool honorNoSplit)
|
|||
}
|
||||
else
|
||||
{
|
||||
side = ClassifyLine (node, test, sidev1, sidev2);
|
||||
side = ClassifyLine (node, &Vertices[test->v1], &Vertices[test->v2], sidev);
|
||||
}
|
||||
switch (side)
|
||||
{
|
||||
|
@ -535,9 +559,9 @@ int FNodeBuilder::Heuristic (node_t &node, DWORD set, bool honorNoSplit)
|
|||
// The "right" thing to do in this case is to only reject it if there is
|
||||
// another nosplit seg from the same sector at this vertex. Note that a line
|
||||
// that lies exactly on top of the splitter is okay.
|
||||
if (test->loopnum && honorNoSplit && (sidev1 == 0 || sidev2 == 0))
|
||||
if (test->loopnum && honorNoSplit && (sidev[0] == 0 || sidev[1] == 0))
|
||||
{
|
||||
if ((sidev1 | sidev2) != 0)
|
||||
if ((sidev[0] | sidev[1]) != 0)
|
||||
{
|
||||
max = Touched.Size();
|
||||
for (p = 0; p < max; ++p)
|
||||
|
@ -735,8 +759,10 @@ int FNodeBuilder::Heuristic (node_t &node, DWORD set, bool honorNoSplit)
|
|||
return score;
|
||||
}
|
||||
|
||||
void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &outset0, DWORD &outset1)
|
||||
void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &outset0, DWORD &outset1, unsigned int &count0, unsigned int &count1)
|
||||
{
|
||||
unsigned int _count0 = 0;
|
||||
unsigned int _count1 = 0;
|
||||
outset0 = DWORD_MAX;
|
||||
outset1 = DWORD_MAX;
|
||||
|
||||
|
@ -749,18 +775,18 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou
|
|||
FPrivSeg *seg = &Segs[set];
|
||||
int next = seg->next;
|
||||
|
||||
int sidev1, sidev2, side;
|
||||
int sidev[2], side;
|
||||
|
||||
if (HackSeg == set)
|
||||
{
|
||||
HackSeg = DWORD_MAX;
|
||||
side = 1;
|
||||
sidev1 = sidev2 = 0;
|
||||
sidev[0] = sidev[1] = 0;
|
||||
hack = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
side = ClassifyLine (node, seg, sidev1, sidev2);
|
||||
side = ClassifyLine (node, &Vertices[seg->v1], &Vertices[seg->v2], sidev);
|
||||
hack = false;
|
||||
}
|
||||
|
||||
|
@ -769,11 +795,13 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou
|
|||
case 0: // seg is entirely in front
|
||||
seg->next = outset0;
|
||||
outset0 = set;
|
||||
_count0++;
|
||||
break;
|
||||
|
||||
case 1: // seg is entirely in back
|
||||
seg->next = outset1;
|
||||
outset1 = set;
|
||||
_count1++;
|
||||
break;
|
||||
|
||||
default: // seg needs to be split
|
||||
|
@ -803,18 +831,20 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou
|
|||
Printf("SelectVertexClose selected endpoint of seg %u\n", set);
|
||||
}
|
||||
|
||||
seg2 = SplitSeg (set, vertnum, sidev1);
|
||||
seg2 = SplitSeg (set, vertnum, sidev[0]);
|
||||
|
||||
Segs[seg2].next = outset0;
|
||||
outset0 = seg2;
|
||||
Segs[set].next = outset1;
|
||||
outset1 = set;
|
||||
_count0++;
|
||||
_count1++;
|
||||
|
||||
// Also split the seg on the back side
|
||||
if (Segs[set].partner != DWORD_MAX)
|
||||
{
|
||||
int partner1 = Segs[set].partner;
|
||||
int partner2 = SplitSeg (partner1, vertnum, sidev2);
|
||||
int partner2 = SplitSeg (partner1, vertnum, sidev[1]);
|
||||
// The newly created seg stays in the same set as the
|
||||
// back seg because it has not been considered for splitting
|
||||
// yet. If it had been, then the front seg would have already
|
||||
|
@ -835,17 +865,17 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou
|
|||
}
|
||||
if (side >= 0 && GLNodes)
|
||||
{
|
||||
if (sidev1 == 0)
|
||||
if (sidev[0] == 0)
|
||||
{
|
||||
double dist1 = AddIntersection (node, seg->v1);
|
||||
if (sidev2 == 0)
|
||||
if (sidev[1] == 0)
|
||||
{
|
||||
double dist2 = AddIntersection (node, seg->v2);
|
||||
FSplitSharer share = { dist1, set, dist2 > dist1 };
|
||||
SplitSharers.Push (share);
|
||||
}
|
||||
}
|
||||
else if (sidev2 == 0)
|
||||
else if (sidev[1] == 0)
|
||||
{
|
||||
AddIntersection (node, seg->v2);
|
||||
}
|
||||
|
@ -881,6 +911,8 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou
|
|||
{
|
||||
AddMinisegs (node, splitseg, outset0, outset1);
|
||||
}
|
||||
count0 = _count0;
|
||||
count1 = _count1;
|
||||
}
|
||||
|
||||
void FNodeBuilder::SetNodeFromSeg (node_t &node, const FPrivSeg *pseg) const
|
||||
|
@ -1038,3 +1070,93 @@ void FNodeBuilder::PrintSet (int l, DWORD set)
|
|||
}
|
||||
Printf (PRINT_LOG, "*\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef BACKPATCH
|
||||
#ifdef _WIN32
|
||||
extern "C" {
|
||||
__declspec(dllimport) int __stdcall VirtualProtect(void *, unsigned long, unsigned long, unsigned long *);
|
||||
}
|
||||
#define PAGE_EXECUTE_READWRITE 64
|
||||
#else
|
||||
#include <sys/mman.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
extern "C" int ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2])
|
||||
#else
|
||||
static int *CallerOffset;
|
||||
int ClassifyLineBackpatchC (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2])
|
||||
#endif
|
||||
{
|
||||
// Select the routine based on SSE2 availability and patch the caller so that
|
||||
// they call that routine directly next time instead of going through here.
|
||||
int *calleroffset;
|
||||
int diff;
|
||||
int (*func)(node_t &, const FSimpleVert *, const FSimpleVert *, int[2]);
|
||||
|
||||
#ifdef __GNUC__
|
||||
calleroffset = (int *)__builtin_return_address(0);
|
||||
#else
|
||||
calleroffset = CallerOffset;
|
||||
#endif
|
||||
// printf ("Patching for SSE %d @ %p %d\n", SSELevel, calleroffset, *calleroffset);
|
||||
|
||||
if (CPU.bSSE2)
|
||||
{
|
||||
func = ClassifyLineSSE2;
|
||||
diff = int((char *)ClassifyLineSSE2 - (char *)calleroffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
func = ClassifyLine2;
|
||||
diff = int((char *)ClassifyLine2 - (char *)calleroffset);
|
||||
}
|
||||
|
||||
calleroffset--;
|
||||
// Patch the caller.
|
||||
#ifdef _WIN32
|
||||
unsigned long oldprotect;
|
||||
if (VirtualProtect (calleroffset, 4, PAGE_EXECUTE_READWRITE, &oldprotect))
|
||||
#else
|
||||
// must make this page-aligned for mprotect
|
||||
long pagesize = sysconf(_SC_PAGESIZE);
|
||||
char *callerpage = (char *)((intptr_t)calleroffset & ~(pagesize - 1));
|
||||
size_t protectlen = (intptr_t)calleroffset + sizeof(void*) - (intptr_t)callerpage;
|
||||
int ptect;
|
||||
if (!(ptect = mprotect(callerpage, protectlen, PROT_READ|PROT_WRITE|PROT_EXEC)))
|
||||
#endif
|
||||
{
|
||||
*calleroffset = diff;
|
||||
#ifdef _WIN32
|
||||
VirtualProtect (calleroffset, sizeof(void*), oldprotect, &oldprotect);
|
||||
#else
|
||||
mprotect(callerpage, protectlen, PROT_READ|PROT_EXEC);
|
||||
#endif
|
||||
}
|
||||
|
||||
// And return by calling the real function.
|
||||
return func (node, v1, v2, sidev);
|
||||
}
|
||||
|
||||
#ifndef __GNUC__
|
||||
// The ClassifyLineBackpatch() function here is a stub that uses inline assembly and nakedness
|
||||
// to retrieve the return address of the stack before sending control to the real
|
||||
// ClassifyLineBackpatchC() function. Since BACKPATCH shouldn't be defined on 64-bit builds,
|
||||
// we're okay that VC++ can't do inline assembly on that target.
|
||||
|
||||
extern "C" __declspec(noinline) __declspec(naked) int ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2])
|
||||
{
|
||||
// We store the return address in a global, so as not to need to mess with the parameter list.
|
||||
__asm
|
||||
{
|
||||
mov eax, [esp]
|
||||
mov CallerOffset, eax
|
||||
jmp ClassifyLineBackpatchC
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
131
src/nodebuild.h
131
src/nodebuild.h
|
@ -1,6 +1,10 @@
|
|||
#include "doomdata.h"
|
||||
#include "tarray.h"
|
||||
#include "r_defs.h"
|
||||
#include "x86.h"
|
||||
|
||||
struct FPolySeg;
|
||||
struct FMiniBSP;
|
||||
|
||||
struct FEventInfo
|
||||
{
|
||||
|
@ -40,6 +44,27 @@ private:
|
|||
FEvent *Predecessor (FEvent *event) const;
|
||||
};
|
||||
|
||||
struct FSimpleVert
|
||||
{
|
||||
fixed_t x, y;
|
||||
};
|
||||
|
||||
extern "C"
|
||||
{
|
||||
int ClassifyLine2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]);
|
||||
#ifndef DISABLE_SSE
|
||||
int ClassifyLineSSE1 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]);
|
||||
int ClassifyLineSSE2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]);
|
||||
#ifdef BACKPATCH
|
||||
#ifdef __GNUC__
|
||||
int ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]) __attribute__((noinline));
|
||||
#else
|
||||
int __declspec(noinline) ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
class FNodeBuilder
|
||||
{
|
||||
struct FPrivSeg
|
||||
|
@ -60,9 +85,8 @@ class FNodeBuilder
|
|||
bool planefront;
|
||||
FPrivSeg *hashnext;
|
||||
};
|
||||
struct FPrivVert
|
||||
struct FPrivVert : FSimpleVert
|
||||
{
|
||||
fixed_t x, y;
|
||||
DWORD segs; // segs that use this vertex as v1
|
||||
DWORD segs2; // segs that use this vertex as v2
|
||||
|
||||
|
@ -87,8 +111,24 @@ class FNodeBuilder
|
|||
bool Forward;
|
||||
};
|
||||
|
||||
struct glseg_t : public seg_t
|
||||
{
|
||||
DWORD Partner;
|
||||
};
|
||||
|
||||
|
||||
// Like a blockmap, but for vertices instead of lines
|
||||
class FVertexMap
|
||||
class IVertexMap
|
||||
{
|
||||
public:
|
||||
virtual ~IVertexMap();
|
||||
virtual int SelectVertexExact(FPrivVert &vert) = 0;
|
||||
virtual int SelectVertexClose(FPrivVert &vert) = 0;
|
||||
private:
|
||||
IVertexMap &operator=(const IVertexMap &);
|
||||
};
|
||||
|
||||
class FVertexMap : public IVertexMap
|
||||
{
|
||||
public:
|
||||
FVertexMap (FNodeBuilder &builder, fixed_t minx, fixed_t miny, fixed_t maxx, fixed_t maxy);
|
||||
|
@ -116,12 +156,23 @@ class FNodeBuilder
|
|||
assert (y <= MaxY);
|
||||
return (unsigned(x - MinX) >> BLOCK_SHIFT) + (unsigned(y - MinY) >> BLOCK_SHIFT) * BlocksWide;
|
||||
}
|
||||
};
|
||||
|
||||
FVertexMap &operator= (const FVertexMap &) { return *this; }
|
||||
class FVertexMapSimple : public IVertexMap
|
||||
{
|
||||
public:
|
||||
FVertexMapSimple(FNodeBuilder &builder);
|
||||
|
||||
int SelectVertexExact(FPrivVert &vert);
|
||||
int SelectVertexClose(FPrivVert &vert);
|
||||
private:
|
||||
int InsertVertex(FPrivVert &vert);
|
||||
|
||||
FNodeBuilder &MyBuilder;
|
||||
};
|
||||
|
||||
friend class FVertexMap;
|
||||
|
||||
friend class FVertexMapSimple;
|
||||
|
||||
public:
|
||||
struct FLevel
|
||||
|
@ -132,7 +183,14 @@ public:
|
|||
|
||||
fixed_t MinX, MinY, MaxX, MaxY;
|
||||
|
||||
void FindMapBounds ();
|
||||
void FindMapBounds();
|
||||
void ResetMapBounds()
|
||||
{
|
||||
MinX = FIXED_MAX;
|
||||
MinY = FIXED_MAX;
|
||||
MaxX = FIXED_MIN;
|
||||
MaxY = FIXED_MIN;
|
||||
}
|
||||
};
|
||||
|
||||
struct FPolyStart
|
||||
|
@ -141,16 +199,24 @@ public:
|
|||
fixed_t x, y;
|
||||
};
|
||||
|
||||
FNodeBuilder (FLevel &level);
|
||||
FNodeBuilder (FLevel &level,
|
||||
TArray<FPolyStart> &polyspots, TArray<FPolyStart> &anchors,
|
||||
bool makeGLNodes, bool enableSSE2);
|
||||
bool makeGLNodes);
|
||||
~FNodeBuilder ();
|
||||
|
||||
void Extract (node_t *&nodes, int &nodeCount,
|
||||
seg_t *&segs, int &segCount,
|
||||
seg_t *&segs, glsegextra_t *&glsegextras, int &segCount,
|
||||
subsector_t *&ssecs, int &subCount,
|
||||
vertex_t *&verts, int &vertCount);
|
||||
|
||||
// These are used for building sub-BSP trees for polyobjects.
|
||||
void Clear();
|
||||
void AddPolySegs(FPolySeg *segs, int numsegs);
|
||||
void AddSegs(seg_t *segs, int numsegs);
|
||||
void BuildMini(bool makeGLNodes);
|
||||
void ExtractMini(FMiniBSP *bsp);
|
||||
|
||||
static angle_t PointToAngle (fixed_t dx, fixed_t dy);
|
||||
|
||||
// < 0 : in front of line
|
||||
|
@ -160,7 +226,7 @@ public:
|
|||
static inline int PointOnSide (int x, int y, int x1, int y1, int dx, int dy);
|
||||
|
||||
private:
|
||||
FVertexMap *VertexMap;
|
||||
IVertexMap *VertexMap;
|
||||
|
||||
TArray<node_t> Nodes;
|
||||
TArray<subsector_t> Subsectors;
|
||||
|
@ -181,7 +247,6 @@ private:
|
|||
DWORD HackMate; // Seg to use in front of hack seg
|
||||
FLevel &Level;
|
||||
bool GLNodes; // Add minisegs to make GL nodes?
|
||||
bool EnableSSE2;
|
||||
|
||||
// Progress meter stuff
|
||||
int SegsStuffed;
|
||||
|
@ -191,29 +256,27 @@ private:
|
|||
void MakeSegsFromSides ();
|
||||
int CreateSeg (int linenum, int sidenum);
|
||||
void GroupSegPlanes ();
|
||||
void GroupSegPlanesSimple ();
|
||||
void FindPolyContainers (TArray<FPolyStart> &spots, TArray<FPolyStart> &anchors);
|
||||
bool GetPolyExtents (int polynum, fixed_t bbox[4]);
|
||||
int MarkLoop (DWORD firstseg, int loopnum);
|
||||
void AddSegToBBox (fixed_t bbox[4], const FPrivSeg *seg);
|
||||
int CreateNode (DWORD set, fixed_t bbox[4]);
|
||||
int CreateNode (DWORD set, unsigned int count, fixed_t bbox[4]);
|
||||
int CreateSubsector (DWORD set, fixed_t bbox[4]);
|
||||
void CreateSubsectorsForReal ();
|
||||
bool CheckSubsector (DWORD set, node_t &node, DWORD &splitseg, int setsize);
|
||||
bool CheckSubsector (DWORD set, node_t &node, DWORD &splitseg);
|
||||
bool CheckSubsectorOverlappingSegs (DWORD set, node_t &node, DWORD &splitseg);
|
||||
bool ShoveSegBehind (DWORD set, node_t &node, DWORD seg, DWORD mate); int SelectSplitter (DWORD set, node_t &node, DWORD &splitseg, int step, bool nosplit);
|
||||
void SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &outset0, DWORD &outset1);
|
||||
void SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &outset0, DWORD &outset1, unsigned int &count0, unsigned int &count1);
|
||||
DWORD SplitSeg (DWORD segnum, int splitvert, int v1InFront);
|
||||
int Heuristic (node_t &node, DWORD set, bool honorNoSplit);
|
||||
int CountSegs (DWORD set) const;
|
||||
|
||||
// Returns:
|
||||
// 0 = seg is in front
|
||||
// 1 = seg is in back
|
||||
// -1 = seg cuts the node
|
||||
|
||||
inline int ClassifyLine (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2);
|
||||
int ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2);
|
||||
int ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2);
|
||||
inline int ClassifyLine (node_t &node, const FPrivVert *v1, const FPrivVert *v2, int sidev[2]);
|
||||
|
||||
void FixSplitSharers (const node_t &node);
|
||||
double AddIntersection (const node_t &node, int vertex);
|
||||
|
@ -225,10 +288,10 @@ private:
|
|||
DWORD AddMiniseg (int v1, int v2, DWORD partner, DWORD seg1, DWORD splitseg);
|
||||
void SetNodeFromSeg (node_t &node, const FPrivSeg *pseg) const;
|
||||
|
||||
int CloseSubsector (TArray<seg_t> &segs, int subsector, vertex_t *outVerts);
|
||||
DWORD PushGLSeg (TArray<seg_t> &segs, const FPrivSeg *seg, vertex_t *outVerts);
|
||||
void PushConnectingGLSeg (int subsector, TArray<seg_t> &segs, vertex_t *v1, vertex_t *v2);
|
||||
int OutputDegenerateSubsector (TArray<seg_t> &segs, int subsector, bool bForward, double lastdot, FPrivSeg *&prev, vertex_t *outVerts);
|
||||
int CloseSubsector (TArray<glseg_t> &segs, int subsector, vertex_t *outVerts);
|
||||
DWORD PushGLSeg (TArray<glseg_t> &segs, const FPrivSeg *seg, vertex_t *outVerts);
|
||||
void PushConnectingGLSeg (int subsector, TArray<glseg_t> &segs, vertex_t *v1, vertex_t *v2);
|
||||
int OutputDegenerateSubsector (TArray<glseg_t> &segs, int subsector, bool bForward, double lastdot, FPrivSeg *&prev, vertex_t *outVerts);
|
||||
|
||||
static int STACK_ARGS SortSegs (const void *a, const void *b);
|
||||
|
||||
|
@ -273,21 +336,27 @@ inline int FNodeBuilder::PointOnSide (int x, int y, int x1, int y1, int dx, int
|
|||
return s_num > 0.0 ? -1 : 1;
|
||||
}
|
||||
|
||||
inline int FNodeBuilder::ClassifyLine (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2)
|
||||
inline int FNodeBuilder::ClassifyLine (node_t &node, const FPrivVert *v1, const FPrivVert *v2, int sidev[2])
|
||||
{
|
||||
#if !defined(_M_IX86) && !defined(_M_X64) && !defined(__i386__) && !defined(__amd64__)
|
||||
return ClassifyLine2 (node, seg, sidev1, sidev2);
|
||||
#elif defined(__SSE2__)
|
||||
#ifdef DISABLE_SSE
|
||||
return ClassifyLine2 (node, v1, v2, sidev);
|
||||
#else
|
||||
#if defined(__SSE2__) || defined(_M_IX64)
|
||||
// If compiling with SSE2 support everywhere, just use the SSE2 version.
|
||||
return ClassifyLineSSE2 (node, seg, sidev1, sidev2);
|
||||
return ClassifyLineSSE2 (node, v1, v2, sidev);
|
||||
#elif defined(_MSC_VER) && _MSC_VER < 1300
|
||||
// VC 6 does not support SSE2 optimizations.
|
||||
return ClassifyLine2 (node, seg, sidev1, sidev2);
|
||||
// VC 6 does not support SSE optimizations.
|
||||
return ClassifyLine2 (node, v1, v2, sidev);
|
||||
#else
|
||||
// Select the routine based on our flag.
|
||||
if (EnableSSE2)
|
||||
return ClassifyLineSSE2 (node, seg, sidev1, sidev2);
|
||||
#ifdef BACKPATCH
|
||||
return ClassifyLineBackpatch (node, v1, v2, sidev);
|
||||
#else
|
||||
if (CPU.bSSE2)
|
||||
return ClassifyLineSSE2 (node, v1, v2, sidev);
|
||||
else
|
||||
return ClassifyLine2 (node, seg, sidev1, sidev2);
|
||||
return ClassifyLine2 (node, v1, v2, sidev);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -3,11 +3,8 @@
|
|||
|
||||
#define FAR_ENOUGH 17179869184.f // 4<<32
|
||||
|
||||
int FNodeBuilder::ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2)
|
||||
extern "C" int ClassifyLine2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2])
|
||||
{
|
||||
const FPrivVert *v1 = &Vertices[seg->v1];
|
||||
const FPrivVert *v2 = &Vertices[seg->v2];
|
||||
|
||||
double d_x1 = double(node.x);
|
||||
double d_y1 = double(node.y);
|
||||
double d_dx = double(node.dx);
|
||||
|
@ -26,13 +23,13 @@ int FNodeBuilder::ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1,
|
|||
{
|
||||
if (s_num2 <= -FAR_ENOUGH)
|
||||
{
|
||||
sidev1 = sidev2 = 1;
|
||||
sidev[0] = sidev[1] = 1;
|
||||
return 1;
|
||||
}
|
||||
if (s_num2 >= FAR_ENOUGH)
|
||||
{
|
||||
sidev1 = 1;
|
||||
sidev2 = -1;
|
||||
sidev[0] = 1;
|
||||
sidev[1] = -1;
|
||||
return -1;
|
||||
}
|
||||
nears = 1;
|
||||
|
@ -41,13 +38,13 @@ int FNodeBuilder::ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1,
|
|||
{
|
||||
if (s_num2 >= FAR_ENOUGH)
|
||||
{
|
||||
sidev1 = sidev2 = -1;
|
||||
sidev[0] = sidev[1] = -1;
|
||||
return 0;
|
||||
}
|
||||
if (s_num2 <= -FAR_ENOUGH)
|
||||
{
|
||||
sidev1 = -1;
|
||||
sidev2 = 1;
|
||||
sidev[0] = -1;
|
||||
sidev[1] = 1;
|
||||
return -1;
|
||||
}
|
||||
nears = 1;
|
||||
|
@ -65,41 +62,41 @@ int FNodeBuilder::ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1,
|
|||
double dist = s_num1 * s_num1 * l;
|
||||
if (dist < SIDE_EPSILON*SIDE_EPSILON)
|
||||
{
|
||||
sidev1 = 0;
|
||||
sidev[0] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sidev1 = s_num1 > 0.0 ? -1 : 1;
|
||||
sidev[0] = s_num1 > 0.0 ? -1 : 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sidev1 = s_num1 > 0.0 ? -1 : 1;
|
||||
sidev[0] = s_num1 > 0.0 ? -1 : 1;
|
||||
}
|
||||
if (nears & 1)
|
||||
{
|
||||
double dist = s_num2 * s_num2 * l;
|
||||
if (dist < SIDE_EPSILON*SIDE_EPSILON)
|
||||
{
|
||||
sidev2 = 0;
|
||||
sidev[1] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sidev2 = s_num2 > 0.0 ? -1 : 1;
|
||||
sidev[1] = s_num2 > 0.0 ? -1 : 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sidev2 = s_num2 > 0.0 ? -1 : 1;
|
||||
sidev[1] = s_num2 > 0.0 ? -1 : 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sidev1 = s_num1 > 0.0 ? -1 : 1;
|
||||
sidev2 = s_num2 > 0.0 ? -1 : 1;
|
||||
sidev[0] = s_num1 > 0.0 ? -1 : 1;
|
||||
sidev[1] = s_num2 > 0.0 ? -1 : 1;
|
||||
}
|
||||
|
||||
if ((sidev1 | sidev2) == 0)
|
||||
if ((sidev[0] | sidev[1]) == 0)
|
||||
{ // seg is coplanar with the splitter, so use its orientation to determine
|
||||
// which child it ends up in. If it faces the same direction as the splitter,
|
||||
// it goes in front. Otherwise, it goes in back.
|
||||
|
@ -127,11 +124,11 @@ int FNodeBuilder::ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1,
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (sidev1 <= 0 && sidev2 <= 0)
|
||||
else if (sidev[0] <= 0 && sidev[1] <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (sidev1 >= 0 && sidev2 >= 0)
|
||||
else if (sidev[0] >= 0 && sidev[1] >= 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
#ifndef DISABLE_SSE
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "nodebuild.h"
|
||||
|
||||
#define FAR_ENOUGH 17179869184.f // 4<<32
|
||||
|
||||
// This function is identical to the ClassifyLine2 version. So how does it use SSE2?
|
||||
// Easy! By explicitly enabling SSE2 in the configuration properties for this one
|
||||
// file, we can build it with SSE2 enabled without forcing SSE2 on the rest of the
|
||||
// project.
|
||||
// You may notice that this function is identical to ClassifyLine2.
|
||||
// The reason it is SSE2 is because this file is explicitly compiled
|
||||
// with SSE2 math enabled, but the other files are not.
|
||||
|
||||
int FNodeBuilder::ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2)
|
||||
extern "C" int ClassifyLineSSE2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2])
|
||||
{
|
||||
const FPrivVert *v1 = &Vertices[seg->v1];
|
||||
const FPrivVert *v2 = &Vertices[seg->v2];
|
||||
|
||||
double d_x1 = double(node.x);
|
||||
double d_y1 = double(node.y);
|
||||
double d_dx = double(node.dx);
|
||||
|
@ -31,13 +29,13 @@ int FNodeBuilder::ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &side
|
|||
{
|
||||
if (s_num2 <= -FAR_ENOUGH)
|
||||
{
|
||||
sidev1 = sidev2 = 1;
|
||||
sidev[0] = sidev[1] = 1;
|
||||
return 1;
|
||||
}
|
||||
if (s_num2 >= FAR_ENOUGH)
|
||||
{
|
||||
sidev1 = 1;
|
||||
sidev2 = -1;
|
||||
sidev[0] = 1;
|
||||
sidev[1] = -1;
|
||||
return -1;
|
||||
}
|
||||
nears = 1;
|
||||
|
@ -46,13 +44,13 @@ int FNodeBuilder::ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &side
|
|||
{
|
||||
if (s_num2 >= FAR_ENOUGH)
|
||||
{
|
||||
sidev1 = sidev2 = -1;
|
||||
sidev[0] = sidev[1] = -1;
|
||||
return 0;
|
||||
}
|
||||
if (s_num2 <= -FAR_ENOUGH)
|
||||
{
|
||||
sidev1 = -1;
|
||||
sidev2 = 1;
|
||||
sidev[0] = -1;
|
||||
sidev[1] = 1;
|
||||
return -1;
|
||||
}
|
||||
nears = 1;
|
||||
|
@ -70,41 +68,41 @@ int FNodeBuilder::ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &side
|
|||
double dist = s_num1 * s_num1 * l;
|
||||
if (dist < SIDE_EPSILON*SIDE_EPSILON)
|
||||
{
|
||||
sidev1 = 0;
|
||||
sidev[0] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sidev1 = s_num1 > 0.0 ? -1 : 1;
|
||||
sidev[0] = s_num1 > 0.0 ? -1 : 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sidev1 = s_num1 > 0.0 ? -1 : 1;
|
||||
sidev[0] = s_num1 > 0.0 ? -1 : 1;
|
||||
}
|
||||
if (nears & 1)
|
||||
{
|
||||
double dist = s_num2 * s_num2 * l;
|
||||
if (dist < SIDE_EPSILON*SIDE_EPSILON)
|
||||
{
|
||||
sidev2 = 0;
|
||||
sidev[1] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sidev2 = s_num2 > 0.0 ? -1 : 1;
|
||||
sidev[1] = s_num2 > 0.0 ? -1 : 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sidev2 = s_num2 > 0.0 ? -1 : 1;
|
||||
sidev[1] = s_num2 > 0.0 ? -1 : 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sidev1 = s_num1 > 0.0 ? -1 : 1;
|
||||
sidev2 = s_num2 > 0.0 ? -1 : 1;
|
||||
sidev[0] = s_num1 > 0.0 ? -1 : 1;
|
||||
sidev[1] = s_num2 > 0.0 ? -1 : 1;
|
||||
}
|
||||
|
||||
if ((sidev1 | sidev2) == 0)
|
||||
if ((sidev[0] | sidev[1]) == 0)
|
||||
{ // seg is coplanar with the splitter, so use its orientation to determine
|
||||
// which child it ends up in. If it faces the same direction as the splitter,
|
||||
// it goes in front. Otherwise, it goes in back.
|
||||
|
@ -132,13 +130,15 @@ int FNodeBuilder::ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &side
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (sidev1 <= 0 && sidev2 <= 0)
|
||||
else if (sidev[0] <= 0 && sidev[1] <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (sidev1 >= 0 && sidev2 >= 0)
|
||||
else if (sidev[0] >= 0 && sidev[1] >= 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
#endif
|
||||
|
||||
void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount,
|
||||
seg_t *&outSegs, int &segCount,
|
||||
seg_t *&outSegs, glsegextra_t *&outSegExtras, int &segCount,
|
||||
subsector_t *&outSubs, int &subCount,
|
||||
vertex_t *&outVerts, int &vertCount)
|
||||
{
|
||||
|
@ -99,25 +99,30 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount,
|
|||
|
||||
if (GLNodes)
|
||||
{
|
||||
TArray<seg_t> segs (Segs.Size()*5/4);
|
||||
TArray<glseg_t> segs (Segs.Size()*5/4);
|
||||
|
||||
for (i = 0; i < subCount; ++i)
|
||||
{
|
||||
DWORD numsegs = CloseSubsector (segs, i, outVerts);
|
||||
outSubs[i].numlines = numsegs;
|
||||
outSubs[i].firstline = segs.Size() - numsegs;
|
||||
outSubs[i].poly = NULL;
|
||||
outSubs[i].firstline = (seg_t *)(size_t)(segs.Size() - numsegs);
|
||||
}
|
||||
|
||||
segCount = segs.Size ();
|
||||
outSegs = new seg_t[segCount];
|
||||
memcpy (outSegs, &segs[0], segCount*sizeof(seg_t));
|
||||
outSegExtras = new glsegextra_t[segCount];
|
||||
|
||||
for (i = 0; i < segCount; ++i)
|
||||
{
|
||||
if (outSegs[i].PartnerSeg != NULL)
|
||||
outSegs[i] = *(seg_t *)&segs[i];
|
||||
|
||||
if (segs[i].Partner != DWORD_MAX)
|
||||
{
|
||||
outSegs[i].PartnerSeg = &outSegs[Segs[(unsigned int)(size_t)outSegs[i].PartnerSeg-1].storedseg];
|
||||
outSegExtras[i].PartnerSeg = Segs[segs[i].Partner].storedseg;
|
||||
}
|
||||
else
|
||||
{
|
||||
outSegExtras[i].PartnerSeg = DWORD_MAX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -126,6 +131,7 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount,
|
|||
memcpy (outSubs, &Subsectors[0], subCount*sizeof(subsector_t));
|
||||
segCount = Segs.Size ();
|
||||
outSegs = new seg_t[segCount];
|
||||
outSegExtras = NULL;
|
||||
for (i = 0; i < segCount; ++i)
|
||||
{
|
||||
const FPrivSeg *org = &Segs[SegList[i].SegNum];
|
||||
|
@ -139,10 +145,12 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount,
|
|||
out->frontsector = org->frontsector;
|
||||
out->linedef = Level.Lines + org->linedef;
|
||||
out->sidedef = Level.Sides + org->sidedef;
|
||||
out->PartnerSeg = NULL;
|
||||
out->bPolySeg = false;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < subCount; ++i)
|
||||
{
|
||||
outSubs[i].firstline = &outSegs[(size_t)outSubs[i].firstline];
|
||||
}
|
||||
|
||||
D(Printf("%i segs, %i nodes, %i subsectors\n", segCount, nodeCount, subCount));
|
||||
|
||||
|
@ -153,7 +161,91 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount,
|
|||
}
|
||||
}
|
||||
|
||||
int FNodeBuilder::CloseSubsector (TArray<seg_t> &segs, int subsector, vertex_t *outVerts)
|
||||
void FNodeBuilder::ExtractMini (FMiniBSP *bsp)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
bsp->Verts.Resize(Vertices.Size());
|
||||
for (i = 0; i < Vertices.Size(); ++i)
|
||||
{
|
||||
bsp->Verts[i].x = Vertices[i].x;
|
||||
bsp->Verts[i].y = Vertices[i].y;
|
||||
}
|
||||
|
||||
bsp->Subsectors.Resize(Subsectors.Size());
|
||||
memset(&bsp->Subsectors[0], 0, Subsectors.Size() * sizeof(subsector_t));
|
||||
|
||||
bsp->Nodes.Resize(Nodes.Size());
|
||||
memcpy(&bsp->Nodes[0], &Nodes[0], Nodes.Size()*sizeof(node_t));
|
||||
for (i = 0; i < Nodes.Size(); ++i)
|
||||
{
|
||||
D(Printf(PRINT_LOG, "Node %d:\n", i));
|
||||
// Go backwards because on 64-bit systems, both of the intchildren are
|
||||
// inside the first in-game child.
|
||||
for (int j = 1; j >= 0; --j)
|
||||
{
|
||||
if (bsp->Nodes[i].intchildren[j] & 0x80000000)
|
||||
{
|
||||
D(Printf(PRINT_LOG, " subsector %d\n", bsp->Nodes[i].intchildren[j] & 0x7FFFFFFF));
|
||||
bsp->Nodes[i].children[j] = (BYTE *)&bsp->Subsectors[bsp->Nodes[i].intchildren[j] & 0x7fffffff] + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
D(Printf(PRINT_LOG, " node %d\n", bsp->Nodes[i].intchildren[j]));
|
||||
bsp->Nodes[i].children[j] = &bsp->Nodes[bsp->Nodes[i].intchildren[j]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (GLNodes)
|
||||
{
|
||||
TArray<glseg_t> glsegs;
|
||||
for (i = 0; i < Subsectors.Size(); ++i)
|
||||
{
|
||||
DWORD numsegs = CloseSubsector (glsegs, i, &bsp->Verts[0]);
|
||||
bsp->Subsectors[i].numlines = numsegs;
|
||||
bsp->Subsectors[i].firstline = &bsp->Segs[bsp->Segs.Size() - numsegs];
|
||||
}
|
||||
bsp->Segs.Resize(glsegs.Size());
|
||||
for (i = 0; i < glsegs.Size(); ++i)
|
||||
{
|
||||
bsp->Segs[i] = *(seg_t *)&glsegs[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(&bsp->Subsectors[0], &Subsectors[0], Subsectors.Size()*sizeof(subsector_t));
|
||||
bsp->Segs.Resize(Segs.Size());
|
||||
for (i = 0; i < Segs.Size(); ++i)
|
||||
{
|
||||
const FPrivSeg *org = &Segs[SegList[i].SegNum];
|
||||
seg_t *out = &bsp->Segs[i];
|
||||
|
||||
D(Printf(PRINT_LOG, "Seg %d: v1(%d) -> v2(%d)\n", i, org->v1, org->v2));
|
||||
|
||||
out->v1 = &bsp->Verts[org->v1];
|
||||
out->v2 = &bsp->Verts[org->v2];
|
||||
out->backsector = org->backsector;
|
||||
out->frontsector = org->frontsector;
|
||||
if (org->sidedef != int(NO_SIDE))
|
||||
{
|
||||
out->linedef = Level.Lines + org->linedef;
|
||||
out->sidedef = Level.Sides + org->sidedef;
|
||||
}
|
||||
else // part of a miniseg
|
||||
{
|
||||
out->linedef = NULL;
|
||||
out->sidedef = NULL;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < bsp->Subsectors.Size(); ++i)
|
||||
{
|
||||
bsp->Subsectors[i].firstline = &bsp->Segs[(size_t)bsp->Subsectors[i].firstline];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int FNodeBuilder::CloseSubsector (TArray<glseg_t> &segs, int subsector, vertex_t *outVerts)
|
||||
{
|
||||
FPrivSeg *seg, *prev;
|
||||
angle_t prevAngle;
|
||||
|
@ -164,7 +256,7 @@ int FNodeBuilder::CloseSubsector (TArray<seg_t> &segs, int subsector, vertex_t *
|
|||
bool diffplanes;
|
||||
int firstplane;
|
||||
|
||||
first = Subsectors[subsector].firstline;
|
||||
first = (DWORD)(size_t)Subsectors[subsector].firstline;
|
||||
max = first + Subsectors[subsector].numlines;
|
||||
count = 0;
|
||||
|
||||
|
@ -315,7 +407,7 @@ int FNodeBuilder::CloseSubsector (TArray<seg_t> &segs, int subsector, vertex_t *
|
|||
return count;
|
||||
}
|
||||
|
||||
int FNodeBuilder::OutputDegenerateSubsector (TArray<seg_t> &segs, int subsector, bool bForward, double lastdot, FPrivSeg *&prev, vertex_t *outVerts)
|
||||
int FNodeBuilder::OutputDegenerateSubsector (TArray<glseg_t> &segs, int subsector, bool bForward, double lastdot, FPrivSeg *&prev, vertex_t *outVerts)
|
||||
{
|
||||
static const double bestinit[2] = { -DBL_MAX, DBL_MAX };
|
||||
FPrivSeg *seg;
|
||||
|
@ -323,7 +415,7 @@ int FNodeBuilder::OutputDegenerateSubsector (TArray<seg_t> &segs, int subsector,
|
|||
double dot, x1, y1, dx, dy, dx2, dy2;
|
||||
bool wantside;
|
||||
|
||||
first = Subsectors[subsector].firstline;
|
||||
first = (DWORD)(size_t)Subsectors[subsector].firstline;
|
||||
max = first + Subsectors[subsector].numlines;
|
||||
count = 0;
|
||||
|
||||
|
@ -382,9 +474,9 @@ int FNodeBuilder::OutputDegenerateSubsector (TArray<seg_t> &segs, int subsector,
|
|||
return count;
|
||||
}
|
||||
|
||||
DWORD FNodeBuilder::PushGLSeg (TArray<seg_t> &segs, const FPrivSeg *seg, vertex_t *outVerts)
|
||||
DWORD FNodeBuilder::PushGLSeg (TArray<glseg_t> &segs, const FPrivSeg *seg, vertex_t *outVerts)
|
||||
{
|
||||
seg_t newseg;
|
||||
glseg_t newseg;
|
||||
|
||||
newseg.v1 = outVerts + seg->v1;
|
||||
newseg.v2 = outVerts + seg->v2;
|
||||
|
@ -400,15 +492,13 @@ DWORD FNodeBuilder::PushGLSeg (TArray<seg_t> &segs, const FPrivSeg *seg, vertex_
|
|||
newseg.linedef = NULL;
|
||||
newseg.sidedef = NULL;
|
||||
}
|
||||
newseg.PartnerSeg = (seg_t *)(seg->partner == DWORD_MAX ? 0 : (size_t)seg->partner + 1);
|
||||
newseg.bPolySeg = false;
|
||||
newseg.Subsector = NULL;
|
||||
newseg.Partner = seg->partner;
|
||||
return (DWORD)segs.Push (newseg);
|
||||
}
|
||||
|
||||
void FNodeBuilder::PushConnectingGLSeg (int subsector, TArray<seg_t> &segs, vertex_t *v1, vertex_t *v2)
|
||||
void FNodeBuilder::PushConnectingGLSeg (int subsector, TArray<glseg_t> &segs, vertex_t *v1, vertex_t *v2)
|
||||
{
|
||||
seg_t newseg;
|
||||
glseg_t newseg;
|
||||
|
||||
newseg.v1 = v1;
|
||||
newseg.v2 = v2;
|
||||
|
@ -416,8 +506,6 @@ void FNodeBuilder::PushConnectingGLSeg (int subsector, TArray<seg_t> &segs, vert
|
|||
newseg.frontsector = NULL;
|
||||
newseg.linedef = NULL;
|
||||
newseg.sidedef = NULL;
|
||||
newseg.PartnerSeg = NULL;
|
||||
newseg.bPolySeg = false;
|
||||
newseg.Subsector = NULL;
|
||||
newseg.Partner = DWORD_MAX;
|
||||
segs.Push (newseg);
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "m_bbox.h"
|
||||
#include "r_main.h"
|
||||
#include "i_system.h"
|
||||
#include "po_man.h"
|
||||
|
||||
static const int PO_LINE_START = 1;
|
||||
static const int PO_LINE_EXPLICIT = 5;
|
||||
|
@ -177,6 +178,86 @@ int FNodeBuilder::CreateSeg (int linenum, int sidenum)
|
|||
return segnum;
|
||||
}
|
||||
|
||||
// For every seg, create FPrivSegs and FPrivVerts.
|
||||
|
||||
void FNodeBuilder::AddSegs(seg_t *segs, int numsegs)
|
||||
{
|
||||
assert(numsegs > 0);
|
||||
|
||||
for (int i = 0; i < numsegs; ++i)
|
||||
{
|
||||
FPrivSeg seg;
|
||||
FPrivVert vert;
|
||||
int segnum;
|
||||
|
||||
seg.next = DWORD_MAX;
|
||||
seg.loopnum = 0;
|
||||
seg.partner = DWORD_MAX;
|
||||
seg.hashnext = NULL;
|
||||
seg.planefront = false;
|
||||
seg.planenum = DWORD_MAX;
|
||||
seg.storedseg = DWORD_MAX;
|
||||
|
||||
seg.frontsector = segs[i].frontsector;
|
||||
seg.backsector = segs[i].backsector;
|
||||
vert.x = segs[i].v1->x;
|
||||
vert.y = segs[i].v1->y;
|
||||
seg.v1 = VertexMap->SelectVertexExact(vert);
|
||||
vert.x = segs[i].v2->x;
|
||||
vert.y = segs[i].v2->y;
|
||||
seg.v2 = VertexMap->SelectVertexExact(vert);
|
||||
seg.linedef = int(segs[i].linedef - Level.Lines);
|
||||
seg.sidedef = segs[i].sidedef != NULL ? int(segs[i].sidedef - Level.Sides) : int(NO_SIDE);
|
||||
seg.nextforvert = Vertices[seg.v1].segs;
|
||||
seg.nextforvert2 = Vertices[seg.v2].segs2;
|
||||
|
||||
segnum = (int)Segs.Push(seg);
|
||||
Vertices[seg.v1].segs = segnum;
|
||||
Vertices[seg.v2].segs2 = segnum;
|
||||
}
|
||||
}
|
||||
|
||||
void FNodeBuilder::AddPolySegs(FPolySeg *segs, int numsegs)
|
||||
{
|
||||
assert(numsegs > 0);
|
||||
|
||||
for (int i = 0; i < numsegs; ++i)
|
||||
{
|
||||
FPrivSeg seg;
|
||||
FPrivVert vert;
|
||||
int segnum;
|
||||
|
||||
seg.next = DWORD_MAX;
|
||||
seg.loopnum = 0;
|
||||
seg.partner = DWORD_MAX;
|
||||
seg.hashnext = NULL;
|
||||
seg.planefront = false;
|
||||
seg.planenum = DWORD_MAX;
|
||||
seg.storedseg = DWORD_MAX;
|
||||
|
||||
side_t *side = segs[i].wall;
|
||||
assert(side != NULL);
|
||||
|
||||
seg.frontsector = side->sector;
|
||||
seg.backsector = side->linedef->frontsector == side->sector ? side->linedef->backsector : side->linedef->frontsector;
|
||||
vert.x = segs[i].v1.x;
|
||||
vert.y = segs[i].v1.y;
|
||||
seg.v1 = VertexMap->SelectVertexExact(vert);
|
||||
vert.x = segs[i].v2.x;
|
||||
vert.y = segs[i].v2.y;
|
||||
seg.v2 = VertexMap->SelectVertexExact(vert);
|
||||
seg.linedef = int(side->linedef - Level.Lines);
|
||||
seg.sidedef = int(side - Level.Sides);
|
||||
seg.nextforvert = Vertices[seg.v1].segs;
|
||||
seg.nextforvert2 = Vertices[seg.v2].segs2;
|
||||
|
||||
segnum = (int)Segs.Push(seg);
|
||||
Vertices[seg.v1].segs = segnum;
|
||||
Vertices[seg.v2].segs2 = segnum;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Group colinear segs together so that only one seg per line needs to be checked
|
||||
// by SelectSplitter().
|
||||
|
||||
|
@ -269,6 +350,27 @@ void FNodeBuilder::GroupSegPlanes ()
|
|||
PlaneChecked.Reserve ((planenum + 7) / 8);
|
||||
}
|
||||
|
||||
// Just create one plane per seg. Should be good enough for mini BSPs.
|
||||
void FNodeBuilder::GroupSegPlanesSimple()
|
||||
{
|
||||
Planes.Resize(Segs.Size());
|
||||
for (int i = 0; i < (int)Segs.Size(); ++i)
|
||||
{
|
||||
FPrivSeg *seg = &Segs[i];
|
||||
FSimpleLine *pline = &Planes[i];
|
||||
seg->next = i+1;
|
||||
seg->hashnext = NULL;
|
||||
seg->planenum = i;
|
||||
seg->planefront = true;
|
||||
pline->x = Vertices[seg->v1].x;
|
||||
pline->y = Vertices[seg->v1].y;
|
||||
pline->dx = Vertices[seg->v2].x - Vertices[seg->v1].x;
|
||||
pline->dy = Vertices[seg->v2].y - Vertices[seg->v1].y;
|
||||
}
|
||||
Segs.Last().next = DWORD_MAX;
|
||||
PlaneChecked.Reserve((Segs.Size() + 7) / 8);
|
||||
}
|
||||
|
||||
// Find "loops" of segs surrounding polyobject's origin. Note that a polyobject's origin
|
||||
// is not solely defined by the polyobject's anchor, but also by the polyobject itself.
|
||||
// For the split avoidance to work properly, you must have a convex, complete loop of
|
||||
|
@ -507,6 +609,10 @@ void FNodeBuilder::FLevel::FindMapBounds ()
|
|||
MaxY = maxy;
|
||||
}
|
||||
|
||||
FNodeBuilder::IVertexMap::~IVertexMap()
|
||||
{
|
||||
}
|
||||
|
||||
FNodeBuilder::FVertexMap::FVertexMap (FNodeBuilder &builder,
|
||||
fixed_t minx, fixed_t miny, fixed_t maxx, fixed_t maxy)
|
||||
: MyBuilder(builder)
|
||||
|
@ -606,3 +712,52 @@ int FNodeBuilder::FVertexMap::InsertVertex (FNodeBuilder::FPrivVert &vert)
|
|||
|
||||
return vertnum;
|
||||
}
|
||||
|
||||
FNodeBuilder::FVertexMapSimple::FVertexMapSimple(FNodeBuilder &builder)
|
||||
: MyBuilder(builder)
|
||||
{
|
||||
}
|
||||
|
||||
int FNodeBuilder::FVertexMapSimple::SelectVertexExact(FNodeBuilder::FPrivVert &vert)
|
||||
{
|
||||
FPrivVert *verts = &MyBuilder.Vertices[0];
|
||||
unsigned int stop = MyBuilder.Vertices.Size();
|
||||
|
||||
for (unsigned int i = 0; i < stop; ++i)
|
||||
{
|
||||
if (verts[i].x == vert.x && verts[i].y == vert.y)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
// Not present: add it!
|
||||
return InsertVertex(vert);
|
||||
}
|
||||
|
||||
int FNodeBuilder::FVertexMapSimple::SelectVertexClose(FNodeBuilder::FPrivVert &vert)
|
||||
{
|
||||
FPrivVert *verts = &MyBuilder.Vertices[0];
|
||||
unsigned int stop = MyBuilder.Vertices.Size();
|
||||
|
||||
for (unsigned int i = 0; i < stop; ++i)
|
||||
{
|
||||
#if VERTEX_EPSILON <= 1
|
||||
if (verts[i].x == vert.x && verts[i].y == y)
|
||||
#else
|
||||
if (abs(verts[i].x - vert.x) < VERTEX_EPSILON &&
|
||||
abs(verts[i].y - vert.y) < VERTEX_EPSILON)
|
||||
#endif
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
// Not present: add it!
|
||||
return InsertVertex (vert);
|
||||
}
|
||||
|
||||
int FNodeBuilder::FVertexMapSimple::InsertVertex (FNodeBuilder::FPrivVert &vert)
|
||||
{
|
||||
vert.segs = DWORD_MAX;
|
||||
vert.segs2 = DWORD_MAX;
|
||||
return (int)MyBuilder.Vertices.Push (vert);
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue