diff --git a/docs/rh-log.txt b/docs/rh-log.txt index e11b64b36..3db28675b 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,3 +1,8 @@ +September 12, 2008 +- Added GetPlayerInput() for examining a player's inputs from ACS. Most + buttons are now passed across the network. Also added four user buttons + that are specifically for use with this command. + September 11, 2008 - Fixed: Hexen's fourth weapon pieces did not play the correct pickup sound, and when they were fully assembled, they did not play the sound across the diff --git a/src/c_dispatch.cpp b/src/c_dispatch.cpp index 66878b4a6..f9c1b6c0f 100644 --- a/src/c_dispatch.cpp +++ b/src/c_dispatch.cpp @@ -116,7 +116,9 @@ FButtonStatus Button_Mlook, Button_Klook, Button_Use, Button_AltAttack, Button_Attack, Button_Speed, Button_MoveRight, Button_MoveLeft, Button_Strafe, Button_LookDown, Button_LookUp, Button_Back, Button_Forward, Button_Right, Button_Left, Button_MoveDown, - Button_MoveUp, Button_Jump, Button_ShowScores, Button_Crouch; + Button_MoveUp, Button_Jump, Button_ShowScores, Button_Crouch, + Button_Zoom, Button_Reload, + Button_User1, Button_User2, Button_User3, Button_User4; bool ParsingKeyConf; @@ -128,11 +130,16 @@ bool ParsingKeyConf; FActionMap ActionMaps[] = { + { 0x125f5226, &Button_User2, "user2" }, { 0x1eefa611, &Button_Jump, "jump" }, { 0x201f1c55, &Button_Right, "right" }, + { 0x20ccc4d5, &Button_Zoom, "zoom" }, { 0x23a99cd7, &Button_Back, "back" }, + { 0x426b69e7, &Button_Reload, "reload" }, { 0x4463f43a, &Button_LookDown, "lookdown" }, + { 0x534c30ee, &Button_User4, "user4" }, { 0x5622bf42, &Button_Attack, "attack" }, + { 0x577712d0, &Button_User1, "user1" }, { 0x57c25cb2, &Button_Klook, "klook" }, { 0x59f3e907, &Button_Forward, "forward" }, { 0x6167ce99, &Button_MoveDown, "movedown" }, @@ -143,6 +150,7 @@ FActionMap ActionMaps[] = { 0xab2c3e71, &Button_Crouch, "crouch" }, { 0xb000b483, &Button_Left, "left" }, { 0xb62b1e49, &Button_LookUp, "lookup" }, + { 0xb6f8fe92, &Button_User3, "user3" }, { 0xb7e6a54b, &Button_Strafe, "strafe" }, { 0xd5897c73, &Button_ShowScores, "showscores" }, { 0xe0ccb317, &Button_Speed, "speed" }, diff --git a/src/c_dispatch.h b/src/c_dispatch.h index 3fb14b2f7..c297a7514 100644 --- a/src/c_dispatch.h +++ b/src/c_dispatch.h @@ -149,7 +149,9 @@ extern FButtonStatus Button_Mlook, Button_Klook, Button_Use, Button_AltAttack, Button_Attack, Button_Speed, Button_MoveRight, Button_MoveLeft, Button_Strafe, Button_LookDown, Button_LookUp, Button_Back, Button_Forward, Button_Right, Button_Left, Button_MoveDown, - Button_MoveUp, Button_Jump, Button_ShowScores, Button_Crouch; + Button_MoveUp, Button_Jump, Button_ShowScores, Button_Crouch, + Button_Zoom, Button_Reload, + Button_User1, Button_User2, Button_User3, Button_User4; extern bool ParsingKeyConf; void ResetButtonTriggers (); // Call ResetTriggers for all buttons diff --git a/src/d_event.h b/src/d_event.h index c54c56afe..6a164138a 100644 --- a/src/d_event.h +++ b/src/d_event.h @@ -76,18 +76,40 @@ typedef enum // // Button/action code definitions. +// The net code supports up to 29 buttons, so don't make this longer than that. // typedef enum { - BT_ATTACK = 1, // Press "Fire". - BT_USE = 2, // Use button, to open doors, activate switches. - BT_JUMP = 4, - BT_DUCK = 8, // Unimplemented - BT_TURN180 = 16, - BT_ALTATTACK = 32, // Press your other "Fire". -} buttoncode_t; + BT_ATTACK = 1<<0, // Press "Fire". + BT_USE = 1<<1, // Use button, to open doors, activate switches. + BT_JUMP = 1<<2, + BT_CROUCH = 1<<3, + BT_TURN180 = 1<<4, + BT_ALTATTACK = 1<<5, // Press your other "Fire". + BT_RELOAD = 1<<6, // Not connected to anything at the moment. + BT_ZOOM = 1<<7, // Neither is this. -#define IMP_WEAPONSLOT + // The rest are all ignored by the play simulation and are for scripts. + BT_SPEED = 1<<8, + BT_STRAFE = 1<<9, + + BT_MOVERIGHT = 1<<10, + BT_MOVELEFT = 1<<11, + BT_BACK = 1<<12, + BT_FORWARD = 1<<13, + BT_RIGHT = 1<<14, + BT_LEFT = 1<<15, + BT_LOOKUP = 1<<16, + BT_LOOKDOWN = 1<<17, + BT_MOVEUP = 1<<18, + BT_MOVEDOWN = 1<<19, + BT_SHOWSCORES = 1<<20, + + BT_USER1 = 1<<21, + BT_USER2 = 1<<22, + BT_USER3 = 1<<23, + BT_USER4 = 1<<24, +} buttoncode_t; // diff --git a/src/d_player.h b/src/d_player.h index c722aa914..824144538 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -200,6 +200,8 @@ public: APlayerPawn *mo; BYTE playerstate; ticcmd_t cmd; + usercmd_t original_cmd; + DWORD original_oldbuttons; userinfo_t userinfo; // [RH] who is this? @@ -220,8 +222,8 @@ public: bool centering; BYTE turnticks; - short oldbuttons; bool attackdown; + DWORD oldbuttons; int health; // only used between levels, mo->health // is used during levels diff --git a/src/d_protocol.cpp b/src/d_protocol.cpp index 91db0a5de..f59c89f4b 100644 --- a/src/d_protocol.cpp +++ b/src/d_protocol.cpp @@ -150,8 +150,30 @@ int UnpackUserCmd (usercmd_t *ucmd, const usercmd_t *basis, BYTE **stream) if (flags) { + // We can support up to 29 buttons, using from 0 to 4 bytes to store them. if (flags & UCMDF_BUTTONS) - ucmd->buttons = ReadByte (stream); + { + DWORD buttons = ucmd->buttons; + BYTE in = ReadByte(stream); + + buttons = (buttons & ~0x7F) | (in & 0x7F); + if (in & 0x80) + { + in = ReadByte(stream); + buttons = (buttons & ~(0x7F << 7)) | ((in & 0x7F) << 7); + if (in & 0x80) + { + in = ReadByte(stream); + buttons = (buttons & ~(0x7F << 14)) | ((in & 0x7F) << 14); + if (in & 0x80) + { + in = ReadByte(stream); + buttons = (buttons & ~(0xFF << 21)) | (in << 21); + } + } + } + ucmd->buttons = buttons; + } if (flags & UCMDF_PITCH) ucmd->pitch = ReadWord (stream); if (flags & UCMDF_YAW) @@ -176,6 +198,7 @@ int PackUserCmd (const usercmd_t *ucmd, const usercmd_t *basis, BYTE **stream) BYTE *temp = *stream; BYTE *start = *stream; usercmd_t blank; + DWORD buttons_changed; if (basis == NULL) { @@ -185,10 +208,41 @@ int PackUserCmd (const usercmd_t *ucmd, const usercmd_t *basis, BYTE **stream) WriteByte (0, stream); // Make room for the packing bits - if (ucmd->buttons != basis->buttons) + buttons_changed = ucmd->buttons ^ basis->buttons; + if (buttons_changed != 0) { + BYTE bytes[4] = { ucmd->buttons & 0x7F, + (ucmd->buttons >> 7) & 0x7F, + (ucmd->buttons >> 14) & 0x7F, + (ucmd->buttons >> 21) & 0xFF }; + flags |= UCMDF_BUTTONS; - WriteByte (ucmd->buttons, stream); + + if (buttons_changed & 0xFFFFFF80) + { + bytes[0] |= 0x80; + if (buttons_changed & 0xFFFFC000) + { + bytes[1] |= 0x80; + if (buttons_changed & 0xFFE00000) + { + bytes[2] |= 0x80; + } + } + } + WriteByte (bytes[0], stream); + if (bytes[0] & 0x80) + { + WriteByte (bytes[1], stream); + if (bytes[1] & 0x80) + { + WriteByte (bytes[2], stream); + if (bytes[2] & 0x80) + { + WriteByte (bytes[3], stream); + } + } + } } if (ucmd->pitch != basis->pitch) { @@ -299,13 +353,25 @@ int SkipTicCmd (BYTE **stream, int count) { moreticdata = false; skip = 1; - if (*flow & UCMDF_BUTTONS) skip += 1; if (*flow & UCMDF_PITCH) skip += 2; if (*flow & UCMDF_YAW) skip += 2; if (*flow & UCMDF_FORWARDMOVE) skip += 2; if (*flow & UCMDF_SIDEMOVE) skip += 2; if (*flow & UCMDF_UPMOVE) skip += 2; if (*flow & UCMDF_ROLL) skip += 2; + if (*flow & UCMDF_BUTTONS) + { + if (*++flow & 0x80) + { + if (*++flow & 0x80) + { + if (*++flow & 0x80) + { + ++flow; + } + } + } + } flow += skip; } else if (type == DEM_EMPTYUSERCMD) diff --git a/src/d_protocol.h b/src/d_protocol.h index 1ddf0e0e8..0bd28b4a2 100644 --- a/src/d_protocol.h +++ b/src/d_protocol.h @@ -69,11 +69,10 @@ struct zdemoheader_s { struct usercmd_s { - BYTE buttons; - BYTE pad; + DWORD buttons; short pitch; // up/down - short yaw; // left/right // If you haven't guessed, I just - short roll; // tilt // ripped these from Quake2's usercmd. + short yaw; // left/right + short roll; // "tilt" short forwardmove; short sidemove; short upmove; @@ -92,7 +91,7 @@ enum UCMDF_FORWARDMOVE = 0x08, UCMDF_SIDEMOVE = 0x10, UCMDF_UPMOVE = 0x20, - UCMDF_ROLL = 0x40 + UCMDF_ROLL = 0x40, }; // When changing the following enum, be sure to update Net_SkipCommand() diff --git a/src/d_ticcmd.h b/src/d_ticcmd.h index 3e458f608..7828d2f50 100644 --- a/src/d_ticcmd.h +++ b/src/d_ticcmd.h @@ -33,11 +33,6 @@ struct ticcmd_t { usercmd_t ucmd; -/* - char forwardmove; // *2048 for move - char sidemove; // *2048 for move - short angleturn; // <<16 for angle delta -*/ SWORD consistancy; // checks for net game }; diff --git a/src/g_game.cpp b/src/g_game.cpp index 0de51d25b..616d48715 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -531,20 +531,32 @@ void G_BuildTiccmd (ticcmd_t *cmd) side -= sidemove[speed]; // buttons - if (Button_Attack.bDown) - cmd->ucmd.buttons |= BT_ATTACK; + if (Button_Attack.bDown) cmd->ucmd.buttons |= BT_ATTACK; + if (Button_AltAttack.bDown) cmd->ucmd.buttons |= BT_ALTATTACK; + if (Button_Use.bDown) cmd->ucmd.buttons |= BT_USE; + if (Button_Jump.bDown) cmd->ucmd.buttons |= BT_JUMP; + if (Button_Crouch.bDown) cmd->ucmd.buttons |= BT_CROUCH; + if (Button_Zoom.bDown) cmd->ucmd.buttons |= BT_ZOOM; + if (Button_Reload.bDown) cmd->ucmd.buttons |= BT_RELOAD; - if (Button_AltAttack.bDown) - cmd->ucmd.buttons |= BT_ALTATTACK; + if (Button_User1.bDown) cmd->ucmd.buttons |= BT_USER1; + if (Button_User2.bDown) cmd->ucmd.buttons |= BT_USER2; + if (Button_User3.bDown) cmd->ucmd.buttons |= BT_USER3; + if (Button_User4.bDown) cmd->ucmd.buttons |= BT_USER4; - if (Button_Use.bDown) - cmd->ucmd.buttons |= BT_USE; - - if (Button_Jump.bDown) - cmd->ucmd.buttons |= BT_JUMP; - - if (Button_Crouch.bDown) - cmd->ucmd.buttons |= BT_DUCK; + if (Button_Speed.bDown) cmd->ucmd.buttons |= BT_SPEED; + if (Button_Strafe.bDown) cmd->ucmd.buttons |= BT_STRAFE; + if (Button_MoveRight.bDown) cmd->ucmd.buttons |= BT_MOVERIGHT; + if (Button_MoveLeft.bDown) cmd->ucmd.buttons |= BT_MOVELEFT; + if (Button_LookDown.bDown) cmd->ucmd.buttons |= BT_LOOKDOWN; + if (Button_LookUp.bDown) cmd->ucmd.buttons |= BT_LOOKUP; + if (Button_Back.bDown) cmd->ucmd.buttons |= BT_BACK; + if (Button_Forward.bDown) cmd->ucmd.buttons |= BT_FORWARD; + if (Button_Right.bDown) cmd->ucmd.buttons |= BT_RIGHT; + if (Button_Left.bDown) cmd->ucmd.buttons |= BT_LEFT; + if (Button_MoveDown.bDown) cmd->ucmd.buttons |= BT_MOVEDOWN; + if (Button_MoveUp.bDown) cmd->ucmd.buttons |= BT_MOVEUP; + if (Button_ShowScores.bDown) cmd->ucmd.buttons |= BT_SHOWSCORES; // [RH] Scale joystick moves to full range of allowed speeds if (JoyAxes[JOYAXIS_PITCH] != 0) @@ -1208,7 +1220,8 @@ void G_PlayerReborn (int player) p->skill = b_skill; //Added by MC: - p->oldbuttons = 255, p->attackdown = true; // don't do anything immediately + p->oldbuttons = ~0, p->attackdown = true; // don't do anything immediately + p->original_oldbuttons = ~0; p->playerstate = PST_LIVE; if (gamestate != GS_TITLELEVEL) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index ca59f9a42..926a7a833 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -2382,6 +2382,77 @@ int DLevelScript::GetActorProperty (int tid, int property) } } +enum +{ + // These are the original inputs sent by the player. + INPUT_OLDBUTTONS, + INPUT_BUTTONS, + INPUT_PITCH, + INPUT_YAW, + INPUT_ROLL, + INPUT_FORWARDMOVE, + INPUT_SIDEMOVE, + INPUT_UPMOVE, + + // These are the inputs, as modified by P_PlayerThink(). + // Most of the time, these will match the original inputs, but + // they can be different if a player is frozen or using a + // chainsaw. + MODINPUT_OLDBUTTONS, + MODINPUT_BUTTONS, + MODINPUT_PITCH, + MODINPUT_YAW, + MODINPUT_ROLL, + MODINPUT_FORWARDMOVE, + MODINPUT_SIDEMOVE, + MODINPUT_UPMOVE +}; + +int DLevelScript::GetPlayerInput(int playernum, int inputnum) +{ + player_t *p; + + if (playernum < 0) + { + p = activator->player; + } + else if (playernum >= MAXPLAYERS || !playeringame[playernum]) + { + return 0; + } + else + { + p = &players[playernum]; + } + if (p == NULL) + { + return 0; + } + + switch (inputnum) + { + case INPUT_OLDBUTTONS: return p->original_oldbuttons; break; + case INPUT_BUTTONS: return p->original_cmd.buttons; break; + case INPUT_PITCH: return p->original_cmd.pitch; break; + case INPUT_YAW: return p->original_cmd.yaw; break; + case INPUT_ROLL: return p->original_cmd.roll; break; + case INPUT_FORWARDMOVE: return p->original_cmd.forwardmove; break; + case INPUT_SIDEMOVE: return p->original_cmd.sidemove; break; + case INPUT_UPMOVE: return p->original_cmd.upmove; break; + + case MODINPUT_OLDBUTTONS: return p->oldbuttons; break; + case MODINPUT_BUTTONS: return p->cmd.ucmd.buttons; break; + case MODINPUT_PITCH: return p->cmd.ucmd.pitch; break; + case MODINPUT_YAW: return p->cmd.ucmd.yaw; break; + case MODINPUT_ROLL: return p->cmd.ucmd.roll; break; + case MODINPUT_FORWARDMOVE: return p->cmd.ucmd.forwardmove; break; + case MODINPUT_SIDEMOVE: return p->cmd.ucmd.sidemove; break; + case MODINPUT_UPMOVE: return p->cmd.ucmd.upmove; break; + + default: return 0; break; + } +} + #define NEXTWORD (LittleLong(*pc++)) #define NEXTBYTE (fmt==ACS_LittleEnhanced?getbyte(pc):NEXTWORD) #define STACK(a) (Stack[sp - (a)]) @@ -4946,6 +5017,11 @@ int DLevelScript::RunScript () sp -= 1; break; + case PCD_GETPLAYERINPUT: + STACK(2) = GetPlayerInput (STACK(2), STACK(1)); + sp -= 1; + break; + case PCD_PLAYERNUMBER: if (activator == NULL || activator->player == NULL) { diff --git a/src/p_acs.h b/src/p_acs.h index 0485a5d67..630dc408f 100644 --- a/src/p_acs.h +++ b/src/p_acs.h @@ -553,8 +553,9 @@ public: PCD_CHECKPLAYERCAMERA, // [TN] PCD_MORPHACTOR, // [MH] PCD_UNMORPHACTOR, // [MH] + PCD_GETPLAYERINPUT, - PCODE_COMMAND_COUNT +/*348*/ PCODE_COMMAND_COUNT }; // Some constants used by ACS scripts @@ -689,6 +690,7 @@ protected: void SetActorProperty (int tid, int property, int value); void DoSetActorProperty (AActor *actor, int property, int value); int GetActorProperty (int tid, int property); + int GetPlayerInput (int playernum, int inputnum); private: DLevelScript (); diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 0ce0760ac..667b71b33 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -2455,7 +2455,9 @@ enum }; FUNC(LS_SetPlayerProperty) -// SetPlayerProperty (who, set, which) +// SetPlayerProperty (who, value, which) +// who == 0: set activator's property +// who == 1: set every player's property { int mask = 0; diff --git a/src/p_user.cpp b/src/p_user.cpp index 42260e1d5..bd01dd01e 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1955,6 +1955,11 @@ void P_PlayerThink (player_t *player) player->mo->flags &= ~MF_NOCLIP; } cmd = &player->cmd; + + // Make unmodified copies for ACS's GetPlayerInput. + player->original_oldbuttons = player->original_cmd.buttons; + player->original_cmd = cmd->ucmd; + if (player->mo->flags & MF_JUSTATTACKED) { // Chainsaw/Gauntlets attack auto forward motion cmd->ucmd.yaw = 0; @@ -1990,7 +1995,10 @@ void P_PlayerThink (player_t *player) } // Handle crouching - if (player->cmd.ucmd.buttons & BT_JUMP) player->cmd.ucmd.buttons &= ~BT_DUCK; + if (player->cmd.ucmd.buttons & BT_CROUCH) + { + player->cmd.ucmd.buttons &= ~BT_CROUCH; + } if (player->morphTics == 0 && player->health > 0 && level.IsCrouchingAllowed()) { if (!(player->cheats & CF_TOTALLYFROZEN)) @@ -1999,9 +2007,9 @@ void P_PlayerThink (player_t *player) if (crouchdir==0) { - crouchdir = (player->cmd.ucmd.buttons & BT_DUCK)? -1 : 1; + crouchdir = (player->cmd.ucmd.buttons & BT_CROUCH)? -1 : 1; } - else if (player->cmd.ucmd.buttons & BT_DUCK) + else if (player->cmd.ucmd.buttons & BT_CROUCH) { player->crouching=0; } @@ -2452,7 +2460,9 @@ void player_t::Serialize (FArchive &arc) arc << crouchfactor << crouching << crouchdir - << crouchviewdelta; + << crouchviewdelta + << original_cmd + << original_oldbuttons; if (isbot) { @@ -2486,6 +2496,7 @@ void player_t::Serialize (FArchive &arc) // If the player reloaded because they pressed +use after dying, we // don't want +use to still be down after the game is loaded. oldbuttons = ~0; + original_oldbuttons = ~0; } } diff --git a/src/version.h b/src/version.h index b5975207d..ff6bff6a5 100644 --- a/src/version.h +++ b/src/version.h @@ -54,7 +54,7 @@ // Version identifier for network games. // Bump it every time you do a release unless you're certain you // didn't change anything that will affect sync. -#define NETGAMEVERSION 216 +#define NETGAMEVERSION 217 // Version stored in the ini's [LastRun] section. // Bump it if you made some configuration change that you want to @@ -64,7 +64,7 @@ // Protocol version used in demos. // Bump it if you change existing DEM_ commands or add new ones. // Otherwise, it should be safe to leave it alone. -#define DEMOGAMEVERSION 0x20C +#define DEMOGAMEVERSION 0x20D // Minimum demo version we can play. // Bump it whenever you change or remove existing DEM_ commands. @@ -75,7 +75,7 @@ // SAVESIG should match SAVEVER. // MINSAVEVER is the minimum level snapshot version that can be loaded. -#define MINSAVEVER 1209 +#define MINSAVEVER 1215 #if SVN_REVISION_NUMBER < MINSAVEVER // Never write a savegame with a version lower than what we need