mirror of
https://github.com/ZDoom/qzdoom.git
synced 2025-01-18 15:11:46 +00:00
Merge branch 'master' into gonesolong
Conflicts: src/CMakeLists.txt src/b_think.cpp src/g_doom/a_doomweaps.cpp src/g_hexen/a_clericstaff.cpp src/g_hexen/a_fighterplayer.cpp src/namedef.h src/p_enemy.cpp src/p_local.h src/p_mobj.cpp src/p_teleport.cpp src/sc_man_tokens.h src/thingdef/thingdef_codeptr.cpp src/thingdef/thingdef_function.cpp src/thingdef/thingdef_parse.cpp wadsrc/static/actors/actor.txt wadsrc/static/actors/constants.txt wadsrc/static/actors/shared/inventory.txt - Added register reuse to VMFunctionBuilder for FxPick's code emitter. - Note to self: Need to reimplement IsPointerEqual and CheckClass, which were added to thingdef_function.cpp over the past year, as this file no longer exists in this branch.
This commit is contained in:
commit
b5e4153c78
182 changed files with 23029 additions and 8734 deletions
|
@ -3,6 +3,7 @@ cmake_minimum_required( VERSION 2.4 )
|
||||||
make_release_only()
|
make_release_only()
|
||||||
|
|
||||||
include( CheckFunctionExists )
|
include( CheckFunctionExists )
|
||||||
|
include( CheckCXXCompilerFlag )
|
||||||
|
|
||||||
# DUMB is much slower in a Debug build than a Release build, so we force a Release
|
# 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.
|
# build here, since we're not maintaining DUMB, only using it.
|
||||||
|
@ -104,5 +105,9 @@ add_library( dumb
|
||||||
target_link_libraries( dumb )
|
target_link_libraries( dumb )
|
||||||
|
|
||||||
if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
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 )
|
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;
|
*c = c2;
|
||||||
*d = d2;
|
*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__ (
|
__asm__ __volatile__ (
|
||||||
"xchgl %%ebx, %1\n"
|
"xchgl %%ebx, %1\n"
|
||||||
|
@ -86,7 +86,7 @@ static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
/* GCC or Clang WITHOUT position-independent code generation */
|
/* GCC or Clang WITHOUT position-independent code generation, or x86_64 */
|
||||||
|
|
||||||
__asm__ __volatile__ (
|
__asm__ __volatile__ (
|
||||||
"cpuid"
|
"cpuid"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
cmake_minimum_required( VERSION 2.4 )
|
cmake_minimum_required( VERSION 2.4 )
|
||||||
add_library( output_sdl MODULE output_sdl.c )
|
add_library( output_sdl MODULE output_sdl.c )
|
||||||
include_directories( ${FMOD_INCLUDE_DIR} ${SDL_INCLUDE_DIR} )
|
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" )
|
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
|
add_custom_command( TARGET output_sdl POST_BUILD
|
||||||
|
|
|
@ -92,30 +92,33 @@ Note: All <bool> fields default to false unless mentioned otherwise.
|
||||||
|
|
||||||
linedef
|
linedef
|
||||||
{
|
{
|
||||||
alpha = <float>; // Translucency of this line, default is 1.0
|
alpha = <float>; // Translucency of this line, default is 1.0
|
||||||
renderstyle = <string>; // Render style, can be "translucent" or "add",
|
renderstyle = <string>; // Render style, can be "translucent" or "add",
|
||||||
// default is "translucent".
|
// default is "translucent".
|
||||||
playeruseback = <bool>; // New SPAC flag, true = player can use from back side.
|
playeruseback = <bool> ; // New SPAC flag, true = player can use from back side.
|
||||||
anycross = <bool>; // New SPAC flag, true = any non-projectile
|
anycross = <bool>; // New SPAC flag, true = any non-projectile
|
||||||
// crossing will trigger this line
|
// crossing will trigger this line
|
||||||
monsteractivate = <bool>; // Monsters can trigger this line.
|
monsteractivate = <bool>; // Monsters can trigger this line.
|
||||||
// For compatibility only because this flag's
|
// For compatibility only because this flag's
|
||||||
// semantics can not be fully reproduced with
|
// semantics can not be fully reproduced with
|
||||||
// explicit trigger flags.
|
// explicit trigger flags.
|
||||||
blockplayers = <bool>; // Line blocks players' movement.
|
blockplayers = <bool>; // Line blocks players' movement.
|
||||||
blockeverything = <bool>; // Line blocks everything.
|
blockeverything = <bool>; // Line blocks everything.
|
||||||
firstsideonly = <bool>; // Line can only be triggered from the front side.
|
firstsideonly = <bool>; // Line can only be triggered from the front side.
|
||||||
zoneboundary = <bool>; // Line is a boundary for sound reverb zones.
|
zoneboundary = <bool>; // Line is a boundary for sound reverb zones.
|
||||||
clipmidtex = <bool>; // Line's mid textures are clipped to floor and ceiling.
|
clipmidtex = <bool>; // Line's mid textures are clipped to floor and ceiling.
|
||||||
wrapmidtex = <bool>; // Line's mid textures are wrapped.
|
wrapmidtex = <bool>; // Line's mid textures are wrapped.
|
||||||
midtex3d = <bool>; // Actors can walk on mid texture.
|
midtex3d = <bool>; // Actors can walk on mid texture.
|
||||||
checkswitchrange = <bool>;// Switches can only be activated when vertically reachable.
|
midtex3dimpassible = <bool>;// Used in conjuction with midtex3d - causes the mid
|
||||||
blockprojectiles = <bool>;// Line blocks all projectiles
|
// texture to behave like an impassible line (projectiles
|
||||||
blockuse = <bool>; // Line blocks all use actions
|
// pass through it).
|
||||||
blocksight = <bool>; // Line blocks monster line of sight
|
checkswitchrange = <bool>; // Switches can only be activated when vertically reachable.
|
||||||
blockhitscan = <bool>; // Line blocks hitscan attacks
|
blockprojectiles = <bool>; // Line blocks all projectiles
|
||||||
locknumber = <int>; // Line special is locked
|
blockuse = <bool>; // Line blocks all use actions
|
||||||
arg0str = <string>; // Alternate string-based version of arg0
|
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)
|
transparent = <bool>; // true = line is a Strife transparent line (alpha 0.25)
|
||||||
|
|
||||||
|
|
2491
src/CMakeLists.txt
2491
src/CMakeLists.txt
File diff suppressed because it is too large
Load diff
|
@ -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_Right, 101, -1, -1, 2)
|
||||||
DEFINE_SPECIAL(Scroll_Texture_Up, 102, -1, -1, 2)
|
DEFINE_SPECIAL(Scroll_Texture_Up, 102, -1, -1, 2)
|
||||||
DEFINE_SPECIAL(Scroll_Texture_Down, 103, -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_ForceLightning, 109, 1, 1, 1)
|
||||||
DEFINE_SPECIAL(Light_RaiseByValue, 110, 2, 2, 2)
|
DEFINE_SPECIAL(Light_RaiseByValue, 110, 2, 2, 2)
|
||||||
|
|
26
src/actor.h
26
src/actor.h
|
@ -343,6 +343,20 @@ enum
|
||||||
MF7_ALWAYSTELEFRAG = 0x00000004, // will unconditionally be telefragged when in the way. Overrides all other settings.
|
MF7_ALWAYSTELEFRAG = 0x00000004, // will unconditionally be telefragged when in the way. Overrides all other settings.
|
||||||
MF7_HANDLENODELAY = 0x00000008, // respect NoDelay state flag
|
MF7_HANDLENODELAY = 0x00000008, // respect NoDelay state flag
|
||||||
MF7_WEAPONSPAWN = 0x00000010, // subject to DF_NO_COOP_WEAPON_SPAWN dmflag
|
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 ---
|
// --- mobj.renderflags ---
|
||||||
|
|
||||||
|
@ -679,6 +693,9 @@ public:
|
||||||
// Transforms the actor into a finely-ground paste
|
// Transforms the actor into a finely-ground paste
|
||||||
virtual bool Grind(bool items);
|
virtual bool Grind(bool items);
|
||||||
|
|
||||||
|
// Get this actor's team
|
||||||
|
int GetTeam();
|
||||||
|
|
||||||
// Is the other actor on my team?
|
// Is the other actor on my team?
|
||||||
bool IsTeammate (AActor *other);
|
bool IsTeammate (AActor *other);
|
||||||
|
|
||||||
|
@ -820,13 +837,14 @@ public:
|
||||||
DWORD flags4; // [RH] Even more flags!
|
DWORD flags4; // [RH] Even more flags!
|
||||||
DWORD flags5; // OMG! We need another one.
|
DWORD flags5; // OMG! We need another one.
|
||||||
DWORD flags6; // Shit! Where did all the flags go?
|
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.
|
// [BB] If 0, everybody can see the actor, if > 0, only members of team (VisibleToTeam-1) can see it.
|
||||||
DWORD VisibleToTeam;
|
DWORD VisibleToTeam;
|
||||||
|
|
||||||
int special1; // Special info
|
int special1; // Special info
|
||||||
int special2; // Special info
|
int special2; // Special info
|
||||||
|
int weaponspecial; // Special info for weapons.
|
||||||
int health;
|
int health;
|
||||||
BYTE movedir; // 0-7
|
BYTE movedir; // 0-7
|
||||||
SBYTE visdir;
|
SBYTE visdir;
|
||||||
|
@ -906,9 +924,6 @@ public:
|
||||||
TObjPtr<AInventory> Inventory; // [RH] This actor's inventory
|
TObjPtr<AInventory> Inventory; // [RH] This actor's inventory
|
||||||
DWORD InventoryID; // A unique ID to keep track of inventory items
|
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 smokecounter;
|
||||||
BYTE FloatBobPhase;
|
BYTE FloatBobPhase;
|
||||||
BYTE FriendPlayer; // [RH] Player # + 1 this friendly monster works for (so 0 is no player, 1 is player 0, etc)
|
BYTE FriendPlayer; // [RH] Player # + 1 this friendly monster works for (so 0 is no player, 1 is player 0, etc)
|
||||||
|
@ -934,9 +949,12 @@ public:
|
||||||
FNameNoInit DamageType;
|
FNameNoInit DamageType;
|
||||||
FNameNoInit DamageTypeReceived;
|
FNameNoInit DamageTypeReceived;
|
||||||
fixed_t DamageFactor;
|
fixed_t DamageFactor;
|
||||||
|
fixed_t DamageMultiply;
|
||||||
|
|
||||||
FNameNoInit PainType;
|
FNameNoInit PainType;
|
||||||
FNameNoInit DeathType;
|
FNameNoInit DeathType;
|
||||||
|
PClassActor *TeleFogSourceType;
|
||||||
|
PClassActor *TeleFogDestType;
|
||||||
|
|
||||||
FState *SpawnState;
|
FState *SpawnState;
|
||||||
FState *SeeState;
|
FState *SeeState;
|
||||||
|
|
|
@ -56,6 +56,13 @@ AActor *COPY_AAPTR(AActor *origin, int selector)
|
||||||
case AAPTR_TRACER: return origin->tracer;
|
case AAPTR_TRACER: return origin->tracer;
|
||||||
case AAPTR_FRIENDPLAYER:
|
case AAPTR_FRIENDPLAYER:
|
||||||
return origin->FriendPlayer ? AAPTR_RESOLVE_PLAYERNUM(origin->FriendPlayer - 1) : NULL;
|
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_PLAYER8 = 0x2000,
|
||||||
|
|
||||||
AAPTR_FRIENDPLAYER = 0x4000,
|
AAPTR_FRIENDPLAYER = 0x4000,
|
||||||
|
AAPTR_GET_LINETARGET = 0x8000,
|
||||||
|
|
||||||
AAPTR_PLAYER_SELECTORS =
|
AAPTR_PLAYER_SELECTORS =
|
||||||
AAPTR_PLAYER_GETTARGET|AAPTR_PLAYER_GETCONVERSATION,
|
AAPTR_PLAYER_GETTARGET|AAPTR_PLAYER_GETCONVERSATION,
|
||||||
|
|
||||||
AAPTR_GENERAL_SELECTORS =
|
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_STATIC_SELECTORS =
|
||||||
AAPTR_PLAYER1|AAPTR_PLAYER2|AAPTR_PLAYER3|AAPTR_PLAYER4|
|
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.mMapArrow.IsNotEmpty()) AM_ParseArrow(MapArrow, gameinfo.mMapArrow);
|
||||||
if (gameinfo.mCheatMapArrow.IsNotEmpty()) AM_ParseArrow(CheatMapArrow, gameinfo.mCheatMapArrow);
|
if (gameinfo.mCheatMapArrow.IsNotEmpty()) AM_ParseArrow(CheatMapArrow, gameinfo.mCheatMapArrow);
|
||||||
AM_ParseArrow(CheatKey, "maparrows/key.txt");
|
AM_ParseArrow(CheatKey, gameinfo.mCheatKey);
|
||||||
AM_ParseArrow(EasyKey, "maparrows/ravenkey.txt");
|
AM_ParseArrow(EasyKey, gameinfo.mEasyKey);
|
||||||
if (MapArrow.Size() == 0) I_FatalError("No automap arrow defined");
|
if (MapArrow.Size() == 0) I_FatalError("No automap arrow defined");
|
||||||
|
|
||||||
char namebuf[9];
|
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
|
// [RH] Moved console commands out of d_netcmd.c (in Cajun source), because
|
||||||
// belong there.
|
// they don't really belong there.
|
||||||
|
|
||||||
#include "c_cvars.h"
|
#include "c_cvars.h"
|
||||||
#include "c_dispatch.h"
|
#include "c_dispatch.h"
|
||||||
|
@ -14,6 +14,102 @@
|
||||||
#include "d_net.h"
|
#include "d_net.h"
|
||||||
#include "farchive.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 (Int, bot_next_color, 11, 0)
|
||||||
CVAR (Bool, bot_observer, false, 0)
|
CVAR (Bool, bot_observer, false, 0)
|
||||||
|
|
||||||
|
@ -55,9 +151,14 @@ void FCajunMaster::ClearPlayer (int i, bool keepTeam)
|
||||||
bot = bot->next;
|
bot = bot->next;
|
||||||
if (bot)
|
if (bot)
|
||||||
{
|
{
|
||||||
bot->inuse = false;
|
bot->inuse = BOTINUSE_No;
|
||||||
bot->lastteam = keepTeam ? players[i].userinfo.GetTeam() : TEAM_NONE;
|
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();
|
players[i].~player_t();
|
||||||
::new(&players[i]) player_t;
|
::new(&players[i]) player_t;
|
||||||
players[i].userinfo.Reset();
|
players[i].userinfo.Reset();
|
||||||
|
@ -66,6 +167,12 @@ void FCajunMaster::ClearPlayer (int i, bool keepTeam)
|
||||||
|
|
||||||
CCMD (removebots)
|
CCMD (removebots)
|
||||||
{
|
{
|
||||||
|
if (!players[consoleplayer].settings_controller)
|
||||||
|
{
|
||||||
|
Printf ("Only setting controllers can remove bots\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Net_WriteByte (DEM_KILLBOTS);
|
Net_WriteByte (DEM_KILLBOTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +198,7 @@ CCMD (listbots)
|
||||||
|
|
||||||
while (thebot)
|
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;
|
thebot = thebot->next;
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
135
src/b_bot.h
135
src/b_bot.h
|
@ -14,6 +14,7 @@
|
||||||
#include "d_ticcmd.h"
|
#include "d_ticcmd.h"
|
||||||
#include "r_defs.h"
|
#include "r_defs.h"
|
||||||
#include "a_pickups.h"
|
#include "a_pickups.h"
|
||||||
|
#include "stats.h"
|
||||||
|
|
||||||
#define FORWARDWALK 0x1900
|
#define FORWARDWALK 0x1900
|
||||||
#define FORWARDRUN 0x3200
|
#define FORWARDRUN 0x3200
|
||||||
|
@ -60,6 +61,13 @@ struct botskill_t
|
||||||
|
|
||||||
FArchive &operator<< (FArchive &arc, botskill_t &skill);
|
FArchive &operator<< (FArchive &arc, botskill_t &skill);
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
BOTINUSE_No,
|
||||||
|
BOTINUSE_Waiting,
|
||||||
|
BOTINUSE_Yes,
|
||||||
|
};
|
||||||
|
|
||||||
//Info about all bots in the bots.cfg
|
//Info about all bots in the bots.cfg
|
||||||
//Updated during each level start.
|
//Updated during each level start.
|
||||||
//Info given to bots when they're spawned.
|
//Info given to bots when they're spawned.
|
||||||
|
@ -69,7 +77,7 @@ struct botinfo_t
|
||||||
char *name;
|
char *name;
|
||||||
char *info;
|
char *info;
|
||||||
botskill_t skill;
|
botskill_t skill;
|
||||||
bool inuse;
|
int inuse;
|
||||||
int lastteam;
|
int lastteam;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -81,35 +89,29 @@ public:
|
||||||
|
|
||||||
void ClearPlayer (int playernum, bool keepTeam);
|
void ClearPlayer (int playernum, bool keepTeam);
|
||||||
|
|
||||||
//(B_Game.c)
|
//(b_game.cpp)
|
||||||
void Main (int buf);
|
void Main ();
|
||||||
void Init ();
|
void Init ();
|
||||||
void End();
|
void End();
|
||||||
void CleanBotstuff (player_t *p);
|
|
||||||
bool SpawnBot (const char *name, int color = NOCOLOR);
|
bool SpawnBot (const char *name, int color = NOCOLOR);
|
||||||
|
void TryAddBot (BYTE **stream, int player);
|
||||||
|
void RemoveAllBots (bool fromlist);
|
||||||
bool LoadBots ();
|
bool LoadBots ();
|
||||||
void ForgetBots ();
|
void ForgetBots ();
|
||||||
void DoAddBot (int bnum, char *info);
|
|
||||||
void RemoveAllBots (bool fromlist);
|
|
||||||
|
|
||||||
//(B_Func.c)
|
//(b_func.cpp)
|
||||||
bool Check_LOS (AActor *mobj1, AActor *mobj2, angle_t vangle);
|
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)
|
//(b_move.cpp)
|
||||||
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);
|
|
||||||
bool CleanAhead (AActor *thing, fixed_t x, fixed_t y, ticcmd_t *cmd);
|
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);
|
bool IsDangerous (sector_t *sec);
|
||||||
|
|
||||||
TArray<FString> getspawned; //Array of bots (their names) which should be spawned when starting a game.
|
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 freeze:1; //Game in freeze mode.
|
||||||
BYTE changefreeze:1; //Game wants to change freeze mode.
|
BYTE changefreeze:1; //Game wants to change freeze mode.
|
||||||
int botnum;
|
int botnum;
|
||||||
|
@ -123,20 +125,8 @@ public:
|
||||||
bool m_Thinking;
|
bool m_Thinking;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//(B_Func.c)
|
//(b_game.cpp)
|
||||||
bool Reachable (AActor *actor, AActor *target);
|
bool DoAddBot (BYTE *info, botskill_t skill);
|
||||||
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);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool ctf;
|
bool ctf;
|
||||||
|
@ -145,9 +135,84 @@ protected:
|
||||||
bool observer; //Consoleplayer is observer.
|
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
|
//Externs
|
||||||
extern FCajunMaster bglobal;
|
extern FCajunMaster bglobal;
|
||||||
|
extern cycle_t BotThinkCycles, BotSupportCycles;
|
||||||
|
|
||||||
EXTERN_CVAR (Float, bot_flag_return_time)
|
EXTERN_CVAR (Float, bot_flag_return_time)
|
||||||
EXTERN_CVAR (Int, bot_next_color)
|
EXTERN_CVAR (Int, bot_next_color)
|
||||||
|
@ -158,7 +223,3 @@ EXTERN_CVAR (Bool, bot_watersplash)
|
||||||
EXTERN_CVAR (Bool, bot_chat)
|
EXTERN_CVAR (Bool, bot_chat)
|
||||||
|
|
||||||
#endif // __B_BOT_H__
|
#endif // __B_BOT_H__
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
255
src/b_func.cpp
255
src/b_func.cpp
|
@ -24,24 +24,23 @@
|
||||||
static FRandom pr_botdofire ("BotDoFire");
|
static FRandom pr_botdofire ("BotDoFire");
|
||||||
|
|
||||||
|
|
||||||
//Checks TRUE reachability from
|
//Checks TRUE reachability from bot to a looker.
|
||||||
//one looker to another. First mobj (looker) is looker.
|
bool DBot::Reachable (AActor *rtarget)
|
||||||
bool FCajunMaster::Reachable (AActor *looker, AActor *rtarget)
|
|
||||||
{
|
{
|
||||||
if (looker == rtarget)
|
if (player->mo == rtarget)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if ((rtarget->Sector->ceilingplane.ZatPoint (rtarget->x, rtarget->y) -
|
if ((rtarget->Sector->ceilingplane.ZatPoint (rtarget->x, rtarget->y) -
|
||||||
rtarget->Sector->floorplane.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;
|
return false;
|
||||||
|
|
||||||
sector_t *last_s = looker->Sector;
|
sector_t *last_s = player->mo->Sector;
|
||||||
fixed_t last_z = last_s->floorplane.ZatPoint (looker->x, looker->y);
|
fixed_t last_z = last_s->floorplane.ZatPoint (player->mo->x, player->mo->y);
|
||||||
fixed_t estimated_dist = P_AproxDistance (looker->x - rtarget->x, looker->y - rtarget->y);
|
fixed_t estimated_dist = P_AproxDistance (player->mo->x - rtarget->x, player->mo->y - rtarget->y);
|
||||||
bool reachable = true;
|
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;
|
intercept_t *in;
|
||||||
while ((in = it.Next()))
|
while ((in = it.Next()))
|
||||||
{
|
{
|
||||||
|
@ -55,8 +54,8 @@ bool FCajunMaster::Reachable (AActor *looker, AActor *rtarget)
|
||||||
frac = in->frac - FixedDiv (4*FRACUNIT, MAX_TRAVERSE_DIST);
|
frac = in->frac - FixedDiv (4*FRACUNIT, MAX_TRAVERSE_DIST);
|
||||||
dist = FixedMul (frac, MAX_TRAVERSE_DIST);
|
dist = FixedMul (frac, MAX_TRAVERSE_DIST);
|
||||||
|
|
||||||
hitx = it.Trace().x + FixedMul (looker->velx, frac);
|
hitx = it.Trace().x + FixedMul (player->mo->velx, frac);
|
||||||
hity = it.Trace().y + FixedMul (looker->vely, frac);
|
hity = it.Trace().y + FixedMul (player->mo->vely, frac);
|
||||||
|
|
||||||
if (in->isaline)
|
if (in->isaline)
|
||||||
{
|
{
|
||||||
|
@ -76,7 +75,7 @@ bool FCajunMaster::Reachable (AActor *looker, AActor *rtarget)
|
||||||
if (!bglobal.IsDangerous (s) && //Any nukage/lava?
|
if (!bglobal.IsDangerous (s) && //Any nukage/lava?
|
||||||
(floorheight <= (last_z+MAXMOVEHEIGHT)
|
(floorheight <= (last_z+MAXMOVEHEIGHT)
|
||||||
&& ((ceilingheight == floorheight && line->special)
|
&& ((ceilingheight == floorheight && line->special)
|
||||||
|| (ceilingheight - floorheight) >= looker->height))) //Does it fit?
|
|| (ceilingheight - floorheight) >= player->mo->height))) //Does it fit?
|
||||||
{
|
{
|
||||||
last_z = floorheight;
|
last_z = floorheight;
|
||||||
last_s = s;
|
last_s = s;
|
||||||
|
@ -95,7 +94,7 @@ bool FCajunMaster::Reachable (AActor *looker, AActor *rtarget)
|
||||||
}
|
}
|
||||||
|
|
||||||
thing = in->d.thing;
|
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;
|
continue;
|
||||||
if (thing == rtarget && (rtarget->Sector->floorplane.ZatPoint (rtarget->x, rtarget->y) <= (last_z+MAXMOVEHEIGHT)))
|
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.
|
//if these conditions are true, the function returns true.
|
||||||
//GOOD TO KNOW is that the player's view angle
|
//GOOD TO KNOW is that the player's view angle
|
||||||
//in doom is 90 degrees infront.
|
//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
|
return false; // out of sight
|
||||||
if (vangle == ANGLE_MAX)
|
if (vangle == ANGLE_MAX)
|
||||||
return true;
|
return true;
|
||||||
if (vangle == 0)
|
if (vangle == 0)
|
||||||
return false; //Looker seems to be blind.
|
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
|
//The bot will check if it's time to fire
|
||||||
//and do so if that is the case.
|
//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.
|
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.
|
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;
|
fixed_t dist;
|
||||||
angle_t an;
|
angle_t an;
|
||||||
int m;
|
int m;
|
||||||
static bool inc[MAXPLAYERS];
|
|
||||||
AActor *enemy = actor->player->enemy;
|
|
||||||
|
|
||||||
if (!enemy || !(enemy->flags & MF_SHOOTABLE) || enemy->health <= 0)
|
if (!enemy || !(enemy->flags & MF_SHOOTABLE) || enemy->health <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (actor->player->ReadyWeapon == NULL)
|
if (player->ReadyWeapon == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (actor->player->damagecount > actor->player->skill.isp)
|
if (player->damagecount > skill.isp)
|
||||||
{
|
{
|
||||||
actor->player->first_shot = true;
|
first_shot = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Reaction skill thing.
|
//Reaction skill thing.
|
||||||
if (actor->player->first_shot &&
|
if (first_shot &&
|
||||||
!(actor->player->ReadyWeapon->WeaponFlags & WIF_BOT_REACTION_SKILL_THING))
|
!(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;
|
first_shot = false;
|
||||||
if (actor->player->t_react)
|
if (t_react)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//MAKEME: Decrease the rocket suicides even more.
|
//MAKEME: Decrease the rocket suicides even more.
|
||||||
|
|
||||||
no_fire = true;
|
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.
|
//Distance to enemy.
|
||||||
dist = P_AproxDistance ((actor->x + actor->velx) - (enemy->x + enemy->velx),
|
dist = P_AproxDistance ((player->mo->x + player->mo->velx) - (enemy->x + enemy->velx),
|
||||||
(actor->y + actor->vely) - (enemy->y + enemy->vely));
|
(player->mo->y + player->mo->vely) - (enemy->y + enemy->vely));
|
||||||
|
|
||||||
//FIRE EACH TYPE OF WEAPON DIFFERENT: Here should all the different weapons go.
|
//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
|
// This weapon can fire a projectile and has enough ammo to do so
|
||||||
goto shootmissile;
|
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
|
// 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.
|
// 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));
|
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.
|
//MAKEME: This should be smarter.
|
||||||
if ((pr_botdofire()%200)<=actor->player->skill.reaction)
|
if ((pr_botdofire()%200)<=skill.reaction)
|
||||||
if(Check_LOS(actor, actor->player->enemy, SHOOTFOV))
|
if(Check_LOS(enemy, SHOOTFOV))
|
||||||
no_fire = false;
|
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
|
//Special rules for RL
|
||||||
an = FireRox (actor, enemy, cmd);
|
an = FireRox (enemy, cmd);
|
||||||
if(an)
|
if(an)
|
||||||
{
|
{
|
||||||
actor->player->angle = an;
|
angle = an;
|
||||||
//have to be somewhat precise. to avoid suicide.
|
//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;
|
no_fire = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// prediction aiming
|
// prediction aiming
|
||||||
shootmissile:
|
shootmissile:
|
||||||
dist = P_AproxDistance (actor->x - enemy->x, actor->y - enemy->y);
|
dist = P_AproxDistance (player->mo->x - enemy->x, player->mo->y - enemy->y);
|
||||||
m = dist / GetDefaultByType (actor->player->ReadyWeapon->ProjectileType)->Speed;
|
m = dist / GetDefaultByType (player->ReadyWeapon->ProjectileType)->Speed;
|
||||||
SetBodyAt (enemy->x + enemy->velx*m*2, enemy->y + enemy->vely*m*2, enemy->z, 1);
|
bglobal.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);
|
angle = R_PointToAngle2 (player->mo->x, player->mo->y, bglobal.body1->x, bglobal.body1->y);
|
||||||
if (Check_LOS (actor, enemy, SHOOTFOV))
|
if (Check_LOS (enemy, SHOOTFOV))
|
||||||
no_fire = false;
|
no_fire = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Other weapons, mostly instant hit stuff.
|
//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;
|
aiming_penalty = 0;
|
||||||
if (enemy->flags & MF_SHADOW)
|
if (enemy->flags & MF_SHADOW)
|
||||||
aiming_penalty += (pr_botdofire()%25)+10;
|
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
|
aiming_penalty += pr_botdofire()%40;//Dark
|
||||||
if (actor->player->damagecount)
|
if (player->damagecount)
|
||||||
aiming_penalty += actor->player->damagecount; //Blood in face makes it hard to aim
|
aiming_penalty += player->damagecount; //Blood in face makes it hard to aim
|
||||||
aiming_value = actor->player->skill.aiming - aiming_penalty;
|
aiming_value = skill.aiming - aiming_penalty;
|
||||||
if (aiming_value <= 0)
|
if (aiming_value <= 0)
|
||||||
aiming_value = 1;
|
aiming_value = 1;
|
||||||
m = ((SHOOTFOV/2)-(aiming_value*SHOOTFOV/200)); //Higher skill is more accurate
|
m = ((SHOOTFOV/2)-(aiming_value*SHOOTFOV/200)); //Higher skill is more accurate
|
||||||
|
@ -249,18 +246,18 @@ shootmissile:
|
||||||
|
|
||||||
if (m)
|
if (m)
|
||||||
{
|
{
|
||||||
if (inc[actor->id])
|
if (increase)
|
||||||
actor->player->angle += m;
|
angle += m;
|
||||||
else
|
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;
|
no_fire = false;
|
||||||
}
|
}
|
||||||
if (!no_fire) //If going to fire weapon
|
if (!no_fire) //If going to fire weapon
|
||||||
|
@ -268,53 +265,48 @@ shootmissile:
|
||||||
cmd->ucmd.buttons |= BT_ATTACK;
|
cmd->ucmd.buttons |= BT_ATTACK;
|
||||||
}
|
}
|
||||||
//Prevents bot from jerking, when firing automatic things with low skill.
|
//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
|
//This function is called every
|
||||||
//tick (for each bot) to set
|
//tick (for each bot) to set
|
||||||
//the mate (teammate coop mate).
|
//the mate (teammate coop mate).
|
||||||
AActor *FCajunMaster::Choose_Mate (AActor *bot)
|
AActor *DBot::Choose_Mate ()
|
||||||
{
|
{
|
||||||
int count;
|
int count;
|
||||||
int count2;
|
|
||||||
fixed_t closest_dist, test;
|
fixed_t closest_dist, test;
|
||||||
AActor *target;
|
AActor *target;
|
||||||
AActor *observer;
|
AActor *observer;
|
||||||
bool p_leader[MAXPLAYERS];
|
|
||||||
|
|
||||||
//is mate alive?
|
//is mate alive?
|
||||||
if (bot->player->mate)
|
if (mate)
|
||||||
{
|
{
|
||||||
if (bot->player->mate->health <= 0)
|
if (mate->health <= 0)
|
||||||
bot->player->mate = NULL;
|
mate = NULL;
|
||||||
else
|
else
|
||||||
bot->player->last_mate = bot->player->mate;
|
last_mate = mate;
|
||||||
}
|
}
|
||||||
if (bot->player->mate) //Still is..
|
if (mate) //Still is..
|
||||||
return bot->player->mate;
|
return mate;
|
||||||
|
|
||||||
//Check old_mates status.
|
//Check old_mates status.
|
||||||
if (bot->player->last_mate)
|
if (last_mate)
|
||||||
if (bot->player->last_mate->health <= 0)
|
if (last_mate->health <= 0)
|
||||||
bot->player->last_mate = NULL;
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
target = NULL;
|
target = NULL;
|
||||||
closest_dist = FIXED_MAX;
|
closest_dist = FIXED_MAX;
|
||||||
|
@ -330,18 +322,17 @@ AActor *FCajunMaster::Choose_Mate (AActor *bot)
|
||||||
|
|
||||||
if (playeringame[count]
|
if (playeringame[count]
|
||||||
&& client->mo
|
&& client->mo
|
||||||
&& bot != client->mo
|
&& player->mo != client->mo
|
||||||
&& (bot->IsTeammate (client->mo) || !deathmatch)
|
&& (player->mo->IsTeammate (client->mo) || !deathmatch)
|
||||||
&& client->mo->health > 0
|
&& client->mo->health > 0
|
||||||
&& client->mo != observer
|
&& client->mo != observer
|
||||||
&& ((bot->health/2) <= client->mo->health || !deathmatch)
|
&& ((player->mo->health/2) <= client->mo->health || !deathmatch)
|
||||||
&& !p_leader[count]) //taken?
|
&& !bglobal.IsLeader(client)) //taken?
|
||||||
{
|
{
|
||||||
|
if (P_CheckSight (player->mo, client->mo, SF_IGNOREVISIBILITY))
|
||||||
if (P_CheckSight (bot, client->mo, SF_IGNOREVISIBILITY))
|
|
||||||
{
|
{
|
||||||
test = P_AproxDistance (client->mo->x - bot->x,
|
test = P_AproxDistance (client->mo->x - player->mo->x,
|
||||||
client->mo->y - bot->y);
|
client->mo->y - player->mo->y);
|
||||||
|
|
||||||
if (test < closest_dist)
|
if (test < closest_dist)
|
||||||
{
|
{
|
||||||
|
@ -354,15 +345,15 @@ AActor *FCajunMaster::Choose_Mate (AActor *bot)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
//Make a introducing to mate.
|
//Make a introducing to mate.
|
||||||
if(target && target!=bot->player->last_mate)
|
if(target && target!=last_mate)
|
||||||
{
|
{
|
||||||
if((P_Random()%(200*bglobal.botnum))<3)
|
if((P_Random()%(200*bglobal.botnum))<3)
|
||||||
{
|
{
|
||||||
bot->player->chat = c_teamup;
|
chat = c_teamup;
|
||||||
if(target->bot)
|
if(target->bot)
|
||||||
strcpy(bot->player->c_target, botsingame[target->bot_id]);
|
strcpy(c_target, botsingame[target->bot_id]);
|
||||||
else if(target->player)
|
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
|
//MAKEME: Make this a smart decision
|
||||||
AActor *FCajunMaster::Find_enemy (AActor *bot)
|
AActor *DBot::Find_enemy ()
|
||||||
{
|
{
|
||||||
int count;
|
int count;
|
||||||
fixed_t closest_dist, temp; //To target.
|
fixed_t closest_dist, temp; //To target.
|
||||||
|
@ -382,15 +373,15 @@ AActor *FCajunMaster::Find_enemy (AActor *bot)
|
||||||
|
|
||||||
if (!deathmatch)
|
if (!deathmatch)
|
||||||
{ // [RH] Take advantage of the Heretic/Hexen code to be a little smarter
|
{ // [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
|
//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;
|
vangle = ANGLE_MAX;
|
||||||
else
|
else
|
||||||
vangle = ENEMY_SCAN_FOV;
|
vangle = ENEMY_SCAN_FOV;
|
||||||
bot->player->allround = false;
|
allround = false;
|
||||||
|
|
||||||
target = NULL;
|
target = NULL;
|
||||||
closest_dist = FIXED_MAX;
|
closest_dist = FIXED_MAX;
|
||||||
|
@ -403,21 +394,21 @@ AActor *FCajunMaster::Find_enemy (AActor *bot)
|
||||||
{
|
{
|
||||||
player_t *client = &players[count];
|
player_t *client = &players[count];
|
||||||
if (playeringame[count]
|
if (playeringame[count]
|
||||||
&& !bot->IsTeammate (client->mo)
|
&& !player->mo->IsTeammate (client->mo)
|
||||||
&& client->mo != observer
|
&& client->mo != observer
|
||||||
&& client->mo->health > 0
|
&& 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 (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( bot, players[count].mo))
|
//if(P_CheckSight(player->mo, players[count].mo))
|
||||||
{
|
{
|
||||||
temp = P_AproxDistance (client->mo->x - bot->x,
|
temp = P_AproxDistance (client->mo->x - player->mo->x,
|
||||||
client->mo->y - bot->y);
|
client->mo->y - player->mo->y);
|
||||||
|
|
||||||
//Too dark?
|
//Too dark?
|
||||||
if (temp > DARK_DIST &&
|
if (temp > DARK_DIST &&
|
||||||
client->mo->Sector->lightlevel < WHATS_DARK /*&&
|
client->mo->Sector->lightlevel < WHATS_DARK /*&&
|
||||||
bot->player->Powers & PW_INFRARED*/)
|
player->Powers & PW_INFRARED*/)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (temp < closest_dist)
|
if (temp < closest_dist)
|
||||||
|
@ -501,16 +492,16 @@ fixed_t FCajunMaster::FakeFire (AActor *source, AActor *dest, ticcmd_t *cmd)
|
||||||
return dist;
|
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;
|
fixed_t dist;
|
||||||
angle_t ang;
|
angle_t ang;
|
||||||
AActor *actor;
|
AActor *actor;
|
||||||
int m;
|
int m;
|
||||||
|
|
||||||
SetBodyAt (bot->x + FixedMul(bot->velx, 5*FRACUNIT),
|
bglobal.SetBodyAt (player->mo->x + FixedMul(player->mo->velx, 5*FRACUNIT),
|
||||||
bot->y + FixedMul(bot->vely, 5*FRACUNIT),
|
player->mo->y + FixedMul(player->mo->vely, 5*FRACUNIT),
|
||||||
bot->z + (bot->height / 2), 2);
|
player->mo->z + (player->mo->height / 2), 2);
|
||||||
|
|
||||||
actor = bglobal.body2;
|
actor = bglobal.body2;
|
||||||
|
|
||||||
|
@ -520,16 +511,16 @@ angle_t FCajunMaster::FireRox (AActor *bot, AActor *enemy, ticcmd_t *cmd)
|
||||||
//Predict.
|
//Predict.
|
||||||
m = (((dist+1)/FRACUNIT) / GetDefaultByName("Rocket")->Speed);
|
m = (((dist+1)/FRACUNIT) / GetDefaultByName("Rocket")->Speed);
|
||||||
|
|
||||||
SetBodyAt (enemy->x + FixedMul(enemy->velx, (m+2*FRACUNIT)),
|
bglobal.SetBodyAt (enemy->x + FixedMul(enemy->velx, (m+2*FRACUNIT)),
|
||||||
enemy->y + FixedMul(enemy->vely, (m+2*FRACUNIT)), ONFLOORZ, 1);
|
enemy->y + FixedMul(enemy->vely, (m+2*FRACUNIT)), ONFLOORZ, 1);
|
||||||
dist = P_AproxDistance(actor->x-bglobal.body1->x, actor->y-bglobal.body1->y);
|
dist = P_AproxDistance(actor->x-bglobal.body1->x, actor->y-bglobal.body1->y);
|
||||||
//try the predicted location
|
//try the predicted location
|
||||||
if (P_CheckSight (actor, bglobal.body1, SF_IGNOREVISIBILITY)) //See the predicted location, so give a test missile
|
if (P_CheckSight (actor, bglobal.body1, SF_IGNOREVISIBILITY)) //See the predicted location, so give a test missile
|
||||||
{
|
{
|
||||||
FCheckPosition tm;
|
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);
|
ang = R_PointToAngle2 (actor->x, actor->y, bglobal.body1->x, bglobal.body1->y);
|
||||||
return ang;
|
return ang;
|
||||||
|
@ -539,9 +530,9 @@ angle_t FCajunMaster::FireRox (AActor *bot, AActor *enemy, ticcmd_t *cmd)
|
||||||
//Try fire straight.
|
//Try fire straight.
|
||||||
if (P_CheckSight (actor, enemy, 0))
|
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;
|
return ang;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -559,3 +550,25 @@ bool FCajunMaster::SafeCheckPosition (AActor *actor, fixed_t x, fixed_t y, FChec
|
||||||
actor->flags = savedFlags;
|
actor->flags = savedFlags;
|
||||||
return res;
|
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
|
BOTCFG_TEAM
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool waitingforspawn[MAXPLAYERS];
|
|
||||||
|
|
||||||
FCajunMaster::~FCajunMaster()
|
FCajunMaster::~FCajunMaster()
|
||||||
{
|
{
|
||||||
ForgetBots();
|
ForgetBots();
|
||||||
}
|
}
|
||||||
|
|
||||||
//This function is called every tick (from g_game.c),
|
//This function is called every tick (from g_game.c).
|
||||||
//send bots into thinking (+more).
|
void FCajunMaster::Main ()
|
||||||
void FCajunMaster::Main (int buf)
|
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
BotThinkCycles.Reset();
|
BotThinkCycles.Reset();
|
||||||
|
|
||||||
if (consoleplayer != Net_Arbitrator || demoplayback)
|
if (demoplayback || gamestate != GS_LEVEL || consoleplayer != Net_Arbitrator)
|
||||||
return;
|
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?
|
//Add new bots?
|
||||||
if (wanted_botnum > botnum && !freeze)
|
if (wanted_botnum > botnum && !freeze)
|
||||||
{
|
{
|
||||||
if (t_join == ((wanted_botnum - botnum) * SPAWN_DELAY))
|
if (t_join == ((wanted_botnum - botnum) * SPAWN_DELAY))
|
||||||
{
|
{
|
||||||
if (!SpawnBot (getspawned[spawn_tries]))
|
if (!SpawnBot (getspawned[spawn_tries]))
|
||||||
wanted_botnum--;
|
wanted_botnum--;
|
||||||
spawn_tries++;
|
spawn_tries++;
|
||||||
}
|
}
|
||||||
|
|
||||||
t_join--;
|
t_join--;
|
||||||
|
@ -156,14 +134,10 @@ void FCajunMaster::Main (int buf)
|
||||||
players[consoleplayer].mo->flags2 &= ~MF2_FLY;
|
players[consoleplayer].mo->flags2 &= ~MF2_FLY;
|
||||||
players[consoleplayer].mo->LinkToWorld ();
|
players[consoleplayer].mo->LinkToWorld ();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Thinking = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCajunMaster::Init ()
|
void FCajunMaster::Init ()
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
botnum = 0;
|
botnum = 0;
|
||||||
firstthing = NULL;
|
firstthing = NULL;
|
||||||
spawn_tries = 0;
|
spawn_tries = 0;
|
||||||
|
@ -172,18 +146,6 @@ void FCajunMaster::Init ()
|
||||||
body1 = NULL;
|
body1 = NULL;
|
||||||
body2 = 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)
|
if (ctf && teamplay == false)
|
||||||
teamplay = true; //Need teamplay for ctf. (which is not done yet)
|
teamplay = true; //Need teamplay for ctf. (which is not done yet)
|
||||||
|
|
||||||
|
@ -199,7 +161,7 @@ void FCajunMaster::Init ()
|
||||||
|
|
||||||
while (thebot != NULL)
|
while (thebot != NULL)
|
||||||
{
|
{
|
||||||
thebot->inuse = false;
|
thebot->inuse = BOTINUSE_No;
|
||||||
thebot = thebot->next;
|
thebot = thebot->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -212,19 +174,13 @@ void FCajunMaster::End ()
|
||||||
|
|
||||||
//Arrange wanted botnum and their names, so they can be spawned next level.
|
//Arrange wanted botnum and their names, so they can be spawned next level.
|
||||||
getspawned.Clear();
|
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)
|
if (deathmatch)
|
||||||
{
|
{
|
||||||
|
for (i = 0; i < MAXPLAYERS; i++)
|
||||||
|
{
|
||||||
|
getspawned.Push(players[i].userinfo.GetName());
|
||||||
|
}
|
||||||
|
|
||||||
wanted_botnum = botnum;
|
wanted_botnum = botnum;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -240,12 +196,10 @@ void FCajunMaster::End ()
|
||||||
//The color parameter can be either a
|
//The color parameter can be either a
|
||||||
//color (range from 0-10), or = NOCOLOR.
|
//color (range from 0-10), or = NOCOLOR.
|
||||||
//The color parameter overides bots
|
//The color parameter overides bots
|
||||||
//induvidual colors if not = NOCOLOR.
|
//individual colors if not = NOCOLOR.
|
||||||
|
|
||||||
bool FCajunMaster::SpawnBot (const char *name, int color)
|
bool FCajunMaster::SpawnBot (const char *name, int color)
|
||||||
{
|
{
|
||||||
int playernumber;
|
|
||||||
|
|
||||||
//COLORS
|
//COLORS
|
||||||
static const char colors[11][17] =
|
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
|
"\\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;
|
botinfo_t *thebot;
|
||||||
|
int botshift;
|
||||||
|
|
||||||
if (name)
|
if (name)
|
||||||
{
|
{
|
||||||
thebot = botinfo;
|
thebot = botinfo;
|
||||||
|
|
||||||
// Check if exist or already in the game.
|
// Check if exist or already in the game.
|
||||||
|
botshift = 0;
|
||||||
while (thebot && stricmp (name, thebot->name))
|
while (thebot && stricmp (name, thebot->name))
|
||||||
|
{
|
||||||
thebot = thebot->next;
|
thebot = thebot->next;
|
||||||
|
botshift++;
|
||||||
|
}
|
||||||
|
|
||||||
if (thebot == NULL)
|
if (thebot == NULL)
|
||||||
{
|
{
|
||||||
Printf ("couldn't find %s in %s\n", name, BOTFILENAME);
|
Printf ("couldn't find %s in %s\n", name, BOTFILENAME);
|
||||||
return false;
|
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);
|
Printf ("%s is already in the thick\n", name);
|
||||||
return false;
|
return false;
|
||||||
|
@ -304,9 +253,13 @@ bool FCajunMaster::SpawnBot (const char *name, int color)
|
||||||
{
|
{
|
||||||
int rnum = (pr_botspawn() % loaded_bots);
|
int rnum = (pr_botspawn() % loaded_bots);
|
||||||
thebot = botinfo;
|
thebot = botinfo;
|
||||||
|
botshift = 0;
|
||||||
while (rnum)
|
while (rnum)
|
||||||
|
{
|
||||||
--rnum, thebot = thebot->next;
|
--rnum, thebot = thebot->next;
|
||||||
if (!thebot->inuse)
|
botshift++;
|
||||||
|
}
|
||||||
|
if (thebot->inuse == BOTINUSE_No)
|
||||||
vacant = true;
|
vacant = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -316,10 +269,10 @@ bool FCajunMaster::SpawnBot (const char *name, int color)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
waitingforspawn[playernumber] = true;
|
thebot->inuse = BOTINUSE_Waiting;
|
||||||
|
|
||||||
Net_WriteByte (DEM_ADDBOT);
|
Net_WriteByte (DEM_ADDBOT);
|
||||||
Net_WriteByte (playernumber);
|
Net_WriteByte (botshift);
|
||||||
{
|
{
|
||||||
//Set color.
|
//Set color.
|
||||||
char concat[512];
|
char concat[512];
|
||||||
|
@ -335,52 +288,106 @@ bool FCajunMaster::SpawnBot (const char *name, int color)
|
||||||
}
|
}
|
||||||
Net_WriteString (concat);
|
Net_WriteString (concat);
|
||||||
}
|
}
|
||||||
|
Net_WriteByte(thebot->skill.aiming);
|
||||||
players[playernumber].skill = thebot->skill;
|
Net_WriteByte(thebot->skill.perfection);
|
||||||
|
Net_WriteByte(thebot->skill.reaction);
|
||||||
thebot->inuse = true;
|
Net_WriteByte(thebot->skill.isp);
|
||||||
|
|
||||||
//Increment this.
|
|
||||||
botnum++;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCajunMaster::DoAddBot (int bnum, char *info)
|
void FCajunMaster::TryAddBot (BYTE **stream, int player)
|
||||||
{
|
{
|
||||||
BYTE *infob = (BYTE *)info;
|
int botshift = ReadByte (stream);
|
||||||
D_ReadUserInfoStrings (bnum, &infob, false);
|
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)
|
if (!deathmatch && playerstarts[bnum].type == 0)
|
||||||
{
|
{
|
||||||
Printf ("%s tried to join, but there was no player %d start\n",
|
Printf ("%s tried to join, but there was no player %d start\n",
|
||||||
players[bnum].userinfo.GetName(), bnum+1);
|
players[bnum].userinfo.GetName(), bnum+1);
|
||||||
ClearPlayer (bnum, false); // Make the bot inactive again
|
ClearPlayer (bnum, false); // Make the bot inactive again
|
||||||
if (botnum > 0)
|
return false;
|
||||||
{
|
|
||||||
botnum--;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
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).
|
StatusBar->MultiplayerChanged ();
|
||||||
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 ();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
waitingforspawn[bnum] = false;
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCajunMaster::RemoveAllBots (bool fromlist)
|
void FCajunMaster::RemoveAllBots (bool fromlist)
|
||||||
|
@ -389,13 +396,13 @@ void FCajunMaster::RemoveAllBots (bool fromlist)
|
||||||
|
|
||||||
for (i = 0; i < MAXPLAYERS; ++i)
|
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
|
// If a player is looking through this bot's eyes, make him
|
||||||
// look through his own eyes instead.
|
// look through his own eyes instead.
|
||||||
for (j = 0; j < MAXPLAYERS; ++j)
|
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)
|
if (players[j].camera == players[i].mo)
|
||||||
{
|
{
|
||||||
|
@ -415,34 +422,10 @@ void FCajunMaster::RemoveAllBots (bool fromlist)
|
||||||
if (fromlist)
|
if (fromlist)
|
||||||
{
|
{
|
||||||
wanted_botnum = 0;
|
wanted_botnum = 0;
|
||||||
for (i = 0; i < MAXPLAYERS; i++)
|
|
||||||
waitingforspawn[i] = false;
|
|
||||||
}
|
}
|
||||||
botnum = 0;
|
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
|
//Reads data for bot from
|
||||||
|
|
142
src/b_move.cpp
142
src/b_move.cpp
|
@ -17,20 +17,7 @@
|
||||||
#include "gi.h"
|
#include "gi.h"
|
||||||
#include "a_keys.h"
|
#include "a_keys.h"
|
||||||
#include "d_event.h"
|
#include "d_event.h"
|
||||||
|
#include "p_enemy.h"
|
||||||
enum dirtype_t
|
|
||||||
{
|
|
||||||
DI_EAST,
|
|
||||||
DI_NORTHEAST,
|
|
||||||
DI_NORTH,
|
|
||||||
DI_NORTHWEST,
|
|
||||||
DI_WEST,
|
|
||||||
DI_SOUTHWEST,
|
|
||||||
DI_SOUTH,
|
|
||||||
DI_SOUTHEAST,
|
|
||||||
DI_NODIR,
|
|
||||||
NUMDIRS
|
|
||||||
};
|
|
||||||
|
|
||||||
static FRandom pr_botopendoor ("BotOpenDoor");
|
static FRandom pr_botopendoor ("BotOpenDoor");
|
||||||
static FRandom pr_bottrywalk ("BotTryWalk");
|
static FRandom pr_bottrywalk ("BotTryWalk");
|
||||||
|
@ -39,62 +26,58 @@ static FRandom pr_botnewchasedir ("BotNewChaseDir");
|
||||||
// borrow some tables from p_enemy.cpp
|
// borrow some tables from p_enemy.cpp
|
||||||
extern dirtype_t opposite[9];
|
extern dirtype_t opposite[9];
|
||||||
extern dirtype_t diags[4];
|
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 dest mobj
|
||||||
|
|
||||||
//Called while the bot moves after its player->dest mobj
|
|
||||||
//which can be a weapon/enemy/item whatever.
|
//which can be a weapon/enemy/item whatever.
|
||||||
void FCajunMaster::Roam (AActor *actor, ticcmd_t *cmd)
|
void DBot::Roam (ticcmd_t *cmd)
|
||||||
{
|
{
|
||||||
int delta;
|
int delta;
|
||||||
|
|
||||||
if (Reachable(actor, actor->player->dest))
|
if (Reachable(dest))
|
||||||
{ // Straight towards it.
|
{ // 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);
|
angle &= (angle_t)(7<<29);
|
||||||
delta = actor->player->angle - (actor->movedir << 29);
|
delta = angle - (player->mo->movedir << 29);
|
||||||
|
|
||||||
if (delta > 0)
|
if (delta > 0)
|
||||||
actor->player->angle -= ANG45;
|
angle -= ANG45;
|
||||||
else if (delta < 0)
|
else if (delta < 0)
|
||||||
actor->player->angle += ANG45;
|
angle += ANG45;
|
||||||
}
|
}
|
||||||
|
|
||||||
// chase towards destination.
|
// 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;
|
fixed_t tryx, tryy;
|
||||||
bool try_ok;
|
bool try_ok;
|
||||||
int good;
|
int good;
|
||||||
|
|
||||||
if (actor->movedir == DI_NODIR)
|
if (player->mo->movedir == DI_NODIR)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if ((unsigned)actor->movedir >= 8)
|
if ((unsigned)player->mo->movedir >= 8)
|
||||||
I_Error ("Weird bot movedir!");
|
I_Error ("Weird bot movedir!");
|
||||||
|
|
||||||
tryx = actor->x + 8*xspeed[actor->movedir];
|
tryx = player->mo->x + 8*xspeed[player->mo->movedir];
|
||||||
tryy = actor->y + 8*yspeed[actor->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 (!try_ok) //Anything blocking that could be opened etc..
|
||||||
{
|
{
|
||||||
if (!spechit.Size ())
|
if (!spechit.Size ())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
actor->movedir = DI_NODIR;
|
player->mo->movedir = DI_NODIR;
|
||||||
|
|
||||||
good = 0;
|
good = 0;
|
||||||
line_t *ld;
|
line_t *ld;
|
||||||
|
@ -103,16 +86,16 @@ bool FCajunMaster::Move (AActor *actor, ticcmd_t *cmd)
|
||||||
{
|
{
|
||||||
bool tryit = true;
|
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;
|
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;
|
tryit = false;
|
||||||
|
|
||||||
if (tryit &&
|
if (tryit &&
|
||||||
(P_TestActivateLine (ld, actor, 0, SPAC_Use) ||
|
(P_TestActivateLine (ld, player->mo, 0, SPAC_Use) ||
|
||||||
P_TestActivateLine (ld, actor, 0, SPAC_Push)))
|
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)))
|
if (good && ((pr_botopendoor() >= 203) ^ (good & 1)))
|
||||||
|
@ -130,16 +113,16 @@ bool FCajunMaster::Move (AActor *actor, ticcmd_t *cmd)
|
||||||
return true;
|
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;
|
return false;
|
||||||
|
|
||||||
actor->movecount = pr_bottrywalk() & 60;
|
player->mo->movecount = pr_bottrywalk() & 60;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd)
|
void DBot::NewChaseDir (ticcmd_t *cmd)
|
||||||
{
|
{
|
||||||
fixed_t deltax;
|
fixed_t deltax;
|
||||||
fixed_t deltay;
|
fixed_t deltay;
|
||||||
|
@ -151,7 +134,7 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd)
|
||||||
|
|
||||||
dirtype_t turnaround;
|
dirtype_t turnaround;
|
||||||
|
|
||||||
if (!actor->player->dest)
|
if (!dest)
|
||||||
{
|
{
|
||||||
#ifndef BOT_RELEASE_COMPILE
|
#ifndef BOT_RELEASE_COMPILE
|
||||||
Printf ("Bot tried move without destination\n");
|
Printf ("Bot tried move without destination\n");
|
||||||
|
@ -159,11 +142,11 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
olddir = (dirtype_t)actor->movedir;
|
olddir = (dirtype_t)player->mo->movedir;
|
||||||
turnaround = opposite[olddir];
|
turnaround = opposite[olddir];
|
||||||
|
|
||||||
deltax = actor->player->dest->x - actor->x;
|
deltax = dest->x - player->mo->x;
|
||||||
deltay = actor->player->dest->y - actor->y;
|
deltay = dest->y - player->mo->y;
|
||||||
|
|
||||||
if (deltax > 10*FRACUNIT)
|
if (deltax > 10*FRACUNIT)
|
||||||
d[1] = DI_EAST;
|
d[1] = DI_EAST;
|
||||||
|
@ -182,8 +165,8 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd)
|
||||||
// try direct route
|
// try direct route
|
||||||
if (d[1] != DI_NODIR && d[2] != DI_NODIR)
|
if (d[1] != DI_NODIR && d[2] != DI_NODIR)
|
||||||
{
|
{
|
||||||
actor->movedir = diags[((deltay<0)<<1)+(deltax>0)];
|
player->mo->movedir = diags[((deltay<0)<<1)+(deltax>0)];
|
||||||
if (actor->movedir != turnaround && TryWalk(actor, cmd))
|
if (player->mo->movedir != turnaround && TryWalk(cmd))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,16 +186,16 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd)
|
||||||
|
|
||||||
if (d[1]!=DI_NODIR)
|
if (d[1]!=DI_NODIR)
|
||||||
{
|
{
|
||||||
actor->movedir = d[1];
|
player->mo->movedir = d[1];
|
||||||
if (TryWalk (actor, cmd))
|
if (TryWalk (cmd))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (d[2]!=DI_NODIR)
|
if (d[2]!=DI_NODIR)
|
||||||
{
|
{
|
||||||
actor->movedir = d[2];
|
player->mo->movedir = d[2];
|
||||||
|
|
||||||
if (TryWalk(actor, cmd))
|
if (TryWalk(cmd))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,9 +203,9 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd)
|
||||||
// so pick another direction.
|
// so pick another direction.
|
||||||
if (olddir!=DI_NODIR)
|
if (olddir!=DI_NODIR)
|
||||||
{
|
{
|
||||||
actor->movedir = olddir;
|
player->mo->movedir = olddir;
|
||||||
|
|
||||||
if (TryWalk(actor, cmd))
|
if (TryWalk(cmd))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,9 +218,9 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd)
|
||||||
{
|
{
|
||||||
if (tdir!=turnaround)
|
if (tdir!=turnaround)
|
||||||
{
|
{
|
||||||
actor->movedir = tdir;
|
player->mo->movedir = tdir;
|
||||||
|
|
||||||
if (TryWalk(actor, cmd))
|
if (TryWalk(cmd))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -250,9 +233,9 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd)
|
||||||
{
|
{
|
||||||
if (tdir!=turnaround)
|
if (tdir!=turnaround)
|
||||||
{
|
{
|
||||||
actor->movedir = tdir;
|
player->mo->movedir = tdir;
|
||||||
|
|
||||||
if (TryWalk(actor, cmd))
|
if (TryWalk(cmd))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -260,12 +243,12 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd)
|
||||||
|
|
||||||
if (turnaround != DI_NODIR)
|
if (turnaround != DI_NODIR)
|
||||||
{
|
{
|
||||||
actor->movedir = turnaround;
|
player->mo->movedir = turnaround;
|
||||||
if (TryWalk(actor, cmd))
|
if (TryWalk(cmd))
|
||||||
return;
|
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 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.
|
#define TURNSENS 3 //Higher is smoother but slower turn.
|
||||||
|
|
||||||
void FCajunMaster::TurnToAng (AActor *actor)
|
void DBot::TurnToAng ()
|
||||||
{
|
{
|
||||||
int maxturn = MAXTURN;
|
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.
|
{ //Keep angle that where when shot where decided.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(actor->player->enemy)
|
if(enemy)
|
||||||
if(!actor->player->dest) //happens when running after item in combat situations, or normal, prevents weak turns
|
if(!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(player->ReadyWeapon->ProjectileType == NULL && !(player->ReadyWeapon->WeaponFlags & WIF_MELEEWEAPON))
|
||||||
if(Check_LOS(actor, actor->player->enemy, SHOOTFOV+5*ANGLE_1))
|
if(Check_LOS(enemy, SHOOTFOV+5*ANGLE_1))
|
||||||
maxturn = 3;
|
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;
|
return;
|
||||||
|
|
||||||
distance /= TURNSENS;
|
distance /= TURNSENS;
|
||||||
if (abs (distance) > maxturn)
|
if (abs (distance) > maxturn)
|
||||||
distance = distance < 0 ? -maxturn : 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 aim;
|
||||||
double diff;
|
double diff;
|
||||||
|
|
||||||
diff = target->z - actor->z;
|
diff = target->z - player->mo->z;
|
||||||
aim = atan (diff / (double)P_AproxDistance (actor->x - target->x, actor->y - target->y));
|
aim = atan (diff / (double)P_AproxDistance (player->mo->x - target->x, player->mo->y - target->y));
|
||||||
actor->pitch = -(int)(aim * ANGLE_180/M_PI);
|
player->mo->pitch = -(int)(aim * ANGLE_180/M_PI);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Checks if a sector is dangerous.
|
//Checks if a sector is dangerous.
|
||||||
|
@ -388,4 +371,3 @@ bool FCajunMaster::IsDangerous (sector_t *sec)
|
||||||
|| special == Damage_InstantDeath
|
|| special == Damage_InstantDeath
|
||||||
|| special == sDamage_SuperHellslime;
|
|| 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,
|
//This function is called each tic for each bot,
|
||||||
//so this is what the bot does.
|
//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));
|
memset (cmd, 0, sizeof(*cmd));
|
||||||
|
|
||||||
if (actor->player->enemy && actor->player->enemy->health <= 0)
|
if (enemy && enemy->health <= 0)
|
||||||
actor->player->enemy = NULL;
|
enemy = NULL;
|
||||||
|
|
||||||
if (actor->health > 0) //Still alive
|
if (player->mo->health > 0) //Still alive
|
||||||
{
|
{
|
||||||
if (teamplay || !deathmatch)
|
if (teamplay || !deathmatch)
|
||||||
actor->player->mate = Choose_Mate (actor);
|
mate = Choose_Mate ();
|
||||||
|
|
||||||
angle_t oldyaw = actor->angle;
|
angle_t oldyaw = player->mo->angle;
|
||||||
int oldpitch = actor->pitch;
|
int oldpitch = player->mo->pitch;
|
||||||
|
|
||||||
Set_enemy (actor);
|
Set_enemy ();
|
||||||
ThinkForMove (actor, cmd);
|
ThinkForMove (cmd);
|
||||||
TurnToAng (actor);
|
TurnToAng ();
|
||||||
|
|
||||||
cmd->ucmd.yaw = (short)((actor->angle - oldyaw) >> 16) / ticdup;
|
cmd->ucmd.yaw = (short)((player->mo->angle - oldyaw) >> 16) / ticdup;
|
||||||
cmd->ucmd.pitch = (short)((oldpitch - actor->pitch) >> 16);
|
cmd->ucmd.pitch = (short)((oldpitch - player->mo->pitch) >> 16);
|
||||||
if (cmd->ucmd.pitch == -32768)
|
if (cmd->ucmd.pitch == -32768)
|
||||||
cmd->ucmd.pitch = -32767;
|
cmd->ucmd.pitch = -32767;
|
||||||
cmd->ucmd.pitch /= ticdup;
|
cmd->ucmd.pitch /= ticdup;
|
||||||
actor->angle = oldyaw + (cmd->ucmd.yaw << 16) * ticdup;
|
player->mo->angle = oldyaw + (cmd->ucmd.yaw << 16) * ticdup;
|
||||||
actor->pitch = oldpitch - (cmd->ucmd.pitch << 16) * ticdup;
|
player->mo->pitch = oldpitch - (cmd->ucmd.pitch << 16) * ticdup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actor->player->t_active) actor->player->t_active--;
|
if (t_active) t_active--;
|
||||||
if (actor->player->t_strafe) actor->player->t_strafe--;
|
if (t_strafe) t_strafe--;
|
||||||
if (actor->player->t_react) actor->player->t_react--;
|
if (t_react) t_react--;
|
||||||
if (actor->player->t_fight) actor->player->t_fight--;
|
if (t_fight) t_fight--;
|
||||||
if (actor->player->t_rocket) actor->player->t_rocket--;
|
if (t_rocket) t_rocket--;
|
||||||
if (actor->player->t_roam) actor->player->t_roam--;
|
if (t_roam) t_roam--;
|
||||||
|
|
||||||
//Respawn ticker
|
//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
|
{ // Time to respawn
|
||||||
cmd->ucmd.buttons |= BT_USE;
|
cmd->ucmd.buttons |= BT_USE;
|
||||||
}
|
}
|
||||||
|
@ -72,62 +74,57 @@ void FCajunMaster::Think (AActor *actor, ticcmd_t *cmd)
|
||||||
|
|
||||||
//how the bot moves.
|
//how the bot moves.
|
||||||
//MAIN movement function.
|
//MAIN movement function.
|
||||||
void FCajunMaster::ThinkForMove (AActor *actor, ticcmd_t *cmd)
|
void DBot::ThinkForMove (ticcmd_t *cmd)
|
||||||
{
|
{
|
||||||
player_t *b;
|
|
||||||
fixed_t dist;
|
fixed_t dist;
|
||||||
bool stuck;
|
bool stuck;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
b = actor->player;
|
|
||||||
if (!b->isbot)
|
|
||||||
return;
|
|
||||||
|
|
||||||
stuck = false;
|
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 &&
|
if (missile &&
|
||||||
((!b->missile->velx || !b->missile->vely) || !Check_LOS(actor, b->missile, SHOOTFOV*3/2)))
|
((!missile->velx || !missile->vely) || !Check_LOS(missile, SHOOTFOV*3/2)))
|
||||||
{
|
{
|
||||||
b->sleft = !b->sleft;
|
sleft = !sleft;
|
||||||
b->missile = NULL; //Probably ended its travel.
|
missile = NULL; //Probably ended its travel.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actor->pitch > 0)
|
if (player->mo->pitch > 0)
|
||||||
actor->pitch -= 80;
|
player->mo->pitch -= 80;
|
||||||
else if (actor->pitch <= -60)
|
else if (player->mo->pitch <= -60)
|
||||||
actor->pitch += 80;
|
player->mo->pitch += 80;
|
||||||
|
|
||||||
//HOW TO MOVE:
|
//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);
|
Pitch (missile);
|
||||||
actor->player->angle = R_PointToAngle2(actor->x, actor->y, b->missile->x, b->missile->y);
|
angle = R_PointToAngle2(player->mo->x, player->mo->y, missile->x, missile->y);
|
||||||
cmd->ucmd.sidemove = b->sleft ? -SIDERUN : SIDERUN;
|
cmd->ucmd.sidemove = sleft ? -SIDERUN : SIDERUN;
|
||||||
cmd->ucmd.forwardmove = -FORWARDRUN; //Back IS best.
|
cmd->ucmd.forwardmove = -FORWARDRUN; //Back IS best.
|
||||||
|
|
||||||
if ((P_AproxDistance(actor->x-b->oldx, actor->y-b->oldy)<50000)
|
if ((P_AproxDistance(player->mo->x-oldx, player->mo->y-oldy)<50000)
|
||||||
&& b->t_strafe<=0)
|
&& t_strafe<=0)
|
||||||
{
|
{
|
||||||
b->t_strafe = 5;
|
t_strafe = 5;
|
||||||
b->sleft = !b->sleft;
|
sleft = !sleft;
|
||||||
}
|
}
|
||||||
|
|
||||||
//If able to see enemy while avoiding missile, still fire at enemy.
|
//If able to see enemy while avoiding missile, still fire at enemy.
|
||||||
if (b->enemy && Check_LOS (actor, b->enemy, SHOOTFOV))
|
if (enemy && Check_LOS (enemy, SHOOTFOV))
|
||||||
Dofire (actor, cmd); //Order bot to fire current weapon
|
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.
|
//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 (
|
if (
|
||||||
(
|
(
|
||||||
(actor->health < b->skill.isp &&
|
(player->mo->health < skill.isp &&
|
||||||
(is (Medikit) ||
|
(is (Medikit) ||
|
||||||
is (Stimpack) ||
|
is (Stimpack) ||
|
||||||
is (Soulsphere) ||
|
is (Soulsphere) ||
|
||||||
|
@ -140,78 +137,78 @@ void FCajunMaster::ThinkForMove (AActor *actor, ticcmd_t *cmd)
|
||||||
is (Megasphere)
|
is (Megasphere)
|
||||||
) ||
|
) ||
|
||||||
dist < (GETINCOMBAT/4) ||
|
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))
|
&& (dist < GETINCOMBAT || (player->ReadyWeapon == NULL || player->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON))
|
||||||
&& Reachable (actor, b->dest))
|
&& Reachable (dest))
|
||||||
#undef is
|
#undef is
|
||||||
{
|
{
|
||||||
goto roam; //Pick it up, no matter the situation. All bonuses are nice close up.
|
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))
|
if (player->ReadyWeapon != NULL && !(player->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON))
|
||||||
actor->flags &= ~MF_DROPOFF; //Don't jump off any ledges when fighting.
|
player->mo->flags &= ~MF_DROPOFF; //Don't jump off any ledges when fighting.
|
||||||
|
|
||||||
if (!(b->enemy->flags3 & MF3_ISMONSTER))
|
if (!(enemy->flags3 & MF3_ISMONSTER))
|
||||||
b->t_fight = AFTERTICS;
|
t_fight = AFTERTICS;
|
||||||
|
|
||||||
if (b->t_strafe <= 0 &&
|
if (t_strafe <= 0 &&
|
||||||
(P_AproxDistance(actor->x-b->oldx, actor->y-b->oldy)<50000
|
(P_AproxDistance(player->mo->x-oldx, player->mo->y-oldy)<50000
|
||||||
|| ((pr_botmove()%30)==10))
|
|| ((pr_botmove()%30)==10))
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
stuck = true;
|
stuck = true;
|
||||||
b->t_strafe = 5;
|
t_strafe = 5;
|
||||||
b->sleft = !b->sleft;
|
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 ||
|
if (player->ReadyWeapon == NULL ||
|
||||||
P_AproxDistance(actor->x-b->enemy->x, actor->y-b->enemy->y) >
|
P_AproxDistance(player->mo->x-enemy->x, player->mo->y-enemy->y) >
|
||||||
b->ReadyWeapon->MoveCombatDist)
|
player->ReadyWeapon->MoveCombatDist)
|
||||||
{
|
{
|
||||||
// If a monster, use lower speed (just for cooler apperance while strafing down doomed monster)
|
// 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.
|
else if (!stuck) //Too close, so move away.
|
||||||
{
|
{
|
||||||
// If a monster, use lower speed (just for cooler apperance while strafing down doomed monster)
|
// 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.
|
//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
|
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;
|
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
|
{ // [RH] If the mate is the dest, pick a new dest sometimes
|
||||||
b->dest = NULL;
|
dest = NULL;
|
||||||
}
|
}
|
||||||
goto roam;
|
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))
|
if (matedist > (FRIEND_DIST*2))
|
||||||
cmd->ucmd.forwardmove = FORWARDRUN;
|
cmd->ucmd.forwardmove = FORWARDRUN;
|
||||||
else if (matedist > FRIEND_DIST)
|
else if (matedist > FRIEND_DIST)
|
||||||
|
@ -221,42 +218,42 @@ void FCajunMaster::ThinkForMove (AActor *actor, ticcmd_t *cmd)
|
||||||
}
|
}
|
||||||
else //Roam after something.
|
else //Roam after something.
|
||||||
{
|
{
|
||||||
b->first_shot = true;
|
first_shot = true;
|
||||||
|
|
||||||
/////
|
/////
|
||||||
roam:
|
roam:
|
||||||
/////
|
/////
|
||||||
if (b->enemy && Check_LOS (actor, b->enemy, SHOOTFOV*3/2)) //If able to see enemy while avoiding missile , still fire at it.
|
if (enemy && Check_LOS (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
|
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.
|
{ //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) ||
|
if (((enemy->player->ReadyWeapon != NULL && enemy->player->ReadyWeapon->WeaponFlags & WIF_BOT_EXPLOSIVE) ||
|
||||||
(pr_botmove()%100)>b->skill.isp) && b->ReadyWeapon != NULL && !(b->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON))
|
(pr_botmove()%100)>skill.isp) && player->ReadyWeapon != NULL && !(player->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON))
|
||||||
b->dest = b->enemy;//Dont let enemy kill the bot by supressive fire. So charge enemy.
|
dest = enemy;//Dont let enemy kill the bot by supressive fire. So charge enemy.
|
||||||
else //hide while b->t_fight, but keep view at enemy.
|
else //hide while t_fight, but keep view at enemy.
|
||||||
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);
|
||||||
} //Just a monster, so kill it.
|
} //Just a monster, so kill it.
|
||||||
else
|
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.
|
else //Choose a distant target. to get things going.
|
||||||
{
|
{
|
||||||
r = pr_botmove();
|
r = pr_botmove();
|
||||||
if (r < 128)
|
if (r < 128)
|
||||||
{
|
{
|
||||||
TThinkerIterator<AInventory> it (STAT_INVENTORY, firstthing);
|
TThinkerIterator<AInventory> it (STAT_INVENTORY, bglobal.firstthing);
|
||||||
AInventory *item = it.Next();
|
AInventory *item = it.Next();
|
||||||
|
|
||||||
if (item != NULL || (item = it.Next()) != NULL)
|
if (item != NULL || (item = it.Next()) != NULL)
|
||||||
|
@ -271,60 +268,53 @@ void FCajunMaster::ThinkForMove (AActor *actor, ticcmd_t *cmd)
|
||||||
{
|
{
|
||||||
item = it.Next();
|
item = it.Next();
|
||||||
}
|
}
|
||||||
firstthing = item;
|
bglobal.firstthing = item;
|
||||||
b->dest = 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)
|
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.
|
{ //Bot has a target so roam after it.
|
||||||
Roam (actor, cmd);
|
Roam (cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
} //End of movement main part.
|
} //End of movement main part.
|
||||||
|
|
||||||
if (!b->t_roam && b->dest)
|
if (!t_roam && dest)
|
||||||
{
|
{
|
||||||
b->prev = b->dest;
|
prev = dest;
|
||||||
b->dest = NULL;
|
dest = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (b->t_fight<(AFTERTICS/2))
|
if (t_fight<(AFTERTICS/2))
|
||||||
actor->flags |= MF_DROPOFF;
|
player->mo->flags |= MF_DROPOFF;
|
||||||
|
|
||||||
b->oldx = actor->x;
|
oldx = player->mo->x;
|
||||||
b->oldy = actor->y;
|
oldy = player->mo->y;
|
||||||
}
|
}
|
||||||
|
|
||||||
//BOT_WhatToGet
|
//BOT_WhatToGet
|
||||||
//
|
//
|
||||||
//Determines if the bot will roam after an item or not.
|
//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))
|
#define typeis(x) item->IsKindOf (PClass::FindClass (#x))
|
||||||
if ((item->renderflags & RF_INVISIBLE) //Under respawn and away.
|
if ((item->renderflags & RF_INVISIBLE) //Under respawn and away.
|
||||||
|| item == b->prev)
|
|| item == prev)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -338,7 +328,7 @@ void FCajunMaster::WhatToGet (AActor *actor, AActor *item)
|
||||||
// FIXME
|
// FIXME
|
||||||
AWeapon *heldWeapon;
|
AWeapon *heldWeapon;
|
||||||
|
|
||||||
heldWeapon = static_cast<AWeapon *> (b->mo->FindInventory (item->GetClass()));
|
heldWeapon = dyn_cast<AWeapon>(player->mo->FindInventory(item->GetClass()));
|
||||||
if (heldWeapon != NULL)
|
if (heldWeapon != NULL)
|
||||||
{
|
{
|
||||||
if (!weapgiveammo)
|
if (!weapgiveammo)
|
||||||
|
@ -354,39 +344,38 @@ void FCajunMaster::WhatToGet (AActor *actor, AActor *item)
|
||||||
{
|
{
|
||||||
AAmmo *ammo = static_cast<AAmmo *> (item);
|
AAmmo *ammo = static_cast<AAmmo *> (item);
|
||||||
PClassActor *parent = ammo->GetParentAmmo ();
|
PClassActor *parent = ammo->GetParentAmmo ();
|
||||||
AInventory *holdingammo = b->mo->FindInventory (parent);
|
AInventory *holdingammo = player->mo->FindInventory (parent);
|
||||||
|
|
||||||
if (holdingammo != NULL && holdingammo->Amount >= holdingammo->MaxAmount)
|
if (holdingammo != NULL && holdingammo->Amount >= holdingammo->MaxAmount)
|
||||||
{
|
{
|
||||||
return;
|
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;
|
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;
|
return;
|
||||||
|
|
||||||
if ((b->dest == NULL ||
|
if ((dest == NULL ||
|
||||||
!(b->dest->flags & MF_SPECIAL)/* ||
|
!(dest->flags & MF_SPECIAL)/* ||
|
||||||
!Reachable (actor, b->dest)*/)/* &&
|
!Reachable (dest)*/)/* &&
|
||||||
Reachable (actor, item)*/) // Calling Reachable slows this down tremendously
|
Reachable (item)*/) // Calling Reachable slows this down tremendously
|
||||||
{
|
{
|
||||||
b->prev = b->dest;
|
prev = dest;
|
||||||
b->dest = item;
|
dest = item;
|
||||||
b->t_roam = MAXROAM;
|
t_roam = MAXROAM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCajunMaster::Set_enemy (AActor *actor)
|
void DBot::Set_enemy ()
|
||||||
{
|
{
|
||||||
AActor *oldenemy;
|
AActor *oldenemy;
|
||||||
AActor **enemy = &actor->player->enemy;
|
|
||||||
|
|
||||||
if (*enemy
|
if (enemy
|
||||||
&& (*enemy)->health > 0
|
&& enemy->health > 0
|
||||||
&& P_CheckSight (actor, *enemy))
|
&& P_CheckSight (player->mo, enemy))
|
||||||
{
|
{
|
||||||
oldenemy = *enemy;
|
oldenemy = enemy;
|
||||||
}
|
}
|
||||||
else
|
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
|
// [RH] Don't even bother looking for a different enemy if this is not deathmatch
|
||||||
// and we already have an existing enemy.
|
// and we already have an existing enemy.
|
||||||
if (deathmatch || !*enemy)
|
if (deathmatch || !enemy)
|
||||||
{
|
{
|
||||||
actor->player->allround = !!*enemy;
|
allround = !!enemy;
|
||||||
*enemy = NULL;
|
enemy = Find_enemy();
|
||||||
*enemy = Find_enemy(actor);
|
if (!enemy)
|
||||||
if (!*enemy)
|
enemy = oldenemy; //Try go for last (it will be NULL if there wasn't anyone)
|
||||||
*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.
|
//Verify that that enemy is really something alive that bot can kill.
|
||||||
if (*enemy && (((*enemy)->health < 0 || !((*enemy)->flags&MF_SHOOTABLE)) || actor->IsFriend(*enemy)))
|
if (enemy && ((enemy->health < 0 || !(enemy->flags&MF_SHOOTABLE)) || player->mo->IsFriend(enemy)))
|
||||||
*enemy = NULL;
|
enemy = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -230,7 +230,11 @@ const char *KeyNames[NUM_KEYS] =
|
||||||
NULL, NULL, NULL, NULL, NULL, "pause", NULL, "home", //C0
|
NULL, NULL, NULL, NULL, NULL, "pause", NULL, "home", //C0
|
||||||
"uparrow", "pgup", NULL, "leftarrow",NULL, "rightarrow",NULL, "end", //C8
|
"uparrow", "pgup", NULL, "leftarrow",NULL, "rightarrow",NULL, "end", //C8
|
||||||
"downarrow","pgdn", "ins", "del", NULL, NULL, NULL, NULL, //D0
|
"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
|
NULL, NULL, NULL, "lwin", "rwin", "apps", "power", "sleep", //D8
|
||||||
|
#endif // __APPLE__
|
||||||
NULL, NULL, NULL, "wake", NULL, "search", "favorites","refresh", //E0
|
NULL, NULL, NULL, "wake", NULL, "search", "favorites","refresh", //E0
|
||||||
"webstop", "webforward","webback", "mycomputer","mail", "mediaselect",NULL, NULL, //E8
|
"webstop", "webforward","webback", "mycomputer","mail", "mediaselect",NULL, NULL, //E8
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, //F0
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, //F0
|
||||||
|
|
|
@ -122,6 +122,15 @@ CCMD (god)
|
||||||
Net_WriteByte (CHT_GOD);
|
Net_WriteByte (CHT_GOD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CCMD(god2)
|
||||||
|
{
|
||||||
|
if (CheckCheatmode())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Net_WriteByte(DEM_GENERICCHEAT);
|
||||||
|
Net_WriteByte(CHT_GOD2);
|
||||||
|
}
|
||||||
|
|
||||||
CCMD (iddqd)
|
CCMD (iddqd)
|
||||||
{
|
{
|
||||||
if (CheckCheatmode ())
|
if (CheckCheatmode ())
|
||||||
|
@ -140,6 +149,15 @@ CCMD (buddha)
|
||||||
Net_WriteByte(CHT_BUDDHA);
|
Net_WriteByte(CHT_BUDDHA);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CCMD(buddha2)
|
||||||
|
{
|
||||||
|
if (CheckCheatmode())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Net_WriteByte(DEM_GENERICCHEAT);
|
||||||
|
Net_WriteByte(CHT_BUDDHA2);
|
||||||
|
}
|
||||||
|
|
||||||
CCMD (notarget)
|
CCMD (notarget)
|
||||||
{
|
{
|
||||||
if (CheckCheatmode ())
|
if (CheckCheatmode ())
|
||||||
|
|
|
@ -561,6 +561,11 @@ int PrintString (int printlevel, const char *outline)
|
||||||
maybedrawnow (false, false);
|
maybedrawnow (false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (Logfile != NULL)
|
||||||
|
{
|
||||||
|
fputs (outline, Logfile);
|
||||||
|
fflush (Logfile);
|
||||||
|
}
|
||||||
return (int)strlen (outline);
|
return (int)strlen (outline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1421,7 +1426,11 @@ static bool C_HandleKey (event_t *ev, BYTE *buffer, int len)
|
||||||
case 'V':
|
case 'V':
|
||||||
TabbedLast = false;
|
TabbedLast = false;
|
||||||
TabbedList = false;
|
TabbedList = false;
|
||||||
|
#ifdef __APPLE__
|
||||||
|
if (ev->data3 & GKM_META)
|
||||||
|
#else // !__APPLE__
|
||||||
if (ev->data3 & GKM_CTRL)
|
if (ev->data3 & GKM_CTRL)
|
||||||
|
#endif // __APPLE__
|
||||||
{
|
{
|
||||||
if (data1 == 'C')
|
if (data1 == 'C')
|
||||||
{ // copy to clipboard
|
{ // copy to clipboard
|
||||||
|
@ -1545,13 +1554,6 @@ void C_MidPrint (FFont *font, const char *msg)
|
||||||
AddToConsole (-1, bar1);
|
AddToConsole (-1, bar1);
|
||||||
AddToConsole (-1, msg);
|
AddToConsole (-1, msg);
|
||||||
AddToConsole (-1, bar3);
|
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,
|
StatusBar->AttachMessage (new DHUDMessage (font, msg, 1.5f, 0.375f, 0, 0,
|
||||||
(EColorRange)PrintColors[PRINTLEVELS], con_midtime), MAKE_ID('C','N','T','R'));
|
(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, bar2);
|
||||||
AddToConsole (-1, msg);
|
AddToConsole (-1, msg);
|
||||||
AddToConsole (-1, bar3);
|
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,
|
StatusBar->AttachMessage (new DHUDMessage (font, msg, 1.5f, 0.375f, 0, 0,
|
||||||
(EColorRange)PrintColors[PRINTLEVELS+1], con_midtime), MAKE_ID('C','N','T','R'));
|
(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;
|
goodv = false;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (value[i] < '0' && value[i] > '9' &&
|
if (value[i] < '0' ||
|
||||||
value[i] < 'A' && value[i] > 'F' &&
|
(value[i] > '9' && value[i] < 'A') ||
|
||||||
value[i] < 'a' && value[i] > 'f')
|
(value[i] > 'F' && value[i] < 'a') ||
|
||||||
|
value[i] > 'f')
|
||||||
{
|
{
|
||||||
goodv = false;
|
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)
|
void C_SetCVarsToDefaults (void)
|
||||||
{
|
{
|
||||||
FBaseCVar *cvar = CVars;
|
FBaseCVar *cvar = CVars;
|
||||||
|
|
|
@ -159,6 +159,7 @@ private:
|
||||||
friend FBaseCVar *FindCVar (const char *var_name, FBaseCVar **prev);
|
friend FBaseCVar *FindCVar (const char *var_name, FBaseCVar **prev);
|
||||||
friend FBaseCVar *FindCVarSub (const char *var_name, int namelen);
|
friend FBaseCVar *FindCVarSub (const char *var_name, int namelen);
|
||||||
friend void UnlatchCVars (void);
|
friend void UnlatchCVars (void);
|
||||||
|
friend void DestroyCVarsFlagged (DWORD flags);
|
||||||
friend void C_ArchiveCVars (FConfigFile *f, uint32 filter);
|
friend void C_ArchiveCVars (FConfigFile *f, uint32 filter);
|
||||||
friend void C_SetCVarsToDefaults (void);
|
friend void C_SetCVarsToDefaults (void);
|
||||||
friend void FilterCompactCVars (TArray<FBaseCVar *> &cvars, uint32 filter);
|
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()
|
// Called from G_InitNew()
|
||||||
void UnlatchCVars (void);
|
void UnlatchCVars (void);
|
||||||
|
|
||||||
|
// Destroy CVars with the matching flags; called from CCMD(restart)
|
||||||
|
void DestroyCVarsFlagged (DWORD flags);
|
||||||
|
|
||||||
// archive cvars to FILE f
|
// archive cvars to FILE f
|
||||||
void C_ArchiveCVars (FConfigFile *f, uint32 filter);
|
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
|
// Note that deferred commands lose track of which key
|
||||||
// (if any) they were pressed from.
|
// (if any) they were pressed from.
|
||||||
*brkpt = ';';
|
*brkpt = ';';
|
||||||
new DWaitingCommand (brkpt, tics+1);
|
new DWaitingCommand (brkpt, tics);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
23
src/cmdlib.h
23
src/cmdlib.h
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
|
|
||||||
#include "doomtype.h"
|
#include "doomtype.h"
|
||||||
|
#include "doomdef.h"
|
||||||
|
#include "m_fixed.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -62,4 +64,25 @@ struct FFileList
|
||||||
|
|
||||||
void ScanDirectory(TArray<FFileList> &list, const char *dirpath);
|
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
|
#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_SECTORFLOOROFFSET,
|
||||||
CP_SETWALLYSCALE,
|
CP_SETWALLYSCALE,
|
||||||
CP_SETTHINGZ,
|
CP_SETTHINGZ,
|
||||||
|
CP_SETTAG,
|
||||||
|
CP_SETTHINGFLAGS,
|
||||||
};
|
};
|
||||||
|
|
||||||
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
||||||
|
@ -140,6 +142,7 @@ static FCompatOption Options[] =
|
||||||
{ "maskedmidtex", COMPATF_MASKEDMIDTEX, SLOT_COMPAT },
|
{ "maskedmidtex", COMPATF_MASKEDMIDTEX, SLOT_COMPAT },
|
||||||
{ "badangles", COMPATF2_BADANGLES, SLOT_COMPAT2 },
|
{ "badangles", COMPATF2_BADANGLES, SLOT_COMPAT2 },
|
||||||
{ "floormove", COMPATF2_FLOORMOVE, SLOT_COMPAT2 },
|
{ "floormove", COMPATF2_FLOORMOVE, SLOT_COMPAT2 },
|
||||||
|
{ "soundcutoff", COMPATF2_SOUNDCUTOFF, SLOT_COMPAT2 },
|
||||||
|
|
||||||
{ NULL, 0, 0 }
|
{ NULL, 0, 0 }
|
||||||
};
|
};
|
||||||
|
@ -307,6 +310,24 @@ void ParseCompatibility()
|
||||||
sc.MustGetFloat();
|
sc.MustGetFloat();
|
||||||
CompatParams.Push(FLOAT2FIXED(sc.Float));
|
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
|
else
|
||||||
{
|
{
|
||||||
sc.UnGet();
|
sc.UnGet();
|
||||||
|
@ -520,6 +541,24 @@ void SetCompatibilityParams()
|
||||||
i += 3;
|
i += 3;
|
||||||
break;
|
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 ();
|
CT_BackSpace ();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#ifdef __APPLE__
|
||||||
|
else if (ev->data1 == 'C' && (ev->data3 & GKM_META))
|
||||||
|
#else // !__APPLE__
|
||||||
else if (ev->data1 == 'C' && (ev->data3 & GKM_CTRL))
|
else if (ev->data1 == 'C' && (ev->data3 & GKM_CTRL))
|
||||||
|
#endif // __APPLE__
|
||||||
{
|
{
|
||||||
I_PutInClipboard ((char *)ChatQueue);
|
I_PutInClipboard ((char *)ChatQueue);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#ifdef __APPLE__
|
||||||
|
else if (ev->data1 == 'V' && (ev->data3 & GKM_META))
|
||||||
|
#else // !__APPLE__
|
||||||
else if (ev->data1 == 'V' && (ev->data3 & GKM_CTRL))
|
else if (ev->data1 == 'V' && (ev->data3 & GKM_CTRL))
|
||||||
|
#endif // __APPLE__
|
||||||
{
|
{
|
||||||
CT_PasteChat(I_GetFromClipboard(false));
|
CT_PasteChat(I_GetFromClipboard(false));
|
||||||
}
|
}
|
||||||
|
@ -273,7 +281,8 @@ void CT_Drawer (void)
|
||||||
|
|
||||||
if (players[consoleplayer].camera != NULL &&
|
if (players[consoleplayer].camera != NULL &&
|
||||||
(Button_ShowScores.bDown ||
|
(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.
|
// Don't draw during intermission, since it has its own scoreboard in wi_stuff.cpp.
|
||||||
gamestate != GS_INTERMISSION)
|
gamestate != GS_INTERMISSION)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2208,6 +2208,13 @@ static int PatchText (int oldSize)
|
||||||
{
|
{
|
||||||
strncpy (deh.PlayerSprite, newStr, 4);
|
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
|
// If this sprite is used by a pickup, then the DehackedPickup sprite map
|
||||||
// needs to be updated too.
|
// needs to be updated too.
|
||||||
for (i = 0; (size_t)i < countof(DehSpriteMappings); ++i)
|
for (i = 0; (size_t)i < countof(DehSpriteMappings); ++i)
|
||||||
|
@ -2294,7 +2301,10 @@ static int PatchStrings (int dummy)
|
||||||
|
|
||||||
ReplaceSpecialChars (holdstring.LockBuffer());
|
ReplaceSpecialChars (holdstring.LockBuffer());
|
||||||
holdstring.UnlockBuffer();
|
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());
|
DPrintf ("%s set to:\n%s\n", Line1, holdstring.GetChars());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,7 @@ typedef enum
|
||||||
ga_loadlevel,
|
ga_loadlevel,
|
||||||
ga_newgame,
|
ga_newgame,
|
||||||
ga_newgame2,
|
ga_newgame2,
|
||||||
|
ga_recordgame,
|
||||||
ga_loadgame,
|
ga_loadgame,
|
||||||
ga_loadgamehidecon,
|
ga_loadgamehidecon,
|
||||||
ga_loadgameplaydemo,
|
ga_loadgameplaydemo,
|
||||||
|
|
|
@ -70,7 +70,8 @@ enum GUIKeyModifiers
|
||||||
GKM_SHIFT = 1,
|
GKM_SHIFT = 1,
|
||||||
GKM_CTRL = 2,
|
GKM_CTRL = 2,
|
||||||
GKM_ALT = 4,
|
GKM_ALT = 4,
|
||||||
GKM_LBUTTON = 8
|
GKM_META = 8,
|
||||||
|
GKM_LBUTTON = 16
|
||||||
};
|
};
|
||||||
|
|
||||||
// Special codes for some GUI keys, including a few real ASCII codes.
|
// 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
|
TArray<FString> steam_path = I_GetSteamPath();
|
||||||
FString steam_path = I_GetSteamPath();
|
for (i = 0; i < steam_path.Size(); ++i)
|
||||||
if (steam_path.IsNotEmpty())
|
|
||||||
{
|
{
|
||||||
static const char *const steam_dirs[] =
|
CheckIWAD (steam_path[i], &wads[0]);
|
||||||
{
|
|
||||||
"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]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iwadparm != NULL && !wads[0].Path.IsEmpty())
|
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.
|
// 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.
|
// Take us out of chasecam mode only.
|
||||||
if (p->cheats & CF_CHASECAM)
|
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_maskedmidtex, compatflags, COMPATF_MASKEDMIDTEX);
|
||||||
CVAR (Flag, compat_badangles, compatflags2, COMPATF2_BADANGLES);
|
CVAR (Flag, compat_badangles, compatflags2, COMPATF2_BADANGLES);
|
||||||
CVAR (Flag, compat_floormove, compatflags2, COMPATF2_FLOORMOVE);
|
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,
|
screen->SetBlendingRect(viewwindowx, viewwindowy,
|
||||||
viewwindowx + viewwidth, viewwindowy + viewheight);
|
viewwindowx + viewwidth, viewwindowy + viewheight);
|
||||||
P_PredictPlayer(&players[consoleplayer]);
|
|
||||||
Renderer->RenderView(&players[consoleplayer]);
|
Renderer->RenderView(&players[consoleplayer]);
|
||||||
P_UnPredictPlayer();
|
|
||||||
if ((hw2d = screen->Begin2D(viewactive)))
|
if ((hw2d = screen->Begin2D(viewactive)))
|
||||||
{
|
{
|
||||||
// Redraw everything every frame when using 2D accel
|
// Redraw everything every frame when using 2D accel
|
||||||
|
@ -832,15 +833,23 @@ void D_Display ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// draw pause pic
|
// draw pause pic
|
||||||
if (paused && menuactive == MENU_Off)
|
if ((paused || pauseext) && menuactive == MENU_Off)
|
||||||
{
|
{
|
||||||
FTexture *tex;
|
FTexture *tex;
|
||||||
int x;
|
int x;
|
||||||
|
FString pstring = "By ";
|
||||||
|
|
||||||
tex = TexMan(gameinfo.PauseSign);
|
tex = TexMan(gameinfo.PauseSign);
|
||||||
x = (SCREENWIDTH - tex->GetScaledWidth() * CleanXfac)/2 +
|
x = (SCREENWIDTH - tex->GetScaledWidth() * CleanXfac)/2 +
|
||||||
tex->GetScaledLeftOffset() * CleanXfac;
|
tex->GetScaledLeftOffset() * CleanXfac;
|
||||||
screen->DrawTexture (tex, x, 4, DTA_CleanNoMove, true, TAG_DONE);
|
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
|
// [RH] Draw icon, if any
|
||||||
|
@ -974,25 +983,6 @@ void D_DoomLoop ()
|
||||||
I_StartTic ();
|
I_StartTic ();
|
||||||
D_ProcessEvents ();
|
D_ProcessEvents ();
|
||||||
G_BuildTiccmd (&netcmds[consoleplayer][maketic%BACKUPTICS]);
|
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)
|
if (advancedemo)
|
||||||
D_DoAdvanceDemo ();
|
D_DoAdvanceDemo ();
|
||||||
C_Ticker ();
|
C_Ticker ();
|
||||||
|
@ -1337,6 +1327,7 @@ CCMD (endgame)
|
||||||
{
|
{
|
||||||
gameaction = ga_fullconsole;
|
gameaction = ga_fullconsole;
|
||||||
demosequence = -1;
|
demosequence = -1;
|
||||||
|
G_CheckDemoStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2588,6 +2579,7 @@ void D_DoomMain (void)
|
||||||
new (&gameinfo) gameinfo_t; // Reset gameinfo
|
new (&gameinfo) gameinfo_t; // Reset gameinfo
|
||||||
S_Shutdown(); // free all channels and delete playlist
|
S_Shutdown(); // free all channels and delete playlist
|
||||||
C_ClearAliases(); // CCMDs won't be reinitialized so these need to be deleted here
|
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
|
GC::FullGC(); // perform one final garbage collection before deleting the class data
|
||||||
restart++;
|
restart++;
|
||||||
|
|
404
src/d_net.cpp
404
src/d_net.cpp
|
@ -39,7 +39,6 @@
|
||||||
#include "cmdlib.h"
|
#include "cmdlib.h"
|
||||||
#include "s_sound.h"
|
#include "s_sound.h"
|
||||||
#include "m_cheat.h"
|
#include "m_cheat.h"
|
||||||
#include "p_effect.h"
|
|
||||||
#include "p_local.h"
|
#include "p_local.h"
|
||||||
#include "c_dispatch.h"
|
#include "c_dispatch.h"
|
||||||
#include "sbar.h"
|
#include "sbar.h"
|
||||||
|
@ -110,13 +109,15 @@ unsigned int lastrecvtime[MAXPLAYERS]; // [RH] Used for pings
|
||||||
unsigned int currrecvtime[MAXPLAYERS];
|
unsigned int currrecvtime[MAXPLAYERS];
|
||||||
unsigned int lastglobalrecvtime; // Identify the last time a packet was recieved.
|
unsigned int lastglobalrecvtime; // Identify the last time a packet was recieved.
|
||||||
bool hadlate;
|
bool hadlate;
|
||||||
|
int netdelay[MAXNETNODES][BACKUPTICS]; // Used for storing network delay times.
|
||||||
|
int lastaverage;
|
||||||
|
|
||||||
int nodeforplayer[MAXPLAYERS];
|
int nodeforplayer[MAXPLAYERS];
|
||||||
int playerfornode[MAXNETNODES];
|
int playerfornode[MAXNETNODES];
|
||||||
|
|
||||||
int maketic;
|
int maketic;
|
||||||
int skiptics;
|
int skiptics;
|
||||||
int ticdup;
|
int ticdup;
|
||||||
|
|
||||||
void D_ProcessEvents (void);
|
void D_ProcessEvents (void);
|
||||||
void G_BuildTiccmd (ticcmd_t *cmd);
|
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
|
// [RH] Special "ticcmds" get stored in here
|
||||||
static struct TicSpecial
|
static struct TicSpecial
|
||||||
{
|
{
|
||||||
|
@ -347,6 +374,9 @@ int NetbufferSize ()
|
||||||
k += netbuffer[k] + 1;
|
k += netbuffer[k] + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Network delay byte
|
||||||
|
k++;
|
||||||
|
|
||||||
if (netbuffer[0] & NCMD_MULTI)
|
if (netbuffer[0] & NCMD_MULTI)
|
||||||
{
|
{
|
||||||
count = netbuffer[k];
|
count = netbuffer[k];
|
||||||
|
@ -487,7 +517,30 @@ void HSendPacket (int node, int len)
|
||||||
doomcom.remotenode = node;
|
doomcom.remotenode = node;
|
||||||
doomcom.datalength = len;
|
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)
|
if (demoplayback)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
doomcom.command = CMD_GET;
|
doomcom.command = CMD_GET;
|
||||||
I_NetCmd ();
|
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)
|
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;
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (debugfile)
|
if (debugfile)
|
||||||
{
|
{
|
||||||
|
@ -570,6 +653,9 @@ bool HGetPacket (void)
|
||||||
|
|
||||||
if (doomcom.datalength != NetbufferSize ())
|
if (doomcom.datalength != NetbufferSize ())
|
||||||
{
|
{
|
||||||
|
Printf("Bad packet length %i (calculated %i)\n",
|
||||||
|
doomcom.datalength, NetbufferSize());
|
||||||
|
|
||||||
if (debugfile)
|
if (debugfile)
|
||||||
fprintf (debugfile,"---bad packet length %i (calculated %i)\n",
|
fprintf (debugfile,"---bad packet length %i (calculated %i)\n",
|
||||||
doomcom.datalength, NetbufferSize());
|
doomcom.datalength, NetbufferSize());
|
||||||
|
@ -583,6 +669,9 @@ void PlayerIsGone (int netnode, int netconsole)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (!nodeingame[netnode])
|
||||||
|
return;
|
||||||
|
|
||||||
for (i = netnode + 1; i < doomcom.numnodes; ++i)
|
for (i = netnode + 1; i < doomcom.numnodes; ++i)
|
||||||
{
|
{
|
||||||
if (nodeingame[i])
|
if (nodeingame[i])
|
||||||
|
@ -593,77 +682,37 @@ void PlayerIsGone (int netnode, int netconsole)
|
||||||
doomcom.numnodes = netnode;
|
doomcom.numnodes = netnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (playeringame[netconsole])
|
||||||
|
{
|
||||||
|
players[netconsole].playerstate = PST_GONE;
|
||||||
|
}
|
||||||
nodeingame[netnode] = false;
|
nodeingame[netnode] = false;
|
||||||
playeringame[netconsole] = false;
|
|
||||||
nodejustleft[netnode] = 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)
|
if (netconsole == Net_Arbitrator)
|
||||||
{
|
{
|
||||||
bglobal.RemoveAllBots (true);
|
|
||||||
Printf ("Removed all bots\n");
|
|
||||||
|
|
||||||
// Pick a new network arbitrator
|
// Pick a new network arbitrator
|
||||||
for (int i = 0; i < MAXPLAYERS; i++)
|
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;
|
Net_Arbitrator = i;
|
||||||
players[i].settings_controller = true;
|
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;
|
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");
|
||||||
{
|
}
|
||||||
fprintf (debugfile, "I am the new master!\n");
|
else
|
||||||
}
|
{
|
||||||
else
|
fprintf(debugfile, "Node %d is the new master!\n", nodeforplayer[Net_Arbitrator]);
|
||||||
{
|
|
||||||
fprintf (debugfile, "Node %d is the new master!\n", nodeforplayer[Net_Arbitrator]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -772,7 +821,6 @@ void GetPackets (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (netbuffer[0] & NCMD_QUITTERS)
|
if (netbuffer[0] & NCMD_QUITTERS)
|
||||||
|
|
||||||
{
|
{
|
||||||
numplayers = netbuffer[k++];
|
numplayers = netbuffer[k++];
|
||||||
for (int i = 0; i < numplayers; ++i)
|
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;
|
playerbytes[0] = netconsole;
|
||||||
if (netbuffer[0] & NCMD_MULTI)
|
if (netbuffer[0] & NCMD_MULTI)
|
||||||
{
|
{
|
||||||
|
@ -847,64 +898,18 @@ void GetPackets (void)
|
||||||
|
|
||||||
for (i = 0; i < numplayers; ++i)
|
for (i = 0; i < numplayers; ++i)
|
||||||
{
|
{
|
||||||
int node = !players[playerbytes[i]].isbot ?
|
int node = nodeforplayer[playerbytes[i]];
|
||||||
nodeforplayer[playerbytes[i]] : netnode;
|
|
||||||
|
|
||||||
SkipTicCmd (&start, nettics[node] - realstart);
|
SkipTicCmd (&start, nettics[node] - realstart);
|
||||||
for (tics = nettics[node]; tics < realend; tics++)
|
for (tics = nettics[node]; tics < realend; tics++)
|
||||||
ReadTicCmd (&start, playerbytes[i], 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)
|
nettics[nodeforplayer[playerbytes[i]]] = realend;
|
||||||
{
|
|
||||||
// [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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// NetUpdate
|
||||||
// Builds ticcmds for console player,
|
// Builds ticcmds for console player,
|
||||||
|
@ -934,7 +939,7 @@ void NetUpdate (void)
|
||||||
newtics = nowtime - gametime;
|
newtics = nowtime - gametime;
|
||||||
gametime = nowtime;
|
gametime = nowtime;
|
||||||
|
|
||||||
if (newtics <= 0) // nothing new to update
|
if (newtics <= 0 || pauseext) // nothing new to update or window paused
|
||||||
{
|
{
|
||||||
GetPackets ();
|
GetPackets ();
|
||||||
return;
|
return;
|
||||||
|
@ -951,9 +956,7 @@ void NetUpdate (void)
|
||||||
newtics = 0;
|
newtics = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// build new ticcmds for console player (and bots if I am the arbitrator)
|
// build new ticcmds for console player
|
||||||
AdjustBots (gametic / ticdup);
|
|
||||||
|
|
||||||
for (i = 0; i < newtics; i++)
|
for (i = 0; i < newtics; i++)
|
||||||
{
|
{
|
||||||
I_StartTic ();
|
I_StartTic ();
|
||||||
|
@ -963,11 +966,6 @@ void NetUpdate (void)
|
||||||
|
|
||||||
//Printf ("mk:%i ",maketic);
|
//Printf ("mk:%i ",maketic);
|
||||||
G_BuildTiccmd (&localcmds[maketic % LOCALCMDTICS]);
|
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++;
|
maketic++;
|
||||||
|
|
||||||
if (ticdup == 1 || maketic == 0)
|
if (ticdup == 1 || maketic == 0)
|
||||||
|
@ -1047,8 +1045,6 @@ void NetUpdate (void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UnadjustBots ();
|
|
||||||
|
|
||||||
if (singletics)
|
if (singletics)
|
||||||
return; // singletic update is synchronous
|
return; // singletic update is synchronous
|
||||||
|
|
||||||
|
@ -1068,14 +1064,11 @@ void NetUpdate (void)
|
||||||
|
|
||||||
if (consoleplayer == Net_Arbitrator)
|
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;
|
netbuffer[k++] = lowtic;
|
||||||
}
|
}
|
||||||
|
|
||||||
numtics = lowtic - realstart;
|
numtics = MAX(0, lowtic - realstart);
|
||||||
if (numtics > BACKUPTICS)
|
if (numtics > BACKUPTICS)
|
||||||
I_Error ("NetUpdate: Node %d missed too many tics", i);
|
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])
|
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)
|
if (numtics > 0)
|
||||||
{
|
{
|
||||||
int l;
|
int l;
|
||||||
|
@ -1199,15 +1203,12 @@ void NetUpdate (void)
|
||||||
netbuffer[0] |= NCMD_MULTI;
|
netbuffer[0] |= NCMD_MULTI;
|
||||||
netbuffer[k++] = count;
|
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++] = playerfornode[j];
|
||||||
{
|
netbuffer[k++] = playerfornode[j];
|
||||||
playerbytes[l++] = j;
|
|
||||||
netbuffer[k++] = j;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1227,7 +1228,7 @@ void NetUpdate (void)
|
||||||
prev %= BACKUPTICS;
|
prev %= BACKUPTICS;
|
||||||
|
|
||||||
// The local player has their tics sent first, followed by
|
// The local player has their tics sent first, followed by
|
||||||
// the other players/bots.
|
// the other players.
|
||||||
if (l == 0)
|
if (l == 0)
|
||||||
{
|
{
|
||||||
WriteWord (localcmds[localstart].consistancy, &cmddata);
|
WriteWord (localcmds[localstart].consistancy, &cmddata);
|
||||||
|
@ -1242,24 +1243,17 @@ void NetUpdate (void)
|
||||||
}
|
}
|
||||||
else if (i != 0)
|
else if (i != 0)
|
||||||
{
|
{
|
||||||
if (players[playerbytes[l]].isbot)
|
int len;
|
||||||
{
|
BYTE *spec;
|
||||||
|
|
||||||
WriteWord (0, &cmddata); // fake consistancy word
|
WriteWord (netcmds[playerbytes[l]][start].consistancy, &cmddata);
|
||||||
}
|
spec = NetSpecs[playerbytes[l]][start].GetData (&len);
|
||||||
else
|
if (spec != NULL)
|
||||||
{
|
{
|
||||||
int len;
|
memcpy (cmddata, spec, len);
|
||||||
BYTE *spec;
|
cmddata += len;
|
||||||
|
|
||||||
WriteWord (netcmds[playerbytes[l]][start].consistancy, &cmddata);
|
|
||||||
spec = NetSpecs[playerbytes[l]][start].GetData (&len);
|
|
||||||
if (spec != NULL)
|
|
||||||
{
|
|
||||||
memcpy (cmddata, spec, len);
|
|
||||||
cmddata += len;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteUserCmdMessage (&netcmds[playerbytes[l]][start].ucmd,
|
WriteUserCmdMessage (&netcmds[playerbytes[l]][start].ucmd,
|
||||||
prev >= 0 ? &netcmds[playerbytes[l]][prev].ucmd : NULL, &cmddata);
|
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
|
// that it won't adapt. Fortunately, player prediction helps
|
||||||
// alleviate the lag somewhat.
|
// 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)
|
if (nettics[0] <= mastertics)
|
||||||
{
|
{
|
||||||
|
@ -1346,9 +1368,8 @@ void NetUpdate (void)
|
||||||
//
|
//
|
||||||
// 0 One byte set to NCMD_SETUP+2
|
// 0 One byte set to NCMD_SETUP+2
|
||||||
// 1 One byte for ticdup setting
|
// 1 One byte for ticdup setting
|
||||||
// 2 One byte for extratics setting
|
// 2 One byte for NetMode setting
|
||||||
// 3 One byte for NetMode setting
|
// 3 String with starting map's name
|
||||||
// 4 String with starting map's name
|
|
||||||
// . Four bytes for the RNG seed
|
// . Four bytes for the RNG seed
|
||||||
// . Stream containing remaining game info
|
// . Stream containing remaining game info
|
||||||
//
|
//
|
||||||
|
@ -1429,10 +1450,9 @@ bool DoArbitrate (void *userdata)
|
||||||
data->gotsetup[0] = 0x80;
|
data->gotsetup[0] = 0x80;
|
||||||
|
|
||||||
ticdup = doomcom.ticdup = netbuffer[1];
|
ticdup = doomcom.ticdup = netbuffer[1];
|
||||||
doomcom.extratics = netbuffer[2];
|
NetMode = netbuffer[2];
|
||||||
NetMode = netbuffer[3];
|
|
||||||
|
|
||||||
stream = &netbuffer[4];
|
stream = &netbuffer[3];
|
||||||
s = ReadString (&stream);
|
s = ReadString (&stream);
|
||||||
startmap = s;
|
startmap = s;
|
||||||
delete[] s;
|
delete[] s;
|
||||||
|
@ -1497,9 +1517,8 @@ bool DoArbitrate (void *userdata)
|
||||||
{
|
{
|
||||||
netbuffer[0] = NCMD_SETUP+2;
|
netbuffer[0] = NCMD_SETUP+2;
|
||||||
netbuffer[1] = (BYTE)doomcom.ticdup;
|
netbuffer[1] = (BYTE)doomcom.ticdup;
|
||||||
netbuffer[2] = (BYTE)doomcom.extratics;
|
netbuffer[2] = NetMode;
|
||||||
netbuffer[3] = NetMode;
|
stream = &netbuffer[3];
|
||||||
stream = &netbuffer[4];
|
|
||||||
WriteString (startmap, &stream);
|
WriteString (startmap, &stream);
|
||||||
WriteLong (rngseed, &stream);
|
WriteLong (rngseed, &stream);
|
||||||
C_WriteCVars (&stream, CVAR_SERVERINFO, true);
|
C_WriteCVars (&stream, CVAR_SERVERINFO, true);
|
||||||
|
@ -1634,10 +1653,19 @@ void D_CheckNetGame (void)
|
||||||
resendto[i] = 0; // which tic to start sending
|
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
|
// I_InitNetwork sets doomcom and netgame
|
||||||
if (I_InitNetwork ())
|
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)
|
if (doomcom.id != DOOMCOM_ID)
|
||||||
{
|
{
|
||||||
|
@ -1647,15 +1675,23 @@ void D_CheckNetGame (void)
|
||||||
|
|
||||||
consoleplayer = doomcom.consoleplayer;
|
consoleplayer = doomcom.consoleplayer;
|
||||||
|
|
||||||
v = Args->CheckValue ("-netmode");
|
if (consoleplayer == Net_Arbitrator)
|
||||||
if (v != NULL)
|
|
||||||
{
|
{
|
||||||
NetMode = atoi (v) != 0 ? NET_PacketServer : NET_PeerToPeer;
|
v = Args->CheckValue("-netmode");
|
||||||
}
|
if (v != NULL)
|
||||||
if (doomcom.numnodes > 1)
|
{
|
||||||
{
|
NetMode = atoi(v) != 0 ? NET_PacketServer : NET_PeerToPeer;
|
||||||
Printf ("Selected " TEXTCOLOR_BLUE "%s" TEXTCOLOR_NORMAL " networking mode. (%s)\n", NetMode == NET_PeerToPeer ? "peer to peer" : "packet server",
|
}
|
||||||
v != NULL ? "forced" : "auto");
|
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
|
// [RH] Setup user info
|
||||||
|
@ -1683,6 +1719,11 @@ void D_CheckNetGame (void)
|
||||||
for (i = 0; i < doomcom.numnodes; i++)
|
for (i = 0; i < doomcom.numnodes; i++)
|
||||||
nodeingame[i] = true;
|
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",
|
Printf ("player %i of %i (%i nodes)\n",
|
||||||
consoleplayer+1, doomcom.numplayers, doomcom.numnodes);
|
consoleplayer+1, doomcom.numplayers, doomcom.numnodes);
|
||||||
}
|
}
|
||||||
|
@ -1809,6 +1850,9 @@ void TryRunTics (void)
|
||||||
{
|
{
|
||||||
C_Ticker();
|
C_Ticker();
|
||||||
M_Ticker();
|
M_Ticker();
|
||||||
|
// Repredict the player for new buffered movement
|
||||||
|
P_UnPredictPlayer();
|
||||||
|
P_PredictPlayer(&players[consoleplayer]);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1844,6 +1888,9 @@ void TryRunTics (void)
|
||||||
{
|
{
|
||||||
C_Ticker ();
|
C_Ticker ();
|
||||||
M_Ticker ();
|
M_Ticker ();
|
||||||
|
// Repredict the player for new buffered movement
|
||||||
|
P_UnPredictPlayer();
|
||||||
|
P_PredictPlayer(&players[consoleplayer]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1857,6 +1904,7 @@ void TryRunTics (void)
|
||||||
// run the count tics
|
// run the count tics
|
||||||
if (counts > 0)
|
if (counts > 0)
|
||||||
{
|
{
|
||||||
|
P_UnPredictPlayer();
|
||||||
while (counts--)
|
while (counts--)
|
||||||
{
|
{
|
||||||
if (gametic > lowtic)
|
if (gametic > lowtic)
|
||||||
|
@ -1876,6 +1924,7 @@ void TryRunTics (void)
|
||||||
|
|
||||||
NetUpdate (); // check for new console commands
|
NetUpdate (); // check for new console commands
|
||||||
}
|
}
|
||||||
|
P_PredictPlayer(&players[consoleplayer]);
|
||||||
S_UpdateSounds (players[consoleplayer].camera); // move positional sounds
|
S_UpdateSounds (players[consoleplayer].camera); // move positional sounds
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2130,10 +2179,7 @@ void Net_DoCommand (int type, BYTE **stream, int player)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DEM_ADDBOT:
|
case DEM_ADDBOT:
|
||||||
{
|
bglobal.TryAddBot (stream, player);
|
||||||
BYTE num = ReadByte (stream);
|
|
||||||
bglobal.DoAddBot (num, s = ReadString (stream));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DEM_KILLBOTS:
|
case DEM_KILLBOTS:
|
||||||
|
@ -2589,10 +2635,13 @@ void Net_SkipCommand (int type, BYTE **stream)
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case DEM_SAY:
|
case DEM_SAY:
|
||||||
case DEM_ADDBOT:
|
|
||||||
skip = strlen ((char *)(*stream + 1)) + 2;
|
skip = strlen ((char *)(*stream + 1)) + 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DEM_ADDBOT:
|
||||||
|
skip = strlen ((char *)(*stream + 1)) + 6;
|
||||||
|
break;
|
||||||
|
|
||||||
case DEM_GIVECHEAT:
|
case DEM_GIVECHEAT:
|
||||||
case DEM_TAKECHEAT:
|
case DEM_TAKECHEAT:
|
||||||
skip = strlen ((char *)(*stream)) + 3;
|
skip = strlen ((char *)(*stream)) + 3;
|
||||||
|
@ -2713,7 +2762,6 @@ void Net_SkipCommand (int type, BYTE **stream)
|
||||||
CCMD (pings)
|
CCMD (pings)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < MAXPLAYERS; i++)
|
for (i = 0; i < MAXPLAYERS; i++)
|
||||||
if (playeringame[i])
|
if (playeringame[i])
|
||||||
Printf ("% 4d %s\n", currrecvtime[i] - lastrecvtime[i],
|
Printf ("% 4d %s\n", currrecvtime[i] - lastrecvtime[i],
|
||||||
|
@ -2755,7 +2803,7 @@ static void Network_Controller (int playernum, bool add)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (players[playernum].isbot)
|
if (players[playernum].Bot != NULL)
|
||||||
{
|
{
|
||||||
Printf ("Bots cannot be added to the controller list.\n");
|
Printf ("Bots cannot be added to the controller list.\n");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -70,7 +70,6 @@ struct doomcom_t
|
||||||
// info common to all nodes
|
// info common to all nodes
|
||||||
SWORD numnodes; // console is always node 0.
|
SWORD numnodes; // console is always node 0.
|
||||||
SWORD ticdup; // 1 = no duplication, 2-5 = dup for slow nets
|
SWORD ticdup; // 1 = no duplication, 2-5 = dup for slow nets
|
||||||
SWORD extratics; // 1 = send a backup tic in every packet
|
|
||||||
#ifdef DJGPP
|
#ifdef DJGPP
|
||||||
SWORD pad[5]; // keep things aligned for DOS drivers
|
SWORD pad[5]; // keep things aligned for DOS drivers
|
||||||
#endif
|
#endif
|
||||||
|
@ -143,6 +142,8 @@ extern struct ticcmd_t localcmds[LOCALCMDTICS];
|
||||||
|
|
||||||
extern int maketic;
|
extern int maketic;
|
||||||
extern int nettics[MAXNETNODES];
|
extern int nettics[MAXNETNODES];
|
||||||
|
extern int netdelay[MAXNETNODES][BACKUPTICS];
|
||||||
|
extern int nodeforplayer[MAXPLAYERS];
|
||||||
|
|
||||||
extern ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS];
|
extern ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS];
|
||||||
extern int ticdup;
|
extern int ticdup;
|
||||||
|
|
|
@ -60,9 +60,6 @@
|
||||||
|
|
||||||
static FRandom pr_pickteam ("PickRandomTeam");
|
static FRandom pr_pickteam ("PickRandomTeam");
|
||||||
|
|
||||||
extern bool st_firsttime;
|
|
||||||
EXTERN_CVAR (Bool, teamplay)
|
|
||||||
|
|
||||||
CVAR (Float, autoaim, 5000.f, CVAR_USERINFO | CVAR_ARCHIVE);
|
CVAR (Float, autoaim, 5000.f, CVAR_USERINFO | CVAR_ARCHIVE);
|
||||||
CVAR (String, name, "Player", CVAR_USERINFO | CVAR_ARCHIVE);
|
CVAR (String, name, "Player", CVAR_USERINFO | CVAR_ARCHIVE);
|
||||||
CVAR (Color, color, 0x40cf00, CVAR_USERINFO | CVAR_ARCHIVE);
|
CVAR (Color, color, 0x40cf00, CVAR_USERINFO | CVAR_ARCHIVE);
|
||||||
|
|
|
@ -96,8 +96,6 @@ public:
|
||||||
};
|
};
|
||||||
FString GetPrintableDisplayName(PClassPlayerPawn *cls);
|
FString GetPrintableDisplayName(PClassPlayerPawn *cls);
|
||||||
|
|
||||||
class player_t;
|
|
||||||
|
|
||||||
class APlayerPawn : public AActor
|
class APlayerPawn : public AActor
|
||||||
{
|
{
|
||||||
DECLARE_CLASS_WITH_META(APlayerPawn, AActor, PClassPlayerPawn)
|
DECLARE_CLASS_WITH_META(APlayerPawn, AActor, PClassPlayerPawn)
|
||||||
|
@ -197,7 +195,8 @@ typedef enum
|
||||||
PST_LIVE, // Playing or camping.
|
PST_LIVE, // Playing or camping.
|
||||||
PST_DEAD, // Dead on the ground, view follows killer.
|
PST_DEAD, // Dead on the ground, view follows killer.
|
||||||
PST_REBORN, // Ready to restart/respawn???
|
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;
|
} playerstate_t;
|
||||||
|
|
||||||
|
|
||||||
|
@ -227,6 +226,8 @@ typedef enum
|
||||||
CF_DOUBLEFIRINGSPEED= 1 << 21, // Player owns a double firing speed artifact
|
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_EXTREMELYDEAD = 1 << 22, // [RH] Reliably let the status bar know about extreme deaths.
|
||||||
CF_INFINITEAMMO = 1 << 23, // Player owns an infinite ammo artifact
|
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_BUDDHA = 1 << 27, // [SP] Buddha mode - take damage, but don't die
|
||||||
CF_NOCLIP2 = 1 << 30, // [RH] More Quake-like noclip
|
CF_NOCLIP2 = 1 << 30, // [RH] More Quake-like noclip
|
||||||
} cheat_t;
|
} cheat_t;
|
||||||
|
@ -419,8 +420,7 @@ public:
|
||||||
|
|
||||||
int inventorytics;
|
int inventorytics;
|
||||||
BYTE CurrentPlayerClass; // class # for this player instance
|
BYTE CurrentPlayerClass; // class # for this player instance
|
||||||
bool backpack;
|
|
||||||
|
|
||||||
int frags[MAXPLAYERS]; // kills of other players
|
int frags[MAXPLAYERS]; // kills of other players
|
||||||
int fragcount; // [RH] Cumulative frags for this player
|
int fragcount; // [RH] Cumulative frags for this player
|
||||||
int lastkilltime; // [RH] For multikills
|
int lastkilltime; // [RH] For multikills
|
||||||
|
@ -465,47 +465,10 @@ public:
|
||||||
FName LastDamageType; // [RH] For damage-specific pain and death sounds
|
FName LastDamageType; // [RH] For damage-specific pain and death sounds
|
||||||
|
|
||||||
//Added by MC:
|
//Added by MC:
|
||||||
angle_t savedyaw;
|
TObjPtr<DBot> Bot;
|
||||||
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.
|
|
||||||
|
|
||||||
bool settings_controller; // Player can control game settings.
|
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 BlendR; // [RH] Final blending values
|
||||||
float BlendG;
|
float BlendG;
|
||||||
float BlendB;
|
float BlendB;
|
||||||
|
|
|
@ -112,7 +112,7 @@ enum EDemoCommand
|
||||||
DEM_DROPPLAYER, // 13 Not implemented, takes a byte
|
DEM_DROPPLAYER, // 13 Not implemented, takes a byte
|
||||||
DEM_CHANGEMAP, // 14 Name of map to change to
|
DEM_CHANGEMAP, // 14 Name of map to change to
|
||||||
DEM_SUICIDE, // 15 Player wants to die
|
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_KILLBOTS, // 17 Remove all bots from the world
|
||||||
DEM_INVUSEALL, // 18 Use every item (panic!)
|
DEM_INVUSEALL, // 18 Use every item (panic!)
|
||||||
DEM_INVUSE, // 19 4 bytes: ID of item to use
|
DEM_INVUSE, // 19 4 bytes: ID of item to use
|
||||||
|
@ -219,7 +219,9 @@ enum ECheatCommand
|
||||||
CHT_GIMMIEJ,
|
CHT_GIMMIEJ,
|
||||||
CHT_GIMMIEZ,
|
CHT_GIMMIEZ,
|
||||||
CHT_BUDDHA,
|
CHT_BUDDHA,
|
||||||
CHT_NOCLIP2
|
CHT_NOCLIP2,
|
||||||
|
CHT_BUDDHA2,
|
||||||
|
CHT_GOD2
|
||||||
};
|
};
|
||||||
|
|
||||||
void StartChunk (int id, BYTE **stream);
|
void StartChunk (int id, BYTE **stream);
|
||||||
|
|
|
@ -162,6 +162,7 @@ enum ELineFlags
|
||||||
ML_BLOCKUSE = 0x02000000, // blocks all use actions through this line
|
ML_BLOCKUSE = 0x02000000, // blocks all use actions through this line
|
||||||
ML_BLOCKSIGHT = 0x04000000, // blocks monster line of sight
|
ML_BLOCKSIGHT = 0x04000000, // blocks monster line of sight
|
||||||
ML_BLOCKHITSCAN = 0x08000000, // blocks hitscan attacks
|
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_BADANGLES = 1 << 0, // It is impossible to face directly NSEW.
|
||||||
COMPATF2_FLOORMOVE = 1 << 1, // Use the same floor motion behavior as Doom.
|
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
|
// 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 bool automapactive; // In AutoMap mode?
|
||||||
extern EMenuState menuactive; // Menu overlayed?
|
extern EMenuState menuactive; // Menu overlayed?
|
||||||
extern int paused; // Game Pause?
|
extern int paused; // Game Pause?
|
||||||
|
extern bool pauseext;
|
||||||
|
|
||||||
|
|
||||||
extern bool viewactive;
|
extern bool viewactive;
|
||||||
|
@ -136,6 +137,8 @@ extern int consoleplayer;
|
||||||
// Disable save/end game?
|
// Disable save/end game?
|
||||||
extern bool usergame;
|
extern bool usergame;
|
||||||
|
|
||||||
|
extern FString newdemoname;
|
||||||
|
extern FString newdemomap;
|
||||||
extern bool demoplayback;
|
extern bool demoplayback;
|
||||||
extern bool demorecording;
|
extern bool demorecording;
|
||||||
extern int demover;
|
extern int demover;
|
||||||
|
|
|
@ -113,6 +113,9 @@ enum SAW_Flags
|
||||||
SF_RANDOMLIGHTHIT = 4,
|
SF_RANDOMLIGHTHIT = 4,
|
||||||
SF_NOUSEAMMOMISS = 8,
|
SF_NOUSEAMMOMISS = 8,
|
||||||
SF_NOUSEAMMO = 16,
|
SF_NOUSEAMMO = 16,
|
||||||
|
SF_NOPULLIN = 32,
|
||||||
|
SF_NOTURN = 64,
|
||||||
|
SF_STEALARMOR = 128,
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw)
|
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw)
|
||||||
|
@ -127,6 +130,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw)
|
||||||
PARAM_ANGLE_OPT (spread_xy) { spread_xy = angle_t(2.8125 * (ANGLE_90 / 90.0)); }
|
PARAM_ANGLE_OPT (spread_xy) { spread_xy = angle_t(2.8125 * (ANGLE_90 / 90.0)); }
|
||||||
PARAM_ANGLE_OPT (spread_z) { spread_z = 0; }
|
PARAM_ANGLE_OPT (spread_z) { spread_z = 0; }
|
||||||
PARAM_FIXED_OPT (lifesteal) { lifesteal = 0; }
|
PARAM_FIXED_OPT (lifesteal) { lifesteal = 0; }
|
||||||
|
PARAM_INT_OPT (lifestealmax) { lifestealmax = 0; }
|
||||||
|
PARAM_CLASS_OPT (armorbonustype, ABasicArmorBonus) { armorbonustype = NULL; }
|
||||||
|
|
||||||
angle_t angle;
|
angle_t angle;
|
||||||
angle_t slope;
|
angle_t slope;
|
||||||
|
@ -197,29 +202,58 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw)
|
||||||
|
|
||||||
if (lifesteal && !(linetarget->flags5 & MF5_DONTDRAIN))
|
if (lifesteal && !(linetarget->flags5 & MF5_DONTDRAIN))
|
||||||
{
|
{
|
||||||
P_GiveBody (self, (actualdamage * lifesteal) >> FRACBITS);
|
if (flags & SF_STEALARMOR)
|
||||||
|
{
|
||||||
|
if (armorbonustype == NULL)
|
||||||
|
{
|
||||||
|
armorbonustype = dyn_cast<ABasicArmorBonus::MetaClass>(PClass::FindClass("ArmorBonus"));
|
||||||
|
}
|
||||||
|
if (armorbonustype != NULL)
|
||||||
|
{
|
||||||
|
assert(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);
|
S_Sound (self, CHAN_WEAPON, hitsound, 1, ATTN_NORM);
|
||||||
|
|
||||||
// turn to face target
|
// turn to face target
|
||||||
angle = R_PointToAngle2 (self->x, self->y,
|
if (!(flags & SF_NOTURN))
|
||||||
linetarget->x, linetarget->y);
|
|
||||||
if (angle - self->angle > ANG180)
|
|
||||||
{
|
{
|
||||||
if (angle - self->angle < (angle_t)(-ANG90/20))
|
angle = R_PointToAngle2(self->x, self->y,
|
||||||
self->angle = angle + ANG90/21;
|
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
|
else
|
||||||
self->angle -= ANG90/20;
|
{
|
||||||
|
if (angle - self->angle > ANG90 / 20)
|
||||||
|
self->angle = angle - ANG90 / 21;
|
||||||
|
else
|
||||||
|
self->angle += ANG90 / 20;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
if (!(flags & SF_NOPULLIN))
|
||||||
{
|
self->flags |= MF_JUSTATTACKED;
|
||||||
if (angle - self->angle > ANG90/20)
|
|
||||||
self->angle = angle - ANG90/21;
|
|
||||||
else
|
|
||||||
self->angle += ANG90/20;
|
|
||||||
}
|
|
||||||
self->flags |= MF_JUSTATTACKED;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -593,6 +627,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireBFG)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// A_BFGSpray
|
// A_BFGSpray
|
||||||
// Spawn a BFG explosion on every monster in view
|
// Spawn a BFG explosion on every monster in view
|
||||||
|
@ -603,6 +638,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray)
|
||||||
PARAM_CLASS_OPT (spraytype, AActor) { spraytype = NULL; }
|
PARAM_CLASS_OPT (spraytype, AActor) { spraytype = NULL; }
|
||||||
PARAM_INT_OPT (numrays) { numrays = 40; }
|
PARAM_INT_OPT (numrays) { numrays = 40; }
|
||||||
PARAM_INT_OPT (damagecnt) { damagecnt = 15; }
|
PARAM_INT_OPT (damagecnt) { damagecnt = 15; }
|
||||||
|
PARAM_ANGLE_OPT (angle) { angle = ANGLE_90; }
|
||||||
|
PARAM_FIXED_OPT (distance) { distance = 16*64*FRACUNIT; }
|
||||||
|
PARAM_ANGLE_OPT (vrange) { vrange = 32*FRACUNIT; }
|
||||||
|
PARAM_INT_OPT (defdamage) { defdamage = 0; }
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
int j;
|
int j;
|
||||||
|
@ -611,10 +650,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray)
|
||||||
AActor *thingToHit;
|
AActor *thingToHit;
|
||||||
AActor *linetarget;
|
AActor *linetarget;
|
||||||
|
|
||||||
|
|
||||||
if (spraytype == NULL) spraytype = PClass::FindActor("BFGExtra");
|
if (spraytype == NULL) spraytype = PClass::FindActor("BFGExtra");
|
||||||
if (numrays <= 0) numrays = 40;
|
if (numrays <= 0) numrays = 40;
|
||||||
if (damagecnt <= 0) damagecnt = 15;
|
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
|
// [RH] Don't crash if no target
|
||||||
if (!self->target)
|
if (!self->target)
|
||||||
|
@ -623,10 +664,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray)
|
||||||
// offset angles from its attack angle
|
// offset angles from its attack angle
|
||||||
for (i = 0; i < numrays; i++)
|
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
|
// 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)
|
if (!linetarget)
|
||||||
continue;
|
continue;
|
||||||
|
@ -637,14 +678,24 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray)
|
||||||
if (spray && (spray->flags5 & MF5_PUFFGETSOWNER))
|
if (spray && (spray->flags5 & MF5_PUFFGETSOWNER))
|
||||||
spray->target = self->target;
|
spray->target = self->target;
|
||||||
|
|
||||||
|
if (defdamage == 0)
|
||||||
damage = 0;
|
{
|
||||||
for (j = 0; j < damagecnt; ++j)
|
damage = 0;
|
||||||
damage += (pr_bfgspray() & 7) + 1;
|
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;
|
thingToHit = linetarget;
|
||||||
int newdam = P_DamageMobj (thingToHit, self->target, self->target, damage, spray != NULL? FName(spray->DamageType) : FName(NAME_BFGSplash),
|
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);
|
P_TraceBleed (newdam > 0 ? newdam : damage, thingToHit, self->target);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
121
src/g_game.cpp
121
src/g_game.cpp
|
@ -76,6 +76,7 @@
|
||||||
#include "d_net.h"
|
#include "d_net.h"
|
||||||
#include "d_event.h"
|
#include "d_event.h"
|
||||||
#include "p_acs.h"
|
#include "p_acs.h"
|
||||||
|
#include "p_effect.h"
|
||||||
#include "m_joy.h"
|
#include "m_joy.h"
|
||||||
#include "farchive.h"
|
#include "farchive.h"
|
||||||
#include "r_renderer.h"
|
#include "r_renderer.h"
|
||||||
|
@ -115,6 +116,7 @@ CVAR (Bool, chasedemo, false, 0);
|
||||||
CVAR (Bool, storesavepic, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
CVAR (Bool, storesavepic, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
CVAR (Bool, longsavemessages, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
CVAR (Bool, longsavemessages, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
CVAR (String, save_dir, "", 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);
|
EXTERN_CVAR (Float, con_midtime);
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -140,6 +142,7 @@ gameaction_t gameaction;
|
||||||
gamestate_t gamestate = GS_STARTUP;
|
gamestate_t gamestate = GS_STARTUP;
|
||||||
|
|
||||||
int paused;
|
int paused;
|
||||||
|
bool pauseext;
|
||||||
bool sendpause; // send a pause event next tic
|
bool sendpause; // send a pause event next tic
|
||||||
bool sendsave; // send a save event next tic
|
bool sendsave; // send a save event next tic
|
||||||
bool sendturn180; // [RH] send a 180 degree turn next tic
|
bool sendturn180; // [RH] send a 180 degree turn next tic
|
||||||
|
@ -161,6 +164,8 @@ int consoleplayer; // player taking events
|
||||||
int gametic;
|
int gametic;
|
||||||
|
|
||||||
CVAR(Bool, demo_compress, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
|
CVAR(Bool, demo_compress, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
|
||||||
|
FString newdemoname;
|
||||||
|
FString newdemomap;
|
||||||
FString demoname;
|
FString demoname;
|
||||||
bool demorecording;
|
bool demorecording;
|
||||||
bool demoplayback;
|
bool demoplayback;
|
||||||
|
@ -877,7 +882,7 @@ static void ChangeSpy (int changespy)
|
||||||
pnum &= MAXPLAYERS-1;
|
pnum &= MAXPLAYERS-1;
|
||||||
if (playeringame[pnum] &&
|
if (playeringame[pnum] &&
|
||||||
(!checkTeam || players[pnum].mo->IsTeammate (players[consoleplayer].mo) ||
|
(!checkTeam || players[pnum].mo->IsTeammate (players[consoleplayer].mo) ||
|
||||||
(bot_allowspy && players[pnum].isbot)))
|
(bot_allowspy && players[pnum].Bot != NULL)))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1016,10 +1021,16 @@ void G_Ticker ()
|
||||||
// do player reborns if needed
|
// do player reborns if needed
|
||||||
for (i = 0; i < MAXPLAYERS; i++)
|
for (i = 0; i < MAXPLAYERS; i++)
|
||||||
{
|
{
|
||||||
if (playeringame[i] &&
|
if (playeringame[i])
|
||||||
(players[i].playerstate == PST_REBORN || players[i].playerstate == PST_ENTER))
|
|
||||||
{
|
{
|
||||||
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1044,6 +1055,10 @@ void G_Ticker ()
|
||||||
case ga_loadlevel:
|
case ga_loadlevel:
|
||||||
G_DoLoadLevel (-1, false);
|
G_DoLoadLevel (-1, false);
|
||||||
break;
|
break;
|
||||||
|
case ga_recordgame:
|
||||||
|
G_CheckDemoStatus();
|
||||||
|
G_RecordDemo(newdemoname);
|
||||||
|
G_BeginRecording(newdemomap);
|
||||||
case ga_newgame2: // Silence GCC (see above)
|
case ga_newgame2: // Silence GCC (see above)
|
||||||
case ga_newgame:
|
case ga_newgame:
|
||||||
G_DoNewGame ();
|
G_DoNewGame ();
|
||||||
|
@ -1117,6 +1132,9 @@ void G_Ticker ()
|
||||||
// check, not just the player's x position like BOOM.
|
// check, not just the player's x position like BOOM.
|
||||||
DWORD rngsum = FRandom::StaticSumSeeds ();
|
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++)
|
for (i = 0; i < MAXPLAYERS; i++)
|
||||||
{
|
{
|
||||||
if (playeringame[i])
|
if (playeringame[i])
|
||||||
|
@ -1136,13 +1154,13 @@ void G_Ticker ()
|
||||||
// If the user alt-tabbed away, paused gets set to -1. In this case,
|
// 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
|
// we do not want to read more demo commands until paused is no
|
||||||
// longer negative.
|
// longer negative.
|
||||||
if (demoplayback && paused >= 0)
|
if (demoplayback)
|
||||||
{
|
{
|
||||||
G_ReadDemoTiccmd (cmd, i);
|
G_ReadDemoTiccmd (cmd, i);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
memcpy (cmd, newcmd, sizeof(ticcmd_t));
|
memcpy(cmd, newcmd, sizeof(ticcmd_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for turbo cheats
|
// check for turbo cheats
|
||||||
|
@ -1152,7 +1170,7 @@ void G_Ticker ()
|
||||||
Printf ("%s is turbo!\n", players[i].userinfo.GetName());
|
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;
|
//players[i].inconsistant = 0;
|
||||||
if (gametic > BACKUPTICS*ticdup && consistancy[i][buf] != cmd->consistancy)
|
if (gametic > BACKUPTICS*ticdup && consistancy[i][buf] != cmd->consistancy)
|
||||||
|
@ -1334,10 +1352,10 @@ void G_PlayerReborn (int player)
|
||||||
int chasecam;
|
int chasecam;
|
||||||
BYTE currclass;
|
BYTE currclass;
|
||||||
userinfo_t userinfo; // [RH] Save userinfo
|
userinfo_t userinfo; // [RH] Save userinfo
|
||||||
botskill_t b_skill; //Added by MC:
|
|
||||||
APlayerPawn *actor;
|
APlayerPawn *actor;
|
||||||
PClassPlayerPawn *cls;
|
PClassPlayerPawn *cls;
|
||||||
FString log;
|
FString log;
|
||||||
|
DBot *Bot; //Added by MC:
|
||||||
|
|
||||||
p = &players[player];
|
p = &players[player];
|
||||||
|
|
||||||
|
@ -1347,18 +1365,19 @@ void G_PlayerReborn (int player)
|
||||||
itemcount = p->itemcount;
|
itemcount = p->itemcount;
|
||||||
secretcount = p->secretcount;
|
secretcount = p->secretcount;
|
||||||
currclass = p->CurrentPlayerClass;
|
currclass = p->CurrentPlayerClass;
|
||||||
b_skill = p->skill; //Added by MC:
|
|
||||||
userinfo.TransferFrom(p->userinfo);
|
userinfo.TransferFrom(p->userinfo);
|
||||||
actor = p->mo;
|
actor = p->mo;
|
||||||
cls = p->cls;
|
cls = p->cls;
|
||||||
log = p->LogText;
|
log = p->LogText;
|
||||||
chasecam = p->cheats & CF_CHASECAM;
|
chasecam = p->cheats & CF_CHASECAM;
|
||||||
|
Bot = p->Bot; //Added by MC:
|
||||||
|
|
||||||
// Reset player structure to its defaults
|
// Reset player structure to its defaults
|
||||||
p->~player_t();
|
p->~player_t();
|
||||||
::new(p) player_t;
|
::new(p) player_t;
|
||||||
|
|
||||||
memcpy (p->frags, frags, sizeof(p->frags));
|
memcpy (p->frags, frags, sizeof(p->frags));
|
||||||
|
p->health = actor->health;
|
||||||
p->fragcount = fragcount;
|
p->fragcount = fragcount;
|
||||||
p->killcount = killcount;
|
p->killcount = killcount;
|
||||||
p->itemcount = itemcount;
|
p->itemcount = itemcount;
|
||||||
|
@ -1369,8 +1388,7 @@ void G_PlayerReborn (int player)
|
||||||
p->cls = cls;
|
p->cls = cls;
|
||||||
p->LogText = log;
|
p->LogText = log;
|
||||||
p->cheats |= chasecam;
|
p->cheats |= chasecam;
|
||||||
|
p->Bot = Bot; //Added by MC:
|
||||||
p->skill = b_skill; //Added by MC:
|
|
||||||
|
|
||||||
p->oldbuttons = ~0, p->attackdown = true; p->usedown = true; // don't do anything immediately
|
p->oldbuttons = ~0, p->attackdown = true; p->usedown = true; // don't do anything immediately
|
||||||
p->original_oldbuttons = ~0;
|
p->original_oldbuttons = ~0;
|
||||||
|
@ -1378,15 +1396,19 @@ void G_PlayerReborn (int player)
|
||||||
|
|
||||||
if (gamestate != GS_TITLELEVEL)
|
if (gamestate != GS_TITLELEVEL)
|
||||||
{
|
{
|
||||||
|
// [GRB] Give inventory specified in DECORATE
|
||||||
actor->GiveDefaultInventory ();
|
actor->GiveDefaultInventory ();
|
||||||
p->ReadyWeapon = p->PendingWeapon;
|
p->ReadyWeapon = p->PendingWeapon;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Added by MC: Init bot structure.
|
//Added by MC: Init bot structure.
|
||||||
if (bglobal.botingame[player])
|
if (p->Bot != NULL)
|
||||||
bglobal.CleanBotstuff (p);
|
{
|
||||||
else
|
botskill_t skill = p->Bot->skill;
|
||||||
p->isbot = false;
|
p->Bot->Clear ();
|
||||||
|
p->Bot->player = p;
|
||||||
|
p->Bot->skill = skill;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -1661,6 +1683,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)
|
void G_ScreenShot (char *filename)
|
||||||
{
|
{
|
||||||
shotfile = filename;
|
shotfile = filename;
|
||||||
|
@ -2079,6 +2151,9 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
|
||||||
filename = G_BuildSaveName ("demosave.zds", -1);
|
filename = G_BuildSaveName ("demosave.zds", -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cl_waitforsave)
|
||||||
|
I_FreezeTime(true);
|
||||||
|
|
||||||
insave = true;
|
insave = true;
|
||||||
G_SnapshotLevel ();
|
G_SnapshotLevel ();
|
||||||
|
|
||||||
|
@ -2088,6 +2163,7 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
|
||||||
{
|
{
|
||||||
Printf ("Could not create savegame '%s'\n", filename.GetChars());
|
Printf ("Could not create savegame '%s'\n", filename.GetChars());
|
||||||
insave = false;
|
insave = false;
|
||||||
|
I_FreezeTime(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2164,6 +2240,7 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
|
||||||
}
|
}
|
||||||
|
|
||||||
insave = false;
|
insave = false;
|
||||||
|
I_FreezeTime(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2376,6 +2453,16 @@ void G_DeferedPlayDemo (const char *name)
|
||||||
|
|
||||||
CCMD (playdemo)
|
CCMD (playdemo)
|
||||||
{
|
{
|
||||||
|
if (netgame)
|
||||||
|
{
|
||||||
|
Printf("End your current netgame first!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (demorecording)
|
||||||
|
{
|
||||||
|
Printf("End your current demo first!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (argv.argc() > 1)
|
if (argv.argc() > 1)
|
||||||
{
|
{
|
||||||
G_DeferedPlayDemo (argv[1]);
|
G_DeferedPlayDemo (argv[1]);
|
||||||
|
@ -2558,7 +2645,7 @@ void G_DoPlayDemo (void)
|
||||||
{
|
{
|
||||||
FixPathSeperator (defdemoname);
|
FixPathSeperator (defdemoname);
|
||||||
DefaultExtension (defdemoname, ".lmp");
|
DefaultExtension (defdemoname, ".lmp");
|
||||||
M_ReadFile (defdemoname, &demobuffer);
|
M_ReadFileMalloc (defdemoname, &demobuffer);
|
||||||
}
|
}
|
||||||
demo_p = demobuffer;
|
demo_p = demobuffer;
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,7 @@ enum EFinishLevelType
|
||||||
void G_PlayerFinishLevel (int player, EFinishLevelType mode, int flags);
|
void G_PlayerFinishLevel (int player, EFinishLevelType mode, int flags);
|
||||||
|
|
||||||
void G_DoReborn (int playernum, bool freshbot);
|
void G_DoReborn (int playernum, bool freshbot);
|
||||||
|
void G_DoPlayerPop(int playernum);
|
||||||
|
|
||||||
// Adds pitch to consoleplayer's viewpitch and clamps it
|
// Adds pitch to consoleplayer's viewpitch and clamps it
|
||||||
void G_AddViewPitch (int look);
|
void G_AddViewPitch (int look);
|
||||||
|
|
|
@ -28,10 +28,14 @@ int AWhirlwind::DoSpecialDamage (AActor *target, int damage, FName damagetype)
|
||||||
{
|
{
|
||||||
int randVal;
|
int randVal;
|
||||||
|
|
||||||
target->angle += pr_foo.Random2() << 20;
|
if (!(target->flags7 & MF7_DONTTHRUST))
|
||||||
target->velx += pr_foo.Random2() << 10;
|
{
|
||||||
target->vely += pr_foo.Random2() << 10;
|
target->angle += pr_foo.Random2() << 20;
|
||||||
if ((level.time & 16) && !(target->flags2 & MF2_BOSS))
|
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();
|
randVal = pr_foo();
|
||||||
if (randVal > 160)
|
if (randVal > 160)
|
||||||
|
|
|
@ -60,7 +60,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CMaceAttack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// didn't find any creatures, so try to strike any walls
|
// didn't find any creatures, so try to strike any walls
|
||||||
player->mo->special1 = 0;
|
player->mo->weaponspecial = 0;
|
||||||
|
|
||||||
angle = player->mo->angle;
|
angle = player->mo->angle;
|
||||||
slope = P_AimLineAttack (player->mo, angle, MELEERANGE, &linetarget);
|
slope = P_AimLineAttack (player->mo, angle, MELEERANGE, &linetarget);
|
||||||
|
|
|
@ -177,7 +177,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffInitBlink)
|
||||||
{
|
{
|
||||||
PARAM_ACTION_PROLOGUE;
|
PARAM_ACTION_PROLOGUE;
|
||||||
|
|
||||||
self->special1 = (pr_blink()>>1)+20;
|
self->weaponspecial = (pr_blink()>>1)+20;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,10 +193,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheckBlink)
|
||||||
|
|
||||||
if (self->player && self->player->ReadyWeapon)
|
if (self->player && self->player->ReadyWeapon)
|
||||||
{
|
{
|
||||||
if (!--self->special1)
|
if (!--self->weaponspecial)
|
||||||
{
|
{
|
||||||
P_SetPsprite (self->player, ps_weapon, self->player->ReadyWeapon->FindState ("Blink"));
|
P_SetPsprite (self->player, ps_weapon, self->player->ReadyWeapon->FindState ("Blink"));
|
||||||
self->special1 = (pr_blink()+50)>>2;
|
self->weaponspecial = (pr_blink()+50)>>2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -270,7 +270,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeAttack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// didn't find any creatures, so try to strike any walls
|
// didn't find any creatures, so try to strike any walls
|
||||||
pmo->special1 = 0;
|
pmo->weaponspecial = 0;
|
||||||
|
|
||||||
angle = pmo->angle;
|
angle = pmo->angle;
|
||||||
slope = P_AimLineAttack (pmo, angle, MELEERANGE, &linetarget);
|
slope = P_AimLineAttack (pmo, angle, MELEERANGE, &linetarget);
|
||||||
|
|
|
@ -61,7 +61,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack)
|
||||||
{
|
{
|
||||||
P_ThrustMobj(linetarget, angle, power);
|
P_ThrustMobj(linetarget, angle, power);
|
||||||
}
|
}
|
||||||
pmo->special1 = false; // Don't throw a hammer
|
pmo->weaponspecial = false; // Don't throw a hammer
|
||||||
goto hammerdone;
|
goto hammerdone;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack)
|
||||||
{
|
{
|
||||||
P_ThrustMobj(linetarget, angle, power);
|
P_ThrustMobj(linetarget, angle, power);
|
||||||
}
|
}
|
||||||
pmo->special1 = false; // Don't throw a hammer
|
pmo->weaponspecial = false; // Don't throw a hammer
|
||||||
goto hammerdone;
|
goto hammerdone;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,11 +87,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack)
|
||||||
slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE, &linetarget, 0, ALF_CHECK3D);
|
slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE, &linetarget, 0, ALF_CHECK3D);
|
||||||
if (P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true) != NULL)
|
if (P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true) != NULL)
|
||||||
{
|
{
|
||||||
pmo->special1 = false;
|
pmo->weaponspecial = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pmo->special1 = true;
|
pmo->weaponspecial = true;
|
||||||
}
|
}
|
||||||
hammerdone:
|
hammerdone:
|
||||||
// Don't spawn a hammer if the player doesn't have enough mana
|
// Don't spawn a hammer if the player doesn't have enough mana
|
||||||
|
@ -99,7 +99,7 @@ hammerdone:
|
||||||
!player->ReadyWeapon->CheckAmmo (player->ReadyWeapon->bAltFire ?
|
!player->ReadyWeapon->CheckAmmo (player->ReadyWeapon->bAltFire ?
|
||||||
AWeapon::AltFire : AWeapon::PrimaryFire, false, true))
|
AWeapon::AltFire : AWeapon::PrimaryFire, false, true))
|
||||||
{
|
{
|
||||||
pmo->special1 = false;
|
pmo->weaponspecial = false;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -122,7 +122,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerThrow)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!player->mo->special1)
|
if (!player->mo->weaponspecial)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
slope = P_AimLineAttack (pmo, angle, 2*MELEERANGE, &linetarget);
|
||||||
if (linetarget != NULL)
|
if (linetarget != NULL)
|
||||||
{
|
{
|
||||||
if (++pmo->special1 >= 3)
|
if (++pmo->weaponspecial >= 3)
|
||||||
{
|
{
|
||||||
damage <<= 1;
|
damage <<= 1;
|
||||||
power *= 3;
|
power *= 3;
|
||||||
|
@ -119,9 +119,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_FPunchAttack)
|
||||||
if (TryPunch(pmo, pmo->angle + i*(ANG45/16), damage, power) ||
|
if (TryPunch(pmo, pmo->angle + i*(ANG45/16), damage, power) ||
|
||||||
TryPunch(pmo, pmo->angle - i*(ANG45/16), damage, power))
|
TryPunch(pmo, pmo->angle - i*(ANG45/16), damage, power))
|
||||||
{ // hit something
|
{ // 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"));
|
P_SetPsprite (player, ps_weapon, player->ReadyWeapon->FindState("Fire2"));
|
||||||
S_Sound (pmo, CHAN_VOICE, "*fistgrunt", 1, ATTN_NORM);
|
S_Sound (pmo, CHAN_VOICE, "*fistgrunt", 1, ATTN_NORM);
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FPunchAttack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// didn't find any creatures, so try to strike any walls
|
// didn't find any creatures, so try to strike any walls
|
||||||
pmo->special1 = 0;
|
pmo->weaponspecial = 0;
|
||||||
|
|
||||||
AActor *linetarget;
|
AActor *linetarget;
|
||||||
int slope = P_AimLineAttack (pmo, pmo->angle, MELEERANGE, &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)
|
CCMD (open)
|
||||||
{
|
{
|
||||||
if (netgame)
|
if (netgame)
|
||||||
|
@ -236,6 +276,18 @@ void G_NewInit ()
|
||||||
{
|
{
|
||||||
int i;
|
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 ();
|
G_ClearSnapshots ();
|
||||||
ST_SetNeedRefresh();
|
ST_SetNeedRefresh();
|
||||||
netgame = false;
|
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)
|
else if (strncmp(levelname, "enDSeQ", 6) != 0)
|
||||||
{
|
{
|
||||||
nextinfo = FindLevelInfo (levelname, false);
|
FString reallevelname = levelname;
|
||||||
|
CheckWarpTransMap(reallevelname, true);
|
||||||
|
nextinfo = FindLevelInfo (reallevelname, false);
|
||||||
if (nextinfo != NULL)
|
if (nextinfo != NULL)
|
||||||
{
|
{
|
||||||
level_info_t *nextredir = nextinfo->CheckLevelRedirect();
|
level_info_t *nextredir = nextinfo->CheckLevelRedirect();
|
||||||
|
@ -507,8 +561,12 @@ void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill
|
||||||
{
|
{
|
||||||
nextinfo = nextredir;
|
nextinfo = nextredir;
|
||||||
}
|
}
|
||||||
|
nextlevel = nextinfo->MapName;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nextlevel = levelname;
|
||||||
}
|
}
|
||||||
nextlevel = nextinfo->MapName;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1106,6 +1164,8 @@ void G_StartTravel ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bglobal.StartTravel ();
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -1169,6 +1229,7 @@ void G_FinishTravel ()
|
||||||
pawn->lastenemy = NULL;
|
pawn->lastenemy = NULL;
|
||||||
pawn->player->mo = pawn;
|
pawn->player->mo = pawn;
|
||||||
pawn->player->camera = pawn;
|
pawn->player->camera = pawn;
|
||||||
|
pawn->flags2 &= ~MF2_BLASTED;
|
||||||
DObject::StaticPointerSubstitution (oldpawn, pawn);
|
DObject::StaticPointerSubstitution (oldpawn, pawn);
|
||||||
oldpawn->Destroy();
|
oldpawn->Destroy();
|
||||||
pawndup->Destroy ();
|
pawndup->Destroy ();
|
||||||
|
@ -1176,6 +1237,15 @@ void G_FinishTravel ()
|
||||||
pawn->AddToHash ();
|
pawn->AddToHash ();
|
||||||
pawn->SetState(pawn->SpawnState);
|
pawn->SetState(pawn->SpawnState);
|
||||||
pawn->player->SendPitchLimits();
|
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)
|
for (inv = pawn->Inventory; inv != NULL; inv = inv->Inventory)
|
||||||
{
|
{
|
||||||
|
@ -1193,6 +1263,8 @@ void G_FinishTravel ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bglobal.FinishTravel ();
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -50,7 +50,7 @@ class FScanner;
|
||||||
#define GCC_YSEG
|
#define GCC_YSEG
|
||||||
#else
|
#else
|
||||||
#define MSVC_YSEG
|
#define MSVC_YSEG
|
||||||
#define GCC_YSEG __attribute__((section(SECTION_YREG)))
|
#define GCC_YSEG __attribute__((section(SECTION_YREG))) __attribute__((used))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct FIntermissionDescriptor;
|
struct FIntermissionDescriptor;
|
||||||
|
@ -523,7 +523,7 @@ level_info_t *CheckLevelRedirect (level_info_t *info);
|
||||||
|
|
||||||
FString CalcMapName (int episode, int level);
|
FString CalcMapName (int episode, int level);
|
||||||
|
|
||||||
void G_ParseMapInfo (const char *basemapinfo);
|
void G_ParseMapInfo (FString basemapinfo);
|
||||||
|
|
||||||
void G_ClearSnapshots (void);
|
void G_ClearSnapshots (void);
|
||||||
void P_RemoveDefereds ();
|
void P_RemoveDefereds ();
|
||||||
|
|
|
@ -1306,6 +1306,7 @@ MapFlagHandlers[] =
|
||||||
{ "compat_maskedmidtex", MITYPE_COMPATFLAG, COMPATF_MASKEDMIDTEX, 0 },
|
{ "compat_maskedmidtex", MITYPE_COMPATFLAG, COMPATF_MASKEDMIDTEX, 0 },
|
||||||
{ "compat_badangles", MITYPE_COMPATFLAG, 0, COMPATF2_BADANGLES },
|
{ "compat_badangles", MITYPE_COMPATFLAG, 0, COMPATF2_BADANGLES },
|
||||||
{ "compat_floormove", MITYPE_COMPATFLAG, 0, COMPATF2_FLOORMOVE },
|
{ "compat_floormove", MITYPE_COMPATFLAG, 0, COMPATF2_FLOORMOVE },
|
||||||
|
{ "compat_soundcutoff", MITYPE_COMPATFLAG, 0, COMPATF2_SOUNDCUTOFF },
|
||||||
{ "cd_start_track", MITYPE_EATNEXT, 0, 0 },
|
{ "cd_start_track", MITYPE_EATNEXT, 0, 0 },
|
||||||
{ "cd_end1_track", MITYPE_EATNEXT, 0, 0 },
|
{ "cd_end1_track", MITYPE_EATNEXT, 0, 0 },
|
||||||
{ "cd_end2_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;
|
int lump, lastlump = 0;
|
||||||
level_info_t gamedefaults;
|
level_info_t gamedefaults;
|
||||||
|
@ -1895,7 +1896,7 @@ void G_ParseMapInfo (const char *basemapinfo)
|
||||||
atterm(ClearMapinfo);
|
atterm(ClearMapinfo);
|
||||||
|
|
||||||
// Parse the default MAPINFO for the current game. This lump *MUST* come from zdoom.pk3.
|
// Parse the default MAPINFO for the current game. This lump *MUST* come from zdoom.pk3.
|
||||||
if (basemapinfo != NULL)
|
if (basemapinfo.IsNotEmpty())
|
||||||
{
|
{
|
||||||
FMapInfoParser parse;
|
FMapInfoParser parse;
|
||||||
level_info_t defaultinfo;
|
level_info_t defaultinfo;
|
||||||
|
@ -1903,7 +1904,7 @@ void G_ParseMapInfo (const char *basemapinfo)
|
||||||
if (Wads.GetLumpFile(baselump) > 0)
|
if (Wads.GetLumpFile(baselump) > 0)
|
||||||
{
|
{
|
||||||
I_FatalError("File %s is overriding core lump %s.",
|
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);
|
parse.ParseMapInfo(baselump, gamedefaults, defaultinfo);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,11 @@ void ABasicArmor::Serialize (FArchive &arc)
|
||||||
{
|
{
|
||||||
Super::Serialize (arc);
|
Super::Serialize (arc);
|
||||||
arc << SavePercent << BonusCount << MaxAbsorb << MaxFullAbsorb << AbsorbCount << ArmorType;
|
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->Icon = Icon;
|
||||||
copy->BonusCount = BonusCount;
|
copy->BonusCount = BonusCount;
|
||||||
copy->ArmorType = ArmorType;
|
copy->ArmorType = ArmorType;
|
||||||
|
copy->ActualSaveAmount = ActualSaveAmount;
|
||||||
GoAwayAndDie ();
|
GoAwayAndDie ();
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
@ -268,6 +274,7 @@ bool ABasicArmorPickup::Use (bool pickup)
|
||||||
armor->MaxAbsorb = MaxAbsorb;
|
armor->MaxAbsorb = MaxAbsorb;
|
||||||
armor->MaxFullAbsorb = MaxFullAbsorb;
|
armor->MaxFullAbsorb = MaxFullAbsorb;
|
||||||
armor->ArmorType = this->GetClass()->TypeName;
|
armor->ArmorType = this->GetClass()->TypeName;
|
||||||
|
armor->ActualSaveAmount = SaveAmount;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,6 +367,7 @@ bool ABasicArmorBonus::Use (bool pickup)
|
||||||
armor->MaxAbsorb = MaxAbsorb;
|
armor->MaxAbsorb = MaxAbsorb;
|
||||||
armor->ArmorType = this->GetClass()->TypeName;
|
armor->ArmorType = this->GetClass()->TypeName;
|
||||||
armor->MaxFullAbsorb = MaxFullAbsorb;
|
armor->MaxFullAbsorb = MaxFullAbsorb;
|
||||||
|
armor->ActualSaveAmount = MaxSaveAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
armor->Amount = MIN(armor->Amount + saveAmount, MaxSaveAmount + armor->BonusCount);
|
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.
|
// with the dragon skin bracers.
|
||||||
if (damage < 10000)
|
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);
|
Slots[i] -= Scale (damage, SlotsIncrement[i], 300);
|
||||||
|
#endif
|
||||||
if (Slots[i] < 2*FRACUNIT)
|
if (Slots[i] < 2*FRACUNIT)
|
||||||
{
|
{
|
||||||
Slots[i] = 0;
|
Slots[i] = 0;
|
||||||
|
|
|
@ -60,7 +60,8 @@ bool APowerupGiver::Use (bool pickup)
|
||||||
}
|
}
|
||||||
if (BlendColor != 0)
|
if (BlendColor != 0)
|
||||||
{
|
{
|
||||||
power->BlendColor = BlendColor;
|
if (BlendColor != MakeSpecialColormap(65535)) power->BlendColor = BlendColor;
|
||||||
|
else power->BlendColor = 0;
|
||||||
}
|
}
|
||||||
if (Mode != NAME_None)
|
if (Mode != NAME_None)
|
||||||
{
|
{
|
||||||
|
@ -1296,6 +1297,18 @@ void APowerTargeter::InitEffect ()
|
||||||
PositionAccuracy ();
|
PositionAccuracy ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool APowerTargeter::HandlePickup(AInventory *item)
|
||||||
|
{
|
||||||
|
if (Super::HandlePickup(item))
|
||||||
|
{
|
||||||
|
InitEffect(); // reset the HUD sprites
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void APowerTargeter::DoEffect ()
|
void APowerTargeter::DoEffect ()
|
||||||
{
|
{
|
||||||
Super::DoEffect ();
|
Super::DoEffect ();
|
||||||
|
@ -1384,6 +1397,42 @@ void APowerFrightener::EndEffect ()
|
||||||
Owner->player->cheats &= ~CF_FRIGHTENING;
|
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 ----------------------------------------------------------
|
// Scanner powerup ----------------------------------------------------------
|
||||||
|
|
||||||
IMPLEMENT_CLASS (APowerScanner)
|
IMPLEMENT_CLASS (APowerScanner)
|
||||||
|
|
|
@ -173,6 +173,7 @@ protected:
|
||||||
void EndEffect ();
|
void EndEffect ();
|
||||||
void PositionAccuracy ();
|
void PositionAccuracy ();
|
||||||
void Travelled ();
|
void Travelled ();
|
||||||
|
bool HandlePickup(AInventory *item);
|
||||||
};
|
};
|
||||||
|
|
||||||
class APowerFrightener : public APowerup
|
class APowerFrightener : public APowerup
|
||||||
|
@ -183,6 +184,14 @@ protected:
|
||||||
void EndEffect ();
|
void EndEffect ();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class APowerBuddha : public APowerup
|
||||||
|
{
|
||||||
|
DECLARE_CLASS (APowerBuddha, APowerup)
|
||||||
|
protected:
|
||||||
|
void InitEffect ();
|
||||||
|
void EndEffect ();
|
||||||
|
};
|
||||||
|
|
||||||
class APowerTimeFreezer : public APowerup
|
class APowerTimeFreezer : public APowerup
|
||||||
{
|
{
|
||||||
DECLARE_CLASS( APowerTimeFreezer, APowerup )
|
DECLARE_CLASS( APowerTimeFreezer, APowerup )
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "doomstat.h"
|
#include "doomstat.h"
|
||||||
#include "g_level.h"
|
#include "g_level.h"
|
||||||
#include "farchive.h"
|
#include "farchive.h"
|
||||||
|
#include "p_enemy.h"
|
||||||
|
|
||||||
static FRandom pr_morphmonst ("MorphMonster");
|
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)))
|
if (actor->GetClass()->IsDescendantOf(RUNTIME_CLASS(AMorphedMonster)))
|
||||||
{
|
{
|
||||||
AMorphedMonster *fakeme = static_cast<AMorphedMonster *>(actor);
|
AMorphedMonster *fakeme = static_cast<AMorphedMonster *>(actor);
|
||||||
|
AActor *realme = fakeme->UnmorphedMe;
|
||||||
if ((fakeme->UnmorphTime) &&
|
if ((fakeme->UnmorphTime) &&
|
||||||
(fakeme->MorphStyle & MORPH_UNDOBYDEATH) &&
|
(fakeme->MorphStyle & MORPH_UNDOBYDEATH) &&
|
||||||
(fakeme->UnmorphedMe))
|
(realme))
|
||||||
{
|
{
|
||||||
AActor *realme = fakeme->UnmorphedMe;
|
|
||||||
int realstyle = fakeme->MorphStyle;
|
int realstyle = fakeme->MorphStyle;
|
||||||
int realhealth = fakeme->health;
|
int realhealth = fakeme->health;
|
||||||
if (P_UndoMonsterMorph(fakeme, !!(fakeme->MorphStyle & MORPH_UNDOBYDEATHFORCED)))
|
if (P_UndoMonsterMorph(fakeme, !!(fakeme->MorphStyle & MORPH_UNDOBYDEATHFORCED)))
|
||||||
|
@ -542,6 +543,14 @@ bool P_MorphedDeath(AActor *actor, AActor **morphed, int *morphedstyle, int *mor
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (realme->flags4 & MF4_BOSSDEATH)
|
||||||
|
{
|
||||||
|
realme->health = 0; // make sure that A_BossDeath considers it dead.
|
||||||
|
// FIXME: Use the caller's stack once the whole chain is scriptable.
|
||||||
|
VMFrameStack stack;
|
||||||
|
VMValue params[3] = { realme, realme, VMValue(NULL, ATAG_STATE) };
|
||||||
|
stack.Call(A_BossDeath_VMPtr, params, countof(params), NULL, 0, NULL);
|
||||||
|
}
|
||||||
fakeme->flags3 |= MF3_STAYMORPHED; // moved here from AMorphedMonster::Die()
|
fakeme->flags3 |= MF3_STAYMORPHED; // moved here from AMorphedMonster::Die()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -545,7 +545,7 @@ bool AInventory::ShouldRespawn ()
|
||||||
{
|
{
|
||||||
if ((ItemFlags & IF_BIGPOWERUP) && !(dmflags2 & DF2_RESPAWN_SUPER)) return false;
|
if ((ItemFlags & IF_BIGPOWERUP) && !(dmflags2 & DF2_RESPAWN_SUPER)) return false;
|
||||||
if (ItemFlags & IF_NEVERRESPAWN) return false;
|
if (ItemFlags & IF_NEVERRESPAWN) return false;
|
||||||
return !!(dmflags & DF_ITEMS_RESPAWN);
|
return !!((dmflags & DF_ITEMS_RESPAWN) || (ItemFlags & IF_ALWAYSRESPAWN));
|
||||||
}
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
@ -1070,8 +1070,8 @@ void AInventory::Touch (AActor *toucher)
|
||||||
//Added by MC: Check if item taken was the roam destination of any bot
|
//Added by MC: Check if item taken was the roam destination of any bot
|
||||||
for (int i = 0; i < MAXPLAYERS; i++)
|
for (int i = 0; i < MAXPLAYERS; i++)
|
||||||
{
|
{
|
||||||
if (playeringame[i] && this == players[i].dest)
|
if (players[i].Bot != NULL && this == players[i].Bot->dest)
|
||||||
players[i].dest = NULL;
|
players[i].Bot->dest = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -126,6 +126,7 @@ enum
|
||||||
IF_NEVERRESPAWN = 1<<20, // Never, ever respawns
|
IF_NEVERRESPAWN = 1<<20, // Never, ever respawns
|
||||||
IF_NOSCREENFLASH = 1<<21, // No pickup flash on the player's screen
|
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_TOSSED = 1<<22, // Was spawned by P_DropItem (i.e. as a monster drop)
|
||||||
|
IF_ALWAYSRESPAWN = 1<<23, // Always respawn, regardless of dmflag
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -455,6 +456,7 @@ public:
|
||||||
int MaxFullAbsorb;
|
int MaxFullAbsorb;
|
||||||
int BonusCount;
|
int BonusCount;
|
||||||
FNameNoInit ArmorType;
|
FNameNoInit ArmorType;
|
||||||
|
int ActualSaveAmount;
|
||||||
};
|
};
|
||||||
|
|
||||||
// BasicArmorPickup replaces the armor you have.
|
// BasicArmorPickup replaces the armor you have.
|
||||||
|
|
|
@ -444,7 +444,7 @@ int FMugShot::UpdateState(player_t *player, StateFlags stateflags)
|
||||||
if (bNormal)
|
if (bNormal)
|
||||||
{
|
{
|
||||||
bool good;
|
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");
|
good = SetState((stateflags & ANIMATEDGODMODE) ? "godanimated" : "god");
|
||||||
}
|
}
|
||||||
|
|
|
@ -886,8 +886,11 @@ class CommandDrawString : public SBarInfoCommand
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TIME:
|
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;
|
break;
|
||||||
|
}
|
||||||
case LOGTEXT:
|
case LOGTEXT:
|
||||||
str = statusBar->CPlayer->LogText;
|
str = statusBar->CPlayer->LogText;
|
||||||
break;
|
break;
|
||||||
|
@ -3380,43 +3383,16 @@ class CommandInInventory : public SBarInfoCommandFlowControl
|
||||||
AInventory *invItem[2] = { statusBar->CPlayer->mo->FindInventory(item[0]), statusBar->CPlayer->mo->FindInventory(item[1]) };
|
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[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 && 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)
|
if (conditionAnd)
|
||||||
{
|
SetTruth((invItem[0] && invItem[1]) != negate, block, statusBar);
|
||||||
SetTruth(true, block, statusBar);
|
else
|
||||||
return;
|
SetTruth((invItem[0] || invItem[1]) != negate, block, statusBar);
|
||||||
}
|
|
||||||
else if((invItem[0] == NULL || invItem[1] == NULL) && negate)
|
|
||||||
{
|
|
||||||
SetTruth(true, block, statusBar);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if(invItem[1] != NULL && !conditionAnd)
|
else
|
||||||
{
|
SetTruth((invItem[0] != NULL) != negate, block, statusBar);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
protected:
|
protected:
|
||||||
bool conditionAnd;
|
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[] =
|
static const char *SBarInfoCommandNames[] =
|
||||||
{
|
{
|
||||||
"drawimage", "drawnumber", "drawswitchableimage",
|
"drawimage", "drawnumber", "drawswitchableimage",
|
||||||
|
@ -3464,7 +3480,7 @@ static const char *SBarInfoCommandNames[] =
|
||||||
"gamemode", "playerclass", "playertype", "aspectratio",
|
"gamemode", "playerclass", "playertype", "aspectratio",
|
||||||
"isselected", "usesammo", "usessecondaryammo",
|
"isselected", "usesammo", "usessecondaryammo",
|
||||||
"hasweaponpiece", "inventorybarnotvisible",
|
"hasweaponpiece", "inventorybarnotvisible",
|
||||||
"weaponammo", "ininventory", "alpha",
|
"weaponammo", "ininventory", "alpha", "ifhealth",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3477,7 +3493,7 @@ enum SBarInfoCommands
|
||||||
SBARINFO_GAMEMODE, SBARINFO_PLAYERCLASS, SBARINFO_PLAYERTYPE, SBARINFO_ASPECTRATIO,
|
SBARINFO_GAMEMODE, SBARINFO_PLAYERCLASS, SBARINFO_PLAYERTYPE, SBARINFO_ASPECTRATIO,
|
||||||
SBARINFO_ISSELECTED, SBARINFO_USESAMMO, SBARINFO_USESSECONDARYAMMO,
|
SBARINFO_ISSELECTED, SBARINFO_USESAMMO, SBARINFO_USESSECONDARYAMMO,
|
||||||
SBARINFO_HASWEAPONPIECE, SBARINFO_INVENTORYBARNOTVISIBLE,
|
SBARINFO_HASWEAPONPIECE, SBARINFO_INVENTORYBARNOTVISIBLE,
|
||||||
SBARINFO_WEAPONAMMO, SBARINFO_ININVENTORY, SBARINFO_ALPHA,
|
SBARINFO_WEAPONAMMO, SBARINFO_ININVENTORY, SBARINFO_ALPHA, SBARINFO_IFHEALTH,
|
||||||
};
|
};
|
||||||
|
|
||||||
SBarInfoCommand *SBarInfoCommandFlowControl::NextCommand(FScanner &sc)
|
SBarInfoCommand *SBarInfoCommandFlowControl::NextCommand(FScanner &sc)
|
||||||
|
@ -3510,6 +3526,7 @@ SBarInfoCommand *SBarInfoCommandFlowControl::NextCommand(FScanner &sc)
|
||||||
case SBARINFO_WEAPONAMMO: return new CommandWeaponAmmo(script);
|
case SBARINFO_WEAPONAMMO: return new CommandWeaponAmmo(script);
|
||||||
case SBARINFO_ININVENTORY: return new CommandInInventory(script);
|
case SBARINFO_ININVENTORY: return new CommandInInventory(script);
|
||||||
case SBARINFO_ALPHA: return new CommandAlpha(script);
|
case SBARINFO_ALPHA: return new CommandAlpha(script);
|
||||||
|
case SBARINFO_IFHEALTH: return new CommandIfHealth(script);
|
||||||
}
|
}
|
||||||
|
|
||||||
sc.ScriptError("Unknown command '%s'.\n", sc.String);
|
sc.ScriptError("Unknown command '%s'.\n", sc.String);
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
// copy would be.
|
// copy would be.
|
||||||
|
|
||||||
#include "doomtype.h"
|
#include "doomtype.h"
|
||||||
|
#include "doomdef.h"
|
||||||
#include "v_video.h"
|
#include "v_video.h"
|
||||||
#include "gi.h"
|
#include "gi.h"
|
||||||
#include "c_cvars.h"
|
#include "c_cvars.h"
|
||||||
|
@ -48,6 +49,7 @@
|
||||||
#include "p_local.h"
|
#include "p_local.h"
|
||||||
#include "doomstat.h"
|
#include "doomstat.h"
|
||||||
#include "g_level.h"
|
#include "g_level.h"
|
||||||
|
#include "d_net.h"
|
||||||
|
|
||||||
#include <time.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 (Bool, hud_showweapons, true, CVAR_ARCHIVE); // Show weapons collected
|
||||||
CVAR (Int , hud_showtime, 0, CVAR_ARCHIVE); // Show time on HUD
|
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_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_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
|
CVAR (Int, hud_ammo_yellow, 50, CVAR_ARCHIVE) // ammo percent less is yellow more green
|
||||||
|
@ -866,7 +869,7 @@ static void DrawTime()
|
||||||
: (hud_showtime < 6
|
: (hud_showtime < 6
|
||||||
? level.time
|
? level.time
|
||||||
: level.totaltime);
|
: level.totaltime);
|
||||||
const int timeSeconds = timeTicks / TICRATE;
|
const int timeSeconds = Tics2Seconds(timeTicks);
|
||||||
|
|
||||||
hours = timeSeconds / 3600;
|
hours = timeSeconds / 3600;
|
||||||
minutes = (timeSeconds % 3600) / 60;
|
minutes = (timeSeconds % 3600) / 60;
|
||||||
|
@ -916,6 +919,51 @@ static void DrawTime()
|
||||||
DrawHudText(SmallFont, hud_timecolor, timeString, hudwidth - width, height, FRACUNIT);
|
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 = (int)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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
|
@ -981,6 +1029,7 @@ void DrawHUD()
|
||||||
if (idmypos) DrawCoordinates(CPlayer);
|
if (idmypos) DrawCoordinates(CPlayer);
|
||||||
|
|
||||||
DrawTime();
|
DrawTime();
|
||||||
|
DrawLatency();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -993,7 +1042,7 @@ void DrawHUD()
|
||||||
|
|
||||||
if (am_showtotaltime)
|
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);
|
mysnprintf(printstr, countof(printstr), "%02i:%02i:%02i", seconds/3600, (seconds%3600)/60, seconds%60);
|
||||||
DrawHudText(SmallFont, hudcolor_ttim, printstr, hudwidth-length, bottom, FRACUNIT);
|
DrawHudText(SmallFont, hudcolor_ttim, printstr, hudwidth-length, bottom, FRACUNIT);
|
||||||
bottom -= fonth;
|
bottom -= fonth;
|
||||||
|
@ -1003,14 +1052,14 @@ void DrawHUD()
|
||||||
{
|
{
|
||||||
if (level.clusterflags&CLUSTER_HUB)
|
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);
|
mysnprintf(printstr, countof(printstr), "%02i:%02i:%02i", seconds/3600, (seconds%3600)/60, seconds%60);
|
||||||
DrawHudText(SmallFont, hudcolor_time, printstr, hudwidth-length, bottom, FRACUNIT);
|
DrawHudText(SmallFont, hudcolor_time, printstr, hudwidth-length, bottom, FRACUNIT);
|
||||||
bottom -= fonth;
|
bottom -= fonth;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Single level time for hubs
|
// 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);
|
mysnprintf(printstr, countof(printstr), "%02i:%02i:%02i", seconds/3600, (seconds%3600)/60, seconds%60);
|
||||||
DrawHudText(SmallFont, hudcolor_ltim, printstr, hudwidth-length, bottom, FRACUNIT);
|
DrawHudText(SmallFont, hudcolor_ltim, printstr, hudwidth-length, bottom, FRACUNIT);
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,7 +146,6 @@ void ST_LoadCrosshair(bool alwaysload)
|
||||||
{
|
{
|
||||||
int num = 0;
|
int num = 0;
|
||||||
char name[16], size;
|
char name[16], size;
|
||||||
int lump;
|
|
||||||
|
|
||||||
if (!crosshairforce &&
|
if (!crosshairforce &&
|
||||||
players[consoleplayer].camera != NULL &&
|
players[consoleplayer].camera != NULL &&
|
||||||
|
@ -179,18 +178,20 @@ void ST_LoadCrosshair(bool alwaysload)
|
||||||
num = -num;
|
num = -num;
|
||||||
}
|
}
|
||||||
size = (SCREENWIDTH < 640) ? 'S' : 'B';
|
size = (SCREENWIDTH < 640) ? 'S' : 'B';
|
||||||
|
|
||||||
mysnprintf (name, countof(name), "XHAIR%c%d", size, num);
|
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);
|
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;
|
CrosshairNum = num;
|
||||||
CrosshairImage = TexMan[TexMan.CheckForTexture(name, FTexture::TEX_MiscPatch)];
|
CrosshairImage = TexMan[texid];
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
@ -1122,7 +1123,7 @@ void DBaseStatusBar::DrawCrosshair ()
|
||||||
ST_LoadCrosshair();
|
ST_LoadCrosshair();
|
||||||
|
|
||||||
// Don't draw the crosshair if there is none
|
// 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;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1306,8 +1307,8 @@ void DBaseStatusBar::Draw (EHudState state)
|
||||||
}
|
}
|
||||||
else if (automapactive)
|
else if (automapactive)
|
||||||
{
|
{
|
||||||
int y, time = level.time / TICRATE, height;
|
int y, time = Tics2Seconds(level.time), height;
|
||||||
int totaltime = level.totaltime / TICRATE;
|
int totaltime = Tics2Seconds(level.totaltime);
|
||||||
EColorRange highlight = (gameinfo.gametype & GAME_DoomChex) ?
|
EColorRange highlight = (gameinfo.gametype & GAME_DoomChex) ?
|
||||||
CR_UNTRANSLATED : CR_YELLOW;
|
CR_UNTRANSLATED : CR_YELLOW;
|
||||||
|
|
||||||
|
|
|
@ -114,7 +114,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_AlienSpectreDeath)
|
||||||
switch (self->GetClass()->TypeName)
|
switch (self->GetClass()->TypeName)
|
||||||
{
|
{
|
||||||
case NAME_AlienSpectre1:
|
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;
|
log = 95;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -188,7 +188,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_AlienSpectreDeath)
|
||||||
{ // Another Sigil piece. Woohoo!
|
{ // Another Sigil piece. Woohoo!
|
||||||
log = 83;
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -94,7 +94,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CrusaderDeath)
|
||||||
|
|
||||||
if (CheckBossDeath (self))
|
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);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -563,7 +563,7 @@ void APowerCoupling::Die (AActor *source, AActor *inflictor, int dmgflags)
|
||||||
P_NoiseAlert (source, this);
|
P_NoiseAlert (source, this);
|
||||||
}
|
}
|
||||||
EV_DoDoor (DDoor::doorClose, NULL, players[i].mo, 225, 2*FRACUNIT, 0, 0, 0);
|
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]);
|
players[i].mo->GiveInventoryType (QuestItemClasses[5]);
|
||||||
S_Sound (CHAN_VOICE, "svox/voc13", 1, ATTN_NORM);
|
S_Sound (CHAN_VOICE, "svox/voc13", 1, ATTN_NORM);
|
||||||
players[i].SetLogNumber (13);
|
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[back], left, top, DTA_CleanNoMove, true, DTA_Alpha, FRACUNIT*3/4, TAG_DONE);
|
||||||
screen->DrawTexture (Images[bars], left, top, DTA_CleanNoMove, true, TAG_DONE);
|
screen->DrawTexture (Images[bars], left, top, DTA_CleanNoMove, true, TAG_DONE);
|
||||||
|
|
||||||
|
|
||||||
switch (CurrentPop)
|
switch (CurrentPop)
|
||||||
{
|
{
|
||||||
case POP_Log:
|
case POP_Log:
|
||||||
|
{
|
||||||
|
int seconds = Tics2Seconds(level.time);
|
||||||
// Draw the latest log message.
|
// Draw the latest log message.
|
||||||
mysnprintf (buff, countof(buff), "%02d:%02d:%02d",
|
mysnprintf(buff, countof(buff), "%02d:%02d:%02d",
|
||||||
(level.time/TICRATE)/3600,
|
seconds / 3600,
|
||||||
((level.time/TICRATE)%3600)/60,
|
(seconds % 3600) / 60,
|
||||||
(level.time/TICRATE)%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);
|
DTA_CleanNoMove, true, TAG_DONE);
|
||||||
|
|
||||||
if (CPlayer->LogText != NULL)
|
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)
|
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);
|
lines[i].Text, DTA_CleanNoMove, true, TAG_DONE);
|
||||||
}
|
}
|
||||||
V_FreeBrokenLines (lines);
|
V_FreeBrokenLines(lines);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case POP_Keys:
|
case POP_Keys:
|
||||||
// List the keys the player has.
|
// 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),
|
: "a,a,a,a,a,a" (a),
|
||||||
"m,r,m,r,d,d" (b),
|
"m,r,m,r,d,d" (b),
|
||||||
"r,r,m,m,r,m" (c)
|
"r,r,m,m,r,m" (c)
|
||||||
: "%cc"
|
: "cc"
|
||||||
);
|
);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -59,7 +59,7 @@ static inline SDWORD MulScale (SDWORD a, SDWORD b, SDWORD c)
|
||||||
: "a,a,a,a" (a),
|
: "a,a,a,a" (a),
|
||||||
"m,r,m,r" (b),
|
"m,r,m,r" (b),
|
||||||
"c,c,I,I" (c)
|
"c,c,I,I" (c)
|
||||||
: "%cc"
|
: "cc"
|
||||||
);
|
);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -210,7 +210,7 @@ static inline SDWORD DivScale (SDWORD a, SDWORD b, SDWORD c)
|
||||||
: "a" (lo),
|
: "a" (lo),
|
||||||
"d" (hi),
|
"d" (hi),
|
||||||
"r" (b)
|
"r" (b)
|
||||||
: "%cc");
|
: "cc");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,7 +226,7 @@ static inline SDWORD DivScale1 (SDWORD a, SDWORD b)
|
||||||
"=&d,d" (dummy)
|
"=&d,d" (dummy)
|
||||||
: "a,a" (a),
|
: "a,a" (a),
|
||||||
"r,m" (b)
|
"r,m" (b)
|
||||||
: "%cc");
|
: "cc");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,7 +241,7 @@ static inline SDWORD DivScale1 (SDWORD a, SDWORD b)
|
||||||
: "a,a" (a<<s), \
|
: "a,a" (a<<s), \
|
||||||
"d,d" (a>>(32-s)), \
|
"d,d" (a>>(32-s)), \
|
||||||
"r,m" (b) \
|
"r,m" (b) \
|
||||||
: "%cc"); \
|
: "cc"); \
|
||||||
return result; \
|
return result; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,7 +287,7 @@ static inline SDWORD DivScale32 (SDWORD a, SDWORD b)
|
||||||
"=d,d" (dummy)
|
"=d,d" (dummy)
|
||||||
: "d,d" (a),
|
: "d,d" (a),
|
||||||
"r,m" (b)
|
"r,m" (b)
|
||||||
: "%cc");
|
: "cc");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,7 +313,7 @@ static inline void clearbufshort (void *buff, unsigned int count, WORD clear)
|
||||||
"rep stosw"
|
"rep stosw"
|
||||||
:"=D" (buff), "=c" (count)
|
:"=D" (buff), "=c" (count)
|
||||||
:"D" (buff), "c" (count), "a" (clear|(clear<<16))
|
:"D" (buff), "c" (count), "a" (clear|(clear<<16))
|
||||||
:"%cc");
|
:"cc");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline SDWORD ksgn (SDWORD a)
|
static inline SDWORD ksgn (SDWORD a)
|
||||||
|
@ -327,6 +327,6 @@ static inline SDWORD ksgn (SDWORD a)
|
||||||
"adc $0,%1"
|
"adc $0,%1"
|
||||||
:"=r" (dummy), "=r" (result)
|
:"=r" (dummy), "=r" (result)
|
||||||
:"0" (a)
|
:"0" (a)
|
||||||
:"%cc");
|
:"cc");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -290,6 +290,8 @@ void FMapInfoParser::ParseGameInfo()
|
||||||
else gameinfo.mCheatMapArrow = "";
|
else gameinfo.mCheatMapArrow = "";
|
||||||
}
|
}
|
||||||
// Insert valid keys here.
|
// Insert valid keys here.
|
||||||
|
GAMEINFOKEY_STRING(mCheatKey, "cheatKey")
|
||||||
|
GAMEINFOKEY_STRING(mEasyKey, "easyKey")
|
||||||
GAMEINFOKEY_STRING(TitlePage, "titlePage")
|
GAMEINFOKEY_STRING(TitlePage, "titlePage")
|
||||||
GAMEINFOKEY_STRINGARRAY(creditPages, "addcreditPage", 8, false)
|
GAMEINFOKEY_STRINGARRAY(creditPages, "addcreditPage", 8, false)
|
||||||
GAMEINFOKEY_STRINGARRAY(creditPages, "CreditPage", 8, true)
|
GAMEINFOKEY_STRINGARRAY(creditPages, "CreditPage", 8, true)
|
||||||
|
|
1
src/gi.h
1
src/gi.h
|
@ -169,6 +169,7 @@ struct gameinfo_t
|
||||||
int TextScreenY;
|
int TextScreenY;
|
||||||
FName DefaultEndSequence;
|
FName DefaultEndSequence;
|
||||||
FString mMapArrow, mCheatMapArrow;
|
FString mMapArrow, mCheatMapArrow;
|
||||||
|
FString mEasyKey, mCheatKey;
|
||||||
FGIFont mStatscreenMapNameFont;
|
FGIFont mStatscreenMapNameFont;
|
||||||
FGIFont mStatscreenFinishedFont;
|
FGIFont mStatscreenFinishedFont;
|
||||||
FGIFont mStatscreenEnteringFont;
|
FGIFont mStatscreenEnteringFont;
|
||||||
|
|
|
@ -48,6 +48,8 @@
|
||||||
#include "d_player.h"
|
#include "d_player.h"
|
||||||
#include "hu_stuff.h"
|
#include "hu_stuff.h"
|
||||||
#include "gstrings.h"
|
#include "gstrings.h"
|
||||||
|
#include "d_net.h"
|
||||||
|
#include "c_dispatch.h"
|
||||||
|
|
||||||
// MACROS ------------------------------------------------------------------
|
// MACROS ------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -61,7 +63,7 @@
|
||||||
|
|
||||||
static void HU_DoDrawScores (player_t *, player_t *[MAXPLAYERS]);
|
static void HU_DoDrawScores (player_t *, player_t *[MAXPLAYERS]);
|
||||||
static void HU_DrawTimeRemaining (int y);
|
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 ----------------------------------------------
|
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
||||||
|
|
||||||
|
@ -116,6 +118,8 @@ int STACK_ARGS compareteams (const void *arg1, const void *arg2)
|
||||||
return diff;
|
return diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SB_ForceActive = false;
|
||||||
|
|
||||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||||
|
|
||||||
// CODE --------------------------------------------------------------------
|
// CODE --------------------------------------------------------------------
|
||||||
|
@ -228,7 +232,7 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER
|
||||||
int maxnamewidth, maxscorewidth, maxiconheight;
|
int maxnamewidth, maxscorewidth, maxiconheight;
|
||||||
int numTeams = 0;
|
int numTeams = 0;
|
||||||
int x, y, ypadding, bottom;
|
int x, y, ypadding, bottom;
|
||||||
int col2, col3, col4;
|
int col2, col3, col4, col5;
|
||||||
|
|
||||||
if (deathmatch)
|
if (deathmatch)
|
||||||
{
|
{
|
||||||
|
@ -309,12 +313,14 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER
|
||||||
|
|
||||||
const char *text_color = GStrings("SCORE_COLOR"),
|
const char *text_color = GStrings("SCORE_COLOR"),
|
||||||
*text_frags = GStrings(deathmatch ? "SCORE_FRAGS" : "SCORE_KILLS"),
|
*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;
|
col2 = (SmallFont->StringWidth(text_color) + 8) * CleanXfac;
|
||||||
col3 = col2 + (SmallFont->StringWidth(text_frags) + 8) * CleanXfac;
|
col3 = col2 + (SmallFont->StringWidth(text_frags) + 8) * CleanXfac;
|
||||||
col4 = col3 + maxscorewidth * 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,
|
screen->DrawText (SmallFont, color, x, y, text_color,
|
||||||
DTA_CleanNoMove, true, TAG_DONE);
|
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,
|
screen->DrawText (SmallFont, color, x + col4, y, text_name,
|
||||||
DTA_CleanNoMove, true, TAG_DONE);
|
DTA_CleanNoMove, true, TAG_DONE);
|
||||||
|
|
||||||
|
screen->DrawText(SmallFont, color, x + col5, y, text_delay,
|
||||||
|
DTA_CleanNoMove, true, TAG_DONE);
|
||||||
|
|
||||||
y += height + 6 * CleanYfac;
|
y += height + 6 * CleanYfac;
|
||||||
bottom -= height;
|
bottom -= height;
|
||||||
|
|
||||||
|
@ -332,7 +341,7 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER
|
||||||
{
|
{
|
||||||
if (playeringame[sortedplayers[i] - players])
|
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;
|
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;
|
int color;
|
||||||
char str[80];
|
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
|
// 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
|
// other way to do highlighting. And it may as well be used for
|
||||||
// all modes for the sake of consistancy.
|
// 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;
|
col2 += col1;
|
||||||
col3 += col1;
|
col3 += col1;
|
||||||
col4 += col1;
|
col4 += col1;
|
||||||
|
col5 += col1;
|
||||||
|
|
||||||
color = HU_GetRowColor(player, highlight);
|
color = HU_GetRowColor(player, highlight);
|
||||||
HU_DrawColorBar(col1, y, height, (int)(player - players));
|
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(),
|
screen->DrawText (SmallFont, color, col4, y + ypadding, player->userinfo.GetName(),
|
||||||
DTA_CleanNoMove, true, TAG_DONE);
|
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 ())
|
if (teamplay && Teams[player->userinfo.GetTeam()].GetLogo().IsNotEmpty ())
|
||||||
{
|
{
|
||||||
FTexture *pic = TexMan[Teams[player->userinfo.GetTeam()].GetLogo().GetChars ()];
|
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);
|
void HU_DrawColorBar(int x, int y, int height, int playernum);
|
||||||
int HU_GetRowColor(player_t *player, bool hightlight);
|
int HU_GetRowColor(player_t *player, bool hightlight);
|
||||||
|
|
||||||
|
extern bool SB_ForceActive;
|
||||||
|
|
||||||
// Sorting routines
|
// Sorting routines
|
||||||
|
|
||||||
int STACK_ARGS comparepoints(const void *arg1, const void *arg2);
|
int STACK_ARGS comparepoints(const void *arg1, const void *arg2);
|
||||||
|
|
|
@ -110,6 +110,7 @@ const char *neterror (void);
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
PRE_CONNECT, // Sent from guest to host for initial connection
|
PRE_CONNECT, // Sent from guest to host for initial connection
|
||||||
|
PRE_KEEPALIVE,
|
||||||
PRE_DISCONNECT, // Sent from guest that aborts the game
|
PRE_DISCONNECT, // Sent from guest that aborts the game
|
||||||
PRE_ALLHERE, // Sent from host to guest when everybody has connected
|
PRE_ALLHERE, // Sent from host to guest when everybody has connected
|
||||||
PRE_CONACK, // Sent from host to guest to acknowledge PRE_CONNECT receipt
|
PRE_CONACK, // Sent from host to guest to acknowledge PRE_CONNECT receipt
|
||||||
|
@ -134,8 +135,8 @@ struct PreGamePacket
|
||||||
};
|
};
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
u_long address;
|
DWORD address;
|
||||||
u_short port;
|
WORD port;
|
||||||
BYTE player;
|
BYTE player;
|
||||||
BYTE pad;
|
BYTE pad;
|
||||||
} machines[MAXNETNODES];
|
} machines[MAXNETNODES];
|
||||||
|
@ -208,11 +209,11 @@ void PacketSend (void)
|
||||||
{
|
{
|
||||||
I_FatalError("Netbuffer overflow!");
|
I_FatalError("Netbuffer overflow!");
|
||||||
}
|
}
|
||||||
|
assert(!(doomcom.data[0] & NCMD_COMPRESSED));
|
||||||
|
|
||||||
uLong size = TRANSMIT_SIZE - 1;
|
uLong size = TRANSMIT_SIZE - 1;
|
||||||
if (doomcom.datalength >= 10)
|
if (doomcom.datalength >= 10)
|
||||||
{
|
{
|
||||||
assert(!(doomcom.data[0] & NCMD_COMPRESSED));
|
|
||||||
TransmitBuffer[0] = doomcom.data[0] | NCMD_COMPRESSED;
|
TransmitBuffer[0] = doomcom.data[0] | NCMD_COMPRESSED;
|
||||||
c = compress2(TransmitBuffer + 1, &size, doomcom.data + 1, doomcom.datalength - 1, 9);
|
c = compress2(TransmitBuffer + 1, &size, doomcom.data + 1, doomcom.datalength - 1, 9);
|
||||||
size += 1;
|
size += 1;
|
||||||
|
@ -548,10 +549,15 @@ bool Host_CheckForConnects (void *userdata)
|
||||||
SendConAck (doomcom.numnodes, numplayers);
|
SendConAck (doomcom.numnodes, numplayers);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PRE_KEEPALIVE:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (doomcom.numnodes < numplayers)
|
if (doomcom.numnodes < numplayers)
|
||||||
{
|
{
|
||||||
|
// Send message to everyone as a keepalive
|
||||||
|
SendConAck(doomcom.numnodes, numplayers);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -654,6 +660,12 @@ void HostGame (int i)
|
||||||
numplayers = 2;
|
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)
|
if (numplayers == 1)
|
||||||
{ // Special case: Only 1 player, so don't bother starting the network
|
{ // Special case: Only 1 player, so don't bother starting the network
|
||||||
netgame = false;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -938,11 +954,6 @@ bool I_InitNetwork (void)
|
||||||
doomcom.ticdup = 1;
|
doomcom.ticdup = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Args->CheckParm ("-extratic"))
|
|
||||||
doomcom.extratics = 1;
|
|
||||||
else
|
|
||||||
doomcom.extratics = 0;
|
|
||||||
|
|
||||||
v = Args->CheckValue ("-port");
|
v = Args->CheckValue ("-port");
|
||||||
if (v)
|
if (v)
|
||||||
{
|
{
|
||||||
|
|
|
@ -99,6 +99,23 @@ void cht_DoCheat (player_t *player, int cheat)
|
||||||
msg = GStrings("TXT_BUDDHAOFF");
|
msg = GStrings("TXT_BUDDHAOFF");
|
||||||
break;
|
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:
|
case CHT_NOCLIP:
|
||||||
player->cheats ^= CF_NOCLIP;
|
player->cheats ^= CF_NOCLIP;
|
||||||
if (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->Translation = TRANSLATION(TRANSLATION_Players, BYTE(player-players));
|
||||||
}
|
}
|
||||||
player->mo->DamageType = NAME_None;
|
player->mo->DamageType = NAME_None;
|
||||||
// player->mo->GiveDefaultInventory();
|
|
||||||
if (player->ReadyWeapon != NULL)
|
if (player->ReadyWeapon != NULL)
|
||||||
{
|
{
|
||||||
P_SetPsprite(player, ps_weapon, player->ReadyWeapon->GetUpState());
|
P_SetPsprite(player, ps_weapon, player->ReadyWeapon->GetUpState());
|
||||||
|
|
|
@ -137,6 +137,32 @@ int M_ReadFile (char const *name, BYTE **buffer)
|
||||||
return length;
|
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
|
// PROC M_FindResponseFile
|
||||||
|
|
|
@ -33,6 +33,7 @@ extern FGameConfigFile *GameConfig;
|
||||||
|
|
||||||
bool M_WriteFile (char const *name, void *source, int length);
|
bool M_WriteFile (char const *name, void *source, int length);
|
||||||
int M_ReadFile (char const *name, BYTE **buffer);
|
int M_ReadFile (char const *name, BYTE **buffer);
|
||||||
|
int M_ReadFileMalloc (char const *name, BYTE **buffer);
|
||||||
void M_FindResponseFile (void);
|
void M_FindResponseFile (void);
|
||||||
|
|
||||||
// [RH] M_ScreenShot now accepts a filename parameter.
|
// [RH] M_ScreenShot now accepts a filename parameter.
|
||||||
|
|
|
@ -300,6 +300,9 @@ xx(Abs)
|
||||||
xx(ACS_NamedExecuteWithResult)
|
xx(ACS_NamedExecuteWithResult)
|
||||||
xx(CallACS)
|
xx(CallACS)
|
||||||
xx(Sqrt)
|
xx(Sqrt)
|
||||||
|
xx(CheckClass)
|
||||||
|
xx(IsPointerEqual)
|
||||||
|
xx(Pick)
|
||||||
|
|
||||||
// Various actor names which are used internally
|
// Various actor names which are used internally
|
||||||
xx(MapSpot)
|
xx(MapSpot)
|
||||||
|
@ -420,6 +423,7 @@ xx(Passuse)
|
||||||
xx(Repeatspecial)
|
xx(Repeatspecial)
|
||||||
xx(Conversation)
|
xx(Conversation)
|
||||||
xx(Locknumber)
|
xx(Locknumber)
|
||||||
|
xx(Midtex3dimpassible)
|
||||||
|
|
||||||
xx(Playercross)
|
xx(Playercross)
|
||||||
xx(Playeruse)
|
xx(Playeruse)
|
||||||
|
|
|
@ -69,7 +69,13 @@ static const int PO_LINE_EXPLICIT = 5;
|
||||||
angle_t FNodeBuilder::PointToAngle (fixed_t x, fixed_t y)
|
angle_t FNodeBuilder::PointToAngle (fixed_t x, fixed_t y)
|
||||||
{
|
{
|
||||||
const double rad2bam = double(1<<30) / M_PI;
|
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));
|
double ang = atan2 (double(y), double(x));
|
||||||
|
#endif // __APPLE__ && !__llvm__
|
||||||
return angle_t(ang * rad2bam) << 1;
|
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));
|
assert(numchips >= 1 && numchips <= countof(chips));
|
||||||
uint i;
|
uint i;
|
||||||
IsOPL3 = (opl_core == 1 || opl_core == 2);
|
IsOPL3 = (opl_core == 1 || opl_core == 2 || opl_core == 3);
|
||||||
|
|
||||||
memset(chips, 0, sizeof(chips));
|
memset(chips, 0, sizeof(chips));
|
||||||
if (IsOPL3)
|
if (IsOPL3)
|
||||||
|
@ -332,7 +332,7 @@ int OPLio::OPLinit(uint numchips, bool stereo, bool initopl3)
|
||||||
}
|
}
|
||||||
for (i = 0; i < numchips; ++i)
|
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)
|
if (chip == NULL)
|
||||||
{
|
{
|
||||||
break;
|
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 *YM3812Create(bool stereo);
|
||||||
OPLEmul *DBOPLCreate(bool stereo);
|
OPLEmul *DBOPLCreate(bool stereo);
|
||||||
OPLEmul *JavaOPLCreate(bool stereo);
|
OPLEmul *JavaOPLCreate(bool stereo);
|
||||||
|
OPLEmul *NukedOPL3Create(bool stereo);
|
||||||
|
|
||||||
#define OPL_SAMPLE_RATE 49716.0
|
#define OPL_SAMPLE_RATE 49716.0
|
||||||
#define CENTER_PANNING_POWER 0.70710678118 /* [RH] volume at center for EQP */
|
#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
|
//Add the floor
|
||||||
ffloor = new F3DFloor;
|
ffloor = new F3DFloor;
|
||||||
|
ffloor->top.copied = ffloor->bottom.copied = false;
|
||||||
ffloor->top.model = ffloor->bottom.model = ffloor->model = sec2;
|
ffloor->top.model = ffloor->bottom.model = ffloor->model = sec2;
|
||||||
ffloor->target = sec;
|
ffloor->target = sec;
|
||||||
ffloor->ceilingclip = ffloor->floorclip = NULL;
|
ffloor->ceilingclip = ffloor->floorclip = NULL;
|
||||||
|
@ -420,6 +421,8 @@ void P_Recalculate3DFloors(sector_t * sector)
|
||||||
F3DFloor * pick;
|
F3DFloor * pick;
|
||||||
unsigned pickindex;
|
unsigned pickindex;
|
||||||
F3DFloor * clipped=NULL;
|
F3DFloor * clipped=NULL;
|
||||||
|
F3DFloor * solid=NULL;
|
||||||
|
fixed_t solid_bottom=0;
|
||||||
fixed_t clipped_top;
|
fixed_t clipped_top;
|
||||||
fixed_t clipped_bottom=0;
|
fixed_t clipped_bottom=0;
|
||||||
fixed_t maxheight, minheight;
|
fixed_t maxheight, minheight;
|
||||||
|
@ -477,6 +480,7 @@ void P_Recalculate3DFloors(sector_t * sector)
|
||||||
}
|
}
|
||||||
|
|
||||||
oldlist.Delete(pickindex);
|
oldlist.Delete(pickindex);
|
||||||
|
fixed_t pick_bottom=pick->bottom.plane->ZatPoint(CenterSpot(sector));
|
||||||
|
|
||||||
if (pick->flags & FF_THISINSIDE)
|
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)
|
else if (pick->flags&(FF_SWIMMABLE|FF_TRANSLUCENT) && pick->flags&FF_EXISTS)
|
||||||
{
|
{
|
||||||
clipped=pick;
|
// We must check if this nonsolid segment gets clipped from the top by another 3D floor
|
||||||
clipped_top=height;
|
if (solid != NULL && solid_bottom < height)
|
||||||
clipped_bottom=pick->bottom.plane->ZatPoint(CenterSpot(sector));
|
{
|
||||||
ffloors.Push(pick);
|
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)
|
else if (clipped && clipped_bottom<height)
|
||||||
{
|
{
|
||||||
|
@ -499,12 +531,10 @@ void P_Recalculate3DFloors(sector_t * sector)
|
||||||
clipped->flags|=FF_CLIPPED;
|
clipped->flags|=FF_CLIPPED;
|
||||||
clipped->flags&=~FF_EXISTS;
|
clipped->flags&=~FF_EXISTS;
|
||||||
dyn->flags|=FF_DYNAMIC;
|
dyn->flags|=FF_DYNAMIC;
|
||||||
dyn->bottom=pick->top;
|
dyn->bottom.copyPlane(&pick->top);
|
||||||
ffloors.Push(dyn);
|
ffloors.Push(dyn);
|
||||||
ffloors.Push(pick);
|
ffloors.Push(pick);
|
||||||
|
|
||||||
fixed_t pick_bottom=pick->bottom.plane->ZatPoint(CenterSpot(sector));
|
|
||||||
|
|
||||||
if (pick_bottom<=clipped_bottom)
|
if (pick_bottom<=clipped_bottom)
|
||||||
{
|
{
|
||||||
clipped=NULL;
|
clipped=NULL;
|
||||||
|
@ -515,14 +545,25 @@ void P_Recalculate3DFloors(sector_t * sector)
|
||||||
dyn=new F3DFloor;
|
dyn=new F3DFloor;
|
||||||
*dyn=*clipped;
|
*dyn=*clipped;
|
||||||
dyn->flags|=FF_DYNAMIC|FF_EXISTS;
|
dyn->flags|=FF_DYNAMIC|FF_EXISTS;
|
||||||
dyn->top=pick->bottom;
|
dyn->top.copyPlane(&pick->bottom);
|
||||||
ffloors.Push(dyn);
|
ffloors.Push(dyn);
|
||||||
|
clipped = dyn;
|
||||||
|
clipped_top = pick_bottom;
|
||||||
}
|
}
|
||||||
|
solid = pick;
|
||||||
|
solid_bottom = pick_bottom;
|
||||||
}
|
}
|
||||||
else
|
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);
|
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
|
#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