mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-23 12:32:34 +00:00
Merge branch 'master' of github.com:rheit/zdoom
This commit is contained in:
commit
549ba3d817
181 changed files with 21477 additions and 7254 deletions
|
@ -3,6 +3,7 @@ cmake_minimum_required( VERSION 2.4 )
|
|||
make_release_only()
|
||||
|
||||
include( CheckFunctionExists )
|
||||
include( CheckCXXCompilerFlag )
|
||||
|
||||
# DUMB is much slower in a Debug build than a Release build, so we force a Release
|
||||
# build here, since we're not maintaining DUMB, only using it.
|
||||
|
@ -104,5 +105,9 @@ add_library( dumb
|
|||
target_link_libraries( dumb )
|
||||
|
||||
if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
||||
set_source_files_properties( src/it/filter.cpp PROPERTIES COMPILE_FLAGS -msse )
|
||||
CHECK_CXX_COMPILER_FLAG( -msse DUMB_CAN_USE_SSE )
|
||||
|
||||
if( DUMB_CAN_USE_SSE )
|
||||
set_source_files_properties( src/it/filter.cpp PROPERTIES COMPILE_FLAGS -msse )
|
||||
endif( DUMB_CAN_USE_SSE )
|
||||
endif( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
||||
|
|
|
@ -70,9 +70,9 @@ static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
|
|||
*c = c2;
|
||||
*d = d2;
|
||||
|
||||
#elif __PIC__
|
||||
#elif defined __PIC__ && defined __i386__
|
||||
|
||||
/* GCC or Clang WITH position-independent code generation */
|
||||
/* GCC or Clang WITH position-independent code generation, i386 only */
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"xchgl %%ebx, %1\n"
|
||||
|
@ -86,7 +86,7 @@ static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
|
|||
|
||||
#else
|
||||
|
||||
/* GCC or Clang WITHOUT position-independent code generation */
|
||||
/* GCC or Clang WITHOUT position-independent code generation, or x86_64 */
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"cpuid"
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
cmake_minimum_required( VERSION 2.4 )
|
||||
add_library( output_sdl MODULE output_sdl.c )
|
||||
include_directories( ${FMOD_INCLUDE_DIR} ${SDL_INCLUDE_DIR} )
|
||||
target_link_libraries( output_sdl SDL )
|
||||
|
||||
FILE( WRITE ${CMAKE_CURRENT_BINARY_DIR}/link-make "if [ ! -e ${ZDOOM_OUTPUT_DIR}/liboutput_sdl.so ]; then ln -sf output_sdl/liboutput_sdl.so ${ZDOOM_OUTPUT_DIR}/liboutput_sdl.so; fi" )
|
||||
add_custom_command( TARGET output_sdl POST_BUILD
|
||||
|
|
|
@ -92,30 +92,33 @@ Note: All <bool> fields default to false unless mentioned otherwise.
|
|||
|
||||
linedef
|
||||
{
|
||||
alpha = <float>; // Translucency of this line, default is 1.0
|
||||
renderstyle = <string>; // Render style, can be "translucent" or "add",
|
||||
// default is "translucent".
|
||||
playeruseback = <bool>; // New SPAC flag, true = player can use from back side.
|
||||
anycross = <bool>; // New SPAC flag, true = any non-projectile
|
||||
// crossing will trigger this line
|
||||
monsteractivate = <bool>; // Monsters can trigger this line.
|
||||
// For compatibility only because this flag's
|
||||
// semantics can not be fully reproduced with
|
||||
// explicit trigger flags.
|
||||
blockplayers = <bool>; // Line blocks players' movement.
|
||||
blockeverything = <bool>; // Line blocks everything.
|
||||
firstsideonly = <bool>; // Line can only be triggered from the front side.
|
||||
zoneboundary = <bool>; // Line is a boundary for sound reverb zones.
|
||||
clipmidtex = <bool>; // Line's mid textures are clipped to floor and ceiling.
|
||||
wrapmidtex = <bool>; // Line's mid textures are wrapped.
|
||||
midtex3d = <bool>; // Actors can walk on mid texture.
|
||||
checkswitchrange = <bool>;// Switches can only be activated when vertically reachable.
|
||||
blockprojectiles = <bool>;// Line blocks all projectiles
|
||||
blockuse = <bool>; // Line blocks all use actions
|
||||
blocksight = <bool>; // Line blocks monster line of sight
|
||||
blockhitscan = <bool>; // Line blocks hitscan attacks
|
||||
locknumber = <int>; // Line special is locked
|
||||
arg0str = <string>; // Alternate string-based version of arg0
|
||||
alpha = <float>; // Translucency of this line, default is 1.0
|
||||
renderstyle = <string>; // Render style, can be "translucent" or "add",
|
||||
// default is "translucent".
|
||||
playeruseback = <bool> ; // New SPAC flag, true = player can use from back side.
|
||||
anycross = <bool>; // New SPAC flag, true = any non-projectile
|
||||
// crossing will trigger this line
|
||||
monsteractivate = <bool>; // Monsters can trigger this line.
|
||||
// For compatibility only because this flag's
|
||||
// semantics can not be fully reproduced with
|
||||
// explicit trigger flags.
|
||||
blockplayers = <bool>; // Line blocks players' movement.
|
||||
blockeverything = <bool>; // Line blocks everything.
|
||||
firstsideonly = <bool>; // Line can only be triggered from the front side.
|
||||
zoneboundary = <bool>; // Line is a boundary for sound reverb zones.
|
||||
clipmidtex = <bool>; // Line's mid textures are clipped to floor and ceiling.
|
||||
wrapmidtex = <bool>; // Line's mid textures are wrapped.
|
||||
midtex3d = <bool>; // Actors can walk on mid texture.
|
||||
midtex3dimpassible = <bool>;// Used in conjuction with midtex3d - causes the mid
|
||||
// texture to behave like an impassible line (projectiles
|
||||
// pass through it).
|
||||
checkswitchrange = <bool>; // Switches can only be activated when vertically reachable.
|
||||
blockprojectiles = <bool>; // Line blocks all projectiles
|
||||
blockuse = <bool>; // Line blocks all use actions
|
||||
blocksight = <bool>; // Line blocks monster line of sight
|
||||
blockhitscan = <bool>; // Line blocks hitscan attacks
|
||||
locknumber = <int>; // Line special is locked
|
||||
arg0str = <string>; // Alternate string-based version of arg0
|
||||
|
||||
transparent = <bool>; // true = line is a Strife transparent line (alpha 0.25)
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ endif( COMMAND cmake_policy )
|
|||
include( CheckCXXSourceCompiles )
|
||||
include( CheckFunctionExists )
|
||||
include( CheckCXXCompilerFlag )
|
||||
include( CheckLibraryExists )
|
||||
include( FindPkgConfig )
|
||||
|
||||
if( NOT APPLE )
|
||||
|
@ -26,6 +27,10 @@ endif( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
|||
|
||||
option( DYN_FLUIDSYNTH "Dynamically load fluidsynth" ON )
|
||||
|
||||
if( APPLE )
|
||||
option( OSX_COCOA_BACKEND "Use native Cocoa backend instead of SDL" ON )
|
||||
endif( APPLE )
|
||||
|
||||
if( CMAKE_SIZEOF_VOID_P MATCHES "8" )
|
||||
set( X64 64 )
|
||||
endif( CMAKE_SIZEOF_VOID_P MATCHES "8" )
|
||||
|
@ -211,7 +216,9 @@ else( WIN32 )
|
|||
if( NOT SDL_FOUND )
|
||||
message( SEND_ERROR "SDL is required for building." )
|
||||
endif( NOT SDL_FOUND )
|
||||
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${SDL_LIBRARY}" )
|
||||
if( NOT APPLE OR NOT OSX_COCOA_BACKEND )
|
||||
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${SDL_LIBRARY}" )
|
||||
endif( NOT APPLE OR NOT OSX_COCOA_BACKEND )
|
||||
include_directories( "${SDL_INCLUDE_DIR}" )
|
||||
|
||||
find_path( FPU_CONTROL_DIR fpu_control.h )
|
||||
|
@ -356,19 +363,19 @@ if( NOT NO_ASM )
|
|||
set( ASM_FLAGS -f win32 -DWIN32 -i${CMAKE_CURRENT_SOURCE_DIR}/ )
|
||||
endif( X64 )
|
||||
endif( UNIX )
|
||||
if( WIN32 )
|
||||
if( WIN32 AND NOT X64 )
|
||||
set( FIXRTEXT fixrtext )
|
||||
else( WIN32 )
|
||||
else( WIN32 AND NOT X64 )
|
||||
set( FIXRTEXT "" )
|
||||
endif( WIN32 )
|
||||
endif( WIN32 AND NOT X64 )
|
||||
message( STATUS "Selected assembler: ${ASSEMBLER}" )
|
||||
MACRO( ADD_ASM_FILE indir infile )
|
||||
set( ASM_OUTPUT_${infile} "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/zdoom.dir/${indir}/${infile}${ASM_OUTPUT_EXTENSION}" )
|
||||
if( WIN32 )
|
||||
if( WIN32 AND NOT X64 )
|
||||
set( FIXRTEXT_${infile} COMMAND ${FIXRTEXT} "${ASM_OUTPUT_${infile}}" )
|
||||
else( WIN32 )
|
||||
else( WIN32 AND NOT X64 )
|
||||
set( FIXRTEXT_${infile} COMMAND "" )
|
||||
endif( WIN32 )
|
||||
endif( WIN32 AND NOT X64 )
|
||||
add_custom_command( OUTPUT ${ASM_OUTPUT_${infile}}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/zdoom.dir/${indir}
|
||||
COMMAND ${ASSEMBLER} ${ASM_FLAGS} -o"${ASM_OUTPUT_${infile}}" "${CMAKE_CURRENT_SOURCE_DIR}/${indir}/${infile}${ASM_SOURCE_EXTENSION}"
|
||||
|
@ -427,9 +434,10 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
|||
endif( PROFILE )
|
||||
|
||||
set( REL_CXX_FLAGS "-fno-rtti" )
|
||||
if( NOT PROFILE )
|
||||
if( NOT PROFILE AND NOT APPLE )
|
||||
# On OS X frame pointers are required for exception handling, at least with Clang
|
||||
set( REL_CXX_FLAGS "${REL_CXX_FLAGS} -fomit-frame-pointer" )
|
||||
endif( NOT PROFILE )
|
||||
endif( NOT PROFILE AND NOT APPLE )
|
||||
set( CMAKE_CXX_FLAGS_RELEASE "${REL_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELEASE}" )
|
||||
set( CMAKE_CXX_FLAGS_MINSIZEREL "${REL_CXX_FLAGS} ${CMAKE_CXX_FLAGS_MINSIZEREL}" )
|
||||
set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${REL_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}" )
|
||||
|
@ -555,21 +563,53 @@ set( PLAT_WIN32_SOURCES
|
|||
win32/i_system.cpp
|
||||
win32/st_start.cpp
|
||||
win32/win32video.cpp )
|
||||
set( PLAT_SDL_SOURCES
|
||||
set( PLAT_SDL_SYSTEM_SOURCES
|
||||
sdl/crashcatcher.c
|
||||
sdl/hardware.cpp
|
||||
sdl/i_cd.cpp
|
||||
sdl/i_input.cpp
|
||||
sdl/i_joystick.cpp
|
||||
sdl/i_main.cpp
|
||||
sdl/i_movie.cpp
|
||||
sdl/i_steam.cpp
|
||||
sdl/i_system.cpp
|
||||
sdl/sdlvideo.cpp
|
||||
sdl/st_start.cpp )
|
||||
set( PLAT_SDL_SPECIAL_SOURCES
|
||||
sdl/i_gui.cpp
|
||||
sdl/i_input.cpp
|
||||
sdl/i_joystick.cpp
|
||||
sdl/i_timer.cpp )
|
||||
set( PLAT_MAC_SOURCES
|
||||
sdl/SDLMain.m
|
||||
sdl/iwadpicker_cocoa.mm
|
||||
sdl/i_system_cocoa.mm )
|
||||
set( PLAT_COCOA_SOURCES
|
||||
cocoa/HID_Config_Utilities.c
|
||||
cocoa/HID_Error_Handler.c
|
||||
cocoa/HID_Name_Lookup.c
|
||||
cocoa/HID_Queue_Utilities.c
|
||||
cocoa/HID_Utilities.c
|
||||
cocoa/IOHIDDevice_.c
|
||||
cocoa/IOHIDElement_.c
|
||||
cocoa/ImmrHIDUtilAddOn.c
|
||||
cocoa/i_backend_cocoa.mm
|
||||
cocoa/i_joystick.cpp
|
||||
cocoa/i_timer.cpp
|
||||
cocoa/zdoom.icns )
|
||||
|
||||
if( APPLE )
|
||||
set( PLAT_SDL_SOURCES ${PLAT_SDL_SYSTEM_SOURCES} "${FMOD_LIBRARY}" )
|
||||
|
||||
if( OSX_COCOA_BACKEND )
|
||||
set( PLAT_MAC_SOURCES ${PLAT_MAC_SOURCES} ${PLAT_COCOA_SOURCES} )
|
||||
else( OSX_COCOA_BACKEND )
|
||||
set( PLAT_MAC_SOURCES ${PLAT_MAC_SOURCES} ${PLAT_SDL_SPECIAL_SOURCES} sdl/SDLMain.m )
|
||||
endif( OSX_COCOA_BACKEND )
|
||||
|
||||
set_source_files_properties( cocoa/zdoom.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources )
|
||||
set_source_files_properties( "${FMOD_LIBRARY}" PROPERTIES MACOSX_PACKAGE_LOCATION Frameworks )
|
||||
else( APPLE )
|
||||
set( PLAT_SDL_SOURCES ${PLAT_SDL_SYSTEM_SOURCES} ${PLAT_SDL_SPECIAL_SOURCES} )
|
||||
endif( APPLE )
|
||||
|
||||
if( WIN32 )
|
||||
set( SYSTEM_SOURCES_DIR win32 )
|
||||
set( SYSTEM_SOURCES ${PLAT_WIN32_SOURCES} )
|
||||
|
@ -771,7 +811,7 @@ set( NOT_COMPILED_SOURCE_FILES
|
|||
asm_x86_64/tmap3.s
|
||||
)
|
||||
|
||||
add_executable( zdoom WIN32
|
||||
add_executable( zdoom WIN32 MACOSX_BUNDLE
|
||||
${HEADER_FILES}
|
||||
${NOT_COMPILED_SOURCE_FILES}
|
||||
__autostart.cpp
|
||||
|
@ -991,6 +1031,7 @@ add_executable( zdoom WIN32
|
|||
oplsynth/opl_mus_player.cpp
|
||||
oplsynth/dosbox/opl.cpp
|
||||
oplsynth/OPL3.cpp
|
||||
oplsynth/nukedopl3.cpp
|
||||
resourcefiles/ancientzip.cpp
|
||||
resourcefiles/file_7z.cpp
|
||||
resourcefiles/file_grp.cpp
|
||||
|
@ -1163,6 +1204,25 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
|||
endif( SSE_MATTERS )
|
||||
endif( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
||||
|
||||
if( APPLE )
|
||||
set_target_properties(zdoom PROPERTIES
|
||||
LINK_FLAGS "-framework Carbon -framework Cocoa -framework IOKit -framework OpenGL"
|
||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/cocoa/zdoom-info.plist" )
|
||||
|
||||
# Fix fmod link so that it can be found in the app bundle.
|
||||
find_program( OTOOL otool HINTS "/usr/bin" "${OSX_DEVELOPER_ROOT}/usr/bin" )
|
||||
find_program( INSTALL_NAME_TOOL install_name_tool HINTS "/usr/bin" "${OSX_DEVELOPER_ROOT}/usr/bin" )
|
||||
execute_process( COMMAND "${OTOOL}" -L "${FMOD_LIBRARY}"
|
||||
COMMAND grep "libfmodex.dylib (compat"
|
||||
COMMAND head -n1
|
||||
COMMAND awk "{print $1}"
|
||||
OUTPUT_VARIABLE FMOD_LINK
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE )
|
||||
add_custom_command( TARGET zdoom POST_BUILD
|
||||
COMMAND "${INSTALL_NAME_TOOL}" -change "${FMOD_LINK}" @executable_path/../Frameworks/libfmodex.dylib "$<TARGET_FILE:zdoom>"
|
||||
COMMENT "Relinking FMOD Ex" )
|
||||
endif( APPLE )
|
||||
|
||||
source_group("Assembly Files\\ia32" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/asm_ia32/.+")
|
||||
source_group("Assembly Files\\x86_64" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/asm_x86_64/.+")
|
||||
source_group("Audio Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/.+")
|
||||
|
@ -1170,6 +1230,7 @@ source_group("Audio Files\\OPL Synth" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURC
|
|||
source_group("Audio Files\\OPL Synth\\DOSBox" FILES oplsynth/dosbox/opl.cpp oplsynth/dosbox/opl.h)
|
||||
source_group("Audio Files\\Timidity\\Headers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/timidity/.+\\.h$")
|
||||
source_group("Audio Files\\Timidity\\Source" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/timidity/.+\\.cpp$")
|
||||
source_group("Cocoa Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/cocoa/.+")
|
||||
source_group("Decorate++" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/thingdef/.+")
|
||||
source_group("FraggleScript" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/fragglescript/.+")
|
||||
source_group("Games\\Doom Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_doom/.+")
|
||||
|
|
|
@ -102,6 +102,7 @@ DEFINE_SPECIAL(Scroll_Texture_Left, 100, -1, -1, 2)
|
|||
DEFINE_SPECIAL(Scroll_Texture_Right, 101, -1, -1, 2)
|
||||
DEFINE_SPECIAL(Scroll_Texture_Up, 102, -1, -1, 2)
|
||||
DEFINE_SPECIAL(Scroll_Texture_Down, 103, -1, -1, 2)
|
||||
DEFINE_SPECIAL(Ceiling_CrushAndRaiseSilentDist, 104, 3, 5, 5)
|
||||
|
||||
DEFINE_SPECIAL(Light_ForceLightning, 109, 1, 1, 1)
|
||||
DEFINE_SPECIAL(Light_RaiseByValue, 110, 2, 2, 2)
|
||||
|
|
26
src/actor.h
26
src/actor.h
|
@ -341,6 +341,20 @@ enum
|
|||
MF7_ALWAYSTELEFRAG = 0x00000004, // will unconditionally be telefragged when in the way. Overrides all other settings.
|
||||
MF7_HANDLENODELAY = 0x00000008, // respect NoDelay state flag
|
||||
MF7_WEAPONSPAWN = 0x00000010, // subject to DF_NO_COOP_WEAPON_SPAWN dmflag
|
||||
MF7_HARMFRIENDS = 0x00000020, // is allowed to harm friendly monsters.
|
||||
MF7_BUDDHA = 0x00000040, // Behaves just like the buddha cheat.
|
||||
MF7_FOILBUDDHA = 0x00000080, // Similar to FOILINVUL, foils buddha mode.
|
||||
MF7_DONTTHRUST = 0x00000100, // Thrusting functions do not take, and do not give thrust (damage) to actors with this flag.
|
||||
MF7_ALLOWPAIN = 0x00000200, // Invulnerable or immune (via damagefactors) actors can still react to taking damage even if they don't.
|
||||
MF7_CAUSEPAIN = 0x00000400, // Damage sources with this flag can cause similar effects like ALLOWPAIN.
|
||||
MF7_THRUREFLECT = 0x00000800, // Actors who are reflective cause the missiles to not slow down or change angles.
|
||||
MF7_MIRRORREFLECT = 0x00001000, // Actor is turned directly 180 degrees around when reflected.
|
||||
MF7_AIMREFLECT = 0x00002000, // Actor is directly reflected straight back at the one who fired the projectile.
|
||||
MF7_HITTARGET = 0x00004000, // The actor the projectile dies on is set to target, provided it's targetable anyway.
|
||||
MF7_HITMASTER = 0x00008000, // Same as HITTARGET, except it's master instead of target.
|
||||
MF7_HITTRACER = 0x00010000, // Same as HITTARGET, but for tracer.
|
||||
|
||||
|
||||
|
||||
// --- mobj.renderflags ---
|
||||
|
||||
|
@ -713,6 +727,9 @@ public:
|
|||
// Transforms the actor into a finely-ground paste
|
||||
virtual bool Grind(bool items);
|
||||
|
||||
// Get this actor's team
|
||||
int GetTeam();
|
||||
|
||||
// Is the other actor on my team?
|
||||
bool IsTeammate (AActor *other);
|
||||
|
||||
|
@ -850,13 +867,14 @@ public:
|
|||
DWORD flags4; // [RH] Even more flags!
|
||||
DWORD flags5; // OMG! We need another one.
|
||||
DWORD flags6; // Shit! Where did all the flags go?
|
||||
DWORD flags7; //
|
||||
DWORD flags7; // WHO WANTS TO BET ON 8!?
|
||||
|
||||
// [BB] If 0, everybody can see the actor, if > 0, only members of team (VisibleToTeam-1) can see it.
|
||||
DWORD VisibleToTeam;
|
||||
|
||||
int special1; // Special info
|
||||
int special2; // Special info
|
||||
int weaponspecial; // Special info for weapons.
|
||||
int health;
|
||||
BYTE movedir; // 0-7
|
||||
SBYTE visdir;
|
||||
|
@ -936,9 +954,6 @@ public:
|
|||
TObjPtr<AInventory> Inventory; // [RH] This actor's inventory
|
||||
DWORD InventoryID; // A unique ID to keep track of inventory items
|
||||
|
||||
//Added by MC:
|
||||
SDWORD id; // Player ID (for items, # in list.)
|
||||
|
||||
BYTE smokecounter;
|
||||
BYTE FloatBobPhase;
|
||||
BYTE FriendPlayer; // [RH] Player # + 1 this friendly monster works for (so 0 is no player, 1 is player 0, etc)
|
||||
|
@ -964,9 +979,12 @@ public:
|
|||
FNameNoInit DamageType;
|
||||
FNameNoInit DamageTypeReceived;
|
||||
fixed_t DamageFactor;
|
||||
fixed_t DamageMultiply;
|
||||
|
||||
FNameNoInit PainType;
|
||||
FNameNoInit DeathType;
|
||||
const PClass *TeleFogSourceType;
|
||||
const PClass *TeleFogDestType;
|
||||
|
||||
FState *SpawnState;
|
||||
FState *SeeState;
|
||||
|
|
|
@ -56,6 +56,13 @@ AActor *COPY_AAPTR(AActor *origin, int selector)
|
|||
case AAPTR_TRACER: return origin->tracer;
|
||||
case AAPTR_FRIENDPLAYER:
|
||||
return origin->FriendPlayer ? AAPTR_RESOLVE_PLAYERNUM(origin->FriendPlayer - 1) : NULL;
|
||||
|
||||
case AAPTR_GET_LINETARGET:
|
||||
{
|
||||
AActor *gettarget = NULL;
|
||||
P_BulletSlope(origin, &gettarget);
|
||||
return gettarget;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,12 +36,13 @@ enum AAPTR
|
|||
AAPTR_PLAYER8 = 0x2000,
|
||||
|
||||
AAPTR_FRIENDPLAYER = 0x4000,
|
||||
AAPTR_GET_LINETARGET = 0x8000,
|
||||
|
||||
AAPTR_PLAYER_SELECTORS =
|
||||
AAPTR_PLAYER_GETTARGET|AAPTR_PLAYER_GETCONVERSATION,
|
||||
|
||||
AAPTR_GENERAL_SELECTORS =
|
||||
AAPTR_TARGET|AAPTR_MASTER|AAPTR_TRACER|AAPTR_FRIENDPLAYER,
|
||||
AAPTR_TARGET|AAPTR_MASTER|AAPTR_TRACER|AAPTR_FRIENDPLAYER|AAPTR_GET_LINETARGET,
|
||||
|
||||
AAPTR_STATIC_SELECTORS =
|
||||
AAPTR_PLAYER1|AAPTR_PLAYER2|AAPTR_PLAYER3|AAPTR_PLAYER4|
|
||||
|
|
|
@ -908,8 +908,8 @@ void AM_StaticInit()
|
|||
|
||||
if (gameinfo.mMapArrow.IsNotEmpty()) AM_ParseArrow(MapArrow, gameinfo.mMapArrow);
|
||||
if (gameinfo.mCheatMapArrow.IsNotEmpty()) AM_ParseArrow(CheatMapArrow, gameinfo.mCheatMapArrow);
|
||||
AM_ParseArrow(CheatKey, "maparrows/key.txt");
|
||||
AM_ParseArrow(EasyKey, "maparrows/ravenkey.txt");
|
||||
AM_ParseArrow(CheatKey, gameinfo.mCheatKey);
|
||||
AM_ParseArrow(EasyKey, gameinfo.mEasyKey);
|
||||
if (MapArrow.Size() == 0) I_FatalError("No automap arrow defined");
|
||||
|
||||
char namebuf[9];
|
||||
|
|
117
src/b_bot.cpp
117
src/b_bot.cpp
|
@ -1,7 +1,7 @@
|
|||
// Cajun bot console commands.
|
||||
// Cajun bot
|
||||
//
|
||||
// [RH] Moved out of d_netcmd.c (in Cajun source), because they don't really
|
||||
// belong there.
|
||||
// [RH] Moved console commands out of d_netcmd.c (in Cajun source), because
|
||||
// they don't really belong there.
|
||||
|
||||
#include "c_cvars.h"
|
||||
#include "c_dispatch.h"
|
||||
|
@ -14,6 +14,102 @@
|
|||
#include "d_net.h"
|
||||
#include "farchive.h"
|
||||
|
||||
IMPLEMENT_POINTY_CLASS(DBot)
|
||||
DECLARE_POINTER(dest)
|
||||
DECLARE_POINTER(prev)
|
||||
DECLARE_POINTER(enemy)
|
||||
DECLARE_POINTER(missile)
|
||||
DECLARE_POINTER(mate)
|
||||
DECLARE_POINTER(last_mate)
|
||||
END_POINTERS
|
||||
|
||||
DBot::DBot ()
|
||||
: DThinker(STAT_BOT)
|
||||
{
|
||||
Clear ();
|
||||
}
|
||||
|
||||
void DBot::Clear ()
|
||||
{
|
||||
player = NULL;
|
||||
angle = 0;
|
||||
dest = NULL;
|
||||
prev = NULL;
|
||||
enemy = NULL;
|
||||
missile = NULL;
|
||||
mate = NULL;
|
||||
last_mate = NULL;
|
||||
memset(&skill, 0, sizeof(skill));
|
||||
t_active = 0;
|
||||
t_respawn = 0;
|
||||
t_strafe = 0;
|
||||
t_react = 0;
|
||||
t_fight = 0;
|
||||
t_roam = 0;
|
||||
t_rocket = 0;
|
||||
first_shot = true;
|
||||
sleft = false;
|
||||
allround = false;
|
||||
increase = false;
|
||||
oldx = 0;
|
||||
oldy = 0;
|
||||
}
|
||||
|
||||
void DBot::Serialize (FArchive &arc)
|
||||
{
|
||||
Super::Serialize (arc);
|
||||
|
||||
if (SaveVersion < 4515)
|
||||
{
|
||||
angle_t savedyaw;
|
||||
int savedpitch;
|
||||
arc << savedyaw
|
||||
<< savedpitch;
|
||||
}
|
||||
else
|
||||
{
|
||||
arc << player;
|
||||
}
|
||||
|
||||
arc << angle
|
||||
<< dest
|
||||
<< prev
|
||||
<< enemy
|
||||
<< missile
|
||||
<< mate
|
||||
<< last_mate
|
||||
<< skill
|
||||
<< t_active
|
||||
<< t_respawn
|
||||
<< t_strafe
|
||||
<< t_react
|
||||
<< t_fight
|
||||
<< t_roam
|
||||
<< t_rocket
|
||||
<< first_shot
|
||||
<< sleft
|
||||
<< allround
|
||||
<< increase
|
||||
<< oldx
|
||||
<< oldy;
|
||||
}
|
||||
|
||||
void DBot::Tick ()
|
||||
{
|
||||
Super::Tick ();
|
||||
|
||||
if (player->mo == NULL || bglobal.freeze)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BotThinkCycles.Clock();
|
||||
bglobal.m_Thinking = true;
|
||||
Think ();
|
||||
bglobal.m_Thinking = false;
|
||||
BotThinkCycles.Unclock();
|
||||
}
|
||||
|
||||
CVAR (Int, bot_next_color, 11, 0)
|
||||
CVAR (Bool, bot_observer, false, 0)
|
||||
|
||||
|
@ -55,9 +151,14 @@ void FCajunMaster::ClearPlayer (int i, bool keepTeam)
|
|||
bot = bot->next;
|
||||
if (bot)
|
||||
{
|
||||
bot->inuse = false;
|
||||
bot->inuse = BOTINUSE_No;
|
||||
bot->lastteam = keepTeam ? players[i].userinfo.GetTeam() : TEAM_NONE;
|
||||
}
|
||||
if (players[i].Bot != NULL)
|
||||
{
|
||||
players[i].Bot->Destroy ();
|
||||
players[i].Bot = NULL;
|
||||
}
|
||||
players[i].~player_t();
|
||||
::new(&players[i]) player_t;
|
||||
players[i].userinfo.Reset();
|
||||
|
@ -66,6 +167,12 @@ void FCajunMaster::ClearPlayer (int i, bool keepTeam)
|
|||
|
||||
CCMD (removebots)
|
||||
{
|
||||
if (!players[consoleplayer].settings_controller)
|
||||
{
|
||||
Printf ("Only setting controllers can remove bots\n");
|
||||
return;
|
||||
}
|
||||
|
||||
Net_WriteByte (DEM_KILLBOTS);
|
||||
}
|
||||
|
||||
|
@ -91,7 +198,7 @@ CCMD (listbots)
|
|||
|
||||
while (thebot)
|
||||
{
|
||||
Printf ("%s%s\n", thebot->name, thebot->inuse ? " (active)" : "");
|
||||
Printf ("%s%s\n", thebot->name, thebot->inuse == BOTINUSE_Yes ? " (active)" : "");
|
||||
thebot = thebot->next;
|
||||
count++;
|
||||
}
|
||||
|
|
135
src/b_bot.h
135
src/b_bot.h
|
@ -14,6 +14,7 @@
|
|||
#include "d_ticcmd.h"
|
||||
#include "r_defs.h"
|
||||
#include "a_pickups.h"
|
||||
#include "stats.h"
|
||||
|
||||
#define FORWARDWALK 0x1900
|
||||
#define FORWARDRUN 0x3200
|
||||
|
@ -60,6 +61,13 @@ struct botskill_t
|
|||
|
||||
FArchive &operator<< (FArchive &arc, botskill_t &skill);
|
||||
|
||||
enum
|
||||
{
|
||||
BOTINUSE_No,
|
||||
BOTINUSE_Waiting,
|
||||
BOTINUSE_Yes,
|
||||
};
|
||||
|
||||
//Info about all bots in the bots.cfg
|
||||
//Updated during each level start.
|
||||
//Info given to bots when they're spawned.
|
||||
|
@ -69,7 +77,7 @@ struct botinfo_t
|
|||
char *name;
|
||||
char *info;
|
||||
botskill_t skill;
|
||||
bool inuse;
|
||||
int inuse;
|
||||
int lastteam;
|
||||
};
|
||||
|
||||
|
@ -81,35 +89,29 @@ public:
|
|||
|
||||
void ClearPlayer (int playernum, bool keepTeam);
|
||||
|
||||
//(B_Game.c)
|
||||
void Main (int buf);
|
||||
//(b_game.cpp)
|
||||
void Main ();
|
||||
void Init ();
|
||||
void End();
|
||||
void CleanBotstuff (player_t *p);
|
||||
bool SpawnBot (const char *name, int color = NOCOLOR);
|
||||
void TryAddBot (BYTE **stream, int player);
|
||||
void RemoveAllBots (bool fromlist);
|
||||
bool LoadBots ();
|
||||
void ForgetBots ();
|
||||
void DoAddBot (int bnum, char *info);
|
||||
void RemoveAllBots (bool fromlist);
|
||||
|
||||
//(B_Func.c)
|
||||
bool Check_LOS (AActor *mobj1, AActor *mobj2, angle_t vangle);
|
||||
//(b_func.cpp)
|
||||
void StartTravel ();
|
||||
void FinishTravel ();
|
||||
bool IsLeader (player_t *player);
|
||||
void SetBodyAt (fixed_t x, fixed_t y, fixed_t z, int hostnum);
|
||||
fixed_t FakeFire (AActor *source, AActor *dest, ticcmd_t *cmd);
|
||||
bool SafeCheckPosition (AActor *actor, fixed_t x, fixed_t y, FCheckPosition &tm);
|
||||
|
||||
//(B_Think.c)
|
||||
void WhatToGet (AActor *actor, AActor *item);
|
||||
|
||||
//(B_move.c)
|
||||
void Roam (AActor *actor, ticcmd_t *cmd);
|
||||
bool Move (AActor *actor, ticcmd_t *cmd);
|
||||
bool TryWalk (AActor *actor, ticcmd_t *cmd);
|
||||
void NewChaseDir (AActor *actor, ticcmd_t *cmd);
|
||||
//(b_move.cpp)
|
||||
bool CleanAhead (AActor *thing, fixed_t x, fixed_t y, ticcmd_t *cmd);
|
||||
void TurnToAng (AActor *actor);
|
||||
void Pitch (AActor *actor, AActor *target);
|
||||
bool IsDangerous (sector_t *sec);
|
||||
|
||||
TArray<FString> getspawned; //Array of bots (their names) which should be spawned when starting a game.
|
||||
bool botingame[MAXPLAYERS];
|
||||
BYTE freeze:1; //Game in freeze mode.
|
||||
BYTE changefreeze:1; //Game wants to change freeze mode.
|
||||
int botnum;
|
||||
|
@ -123,20 +125,8 @@ public:
|
|||
bool m_Thinking;
|
||||
|
||||
private:
|
||||
//(B_Func.c)
|
||||
bool Reachable (AActor *actor, AActor *target);
|
||||
void Dofire (AActor *actor, ticcmd_t *cmd);
|
||||
AActor *Choose_Mate (AActor *bot);
|
||||
AActor *Find_enemy (AActor *bot);
|
||||
void SetBodyAt (fixed_t x, fixed_t y, fixed_t z, int hostnum);
|
||||
fixed_t FakeFire (AActor *source, AActor *dest, ticcmd_t *cmd);
|
||||
angle_t FireRox (AActor *bot, AActor *enemy, ticcmd_t *cmd);
|
||||
bool SafeCheckPosition (AActor *actor, fixed_t x, fixed_t y, FCheckPosition &tm);
|
||||
|
||||
//(B_Think.c)
|
||||
void Think (AActor *actor, ticcmd_t *cmd);
|
||||
void ThinkForMove (AActor *actor, ticcmd_t *cmd);
|
||||
void Set_enemy (AActor *actor);
|
||||
//(b_game.cpp)
|
||||
bool DoAddBot (BYTE *info, botskill_t skill);
|
||||
|
||||
protected:
|
||||
bool ctf;
|
||||
|
@ -145,9 +135,84 @@ protected:
|
|||
bool observer; //Consoleplayer is observer.
|
||||
};
|
||||
|
||||
class DBot : public DThinker
|
||||
{
|
||||
DECLARE_CLASS(DBot,DThinker)
|
||||
HAS_OBJECT_POINTERS
|
||||
public:
|
||||
DBot ();
|
||||
|
||||
void Clear ();
|
||||
void Serialize (FArchive &arc);
|
||||
void Tick ();
|
||||
|
||||
//(b_think.cpp)
|
||||
void WhatToGet (AActor *item);
|
||||
|
||||
//(b_func.cpp)
|
||||
bool Check_LOS (AActor *to, angle_t vangle);
|
||||
|
||||
player_t *player;
|
||||
angle_t angle; // The wanted angle that the bot try to get every tic.
|
||||
// (used to get a smooth view movement)
|
||||
TObjPtr<AActor> dest; // Move Destination.
|
||||
TObjPtr<AActor> prev; // Previous move destination.
|
||||
TObjPtr<AActor> enemy; // The dead meat.
|
||||
TObjPtr<AActor> missile; // A threatening missile that needs to be avoided.
|
||||
TObjPtr<AActor> mate; // Friend (used for grouping in teamplay or coop).
|
||||
TObjPtr<AActor> last_mate; // If bots mate disappeared (not if died) that mate is
|
||||
// pointed to by this. Allows bot to roam to it if
|
||||
// necessary.
|
||||
|
||||
//Skills
|
||||
struct botskill_t skill;
|
||||
|
||||
//Tickers
|
||||
int t_active; // Open door, lower lift stuff, door must open and
|
||||
// lift must go down before bot does anything
|
||||
// radical like try a stuckmove
|
||||
int t_respawn;
|
||||
int t_strafe;
|
||||
int t_react;
|
||||
int t_fight;
|
||||
int t_roam;
|
||||
int t_rocket;
|
||||
|
||||
//Misc booleans
|
||||
bool first_shot; // Used for reaction skill.
|
||||
bool sleft; // If false, strafe is right.
|
||||
bool allround;
|
||||
bool increase;
|
||||
|
||||
fixed_t oldx;
|
||||
fixed_t oldy;
|
||||
|
||||
private:
|
||||
//(B_think.cpp)
|
||||
void Think ();
|
||||
void ThinkForMove (ticcmd_t *cmd);
|
||||
void Set_enemy ();
|
||||
|
||||
//(B_func.cpp)
|
||||
bool Reachable (AActor *target);
|
||||
void Dofire (ticcmd_t *cmd);
|
||||
AActor *Choose_Mate ();
|
||||
AActor *Find_enemy ();
|
||||
angle_t FireRox (AActor *enemy, ticcmd_t *cmd);
|
||||
|
||||
//(b_move.cpp)
|
||||
void Roam (ticcmd_t *cmd);
|
||||
bool Move (ticcmd_t *cmd);
|
||||
bool TryWalk (ticcmd_t *cmd);
|
||||
void NewChaseDir (ticcmd_t *cmd);
|
||||
void TurnToAng ();
|
||||
void Pitch (AActor *target);
|
||||
};
|
||||
|
||||
|
||||
//Externs
|
||||
extern FCajunMaster bglobal;
|
||||
extern cycle_t BotThinkCycles, BotSupportCycles;
|
||||
|
||||
EXTERN_CVAR (Float, bot_flag_return_time)
|
||||
EXTERN_CVAR (Int, bot_next_color)
|
||||
|
@ -158,7 +223,3 @@ EXTERN_CVAR (Bool, bot_watersplash)
|
|||
EXTERN_CVAR (Bool, bot_chat)
|
||||
|
||||
#endif // __B_BOT_H__
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
255
src/b_func.cpp
255
src/b_func.cpp
|
@ -24,24 +24,23 @@
|
|||
static FRandom pr_botdofire ("BotDoFire");
|
||||
|
||||
|
||||
//Checks TRUE reachability from
|
||||
//one looker to another. First mobj (looker) is looker.
|
||||
bool FCajunMaster::Reachable (AActor *looker, AActor *rtarget)
|
||||
//Checks TRUE reachability from bot to a looker.
|
||||
bool DBot::Reachable (AActor *rtarget)
|
||||
{
|
||||
if (looker == rtarget)
|
||||
if (player->mo == rtarget)
|
||||
return false;
|
||||
|
||||
if ((rtarget->Sector->ceilingplane.ZatPoint (rtarget->x, rtarget->y) -
|
||||
rtarget->Sector->floorplane.ZatPoint (rtarget->x, rtarget->y))
|
||||
< looker->height) //Where rtarget is, looker can't be.
|
||||
< player->mo->height) //Where rtarget is, player->mo can't be.
|
||||
return false;
|
||||
|
||||
sector_t *last_s = looker->Sector;
|
||||
fixed_t last_z = last_s->floorplane.ZatPoint (looker->x, looker->y);
|
||||
fixed_t estimated_dist = P_AproxDistance (looker->x - rtarget->x, looker->y - rtarget->y);
|
||||
sector_t *last_s = player->mo->Sector;
|
||||
fixed_t last_z = last_s->floorplane.ZatPoint (player->mo->x, player->mo->y);
|
||||
fixed_t estimated_dist = P_AproxDistance (player->mo->x - rtarget->x, player->mo->y - rtarget->y);
|
||||
bool reachable = true;
|
||||
|
||||
FPathTraverse it(looker->x+looker->velx, looker->y+looker->vely, rtarget->x, rtarget->y, PT_ADDLINES|PT_ADDTHINGS);
|
||||
FPathTraverse it(player->mo->x+player->mo->velx, player->mo->y+player->mo->vely, rtarget->x, rtarget->y, PT_ADDLINES|PT_ADDTHINGS);
|
||||
intercept_t *in;
|
||||
while ((in = it.Next()))
|
||||
{
|
||||
|
@ -55,8 +54,8 @@ bool FCajunMaster::Reachable (AActor *looker, AActor *rtarget)
|
|||
frac = in->frac - FixedDiv (4*FRACUNIT, MAX_TRAVERSE_DIST);
|
||||
dist = FixedMul (frac, MAX_TRAVERSE_DIST);
|
||||
|
||||
hitx = it.Trace().x + FixedMul (looker->velx, frac);
|
||||
hity = it.Trace().y + FixedMul (looker->vely, frac);
|
||||
hitx = it.Trace().x + FixedMul (player->mo->velx, frac);
|
||||
hity = it.Trace().y + FixedMul (player->mo->vely, frac);
|
||||
|
||||
if (in->isaline)
|
||||
{
|
||||
|
@ -76,7 +75,7 @@ bool FCajunMaster::Reachable (AActor *looker, AActor *rtarget)
|
|||
if (!bglobal.IsDangerous (s) && //Any nukage/lava?
|
||||
(floorheight <= (last_z+MAXMOVEHEIGHT)
|
||||
&& ((ceilingheight == floorheight && line->special)
|
||||
|| (ceilingheight - floorheight) >= looker->height))) //Does it fit?
|
||||
|| (ceilingheight - floorheight) >= player->mo->height))) //Does it fit?
|
||||
{
|
||||
last_z = floorheight;
|
||||
last_s = s;
|
||||
|
@ -95,7 +94,7 @@ bool FCajunMaster::Reachable (AActor *looker, AActor *rtarget)
|
|||
}
|
||||
|
||||
thing = in->d.thing;
|
||||
if (thing == looker) //Can't reach self in this case.
|
||||
if (thing == player->mo) //Can't reach self in this case.
|
||||
continue;
|
||||
if (thing == rtarget && (rtarget->Sector->floorplane.ZatPoint (rtarget->x, rtarget->y) <= (last_z+MAXMOVEHEIGHT)))
|
||||
{
|
||||
|
@ -115,16 +114,16 @@ bool FCajunMaster::Reachable (AActor *looker, AActor *rtarget)
|
|||
//if these conditions are true, the function returns true.
|
||||
//GOOD TO KNOW is that the player's view angle
|
||||
//in doom is 90 degrees infront.
|
||||
bool FCajunMaster::Check_LOS (AActor *from, AActor *to, angle_t vangle)
|
||||
bool DBot::Check_LOS (AActor *to, angle_t vangle)
|
||||
{
|
||||
if (!P_CheckSight (from, to, SF_SEEPASTBLOCKEVERYTHING))
|
||||
if (!P_CheckSight (player->mo, to, SF_SEEPASTBLOCKEVERYTHING))
|
||||
return false; // out of sight
|
||||
if (vangle == ANGLE_MAX)
|
||||
return true;
|
||||
if (vangle == 0)
|
||||
return false; //Looker seems to be blind.
|
||||
|
||||
return (angle_t)abs (R_PointToAngle2 (from->x, from->y, to->x, to->y) - from->angle) <= vangle/2;
|
||||
return (angle_t)abs (R_PointToAngle2 (player->mo->x, player->mo->y, to->x, to->y) - player->mo->angle) <= vangle/2;
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
@ -132,7 +131,7 @@ bool FCajunMaster::Check_LOS (AActor *from, AActor *to, angle_t vangle)
|
|||
//-------------------------------------
|
||||
//The bot will check if it's time to fire
|
||||
//and do so if that is the case.
|
||||
void FCajunMaster::Dofire (AActor *actor, ticcmd_t *cmd)
|
||||
void DBot::Dofire (ticcmd_t *cmd)
|
||||
{
|
||||
bool no_fire; //used to prevent bot from pumping rockets into nearby walls.
|
||||
int aiming_penalty=0; //For shooting at shading target, if screen is red, MAKEME: When screen red.
|
||||
|
@ -140,50 +139,48 @@ void FCajunMaster::Dofire (AActor *actor, ticcmd_t *cmd)
|
|||
fixed_t dist;
|
||||
angle_t an;
|
||||
int m;
|
||||
static bool inc[MAXPLAYERS];
|
||||
AActor *enemy = actor->player->enemy;
|
||||
|
||||
if (!enemy || !(enemy->flags & MF_SHOOTABLE) || enemy->health <= 0)
|
||||
return;
|
||||
|
||||
if (actor->player->ReadyWeapon == NULL)
|
||||
if (player->ReadyWeapon == NULL)
|
||||
return;
|
||||
|
||||
if (actor->player->damagecount > actor->player->skill.isp)
|
||||
if (player->damagecount > skill.isp)
|
||||
{
|
||||
actor->player->first_shot = true;
|
||||
first_shot = true;
|
||||
return;
|
||||
}
|
||||
|
||||
//Reaction skill thing.
|
||||
if (actor->player->first_shot &&
|
||||
!(actor->player->ReadyWeapon->WeaponFlags & WIF_BOT_REACTION_SKILL_THING))
|
||||
if (first_shot &&
|
||||
!(player->ReadyWeapon->WeaponFlags & WIF_BOT_REACTION_SKILL_THING))
|
||||
{
|
||||
actor->player->t_react = (100-actor->player->skill.reaction+1)/((pr_botdofire()%3)+3);
|
||||
t_react = (100-skill.reaction+1)/((pr_botdofire()%3)+3);
|
||||
}
|
||||
actor->player->first_shot = false;
|
||||
if (actor->player->t_react)
|
||||
first_shot = false;
|
||||
if (t_react)
|
||||
return;
|
||||
|
||||
//MAKEME: Decrease the rocket suicides even more.
|
||||
|
||||
no_fire = true;
|
||||
//actor->player->angle = R_PointToAngle2(actor->x, actor->y, actor->player->enemy->x, actor->player->enemy->y);
|
||||
//angle = R_PointToAngle2(player->mo->x, player->mo->y, player->enemy->x, player->enemy->y);
|
||||
//Distance to enemy.
|
||||
dist = P_AproxDistance ((actor->x + actor->velx) - (enemy->x + enemy->velx),
|
||||
(actor->y + actor->vely) - (enemy->y + enemy->vely));
|
||||
dist = P_AproxDistance ((player->mo->x + player->mo->velx) - (enemy->x + enemy->velx),
|
||||
(player->mo->y + player->mo->vely) - (enemy->y + enemy->vely));
|
||||
|
||||
//FIRE EACH TYPE OF WEAPON DIFFERENT: Here should all the different weapons go.
|
||||
if (actor->player->ReadyWeapon->WeaponFlags & WIF_MELEEWEAPON)
|
||||
if (player->ReadyWeapon->WeaponFlags & WIF_MELEEWEAPON)
|
||||
{
|
||||
if ((actor->player->ReadyWeapon->ProjectileType != NULL))
|
||||
if ((player->ReadyWeapon->ProjectileType != NULL))
|
||||
{
|
||||
if (actor->player->ReadyWeapon->CheckAmmo (AWeapon::PrimaryFire, false, true))
|
||||
if (player->ReadyWeapon->CheckAmmo (AWeapon::PrimaryFire, false, true))
|
||||
{
|
||||
// This weapon can fire a projectile and has enough ammo to do so
|
||||
goto shootmissile;
|
||||
}
|
||||
else if (!(actor->player->ReadyWeapon->WeaponFlags & WIF_AMMO_OPTIONAL))
|
||||
else if (!(player->ReadyWeapon->WeaponFlags & WIF_AMMO_OPTIONAL))
|
||||
{
|
||||
// Ammo is required, so don't shoot. This is for weapons that shoot
|
||||
// missiles that die at close range, such as the powered-up Phoneix Rod.
|
||||
|
@ -196,51 +193,51 @@ void FCajunMaster::Dofire (AActor *actor, ticcmd_t *cmd)
|
|||
no_fire = (dist > (MELEERANGE*4));
|
||||
}
|
||||
}
|
||||
else if (actor->player->ReadyWeapon->WeaponFlags & WIF_BOT_BFG)
|
||||
else if (player->ReadyWeapon->WeaponFlags & WIF_BOT_BFG)
|
||||
{
|
||||
//MAKEME: This should be smarter.
|
||||
if ((pr_botdofire()%200)<=actor->player->skill.reaction)
|
||||
if(Check_LOS(actor, actor->player->enemy, SHOOTFOV))
|
||||
if ((pr_botdofire()%200)<=skill.reaction)
|
||||
if(Check_LOS(enemy, SHOOTFOV))
|
||||
no_fire = false;
|
||||
}
|
||||
else if (actor->player->ReadyWeapon->ProjectileType != NULL)
|
||||
else if (player->ReadyWeapon->ProjectileType != NULL)
|
||||
{
|
||||
if (actor->player->ReadyWeapon->WeaponFlags & WIF_BOT_EXPLOSIVE)
|
||||
if (player->ReadyWeapon->WeaponFlags & WIF_BOT_EXPLOSIVE)
|
||||
{
|
||||
//Special rules for RL
|
||||
an = FireRox (actor, enemy, cmd);
|
||||
an = FireRox (enemy, cmd);
|
||||
if(an)
|
||||
{
|
||||
actor->player->angle = an;
|
||||
angle = an;
|
||||
//have to be somewhat precise. to avoid suicide.
|
||||
if (abs (actor->player->angle - actor->angle) < 12*ANGLE_1)
|
||||
if (abs (angle - player->mo->angle) < 12*ANGLE_1)
|
||||
{
|
||||
actor->player->t_rocket = 9;
|
||||
t_rocket = 9;
|
||||
no_fire = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// prediction aiming
|
||||
shootmissile:
|
||||
dist = P_AproxDistance (actor->x - enemy->x, actor->y - enemy->y);
|
||||
m = dist / GetDefaultByType (actor->player->ReadyWeapon->ProjectileType)->Speed;
|
||||
SetBodyAt (enemy->x + enemy->velx*m*2, enemy->y + enemy->vely*m*2, enemy->z, 1);
|
||||
actor->player->angle = R_PointToAngle2 (actor->x, actor->y, body1->x, body1->y);
|
||||
if (Check_LOS (actor, enemy, SHOOTFOV))
|
||||
dist = P_AproxDistance (player->mo->x - enemy->x, player->mo->y - enemy->y);
|
||||
m = dist / GetDefaultByType (player->ReadyWeapon->ProjectileType)->Speed;
|
||||
bglobal.SetBodyAt (enemy->x + enemy->velx*m*2, enemy->y + enemy->vely*m*2, enemy->z, 1);
|
||||
angle = R_PointToAngle2 (player->mo->x, player->mo->y, bglobal.body1->x, bglobal.body1->y);
|
||||
if (Check_LOS (enemy, SHOOTFOV))
|
||||
no_fire = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Other weapons, mostly instant hit stuff.
|
||||
actor->player->angle = R_PointToAngle2 (actor->x, actor->y, enemy->x, enemy->y);
|
||||
angle = R_PointToAngle2 (player->mo->x, player->mo->y, enemy->x, enemy->y);
|
||||
aiming_penalty = 0;
|
||||
if (enemy->flags & MF_SHADOW)
|
||||
aiming_penalty += (pr_botdofire()%25)+10;
|
||||
if (enemy->Sector->lightlevel<WHATS_DARK/* && !(actor->player->powers & PW_INFRARED)*/)
|
||||
if (enemy->Sector->lightlevel<WHATS_DARK/* && !(player->powers & PW_INFRARED)*/)
|
||||
aiming_penalty += pr_botdofire()%40;//Dark
|
||||
if (actor->player->damagecount)
|
||||
aiming_penalty += actor->player->damagecount; //Blood in face makes it hard to aim
|
||||
aiming_value = actor->player->skill.aiming - aiming_penalty;
|
||||
if (player->damagecount)
|
||||
aiming_penalty += player->damagecount; //Blood in face makes it hard to aim
|
||||
aiming_value = skill.aiming - aiming_penalty;
|
||||
if (aiming_value <= 0)
|
||||
aiming_value = 1;
|
||||
m = ((SHOOTFOV/2)-(aiming_value*SHOOTFOV/200)); //Higher skill is more accurate
|
||||
|
@ -249,18 +246,18 @@ shootmissile:
|
|||
|
||||
if (m)
|
||||
{
|
||||
if (inc[actor->id])
|
||||
actor->player->angle += m;
|
||||
if (increase)
|
||||
angle += m;
|
||||
else
|
||||
actor->player->angle -= m;
|
||||
angle -= m;
|
||||
}
|
||||
|
||||
if (abs (actor->player->angle - actor->angle) < 4*ANGLE_1)
|
||||
if (abs (angle - player->mo->angle) < 4*ANGLE_1)
|
||||
{
|
||||
inc[actor->id] = !inc[actor->id];
|
||||
increase = !increase;
|
||||
}
|
||||
|
||||
if (Check_LOS (actor, enemy, (SHOOTFOV/2)))
|
||||
if (Check_LOS (enemy, (SHOOTFOV/2)))
|
||||
no_fire = false;
|
||||
}
|
||||
if (!no_fire) //If going to fire weapon
|
||||
|
@ -268,53 +265,48 @@ shootmissile:
|
|||
cmd->ucmd.buttons |= BT_ATTACK;
|
||||
}
|
||||
//Prevents bot from jerking, when firing automatic things with low skill.
|
||||
//actor->angle = R_PointToAngle2(actor->x, actor->y, actor->player->enemy->x, actor->player->enemy->y);
|
||||
//player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, player->enemy->x, player->enemy->y);
|
||||
}
|
||||
|
||||
bool FCajunMaster::IsLeader (player_t *player)
|
||||
{
|
||||
for (int count = 0; count < MAXPLAYERS; count++)
|
||||
{
|
||||
if (players[count].Bot != NULL
|
||||
&& players[count].Bot->mate == player->mo)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//This function is called every
|
||||
//tick (for each bot) to set
|
||||
//the mate (teammate coop mate).
|
||||
AActor *FCajunMaster::Choose_Mate (AActor *bot)
|
||||
AActor *DBot::Choose_Mate ()
|
||||
{
|
||||
int count;
|
||||
int count2;
|
||||
fixed_t closest_dist, test;
|
||||
AActor *target;
|
||||
AActor *observer;
|
||||
bool p_leader[MAXPLAYERS];
|
||||
|
||||
//is mate alive?
|
||||
if (bot->player->mate)
|
||||
if (mate)
|
||||
{
|
||||
if (bot->player->mate->health <= 0)
|
||||
bot->player->mate = NULL;
|
||||
if (mate->health <= 0)
|
||||
mate = NULL;
|
||||
else
|
||||
bot->player->last_mate = bot->player->mate;
|
||||
last_mate = mate;
|
||||
}
|
||||
if (bot->player->mate) //Still is..
|
||||
return bot->player->mate;
|
||||
if (mate) //Still is..
|
||||
return mate;
|
||||
|
||||
//Check old_mates status.
|
||||
if (bot->player->last_mate)
|
||||
if (bot->player->last_mate->health <= 0)
|
||||
bot->player->last_mate = NULL;
|
||||
|
||||
for (count = 0; count < MAXPLAYERS; count++)
|
||||
{
|
||||
if (!playeringame[count])
|
||||
continue;
|
||||
p_leader[count] = false;
|
||||
for (count2 = 0; count2 < MAXPLAYERS; count2++)
|
||||
{
|
||||
if (players[count].isbot
|
||||
&& players[count2].mate == players[count].mo)
|
||||
{
|
||||
p_leader[count] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (last_mate)
|
||||
if (last_mate->health <= 0)
|
||||
last_mate = NULL;
|
||||
|
||||
target = NULL;
|
||||
closest_dist = FIXED_MAX;
|
||||
|
@ -330,18 +322,17 @@ AActor *FCajunMaster::Choose_Mate (AActor *bot)
|
|||
|
||||
if (playeringame[count]
|
||||
&& client->mo
|
||||
&& bot != client->mo
|
||||
&& (bot->IsTeammate (client->mo) || !deathmatch)
|
||||
&& player->mo != client->mo
|
||||
&& (player->mo->IsTeammate (client->mo) || !deathmatch)
|
||||
&& client->mo->health > 0
|
||||
&& client->mo != observer
|
||||
&& ((bot->health/2) <= client->mo->health || !deathmatch)
|
||||
&& !p_leader[count]) //taken?
|
||||
&& ((player->mo->health/2) <= client->mo->health || !deathmatch)
|
||||
&& !bglobal.IsLeader(client)) //taken?
|
||||
{
|
||||
|
||||
if (P_CheckSight (bot, client->mo, SF_IGNOREVISIBILITY))
|
||||
if (P_CheckSight (player->mo, client->mo, SF_IGNOREVISIBILITY))
|
||||
{
|
||||
test = P_AproxDistance (client->mo->x - bot->x,
|
||||
client->mo->y - bot->y);
|
||||
test = P_AproxDistance (client->mo->x - player->mo->x,
|
||||
client->mo->y - player->mo->y);
|
||||
|
||||
if (test < closest_dist)
|
||||
{
|
||||
|
@ -354,15 +345,15 @@ AActor *FCajunMaster::Choose_Mate (AActor *bot)
|
|||
|
||||
/*
|
||||
//Make a introducing to mate.
|
||||
if(target && target!=bot->player->last_mate)
|
||||
if(target && target!=last_mate)
|
||||
{
|
||||
if((P_Random()%(200*bglobal.botnum))<3)
|
||||
{
|
||||
bot->player->chat = c_teamup;
|
||||
chat = c_teamup;
|
||||
if(target->bot)
|
||||
strcpy(bot->player->c_target, botsingame[target->bot_id]);
|
||||
strcpy(c_target, botsingame[target->bot_id]);
|
||||
else if(target->player)
|
||||
strcpy(bot->player->c_target, player_names[target->play_id]);
|
||||
strcpy(c_target, player_names[target->play_id]);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
@ -372,7 +363,7 @@ AActor *FCajunMaster::Choose_Mate (AActor *bot)
|
|||
}
|
||||
|
||||
//MAKEME: Make this a smart decision
|
||||
AActor *FCajunMaster::Find_enemy (AActor *bot)
|
||||
AActor *DBot::Find_enemy ()
|
||||
{
|
||||
int count;
|
||||
fixed_t closest_dist, temp; //To target.
|
||||
|
@ -382,15 +373,15 @@ AActor *FCajunMaster::Find_enemy (AActor *bot)
|
|||
|
||||
if (!deathmatch)
|
||||
{ // [RH] Take advantage of the Heretic/Hexen code to be a little smarter
|
||||
return P_RoughMonsterSearch (bot, 20);
|
||||
return P_RoughMonsterSearch (player->mo, 20);
|
||||
}
|
||||
|
||||
//Note: It's hard to ambush a bot who is not alone
|
||||
if (bot->player->allround || bot->player->mate)
|
||||
if (allround || mate)
|
||||
vangle = ANGLE_MAX;
|
||||
else
|
||||
vangle = ENEMY_SCAN_FOV;
|
||||
bot->player->allround = false;
|
||||
allround = false;
|
||||
|
||||
target = NULL;
|
||||
closest_dist = FIXED_MAX;
|
||||
|
@ -403,21 +394,21 @@ AActor *FCajunMaster::Find_enemy (AActor *bot)
|
|||
{
|
||||
player_t *client = &players[count];
|
||||
if (playeringame[count]
|
||||
&& !bot->IsTeammate (client->mo)
|
||||
&& !player->mo->IsTeammate (client->mo)
|
||||
&& client->mo != observer
|
||||
&& client->mo->health > 0
|
||||
&& bot != client->mo)
|
||||
&& player->mo != client->mo)
|
||||
{
|
||||
if (Check_LOS (bot, client->mo, vangle)) //Here's a strange one, when bot is standing still, the P_CheckSight within Check_LOS almost always returns false. tought it should be the same checksight as below but.. (below works) something must be fuckin wierd screded up.
|
||||
//if(P_CheckSight( bot, players[count].mo))
|
||||
if (Check_LOS (client->mo, vangle)) //Here's a strange one, when bot is standing still, the P_CheckSight within Check_LOS almost always returns false. tought it should be the same checksight as below but.. (below works) something must be fuckin wierd screded up.
|
||||
//if(P_CheckSight(player->mo, players[count].mo))
|
||||
{
|
||||
temp = P_AproxDistance (client->mo->x - bot->x,
|
||||
client->mo->y - bot->y);
|
||||
temp = P_AproxDistance (client->mo->x - player->mo->x,
|
||||
client->mo->y - player->mo->y);
|
||||
|
||||
//Too dark?
|
||||
if (temp > DARK_DIST &&
|
||||
client->mo->Sector->lightlevel < WHATS_DARK /*&&
|
||||
bot->player->Powers & PW_INFRARED*/)
|
||||
player->Powers & PW_INFRARED*/)
|
||||
continue;
|
||||
|
||||
if (temp < closest_dist)
|
||||
|
@ -501,16 +492,16 @@ fixed_t FCajunMaster::FakeFire (AActor *source, AActor *dest, ticcmd_t *cmd)
|
|||
return dist;
|
||||
}
|
||||
|
||||
angle_t FCajunMaster::FireRox (AActor *bot, AActor *enemy, ticcmd_t *cmd)
|
||||
angle_t DBot::FireRox (AActor *enemy, ticcmd_t *cmd)
|
||||
{
|
||||
fixed_t dist;
|
||||
angle_t ang;
|
||||
AActor *actor;
|
||||
int m;
|
||||
|
||||
SetBodyAt (bot->x + FixedMul(bot->velx, 5*FRACUNIT),
|
||||
bot->y + FixedMul(bot->vely, 5*FRACUNIT),
|
||||
bot->z + (bot->height / 2), 2);
|
||||
bglobal.SetBodyAt (player->mo->x + FixedMul(player->mo->velx, 5*FRACUNIT),
|
||||
player->mo->y + FixedMul(player->mo->vely, 5*FRACUNIT),
|
||||
player->mo->z + (player->mo->height / 2), 2);
|
||||
|
||||
actor = bglobal.body2;
|
||||
|
||||
|
@ -520,16 +511,16 @@ angle_t FCajunMaster::FireRox (AActor *bot, AActor *enemy, ticcmd_t *cmd)
|
|||
//Predict.
|
||||
m = (((dist+1)/FRACUNIT) / GetDefaultByName("Rocket")->Speed);
|
||||
|
||||
SetBodyAt (enemy->x + FixedMul(enemy->velx, (m+2*FRACUNIT)),
|
||||
enemy->y + FixedMul(enemy->vely, (m+2*FRACUNIT)), ONFLOORZ, 1);
|
||||
bglobal.SetBodyAt (enemy->x + FixedMul(enemy->velx, (m+2*FRACUNIT)),
|
||||
enemy->y + FixedMul(enemy->vely, (m+2*FRACUNIT)), ONFLOORZ, 1);
|
||||
dist = P_AproxDistance(actor->x-bglobal.body1->x, actor->y-bglobal.body1->y);
|
||||
//try the predicted location
|
||||
if (P_CheckSight (actor, bglobal.body1, SF_IGNOREVISIBILITY)) //See the predicted location, so give a test missile
|
||||
{
|
||||
FCheckPosition tm;
|
||||
if (SafeCheckPosition (bot, actor->x, actor->y, tm))
|
||||
if (bglobal.SafeCheckPosition (player->mo, actor->x, actor->y, tm))
|
||||
{
|
||||
if (FakeFire (actor, bglobal.body1, cmd) >= SAFE_SELF_MISDIST)
|
||||
if (bglobal.FakeFire (actor, bglobal.body1, cmd) >= SAFE_SELF_MISDIST)
|
||||
{
|
||||
ang = R_PointToAngle2 (actor->x, actor->y, bglobal.body1->x, bglobal.body1->y);
|
||||
return ang;
|
||||
|
@ -539,9 +530,9 @@ angle_t FCajunMaster::FireRox (AActor *bot, AActor *enemy, ticcmd_t *cmd)
|
|||
//Try fire straight.
|
||||
if (P_CheckSight (actor, enemy, 0))
|
||||
{
|
||||
if (FakeFire (bot, enemy, cmd) >= SAFE_SELF_MISDIST)
|
||||
if (bglobal.FakeFire (player->mo, enemy, cmd) >= SAFE_SELF_MISDIST)
|
||||
{
|
||||
ang = R_PointToAngle2(bot->x, bot->y, enemy->x, enemy->y);
|
||||
ang = R_PointToAngle2(player->mo->x, player->mo->y, enemy->x, enemy->y);
|
||||
return ang;
|
||||
}
|
||||
}
|
||||
|
@ -559,3 +550,25 @@ bool FCajunMaster::SafeCheckPosition (AActor *actor, fixed_t x, fixed_t y, FChec
|
|||
actor->flags = savedFlags;
|
||||
return res;
|
||||
}
|
||||
|
||||
void FCajunMaster::StartTravel ()
|
||||
{
|
||||
for (int i = 0; i < MAXPLAYERS; ++i)
|
||||
{
|
||||
if (players[i].Bot != NULL)
|
||||
{
|
||||
players[i].Bot->ChangeStatNum (STAT_TRAVELLING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FCajunMaster::FinishTravel ()
|
||||
{
|
||||
for (int i = 0; i < MAXPLAYERS; ++i)
|
||||
{
|
||||
if (players[i].Bot != NULL)
|
||||
{
|
||||
players[i].Bot->ChangeStatNum (STAT_BOT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
251
src/b_game.cpp
251
src/b_game.cpp
|
@ -89,49 +89,27 @@ enum
|
|||
BOTCFG_TEAM
|
||||
};
|
||||
|
||||
static bool waitingforspawn[MAXPLAYERS];
|
||||
|
||||
FCajunMaster::~FCajunMaster()
|
||||
{
|
||||
ForgetBots();
|
||||
}
|
||||
|
||||
//This function is called every tick (from g_game.c),
|
||||
//send bots into thinking (+more).
|
||||
void FCajunMaster::Main (int buf)
|
||||
//This function is called every tick (from g_game.c).
|
||||
void FCajunMaster::Main ()
|
||||
{
|
||||
int i;
|
||||
|
||||
BotThinkCycles.Reset();
|
||||
|
||||
if (consoleplayer != Net_Arbitrator || demoplayback)
|
||||
if (demoplayback || gamestate != GS_LEVEL || consoleplayer != Net_Arbitrator)
|
||||
return;
|
||||
|
||||
if (gamestate != GS_LEVEL)
|
||||
return;
|
||||
|
||||
m_Thinking = true;
|
||||
|
||||
//Think for bots.
|
||||
if (botnum)
|
||||
{
|
||||
BotThinkCycles.Clock();
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && players[i].mo && !freeze && players[i].isbot)
|
||||
Think (players[i].mo, &netcmds[i][buf]);
|
||||
}
|
||||
BotThinkCycles.Unclock();
|
||||
}
|
||||
|
||||
//Add new bots?
|
||||
if (wanted_botnum > botnum && !freeze)
|
||||
{
|
||||
if (t_join == ((wanted_botnum - botnum) * SPAWN_DELAY))
|
||||
{
|
||||
if (!SpawnBot (getspawned[spawn_tries]))
|
||||
if (!SpawnBot (getspawned[spawn_tries]))
|
||||
wanted_botnum--;
|
||||
spawn_tries++;
|
||||
spawn_tries++;
|
||||
}
|
||||
|
||||
t_join--;
|
||||
|
@ -156,14 +134,10 @@ void FCajunMaster::Main (int buf)
|
|||
players[consoleplayer].mo->flags2 &= ~MF2_FLY;
|
||||
players[consoleplayer].mo->LinkToWorld ();
|
||||
}
|
||||
|
||||
m_Thinking = false;
|
||||
}
|
||||
|
||||
void FCajunMaster::Init ()
|
||||
{
|
||||
int i;
|
||||
|
||||
botnum = 0;
|
||||
firstthing = NULL;
|
||||
spawn_tries = 0;
|
||||
|
@ -172,18 +146,6 @@ void FCajunMaster::Init ()
|
|||
body1 = NULL;
|
||||
body2 = NULL;
|
||||
|
||||
//Remove all bots upon each level start, they'll get spawned instead.
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
waitingforspawn[i] = false;
|
||||
if (playeringame[i] && players[i].isbot)
|
||||
{
|
||||
CleanBotstuff (&players[i]);
|
||||
players[i].isbot = false;
|
||||
botingame[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctf && teamplay == false)
|
||||
teamplay = true; //Need teamplay for ctf. (which is not done yet)
|
||||
|
||||
|
@ -199,7 +161,7 @@ void FCajunMaster::Init ()
|
|||
|
||||
while (thebot != NULL)
|
||||
{
|
||||
thebot->inuse = false;
|
||||
thebot->inuse = BOTINUSE_No;
|
||||
thebot = thebot->next;
|
||||
}
|
||||
}
|
||||
|
@ -212,19 +174,13 @@ void FCajunMaster::End ()
|
|||
|
||||
//Arrange wanted botnum and their names, so they can be spawned next level.
|
||||
getspawned.Clear();
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && players[i].isbot)
|
||||
{
|
||||
if (deathmatch)
|
||||
{
|
||||
getspawned.Push(players[i].userinfo.GetName());
|
||||
}
|
||||
CleanBotstuff (&players[i]);
|
||||
}
|
||||
}
|
||||
if (deathmatch)
|
||||
{
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
getspawned.Push(players[i].userinfo.GetName());
|
||||
}
|
||||
|
||||
wanted_botnum = botnum;
|
||||
}
|
||||
}
|
||||
|
@ -240,12 +196,10 @@ void FCajunMaster::End ()
|
|||
//The color parameter can be either a
|
||||
//color (range from 0-10), or = NOCOLOR.
|
||||
//The color parameter overides bots
|
||||
//induvidual colors if not = NOCOLOR.
|
||||
//individual colors if not = NOCOLOR.
|
||||
|
||||
bool FCajunMaster::SpawnBot (const char *name, int color)
|
||||
{
|
||||
int playernumber;
|
||||
|
||||
//COLORS
|
||||
static const char colors[11][17] =
|
||||
{
|
||||
|
@ -262,36 +216,31 @@ bool FCajunMaster::SpawnBot (const char *name, int color)
|
|||
"\\color\\cf df 90" //10 = Bleached Bone
|
||||
};
|
||||
|
||||
for (playernumber = 0; playernumber < MAXPLAYERS; playernumber++)
|
||||
{
|
||||
if (!playeringame[playernumber] && !waitingforspawn[playernumber])
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (playernumber == MAXPLAYERS)
|
||||
{
|
||||
Printf ("The maximum of %d players/bots has been reached\n", MAXPLAYERS);
|
||||
return false;
|
||||
}
|
||||
|
||||
botinfo_t *thebot;
|
||||
int botshift;
|
||||
|
||||
if (name)
|
||||
{
|
||||
thebot = botinfo;
|
||||
|
||||
// Check if exist or already in the game.
|
||||
botshift = 0;
|
||||
while (thebot && stricmp (name, thebot->name))
|
||||
{
|
||||
thebot = thebot->next;
|
||||
botshift++;
|
||||
}
|
||||
|
||||
if (thebot == NULL)
|
||||
{
|
||||
Printf ("couldn't find %s in %s\n", name, BOTFILENAME);
|
||||
return false;
|
||||
}
|
||||
else if (thebot->inuse)
|
||||
else if (thebot->inuse == BOTINUSE_Waiting)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (thebot->inuse == BOTINUSE_Yes)
|
||||
{
|
||||
Printf ("%s is already in the thick\n", name);
|
||||
return false;
|
||||
|
@ -304,9 +253,13 @@ bool FCajunMaster::SpawnBot (const char *name, int color)
|
|||
{
|
||||
int rnum = (pr_botspawn() % loaded_bots);
|
||||
thebot = botinfo;
|
||||
botshift = 0;
|
||||
while (rnum)
|
||||
{
|
||||
--rnum, thebot = thebot->next;
|
||||
if (!thebot->inuse)
|
||||
botshift++;
|
||||
}
|
||||
if (thebot->inuse == BOTINUSE_No)
|
||||
vacant = true;
|
||||
}
|
||||
}
|
||||
|
@ -316,10 +269,10 @@ bool FCajunMaster::SpawnBot (const char *name, int color)
|
|||
return false;
|
||||
}
|
||||
|
||||
waitingforspawn[playernumber] = true;
|
||||
thebot->inuse = BOTINUSE_Waiting;
|
||||
|
||||
Net_WriteByte (DEM_ADDBOT);
|
||||
Net_WriteByte (playernumber);
|
||||
Net_WriteByte (botshift);
|
||||
{
|
||||
//Set color.
|
||||
char concat[512];
|
||||
|
@ -335,52 +288,106 @@ bool FCajunMaster::SpawnBot (const char *name, int color)
|
|||
}
|
||||
Net_WriteString (concat);
|
||||
}
|
||||
|
||||
players[playernumber].skill = thebot->skill;
|
||||
|
||||
thebot->inuse = true;
|
||||
|
||||
//Increment this.
|
||||
botnum++;
|
||||
Net_WriteByte(thebot->skill.aiming);
|
||||
Net_WriteByte(thebot->skill.perfection);
|
||||
Net_WriteByte(thebot->skill.reaction);
|
||||
Net_WriteByte(thebot->skill.isp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FCajunMaster::DoAddBot (int bnum, char *info)
|
||||
void FCajunMaster::TryAddBot (BYTE **stream, int player)
|
||||
{
|
||||
BYTE *infob = (BYTE *)info;
|
||||
D_ReadUserInfoStrings (bnum, &infob, false);
|
||||
int botshift = ReadByte (stream);
|
||||
char *info = ReadString (stream);
|
||||
botskill_t skill;
|
||||
skill.aiming = ReadByte (stream);
|
||||
skill.perfection = ReadByte (stream);
|
||||
skill.reaction = ReadByte (stream);
|
||||
skill.isp = ReadByte (stream);
|
||||
|
||||
botinfo_t *thebot = NULL;
|
||||
|
||||
if (consoleplayer == player)
|
||||
{
|
||||
thebot = botinfo;
|
||||
|
||||
while (botshift > 0)
|
||||
{
|
||||
thebot = thebot->next;
|
||||
botshift--;
|
||||
}
|
||||
}
|
||||
|
||||
if (DoAddBot ((BYTE *)info, skill))
|
||||
{
|
||||
//Increment this.
|
||||
botnum++;
|
||||
|
||||
if (thebot != NULL)
|
||||
{
|
||||
thebot->inuse = BOTINUSE_Yes;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (thebot != NULL)
|
||||
{
|
||||
thebot->inuse = BOTINUSE_No;
|
||||
}
|
||||
}
|
||||
|
||||
delete[] info;
|
||||
}
|
||||
|
||||
bool FCajunMaster::DoAddBot (BYTE *info, botskill_t skill)
|
||||
{
|
||||
int bnum;
|
||||
|
||||
for (bnum = 0; bnum < MAXPLAYERS; bnum++)
|
||||
{
|
||||
if (!playeringame[bnum])
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bnum == MAXPLAYERS)
|
||||
{
|
||||
Printf ("The maximum of %d players/bots has been reached\n", MAXPLAYERS);
|
||||
return false;
|
||||
}
|
||||
|
||||
D_ReadUserInfoStrings (bnum, &info, false);
|
||||
|
||||
if (!deathmatch && playerstarts[bnum].type == 0)
|
||||
{
|
||||
Printf ("%s tried to join, but there was no player %d start\n",
|
||||
players[bnum].userinfo.GetName(), bnum+1);
|
||||
ClearPlayer (bnum, false); // Make the bot inactive again
|
||||
if (botnum > 0)
|
||||
{
|
||||
botnum--;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
multiplayer = true; //Prevents cheating and so on; emulates real netgame (almost).
|
||||
players[bnum].Bot = new DBot;
|
||||
players[bnum].Bot->player = &players[bnum];
|
||||
players[bnum].Bot->skill = skill;
|
||||
playeringame[bnum] = true;
|
||||
players[bnum].mo = NULL;
|
||||
players[bnum].playerstate = PST_ENTER;
|
||||
|
||||
if (teamplay)
|
||||
Printf ("%s joined the %s team\n", players[bnum].userinfo.GetName(), Teams[players[bnum].userinfo.GetTeam()].GetName());
|
||||
else
|
||||
Printf ("%s joined the game\n", players[bnum].userinfo.GetName());
|
||||
|
||||
G_DoReborn (bnum, true);
|
||||
if (StatusBar != NULL)
|
||||
{
|
||||
multiplayer = true; //Prevents cheating and so on; emulates real netgame (almost).
|
||||
players[bnum].isbot = true;
|
||||
playeringame[bnum] = true;
|
||||
players[bnum].mo = NULL;
|
||||
players[bnum].playerstate = PST_ENTER;
|
||||
botingame[bnum] = true;
|
||||
|
||||
if (teamplay)
|
||||
Printf ("%s joined the %s team\n", players[bnum].userinfo.GetName(), Teams[players[bnum].userinfo.GetTeam()].GetName());
|
||||
else
|
||||
Printf ("%s joined the game\n", players[bnum].userinfo.GetName());
|
||||
|
||||
G_DoReborn (bnum, true);
|
||||
if (StatusBar != NULL)
|
||||
{
|
||||
StatusBar->MultiplayerChanged ();
|
||||
}
|
||||
StatusBar->MultiplayerChanged ();
|
||||
}
|
||||
waitingforspawn[bnum] = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FCajunMaster::RemoveAllBots (bool fromlist)
|
||||
|
@ -389,13 +396,13 @@ void FCajunMaster::RemoveAllBots (bool fromlist)
|
|||
|
||||
for (i = 0; i < MAXPLAYERS; ++i)
|
||||
{
|
||||
if (playeringame[i] && botingame[i])
|
||||
if (players[i].Bot != NULL)
|
||||
{
|
||||
// If a player is looking through this bot's eyes, make him
|
||||
// look through his own eyes instead.
|
||||
for (j = 0; j < MAXPLAYERS; ++j)
|
||||
{
|
||||
if (i != j && playeringame[j] && !botingame[j])
|
||||
if (i != j && playeringame[j] && players[j].Bot == NULL)
|
||||
{
|
||||
if (players[j].camera == players[i].mo)
|
||||
{
|
||||
|
@ -415,34 +422,10 @@ void FCajunMaster::RemoveAllBots (bool fromlist)
|
|||
if (fromlist)
|
||||
{
|
||||
wanted_botnum = 0;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
waitingforspawn[i] = false;
|
||||
}
|
||||
botnum = 0;
|
||||
}
|
||||
|
||||
//Clean the bot part of the player_t
|
||||
//Used when bots are respawned or at level starts.
|
||||
void FCajunMaster::CleanBotstuff (player_t *p)
|
||||
{
|
||||
p->angle = ANG45;
|
||||
p->dest = NULL;
|
||||
p->enemy = NULL; //The dead meat.
|
||||
p->missile = NULL; //A threatening missile that needs to be avoided.
|
||||
p->mate = NULL; //Friend (used for grouping in templay or coop.
|
||||
p->last_mate = NULL; //If bot's mate dissapeared (not if died) that mate is pointed to by this. Allows bot to roam to it if necessary.
|
||||
//Tickers
|
||||
p->t_active = 0; //Open door, lower lift stuff, door must open and lift must go down before bot does anything radical like try a stuckmove
|
||||
p->t_respawn = 0;
|
||||
p->t_strafe = 0;
|
||||
p->t_react = 0;
|
||||
//Misc bools
|
||||
p->isbot = true; //Important.
|
||||
p->first_shot = true; //Used for reaction skill.
|
||||
p->sleft = false; //If false, strafe is right.
|
||||
p->allround = false;
|
||||
}
|
||||
|
||||
|
||||
//------------------
|
||||
//Reads data for bot from
|
||||
|
|
142
src/b_move.cpp
142
src/b_move.cpp
|
@ -17,20 +17,7 @@
|
|||
#include "gi.h"
|
||||
#include "a_keys.h"
|
||||
#include "d_event.h"
|
||||
|
||||
enum dirtype_t
|
||||
{
|
||||
DI_EAST,
|
||||
DI_NORTHEAST,
|
||||
DI_NORTH,
|
||||
DI_NORTHWEST,
|
||||
DI_WEST,
|
||||
DI_SOUTHWEST,
|
||||
DI_SOUTH,
|
||||
DI_SOUTHEAST,
|
||||
DI_NODIR,
|
||||
NUMDIRS
|
||||
};
|
||||
#include "p_enemy.h"
|
||||
|
||||
static FRandom pr_botopendoor ("BotOpenDoor");
|
||||
static FRandom pr_bottrywalk ("BotTryWalk");
|
||||
|
@ -39,62 +26,58 @@ static FRandom pr_botnewchasedir ("BotNewChaseDir");
|
|||
// borrow some tables from p_enemy.cpp
|
||||
extern dirtype_t opposite[9];
|
||||
extern dirtype_t diags[4];
|
||||
extern fixed_t xspeed[8];
|
||||
extern fixed_t yspeed[8];
|
||||
|
||||
extern TArray<line_t *> spechit;
|
||||
|
||||
//Called while the bot moves after its player->dest mobj
|
||||
//Called while the bot moves after its dest mobj
|
||||
//which can be a weapon/enemy/item whatever.
|
||||
void FCajunMaster::Roam (AActor *actor, ticcmd_t *cmd)
|
||||
void DBot::Roam (ticcmd_t *cmd)
|
||||
{
|
||||
int delta;
|
||||
|
||||
if (Reachable(actor, actor->player->dest))
|
||||
if (Reachable(dest))
|
||||
{ // Straight towards it.
|
||||
actor->player->angle = R_PointToAngle2(actor->x, actor->y, actor->player->dest->x, actor->player->dest->y);
|
||||
angle = R_PointToAngle2(player->mo->x, player->mo->y, dest->x, dest->y);
|
||||
}
|
||||
else if (actor->movedir < 8) // turn towards movement direction if not there yet
|
||||
else if (player->mo->movedir < 8) // turn towards movement direction if not there yet
|
||||
{
|
||||
actor->player->angle &= (angle_t)(7<<29);
|
||||
delta = actor->player->angle - (actor->movedir << 29);
|
||||
angle &= (angle_t)(7<<29);
|
||||
delta = angle - (player->mo->movedir << 29);
|
||||
|
||||
if (delta > 0)
|
||||
actor->player->angle -= ANG45;
|
||||
angle -= ANG45;
|
||||
else if (delta < 0)
|
||||
actor->player->angle += ANG45;
|
||||
angle += ANG45;
|
||||
}
|
||||
|
||||
// chase towards destination.
|
||||
if (--actor->movecount < 0 || !Move (actor, cmd))
|
||||
if (--player->mo->movecount < 0 || !Move (cmd))
|
||||
{
|
||||
NewChaseDir (actor, cmd);
|
||||
NewChaseDir (cmd);
|
||||
}
|
||||
}
|
||||
|
||||
bool FCajunMaster::Move (AActor *actor, ticcmd_t *cmd)
|
||||
bool DBot::Move (ticcmd_t *cmd)
|
||||
{
|
||||
fixed_t tryx, tryy;
|
||||
bool try_ok;
|
||||
int good;
|
||||
|
||||
if (actor->movedir == DI_NODIR)
|
||||
if (player->mo->movedir == DI_NODIR)
|
||||
return false;
|
||||
|
||||
if ((unsigned)actor->movedir >= 8)
|
||||
if ((unsigned)player->mo->movedir >= 8)
|
||||
I_Error ("Weird bot movedir!");
|
||||
|
||||
tryx = actor->x + 8*xspeed[actor->movedir];
|
||||
tryy = actor->y + 8*yspeed[actor->movedir];
|
||||
tryx = player->mo->x + 8*xspeed[player->mo->movedir];
|
||||
tryy = player->mo->y + 8*yspeed[player->mo->movedir];
|
||||
|
||||
try_ok = CleanAhead (actor, tryx, tryy, cmd);
|
||||
try_ok = bglobal.CleanAhead (player->mo, tryx, tryy, cmd);
|
||||
|
||||
if (!try_ok) //Anything blocking that could be opened etc..
|
||||
{
|
||||
if (!spechit.Size ())
|
||||
return false;
|
||||
|
||||
actor->movedir = DI_NODIR;
|
||||
player->mo->movedir = DI_NODIR;
|
||||
|
||||
good = 0;
|
||||
line_t *ld;
|
||||
|
@ -103,16 +86,16 @@ bool FCajunMaster::Move (AActor *actor, ticcmd_t *cmd)
|
|||
{
|
||||
bool tryit = true;
|
||||
|
||||
if (ld->special == Door_LockedRaise && !P_CheckKeys (actor, ld->args[3], false))
|
||||
if (ld->special == Door_LockedRaise && !P_CheckKeys (player->mo, ld->args[3], false))
|
||||
tryit = false;
|
||||
else if (ld->special == Generic_Door && !P_CheckKeys (actor, ld->args[4], false))
|
||||
else if (ld->special == Generic_Door && !P_CheckKeys (player->mo, ld->args[4], false))
|
||||
tryit = false;
|
||||
|
||||
if (tryit &&
|
||||
(P_TestActivateLine (ld, actor, 0, SPAC_Use) ||
|
||||
P_TestActivateLine (ld, actor, 0, SPAC_Push)))
|
||||
(P_TestActivateLine (ld, player->mo, 0, SPAC_Use) ||
|
||||
P_TestActivateLine (ld, player->mo, 0, SPAC_Push)))
|
||||
{
|
||||
good |= ld == actor->BlockingLine ? 1 : 2;
|
||||
good |= ld == player->mo->BlockingLine ? 1 : 2;
|
||||
}
|
||||
}
|
||||
if (good && ((pr_botopendoor() >= 203) ^ (good & 1)))
|
||||
|
@ -130,16 +113,16 @@ bool FCajunMaster::Move (AActor *actor, ticcmd_t *cmd)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool FCajunMaster::TryWalk (AActor *actor, ticcmd_t *cmd)
|
||||
bool DBot::TryWalk (ticcmd_t *cmd)
|
||||
{
|
||||
if (!Move (actor, cmd))
|
||||
if (!Move (cmd))
|
||||
return false;
|
||||
|
||||
actor->movecount = pr_bottrywalk() & 60;
|
||||
player->mo->movecount = pr_bottrywalk() & 60;
|
||||
return true;
|
||||
}
|
||||
|
||||
void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd)
|
||||
void DBot::NewChaseDir (ticcmd_t *cmd)
|
||||
{
|
||||
fixed_t deltax;
|
||||
fixed_t deltay;
|
||||
|
@ -151,7 +134,7 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd)
|
|||
|
||||
dirtype_t turnaround;
|
||||
|
||||
if (!actor->player->dest)
|
||||
if (!dest)
|
||||
{
|
||||
#ifndef BOT_RELEASE_COMPILE
|
||||
Printf ("Bot tried move without destination\n");
|
||||
|
@ -159,11 +142,11 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd)
|
|||
return;
|
||||
}
|
||||
|
||||
olddir = (dirtype_t)actor->movedir;
|
||||
olddir = (dirtype_t)player->mo->movedir;
|
||||
turnaround = opposite[olddir];
|
||||
|
||||
deltax = actor->player->dest->x - actor->x;
|
||||
deltay = actor->player->dest->y - actor->y;
|
||||
deltax = dest->x - player->mo->x;
|
||||
deltay = dest->y - player->mo->y;
|
||||
|
||||
if (deltax > 10*FRACUNIT)
|
||||
d[1] = DI_EAST;
|
||||
|
@ -182,8 +165,8 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd)
|
|||
// try direct route
|
||||
if (d[1] != DI_NODIR && d[2] != DI_NODIR)
|
||||
{
|
||||
actor->movedir = diags[((deltay<0)<<1)+(deltax>0)];
|
||||
if (actor->movedir != turnaround && TryWalk(actor, cmd))
|
||||
player->mo->movedir = diags[((deltay<0)<<1)+(deltax>0)];
|
||||
if (player->mo->movedir != turnaround && TryWalk(cmd))
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -203,16 +186,16 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd)
|
|||
|
||||
if (d[1]!=DI_NODIR)
|
||||
{
|
||||
actor->movedir = d[1];
|
||||
if (TryWalk (actor, cmd))
|
||||
player->mo->movedir = d[1];
|
||||
if (TryWalk (cmd))
|
||||
return;
|
||||
}
|
||||
|
||||
if (d[2]!=DI_NODIR)
|
||||
{
|
||||
actor->movedir = d[2];
|
||||
player->mo->movedir = d[2];
|
||||
|
||||
if (TryWalk(actor, cmd))
|
||||
if (TryWalk(cmd))
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -220,9 +203,9 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd)
|
|||
// so pick another direction.
|
||||
if (olddir!=DI_NODIR)
|
||||
{
|
||||
actor->movedir = olddir;
|
||||
player->mo->movedir = olddir;
|
||||
|
||||
if (TryWalk(actor, cmd))
|
||||
if (TryWalk(cmd))
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -235,9 +218,9 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd)
|
|||
{
|
||||
if (tdir!=turnaround)
|
||||
{
|
||||
actor->movedir = tdir;
|
||||
player->mo->movedir = tdir;
|
||||
|
||||
if (TryWalk(actor, cmd))
|
||||
if (TryWalk(cmd))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -250,9 +233,9 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd)
|
|||
{
|
||||
if (tdir!=turnaround)
|
||||
{
|
||||
actor->movedir = tdir;
|
||||
player->mo->movedir = tdir;
|
||||
|
||||
if (TryWalk(actor, cmd))
|
||||
if (TryWalk(cmd))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -260,12 +243,12 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd)
|
|||
|
||||
if (turnaround != DI_NODIR)
|
||||
{
|
||||
actor->movedir = turnaround;
|
||||
if (TryWalk(actor, cmd))
|
||||
player->mo->movedir = turnaround;
|
||||
if (TryWalk(cmd))
|
||||
return;
|
||||
}
|
||||
|
||||
actor->movedir = DI_NODIR; // can not move
|
||||
player->mo->movedir = DI_NODIR; // can not move
|
||||
}
|
||||
|
||||
|
||||
|
@ -324,48 +307,48 @@ bool FCajunMaster::CleanAhead (AActor *thing, fixed_t x, fixed_t y, ticcmd_t *cm
|
|||
#define MAXTURN (15*ANGLE_1) //Max degrees turned in one tic. Lower is smother but may cause the bot not getting where it should = crash
|
||||
#define TURNSENS 3 //Higher is smoother but slower turn.
|
||||
|
||||
void FCajunMaster::TurnToAng (AActor *actor)
|
||||
void DBot::TurnToAng ()
|
||||
{
|
||||
int maxturn = MAXTURN;
|
||||
|
||||
if (actor->player->ReadyWeapon != NULL)
|
||||
if (player->ReadyWeapon != NULL)
|
||||
{
|
||||
if (actor->player->ReadyWeapon->WeaponFlags & WIF_BOT_EXPLOSIVE)
|
||||
if (player->ReadyWeapon->WeaponFlags & WIF_BOT_EXPLOSIVE)
|
||||
{
|
||||
if (actor->player->t_roam && !actor->player->missile)
|
||||
if (t_roam && !missile)
|
||||
{ //Keep angle that where when shot where decided.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(actor->player->enemy)
|
||||
if(!actor->player->dest) //happens when running after item in combat situations, or normal, prevents weak turns
|
||||
if(actor->player->ReadyWeapon->ProjectileType == NULL && !(actor->player->ReadyWeapon->WeaponFlags & WIF_MELEEWEAPON))
|
||||
if(Check_LOS(actor, actor->player->enemy, SHOOTFOV+5*ANGLE_1))
|
||||
if(enemy)
|
||||
if(!dest) //happens when running after item in combat situations, or normal, prevents weak turns
|
||||
if(player->ReadyWeapon->ProjectileType == NULL && !(player->ReadyWeapon->WeaponFlags & WIF_MELEEWEAPON))
|
||||
if(Check_LOS(enemy, SHOOTFOV+5*ANGLE_1))
|
||||
maxturn = 3;
|
||||
}
|
||||
|
||||
int distance = actor->player->angle - actor->angle;
|
||||
int distance = angle - player->mo->angle;
|
||||
|
||||
if (abs (distance) < OKAYRANGE && !actor->player->enemy)
|
||||
if (abs (distance) < OKAYRANGE && !enemy)
|
||||
return;
|
||||
|
||||
distance /= TURNSENS;
|
||||
if (abs (distance) > maxturn)
|
||||
distance = distance < 0 ? -maxturn : maxturn;
|
||||
|
||||
actor->angle += distance;
|
||||
player->mo->angle += distance;
|
||||
}
|
||||
|
||||
void FCajunMaster::Pitch (AActor *actor, AActor *target)
|
||||
void DBot::Pitch (AActor *target)
|
||||
{
|
||||
double aim;
|
||||
double diff;
|
||||
|
||||
diff = target->z - actor->z;
|
||||
aim = atan (diff / (double)P_AproxDistance (actor->x - target->x, actor->y - target->y));
|
||||
actor->pitch = -(int)(aim * ANGLE_180/M_PI);
|
||||
diff = target->z - player->mo->z;
|
||||
aim = atan (diff / (double)P_AproxDistance (player->mo->x - target->x, player->mo->y - target->y));
|
||||
player->mo->pitch = -(int)(aim * ANGLE_180/M_PI);
|
||||
}
|
||||
|
||||
//Checks if a sector is dangerous.
|
||||
|
@ -388,4 +371,3 @@ bool FCajunMaster::IsDangerous (sector_t *sec)
|
|||
|| special == Damage_InstantDeath
|
||||
|| special == sDamage_SuperHellslime;
|
||||
}
|
||||
|
||||
|
|
284
src/b_think.cpp
284
src/b_think.cpp
|
@ -24,47 +24,49 @@ static FRandom pr_botmove ("BotMove");
|
|||
|
||||
//This function is called each tic for each bot,
|
||||
//so this is what the bot does.
|
||||
void FCajunMaster::Think (AActor *actor, ticcmd_t *cmd)
|
||||
void DBot::Think ()
|
||||
{
|
||||
ticcmd_t *cmd = &netcmds[player - players][((gametic + 1)/ticdup)%BACKUPTICS];
|
||||
|
||||
memset (cmd, 0, sizeof(*cmd));
|
||||
|
||||
if (actor->player->enemy && actor->player->enemy->health <= 0)
|
||||
actor->player->enemy = NULL;
|
||||
if (enemy && enemy->health <= 0)
|
||||
enemy = NULL;
|
||||
|
||||
if (actor->health > 0) //Still alive
|
||||
if (player->mo->health > 0) //Still alive
|
||||
{
|
||||
if (teamplay || !deathmatch)
|
||||
actor->player->mate = Choose_Mate (actor);
|
||||
mate = Choose_Mate ();
|
||||
|
||||
angle_t oldyaw = actor->angle;
|
||||
int oldpitch = actor->pitch;
|
||||
angle_t oldyaw = player->mo->angle;
|
||||
int oldpitch = player->mo->pitch;
|
||||
|
||||
Set_enemy (actor);
|
||||
ThinkForMove (actor, cmd);
|
||||
TurnToAng (actor);
|
||||
Set_enemy ();
|
||||
ThinkForMove (cmd);
|
||||
TurnToAng ();
|
||||
|
||||
cmd->ucmd.yaw = (short)((actor->angle - oldyaw) >> 16) / ticdup;
|
||||
cmd->ucmd.pitch = (short)((oldpitch - actor->pitch) >> 16);
|
||||
cmd->ucmd.yaw = (short)((player->mo->angle - oldyaw) >> 16) / ticdup;
|
||||
cmd->ucmd.pitch = (short)((oldpitch - player->mo->pitch) >> 16);
|
||||
if (cmd->ucmd.pitch == -32768)
|
||||
cmd->ucmd.pitch = -32767;
|
||||
cmd->ucmd.pitch /= ticdup;
|
||||
actor->angle = oldyaw + (cmd->ucmd.yaw << 16) * ticdup;
|
||||
actor->pitch = oldpitch - (cmd->ucmd.pitch << 16) * ticdup;
|
||||
player->mo->angle = oldyaw + (cmd->ucmd.yaw << 16) * ticdup;
|
||||
player->mo->pitch = oldpitch - (cmd->ucmd.pitch << 16) * ticdup;
|
||||
}
|
||||
|
||||
if (actor->player->t_active) actor->player->t_active--;
|
||||
if (actor->player->t_strafe) actor->player->t_strafe--;
|
||||
if (actor->player->t_react) actor->player->t_react--;
|
||||
if (actor->player->t_fight) actor->player->t_fight--;
|
||||
if (actor->player->t_rocket) actor->player->t_rocket--;
|
||||
if (actor->player->t_roam) actor->player->t_roam--;
|
||||
if (t_active) t_active--;
|
||||
if (t_strafe) t_strafe--;
|
||||
if (t_react) t_react--;
|
||||
if (t_fight) t_fight--;
|
||||
if (t_rocket) t_rocket--;
|
||||
if (t_roam) t_roam--;
|
||||
|
||||
//Respawn ticker
|
||||
if (actor->player->t_respawn)
|
||||
if (t_respawn)
|
||||
{
|
||||
actor->player->t_respawn--;
|
||||
t_respawn--;
|
||||
}
|
||||
else if (actor->health <= 0)
|
||||
else if (player->mo->health <= 0)
|
||||
{ // Time to respawn
|
||||
cmd->ucmd.buttons |= BT_USE;
|
||||
}
|
||||
|
@ -72,62 +74,57 @@ void FCajunMaster::Think (AActor *actor, ticcmd_t *cmd)
|
|||
|
||||
//how the bot moves.
|
||||
//MAIN movement function.
|
||||
void FCajunMaster::ThinkForMove (AActor *actor, ticcmd_t *cmd)
|
||||
void DBot::ThinkForMove (ticcmd_t *cmd)
|
||||
{
|
||||
player_t *b;
|
||||
fixed_t dist;
|
||||
bool stuck;
|
||||
int r;
|
||||
|
||||
b = actor->player;
|
||||
if (!b->isbot)
|
||||
return;
|
||||
|
||||
stuck = false;
|
||||
dist = b->dest ? P_AproxDistance(actor->x-b->dest->x, actor->y-b->dest->y) : 0;
|
||||
dist = dest ? P_AproxDistance(player->mo->x-dest->x, player->mo->y-dest->y) : 0;
|
||||
|
||||
if (b->missile &&
|
||||
((!b->missile->velx || !b->missile->vely) || !Check_LOS(actor, b->missile, SHOOTFOV*3/2)))
|
||||
if (missile &&
|
||||
((!missile->velx || !missile->vely) || !Check_LOS(missile, SHOOTFOV*3/2)))
|
||||
{
|
||||
b->sleft = !b->sleft;
|
||||
b->missile = NULL; //Probably ended its travel.
|
||||
sleft = !sleft;
|
||||
missile = NULL; //Probably ended its travel.
|
||||
}
|
||||
|
||||
if (actor->pitch > 0)
|
||||
actor->pitch -= 80;
|
||||
else if (actor->pitch <= -60)
|
||||
actor->pitch += 80;
|
||||
if (player->mo->pitch > 0)
|
||||
player->mo->pitch -= 80;
|
||||
else if (player->mo->pitch <= -60)
|
||||
player->mo->pitch += 80;
|
||||
|
||||
//HOW TO MOVE:
|
||||
if (b->missile && (P_AproxDistance(actor->x-b->missile->x, actor->y-b->missile->y)<AVOID_DIST)) //try avoid missile got from P_Mobj.c thinking part.
|
||||
if (missile && (P_AproxDistance(player->mo->x-missile->x, player->mo->y-missile->y)<AVOID_DIST)) //try avoid missile got from P_Mobj.c thinking part.
|
||||
{
|
||||
Pitch (actor, b->missile);
|
||||
actor->player->angle = R_PointToAngle2(actor->x, actor->y, b->missile->x, b->missile->y);
|
||||
cmd->ucmd.sidemove = b->sleft ? -SIDERUN : SIDERUN;
|
||||
Pitch (missile);
|
||||
angle = R_PointToAngle2(player->mo->x, player->mo->y, missile->x, missile->y);
|
||||
cmd->ucmd.sidemove = sleft ? -SIDERUN : SIDERUN;
|
||||
cmd->ucmd.forwardmove = -FORWARDRUN; //Back IS best.
|
||||
|
||||
if ((P_AproxDistance(actor->x-b->oldx, actor->y-b->oldy)<50000)
|
||||
&& b->t_strafe<=0)
|
||||
if ((P_AproxDistance(player->mo->x-oldx, player->mo->y-oldy)<50000)
|
||||
&& t_strafe<=0)
|
||||
{
|
||||
b->t_strafe = 5;
|
||||
b->sleft = !b->sleft;
|
||||
t_strafe = 5;
|
||||
sleft = !sleft;
|
||||
}
|
||||
|
||||
//If able to see enemy while avoiding missile, still fire at enemy.
|
||||
if (b->enemy && Check_LOS (actor, b->enemy, SHOOTFOV))
|
||||
Dofire (actor, cmd); //Order bot to fire current weapon
|
||||
if (enemy && Check_LOS (enemy, SHOOTFOV))
|
||||
Dofire (cmd); //Order bot to fire current weapon
|
||||
}
|
||||
else if (b->enemy && P_CheckSight (actor, b->enemy, 0)) //Fight!
|
||||
else if (enemy && P_CheckSight (player->mo, enemy, 0)) //Fight!
|
||||
{
|
||||
Pitch (actor, b->enemy);
|
||||
Pitch (enemy);
|
||||
|
||||
//Check if it's more important to get an item than fight.
|
||||
if (b->dest && (b->dest->flags&MF_SPECIAL)) //Must be an item, that is close enough.
|
||||
if (dest && (dest->flags&MF_SPECIAL)) //Must be an item, that is close enough.
|
||||
{
|
||||
#define is(x) b->dest->IsKindOf (PClass::FindClass (#x))
|
||||
#define is(x) dest->IsKindOf (PClass::FindClass (#x))
|
||||
if (
|
||||
(
|
||||
(actor->health < b->skill.isp &&
|
||||
(player->mo->health < skill.isp &&
|
||||
(is (Medikit) ||
|
||||
is (Stimpack) ||
|
||||
is (Soulsphere) ||
|
||||
|
@ -140,78 +137,78 @@ void FCajunMaster::ThinkForMove (AActor *actor, ticcmd_t *cmd)
|
|||
is (Megasphere)
|
||||
) ||
|
||||
dist < (GETINCOMBAT/4) ||
|
||||
(b->ReadyWeapon == NULL || b->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON)
|
||||
(player->ReadyWeapon == NULL || player->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON)
|
||||
)
|
||||
&& (dist < GETINCOMBAT || (b->ReadyWeapon == NULL || b->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON))
|
||||
&& Reachable (actor, b->dest))
|
||||
&& (dist < GETINCOMBAT || (player->ReadyWeapon == NULL || player->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON))
|
||||
&& Reachable (dest))
|
||||
#undef is
|
||||
{
|
||||
goto roam; //Pick it up, no matter the situation. All bonuses are nice close up.
|
||||
}
|
||||
}
|
||||
|
||||
b->dest = NULL; //To let bot turn right
|
||||
dest = NULL; //To let bot turn right
|
||||
|
||||
if (b->ReadyWeapon != NULL && !(b->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON))
|
||||
actor->flags &= ~MF_DROPOFF; //Don't jump off any ledges when fighting.
|
||||
if (player->ReadyWeapon != NULL && !(player->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON))
|
||||
player->mo->flags &= ~MF_DROPOFF; //Don't jump off any ledges when fighting.
|
||||
|
||||
if (!(b->enemy->flags3 & MF3_ISMONSTER))
|
||||
b->t_fight = AFTERTICS;
|
||||
if (!(enemy->flags3 & MF3_ISMONSTER))
|
||||
t_fight = AFTERTICS;
|
||||
|
||||
if (b->t_strafe <= 0 &&
|
||||
(P_AproxDistance(actor->x-b->oldx, actor->y-b->oldy)<50000
|
||||
if (t_strafe <= 0 &&
|
||||
(P_AproxDistance(player->mo->x-oldx, player->mo->y-oldy)<50000
|
||||
|| ((pr_botmove()%30)==10))
|
||||
)
|
||||
{
|
||||
stuck = true;
|
||||
b->t_strafe = 5;
|
||||
b->sleft = !b->sleft;
|
||||
t_strafe = 5;
|
||||
sleft = !sleft;
|
||||
}
|
||||
|
||||
b->angle = R_PointToAngle2(actor->x, actor->y, b->enemy->x, b->enemy->y);
|
||||
angle = R_PointToAngle2(player->mo->x, player->mo->y, enemy->x, enemy->y);
|
||||
|
||||
if (b->ReadyWeapon == NULL ||
|
||||
P_AproxDistance(actor->x-b->enemy->x, actor->y-b->enemy->y) >
|
||||
b->ReadyWeapon->MoveCombatDist)
|
||||
if (player->ReadyWeapon == NULL ||
|
||||
P_AproxDistance(player->mo->x-enemy->x, player->mo->y-enemy->y) >
|
||||
player->ReadyWeapon->MoveCombatDist)
|
||||
{
|
||||
// If a monster, use lower speed (just for cooler apperance while strafing down doomed monster)
|
||||
cmd->ucmd.forwardmove = (b->enemy->flags3 & MF3_ISMONSTER) ? FORWARDWALK : FORWARDRUN;
|
||||
cmd->ucmd.forwardmove = (enemy->flags3 & MF3_ISMONSTER) ? FORWARDWALK : FORWARDRUN;
|
||||
}
|
||||
else if (!stuck) //Too close, so move away.
|
||||
{
|
||||
// If a monster, use lower speed (just for cooler apperance while strafing down doomed monster)
|
||||
cmd->ucmd.forwardmove = (b->enemy->flags3 & MF3_ISMONSTER) ? -FORWARDWALK : -FORWARDRUN;
|
||||
cmd->ucmd.forwardmove = (enemy->flags3 & MF3_ISMONSTER) ? -FORWARDWALK : -FORWARDRUN;
|
||||
}
|
||||
|
||||
//Strafing.
|
||||
if (b->enemy->flags3 & MF3_ISMONSTER) //It's just a monster so take it down cool.
|
||||
if (enemy->flags3 & MF3_ISMONSTER) //It's just a monster so take it down cool.
|
||||
{
|
||||
cmd->ucmd.sidemove = b->sleft ? -SIDEWALK : SIDEWALK;
|
||||
cmd->ucmd.sidemove = sleft ? -SIDEWALK : SIDEWALK;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd->ucmd.sidemove = b->sleft ? -SIDERUN : SIDERUN;
|
||||
cmd->ucmd.sidemove = sleft ? -SIDERUN : SIDERUN;
|
||||
}
|
||||
Dofire (actor, cmd); //Order bot to fire current weapon
|
||||
Dofire (cmd); //Order bot to fire current weapon
|
||||
}
|
||||
else if (b->mate && !b->enemy && (!b->dest || b->dest==b->mate)) //Follow mate move.
|
||||
else if (mate && !enemy && (!dest || dest==mate)) //Follow mate move.
|
||||
{
|
||||
fixed_t matedist;
|
||||
|
||||
Pitch (actor, b->mate);
|
||||
Pitch (mate);
|
||||
|
||||
if (!Reachable (actor, b->mate))
|
||||
if (!Reachable (mate))
|
||||
{
|
||||
if (b->mate == b->dest && pr_botmove.Random() < 32)
|
||||
if (mate == dest && pr_botmove.Random() < 32)
|
||||
{ // [RH] If the mate is the dest, pick a new dest sometimes
|
||||
b->dest = NULL;
|
||||
dest = NULL;
|
||||
}
|
||||
goto roam;
|
||||
}
|
||||
|
||||
actor->player->angle = R_PointToAngle2(actor->x, actor->y, b->mate->x, b->mate->y);
|
||||
angle = R_PointToAngle2(player->mo->x, player->mo->y, mate->x, mate->y);
|
||||
|
||||
matedist = P_AproxDistance(actor->x - b->mate->x, actor->y - b->mate->y);
|
||||
matedist = P_AproxDistance(player->mo->x - mate->x, player->mo->y - mate->y);
|
||||
if (matedist > (FRIEND_DIST*2))
|
||||
cmd->ucmd.forwardmove = FORWARDRUN;
|
||||
else if (matedist > FRIEND_DIST)
|
||||
|
@ -221,42 +218,42 @@ void FCajunMaster::ThinkForMove (AActor *actor, ticcmd_t *cmd)
|
|||
}
|
||||
else //Roam after something.
|
||||
{
|
||||
b->first_shot = true;
|
||||
first_shot = true;
|
||||
|
||||
/////
|
||||
roam:
|
||||
/////
|
||||
if (b->enemy && Check_LOS (actor, b->enemy, SHOOTFOV*3/2)) //If able to see enemy while avoiding missile , still fire at it.
|
||||
Dofire (actor, cmd); //Order bot to fire current weapon
|
||||
if (enemy && Check_LOS (enemy, SHOOTFOV*3/2)) //If able to see enemy while avoiding missile , still fire at it.
|
||||
Dofire (cmd); //Order bot to fire current weapon
|
||||
|
||||
if (b->dest && !(b->dest->flags&MF_SPECIAL) && b->dest->health < 0)
|
||||
if (dest && !(dest->flags&MF_SPECIAL) && dest->health < 0)
|
||||
{ //Roaming after something dead.
|
||||
b->dest = NULL;
|
||||
dest = NULL;
|
||||
}
|
||||
|
||||
if (b->dest == NULL)
|
||||
if (dest == NULL)
|
||||
{
|
||||
if (b->t_fight && b->enemy) //Enemy/bot has jumped around corner. So what to do?
|
||||
if (t_fight && enemy) //Enemy/bot has jumped around corner. So what to do?
|
||||
{
|
||||
if (b->enemy->player)
|
||||
if (enemy->player)
|
||||
{
|
||||
if (((b->enemy->player->ReadyWeapon != NULL && b->enemy->player->ReadyWeapon->WeaponFlags & WIF_BOT_EXPLOSIVE) ||
|
||||
(pr_botmove()%100)>b->skill.isp) && b->ReadyWeapon != NULL && !(b->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON))
|
||||
b->dest = b->enemy;//Dont let enemy kill the bot by supressive fire. So charge enemy.
|
||||
else //hide while b->t_fight, but keep view at enemy.
|
||||
b->angle = R_PointToAngle2(actor->x, actor->y, b->enemy->x, b->enemy->y);
|
||||
if (((enemy->player->ReadyWeapon != NULL && enemy->player->ReadyWeapon->WeaponFlags & WIF_BOT_EXPLOSIVE) ||
|
||||
(pr_botmove()%100)>skill.isp) && player->ReadyWeapon != NULL && !(player->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON))
|
||||
dest = enemy;//Dont let enemy kill the bot by supressive fire. So charge enemy.
|
||||
else //hide while t_fight, but keep view at enemy.
|
||||
angle = R_PointToAngle2(player->mo->x, player->mo->y, enemy->x, enemy->y);
|
||||
} //Just a monster, so kill it.
|
||||
else
|
||||
b->dest = b->enemy;
|
||||
dest = enemy;
|
||||
|
||||
//VerifFavoritWeapon(actor->player); //Dont know why here.., but it must be here, i know the reason, but not why at this spot, uh.
|
||||
//VerifFavoritWeapon(player); //Dont know why here.., but it must be here, i know the reason, but not why at this spot, uh.
|
||||
}
|
||||
else //Choose a distant target. to get things going.
|
||||
{
|
||||
r = pr_botmove();
|
||||
if (r < 128)
|
||||
{
|
||||
TThinkerIterator<AInventory> it (STAT_INVENTORY, firstthing);
|
||||
TThinkerIterator<AInventory> it (STAT_INVENTORY, bglobal.firstthing);
|
||||
AInventory *item = it.Next();
|
||||
|
||||
if (item != NULL || (item = it.Next()) != NULL)
|
||||
|
@ -271,60 +268,53 @@ void FCajunMaster::ThinkForMove (AActor *actor, ticcmd_t *cmd)
|
|||
{
|
||||
item = it.Next();
|
||||
}
|
||||
firstthing = item;
|
||||
b->dest = item;
|
||||
bglobal.firstthing = item;
|
||||
dest = item;
|
||||
}
|
||||
}
|
||||
else if (b->mate && (r < 179 || P_CheckSight(actor, b->mate)))
|
||||
else if (mate && (r < 179 || P_CheckSight(player->mo, mate)))
|
||||
{
|
||||
b->dest = b->mate;
|
||||
dest = mate;
|
||||
}
|
||||
else if ((playeringame[(r&(MAXPLAYERS-1))]) && players[(r&(MAXPLAYERS-1))].mo->health > 0)
|
||||
{
|
||||
b->dest = players[(r&(MAXPLAYERS-1))].mo;
|
||||
dest = players[(r&(MAXPLAYERS-1))].mo;
|
||||
}
|
||||
}
|
||||
|
||||
if (b->dest)
|
||||
if (dest)
|
||||
{
|
||||
b->t_roam = MAXROAM;
|
||||
t_roam = MAXROAM;
|
||||
}
|
||||
}
|
||||
if (b->dest)
|
||||
if (dest)
|
||||
{ //Bot has a target so roam after it.
|
||||
Roam (actor, cmd);
|
||||
Roam (cmd);
|
||||
}
|
||||
|
||||
} //End of movement main part.
|
||||
|
||||
if (!b->t_roam && b->dest)
|
||||
if (!t_roam && dest)
|
||||
{
|
||||
b->prev = b->dest;
|
||||
b->dest = NULL;
|
||||
prev = dest;
|
||||
dest = NULL;
|
||||
}
|
||||
|
||||
if (b->t_fight<(AFTERTICS/2))
|
||||
actor->flags |= MF_DROPOFF;
|
||||
if (t_fight<(AFTERTICS/2))
|
||||
player->mo->flags |= MF_DROPOFF;
|
||||
|
||||
b->oldx = actor->x;
|
||||
b->oldy = actor->y;
|
||||
oldx = player->mo->x;
|
||||
oldy = player->mo->y;
|
||||
}
|
||||
|
||||
//BOT_WhatToGet
|
||||
//
|
||||
//Determines if the bot will roam after an item or not.
|
||||
void FCajunMaster::WhatToGet (AActor *actor, AActor *item)
|
||||
void DBot::WhatToGet (AActor *item)
|
||||
{
|
||||
player_t *b = actor->player;
|
||||
|
||||
if (b == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#define typeis(x) item->IsKindOf (PClass::FindClass (#x))
|
||||
if ((item->renderflags & RF_INVISIBLE) //Under respawn and away.
|
||||
|| item == b->prev)
|
||||
|| item == prev)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -338,7 +328,7 @@ void FCajunMaster::WhatToGet (AActor *actor, AActor *item)
|
|||
// FIXME
|
||||
AWeapon *heldWeapon;
|
||||
|
||||
heldWeapon = static_cast<AWeapon *> (b->mo->FindInventory (item->GetClass()));
|
||||
heldWeapon = static_cast<AWeapon *> (player->mo->FindInventory (item->GetClass()));
|
||||
if (heldWeapon != NULL)
|
||||
{
|
||||
if (!weapgiveammo)
|
||||
|
@ -354,39 +344,38 @@ void FCajunMaster::WhatToGet (AActor *actor, AActor *item)
|
|||
{
|
||||
AAmmo *ammo = static_cast<AAmmo *> (item);
|
||||
const PClass *parent = ammo->GetParentAmmo ();
|
||||
AInventory *holdingammo = b->mo->FindInventory (parent);
|
||||
AInventory *holdingammo = player->mo->FindInventory (parent);
|
||||
|
||||
if (holdingammo != NULL && holdingammo->Amount >= holdingammo->MaxAmount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if ((typeis (Megasphere) || typeis (Soulsphere) || typeis (HealthBonus)) && actor->health >= deh.MaxSoulsphere)
|
||||
else if ((typeis (Megasphere) || typeis (Soulsphere) || typeis (HealthBonus)) && player->mo->health >= deh.MaxSoulsphere)
|
||||
return;
|
||||
else if (item->IsKindOf (RUNTIME_CLASS(AHealth)) && actor->health >= deh.MaxHealth /*MAXHEALTH*/)
|
||||
else if (item->IsKindOf (RUNTIME_CLASS(AHealth)) && player->mo->health >= deh.MaxHealth /*MAXHEALTH*/)
|
||||
return;
|
||||
|
||||
if ((b->dest == NULL ||
|
||||
!(b->dest->flags & MF_SPECIAL)/* ||
|
||||
!Reachable (actor, b->dest)*/)/* &&
|
||||
Reachable (actor, item)*/) // Calling Reachable slows this down tremendously
|
||||
if ((dest == NULL ||
|
||||
!(dest->flags & MF_SPECIAL)/* ||
|
||||
!Reachable (dest)*/)/* &&
|
||||
Reachable (item)*/) // Calling Reachable slows this down tremendously
|
||||
{
|
||||
b->prev = b->dest;
|
||||
b->dest = item;
|
||||
b->t_roam = MAXROAM;
|
||||
prev = dest;
|
||||
dest = item;
|
||||
t_roam = MAXROAM;
|
||||
}
|
||||
}
|
||||
|
||||
void FCajunMaster::Set_enemy (AActor *actor)
|
||||
void DBot::Set_enemy ()
|
||||
{
|
||||
AActor *oldenemy;
|
||||
AActor **enemy = &actor->player->enemy;
|
||||
|
||||
if (*enemy
|
||||
&& (*enemy)->health > 0
|
||||
&& P_CheckSight (actor, *enemy))
|
||||
if (enemy
|
||||
&& enemy->health > 0
|
||||
&& P_CheckSight (player->mo, enemy))
|
||||
{
|
||||
oldenemy = *enemy;
|
||||
oldenemy = enemy;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -395,15 +384,14 @@ void FCajunMaster::Set_enemy (AActor *actor)
|
|||
|
||||
// [RH] Don't even bother looking for a different enemy if this is not deathmatch
|
||||
// and we already have an existing enemy.
|
||||
if (deathmatch || !*enemy)
|
||||
if (deathmatch || !enemy)
|
||||
{
|
||||
actor->player->allround = !!*enemy;
|
||||
*enemy = NULL;
|
||||
*enemy = Find_enemy(actor);
|
||||
if (!*enemy)
|
||||
*enemy = oldenemy; //Try go for last (it will be NULL if there wasn't anyone)
|
||||
allround = !!enemy;
|
||||
enemy = Find_enemy();
|
||||
if (!enemy)
|
||||
enemy = oldenemy; //Try go for last (it will be NULL if there wasn't anyone)
|
||||
}
|
||||
//Verify that that enemy is really something alive that bot can kill.
|
||||
if (*enemy && (((*enemy)->health < 0 || !((*enemy)->flags&MF_SHOOTABLE)) || actor->IsFriend(*enemy)))
|
||||
*enemy = NULL;
|
||||
if (enemy && ((enemy->health < 0 || !(enemy->flags&MF_SHOOTABLE)) || player->mo->IsFriend(enemy)))
|
||||
enemy = NULL;
|
||||
}
|
||||
|
|
|
@ -230,7 +230,11 @@ const char *KeyNames[NUM_KEYS] =
|
|||
NULL, NULL, NULL, NULL, NULL, "pause", NULL, "home", //C0
|
||||
"uparrow", "pgup", NULL, "leftarrow",NULL, "rightarrow",NULL, "end", //C8
|
||||
"downarrow","pgdn", "ins", "del", NULL, NULL, NULL, NULL, //D0
|
||||
#ifdef __APPLE__
|
||||
NULL, NULL, NULL, "command", NULL, "apps", "power", "sleep", //D8
|
||||
#else // !__APPLE__
|
||||
NULL, NULL, NULL, "lwin", "rwin", "apps", "power", "sleep", //D8
|
||||
#endif // __APPLE__
|
||||
NULL, NULL, NULL, "wake", NULL, "search", "favorites","refresh", //E0
|
||||
"webstop", "webforward","webback", "mycomputer","mail", "mediaselect",NULL, NULL, //E8
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, //F0
|
||||
|
|
|
@ -124,6 +124,15 @@ CCMD (god)
|
|||
Net_WriteByte (CHT_GOD);
|
||||
}
|
||||
|
||||
CCMD(god2)
|
||||
{
|
||||
if (CheckCheatmode())
|
||||
return;
|
||||
|
||||
Net_WriteByte(DEM_GENERICCHEAT);
|
||||
Net_WriteByte(CHT_GOD2);
|
||||
}
|
||||
|
||||
CCMD (iddqd)
|
||||
{
|
||||
if (CheckCheatmode ())
|
||||
|
@ -142,6 +151,15 @@ CCMD (buddha)
|
|||
Net_WriteByte(CHT_BUDDHA);
|
||||
}
|
||||
|
||||
CCMD(buddha2)
|
||||
{
|
||||
if (CheckCheatmode())
|
||||
return;
|
||||
|
||||
Net_WriteByte(DEM_GENERICCHEAT);
|
||||
Net_WriteByte(CHT_BUDDHA2);
|
||||
}
|
||||
|
||||
CCMD (notarget)
|
||||
{
|
||||
if (CheckCheatmode ())
|
||||
|
|
|
@ -561,6 +561,11 @@ int PrintString (int printlevel, const char *outline)
|
|||
maybedrawnow (false, false);
|
||||
}
|
||||
}
|
||||
else if (Logfile != NULL)
|
||||
{
|
||||
fputs (outline, Logfile);
|
||||
fflush (Logfile);
|
||||
}
|
||||
return (int)strlen (outline);
|
||||
}
|
||||
|
||||
|
@ -1421,7 +1426,11 @@ static bool C_HandleKey (event_t *ev, BYTE *buffer, int len)
|
|||
case 'V':
|
||||
TabbedLast = false;
|
||||
TabbedList = false;
|
||||
#ifdef __APPLE__
|
||||
if (ev->data3 & GKM_META)
|
||||
#else // !__APPLE__
|
||||
if (ev->data3 & GKM_CTRL)
|
||||
#endif // __APPLE__
|
||||
{
|
||||
if (data1 == 'C')
|
||||
{ // copy to clipboard
|
||||
|
@ -1545,13 +1554,6 @@ void C_MidPrint (FFont *font, const char *msg)
|
|||
AddToConsole (-1, bar1);
|
||||
AddToConsole (-1, msg);
|
||||
AddToConsole (-1, bar3);
|
||||
if (Logfile)
|
||||
{
|
||||
fputs (logbar, Logfile);
|
||||
fputs (msg, Logfile);
|
||||
fputs (logbar, Logfile);
|
||||
fflush (Logfile);
|
||||
}
|
||||
|
||||
StatusBar->AttachMessage (new DHUDMessage (font, msg, 1.5f, 0.375f, 0, 0,
|
||||
(EColorRange)PrintColors[PRINTLEVELS], con_midtime), MAKE_ID('C','N','T','R'));
|
||||
|
@ -1569,13 +1571,6 @@ void C_MidPrintBold (FFont *font, const char *msg)
|
|||
AddToConsole (-1, bar2);
|
||||
AddToConsole (-1, msg);
|
||||
AddToConsole (-1, bar3);
|
||||
if (Logfile)
|
||||
{
|
||||
fputs (logbar, Logfile);
|
||||
fputs (msg, Logfile);
|
||||
fputs (logbar, Logfile);
|
||||
fflush (Logfile);
|
||||
}
|
||||
|
||||
StatusBar->AttachMessage (new DHUDMessage (font, msg, 1.5f, 0.375f, 0, 0,
|
||||
(EColorRange)PrintColors[PRINTLEVELS+1], con_midtime), MAKE_ID('C','N','T','R'));
|
||||
|
|
|
@ -500,9 +500,10 @@ UCVarValue FBaseCVar::FromString (const char *value, ECVarType type)
|
|||
goodv = false;
|
||||
break;
|
||||
default:
|
||||
if (value[i] < '0' && value[i] > '9' &&
|
||||
value[i] < 'A' && value[i] > 'F' &&
|
||||
value[i] < 'a' && value[i] > 'f')
|
||||
if (value[i] < '0' ||
|
||||
(value[i] > '9' && value[i] < 'A') ||
|
||||
(value[i] > 'F' && value[i] < 'a') ||
|
||||
value[i] > 'f')
|
||||
{
|
||||
goodv = false;
|
||||
}
|
||||
|
@ -1514,6 +1515,22 @@ void UnlatchCVars (void)
|
|||
}
|
||||
}
|
||||
|
||||
void DestroyCVarsFlagged (DWORD flags)
|
||||
{
|
||||
FBaseCVar *cvar = CVars;
|
||||
FBaseCVar *next = cvar;
|
||||
|
||||
while(cvar)
|
||||
{
|
||||
next = cvar->m_Next;
|
||||
|
||||
if(cvar->Flags & flags)
|
||||
delete cvar;
|
||||
|
||||
cvar = next;
|
||||
}
|
||||
}
|
||||
|
||||
void C_SetCVarsToDefaults (void)
|
||||
{
|
||||
FBaseCVar *cvar = CVars;
|
||||
|
|
|
@ -159,6 +159,7 @@ private:
|
|||
friend FBaseCVar *FindCVar (const char *var_name, FBaseCVar **prev);
|
||||
friend FBaseCVar *FindCVarSub (const char *var_name, int namelen);
|
||||
friend void UnlatchCVars (void);
|
||||
friend void DestroyCVarsFlagged (DWORD flags);
|
||||
friend void C_ArchiveCVars (FConfigFile *f, uint32 filter);
|
||||
friend void C_SetCVarsToDefaults (void);
|
||||
friend void FilterCompactCVars (TArray<FBaseCVar *> &cvars, uint32 filter);
|
||||
|
@ -190,6 +191,9 @@ FBaseCVar *C_CreateCVar(const char *var_name, ECVarType var_type, DWORD flags);
|
|||
// Called from G_InitNew()
|
||||
void UnlatchCVars (void);
|
||||
|
||||
// Destroy CVars with the matching flags; called from CCMD(restart)
|
||||
void DestroyCVarsFlagged (DWORD flags);
|
||||
|
||||
// archive cvars to FILE f
|
||||
void C_ArchiveCVars (FConfigFile *f, uint32 filter);
|
||||
|
||||
|
|
|
@ -723,7 +723,7 @@ void AddCommandString (char *cmd, int keynum)
|
|||
// Note that deferred commands lose track of which key
|
||||
// (if any) they were pressed from.
|
||||
*brkpt = ';';
|
||||
new DWaitingCommand (brkpt, tics+1);
|
||||
new DWaitingCommand (brkpt, tics);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
23
src/cmdlib.h
23
src/cmdlib.h
|
@ -5,6 +5,8 @@
|
|||
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "doomdef.h"
|
||||
#include "m_fixed.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -62,4 +64,25 @@ struct FFileList
|
|||
|
||||
void ScanDirectory(TArray<FFileList> &list, const char *dirpath);
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Functions to compensate for a tic being a bit short.
|
||||
// Since ZDoom uses a milliseconds timer for game timing
|
||||
// 35 tics are actually only 0.98 seconds.
|
||||
// For real time display this needs to be adjusted
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
inline int AdjustTics(int tics)
|
||||
{
|
||||
return Scale(tics, 98, 100);
|
||||
}
|
||||
|
||||
inline int Tics2Seconds(int tics)
|
||||
{
|
||||
return Scale(tics, 98, (100 * TICRATE));
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
926
src/cocoa/HID_Config_Utilities.c
Normal file
926
src/cocoa/HID_Config_Utilities.c
Normal file
|
@ -0,0 +1,926 @@
|
|||
// File: HID_Config_Utilities.c
|
||||
// Abstract: Implementation of the HID configuration utilities
|
||||
// Version: 2.0
|
||||
//
|
||||
// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
// Inc. ("Apple") in consideration of your agreement to the following
|
||||
// terms, and your use, installation, modification or redistribution of
|
||||
// this Apple software constitutes acceptance of these terms. If you do
|
||||
// not agree with these terms, please do not use, install, modify or
|
||||
// redistribute this Apple software.
|
||||
//
|
||||
// In consideration of your agreement to abide by the following terms, and
|
||||
// subject to these terms, Apple grants you a personal, non-exclusive
|
||||
// license, under Apple's copyrights in this original Apple software (the
|
||||
// "Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
// Software, with or without modifications, in source and/or binary forms;
|
||||
// provided that if you redistribute the Apple Software in its entirety and
|
||||
// without modifications, you must retain this notice and the following
|
||||
// text and disclaimers in all such redistributions of the Apple Software.
|
||||
// Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
// be used to endorse or promote products derived from the Apple Software
|
||||
// without specific prior written permission from Apple. Except as
|
||||
// expressly stated in this notice, no other rights or licenses, express or
|
||||
// implied, are granted by Apple herein, including but not limited to any
|
||||
// patent rights that may be infringed by your derivative works or by other
|
||||
// works in which the Apple Software may be incorporated.
|
||||
//
|
||||
// The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
//
|
||||
// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (C) 2009 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
//*****************************************************
|
||||
|
||||
#include <AvailabilityMacros.h>
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
|
||||
|
||||
#define LOG_SCORING 0
|
||||
|
||||
#include <stdlib.h> // malloc
|
||||
#include <time.h> // clock
|
||||
|
||||
#include <AssertMacros.h>
|
||||
|
||||
#include "HID_Utilities_External.h"
|
||||
|
||||
// ---------------------------------
|
||||
|
||||
// polls single device's elements for a change greater than kPercentMove. Times out after given time
|
||||
// returns 1 and pointer to element if found
|
||||
// returns 0 and NULL for both parameters if not found
|
||||
|
||||
unsigned char HIDConfigureSingleDeviceAction(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef *outIOHIDElementRef, float timeout) {
|
||||
if ( !inIOHIDDeviceRef ) {
|
||||
return (0);
|
||||
}
|
||||
if ( 0 == HIDHaveDeviceList() ) { // if we do not have a device list
|
||||
return (0); // return 0
|
||||
}
|
||||
|
||||
Boolean found = FALSE;
|
||||
|
||||
// build list of device and elements to save current values
|
||||
int maxElements = HIDCountDeviceElements(inIOHIDDeviceRef, kHIDElementTypeInput);
|
||||
int *saveValueArray = (int *) calloc( maxElements, sizeof(int) ); // 2D array to save values
|
||||
|
||||
// store initial values on first pass / compare to initial value on subsequent passes
|
||||
Boolean first = TRUE;
|
||||
|
||||
// get all the elements from this device
|
||||
CFArrayRef elementCFArrayRef = IOHIDDeviceCopyMatchingElements(inIOHIDDeviceRef, NULL, kIOHIDOptionsTypeNone);
|
||||
// if that worked...
|
||||
if ( elementCFArrayRef ) {
|
||||
clock_t start = clock(), end;
|
||||
|
||||
// poll all devices and elements
|
||||
while ( !found ) {
|
||||
int currElementIndex = 0;
|
||||
CFIndex idx, cnt = CFArrayGetCount(elementCFArrayRef);
|
||||
for ( idx = 0; idx < cnt; idx++ ) {
|
||||
*outIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(elementCFArrayRef, idx);
|
||||
if ( !*outIOHIDElementRef ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// is this an input element?
|
||||
IOHIDElementType type = IOHIDElementGetType(*outIOHIDElementRef);
|
||||
|
||||
switch ( type ) {
|
||||
// these types are inputs
|
||||
case kIOHIDElementTypeInput_Misc:
|
||||
case kIOHIDElementTypeInput_Button:
|
||||
case kIOHIDElementTypeInput_Axis:
|
||||
case kIOHIDElementTypeInput_ScanCodes:
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case kIOHIDElementTypeOutput:
|
||||
case kIOHIDElementTypeFeature:
|
||||
case kIOHIDElementTypeCollection:
|
||||
{
|
||||
*outIOHIDElementRef = NULL; // these types are not ( Skip them )
|
||||
break;
|
||||
}
|
||||
} /* switch */
|
||||
if ( !*outIOHIDElementRef ) {
|
||||
continue; // skip this element
|
||||
}
|
||||
|
||||
// get this elements current value
|
||||
int value = 0; // default value is zero
|
||||
IOHIDValueRef tIOHIDValueRef;
|
||||
IOReturn ioReturn = IOHIDDeviceGetValue(inIOHIDDeviceRef, *outIOHIDElementRef, &tIOHIDValueRef);
|
||||
if ( kIOReturnSuccess == ioReturn ) {
|
||||
value = IOHIDValueGetScaledValue(tIOHIDValueRef, kIOHIDValueScaleTypePhysical);
|
||||
}
|
||||
if ( first ) {
|
||||
saveValueArray[currElementIndex] = value;
|
||||
} else {
|
||||
CFIndex min = IOHIDElementGetLogicalMin(*outIOHIDElementRef);
|
||||
CFIndex max = IOHIDElementGetLogicalMax(*outIOHIDElementRef);
|
||||
|
||||
int initialValue = saveValueArray[currElementIndex];
|
||||
int delta = (float)(max - min) * kPercentMove * 0.01;
|
||||
// is the new value within +/- delta of the initial value?
|
||||
if ( ( (initialValue + delta) < value ) || ( (initialValue - delta) > value ) ) {
|
||||
found = 1; // ( yes! ) mark as found
|
||||
break;
|
||||
}
|
||||
} // if ( first )
|
||||
|
||||
currElementIndex++; // bump element index
|
||||
} // next idx
|
||||
|
||||
first = FALSE; // no longer the first pass
|
||||
|
||||
// are we done?
|
||||
end = clock();
|
||||
double secs = (double)(end - start) / CLOCKS_PER_SEC;
|
||||
if ( secs > timeout ) {
|
||||
break; // ( yes ) timeout
|
||||
}
|
||||
} // while ( !found )
|
||||
|
||||
CFRelease(elementCFArrayRef);
|
||||
} // if ( elementCFArrayRef )
|
||||
// return device and element moved
|
||||
if ( found ) {
|
||||
return (1);
|
||||
} else {
|
||||
*outIOHIDElementRef = NULL;
|
||||
return (0);
|
||||
}
|
||||
} // HIDConfigureSingleDeviceAction
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// HIDConfigureAction( outIOHIDDeviceRef, outIOHIDElementRef, inTimeout )
|
||||
//
|
||||
// Purpose: polls all devices and elements for a change greater than kPercentMove.
|
||||
// Times out after given time returns 1 and pointer to device and element
|
||||
// if found; returns 0 and NULL for both parameters if not found
|
||||
//
|
||||
// Inputs: outIOHIDDeviceRef - address where to store the device
|
||||
// outIOHIDElementRef - address where to store the element
|
||||
// inTimeout - the timeout
|
||||
// Returns: Boolean - if successful
|
||||
// outIOHIDDeviceRef - the device
|
||||
// outIOHIDElementRef - the element
|
||||
//
|
||||
|
||||
Boolean HIDConfigureAction(IOHIDDeviceRef *outIOHIDDeviceRef, IOHIDElementRef *outIOHIDElementRef, float inTimeout) {
|
||||
// param error?
|
||||
if ( !outIOHIDDeviceRef || !outIOHIDElementRef ) {
|
||||
return (0);
|
||||
}
|
||||
if ( !gDeviceCFArrayRef ) { // if we do not have a device list
|
||||
// and we can't build another list
|
||||
if ( !HIDBuildDeviceList(0, 0) || !gDeviceCFArrayRef ) {
|
||||
return (FALSE); // bail
|
||||
}
|
||||
}
|
||||
|
||||
IOHIDDeviceRef tIOHIDDeviceRef;
|
||||
IOHIDElementRef tIOHIDElementRef;
|
||||
|
||||
// remember when we start; used to calculate timeout
|
||||
clock_t start = clock(), end;
|
||||
|
||||
// determine the maximum number of elements
|
||||
CFIndex maxElements = 0;
|
||||
CFIndex devIndex, devCount = CFArrayGetCount(gDeviceCFArrayRef);
|
||||
for ( devIndex = 0; devIndex < devCount; devIndex++ ) {
|
||||
tIOHIDDeviceRef = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef, devIndex);
|
||||
if ( !tIOHIDDeviceRef ) {
|
||||
continue; // skip this one
|
||||
}
|
||||
|
||||
CFIndex count = HIDCountDeviceElements(tIOHIDDeviceRef, kHIDElementTypeInput);
|
||||
if ( count > maxElements ) {
|
||||
maxElements = count;
|
||||
}
|
||||
}
|
||||
|
||||
// allocate an array of int's in which to store devCount * maxElements values
|
||||
double *saveValueArray = (double *) calloc( devCount * maxElements, sizeof(double) ); // clear 2D array to save values
|
||||
|
||||
// on first pass store initial values / compare current values to initial values on subsequent passes
|
||||
Boolean found = FALSE, first = TRUE;
|
||||
|
||||
while ( !found ) {
|
||||
double maxDeltaPercent = 0; // we want to find the one that moves the most ( percentage wise )
|
||||
for ( devIndex = 0; devIndex < devCount; devIndex++ ) {
|
||||
tIOHIDDeviceRef = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef, devIndex);
|
||||
if ( !tIOHIDDeviceRef ) {
|
||||
continue; // skip this one
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
long vendorID = IOHIDDevice_GetVendorID(tIOHIDDeviceRef);
|
||||
long productID = IOHIDDevice_GetProductID(tIOHIDDeviceRef);
|
||||
#endif
|
||||
gElementCFArrayRef = IOHIDDeviceCopyMatchingElements(tIOHIDDeviceRef, NULL, kIOHIDOptionsTypeNone);
|
||||
if ( gElementCFArrayRef ) {
|
||||
CFIndex eleIndex, eleCount = CFArrayGetCount(gElementCFArrayRef);
|
||||
for ( eleIndex = 0; eleIndex < eleCount; eleIndex++ ) {
|
||||
tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(gElementCFArrayRef, eleIndex);
|
||||
if ( !tIOHIDElementRef ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
IOHIDElementType tIOHIDElementType = IOHIDElementGetType(tIOHIDElementRef);
|
||||
// only care about inputs (no outputs or features)
|
||||
if ( tIOHIDElementType <= kIOHIDElementTypeInput_ScanCodes ) {
|
||||
if ( IOHIDElementIsArray(tIOHIDElementRef) ) {
|
||||
//printf( "ARRAY!\n" );
|
||||
continue; // skip array elements
|
||||
}
|
||||
|
||||
uint32_t usagePage = IOHIDElementGetUsagePage(tIOHIDElementRef);
|
||||
uint32_t usage = IOHIDElementGetUsage(tIOHIDElementRef);
|
||||
uint32_t reportCount = IOHIDElementGetReportCount(tIOHIDElementRef);
|
||||
#ifdef DEBUG
|
||||
if ( first ) {
|
||||
IOHIDElementCookie cookie = IOHIDElementGetCookie(tIOHIDElementRef);
|
||||
printf("%s, dev: {ref:%p, ven: 0x%08lX, pro: 0x%08lX}, ele: {ref:%p, cookie: %p, usage:%04lX:%08lX}\n",
|
||||
__PRETTY_FUNCTION__,
|
||||
tIOHIDDeviceRef,
|
||||
vendorID,
|
||||
productID,
|
||||
tIOHIDElementRef,
|
||||
cookie,
|
||||
(long unsigned int) usagePage,
|
||||
(long unsigned int) usage);
|
||||
fflush(stdout);
|
||||
if ( (0x054C == vendorID) && (0x0268 == productID) && (0x001E == (UInt32) cookie) ) {
|
||||
//printf( "DING!\n" );
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#if 1 // work-around for IOHIDValueGetScaledValue crash (when element report count > 1)
|
||||
if ( reportCount > 1 ) {
|
||||
//printf( "REPORT!\n" );
|
||||
continue; // skip reports
|
||||
}
|
||||
|
||||
#endif
|
||||
// ignore PID elements and arrays
|
||||
if ( (kHIDPage_PID != usagePage) && (((uint32_t)-1) != usage) ) {
|
||||
// get this elements current value
|
||||
double value = 0.0; // default value is zero
|
||||
IOHIDValueRef tIOHIDValueRef;
|
||||
IOReturn ioReturn = IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &tIOHIDValueRef);
|
||||
if ( kIOReturnSuccess == ioReturn ) {
|
||||
value = IOHIDValueGetScaledValue(tIOHIDValueRef, kIOHIDValueScaleTypePhysical);
|
||||
}
|
||||
if ( first ) {
|
||||
saveValueArray[(devIndex * maxElements) + eleIndex] = value;
|
||||
} else {
|
||||
double initialValue = saveValueArray[(devIndex * maxElements) + eleIndex];
|
||||
|
||||
CFIndex valueMin = IOHIDElementGetPhysicalMin(tIOHIDElementRef);
|
||||
CFIndex valueMax = IOHIDElementGetPhysicalMax(tIOHIDElementRef);
|
||||
|
||||
double deltaPercent = fabs( (initialValue - value) * 100.0 / (valueMax - valueMin) );
|
||||
#if 0 // debug code useful to dump out value info for specific (vendorID, productID, usagePage and usage) device
|
||||
if ( !first ) {
|
||||
// Device: 0x13b6a0 = { Logitech Inc. - WingMan Force 3D, vendorID: 0x046D, productID: 0xC283,
|
||||
// usage: 0x0001:0x0004, "Generic Desktop Joystick"
|
||||
if ( (vendorID == 0x046D) && (productID == 0xC283) ) {
|
||||
if ( (kHIDPage_GenericDesktop == usagePage) && (kHIDUsage_GD_Rz == usage) ) {
|
||||
printf("initial: %6.2f, value: %6.2f, diff: %6.2f, delta percent: %6.2f!\n",
|
||||
initialValue,
|
||||
value,
|
||||
fabs(initialValue - value),
|
||||
deltaPercent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deltaPercent = 0.0;
|
||||
#endif
|
||||
if ( deltaPercent >= kPercentMove ) {
|
||||
found = TRUE;
|
||||
if ( deltaPercent > maxDeltaPercent ) {
|
||||
maxDeltaPercent = deltaPercent;
|
||||
|
||||
*outIOHIDDeviceRef = tIOHIDDeviceRef;
|
||||
*outIOHIDElementRef = tIOHIDElementRef;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
} // if first
|
||||
|
||||
} // if usage
|
||||
|
||||
} // if type
|
||||
|
||||
} // for elements...
|
||||
|
||||
CFRelease(gElementCFArrayRef);
|
||||
gElementCFArrayRef = NULL;
|
||||
} // if ( gElementCFArrayRef )
|
||||
if ( found ) {
|
||||
// HIDDumpElementInfo( tIOHIDElementRef );
|
||||
break; // DONE!
|
||||
}
|
||||
} // for devices
|
||||
|
||||
first = FALSE; // no longer the first pass
|
||||
|
||||
// are we done?
|
||||
end = clock();
|
||||
double secs = (double)(end - start) / CLOCKS_PER_SEC;
|
||||
if ( secs > inTimeout ) {
|
||||
break; // ( yes ) timeout
|
||||
}
|
||||
} // while ( !found )
|
||||
// return device and element moved
|
||||
if ( !found ) {
|
||||
*outIOHIDDeviceRef = NULL;
|
||||
*outIOHIDElementRef = NULL;
|
||||
}
|
||||
|
||||
return (found);
|
||||
} // HIDConfigureAction
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// HIDSaveElementPref( inKeyCFStringRef, inAppCFStringRef, inIOHIDDeviceRef, inIOHIDElementRef )
|
||||
//
|
||||
// Purpose: Save the device & element values into the specified key in the specified applications preferences
|
||||
//
|
||||
// Inputs: inKeyCFStringRef - the preference key
|
||||
// inAppCFStringRef - the application identifier
|
||||
// inIOHIDDeviceRef - the device
|
||||
// inIOHIDElementRef - the element
|
||||
// Returns: Boolean - if successful
|
||||
//
|
||||
|
||||
Boolean HIDSaveElementPref(const CFStringRef inKeyCFStringRef,
|
||||
CFStringRef inAppCFStringRef,
|
||||
IOHIDDeviceRef inIOHIDDeviceRef,
|
||||
IOHIDElementRef inIOHIDElementRef) {
|
||||
Boolean success = FALSE;
|
||||
if ( inKeyCFStringRef && inAppCFStringRef && inIOHIDDeviceRef && inIOHIDElementRef ) {
|
||||
long vendorID = IOHIDDevice_GetVendorID(inIOHIDDeviceRef);
|
||||
require(vendorID, Oops);
|
||||
|
||||
long productID = IOHIDDevice_GetProductID(inIOHIDDeviceRef);
|
||||
require(productID, Oops);
|
||||
|
||||
long locID = IOHIDDevice_GetLocationID(inIOHIDDeviceRef);
|
||||
require(locID, Oops);
|
||||
|
||||
uint32_t usagePage = IOHIDDevice_GetUsagePage(inIOHIDDeviceRef);
|
||||
uint32_t usage = IOHIDDevice_GetUsage(inIOHIDDeviceRef);
|
||||
if ( !usagePage || !usage ) {
|
||||
usagePage = IOHIDDevice_GetPrimaryUsagePage(inIOHIDDeviceRef);
|
||||
usage = IOHIDDevice_GetPrimaryUsage(inIOHIDDeviceRef);
|
||||
}
|
||||
|
||||
require(usagePage && usage, Oops);
|
||||
|
||||
uint32_t usagePageE = IOHIDElementGetUsagePage(inIOHIDElementRef);
|
||||
uint32_t usageE = IOHIDElementGetUsage(inIOHIDElementRef);
|
||||
IOHIDElementCookie eleCookie = IOHIDElementGetCookie(inIOHIDElementRef);
|
||||
|
||||
CFStringRef prefCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
|
||||
CFSTR("d:{v:%ld, p:%ld, l:%ld, p:%ld, u:%ld}, e:{p:%ld, u:%ld, c:%ld}"),
|
||||
vendorID, productID, locID, usagePage, usage,
|
||||
usagePageE, usageE, eleCookie);
|
||||
if ( prefCFStringRef ) {
|
||||
CFPreferencesSetAppValue(inKeyCFStringRef, prefCFStringRef, inAppCFStringRef);
|
||||
CFRelease(prefCFStringRef);
|
||||
success = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
Oops: ;
|
||||
return (success);
|
||||
} // HIDSaveElementPref
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// HIDRestoreElementPref( inKeyCFStringRef, inAppCFStringRef, outIOHIDDeviceRef, outIOHIDElementRef )
|
||||
//
|
||||
// Purpose: Find the specified preference in the specified application
|
||||
//
|
||||
// Inputs: inKeyCFStringRef - the preference key
|
||||
// inAppCFStringRef - the application identifier
|
||||
// outIOHIDDeviceRef - address where to restore the device
|
||||
// outIOHIDElementRef - address where to restore the element
|
||||
// Returns: Boolean - if successful
|
||||
// outIOHIDDeviceRef - the device
|
||||
// outIOHIDElementRef - the element
|
||||
//
|
||||
|
||||
Boolean HIDRestoreElementPref(CFStringRef inKeyCFStringRef,
|
||||
CFStringRef inAppCFStringRef,
|
||||
IOHIDDeviceRef * outIOHIDDeviceRef,
|
||||
IOHIDElementRef *outIOHIDElementRef) {
|
||||
Boolean found = FALSE;
|
||||
if ( inKeyCFStringRef && inAppCFStringRef && outIOHIDDeviceRef && outIOHIDElementRef ) {
|
||||
CFPropertyListRef prefCFPropertyListRef = CFPreferencesCopyAppValue(inKeyCFStringRef, inAppCFStringRef);
|
||||
if ( prefCFPropertyListRef ) {
|
||||
if ( CFStringGetTypeID() == CFGetTypeID(prefCFPropertyListRef) ) {
|
||||
char buffer[256];
|
||||
if ( CFStringGetCString( (CFStringRef) prefCFPropertyListRef, buffer, sizeof(buffer),
|
||||
kCFStringEncodingUTF8 ) )
|
||||
{
|
||||
HID_info_rec searchHIDInfo;
|
||||
|
||||
int count = sscanf(buffer,
|
||||
"d:{v:%d, p:%d, l:%d, p:%d, u:%d}, e:{p:%d, u:%d, c:%ld}",
|
||||
&searchHIDInfo.device.vendorID,
|
||||
&searchHIDInfo.device.productID,
|
||||
&searchHIDInfo.device.locID,
|
||||
&searchHIDInfo.device.usagePage,
|
||||
&searchHIDInfo.device.usage,
|
||||
&searchHIDInfo.element.usagePage,
|
||||
&searchHIDInfo.element.usage,
|
||||
(long *) &searchHIDInfo.element.cookie);
|
||||
if ( 8 == count ) { // if we found all eight parameters…
|
||||
// and can find a device & element that matches these…
|
||||
if ( HIDFindDeviceAndElement(&searchHIDInfo, outIOHIDDeviceRef, outIOHIDElementRef) ) {
|
||||
found = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We found the entry with this key but it's the wrong type; delete it.
|
||||
CFPreferencesSetAppValue(inKeyCFStringRef, NULL, inAppCFStringRef);
|
||||
(void) CFPreferencesAppSynchronize(inAppCFStringRef);
|
||||
}
|
||||
|
||||
CFRelease(prefCFPropertyListRef);
|
||||
}
|
||||
}
|
||||
|
||||
return (found);
|
||||
} // HIDRestoreElementPref
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// HIDFindDeviceAndElement( inSearchInfo, outFoundDevice, outFoundElement )
|
||||
//
|
||||
// Purpose: find the closest matching device and element for this action
|
||||
//
|
||||
// Notes: matches device: serial, vendorID, productID, location, inUsagePage, usage
|
||||
// matches element: cookie, inUsagePage, usage,
|
||||
//
|
||||
// Inputs: inSearchInfo - the device & element info we searching for
|
||||
// outFoundDevice - the address of the best matching device
|
||||
// outFoundElement - the address of the best matching element
|
||||
//
|
||||
// Returns: Boolean - TRUE if we find a match
|
||||
// outFoundDevice - the best matching device
|
||||
// outFoundElement - the best matching element
|
||||
//
|
||||
|
||||
Boolean HIDFindDeviceAndElement(const HID_info_rec *inSearchInfo, IOHIDDeviceRef *outFoundDevice, IOHIDElementRef *outFoundElement) {
|
||||
Boolean result = FALSE;
|
||||
|
||||
IOHIDDeviceRef bestIOHIDDeviceRef = NULL;
|
||||
IOHIDElementRef bestIOHIDElementRef = NULL;
|
||||
long bestScore = 0;
|
||||
|
||||
CFIndex devIndex, devCount = CFArrayGetCount(gDeviceCFArrayRef);
|
||||
for ( devIndex = 0; devIndex < devCount; devIndex++ ) {
|
||||
long deviceScore = 1;
|
||||
|
||||
IOHIDDeviceRef tIOHIDDeviceRef = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef, devIndex);
|
||||
if ( !tIOHIDDeviceRef ) {
|
||||
continue;
|
||||
}
|
||||
// match vendorID, productID (+10, +8)
|
||||
if ( inSearchInfo->device.vendorID ) {
|
||||
long vendorID = IOHIDDevice_GetVendorID(tIOHIDDeviceRef);
|
||||
if ( vendorID ) {
|
||||
if ( inSearchInfo->device.vendorID == vendorID ) {
|
||||
deviceScore += 10;
|
||||
if ( inSearchInfo->device.productID ) {
|
||||
long productID = IOHIDDevice_GetProductID(tIOHIDDeviceRef);
|
||||
if ( productID ) {
|
||||
if ( inSearchInfo->device.productID == productID ) {
|
||||
deviceScore += 8;
|
||||
} // if ( inSearchInfo->device.productID == productID )
|
||||
|
||||
} // if ( productID )
|
||||
|
||||
} // if ( inSearchInfo->device.productID )
|
||||
|
||||
} // if (inSearchInfo->device.vendorID == vendorID)
|
||||
|
||||
} // if vendorID
|
||||
|
||||
} // if search->device.vendorID
|
||||
// match usagePage & usage (+9)
|
||||
if ( inSearchInfo->device.usagePage && inSearchInfo->device.usage ) {
|
||||
uint32_t usagePage = IOHIDDevice_GetUsagePage(tIOHIDDeviceRef) ;
|
||||
uint32_t usage = IOHIDDevice_GetUsage(tIOHIDDeviceRef);
|
||||
if ( !usagePage || !usage ) {
|
||||
usagePage = IOHIDDevice_GetPrimaryUsagePage(tIOHIDDeviceRef);
|
||||
usage = IOHIDDevice_GetPrimaryUsage(tIOHIDDeviceRef);
|
||||
}
|
||||
if ( usagePage ) {
|
||||
if ( inSearchInfo->device.usagePage == usagePage ) {
|
||||
if ( usage ) {
|
||||
if ( inSearchInfo->device.usage == usage ) {
|
||||
deviceScore += 9;
|
||||
} // if ( inSearchInfo->usage == usage )
|
||||
|
||||
} // if ( usage )
|
||||
|
||||
} // if ( inSearchInfo->usagePage == usagePage )
|
||||
|
||||
} // if ( usagePage )
|
||||
|
||||
} // if ( inSearchInfo->usagePage && inSearchInfo->usage )
|
||||
// match location ID (+5)
|
||||
if ( inSearchInfo->device.locID ) {
|
||||
long locID = IOHIDDevice_GetLocationID(tIOHIDDeviceRef);
|
||||
if ( locID ) {
|
||||
if ( inSearchInfo->device.locID == locID ) {
|
||||
deviceScore += 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// iterate over all elements of this device
|
||||
gElementCFArrayRef = IOHIDDeviceCopyMatchingElements(tIOHIDDeviceRef, NULL, 0);
|
||||
if ( gElementCFArrayRef ) {
|
||||
CFIndex eleIndex, eleCount = CFArrayGetCount(gElementCFArrayRef);
|
||||
for ( eleIndex = 0; eleIndex < eleCount; eleIndex++ ) {
|
||||
IOHIDElementRef tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(gElementCFArrayRef, eleIndex);
|
||||
if ( !tIOHIDElementRef ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
long score = deviceScore;
|
||||
// match usage page, usage & cookie
|
||||
if ( inSearchInfo->element.usagePage && inSearchInfo->element.usage ) {
|
||||
uint32_t usagePage = IOHIDElementGetUsagePage(tIOHIDElementRef);
|
||||
if ( inSearchInfo->element.usagePage == usagePage ) {
|
||||
uint32_t usage = IOHIDElementGetUsage(tIOHIDElementRef);
|
||||
if ( inSearchInfo->element.usage == usage ) {
|
||||
score += 5;
|
||||
IOHIDElementCookie cookie = IOHIDElementGetCookie(tIOHIDElementRef);
|
||||
if ( inSearchInfo->element.cookie == cookie ) {
|
||||
score += 4;
|
||||
} // cookies match
|
||||
|
||||
} else {
|
||||
score = 0;
|
||||
} // usages match
|
||||
|
||||
} else {
|
||||
score = 0;
|
||||
} // usage pages match
|
||||
|
||||
} // if ( search usage page & usage )
|
||||
|
||||
#if LOG_SCORING
|
||||
if ( kHIDPage_KeyboardOrKeypad != tElementRef->usagePage ) { // skip keyboards here
|
||||
printf("%s: ( %ld:%ld )-I-Debug, score: %ld\t",
|
||||
__PRETTY_FUNCTION__,
|
||||
inSearchInfo->element.usagePage,
|
||||
inSearchInfo->element.usage,
|
||||
score);
|
||||
HIDPrintElement(tIOHIDElementRef);
|
||||
}
|
||||
|
||||
#endif // LOG_SCORING
|
||||
if ( score > bestScore ) {
|
||||
bestIOHIDDeviceRef = tIOHIDDeviceRef;
|
||||
bestIOHIDElementRef = tIOHIDElementRef;
|
||||
bestScore = score;
|
||||
#if LOG_SCORING
|
||||
printf("%s: ( %ld:%ld )-I-Debug, better score: %ld\t",
|
||||
__PRETTY_FUNCTION__,
|
||||
inSearchInfo->element.usagePage,
|
||||
inSearchInfo->element.usage,
|
||||
score);
|
||||
HIDPrintElement(bestIOHIDElementRef);
|
||||
#endif // LOG_SCORING
|
||||
}
|
||||
} // for elements...
|
||||
|
||||
CFRelease(gElementCFArrayRef);
|
||||
gElementCFArrayRef = NULL;
|
||||
} // if ( gElementCFArrayRef )
|
||||
|
||||
} // for ( devIndex = 0; devIndex < devCount; devIndex++ )
|
||||
if ( bestIOHIDDeviceRef || bestIOHIDElementRef ) {
|
||||
*outFoundDevice = bestIOHIDDeviceRef;
|
||||
*outFoundElement = bestIOHIDElementRef;
|
||||
#if LOG_SCORING
|
||||
printf("%s: ( %ld:%ld )-I-Debug, best score: %ld\t",
|
||||
__PRETTY_FUNCTION__,
|
||||
inSearchInfo->element.usagePage,
|
||||
inSearchInfo->element.usage,
|
||||
bestScore);
|
||||
HIDPrintElement(bestIOHIDElementRef);
|
||||
#endif // LOG_SCORING
|
||||
result = TRUE;
|
||||
}
|
||||
|
||||
return (result);
|
||||
} // HIDFindDeviceAndElement
|
||||
|
||||
// ---------------------------------
|
||||
|
||||
// takes input records, save required info
|
||||
// assume file is open and at correct position.
|
||||
// will always write to file (if file exists) size of HID_info_rec, even if device and or element is bad
|
||||
|
||||
void HIDSaveElementConfig(FILE *fileRef, IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHIDElementRef, int actionCookie) {
|
||||
// must save:
|
||||
// actionCookie
|
||||
// Device: serial,vendorID, productID, location, usagePage, usage
|
||||
// Element: cookie, usagePage, usage,
|
||||
HID_info_rec hidInfoRec;
|
||||
HIDSetElementConfig(&hidInfoRec, inIOHIDDeviceRef, inIOHIDElementRef, actionCookie);
|
||||
// write to file
|
||||
if ( fileRef ) {
|
||||
fwrite( (void *)&hidInfoRec, sizeof(HID_info_rec), 1, fileRef );
|
||||
}
|
||||
} // HIDSaveElementConfig
|
||||
|
||||
// ---------------------------------
|
||||
|
||||
// take file, read one record (assume file position is correct and file is open)
|
||||
// search for matching device
|
||||
// return pDevice, pElement and cookie for action
|
||||
|
||||
int HIDRestoreElementConfig(FILE *fileRef, IOHIDDeviceRef *outIOHIDDeviceRef, IOHIDElementRef *outIOHIDElementRef) {
|
||||
// Device: serial,vendorID, productID, location, usagePage, usage
|
||||
// Element: cookie, usagePage, usage,
|
||||
|
||||
HID_info_rec hidInfoRec;
|
||||
fread( (void *) &hidInfoRec, 1, sizeof(HID_info_rec), fileRef );
|
||||
return ( HIDGetElementConfig(&hidInfoRec, outIOHIDDeviceRef, outIOHIDElementRef) );
|
||||
} // HIDRestoreElementConfig
|
||||
|
||||
// ---------------------------------
|
||||
|
||||
// Set up a config record for saving
|
||||
// takes an input records, returns record user can save as they want
|
||||
// Note: the save rec must be pre-allocated by the calling app and will be filled out
|
||||
void HIDSetElementConfig(HID_info_ptr inHIDInfoPtr,
|
||||
IOHIDDeviceRef inIOHIDDeviceRef,
|
||||
IOHIDElementRef inIOHIDElementRef,
|
||||
int actionCookie) {
|
||||
// must save:
|
||||
// actionCookie
|
||||
// Device: serial,vendorID, productID, location, usagePage, usage
|
||||
// Element: cookie, usagePage, usage,
|
||||
inHIDInfoPtr->actionCookie = actionCookie;
|
||||
// device
|
||||
// need to add serial number when I have a test case
|
||||
if ( inIOHIDDeviceRef && inIOHIDElementRef ) {
|
||||
inHIDInfoPtr->device.vendorID = IOHIDDevice_GetVendorID(inIOHIDDeviceRef);
|
||||
inHIDInfoPtr->device.productID = IOHIDDevice_GetProductID(inIOHIDDeviceRef);
|
||||
inHIDInfoPtr->device.locID = IOHIDDevice_GetLocationID(inIOHIDDeviceRef);
|
||||
inHIDInfoPtr->device.usage = IOHIDDevice_GetUsage(inIOHIDDeviceRef);
|
||||
inHIDInfoPtr->device.usagePage = IOHIDDevice_GetUsagePage(inIOHIDDeviceRef);
|
||||
|
||||
inHIDInfoPtr->element.usagePage = IOHIDElementGetUsagePage(inIOHIDElementRef);
|
||||
inHIDInfoPtr->element.usage = IOHIDElementGetUsage(inIOHIDElementRef);
|
||||
inHIDInfoPtr->element.minReport = IOHIDElement_GetCalibrationSaturationMin(inIOHIDElementRef);
|
||||
inHIDInfoPtr->element.maxReport = IOHIDElement_GetCalibrationSaturationMax(inIOHIDElementRef);
|
||||
inHIDInfoPtr->element.cookie = IOHIDElementGetCookie(inIOHIDElementRef);
|
||||
} else {
|
||||
inHIDInfoPtr->device.vendorID = 0;
|
||||
inHIDInfoPtr->device.productID = 0;
|
||||
inHIDInfoPtr->device.locID = 0;
|
||||
inHIDInfoPtr->device.usage = 0;
|
||||
inHIDInfoPtr->device.usagePage = 0;
|
||||
|
||||
inHIDInfoPtr->element.usagePage = 0;
|
||||
inHIDInfoPtr->element.usage = 0;
|
||||
inHIDInfoPtr->element.minReport = 0;
|
||||
inHIDInfoPtr->element.maxReport = 0;
|
||||
inHIDInfoPtr->element.cookie = 0;
|
||||
}
|
||||
} // HIDSetElementConfig
|
||||
|
||||
// ---------------------------------
|
||||
#if 0 // debug utility function to dump config record
|
||||
void HIDDumpConfig(HID_info_ptr inHIDInfoPtr) {
|
||||
printf(
|
||||
"Config Record for action: %d\n\t vendor: %d product: %d location: %d\n\t usage: %d usagePage: %d\n\t element.usagePage: %d element.usage: %d\n\t minReport: %d maxReport: %d\n\t cookie: %d\n",
|
||||
inHIDInfoPtr->actionCookie,
|
||||
inHIDInfoPtr->device.vendorID,
|
||||
inHIDInfoPtr->device.productID,
|
||||
inHIDInfoPtr->locID,
|
||||
inHIDInfoPtr->usage,
|
||||
inHIDInfoPtr->usagePage,
|
||||
inHIDInfoPtr->element.usagePage,
|
||||
inHIDInfoPtr->element.usage,
|
||||
inHIDInfoPtr->minReport,
|
||||
inHIDInfoPtr->maxReport,
|
||||
inHIDInfoPtr->cookie);
|
||||
} // HIDDumpConfig
|
||||
#endif // 0
|
||||
// ---------------------------------
|
||||
|
||||
// Get matching element from config record
|
||||
// takes a pre-allocated and filled out config record
|
||||
// search for matching device
|
||||
// return pDevice, pElement and cookie for action
|
||||
int HIDGetElementConfig(HID_info_ptr inHIDInfoPtr, IOHIDDeviceRef *outIOHIDDeviceRef, IOHIDElementRef *outIOHIDElementRef) {
|
||||
if ( !inHIDInfoPtr->device.locID && !inHIDInfoPtr->device.vendorID && !inHIDInfoPtr->device.productID && !inHIDInfoPtr->device.usage
|
||||
&& !inHIDInfoPtr->device.usagePage ) //
|
||||
{ //
|
||||
// early out
|
||||
*outIOHIDDeviceRef = NULL;
|
||||
*outIOHIDElementRef = NULL;
|
||||
return (inHIDInfoPtr->actionCookie);
|
||||
}
|
||||
|
||||
IOHIDDeviceRef tIOHIDDeviceRef, foundIOHIDDeviceRef = NULL;
|
||||
IOHIDElementRef tIOHIDElementRef, foundIOHIDElementRef = NULL;
|
||||
|
||||
CFIndex devIdx, devCnt, idx, cnt;
|
||||
// compare to current device list for matches
|
||||
// look for device
|
||||
if ( inHIDInfoPtr->device.locID && inHIDInfoPtr->device.vendorID && inHIDInfoPtr->device.productID ) { // look for specific device
|
||||
// type plug in to same port
|
||||
devCnt = CFArrayGetCount(gDeviceCFArrayRef);
|
||||
for ( devIdx = 0; devIdx < devCnt; devIdx++ ) {
|
||||
tIOHIDDeviceRef = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef, devIdx);
|
||||
if ( !tIOHIDDeviceRef ) {
|
||||
continue; // skip this device
|
||||
}
|
||||
|
||||
long locID = IOHIDDevice_GetLocationID(tIOHIDDeviceRef);
|
||||
long vendorID = IOHIDDevice_GetVendorID(tIOHIDDeviceRef);
|
||||
long productID = IOHIDDevice_GetProductID(tIOHIDDeviceRef);
|
||||
if ( (inHIDInfoPtr->device.locID == locID)
|
||||
&& (inHIDInfoPtr->device.vendorID == vendorID)
|
||||
&& (inHIDInfoPtr->device.productID == productID) )
|
||||
{
|
||||
foundIOHIDDeviceRef = tIOHIDDeviceRef;
|
||||
}
|
||||
if ( foundIOHIDDeviceRef ) {
|
||||
break;
|
||||
}
|
||||
} // next devIdx
|
||||
if ( foundIOHIDDeviceRef ) {
|
||||
CFArrayRef elementCFArrayRef = IOHIDDeviceCopyMatchingElements(foundIOHIDDeviceRef, NULL, kIOHIDOptionsTypeNone);
|
||||
if ( elementCFArrayRef ) {
|
||||
cnt = CFArrayGetCount(elementCFArrayRef);
|
||||
for ( idx = 0; idx < cnt; idx++ ) {
|
||||
tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(elementCFArrayRef, idx);
|
||||
if ( !tIOHIDElementRef ) {
|
||||
continue; // skip this element
|
||||
}
|
||||
|
||||
IOHIDElementCookie cookie = IOHIDElementGetCookie(tIOHIDElementRef);
|
||||
if ( inHIDInfoPtr->element.cookie == cookie ) {
|
||||
foundIOHIDElementRef = tIOHIDElementRef;
|
||||
}
|
||||
if ( foundIOHIDElementRef ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !foundIOHIDElementRef ) {
|
||||
cnt = CFArrayGetCount(elementCFArrayRef);
|
||||
for ( idx = 0; idx < cnt; idx++ ) {
|
||||
tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(elementCFArrayRef, idx);
|
||||
if ( !tIOHIDElementRef ) {
|
||||
continue; // skip this element
|
||||
}
|
||||
|
||||
uint32_t usagePage = IOHIDElementGetUsagePage(tIOHIDElementRef);
|
||||
uint32_t usage = IOHIDElementGetUsage(tIOHIDElementRef);
|
||||
if ( (inHIDInfoPtr->element.usage == usage) && (inHIDInfoPtr->element.usagePage == usagePage) ) {
|
||||
foundIOHIDElementRef = tIOHIDElementRef;
|
||||
}
|
||||
if ( foundIOHIDElementRef ) {
|
||||
break;
|
||||
}
|
||||
} // next idx
|
||||
|
||||
} // if ( !foundIOHIDElementRef )
|
||||
if ( foundIOHIDElementRef ) { // if same device
|
||||
// setup the calibration
|
||||
IOHIDElement_SetupCalibration(tIOHIDElementRef);
|
||||
|
||||
IOHIDElement_SetCalibrationSaturationMin(tIOHIDElementRef, inHIDInfoPtr->element.minReport);
|
||||
IOHIDElement_SetCalibrationSaturationMax(tIOHIDElementRef, inHIDInfoPtr->element.maxReport);
|
||||
}
|
||||
|
||||
CFRelease(elementCFArrayRef);
|
||||
} // if ( elementCFArrayRef )
|
||||
|
||||
} // if ( foundIOHIDDeviceRef )
|
||||
// if we have not found a match, look at just vendor and product
|
||||
if ( (!foundIOHIDDeviceRef) && (inHIDInfoPtr->device.vendorID && inHIDInfoPtr->device.productID) ) {
|
||||
devCnt = CFArrayGetCount(gDeviceCFArrayRef);
|
||||
for ( devIdx = 0; devIdx < devCnt; devIdx++ ) {
|
||||
tIOHIDDeviceRef = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef, devIdx);
|
||||
if ( !tIOHIDDeviceRef ) {
|
||||
continue; // skip this device
|
||||
}
|
||||
|
||||
long vendorID = IOHIDDevice_GetVendorID(tIOHIDDeviceRef);
|
||||
long productID = IOHIDDevice_GetProductID(tIOHIDDeviceRef);
|
||||
if ( (inHIDInfoPtr->device.vendorID == vendorID)
|
||||
&& (inHIDInfoPtr->device.productID == productID) )
|
||||
{
|
||||
foundIOHIDDeviceRef = tIOHIDDeviceRef;
|
||||
}
|
||||
if ( foundIOHIDDeviceRef ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// match elements by cookie since same device type
|
||||
if ( foundIOHIDDeviceRef ) {
|
||||
CFArrayRef elementCFArrayRef = IOHIDDeviceCopyMatchingElements(foundIOHIDDeviceRef, NULL, kIOHIDOptionsTypeNone);
|
||||
if ( elementCFArrayRef ) {
|
||||
cnt = CFArrayGetCount(elementCFArrayRef);
|
||||
for ( idx = 0; idx < cnt; idx++ ) {
|
||||
tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(elementCFArrayRef, idx);
|
||||
if ( !tIOHIDElementRef ) {
|
||||
continue; // skip this element
|
||||
}
|
||||
|
||||
IOHIDElementCookie cookie = IOHIDElementGetCookie(tIOHIDElementRef);
|
||||
if ( inHIDInfoPtr->element.cookie == cookie ) {
|
||||
foundIOHIDElementRef = tIOHIDElementRef;
|
||||
}
|
||||
if ( foundIOHIDElementRef ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if no cookie match (should NOT occur) match on usage
|
||||
if ( !foundIOHIDElementRef ) {
|
||||
cnt = CFArrayGetCount(elementCFArrayRef);
|
||||
for ( idx = 0; idx < cnt; idx++ ) {
|
||||
tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(elementCFArrayRef, idx);
|
||||
if ( !tIOHIDElementRef ) {
|
||||
continue; // skip this element
|
||||
}
|
||||
|
||||
uint32_t usagePage = IOHIDElementGetUsagePage(tIOHIDElementRef);
|
||||
uint32_t usage = IOHIDElementGetUsage(tIOHIDElementRef);
|
||||
if ( (inHIDInfoPtr->element.usage == usage)
|
||||
&& (inHIDInfoPtr->element.usagePage == usagePage) )
|
||||
{
|
||||
foundIOHIDElementRef = tIOHIDElementRef;
|
||||
}
|
||||
if ( foundIOHIDElementRef ) {
|
||||
break;
|
||||
}
|
||||
} // next idx
|
||||
|
||||
} // if ( !foundIOHIDElementRef )
|
||||
if ( foundIOHIDElementRef ) { // if same device
|
||||
// setup the calibration
|
||||
IOHIDElement_SetupCalibration(tIOHIDElementRef);
|
||||
IOHIDElement_SetCalibrationSaturationMin(tIOHIDElementRef, inHIDInfoPtr->element.minReport);
|
||||
IOHIDElement_SetCalibrationSaturationMax(tIOHIDElementRef, inHIDInfoPtr->element.maxReport);
|
||||
}
|
||||
|
||||
CFRelease(elementCFArrayRef);
|
||||
} // if ( elementCFArrayRef )
|
||||
|
||||
} // if ( foundIOHIDDeviceRef )
|
||||
|
||||
} // if ( device not found & vendorID & productID )
|
||||
|
||||
} // if ( inHIDInfoPtr->locID && inHIDInfoPtr->device.vendorID && inHIDInfoPtr->device.productID )
|
||||
// can't find matching device return NULL, do not return first device
|
||||
if ( (!foundIOHIDDeviceRef) || (!foundIOHIDElementRef) ) {
|
||||
// no HID device
|
||||
*outIOHIDDeviceRef = NULL;
|
||||
*outIOHIDElementRef = NULL;
|
||||
return (inHIDInfoPtr->actionCookie);
|
||||
} else {
|
||||
// HID device
|
||||
*outIOHIDDeviceRef = foundIOHIDDeviceRef;
|
||||
*outIOHIDElementRef = foundIOHIDElementRef;
|
||||
return (inHIDInfoPtr->actionCookie);
|
||||
}
|
||||
} // HIDGetElementConfig
|
||||
|
||||
#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
|
108
src/cocoa/HID_Error_Handler.c
Normal file
108
src/cocoa/HID_Error_Handler.c
Normal file
|
@ -0,0 +1,108 @@
|
|||
// File: HID_Error_Handler.c
|
||||
// Abstract: Implementation of the HID utilities error handlers
|
||||
// Version: 2.0
|
||||
//
|
||||
// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
// Inc. ("Apple") in consideration of your agreement to the following
|
||||
// terms, and your use, installation, modification or redistribution of
|
||||
// this Apple software constitutes acceptance of these terms. If you do
|
||||
// not agree with these terms, please do not use, install, modify or
|
||||
// redistribute this Apple software.
|
||||
//
|
||||
// In consideration of your agreement to abide by the following terms, and
|
||||
// subject to these terms, Apple grants you a personal, non-exclusive
|
||||
// license, under Apple's copyrights in this original Apple software (the
|
||||
// "Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
// Software, with or without modifications, in source and/or binary forms;
|
||||
// provided that if you redistribute the Apple Software in its entirety and
|
||||
// without modifications, you must retain this notice and the following
|
||||
// text and disclaimers in all such redistributions of the Apple Software.
|
||||
// Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
// be used to endorse or promote products derived from the Apple Software
|
||||
// without specific prior written permission from Apple. Except as
|
||||
// expressly stated in this notice, no other rights or licenses, express or
|
||||
// implied, are granted by Apple herein, including but not limited to any
|
||||
// patent rights that may be infringed by your derivative works or by other
|
||||
// works in which the Apple Software may be incorporated.
|
||||
//
|
||||
// The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
//
|
||||
// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (C) 2009 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
//*****************************************************
|
||||
|
||||
#include <AvailabilityMacros.h>
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
|
||||
|
||||
#ifdef DEBUG // not used in release
|
||||
#if !defined (kBuildingLibrary)
|
||||
#define kVerboseErrors
|
||||
|
||||
// system includes ----------------------------------------------------------
|
||||
|
||||
#ifdef kVerboseErrors
|
||||
//#include <Carbon/Carbon.h>
|
||||
#endif
|
||||
#endif // not kBuildingLibrary
|
||||
#endif // DEBUG
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
// project includes ---------------------------------------------------------
|
||||
|
||||
#include "HID_Utilities_External.h"
|
||||
|
||||
// globals (internal/private) -----------------------------------------------
|
||||
|
||||
// prototypes (internal/private) --------------------------------------------
|
||||
|
||||
// functions (internal/private) ---------------------------------------------
|
||||
|
||||
#pragma mark -
|
||||
// -------------------------------------
|
||||
|
||||
// central error reporting
|
||||
|
||||
void HIDReportErrorNum(const char *strError, int numError) {
|
||||
char errMsgCStr[256];
|
||||
|
||||
sprintf(errMsgCStr, "%s #%d (0x%x)", strError, numError, numError);
|
||||
|
||||
// out as debug string
|
||||
#ifdef kVerboseErrors
|
||||
{
|
||||
fputs(errMsgCStr, stderr);
|
||||
}
|
||||
#endif // kVerboseErrors
|
||||
} // HIDReportErrorNum
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
void HIDReportError(const char *strError) {
|
||||
char errMsgCStr[256];
|
||||
|
||||
sprintf(errMsgCStr, "%s", strError);
|
||||
|
||||
// out as debug string
|
||||
#ifdef kVerboseErrors
|
||||
{
|
||||
fputs(errMsgCStr, stderr);
|
||||
}
|
||||
#endif // kVerboseErrors
|
||||
} // HIDReportError
|
||||
|
||||
#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
|
1210
src/cocoa/HID_Name_Lookup.c
Normal file
1210
src/cocoa/HID_Name_Lookup.c
Normal file
File diff suppressed because it is too large
Load diff
361
src/cocoa/HID_Queue_Utilities.c
Normal file
361
src/cocoa/HID_Queue_Utilities.c
Normal file
|
@ -0,0 +1,361 @@
|
|||
// File: HID_Queue_Utilities.c
|
||||
// Abstract: HID Queue Utilities.
|
||||
// Version: 2.0
|
||||
//
|
||||
// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
// Inc. ("Apple") in consideration of your agreement to the following
|
||||
// terms, and your use, installation, modification or redistribution of
|
||||
// this Apple software constitutes acceptance of these terms. If you do
|
||||
// not agree with these terms, please do not use, install, modify or
|
||||
// redistribute this Apple software.
|
||||
//
|
||||
// In consideration of your agreement to abide by the following terms, and
|
||||
// subject to these terms, Apple grants you a personal, non-exclusive
|
||||
// license, under Apple's copyrights in this original Apple software (the
|
||||
// "Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
// Software, with or without modifications, in source and/or binary forms;
|
||||
// provided that if you redistribute the Apple Software in its entirety and
|
||||
// without modifications, you must retain this notice and the following
|
||||
// text and disclaimers in all such redistributions of the Apple Software.
|
||||
// Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
// be used to endorse or promote products derived from the Apple Software
|
||||
// without specific prior written permission from Apple. Except as
|
||||
// expressly stated in this notice, no other rights or licenses, express or
|
||||
// implied, are granted by Apple herein, including but not limited to any
|
||||
// patent rights that may be infringed by your derivative works or by other
|
||||
// works in which the Apple Software may be incorporated.
|
||||
//
|
||||
// The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
//
|
||||
// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (C) 2009 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
//*****************************************************
|
||||
|
||||
#include <AvailabilityMacros.h>
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
|
||||
|
||||
#include "HID_Utilities_External.h"
|
||||
|
||||
// ==================================
|
||||
// private functions
|
||||
|
||||
// creates a queue for a device, creates and opens device interface if required
|
||||
static IOReturn HIDCreateQueue(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
IOReturn result = kIOReturnSuccess;
|
||||
if ( inIOHIDDeviceRef ) {
|
||||
assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) );
|
||||
|
||||
// do we already have a queue?
|
||||
IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
|
||||
if ( tIOHIDQueueRef ) { // (yes)
|
||||
assert( IOHIDQueueGetTypeID() == CFGetTypeID(tIOHIDQueueRef) );
|
||||
} else {
|
||||
tIOHIDQueueRef = IOHIDQueueCreate(kCFAllocatorDefault, inIOHIDDeviceRef, kDeviceQueueSize, kIOHIDOptionsTypeNone);
|
||||
if ( tIOHIDQueueRef ) { // did that work
|
||||
IOHIDDevice_SetQueue(inIOHIDDeviceRef, tIOHIDQueueRef);
|
||||
result = kIOReturnSuccess;
|
||||
} else {
|
||||
HIDReportErrorNum("Failed to create queue via create", result);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
HIDReportErrorNum("HID device ref does not exist for queue creation", result);
|
||||
}
|
||||
|
||||
return (result);
|
||||
} /* HIDCreateQueue */
|
||||
|
||||
// ---------------------------------
|
||||
// returns true if queue is empty false otherwise
|
||||
// error if no device, empty if no queue
|
||||
static unsigned char HIDIsDeviceQueueEmpty(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
if ( inIOHIDDeviceRef ) { // need device and queue
|
||||
assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) );
|
||||
IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
|
||||
if ( tIOHIDQueueRef ) {
|
||||
IOHIDElementRef tIOHIDElementRef = HIDGetFirstDeviceElement(inIOHIDDeviceRef, kHIDElementTypeIO);
|
||||
|
||||
while ( tIOHIDElementRef ) {
|
||||
if ( IOHIDQueueContainsElement(tIOHIDQueueRef, tIOHIDElementRef) ) {
|
||||
return (false);
|
||||
}
|
||||
|
||||
tIOHIDElementRef = HIDGetNextDeviceElement(tIOHIDElementRef, kHIDElementTypeIO);
|
||||
}
|
||||
} else {
|
||||
HIDReportError("NULL device passed to HIDIsDeviceQueueEmpty.");
|
||||
}
|
||||
} else {
|
||||
HIDReportError("NULL device passed to HIDIsDeviceQueueEmpty.");
|
||||
}
|
||||
|
||||
return (true);
|
||||
} /* HIDIsDeviceQueueEmpty */
|
||||
|
||||
// ---------------------------------
|
||||
|
||||
// disposes and releases queue, sets queue to NULL,.
|
||||
// Note: will have no effect if device or queue do not exist
|
||||
static IOReturn HIDDisposeReleaseQueue(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
IOReturn result = kIOReturnSuccess;
|
||||
if ( inIOHIDDeviceRef ) {
|
||||
IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
|
||||
if ( tIOHIDQueueRef ) {
|
||||
// stop queue
|
||||
IOHIDQueueStop(tIOHIDQueueRef);
|
||||
|
||||
// release the queue
|
||||
CFRelease(tIOHIDQueueRef);
|
||||
}
|
||||
} else {
|
||||
HIDReportError("NULL device passed to HIDDisposeReleaseQueue.");
|
||||
}
|
||||
|
||||
return (result);
|
||||
} /* HIDDisposeReleaseQueue */
|
||||
|
||||
// ==================================
|
||||
// public functions
|
||||
// ----------------------------------
|
||||
|
||||
// queues specific element, performing any device queue set up required
|
||||
// queue is started and ready to return events on exit from this function
|
||||
int HIDQueueElement(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHIDElementRef) {
|
||||
IOReturn result = kIOReturnSuccess;
|
||||
if ( inIOHIDDeviceRef ) {
|
||||
assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) );
|
||||
if ( inIOHIDElementRef ) {
|
||||
assert( IOHIDElementGetTypeID() == CFGetTypeID(inIOHIDElementRef) );
|
||||
IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
|
||||
if ( !tIOHIDQueueRef ) { // if no queue create queue
|
||||
result = HIDCreateQueue(inIOHIDDeviceRef);
|
||||
if ( kIOReturnSuccess == result ) {
|
||||
tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
|
||||
}
|
||||
}
|
||||
if ( tIOHIDQueueRef ) {
|
||||
// stop queue
|
||||
IOHIDQueueStop(tIOHIDQueueRef);
|
||||
// queue element
|
||||
if ( !IOHIDQueueContainsElement(tIOHIDQueueRef, inIOHIDElementRef) ) {
|
||||
IOHIDQueueAddElement(tIOHIDQueueRef, inIOHIDElementRef);
|
||||
}
|
||||
|
||||
// restart queue
|
||||
IOHIDQueueStart(tIOHIDQueueRef);
|
||||
} else {
|
||||
HIDReportError("No queue for device passed to HIDQueueElement.");
|
||||
if ( kIOReturnSuccess == result ) {
|
||||
result = kIOReturnError;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
HIDReportError("NULL element passed to HIDQueueElement.");
|
||||
result = kIOReturnBadArgument;
|
||||
}
|
||||
} else {
|
||||
HIDReportError("NULL device passed to HIDQueueElement.");
|
||||
result = kIOReturnBadArgument;
|
||||
}
|
||||
|
||||
return (result);
|
||||
} /* HIDQueueElement */
|
||||
// ---------------------------------
|
||||
|
||||
// adds all elements to queue, performing any device queue set up required
|
||||
// queue is started and ready to return events on exit from this function
|
||||
int HIDQueueDevice(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
IOReturn result = kIOReturnSuccess;
|
||||
// error checking
|
||||
if ( !inIOHIDDeviceRef ) {
|
||||
HIDReportError("Device does not exist, cannot queue device.");
|
||||
return (kIOReturnBadArgument);
|
||||
}
|
||||
if ( !inIOHIDDeviceRef ) { // must have interface
|
||||
HIDReportError("Device does not have hid device ref, cannot queue device.");
|
||||
return (kIOReturnError);
|
||||
}
|
||||
|
||||
IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
|
||||
if ( !tIOHIDQueueRef ) { // if no queue create queue
|
||||
result = HIDCreateQueue(inIOHIDDeviceRef);
|
||||
if ( kIOReturnSuccess == result ) {
|
||||
tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
|
||||
}
|
||||
}
|
||||
if ( (kIOReturnSuccess != result) || (!tIOHIDQueueRef) ) {
|
||||
HIDReportErrorNum("Could not queue device due to problem creating queue.", result);
|
||||
if ( kIOReturnSuccess != result ) {
|
||||
return (result);
|
||||
} else {
|
||||
return (kIOReturnError);
|
||||
}
|
||||
}
|
||||
|
||||
// stop queue
|
||||
IOHIDQueueStop(tIOHIDQueueRef);
|
||||
|
||||
// queue element
|
||||
IOHIDElementRef tIOHIDElementRef = HIDGetFirstDeviceElement(inIOHIDDeviceRef, kHIDElementTypeIO);
|
||||
|
||||
while ( tIOHIDElementRef ) {
|
||||
if ( !IOHIDQueueContainsElement(tIOHIDQueueRef, tIOHIDElementRef) ) {
|
||||
IOHIDQueueAddElement(tIOHIDQueueRef, tIOHIDElementRef);
|
||||
}
|
||||
|
||||
tIOHIDElementRef = HIDGetNextDeviceElement(tIOHIDElementRef, kHIDElementTypeIO);
|
||||
}
|
||||
|
||||
// restart queue
|
||||
IOHIDQueueStart(tIOHIDQueueRef);
|
||||
|
||||
return (result);
|
||||
} /* HIDQueueDevice */
|
||||
|
||||
// ---------------------------------
|
||||
// removes element for queue, if last element in queue will release queue and closes device interface
|
||||
int HIDDequeueElement(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHIDElementRef) {
|
||||
IOReturn result = kIOReturnSuccess;
|
||||
if ( inIOHIDDeviceRef ) {
|
||||
assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) );
|
||||
if ( inIOHIDElementRef ) {
|
||||
assert( IOHIDElementGetTypeID() == CFGetTypeID(inIOHIDElementRef) );
|
||||
IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
|
||||
if ( tIOHIDQueueRef ) {
|
||||
// stop queue
|
||||
IOHIDQueueStop(tIOHIDQueueRef);
|
||||
// de-queue element
|
||||
if ( IOHIDQueueContainsElement(tIOHIDQueueRef, inIOHIDElementRef) ) {
|
||||
IOHIDQueueRemoveElement(tIOHIDQueueRef, inIOHIDElementRef);
|
||||
}
|
||||
// release device queue and close interface if queue empty
|
||||
if ( HIDIsDeviceQueueEmpty(inIOHIDDeviceRef) ) {
|
||||
result = HIDDisposeReleaseQueue(inIOHIDDeviceRef);
|
||||
if ( kIOReturnSuccess != result ) {
|
||||
HIDReportErrorNum("Failed to dispose and release queue.", result);
|
||||
}
|
||||
} else { // not empty so restart queue
|
||||
IOHIDQueueStart(tIOHIDQueueRef);
|
||||
}
|
||||
} else {
|
||||
HIDReportError("No queue for device passed to HIDDequeueElement.");
|
||||
if ( kIOReturnSuccess == result ) {
|
||||
result = kIOReturnError;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
HIDReportError("NULL element passed to HIDDequeueElement.");
|
||||
result = kIOReturnBadArgument;
|
||||
}
|
||||
} else {
|
||||
HIDReportError("NULL device passed to HIDDequeueElement.");
|
||||
result = kIOReturnBadArgument;
|
||||
}
|
||||
|
||||
return (result);
|
||||
} /* HIDDequeueElement */
|
||||
|
||||
// ---------------------------------
|
||||
// completely removes all elements from queue and releases queue and closes device interface
|
||||
// does not release device interfaces, application must call ReleaseHIDDeviceList on exit
|
||||
int HIDDequeueDevice(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
IOReturn result = kIOReturnSuccess;
|
||||
// error checking
|
||||
if ( !inIOHIDDeviceRef ) {
|
||||
HIDReportError("Device does not exist, cannot queue device.");
|
||||
return (kIOReturnBadArgument);
|
||||
}
|
||||
if ( !inIOHIDDeviceRef ) { // must have interface
|
||||
HIDReportError("Device does not have hid device ref, cannot queue device.");
|
||||
return (kIOReturnError);
|
||||
}
|
||||
|
||||
IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
|
||||
if ( tIOHIDQueueRef ) {
|
||||
// iterate through elements and if queued, remove
|
||||
IOHIDElementRef tIOHIDElementRef = HIDGetFirstDeviceElement(inIOHIDDeviceRef, kHIDElementTypeIO);
|
||||
|
||||
while ( tIOHIDElementRef ) {
|
||||
// de-queue element
|
||||
if ( IOHIDQueueContainsElement(tIOHIDQueueRef, tIOHIDElementRef) ) {
|
||||
IOHIDQueueRemoveElement(tIOHIDQueueRef, tIOHIDElementRef);
|
||||
}
|
||||
|
||||
tIOHIDElementRef = HIDGetNextDeviceElement(tIOHIDElementRef, kHIDElementTypeIO);
|
||||
}
|
||||
|
||||
// ensure queue is disposed and released
|
||||
result = HIDDisposeReleaseQueue(inIOHIDDeviceRef);
|
||||
if ( kIOReturnSuccess != result ) {
|
||||
HIDReportErrorNum("Failed to dispose and release queue.", result);
|
||||
}
|
||||
} else {
|
||||
HIDReportError("No queue for device passed to HIDDequeueElement.");
|
||||
if ( kIOReturnSuccess == result ) {
|
||||
result = kIOReturnError;
|
||||
}
|
||||
}
|
||||
|
||||
return (result);
|
||||
} /* HIDDequeueDevice */
|
||||
// ---------------------------------
|
||||
|
||||
// releases all device queues for quit or rebuild (must be called)
|
||||
// does not release device interfaces, application must call ReleaseHIDDeviceList on exit
|
||||
IOReturn HIDReleaseAllDeviceQueues(void) {
|
||||
IOReturn result = kIOReturnSuccess;
|
||||
IOHIDDeviceRef tIOHIDDeviceRef = HIDGetFirstDevice();
|
||||
|
||||
while ( tIOHIDDeviceRef ) {
|
||||
result = HIDDequeueDevice(tIOHIDDeviceRef);
|
||||
if ( kIOReturnSuccess != result ) {
|
||||
HIDReportErrorNum("Could not dequeue device.", result);
|
||||
}
|
||||
|
||||
tIOHIDDeviceRef = HIDGetNextDevice(tIOHIDDeviceRef);
|
||||
}
|
||||
|
||||
return (result);
|
||||
} /* HIDReleaseAllDeviceQueues */
|
||||
|
||||
// ---------------------------------
|
||||
// Get the next event in the queue for a device
|
||||
// elements or entire device should be queued prior to calling this with HIDQueueElement or HIDQueueDevice
|
||||
// returns true if an event is avialable for the element and fills out *pHIDEvent structure, returns false otherwise
|
||||
// Note: kIOReturnUnderrun returned from getNextEvent indicates an empty queue not an error condition
|
||||
// Note: application should pass in a pointer to a IOHIDEventStruct cast to a void (for CFM compatibility)
|
||||
unsigned char HIDGetEvent(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDValueRef *pIOHIDValueRef) {
|
||||
if ( inIOHIDDeviceRef ) {
|
||||
IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
|
||||
if ( tIOHIDQueueRef ) {
|
||||
if ( pIOHIDValueRef ) {
|
||||
*pIOHIDValueRef = IOHIDQueueCopyNextValueWithTimeout(tIOHIDQueueRef, 0.0);
|
||||
if ( *pIOHIDValueRef ) {
|
||||
return (true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
HIDReportError("Could not get HID event, hid queue reference does not exist.");
|
||||
}
|
||||
} else {
|
||||
HIDReportError("Could not get HID event, device does not exist.");
|
||||
}
|
||||
|
||||
return (false); // did not get event
|
||||
} /* HIDGetEvent */
|
||||
|
||||
#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
|
1068
src/cocoa/HID_Utilities.c
Normal file
1068
src/cocoa/HID_Utilities.c
Normal file
File diff suppressed because it is too large
Load diff
417
src/cocoa/HID_Utilities_External.h
Normal file
417
src/cocoa/HID_Utilities_External.h
Normal file
|
@ -0,0 +1,417 @@
|
|||
// File: HID_Utilities_External.h
|
||||
// Abstract: External interface for HID Utilities, can be used with either library or source.
|
||||
// Version: 2.0
|
||||
//
|
||||
// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
// Inc. ("Apple") in consideration of your agreement to the following
|
||||
// terms, and your use, installation, modification or redistribution of
|
||||
// this Apple software constitutes acceptance of these terms. If you do
|
||||
// not agree with these terms, please do not use, install, modify or
|
||||
// redistribute this Apple software.
|
||||
//
|
||||
// In consideration of your agreement to abide by the following terms, and
|
||||
// subject to these terms, Apple grants you a personal, non-exclusive
|
||||
// license, under Apple's copyrights in this original Apple software (the
|
||||
// "Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
// Software, with or without modifications, in source and/or binary forms;
|
||||
// provided that if you redistribute the Apple Software in its entirety and
|
||||
// without modifications, you must retain this notice and the following
|
||||
// text and disclaimers in all such redistributions of the Apple Software.
|
||||
// Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
// be used to endorse or promote products derived from the Apple Software
|
||||
// without specific prior written permission from Apple. Except as
|
||||
// expressly stated in this notice, no other rights or licenses, express or
|
||||
// implied, are granted by Apple herein, including but not limited to any
|
||||
// patent rights that may be infringed by your derivative works or by other
|
||||
// works in which the Apple Software may be incorporated.
|
||||
//
|
||||
// The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
//
|
||||
// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (C) 2009 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
//*****************************************************
|
||||
#ifndef _HID_Utilities_External_h_
|
||||
#define _HID_Utilities_External_h_
|
||||
|
||||
// ==================================
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// ==================================
|
||||
|
||||
//includes
|
||||
|
||||
#include <stdio.h>
|
||||
#include "IOHIDLib_.h"
|
||||
|
||||
// ==================================
|
||||
|
||||
#ifndef _IOKIT_HID_IOHIDKEYS_H_
|
||||
/*!
|
||||
@typedef IOHIDElementCookie
|
||||
@abstract Abstract data type used as a unique identifier for an element.
|
||||
*/
|
||||
#ifdef __LP64__
|
||||
typedef uint32_t IOHIDElementCookie;
|
||||
#else
|
||||
typedef void *IOHIDElementCookie;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Device and Element Interfaces
|
||||
|
||||
enum HIDElementTypeMask {
|
||||
kHIDElementTypeInput = 1 << 1,
|
||||
kHIDElementTypeOutput = 1 << 2,
|
||||
kHIDElementTypeFeature = 1 << 3,
|
||||
kHIDElementTypeCollection = 1 << 4,
|
||||
kHIDElementTypeIO = kHIDElementTypeInput | kHIDElementTypeOutput | kHIDElementTypeFeature,
|
||||
kHIDElementTypeAll = kHIDElementTypeIO | kHIDElementTypeCollection
|
||||
};
|
||||
typedef enum HIDElementTypeMask HIDElementTypeMask;
|
||||
|
||||
// ==================================
|
||||
|
||||
//*****************************************************
|
||||
#pragma mark - exported globals
|
||||
//-----------------------------------------------------
|
||||
|
||||
extern IOHIDManagerRef gIOHIDManagerRef;
|
||||
extern CFMutableArrayRef gDeviceCFArrayRef;
|
||||
extern CFArrayRef gElementCFArrayRef;
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// HIDBuildMultiDeviceList( inUsagePages, inUsages, inNumDeviceTypes )
|
||||
//
|
||||
// Purpose: builds list of devices with elements (allocates memory and captures devices) in which
|
||||
// the devices could be of different types/usages list is allocated internally within HID
|
||||
// Utilites and can be accessed via accessor functions structures within list are considered
|
||||
// flat and user accessable, but not user modifiable can be called again to rebuild list to
|
||||
// account for new devices (will do the right thing in case of disposing existing list)
|
||||
// usagePage, usage are each a numDeviceTypes sized array of matching usage and usage pages
|
||||
// returns true if succesful
|
||||
//
|
||||
// Inputs: inUsagePages - inNumDeviceTypes sized array of matching usage pages
|
||||
// inUsages - inNumDeviceTypes sized array of matching usages
|
||||
// inNumDeviceTypes - number of usage pages & usages
|
||||
//
|
||||
// Returns: Boolean - if successful
|
||||
//
|
||||
extern Boolean HIDBuildMultiDeviceList(const UInt32 *inUsagePages, const UInt32 *inUsages, int inNumDeviceTypes);
|
||||
|
||||
// same as above but this uses a single usagePage and usage
|
||||
extern Boolean HIDBuildDeviceList(UInt32 usagePage, UInt32 usage);
|
||||
|
||||
// updates the current device list for any new/removed devices
|
||||
// if this is called before HIDBuildDeviceList the it functions like HIDBuildMultiDeviceList
|
||||
// usagePage, usage are each a numDeviceTypes sized array of matching usage and usage pages
|
||||
// returns true if successful which means if any device were added or removed (the device config changed)
|
||||
extern Boolean HIDUpdateDeviceList(const UInt32 *inUsagePages, const UInt32 *inUsages, int inNumDeviceTypes);
|
||||
|
||||
// release list built by above function
|
||||
// MUST be called prior to application exit to properly release devices
|
||||
// if not called (or app crashes) devices can be recovered by pluging into different location in USB chain
|
||||
extern void HIDReleaseDeviceList(void);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// HIDRebuildDevices( )
|
||||
//
|
||||
// Purpose: rebuilds the (internal) list of devices
|
||||
//
|
||||
// Inputs: none
|
||||
//
|
||||
// Returns: none
|
||||
//
|
||||
|
||||
extern void HIDRebuildDevices(void);
|
||||
|
||||
// does a device list exist
|
||||
extern unsigned char HIDHaveDeviceList(void);
|
||||
|
||||
// how many HID devices have been found
|
||||
// returns 0 if no device list exist
|
||||
extern UInt32 HIDCountDevices(void);
|
||||
|
||||
// how many elements does a specific device have
|
||||
// returns 0 if device is invalid or NULL
|
||||
// uses mask of HIDElementTypeMask to restrict element found
|
||||
// use kHIDElementTypeIO to get non-collection elements
|
||||
extern UInt32 HIDCountDeviceElements(IOHIDDeviceRef inIOHIDDeviceRef, HIDElementTypeMask typeMask);
|
||||
|
||||
// get the first device in the device list
|
||||
// returns NULL if no list exists
|
||||
extern IOHIDDeviceRef HIDGetFirstDevice(void);
|
||||
|
||||
// get next device in list given current device as parameter
|
||||
// returns NULL if end of list
|
||||
extern IOHIDDeviceRef HIDGetNextDevice(IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
|
||||
// get the first element of device passed in as parameter
|
||||
// returns NULL if no list exists or device does not exists or is NULL
|
||||
// uses mask of HIDElementTypeMask to restrict element found
|
||||
// use kHIDElementTypeIO to get previous HIDGetFirstDeviceElement functionality
|
||||
extern IOHIDElementRef HIDGetFirstDeviceElement(IOHIDDeviceRef inIOHIDDeviceRef, HIDElementTypeMask typeMask);
|
||||
|
||||
// get next element of given device in list given current element as parameter
|
||||
// will walk down each collection then to next element or collection (depthwise traverse)
|
||||
// returns NULL if end of list
|
||||
// uses mask of HIDElementTypeMask to restrict element found
|
||||
// use kHIDElementTypeIO to get previous HIDGetNextDeviceElement functionality
|
||||
extern IOHIDElementRef HIDGetNextDeviceElement(IOHIDElementRef inIOHidElementRef, HIDElementTypeMask typeMask);
|
||||
|
||||
// get previous element of given device in list given current element as parameter
|
||||
// this walks directly up the tree to the top element and does not search at each level
|
||||
// returns NULL if beginning of list
|
||||
// uses mask of HIDElementTypeMask to restrict element found
|
||||
// use kHIDElementTypeIO to get non-collection elements
|
||||
extern IOHIDElementRef HIDGetPreviousDeviceElement(IOHIDElementRef inIOHidElementRef, HIDElementTypeMask typeMask);
|
||||
|
||||
// returns C string type name given a type enumeration passed in as parameter( see IOHIDKeys.h )
|
||||
// returns empty string for invalid types
|
||||
extern void HIDGetTypeName(IOHIDElementType inIOHIDElementType, char *outCStrName);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// HIDCopyUsageName( inUsagePage, inUsage )
|
||||
//
|
||||
// Purpose: return a CFStringRef string for a given usage page & usage( see IOUSBHIDParser.h )
|
||||
//
|
||||
// Notes: returns usage page and usage values in CFString form for unknown values
|
||||
//
|
||||
// Inputs: inUsagePage - the usage page
|
||||
// inUsage - the usage
|
||||
//
|
||||
// Returns: CFStringRef - the resultant string
|
||||
//
|
||||
|
||||
extern CFStringRef HIDCopyUsageName(long inUsagePage, long inUsage);
|
||||
|
||||
// ==================================
|
||||
|
||||
// Element Event Queue and Value Interfaces
|
||||
|
||||
enum {
|
||||
kDefaultUserMin = 0, // default user min and max used for scaling
|
||||
kDefaultUserMax = 255
|
||||
};
|
||||
|
||||
enum {
|
||||
kDeviceQueueSize = 50 // this is wired kernel memory so should be set to as small as possible
|
||||
// but should account for the maximum possible events in the queue
|
||||
// USB updates will likely occur at 100 Hz so one must account for this rate of
|
||||
// if states change quickly (updates are only posted on state changes)
|
||||
};
|
||||
|
||||
// ==================================
|
||||
|
||||
// queues specific element, performing any device queue set up required
|
||||
extern int HIDQueueElement(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHidElementRef);
|
||||
|
||||
// adds all elements to queue, performing any device queue set up required
|
||||
extern int HIDQueueDevice(IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
|
||||
// removes element for queue, if last element in queue will release queue and device
|
||||
extern int HIDDequeueElement(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHidElementRef);
|
||||
|
||||
// completely removes all elements from queue and releases queue and device
|
||||
extern int HIDDequeueDevice(IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
|
||||
// releases all device queues for quit or rebuild (must be called)
|
||||
extern int HIDReleaseAllDeviceQueues(void);
|
||||
|
||||
// returns true if an event is avialable for the element and fills out *pHIDEvent structure, returns false otherwise
|
||||
// pHIDEvent is a poiner to a IOHIDEventStruct, using void here for compatibility, users can cast a required
|
||||
extern unsigned char HIDGetEvent(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDValueRef *pIOHIDValueRef);
|
||||
|
||||
// ==================================
|
||||
|
||||
// Conguration and Save Interfaces
|
||||
|
||||
enum {
|
||||
kPercentMove = 10 // precent of overall range a element must move to register
|
||||
};
|
||||
|
||||
typedef struct HID_info_struct {
|
||||
int actionCookie;
|
||||
// device
|
||||
// need to add serial number when I have a test case
|
||||
struct {
|
||||
int vendorID, productID;
|
||||
int locID;
|
||||
uint32_t usagePage, usage;
|
||||
} device;
|
||||
// elements
|
||||
struct {
|
||||
uint32_t usagePage, usage;
|
||||
int minReport, maxReport;
|
||||
IOHIDElementCookie cookie; // always 32 bits
|
||||
} element;
|
||||
}HID_info_rec, *HID_info_ptr;
|
||||
|
||||
// get vendor name from vendor ID
|
||||
extern Boolean HIDGetVendorNameFromVendorID(long inVendorID, char *outCStrName);
|
||||
|
||||
// get product name from vendor/product ID
|
||||
extern Boolean HIDGetProductNameFromVendorProductID(long inVendorID, long inProductID, char *outCStrName);
|
||||
|
||||
// get element name from vendor id/product id look up ( using element cookie )
|
||||
extern Boolean HIDGetElementNameFromVendorProductCookie(int inVendorID,
|
||||
int inProductID,
|
||||
IOHIDElementCookie inCookie,
|
||||
char * outCStrName);
|
||||
|
||||
// get element name from vendor id/product id look up ( using element usage page & usage )
|
||||
extern Boolean HIDGetElementNameFromVendorProductUsage(long inVendorID,
|
||||
long inProductID,
|
||||
long inUsagePage,
|
||||
long inUsage,
|
||||
char *inCStrName);
|
||||
|
||||
// utility routines to dump device or element info
|
||||
extern void HIDDumpDeviceInfo(IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
extern void HIDDumpElementInfo(IOHIDElementRef inIOHIDElementRef);
|
||||
extern void HIDDumpElementCalibrationInfo(IOHIDElementRef inIOHIDElementRef);
|
||||
|
||||
// polls single device's elements for a change greater than kPercentMove. Times out after given time
|
||||
// returns 1 and pointer to element if found
|
||||
// returns 0 and NULL for both parameters if not found
|
||||
extern unsigned char HIDConfigureSingleDeviceAction(IOHIDDeviceRef inIOHIDDeviceRef,
|
||||
IOHIDElementRef *outIOHIDElementRef,
|
||||
float timeout);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// HIDConfigureAction( outDeviceRef, outElementRef, inTimeout )
|
||||
//
|
||||
// Purpose: polls all devices and elements for a change greater than kPercentMove.
|
||||
// Times out after given time returns 1 and pointer to device and element
|
||||
// if found; returns 0 and NULL for both parameters if not found
|
||||
//
|
||||
// Inputs: outDeviceRef - address where to store the device
|
||||
// outElementRef - address where to store the element
|
||||
// inTimeout - the timeout
|
||||
// Returns: Boolean - TRUE if successful
|
||||
// outDeviceRef - the device
|
||||
// outElementRef - the element
|
||||
//
|
||||
|
||||
extern Boolean HIDConfigureAction(IOHIDDeviceRef *outDeviceRef, IOHIDElementRef *outElementRef, float inTimeout);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// HIDSaveElementPref( inKeyCFStringRef, inAppCFStringRef, inDeviceRef, inElementRef )
|
||||
//
|
||||
// Purpose: Save the device & element values into the specified key in the specified applications preferences
|
||||
//
|
||||
// Inputs: inKeyCFStringRef - the preference key
|
||||
// inAppCFStringRef - the application identifier
|
||||
// inDeviceRef - the device
|
||||
// inElementRef - the element
|
||||
// Returns: Boolean - if successful
|
||||
//
|
||||
|
||||
extern Boolean HIDSaveElementPref(const CFStringRef inKeyCFStringRef,
|
||||
CFStringRef inAppCFStringRef,
|
||||
IOHIDDeviceRef inDeviceRef,
|
||||
IOHIDElementRef inElementRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// HIDRestoreElementPref( inKeyCFStringRef, inAppCFStringRef, outDeviceRef, outElementRef )
|
||||
//
|
||||
// Purpose: Find the specified preference in the specified application
|
||||
//
|
||||
// Inputs: inKeyCFStringRef - the preference key
|
||||
// inAppCFStringRef - the application identifier
|
||||
// outDeviceRef - address where to restore the device
|
||||
// outElementRef - address where to restore the element
|
||||
// Returns: Boolean - if successful
|
||||
// outDeviceRef - the device
|
||||
// outElementRef - the element
|
||||
//
|
||||
|
||||
extern Boolean HIDRestoreElementPref(CFStringRef inKeyCFStringRef,
|
||||
CFStringRef inAppCFStringRef,
|
||||
IOHIDDeviceRef * outDeviceRef,
|
||||
IOHIDElementRef *outElementRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// HIDFindDeviceAndElement( inSearchInfo, outFoundDevice, outFoundElement )
|
||||
//
|
||||
// Purpose: find the closest matching device and element for this action
|
||||
//
|
||||
// Notes: matches device: serial, vendorID, productID, location, inUsagePage, usage
|
||||
// matches element: cookie, inUsagePage, usage,
|
||||
//
|
||||
// Inputs: inSearchInfo - the device & element info we searching for
|
||||
// outFoundDevice - the address of the best matching device
|
||||
// outFoundElement - the address of the best matching element
|
||||
//
|
||||
// Returns: Boolean - TRUE if we find a match
|
||||
// outFoundDevice - the best matching device
|
||||
// outFoundElement - the best matching element
|
||||
//
|
||||
|
||||
extern Boolean HIDFindDeviceAndElement(const HID_info_rec *inSearchInfo,
|
||||
IOHIDDeviceRef * outFoundDevice,
|
||||
IOHIDElementRef * outFoundElement);
|
||||
|
||||
// -- These are routines to use if the applcationwants HID Utilities to do the file handling --
|
||||
// Note: the FILE * is a MachO posix FILE and will not likely work directly with MW MSL FILE * type.
|
||||
|
||||
// take input records, save required info
|
||||
// assume file is open and at correct position.
|
||||
void HIDSaveElementConfig(FILE *fileRef, IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHidElementRef, int actionCookie);
|
||||
|
||||
// takes a file, reads one record (assume file position is correct and file is open)
|
||||
// search for matching device
|
||||
// return tIOHIDDeviceRef, tIOHIDElementRef and cookie for action
|
||||
int HIDRestoreElementConfig(FILE *fileRef, IOHIDDeviceRef *outIOHIDDeviceRef, IOHIDElementRef *outIOHIDElementRef);
|
||||
|
||||
// -- These are routines to use if the client wants to use their own file handling --
|
||||
|
||||
// Set up a config record for saving
|
||||
// takes an input records, returns record user can save as they want
|
||||
// Note: the save rec must be pre-allocated by the calling app and will be filled out
|
||||
void HIDSetElementConfig(HID_info_ptr inHIDInfoPtr,
|
||||
IOHIDDeviceRef inIOHIDDeviceRef,
|
||||
IOHIDElementRef inIOHidElementRef,
|
||||
int actionCookie);
|
||||
|
||||
// Get matching element from config record
|
||||
// takes a pre-allocated and filled out config record
|
||||
// search for matching device
|
||||
// return tIOHIDDeviceRef, tIOHIDElementRef and cookie for action
|
||||
int HIDGetElementConfig(HID_info_ptr inHIDInfoPtr, IOHIDDeviceRef *outIOHIDDeviceRef, IOHIDElementRef *outIOHIDElementRef);
|
||||
|
||||
// ==================================
|
||||
|
||||
// Error reporter, can be set to report however the application desires
|
||||
extern void HIDReportError(const char *strError);
|
||||
|
||||
// Error with numeric code reporter, can be set to report however the application desires
|
||||
extern void HIDReportErrorNum(const char *strError, int numError);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _HID_Utilities_External_h_
|
619
src/cocoa/IOHIDDevice_.c
Normal file
619
src/cocoa/IOHIDDevice_.c
Normal file
|
@ -0,0 +1,619 @@
|
|||
// File: IOHIDDevice_.c
|
||||
// Abstract: convieance functions for IOHIDDeviceGetProperty
|
||||
// Version: 2.0 + 5.3
|
||||
//
|
||||
// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
// Inc. ("Apple") in consideration of your agreement to the following
|
||||
// terms, and your use, installation, modification or redistribution of
|
||||
// this Apple software constitutes acceptance of these terms. If you do
|
||||
// not agree with these terms, please do not use, install, modify or
|
||||
// redistribute this Apple software.
|
||||
//
|
||||
// In consideration of your agreement to abide by the following terms, and
|
||||
// subject to these terms, Apple grants you a personal, non-exclusive
|
||||
// license, under Apple's copyrights in this original Apple software (the
|
||||
// "Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
// Software, with or without modifications, in source and/or binary forms;
|
||||
// provided that if you redistribute the Apple Software in its entirety and
|
||||
// without modifications, you must retain this notice and the following
|
||||
// text and disclaimers in all such redistributions of the Apple Software.
|
||||
// Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
// be used to endorse or promote products derived from the Apple Software
|
||||
// without specific prior written permission from Apple. Except as
|
||||
// expressly stated in this notice, no other rights or licenses, express or
|
||||
// implied, are granted by Apple herein, including but not limited to any
|
||||
// patent rights that may be infringed by your derivative works or by other
|
||||
// works in which the Apple Software may be incorporated.
|
||||
//
|
||||
// The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
//
|
||||
// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (C) 2009 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
//*****************************************************
|
||||
|
||||
#include <AvailabilityMacros.h>
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
|
||||
|
||||
#pragma mark - includes & imports
|
||||
//-----------------------------------------------------
|
||||
|
||||
#include "IOHIDDevice_.h"
|
||||
|
||||
//*****************************************************
|
||||
#pragma mark - typedef's, struct's, enums, defines, etc.
|
||||
//-----------------------------------------------------
|
||||
|
||||
#define kIOHIDDevice_TransactionKey "DeviceTransactionRef"
|
||||
#define kIOHIDDevice_QueueKey "DeviceQueueRef"
|
||||
|
||||
//*****************************************************
|
||||
#pragma mark - local (static) function prototypes
|
||||
//-----------------------------------------------------
|
||||
|
||||
static Boolean IOHIDDevice_GetUInt32Property(IOHIDDeviceRef inIOHIDDeviceRef,
|
||||
CFStringRef inKey,
|
||||
uint32_t * outValue);
|
||||
// static void IOHIDDevice_SetUInt32Property(IOHIDDeviceRef inIOHIDDeviceRef, CFStringRef inKey, uint32_t inValue);
|
||||
|
||||
static Boolean IOHIDDevice_GetPtrProperty(IOHIDDeviceRef inIOHIDDeviceRef,
|
||||
CFStringRef inKey,
|
||||
void ** outValue);
|
||||
static void IOHIDDevice_SetPtrProperty(IOHIDDeviceRef inIOHIDDeviceRef,
|
||||
CFStringRef inKey,
|
||||
void * inValue);
|
||||
|
||||
//*****************************************************
|
||||
#pragma mark - exported globals
|
||||
//-----------------------------------------------------
|
||||
|
||||
//*****************************************************
|
||||
#pragma mark - local (static) globals
|
||||
//-----------------------------------------------------
|
||||
|
||||
//*****************************************************
|
||||
#pragma mark - exported function implementations
|
||||
//-----------------------------------------------------
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// HIDIsValidDevice( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: validate this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: Boolean - TRUE if we find the device in our( internal ) device list
|
||||
//
|
||||
|
||||
Boolean HIDIsValidDevice(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
Boolean result = FALSE; // assume failure (pessimist!)
|
||||
if ( inIOHIDDeviceRef ) {
|
||||
if ( CFGetTypeID(inIOHIDDeviceRef) ==IOHIDDeviceGetTypeID() ) {
|
||||
result = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return (result);
|
||||
} // HIDIsValidDevice
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetTransport( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the Transport CFString for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: CFStringRef - the Transport for this device
|
||||
//
|
||||
|
||||
CFStringRef IOHIDDevice_GetTransport(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) );
|
||||
return ( IOHIDDeviceGetProperty( inIOHIDDeviceRef, CFSTR(kIOHIDTransportKey) ) );
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetVendorID( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the vendor ID for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: uint32_t - the vendor ID for this device
|
||||
//
|
||||
|
||||
uint32_t IOHIDDevice_GetVendorID(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
uint32_t result = 0;
|
||||
(void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDVendorIDKey), &result);
|
||||
return (result);
|
||||
} // IOHIDDevice_GetVendorID
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetVendorIDSource( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the VendorIDSource for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: uint32_t - the VendorIDSource for this device
|
||||
//
|
||||
|
||||
uint32_t IOHIDDevice_GetVendorIDSource(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
uint32_t result = 0;
|
||||
(void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDVendorIDSourceKey), &result);
|
||||
return (result);
|
||||
} // IOHIDDevice_GetVendorIDSource
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetProductID( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the product ID for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: uint32_t - the product ID for this device
|
||||
//
|
||||
|
||||
uint32_t IOHIDDevice_GetProductID(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
uint32_t result = 0;
|
||||
(void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDProductIDKey), &result);
|
||||
return (result);
|
||||
} // IOHIDDevice_GetProductID
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetVersionNumber( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the VersionNumber CFString for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: uint32_t - the VersionNumber for this device
|
||||
//
|
||||
|
||||
uint32_t IOHIDDevice_GetVersionNumber(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
uint32_t result = 0;
|
||||
(void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDVersionNumberKey), &result);
|
||||
return (result);
|
||||
} // IOHIDDevice_GetVersionNumber
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetManufacturer( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the Manufacturer CFString for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: CFStringRef - the Manufacturer for this device
|
||||
//
|
||||
|
||||
CFStringRef IOHIDDevice_GetManufacturer(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) );
|
||||
return ( IOHIDDeviceGetProperty( inIOHIDDeviceRef, CFSTR(kIOHIDManufacturerKey) ) );
|
||||
} // IOHIDDevice_GetManufacturer
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetProduct( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the Product CFString for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: CFStringRef - the Product for this device
|
||||
//
|
||||
|
||||
CFStringRef IOHIDDevice_GetProduct(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) );
|
||||
return ( IOHIDDeviceGetProperty( inIOHIDDeviceRef, CFSTR(kIOHIDProductKey) ) );
|
||||
} // IOHIDDevice_GetProduct
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetSerialNumber( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the SerialNumber CFString for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: CFStringRef - the SerialNumber for this device
|
||||
//
|
||||
|
||||
CFStringRef IOHIDDevice_GetSerialNumber(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) );
|
||||
return ( IOHIDDeviceGetProperty( inIOHIDDeviceRef, CFSTR(kIOHIDSerialNumberKey) ) );
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetCountryCode( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the CountryCode CFString for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: uint32_t - the CountryCode for this device
|
||||
//
|
||||
|
||||
uint32_t IOHIDDevice_GetCountryCode(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
uint32_t result = 0;
|
||||
(void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDCountryCodeKey), &result);
|
||||
return (result);
|
||||
} // IOHIDDevice_GetCountryCode
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetLocationID( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the location ID for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: uint32_t - the location ID for this device
|
||||
//
|
||||
|
||||
uint32_t IOHIDDevice_GetLocationID(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
uint32_t result = 0;
|
||||
(void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDLocationIDKey), &result);
|
||||
return (result);
|
||||
} // IOHIDDevice_GetLocationID
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetUsage( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the usage for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: uint32_t - the usage for this device
|
||||
//
|
||||
|
||||
uint32_t IOHIDDevice_GetUsage(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
uint32_t result = 0;
|
||||
(void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDDeviceUsageKey), &result);
|
||||
return (result);
|
||||
} // IOHIDDevice_GetUsage
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetUsagePage( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the usage page for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: uint32_t - the usage page for this device
|
||||
//
|
||||
|
||||
uint32_t IOHIDDevice_GetUsagePage(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
uint32_t result = 0;
|
||||
(void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDDeviceUsagePageKey), &result);
|
||||
return (result);
|
||||
} // IOHIDDevice_GetUsagePage
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetUsagePairs( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the UsagePairs CFString for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: CFArrayRef - the UsagePairs for this device
|
||||
//
|
||||
|
||||
CFArrayRef IOHIDDevice_GetUsagePairs(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) );
|
||||
return ( IOHIDDeviceGetProperty( inIOHIDDeviceRef, CFSTR(kIOHIDDeviceUsagePairsKey) ) );
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetPrimaryUsage( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the PrimaryUsage CFString for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: uint32_t - the PrimaryUsage for this device
|
||||
//
|
||||
|
||||
uint32_t IOHIDDevice_GetPrimaryUsage(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
uint32_t result = 0;
|
||||
(void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDPrimaryUsageKey), &result);
|
||||
return (result);
|
||||
} // IOHIDDevice_GetPrimaryUsage
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetPrimaryUsagePage( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the PrimaryUsagePage CFString for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: uint32_t - the PrimaryUsagePage for this device
|
||||
//
|
||||
|
||||
uint32_t IOHIDDevice_GetPrimaryUsagePage(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
uint32_t result = 0;
|
||||
(void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDPrimaryUsagePageKey), &result);
|
||||
return (result);
|
||||
} // IOHIDDevice_GetPrimaryUsagePage
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetMaxInputReportSize( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the MaxInputReportSize CFString for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: uint32_t - the MaxInputReportSize for this device
|
||||
//
|
||||
|
||||
uint32_t IOHIDDevice_GetMaxInputReportSize(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
uint32_t result = 0;
|
||||
(void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDMaxInputReportSizeKey), &result);
|
||||
return (result);
|
||||
} // IOHIDDevice_GetMaxInputReportSize
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetMaxOutputReportSize( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the MaxOutputReportSize for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: uint32_t - the MaxOutput for this device
|
||||
//
|
||||
|
||||
uint32_t IOHIDDevice_GetMaxOutputReportSize(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
uint32_t result = 0;
|
||||
(void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDMaxOutputReportSizeKey), &result);
|
||||
return (result);
|
||||
} // IOHIDDevice_GetMaxOutputReportSize
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetMaxFeatureReportSize( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the MaxFeatureReportSize for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: uint32_t - the MaxFeatureReportSize for this device
|
||||
//
|
||||
|
||||
uint32_t IOHIDDevice_GetMaxFeatureReportSize(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
uint32_t result = 0;
|
||||
(void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDMaxFeatureReportSizeKey), &result);
|
||||
return (result);
|
||||
} // IOHIDDevice_GetMaxFeatureReportSize
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetReportInterval( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the ReportInterval for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: uint32_t - the ReportInterval for this device
|
||||
//
|
||||
#ifndef kIOHIDReportIntervalKey
|
||||
#define kIOHIDReportIntervalKey "ReportInterval"
|
||||
#endif
|
||||
uint32_t IOHIDDevice_GetReportInterval(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
uint32_t result = 0;
|
||||
(void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDReportIntervalKey), &result);
|
||||
return (result);
|
||||
} // IOHIDDevice_GetReportInterval
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetQueue( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the Queue for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: IOHIDQueueRef - the Queue for this device
|
||||
//
|
||||
|
||||
IOHIDQueueRef IOHIDDevice_GetQueue(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
IOHIDQueueRef result = 0;
|
||||
(void) IOHIDDevice_GetPtrProperty(inIOHIDDeviceRef, CFSTR(kIOHIDDevice_QueueKey), (void *) &result);
|
||||
if ( result ) {
|
||||
assert( IOHIDQueueGetTypeID() == CFGetTypeID(result) );
|
||||
}
|
||||
|
||||
return (result);
|
||||
} // IOHIDDevice_GetQueue
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_SetQueue( inIOHIDDeviceRef, inQueueRef )
|
||||
//
|
||||
// Purpose: Set the Queue for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
// inQueueRef - the Queue reference
|
||||
//
|
||||
// Returns: nothing
|
||||
//
|
||||
|
||||
void IOHIDDevice_SetQueue(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDQueueRef inQueueRef) {
|
||||
IOHIDDevice_SetPtrProperty(inIOHIDDeviceRef, CFSTR(kIOHIDDevice_QueueKey), inQueueRef);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetTransaction( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the Transaction for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: IOHIDTransactionRef - the Transaction for this device
|
||||
//
|
||||
|
||||
IOHIDTransactionRef IOHIDDevice_GetTransaction(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
IOHIDTransactionRef result = 0;
|
||||
(void) IOHIDDevice_GetPtrProperty(inIOHIDDeviceRef, CFSTR(kIOHIDDevice_TransactionKey), (void *) &result);
|
||||
return (result);
|
||||
} // IOHIDDevice_GetTransaction
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_SetTransaction( inIOHIDDeviceRef, inTransactionRef )
|
||||
//
|
||||
// Purpose: Set the Transaction for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
// inTransactionRef - the Transaction reference
|
||||
//
|
||||
// Returns: nothing
|
||||
//
|
||||
|
||||
void IOHIDDevice_SetTransaction(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDTransactionRef inTransactionRef) {
|
||||
IOHIDDevice_SetPtrProperty(inIOHIDDeviceRef, CFSTR(kIOHIDDevice_TransactionKey), inTransactionRef);
|
||||
}
|
||||
|
||||
//*****************************************************
|
||||
#pragma mark - local (static) function implementations
|
||||
//-----------------------------------------------------
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetUInt32Property( inIOHIDDeviceRef, inKey, outValue )
|
||||
//
|
||||
// Purpose: convieance function to return a uint32_t property of a device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the device
|
||||
// inKey - CFString for the
|
||||
// outValue - address where to restore the element
|
||||
// Returns: the action cookie
|
||||
// outValue - the device
|
||||
//
|
||||
|
||||
static Boolean IOHIDDevice_GetUInt32Property(IOHIDDeviceRef inIOHIDDeviceRef, CFStringRef inKey, uint32_t *outValue) {
|
||||
Boolean result = FALSE;
|
||||
if ( inIOHIDDeviceRef ) {
|
||||
assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) );
|
||||
|
||||
CFTypeRef tCFTypeRef = IOHIDDeviceGetProperty(inIOHIDDeviceRef, inKey);
|
||||
if ( tCFTypeRef ) {
|
||||
// if this is a number
|
||||
if ( CFNumberGetTypeID() == CFGetTypeID(tCFTypeRef) ) {
|
||||
// get it's value
|
||||
result = CFNumberGetValue( (CFNumberRef) tCFTypeRef, kCFNumberSInt32Type, outValue );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (result);
|
||||
} // IOHIDDevice_GetUInt32Property
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_SetUInt32Property( inIOHIDDeviceRef, inKey, inValue )
|
||||
//
|
||||
// Purpose: convieance function to set a long property of an Device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the Device
|
||||
// inKey - CFString for the key
|
||||
// inValue - the value to set it to
|
||||
// Returns: nothing
|
||||
//
|
||||
#if 0 // unused
|
||||
static void IOHIDDevice_SetUInt32Property(IOHIDDeviceRef inIOHIDDeviceRef, CFStringRef inKey, uint32_t inValue) {
|
||||
CFNumberRef tCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &inValue);
|
||||
if ( tCFNumberRef ) {
|
||||
IOHIDDeviceSetProperty(inIOHIDDeviceRef, inKey, tCFNumberRef);
|
||||
CFRelease(tCFNumberRef);
|
||||
}
|
||||
} // IOHIDDevice_SetUInt32Property
|
||||
#endif
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetPtrProperty( inIOHIDDeviceRef, inKey, outValue )
|
||||
//
|
||||
// Purpose: convieance function to return a pointer property of a device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the device
|
||||
// inKey - CFString for the
|
||||
// outValue - address where to restore the element
|
||||
// Returns: the action cookie
|
||||
// outValue - the device
|
||||
//
|
||||
|
||||
static Boolean IOHIDDevice_GetPtrProperty(IOHIDDeviceRef inIOHIDDeviceRef, CFStringRef inKey, void **outValue) {
|
||||
Boolean result = FALSE;
|
||||
if ( inIOHIDDeviceRef ) {
|
||||
assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) );
|
||||
|
||||
CFTypeRef tCFTypeRef = IOHIDDeviceGetProperty(inIOHIDDeviceRef, inKey);
|
||||
if ( tCFTypeRef ) {
|
||||
// if this is a number
|
||||
if ( CFNumberGetTypeID() == CFGetTypeID(tCFTypeRef) ) {
|
||||
// get it's value
|
||||
#ifdef __LP64__
|
||||
result = CFNumberGetValue( (CFNumberRef) tCFTypeRef, kCFNumberSInt64Type, outValue );
|
||||
#else
|
||||
result = CFNumberGetValue( (CFNumberRef) tCFTypeRef, kCFNumberSInt32Type, outValue );
|
||||
#endif // ifdef __LP64__
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (result);
|
||||
} // IOHIDDevice_GetPtrProperty
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_SetPtrProperty( inIOHIDDeviceRef, inKey, inValue )
|
||||
//
|
||||
// Purpose: convieance function to set a long property of an Device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the Device
|
||||
// inKey - CFString for the key
|
||||
// inValue - the value to set it to
|
||||
// Returns: nothing
|
||||
//
|
||||
|
||||
static void IOHIDDevice_SetPtrProperty(IOHIDDeviceRef inIOHIDDeviceRef, CFStringRef inKey, void *inValue) {
|
||||
#ifdef __LP64__
|
||||
CFNumberRef tCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &inValue);
|
||||
#else
|
||||
CFNumberRef tCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &inValue);
|
||||
#endif // ifdef __LP64__
|
||||
if ( tCFNumberRef ) {
|
||||
IOHIDDeviceSetProperty(inIOHIDDeviceRef, inKey, tCFNumberRef);
|
||||
CFRelease(tCFNumberRef);
|
||||
}
|
||||
} // IOHIDDevice_SetPtrProperty
|
||||
|
||||
//*****************************************************
|
||||
|
||||
#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
|
422
src/cocoa/IOHIDDevice_.h
Normal file
422
src/cocoa/IOHIDDevice_.h
Normal file
|
@ -0,0 +1,422 @@
|
|||
// File: IOHIDDevice_.h
|
||||
// Abstract: convieance functions for IOHIDDeviceGetProperty
|
||||
// Version: 2.0 + 5.3
|
||||
//
|
||||
// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
// Inc. ("Apple") in consideration of your agreement to the following
|
||||
// terms, and your use, installation, modification or redistribution of
|
||||
// this Apple software constitutes acceptance of these terms. If you do
|
||||
// not agree with these terms, please do not use, install, modify or
|
||||
// redistribute this Apple software.
|
||||
//
|
||||
// In consideration of your agreement to abide by the following terms, and
|
||||
// subject to these terms, Apple grants you a personal, non-exclusive
|
||||
// license, under Apple's copyrights in this original Apple software (the
|
||||
// "Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
// Software, with or without modifications, in source and/or binary forms;
|
||||
// provided that if you redistribute the Apple Software in its entirety and
|
||||
// without modifications, you must retain this notice and the following
|
||||
// text and disclaimers in all such redistributions of the Apple Software.
|
||||
// Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
// be used to endorse or promote products derived from the Apple Software
|
||||
// without specific prior written permission from Apple. Except as
|
||||
// expressly stated in this notice, no other rights or licenses, express or
|
||||
// implied, are granted by Apple herein, including but not limited to any
|
||||
// patent rights that may be infringed by your derivative works or by other
|
||||
// works in which the Apple Software may be incorporated.
|
||||
//
|
||||
// The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
//
|
||||
// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (C) 2014 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
//*****************************************************
|
||||
#ifndef __IOHIDDevice__
|
||||
#define __IOHIDDevice__
|
||||
|
||||
//*****************************************************
|
||||
#pragma mark - includes & imports
|
||||
|
||||
#include <AvailabilityMacros.h>
|
||||
|
||||
#include "IOHIDLib_.h"
|
||||
|
||||
//*****************************************************
|
||||
#if PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if PRAGMA_IMPORT
|
||||
#pragma import on
|
||||
#endif
|
||||
|
||||
#if PRAGMA_STRUCT_ALIGN
|
||||
#pragma options align=mac68k
|
||||
#elif PRAGMA_STRUCT_PACKPUSH
|
||||
#pragma pack(push, 2)
|
||||
#elif PRAGMA_STRUCT_PACK
|
||||
#pragma pack(2)
|
||||
#endif
|
||||
|
||||
//*****************************************************
|
||||
#pragma mark - typedef's, struct's, enums, defines, etc.
|
||||
//-----------------------------------------------------
|
||||
|
||||
//*****************************************************
|
||||
#pragma mark - exported globals
|
||||
//-----------------------------------------------------
|
||||
|
||||
//*****************************************************
|
||||
#pragma mark - exported function prototypes
|
||||
//-----------------------------------------------------
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// HIDIsValidDevice( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: validate this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: Boolean - TRUE if we find the device in our( internal ) device list
|
||||
//
|
||||
|
||||
extern Boolean HIDIsValidDevice(IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetTransport( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the Transport CFString for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: CFStringRef - the Transport CFString for this device
|
||||
//
|
||||
|
||||
extern CFStringRef IOHIDDevice_GetTransport(IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetVendorID( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the vendor ID for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: uint32_t - the vendor ID for this device
|
||||
//
|
||||
|
||||
extern uint32_t IOHIDDevice_GetVendorID(IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetVendorIDSource( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the VendorIDSource for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: uint32_t - the VendorIDSource for this device
|
||||
//
|
||||
|
||||
extern uint32_t IOHIDDevice_GetVendorIDSource(IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetProductID( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the product ID for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: uint32_t - the product ID for this device
|
||||
//
|
||||
|
||||
extern uint32_t IOHIDDevice_GetProductID(IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetVersionNumber( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the VersionNumber CFString for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: uint32_t - the VersionNumber for this device
|
||||
//
|
||||
|
||||
extern uint32_t IOHIDDevice_GetVersionNumber(IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetManufacturer( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the Manufacturer CFString for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: CFStringRef - the Manufacturer CFString for this device
|
||||
//
|
||||
|
||||
extern CFStringRef IOHIDDevice_GetManufacturer(IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetProduct( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the Product CFString for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: CFStringRef - the Product CFString for this device
|
||||
//
|
||||
|
||||
extern CFStringRef IOHIDDevice_GetProduct(IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetSerialNumber( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the SerialNumber CFString for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: CFStringRef - the SerialNumber CFString for this device
|
||||
//
|
||||
|
||||
extern CFStringRef IOHIDDevice_GetSerialNumber(IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetCountryCode( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the CountryCode CFString for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: uint32_t - the CountryCode for this device
|
||||
//
|
||||
|
||||
extern uint32_t IOHIDDevice_GetCountryCode(IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetLocationID( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the location ID for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: uint32_t - the location ID for this device
|
||||
//
|
||||
|
||||
extern uint32_t IOHIDDevice_GetLocationID(IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetUsage( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the usage for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: uint32_t - the usage for this device
|
||||
//
|
||||
|
||||
extern uint32_t IOHIDDevice_GetUsage(IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetUsagePage( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the usage page for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: uint32_t - the usage page for this device
|
||||
//
|
||||
|
||||
extern uint32_t IOHIDDevice_GetUsagePage(IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetUsagePairs( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the UsagePairs CFString for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: CFArrayRef - the UsagePairs for this device
|
||||
//
|
||||
|
||||
extern CFArrayRef IOHIDDevice_GetUsagePairs(IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetPrimaryUsage( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the PrimaryUsage CFString for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: CFStringRef - the PrimaryUsage CFString for this device
|
||||
//
|
||||
|
||||
extern uint32_t IOHIDDevice_GetPrimaryUsage(IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetPrimaryUsagePage( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the PrimaryUsagePage CFString for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: CFStringRef - the PrimaryUsagePage CFString for this device
|
||||
//
|
||||
|
||||
extern uint32_t IOHIDDevice_GetPrimaryUsagePage(IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetMaxInputReportSize( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the MaxInputReportSize for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: uint32_t - the MaxInputReportSize for this device
|
||||
//
|
||||
|
||||
extern uint32_t IOHIDDevice_GetMaxInputReportSize(IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetMaxOutputReportSize( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the MaxOutputReportSize for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: uint32_t - the MaxOutputReportSize for this device
|
||||
//
|
||||
|
||||
extern uint32_t IOHIDDevice_GetMaxOutputReportSize(IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetMaxFeatureReportSize( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the MaxFeatureReportSize for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: uint32_t - the MaxFeatureReportSize for this device
|
||||
//
|
||||
|
||||
extern uint32_t IOHIDDevice_GetMaxFeatureReportSize(IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetReportInterval( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the ReportInterval for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: uint32_t - the ReportInterval for this device
|
||||
//
|
||||
|
||||
extern uint32_t IOHIDDevice_GetReportInterval(IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetQueue( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the Queue for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: IOHIDQueueRef - the Queue for this device
|
||||
//
|
||||
|
||||
extern IOHIDQueueRef IOHIDDevice_GetQueue(IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_SetQueue( inIOHIDDeviceRef, inQueueRef )
|
||||
//
|
||||
// Purpose: Set the Queue for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
// inQueueRef - the Queue
|
||||
//
|
||||
// Returns: nothing
|
||||
//
|
||||
|
||||
extern void IOHIDDevice_SetQueue(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDQueueRef inQueueRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_GetTransaction( inIOHIDDeviceRef )
|
||||
//
|
||||
// Purpose: get the Transaction for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
//
|
||||
// Returns: IOHIDTransactionRef - the Transaction for this device
|
||||
//
|
||||
|
||||
extern IOHIDTransactionRef IOHIDDevice_GetTransaction(IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDDevice_SetTransaction( inIOHIDDeviceRef, inTransactionRef )
|
||||
//
|
||||
// Purpose: Set the Transaction for this device
|
||||
//
|
||||
// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device
|
||||
// inTransactionRef - the Transaction
|
||||
//
|
||||
// Returns: nothing
|
||||
//
|
||||
|
||||
extern void IOHIDDevice_SetTransaction(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDTransactionRef inTransactionRef);
|
||||
|
||||
//*****************************************************
|
||||
#if PRAGMA_STRUCT_ALIGN
|
||||
#pragma options align=reset
|
||||
#elif PRAGMA_STRUCT_PACKPUSH
|
||||
#pragma pack(pop)
|
||||
#elif PRAGMA_STRUCT_PACK
|
||||
#pragma pack()
|
||||
#endif
|
||||
|
||||
#ifdef PRAGMA_IMPORT_OFF
|
||||
#pragma import off
|
||||
#elif PRAGMA_IMPORT
|
||||
#pragma import reset
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __IOHIDDevice__ //
|
509
src/cocoa/IOHIDElement_.c
Normal file
509
src/cocoa/IOHIDElement_.c
Normal file
|
@ -0,0 +1,509 @@
|
|||
// File: IOHIDElement_.c
|
||||
// Abstract: convieance functions for IOHIDElementGetProperty
|
||||
// Version: 2.0
|
||||
//
|
||||
// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
// Inc. ("Apple") in consideration of your agreement to the following
|
||||
// terms, and your use, installation, modification or redistribution of
|
||||
// this Apple software constitutes acceptance of these terms. If you do
|
||||
// not agree with these terms, please do not use, install, modify or
|
||||
// redistribute this Apple software.
|
||||
//
|
||||
// In consideration of your agreement to abide by the following terms, and
|
||||
// subject to these terms, Apple grants you a personal, non-exclusive
|
||||
// license, under Apple's copyrights in this original Apple software (the
|
||||
// "Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
// Software, with or without modifications, in source and/or binary forms;
|
||||
// provided that if you redistribute the Apple Software in its entirety and
|
||||
// without modifications, you must retain this notice and the following
|
||||
// text and disclaimers in all such redistributions of the Apple Software.
|
||||
// Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
// be used to endorse or promote products derived from the Apple Software
|
||||
// without specific prior written permission from Apple. Except as
|
||||
// expressly stated in this notice, no other rights or licenses, express or
|
||||
// implied, are granted by Apple herein, including but not limited to any
|
||||
// patent rights that may be infringed by your derivative works or by other
|
||||
// works in which the Apple Software may be incorporated.
|
||||
//
|
||||
// The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
//
|
||||
// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (C) 2009 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
//*****************************************************
|
||||
|
||||
#include <AvailabilityMacros.h>
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
|
||||
|
||||
#pragma mark - includes & imports
|
||||
//-----------------------------------------------------
|
||||
|
||||
#include "IOHIDElement_.h"
|
||||
|
||||
//*****************************************************
|
||||
#pragma mark - typedef's, struct's, enums, defines, etc.
|
||||
//-----------------------------------------------------
|
||||
|
||||
//*****************************************************
|
||||
#pragma mark - local (static) function prototypes
|
||||
//-----------------------------------------------------
|
||||
|
||||
// static Boolean IOHIDElement_GetLongProperty( IOHIDElementRef inElementRef, CFStringRef inKey, long * outValue );
|
||||
// static void IOHIDElement_SetLongProperty( IOHIDElementRef inElementRef, CFStringRef inKey, long inValue );
|
||||
|
||||
//*****************************************************
|
||||
#pragma mark - exported globals
|
||||
//-----------------------------------------------------
|
||||
|
||||
//*****************************************************
|
||||
#pragma mark - local (static) globals
|
||||
//-----------------------------------------------------
|
||||
|
||||
//*****************************************************
|
||||
#pragma mark - exported function implementations
|
||||
//-----------------------------------------------------
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// HIDIsValidElement( inIOHIDElementRef )
|
||||
//
|
||||
// Purpose: validate this element
|
||||
//
|
||||
// Inputs: inIOHIDElementRef - the element
|
||||
//
|
||||
// Returns: Boolean - TRUE if this is a valid element ref
|
||||
//
|
||||
Boolean HIDIsValidElement(IOHIDElementRef inIOHIDElementRef) {
|
||||
Boolean result = FALSE; // assume failure (pessimist!)
|
||||
if ( inIOHIDElementRef ) {
|
||||
if ( CFGetTypeID(inIOHIDElementRef) ==IOHIDElementGetTypeID() ) {
|
||||
result = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return (result);
|
||||
} // HIDIsValidElement
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_GetValue( inElementRef, inIOHIDValueScaleType )
|
||||
//
|
||||
// Purpose: returns the current value for an element( polling )
|
||||
//
|
||||
// Notes: will return 0 on error conditions which should be accounted for by application
|
||||
//
|
||||
// Inputs: inElementRef - the element
|
||||
// inIOHIDValueScaleType - scale type ( calibrated or physical )
|
||||
//
|
||||
// Returns: double - current value for element
|
||||
//
|
||||
double IOHIDElement_GetValue(IOHIDElementRef inElementRef, IOHIDValueScaleType inIOHIDValueScaleType) {
|
||||
long result = 0;
|
||||
IOHIDValueRef tIOHIDValueRef;
|
||||
if ( kIOReturnSuccess == IOHIDDeviceGetValue(IOHIDElementGetDevice(inElementRef), inElementRef, &tIOHIDValueRef) ) {
|
||||
result = IOHIDValueGetScaledValue(tIOHIDValueRef, inIOHIDValueScaleType);
|
||||
}
|
||||
|
||||
return (result);
|
||||
} // IOHIDElement_GetValue
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_GetCalibrationMin( inElementRef )
|
||||
//
|
||||
// Purpose: get the minimum bounds for a calibrated value for this element
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
//
|
||||
// Returns: CFIndex - the minimum Calibration value for this element
|
||||
//
|
||||
|
||||
CFIndex IOHIDElement_GetCalibrationMin(IOHIDElementRef inElementRef) {
|
||||
CFIndex result;
|
||||
if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationMinKey), &result) ) {
|
||||
if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementMaxKey), &result) ) {
|
||||
result = 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationMinKey), result);
|
||||
}
|
||||
|
||||
return (result);
|
||||
} // IOHIDElement_GetCalibrationMin
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_SetCalibrationMin( inElementRef, inValue )
|
||||
//
|
||||
// Purpose: set the minimum bounds for a calibrated value for this element
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
// inValue - the minimum bounds for a calibrated value for this element
|
||||
//
|
||||
// Returns: nothing
|
||||
//
|
||||
|
||||
void IOHIDElement_SetCalibrationMin(IOHIDElementRef inElementRef, CFIndex inValue) {
|
||||
IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationMinKey), inValue);
|
||||
} // IOHIDElement_SetCalibrationMin
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_GetCalibrationMax( inElementRef )
|
||||
//
|
||||
// Purpose: get the maximum bounds for a calibrated value for this element
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
//
|
||||
// Returns: CFIndex - the maximum Calibration value for this element
|
||||
//
|
||||
|
||||
CFIndex IOHIDElement_GetCalibrationMax(IOHIDElementRef inElementRef) {
|
||||
CFIndex result;
|
||||
if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationMaxKey), &result) ) {
|
||||
if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementMinKey), &result) ) {
|
||||
result = -0x7FFFFFFF;
|
||||
}
|
||||
|
||||
IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationMaxKey), result);
|
||||
}
|
||||
|
||||
return (result);
|
||||
} // IOHIDElement_GetCalibrationMax
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_SetCalibrationMax( inElementRef, inValue )
|
||||
//
|
||||
// Purpose: set the maximum bounds for a calibrated value for this element
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
// inValue - the maximum Calibration value for this element
|
||||
//
|
||||
// Returns: nothing
|
||||
//
|
||||
|
||||
void IOHIDElement_SetCalibrationMax(IOHIDElementRef inElementRef, CFIndex inValue) {
|
||||
IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationMaxKey), inValue);
|
||||
} // IOHIDElement_SetCalibrationMax
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_GetCalibrationSaturationMin( inElementRef )
|
||||
//
|
||||
// Purpose: get the mininum tolerance to be used when calibrating a logical element value
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
//
|
||||
// Returns: CFIndex - the maximum Calibration value for this element
|
||||
//
|
||||
|
||||
CFIndex IOHIDElement_GetCalibrationSaturationMin(IOHIDElementRef inElementRef) {
|
||||
CFIndex result;
|
||||
if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationSaturationMinKey), &result) ) {
|
||||
if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementMinKey), &result) ) {
|
||||
result = -0x7FFFFFFF;
|
||||
}
|
||||
|
||||
IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationSaturationMinKey), result);
|
||||
}
|
||||
|
||||
return (result);
|
||||
} // IOHIDElement_GetCalibrationSaturationMin
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_SetCalibrationSaturationMin( inElementRef, inValue )
|
||||
//
|
||||
// Purpose: set the mininum tolerance to be used when calibrating a logical element value
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
// inValue - the maximum Calibration value for this element
|
||||
//
|
||||
// Returns: nothing
|
||||
//
|
||||
|
||||
void IOHIDElement_SetCalibrationSaturationMin(IOHIDElementRef inElementRef, CFIndex inValue) {
|
||||
IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationSaturationMinKey), inValue);
|
||||
} // IOHIDElement_SetCalibrationSaturationMin
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_GetCalibrationSaturationMax( inElementRef )
|
||||
//
|
||||
// Purpose: get the maximum tolerance to be used when calibrating a logical element value
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
//
|
||||
// Returns: CFIndex - the maximum Calibration value for this element
|
||||
//
|
||||
|
||||
CFIndex IOHIDElement_GetCalibrationSaturationMax(IOHIDElementRef inElementRef) {
|
||||
CFIndex result;
|
||||
if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationSaturationMaxKey), &result) ) {
|
||||
if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementMinKey), &result) ) {
|
||||
result = -0x7FFFFFFF;
|
||||
}
|
||||
|
||||
IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationSaturationMaxKey), result);
|
||||
}
|
||||
|
||||
return (result);
|
||||
} // IOHIDElement_GetCalibrationSaturationMax
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_SetCalibrationSaturationMax( inElementRef, inValue )
|
||||
//
|
||||
// Purpose: set the maximum tolerance to be used when calibrating a logical element value
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
// inValue - the maximum Calibration value for this element
|
||||
//
|
||||
// Returns: nothing
|
||||
//
|
||||
|
||||
void IOHIDElement_SetCalibrationSaturationMax(IOHIDElementRef inElementRef, CFIndex inValue) {
|
||||
IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationSaturationMaxKey), inValue);
|
||||
} // IOHIDElement_SetCalibrationSaturationMax
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_GetCalibrationDeadZoneMin( inElementRef )
|
||||
//
|
||||
// Purpose: get the minimum bounds near the midpoint of a logical value in which the value is ignored
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
//
|
||||
// Returns: CFIndex - the maximum Calibration value for this element
|
||||
//
|
||||
|
||||
CFIndex IOHIDElement_GetCalibrationDeadZoneMin(IOHIDElementRef inElementRef) {
|
||||
CFIndex result;
|
||||
if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationDeadZoneMinKey), &result) ) {
|
||||
if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementMinKey), &result) ) {
|
||||
result = -0x7FFFFFFF;
|
||||
}
|
||||
|
||||
IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationDeadZoneMinKey), result);
|
||||
}
|
||||
|
||||
return (result);
|
||||
} // IOHIDElement_GetCalibrationDeadZoneMin
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_SetCalibrationDeadZoneMin( inElementRef, inValue )
|
||||
//
|
||||
// Purpose: set the minimum bounds near the midpoint of a logical value in which the value is ignored
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
// inValue - the maximum Calibration value for this element
|
||||
//
|
||||
// Returns: nothing
|
||||
//
|
||||
|
||||
void IOHIDElement_SetCalibrationDeadZoneMin(IOHIDElementRef inElementRef, CFIndex inValue) {
|
||||
IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationDeadZoneMinKey), inValue);
|
||||
} // IOHIDElement_SetCalibrationDeadZoneMin
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_GetCalibrationDeadZoneMax( inElementRef )
|
||||
//
|
||||
// Purpose: get the maximum bounds near the midpoint of a logical value in which the value is ignored
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
//
|
||||
// Returns: CFIndex - the maximum Calibration value for this element
|
||||
//
|
||||
|
||||
CFIndex IOHIDElement_GetCalibrationDeadZoneMax(IOHIDElementRef inElementRef) {
|
||||
CFIndex result;
|
||||
if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationDeadZoneMaxKey), &result) ) {
|
||||
if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementMinKey), &result) ) {
|
||||
result = -0x7FFFFFFF;
|
||||
}
|
||||
|
||||
IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationDeadZoneMaxKey), result);
|
||||
}
|
||||
|
||||
return (result);
|
||||
} // IOHIDElement_GetCalibrationDeadZoneMax
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_SetCalibrationDeadZoneMax( inElementRef, inValue )
|
||||
//
|
||||
// Purpose: set the maximum bounds near the midpoint of a logical value in which the value is ignored
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
// inValue - the maximum Calibration value for this element
|
||||
//
|
||||
// Returns: nothing
|
||||
//
|
||||
|
||||
void IOHIDElement_SetCalibrationDeadZoneMax(IOHIDElementRef inElementRef, CFIndex inValue) {
|
||||
IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationDeadZoneMaxKey), inValue);
|
||||
} // IOHIDElement_SetCalibrationDeadZoneMax
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_GetCalibrationGranularity( inElementRef )
|
||||
//
|
||||
// Purpose: get the level of detail returned for a calibrated element value
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
//
|
||||
// Returns: double_t - the maximum Calibration value for this element
|
||||
//
|
||||
|
||||
double_t IOHIDElement_GetCalibrationGranularity(IOHIDElementRef inElementRef) {
|
||||
CFIndex result;
|
||||
if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationGranularityKey), &result) ) {
|
||||
if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementMinKey), &result) ) {
|
||||
result = -0x7FFFFFFF;
|
||||
}
|
||||
|
||||
IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationGranularityKey), result);
|
||||
}
|
||||
|
||||
return (result);
|
||||
} // IOHIDElement_GetCalibrationGranularity
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_SetCalibrationGranularity( inElementRef, inValue )
|
||||
//
|
||||
// Purpose: set the level of detail returned for a calibrated element value
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
// inValue - the the level of detail for this element
|
||||
//
|
||||
// Returns: nothing
|
||||
//
|
||||
|
||||
void IOHIDElement_SetCalibrationGranularity(IOHIDElementRef inElementRef, double_t inValue) {
|
||||
IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationGranularityKey), inValue);
|
||||
} // IOHIDElement_SetCalibrationGranularity
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_SetupCalibration( inElementRef )
|
||||
//
|
||||
// Purpose: set default values for the element calibration parameters
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
//
|
||||
// Returns: nothing
|
||||
//
|
||||
void IOHIDElement_SetupCalibration(IOHIDElementRef inIOHIDElementRef) {
|
||||
// these are the min/max values returned by IOHIDValueGetScaledValue( v, kIOHIDValueScaleTypeCalibrated );
|
||||
IOHIDElement_SetCalibrationMin( inIOHIDElementRef, IOHIDElementGetLogicalMin(inIOHIDElementRef) );
|
||||
IOHIDElement_SetCalibrationMax( inIOHIDElementRef, IOHIDElementGetLogicalMax(inIOHIDElementRef) );
|
||||
|
||||
// this is the granularity of the values returned by IOHIDValueGetScaledValue( v, kIOHIDValueScaleTypeCalibrated );
|
||||
// for example if set to 0.1 the values returned will be multiples of 0.1 ( 0.1, 0.2, 0.3, etc. )
|
||||
IOHIDElement_SetCalibrationGranularity(inIOHIDElementRef, 0.);
|
||||
|
||||
// these define the dead zone (like in the middel of joystick axis)
|
||||
IOHIDElement_SetCalibrationDeadZoneMin(inIOHIDElementRef, 0);
|
||||
IOHIDElement_SetCalibrationDeadZoneMax(inIOHIDElementRef, 0);
|
||||
#if 1
|
||||
// get the current value of this element
|
||||
double value = IOHIDElement_GetValue(inIOHIDElementRef, kIOHIDValueScaleTypePhysical);
|
||||
// use it as our min/mas saturation
|
||||
IOHIDElement_SetCalibrationSaturationMin(inIOHIDElementRef, value);
|
||||
IOHIDElement_SetCalibrationSaturationMax(inIOHIDElementRef, value);
|
||||
#else
|
||||
// calculate the middle physical value we would expect from this element
|
||||
CFIndex valueMin = IOHIDElementGetPhysicalMin(inIOHIDElementRef);
|
||||
CFIndex valueMax = IOHIDElementGetPhysicalMax(inIOHIDElementRef);
|
||||
CFIndex valueMid = (valueMin + valueMax) / 2;
|
||||
|
||||
// use it as our min/mas saturation
|
||||
// this value determines the min/max values that have been recieved from the device element
|
||||
IOHIDElement_SetCalibrationSaturationMin(inIOHIDElementRef, valueMid);
|
||||
IOHIDElement_SetCalibrationSaturationMax(inIOHIDElementRef, valueMid);
|
||||
|
||||
// get the current value of this element
|
||||
double value = IOHIDElement_GetValue(inIOHIDElementRef, kIOHIDValueScaleTypePhysical);
|
||||
// and use it to adjust the current saturation values if it's outside their range
|
||||
if ( value < IOHIDElement_GetCalibrationSaturationMin(inIOHIDElementRef) ) {
|
||||
IOHIDElement_SetCalibrationSaturationMin(inIOHIDElementRef, value);
|
||||
}
|
||||
if ( value > IOHIDElement_GetCalibrationSaturationMax(inIOHIDElementRef) ) {
|
||||
IOHIDElement_SetCalibrationSaturationMax(inIOHIDElementRef, value);
|
||||
}
|
||||
|
||||
#endif
|
||||
} // IOHIDElement_SetupCalibration
|
||||
//*****************************************************
|
||||
#pragma mark - local (static) function implementations
|
||||
//-----------------------------------------------------
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_GetLongProperty( inElementRef, inKey, outValue )
|
||||
//
|
||||
// Purpose: convieance function to return a long property of an element
|
||||
//
|
||||
// Inputs: inElementRef - the element
|
||||
// inKey - CFString for the key
|
||||
// outValue - address where to store the value
|
||||
// Returns: Boolean - TRUE if successful
|
||||
// outValue - the long property's value
|
||||
//
|
||||
|
||||
Boolean IOHIDElement_GetLongProperty(IOHIDElementRef inElementRef, CFStringRef inKey, long *outValue) {
|
||||
Boolean result = FALSE;
|
||||
|
||||
CFTypeRef tCFTypeRef = IOHIDElementGetProperty(inElementRef, inKey);
|
||||
if ( tCFTypeRef ) {
|
||||
// if this is a number
|
||||
if ( CFNumberGetTypeID() == CFGetTypeID(tCFTypeRef) ) {
|
||||
// get it's value
|
||||
result = CFNumberGetValue( (CFNumberRef) tCFTypeRef, kCFNumberSInt32Type, outValue );
|
||||
}
|
||||
}
|
||||
|
||||
return (result);
|
||||
} /* IOHIDElement_GetLongProperty */
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_SetLongProperty( inElementRef, inKey, inValue )
|
||||
//
|
||||
// Purpose: convieance function to set a long property of an element
|
||||
//
|
||||
// Inputs: inElementRef - the element
|
||||
// inKey - CFString for the key
|
||||
// inValue - the value to set it to
|
||||
//
|
||||
// Returns: nothing
|
||||
//
|
||||
|
||||
void IOHIDElement_SetLongProperty(IOHIDElementRef inElementRef, CFStringRef inKey, long inValue) {
|
||||
CFNumberRef tCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &inValue);
|
||||
if ( tCFNumberRef ) {
|
||||
IOHIDElementSetProperty(inElementRef, inKey, tCFNumberRef);
|
||||
CFRelease(tCFNumberRef);
|
||||
}
|
||||
} // IOHIDElement_SetLongProperty
|
||||
|
||||
//*****************************************************
|
||||
|
||||
#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
|
339
src/cocoa/IOHIDElement_.h
Normal file
339
src/cocoa/IOHIDElement_.h
Normal file
|
@ -0,0 +1,339 @@
|
|||
// File: IOHIDElement_.h
|
||||
// Abstract: convieance functions for IOHIDElementGetProperty
|
||||
// Version: 2.0
|
||||
//
|
||||
// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
// Inc. ("Apple") in consideration of your agreement to the following
|
||||
// terms, and your use, installation, modification or redistribution of
|
||||
// this Apple software constitutes acceptance of these terms. If you do
|
||||
// not agree with these terms, please do not use, install, modify or
|
||||
// redistribute this Apple software.
|
||||
//
|
||||
// In consideration of your agreement to abide by the following terms, and
|
||||
// subject to these terms, Apple grants you a personal, non-exclusive
|
||||
// license, under Apple's copyrights in this original Apple software (the
|
||||
// "Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
// Software, with or without modifications, in source and/or binary forms;
|
||||
// provided that if you redistribute the Apple Software in its entirety and
|
||||
// without modifications, you must retain this notice and the following
|
||||
// text and disclaimers in all such redistributions of the Apple Software.
|
||||
// Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
// be used to endorse or promote products derived from the Apple Software
|
||||
// without specific prior written permission from Apple. Except as
|
||||
// expressly stated in this notice, no other rights or licenses, express or
|
||||
// implied, are granted by Apple herein, including but not limited to any
|
||||
// patent rights that may be infringed by your derivative works or by other
|
||||
// works in which the Apple Software may be incorporated.
|
||||
//
|
||||
// The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
//
|
||||
// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (C) 2009 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
//*****************************************************
|
||||
#ifndef __IOHIDElement___
|
||||
#define __IOHIDElement___
|
||||
|
||||
//*****************************************************
|
||||
#pragma mark - includes & imports
|
||||
|
||||
#include <AvailabilityMacros.h>
|
||||
|
||||
#include "IOHIDLib_.h"
|
||||
//*****************************************************
|
||||
#if PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if PRAGMA_IMPORT
|
||||
#pragma import on
|
||||
#endif
|
||||
|
||||
#if PRAGMA_STRUCT_ALIGN
|
||||
#pragma options align=mac68k
|
||||
#elif PRAGMA_STRUCT_PACKPUSH
|
||||
#pragma pack(push, 2)
|
||||
#elif PRAGMA_STRUCT_PACK
|
||||
#pragma pack(2)
|
||||
#endif
|
||||
|
||||
//*****************************************************
|
||||
#pragma mark - typedef's, struct's, enums, defines, etc.
|
||||
//-----------------------------------------------------
|
||||
|
||||
//*****************************************************
|
||||
#pragma mark - exported globals
|
||||
//-----------------------------------------------------
|
||||
|
||||
//*****************************************************
|
||||
#pragma mark - exported function prototypes
|
||||
//-----------------------------------------------------
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// HIDIsValidElement( inIOHIDElementRef )
|
||||
//
|
||||
// Purpose: validate this element
|
||||
//
|
||||
// Inputs: inIOHIDElementRef - the element
|
||||
//
|
||||
// Returns: Boolean - TRUE if this is a valid element ref
|
||||
//
|
||||
extern Boolean HIDIsValidElement(IOHIDElementRef inIOHIDElementRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_GetValue( inElementRef, inIOHIDValueScaleType )
|
||||
//
|
||||
// Purpose: returns the current value for an element( polling )
|
||||
//
|
||||
// Notes: will return 0 on error conditions which should be accounted for by application
|
||||
//
|
||||
// Inputs: inElementRef - the element
|
||||
// inIOHIDValueScaleType - scale type ( calibrated or physical )
|
||||
//
|
||||
// Returns: double - current value for element
|
||||
//
|
||||
extern double IOHIDElement_GetValue(IOHIDElementRef inElementRef, IOHIDValueScaleType inIOHIDValueScaleType);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_GetCalibrationMin( inElementRef )
|
||||
//
|
||||
// Purpose: get the minimum bounds for a calibrated value for this element
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
//
|
||||
// Returns: CFIndex - the minimum Calibration value for this element
|
||||
//
|
||||
|
||||
extern CFIndex IOHIDElement_GetCalibrationMin(IOHIDElementRef inElementRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_SetCalibrationMin( inElementRef, inValue )
|
||||
//
|
||||
// Purpose: set the minimum bounds for a calibrated value for this element
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
// inValue - the minimum bounds for a calibrated value for this element
|
||||
//
|
||||
// Returns: nothing
|
||||
//
|
||||
|
||||
extern void IOHIDElement_SetCalibrationMin(IOHIDElementRef inElementRef, CFIndex inValue);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_GetCalibrationMax( inElementRef )
|
||||
//
|
||||
// Purpose: get the maximum bounds for a calibrated value for this element
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
//
|
||||
// Returns: CFIndex - the maximum Calibration value for this element
|
||||
//
|
||||
|
||||
extern CFIndex IOHIDElement_GetCalibrationMax(IOHIDElementRef inElementRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_SetCalibrationMax( inElementRef, inValue )
|
||||
//
|
||||
// Purpose: set the maximum bounds for a calibrated value for this element
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
// inValue - the maximum Calibration value for this element
|
||||
//
|
||||
// Returns: nothing
|
||||
//
|
||||
|
||||
extern void IOHIDElement_SetCalibrationMax(IOHIDElementRef inElementRef, CFIndex inValue);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_GetCalibrationSaturationMin( inElementRef )
|
||||
//
|
||||
// Purpose: get the mininum tolerance to be used when calibrating a logical element value
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
//
|
||||
// Returns: CFIndex - the maximum Calibration value for this element
|
||||
//
|
||||
|
||||
extern CFIndex IOHIDElement_GetCalibrationSaturationMin(IOHIDElementRef inElementRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_SetCalibrationSaturationMin( inElementRef, inValue )
|
||||
//
|
||||
// Purpose: set the mininum tolerance to be used when calibrating a logical element value
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
// inValue - the maximum Calibration value for this element
|
||||
//
|
||||
// Returns: nothing
|
||||
//
|
||||
|
||||
extern void IOHIDElement_SetCalibrationSaturationMin(IOHIDElementRef inElementRef, CFIndex inValue);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_GetCalibrationSaturationMax( inElementRef )
|
||||
//
|
||||
// Purpose: get the maximum tolerance to be used when calibrating a logical element value
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
//
|
||||
// Returns: CFIndex - the maximum Calibration value for this element
|
||||
//
|
||||
|
||||
extern CFIndex IOHIDElement_GetCalibrationSaturationMax(IOHIDElementRef inElementRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_SetCalibrationSaturationMax( inElementRef, inValue )
|
||||
//
|
||||
// Purpose: set the maximum tolerance to be used when calibrating a logical element value
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
// inValue - the maximum Calibration value for this element
|
||||
//
|
||||
// Returns: nothing
|
||||
//
|
||||
|
||||
extern void IOHIDElement_SetCalibrationSaturationMax(IOHIDElementRef inElementRef, CFIndex inValue);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_GetCalibrationDeadZoneMin( inElementRef )
|
||||
//
|
||||
// Purpose: get the minimum bounds near the midpoint of a logical value in which the value is ignored
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
//
|
||||
// Returns: CFIndex - the maximum Calibration value for this element
|
||||
//
|
||||
|
||||
extern CFIndex IOHIDElement_GetCalibrationDeadZoneMin(IOHIDElementRef inElementRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_SetCalibrationDeadZoneMin( inElementRef, inValue )
|
||||
//
|
||||
// Purpose: set the minimum bounds near the midpoint of a logical value in which the value is ignored
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
// inValue - the maximum Calibration value for this element
|
||||
//
|
||||
// Returns: nothing
|
||||
//
|
||||
|
||||
extern void IOHIDElement_SetCalibrationDeadZoneMin(IOHIDElementRef inElementRef, CFIndex inValue);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_GetCalibrationDeadZoneMax( inElementRef )
|
||||
//
|
||||
// Purpose: get the maximum bounds near the midpoint of a logical value in which the value is ignored
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
//
|
||||
// Returns: CFIndex - the maximum Calibration value for this element
|
||||
//
|
||||
|
||||
extern CFIndex IOHIDElement_GetCalibrationDeadZoneMax(IOHIDElementRef inElementRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_SetCalibrationDeadZoneMax( inElementRef, inValue )
|
||||
//
|
||||
// Purpose: set the maximum bounds near the midpoint of a logical value in which the value is ignored
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
// inValue - the maximum Calibration value for this element
|
||||
//
|
||||
// Returns: nothing
|
||||
//
|
||||
|
||||
extern void IOHIDElement_SetCalibrationDeadZoneMax(IOHIDElementRef inElementRef, CFIndex inValue);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_GetCalibrationGranularity( inElementRef )
|
||||
//
|
||||
// Purpose: get the level of detail returned for a calibrated element value
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
//
|
||||
// Returns: double_t - the maximum Calibration value for this element
|
||||
//
|
||||
|
||||
extern double_t IOHIDElement_GetCalibrationGranularity(IOHIDElementRef inElementRef);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_SetCalibrationGranularity( inElementRef, inValue )
|
||||
//
|
||||
// Purpose: set the level of detail returned for a calibrated element value
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
// inValue - the the level of detail for this element
|
||||
//
|
||||
// Returns: nothing
|
||||
//
|
||||
|
||||
extern void IOHIDElement_SetCalibrationGranularity(IOHIDElementRef inElementRef, double_t inValue);
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// IOHIDElement_SetupCalibration( inElementRef )
|
||||
//
|
||||
// Purpose: set default values for the element calibration parameters
|
||||
//
|
||||
// Inputs: inElementRef - the IOHIDElementRef for this element
|
||||
//
|
||||
// Returns: nothing
|
||||
//
|
||||
|
||||
extern void IOHIDElement_SetupCalibration(IOHIDElementRef inIOHIDElementRef);
|
||||
|
||||
extern Boolean IOHIDElement_GetLongProperty(IOHIDElementRef inElementRef, CFStringRef inKey, long *outValue);
|
||||
extern void IOHIDElement_SetLongProperty(IOHIDElementRef inElementRef, CFStringRef inKey, long inValue);
|
||||
|
||||
//*****************************************************
|
||||
#if PRAGMA_STRUCT_ALIGN
|
||||
#pragma options align=reset
|
||||
#elif PRAGMA_STRUCT_PACKPUSH
|
||||
#pragma pack(pop)
|
||||
#elif PRAGMA_STRUCT_PACK
|
||||
#pragma pack()
|
||||
#endif
|
||||
|
||||
#ifdef PRAGMA_IMPORT_OFF
|
||||
#pragma import off
|
||||
#elif PRAGMA_IMPORT
|
||||
#pragma import reset
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __IOHIDElement___ //
|
111
src/cocoa/IOHIDLib_.h
Normal file
111
src/cocoa/IOHIDLib_.h
Normal file
|
@ -0,0 +1,111 @@
|
|||
// File: IOHIDLib_.h
|
||||
// Abstract: Single include file for all header files of IOHIDLib
|
||||
// Version: 2.0
|
||||
//
|
||||
// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
// Inc. ("Apple") in consideration of your agreement to the following
|
||||
// terms, and your use, installation, modification or redistribution of
|
||||
// this Apple software constitutes acceptance of these terms. If you do
|
||||
// not agree with these terms, please do not use, install, modify or
|
||||
// redistribute this Apple software.
|
||||
//
|
||||
// In consideration of your agreement to abide by the following terms, and
|
||||
// subject to these terms, Apple grants you a personal, non-exclusive
|
||||
// license, under Apple's copyrights in this original Apple software (the
|
||||
// "Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
// Software, with or without modifications, in source and/or binary forms;
|
||||
// provided that if you redistribute the Apple Software in its entirety and
|
||||
// without modifications, you must retain this notice and the following
|
||||
// text and disclaimers in all such redistributions of the Apple Software.
|
||||
// Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
// be used to endorse or promote products derived from the Apple Software
|
||||
// without specific prior written permission from Apple. Except as
|
||||
// expressly stated in this notice, no other rights or licenses, express or
|
||||
// implied, are granted by Apple herein, including but not limited to any
|
||||
// patent rights that may be infringed by your derivative works or by other
|
||||
// works in which the Apple Software may be incorporated.
|
||||
//
|
||||
// The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
//
|
||||
// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (C) 2009 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
//*****************************************************
|
||||
#ifndef __IOHIDLib___
|
||||
#define __IOHIDLib___
|
||||
|
||||
//*****************************************************
|
||||
#pragma mark - includes & imports
|
||||
//-----------------------------------------------------
|
||||
#include <IOKit/hid/IOHIDLib.h>
|
||||
|
||||
#include "IOHIDDevice_.h"
|
||||
#include "IOHIDElement_.h"
|
||||
|
||||
#include "ImmrHIDUtilAddOn.h"
|
||||
|
||||
//*****************************************************
|
||||
#if PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if PRAGMA_IMPORT
|
||||
#pragma import on
|
||||
#endif
|
||||
|
||||
#if PRAGMA_STRUCT_ALIGN
|
||||
#pragma options align=mac68k
|
||||
#elif PRAGMA_STRUCT_PACKPUSH
|
||||
#pragma pack(push, 2)
|
||||
#elif PRAGMA_STRUCT_PACK
|
||||
#pragma pack(2)
|
||||
#endif
|
||||
|
||||
//*****************************************************
|
||||
#pragma mark - typedef's, struct's, enums, defines, etc.
|
||||
//-----------------------------------------------------
|
||||
|
||||
//*****************************************************
|
||||
#pragma mark - exported globals
|
||||
//-----------------------------------------------------
|
||||
|
||||
//*****************************************************
|
||||
#pragma mark - exported function prototypes
|
||||
//-----------------------------------------------------
|
||||
|
||||
//*****************************************************
|
||||
#if PRAGMA_STRUCT_ALIGN
|
||||
#pragma options align=reset
|
||||
#elif PRAGMA_STRUCT_PACKPUSH
|
||||
#pragma pack(pop)
|
||||
#elif PRAGMA_STRUCT_PACK
|
||||
#pragma pack()
|
||||
#endif
|
||||
|
||||
#ifdef PRAGMA_IMPORT_OFF
|
||||
#pragma import off
|
||||
#elif PRAGMA_IMPORT
|
||||
#pragma import reset
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __IOHIDLib___
|
108
src/cocoa/ImmrHIDUtilAddOn.c
Normal file
108
src/cocoa/ImmrHIDUtilAddOn.c
Normal file
|
@ -0,0 +1,108 @@
|
|||
// File: ImmrHIDUtilAddOn.c
|
||||
// Abstract: Glue code to convert IOHIDDeviceRef's to (FFB) io_object_t's
|
||||
// Version: 2.0
|
||||
//
|
||||
// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
// Inc. ("Apple") in consideration of your agreement to the following
|
||||
// terms, and your use, installation, modification or redistribution of
|
||||
// this Apple software constitutes acceptance of these terms. If you do
|
||||
// not agree with these terms, please do not use, install, modify or
|
||||
// redistribute this Apple software.
|
||||
//
|
||||
// In consideration of your agreement to abide by the following terms, and
|
||||
// subject to these terms, Apple grants you a personal, non-exclusive
|
||||
// license, under Apple's copyrights in this original Apple software (the
|
||||
// "Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
// Software, with or without modifications, in source and/or binary forms;
|
||||
// provided that if you redistribute the Apple Software in its entirety and
|
||||
// without modifications, you must retain this notice and the following
|
||||
// text and disclaimers in all such redistributions of the Apple Software.
|
||||
// Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
// be used to endorse or promote products derived from the Apple Software
|
||||
// without specific prior written permission from Apple. Except as
|
||||
// expressly stated in this notice, no other rights or licenses, express or
|
||||
// implied, are granted by Apple herein, including but not limited to any
|
||||
// patent rights that may be infringed by your derivative works or by other
|
||||
// works in which the Apple Software may be incorporated.
|
||||
//
|
||||
// The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
//
|
||||
// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (C) 2009 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
//*****************************************************
|
||||
|
||||
#include <AvailabilityMacros.h>
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
|
||||
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach_error.h>
|
||||
|
||||
#include "ImmrHIDUtilAddOn.h"
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
//
|
||||
// AllocateHIDObjectFromIOHIDDeviceRef( )
|
||||
//
|
||||
// returns:
|
||||
// NULL, or acceptable io_object_t
|
||||
//
|
||||
//---------------------------------------------------------------------------------
|
||||
io_service_t AllocateHIDObjectFromIOHIDDeviceRef(IOHIDDeviceRef inIOHIDDeviceRef) {
|
||||
io_service_t result = 0L;
|
||||
if ( inIOHIDDeviceRef ) {
|
||||
// Set up the matching criteria for the devices we're interested in.
|
||||
// We are interested in instances of class IOHIDDevice.
|
||||
// matchingDict is consumed below( in IOServiceGetMatchingService )
|
||||
// so we have no leak here.
|
||||
CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOHIDDeviceKey);
|
||||
if ( matchingDict ) {
|
||||
// Add a key for locationID to our matching dictionary. This works for matching to
|
||||
// IOHIDDevices, so we will only look for a device attached to that particular port
|
||||
// on the machine.
|
||||
CFTypeRef tCFTypeRef = IOHIDDeviceGetProperty( inIOHIDDeviceRef, CFSTR(kIOHIDLocationIDKey) );
|
||||
if ( tCFTypeRef ) {
|
||||
CFDictionaryAddValue(matchingDict, CFSTR(kIOHIDLocationIDKey), tCFTypeRef);
|
||||
// CFRelease( tCFTypeRef ); // don't release objects that we "Get".
|
||||
|
||||
// IOServiceGetMatchingService assumes that we already know that there is only one device
|
||||
// that matches. This way we don't have to do the whole iteration dance to look at each
|
||||
// device that matches. This is a new API in 10.2
|
||||
result = IOServiceGetMatchingService(kIOMasterPortDefault, matchingDict);
|
||||
}
|
||||
|
||||
// Note: We're not leaking the matchingDict.
|
||||
// One reference is consumed by IOServiceGetMatchingServices
|
||||
}
|
||||
}
|
||||
|
||||
return (result);
|
||||
} // AllocateHIDObjectFromIOHIDDeviceRef
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
//
|
||||
// FreeHIDObject( )
|
||||
//
|
||||
//---------------------------------------------------------------------------------
|
||||
bool FreeHIDObject(io_service_t inHIDObject) {
|
||||
kern_return_t kr;
|
||||
|
||||
kr = IOObjectRelease(inHIDObject);
|
||||
|
||||
return (kIOReturnSuccess == kr);
|
||||
} // FreeHIDObject
|
||||
|
||||
#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
|
50
src/cocoa/ImmrHIDUtilAddOn.h
Normal file
50
src/cocoa/ImmrHIDUtilAddOn.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
// File: ImmrHIDUtilAddOn.h
|
||||
// Abstract: Glue code to convert IOHIDDeviceRef's to (FFB) io_object_t's
|
||||
// Version: 2.0
|
||||
//
|
||||
// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
// Inc. ("Apple") in consideration of your agreement to the following
|
||||
// terms, and your use, installation, modification or redistribution of
|
||||
// this Apple software constitutes acceptance of these terms. If you do
|
||||
// not agree with these terms, please do not use, install, modify or
|
||||
// redistribute this Apple software.
|
||||
//
|
||||
// In consideration of your agreement to abide by the following terms, and
|
||||
// subject to these terms, Apple grants you a personal, non-exclusive
|
||||
// license, under Apple's copyrights in this original Apple software (the
|
||||
// "Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
// Software, with or without modifications, in source and/or binary forms;
|
||||
// provided that if you redistribute the Apple Software in its entirety and
|
||||
// without modifications, you must retain this notice and the following
|
||||
// text and disclaimers in all such redistributions of the Apple Software.
|
||||
// Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
// be used to endorse or promote products derived from the Apple Software
|
||||
// without specific prior written permission from Apple. Except as
|
||||
// expressly stated in this notice, no other rights or licenses, express or
|
||||
// implied, are granted by Apple herein, including but not limited to any
|
||||
// patent rights that may be infringed by your derivative works or by other
|
||||
// works in which the Apple Software may be incorporated.
|
||||
//
|
||||
// The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
//
|
||||
// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (C) 2009 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
//*****************************************************
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOKit/hid/IOHIDLib.h>
|
||||
|
||||
extern io_service_t AllocateHIDObjectFromIOHIDDeviceRef(IOHIDDeviceRef inIOHIDDeviceRef);
|
||||
extern bool FreeHIDObject(io_object_t inHIDObject);
|
2179
src/cocoa/i_backend_cocoa.mm
Normal file
2179
src/cocoa/i_backend_cocoa.mm
Normal file
File diff suppressed because it is too large
Load diff
830
src/cocoa/i_joystick.cpp
Normal file
830
src/cocoa/i_joystick.cpp
Normal file
|
@ -0,0 +1,830 @@
|
|||
/*
|
||||
** i_joystick.cpp
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2012-2014 Alexey Lysiuk
|
||||
** 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 "m_joy.h"
|
||||
|
||||
#include <AvailabilityMacros.h>
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
|
||||
|
||||
#include "HID_Utilities_External.h"
|
||||
|
||||
#include "d_event.h"
|
||||
#include "doomdef.h"
|
||||
#include "templates.h"
|
||||
#include "i_osversion.h"
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
FString ToFString( const CFStringRef string )
|
||||
{
|
||||
if ( NULL == string )
|
||||
{
|
||||
return FString();
|
||||
}
|
||||
|
||||
const CFIndex stringLength = CFStringGetLength( string );
|
||||
|
||||
if ( 0 == stringLength )
|
||||
{
|
||||
return FString();
|
||||
}
|
||||
|
||||
const size_t bufferSize = CFStringGetMaximumSizeForEncoding( stringLength, kCFStringEncodingUTF8 ) + 1;
|
||||
|
||||
char buffer[ bufferSize ];
|
||||
memset( buffer, 0, bufferSize );
|
||||
|
||||
CFStringGetCString( string, buffer, bufferSize, kCFStringEncodingUTF8 );
|
||||
|
||||
return FString( buffer );
|
||||
}
|
||||
|
||||
|
||||
class IOKitJoystick : public IJoystickConfig
|
||||
{
|
||||
public:
|
||||
explicit IOKitJoystick( IOHIDDeviceRef device );
|
||||
virtual ~IOKitJoystick();
|
||||
|
||||
virtual FString GetName();
|
||||
virtual float GetSensitivity();
|
||||
virtual void SetSensitivity( float scale );
|
||||
|
||||
virtual int GetNumAxes();
|
||||
virtual float GetAxisDeadZone( int axis );
|
||||
virtual EJoyAxis GetAxisMap( int axis );
|
||||
virtual const char* GetAxisName( int axis );
|
||||
virtual float GetAxisScale( int axis );
|
||||
|
||||
virtual void SetAxisDeadZone( int axis, float deadZone );
|
||||
virtual void SetAxisMap( int axis, EJoyAxis gameAxis );
|
||||
virtual void SetAxisScale( int axis, float scale );
|
||||
|
||||
virtual bool IsSensitivityDefault();
|
||||
virtual bool IsAxisDeadZoneDefault( int axis );
|
||||
virtual bool IsAxisMapDefault( int axis );
|
||||
virtual bool IsAxisScaleDefault( int axis );
|
||||
|
||||
virtual void SetDefaultConfig();
|
||||
virtual FString GetIdentifier();
|
||||
|
||||
void AddAxes( float axes[ NUM_JOYAXIS ] ) const;
|
||||
|
||||
void Update();
|
||||
|
||||
private:
|
||||
IOHIDDeviceRef m_device;
|
||||
|
||||
float m_sensitivity;
|
||||
|
||||
struct AxisInfo
|
||||
{
|
||||
char name[ 64 ];
|
||||
|
||||
float value;
|
||||
|
||||
float deadZone;
|
||||
float defaultDeadZone;
|
||||
float sensitivity;
|
||||
float defaultSensitivity;
|
||||
|
||||
EJoyAxis gameAxis;
|
||||
EJoyAxis defaultGameAxis;
|
||||
|
||||
IOHIDElementRef element;
|
||||
};
|
||||
|
||||
TArray< AxisInfo > m_axes;
|
||||
|
||||
TArray< IOHIDElementRef > m_buttons;
|
||||
TArray< IOHIDElementRef > m_POVs;
|
||||
|
||||
|
||||
static const float DEFAULT_DEADZONE;
|
||||
static const float DEFAULT_SENSITIVITY;
|
||||
|
||||
|
||||
bool ProcessAxis ( const IOHIDValueRef value );
|
||||
bool ProcessButton( const IOHIDValueRef value );
|
||||
bool ProcessPOV ( const IOHIDValueRef value );
|
||||
|
||||
};
|
||||
|
||||
|
||||
const float IOKitJoystick::DEFAULT_DEADZONE = 0.25f;
|
||||
const float IOKitJoystick::DEFAULT_SENSITIVITY = 1.0f;
|
||||
|
||||
|
||||
IOKitJoystick::IOKitJoystick( IOHIDDeviceRef device )
|
||||
: m_device( device )
|
||||
, m_sensitivity( DEFAULT_SENSITIVITY )
|
||||
{
|
||||
assert(NULL != device);
|
||||
assert(IOHIDDeviceGetTypeID() == CFGetTypeID(device));
|
||||
|
||||
CFArrayRef elements = IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone);
|
||||
assert(NULL != elements);
|
||||
assert(CFArrayGetTypeID() == CFGetTypeID(elements));
|
||||
|
||||
for (CFIndex i = 0, count = CFArrayGetCount(elements); i < count; ++i)
|
||||
{
|
||||
const IOHIDElementRef element =
|
||||
static_cast<IOHIDElementRef>(const_cast<void*>(CFArrayGetValueAtIndex(elements, i)));
|
||||
assert(NULL != element);
|
||||
assert(IOHIDElementGetTypeID() == CFGetTypeID(element));
|
||||
|
||||
const uint32_t usagePage = IOHIDElementGetUsagePage( element );
|
||||
|
||||
if ( kHIDPage_GenericDesktop == usagePage )
|
||||
{
|
||||
const uint32_t usage = IOHIDElementGetUsage( element );
|
||||
|
||||
if ( kHIDUsage_GD_Slider == usage
|
||||
|| kHIDUsage_GD_X == usage || kHIDUsage_GD_Y == usage || kHIDUsage_GD_Z == usage
|
||||
|| kHIDUsage_GD_Rx == usage || kHIDUsage_GD_Ry == usage || kHIDUsage_GD_Rz == usage )
|
||||
{
|
||||
AxisInfo axis;
|
||||
memset( &axis, 0, sizeof( axis ) );
|
||||
|
||||
if ( const CFStringRef name = IOHIDElementGetName( element ) )
|
||||
{
|
||||
CFStringGetCString( name, axis.name, sizeof( axis.name ) - 1, kCFStringEncodingUTF8 );
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf( axis.name, sizeof( axis.name ), "Axis %i", m_axes.Size() + 1 );
|
||||
}
|
||||
|
||||
axis.element = element;
|
||||
|
||||
m_axes.Push( axis );
|
||||
|
||||
IOHIDElement_SetCalibrationMin( element, -1 );
|
||||
IOHIDElement_SetCalibrationMax( element, 1 );
|
||||
|
||||
HIDQueueElement( m_device, element );
|
||||
}
|
||||
else if ( kHIDUsage_GD_Hatswitch == usage && m_POVs.Size() < 4 )
|
||||
{
|
||||
m_POVs.Push( element );
|
||||
|
||||
HIDQueueElement( m_device, element );
|
||||
}
|
||||
}
|
||||
else if ( kHIDPage_Button == usagePage )
|
||||
{
|
||||
m_buttons.Push( element );
|
||||
|
||||
HIDQueueElement( m_device, element );
|
||||
}
|
||||
}
|
||||
|
||||
CFRelease(elements);
|
||||
|
||||
SetDefaultConfig();
|
||||
}
|
||||
|
||||
IOKitJoystick::~IOKitJoystick()
|
||||
{
|
||||
M_SaveJoystickConfig( this );
|
||||
}
|
||||
|
||||
|
||||
FString IOKitJoystick::GetName()
|
||||
{
|
||||
FString result;
|
||||
|
||||
result += ToFString( IOHIDDevice_GetManufacturer( m_device ) );
|
||||
result += " ";
|
||||
result += ToFString( IOHIDDevice_GetProduct( m_device ) );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
float IOKitJoystick::GetSensitivity()
|
||||
{
|
||||
return m_sensitivity;
|
||||
}
|
||||
|
||||
void IOKitJoystick::SetSensitivity( float scale )
|
||||
{
|
||||
m_sensitivity = scale;
|
||||
}
|
||||
|
||||
|
||||
int IOKitJoystick::GetNumAxes()
|
||||
{
|
||||
return static_cast< int >( m_axes.Size() );
|
||||
}
|
||||
|
||||
#define IS_AXIS_VALID ( static_cast< unsigned int >( axis ) < m_axes.Size() )
|
||||
|
||||
float IOKitJoystick::GetAxisDeadZone( int axis )
|
||||
{
|
||||
return IS_AXIS_VALID ? m_axes[ axis ].deadZone : 0.0f;
|
||||
}
|
||||
|
||||
EJoyAxis IOKitJoystick::GetAxisMap( int axis )
|
||||
{
|
||||
return IS_AXIS_VALID ? m_axes[ axis ].gameAxis : JOYAXIS_None;
|
||||
}
|
||||
|
||||
const char* IOKitJoystick::GetAxisName( int axis )
|
||||
{
|
||||
return IS_AXIS_VALID ? m_axes[ axis ].name : "Invalid";
|
||||
}
|
||||
|
||||
float IOKitJoystick::GetAxisScale( int axis )
|
||||
{
|
||||
return IS_AXIS_VALID ? m_axes[ axis ].sensitivity : 0.0f;
|
||||
}
|
||||
|
||||
void IOKitJoystick::SetAxisDeadZone( int axis, float deadZone )
|
||||
{
|
||||
if ( IS_AXIS_VALID )
|
||||
{
|
||||
m_axes[ axis ].deadZone = clamp( deadZone, 0.0f, 1.0f );
|
||||
}
|
||||
}
|
||||
|
||||
void IOKitJoystick::SetAxisMap( int axis, EJoyAxis gameAxis )
|
||||
{
|
||||
if ( IS_AXIS_VALID )
|
||||
{
|
||||
m_axes[ axis ].gameAxis = ( gameAxis > JOYAXIS_None && gameAxis < NUM_JOYAXIS )
|
||||
? gameAxis
|
||||
: JOYAXIS_None;
|
||||
}
|
||||
}
|
||||
|
||||
void IOKitJoystick::SetAxisScale( int axis, float scale )
|
||||
{
|
||||
if ( IS_AXIS_VALID )
|
||||
{
|
||||
m_axes[ axis ].sensitivity = scale;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool IOKitJoystick::IsSensitivityDefault()
|
||||
{
|
||||
return DEFAULT_SENSITIVITY == m_sensitivity;
|
||||
}
|
||||
|
||||
bool IOKitJoystick::IsAxisDeadZoneDefault( int axis )
|
||||
{
|
||||
return IS_AXIS_VALID
|
||||
? ( m_axes[ axis ].deadZone == m_axes[ axis ].defaultDeadZone )
|
||||
: true;
|
||||
}
|
||||
|
||||
bool IOKitJoystick::IsAxisMapDefault( int axis )
|
||||
{
|
||||
return IS_AXIS_VALID
|
||||
? ( m_axes[ axis ].gameAxis == m_axes[ axis ].defaultGameAxis )
|
||||
: true;
|
||||
}
|
||||
|
||||
bool IOKitJoystick::IsAxisScaleDefault( int axis )
|
||||
{
|
||||
return IS_AXIS_VALID
|
||||
? ( m_axes[ axis ].sensitivity == m_axes[ axis ].defaultSensitivity )
|
||||
: true;
|
||||
}
|
||||
|
||||
#undef IS_AXIS_VALID
|
||||
|
||||
void IOKitJoystick::SetDefaultConfig()
|
||||
{
|
||||
m_sensitivity = DEFAULT_SENSITIVITY;
|
||||
|
||||
const size_t axisCount = m_axes.Size();
|
||||
|
||||
for ( size_t i = 0; i < axisCount; ++i )
|
||||
{
|
||||
m_axes[i].deadZone = DEFAULT_DEADZONE;
|
||||
m_axes[i].sensitivity = DEFAULT_SENSITIVITY;
|
||||
m_axes[i].gameAxis = JOYAXIS_None;
|
||||
}
|
||||
|
||||
// Two axes? Horizontal is yaw and vertical is forward.
|
||||
|
||||
if ( 2 == axisCount)
|
||||
{
|
||||
m_axes[0].gameAxis = JOYAXIS_Yaw;
|
||||
m_axes[1].gameAxis = JOYAXIS_Forward;
|
||||
}
|
||||
|
||||
// Three axes? First two are movement, third is yaw.
|
||||
|
||||
else if ( axisCount >= 3 )
|
||||
{
|
||||
m_axes[0].gameAxis = JOYAXIS_Side;
|
||||
m_axes[1].gameAxis = JOYAXIS_Forward;
|
||||
m_axes[2].gameAxis = JOYAXIS_Yaw;
|
||||
|
||||
// Four axes? First two are movement, last two are looking around.
|
||||
|
||||
if ( axisCount >= 4 )
|
||||
{
|
||||
m_axes[3].gameAxis = JOYAXIS_Pitch;
|
||||
// ??? m_axes[3].sensitivity = 0.75f;
|
||||
|
||||
// Five axes? Use the fifth one for moving up and down.
|
||||
|
||||
if ( axisCount >= 5 )
|
||||
{
|
||||
m_axes[4].gameAxis = JOYAXIS_Up;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there is only one axis, then we make no assumptions about how
|
||||
// the user might want to use it.
|
||||
|
||||
// Preserve defaults for config saving.
|
||||
|
||||
for ( size_t i = 0; i < axisCount; ++i )
|
||||
{
|
||||
m_axes[i].defaultDeadZone = m_axes[i].deadZone;
|
||||
m_axes[i].defaultSensitivity = m_axes[i].sensitivity;
|
||||
m_axes[i].defaultGameAxis = m_axes[i].gameAxis;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FString IOKitJoystick::GetIdentifier()
|
||||
{
|
||||
char identifier[ 32 ] = {0};
|
||||
|
||||
snprintf( identifier, sizeof( identifier ), "VID_%04x_PID_%04x",
|
||||
IOHIDDevice_GetVendorID( m_device ), IOHIDDevice_GetProductID( m_device ) );
|
||||
|
||||
return FString( identifier );
|
||||
}
|
||||
|
||||
|
||||
void IOKitJoystick::AddAxes( float axes[ NUM_JOYAXIS ] ) const
|
||||
{
|
||||
for ( size_t i = 0, count = m_axes.Size(); i < count; ++i )
|
||||
{
|
||||
const EJoyAxis axis = m_axes[i].gameAxis;
|
||||
|
||||
if ( JOYAXIS_None == axis )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
axes[ axis ] -= m_axes[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void IOKitJoystick::Update()
|
||||
{
|
||||
IOHIDValueRef value = NULL;
|
||||
|
||||
while ( HIDGetEvent( m_device, &value ) && NULL != value )
|
||||
{
|
||||
ProcessAxis( value ) || ProcessButton( value ) || ProcessPOV( value );
|
||||
|
||||
CFRelease( value );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool IOKitJoystick::ProcessAxis( const IOHIDValueRef value )
|
||||
{
|
||||
const IOHIDElementRef element = IOHIDValueGetElement( value );
|
||||
|
||||
if ( NULL == element )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for ( size_t i = 0, count = m_axes.Size(); i < count; ++i )
|
||||
{
|
||||
if ( element != m_axes[i].element )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
AxisInfo& axis = m_axes[i];
|
||||
|
||||
const double scaledValue = IOHIDValueGetScaledValue( value, kIOHIDValueScaleTypeCalibrated );
|
||||
const double filteredValue = Joy_RemoveDeadZone( scaledValue, axis.deadZone, NULL );
|
||||
|
||||
axis.value = static_cast< float >( filteredValue * m_sensitivity * axis.sensitivity );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IOKitJoystick::ProcessButton( const IOHIDValueRef value )
|
||||
{
|
||||
const IOHIDElementRef element = IOHIDValueGetElement( value );
|
||||
|
||||
if ( NULL == element )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for ( size_t i = 0, count = m_buttons.Size(); i < count; ++i )
|
||||
{
|
||||
if ( element != m_buttons[i] )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const int newButton = IOHIDValueGetIntegerValue( value ) & 1;
|
||||
const int oldButton = ~newButton;
|
||||
|
||||
Joy_GenerateButtonEvents( oldButton, newButton, 1,
|
||||
static_cast< int >( KEY_FIRSTJOYBUTTON + i ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IOKitJoystick::ProcessPOV( const IOHIDValueRef value )
|
||||
{
|
||||
const IOHIDElementRef element = IOHIDValueGetElement( value );
|
||||
|
||||
if ( NULL == element )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for ( size_t i = 0, count = m_POVs.Size(); i < count; ++i )
|
||||
{
|
||||
if ( element != m_POVs[i] )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const CFIndex direction = IOHIDValueGetIntegerValue( value );
|
||||
|
||||
// Default values is for Up/North
|
||||
int oldButtons = 0;
|
||||
int newButtons = 1;
|
||||
int numButtons = 1;
|
||||
int baseButton = KEY_JOYPOV1_UP;
|
||||
|
||||
switch ( direction )
|
||||
{
|
||||
case 0: // N
|
||||
break;
|
||||
|
||||
case 1: // NE
|
||||
newButtons = 3;
|
||||
numButtons = 2;
|
||||
break;
|
||||
|
||||
case 2: // E
|
||||
baseButton = KEY_JOYPOV1_RIGHT;
|
||||
break;
|
||||
|
||||
case 3: // SE
|
||||
newButtons = 3;
|
||||
numButtons = 2;
|
||||
baseButton = KEY_JOYPOV1_RIGHT;
|
||||
break;
|
||||
|
||||
case 4: // S
|
||||
baseButton = KEY_JOYPOV1_DOWN;
|
||||
break;
|
||||
|
||||
case 5: // SW
|
||||
newButtons = 3;
|
||||
numButtons = 2;
|
||||
baseButton = KEY_JOYPOV1_DOWN;
|
||||
break;
|
||||
|
||||
case 6: // W
|
||||
baseButton = KEY_JOYPOV1_LEFT;
|
||||
break;
|
||||
|
||||
case 7: // NW
|
||||
newButtons = 9; // UP and LEFT
|
||||
numButtons = 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
// release all four directions
|
||||
oldButtons = 15;
|
||||
newButtons = 0;
|
||||
numButtons = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
Joy_GenerateButtonEvents( oldButtons, newButtons, numButtons,
|
||||
static_cast< int >( baseButton + i * 4 ) );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class IOKitJoystickManager
|
||||
{
|
||||
public:
|
||||
IOKitJoystickManager();
|
||||
~IOKitJoystickManager();
|
||||
|
||||
void GetJoysticks( TArray< IJoystickConfig* >& joysticks ) const;
|
||||
|
||||
void AddAxes( float axes[ NUM_JOYAXIS ] ) const;
|
||||
|
||||
// Updates axes/buttons states
|
||||
void Update();
|
||||
|
||||
// Rebuilds device list
|
||||
void Rescan();
|
||||
|
||||
private:
|
||||
TArray< IOKitJoystick* > m_joysticks;
|
||||
|
||||
static void OnDeviceChanged( void* context, IOReturn result, void* sender, IOHIDDeviceRef device );
|
||||
|
||||
void ReleaseJoysticks();
|
||||
|
||||
void EnableCallbacks();
|
||||
void DisableCallbacks();
|
||||
|
||||
};
|
||||
|
||||
|
||||
IOKitJoystickManager::IOKitJoystickManager()
|
||||
{
|
||||
Rescan();
|
||||
}
|
||||
|
||||
IOKitJoystickManager::~IOKitJoystickManager()
|
||||
{
|
||||
ReleaseJoysticks();
|
||||
DisableCallbacks();
|
||||
|
||||
HIDReleaseDeviceList();
|
||||
}
|
||||
|
||||
|
||||
void IOKitJoystickManager::GetJoysticks( TArray< IJoystickConfig* >& joysticks ) const
|
||||
{
|
||||
const size_t joystickCount = m_joysticks.Size();
|
||||
|
||||
joysticks.Resize( joystickCount );
|
||||
|
||||
for ( size_t i = 0; i < joystickCount; ++i )
|
||||
{
|
||||
M_LoadJoystickConfig( m_joysticks[i] );
|
||||
|
||||
joysticks[i] = m_joysticks[i];
|
||||
}
|
||||
}
|
||||
|
||||
void IOKitJoystickManager::AddAxes( float axes[ NUM_JOYAXIS ] ) const
|
||||
{
|
||||
for ( size_t i = 0, count = m_joysticks.Size(); i < count; ++i )
|
||||
{
|
||||
m_joysticks[i]->AddAxes( axes );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void IOKitJoystickManager::Update()
|
||||
{
|
||||
for ( size_t i = 0, count = m_joysticks.Size(); i < count; ++i )
|
||||
{
|
||||
m_joysticks[i]->Update();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void IOKitJoystickManager::Rescan()
|
||||
{
|
||||
ReleaseJoysticks();
|
||||
DisableCallbacks();
|
||||
|
||||
const int usageCount = 2;
|
||||
|
||||
const UInt32 usagePages[ usageCount ] =
|
||||
{
|
||||
kHIDPage_GenericDesktop,
|
||||
kHIDPage_GenericDesktop
|
||||
};
|
||||
|
||||
const UInt32 usages[ usageCount ] =
|
||||
{
|
||||
kHIDUsage_GD_Joystick,
|
||||
kHIDUsage_GD_GamePad
|
||||
};
|
||||
|
||||
if ( HIDUpdateDeviceList( usagePages, usages, usageCount ) )
|
||||
{
|
||||
IOHIDDeviceRef device = HIDGetFirstDevice();
|
||||
|
||||
while ( NULL != device )
|
||||
{
|
||||
IOKitJoystick* joystick = new IOKitJoystick( device );
|
||||
m_joysticks.Push( joystick );
|
||||
|
||||
device = HIDGetNextDevice( device );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf( "IOKitJoystickManager: Failed to build gamepad/joystick device list.\n" );
|
||||
}
|
||||
|
||||
EnableCallbacks();
|
||||
}
|
||||
|
||||
|
||||
void IOKitJoystickManager::OnDeviceChanged( void* context, IOReturn result, void* sender, IOHIDDeviceRef device )
|
||||
{
|
||||
event_t event;
|
||||
|
||||
memset( &event, 0, sizeof( event ) );
|
||||
event.type = EV_DeviceChange;
|
||||
|
||||
D_PostEvent( &event );
|
||||
}
|
||||
|
||||
|
||||
void IOKitJoystickManager::ReleaseJoysticks()
|
||||
{
|
||||
for ( size_t i = 0, count = m_joysticks.Size(); i < count; ++i )
|
||||
{
|
||||
delete m_joysticks[i];
|
||||
}
|
||||
|
||||
m_joysticks.Clear();
|
||||
}
|
||||
|
||||
|
||||
void IOKitJoystickManager::EnableCallbacks()
|
||||
{
|
||||
if ( NULL == gIOHIDManagerRef )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IOHIDManagerRegisterDeviceMatchingCallback( gIOHIDManagerRef, OnDeviceChanged, this );
|
||||
IOHIDManagerRegisterDeviceRemovalCallback ( gIOHIDManagerRef, OnDeviceChanged, this );
|
||||
IOHIDManagerScheduleWithRunLoop( gIOHIDManagerRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode );
|
||||
}
|
||||
|
||||
void IOKitJoystickManager::DisableCallbacks()
|
||||
{
|
||||
if ( NULL == gIOHIDManagerRef )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IOHIDManagerUnscheduleFromRunLoop( gIOHIDManagerRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode );
|
||||
IOHIDManagerRegisterDeviceMatchingCallback( gIOHIDManagerRef, NULL, NULL );
|
||||
IOHIDManagerRegisterDeviceRemovalCallback ( gIOHIDManagerRef, NULL, NULL );
|
||||
}
|
||||
|
||||
|
||||
IOKitJoystickManager* s_joystickManager;
|
||||
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
void I_StartupJoysticks()
|
||||
{
|
||||
// HID Manager API is available on 10.5 (Darwin 9.x) or newer
|
||||
|
||||
if (darwinVersion.major >= 9)
|
||||
{
|
||||
s_joystickManager = new IOKitJoystickManager;
|
||||
}
|
||||
}
|
||||
|
||||
void I_ShutdownJoysticks()
|
||||
{
|
||||
delete s_joystickManager;
|
||||
}
|
||||
|
||||
void I_GetJoysticks( TArray< IJoystickConfig* >& sticks )
|
||||
{
|
||||
if ( NULL != s_joystickManager )
|
||||
{
|
||||
s_joystickManager->GetJoysticks( sticks );
|
||||
}
|
||||
}
|
||||
|
||||
void I_GetAxes( float axes[ NUM_JOYAXIS ] )
|
||||
{
|
||||
for ( size_t i = 0; i < NUM_JOYAXIS; ++i )
|
||||
{
|
||||
axes[i] = 0.0f;
|
||||
}
|
||||
|
||||
if ( use_joystick && NULL != s_joystickManager )
|
||||
{
|
||||
s_joystickManager->AddAxes( axes );
|
||||
}
|
||||
}
|
||||
|
||||
IJoystickConfig* I_UpdateDeviceList()
|
||||
{
|
||||
if ( use_joystick && NULL != s_joystickManager )
|
||||
{
|
||||
s_joystickManager->Rescan();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
void I_ProcessJoysticks()
|
||||
{
|
||||
if ( use_joystick && NULL != s_joystickManager )
|
||||
{
|
||||
s_joystickManager->Update();
|
||||
}
|
||||
}
|
||||
|
||||
#else // prior to 10.5
|
||||
|
||||
void I_StartupJoysticks()
|
||||
{
|
||||
}
|
||||
|
||||
void I_ShutdownJoysticks()
|
||||
{
|
||||
}
|
||||
|
||||
void I_GetJoysticks(TArray<IJoystickConfig*>& sticks)
|
||||
{
|
||||
sticks.Clear();
|
||||
}
|
||||
|
||||
void I_GetAxes(float axes[NUM_JOYAXIS])
|
||||
{
|
||||
for (size_t i = 0; i < NUM_JOYAXIS; ++i)
|
||||
{
|
||||
axes[i] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
IJoystickConfig *I_UpdateDeviceList()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void I_ProcessJoysticks()
|
||||
{
|
||||
}
|
||||
|
||||
#endif // 10.5 or higher
|
43
src/cocoa/i_osversion.h
Executable file
43
src/cocoa/i_osversion.h
Executable file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
** i_osversion.h
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2012-2014 Alexey Lysiuk
|
||||
** 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 <stdint.h>
|
||||
|
||||
struct DarwinVersion
|
||||
{
|
||||
uint16_t major;
|
||||
uint16_t minor;
|
||||
uint16_t bugfix;
|
||||
};
|
||||
|
||||
extern const DarwinVersion darwinVersion;
|
52
src/cocoa/i_rbopts.h
Normal file
52
src/cocoa/i_rbopts.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
** i_rbopts.h
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2014 Alexey Lysiuk
|
||||
** 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.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef SRC_COCOA_I_RBOPTS_H_INCLUDED
|
||||
#define SRC_COCOA_I_RBOPTS_H_INCLUDED
|
||||
|
||||
struct RenderBufferOptions
|
||||
{
|
||||
float pixelScale;
|
||||
|
||||
float shiftX;
|
||||
float shiftY;
|
||||
|
||||
float width;
|
||||
float height;
|
||||
|
||||
bool dirty;
|
||||
};
|
||||
|
||||
extern RenderBufferOptions rbOpts;
|
||||
|
||||
#endif // SRC_COCOA_I_RBOPTS_H_INCLUDED
|
190
src/cocoa/i_timer.cpp
Normal file
190
src/cocoa/i_timer.cpp
Normal file
|
@ -0,0 +1,190 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <sys/time.h>
|
||||
#include <pthread.h>
|
||||
#include <libkern/OSAtomic.h>
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "basictypes.h"
|
||||
#include "basicinlines.h"
|
||||
#include "doomdef.h"
|
||||
#include "i_system.h"
|
||||
#include "templates.h"
|
||||
|
||||
|
||||
unsigned int I_MSTime()
|
||||
{
|
||||
return SDL_GetTicks();
|
||||
}
|
||||
|
||||
unsigned int I_FPSTime()
|
||||
{
|
||||
return SDL_GetTicks();
|
||||
}
|
||||
|
||||
|
||||
bool g_isTicFrozen;
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
timespec GetNextTickTime()
|
||||
{
|
||||
static const long MILLISECONDS_IN_SECOND = 1000;
|
||||
static const long MICROSECONDS_IN_SECOND = 1000 * MILLISECONDS_IN_SECOND;
|
||||
static const long NANOSECONDS_IN_SECOND = 1000 * MICROSECONDS_IN_SECOND;
|
||||
|
||||
static timespec ts = {};
|
||||
|
||||
if (__builtin_expect((0 == ts.tv_sec), 0))
|
||||
{
|
||||
timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
ts.tv_sec = tv.tv_sec;
|
||||
ts.tv_nsec = (tv.tv_usec + MICROSECONDS_IN_SECOND / TICRATE) * MILLISECONDS_IN_SECOND;
|
||||
}
|
||||
else
|
||||
{
|
||||
ts.tv_nsec += (MICROSECONDS_IN_SECOND / TICRATE) * MILLISECONDS_IN_SECOND;
|
||||
}
|
||||
|
||||
if (ts.tv_nsec >= NANOSECONDS_IN_SECOND)
|
||||
{
|
||||
ts.tv_sec++;
|
||||
ts.tv_nsec -= NANOSECONDS_IN_SECOND;
|
||||
}
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
||||
pthread_cond_t s_timerEvent;
|
||||
pthread_mutex_t s_timerMutex;
|
||||
pthread_t s_timerThread;
|
||||
|
||||
bool s_timerInitialized;
|
||||
bool s_timerExitRequested;
|
||||
|
||||
uint32_t s_ticStart;
|
||||
uint32_t s_timerStart;
|
||||
|
||||
int s_tics;
|
||||
|
||||
|
||||
void* TimerThreadFunc(void*)
|
||||
{
|
||||
assert(s_timerInitialized);
|
||||
assert(!s_timerExitRequested);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (s_timerExitRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
const timespec timeToNextTick = GetNextTickTime();
|
||||
|
||||
pthread_mutex_lock(&s_timerMutex);
|
||||
pthread_cond_timedwait(&s_timerEvent, &s_timerMutex, &timeToNextTick);
|
||||
|
||||
if (!g_isTicFrozen)
|
||||
{
|
||||
// The following GCC/Clang intrinsic can be used instead of OS X specific function:
|
||||
// __sync_add_and_fetch(&s_tics, 1);
|
||||
// Although it's not supported on all platform/compiler combination,
|
||||
// e.g. GCC 4.0.1 with PowerPC target architecture
|
||||
|
||||
OSAtomicIncrement32(&s_tics);
|
||||
}
|
||||
|
||||
s_timerStart = SDL_GetTicks();
|
||||
|
||||
pthread_cond_broadcast(&s_timerEvent);
|
||||
pthread_mutex_unlock(&s_timerMutex);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int GetTimeThreaded(bool saveMS)
|
||||
{
|
||||
if (saveMS)
|
||||
{
|
||||
s_ticStart = s_timerStart;
|
||||
}
|
||||
|
||||
return s_tics;
|
||||
}
|
||||
|
||||
int WaitForTicThreaded(int prevTic)
|
||||
{
|
||||
assert(!g_isTicFrozen);
|
||||
|
||||
while (s_tics <= prevTic)
|
||||
{
|
||||
pthread_mutex_lock(&s_timerMutex);
|
||||
pthread_cond_wait(&s_timerEvent, &s_timerMutex);
|
||||
pthread_mutex_unlock(&s_timerMutex);
|
||||
}
|
||||
|
||||
return s_tics;
|
||||
}
|
||||
|
||||
void FreezeTimeThreaded(bool frozen)
|
||||
{
|
||||
g_isTicFrozen = frozen;
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
|
||||
fixed_t I_GetTimeFrac(uint32* ms)
|
||||
{
|
||||
const uint32_t now = SDL_GetTicks();
|
||||
|
||||
if (NULL != ms)
|
||||
{
|
||||
*ms = s_ticStart + 1000 / TICRATE;
|
||||
}
|
||||
|
||||
return 0 == s_ticStart
|
||||
? FRACUNIT
|
||||
: clamp<fixed_t>( (now - s_ticStart) * FRACUNIT * TICRATE / 1000, 0, FRACUNIT);
|
||||
}
|
||||
|
||||
|
||||
void I_InitTimer ()
|
||||
{
|
||||
assert(!s_timerInitialized);
|
||||
s_timerInitialized = true;
|
||||
|
||||
pthread_cond_init (&s_timerEvent, NULL);
|
||||
pthread_mutex_init(&s_timerMutex, NULL);
|
||||
|
||||
pthread_create(&s_timerThread, NULL, TimerThreadFunc, NULL);
|
||||
|
||||
I_GetTime = GetTimeThreaded;
|
||||
I_WaitForTic = WaitForTicThreaded;
|
||||
I_FreezeTime = FreezeTimeThreaded;
|
||||
}
|
||||
|
||||
void I_ShutdownTimer ()
|
||||
{
|
||||
if (!s_timerInitialized)
|
||||
{
|
||||
// This might happen if Cancel button was pressed
|
||||
// in the IWAD selector window
|
||||
return;
|
||||
}
|
||||
|
||||
s_timerExitRequested = true;
|
||||
|
||||
pthread_join(s_timerThread, NULL);
|
||||
|
||||
pthread_mutex_destroy(&s_timerMutex);
|
||||
pthread_cond_destroy (&s_timerEvent);
|
||||
}
|
47
src/cocoa/zdoom-info.plist
Normal file
47
src/cocoa/zdoom-info.plist
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>zdoom.icns</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.zdoom.zdoom</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>ZDoom</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>Version 2.8.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.action-games</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.4</string>
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>Doom Resource File</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>wad</string>
|
||||
<string>pk3</string>
|
||||
<string>zip</string>
|
||||
<string>pk7</string>
|
||||
<string>7z</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
BIN
src/cocoa/zdoom.icns
Normal file
BIN
src/cocoa/zdoom.icns
Normal file
Binary file not shown.
|
@ -81,6 +81,8 @@ enum
|
|||
CP_SECTORFLOOROFFSET,
|
||||
CP_SETWALLYSCALE,
|
||||
CP_SETTHINGZ,
|
||||
CP_SETTAG,
|
||||
CP_SETTHINGFLAGS,
|
||||
};
|
||||
|
||||
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
||||
|
@ -140,6 +142,7 @@ static FCompatOption Options[] =
|
|||
{ "maskedmidtex", COMPATF_MASKEDMIDTEX, SLOT_COMPAT },
|
||||
{ "badangles", COMPATF2_BADANGLES, SLOT_COMPAT2 },
|
||||
{ "floormove", COMPATF2_FLOORMOVE, SLOT_COMPAT2 },
|
||||
{ "soundcutoff", COMPATF2_SOUNDCUTOFF, SLOT_COMPAT2 },
|
||||
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
|
@ -307,6 +310,24 @@ void ParseCompatibility()
|
|||
sc.MustGetFloat();
|
||||
CompatParams.Push(FLOAT2FIXED(sc.Float));
|
||||
}
|
||||
else if (sc.Compare("setsectortag"))
|
||||
{
|
||||
if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size();
|
||||
CompatParams.Push(CP_SETTAG);
|
||||
sc.MustGetNumber();
|
||||
CompatParams.Push(sc.Number);
|
||||
sc.MustGetNumber();
|
||||
CompatParams.Push(sc.Number);
|
||||
}
|
||||
else if (sc.Compare("setthingflags"))
|
||||
{
|
||||
if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size();
|
||||
CompatParams.Push(CP_SETTHINGFLAGS);
|
||||
sc.MustGetNumber();
|
||||
CompatParams.Push(sc.Number);
|
||||
sc.MustGetNumber();
|
||||
CompatParams.Push(sc.Number);
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.UnGet();
|
||||
|
@ -520,6 +541,24 @@ void SetCompatibilityParams()
|
|||
i += 3;
|
||||
break;
|
||||
}
|
||||
case CP_SETTAG:
|
||||
{
|
||||
if ((unsigned)CompatParams[i + 1] < (unsigned)numsectors)
|
||||
{
|
||||
sectors[CompatParams[i + 1]].tag = CompatParams[i + 2];
|
||||
}
|
||||
i += 3;
|
||||
break;
|
||||
}
|
||||
case CP_SETTHINGFLAGS:
|
||||
{
|
||||
if ((unsigned)CompatParams[i + 1] < MapThingsConverted.Size())
|
||||
{
|
||||
MapThingsConverted[CompatParams[i + 1]].flags = CompatParams[i + 2];
|
||||
}
|
||||
i += 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,12 +145,20 @@ bool CT_Responder (event_t *ev)
|
|||
CT_BackSpace ();
|
||||
return true;
|
||||
}
|
||||
#ifdef __APPLE__
|
||||
else if (ev->data1 == 'C' && (ev->data3 & GKM_META))
|
||||
#else // !__APPLE__
|
||||
else if (ev->data1 == 'C' && (ev->data3 & GKM_CTRL))
|
||||
#endif // __APPLE__
|
||||
{
|
||||
I_PutInClipboard ((char *)ChatQueue);
|
||||
return true;
|
||||
}
|
||||
#ifdef __APPLE__
|
||||
else if (ev->data1 == 'V' && (ev->data3 & GKM_META))
|
||||
#else // !__APPLE__
|
||||
else if (ev->data1 == 'V' && (ev->data3 & GKM_CTRL))
|
||||
#endif // __APPLE__
|
||||
{
|
||||
CT_PasteChat(I_GetFromClipboard(false));
|
||||
}
|
||||
|
@ -273,7 +281,8 @@ void CT_Drawer (void)
|
|||
|
||||
if (players[consoleplayer].camera != NULL &&
|
||||
(Button_ShowScores.bDown ||
|
||||
players[consoleplayer].camera->health <= 0) &&
|
||||
players[consoleplayer].camera->health <= 0 ||
|
||||
SB_ForceActive) &&
|
||||
// Don't draw during intermission, since it has its own scoreboard in wi_stuff.cpp.
|
||||
gamestate != GS_INTERMISSION)
|
||||
{
|
||||
|
|
|
@ -2154,6 +2154,13 @@ static int PatchText (int oldSize)
|
|||
{
|
||||
strncpy (deh.PlayerSprite, newStr, 4);
|
||||
}
|
||||
for (unsigned ii = 0; ii < OrgSprNames.Size(); ii++)
|
||||
{
|
||||
if (!stricmp(OrgSprNames[ii].c, oldStr))
|
||||
{
|
||||
strcpy(OrgSprNames[ii].c, newStr);
|
||||
}
|
||||
}
|
||||
// If this sprite is used by a pickup, then the DehackedPickup sprite map
|
||||
// needs to be updated too.
|
||||
for (i = 0; (size_t)i < countof(DehSpriteMappings); ++i)
|
||||
|
@ -2240,7 +2247,10 @@ static int PatchStrings (int dummy)
|
|||
|
||||
ReplaceSpecialChars (holdstring.LockBuffer());
|
||||
holdstring.UnlockBuffer();
|
||||
GStrings.SetString (Line1, holdstring);
|
||||
// Account for a discrepancy between Boom's and ZDoom's name for the red skull key pickup message
|
||||
const char *ll = Line1;
|
||||
if (!stricmp(ll, "GOTREDSKULL")) ll = "GOTREDSKUL";
|
||||
GStrings.SetString (ll, holdstring);
|
||||
DPrintf ("%s set to:\n%s\n", Line1, holdstring.GetChars());
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ typedef enum
|
|||
ga_loadlevel,
|
||||
ga_newgame,
|
||||
ga_newgame2,
|
||||
ga_recordgame,
|
||||
ga_loadgame,
|
||||
ga_loadgamehidecon,
|
||||
ga_loadgameplaydemo,
|
||||
|
|
|
@ -70,7 +70,8 @@ enum GUIKeyModifiers
|
|||
GKM_SHIFT = 1,
|
||||
GKM_CTRL = 2,
|
||||
GKM_ALT = 4,
|
||||
GKM_LBUTTON = 8
|
||||
GKM_META = 8,
|
||||
GKM_LBUTTON = 16
|
||||
};
|
||||
|
||||
// Special codes for some GUI keys, including a few real ASCII codes.
|
||||
|
|
|
@ -430,27 +430,11 @@ int FIWadManager::IdentifyVersion (TArray<FString> &wadfiles, const char *iwad,
|
|||
}
|
||||
}
|
||||
}
|
||||
#ifdef _WIN32
|
||||
FString steam_path = I_GetSteamPath();
|
||||
if (steam_path.IsNotEmpty())
|
||||
TArray<FString> steam_path = I_GetSteamPath();
|
||||
for (i = 0; i < steam_path.Size(); ++i)
|
||||
{
|
||||
static const char *const steam_dirs[] =
|
||||
{
|
||||
"doom 2/base",
|
||||
"final doom/base",
|
||||
"heretic shadow of the serpent riders/base",
|
||||
"hexen/base",
|
||||
"hexen deathkings of the dark citadel/base",
|
||||
"ultimate doom/base",
|
||||
"DOOM 3 BFG Edition/base/wads"
|
||||
};
|
||||
steam_path += "/SteamApps/common/";
|
||||
for (i = 0; i < countof(steam_dirs); ++i)
|
||||
{
|
||||
CheckIWAD (steam_path + steam_dirs[i], &wads[0]);
|
||||
}
|
||||
CheckIWAD (steam_path[i], &wads[0]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (iwadparm != NULL && !wads[0].Path.IsEmpty())
|
||||
|
|
|
@ -466,7 +466,7 @@ CUSTOM_CVAR (Int, dmflags2, 0, CVAR_SERVERINFO)
|
|||
}
|
||||
|
||||
// Come out of chasecam mode if we're not allowed to use chasecam.
|
||||
if (!(dmflags2 & DF2_CHASECAM) && !G_SkillProperty (SKILLP_DisableCheats) && !sv_cheats)
|
||||
if (!(dmflags2 & DF2_CHASECAM) && CheckCheatmode(false))
|
||||
{
|
||||
// Take us out of chasecam mode only.
|
||||
if (p->cheats & CF_CHASECAM)
|
||||
|
@ -620,6 +620,7 @@ CVAR (Flag, compat_polyobj, compatflags, COMPATF_POLYOBJ);
|
|||
CVAR (Flag, compat_maskedmidtex, compatflags, COMPATF_MASKEDMIDTEX);
|
||||
CVAR (Flag, compat_badangles, compatflags2, COMPATF2_BADANGLES);
|
||||
CVAR (Flag, compat_floormove, compatflags2, COMPATF2_FLOORMOVE);
|
||||
CVAR (Flag, compat_soundcutoff, compatflags2, COMPATF2_SOUNDCUTOFF);
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -756,9 +757,9 @@ void D_Display ()
|
|||
}
|
||||
screen->SetBlendingRect(viewwindowx, viewwindowy,
|
||||
viewwindowx + viewwidth, viewwindowy + viewheight);
|
||||
P_PredictPlayer(&players[consoleplayer]);
|
||||
|
||||
Renderer->RenderView(&players[consoleplayer]);
|
||||
P_UnPredictPlayer();
|
||||
|
||||
if ((hw2d = screen->Begin2D(viewactive)))
|
||||
{
|
||||
// Redraw everything every frame when using 2D accel
|
||||
|
@ -832,15 +833,23 @@ void D_Display ()
|
|||
}
|
||||
}
|
||||
// draw pause pic
|
||||
if (paused && menuactive == MENU_Off)
|
||||
if ((paused || pauseext) && menuactive == MENU_Off)
|
||||
{
|
||||
FTexture *tex;
|
||||
int x;
|
||||
FString pstring = "By ";
|
||||
|
||||
tex = TexMan(gameinfo.PauseSign);
|
||||
x = (SCREENWIDTH - tex->GetScaledWidth() * CleanXfac)/2 +
|
||||
tex->GetScaledLeftOffset() * CleanXfac;
|
||||
screen->DrawTexture (tex, x, 4, DTA_CleanNoMove, true, TAG_DONE);
|
||||
if (paused && multiplayer)
|
||||
{
|
||||
pstring += players[paused - 1].userinfo.GetName();
|
||||
screen->DrawText(SmallFont, CR_RED,
|
||||
(screen->GetWidth() - SmallFont->StringWidth(pstring)*CleanXfac) / 2,
|
||||
(tex->GetScaledHeight() * CleanYfac) + 4, pstring, DTA_CleanNoMove, true, TAG_DONE);
|
||||
}
|
||||
}
|
||||
|
||||
// [RH] Draw icon, if any
|
||||
|
@ -974,25 +983,6 @@ void D_DoomLoop ()
|
|||
I_StartTic ();
|
||||
D_ProcessEvents ();
|
||||
G_BuildTiccmd (&netcmds[consoleplayer][maketic%BACKUPTICS]);
|
||||
//Added by MC: For some of that bot stuff. The main bot function.
|
||||
int i;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && players[i].isbot && players[i].mo)
|
||||
{
|
||||
players[i].savedyaw = players[i].mo->angle;
|
||||
players[i].savedpitch = players[i].mo->pitch;
|
||||
}
|
||||
}
|
||||
bglobal.Main (maketic%BACKUPTICS);
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && players[i].isbot && players[i].mo)
|
||||
{
|
||||
players[i].mo->angle = players[i].savedyaw;
|
||||
players[i].mo->pitch = players[i].savedpitch;
|
||||
}
|
||||
}
|
||||
if (advancedemo)
|
||||
D_DoAdvanceDemo ();
|
||||
C_Ticker ();
|
||||
|
@ -1337,6 +1327,7 @@ CCMD (endgame)
|
|||
{
|
||||
gameaction = ga_fullconsole;
|
||||
demosequence = -1;
|
||||
G_CheckDemoStatus();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2587,6 +2578,7 @@ void D_DoomMain (void)
|
|||
new (&gameinfo) gameinfo_t; // Reset gameinfo
|
||||
S_Shutdown(); // free all channels and delete playlist
|
||||
C_ClearAliases(); // CCMDs won't be reinitialized so these need to be deleted here
|
||||
DestroyCVarsFlagged(CVAR_MOD); // Delete any cvar left by mods
|
||||
|
||||
GC::FullGC(); // perform one final garbage collection before deleting the class data
|
||||
PClass::ClearRuntimeData(); // clear all runtime generated class data
|
||||
|
|
404
src/d_net.cpp
404
src/d_net.cpp
|
@ -39,7 +39,6 @@
|
|||
#include "cmdlib.h"
|
||||
#include "s_sound.h"
|
||||
#include "m_cheat.h"
|
||||
#include "p_effect.h"
|
||||
#include "p_local.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "sbar.h"
|
||||
|
@ -110,13 +109,15 @@ unsigned int lastrecvtime[MAXPLAYERS]; // [RH] Used for pings
|
|||
unsigned int currrecvtime[MAXPLAYERS];
|
||||
unsigned int lastglobalrecvtime; // Identify the last time a packet was recieved.
|
||||
bool hadlate;
|
||||
int netdelay[MAXNETNODES][BACKUPTICS]; // Used for storing network delay times.
|
||||
int lastaverage;
|
||||
|
||||
int nodeforplayer[MAXPLAYERS];
|
||||
int playerfornode[MAXNETNODES];
|
||||
|
||||
int maketic;
|
||||
int skiptics;
|
||||
int ticdup;
|
||||
int ticdup;
|
||||
|
||||
void D_ProcessEvents (void);
|
||||
void G_BuildTiccmd (ticcmd_t *cmd);
|
||||
|
@ -151,6 +152,32 @@ CUSTOM_CVAR (Bool, cl_capfps, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
|||
}
|
||||
}
|
||||
|
||||
CVAR(Bool, net_ticbalance, false, CVAR_SERVERINFO | CVAR_NOSAVE)
|
||||
CUSTOM_CVAR(Int, net_extratic, 0, CVAR_SERVERINFO | CVAR_NOSAVE)
|
||||
{
|
||||
if (self < 0)
|
||||
{
|
||||
self = 0;
|
||||
}
|
||||
else if (self > 2)
|
||||
{
|
||||
self = 2;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
CVAR(Int, net_fakelatency, 0, 0);
|
||||
|
||||
struct PacketStore
|
||||
{
|
||||
int timer;
|
||||
doomcom_t message;
|
||||
};
|
||||
|
||||
static TArray<PacketStore> InBuffer;
|
||||
static TArray<PacketStore> OutBuffer;
|
||||
#endif
|
||||
|
||||
// [RH] Special "ticcmds" get stored in here
|
||||
static struct TicSpecial
|
||||
{
|
||||
|
@ -347,6 +374,9 @@ int NetbufferSize ()
|
|||
k += netbuffer[k] + 1;
|
||||
}
|
||||
|
||||
// Network delay byte
|
||||
k++;
|
||||
|
||||
if (netbuffer[0] & NCMD_MULTI)
|
||||
{
|
||||
count = netbuffer[k];
|
||||
|
@ -487,7 +517,30 @@ void HSendPacket (int node, int len)
|
|||
doomcom.remotenode = node;
|
||||
doomcom.datalength = len;
|
||||
|
||||
I_NetCmd ();
|
||||
#ifdef _DEBUG
|
||||
if (net_fakelatency / 2 > 0)
|
||||
{
|
||||
PacketStore store;
|
||||
store.message = doomcom;
|
||||
store.timer = I_GetTime(false) + ((net_fakelatency / 2) / (1000 / TICRATE));
|
||||
OutBuffer.Push(store);
|
||||
}
|
||||
else
|
||||
I_NetCmd();
|
||||
|
||||
for (unsigned int i = 0; i < OutBuffer.Size(); i++)
|
||||
{
|
||||
if (OutBuffer[i].timer <= I_GetTime(false))
|
||||
{
|
||||
doomcom = OutBuffer[i].message;
|
||||
I_NetCmd();
|
||||
OutBuffer.Delete(i);
|
||||
i = -1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
I_NetCmd();
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -509,12 +562,42 @@ bool HGetPacket (void)
|
|||
|
||||
if (demoplayback)
|
||||
return false;
|
||||
|
||||
|
||||
doomcom.command = CMD_GET;
|
||||
I_NetCmd ();
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (net_fakelatency / 2 > 0 && doomcom.remotenode != -1)
|
||||
{
|
||||
PacketStore store;
|
||||
store.message = doomcom;
|
||||
store.timer = I_GetTime(false) + ((net_fakelatency / 2) / (1000 / TICRATE));
|
||||
InBuffer.Push(store);
|
||||
doomcom.remotenode = -1;
|
||||
}
|
||||
|
||||
if (doomcom.remotenode == -1)
|
||||
{
|
||||
bool gotmessage = false;
|
||||
for (unsigned int i = 0; i < InBuffer.Size(); i++)
|
||||
{
|
||||
if (InBuffer[i].timer <= I_GetTime(false))
|
||||
{
|
||||
doomcom = InBuffer[i].message;
|
||||
InBuffer.Delete(i);
|
||||
gotmessage = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!gotmessage)
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (doomcom.remotenode == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (debugfile)
|
||||
{
|
||||
|
@ -570,6 +653,9 @@ bool HGetPacket (void)
|
|||
|
||||
if (doomcom.datalength != NetbufferSize ())
|
||||
{
|
||||
Printf("Bad packet length %i (calculated %i)\n",
|
||||
doomcom.datalength, NetbufferSize());
|
||||
|
||||
if (debugfile)
|
||||
fprintf (debugfile,"---bad packet length %i (calculated %i)\n",
|
||||
doomcom.datalength, NetbufferSize());
|
||||
|
@ -583,6 +669,9 @@ void PlayerIsGone (int netnode, int netconsole)
|
|||
{
|
||||
int i;
|
||||
|
||||
if (!nodeingame[netnode])
|
||||
return;
|
||||
|
||||
for (i = netnode + 1; i < doomcom.numnodes; ++i)
|
||||
{
|
||||
if (nodeingame[i])
|
||||
|
@ -593,77 +682,37 @@ void PlayerIsGone (int netnode, int netconsole)
|
|||
doomcom.numnodes = netnode;
|
||||
}
|
||||
|
||||
if (playeringame[netconsole])
|
||||
{
|
||||
players[netconsole].playerstate = PST_GONE;
|
||||
}
|
||||
nodeingame[netnode] = false;
|
||||
playeringame[netconsole] = false;
|
||||
nodejustleft[netnode] = false;
|
||||
|
||||
if (deathmatch)
|
||||
{
|
||||
Printf ("%s left the game with %d frags\n",
|
||||
players[netconsole].userinfo.GetName(),
|
||||
players[netconsole].fragcount);
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf ("%s left the game\n", players[netconsole].userinfo.GetName());
|
||||
}
|
||||
|
||||
// [RH] Revert each player to their own view if spying through the player who left
|
||||
for (int ii = 0; ii < MAXPLAYERS; ++ii)
|
||||
{
|
||||
if (playeringame[ii] && players[ii].camera == players[netconsole].mo)
|
||||
{
|
||||
players[ii].camera = players[ii].mo;
|
||||
if (ii == consoleplayer && StatusBar != NULL)
|
||||
{
|
||||
StatusBar->AttachToPlayer (&players[ii]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// [RH] Make the player disappear
|
||||
FBehavior::StaticStopMyScripts (players[netconsole].mo);
|
||||
if (players[netconsole].mo != NULL)
|
||||
{
|
||||
P_DisconnectEffect (players[netconsole].mo);
|
||||
players[netconsole].mo->player = NULL;
|
||||
players[netconsole].mo->Destroy ();
|
||||
if (!(players[netconsole].mo->ObjectFlags & OF_EuthanizeMe))
|
||||
{ // We just destroyed a morphed player, so now the original player
|
||||
// has taken their place. Destroy that one too.
|
||||
players[netconsole].mo->Destroy();
|
||||
}
|
||||
players[netconsole].mo = NULL;
|
||||
players[netconsole].camera = NULL;
|
||||
}
|
||||
// [RH] Let the scripts know the player left
|
||||
FBehavior::StaticStartTypedScripts (SCRIPT_Disconnect, NULL, true, netconsole);
|
||||
if (netconsole == Net_Arbitrator)
|
||||
{
|
||||
bglobal.RemoveAllBots (true);
|
||||
Printf ("Removed all bots\n");
|
||||
|
||||
// Pick a new network arbitrator
|
||||
for (int i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && !players[i].isbot)
|
||||
if (i != netconsole && playeringame[i] && players[i].Bot == NULL)
|
||||
{
|
||||
Net_Arbitrator = i;
|
||||
players[i].settings_controller = true;
|
||||
Printf ("%s is the new arbitrator\n", players[i].userinfo.GetName());
|
||||
Printf("%s is the new arbitrator\n", players[i].userinfo.GetName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (debugfile && NetMode == NET_PacketServer)
|
||||
}
|
||||
|
||||
if (debugfile && NetMode == NET_PacketServer)
|
||||
{
|
||||
if (Net_Arbitrator == consoleplayer)
|
||||
{
|
||||
if (Net_Arbitrator == consoleplayer)
|
||||
{
|
||||
fprintf (debugfile, "I am the new master!\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (debugfile, "Node %d is the new master!\n", nodeforplayer[Net_Arbitrator]);
|
||||
}
|
||||
fprintf(debugfile, "I am the new master!\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(debugfile, "Node %d is the new master!\n", nodeforplayer[Net_Arbitrator]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -772,7 +821,6 @@ void GetPackets (void)
|
|||
}
|
||||
|
||||
if (netbuffer[0] & NCMD_QUITTERS)
|
||||
|
||||
{
|
||||
numplayers = netbuffer[k++];
|
||||
for (int i = 0; i < numplayers; ++i)
|
||||
|
@ -782,6 +830,9 @@ void GetPackets (void)
|
|||
}
|
||||
}
|
||||
|
||||
// Pull current network delay from node
|
||||
netdelay[netnode][(nettics[netnode]+1) % BACKUPTICS] = netbuffer[k++];
|
||||
|
||||
playerbytes[0] = netconsole;
|
||||
if (netbuffer[0] & NCMD_MULTI)
|
||||
{
|
||||
|
@ -847,64 +898,18 @@ void GetPackets (void)
|
|||
|
||||
for (i = 0; i < numplayers; ++i)
|
||||
{
|
||||
int node = !players[playerbytes[i]].isbot ?
|
||||
nodeforplayer[playerbytes[i]] : netnode;
|
||||
int node = nodeforplayer[playerbytes[i]];
|
||||
|
||||
SkipTicCmd (&start, nettics[node] - realstart);
|
||||
for (tics = nettics[node]; tics < realend; tics++)
|
||||
ReadTicCmd (&start, playerbytes[i], tics);
|
||||
}
|
||||
// Update the number of tics received from each node. This must
|
||||
// be separate from the above loop in case the master is also
|
||||
// sending bot movements. If it's not separate, then the bots
|
||||
// will only move on the master, because the other players will
|
||||
// read the master's tics and then think they already got all
|
||||
// the tics for the bots and skip the bot tics included in the
|
||||
// packet.
|
||||
for (i = 0; i < numplayers; ++i)
|
||||
{
|
||||
if (!players[playerbytes[i]].isbot)
|
||||
{
|
||||
nettics[nodeforplayer[playerbytes[i]]] = realend;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AdjustBots (int gameticdiv)
|
||||
{
|
||||
// [RH] This loop adjusts the bots' rotations for ticcmds that have
|
||||
// been already created but not yet executed. This way, the bot is still
|
||||
// able to create ticcmds that accurately reflect the state it wants to
|
||||
// be in even when gametic lags behind maketic.
|
||||
for (int i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && players[i].isbot && players[i].mo)
|
||||
{
|
||||
players[i].savedyaw = players[i].mo->angle;
|
||||
players[i].savedpitch = players[i].mo->pitch;
|
||||
for (int j = gameticdiv; j < maketic/ticdup; j++)
|
||||
{
|
||||
players[i].mo->angle += (netcmds[i][j%BACKUPTICS].ucmd.yaw << 16) * ticdup;
|
||||
players[i].mo->pitch -= (netcmds[i][j%BACKUPTICS].ucmd.pitch << 16) * ticdup;
|
||||
nettics[nodeforplayer[playerbytes[i]]] = realend;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UnadjustBots ()
|
||||
{
|
||||
for (int i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && players[i].isbot && players[i].mo)
|
||||
{
|
||||
players[i].mo->angle = players[i].savedyaw;
|
||||
players[i].mo->pitch = players[i].savedpitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// NetUpdate
|
||||
// Builds ticcmds for console player,
|
||||
|
@ -934,7 +939,7 @@ void NetUpdate (void)
|
|||
newtics = nowtime - gametime;
|
||||
gametime = nowtime;
|
||||
|
||||
if (newtics <= 0) // nothing new to update
|
||||
if (newtics <= 0 || pauseext) // nothing new to update or window paused
|
||||
{
|
||||
GetPackets ();
|
||||
return;
|
||||
|
@ -951,9 +956,7 @@ void NetUpdate (void)
|
|||
newtics = 0;
|
||||
}
|
||||
|
||||
// build new ticcmds for console player (and bots if I am the arbitrator)
|
||||
AdjustBots (gametic / ticdup);
|
||||
|
||||
// build new ticcmds for console player
|
||||
for (i = 0; i < newtics; i++)
|
||||
{
|
||||
I_StartTic ();
|
||||
|
@ -963,11 +966,6 @@ void NetUpdate (void)
|
|||
|
||||
//Printf ("mk:%i ",maketic);
|
||||
G_BuildTiccmd (&localcmds[maketic % LOCALCMDTICS]);
|
||||
if (maketic % ticdup == 0)
|
||||
{
|
||||
//Added by MC: For some of that bot stuff. The main bot function.
|
||||
bglobal.Main ((maketic / ticdup) % BACKUPTICS);
|
||||
}
|
||||
maketic++;
|
||||
|
||||
if (ticdup == 1 || maketic == 0)
|
||||
|
@ -1047,8 +1045,6 @@ void NetUpdate (void)
|
|||
}
|
||||
}
|
||||
|
||||
UnadjustBots ();
|
||||
|
||||
if (singletics)
|
||||
return; // singletic update is synchronous
|
||||
|
||||
|
@ -1068,14 +1064,11 @@ void NetUpdate (void)
|
|||
|
||||
if (consoleplayer == Net_Arbitrator)
|
||||
{
|
||||
for (j = 0; j < MAXPLAYERS; j++)
|
||||
for (j = 0; j < doomcom.numnodes; j++)
|
||||
{
|
||||
if (playeringame[j])
|
||||
if (nodeingame[j] && NetMode == NET_PacketServer)
|
||||
{
|
||||
if (players[j].isbot || NetMode == NET_PacketServer)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1150,11 +1143,18 @@ void NetUpdate (void)
|
|||
netbuffer[k++] = lowtic;
|
||||
}
|
||||
|
||||
numtics = lowtic - realstart;
|
||||
numtics = MAX(0, lowtic - realstart);
|
||||
if (numtics > BACKUPTICS)
|
||||
I_Error ("NetUpdate: Node %d missed too many tics", i);
|
||||
|
||||
resendto[i] = MAX (0, lowtic - doomcom.extratics);
|
||||
switch (net_extratic)
|
||||
{
|
||||
case 0:
|
||||
default:
|
||||
resendto[i] = lowtic; break;
|
||||
case 1: resendto[i] = MAX(0, lowtic - 1); break;
|
||||
case 2: resendto[i] = nettics[i]; break;
|
||||
}
|
||||
|
||||
if (numtics == 0 && resendOnly && !remoteresend[i] && nettics[i])
|
||||
{
|
||||
|
@ -1190,6 +1190,10 @@ void NetUpdate (void)
|
|||
}
|
||||
}
|
||||
|
||||
// Send current network delay
|
||||
// The number of tics we just made should be removed from the count.
|
||||
netbuffer[k++] = ((maketic - newtics - gametic) / ticdup);
|
||||
|
||||
if (numtics > 0)
|
||||
{
|
||||
int l;
|
||||
|
@ -1199,15 +1203,12 @@ void NetUpdate (void)
|
|||
netbuffer[0] |= NCMD_MULTI;
|
||||
netbuffer[k++] = count;
|
||||
|
||||
for (l = 1, j = 0; j < MAXPLAYERS; j++)
|
||||
for (l = 1, j = 0; j < doomcom.numnodes; j++)
|
||||
{
|
||||
if (playeringame[j] && j != playerfornode[i] && j != consoleplayer)
|
||||
if (nodeingame[j] && j != i && j != nodeforplayer[consoleplayer] && NetMode == NET_PacketServer)
|
||||
{
|
||||
if (players[j].isbot || NetMode == NET_PacketServer)
|
||||
{
|
||||
playerbytes[l++] = j;
|
||||
netbuffer[k++] = j;
|
||||
}
|
||||
playerbytes[l++] = playerfornode[j];
|
||||
netbuffer[k++] = playerfornode[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1227,7 +1228,7 @@ void NetUpdate (void)
|
|||
prev %= BACKUPTICS;
|
||||
|
||||
// The local player has their tics sent first, followed by
|
||||
// the other players/bots.
|
||||
// the other players.
|
||||
if (l == 0)
|
||||
{
|
||||
WriteWord (localcmds[localstart].consistancy, &cmddata);
|
||||
|
@ -1242,24 +1243,17 @@ void NetUpdate (void)
|
|||
}
|
||||
else if (i != 0)
|
||||
{
|
||||
if (players[playerbytes[l]].isbot)
|
||||
{
|
||||
int len;
|
||||
BYTE *spec;
|
||||
|
||||
WriteWord (0, &cmddata); // fake consistancy word
|
||||
}
|
||||
else
|
||||
WriteWord (netcmds[playerbytes[l]][start].consistancy, &cmddata);
|
||||
spec = NetSpecs[playerbytes[l]][start].GetData (&len);
|
||||
if (spec != NULL)
|
||||
{
|
||||
int len;
|
||||
BYTE *spec;
|
||||
|
||||
WriteWord (netcmds[playerbytes[l]][start].consistancy, &cmddata);
|
||||
spec = NetSpecs[playerbytes[l]][start].GetData (&len);
|
||||
if (spec != NULL)
|
||||
{
|
||||
memcpy (cmddata, spec, len);
|
||||
cmddata += len;
|
||||
}
|
||||
memcpy (cmddata, spec, len);
|
||||
cmddata += len;
|
||||
}
|
||||
|
||||
WriteUserCmdMessage (&netcmds[playerbytes[l]][start].ucmd,
|
||||
prev >= 0 ? &netcmds[playerbytes[l]][prev].ucmd : NULL, &cmddata);
|
||||
}
|
||||
|
@ -1299,9 +1293,37 @@ void NetUpdate (void)
|
|||
// that it won't adapt. Fortunately, player prediction helps
|
||||
// alleviate the lag somewhat.
|
||||
|
||||
if (NetMode != NET_PacketServer)
|
||||
if (NetMode == NET_PeerToPeer)
|
||||
{
|
||||
mastertics = nettics[nodeforplayer[Net_Arbitrator]];
|
||||
int totalavg = 0;
|
||||
if (net_ticbalance)
|
||||
{
|
||||
// Try to guess ahead the time it takes to send responses to the slowest node
|
||||
int nodeavg = 0, arbavg = 0;
|
||||
|
||||
for (j = 0; j < BACKUPTICS; j++)
|
||||
{
|
||||
arbavg += netdelay[nodeforplayer[Net_Arbitrator]][j];
|
||||
nodeavg += netdelay[0][j];
|
||||
}
|
||||
arbavg /= BACKUPTICS;
|
||||
nodeavg /= BACKUPTICS;
|
||||
|
||||
// We shouldn't adapt if we are already the arbitrator isn't what we are waiting for, otherwise it just adds more latency
|
||||
if (arbavg > nodeavg)
|
||||
{
|
||||
lastaverage = totalavg = ((arbavg + nodeavg) / 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Allow room to guess two tics ahead
|
||||
if (nodeavg > (arbavg + 2) && lastaverage > 0)
|
||||
lastaverage--;
|
||||
totalavg = lastaverage;
|
||||
}
|
||||
}
|
||||
|
||||
mastertics = nettics[nodeforplayer[Net_Arbitrator]] + totalavg;
|
||||
}
|
||||
if (nettics[0] <= mastertics)
|
||||
{
|
||||
|
@ -1346,9 +1368,8 @@ void NetUpdate (void)
|
|||
//
|
||||
// 0 One byte set to NCMD_SETUP+2
|
||||
// 1 One byte for ticdup setting
|
||||
// 2 One byte for extratics setting
|
||||
// 3 One byte for NetMode setting
|
||||
// 4 String with starting map's name
|
||||
// 2 One byte for NetMode setting
|
||||
// 3 String with starting map's name
|
||||
// . Four bytes for the RNG seed
|
||||
// . Stream containing remaining game info
|
||||
//
|
||||
|
@ -1429,10 +1450,9 @@ bool DoArbitrate (void *userdata)
|
|||
data->gotsetup[0] = 0x80;
|
||||
|
||||
ticdup = doomcom.ticdup = netbuffer[1];
|
||||
doomcom.extratics = netbuffer[2];
|
||||
NetMode = netbuffer[3];
|
||||
NetMode = netbuffer[2];
|
||||
|
||||
stream = &netbuffer[4];
|
||||
stream = &netbuffer[3];
|
||||
s = ReadString (&stream);
|
||||
startmap = s;
|
||||
delete[] s;
|
||||
|
@ -1497,9 +1517,8 @@ bool DoArbitrate (void *userdata)
|
|||
{
|
||||
netbuffer[0] = NCMD_SETUP+2;
|
||||
netbuffer[1] = (BYTE)doomcom.ticdup;
|
||||
netbuffer[2] = (BYTE)doomcom.extratics;
|
||||
netbuffer[3] = NetMode;
|
||||
stream = &netbuffer[4];
|
||||
netbuffer[2] = NetMode;
|
||||
stream = &netbuffer[3];
|
||||
WriteString (startmap, &stream);
|
||||
WriteLong (rngseed, &stream);
|
||||
C_WriteCVars (&stream, CVAR_SERVERINFO, true);
|
||||
|
@ -1634,10 +1653,19 @@ void D_CheckNetGame (void)
|
|||
resendto[i] = 0; // which tic to start sending
|
||||
}
|
||||
|
||||
// Packet server has proven to be rather slow over the internet. Print a warning about it.
|
||||
v = Args->CheckValue("-netmode");
|
||||
if (v != NULL && (atoi(v) != 0))
|
||||
{
|
||||
Printf(TEXTCOLOR_YELLOW "Notice: Using PacketServer (netmode 1) over the internet is prone to running too slow on some internet configurations."
|
||||
"\nIf the game is running well below expected speeds, use netmode 0 (P2P) instead.\n");
|
||||
}
|
||||
|
||||
// I_InitNetwork sets doomcom and netgame
|
||||
if (I_InitNetwork ())
|
||||
{
|
||||
NetMode = NET_PacketServer;
|
||||
// For now, stop auto selecting PacketServer, as it's more likely to cause confusion.
|
||||
//NetMode = NET_PacketServer;
|
||||
}
|
||||
if (doomcom.id != DOOMCOM_ID)
|
||||
{
|
||||
|
@ -1647,15 +1675,23 @@ void D_CheckNetGame (void)
|
|||
|
||||
consoleplayer = doomcom.consoleplayer;
|
||||
|
||||
v = Args->CheckValue ("-netmode");
|
||||
if (v != NULL)
|
||||
if (consoleplayer == Net_Arbitrator)
|
||||
{
|
||||
NetMode = atoi (v) != 0 ? NET_PacketServer : NET_PeerToPeer;
|
||||
}
|
||||
if (doomcom.numnodes > 1)
|
||||
{
|
||||
Printf ("Selected " TEXTCOLOR_BLUE "%s" TEXTCOLOR_NORMAL " networking mode. (%s)\n", NetMode == NET_PeerToPeer ? "peer to peer" : "packet server",
|
||||
v != NULL ? "forced" : "auto");
|
||||
v = Args->CheckValue("-netmode");
|
||||
if (v != NULL)
|
||||
{
|
||||
NetMode = atoi(v) != 0 ? NET_PacketServer : NET_PeerToPeer;
|
||||
}
|
||||
if (doomcom.numnodes > 1)
|
||||
{
|
||||
Printf("Selected " TEXTCOLOR_BLUE "%s" TEXTCOLOR_NORMAL " networking mode. (%s)\n", NetMode == NET_PeerToPeer ? "peer to peer" : "packet server",
|
||||
v != NULL ? "forced" : "auto");
|
||||
}
|
||||
|
||||
if (Args->CheckParm("-extratic"))
|
||||
{
|
||||
net_extratic = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// [RH] Setup user info
|
||||
|
@ -1683,6 +1719,11 @@ void D_CheckNetGame (void)
|
|||
for (i = 0; i < doomcom.numnodes; i++)
|
||||
nodeingame[i] = true;
|
||||
|
||||
if (consoleplayer != Net_Arbitrator && doomcom.numnodes > 1)
|
||||
{
|
||||
Printf("Arbitrator selected " TEXTCOLOR_BLUE "%s" TEXTCOLOR_NORMAL " networking mode.\n", NetMode == NET_PeerToPeer ? "peer to peer" : "packet server");
|
||||
}
|
||||
|
||||
Printf ("player %i of %i (%i nodes)\n",
|
||||
consoleplayer+1, doomcom.numplayers, doomcom.numnodes);
|
||||
}
|
||||
|
@ -1809,6 +1850,9 @@ void TryRunTics (void)
|
|||
{
|
||||
C_Ticker();
|
||||
M_Ticker();
|
||||
// Repredict the player for new buffered movement
|
||||
P_UnPredictPlayer();
|
||||
P_PredictPlayer(&players[consoleplayer]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -1844,6 +1888,9 @@ void TryRunTics (void)
|
|||
{
|
||||
C_Ticker ();
|
||||
M_Ticker ();
|
||||
// Repredict the player for new buffered movement
|
||||
P_UnPredictPlayer();
|
||||
P_PredictPlayer(&players[consoleplayer]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1857,6 +1904,7 @@ void TryRunTics (void)
|
|||
// run the count tics
|
||||
if (counts > 0)
|
||||
{
|
||||
P_UnPredictPlayer();
|
||||
while (counts--)
|
||||
{
|
||||
if (gametic > lowtic)
|
||||
|
@ -1876,6 +1924,7 @@ void TryRunTics (void)
|
|||
|
||||
NetUpdate (); // check for new console commands
|
||||
}
|
||||
P_PredictPlayer(&players[consoleplayer]);
|
||||
S_UpdateSounds (players[consoleplayer].camera); // move positional sounds
|
||||
}
|
||||
}
|
||||
|
@ -2130,10 +2179,7 @@ void Net_DoCommand (int type, BYTE **stream, int player)
|
|||
break;
|
||||
|
||||
case DEM_ADDBOT:
|
||||
{
|
||||
BYTE num = ReadByte (stream);
|
||||
bglobal.DoAddBot (num, s = ReadString (stream));
|
||||
}
|
||||
bglobal.TryAddBot (stream, player);
|
||||
break;
|
||||
|
||||
case DEM_KILLBOTS:
|
||||
|
@ -2589,10 +2635,13 @@ void Net_SkipCommand (int type, BYTE **stream)
|
|||
switch (type)
|
||||
{
|
||||
case DEM_SAY:
|
||||
case DEM_ADDBOT:
|
||||
skip = strlen ((char *)(*stream + 1)) + 2;
|
||||
break;
|
||||
|
||||
case DEM_ADDBOT:
|
||||
skip = strlen ((char *)(*stream + 1)) + 6;
|
||||
break;
|
||||
|
||||
case DEM_GIVECHEAT:
|
||||
case DEM_TAKECHEAT:
|
||||
skip = strlen ((char *)(*stream)) + 3;
|
||||
|
@ -2713,7 +2762,6 @@ void Net_SkipCommand (int type, BYTE **stream)
|
|||
CCMD (pings)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
if (playeringame[i])
|
||||
Printf ("% 4d %s\n", currrecvtime[i] - lastrecvtime[i],
|
||||
|
@ -2755,7 +2803,7 @@ static void Network_Controller (int playernum, bool add)
|
|||
return;
|
||||
}
|
||||
|
||||
if (players[playernum].isbot)
|
||||
if (players[playernum].Bot != NULL)
|
||||
{
|
||||
Printf ("Bots cannot be added to the controller list.\n");
|
||||
return;
|
||||
|
|
|
@ -70,7 +70,6 @@ struct doomcom_t
|
|||
// info common to all nodes
|
||||
SWORD numnodes; // console is always node 0.
|
||||
SWORD ticdup; // 1 = no duplication, 2-5 = dup for slow nets
|
||||
SWORD extratics; // 1 = send a backup tic in every packet
|
||||
#ifdef DJGPP
|
||||
SWORD pad[5]; // keep things aligned for DOS drivers
|
||||
#endif
|
||||
|
@ -143,6 +142,8 @@ extern struct ticcmd_t localcmds[LOCALCMDTICS];
|
|||
|
||||
extern int maketic;
|
||||
extern int nettics[MAXNETNODES];
|
||||
extern int netdelay[MAXNETNODES][BACKUPTICS];
|
||||
extern int nodeforplayer[MAXPLAYERS];
|
||||
|
||||
extern ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS];
|
||||
extern int ticdup;
|
||||
|
|
|
@ -60,9 +60,6 @@
|
|||
|
||||
static FRandom pr_pickteam ("PickRandomTeam");
|
||||
|
||||
extern bool st_firsttime;
|
||||
EXTERN_CVAR (Bool, teamplay)
|
||||
|
||||
CVAR (Float, autoaim, 5000.f, CVAR_USERINFO | CVAR_ARCHIVE);
|
||||
CVAR (String, name, "Player", CVAR_USERINFO | CVAR_ARCHIVE);
|
||||
CVAR (Color, color, 0x40cf00, CVAR_USERINFO | CVAR_ARCHIVE);
|
||||
|
|
|
@ -76,8 +76,6 @@ FPlayerColorSet *P_GetPlayerColorSet(FName classname, int setnum);
|
|||
void P_EnumPlayerColorSets(FName classname, TArray<int> *out);
|
||||
const char *GetPrintableDisplayName(const PClass *cls);
|
||||
|
||||
class player_t;
|
||||
|
||||
class APlayerPawn : public AActor
|
||||
{
|
||||
DECLARE_CLASS (APlayerPawn, AActor)
|
||||
|
@ -176,7 +174,8 @@ typedef enum
|
|||
PST_LIVE, // Playing or camping.
|
||||
PST_DEAD, // Dead on the ground, view follows killer.
|
||||
PST_REBORN, // Ready to restart/respawn???
|
||||
PST_ENTER // [BC] Entered the game
|
||||
PST_ENTER, // [BC] Entered the game
|
||||
PST_GONE // Player has left the game
|
||||
} playerstate_t;
|
||||
|
||||
|
||||
|
@ -206,6 +205,8 @@ typedef enum
|
|||
CF_DOUBLEFIRINGSPEED= 1 << 21, // Player owns a double firing speed artifact
|
||||
CF_EXTREMELYDEAD = 1 << 22, // [RH] Reliably let the status bar know about extreme deaths.
|
||||
CF_INFINITEAMMO = 1 << 23, // Player owns an infinite ammo artifact
|
||||
CF_BUDDHA2 = 1 << 24, // [MC] Absolute buddha. No voodoo can kill it either.
|
||||
CF_GODMODE2 = 1 << 25, // [MC] Absolute godmode. No voodoo can kill it either.
|
||||
CF_BUDDHA = 1 << 27, // [SP] Buddha mode - take damage, but don't die
|
||||
CF_NOCLIP2 = 1 << 30, // [RH] More Quake-like noclip
|
||||
} cheat_t;
|
||||
|
@ -398,8 +399,7 @@ public:
|
|||
|
||||
int inventorytics;
|
||||
BYTE CurrentPlayerClass; // class # for this player instance
|
||||
bool backpack;
|
||||
|
||||
|
||||
int frags[MAXPLAYERS]; // kills of other players
|
||||
int fragcount; // [RH] Cumulative frags for this player
|
||||
int lastkilltime; // [RH] For multikills
|
||||
|
@ -444,47 +444,10 @@ public:
|
|||
FName LastDamageType; // [RH] For damage-specific pain and death sounds
|
||||
|
||||
//Added by MC:
|
||||
angle_t savedyaw;
|
||||
int savedpitch;
|
||||
|
||||
angle_t angle; // The wanted angle that the bot try to get every tic.
|
||||
// (used to get a smoth view movement)
|
||||
TObjPtr<AActor> dest; // Move Destination.
|
||||
TObjPtr<AActor> prev; // Previous move destination.
|
||||
|
||||
|
||||
TObjPtr<AActor> enemy; // The dead meat.
|
||||
TObjPtr<AActor> missile; // A threatening missile that needs to be avoided.
|
||||
TObjPtr<AActor> mate; // Friend (used for grouping in teamplay or coop).
|
||||
TObjPtr<AActor> last_mate; // If bots mate disappeared (not if died) that mate is
|
||||
// pointed to by this. Allows bot to roam to it if
|
||||
// necessary.
|
||||
TObjPtr<DBot> Bot;
|
||||
|
||||
bool settings_controller; // Player can control game settings.
|
||||
|
||||
//Skills
|
||||
struct botskill_t skill;
|
||||
|
||||
//Tickers
|
||||
int t_active; // Open door, lower lift stuff, door must open and
|
||||
// lift must go down before bot does anything
|
||||
// radical like try a stuckmove
|
||||
int t_respawn;
|
||||
int t_strafe;
|
||||
int t_react;
|
||||
int t_fight;
|
||||
int t_roam;
|
||||
int t_rocket;
|
||||
|
||||
//Misc booleans
|
||||
bool isbot;
|
||||
bool first_shot; // Used for reaction skill.
|
||||
bool sleft; // If false, strafe is right.
|
||||
bool allround;
|
||||
|
||||
fixed_t oldx;
|
||||
fixed_t oldy;
|
||||
|
||||
float BlendR; // [RH] Final blending values
|
||||
float BlendG;
|
||||
float BlendB;
|
||||
|
|
|
@ -112,7 +112,7 @@ enum EDemoCommand
|
|||
DEM_DROPPLAYER, // 13 Not implemented, takes a byte
|
||||
DEM_CHANGEMAP, // 14 Name of map to change to
|
||||
DEM_SUICIDE, // 15 Player wants to die
|
||||
DEM_ADDBOT, // 16 Byte: player#, String: userinfo for bot
|
||||
DEM_ADDBOT, // 16 Byte: botshift, String: userinfo for bot, 4 Bytes: skill (aiming, perfection, reaction, isp)
|
||||
DEM_KILLBOTS, // 17 Remove all bots from the world
|
||||
DEM_INVUSEALL, // 18 Use every item (panic!)
|
||||
DEM_INVUSE, // 19 4 bytes: ID of item to use
|
||||
|
@ -219,7 +219,9 @@ enum ECheatCommand
|
|||
CHT_GIMMIEJ,
|
||||
CHT_GIMMIEZ,
|
||||
CHT_BUDDHA,
|
||||
CHT_NOCLIP2
|
||||
CHT_NOCLIP2,
|
||||
CHT_BUDDHA2,
|
||||
CHT_GOD2
|
||||
};
|
||||
|
||||
void StartChunk (int id, BYTE **stream);
|
||||
|
|
|
@ -162,6 +162,7 @@ enum ELineFlags
|
|||
ML_BLOCKUSE = 0x02000000, // blocks all use actions through this line
|
||||
ML_BLOCKSIGHT = 0x04000000, // blocks monster line of sight
|
||||
ML_BLOCKHITSCAN = 0x08000000, // blocks hitscan attacks
|
||||
ML_3DMIDTEX_IMPASS = 0x10000000, // [TP] if 3D midtex, behaves like a height-restricted ML_BLOCKING
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -339,6 +339,7 @@ enum
|
|||
|
||||
COMPATF2_BADANGLES = 1 << 0, // It is impossible to face directly NSEW.
|
||||
COMPATF2_FLOORMOVE = 1 << 1, // Use the same floor motion behavior as Doom.
|
||||
COMPATF2_SOUNDCUTOFF = 1 << 2, // Cut off sounds when an actor vanishes instead of making it owner-less
|
||||
};
|
||||
|
||||
// Emulate old bugs for select maps. These are not exposed by a cvar
|
||||
|
|
|
@ -109,6 +109,7 @@ enum EMenuState
|
|||
extern bool automapactive; // In AutoMap mode?
|
||||
extern EMenuState menuactive; // Menu overlayed?
|
||||
extern int paused; // Game Pause?
|
||||
extern bool pauseext;
|
||||
|
||||
|
||||
extern bool viewactive;
|
||||
|
@ -136,6 +137,8 @@ extern int consoleplayer;
|
|||
// Disable save/end game?
|
||||
extern bool usergame;
|
||||
|
||||
extern FString newdemoname;
|
||||
extern FString newdemomap;
|
||||
extern bool demoplayback;
|
||||
extern bool demorecording;
|
||||
extern int demover;
|
||||
|
|
|
@ -107,6 +107,9 @@ enum SAW_Flags
|
|||
SF_RANDOMLIGHTHIT = 4,
|
||||
SF_NOUSEAMMOMISS = 8,
|
||||
SF_NOUSEAMMO = 16,
|
||||
SF_NOPULLIN = 32,
|
||||
SF_NOTURN = 64,
|
||||
SF_STEALARMOR = 128,
|
||||
};
|
||||
|
||||
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw)
|
||||
|
@ -117,7 +120,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw)
|
|||
AActor *linetarget;
|
||||
int actualdamage;
|
||||
|
||||
ACTION_PARAM_START(9);
|
||||
ACTION_PARAM_START(11);
|
||||
ACTION_PARAM_SOUND(fullsound, 0);
|
||||
ACTION_PARAM_SOUND(hitsound, 1);
|
||||
ACTION_PARAM_INT(damage, 2);
|
||||
|
@ -127,6 +130,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw)
|
|||
ACTION_PARAM_ANGLE(Spread_XY, 6);
|
||||
ACTION_PARAM_ANGLE(Spread_Z, 7);
|
||||
ACTION_PARAM_FIXED(LifeSteal, 8);
|
||||
ACTION_PARAM_INT(lifestealmax, 9);
|
||||
ACTION_PARAM_CLASS(armorbonustype, 10);
|
||||
|
||||
if (NULL == (player = self->player))
|
||||
{
|
||||
|
@ -182,28 +187,56 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw)
|
|||
}
|
||||
|
||||
if (LifeSteal && !(linetarget->flags5 & MF5_DONTDRAIN))
|
||||
P_GiveBody (self, (actualdamage * LifeSteal) >> FRACBITS);
|
||||
{
|
||||
if (Flags & SF_STEALARMOR)
|
||||
{
|
||||
if (!armorbonustype) armorbonustype = PClass::FindClass("ArmorBonus");
|
||||
|
||||
if (armorbonustype->IsDescendantOf (RUNTIME_CLASS(ABasicArmorBonus)))
|
||||
{
|
||||
ABasicArmorBonus *armorbonus = static_cast<ABasicArmorBonus *>(Spawn (armorbonustype, 0,0,0, NO_REPLACE));
|
||||
armorbonus->SaveAmount *= (actualdamage * LifeSteal) >> FRACBITS;
|
||||
armorbonus->MaxSaveAmount = lifestealmax <= 0 ? armorbonus->MaxSaveAmount : lifestealmax;
|
||||
armorbonus->flags |= MF_DROPPED;
|
||||
armorbonus->ClearCounters();
|
||||
|
||||
if (!armorbonus->CallTryPickup (self))
|
||||
{
|
||||
armorbonus->Destroy ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
P_GiveBody (self, (actualdamage * LifeSteal) >> FRACBITS, lifestealmax);
|
||||
}
|
||||
}
|
||||
|
||||
S_Sound (self, CHAN_WEAPON, hitsound, 1, ATTN_NORM);
|
||||
|
||||
// turn to face target
|
||||
angle = R_PointToAngle2 (self->x, self->y,
|
||||
linetarget->x, linetarget->y);
|
||||
if (angle - self->angle > ANG180)
|
||||
if (!(Flags & SF_NOTURN))
|
||||
{
|
||||
if (angle - self->angle < (angle_t)(-ANG90/20))
|
||||
self->angle = angle + ANG90/21;
|
||||
angle = R_PointToAngle2(self->x, self->y,
|
||||
linetarget->x, linetarget->y);
|
||||
if (angle - self->angle > ANG180)
|
||||
{
|
||||
if (angle - self->angle < (angle_t)(-ANG90 / 20))
|
||||
self->angle = angle + ANG90 / 21;
|
||||
else
|
||||
self->angle -= ANG90 / 20;
|
||||
}
|
||||
else
|
||||
self->angle -= ANG90/20;
|
||||
{
|
||||
if (angle - self->angle > ANG90 / 20)
|
||||
self->angle = angle - ANG90 / 21;
|
||||
else
|
||||
self->angle += ANG90 / 20;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (angle - self->angle > ANG90/20)
|
||||
self->angle = angle - ANG90/21;
|
||||
else
|
||||
self->angle += ANG90/20;
|
||||
}
|
||||
self->flags |= MF_JUSTATTACKED;
|
||||
if (!(Flags & SF_NOPULLIN))
|
||||
self->flags |= MF_JUSTATTACKED;
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -540,6 +573,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireBFG)
|
|||
P_SpawnPlayerMissile (self, 0, 0, 0, PClass::FindClass("BFGBall"), self->angle, NULL, NULL, !!(dmflags2 & DF2_NO_FREEAIMBFG));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// A_BFGSpray
|
||||
// Spawn a BFG explosion on every monster in view
|
||||
|
@ -553,14 +587,21 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray)
|
|||
AActor *thingToHit;
|
||||
AActor *linetarget;
|
||||
|
||||
ACTION_PARAM_START(3);
|
||||
ACTION_PARAM_START(7);
|
||||
ACTION_PARAM_CLASS(spraytype, 0);
|
||||
ACTION_PARAM_INT(numrays, 1);
|
||||
ACTION_PARAM_INT(damagecnt, 2);
|
||||
ACTION_PARAM_ANGLE(angle, 3);
|
||||
ACTION_PARAM_FIXED(distance, 4);
|
||||
ACTION_PARAM_ANGLE(vrange, 5);
|
||||
ACTION_PARAM_INT(defdamage, 6);
|
||||
|
||||
if (spraytype == NULL) spraytype = PClass::FindClass("BFGExtra");
|
||||
if (numrays <= 0) numrays = 40;
|
||||
if (damagecnt <= 0) damagecnt = 15;
|
||||
if (angle == 0) angle = ANG90;
|
||||
if (distance <= 0) distance = 16 * 64 * FRACUNIT;
|
||||
if (vrange == 0) vrange = ANGLE_1 * 32;
|
||||
|
||||
// [RH] Don't crash if no target
|
||||
if (!self->target)
|
||||
|
@ -569,10 +610,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray)
|
|||
// offset angles from its attack angle
|
||||
for (i = 0; i < numrays; i++)
|
||||
{
|
||||
an = self->angle - ANG90/2 + ANG90/numrays*i;
|
||||
an = self->angle - angle/2 + angle/numrays*i;
|
||||
|
||||
// self->target is the originator (player) of the missile
|
||||
P_AimLineAttack (self->target, an, 16*64*FRACUNIT, &linetarget, ANGLE_1*32);
|
||||
P_AimLineAttack (self->target, an, distance, &linetarget, vrange);
|
||||
|
||||
if (!linetarget)
|
||||
continue;
|
||||
|
@ -583,14 +624,24 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray)
|
|||
if (spray && (spray->flags5 & MF5_PUFFGETSOWNER))
|
||||
spray->target = self->target;
|
||||
|
||||
|
||||
damage = 0;
|
||||
for (j = 0; j < damagecnt; ++j)
|
||||
damage += (pr_bfgspray() & 7) + 1;
|
||||
if (defdamage == 0)
|
||||
{
|
||||
damage = 0;
|
||||
for (j = 0; j < damagecnt; ++j)
|
||||
damage += (pr_bfgspray() & 7) + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if this is used, damagecnt will be ignored
|
||||
damage = defdamage;
|
||||
}
|
||||
|
||||
int dmgFlagPass = 0;
|
||||
dmgFlagPass += (spray != NULL && (spray->flags3 & MF3_FOILINVUL)) ? DMG_FOILINVUL : 0; //[MC]Because the original foilinvul wasn't working.
|
||||
dmgFlagPass += (spray != NULL && (spray->flags7 & MF7_FOILBUDDHA)) ? DMG_FOILBUDDHA : 0;
|
||||
thingToHit = linetarget;
|
||||
int newdam = P_DamageMobj (thingToHit, self->target, self->target, damage, spray != NULL? FName(spray->DamageType) : FName(NAME_BFGSplash),
|
||||
spray != NULL && (spray->flags3 & MF3_FOILINVUL)? DMG_FOILINVUL : 0);
|
||||
dmgFlagPass);
|
||||
P_TraceBleed (newdam > 0 ? newdam : damage, thingToHit, self->target);
|
||||
}
|
||||
}
|
||||
|
|
121
src/g_game.cpp
121
src/g_game.cpp
|
@ -76,6 +76,7 @@
|
|||
#include "d_net.h"
|
||||
#include "d_event.h"
|
||||
#include "p_acs.h"
|
||||
#include "p_effect.h"
|
||||
#include "m_joy.h"
|
||||
#include "farchive.h"
|
||||
#include "r_renderer.h"
|
||||
|
@ -115,6 +116,7 @@ CVAR (Bool, chasedemo, false, 0);
|
|||
CVAR (Bool, storesavepic, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR (Bool, longsavemessages, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR (String, save_dir, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
|
||||
CVAR (Bool, cl_waitforsave, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
||||
EXTERN_CVAR (Float, con_midtime);
|
||||
|
||||
//==========================================================================
|
||||
|
@ -140,6 +142,7 @@ gameaction_t gameaction;
|
|||
gamestate_t gamestate = GS_STARTUP;
|
||||
|
||||
int paused;
|
||||
bool pauseext;
|
||||
bool sendpause; // send a pause event next tic
|
||||
bool sendsave; // send a save event next tic
|
||||
bool sendturn180; // [RH] send a 180 degree turn next tic
|
||||
|
@ -161,6 +164,8 @@ int consoleplayer; // player taking events
|
|||
int gametic;
|
||||
|
||||
CVAR(Bool, demo_compress, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
|
||||
FString newdemoname;
|
||||
FString newdemomap;
|
||||
FString demoname;
|
||||
bool demorecording;
|
||||
bool demoplayback;
|
||||
|
@ -874,7 +879,7 @@ static void ChangeSpy (int changespy)
|
|||
pnum &= MAXPLAYERS-1;
|
||||
if (playeringame[pnum] &&
|
||||
(!checkTeam || players[pnum].mo->IsTeammate (players[consoleplayer].mo) ||
|
||||
(bot_allowspy && players[pnum].isbot)))
|
||||
(bot_allowspy && players[pnum].Bot != NULL)))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -1013,10 +1018,16 @@ void G_Ticker ()
|
|||
// do player reborns if needed
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] &&
|
||||
(players[i].playerstate == PST_REBORN || players[i].playerstate == PST_ENTER))
|
||||
if (playeringame[i])
|
||||
{
|
||||
G_DoReborn (i, false);
|
||||
if ((players[i].playerstate == PST_GONE))
|
||||
{
|
||||
G_DoPlayerPop(i);
|
||||
}
|
||||
if ((players[i].playerstate == PST_REBORN || players[i].playerstate == PST_ENTER))
|
||||
{
|
||||
G_DoReborn(i, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1041,6 +1052,10 @@ void G_Ticker ()
|
|||
case ga_loadlevel:
|
||||
G_DoLoadLevel (-1, false);
|
||||
break;
|
||||
case ga_recordgame:
|
||||
G_CheckDemoStatus();
|
||||
G_RecordDemo(newdemoname);
|
||||
G_BeginRecording(newdemomap);
|
||||
case ga_newgame2: // Silence GCC (see above)
|
||||
case ga_newgame:
|
||||
G_DoNewGame ();
|
||||
|
@ -1114,6 +1129,9 @@ void G_Ticker ()
|
|||
// check, not just the player's x position like BOOM.
|
||||
DWORD rngsum = FRandom::StaticSumSeeds ();
|
||||
|
||||
//Added by MC: For some of that bot stuff. The main bot function.
|
||||
bglobal.Main ();
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i])
|
||||
|
@ -1133,13 +1151,13 @@ void G_Ticker ()
|
|||
// If the user alt-tabbed away, paused gets set to -1. In this case,
|
||||
// we do not want to read more demo commands until paused is no
|
||||
// longer negative.
|
||||
if (demoplayback && paused >= 0)
|
||||
if (demoplayback)
|
||||
{
|
||||
G_ReadDemoTiccmd (cmd, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy (cmd, newcmd, sizeof(ticcmd_t));
|
||||
memcpy(cmd, newcmd, sizeof(ticcmd_t));
|
||||
}
|
||||
|
||||
// check for turbo cheats
|
||||
|
@ -1149,7 +1167,7 @@ void G_Ticker ()
|
|||
Printf ("%s is turbo!\n", players[i].userinfo.GetName());
|
||||
}
|
||||
|
||||
if (netgame && !players[i].isbot && !demoplayback && (gametic%ticdup) == 0)
|
||||
if (netgame && players[i].Bot == NULL && !demoplayback && (gametic%ticdup) == 0)
|
||||
{
|
||||
//players[i].inconsistant = 0;
|
||||
if (gametic > BACKUPTICS*ticdup && consistancy[i][buf] != cmd->consistancy)
|
||||
|
@ -1331,10 +1349,10 @@ void G_PlayerReborn (int player)
|
|||
int chasecam;
|
||||
BYTE currclass;
|
||||
userinfo_t userinfo; // [RH] Save userinfo
|
||||
botskill_t b_skill; //Added by MC:
|
||||
APlayerPawn *actor;
|
||||
const PClass *cls;
|
||||
FString log;
|
||||
DBot *Bot; //Added by MC:
|
||||
|
||||
p = &players[player];
|
||||
|
||||
|
@ -1344,18 +1362,19 @@ void G_PlayerReborn (int player)
|
|||
itemcount = p->itemcount;
|
||||
secretcount = p->secretcount;
|
||||
currclass = p->CurrentPlayerClass;
|
||||
b_skill = p->skill; //Added by MC:
|
||||
userinfo.TransferFrom(p->userinfo);
|
||||
actor = p->mo;
|
||||
cls = p->cls;
|
||||
log = p->LogText;
|
||||
chasecam = p->cheats & CF_CHASECAM;
|
||||
Bot = p->Bot; //Added by MC:
|
||||
|
||||
// Reset player structure to its defaults
|
||||
p->~player_t();
|
||||
::new(p) player_t;
|
||||
|
||||
memcpy (p->frags, frags, sizeof(p->frags));
|
||||
p->health = actor->health;
|
||||
p->fragcount = fragcount;
|
||||
p->killcount = killcount;
|
||||
p->itemcount = itemcount;
|
||||
|
@ -1366,8 +1385,7 @@ void G_PlayerReborn (int player)
|
|||
p->cls = cls;
|
||||
p->LogText = log;
|
||||
p->cheats |= chasecam;
|
||||
|
||||
p->skill = b_skill; //Added by MC:
|
||||
p->Bot = Bot; //Added by MC:
|
||||
|
||||
p->oldbuttons = ~0, p->attackdown = true; p->usedown = true; // don't do anything immediately
|
||||
p->original_oldbuttons = ~0;
|
||||
|
@ -1375,15 +1393,19 @@ void G_PlayerReborn (int player)
|
|||
|
||||
if (gamestate != GS_TITLELEVEL)
|
||||
{
|
||||
// [GRB] Give inventory specified in DECORATE
|
||||
actor->GiveDefaultInventory ();
|
||||
p->ReadyWeapon = p->PendingWeapon;
|
||||
}
|
||||
|
||||
//Added by MC: Init bot structure.
|
||||
if (bglobal.botingame[player])
|
||||
bglobal.CleanBotstuff (p);
|
||||
else
|
||||
p->isbot = false;
|
||||
//Added by MC: Init bot structure.
|
||||
if (p->Bot != NULL)
|
||||
{
|
||||
botskill_t skill = p->Bot->skill;
|
||||
p->Bot->Clear ();
|
||||
p->Bot->player = p;
|
||||
p->Bot->skill = skill;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -1658,6 +1680,56 @@ void G_DoReborn (int playernum, bool freshbot)
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// G_DoReborn
|
||||
//
|
||||
void G_DoPlayerPop(int playernum)
|
||||
{
|
||||
playeringame[playernum] = false;
|
||||
|
||||
if (deathmatch)
|
||||
{
|
||||
Printf("%s left the game with %d frags\n",
|
||||
players[playernum].userinfo.GetName(),
|
||||
players[playernum].fragcount);
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("%s left the game\n", players[playernum].userinfo.GetName());
|
||||
}
|
||||
|
||||
// [RH] Revert each player to their own view if spying through the player who left
|
||||
for (int ii = 0; ii < MAXPLAYERS; ++ii)
|
||||
{
|
||||
if (playeringame[ii] && players[ii].camera == players[playernum].mo)
|
||||
{
|
||||
players[ii].camera = players[ii].mo;
|
||||
if (ii == consoleplayer && StatusBar != NULL)
|
||||
{
|
||||
StatusBar->AttachToPlayer(&players[ii]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// [RH] Make the player disappear
|
||||
FBehavior::StaticStopMyScripts(players[playernum].mo);
|
||||
if (players[playernum].mo != NULL)
|
||||
{
|
||||
P_DisconnectEffect(players[playernum].mo);
|
||||
players[playernum].mo->player = NULL;
|
||||
players[playernum].mo->Destroy();
|
||||
if (!(players[playernum].mo->ObjectFlags & OF_EuthanizeMe))
|
||||
{ // We just destroyed a morphed player, so now the original player
|
||||
// has taken their place. Destroy that one too.
|
||||
players[playernum].mo->Destroy();
|
||||
}
|
||||
players[playernum].mo = NULL;
|
||||
players[playernum].camera = NULL;
|
||||
}
|
||||
// [RH] Let the scripts know the player left
|
||||
FBehavior::StaticStartTypedScripts(SCRIPT_Disconnect, NULL, true, playernum);
|
||||
}
|
||||
|
||||
void G_ScreenShot (char *filename)
|
||||
{
|
||||
shotfile = filename;
|
||||
|
@ -2076,6 +2148,9 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
|
|||
filename = G_BuildSaveName ("demosave.zds", -1);
|
||||
}
|
||||
|
||||
if (cl_waitforsave)
|
||||
I_FreezeTime(true);
|
||||
|
||||
insave = true;
|
||||
G_SnapshotLevel ();
|
||||
|
||||
|
@ -2085,6 +2160,7 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
|
|||
{
|
||||
Printf ("Could not create savegame '%s'\n", filename.GetChars());
|
||||
insave = false;
|
||||
I_FreezeTime(false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2161,6 +2237,7 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
|
|||
}
|
||||
|
||||
insave = false;
|
||||
I_FreezeTime(false);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2373,6 +2450,16 @@ void G_DeferedPlayDemo (const char *name)
|
|||
|
||||
CCMD (playdemo)
|
||||
{
|
||||
if (netgame)
|
||||
{
|
||||
Printf("End your current netgame first!");
|
||||
return;
|
||||
}
|
||||
if (demorecording)
|
||||
{
|
||||
Printf("End your current demo first!");
|
||||
return;
|
||||
}
|
||||
if (argv.argc() > 1)
|
||||
{
|
||||
G_DeferedPlayDemo (argv[1]);
|
||||
|
@ -2555,7 +2642,7 @@ void G_DoPlayDemo (void)
|
|||
{
|
||||
FixPathSeperator (defdemoname);
|
||||
DefaultExtension (defdemoname, ".lmp");
|
||||
M_ReadFile (defdemoname, &demobuffer);
|
||||
M_ReadFileMalloc (defdemoname, &demobuffer);
|
||||
}
|
||||
demo_p = demobuffer;
|
||||
|
||||
|
|
|
@ -81,6 +81,7 @@ enum EFinishLevelType
|
|||
void G_PlayerFinishLevel (int player, EFinishLevelType mode, int flags);
|
||||
|
||||
void G_DoReborn (int playernum, bool freshbot);
|
||||
void G_DoPlayerPop(int playernum);
|
||||
|
||||
// Adds pitch to consoleplayer's viewpitch and clamps it
|
||||
void G_AddViewPitch (int look);
|
||||
|
|
|
@ -28,10 +28,14 @@ int AWhirlwind::DoSpecialDamage (AActor *target, int damage, FName damagetype)
|
|||
{
|
||||
int randVal;
|
||||
|
||||
target->angle += pr_foo.Random2() << 20;
|
||||
target->velx += pr_foo.Random2() << 10;
|
||||
target->vely += pr_foo.Random2() << 10;
|
||||
if ((level.time & 16) && !(target->flags2 & MF2_BOSS))
|
||||
if (!(target->flags7 & MF7_DONTTHRUST))
|
||||
{
|
||||
target->angle += pr_foo.Random2() << 20;
|
||||
target->velx += pr_foo.Random2() << 10;
|
||||
target->vely += pr_foo.Random2() << 10;
|
||||
}
|
||||
|
||||
if ((level.time & 16) && !(target->flags2 & MF2_BOSS) && !(target->flags7 & MF7_DONTTHRUST))
|
||||
{
|
||||
randVal = pr_foo();
|
||||
if (randVal > 160)
|
||||
|
|
|
@ -56,7 +56,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CMaceAttack)
|
|||
}
|
||||
}
|
||||
// didn't find any creatures, so try to strike any walls
|
||||
player->mo->special1 = 0;
|
||||
player->mo->weaponspecial = 0;
|
||||
|
||||
angle = player->mo->angle;
|
||||
slope = P_AimLineAttack (player->mo, angle, MELEERANGE, &linetarget);
|
||||
|
|
|
@ -164,7 +164,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffMissileSlither)
|
|||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_CStaffInitBlink)
|
||||
{
|
||||
self->special1 = (pr_blink()>>1)+20;
|
||||
self->weaponspecial = (pr_blink()>>1)+20;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
@ -177,10 +177,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheckBlink)
|
|||
{
|
||||
if (self->player && self->player->ReadyWeapon)
|
||||
{
|
||||
if (!--self->special1)
|
||||
if (!--self->weaponspecial)
|
||||
{
|
||||
P_SetPsprite (self->player, ps_weapon, self->player->ReadyWeapon->FindState ("Blink"));
|
||||
self->special1 = (pr_blink()+50)>>2;
|
||||
self->weaponspecial = (pr_blink()+50)>>2;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -253,7 +253,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeAttack)
|
|||
}
|
||||
}
|
||||
// didn't find any creatures, so try to strike any walls
|
||||
pmo->special1 = 0;
|
||||
pmo->weaponspecial = 0;
|
||||
|
||||
angle = pmo->angle;
|
||||
slope = P_AimLineAttack (pmo, angle, MELEERANGE, &linetarget);
|
||||
|
|
|
@ -57,7 +57,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack)
|
|||
{
|
||||
P_ThrustMobj (linetarget, angle, power);
|
||||
}
|
||||
pmo->special1 = false; // Don't throw a hammer
|
||||
pmo->weaponspecial = false; // Don't throw a hammer
|
||||
goto hammerdone;
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack)
|
|||
{
|
||||
P_ThrustMobj(linetarget, angle, power);
|
||||
}
|
||||
pmo->special1 = false; // Don't throw a hammer
|
||||
pmo->weaponspecial = false; // Don't throw a hammer
|
||||
goto hammerdone;
|
||||
}
|
||||
}
|
||||
|
@ -83,11 +83,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack)
|
|||
slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE, &linetarget, 0, ALF_CHECK3D);
|
||||
if (P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, PClass::FindClass ("HammerPuff"), true) != NULL)
|
||||
{
|
||||
pmo->special1 = false;
|
||||
pmo->weaponspecial = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
pmo->special1 = true;
|
||||
pmo->weaponspecial = true;
|
||||
}
|
||||
hammerdone:
|
||||
// Don't spawn a hammer if the player doesn't have enough mana
|
||||
|
@ -95,7 +95,7 @@ hammerdone:
|
|||
!player->ReadyWeapon->CheckAmmo (player->ReadyWeapon->bAltFire ?
|
||||
AWeapon::AltFire : AWeapon::PrimaryFire, false, true))
|
||||
{
|
||||
pmo->special1 = false;
|
||||
pmo->weaponspecial = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerThrow)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!player->mo->special1)
|
||||
if (!player->mo->weaponspecial)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ static bool TryPunch(APlayerPawn *pmo, angle_t angle, int damage, fixed_t power)
|
|||
slope = P_AimLineAttack (pmo, angle, 2*MELEERANGE, &linetarget);
|
||||
if (linetarget != NULL)
|
||||
{
|
||||
if (++pmo->special1 >= 3)
|
||||
if (++pmo->weaponspecial >= 3)
|
||||
{
|
||||
damage <<= 1;
|
||||
power *= 3;
|
||||
|
@ -117,9 +117,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_FPunchAttack)
|
|||
if (TryPunch(pmo, pmo->angle + i*(ANG45/16), damage, power) ||
|
||||
TryPunch(pmo, pmo->angle - i*(ANG45/16), damage, power))
|
||||
{ // hit something
|
||||
if (pmo->special1 >= 3)
|
||||
if (pmo->weaponspecial >= 3)
|
||||
{
|
||||
pmo->special1 = 0;
|
||||
pmo->weaponspecial = 0;
|
||||
P_SetPsprite (player, ps_weapon, player->ReadyWeapon->FindState ("Fire2"));
|
||||
S_Sound (pmo, CHAN_VOICE, "*fistgrunt", 1, ATTN_NORM);
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FPunchAttack)
|
|||
}
|
||||
}
|
||||
// didn't find any creatures, so try to strike any walls
|
||||
pmo->special1 = 0;
|
||||
pmo->weaponspecial = 0;
|
||||
|
||||
AActor *linetarget;
|
||||
int slope = P_AimLineAttack (pmo, pmo->angle, MELEERANGE, &linetarget);
|
||||
|
|
|
@ -199,6 +199,46 @@ CCMD (map)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
CCMD(recordmap)
|
||||
{
|
||||
if (netgame)
|
||||
{
|
||||
Printf("You cannot record a new game while in a netgame.");
|
||||
return;
|
||||
}
|
||||
if (argv.argc() > 2)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!P_CheckMapData(argv[2]))
|
||||
{
|
||||
Printf("No map %s\n", argv[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
G_DeferedInitNew(argv[2]);
|
||||
gameaction = ga_recordgame;
|
||||
newdemoname = argv[1];
|
||||
newdemomap = argv[2];
|
||||
}
|
||||
}
|
||||
catch (CRecoverableError &error)
|
||||
{
|
||||
if (error.GetMessage())
|
||||
Printf("%s", error.GetMessage());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("Usage: recordmap <filename> <map name>\n");
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
CCMD (open)
|
||||
{
|
||||
if (netgame)
|
||||
|
@ -236,6 +276,18 @@ void G_NewInit ()
|
|||
{
|
||||
int i;
|
||||
|
||||
// Destory all old player refrences that may still exist
|
||||
TThinkerIterator<APlayerPawn> it(STAT_TRAVELLING);
|
||||
APlayerPawn *pawn, *next;
|
||||
|
||||
next = it.Next();
|
||||
while ((pawn = next) != NULL)
|
||||
{
|
||||
next = it.Next();
|
||||
pawn->flags |= MF_NOSECTOR | MF_NOBLOCKMAP;
|
||||
pawn->Destroy();
|
||||
}
|
||||
|
||||
G_ClearSnapshots ();
|
||||
ST_SetNeedRefresh();
|
||||
netgame = false;
|
||||
|
@ -499,7 +551,9 @@ void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill
|
|||
}
|
||||
else if (strncmp(levelname, "enDSeQ", 6) != 0)
|
||||
{
|
||||
nextinfo = FindLevelInfo (levelname, false);
|
||||
FString reallevelname = levelname;
|
||||
CheckWarpTransMap(reallevelname, true);
|
||||
nextinfo = FindLevelInfo (reallevelname, false);
|
||||
if (nextinfo != NULL)
|
||||
{
|
||||
level_info_t *nextredir = nextinfo->CheckLevelRedirect();
|
||||
|
@ -507,8 +561,12 @@ void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill
|
|||
{
|
||||
nextinfo = nextredir;
|
||||
}
|
||||
nextlevel = nextinfo->MapName;
|
||||
}
|
||||
else
|
||||
{
|
||||
nextlevel = levelname;
|
||||
}
|
||||
nextlevel = nextinfo->MapName;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1106,6 +1164,8 @@ void G_StartTravel ()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
bglobal.StartTravel ();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -1169,6 +1229,7 @@ void G_FinishTravel ()
|
|||
pawn->lastenemy = NULL;
|
||||
pawn->player->mo = pawn;
|
||||
pawn->player->camera = pawn;
|
||||
pawn->flags2 &= ~MF2_BLASTED;
|
||||
DObject::StaticPointerSubstitution (oldpawn, pawn);
|
||||
oldpawn->Destroy();
|
||||
pawndup->Destroy ();
|
||||
|
@ -1176,6 +1237,15 @@ void G_FinishTravel ()
|
|||
pawn->AddToHash ();
|
||||
pawn->SetState(pawn->SpawnState);
|
||||
pawn->player->SendPitchLimits();
|
||||
// Sync the FLY flags.
|
||||
if (pawn->flags2 & MF2_FLY)
|
||||
{
|
||||
pawn->player->cheats |= CF_FLY;
|
||||
}
|
||||
else
|
||||
{
|
||||
pawn->player->cheats &= ~CF_FLY;
|
||||
}
|
||||
|
||||
for (inv = pawn->Inventory; inv != NULL; inv = inv->Inventory)
|
||||
{
|
||||
|
@ -1193,6 +1263,8 @@ void G_FinishTravel ()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
bglobal.FinishTravel ();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -52,7 +52,7 @@ class FScanner;
|
|||
#define GCC_YSEG
|
||||
#else
|
||||
#define MSVC_YSEG
|
||||
#define GCC_YSEG __attribute__((section(SECTION_YREG)))
|
||||
#define GCC_YSEG __attribute__((section(SECTION_YREG))) __attribute__((used))
|
||||
#endif
|
||||
|
||||
struct FIntermissionDescriptor;
|
||||
|
@ -525,7 +525,7 @@ level_info_t *CheckLevelRedirect (level_info_t *info);
|
|||
|
||||
FString CalcMapName (int episode, int level);
|
||||
|
||||
void G_ParseMapInfo (const char *basemapinfo);
|
||||
void G_ParseMapInfo (FString basemapinfo);
|
||||
|
||||
void G_ClearSnapshots (void);
|
||||
void P_RemoveDefereds ();
|
||||
|
|
|
@ -1306,6 +1306,7 @@ MapFlagHandlers[] =
|
|||
{ "compat_maskedmidtex", MITYPE_COMPATFLAG, COMPATF_MASKEDMIDTEX, 0 },
|
||||
{ "compat_badangles", MITYPE_COMPATFLAG, 0, COMPATF2_BADANGLES },
|
||||
{ "compat_floormove", MITYPE_COMPATFLAG, 0, COMPATF2_FLOORMOVE },
|
||||
{ "compat_soundcutoff", MITYPE_COMPATFLAG, 0, COMPATF2_SOUNDCUTOFF },
|
||||
{ "cd_start_track", MITYPE_EATNEXT, 0, 0 },
|
||||
{ "cd_end1_track", MITYPE_EATNEXT, 0, 0 },
|
||||
{ "cd_end2_track", MITYPE_EATNEXT, 0, 0 },
|
||||
|
@ -1886,7 +1887,7 @@ static void ClearMapinfo()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void G_ParseMapInfo (const char *basemapinfo)
|
||||
void G_ParseMapInfo (FString basemapinfo)
|
||||
{
|
||||
int lump, lastlump = 0;
|
||||
level_info_t gamedefaults;
|
||||
|
@ -1895,7 +1896,7 @@ void G_ParseMapInfo (const char *basemapinfo)
|
|||
atterm(ClearMapinfo);
|
||||
|
||||
// Parse the default MAPINFO for the current game. This lump *MUST* come from zdoom.pk3.
|
||||
if (basemapinfo != NULL)
|
||||
if (basemapinfo.IsNotEmpty())
|
||||
{
|
||||
FMapInfoParser parse;
|
||||
level_info_t defaultinfo;
|
||||
|
@ -1903,7 +1904,7 @@ void G_ParseMapInfo (const char *basemapinfo)
|
|||
if (Wads.GetLumpFile(baselump) > 0)
|
||||
{
|
||||
I_FatalError("File %s is overriding core lump %s.",
|
||||
Wads.GetWadFullName(Wads.GetLumpFile(baselump)), basemapinfo);
|
||||
Wads.GetWadFullName(Wads.GetLumpFile(baselump)), basemapinfo.GetChars());
|
||||
}
|
||||
parse.ParseMapInfo(baselump, gamedefaults, defaultinfo);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,11 @@ void ABasicArmor::Serialize (FArchive &arc)
|
|||
{
|
||||
Super::Serialize (arc);
|
||||
arc << SavePercent << BonusCount << MaxAbsorb << MaxFullAbsorb << AbsorbCount << ArmorType;
|
||||
|
||||
if (SaveVersion >= 4511)
|
||||
{
|
||||
arc << ActualSaveAmount;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
@ -69,6 +74,7 @@ AInventory *ABasicArmor::CreateCopy (AActor *other)
|
|||
copy->Icon = Icon;
|
||||
copy->BonusCount = BonusCount;
|
||||
copy->ArmorType = ArmorType;
|
||||
copy->ActualSaveAmount = ActualSaveAmount;
|
||||
GoAwayAndDie ();
|
||||
return copy;
|
||||
}
|
||||
|
@ -268,6 +274,7 @@ bool ABasicArmorPickup::Use (bool pickup)
|
|||
armor->MaxAbsorb = MaxAbsorb;
|
||||
armor->MaxFullAbsorb = MaxFullAbsorb;
|
||||
armor->ArmorType = this->GetClass()->TypeName;
|
||||
armor->ActualSaveAmount = SaveAmount;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -360,6 +367,7 @@ bool ABasicArmorBonus::Use (bool pickup)
|
|||
armor->MaxAbsorb = MaxAbsorb;
|
||||
armor->ArmorType = this->GetClass()->TypeName;
|
||||
armor->MaxFullAbsorb = MaxFullAbsorb;
|
||||
armor->ActualSaveAmount = MaxSaveAmount;
|
||||
}
|
||||
|
||||
armor->Amount = MIN(armor->Amount + saveAmount, MaxSaveAmount + armor->BonusCount);
|
||||
|
@ -508,7 +516,14 @@ void AHexenArmor::AbsorbDamage (int damage, FName damageType, int &newdamage)
|
|||
// with the dragon skin bracers.
|
||||
if (damage < 10000)
|
||||
{
|
||||
#if __APPLE__ && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && __GNUC_PATCHLEVEL__ == 1
|
||||
// -O1 optimizer bug work around. Only needed for
|
||||
// GCC 4.2.1 on OS X for 10.4/10.5 tools compatibility.
|
||||
volatile fixed_t tmp = 300;
|
||||
Slots[i] -= Scale (damage, SlotsIncrement[i], tmp);
|
||||
#else
|
||||
Slots[i] -= Scale (damage, SlotsIncrement[i], 300);
|
||||
#endif
|
||||
if (Slots[i] < 2*FRACUNIT)
|
||||
{
|
||||
Slots[i] = 0;
|
||||
|
|
|
@ -60,7 +60,8 @@ bool APowerupGiver::Use (bool pickup)
|
|||
}
|
||||
if (BlendColor != 0)
|
||||
{
|
||||
power->BlendColor = BlendColor;
|
||||
if (BlendColor != MakeSpecialColormap(65535)) power->BlendColor = BlendColor;
|
||||
else power->BlendColor = 0;
|
||||
}
|
||||
if (Mode != NAME_None)
|
||||
{
|
||||
|
@ -1296,6 +1297,18 @@ void APowerTargeter::InitEffect ()
|
|||
PositionAccuracy ();
|
||||
}
|
||||
|
||||
bool APowerTargeter::HandlePickup(AInventory *item)
|
||||
{
|
||||
if (Super::HandlePickup(item))
|
||||
{
|
||||
InitEffect(); // reset the HUD sprites
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void APowerTargeter::DoEffect ()
|
||||
{
|
||||
Super::DoEffect ();
|
||||
|
@ -1384,6 +1397,42 @@ void APowerFrightener::EndEffect ()
|
|||
Owner->player->cheats &= ~CF_FRIGHTENING;
|
||||
}
|
||||
|
||||
// Buddha Powerup --------------------------------
|
||||
|
||||
IMPLEMENT_CLASS (APowerBuddha)
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerBuddha :: InitEffect
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void APowerBuddha::InitEffect ()
|
||||
{
|
||||
Super::InitEffect();
|
||||
|
||||
if (Owner== NULL || Owner->player == NULL)
|
||||
return;
|
||||
|
||||
Owner->player->cheats |= CF_BUDDHA;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerBuddha :: EndEffect
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void APowerBuddha::EndEffect ()
|
||||
{
|
||||
Super::EndEffect();
|
||||
|
||||
if (Owner== NULL || Owner->player == NULL)
|
||||
return;
|
||||
|
||||
Owner->player->cheats &= ~CF_BUDDHA;
|
||||
}
|
||||
|
||||
// Scanner powerup ----------------------------------------------------------
|
||||
|
||||
IMPLEMENT_CLASS (APowerScanner)
|
||||
|
|
|
@ -173,6 +173,7 @@ protected:
|
|||
void EndEffect ();
|
||||
void PositionAccuracy ();
|
||||
void Travelled ();
|
||||
bool HandlePickup(AInventory *item);
|
||||
};
|
||||
|
||||
class APowerFrightener : public APowerup
|
||||
|
@ -183,6 +184,14 @@ protected:
|
|||
void EndEffect ();
|
||||
};
|
||||
|
||||
class APowerBuddha : public APowerup
|
||||
{
|
||||
DECLARE_CLASS (APowerBuddha, APowerup)
|
||||
protected:
|
||||
void InitEffect ();
|
||||
void EndEffect ();
|
||||
};
|
||||
|
||||
class APowerTimeFreezer : public APowerup
|
||||
{
|
||||
DECLARE_CLASS( APowerTimeFreezer, APowerup )
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "doomstat.h"
|
||||
#include "g_level.h"
|
||||
#include "farchive.h"
|
||||
#include "p_enemy.h"
|
||||
|
||||
static FRandom pr_morphmonst ("MorphMonster");
|
||||
|
||||
|
@ -527,11 +528,11 @@ bool P_MorphedDeath(AActor *actor, AActor **morphed, int *morphedstyle, int *mor
|
|||
if (actor->GetClass()->IsDescendantOf(RUNTIME_CLASS(AMorphedMonster)))
|
||||
{
|
||||
AMorphedMonster *fakeme = static_cast<AMorphedMonster *>(actor);
|
||||
AActor *realme = fakeme->UnmorphedMe;
|
||||
if ((fakeme->UnmorphTime) &&
|
||||
(fakeme->MorphStyle & MORPH_UNDOBYDEATH) &&
|
||||
(fakeme->UnmorphedMe))
|
||||
(realme))
|
||||
{
|
||||
AActor *realme = fakeme->UnmorphedMe;
|
||||
int realstyle = fakeme->MorphStyle;
|
||||
int realhealth = fakeme->health;
|
||||
if (P_UndoMonsterMorph(fakeme, !!(fakeme->MorphStyle & MORPH_UNDOBYDEATHFORCED)))
|
||||
|
@ -542,6 +543,11 @@ bool P_MorphedDeath(AActor *actor, AActor **morphed, int *morphedstyle, int *mor
|
|||
return true;
|
||||
}
|
||||
}
|
||||
if (realme->flags4 & MF4_BOSSDEATH)
|
||||
{
|
||||
realme->health = 0; // make sure that A_BossDeath considers it dead.
|
||||
CALL_ACTION(A_BossDeath, realme);
|
||||
}
|
||||
fakeme->flags3 |= MF3_STAYMORPHED; // moved here from AMorphedMonster::Die()
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -499,7 +499,7 @@ bool AInventory::ShouldRespawn ()
|
|||
{
|
||||
if ((ItemFlags & IF_BIGPOWERUP) && !(dmflags2 & DF2_RESPAWN_SUPER)) return false;
|
||||
if (ItemFlags & IF_NEVERRESPAWN) return false;
|
||||
return !!(dmflags & DF_ITEMS_RESPAWN);
|
||||
return !!((dmflags & DF_ITEMS_RESPAWN) || (ItemFlags & IF_ALWAYSRESPAWN));
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
@ -1024,8 +1024,8 @@ void AInventory::Touch (AActor *toucher)
|
|||
//Added by MC: Check if item taken was the roam destination of any bot
|
||||
for (int i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && this == players[i].dest)
|
||||
players[i].dest = NULL;
|
||||
if (players[i].Bot != NULL && this == players[i].Bot->dest)
|
||||
players[i].Bot->dest = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -135,6 +135,7 @@ enum
|
|||
IF_NEVERRESPAWN = 1<<20, // Never, ever respawns
|
||||
IF_NOSCREENFLASH = 1<<21, // No pickup flash on the player's screen
|
||||
IF_TOSSED = 1<<22, // Was spawned by P_DropItem (i.e. as a monster drop)
|
||||
IF_ALWAYSRESPAWN = 1<<23, // Always respawn, regardless of dmflag
|
||||
|
||||
};
|
||||
|
||||
|
@ -423,6 +424,7 @@ public:
|
|||
int MaxFullAbsorb;
|
||||
int BonusCount;
|
||||
FNameNoInit ArmorType;
|
||||
int ActualSaveAmount;
|
||||
};
|
||||
|
||||
// BasicArmorPickup replaces the armor you have.
|
||||
|
|
|
@ -444,7 +444,7 @@ int FMugShot::UpdateState(player_t *player, StateFlags stateflags)
|
|||
if (bNormal)
|
||||
{
|
||||
bool good;
|
||||
if ((player->cheats & CF_GODMODE) || (player->mo != NULL && player->mo->flags2 & MF2_INVULNERABLE))
|
||||
if ((player->cheats & CF_GODMODE) || (player->cheats & CF_GODMODE2) || (player->mo != NULL && player->mo->flags2 & MF2_INVULNERABLE))
|
||||
{
|
||||
good = SetState((stateflags & ANIMATEDGODMODE) ? "godanimated" : "god");
|
||||
}
|
||||
|
|
|
@ -886,8 +886,11 @@ class CommandDrawString : public SBarInfoCommand
|
|||
}
|
||||
break;
|
||||
case TIME:
|
||||
str.Format("%02d:%02d:%02d", (level.time/TICRATE)/3600, ((level.time/TICRATE)%3600)/60, (level.time/TICRATE)%60);
|
||||
{
|
||||
int sec = Tics2Seconds(level.time);
|
||||
str.Format("%02d:%02d:%02d", sec / 3600, (sec % 3600) / 60, sec % 60);
|
||||
break;
|
||||
}
|
||||
case LOGTEXT:
|
||||
str = statusBar->CPlayer->LogText;
|
||||
break;
|
||||
|
@ -3380,43 +3383,16 @@ class CommandInInventory : public SBarInfoCommandFlowControl
|
|||
AInventory *invItem[2] = { statusBar->CPlayer->mo->FindInventory(item[0]), statusBar->CPlayer->mo->FindInventory(item[1]) };
|
||||
if (invItem[0] != NULL && amount[0] > 0 && invItem[0]->Amount < amount[0]) invItem[0] = NULL;
|
||||
if (invItem[1] != NULL && amount[1] > 0 && invItem[1]->Amount < amount[1]) invItem[1] = NULL;
|
||||
if(invItem[1] != NULL && conditionAnd)
|
||||
|
||||
if (item[1])
|
||||
{
|
||||
if((invItem[0] != NULL && invItem[1] != NULL) && !negate)
|
||||
{
|
||||
SetTruth(true, block, statusBar);
|
||||
return;
|
||||
}
|
||||
else if((invItem[0] == NULL || invItem[1] == NULL) && negate)
|
||||
{
|
||||
SetTruth(true, block, statusBar);
|
||||
return;
|
||||
}
|
||||
if (conditionAnd)
|
||||
SetTruth((invItem[0] && invItem[1]) != negate, block, statusBar);
|
||||
else
|
||||
SetTruth((invItem[0] || invItem[1]) != negate, block, statusBar);
|
||||
}
|
||||
else if(invItem[1] != NULL && !conditionAnd)
|
||||
{
|
||||
if((invItem[0] != NULL || invItem[1] != NULL) && !negate)
|
||||
{
|
||||
SetTruth(true, block, statusBar);
|
||||
return;
|
||||
}
|
||||
else if((invItem[0] == NULL && invItem[1] == NULL) && negate)
|
||||
{
|
||||
SetTruth(true, block, statusBar);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if((invItem[0] != NULL) && !negate)
|
||||
{
|
||||
SetTruth(true, block, statusBar);
|
||||
return;
|
||||
}
|
||||
else if((invItem[0] == NULL) && negate)
|
||||
{
|
||||
SetTruth(true, block, statusBar);
|
||||
return;
|
||||
}
|
||||
SetTruth(false, block, statusBar);
|
||||
else
|
||||
SetTruth((invItem[0] != NULL) != negate, block, statusBar);
|
||||
}
|
||||
protected:
|
||||
bool conditionAnd;
|
||||
|
@ -3455,6 +3431,46 @@ class CommandAlpha : public SBarInfoMainBlock
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CommandIfHealth : public SBarInfoCommandFlowControl
|
||||
{
|
||||
public:
|
||||
CommandIfHealth(SBarInfo *script) : SBarInfoCommandFlowControl(script),
|
||||
negate(false), percentage(false)
|
||||
{
|
||||
}
|
||||
|
||||
void Parse(FScanner &sc, bool fullScreenOffsets)
|
||||
{
|
||||
if (sc.CheckToken(TK_Identifier))
|
||||
{
|
||||
if (sc.Compare("not"))
|
||||
negate = true;
|
||||
else
|
||||
sc.ScriptError("Expected 'not', but got '%s' instead.", sc.String);
|
||||
}
|
||||
|
||||
sc.MustGetToken(TK_IntConst);
|
||||
percentage = sc.CheckToken('%');
|
||||
hpamount = sc.Number;
|
||||
|
||||
SBarInfoCommandFlowControl::Parse(sc, fullScreenOffsets);
|
||||
}
|
||||
void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged)
|
||||
{
|
||||
SBarInfoCommandFlowControl::Tick(block, statusBar, hudChanged);
|
||||
|
||||
int phealth = percentage ? statusBar->CPlayer->mo->health * 100 / statusBar->CPlayer->mo->GetMaxHealth() : statusBar->CPlayer->mo->health;
|
||||
|
||||
SetTruth((phealth >= hpamount) ^ negate, block, statusBar);
|
||||
}
|
||||
protected:
|
||||
bool negate;
|
||||
bool percentage;
|
||||
int hpamount;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static const char *SBarInfoCommandNames[] =
|
||||
{
|
||||
"drawimage", "drawnumber", "drawswitchableimage",
|
||||
|
@ -3464,7 +3480,7 @@ static const char *SBarInfoCommandNames[] =
|
|||
"gamemode", "playerclass", "playertype", "aspectratio",
|
||||
"isselected", "usesammo", "usessecondaryammo",
|
||||
"hasweaponpiece", "inventorybarnotvisible",
|
||||
"weaponammo", "ininventory", "alpha",
|
||||
"weaponammo", "ininventory", "alpha", "ifhealth",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -3477,7 +3493,7 @@ enum SBarInfoCommands
|
|||
SBARINFO_GAMEMODE, SBARINFO_PLAYERCLASS, SBARINFO_PLAYERTYPE, SBARINFO_ASPECTRATIO,
|
||||
SBARINFO_ISSELECTED, SBARINFO_USESAMMO, SBARINFO_USESSECONDARYAMMO,
|
||||
SBARINFO_HASWEAPONPIECE, SBARINFO_INVENTORYBARNOTVISIBLE,
|
||||
SBARINFO_WEAPONAMMO, SBARINFO_ININVENTORY, SBARINFO_ALPHA,
|
||||
SBARINFO_WEAPONAMMO, SBARINFO_ININVENTORY, SBARINFO_ALPHA, SBARINFO_IFHEALTH,
|
||||
};
|
||||
|
||||
SBarInfoCommand *SBarInfoCommandFlowControl::NextCommand(FScanner &sc)
|
||||
|
@ -3510,6 +3526,7 @@ SBarInfoCommand *SBarInfoCommandFlowControl::NextCommand(FScanner &sc)
|
|||
case SBARINFO_WEAPONAMMO: return new CommandWeaponAmmo(script);
|
||||
case SBARINFO_ININVENTORY: return new CommandInInventory(script);
|
||||
case SBARINFO_ALPHA: return new CommandAlpha(script);
|
||||
case SBARINFO_IFHEALTH: return new CommandIfHealth(script);
|
||||
}
|
||||
|
||||
sc.ScriptError("Unknown command '%s'.\n", sc.String);
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
// copy would be.
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "doomdef.h"
|
||||
#include "v_video.h"
|
||||
#include "gi.h"
|
||||
#include "c_cvars.h"
|
||||
|
@ -48,6 +49,7 @@
|
|||
#include "p_local.h"
|
||||
#include "doomstat.h"
|
||||
#include "g_level.h"
|
||||
#include "d_net.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
|
@ -73,6 +75,7 @@ CVAR (Bool, hud_showscore, false, CVAR_ARCHIVE); // for user maintained score
|
|||
CVAR (Bool, hud_showweapons, true, CVAR_ARCHIVE); // Show weapons collected
|
||||
CVAR (Int , hud_showtime, 0, CVAR_ARCHIVE); // Show time on HUD
|
||||
CVAR (Int , hud_timecolor, CR_GOLD,CVAR_ARCHIVE); // Color of in-game time on HUD
|
||||
CVAR (Int , hud_showlag, 0, CVAR_ARCHIVE); // Show input latency (maketic - gametic difference)
|
||||
|
||||
CVAR (Int, hud_ammo_red, 25, CVAR_ARCHIVE) // ammo percent less than which status is red
|
||||
CVAR (Int, hud_ammo_yellow, 50, CVAR_ARCHIVE) // ammo percent less is yellow more green
|
||||
|
@ -867,7 +870,7 @@ static void DrawTime()
|
|||
: (hud_showtime < 6
|
||||
? level.time
|
||||
: level.totaltime);
|
||||
const int timeSeconds = timeTicks / TICRATE;
|
||||
const int timeSeconds = Tics2Seconds(timeTicks);
|
||||
|
||||
hours = timeSeconds / 3600;
|
||||
minutes = (timeSeconds % 3600) / 60;
|
||||
|
@ -917,6 +920,51 @@ static void DrawTime()
|
|||
DrawHudText(SmallFont, hud_timecolor, timeString, hudwidth - width, height, FRACUNIT);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Draw in-game latency
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
static void DrawLatency()
|
||||
{
|
||||
if (hud_showlag <= 0 ||
|
||||
(hud_showlag == 1 && !netgame) ||
|
||||
hud_showlag > 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int i, localdelay = 0, arbitratordelay = 0;
|
||||
for (i = 0; i < BACKUPTICS; i++) localdelay += netdelay[0][i];
|
||||
for (i = 0; i < BACKUPTICS; i++) arbitratordelay += netdelay[nodeforplayer[Net_Arbitrator]][i];
|
||||
localdelay = ((localdelay / BACKUPTICS) * ticdup) * (1000 / TICRATE);
|
||||
arbitratordelay = ((arbitratordelay / BACKUPTICS) * ticdup) * (1000 / TICRATE);
|
||||
int color = CR_GREEN;
|
||||
if (MAX(localdelay, arbitratordelay) > 200)
|
||||
{
|
||||
color = CR_YELLOW;
|
||||
}
|
||||
if (MAX(localdelay, arbitratordelay) > 400)
|
||||
{
|
||||
color = CR_ORANGE;
|
||||
}
|
||||
if (MAX(localdelay, arbitratordelay) >= ((BACKUPTICS / 2 - 1) * ticdup) * (1000 / TICRATE))
|
||||
{
|
||||
color = CR_RED;
|
||||
}
|
||||
|
||||
char tempstr[32];
|
||||
|
||||
const int millis = (level.time % TICRATE) * (1000 / TICRATE);
|
||||
mysnprintf(tempstr, sizeof(tempstr), "a:%dms - l:%dms", arbitratordelay, localdelay);
|
||||
|
||||
const int characterCount = strlen(tempstr);
|
||||
const int width = SmallFont->GetCharWidth('0') * characterCount + 2; // small offset from screen's border
|
||||
const int height = SmallFont->GetHeight() * 2;
|
||||
|
||||
DrawHudText(SmallFont, color, tempstr, hudwidth - width, height, FRACUNIT);
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
|
@ -982,6 +1030,7 @@ void DrawHUD()
|
|||
if (idmypos) DrawCoordinates(CPlayer);
|
||||
|
||||
DrawTime();
|
||||
DrawLatency();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -994,7 +1043,7 @@ void DrawHUD()
|
|||
|
||||
if (am_showtotaltime)
|
||||
{
|
||||
seconds = level.totaltime / TICRATE;
|
||||
seconds = Tics2Seconds(level.totaltime);
|
||||
mysnprintf(printstr, countof(printstr), "%02i:%02i:%02i", seconds/3600, (seconds%3600)/60, seconds%60);
|
||||
DrawHudText(SmallFont, hudcolor_ttim, printstr, hudwidth-length, bottom, FRACUNIT);
|
||||
bottom -= fonth;
|
||||
|
@ -1004,14 +1053,14 @@ void DrawHUD()
|
|||
{
|
||||
if (level.clusterflags&CLUSTER_HUB)
|
||||
{
|
||||
seconds = level.time /TICRATE;
|
||||
seconds = Tics2Seconds(level.time);
|
||||
mysnprintf(printstr, countof(printstr), "%02i:%02i:%02i", seconds/3600, (seconds%3600)/60, seconds%60);
|
||||
DrawHudText(SmallFont, hudcolor_time, printstr, hudwidth-length, bottom, FRACUNIT);
|
||||
bottom -= fonth;
|
||||
}
|
||||
|
||||
// Single level time for hubs
|
||||
seconds= level.maptime /TICRATE;
|
||||
seconds= Tics2Seconds(level.maptime);
|
||||
mysnprintf(printstr, countof(printstr), "%02i:%02i:%02i", seconds/3600, (seconds%3600)/60, seconds%60);
|
||||
DrawHudText(SmallFont, hudcolor_ltim, printstr, hudwidth-length, bottom, FRACUNIT);
|
||||
}
|
||||
|
|
|
@ -146,7 +146,6 @@ void ST_LoadCrosshair(bool alwaysload)
|
|||
{
|
||||
int num = 0;
|
||||
char name[16], size;
|
||||
int lump;
|
||||
|
||||
if (!crosshairforce &&
|
||||
players[consoleplayer].camera != NULL &&
|
||||
|
@ -179,18 +178,20 @@ void ST_LoadCrosshair(bool alwaysload)
|
|||
num = -num;
|
||||
}
|
||||
size = (SCREENWIDTH < 640) ? 'S' : 'B';
|
||||
|
||||
mysnprintf (name, countof(name), "XHAIR%c%d", size, num);
|
||||
if ((lump = Wads.CheckNumForName (name, ns_graphics)) == -1)
|
||||
FTextureID texid = TexMan.CheckForTexture(name, FTexture::TEX_MiscPatch, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ShortNameOnly);
|
||||
if (!texid.isValid())
|
||||
{
|
||||
mysnprintf (name, countof(name), "XHAIR%c1", size);
|
||||
if ((lump = Wads.CheckNumForName (name, ns_graphics)) == -1)
|
||||
texid = TexMan.CheckForTexture(name, FTexture::TEX_MiscPatch, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ShortNameOnly);
|
||||
if (!texid.isValid())
|
||||
{
|
||||
strcpy (name, "XHAIRS1");
|
||||
texid = TexMan.CheckForTexture("XHAIRS1", FTexture::TEX_MiscPatch, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ShortNameOnly);
|
||||
}
|
||||
num = 1;
|
||||
}
|
||||
CrosshairNum = num;
|
||||
CrosshairImage = TexMan[TexMan.CheckForTexture(name, FTexture::TEX_MiscPatch)];
|
||||
CrosshairImage = TexMan[texid];
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -1122,7 +1123,7 @@ void DBaseStatusBar::DrawCrosshair ()
|
|||
ST_LoadCrosshair();
|
||||
|
||||
// Don't draw the crosshair if there is none
|
||||
if (CrosshairImage == NULL || gamestate == GS_TITLELEVEL)
|
||||
if (CrosshairImage == NULL || gamestate == GS_TITLELEVEL || camera->health <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -1306,8 +1307,8 @@ void DBaseStatusBar::Draw (EHudState state)
|
|||
}
|
||||
else if (automapactive)
|
||||
{
|
||||
int y, time = level.time / TICRATE, height;
|
||||
int totaltime = level.totaltime / TICRATE;
|
||||
int y, time = Tics2Seconds(level.time), height;
|
||||
int totaltime = Tics2Seconds(level.totaltime);
|
||||
EColorRange highlight = (gameinfo.gametype & GAME_DoomChex) ?
|
||||
CR_UNTRANSLATED : CR_YELLOW;
|
||||
|
||||
|
|
|
@ -106,7 +106,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_AlienSpectreDeath)
|
|||
switch (self->GetClass()->TypeName)
|
||||
{
|
||||
case NAME_AlienSpectre1:
|
||||
EV_DoFloor (DFloor::floorLowerToLowest, NULL, 999, FRACUNIT, 0, 0, 0, false);
|
||||
EV_DoFloor (DFloor::floorLowerToLowest, NULL, 999, FRACUNIT, 0, -1, 0, false);
|
||||
log = 95;
|
||||
break;
|
||||
|
||||
|
@ -180,7 +180,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_AlienSpectreDeath)
|
|||
{ // Another Sigil piece. Woohoo!
|
||||
log = 83;
|
||||
}
|
||||
EV_DoFloor (DFloor::floorLowerToLowest, NULL, 666, FRACUNIT, 0, 0, 0, false);
|
||||
EV_DoFloor (DFloor::floorLowerToLowest, NULL, 666, FRACUNIT, 0, -1, 0, false);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -80,6 +80,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_CrusaderDeath)
|
|||
{
|
||||
if (CheckBossDeath (self))
|
||||
{
|
||||
EV_DoFloor (DFloor::floorLowerToLowest, NULL, 667, FRACUNIT, 0, 0, 0, false);
|
||||
EV_DoFloor (DFloor::floorLowerToLowest, NULL, 667, FRACUNIT, 0, -1, 0, false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -548,7 +548,7 @@ void APowerCoupling::Die (AActor *source, AActor *inflictor, int dmgflags)
|
|||
P_NoiseAlert (source, this);
|
||||
}
|
||||
EV_DoDoor (DDoor::doorClose, NULL, players[i].mo, 225, 2*FRACUNIT, 0, 0, 0);
|
||||
EV_DoFloor (DFloor::floorLowerToHighest, NULL, 44, FRACUNIT, 0, 0, 0, false);
|
||||
EV_DoFloor (DFloor::floorLowerToHighest, NULL, 44, FRACUNIT, 0, -1, 0, false);
|
||||
players[i].mo->GiveInventoryType (QuestItemClasses[5]);
|
||||
S_Sound (CHAN_VOICE, "svox/voc13", 1, ATTN_NORM);
|
||||
players[i].SetLogNumber (13);
|
||||
|
|
|
@ -586,29 +586,33 @@ private:
|
|||
screen->DrawTexture (Images[back], left, top, DTA_CleanNoMove, true, DTA_Alpha, FRACUNIT*3/4, TAG_DONE);
|
||||
screen->DrawTexture (Images[bars], left, top, DTA_CleanNoMove, true, TAG_DONE);
|
||||
|
||||
|
||||
switch (CurrentPop)
|
||||
{
|
||||
case POP_Log:
|
||||
{
|
||||
int seconds = Tics2Seconds(level.time);
|
||||
// Draw the latest log message.
|
||||
mysnprintf (buff, countof(buff), "%02d:%02d:%02d",
|
||||
(level.time/TICRATE)/3600,
|
||||
((level.time/TICRATE)%3600)/60,
|
||||
(level.time/TICRATE)%60);
|
||||
mysnprintf(buff, countof(buff), "%02d:%02d:%02d",
|
||||
seconds / 3600,
|
||||
(seconds % 3600) / 60,
|
||||
(seconds) % 60);
|
||||
|
||||
screen->DrawText (SmallFont2, CR_UNTRANSLATED, left+210*xscale, top+8*yscale, buff,
|
||||
screen->DrawText(SmallFont2, CR_UNTRANSLATED, left + 210 * xscale, top + 8 * yscale, buff,
|
||||
DTA_CleanNoMove, true, TAG_DONE);
|
||||
|
||||
if (CPlayer->LogText != NULL)
|
||||
{
|
||||
FBrokenLines *lines = V_BreakLines (SmallFont2, 272, CPlayer->LogText);
|
||||
FBrokenLines *lines = V_BreakLines(SmallFont2, 272, CPlayer->LogText);
|
||||
for (i = 0; lines[i].Width >= 0; ++i)
|
||||
{
|
||||
screen->DrawText (SmallFont2, CR_UNTRANSLATED, left+24*xscale, top+(18+i*12)*yscale,
|
||||
screen->DrawText(SmallFont2, CR_UNTRANSLATED, left + 24 * xscale, top + (18 + i * 12)*yscale,
|
||||
lines[i].Text, DTA_CleanNoMove, true, TAG_DONE);
|
||||
}
|
||||
V_FreeBrokenLines (lines);
|
||||
V_FreeBrokenLines(lines);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case POP_Keys:
|
||||
// List the keys the player has.
|
||||
|
|
|
@ -41,7 +41,7 @@ static inline SDWORD Scale (SDWORD a, SDWORD b, SDWORD c)
|
|||
: "a,a,a,a,a,a" (a),
|
||||
"m,r,m,r,d,d" (b),
|
||||
"r,r,m,m,r,m" (c)
|
||||
: "%cc"
|
||||
: "cc"
|
||||
);
|
||||
|
||||
return result;
|
||||
|
@ -59,7 +59,7 @@ static inline SDWORD MulScale (SDWORD a, SDWORD b, SDWORD c)
|
|||
: "a,a,a,a" (a),
|
||||
"m,r,m,r" (b),
|
||||
"c,c,I,I" (c)
|
||||
: "%cc"
|
||||
: "cc"
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
@ -210,7 +210,7 @@ static inline SDWORD DivScale (SDWORD a, SDWORD b, SDWORD c)
|
|||
: "a" (lo),
|
||||
"d" (hi),
|
||||
"r" (b)
|
||||
: "%cc");
|
||||
: "cc");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -226,7 +226,7 @@ static inline SDWORD DivScale1 (SDWORD a, SDWORD b)
|
|||
"=&d,d" (dummy)
|
||||
: "a,a" (a),
|
||||
"r,m" (b)
|
||||
: "%cc");
|
||||
: "cc");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -241,7 +241,7 @@ static inline SDWORD DivScale1 (SDWORD a, SDWORD b)
|
|||
: "a,a" (a<<s), \
|
||||
"d,d" (a>>(32-s)), \
|
||||
"r,m" (b) \
|
||||
: "%cc"); \
|
||||
: "cc"); \
|
||||
return result; \
|
||||
}
|
||||
|
||||
|
@ -287,7 +287,7 @@ static inline SDWORD DivScale32 (SDWORD a, SDWORD b)
|
|||
"=d,d" (dummy)
|
||||
: "d,d" (a),
|
||||
"r,m" (b)
|
||||
: "%cc");
|
||||
: "cc");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -313,7 +313,7 @@ static inline void clearbufshort (void *buff, unsigned int count, WORD clear)
|
|||
"rep stosw"
|
||||
:"=D" (buff), "=c" (count)
|
||||
:"D" (buff), "c" (count), "a" (clear|(clear<<16))
|
||||
:"%cc");
|
||||
:"cc");
|
||||
}
|
||||
|
||||
static inline SDWORD ksgn (SDWORD a)
|
||||
|
@ -327,6 +327,6 @@ static inline SDWORD ksgn (SDWORD a)
|
|||
"adc $0,%1"
|
||||
:"=r" (dummy), "=r" (result)
|
||||
:"0" (a)
|
||||
:"%cc");
|
||||
:"cc");
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -290,6 +290,8 @@ void FMapInfoParser::ParseGameInfo()
|
|||
else gameinfo.mCheatMapArrow = "";
|
||||
}
|
||||
// Insert valid keys here.
|
||||
GAMEINFOKEY_STRING(mCheatKey, "cheatKey")
|
||||
GAMEINFOKEY_STRING(mEasyKey, "easyKey")
|
||||
GAMEINFOKEY_STRING(TitlePage, "titlePage")
|
||||
GAMEINFOKEY_STRINGARRAY(creditPages, "addcreditPage", 8, false)
|
||||
GAMEINFOKEY_STRINGARRAY(creditPages, "CreditPage", 8, true)
|
||||
|
|
1
src/gi.h
1
src/gi.h
|
@ -169,6 +169,7 @@ struct gameinfo_t
|
|||
int TextScreenY;
|
||||
FName DefaultEndSequence;
|
||||
FString mMapArrow, mCheatMapArrow;
|
||||
FString mEasyKey, mCheatKey;
|
||||
FGIFont mStatscreenMapNameFont;
|
||||
FGIFont mStatscreenFinishedFont;
|
||||
FGIFont mStatscreenEnteringFont;
|
||||
|
|
|
@ -48,6 +48,8 @@
|
|||
#include "d_player.h"
|
||||
#include "hu_stuff.h"
|
||||
#include "gstrings.h"
|
||||
#include "d_net.h"
|
||||
#include "c_dispatch.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
@ -61,7 +63,7 @@
|
|||
|
||||
static void HU_DoDrawScores (player_t *, player_t *[MAXPLAYERS]);
|
||||
static void HU_DrawTimeRemaining (int y);
|
||||
static void HU_DrawPlayer (player_t *, bool, int, int, int, int, int, int, int, int);
|
||||
static void HU_DrawPlayer(player_t *, bool, int, int, int, int, int, int, int, int, int);
|
||||
|
||||
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
||||
|
||||
|
@ -116,6 +118,8 @@ int STACK_ARGS compareteams (const void *arg1, const void *arg2)
|
|||
return diff;
|
||||
}
|
||||
|
||||
bool SB_ForceActive = false;
|
||||
|
||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||
|
||||
// CODE --------------------------------------------------------------------
|
||||
|
@ -228,7 +232,7 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER
|
|||
int maxnamewidth, maxscorewidth, maxiconheight;
|
||||
int numTeams = 0;
|
||||
int x, y, ypadding, bottom;
|
||||
int col2, col3, col4;
|
||||
int col2, col3, col4, col5;
|
||||
|
||||
if (deathmatch)
|
||||
{
|
||||
|
@ -309,12 +313,14 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER
|
|||
|
||||
const char *text_color = GStrings("SCORE_COLOR"),
|
||||
*text_frags = GStrings(deathmatch ? "SCORE_FRAGS" : "SCORE_KILLS"),
|
||||
*text_name = GStrings("SCORE_NAME");
|
||||
*text_name = GStrings("SCORE_NAME"),
|
||||
*text_delay = GStrings("SCORE_DELAY");
|
||||
|
||||
col2 = (SmallFont->StringWidth(text_color) + 8) * CleanXfac;
|
||||
col3 = col2 + (SmallFont->StringWidth(text_frags) + 8) * CleanXfac;
|
||||
col4 = col3 + maxscorewidth * CleanXfac;
|
||||
x = (SCREENWIDTH >> 1) - ((maxnamewidth * CleanXfac + col4) >> 1);
|
||||
col5 = col4 + (maxnamewidth + 8) * CleanXfac;
|
||||
x = (SCREENWIDTH >> 1) - (((SmallFont->StringWidth(text_delay) * CleanXfac) + col5) >> 1);
|
||||
|
||||
screen->DrawText (SmallFont, color, x, y, text_color,
|
||||
DTA_CleanNoMove, true, TAG_DONE);
|
||||
|
@ -325,6 +331,9 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER
|
|||
screen->DrawText (SmallFont, color, x + col4, y, text_name,
|
||||
DTA_CleanNoMove, true, TAG_DONE);
|
||||
|
||||
screen->DrawText(SmallFont, color, x + col5, y, text_delay,
|
||||
DTA_CleanNoMove, true, TAG_DONE);
|
||||
|
||||
y += height + 6 * CleanYfac;
|
||||
bottom -= height;
|
||||
|
||||
|
@ -332,7 +341,7 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER
|
|||
{
|
||||
if (playeringame[sortedplayers[i] - players])
|
||||
{
|
||||
HU_DrawPlayer (sortedplayers[i], player==sortedplayers[i], x, col2, col3, col4, maxnamewidth, y, ypadding, lineheight);
|
||||
HU_DrawPlayer(sortedplayers[i], player == sortedplayers[i], x, col2, col3, col4, col5, maxnamewidth, y, ypadding, lineheight);
|
||||
y += lineheight + CleanYfac;
|
||||
}
|
||||
}
|
||||
|
@ -377,7 +386,7 @@ static void HU_DrawTimeRemaining (int y)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2, int col3, int col4, int maxnamewidth, int y, int ypadding, int height)
|
||||
static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2, int col3, int col4, int col5, int maxnamewidth, int y, int ypadding, int height)
|
||||
{
|
||||
int color;
|
||||
char str[80];
|
||||
|
@ -387,12 +396,13 @@ static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2,
|
|||
// The teamplay mode uses colors to show teams, so we need some
|
||||
// other way to do highlighting. And it may as well be used for
|
||||
// all modes for the sake of consistancy.
|
||||
screen->Dim(MAKERGB(200,245,255), 0.125f, col1 - 12*CleanXfac, y - 1, col4 + (maxnamewidth + 24)*CleanXfac, height + 2);
|
||||
screen->Dim(MAKERGB(200,245,255), 0.125f, col1 - 12*CleanXfac, y - 1, col5 + (maxnamewidth + 24)*CleanXfac, height + 2);
|
||||
}
|
||||
|
||||
col2 += col1;
|
||||
col3 += col1;
|
||||
col4 += col1;
|
||||
col5 += col1;
|
||||
|
||||
color = HU_GetRowColor(player, highlight);
|
||||
HU_DrawColorBar(col1, y, height, (int)(player - players));
|
||||
|
@ -412,6 +422,18 @@ static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2,
|
|||
screen->DrawText (SmallFont, color, col4, y + ypadding, player->userinfo.GetName(),
|
||||
DTA_CleanNoMove, true, TAG_DONE);
|
||||
|
||||
int avgdelay = 0;
|
||||
for (int i = 0; i < BACKUPTICS; i++)
|
||||
{
|
||||
avgdelay += netdelay[nodeforplayer[(int)(player - players)]][i];
|
||||
}
|
||||
avgdelay /= BACKUPTICS;
|
||||
|
||||
mysnprintf(str, countof(str), "%d", (avgdelay * ticdup) * (1000 / TICRATE));
|
||||
|
||||
screen->DrawText(SmallFont, color, col5, y + ypadding, str,
|
||||
DTA_CleanNoMove, true, TAG_DONE);
|
||||
|
||||
if (teamplay && Teams[player->userinfo.GetTeam()].GetLogo().IsNotEmpty ())
|
||||
{
|
||||
FTexture *pic = TexMan[Teams[player->userinfo.GetTeam()].GetLogo().GetChars ()];
|
||||
|
@ -473,3 +495,8 @@ int HU_GetRowColor(player_t *player, bool highlight)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
CCMD (togglescoreboard)
|
||||
{
|
||||
SB_ForceActive = !SB_ForceActive;
|
||||
}
|
||||
|
|
|
@ -52,6 +52,8 @@ void HU_GetPlayerWidths(int &maxnamewidth, int &maxscorewidth, int &maxiconheigh
|
|||
void HU_DrawColorBar(int x, int y, int height, int playernum);
|
||||
int HU_GetRowColor(player_t *player, bool hightlight);
|
||||
|
||||
extern bool SB_ForceActive;
|
||||
|
||||
// Sorting routines
|
||||
|
||||
int STACK_ARGS comparepoints(const void *arg1, const void *arg2);
|
||||
|
|
|
@ -110,6 +110,7 @@ const char *neterror (void);
|
|||
enum
|
||||
{
|
||||
PRE_CONNECT, // Sent from guest to host for initial connection
|
||||
PRE_KEEPALIVE,
|
||||
PRE_DISCONNECT, // Sent from guest that aborts the game
|
||||
PRE_ALLHERE, // Sent from host to guest when everybody has connected
|
||||
PRE_CONACK, // Sent from host to guest to acknowledge PRE_CONNECT receipt
|
||||
|
@ -134,8 +135,8 @@ struct PreGamePacket
|
|||
};
|
||||
struct
|
||||
{
|
||||
u_long address;
|
||||
u_short port;
|
||||
DWORD address;
|
||||
WORD port;
|
||||
BYTE player;
|
||||
BYTE pad;
|
||||
} machines[MAXNETNODES];
|
||||
|
@ -208,11 +209,11 @@ void PacketSend (void)
|
|||
{
|
||||
I_FatalError("Netbuffer overflow!");
|
||||
}
|
||||
assert(!(doomcom.data[0] & NCMD_COMPRESSED));
|
||||
|
||||
uLong size = TRANSMIT_SIZE - 1;
|
||||
if (doomcom.datalength >= 10)
|
||||
{
|
||||
assert(!(doomcom.data[0] & NCMD_COMPRESSED));
|
||||
TransmitBuffer[0] = doomcom.data[0] | NCMD_COMPRESSED;
|
||||
c = compress2(TransmitBuffer + 1, &size, doomcom.data + 1, doomcom.datalength - 1, 9);
|
||||
size += 1;
|
||||
|
@ -548,10 +549,15 @@ bool Host_CheckForConnects (void *userdata)
|
|||
SendConAck (doomcom.numnodes, numplayers);
|
||||
}
|
||||
break;
|
||||
|
||||
case PRE_KEEPALIVE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (doomcom.numnodes < numplayers)
|
||||
{
|
||||
// Send message to everyone as a keepalive
|
||||
SendConAck(doomcom.numnodes, numplayers);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -654,6 +660,12 @@ void HostGame (int i)
|
|||
numplayers = 2;
|
||||
}
|
||||
|
||||
if (numplayers > MAXNETNODES)
|
||||
{
|
||||
I_FatalError("You cannot host a game with %d players. The limit is currently %d.", numplayers, MAXNETNODES);
|
||||
return;
|
||||
}
|
||||
|
||||
if (numplayers == 1)
|
||||
{ // Special case: Only 1 player, so don't bother starting the network
|
||||
netgame = false;
|
||||
|
@ -822,6 +834,10 @@ bool Guest_WaitForOthers (void *userdata)
|
|||
}
|
||||
}
|
||||
|
||||
packet.Fake = PRE_FAKE;
|
||||
packet.Message = PRE_KEEPALIVE;
|
||||
PreSend(&packet, 2, &sendaddress[1]);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -938,11 +954,6 @@ bool I_InitNetwork (void)
|
|||
doomcom.ticdup = 1;
|
||||
}
|
||||
|
||||
if (Args->CheckParm ("-extratic"))
|
||||
doomcom.extratics = 1;
|
||||
else
|
||||
doomcom.extratics = 0;
|
||||
|
||||
v = Args->CheckValue ("-port");
|
||||
if (v)
|
||||
{
|
||||
|
|
|
@ -99,6 +99,23 @@ void cht_DoCheat (player_t *player, int cheat)
|
|||
msg = GStrings("TXT_BUDDHAOFF");
|
||||
break;
|
||||
|
||||
case CHT_GOD2:
|
||||
player->cheats ^= CF_GODMODE2;
|
||||
if (player->cheats & CF_GODMODE2)
|
||||
msg = GStrings("STSTR_DQD2ON");
|
||||
else
|
||||
msg = GStrings("STSTR_DQD2OFF");
|
||||
ST_SetNeedRefresh();
|
||||
break;
|
||||
|
||||
case CHT_BUDDHA2:
|
||||
player->cheats ^= CF_BUDDHA2;
|
||||
if (player->cheats & CF_BUDDHA2)
|
||||
msg = GStrings("TXT_BUDDHA2ON");
|
||||
else
|
||||
msg = GStrings("TXT_BUDDHA2OFF");
|
||||
break;
|
||||
|
||||
case CHT_NOCLIP:
|
||||
player->cheats ^= CF_NOCLIP;
|
||||
if (player->cheats & CF_NOCLIP)
|
||||
|
@ -323,7 +340,6 @@ void cht_DoCheat (player_t *player, int cheat)
|
|||
player->mo->Translation = TRANSLATION(TRANSLATION_Players, BYTE(player-players));
|
||||
}
|
||||
player->mo->DamageType = NAME_None;
|
||||
// player->mo->GiveDefaultInventory();
|
||||
if (player->ReadyWeapon != NULL)
|
||||
{
|
||||
P_SetPsprite(player, ps_weapon, player->ReadyWeapon->GetUpState());
|
||||
|
|
|
@ -137,6 +137,32 @@ int M_ReadFile (char const *name, BYTE **buffer)
|
|||
return length;
|
||||
}
|
||||
|
||||
//
|
||||
// M_ReadFile (same as above but use malloc instead of new to allocate the buffer.)
|
||||
//
|
||||
int M_ReadFileMalloc (char const *name, BYTE **buffer)
|
||||
{
|
||||
int handle, count, length;
|
||||
struct stat fileinfo;
|
||||
BYTE *buf;
|
||||
|
||||
handle = open (name, O_RDONLY | O_BINARY, 0666);
|
||||
if (handle == -1)
|
||||
I_Error ("Couldn't read file %s", name);
|
||||
if (fstat (handle,&fileinfo) == -1)
|
||||
I_Error ("Couldn't read file %s", name);
|
||||
length = fileinfo.st_size;
|
||||
buf = (BYTE*)M_Malloc(length);
|
||||
count = read (handle, buf, length);
|
||||
close (handle);
|
||||
|
||||
if (count < length)
|
||||
I_Error ("Couldn't read file %s", name);
|
||||
|
||||
*buffer = buf;
|
||||
return length;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// PROC M_FindResponseFile
|
||||
|
|
|
@ -33,6 +33,7 @@ extern FGameConfigFile *GameConfig;
|
|||
|
||||
bool M_WriteFile (char const *name, void *source, int length);
|
||||
int M_ReadFile (char const *name, BYTE **buffer);
|
||||
int M_ReadFileMalloc (char const *name, BYTE **buffer);
|
||||
void M_FindResponseFile (void);
|
||||
|
||||
// [RH] M_ScreenShot now accepts a filename parameter.
|
||||
|
|
|
@ -298,6 +298,9 @@ xx(Abs)
|
|||
xx(ACS_NamedExecuteWithResult)
|
||||
xx(CallACS)
|
||||
xx(Sqrt)
|
||||
xx(CheckClass)
|
||||
xx(IsPointerEqual)
|
||||
xx(Pick)
|
||||
|
||||
// Various actor names which are used internally
|
||||
xx(MapSpot)
|
||||
|
@ -418,6 +421,7 @@ xx(Passuse)
|
|||
xx(Repeatspecial)
|
||||
xx(Conversation)
|
||||
xx(Locknumber)
|
||||
xx(Midtex3dimpassible)
|
||||
|
||||
xx(Playercross)
|
||||
xx(Playeruse)
|
||||
|
@ -596,4 +600,4 @@ xx(NeverSwitchOnPickup)
|
|||
xx(MoveBob)
|
||||
xx(StillBob)
|
||||
xx(PlayerClass)
|
||||
xx(Wi_NoAutostartMap)
|
||||
xx(Wi_NoAutostartMap)
|
||||
|
|
|
@ -69,7 +69,13 @@ static const int PO_LINE_EXPLICIT = 5;
|
|||
angle_t FNodeBuilder::PointToAngle (fixed_t x, fixed_t y)
|
||||
{
|
||||
const double rad2bam = double(1<<30) / M_PI;
|
||||
#if defined __APPLE__ && !defined __llvm__
|
||||
// Work-around for vectorization issue in Apple's GCC 4.x
|
||||
// See https://gcc.gnu.org/wiki/Math_Optimization_Flags for details
|
||||
long double ang = atan2l (double(y), double(x));
|
||||
#else // !__APPLE__ || __llvm__
|
||||
double ang = atan2 (double(y), double(x));
|
||||
#endif // __APPLE__ && !__llvm__
|
||||
return angle_t(ang * rad2bam) << 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -323,7 +323,7 @@ int OPLio::OPLinit(uint numchips, bool stereo, bool initopl3)
|
|||
{
|
||||
assert(numchips >= 1 && numchips <= countof(chips));
|
||||
uint i;
|
||||
IsOPL3 = (opl_core == 1 || opl_core == 2);
|
||||
IsOPL3 = (opl_core == 1 || opl_core == 2 || opl_core == 3);
|
||||
|
||||
memset(chips, 0, sizeof(chips));
|
||||
if (IsOPL3)
|
||||
|
@ -332,7 +332,7 @@ int OPLio::OPLinit(uint numchips, bool stereo, bool initopl3)
|
|||
}
|
||||
for (i = 0; i < numchips; ++i)
|
||||
{
|
||||
OPLEmul *chip = IsOPL3 ? (opl_core == 1 ? DBOPLCreate(stereo) : JavaOPLCreate(stereo)) : YM3812Create(stereo);
|
||||
OPLEmul *chip = IsOPL3 ? (opl_core == 1 ? DBOPLCreate(stereo) : (opl_core == 2 ? JavaOPLCreate(stereo) : NukedOPL3Create(stereo))) : YM3812Create(stereo);
|
||||
if (chip == NULL)
|
||||
{
|
||||
break;
|
||||
|
|
979
src/oplsynth/nukedopl3.cpp
Normal file
979
src/oplsynth/nukedopl3.cpp
Normal file
|
@ -0,0 +1,979 @@
|
|||
/*
|
||||
* Copyright (C) 2013-2014 Nuke.YKT
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
Nuked Yamaha YMF262(aka OPL3) emulator.
|
||||
Thanks:
|
||||
MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh):
|
||||
Feedback and Rhythm part calculation information.
|
||||
forums.submarine.org.uk(carbon14, opl3):
|
||||
Tremolo and phase generator calculation information.
|
||||
OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
|
||||
OPL2 ROMs.
|
||||
*/
|
||||
|
||||
//version 1.5
|
||||
|
||||
/* Changelog:
|
||||
v1.1:
|
||||
Vibrato's sign fix
|
||||
v1.2:
|
||||
Operator key fix
|
||||
Corrected 4-operator mode
|
||||
Corrected rhythm mode
|
||||
Some small fixes
|
||||
v1.2.1:
|
||||
Small envelope generator fix
|
||||
Removed EX_Get function(not used)
|
||||
v1.3:
|
||||
Complete rewrite
|
||||
(Not released)
|
||||
v1.4:
|
||||
New envelope and waveform generator
|
||||
Some small fixes.
|
||||
(Not released)
|
||||
v1.4.1:
|
||||
Envelope generator rate calculation fix
|
||||
(Not released)
|
||||
v1.4.2:
|
||||
Version for ZDoom.
|
||||
v1.5:
|
||||
Optimizations
|
||||
*/
|
||||
|
||||
|
||||
/* Verified:
|
||||
Noise generator.
|
||||
Waveform generator.
|
||||
Envelope generator increase table.
|
||||
Tremolo.
|
||||
*/
|
||||
|
||||
/* TODO:
|
||||
Verify:
|
||||
kslrom[15] value(is it 128?).
|
||||
Sustain level = 15.
|
||||
Vibrato, Phase generator.
|
||||
Rhythm part.
|
||||
Envelope generator state switching(decay->sustain when egt = 1 and decay->release).
|
||||
Feedback.
|
||||
Register write.
|
||||
4-operator.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "nukedopl3.h"
|
||||
|
||||
//
|
||||
// Envelope generator
|
||||
//
|
||||
|
||||
typedef Bit16s(*envelope_sinfunc)(Bit16u phase, Bit16u envelope);
|
||||
typedef void(*envelope_genfunc)(opl_slot *slott);
|
||||
|
||||
Bit16s envelope_calcexp(Bit32u level) {
|
||||
if (level > 0x1fff) {
|
||||
level = 0x1fff;
|
||||
}
|
||||
return ((exprom[(level & 0xff) ^ 0xff] | 0x400) << 1) >> (level >> 8);
|
||||
}
|
||||
|
||||
Bit16s envelope_calcsin0(Bit16u phase, Bit16u envelope) {
|
||||
phase &= 0x3ff;
|
||||
Bit16u out = 0;
|
||||
Bit16u neg = 0;
|
||||
if (phase & 0x200 && (phase & 0x1ff)) {
|
||||
phase--;
|
||||
neg = ~0;
|
||||
}
|
||||
if (phase & 0x100) {
|
||||
out = logsinrom[(phase & 0xff) ^ 0xff];
|
||||
}
|
||||
else {
|
||||
out = logsinrom[phase & 0xff];
|
||||
}
|
||||
return envelope_calcexp(out + (envelope << 3)) ^ neg;
|
||||
}
|
||||
|
||||
Bit16s envelope_calcsin1(Bit16u phase, Bit16u envelope) {
|
||||
phase &= 0x3ff;
|
||||
Bit16u out = 0;
|
||||
if (phase & 0x200) {
|
||||
out = 0x1000;
|
||||
}
|
||||
else if (phase & 0x100) {
|
||||
out = logsinrom[(phase & 0xff) ^ 0xff];
|
||||
}
|
||||
else {
|
||||
out = logsinrom[phase & 0xff];
|
||||
}
|
||||
return envelope_calcexp(out + (envelope << 3));
|
||||
}
|
||||
|
||||
Bit16s envelope_calcsin2(Bit16u phase, Bit16u envelope) {
|
||||
phase &= 0x3ff;
|
||||
Bit16u out = 0;
|
||||
if (phase & 0x100) {
|
||||
out = logsinrom[(phase & 0xff) ^ 0xff];
|
||||
}
|
||||
else {
|
||||
out = logsinrom[phase & 0xff];
|
||||
}
|
||||
return envelope_calcexp(out + (envelope << 3));
|
||||
}
|
||||
|
||||
Bit16s envelope_calcsin3(Bit16u phase, Bit16u envelope) {
|
||||
phase &= 0x3ff;
|
||||
Bit16u out = 0;
|
||||
if (phase & 0x100) {
|
||||
out = 0x1000;
|
||||
}
|
||||
else {
|
||||
out = logsinrom[phase & 0xff];
|
||||
}
|
||||
return envelope_calcexp(out + (envelope << 3));
|
||||
}
|
||||
|
||||
Bit16s envelope_calcsin4(Bit16u phase, Bit16u envelope) {
|
||||
phase &= 0x3ff;
|
||||
Bit16u out = 0;
|
||||
Bit16u neg = 0;
|
||||
if ((phase & 0x300) == 0x100 && (phase & 0xff)) {
|
||||
phase--;
|
||||
neg = ~0;
|
||||
}
|
||||
if (phase & 0x200) {
|
||||
out = 0x1000;
|
||||
}
|
||||
else if (phase & 0x80) {
|
||||
out = logsinrom[((phase ^ 0xff) << 1) & 0xff];
|
||||
}
|
||||
else {
|
||||
out = logsinrom[(phase << 1) & 0xff];
|
||||
}
|
||||
return envelope_calcexp(out + (envelope << 3)) ^ neg;
|
||||
}
|
||||
|
||||
Bit16s envelope_calcsin5(Bit16u phase, Bit16u envelope) {
|
||||
phase &= 0x3ff;
|
||||
Bit16u out = 0;
|
||||
if (phase & 0x200) {
|
||||
out = 0x1000;
|
||||
}
|
||||
else if (phase & 0x80) {
|
||||
out = logsinrom[((phase ^ 0xff) << 1) & 0xff];
|
||||
}
|
||||
else {
|
||||
out = logsinrom[(phase << 1) & 0xff];
|
||||
}
|
||||
return envelope_calcexp(out + (envelope << 3));
|
||||
}
|
||||
|
||||
Bit16s envelope_calcsin6(Bit16u phase, Bit16u envelope) {
|
||||
phase &= 0x3ff;
|
||||
Bit16u neg = 0;
|
||||
if (phase & 0x200 && (phase & 0x1ff)) {
|
||||
phase--;
|
||||
neg = ~0;
|
||||
}
|
||||
return envelope_calcexp(envelope << 3) ^ neg;
|
||||
}
|
||||
|
||||
Bit16s envelope_calcsin7(Bit16u phase, Bit16u envelope) {
|
||||
phase &= 0x3ff;
|
||||
Bit16u out = 0;
|
||||
Bit16u neg = 0;
|
||||
if (phase & 0x200 && (phase & 0x1ff)) {
|
||||
phase--;
|
||||
neg = ~0;
|
||||
phase = (phase & 0x1ff) ^ 0x1ff;
|
||||
}
|
||||
out = phase << 3;
|
||||
return envelope_calcexp(out + (envelope << 3)) ^ neg;
|
||||
}
|
||||
|
||||
envelope_sinfunc envelope_sin[8] = {
|
||||
envelope_calcsin0,
|
||||
envelope_calcsin1,
|
||||
envelope_calcsin2,
|
||||
envelope_calcsin3,
|
||||
envelope_calcsin4,
|
||||
envelope_calcsin5,
|
||||
envelope_calcsin6,
|
||||
envelope_calcsin7
|
||||
};
|
||||
|
||||
void envelope_gen_off(opl_slot *slott);
|
||||
void envelope_gen_change(opl_slot *slott);
|
||||
void envelope_gen_attack(opl_slot *slott);
|
||||
void envelope_gen_decay(opl_slot *slott);
|
||||
void envelope_gen_sustain(opl_slot *slott);
|
||||
void envelope_gen_release(opl_slot *slott);
|
||||
|
||||
envelope_genfunc envelope_gen[6] = {
|
||||
envelope_gen_off,
|
||||
envelope_gen_attack,
|
||||
envelope_gen_decay,
|
||||
envelope_gen_sustain,
|
||||
envelope_gen_release,
|
||||
envelope_gen_change
|
||||
};
|
||||
|
||||
enum envelope_gen_num {
|
||||
envelope_gen_num_off = 0,
|
||||
envelope_gen_num_attack = 1,
|
||||
envelope_gen_num_decay = 2,
|
||||
envelope_gen_num_sustain = 3,
|
||||
envelope_gen_num_release = 4,
|
||||
envelope_gen_num_change = 5
|
||||
};
|
||||
|
||||
Bit8u envelope_calc_rate(opl_slot *slot, Bit8u reg_rate) {
|
||||
if (reg_rate == 0x00) {
|
||||
return 0x00;
|
||||
}
|
||||
Bit8u rate = (reg_rate << 2) + (slot->reg_ksr ? slot->channel->ksv : (slot->channel->ksv >> 2));
|
||||
if (rate > 0x3c) {
|
||||
rate = 0x3c;
|
||||
}
|
||||
return rate;
|
||||
}
|
||||
|
||||
void envelope_update_ksl(opl_slot *slot) {
|
||||
Bit16s ksl = (kslrom[slot->channel->f_num >> 6] << 1) - ((slot->channel->block ^ 0x07) << 5) - 0x20;
|
||||
if (ksl < 0) {
|
||||
ksl = 0;
|
||||
}
|
||||
slot->eg_ksl = (Bit8u)ksl;
|
||||
}
|
||||
|
||||
void envelope_update_rate(opl_slot *slot) {
|
||||
switch (slot->eg_gen) {
|
||||
case envelope_gen_num_off:
|
||||
slot->eg_rate = 0;
|
||||
break;
|
||||
case envelope_gen_num_attack:
|
||||
slot->eg_rate = envelope_calc_rate(slot, slot->reg_ar);
|
||||
break;
|
||||
case envelope_gen_num_decay:
|
||||
slot->eg_rate = envelope_calc_rate(slot, slot->reg_dr);
|
||||
break;
|
||||
case envelope_gen_num_sustain:
|
||||
case envelope_gen_num_release:
|
||||
slot->eg_rate = envelope_calc_rate(slot, slot->reg_rr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void envelope_gen_off(opl_slot *slot) {
|
||||
slot->eg_rout = 0x1ff;
|
||||
}
|
||||
|
||||
void envelope_gen_change(opl_slot *slot) {
|
||||
slot->eg_gen = slot->eg_gennext;
|
||||
envelope_update_rate(slot);
|
||||
}
|
||||
|
||||
void envelope_gen_attack(opl_slot *slot) {
|
||||
slot->eg_rout += ((~slot->eg_rout) *slot->eg_inc) >> 3;
|
||||
if (slot->eg_rout < 0x00) {
|
||||
slot->eg_rout = 0x00;
|
||||
}
|
||||
if (!slot->eg_rout) {
|
||||
slot->eg_gen = envelope_gen_num_change;
|
||||
slot->eg_gennext = envelope_gen_num_decay;
|
||||
}
|
||||
}
|
||||
|
||||
void envelope_gen_decay(opl_slot *slot) {
|
||||
slot->eg_rout += slot->eg_inc;
|
||||
if (slot->eg_rout >= slot->reg_sl << 4) {
|
||||
slot->eg_gen = envelope_gen_num_change;
|
||||
slot->eg_gennext = envelope_gen_num_sustain;
|
||||
}
|
||||
}
|
||||
|
||||
void envelope_gen_sustain(opl_slot *slot) {
|
||||
if (!slot->reg_type) {
|
||||
envelope_gen_release(slot);
|
||||
}
|
||||
}
|
||||
|
||||
void envelope_gen_release(opl_slot *slot) {
|
||||
slot->eg_rout += slot->eg_inc;
|
||||
if (slot->eg_rout >= 0x1ff) {
|
||||
slot->eg_gen = envelope_gen_num_change;
|
||||
slot->eg_gennext = envelope_gen_num_off;
|
||||
}
|
||||
}
|
||||
|
||||
void envelope_calc(opl_slot *slot) {
|
||||
Bit8u rate_h, rate_l;
|
||||
rate_h = slot->eg_rate >> 2;
|
||||
rate_l = slot->eg_rate & 3;
|
||||
Bit8u inc = 0;
|
||||
if (slot->eg_gen == envelope_gen_num_attack && rate_h == 0x0f) {
|
||||
inc = 8;
|
||||
}
|
||||
else if (eg_incsh[rate_h] > 0) {
|
||||
if ((slot->chip->timer & ((1 << eg_incsh[rate_h]) - 1)) == 0) {
|
||||
inc = eg_incstep[eg_incdesc[rate_h]][rate_l][((slot->chip->timer) >> eg_incsh[rate_h]) & 0x07];
|
||||
}
|
||||
}
|
||||
else {
|
||||
inc = eg_incstep[eg_incdesc[rate_h]][rate_l][slot->chip->timer & 0x07] << (-eg_incsh[rate_h]);
|
||||
}
|
||||
slot->eg_inc = inc;
|
||||
envelope_gen[slot->eg_gen](slot);
|
||||
slot->eg_out = slot->eg_rout + (slot->reg_tl << 2) + (slot->eg_ksl >> kslshift[slot->reg_ksl]) + *slot->trem;
|
||||
}
|
||||
|
||||
void eg_keyon(opl_slot *slot, Bit8u type) {
|
||||
if (!slot->key) {
|
||||
slot->eg_gen = envelope_gen_num_change;
|
||||
slot->eg_gennext = envelope_gen_num_attack;
|
||||
slot->pg_phase = 0x00;
|
||||
}
|
||||
slot->key |= type;
|
||||
}
|
||||
|
||||
void eg_keyoff(opl_slot *slot, Bit8u type) {
|
||||
if (slot->key) {
|
||||
slot->key &= (~type);
|
||||
if (!slot->key) {
|
||||
slot->eg_gen = envelope_gen_num_change;
|
||||
slot->eg_gennext = envelope_gen_num_release;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Phase Generator
|
||||
//
|
||||
|
||||
void pg_generate(opl_slot *slot) {
|
||||
Bit16u f_num = slot->channel->f_num;
|
||||
if (slot->reg_vib) {
|
||||
Bit8u f_num_high = f_num >> (7 + vib_table[(slot->chip->timer >> 10)&0x07] + (0x01 - slot->chip->dvb));
|
||||
f_num += f_num_high * vibsgn_table[(slot->chip->timer >> 10) & 0x07];
|
||||
}
|
||||
slot->pg_phase += (((f_num << slot->channel->block) >> 1) * mt[slot->reg_mult]) >> 1;
|
||||
}
|
||||
|
||||
//
|
||||
// Noise Generator
|
||||
//
|
||||
|
||||
void n_generate(opl_chip *chip) {
|
||||
if (chip->noise & 0x01) {
|
||||
chip->noise ^= 0x800302;
|
||||
}
|
||||
chip->noise >>= 1;
|
||||
}
|
||||
|
||||
//
|
||||
// Slot
|
||||
//
|
||||
|
||||
void slot_write20(opl_slot *slot,Bit8u data) {
|
||||
if ((data >> 7) & 0x01) {
|
||||
slot->trem = &slot->chip->tremval;
|
||||
}
|
||||
else {
|
||||
slot->trem = (Bit8u*)&slot->chip->zeromod;
|
||||
}
|
||||
slot->reg_vib = (data >> 6) & 0x01;
|
||||
slot->reg_type = (data >> 5) & 0x01;
|
||||
slot->reg_ksr = (data >> 4) & 0x01;
|
||||
slot->reg_mult = data & 0x0f;
|
||||
envelope_update_rate(slot);
|
||||
}
|
||||
|
||||
void slot_write40(opl_slot *slot, Bit8u data) {
|
||||
slot->reg_ksl = (data >> 6) & 0x03;
|
||||
slot->reg_tl = data & 0x3f;
|
||||
envelope_update_ksl(slot);
|
||||
}
|
||||
|
||||
void slot_write60(opl_slot *slot, Bit8u data) {
|
||||
slot->reg_ar = (data >> 4) & 0x0f;
|
||||
slot->reg_dr = data & 0x0f;
|
||||
envelope_update_rate(slot);
|
||||
}
|
||||
|
||||
void slot_write80(opl_slot *slot, Bit8u data) {
|
||||
slot->reg_sl = (data >> 4) & 0x0f;
|
||||
if (slot->reg_sl == 0x0f) {
|
||||
slot->reg_sl = 0x1f;
|
||||
}
|
||||
slot->reg_rr = data & 0x0f;
|
||||
envelope_update_rate(slot);
|
||||
}
|
||||
|
||||
void slot_writee0(opl_slot *slot, Bit8u data) {
|
||||
slot->reg_wf = data & 0x07;
|
||||
if (slot->chip->newm == 0x00) {
|
||||
slot->reg_wf &= 0x03;
|
||||
}
|
||||
}
|
||||
|
||||
void slot_generatephase(opl_slot *slot, Bit16u phase) {
|
||||
slot->out = envelope_sin[slot->reg_wf](phase, slot->eg_out);
|
||||
}
|
||||
|
||||
void slot_generate(opl_slot *slot) {
|
||||
slot->out = envelope_sin[slot->reg_wf]((slot->pg_phase >> 9) + (*slot->mod), slot->eg_out);
|
||||
}
|
||||
|
||||
void slot_generatezm(opl_slot *slot) {
|
||||
slot->out = envelope_sin[slot->reg_wf]((slot->pg_phase >> 9), slot->eg_out);
|
||||
}
|
||||
|
||||
void slot_calgfb(opl_slot *slot) {
|
||||
slot->prout[1] = slot->prout[0];
|
||||
slot->prout[0] = slot->out;
|
||||
if (slot->channel->fb != 0x00) {
|
||||
slot->fbmod = (slot->prout[0] + slot->prout[1]) >> (0x09 - slot->channel->fb);
|
||||
}
|
||||
else {
|
||||
slot->fbmod = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Channel
|
||||
//
|
||||
|
||||
void chan_setupalg(opl_channel *channel);
|
||||
|
||||
void chan_updaterhythm(opl_chip *chip, Bit8u data) {
|
||||
chip->rhy = data & 0x3f;
|
||||
if (chip->rhy & 0x20) {
|
||||
chip->channel[6].out[0] = &chip->slot[13].out;
|
||||
chip->channel[6].out[1] = &chip->slot[13].out;
|
||||
chip->channel[6].out[2] = &chip->zeromod;
|
||||
chip->channel[6].out[3] = &chip->zeromod;
|
||||
chip->channel[7].out[0] = &chip->slot[14].out;
|
||||
chip->channel[7].out[1] = &chip->slot[14].out;
|
||||
chip->channel[7].out[2] = &chip->slot[15].out;
|
||||
chip->channel[7].out[3] = &chip->slot[15].out;
|
||||
chip->channel[8].out[0] = &chip->slot[16].out;
|
||||
chip->channel[8].out[1] = &chip->slot[16].out;
|
||||
chip->channel[8].out[2] = &chip->slot[17].out;
|
||||
chip->channel[8].out[3] = &chip->slot[17].out;
|
||||
for (Bit8u chnum = 6; chnum < 9; chnum++) {
|
||||
chip->channel[chnum].chtype = ch_drum;
|
||||
}
|
||||
//hh
|
||||
if (chip->rhy & 0x01) {
|
||||
eg_keyon(&chip->slot[14], egk_drum);
|
||||
}
|
||||
else {
|
||||
eg_keyoff(&chip->slot[14], egk_drum);
|
||||
}
|
||||
//tc
|
||||
if (chip->rhy & 0x02) {
|
||||
eg_keyon(&chip->slot[17], egk_drum);
|
||||
}
|
||||
else {
|
||||
eg_keyoff(&chip->slot[17], egk_drum);
|
||||
}
|
||||
//tom
|
||||
if (chip->rhy & 0x04) {
|
||||
eg_keyon(&chip->slot[16], egk_drum);
|
||||
}
|
||||
else {
|
||||
eg_keyoff(&chip->slot[16], egk_drum);
|
||||
}
|
||||
//sd
|
||||
if (chip->rhy & 0x08) {
|
||||
eg_keyon(&chip->slot[15], egk_drum);
|
||||
}
|
||||
else {
|
||||
eg_keyoff(&chip->slot[15], egk_drum);
|
||||
}
|
||||
//bd
|
||||
if (chip->rhy & 0x10) {
|
||||
eg_keyon(&chip->slot[12], egk_drum);
|
||||
eg_keyon(&chip->slot[13], egk_drum);
|
||||
}
|
||||
else {
|
||||
eg_keyoff(&chip->slot[12], egk_drum);
|
||||
eg_keyoff(&chip->slot[13], egk_drum);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (Bit8u chnum = 6; chnum < 9; chnum++) {
|
||||
chip->channel[chnum].chtype = ch_2op;
|
||||
chan_setupalg(&chip->channel[chnum]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void chan_writea0(opl_channel *channel, Bit8u data) {
|
||||
if (channel->chip->newm && channel->chtype == ch_4op2) {
|
||||
return;
|
||||
}
|
||||
channel->f_num = (channel->f_num & 0x300) | data;
|
||||
channel->ksv = (channel->block << 1) | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01);
|
||||
envelope_update_ksl(channel->slots[0]);
|
||||
envelope_update_ksl(channel->slots[1]);
|
||||
envelope_update_rate(channel->slots[0]);
|
||||
envelope_update_rate(channel->slots[1]);
|
||||
if (channel->chip->newm && channel->chtype == ch_4op) {
|
||||
channel->pair->f_num = channel->f_num;
|
||||
channel->pair->ksv = channel->ksv;
|
||||
envelope_update_ksl(channel->pair->slots[0]);
|
||||
envelope_update_ksl(channel->pair->slots[1]);
|
||||
envelope_update_rate(channel->pair->slots[0]);
|
||||
envelope_update_rate(channel->pair->slots[1]);
|
||||
}
|
||||
}
|
||||
|
||||
void chan_writeb0(opl_channel *channel, Bit8u data) {
|
||||
if (channel->chip->newm && channel->chtype == ch_4op2) {
|
||||
return;
|
||||
}
|
||||
channel->f_num = (channel->f_num & 0xff) | ((data & 0x03) << 8);
|
||||
channel->block = (data >> 2) & 0x07;
|
||||
channel->ksv = (channel->block << 1) | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01);
|
||||
envelope_update_ksl(channel->slots[0]);
|
||||
envelope_update_ksl(channel->slots[1]);
|
||||
envelope_update_rate(channel->slots[0]);
|
||||
envelope_update_rate(channel->slots[1]);
|
||||
if (channel->chip->newm && channel->chtype == ch_4op) {
|
||||
channel->pair->f_num = channel->f_num;
|
||||
channel->pair->block = channel->block;
|
||||
channel->pair->ksv = channel->ksv;
|
||||
envelope_update_ksl(channel->pair->slots[0]);
|
||||
envelope_update_ksl(channel->pair->slots[1]);
|
||||
envelope_update_rate(channel->pair->slots[0]);
|
||||
envelope_update_rate(channel->pair->slots[1]);
|
||||
}
|
||||
}
|
||||
|
||||
void chan_setupalg(opl_channel *channel) {
|
||||
if (channel->chtype == ch_drum) {
|
||||
return;
|
||||
}
|
||||
if (channel->alg & 0x08) {
|
||||
return;
|
||||
}
|
||||
if (channel->alg & 0x04) {
|
||||
channel->pair->out[0] = &channel->chip->zeromod;
|
||||
channel->pair->out[1] = &channel->chip->zeromod;
|
||||
channel->pair->out[2] = &channel->chip->zeromod;
|
||||
channel->pair->out[3] = &channel->chip->zeromod;
|
||||
switch (channel->alg & 0x03) {
|
||||
case 0x00:
|
||||
channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod;
|
||||
channel->pair->slots[1]->mod = &channel->pair->slots[0]->out;
|
||||
channel->slots[0]->mod = &channel->pair->slots[1]->out;
|
||||
channel->slots[1]->mod = &channel->slots[0]->out;
|
||||
channel->out[0] = &channel->slots[1]->out;
|
||||
channel->out[1] = &channel->chip->zeromod;
|
||||
channel->out[2] = &channel->chip->zeromod;
|
||||
channel->out[3] = &channel->chip->zeromod;
|
||||
break;
|
||||
case 0x01:
|
||||
channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod;
|
||||
channel->pair->slots[1]->mod = &channel->pair->slots[0]->out;
|
||||
channel->slots[0]->mod = &channel->chip->zeromod;
|
||||
channel->slots[1]->mod = &channel->slots[0]->out;
|
||||
channel->out[0] = &channel->pair->slots[1]->out;
|
||||
channel->out[1] = &channel->slots[1]->out;
|
||||
channel->out[2] = &channel->chip->zeromod;
|
||||
channel->out[3] = &channel->chip->zeromod;
|
||||
break;
|
||||
case 0x02:
|
||||
channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod;
|
||||
channel->pair->slots[1]->mod = &channel->chip->zeromod;
|
||||
channel->slots[0]->mod = &channel->pair->slots[1]->out;
|
||||
channel->slots[1]->mod = &channel->slots[0]->out;
|
||||
channel->out[0] = &channel->pair->slots[0]->out;
|
||||
channel->out[1] = &channel->slots[1]->out;
|
||||
channel->out[2] = &channel->chip->zeromod;
|
||||
channel->out[3] = &channel->chip->zeromod;
|
||||
break;
|
||||
case 0x03:
|
||||
channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod;
|
||||
channel->pair->slots[1]->mod = &channel->chip->zeromod;
|
||||
channel->slots[0]->mod = &channel->pair->slots[1]->out;
|
||||
channel->slots[1]->mod = &channel->chip->zeromod;
|
||||
channel->out[0] = &channel->pair->slots[0]->out;
|
||||
channel->out[1] = &channel->slots[0]->out;
|
||||
channel->out[2] = &channel->slots[1]->out;
|
||||
channel->out[3] = &channel->chip->zeromod;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (channel->alg & 0x01) {
|
||||
case 0x00:
|
||||
channel->slots[0]->mod = &channel->slots[0]->fbmod;
|
||||
channel->slots[1]->mod = &channel->slots[0]->out;
|
||||
channel->out[0] = &channel->slots[1]->out;
|
||||
channel->out[1] = &channel->chip->zeromod;
|
||||
channel->out[2] = &channel->chip->zeromod;
|
||||
channel->out[3] = &channel->chip->zeromod;
|
||||
break;
|
||||
case 0x01:
|
||||
channel->slots[0]->mod = &channel->slots[0]->fbmod;
|
||||
channel->slots[1]->mod = &channel->chip->zeromod;
|
||||
channel->out[0] = &channel->slots[0]->out;
|
||||
channel->out[1] = &channel->slots[1]->out;
|
||||
channel->out[2] = &channel->chip->zeromod;
|
||||
channel->out[3] = &channel->chip->zeromod;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void chan_writec0(opl_channel *channel, Bit8u data) {
|
||||
channel->fb = (data & 0x0e) >> 1;
|
||||
channel->con = data & 0x01;
|
||||
channel->alg = channel->con;
|
||||
if (channel->chip->newm) {
|
||||
if (channel->chtype == ch_4op) {
|
||||
channel->pair->alg = 0x04 | (channel->con << 1) | (channel->pair->con);
|
||||
channel->alg = 0x08;
|
||||
chan_setupalg(channel->pair);
|
||||
}
|
||||
else if (channel->chtype == ch_4op2) {
|
||||
channel->alg = 0x04 | (channel->pair->con << 1) | (channel->con);
|
||||
channel->pair->alg = 0x08;
|
||||
chan_setupalg(channel);
|
||||
}
|
||||
else {
|
||||
chan_setupalg(channel);
|
||||
}
|
||||
}
|
||||
else {
|
||||
chan_setupalg(channel);
|
||||
}
|
||||
if (channel->chip->newm) {
|
||||
channel->cha = ((data >> 4) & 0x01) ? ~0 : 0;
|
||||
channel->chb = ((data >> 5) & 0x01) ? ~0 : 0;
|
||||
}
|
||||
else {
|
||||
channel->cha = channel->chb = ~0;
|
||||
}
|
||||
}
|
||||
|
||||
void chan_generaterhythm(opl_chip *chip) {
|
||||
if (chip->rhy & 0x20) {
|
||||
opl_channel *channel6 = &chip->channel[6];
|
||||
opl_channel *channel7 = &chip->channel[7];
|
||||
opl_channel *channel8 = &chip->channel[8];
|
||||
slot_generate(channel6->slots[0]);
|
||||
slot_generate(channel6->slots[1]);
|
||||
Bit16u phase14 = channel7->slots[0]->pg_phase & 0x3ff;
|
||||
Bit16u phase17 = channel8->slots[1]->pg_phase & 0x3ff;
|
||||
Bit16u phase = 0x00;
|
||||
//hh tc phase bit
|
||||
Bit16u phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04) | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00;
|
||||
//hh
|
||||
phase = (phasebit << 9) | (0x34 << ((phasebit ^ (chip->noise & 0x01) << 1)));
|
||||
slot_generatephase(channel7->slots[0], phase);
|
||||
//sd
|
||||
phase = (0x100 << ((phase14 >> 8) & 0x01)) ^ ((chip->noise & 0x01) << 8);
|
||||
slot_generatephase(channel7->slots[1], phase);
|
||||
//tt
|
||||
slot_generatezm(channel8->slots[0]);
|
||||
//tc
|
||||
phase = 0x100 | (phasebit << 9);
|
||||
slot_generatephase(channel8->slots[1], phase);
|
||||
}
|
||||
}
|
||||
|
||||
void chan_generate(opl_channel *channel) {
|
||||
if (channel->chtype == ch_drum) {
|
||||
return;
|
||||
}
|
||||
if (channel->alg & 0x08) {
|
||||
return;
|
||||
}
|
||||
if (channel->alg & 0x04) {
|
||||
slot_generate(channel->pair->slots[0]);
|
||||
slot_generate(channel->pair->slots[1]);
|
||||
slot_generate(channel->slots[0]);
|
||||
slot_generate(channel->slots[1]);
|
||||
}
|
||||
else {
|
||||
slot_generate(channel->slots[0]);
|
||||
slot_generate(channel->slots[1]);
|
||||
}
|
||||
}
|
||||
|
||||
void chan_enable(opl_channel *channel) {
|
||||
if (channel->chip->newm) {
|
||||
if (channel->chtype == ch_4op) {
|
||||
eg_keyon(channel->slots[0], egk_norm);
|
||||
eg_keyon(channel->slots[1], egk_norm);
|
||||
eg_keyon(channel->pair->slots[0], egk_norm);
|
||||
eg_keyon(channel->pair->slots[1], egk_norm);
|
||||
}
|
||||
else if (channel->chtype == ch_2op || channel->chtype == ch_drum) {
|
||||
eg_keyon(channel->slots[0], egk_norm);
|
||||
eg_keyon(channel->slots[1], egk_norm);
|
||||
}
|
||||
}
|
||||
else {
|
||||
eg_keyon(channel->slots[0], egk_norm);
|
||||
eg_keyon(channel->slots[1], egk_norm);
|
||||
}
|
||||
}
|
||||
|
||||
void chan_disable(opl_channel *channel) {
|
||||
if (channel->chip->newm) {
|
||||
if (channel->chtype == ch_4op) {
|
||||
eg_keyoff(channel->slots[0], egk_norm);
|
||||
eg_keyoff(channel->slots[1], egk_norm);
|
||||
eg_keyoff(channel->pair->slots[0], egk_norm);
|
||||
eg_keyoff(channel->pair->slots[1], egk_norm);
|
||||
}
|
||||
else if (channel->chtype == ch_2op || channel->chtype == ch_drum) {
|
||||
eg_keyoff(channel->slots[0], egk_norm);
|
||||
eg_keyoff(channel->slots[1], egk_norm);
|
||||
}
|
||||
}
|
||||
else {
|
||||
eg_keyoff(channel->slots[0], egk_norm);
|
||||
eg_keyoff(channel->slots[1], egk_norm);
|
||||
}
|
||||
}
|
||||
|
||||
void chan_set4op(opl_chip *chip, Bit8u data) {
|
||||
for (Bit8u bit = 0; bit < 6; bit++) {
|
||||
Bit8u chnum = bit;
|
||||
if (bit >= 3) {
|
||||
chnum += 9 - 3;
|
||||
}
|
||||
if ((data >> bit) & 0x01) {
|
||||
chip->channel[chnum].chtype = ch_4op;
|
||||
chip->channel[chnum + 3].chtype = ch_4op2;
|
||||
}
|
||||
else {
|
||||
chip->channel[chnum].chtype = ch_2op;
|
||||
chip->channel[chnum + 3].chtype = ch_2op;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Bit16s limshort(Bit32s a) {
|
||||
if (a > 32767) {
|
||||
a = 32767;
|
||||
}
|
||||
else if (a < -32768) {
|
||||
a = -32768;
|
||||
}
|
||||
return (Bit16s)a;
|
||||
}
|
||||
|
||||
void NukedOPL3::Reset() {
|
||||
memset(&opl3, 0, sizeof(opl_chip));
|
||||
for (Bit8u slotnum = 0; slotnum < 36; slotnum++) {
|
||||
opl3.slot[slotnum].channel = &opl3.channel[slotnum / 2];
|
||||
opl3.slot[slotnum].chip = &opl3;
|
||||
opl3.slot[slotnum].mod = &opl3.zeromod;
|
||||
opl3.slot[slotnum].eg_rout = 0x1ff;
|
||||
opl3.slot[slotnum].eg_out = 0x1ff;
|
||||
opl3.slot[slotnum].eg_gen = envelope_gen_num_off;
|
||||
opl3.slot[slotnum].eg_gennext = envelope_gen_num_off;
|
||||
opl3.slot[slotnum].trem = (Bit8u*)&opl3.zeromod;
|
||||
}
|
||||
for (Bit8u channum = 0; channum < 18; channum++) {
|
||||
opl3.channel[channum].slots[0] = &opl3.slot[2 * channum];
|
||||
opl3.channel[channum].slots[1] = &opl3.slot[2 * channum + 1];
|
||||
if ((channum % 9) < 3) {
|
||||
opl3.channel[channum].pair = &opl3.channel[channum + 3];
|
||||
}
|
||||
else if ((channum % 9) < 6) {
|
||||
opl3.channel[channum].pair = &opl3.channel[channum - 3];
|
||||
}
|
||||
opl3.channel[channum].chip = &opl3;
|
||||
opl3.channel[channum].out[0] = &opl3.zeromod;
|
||||
opl3.channel[channum].out[1] = &opl3.zeromod;
|
||||
opl3.channel[channum].out[2] = &opl3.zeromod;
|
||||
opl3.channel[channum].out[3] = &opl3.zeromod;
|
||||
opl3.channel[channum].chtype = ch_2op;
|
||||
opl3.channel[channum].cha = ~0;
|
||||
opl3.channel[channum].chb = ~0;
|
||||
opl3.channel[channum].fcha = 1.0;
|
||||
opl3.channel[channum].fchb = 1.0;
|
||||
chan_setupalg(&opl3.channel[channum]);
|
||||
}
|
||||
opl3.noise = 0x306600;
|
||||
}
|
||||
|
||||
void NukedOPL3::WriteReg(int reg, int v) {
|
||||
v &= 0xff;
|
||||
reg &= 0x1ff;
|
||||
Bit8u high = (reg >> 8) & 0x01;
|
||||
Bit8u regm = reg & 0xff;
|
||||
switch (regm & 0xf0) {
|
||||
case 0x00:
|
||||
if (high) {
|
||||
switch (regm & 0x0f) {
|
||||
case 0x04:
|
||||
chan_set4op(&opl3, v);
|
||||
break;
|
||||
case 0x05:
|
||||
opl3.newm = v & 0x01;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (regm & 0x0f) {
|
||||
case 0x08:
|
||||
opl3.nts = (v >> 6) & 0x01;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x20:
|
||||
case 0x30:
|
||||
if (ad_slot[regm & 0x1f] >= 0) {
|
||||
slot_write20(&opl3.slot[18 * high + ad_slot[regm & 0x1f]], v);
|
||||
}
|
||||
break;
|
||||
case 0x40:
|
||||
case 0x50:
|
||||
if (ad_slot[regm & 0x1f] >= 0) {
|
||||
slot_write40(&opl3.slot[18 * high + ad_slot[regm & 0x1f]], v);
|
||||
}
|
||||
break;
|
||||
case 0x60:
|
||||
case 0x70:
|
||||
if (ad_slot[regm & 0x1f] >= 0) {
|
||||
slot_write60(&opl3.slot[18 * high + ad_slot[regm & 0x1f]], v);
|
||||
}
|
||||
break;
|
||||
case 0x80:
|
||||
case 0x90:
|
||||
if (ad_slot[regm & 0x1f] >= 0) {
|
||||
slot_write80(&opl3.slot[18 * high + ad_slot[regm & 0x1f]], v);;
|
||||
}
|
||||
break;
|
||||
case 0xe0:
|
||||
case 0xf0:
|
||||
if (ad_slot[regm & 0x1f] >= 0) {
|
||||
slot_writee0(&opl3.slot[18 * high + ad_slot[regm & 0x1f]], v);
|
||||
}
|
||||
break;
|
||||
case 0xa0:
|
||||
if ((regm & 0x0f) < 9) {
|
||||
chan_writea0(&opl3.channel[9 * high + (regm & 0x0f)], v);
|
||||
}
|
||||
break;
|
||||
case 0xb0:
|
||||
if (regm == 0xbd && !high) {
|
||||
opl3.dam = v >> 7;
|
||||
opl3.dvb = (v >> 6) & 0x01;
|
||||
chan_updaterhythm(&opl3, v);
|
||||
}
|
||||
else if ((regm & 0x0f) < 9) {
|
||||
chan_writeb0(&opl3.channel[9 * high + (regm & 0x0f)], v);
|
||||
if (v & 0x20) {
|
||||
chan_enable(&opl3.channel[9 * high + (regm & 0x0f)]);
|
||||
}
|
||||
else {
|
||||
chan_disable(&opl3.channel[9 * high + (regm & 0x0f)]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xc0:
|
||||
if ((regm & 0x0f) < 9) {
|
||||
chan_writec0(&opl3.channel[9 * high + (regm & 0x0f)], v);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void NukedOPL3::Update(float* sndptr, int numsamples) {
|
||||
Bit32s outa, outb;
|
||||
for (Bit32u i = 0; i < (Bit32u)numsamples; i++) {
|
||||
outa = 0;
|
||||
outb = 0;
|
||||
for (Bit8u ii = 0; ii < 36; ii++) {
|
||||
slot_calgfb(&opl3.slot[ii]);
|
||||
}
|
||||
chan_generaterhythm(&opl3);
|
||||
for (Bit8u ii = 0; ii < 18; ii++) {
|
||||
chan_generate(&opl3.channel[ii]);
|
||||
Bit16s accm = 0;
|
||||
for (Bit8u jj = 0; jj < 4; jj++) {
|
||||
accm += *opl3.channel[ii].out[jj];
|
||||
}
|
||||
if (FullPan) {
|
||||
outa += (Bit16s)(accm * opl3.channel[ii].fcha);
|
||||
outb += (Bit16s)(accm * opl3.channel[ii].fchb);
|
||||
}
|
||||
else {
|
||||
outa += (Bit16s)(accm & opl3.channel[ii].cha);
|
||||
outb += (Bit16s)(accm & opl3.channel[ii].chb);
|
||||
}
|
||||
}
|
||||
for (Bit8u ii = 0; ii < 36; ii++) {
|
||||
envelope_calc(&opl3.slot[ii]);
|
||||
pg_generate(&opl3.slot[ii]);
|
||||
}
|
||||
n_generate(&opl3);
|
||||
opl3.timer++;
|
||||
if (!(opl3.timer & 0x3f)) {
|
||||
if (!opl3.tremdir) {
|
||||
if (opl3.tremtval == 105) {
|
||||
opl3.tremtval--;
|
||||
opl3.tremdir = 1;
|
||||
}
|
||||
else {
|
||||
opl3.tremtval++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (opl3.tremtval == 0) {
|
||||
opl3.tremtval++;
|
||||
opl3.tremdir = 0;
|
||||
}
|
||||
else {
|
||||
opl3.tremtval--;
|
||||
}
|
||||
}
|
||||
opl3.tremval = (opl3.tremtval >> 2) >> ((1 - opl3.dam) << 1);
|
||||
}
|
||||
*sndptr++ += (float)(outa / 10240.0);
|
||||
*sndptr++ += (float)(outb / 10240.0);
|
||||
}
|
||||
}
|
||||
|
||||
void NukedOPL3::SetPanning(int c, float left, float right) {
|
||||
if (FullPan) {
|
||||
opl3.channel[c].fcha = left;
|
||||
opl3.channel[c].fchb = right;
|
||||
}
|
||||
}
|
||||
|
||||
NukedOPL3::NukedOPL3(bool stereo) {
|
||||
FullPan = stereo;
|
||||
Reset();
|
||||
}
|
||||
|
||||
OPLEmul *NukedOPL3Create(bool stereo) {
|
||||
return new NukedOPL3(stereo);
|
||||
}
|
234
src/oplsynth/nukedopl3.h
Normal file
234
src/oplsynth/nukedopl3.h
Normal file
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* Copyright (C) 2013-2014 Nuke.YKT
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
Nuked Yamaha YMF262(aka OPL3) emulator.
|
||||
Thanks:
|
||||
MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh):
|
||||
Feedback and Rhythm part calculation information.
|
||||
forums.submarine.org.uk(carbon14, opl3):
|
||||
Tremolo and phase generator calculation information.
|
||||
OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
|
||||
OPL2 ROMs.
|
||||
*/
|
||||
|
||||
//version 1.5
|
||||
|
||||
#include "opl.h"
|
||||
#include "muslib.h"
|
||||
|
||||
typedef uintptr_t Bitu;
|
||||
typedef intptr_t Bits;
|
||||
typedef DWORD Bit32u;
|
||||
typedef SDWORD Bit32s;
|
||||
typedef WORD Bit16u;
|
||||
typedef SWORD Bit16s;
|
||||
typedef BYTE Bit8u;
|
||||
typedef SBYTE Bit8s;
|
||||
|
||||
// Channel types
|
||||
|
||||
enum {
|
||||
ch_2op = 0,
|
||||
ch_4op = 1,
|
||||
ch_4op2 = 2,
|
||||
ch_drum = 3
|
||||
};
|
||||
|
||||
// Envelope key types
|
||||
|
||||
enum {
|
||||
egk_norm = 0x01,
|
||||
egk_drum = 0x02
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// logsin table
|
||||
//
|
||||
|
||||
static const Bit16u logsinrom[256] = {
|
||||
0x859, 0x6c3, 0x607, 0x58b, 0x52e, 0x4e4, 0x4a6, 0x471, 0x443, 0x41a, 0x3f5, 0x3d3, 0x3b5, 0x398, 0x37e, 0x365,
|
||||
0x34e, 0x339, 0x324, 0x311, 0x2ff, 0x2ed, 0x2dc, 0x2cd, 0x2bd, 0x2af, 0x2a0, 0x293, 0x286, 0x279, 0x26d, 0x261,
|
||||
0x256, 0x24b, 0x240, 0x236, 0x22c, 0x222, 0x218, 0x20f, 0x206, 0x1fd, 0x1f5, 0x1ec, 0x1e4, 0x1dc, 0x1d4, 0x1cd,
|
||||
0x1c5, 0x1be, 0x1b7, 0x1b0, 0x1a9, 0x1a2, 0x19b, 0x195, 0x18f, 0x188, 0x182, 0x17c, 0x177, 0x171, 0x16b, 0x166,
|
||||
0x160, 0x15b, 0x155, 0x150, 0x14b, 0x146, 0x141, 0x13c, 0x137, 0x133, 0x12e, 0x129, 0x125, 0x121, 0x11c, 0x118,
|
||||
0x114, 0x10f, 0x10b, 0x107, 0x103, 0x0ff, 0x0fb, 0x0f8, 0x0f4, 0x0f0, 0x0ec, 0x0e9, 0x0e5, 0x0e2, 0x0de, 0x0db,
|
||||
0x0d7, 0x0d4, 0x0d1, 0x0cd, 0x0ca, 0x0c7, 0x0c4, 0x0c1, 0x0be, 0x0bb, 0x0b8, 0x0b5, 0x0b2, 0x0af, 0x0ac, 0x0a9,
|
||||
0x0a7, 0x0a4, 0x0a1, 0x09f, 0x09c, 0x099, 0x097, 0x094, 0x092, 0x08f, 0x08d, 0x08a, 0x088, 0x086, 0x083, 0x081,
|
||||
0x07f, 0x07d, 0x07a, 0x078, 0x076, 0x074, 0x072, 0x070, 0x06e, 0x06c, 0x06a, 0x068, 0x066, 0x064, 0x062, 0x060,
|
||||
0x05e, 0x05c, 0x05b, 0x059, 0x057, 0x055, 0x053, 0x052, 0x050, 0x04e, 0x04d, 0x04b, 0x04a, 0x048, 0x046, 0x045,
|
||||
0x043, 0x042, 0x040, 0x03f, 0x03e, 0x03c, 0x03b, 0x039, 0x038, 0x037, 0x035, 0x034, 0x033, 0x031, 0x030, 0x02f,
|
||||
0x02e, 0x02d, 0x02b, 0x02a, 0x029, 0x028, 0x027, 0x026, 0x025, 0x024, 0x023, 0x022, 0x021, 0x020, 0x01f, 0x01e,
|
||||
0x01d, 0x01c, 0x01b, 0x01a, 0x019, 0x018, 0x017, 0x017, 0x016, 0x015, 0x014, 0x014, 0x013, 0x012, 0x011, 0x011,
|
||||
0x010, 0x00f, 0x00f, 0x00e, 0x00d, 0x00d, 0x00c, 0x00c, 0x00b, 0x00a, 0x00a, 0x009, 0x009, 0x008, 0x008, 0x007,
|
||||
0x007, 0x007, 0x006, 0x006, 0x005, 0x005, 0x005, 0x004, 0x004, 0x004, 0x003, 0x003, 0x003, 0x002, 0x002, 0x002,
|
||||
0x002, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000
|
||||
};
|
||||
|
||||
//
|
||||
// exp table
|
||||
//
|
||||
|
||||
static const Bit16u exprom[256] = {
|
||||
0x000, 0x003, 0x006, 0x008, 0x00b, 0x00e, 0x011, 0x014, 0x016, 0x019, 0x01c, 0x01f, 0x022, 0x025, 0x028, 0x02a,
|
||||
0x02d, 0x030, 0x033, 0x036, 0x039, 0x03c, 0x03f, 0x042, 0x045, 0x048, 0x04b, 0x04e, 0x051, 0x054, 0x057, 0x05a,
|
||||
0x05d, 0x060, 0x063, 0x066, 0x069, 0x06c, 0x06f, 0x072, 0x075, 0x078, 0x07b, 0x07e, 0x082, 0x085, 0x088, 0x08b,
|
||||
0x08e, 0x091, 0x094, 0x098, 0x09b, 0x09e, 0x0a1, 0x0a4, 0x0a8, 0x0ab, 0x0ae, 0x0b1, 0x0b5, 0x0b8, 0x0bb, 0x0be,
|
||||
0x0c2, 0x0c5, 0x0c8, 0x0cc, 0x0cf, 0x0d2, 0x0d6, 0x0d9, 0x0dc, 0x0e0, 0x0e3, 0x0e7, 0x0ea, 0x0ed, 0x0f1, 0x0f4,
|
||||
0x0f8, 0x0fb, 0x0ff, 0x102, 0x106, 0x109, 0x10c, 0x110, 0x114, 0x117, 0x11b, 0x11e, 0x122, 0x125, 0x129, 0x12c,
|
||||
0x130, 0x134, 0x137, 0x13b, 0x13e, 0x142, 0x146, 0x149, 0x14d, 0x151, 0x154, 0x158, 0x15c, 0x160, 0x163, 0x167,
|
||||
0x16b, 0x16f, 0x172, 0x176, 0x17a, 0x17e, 0x181, 0x185, 0x189, 0x18d, 0x191, 0x195, 0x199, 0x19c, 0x1a0, 0x1a4,
|
||||
0x1a8, 0x1ac, 0x1b0, 0x1b4, 0x1b8, 0x1bc, 0x1c0, 0x1c4, 0x1c8, 0x1cc, 0x1d0, 0x1d4, 0x1d8, 0x1dc, 0x1e0, 0x1e4,
|
||||
0x1e8, 0x1ec, 0x1f0, 0x1f5, 0x1f9, 0x1fd, 0x201, 0x205, 0x209, 0x20e, 0x212, 0x216, 0x21a, 0x21e, 0x223, 0x227,
|
||||
0x22b, 0x230, 0x234, 0x238, 0x23c, 0x241, 0x245, 0x249, 0x24e, 0x252, 0x257, 0x25b, 0x25f, 0x264, 0x268, 0x26d,
|
||||
0x271, 0x276, 0x27a, 0x27f, 0x283, 0x288, 0x28c, 0x291, 0x295, 0x29a, 0x29e, 0x2a3, 0x2a8, 0x2ac, 0x2b1, 0x2b5,
|
||||
0x2ba, 0x2bf, 0x2c4, 0x2c8, 0x2cd, 0x2d2, 0x2d6, 0x2db, 0x2e0, 0x2e5, 0x2e9, 0x2ee, 0x2f3, 0x2f8, 0x2fd, 0x302,
|
||||
0x306, 0x30b, 0x310, 0x315, 0x31a, 0x31f, 0x324, 0x329, 0x32e, 0x333, 0x338, 0x33d, 0x342, 0x347, 0x34c, 0x351,
|
||||
0x356, 0x35b, 0x360, 0x365, 0x36a, 0x370, 0x375, 0x37a, 0x37f, 0x384, 0x38a, 0x38f, 0x394, 0x399, 0x39f, 0x3a4,
|
||||
0x3a9, 0x3ae, 0x3b4, 0x3b9, 0x3bf, 0x3c4, 0x3c9, 0x3cf, 0x3d4, 0x3da, 0x3df, 0x3e4, 0x3ea, 0x3ef, 0x3f5, 0x3fa
|
||||
};
|
||||
|
||||
//
|
||||
// freq mult table multiplied by 2
|
||||
//
|
||||
// 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 12, 12, 15, 15
|
||||
//
|
||||
|
||||
static const Bit8u mt[16] = { 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30 };
|
||||
|
||||
//
|
||||
// ksl table
|
||||
//
|
||||
|
||||
static const Bit8u kslrom[16] = { 0, 64, 80, 90, 96, 102, 106, 110, 112, 116, 118, 120, 122, 124, 126, 127 };
|
||||
|
||||
static const Bit8u kslshift[4] = { 8, 1, 2, 0 };
|
||||
|
||||
//
|
||||
// LFO vibrato
|
||||
//
|
||||
|
||||
static const Bit8u vib_table[8] = { 3, 1, 0, 1, 3, 1, 0, 1 };
|
||||
static const Bit8s vibsgn_table[8] = { 1, 1, 1, 1, -1, -1, -1, -1 };
|
||||
|
||||
//
|
||||
// envelope generator constants
|
||||
//
|
||||
|
||||
static const Bit8u eg_incstep[3][4][8] = {
|
||||
{ { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } },
|
||||
{ { 0, 1, 0, 1, 0, 1, 0, 1 }, { 1, 1, 0, 1, 0, 1, 0, 1 }, { 1, 1, 0, 1, 1, 1, 0, 1 }, { 1, 1, 1, 1, 1, 1, 0, 1 } },
|
||||
{ { 1, 1, 1, 1, 1, 1, 1, 1 }, { 2, 2, 1, 1, 1, 1, 1, 1 }, { 2, 2, 1, 1, 2, 2, 1, 1 }, { 2, 2, 2, 2, 2, 2, 1, 1 } }
|
||||
};
|
||||
|
||||
static const Bit8u eg_incdesc[16] = {
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2
|
||||
};
|
||||
|
||||
static const Bit8s eg_incsh[16] = {
|
||||
0, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, -1, -2
|
||||
};
|
||||
|
||||
//
|
||||
// address decoding
|
||||
//
|
||||
|
||||
static const Bit8s ad_slot[0x20] = { 0, 2, 4, 1, 3, 5, -1, -1, 6, 8, 10, 7, 9, 11, -1, -1, 12, 14, 16, 13, 15, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
|
||||
|
||||
|
||||
struct opl_chip;
|
||||
struct opl_slot;
|
||||
struct opl_channel;
|
||||
|
||||
struct opl_slot {
|
||||
opl_channel *channel;
|
||||
opl_chip *chip;
|
||||
Bit16s out;
|
||||
Bit16s fbmod;
|
||||
Bit16s *mod;
|
||||
Bit16s prout[2];
|
||||
Bit16s eg_rout;
|
||||
Bit16s eg_out;
|
||||
Bit8u eg_inc;
|
||||
Bit8u eg_gen;
|
||||
Bit8u eg_gennext;
|
||||
Bit8u eg_rate;
|
||||
Bit8u eg_ksl;
|
||||
Bit8u *trem;
|
||||
Bit8u reg_vib;
|
||||
Bit8u reg_type;
|
||||
Bit8u reg_ksr;
|
||||
Bit8u reg_mult;
|
||||
Bit8u reg_ksl;
|
||||
Bit8u reg_tl;
|
||||
Bit8u reg_ar;
|
||||
Bit8u reg_dr;
|
||||
Bit8u reg_sl;
|
||||
Bit8u reg_rr;
|
||||
Bit8u reg_wf;
|
||||
Bit8u key;
|
||||
Bit32u pg_phase;
|
||||
};
|
||||
|
||||
struct opl_channel {
|
||||
opl_slot *slots[2];
|
||||
opl_channel *pair;
|
||||
opl_chip *chip;
|
||||
Bit16s *out[4];
|
||||
Bit8u chtype;
|
||||
Bit16u f_num;
|
||||
Bit8u block;
|
||||
Bit8u fb;
|
||||
Bit8u con;
|
||||
Bit8u alg;
|
||||
Bit8u ksv;
|
||||
Bit16u cha, chb;
|
||||
float fcha, fchb;
|
||||
};
|
||||
|
||||
struct opl_chip {
|
||||
opl_channel channel[18];
|
||||
opl_slot slot[36];
|
||||
Bit16u timer;
|
||||
Bit8u newm;
|
||||
Bit8u nts;
|
||||
Bit8u dvb;
|
||||
Bit8u dam;
|
||||
Bit8u rhy;
|
||||
Bit8u vibpos;
|
||||
Bit8u tremval;
|
||||
Bit8u tremtval;
|
||||
Bit8u tremdir;
|
||||
Bit32u noise;
|
||||
Bit16s zeromod;
|
||||
};
|
||||
|
||||
|
||||
class NukedOPL3 : public OPLEmul {
|
||||
private:
|
||||
opl_chip opl3;
|
||||
bool FullPan;
|
||||
public:
|
||||
void Reset();
|
||||
void Update(float* sndptr, int numsamples);
|
||||
void WriteReg(int reg, int v);
|
||||
void SetPanning(int c, float left, float right);
|
||||
|
||||
NukedOPL3(bool stereo);
|
||||
};
|
|
@ -20,6 +20,7 @@ public:
|
|||
OPLEmul *YM3812Create(bool stereo);
|
||||
OPLEmul *DBOPLCreate(bool stereo);
|
||||
OPLEmul *JavaOPLCreate(bool stereo);
|
||||
OPLEmul *NukedOPL3Create(bool stereo);
|
||||
|
||||
#define OPL_SAMPLE_RATE 49716.0
|
||||
#define CENTER_PANNING_POWER 0.70710678118 /* [RH] volume at center for EQP */
|
||||
|
|
|
@ -120,6 +120,7 @@ static void P_Add3DFloor(sector_t* sec, sector_t* sec2, line_t* master, int flag
|
|||
|
||||
//Add the floor
|
||||
ffloor = new F3DFloor;
|
||||
ffloor->top.copied = ffloor->bottom.copied = false;
|
||||
ffloor->top.model = ffloor->bottom.model = ffloor->model = sec2;
|
||||
ffloor->target = sec;
|
||||
ffloor->ceilingclip = ffloor->floorclip = NULL;
|
||||
|
@ -420,6 +421,8 @@ void P_Recalculate3DFloors(sector_t * sector)
|
|||
F3DFloor * pick;
|
||||
unsigned pickindex;
|
||||
F3DFloor * clipped=NULL;
|
||||
F3DFloor * solid=NULL;
|
||||
fixed_t solid_bottom=0;
|
||||
fixed_t clipped_top;
|
||||
fixed_t clipped_bottom=0;
|
||||
fixed_t maxheight, minheight;
|
||||
|
@ -477,6 +480,7 @@ void P_Recalculate3DFloors(sector_t * sector)
|
|||
}
|
||||
|
||||
oldlist.Delete(pickindex);
|
||||
fixed_t pick_bottom=pick->bottom.plane->ZatPoint(CenterSpot(sector));
|
||||
|
||||
if (pick->flags & FF_THISINSIDE)
|
||||
{
|
||||
|
@ -486,10 +490,38 @@ void P_Recalculate3DFloors(sector_t * sector)
|
|||
}
|
||||
else if (pick->flags&(FF_SWIMMABLE|FF_TRANSLUCENT) && pick->flags&FF_EXISTS)
|
||||
{
|
||||
clipped=pick;
|
||||
clipped_top=height;
|
||||
clipped_bottom=pick->bottom.plane->ZatPoint(CenterSpot(sector));
|
||||
ffloors.Push(pick);
|
||||
// We must check if this nonsolid segment gets clipped from the top by another 3D floor
|
||||
if (solid != NULL && solid_bottom < height)
|
||||
{
|
||||
ffloors.Push(pick);
|
||||
if (solid_bottom < pick_bottom)
|
||||
{
|
||||
// this one is fully covered
|
||||
pick->flags|=FF_CLIPPED;
|
||||
pick->flags&=~FF_EXISTS;
|
||||
}
|
||||
else
|
||||
{
|
||||
F3DFloor * dyn=new F3DFloor;
|
||||
*dyn=*pick;
|
||||
pick->flags|=FF_CLIPPED;
|
||||
pick->flags&=~FF_EXISTS;
|
||||
dyn->flags|=FF_DYNAMIC;
|
||||
dyn->top.copyPlane(&solid->bottom);
|
||||
ffloors.Push(dyn);
|
||||
|
||||
clipped = dyn;
|
||||
clipped_top = solid_bottom;
|
||||
clipped_bottom = pick_bottom;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
clipped = pick;
|
||||
clipped_top = height;
|
||||
clipped_bottom = pick_bottom;
|
||||
ffloors.Push(pick);
|
||||
}
|
||||
}
|
||||
else if (clipped && clipped_bottom<height)
|
||||
{
|
||||
|
@ -499,12 +531,10 @@ void P_Recalculate3DFloors(sector_t * sector)
|
|||
clipped->flags|=FF_CLIPPED;
|
||||
clipped->flags&=~FF_EXISTS;
|
||||
dyn->flags|=FF_DYNAMIC;
|
||||
dyn->bottom=pick->top;
|
||||
dyn->bottom.copyPlane(&pick->top);
|
||||
ffloors.Push(dyn);
|
||||
ffloors.Push(pick);
|
||||
|
||||
fixed_t pick_bottom=pick->bottom.plane->ZatPoint(CenterSpot(sector));
|
||||
|
||||
if (pick_bottom<=clipped_bottom)
|
||||
{
|
||||
clipped=NULL;
|
||||
|
@ -515,14 +545,25 @@ void P_Recalculate3DFloors(sector_t * sector)
|
|||
dyn=new F3DFloor;
|
||||
*dyn=*clipped;
|
||||
dyn->flags|=FF_DYNAMIC|FF_EXISTS;
|
||||
dyn->top=pick->bottom;
|
||||
dyn->top.copyPlane(&pick->bottom);
|
||||
ffloors.Push(dyn);
|
||||
clipped = dyn;
|
||||
clipped_top = pick_bottom;
|
||||
}
|
||||
solid = pick;
|
||||
solid_bottom = pick_bottom;
|
||||
}
|
||||
else
|
||||
{
|
||||
clipped=NULL;
|
||||
clipped = NULL;
|
||||
if (solid == NULL || solid_bottom > pick_bottom)
|
||||
{
|
||||
// only if this one is lower
|
||||
solid = pick;
|
||||
solid_bottom = pick_bottom;
|
||||
}
|
||||
ffloors.Push(pick);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -910,3 +951,27 @@ int P_Find3DFloor(sector_t * sec, fixed_t x, fixed_t y, fixed_t z, bool above, b
|
|||
}
|
||||
|
||||
#endif
|
||||
|
||||
#include "c_dispatch.h"
|
||||
|
||||
|
||||
CCMD (dump3df)
|
||||
{
|
||||
if (argv.argc() > 1)
|
||||
{
|
||||
int sec = strtol(argv[1], NULL, 10);
|
||||
sector_t *sector = §ors[sec];
|
||||
TArray<F3DFloor*> & ffloors=sector->e->XFloor.ffloors;
|
||||
|
||||
for (unsigned int i = 0; i < ffloors.Size(); i++)
|
||||
{
|
||||
fixed_t height=ffloors[i]->top.plane->ZatPoint(CenterSpot(sector));
|
||||
fixed_t bheight=ffloors[i]->bottom.plane->ZatPoint(CenterSpot(sector));
|
||||
|
||||
Printf("FFloor %d @ top = %f (model = %d), bottom = %f (model = %d), flags = %B, alpha = %d %s %s\n",
|
||||
i, height / 65536., ffloors[i]->top.model->sectornum,
|
||||
bheight / 65536., ffloors[i]->bottom.model->sectornum,
|
||||
ffloors[i]->flags, ffloors[i]->alpha, (ffloors[i]->flags&FF_EXISTS)? "Exists":"", (ffloors[i]->flags&FF_DYNAMIC)? "Dynamic":"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue