如何在批处理游戏中制作库存

问题描述

我正在尝试创建一个批处理游戏,其中包含类似于 Skyrim、Oblivion 和其他类似游戏的库存。想法是没有固定数量的库存插槽,而是如果现有插槽被占用,游戏会创建一个新插槽。我已经知道如何让游戏检查他们,是的。

if '%item1%'=='blank' (set item1=%item%) else (if '%item1%'=='%item%' set /A item1qua=%item1qua%+1)
if '%item2%'=='blank' (set item2=%item%) else (if '%item2%'=='%item%' set /A item2qua=%item2qua%+1)

我也不知道如何创建一个批处理脚本,每次更改数字,直到发现库存槽为空白。 然后游戏必须在完成后保存所有库存插槽。我目前的方法是这样的:

( Echo @echo off
  Echo set item1=%item1%
  Echo set item1qua=%item1qua%
  Echo set item2=%item2%
  Echo set item2qua=%item2qua%
  Echo set item3=%item3%
  Echo set item3qua=%item3qua%
  Echo set item4=%item4%
  Echo set item4qua=%item4qua%)>>%playername%.bat

术语“qua”仅指数量。 我试过这个代码

set num=1
:inv
if '%item%num%%'=='blank' (set %item%num%%=%item% && goto next) else (set /a num=%num%+1)
goto inv

简而言之,这将随着玩家获得更多物品而扩大库存。 物品会有重量,就像在上古卷轴和其他游戏中一样,我想为玩家添加神圣的烦恼(呵呵),但是,我还希望代码删除额外的“空白”物品槽,而不会留下间隙在编号系统中,例如: item1,item2 item4,item7,item8

我以前的方法是将现有的 .bat 文件和 thw 项目数据复制到母文件夹中,并将其放在其他地方的文件夹中,玩家可以使用 dir 命令查看他们的项目。 可以想象,效率并不高。

我的第二种方法更多是在游戏的 Alpha 阶段,当时它基本上是一个生活模拟器,有点被放弃了,但留在游戏文件夹中以防我再次捡起它:

>>Users\%fname%.bat Echo set weed=%weed%
>>Users\%fname%.bat Echo set money=%money%
>>Users\%fname%.bat Echo set water=%water%
>>Users\%fname%.bat Echo set lighters=%lighters%
>>Users\%fname%.bat Echo set cigarettes=%cigarettes%
>>Users\%fname%.bat Echo set lightbulbs=%lightbulbs%

编辑

感谢 Chris Schaller 提供的链接,我找到了一个可以工作的代码,并根据我的需要进行了编辑。


@echo off
set len=11
set obj[0]=Gold
set obj[1]=Silver
set obj[2]=Sword
set obj[3]=Knife
set obj[4]=Greenfelt
set obj[5]=Amulet
set obj[6]=Chickenleg
set obj[7]=Necklace
set obj[8]=StolenItem
set obj[9]=GoldIngot
set obj[10]=Statuette
set obj[11]=Seeds

set i=0
:loop
if /i %i% equ %len% goto :eof
for /f "usebackq delims== tokens=2" %%j in (`set obj[%i%]`) do (
    echo %%j
)
pause
set /a i=%i%+1
goto loop

代码在某些方面效果很好,但是我如何让 obj[0] 每次增加

A.S.C

解决方法

