Compare commits

...

2 Commits

Author SHA1 Message Date
Nicholas Hope 9331f13786 More methods! 2022-10-05 21:32:07 -04:00
Nicholas Hope 607894648c Added unused warning options 2022-10-05 21:31:58 -04:00
2 changed files with 140 additions and 142 deletions

View File

@ -91,6 +91,16 @@ def parseCLI():
help='Force tfscript to continue until catastrophic failure')
parser.add_argument( '-D', '--directory', action='store', type=str,
help='Change output directory')
# warnings
parseWarnNames = [
'implicit-release', 'implicit-off',
'implicit-primary', 'implicit-secondary',
'implicit'
]
for warnName in parseWarnNames:
splitWarnName = ' '.join(warnName.split('-'))
parser.add_argument( '-W' + warnName, action='store_true',
help=f'Generate warning on {splitWarnName} creation')
# positional argument: first non-hyphenated argument is input file
parser.add_argument( 'infile', type=argparse.FileType('r'),
help='File containing YAML to convert.')
@ -100,11 +110,12 @@ def getTargetDir(systemName):
if systemName == 'Darwin':
if float( '.'.join( GetOSRelease().split('.')[0:2] ) ) >= 10.15:
warn(
'As of macOS Catalina (v10.15), 32-bit applications '
'like TF2 do not run. tfscript will run, but you can\'t run TF2 '
'on this system',
'As of macOS Catalina (v10.15), 32-bit applications'
+ ' like TF2 do not run. tfscript will run, but you can\'t run TF2'
+ ' on this system',
category=RuntimeWarning )
return expanduser('~/Library/Application Support/Steam')
return None
return expanduser('~/Library/Application Support/Steam')
elif systemName == 'Windows':
# oh god why do we have to use the registry

View File

