From 1011c15449e1bc3da8c9a7bdd46b2ff26dc83ebb Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Mon, 6 Jul 2015 17:24:12 +1000 Subject: [PATCH 1/4] Ensure the config file directory exists This fixes issue #71. Also move the error log up a directory, so we can be sure that directory exits. --- src/BEE2.pyw | 2 +- src/BEE2_config.py | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/BEE2.pyw b/src/BEE2.pyw index 9a1286d23..96cc707e9 100644 --- a/src/BEE2.pyw +++ b/src/BEE2.pyw @@ -129,7 +129,7 @@ if __name__ == '__main__': print('Logging ' + repr(e) + '!') # Always log the exception into a file. - with open('../config/BEE2-error.log', 'a') as log: + with open('../BEE2-error.log', 'a') as log: log.write(ERR_FORMAT.format( time=cur_time, underline='=' * len(cur_time), diff --git a/src/BEE2_config.py b/src/BEE2_config.py index e20fcb388..e3aa1184c 100644 --- a/src/BEE2_config.py +++ b/src/BEE2_config.py @@ -32,6 +32,11 @@ def save(self): if self.filename is None: return self.has_changed = False + # Make sure the directory exists + folder = os.path.dirname(self.filename) + if folder: + os.makedirs(folder, exist_ok=True) + with open(self.filename, 'w') as conf: self.write(conf) From ee6357b392219cbdc1a12d08f49e609ed8703ea1 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Sat, 11 Jul 2015 12:56:34 +1000 Subject: [PATCH 2/4] Fix crash when config folder is missing --- src/BEE2.pyw | 2 ++ src/BEE2_config.py | 10 ++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/BEE2.pyw b/src/BEE2.pyw index 96cc707e9..30767d7c8 100644 --- a/src/BEE2.pyw +++ b/src/BEE2.pyw @@ -56,6 +56,8 @@ if __name__ == '__main__': } loadScreen.main_loader.set_length('UI', 9) loadScreen.main_loader.show() + + GEN_OPTS.load() GEN_OPTS.set_defaults(DEFAULT_SETTINGS) show_errors = False diff --git a/src/BEE2_config.py b/src/BEE2_config.py index e3aa1184c..48881c1be 100644 --- a/src/BEE2_config.py +++ b/src/BEE2_config.py @@ -4,11 +4,11 @@ class ConfigFile(ConfigParser): - def __init__(self, filename, root='../config'): + def __init__(self, filename, root='../config', auto_load=True): """Initialise the config file. filename is the name of the config file, in the 'root' directory. - This file will immediately be read and parsed. + If auto_load is true, this file will immediately be read and parsed. """ super().__init__() self.filename = os.path.join(root, filename) @@ -22,7 +22,7 @@ def load(self): try: with open(self.filename, 'r') as conf: self.read_file(conf) - except FileNotFoundError: + except (FileNotFoundError, IOError): print('Config "' + self.filename + '" not found! Using defaults...') # If we fail, just continue - we just use the default values self.has_changed = False @@ -120,4 +120,6 @@ def set(self, section, option, value=None): remove_section.__doc__ = ConfigParser.remove_section.__doc__ set.__doc__ = ConfigParser.set.__doc__ -GEN_OPTS = ConfigFile('config.cfg') \ No newline at end of file +# Define this here so app modules can easily acess the config +# Don't load it though, since this is imported by VBSP too. +GEN_OPTS = ConfigFile('config.cfg', auto_load=False) From d0c6cc0d0e0b3a2eedc2a455949fd5cacb9ce688 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Sat, 11 Jul 2015 17:10:00 +1000 Subject: [PATCH 3/4] Fix voice lines - Use condition flag code instead of duplicating - Fix actually picking quotes - Randomise based on map seed --- src/packageLoader.py | 3 -- src/vbsp.py | 1 + src/voiceLine.py | 108 +++++++++++++++++++++++-------------------- 3 files changed, 60 insertions(+), 52 deletions(-) diff --git a/src/packageLoader.py b/src/packageLoader.py index f9e71836d..5ce1cc609 100644 --- a/src/packageLoader.py +++ b/src/packageLoader.py @@ -538,9 +538,6 @@ def parse(cls, data): folders = {} unstyled = utils.conv_bool(data.info['unstyled', '0']) - if data.id == 'ITEM_GOO': - print(data.info) - all_config = get_config( data.info, data.zip_file, diff --git a/src/vbsp.py b/src/vbsp.py index bf5dfe23e..da0be717f 100644 --- a/src/vbsp.py +++ b/src/vbsp.py @@ -421,6 +421,7 @@ def add_voice(inst): style_vars_=settings['style_vars'], vmf_file=VMF, mode=GAME_MODE, + map_seed=MAP_SEED, ) @conditions.meta_cond(priority=-200, only_once=False) diff --git a/src/voiceLine.py b/src/voiceLine.py index eaed2a066..3bd0833c3 100644 --- a/src/voiceLine.py +++ b/src/voiceLine.py @@ -1,9 +1,12 @@ # coding=utf-8 -import itertools from decimal import Decimal +import itertools +import random from BEE2_config import ConfigFile +import conditions import utils +import vmfLib map_attr = {} style_vars = {} @@ -13,6 +16,15 @@ INST_PREFIX = 'instances/BEE2/voice/' +# Create a fake instance to pass to condition flags. This way we can +# reuse all that logic, without breaking flags that check the instance. +fake_inst = vmfLib.VMF().create_ent( + classname='func_instance', + file='', + angles='0 0 0', + origin='0 0 0', +) + def find_group_quotes(group, mid_quotes, conf): is_mid = group.name == 'midinst' @@ -22,21 +34,10 @@ def find_group_quotes(group, mid_quotes, conf): valid_quote = True for flag in quote: name = flag.name - if name == 'instance': + if name == 'instance' or name == 'priority': + # Not flags! continue - # break out if a flag is unsatisfied - if name == 'has' and map_attr[flag.value.casefold()] is False: - valid_quote = False - break - elif name == 'nothas' and map_attr[flag.value.casefold()] is True: - valid_quote = False - break - elif (name == 'stylevartrue' and - style_vars[flag.value.casefold()] is False): - valid_quote = False - break - elif (name == 'stylevarfalse' and - style_vars[flag.value.casefold()] is True): + if not conditions.check_flag(flag, fake_inst): valid_quote = False break @@ -58,35 +59,38 @@ def find_group_quotes(group, mid_quotes, conf): ) -def add_quote(prop, targetname, quote_loc): +def add_quote(quote, targetname, quote_loc): """Add a quote to the map.""" - name = prop.name - if name == 'file': - VMF.create_ent( - classname='func_instance', - targetname='', - file=INST_PREFIX + prop.value, - origin=quote_loc, - fixup_style='2', # No fixup - ) - elif name == 'choreo': - VMF.create_ent( - classname='logic_choreographed_scene', - targetname=targetname, - origin=quote_loc, - scenefile=prop.value, - busyactor="1", # Wait for actor to stop talking - onplayerdeath='0', - ) - elif name == 'snd': - VMF.create_ent( - classname='ambient_generic', - spawnflags='49', # Infinite Range, Starts Silent - targetname=targetname, - origin=quote_loc, - message=prop.value, - health='10', # Volume - ) + utils.con_log('Adding quote: ', quote) + + for prop in quote: + name = prop.name.casefold() + if name == 'file': + VMF.create_ent( + classname='func_instance', + targetname='', + file=INST_PREFIX + prop.value, + origin=quote_loc, + fixup_style='2', # No fixup + ) + elif name == 'choreo': + VMF.create_ent( + classname='logic_choreographed_scene', + targetname=targetname, + origin=quote_loc, + scenefile=prop.value, + busyactor="1", # Wait for actor to stop talking + onplayerdeath='0', + ) + elif name == 'snd': + VMF.create_ent( + classname='ambient_generic', + spawnflags='49', # Infinite Range, Starts Silent + targetname=targetname, + origin=quote_loc, + message=prop.value, + health='10', # Volume + ) def sort_func(quote): @@ -105,6 +109,7 @@ def add_voice( has_items, style_vars_, vmf_file, + map_seed, mode='SP', ): """Add a voice line to the map.""" @@ -166,12 +171,17 @@ def add_voice( chosen = possible_quotes[0][1] - utils.con_log('Chosen: {!r}'.format(chosen)) - - # Add all the associated quotes - - for prop in chosen: - add_quote(prop, quote_targetname, choreo_loc) + utils.con_log('Chosen:', '\n'.join(map(repr, chosen))) + + # Join the IDs for the voice lines to the map seed, + # so each quote block will chose different lines. + random.seed(map_seed + '-VOICE_' + '|'.join( + prop['id', 'ID'] + for prop in + chosen + )) + # Add one of the associated quotes + add_quote(random.choice(chosen), quote_targetname, choreo_loc) print('mid quotes: ', mid_quotes) for mid_item in mid_quotes: From 89880f32a2747a795a1baafeb29e20b8a76cae1c Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Sat, 11 Jul 2015 17:15:04 +1000 Subject: [PATCH 4/4] Add ability to rescale goo textures --- src/vbsp.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/vbsp.py b/src/vbsp.py index da0be717f..9b25f641c 100644 --- a/src/vbsp.py +++ b/src/vbsp.py @@ -158,6 +158,7 @@ class ORIENT(Enum): "glass_scale": "0.15", # Scale of glass texture "grating_scale": "0.15", # Scale of grating texture + "goo_scale": "1", # Scale of goo material # If set, use these as the glass/grating 128x128 instances "glass_inst": "NONE", @@ -1026,6 +1027,7 @@ def change_brush(): utils.con_log("Editing Brushes...") glass_inst = get_opt('glass_inst') glass_scale = get_opt('glass_scale') + goo_scale = get_opt('goo_scale') is_bottomless = get_bool_opt('bottomless_pit') # Goo mist must be enabled by both the style and the user. make_goo_mist = get_bool_opt('goo_mist') and utils.conv_bool( @@ -1051,7 +1053,6 @@ def change_brush(): pit_solids = [] pit_height = settings['pit']['height'] pit_goo_tex = settings['pit']['tex_goo'] - print('Glass inst', glass_inst) if glass_inst == "NONE": glass_inst = None @@ -1084,9 +1085,16 @@ def change_brush(): mist_solids.add( solid.get_origin().as_tuple() ) + + split_u = face.uaxis.split() + split_v = face.vaxis.split() + split_u[-1] = goo_scale # Apply goo scaling + split_v[-1] = goo_scale + face.uaxis = " ".join(split_u) + face.vaxis = " ".join(split_v) if face.mat.casefold() == "glass/glasswindow007a_less_shiny": - split_u = face.uaxis.split(" ") - split_v = face.vaxis.split(" ") + split_u = face.uaxis.split() + split_v = face.vaxis.split() split_u[-1] = glass_scale # apply the glass scaling option split_v[-1] = glass_scale face.uaxis = " ".join(split_u) @@ -1095,6 +1103,7 @@ def change_brush(): is_glass = True if is_glass and glass_inst is not None: switch_glass_inst(solid.get_origin(), glass_inst) + if is_bottomless: utils.con_log('Creating Bottomless Pits...') make_bottomless_pit(pit_solids, highest_brush)