最简单的方法是让所有必须保存的变量以特殊字符(如 #@~_ 或 .. .) 或字符串(如您编辑中的 obj[)。保存它们就像这样简单:

>Users\%fname%.sav set #

(或使用您编辑中的示例:>Users\%fname%.sav set obj[

并再次阅读它们:

for /f "delims=" %%a in ("users\%fname%.sav") do set "%%a" 
,

您的目标是随着新物品添加到库存而增加计数。

对于这种任务类型,我建议使用一个函数,因为库存管理是批量 rpg 游戏中高度重复的任务。

批处理脚本中的函数是使用重复操作执行的参数调用的标签。

在 RPG 游戏设计的背景下,您需要允许在不同情况下使用,例如添加战利品、购买或奖励到库存。

对于支持类似类型的各种物品的更复杂的游戏,使用 itemtype 数组可以使事情变得更容易 - 想想菜单选项卡,您可以在其中选择武器并获得库存中的武器列表。

下面是一个示例,说明如何编写用于将项目添加到库存的函数的示例,该函数在添加项目之前测试 2 个条件是否有效 - 1) 成本不超过资金,2) 项目的重量不推动总承载重量超过最大值。

itemweight 和 itemcost 值默认为 0,如果调用时没有提供参数以允许没有重量的物品或找到/给定的物品添加到库存中。

@Echo off & Cls
 For /F "Tokens=1 Delims==" %%G in (' Set "#"  2^> nul ')Do Set "%%G="
 Set /A "#Money=100,Maxweight=25000,#weight=0"
::: redirect output of inventory to nul to suppress output of item added to inventory notifcation as desired
 For %%G in ("Healing Potion" "Old Key" "Map")DO Call :Inventory %%G Miscellaneous 10 >nul
 For %%G in ("Vambraces" "Boots of Luck" "Helm")DO Call :Inventory %%G Armor 1000 >nul
 Call :Inventory "Dagger" OneHandedWeapon 250 >nul
 Call :Inventory "Short sword" OneHandedWeapon 4000 >nul
 Call :Inventory "Katana" OneHandedWeapon 4750 > nul
 Set #
 Endlocal
Goto :Eof

:Inventory         <itemname> <itemtype> <itemweight> <itemcost>
::: Remove item:   <itemname> /R
::: undefines all array elements containing itemname in varname or value. Use unique and descriptive Item names.
 If /I "%~2" == "/R" (
  For /F "Tokens=1,2* Delims==" %%G in (' Set "#" 2^> nul ^|%__Appdir__%\findstr.exe /LIC:"%~1" ')Do Set "%%G="
  Goto :getweight
 )
 Set "Itemname=%~1"
 Set "Itemtype=%~2"
 If "%~4"=="" (Set "cost=0")Else (
  Set "cost=%~4"
  For /F %%G in ('Set /A #money-%~4')Do if %%G LSS 0 (
   Echo(You cannot afford %itemname%
   Goto :Eof
  )
 )
 If "%~3" == "" (Set "itemweight=0")Else (
  Set "itemweight=%~3"
  For /F %%G in ('Set /A maxweight-%~3-#weight')Do if %%G LSS 0 (
   Echo/You are carrying too much.
   Goto :Eof
  )
 )
 Set /A "#money-=cost"
 Set "#%itemname%[grams]=%itemweight%"
 Set /A #Inv{i}+=1+0
 Set "#Inventory[%#Inv{i}%]=%itemname%"
 If Defined Itemtype (
  Set /A #%ItemType%{i}+=1+0
  Call Set "#%ItemType%[%%#%ItemType%{i}%%]=%itemname%"
 )
 Echo(%~1 added to Inventory.
:getweight
::: Updates the current weight of all inventory items by summing all itemname[grams] definitions
 Set "#weight=0"
 For /F "Tokens=2 Delims==" %%G in (' Set "#" ^| Findstr /LIC:"[grams]"')Do Set /A #weight+=%%G
Goto :Eof

注意:以上内容旨在举例说明在评估是否可以/应该添加项目后将项目添加到库存的方法。函数的 itemname /R 'remove item' 组件是从库存数组中取消定义元素的一个最小示例,但是这种方法不会移动数组变量索引以填补未定义变量留下的空白 - 需要注意的事情如果您要使用 for /L 循环遍历数组。

以下是结合使用#perfixed变量的字符登录和保存系统的示例。

::: AUTHOR: T3RRY Created: 06/03/2021 Version: 1.3 Filename: RPGInventorySystem
:# Purpose:  Provide an easy to use,ready to go Template for creating Batch RPG Games
:# Features:
:# - :Login Function 
:#   - remembers last played character; offers single key login for that character.
:#   - flags if character is New or Returning
:# - :Getin Input function to restrict and validate player Input
:# - Example Template of Creating Classes with Starting Inventory { :Knight function }
:# - Multipurpose :Inventory Funtion That Saves Inventory changes Immediately
:# - :ManageInventory Function to allow players to well... manage their inventory.
:# - Menu Macro for easy menus.

@Echo off & Goto Prep
=======================================================================:# FUNCTIONS
:# Inventory Arguments and Usage Info:
:# Arg order Mandatory

======================:# ADDING ITEMS TO INVENTORY: Initial Inventory; Loot; Gifts / Rewards; Purchases
:Inventory              <ItemName> <ItemType> <ItemSubType> <ItemWeight> <ItemCost> {Optional:"ModifierType=Value"} {Optional:/F}
::::::::::::::::::::::::::::::::::::::::::::::::::
:# Optional Arg "/F": Must be last Arg; Flags the Item as free; Does not Subtract ItemCost from Players #Money
:#  Allows Items to be Looted / Gifted / Rewarded that have value stored for use when Selling Items. See Below
======================:# REMOVING / SELLING ITEMS:
:# Remove item:         <ItemName> /R <ItemSubType>
:#  Optional third Arg is used when selling an Item. May be a Sum,Integer Value or use Array: !#ItemName.Value!
:#  /R - Undefines all array elements containing ItemName in varname or value. Use unique and descriptive Item names.
:::::::::::::::::::::::::::::::::::::::::::::::::::
:# Sell item:           <ItemName> /R <ItemSubType> <ItemSaleValue>
======================:# EQUIPPING ITEMS:
:# Equip an item   :    <Itemname> /E <ItemSubtype>
======================:# CHECKPOINTS:
:# Save a Checkpoint:   <LabelName> /L
:::::::::::::::::::::::::::::::::::::::::::::::::::
:# IMPORTANT - RESERVED VARIABLES - The above Parameter names; #%1.Grams #%1.Value #Display.Weight #%3{i} #Weight List? Count
:#  - Arrays:         #%ItemName%.Grams #%ItemName%.Value #Equipped.%ItemSubType%
:#  - Lists:          #Inventory.Types #Inventory.%ItemType% #Inventory.%ItemType%.%ItemSubType%
:# RECOMMENDATION: Use a selection of Category names for ItemTypes that will be Equipped.
:# - Only one of Each ItemSubType may be Equipped at A time.
:#  - It is appropriate that only 1 pair of Boots may be worn,but multiple pieces of different Armor may be equipped:
:#  - Instead of just Defining all armors to the ItemType Armor:
:#  - Define Type Armor and Subtypes: Helm Mantle Gloves Vambraces Pauldrons Boots Pants
:# DEPENDENCIES - Defined in ':Login': #Name Game.Save
 If /I "%~2" == "/L" (
  Set "#Location=%~1"
  Goto :Save
 )

:# Removes or Sell ItemName From Inventory;  Removes ItemName From ItemSubtype List
 If /I "%~2" == "/R" (
  Set "Value="
  If not "%~5" == "" Set "Value=%~5"
  For /F "Tokens=1,2* Delims==" %%G in (' Set "#" 2^> nul ^|%__Appdir__%findstr.exe /LIC:"%~1" ')Do (
rem /* Test if Variable is a List Variable; If Not Undefines Variable */
   Set "List?=%%G"
   If not "!List?:~0,10!" == "#Inventory" (
    Set "%%G="
   )Else (
rem /* If Variable is a List Variable; Remove ItemName from ItemSubType List */
    Set "%%G=!%%G: "%~1"=!"
Rem /* If ItemSubType List is Empty; Remove ItemSubtype from ItemType List */
    If "!%%G!" == "" (Set "#Inventory.%~3=!#Inventory.%~3: "%~4"=!")
   )
  )
rem /* If Item SaleValue provided; Increment #Money by Value */
  Set /A "#Money+=!Value!+0"
  Goto :Save
 )


:# Build Itemtype Arrays and List Using Parameters
 Set "ItemName=%~1"
 Set "ItemType=%~2"
 Set "ItemSubtype=%~3"
 Set "Count=0"
:# Limit ItemTypes to 36 max supported by Menu macro
 If Not "!#Inventory.%ItemType%!" == "" (
  For %%G in (!#Inventory.%ItemType%!)Do Set /A "Count+=1"
  If !Count! GTR 36 (
   Echo(You own too many types of %ItemType%. !ItemName! cannot be Acquired.
   Exit /B 3
  )
 )
 Set "Count=0"
:# Limit Subtypes to 36 max supported by Menu macro
 If Not "!#Inventory.%ItemType%.%ItemSubType%!" == "" (
  For %%G in (!#Inventory.%ItemType%.%ItemSubType%!)Do Set /A "Count+=1"
  If !Count! GTR 36 (
   Echo(You own too many types of %ItemSubtype%. !ItemName! cannot be Acquired.
   Exit /B 3
  )
 )
 If "%~4" == "" (Set "ItemWeight=0")Else (
  Set "ItemWeight=%~4"
  For /F %%G in ('Set /A #MaxWeight-%~4-#weight')Do if %%G LSS 0 (
   Echo/You are carrying too much.
   Exit /B 2
 ))
:# Determine Value of Item and If item is To be Free or Paid For
 Set "Free.Item="
 Echo(%*|%__APPDIR__%findstr.exe /LIC:"/F" > Nul && Set "Free.Item=Y"
 If "%~5"=="" (Set "ItemCost=0")Else (
  Set "ItemCost=%~5"
  If Not Defined Free.Item (
   For /F %%G in ('Set /A #money-%~5')Do if %%G LSS 0 (
    Echo(You cannot afford %ItemName%
    Exit /B 1
   )
  )
 )
:# Define a Modifier To ItemName.modname For Items With Stat Modifiers If supplied
 If not "%~6" == "" If /I not "%~6" == "/F" (
  Set "#%ItemName%.%~6" 2> Nul || (
   Echo(Invalid Argument "[%~6]" In %*
   Echo(Required: "ModifierType=Value"
   Timeout /T 3 /NoBreak
   Pause
   Endlocal & Goto :Eof
  )
 )
:# Define #ItemName Arrays for Grams and Value
 Set "#%ItemName%.Grams=%Itemweight%"
 Set "#%ItemName%.Value=%ItemCost%"
 Echo(!ItemName! added to Inventory.
:# Search savefile for Itemtype; Itemsubtype; and Itemname; Append to relevant list if not present
 %__APPDIR__%findstr.exe /LIC:"!ItemType!" "%Game.Save%" > nul 2> nul || Set "#Inventory.Types=!#Inventory.Types! "!ItemType!""
 %__APPDIR__%findstr.exe /LIC:"!ItemSubType!" "%Game.Save%" > nul 2> nul || Set "#Inventory.%ItemType%=!#Inventory.%ItemType%! "!ItemSubType!""
 %__APPDIR__%findstr.exe /LIC:"!ItemName!" "%Game.Save%" > nul 2> nul || Set "#Inventory.%ItemType%.%ItemSubType%=!#Inventory.%ItemType%.%ItemSubType%! "!ItemName!""

=================================================
:Save
:# Remove Item Categories from #Inventory.Types list when all Category sub items are sold / dropped.
 For %%G in (!#Inventory.Types!)Do If "!#Inventory.%%~G!" == "" Set "#Inventory.Types=!#Inventory.Types: "%%~G"=!"
 Set /A "#Def=#Dmg=#weight=0"
:# Updates the below Modifiers of all equipped inventory items by summing all ItemName.%%M definitions
 For %%M in (DEF DMG)Do For /F "Tokens=1,2* Delims==" %%G in ('Set "#Equipped" 2^> nul')Do (
  For /F "Tokens=2 Delims==" %%i in ('Set "#%%H"^|%__APPDIR__%Findstr.exe /LIC:".%%M"')Do (
   Set /A "#%%M+=%%i+0"
  )
 )
:# Updates the current weight of all inventory items by summing all ItemName.Grams definitions
 For /F "Tokens=2 Delims==" %%G in (' Set "#" ^| Findstr /LIC:".Grams"')Do Set /A #weight+=%%G
 Set "#Display.weight=%#weight:~0,-3%.%#weight:~-3%"
:# Enact Save for # prefixed variables
:# Saves Game Variables prefixed by # to Game.Save cmd file to be called on Login
 (For /F "tokens=1,2* Delims==" %%G in ('Set "#"')Do Echo(Set "%%G=%%H") >"%Game.Save%"
 Echo(%#Name%>"%~f0:Last_Char"
 Exit /B 0

=================================================
:ManageInventory {Optional:/E /S /D}
:# Control Available Inventory options by Calling ManageInventory with the Options you wish
:# to allow according to the current Gamestate.
 Set "MI.Options="
 If not "%~1" == "" Echo/%*|Findstr /LIC:"E" > Nul && Set "MI.Options=!MI.Options! Equip"
 If not "%~1" == "" Echo/%*|Findstr /LIC:"S" > Nul && Set "MI.Options=!MI.Options! Sell"
 If not "%~1" == "" Echo/%*|Findstr /LIC:"D" > Nul && Set "MI.Options=!MI.Options! Drop"
:# /R - Removes the Sell option from Invetory Action
:# RESERVED VARIABLES - Type; SubType; Action; All Menu Macro Reserved Variables
:# DEPENDENCIES -Functions: Inventory; Save -Macro: Menu -Variables: #Money #Equipped
:#                          Inventory Function Defines Lists used with Each Submenu.
:# This function returns no Errorlevels.
CLS
 Echo(         Credit: !#Money! Damage: !#Dmg! Defence: !#Def! Burden: !#Display.Weight! kg /!#MaxWeight:~0,-3!.!#MaxWeight:~-3! kg.
 Echo( Equipped Items:
 (Set "#Equipped" 2> nul > nul ) || Echo( No items equipped.
 (For /F "Delims=" %%# in ('Set #Equipped 2^> nul') Do For /F "Tokens=1,2 Delims==" %%C in ("%%#")Do (
  Set "[item]=%%C"
  Set "[item]=![item]:*.=!"
  Set "[item]=![item]:.=: !"
  <nul set /P "=> ![item]! = %%D!LF!"
 )) 2> nul

:# Choose Action Type or Exit ManageInventory Function; Each Submenu can abort to this Primary Menu
 %Menu% Exit !MI.Options!
 CLS
 Set "Action=!Option!"
 Echo(Select Inventory Category:
 %Menu% Return !#Inventory.Types!
 If "!Option!" == "Return" (Goto :ManageInventory)Else CLS
 Set "Type=!Option!"
 Echo(Select a type of !Type! to !Action!:
 %Menu% Return !#Inventory.%Type%!
 If "!Option!" == "Return" (Goto :ManageInventory)Else CLS
 Set "SubType=%Option%"
:# Apply action type to selected ItemName
:# If Equipping; Handle Two Handed / [One Handed/Off Hand] Equipment Conflict
 Echo(Selecting a !Subtype! from your !Type! Will !Action! it. Return [0] To cancel.
 %Menu% Return !#Inventory.%Type%.%SubType%!
 If Not "!Option!" == "Return" (
  If "!Action!" == "Equip" (
   Set "#Equipped.%Type%.%Subtype%=%Option%"
   If /I "%SubType%" == "Two Handed" (Set "#Equipped.Weapons.One Handed="&Set "#Equipped.Weapons.Off Hand=")
   If /I "%SubType%" == "One Handed" (Set "#Equipped.Weapons.Two Handed=")
   If /I "%SubType%" == "Off Hand" (Set "#Equipped.Weapons.Two Handed=")
   Call :Save
  )
  If "!Action!" == "Sell" (
   Echo(Sell Value: $!#%Option%.Value!. Confirm [Y/N]
   For /F "Delims=" %%O in ('Choice /N /C:YN')Do If %%O==Y Call :Inventory "%Option%" /R "!Type!" "!SubType!" "!#%Option%.Value!"
  )
  If "!Action!" == "Drop" Call :Inventory "%Option%" /R "!Type!" "!SubType!"
 )
Goto :ManageInventory

=================================================
:login
:# clear any preexisting definitions
 (For /F "tokens=1,2* Delims==" %%G in ('Set "#"')Do Set "%%G=") 2> nul

:# check Alternate data stream 'Last_Char' of this file; offer single key login for last played character.
 more < "%~f0:Last_Char" 2>nul >nul && For /F "Delims=" %%G in ('more ^< "%~f0:Last_Char"')Do (
  Echo(Continue as %%G Y/N
  For /F "Delims=" %%C in ('Choice /N /C:YN')Do if "%%C"=="Y" (
   Set "Game.Save=%TEMP%\%~n0_%%G_Save.cmd"
   CALL "%TEMP%\%~n0_%%G_Save.cmd"
   Exit /B 0
  )
 )
 (For /F "tokens=1,2* Delims==" %%G in ('Set "#"')Do Set "%%G=") 2> nul
:# Login Errorlevels: [2:User quit during Login.] [1:New Character] [0:Existing Character]
:# IMPORTANT - RESERVED VARIABLES:
:# - #Name #Pass Verify
:#   #Name used to create a .cmd file that is called when the user logs back in to the character to reassign
:#   # prefixed variables.
CLS
 Echo(Existing Characters:
 (Dir /B "%TEMP%\%~n0_*_Save.cmd" > Nul 2> nul || Echo(None. )
 For /F "Tokens=2 Delims=_" %%G in (' Dir /B "%TEMP%\%~n0_*_Save.cmd" 2^> nul ')Do Echo(%%G
rem /* example definitions */
 Call :GetIn #Name "[a-zA-Z ]*" /C /S /P:Enter your characters name
 If Not "%Errorlevel%" == "0" Goto :login
 Call :GetIn #Pass "[0-9][0-9][0-9][0-9]" /S /P:Enter your four Digit Pin
 If Not "%Errorlevel%" == "0" Goto :login
 Set "Verify=%#Pass%"
 Set "Game.Save=%TEMP%\%~n0_%#Name%_Save.cmd"
rem /* load saved values */
 If Exist "%Game.Save%" Call "%Game.Save%"
 If /I not "%Verify%" == "%#Pass%" (
  Echo(Invalid Password
  %Menu% Exit Retry
rem /* Flag quit program */
  Goto :Login
 )
rem /* offer delete/ login if exists */
 If Exist "%Game.Save%" (
rem /* Flag Existing Character Errorlevel 0 */
  %Menu% "Remove Character" "Continue"
  If /I "!Option!"=="Continue" Exit /b 0
  %Menu% "Abort" "Proceed"
  If /I "!Option!"=="Abort" Goto :Login
  Del "%Game.Save%"
  Goto :Login
 ) Else (
rem /* Flag New Character Errorlevel 1 */
  Exit /B 1
 )
=====================================================

:strlen <resultVar> <stringVar>
(   
    setlocal EnableDelayedExpansion
    (set^ tmp=!%~2!)
    if defined tmp (
        set "len=1"
        for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
            if "!tmp:~%%P,1!" NEQ "" ( 
                set /a "len+=%%P"
                set "tmp=!tmp:~%%P!"
            )
        )
    ) ELSE (
        set len=0
    )
)
( 
    endlocal
    set "%~1=%len%"
    exit /b
)
=====================================================

:GetIn [ReturnVar] ["qouted findstr search pattern"]  [Optional:"/C" - required for patterns with spaces] [Optional "/S" - Suppress input accepted] [/P:Custom Prompt]
:# Input validation function for restricting input to desired character classes or [limited] Regex Patterns.
:# -IMPORTANT - RESERVED VARIABLES: InputParams /C /P /S rVar Pattern Exit.Code
:# - GetIn Errorlevels: 
:#  - Errorlevel 3 - User has failed to provide valid input * OR * regex pattern is
:#    invalid * OR * GetIn is a called label in a file that has recieved input
:#    from a pipe that has not been handeled before the call.
:#  - Errorlevel 2 - GetIn is a script that has been invoked by a pipe
:#  - Errorlevel 1 - GetIn has been called without Arg 2 for Regex Pattern
:#  - Errorlevel 0 - Input has been assigned that matches the Regex Pattern
:# GetIn Usage Examples - Description is replaced with Arg 1-ReturnVar:
:#  Call :GetIn Pin "[0-9][0-9][0-9][0-9]" /S /P:Enter a four Digit Pin Number
:#  Call :GetIn Alphanumeric-String "[0-9a-zA-Z]*"
:#  Call :GetIn semicolon-delimited-hexadecimal-String "[0-9a-fA-F][0-9a-fA-F][:][0-9a-fA-F][0-9a-fA-F]"
:#  Call :GetIn AlphaString-with-3-Digit-Numeric-suffix "[a-zA-Z]*[0-9][0-9][0-9]"
:#  Call :GetIn list-of-delimited-words "[a-zA-Z,]*" /C
:#  Call :GetIn pair-of-delimited-numbers "[0-9]*[,][0-9]*" /C

 SETLOCAL EnableExtensions EnableDelayedExpansion
 Set "/C=" & Set "/P=" & Set "/S="
 Set InputParams=%*
 If Not "!InputParams:/C=!" == "!InputParams!" Set "/C=_"
 If Not "!InputParams:/S=!" == "!InputParams!" Set "/S=_"
 If Not "!InputParams:/P=!" == "!InputParams!" (
  Set "/P=!InputParams:*/P:=!"
  Set "/P=!/P:"=!"
 )
rem [ test if standalone script - if so test if accessed by pipe; reject execution if true ]
 If "%~0" == "%~n0" For %%G in (!cmdcmdline!)Do Echo/%%~G|Findstr.exe /LIC:"/S" > nul 2> nul && (Set "Exit.Code=2" & Goto :Getin.Err)

:GetInRetry
 Del /Q "%TEMP%\%~n0_validate.~tmp" 2> nul
 If !Exit.Code! GTR 5 Goto :Getin.Err
 Set "rVar="
 If "%~2" == "" GOTO :Getin.Err
 Setlocal DISABLEdelayedExpansion & rem ::: display occurances of carets [^] in pattern
 Endlocal & Set "Pattern=%~2"
 If Not Defined /P (
  Set /P "rVar=Input Format for %1:!LF!!Pattern!!LF!!LF!Enter %1: "
 )Else  Set /P "rVar=!/P!: "
 If "!rVar!" == "" (Set /A "Exit.Code+=1" & <nul Set /P"= ^! Invalid value.!LF!" & Goto :GetInRetry)
 > "%TEMP%\%~n0_validate.~tmp" (Echo/!rVar!)
 If Defined /C (
  Type "%TEMP%\%~n0_validate.~tmp" | %__APPDIR__%findstr.exe /RXC:"%~2" >nul || (Set /A "Exit.Code+=1" & <nul Set /P"= ^! Invalid value. !LF!" & Goto :GetInRetry)
 ) Else (
  Type "%TEMP%\%~n0_validate.~tmp" | %__APPDIR__%findstr.exe /RX "^%~2$" >nul || (Set /A "Exit.Code+=1" & <nul Set /P"=- ^! Invalid value. !LF!" & Goto :GetInRetry)
 )
 If not defined /S Echo/%1: [!rVar!] Accepted
 ENDLOCAL & Set "%~1=%rVar%"
 Del /Q "%TEMP%\%~n0_validate.~tmp"
 Exit /B 0
:GetIn.Err
Exit /B %Exit.Code%

===========================:# DEFINE INITIAL INVENTORY - EXAMPLE Only
:Knight Starter Pack
:# Example of defining initial variables for a new character prior to commencing gameplay
:# IMPORTANT - Inventory function is Dependant on #Money #MaxWeight and #Weight variables.
 Set /A "#Money=500,#MaxWeight=25000,#Weight=0"
:# suppress output of Inventory added notifcation by redirecting to nul as desired.
 Call :Inventory "Dagger" Weapons "Off Hand" 250 50 "DMG=5" /F > nul
 Call :Inventory "Buckler" Weapons "Off Hand" 400 40 "DEF=6" /F > nul
 Call :Inventory "Short sword" Weapons "One Handed" 4000 250 "DMG=10" /F > nul
 Call :Inventory "Twin Bladed Katana" Weapons "Two Handed" 5500 350 "DMG=12" /F > nul
 Call :Inventory "Leather Cap" Armor Helm 500 25 "DEF=3" /F > nul
 Call :Inventory "Faded Map" Miscellaneous Maps 20 "DEF=5" /F > nul
 Call :Inventory "Healing Potion" Potions Restorative 10 25 "Heal=30" /F > nul
 Call :Inventory "Old Key" Miscellaneous Keys 10 1 /F > nul
 Call :Inventory "Worn Leather Vambraces" Armor Vambraces 1000 15 "DEF=2" /F > nul
 Call :Inventory "Boots of Luck" Armor Boots 1500 50 "DEF=4" /F > nul
Goto :Eof
===========================:# END OF FUNCTIONS

:Prep
=====================================================:# MACRO DEFINITIONS
===================================:# MENU macro prep and Definition :::
:# IMPORTANT - RESERVED VARIABLES:
:# - LF \N Game.Save
(Set LF=^

%= Linefeed var used for multi-line output in GetIn macro - Do not modify. =%)
(Set \n=^^^

%= Newline var \n for multi-line macro definition - Do not modify. =%)

:# Enable environment for macro expansion,Arrays and code block variable operations
 Setlocal EnableExtensions EnableDelayedExpansion
==================================================================
:# Menu macro escaped for Definition with DelayedExpansion Enabled
:# IMPORTANT - RESERVED VARIABLES: Menu CH# CHCS Options Option Opt[i] Option.Output Cholist DIV
:# Key index list Allows 36 menu options. Component of Menu Macro
 Set "ChoList=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
rem /* Get console width for dividing line. */
 for /F "usebackq tokens=2* delims=: " %%W in (`mode con ^| %__APPDIR__%findstr.exe /LIC:"Columns"`) do Set /A "Console_Width=%%W"
:# Build dividing line for menu output.
 Set "DIV="&For /L %%i in (2 1 %Console_Width%)Do Set "DIV=!DIV!-"
:# Menu macro Usage: %Menu% "quoted" "list of" "options"
==== Set Menu=For %%n in (1 2)Do if %%n==2 (%\n%
%= Output Dividing Line                 =%  Echo(^^!DIV^^!%\n%
%= Reset CH# index value for Opt[#]     =%  Set "CH#=0"%\n%
%= Undefine choice option key list      =%  Set "CHCS="%\n%
%= For Each in list;                    =%  For %%G in (^^!Options^^!)Do (%\n%
%= For Option Index value               =%   For %%i in (^^!CH#^^!)Do (%\n%
%= Build the Choice key list and Opt[#] =%    Set "CHCS=^!CHCS^!^!ChoList:~%%i,1^!"%\n%
%= array using the character at the     =%    Set "Opt[^!ChoList:~%%i,1^!]=%%~G"%\n%
%= current substring index.             =%    Set "option.output=%%~G"%\n%
%= Display ; removing # variable prefix =%    Echo([^^!ChoList:~%%i,1^^!] ^^!Option.output:#=^^!%\n%
%= Increment Opt[#] Index var 'CH#'     =%    Set /A "CH#+=1"%\n%
%= Close CH# loop                       =%   )%\n%
%= Close Options loop                   =%  )%\n%
%= Output Dividing Line                 =%  Echo(^^!DIV^^!%\n%
%= Select option by character index     =%  For /F "Delims=" %%o in ('Choice /N /C:^^!CHCS^^!')Do (%\n%
%= Assign return var 'OPTION' with the  =%   Set "Option=^!Opt[%%o]^!"%\n%
%= value selected from Opt[CH#] array.  =%   If /I "^!Option^!" == "Exit" Exit /B 2%\n%
%= Return to previous script on Exit    =%  )%\n%
%= Capture Macro input - Options List   =% )Else Set Options=
========================================== ::: End Menu Definition

:StartGame
:# Make the Session Local
 Setlocal
==========================================:# MAIN GAME SCRIPT [ EXAMPLE ]
:# To Create / Continue a Character; Call Login. Errorlevel 0 = Returning Character
:# Modify The reponse to Errorlevel 1 [New Character] As you Wish to facilitate Creation of Character Classes.
:# Suggested: Use the Menu Macro with a list of Character Classes corresponding to functions and Call the selected class Label (IE - Call :Rogue)
 Call :Login
 If Errorlevel 2 Goto :Eof
 If Errorlevel 1 (
  Echo(Select your Class:
  %Menu% Exit "Knight" "Rogue"
  Call :!Option! 2>nul || (
   Echo(The !Option! Class has not been created yet. Use the example of the :Knight function to create your own Classes.
   Timeout /T 3 /NoBreak > Nul
   Pause
   Endlocal
   Goto :StartGame
  )
 )
:# Use Labels as checkpoints by Defining them to the Variable #Location
 If Errorlevel 0 If Defined #Location (Goto :!#Location!)
:# To [S]ell [E]quip or [D]rop Inventory:
:# If the Player is not in a Town / Shop; Use: Call :ManageInventory /ED to Lock out Sale of Items
 Call :ManageInventory /ESD

:Home This and below Label locations are examples of using Label Checkpoints
 CLS
 Call :Inventory Home /L
:# Use last selected option to prevent recursive calls.
 If not "!Option!" == "Home" (
  %Menu% Exit "Manage Inventory" "Travel"
 )Else %Menu% Exit "Manage Inventory"
 If "!Option!" == "Manage Inventory" (
  Call :!Option: =! /ESD
  Goto :Home
 )
 If not "!Option!" == "Travel" Goto :Eof

:Travel
 CLS
 Call :Inventory Travel /L
 Echo(Choose a Direction:
 %Menu% Exit Home East West North South
 Call :!Option: =! 2> Nul || If not Errorlevel 2 (
  Echo That Direction has not been Scripted yet. You'll have to make your own Adventure.
  Pause
 )
 Goto :Travel