Announcement

Collapse
No announcement yet.

Running Multiple Engines Against 1 ID1 (or mod) Folder

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Running Multiple Engines Against 1 ID1 (or mod) Folder

    The concepts stated below were intended to be utilized from the radiant build menu. From that angle, the possibilities that this creates make sense. Be warned however that, this script is incomplete in the sense that a solid way to juggle .cfg files was never implemented. I remember that my method was going to be to store .cfg files in the engine folder that corresponds, and upon using that engine, it's .cfg would overwrite whatever .cfg is in the ID1 folder. To handle if a change was made to the config between opening and closing the engine was going to be a manual system (ie you move the new .cfg to the proper engine folder). I understand that isn't ideal but the original purpose of this was to allow map developers to test their maps on numerous engines, and my line of thinking was: if someone is going so vanilla there probably wouldn't be many changes being made to .cfg files.

    With no further ado, How to do it...

    The entire meat and potatoes of this relies on 2 things

    1) Directory Structure


    ignore proxy.bat. It's purpose was radiant related and isn't necessary for using my scripts this way.

    2) Run.bat

    I put a bunch of stuff in here that is not necessary but, can be handy to force certain results early on

    Code:
    :: turn off console printing for a moment
    @echo off
    
    :: set some user options
    set height=720
    set width=1200
    set conheight=480
    set conwidth=768
    set gamename=id1
    
    :: set path to the directory which this bat resides in
    set path=%~dp0
    
    :: change CWD to current directory
    cd /d %path%
    
    :: turn printing back on
    ECHO.
    
    :: make sure there is any data at all
    if "%1" EQU "" goto ENG_ERR
    
    :: make sure there is a map name
    if "%2" EQU "" (goTo MAP_ERR) else set map=%~n2
    
    :: print out the current commandline variables
    ECHO Label: %1
    ECHO -basedir %path%
    ECHO -game %gamename%
    ECHO +map: %map%
    
    :: determine which engine was chosen
    if "%1" EQU "darkplaces" goto DP
    if "%1" EQU "darkplaces_develop" goto DP_DEV
    if "%1" EQU "fitzquake" goto FQ
    if "%1" EQU "proquake" goto PQ
    if "%1" EQU "qbismsuper8" goto QBS8
    if "%1" EQU "fteqw" goto FTE
    if "%1" EQU "qrack" goto QR
    if "%1" EQU "quakespasm" goto QS
    if "%1" EQU "directq" goto DQ
    
    :: unrecognized label
    :UNR_ERR
    ECHO their is no engine path associated with this label: %1
    goto END
    
    :: there are no commands
    :ENG_ERR
    ECHO you didn't specify anything
    goto END
    
    :: no map name was specified
    :MAP_ERR
    ECHO you didn't specify a map
    goto END
    
    
    :: run the commandline that corresponds with the "case" provided by %1
    :DP
    set engine=%path%darkplaces\darkplaces.exe
    ECHO Engine Path: %engine%
    %engine% -basedir %path% -game %gamename% +map %map% -width %width% -height %height% -conwidth %conwidth% -conheight %conheight% -window
    goto END
    
    :DP_DEV
    set engine=%path%darkplaces\darkplaces.exe
    ECHO Engine Path: %engine%
    %engine% -basedir %path% -game %gamename% +map %map% -width %width% -height %height% -conwidth %conwidth% -conheight %conheight% -window
    goto END
    
    :FQ
    set engine=%path%fitzquake\fitzquake085.exe
    ECHO Engine Path: %engine%
    %engine% -basedir %path% -game %gamename% +map %map% -width %width% -height %height% -conwidth %conwidth% -conheight %conheight% -window -bpp 32
    goto END
    
    :PQ
    set engine=%path%proquake\glpro493.exe
    ECHO Engine Path: %engine%
    %engine% -basedir %path% -game %gamename% +map %map% -width %width% -height %height% -conwidth %conwidth% -conheight %conheight% -window -bpp 32
    goto END
    
    :FTE
    set engine=%path%fteqw\fteqw.exe
    ECHO Engine Path: %engine%
    %engine% -basedir %path% -game %gamename% +map %map% -width %width% -height %height% -conwidth %conwidth% -conheight %conheight% -window
    goto END
    
    :QBS8
    set engine=%path%qbismsuper8\qbismS8.exe
    ECHO Engine Path: %engine%
    %engine% -nocdaudio -basedir %path% -game %gamename% +map %map%
    goto END
    
    :QR
    set engine=%path%qrack\glQrack.exe
    ECHO Engine Path: %engine%
    %engine% -basedir %path% -game %gamename% +map %map% -width %width% -height %height% -conwidth %conwidth% -conheight %conheight% -window -bpp 32
    goto END
    
    :QS
    set engine=%path%quakespasm\quakespasm.exe
    ECHO Engine Path: %engine%
    %engine% -nocdaudio -basedir %path% -game %gamename% +map %map%
    goto END
    
    :DQ
    set engine=%path%directq\DirectQ.exe
    ECHO Engine Path: %engine%
    %engine% -basedir %path% -game %gamename% +map %map% -width %width% -height %height% -conwidth %conwidth% -conheight %conheight% -window -bpp 32
    goto END
    
    :END
    PAUSE
    
    EXIT
    note that double colons denote a comment whereas, single colon is a label. Also, EQU is a comparison equals (==).

    To utilize this script is simple:

    :> Run.bat "fitzquake" "e1m1"

    A menu could be made fairly easy where each engine would be tied to a %choice% and then you are asked to type the mapname. Maybe I'll spin a simple one today. I forgot I can program in this language, and it might be fun to play with it for a minute.

    Edit: whoops I forgot to implement the -developer flag in the DP_DEV build. I didn't add it in during this edit cause I don't remember if there is more to it and I don't feel like looking it up.

    Edit2: I remember that QubismSuper8 does not like this method at all. I never could get it to run properly. The rest of the engines work fine.
    Last edited by MadGypsy; 03-25-2015, 07:08 AM.

  • TheRealMadGypsy
    replied
    I finished this project a while back. It has the following features:

    1) Load any map in any engine (except engineX)
    2) Load any demo in any engine (except engineX)
    3) Run "no-map" mods (like smc) from a game folder of it's own. For instance you do not need to put RogueSMC in your Rogue folder. It can be put in some other folder and run using Rogue as a "basegame"
    4) Paks are searched and archived for maps and demos, meaning if you choose a game to run, you are automatically presented with all the maps and/or demos for that game as a list of choices. In the case of "no-map" mods (like smc) you are presented with a list based on the "basegame" for that mod
    5) all configs (regardless of what they are named) get juggled in the background according to the engine you choose.
    6) you are presented with the final commandline that is created based on all of your choices and you can further modify this manually before running the game
    7) an entire profile system which allows you to save/load profiles based on choices you have made regarding a specific game. So let's say you chose darkplaces, rogue, R1m1, some other commandline options, etc... you can save that profile and bring it all back just as you selected it, with one click
    a simple .cfg editor, really this is not even as robust as notepad BUT it brings up the config for the engine you selected. So, instead of looking around for configs, you simply select the engine you want to use and the .cfg that appears will be the one for that engine.

    There are more and more options but these are the most powerful. All engines get stored in an engines directory and all games get stored in a game directory. Unlike how the normal system works, where you would need a game directory in every engine directory, my method separates all of the coupling and repetition of the standard method. All engines and games get recorded and presented to you in a selectable list format. Basically you can load any game/demo in any engine with little more than a few clicks. My system does not work with engineX for reasons that must be engine related. I have loaded games with every engine you can imagine, with no issues, except engineX. Even old engines work.

    My app uses NO batch files. It is windows only but the entire app was built using vbscript, jquery/javascript, html, css & a couple of 3rd party .exe tools. The third party tools just do 2 things. One of them searches all paks for maps, demos and records their filenames, the other makes the xml database that is created pretty (humanly readable). The app is wrapped in an .HTA and runs as if it was an .exe (ie... not in your browser).

    The original app was named AQuake, then it was changed to Dark_Roast (based on the color theme of the app and Dark & Roast being words that can apply to Quake). The final App name is Dark Arts, has an entirely new theme and all the code has been rewritten from the ground up to be clean, optimized and (hopefully) glitch free.

    I would share this app, but I am not posting one more piece of my work here til I get my account back. If I never get it back,... I will never share this. I am not giving away more of my efforts while I am locked out of 4 years worth of them.
    Last edited by TheRealMadGypsy; 06-23-2015, 07:42 PM.

    Leave a comment:


  • MadGypsy
    replied


    Doesn't look like much, does it? Psssh, this menu is elite as fuck for batch script.

    Features:

    Create a menu from directories, specific filetypes and/or file contents
    All input (number or "manual") is checked within context for legitimacy (existence)
    All invalid input is discarded and the menu refreshes, allowing you to try again.
    Choose items by number or use 0 option and input them manually
    Automatic pagination of long lists

    That's the basic menu class description but, implementation is as simple as one line of code. You can even chain menus to create some pretty powerful menu systems. Here is the line of code that implemented the menu in the image.

    Code:
    call path\menus.cmd "contents" "Choose_A_Map:" "path\id1.lst"
    That's it. That's all it takes to build completed menus with all the bells and whistles, utilizing my menu script.


    For anybody that actually reads the code, here is the source to my menu class.

    menus.cmd
    Code:
    @echo off
    
    REM # Create a list...
    REM - of specific files in a path 
    REM - from the contents of a file
    REM - from the folders in a directory
    REM - from a range of map values
    
    REM # Automatically paginate long lists
    REM - pagination options only appear if max list options exceed page length
    REM - "-" & "+" keys paginate list
    REM - pagination options only display currently possible paging directions
    
    REM # Allow 0 option
    REM - option to input the value of your number choice manually
    REM - input is compared in context for existance
    
    :constructor
      SetLocal
        ::establish that everything is in order
        if not "%~1"=="" (set "case=%~1")    else goto :case_error "constructor"
        if not "%~2"=="" (set "title=%~2")   else set "title=Menu:"
        if not "%~3"=="" (set "pointer=%~3") else goto pointer_error "constructor"
        if not "%~4"=="" (set "arg1=%~4")    else set "arg1=*"
        if not "%~5"=="" set "max=%~5"
        
        call :menu_header %title
        
        ::set valid menu selection switches
        set "access=0"
        set "pagination=0"
        set "page_prev=0"
        set "page_next=0"
        
        ::set page length
        set "page=9"
        
        ::set the current maximum viewed list number to 0
        if "%case%"=="range_map" (set "cmax=%arg1%") else set "cmax=%page%"
        
        ::include manual input in the list
        echo. 0. manual input
        
        ::prints an ordered list, returns %map% of the list, returns %max% of the maximum list number
        if "%case%"=="contents"  call :content_list %pointer%
        if "%case%"=="directory" call :directory_list %pointer%
        if "%case%"=="files"     call :file_list %pointer% %arg1%
        
        ::returns %cmax% instead of max and doesn't return a map
        if "%case%"=="range_map" call :range_map_list %pointer% %arg1% 
        
        ::pagination options
        if %max% gtr %page% set "pagination=1"
        if %pagination% equ 1 if %cmax% gtr %page% set "page_prev=1"
        if %pagination% equ 1 if %cmax% lss %max% set "page_next=1"
        if %pagination% equ 1 echo.
        
        if %pagination% equ 1 echo. page options:
        if %page_prev% equ 1 echo. - previous
        if %page_next% equ 1 echo. + next
        if %pagination% equ 1 echo.
        
        ::allow the user to select a number
        set /p "choice=  >" 
        
        ::catch empty input
        if "%choice%"=="" set "choice=0"
        
        set /a "diff=max%%page"
        set /a "prev=(cmax-(page*2))+1"
        if not %cmax% lss %max% set /a "prev=(max-(page+diff))+1"
        if %prev% lss 1 set "prev=1"
        
        if %page_prev% equ 1 if "%choice%"=="-" set /a "arg1=prev"&set "access=3"
        if %page_next% equ 1 if "%choice%"=="+" set /a "arg1=cmax+1"&set "access=3"
        
        if not %access% equ 3 if not %choice% gtr %max% set "access=1"
        if %choice% equ 0 if %access% equ 1 set "access=2"
        
        ::if the choice was 
        if %access% equ 3 call :constructor "range_map" %title% %map% %arg1% %max%
        if %access% equ 3 set "parse_map=%value%"
        
        ::if the choice was 
        if %access% equ 2 call :user_input %map% %choice%
        if %access% equ 2 set "parse_map=%user_input%"
        
        ::returns %parse_map% as the value of the chosen number 
        if %access% equ 1 call :parse_map %map% "%choice%"
        
        ::if the choice was not valid, call this constructor again and pass it's return value to this instances %parse_map%
        if %access% equ 0 echo.
        if %access% equ 0 echo.%choice% is not a valid selection
        if %access% equ 0 pause&call :constructor %case% %title% %pointer% %arg1% %max%
        if %access% equ 0 set "parse_map=%value%"
        
      EndLocal&(
        set "value=%parse_map%"
      )&goto :eof
      
    REM ---Various methods of looping remote data to create lists
    
    :content_list
      ::expansion is enabled here in order for i to increment
      SetLocal EnableDelayedExpansion
        set /a i=0
    	
        ::get every line from the file
        for /f "delims=" %%d in (%~1) do (
          set /a i=i+1
          ::build a map of number value pairs, where the value is the current line of the file
          if not "!return_map!"=="" (set "return_map=!return_map!+!i!:%%d") else set "return_map=!i!:%%d"
          ::align and print list
          if not !i! gtr %page% echo. !i!. %%d
        )
        echo.
      EndLocal&(
        set "map=%return_map%"
        set "max=%i%"
      )&goto :eof
      
    :file_list
      ::expansion is enabled here in order for i to increment
      SetLocal EnableDelayedExpansion
        set /a i=0
    	
        ::get every file of a specific type within a directory
        for %%d in (%~1\*.%~2) do (
          set /a i=i+1
          ::build a map of number value pairs, where the value is the current filename.ext
          if not "!return_map!"=="" (set "return_map=!return_map!+!i!:%%~nxd") else set "return_map=!i!:%%~nxd"
          ::align and print list
          if not !i! gtr %page% echo. !i!. %%~nd
        )
        echo.
      EndLocal&(
        set "map=%return_map%"
        set "max=%i%"
      )&goto :eof
     
    :directory_list
      SetLocal EnableDelayedExpansion
        set /a i=0
    	
        ::get every directory within a directory
        for /d %%d in (%~1\*.*) do (
          set /a i=i+1
          ::build a map of number value pairs, where the value is the current filename.ext
          if not "!return_map!"=="" (set "return_map=!return_map!+!i!:%%~nd") else set "return_map=!i!:%%~nd"
          ::align and print list
          if not !i! gtr %page% echo. !i!. %%~nd
        )
        echo.
      EndLocal&(
        set "map=%return_map%"
        set "max=%i%"
      )&goto :eof
        
    :range_map_list
      SetLocal EnableDelayedExpansion
        set /a "i=0"
        set /a "e=%~2+(page-1)"
        ::get a range of options from a map
        for /l %%d in (%~2,1,%e%) do (
          if not %%d gtr %max% call :parse_map "%~1" %%d
          ::if not %%d gtr %max% set "parse_map=%parse_map:.=&rem.%"
          if not %%d gtr %max% echo. %%d. !parse_map!
          if not %%d gtr %max% set "i=%%d"
        )
        echo.
      EndLocal&(
        set "map=%~1"
        set "cmax=%i%"
      )&goto :eof
      
    REM ---Parse the value of a selected number from a map of choices
    
    :parse_map
      SetLocal
        ::establish that everything is in order
        if not "%~1"=="" (set "m=%~1") else goto :map_error %0
        if not "%~2"=="" (set "i=%~2") else goto :case_error %0
    	
        ::parse the value of the selected number from the map
        call set return=%%m:*%i%:=%%
        set return=%return:+=&rem.%
    	
      EndLocal&(
        set "parse_map=%return%"
      )&goto :eof
      
    :parse_input
      SetLocal
        set "return=0"
    	
        ::establish that everything is in order
        if not "%~1"=="" (set "m=%~1") else goto map_error %0
        if not "%~2"=="" (set "c=%~2") else goto :case_error %0
    	
        ::parse the value of the selected number from the map
        call set temp=%%m:*:%c%+=%%
        if not "%temp%"=="%m%" set "return=1"
    	
      EndLocal&(
        set "parse_input=%return%
      )&goto :eof
      
    REM ---Switch to user input mode
    
    :user_input
      SetLocal
        echo.
        echo. Type the name of your selection:
        set /p "return=>"
    
        call :parse_input "%~1" "%return%"
        if %parse_input% equ 0 set "return="	
      EndLocal&(
        set "user_input=%return%
      )&goto :eof
      
    REM ---Simple menu header
      
    :menu_header
      set t=%title:_= %
      cls
      echo.
      echo. %t%
      echo.
      goto :eof
    
    REM ---Various errors
    
    :case_error
      echo.menu.cmd::%~1 
      echo.A case has not been supplied
      pause&goto :eof
     
    :map_error
      echo.menu.cmd::%~1
      echo.A map has not been supplied
      pause&goto :eof
    
    :pointer_error
      echo.menu.cmd::%~1
      echo.You have not supplied a pointer to the file or folder that you want to access
      pause&goto :eof
    Last edited by MadGypsy; 04-09-2015, 05:49 PM.

    Leave a comment:


  • MadGypsy
    replied
    Lol, I know nobody cares about this thread but, I am keeping it alive because I have not stopped working on "enginator". I have built more and more advanced versions of it about 4 or 5 times now. They all work and they all do almost the same thing. The difference between them is the sophistication of the code. My current level is a bit like treating remote batch scripts like classes (as much as possible). I think this is the last rewrite cause, the code is finally resembling how I would program in a more OOP friendly language. I've got abstraction, encap, inheritance... probably more stuff but, that's what I can think of off the top.

    Some of you may wonder why I have put so much energy into this. Well, it hasn't really been that much energy, an hour or two every night since my first post and two (maybe 3) entire days. That's time learning and implementing.

    My focus on this is because this language is very different from the grand majority of languages that I know. It's taken me 2 weeks to figure out how to apply advanced programming concepts to this language. Batch script is not your friend. It is a bitch. Look at the most bare bones structure for a function

    Code:
    set "reference_var="
    
    call :template reference_var
    
    :template
      set_local
        set "return_value="
        //do work that ultimately sets return_value
      (endlocal
        set "%~1=%return_value%"
        goto :eof
      )
    Just this simple process has so much going on that it's suffocating.

    A var is passed by reference to a subroutine with no argument interface. A value within a local block (contained vars expire) is assigned. Delayed Expansion is raped from the endlocal to maintain the dynamically created value and assign it to the reference that was initially passed.

    Psssh... all that just for a returnable function. This is not the work around. This is how you do it.

    note: The (endlocal stuff) above is the fancy way of putting all the code on one line without it actually being on one line
    Code:
      these are the same thing
    
      (endlocal
        set "%~1=%return_value%"
        goto :eof
      )
    
      endlocal&set "%~1=%return_value%"&goto :eof
    Anyway, I have given this language time and energy because it is so different. I program in a bunch of languages because this is what I do, learn them. VBScript has me interested on the same level batch scripting does. It's syntax needs therapy.

    EDIT: Earlier I said "They all work and they all do almost the same thing." I meant how they internally work. My latest version of enginator is beast far more ellaborate than any version before it. It does EVERY fucking thing. You put engines in the engines folder and games in the games folder, start enginator. That's it. No renaming anything. Nothing confusing. The program holds your hand almost the entire way. About the only way you could fuck up is to type a mapname that doesn't exist or include an invalid switch in one of the command line files. The map thing is semi fixed cause, if your maps folders are un-paked (at least upon first run/install), my app will make a list of all available maps (without including bsp models). That list becomes a number choice menu. The engines and games choices already work this way. This means only cmd line switches allow unverified user input and there is no way around that really. I'm not writing cmd line switch profiles for every possible engine.
    Last edited by MadGypsy; 04-07-2015, 10:24 AM.

    Leave a comment:


  • MadGypsy
    replied
    Whoops, I realized the huge flaw in my last post. It's a write-only system. You can't actually read any of those arguments... lol. Oh well, back to the drawing board.

    Leave a comment:


  • MadGypsy
    replied


    hah, look at the results of my little experiment. The main.bat file creates a var, passes it by reference to a remote bat, and then echoes successful results. This happens without the called bat (funcs.bat) ever opening visually.

    My funcs.bat has a work-around for having to create cases for every possible function that may be included in the document. It relies on you providing the proper subroutine and then allows up to 7 arguments. Placeholder vars are used as reference and then the original references are reassigned the new values accordingly. This is probably not the best way to do this but, it works, and it's reusable. It also allows me to keep my script cleaner in the long run.

    this:

    set "ref1="
    call remote.bat ":label" ref1

    is as close as I can get to:

    public var ref1:SomeType = src.class.ExternalClass::labelAsFunc() as SomeType

    You may also notice that I have upgraded my batch scripting even more. I'm using a different method of delayed expansion, returning input, using remote scripts... I'm gonna have this language licked in another couple of days.
    Last edited by MadGypsy; 04-06-2015, 11:50 AM.

    Leave a comment:


  • MadGypsy
    replied
    Bat tut

    I don't want this thread to die just yet. The "theme" (to some degree) was batch scripting. That being said and due to the fact that I have polished my bat skills, I decided to post a bit of a tutorial here.

    The point of this tutorial is to illustrate a menu system. The system works by creating text files with no extension, in the same directory as the bat. The file names double as menu titles. The contents of the files become menu options. The system maps all possible options and retrieves the option name due to the number you chose. This is illustrated by a sophisticated case system that can determine which option you chose and from which menu it came. Included is also a check that the user choice is within the range of possible choices and the menu is reset upon invalid choices being made. This all sounds very complicated but, I'm posting it and went to the trouble to create/comment this because it is actually very simple. If you remove all comments this script is like 62 lines, very tight.

    This is the results of the bat script


    Below are the 4 files needed for this example. All the menu files/options are arbitrary and serve as placeholders for an actual menu. The bat script is fully ::commented and should serve as the body of this tutorial.

    example\menu.bat
    Code:
    @echo off
    
    :main
      ::create a list of filenames to loop through
      set menus="menuOne;menuTwo;menuThree"
      
      ::localize enviro vars and expand vars at execution (vs parse)
      setlocal EnableDelayedExpansion
      
      ::send the menu list through the switch loop
      call :menu_from_file_switch %menus%
      
      ::program is complete
      goto end
      
    :menu_from_file_switch
      ::get list of cases
      set case=%1
    
      ::rape a for loop for it's delim parsing capabilities
      for /f "tokens=1* delims=;" %%a in (%case%) do (
        ::menu creation and choice subroutine
        call :menu_from_file %%a
        ::if there is more to the list (ex: %%b="menuTwo;menuThree") send it back through
        if not "%%b"=="" call :menu_from_file_switch "%%b"
        ::kill this loop iteration
        if not "%%b"=="" exit /b
      )
    
      ::%%b is empty (="")
      endlocal
      exit /b
    
    :menu_from_file
      ::get path for list content
      ::all files are in the same directory in this example so, only filenames are needed
      set list_path=%1
      
      ::reset choice success
      set pass=0
      ::reset map of choices
      set "map="
      ::reset current max list number
      set /a max=0
      
      ::echo the filepath (filename only in this example), in this case the file has no extension
      ::this means it can be used as a menu name
      echo.
      echo.%list_path%
      
      ::loop through file contents
      for /f "delims=" %%i in (%list_path%) do (
        ::increment current max choice number
        set /a max=max+1
    	::concat num-option to map
    	if not "!map!"=="" (set "map=!map!;!max!-%%i") else set "map=!max!-%%i"
    	::ex 3. someOption
    	echo.!max!. %%i
      )
      
      ::start user input
      set /p choice=Choose an option: 
      
      ::if the user choice is !> than the max possible choice and choice!=0 set choice success
      if not !choice! gtr !max! if not !choice!==0 set pass=1
      
      ::if the choice was not valid give a message and start the choice over
      if !pass! egu 0 echo.!choice! is not a valid option
      if !pass! equ 0 goto menu_from_file %list_path%
      
      ::ex: assume choice = 2
      ::map="1-val1;2-val2;3-val3" call set choice= "val2;3-val3"
      if !pass! equ 1 call set choice=%%map:*%choice%-=%%
      ::remove from the first ; clean to the end of the string
      if !pass! equ 1 set value=%choice:;=&rem.%
      
      ::switch through menu possibilities
      if !pass! equ 1 if "%list_path%"=="menuOne" call :one %value%
      if !pass! equ 1 if "%list_path%"=="menuTwo" call :two %value%
      if !pass! equ 1 if "%list_path%"=="menuThree" call :three %value%
      
      ::same as exit /b ... exits this subroutine but not the entire script
      goto :eof
    
    ::a bunch of generic subroutines to illustrate cases
    :one
       set opt=%1
       echo.menuOne: You chose %opt%
       echo.
       exit /b
    :two
       set opt=%1
       echo.menuTwo: You chose %opt%
       echo.
       exit /b
    :three
       set opt=%1
       echo.menuThree: You chose %opt%
       echo.
       exit /b
    
    :end
      ::this is a done deal but stay open until the user presses a key
      pause
      ::upon keypress
      exit
    Note that each menu ends with one line break. This is necessary to be properly parsed.

    example\menuOne
    Code:
    A
    B
    C
    D
    example\menuTwo
    Code:
    aa
    bb
    cc
    dd
    example\menuThree
    Code:
    AaA
    BaB
    CaC
    DaD
    EaE
    FaF
    GaG
    My enginator menu (last posted) utilizes some of these concepts but, where it differs greatly is: This menu uses recursion for a repeatable menu system. My other bat used "spaghetti programming" - where things are repeated instead of recursed.

    ie - do this 3 times VS do this, then do this again but a lil different, then do this again but different still (but not different enough to be 3 separate things)

    Notes:

    My "cases" (ne,:two,:three) may seem repetitive but, this is because this is not a real world example. Those cases could do very different things, completely different. That's the whole power behind the menu. The case will only be hit by the menu that corresponds and the case knows the exact value of the chosen option (you could make more cases). consider:

    menuThree:
    set opt=%1
    if "%opt"=="AaA" do Something
    if "%opt"=="BaB" do Something
    if "%opt"=="CaC" do Something
    etc...

    You could build an entire text option game with this one menu concept.

    Bonus @echo , echo. , echo

    @echo on/off (turns on/off constant echo)
    echo. -> echoes regardless of @echo status
    echo -> echoes only if @echo on, otherwise prints "echo is off"

    I also wanted to post a no-comment version. I don't know about all programmers but personally, I like uncommented code versions. I can read the commented one once or twice and then run the uncommented one in my head. With the exception of QC. QC is usually commented to the side, which is not as distracting.

    Code:
    @echo off
    
    :main
      set menus="menuOne;menuTwo;menuThree"
      setlocal EnableDelayedExpansion
      call :menu_from_file_switch %menus%
      goto end
      
    :menu_from_file_switch
      set case=%1
      for /f "tokens=1* delims=;" %%a in (%case%) do (
        call :menu_from_file %%a
        if not "%%b"=="" call :menu_from_file_switch "%%b"
        if not "%%b"=="" exit /b
      )
      endlocal
      exit /b
    
    :menu_from_file
      set list_path=%1
      set pass=0
      set "map="
      set /a max=0
      
      echo.
      echo.%list_path%
      
      for /f "delims=" %%i in (%list_path%) do (
        set /a max=max+1
    	if not "!map!"=="" (set "map=!map!;!max!-%%i") else set "map=!max!-%%i"
    	echo.!max!. %%i
      )
      
      set /p choice=Choose an option: 
      if not !choice! gtr !max! if not !choice!==0 set pass=1
      if !pass! equ 0 echo.!choice! is not a valid option
      if !pass! equ 0 goto menu_from_file %list_path%
      if !pass! equ 1 call set choice=%%map:*%choice%-=%%
      if !pass! equ 1 set value=%choice:;=&rem.%
      if !pass! equ 1 if "%list_path%"=="menuOne" call :one %value%
      if !pass! equ 1 if "%list_path%"=="menuTwo" call :two %value%
      if !pass! equ 1 if "%list_path%"=="menuThree" call :three %value%
      goto :eof
    
    :one
       set opt=%1
       echo.menuOne: You chose %opt%
       echo.
       exit /b
    :two
       set opt=%1
       echo.menuTwo: You chose %opt%
       echo.
       exit /b
    :three
       set opt=%1
       echo.menuThree: You chose %opt%
       echo.
       exit /b
    
    :end
      pause
      exit
    Last edited by MadGypsy; 04-02-2015, 06:28 PM.

    Leave a comment:


  • MadGypsy
    replied
    In just one day I have severely upgraded my bat skills. I rewrote this entire thing from the ground up and it is awesome.

    Changes:

    1 everything works (last bat had 2 unlikely mistakes - unlikely you would find them)
    2 install script is separate and only meant to be run if you add an engine or game
    3 better folder structure and dynamic menu system
    4 30% more fiber

    I don't intend to release it yet. I released the gist of it yesterday. Imma let some time go by and come back with a much meaner version.

    Leave a comment:


  • MadGypsy
    replied
    One more thing and I'll stop spamming.

    I built this on a win 8.1 machine. I am not some bat script guru and therefore I have no idea of the backwards/?forwards? compatibility of this script. If you have issues getting something to work, feel free to post here about it and I will attempt to troubleshoot it for you.

    What kind of info do I need regarding issues?

    1) how far did the script get before it failed? ie. what is the last expected line in the console window
    2) what error did it give you?
    3) what windows operating system are you using?

    These are pretty much standard but if you think of anything else that you would like to add, feel free. Also keep in mind that I will be troubleshooting your issue "in the dark". I do not have your operating system or access to a computer that does. This means I may never figure out what is wrong but, I will certainly try.

    I want this to work... period, and I am a talented guy. If my stuff doesn't work, don't get frustrated and assume it is garbage, get proactive. I don't make junk, I simply can't be expected to spit out perfect code for a slew of OS's when I only have 1 OS to test with. If you are using Win 8.1 and you have issues, I call bullshit. Read the directions again.

    The script fails but the console disappears too fast for me to see what it says. What do I do?

    You can write PAUSE on a new line anywhere in the script and it will wait for a keypress to continue. It's a little bit of work but you can keep running the script and moving your PAUSE down the script until it gets to a point where your console spits out the error and then pauses. It's not too hard to isolate where to pause because my script happens "in a row" so you can see how far the script gets and eliminate a bunch of labels as the culprit.

    :ENG_CHOICE <-stuff like this is a label

    An example:
    Let's say the script gets to - use default command line (y/n), you input something and it fails. Well, that is the DEF_CHOICE label, and since my script is linear ALL labels before that are not the problem. Which means PAUSE should be put somewhere after the line that asks you to make a choice. Inputting something other than y or n is not going to be the culprit. My script only cares about y and considers anything that is not a y to be an n. You could even just hit enter and it will assume you mean n (except +skill 0 to 3 or n only, anything else will ask you to set it again).

    This package is pretty portable and can be put basically anywhere on your harddrive BUT it is NOT recommended that you put it anywhere that includes a space or strange characters in the path (ex ProgramFiles (x86)). Will putting it there break it? Probably not but, if it does, it could take forever to isolate that as the problem. Spaces in the path is more of a cygwin console problem but treating all console applications like they have this problem means you will never have this problem.

    If you are a guest using my app and you have issues but don't want to sign up here to report them, you can email me [email protected] however, I check this account very rarely and it may be some time before you get a response. The fastest way to get help is to post in this thread.

    If you have issues AND fix them - please please please post about it here.

    Overall, I'm beating the hell out of this issue drum but you probably aren't going to have any. I ripped a bunch of this script from bats I made on XP. There is a small portion that I'm unsure of (basically my fake array). I just want it to be clear as to how to get me to fix issues and the info I need to start troubleshooting.
    Last edited by MadGypsy; 03-30-2015, 10:57 AM.

    Leave a comment:


  • MadGypsy
    replied
    Do y'all want me to release the bat before I finish the HTA?

    all you have to do is make this directory structure

    Quake(or whatever you want)
    Quake/engines/
    Quake/id1/(or some other game folder)
    Quake/GQE/configs/
    Quake/GQE/configs/cmln (empty text file with no extension - put generic switches in this file)
    Quake/gqe.bat

    or click here for a premade. You need to supply your own id1 (or equivalent) folder
    https://anonfiles.com/file/0b9939852...2c9e68ba92228d

    dump all the engines you want in Quake/engines within properly named folders (same name as engine exe) and start the bat.

    Ex: Quake/engines/glpro493/glpro493.exe

    here Is the bat for people "building" from scratch
    Code:
    :: turn off console printing for a moment
    @echo off
    
    
    :CONFIG
    ::prime some options
    set usedef=0
    set useopt=0
    set engine=0
    
    ::path=directory of this bat
    set path=%~dp0
    ::get the default command line
    set /p default=<%path%GQE\configs\cmln
    ::change CWD to current directory
    cd /d %path%
    ::spam clear
    cls
    
    ::check if this is being caslled from the hta menu
    :CHECK
    ::if the first variable is set
    if not "%1"=="" goto FROM_HTA
    ::else, if it wasn't
    goto ENG_CHOICE
    
    
    ::if %1 was assigned these need to be assigned as well
    :FROM_HTA
    
    ::engine
    set engine=%1
    ::-game
    if "%2"=="" (goto GAM_ERR) else set gameName=%2
    ::+map
    if "%3"=="" (goto MAP_ERR) else set mapName=%~n3
    ::use default commandline
    if not "%4"=="y" (set usedef=n) else set usedef=y
    ::use optional commandline
    if not "%5"=="y" (set useopt=n) else set useopt=y
    ::get optional commandline
    set /p optional=<%path%gqe\configs\%engine%\cmln
    ::+skill
    if not "%6"=="n" (set setskill=%6) else set setskill=n
    goto RUN
    
    ::unspecified stuff
    :GAM_ERR
    ECHO -game was unspecified
    :MAP_ERR
    ECHO +map was unspecified
    goto END
    
    
    :ENG_CHOICE
    @echo off
    set engPath=%path%engines
    cd %engPath%
    
    set /a c=0
    set "eng_map="
    
    setlocal ENABLEDELAYEDEXPANSION
    
    for /d %%a in (*.*) do (
    	@echo off
    	set cfgPath=%path%GQE\configs\%%a\
    	if not exist !cfgPath! md !cfgPath!
    	if not exist !cfgPath!cmdl break>!cfgPath!cmdl
    	
    	set /a c=c+1
    	if not "!eng_map!"=="" set "eng_map=!eng_map!;!c!-%%a"
    	if "!eng_map!"=="" set "eng_map=!c!-%%a"
    	echo.!c!. %%a
    )
    
    set /p v=engine:
    if not "%v%"=="" call set v=%%eng_map:*%v%-=%%
    if not "%v%"=="" set engine=%v:;=&rem.%
    
    if not "%engine%"=="0" goto GAM_CHOICE
    ECHO "%v%" is not a valid choice. Try again
    
    endlocal
    
    goto ENG_CHOICE
    
    :GAM_CHOICE
    ::get optional command line file
    set /p optional=<%path%GQE\configs\%engine%\cmln
    ::start a choice
    set /p gameName=-game:
    ::default to id1 if there is an empty result
    if "%gameName%"=="" set gameName=id1
    
    
    :MAP_CHOICE
    ::start a choice
    set /p mapName=+map:
    ::if a map was given goto +skill choice
    if not "%mapName%"=="" goto SKL_CHOICE
    ::if not...
    ECHO You didn't supply a mapName. Try again.
    ::start the choice over
    goto MAP_CHOICE
    
    :SKL_CHOICE
    ::start a choice
    set /p setskill=+skill (0-easy to 3-nightmare) or n to skip:
    if "%setskill%"=="0" goto RESUME
    if "%setskill%"=="1" goto RESUME
    if "%setskill%"=="2" goto RESUME
    if "%setskill%"=="3" goto RESUME
    if "%setskill%"=="n" goto RESUME
    ::if the choice did not match any of the approved values...
    echo %setskill% is not a valid option
    ::start the choice over
    goto SKL_CHOICE 
    
    
    :RESUME
    if not "%default%"=="" goto DEF_CHOICE
    if not "%optional%"=="" goto OPT_CHOICE
    goto RUN
    
    :DEF_CHOICE
    Echo %default%
    set /p usedef=Use default commandline options (y/n):
    if not "%optional%"=="" goto OPT_CHOICE
    goto RUN
    
    :OPT_CHOICE
    Echo %optional%
    set /p useopt=Use engine specific commandline options (y/n):
    goto RUN
    
    :RUN
    set "base=-basedir %path% -game %gameName% +map %mapName%"
    
    if not "%setskill%"=="n" set "base=%base% +skill %setskill%"
    
    if "%usedef%"=="y" set "base=%base% %default%"
    if "%useopt%"=="y" set "base=%base% %optional%"
    Echo cmd line: %engine%.exe %base%
    
    set enginePath=%path%engines\%engine%\
    cd /d %enginePath%
    
    %engine%.exe %base%
    goto END
    
    :END
    PAUSE
    
    EXIT
    How do you know it really worked, beyond just starting a map in an engine?

    after running the bat once...
    1. Check configs folder. You should have a virtual copy of your engines folder structure and within each folder will be an empty cmln file
    2. Open configs/cmln and type something (preferably switches - ex: -width 1024 -height 768 -window). Now start the bat. When it gets to cmln part it should echo your command line and ask if you want to include it.
    3. Do the same thing as 2 but to configs/someEngine/cmln and with different switches

    My hta eliminates the need to navigate to these files but it isn't complete yet.

    It may seem strange to have a virtualky empty folder (GQE) with nothing but another folder in it. My HTA puts a lot more files in the GQE folder. Basically this is the stripped version, still using the advanced versions folder structure.
    Last edited by MadGypsy; 03-30-2015, 07:32 AM.

    Leave a comment:


  • MadGypsy
    replied
    @rook - I had the +, I just didn't type it in my post

    @talisa - I did like you said and typed "skill" in the console and it said "skill 3, [1]" (in darkplaces). It still didn't seem like nightmare, unless nightmare is super easy.

    ---- fun code stuff

    Here is the part of my bat that creates the engine selection menu on-the-fly, and "installs" it's config folder.

    Array's basically don't exist in batch script so, I had to sort of invent them.

    eng_map basically ends up looking something like this:
    "1-darkplaces;2-DirectQ;3-glpro493;"...etc

    v first gets assigned by the user selection then uses itself to become the answer of itself (sort of...it works whatever I did, lol). Basically this is just a string manipulation that uses v- and ; as delimiters BUT I had to throw some voodoo in the mix with "call set", and that had me stumped for a long time cause I have never even heard of call set. I'm still not 100% sure of what it does but, the results are unarguable.

    Another tricky thing was string concat. My line: set "eng_map=" may look nutty but that is basically creating the var in a way that I can concat to it. I tried it other ways and that is the only one that worked. Finding the proper balance of !var! and %var% in my delayedexpansion was also a bit tricky. I can't lie, bat script has me confused on many levels. I always get this shit to work but, I don't always understand why it works. Searching the internet for some of these answers is futile. Often I end up just resyntaxing things til they finally work.

    break>filepath is a cheap and quick way for me to create a text file if it doesn't exist.

    the results of this code dynamically spit out something like
    1. darkplaces
    2. DirectQ
    3. fitzquake085
    4. fteqw
    5. glpro493
    6. g1Qrack
    7. qbismS8
    8. quakespasm
    choose an engine:

    then your number choice is converted to engineName (via eng_map) and %path%\engines\engineName\engineName.exe becomes the executable. (this part of code is not shown)

    Code:
    :ENG_CHOICE
    @echo off
    set engPath=%path%engines
    cd %engPath%
    
    set /a c=0
    set "eng_map="
    
    setlocal ENABLEDELAYEDEXPANSION
    
    for /d %%a in (*.*) do (
    	@echo off
    	set cfgPath=%path%GQE\configs\%%a\
    	if not exist !cfgPath! md !cfgPath!
    	if not exist !cfgPath!cmln break>!cfgPath!cmln
    	
    	set /a c=c+1
    	if not "!eng_map!"=="" set "eng_map=!eng_map!;!c!-%%a"
    	if "!eng_map!"=="" set "eng_map=!c!-%%a"
    	echo.!c!. %%a
    )
    
    set /p v=engine:
    if not "%v%"=="" call set v=%%eng_map:*%v%-=%%
    if not "%v%"=="" set engine=%v:;=&rem.%
    
    if not "%engine%"=="0" goto GAM_CHOICE
    ECHO "%v%" is not a valid choice. Try again
    
    endlocal
    it works great. All you have to do is dump the engine in Quake/engines/folderNamedAfterExeToRun and start Enginator...voila, no hard coding or other bullshit to do

    EDIT WOOOOPS:
    line 72: if not exist !cfgPath!cmdl break>!cfgPath!cmdl

    should be:
    if not exist !cfgPath!cmln break>!cfgPath!cmln

    sorry. Already fixed it in the above code
    Last edited by MadGypsy; 03-30-2015, 11:09 AM.

    Leave a comment:


  • R00k
    replied
    Originally posted by MadGypsy View Post
    @skill - i didn't check it via console. I just started e1m1 with skill 3 and it wasn't any different.
    +skill 3, you need the +

    Leave a comment:


  • talisa
    replied
    hmm which engine did you try it in?

    cuz i know it works in darkplaces, i always start all mods and maps using the +skill parameter so i dont have to change the skill via console

    Leave a comment:


  • MadGypsy
    replied
    @skill - i didn't check it via console. I just started e1m1 with skill 3 and it wasn't any different.

    Leave a comment:


  • talisa
    replied
    @gypsy
    it works for me. i always start any maps with the +skill switch

    all my bats i have created for maps and mods include '+skill 3' at the end
    cuz i prefer to play in nightmare and this way i dont have to set it manually after starting the map/mod

    this is something thats engine-independant, it works also in the original quake.

    just try starting an engine with parameter '+skill 3' and then in-game open console and type 'skill' and you'll see its set to that skill

    0 is easy, 1 is normal, 2 is hard, and 3 for nightmare

    .

    regarding documentation about the +skill switch: http://quakewiki.org/wiki/Installing_addons
    right at the bottom of that page is a mention of the +skill parameter
    Last edited by talisa; 03-29-2015, 08:39 AM.

    Leave a comment:

Working...
X