xttl Posted December 13, 2015 Ever wanted to play vanilla Heretic or Hexen with mouselook or freelook like in ZDoom and other advanced ports? Well now you can! First, disable internal mouse support from Setup (set your controller to keyboard only). Then, download this little program, place it into the same directory with your vanilla game executable file and run it. Sensitivity and button mappings can be adjusted with command line parameters, use ravmouse -? to see how. It works fine in demos and netgames even if the other players do not have ravmouse. It should also work fine with Heretic+, Hexen+, heretic.com and any other EXE hacks you might be using since it doesn't modify the executable at all. Tested in DOSBox only so far but I see no reason why it wouldn't work on real hardware. Source code (for 16-bit Open Watcom) here if you're interested. EXE hack for Strife, this one does not support demos or multiplayer... 8 Quote Share this post Link to post
Da Werecat Posted December 13, 2015 I expected slow keyboard-like handling, but I was pleasantly surprised. Since decent mouse look is possible with the original executables, maybe Chocolate Heretic and Hexen (and Strife?) could have this option. 0 Quote Share this post Link to post
xttl Posted December 13, 2015 It uses this: http://doomwiki.org/wiki/External_control_driver Because the external input driver API in Heretic and Hexen was intended to be used (among other things) by VR hardware with head tracking, it allowss setting the view pitch and yaw in the game. Since vertical aiming is always locked (when autoaim doesn't kick in, anyway) to the orientation of the camera, or your head, setting the pitch field is actually also useful for implementing real functional mouselook in vanilla even though this'd be considered a limitation in real VR use. I don't know if this is possible to do in Strife, it definitely has support for external control drivers but since it isn't open source, I don't know the buffer format and whether it allows for something like this. If it is possible, I'll add support for Strife later. nope, but have a hacked EXE instead I may also improve the program otherwise, would be handy to have the settings in a configuration file at least, perhaps integrate the functionality of Heretic/Hexen+ or heretic.com. 2 Quote Share this post Link to post
ReFracture Posted December 13, 2015 Edit: Disregard, this was a problem with how I setup dosbox. Neat stuff! Neat, I got horizontal mouse movement and the mappings working, but I can't seem to get vertical mouselook to work. I created a new hexen.cfg and set it to keyboard only and tried playing with -vs values.. no dice though. 0 Quote Share this post Link to post
xttl Posted December 13, 2015 Turns out it is not possible to use an external input driver to do this in Strife, so here is a hacked EXE for that instead. This one will break demos and multiplayer, but since Strife does not support coop, nobody plays Strife deathmatch and vanilla Strife demo recording is broken in SP anyway I don't think it matters. Just run that instead of strife1.exe, no way to adjust vertical sensitivity separately from horizontal, at least not yet but I hope the hardcoded divisor feels ok. 0 Quote Share this post Link to post
VGA Posted December 14, 2015 Will you do a little write up about your findings before you forget the specifics? I'm talking about the strife hacked exe, since you provided the code for the tool. Also, thanks and a job well done !! I will test it out for myself in the next days. 0 Quote Share this post Link to post
xttl Posted December 14, 2015 Ok. The patch for Strife is actually quite simple, it works like this: First, as in all games using the Doom engine, there is a function called G_BuildTiccmd. This function builds ticcmds based on input from keyboard, mouse, joystick, or an external control driver. As you may already know, these ticcmds are what get sent over the network in multiplayer games and (partially) recorded in demo files. Unlike Heretic and Hexen, Strife's ticcmds do not support fine control over how much the player is turning up/down on any given gametic. Instead, there are only 3 extended button flags (0/1 toggles) provided for this. (Chocolate Strife calls them BT2_CENTERVIEW, BT2_LOOKUP and BT2_LOOKDOWN) Anyway, inside this same function, global variable mousey (set by G_Responder) is used for adjusting forwards/backwards movement for the current ticcmd. Basically, the patch works by changing "forward += mousey;" to:players[0].pitch += mousey >> 3; if (players[0].pitch > LOOKUPMAX) players[0].pitch = LOOKUPMAX; else if (players[0].pitch < LOOKDOWNMAX) players[0].pitch = LOOKDOWNMAX;Since this bypasses the ticcmd system and just writes to player #1's player_t structure directly it won't work over the network or get recorded in demos. (However, on the other hand, it actually allows for slightly finer control over looking up/down than is possible in Heretic and Hexen via ticcmds!) I also removed this part if (cmd->buttons2 & BT2_CENTERVIEW) player->centerview = 1; if (player->centerview) { if (player->pitch <= 0) { if (player->pitch < 0) player->pitch = player->pitch + CENTERVIEWAMOUNT; } else { player->pitch = player->pitch - CENTERVIEWAMOUNT; } if (abs(player->pitch) < CENTERVIEWAMOUNT) { player->pitch = 0; player->centerview = 0; } }from P_MovePlayer completely to free some space for patching the binary equivalent of the first code snippet in. Doing this also handily prevents automatic view centering every time you try to press the run key (or all the time if you're using the always run hack) or fall down from a jump. 0 Quote Share this post Link to post
fraggle Posted December 14, 2015 Your links are all broken for me. Nice hack though. Reminds me that I never got around to updating my Control API library code to support the -externdriver mechanism. 0 Quote Share this post Link to post
xttl Posted August 21, 2016 I updated the driver for Heretic and Hexen a bit. New binary and source. Source code is also available from here in case there's a problem with those links. Spoiler #include <stdio.h> #include <stdarg.h> #include <stdlib.h> #include <mem.h> #include <i86.h> #include <process.h> #include <dos.h> #include <malloc.h> #include <io.h> #include <stdint.h> // // From Heretic / Hexen source code, definition of the structure that an // external input driver must fill and button action flags. // #define EBT_FIRE 1 #define EBT_OPENDOOR 2 #define EBT_SPEED 4 #define EBT_STRAFE 8 #define EBT_MAP 0x10 #define EBT_INVENTORYLEFT 0x20 #define EBT_INVENTORYRIGHT 0x40 #define EBT_USEARTIFACT 0x80 #define EBT_FLYDROP 0x100 #define EBT_CENTERVIEW 0x200 #define EBT_PAUSE 0x400 #define EBT_WEAPONCYCLE 0x800 #define EBT_JUMP 0x1000 typedef _Packed struct { int16_t vector; // Interrupt vector int8_t moveForward; // forward/backward (-50 to 50) int8_t moveSideways; // strafe (-50 to 50) int16_t angleTurn; // turning speed (640 [slow] 1280 [fast]) int16_t angleHead; // head angle (+2080 [left] : 0 [center] : -2048 [right]) int8_t pitch; // look up/down (-110 : +90) int8_t flyDirection; // flyheight (+1/-1) uint16_t buttons; // EBT_* flags } externdata_t; #define MOUSE_INTNUM 0x33 #define MOUSE_RESET 0 #define MOUSE_GETMICKEYS 11 #define MOUSE_GETBUTTONS 3 #define MY_DEFAULT_INTNUM 0x64 #define DEFAULT_HSENS 40 #define DEFAULT_VSENS 1 #define DEFAULT_DCLICKTICS 20 externdata_t extdata; void interrupt (*saved_vector) (void); int vector_is_hooked = 0; union REGPACK regs; // these can be changed from the config file or command line int myintnum = MY_DEFAULT_INTNUM; int h_sensitivity = DEFAULT_HSENS; int v_sensitivity = DEFAULT_VSENS; int dclicktics = DEFAULT_DCLICKTICS; #define NUM_BUTTONS 3 // left right middle int clickactions[NUM_BUTTONS] = {EBT_FIRE, EBT_STRAFE, 0}; int dclickactions[NUM_BUTTONS] = {0, EBT_OPENDOOR, EBT_CENTERVIEW}; // need to know this to time double clicks properly int ticdup; int myargc; char **myargv; void Error (char *error, ...) { va_list argptr; if (vector_is_hooked) _dos_setvect (myintnum, saved_vector); printf ("Error: "); va_start (argptr,error); vprintf (error,argptr); va_end (argptr); printf ("\n"); exit(-1); } int CheckParmWithArgs(char *parm, int num_args) { int i; for (i = 1; i < myargc-num_args; i++) { if (!stricmp(parm, myargv[i])) return i; } return 0; } int CheckParm (char *parm) { return CheckParmWithArgs (parm, 0); } int InitMouse (void) { regs.w.ax = MOUSE_RESET; intr (MOUSE_INTNUM, ®s); if (regs.w.ax == 0xFFFF) return 1; // mouse driver installed else return 0; // not installed } void interrupt ControlISR (void) { static int pitch = 0; static int dclicktime[NUM_BUTTONS]={0,0,0}; static int dclickstate[NUM_BUTTONS]={0,0,0}; static int dclicks[NUM_BUTTONS]={0,0,0}; int mbuttons[NUM_BUTTONS]={0,0,0}; int i; long int mxmove, mymove; extdata.buttons = 0; regs.w.ax = MOUSE_GETBUTTONS; intr (MOUSE_INTNUM, ®s); if (regs.w.bx & 1) mbuttons[0] = 1; if (regs.w.bx & 2) mbuttons[1] = 1; if (regs.w.bx & 4) mbuttons[2] = 1; for (i=0; i<NUM_BUTTONS; i++) { if (mbuttons[i]) extdata.buttons |= clickactions[i]; if (mbuttons[i] != dclickstate[i] && dclicktime[i] > 1) { dclickstate[i] = mbuttons[i]; if (dclickstate[i]) dclicks[i]++; if (dclicks[i]==2) { extdata.buttons |= dclickactions[i]; dclicks[i] = 0; } else dclicktime[i] = 0; } else { dclicktime[i] += ticdup; if (dclicktime[i] > dclicktics) { dclicks[i] = 0; dclickstate[i] = 0; } } } regs.w.ax = MOUSE_GETMICKEYS; intr (MOUSE_INTNUM, ®s); extdata.angleTurn = regs.w.cx * h_sensitivity; // must be inverted when not strafing if (!(extdata.buttons & EBT_STRAFE)) extdata.angleTurn = -extdata.angleTurn; if (extdata.buttons & EBT_CENTERVIEW) pitch = 0; else { pitch -= regs.w.dx * v_sensitivity; if (pitch < -110) pitch = -110; else if (pitch > 90) pitch = 90; } extdata.pitch = pitch; return; } int main (int argc, char **argv) { unsigned long flataddr; unsigned char far *vector; char *launchcmd; char **spawnargs; int p; printf ("\n"\ "RAVMOUSE - External mouse driver with mouselook for Heretic/Hexen\n"\ "by xttl@dwf, built on " __DATE__ " " __TIME__ "\n"\ "\n"); myargc = argc; myargv = argv; if (CheckParm("-?")) { printf ("-rmvec int......: Specify alternate interrupt vector (default 0x%02X).\n", myintnum); printf ("-hs/-vs num.....: Change horizontal/vertical sensitivity (defaults %i/%i).\n", h_sensitivity, v_sensitivity); printf ("-game/-exe/-exec: Specify game launch command other than \"heretic\"/\"hexen\".\n"); printf ("-dctics num.....: Change double click timing window (default is %i gametics).\n", dclicktics); printf ("-mb#/-db# flags.: Change button single click (-mb#) or double click (-db#)\n"\ " action flags. Left mouse button is #1, right button is #2\n"\ " and middle button is #3. Defaults are MB1=fire, MB2=strafe,\n"\ " MB3=do nothing, DB1=do nothing, DB2=open/use, and\n"\ " DB3=center view.\n"); printf ("\n"\ "Action flags: 0x0001 = fire 0x0002 = use\n"\ " 0x0004 = run 0x0008 = strafe\n"\ " 0x0010 = automap 0x0020 = inventory left\n"\ " 0x0040 = inventory right 0x0080 = use artifact\n"\ " 0x0100 = stop flying 0x0200 = center view\n"\ " 0x0400 = toggle pause 0x0800 = cycle weapons\n"\ " 0x1000 = jump (Hexen only) \n"\ " * Flags can be added together if you want to bind multiple actions to a\n"\ " single mouse button. For example: -mb3 0x81 = fire AND use artifact\n"\ " when you press the middle button.\n"); return -1; } if (!InitMouse()) Error ("Mouse driver not detected."); // must know this to time double clicks properly p = CheckParmWithArgs("-dup", 1); if (p) sscanf(myargv[p+1], "%i", &ticdup); else ticdup = 1; p = CheckParmWithArgs("-dctics", 1); if (p) dclicktics = atoi(myargv[p+1]); p = CheckParmWithArgs("-rmvec", 1); if (p) sscanf(myargv[p+1], "0x%x", &myintnum); p = CheckParmWithArgs("-hs",1); if (p) h_sensitivity = atoi(myargv[p+1]); p = CheckParmWithArgs("-vs", 1); if (p) v_sensitivity = atoi(myargv[p+1]); p = CheckParmWithArgs("-mb1",1); if (p) sscanf(myargv[p+1], "0x%x", &clickactions[0]); p = CheckParmWithArgs("-mb2",1); if (p) sscanf(myargv[p+1], "0x%x", &clickactions[1]); p = CheckParmWithArgs("-mb3",1); if (p) sscanf(myargv[p+1], "0x%x", &clickactions[2]); p = CheckParmWithArgs("-db1",1); if (p) sscanf(myargv[p+1], "0x%x", &dclickactions[0]); p = CheckParmWithArgs("-db2",1); if (p) sscanf(myargv[p+1], "0x%x", &dclickactions[1]); p = CheckParmWithArgs("-db3",1); if (p) sscanf(myargv[p+1], "0x%x", &dclickactions[2]); memset (&extdata, 0, sizeof(externdata_t)); extdata.vector = myintnum; // add extra args for passing the address of the buffer to the game // and also to disable the game's internal mouse support spawnargs = malloc ((myargc+4)*sizeof(char*)); memcpy (spawnargs, myargv, myargc*sizeof(char*)); spawnargs[myargc] = "-externdriver"; spawnargs[myargc+1] = alloca(32); flataddr = (long)FP_SEG(&extdata)*16 + (unsigned)(&extdata); sprintf (spawnargs[myargc+1], "%li", flataddr); spawnargs[myargc+2] = "-nomouse"; spawnargs[myargc+3] = NULL; // custom game launch command specified? p = CheckParmWithArgs("-exec", 1); if (!p) p = CheckParmWithArgs("-game", 1); if (!p) p = CheckParmWithArgs("-exe", 1); if (p) launchcmd = myargv[p+1]; // else try the defaults else { if (!access("HERETIC.EXE", 0) || !access("HERETIC.COM", 0)) launchcmd = "heretic"; else if (!access("HEXEN.EXE", 0) || !access("HEXEN.COM", 0)) launchcmd = "hexen"; else { Error ("No Heretic or Hexen executables in current directory and no\n"\ "alternate launch command was specified."); } } // hook the interrupt vector = *(char far * far *)(myintnum*4); if (vector != NULL && *vector != 0xCF) // 0xCF = x86 IRET Error ("Interrupt vector 0x%02X is already hooked.", myintnum); saved_vector = _dos_getvect (myintnum); _dos_setvect (myintnum, (void interrupt (*)(void))MK_FP(FP_SEG(ControlISR),(int)ControlISR)); vector_is_hooked = 1; // launch the game if (spawnv (P_WAIT, launchcmd, (const char **)spawnargs) == -1) printf ("spawnv(%s) failed: %i (%s)\n", launchcmd, errno, strerror(errno)); // restore interrupt _dos_setvect (myintnum, saved_vector); return 0; } It supports binding actions to double clicks now. The default double click timing window is 20 gametics (approx. 0,6 seconds), the same length as the internal mouse support of those games use, this can be adjusted from the command line with -dctics. By default, double clicking the left mouse button does nothing, double clicking the right button acts as the use key and double clicking the middle button will center your view. View centering also actually works now (from the mouse, still not from keyboard but in the previous version it didn't work at all) and is why I added double clicking support, since it's not an action I wanted to waste a button on but which can still be useful: level changes, respawns and restarting the game or loading a save from the menu can cause the game's idea and the driver's idea of the current view pitch to go out of sync with each other, which will prevent you from looking up/down all the way until you resynchronize them. In the previous version this could be done by moving the mouse enough in the direction opposite the way you couldn't look, but now you can just bind something to the centerview action. Also, it automatically passes -nomouse to the game now so you don't have to write it yourself anymore or remember to disable internal mouse support from setup. I wish there was a way to get notified of level changes, restarts and any other events which may reset the view pitch but seems that's not possible without patching the games (and might as well make the mlook support internal at that point...) 0 Quote Share this post Link to post
kb1 Posted August 24, 2016 Dos your Heretic patch build onto Heretic Plus? (You know, Heretic, patched to support higher limits, like visplanes, and samegame size?). By the way, very nice modifications - this is great stuff! 0 Quote Share this post Link to post
xttl Posted August 25, 2016 kb1 said:Dos your Heretic patch build onto Heretic Plus? (You know, Heretic, patched to support higher limits, like visplanes, and samegame size?). By the way, very nice modifications - this is great stuff! It does not need to patch the EXE at all so yes, it'll work with Heretic+ or Hexen+. It would work even if you recompiled Heretic or Hexen from sources using Open Watcom with some drastic changes as long as you keep the -externdriver API intact. 0 Quote Share this post Link to post
kb1 Posted August 25, 2016 xttl said:It does not need to patch the EXE at all so yes, it'll work with Heretic+ or Hexen+. It would work even if you recompiled Heretic or Hexen from sources using Open Watcom with some drastic changes as long as you keep the -externdriver API intact.Oh, duh, I got you. Very cool! 0 Quote Share this post Link to post
Volo Posted October 13, 2018 (edited) Guys, Please re-upload the ravmouse.exe binary. I really need it for real hardware. If no one has it, I'll try to compile from source, but I have NO IDEA how it's done. Edited October 13, 2018 by Volo 0 Quote Share this post Link to post
chungy Posted October 13, 2018 Looks like archive.org captured it: https://web.archive.org/web/20160902221258/http://koti.kapsi.fi/vv/ravmouse.exe 3 Quote Share this post Link to post
Volo Posted October 14, 2018 Thanks, chungy! 👍 I'll have it running this week. My collection of ancient WASD-moselook games is shaping up! (Future Shock, Duke3D, Eradicator and now Heretic) Is there something similar for Doom? As of now - I have to resort to modifying MOUSE.COM parameters to kill mouse Y-axis and make x-axis more sensitive. It works, but not on any PC. 0 Quote Share this post Link to post
Linguica Posted October 14, 2018 32 minutes ago, Volo said: Is there something similar for Doom? You could use an old DOS port like Doom Legacy, but no, there is no freelook in standard Doom. 1 Quote Share this post Link to post
Gez Posted October 14, 2018 43 minutes ago, Volo said: Is there something similar for Doom? Contrarily to Heretic, Hexen, and Strife; Doom (as well as Chex Quest which only had minimal changes) do not have a concept of looking up and down, so there's no hook in the game code for that. You need to provide a custom engine with this function plugged in, and that's where you're directed to the width and breadth of source port choices. 0 Quote Share this post Link to post
Volo Posted October 14, 2018 Thanks guys, I don't want mouselook in Doom. I want to stop the doomguy from mouse-running. Just to kill Y-axis altogether. I do it by manipulating drivers (made a .bat file for starting the game), but that's, ahem, not the most elegant solution. Is there any better? 0 Quote Share this post Link to post
Linguica Posted October 14, 2018 Oh, then you want https://www.doomworld.com/idgames/utils/misc/novert 1 Quote Share this post Link to post
MaxRideWizardLord Posted September 19, 2019 (edited) While freelook is nice, it kinda gives too much advantage over what HeXen originally meant to be. Maybe I'm just afraid of third party programms... However, does anyone know how to disable mouse movement completely? NOW this is trully annoying, so when I try to look around, I accidently move forward and backward which often result to my doom. Is there a way to adjust it in configurations manually, without downloading anything else? Edited September 19, 2019 by MaxRideWizardLord 0 Quote Share this post Link to post
fabian Posted September 19, 2019 Well, linguica provided the link literally in the previous post. 0 Quote Share this post Link to post
MaxRideWizardLord Posted September 19, 2019 4 hours ago, fabian said: Well, linguica provided the link literally in the previous post. This require downloading a new third party programm, however. What exactly novert does and is there a way to replicate it manually without actually downloading? 0 Quote Share this post Link to post
chungy Posted September 19, 2019 If you follow the link, it gives you a description right there to tell exactly what novert does. If that's not good enough for you, use any source port; pretty much all of them have the functionality built-in. 1 Quote Share this post Link to post
MaxRideWizardLord Posted September 19, 2019 1 hour ago, chungy said: If you follow the link, it gives you a description right there to tell exactly what novert does. If that's not good enough for you, use any source port; pretty much all of them have the functionality built-in. It just says what it's used for, not exactly what it does and how. I was just wonder if this file does change the .cfg file or something of that matter, so I'm curious if it this novert can be replicated with notepad or similar thing? The .zip contains some novert.com mysterious file, I have no idea what it does and what is it for. 0 Quote Share this post Link to post
CyberDreams Posted September 30, 2019 @MaxRideWizardLord As far as i know, novert is a DOS TSR (terminate and stay resident program) that disables vertical mouse movement in Doom (and similar games). Linguica wouldn't link you to anything that is harmful. The link is straight to the idgames directory so it's perfectly safe. Also, novert is only for DOS (as well as DOSBox from what i've read) so you might be better off using a source port since those usually have options to disable the Y-axis for the mouse. The "mysterious file" is the application. I don't know if novert changes your config file as i have never used it. 1 Quote Share this post Link to post
Edward850 Posted September 30, 2019 (edited) 2 hours ago, CyberDreams said: The "mysterious file" is the application. I don't know if novert changes your config file as i have never used it. It's a TSR program, put simply it plonks itself into DOS memory and nullifies all vertical mouse input for the remainder of the DOS session. So it doesn't change anything config related, but due to the way it operates it only works in DOS and Win95/98 (and Windows 3.1 I believe, though I've never tired it in that environment). Edited September 30, 2019 by Edward850 0 Quote Share this post Link to post
chungy Posted September 30, 2019 I recall that novert did some weird things with mouse support in non-Doom games and applications, so you'd unload it if you weren't running Doom. And no, it's not a config file change. If it were, we wouldn't have needed that program :) 0 Quote Share this post Link to post
OpenRift Posted April 17, 2021 Don't mean to resurrect a dead thread, but I finally got around to giving this a try and found that the vertical sensitivity is way higher than the horizontal, even when -vs is set to 1. How would I go about changing the code to have a lower overall sensitivity? 0 Quote Share this post Link to post
Nikku4211 Posted August 28, 2021 I've tried Ravmouse on both DOSBox-X and DOSBox-ECE and the mouse didn't work at all. I set the setup to keyboard only like what was asked, and the exe is in the same directory as the game. 0 Quote Share this post Link to post
xttl Posted August 29, 2021 (edited) On 4/18/2021 at 2:11 AM, OpenRift said: Don't mean to resurrect a dead thread, but I finally got around to giving this a try and found that the vertical sensitivity is way higher than the horizontal, even when -vs is set to 1. How would I go about changing the code to have a lower overall sensitivity? I updated the program at some point to support negative values for -vs, which is (perhaps counterintuitively, you might expect it to invert direction) interpreted as meaning that the vertical input value from the mouse driver is to be divided by that value (absolute value to be precise) rather than multiplied, but seems the version on archive.org is too old as is the version I've posted as an attachment here once before. Here's a version with that feature (and 16-bit Open Watcom C source) included: ravmouse2.zip Note that the limited vertical look resolution afforded by the external control API starts to become more and more of an issue the lower you go in vertical sensitivity. This really needs to be a heretic.exe/hexen.exe modification anyway because there is no way for the external control driver to know if the view pitch has been reset (by teleportation, level exit, etc.) or if the game was paused or in menus when mouse was moved, both things which it really needs to know due to the way looking up/down via the external control API works. It seems a bit difficult to even solve this by reading game memory from the driver because it is a 16-bit real mode program and the game is running in protected mode using memory above 1MB. On 8/28/2021 at 10:04 AM, Nikku4211 said: I've tried Ravmouse on both DOSBox-X and DOSBox-ECE and the mouse didn't work at all. No idea why that might be. :( (assuming mouse is fully working in other games and programs) Edited August 29, 2021 by xttl 2 Quote Share this post Link to post
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.