@ -28,19 +28,19 @@ class Bind(object):
bindTypes = []
instances = {}
def __init__(self, key='', fields={}, *, parent=None):
def __init__(self, key='', fields={}, /,*, parent=None):
if parent is None:
self.alias = False
self.key = str(key)
self.fields = fields
self.errors = []
self.warnings = []
self.alias = False
self.key = str(key)
self.fields = fields
self.errors = []
self.warnings = []
self.TargetType = None
else:
self.alias = parent.alias
self.key = parent.key
self.fields = parent.fields
self.errors = parent.errors
self.alias = parent.alias
self.key = parent.key
self.fields = parent.fields
self.errors = parent.errors
self.warnings = parent.warnings
# redefined for each unique type, default just verifies key
@ -72,15 +72,11 @@ class Bind(object):
self.instances[type(self)] = [self]
def verify(self):
try:
self.alias = self.fields.pop('alias')
if not isinstance(self.alias, bool):
self.errors.append(
f'alias should be "yes" or "no", not "{self.alias}"'
)
self.alias = False
except popErrors:
self.alias = False
self.alias = self.optional('alias', default=False)
if not isinstance(self.alias, bool):
self.err(
f'`alias` should be "yes" or "no", not "{self.alias}"'
)
try:
typeName, self.key = self.key.split(' ', 1)
@ -107,6 +103,21 @@ class Bind(object):
if (not self.alias) and (self.key not in validKeyList):
self.errors.append(f'invalid key name: "{self.key}"')
def optional(self, name, /,*, default=None):
try:
return self.fields.pop(name)
except popErrors:
return default
def cmdListFrom(self, name, /,*, default=None):
result = self.fields.pop(name)
if isinstance(result, str):
return result.split(';')
elif isinstance(result, list):
return result
else:
return default
def toTargetType(self):
if self.TargetType is None:
# do nothing
@ -128,21 +139,20 @@ class Bind(object):
class Impulse(Bind):
def verify(self):
self.command = None
self.command: list = None
if not isinstance(self.fields, dict):
self.fields = {'command': self.fields}
try:
self.command = self.fields.pop('command')
if isinstance(self.command, str):
self.command = self.command.split(';')
elif not isinstance(self.command, list):
self.err('`command` field must be argument of string or list')
self.command = None
except KeyError:
self.command = self.cmdListFrom(
'command',
default=self.fields
)
if self.command is None:
self.err('`command` field must be string or list')
except popErrors:
self.err('requires `command` field')
def toTF2(self) -> str:
if self.alias:
bindOrAlias = 'alias'
@ -167,11 +177,8 @@ class Impulse(Bind):
'secondary': 'slot2',
'melee': 'slot3'
}
try:
cmd = simpleSCs[cmd]
except KeyError:
# not a shortcut
pass
# if is shortcut, change
cmd = simpleSCs.get(cmd, cmd)
if cmd == 'voice':
cmd = 'voicemenu'
@ -183,8 +190,8 @@ class Impulse(Bind):
elif cmd == 'loadout' and restOfCmd.isalpha():
cmd = 'load_itempreset'
try:
restOfCmd = restOfCmd.lower()
restOfCmd = str(['a','b','c','d'].index(restOfCmd))
loadoutNum = ['a','b','c','d'].index(restOfCmd.lower())
restOfCmd = str(loadoutNum)
except ValueError:
# not a load_itempreset shortcut
pass
@ -204,9 +211,9 @@ class Impulse(Bind):
keyword = keyword.lower()
allLists = (
('medic', 'thanks', 'go', 'move up', 'go left', 'go right', 'yes', 'no', 'pass to me'),
('incoming', 'spy', 'sentry ahead', 'teleporter here', 'dispenser here', 'sentry here', 'activate uber', 'uber ready'),
('help', 'battle cry', 'cheers', 'jeers', 'positive', 'negative', 'nice shot', 'good job'),
('medic', 'thanks', 'go', 'move up', 'go left', 'go right', 'yes', 'no', 'pass to me'),
('incoming', 'spy', 'sentry ahead', 'teleporter here', 'dispenser here', 'sentry here', 'activate uber', 'uber ready'),
('help', 'battle cry', 'cheers', 'jeers', 'positive', 'negative', 'nice shot', 'good job'),
)
for menu, voiceList in enumerate(allLists):
@ -221,40 +228,32 @@ class Impulse(Bind):
'exit': '1 1',
'sentry': '2 0'
}
for shortBuild, num in buildingNums.items():
if building == shortBuild:
return num
return buildingNums.get(building, building)
class Hold(Bind):
def verify(self):
self.press = None
self.release = None
self.press: list = None
self.release: list = None
if not isinstance(self.fields, dict):
self.fields = {'press': self.fields}
# verify press
try:
self.press = self.fields.pop('press')
if isinstance(self.press, str):
self.press = self.press.split(';')
elif not isinstance(self.press, list):
self.press = self.cmdListFrom('press')
if self.press is None:
self.err('`press` field must be string or list')
self.press = None
except KeyError:
except popErrors:
self.err('requires `press` field')
if self.press is None:
return
# verify release
try:
self.release = self.fields.pop('release')
if isinstance(self.release, str):
self.release = self.release.split(';')
elif not isinstance(self.release, list):
self.release = self.cmdListFrom('release')
if self.release is None:
self.err('`release` field must be string or list')
self.release = None
except popErrors:
if self.press is None:
return
self.warn('has no `release`, creating one')
# no release specified, do -action for each item in press
self.release = []
@ -271,11 +270,11 @@ class Hold(Bind):
# Making impulse instances from self.press and .release
# allows them to share the shortcuts
pressObj = Impulse(f'+{holdStr}', self.press)
pressObj = Impulse('+' + holdStr, self.press)
pressObj.alias = True
pressStr = pressObj.toTF2()
releaseObj = Impulse(f'-{holdStr}', self.release)
releaseObj = Impulse('-' + holdStr, self.release)
releaseObj.alias = True
releaseStr = releaseObj.toTF2()
@ -296,34 +295,29 @@ class Hold(Bind):
class Toggle(Bind):
def verify(self):
self.on = None
self.off = None
self.on : list = None
self.off: list = None
if not isinstance(self.fields, dict):
self.fields = {'on': self.fields}
# verify on
try:
self.on = self.fields.pop('on')
if isinstance(self.on, str):
self.on = self.on.split(';')
elif not isinstance(self.on, list):
self.err('`on` field must be string or list')
self.on = None
except KeyError:
self.on = self.cmdListFrom('on')
if self.on is None:
self.err(f'`on` field must be string or list')
except popErrors:
self.err('requires `on` field')
if self.on is None:
return
# verify off
try:
self.off = self.fields.pop('off')
if isinstance(self.off, str):
self.off = self.off.split(';')
elif not isinstance(self.off, list):
self.err('`off` field must be string or list')
self.off = self.cmdListFrom('off')
if self.off is None:
self.err(f'`off` field must be string or list')
except popErrors:
# no off specified, do -action for each item in on
self.off = []
if self.on is None:
return
for cmd in self.on:
if cmd[0] == '+':
self.off.append('-' + cmd[1:])
@ -357,25 +351,20 @@ class Toggle(Bind):
class Double(Bind):
defaultDict = {}
condDict = {}
bindNames = []
condDict = {}
bindNames = []
def verify(self):
self.primary = None
self.primStr = f'{self.key}_primary'
self.secondary = None
self.secondStr = f'{self.key}_secondary'
self.condition = None
self.isToggle = False
# name of a bind type
self.type = None
# either 'released' (default) or 'both'
self.primStr = f'{self.key}_primary'
self.secondStr = f'{self.key}_secondary'
self.isToggle = False
self.cancelBoth = False
self.primary: Bind = None
self.secondary: Bind = None
self.condition: str = None
self.type: str = None
# toggler
try:
self.condition = self.fields.pop('condition')
@ -384,15 +373,12 @@ class Double(Bind):
except popErrors:
self.err('requires `condition` field')
try:
self.isToggle = self.fields.pop('toggle')
if not isinstance(self.isToggle, bool):
self.err(
'`toggle` field should be "yes" or "no", '
+ f'not "{self.isToggle}"'
)
except popErrors:
self.isToggle = False
self.isToggle = self.optional('toggle', default=False)
if not isinstance(self.isToggle, bool):
self.err(
'`toggle` field should be "yes" or "no",'
+ f' not "{self.isToggle}"'
)
# type
try:
@ -407,56 +393,57 @@ class Double(Bind):
return
# cancel mode, must happend after type has been inferred
try:
cancel = self.fields.pop('cancel')
cancel = self.optional('cancel', default='released')
if not isinstance(cancel, str):
self.err(f'`cancel` field must be "released" or "both"')
else:
if cancel == 'both':
if self.type == 'hold':
self.cancelBoth = True
else:
self.err(
'`cancel` field only affects "hold", '
+ f'not "{self.type}"'
)
elif cancel != 'released':
if not isinstance(cancel, str):
self.err(f'`cancel` field must be "released" or "both"')
else:
if cancel == 'both':
if self.type == 'hold':
self.cancelBoth = True
else:
self.err(
'`cancel` field must be "released" '
+ f'or "both", not "{cancel}"'
'`cancel` field only affects "hold",'
+ f' not "{self.type}"'
)
except popErrors:
cancel = 'released'
elif cancel == 'released':
self.cancelBoth = False
else:
self.err(
'`cancel` field must be "released"'
+ f' or "both", not "{cancel}"'
)
# primary action
try:
mainSection = self.fields.pop('primary')
mainBind = Bind(f'{self.type} {self.primStr}', mainSection)
mainBind = mainBind.toTargetType()
self.errors.extend(mainBind.errors)
self.warnings.extend(mainBind.warnings)
self.errors.remove(f'invalid key name: "{self.primStr}"')
self.primary = mainBind
self.primary = self.getSection('primary', self.primStr)
except popErrors:
self.err('requires `primary` field')
self.primary = None
# secondary action
try:
altSection = self.fields.pop('secondary')
altBind = Bind(f'{self.type} {self.secondStr}', altSection)
altBind = altBind.toTargetType()
self.errors.extend(altBind.errors)
self.warnings.extend(altBind.warnings)
self.errors.remove(f'invalid key name: "{self.secondStr}"')
self.secondary = altBind
self.secondary = self.getSection('secondary', self.secondStr)
except popErrors:
self.err('requires `secondary` field')
self.secondary = None
if self.primary is self.secondary is None:
self.err('has neither primary nor secondary')
def getSection(self, popName, key, /) -> Bind:
section = self.fields.pop(popName)
bind = Bind(f'{self.type} {key}', section)
bind = bind.toTargetType()
bind.errors.remove(f'invalid key name: "{key}"')
self.prettifyList(bind.errors, key)
self.errors.extend(bind.errors)
self.prettifyList(bind.warnings, key)
self.warnings.extend(bind.warnings)
return bind
def prettifyList(self, strList, origStr):
repStr = ' '.join(origStr.split('_', 1))
for i, cmd in enumerate(strList):
strList[i] = cmd.replace(origStr, repStr)
def toTF2(self) -> str:
# Get code for primary and secondary actions.