From 8c8a43207bf71240df662919ee7f8f1f4c6a45f8 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Mon, 20 Jul 2020 09:26:06 +1000 Subject: [PATCH 01/87] Move the application's modules into a different package --- src/BEE2_launch.pyw | 8 ++-- src/{ => app}/BEE2.py | 10 +--- src/{ => app}/CheckDetails.py | 4 +- src/{ => app}/CompilerPane.py | 24 +++++----- src/{ => app}/StyleVarPane.py | 9 ++-- src/{ => app}/SubPane.py | 11 +++-- src/{ => app}/UI.py | 48 ++++++++++--------- src/app/__init__.py | 0 src/{ => app}/backup.py | 15 +++--- src/{ => app}/contextWin.py | 31 ++++++------ src/{ => app}/dragdrop.py | 6 +-- src/{ => app}/gameMan.py | 5 +- src/{ => app}/helpMenu.py | 9 ++-- src/{ => app}/img.py | 2 +- src/{ => app}/itemPropWin.py | 8 +--- src/{ => app}/itemconfig.py | 11 ++--- src/{ => app}/logWindow.py | 4 +- src/{ => app}/music_conf.py | 6 +-- src/{ => app}/optionWindow.py | 10 ++-- src/{ => app}/packageMan.py | 4 +- src/{ => app}/paletteLoader.py | 0 src/{ => app}/richTextBox.py | 3 +- src/{selectorWin.py => app/selector_win.py} | 11 ++--- src/{selectorWin.pyi => app/selector_win.pyi} | 10 ++-- src/{ => app}/signage_ui.py | 5 +- src/{ => app}/sound.py | 2 +- src/{ => app}/tagsPane.py | 12 ++--- src/{ => app}/tkMarkdown.py | 0 src/{ => app}/tk_tools.py | 6 +-- src/{ => app}/tooltip.py | 2 +- src/{ => app}/voiceEditor.py | 9 ++-- src/loadScreen_daemon.py | 2 +- src/packageLoader.py | 12 ++--- 33 files changed, 129 insertions(+), 170 deletions(-) rename src/{ => app}/BEE2.py (96%) rename src/{ => app}/CheckDetails.py (99%) rename src/{ => app}/CompilerPane.py (98%) rename src/{ => app}/StyleVarPane.py (98%) rename src/{ => app}/SubPane.py (98%) rename src/{ => app}/UI.py (99%) create mode 100644 src/app/__init__.py rename src/{ => app}/backup.py (99%) rename src/{ => app}/contextWin.py (98%) rename src/{ => app}/dragdrop.py (99%) rename src/{ => app}/gameMan.py (99%) rename src/{ => app}/helpMenu.py (98%) rename src/{ => app}/img.py (99%) rename src/{ => app}/itemPropWin.py (99%) rename src/{ => app}/itemconfig.py (99%) rename src/{ => app}/logWindow.py (99%) rename src/{ => app}/music_conf.py (98%) rename src/{ => app}/optionWindow.py (99%) rename src/{ => app}/packageMan.py (96%) rename src/{ => app}/paletteLoader.py (100%) rename src/{ => app}/richTextBox.py (99%) rename src/{selectorWin.py => app/selector_win.py} (99%) rename src/{selectorWin.pyi => app/selector_win.pyi} (97%) rename src/{ => app}/signage_ui.py (98%) rename src/{ => app}/sound.py (99%) rename src/{ => app}/tagsPane.py (98%) rename src/{ => app}/tkMarkdown.py (100%) rename src/{ => app}/tk_tools.py (99%) rename src/{ => app}/tooltip.py (99%) rename src/{ => app}/voiceEditor.py (99%) diff --git a/src/BEE2_launch.pyw b/src/BEE2_launch.pyw index 44555e364..37b7bbd13 100644 --- a/src/BEE2_launch.pyw +++ b/src/BEE2_launch.pyw @@ -23,7 +23,7 @@ freeze_support() if __name__ == '__main__': import srctools.logger - import tk_tools + from app import tk_tools import utils if len(sys.argv) > 1: @@ -47,12 +47,12 @@ if __name__ == '__main__': LOGGER.info('Running "{}":', app_name) if app_name == 'bee2': - import BEE2 + from app import BEE2 elif app_name == 'backup': - import backup + from app import backup backup.init_application() elif app_name == 'compilepane': - import CompilerPane + from app import CompilerPane CompilerPane.init_application() else: raise ValueError(f'Invalid component name "{app_name}"!') diff --git a/src/BEE2.py b/src/app/BEE2.py similarity index 96% rename from src/BEE2.py rename to src/app/BEE2.py index 8dd705074..7038bd1e8 100644 --- a/src/BEE2.py +++ b/src/app/BEE2.py @@ -2,17 +2,11 @@ # BEE2_config creates this config file to allow easy cross-module access from BEE2_config import GEN_OPTS -from tk_tools import TK_ROOT - -import UI +from app import gameMan, paletteLoader, UI, music_conf, logWindow, img +from app.tk_tools import TK_ROOT import loadScreen -import paletteLoader import packageLoader -import gameMan -import logWindow -import img import utils -import music_conf import srctools.logger LOGGER = srctools.logger.get_logger('BEE2') diff --git a/src/CheckDetails.py b/src/app/CheckDetails.py similarity index 99% rename from src/CheckDetails.py rename to src/app/CheckDetails.py index 39953bd74..d1411b498 100644 --- a/src/CheckDetails.py +++ b/src/app/CheckDetails.py @@ -11,9 +11,9 @@ import functools -from tooltip import add_tooltip, set_tooltip +from app.tooltip import add_tooltip, set_tooltip +from app import tk_tools import utils -import tk_tools from typing import List, Iterator diff --git a/src/CompilerPane.py b/src/app/CompilerPane.py similarity index 98% rename from src/CompilerPane.py rename to src/app/CompilerPane.py index 0b3718f0c..b4088c9df 100644 --- a/src/CompilerPane.py +++ b/src/app/CompilerPane.py @@ -1,21 +1,19 @@ from tkinter import * from tkinter import filedialog from tkinter import ttk -from tooltip import add_tooltip, set_tooltip +from app.tooltip import add_tooltip, set_tooltip import base64 from PIL import Image, ImageTk -import SubPane -import img -import selectorWin -import tkMarkdown +from app import selector_win +from app import tkMarkdown, SubPane, img import utils -from BEE2_config import ConfigFile, GEN_OPTS, option_handler +from BEE2_config import ConfigFile, option_handler from packageLoader import CORRIDOR_COUNTS, CorrDesc from srctools import Property, AtomicWriter from srctools.logger import get_logger -from tk_tools import TK_ROOT, FileField +from app.tk_tools import TK_ROOT, FileField from typing import Dict, Tuple, Optional @@ -26,8 +24,8 @@ PETI_WIDTH = 555 PETI_HEIGHT = 312 -CORRIDOR = {} # type: Dict[str, selectorWin.selWin] -CORRIDOR_DATA = {} # type: Dict[Tuple[str, int], CorrDesc] +CORRIDOR: Dict[str, selector_win.selWin] = {} +CORRIDOR_DATA: Dict[Tuple[str, int], CorrDesc] = {} CORRIDOR_DESC = tkMarkdown.convert('') @@ -278,12 +276,12 @@ def set_corridors(config: Dict[Tuple[str, int], CorrDesc]): if data.icon: item.large_icon = img.png( 'corr/' + data.icon, - resize_to=selectorWin.ICON_SIZE_LRG, + resize_to=selector_win.ICON_SIZE_LRG, error=default_icon, ) item.icon = img.png( 'corr/' + data.icon, - resize_to=selectorWin.ICON_SIZE, + resize_to=selector_win.ICON_SIZE, error=default_icon, ) else: @@ -303,10 +301,10 @@ def make_corr_wid(corr_name: str): """Create the corridor widget and items.""" length = CORRIDOR_COUNTS[corr_name] - CORRIDOR[corr_name] = sel = selectorWin.selWin( + CORRIDOR[corr_name] = sel = selector_win.selWin( TK_ROOT, [ - selectorWin.Item( + selector_win.Item( str(i), 'INVALID: ' + str(i), ) diff --git a/src/StyleVarPane.py b/src/app/StyleVarPane.py similarity index 98% rename from src/StyleVarPane.py rename to src/app/StyleVarPane.py index 9d752059f..2e885c3f1 100644 --- a/src/StyleVarPane.py +++ b/src/app/StyleVarPane.py @@ -1,19 +1,18 @@ from tkinter import * -from tk_tools import TK_ROOT +from app.tk_tools import TK_ROOT from tkinter import ttk from collections import namedtuple import operator -from SubPane import SubPane +from app.SubPane import SubPane from srctools import Property from srctools.logger import get_logger import packageLoader -import tooltip +from app import tooltip import utils -import itemconfig +from app import itemconfig, img import BEE2_config -import img from typing import Union, List, Dict diff --git a/src/SubPane.py b/src/app/SubPane.py similarity index 98% rename from src/SubPane.py rename to src/app/SubPane.py index d17185adf..b5a80f77c 100644 --- a/src/SubPane.py +++ b/src/app/SubPane.py @@ -4,11 +4,12 @@ from tkinter import ttk from BEE2_config import GEN_OPTS -import tooltip -import tk_tools +from app import tooltip +from app import tk_tools import utils import srctools -import sound as snd +from app import sound + # This is a bit of an ugly hack. On OSX the buttons are set to have # default padding on the left and right, spreading out the toolbar @@ -96,7 +97,7 @@ def __init__( def hide_win(self, play_snd: bool=True) -> None: """Hide the window.""" if play_snd: - snd.fx('config') + sound.fx('config') self.withdraw() self.visible.set(False) self.save_conf() @@ -105,7 +106,7 @@ def hide_win(self, play_snd: bool=True) -> None: def show_win(self, play_snd: bool=True) -> None: """Show the window.""" if play_snd: - snd.fx('config') + sound.fx('config') self.deiconify() self.visible.set(True) self.save_conf() diff --git a/src/UI.py b/src/app/UI.py similarity index 99% rename from src/UI.py rename to src/app/UI.py index 3ced5b202..b97e60fae 100644 --- a/src/UI.py +++ b/src/app/UI.py @@ -7,34 +7,36 @@ import random from srctools import Property -import music_conf -from tk_tools import TK_ROOT -from itemPropWin import PROP_TYPES +from app import music_conf +from app.tk_tools import TK_ROOT +from app.itemPropWin import PROP_TYPES from BEE2_config import ConfigFile, GEN_OPTS -from selectorWin import selWin, Item as selWinItem, AttrDef as SelAttr +from app.selector_win import selWin, Item as selWinItem, AttrDef as SelAttr from loadScreen import main_loader as loader import srctools.logger -import sound as snd +from app import sound as snd import BEE2_config -import paletteLoader +from app import paletteLoader import packageLoader -import img -import itemconfig +from app import img +from app import itemconfig import utils -import tk_tools -import SubPane -import voiceEditor -import contextWin -import gameMan -import packageMan -import StyleVarPane -import CompilerPane -import tagsPane -import optionWindow -import helpMenu -import backup as backup_win -import tooltip -import signage_ui +from app import ( + tk_tools, + SubPane, + voiceEditor, + contextWin, + gameMan, + packageMan, + StyleVarPane, + CompilerPane, + tagsPane, + optionWindow, + helpMenu, + backup as backup_win, + tooltip, + signage_ui, +) from typing import List, Dict, Tuple @@ -137,7 +139,7 @@ def __init__(self, item): def load_data(self): """Load data from the item.""" - from tagsPane import Section + from app.tagsPane import Section version = self.item.versions[self.selected_ver] self.data = version['styles'].get( diff --git a/src/app/__init__.py b/src/app/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/backup.py b/src/app/backup.py similarity index 99% rename from src/backup.py rename to src/app/backup.py index d7c860044..e3ae8299e 100644 --- a/src/backup.py +++ b/src/app/backup.py @@ -11,22 +11,21 @@ from typing import List, TYPE_CHECKING, Dict, Any from zipfile import ZipFile, ZIP_LZMA -import img import loadScreen import srctools.logger -import tk_tools +from app import tk_tools, img import tkinter as tk import utils -from CheckDetails import CheckDetails, Item as CheckItem +from app.CheckDetails import CheckDetails, Item as CheckItem from FakeZip import FakeZip, zip_names, zip_open_bin from srctools import Property, KeyValError -from tk_tools import TK_ROOT +from app.tk_tools import TK_ROOT from tkinter import filedialog from tkinter import messagebox from tkinter import ttk -from tooltip import add_tooltip +from app.tooltip import add_tooltip if TYPE_CHECKING: - import gameMan + from app import gameMan LOGGER = srctools.logger.get_logger(__name__) @@ -640,7 +639,6 @@ def ui_save_backup_as() -> None: def ui_refresh_game() -> None: """Reload the game maps list.""" - import gameMan if gameMan.selected_game is not None: load_game(gameMan.selected_game) @@ -851,7 +849,6 @@ def init() -> None: def init_application() -> None: """Initialise the standalone application.""" - import gameMan global window window = TK_ROOT TK_ROOT.title( @@ -884,7 +881,7 @@ def init_application() -> None: bar.add_cascade(menu=game_menu, label=_('Game')) gameMan.game_menu = game_menu - import helpMenu + from app import helpMenu # Add the 'Help' menu here too. helpMenu.make_help_menu(bar) diff --git a/src/contextWin.py b/src/app/contextWin.py similarity index 98% rename from src/contextWin.py rename to src/app/contextWin.py index 7d4605966..ff422dfcf 100644 --- a/src/contextWin.py +++ b/src/app/contextWin.py @@ -10,7 +10,7 @@ from tkinter import * from srctools import Property -from tk_tools import TK_ROOT +from app.tk_tools import TK_ROOT from tkinter import ttk from tkinter import messagebox @@ -19,19 +19,16 @@ import webbrowser import srctools.logger -from richTextBox import tkRichText -import img -import itemconfig -import sound as snd -import itemPropWin -import tkMarkdown -import tooltip -import tk_tools +from app.richTextBox import tkRichText +from app import ( + itemPropWin, itemconfig, tkMarkdown, tooltip, tk_tools, + sound, + img, + UI, +) import utils import packageLoader -import UI - LOGGER = srctools.logger.get_logger(__name__) OPEN_IN_TAB = 2 @@ -126,7 +123,7 @@ def pos_for_item(): def hide_item_props(vals): - snd.fx('contract') + sound.fx('contract') selected_item.set_properties(vals) @@ -136,7 +133,7 @@ def sub_sel(ind, e=None): if selected_sub_item.is_pre: pos = SUBITEM_POS[selected_item.num_sub][ind] if pos != -1 and pos != selected_sub_item.subKey: - snd.fx('config') + sound.fx('config') selected_sub_item.change_subtype(pos) # Redisplay the window to refresh data and move it to match show_prop(selected_sub_item, warp_cursor=True) @@ -146,14 +143,14 @@ def sub_open(ind, e=None): """Move the context window to apply to the given item.""" pos = SUBITEM_POS[selected_item.num_sub][ind] if pos != -1 and pos != selected_sub_item.subKey: - snd.fx('expand') + sound.fx('expand') selected_sub_item.open_menu_at_sub(pos) def open_event(item): """Show the window for a particular PalItem.""" def func(e): - snd.fx('expand') + sound.fx('expand') show_prop(item) return func @@ -418,7 +415,7 @@ def hide_context(e=None): if is_open: is_open = False prop_window.withdraw() - snd.fx('contract') + sound.fx('contract') selected_item = selected_sub_item = None @@ -549,7 +546,7 @@ def show_more_info(): menu_info.add_command(label='', state='disabled') def show_item_props(): - snd.fx('expand') + sound.fx('expand') itemPropWin.show_window( selected_item.get_properties(), wid['changedefaults'], diff --git a/src/dragdrop.py b/src/app/dragdrop.py similarity index 99% rename from src/dragdrop.py rename to src/app/dragdrop.py index 74df54ef7..993916deb 100644 --- a/src/dragdrop.py +++ b/src/app/dragdrop.py @@ -1,11 +1,9 @@ """Implements drag/drop logic.""" from collections import defaultdict -from tk_tools import TK_ROOT import tkinter -import img import utils -import sound +from app import sound, img from enum import Enum from tkinter import ttk, messagebox from srctools.logger import get_logger @@ -556,7 +554,7 @@ def _evt_configure(self, event: tkinter.Event) -> None: def _test() -> None: """Test the GUI.""" from srctools.logger import init_logging - from tk_tools import TK_ROOT + from app.tk_tools import TK_ROOT from BEE2_config import GEN_OPTS from packageLoader import find_packages, PACKAGE_SYS diff --git a/src/gameMan.py b/src/app/gameMan.py similarity index 99% rename from src/gameMan.py rename to src/app/gameMan.py index 664cf6df5..fa2d085c5 100644 --- a/src/gameMan.py +++ b/src/app/gameMan.py @@ -7,11 +7,10 @@ """ from pathlib import Path -import tk_tools from tkinter import * # ui library from tkinter import filedialog # open/save as dialog creator from tkinter import messagebox # simple, standard modal dialogs -from tk_tools import TK_ROOT +from app.tk_tools import TK_ROOT import os import shutil @@ -27,7 +26,7 @@ FileSystem, FileSystemChain, ) import srctools.logger -import backup +from app import backup, tk_tools import loadScreen import packageLoader import utils diff --git a/src/helpMenu.py b/src/app/helpMenu.py similarity index 98% rename from src/helpMenu.py rename to src/app/helpMenu.py index 75f87df10..789c8cbe8 100644 --- a/src/helpMenu.py +++ b/src/app/helpMenu.py @@ -7,17 +7,14 @@ import webbrowser import functools -from richTextBox import tkRichText -from tk_tools import TK_ROOT, HidingScroll -import tkMarkdown -import img +from app.richTextBox import tkRichText +from app.tk_tools import TK_ROOT, HidingScroll +from app import tkMarkdown, tk_tools, sound, img import utils -import tk_tools # For version info import PIL import platform -import sound # We read pyglet indirectly from here so it can safely fail. import markdown diff --git a/src/img.py b/src/app/img.py similarity index 99% rename from src/img.py rename to src/app/img.py index 32c63271b..b4c1000b6 100644 --- a/src/img.py +++ b/src/app/img.py @@ -12,7 +12,7 @@ import srctools.logger import logging import utils -from tk_tools import TK_ROOT # Make sure this is initialised! +from app.tk_tools import TK_ROOT # Make sure this is initialised! from typing import Iterable, Union, Dict, Tuple diff --git a/src/itemPropWin.py b/src/app/itemPropWin.py similarity index 99% rename from src/itemPropWin.py rename to src/app/itemPropWin.py index 570976a5d..e1b82787c 100644 --- a/src/itemPropWin.py +++ b/src/app/itemPropWin.py @@ -1,18 +1,14 @@ from tkinter import * # ui library -from tk_tools import TK_ROOT +from app.tk_tools import TK_ROOT from tkinter import ttk # themed ui components that match the OS from functools import partial as func_partial from enum import Enum -import math import random -import sound import utils import srctools -import contextWin -import gameMan -import tk_tools +from app import contextWin, gameMan, tk_tools, sound import srctools.logger from typing import Dict, List, Union, Any diff --git a/src/itemconfig.py b/src/app/itemconfig.py similarity index 99% rename from src/itemconfig.py rename to src/app/itemconfig.py index d5952ea00..65f32af91 100644 --- a/src/itemconfig.py +++ b/src/app/itemconfig.py @@ -8,14 +8,10 @@ from srctools import Property, Vec, conv_int, conv_bool from packageLoader import PakObject, ExportData, ParseData, desc_parse import BEE2_config -from tooltip import add_tooltip -from tk_tools import ttk_Spinbox -import tkMarkdown +from app.tooltip import add_tooltip import utils import srctools.logger -import img -import sound -import signage_ui +from app import signage_ui, UI, tkMarkdown, sound, img from typing import Union, Callable, List, Tuple, Optional @@ -426,8 +422,7 @@ def widget_item_variant(parent: tk.Frame, var: tk.StringVar, conf: Property) -> This replicates the box on the right-click menu for items. It's special-cased in the above code. """ - import UI - import contextWin + from app import contextWin # We don't use the variable passed to us. try: diff --git a/src/logWindow.py b/src/app/logWindow.py similarity index 99% rename from src/logWindow.py rename to src/app/logWindow.py index 68ebd7e95..b23e808e9 100644 --- a/src/logWindow.py +++ b/src/app/logWindow.py @@ -6,9 +6,9 @@ import logging import srctools.logger -from tk_tools import TK_ROOT +from app.tk_tools import TK_ROOT from BEE2_config import GEN_OPTS -import tk_tools +from app import tk_tools import utils # Colours to use for each log level diff --git a/src/music_conf.py b/src/app/music_conf.py similarity index 98% rename from src/music_conf.py rename to src/app/music_conf.py index d0c82ed21..7c90ede9c 100644 --- a/src/music_conf.py +++ b/src/app/music_conf.py @@ -2,13 +2,13 @@ from typing import Dict, Iterable, Optional, List from BEE2_config import GEN_OPTS -from SubPane import SubPane +from app.SubPane import SubPane from loadScreen import LoadScreen from packageLoader import Music, MusicChannel from tkinter import ttk -from selectorWin import Item as SelItem, selWin as SelectorWin, AttrDef as SelAttr +from app.selector_win import Item as SelItem, selWin as SelectorWin, AttrDef as SelAttr from srctools import FileSystemChain, FileSystem -from tk_tools import TK_ROOT +from app.tk_tools import TK_ROOT import tkinter import srctools.logger diff --git a/src/optionWindow.py b/src/app/optionWindow.py similarity index 99% rename from src/optionWindow.py rename to src/app/optionWindow.py index ac85de883..8bf9bb63c 100644 --- a/src/optionWindow.py +++ b/src/app/optionWindow.py @@ -7,18 +7,15 @@ from tkinter import messagebox from typing import Callable, List, Tuple, Dict -from tk_tools import TK_ROOT +from app.tk_tools import TK_ROOT from enum import Enum from BEE2_config import GEN_OPTS -from tooltip import add_tooltip +from app.tooltip import add_tooltip -import sound import utils -import tk_tools import srctools.logger -import contextWin -import logWindow +from app import contextWin, gameMan, tk_tools, sound, logWindow import loadScreen @@ -95,7 +92,6 @@ def clear_caches() -> None: This will force package resources to be extracted again. """ - import gameMan import packageLoader message = _( diff --git a/src/packageMan.py b/src/app/packageMan.py similarity index 96% rename from src/packageMan.py rename to src/app/packageMan.py index 101bda74f..07f2a53bf 100644 --- a/src/packageMan.py +++ b/src/app/packageMan.py @@ -4,9 +4,9 @@ from tkinter import ttk from tkinter import messagebox import tkinter as tk -from tk_tools import TK_ROOT +from app.tk_tools import TK_ROOT -from CheckDetails import CheckDetails, Item as CheckItem +from app.CheckDetails import CheckDetails, Item as CheckItem from BEE2_config import ConfigFile import packageLoader import utils diff --git a/src/paletteLoader.py b/src/app/paletteLoader.py similarity index 100% rename from src/paletteLoader.py rename to src/app/paletteLoader.py diff --git a/src/richTextBox.py b/src/app/richTextBox.py similarity index 99% rename from src/richTextBox.py rename to src/app/richTextBox.py index 32f215f6a..16fa94535 100644 --- a/src/richTextBox.py +++ b/src/app/richTextBox.py @@ -6,8 +6,7 @@ import webbrowser from typing import Union -import img -import tkMarkdown +from app import tkMarkdown, img import utils import srctools.logger diff --git a/src/selectorWin.py b/src/app/selector_win.py similarity index 99% rename from src/selectorWin.py rename to src/app/selector_win.py index 54c60a27f..38ff6c2a1 100644 --- a/src/selectorWin.py +++ b/src/app/selector_win.py @@ -8,7 +8,7 @@ from tkinter import font as tk_font from tkinter import ttk # themed ui components that match the OS -from tk_tools import TK_ROOT +from app.tk_tools import TK_ROOT from collections import namedtuple, defaultdict from operator import itemgetter @@ -16,16 +16,13 @@ import functools import math -import img # png library for TKinter -from richTextBox import tkRichText -from tooltip import add_tooltip, set_tooltip +from app.richTextBox import tkRichText +from app.tooltip import add_tooltip, set_tooltip from srctools import Vec, EmptyMapping import srctools.logger from srctools.filesys import FileSystemChain -import tkMarkdown -import sound +from app import tkMarkdown, tk_tools, sound, img import utils -import tk_tools LOGGER = srctools.logger.get_logger(__name__) diff --git a/src/selectorWin.pyi b/src/app/selector_win.pyi similarity index 97% rename from src/selectorWin.pyi rename to src/app/selector_win.pyi index bdf326fb2..a2c2d3e8a 100644 --- a/src/selectorWin.pyi +++ b/src/app/selector_win.pyi @@ -9,16 +9,16 @@ from tkinter import ( from enum import Enum -from richTextBox import tkRichText -from sound import SamplePlayer +from app.richTextBox import tkRichText +from app.sound import SamplePlayer from srctools import Vec, FileSystemChain from typing import ( - NamedTuple, Optional, Union, Tuple, List, Dict, Any, + Optional, Union, Tuple, List, Dict, Any, Callable, Iterable, ) -from tkMarkdown import MarkdownData -from tk_tools import HidingScroll +from app.tkMarkdown import MarkdownData +from app.tk_tools import HidingScroll __all__ = [ 'ICON_SIZE', 'ICON_SIZE_LRG', diff --git a/src/signage_ui.py b/src/app/signage_ui.py similarity index 98% rename from src/signage_ui.py rename to src/app/signage_ui.py index 50fd2e9d0..d067d580a 100644 --- a/src/signage_ui.py +++ b/src/app/signage_ui.py @@ -1,8 +1,7 @@ """Configures which signs are defined for the Signage item.""" from typing import Optional, Tuple, List, Dict, overload -import dragdrop -import img +from app import dragdrop, img import srctools.logger import utils import BEE2_config @@ -10,7 +9,7 @@ import tkinter as tk from srctools import Property from tkinter import ttk -from tk_tools import TK_ROOT, HidingScroll +from app.tk_tools import TK_ROOT, HidingScroll LOGGER = srctools.logger.get_logger(__name__) diff --git a/src/sound.py b/src/app/sound.py similarity index 99% rename from src/sound.py rename to src/app/sound.py index bd9491f05..e4b465496 100644 --- a/src/sound.py +++ b/src/app/sound.py @@ -10,7 +10,7 @@ import utils -from tk_tools import TK_ROOT +from app.tk_tools import TK_ROOT from srctools.filesys import FileSystemChain, FileSystem, RawFileSystem import srctools.logger diff --git a/src/tagsPane.py b/src/app/tagsPane.py similarity index 98% rename from src/tagsPane.py rename to src/app/tagsPane.py index 00da037b9..34fba83c4 100644 --- a/src/tagsPane.py +++ b/src/app/tagsPane.py @@ -1,6 +1,6 @@ from tkinter import ttk from tkinter import font -from tk_tools import TK_ROOT +from app.tk_tools import TK_ROOT import tkinter as tk from functools import partial @@ -9,12 +9,8 @@ from enum import Enum import string -import sound as snd -import optionWindow -import StyleVarPane -import UI +from app import optionWindow, StyleVarPane, UI, tk_tools, sound import utils -import tk_tools from typing import Dict, List @@ -107,7 +103,7 @@ def expand(_): ) wid['tag_list']['height'] = TK_ROOT.winfo_height() / 48 - snd.fx('expand') + sound.fx('expand') UI.flow_picker() @@ -116,7 +112,7 @@ def contract(_): global is_expanded is_expanded = False wid['expand_frame'].grid_remove() - snd.fx('contract') + sound.fx('contract') UI.flow_picker() diff --git a/src/tkMarkdown.py b/src/app/tkMarkdown.py similarity index 100% rename from src/tkMarkdown.py rename to src/app/tkMarkdown.py diff --git a/src/tk_tools.py b/src/app/tk_tools.py similarity index 99% rename from src/tk_tools.py rename to src/app/tk_tools.py index d2cd1494b..49d723c34 100644 --- a/src/tk_tools.py +++ b/src/app/tk_tools.py @@ -85,7 +85,7 @@ def set_window_icon(window: Union[tk.Toplevel, tk.Tk]): LISTBOX_BG_COLOR = 'white' else: # Linux # Get the tk image object. - import img + from app import img app_icon = img.get_app_icon(ICO_PATH) def set_window_icon(window: Union[tk.Toplevel, tk.Tk]): @@ -319,7 +319,7 @@ def __init__( - callback is a function to be called with the new path whenever it changes. """ - from tooltip import add_tooltip + from app.tooltip import add_tooltip super(FileField, self).__init__(master) @@ -385,7 +385,7 @@ def value(self) -> str: @value.setter def value(self, path: str) -> None: """Set the current path. This calls the callback function.""" - import tooltip + from app import tooltip self.callback(path) self._location = path tooltip.set_tooltip(self, path) diff --git a/src/tooltip.py b/src/app/tooltip.py similarity index 99% rename from src/tooltip.py rename to src/app/tooltip.py index 1e17f7d8e..8d58d4f18 100644 --- a/src/tooltip.py +++ b/src/app/tooltip.py @@ -4,7 +4,7 @@ Call add_tooltip with a widget to add all the events automatically. """ import tkinter as tk -from tk_tools import TK_ROOT +from app.tk_tools import TK_ROOT PADDING = 0 # Space around the target widget CENT_DIST = 50 # Distance around center where we align centered. diff --git a/src/voiceEditor.py b/src/app/voiceEditor.py similarity index 99% rename from src/voiceEditor.py rename to src/app/voiceEditor.py index ce3031a27..36a9307f5 100644 --- a/src/voiceEditor.py +++ b/src/app/voiceEditor.py @@ -1,7 +1,6 @@ """Allows enabling and disabling specific voicelines.""" import functools import itertools -import os from decimal import Decimal from enum import Enum from typing import Iterator, List, Tuple, Dict @@ -10,14 +9,14 @@ from tkinter import font from tkinter import ttk -import img +from app import img import srctools.logger -import tk_tools +from app import tk_tools import utils from BEE2_config import ConfigFile -from tooltip import add_tooltip +from app.tooltip import add_tooltip from srctools import Property -from tk_tools import TK_ROOT +from app.tk_tools import TK_ROOT LOGGER = srctools.logger.get_logger(__name__) diff --git a/src/loadScreen_daemon.py b/src/loadScreen_daemon.py index a6e049b8f..ac78eebc3 100644 --- a/src/loadScreen_daemon.py +++ b/src/loadScreen_daemon.py @@ -272,7 +272,7 @@ def __init__(self, *args): ) # Must be done late, so we know TK is initialised. - import img + from app import img logo_img = img.png('BEE2/splash_logo') diff --git a/src/packageLoader.py b/src/packageLoader.py index b9f828625..b95eefb12 100644 --- a/src/packageLoader.py +++ b/src/packageLoader.py @@ -10,9 +10,9 @@ from enum import Enum import srctools -import tkMarkdown +from app import tkMarkdown import utils -from packageMan import PACK_CONFIG +from app.packageMan import PACK_CONFIG from srctools import ( Property, NoKeyError, Vec, EmptyMapping, @@ -33,8 +33,8 @@ # noinspection PyUnresolvedReferences if TYPE_CHECKING: - from gameMan import Game - from selectorWin import SelitemData + from app.gameMan import Game + from app.selector_win import SelitemData from loadScreen import LoadScreen from typing import NoReturn @@ -3533,7 +3533,7 @@ def desc_parse( def get_selitem_data(info: Property) -> 'SelitemData': """Return the common data for all item types - name, author, description. """ - from selectorWin import SelitemData + from app.selector_win import SelitemData auth = sep_values(info['authors', '']) short_name = info['shortName', None] @@ -3569,7 +3569,7 @@ def join_selitem_data( This uses the over_data values if defined, using our_data if not. Authors and descriptions will be joined to each other. """ - from selectorWin import SelitemData + from app.selector_win import SelitemData ( our_name, our_short_name, From bc29601561b92d9313ad3b2053de60edd1da36ff Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Mon, 20 Jul 2020 09:57:16 +1000 Subject: [PATCH 02/87] Move the precompiler code into a package --- src/{comp_consts.py => consts.py} | 20 ++-- src/precomp/__init__.py | 0 src/{ => precomp}/antlines.py | 14 ++- src/{ => precomp}/barriers.py | 41 ++++---- src/{ => precomp}/bottomlessPit.py | 9 +- src/{ => precomp}/brushLoc.py | 6 +- src/{ => precomp}/conditions/__init__.py | 31 +++--- src/{ => precomp}/conditions/addInstance.py | 10 +- src/{ => precomp}/conditions/antlaser.py | 10 +- src/{ => precomp}/conditions/apTag.py | 22 ++--- src/{ => precomp}/conditions/brushes.py | 24 +++-- src/{ => precomp}/conditions/catwalks.py | 11 +-- src/{ => precomp}/conditions/connections.py | 6 +- src/{ => precomp}/conditions/conveyorBelt.py | 15 ++- src/{ => precomp}/conditions/custItems.py | 14 ++- src/{ => precomp}/conditions/cutoutTile.py | 11 ++- src/{ => precomp}/conditions/entities.py | 14 ++- src/{ => precomp}/conditions/faithplate.py | 7 +- src/{ => precomp}/conditions/fizzler.py | 9 +- src/{ => precomp}/conditions/glass.py | 12 +-- src/{ => precomp}/conditions/globals.py | 29 +++--- src/{ => precomp}/conditions/instances.py | 6 +- src/{ => precomp}/conditions/logical.py | 2 +- src/{ => precomp}/conditions/monitor.py | 33 +++---- .../conditions/piston_platform.py | 16 ++-- src/{ => precomp}/conditions/positioning.py | 9 +- src/{ => precomp}/conditions/python.py | 2 +- src/{ => precomp}/conditions/randomise.py | 4 +- src/{ => precomp}/conditions/removed.py | 2 +- .../conditions/resizableTrigger.py | 24 ++--- src/{ => precomp}/conditions/scaffold.py | 13 +-- src/{ => precomp}/conditions/sendificator.py | 3 +- src/{ => precomp}/conditions/signage.py | 16 ++-- src/{ => precomp}/conditions/trackPlat.py | 5 +- src/{ => precomp}/conditions/vactubes.py | 14 ++- src/{ => precomp}/connections.py | 96 ++++++++++--------- src/{ => precomp}/cubes.py | 18 ++-- src/{ => precomp}/faithplate.py | 6 +- src/{ => precomp}/fizzler.py | 41 ++++---- src/{ => precomp}/grid_optim.py | 1 - src/{ => precomp}/instanceLocs.py | 0 src/{ => precomp}/instance_traits.py | 6 +- src/{ => precomp}/item_chain.py | 4 +- src/{vbsp_options.py => precomp/options.py} | 0 src/{ => precomp}/packing.py | 7 +- src/{ => precomp}/template_brush.py | 16 ++-- src/{ => precomp}/texturing.py | 4 +- src/{ => precomp}/tiling.py | 41 ++++---- src/{voiceLine.py => precomp/voice_line.py} | 7 +- src/vbsp.py | 96 +++++++++---------- 50 files changed, 383 insertions(+), 424 deletions(-) rename src/{comp_consts.py => consts.py} (95%) create mode 100644 src/precomp/__init__.py rename src/{ => precomp}/antlines.py (98%) rename src/{ => precomp}/barriers.py (95%) rename src/{ => precomp}/bottomlessPit.py (98%) rename src/{ => precomp}/brushLoc.py (99%) rename src/{ => precomp}/conditions/__init__.py (98%) rename src/{ => precomp}/conditions/addInstance.py (96%) rename src/{ => precomp}/conditions/antlaser.py (98%) rename src/{ => precomp}/conditions/apTag.py (97%) rename src/{ => precomp}/conditions/brushes.py (99%) rename src/{ => precomp}/conditions/catwalks.py (98%) rename src/{ => precomp}/conditions/connections.py (96%) rename src/{ => precomp}/conditions/conveyorBelt.py (97%) rename src/{ => precomp}/conditions/custItems.py (91%) rename src/{ => precomp}/conditions/cutoutTile.py (99%) rename src/{ => precomp}/conditions/entities.py (97%) rename src/{ => precomp}/conditions/faithplate.py (96%) rename src/{ => precomp}/conditions/fizzler.py (96%) rename src/{ => precomp}/conditions/glass.py (97%) rename src/{ => precomp}/conditions/globals.py (91%) rename src/{ => precomp}/conditions/instances.py (99%) rename src/{ => precomp}/conditions/logical.py (96%) rename src/{ => precomp}/conditions/monitor.py (92%) rename src/{ => precomp}/conditions/piston_platform.py (96%) rename src/{ => precomp}/conditions/positioning.py (98%) rename src/{ => precomp}/conditions/python.py (99%) rename src/{ => precomp}/conditions/randomise.py (99%) rename src/{ => precomp}/conditions/removed.py (94%) rename src/{ => precomp}/conditions/resizableTrigger.py (96%) rename src/{ => precomp}/conditions/scaffold.py (98%) rename src/{ => precomp}/conditions/sendificator.py (98%) rename src/{ => precomp}/conditions/signage.py (94%) rename src/{ => precomp}/conditions/trackPlat.py (98%) rename src/{ => precomp}/conditions/vactubes.py (99%) rename src/{ => precomp}/connections.py (95%) rename src/{ => precomp}/cubes.py (99%) rename src/{ => precomp}/faithplate.py (98%) rename src/{ => precomp}/fizzler.py (98%) rename src/{ => precomp}/grid_optim.py (99%) rename src/{ => precomp}/instanceLocs.py (100%) rename src/{ => precomp}/instance_traits.py (98%) rename src/{ => precomp}/item_chain.py (97%) rename src/{vbsp_options.py => precomp/options.py} (100%) rename src/{ => precomp}/packing.py (92%) rename src/{ => precomp}/template_brush.py (99%) rename src/{ => precomp}/texturing.py (99%) rename src/{ => precomp}/tiling.py (99%) rename src/{voiceLine.py => precomp/voice_line.py} (99%) diff --git a/src/comp_consts.py b/src/consts.py similarity index 95% rename from src/comp_consts.py rename to src/consts.py index 107d786d7..8c4417a51 100644 --- a/src/comp_consts.py +++ b/src/consts.py @@ -1,12 +1,13 @@ -"""Various constant values for use by VBSP. (Mainly texture names.)""" +"""Various constant values (Mainly texture names.)""" from enum import Enum, EnumMeta - -from srctools import Side as _Side, Entity +from srctools import Side __all__ = [ 'MaterialGroup', + 'ItemClass', + 'WhitePan', 'BlackPan', 'Signage', 'Antlines', 'Goo', 'Fizzler', @@ -25,6 +26,7 @@ def __prepare__(mcs, cls, bases): # The original class is private - grab it via prepare, and make # a subclass right here. orig_dict = type(super().__prepare__(cls, bases)) + class RepDict(orig_dict): def __setitem__(self, key, value): if isinstance(value, str): @@ -33,11 +35,11 @@ def __setitem__(self, key, value): return RepDict() - def __contains__(cls, value): + def __contains__(cls, value) -> bool: """MaterialGroup can check if strings are equal to a member.""" if isinstance(value, str): return value.casefold() in cls._value2member_map_ - elif isinstance(value, _Side): + elif isinstance(value, Side): return value.mat.casefold() in cls._value2member_map_ return super().__contains__(value) @@ -58,15 +60,15 @@ class MaterialGroup(str, Enum, metaclass=MaterialGroupMeta): to any members. * str(member) == member.value """ - def __eq__(self, other): - if isinstance(other, _Side): + def __eq__(self, other) -> bool: + if isinstance(other, Side): other = other.mat return self.value == other.casefold() - def __str__(self): + def __str__(self) -> str: return self.value - def __hash__(self): + def __hash__(self) -> int: """Allow hashing MaterialGroup values.""" return hash(self.value) diff --git a/src/precomp/__init__.py b/src/precomp/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/antlines.py b/src/precomp/antlines.py similarity index 98% rename from src/antlines.py rename to src/precomp/antlines.py index 79200c585..27ea0a8d0 100644 --- a/src/antlines.py +++ b/src/precomp/antlines.py @@ -2,16 +2,14 @@ import random from collections import namedtuple -from srctools import Vec, Property, conv_float, Entity, VMF, logger +from srctools import Vec, Property, conv_float, VMF, logger from srctools.vmf import overlay_bounds, make_overlay -import comp_consts as const +import consts from collections import defaultdict from typing import List, Dict, Tuple, TYPE_CHECKING, Iterator, Optional, Set from enum import Enum -if TYPE_CHECKING: - from tiling import TileDef LOGGER = logger.get_logger(__name__) @@ -118,8 +116,8 @@ def parse(cls, prop: Property) -> 'AntType': def default(cls) -> 'AntType': """Make a copy of the original PeTI antline config.""" return cls( - [AntTex(const.Antlines.STRAIGHT, 0.25, False)], - [AntTex(const.Antlines.CORNER, 1, False)], + [AntTex(consts.Antlines.STRAIGHT, 0.25, False)], + [AntTex(consts.Antlines.CORNER, 1, False)], [], [], 0, ) @@ -350,8 +348,8 @@ def parse_antlines(vmf: VMF) -> Tuple[ # so we only join related antlines. join_points = {} # type: Dict[Tuple[str, float, float, float], Segment] - mat_straight = const.Antlines.STRAIGHT - mat_corner = const.Antlines.CORNER + mat_straight = consts.Antlines.STRAIGHT + mat_corner = consts.Antlines.CORNER side_to_seg = {} # type: Dict[int, List[Segment]] antlines = {} # type: Dict[str, List[Antline]] diff --git a/src/barriers.py b/src/precomp/barriers.py similarity index 95% rename from src/barriers.py rename to src/precomp/barriers.py index 49a0a7a56..1106f6057 100644 --- a/src/barriers.py +++ b/src/precomp/barriers.py @@ -3,15 +3,15 @@ from enum import Enum from typing import Dict, Tuple, List, Set, Callable -import comp_consts as consts +from precomp import ( + texturing, options, packing, + template_brush, +) +import consts import srctools.logger -import template_brush -import vbsp_options -import packing -import texturing -from conditions import make_result -from grid_optim import optimise as grid_optimise -from instanceLocs import resolve_one +from precomp.conditions import make_result +from precomp.grid_optim import optimise as grid_optimise +from precomp.instanceLocs import resolve_one from srctools import VMF, Vec, Solid, Property, Entity @@ -78,8 +78,8 @@ def parse_map(vmf: VMF, has_attr: Dict[str, bool]) -> None: if filename == glass_inst: inst.remove() - if vbsp_options.get(str, 'glass_pack') and has_attr['glass']: - packing.pack_list(vmf, vbsp_options.get(str, 'glass_pack')) + if options.get(str, 'glass_pack') and has_attr['glass']: + packing.pack_list(vmf, options.get(str, 'glass_pack')) def test_hole_spot(origin: Vec, normal: Vec, hole_type: HoleType): @@ -151,16 +151,16 @@ def res_glass_hole(inst: Entity, res: Property): def make_barriers(vmf: VMF): """Make barrier entities. get_tex is vbsp.get_tex.""" glass_temp = template_brush.get_scaling_template( - vbsp_options.get(str, "glass_template") + options.get(str, "glass_template") ) grate_temp = template_brush.get_scaling_template( - vbsp_options.get(str, "grating_template") + options.get(str, "grating_template") ) # Avoid error without this package. if HOLES: # Grab the template solids we need. hole_temp = template_brush.get_template( - vbsp_options.get(str, 'glass_hole_temp') + options.get(str, 'glass_hole_temp') ) hole_world, hole_detail, _ = hole_temp.visgrouped({'small'}) hole_temp_small = hole_world + hole_detail @@ -171,12 +171,12 @@ def make_barriers(vmf: VMF): else: hole_temp_small = hole_temp_large = hole_temp_corner = None - floorbeam_temp = vbsp_options.get(str, 'glass_floorbeam_temp') + floorbeam_temp = options.get(str, 'glass_floorbeam_temp') - if vbsp_options.get_itemconf('BEE_PELLET:PelletGrating', False): + if options.get_itemconf('BEE_PELLET:PelletGrating', False): # Merge together these existing filters in global_pti_ents vmf.create_ent( - origin=vbsp_options.get(Vec, 'global_pti_ents_loc'), + origin=options.get(Vec, 'global_pti_ents_loc'), targetname='@grating_filter', classname='filter_multi', filtertype=0, @@ -187,7 +187,7 @@ def make_barriers(vmf: VMF): else: # Just skip paint bombs. vmf.create_ent( - origin=vbsp_options.get(Vec, 'global_pti_ents_loc'), + origin=options.get(Vec, 'global_pti_ents_loc'), targetname='@grating_filter', classname='filter_activator_class', negated=1, @@ -452,7 +452,7 @@ def add_glass_floorbeams(vmf: VMF, temp_name: str): else: raise ValueError('Not aligned to world...') - separation = vbsp_options.get(int, 'glass_floorbeam_sep') + 1 + separation = options.get(int, 'glass_floorbeam_sep') + 1 separation *= 128 # First we want to find all the groups of contiguous glass sections. @@ -580,8 +580,8 @@ def beam_hole_split(axis: str, min_pos: Vec, max_pos: Vec): # Inset in 4 units from each end to not overlap with the frames. start_pos = min_pos - Vec.with_axes(axis, 60) if HOLES: - hole_size_large = vbsp_options.get(float, 'glass_hole_size_large') / 2 - hole_size_small = vbsp_options.get(float, 'glass_hole_size_small') / 2 + hole_size_large = options.get(float, 'glass_hole_size_large') / 2 + hole_size_small = options.get(float, 'glass_hole_size_small') / 2 # Extract normal from the z-axis. grid_height = min_pos.z // 128 * 128 + 64 @@ -589,7 +589,6 @@ def beam_hole_split(axis: str, min_pos: Vec, max_pos: Vec): normal = (0, 0, 1) else: normal = (0, 0, -1) - import vbsp for pos in min_pos.iter_line(max_pos, 128): try: hole_type = HOLES[(pos.x, pos.y, grid_height), normal] diff --git a/src/bottomlessPit.py b/src/precomp/bottomlessPit.py similarity index 98% rename from src/bottomlessPit.py rename to src/precomp/bottomlessPit.py index 3210e83b0..e56f3bce7 100644 --- a/src/bottomlessPit.py +++ b/src/precomp/bottomlessPit.py @@ -4,8 +4,7 @@ from srctools import Vec, Property, VMF, Solid, Side, Output import srctools.logger import utils -import brushLoc -import vbsp_options +from precomp import brushLoc, options LOGGER = srctools.logger.get_logger(__name__) @@ -82,7 +81,7 @@ def make_bottomless_pit(vmf: VMF, max_height): tele_off = Vec(0, 0, 0) # Controlled by the style, not skybox! - blend_light = vbsp_options.get(str, 'pit_blend_light') + blend_light = options.get(str, 'pit_blend_light') if use_skybox: # Add in the actual skybox edges and triggers. @@ -371,7 +370,7 @@ def make_pit_shell(vmf: VMF): classname='trigger_multiple', spawnflags=4104, wait=0.1, - origin=vbsp_options.get(Vec, 'global_pti_ents_loc'), + origin=options.get(Vec, 'global_pti_ents_loc'), ) diss_trig.solids = [vmf.make_prism( Vec(-8 * 128, -8 * 128, -4182), @@ -388,7 +387,7 @@ def make_pit_shell(vmf: VMF): # to stop players from portalling past the hurt trigger. diss_trig = vmf.create_ent( classname='func_noportal_volume', - origin=vbsp_options.get(Vec, 'global_pti_ents_loc'), + origin=options.get(Vec, 'global_pti_ents_loc'), ) diss_trig.solids = [vmf.make_prism( Vec(-8 * 128, -8 * 128, -64), diff --git a/src/brushLoc.py b/src/precomp/brushLoc.py similarity index 99% rename from src/brushLoc.py rename to src/precomp/brushLoc.py index 326ec595b..1badd070f 100644 --- a/src/brushLoc.py +++ b/src/precomp/brushLoc.py @@ -7,7 +7,7 @@ from enum import Enum import srctools.logger -import bottomlessPit +from precomp import bottomlessPit from typing import ( Union, Any, Tuple, @@ -258,8 +258,8 @@ def items(self) -> '_GridItemsView': def read_from_map(self, vmf: VMF, has_attr: Dict[str, bool]) -> None: """Given the map file, set blocks.""" - from conditions import EMBED_OFFSETS - from instance_traits import get_item_id + from precomp.conditions import EMBED_OFFSETS + from precomp.instance_traits import get_item_id # Starting points to fill air and goo. # We want to fill goo first... diff --git a/src/conditions/__init__.py b/src/precomp/conditions/__init__.py similarity index 98% rename from src/conditions/__init__.py rename to src/precomp/conditions/__init__.py index e0600eff9..159aad302 100644 --- a/src/conditions/__init__.py +++ b/src/precomp/conditions/__init__.py @@ -39,13 +39,14 @@ TextIO, ) -import comp_consts as consts +from precomp import ( + instanceLocs, + template_brush, +) +import consts import srctools.logger -import template_brush import utils -import comp_consts as const -import instanceLocs -from texturing import Portalable +from precomp.texturing import Portalable from srctools import ( Property, Vec_tuple, Vec, @@ -609,16 +610,16 @@ def import_conditions() -> None: # See PyInstaller/loader/pyimod03_importers.py # toc is a PyInstaller-specific attribute containing a set of # all frozen modules. - loader = pkgutil.get_loader('conditions') + loader = pkgutil.get_loader('precomp.conditions') modules = [ module for module in loader.toc - if module.startswith('conditions.') + if module.startswith('precomp.conditions.') ] # type: List[str] else: # We can grab them properly. modules = [ - 'conditions.' + module + 'precomp.conditions.' + module for loader, module, is_package in pkgutil.iter_modules(__path__) ] @@ -1103,23 +1104,23 @@ def resolve_offset(inst, value: str, scale: float=1, zoff: float=0) -> Vec: # Offset the overlay by the given distance # Some special placeholder values: if value == '' or value == '': - if inst.fixup.bool(const.FixupVars.PIST_IS_UP): + if inst.fixup.bool(consts.FixupVars.PIST_IS_UP): value = '' else: value = '' elif value == '': - if inst.fixup.bool(const.FixupVars.PIST_IS_UP): + if inst.fixup.bool(consts.FixupVars.PIST_IS_UP): value = '' else: value = '' if value == '': offset = Vec( - z=inst.fixup.int(const.FixupVars.PIST_BTM) * 128, + z=inst.fixup.int(consts.FixupVars.PIST_BTM) * 128, ) elif value == '': offset = Vec( - z=inst.fixup.int(const.FixupVars.PIST_TOP) * 128, + z=inst.fixup.int(consts.FixupVars.PIST_TOP) * 128, ) else: # Regular vector @@ -1136,7 +1137,7 @@ def resolve_offset(inst, value: str, scale: float=1, zoff: float=0) -> Vec: def set_random_seed(inst: Entity, seed: str) -> None: """Compute and set a random seed for a specific entity.""" - import instance_traits # Import loop... + from precomp import instance_traits name = inst['targetname'] # The global instances like elevators always get the same name, or @@ -1491,7 +1492,7 @@ def res_goo_debris(res: Property): - chance: The percentage chance a square will have a debris item - offset: A random xy offset applied to the instances. """ - import brushLoc + from precomp import brushLoc space = res.int('spacing', 1) rand_count = res.int('number', None) @@ -1536,7 +1537,7 @@ def res_goo_debris(res: Property): if (x + x_off, y + y_off, z) not in goo_top_locs: break # This doesn't qualify else: - possible_locs.append(brushLoc.grid_to_world(Vec(x,y,z))) + possible_locs.append(brushLoc.grid_to_world(Vec(x, y, z))) LOGGER.info( 'GooDebris: {}/{} locations', diff --git a/src/conditions/addInstance.py b/src/precomp/conditions/addInstance.py similarity index 96% rename from src/conditions/addInstance.py rename to src/precomp/conditions/addInstance.py index 045bebcf9..426afced1 100644 --- a/src/conditions/addInstance.py +++ b/src/precomp/conditions/addInstance.py @@ -1,12 +1,10 @@ """Results for generating additional instances. """ -import conditions -import instanceLocs +from precomp import instanceLocs, options, conditions import srctools.logger import vbsp -import vbsp_options -from conditions import ( +from precomp.conditions import ( make_result, RES_EXHAUSTED, GLOBAL_INSTANCES, ) @@ -54,7 +52,7 @@ def res_add_global_inst(res: Property): try: new_inst['origin'] = res['position'] except IndexError: - new_inst['origin'] = vbsp_options.get(Vec, 'global_ents_loc') + new_inst['origin'] = options.get(Vec, 'global_ents_loc') GLOBAL_INSTANCES.add(res['file']) if new_inst['targetname'] == '': new_inst['targetname'] = "inst_" @@ -141,7 +139,7 @@ def res_cave_portrait(inst: Entity, res: Property): Otherwise, this overlays an instance, setting the $skin variable appropriately. Config values match that of addOverlay. """ - skin = vbsp_options.get(int, 'cave_port_skin') + skin = options.get(int, 'cave_port_skin') if skin is not None: new_inst = res_add_overlay_inst(inst, res) if new_inst: diff --git a/src/conditions/antlaser.py b/src/precomp/conditions/antlaser.py similarity index 98% rename from src/conditions/antlaser.py rename to src/precomp/conditions/antlaser.py index 324141d3f..2680cfaa4 100644 --- a/src/conditions/antlaser.py +++ b/src/precomp/conditions/antlaser.py @@ -3,13 +3,11 @@ from enum import Enum from typing import Dict, List, Tuple, Set, FrozenSet, Callable, Union -import conditions -import instanceLocs +from precomp import instanceLocs, connections, conditions import srctools.logger -from conditions import make_result -import connections -from connections import Item -from srctools import VMF, Property, Output, Vec, Vec_tuple, Entity +from precomp.conditions import make_result +from precomp.connections import Item +from srctools import VMF, Property, Output, Vec, Entity COND_MOD_NAME = None diff --git a/src/conditions/apTag.py b/src/precomp/conditions/apTag.py similarity index 97% rename from src/conditions/apTag.py rename to src/precomp/conditions/apTag.py index 10b0f277b..2145c78e0 100644 --- a/src/conditions/apTag.py +++ b/src/precomp/conditions/apTag.py @@ -3,20 +3,20 @@ import math import os -import instanceLocs +from srctools import Vec, Property, VMF, Entity, Output import srctools.logger -import utils -import vbsp -import vbsp_options -from conditions import ( + +from precomp import instanceLocs, options +from precomp.conditions import ( meta_cond, make_result, PETI_INST_ANGLE, RES_EXHAUSTED, local_name, make_result_setup, ) -from connections import ITEMS, ItemType -from fizzler import FIZZLERS, FIZZ_TYPES -from srctools import Vec, Property, VMF, Entity, Output +from precomp.connections import ITEMS, ItemType +from precomp.fizzler import FIZZLERS, FIZZ_TYPES +import utils +import vbsp COND_MOD_NAME = None @@ -38,7 +38,7 @@ def res_make_tag_coop_spawn(vmf: VMF, inst: Entity, res: Property): if vbsp.GAME_MODE != 'COOP': return RES_EXHAUSTED - is_tag = vbsp_options.get(str, 'game_id') == utils.STEAM_IDS['TAG'] + is_tag = options.get(str, 'game_id') == utils.STEAM_IDS['TAG'] origin = res.vec('origin') normal = res.vec('facing', z=1) @@ -97,7 +97,7 @@ def ap_tag_modifications(vmf: VMF): * In singleplayer, override the transition ent instance to have the Gel Gun. * Create subdirectories with the user's steam ID to fix a workshop compile bug. """ - if vbsp_options.get(str, 'game_id') != utils.STEAM_IDS['APTAG']: + if options.get(str, 'game_id') != utils.STEAM_IDS['APTAG']: return # Wrong game! LOGGER.info('Performing Aperture Tag modifications...') @@ -177,7 +177,7 @@ def res_make_tag_fizzler(vmf: VMF, inst: Entity, res: Property): oran_sign_off, ) = res.value # type: int, ItemType, str, str, str, str, str, str import vbsp - if vbsp_options.get(str, 'game_id') != utils.STEAM_IDS['TAG']: + if options.get(str, 'game_id') != utils.STEAM_IDS['TAG']: # Abort - TAG fizzlers shouldn't appear in any other game! inst.remove() return diff --git a/src/conditions/brushes.py b/src/precomp/conditions/brushes.py similarity index 99% rename from src/conditions/brushes.py rename to src/precomp/conditions/brushes.py index 2029c8b0f..124efa719 100644 --- a/src/conditions/brushes.py +++ b/src/precomp/conditions/brushes.py @@ -2,20 +2,18 @@ import random from collections import defaultdict -import brushLoc -import conditions +from srctools import Property, NoKeyError, Vec, Output, Entity, VMF import srctools.logger -import template_brush -import vbsp -import tiling -import texturing -import faithplate -import comp_consts as const -import instance_traits -from conditions import ( - make_result, make_result_setup + +from precomp import ( + instance_traits, tiling, brushLoc, texturing, + faithplate, + template_brush, + conditions, ) -from srctools import Property, NoKeyError, Vec, Output, Entity, VMF +import vbsp +import consts +from precomp.conditions import make_result, make_result_setup from typing import Dict, Tuple, Optional, Callable, Set, Iterable, List @@ -768,7 +766,7 @@ def res_checkpoint_trigger(inst: Entity, res: Property) -> None: trig.solids.append(inst.map.make_prism( bbox_min, bbox_max, - mat=const.Tools.TRIGGER, + mat=consts.Tools.TRIGGER, ).solid) for prop in res: diff --git a/src/conditions/catwalks.py b/src/precomp/conditions/catwalks.py similarity index 98% rename from src/conditions/catwalks.py rename to src/precomp/conditions/catwalks.py index 28c52fe53..2184b793f 100644 --- a/src/conditions/catwalks.py +++ b/src/precomp/conditions/catwalks.py @@ -1,13 +1,10 @@ """Implement Catwalks.""" -import brushLoc -from conditions import ( - make_result, RES_EXHAUSTED, - INST_ANGLE, -) -import instanceLocs from srctools import Vec, Property, VMF, Entity import srctools.logger -from connections import ITEMS + +from precomp import brushLoc, instanceLocs +from precomp.conditions import make_result, RES_EXHAUSTED, INST_ANGLE +from precomp.connections import ITEMS import utils from typing import Dict, Tuple diff --git a/src/conditions/connections.py b/src/precomp/conditions/connections.py similarity index 96% rename from src/conditions/connections.py rename to src/precomp/conditions/connections.py index a14f51b6d..9776f6bd5 100644 --- a/src/conditions/connections.py +++ b/src/precomp/conditions/connections.py @@ -1,8 +1,8 @@ """Results relating to item connections.""" import srctools.logger -import connections -from conditions import ( - make_flag, make_result, make_result_setup, +from precomp import connections +from precomp.conditions import ( + make_result, make_result_setup, resolve_value, local_name, ) from srctools import Property, Entity, Output diff --git a/src/conditions/conveyorBelt.py b/src/precomp/conditions/conveyorBelt.py similarity index 97% rename from src/conditions/conveyorBelt.py rename to src/precomp/conditions/conveyorBelt.py index dd9bcbcae..2d695ffc0 100644 --- a/src/conditions/conveyorBelt.py +++ b/src/precomp/conditions/conveyorBelt.py @@ -2,11 +2,10 @@ """ from srctools import Property, Vec, Entity, Output, VMF -import conditions -import template_brush -import instanceLocs import srctools.logger -import comp_consts as const +from precomp import instanceLocs, template_brush, conditions +import consts + COND_MOD_NAME = None LOGGER = srctools.logger.get_logger(__name__, alias='cond.conveyorBelt') @@ -191,7 +190,7 @@ def res_conveyor_belt(vmf: VMF, inst: Entity, res: Property) -> None: motion_trig.solids.append(vmf.make_prism( start_pos + Vec(72, -56, 58).rotate(*angles), end_pos + Vec(-72, 56, 144).rotate(*angles), - mat=const.Tools.TRIGGER, + mat=consts.Tools.TRIGGER, ).solid) if res.bool('NoPortalFloor'): @@ -203,14 +202,14 @@ def res_conveyor_belt(vmf: VMF, inst: Entity, res: Property) -> None: floor_noportal.solids.append(vmf.make_prism( start_pos + Vec(-60, -60, -66).rotate(*angles), end_pos + Vec(60, 60, -60).rotate(*angles), - mat=const.Tools.INVISIBLE, + mat=consts.Tools.INVISIBLE, ).solid) # A brush covering under the platform. base_trig = vmf.make_prism( start_pos + Vec(-64, -64, 48).rotate(*angles), end_pos + Vec(64, 64, 56).rotate(*angles), - mat=const.Tools.INVISIBLE, + mat=consts.Tools.INVISIBLE, ).solid vmf.add_brush(base_trig) @@ -223,4 +222,4 @@ def res_conveyor_belt(vmf: VMF, inst: Entity, res: Property) -> None: ) pfizz.solids.append(base_trig.copy()) for face in pfizz.sides(): - face.mat = const.Tools.TRIGGER + face.mat = consts.Tools.TRIGGER diff --git a/src/conditions/custItems.py b/src/precomp/conditions/custItems.py similarity index 91% rename from src/conditions/custItems.py rename to src/precomp/conditions/custItems.py index b76f6d43a..9bce287e0 100644 --- a/src/conditions/custItems.py +++ b/src/precomp/conditions/custItems.py @@ -1,15 +1,12 @@ """Results for customising the behaviour of certain items - antlines, faith plates, """ -import antlines -import connections -import conditions +from typing import Optional, Tuple +from srctools import Property, Entity import srctools.logger -import template_brush -import vbsp -from srctools import Property, Vec, Entity -from typing import Optional, Tuple +from precomp import connections, antlines, conditions + COND_MOD_NAME = 'Custom Items' @@ -35,7 +32,8 @@ def res_cust_antline_setup(res: Property): res['toggle_var', ''], ) -CustAntValue = Tuple[Optional[antlines.AntType], Optional[antlines.AntType], bool, str] +CustAntValue = Tuple[Optional[antlines.AntType], Optional[ + antlines.AntType], bool, str] @conditions.make_result('custAntline') diff --git a/src/conditions/cutoutTile.py b/src/precomp/conditions/cutoutTile.py similarity index 99% rename from src/conditions/cutoutTile.py rename to src/precomp/conditions/cutoutTile.py index 747c34fe1..ac18b9368 100644 --- a/src/conditions/cutoutTile.py +++ b/src/precomp/conditions/cutoutTile.py @@ -3,14 +3,15 @@ from collections import defaultdict, namedtuple from typing import Tuple, Set, Dict, List -import conditions -import connections import srctools.logger -import template_brush import utils import vbsp -import comp_consts as consts -import instanceLocs +from precomp import ( + instanceLocs, connections, + template_brush, + conditions, +) +import consts from perlin import SimplexNoise from srctools import Property, Vec_tuple, Vec, Side, UVAxis, VMF diff --git a/src/conditions/entities.py b/src/precomp/conditions/entities.py similarity index 97% rename from src/conditions/entities.py rename to src/precomp/conditions/entities.py index 56b523e0b..04435e5c6 100644 --- a/src/conditions/entities.py +++ b/src/precomp/conditions/entities.py @@ -3,15 +3,13 @@ from collections import defaultdict from typing import List, Dict, Tuple -import conditions -import srctools.logger -import template_brush -import texturing -import tiling -from brushLoc import POS as BLOCK_POS -from conditions import make_result, make_result_setup -from template_brush import TEMP_TYPES from srctools import Property, Vec, VMF, Entity +import srctools.logger + +from precomp import tiling, texturing, template_brush, conditions +from precomp.brushLoc import POS as BLOCK_POS +from precomp.conditions import make_result, make_result_setup +from precomp.template_brush import TEMP_TYPES COND_MOD_NAME = 'Entities' diff --git a/src/conditions/faithplate.py b/src/precomp/conditions/faithplate.py similarity index 96% rename from src/conditions/faithplate.py rename to src/precomp/conditions/faithplate.py index 84ac04b38..4339c36d5 100644 --- a/src/conditions/faithplate.py +++ b/src/precomp/conditions/faithplate.py @@ -1,12 +1,11 @@ """Modify and inspect faith plates.""" import srctools.logger -import faithplate -import template_brush -from conditions import ( +from precomp import faithplate, template_brush +from precomp.conditions import ( make_flag, make_result, make_result_setup, RES_EXHAUSTED, ) -from srctools import Property, Entity, VMF +from srctools import Property, Entity COND_MOD_NAME = 'Faith Plates' diff --git a/src/conditions/fizzler.py b/src/precomp/conditions/fizzler.py similarity index 96% rename from src/conditions/fizzler.py rename to src/precomp/conditions/fizzler.py index 259c5530d..80180f8a7 100644 --- a/src/conditions/fizzler.py +++ b/src/precomp/conditions/fizzler.py @@ -1,11 +1,12 @@ """Results for custom fizzlers.""" -from conditions import make_result, make_flag from srctools import Property, Entity, Vec, VMF -from instanceLocs import resolve as resolve_inst -import connections -import fizzler import srctools.logger +from precomp.conditions import make_result, make_flag +from precomp.instanceLocs import resolve as resolve_inst +from precomp import connections, fizzler + + COND_MOD_NAME = 'Fizzlers' LOGGER = srctools.logger.get_logger(__name__, alias='cond.fizzler') diff --git a/src/conditions/glass.py b/src/precomp/conditions/glass.py similarity index 97% rename from src/conditions/glass.py rename to src/precomp/conditions/glass.py index 0f109a7ef..f5d8a5181 100644 --- a/src/conditions/glass.py +++ b/src/precomp/conditions/glass.py @@ -1,11 +1,11 @@ """Adds breakable glass.""" -from conditions import make_result_setup, make_result, RES_EXHAUSTED, local_name -from instanceLocs import resolve as resolve_inst -from srctools import Property, Vec, VMF, Solid, Side, Entity, Output +from precomp.conditions import make_result_setup, make_result, RES_EXHAUSTED +from precomp.instanceLocs import resolve as resolve_inst +from srctools import Property, Vec, VMF, Side, Entity, Output import srctools.logger -import comp_consts as const -import template_brush +from precomp import template_brush +import consts from typing import Iterator, Any, Tuple, Dict, List, Optional @@ -322,7 +322,7 @@ def res_breakable_glass(inst: Entity, res: Property): vmf.make_prism( clip_min, clip_max, - mat=const.Tools.NODRAW, + mat=consts.Tools.NODRAW, ).solid ) diff --git a/src/conditions/globals.py b/src/precomp/conditions/globals.py similarity index 91% rename from src/conditions/globals.py rename to src/precomp/conditions/globals.py index edf154ded..f09aa1f5a 100644 --- a/src/conditions/globals.py +++ b/src/precomp/conditions/globals.py @@ -1,14 +1,13 @@ """Conditions related to global properties - stylevars, music, which game, etc.""" -import utils -import vbsp_options - from srctools import Vec, Property, Entity, conv_bool, VMF -from conditions import ( - make_flag, make_result, RES_EXHAUSTED, -) -import vbsp import srctools.logger +from precomp import options +from precomp.conditions import make_flag, make_result, RES_EXHAUSTED +import vbsp +import utils + + LOGGER = srctools.logger.get_logger(__name__, alias='cond.globals') COND_MOD_NAME = 'Global Properties' @@ -58,7 +57,7 @@ def flag_game(flag: Property) -> bool: - `DEST_AP` - `Destroyed Aperture` """ - return vbsp_options.get(str, 'game_id') == utils.STEAM_IDS.get( + return options.get(str, 'game_id') == utils.STEAM_IDS.get( flag.value.upper(), flag.value, ) @@ -74,8 +73,8 @@ def flag_voice_char(flag: Property) -> bool: """ targ_char = flag.value.casefold() if targ_char == '': - return vbsp_options.get(str, 'voice_id') == '' - for char in vbsp_options.get(str, 'voice_char').split(','): + return options.get(str, 'voice_id') == '' + for char in options.get(str, 'voice_char').split(','): if targ_char in char.casefold(): return True return False @@ -85,7 +84,7 @@ def flag_voice_char(flag: Property) -> bool: def res_cave_portrait() -> bool: """Checks to see if the Cave Portrait option is set for the given voice pack. """ - return vbsp_options.get(int, 'cave_port_skin') is not None + return options.get(int, 'cave_port_skin') is not None @make_flag('ifMode', 'iscoop', 'gamemode') @@ -125,7 +124,7 @@ def res_set_option(res: Property) -> bool: Each child property will be set. """ for opt in res.value: - vbsp_options.set_opt(opt.name, opt.value) + options.set_opt(opt.name, opt.value) return RES_EXHAUSTED @@ -146,7 +145,7 @@ def res_match_item_config(inst: Entity, res: Property) -> bool: else: timer_delay = None - conf = vbsp_options.get_itemconf((group_id, wid_name), None, timer_delay) + conf = options.get_itemconf((group_id, wid_name), None, timer_delay) if conf is None: # Doesn't exist return False @@ -211,7 +210,7 @@ def precache_model(vmf: VMF, mdl_name: str): CACHED_MODELS.add(mdl_name) vmf.create_ent( classname='comp_precache_model', - origin=vbsp_options.get(Vec, 'global_ents_loc'), + origin=options.get(Vec, 'global_ents_loc'), model=mdl_name, ) @@ -234,7 +233,7 @@ def res_item_config_to_fixup(inst: Entity, res: Property): else: timer_delay = None - inst.fixup[res['ResultVar']] = vbsp_options.get_itemconf( + inst.fixup[res['ResultVar']] = options.get_itemconf( (group_id, wid_name), default, timer_delay, diff --git a/src/conditions/instances.py b/src/precomp/conditions/instances.py similarity index 99% rename from src/conditions/instances.py rename to src/precomp/conditions/instances.py index 35aac3b90..24299ab6f 100644 --- a/src/conditions/instances.py +++ b/src/precomp/conditions/instances.py @@ -5,14 +5,12 @@ from typing import Dict, Optional, Union -import conditions import srctools.logger -from conditions import ( +from precomp.conditions import ( make_flag, make_result, make_result_setup, ALL_INST, ) -import instanceLocs -import instance_traits +from precomp import instance_traits, instanceLocs, conditions from srctools import Property, Vec, Entity, Output, VMF LOGGER = srctools.logger.get_logger(__name__, 'cond.instances') diff --git a/src/conditions/logical.py b/src/precomp/conditions/logical.py similarity index 96% rename from src/conditions/logical.py rename to src/precomp/conditions/logical.py index 4e21da605..1ec77d5ae 100644 --- a/src/conditions/logical.py +++ b/src/precomp/conditions/logical.py @@ -1,6 +1,6 @@ """Logical flags used to combine others (AND, OR, NOT, etc).""" -from conditions import make_flag, check_flag +from precomp.conditions import make_flag, check_flag from srctools import Entity, Property COND_MOD_NAME = 'Logic' diff --git a/src/conditions/monitor.py b/src/precomp/conditions/monitor.py similarity index 92% rename from src/conditions/monitor.py rename to src/precomp/conditions/monitor.py index d9bda0a80..063f88e95 100644 --- a/src/conditions/monitor.py +++ b/src/precomp/conditions/monitor.py @@ -1,16 +1,9 @@ import math -import connections -from conditions import ( - make_result, make_result_setup, meta_cond, - local_name -) -import instanceLocs -import faithplate +from precomp.conditions import make_result, make_result_setup, meta_cond, local_name +from precomp import instanceLocs, connections, options, faithplate, voice_line from srctools import Property, Vec, Entity, VMF, Output import srctools.logger -import vbsp_options -import voiceLine from typing import List, NamedTuple @@ -38,7 +31,7 @@ class Camera(NamedTuple): def get_studio_pose() -> Vec: """Return the position of the studio camera.""" - return voiceLine.get_studio_loc() + vbsp_options.get(Vec, 'voice_studio_cam_loc') + return voice_line.get_studio_loc() + options.get(Vec, 'voice_studio_cam_loc') def scriptvar_set( @@ -101,7 +94,7 @@ def res_monitor(inst: Entity, res: Property) -> None: has_laser = vbsp.settings['has_attr']['laser'] # Allow turrets if the monitor is setup to allow it, and the actor should # be shot. - needs_turret = bullseye_name and vbsp_options.get(bool, 'voice_studio_should_shoot') + needs_turret = bullseye_name and options.get(bool, 'voice_studio_should_shoot') inst.fixup['$is_breakable'] = has_laser or needs_turret @@ -287,12 +280,12 @@ def mon_camera_link(vmf: VMF) -> None: break else: # No cameras start active, we need to be positioned elsewhere. - if vbsp_options.get(str, 'voice_studio_inst'): + if options.get(str, 'voice_studio_inst'): # Start at the studio, if it exists. start_pos = get_studio_pose() start_angles = '{:g} {:g} 0'.format( - vbsp_options.get(float, 'voice_studio_cam_pitch'), - vbsp_options.get(float, 'voice_studio_cam_yaw'), + options.get(float, 'voice_studio_cam_pitch'), + options.get(float, 'voice_studio_cam_yaw'), ) # If we start at the studio, make the ai_relationships # for turret fire start active. @@ -363,18 +356,18 @@ def mon_camera_link(vmf: VMF) -> None: value=active, ) - if vbsp_options.get(str, 'voice_studio_inst'): + if options.get(str, 'voice_studio_inst'): # We have a voice studio, send values to the script. scriptvar_set(cam_ent, get_studio_pose(), 'CAM_STUDIO_LOC', mode='pos') scriptvar_set( cam_ent, get_studio_pose(), 'CAM_STUDIO_ANG', mode='ang', angles='{:g} {:g} 0'.format( - vbsp_options.get(float, 'voice_studio_cam_pitch'), - vbsp_options.get(float, 'voice_studio_cam_yaw'), + options.get(float, 'voice_studio_cam_pitch'), + options.get(float, 'voice_studio_cam_yaw'), ), ) use_turret = '1' if MONITOR_RELATIONSHIP_ENTS else '0' - swap_chance = vbsp_options.get(float, 'voice_studio_inter_chance') + swap_chance = options.get(float, 'voice_studio_inter_chance') else: use_turret = '0' swap_chance = -1 @@ -389,8 +382,8 @@ def make_voice_studio(vmf: VMF) -> bool: This is either an instance (if monitors are present), or a nodraw room. """ - studio_file = vbsp_options.get(str, 'voice_studio_inst') - loc = voiceLine.get_studio_loc() + studio_file = options.get(str, 'voice_studio_inst') + loc = voice_line.get_studio_loc() if HAS_MONITOR and studio_file: vmf.create_ent( diff --git a/src/conditions/piston_platform.py b/src/precomp/conditions/piston_platform.py similarity index 96% rename from src/conditions/piston_platform.py rename to src/precomp/conditions/piston_platform.py index 041168c95..85754c81e 100644 --- a/src/conditions/piston_platform.py +++ b/src/precomp/conditions/piston_platform.py @@ -1,17 +1,15 @@ """Handles generating Piston Platforms with specific logic.""" from typing import Dict, List, Optional -import conditions -import packing +from precomp import packing, template_brush, conditions import srctools.logger -import template_brush -from comp_consts import FixupVars -from conditions import make_result, make_result_setup, local_name -from connections import ITEMS -from instanceLocs import resolve_one as resolve_single +from consts import FixupVars +from precomp.conditions import make_result, make_result_setup, local_name +from precomp.connections import ITEMS +from precomp.instanceLocs import resolve_one as resolve_single from srctools import Entity, VMF, Property, Output, Vec -from texturing import GenCat -from tiling import TILES, Panel +from precomp.texturing import GenCat +from precomp.tiling import TILES, Panel COND_MOD_NAME = 'Piston Platform' diff --git a/src/conditions/positioning.py b/src/precomp/conditions/positioning.py similarity index 98% rename from src/conditions/positioning.py rename to src/precomp/conditions/positioning.py index c4b846af7..14b85bedf 100644 --- a/src/conditions/positioning.py +++ b/src/precomp/conditions/positioning.py @@ -1,12 +1,11 @@ import math -from typing import Tuple, Dict, Callable, Set +from typing import Tuple, Dict, Set -from conditions import ( +from precomp.conditions import ( make_flag, make_result, resolve_offset, DIRECTIONS, ) -import tiling -import brushLoc +from precomp import tiling, brushLoc from srctools import Vec, Entity, Property from srctools.logger import get_logger @@ -473,7 +472,7 @@ def res_calc_opposite_wall_dist(inst: Entity, res: Property): mask, ) - if adjust_goo and brushLoc.POS['world': opposing_pos + 128*normal].is_goo: + if adjust_goo and brushLoc.POS['world': opposing_pos + 128 * normal].is_goo: # If the top is goo, adjust so the 64 below is the top of the goo. dist_off += 32 diff --git a/src/conditions/python.py b/src/precomp/conditions/python.py similarity index 99% rename from src/conditions/python.py rename to src/precomp/conditions/python.py index 6389e2eff..6128fe188 100644 --- a/src/conditions/python.py +++ b/src/precomp/conditions/python.py @@ -2,7 +2,7 @@ import ast from typing import List, Dict, Any, Callable, Tuple -from conditions import make_result_setup, make_result +from precomp.conditions import make_result_setup, make_result from srctools import Property, Vec, Entity, conv_bool import srctools.logger from srctools.vmf import EntityFixup diff --git a/src/conditions/randomise.py b/src/precomp/conditions/randomise.py similarity index 99% rename from src/conditions/randomise.py rename to src/precomp/conditions/randomise.py index 34fc9a35b..3bf15ab62 100644 --- a/src/conditions/randomise.py +++ b/src/precomp/conditions/randomise.py @@ -3,10 +3,10 @@ from typing import List from srctools import Property, Vec, Entity -import conditions +from precomp import conditions import srctools -from conditions import ( +from precomp.conditions import ( Condition, make_flag, make_result, make_result_setup, RES_EXHAUSTED, set_random_seed, ) diff --git a/src/conditions/removed.py b/src/precomp/conditions/removed.py similarity index 94% rename from src/conditions/removed.py rename to src/precomp/conditions/removed.py index 9a16c06ae..8e805482d 100644 --- a/src/conditions/removed.py +++ b/src/precomp/conditions/removed.py @@ -1,5 +1,5 @@ """Conditions that were present in older versions only.""" -from conditions import RES_EXHAUSTED, make_flag, make_result +from precomp.conditions import RES_EXHAUSTED, make_flag, make_result import srctools.logger COND_MOD_NAME = 'Removed' diff --git a/src/conditions/resizableTrigger.py b/src/precomp/conditions/resizableTrigger.py similarity index 96% rename from src/conditions/resizableTrigger.py rename to src/precomp/conditions/resizableTrigger.py index c7a1b7950..e3df0866f 100644 --- a/src/conditions/resizableTrigger.py +++ b/src/precomp/conditions/resizableTrigger.py @@ -1,17 +1,17 @@ """Logic for trigger items, allowing them to be resized.""" from contextlib import suppress - -import conditions -import instanceLocs +from srctools import Property, Vec, Output, VMF import srctools.logger -import vbsp -import vbsp_options -import comp_consts as const -import connections -from conditions import ( + +from precomp.conditions import ( make_result, RES_EXHAUSTED, ) -from srctools import Property, Vec, Output, VMF +from precomp import instanceLocs +from precomp import connections +from precomp import options +from precomp import conditions +import consts +import vbsp COND_MOD_NAME = None @@ -96,7 +96,7 @@ def res_resizeable_trigger(vmf: VMF, res: Property): # Display preview overlays if it's preview mode, and the config is true pre_act = pre_deact = None - if vbsp.IS_PREVIEW and vbsp_options.get_itemconf(res['previewConf', ''], False): + if vbsp.IS_PREVIEW and options.get_itemconf(res['previewConf', ''], False): preview_mat = res['previewMat', ''] preview_inst_file = res['previewInst', ''] preview_scale = res.float('previewScale', 0.25) @@ -157,14 +157,14 @@ def res_resizeable_trigger(vmf: VMF, res: Property): out_ent = trig_ent = vmf.create_ent( classname='trigger_multiple', # Default targetname=targ, - origin=vbsp_options.get(Vec, "global_ents_loc"), + origin=options.get(Vec, "global_ents_loc"), angles='0 0 0', ) trig_ent.solids = [ vmf.make_prism( bbox_min, bbox_max, - mat=const.Tools.TRIGGER, + mat=consts.Tools.TRIGGER, ).solid, ] diff --git a/src/conditions/scaffold.py b/src/precomp/conditions/scaffold.py similarity index 98% rename from src/conditions/scaffold.py rename to src/precomp/conditions/scaffold.py index 41d7d23ea..52cced20d 100644 --- a/src/conditions/scaffold.py +++ b/src/precomp/conditions/scaffold.py @@ -1,16 +1,13 @@ """The result used to generate unstationary scaffolds.""" -import math from typing import Tuple, Optional - from enum import Enum +import math -import instanceLocs -import item_chain -import srctools.logger -from conditions import ( - make_result, make_result_setup, RES_EXHAUSTED, -) from srctools import Vec, Property, VMF +import srctools.logger + +from precomp import instanceLocs, item_chain +from precomp.conditions import make_result, make_result_setup, RES_EXHAUSTED class LinkType(Enum): diff --git a/src/conditions/sendificator.py b/src/precomp/conditions/sendificator.py similarity index 98% rename from src/conditions/sendificator.py rename to src/precomp/conditions/sendificator.py index 5a5e6690a..1fb7881c9 100644 --- a/src/conditions/sendificator.py +++ b/src/precomp/conditions/sendificator.py @@ -1,7 +1,6 @@ from typing import Tuple, Dict -import conditions -import connections +from precomp import connections, conditions import srctools.logger from srctools import Property, Entity, VMF, Vec, Output diff --git a/src/conditions/signage.py b/src/precomp/conditions/signage.py similarity index 94% rename from src/conditions/signage.py rename to src/precomp/conditions/signage.py index 11d677b9a..39307370b 100644 --- a/src/conditions/signage.py +++ b/src/precomp/conditions/signage.py @@ -2,14 +2,12 @@ from typing import Tuple, Dict, Optional, Iterable, List from enum import Enum -import conditions import srctools.logger -import tiling -import texturing -import template_brush +from precomp import tiling, texturing, template_brush, conditions +import consts from srctools import Property, Entity, VMF, Vec, NoKeyError from srctools.vmf import make_overlay, Side -import comp_consts as const + COND_MOD_NAME = None @@ -102,12 +100,12 @@ def res_signage(vmf: VMF, inst: Entity, res: Property): CONN_SIGNAGES if res.bool('connection') else SIGNAGES - )[inst.fixup[const.FixupVars.TIM_DELAY]] + )[inst.fixup[consts.FixupVars.TIM_DELAY]] except KeyError: # Blank sign sign = None - has_arrow = inst.fixup.bool(const.FixupVars.ST_ENABLED) + has_arrow = inst.fixup.bool(consts.FixupVars.ST_ENABLED) sign_prim: Optional[Sign] sign_sec: Optional[Sign] @@ -137,7 +135,7 @@ def res_signage(vmf: VMF, inst: Entity, res: Property): template_id = res['template_id', ''] - if inst.fixup.bool(const.FixupVars.ST_REVERSED): + if inst.fixup.bool(consts.FixupVars.ST_REVERSED): # Flip around. forward = -forward prim_visgroup = 'secondary' @@ -180,7 +178,7 @@ def res_signage(vmf: VMF, inst: Entity, res: Property): # Find the grid pos first. grid_pos = (origin // 128) * 128 + 64 try: - tiledef = tiling.TILES[(grid_pos + 128*normal).as_tuple(), (-normal).as_tuple()] + tiledef = tiling.TILES[(grid_pos + 128 * normal).as_tuple(), (-normal).as_tuple()] except KeyError: LOGGER.warning( "Can't place signage at ({}) in ({}) direction!", diff --git a/src/conditions/trackPlat.py b/src/precomp/conditions/trackPlat.py similarity index 98% rename from src/conditions/trackPlat.py rename to src/precomp/conditions/trackPlat.py index 86e6a82d3..8a10a2f89 100644 --- a/src/conditions/trackPlat.py +++ b/src/precomp/conditions/trackPlat.py @@ -1,12 +1,11 @@ """Conditions relating to track platforms.""" from typing import Set, Dict, Tuple -import conditions import srctools.logger -from conditions import ( +from precomp.conditions import ( make_result, RES_EXHAUSTED, ) -import instanceLocs +from precomp import instanceLocs, conditions from srctools import Vec, Property, Entity, VMF diff --git a/src/conditions/vactubes.py b/src/precomp/conditions/vactubes.py similarity index 99% rename from src/conditions/vactubes.py rename to src/precomp/conditions/vactubes.py index d80245964..3bd506338 100644 --- a/src/conditions/vactubes.py +++ b/src/precomp/conditions/vactubes.py @@ -3,18 +3,16 @@ from collections import namedtuple from typing import Dict, Tuple, List, Iterator, Optional -import connections +from srctools import Vec, Vec_tuple, Property, Entity, VMF import srctools.logger -import template_brush -import tiling -import vbsp -from brushLoc import POS as BLOCK_POS -from conditions import ( + +from precomp import tiling, instanceLocs, connections, template_brush +from precomp.brushLoc import POS as BLOCK_POS +from precomp.conditions import ( make_result, make_result_setup, RES_EXHAUSTED, meta_cond ) -import instanceLocs -from srctools import Vec, Vec_tuple, Property, Entity, VMF +import vbsp COND_MOD_NAME = None diff --git a/src/connections.py b/src/precomp/connections.py similarity index 95% rename from src/connections.py rename to src/precomp/connections.py index 432e9c00d..ea288a278 100644 --- a/src/connections.py +++ b/src/precomp/connections.py @@ -7,14 +7,15 @@ from collections import defaultdict from srctools import VMF, Entity, Output, Property, conv_bool, Vec -from antlines import Antline, AntType -import comp_consts as const -import instanceLocs -import conditions -import instance_traits +from precomp.antlines import Antline, AntType +from precomp import ( + instance_traits, instanceLocs, + options, + packing, + conditions, +) +import consts import srctools.logger -import vbsp_options -import packing from typing import Optional, Iterable, Dict, List, Set, Tuple, Iterator, Union @@ -40,10 +41,10 @@ # interfere with each other. We use the 'inst_local' pattern not 'inst-local' # deliberately so the actual item can't affect the IO input. COUNTER_NAME = { - const.FixupVars.CONN_COUNT: '_counter', - const.FixupVars.CONN_COUNT_TBEAM: '_counter_polarity', - const.FixupVars.BEE_CONN_COUNT_A: '_counter_a', - const.FixupVars.BEE_CONN_COUNT_B: '_counter_b', + consts.FixupVars.CONN_COUNT: '_counter', + consts.FixupVars.CONN_COUNT_TBEAM: '_counter_polarity', + consts.FixupVars.BEE_CONN_COUNT_A: '_counter_a', + consts.FixupVars.BEE_CONN_COUNT_B: '_counter_b', } @@ -155,16 +156,16 @@ def valid(self, item: 'Item') -> bool: # The order signs are used in maps. SIGN_ORDER = [ - const.Signage.SHAPE_DOT, - const.Signage.SHAPE_MOON, - const.Signage.SHAPE_TRIANGLE, - const.Signage.SHAPE_CROSS, - const.Signage.SHAPE_SQUARE, - const.Signage.SHAPE_CIRCLE, - const.Signage.SHAPE_SINE, - const.Signage.SHAPE_SLASH, - const.Signage.SHAPE_STAR, - const.Signage.SHAPE_WAVY + consts.Signage.SHAPE_DOT, + consts.Signage.SHAPE_MOON, + consts.Signage.SHAPE_TRIANGLE, + consts.Signage.SHAPE_CROSS, + consts.Signage.SHAPE_SQUARE, + consts.Signage.SHAPE_CIRCLE, + consts.Signage.SHAPE_SINE, + consts.Signage.SHAPE_SLASH, + consts.Signage.SHAPE_STAR, + consts.Signage.SHAPE_WAVY ] SIGN_ORDER_LOOKUP = { @@ -813,7 +814,8 @@ def calc_connections( else: # Normal item. try: - item_type = ITEM_TYPES[instance_traits.get_item_id(inst).casefold()] + item_type = ITEM_TYPES[ + instance_traits.get_item_id(inst).casefold()] except (KeyError, AttributeError): # KeyError from no item type, AttributeError from None.casefold() # These aren't made for non-io items. If it has outputs, @@ -826,8 +828,8 @@ def calc_connections( # Strip off the original connection count variables, these are # invalid. if item_type.input_type is InputType.DUAL: - del inst.fixup[const.FixupVars.CONN_COUNT] - del inst.fixup[const.FixupVars.CONN_COUNT_TBEAM] + del inst.fixup[consts.FixupVars.CONN_COUNT] + del inst.fixup[consts.FixupVars.CONN_COUNT_TBEAM] for over in vmf.by_class['info_overlay']: name = over['targetname'] @@ -867,9 +869,9 @@ def calc_connections( item.inst.outputs.clear() # Pre-set the timer value, for items without antlines but with an output. - if const.FixupVars.TIM_DELAY in item.inst.fixup: + if consts.FixupVars.TIM_DELAY in item.inst.fixup: if item.item_type.output_act or item.item_type.output_deact: - item.timer = tim = item.inst.fixup.int(const.FixupVars.TIM_DELAY) + item.timer = tim = item.inst.fixup.int(consts.FixupVars.TIM_DELAY) if not (1 <= tim <= 30): # These would be infinite. item.timer = None @@ -891,8 +893,8 @@ def calc_connections( elif out_name in panels: pan = panels[out_name] item.ind_panels.add(pan) - if pan.fixup.bool(const.FixupVars.TIM_ENABLED): - item.timer = tim = pan.fixup.int(const.FixupVars.TIM_DELAY) + if pan.fixup.bool(consts.FixupVars.TIM_ENABLED): + item.timer = tim = pan.fixup.int(consts.FixupVars.TIM_DELAY) if not (1 <= tim <= 30): # These would be infinite. item.timer = None @@ -1034,7 +1036,7 @@ def do_item_optimisation(vmf: VMF) -> None: if needs_global_toggle: vmf.create_ent( classname='env_texturetoggle', - origin=vbsp_options.get(Vec, 'global_ents_loc'), + origin=options.get(Vec, 'global_ents_loc'), targetname='_static_ind_tog', target='_static_ind', ) @@ -1051,8 +1053,8 @@ def gen_item_outputs(vmf: VMF) -> None: """ LOGGER.info('Generating item IO...') - pan_switching_check = vbsp_options.get(PanelSwitchingStyle, 'ind_pan_check_switching') - pan_switching_timer = vbsp_options.get(PanelSwitchingStyle, 'ind_pan_timer_switching') + pan_switching_check = options.get(PanelSwitchingStyle, 'ind_pan_check_switching') + pan_switching_timer = options.get(PanelSwitchingStyle, 'ind_pan_timer_switching') pan_check_type = ITEM_TYPES['item_indicator_panel'] pan_timer_type = ITEM_TYPES['item_indicator_panel_timer'] @@ -1156,7 +1158,7 @@ def gen_item_outputs(vmf: VMF) -> None: item, InputType.AND, prim_inputs, - const.FixupVars.BEE_CONN_COUNT_A, + consts.FixupVars.BEE_CONN_COUNT_A, item.enable_cmd, item.disable_cmd, item.item_type.invert_var, @@ -1165,7 +1167,7 @@ def gen_item_outputs(vmf: VMF) -> None: item, InputType.AND, sec_inputs, - const.FixupVars.BEE_CONN_COUNT_B, + consts.FixupVars.BEE_CONN_COUNT_B, item.sec_enable_cmd, item.sec_disable_cmd, item.item_type.sec_invert_var, @@ -1175,7 +1177,7 @@ def gen_item_outputs(vmf: VMF) -> None: item, item.item_type.input_type, list(item.inputs), - const.FixupVars.CONN_COUNT, + consts.FixupVars.CONN_COUNT, item.enable_cmd, item.disable_cmd, item.item_type.invert_var, @@ -1192,11 +1194,11 @@ def gen_item_outputs(vmf: VMF) -> None: for pan in item.ind_panels: pan['file'] = desired_panel_inst - pan.fixup[const.FixupVars.TIM_ENABLED] = item.timer is not None + pan.fixup[consts.FixupVars.TIM_ENABLED] = item.timer is not None logic_auto = vmf.create_ent( 'logic_auto', - origin=vbsp_options.get(Vec, 'global_ents_loc') + origin=options.get(Vec, 'global_ents_loc') ) for ent in auto_logic: @@ -1310,8 +1312,8 @@ def add_timer_relay(item: Item, has_sounds: bool) -> None: )) if item.item_type.timer_sound_pos is not None and has_sounds: - timer_sound = vbsp_options.get(str, 'timer_sound') - timer_cc = vbsp_options.get(str, 'timer_sound_cc') + timer_sound = options.get(str, 'timer_sound') + timer_cc = options.get(str, 'timer_sound_cc') # The default sound has 'ticking' closed captions. # So reuse that if the style doesn't specify a different noise. @@ -1413,8 +1415,8 @@ def add_item_inputs( ) if ( - count_var is const.FixupVars.BEE_CONN_COUNT_A or - count_var is const.FixupVars.BEE_CONN_COUNT_B + count_var is consts.FixupVars.BEE_CONN_COUNT_A or + count_var is consts.FixupVars.BEE_CONN_COUNT_B ): LOGGER.warning( '{}: Daisychain logic type is ' @@ -1678,23 +1680,23 @@ def add_item_indicators( for pan in item.ind_panels: if inst_type is PanelSwitchingStyle.EXTERNAL: - pan.fixup[const.FixupVars.TOGGLE_OVERLAY] = ant_name + pan.fixup[consts.FixupVars.TOGGLE_OVERLAY] = ant_name # Ensure only one gets the indicator name. elif first_inst and inst_type is PanelSwitchingStyle.INTERNAL: - pan.fixup[const.FixupVars.TOGGLE_OVERLAY] = ant_name if has_ant else ' ' + pan.fixup[consts.FixupVars.TOGGLE_OVERLAY] = ant_name if has_ant else ' ' first_inst = False else: # VBSP and/or Hammer seems to get confused with totally empty # instance var, so give it a blank name. - pan.fixup[const.FixupVars.TOGGLE_OVERLAY] = '-' + pan.fixup[consts.FixupVars.TOGGLE_OVERLAY] = '-' # Overwrite the timer delay value, in case a sign changed ownership. if item.timer is not None: - pan.fixup[const.FixupVars.TIM_DELAY] = item.timer - pan.fixup[const.FixupVars.TIM_ENABLED] = '1' + pan.fixup[consts.FixupVars.TIM_DELAY] = item.timer + pan.fixup[consts.FixupVars.TIM_ENABLED] = '1' else: - pan.fixup[const.FixupVars.TIM_DELAY] = '99999999999' - pan.fixup[const.FixupVars.TIM_ENABLED] = '0' + pan.fixup[consts.FixupVars.TIM_DELAY] = '99999999999' + pan.fixup[consts.FixupVars.TIM_ENABLED] = '0' for outputs, input_cmds in [ (item.timer_output_start(), pan_item.enable_cmd), diff --git a/src/cubes.py b/src/precomp/cubes.py similarity index 99% rename from src/cubes.py rename to src/precomp/cubes.py index 0e0cf0a06..a7bc460ae 100644 --- a/src/cubes.py +++ b/src/precomp/cubes.py @@ -7,17 +7,14 @@ from enum import Enum from typing import Dict, Optional, List, Union, Tuple, Set, FrozenSet, Iterable -import brushLoc -import packing -import vbsp_options -from conditions import meta_cond, make_result, make_flag, RES_EXHAUSTED -from instanceLocs import resolve as resolve_inst +from precomp import brushLoc, options, packing, conditions +from precomp.conditions import meta_cond, make_result, make_flag, RES_EXHAUSTED +from precomp.instanceLocs import resolve as resolve_inst from srctools import ( - Property, NoKeyError, VMF, Entity, Vec, Output, + Property, VMF, Entity, Vec, Output, EmptyMapping ) import srctools.logger -import conditions.globals from srctools.vmf import EntityFixup @@ -957,7 +954,8 @@ def res_set_dropper_off(inst: Entity, res: Property) -> None: except AttributeError: LOGGER.warning('SetDropperOffset applied to non cube ("{}")', res.value) else: - pair.spawn_offset = Vec.from_str(conditions.resolve_value(inst, res.value)) + pair.spawn_offset = Vec.from_str( + conditions.resolve_value(inst, res.value)) @make_result('ChangeCubeType', 'SetCubeType') @@ -1250,7 +1248,7 @@ def link_cubes(vmf: VMF): # The instance is useless now we know about it. inst.remove() - color = Vec.from_str(vbsp_options.get_itemconf( + color = Vec.from_str(options.get_itemconf( ('BEE2_CUBE_COLORISER', 'COLOR'), '255 255 255', timer_delay=inst.fixup.int('$timer_delay'), @@ -1646,7 +1644,7 @@ def generate_cubes(vmf: VMF): CUBE_SKINS[spawn_paint, pair.cube_type.type], ), )) - conditions.globals.precache_model(vmf, cust_model) + precomp.conditions.globals.precache_model(vmf, cust_model) drop_cube = cube = should_respawn = None diff --git a/src/faithplate.py b/src/precomp/faithplate.py similarity index 98% rename from src/faithplate.py rename to src/precomp/faithplate.py index 13f9a4e4a..5afebf425 100644 --- a/src/faithplate.py +++ b/src/precomp/faithplate.py @@ -4,11 +4,7 @@ """ import collections -import brushLoc -import conditions -import instanceLocs -import tiling -import template_brush +from precomp import tiling, brushLoc, instanceLocs, template_brush, conditions from srctools import Entity, Vec, VMF from srctools.logger import get_logger diff --git a/src/fizzler.py b/src/precomp/fizzler.py similarity index 98% rename from src/fizzler.py rename to src/precomp/fizzler.py index fb19c15c2..1c914885d 100644 --- a/src/fizzler.py +++ b/src/precomp/fizzler.py @@ -6,20 +6,21 @@ import itertools from enum import Enum -import conditions -import connections -import packing -import texturing import utils -import vbsp_options import srctools.logger import srctools.vmf from srctools import Output, Vec, VMF, Solid, Entity, Side, Property, NoKeyError -import comp_consts as const -import instance_traits -import instanceLocs -import template_brush -import tiling +from precomp import ( + instance_traits, tiling, instanceLocs, + texturing, + connections, + options, + packing, + template_brush, + conditions, +) +import consts + LOGGER = srctools.logger.get_logger(__name__) @@ -102,7 +103,7 @@ def read_configs(conf: Property) -> None: LOGGER.info('Loaded {} fizzlers.', len(FIZZ_TYPES)) - if vbsp_options.get(str, 'game_id') != utils.STEAM_IDS['APTAG']: + if options.get(str, 'game_id') != utils.STEAM_IDS['APTAG']: return # In Aperture Tag, we don't have portals. For fizzler types which block # portals (trigger_portal_cleanser), additionally fizzle paint. @@ -127,7 +128,7 @@ def read_configs(conf: Property) -> None: fizz.brushes.append(FizzlerBrush( brush_name, textures={ - TexGroup.TRIGGER: const.Tools.TRIGGER, + TexGroup.TRIGGER: consts.Tools.TRIGGER, }, keys={ 'classname': 'trigger_paint_cleanser', @@ -380,12 +381,12 @@ def gen_flinch_trigs(self, vmf: VMF, name: str, start_disabled: str) -> None: return # Disabled. - if not vbsp_options.get_itemconf(('VALVE_FIZZLER', 'FlinchBack'), False): + if not options.get_itemconf(('VALVE_FIZZLER', 'FlinchBack'), False): return # Make global entities if not present. if '_fizz_flinch_hurt' not in vmf.by_target: - glob_ent_loc = vbsp_options.get(Vec, 'global_ents_loc') + glob_ent_loc = options.get(Vec, 'global_ents_loc') vmf.create_ent( classname='point_hurt', targetname='_fizz_flinch_hurt', @@ -421,7 +422,7 @@ def gen_flinch_trigs(self, vmf: VMF, name: str, start_disabled: str) -> None: - 64 * self.up_axis ), p2=seg_max + 64 * self.up_axis, - mat=const.Tools.TRIGGER, + mat=consts.Tools.TRIGGER, ).solid) pos_brush.solids.append(vmf.make_prism( p1=seg_min - 64 * self.up_axis, @@ -429,7 +430,7 @@ def gen_flinch_trigs(self, vmf: VMF, name: str, start_disabled: str) -> None: + 4 * normal + 64 * self.up_axis ), - mat=const.Tools.TRIGGER, + mat=consts.Tools.TRIGGER, ).solid) def set_tiles_behind_models(self, origin: Vec, normal: Vec, to_nodraw: bool): @@ -535,9 +536,9 @@ def _gen_fizz_border(self, vmf: VMF, seg_min: Vec, seg_max: Vec): if not tiledefs_up and not tiledefs_dn: return - overlay_thickness = vbsp_options.get(int, 'fizz_border_thickness') - overlay_repeat = vbsp_options.get(int, 'fizz_border_repeat') - flip_uv = vbsp_options.get(bool, 'fizz_border_vertical') + overlay_thickness = options.get(int, 'fizz_border_thickness') + overlay_repeat = options.get(int, 'fizz_border_repeat') + flip_uv = options.get(bool, 'fizz_border_vertical') if flip_uv: u_rep = 1.0 @@ -697,7 +698,7 @@ def _side_color( """ if not self.side_color: # Just apply nodraw. - side.mat = const.Tools.NODRAW + side.mat = consts.Tools.NODRAW return # Produce a hex colour string, and use that as the material name. diff --git a/src/grid_optim.py b/src/precomp/grid_optim.py similarity index 99% rename from src/grid_optim.py rename to src/precomp/grid_optim.py index e965c4b34..b20993b6b 100644 --- a/src/grid_optim.py +++ b/src/precomp/grid_optim.py @@ -4,7 +4,6 @@ efficiently cover the True positions without the False ones. """ from typing import Tuple, Dict - from enum import Enum diff --git a/src/instanceLocs.py b/src/precomp/instanceLocs.py similarity index 100% rename from src/instanceLocs.py rename to src/precomp/instanceLocs.py diff --git a/src/instance_traits.py b/src/precomp/instance_traits.py similarity index 98% rename from src/instance_traits.py rename to src/precomp/instance_traits.py index 9b2ddba9c..21bd128e9 100644 --- a/src/instance_traits.py +++ b/src/precomp/instance_traits.py @@ -2,9 +2,9 @@ from srctools import Entity from srctools import VMF import srctools.logger -from comp_consts import ItemClass -from conditions import CLASS_FOR_ITEM -from instanceLocs import ITEM_FOR_FILE +from consts import ItemClass +from precomp.conditions import CLASS_FOR_ITEM +from precomp.instanceLocs import ITEM_FOR_FILE from typing import Optional, Callable, Dict, Set diff --git a/src/item_chain.py b/src/precomp/item_chain.py similarity index 97% rename from src/item_chain.py rename to src/precomp/item_chain.py index a6190513d..bd7147ea3 100644 --- a/src/item_chain.py +++ b/src/precomp/item_chain.py @@ -4,9 +4,9 @@ """ from typing import Any, Dict, Container, List, Optional, Iterator -import connections +from precomp import connections from srctools import Entity, VMF -from connections import Item +from precomp.connections import Item __all__ = ['Node', 'chain'] diff --git a/src/vbsp_options.py b/src/precomp/options.py similarity index 100% rename from src/vbsp_options.py rename to src/precomp/options.py diff --git a/src/packing.py b/src/precomp/packing.py similarity index 92% rename from src/packing.py rename to src/precomp/packing.py index d1284d1e7..49f829cc9 100644 --- a/src/packing.py +++ b/src/precomp/packing.py @@ -1,9 +1,8 @@ """Conditions related to packing.""" -from typing import Dict, Set, Iterable +from typing import Dict, Set -import conditions import srctools.logger -import vbsp_options +from precomp import options, conditions from srctools import VMF, Property, Vec @@ -55,7 +54,7 @@ def pack_files( ent = vmf.create_ent( classname='comp_pack', - origin=vbsp_options.get(Vec, 'global_ents_loc'), + origin=options.get(Vec, 'global_ents_loc'), ) for i, file in enumerate(packlist, start=1): diff --git a/src/template_brush.py b/src/precomp/template_brush.py similarity index 99% rename from src/template_brush.py rename to src/precomp/template_brush.py index 5ef9d27aa..85044dd71 100644 --- a/src/template_brush.py +++ b/src/precomp/template_brush.py @@ -7,16 +7,14 @@ from operator import attrgetter import srctools -import vbsp_options - from srctools import Entity, Solid, Side, Property, UVAxis, Vec, VMF from srctools.vmf import EntityFixup -from texturing import Portalable, GenCat, TileSize -from tiling import TileType -import comp_consts as consts import srctools.logger -import tiling -import texturing + +from .texturing import Portalable, GenCat, TileSize +from .tiling import TileType +from . import tiling, texturing, options +import consts from typing import ( Iterable, Union, Callable, @@ -1096,12 +1094,12 @@ def retexture_template( face.uaxis = UVAxis( 1, 0, 0, offset=0, - scale=vbsp_options.get(float, 'goo_scale'), + scale=options.get(float, 'goo_scale'), ) face.vaxis = UVAxis( 0, -1, 0, offset=0, - scale=vbsp_options.get(float, 'goo_scale'), + scale=options.get(float, 'goo_scale'), ) continue else: diff --git a/src/texturing.py b/src/precomp/texturing.py similarity index 99% rename from src/texturing.py rename to src/precomp/texturing.py index 00cea864b..424dd5f7c 100644 --- a/src/texturing.py +++ b/src/precomp/texturing.py @@ -10,7 +10,7 @@ from srctools import Property, Side, Solid, Vec from srctools.vmf import VisGroup -import comp_consts as consts +import consts from typing import ( TYPE_CHECKING, @@ -23,7 +23,7 @@ import utils if TYPE_CHECKING: - from tiling import TileDef + from precomp.tiling import TileDef LOGGER = srctools.logger.get_logger(__name__) diff --git a/src/tiling.py b/src/precomp/tiling.py similarity index 99% rename from src/tiling.py rename to src/precomp/tiling.py index 5e90f07be..b9198c4f4 100644 --- a/src/tiling.py +++ b/src/precomp/tiling.py @@ -21,21 +21,25 @@ ) import math +from weakref import WeakKeyDictionary -import instanceLocs -import utils -import vbsp_options from srctools import Vec, VMF, Entity, Side, Solid, Output import srctools.logger -from brushLoc import POS as BLOCK_POS, Block, grid_to_world -from texturing import TileSize, Portalable -from weakref import WeakKeyDictionary import srctools.vmf -import comp_consts as consts -import template_brush -import texturing -import antlines -import grid_optim +from precomp.brushLoc import POS as BLOCK_POS, Block, grid_to_world +from precomp.texturing import TileSize, Portalable +from . import ( + grid_optim, + instanceLocs, + texturing, + options, + antlines, + template_brush, + conditions, +) +import utils +import consts + LOGGER = srctools.logger.get_logger(__name__) @@ -499,8 +503,8 @@ def export( inst_normal = Vec(z=1).rotate(*angles) if inst_normal != tile.normal: # It's not aligned to ourselves, so dump the rotation. - import conditions - angles = Vec.from_str(conditions.PETI_INST_ANGLE[tile.normal.as_tuple()]) + angles = Vec.from_str( + conditions.PETI_INST_ANGLE[tile.normal.as_tuple()]) # Points towards the open end on angled panels. front_normal = Vec(x=1).rotate(*angles) # Point along the hinge axis on angled panels. @@ -1576,7 +1580,8 @@ def gen_tile_temp() -> None: } try: - template = template_brush.get_template(vbsp_options.get(str, '_tiling_template_')) + template = template_brush.get_template( + options.get(str, '_tiling_template_')) # Grab the single world brush for each visgroup. for (key, name) in cat_names.items(): world, detail, over = template.visgrouped(name) @@ -1618,7 +1623,8 @@ def gen_tile_temp() -> None: temp_part[int(u_dir), int(v_dir), thickness, bevel] = face -def analyse_map(vmf_file: VMF, side_to_ant_seg: Dict[int, List[antlines.Segment]]): +def analyse_map(vmf_file: VMF, side_to_ant_seg: Dict[int, List[ + antlines.Segment]]): """Create TileDefs from all the brush sides. Once done, all wall brushes have been removed from the map. @@ -1678,8 +1684,7 @@ def analyse_map(vmf_file: VMF, side_to_ant_seg: Dict[int, List[antlines.Segment] tile.add_portal_helper() inst.remove() - dynamic_pan_parent = vbsp_options.get(str, "dynamic_pan_parent") - import conditions + dynamic_pan_parent = options.get(str, "dynamic_pan_parent") # Find Angled Panel brushes. for brush_ent in vmf_file.by_class['func_brush']: @@ -2173,7 +2178,7 @@ def generate_goo(vmf: VMF) -> None: damagetype=(1 << 18), # Radiation ) - goo_scale = vbsp_options.get(float, 'goo_scale') + goo_scale = options.get(float, 'goo_scale') # Find key with the highest value - that gives the largest z-level. [best_goo, _] = max(goo_heights.items(), key=lambda x: x[1]) diff --git a/src/voiceLine.py b/src/precomp/voice_line.py similarity index 99% rename from src/voiceLine.py rename to src/precomp/voice_line.py index 052073535..54fedc386 100644 --- a/src/voiceLine.py +++ b/src/precomp/voice_line.py @@ -5,11 +5,9 @@ from decimal import Decimal from typing import List, Set -import conditions.monitor -import packing import srctools.logger import vbsp -import vbsp_options +from precomp import options as vbsp_options, packing, conditions from BEE2_config import ConfigFile from srctools import Property, Vec, VMF, Output, Entity @@ -434,6 +432,7 @@ def add_voice( use_priority=True, ): """Add a voice line to the map.""" + from precomp.conditions.monitor import make_voice_studio global ALLOW_MID_VOICES, vmf_file, map_attr, style_vars LOGGER.info('Adding Voice Lines!') @@ -458,7 +457,7 @@ def add_voice( ) # Either box in with nodraw, or place the voiceline studio. - has_studio = conditions.monitor.make_voice_studio(vmf_file) + has_studio = make_voice_studio(vmf_file) bullsye_actor = vbsp_options.get(str, 'voice_studio_actor') if bullsye_actor and has_studio: diff --git a/src/vbsp.py b/src/vbsp.py index 2408eb7d2..a3c4f36e2 100644 --- a/src/vbsp.py +++ b/src/vbsp.py @@ -18,24 +18,23 @@ import srctools.vmf as VLib import srctools.run import srctools.logger -import antlines -import voiceLine -import vbsp_options -import instanceLocs -import brushLoc -import bottomlessPit -import packing -import conditions -import tiling -import texturing -import connections -import instance_traits -import template_brush -import fizzler -import faithplate -import comp_consts as consts -import cubes -import barriers +from precomp import ( + instance_traits, tiling, brushLoc, bottomlessPit, + instanceLocs, + cubes, + texturing, + barriers, + connections, + options, + faithplate, + antlines, + packing, + template_brush, + conditions, + fizzler, + voice_line, +) +import consts from typing import Any, Dict, Tuple, List, Set @@ -124,11 +123,11 @@ def load_settings() -> Tuple[antlines.AntType, antlines.AntType]: ant_floor = ant_wall # Load in our main configs.. - vbsp_options.load(conf.find_all('Options')) + options.load(conf.find_all('Options')) # The voice line property block for quote_block in conf.find_all("quotes"): - voiceLine.QUOTE_DATA += quote_block.value + voice_line.QUOTE_DATA += quote_block.value # Configuration properties for styles. for stylevar_block in conf.find_all('stylevars'): @@ -169,7 +168,7 @@ def load_settings() -> Tuple[antlines.AntType, antlines.AntType]: fizzler.read_configs(conf) # Signage items - from conditions.signage import load_signs + from precomp.conditions.signage import load_signs load_signs(conf) # Get configuration for the elevator, defaulting to ''. @@ -233,7 +232,7 @@ def load_map(map_path): @conditions.meta_cond(priority=100) def add_voice(): """Add voice lines to the map.""" - voiceLine.add_voice( + voice_line.add_voice( has_items=settings['has_attr'], style_vars_=settings['style_vars'], vmf_file_=VMF, @@ -348,7 +347,7 @@ def set_player_model(): if GAME_MODE == 'COOP': # Not in coop.. return - loc = vbsp_options.get(Vec, 'global_ents_loc') + loc = options.get(Vec, 'global_ents_loc') chosen_model = BEE2_config.get_val('General', 'player_model', 'PETI').casefold() if chosen_model == 'peti': @@ -389,7 +388,7 @@ def set_player_model(): delay=0.1, )) - if pgun_skin and vbsp_options.get(str, 'game_id') == utils.STEAM_IDS['PORTAL2']: + if pgun_skin and options.get(str, 'game_id') == utils.STEAM_IDS['PORTAL2']: # Only change portalgun skins in Portal 2 - this is the vanilla # portalgun weapon/viewmodel. auto.add_out(VLib.Output( @@ -431,7 +430,7 @@ def set_player_portalgun() -> None: `NeedsPortalMan` still works to add this in Coop. """ - if vbsp_options.get(str, 'game_id') == utils.STEAM_IDS['TAG']: + if options.get(str, 'game_id') == utils.STEAM_IDS['TAG']: return # Aperture Tag doesn't have Portal Guns! LOGGER.info('Setting Portalgun:') @@ -462,7 +461,7 @@ def set_player_portalgun() -> None: has['spawn_single'] = False has['spawn_nogun'] = True - ent_pos = vbsp_options.get(Vec, 'global_pti_ents_loc') + ent_pos = options.get(Vec, 'global_pti_ents_loc') logic_auto = VMF.create_ent('logic_auto', origin=ent_pos, flags='1') @@ -599,8 +598,8 @@ def set_player_portalgun() -> None: )) # Shuts down various parts when you've reached the exit. - import conditions.instances - conditions.instances.global_input(VMF, ent_pos, VLib.Output( + import precomp.conditions.instances + precomp.conditions.instances.global_input(VMF, ent_pos, VLib.Output( 'OnTrigger', '@portalgun', 'RunScriptCode', @@ -634,7 +633,7 @@ def add_screenshot_logic() -> None: VMF.create_ent( classname='func_instance', file='instances/bee2/logic/screenshot_logic.vmf', - origin=vbsp_options.get(Vec, 'global_ents_loc'), + origin=options.get(Vec, 'global_ents_loc'), angles='0 0 0', ) LOGGER.info('Added Screenshot Logic') @@ -643,7 +642,7 @@ def add_screenshot_logic() -> None: @conditions.meta_cond(priority=100, only_once=True) def add_fog_ents(): """Add the tonemap and fog controllers, based on the skybox.""" - pos = vbsp_options.get(Vec, 'global_ents_loc') + pos = options.get(Vec, 'global_ents_loc') VMF.create_ent( classname='env_tonemap_controller', targetname='@tonemapper', @@ -1298,10 +1297,10 @@ def change_brush() -> None: """Alter all world/detail brush textures to use the configured ones.""" LOGGER.info("Editing Brushes...") - goo_scale = vbsp_options.get(float, 'goo_scale') + goo_scale = options.get(float, 'goo_scale') # Goo mist must be enabled by both the style and the user. - make_goo_mist = vbsp_options.get(bool, 'goo_mist') and srctools.conv_bool( + make_goo_mist = options.get(bool, 'goo_mist') and srctools.conv_bool( settings['style_vars'].get('AllowGooMist', '1') ) mist_solids = set() @@ -1435,13 +1434,13 @@ def change_overlays() -> None: LOGGER.info("Editing Overlays...") # A frame instance to add around all the 32x32 signs - sign_inst = vbsp_options.get(str, 'signInst') + sign_inst = options.get(str, 'signInst') # Resize the signs to this size. 4 vertexes are saved relative # to the origin, so we must divide by 2. - sign_size = vbsp_options.get(int, 'signSize') / 2 + sign_size = options.get(int, 'signSize') / 2 # A packlist associated with the sign_inst. - sign_inst_pack = vbsp_options.get(str, 'signPack') + sign_inst_pack = options.get(str, 'signPack') # Grab all the textures we're using... for over in VMF.by_class['info_overlay']: @@ -1452,7 +1451,7 @@ def change_overlays() -> None: if (over['targetname'] == 'exitdoor_stickman' or over['targetname'] == 'exitdoor_arrow'): - if vbsp_options.get(bool, "remove_exit_signs"): + if options.get(bool, "remove_exit_signs"): # Some styles have instance-based ones, remove the # originals if needed to ensure it looks nice. VMF.remove_ent(over) @@ -1501,12 +1500,12 @@ def add_extra_ents(game_mode: str) -> None: """Add the various extra instances to the map.""" LOGGER.info("Adding Music...") - loc = vbsp_options.get(Vec, 'global_ents_loc') + loc = options.get(Vec, 'global_ents_loc') # These values are exported by the BEE2 app, indicating the # options on the music item. - inst = vbsp_options.get(str, 'music_instance') - snd_length = vbsp_options.get(int, 'music_looplen') + inst = options.get(str, 'music_instance') + snd_length = options.get(int, 'music_looplen') # Don't add our logic if an instance was provided. # If this settings is set, we have a music config. @@ -1614,9 +1613,9 @@ def add_extra_ents(game_mode: str) -> None: # Add the global_pti_ents instance automatically, with disable_pti_audio # set. - global_ents_pos = vbsp_options.get(Vec, 'global_ents_loc') - pti_file = vbsp_options.get(str, 'global_pti_ents') - pti_loc = vbsp_options.get(Vec, 'global_pti_ents_loc') + global_ents_pos = options.get(Vec, 'global_ents_loc') + pti_file = options.get(str, 'global_pti_ents') + pti_loc = options.get(Vec, 'global_pti_ents_loc') # Add a nodraw box around the global entity location, to seal it. VMF.add_brushes(VMF.make_hollow( @@ -1674,7 +1673,7 @@ def add_extra_ents(game_mode: str) -> None: def change_ents() -> None: """Edit misc entities.""" LOGGER.info("Editing Other Entities...") - if vbsp_options.get(bool, "remove_info_lighting"): + if options.get(bool, "remove_info_lighting"): # Styles with brush-based glass edges don't need the info_lighting, # delete it to save ents. for ent in VMF.by_class['info_lighting']: @@ -1696,9 +1695,9 @@ def fix_worldspawn() -> None: # If the game is Aperture Tag, it's always forced on VMF.spawn['paintinmap'] = srctools.bool_as_int( settings['has_attr']['gel'] or - vbsp_options.get(str, 'game_id') == utils.STEAM_IDS['APTAG'] + options.get(str, 'game_id') == utils.STEAM_IDS['APTAG'] ) - VMF.spawn['skyname'] = vbsp_options.get(str, 'skybox') + VMF.spawn['skyname'] = options.get(str, 'skybox') def make_vrad_config(is_peti: bool) -> None: @@ -1724,7 +1723,7 @@ def make_vrad_config(is_peti: bool) -> None: conf['is_preview'] = srctools.bool_as_int( IS_PREVIEW ) - conf['game_id'] = vbsp_options.get(str, 'game_id') + conf['game_id'] = options.get(str, 'game_id') if BEE2_config.get_bool('General', 'packfile_dump_enable'): conf['packfile_dump'] = BEE2_config.get_val( @@ -1747,8 +1746,7 @@ def make_vrad_config(is_peti: bool) -> None: # block when written. conf['MusicScript'] = settings['music_conf'] - import cubes - import conditions.piston_platform + import precomp.conditions.piston_platform # This generates scripts and might need to tell VRAD. cubes.write_vscripts(conf) @@ -1951,7 +1949,7 @@ def main() -> None: # Special override - generate docs for the BEE2 wiki. LOGGER.info('Writing Wiki text...') with open(os.environ['BEE2_WIKI_OPT_LOC'], 'w') as f: - vbsp_options.dump_info(f) + options.dump_info(f) with open(os.environ['BEE2_WIKI_COND_LOC'], 'a+') as f: conditions.dump_conditions(f) LOGGER.info('Done. Exiting now!') From 1850b00e0c99c29cbd777ee81b7c6c98b0c92137 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Mon, 20 Jul 2020 10:24:11 +1000 Subject: [PATCH 03/87] Move TK_ROOT to the package __init__ This means it's going to be the first code run in the package. --- src/BEE2_launch.pyw | 7 ++- src/app/BEE2.py | 3 +- src/app/CheckDetails.py | 21 ++++---- src/app/CompilerPane.py | 4 +- src/app/StyleVarPane.py | 3 +- src/app/UI.py | 3 +- src/app/__init__.py | 111 +++++++++++++++++++++++++++++++++++++++ src/app/backup.py | 3 +- src/app/contextWin.py | 2 +- src/app/dragdrop.py | 3 +- src/app/gameMan.py | 3 +- src/app/helpMenu.py | 5 +- src/app/img.py | 1 - src/app/itemPropWin.py | 3 +- src/app/logWindow.py | 3 +- src/app/music_conf.py | 2 +- src/app/optionWindow.py | 3 +- src/app/packageMan.py | 2 +- src/app/selector_win.py | 4 +- src/app/signage_ui.py | 4 +- src/app/sound.py | 2 +- src/app/tagsPane.py | 3 +- src/app/tk_tools.py | 107 ++----------------------------------- src/app/tooltip.py | 3 +- src/app/voiceEditor.py | 3 +- src/loadScreen_daemon.py | 17 +++--- 26 files changed, 158 insertions(+), 167 deletions(-) diff --git a/src/BEE2_launch.pyw b/src/BEE2_launch.pyw index 37b7bbd13..69492e6a4 100644 --- a/src/BEE2_launch.pyw +++ b/src/BEE2_launch.pyw @@ -5,7 +5,6 @@ import sys # We need to add dummy files if these are None - MultiProccessing tries to flush # them. - if sys.stdout is None: sys.stdout = open(os.devnull, 'w') if sys.stderr is None: @@ -23,7 +22,7 @@ freeze_support() if __name__ == '__main__': import srctools.logger - from app import tk_tools + from app import on_error, TK_ROOT import utils if len(sys.argv) > 1: @@ -39,7 +38,7 @@ if __name__ == '__main__': LOGGER = srctools.logger.init_logging( str(utils.install_path(f'logs/{log_name}.log')), __name__, - on_error=tk_tools.on_error, + on_error=on_error, ) utils.setup_localisations(LOGGER) @@ -58,5 +57,5 @@ if __name__ == '__main__': raise ValueError(f'Invalid component name "{app_name}"!') # Run the TK loop forever. - tk_tools.TK_ROOT.mainloop() + TK_ROOT.mainloop() diff --git a/src/app/BEE2.py b/src/app/BEE2.py index 7038bd1e8..c9e452d2e 100644 --- a/src/app/BEE2.py +++ b/src/app/BEE2.py @@ -2,8 +2,7 @@ # BEE2_config creates this config file to allow easy cross-module access from BEE2_config import GEN_OPTS -from app import gameMan, paletteLoader, UI, music_conf, logWindow, img -from app.tk_tools import TK_ROOT +from app import gameMan, paletteLoader, UI, music_conf, logWindow, img, TK_ROOT import loadScreen import packageLoader import utils diff --git a/src/app/CheckDetails.py b/src/app/CheckDetails.py index d1411b498..17fdc6824 100644 --- a/src/app/CheckDetails.py +++ b/src/app/CheckDetails.py @@ -12,10 +12,9 @@ import functools from app.tooltip import add_tooltip, set_tooltip -from app import tk_tools import utils -from typing import List, Iterator +from typing import List, Iterator, Optional UP_ARROW = '\u25B3' @@ -73,8 +72,8 @@ def __init__( """ self.values = values self.state_var = tk.IntVar(value=bool(state)) - self.master = None # type: CheckDetails - self.check = None # type: ttk.Checkbutton + self.master = None # type: Optional[CheckDetails] + self.check = None # type: Optional[ttk.Checkbutton] self.locked = lock_check self.hover_text = hover_text self.val_widgets = [] @@ -502,9 +501,9 @@ def unchecked(self) -> Iterator[Item]: if __name__ == '__main__': - root = tk_tools.TK_ROOT + from app import TK_ROOT test_inst = CheckDetails( - parent=root, + parent=TK_ROOT, headers=['Name', 'Author', 'Description'], items=[ Item('Item1', 'Auth1', 'Blah blah blah'), @@ -516,9 +515,9 @@ def unchecked(self) -> Iterator[Item]: ] ) test_inst.grid(sticky='NSEW') - utils.add_mousewheel(test_inst.wid_canvas, root) + utils.add_mousewheel(test_inst.wid_canvas, TK_ROOT) - root.columnconfigure(0, weight=1) - root.rowconfigure(0, weight=1) - root.deiconify() - root.mainloop() \ No newline at end of file + TK_ROOT.columnconfigure(0, weight=1) + TK_ROOT.rowconfigure(0, weight=1) + TK_ROOT.deiconify() + TK_ROOT.mainloop() \ No newline at end of file diff --git a/src/app/CompilerPane.py b/src/app/CompilerPane.py index b4088c9df..adac7745b 100644 --- a/src/app/CompilerPane.py +++ b/src/app/CompilerPane.py @@ -6,14 +6,14 @@ from PIL import Image, ImageTk -from app import selector_win +from app import selector_win, TK_ROOT from app import tkMarkdown, SubPane, img import utils from BEE2_config import ConfigFile, option_handler from packageLoader import CORRIDOR_COUNTS, CorrDesc from srctools import Property, AtomicWriter from srctools.logger import get_logger -from app.tk_tools import TK_ROOT, FileField +from app.tk_tools import FileField from typing import Dict, Tuple, Optional diff --git a/src/app/StyleVarPane.py b/src/app/StyleVarPane.py index 2e885c3f1..5dd205635 100644 --- a/src/app/StyleVarPane.py +++ b/src/app/StyleVarPane.py @@ -1,5 +1,4 @@ from tkinter import * -from app.tk_tools import TK_ROOT from tkinter import ttk from collections import namedtuple @@ -9,7 +8,7 @@ from srctools import Property from srctools.logger import get_logger import packageLoader -from app import tooltip +from app import tooltip, TK_ROOT import utils from app import itemconfig, img import BEE2_config diff --git a/src/app/UI.py b/src/app/UI.py index b97e60fae..9d3d93a0e 100644 --- a/src/app/UI.py +++ b/src/app/UI.py @@ -7,8 +7,7 @@ import random from srctools import Property -from app import music_conf -from app.tk_tools import TK_ROOT +from app import music_conf, TK_ROOT from app.itemPropWin import PROP_TYPES from BEE2_config import ConfigFile, GEN_OPTS from app.selector_win import selWin, Item as selWinItem, AttrDef as SelAttr diff --git a/src/app/__init__.py b/src/app/__init__.py index e69de29bb..22e0b7f43 100644 --- a/src/app/__init__.py +++ b/src/app/__init__.py @@ -0,0 +1,111 @@ +"""The package containg all UI code.""" +import tkinter as tk +from types import TracebackType + +# We must always have one Tk object, and it needs to be constructed +# before most of TKinter will function. So doing it here does it first. +from typing import Type + + +TK_ROOT = tk.Tk() +TK_ROOT.withdraw() # Hide the window until everything is loaded. + + +def _run_main_loop(*args, **kwargs) -> None: + """Allow determining if this is running.""" + global _main_loop_running + _main_loop_running = True + _orig_mainloop(*args, **kwargs) + + +_main_loop_running = False +_orig_mainloop = TK_ROOT.mainloop +TK_ROOT.mainloop = _run_main_loop +del _run_main_loop + + +# noinspection PyBroadException +def tk_error( + exc_type: Type[BaseException], + exc_value: BaseException, + exc_tb: TracebackType, +) -> None: + """Log TK errors.""" + # The exception is caught inside the TK code. + # We don't care about that, so try and move the traceback up + # one level. + import sys + import logging + if exc_tb.tb_next: + exc_tb = exc_tb.tb_next + + try: + on_error(exc_type, exc_value, exc_tb) + except: + pass + + logger = logging.getLogger('BEE2') + logger.error( + msg='Uncaught Exception:', + exc_info=(exc_type, exc_value, exc_tb), + ) + logging.shutdown() + + # Since this isn't caught normally, it won't quit the application. + # Quit ourselves manually. to prevent TK just freezing. + TK_ROOT.quit() + sys.exit() + +TK_ROOT.report_callback_exception = tk_error + + +# noinspection PyBroadException +def on_error( + exc_type: Type[BaseException], + exc_value: BaseException, + exc_tb: TracebackType, +) -> None: + """Run when the application crashes. Display to the user, log it, and quit.""" + # We don't want this to fail, so import everything here, and wrap in + # except Exception. + import traceback + + err = ''.join(traceback.format_exception(exc_type, exc_value, exc_tb)) + + # Grab and release the grab so nothing else can block the error message. + try: + TK_ROOT.grab_set_global() + TK_ROOT.grab_release() + + # Append traceback to the clipboard. + TK_ROOT.clipboard_append(err) + except Exception: + pass + + if not issubclass(exc_type, Exception): + # It's subclassing BaseException (KeyboardInterrupt, SystemExit), + # so ignore the error. + return + + # Put it onscreen. + try: + from tkinter import messagebox + messagebox.showinfo( + title='BEE2 Error!', + message='An error occurred: \n{}\n\nThis has ' + 'been copied to the clipboard.'.format(err), + icon=messagebox.ERROR, + ) + except Exception: + pass + + try: + from BEE2_config import GEN_OPTS + # Try to turn on the logging window for next time.. + GEN_OPTS.load() + GEN_OPTS['Debug']['show_log_win'] = '1' + GEN_OPTS['Debug']['window_log_level'] = 'DEBUG' + GEN_OPTS.save() + except Exception: + # Ignore failures... + pass diff --git a/src/app/backup.py b/src/app/backup.py index e3ae8299e..5af60c9a4 100644 --- a/src/app/backup.py +++ b/src/app/backup.py @@ -13,13 +13,12 @@ import loadScreen import srctools.logger -from app import tk_tools, img +from app import tk_tools, img, TK_ROOT import tkinter as tk import utils from app.CheckDetails import CheckDetails, Item as CheckItem from FakeZip import FakeZip, zip_names, zip_open_bin from srctools import Property, KeyValError -from app.tk_tools import TK_ROOT from tkinter import filedialog from tkinter import messagebox from tkinter import ttk diff --git a/src/app/contextWin.py b/src/app/contextWin.py index ff422dfcf..272154a50 100644 --- a/src/app/contextWin.py +++ b/src/app/contextWin.py @@ -10,7 +10,6 @@ from tkinter import * from srctools import Property -from app.tk_tools import TK_ROOT from tkinter import ttk from tkinter import messagebox @@ -25,6 +24,7 @@ sound, img, UI, + TK_ROOT, ) import utils import packageLoader diff --git a/src/app/dragdrop.py b/src/app/dragdrop.py index 993916deb..bc1bcc188 100644 --- a/src/app/dragdrop.py +++ b/src/app/dragdrop.py @@ -3,7 +3,7 @@ import tkinter import utils -from app import sound, img +from app import sound, img, TK_ROOT from enum import Enum from tkinter import ttk, messagebox from srctools.logger import get_logger @@ -554,7 +554,6 @@ def _evt_configure(self, event: tkinter.Event) -> None: def _test() -> None: """Test the GUI.""" from srctools.logger import init_logging - from app.tk_tools import TK_ROOT from BEE2_config import GEN_OPTS from packageLoader import find_packages, PACKAGE_SYS diff --git a/src/app/gameMan.py b/src/app/gameMan.py index fa2d085c5..a4998c6be 100644 --- a/src/app/gameMan.py +++ b/src/app/gameMan.py @@ -10,7 +10,6 @@ from tkinter import * # ui library from tkinter import filedialog # open/save as dialog creator from tkinter import messagebox # simple, standard modal dialogs -from app.tk_tools import TK_ROOT import os import shutil @@ -26,7 +25,7 @@ FileSystem, FileSystemChain, ) import srctools.logger -from app import backup, tk_tools +from app import backup, tk_tools, TK_ROOT import loadScreen import packageLoader import utils diff --git a/src/app/helpMenu.py b/src/app/helpMenu.py index 789c8cbe8..79baa3b24 100644 --- a/src/app/helpMenu.py +++ b/src/app/helpMenu.py @@ -8,8 +8,7 @@ import functools from app.richTextBox import tkRichText -from app.tk_tools import TK_ROOT, HidingScroll -from app import tkMarkdown, tk_tools, sound, img +from app import tkMarkdown, tk_tools, sound, img, TK_ROOT import utils # For version info @@ -226,7 +225,7 @@ def __init__(self, title: str, text: str): frame.grid_columnconfigure(0, weight=1) frame.grid_rowconfigure(0, weight=1) - scrollbox = HidingScroll( + scrollbox = tk_tools.HidingScroll( frame, orient='vertical', command=self.textbox.yview, diff --git a/src/app/img.py b/src/app/img.py index b4c1000b6..aba76359f 100644 --- a/src/app/img.py +++ b/src/app/img.py @@ -12,7 +12,6 @@ import srctools.logger import logging import utils -from app.tk_tools import TK_ROOT # Make sure this is initialised! from typing import Iterable, Union, Dict, Tuple diff --git a/src/app/itemPropWin.py b/src/app/itemPropWin.py index e1b82787c..217629e32 100644 --- a/src/app/itemPropWin.py +++ b/src/app/itemPropWin.py @@ -1,6 +1,5 @@ from tkinter import * # ui library -from app.tk_tools import TK_ROOT from tkinter import ttk # themed ui components that match the OS from functools import partial as func_partial from enum import Enum @@ -8,7 +7,7 @@ import utils import srctools -from app import contextWin, gameMan, tk_tools, sound +from app import contextWin, gameMan, tk_tools, sound, TK_ROOT import srctools.logger from typing import Dict, List, Union, Any diff --git a/src/app/logWindow.py b/src/app/logWindow.py index b23e808e9..f7f94fdda 100644 --- a/src/app/logWindow.py +++ b/src/app/logWindow.py @@ -6,9 +6,8 @@ import logging import srctools.logger -from app.tk_tools import TK_ROOT from BEE2_config import GEN_OPTS -from app import tk_tools +from app import tk_tools, TK_ROOT import utils # Colours to use for each log level diff --git a/src/app/music_conf.py b/src/app/music_conf.py index 7c90ede9c..f64461d3e 100644 --- a/src/app/music_conf.py +++ b/src/app/music_conf.py @@ -8,7 +8,7 @@ from tkinter import ttk from app.selector_win import Item as SelItem, selWin as SelectorWin, AttrDef as SelAttr from srctools import FileSystemChain, FileSystem -from app.tk_tools import TK_ROOT +from app import TK_ROOT import tkinter import srctools.logger diff --git a/src/app/optionWindow.py b/src/app/optionWindow.py index 8bf9bb63c..03e2ec044 100644 --- a/src/app/optionWindow.py +++ b/src/app/optionWindow.py @@ -7,7 +7,6 @@ from tkinter import messagebox from typing import Callable, List, Tuple, Dict -from app.tk_tools import TK_ROOT from enum import Enum from BEE2_config import GEN_OPTS @@ -15,7 +14,7 @@ import utils import srctools.logger -from app import contextWin, gameMan, tk_tools, sound, logWindow +from app import contextWin, gameMan, tk_tools, sound, logWindow, TK_ROOT import loadScreen diff --git a/src/app/packageMan.py b/src/app/packageMan.py index 07f2a53bf..57708e592 100644 --- a/src/app/packageMan.py +++ b/src/app/packageMan.py @@ -4,7 +4,7 @@ from tkinter import ttk from tkinter import messagebox import tkinter as tk -from app.tk_tools import TK_ROOT +from app import TK_ROOT from app.CheckDetails import CheckDetails, Item as CheckItem from BEE2_config import ConfigFile diff --git a/src/app/selector_win.py b/src/app/selector_win.py index 38ff6c2a1..4b929d4b8 100644 --- a/src/app/selector_win.py +++ b/src/app/selector_win.py @@ -8,8 +8,6 @@ from tkinter import font as tk_font from tkinter import ttk # themed ui components that match the OS -from app.tk_tools import TK_ROOT - from collections import namedtuple, defaultdict from operator import itemgetter from enum import Enum @@ -21,7 +19,7 @@ from srctools import Vec, EmptyMapping import srctools.logger from srctools.filesys import FileSystemChain -from app import tkMarkdown, tk_tools, sound, img +from app import tkMarkdown, tk_tools, sound, img, TK_ROOT import utils diff --git a/src/app/signage_ui.py b/src/app/signage_ui.py index d067d580a..45643a1c7 100644 --- a/src/app/signage_ui.py +++ b/src/app/signage_ui.py @@ -1,7 +1,7 @@ """Configures which signs are defined for the Signage item.""" from typing import Optional, Tuple, List, Dict, overload -from app import dragdrop, img +from app import dragdrop, img, TK_ROOT import srctools.logger import utils import BEE2_config @@ -9,7 +9,7 @@ import tkinter as tk from srctools import Property from tkinter import ttk -from app.tk_tools import TK_ROOT, HidingScroll +from app.tk_tools import HidingScroll LOGGER = srctools.logger.get_logger(__name__) diff --git a/src/app/sound.py b/src/app/sound.py index e4b465496..45fb388b1 100644 --- a/src/app/sound.py +++ b/src/app/sound.py @@ -10,7 +10,7 @@ import utils -from app.tk_tools import TK_ROOT +from app import TK_ROOT from srctools.filesys import FileSystemChain, FileSystem, RawFileSystem import srctools.logger diff --git a/src/app/tagsPane.py b/src/app/tagsPane.py index 34fba83c4..7318241a5 100644 --- a/src/app/tagsPane.py +++ b/src/app/tagsPane.py @@ -1,6 +1,5 @@ from tkinter import ttk from tkinter import font -from app.tk_tools import TK_ROOT import tkinter as tk from functools import partial @@ -9,7 +8,7 @@ from enum import Enum import string -from app import optionWindow, StyleVarPane, UI, tk_tools, sound +from app import optionWindow, StyleVarPane, UI, tk_tools, sound, TK_ROOT import utils from typing import Dict, List diff --git a/src/app/tk_tools.py b/src/app/tk_tools.py index 49d723c34..7d23249c6 100644 --- a/src/app/tk_tools.py +++ b/src/app/tk_tools.py @@ -8,9 +8,10 @@ from tkinter import font as _tk_font from tkinter import filedialog, commondialog, simpledialog import tkinter as tk - import os.path +from app import TK_ROOT + try: # Python 3.6+ # noinspection PyCompatibility @@ -25,22 +26,6 @@ import utils -# Put this in a module so it's a singleton, and we can always import the same -# object. -TK_ROOT = tk.Tk() - - -def _run_main_loop(*args, **kwargs) -> None: - """Allow determining if this is running.""" - global _main_loop_running - _main_loop_running = True - _orig_mainloop(*args, **kwargs) - - -_main_loop_running = False -_orig_mainloop = TK_ROOT.mainloop -TK_ROOT.mainloop = _run_main_loop -del _run_main_loop # Set icons for the application. @@ -96,91 +81,6 @@ def set_window_icon(window: Union[tk.Toplevel, tk.Tk]): LISTBOX_BG_SEL_COLOR = 'blue' LISTBOX_BG_COLOR = 'white' -TK_ROOT.withdraw() # Hide the window until everything is loaded. - - -# noinspection PyBroadException -def on_error(exc_type, exc_value, exc_tb): - """Run when the application crashes. Display to the user, log it, and quit.""" - # We don't want this to fail, so import everything here, and wrap in - # except Exception. - import traceback - - err = ''.join(traceback.format_exception(exc_type, exc_value, exc_tb)) - - # Grab and release the grab so nothing else can block the error message. - try: - TK_ROOT.grab_set_global() - TK_ROOT.grab_release() - - # Append traceback to the clipboard. - TK_ROOT.clipboard_append(err) - except Exception: - pass - - if not issubclass(exc_type, Exception): - # It's subclassing BaseException (KeyboardInterrupt, SystemExit), - # so ignore the error. - return - - # Put it onscreen. - try: - from tkinter import messagebox - messagebox.showinfo( - title='BEE2 Error!', - message='An error occurred: \n{}\n\nThis has ' - 'been copied to the clipboard.'.format(err), - icon=messagebox.ERROR, - ) - except Exception: - pass - - try: - from BEE2_config import GEN_OPTS - # Try to turn on the logging window for next time.. - GEN_OPTS.load() - GEN_OPTS['Debug']['show_log_win'] = '1' - GEN_OPTS['Debug']['window_log_level'] = 'DEBUG' - GEN_OPTS.save() - except Exception: - # Ignore failures... - pass - - -def hook_tk_errors(): - """TKinter catches and swallows callback errors. - - We need to hook into that to log those seperately. - """ - - def tk_error(exc_type, exc_value, exc_tb): - """Log TK errors.""" - # The exception is caught inside the TK code. - # We don't care about that, so try and move the traceback up - # one level. - import sys - import logging - if exc_tb.tb_next: - exc_tb = exc_tb.tb_next - - on_error(exc_type, exc_value, exc_tb) - - logger = logging.getLogger('BEE2') - logger.error( - msg='Uncaught Exception:', - exc_info=(exc_type, exc_value, exc_tb), - ) - logging.shutdown() - - # Since this isn't caught normally, it won't quit the application. - # Quit ourselves manually. to prevent TK just freezing. - TK_ROOT.quit() - sys.exit() - - TK_ROOT.report_callback_exception = tk_error # type: ignore - -hook_tk_errors() # Always do this. - def event_cancel(*args, **kwargs): """Bind to an event to cancel it, and prevent it from propagating.""" @@ -201,10 +101,11 @@ def body(self, master): def prompt( title: str, message: str, initialvalue: str='', - parent: tk.Misc=TK_ROOT, + parent: tk.Misc= TK_ROOT, ) -> Optional[str]: """Ask the user to enter a string.""" from loadScreen import suppress_screens + from app import _main_loop_running with suppress_screens(): # If the main loop isn't running, this doesn't work correctly. # Probably also if it's not visible. So swap back to the old style. diff --git a/src/app/tooltip.py b/src/app/tooltip.py index 8d58d4f18..569503f4f 100644 --- a/src/app/tooltip.py +++ b/src/app/tooltip.py @@ -4,7 +4,8 @@ Call add_tooltip with a widget to add all the events automatically. """ import tkinter as tk -from app.tk_tools import TK_ROOT +from app import TK_ROOT + PADDING = 0 # Space around the target widget CENT_DIST = 50 # Distance around center where we align centered. diff --git a/src/app/voiceEditor.py b/src/app/voiceEditor.py index 36a9307f5..5e8545df2 100644 --- a/src/app/voiceEditor.py +++ b/src/app/voiceEditor.py @@ -9,14 +9,13 @@ from tkinter import font from tkinter import ttk -from app import img +from app import img, TK_ROOT import srctools.logger from app import tk_tools import utils from BEE2_config import ConfigFile from app.tooltip import add_tooltip from srctools import Property -from app.tk_tools import TK_ROOT LOGGER = srctools.logger.get_logger(__name__) diff --git a/src/loadScreen_daemon.py b/src/loadScreen_daemon.py index ac78eebc3..fedb4db8e 100644 --- a/src/loadScreen_daemon.py +++ b/src/loadScreen_daemon.py @@ -8,6 +8,7 @@ from tkinter import ttk from tkinter.font import Font +from app import img, TK_ROOT import tkinter as tk import multiprocessing.connection @@ -37,7 +38,6 @@ class BaseLoadScreen: """Code common to both loading screen types.""" def __init__( self, - master: tk.Tk, scr_id: int, title_text: str, force_ontop: bool, @@ -46,7 +46,7 @@ def __init__( self.scr_id = scr_id self.title_text = title_text - self.win = tk.Toplevel(master) + self.win = tk.Toplevel(TK_ROOT) self.win.withdraw() self.win.wm_overrideredirect(True) self.win.attributes('-topmost', int(force_ontop)) @@ -271,9 +271,6 @@ def __init__(self, *args): size=-12, # negative = in pixels ) - # Must be done late, so we know TK is initialised. - from app import img - logo_img = img.png('BEE2/splash_logo') self.lrg_canvas = tk.Canvas(self.win) @@ -583,8 +580,6 @@ def run_screen( PIPE_REC = pipe_rec TRANSLATION.update(translations) - root = tk.Tk() - root.withdraw() force_ontop = True def check_queue(): @@ -597,7 +592,7 @@ def check_queue(): if operation == 'init': # Create a new loadscreen. is_main, title, stages = args - screen = (SplashScreen if is_main else LoadScreen)(root, scr_id, title, force_ontop, stages) + screen = (SplashScreen if is_main else LoadScreen)(scr_id, title, force_ontop, stages) SCREENS[scr_id] = screen elif operation == 'set_force_ontop': [force_ontop] = args @@ -616,7 +611,7 @@ def check_queue(): # Continually re-run this function in the TK loop. # If we didn't find anything in the pipe, wait longer. # Otherwise we hog the CPU. - root.after(1 if had_values else 200, check_queue) + TK_ROOT.after(1 if had_values else 200, check_queue) - root.after(10, check_queue) - root.mainloop() # Infinite loop, until the entire process tree quits. + TK_ROOT.after(10, check_queue) + TK_ROOT.mainloop() # Infinite loop, until the entire process tree quits. From ecb6aa231b11b8f7fd04180d7cecb79296558294 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Mon, 20 Jul 2020 10:36:27 +1000 Subject: [PATCH 04/87] Fix some code directly altering property children --- src/app/UI.py | 2 +- src/packageLoader.py | 16 ++++++++-------- src/vbsp.py | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/app/UI.py b/src/app/UI.py index 9d3d93a0e..0b5874fe7 100644 --- a/src/app/UI.py +++ b/src/app/UI.py @@ -518,7 +518,7 @@ def load_packages(data): # the object. obj_types = [ (sky_list, 'Skybox', { - '3D': 'config.value', # Check if it has a config + '3D': 'config', # Check if it has a config 'COLOR': 'fog_color', }), (voice_list, 'QuotePack', { diff --git a/src/packageLoader.py b/src/packageLoader.py index b95eefb12..69d8afc67 100644 --- a/src/packageLoader.py +++ b/src/packageLoader.py @@ -2003,20 +2003,20 @@ def parse(cls, data: ParseData) -> 'QuotePack': # portrait. port_skin = srctools.conv_int(data.info['caveSkin', None], None) - monitor_data = data.info.find_key('monitor', None) - - if monitor_data.value is not None: + try: + monitor_data = data.info.find_key('monitor') + except NoKeyError: + mon_studio = mon_cam_loc = None + mon_interrupt = mon_cam_pitch = mon_cam_yaw = 0 + mon_studio_actor = '' + turret_hate = False + else: mon_studio = monitor_data['studio'] mon_studio_actor = monitor_data['studio_actor', ''] mon_interrupt = monitor_data.float('interrupt_chance', 0) mon_cam_loc = monitor_data.vec('Cam_loc') mon_cam_pitch, mon_cam_yaw, _ = monitor_data.vec('Cam_angles') turret_hate = monitor_data.bool('TurretShoot') - else: - mon_studio = mon_cam_loc = None - mon_interrupt = mon_cam_pitch = mon_cam_yaw = 0 - mon_studio_actor = '' - turret_hate = False config = get_config( data.info, diff --git a/src/vbsp.py b/src/vbsp.py index a3c4f36e2..d8cbc9c82 100644 --- a/src/vbsp.py +++ b/src/vbsp.py @@ -127,7 +127,7 @@ def load_settings() -> Tuple[antlines.AntType, antlines.AntType]: # The voice line property block for quote_block in conf.find_all("quotes"): - voice_line.QUOTE_DATA += quote_block.value + voice_line.QUOTE_DATA += quote_block.copy() # Configuration properties for styles. for stylevar_block in conf.find_all('stylevars'): From f532b2cb7bdc00db67b26a6ed26eb0259175adb7 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Tue, 21 Jul 2020 18:02:31 +1000 Subject: [PATCH 05/87] Fix missing import for precache_model --- src/precomp/cubes.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/precomp/cubes.py b/src/precomp/cubes.py index a7bc460ae..90756907b 100644 --- a/src/precomp/cubes.py +++ b/src/precomp/cubes.py @@ -9,6 +9,7 @@ from precomp import brushLoc, options, packing, conditions from precomp.conditions import meta_cond, make_result, make_flag, RES_EXHAUSTED +from precomp.conditions.globals import precache_model from precomp.instanceLocs import resolve as resolve_inst from srctools import ( Property, VMF, Entity, Vec, Output, @@ -1644,7 +1645,7 @@ def generate_cubes(vmf: VMF): CUBE_SKINS[spawn_paint, pair.cube_type.type], ), )) - precomp.conditions.globals.precache_model(vmf, cust_model) + precache_model(vmf, cust_model) drop_cube = cube = should_respawn = None From ace44210074283c74affcb73bbb5c83319f16b29 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Tue, 21 Jul 2020 18:03:02 +1000 Subject: [PATCH 06/87] Fix conditions modules not being included --- src/compiler.spec | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/compiler.spec b/src/compiler.spec index 050a703f0..dd651bcc1 100644 --- a/src/compiler.spec +++ b/src/compiler.spec @@ -88,14 +88,15 @@ if MAC or LINUX: # Include the condition sub-modules that are dynamically imported. INCLUDES = [ - 'conditions.' + module + 'precomp.conditions.' + module for loader, module, is_package in - pkgutil.iter_modules(['conditions']) + pkgutil.iter_modules(['precomp/conditions']) ] +print(INCLUDES) bee_version = input('BEE2 Version ("x.y.z" or blank for dev): ') if bee_version: - bee_version = '2 v' + bee_version = '2 v' + bee_version # Write this to the temp folder, so it's picked up and included. # Don't write it out though if it's the same, so PyInstaller doesn't reparse. From 2d6d9ab2636c9ad5c9e9a7037c30bf45ca133b21 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Tue, 21 Jul 2020 12:32:20 +1000 Subject: [PATCH 07/87] Use a local variable for the map in VBSP's main() This allows starting to disentangle this from being global at all. --- src/vbsp.py | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/vbsp.py b/src/vbsp.py index d8cbc9c82..c27e93906 100644 --- a/src/vbsp.py +++ b/src/vbsp.py @@ -218,7 +218,7 @@ def load_settings() -> Tuple[antlines.AntType, antlines.AntType]: return ant_floor, ant_wall -def load_map(map_path): +def load_map(map_path) -> VLib.VMF: """Load in the VMF file.""" global VMF with open(map_path) as file: @@ -227,6 +227,7 @@ def load_map(map_path): LOGGER.info('Reading Map...') VMF = VLib.VMF.parse(props) LOGGER.info("Loading complete!") + return VMF @conditions.meta_cond(priority=100) @@ -1777,13 +1778,13 @@ def instance_symlink(): os.symlink(inst, link_loc, target_is_directory=True) -def save(path: str) -> None: +def save(vmf: VLib.VMF, path: str) -> None: """Save the modified map back to the correct location. """ LOGGER.info("Saving New Map...") os.makedirs(os.path.dirname(path), exist_ok=True) with AtomicWriter(path) as f: - VMF.export(dest_file=f, inc_version=True) + vmf.export(dest_file=f, inc_version=True) LOGGER.info("Complete!") @@ -2035,14 +2036,14 @@ def main() -> None: LOGGER.info("Loading settings...") ant_floor, ant_wall = load_settings() - load_map(path) - instance_traits.set_traits(VMF) + vmf = load_map(path) + instance_traits.set_traits(vmf) - ant, side_to_antline = antlines.parse_antlines(VMF) + ant, side_to_antline = antlines.parse_antlines(vmf) # Requires instance traits! connections.calc_connections( - VMF, + vmf, ant, texturing.OVERLAYS.get_all('shapeframe'), settings['style_vars']['enableshapesignageframe'], @@ -2054,19 +2055,19 @@ def main() -> None: all_inst = get_map_info() - brushLoc.POS.read_from_map(VMF, settings['has_attr']) + brushLoc.POS.read_from_map(vmf, settings['has_attr']) - fizzler.parse_map(VMF, settings['has_attr']) - barriers.parse_map(VMF, settings['has_attr']) + fizzler.parse_map(vmf, settings['has_attr']) + barriers.parse_map(vmf, settings['has_attr']) conditions.init( seed=MAP_RAND_SEED, inst_list=all_inst, - vmf_file=VMF, + vmf_file=vmf, ) tiling.gen_tile_temp() - tiling.analyse_map(VMF, side_to_antline) + tiling.analyse_map(vmf, side_to_antline) del side_to_antline @@ -2076,18 +2077,18 @@ def main() -> None: add_extra_ents(GAME_MODE) change_ents() - tiling.generate_brushes(VMF) - faithplate.gen_faithplates(VMF) + tiling.generate_brushes(vmf) + faithplate.gen_faithplates(vmf) change_overlays() - barriers.make_barriers(VMF) + barriers.make_barriers(vmf) fix_worldspawn() # Ensure all VMF outputs use the correct separator. - for ent in VMF.entities: + for ent in vmf.entities: for out in ent.outputs: out.comma_sep = False - save(new_path) + save(vmf, new_path) run_vbsp( vbsp_args=new_args, path=path, From cf916aecb582680a5151f9dd0719cbdb64e2006c Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 22 Jul 2020 10:11:05 +1000 Subject: [PATCH 08/87] This if check is redundant, the instances would just be an empty list --- src/precomp/cubes.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/precomp/cubes.py b/src/precomp/cubes.py index 90756907b..8fea7b404 100644 --- a/src/precomp/cubes.py +++ b/src/precomp/cubes.py @@ -1074,8 +1074,6 @@ def link_cubes(vmf: VMF): inst_to_type = {} # type: Dict[str, Union[CubeType, DropperType]] for obj_type in itertools.chain(CUBE_TYPES.values(), DROPPER_TYPES.values()): - if not obj_type.instances: - continue for inst in obj_type.instances: inst_to_type[inst] = obj_type From ad60b827efa13badfc5fb84c50966850515b4da2 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 22 Jul 2020 10:11:41 +1000 Subject: [PATCH 09/87] Pass the map object into these functions. --- src/vbsp.py | 188 ++++++++++++++++++++++------------------------------ 1 file changed, 81 insertions(+), 107 deletions(-) diff --git a/src/vbsp.py b/src/vbsp.py index c27e93906..8eef4037c 100644 --- a/src/vbsp.py +++ b/src/vbsp.py @@ -231,12 +231,12 @@ def load_map(map_path) -> VLib.VMF: @conditions.meta_cond(priority=100) -def add_voice(): +def add_voice(vmf: VLib.VMF): """Add voice lines to the map.""" voice_line.add_voice( has_items=settings['has_attr'], style_vars_=settings['style_vars'], - vmf_file_=VMF, + vmf_file_=vmf, map_seed=MAP_RAND_SEED, use_priority=BEE2_config.get_bool('General', 'use_voice_priority', True), ) @@ -247,7 +247,7 @@ def add_voice(): @conditions.meta_cond(priority=200, only_once=True) -def anti_fizz_bump(): +def anti_fizz_bump(vmf: VLib.VMF) -> None: """Create portal_bumpers and noportal_volumes surrounding fizzlers. This makes it more difficult to portal-bump through an active fizzler. @@ -258,13 +258,13 @@ def anti_fizz_bump(): # to get the difference for each face. if not srctools.conv_bool(settings['style_vars']['fixfizzlerbump']): - return True + return # Only use 1 bumper entity for each fizzler, since we can. bumpers = {} LOGGER.info('Adding Portal Bumpers to fizzlers...') - for cleanser in VMF.by_class['trigger_portal_cleanser']: + for cleanser in vmf.by_class['trigger_portal_cleanser']: # Client bit flag = 1, triggers without it won't destroy portals # - so don't add a bumper. if int(cleanser['spawnflags']) & 1 != 1: @@ -277,7 +277,7 @@ def anti_fizz_bump(): # Only have 1 bumper per brush if fizz_name not in bumpers: - bumper = bumpers[fizz_name] = VMF.create_ent( + bumper = bumpers[fizz_name] = vmf.create_ent( classname='func_portal_bumper', targetname=fizz_name, origin=cleanser['origin'], @@ -290,7 +290,7 @@ def anti_fizz_bump(): # Noportal_volumes need separate parts, since they can't be # concave. - noportal = VMF.create_ent( + noportal = vmf.create_ent( classname='func_noportal_volume', targetname=fizz_name, origin=cleanser['origin'], @@ -339,7 +339,7 @@ def anti_fizz_bump(): @conditions.meta_cond(priority=400, only_once=True) -def set_player_model(): +def set_player_model(vmf: VLib.VMF) -> None: """Set the player model in SinglePlayer.""" # Add the model changer instance. @@ -358,13 +358,13 @@ def set_player_model(): model_path, pgun_skin = PLAYER_MODELS[chosen_model] # Precache the model, so we can switch to it. - VMF.create_ent( + vmf.create_ent( classname='comp_precache_model', origin=loc, model='models/' + model_path + '.mdl', ) - auto = VMF.create_ent( + auto = vmf.create_ent( classname='logic_auto', spawnflags=0, # Don't remove on fire. origin=loc, @@ -412,7 +412,7 @@ def set_player_model(): @conditions.meta_cond(priority=500, only_once=True) -def set_player_portalgun() -> None: +def set_player_portalgun(vmf: VLib.VMF) -> None: """Controls which portalgun the player will be given. This does not apply to coop. It checks the 'blueportal' and @@ -464,10 +464,10 @@ def set_player_portalgun() -> None: ent_pos = options.get(Vec, 'global_pti_ents_loc') - logic_auto = VMF.create_ent('logic_auto', origin=ent_pos, flags='1') + logic_auto = vmf.create_ent('logic_auto', origin=ent_pos, flags='1') if not blue_portal or not oran_portal or force_portal_man: - pgun_script = VMF.create_ent( + pgun_script = vmf.create_ent( classname='point_template', targetname='@portalgun', vscripts='bee2/portal_man.nut', @@ -475,7 +475,7 @@ def set_player_portalgun() -> None: ) if GAME_MODE == 'SP': - VMF.create_ent( + vmf.create_ent( classname='weapon_portalgun', targetname='__pgun_template', CanFirePortal1=0, @@ -491,7 +491,7 @@ def set_player_portalgun() -> None: # For Absolute Fizzler or otherwise, this fizzles portals on a # player remotely. - cleanser = VMF.create_ent( + cleanser = vmf.create_ent( classname='trigger_portal_cleanser', targetname='__pgun_cleanser', parentname=pgun_script['targetname'], @@ -500,13 +500,13 @@ def set_player_portalgun() -> None: visible=0, spawnflags=1, # Clients only. ) - cleanser.solids.append(VMF.make_prism( + cleanser.solids.append(vmf.make_prism( ent_pos - 4, ent_pos + 4, mat=consts.Tools.TRIGGER, ).solid) # For removing portalguns from players. - trig_stripper = VMF.create_ent( + trig_stripper = vmf.create_ent( targetname='__pgun_weapon_strip', classname='trigger_weapon_strip', origin=ent_pos, @@ -516,7 +516,7 @@ def set_player_portalgun() -> None: ) # Max map size is +-16384, for some reason we can't have a brush bigger than # that in any dimension? - whole_map = VMF.make_prism( + whole_map = vmf.make_prism( Vec(-8192, -8192, -8192), Vec(8192, 8192, 8192), mat=consts.Tools.TRIGGER, @@ -532,7 +532,7 @@ def set_player_portalgun() -> None: port_ids = (0, ) for port_id in port_ids: - trigger_portal = VMF.create_ent( + trigger_portal = vmf.create_ent( targetname='__pgun_port_detect_{}'.format(port_id), classname='func_portal_detector', origin=ent_pos, @@ -567,7 +567,7 @@ def set_player_portalgun() -> None: # Checking for held cubes, for pgun buttons. if has_btn_onoff: - trig_cube = VMF.create_ent( + trig_cube = vmf.create_ent( targetname='__pgun_held_trig', classname='trigger_multiple', origin=ent_pos, @@ -600,7 +600,7 @@ def set_player_portalgun() -> None: # Shuts down various parts when you've reached the exit. import precomp.conditions.instances - precomp.conditions.instances.global_input(VMF, ent_pos, VLib.Output( + precomp.conditions.instances.global_input(vmf, ent_pos, VLib.Output( 'OnTrigger', '@portalgun', 'RunScriptCode', @@ -626,12 +626,12 @@ def set_player_portalgun() -> None: @conditions.meta_cond(priority=750, only_once=True) -def add_screenshot_logic() -> None: +def add_screenshot_logic(vmf: VLib.VMF) -> None: """If the screenshot type is 'auto', add in the needed ents.""" if BEE2_config.get_val( 'Screenshot', 'type', 'PETI' ).upper() == 'AUTO' and IS_PREVIEW: - VMF.create_ent( + vmf.create_ent( classname='func_instance', file='instances/bee2/logic/screenshot_logic.vmf', origin=options.get(Vec, 'global_ents_loc'), @@ -641,10 +641,10 @@ def add_screenshot_logic() -> None: @conditions.meta_cond(priority=100, only_once=True) -def add_fog_ents(): +def add_fog_ents(vmf: VLib.VMF) -> None: """Add the tonemap and fog controllers, based on the skybox.""" pos = options.get(Vec, 'global_ents_loc') - VMF.create_ent( + vmf.create_ent( classname='env_tonemap_controller', targetname='@tonemapper', origin=pos + (-16, 0, 0), @@ -653,7 +653,7 @@ def add_fog_ents(): fog_opt = settings['fog'] random.seed(MAP_RAND_SEED + '_shadow_angle') - VMF.create_ent( + vmf.create_ent( classname='shadow_control', # Slight variations around downward direction. angles=Vec(random.randrange(85, 90), random.randrange(0, 360), 0), @@ -664,7 +664,7 @@ def add_fog_ents(): enableshadowsfromlocallights=1, ) - fog_controller = VMF.create_ent( + fog_controller = vmf.create_ent( classname='env_fog_controller', targetname='@fog_controller', origin=pos + (16, 0, 0), @@ -690,7 +690,7 @@ def add_fog_ents(): fog_controller['fogcolor2'] = fog_opt['secondary'] fog_controller['use_angles'] = '1' - logic_auto = VMF.create_ent(classname='logic_auto', origin=pos, flags='1') + logic_auto = vmf.create_ent(classname='logic_auto', origin=pos, flags='1') logic_auto.add_out( VLib.Output( @@ -764,7 +764,7 @@ def add_fog_ents(): @conditions.meta_cond(priority=50, only_once=True) -def set_elev_videos() -> None: +def set_elev_videos(vmf: VLib.VMF) -> None: """Add the scripts and options for customisable elevator videos to the map.""" vid_type = settings['elevator']['type'].casefold() @@ -792,7 +792,7 @@ def set_elev_videos() -> None: return transition_ents = instanceLocs.resolve('[transitionents]') - for inst in VMF.by_class['func_instance']: + for inst in vmf.by_class['func_instance']: if inst['file'].casefold() not in transition_ents: continue if vert_vid: @@ -801,7 +801,7 @@ def set_elev_videos() -> None: inst.fixup[consts.FixupVars.BEE_ELEV_HORIZ] = 'media/' + horiz_vid + '.bik' # Create the video script - VMF.create_ent( + vmf.create_ent( classname='logic_script', targetname='@video_splitter', vscripts=script, @@ -809,7 +809,7 @@ def set_elev_videos() -> None: ) -def get_map_info() -> Set[str]: +def get_map_info(vmf: VLib.VMF) -> Set[str]: """Determine various attributes about the map. This also set the 'preview in elevator' options and forces @@ -863,7 +863,7 @@ def get_map_info() -> Set[str]: # The door frame instances entry_door_frame = exit_door_frame = None - for item in VMF.by_class['func_instance']: + for item in vmf.by_class['func_instance']: # Loop through all the instances in the map, looking for the entry/exit # doors. # - Read the $no_player_start var to see if we're in preview mode, @@ -1012,13 +1012,13 @@ def get_map_info() -> Set[str]: def mod_entryexit( - inst: VLib.Entity, - resolve_name, - pretty_name, - elev_override=False, - override_corr=-1, - is_exit=False, - ): + inst: VLib.Entity, + resolve_name: str, + pretty_name: str, + elev_override: bool = False, + override_corr: int = -1, + is_exit: bool = False, +) -> str: """Modify this entrance or exit. This sets IS_PREVIEW, switches to vertical variants, and chooses a @@ -1062,7 +1062,7 @@ def mod_entryexit( return 'vert_down' if override_corr == -1: - return None # There aren't any variants (coop spawn room) + return '0' # There aren't any variants (coop spawn room) if override_corr == 0: index = files.index(inst['file'].casefold()) @@ -1081,7 +1081,7 @@ def mod_entryexit( ) inst.fixup[consts.FixupVars.BEE_CORR_INDEX] = override_corr inst['file'] = files[override_corr - 1] - return override_corr - 1 + return str(override_corr - 1) def mod_doorframe(inst: VLib.Entity, corr_id, corr_type, corr_name): @@ -1112,7 +1112,7 @@ def mod_doorframe(inst: VLib.Entity, corr_id, corr_type, corr_name): inst['file'] = replace -def calc_rand_seed() -> str: +def calc_rand_seed(vmf: VLib.VMF) -> str: """Use the ambient light entities to create a map seed. This ensures textures remain the same when the map is recompiled. @@ -1121,7 +1121,7 @@ def calc_rand_seed() -> str: lst = [ inst['targetname'] or '-' # If no targ for inst in - VMF.by_class['func_instance'] + vmf.by_class['func_instance'] if inst['file'].casefold() in amb_light ] if len(lst) == 0: @@ -1215,7 +1215,7 @@ def fit_goo_mist( @conditions.meta_cond(priority=-50) -def set_barrier_frame_type() -> None: +def set_barrier_frame_type(vmf: VLib.VMF) -> None: """Set a $type instvar on glass frame. This allows using different instances on glass and grating. @@ -1225,7 +1225,7 @@ def set_barrier_frame_type() -> None: barrier_pos = [] # type: List[Tuple[Vec, str]] # Find glass and grating brushes.. - for brush in VMF.iter_wbrushes(world=False, detail=True): + for brush in vmf.iter_wbrushes(world=False, detail=True): for side in brush: if side.mat == consts.Special.GLASS: break @@ -1234,7 +1234,7 @@ def set_barrier_frame_type() -> None: continue barrier_pos.append((brush.get_origin(), 'glass')) - for brush_ent in VMF.by_class['func_brush']: + for brush_ent in vmf.by_class['func_brush']: for side in brush_ent.sides(): if side.mat == consts.Special.GRATING: break @@ -1253,7 +1253,7 @@ def set_barrier_frame_type() -> None: barrier_files = instanceLocs.resolve('') glass_file = instanceLocs.resolve('[glass_128]') - for inst in VMF.by_class['func_instance']: + for inst in vmf.by_class['func_instance']: if inst['file'].casefold() not in barrier_files: continue if inst['file'].casefold() in glass_file: @@ -1268,32 +1268,6 @@ def set_barrier_frame_type() -> None: pass -def fix_squarebeams( - face: VLib.Side, - rotate: bool, - reset_offset: bool, - scale: float, -) -> None: - """Fix a squarebeams brush for use in other styles. - - If rotate is True, rotate the texture 90 degrees. - offset is the offset for the texture. - """ - if rotate: - # To rotate, swap the two values - face.uaxis, face.vaxis = face.vaxis, face.uaxis - - # We want to modify the value with an offset - if face.uaxis.offset != 0: - targ = face.uaxis - else: - targ = face.vaxis - - if reset_offset: - targ.offset = 0 - targ.scale = scale - - def change_brush() -> None: """Alter all world/detail brush textures to use the configured ones.""" LOGGER.info("Editing Brushes...") @@ -1430,7 +1404,7 @@ def cond_force_clump(inst: Entity, res: Property): )) -def change_overlays() -> None: +def change_overlays(vmf: VLib.VMF) -> None: """Alter the overlays.""" LOGGER.info("Editing Overlays...") @@ -1444,9 +1418,9 @@ def change_overlays() -> None: sign_inst_pack = options.get(str, 'signPack') # Grab all the textures we're using... - for over in VMF.by_class['info_overlay']: + for over in vmf.by_class['info_overlay']: if over in IGNORED_OVERLAYS: - # Overlays added by us, or conditions. These are styled aleady, + # Overlays added by us, or conditions. These are styled already, # don't touch them. continue @@ -1455,7 +1429,7 @@ def change_overlays() -> None: if options.get(bool, "remove_exit_signs"): # Some styles have instance-based ones, remove the # originals if needed to ensure it looks nice. - VMF.remove_ent(over) + over.remove() continue # Break out, to make sure the instance isn't added else: # blank the targetname, so we don't get the @@ -1470,14 +1444,14 @@ def change_overlays() -> None: continue if sign_inst is not None: - new_inst = VMF.create_ent( + new_inst = vmf.create_ent( classname='func_instance', origin=over['origin'], angles=over['angles', '0 0 0'], file=sign_inst, ) if sign_inst_pack: - packing.pack_list(VMF, sign_inst_pack) + packing.pack_list(vmf, sign_inst_pack) new_inst.fixup['mat'] = sign_type.name.lower() # Delete the overlay's targetname - signs aren't ever dynamic. @@ -1497,7 +1471,7 @@ def change_overlays() -> None: over[prop] = val.join(' ') -def add_extra_ents(game_mode: str) -> None: +def add_extra_ents(vmf: VLib.VMF, game_mode: str) -> None: """Add the various extra instances to the map.""" LOGGER.info("Adding Music...") @@ -1511,7 +1485,7 @@ def add_extra_ents(game_mode: str) -> None: # Don't add our logic if an instance was provided. # If this settings is set, we have a music config. if settings['music_conf'] and not inst: - music = VMF.create_ent( + music = vmf.create_ent( classname='ambient_generic', spawnflags='17', # Looping, Infinite Range, Starts Silent targetname='@music', @@ -1520,13 +1494,13 @@ def add_extra_ents(game_mode: str) -> None: health='10', # Volume ) - music_start = VMF.create_ent( + music_start = vmf.create_ent( classname='logic_relay', spawnflags='0', targetname='@music_start', origin=loc + (-16, 0, -16), ) - music_stop = VMF.create_ent( + music_stop = vmf.create_ent( classname='logic_relay', spawnflags='0', targetname='@music_stop', @@ -1547,7 +1521,7 @@ def add_extra_ents(game_mode: str) -> None: # In either case, we need @music_restart to do that safely. if game_mode == 'SP' or snd_length > 0: - music_restart = VMF.create_ent( + music_restart = vmf.create_ent( classname='logic_relay', spawnflags='2', # Allow fast retrigger. targetname='@music_restart', @@ -1574,7 +1548,7 @@ def add_extra_ents(game_mode: str) -> None: if game_mode == 'SP': # Trigger on level loads. - VMF.create_ent( + vmf.create_ent( classname='logic_auto', origin=loc + (0, 0, 16), spawnflags='0', # Don't remove after fire @@ -1601,7 +1575,7 @@ def add_extra_ents(game_mode: str) -> None: if inst: # We assume the instance is setup correct. - VMF.create_ent( + vmf.create_ent( classname='func_instance', targetname='music', angles='0 0 0', @@ -1619,21 +1593,21 @@ def add_extra_ents(game_mode: str) -> None: pti_loc = options.get(Vec, 'global_pti_ents_loc') # Add a nodraw box around the global entity location, to seal it. - VMF.add_brushes(VMF.make_hollow( + vmf.add_brushes(vmf.make_hollow( global_ents_pos + (128, 128, 128), global_ents_pos - (128, 128, 64), )) # Add a cubemap into the map, so materials get a blank one generated. # If none are present this doesn't happen... - VMF.create_ent( + vmf.create_ent( classname='env_cubemap', cubemapsize=1, # Make as small as possible.. origin=global_ents_pos, ) # So we have one in the map. - VMF.create_ent( + vmf.create_ent( classname='info_node', origin=global_ents_pos - (0, 0, 64), nodeid=1, @@ -1643,7 +1617,7 @@ def add_extra_ents(game_mode: str) -> None: if settings['has_attr']['bridge'] or settings['has_attr']['lightbridge']: # If we have light bridges, make sure we precache the particle. - VMF.create_ent( + vmf.create_ent( classname='info_particle_system', origin=global_ents_pos, effect_name='projected_wall_impact', @@ -1652,7 +1626,7 @@ def add_extra_ents(game_mode: str) -> None: if pti_file: LOGGER.info('Adding Global PTI Ents') - global_pti_ents = VMF.create_ent( + global_pti_ents = vmf.create_ent( classname='func_instance', targetname='global_pti_ents', angles='0 0 0', @@ -1671,34 +1645,34 @@ def add_extra_ents(game_mode: str) -> None: global_pti_ents.fixup['glados_script'] = 'choreo/glados.nut' # Implements Multiverse Cave.. -def change_ents() -> None: +def change_ents(vmf: VLib.VMF) -> None: """Edit misc entities.""" LOGGER.info("Editing Other Entities...") if options.get(bool, "remove_info_lighting"): # Styles with brush-based glass edges don't need the info_lighting, # delete it to save ents. - for ent in VMF.by_class['info_lighting']: + for ent in vmf.by_class['info_lighting']: ent.remove() - for auto in VMF.by_class['logic_auto']: + for auto in vmf.by_class['logic_auto']: # Remove all the logic_autos that set attachments, we can # replicate this in the instance for out in auto.outputs: if 'panel_top' in out.target: - VMF.remove_ent(auto) + vmf.remove_ent(auto) -def fix_worldspawn() -> None: +def fix_worldspawn(vmf: VLib.VMF) -> None: """Adjust some properties on WorldSpawn.""" LOGGER.info("Editing WorldSpawn") - if VMF.spawn['paintinmap'] != '1': + if vmf.spawn['paintinmap'] != '1': # If PeTI thinks there should be paint, don't touch it # Otherwise set it based on the 'gel' voice attribute # If the game is Aperture Tag, it's always forced on - VMF.spawn['paintinmap'] = srctools.bool_as_int( + vmf.spawn['paintinmap'] = srctools.bool_as_int( settings['has_attr']['gel'] or options.get(str, 'game_id') == utils.STEAM_IDS['APTAG'] ) - VMF.spawn['skyname'] = options.get(str, 'skybox') + vmf.spawn['skyname'] = options.get(str, 'skybox') def make_vrad_config(is_peti: bool) -> None: @@ -1757,7 +1731,7 @@ def make_vrad_config(is_peti: bool) -> None: f.write(line) -def instance_symlink(): +def instance_symlink() -> None: """On OS X and Linux, Valve broke VBSP's instances/ finding code. We need to symlink maps/styled/instances/ -> maps/instances/ to allow @@ -2051,9 +2025,9 @@ def main() -> None: ant_wall, ) - MAP_RAND_SEED = calc_rand_seed() + MAP_RAND_SEED = calc_rand_seed(vmf) - all_inst = get_map_info() + all_inst = get_map_info(vmf) brushLoc.POS.read_from_map(vmf, settings['has_attr']) @@ -2074,14 +2048,14 @@ def main() -> None: texturing.setup(MAP_RAND_SEED, list(tiling.TILES.values())) conditions.check_all() - add_extra_ents(GAME_MODE) + add_extra_ents(vmf, GAME_MODE) - change_ents() + change_ents(vmf) tiling.generate_brushes(vmf) faithplate.gen_faithplates(vmf) - change_overlays() + change_overlays(vmf) barriers.make_barriers(vmf) - fix_worldspawn() + fix_worldspawn(vmf) # Ensure all VMF outputs use the correct separator. for ent in vmf.entities: From 436de44aa7b73aff27475e6433c80c46ca623fe2 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 22 Jul 2020 11:05:38 +1000 Subject: [PATCH 10/87] Remove usages of VMF global from conditions module Instead it is passed in locally when required --- src/precomp/conditions/__init__.py | 177 +++++++--------------------- src/precomp/conditions/brushes.py | 4 +- src/precomp/conditions/logical.py | 27 +++-- src/precomp/conditions/randomise.py | 8 +- src/precomp/voice_line.py | 5 +- src/vbsp.py | 2 +- 6 files changed, 67 insertions(+), 156 deletions(-) diff --git a/src/precomp/conditions/__init__.py b/src/precomp/conditions/__init__.py index 159aad302..aeec9ac83 100644 --- a/src/precomp/conditions/__init__.py +++ b/src/precomp/conditions/__init__.py @@ -39,10 +39,7 @@ TextIO, ) -from precomp import ( - instanceLocs, - template_brush, -) +from precomp import instanceLocs import consts import srctools.logger import utils @@ -50,7 +47,7 @@ from srctools import ( Property, Vec_tuple, Vec, - Entity, Output, Solid, Side + VMF, Entity, Output, Solid, Side ) @@ -61,9 +58,8 @@ # Stuff we get from VBSP in init() GLOBAL_INSTANCES = set() # type: Set[str] ALL_INST = set() # type: Set[str] -VMF = None # type: srctools.VMF -conditions = [] +conditions: List['Condition'] = [] FLAG_LOOKUP = {} # type: Dict[str, Callable[[srctools.VMF, Entity, Property], bool]] RESULT_LOOKUP = {} # type: Dict[str, Callable[[srctools.VMF, Entity, Property], object]] RESULT_SETUP = {} # type: Dict[str, Callable[[srctools.VMF, Property], object]] @@ -203,7 +199,6 @@ def __init__( self.else_results = else_results or [] self.priority = priority self.source = source - self.setup() def __repr__(self): return ( @@ -260,25 +255,25 @@ def parse(cls, prop_block: Property) -> 'Condition': source, ) - def setup(self) -> None: + def setup(self, vmf: VMF) -> None: """Some results need some pre-processing before they can be used. """ for res in self.results[:]: - self.setup_result(self.results, res, self.source) + self.setup_result(vmf, self.results, res, self.source) for res in self.else_results[:]: - self.setup_result(self.else_results, res, self.source) + self.setup_result(vmf, self.else_results, res, self.source) @staticmethod - def setup_result(res_list: List[Property], result: Property, source: Optional[str]='') -> None: + def setup_result(vmf: VMF, res_list: List[Property], result: Property, source: Optional[str]='') -> None: """Helper method to perform result setup.""" func = RESULT_SETUP.get(result.name) if func: # noinspection PyBroadException try: - result.value = func(VMF, result) - except: + result.value = func(vmf, result) + except Exception: # Print the source of the condition if if fails... LOGGER.exception( 'Error in {} setup:', @@ -312,13 +307,13 @@ def test_result(inst: Entity, res: Property) -> Union[bool, object]: # Delete this so it doesn't re-fire.. return RES_EXHAUSTED else: - return func(VMF, inst, res) + return func(inst.map, inst, res) def test(self, inst: Entity) -> None: """Try to satisfy this condition on the given instance.""" success = True for flag in self.flags: - if not check_flag(flag, inst): + if not check_flag(inst.map, flag, inst): success = False break results = self.results if success else self.else_results @@ -514,11 +509,10 @@ def add(prop_block): conditions.append(con) -def init(seed: str, inst_list: Set[str], vmf_file: srctools.vmf.VMF) -> None: +def init(seed: str, inst_list: Set[str], vmf_file: VMF) -> None: """Initialise the Conditions system.""" # Get a bunch of values from VBSP - global MAP_RAND_SEED, ALL_INST, VMF - VMF = vmf_file + global MAP_RAND_SEED MAP_RAND_SEED = seed ALL_INST.update(inst_list) @@ -526,14 +520,16 @@ def init(seed: str, inst_list: Set[str], vmf_file: srctools.vmf.VMF) -> None: zero = Decimal(0) conditions.sort(key=lambda cond: getattr(cond, 'priority', zero)) - build_solid_dict() + build_solid_dict(vmf_file) -def check_all() -> None: +def check_all(vmf: VMF) -> None: """Check all conditions.""" LOGGER.info('Checking Conditions...') + LOGGER.info('-----------------------') for condition in conditions: - for inst in VMF.by_class['func_instance']: + condition.setup(vmf) + for inst in vmf.by_class['func_instance']: try: condition.test(inst) except NextInstance: @@ -556,6 +552,8 @@ def check_all() -> None: if not condition.results and not condition.else_results: break # Condition has run out of results, quit early + LOGGER.info('---------------------') + LOGGER.info('Conditions executed!') import vbsp LOGGER.info('Map has attributes: {}', [ key @@ -570,7 +568,7 @@ def check_all() -> None: LOGGER.info('Global instances: {}', GLOBAL_INSTANCES) -def check_flag(flag: Property, inst: Entity): +def check_flag(vmf: VMF, flag: Property, inst: Entity) -> bool: """Determine the result for a condition flag.""" name = flag.name # If starting with '!', invert the result. @@ -591,7 +589,7 @@ def check_flag(flag: Property, inst: Entity): # Skip these conditions.. return False - res = func(VMF, inst, flag) + res = func(vmf, inst, flag) return res == desired_result @@ -633,7 +631,7 @@ def import_conditions() -> None: LOGGER.info('Imported all conditions modules!') -def build_solid_dict() -> None: +def build_solid_dict(vmf: VMF) -> None: """Build a dictionary mapping origins to brush faces. This allows easily finding brushes that are at certain locations. @@ -646,7 +644,7 @@ def build_solid_dict() -> None: for mat in vbsp.WHITE_PAN: mat_types[mat] = Portalable.white - for solid in VMF.brushes: + for solid in vmf.brushes: for face in solid: try: mat_type = mat_types[face.mat] @@ -670,7 +668,7 @@ def build_solid_dict() -> None: ) -def build_itemclass_dict(prop_block: Property): +def build_itemclass_dict(prop_block: Property) -> None: """Load in the item ID database. This maps item IDs to their item class, and their embed locations. @@ -940,92 +938,6 @@ def widen_fizz_brush(brush: Solid, thickness: float, bounds: Tuple[Vec, Vec]=Non v[axis] = bound_min[axis] -def remove_ant_toggle(toggle_ent: Entity): - """Remove a texture_toggle instance , plus the associated antline. - - For non-toggle instances, they will just be removed. - """ - toggle_ent.remove() - - # Assume anything with '$indicator_name' is a toggle instance - # This will likely be called on the signs too, if present. - overlay_name = toggle_ent.fixup[consts.FixupVars.TOGGLE_OVERLAY, ''] - if overlay_name != '': - for ent in VMF.by_target[overlay_name]: - ent.remove() - - -def reallocate_overlays(mapping: Dict[str, Optional[List[str]]]): - """Replace one side ID with others in all overlays. - - The IDs should be strings. - """ - for overlay in VMF.by_class['info_overlay']: - sides = overlay['sides', ''].split(' ') - for side in sides[:]: - try: - new_ids = mapping[side] - except KeyError: - continue - sides.remove(side) - if new_ids is not None: - sides.extend(new_ids) - if not sides: - # The overlay doesn't have any sides at all! - VMF.remove_ent(overlay) - else: - overlay['sides'] = ' '.join(sides) - - -def steal_from_brush( - temp_data: template_brush.ExportedTemplate, - brush_group: 'solidGroup', - rem_brush=True, - additional: Iterable[int]=(), - transfer_overlays=True, -): - """Copy IDs from a brush to a template.""" - temp_brushes = temp_data.world.copy() - # Overlays can't be applied to entities (other than func_detail). - if temp_data.detail is not None and temp_data.detail['classname'] == 'func_detail': - temp_brushes.extend(temp_data.detail.solids) - - if rem_brush: - VMF.remove_brush(brush_group.solid) - else: - # Switch it to nodraw if still in the map, since it must be - # covered. - brush_group.face.mat = 'tools/toolsnodraw' - - # Additional is a list of IDs in the template VMF, not the final one. - additional = { - temp_data.orig_ids.get(int(face_id), -1) - for face_id in - additional - } - new_ids: Optional[List[str]] = [] - - for brush in temp_brushes: - for face in brush.sides: - # Only faces pointing the same way! - if face.normal() == brush_group.normal: - # Skip tool brushes in the template (nodraw, player clips..) - if face.mat.casefold().startswith('tools/'): - continue - new_ids.append(str(face.id)) - # If the original ID is present in the 'additional' values - # use it. This allows specifying specific faces. - elif face.id in additional: - new_ids.append(str(face.id)) - - if new_ids: - if not transfer_overlays: - new_ids = None - reallocate_overlays({ - str(brush_group.face.id): new_ids, - }) - - def set_ent_keys( ent: Entity, inst: Entity, @@ -1182,7 +1094,7 @@ def dummy_result(inst: Entity, props: Property): @meta_cond(priority=1000, only_once=False) -def remove_blank_inst(inst: Entity): +def remove_blank_inst(inst: Entity) -> None: """Remove instances with a blank file keyvalue. This allows conditions to strip the instances when requested. @@ -1190,18 +1102,7 @@ def remove_blank_inst(inst: Entity): # If editoritems instances are set to "", PeTI will autocorrect it to # ".vmf" - we need to handle that too. if inst['file', ''] in ('', '.vmf'): - VMF.remove_ent(inst) - - -@meta_cond(priority=0, only_once=True) -def fix_catapult_targets(inst: Entity): - """Set faith plate targets to transmit to clients. - - This fixes some console spam in coop, and might improve trajectories - for faith plates. - """ - for targ in VMF.by_class['info_target']: - targ['spawnflags'] = '3' # Transmit to client, ignoring PVS + inst.remove() @make_result_setup('timedRelay') @@ -1231,14 +1132,14 @@ def res_timed_relay_setup(res: Property): @make_result('timedRelay') -def res_timed_relay(inst: Entity, res: Property): +def res_timed_relay(vmf: VMF, inst: Entity, res: Property) -> None: """Generate a logic_relay with outputs delayed by a certain amount. This allows triggering outputs based $timer_delay values. """ var, name, disabled, flags, final_outs, rep_outs = res.value - relay = VMF.create_ent( + relay = vmf.create_ent( classname='logic_relay', spawnflags=flags, origin=inst['origin'], @@ -1273,11 +1174,18 @@ def res_timed_relay(inst: Entity, res: Property): relay.add_out(new_out) +@make_result_setup('condition') +def res_sub_condition_setup(vmf: VMF, res: Property): + """Setup the sub-condition.""" + cond = Condition.parse(res) + cond.setup(vmf) + return cond + + @make_result('condition') def res_sub_condition(base_inst: Entity, res: Property): """Check a different condition if the outer block is true.""" res.value.test(base_inst) -make_result_setup('condition')(Condition.parse) @make_result('nextInstance') @@ -1299,7 +1207,7 @@ def res_end_condition(): @make_result_setup('switch') -def res_switch_setup(res: Property): +def res_switch_setup(vmf: VMF, res: Property): flag = None method = SWITCH_TYPE.FIRST cases = [] @@ -1326,6 +1234,7 @@ def res_switch_setup(res: Property): for prop in itertools.chain(cases, default): for result in prop.value: Condition.setup_result( + vmf, prop.value, result, 'switch: {} -> {}'.format(flag, prop.real_name), @@ -1344,7 +1253,7 @@ def res_switch_setup(res: Property): @make_result('switch') -def res_switch(inst: Entity, res: Property): +def res_switch(vmf: VMF, inst: Entity, res: Property): """Run the same flag multiple times with different arguments. 'method' is the way the search is done - first, last, random, or all. @@ -1368,7 +1277,7 @@ def res_switch(inst: Entity, res: Property): for case in cases: if flag_name is not None: flag = Property(flag_name, case.real_name) - if not check_flag(flag, inst): + if not check_flag(vmf, flag, inst): continue for res in case: Condition.test_result(inst, res) @@ -1479,7 +1388,7 @@ def make_static_pist(vmf: srctools.VMF, ent: Entity, res: Property): @make_result('GooDebris') -def res_goo_debris(res: Property): +def res_goo_debris(vmf: VMF, res: Property) -> object: """Add random instances to goo squares. Options: @@ -1558,7 +1467,7 @@ def res_goo_debris(res: Property): loc.x += random.randint(-offset, offset) loc.y += random.randint(-offset, offset) loc.z -= 32 # Position the instances in the center of the 128 grid. - VMF.create_ent( + vmf.create_ent( classname='func_instance', file=file + suff + '.vmf', origin=loc.join(' '), diff --git a/src/precomp/conditions/brushes.py b/src/precomp/conditions/brushes.py index 124efa719..52aff6a18 100644 --- a/src/precomp/conditions/brushes.py +++ b/src/precomp/conditions/brushes.py @@ -504,7 +504,7 @@ def visgroup_func(groups): @make_result('TemplateBrush') -def res_import_template(inst: Entity, res: Property): +def res_import_template(vmf: VMF, inst: Entity, res: Property): """Import a template VMF file, retexturing it to match orientation. It will be placed overlapping the given instance. If no block is used, only @@ -619,7 +619,7 @@ def visgroup_func(group): return for vis_flag_block in visgroup_instvars: - if all(conditions.check_flag(flag, inst) for flag in vis_flag_block): + if all(conditions.check_flag(vmf, flag, inst) for flag in vis_flag_block): visgroups.add(vis_flag_block.real_name) if color_var.casefold() == '': diff --git a/src/precomp/conditions/logical.py b/src/precomp/conditions/logical.py index 1ec77d5ae..db2a7c9a5 100644 --- a/src/precomp/conditions/logical.py +++ b/src/precomp/conditions/logical.py @@ -1,50 +1,51 @@ """Logical flags used to combine others (AND, OR, NOT, etc).""" from precomp.conditions import make_flag, check_flag -from srctools import Entity, Property +from srctools import Entity, Property, VMF + COND_MOD_NAME = 'Logic' @make_flag('AND') -def flag_and(inst: Entity, flag: Property): +def flag_and(vmf: VMF, inst: Entity, flag: Property): """The AND group evaluates True if all sub-flags are True.""" for sub_flag in flag: - if not check_flag(sub_flag, inst): + if not check_flag(vmf, sub_flag, inst): return False return True @make_flag('OR') -def flag_or(inst: Entity, flag: Property): +def flag_or(vmf: VMF, inst: Entity, flag: Property): """The OR group evaluates True if any sub-flags are True.""" for sub_flag in flag: - if check_flag(sub_flag, inst): + if check_flag(vmf, sub_flag, inst): return True return False @make_flag('NOT') -def flag_not(inst: Entity, flag: Property): +def flag_not(vmf: VMF, inst: Entity, flag: Property): """The NOT group inverts the value of it's one sub-flag.""" if len(flag.value) == 1: - return not check_flag(flag[0], inst) + return not check_flag(vmf, flag[0], inst) return False @make_flag('XOR') -def flag_xor(inst: Entity, flag:Property): +def flag_xor(vmf: VMF, inst: Entity, flag:Property): """The XOR group returns True if the number of true sub-flags is odd.""" - return sum([check_flag(sub_flag, inst) for sub_flag in flag]) % 2 == 1 + return sum([check_flag(vmf, sub_flag, inst) for sub_flag in flag]) % 2 == 1 @make_flag('NOR') -def flag_nor(inst: Entity, flag: Property): +def flag_nor(vmf: VMF, inst: Entity, flag: Property): """The NOR group evaluates True if any sub-flags are False.""" - return not flag_or(inst, flag) + return not flag_or(vmf, inst, flag) @make_flag('NAND') -def flag_nand(inst: Entity, flag: Property): +def flag_nand(vmf: VMF, inst: Entity, flag: Property): """The NAND group evaluates True if all sub-flags are False.""" - return not flag_and(inst, flag) + return not flag_and(vmf, inst, flag) diff --git a/src/precomp/conditions/randomise.py b/src/precomp/conditions/randomise.py index 3bf15ab62..061233e19 100644 --- a/src/precomp/conditions/randomise.py +++ b/src/precomp/conditions/randomise.py @@ -2,7 +2,7 @@ import random from typing import List -from srctools import Property, Vec, Entity +from srctools import Property, Vec, Entity, VMF from precomp import conditions import srctools @@ -32,7 +32,7 @@ def flag_random(inst: Entity, res: Property) -> bool: @make_result_setup('random') -def res_random_setup(res: Property) -> object: +def res_random_setup(vmf: VMF, res: Property) -> object: weight = '' results = [] chance = 100 @@ -60,9 +60,9 @@ def res_random_setup(res: Property) -> object: for prop in results[:]: if prop.name == 'group': for sub_prop in list(prop): - Condition.setup_result(prop.value, sub_prop) + Condition.setup_result(vmf, prop.value, sub_prop) else: - Condition.setup_result(results, prop) + Condition.setup_result(vmf, results, prop) return seed, chance, weight, results diff --git a/src/precomp/voice_line.py b/src/precomp/voice_line.py index 54fedc386..dfc9545f2 100644 --- a/src/precomp/voice_line.py +++ b/src/precomp/voice_line.py @@ -119,7 +119,7 @@ def res_quote_event(res: Property): return conditions.RES_EXHAUSTED -def find_group_quotes(group, mid_quotes, use_dings, conf, mid_name, player_flag_set): +def find_group_quotes(vmf, group, mid_quotes, use_dings, conf, mid_name, player_flag_set): """Scan through a group, looking for applicable quote options.""" is_mid = (group.name == 'midchamber') @@ -138,7 +138,7 @@ def find_group_quotes(group, mid_quotes, use_dings, conf, mid_name, player_flag_ if name in ('priority', 'name', 'id', 'line') or name.startswith('line_'): # Not flags! continue - if not conditions.check_flag(flag, fake_inst): + if not conditions.check_flag(vmf, flag, fake_inst): valid_quote = False break @@ -553,6 +553,7 @@ def add_voice( possible_quotes = sorted( find_group_quotes( + vmf_file, group, mid_quotes, use_dings, diff --git a/src/vbsp.py b/src/vbsp.py index 8eef4037c..7a955dbae 100644 --- a/src/vbsp.py +++ b/src/vbsp.py @@ -2047,7 +2047,7 @@ def main() -> None: texturing.setup(MAP_RAND_SEED, list(tiling.TILES.values())) - conditions.check_all() + conditions.check_all(vmf) add_extra_ents(vmf, GAME_MODE) change_ents(vmf) From a66a8abb0cfcc0be956da60d599eea32bcf14128 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 22 Jul 2020 11:54:42 +1000 Subject: [PATCH 11/87] Fix import loop between template_brush <-> tiling --- src/vbsp.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vbsp.py b/src/vbsp.py index 7a955dbae..cc18a73c5 100644 --- a/src/vbsp.py +++ b/src/vbsp.py @@ -19,17 +19,20 @@ import srctools.run import srctools.logger from precomp import ( - instance_traits, tiling, brushLoc, bottomlessPit, + instance_traits, + brushLoc, + bottomlessPit, instanceLocs, cubes, + template_brush, texturing, + tiling, barriers, connections, options, faithplate, antlines, packing, - template_brush, conditions, fizzler, voice_line, From 6c6215710a58a4e5981a873e2e40c488691b94f2 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 22 Jul 2020 14:37:31 +1000 Subject: [PATCH 12/87] Remove the unused SOLIDS dict --- src/precomp/conditions/__init__.py | 53 ++---------------------------- 1 file changed, 2 insertions(+), 51 deletions(-) diff --git a/src/precomp/conditions/__init__.py b/src/precomp/conditions/__init__.py index aeec9ac83..dfcd1ef5e 100644 --- a/src/precomp/conditions/__init__.py +++ b/src/precomp/conditions/__init__.py @@ -81,16 +81,6 @@ class SWITCH_TYPE(Enum): ALL = 'all' # Run all matching commands -# A dictionary mapping origins to their brushes -class solidGroup(NamedTuple): - face: Side - solid: Solid - normal: Vec # The normal of the face. - color: Portalable - -SOLIDS = {} # type: Dict[Vec_tuple, solidGroup] - - # For each class, a list of item IDs of that type. ITEMS_WITH_CLASS = defaultdict(list) # type: Dict[consts.ItemClass, List[str]] # For each item Id, the item class for it. @@ -280,7 +270,7 @@ def setup_result(vmf: VMF, res_list: List[Property], result: Property, source: O source or 'condition', ) if utils.DEV_MODE: - # Crash so this is immediately noticable.. + # Crash so this is immediately noticeable.. utils.quit_app(1) else: # In release, just skip this one - that way it's @@ -413,7 +403,7 @@ def add_meta(func, priority: Union[Decimal, int], only_once=True): dec_priority = Decimal(priority) # This adds a condition result like "func" (with quotes), which cannot # be entered into property files. - # The qualname will be unique across modules. + # The qualified name will be unique across modules. name = '"' + func.__qualname__ + '"' LOGGER.debug( "Adding metacondition ({}) with priority {!s}!", @@ -520,8 +510,6 @@ def init(seed: str, inst_list: Set[str], vmf_file: VMF) -> None: zero = Decimal(0) conditions.sort(key=lambda cond: getattr(cond, 'priority', zero)) - build_solid_dict(vmf_file) - def check_all(vmf: VMF) -> None: """Check all conditions.""" @@ -631,43 +619,6 @@ def import_conditions() -> None: LOGGER.info('Imported all conditions modules!') -def build_solid_dict(vmf: VMF) -> None: - """Build a dictionary mapping origins to brush faces. - - This allows easily finding brushes that are at certain locations. - """ - import vbsp - mat_types = {} - for mat in vbsp.BLACK_PAN: - mat_types[mat] = Portalable.black - - for mat in vbsp.WHITE_PAN: - mat_types[mat] = Portalable.white - - for solid in vmf.brushes: - for face in solid: - try: - mat_type = mat_types[face.mat] - except KeyError: - continue - else: - origin = face.get_origin().as_tuple() - if origin in SOLIDS: - # The only time two textures will be in the same - # place is if they are covering each other - - # nodraw them both and ignore them - SOLIDS.pop(origin).face.mat = consts.Tools.NODRAW - face.mat = consts.Tools.NODRAW - continue - - SOLIDS[origin] = solidGroup( - color=mat_type, - face=face, - solid=solid, - normal=face.normal(), - ) - - def build_itemclass_dict(prop_block: Property) -> None: """Load in the item ID database. From 8b54179e27f52752d741f1e97efad9082c5d6c2d Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 22 Jul 2020 14:39:34 +1000 Subject: [PATCH 13/87] Remove the global VMF entirely Finally! --- src/vbsp.py | 117 +++++++++++++++++++++++++--------------------------- 1 file changed, 57 insertions(+), 60 deletions(-) diff --git a/src/vbsp.py b/src/vbsp.py index cc18a73c5..c3736125d 100644 --- a/src/vbsp.py +++ b/src/vbsp.py @@ -12,10 +12,10 @@ from io import StringIO from collections import defaultdict, namedtuple, Counter -from srctools import Property, Vec, AtomicWriter, Entity +from srctools import Property, Vec, AtomicWriter +from srctools.vmf import VMF, Entity, Output from BEE2_config import ConfigFile import utils -import srctools.vmf as VLib import srctools.run import srctools.logger from precomp import ( @@ -87,9 +87,6 @@ # when recompiling. MAP_RAND_SEED = '' -# The actual map. -VMF = None # type: VLib.VMF - # These are overlays which have been modified by # conditions, and shouldn't be restyled or modified later. IGNORED_OVERLAYS = set() @@ -221,20 +218,20 @@ def load_settings() -> Tuple[antlines.AntType, antlines.AntType]: return ant_floor, ant_wall -def load_map(map_path) -> VLib.VMF: +def load_map(map_path) -> VMF: """Load in the VMF file.""" global VMF with open(map_path) as file: LOGGER.info("Parsing Map...") props = Property.parse(file, map_path) LOGGER.info('Reading Map...') - VMF = VLib.VMF.parse(props) + VMF = VMF.parse(props) LOGGER.info("Loading complete!") return VMF @conditions.meta_cond(priority=100) -def add_voice(vmf: VLib.VMF): +def add_voice(vmf: VMF): """Add voice lines to the map.""" voice_line.add_voice( has_items=settings['has_attr'], @@ -250,7 +247,7 @@ def add_voice(vmf: VLib.VMF): @conditions.meta_cond(priority=200, only_once=True) -def anti_fizz_bump(vmf: VLib.VMF) -> None: +def anti_fizz_bump(vmf: VMF) -> None: """Create portal_bumpers and noportal_volumes surrounding fizzlers. This makes it more difficult to portal-bump through an active fizzler. @@ -342,7 +339,7 @@ def anti_fizz_bump(vmf: VLib.VMF) -> None: @conditions.meta_cond(priority=400, only_once=True) -def set_player_model(vmf: VLib.VMF) -> None: +def set_player_model(vmf: VMF) -> None: """Set the player model in SinglePlayer.""" # Add the model changer instance. @@ -375,7 +372,7 @@ def set_player_model(vmf: VLib.VMF) -> None: # The delay is required to ensure the portalgun parents properly # to the player's hand. - auto.add_out(VLib.Output( + auto.add_out(Output( 'OnMapSpawn', '@command', 'Command', @@ -384,7 +381,7 @@ def set_player_model(vmf: VLib.VMF) -> None: )) # We need to redo this whenever a saved game is loaded.. - auto.add_out(VLib.Output( + auto.add_out(Output( 'OnLoadGame', '@command', 'Command', @@ -395,14 +392,14 @@ def set_player_model(vmf: VLib.VMF) -> None: if pgun_skin and options.get(str, 'game_id') == utils.STEAM_IDS['PORTAL2']: # Only change portalgun skins in Portal 2 - this is the vanilla # portalgun weapon/viewmodel. - auto.add_out(VLib.Output( + auto.add_out(Output( 'OnMapSpawn', 'viewmodel', # Classname of the viewmodel. 'Skin', str(pgun_skin), delay=0.1, )) - auto.add_out(VLib.Output( + auto.add_out(Output( 'OnMapSpawn', # Classname of the portalgun. # This will also change pedestals and the like, @@ -415,7 +412,7 @@ def set_player_model(vmf: VLib.VMF) -> None: @conditions.meta_cond(priority=500, only_once=True) -def set_player_portalgun(vmf: VLib.VMF) -> None: +def set_player_portalgun(vmf: VMF) -> None: """Controls which portalgun the player will be given. This does not apply to coop. It checks the 'blueportal' and @@ -544,7 +541,7 @@ def set_player_portalgun(vmf: VLib.VMF) -> None: ) trigger_portal.solids = [whole_map.copy()] trigger_portal.add_out( - VLib.Output( + Output( 'OnStartTouchPortal1', '!activator', 'RunScriptCode', @@ -552,7 +549,7 @@ def set_player_portalgun(vmf: VLib.VMF) -> None: '__pgun_port_id <- {}; ' '__pgun_active <- 1'.format(port_id), ), - VLib.Output( + Output( 'OnStartTouchPortal2', '!activator', 'RunScriptCode', @@ -560,7 +557,7 @@ def set_player_portalgun(vmf: VLib.VMF) -> None: '__pgun_port_id <- {}; ' '__pgun_active <- 1'.format(port_id), ), - VLib.Output( + Output( 'OnEndTouchPortal', '!activator', 'RunScriptCode', @@ -580,7 +577,7 @@ def set_player_portalgun(vmf: VLib.VMF) -> None: wait=0.01, ) trig_cube.solids = [whole_map.copy()] - trig_cube.add_out(VLib.Output( + trig_cube.add_out(Output( 'OnStartTouch', '@portalgun', 'RunScriptCode', @@ -588,7 +585,7 @@ def set_player_portalgun(vmf: VLib.VMF) -> None: )) if GAME_MODE == 'SP': - logic_auto.add_out(VLib.Output( + logic_auto.add_out(Output( 'OnMapSpawn', '@portalgun', 'RunScriptCode', @@ -603,7 +600,7 @@ def set_player_portalgun(vmf: VLib.VMF) -> None: # Shuts down various parts when you've reached the exit. import precomp.conditions.instances - precomp.conditions.instances.global_input(vmf, ent_pos, VLib.Output( + precomp.conditions.instances.global_input(vmf, ent_pos, Output( 'OnTrigger', '@portalgun', 'RunScriptCode', @@ -611,14 +608,14 @@ def set_player_portalgun(vmf: VLib.VMF) -> None: ), relay_name='@map_won') if blue_portal: - logic_auto.add_out(VLib.Output( + logic_auto.add_out(Output( 'OnMapSpawn', '@player_has_blue', 'Trigger', only_once=True, )) if oran_portal: - logic_auto.add_out(VLib.Output( + logic_auto.add_out(Output( 'OnMapSpawn', '@player_has_oran', 'Trigger', @@ -629,7 +626,7 @@ def set_player_portalgun(vmf: VLib.VMF) -> None: @conditions.meta_cond(priority=750, only_once=True) -def add_screenshot_logic(vmf: VLib.VMF) -> None: +def add_screenshot_logic(vmf: VMF) -> None: """If the screenshot type is 'auto', add in the needed ents.""" if BEE2_config.get_val( 'Screenshot', 'type', 'PETI' @@ -644,7 +641,7 @@ def add_screenshot_logic(vmf: VLib.VMF) -> None: @conditions.meta_cond(priority=100, only_once=True) -def add_fog_ents(vmf: VLib.VMF) -> None: +def add_fog_ents(vmf: VMF) -> None: """Add the tonemap and fog controllers, based on the skybox.""" pos = options.get(Vec, 'global_ents_loc') vmf.create_ent( @@ -696,35 +693,35 @@ def add_fog_ents(vmf: VLib.VMF) -> None: logic_auto = vmf.create_ent(classname='logic_auto', origin=pos, flags='1') logic_auto.add_out( - VLib.Output( + Output( 'OnMapSpawn', '@clientcommand', 'Command', 'r_flashlightbrightness 1', ), - VLib.Output( + Output( 'OnMapSpawn', '@tonemapper', 'SetTonemapPercentBrightPixels', fog_opt['tonemap_brightpixels'], only_once=True, ), - VLib.Output( + Output( 'OnMapSpawn', '@tonemapper', 'SetTonemapRate', fog_opt['tonemap_rate'], only_once=True, ), - VLib.Output( + Output( 'OnMapSpawn', '@tonemapper', 'SetAutoExposureMin', fog_opt['tonemap_exp_min'], only_once=True, ), - VLib.Output( + Output( 'OnMapSpawn', '@tonemapper', 'SetAutoExposureMax', @@ -734,7 +731,7 @@ def add_fog_ents(vmf: VLib.VMF) -> None: ) if fog_opt['tonemap_bloom_scale']: - logic_auto.add_out(VLib.Output( + logic_auto.add_out(Output( 'OnMapSpawn', '@tonemapper', 'SetBloomScale', @@ -743,7 +740,7 @@ def add_fog_ents(vmf: VLib.VMF) -> None: )) if GAME_MODE == 'SP': - logic_auto.add_out(VLib.Output( + logic_auto.add_out(Output( 'OnMapSpawn', '!player', 'SetFogController', @@ -751,13 +748,13 @@ def add_fog_ents(vmf: VLib.VMF) -> None: only_once=True, )) else: - logic_auto.add_out(VLib.Output( + logic_auto.add_out(Output( 'OnMapSpawn', '!player_blue', 'SetFogController', '@fog_controller', only_once=True, - ), VLib.Output( + ), Output( 'OnMapSpawn', '!player_orange', 'SetFogController', @@ -767,7 +764,7 @@ def add_fog_ents(vmf: VLib.VMF) -> None: @conditions.meta_cond(priority=50, only_once=True) -def set_elev_videos(vmf: VLib.VMF) -> None: +def set_elev_videos(vmf: VMF) -> None: """Add the scripts and options for customisable elevator videos to the map.""" vid_type = settings['elevator']['type'].casefold() @@ -812,7 +809,7 @@ def set_elev_videos(vmf: VLib.VMF) -> None: ) -def get_map_info(vmf: VLib.VMF) -> Set[str]: +def get_map_info(vmf: VMF) -> Set[str]: """Determine various attributes about the map. This also set the 'preview in elevator' options and forces @@ -1015,7 +1012,7 @@ def get_map_info(vmf: VLib.VMF) -> Set[str]: def mod_entryexit( - inst: VLib.Entity, + inst: Entity, resolve_name: str, pretty_name: str, elev_override: bool = False, @@ -1087,7 +1084,7 @@ def mod_entryexit( return str(override_corr - 1) -def mod_doorframe(inst: VLib.Entity, corr_id, corr_type, corr_name): +def mod_doorframe(inst: Entity, corr_id, corr_type, corr_name): """Change the instance used by door frames, if desired. corr_id is the item ID of the dooor, and corr_type is the @@ -1115,7 +1112,7 @@ def mod_doorframe(inst: VLib.Entity, corr_id, corr_type, corr_name): inst['file'] = replace -def calc_rand_seed(vmf: VLib.VMF) -> str: +def calc_rand_seed(vmf: VMF) -> str: """Use the ambient light entities to create a map seed. This ensures textures remain the same when the map is recompiled. @@ -1218,7 +1215,7 @@ def fit_goo_mist( @conditions.meta_cond(priority=-50) -def set_barrier_frame_type(vmf: VLib.VMF) -> None: +def set_barrier_frame_type(vmf: VMF) -> None: """Set a $type instvar on glass frame. This allows using different instances on glass and grating. @@ -1407,7 +1404,7 @@ def cond_force_clump(inst: Entity, res: Property): )) -def change_overlays(vmf: VLib.VMF) -> None: +def change_overlays(vmf: VMF) -> None: """Alter the overlays.""" LOGGER.info("Editing Overlays...") @@ -1474,7 +1471,7 @@ def change_overlays(vmf: VLib.VMF) -> None: over[prop] = val.join(' ') -def add_extra_ents(vmf: VLib.VMF, game_mode: str) -> None: +def add_extra_ents(vmf: VMF, game_mode: str) -> None: """Add the various extra instances to the map.""" LOGGER.info("Adding Music...") @@ -1510,8 +1507,8 @@ def add_extra_ents(vmf: VLib.VMF, game_mode: str) -> None: origin=loc + (16, 0, -16), ) music_stop.add_out( - VLib.Output('OnTrigger', music, 'StopSound'), - VLib.Output('OnTrigger', music, 'Volume', '0'), + Output('OnTrigger', music, 'StopSound'), + Output('OnTrigger', music, 'Volume', '0'), ) # In SinglePlayer, music gets killed during reload, @@ -1533,20 +1530,20 @@ def add_extra_ents(vmf: VLib.VMF, game_mode: str) -> None: ) music_start.add_out( - VLib.Output('OnTrigger', music_restart, 'Enable'), - VLib.Output('OnTrigger', music_restart, 'Trigger', delay=0.01), + Output('OnTrigger', music_restart, 'Enable'), + Output('OnTrigger', music_restart, 'Trigger', delay=0.01), ) music_stop.add_out( - VLib.Output('OnTrigger', music_restart, 'Disable'), - VLib.Output('OnTrigger', music_restart, 'CancelPending'), + Output('OnTrigger', music_restart, 'Disable'), + Output('OnTrigger', music_restart, 'CancelPending'), ) music_restart.add_out( - VLib.Output('OnTrigger', music, 'StopSound'), - VLib.Output('OnTrigger', music, 'Volume', '0'), - VLib.Output('OnTrigger', music, 'Volume', '10', delay=0.1), - VLib.Output('OnTrigger', music, 'PlaySound', delay=0.1), + Output('OnTrigger', music, 'StopSound'), + Output('OnTrigger', music, 'Volume', '0'), + Output('OnTrigger', music, 'Volume', '10', delay=0.1), + Output('OnTrigger', music, 'PlaySound', delay=0.1), ) if game_mode == 'SP': @@ -1557,14 +1554,14 @@ def add_extra_ents(vmf: VLib.VMF, game_mode: str) -> None: spawnflags='0', # Don't remove after fire globalstate='', ).add_out( - VLib.Output('OnLoadGame', music_restart, 'CancelPending'), - VLib.Output('OnLoadGame', music_restart, 'Trigger', delay=0.01), + Output('OnLoadGame', music_restart, 'CancelPending'), + Output('OnLoadGame', music_restart, 'Trigger', delay=0.01), ) if snd_length > 0: # Re-trigger after the music duration. music_restart.add_out( - VLib.Output('OnTrigger', '!self', 'Trigger', delay=snd_length) + Output('OnTrigger', '!self', 'Trigger', delay=snd_length) ) # Set to non-looping, so re-playing will restart it correctly. music['spawnflags'] = '49' @@ -1572,8 +1569,8 @@ def add_extra_ents(vmf: VLib.VMF, game_mode: str) -> None: # The music track never needs to have repeating managed, # just directly trigger. music_start.add_out( - VLib.Output('OnTrigger', music, 'PlaySound'), - VLib.Output('OnTrigger', music, 'Volume', '10'), + Output('OnTrigger', music, 'PlaySound'), + Output('OnTrigger', music, 'Volume', '10'), ) if inst: @@ -1648,7 +1645,7 @@ def add_extra_ents(vmf: VLib.VMF, game_mode: str) -> None: global_pti_ents.fixup['glados_script'] = 'choreo/glados.nut' # Implements Multiverse Cave.. -def change_ents(vmf: VLib.VMF) -> None: +def change_ents(vmf: VMF) -> None: """Edit misc entities.""" LOGGER.info("Editing Other Entities...") if options.get(bool, "remove_info_lighting"): @@ -1664,7 +1661,7 @@ def change_ents(vmf: VLib.VMF) -> None: vmf.remove_ent(auto) -def fix_worldspawn(vmf: VLib.VMF) -> None: +def fix_worldspawn(vmf: VMF) -> None: """Adjust some properties on WorldSpawn.""" LOGGER.info("Editing WorldSpawn") if vmf.spawn['paintinmap'] != '1': @@ -1755,7 +1752,7 @@ def instance_symlink() -> None: os.symlink(inst, link_loc, target_is_directory=True) -def save(vmf: VLib.VMF, path: str) -> None: +def save(vmf: VMF, path: str) -> None: """Save the modified map back to the correct location. """ LOGGER.info("Saving New Map...") From 7e4a1de49704fe0087a695a0ee355a263e19dd83 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 22 Jul 2020 14:39:53 +1000 Subject: [PATCH 14/87] Minor type hints --- src/precomp/conditions/__init__.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/precomp/conditions/__init__.py b/src/precomp/conditions/__init__.py index dfcd1ef5e..3fbb32110 100644 --- a/src/precomp/conditions/__init__.py +++ b/src/precomp/conditions/__init__.py @@ -168,12 +168,13 @@ class EndCondition(Exception): """Raised to skip the condition entirely, from the EndCond result.""" pass -# Flag to indicate a result doesn't need to be exectuted anymore, +# Flag to indicate a result doesn't need to be executed anymore, # and can be cleaned up - adding a global instance, for example. RES_EXHAUSTED = object() class Condition: + """A single condition which may be evaluated.""" __slots__ = ['flags', 'results', 'else_results', 'priority', 'source'] def __init__( @@ -190,7 +191,7 @@ def __init__( self.priority = priority self.source = source - def __repr__(self): + def __repr__(self) -> str: return ( 'Condition(flags={!r}, ' 'results={!r}, else_results={!r}, ' @@ -938,11 +939,10 @@ def resolve_value(inst: Entity, value: Union[str, T]) -> Union[str, T]: value = inst.fixup[value] else: LOGGER.warning( - 'Invalid fixup ({}) in the "{}" instance:\n{}\n{}', + 'Invalid fixup ({}) in the "{}" instance:\n{}', value, inst['targetname'], inst, - inst.fixup._fixup ) value = '' @@ -1140,7 +1140,7 @@ def res_sub_condition(base_inst: Entity, res: Property): @make_result('nextInstance') -def res_break(): +def res_break() -> None: """Skip to the next instance. The value will be ignored. @@ -1149,7 +1149,7 @@ def res_break(): @make_result('endCondition', 'nextCondition') -def res_end_condition(): +def res_end_condition() -> None: """Skip to the next condition. The value will be ignored. From 3296100e72cae4a5f1c1dd6edb16066daf881dc6 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 22 Jul 2020 14:41:50 +1000 Subject: [PATCH 15/87] Redo flip panel logic correctly - Make start_deployed inbuilt - Mirror around the subtiles to match the rotation of the panel --- src/precomp/tiling.py | 54 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/src/precomp/tiling.py b/src/precomp/tiling.py index b9198c4f4..134573747 100644 --- a/src/precomp/tiling.py +++ b/src/precomp/tiling.py @@ -517,6 +517,48 @@ def export( all_brushes: List[Solid] = [] + if self.pan_type.is_flip: + # Two surfaces, forward and backward - each is 4 thick. + invert_black = self.pan_type is PanelType.FLIP_INVERT + back_subtiles = { + uv: ( + tile_type.inverted + if invert_black or tile_type.color is Portalable.WHITE else + tile_type + ) for uv, tile_type in sub_tiles.items() + } + # If facing black first, use that side. + if not self.inst.fixup.bool(consts.FixupVars.ST_DEPLOYED): + back_subtiles, sub_tiles = sub_tiles, back_subtiles + + # Now, we need to flip this across the appropriate axis to + # replicate rotation. + u_ax, v_ax = Vec.INV_AXIS[tile.normal.axis()] + rot_flag = srctools.conv_int(self.brush_ent['spawnflags']) + if rot_flag & 64: + rot_axis = 'x' + elif rot_flag & 128: + rot_axis = 'y' + else: + rot_axis = 'z' + if rot_axis == v_ax: + back_subtiles = { + (3-u, v): tile_type + for (u, v), tile_type in back_subtiles.items() + } + elif rot_axis == u_ax: + back_subtiles = { + (u, 3-v): tile_type + for (u, v), tile_type in back_subtiles.items() + } + else: + LOGGER.warning( + 'Flip panel "{}" rotates on normal axis??', + self.brush_ent['targetname'], + ) + else: # Should never be needed, but makes typecheck happy. + back_subtiles = sub_tiles + faces, brushes = tile.gen_multitile_pattern( vmf, sub_tiles, @@ -544,23 +586,15 @@ def export( side.scale = 0.25 if self.pan_type.is_flip: - # Two surfaces, forward and backward - each is 4 thick. - invert_black = self.pan_type is PanelType.FLIP_INVERT - inv_subtiles = { - uv: ( - tile_type.inverted - if invert_black or tile_type.color is Portalable.WHITE else - tile_type - ) for uv, tile_type in sub_tiles.items() - } back_faces, brushes = tile.gen_multitile_pattern( vmf, - inv_subtiles, + back_subtiles, is_wall, self.bevels, -tile.normal, thickness=self.thickness, offset=64 - 2*self.thickness, + is_panel=True, add_bullseye=use_bullseye and not is_static, interior_bevel=False, # User must specify this themselves. ) From e7315a78db49bbdc0c923d9feaeb3de3aa068efd Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 22 Jul 2020 16:23:04 +1000 Subject: [PATCH 16/87] Fix some cases where vbsp.VMF was still used --- src/precomp/conditions/addInstance.py | 24 +++--- src/precomp/conditions/brushes.py | 19 ++--- src/precomp/conditions/conveyorBelt.py | 1 + src/precomp/conditions/cutoutTile.py | 2 + src/precomp/conditions/entities.py | 3 +- src/precomp/conditions/instances.py | 4 +- src/precomp/conditions/piston_platform.py | 1 + src/precomp/conditions/signage.py | 1 + src/precomp/conditions/vactubes.py | 89 +++++++++++++---------- src/precomp/faithplate.py | 7 +- src/precomp/fizzler.py | 3 + src/precomp/template_brush.py | 15 ++-- src/precomp/texturing.py | 19 +++-- src/precomp/tiling.py | 1 + src/vbsp.py | 59 ++++++++------- 15 files changed, 133 insertions(+), 115 deletions(-) diff --git a/src/precomp/conditions/addInstance.py b/src/precomp/conditions/addInstance.py index 426afced1..c2d19d1bd 100644 --- a/src/precomp/conditions/addInstance.py +++ b/src/precomp/conditions/addInstance.py @@ -1,14 +1,12 @@ """Results for generating additional instances. """ -from precomp import instanceLocs, options, conditions +from typing import Optional +from srctools import Vec, Entity, Property, VMF import srctools.logger -import vbsp -from precomp.conditions import ( - make_result, RES_EXHAUSTED, - GLOBAL_INSTANCES, -) -from srctools import Vec, Entity, Property + +from precomp import instanceLocs, options, conditions +from precomp.conditions import make_result, RES_EXHAUSTED, GLOBAL_INSTANCES COND_MOD_NAME = 'Instance Generation' @@ -17,7 +15,7 @@ @make_result('addGlobal') -def res_add_global_inst(res: Property): +def res_add_global_inst(vmf: VMF, res: Property): """Add one instance in a specific location. Options: @@ -42,7 +40,7 @@ def res_add_global_inst(res: Property): # if was already added - this is helpful for # items that add to original items, or to avoid # bugs. - new_inst = vbsp.VMF.create_ent( + new_inst = vmf.create_ent( classname="func_instance", targetname=res['name', ''], file=instanceLocs.resolve_one(res['file'], error=True), @@ -61,7 +59,7 @@ def res_add_global_inst(res: Property): @make_result('addOverlay', 'overlayinst') -def res_add_overlay_inst(inst: Entity, res: Property): +def res_add_overlay_inst(vmf: VMF, inst: Entity, res: Property) -> Optional[Entity]: """Add another instance on top of this one. If a single value, this sets only the filename. @@ -102,9 +100,9 @@ def res_add_overlay_inst(inst: Entity, res: Property): if not res.bool('silentLookup'): LOGGER.warning('Bad filename for "{}" when adding overlay!', orig_name) # Don't bother making a overlay which will be deleted. - return + return None - overlay_inst = vbsp.VMF.create_ent( + overlay_inst = vmf.create_ent( classname='func_instance', targetname=inst['targetname', ''], file=filename, @@ -142,5 +140,5 @@ def res_cave_portrait(inst: Entity, res: Property): skin = options.get(int, 'cave_port_skin') if skin is not None: new_inst = res_add_overlay_inst(inst, res) - if new_inst: + if new_inst is not None: new_inst.fixup['$skin'] = skin diff --git a/src/precomp/conditions/brushes.py b/src/precomp/conditions/brushes.py index 52aff6a18..3c9be4a3d 100644 --- a/src/precomp/conditions/brushes.py +++ b/src/precomp/conditions/brushes.py @@ -157,7 +157,7 @@ def res_fix_rotation_axis(vmf: VMF, ent: Entity, res: Property): )) # Generate brush - door_ent.solids = [vbsp.VMF.make_prism(pos - 1, pos + 1).solid] + door_ent.solids = [vmf.make_prism(pos - 1, pos + 1).solid] # Add or remove flags as needed by creating KV setters. @@ -256,7 +256,7 @@ def res_set_texture(inst: Entity, res: Property): @make_result('AddBrush') -def res_add_brush(inst: Entity, res: Property) -> None: +def res_add_brush(vmf: VMF, inst: Entity, res: Property) -> None: """Spawn in a brush at the indicated points. - `point1` and `point2` are locations local to the instance, with `0 0 0` @@ -268,8 +268,6 @@ def res_add_brush(inst: Entity, res: Property) -> None: The sides will be textured with 1x1, 2x2 or 4x4 wall, ceiling and floor textures as needed. """ - import vbsp - point1 = Vec.from_str(res['point1']) point2 = Vec.from_str(res['point2']) @@ -323,7 +321,7 @@ def res_add_brush(inst: Entity, res: Property) -> None: # All brushes in each grid have the same textures for each side. random.seed(grid_offset.join(' ') + '-partial_block') - solids = vbsp.VMF.make_prism(point1, point2) + solids = vmf.make_prism(point1, point2) solids.north.mat = texturing.gen( texturing.GenCat.NORMAL, @@ -356,16 +354,14 @@ def res_add_brush(inst: Entity, res: Property) -> None: tex_type, ).get(solids.north.get_origin(), tile_grids['z']) - if srctools.conv_bool(res['detail', False], False): + if res.bool('detail'): # Add the brush to a func_detail entity - vbsp.VMF.create_ent( + vmf.create_ent( classname='func_detail' - ).solids = [ - solids.solid - ] + ).solids = [solids.solid] else: # Add to the world - vbsp.VMF.add_brush(solids.solid) + vmf.add_brush(solids.solid) @make_result_setup('TemplateBrush') @@ -652,6 +648,7 @@ def visgroup_func(group): origin = Vec.from_str(inst['origin']) angles = Vec.from_str(inst['angles', '0 0 0']) temp_data = template_brush.import_template( + vmf, template, origin, angles, diff --git a/src/precomp/conditions/conveyorBelt.py b/src/precomp/conditions/conveyorBelt.py index 2d695ffc0..0fd038994 100644 --- a/src/precomp/conditions/conveyorBelt.py +++ b/src/precomp/conditions/conveyorBelt.py @@ -119,6 +119,7 @@ def res_conveyor_belt(vmf: VMF, inst: Entity, res: Property) -> None: if rail_template: temp = template_brush.import_template( + vmf, rail_template, pos, angles, diff --git a/src/precomp/conditions/cutoutTile.py b/src/precomp/conditions/cutoutTile.py index ac18b9368..a21ffb004 100644 --- a/src/precomp/conditions/cutoutTile.py +++ b/src/precomp/conditions/cutoutTile.py @@ -414,6 +414,7 @@ def convert_floor( brush.face.mat = 'tools/toolsnodraw' # It won't be visible temp_data = template_brush.import_template( + vmf, temp_name=FLOOR_TEMP_PILLAR, origin=loc, ) @@ -804,6 +805,7 @@ def add_floor_sides(vmf: VMF, locs): diag_loc = (wall_loc.x, wall_loc.y, wall_loc.z + 128) temp_data = template_brush.import_template( + vmf, # If there's a wall surface directly above this point # or a ceiling brush in the next block over # we want to use a world brush to seal the leak. diff --git a/src/precomp/conditions/entities.py b/src/precomp/conditions/entities.py index 04435e5c6..a69cc1aff 100644 --- a/src/precomp/conditions/entities.py +++ b/src/precomp/conditions/entities.py @@ -41,7 +41,7 @@ def res_import_template_setup( @make_result('TemplateOverlay') -def res_insert_overlay(inst: Entity, res: Property) -> None: +def res_insert_overlay(vmf: VMF, inst: Entity, res: Property) -> None: """Use a template to insert one or more overlays on a surface. Options: @@ -89,6 +89,7 @@ def res_insert_overlay(inst: Entity, res: Property) -> None: return temp = template_brush.import_template( + vmf, temp_id, origin, angles, diff --git a/src/precomp/conditions/instances.py b/src/precomp/conditions/instances.py index 24299ab6f..0b2b5a021 100644 --- a/src/precomp/conditions/instances.py +++ b/src/precomp/conditions/instances.py @@ -285,7 +285,7 @@ def res_local_targetname(inst: Entity, res: Property): @make_result('replaceInstance') -def res_replace_instance(inst: Entity, res: Property): +def res_replace_instance(vmf: VMF, inst: Entity, res: Property): """Replace an instance with another entity. `keys` and `localkeys` defines the new keyvalues used. @@ -309,7 +309,7 @@ def res_replace_instance(inst: Entity, res: Property): # Ensure there's a classname, just in case. new_ent['classname'] = 'info_null' - vbsp.VMF.add_ent(new_ent) + vmf.add_ent(new_ent) conditions.set_ent_keys(new_ent, inst, res) diff --git a/src/precomp/conditions/piston_platform.py b/src/precomp/conditions/piston_platform.py index 85754c81e..d035e1909 100644 --- a/src/precomp/conditions/piston_platform.py +++ b/src/precomp/conditions/piston_platform.py @@ -226,6 +226,7 @@ def res_piston_plat(vmf: VMF, inst: Entity, res: Property) -> None: pist_ent.remove() temp_result = template_brush.import_template( + vmf, template, brush_pos, angles, diff --git a/src/precomp/conditions/signage.py b/src/precomp/conditions/signage.py index 39307370b..a90077175 100644 --- a/src/precomp/conditions/signage.py +++ b/src/precomp/conditions/signage.py @@ -163,6 +163,7 @@ def res_signage(vmf: VMF, inst: Entity, res: Property): else: visgroup = [sec_visgroup] template = template_brush.import_template( + vmf, template_id, origin, angles, diff --git a/src/precomp/conditions/vactubes.py b/src/precomp/conditions/vactubes.py index 3bd506338..7da0ebbd5 100644 --- a/src/precomp/conditions/vactubes.py +++ b/src/precomp/conditions/vactubes.py @@ -3,7 +3,7 @@ from collections import namedtuple from typing import Dict, Tuple, List, Iterator, Optional -from srctools import Vec, Vec_tuple, Property, Entity, VMF +from srctools import Vec, Vec_tuple, Property, Entity, VMF, Solid import srctools.logger from precomp import tiling, instanceLocs, connections, template_brush @@ -166,7 +166,7 @@ def res_vactube_setup(res: Property): @make_result('CustVactube') -def res_make_vactubes(res: Property): +def res_make_vactubes(vmf: VMF, res: Property): """Specialised result to parse vactubes from markers. Only runs once, and then quits the condition list. After priority 400, @@ -182,7 +182,7 @@ def res_make_vactubes(res: Property): markers: Dict[str, Marker] = {} # Find all our markers, so we can look them up by targetname. - for inst in vbsp.VMF.by_class['func_instance']: # type: Entity + for inst in vmf.by_class['func_instance']: # type: Entity try: config, inst_size = INST_CONFIGS[inst['file'].casefold()] except KeyError: @@ -241,7 +241,7 @@ def vactube_gen(vmf: VMF) -> None: # First create the start section.. start_logic = start.ent.copy() - vbsp.VMF.add_ent(start_logic) + vmf.add_ent(start_logic) start_logic['file'] = start.conf['entry', ( 'ceiling' if (start_normal.z > 0) else @@ -252,7 +252,7 @@ def vactube_gen(vmf: VMF) -> None: end = start for inst, end in start.follow_path(all_markers): - join_markers(inst, end, inst is start) + join_markers(vmf, inst, end, inst is start) end_loc = Vec.from_str(end.ent['origin']) end_norm = Vec(-1, 0, 0).rotate_by_str(end.ent['angles']) @@ -260,6 +260,7 @@ def vactube_gen(vmf: VMF) -> None: # join_markers creates straight parts up-to the marker, but not at it's # location - create the last one. make_straight( + vmf, end_loc, end_norm, 128, @@ -270,16 +271,16 @@ def vactube_gen(vmf: VMF) -> None: # the object is on a one-way trip anyway. if BLOCK_POS['world': end_loc].is_goo and end_norm == (0, 0, -1): end_logic = end.ent.copy() - vbsp.VMF.add_ent(end_logic) + vmf.add_ent(end_logic) end_logic['file'] = end.conf['exit'] -def push_trigger(loc, normal, solids): +def push_trigger(vmf: VMF, loc: Vec, normal: Vec, solids: List[Solid]) -> None: # We only need one trigger per direction, for now. try: ent = PUSH_TRIGS[normal.as_tuple()] except KeyError: - ent = PUSH_TRIGS[normal.as_tuple()] = vbsp.VMF.create_ent( + ent = PUSH_TRIGS[normal.as_tuple()] = vmf.create_ent( classname='trigger_push', origin=loc, # The z-direction is reversed.. @@ -295,15 +296,15 @@ def push_trigger(loc, normal, solids): ent.solids.extend(solids) -def motion_trigger(*solids): +def motion_trigger(vmf: VMF, *solids: Solid) -> None: """Create the anti-gravity trigger, and force crouching.""" - motion_trig = vbsp.VMF.create_ent( + motion_trig = vmf.create_ent( classname='trigger_vphysics_motion', SetGravityScale='0.0', origin=solids[0].get_origin(), spawnflags='1103', # Clients, Physics, Everything ) - duck_trig = vbsp.VMF.create_ent( + duck_trig = vmf.create_ent( classname='trigger_playermovement', origin=motion_trig['origin'], spawnflags=1 + 2048, # Clients, Auto-duck while in trigger. @@ -314,6 +315,7 @@ def motion_trigger(*solids): def make_straight( + vmf: VMF, origin: Vec, normal: Vec, dist: int, @@ -333,15 +335,15 @@ def make_straight( # bbox before +- 32 to ensure the above doesn't wipe it out p1, p2 = Vec.bbox(p1, p2) - solid = vbsp.VMF.make_prism( + solid = vmf.make_prism( # Expand to 64x64 in the other two directions p1 - 32, p2 + 32, mat='tools/toolstrigger', ).solid - motion_trigger(solid.copy()) + motion_trigger(vmf, solid.copy()) - push_trigger(origin, normal, [solid]) + push_trigger(vmf, origin, normal, [solid]) angles = normal.to_angle() @@ -355,7 +357,7 @@ def make_straight( for off in range(0, int(dist), 128): position = origin + off * normal - vbsp.VMF.create_ent( + vmf.create_ent( classname='func_instance', origin=position, angles=angles, @@ -372,7 +374,7 @@ def make_straight( continue # Check all 4 center tiles are present. if all(tile[u, v].is_tile for u in (1,2) for v in (1, 2)): - vbsp.VMF.create_ent( + vmf.create_ent( classname='func_instance', origin=position, angles=supp_ang, @@ -380,8 +382,8 @@ def make_straight( ) -def make_corner(origin, angle, size, config): - vbsp.VMF.create_ent( +def make_corner(vmf: VMF, origin: Vec, angle: str, size: int, config: dict) -> None: + vmf.create_ent( classname='func_instance', origin=origin, angles=angle, @@ -391,26 +393,27 @@ def make_corner(origin, angle, size, config): temp = config['corner_temp', size] if temp: temp_solids = template_brush.import_template( + vmf, temp, origin=origin, angles=Vec.from_str(angle), force_type=template_brush.TEMP_TYPES.world, + add_to_map=False, ).world - for solid in temp_solids: - vbsp.VMF.remove_brush(solid) motion_trigger(*temp_solids) def make_bend( - origin_a: Vec, - origin_b: Vec, - norm_a: Vec, - norm_b: Vec, - corner_ang: str, - config, - max_size: int, - is_start=False, -): + vmf: VMF, + origin_a: Vec, + origin_b: Vec, + norm_a: Vec, + norm_b: Vec, + corner_ang: str, + config, + max_size: int, + is_start=False, +) -> None: """Make a corner and the straight sections leading into it.""" off = origin_b - origin_a # The distance to move first, then second. @@ -428,10 +431,11 @@ def make_bend( straight_b = sec_movement.mag() - (corner_size * 128) if corner_size < 1: - return [] # No room! + return # No room! if straight_a > 0: make_straight( + vmf, origin_a, norm_a, straight_a, @@ -441,6 +445,7 @@ def make_bend( corner_origin = origin_a + norm_a * straight_a make_corner( + vmf, corner_origin, corner_ang, corner_size, @@ -449,6 +454,7 @@ def make_bend( if straight_b > 0: make_straight( + vmf, origin_b - (straight_b * norm_b), norm_b, straight_b, @@ -457,12 +463,13 @@ def make_bend( def make_ubend( - origin_a: Vec, - origin_b: Vec, - normal: Vec, - config, - max_size: int, - is_start=False, + vmf: VMF, + origin_a: Vec, + origin_b: Vec, + normal: Vec, + config, + max_size: int, + is_start=False, ): """Create u-shaped bends.""" offset = origin_b - origin_a @@ -552,6 +559,7 @@ def make_ubend( ) make_straight( + vmf, origin_a, normal, first_straight, @@ -562,6 +570,7 @@ def make_ubend( first_corner_loc = origin_a + (normal * first_straight) make_corner( + vmf, first_corner_loc, CORNER_ANG[normal.as_tuple(), side_norm.as_tuple()].ang, first_size, @@ -573,6 +582,7 @@ def make_ubend( if side_straight > 0: make_straight( + vmf, off_straight_loc, side_norm, side_straight, @@ -582,6 +592,7 @@ def make_ubend( sec_corner_loc = off_straight_loc + side_norm * side_straight make_corner( + vmf, sec_corner_loc, CORNER_ANG[side_norm.as_tuple(), (-normal).as_tuple()].ang, second_size, @@ -590,6 +601,7 @@ def make_ubend( if second_straight > 0: make_straight( + vmf, sec_corner_loc - normal * (128 * second_size), -normal, second_straight, @@ -597,7 +609,7 @@ def make_ubend( ) -def join_markers(mark_a: Marker, mark_b: Marker, is_start: bool=False) -> None: +def join_markers(vmf: VMF, mark_a: Marker, mark_b: Marker, is_start: bool=False) -> None: """Join two marker ents together with corners.""" origin_a = Vec.from_str(mark_a.ent['origin']) origin_b = Vec.from_str(mark_b.ent['origin']) @@ -613,6 +625,7 @@ def join_markers(mark_a: Marker, mark_b: Marker, is_start: bool=False) -> None: if origin_a + (norm_a * dist) == origin_b: make_straight( + vmf, origin_a, norm_a, dist, @@ -625,6 +638,7 @@ def join_markers(mark_a: Marker, mark_b: Marker, is_start: bool=False) -> None: if norm_a == -norm_b: # U-shape bend.. make_ubend( + vmf, origin_a, origin_b, norm_a, @@ -644,6 +658,7 @@ def join_markers(mark_a: Marker, mark_b: Marker, is_start: bool=False) -> None: return else: make_bend( + vmf, origin_a, origin_b, norm_a, diff --git a/src/precomp/faithplate.py b/src/precomp/faithplate.py index 5afebf425..37e775d8f 100644 --- a/src/precomp/faithplate.py +++ b/src/precomp/faithplate.py @@ -238,9 +238,10 @@ def gen_faithplates(vmf: VMF) -> None: trig_origin = trig.get_origin() if plate.template is not None: trig.solids = template_brush.import_template( - temp_name=plate.template, - origin=trig_origin + plate.trig_offset, - angles=Vec.from_str(plate.inst['angles']), + vmf, + plate.template, + trig_origin + plate.trig_offset, + Vec.from_str(plate.inst['angles']), force_type=template_brush.TEMP_TYPES.world, add_to_map=False, ).world diff --git a/src/precomp/fizzler.py b/src/precomp/fizzler.py index 1c914885d..0ecb8e4cd 100644 --- a/src/precomp/fizzler.py +++ b/src/precomp/fizzler.py @@ -1348,6 +1348,7 @@ def get_model_name(ind): if template_brush_ent is not None: if length == 128 and fizz_type.temp_single: temp = template_brush.import_template( + vmf, fizz_type.temp_single, (seg_min + seg_max) / 2, min_angles, @@ -1358,6 +1359,7 @@ def get_model_name(ind): else: if fizz_type.temp_min: temp = template_brush.import_template( + vmf, fizz_type.temp_min, seg_min, min_angles, @@ -1367,6 +1369,7 @@ def get_model_name(ind): template_brush_ent.solids.extend(temp.world) if fizz_type.temp_max: temp = template_brush.import_template( + vmf, fizz_type.temp_max, seg_max, max_angles, diff --git a/src/precomp/template_brush.py b/src/precomp/template_brush.py index 85044dd71..a11737079 100644 --- a/src/precomp/template_brush.py +++ b/src/precomp/template_brush.py @@ -571,6 +571,7 @@ def get_template(temp_name) -> Template: def import_template( + vmf: VMF, temp_name: Union[str, Template], origin: Vec, angles: Optional[Vec]=None, @@ -626,7 +627,7 @@ def import_template( ]: for old_brush in orig_list: brush = old_brush.copy( - vmf_file=vbsp.VMF, + vmf_file=vmf, side_mapping=id_mapping, keep_vis=False, ) @@ -635,7 +636,7 @@ def import_template( for overlay in orig_over: # type: Entity new_overlay = overlay.copy( - vmf_file=vbsp.VMF, + vmf_file=vmf, keep_vis=False, ) del new_overlay['template_id'] # Remove this, it's not part of overlays @@ -656,7 +657,7 @@ def import_template( if targetname and orig_target and orig_target[0] != '@': new_overlay['targetname'] = targetname + '-' + orig_target - vbsp.VMF.add_ent(new_overlay) + vmf.add_ent(new_overlay) new_over.append(new_overlay) # Don't let the overlays get retextured too! @@ -670,14 +671,12 @@ def import_template( new_detail.clear() if add_to_map: - vbsp.VMF.add_brushes(new_world) + vmf.add_brushes(new_world) detail_ent: Optional[Entity] = None if new_detail: - detail_ent = vbsp.VMF.create_ent( - classname='func_detail' - ) + detail_ent = vmf.create_ent(classname='func_detail') detail_ent.solids = new_detail if not add_to_map: detail_ent.remove() @@ -910,7 +909,7 @@ def retexture_template( for v in (0, 1, 2, 3) }, is_wall=tiledef.normal.z != 0, - bevels=(False, False, False, False), + bevels=frozenset(), normal=tiledef.normal, face_output=pattern, ) diff --git a/src/precomp/texturing.py b/src/precomp/texturing.py index 424dd5f7c..25dd0854f 100644 --- a/src/precomp/texturing.py +++ b/src/precomp/texturing.py @@ -7,8 +7,8 @@ import abc import srctools.logger -from srctools import Property, Side, Solid, Vec -from srctools.vmf import VisGroup +from srctools import Property, Vec +from srctools.vmf import VisGroup, VMF, Side, Solid import consts @@ -600,7 +600,7 @@ def load_config(conf: Property): OVERLAYS = GENERATORS[GenCat.OVERLAYS] -def setup(global_seed, tiles: List['TileDef']): +def setup(vmf: VMF, global_seed: str, tiles: List['TileDef']) -> None: """Set randomisation seed on all the generators, and build clumps.""" gen_key_str: Union[GenCat, str] for gen_key, generator in GENERATORS.items(): @@ -615,7 +615,7 @@ def setup(global_seed, tiles: List['TileDef']): gen_key_str = gen_key generator.map_seed = '{}_tex_{}_'.format(global_seed, gen_key_str) - generator.setup(global_seed, tiles) + generator.setup(vmf, global_seed, tiles) class Generator(abc.ABC): @@ -661,7 +661,7 @@ def get(self, loc: Vec, tex_name: str) -> str: except KeyError as exc: raise self._missing_error(repr(exc.args[0])) - def setup(self, global_seed: str, tiles: List['TileDef']): + def setup(self, vmf: VMF, global_seed: str, tiles: List['TileDef']) -> None: """Scan tiles in the map and setup the generator.""" def _missing_error(self, tex_name: str): @@ -736,7 +736,7 @@ def __init__(self, *args, **kwargs) -> None: self.gen_seed = 0 self._clump_locs = [] # type: List[Clump] - def setup(self, global_seed: str, tiles: List['TileDef']): + def setup(self, vmf: VMF, global_seed: str, tiles: List['TileDef']) -> None: """Build the list of clump locations.""" assert self.portal is not None assert self.orient is not None @@ -772,8 +772,7 @@ def setup(self, global_seed: str, tiles: List['TileDef']): # For debugging, generate skip brushes with the shape of the clumps. debug_visgroup: Optional[VisGroup] if self.options['clump_debug']: - import vbsp - debug_visgroup = vbsp.VMF.create_visgroup( + debug_visgroup = vmf.create_visgroup( f'{self.category.name}_{self.orient.name}_{self.portal.name}' ) else: @@ -815,14 +814,14 @@ def setup(self, global_seed: str, tiles: List['TileDef']): )) if debug_visgroup is not None: # noinspection PyUnboundLocalVariable - debug_brush: Solid = vbsp.VMF.make_prism( + debug_brush: Solid = vmf.make_prism( pos_min - 64, pos_max + 64, 'tools/toolsskip', ).solid debug_brush.visgroup_ids.add(debug_visgroup.id) debug_brush.vis_shown = False - vbsp.VMF.add_brush(debug_brush) + vmf.add_brush(debug_brush) LOGGER.info( '{}.{}.{}: {} Clumps for {} tiles', diff --git a/src/precomp/tiling.py b/src/precomp/tiling.py index 134573747..4a9accb5c 100644 --- a/src/precomp/tiling.py +++ b/src/precomp/tiling.py @@ -603,6 +603,7 @@ def export( if self.template: template = template_brush.import_template( + vmf, self.template, # Don't offset these at all. Assume the user knows # where it should go. diff --git a/src/vbsp.py b/src/vbsp.py index c3736125d..c44e55048 100644 --- a/src/vbsp.py +++ b/src/vbsp.py @@ -12,7 +12,7 @@ from io import StringIO from collections import defaultdict, namedtuple, Counter -from srctools import Property, Vec, AtomicWriter +from srctools import Property, Vec, AtomicWriter, Vec_tuple from srctools.vmf import VMF, Entity, Output from BEE2_config import ConfigFile import utils @@ -39,7 +39,8 @@ ) import consts -from typing import Any, Dict, Tuple, List, Set +from typing import Any, Dict, Tuple, List, Set, Iterable + COND_MOD_NAME = 'VBSP' @@ -218,16 +219,15 @@ def load_settings() -> Tuple[antlines.AntType, antlines.AntType]: return ant_floor, ant_wall -def load_map(map_path) -> VMF: +def load_map(map_path: str) -> VMF: """Load in the VMF file.""" - global VMF with open(map_path) as file: LOGGER.info("Parsing Map...") props = Property.parse(file, map_path) LOGGER.info('Reading Map...') - VMF = VMF.parse(props) + vmf = VMF.parse(props) LOGGER.info("Loading complete!") - return VMF + return vmf @conditions.meta_cond(priority=100) @@ -1072,7 +1072,7 @@ def mod_entryexit( pretty_name, index + 1, ) - return index + return str(index) else: LOGGER.info( 'Setting {} to {}', @@ -1131,23 +1131,22 @@ def calc_rand_seed(vmf: VMF) -> str: return '|'.join(lst) -def add_goo_mist(sides): +def add_goo_mist(vmf, sides: Iterable[Vec_tuple]): """Add water_mist* particle systems to goo. This uses larger particles when needed to save ents. """ needs_mist = set(sides) # Locations that still need mist - sides = sorted(sides) + ordered_sides = sorted(sides) fit_goo_mist( - sides, needs_mist, + vmf, ordered_sides, needs_mist, grid_x=1024, grid_y=512, particle='water_mist_1024_512', - angles='0 0 0', ) fit_goo_mist( - sides, needs_mist, + vmf, ordered_sides, needs_mist, grid_x=512, grid_y=1024, particle='water_mist_1024_512', @@ -1155,14 +1154,14 @@ def add_goo_mist(sides): ) fit_goo_mist( - sides, needs_mist, + vmf, ordered_sides, needs_mist, grid_x=512, grid_y=512, particle='water_mist_512', ) fit_goo_mist( - sides, needs_mist, + vmf, sides, needs_mist, grid_x=256, grid_y=256, particle='water_mist_256', @@ -1170,7 +1169,7 @@ def add_goo_mist(sides): # There isn't a 128 particle so use 256 centered fit_goo_mist( - sides, needs_mist, + vmf, ordered_sides, needs_mist, grid_x=128, grid_y=128, particle='water_mist_256', @@ -1178,13 +1177,14 @@ def add_goo_mist(sides): def fit_goo_mist( - sides, - needs_mist, - grid_x: int, - grid_y: int, - particle, - angles='0 0 0', - ): + vmf: VMF, + sides: Iterable[Vec_tuple], + needs_mist: Set[Vec_tuple], + grid_x: int, + grid_y: int, + particle: str, + angles: str = '0 0 0', +) -> None: """Try to add particles of the given size. needs_mist is a set of all added sides, so we don't double-up on a space. @@ -1198,7 +1198,7 @@ def fit_goo_mist( if (pos.x+x, pos.y+y, pos.z) not in needs_mist: break # Doesn't match else: - VMF.create_ent( + vmf.create_ent( classname='info_particle_system', targetname='@goo_mist', start_active='1', @@ -1221,8 +1221,7 @@ def set_barrier_frame_type(vmf: VMF) -> None: This allows using different instances on glass and grating. """ barrier_types = {} # origin, normal -> 'glass' / 'grating' - - barrier_pos = [] # type: List[Tuple[Vec, str]] + barrier_pos: List[Tuple[Vec, str]] = [] # Find glass and grating brushes.. for brush in vmf.iter_wbrushes(world=False, detail=True): @@ -1268,7 +1267,7 @@ def set_barrier_frame_type(vmf: VMF) -> None: pass -def change_brush() -> None: +def change_brush(vmf: VMF) -> None: """Alter all world/detail brush textures to use the configured ones.""" LOGGER.info("Editing Brushes...") @@ -1303,7 +1302,7 @@ def change_brush() -> None: LOGGER.info('Goo heights: {} <- {}', best_goo, goo_heights) - for solid in VMF.iter_wbrushes(world=True, detail=True): + for solid in vmf.iter_wbrushes(world=True, detail=True): for face in solid: highest_brush = max( highest_brush, @@ -1331,12 +1330,12 @@ def change_brush() -> None: if make_bottomless: LOGGER.info('Creating Bottomless Pits...') - bottomlessPit.make_bottomless_pit(VMF, highest_brush) + bottomlessPit.make_bottomless_pit(vmf, highest_brush) LOGGER.info('Done!') if make_goo_mist: LOGGER.info('Adding Goo Mist...') - add_goo_mist(mist_solids) + add_goo_mist(vmf, mist_solids) LOGGER.info('Done!') @@ -2045,7 +2044,7 @@ def main() -> None: del side_to_antline - texturing.setup(MAP_RAND_SEED, list(tiling.TILES.values())) + texturing.setup(vmf, MAP_RAND_SEED, list(tiling.TILES.values())) conditions.check_all(vmf) add_extra_ents(vmf, GAME_MODE) From 04a2a2601757807006f3816931eac11421949267 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 22 Jul 2020 16:26:50 +1000 Subject: [PATCH 17/87] Make TEMPLATES private --- src/precomp/template_brush.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/precomp/template_brush.py b/src/precomp/template_brush.py index a11737079..1afb139e5 100644 --- a/src/precomp/template_brush.py +++ b/src/precomp/template_brush.py @@ -27,7 +27,7 @@ LOGGER = srctools.logger.get_logger(__name__, alias='template') # A lookup for templates. -TEMPLATES = {} # type: Dict[str, Union[Template, ScalingTemplate]] +_TEMPLATES = {} # type: Dict[str, Union[Template, ScalingTemplate]] # The location of the template data. TEMPLATE_LOCATION = 'bee2/templates.vmf' @@ -35,7 +35,7 @@ class InvalidTemplateName(LookupError): """Raised if a template ID is invalid.""" - def __init__(self, temp_name): + def __init__(self, temp_name: str) -> None: self.temp_name = temp_name def __str__(self): @@ -45,7 +45,7 @@ def __str__(self): '\n'.join( (' * "' + temp.upper() + '"') for temp in - sorted(TEMPLATES.keys()) + sorted(_TEMPLATES.keys()) ), ) @@ -452,7 +452,7 @@ def make_subdict() -> Dict[str, list]: for ent in vmf.by_class['bee2_template_scaling']: temp = ScalingTemplate.parse(ent) - TEMPLATES[temp.id.casefold()] = temp + _TEMPLATES[temp.id.casefold()] = temp for ent in vmf.by_class['bee2_template_colorpicker']: # Parse the colorpicker data. @@ -540,7 +540,7 @@ def make_subdict() -> Dict[str, list]: overlay_faces = conf['overlay_faces'].split() skip_faces = conf['skip_faces'].split() - TEMPLATES[temp_id.casefold()] = Template( + _TEMPLATES[temp_id.casefold()] = Template( temp_id, world_ents[temp_id], detail_ents[temp_id], @@ -554,10 +554,10 @@ def make_subdict() -> Dict[str, list]: ) -def get_template(temp_name) -> Template: +def get_template(temp_name: str) -> Template: """Get the data associated with a given template.""" try: - temp = TEMPLATES[temp_name.casefold()] + temp = _TEMPLATES[temp_name.casefold()] except KeyError: raise InvalidTemplateName(temp_name) from None @@ -732,7 +732,7 @@ def get_scaling_template(temp_id: str) -> ScalingTemplate: temp_name, over_names = parse_temp_name(temp_id) try: - temp = TEMPLATES[temp_name.casefold()] + temp = _TEMPLATES[temp_name.casefold()] except KeyError: raise InvalidTemplateName(temp_name) from None From 8b00911fdc62a2a3cd7c84457b2a8157899f5f53 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 22 Jul 2020 18:22:02 +1000 Subject: [PATCH 18/87] Move VRAD music into postcompiler package --- src/postcomp/__init__.py | 0 src/postcomp/music.py | 335 ++++++++++++++++++++++++++++++++++++ src/vrad.py | 358 +-------------------------------------- 3 files changed, 344 insertions(+), 349 deletions(-) create mode 100644 src/postcomp/__init__.py create mode 100644 src/postcomp/music.py diff --git a/src/postcomp/__init__.py b/src/postcomp/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/postcomp/music.py b/src/postcomp/music.py new file mode 100644 index 000000000..48610ece1 --- /dev/null +++ b/src/postcomp/music.py @@ -0,0 +1,335 @@ +"""Generates the soundscript for background music.""" +from typing import Set +from io import StringIO + +from srctools.sndscript import SND_CHARS +from srctools.packlist import PackList +from srctools import Property + + +# The starting section defining the name and volume. +# SNDLVL_NONE means it's infinite range. +MUSIC_START = """\ +"music.BEE2{name}" +{{ +"channel" "CHAN_STATIC" +"soundlevel" "SNDLVL_NONE" +"volume" "{vol}" +""" + +# The basic operator stack for music without any additional tracks. +MUSIC_BASE = """\ +"soundentry_version" "2" +"operator_stacks" +\t{ +\t"update_stack" +\t\t{ +\t\t"import_stack" "update_music_stereo" +\t\t"volume_fade_in" +\t\t\t{ +\t\t\t"input_max" "0.5" +\t\t\t} +\t\t"volume_fade_out" +\t\t\t{ +\t\t\t"input_max" "1.5" +\t\t\t} +""" + +# We need to stop the sub-tracks after the main track stops... +MUSIC_END = """\ +\t\t} +\t"stop_stack" +\t\t{ +\t\t"stop_entry" +\t\t\t{ +\t\t\t"operator" "sys_stop_entries" +\t\t\t"input_max_entries" "0" +\t\t\t"match_entity" "false" +\t\t\t"match_substring" "true" +\t\t\t"match_entry" "music.BEE2_" +\t\t\t} +\t\t} +\t} +} +""" + +# Operator stacks which enable the given gel types. +MUSIC_GEL_BOUNCE_MAIN = """\ + +\t\t"import_stack" "p2_update_music_play_gel" +\t\t"gel_play_entry" +\t\t\t{ +\t\t\t"entry_name" "music.BEE2_gel_bounce" +\t\t\t} +\t\t"gel_stop_entry" +\t\t\t{ +\t\t\t"match_entry" "music.BEE2_gel_bounce" +\t\t\t} +""" + +MUSIC_GEL_SPEED_MAIN = """\ + +\t\t"import_stack" "p2_update_music_play_speed_gel" +\t\t"speed_velocity_trigger" +\t\t\t{ +\t\t\t"input2" "250" +\t\t\t} +\t\t"speed_play_entry" +\t\t\t{ +\t\t\t"entry_name" "music.BEE2_gel_speed" +\t\t\t} +\t\t"speed_stop_entry" +\t\t\t{ +\t\t\t"match_entry" "music.BEE2_gel_speed" +\t\t\t} +""" + +MUSIC_FUNNEL_MAIN = """\ + +\t"import_stack" "p2_update_music_play_tbeam" +\t"play_entry" +\t\t{ +\t\t"entry_name" "music.BEE2_funnel" +\t\t} +\t"stop_entry" +\t\t{ +\t\t"match_entry" "music.BEE2_funnel" +\t\t} +""" + +# The gel operator stack syncronises the music with the base track. +MUSIC_GEL_STACK = """\ + +"soundentry_version" "2" +"operator_stacks" +\t{{ +\t"start_stack" +\t\t{{ +\t\t"import_stack" "start_sync_to_entry" +\t\t"elapsed_time" +\t\t\t{{ +\t\t\t"entry" "music.BEE2" +\t\t\t}} +\t\t"duration_div" +\t\t\t{{ +\t\t\t"input2" "1" +\t\t\t}} +\t\t"div_mult" +\t\t\t{{ +\t\t\t"input1" "1.0" +\t\t\t}} +\t\t}} +\t"update_stack" +\t\t{{ +\t\t"import_stack" "update_music_stereo" +\t\t"volume_fade_in" +\t\t\t{{ +\t\t\t"input_max" "{fadein}" +\t\t\t}} +\t\t"volume_fade_out" +\t\t\t{{ +\t\t\t"input_max" "{fadeout}" +\t\t\t}} +\t\t}} +\t}} +}} +""" + +# This funnel stack makes it start randomly offset into the music. +MUSIC_FUNNEL_RAND_STACK = """\ + +"soundentry_version" "2" +"operator_stacks" +\t{ +\t"start_stack" +\t\t{ +\t\t"random_offset" +\t\t\t{ +\t\t\t"operator" "math_random" +\t\t\t"input_min" "0.0" +\t\t\t"input_max" "126" +\t\t\t} +\t\t"negative_delay" +\t\t\t{ +\t\t\t"operator" "math_float" +\t\t\t"apply" "mult" +\t\t\t"input1" "@random_offset.output" +\t\t\t"input2" "-1.0" +\t\t\t} +\t\t"delay_output" +\t\t\t{ +\t\t\t"operator" "sys_output" +\t\t\t"input_float" "@negative_delay.output" +\t\t\t"output" "delay" +\t\t\t} +\t\t} +""" + +# This funnel stack makes it synchronise with the main track. +MUSIC_FUNNEL_SYNC_STACK = """\ + +"soundentry_version" "2" +"operator_stacks" +\t{ +\t"start_stack" +\t\t{ +\t\t"import_stack" "start_sync_to_entry" +\t\t"elapsed_time" +\t\t\t{ +\t\t\t"entry" "music.BEE2" +\t\t\t} +\t\t"duration_div" +\t\t\t{ +\t\t\t"input2" "1" +\t\t\t} +\t\t"div_mult" +\t\t\t{ +\t\t\t"input1" "1.0" +\t\t\t} +\t\t} +""" + +# Both funnel versions share the same update stack. +MUSIC_FUNNEL_UPDATE_STACK = """\ +\t"update_stack" +\t\t{ +\t\t"import_stack" "update_music_stereo" +\t\t"mixer" +\t\t\t{ +\t\t\t"mixgroup" "unduckedMusic" +\t\t\t} +\t\t"volume_fade_in" +\t\t\t{ +\t\t\t"input_max" "3.0" +\t\t\t"input_map_min" "0.05" +\t\t\t} +\t\t"volume_fade_out" +\t\t\t{ +\t\t\t"input_max" "0.75" +\t\t\t"input_map_min" "0.05" +\t\t\t} +\t\t"volume_lfo_time_scale" +\t\t\t{ +\t\t\t"input2" "0.3" +\t\t\t} +\t\t"volume_lfo_scale" +\t\t\t{ +\t\t\t"input2" "0.4" +\t\t\t} +\t\t} +\t} +} +""" + +def generate(data: Property, voice_attr: Set[str], pack_list: PackList) -> bytes: + """Generate a soundscript file for music.""" + # We also pack the filenames used for the tracks - that way funnel etc + # only get packed when needed. Stock sounds are in VPKS or in aperturetag/, + # we don't check there. + + funnel = data.find_key('tbeam', '') + bounce = data.find_key('bouncegel', '') + speed = data.find_key('speedgel', '') + + sync_funnel = data.bool('sync_funnel') + + if 'base' not in data: + base = Property('base', 'bee2/silent_lp.wav') + # Don't sync to a 2-second sound. + sync_funnel = False + else: + base = data.find_key('base') + + # The sounds must be present, and the items should be in the map. + has_funnel = funnel.value and ( + 'funnel' in voice_attr or + 'excursionfunnel' in voice_attr + ) + has_bounce = bounce.value and ( + 'bouncegel' in voice_attr or + 'bluegel' in voice_attr + ) + # Speed-gel sounds also play when flinging, so keep it always. + + file = StringIO() + + # Write the base music track + file.write(MUSIC_START.format(name='', vol='1')) + write_sound(file, base, pack_list, snd_prefix='#*') + file.write(MUSIC_BASE) + # The 'soundoperators' section is still open now. + + # Add the operators to play the auxilluary sounds.. + if has_funnel: + file.write(MUSIC_FUNNEL_MAIN) + if has_bounce: + file.write(MUSIC_GEL_BOUNCE_MAIN) + if speed.value: + file.write(MUSIC_GEL_SPEED_MAIN) + + # End the main sound block + file.write(MUSIC_END) + + if has_funnel: + # Write the 'music.BEE2_funnel' sound entry + file.write('\n') + file.write(MUSIC_START.format(name='_funnel', vol='1')) + write_sound(file, funnel, pack_list, snd_prefix='*') + # Some tracks want the funnel music to sync with the normal + # track, others randomly choose a start. + file.write( + MUSIC_FUNNEL_SYNC_STACK + if sync_funnel else + MUSIC_FUNNEL_RAND_STACK + ) + file.write(MUSIC_FUNNEL_UPDATE_STACK) + + if has_bounce: + file.write('\n') + file.write(MUSIC_START.format(name='_gel_bounce', vol='0.5')) + write_sound(file, bounce, pack_list, snd_prefix='*') + # Fade in fast (we never get false positives, but fade out slow + # since this disables when falling back.. + file.write(MUSIC_GEL_STACK.format(fadein=0.25, fadeout=1.5)) + + if speed.value: + file.write('\n') + file.write(MUSIC_START.format(name='_gel_speed', vol='0.5')) + write_sound(file, speed, pack_list, snd_prefix='*') + # We need to shut off the sound fast, so portals don't confuse it. + # Fade in slow so it doesn't make much sound (and also as we get + # up to speed). We stop almost immediately on gel too. + file.write(MUSIC_GEL_STACK.format(fadein=0.5, fadeout=0.1)) + + return file.getvalue().encode() + + +def write_sound( + file: StringIO, + snds: Property, + pack_list: PackList, + snd_prefix: str='*', +) -> None: + """Write either a single sound, or multiple rndsound. + + snd_prefix is the prefix for each filename - *, #, @, etc. + """ + if snds.has_children(): + file.write('"rndwave"\n\t{\n') + for snd in snds: + file.write( + '\t"wave" "{sndchar}{file}"\n'.format( + file=snd.value.lstrip(SND_CHARS), + sndchar=snd_prefix, + ) + ) + pack_list.pack_file('sound/' + snd.value.casefold()) + file.write('\t}\n') + else: + file.write( + '"wave" "{sndchar}{file}"\n'.format( + file=snds.value.lstrip(SND_CHARS), + sndchar=snd_prefix, + ) + ) + pack_list.pack_file('sound/' + snds.value.casefold()) diff --git a/src/vrad.py b/src/vrad.py index fcf5fdbef..d9dcc9efb 100644 --- a/src/vrad.py +++ b/src/vrad.py @@ -31,6 +31,8 @@ trans as register_transform, ) +from postcomp import music + CONF = Property('Config', []) SCREENSHOT_DIR = os.path.join( @@ -48,248 +50,21 @@ utils.STEAM_IDS['DEST_AP']: 'portal2', } -SOUND_MAN_FOLDER = { - # The folder where game_sounds_manifest is found - utils.STEAM_IDS['PORTAL2']: 'portal2_dlc2', - utils.STEAM_IDS['DEST_AP']: 'portal2_dlc2', - utils.STEAM_IDS['TWTM']: 'twtm', - utils.STEAM_IDS['APTAG']: 'aperturetag', -} - -# Various parts of the soundscript generated for BG music. - -# Things that can appear at the beginning of filenames.. -SOUND_CHARS = '*#@><^)}$!?' - -# The starting section defining the name and volume. -# SNDLVL_NONE means it's infinite range. -MUSIC_START = """\ -"music.BEE2{name}" -{{ -"channel" "CHAN_STATIC" -"soundlevel" "SNDLVL_NONE" -"volume" "{vol}" -""" - -# The basic operator stack for music without any additional tracks. -MUSIC_BASE = """\ -"soundentry_version" "2" -"operator_stacks" -\t{ -\t"update_stack" -\t\t{ -\t\t"import_stack" "update_music_stereo" -\t\t"volume_fade_in" -\t\t\t{ -\t\t\t"input_max" "0.5" -\t\t\t} -\t\t"volume_fade_out" -\t\t\t{ -\t\t\t"input_max" "1.5" -\t\t\t} -""" - -# We need to stop the sub-tracks after the main track stops... -MUSIC_END = """\ -\t\t} -\t"stop_stack" -\t\t{ -\t\t"stop_entry" -\t\t\t{ -\t\t\t"operator" "sys_stop_entries" -\t\t\t"input_max_entries" "0" -\t\t\t"match_entity" "false" -\t\t\t"match_substring" "true" -\t\t\t"match_entry" "music.BEE2_" -\t\t\t} -\t\t} -\t} -} -""" - -# Operator stacks which enable the given gel types. -MUSIC_GEL_BOUNCE_MAIN = """\ - -\t\t"import_stack" "p2_update_music_play_gel" -\t\t"gel_play_entry" -\t\t\t{ -\t\t\t"entry_name" "music.BEE2_gel_bounce" -\t\t\t} -\t\t"gel_stop_entry" -\t\t\t{ -\t\t\t"match_entry" "music.BEE2_gel_bounce" -\t\t\t} -""" - -MUSIC_GEL_SPEED_MAIN = """\ - -\t\t"import_stack" "p2_update_music_play_speed_gel" -\t\t"speed_velocity_trigger" -\t\t\t{ -\t\t\t"input2" "250" -\t\t\t} -\t\t"speed_play_entry" -\t\t\t{ -\t\t\t"entry_name" "music.BEE2_gel_speed" -\t\t\t} -\t\t"speed_stop_entry" -\t\t\t{ -\t\t\t"match_entry" "music.BEE2_gel_speed" -\t\t\t} -""" - -MUSIC_FUNNEL_MAIN = """\ - -\t"import_stack" "p2_update_music_play_tbeam" -\t"play_entry" -\t\t{ -\t\t"entry_name" "music.BEE2_funnel" -\t\t} -\t"stop_entry" -\t\t{ -\t\t"match_entry" "music.BEE2_funnel" -\t\t} -""" - -# The gel operator stack syncronises the music with the base track. -MUSIC_GEL_STACK = """\ - -"soundentry_version" "2" -"operator_stacks" -\t{{ -\t"start_stack" -\t\t{{ -\t\t"import_stack" "start_sync_to_entry" -\t\t"elapsed_time" -\t\t\t{{ -\t\t\t"entry" "music.BEE2" -\t\t\t}} -\t\t"duration_div" -\t\t\t{{ -\t\t\t"input2" "1" -\t\t\t}} -\t\t"div_mult" -\t\t\t{{ -\t\t\t"input1" "1.0" -\t\t\t}} -\t\t}} -\t"update_stack" -\t\t{{ -\t\t"import_stack" "update_music_stereo" -\t\t"volume_fade_in" -\t\t\t{{ -\t\t\t"input_max" "{fadein}" -\t\t\t}} -\t\t"volume_fade_out" -\t\t\t{{ -\t\t\t"input_max" "{fadeout}" -\t\t\t}} -\t\t}} -\t}} -}} -""" - -# This funnel stack makes it start randomly offset into the music. -MUSIC_FUNNEL_RAND_STACK = """\ - -"soundentry_version" "2" -"operator_stacks" -\t{ -\t"start_stack" -\t\t{ -\t\t"random_offset" -\t\t\t{ -\t\t\t"operator" "math_random" -\t\t\t"input_min" "0.0" -\t\t\t"input_max" "126" -\t\t\t} -\t\t"negative_delay" -\t\t\t{ -\t\t\t"operator" "math_float" -\t\t\t"apply" "mult" -\t\t\t"input1" "@random_offset.output" -\t\t\t"input2" "-1.0" -\t\t\t} -\t\t"delay_output" -\t\t\t{ -\t\t\t"operator" "sys_output" -\t\t\t"input_float" "@negative_delay.output" -\t\t\t"output" "delay" -\t\t\t} -\t\t} -""" - -# This funnel stack makes it synchronise with the main track. -MUSIC_FUNNEL_SYNC_STACK = """\ - -"soundentry_version" "2" -"operator_stacks" -\t{ -\t"start_stack" -\t\t{ -\t\t"import_stack" "start_sync_to_entry" -\t\t"elapsed_time" -\t\t\t{ -\t\t\t"entry" "music.BEE2" -\t\t\t} -\t\t"duration_div" -\t\t\t{ -\t\t\t"input2" "1" -\t\t\t} -\t\t"div_mult" -\t\t\t{ -\t\t\t"input1" "1.0" -\t\t\t} -\t\t} -""" -# Both funnel versions share the same update stack. -MUSIC_FUNNEL_UPDATE_STACK = """\ -\t"update_stack" -\t\t{ -\t\t"import_stack" "update_music_stereo" -\t\t"mixer" -\t\t\t{ -\t\t\t"mixgroup" "unduckedMusic" -\t\t\t} -\t\t"volume_fade_in" -\t\t\t{ -\t\t\t"input_max" "3.0" -\t\t\t"input_map_min" "0.05" -\t\t\t} -\t\t"volume_fade_out" -\t\t\t{ -\t\t\t"input_max" "0.75" -\t\t\t"input_map_min" "0.05" -\t\t\t} -\t\t"volume_lfo_time_scale" -\t\t\t{ -\t\t\t"input2" "0.3" -\t\t\t} -\t\t"volume_lfo_scale" -\t\t\t{ -\t\t\t"input2" "0.4" -\t\t\t} -\t\t} -\t} -} -""" - - -def load_config(): +def load_config() -> None: global CONF LOGGER.info('Loading Settings...') try: with open("bee2/vrad_config.cfg", encoding='utf8') as config: - CONF = Property.parse(config, 'bee2/vrad_config.cfg').find_key( + CONF.append(Property.parse(config, 'bee2/vrad_config.cfg').find_key( 'Config', [] - ) + )) except FileNotFoundError: pass LOGGER.info('Config Loaded!') -def dump_files(bsp: BSP): +def dump_files(bsp: BSP) -> None: """Dump packed files to a location. """ dump_folder = CONF['packfile_dump', ''] @@ -353,123 +128,6 @@ def generate_coop_responses(ctx: TransContext) -> None: if ent is None: LOGGER.warning('Response scripts present, but @glados is not!') - -def generate_music_script(data: Property, pack_list: PackList) -> bytes: - """Generate a soundscript file for music.""" - # We also pack the filenames used for the tracks - that way funnel etc - # only get packed when needed. Stock sounds are in VPKS or in aperturetag/, - # we don't check there. - # The voice attrs used in the map - we can skip tracks - voice_attr = CONF['VoiceAttr', ''].casefold().split(';') - - funnel = data.find_key('tbeam', '') - bounce = data.find_key('bouncegel', '') - speed = data.find_key('speedgel', '') - - sync_funnel = data.bool('sync_funnel') - - if 'base' not in data: - base = Property('base', 'bee2/silent_lp.wav') - # Don't sync to a 2-second sound. - sync_funnel = False - else: - base = data.find_key('base') - - # The sounds must be present, and the items should be in the map. - has_funnel = funnel.value and ( - 'funnel' in voice_attr or - 'excursionfunnel' in voice_attr - ) - has_bounce = bounce.value and ( - 'bouncegel' in voice_attr or - 'bluegel' in voice_attr - ) - # Speed-gel sounds also play when flinging, so keep it always. - - file = StringIO() - - # Write the base music track - file.write(MUSIC_START.format(name='', vol='1')) - write_sound(file, base, pack_list, snd_prefix='#*') - file.write(MUSIC_BASE) - # The 'soundoperators' section is still open now. - - # Add the operators to play the auxilluary sounds.. - if has_funnel: - file.write(MUSIC_FUNNEL_MAIN) - if has_bounce: - file.write(MUSIC_GEL_BOUNCE_MAIN) - if speed.value: - file.write(MUSIC_GEL_SPEED_MAIN) - - # End the main sound block - file.write(MUSIC_END) - - if has_funnel: - # Write the 'music.BEE2_funnel' sound entry - file.write('\n') - file.write(MUSIC_START.format(name='_funnel', vol='1')) - write_sound(file, funnel, pack_list, snd_prefix='*') - # Some tracks want the funnel music to sync with the normal - # track, others randomly choose a start. - file.write( - MUSIC_FUNNEL_SYNC_STACK - if sync_funnel else - MUSIC_FUNNEL_RAND_STACK - ) - file.write(MUSIC_FUNNEL_UPDATE_STACK) - - if has_bounce: - file.write('\n') - file.write(MUSIC_START.format(name='_gel_bounce', vol='0.5')) - write_sound(file, bounce, pack_list, snd_prefix='*') - # Fade in fast (we never get false positives, but fade out slow - # since this disables when falling back.. - file.write(MUSIC_GEL_STACK.format(fadein=0.25, fadeout=1.5)) - - if speed.value: - file.write('\n') - file.write(MUSIC_START.format(name='_gel_speed', vol='0.5')) - write_sound(file, speed, pack_list, snd_prefix='*') - # We need to shut off the sound fast, so portals don't confuse it. - # Fade in slow so it doesn't make much sound (and also as we get - # up to speed). We stop almost immediately on gel too. - file.write(MUSIC_GEL_STACK.format(fadein=0.5, fadeout=0.1)) - - return file.getvalue().encode() - - -def write_sound( - file: StringIO, - snds: Property, - pack_list: PackList, - snd_prefix: str='*', -) -> None: - """Write either a single sound, or multiple rndsound. - - snd_prefix is the prefix for each filename - *, #, @, etc. - """ - if snds.has_children(): - file.write('"rndwave"\n\t{\n') - for snd in snds: - file.write( - '\t"wave" "{sndchar}{file}"\n'.format( - file=snd.value.lstrip(SOUND_CHARS), - sndchar=snd_prefix, - ) - ) - pack_list.pack_file('sound/' + snd.value.casefold()) - file.write('\t}\n') - else: - file.write( - '"wave" "{sndchar}{file}"\n'.format( - file=snds.value.lstrip(SOUND_CHARS), - sndchar=snd_prefix, - ) - ) - pack_list.pack_file('sound/' + snds.value.casefold()) - - def inject_files() -> Iterator[Tuple[str, str]]: """Generate the names of files to inject, if they exist..""" # Additionally add files set in the config. @@ -750,12 +408,14 @@ def main(argv: List[str]) -> None: if is_peti: LOGGER.info('Adding special packed files:') + voice_attr = set(CONF['VoiceAttr', ''].casefold().split(';')) + music_data = CONF.find_key('MusicScript', []) if music_data: packlist.pack_file( 'scripts/BEE2_generated_music.txt', PackType.SOUNDSCRIPT, - data=generate_music_script(music_data, packlist) + data=music.generate(music_data, voice_attr, packlist) ) for filename, arcname in inject_files(): From d6233396677f780c4414e14f890438336b8c8397 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 22 Jul 2020 18:26:03 +1000 Subject: [PATCH 19/87] Move screenshot code into its own module --- src/postcomp/screenshot.py | 146 +++++++++++++++++++++++++++++++++++++ src/vrad.py | 141 +---------------------------------- 2 files changed, 149 insertions(+), 138 deletions(-) create mode 100644 src/postcomp/screenshot.py diff --git a/src/postcomp/screenshot.py b/src/postcomp/screenshot.py new file mode 100644 index 000000000..429aab955 --- /dev/null +++ b/src/postcomp/screenshot.py @@ -0,0 +1,146 @@ +"""Handles modification of the editor screenshot.""" +import os +import shutil +from datetime import datetime +from typing import Iterator + +import srctools.logger +import utils +from srctools import Property + + +LOGGER = srctools.logger.get_logger(__name__) + +SCREENSHOT_DIR = os.path.join( + '..', + 'portal2', # This is hardcoded into P2, it won't change for mods. + 'puzzles', + # Then the folder +) + + +GAME_FOLDER = { + # The game's root folder, where screenshots are saved + utils.STEAM_IDS['PORTAL2']: 'portal2', + utils.STEAM_IDS['TWTM']: 'twtm', + utils.STEAM_IDS['APTAG']: 'aperturetag', + utils.STEAM_IDS['DEST_AP']: 'portal2', +} + + +def find() -> Iterator[str]: + """Find candidate screenshots to overwrite.""" + # Inside SCREENSHOT_DIR, there should be 1 folder with a + # random name which contains the user's puzzles. Just + # attempt to modify a screenshot in each of the directories + # in the folder. + for folder in os.listdir(SCREENSHOT_DIR): + full_path = os.path.join(SCREENSHOT_DIR, folder) + if os.path.isdir(full_path): + # The screenshot to modify is untitled.jpg + screenshot = os.path.join(full_path, 'untitled.jpg') + if os.path.isfile(screenshot): + yield screenshot + + +def modify(conf: Property) -> None: + """Modify the map's screenshot.""" + mod_type = conf['screenshot_type', 'PETI'].lower() + + if mod_type == 'cust': + LOGGER.info('Using custom screenshot!') + scr_loc = str(utils.conf_location('screenshot.jpg')) + elif mod_type == 'auto': + LOGGER.info('Using automatic screenshot!') + scr_loc = None + # The automatic screenshots are found at this location: + auto_path = os.path.join( + '..', + GAME_FOLDER.get(conf['game_id', ''], 'portal2'), + 'screenshots' + ) + # We need to find the most recent one. If it's named + # "previewcomplete", we want to ignore it - it's a flag + # to indicate the map was playtested correctly. + try: + screens = [ + os.path.join(auto_path, path) + for path in + os.listdir(auto_path) + ] + except FileNotFoundError: + # The screenshot folder doesn't exist! + screens = [] + screens.sort( + key=os.path.getmtime, + reverse=True, + # Go from most recent to least + ) + playtested = False + for scr_shot in screens: + filename = os.path.basename(scr_shot) + if filename.startswith('bee2_playtest_flag'): + # Previewcomplete is a flag to indicate the map's + # been playtested. It must be newer than the screenshot + playtested = True + continue + elif filename.startswith('bee2_screenshot'): + continue # Ignore other screenshots + + # We have a screenshot. Check to see if it's + # not too old. (Old is > 2 hours) + date = datetime.fromtimestamp( + os.path.getmtime(scr_shot) + ) + diff = datetime.now() - date + if diff.total_seconds() > 2 * 3600: + LOGGER.info( + 'Screenshot "{scr}" too old ({diff!s})', + scr=scr_shot, + diff=diff, + ) + continue + + # If we got here, it's a good screenshot! + LOGGER.info('Chosen "{}"', scr_shot) + LOGGER.info('Map Playtested: {}', playtested) + scr_loc = scr_shot + break + else: + # If we get to the end, we failed to find an automatic + # screenshot! + LOGGER.info('No Auto Screenshot found!') + mod_type = 'peti' # Suppress the "None not found" error + + if srctools.conv_bool(conf['clean_screenshots', '0']): + LOGGER.info('Cleaning up screenshots...') + # Clean up this folder - otherwise users will get thousands of + # pics in there! + for screen in screens: + if screen != scr_loc and os.path.isfile(screen): + os.remove(screen) + LOGGER.info('Done!') + else: + # PeTI type, or something else + scr_loc = None + + if scr_loc is not None and os.path.isfile(scr_loc): + # We should use a screenshot! + for screen in find(): + LOGGER.info('Replacing "{}"...', screen) + # Allow us to edit the file... + utils.unset_readonly(screen) + shutil.copy(scr_loc, screen) + # Make the screenshot readonly, so P2 can't replace it. + # Then it'll use our own + utils.set_readonly(screen) + + else: + if mod_type != 'peti': + # Error if we were looking for a screenshot + LOGGER.warning('"{}" not found!', scr_loc) + LOGGER.info('Using PeTI screenshot!') + for screen in find(): + # Make the screenshot writeable, so P2 will replace it + LOGGER.info('Making "{}" replaceable...', screen) + utils.unset_readonly(screen) diff --git a/src/vrad.py b/src/vrad.py index d9dcc9efb..89a75fbf2 100644 --- a/src/vrad.py +++ b/src/vrad.py @@ -10,13 +10,11 @@ import os import shutil import sys -from datetime import datetime -from io import BytesIO, StringIO +from io import BytesIO from zipfile import ZipFile from typing import Iterator, List, Tuple, Set, Dict, Optional import srctools.run -import utils from srctools import Property, Entity from srctools.bsp import BSP, BSP_LUMPS from srctools.filesys import ( @@ -31,25 +29,10 @@ trans as register_transform, ) -from postcomp import music +from postcomp import music, screenshot CONF = Property('Config', []) -SCREENSHOT_DIR = os.path.join( - '..', - 'portal2', # This is hardcoded into P2, it won't change for mods. - 'puzzles', - # Then the folder -) - -GAME_FOLDER = { - # The game's root folder, where screenshots are saved - utils.STEAM_IDS['PORTAL2']: 'portal2', - utils.STEAM_IDS['TWTM']: 'twtm', - utils.STEAM_IDS['APTAG']: 'aperturetag', - utils.STEAM_IDS['DEST_AP']: 'portal2', -} - def load_config() -> None: global CONF @@ -137,124 +120,6 @@ def inject_files() -> Iterator[Tuple[str, str]]: yield filename, prop.value -def find_screenshots() -> Iterator[str]: - """Find candidate screenshots to overwrite.""" - # Inside SCREENSHOT_DIR, there should be 1 folder with a - # random name which contains the user's puzzles. Just - # attempt to modify a screenshot in each of the directories - # in the folder. - for folder in os.listdir(SCREENSHOT_DIR): - full_path = os.path.join(SCREENSHOT_DIR, folder) - if os.path.isdir(full_path): - # The screenshot to modify is untitled.jpg - screenshot = os.path.join(full_path, 'untitled.jpg') - if os.path.isfile(screenshot): - yield screenshot - - -def mod_screenshots() -> None: - """Modify the map's screenshot.""" - mod_type = CONF['screenshot_type', 'PETI'].lower() - - if mod_type == 'cust': - LOGGER.info('Using custom screenshot!') - scr_loc = str(utils.conf_location('screenshot.jpg')) - elif mod_type == 'auto': - LOGGER.info('Using automatic screenshot!') - scr_loc = None - # The automatic screenshots are found at this location: - auto_path = os.path.join( - '..', - GAME_FOLDER.get(CONF['game_id', ''], 'portal2'), - 'screenshots' - ) - # We need to find the most recent one. If it's named - # "previewcomplete", we want to ignore it - it's a flag - # to indicate the map was playtested correctly. - try: - screens = [ - os.path.join(auto_path, path) - for path in - os.listdir(auto_path) - ] - except FileNotFoundError: - # The screenshot folder doesn't exist! - screens = [] - screens.sort( - key=os.path.getmtime, - reverse=True, - # Go from most recent to least - ) - playtested = False - for scr_shot in screens: - filename = os.path.basename(scr_shot) - if filename.startswith('bee2_playtest_flag'): - # Previewcomplete is a flag to indicate the map's - # been playtested. It must be newer than the screenshot - playtested = True - continue - elif filename.startswith('bee2_screenshot'): - continue # Ignore other screenshots - - # We have a screenshot. Check to see if it's - # not too old. (Old is > 2 hours) - date = datetime.fromtimestamp( - os.path.getmtime(scr_shot) - ) - diff = datetime.now() - date - if diff.total_seconds() > 2 * 3600: - LOGGER.info( - 'Screenshot "{scr}" too old ({diff!s})', - scr=scr_shot, - diff=diff, - ) - continue - - # If we got here, it's a good screenshot! - LOGGER.info('Chosen "{}"', scr_shot) - LOGGER.info('Map Playtested: {}', playtested) - scr_loc = scr_shot - break - else: - # If we get to the end, we failed to find an automatic - # screenshot! - LOGGER.info('No Auto Screenshot found!') - mod_type = 'peti' # Suppress the "None not found" error - - if srctools.conv_bool(CONF['clean_screenshots', '0']): - LOGGER.info('Cleaning up screenshots...') - # Clean up this folder - otherwise users will get thousands of - # pics in there! - for screen in screens: - if screen != scr_loc and os.path.isfile(screen): - os.remove(screen) - LOGGER.info('Done!') - else: - # PeTI type, or something else - scr_loc = None - - if scr_loc is not None and os.path.isfile(scr_loc): - # We should use a screenshot! - for screen in find_screenshots(): - LOGGER.info('Replacing "{}"...', screen) - # Allow us to edit the file... - utils.unset_readonly(screen) - shutil.copy(scr_loc, screen) - # Make the screenshot readonly, so P2 can't replace it. - # Then it'll use our own - utils.set_readonly(screen) - - else: - if mod_type != 'peti': - # Error if we were looking for a screenshot - LOGGER.warning('"{}" not found!', scr_loc) - LOGGER.info('Using PeTI screenshot!') - for screen in find_screenshots(): - # Make the screenshot writeable, so P2 will replace it - LOGGER.info('Making "{}" replaceable...', screen) - utils.unset_readonly(screen) - - def run_vrad(args: List[str]) -> None: """Execute the original VRAD.""" code = srctools.run.run_compiler(os.path.join(os.getcwd(), "vrad"), args) @@ -484,7 +349,7 @@ def main(argv: List[str]) -> None: LOGGER.info(' - BSP written!') if is_peti: - mod_screenshots() + screenshot.modify(CONF) if edit_args: LOGGER.info("Forcing Cheap Lighting!") From cc665141972133fd73d1927f7fb46d9c75199872 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 22 Jul 2020 18:33:42 +1000 Subject: [PATCH 20/87] Inline bits of vrad script, make config non-global --- src/vrad.py | 75 +++++++++++++++++++++++------------------------------ 1 file changed, 33 insertions(+), 42 deletions(-) diff --git a/src/vrad.py b/src/vrad.py index 89a75fbf2..e18f1e181 100644 --- a/src/vrad.py +++ b/src/vrad.py @@ -12,7 +12,7 @@ import sys from io import BytesIO from zipfile import ZipFile -from typing import Iterator, List, Tuple, Set, Dict, Optional +from typing import List, Set, Dict, Optional import srctools.run from srctools import Property, Entity @@ -31,26 +31,10 @@ from postcomp import music, screenshot -CONF = Property('Config', []) - -def load_config() -> None: - global CONF - LOGGER.info('Loading Settings...') - try: - with open("bee2/vrad_config.cfg", encoding='utf8') as config: - CONF.append(Property.parse(config, 'bee2/vrad_config.cfg').find_key( - 'Config', [] - )) - except FileNotFoundError: - pass - LOGGER.info('Config Loaded!') - - -def dump_files(bsp: BSP) -> None: +def dump_files(bsp: BSP, dump_folder: str) -> None: """Dump packed files to a location. """ - dump_folder = CONF['packfile_dump', ''] if not dump_folder: return @@ -111,14 +95,6 @@ def generate_coop_responses(ctx: TransContext) -> None: if ent is None: LOGGER.warning('Response scripts present, but @glados is not!') -def inject_files() -> Iterator[Tuple[str, str]]: - """Generate the names of files to inject, if they exist..""" - # Additionally add files set in the config. - for prop in CONF.find_children('InjectFiles'): - filename = os.path.join('bee2', 'inject', prop.real_name) - if os.path.exists(filename): - yield filename, prop.value - def run_vrad(args: List[str]) -> None: """Execute the original VRAD.""" @@ -131,6 +107,7 @@ def run_vrad(args: List[str]) -> None: def main(argv: List[str]) -> None: + """Main VRAD script.""" LOGGER.info('BEE2 VRAD hook started!') args = " ".join(argv) @@ -156,7 +133,17 @@ def main(argv: List[str]) -> None: LOGGER.info("Map path is " + path) - load_config() + LOGGER.info('Loading Settings...') + try: + with open("bee2/vrad_config.cfg", encoding='utf8') as config: + conf = Property.parse(config, 'bee2/vrad_config.cfg').find_key( + 'Config', [] + ) + except FileNotFoundError: + conf = Property('Config', []) + else: + LOGGER.info('Config Loaded!') + for a in fast_args[:]: folded_a = a.casefold() @@ -193,14 +180,14 @@ def main(argv: List[str]) -> None: raise ValueError('"{}" is not a file!'.format(path)) # If VBSP thinks it's hammer, trust it. - if CONF.bool('is_hammer', False): + if conf.bool('is_hammer', False): is_peti = edit_args = False else: is_peti = True # Detect preview via knowing the bsp name. If we are in preview, # check the config file to see what was specified there. if os.path.basename(path) == "preview.bsp": - edit_args = not CONF.bool('force_full', False) + edit_args = not conf.bool('force_full', False) else: # publishing - always force full lighting. edit_args = False @@ -223,11 +210,11 @@ def main(argv: List[str]) -> None: # Put the Mel and Tag filesystems in so we can pack from there. fsys_tag = fsys_mel = None - if is_peti and 'mel_vpk' in CONF: - fsys_mel = VPKFileSystem(CONF['mel_vpk']) + if is_peti and 'mel_vpk' in conf: + fsys_mel = VPKFileSystem(conf['mel_vpk']) fsys.add_sys(fsys_mel) - if is_peti and 'tag_dir' in CONF: - fsys_tag = RawFileSystem(CONF['tag_dir']) + if is_peti and 'tag_dir' in conf: + fsys_tag = RawFileSystem(conf['tag_dir']) fsys.add_sys(fsys_tag) # Special case - move the BEE2 fsys FIRST, so we always pack files found @@ -265,7 +252,7 @@ def main(argv: List[str]) -> None: str(root_folder / 'bin/bee2/sndscript_cache.vdf') ) - # We nee to add all soundscripts in scripts/bee2_snd/ + # We need to add all soundscripts in scripts/bee2_snd/ # This way we can pack those, if required. for soundscript in fsys.walk_folder('scripts/bee2_snd/'): if soundscript.path.endswith('.txt'): @@ -273,9 +260,9 @@ def main(argv: List[str]) -> None: if is_peti: LOGGER.info('Adding special packed files:') - voice_attr = set(CONF['VoiceAttr', ''].casefold().split(';')) + voice_attr = set(conf['VoiceAttr', ''].casefold().split(';')) - music_data = CONF.find_key('MusicScript', []) + music_data = conf.find_key('MusicScript', []) if music_data: packlist.pack_file( 'scripts/BEE2_generated_music.txt', @@ -283,10 +270,14 @@ def main(argv: List[str]) -> None: data=music.generate(music_data, voice_attr, packlist) ) - for filename, arcname in inject_files(): - LOGGER.info('Injecting "{}" into packfile.', arcname) - with open(filename, 'rb') as f: - packlist.pack_file(arcname, data=f.read()) + for prop in conf.find_children('InjectFiles'): + filename = os.path.join('bee2', 'inject', prop.real_name) + try: + with open(filename, 'rb') as f: + LOGGER.info('Injecting "{}" into packfile.', prop.value) + packlist.pack_file(prop.value, data=f.read()) + except FileNotFoundError: + pass LOGGER.info('Run transformations...') run_transformations(bsp_ents, fsys, packlist, bsp_file, game) @@ -340,7 +331,7 @@ def main(argv: List[str]) -> None: set(zipfile.namelist()) - existing )) - dump_files(bsp_file) + dump_files(bsp_file, conf['packfile_dump', '']) # Copy new entity data. bsp_file.lumps[BSP_LUMPS.ENTITIES].data = BSP.write_ent_data(bsp_ents) @@ -349,7 +340,7 @@ def main(argv: List[str]) -> None: LOGGER.info(' - BSP written!') if is_peti: - screenshot.modify(CONF) + screenshot.modify(conf) if edit_args: LOGGER.info("Forcing Cheap Lighting!") From 73c76799c9608c46d6a186180920cd06a6c256ae Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 22 Jul 2020 18:44:09 +1000 Subject: [PATCH 21/87] Move reading the BSP to much earlier The config will be moving into this as much as possible --- src/vrad.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/vrad.py b/src/vrad.py index e18f1e181..fcf621423 100644 --- a/src/vrad.py +++ b/src/vrad.py @@ -144,7 +144,6 @@ def main(argv: List[str]) -> None: else: LOGGER.info('Config Loaded!') - for a in fast_args[:]: folded_a = a.casefold() if folded_a.casefold() in ( @@ -179,6 +178,11 @@ def main(argv: List[str]) -> None: if not os.path.isfile(path): raise ValueError('"{}" is not a file!'.format(path)) + LOGGER.info('Reading BSP') + bsp_file = BSP(path) + + bsp_ents = bsp_file.read_ent_data() + # If VBSP thinks it's hammer, trust it. if conf.bool('is_hammer', False): is_peti = edit_args = False @@ -224,11 +228,6 @@ def main(argv: List[str]) -> None: fsys.systems.remove(child_sys) fsys.systems.insert(0, child_sys) - LOGGER.info('Reading BSP') - bsp_file = BSP(path) - - bsp_ents = bsp_file.read_ent_data() - zip_data = BytesIO() zip_data.write(bsp_file.get_lump(BSP_LUMPS.PAKFILE)) zipfile = ZipFile(zip_data, mode='a') From a41e2a52a4f924e4afe72ccb8169a3f737724b7b Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 22 Jul 2020 18:47:20 +1000 Subject: [PATCH 22/87] Move coop responses logic to its own module --- src/postcomp/coop_responses.py | 39 ++++++++++++++++++++++++++++ src/vrad.py | 47 ++++++---------------------------- 2 files changed, 47 insertions(+), 39 deletions(-) create mode 100644 src/postcomp/coop_responses.py diff --git a/src/postcomp/coop_responses.py b/src/postcomp/coop_responses.py new file mode 100644 index 000000000..071d92ee0 --- /dev/null +++ b/src/postcomp/coop_responses.py @@ -0,0 +1,39 @@ +from typing import Dict, List, Optional + +from srctools import Entity +from srctools.bsp_transform import Context, trans +import srctools.logger + +LOGGER = srctools.logger.get_logger(__name__) + + +@trans('BEE2: Coop Responses') +def generate_coop_responses(ctx: Context) -> None: + """If the entities are present, add the coop response script.""" + responses: Dict[str, List[str]] = {} + for response in ctx.vmf.by_class['bee2_coop_response']: + responses[response['type']] = [ + value for key, value in response.keys.items() + if key.startswith('choreo') + ] + response.remove() + script = ["BEE2_RESPONSES <- {"] + for response_type, lines in sorted(responses.items()): + script.append(f'\t{response_type} = [') + for line in lines: + script.append(f'\t\tCreateSceneEntity("{line}"),') + script.append('\t],') + script.append('};') + + # We want to write this onto the '@glados' entity. + ent: Optional[Entity] = None + for ent in ctx.vmf.by_target['@glados']: + ctx.add_code(ent, '\n'.join(script)) + # Also include the actual script. + split_script = ent['vscripts'].split() + split_script.append('bee2/coop_responses.nut') + ent['vscripts'] = ' '.join(split_script) + + if ent is None: + LOGGER.warning('Response scripts present, but @glados is not!') + diff --git a/src/vrad.py b/src/vrad.py index fcf621423..3d0120003 100644 --- a/src/vrad.py +++ b/src/vrad.py @@ -12,10 +12,10 @@ import sys from io import BytesIO from zipfile import ZipFile -from typing import List, Set, Dict, Optional +from typing import List, Set import srctools.run -from srctools import Property, Entity +from srctools import Property from srctools.bsp import BSP, BSP_LUMPS from srctools.filesys import ( RawFileSystem, VPKFileSystem, ZipFileSystem, @@ -23,13 +23,13 @@ ) from srctools.packlist import PackList, FileType as PackType, load_fgd from srctools.game import find_gameinfo -from srctools.bsp_transform import ( - run_transformations, - Context as TransContext, - trans as register_transform, -) +from srctools.bsp_transform import run_transformations -from postcomp import music, screenshot +from postcomp import ( + music, + screenshot, + coop_responses, +) def dump_files(bsp: BSP, dump_folder: str) -> None: @@ -65,37 +65,6 @@ def dump_files(bsp: BSP, dump_folder: str) -> None: zipfile.extract(zipinfo, dump_folder) -@register_transform('BEE2: Coop Responses') -def generate_coop_responses(ctx: TransContext) -> None: - """If the entities are present, add the coop response script.""" - responses: Dict[str, List[str]] = {} - for response in ctx.vmf.by_class['bee2_coop_response']: - responses[response['type']] = [ - value for key, value in response.keys.items() - if key.startswith('choreo') - ] - response.remove() - script = ["BEE2_RESPONSES <- {"] - for response_type, lines in sorted(responses.items()): - script.append(f'\t{response_type} = [') - for line in lines: - script.append(f'\t\tCreateSceneEntity("{line}"),') - script.append('\t],') - script.append('};') - - # We want to write this onto the '@glados' entity. - ent: Optional[Entity] = None - for ent in ctx.vmf.by_target['@glados']: - ctx.add_code(ent, '\n'.join(script)) - # Also include the actual script. - split_script = ent['vscripts'].split() - split_script.append('bee2/coop_responses.nut') - ent['vscripts'] = ' '.join(split_script) - - if ent is None: - LOGGER.warning('Response scripts present, but @glados is not!') - - def run_vrad(args: List[str]) -> None: """Execute the original VRAD.""" code = srctools.run.run_compiler(os.path.join(os.getcwd(), "vrad"), args) From 10f5a7214c3778352eb3d5e90e9df7635eb71219 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 22 Jul 2020 20:23:36 +1000 Subject: [PATCH 23/87] Move the MusicChannel enum to the consts module This allows it to be used by the compiler --- src/app/UI.py | 3 ++- src/app/music_conf.py | 3 ++- src/consts.py | 12 ++++++++++-- src/packageLoader.py | 10 +--------- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/app/UI.py b/src/app/UI.py index 0b5874fe7..c412f9fca 100644 --- a/src/app/UI.py +++ b/src/app/UI.py @@ -20,6 +20,7 @@ from app import img from app import itemconfig import utils +import consts from app import ( tk_tools, SubPane, @@ -2044,7 +2045,7 @@ def style_select_callback(style_id: str) -> None: sugg = style_obj.suggested win_types = ( voice_win, - music_conf.WINDOWS[music_conf.MusicChannel.BASE], + music_conf.WINDOWS[consts.MusicChannel.BASE], skybox_win, elev_win, ) diff --git a/src/app/music_conf.py b/src/app/music_conf.py index f64461d3e..77418aa03 100644 --- a/src/app/music_conf.py +++ b/src/app/music_conf.py @@ -4,7 +4,8 @@ from BEE2_config import GEN_OPTS from app.SubPane import SubPane from loadScreen import LoadScreen -from packageLoader import Music, MusicChannel +from packageLoader import Music +from consts import MusicChannel from tkinter import ttk from app.selector_win import Item as SelItem, selWin as SelectorWin, AttrDef as SelAttr from srctools import FileSystemChain, FileSystem diff --git a/src/consts.py b/src/consts.py index 8c4417a51..c96784a08 100644 --- a/src/consts.py +++ b/src/consts.py @@ -6,13 +6,13 @@ __all__ = [ 'MaterialGroup', - 'ItemClass', + 'ItemClass', 'MusicChannel', 'WhitePan', 'BlackPan', 'Signage', 'Antlines', 'Goo', 'Fizzler', 'Special', 'Tools', - 'FixupVars' + 'FixupVars', ] @@ -253,3 +253,11 @@ class Fizzler(MaterialGroup): LEFT = "effects/fizzler_l" RIGHT = "effects/fizzler_r" SHORT = "effects/fizzler" + + +class MusicChannel(Enum): + """Categories of music.""" + BASE = 'base' # Main track + TBEAM = 'tbeam' # Funnel audio + BOUNCE = 'BounceGel' # Jumping on repulsion gel. + SPEED = 'SpeedGel' # Moving fast horizontally diff --git a/src/packageLoader.py b/src/packageLoader.py index 69d8afc67..ca47c8cf1 100644 --- a/src/packageLoader.py +++ b/src/packageLoader.py @@ -7,12 +7,12 @@ import math import re from collections import defaultdict -from enum import Enum import srctools from app import tkMarkdown import utils from app.packageMan import PACK_CONFIG +from consts import MusicChannel from srctools import ( Property, NoKeyError, Vec, EmptyMapping, @@ -149,14 +149,6 @@ class CorrDesc(NamedTuple): } -class MusicChannel(Enum): - """Categories that can have music.""" - BASE = 'base' # Main track - TBEAM = 'tbeam' # Funnel audio - BOUNCE = 'BounceGel' # Jumping on repulsion gel. - SPEED = 'SpeedGel' # Moving fast horizontally - - class SignStyle(NamedTuple): """Signage information for a specific style.""" world: str From 4eb2731d863edd988cf03e4b55add5f52c05a83f Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Thu, 23 Jul 2020 11:21:00 +1000 Subject: [PATCH 24/87] Move music logic to its own module --- src/precomp/music.py | 119 ++++++++++++++++++++++++++++++++++++++++ src/vbsp.py | 127 ++++--------------------------------------- 2 files changed, 129 insertions(+), 117 deletions(-) create mode 100644 src/precomp/music.py diff --git a/src/precomp/music.py b/src/precomp/music.py new file mode 100644 index 000000000..13950a397 --- /dev/null +++ b/src/precomp/music.py @@ -0,0 +1,119 @@ +"""Handles adding music to the level.""" +from typing import Set, Dict, Iterable + +from srctools import VMF, Vec, Property, Output +from precomp import options +import srctools.logger + +LOGGER = srctools.logger.get_logger(__name__) + + +def add(vmf: VMF, loc: Vec, conf: Property, voice_attr: Dict[str, str], is_sp: bool) -> None: + """Add music to the map.""" + LOGGER.info("Adding Music...") + # These values are exported by the BEE2 app, indicating the + # options on the music item. + inst = options.get(str, 'music_instance') + snd_length = options.get(int, 'music_looplen') + + # Don't add our logic if an instance was provided. + # If this settings is set, we have a music config. + if conf and not inst: + music = vmf.create_ent( + classname='ambient_generic', + spawnflags='17', # Looping, Infinite Range, Starts Silent + targetname='@music', + origin=loc, + message='music.BEE2', + health='10', # Volume + ) + + music_start = vmf.create_ent( + classname='logic_relay', + spawnflags='0', + targetname='@music_start', + origin=loc + (-16, 0, -16), + ) + music_stop = vmf.create_ent( + classname='logic_relay', + spawnflags='0', + targetname='@music_stop', + origin=loc + (16, 0, -16), + ) + music_stop.add_out( + Output('OnTrigger', music, 'StopSound'), + Output('OnTrigger', music, 'Volume', '0'), + ) + + # In SinglePlayer, music gets killed during reload, + # so we need to restart it. + + # If snd_length is set, we have a non-loopable MP3 + # and want to re-trigger it after the time elapses, to simulate + # looping. + + # In either case, we need @music_restart to do that safely. + if is_sp or snd_length > 0: + + music_restart = vmf.create_ent( + classname='logic_relay', + spawnflags='2', # Allow fast retrigger. + targetname='@music_restart', + StartDisabled='1', + origin=loc + (0, 0, -16), + ) + + music_start.add_out( + Output('OnTrigger', music_restart, 'Enable'), + Output('OnTrigger', music_restart, 'Trigger', delay=0.01), + ) + + music_stop.add_out( + Output('OnTrigger', music_restart, 'Disable'), + Output('OnTrigger', music_restart, 'CancelPending'), + ) + + music_restart.add_out( + Output('OnTrigger', music, 'StopSound'), + Output('OnTrigger', music, 'Volume', '0'), + Output('OnTrigger', music, 'Volume', '10', delay=0.1), + Output('OnTrigger', music, 'PlaySound', delay=0.1), + ) + + if is_sp == 'SP': + # Trigger on level loads. + vmf.create_ent( + classname='logic_auto', + origin=loc + (0, 0, 16), + spawnflags='0', # Don't remove after fire + globalstate='', + ).add_out( + Output('OnLoadGame', music_restart, 'CancelPending'), + Output('OnLoadGame', music_restart, 'Trigger', delay=0.01), + ) + + if snd_length > 0: + # Re-trigger after the music duration. + music_restart.add_out( + Output('OnTrigger', '!self', 'Trigger', delay=snd_length) + ) + # Set to non-looping, so re-playing will restart it correctly. + music['spawnflags'] = '49' + else: + # The music track never needs to have repeating managed, + # just directly trigger. + music_start.add_out( + Output('OnTrigger', music, 'PlaySound'), + Output('OnTrigger', music, 'Volume', '10'), + ) + + if inst: + # We assume the instance is setup correct. + vmf.create_ent( + classname='func_instance', + targetname='music', + angles='0 0 0', + origin=loc, + file=inst, + fixup_style='0', + ) diff --git a/src/vbsp.py b/src/vbsp.py index c44e55048..625ceefa6 100644 --- a/src/vbsp.py +++ b/src/vbsp.py @@ -36,6 +36,7 @@ conditions, fizzler, voice_line, + music, ) import consts @@ -45,7 +46,7 @@ COND_MOD_NAME = 'VBSP' # Configuration data extracted from VBSP_config -settings = { +settings: Dict[str, Dict[str, Any]] = { "textures": {}, "options": {}, "fog": {}, @@ -55,8 +56,7 @@ "style_vars": defaultdict(bool), "has_attr": defaultdict(bool), "packtrigger": defaultdict(list), -} # type: Dict[str, Dict[str, Any]] - +} # The textures used for white surfaces. WHITE_PAN = [ @@ -1472,116 +1472,15 @@ def change_overlays(vmf: VMF) -> None: def add_extra_ents(vmf: VMF, game_mode: str) -> None: """Add the various extra instances to the map.""" - LOGGER.info("Adding Music...") - loc = options.get(Vec, 'global_ents_loc') - # These values are exported by the BEE2 app, indicating the - # options on the music item. - inst = options.get(str, 'music_instance') - snd_length = options.get(int, 'music_looplen') - - # Don't add our logic if an instance was provided. - # If this settings is set, we have a music config. - if settings['music_conf'] and not inst: - music = vmf.create_ent( - classname='ambient_generic', - spawnflags='17', # Looping, Infinite Range, Starts Silent - targetname='@music', - origin=loc, - message='music.BEE2', - health='10', # Volume - ) - - music_start = vmf.create_ent( - classname='logic_relay', - spawnflags='0', - targetname='@music_start', - origin=loc + (-16, 0, -16), - ) - music_stop = vmf.create_ent( - classname='logic_relay', - spawnflags='0', - targetname='@music_stop', - origin=loc + (16, 0, -16), - ) - music_stop.add_out( - Output('OnTrigger', music, 'StopSound'), - Output('OnTrigger', music, 'Volume', '0'), - ) - - # In SinglePlayer, music gets killed during reload, - # so we need to restart it. - - # If snd_length is set, we have a non-loopable MP3 - # and want to re-trigger it after the time elapses, to simulate - # looping. - - # In either case, we need @music_restart to do that safely. - if game_mode == 'SP' or snd_length > 0: - - music_restart = vmf.create_ent( - classname='logic_relay', - spawnflags='2', # Allow fast retrigger. - targetname='@music_restart', - StartDisabled='1', - origin=loc + (0, 0, -16), - ) - - music_start.add_out( - Output('OnTrigger', music_restart, 'Enable'), - Output('OnTrigger', music_restart, 'Trigger', delay=0.01), - ) - - music_stop.add_out( - Output('OnTrigger', music_restart, 'Disable'), - Output('OnTrigger', music_restart, 'CancelPending'), - ) - - music_restart.add_out( - Output('OnTrigger', music, 'StopSound'), - Output('OnTrigger', music, 'Volume', '0'), - Output('OnTrigger', music, 'Volume', '10', delay=0.1), - Output('OnTrigger', music, 'PlaySound', delay=0.1), - ) - - if game_mode == 'SP': - # Trigger on level loads. - vmf.create_ent( - classname='logic_auto', - origin=loc + (0, 0, 16), - spawnflags='0', # Don't remove after fire - globalstate='', - ).add_out( - Output('OnLoadGame', music_restart, 'CancelPending'), - Output('OnLoadGame', music_restart, 'Trigger', delay=0.01), - ) - - if snd_length > 0: - # Re-trigger after the music duration. - music_restart.add_out( - Output('OnTrigger', '!self', 'Trigger', delay=snd_length) - ) - # Set to non-looping, so re-playing will restart it correctly. - music['spawnflags'] = '49' - else: - # The music track never needs to have repeating managed, - # just directly trigger. - music_start.add_out( - Output('OnTrigger', music, 'PlaySound'), - Output('OnTrigger', music, 'Volume', '10'), - ) - - if inst: - # We assume the instance is setup correct. - vmf.create_ent( - classname='func_instance', - targetname='music', - angles='0 0 0', - origin=loc, - file=inst, - fixup_style='0', - ) + music.add( + vmf, + loc, + settings['music_conf'], + settings['has_attr'], + game_mode == 'SP', + ) LOGGER.info('Adding global ents...') @@ -1714,12 +1613,6 @@ def make_vrad_config(is_peti: bool) -> None: if value ) - # Copy over music soundscript data so VRAD can generate it.. - if settings['music_conf']: - # It's a list of prop objects, so it'll become a proper - # block when written. - conf['MusicScript'] = settings['music_conf'] - import precomp.conditions.piston_platform # This generates scripts and might need to tell VRAD. From 7012f41f8a7b7a4cd50d4663028ff5185de344ce Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Thu, 23 Jul 2020 12:37:01 +1000 Subject: [PATCH 25/87] Redo music logic to pass data from VBSP to VRAD via entities This removes another piece of data --- BEE2.fgd | 44 ++++++++++++++++++- src/consts.py | 4 +- src/postcomp/music.py | 99 ++++++++++++++++++++++++------------------- src/precomp/music.py | 63 +++++++++++++++++++++++++-- src/vbsp.py | 12 +----- src/vrad.py | 12 +----- 6 files changed, 163 insertions(+), 71 deletions(-) diff --git a/BEE2.fgd b/BEE2.fgd index 6d2bc32c3..b82ef0d77 100644 --- a/BEE2.fgd +++ b/BEE2.fgd @@ -207,10 +207,47 @@ ] // Entities added to the finished map to pass information to VRAD. + +@PointClass + base(Angles) + iconsprite("BEE2/editor/bee2_icon.vmt") += bee2_music_channel: + "Stores the configuration for the music soundscript." + [ + channel(choices) : "Channel" : "BASE" : "The type of music this contains." = + [ + "base" : "Main track" + "tbeam" : "Excursion Funnel" + "BounceGel" : "Repulsion Gel" + "SpeedGel" : "Propulsion Gel" + ] + sync(boolean) : "Sync" : 0 : "For funnels only, synchronise to the base track." + + track01(sound) : "Track" : : "A track which may be potentially selected." + track02(sound) : "Track" : : "A track which may be potentially selected." + track03(sound) : "Track" : : "A track which may be potentially selected." + track04(sound) : "Track" : : "A track which may be potentially selected." + track05(sound) : "Track" : : "A track which may be potentially selected." + track06(sound) : "Track" : : "A track which may be potentially selected." + track07(sound) : "Track" : : "A track which may be potentially selected." + track08(sound) : "Track" : : "A track which may be potentially selected." + track09(sound) : "Track" : : "A track which may be potentially selected." + track10(sound) : "Track" : : "A track which may be potentially selected." + track11(sound) : "Track" : : "A track which may be potentially selected." + track12(sound) : "Track" : : "A track which may be potentially selected." + track13(sound) : "Track" : : "A track which may be potentially selected." + track14(sound) : "Track" : : "A track which may be potentially selected." + track15(sound) : "Track" : : "A track which may be potentially selected." + track16(sound) : "Track" : : "A track which may be potentially selected." + track17(sound) : "Track" : : "A track which may be potentially selected." + track18(sound) : "Track" : : "A track which may be potentially selected." + track19(sound) : "Track" : : "A track which may be potentially selected." + track20(sound) : "Track" : : "A track which may be potentially selected." + ] @PointClass iconsprite("BEE2/editor/bee2_icon.vmt") - = bee2_coop_response : += bee2_coop_response : "Stores the choreo scenes for responses to players in Coop." [ type(string) : "Type" : : "The type of response this is." @@ -253,6 +290,11 @@ "bee2_editor_embeddedvoxel" "bee2_editor_embedface" ] + "Map Data" + [ + "bee2_music_channel" + "bee2_coop_response" + ] ] @AutoVisGroup = "Templates" diff --git a/src/consts.py b/src/consts.py index c96784a08..06b77efa1 100644 --- a/src/consts.py +++ b/src/consts.py @@ -259,5 +259,5 @@ class MusicChannel(Enum): """Categories of music.""" BASE = 'base' # Main track TBEAM = 'tbeam' # Funnel audio - BOUNCE = 'BounceGel' # Jumping on repulsion gel. - SPEED = 'SpeedGel' # Moving fast horizontally + BOUNCE = 'bouncegel' # Jumping on repulsion gel. + SPEED = 'speedgel' # Moving fast horizontally diff --git a/src/postcomp/music.py b/src/postcomp/music.py index 48610ece1..3d658320c 100644 --- a/src/postcomp/music.py +++ b/src/postcomp/music.py @@ -1,11 +1,16 @@ """Generates the soundscript for background music.""" -from typing import Set +import itertools +from typing import Dict, List from io import StringIO + from srctools.sndscript import SND_CHARS -from srctools.packlist import PackList -from srctools import Property +from srctools.packlist import PackList, FileType +from srctools.vmf import VMF +from consts import MusicChannel as Channel +import srctools.logger +LOGGER = srctools.logger.get_logger(__name__) # The starting section defining the name and volume. # SNDLVL_NONE means it's infinite range. @@ -221,60 +226,62 @@ } """ -def generate(data: Property, voice_attr: Set[str], pack_list: PackList) -> bytes: + +def generate(bsp: VMF, pack_list: PackList): """Generate a soundscript file for music.""" # We also pack the filenames used for the tracks - that way funnel etc # only get packed when needed. Stock sounds are in VPKS or in aperturetag/, # we don't check there. - - funnel = data.find_key('tbeam', '') - bounce = data.find_key('bouncegel', '') - speed = data.find_key('speedgel', '') - - sync_funnel = data.bool('sync_funnel') - - if 'base' not in data: - base = Property('base', 'bee2/silent_lp.wav') + tracks: Dict[Channel, List[str]] = {} + sync_funnel = False + + for conf_ent in bsp.by_class['bee2_music_channel']: + conf_ent.remove() + channel = Channel(conf_ent['channel'].casefold()) + if channel is Channel.TBEAM: + sync_funnel = srctools.conv_bool(conf_ent['sync']) + + track = [] + for i in itertools.count(1): + snd = conf_ent[f'track{i:02}'] + if not snd: + break + track.append(snd) + if track: + tracks[channel] = track + + if not tracks: + return None # No music. + + if Channel.BASE not in tracks: + tracks[Channel.BASE] = ['bee2/silent_lp.wav'] # Don't sync to a 2-second sound. sync_funnel = False - else: - base = data.find_key('base') - - # The sounds must be present, and the items should be in the map. - has_funnel = funnel.value and ( - 'funnel' in voice_attr or - 'excursionfunnel' in voice_attr - ) - has_bounce = bounce.value and ( - 'bouncegel' in voice_attr or - 'bluegel' in voice_attr - ) - # Speed-gel sounds also play when flinging, so keep it always. file = StringIO() # Write the base music track file.write(MUSIC_START.format(name='', vol='1')) - write_sound(file, base, pack_list, snd_prefix='#*') + write_sound(file, tracks[Channel.BASE], pack_list, snd_prefix='#*') file.write(MUSIC_BASE) # The 'soundoperators' section is still open now. - # Add the operators to play the auxilluary sounds.. - if has_funnel: + # Add the operators to play the auxiliary sounds.. + if Channel.TBEAM in tracks: file.write(MUSIC_FUNNEL_MAIN) - if has_bounce: + if Channel.BOUNCE in tracks: file.write(MUSIC_GEL_BOUNCE_MAIN) - if speed.value: + if Channel.SPEED in tracks: file.write(MUSIC_GEL_SPEED_MAIN) # End the main sound block file.write(MUSIC_END) - if has_funnel: + if Channel.TBEAM in tracks: # Write the 'music.BEE2_funnel' sound entry file.write('\n') file.write(MUSIC_START.format(name='_funnel', vol='1')) - write_sound(file, funnel, pack_list, snd_prefix='*') + write_sound(file, tracks[Channel.TBEAM], pack_list) # Some tracks want the funnel music to sync with the normal # track, others randomly choose a start. file.write( @@ -284,29 +291,33 @@ def generate(data: Property, voice_attr: Set[str], pack_list: PackList) -> bytes ) file.write(MUSIC_FUNNEL_UPDATE_STACK) - if has_bounce: + if Channel.BOUNCE in tracks: file.write('\n') file.write(MUSIC_START.format(name='_gel_bounce', vol='0.5')) - write_sound(file, bounce, pack_list, snd_prefix='*') + write_sound(file, tracks[Channel.BOUNCE], pack_list) # Fade in fast (we never get false positives, but fade out slow # since this disables when falling back.. file.write(MUSIC_GEL_STACK.format(fadein=0.25, fadeout=1.5)) - if speed.value: + if Channel.SPEED in tracks: file.write('\n') file.write(MUSIC_START.format(name='_gel_speed', vol='0.5')) - write_sound(file, speed, pack_list, snd_prefix='*') + write_sound(file, tracks[Channel.SPEED], pack_list) # We need to shut off the sound fast, so portals don't confuse it. # Fade in slow so it doesn't make much sound (and also as we get # up to speed). We stop almost immediately on gel too. file.write(MUSIC_GEL_STACK.format(fadein=0.5, fadeout=0.1)) - return file.getvalue().encode() + pack_list.pack_file( + 'scripts/BEE2_generated_music.txt', + FileType.SOUNDSCRIPT, + data=file.getvalue().encode() + ) def write_sound( file: StringIO, - snds: Property, + snds: List[str], pack_list: PackList, snd_prefix: str='*', ) -> None: @@ -314,22 +325,22 @@ def write_sound( snd_prefix is the prefix for each filename - *, #, @, etc. """ - if snds.has_children(): + if len(snds) > 1: file.write('"rndwave"\n\t{\n') for snd in snds: file.write( '\t"wave" "{sndchar}{file}"\n'.format( - file=snd.value.lstrip(SND_CHARS), + file=snd.lstrip(SND_CHARS), sndchar=snd_prefix, ) ) - pack_list.pack_file('sound/' + snd.value.casefold()) + pack_list.pack_file('sound/' + snd.casefold()) file.write('\t}\n') else: file.write( '"wave" "{sndchar}{file}"\n'.format( - file=snds.value.lstrip(SND_CHARS), + file=snds[0].lstrip(SND_CHARS), sndchar=snd_prefix, ) ) - pack_list.pack_file('sound/' + snds.value.casefold()) + pack_list.pack_file('sound/' + snds[0].casefold()) diff --git a/src/precomp/music.py b/src/precomp/music.py index 13950a397..edfeb0294 100644 --- a/src/precomp/music.py +++ b/src/precomp/music.py @@ -1,14 +1,21 @@ """Handles adding music to the level.""" -from typing import Set, Dict, Iterable +from typing import Dict, List from srctools import VMF, Vec, Property, Output from precomp import options +from consts import MusicChannel as Channel import srctools.logger LOGGER = srctools.logger.get_logger(__name__) -def add(vmf: VMF, loc: Vec, conf: Property, voice_attr: Dict[str, str], is_sp: bool) -> None: +def add( + vmf: VMF, + loc: Vec, + conf: Property, + voice_attr: Dict[str, str], + is_sp: bool, +) -> None: """Add music to the map.""" LOGGER.info("Adding Music...") # These values are exported by the BEE2 app, indicating the @@ -54,7 +61,6 @@ def add(vmf: VMF, loc: Vec, conf: Property, voice_attr: Dict[str, str], is_sp: b # In either case, we need @music_restart to do that safely. if is_sp or snd_length > 0: - music_restart = vmf.create_ent( classname='logic_relay', spawnflags='2', # Allow fast retrigger. @@ -107,6 +113,38 @@ def add(vmf: VMF, loc: Vec, conf: Property, voice_attr: Dict[str, str], is_sp: b Output('OnTrigger', music, 'Volume', '10'), ) + # Add the ents for the config itself. + # If the items aren't in the map, we can skip adding them. + # Speed-gel sounds also play when flinging, so keep it always. + + funnel = conf.find_key('tbeam', []) + bounce = conf.find_key('bouncegel', []) + + make_channel_conf( + vmf, loc, + Channel.BASE, + conf.find_key('base', []).as_array(), + ) + make_channel_conf( + vmf, loc, + Channel.SPEED, + conf.find_key('speedgel', []).as_array(), + ) + if 'funnel' in voice_attr or 'excursionfunnel' in voice_attr: + make_channel_conf( + vmf, loc, + Channel.TBEAM, + funnel.as_array(), + conf.bool('sync_funnel'), + ) + + if 'bouncegel' in voice_attr or 'bluegel' in voice_attr: + make_channel_conf( + vmf, loc, + Channel.BOUNCE, + bounce.as_array(), + ) + if inst: # We assume the instance is setup correct. vmf.create_ent( @@ -117,3 +155,22 @@ def add(vmf: VMF, loc: Vec, conf: Property, voice_attr: Dict[str, str], is_sp: b file=inst, fixup_style='0', ) + + +def make_channel_conf( + vmf: VMF, + pos: Vec, + channel: Channel, + tracks: List[str], + sync: bool = False, +) -> None: + """Embed the specified channel's data into the map via a custom ent.""" + if tracks: + ent = vmf.create_ent( + 'bee2_music_channel', + origin=pos, + channel=channel.value, + sync=sync, + ) + for i, track in enumerate(tracks, 1): + ent[f'track{i:02}'] = track diff --git a/src/vbsp.py b/src/vbsp.py index 625ceefa6..157e8ead3 100644 --- a/src/vbsp.py +++ b/src/vbsp.py @@ -183,7 +183,7 @@ def load_settings() -> Tuple[antlines.AntType, antlines.AntType]: ) } - settings['music_conf'] = conf['MusicScript', []] + settings['music_conf'] = conf.find_key('MusicScript', []) # Bottomless pit configuration pit = conf.find_key("bottomless_pit", []) @@ -1605,16 +1605,6 @@ def make_vrad_config(is_peti: bool) -> None: '' ) - # Copy over the voice attributes - conf['VoiceAttr'] = ';'.join( - key - for key, value in - settings['has_attr'].items() - if value - ) - - import precomp.conditions.piston_platform - # This generates scripts and might need to tell VRAD. cubes.write_vscripts(conf) diff --git a/src/vrad.py b/src/vrad.py index 3d0120003..dabf2ca12 100644 --- a/src/vrad.py +++ b/src/vrad.py @@ -227,16 +227,8 @@ def main(argv: List[str]) -> None: packlist.load_soundscript(soundscript, always_include=False) if is_peti: - LOGGER.info('Adding special packed files:') - voice_attr = set(conf['VoiceAttr', ''].casefold().split(';')) - - music_data = conf.find_key('MusicScript', []) - if music_data: - packlist.pack_file( - 'scripts/BEE2_generated_music.txt', - PackType.SOUNDSCRIPT, - data=music.generate(music_data, voice_attr, packlist) - ) + LOGGER.info('Checking for music:') + music.generate(bsp_ents, packlist) for prop in conf.find_children('InjectFiles'): filename = os.path.join('bee2', 'inject', prop.real_name) From 3fd078130475122527aacdb197b9c8ecee32892d Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Thu, 23 Jul 2020 12:26:34 +1000 Subject: [PATCH 26/87] Fix this template being upside-down --- src/precomp/template_brush.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/precomp/template_brush.py b/src/precomp/template_brush.py index 1afb139e5..68e7a1fec 100644 --- a/src/precomp/template_brush.py +++ b/src/precomp/template_brush.py @@ -1083,7 +1083,7 @@ def retexture_template( texturing.apply(gen_type, face, tex_name) if tex_name in ('goo', 'goo_cheap'): - if norm != (0, 0, 1): + if norm != (0, 0, -1): # Goo must be facing upright! # Retexture to nodraw, so a template can be made with # all faces goo to work in multiple orientations. From 69a396c98ea7781f797b07b7f42e3d8c23202ee0 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Thu, 23 Jul 2020 12:29:47 +1000 Subject: [PATCH 27/87] Only produce the mismatched music warning if all the values match This prevents the false warnings for all PeTI versus each individual track. --- src/packageLoader.py | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/packageLoader.py b/src/packageLoader.py index ca47c8cf1..15b64f5b9 100644 --- a/src/packageLoader.py +++ b/src/packageLoader.py @@ -28,6 +28,7 @@ Dict, List, Tuple, Set, Match, NamedTuple, Collection, Iterable, Iterator, + FrozenSet, ) @@ -2521,12 +2522,13 @@ def export(exp_data: ExportData): ) @classmethod - def post_parse(cls): + def post_parse(cls) -> None: """Check children of each music item actually exist. This must be done after they all were parsed. """ - sounds = {} # type: Dict[str, str] + sounds: Dict[FrozenSet[str], str] = {} + for music in cls.all(): for channel in MusicChannel: # Base isn't present in this. @@ -2544,20 +2546,22 @@ def post_parse(cls): ) # Look for tracks used in two items, indicates # they should be children of one... - for sound in music.sound[channel]: - sound = sound.casefold() - try: - other_id = sounds[sound] - except KeyError: - sounds[sound] = music.id - else: - if music.id != other_id: - LOGGER.warning( - 'Sound "{}" was reused in "{}" <> "{}".', - sound, - music.id, - other_id - ) + soundset = frozenset(map(str.casefold, music.sound[channel])) + if not soundset: + continue # Blank shouldn't match blanks... + + try: + other_id = sounds[soundset] + except KeyError: + sounds[soundset] = music.id + else: + if music.id != other_id: + LOGGER.warning( + 'Music tracks were reused in "{}" <> "{}": \n{}', + music.id, + other_id, + sorted(soundset) + ) class Signage(PakObject, allow_mult=True, has_img=False): From 60a34a98a09c559715932949163bd5dcda559b9f Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Sun, 26 Jul 2020 12:14:38 +1000 Subject: [PATCH 28/87] Add option to packages_sync to just skip prompts --- src/packages_sync.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/packages_sync.py b/src/packages_sync.py index 949abaf49..7a25fe513 100644 --- a/src/packages_sync.py +++ b/src/packages_sync.py @@ -39,6 +39,10 @@ # If true, user said * for packages - use last for all. PACKAGE_REPEAT: Optional[RawFileSystem] = None +SKIPPED_FILES: List[str] = [] + +# If enabled, ignore anything not in packages and that needs prompting. +NO_PROMPT = False def get_package(file: Path) -> RawFileSystem: @@ -139,6 +143,9 @@ def check_file(file: Path, portal2: Path, packages: Path) -> None: target_systems.append(package.fsys) if not target_systems: + if NO_PROMPT: + EXTRA_FILES.append(rel_loc) + return # This file is totally new. try: target_systems.append(get_package(rel_loc)) @@ -224,6 +231,11 @@ def main(files: List[str]) -> int: for file_path in files_to_check: check_file(file_path, portal2_loc, package_loc) + if SKIPPED_FILES: + LOGGER.warning('Skipped missing files:') + for file in SKIPPED_FILES: + LOGGER.info('- {}', file) + return 0 From 748e962c282ede31a3daa34553592a49b4fed37a Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Sat, 1 Aug 2020 10:40:09 +1000 Subject: [PATCH 29/87] Fix BEEmod/BEE2-items#3359: Logic items not removing their instances --- src/precomp/connections.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/precomp/connections.py b/src/precomp/connections.py index ea288a278..606d8b135 100644 --- a/src/precomp/connections.py +++ b/src/precomp/connections.py @@ -1563,8 +1563,10 @@ def add_item_inputs( if needs_counter: if logic_type.is_logic: - # Logic items are the counter. + # Logic items are just the counter. The instance is useless, so + # remove that from the map. counter_name = item.name + item.inst.remove() else: counter_name = item.name + COUNTER_NAME[count_var] @@ -1591,7 +1593,6 @@ def add_item_inputs( elif logic_type.is_logic: # We don't add outputs here, the outputted items do that. # counter is item.inst, so those are added to that. - LOGGER.info('LOGIC counter: {}', counter['targetname']) return else: # Should never happen, not other types. From 1ceb125f00b345613211632800c40e1b20c49030 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Sun, 2 Aug 2020 10:09:01 +1000 Subject: [PATCH 30/87] Fix #3408: Move VScriptCubePredicate data to an ent in the map --- BEE2.fgd | 30 ++++++++++++++++++++++ src/postcomp/filter.py | 58 ++++++++++++++++++++++++++++++++++++++++++ src/precomp/cubes.py | 40 ++++++++--------------------- src/vrad.py | 3 ++- 4 files changed, 101 insertions(+), 30 deletions(-) create mode 100644 src/postcomp/filter.py diff --git a/BEE2.fgd b/BEE2.fgd index b82ef0d77..c125f03ef 100644 --- a/BEE2.fgd +++ b/BEE2.fgd @@ -273,6 +273,35 @@ choreo20(scene) : "Scene" : : "Random line to use." ] +@PointClass + iconsprite("BEE2/editor/bee2_icon.vmt") += bee2_cube_filter_script: + "Stores models used for VScript cube filters." + [ + filename(string) : "Filename" : : "The filename to produce." + function(string) : "Function" : : "The name of the function generated." + mdl01(studio) : "Model" : : "A model that satisfies the predicate." + mdl02(studio) : "Model" : : "A model that satisfies the predicate." + mdl03(studio) : "Model" : : "A model that satisfies the predicate." + mdl04(studio) : "Model" : : "A model that satisfies the predicate." + mdl05(studio) : "Model" : : "A model that satisfies the predicate." + mdl06(studio) : "Model" : : "A model that satisfies the predicate." + mdl07(studio) : "Model" : : "A model that satisfies the predicate." + mdl08(studio) : "Model" : : "A model that satisfies the predicate." + mdl09(studio) : "Model" : : "A model that satisfies the predicate." + mdl10(studio) : "Model" : : "A model that satisfies the predicate." + mdl11(studio) : "Model" : : "A model that satisfies the predicate." + mdl12(studio) : "Model" : : "A model that satisfies the predicate." + mdl13(studio) : "Model" : : "A model that satisfies the predicate." + mdl14(studio) : "Model" : : "A model that satisfies the predicate." + mdl15(studio) : "Model" : : "A model that satisfies the predicate." + mdl16(studio) : "Model" : : "A model that satisfies the predicate." + mdl17(studio) : "Model" : : "A model that satisfies the predicate." + mdl18(studio) : "Model" : : "A model that satisfies the predicate." + mdl19(studio) : "Model" : : "A model that satisfies the predicate." + mdl20(studio) : "Model" : : "A model that satisfies the predicate." + ] + @AutoVisGroup = "BEE2" [ @@ -294,6 +323,7 @@ [ "bee2_music_channel" "bee2_coop_response" + "bee2_cube_filter_script" ] ] diff --git a/src/postcomp/filter.py b/src/postcomp/filter.py new file mode 100644 index 000000000..c238bc90f --- /dev/null +++ b/src/postcomp/filter.py @@ -0,0 +1,58 @@ +"""Transformations related to entity filters.""" +from io import BytesIO +from typing import Dict + +from srctools.bsp_transform import Context, trans +import srctools.logger +from srctools.packlist import FileType + + +LOGGER = srctools.logger.get_logger(__name__) + + +# For filtering, we use this class. It stores the table of values, and then +# provides a __call__()-style method to check if an ent matches the models. + +VSCRIPT_CLOSURE = b'''\ +class __BEE2_CUBE_FUNC__{ +\ttable = null; +\tconstructor(table) { +\t\tthis.table = table; +\t} +\tfunction _call(this2, ent) { +\t\treturn ent.GetModelName().tolower() in this.table; +\t} +} +''' + + +@trans('BEE2: Cube VScript Filters') +def cube_filter(ctx: Context) -> None: + """Generate and pack scripts duplicating the filter functionality for VScript.""" + # Build it up as a binary buffer, since we don't need to do difficult + # encoding. + script_buffers: Dict[str, BytesIO] = {} + + for ent in ctx.vmf.by_class['bee2_cube_filter_script']: + ent.remove() + filename = ent['filename'] + try: + buffer = script_buffers[filename] + except KeyError: + buffer = script_buffers[filename] = BytesIO() + buffer.write(VSCRIPT_CLOSURE) + + buffer.write(ent['function'].encode() + b' <- __BEE2_CUBE_FUNC__({\n') + for key, value in ent.keys.items(): + if key.startswith('mdl'): + buffer.write(b' ["%s"]=1,\n' % value.encode()) + buffer.write(b'});\n') + + LOGGER.info('Script buffers: {}', list(script_buffers)) + + for filename, buffer in script_buffers.items(): + ctx.pack.pack_file( + 'scripts/vscripts/' + filename, + FileType.VSCRIPT_SQUIRREL, + buffer.getvalue(), + ) diff --git a/src/precomp/cubes.py b/src/precomp/cubes.py index 8fea7b404..97bb27f98 100644 --- a/src/precomp/cubes.py +++ b/src/precomp/cubes.py @@ -79,21 +79,6 @@ ScriptVar = namedtuple('ScriptVar', 'local_name function vars') -# For filtering, we use this class. It stores the table of values, and then -# provides a __call__()-style method to check if an ent matches the models. - -VSCRIPT_CLOSURE = '''\ -class __BEE2_CUBE_FUNC__{ -\ttable = null; -\tconstructor(table) { -\t\tthis.table = table; -\t} -\tfunction _call(this2, ent) { -\t\treturn ent.GetModelName().tolower() in this.table; -\t} -} -''' - class CubeEntType(Enum): """Cube types, as set on prop_weighted_cube. @@ -1002,7 +987,7 @@ def res_cube_filter(vmf: VMF, inst: Entity, res: Property): @make_result('VScriptCubePredicate') -def res_script_cube_predicate(res: Property): +def res_script_cube_predicate(vmf: VMF, ent: Entity, res: Property) -> None: """Given a set of cube-type IDs, generate VScript code to identify them. This produces a script to include, which will define the specified function @@ -1033,13 +1018,6 @@ def res_script_cube_predicate(res: Property): if script_filename[-4:] != '.nut': script_filename += '.nut' - try: - buffer = CUBE_SCRIPT_FILTERS[script_filename] - except KeyError: - CUBE_SCRIPT_FILTERS[script_filename] = buffer = io.StringIO() - # Write our starting code. - buffer.write(VSCRIPT_CLOSURE) - all_cubes, inclusions, exclusions = parse_filter_types([ prop.value for prop in res.find_all('Cube') ]) @@ -1051,15 +1029,19 @@ def res_script_cube_predicate(res: Property): cube_type.add_models(models) # Normalise the names to a consistent format. - model_names = { + model_names = list({ model.lower().replace('\\', '/') for model in models - } + }) - buffer.write(script_function + ' <- __BEE2_CUBE_FUNC__({\n') - for model in model_names: - buffer.write(' ["{}"]=1,\n'.format(model)) - buffer.write('});\n') + conf_ent = vmf.create_ent( + 'bee2_cube_filter_script', + origin=ent['origin'], + filename=script_filename, + function=script_function, + ) + for i, model in enumerate(model_names, 1): + conf_ent[f'mdl{i:02}'] = model return RES_EXHAUSTED diff --git a/src/vrad.py b/src/vrad.py index dabf2ca12..e8b71b9b4 100644 --- a/src/vrad.py +++ b/src/vrad.py @@ -21,7 +21,7 @@ RawFileSystem, VPKFileSystem, ZipFileSystem, FileSystem, ) -from srctools.packlist import PackList, FileType as PackType, load_fgd +from srctools.packlist import PackList, load_fgd from srctools.game import find_gameinfo from srctools.bsp_transform import run_transformations @@ -29,6 +29,7 @@ music, screenshot, coop_responses, + filter, ) From cb9316b25f04c1b94fc61b2f4d6101ea45ae9226 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Sun, 2 Aug 2020 10:09:59 +1000 Subject: [PATCH 31/87] Add option to cube filter IDs --- src/precomp/cubes.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/precomp/cubes.py b/src/precomp/cubes.py index 97bb27f98..7b4b34e1d 100644 --- a/src/precomp/cubes.py +++ b/src/precomp/cubes.py @@ -634,6 +634,7 @@ def parse_filter_types( * to detect all cube types (including franken) * to detect 'companion' items. * to detect sphere-type items. + * to detect reflection-type items. This returns 3 sets of CubeTypes - all cubes, ones to include, and ones to exclude. @@ -672,6 +673,13 @@ def parse_filter_types( for cube in all_cubes: if cube.type is CubeEntType.sphere: targ_set.add(cube) + elif cube_id in ('reflect', 'reflection'): + for cube in all_cubes: + if cube.type is CubeEntType.reflect: + targ_set.add(cube) + # The other entity types don't have special behaviour really. + else: + raise KeyError('Unknown special cube type "<{}>"', cube_id) else: try: cube = CUBE_TYPES[cube_id] From 4f896553b57bb338fca5bd46ea30ec4b083d190b Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 5 Aug 2020 06:30:53 +1000 Subject: [PATCH 32/87] Restore the ability of TemplateOverlay to work with off-centre instances This was accidentally removed. --- src/precomp/conditions/entities.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/precomp/conditions/entities.py b/src/precomp/conditions/entities.py index a69cc1aff..4861a1c2a 100644 --- a/src/precomp/conditions/entities.py +++ b/src/precomp/conditions/entities.py @@ -74,6 +74,12 @@ def res_insert_overlay(vmf: VMF, inst: Entity, res: Property) -> None: origin += offset.copy().rotate_by_str( inst['angles', '0 0 0'] ) + + for axis, norm in enumerate(normal): + # Align to the center of the block grid. The normal direction is + # already correct. + if norm == 0: + face_pos[axis] = face_pos[axis] // 128 * 128 + 64 # Shift so that the user perceives the position as the pos of the face # itself. From f72d1b7917d26367da41c96a890a0cb4c9e8917f Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Tue, 4 Aug 2020 10:34:04 +1000 Subject: [PATCH 33/87] Make this code not depend on rotate_by_str mutating self. --- src/precomp/conditions/brushes.py | 4 ++-- src/precomp/conditions/conveyorBelt.py | 2 +- src/precomp/conditions/randomise.py | 3 +-- src/precomp/conditions/scaffold.py | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/precomp/conditions/brushes.py b/src/precomp/conditions/brushes.py index 3c9be4a3d..11739bd98 100644 --- a/src/precomp/conditions/brushes.py +++ b/src/precomp/conditions/brushes.py @@ -275,8 +275,8 @@ def res_add_brush(vmf: VMF, inst: Entity, res: Property) -> None: point2.z -= 64 # Rotate to match the instance - point1.rotate_by_str(inst['angles']) - point2.rotate_by_str(inst['angles']) + point1 = point1.rotate_by_str(inst['angles']) + point2 = point2.rotate_by_str(inst['angles']) origin = Vec.from_str(inst['origin']) point1 += origin # Then offset to the location of the instance diff --git a/src/precomp/conditions/conveyorBelt.py b/src/precomp/conditions/conveyorBelt.py index 0fd038994..8330a937d 100644 --- a/src/precomp/conditions/conveyorBelt.py +++ b/src/precomp/conditions/conveyorBelt.py @@ -44,7 +44,7 @@ def res_conveyor_belt(vmf: VMF, inst: Entity, res: Property) -> None: return move_dir = Vec(1, 0, 0).rotate_by_str(inst.fixup['$travel_direction']) - move_dir.rotate_by_str(inst['angles']) + move_dir = move_dir.rotate_by_str(inst['angles']) start_offset = inst.fixup.float('$starting_position') teleport_to_start = res.bool('TrackTeleport', True) segment_inst_file = instanceLocs.resolve_one(res['SegmentInst', '']) diff --git a/src/precomp/conditions/randomise.py b/src/precomp/conditions/randomise.py index 061233e19..80ff1a88d 100644 --- a/src/precomp/conditions/randomise.py +++ b/src/precomp/conditions/randomise.py @@ -244,9 +244,8 @@ def res_rand_inst_shift(inst: Entity, res: Property) -> None: random.uniform(min_x, max_x), random.uniform(min_y, max_y), random.uniform(min_z, max_z), - ) + ).rotate_by_str(inst['angles']) - offset.rotate_by_str(inst['angles']) origin = Vec.from_str(inst['origin']) origin += offset inst['origin'] = origin diff --git a/src/precomp/conditions/scaffold.py b/src/precomp/conditions/scaffold.py index 52cced20d..3ef280372 100644 --- a/src/precomp/conditions/scaffold.py +++ b/src/precomp/conditions/scaffold.py @@ -54,7 +54,7 @@ def get_config( else '$bottom_level' ] ) - offset.rotate_by_str(node.inst['angles']) + offset = offset.rotate_by_str(node.inst['angles']) offset += Vec.from_str(node.inst['origin']) return orient, offset From 69fa56455d7ef48929b54b253c5a6ae11cedc053 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Tue, 4 Aug 2020 17:42:02 +1000 Subject: [PATCH 34/87] Fix connections not allowing delays here. --- src/precomp/connections.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/precomp/connections.py b/src/precomp/connections.py index 606d8b135..9e5854871 100644 --- a/src/precomp/connections.py +++ b/src/precomp/connections.py @@ -1713,6 +1713,7 @@ def add_item_indicators( ) or pan, conditions.resolve_value(item.inst, cmd.input), conditions.resolve_value(item.inst, cmd.params), + delay=cmd.delay, inst_in=cmd.inst_in, times=cmd.times, ) From 08a5260ffd753be7344f43858a4e804e3f46eac3 Mon Sep 17 00:00:00 2001 From: Spencer Brown Date: Mon, 10 Aug 2020 05:57:18 +1000 Subject: [PATCH 35/87] Don't pack coop responses when none are specified --- src/postcomp/coop_responses.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/postcomp/coop_responses.py b/src/postcomp/coop_responses.py index 071d92ee0..12d10a2ea 100644 --- a/src/postcomp/coop_responses.py +++ b/src/postcomp/coop_responses.py @@ -17,6 +17,10 @@ def generate_coop_responses(ctx: Context) -> None: if key.startswith('choreo') ] response.remove() + + if not responses: + return + script = ["BEE2_RESPONSES <- {"] for response_type, lines in sorted(responses.items()): script.append(f'\t{response_type} = [') From 65fe904b11dab1ef162ea1e3c002173ac72ef4a0 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Tue, 18 Aug 2020 13:15:17 +1000 Subject: [PATCH 36/87] Implement #1349: Make choosing "no" in the confirmation window for exports Make the window also show if any action is chosen but the game isn't to be launched. --- src/app/UI.py | 40 ++++++++++++++++++++++------------------ src/app/optionWindow.py | 14 +++++++++++++- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/app/UI.py b/src/app/UI.py index c412f9fca..fb4a30f05 100644 --- a/src/app/UI.py +++ b/src/app/UI.py @@ -889,30 +889,34 @@ def export_editoritems(e=None): 'Hammer to ensure editor wall previews are changed.' ) - chosen_action = optionWindow.AfterExport( - optionWindow.AFTER_EXPORT_ACTION.get() - ) + chosen_action = optionWindow.AfterExport(optionWindow.AFTER_EXPORT_ACTION.get()) + want_launch = optionWindow.LAUNCH_AFTER_EXPORT.get() - # Launch first so quitting doesn't affect this. - if optionWindow.LAUNCH_AFTER_EXPORT.get(): - if messagebox.askyesno( + if want_launch or chosen_action is not optionWindow.AfterExport.NORMAL: + do_action = messagebox.askyesno( 'BEEMOD2', - message + _('\n Launch Game?'), + message + optionWindow.AFTER_EXPORT_TEXT[chosen_action, want_launch], parent=TK_ROOT, - ): - gameMan.selected_game.launch() - else: + ) + else: # No action to do, so just show an OK. messagebox.showinfo('BEEMOD2', message, parent=TK_ROOT) + do_action = False # Do the desired action - if quit, we don't bother to update UI. - if chosen_action is optionWindow.AfterExport.NORMAL: - pass - elif chosen_action is optionWindow.AfterExport.MINIMISE: - TK_ROOT.iconify() - elif chosen_action is optionWindow.AfterExport.QUIT: - utils.quit_app() - else: - raise ValueError('Unknown action "{}"'.format(chosen_action)) + if do_action: + # Launch first so quitting doesn't affect this. + if want_launch: + gameMan.selected_game.launch() + + if chosen_action is optionWindow.AfterExport.NORMAL: + pass + elif chosen_action is optionWindow.AfterExport.MINIMISE: + TK_ROOT.iconify() + elif chosen_action is optionWindow.AfterExport.QUIT: + quit_application() + # We never return from this. + else: + raise ValueError('Unknown action "{}"'.format(chosen_action)) # Select the last_export palette, so reloading loads this item selection. paletteLoader.pal_list.sort(key=str) diff --git a/src/app/optionWindow.py b/src/app/optionWindow.py index 03e2ec044..a4fe1091d 100644 --- a/src/app/optionWindow.py +++ b/src/app/optionWindow.py @@ -1,4 +1,4 @@ -# coding=utf-8 +"""Window for configuring BEE2's options, as well as the home of some options.""" from collections import defaultdict from pathlib import Path @@ -39,6 +39,18 @@ class AfterExport(Enum): name='OPT_after_export_action', ) +# action, launching_game -> suffix on the message box. +AFTER_EXPORT_TEXT: Dict[Tuple[AfterExport, bool], str] = { + (AfterExport.NORMAL, False): '', + (AfterExport.NORMAL, True): _('\nLaunch Game?'), + + (AfterExport.MINIMISE, False): _('\nMinimise BEE2?'), + (AfterExport.MINIMISE, True): _('\nLaunch Game and minimise BEE2?'), + + (AfterExport.QUIT, False): _('\nQuit BEE2?'), + (AfterExport.QUIT, True): _('\nLaunch Game and quit BEE2?'), +} + refresh_callbacks: List[Callable[[], None]] = [] # functions called to apply settings. # All the auto-created checkbox variables From 894ec08d6cd32664319e2a3055bf90b83d72ac28 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Tue, 18 Aug 2020 13:15:37 +1000 Subject: [PATCH 37/87] Make quitting the app properly shutdown the logger. --- src/app/UI.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/app/UI.py b/src/app/UI.py index fb4a30f05..a9bd1153b 100644 --- a/src/app/UI.py +++ b/src/app/UI.py @@ -434,7 +434,10 @@ def __repr__(self): def quit_application() -> None: """Do a last-minute save of our config files, and quit the app.""" - import sys + import sys, logging + + LOGGER.info('Shutting down application.') + # If our window isn't actually visible, this is set to nonsense - # ignore those values. if TK_ROOT.winfo_viewable(): @@ -447,7 +450,8 @@ def quit_application() -> None: CompilerPane.COMPILE_CFG.save_check() gameMan.save() - # Destroy the TK windows + # Destroy the TK windows, finalise logging, then quit. + logging.shutdown() TK_ROOT.quit() sys.exit(0) From 495cf96b45a3129d05b952db7af978649cbaebdb Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Tue, 18 Aug 2020 13:30:44 +1000 Subject: [PATCH 38/87] Resolve #694: Add versions to app crash windows and the log --- src/BEE2_launch.pyw | 2 +- src/app/__init__.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/BEE2_launch.pyw b/src/BEE2_launch.pyw index 69492e6a4..65a91445c 100644 --- a/src/BEE2_launch.pyw +++ b/src/BEE2_launch.pyw @@ -43,7 +43,7 @@ if __name__ == '__main__': utils.setup_localisations(LOGGER) LOGGER.info('Arguments: {}', sys.argv) - LOGGER.info('Running "{}":', app_name) + LOGGER.info('Running "{}", version {}:', app_name, utils.BEE_VERSION) if app_name == 'bee2': from app import BEE2 diff --git a/src/app/__init__.py b/src/app/__init__.py index 22e0b7f43..ea68905f5 100644 --- a/src/app/__init__.py +++ b/src/app/__init__.py @@ -1,12 +1,12 @@ """The package containg all UI code.""" import tkinter as tk from types import TracebackType - -# We must always have one Tk object, and it needs to be constructed -# before most of TKinter will function. So doing it here does it first. from typing import Type +from utils import BEE_VERSION +# We must always have one Tk object, and it needs to be constructed +# before most of TKinter will function. So doing it here does it first. TK_ROOT = tk.Tk() TK_ROOT.withdraw() # Hide the window until everything is loaded. @@ -91,7 +91,7 @@ def on_error( try: from tkinter import messagebox messagebox.showinfo( - title='BEE2 Error!', + title='BEEMOD {} Error!'.format(BEE_VERSION), message='An error occurred: \n{}\n\nThis has ' 'been copied to the clipboard.'.format(err), icon=messagebox.ERROR, From c93a836ecc4436477426f598b2ef4c749a9df06a Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Tue, 18 Aug 2020 13:45:21 +1000 Subject: [PATCH 39/87] Fix #1225: Extra blank row when items window exactly fits them all. --- src/app/UI.py | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/app/UI.py b/src/app/UI.py index a9bd1153b..50c622d3f 100644 --- a/src/app/UI.py +++ b/src/app/UI.py @@ -5,6 +5,7 @@ import itertools import operator import random +import math from srctools import Property from app import music_conf, TK_ROOT @@ -1601,30 +1602,28 @@ def flow_picker(e=None): for item in (it for it in pal_items if not it.visible): item.place_forget() - height = (num_items // width + 1) * 65 + 2 - pal_canvas['scrollregion'] = ( - 0, - 0, - width * 65, - height, - ) + + height = int(math.ceil(num_items / width)) * 65 + 2 + pal_canvas['scrollregion'] = (0, 0, width * 65, height) frmScroll['height'] = height - # This adds extra blank items on the end to finish the grid nicely. - for i in range(width): + # Now, add extra blank items on the end to finish the grid nicely. + # pal_items_fake allows us to recycle existing icons. + last_row = num_items % width + # Special case, don't add a full row if it's exactly the right count. + extra_items = (width - last_row) if last_row != 0 else 0 + + y = (num_items // width)*65 + offset + 1 + for i in range(extra_items): if i not in pal_items_fake: pal_items_fake.append(ttk.Label(frmScroll, image=img.PAL_BG_64)) - if (num_items % width) <= i < width: # if this space is empty - pal_items_fake[i].place( - x=((i % width)*65 + 1), - y=(num_items // width)*65 + offset + 1, - ) + pal_items_fake[i].place(x=((i + last_row) % width)*65 + 1, y=y) - for item in pal_items_fake[width:]: + for item in pal_items_fake[extra_items:]: item.place_forget() -def init_drag_icon(): +def init_drag_icon() -> None: drag_win = Toplevel(TK_ROOT) # this prevents stuff like the title bar, normal borders etc from # appearing in this window. From 40d33cecced1d216b234da1390182f852c691073 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Tue, 18 Aug 2020 14:00:07 +1000 Subject: [PATCH 40/87] Document the members of the drag-drop slot --- src/app/dragdrop.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/app/dragdrop.py b/src/app/dragdrop.py index bc1bcc188..597a67e58 100644 --- a/src/app/dragdrop.py +++ b/src/app/dragdrop.py @@ -368,8 +368,24 @@ def _evt_stop(self, event: tkinter.Event) -> None: # noinspection PyProtectedMember class Slot(Generic[ItemT]): """Represents a single slot.""" + # The two widgets shown at the bottom when moused over. _text_lbl: Optional[tkinter.Label] _info_btn: Optional[tkinter.Label] + # Our main widget. + _lbl: tkinter.Label + + # The current thing in the slot. + _contents: Optional[ItemT] + + # The geometry manager used to position this. + # Either 'pack', 'place', 'grid', or '_canvas_XX' to indicate + # we're on the canvas with ID XX. + _pos_type: Optional[str] + + # If true, this can't be changed, and dragging out of it produces a second + # reference to the contents. + is_source: bool + man: Manager # Our drag/drop controller. def __init__( self, @@ -382,8 +398,8 @@ def __init__( self.man = man self.is_source = is_source - self._contents: Optional[ItemT] = None - self._pos_type: Optional[str] = None + self._contents = None + self._pos_type = None self._lbl = tkinter.Label( parent, image=man._img_blank, From 2d75c4845b16365404aa4653dbbc42cd9706927e Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Tue, 18 Aug 2020 14:15:27 +1000 Subject: [PATCH 41/87] Fix #1216: Fix some cases where readonly palettes can be deleted --- src/app/UI.py | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/src/app/UI.py b/src/app/UI.py index 50c622d3f..8d16452a2 100644 --- a/src/app/UI.py +++ b/src/app/UI.py @@ -750,7 +750,7 @@ def suggested_refresh(): UI['suggested_style'].state(['!disabled']) -def refresh_pal_ui(): +def refresh_pal_ui() -> None: """Update the UI to show the correct palettes.""" global selectedPalette cur_palette = paletteLoader.pal_list[selectedPalette] @@ -781,6 +781,13 @@ def refresh_pal_ui(): selectbackground=tk_tools.LISTBOX_BG_SEL_COLOR, ) + if len(paletteLoader.pal_list) < 2 or cur_palette.prevent_overwrite: + UI['pal_remove'].state(('disabled',)) + menus['pal'].entryconfigure(1, state=DISABLED) + else: + UI['pal_remove'].state(('!disabled',)) + menus['pal'].entryconfigure(1, state=NORMAL) + for ind in range(menus['pal'].index(END), 0, -1): # Delete all the old radiobuttons # Iterate backward to ensure indexes stay the same. @@ -1232,20 +1239,24 @@ def pal_save(e=None) -> None: def pal_remove() -> None: global selectedPalette - if len(paletteLoader.pal_list) >= 2: - pal = paletteLoader.pal_list[selectedPalette] - if messagebox.askyesno( - title='BEE2', - message=_('Are you sure you want to delete "{}"?').format( - pal.name, - ), - parent=TK_ROOT, - ): - pal.delete_from_disk() - del paletteLoader.pal_list[selectedPalette] - selectedPalette -= 1 - selectedPalette_radio.set(selectedPalette) - refresh_pal_ui() + pal = paletteLoader.pal_list[selectedPalette] + # Don't delete if there's only 1, or it's readonly. + if len(paletteLoader.pal_list) < 2 or pal.prevent_overwrite: + return + + if messagebox.askyesno( + title='BEE2', + message=_('Are you sure you want to delete "{}"?').format( + pal.name, + ), + parent=TK_ROOT, + ): + pal.delete_from_disk() + del paletteLoader.pal_list[selectedPalette] + selectedPalette -= 1 + selectedPalette_radio.set(selectedPalette) + refresh_pal_ui() + set_palette() # UI functions, each accepts the parent frame to place everything in. From e6c01baa0e5073aea9f973ba0d36b7935211848a Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Fri, 21 Aug 2020 08:04:37 +1000 Subject: [PATCH 42/87] Fix #1372: Cave portrait result not working properly --- src/precomp/conditions/addInstance.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/precomp/conditions/addInstance.py b/src/precomp/conditions/addInstance.py index c2d19d1bd..112d2365c 100644 --- a/src/precomp/conditions/addInstance.py +++ b/src/precomp/conditions/addInstance.py @@ -130,7 +130,7 @@ def res_add_overlay_inst(vmf: VMF, inst: Entity, res: Property) -> Optional[Enti @make_result('addCavePortrait') -def res_cave_portrait(inst: Entity, res: Property): +def res_cave_portrait(vmf: VMF, inst: Entity, res: Property) -> None: """A variant of AddOverlay for adding Cave Portraits. If the set quote pack is not Cave Johnson, this does nothing. @@ -139,6 +139,6 @@ def res_cave_portrait(inst: Entity, res: Property): """ skin = options.get(int, 'cave_port_skin') if skin is not None: - new_inst = res_add_overlay_inst(inst, res) + new_inst = res_add_overlay_inst(vmf, inst, res) if new_inst is not None: new_inst.fixup['$skin'] = skin From c9fde5aadb6ef8a72ea1c28088fbf278d8110d92 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Thu, 20 Aug 2020 16:56:52 +1000 Subject: [PATCH 43/87] Make this error message more clear --- src/packageLoader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/packageLoader.py b/src/packageLoader.py index 15b64f5b9..8a5220b39 100644 --- a/src/packageLoader.py +++ b/src/packageLoader.py @@ -370,7 +370,7 @@ def find_packages(pak_dir: str) -> None: LOGGER.debug('Checking subdir "{}" for packages...', name) find_packages(name) else: - LOGGER.warning('ERROR: Bad package "{}"!', name) + LOGGER.warning('ERROR: package "{}" has no info.txt!', name) # Don't continue to parse this "package" continue try: From dba8750d66da8e3a3f151612161e98c7b72eeb61 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 16 Sep 2020 11:27:47 +1000 Subject: [PATCH 44/87] Implement "rotate to vertical" on templates --- src/precomp/template_brush.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/precomp/template_brush.py b/src/precomp/template_brush.py index 68e7a1fec..4a2dc00d9 100644 --- a/src/precomp/template_brush.py +++ b/src/precomp/template_brush.py @@ -1042,6 +1042,26 @@ def retexture_template( else: face.uaxis = uaxis.copy() face.vaxis = vaxis.copy() + elif orig_id in template.vertical_faces: + # Rotate the face in increments of 90 degress, so it is as + # upright as possible. + pos_u = face.uaxis + pos_v = face.vaxis + # If both are zero, we're on the floor/ceiling and this is + # pointless. + if pos_u.z != 0 or pos_v.z != 0: + neg_u = UVAxis(-pos_u.x, -pos_u.y, -pos_u.z, pos_u.offset, + pos_u.scale) + neg_v = UVAxis(-pos_v.x, -pos_v.y, -pos_v.z, pos_v.offset, + pos_v.scale) + # Each row does u, v = v, -u to rotate 90 degrees. + # We want whichever makes V point vertically. + face.uaxis, face.vaxis = max([ + (pos_u, pos_v), + (pos_v, neg_u), + (neg_u, neg_v), + (neg_v, pos_u), + ], key=lambda uv: -uv[1].z) override_mat: Optional[List[str]] try: From e9e65d772c504cbf08a7f7391a00953ee0426f24 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 16 Sep 2020 11:45:03 +1000 Subject: [PATCH 45/87] Fix #1389: View buttons not functioning properly --- src/app/SubPane.py | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/app/SubPane.py b/src/app/SubPane.py index b5a80f77c..af817e88e 100644 --- a/src/app/SubPane.py +++ b/src/app/SubPane.py @@ -71,7 +71,7 @@ def __init__( self.tool_button = make_tool_button( frame=tool_frame, img=tool_img, - command=self.toggle_win, + command=self._toggle_win, ) self.tool_button.state(('pressed',)) self.tool_button.grid( @@ -83,7 +83,12 @@ def __init__( tooltip.add_tooltip( self.tool_button, text=_('Hide/Show the "{}" window.').format(title)) - menu_bar.add_checkbutton(label=title, variable=self.visible, command=self.toggle_win) + menu_bar.add_checkbutton( + label=title, + variable=self.visible, + command=self._set_state_from_menu, + ) + self.transient(master=parent) self.resizable(resize_x, resize_y) self.title(title) @@ -113,13 +118,24 @@ def show_win(self, play_snd: bool=True) -> None: self.tool_button.state(('pressed',)) self.follow_main() - def toggle_win(self) -> None: + def _toggle_win(self) -> None: """Toggle the window between shown and hidden.""" if self.visible.get(): self.hide_win() else: self.show_win() + def _set_state_from_menu(self) -> None: + """Called when the menu bar button is pressed. + + This has already toggled the variable, so we just need to read + from it. + """ + if self.visible.get(): + self.show_win() + else: + self.hide_win() + def move(self, x: int=None, y: int=None, width: int=None, height: int=None) -> None: """Move the window to the specified position. @@ -215,4 +231,4 @@ def load_conf(self) -> None: # Prevent this until here, so the event won't erase our # settings - self.can_save = True \ No newline at end of file + self.can_save = True From b0f3f338f8aa483f36567914273039bcb74584c3 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 16 Sep 2020 11:46:23 +1000 Subject: [PATCH 46/87] Remove use of import * in SubPane --- src/app/SubPane.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/app/SubPane.py b/src/app/SubPane.py index af817e88e..e9aa8c998 100644 --- a/src/app/SubPane.py +++ b/src/app/SubPane.py @@ -1,6 +1,6 @@ from typing import Callable, Any -from tkinter import * +import tkinter as tk from tkinter import ttk from BEE2_config import GEN_OPTS @@ -23,8 +23,8 @@ def make_tool_button( - frame: Misc, - img: PhotoImage, + frame: tk.Misc, + img: tk.PhotoImage, command: Callable[[], Any] ) -> ttk.Button: """Make a toolbar icon.""" @@ -38,25 +38,25 @@ def make_tool_button( return button -class SubPane(Toplevel): +class SubPane(tk.Toplevel): """A Toplevel window that can be shown/hidden. This follows the main window when moved. """ def __init__( self, - parent: Misc, + parent: tk.Misc, *, - tool_frame: Frame, - tool_img: PhotoImage, - menu_bar: Menu, + tool_frame: tk.Frame, + tool_img: tk.PhotoImage, + menu_bar: tk.Menu, tool_col: int=0, title: str='', resize_x: bool=False, resize_y: bool=False, name: str='', ) -> None: - self.visible = BooleanVar(parent, True) + self.visible = tk.BooleanVar(parent, True) self.win_name = name self.allow_snap = False self.can_save = False From 68e6e19d54d0b82c2c7ba449ac8314ac3583ea91 Mon Sep 17 00:00:00 2001 From: Luke18033 Date: Sun, 20 Sep 2020 10:34:32 -0700 Subject: [PATCH 47/87] Clarify what Preseve Game Directories does --- i18n/BEE2.pot | 817 ++++++++++++++++++++------------------- i18n/es.po | 832 +++++++++++++++++++++------------------- i18n/fr.po | 828 ++++++++++++++++++++------------------- i18n/ja.po | 832 +++++++++++++++++++++------------------- i18n/zh.po | 831 ++++++++++++++++++++------------------- src/app/optionWindow.py | 6 +- 6 files changed, 2156 insertions(+), 1990 deletions(-) diff --git a/i18n/BEE2.pot b/i18n/BEE2.pot index a87799994..69bb50edc 100644 --- a/i18n/BEE2.pot +++ b/i18n/BEE2.pot @@ -4,43 +4,79 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: https://github.com/BEEmod/BEE2.4/issues\n" -"POT-Creation-Date: 2020-07-18 11:58+1000\n" +"POT-Creation-Date: 2020-09-20 10:31-0700\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.6.0\n" +"Generated-By: Babel 2.8.0\n" -#: CheckDetails.py +#: loadScreen.py +msgid "Skipped!" +msgstr "" + +#: loadScreen.py +msgid "Version: " +msgstr "" + +#: app/optionWindow.py app/packageMan.py app/selector_win.py loadScreen.py +msgid "Cancel" +msgstr "" + +#: app/tagsPane.py loadScreen.py +msgid "Packages" +msgstr "" + +#: loadScreen.py +msgid "Loading Objects" +msgstr "" + +#: loadScreen.py +msgid "Loading Images" +msgstr "" + +#: loadScreen.py +msgid "Initialising UI" +msgstr "" + +#: loadScreen.py +msgid "Better Extended Editor for Portal 2" +msgstr "" + +#: utils.py +msgid "__LANG_USE_SANS_SERIF__" +msgstr "" + +#: app/CheckDetails.py msgid "Toggle all checkboxes." msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "ATLAS" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "P-Body" msgstr "" -#: CompilerPane.py voiceEditor.py +#: app/CompilerPane.py app/voiceEditor.py msgid "Chell" msgstr "" -#: CompilerPane.py voiceEditor.py +#: app/CompilerPane.py app/voiceEditor.py msgid "Bendy" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "" "Brushes form the walls or other parts of the test chamber. If this is " "high, it may help to reduce the size of the map or remove intricate " "shapes." msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "" "Entities are the things in the map that have functionality. Removing " "complex moving items will help reduce this. Items have their entity count" @@ -51,66 +87,66 @@ msgid "" "entities at runtime." msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "" "Overlays are smaller images affixed to surfaces, like signs or indicator " "lights. Hiding complex antlines or setting them to signage will reduce " "this." msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "Corridor" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "" "Randomly choose a corridor. This is saved in the puzzle data and will not" " change." msgstr "" -#: CompilerPane.py UI.py +#: app/CompilerPane.py app/UI.py msgid "Random" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "Image Files" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "" "Options on this panel can be changed \n" "without exporting or restarting the game." msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "Map Settings" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "Compile Settings" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "Thumbnail" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "Auto" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "PeTI" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "Custom:" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "Cleanup old screenshots" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "" "Override the map image to use a screenshot automatically taken from the " "beginning of a chamber. Press F5 to take a new screenshot. If the map has" @@ -118,199 +154,199 @@ msgid "" "PeTI screenshot will be used instead." msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "Use the normal editor view for the map preview image." msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "" "Use a custom image for the map preview image. Click the screenshot to " "select.\n" "Images will be converted to JPEGs if needed." msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "" "Automatically delete unused Automatic screenshots. Disable if you want to" " keep things in \"portal2/screenshots\". " msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "Lighting:" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "Fast" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "Full" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "" "Compile with lower-quality, fast lighting. This speeds up compile times, " "but does not appear as good. Some shadows may appear wrong.\n" "When publishing, this is ignored." msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "" "Compile with high-quality lighting. This looks correct, but takes longer " "to compute. Use if you're arranging lights.\n" "When publishing, this is always used." msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "Dump packed files to:" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "" "When compiling, dump all files which were packed into the map. Useful if " "you're intending to edit maps in Hammer." msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "Last Compile:" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "Entity" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "Overlay" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "" "Refresh the compile progress bars. Press after a compile has been " "performed to show the new values." msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "Brush" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "Voicelines:" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "Use voiceline priorities" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "" "Only choose the highest-priority voicelines. This means more generic " "lines will can only be chosen if few test elements are in the map. If " "disabled any applicable lines will be used." msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "Spawn at:" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "Entry Door" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "Elevator" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "" "When previewing in SP, spawn inside the entry elevator. Use this to " "examine the entry and exit corridors." msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "When previewing in SP, spawn just before the entry door." msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "Corridor:" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "SP Entry:" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "SP Exit:" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "Coop:" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "Player Model (SP):" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "Compile Options" msgstr "" -#: CompilerPane.py +#: app/CompilerPane.py msgid "Compiler Options - {}" msgstr "" -#: StyleVarPane.py +#: app/StyleVarPane.py msgid "Multiverse Cave" msgstr "" -#: StyleVarPane.py +#: app/StyleVarPane.py msgid "Play the Workshop Cave Johnson lines on map start." msgstr "" -#: StyleVarPane.py +#: app/StyleVarPane.py msgid "Prevent Portal Bump (fizzler)" msgstr "" -#: StyleVarPane.py +#: app/StyleVarPane.py msgid "" "Add portal bumpers to make it more difficult to portal across fizzler " "edges. This can prevent placing portals in tight spaces near fizzlers, or" " fizzle portals on activation." msgstr "" -#: StyleVarPane.py +#: app/StyleVarPane.py msgid "Suppress Mid-Chamber Dialogue" msgstr "" -#: StyleVarPane.py +#: app/StyleVarPane.py msgid "Disable all voicelines other than entry and exit lines." msgstr "" -#: StyleVarPane.py +#: app/StyleVarPane.py msgid "Unlock Default Items" msgstr "" -#: StyleVarPane.py +#: app/StyleVarPane.py msgid "" "Allow placing and deleting the mandatory Entry/Exit Doors and Large " "Observation Room. Use with caution, this can have weird results!" msgstr "" -#: StyleVarPane.py +#: app/StyleVarPane.py msgid "Allow Adding Goo Mist" msgstr "" -#: StyleVarPane.py +#: app/StyleVarPane.py msgid "" "Add mist particles above Toxic Goo in certain styles. This can increase " "the entity count significantly with large, complex goo pits, so disable " "if needed." msgstr "" -#: StyleVarPane.py +#: app/StyleVarPane.py msgid "Light Reversible Excursion Funnels" msgstr "" -#: StyleVarPane.py +#: app/StyleVarPane.py msgid "" "Funnels emit a small amount of light. However, if multiple funnels are " "near each other and can reverse polarity, this can cause lighting issues." @@ -318,102 +354,102 @@ msgid "" " do not have this issue." msgstr "" -#: StyleVarPane.py +#: app/StyleVarPane.py msgid "Enable Shape Framing" msgstr "" -#: StyleVarPane.py +#: app/StyleVarPane.py msgid "" "After 10 shape-type antlines are used, the signs repeat. With this " "enabled, colored frames will be added to distinguish them." msgstr "" -#: StyleVarPane.py +#: app/StyleVarPane.py msgid "Default: On" msgstr "" -#: StyleVarPane.py +#: app/StyleVarPane.py msgid "Default: Off" msgstr "" -#: StyleVarPane.py +#: app/StyleVarPane.py msgid "Styles: Unstyled" msgstr "" -#: StyleVarPane.py +#: app/StyleVarPane.py msgid "Styles: All" msgstr "" -#: StyleVarPane.py +#: app/StyleVarPane.py msgid "Style: {}" msgid_plural "Styles: {}" msgstr[0] "" msgstr[1] "" -#: StyleVarPane.py +#: app/StyleVarPane.py msgid "Style/Item Properties" msgstr "" -#: StyleVarPane.py +#: app/StyleVarPane.py msgid "Styles" msgstr "" -#: StyleVarPane.py +#: app/StyleVarPane.py msgid "All:" msgstr "" -#: StyleVarPane.py +#: app/StyleVarPane.py msgid "Selected Style:" msgstr "" -#: StyleVarPane.py +#: app/StyleVarPane.py msgid "Other Styles:" msgstr "" -#: StyleVarPane.py +#: app/StyleVarPane.py msgid "No Options!" msgstr "" -#: StyleVarPane.py +#: app/StyleVarPane.py msgid "None!" msgstr "" -#: StyleVarPane.py +#: app/StyleVarPane.py msgid "Items" msgstr "" -#: SubPane.py +#: app/SubPane.py msgid "Hide/Show the \"{}\" window." msgstr "" -#: UI.py +#: app/UI.py msgid "Export..." msgstr "" -#: UI.py +#: app/UI.py msgid "Select Skyboxes" msgstr "" -#: UI.py +#: app/UI.py msgid "" "The skybox decides what the area outside the chamber is like. It chooses " "the colour of sky (seen in some items), the style of bottomless pit (if " "present), as well as color of \"fog\" (seen in larger chambers)." msgstr "" -#: UI.py +#: app/UI.py msgid "3D Skybox" msgstr "" -#: UI.py +#: app/UI.py msgid "Fog Color" msgstr "" -#: UI.py +#: app/UI.py msgid "Select Additional Voice Lines" msgstr "" -#: UI.py +#: app/UI.py msgid "" "Voice lines choose which extra voices play as the player enters or exits " "a chamber. They are chosen based on which items are present in the map. " @@ -421,31 +457,31 @@ msgid "" "Style Properties." msgstr "" -#: UI.py +#: app/UI.py msgid "Add no extra voice lines, only Multiverse Cave if enabled." msgstr "" -#: UI.py +#: app/UI.py msgid "" msgstr "" -#: UI.py +#: app/UI.py msgid "Characters" msgstr "" -#: UI.py +#: app/UI.py msgid "Turret Shoot Monitor" msgstr "" -#: UI.py +#: app/UI.py msgid "Monitor Visuals" msgstr "" -#: UI.py +#: app/UI.py msgid "Select Style" msgstr "" -#: UI.py +#: app/UI.py msgid "" "The Style controls many aspects of the map. It decides the materials used" " for walls, the appearance of entrances and exits, the design for most " @@ -454,38 +490,38 @@ msgid "" "The style broadly defines the time period a chamber is set in." msgstr "" -#: UI.py +#: app/UI.py msgid "Elevator Videos" msgstr "" -#: UI.py +#: app/UI.py msgid "Select Elevator Video" msgstr "" -#: UI.py +#: app/UI.py msgid "" "Set the video played on the video screens in modern Aperture elevator " "rooms. Not all styles feature these. If set to \"None\", a random video " "will be selected each time the map is played, like in the default PeTI." msgstr "" -#: UI.py +#: app/UI.py msgid "This style does not have a elevator video screen." msgstr "" -#: UI.py +#: app/UI.py msgid "Choose a random video." msgstr "" -#: UI.py +#: app/UI.py msgid "Multiple Orientations" msgstr "" -#: UI.py +#: app/UI.py msgid "Selected Items and Style successfully exported!" msgstr "" -#: UI.py +#: app/UI.py msgid "" "\n" "\n" @@ -493,1091 +529,1080 @@ msgid "" "editor wall previews are changed." msgstr "" -#: UI.py -msgid "" -"\n" -" Launch Game?" -msgstr "" - -#: UI.py +#: app/UI.py msgid "Delete Palette \"{}\"" msgstr "" -#: UI.py +#: app/UI.py msgid "BEE2 - Save Palette" msgstr "" -#: UI.py +#: app/UI.py msgid "Enter a name:" msgstr "" -#: UI.py +#: app/UI.py msgid "This palette already exists. Overwrite?" msgstr "" -#: UI.py gameMan.py +#: app/UI.py app/gameMan.py msgid "Are you sure you want to delete \"{}\"?" msgstr "" -#: UI.py +#: app/UI.py msgid "Clear Palette" msgstr "" -#: UI.py UI.py +#: app/UI.py app/UI.py msgid "Delete Palette" msgstr "" -#: UI.py +#: app/UI.py msgid "Save Palette..." msgstr "" -#: UI.py UI.py +#: app/UI.py app/UI.py msgid "Save Palette As..." msgstr "" -#: UI.py UI.py +#: app/UI.py app/UI.py msgid "Save Settings in Palettes" msgstr "" -#: UI.py music_conf.py +#: app/UI.py app/music_conf.py msgid "Music: " msgstr "" -#: UI.py +#: app/UI.py msgid "{arr} Use Suggested {arr}" msgstr "" -#: UI.py +#: app/UI.py msgid "Style: " msgstr "" -#: UI.py +#: app/UI.py msgid "Voice: " msgstr "" -#: UI.py +#: app/UI.py msgid "Skybox: " msgstr "" -#: UI.py +#: app/UI.py msgid "Elev Vid: " msgstr "" -#: UI.py +#: app/UI.py msgid "" "Enable or disable particular voice lines, to prevent them from being " "added." msgstr "" -#: UI.py +#: app/UI.py msgid "All Items: " msgstr "" -#: UI.py +#: app/UI.py msgid "Export to \"{}\"..." msgstr "" -#: UI.py backup.py +#: app/UI.py app/backup.py msgid "File" msgstr "" -#: UI.py +#: app/UI.py msgid "Export" msgstr "" -#: UI.py backup.py +#: app/UI.py app/backup.py msgid "Add Game" msgstr "" -#: UI.py +#: app/UI.py msgid "Uninstall from Selected Game" msgstr "" -#: UI.py +#: app/UI.py msgid "Backup/Restore Puzzles..." msgstr "" -#: UI.py +#: app/UI.py msgid "Manage Packages..." msgstr "" -#: UI.py +#: app/UI.py msgid "Options" msgstr "" -#: UI.py gameMan.py +#: app/UI.py app/gameMan.py msgid "Quit" msgstr "" -#: UI.py +#: app/UI.py msgid "Palette" msgstr "" -#: UI.py +#: app/UI.py msgid "Clear" msgstr "" -#: UI.py +#: app/UI.py msgid "Fill Palette" msgstr "" -#: UI.py +#: app/UI.py msgid "Save Palette" msgstr "" -#: UI.py +#: app/UI.py msgid "View" msgstr "" -#: UI.py +#: app/UI.py msgid "Palettes" msgstr "" -#: UI.py +#: app/UI.py msgid "Export Options" msgstr "" -#: UI.py +#: app/UI.py msgid "Fill empty spots in the palette with random items." msgstr "" -#: backup.py +#: app/backup.py msgid "Copying maps" msgstr "" -#: backup.py +#: app/backup.py msgid "Loading maps" msgstr "" -#: backup.py +#: app/backup.py msgid "Deleting maps" msgstr "" -#: backup.py +#: app/backup.py msgid "Failed to parse this puzzle file. It can still be backed up." msgstr "" -#: backup.py +#: app/backup.py msgid "No description found." msgstr "" -#: backup.py +#: app/backup.py msgid "Coop" msgstr "" -#: backup.py +#: app/backup.py msgid "SP" msgstr "" -#: backup.py +#: app/backup.py msgid "This filename is already in the backup.Do you wish to overwrite it? ({})" msgstr "" -#: backup.py +#: app/backup.py msgid "BEE2 Backup" msgstr "" -#: backup.py +#: app/backup.py msgid "No maps were chosen to backup!" msgstr "" -#: backup.py +#: app/backup.py msgid "" "This map is already in the game directory.Do you wish to overwrite it? " "({})" msgstr "" -#: backup.py +#: app/backup.py msgid "Load Backup" msgstr "" -#: backup.py backup.py +#: app/backup.py app/backup.py msgid "Backup zip" msgstr "" -#: backup.py +#: app/backup.py msgid "Unsaved Backup" msgstr "" -#: backup.py backup.py +#: app/backup.py app/backup.py msgid "Save Backup As" msgstr "" -#: backup.py +#: app/backup.py msgid "Confirm Deletion" msgstr "" -#: backup.py +#: app/backup.py msgid "Do you wish to delete {} map?\n" msgid_plural "Do you wish to delete {} maps?\n" msgstr[0] "" msgstr[1] "" -#: backup.py +#: app/backup.py msgid "Restore:" msgstr "" -#: backup.py +#: app/backup.py msgid "Backup:" msgstr "" -#: backup.py +#: app/backup.py msgid "Checked" msgstr "" -#: backup.py +#: app/backup.py msgid "Delete Checked" msgstr "" -#: backup.py +#: app/backup.py msgid "BEEMOD {} - Backup / Restore Puzzles" msgstr "" -#: backup.py backup.py +#: app/backup.py app/backup.py msgid "New Backup" msgstr "" -#: backup.py backup.py +#: app/backup.py app/backup.py msgid "Open Backup" msgstr "" -#: backup.py backup.py +#: app/backup.py app/backup.py msgid "Save Backup" msgstr "" -#: backup.py +#: app/backup.py msgid "Remove Game" msgstr "" -#: backup.py +#: app/backup.py msgid "Game" msgstr "" -#: backup.py +#: app/backup.py msgid "Automatic Backup After Export" msgstr "" -#: backup.py +#: app/backup.py msgid "Keep (Per Game):" msgstr "" -#: backup.py +#: app/backup.py msgid "Backup/Restore Puzzles" msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "This item may not be rotated." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "This item can be pointed in 4 directions." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "This item can be positioned on the sides and center." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "This item can be centered in two directions, plus on the sides." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "This item can be placed like light strips." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "This item can be rotated on the floor to face 360 degrees." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "This item is positioned using a catapult trajectory." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "This item positions the dropper to hit target locations." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "This item does not accept any inputs." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "This item accepts inputs." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "This item has two input types (A and B), using the Input A and B items." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "This item does not output." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "This item has an output." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "This item has a timed output." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "This item does not take up any space inside walls." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "This item takes space inside the wall." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "This item cannot be placed anywhere..." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "This item can only be attached to ceilings." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "This item can only be placed on the floor." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "This item can be placed on floors and ceilings." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "This item can be placed on walls only." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "This item can be attached to walls and ceilings." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "This item can be placed on floors and walls." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "This item can be placed in any orientation." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "No Alternate Versions" msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "Excursion Funnels accept a on/off input and a directional input." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "" "This item can be rotated on the floor to face 360 degrees, for Reflection" " Cubes only." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "Properties:" msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "" "The number of entities used for this item. The Source engine limits this " "to 2048 in total. This provides a guide to how many of these items can be" " placed in a map at once." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "Description:" msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "" "Failed to open a web browser. Do you wish for the URL to be copied to the" " clipboard instead?" msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "More Info>>" msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "Change Defaults..." msgstr "" -#: contextWin.py +#: app/contextWin.py msgid "Change the default settings for this item when placed." msgstr "" -#: gameMan.py gameMan.py +#: app/gameMan.py app/gameMan.py msgid "BEE2 - Export Failed!" msgstr "" -#: gameMan.py +#: app/gameMan.py msgid "" "Compiler file {file} missing. Exit Steam applications, then press OK to " "verify your game cache. You can then export again." msgstr "" -#: gameMan.py +#: app/gameMan.py msgid "Copying compiler file {file} failed. Ensure {game} is not running." msgstr "" -#: gameMan.py +#: app/gameMan.py msgid "" "Ap-Tag Coop gun instance not found!\n" "Coop guns will not work - verify cache to fix." msgstr "" -#: gameMan.py +#: app/gameMan.py msgid "BEE2 - Aperture Tag Files Missing" msgstr "" -#: gameMan.py +#: app/gameMan.py msgid "Select the folder where the game executable is located ({appname})..." msgstr "" -#: gameMan.py gameMan.py gameMan.py gameMan.py gameMan.py gameMan.py +#: app/gameMan.py app/gameMan.py app/gameMan.py app/gameMan.py app/gameMan.py +#: app/gameMan.py msgid "BEE2 - Add Game" msgstr "" -#: gameMan.py +#: app/gameMan.py msgid "Find Game Exe" msgstr "" -#: gameMan.py +#: app/gameMan.py msgid "Executable" msgstr "" -#: gameMan.py +#: app/gameMan.py msgid "This does not appear to be a valid game folder!" msgstr "" -#: gameMan.py +#: app/gameMan.py msgid "Portal Stories: Mel doesn't have an editor!" msgstr "" -#: gameMan.py +#: app/gameMan.py msgid "Enter the name of this game:" msgstr "" -#: gameMan.py +#: app/gameMan.py msgid "This name is already taken!" msgstr "" -#: gameMan.py +#: app/gameMan.py msgid "Please enter a name for this game!" msgstr "" -#: gameMan.py +#: app/gameMan.py msgid "" "\n" " (BEE2 will quit, this is the last game set!)" msgstr "" -#: helpMenu.py +#: app/helpMenu.py msgid "Wiki..." msgstr "" -#: helpMenu.py +#: app/helpMenu.py msgid "Original Items..." msgstr "" -#: helpMenu.py +#: app/helpMenu.py msgid "Discord Server..." msgstr "" -#: helpMenu.py +#: app/helpMenu.py msgid "aerond's Music Changer..." msgstr "" -#: helpMenu.py +#: app/helpMenu.py msgid "Application Repository..." msgstr "" -#: helpMenu.py +#: app/helpMenu.py msgid "Items Repository..." msgstr "" -#: helpMenu.py +#: app/helpMenu.py msgid "Submit Application Bugs..." msgstr "" -#: helpMenu.py +#: app/helpMenu.py msgid "Submit Item Bugs..." msgstr "" -#: helpMenu.py paletteLoader.py +#: app/helpMenu.py app/paletteLoader.py msgid "Portal 2" msgstr "" -#: helpMenu.py paletteLoader.py +#: app/helpMenu.py app/paletteLoader.py msgid "Aperture Tag" msgstr "" -#: helpMenu.py +#: app/helpMenu.py msgid "Portal Stories: Mel" msgstr "" -#: helpMenu.py +#: app/helpMenu.py msgid "Thinking With Time Machine" msgstr "" -#: helpMenu.py itemPropWin.py +#: app/helpMenu.py app/itemPropWin.py msgid "Close" msgstr "" -#: helpMenu.py +#: app/helpMenu.py msgid "Help" msgstr "" -#: helpMenu.py +#: app/helpMenu.py msgid "BEE2 Credits" msgstr "" -#: helpMenu.py +#: app/helpMenu.py msgid "Credits..." msgstr "" -#: itemPropWin.py +#: app/itemPropWin.py msgid "Start Position" msgstr "" -#: itemPropWin.py +#: app/itemPropWin.py msgid "End Position" msgstr "" -#: itemPropWin.py +#: app/itemPropWin.py msgid "" "Delay \n" "(0=infinite)" msgstr "" -#: itemPropWin.py +#: app/itemPropWin.py msgid "No Properties available!" msgstr "" -#: itemconfig.py +#: app/itemconfig.py msgid "Choose a Color" msgstr "" -#: loadScreen.py -msgid "Skipped!" -msgstr "" - -#: loadScreen.py -msgid "Version: " -msgstr "" - -#: loadScreen.py optionWindow.py packageMan.py selectorWin.py -msgid "Cancel" -msgstr "" - -#: loadScreen.py tagsPane.py -msgid "Packages" -msgstr "" - -#: loadScreen.py -msgid "Loading Objects" -msgstr "" - -#: loadScreen.py -msgid "Loading Images" -msgstr "" - -#: loadScreen.py -msgid "Initialising UI" -msgstr "" - -#: loadScreen.py -msgid "Better Extended Editor for Portal 2" -msgstr "" - -#: logWindow.py +#: app/logWindow.py msgid "Debug messages" msgstr "" -#: logWindow.py +#: app/logWindow.py msgid "Default" msgstr "" -#: logWindow.py +#: app/logWindow.py msgid "Warnings Only" msgstr "" -#: logWindow.py +#: app/logWindow.py msgid "Logs - {}" msgstr "" -#: logWindow.py +#: app/logWindow.py msgid "Copy" msgstr "" -#: logWindow.py +#: app/logWindow.py msgid "Show:" msgstr "" -#: music_conf.py +#: app/music_conf.py msgid "Select Background Music - Base" msgstr "" -#: music_conf.py +#: app/music_conf.py msgid "" "This controls the background music used for a map. Expand the dropdown to" " set tracks for specific test elements." msgstr "" -#: music_conf.py +#: app/music_conf.py msgid "" "Add no music to the map at all. Testing Element-specific music may still " "be added." msgstr "" -#: music_conf.py +#: app/music_conf.py msgid "Propulsion Gel SFX" msgstr "" -#: music_conf.py +#: app/music_conf.py msgid "Repulsion Gel SFX" msgstr "" -#: music_conf.py +#: app/music_conf.py msgid "Excursion Funnel Music" msgstr "" -#: music_conf.py music_conf.py +#: app/music_conf.py app/music_conf.py msgid "Synced Funnel Music" msgstr "" -#: music_conf.py +#: app/music_conf.py msgid "Select Excursion Funnel Music" msgstr "" -#: music_conf.py +#: app/music_conf.py msgid "Set the music used while inside Excursion Funnels." msgstr "" -#: music_conf.py +#: app/music_conf.py msgid "Have no music playing when inside funnels." msgstr "" -#: music_conf.py +#: app/music_conf.py msgid "Select Repulsion Gel Music" msgstr "" -#: music_conf.py +#: app/music_conf.py msgid "Select the music played when players jump on Repulsion Gel." msgstr "" -#: music_conf.py +#: app/music_conf.py msgid "Add no music when jumping on Repulsion Gel." msgstr "" -#: music_conf.py +#: app/music_conf.py msgid "Select Propulsion Gel Music" msgstr "" -#: music_conf.py +#: app/music_conf.py msgid "" "Select music played when players have large amounts of horizontal " "velocity." msgstr "" -#: music_conf.py +#: app/music_conf.py msgid "Add no music while running fast." msgstr "" -#: music_conf.py +#: app/music_conf.py msgid "Base: " msgstr "" -#: music_conf.py +#: app/music_conf.py msgid "Funnel:" msgstr "" -#: music_conf.py +#: app/music_conf.py msgid "Bounce:" msgstr "" -#: music_conf.py +#: app/music_conf.py msgid "Speed:" msgstr "" -#: optionWindow.py +#: app/optionWindow.py +msgid "" +"\n" +"Launch Game?" +msgstr "" + +#: app/optionWindow.py +msgid "" +"\n" +"Minimise BEE2?" +msgstr "" + +#: app/optionWindow.py +msgid "" +"\n" +"Launch Game and minimise BEE2?" +msgstr "" + +#: app/optionWindow.py +msgid "" +"\n" +"Quit BEE2?" +msgstr "" + +#: app/optionWindow.py +msgid "" +"\n" +"Launch Game and quit BEE2?" +msgstr "" + +#: app/optionWindow.py msgid "BEE2 Options" msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "" "Package cache times have been reset. These will now be extracted during " "the next export." msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "\"Preserve Game Resources\" has been disabled." msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "Packages Reset" msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "General" msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "Windows" msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "Development" msgstr "" -#: optionWindow.py packageMan.py selectorWin.py +#: app/optionWindow.py app/packageMan.py app/selector_win.py msgid "OK" msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "After Export:" msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "Do Nothing" msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "Minimise BEE2" msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "Quit BEE2" msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "After exports, do nothing and keep the BEE2 in focus." msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "After exports, minimise to the taskbar/dock." msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "After exports, quit the BEE2." msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "Launch Game" msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "After exporting, launch the selected game automatically." msgstr "" -#: optionWindow.py optionWindow.py +#: app/optionWindow.py app/optionWindow.py msgid "Play Sounds" msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "" "Pyglet is either not installed or broken.\n" "Sound effects have been disabled." msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "Reset Package Caches" msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "Force re-extracting all package resources." msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "Keep windows inside screen" msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "" "Prevent sub-windows from moving outside the screen borders. If you have " "multiple monitors, disable this." msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "Keep loading screens on top" msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "" "Force loading screens to be on top of other windows. Since they don't " "appear on the taskbar/dock, they can't be brought to the top easily " "again." msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "Reset All Window Positions" msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "Log missing entity counts" msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "" "When loading items, log items with missing entity counts in their " "properties.txt file." msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "Log when item doesn't have a style" msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "" "Log items have no applicable version for a particular style.This usually " "means it will look very bad." msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "Log when item uses parent's style" msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "" "Log when an item reuses a variant from a parent style (1970s using 1950s " "items, for example). This is usually fine, but may need to be fixed." msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "Log missing packfile resources" msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "" "Log when the resources a \"PackList\" refers to are not present in the " "zip. This may be fine (in a prerequisite zip), but it often indicates an " "error." msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "Preserve Game Directories" msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "" -"When exporting, do not overwrite \n" -"\"bee2/\" and\n" -"\"sdk_content/maps/bee2/\".\n" -"Enable if you're developing new content, to ensure it is not overwritten." +"When exporting, do not copy resources to \n" +"\"bee2/\" and \"sdk_content/maps/bee2/\".\n" +"Only enable if you're developing new content, to ensure it is not " +"overwritten." msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "Show Log Window" msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "Show the log file in real-time." msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "Force Editor Models" msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "" "Make all props_map_editor models available for use. Portal 2 has a limit " "of 1024 models loaded in memory at once, so we need to disable unused " "ones to free this up." msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "Dump All objects" msgstr "" -#: optionWindow.py +#: app/optionWindow.py msgid "Dump Items list" msgstr "" -#: packageMan.py +#: app/packageMan.py msgid "BEE2 - Restart Required!" msgstr "" -#: packageMan.py +#: app/packageMan.py msgid "" "Changing enabled packages requires a restart.\n" "Continue?" msgstr "" -#: packageMan.py +#: app/packageMan.py msgid "BEE2 - Manage Packages" msgstr "" -#: paletteLoader.py +#: app/paletteLoader.py msgid "" msgstr "" -#: paletteLoader.py +#: app/paletteLoader.py msgid "Blank" msgstr "" -#: paletteLoader.py +#: app/paletteLoader.py msgid "BEEMod" msgstr "" -#: paletteLoader.py +#: app/paletteLoader.py msgid "Portal 2 Collapsed" msgstr "" -#: richTextBox.py +#: app/richTextBox.py msgid "Open \"{}\" in the default browser?" msgstr "" -#: selectorWin.py +#: app/selector_win.py msgid "Do not add anything." msgstr "" -#: selectorWin.py +#: app/selector_win.py msgid "" msgstr "" -#: selectorWin.py selectorWin.py +#: app/selector_win.py app/selector_win.py msgid "Suggested" msgstr "" -#: selectorWin.py +#: app/selector_win.py msgid "Play a sample of this item." msgstr "" -#: selectorWin.py +#: app/selector_win.py msgid "Reset to Default" msgstr "" -#: selectorWin.py +#: app/selector_win.py msgid "Other" msgstr "" -#: selectorWin.py +#: app/selector_win.py msgid "Author: {}" msgid_plural "Authors: {}" msgstr[0] "" msgstr[1] "" -#: selectorWin.py +#: app/selector_win.py msgid "Color: R={r}, G={g}, B={b}" msgstr "" -#: signage_ui.py signage_ui.py +#: app/signage_ui.py app/signage_ui.py msgid "Configure Signage" msgstr "" -#: signage_ui.py +#: app/signage_ui.py msgid "Selected" msgstr "" -#: signage_ui.py +#: app/signage_ui.py msgid "Signage: {}" msgstr "" -#: tagsPane.py +#: app/tagsPane.py msgid "Tags" msgstr "" -#: tagsPane.py +#: app/tagsPane.py msgid "Authors" msgstr "" -#: tagsPane.py +#: app/tagsPane.py msgid "Any" msgstr "" -#: tagsPane.py +#: app/tagsPane.py msgid "All" msgstr "" -#: tagsPane.py +#: app/tagsPane.py msgid "Available Tags (click):" msgstr "" -#: utils.py -msgid "__LANG_USE_SANS_SERIF__" -msgstr "" - -#: voiceEditor.py +#: app/voiceEditor.py msgid "Singleplayer" msgstr "" -#: voiceEditor.py +#: app/voiceEditor.py msgid "Cooperative" msgstr "" -#: voiceEditor.py +#: app/voiceEditor.py msgid "ATLAS (SP/Coop)" msgstr "" -#: voiceEditor.py +#: app/voiceEditor.py msgid "P-Body (SP/Coop)" msgstr "" -#: voiceEditor.py +#: app/voiceEditor.py msgid "Human characters (Bendy and Chell)" msgstr "" -#: voiceEditor.py +#: app/voiceEditor.py msgid "AI characters (ATLAS, P-Body, or Coop)" msgstr "" -#: voiceEditor.py +#: app/voiceEditor.py msgid "Death - Toxic Goo" msgstr "" -#: voiceEditor.py +#: app/voiceEditor.py msgid "Death - Turrets" msgstr "" -#: voiceEditor.py +#: app/voiceEditor.py msgid "Death - Crusher" msgstr "" -#: voiceEditor.py +#: app/voiceEditor.py msgid "Death - LaserField" msgstr "" -#: voiceEditor.py +#: app/voiceEditor.py msgid "Transcript:" msgstr "" -#: voiceEditor.py +#: app/voiceEditor.py msgid "Save" msgstr "" -#: voiceEditor.py +#: app/voiceEditor.py msgid "Resp" msgstr "" -#: voiceEditor.py +#: app/voiceEditor.py msgid "BEE2 - Configure \"{}\"" msgstr "" -#: voiceEditor.py +#: app/voiceEditor.py msgid "Mid - Chamber" msgstr "" -#: voiceEditor.py +#: app/voiceEditor.py msgid "" "Lines played during the actual chamber, after specific events have " "occurred." msgstr "" -#: voiceEditor.py +#: app/voiceEditor.py msgid "Responses" msgstr "" -#: voiceEditor.py +#: app/voiceEditor.py msgid "Lines played in response to certain events in Coop." msgstr "" -#: voiceEditor.py +#: app/voiceEditor.py msgid "No Name!" msgstr "" -#: voiceEditor.py +#: app/voiceEditor.py msgid "No Name?" msgstr "" diff --git a/i18n/es.po b/i18n/es.po index 1c1744c40..533e66d1c 100644 --- a/i18n/es.po +++ b/i18n/es.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2020-07-18 11:58+1000\n" +"POT-Creation-Date: 2020-09-20 10:31-0700\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: es\n" @@ -12,29 +12,66 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.6.0\n" +"Generated-By: Babel 2.8.0\n" -#: CheckDetails.py:220 +#: loadScreen.py:199 +msgid "Skipped!" +msgstr "Saltado!" + +#: loadScreen.py:200 +msgid "Version: " +msgstr "" + +#: app/optionWindow.py:259 app/packageMan.py:116 app/selector_win.py:718 +#: loadScreen.py:201 +msgid "Cancel" +msgstr "Cancelar" + +#: app/tagsPane.py:48 loadScreen.py:211 +msgid "Packages" +msgstr "Paquetes" + +#: loadScreen.py:212 +msgid "Loading Objects" +msgstr "Cargando Objetos" + +#: loadScreen.py:213 +msgid "Loading Images" +msgstr "Cargando Imagenes" + +#: loadScreen.py:214 +msgid "Initialising UI" +msgstr "Iniciando Interfaz" + +#: loadScreen.py:215 +msgid "Better Extended Editor for Portal 2" +msgstr "" + +#: utils.py:841 +msgid "__LANG_USE_SANS_SERIF__" +msgstr "" + +#: app/CheckDetails.py:219 msgid "Toggle all checkboxes." msgstr "Activar todas las casillas." -#: CompilerPane.py:66 +#: app/CompilerPane.py:64 msgid "ATLAS" msgstr "ATLAS" -#: CompilerPane.py:67 +#: app/CompilerPane.py:65 msgid "P-Body" msgstr "P-Body" -#: CompilerPane.py:68 voiceEditor.py:40 +#: app/CompilerPane.py:66 app/voiceEditor.py:38 msgid "Chell" msgstr "Chell" -#: CompilerPane.py:69 voiceEditor.py:39 +#: app/CompilerPane.py:67 app/voiceEditor.py:37 msgid "Bendy" msgstr "Bendy" -#: CompilerPane.py:122 +#: app/CompilerPane.py:120 msgid "" "Brushes form the walls or other parts of the test chamber. If this is " "high, it may help to reduce the size of the map or remove intricate " @@ -44,7 +81,7 @@ msgstr "" " esto es alto, te puede servir como guía para que puedas reducir el " "tamaño del mapa o eliminar formas complejas del mismo." -#: CompilerPane.py:129 +#: app/CompilerPane.py:127 #, fuzzy msgid "" "Entities are the things in the map that have functionality. Removing " @@ -61,7 +98,7 @@ msgstr "" "enlistado en la parte superior derecha de la ventana de descripción de " "los mismos." -#: CompilerPane.py:139 +#: app/CompilerPane.py:137 #, fuzzy msgid "" "Overlays are smaller images affixed to surfaces, like signs or indicator " @@ -72,59 +109,59 @@ msgstr "" "pueden ser los símbolos, indicadores o las lineas de conexión. Ocultando " "largas lineas de conexión o cambiándolas a indicadores reducirá esto." -#: CompilerPane.py:275 +#: app/CompilerPane.py:273 msgid "Corridor" msgstr "Pasillo" -#: CompilerPane.py:316 +#: app/CompilerPane.py:314 msgid "" "Randomly choose a corridor. This is saved in the puzzle data and will not" " change." msgstr "" -#: CompilerPane.py:322 UI.py:657 +#: app/CompilerPane.py:320 app/UI.py:664 msgid "Random" msgstr "" -#: CompilerPane.py:421 +#: app/CompilerPane.py:419 msgid "Image Files" msgstr "Archivos de imagenes" -#: CompilerPane.py:504 +#: app/CompilerPane.py:502 msgid "" "Options on this panel can be changed \n" "without exporting or restarting the game." msgstr "" -#: CompilerPane.py:519 +#: app/CompilerPane.py:517 msgid "Map Settings" msgstr "Configuración del Mapa" -#: CompilerPane.py:524 +#: app/CompilerPane.py:522 msgid "Compile Settings" msgstr "Configuración de la Compilación" -#: CompilerPane.py:538 +#: app/CompilerPane.py:536 msgid "Thumbnail" msgstr "Miniatura" -#: CompilerPane.py:546 +#: app/CompilerPane.py:544 msgid "Auto" msgstr "Automático" -#: CompilerPane.py:554 +#: app/CompilerPane.py:552 msgid "PeTI" msgstr "PeTI" -#: CompilerPane.py:562 +#: app/CompilerPane.py:560 msgid "Custom:" msgstr "Personalizada:" -#: CompilerPane.py:580 +#: app/CompilerPane.py:578 msgid "Cleanup old screenshots" msgstr "Limpiar viejas capturas de pantalla" -#: CompilerPane.py:590 +#: app/CompilerPane.py:588 msgid "" "Override the map image to use a screenshot automatically taken from the " "beginning of a chamber. Press F5 to take a new screenshot. If the map has" @@ -137,11 +174,11 @@ msgstr "" "recientemente (en las últimas horas), se utilizará una captura por " "defecto de la visión del editor del juego." -#: CompilerPane.py:598 +#: app/CompilerPane.py:596 msgid "Use the normal editor view for the map preview image." msgstr "Utiliza la imagen por defecto del editor del juego." -#: CompilerPane.py:600 +#: app/CompilerPane.py:598 msgid "" "Use a custom image for the map preview image. Click the screenshot to " "select.\n" @@ -151,7 +188,7 @@ msgstr "" "tu mapa. Haz clic en el rectángulo negro de abajo para seleccionarla. \n" "Las imágenes serán convertidas a formato JPEG de ser necesario." -#: CompilerPane.py:617 +#: app/CompilerPane.py:615 msgid "" "Automatically delete unused Automatic screenshots. Disable if you want to" " keep things in \"portal2/screenshots\". " @@ -160,19 +197,19 @@ msgstr "" "utilizadas. Deshabilita esta casilla si deseas mantener esas capturas. " "Las mismas se encuentran en: \"portal2/screenshots\"." -#: CompilerPane.py:628 +#: app/CompilerPane.py:626 msgid "Lighting:" msgstr "Iluminación:" -#: CompilerPane.py:635 +#: app/CompilerPane.py:633 msgid "Fast" msgstr "Rápida" -#: CompilerPane.py:642 +#: app/CompilerPane.py:640 msgid "Full" msgstr "Completa" -#: CompilerPane.py:650 +#: app/CompilerPane.py:648 msgid "" "Compile with lower-quality, fast lighting. This speeds up compile times, " "but does not appear as good. Some shadows may appear wrong.\n" @@ -183,7 +220,7 @@ msgstr "" "incorrectas. En el momento que se publica el mapa, esta opción no será " "tenida en cuenta." -#: CompilerPane.py:657 +#: app/CompilerPane.py:655 #, fuzzy msgid "" "Compile with high-quality lighting. This looks correct, but takes longer " @@ -195,11 +232,11 @@ msgstr "" "efectos lumínicos. En el momento que se publica el mapa, esto siempre se " "activará de forma automática." -#: CompilerPane.py:664 +#: app/CompilerPane.py:662 msgid "Dump packed files to:" msgstr "Envíar archivos empacados a:" -#: CompilerPane.py:689 +#: app/CompilerPane.py:687 msgid "" "When compiling, dump all files which were packed into the map. Useful if " "you're intending to edit maps in Hammer." @@ -208,19 +245,19 @@ msgstr "" " empacados dentro del mapa. Útil si tienes la intención de editar los " "mapas en Hammer." -#: CompilerPane.py:695 +#: app/CompilerPane.py:693 msgid "Last Compile:" msgstr "Última Compilación:" -#: CompilerPane.py:705 +#: app/CompilerPane.py:703 msgid "Entity" msgstr "Entidades" -#: CompilerPane.py:725 +#: app/CompilerPane.py:723 msgid "Overlay" msgstr "Overlays" -#: CompilerPane.py:744 +#: app/CompilerPane.py:742 msgid "" "Refresh the compile progress bars. Press after a compile has been " "performed to show the new values." @@ -229,19 +266,19 @@ msgstr "" "Pulse después de que se haya realizado una compilación para mostrar los " "nuevos valores." -#: CompilerPane.py:750 +#: app/CompilerPane.py:748 msgid "Brush" msgstr "" -#: CompilerPane.py:778 +#: app/CompilerPane.py:776 msgid "Voicelines:" msgstr "Líneas de voz:" -#: CompilerPane.py:785 +#: app/CompilerPane.py:783 msgid "Use voiceline priorities" msgstr "Usar líneas de voces prioritarias" -#: CompilerPane.py:791 +#: app/CompilerPane.py:789 msgid "" "Only choose the highest-priority voicelines. This means more generic " "lines will can only be chosen if few test elements are in the map. If " @@ -252,19 +289,19 @@ msgstr "" " prueba en el mapa. Si se deshabilita, cualquier línea aplicable será " "utilizada." -#: CompilerPane.py:798 +#: app/CompilerPane.py:796 msgid "Spawn at:" msgstr "Aparecer en:" -#: CompilerPane.py:809 +#: app/CompilerPane.py:807 msgid "Entry Door" msgstr "Puerta de entrada" -#: CompilerPane.py:816 +#: app/CompilerPane.py:814 msgid "Elevator" msgstr "Elevador" -#: CompilerPane.py:826 +#: app/CompilerPane.py:824 #, fuzzy msgid "" "When previewing in SP, spawn inside the entry elevator. Use this to " @@ -275,7 +312,7 @@ msgstr "" "si se llega atravesar la puerta de salida. Utilizar esta opción si deseas" " examinar los pasillos de entrada y salida del mapa." -#: CompilerPane.py:831 +#: app/CompilerPane.py:829 #, fuzzy msgid "When previewing in SP, spawn just before the entry door." msgstr "" @@ -283,49 +320,49 @@ msgstr "" "antes de la puerta de entrada. Cuando atravieses la puerta de salida, el " "mapa se reiniciará." -#: CompilerPane.py:837 +#: app/CompilerPane.py:835 msgid "Corridor:" msgstr "Pasillo:" -#: CompilerPane.py:856 +#: app/CompilerPane.py:854 msgid "SP Entry:" msgstr "Entrada SP:" -#: CompilerPane.py:861 +#: app/CompilerPane.py:859 msgid "SP Exit:" msgstr "Salida SP:" -#: CompilerPane.py:866 +#: app/CompilerPane.py:864 msgid "Coop:" msgstr "Coop:" -#: CompilerPane.py:872 +#: app/CompilerPane.py:870 msgid "Player Model (SP):" msgstr "Modelo del jugador (SP):" -#: CompilerPane.py:896 +#: app/CompilerPane.py:894 msgid "Compile Options" msgstr "Opciones de Compilación" -#: CompilerPane.py:914 +#: app/CompilerPane.py:912 msgid "Compiler Options - {}" msgstr "Opciones de Compilación - {}" -#: StyleVarPane.py:33 +#: app/StyleVarPane.py:31 msgid "Multiverse Cave" msgstr "Voz de Cave Johnson (Workshop)" -#: StyleVarPane.py:35 +#: app/StyleVarPane.py:33 msgid "Play the Workshop Cave Johnson lines on map start." msgstr "" "Reproduce la voz de Cave Johnson que fue programada para el Workshop en " "el comienzo del mapa." -#: StyleVarPane.py:40 +#: app/StyleVarPane.py:38 msgid "Prevent Portal Bump (fizzler)" msgstr "Prevenir trucos con los portales (En desintegrador)" -#: StyleVarPane.py:42 +#: app/StyleVarPane.py:40 msgid "" "Add portal bumpers to make it more difficult to portal across fizzler " "edges. This can prevent placing portals in tight spaces near fizzlers, or" @@ -334,19 +371,19 @@ msgstr "" "Añade un volumen anti-portal que hace más difícil el colocar portales a " "través de los bordes del desintegrador." -#: StyleVarPane.py:49 +#: app/StyleVarPane.py:47 msgid "Suppress Mid-Chamber Dialogue" msgstr "Suprimir el diálogo de mitad de cámara" -#: StyleVarPane.py:51 +#: app/StyleVarPane.py:49 msgid "Disable all voicelines other than entry and exit lines." msgstr "Deshabilita todas las líneas de voz exceptuando las de entrada y salida." -#: StyleVarPane.py:56 +#: app/StyleVarPane.py:54 msgid "Unlock Default Items" msgstr "Desbloquear elementos obligatorios" -#: StyleVarPane.py:58 +#: app/StyleVarPane.py:56 msgid "" "Allow placing and deleting the mandatory Entry/Exit Doors and Large " "Observation Room. Use with caution, this can have weird results!" @@ -355,13 +392,13 @@ msgstr "" " como la gran sala de observación. Solo recomendable con la gran sala de " "observación." -#: StyleVarPane.py:65 +#: app/StyleVarPane.py:63 msgid "Allow Adding Goo Mist" msgstr "" "Permitir agregar vapor sobre la \n" "superficie del pringue mortal" -#: StyleVarPane.py:67 +#: app/StyleVarPane.py:65 msgid "" "Add mist particles above Toxic Goo in certain styles. This can increase " "the entity count significantly with large, complex goo pits, so disable " @@ -372,11 +409,11 @@ msgstr "" "creado grandes y complejos pozos de ácido, así que deshabilítalo si es " "necesario." -#: StyleVarPane.py:74 +#: app/StyleVarPane.py:72 msgid "Light Reversible Excursion Funnels" msgstr "" -#: StyleVarPane.py:76 +#: app/StyleVarPane.py:74 msgid "" "Funnels emit a small amount of light. However, if multiple funnels are " "near each other and can reverse polarity, this can cause lighting issues." @@ -384,84 +421,84 @@ msgid "" " do not have this issue." msgstr "" -#: StyleVarPane.py:84 +#: app/StyleVarPane.py:82 msgid "Enable Shape Framing" msgstr "" -#: StyleVarPane.py:86 +#: app/StyleVarPane.py:84 msgid "" "After 10 shape-type antlines are used, the signs repeat. With this " "enabled, colored frames will be added to distinguish them." msgstr "" -#: StyleVarPane.py:155 +#: app/StyleVarPane.py:153 msgid "Default: On" msgstr "Predeterminado: Activado" -#: StyleVarPane.py:157 +#: app/StyleVarPane.py:155 msgid "Default: Off" msgstr "Predeterminado: Desactivado" -#: StyleVarPane.py:161 +#: app/StyleVarPane.py:159 msgid "Styles: Unstyled" msgstr "Estilos: Sin estilo" -#: StyleVarPane.py:171 +#: app/StyleVarPane.py:169 msgid "Styles: All" msgstr "Estilos: Todos" -#: StyleVarPane.py:179 +#: app/StyleVarPane.py:177 msgid "Style: {}" msgid_plural "Styles: {}" msgstr[0] "Estilo: {}" msgstr[1] "Plural: Estilos: {}" -#: StyleVarPane.py:233 +#: app/StyleVarPane.py:231 #, fuzzy msgid "Style/Item Properties" msgstr "Propiedades de Estilo" -#: StyleVarPane.py:252 +#: app/StyleVarPane.py:250 msgid "Styles" msgstr "" -#: StyleVarPane.py:271 +#: app/StyleVarPane.py:269 msgid "All:" msgstr "En todos:" -#: StyleVarPane.py:274 +#: app/StyleVarPane.py:272 msgid "Selected Style:" msgstr "Estilo seleccionado:" -#: StyleVarPane.py:282 +#: app/StyleVarPane.py:280 msgid "Other Styles:" msgstr "Otros Estilos:" -#: StyleVarPane.py:287 +#: app/StyleVarPane.py:285 msgid "No Options!" msgstr "Sin Opciones!" -#: StyleVarPane.py:293 +#: app/StyleVarPane.py:291 msgid "None!" msgstr "Ninguna!" -#: StyleVarPane.py:364 +#: app/StyleVarPane.py:362 msgid "Items" msgstr "" -#: SubPane.py:84 +#: app/SubPane.py:85 msgid "Hide/Show the \"{}\" window." msgstr "Oculta/Muestra las \"{}\" ventanas." -#: UI.py:67 +#: app/UI.py:70 msgid "Export..." msgstr "Exportar..." -#: UI.py:591 +#: app/UI.py:598 msgid "Select Skyboxes" msgstr "Seleccionar Cielos" -#: UI.py:592 +#: app/UI.py:599 msgid "" "The skybox decides what the area outside the chamber is like. It chooses " "the colour of sky (seen in some items), the style of bottomless pit (if " @@ -473,19 +510,19 @@ msgstr "" "precipicios, así como el color de la \"neblina\" vistos en las cámaras " "largas." -#: UI.py:600 +#: app/UI.py:607 msgid "3D Skybox" msgstr "3D Skybox" -#: UI.py:601 +#: app/UI.py:608 msgid "Fog Color" msgstr "Color de Neblina" -#: UI.py:608 +#: app/UI.py:615 msgid "Select Additional Voice Lines" msgstr "Selecciona línea de voces adicionales" -#: UI.py:609 +#: app/UI.py:616 msgid "" "Voice lines choose which extra voices play as the player enters or exits " "a chamber. They are chosen based on which items are present in the map. " @@ -497,31 +534,31 @@ msgstr "" "elementos presentes en el mapa. Las líneas de voz adicionales de Cave " "Johnson se controlan por separado en las propiedades del estilo." -#: UI.py:614 +#: app/UI.py:621 msgid "Add no extra voice lines, only Multiverse Cave if enabled." msgstr "No añadir voces de línea adicionales, only Multiverse Cave if enabled." -#: UI.py:616 +#: app/UI.py:623 msgid "" msgstr "" -#: UI.py:620 +#: app/UI.py:627 msgid "Characters" msgstr "Caracteres" -#: UI.py:621 +#: app/UI.py:628 msgid "Turret Shoot Monitor" msgstr "" -#: UI.py:622 +#: app/UI.py:629 msgid "Monitor Visuals" msgstr "" -#: UI.py:629 +#: app/UI.py:636 msgid "Select Style" msgstr "Selecciona Estilo" -#: UI.py:630 +#: app/UI.py:637 msgid "" "The Style controls many aspects of the map. It decides the materials used" " for walls, the appearance of entrances and exits, the design for most " @@ -537,15 +574,15 @@ msgstr "" "El Estilo define ampliamente el período de tiempo en el que se establece " "una cámara de pruebas." -#: UI.py:641 +#: app/UI.py:648 msgid "Elevator Videos" msgstr "Videos del elevador" -#: UI.py:648 +#: app/UI.py:655 msgid "Select Elevator Video" msgstr "Selecciona el video del Elevador" -#: UI.py:649 +#: app/UI.py:656 msgid "" "Set the video played on the video screens in modern Aperture elevator " "rooms. Not all styles feature these. If set to \"None\", a random video " @@ -556,23 +593,23 @@ msgstr "" "seleccionado \"Ninguno\", se elegirá un vídeo aleatorio cada vez que se " "juegue el mapa, como en el editor de niveles del juego predeterminado." -#: UI.py:653 +#: app/UI.py:660 msgid "This style does not have a elevator video screen." msgstr "Este estilo no cuenta con una pantalla en el elevador." -#: UI.py:658 +#: app/UI.py:665 msgid "Choose a random video." msgstr "Se elegirá un video aleatorio." -#: UI.py:662 +#: app/UI.py:669 msgid "Multiple Orientations" msgstr "Orientación Multiple" -#: UI.py:883 +#: app/UI.py:897 msgid "Selected Items and Style successfully exported!" msgstr "¡Estilo y elementos exportados correctamente!" -#: UI.py:885 +#: app/UI.py:899 msgid "" "\n" "\n" @@ -580,403 +617,397 @@ msgid "" "editor wall previews are changed." msgstr "" -#: UI.py:898 -msgid "" -"\n" -" Launch Game?" -msgstr "" - -#: UI.py:1113 +#: app/UI.py:1131 msgid "Delete Palette \"{}\"" msgstr "Borrar Paleta \"{}\"" -#: UI.py:1189 +#: app/UI.py:1207 msgid "BEE2 - Save Palette" msgstr "BEE2 - Guardar Paleta" -#: UI.py:1190 +#: app/UI.py:1208 msgid "Enter a name:" msgstr "" -#: UI.py:1199 +#: app/UI.py:1217 msgid "This palette already exists. Overwrite?" msgstr "Esta paleta ya existe. Desea reemplazarla?" -#: UI.py:1228 gameMan.py:1529 +#: app/UI.py:1249 app/gameMan.py:1527 msgid "Are you sure you want to delete \"{}\"?" msgstr "Estas seguro que deseas borrar \"{}?\"" -#: UI.py:1255 +#: app/UI.py:1277 msgid "Clear Palette" msgstr "Limpiar la Paleta" -#: UI.py:1291 UI.py:1727 +#: app/UI.py:1313 app/UI.py:1747 msgid "Delete Palette" msgstr "Borrar Paleta" -#: UI.py:1311 +#: app/UI.py:1333 msgid "Save Palette..." msgstr "Guardar Paleta..." -#: UI.py:1316 UI.py:1750 +#: app/UI.py:1338 app/UI.py:1770 msgid "Save Palette As..." msgstr "Guardar Paleta Como..." -#: UI.py:1327 UI.py:1738 +#: app/UI.py:1349 app/UI.py:1758 msgid "Save Settings in Palettes" msgstr "" -#: UI.py:1345 music_conf.py:204 +#: app/UI.py:1367 app/music_conf.py:205 msgid "Music: " msgstr "Música:" -#: UI.py:1371 +#: app/UI.py:1393 msgid "{arr} Use Suggested {arr}" msgstr "{arr} Usar Recomendado {arr}" -#: UI.py:1387 +#: app/UI.py:1409 msgid "Style: " msgstr "Estilo:" -#: UI.py:1389 +#: app/UI.py:1411 msgid "Voice: " msgstr "Voz:" -#: UI.py:1390 +#: app/UI.py:1412 msgid "Skybox: " msgstr "Skybox:" -#: UI.py:1391 +#: app/UI.py:1413 msgid "Elev Vid: " msgstr "Vid Elev" -#: UI.py:1409 +#: app/UI.py:1431 msgid "" "Enable or disable particular voice lines, to prevent them from being " "added." msgstr "Habilita o deshabilita ciertas lineas de voces." -#: UI.py:1512 +#: app/UI.py:1534 msgid "All Items: " msgstr "Todos los Elementos:" -#: UI.py:1646 +#: app/UI.py:1666 msgid "Export to \"{}\"..." msgstr "" -#: UI.py:1674 backup.py:876 +#: app/UI.py:1694 app/backup.py:872 msgid "File" msgstr "Archivo" -#: UI.py:1681 +#: app/UI.py:1701 msgid "Export" msgstr "Exportar" -#: UI.py:1688 backup.py:880 +#: app/UI.py:1708 app/backup.py:876 msgid "Add Game" msgstr "Añadir Juego" -#: UI.py:1692 +#: app/UI.py:1712 #, fuzzy msgid "Uninstall from Selected Game" msgstr "Borrar Juego Seleccionado" -#: UI.py:1696 +#: app/UI.py:1716 msgid "Backup/Restore Puzzles..." msgstr "Copias de seguridad/Restaurar mapas..." -#: UI.py:1700 +#: app/UI.py:1720 msgid "Manage Packages..." msgstr "Administrar Paquetes..." -#: UI.py:1705 +#: app/UI.py:1725 msgid "Options" msgstr "Ociones" -#: UI.py:1710 gameMan.py:1208 +#: app/UI.py:1730 app/gameMan.py:1206 msgid "Quit" msgstr "Quitar" -#: UI.py:1720 +#: app/UI.py:1740 msgid "Palette" msgstr "Paleta" -#: UI.py:1722 +#: app/UI.py:1742 msgid "Clear" msgstr "Limpiar" -#: UI.py:1731 +#: app/UI.py:1751 msgid "Fill Palette" msgstr "Rellenar Paleta" -#: UI.py:1745 +#: app/UI.py:1765 msgid "Save Palette" msgstr "Guardar Paleta" -#: UI.py:1760 +#: app/UI.py:1780 msgid "View" msgstr "" -#: UI.py:1879 +#: app/UI.py:1899 msgid "Palettes" msgstr "" -#: UI.py:1904 +#: app/UI.py:1924 msgid "Export Options" msgstr "Opciones de Exportación" -#: UI.py:1936 +#: app/UI.py:1956 msgid "Fill empty spots in the palette with random items." msgstr "Rellenar espacios vacíos de la paleta con elementos aleatorios." -#: backup.py:81 +#: app/backup.py:79 msgid "Copying maps" msgstr "Copiando mapas" -#: backup.py:86 +#: app/backup.py:84 msgid "Loading maps" msgstr "Cargando mapas" -#: backup.py:91 +#: app/backup.py:89 msgid "Deleting maps" msgstr "" -#: backup.py:142 +#: app/backup.py:140 msgid "Failed to parse this puzzle file. It can still be backed up." msgstr "Error al analizar este mapa. Pero es posible hacer una copia de seguridad." -#: backup.py:146 +#: app/backup.py:144 msgid "No description found." msgstr "No se ha encontrado una descripción." -#: backup.py:177 +#: app/backup.py:175 msgid "Coop" msgstr "Cooperativo" -#: backup.py:177 +#: app/backup.py:175 msgid "SP" msgstr "Un solo jugador" -#: backup.py:339 +#: app/backup.py:337 msgid "This filename is already in the backup.Do you wish to overwrite it? ({})" msgstr "" "Este nombre de archivo ya está en la copia de seguridad. Desea " "reemplazarlo? ({})" -#: backup.py:445 +#: app/backup.py:443 msgid "BEE2 Backup" msgstr "BEE2 Copia de seguridad" -#: backup.py:446 +#: app/backup.py:444 msgid "No maps were chosen to backup!" msgstr "No se ha elegido ningún mapa para realizar copias de seguridad!" -#: backup.py:506 +#: app/backup.py:504 msgid "" "This map is already in the game directory.Do you wish to overwrite it? " "({})" msgstr "Este mapa ya está en el directorio del juego. ¿Desea reemplazarlo? ({})" -#: backup.py:568 +#: app/backup.py:566 msgid "Load Backup" msgstr "Cargar Copia de Seguridad" -#: backup.py:569 backup.py:628 +#: app/backup.py:567 app/backup.py:626 msgid "Backup zip" msgstr "Copia de seguridad zip" -#: backup.py:602 +#: app/backup.py:600 msgid "Unsaved Backup" msgstr "Copia de seguridad no guardada" -#: backup.py:627 backup.py:874 +#: app/backup.py:625 app/backup.py:870 msgid "Save Backup As" msgstr "Guardar Copia de Seguridad como" -#: backup.py:724 +#: app/backup.py:721 msgid "Confirm Deletion" msgstr "" -#: backup.py:725 +#: app/backup.py:722 msgid "Do you wish to delete {} map?\n" msgid_plural "Do you wish to delete {} maps?\n" msgstr[0] "" msgstr[1] "" -#: backup.py:762 +#: app/backup.py:759 msgid "Restore:" msgstr "Restaurar:" -#: backup.py:763 +#: app/backup.py:760 msgid "Backup:" msgstr "Copia de Seguridad:" -#: backup.py:800 +#: app/backup.py:797 msgid "Checked" msgstr "Marcado" -#: backup.py:808 +#: app/backup.py:805 msgid "Delete Checked" msgstr "Eliminar marcado" -#: backup.py:858 +#: app/backup.py:854 msgid "BEEMOD {} - Backup / Restore Puzzles" msgstr "BEEMOD {} - Copia de Seguridad / Restaurar Mapas" -#: backup.py:871 backup.py:999 +#: app/backup.py:867 app/backup.py:995 msgid "New Backup" msgstr "Nueva Copia de Seguridad" -#: backup.py:872 backup.py:1006 +#: app/backup.py:868 app/backup.py:1002 msgid "Open Backup" msgstr "Abrir Copia de Seguridad" -#: backup.py:873 backup.py:1013 +#: app/backup.py:869 app/backup.py:1009 msgid "Save Backup" msgstr "Guardar Copia de Seguridad" -#: backup.py:881 +#: app/backup.py:877 msgid "Remove Game" msgstr "Borrar Juego" -#: backup.py:884 +#: app/backup.py:880 msgid "Game" msgstr "Juego" -#: backup.py:930 +#: app/backup.py:926 msgid "Automatic Backup After Export" msgstr "Crear una Copia de Seguridad automáticamente luego de exportar" -#: backup.py:962 +#: app/backup.py:958 msgid "Keep (Per Game):" msgstr "Mantener (Por Juego):" -#: backup.py:980 +#: app/backup.py:976 msgid "Backup/Restore Puzzles" msgstr "Copia De Seguridad / Restaurar Mapas" -#: contextWin.py:79 +#: app/contextWin.py:76 msgid "This item may not be rotated." msgstr "Este elemento no puede ser rotado." -#: contextWin.py:80 +#: app/contextWin.py:77 msgid "This item can be pointed in 4 directions." msgstr "Este elemento puede ser rotado en 4 direcciones." -#: contextWin.py:81 +#: app/contextWin.py:78 msgid "This item can be positioned on the sides and center." msgstr "Este elemento se puede colocar en los lados y en el centro." -#: contextWin.py:82 +#: app/contextWin.py:79 msgid "This item can be centered in two directions, plus on the sides." msgstr "Este elemento puede centrarse en dos direcciones y en los lados." -#: contextWin.py:83 +#: app/contextWin.py:80 msgid "This item can be placed like light strips." msgstr "Este elemento puede ser rotado como una banda luminosa." -#: contextWin.py:84 +#: app/contextWin.py:81 msgid "This item can be rotated on the floor to face 360 degrees." msgstr "Este elemento se puede rotar en el piso para hacer frente a 360 grados." -#: contextWin.py:85 +#: app/contextWin.py:82 msgid "This item is positioned using a catapult trajectory." msgstr "Este elemento se posiciona mediante la trayectoria de salto de fe." -#: contextWin.py:86 +#: app/contextWin.py:83 msgid "This item positions the dropper to hit target locations." msgstr "" "Este elemento posiciona el dispensador para alcanzar las ubicaciones del " "objetivo." -#: contextWin.py:88 +#: app/contextWin.py:85 msgid "This item does not accept any inputs." msgstr "Este elemento no acepta ninguna conexión entrante." -#: contextWin.py:89 +#: app/contextWin.py:86 msgid "This item accepts inputs." msgstr "Este elemento acepta conexiones entrantes." -#: contextWin.py:90 +#: app/contextWin.py:87 msgid "This item has two input types (A and B), using the Input A and B items." msgstr "" -#: contextWin.py:92 +#: app/contextWin.py:89 msgid "This item does not output." msgstr "Este elemento no tiene conexiones de salida." -#: contextWin.py:93 +#: app/contextWin.py:90 msgid "This item has an output." msgstr "Este elemento tiene conexiones de salida." -#: contextWin.py:94 +#: app/contextWin.py:91 msgid "This item has a timed output." msgstr "Este elemento tiene conexiones de salida temporizadas." -#: contextWin.py:96 +#: app/contextWin.py:93 msgid "This item does not take up any space inside walls." msgstr "Este elemento no ocupa ningún espacio dentro de las paredes." -#: contextWin.py:97 +#: app/contextWin.py:94 msgid "This item takes space inside the wall." msgstr "Este elemento ocupa espacio dentro de las paredes." -#: contextWin.py:99 +#: app/contextWin.py:96 msgid "This item cannot be placed anywhere..." msgstr "Este elemento no puede ser colocado en ningún lado..." -#: contextWin.py:100 +#: app/contextWin.py:97 msgid "This item can only be attached to ceilings." msgstr "Este elemento solo puede ser colocado en los techos." -#: contextWin.py:101 +#: app/contextWin.py:98 msgid "This item can only be placed on the floor." msgstr "Este elemento solo puede ser colocado en el suelo." -#: contextWin.py:102 +#: app/contextWin.py:99 msgid "This item can be placed on floors and ceilings." msgstr "Este elemento puede ser colocado en los techos y el piso." -#: contextWin.py:103 +#: app/contextWin.py:100 msgid "This item can be placed on walls only." msgstr "Este elemento solo puede ser colocado en las paredes." -#: contextWin.py:104 +#: app/contextWin.py:101 msgid "This item can be attached to walls and ceilings." msgstr "Este elemento puede ser colocado en las paredes y los techos." -#: contextWin.py:105 +#: app/contextWin.py:102 msgid "This item can be placed on floors and walls." msgstr "Este elemento puede ser colocado en el piso y las paredes." -#: contextWin.py:106 +#: app/contextWin.py:103 msgid "This item can be placed in any orientation." msgstr "Este elemento puede ser colocado en el piso, paredes y techos." -#: contextWin.py:212 +#: app/contextWin.py:209 #, fuzzy msgid "No Alternate Versions" msgstr "¡No hay otras versiones!" -#: contextWin.py:304 +#: app/contextWin.py:301 msgid "Excursion Funnels accept a on/off input and a directional input." msgstr "" "Los Rayos Tractores aceptan una conexión de activación/desactivación, así" " como una conexión direccional." -#: contextWin.py:361 +#: app/contextWin.py:358 #, fuzzy msgid "" "This item can be rotated on the floor to face 360 degrees, for Reflection" " Cubes only." msgstr "Este elemento se puede rotar en el piso para hacer frente a 360 grados." -#: contextWin.py:440 +#: app/contextWin.py:437 #, fuzzy msgid "Properties:" msgstr "Propiedades" -#: contextWin.py:462 +#: app/contextWin.py:459 msgid "" "The number of entities used for this item. The Source engine limits this " "to 2048 in total. This provides a guide to how many of these items can be" @@ -986,11 +1017,11 @@ msgstr "" "límite de 2048 en total. Esto proporciona una guía de cuantos de estos " "elementos pueden ser puestos en un mapa." -#: contextWin.py:487 +#: app/contextWin.py:484 msgid "Description:" msgstr "Descripción:" -#: contextWin.py:530 +#: app/contextWin.py:527 msgid "" "Failed to open a web browser. Do you wish for the URL to be copied to the" " clipboard instead?" @@ -998,87 +1029,87 @@ msgstr "" "Error al abrir un navegador web. ¿Desea que la URL sea copiada en el " "Portapapeles?" -#: contextWin.py:544 +#: app/contextWin.py:541 msgid "More Info>>" msgstr "" -#: contextWin.py:561 +#: app/contextWin.py:558 msgid "Change Defaults..." msgstr "Cambiar Predeterminación" -#: contextWin.py:567 +#: app/contextWin.py:564 msgid "Change the default settings for this item when placed." msgstr "" "Cambia la configuración predeterminada de este elemento cuando es " "colocado en el mapa." -#: gameMan.py:750 gameMan.py:852 +#: app/gameMan.py:748 app/gameMan.py:850 msgid "BEE2 - Export Failed!" msgstr "BEE2 - ¡Exportación Fallida!" -#: gameMan.py:751 +#: app/gameMan.py:749 msgid "" "Compiler file {file} missing. Exit Steam applications, then press OK to " "verify your game cache. You can then export again." msgstr "" -#: gameMan.py:853 +#: app/gameMan.py:851 #, fuzzy msgid "Copying compiler file {file} failed. Ensure {game} is not running." msgstr "" "Copiando archivo del compilador {file} ha fallado. Asegurese de que el " "{game} no esta abierto.\n" -#: gameMan.py:1265 +#: app/gameMan.py:1263 msgid "" "Ap-Tag Coop gun instance not found!\n" "Coop guns will not work - verify cache to fix." msgstr "" -#: gameMan.py:1269 +#: app/gameMan.py:1267 msgid "BEE2 - Aperture Tag Files Missing" msgstr "" -#: gameMan.py:1452 +#: app/gameMan.py:1450 msgid "Select the folder where the game executable is located ({appname})..." msgstr "" "Selecciona el directorio donde se encuentre el ejecutable del juego " "({appname})..." -#: gameMan.py:1455 gameMan.py:1470 gameMan.py:1480 gameMan.py:1487 -#: gameMan.py:1496 gameMan.py:1505 +#: app/gameMan.py:1453 app/gameMan.py:1468 app/gameMan.py:1478 +#: app/gameMan.py:1485 app/gameMan.py:1494 app/gameMan.py:1503 msgid "BEE2 - Add Game" msgstr "BEE2 - Añadir juego" -#: gameMan.py:1458 +#: app/gameMan.py:1456 msgid "Find Game Exe" msgstr "Encontrar Ejecutable del Juego" -#: gameMan.py:1459 +#: app/gameMan.py:1457 msgid "Executable" msgstr "Ejecutable" -#: gameMan.py:1467 +#: app/gameMan.py:1465 msgid "This does not appear to be a valid game folder!" msgstr "Eso no parece ser un directorio de juego valido!" -#: gameMan.py:1477 +#: app/gameMan.py:1475 msgid "Portal Stories: Mel doesn't have an editor!" msgstr "" -#: gameMan.py:1488 +#: app/gameMan.py:1486 msgid "Enter the name of this game:" msgstr "Coloca el nombre de este juego:" -#: gameMan.py:1495 +#: app/gameMan.py:1493 msgid "This name is already taken!" msgstr "Este nombre ya fue tomado!" -#: gameMan.py:1504 +#: app/gameMan.py:1502 msgid "Please enter a name for this game!" msgstr "Por favor colocale un nombre a este juego!" -#: gameMan.py:1523 +#: app/gameMan.py:1521 msgid "" "\n" " (BEE2 will quit, this is the last game set!)" @@ -1086,79 +1117,79 @@ msgstr "" "\n" "(BEE2 se cerrará, este es el último juego seleccionado!)" -#: helpMenu.py:60 +#: app/helpMenu.py:56 msgid "Wiki..." msgstr "" -#: helpMenu.py:62 +#: app/helpMenu.py:58 msgid "Original Items..." msgstr "" -#: helpMenu.py:67 +#: app/helpMenu.py:63 msgid "Discord Server..." msgstr "" -#: helpMenu.py:68 +#: app/helpMenu.py:64 msgid "aerond's Music Changer..." msgstr "" -#: helpMenu.py:70 +#: app/helpMenu.py:66 msgid "Application Repository..." msgstr "" -#: helpMenu.py:71 +#: app/helpMenu.py:67 msgid "Items Repository..." msgstr "" -#: helpMenu.py:73 +#: app/helpMenu.py:69 msgid "Submit Application Bugs..." msgstr "" -#: helpMenu.py:74 +#: app/helpMenu.py:70 msgid "Submit Item Bugs..." msgstr "" -#: helpMenu.py:76 paletteLoader.py:35 +#: app/helpMenu.py:72 app/paletteLoader.py:35 msgid "Portal 2" msgstr "" -#: helpMenu.py:77 paletteLoader.py:37 +#: app/helpMenu.py:73 app/paletteLoader.py:37 msgid "Aperture Tag" msgstr "" -#: helpMenu.py:78 +#: app/helpMenu.py:74 msgid "Portal Stories: Mel" msgstr "" -#: helpMenu.py:79 +#: app/helpMenu.py:75 msgid "Thinking With Time Machine" msgstr "" -#: helpMenu.py:242 itemPropWin.py:347 +#: app/helpMenu.py:238 app/itemPropWin.py:342 msgid "Close" msgstr "Cerrar" -#: helpMenu.py:266 +#: app/helpMenu.py:262 msgid "Help" msgstr "Ayuda" -#: helpMenu.py:277 +#: app/helpMenu.py:273 msgid "BEE2 Credits" msgstr "" -#: helpMenu.py:294 +#: app/helpMenu.py:290 msgid "Credits..." msgstr "" -#: itemPropWin.py:43 +#: app/itemPropWin.py:38 msgid "Start Position" msgstr "Posición de Entrada" -#: itemPropWin.py:44 +#: app/itemPropWin.py:39 msgid "End Position" msgstr "Posición de Salida" -#: itemPropWin.py:45 +#: app/itemPropWin.py:40 msgid "" "Delay \n" "(0=infinite)" @@ -1166,76 +1197,44 @@ msgstr "" "Ralentizar\n" "(0=infinito)" -#: itemPropWin.py:346 +#: app/itemPropWin.py:341 msgid "No Properties available!" msgstr "No hay propiedades disponibles!" -#: itemconfig.py:621 +#: app/itemconfig.py:616 msgid "Choose a Color" msgstr "" -#: loadScreen.py:199 -msgid "Skipped!" -msgstr "Saltado!" - -#: loadScreen.py:200 -msgid "Version: " -msgstr "" - -#: loadScreen.py:201 optionWindow.py:252 packageMan.py:116 selectorWin.py:723 -msgid "Cancel" -msgstr "Cancelar" - -#: loadScreen.py:211 tagsPane.py:53 -msgid "Packages" -msgstr "Paquetes" - -#: loadScreen.py:212 -msgid "Loading Objects" -msgstr "Cargando Objetos" - -#: loadScreen.py:213 -msgid "Loading Images" -msgstr "Cargando Imagenes" - -#: loadScreen.py:214 -msgid "Initialising UI" -msgstr "Iniciando Interfaz" - -#: loadScreen.py:215 -msgid "Better Extended Editor for Portal 2" -msgstr "" - -#: logWindow.py:30 +#: app/logWindow.py:29 msgid "Debug messages" msgstr "Mensajes de depuración" -#: logWindow.py:31 +#: app/logWindow.py:30 msgid "Default" msgstr "Predeterminado" -#: logWindow.py:32 +#: app/logWindow.py:31 msgid "Warnings Only" msgstr "Sólo advertencias" -#: logWindow.py:160 +#: app/logWindow.py:159 msgid "Logs - {}" msgstr "Registros - {}" -#: logWindow.py:209 +#: app/logWindow.py:208 msgid "Copy" msgstr "Copiar" -#: logWindow.py:221 +#: app/logWindow.py:220 msgid "Show:" msgstr "Mostrar:" -#: music_conf.py:132 +#: app/music_conf.py:133 #, fuzzy msgid "Select Background Music - Base" msgstr "Selecciona la música de fondo" -#: music_conf.py:133 +#: app/music_conf.py:134 #, fuzzy msgid "" "This controls the background music used for a map. Expand the dropdown to" @@ -1245,284 +1244,314 @@ msgstr "" " tienen variaciones que se oyen al interactuar con ciertos elementos de " "prueba." -#: music_conf.py:137 +#: app/music_conf.py:138 msgid "" "Add no music to the map at all. Testing Element-specific music may still " "be added." msgstr "No añadir ninguna música de fondo al mapa en absoluto." -#: music_conf.py:142 +#: app/music_conf.py:143 msgid "Propulsion Gel SFX" msgstr "SFX del gel de propulsión" -#: music_conf.py:143 +#: app/music_conf.py:144 msgid "Repulsion Gel SFX" msgstr "SFX del gel de repulsion" -#: music_conf.py:144 +#: app/music_conf.py:145 msgid "Excursion Funnel Music" msgstr "La música de fondo" -#: music_conf.py:145 music_conf.py:160 +#: app/music_conf.py:146 app/music_conf.py:161 msgid "Synced Funnel Music" msgstr "" -#: music_conf.py:152 +#: app/music_conf.py:153 #, fuzzy msgid "Select Excursion Funnel Music" msgstr "Selecciona la música de fondo" -#: music_conf.py:153 +#: app/music_conf.py:154 msgid "Set the music used while inside Excursion Funnels." msgstr "" -#: music_conf.py:156 +#: app/music_conf.py:157 msgid "Have no music playing when inside funnels." msgstr "" -#: music_conf.py:167 +#: app/music_conf.py:168 msgid "Select Repulsion Gel Music" msgstr "" -#: music_conf.py:168 +#: app/music_conf.py:169 msgid "Select the music played when players jump on Repulsion Gel." msgstr "" -#: music_conf.py:171 +#: app/music_conf.py:172 msgid "Add no music when jumping on Repulsion Gel." msgstr "" -#: music_conf.py:179 +#: app/music_conf.py:180 #, fuzzy msgid "Select Propulsion Gel Music" msgstr "Selecciona la música de fondo" -#: music_conf.py:180 +#: app/music_conf.py:181 msgid "" "Select music played when players have large amounts of horizontal " "velocity." msgstr "" -#: music_conf.py:183 +#: app/music_conf.py:184 msgid "Add no music while running fast." msgstr "" -#: music_conf.py:218 +#: app/music_conf.py:219 msgid "Base: " msgstr "" -#: music_conf.py:251 +#: app/music_conf.py:252 msgid "Funnel:" msgstr "" -#: music_conf.py:252 +#: app/music_conf.py:253 msgid "Bounce:" msgstr "" -#: music_conf.py:253 +#: app/music_conf.py:254 msgid "Speed:" msgstr "" -#: optionWindow.py:62 +#: app/optionWindow.py:45 +msgid "" +"\n" +"Launch Game?" +msgstr "" + +#: app/optionWindow.py:47 +msgid "" +"\n" +"Minimise BEE2?" +msgstr "" + +#: app/optionWindow.py:48 +msgid "" +"\n" +"Launch Game and minimise BEE2?" +msgstr "" + +#: app/optionWindow.py:50 +msgid "" +"\n" +"Quit BEE2?" +msgstr "" + +#: app/optionWindow.py:51 +msgid "" +"\n" +"Launch Game and quit BEE2?" +msgstr "" + +#: app/optionWindow.py:70 msgid "BEE2 Options" msgstr "BEE2 Opciones" -#: optionWindow.py:101 +#: app/optionWindow.py:108 msgid "" "Package cache times have been reset. These will now be extracted during " "the next export." msgstr "" -#: optionWindow.py:118 +#: app/optionWindow.py:125 msgid "\"Preserve Game Resources\" has been disabled." msgstr "" -#: optionWindow.py:130 +#: app/optionWindow.py:137 #, fuzzy msgid "Packages Reset" msgstr "Paquetes" -#: optionWindow.py:211 +#: app/optionWindow.py:218 msgid "General" msgstr "General" -#: optionWindow.py:217 +#: app/optionWindow.py:224 msgid "Windows" msgstr "Ventana" -#: optionWindow.py:223 +#: app/optionWindow.py:230 msgid "Development" msgstr "Desarollo" -#: optionWindow.py:247 packageMan.py:110 selectorWin.py:701 +#: app/optionWindow.py:254 app/packageMan.py:110 app/selector_win.py:696 msgid "OK" msgstr "SI" -#: optionWindow.py:278 +#: app/optionWindow.py:285 msgid "After Export:" msgstr "" -#: optionWindow.py:295 +#: app/optionWindow.py:302 msgid "Do Nothing" msgstr "" -#: optionWindow.py:301 +#: app/optionWindow.py:308 msgid "Minimise BEE2" msgstr "" -#: optionWindow.py:307 +#: app/optionWindow.py:314 msgid "Quit BEE2" msgstr "" -#: optionWindow.py:315 +#: app/optionWindow.py:322 msgid "After exports, do nothing and keep the BEE2 in focus." msgstr "" -#: optionWindow.py:317 +#: app/optionWindow.py:324 msgid "After exports, minimise to the taskbar/dock." msgstr "" -#: optionWindow.py:318 +#: app/optionWindow.py:325 msgid "After exports, quit the BEE2." msgstr "" -#: optionWindow.py:325 +#: app/optionWindow.py:332 msgid "Launch Game" msgstr "" -#: optionWindow.py:326 +#: app/optionWindow.py:333 msgid "After exporting, launch the selected game automatically." msgstr "" -#: optionWindow.py:334 optionWindow.py:340 +#: app/optionWindow.py:341 app/optionWindow.py:347 msgid "Play Sounds" msgstr "" -#: optionWindow.py:345 +#: app/optionWindow.py:352 msgid "" "Pyglet is either not installed or broken.\n" "Sound effects have been disabled." msgstr "" -#: optionWindow.py:352 +#: app/optionWindow.py:359 msgid "Reset Package Caches" msgstr "" -#: optionWindow.py:358 +#: app/optionWindow.py:365 msgid "Force re-extracting all package resources." msgstr "" -#: optionWindow.py:367 +#: app/optionWindow.py:374 msgid "Keep windows inside screen" msgstr "" -#: optionWindow.py:368 +#: app/optionWindow.py:375 msgid "" "Prevent sub-windows from moving outside the screen borders. If you have " "multiple monitors, disable this." msgstr "" -#: optionWindow.py:378 +#: app/optionWindow.py:385 #, fuzzy msgid "Keep loading screens on top" msgstr "Limpiar viejas capturas de pantalla" -#: optionWindow.py:380 +#: app/optionWindow.py:387 msgid "" "Force loading screens to be on top of other windows. Since they don't " "appear on the taskbar/dock, they can't be brought to the top easily " "again." msgstr "" -#: optionWindow.py:389 +#: app/optionWindow.py:396 msgid "Reset All Window Positions" msgstr "" -#: optionWindow.py:403 +#: app/optionWindow.py:410 msgid "Log missing entity counts" msgstr "" -#: optionWindow.py:404 +#: app/optionWindow.py:411 msgid "" "When loading items, log items with missing entity counts in their " "properties.txt file." msgstr "" -#: optionWindow.py:412 +#: app/optionWindow.py:419 msgid "Log when item doesn't have a style" msgstr "" -#: optionWindow.py:413 +#: app/optionWindow.py:420 msgid "" "Log items have no applicable version for a particular style.This usually " "means it will look very bad." msgstr "" -#: optionWindow.py:421 +#: app/optionWindow.py:428 msgid "Log when item uses parent's style" msgstr "" -#: optionWindow.py:422 +#: app/optionWindow.py:429 msgid "" "Log when an item reuses a variant from a parent style (1970s using 1950s " "items, for example). This is usually fine, but may need to be fixed." msgstr "" -#: optionWindow.py:431 +#: app/optionWindow.py:438 msgid "Log missing packfile resources" msgstr "" -#: optionWindow.py:432 +#: app/optionWindow.py:439 msgid "" "Log when the resources a \"PackList\" refers to are not present in the " "zip. This may be fine (in a prerequisite zip), but it often indicates an " "error." msgstr "" -#: optionWindow.py:441 +#: app/optionWindow.py:448 msgid "Preserve Game Directories" msgstr "" -#: optionWindow.py:443 +#: app/optionWindow.py:450 msgid "" -"When exporting, do not overwrite \n" -"\"bee2/\" and\n" -"\"sdk_content/maps/bee2/\".\n" -"Enable if you're developing new content, to ensure it is not overwritten." +"When exporting, do not copy resources to \n" +"\"bee2/\" and \"sdk_content/maps/bee2/\".\n" +"Only enable if you're developing new content, to ensure it is not " +"overwritten." msgstr "" -#: optionWindow.py:454 +#: app/optionWindow.py:461 msgid "Show Log Window" msgstr "" -#: optionWindow.py:456 +#: app/optionWindow.py:463 msgid "Show the log file in real-time." msgstr "" -#: optionWindow.py:463 +#: app/optionWindow.py:470 msgid "Force Editor Models" msgstr "" -#: optionWindow.py:464 +#: app/optionWindow.py:471 msgid "" "Make all props_map_editor models available for use. Portal 2 has a limit " "of 1024 models loaded in memory at once, so we need to disable unused " "ones to free this up." msgstr "" -#: optionWindow.py:475 +#: app/optionWindow.py:482 msgid "Dump All objects" msgstr "" -#: optionWindow.py:481 +#: app/optionWindow.py:488 msgid "Dump Items list" msgstr "" -#: packageMan.py:64 +#: app/packageMan.py:64 msgid "BEE2 - Restart Required!" msgstr "BEE2 - Reinicio Requerido!" -#: packageMan.py:65 +#: app/packageMan.py:65 msgid "" "Changing enabled packages requires a restart.\n" "Continue?" @@ -1530,163 +1559,159 @@ msgstr "" "El cambiar paquetes ya activados requiere un reinicio.\n" "Desea continuar?" -#: packageMan.py:88 +#: app/packageMan.py:88 msgid "BEE2 - Manage Packages" msgstr "BEE2 - Administrar Paquetes" -#: paletteLoader.py:25 +#: app/paletteLoader.py:25 msgid "" msgstr "" -#: paletteLoader.py:27 +#: app/paletteLoader.py:27 msgid "Blank" msgstr "" -#: paletteLoader.py:30 +#: app/paletteLoader.py:30 msgid "BEEMod" msgstr "" -#: paletteLoader.py:32 +#: app/paletteLoader.py:32 msgid "Portal 2 Collapsed" msgstr "" -#: richTextBox.py:153 +#: app/richTextBox.py:152 msgid "Open \"{}\" in the default browser?" msgstr "Abrir \"{}\" en el navegador predeterminado?" -#: selectorWin.py:404 +#: app/selector_win.py:399 msgid "Do not add anything." msgstr "No añadir nada." -#: selectorWin.py:408 +#: app/selector_win.py:403 msgid "" msgstr " " -#: selectorWin.py:585 selectorWin.py:590 +#: app/selector_win.py:580 app/selector_win.py:585 msgid "Suggested" msgstr "Recomendado" -#: selectorWin.py:638 +#: app/selector_win.py:633 msgid "Play a sample of this item." msgstr "Dar una demostración de este elemento." -#: selectorWin.py:712 +#: app/selector_win.py:707 msgid "Reset to Default" msgstr "Reiniciar a predeterminado." -#: selectorWin.py:773 +#: app/selector_win.py:768 msgid "Other" msgstr "Otro" -#: selectorWin.py:1086 +#: app/selector_win.py:1081 msgid "Author: {}" msgid_plural "Authors: {}" msgstr[0] "Autor: {}" msgstr[1] "Plural: Autores: {}" -#: selectorWin.py:1142 +#: app/selector_win.py:1137 msgid "Color: R={r}, G={g}, B={b}" msgstr "Color: R={r}, G={g}, B={b} " -#: signage_ui.py:140 signage_ui.py:213 +#: app/signage_ui.py:139 app/signage_ui.py:212 msgid "Configure Signage" msgstr "" -#: signage_ui.py:144 +#: app/signage_ui.py:143 #, fuzzy msgid "Selected" msgstr "Estilo seleccionado:" -#: signage_ui.py:167 +#: app/signage_ui.py:166 msgid "Signage: {}" msgstr "" -#: tagsPane.py:51 +#: app/tagsPane.py:46 msgid "Tags" msgstr "Etiquetas" -#: tagsPane.py:52 +#: app/tagsPane.py:47 msgid "Authors" msgstr "Autores" -#: tagsPane.py:162 +#: app/tagsPane.py:157 msgid "Any" msgstr "" -#: tagsPane.py:171 +#: app/tagsPane.py:166 msgid "All" msgstr "" -#: tagsPane.py:197 +#: app/tagsPane.py:192 msgid "Available Tags (click):" msgstr "" -#: utils.py:841 -msgid "__LANG_USE_SANS_SERIF__" -msgstr "" - -#: voiceEditor.py:35 +#: app/voiceEditor.py:33 msgid "Singleplayer" msgstr "" -#: voiceEditor.py:36 +#: app/voiceEditor.py:34 #, fuzzy msgid "Cooperative" msgstr "Propiedades" -#: voiceEditor.py:37 +#: app/voiceEditor.py:35 msgid "ATLAS (SP/Coop)" msgstr "" -#: voiceEditor.py:38 +#: app/voiceEditor.py:36 msgid "P-Body (SP/Coop)" msgstr "" -#: voiceEditor.py:41 +#: app/voiceEditor.py:39 msgid "Human characters (Bendy and Chell)" msgstr "" -#: voiceEditor.py:42 +#: app/voiceEditor.py:40 msgid "AI characters (ATLAS, P-Body, or Coop)" msgstr "" -#: voiceEditor.py:53 +#: app/voiceEditor.py:51 msgid "Death - Toxic Goo" msgstr "Muerte - Pringue mortal" -#: voiceEditor.py:54 +#: app/voiceEditor.py:52 msgid "Death - Turrets" msgstr "Muerte - Torretas" -#: voiceEditor.py:55 +#: app/voiceEditor.py:53 msgid "Death - Crusher" msgstr "Muerte - Machacador" -#: voiceEditor.py:56 +#: app/voiceEditor.py:54 msgid "Death - LaserField" msgstr "Muerte - Campo Láser" -#: voiceEditor.py:107 +#: app/voiceEditor.py:105 msgid "Transcript:" msgstr "Transcripción:" -#: voiceEditor.py:146 +#: app/voiceEditor.py:144 msgid "Save" msgstr "" -#: voiceEditor.py:221 +#: app/voiceEditor.py:219 msgid "Resp" msgstr "Resp" -#: voiceEditor.py:238 +#: app/voiceEditor.py:236 msgid "BEE2 - Configure \"{}\"" msgstr "BEE2 - Configurar \"{}\"" -#: voiceEditor.py:315 +#: app/voiceEditor.py:313 msgid "Mid - Chamber" msgstr "Mitad - Camara" -#: voiceEditor.py:317 +#: app/voiceEditor.py:315 msgid "" "Lines played during the actual chamber, after specific events have " "occurred." @@ -1694,21 +1719,34 @@ msgstr "" "Líneas de voz reproducidas durante la camara actual, después de que se " "hayan producido eventos específicos." -#: voiceEditor.py:323 +#: app/voiceEditor.py:321 msgid "Responses" msgstr "Respuestas" -#: voiceEditor.py:325 +#: app/voiceEditor.py:323 msgid "Lines played in response to certain events in Coop." msgstr "" "Líneas de voz reproducidas en respuesta a ciertos acontecimientos en el " "modo cooperativo." -#: voiceEditor.py:423 +#: app/voiceEditor.py:421 msgid "No Name!" msgstr "¡Sin nombre!" -#: voiceEditor.py:458 +#: app/voiceEditor.py:456 msgid "No Name?" msgstr "¿Sin nombre?" +#~ msgid "" +#~ "\n" +#~ " Launch Game?" +#~ msgstr "" + +#~ msgid "" +#~ "When exporting, do not overwrite \n" +#~ "\"bee2/\" and\n" +#~ "\"sdk_content/maps/bee2/\".\n" +#~ "Enable if you're developing new content," +#~ " to ensure it is not overwritten." +#~ msgstr "" + diff --git a/i18n/fr.po b/i18n/fr.po index 09494f7fb..b3469e319 100644 --- a/i18n/fr.po +++ b/i18n/fr.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: BEEMOD2\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2020-07-18 11:58+1000\n" +"POT-Creation-Date: 2020-09-20 10:31-0700\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: fr\n" @@ -12,29 +12,66 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.6.0\n" +"Generated-By: Babel 2.8.0\n" -#: CheckDetails.py:220 +#: loadScreen.py:199 +msgid "Skipped!" +msgstr "Sauté !" + +#: loadScreen.py:200 +msgid "Version: " +msgstr "Version: " + +#: app/optionWindow.py:259 app/packageMan.py:116 app/selector_win.py:718 +#: loadScreen.py:201 +msgid "Cancel" +msgstr "Annuler" + +#: app/tagsPane.py:48 loadScreen.py:211 +msgid "Packages" +msgstr "Paquets" + +#: loadScreen.py:212 +msgid "Loading Objects" +msgstr "Chargement des objets" + +#: loadScreen.py:213 +msgid "Loading Images" +msgstr "Chargement des images" + +#: loadScreen.py:214 +msgid "Initialising UI" +msgstr "Initialisation de l'interface" + +#: loadScreen.py:215 +msgid "Better Extended Editor for Portal 2" +msgstr "Better Extended Editor pour Portal 2" + +#: utils.py:841 +msgid "__LANG_USE_SANS_SERIF__" +msgstr "" + +#: app/CheckDetails.py:219 msgid "Toggle all checkboxes." msgstr "Cocher toutes les cases" -#: CompilerPane.py:66 +#: app/CompilerPane.py:64 msgid "ATLAS" msgstr "ATLAS" -#: CompilerPane.py:67 +#: app/CompilerPane.py:65 msgid "P-Body" msgstr "P-Body" -#: CompilerPane.py:68 voiceEditor.py:40 +#: app/CompilerPane.py:66 app/voiceEditor.py:38 msgid "Chell" msgstr "Chell" -#: CompilerPane.py:69 voiceEditor.py:39 +#: app/CompilerPane.py:67 app/voiceEditor.py:37 msgid "Bendy" msgstr "Bendy" -#: CompilerPane.py:122 +#: app/CompilerPane.py:120 msgid "" "Brushes form the walls or other parts of the test chamber. If this is " "high, it may help to reduce the size of the map or remove intricate " @@ -44,7 +81,7 @@ msgstr "" "Si cette valeur est élevée, essayer de réduire la taille de la carte ou " "simplifier sa forme." -#: CompilerPane.py:129 +#: app/CompilerPane.py:127 #, fuzzy msgid "" "Entities are the things in the map that have functionality. Removing " @@ -62,7 +99,7 @@ msgstr "" "Ce n'est pas exactement précis. Certains types d'entités comptés ici ne " "le sont pas par le moteur de jeu." -#: CompilerPane.py:139 +#: app/CompilerPane.py:137 #, fuzzy msgid "" "Overlays are smaller images affixed to surfaces, like signs or indicator " @@ -73,25 +110,25 @@ msgstr "" " comme les symboles ou les lignes en pointillés. Cacher les longues " "lignes ou régler le paramètre sur Signalisation réduira cette valeur." -#: CompilerPane.py:275 +#: app/CompilerPane.py:273 msgid "Corridor" msgstr "Couloir" -#: CompilerPane.py:316 +#: app/CompilerPane.py:314 msgid "" "Randomly choose a corridor. This is saved in the puzzle data and will not" " change." msgstr "" -#: CompilerPane.py:322 UI.py:657 +#: app/CompilerPane.py:320 app/UI.py:664 msgid "Random" msgstr "Aléatoire" -#: CompilerPane.py:421 +#: app/CompilerPane.py:419 msgid "Image Files" msgstr "Fichiers image" -#: CompilerPane.py:504 +#: app/CompilerPane.py:502 msgid "" "Options on this panel can be changed \n" "without exporting or restarting the game." @@ -99,35 +136,35 @@ msgstr "" "Les options de ce panneau peuvent être modifiées sans exporter ou " "redémarrer le jeu." -#: CompilerPane.py:519 +#: app/CompilerPane.py:517 msgid "Map Settings" msgstr "Paramètres de carte" -#: CompilerPane.py:524 +#: app/CompilerPane.py:522 msgid "Compile Settings" msgstr "Paramètres de compilation" -#: CompilerPane.py:538 +#: app/CompilerPane.py:536 msgid "Thumbnail" msgstr "Miniature" -#: CompilerPane.py:546 +#: app/CompilerPane.py:544 msgid "Auto" msgstr "Auto" -#: CompilerPane.py:554 +#: app/CompilerPane.py:552 msgid "PeTI" msgstr "PeTI" -#: CompilerPane.py:562 +#: app/CompilerPane.py:560 msgid "Custom:" msgstr "Personnalisée:" -#: CompilerPane.py:580 +#: app/CompilerPane.py:578 msgid "Cleanup old screenshots" msgstr "Supprimer les anciens screenshots" -#: CompilerPane.py:590 +#: app/CompilerPane.py:588 msgid "" "Override the map image to use a screenshot automatically taken from the " "beginning of a chamber. Press F5 to take a new screenshot. If the map has" @@ -139,11 +176,11 @@ msgstr "" "la carte n'a pas été prévisualisée récemment (dans les dernières heures)," " le screenshot PeTI par défaut sera utilisé à la place." -#: CompilerPane.py:598 +#: app/CompilerPane.py:596 msgid "Use the normal editor view for the map preview image." msgstr "Utilise la vue normale de l'éditeur pour l'image de prévisualisation." -#: CompilerPane.py:600 +#: app/CompilerPane.py:598 msgid "" "Use a custom image for the map preview image. Click the screenshot to " "select.\n" @@ -153,7 +190,7 @@ msgstr "" "l'image pour la choisir.\n" "Les images seront converties en JPEG si besoin." -#: CompilerPane.py:617 +#: app/CompilerPane.py:615 msgid "" "Automatically delete unused Automatic screenshots. Disable if you want to" " keep things in \"portal2/screenshots\". " @@ -161,19 +198,19 @@ msgstr "" "Supprimer automatiquement les screenshots Autos non utilisés. Décochez si" " vous souhaitez garder des images dans \"portal2/screenshots\"." -#: CompilerPane.py:628 +#: app/CompilerPane.py:626 msgid "Lighting:" msgstr "Lumière:" -#: CompilerPane.py:635 +#: app/CompilerPane.py:633 msgid "Fast" msgstr "Rapide" -#: CompilerPane.py:642 +#: app/CompilerPane.py:640 msgid "Full" msgstr "Complète" -#: CompilerPane.py:650 +#: app/CompilerPane.py:648 msgid "" "Compile with lower-quality, fast lighting. This speeds up compile times, " "but does not appear as good. Some shadows may appear wrong.\n" @@ -184,7 +221,7 @@ msgstr "" "incorrectes.\n" "À la publication, ce n'est pas utilisé." -#: CompilerPane.py:657 +#: app/CompilerPane.py:655 #, fuzzy msgid "" "Compile with high-quality lighting. This looks correct, but takes longer " @@ -195,11 +232,11 @@ msgstr "" "rend mieux. À utiliser si vous arrangez les lumières.\n" "À la publication, ceci est toujours utilisé." -#: CompilerPane.py:664 +#: app/CompilerPane.py:662 msgid "Dump packed files to:" msgstr "Vider les fichiers enpaquetés vers :" -#: CompilerPane.py:689 +#: app/CompilerPane.py:687 msgid "" "When compiling, dump all files which were packed into the map. Useful if " "you're intending to edit maps in Hammer." @@ -207,19 +244,19 @@ msgstr "" "Lors de la compilation, vide tous les fichiers venant d'être compilés " "dans la carte. Utile si vous prévoyez d'éditer la carte sous Hammer." -#: CompilerPane.py:695 +#: app/CompilerPane.py:693 msgid "Last Compile:" msgstr "Dernière compilation:" -#: CompilerPane.py:705 +#: app/CompilerPane.py:703 msgid "Entity" msgstr "Entités" -#: CompilerPane.py:725 +#: app/CompilerPane.py:723 msgid "Overlay" msgstr "Overlays" -#: CompilerPane.py:744 +#: app/CompilerPane.py:742 msgid "" "Refresh the compile progress bars. Press after a compile has been " "performed to show the new values." @@ -227,19 +264,19 @@ msgstr "" "Rafraîchir les barres de progression. Cliquez après une compilation pour " "actualiser les valeurs." -#: CompilerPane.py:750 +#: app/CompilerPane.py:748 msgid "Brush" msgstr "Brushes" -#: CompilerPane.py:778 +#: app/CompilerPane.py:776 msgid "Voicelines:" msgstr "Répliques:" -#: CompilerPane.py:785 +#: app/CompilerPane.py:783 msgid "Use voiceline priorities" msgstr "Utiliser les priorités des répliques" -#: CompilerPane.py:791 +#: app/CompilerPane.py:789 msgid "" "Only choose the highest-priority voicelines. This means more generic " "lines will can only be chosen if few test elements are in the map. If " @@ -250,19 +287,19 @@ msgstr "" "d'éléments de test dans la carte. Si décoché, toute réplique applicable " "sera utilisée." -#: CompilerPane.py:798 +#: app/CompilerPane.py:796 msgid "Spawn at:" msgstr "Apparaître à:" -#: CompilerPane.py:809 +#: app/CompilerPane.py:807 msgid "Entry Door" msgstr "Porte d'entrée" -#: CompilerPane.py:816 +#: app/CompilerPane.py:814 msgid "Elevator" msgstr "Ascenseur" -#: CompilerPane.py:826 +#: app/CompilerPane.py:824 #, fuzzy msgid "" "When previewing in SP, spawn inside the entry elevator. Use this to " @@ -273,54 +310,54 @@ msgstr "" "atteignez la sortie. Utilisez ceci pour vérifier les couloirs d'entrée et" " de sortie." -#: CompilerPane.py:831 +#: app/CompilerPane.py:829 #, fuzzy msgid "When previewing in SP, spawn just before the entry door." msgstr "" "Lors d'une prévisualisation en solo, cela fait apparaître derrière la " "porte d'entrée. Quand vous atteindrez la sortie, la carte redémarrera." -#: CompilerPane.py:837 +#: app/CompilerPane.py:835 msgid "Corridor:" msgstr "Couloir:" -#: CompilerPane.py:856 +#: app/CompilerPane.py:854 msgid "SP Entry:" msgstr "Entrée solo:" -#: CompilerPane.py:861 +#: app/CompilerPane.py:859 msgid "SP Exit:" msgstr "Sortie solo:" -#: CompilerPane.py:866 +#: app/CompilerPane.py:864 msgid "Coop:" msgstr "Coop:" -#: CompilerPane.py:872 +#: app/CompilerPane.py:870 msgid "Player Model (SP):" msgstr "Modèle de joueur (Solo):" -#: CompilerPane.py:896 +#: app/CompilerPane.py:894 msgid "Compile Options" msgstr "Options de compilation" -#: CompilerPane.py:914 +#: app/CompilerPane.py:912 msgid "Compiler Options - {}" msgstr "Options de compilateur - {}" -#: StyleVarPane.py:33 +#: app/StyleVarPane.py:31 msgid "Multiverse Cave" msgstr "Cave du multivers" -#: StyleVarPane.py:35 +#: app/StyleVarPane.py:33 msgid "Play the Workshop Cave Johnson lines on map start." msgstr "Joue les répliques de Cave Johnson du Workshop au début de la carte." -#: StyleVarPane.py:40 +#: app/StyleVarPane.py:38 msgid "Prevent Portal Bump (fizzler)" msgstr "Empêcher le Portal Bump (Grilles d'Émancipation)" -#: StyleVarPane.py:42 +#: app/StyleVarPane.py:40 msgid "" "Add portal bumpers to make it more difficult to portal across fizzler " "edges. This can prevent placing portals in tight spaces near fizzlers, or" @@ -331,19 +368,19 @@ msgstr "" "empêcher le placement de portails dans des endroits serrés proches de " "Grilles ou dissoudre les portails lors de leur placement." -#: StyleVarPane.py:49 +#: app/StyleVarPane.py:47 msgid "Suppress Mid-Chamber Dialogue" msgstr "Retirer les répliques se déclenchant en cours de salle" -#: StyleVarPane.py:51 +#: app/StyleVarPane.py:49 msgid "Disable all voicelines other than entry and exit lines." msgstr "Désactive toutes les répliques autres que celles d'entrée et de sortie." -#: StyleVarPane.py:56 +#: app/StyleVarPane.py:54 msgid "Unlock Default Items" msgstr "Débloquer les objets par défaut." -#: StyleVarPane.py:58 +#: app/StyleVarPane.py:56 msgid "" "Allow placing and deleting the mandatory Entry/Exit Doors and Large " "Observation Room. Use with caution, this can have weird results!" @@ -352,11 +389,11 @@ msgstr "" "et de la grande salle d'observation. À utiliser avec précaution, cela " "peut causer des résultats étranges." -#: StyleVarPane.py:65 +#: app/StyleVarPane.py:63 msgid "Allow Adding Goo Mist" msgstr "Ajouter de la brume sur l'acide" -#: StyleVarPane.py:67 +#: app/StyleVarPane.py:65 msgid "" "Add mist particles above Toxic Goo in certain styles. This can increase " "the entity count significantly with large, complex goo pits, so disable " @@ -366,11 +403,11 @@ msgstr "" " styles. Cela peut augmenter le nombre d'entités avec de grandes fosses. " "À désactiver au besoin." -#: StyleVarPane.py:74 +#: app/StyleVarPane.py:72 msgid "Light Reversible Excursion Funnels" msgstr "Lumière réversible des Halos d’Excursion" -#: StyleVarPane.py:76 +#: app/StyleVarPane.py:74 msgid "" "Funnels emit a small amount of light. However, if multiple funnels are " "near each other and can reverse polarity, this can cause lighting issues." @@ -382,11 +419,11 @@ msgstr "" " bugs de lumière. Désactiver cela pour prévenir ces bugs (retire la " "lumière des Halos). Les Halos non réversibles n'ont pas ce problème." -#: StyleVarPane.py:84 +#: app/StyleVarPane.py:82 msgid "Enable Shape Framing" msgstr "Autoriser les contours de symboles" -#: StyleVarPane.py:86 +#: app/StyleVarPane.py:84 msgid "" "After 10 shape-type antlines are used, the signs repeat. With this " "enabled, colored frames will be added to distinguish them." @@ -394,73 +431,73 @@ msgstr "" "Une fois 10 symboles utilisés (mode Signalisation), ils se répètent. Si " "ceci est activé, des cadres colorés seront ajoutés pour les différencier." -#: StyleVarPane.py:155 +#: app/StyleVarPane.py:153 msgid "Default: On" msgstr "Par défaut: On" -#: StyleVarPane.py:157 +#: app/StyleVarPane.py:155 msgid "Default: Off" msgstr "Par défaut: Off" -#: StyleVarPane.py:161 +#: app/StyleVarPane.py:159 msgid "Styles: Unstyled" msgstr "Styles: Sans style" -#: StyleVarPane.py:171 +#: app/StyleVarPane.py:169 msgid "Styles: All" msgstr "Styles: Tous" -#: StyleVarPane.py:179 +#: app/StyleVarPane.py:177 msgid "Style: {}" msgid_plural "Styles: {}" msgstr[0] "Style: {}" msgstr[1] "Styles: {}" -#: StyleVarPane.py:233 +#: app/StyleVarPane.py:231 msgid "Style/Item Properties" msgstr "Propriétés de style/d'objet" -#: StyleVarPane.py:252 +#: app/StyleVarPane.py:250 msgid "Styles" msgstr "Styles" -#: StyleVarPane.py:271 +#: app/StyleVarPane.py:269 msgid "All:" msgstr "Tous:" -#: StyleVarPane.py:274 +#: app/StyleVarPane.py:272 msgid "Selected Style:" msgstr "Style choisi:" -#: StyleVarPane.py:282 +#: app/StyleVarPane.py:280 msgid "Other Styles:" msgstr "Autres styles:" -#: StyleVarPane.py:287 +#: app/StyleVarPane.py:285 msgid "No Options!" msgstr "Pas d'options!" -#: StyleVarPane.py:293 +#: app/StyleVarPane.py:291 msgid "None!" msgstr "Aucun(e)" -#: StyleVarPane.py:364 +#: app/StyleVarPane.py:362 msgid "Items" msgstr "Objets" -#: SubPane.py:84 +#: app/SubPane.py:85 msgid "Hide/Show the \"{}\" window." msgstr "Cacher/Montrer la fenêtre \"{}\"" -#: UI.py:67 +#: app/UI.py:70 msgid "Export..." msgstr "Export..." -#: UI.py:591 +#: app/UI.py:598 msgid "Select Skyboxes" msgstr "Sélectionnez une skybox" -#: UI.py:592 +#: app/UI.py:599 msgid "" "The skybox decides what the area outside the chamber is like. It chooses " "the colour of sky (seen in some items), the style of bottomless pit (if " @@ -471,19 +508,19 @@ msgstr "" "sans fond (si présents) tout comme la couleur du \"brouillard\" (vu dans " "les grandes salles)." -#: UI.py:600 +#: app/UI.py:607 msgid "3D Skybox" msgstr "Skybox 3D" -#: UI.py:601 +#: app/UI.py:608 msgid "Fog Color" msgstr "Couleur du brouillard" -#: UI.py:608 +#: app/UI.py:615 msgid "Select Additional Voice Lines" msgstr "Sélectionnez les répliques additionnelles" -#: UI.py:609 +#: app/UI.py:616 msgid "" "Voice lines choose which extra voices play as the player enters or exits " "a chamber. They are chosen based on which items are present in the map. " @@ -495,31 +532,31 @@ msgstr "" "dans la salle. Les répliques additionnelles de Cave du multivers sont " "contrôlées séparément dans les propriétés de style." -#: UI.py:614 +#: app/UI.py:621 msgid "Add no extra voice lines, only Multiverse Cave if enabled." msgstr "N'ajoute aucune réplique supplémentaire." -#: UI.py:616 +#: app/UI.py:623 msgid "" msgstr "" -#: UI.py:620 +#: app/UI.py:627 msgid "Characters" msgstr "Personnages" -#: UI.py:621 +#: app/UI.py:628 msgid "Turret Shoot Monitor" msgstr "Les tourelles tirent sur les moniteurs" -#: UI.py:622 +#: app/UI.py:629 msgid "Monitor Visuals" msgstr "Visuels des moniteurs" -#: UI.py:629 +#: app/UI.py:636 msgid "Select Style" msgstr "Sélectionnez un style" -#: UI.py:630 +#: app/UI.py:637 msgid "" "The Style controls many aspects of the map. It decides the materials used" " for walls, the appearance of entrances and exits, the design for most " @@ -533,15 +570,15 @@ msgstr "" "\n" "Le style définit de façon large l'époque où se place la salle." -#: UI.py:641 +#: app/UI.py:648 msgid "Elevator Videos" msgstr "Vidéos d'ascenseur" -#: UI.py:648 +#: app/UI.py:655 msgid "Select Elevator Video" msgstr "Sélectionnez une vidéo d'ascenceur" -#: UI.py:649 +#: app/UI.py:656 msgid "" "Set the video played on the video screens in modern Aperture elevator " "rooms. Not all styles feature these. If set to \"None\", a random video " @@ -552,23 +589,23 @@ msgstr "" "est choisit, une vidéo aléatoire sera sélectionnée chaque fois que la " "carte sera jouée, comme avec le style PeTI par défaut." -#: UI.py:653 +#: app/UI.py:660 msgid "This style does not have a elevator video screen." msgstr "Ce style n'a aucune vidéo d'ascenseur." -#: UI.py:658 +#: app/UI.py:665 msgid "Choose a random video." msgstr "Choisit une vidéo aléatoire." -#: UI.py:662 +#: app/UI.py:669 msgid "Multiple Orientations" msgstr "Orientations multiples" -#: UI.py:883 +#: app/UI.py:897 msgid "Selected Items and Style successfully exported!" msgstr "Le style et les objets sélectionnés ont été exportés avec succès !" -#: UI.py:885 +#: app/UI.py:899 msgid "" "\n" "\n" @@ -581,78 +618,71 @@ msgstr "" "Hammer pour assurer le rafraîchissement des apparences des murs en " "prévisualisation." -#: UI.py:898 -#, fuzzy -msgid "" -"\n" -" Launch Game?" -msgstr "Lancer le jeu" - -#: UI.py:1113 +#: app/UI.py:1131 msgid "Delete Palette \"{}\"" msgstr "Supprimer la palette \"{}\"" -#: UI.py:1189 +#: app/UI.py:1207 msgid "BEE2 - Save Palette" msgstr "BEE2 - Enregistrer la palette" -#: UI.py:1190 +#: app/UI.py:1208 msgid "Enter a name:" msgstr "Entrer un nom:" -#: UI.py:1199 +#: app/UI.py:1217 msgid "This palette already exists. Overwrite?" msgstr "Cette palette existe déjà. Remplacer ?" -#: UI.py:1228 gameMan.py:1529 +#: app/UI.py:1249 app/gameMan.py:1527 msgid "Are you sure you want to delete \"{}\"?" msgstr "Êtes-vous sûr de vouloir supprimer cette palette ?" -#: UI.py:1255 +#: app/UI.py:1277 msgid "Clear Palette" msgstr "Vider la palette" -#: UI.py:1291 UI.py:1727 +#: app/UI.py:1313 app/UI.py:1747 msgid "Delete Palette" msgstr "Supprimer la palette" -#: UI.py:1311 +#: app/UI.py:1333 msgid "Save Palette..." msgstr "Enregistrer la palette..." -#: UI.py:1316 UI.py:1750 +#: app/UI.py:1338 app/UI.py:1770 msgid "Save Palette As..." msgstr "Enregistrer la palette sous..." -#: UI.py:1327 UI.py:1738 +#: app/UI.py:1349 app/UI.py:1758 msgid "Save Settings in Palettes" msgstr "" -#: UI.py:1345 music_conf.py:204 +#: app/UI.py:1367 app/music_conf.py:205 msgid "Music: " msgstr "Musique: " -#: UI.py:1371 +#: app/UI.py:1393 msgid "{arr} Use Suggested {arr}" msgstr "{arr} Utiliser les suggestions {arr}" -#: UI.py:1387 +#: app/UI.py:1409 msgid "Style: " msgstr "Style: " -#: UI.py:1389 +#: app/UI.py:1411 msgid "Voice: " msgstr "Voix: " -#: UI.py:1390 +#: app/UI.py:1412 msgid "Skybox: " msgstr "Skybox: " -#: UI.py:1391 +#: app/UI.py:1413 msgid "Elev Vid: " msgstr "Vid Asc: " -#: UI.py:1409 +#: app/UI.py:1431 msgid "" "Enable or disable particular voice lines, to prevent them from being " "added." @@ -660,123 +690,123 @@ msgstr "" "Activer ou désactiver certaines répliques pour les empêcher d'être " "ajoutées." -#: UI.py:1512 +#: app/UI.py:1534 msgid "All Items: " msgstr "Tous les objets: " -#: UI.py:1646 +#: app/UI.py:1666 msgid "Export to \"{}\"..." msgstr "Exporter vers \"{}\"..." -#: UI.py:1674 backup.py:876 +#: app/UI.py:1694 app/backup.py:872 msgid "File" msgstr "Fichier" -#: UI.py:1681 +#: app/UI.py:1701 msgid "Export" msgstr "Exporter" -#: UI.py:1688 backup.py:880 +#: app/UI.py:1708 app/backup.py:876 msgid "Add Game" msgstr "Ajouter le jeu" -#: UI.py:1692 +#: app/UI.py:1712 msgid "Uninstall from Selected Game" msgstr "Désinstaller du jeu sélectionné" -#: UI.py:1696 +#: app/UI.py:1716 msgid "Backup/Restore Puzzles..." msgstr "Sauvegarder/Restaurer les puzzles..." -#: UI.py:1700 +#: app/UI.py:1720 msgid "Manage Packages..." msgstr "Gérer les paquets..." -#: UI.py:1705 +#: app/UI.py:1725 msgid "Options" msgstr "Options" -#: UI.py:1710 gameMan.py:1208 +#: app/UI.py:1730 app/gameMan.py:1206 msgid "Quit" msgstr "Quitter" -#: UI.py:1720 +#: app/UI.py:1740 msgid "Palette" msgstr "Palette" -#: UI.py:1722 +#: app/UI.py:1742 msgid "Clear" msgstr "Vider" -#: UI.py:1731 +#: app/UI.py:1751 msgid "Fill Palette" msgstr "Remplir la palette" -#: UI.py:1745 +#: app/UI.py:1765 msgid "Save Palette" msgstr "Enregistrer la palette" -#: UI.py:1760 +#: app/UI.py:1780 msgid "View" msgstr "" -#: UI.py:1879 +#: app/UI.py:1899 msgid "Palettes" msgstr "Palettes" -#: UI.py:1904 +#: app/UI.py:1924 msgid "Export Options" msgstr "Options d'export" -#: UI.py:1936 +#: app/UI.py:1956 msgid "Fill empty spots in the palette with random items." msgstr "Remplir les emplacements vides de la palette avec des objets aléatoires." -#: backup.py:81 +#: app/backup.py:79 msgid "Copying maps" msgstr "Copie des cartes" -#: backup.py:86 +#: app/backup.py:84 msgid "Loading maps" msgstr "Chargement des cartes" -#: backup.py:91 +#: app/backup.py:89 msgid "Deleting maps" msgstr "Suppression des cartes" -#: backup.py:142 +#: app/backup.py:140 msgid "Failed to parse this puzzle file. It can still be backed up." msgstr "" "Échec du traitement de ce fichier de puzzle. Il peut toujours être " "restauré." -#: backup.py:146 +#: app/backup.py:144 msgid "No description found." msgstr "Aucune description trouvée." -#: backup.py:177 +#: app/backup.py:175 msgid "Coop" msgstr "Coop" -#: backup.py:177 +#: app/backup.py:175 msgid "SP" msgstr "Solo" -#: backup.py:339 +#: app/backup.py:337 msgid "This filename is already in the backup.Do you wish to overwrite it? ({})" msgstr "" "Ce nom de fichier est déjà présent dans la sauvegarde. Voulez-vous le " "remplacer ? ({})" -#: backup.py:445 +#: app/backup.py:443 msgid "BEE2 Backup" msgstr "Sauvegarde BEE2" -#: backup.py:446 +#: app/backup.py:444 msgid "No maps were chosen to backup!" msgstr "Aucune carte sélectionnée !" -#: backup.py:506 +#: app/backup.py:504 msgid "" "This map is already in the game directory.Do you wish to overwrite it? " "({})" @@ -784,27 +814,27 @@ msgstr "" "Cette carte est déjà dans les fichiers du jeu. Voulez-vous la remplacer ?" " ({})" -#: backup.py:568 +#: app/backup.py:566 msgid "Load Backup" msgstr "Charger la sauvegarde" -#: backup.py:569 backup.py:628 +#: app/backup.py:567 app/backup.py:626 msgid "Backup zip" msgstr "Compresser la sauvegarde" -#: backup.py:602 +#: app/backup.py:600 msgid "Unsaved Backup" msgstr "Sauvegarde non enregistrée" -#: backup.py:627 backup.py:874 +#: app/backup.py:625 app/backup.py:870 msgid "Save Backup As" msgstr "Enregistrer la sauvegarde sous" -#: backup.py:724 +#: app/backup.py:721 msgid "Confirm Deletion" msgstr "Confirmer la suppression" -#: backup.py:725 +#: app/backup.py:722 msgid "Do you wish to delete {} map?\n" msgid_plural "Do you wish to delete {} maps?\n" msgstr[0] "" @@ -814,178 +844,178 @@ msgstr[1] "" "Voulez-vous supprimer {} cartes ?\n" "\n" -#: backup.py:762 +#: app/backup.py:759 msgid "Restore:" msgstr "Restaurer:" -#: backup.py:763 +#: app/backup.py:760 msgid "Backup:" msgstr "Sauvegarder:" -#: backup.py:800 +#: app/backup.py:797 msgid "Checked" msgstr "Celles cochées" -#: backup.py:808 +#: app/backup.py:805 msgid "Delete Checked" msgstr "Supprimer celles cochées" -#: backup.py:858 +#: app/backup.py:854 msgid "BEEMOD {} - Backup / Restore Puzzles" msgstr "BEEMOD {} - Sauvegarder / Restaurer les puzzles" -#: backup.py:871 backup.py:999 +#: app/backup.py:867 app/backup.py:995 msgid "New Backup" msgstr "Nouvelle sauvegarde" -#: backup.py:872 backup.py:1006 +#: app/backup.py:868 app/backup.py:1002 msgid "Open Backup" msgstr "Ouvrir la sauvegarde" -#: backup.py:873 backup.py:1013 +#: app/backup.py:869 app/backup.py:1009 msgid "Save Backup" msgstr "Sauvegarder" -#: backup.py:881 +#: app/backup.py:877 msgid "Remove Game" msgstr "Retirer le jeu" -#: backup.py:884 +#: app/backup.py:880 msgid "Game" msgstr "Jeu" -#: backup.py:930 +#: app/backup.py:926 msgid "Automatic Backup After Export" msgstr "Sauvegarde automatique après export" -#: backup.py:962 +#: app/backup.py:958 msgid "Keep (Per Game):" msgstr "Nombre (par jeu):" -#: backup.py:980 +#: app/backup.py:976 msgid "Backup/Restore Puzzles" msgstr "Sauvegarder/Restaurer des puzzles" -#: contextWin.py:79 +#: app/contextWin.py:76 msgid "This item may not be rotated." msgstr "Cet objet ne peut pas être tourné." -#: contextWin.py:80 +#: app/contextWin.py:77 msgid "This item can be pointed in 4 directions." msgstr "Cet objet peut être pointé dans 4 directions." -#: contextWin.py:81 +#: app/contextWin.py:78 msgid "This item can be positioned on the sides and center." msgstr "Cet objet peut être positionné sur les côtés ou au centre." -#: contextWin.py:82 +#: app/contextWin.py:79 msgid "This item can be centered in two directions, plus on the sides." msgstr "Cet objet peut être centré sur deux directions et sur les côtés." -#: contextWin.py:83 +#: app/contextWin.py:80 msgid "This item can be placed like light strips." msgstr "Cet objet peut être placé comme une source lumineuse." -#: contextWin.py:84 +#: app/contextWin.py:81 msgid "This item can be rotated on the floor to face 360 degrees." msgstr "Cet objet peut être tourné sur le sol à 360°." -#: contextWin.py:85 +#: app/contextWin.py:82 msgid "This item is positioned using a catapult trajectory." msgstr "Cet objet est positionné avec une trajectoire de catapulte." -#: contextWin.py:86 +#: app/contextWin.py:83 msgid "This item positions the dropper to hit target locations." msgstr "Cet objet positionne le distributeur pour toucher des zones ciblées." -#: contextWin.py:88 +#: app/contextWin.py:85 msgid "This item does not accept any inputs." msgstr "Cet objet n'accepte pas de connexion entrante." -#: contextWin.py:89 +#: app/contextWin.py:86 msgid "This item accepts inputs." msgstr "Cet objet accepte des connexions entrantes." -#: contextWin.py:90 +#: app/contextWin.py:87 msgid "This item has two input types (A and B), using the Input A and B items." msgstr "" -#: contextWin.py:92 +#: app/contextWin.py:89 msgid "This item does not output." msgstr "Cet objet n'a pas de connexion sortante." -#: contextWin.py:93 +#: app/contextWin.py:90 msgid "This item has an output." msgstr "Cet objet a une connexion sortante." -#: contextWin.py:94 +#: app/contextWin.py:91 msgid "This item has a timed output." msgstr "Cet objet a une connexion sortante temporisée." -#: contextWin.py:96 +#: app/contextWin.py:93 msgid "This item does not take up any space inside walls." msgstr "Cet objet ne prend pas de place dans le mur." -#: contextWin.py:97 +#: app/contextWin.py:94 msgid "This item takes space inside the wall." msgstr "Cet objet prend de la place dans le mur." -#: contextWin.py:99 +#: app/contextWin.py:96 msgid "This item cannot be placed anywhere..." msgstr "Cet objet ne peut pas être placé." -#: contextWin.py:100 +#: app/contextWin.py:97 msgid "This item can only be attached to ceilings." msgstr "Cet objet est attaché au plafond seulement." -#: contextWin.py:101 +#: app/contextWin.py:98 msgid "This item can only be placed on the floor." msgstr "Cet objet est posé au sol seulement." -#: contextWin.py:102 +#: app/contextWin.py:99 msgid "This item can be placed on floors and ceilings." msgstr "Cet objet peut être placé au plafond et au sol." -#: contextWin.py:103 +#: app/contextWin.py:100 msgid "This item can be placed on walls only." msgstr "Cet objet ne se place que sur les murs." -#: contextWin.py:104 +#: app/contextWin.py:101 msgid "This item can be attached to walls and ceilings." msgstr "Cet objet peut être attaché au plafond et aux murs." -#: contextWin.py:105 +#: app/contextWin.py:102 msgid "This item can be placed on floors and walls." msgstr "Cet objet peut être placé au sol et aux murs." -#: contextWin.py:106 +#: app/contextWin.py:103 msgid "This item can be placed in any orientation." msgstr "Cet objet peut être placé dans n'importe quel sens." -#: contextWin.py:212 +#: app/contextWin.py:209 #, fuzzy msgid "No Alternate Versions" msgstr "Pas de versions alternatives !" -#: contextWin.py:304 +#: app/contextWin.py:301 msgid "Excursion Funnels accept a on/off input and a directional input." msgstr "" "Les Halos d'Excursion acceptent une connexion on/off et une connexion de " "polarité." -#: contextWin.py:361 +#: app/contextWin.py:358 #, fuzzy msgid "" "This item can be rotated on the floor to face 360 degrees, for Reflection" " Cubes only." msgstr "Cet objet peut être tourné sur le sol à 360°." -#: contextWin.py:440 +#: app/contextWin.py:437 #, fuzzy msgid "Properties:" msgstr "Propriétés" -#: contextWin.py:462 +#: app/contextWin.py:459 msgid "" "The number of entities used for this item. The Source engine limits this " "to 2048 in total. This provides a guide to how many of these items can be" @@ -995,11 +1025,11 @@ msgstr "" "nombre d'entités à 2048 en tout. Ceci fournit un guide pour savoir " "combien de ces objets il est possible de placer à la fois sur la carte." -#: contextWin.py:487 +#: app/contextWin.py:484 msgid "Description:" msgstr "Description:" -#: contextWin.py:530 +#: app/contextWin.py:527 msgid "" "Failed to open a web browser. Do you wish for the URL to be copied to the" " clipboard instead?" @@ -1007,83 +1037,83 @@ msgstr "" "Échec de l'ouverture du navigateur. Voulez-vous que l'URL soit copiée " "dans le presse-papiers à la place ?" -#: contextWin.py:544 +#: app/contextWin.py:541 msgid "More Info>>" msgstr "Plus d'infos>>" -#: contextWin.py:561 +#: app/contextWin.py:558 msgid "Change Defaults..." msgstr "Changer les valeurs par défaut..." -#: contextWin.py:567 +#: app/contextWin.py:564 msgid "Change the default settings for this item when placed." msgstr "Changer les réglages par défaut pour cet objet lorsqu'il est placé." -#: gameMan.py:750 gameMan.py:852 +#: app/gameMan.py:748 app/gameMan.py:850 msgid "BEE2 - Export Failed!" msgstr "BEE2 - Export échoué !" -#: gameMan.py:751 +#: app/gameMan.py:749 msgid "" "Compiler file {file} missing. Exit Steam applications, then press OK to " "verify your game cache. You can then export again." msgstr "" -#: gameMan.py:853 +#: app/gameMan.py:851 #, fuzzy msgid "Copying compiler file {file} failed. Ensure {game} is not running." msgstr "" "Copie du fichier {file} échouée. Veuillez vous assurer que {game} n'est " "pas en cours d'exécution." -#: gameMan.py:1265 +#: app/gameMan.py:1263 msgid "" "Ap-Tag Coop gun instance not found!\n" "Coop guns will not work - verify cache to fix." msgstr "" -#: gameMan.py:1269 +#: app/gameMan.py:1267 msgid "BEE2 - Aperture Tag Files Missing" msgstr "" -#: gameMan.py:1452 +#: app/gameMan.py:1450 msgid "Select the folder where the game executable is located ({appname})..." msgstr "Sélectionnez le dossier où l'exécutable du jeu est localisé ({appname})..." -#: gameMan.py:1455 gameMan.py:1470 gameMan.py:1480 gameMan.py:1487 -#: gameMan.py:1496 gameMan.py:1505 +#: app/gameMan.py:1453 app/gameMan.py:1468 app/gameMan.py:1478 +#: app/gameMan.py:1485 app/gameMan.py:1494 app/gameMan.py:1503 msgid "BEE2 - Add Game" msgstr "BEE2 - Ajouter un jeu" -#: gameMan.py:1458 +#: app/gameMan.py:1456 msgid "Find Game Exe" msgstr "Trouvez l'exécutable du jeu" -#: gameMan.py:1459 +#: app/gameMan.py:1457 msgid "Executable" msgstr "Exécutable" -#: gameMan.py:1467 +#: app/gameMan.py:1465 msgid "This does not appear to be a valid game folder!" msgstr "Cela ne semble pas être un dossier de jeu valide." -#: gameMan.py:1477 +#: app/gameMan.py:1475 msgid "Portal Stories: Mel doesn't have an editor!" msgstr "Portal Stories: Mel n'a pas d'éditeur." -#: gameMan.py:1488 +#: app/gameMan.py:1486 msgid "Enter the name of this game:" msgstr "Entrez le nom de ce jeu:" -#: gameMan.py:1495 +#: app/gameMan.py:1493 msgid "This name is already taken!" msgstr "Ce nom est déjà pris !" -#: gameMan.py:1504 +#: app/gameMan.py:1502 msgid "Please enter a name for this game!" msgstr "Veuillez entrer un nom pour ce jeu." -#: gameMan.py:1523 +#: app/gameMan.py:1521 msgid "" "\n" " (BEE2 will quit, this is the last game set!)" @@ -1091,79 +1121,79 @@ msgstr "" "\n" "(BEE2 va se fermer.)" -#: helpMenu.py:60 +#: app/helpMenu.py:56 msgid "Wiki..." msgstr "Wiki..." -#: helpMenu.py:62 +#: app/helpMenu.py:58 msgid "Original Items..." msgstr "Items originaux..." -#: helpMenu.py:67 +#: app/helpMenu.py:63 msgid "Discord Server..." msgstr "Serveur Discord..." -#: helpMenu.py:68 +#: app/helpMenu.py:64 msgid "aerond's Music Changer..." msgstr "" -#: helpMenu.py:70 +#: app/helpMenu.py:66 msgid "Application Repository..." msgstr "Emplacement web de l'application..." -#: helpMenu.py:71 +#: app/helpMenu.py:67 msgid "Items Repository..." msgstr "Emplacement web des objets..." -#: helpMenu.py:73 +#: app/helpMenu.py:69 msgid "Submit Application Bugs..." msgstr "Soumettre un bug de l'application..." -#: helpMenu.py:74 +#: app/helpMenu.py:70 msgid "Submit Item Bugs..." msgstr "Soumettre un bug des objets..." -#: helpMenu.py:76 paletteLoader.py:35 +#: app/helpMenu.py:72 app/paletteLoader.py:35 msgid "Portal 2" msgstr "Portal 2" -#: helpMenu.py:77 paletteLoader.py:37 +#: app/helpMenu.py:73 app/paletteLoader.py:37 msgid "Aperture Tag" msgstr "Aperture Tag" -#: helpMenu.py:78 +#: app/helpMenu.py:74 msgid "Portal Stories: Mel" msgstr "Portal Stories: Mel" -#: helpMenu.py:79 +#: app/helpMenu.py:75 msgid "Thinking With Time Machine" msgstr "Thinking with Time Machine" -#: helpMenu.py:242 itemPropWin.py:347 +#: app/helpMenu.py:238 app/itemPropWin.py:342 msgid "Close" msgstr "Fermer" -#: helpMenu.py:266 +#: app/helpMenu.py:262 msgid "Help" msgstr "Aide" -#: helpMenu.py:277 +#: app/helpMenu.py:273 msgid "BEE2 Credits" msgstr "Crédits du BEE2" -#: helpMenu.py:294 +#: app/helpMenu.py:290 msgid "Credits..." msgstr "Crédits..." -#: itemPropWin.py:43 +#: app/itemPropWin.py:38 msgid "Start Position" msgstr "Position de départ" -#: itemPropWin.py:44 +#: app/itemPropWin.py:39 msgid "End Position" msgstr "Position de fin" -#: itemPropWin.py:45 +#: app/itemPropWin.py:40 msgid "" "Delay \n" "(0=infinite)" @@ -1171,76 +1201,44 @@ msgstr "" "Délai\n" "(0=infini)" -#: itemPropWin.py:346 +#: app/itemPropWin.py:341 msgid "No Properties available!" msgstr "Aucune propriété disponible !" -#: itemconfig.py:621 +#: app/itemconfig.py:616 msgid "Choose a Color" msgstr "Choisissez une couleur" -#: loadScreen.py:199 -msgid "Skipped!" -msgstr "Sauté !" - -#: loadScreen.py:200 -msgid "Version: " -msgstr "Version: " - -#: loadScreen.py:201 optionWindow.py:252 packageMan.py:116 selectorWin.py:723 -msgid "Cancel" -msgstr "Annuler" - -#: loadScreen.py:211 tagsPane.py:53 -msgid "Packages" -msgstr "Paquets" - -#: loadScreen.py:212 -msgid "Loading Objects" -msgstr "Chargement des objets" - -#: loadScreen.py:213 -msgid "Loading Images" -msgstr "Chargement des images" - -#: loadScreen.py:214 -msgid "Initialising UI" -msgstr "Initialisation de l'interface" - -#: loadScreen.py:215 -msgid "Better Extended Editor for Portal 2" -msgstr "Better Extended Editor pour Portal 2" - -#: logWindow.py:30 +#: app/logWindow.py:29 msgid "Debug messages" msgstr "Messages de débug" -#: logWindow.py:31 +#: app/logWindow.py:30 msgid "Default" msgstr "Par défaut" -#: logWindow.py:32 +#: app/logWindow.py:31 msgid "Warnings Only" msgstr "Avertissements seulement" -#: logWindow.py:160 +#: app/logWindow.py:159 msgid "Logs - {}" msgstr "Logs - {}" -#: logWindow.py:209 +#: app/logWindow.py:208 msgid "Copy" msgstr "Copier" -#: logWindow.py:221 +#: app/logWindow.py:220 msgid "Show:" msgstr "Montrer:" -#: music_conf.py:132 +#: app/music_conf.py:133 #, fuzzy msgid "Select Background Music - Base" msgstr "Sélectionnez la musique de fond" -#: music_conf.py:133 +#: app/music_conf.py:134 #, fuzzy msgid "" "This controls the background music used for a map. Expand the dropdown to" @@ -1250,160 +1248,192 @@ msgstr "" " ont des variations jouées lors d’interactions avec certains éléments de " "test." -#: music_conf.py:137 +#: app/music_conf.py:138 msgid "" "Add no music to the map at all. Testing Element-specific music may still " "be added." msgstr "N'ajoute aucune musique à la carte." -#: music_conf.py:142 +#: app/music_conf.py:143 msgid "Propulsion Gel SFX" msgstr "Effet sonore pour Gel Propulsif" -#: music_conf.py:143 +#: app/music_conf.py:144 msgid "Repulsion Gel SFX" msgstr "Effet sonore pour Gel Répulsif" -#: music_conf.py:144 +#: app/music_conf.py:145 msgid "Excursion Funnel Music" msgstr "Musique du Halo d'Excursion" -#: music_conf.py:145 music_conf.py:160 +#: app/music_conf.py:146 app/music_conf.py:161 msgid "Synced Funnel Music" msgstr "Musique du Halo synchronisée" -#: music_conf.py:152 +#: app/music_conf.py:153 #, fuzzy msgid "Select Excursion Funnel Music" msgstr "Musique du Halo d'Excursion" -#: music_conf.py:153 +#: app/music_conf.py:154 msgid "Set the music used while inside Excursion Funnels." msgstr "" -#: music_conf.py:156 +#: app/music_conf.py:157 msgid "Have no music playing when inside funnels." msgstr "" -#: music_conf.py:167 +#: app/music_conf.py:168 msgid "Select Repulsion Gel Music" msgstr "" -#: music_conf.py:168 +#: app/music_conf.py:169 msgid "Select the music played when players jump on Repulsion Gel." msgstr "" -#: music_conf.py:171 +#: app/music_conf.py:172 msgid "Add no music when jumping on Repulsion Gel." msgstr "" -#: music_conf.py:179 +#: app/music_conf.py:180 #, fuzzy msgid "Select Propulsion Gel Music" msgstr "Sélectionnez la musique de fond" -#: music_conf.py:180 +#: app/music_conf.py:181 msgid "" "Select music played when players have large amounts of horizontal " "velocity." msgstr "" -#: music_conf.py:183 +#: app/music_conf.py:184 msgid "Add no music while running fast." msgstr "" -#: music_conf.py:218 +#: app/music_conf.py:219 msgid "Base: " msgstr "" -#: music_conf.py:251 +#: app/music_conf.py:252 msgid "Funnel:" msgstr "" -#: music_conf.py:252 +#: app/music_conf.py:253 msgid "Bounce:" msgstr "" -#: music_conf.py:253 +#: app/music_conf.py:254 msgid "Speed:" msgstr "" -#: optionWindow.py:62 +#: app/optionWindow.py:45 +#, fuzzy +msgid "" +"\n" +"Launch Game?" +msgstr "Lancer le jeu" + +#: app/optionWindow.py:47 +#, fuzzy +msgid "" +"\n" +"Minimise BEE2?" +msgstr "Minimiser le BEE2" + +#: app/optionWindow.py:48 +msgid "" +"\n" +"Launch Game and minimise BEE2?" +msgstr "" + +#: app/optionWindow.py:50 +msgid "" +"\n" +"Quit BEE2?" +msgstr "" + +#: app/optionWindow.py:51 +msgid "" +"\n" +"Launch Game and quit BEE2?" +msgstr "" + +#: app/optionWindow.py:70 msgid "BEE2 Options" msgstr "Options BEE2" -#: optionWindow.py:101 +#: app/optionWindow.py:108 msgid "" "Package cache times have been reset. These will now be extracted during " "the next export." msgstr "" -#: optionWindow.py:118 +#: app/optionWindow.py:125 msgid "\"Preserve Game Resources\" has been disabled." msgstr "" -#: optionWindow.py:130 +#: app/optionWindow.py:137 #, fuzzy msgid "Packages Reset" msgstr "Paquets" -#: optionWindow.py:211 +#: app/optionWindow.py:218 msgid "General" msgstr "Général" -#: optionWindow.py:217 +#: app/optionWindow.py:224 msgid "Windows" msgstr "Windows" -#: optionWindow.py:223 +#: app/optionWindow.py:230 msgid "Development" msgstr "Développement" -#: optionWindow.py:247 packageMan.py:110 selectorWin.py:701 +#: app/optionWindow.py:254 app/packageMan.py:110 app/selector_win.py:696 msgid "OK" msgstr "OK" -#: optionWindow.py:278 +#: app/optionWindow.py:285 msgid "After Export:" msgstr "Après l'export:" -#: optionWindow.py:295 +#: app/optionWindow.py:302 msgid "Do Nothing" msgstr "Ne rien faire" -#: optionWindow.py:301 +#: app/optionWindow.py:308 msgid "Minimise BEE2" msgstr "Minimiser le BEE2" -#: optionWindow.py:307 +#: app/optionWindow.py:314 msgid "Quit BEE2" msgstr "Quitter le BEE2" -#: optionWindow.py:315 +#: app/optionWindow.py:322 msgid "After exports, do nothing and keep the BEE2 in focus." msgstr "Après l'export, ne rien faire et garder le BEE2 au premier plan." -#: optionWindow.py:317 +#: app/optionWindow.py:324 msgid "After exports, minimise to the taskbar/dock." msgstr "Après l'export, minimiser le BEE2 dans la barre des tâches." -#: optionWindow.py:318 +#: app/optionWindow.py:325 msgid "After exports, quit the BEE2." msgstr "Après l'export, quitter le BEE2." -#: optionWindow.py:325 +#: app/optionWindow.py:332 msgid "Launch Game" msgstr "Lancer le jeu" -#: optionWindow.py:326 +#: app/optionWindow.py:333 msgid "After exporting, launch the selected game automatically." msgstr "Après l'export, lancer le jeu sélectionné automatiquement." -#: optionWindow.py:334 optionWindow.py:340 +#: app/optionWindow.py:341 app/optionWindow.py:347 msgid "Play Sounds" msgstr "Jouer les sons" -#: optionWindow.py:345 +#: app/optionWindow.py:352 msgid "" "Pyglet is either not installed or broken.\n" "Sound effects have been disabled." @@ -1411,22 +1441,22 @@ msgstr "" "Pyglet est soit désinstallé soit endommagé.\n" "Les effets sonores ont été désactivés." -#: optionWindow.py:352 +#: app/optionWindow.py:359 msgid "Reset Package Caches" msgstr "Réinitialiser le cache des paquets" -#: optionWindow.py:358 +#: app/optionWindow.py:365 #, fuzzy msgid "Force re-extracting all package resources." msgstr "" "Forcer la ré-extraction de tous les paquets de ressources. Cela requiert " "un redémarrage." -#: optionWindow.py:367 +#: app/optionWindow.py:374 msgid "Keep windows inside screen" msgstr "Garder les fenêtres dans l'écran." -#: optionWindow.py:368 +#: app/optionWindow.py:375 msgid "" "Prevent sub-windows from moving outside the screen borders. If you have " "multiple monitors, disable this." @@ -1434,27 +1464,27 @@ msgstr "" "Empêcher les sous-fenêtres de sortir des limites de l'écran. Si vous avez" " plusieurs écrans, désactivez cela." -#: optionWindow.py:378 +#: app/optionWindow.py:385 #, fuzzy msgid "Keep loading screens on top" msgstr "Supprimer les anciens screenshots" -#: optionWindow.py:380 +#: app/optionWindow.py:387 msgid "" "Force loading screens to be on top of other windows. Since they don't " "appear on the taskbar/dock, they can't be brought to the top easily " "again." msgstr "" -#: optionWindow.py:389 +#: app/optionWindow.py:396 msgid "Reset All Window Positions" msgstr "Réinitialiser les positions des sous-fenêtres" -#: optionWindow.py:403 +#: app/optionWindow.py:410 msgid "Log missing entity counts" msgstr "Enregistrer dans un fichier les nombres d'entités manquants" -#: optionWindow.py:404 +#: app/optionWindow.py:411 msgid "" "When loading items, log items with missing entity counts in their " "properties.txt file." @@ -1462,11 +1492,11 @@ msgstr "" "Lors du chargement des objets, enregistrer les objets n'ayant pas de " "nombre d'entités dans leur fichier properties.txt." -#: optionWindow.py:412 +#: app/optionWindow.py:419 msgid "Log when item doesn't have a style" msgstr "Enregistrer dans un fichier quand un objet n'a pas de style" -#: optionWindow.py:413 +#: app/optionWindow.py:420 msgid "" "Log items have no applicable version for a particular style.This usually " "means it will look very bad." @@ -1474,11 +1504,11 @@ msgstr "" "Enregistrer dans un fichier les objets n'ayant pas de version applicable " "pour un style donné. Cela signifie qu'il rendra très moche." -#: optionWindow.py:421 +#: app/optionWindow.py:428 msgid "Log when item uses parent's style" msgstr "Enregistrer dans un fichier quand un objet utilise le style du parent" -#: optionWindow.py:422 +#: app/optionWindow.py:429 msgid "" "Log when an item reuses a variant from a parent style (1970s using 1950s " "items, for example). This is usually fine, but may need to be fixed." @@ -1488,11 +1518,11 @@ msgstr "" "Ce n'est généralement pas un problème mais nécessite parfois des " "ajustements." -#: optionWindow.py:431 +#: app/optionWindow.py:438 msgid "Log missing packfile resources" msgstr "Enregistrer dans un fichier les ressources empaquetées manquantes" -#: optionWindow.py:432 +#: app/optionWindow.py:439 msgid "" "Log when the resources a \"PackList\" refers to are not present in the " "zip. This may be fine (in a prerequisite zip), but it often indicates an " @@ -1502,16 +1532,17 @@ msgstr "" "\"PackList\" ne sont pas présentes dans le zip. Cela peut être normal " "(dans un zip prérequis) mais peut autrement indiquer un erreur." -#: optionWindow.py:441 +#: app/optionWindow.py:448 msgid "Preserve Game Directories" msgstr "Préserver les dossiers du jeu" -#: optionWindow.py:443 +#: app/optionWindow.py:450 +#, fuzzy msgid "" -"When exporting, do not overwrite \n" -"\"bee2/\" and\n" -"\"sdk_content/maps/bee2/\".\n" -"Enable if you're developing new content, to ensure it is not overwritten." +"When exporting, do not copy resources to \n" +"\"bee2/\" and \"sdk_content/maps/bee2/\".\n" +"Only enable if you're developing new content, to ensure it is not " +"overwritten." msgstr "" "Lors de l'export, ne pas remplacer\n" "\"bee2/\" et\n" @@ -1519,38 +1550,38 @@ msgstr "" "Activez cela si vous développez du contenu nouveau afin qu'il ne soit pas" " remplacé." -#: optionWindow.py:454 +#: app/optionWindow.py:461 msgid "Show Log Window" msgstr "Montrer la fenêtre de log" -#: optionWindow.py:456 +#: app/optionWindow.py:463 msgid "Show the log file in real-time." msgstr "Montrer le log en temps réel." -#: optionWindow.py:463 +#: app/optionWindow.py:470 msgid "Force Editor Models" msgstr "" -#: optionWindow.py:464 +#: app/optionWindow.py:471 msgid "" "Make all props_map_editor models available for use. Portal 2 has a limit " "of 1024 models loaded in memory at once, so we need to disable unused " "ones to free this up." msgstr "" -#: optionWindow.py:475 +#: app/optionWindow.py:482 msgid "Dump All objects" msgstr "" -#: optionWindow.py:481 +#: app/optionWindow.py:488 msgid "Dump Items list" msgstr "" -#: packageMan.py:64 +#: app/packageMan.py:64 msgid "BEE2 - Restart Required!" msgstr "BEE2 - Redémarrage requis !" -#: packageMan.py:65 +#: app/packageMan.py:65 msgid "" "Changing enabled packages requires a restart.\n" "Continue?" @@ -1558,181 +1589,182 @@ msgstr "" "Changer les paquets activés demande un redémarrage.\n" "Continuer ?" -#: packageMan.py:88 +#: app/packageMan.py:88 msgid "BEE2 - Manage Packages" msgstr "BEE2 - Gérer les paquets" -#: paletteLoader.py:25 +#: app/paletteLoader.py:25 msgid "" msgstr "" -#: paletteLoader.py:27 +#: app/paletteLoader.py:27 msgid "Blank" msgstr "Vide" -#: paletteLoader.py:30 +#: app/paletteLoader.py:30 msgid "BEEMod" msgstr "BEEMod" -#: paletteLoader.py:32 +#: app/paletteLoader.py:32 msgid "Portal 2 Collapsed" msgstr "Portal 2 Compressé" -#: richTextBox.py:153 +#: app/richTextBox.py:152 msgid "Open \"{}\" in the default browser?" msgstr "Ouvrir \"{}\" dans le navigateur par défaut ?" -#: selectorWin.py:404 +#: app/selector_win.py:399 msgid "Do not add anything." msgstr "Ne rien ajouter." -#: selectorWin.py:408 +#: app/selector_win.py:403 msgid "" msgstr "" -#: selectorWin.py:585 selectorWin.py:590 +#: app/selector_win.py:580 app/selector_win.py:585 msgid "Suggested" msgstr "Suggéré" -#: selectorWin.py:638 +#: app/selector_win.py:633 msgid "Play a sample of this item." msgstr "Jouer un échantillon de cet objet" -#: selectorWin.py:712 +#: app/selector_win.py:707 msgid "Reset to Default" msgstr "Réinitialiser aux valeurs par défaut" -#: selectorWin.py:773 +#: app/selector_win.py:768 msgid "Other" msgstr "Autre" -#: selectorWin.py:1086 +#: app/selector_win.py:1081 msgid "Author: {}" msgid_plural "Authors: {}" msgstr[0] "Auteur: {}" msgstr[1] "Auteurs: {}" -#: selectorWin.py:1142 +#: app/selector_win.py:1137 msgid "Color: R={r}, G={g}, B={b}" msgstr "Couleur: R={r}, V={g}, B={b}" -#: signage_ui.py:140 signage_ui.py:213 +#: app/signage_ui.py:139 app/signage_ui.py:212 msgid "Configure Signage" msgstr "" -#: signage_ui.py:144 +#: app/signage_ui.py:143 #, fuzzy msgid "Selected" msgstr "Style choisi:" -#: signage_ui.py:167 +#: app/signage_ui.py:166 msgid "Signage: {}" msgstr "" -#: tagsPane.py:51 +#: app/tagsPane.py:46 msgid "Tags" msgstr "Tags" -#: tagsPane.py:52 +#: app/tagsPane.py:47 msgid "Authors" msgstr "Auteurs" -#: tagsPane.py:162 +#: app/tagsPane.py:157 msgid "Any" msgstr "N'importe" -#: tagsPane.py:171 +#: app/tagsPane.py:166 msgid "All" msgstr "Tout" -#: tagsPane.py:197 +#: app/tagsPane.py:192 msgid "Available Tags (click):" msgstr "Tags disponibles (cliquez):" -#: utils.py:841 -msgid "__LANG_USE_SANS_SERIF__" -msgstr "" - -#: voiceEditor.py:35 +#: app/voiceEditor.py:33 msgid "Singleplayer" msgstr "" -#: voiceEditor.py:36 +#: app/voiceEditor.py:34 #, fuzzy msgid "Cooperative" msgstr "Propriétés" -#: voiceEditor.py:37 +#: app/voiceEditor.py:35 msgid "ATLAS (SP/Coop)" msgstr "" -#: voiceEditor.py:38 +#: app/voiceEditor.py:36 msgid "P-Body (SP/Coop)" msgstr "" -#: voiceEditor.py:41 +#: app/voiceEditor.py:39 msgid "Human characters (Bendy and Chell)" msgstr "" -#: voiceEditor.py:42 +#: app/voiceEditor.py:40 msgid "AI characters (ATLAS, P-Body, or Coop)" msgstr "" -#: voiceEditor.py:53 +#: app/voiceEditor.py:51 msgid "Death - Toxic Goo" msgstr "Mort - Acide mortel" -#: voiceEditor.py:54 +#: app/voiceEditor.py:52 msgid "Death - Turrets" msgstr "Mort - Tourelles" -#: voiceEditor.py:55 +#: app/voiceEditor.py:53 msgid "Death - Crusher" msgstr "Mort - Écrabouilleur" -#: voiceEditor.py:56 +#: app/voiceEditor.py:54 msgid "Death - LaserField" msgstr "Mort - Champ de lasers" -#: voiceEditor.py:107 +#: app/voiceEditor.py:105 msgid "Transcript:" msgstr "Transcript:" -#: voiceEditor.py:146 +#: app/voiceEditor.py:144 msgid "Save" msgstr "Enregistrer" -#: voiceEditor.py:221 +#: app/voiceEditor.py:219 msgid "Resp" msgstr "Rép." -#: voiceEditor.py:238 +#: app/voiceEditor.py:236 msgid "BEE2 - Configure \"{}\"" msgstr "BEE2 - Configurer \"{}\"" -#: voiceEditor.py:315 +#: app/voiceEditor.py:313 msgid "Mid - Chamber" msgstr "En cours de salle" -#: voiceEditor.py:317 +#: app/voiceEditor.py:315 msgid "" "Lines played during the actual chamber, after specific events have " "occurred." msgstr "Répliques jouées durant la salle après certains événements spécifiques." -#: voiceEditor.py:323 +#: app/voiceEditor.py:321 msgid "Responses" msgstr "Réponses" -#: voiceEditor.py:325 +#: app/voiceEditor.py:323 msgid "Lines played in response to certain events in Coop." msgstr "Répliques jouées en réponse à certains événements en Coop." -#: voiceEditor.py:423 +#: app/voiceEditor.py:421 msgid "No Name!" msgstr "Sans nom !" -#: voiceEditor.py:458 +#: app/voiceEditor.py:456 msgid "No Name?" msgstr "Sans nom ?" +#~ msgid "" +#~ "\n" +#~ " Launch Game?" +#~ msgstr "Lancer le jeu" + diff --git a/i18n/ja.po b/i18n/ja.po index b001f5e3f..9abd2c362 100644 --- a/i18n/ja.po +++ b/i18n/ja.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2020-07-18 11:58+1000\n" +"POT-Creation-Date: 2020-09-20 10:31-0700\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: ja\n" @@ -12,36 +12,73 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.6.0\n" +"Generated-By: Babel 2.8.0\n" -#: CheckDetails.py:220 +#: loadScreen.py:199 +msgid "Skipped!" +msgstr "" + +#: loadScreen.py:200 +msgid "Version: " +msgstr "バージョン:" + +#: app/optionWindow.py:259 app/packageMan.py:116 app/selector_win.py:718 +#: loadScreen.py:201 +msgid "Cancel" +msgstr "キャンセル" + +#: app/tagsPane.py:48 loadScreen.py:211 +msgid "Packages" +msgstr "" + +#: loadScreen.py:212 +msgid "Loading Objects" +msgstr "" + +#: loadScreen.py:213 +msgid "Loading Images" +msgstr "" + +#: loadScreen.py:214 +msgid "Initialising UI" +msgstr "" + +#: loadScreen.py:215 +msgid "Better Extended Editor for Portal 2" +msgstr "" + +#: utils.py:841 +msgid "__LANG_USE_SANS_SERIF__" +msgstr "YES" + +#: app/CheckDetails.py:219 msgid "Toggle all checkboxes." msgstr "" -#: CompilerPane.py:66 +#: app/CompilerPane.py:64 msgid "ATLAS" msgstr "ATLAS" -#: CompilerPane.py:67 +#: app/CompilerPane.py:65 msgid "P-Body" msgstr "P-Body" -#: CompilerPane.py:68 voiceEditor.py:40 +#: app/CompilerPane.py:66 app/voiceEditor.py:38 msgid "Chell" msgstr "Chell" -#: CompilerPane.py:69 voiceEditor.py:39 +#: app/CompilerPane.py:67 app/voiceEditor.py:37 msgid "Bendy" msgstr "Bendy" -#: CompilerPane.py:122 +#: app/CompilerPane.py:120 msgid "" "Brushes form the walls or other parts of the test chamber. If this is " "high, it may help to reduce the size of the map or remove intricate " "shapes." msgstr "" -#: CompilerPane.py:129 +#: app/CompilerPane.py:127 msgid "" "Entities are the things in the map that have functionality. Removing " "complex moving items will help reduce this. Items have their entity count" @@ -52,66 +89,66 @@ msgid "" "entities at runtime." msgstr "" -#: CompilerPane.py:139 +#: app/CompilerPane.py:137 msgid "" "Overlays are smaller images affixed to surfaces, like signs or indicator " "lights. Hiding complex antlines or setting them to signage will reduce " "this." msgstr "" -#: CompilerPane.py:275 +#: app/CompilerPane.py:273 msgid "Corridor" msgstr "廊下" -#: CompilerPane.py:316 +#: app/CompilerPane.py:314 msgid "" "Randomly choose a corridor. This is saved in the puzzle data and will not" " change." msgstr "" -#: CompilerPane.py:322 UI.py:657 +#: app/CompilerPane.py:320 app/UI.py:664 msgid "Random" msgstr "ランダム" -#: CompilerPane.py:421 +#: app/CompilerPane.py:419 msgid "Image Files" msgstr "" -#: CompilerPane.py:504 +#: app/CompilerPane.py:502 msgid "" "Options on this panel can be changed \n" "without exporting or restarting the game." msgstr "" -#: CompilerPane.py:519 +#: app/CompilerPane.py:517 msgid "Map Settings" msgstr "マップ" -#: CompilerPane.py:524 +#: app/CompilerPane.py:522 msgid "Compile Settings" msgstr "コンパイラ" -#: CompilerPane.py:538 +#: app/CompilerPane.py:536 msgid "Thumbnail" msgstr "サムネイル" -#: CompilerPane.py:546 +#: app/CompilerPane.py:544 msgid "Auto" msgstr "自動" -#: CompilerPane.py:554 +#: app/CompilerPane.py:552 msgid "PeTI" msgstr "PeTI" -#: CompilerPane.py:562 +#: app/CompilerPane.py:560 msgid "Custom:" msgstr "カスタム:" -#: CompilerPane.py:580 +#: app/CompilerPane.py:578 msgid "Cleanup old screenshots" msgstr "" -#: CompilerPane.py:590 +#: app/CompilerPane.py:588 msgid "" "Override the map image to use a screenshot automatically taken from the " "beginning of a chamber. Press F5 to take a new screenshot. If the map has" @@ -119,199 +156,199 @@ msgid "" "PeTI screenshot will be used instead." msgstr "" -#: CompilerPane.py:598 +#: app/CompilerPane.py:596 msgid "Use the normal editor view for the map preview image." msgstr "" -#: CompilerPane.py:600 +#: app/CompilerPane.py:598 msgid "" "Use a custom image for the map preview image. Click the screenshot to " "select.\n" "Images will be converted to JPEGs if needed." msgstr "" -#: CompilerPane.py:617 +#: app/CompilerPane.py:615 msgid "" "Automatically delete unused Automatic screenshots. Disable if you want to" " keep things in \"portal2/screenshots\". " msgstr "" -#: CompilerPane.py:628 +#: app/CompilerPane.py:626 msgid "Lighting:" msgstr "照明:" -#: CompilerPane.py:635 +#: app/CompilerPane.py:633 msgid "Fast" msgstr "迅速" -#: CompilerPane.py:642 +#: app/CompilerPane.py:640 msgid "Full" msgstr "完成" -#: CompilerPane.py:650 +#: app/CompilerPane.py:648 msgid "" "Compile with lower-quality, fast lighting. This speeds up compile times, " "but does not appear as good. Some shadows may appear wrong.\n" "When publishing, this is ignored." msgstr "" -#: CompilerPane.py:657 +#: app/CompilerPane.py:655 msgid "" "Compile with high-quality lighting. This looks correct, but takes longer " "to compute. Use if you're arranging lights.\n" "When publishing, this is always used." msgstr "" -#: CompilerPane.py:664 +#: app/CompilerPane.py:662 msgid "Dump packed files to:" msgstr "" -#: CompilerPane.py:689 +#: app/CompilerPane.py:687 msgid "" "When compiling, dump all files which were packed into the map. Useful if " "you're intending to edit maps in Hammer." msgstr "" -#: CompilerPane.py:695 +#: app/CompilerPane.py:693 msgid "Last Compile:" msgstr "前のコンパイル:" -#: CompilerPane.py:705 +#: app/CompilerPane.py:703 msgid "Entity" msgstr "エンティティ" -#: CompilerPane.py:725 +#: app/CompilerPane.py:723 msgid "Overlay" msgstr "オーバーレイ" -#: CompilerPane.py:744 +#: app/CompilerPane.py:742 msgid "" "Refresh the compile progress bars. Press after a compile has been " "performed to show the new values." msgstr "" -#: CompilerPane.py:750 +#: app/CompilerPane.py:748 msgid "Brush" msgstr "ブラシ" -#: CompilerPane.py:778 +#: app/CompilerPane.py:776 msgid "Voicelines:" msgstr "" -#: CompilerPane.py:785 +#: app/CompilerPane.py:783 msgid "Use voiceline priorities" msgstr "" -#: CompilerPane.py:791 +#: app/CompilerPane.py:789 msgid "" "Only choose the highest-priority voicelines. This means more generic " "lines will can only be chosen if few test elements are in the map. If " "disabled any applicable lines will be used." msgstr "" -#: CompilerPane.py:798 +#: app/CompilerPane.py:796 msgid "Spawn at:" msgstr "" -#: CompilerPane.py:809 +#: app/CompilerPane.py:807 msgid "Entry Door" msgstr "入口" -#: CompilerPane.py:816 +#: app/CompilerPane.py:814 msgid "Elevator" msgstr "エレベーター" -#: CompilerPane.py:826 +#: app/CompilerPane.py:824 msgid "" "When previewing in SP, spawn inside the entry elevator. Use this to " "examine the entry and exit corridors." msgstr "" -#: CompilerPane.py:831 +#: app/CompilerPane.py:829 msgid "When previewing in SP, spawn just before the entry door." msgstr "" -#: CompilerPane.py:837 +#: app/CompilerPane.py:835 msgid "Corridor:" msgstr "廊下:" -#: CompilerPane.py:856 +#: app/CompilerPane.py:854 msgid "SP Entry:" msgstr "SP入口:" -#: CompilerPane.py:861 +#: app/CompilerPane.py:859 msgid "SP Exit:" msgstr "SP出口:" -#: CompilerPane.py:866 +#: app/CompilerPane.py:864 msgid "Coop:" msgstr "生協出口:" -#: CompilerPane.py:872 +#: app/CompilerPane.py:870 msgid "Player Model (SP):" msgstr "" -#: CompilerPane.py:896 +#: app/CompilerPane.py:894 msgid "Compile Options" msgstr "" -#: CompilerPane.py:914 +#: app/CompilerPane.py:912 msgid "Compiler Options - {}" msgstr "" -#: StyleVarPane.py:33 +#: app/StyleVarPane.py:31 msgid "Multiverse Cave" msgstr "" -#: StyleVarPane.py:35 +#: app/StyleVarPane.py:33 msgid "Play the Workshop Cave Johnson lines on map start." msgstr "" -#: StyleVarPane.py:40 +#: app/StyleVarPane.py:38 msgid "Prevent Portal Bump (fizzler)" msgstr "" -#: StyleVarPane.py:42 +#: app/StyleVarPane.py:40 msgid "" "Add portal bumpers to make it more difficult to portal across fizzler " "edges. This can prevent placing portals in tight spaces near fizzlers, or" " fizzle portals on activation." msgstr "" -#: StyleVarPane.py:49 +#: app/StyleVarPane.py:47 msgid "Suppress Mid-Chamber Dialogue" msgstr "" -#: StyleVarPane.py:51 +#: app/StyleVarPane.py:49 msgid "Disable all voicelines other than entry and exit lines." msgstr "" -#: StyleVarPane.py:56 +#: app/StyleVarPane.py:54 msgid "Unlock Default Items" msgstr "" -#: StyleVarPane.py:58 +#: app/StyleVarPane.py:56 msgid "" "Allow placing and deleting the mandatory Entry/Exit Doors and Large " "Observation Room. Use with caution, this can have weird results!" msgstr "" -#: StyleVarPane.py:65 +#: app/StyleVarPane.py:63 msgid "Allow Adding Goo Mist" msgstr "" -#: StyleVarPane.py:67 +#: app/StyleVarPane.py:65 msgid "" "Add mist particles above Toxic Goo in certain styles. This can increase " "the entity count significantly with large, complex goo pits, so disable " "if needed." msgstr "" -#: StyleVarPane.py:74 +#: app/StyleVarPane.py:72 msgid "Light Reversible Excursion Funnels" msgstr "" -#: StyleVarPane.py:76 +#: app/StyleVarPane.py:74 msgid "" "Funnels emit a small amount of light. However, if multiple funnels are " "near each other and can reverse polarity, this can cause lighting issues." @@ -319,101 +356,101 @@ msgid "" " do not have this issue." msgstr "" -#: StyleVarPane.py:84 +#: app/StyleVarPane.py:82 msgid "Enable Shape Framing" msgstr "" -#: StyleVarPane.py:86 +#: app/StyleVarPane.py:84 msgid "" "After 10 shape-type antlines are used, the signs repeat. With this " "enabled, colored frames will be added to distinguish them." msgstr "" -#: StyleVarPane.py:155 +#: app/StyleVarPane.py:153 msgid "Default: On" msgstr "" -#: StyleVarPane.py:157 +#: app/StyleVarPane.py:155 msgid "Default: Off" msgstr "" -#: StyleVarPane.py:161 +#: app/StyleVarPane.py:159 msgid "Styles: Unstyled" msgstr "" -#: StyleVarPane.py:171 +#: app/StyleVarPane.py:169 msgid "Styles: All" msgstr "" -#: StyleVarPane.py:179 +#: app/StyleVarPane.py:177 msgid "Style: {}" msgid_plural "Styles: {}" msgstr[0] "" -#: StyleVarPane.py:233 +#: app/StyleVarPane.py:231 msgid "Style/Item Properties" msgstr "" -#: StyleVarPane.py:252 +#: app/StyleVarPane.py:250 msgid "Styles" msgstr "" -#: StyleVarPane.py:271 +#: app/StyleVarPane.py:269 msgid "All:" msgstr "全:" -#: StyleVarPane.py:274 +#: app/StyleVarPane.py:272 msgid "Selected Style:" msgstr "" -#: StyleVarPane.py:282 +#: app/StyleVarPane.py:280 msgid "Other Styles:" msgstr "" -#: StyleVarPane.py:287 +#: app/StyleVarPane.py:285 msgid "No Options!" msgstr "オプションありません!" -#: StyleVarPane.py:293 +#: app/StyleVarPane.py:291 msgid "None!" msgstr "なし!" -#: StyleVarPane.py:364 +#: app/StyleVarPane.py:362 msgid "Items" msgstr "" -#: SubPane.py:84 +#: app/SubPane.py:85 msgid "Hide/Show the \"{}\" window." msgstr "" -#: UI.py:67 +#: app/UI.py:70 msgid "Export..." msgstr "" -#: UI.py:591 +#: app/UI.py:598 msgid "Select Skyboxes" msgstr "" -#: UI.py:592 +#: app/UI.py:599 msgid "" "The skybox decides what the area outside the chamber is like. It chooses " "the colour of sky (seen in some items), the style of bottomless pit (if " "present), as well as color of \"fog\" (seen in larger chambers)." msgstr "" -#: UI.py:600 +#: app/UI.py:607 msgid "3D Skybox" msgstr "" -#: UI.py:601 +#: app/UI.py:608 msgid "Fog Color" msgstr "" -#: UI.py:608 +#: app/UI.py:615 msgid "Select Additional Voice Lines" msgstr "" -#: UI.py:609 +#: app/UI.py:616 msgid "" "Voice lines choose which extra voices play as the player enters or exits " "a chamber. They are chosen based on which items are present in the map. " @@ -421,31 +458,31 @@ msgid "" "Style Properties." msgstr "" -#: UI.py:614 +#: app/UI.py:621 msgid "Add no extra voice lines, only Multiverse Cave if enabled." msgstr "" -#: UI.py:616 +#: app/UI.py:623 msgid "" msgstr "" -#: UI.py:620 +#: app/UI.py:627 msgid "Characters" msgstr "キャラクター" -#: UI.py:621 +#: app/UI.py:628 msgid "Turret Shoot Monitor" msgstr "" -#: UI.py:622 +#: app/UI.py:629 msgid "Monitor Visuals" msgstr "" -#: UI.py:629 +#: app/UI.py:636 msgid "Select Style" msgstr "" -#: UI.py:630 +#: app/UI.py:637 msgid "" "The Style controls many aspects of the map. It decides the materials used" " for walls, the appearance of entrances and exits, the design for most " @@ -454,38 +491,38 @@ msgid "" "The style broadly defines the time period a chamber is set in." msgstr "" -#: UI.py:641 +#: app/UI.py:648 msgid "Elevator Videos" msgstr "エレベータービデオ" -#: UI.py:648 +#: app/UI.py:655 msgid "Select Elevator Video" msgstr "" -#: UI.py:649 +#: app/UI.py:656 msgid "" "Set the video played on the video screens in modern Aperture elevator " "rooms. Not all styles feature these. If set to \"None\", a random video " "will be selected each time the map is played, like in the default PeTI." msgstr "" -#: UI.py:653 +#: app/UI.py:660 msgid "This style does not have a elevator video screen." msgstr "" -#: UI.py:658 +#: app/UI.py:665 msgid "Choose a random video." msgstr "" -#: UI.py:662 +#: app/UI.py:669 msgid "Multiple Orientations" msgstr "" -#: UI.py:883 +#: app/UI.py:897 msgid "Selected Items and Style successfully exported!" msgstr "" -#: UI.py:885 +#: app/UI.py:899 msgid "" "\n" "\n" @@ -493,1093 +530,1081 @@ msgid "" "editor wall previews are changed." msgstr "" -#: UI.py:898 -msgid "" -"\n" -" Launch Game?" -msgstr "" - -#: UI.py:1113 +#: app/UI.py:1131 msgid "Delete Palette \"{}\"" msgstr "" -#: UI.py:1189 +#: app/UI.py:1207 msgid "BEE2 - Save Palette" msgstr "" -#: UI.py:1190 +#: app/UI.py:1208 msgid "Enter a name:" msgstr "" -#: UI.py:1199 +#: app/UI.py:1217 msgid "This palette already exists. Overwrite?" msgstr "" -#: UI.py:1228 gameMan.py:1529 +#: app/UI.py:1249 app/gameMan.py:1527 msgid "Are you sure you want to delete \"{}\"?" msgstr "" -#: UI.py:1255 +#: app/UI.py:1277 msgid "Clear Palette" msgstr "" -#: UI.py:1291 UI.py:1727 +#: app/UI.py:1313 app/UI.py:1747 msgid "Delete Palette" msgstr "" -#: UI.py:1311 +#: app/UI.py:1333 msgid "Save Palette..." msgstr "" -#: UI.py:1316 UI.py:1750 +#: app/UI.py:1338 app/UI.py:1770 msgid "Save Palette As..." msgstr "" -#: UI.py:1327 UI.py:1738 +#: app/UI.py:1349 app/UI.py:1758 msgid "Save Settings in Palettes" msgstr "" -#: UI.py:1345 music_conf.py:204 +#: app/UI.py:1367 app/music_conf.py:205 msgid "Music: " msgstr "音楽:" -#: UI.py:1371 +#: app/UI.py:1393 msgid "{arr} Use Suggested {arr}" msgstr "" -#: UI.py:1387 +#: app/UI.py:1409 msgid "Style: " msgstr "" -#: UI.py:1389 +#: app/UI.py:1411 msgid "Voice: " msgstr "" -#: UI.py:1390 +#: app/UI.py:1412 msgid "Skybox: " msgstr "" -#: UI.py:1391 +#: app/UI.py:1413 msgid "Elev Vid: " msgstr "エレベータービデオ:" -#: UI.py:1409 +#: app/UI.py:1431 msgid "" "Enable or disable particular voice lines, to prevent them from being " "added." msgstr "" -#: UI.py:1512 +#: app/UI.py:1534 msgid "All Items: " msgstr "" -#: UI.py:1646 +#: app/UI.py:1666 msgid "Export to \"{}\"..." msgstr "" -#: UI.py:1674 backup.py:876 +#: app/UI.py:1694 app/backup.py:872 msgid "File" msgstr "ファイル" -#: UI.py:1681 +#: app/UI.py:1701 msgid "Export" msgstr "" -#: UI.py:1688 backup.py:880 +#: app/UI.py:1708 app/backup.py:876 msgid "Add Game" msgstr "" -#: UI.py:1692 +#: app/UI.py:1712 msgid "Uninstall from Selected Game" msgstr "" -#: UI.py:1696 +#: app/UI.py:1716 msgid "Backup/Restore Puzzles..." msgstr "" -#: UI.py:1700 +#: app/UI.py:1720 msgid "Manage Packages..." msgstr "" -#: UI.py:1705 +#: app/UI.py:1725 msgid "Options" msgstr "環境設定" -#: UI.py:1710 gameMan.py:1208 +#: app/UI.py:1730 app/gameMan.py:1206 msgid "Quit" msgstr "終了" -#: UI.py:1720 +#: app/UI.py:1740 msgid "Palette" msgstr "" -#: UI.py:1722 +#: app/UI.py:1742 msgid "Clear" msgstr "" -#: UI.py:1731 +#: app/UI.py:1751 msgid "Fill Palette" msgstr "" -#: UI.py:1745 +#: app/UI.py:1765 msgid "Save Palette" msgstr "" -#: UI.py:1760 +#: app/UI.py:1780 msgid "View" msgstr "" -#: UI.py:1879 +#: app/UI.py:1899 msgid "Palettes" msgstr "" -#: UI.py:1904 +#: app/UI.py:1924 msgid "Export Options" msgstr "" -#: UI.py:1936 +#: app/UI.py:1956 msgid "Fill empty spots in the palette with random items." msgstr "" -#: backup.py:81 +#: app/backup.py:79 msgid "Copying maps" msgstr "" -#: backup.py:86 +#: app/backup.py:84 msgid "Loading maps" msgstr "" -#: backup.py:91 +#: app/backup.py:89 msgid "Deleting maps" msgstr "" -#: backup.py:142 +#: app/backup.py:140 msgid "Failed to parse this puzzle file. It can still be backed up." msgstr "" -#: backup.py:146 +#: app/backup.py:144 msgid "No description found." msgstr "" -#: backup.py:177 +#: app/backup.py:175 msgid "Coop" msgstr "生協" -#: backup.py:177 +#: app/backup.py:175 msgid "SP" msgstr "SP" -#: backup.py:339 +#: app/backup.py:337 msgid "This filename is already in the backup.Do you wish to overwrite it? ({})" msgstr "" -#: backup.py:445 +#: app/backup.py:443 msgid "BEE2 Backup" msgstr "" -#: backup.py:446 +#: app/backup.py:444 msgid "No maps were chosen to backup!" msgstr "" -#: backup.py:506 +#: app/backup.py:504 msgid "" "This map is already in the game directory.Do you wish to overwrite it? " "({})" msgstr "" -#: backup.py:568 +#: app/backup.py:566 msgid "Load Backup" msgstr "" -#: backup.py:569 backup.py:628 +#: app/backup.py:567 app/backup.py:626 msgid "Backup zip" msgstr "" -#: backup.py:602 +#: app/backup.py:600 msgid "Unsaved Backup" msgstr "" -#: backup.py:627 backup.py:874 +#: app/backup.py:625 app/backup.py:870 msgid "Save Backup As" msgstr "" -#: backup.py:724 +#: app/backup.py:721 msgid "Confirm Deletion" msgstr "" -#: backup.py:725 +#: app/backup.py:722 msgid "Do you wish to delete {} map?\n" msgid_plural "Do you wish to delete {} maps?\n" msgstr[0] "" -#: backup.py:762 +#: app/backup.py:759 msgid "Restore:" msgstr "" -#: backup.py:763 +#: app/backup.py:760 msgid "Backup:" msgstr "" -#: backup.py:800 +#: app/backup.py:797 msgid "Checked" msgstr "" -#: backup.py:808 +#: app/backup.py:805 msgid "Delete Checked" msgstr "" -#: backup.py:858 +#: app/backup.py:854 msgid "BEEMOD {} - Backup / Restore Puzzles" msgstr "" -#: backup.py:871 backup.py:999 +#: app/backup.py:867 app/backup.py:995 msgid "New Backup" msgstr "" -#: backup.py:872 backup.py:1006 +#: app/backup.py:868 app/backup.py:1002 msgid "Open Backup" msgstr "" -#: backup.py:873 backup.py:1013 +#: app/backup.py:869 app/backup.py:1009 msgid "Save Backup" msgstr "" -#: backup.py:881 +#: app/backup.py:877 msgid "Remove Game" msgstr "" -#: backup.py:884 +#: app/backup.py:880 msgid "Game" msgstr "ゲーム" -#: backup.py:930 +#: app/backup.py:926 msgid "Automatic Backup After Export" msgstr "" -#: backup.py:962 +#: app/backup.py:958 msgid "Keep (Per Game):" msgstr "" -#: backup.py:980 +#: app/backup.py:976 msgid "Backup/Restore Puzzles" msgstr "" -#: contextWin.py:79 +#: app/contextWin.py:76 msgid "This item may not be rotated." msgstr "" -#: contextWin.py:80 +#: app/contextWin.py:77 msgid "This item can be pointed in 4 directions." msgstr "" -#: contextWin.py:81 +#: app/contextWin.py:78 msgid "This item can be positioned on the sides and center." msgstr "" -#: contextWin.py:82 +#: app/contextWin.py:79 msgid "This item can be centered in two directions, plus on the sides." msgstr "" -#: contextWin.py:83 +#: app/contextWin.py:80 msgid "This item can be placed like light strips." msgstr "" -#: contextWin.py:84 +#: app/contextWin.py:81 msgid "This item can be rotated on the floor to face 360 degrees." msgstr "" -#: contextWin.py:85 +#: app/contextWin.py:82 msgid "This item is positioned using a catapult trajectory." msgstr "" -#: contextWin.py:86 +#: app/contextWin.py:83 msgid "This item positions the dropper to hit target locations." msgstr "" -#: contextWin.py:88 +#: app/contextWin.py:85 msgid "This item does not accept any inputs." msgstr "" -#: contextWin.py:89 +#: app/contextWin.py:86 msgid "This item accepts inputs." msgstr "" -#: contextWin.py:90 +#: app/contextWin.py:87 msgid "This item has two input types (A and B), using the Input A and B items." msgstr "" -#: contextWin.py:92 +#: app/contextWin.py:89 msgid "This item does not output." msgstr "" -#: contextWin.py:93 +#: app/contextWin.py:90 msgid "This item has an output." msgstr "" -#: contextWin.py:94 +#: app/contextWin.py:91 msgid "This item has a timed output." msgstr "" -#: contextWin.py:96 +#: app/contextWin.py:93 msgid "This item does not take up any space inside walls." msgstr "" -#: contextWin.py:97 +#: app/contextWin.py:94 msgid "This item takes space inside the wall." msgstr "" -#: contextWin.py:99 +#: app/contextWin.py:96 msgid "This item cannot be placed anywhere..." msgstr "" -#: contextWin.py:100 +#: app/contextWin.py:97 msgid "This item can only be attached to ceilings." msgstr "" -#: contextWin.py:101 +#: app/contextWin.py:98 msgid "This item can only be placed on the floor." msgstr "" -#: contextWin.py:102 +#: app/contextWin.py:99 msgid "This item can be placed on floors and ceilings." msgstr "" -#: contextWin.py:103 +#: app/contextWin.py:100 msgid "This item can be placed on walls only." msgstr "" -#: contextWin.py:104 +#: app/contextWin.py:101 msgid "This item can be attached to walls and ceilings." msgstr "" -#: contextWin.py:105 +#: app/contextWin.py:102 msgid "This item can be placed on floors and walls." msgstr "" -#: contextWin.py:106 +#: app/contextWin.py:103 msgid "This item can be placed in any orientation." msgstr "" -#: contextWin.py:212 +#: app/contextWin.py:209 msgid "No Alternate Versions" msgstr "" -#: contextWin.py:304 +#: app/contextWin.py:301 msgid "Excursion Funnels accept a on/off input and a directional input." msgstr "" -#: contextWin.py:361 +#: app/contextWin.py:358 msgid "" "This item can be rotated on the floor to face 360 degrees, for Reflection" " Cubes only." msgstr "" -#: contextWin.py:440 +#: app/contextWin.py:437 msgid "Properties:" msgstr "" -#: contextWin.py:462 +#: app/contextWin.py:459 msgid "" "The number of entities used for this item. The Source engine limits this " "to 2048 in total. This provides a guide to how many of these items can be" " placed in a map at once." msgstr "" -#: contextWin.py:487 +#: app/contextWin.py:484 msgid "Description:" msgstr "" -#: contextWin.py:530 +#: app/contextWin.py:527 msgid "" "Failed to open a web browser. Do you wish for the URL to be copied to the" " clipboard instead?" msgstr "" -#: contextWin.py:544 +#: app/contextWin.py:541 msgid "More Info>>" msgstr "" -#: contextWin.py:561 +#: app/contextWin.py:558 msgid "Change Defaults..." msgstr "" -#: contextWin.py:567 +#: app/contextWin.py:564 msgid "Change the default settings for this item when placed." msgstr "" -#: gameMan.py:750 gameMan.py:852 +#: app/gameMan.py:748 app/gameMan.py:850 msgid "BEE2 - Export Failed!" msgstr "" -#: gameMan.py:751 +#: app/gameMan.py:749 msgid "" "Compiler file {file} missing. Exit Steam applications, then press OK to " "verify your game cache. You can then export again." msgstr "" -#: gameMan.py:853 +#: app/gameMan.py:851 msgid "Copying compiler file {file} failed. Ensure {game} is not running." msgstr "" -#: gameMan.py:1265 +#: app/gameMan.py:1263 msgid "" "Ap-Tag Coop gun instance not found!\n" "Coop guns will not work - verify cache to fix." msgstr "" -#: gameMan.py:1269 +#: app/gameMan.py:1267 msgid "BEE2 - Aperture Tag Files Missing" msgstr "" -#: gameMan.py:1452 +#: app/gameMan.py:1450 msgid "Select the folder where the game executable is located ({appname})..." msgstr "" -#: gameMan.py:1455 gameMan.py:1470 gameMan.py:1480 gameMan.py:1487 -#: gameMan.py:1496 gameMan.py:1505 +#: app/gameMan.py:1453 app/gameMan.py:1468 app/gameMan.py:1478 +#: app/gameMan.py:1485 app/gameMan.py:1494 app/gameMan.py:1503 msgid "BEE2 - Add Game" msgstr "" -#: gameMan.py:1458 +#: app/gameMan.py:1456 msgid "Find Game Exe" msgstr "" -#: gameMan.py:1459 +#: app/gameMan.py:1457 msgid "Executable" msgstr "" -#: gameMan.py:1467 +#: app/gameMan.py:1465 msgid "This does not appear to be a valid game folder!" msgstr "" -#: gameMan.py:1477 +#: app/gameMan.py:1475 msgid "Portal Stories: Mel doesn't have an editor!" msgstr "" -#: gameMan.py:1488 +#: app/gameMan.py:1486 msgid "Enter the name of this game:" msgstr "" -#: gameMan.py:1495 +#: app/gameMan.py:1493 msgid "This name is already taken!" msgstr "" -#: gameMan.py:1504 +#: app/gameMan.py:1502 msgid "Please enter a name for this game!" msgstr "" -#: gameMan.py:1523 +#: app/gameMan.py:1521 msgid "" "\n" " (BEE2 will quit, this is the last game set!)" msgstr "" -#: helpMenu.py:60 +#: app/helpMenu.py:56 msgid "Wiki..." msgstr "ウィキ。。。" -#: helpMenu.py:62 +#: app/helpMenu.py:58 msgid "Original Items..." msgstr "" -#: helpMenu.py:67 +#: app/helpMenu.py:63 msgid "Discord Server..." msgstr "" -#: helpMenu.py:68 +#: app/helpMenu.py:64 msgid "aerond's Music Changer..." msgstr "" -#: helpMenu.py:70 +#: app/helpMenu.py:66 msgid "Application Repository..." msgstr "" -#: helpMenu.py:71 +#: app/helpMenu.py:67 msgid "Items Repository..." msgstr "" -#: helpMenu.py:73 +#: app/helpMenu.py:69 msgid "Submit Application Bugs..." msgstr "" -#: helpMenu.py:74 +#: app/helpMenu.py:70 msgid "Submit Item Bugs..." msgstr "" -#: helpMenu.py:76 paletteLoader.py:35 +#: app/helpMenu.py:72 app/paletteLoader.py:35 msgid "Portal 2" msgstr "Portal 2" -#: helpMenu.py:77 paletteLoader.py:37 +#: app/helpMenu.py:73 app/paletteLoader.py:37 msgid "Aperture Tag" msgstr "Aperture Tag" -#: helpMenu.py:78 +#: app/helpMenu.py:74 msgid "Portal Stories: Mel" msgstr "Portal Stories: Mel" -#: helpMenu.py:79 +#: app/helpMenu.py:75 msgid "Thinking With Time Machine" msgstr "Thinking With Time Machine" -#: helpMenu.py:242 itemPropWin.py:347 +#: app/helpMenu.py:238 app/itemPropWin.py:342 msgid "Close" msgstr "閉じる" -#: helpMenu.py:266 +#: app/helpMenu.py:262 msgid "Help" msgstr "ヘルプ" -#: helpMenu.py:277 +#: app/helpMenu.py:273 msgid "BEE2 Credits" msgstr "BEE2のクレジット" -#: helpMenu.py:294 +#: app/helpMenu.py:290 msgid "Credits..." msgstr "クレジット。。。" -#: itemPropWin.py:43 +#: app/itemPropWin.py:38 msgid "Start Position" msgstr "" -#: itemPropWin.py:44 +#: app/itemPropWin.py:39 msgid "End Position" msgstr "" -#: itemPropWin.py:45 +#: app/itemPropWin.py:40 msgid "" "Delay \n" "(0=infinite)" msgstr "" -#: itemPropWin.py:346 +#: app/itemPropWin.py:341 msgid "No Properties available!" msgstr "" -#: itemconfig.py:621 +#: app/itemconfig.py:616 msgid "Choose a Color" msgstr "" -#: loadScreen.py:199 -msgid "Skipped!" -msgstr "" - -#: loadScreen.py:200 -msgid "Version: " -msgstr "バージョン:" - -#: loadScreen.py:201 optionWindow.py:252 packageMan.py:116 selectorWin.py:723 -msgid "Cancel" -msgstr "キャンセル" - -#: loadScreen.py:211 tagsPane.py:53 -msgid "Packages" -msgstr "" - -#: loadScreen.py:212 -msgid "Loading Objects" -msgstr "" - -#: loadScreen.py:213 -msgid "Loading Images" -msgstr "" - -#: loadScreen.py:214 -msgid "Initialising UI" -msgstr "" - -#: loadScreen.py:215 -msgid "Better Extended Editor for Portal 2" -msgstr "" - -#: logWindow.py:30 +#: app/logWindow.py:29 msgid "Debug messages" msgstr "" -#: logWindow.py:31 +#: app/logWindow.py:30 msgid "Default" msgstr "" -#: logWindow.py:32 +#: app/logWindow.py:31 msgid "Warnings Only" msgstr "" -#: logWindow.py:160 +#: app/logWindow.py:159 msgid "Logs - {}" msgstr "" -#: logWindow.py:209 +#: app/logWindow.py:208 msgid "Copy" msgstr "コピー" -#: logWindow.py:221 +#: app/logWindow.py:220 msgid "Show:" msgstr "" -#: music_conf.py:132 +#: app/music_conf.py:133 #, fuzzy msgid "Select Background Music - Base" msgstr "音楽を選択" -#: music_conf.py:133 +#: app/music_conf.py:134 msgid "" "This controls the background music used for a map. Expand the dropdown to" " set tracks for specific test elements." msgstr "" -#: music_conf.py:137 +#: app/music_conf.py:138 msgid "" "Add no music to the map at all. Testing Element-specific music may still " "be added." msgstr "" -#: music_conf.py:142 +#: app/music_conf.py:143 msgid "Propulsion Gel SFX" msgstr "速ゲルSFX" -#: music_conf.py:143 +#: app/music_conf.py:144 msgid "Repulsion Gel SFX" msgstr "" -#: music_conf.py:144 +#: app/music_conf.py:145 msgid "Excursion Funnel Music" msgstr "" -#: music_conf.py:145 music_conf.py:160 +#: app/music_conf.py:146 app/music_conf.py:161 msgid "Synced Funnel Music" msgstr "" -#: music_conf.py:152 +#: app/music_conf.py:153 #, fuzzy msgid "Select Excursion Funnel Music" msgstr "音楽を選択" -#: music_conf.py:153 +#: app/music_conf.py:154 msgid "Set the music used while inside Excursion Funnels." msgstr "" -#: music_conf.py:156 +#: app/music_conf.py:157 msgid "Have no music playing when inside funnels." msgstr "" -#: music_conf.py:167 +#: app/music_conf.py:168 msgid "Select Repulsion Gel Music" msgstr "" -#: music_conf.py:168 +#: app/music_conf.py:169 msgid "Select the music played when players jump on Repulsion Gel." msgstr "" -#: music_conf.py:171 +#: app/music_conf.py:172 msgid "Add no music when jumping on Repulsion Gel." msgstr "" -#: music_conf.py:179 +#: app/music_conf.py:180 #, fuzzy msgid "Select Propulsion Gel Music" msgstr "音楽を選択" -#: music_conf.py:180 +#: app/music_conf.py:181 msgid "" "Select music played when players have large amounts of horizontal " "velocity." msgstr "" -#: music_conf.py:183 +#: app/music_conf.py:184 msgid "Add no music while running fast." msgstr "" -#: music_conf.py:218 +#: app/music_conf.py:219 msgid "Base: " msgstr "" -#: music_conf.py:251 +#: app/music_conf.py:252 msgid "Funnel:" msgstr "" -#: music_conf.py:252 +#: app/music_conf.py:253 msgid "Bounce:" msgstr "" -#: music_conf.py:253 +#: app/music_conf.py:254 msgid "Speed:" msgstr "" -#: optionWindow.py:62 +#: app/optionWindow.py:45 +msgid "" +"\n" +"Launch Game?" +msgstr "" + +#: app/optionWindow.py:47 +msgid "" +"\n" +"Minimise BEE2?" +msgstr "" + +#: app/optionWindow.py:48 +msgid "" +"\n" +"Launch Game and minimise BEE2?" +msgstr "" + +#: app/optionWindow.py:50 +msgid "" +"\n" +"Quit BEE2?" +msgstr "" + +#: app/optionWindow.py:51 +msgid "" +"\n" +"Launch Game and quit BEE2?" +msgstr "" + +#: app/optionWindow.py:70 msgid "BEE2 Options" msgstr "" -#: optionWindow.py:101 +#: app/optionWindow.py:108 msgid "" "Package cache times have been reset. These will now be extracted during " "the next export." msgstr "" -#: optionWindow.py:118 +#: app/optionWindow.py:125 msgid "\"Preserve Game Resources\" has been disabled." msgstr "" -#: optionWindow.py:130 +#: app/optionWindow.py:137 msgid "Packages Reset" msgstr "" -#: optionWindow.py:211 +#: app/optionWindow.py:218 msgid "General" msgstr "" -#: optionWindow.py:217 +#: app/optionWindow.py:224 msgid "Windows" msgstr "" -#: optionWindow.py:223 +#: app/optionWindow.py:230 msgid "Development" msgstr "" -#: optionWindow.py:247 packageMan.py:110 selectorWin.py:701 +#: app/optionWindow.py:254 app/packageMan.py:110 app/selector_win.py:696 msgid "OK" msgstr "OK" -#: optionWindow.py:278 +#: app/optionWindow.py:285 msgid "After Export:" msgstr "" -#: optionWindow.py:295 +#: app/optionWindow.py:302 msgid "Do Nothing" msgstr "" -#: optionWindow.py:301 +#: app/optionWindow.py:308 msgid "Minimise BEE2" msgstr "" -#: optionWindow.py:307 +#: app/optionWindow.py:314 msgid "Quit BEE2" msgstr "" -#: optionWindow.py:315 +#: app/optionWindow.py:322 msgid "After exports, do nothing and keep the BEE2 in focus." msgstr "" -#: optionWindow.py:317 +#: app/optionWindow.py:324 msgid "After exports, minimise to the taskbar/dock." msgstr "" -#: optionWindow.py:318 +#: app/optionWindow.py:325 msgid "After exports, quit the BEE2." msgstr "" -#: optionWindow.py:325 +#: app/optionWindow.py:332 msgid "Launch Game" msgstr "" -#: optionWindow.py:326 +#: app/optionWindow.py:333 msgid "After exporting, launch the selected game automatically." msgstr "" -#: optionWindow.py:334 optionWindow.py:340 +#: app/optionWindow.py:341 app/optionWindow.py:347 msgid "Play Sounds" msgstr "" -#: optionWindow.py:345 +#: app/optionWindow.py:352 msgid "" "Pyglet is either not installed or broken.\n" "Sound effects have been disabled." msgstr "" -#: optionWindow.py:352 +#: app/optionWindow.py:359 msgid "Reset Package Caches" msgstr "" -#: optionWindow.py:358 +#: app/optionWindow.py:365 msgid "Force re-extracting all package resources." msgstr "" -#: optionWindow.py:367 +#: app/optionWindow.py:374 msgid "Keep windows inside screen" msgstr "" -#: optionWindow.py:368 +#: app/optionWindow.py:375 msgid "" "Prevent sub-windows from moving outside the screen borders. If you have " "multiple monitors, disable this." msgstr "" -#: optionWindow.py:378 +#: app/optionWindow.py:385 msgid "Keep loading screens on top" msgstr "" -#: optionWindow.py:380 +#: app/optionWindow.py:387 msgid "" "Force loading screens to be on top of other windows. Since they don't " "appear on the taskbar/dock, they can't be brought to the top easily " "again." msgstr "" -#: optionWindow.py:389 +#: app/optionWindow.py:396 msgid "Reset All Window Positions" msgstr "" -#: optionWindow.py:403 +#: app/optionWindow.py:410 msgid "Log missing entity counts" msgstr "" -#: optionWindow.py:404 +#: app/optionWindow.py:411 msgid "" "When loading items, log items with missing entity counts in their " "properties.txt file." msgstr "" -#: optionWindow.py:412 +#: app/optionWindow.py:419 msgid "Log when item doesn't have a style" msgstr "" -#: optionWindow.py:413 +#: app/optionWindow.py:420 msgid "" "Log items have no applicable version for a particular style.This usually " "means it will look very bad." msgstr "" -#: optionWindow.py:421 +#: app/optionWindow.py:428 msgid "Log when item uses parent's style" msgstr "" -#: optionWindow.py:422 +#: app/optionWindow.py:429 msgid "" "Log when an item reuses a variant from a parent style (1970s using 1950s " "items, for example). This is usually fine, but may need to be fixed." msgstr "" -#: optionWindow.py:431 +#: app/optionWindow.py:438 msgid "Log missing packfile resources" msgstr "" -#: optionWindow.py:432 +#: app/optionWindow.py:439 msgid "" "Log when the resources a \"PackList\" refers to are not present in the " "zip. This may be fine (in a prerequisite zip), but it often indicates an " "error." msgstr "" -#: optionWindow.py:441 +#: app/optionWindow.py:448 msgid "Preserve Game Directories" msgstr "" -#: optionWindow.py:443 +#: app/optionWindow.py:450 msgid "" -"When exporting, do not overwrite \n" -"\"bee2/\" and\n" -"\"sdk_content/maps/bee2/\".\n" -"Enable if you're developing new content, to ensure it is not overwritten." +"When exporting, do not copy resources to \n" +"\"bee2/\" and \"sdk_content/maps/bee2/\".\n" +"Only enable if you're developing new content, to ensure it is not " +"overwritten." msgstr "" -#: optionWindow.py:454 +#: app/optionWindow.py:461 msgid "Show Log Window" msgstr "" -#: optionWindow.py:456 +#: app/optionWindow.py:463 msgid "Show the log file in real-time." msgstr "" -#: optionWindow.py:463 +#: app/optionWindow.py:470 msgid "Force Editor Models" msgstr "" -#: optionWindow.py:464 +#: app/optionWindow.py:471 msgid "" "Make all props_map_editor models available for use. Portal 2 has a limit " "of 1024 models loaded in memory at once, so we need to disable unused " "ones to free this up." msgstr "" -#: optionWindow.py:475 +#: app/optionWindow.py:482 msgid "Dump All objects" msgstr "" -#: optionWindow.py:481 +#: app/optionWindow.py:488 msgid "Dump Items list" msgstr "" -#: packageMan.py:64 +#: app/packageMan.py:64 msgid "BEE2 - Restart Required!" msgstr "" -#: packageMan.py:65 +#: app/packageMan.py:65 msgid "" "Changing enabled packages requires a restart.\n" "Continue?" msgstr "" -#: packageMan.py:88 +#: app/packageMan.py:88 msgid "BEE2 - Manage Packages" msgstr "" -#: paletteLoader.py:25 +#: app/paletteLoader.py:25 msgid "" msgstr "" -#: paletteLoader.py:27 +#: app/paletteLoader.py:27 msgid "Blank" msgstr "空ろ" -#: paletteLoader.py:30 +#: app/paletteLoader.py:30 msgid "BEEMod" msgstr "BEEMod" -#: paletteLoader.py:32 +#: app/paletteLoader.py:32 msgid "Portal 2 Collapsed" msgstr "短縮のPortal 2" -#: richTextBox.py:153 +#: app/richTextBox.py:152 msgid "Open \"{}\" in the default browser?" msgstr "" -#: selectorWin.py:404 +#: app/selector_win.py:399 msgid "Do not add anything." msgstr "" -#: selectorWin.py:408 +#: app/selector_win.py:403 msgid "" msgstr "<なし>" -#: selectorWin.py:585 selectorWin.py:590 +#: app/selector_win.py:580 app/selector_win.py:585 msgid "Suggested" msgstr "" -#: selectorWin.py:638 +#: app/selector_win.py:633 msgid "Play a sample of this item." msgstr "" -#: selectorWin.py:712 +#: app/selector_win.py:707 msgid "Reset to Default" msgstr "" -#: selectorWin.py:773 +#: app/selector_win.py:768 msgid "Other" msgstr "" -#: selectorWin.py:1086 +#: app/selector_win.py:1081 msgid "Author: {}" msgid_plural "Authors: {}" msgstr[0] "" -#: selectorWin.py:1142 +#: app/selector_win.py:1137 msgid "Color: R={r}, G={g}, B={b}" msgstr "" -#: signage_ui.py:140 signage_ui.py:213 +#: app/signage_ui.py:139 app/signage_ui.py:212 msgid "Configure Signage" msgstr "" -#: signage_ui.py:144 +#: app/signage_ui.py:143 msgid "Selected" msgstr "" -#: signage_ui.py:167 +#: app/signage_ui.py:166 msgid "Signage: {}" msgstr "" -#: tagsPane.py:51 +#: app/tagsPane.py:46 msgid "Tags" msgstr "付箋" -#: tagsPane.py:52 +#: app/tagsPane.py:47 msgid "Authors" msgstr "" -#: tagsPane.py:162 +#: app/tagsPane.py:157 msgid "Any" msgstr "選ぶ" -#: tagsPane.py:171 +#: app/tagsPane.py:166 msgid "All" msgstr "全て" -#: tagsPane.py:197 +#: app/tagsPane.py:192 msgid "Available Tags (click):" msgstr "" -#: utils.py:841 -msgid "__LANG_USE_SANS_SERIF__" -msgstr "YES" - -#: voiceEditor.py:35 +#: app/voiceEditor.py:33 msgid "Singleplayer" msgstr "" -#: voiceEditor.py:36 +#: app/voiceEditor.py:34 msgid "Cooperative" msgstr "" -#: voiceEditor.py:37 +#: app/voiceEditor.py:35 msgid "ATLAS (SP/Coop)" msgstr "" -#: voiceEditor.py:38 +#: app/voiceEditor.py:36 msgid "P-Body (SP/Coop)" msgstr "" -#: voiceEditor.py:41 +#: app/voiceEditor.py:39 msgid "Human characters (Bendy and Chell)" msgstr "" -#: voiceEditor.py:42 +#: app/voiceEditor.py:40 msgid "AI characters (ATLAS, P-Body, or Coop)" msgstr "" -#: voiceEditor.py:53 +#: app/voiceEditor.py:51 msgid "Death - Toxic Goo" msgstr "" -#: voiceEditor.py:54 +#: app/voiceEditor.py:52 msgid "Death - Turrets" msgstr "" -#: voiceEditor.py:55 +#: app/voiceEditor.py:53 msgid "Death - Crusher" msgstr "" -#: voiceEditor.py:56 +#: app/voiceEditor.py:54 msgid "Death - LaserField" msgstr "" -#: voiceEditor.py:107 +#: app/voiceEditor.py:105 msgid "Transcript:" msgstr "" -#: voiceEditor.py:146 +#: app/voiceEditor.py:144 msgid "Save" msgstr "" -#: voiceEditor.py:221 +#: app/voiceEditor.py:219 msgid "Resp" msgstr "" -#: voiceEditor.py:238 +#: app/voiceEditor.py:236 msgid "BEE2 - Configure \"{}\"" msgstr "" -#: voiceEditor.py:315 +#: app/voiceEditor.py:313 msgid "Mid - Chamber" msgstr "" -#: voiceEditor.py:317 +#: app/voiceEditor.py:315 msgid "" "Lines played during the actual chamber, after specific events have " "occurred." msgstr "" -#: voiceEditor.py:323 +#: app/voiceEditor.py:321 msgid "Responses" msgstr "" -#: voiceEditor.py:325 +#: app/voiceEditor.py:323 msgid "Lines played in response to certain events in Coop." msgstr "" -#: voiceEditor.py:423 +#: app/voiceEditor.py:421 msgid "No Name!" msgstr "名前ありません!" -#: voiceEditor.py:458 +#: app/voiceEditor.py:456 msgid "No Name?" msgstr "名前ありません?" @@ -1704,3 +1729,16 @@ msgstr "名前ありません?" #~ " restart." #~ msgstr "" +#~ msgid "" +#~ "\n" +#~ " Launch Game?" +#~ msgstr "" + +#~ msgid "" +#~ "When exporting, do not overwrite \n" +#~ "\"bee2/\" and\n" +#~ "\"sdk_content/maps/bee2/\".\n" +#~ "Enable if you're developing new content," +#~ " to ensure it is not overwritten." +#~ msgstr "" + diff --git a/i18n/zh.po b/i18n/zh.po index b63265ce3..ff139b2fe 100644 --- a/i18n/zh.po +++ b/i18n/zh.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: https://github.com/BEEmod/BEE2.4/issues\n" -"POT-Creation-Date: 2020-07-18 11:58+1000\n" +"POT-Creation-Date: 2020-09-20 10:31-0700\n" "PO-Revision-Date: 2019-11-22 10:47+1000\n" "Last-Translator: Antecer \n" "Language: zh\n" @@ -12,29 +12,66 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.6.0\n" +"Generated-By: Babel 2.8.0\n" -#: CheckDetails.py:220 +#: loadScreen.py:199 +msgid "Skipped!" +msgstr "跳过!" + +#: loadScreen.py:200 +msgid "Version: " +msgstr "版本:" + +#: app/optionWindow.py:259 app/packageMan.py:116 app/selector_win.py:718 +#: loadScreen.py:201 +msgid "Cancel" +msgstr "取消" + +#: app/tagsPane.py:48 loadScreen.py:211 +msgid "Packages" +msgstr "资源包" + +#: loadScreen.py:212 +msgid "Loading Objects" +msgstr "正在载入对象" + +#: loadScreen.py:213 +msgid "Loading Images" +msgstr "正在载入图像" + +#: loadScreen.py:214 +msgid "Initialising UI" +msgstr "初始化界面" + +#: loadScreen.py:215 +msgid "Better Extended Editor for Portal 2" +msgstr "更棒的传送门2扩展编辑器" + +#: utils.py:841 +msgid "__LANG_USE_SANS_SERIF__" +msgstr "" + +#: app/CheckDetails.py:219 msgid "Toggle all checkboxes." msgstr "反选所有复选框" -#: CompilerPane.py:66 +#: app/CompilerPane.py:64 msgid "ATLAS" msgstr "ATLAS(蓝色机器人)" -#: CompilerPane.py:67 +#: app/CompilerPane.py:65 msgid "P-Body" msgstr "P-Body(橙色机器人)" -#: CompilerPane.py:68 voiceEditor.py:40 +#: app/CompilerPane.py:66 app/voiceEditor.py:38 msgid "Chell" msgstr "Chell(主角雪儿)" -#: CompilerPane.py:69 voiceEditor.py:39 +#: app/CompilerPane.py:67 app/voiceEditor.py:37 msgid "Bendy" msgstr "Bendy(纸片人小黑)" -#: CompilerPane.py:122 +#: app/CompilerPane.py:120 msgid "" "Brushes form the walls or other parts of the test chamber. If this is " "high, it may help to reduce the size of the map or remove intricate " @@ -44,7 +81,7 @@ msgstr "" "大量使用画刷能够帮助缩减地图文件的大小或移除复杂的地图结构。\n" "(注:减少复杂的地图结构能有效提升画面渲染性能!)" -#: CompilerPane.py:129 +#: app/CompilerPane.py:127 #, fuzzy msgid "" "Entities are the things in the map that have functionality. Removing " @@ -59,7 +96,7 @@ msgstr "" "项目描述窗口中将统计已使用的实体数量,但并不完全准确,某些实体虽会被统计在内,但不会受到实体数量的限制。\n" "(注:地图内的实体数量被限制为2048个,超过这个数量有可能导致游戏崩溃!)" -#: CompilerPane.py:139 +#: app/CompilerPane.py:137 #, fuzzy msgid "" "Overlays are smaller images affixed to surfaces, like signs or indicator " @@ -69,25 +106,25 @@ msgstr "" "标记是地面(或墙面)上较小的图片,例如标志或指示灯。\n" "隐藏蚂蚁线或将其设置为标志将有助于升画面渲染性能。" -#: CompilerPane.py:275 +#: app/CompilerPane.py:273 msgid "Corridor" msgstr "走廊" -#: CompilerPane.py:316 +#: app/CompilerPane.py:314 msgid "" "Randomly choose a corridor. This is saved in the puzzle data and will not" " change." msgstr "随机选择一个走廊,被随机选中的走廊将保存在地图编辑器中且不会再次变更。" -#: CompilerPane.py:322 UI.py:657 +#: app/CompilerPane.py:320 app/UI.py:664 msgid "Random" msgstr "随机" -#: CompilerPane.py:421 +#: app/CompilerPane.py:419 msgid "Image Files" msgstr "图片文件" -#: CompilerPane.py:504 +#: app/CompilerPane.py:502 msgid "" "Options on this panel can be changed \n" "without exporting or restarting the game." @@ -95,35 +132,35 @@ msgstr "" "修改此面板的选项将立即生效,\n" "而无需导出或重新启动游戏。" -#: CompilerPane.py:519 +#: app/CompilerPane.py:517 msgid "Map Settings" msgstr "地图设置" -#: CompilerPane.py:524 +#: app/CompilerPane.py:522 msgid "Compile Settings" msgstr "编译设置" -#: CompilerPane.py:538 +#: app/CompilerPane.py:536 msgid "Thumbnail" msgstr "地图预览快照" -#: CompilerPane.py:546 +#: app/CompilerPane.py:544 msgid "Auto" msgstr "自动获取截图" -#: CompilerPane.py:554 +#: app/CompilerPane.py:552 msgid "PeTI" msgstr "编辑器预览图" -#: CompilerPane.py:562 +#: app/CompilerPane.py:560 msgid "Custom:" msgstr "自定义预览图" -#: CompilerPane.py:580 +#: app/CompilerPane.py:578 msgid "Cleanup old screenshots" msgstr "清理过时的旧截图" -#: CompilerPane.py:590 +#: app/CompilerPane.py:588 msgid "" "Override the map image to use a screenshot automatically taken from the " "beginning of a chamber. Press F5 to take a new screenshot. If the map has" @@ -133,11 +170,11 @@ msgstr "" "使用实验室开始的自动截图作为地图的介绍图,或者使用F5拍摄的新截图。\n" "如果最近几小时内未预览地图,则使用默认的编辑器预览图。" -#: CompilerPane.py:598 +#: app/CompilerPane.py:596 msgid "Use the normal editor view for the map preview image." msgstr "使用默认编辑器视图作为地图预览图像。" -#: CompilerPane.py:600 +#: app/CompilerPane.py:598 msgid "" "Use a custom image for the map preview image. Click the screenshot to " "select.\n" @@ -146,7 +183,7 @@ msgstr "" "将自定义图片用作地图预览图片,点击快照窗口选择图片。\n" "如果需要,图片将转换为JPEG格式。" -#: CompilerPane.py:617 +#: app/CompilerPane.py:615 msgid "" "Automatically delete unused Automatic screenshots. Disable if you want to" " keep things in \"portal2/screenshots\". " @@ -154,19 +191,19 @@ msgstr "" "自动删除未使用的自动截图,如果你想保留这些截图请取消勾选。\n" "这些截图将保留在此路径“portal2/screenshots”" -#: CompilerPane.py:628 +#: app/CompilerPane.py:626 msgid "Lighting:" msgstr "光影渲染模式" -#: CompilerPane.py:635 +#: app/CompilerPane.py:633 msgid "Fast" msgstr "最快速度" -#: CompilerPane.py:642 +#: app/CompilerPane.py:640 msgid "Full" msgstr "最佳画质" -#: CompilerPane.py:650 +#: app/CompilerPane.py:648 msgid "" "Compile with lower-quality, fast lighting. This speeds up compile times, " "but does not appear as good. Some shadows may appear wrong.\n" @@ -175,7 +212,7 @@ msgstr "" "使用低质量的光照以加快渲染,但将导致画面变得糟糕,部分阴影可能会导致失真。\n" "发布地图时,这个选项将被忽略。" -#: CompilerPane.py:657 +#: app/CompilerPane.py:655 #, fuzzy msgid "" "Compile with high-quality lighting. This looks correct, but takes longer " @@ -186,11 +223,11 @@ msgstr "" "如果你希望布置酷炫的光线效果,请使用此选项。\n" "发布地图时,将始终使用此选项。" -#: CompilerPane.py:664 +#: app/CompilerPane.py:662 msgid "Dump packed files to:" msgstr "转储打包后的文件" -#: CompilerPane.py:689 +#: app/CompilerPane.py:687 msgid "" "When compiling, dump all files which were packed into the map. Useful if " "you're intending to edit maps in Hammer." @@ -198,37 +235,37 @@ msgstr "" "编译时,转储地图会用到的所有数据包文件,用于Hammer编辑地图。\n" "(必须使用全英文路径,并建立新文件夹,转储数据时会清空同名文件夹内原有的内容)" -#: CompilerPane.py:695 +#: app/CompilerPane.py:693 msgid "Last Compile:" msgstr "编译数据统计" -#: CompilerPane.py:705 +#: app/CompilerPane.py:703 msgid "Entity" msgstr "实体" -#: CompilerPane.py:725 +#: app/CompilerPane.py:723 msgid "Overlay" msgstr "标记" -#: CompilerPane.py:744 +#: app/CompilerPane.py:742 msgid "" "Refresh the compile progress bars. Press after a compile has been " "performed to show the new values." msgstr "刷新数据统计。 执行编译后点击,以更新数据。" -#: CompilerPane.py:750 +#: app/CompilerPane.py:748 msgid "Brush" msgstr "画刷" -#: CompilerPane.py:778 +#: app/CompilerPane.py:776 msgid "Voicelines:" msgstr "声线选择" -#: CompilerPane.py:785 +#: app/CompilerPane.py:783 msgid "Use voiceline priorities" msgstr "使用高优先级声线" -#: CompilerPane.py:791 +#: app/CompilerPane.py:789 msgid "" "Only choose the highest-priority voicelines. This means more generic " "lines will can only be chosen if few test elements are in the map. If " @@ -237,19 +274,19 @@ msgstr "" "仅选择优先级最高的声线,这意味着当地图中测试元素很少时,仅能选择通用的声线。\n" "如果禁用,将可使用任何可选的声线。" -#: CompilerPane.py:798 +#: app/CompilerPane.py:796 msgid "Spawn at:" msgstr "出生位置" -#: CompilerPane.py:809 +#: app/CompilerPane.py:807 msgid "Entry Door" msgstr "入口" -#: CompilerPane.py:816 +#: app/CompilerPane.py:814 msgid "Elevator" msgstr "电梯" -#: CompilerPane.py:826 +#: app/CompilerPane.py:824 #, fuzzy msgid "" "When previewing in SP, spawn inside the entry elevator. Use this to " @@ -259,54 +296,54 @@ msgstr "" "这会禁用到达出口后地图重新开始。\n" "使用此选项来检查入口走廊和出口走廊是否令人满意。" -#: CompilerPane.py:831 +#: app/CompilerPane.py:829 #, fuzzy msgid "When previewing in SP, spawn just before the entry door." msgstr "" "单人模式预览地图时,在入口前出生(跳过入口走廊)。\n" "当你到达出口时,地图将重新开始。(以便快速检查地图的谜题)" -#: CompilerPane.py:837 +#: app/CompilerPane.py:835 msgid "Corridor:" msgstr "走廊样式" -#: CompilerPane.py:856 +#: app/CompilerPane.py:854 msgid "SP Entry:" msgstr "单人模式入口" -#: CompilerPane.py:861 +#: app/CompilerPane.py:859 msgid "SP Exit:" msgstr "单人模式出口" -#: CompilerPane.py:866 +#: app/CompilerPane.py:864 msgid "Coop:" msgstr "合作模式" -#: CompilerPane.py:872 +#: app/CompilerPane.py:870 msgid "Player Model (SP):" msgstr "玩家模型(单人模式)" -#: CompilerPane.py:896 +#: app/CompilerPane.py:894 msgid "Compile Options" msgstr "编译选项" -#: CompilerPane.py:914 +#: app/CompilerPane.py:912 msgid "Compiler Options - {}" msgstr "开发者选项 - {}" -#: StyleVarPane.py:33 +#: app/StyleVarPane.py:31 msgid "Multiverse Cave" msgstr "启用Cave谈论平行宇宙的语音" -#: StyleVarPane.py:35 +#: app/StyleVarPane.py:33 msgid "Play the Workshop Cave Johnson lines on map start." msgstr "进入地图后播放Cave谈论平行宇宙的语音" -#: StyleVarPane.py:40 +#: app/StyleVarPane.py:38 msgid "Prevent Portal Bump (fizzler)" msgstr "阻止传送门跃过消散力场" -#: StyleVarPane.py:42 +#: app/StyleVarPane.py:40 msgid "" "Add portal bumpers to make it more difficult to portal across fizzler " "edges. This can prevent placing portals in tight spaces near fizzlers, or" @@ -316,19 +353,19 @@ msgstr "" "这可以防止将传送门放置在消散立场与墙壁之间的夹缝中,\n" "同时也阻止通过挤门的方式把传送门开启到消散立场的另一边。" -#: StyleVarPane.py:49 +#: app/StyleVarPane.py:47 msgid "Suppress Mid-Chamber Dialogue" msgstr "禁用实验室内的AI语音" -#: StyleVarPane.py:51 +#: app/StyleVarPane.py:49 msgid "Disable all voicelines other than entry and exit lines." msgstr "禁用在入口通道和出口通道以外的地区播放电脑语音。" -#: StyleVarPane.py:56 +#: app/StyleVarPane.py:54 msgid "Unlock Default Items" msgstr "允许编辑默认物品" -#: StyleVarPane.py:58 +#: app/StyleVarPane.py:56 msgid "" "Allow placing and deleting the mandatory Entry/Exit Doors and Large " "Observation Room. Use with caution, this can have weird results!" @@ -336,11 +373,11 @@ msgstr "" "允许放置和删除强制性的进/出门和大型观察室。\n" "谨慎使用,可能会产生奇怪的结果!" -#: StyleVarPane.py:65 +#: app/StyleVarPane.py:63 msgid "Allow Adding Goo Mist" msgstr "允许为致命酸液添加雾气效果" -#: StyleVarPane.py:67 +#: app/StyleVarPane.py:65 msgid "" "Add mist particles above Toxic Goo in certain styles. This can increase " "the entity count significantly with large, complex goo pits, so disable " @@ -349,11 +386,11 @@ msgstr "" "在某些风格中的致命酸液上添加带有雾气的粒子效果。\n" "但这会增加实体的数量,如果有复杂的酸液池,可以考虑禁用此特效以提升性能。" -#: StyleVarPane.py:74 +#: app/StyleVarPane.py:72 msgid "Light Reversible Excursion Funnels" msgstr "允许牵引光束转换极性" -#: StyleVarPane.py:76 +#: app/StyleVarPane.py:74 msgid "" "Funnels emit a small amount of light. However, if multiple funnels are " "near each other and can reverse polarity, this can cause lighting issues." @@ -363,11 +400,11 @@ msgstr "" "牵引光束会发出少量的光。然而,多个牵引光束彼此靠近且可以反转极性时,则可能导致照明出现问题。\n" "禁用此功能可以通过关闭发光来避免这个问题,不可逆的牵引光束没有此问题。" -#: StyleVarPane.py:84 +#: app/StyleVarPane.py:82 msgid "Enable Shape Framing" msgstr "为蚂蚁标志添加边框" -#: StyleVarPane.py:86 +#: app/StyleVarPane.py:84 msgid "" "After 10 shape-type antlines are used, the signs repeat. With this " "enabled, colored frames will be added to distinguish them." @@ -375,91 +412,91 @@ msgstr "" "当蚂蚁线标志超过10个种类时会出现符号重复。\n" "启用此功能可以通过添加彩色边框的方式区分它们。" -#: StyleVarPane.py:155 +#: app/StyleVarPane.py:153 msgid "Default: On" msgstr "默认:开启" -#: StyleVarPane.py:157 +#: app/StyleVarPane.py:155 msgid "Default: Off" msgstr "默认:关闭" -#: StyleVarPane.py:161 +#: app/StyleVarPane.py:159 msgid "Styles: Unstyled" msgstr "风格:无" -#: StyleVarPane.py:171 +#: app/StyleVarPane.py:169 msgid "Styles: All" msgstr "风格:所有" -#: StyleVarPane.py:179 +#: app/StyleVarPane.py:177 msgid "Style: {}" msgid_plural "Styles: {}" msgstr[0] "风格:{}" -#: StyleVarPane.py:233 +#: app/StyleVarPane.py:231 msgid "Style/Item Properties" msgstr "风格/物品 属性" -#: StyleVarPane.py:252 +#: app/StyleVarPane.py:250 msgid "Styles" msgstr "风格属性" -#: StyleVarPane.py:271 +#: app/StyleVarPane.py:269 msgid "All:" msgstr "所有风格:" -#: StyleVarPane.py:274 +#: app/StyleVarPane.py:272 msgid "Selected Style:" msgstr "所选风格:" -#: StyleVarPane.py:282 +#: app/StyleVarPane.py:280 msgid "Other Styles:" msgstr "其它风格:" -#: StyleVarPane.py:287 +#: app/StyleVarPane.py:285 msgid "No Options!" msgstr "没有选项!" -#: StyleVarPane.py:293 +#: app/StyleVarPane.py:291 msgid "None!" msgstr "无!" -#: StyleVarPane.py:364 +#: app/StyleVarPane.py:362 msgid "Items" msgstr "物品属性" -#: SubPane.py:84 +#: app/SubPane.py:85 msgid "Hide/Show the \"{}\" window." msgstr "隐藏/显示 \"{}\" 窗口。" -#: UI.py:67 +#: app/UI.py:70 msgid "Export..." msgstr "导出到..." -#: UI.py:591 +#: app/UI.py:598 msgid "Select Skyboxes" msgstr "选择天空布景" -#: UI.py:592 +#: app/UI.py:599 msgid "" "The skybox decides what the area outside the chamber is like. It chooses " "the colour of sky (seen in some items), the style of bottomless pit (if " "present), as well as color of \"fog\" (seen in larger chambers)." msgstr "天空布景决定了实验室外部空间的样子。它选择天空的颜色(在某些项目中可见),底板悬空的风格(如果存在)以及“雾”的颜色(在较大的实验室可见)。" -#: UI.py:600 +#: app/UI.py:607 msgid "3D Skybox" msgstr "3D天空布景" -#: UI.py:601 +#: app/UI.py:608 msgid "Fog Color" msgstr "迷雾颜色" -#: UI.py:608 +#: app/UI.py:615 msgid "Select Additional Voice Lines" msgstr "选择其它语音声线" -#: UI.py:609 +#: app/UI.py:616 msgid "" "Voice lines choose which extra voices play as the player enters or exits " "a chamber. They are chosen based on which items are present in the map. " @@ -470,31 +507,31 @@ msgstr "" "它们会根据地图中存在哪些物品来选择播放哪一段语音。\n" "附加的“Cave谈论平行宇宙”的语音在“风格属性”中单独控制。" -#: UI.py:614 +#: app/UI.py:621 msgid "Add no extra voice lines, only Multiverse Cave if enabled." msgstr "不添加额外的声线,仅使用Cave关于多元宇宙的谈话。(如果它被勾选)" -#: UI.py:616 +#: app/UI.py:623 msgid "" msgstr "<仅使用平行宇宙的凯文>" -#: UI.py:620 +#: app/UI.py:627 msgid "Characters" msgstr "角色" -#: UI.py:621 +#: app/UI.py:628 msgid "Turret Shoot Monitor" msgstr "炮塔会射击显示器" -#: UI.py:622 +#: app/UI.py:629 msgid "Monitor Visuals" msgstr "显示器视觉效果" -#: UI.py:629 +#: app/UI.py:636 msgid "Select Style" msgstr "选择风格" -#: UI.py:630 +#: app/UI.py:637 msgid "" "The Style controls many aspects of the map. It decides the materials used" " for walls, the appearance of entrances and exits, the design for most " @@ -503,15 +540,15 @@ msgid "" "The style broadly defines the time period a chamber is set in." msgstr "地图的风格决定了墙壁的材质,出入口的外观,大多数物品的外观以及其它设置。" -#: UI.py:641 +#: app/UI.py:648 msgid "Elevator Videos" msgstr "电梯间墙壁上播放的影像" -#: UI.py:648 +#: app/UI.py:655 msgid "Select Elevator Video" msgstr "选择电梯间播放的影响" -#: UI.py:649 +#: app/UI.py:656 msgid "" "Set the video played on the video screens in modern Aperture elevator " "rooms. Not all styles feature these. If set to \"None\", a random video " @@ -520,23 +557,23 @@ msgstr "" "设置现代光圈科技电梯间墙壁上播放的影像,并非所有风格都有这个影像。\n" "如果设置为无,将在每次载入地图时随机选择影像,就像默认编辑器里的一样。" -#: UI.py:653 +#: app/UI.py:660 msgid "This style does not have a elevator video screen." msgstr "这种风格的电梯间没有影像屏幕。" -#: UI.py:658 +#: app/UI.py:665 msgid "Choose a random video." msgstr "随机选择一个影像。" -#: UI.py:662 +#: app/UI.py:669 msgid "Multiple Orientations" msgstr "多种方向" -#: UI.py:883 +#: app/UI.py:897 msgid "Selected Items and Style successfully exported!" msgstr "所选物品和风格已成功导出!" -#: UI.py:885 +#: app/UI.py:899 msgid "" "\n" "\n" @@ -547,199 +584,191 @@ msgstr "" "\n" "警告:VPK文件未导出,退出 Portal 2 和 Hammer 以应用地图编辑器的物品栏更改。" -#: UI.py:898 -msgid "" -"\n" -" Launch Game?" -msgstr "" -"\n" -"启动游戏?" - -#: UI.py:1113 +#: app/UI.py:1131 msgid "Delete Palette \"{}\"" msgstr "删除模板 \"{}\"" -#: UI.py:1189 +#: app/UI.py:1207 msgid "BEE2 - Save Palette" msgstr "BEE2 - 保存模板" -#: UI.py:1190 +#: app/UI.py:1208 msgid "Enter a name:" msgstr "键入模板名称:" -#: UI.py:1199 +#: app/UI.py:1217 msgid "This palette already exists. Overwrite?" msgstr "已经存在同名模板,是否覆盖?" -#: UI.py:1228 gameMan.py:1529 +#: app/UI.py:1249 app/gameMan.py:1527 msgid "Are you sure you want to delete \"{}\"?" msgstr "你确定要删除 \"{}\" 吗?" -#: UI.py:1255 +#: app/UI.py:1277 msgid "Clear Palette" msgstr "清空模板内容" -#: UI.py:1291 UI.py:1727 +#: app/UI.py:1313 app/UI.py:1747 msgid "Delete Palette" msgstr "删除选中模板" -#: UI.py:1311 +#: app/UI.py:1333 msgid "Save Palette..." msgstr "保存模板..." -#: UI.py:1316 UI.py:1750 +#: app/UI.py:1338 app/UI.py:1770 msgid "Save Palette As..." msgstr "另存为模板..." -#: UI.py:1327 UI.py:1738 +#: app/UI.py:1349 app/UI.py:1758 msgid "Save Settings in Palettes" msgstr "在模板中保存配置" -#: UI.py:1345 music_conf.py:204 +#: app/UI.py:1367 app/music_conf.py:205 msgid "Music: " msgstr "音乐选择:" -#: UI.py:1371 +#: app/UI.py:1393 msgid "{arr} Use Suggested {arr}" msgstr "{arr} 使用推荐配置 {arr}" -#: UI.py:1387 +#: app/UI.py:1409 msgid "Style: " msgstr "物品风格" -#: UI.py:1389 +#: app/UI.py:1411 msgid "Voice: " msgstr "旁白语音" -#: UI.py:1390 +#: app/UI.py:1412 msgid "Skybox: " msgstr "天空布景" -#: UI.py:1391 +#: app/UI.py:1413 msgid "Elev Vid: " msgstr "电梯视频" -#: UI.py:1409 +#: app/UI.py:1431 msgid "" "Enable or disable particular voice lines, to prevent them from being " "added." msgstr "启用或禁用特定的台词,以防止添加它们。" -#: UI.py:1512 +#: app/UI.py:1534 msgid "All Items: " msgstr "所有物品:" -#: UI.py:1646 +#: app/UI.py:1666 msgid "Export to \"{}\"..." msgstr "导出到 \"{}\"..." -#: UI.py:1674 backup.py:876 +#: app/UI.py:1694 app/backup.py:872 msgid "File" msgstr "文件" -#: UI.py:1681 +#: app/UI.py:1701 msgid "Export" msgstr "导出" -#: UI.py:1688 backup.py:880 +#: app/UI.py:1708 app/backup.py:876 msgid "Add Game" msgstr "添加游戏" -#: UI.py:1692 +#: app/UI.py:1712 msgid "Uninstall from Selected Game" msgstr "删除选中的游戏" -#: UI.py:1696 +#: app/UI.py:1716 msgid "Backup/Restore Puzzles..." msgstr "备份/恢复 谜题..." -#: UI.py:1700 +#: app/UI.py:1720 msgid "Manage Packages..." msgstr "管理资源包..." -#: UI.py:1705 +#: app/UI.py:1725 msgid "Options" msgstr "设置" -#: UI.py:1710 gameMan.py:1208 +#: app/UI.py:1730 app/gameMan.py:1206 msgid "Quit" msgstr "退出" -#: UI.py:1720 +#: app/UI.py:1740 msgid "Palette" msgstr "模板" -#: UI.py:1722 +#: app/UI.py:1742 msgid "Clear" msgstr "清空模板" -#: UI.py:1731 +#: app/UI.py:1751 msgid "Fill Palette" msgstr "重置模板" -#: UI.py:1745 +#: app/UI.py:1765 msgid "Save Palette" msgstr "保存模板" -#: UI.py:1760 +#: app/UI.py:1780 msgid "View" msgstr "" -#: UI.py:1879 +#: app/UI.py:1899 msgid "Palettes" msgstr "模板列表" -#: UI.py:1904 +#: app/UI.py:1924 msgid "Export Options" msgstr "导出设置" -#: UI.py:1936 +#: app/UI.py:1956 msgid "Fill empty spots in the palette with random items." msgstr "随机选择物品填充物品栏中的空位。" -#: backup.py:81 +#: app/backup.py:79 msgid "Copying maps" msgstr "正在复制地图..." -#: backup.py:86 +#: app/backup.py:84 msgid "Loading maps" msgstr "正在载入地图..." -#: backup.py:91 +#: app/backup.py:89 msgid "Deleting maps" msgstr "正在删除地图..." -#: backup.py:142 +#: app/backup.py:140 msgid "Failed to parse this puzzle file. It can still be backed up." msgstr "无法解析此谜题文件,但它仍然可以备份。" -#: backup.py:146 +#: app/backup.py:144 msgid "No description found." msgstr "找不到描述。" -#: backup.py:177 +#: app/backup.py:175 msgid "Coop" msgstr "合作模式" -#: backup.py:177 +#: app/backup.py:175 msgid "SP" msgstr "单人模式" -#: backup.py:339 +#: app/backup.py:337 msgid "This filename is already in the backup.Do you wish to overwrite it? ({})" msgstr "" "已存在同名的备份文件,是否要覆盖它?\n" "({})" -#: backup.py:445 +#: app/backup.py:443 msgid "BEE2 Backup" msgstr "BEE2 备份" -#: backup.py:446 +#: app/backup.py:444 msgid "No maps were chosen to backup!" msgstr "请选择要备份的地图!" -#: backup.py:506 +#: app/backup.py:504 msgid "" "This map is already in the game directory.Do you wish to overwrite it? " "({})" @@ -747,243 +776,243 @@ msgstr "" "游戏目录中已存在同名的地图文件,是否要覆盖它?\n" "({})" -#: backup.py:568 +#: app/backup.py:566 msgid "Load Backup" msgstr "载入备份" -#: backup.py:569 backup.py:628 +#: app/backup.py:567 app/backup.py:626 msgid "Backup zip" msgstr "备份为zip文件" -#: backup.py:602 +#: app/backup.py:600 msgid "Unsaved Backup" msgstr "未保持的备份" -#: backup.py:627 backup.py:874 +#: app/backup.py:625 app/backup.py:870 msgid "Save Backup As" msgstr "将备份另存为" -#: backup.py:724 +#: app/backup.py:721 msgid "Confirm Deletion" msgstr "确认删除" -#: backup.py:725 +#: app/backup.py:722 msgid "Do you wish to delete {} map?\n" msgid_plural "Do you wish to delete {} maps?\n" msgstr[0] "确定要删除 {} 张地图?\n" -#: backup.py:762 +#: app/backup.py:759 msgid "Restore:" msgstr "还原:" -#: backup.py:763 +#: app/backup.py:760 msgid "Backup:" msgstr "备份:" -#: backup.py:800 +#: app/backup.py:797 msgid "Checked" msgstr "已选" -#: backup.py:808 +#: app/backup.py:805 msgid "Delete Checked" msgstr "删除已选" -#: backup.py:858 +#: app/backup.py:854 msgid "BEEMOD {} - Backup / Restore Puzzles" msgstr "BEEMOD {} - 备份/恢复 谜题" -#: backup.py:871 backup.py:999 +#: app/backup.py:867 app/backup.py:995 msgid "New Backup" msgstr "新建备份" -#: backup.py:872 backup.py:1006 +#: app/backup.py:868 app/backup.py:1002 msgid "Open Backup" msgstr "打开备份" -#: backup.py:873 backup.py:1013 +#: app/backup.py:869 app/backup.py:1009 msgid "Save Backup" msgstr "保存备份" -#: backup.py:881 +#: app/backup.py:877 msgid "Remove Game" msgstr "删除游戏" -#: backup.py:884 +#: app/backup.py:880 msgid "Game" msgstr "游戏" -#: backup.py:930 +#: app/backup.py:926 msgid "Automatic Backup After Export" msgstr "导出后自动备份" -#: backup.py:962 +#: app/backup.py:958 msgid "Keep (Per Game):" msgstr "保持(每N场游戏)" -#: backup.py:980 +#: app/backup.py:976 msgid "Backup/Restore Puzzles" msgstr "备份/恢复 谜题" -#: contextWin.py:79 +#: app/contextWin.py:76 msgid "This item may not be rotated." msgstr "该物品可能无法旋转。" -#: contextWin.py:80 +#: app/contextWin.py:77 msgid "This item can be pointed in 4 directions." msgstr "该物品可以面向4个方向。" -#: contextWin.py:81 +#: app/contextWin.py:78 msgid "This item can be positioned on the sides and center." msgstr "该物品可以放在侧面和中间。" -#: contextWin.py:82 +#: app/contextWin.py:79 msgid "This item can be centered in two directions, plus on the sides." msgstr "该物品可以向三个方向延伸。" -#: contextWin.py:83 +#: app/contextWin.py:80 msgid "This item can be placed like light strips." msgstr "该物品可以像灯条一样放置。" -#: contextWin.py:84 +#: app/contextWin.py:81 msgid "This item can be rotated on the floor to face 360 degrees." msgstr "该物品可以在地面上360°旋转。" -#: contextWin.py:85 +#: app/contextWin.py:82 msgid "This item is positioned using a catapult trajectory." msgstr "该物品用于定位弹射板的弹道及落点。" -#: contextWin.py:86 +#: app/contextWin.py:83 msgid "This item positions the dropper to hit target locations." msgstr "该物品定位物品掉落器击中目标的位置。" -#: contextWin.py:88 +#: app/contextWin.py:85 msgid "This item does not accept any inputs." msgstr "该物品不会接收任何输入信号。" -#: contextWin.py:89 +#: app/contextWin.py:86 msgid "This item accepts inputs." msgstr "该物品可以接收信号输入以改变状态。" -#: contextWin.py:90 +#: app/contextWin.py:87 msgid "This item has two input types (A and B), using the Input A and B items." msgstr "该物品具有两种输入类型(A和B),使用A物品和B物品进行输入。" -#: contextWin.py:92 +#: app/contextWin.py:89 msgid "This item does not output." msgstr "该物品不会输出信号。" -#: contextWin.py:93 +#: app/contextWin.py:90 msgid "This item has an output." msgstr "该物品可以输出信号。" -#: contextWin.py:94 +#: app/contextWin.py:91 msgid "This item has a timed output." msgstr "该物品具有延时输出信号的功能。" -#: contextWin.py:96 +#: app/contextWin.py:93 msgid "This item does not take up any space inside walls." msgstr "该物品不会占据墙壁后面的空间。" -#: contextWin.py:97 +#: app/contextWin.py:94 msgid "This item takes space inside the wall." msgstr "该物品需要占据墙壁后面的空间。" -#: contextWin.py:99 +#: app/contextWin.py:96 msgid "This item cannot be placed anywhere..." msgstr "该物品不能手动放置" -#: contextWin.py:100 +#: app/contextWin.py:97 msgid "This item can only be attached to ceilings." msgstr "该物品只能放置在天花板上。" -#: contextWin.py:101 +#: app/contextWin.py:98 msgid "This item can only be placed on the floor." msgstr "该物品只能放置在地板上。" -#: contextWin.py:102 +#: app/contextWin.py:99 msgid "This item can be placed on floors and ceilings." msgstr "该物品可以放置在地板和天花板上。" -#: contextWin.py:103 +#: app/contextWin.py:100 msgid "This item can be placed on walls only." msgstr "该物品只能放置在墙上。" -#: contextWin.py:104 +#: app/contextWin.py:101 msgid "This item can be attached to walls and ceilings." msgstr "该物品可以放置在墙壁和天花板上。" -#: contextWin.py:105 +#: app/contextWin.py:102 msgid "This item can be placed on floors and walls." msgstr "该物品可以放置在地板和墙壁上。" -#: contextWin.py:106 +#: app/contextWin.py:103 msgid "This item can be placed in any orientation." msgstr "该物品可以放置在任何方向。" -#: contextWin.py:212 +#: app/contextWin.py:209 #, fuzzy msgid "No Alternate Versions" msgstr "无替代版本!" -#: contextWin.py:304 +#: app/contextWin.py:301 msgid "Excursion Funnels accept a on/off input and a directional input." msgstr "牵引光束接受“开/关”控制和“方向”转换控制。" -#: contextWin.py:361 +#: app/contextWin.py:358 msgid "" "This item can be rotated on the floor to face 360 degrees, for Reflection" " Cubes only." msgstr "该物品可以在地面上360°旋转放置。(仅适用于透镜方块)" -#: contextWin.py:440 +#: app/contextWin.py:437 msgid "Properties:" msgstr "物品属性:" -#: contextWin.py:462 +#: app/contextWin.py:459 msgid "" "The number of entities used for this item. The Source engine limits this " "to 2048 in total. This provides a guide to how many of these items can be" " placed in a map at once." msgstr "用于此物品的实体数量。起源引擎将其限制为2048。这里提供了一篇可以一次性放置多少物品在地图里的指南。" -#: contextWin.py:487 +#: app/contextWin.py:484 msgid "Description:" msgstr "描述:" -#: contextWin.py:530 +#: app/contextWin.py:527 msgid "" "Failed to open a web browser. Do you wish for the URL to be copied to the" " clipboard instead?" msgstr "无法打开浏览器。你希望将网址复制到剪贴板吗?" -#: contextWin.py:544 +#: app/contextWin.py:541 msgid "More Info>>" msgstr "更多信息>>" -#: contextWin.py:561 +#: app/contextWin.py:558 msgid "Change Defaults..." msgstr "更改默认值..." -#: contextWin.py:567 +#: app/contextWin.py:564 msgid "Change the default settings for this item when placed." msgstr "修改该物品在放置时的默认设置。" -#: gameMan.py:750 gameMan.py:852 +#: app/gameMan.py:748 app/gameMan.py:850 msgid "BEE2 - Export Failed!" msgstr "BEE2 - 导出失败!" -#: gameMan.py:751 +#: app/gameMan.py:749 msgid "" "Compiler file {file} missing. Exit Steam applications, then press OK to " "verify your game cache. You can then export again." msgstr "编译器文件 {file} 丢失。退出Steam程序,然后点击OK以校验你的游戏缓存。然后再次尝试导出。" -#: gameMan.py:853 +#: app/gameMan.py:851 #, fuzzy msgid "Copying compiler file {file} failed. Ensure {game} is not running." msgstr "复制编译器文件 {file} 失败。确保 {game} 未运行" -#: gameMan.py:1265 +#: app/gameMan.py:1263 msgid "" "Ap-Tag Coop gun instance not found!\n" "Coop guns will not work - verify cache to fix." @@ -991,48 +1020,48 @@ msgstr "" "找不到光圈科技附加传送枪的实例!\n" "传送器将不起作用 - 校验缓存以修复此问题。" -#: gameMan.py:1269 +#: app/gameMan.py:1267 msgid "BEE2 - Aperture Tag Files Missing" msgstr "BEE2 - 光圈科技附加文件丢失" -#: gameMan.py:1452 +#: app/gameMan.py:1450 msgid "Select the folder where the game executable is located ({appname})..." msgstr "选择游戏可执行文件的路径 {appname}" -#: gameMan.py:1455 gameMan.py:1470 gameMan.py:1480 gameMan.py:1487 -#: gameMan.py:1496 gameMan.py:1505 +#: app/gameMan.py:1453 app/gameMan.py:1468 app/gameMan.py:1478 +#: app/gameMan.py:1485 app/gameMan.py:1494 app/gameMan.py:1503 msgid "BEE2 - Add Game" msgstr "BEE2 - 添加游戏" -#: gameMan.py:1458 +#: app/gameMan.py:1456 msgid "Find Game Exe" msgstr "查找游戏的exe文件" -#: gameMan.py:1459 +#: app/gameMan.py:1457 msgid "Executable" msgstr "可执行文件" -#: gameMan.py:1467 +#: app/gameMan.py:1465 msgid "This does not appear to be a valid game folder!" msgstr "这似乎不是一个有效的游戏文件夹!" -#: gameMan.py:1477 +#: app/gameMan.py:1475 msgid "Portal Stories: Mel doesn't have an editor!" msgstr "没有《传送门:梅尔的故事》的编辑器!" -#: gameMan.py:1488 +#: app/gameMan.py:1486 msgid "Enter the name of this game:" msgstr "输入此游戏的名称:" -#: gameMan.py:1495 +#: app/gameMan.py:1493 msgid "This name is already taken!" msgstr "该名称已经存在!" -#: gameMan.py:1504 +#: app/gameMan.py:1502 msgid "Please enter a name for this game!" msgstr "请为此游戏创建一个名称!" -#: gameMan.py:1523 +#: app/gameMan.py:1521 msgid "" "\n" " (BEE2 will quit, this is the last game set!)" @@ -1040,79 +1069,79 @@ msgstr "" "\n" "(BEE2即将退出,这是最后一次修改游戏的配置!)" -#: helpMenu.py:60 +#: app/helpMenu.py:56 msgid "Wiki..." msgstr "维基百科..." -#: helpMenu.py:62 +#: app/helpMenu.py:58 msgid "Original Items..." msgstr "默认物品..." -#: helpMenu.py:67 +#: app/helpMenu.py:63 msgid "Discord Server..." msgstr "Discord服务器..." -#: helpMenu.py:68 +#: app/helpMenu.py:64 msgid "aerond's Music Changer..." msgstr "BEEMod音乐转换器..." -#: helpMenu.py:70 +#: app/helpMenu.py:66 msgid "Application Repository..." msgstr "软件开源代码库..." -#: helpMenu.py:71 +#: app/helpMenu.py:67 msgid "Items Repository..." msgstr "物品开源代码库..." -#: helpMenu.py:73 +#: app/helpMenu.py:69 msgid "Submit Application Bugs..." msgstr "反馈程序Bug..." -#: helpMenu.py:74 +#: app/helpMenu.py:70 msgid "Submit Item Bugs..." msgstr "反馈物品Bug..." -#: helpMenu.py:76 paletteLoader.py:35 +#: app/helpMenu.py:72 app/paletteLoader.py:35 msgid "Portal 2" msgstr "传送门2" -#: helpMenu.py:77 paletteLoader.py:37 +#: app/helpMenu.py:73 app/paletteLoader.py:37 msgid "Aperture Tag" msgstr "Aperture Tag" -#: helpMenu.py:78 +#: app/helpMenu.py:74 msgid "Portal Stories: Mel" msgstr "传送门:梅尔的故事" -#: helpMenu.py:79 +#: app/helpMenu.py:75 msgid "Thinking With Time Machine" msgstr "传送门:时间机器" -#: helpMenu.py:242 itemPropWin.py:347 +#: app/helpMenu.py:238 app/itemPropWin.py:342 msgid "Close" msgstr "关闭" -#: helpMenu.py:266 +#: app/helpMenu.py:262 msgid "Help" msgstr "帮助" -#: helpMenu.py:277 +#: app/helpMenu.py:273 msgid "BEE2 Credits" msgstr "BEE2 声明" -#: helpMenu.py:294 +#: app/helpMenu.py:290 msgid "Credits..." msgstr "声明..." -#: itemPropWin.py:43 +#: app/itemPropWin.py:38 msgid "Start Position" msgstr "开始位置" -#: itemPropWin.py:44 +#: app/itemPropWin.py:39 msgid "End Position" msgstr "结束位置" -#: itemPropWin.py:45 +#: app/itemPropWin.py:40 msgid "" "Delay \n" "(0=infinite)" @@ -1120,75 +1149,43 @@ msgstr "" "延时\n" "(0=无限)" -#: itemPropWin.py:346 +#: app/itemPropWin.py:341 msgid "No Properties available!" msgstr "没有可用的属性!" -#: itemconfig.py:621 +#: app/itemconfig.py:616 msgid "Choose a Color" msgstr "选择一种颜色" -#: loadScreen.py:199 -msgid "Skipped!" -msgstr "跳过!" - -#: loadScreen.py:200 -msgid "Version: " -msgstr "版本:" - -#: loadScreen.py:201 optionWindow.py:252 packageMan.py:116 selectorWin.py:723 -msgid "Cancel" -msgstr "取消" - -#: loadScreen.py:211 tagsPane.py:53 -msgid "Packages" -msgstr "资源包" - -#: loadScreen.py:212 -msgid "Loading Objects" -msgstr "正在载入对象" - -#: loadScreen.py:213 -msgid "Loading Images" -msgstr "正在载入图像" - -#: loadScreen.py:214 -msgid "Initialising UI" -msgstr "初始化界面" - -#: loadScreen.py:215 -msgid "Better Extended Editor for Portal 2" -msgstr "更棒的传送门2扩展编辑器" - -#: logWindow.py:30 +#: app/logWindow.py:29 msgid "Debug messages" msgstr "调试信息" -#: logWindow.py:31 +#: app/logWindow.py:30 msgid "Default" msgstr "默认值" -#: logWindow.py:32 +#: app/logWindow.py:31 msgid "Warnings Only" msgstr "仅记录警告" -#: logWindow.py:160 +#: app/logWindow.py:159 msgid "Logs - {}" msgstr "日志 - {}" -#: logWindow.py:209 +#: app/logWindow.py:208 msgid "Copy" msgstr "复制" -#: logWindow.py:221 +#: app/logWindow.py:220 msgid "Show:" msgstr "显示:" -#: music_conf.py:132 +#: app/music_conf.py:133 msgid "Select Background Music - Base" msgstr "选择背景音乐 - 基础" -#: music_conf.py:133 +#: app/music_conf.py:134 msgid "" "This controls the background music used for a map. Expand the dropdown to" " set tracks for specific test elements." @@ -1196,157 +1193,189 @@ msgstr "" "这控制用于地图的背景音乐。\n" "展开下拉菜单以设置特定试验元素的声音。" -#: music_conf.py:137 +#: app/music_conf.py:138 msgid "" "Add no music to the map at all. Testing Element-specific music may still " "be added." msgstr "不添在地图内加任何背景音乐。某些特定试验元素的声音仍然可能被添加。" -#: music_conf.py:142 +#: app/music_conf.py:143 msgid "Propulsion Gel SFX" msgstr "加速凝胶的音效" -#: music_conf.py:143 +#: app/music_conf.py:144 msgid "Repulsion Gel SFX" msgstr "斥力凝胶的音效" -#: music_conf.py:144 +#: app/music_conf.py:145 msgid "Excursion Funnel Music" msgstr "牵引光束的音效" -#: music_conf.py:145 music_conf.py:160 +#: app/music_conf.py:146 app/music_conf.py:161 msgid "Synced Funnel Music" msgstr "同步牵引光束的音效" -#: music_conf.py:152 +#: app/music_conf.py:153 msgid "Select Excursion Funnel Music" msgstr "选择牵引光束的音效" -#: music_conf.py:153 +#: app/music_conf.py:154 msgid "Set the music used while inside Excursion Funnels." msgstr "设置玩家处于牵引光束内部时的音效。" -#: music_conf.py:156 +#: app/music_conf.py:157 msgid "Have no music playing when inside funnels." msgstr "玩家处于牵引光束内部时不播放音效。" -#: music_conf.py:167 +#: app/music_conf.py:168 msgid "Select Repulsion Gel Music" msgstr "选择斥力凝胶的音效" -#: music_conf.py:168 +#: app/music_conf.py:169 msgid "Select the music played when players jump on Repulsion Gel." msgstr "选择当玩家跳上斥力凝胶时的音效。" -#: music_conf.py:171 +#: app/music_conf.py:172 msgid "Add no music when jumping on Repulsion Gel." msgstr "玩家跳上斥力凝胶时不播放音效。" -#: music_conf.py:179 +#: app/music_conf.py:180 msgid "Select Propulsion Gel Music" msgstr "选择加速凝胶的音效" -#: music_conf.py:180 +#: app/music_conf.py:181 msgid "" "Select music played when players have large amounts of horizontal " "velocity." msgstr "选择玩家在加速凝胶上奔跑时的音效。" -#: music_conf.py:183 +#: app/music_conf.py:184 msgid "Add no music while running fast." msgstr "玩家在加速凝胶上移动时不播放音效。" -#: music_conf.py:218 +#: app/music_conf.py:219 msgid "Base: " msgstr "基础音乐" -#: music_conf.py:251 +#: app/music_conf.py:252 msgid "Funnel:" msgstr "牵引光束" -#: music_conf.py:252 +#: app/music_conf.py:253 msgid "Bounce:" msgstr "弹性凝胶" -#: music_conf.py:253 +#: app/music_conf.py:254 msgid "Speed:" msgstr "加速凝胶" -#: optionWindow.py:62 +#: app/optionWindow.py:45 +#, fuzzy +msgid "" +"\n" +"Launch Game?" +msgstr "启动游戏" + +#: app/optionWindow.py:47 +#, fuzzy +msgid "" +"\n" +"Minimise BEE2?" +msgstr "最小化BEE2" + +#: app/optionWindow.py:48 +msgid "" +"\n" +"Launch Game and minimise BEE2?" +msgstr "" + +#: app/optionWindow.py:50 +msgid "" +"\n" +"Quit BEE2?" +msgstr "" + +#: app/optionWindow.py:51 +msgid "" +"\n" +"Launch Game and quit BEE2?" +msgstr "" + +#: app/optionWindow.py:70 msgid "BEE2 Options" msgstr "BEE2 选项" -#: optionWindow.py:101 +#: app/optionWindow.py:108 msgid "" "Package cache times have been reset. These will now be extracted during " "the next export." msgstr "" -#: optionWindow.py:118 +#: app/optionWindow.py:125 msgid "\"Preserve Game Resources\" has been disabled." msgstr "" -#: optionWindow.py:130 +#: app/optionWindow.py:137 msgid "Packages Reset" msgstr "" -#: optionWindow.py:211 +#: app/optionWindow.py:218 msgid "General" msgstr "常规" -#: optionWindow.py:217 +#: app/optionWindow.py:224 msgid "Windows" msgstr "窗口" -#: optionWindow.py:223 +#: app/optionWindow.py:230 msgid "Development" msgstr "开发者选项" -#: optionWindow.py:247 packageMan.py:110 selectorWin.py:701 +#: app/optionWindow.py:254 app/packageMan.py:110 app/selector_win.py:696 msgid "OK" msgstr "确定" -#: optionWindow.py:278 +#: app/optionWindow.py:285 msgid "After Export:" msgstr "导出后:" -#: optionWindow.py:295 +#: app/optionWindow.py:302 msgid "Do Nothing" msgstr "什么都不做" -#: optionWindow.py:301 +#: app/optionWindow.py:308 msgid "Minimise BEE2" msgstr "最小化BEE2" -#: optionWindow.py:307 +#: app/optionWindow.py:314 msgid "Quit BEE2" msgstr "退出BEE2" -#: optionWindow.py:315 +#: app/optionWindow.py:322 msgid "After exports, do nothing and keep the BEE2 in focus." msgstr "导出后,什么也不做,保持BEE2窗口处于焦点。" -#: optionWindow.py:317 +#: app/optionWindow.py:324 msgid "After exports, minimise to the taskbar/dock." msgstr "导出后,最小化到任务栏。" -#: optionWindow.py:318 +#: app/optionWindow.py:325 msgid "After exports, quit the BEE2." msgstr "导出后,退出BEE2。" -#: optionWindow.py:325 +#: app/optionWindow.py:332 msgid "Launch Game" msgstr "启动游戏" -#: optionWindow.py:326 +#: app/optionWindow.py:333 msgid "After exporting, launch the selected game automatically." msgstr "导出后,自动启动目标游戏" -#: optionWindow.py:334 optionWindow.py:340 +#: app/optionWindow.py:341 app/optionWindow.py:347 msgid "Play Sounds" msgstr "播放音效" -#: optionWindow.py:345 +#: app/optionWindow.py:352 msgid "" "Pyglet is either not installed or broken.\n" "Sound effects have been disabled." @@ -1354,108 +1383,109 @@ msgstr "" "Pyglet未安装或损坏。\n" "音效已被禁用。" -#: optionWindow.py:352 +#: app/optionWindow.py:359 msgid "Reset Package Caches" msgstr "重置数据包缓存" -#: optionWindow.py:358 +#: app/optionWindow.py:365 msgid "Force re-extracting all package resources." msgstr "" -#: optionWindow.py:367 +#: app/optionWindow.py:374 msgid "Keep windows inside screen" msgstr "保持窗口在屏幕内" -#: optionWindow.py:368 +#: app/optionWindow.py:375 msgid "" "Prevent sub-windows from moving outside the screen borders. If you have " "multiple monitors, disable this." msgstr "防止子窗口移出屏幕边界。 如果您有多台显示器,请禁用此功能。" -#: optionWindow.py:378 +#: app/optionWindow.py:385 #, fuzzy msgid "Keep loading screens on top" msgstr "清理过时的旧截图" -#: optionWindow.py:380 +#: app/optionWindow.py:387 msgid "" "Force loading screens to be on top of other windows. Since they don't " "appear on the taskbar/dock, they can't be brought to the top easily " "again." msgstr "" -#: optionWindow.py:389 +#: app/optionWindow.py:396 msgid "Reset All Window Positions" msgstr "重置所有窗口的位置" -#: optionWindow.py:403 +#: app/optionWindow.py:410 msgid "Log missing entity counts" msgstr "记录丢失的实体数量" -#: optionWindow.py:404 +#: app/optionWindow.py:411 msgid "" "When loading items, log items with missing entity counts in their " "properties.txt file." msgstr "加载物品时,将缺少实体的物品数量记录在properties.txt文件中。" -#: optionWindow.py:412 +#: app/optionWindow.py:419 msgid "Log when item doesn't have a style" msgstr "记录缺失风格的物品" -#: optionWindow.py:413 +#: app/optionWindow.py:420 msgid "" "Log items have no applicable version for a particular style.This usually " "means it will look very bad." msgstr "记录没有当前风格版本的物品。这通常意味着它看起来很违和。" -#: optionWindow.py:421 +#: app/optionWindow.py:428 msgid "Log when item uses parent's style" msgstr "记录使用父风格的物品" -#: optionWindow.py:422 +#: app/optionWindow.py:429 msgid "" "Log when an item reuses a variant from a parent style (1970s using 1950s " "items, for example). This is usually fine, but may need to be fixed." msgstr "记录重复使用父风格变体的物品(例如1970s年代使用1950s年代的物品)。这通常没问题,但是可能需要修复。" -#: optionWindow.py:431 +#: app/optionWindow.py:438 msgid "Log missing packfile resources" msgstr "记录丢失的数据包" -#: optionWindow.py:432 +#: app/optionWindow.py:439 msgid "" "Log when the resources a \"PackList\" refers to are not present in the " "zip. This may be fine (in a prerequisite zip), but it often indicates an " "error." msgstr "记录“数据包列表”里丢失的zip文件。这可能没问题(必备的数据包还在),但通常会报错。" -#: optionWindow.py:441 +#: app/optionWindow.py:448 msgid "Preserve Game Directories" msgstr "保留游戏目录" -#: optionWindow.py:443 +#: app/optionWindow.py:450 +#, fuzzy msgid "" -"When exporting, do not overwrite \n" -"\"bee2/\" and\n" -"\"sdk_content/maps/bee2/\".\n" -"Enable if you're developing new content, to ensure it is not overwritten." +"When exporting, do not copy resources to \n" +"\"bee2/\" and \"sdk_content/maps/bee2/\".\n" +"Only enable if you're developing new content, to ensure it is not " +"overwritten." msgstr "" "当你导出时,不要覆盖写入目录“bee2/”和“sdk_content/maps/bee2/”。\n" "除非你正在建造新的内容,但要确定它不会被覆盖写入。" -#: optionWindow.py:454 +#: app/optionWindow.py:461 msgid "Show Log Window" msgstr "显示日志窗口" -#: optionWindow.py:456 +#: app/optionWindow.py:463 msgid "Show the log file in real-time." msgstr "实时显示日志文件。" -#: optionWindow.py:463 +#: app/optionWindow.py:470 msgid "Force Editor Models" msgstr "强制使用编辑器模型" -#: optionWindow.py:464 +#: app/optionWindow.py:471 msgid "" "Make all props_map_editor models available for use. Portal 2 has a limit " "of 1024 models loaded in memory at once, so we need to disable unused " @@ -1464,20 +1494,20 @@ msgstr "" "使所有props_map_editor模型可用。\n" "Portal 2一次最多可将1024个模型加载到内存中,因此我们需要禁用未使用的模型以释放此模型。" -#: optionWindow.py:475 +#: app/optionWindow.py:482 #, fuzzy msgid "Dump All objects" msgstr "反选所有复选框" -#: optionWindow.py:481 +#: app/optionWindow.py:488 msgid "Dump Items list" msgstr "" -#: packageMan.py:64 +#: app/packageMan.py:64 msgid "BEE2 - Restart Required!" msgstr "BEE2 - 需要重新启动!" -#: packageMan.py:65 +#: app/packageMan.py:65 msgid "" "Changing enabled packages requires a restart.\n" "Continue?" @@ -1485,178 +1515,174 @@ msgstr "" "更改已启用的数据包需要重新启动程序。\n" "继续吗?" -#: packageMan.py:88 +#: app/packageMan.py:88 msgid "BEE2 - Manage Packages" msgstr "BEE2 - 管理数据包" -#: paletteLoader.py:25 +#: app/paletteLoader.py:25 msgid "" msgstr "<上次导出的模板>" -#: paletteLoader.py:27 +#: app/paletteLoader.py:27 msgid "Blank" msgstr "空白" -#: paletteLoader.py:30 +#: app/paletteLoader.py:30 msgid "BEEMod" msgstr "BEE模组物品" -#: paletteLoader.py:32 +#: app/paletteLoader.py:32 msgid "Portal 2 Collapsed" msgstr "传送门2(已折叠)" -#: richTextBox.py:153 +#: app/richTextBox.py:152 msgid "Open \"{}\" in the default browser?" msgstr "在默认浏览器中打开 \"{}\" ?" -#: selectorWin.py:404 +#: app/selector_win.py:399 msgid "Do not add anything." msgstr "不要添加任何东西。" -#: selectorWin.py:408 +#: app/selector_win.py:403 msgid "" msgstr "<无>" -#: selectorWin.py:585 selectorWin.py:590 +#: app/selector_win.py:580 app/selector_win.py:585 msgid "Suggested" msgstr "建议" -#: selectorWin.py:638 +#: app/selector_win.py:633 msgid "Play a sample of this item." msgstr "播放该物品的示例" -#: selectorWin.py:712 +#: app/selector_win.py:707 msgid "Reset to Default" msgstr "重置为默认值" -#: selectorWin.py:773 +#: app/selector_win.py:768 msgid "Other" msgstr "其它" -#: selectorWin.py:1086 +#: app/selector_win.py:1081 msgid "Author: {}" msgid_plural "Authors: {}" msgstr[0] "作者: {}" -#: selectorWin.py:1142 +#: app/selector_win.py:1137 msgid "Color: R={r}, G={g}, B={b}" msgstr "颜色: R={r}, G={g}, B={b}" -#: signage_ui.py:140 signage_ui.py:213 +#: app/signage_ui.py:139 app/signage_ui.py:212 msgid "Configure Signage" msgstr "设置指示标志" -#: signage_ui.py:144 +#: app/signage_ui.py:143 msgid "Selected" msgstr "所选风格" -#: signage_ui.py:167 +#: app/signage_ui.py:166 msgid "Signage: {}" msgstr "指示标志: {}" -#: tagsPane.py:51 +#: app/tagsPane.py:46 msgid "Tags" msgstr "标签" -#: tagsPane.py:52 +#: app/tagsPane.py:47 msgid "Authors" msgstr "制作组" -#: tagsPane.py:162 +#: app/tagsPane.py:157 msgid "Any" msgstr "任何" -#: tagsPane.py:171 +#: app/tagsPane.py:166 msgid "All" msgstr "所有" -#: tagsPane.py:197 +#: app/tagsPane.py:192 msgid "Available Tags (click):" msgstr "可用标签(点击)" -#: utils.py:841 -msgid "__LANG_USE_SANS_SERIF__" -msgstr "" - -#: voiceEditor.py:35 +#: app/voiceEditor.py:33 msgid "Singleplayer" msgstr "单人模式" -#: voiceEditor.py:36 +#: app/voiceEditor.py:34 msgid "Cooperative" msgstr "合作模式" -#: voiceEditor.py:37 +#: app/voiceEditor.py:35 msgid "ATLAS (SP/Coop)" msgstr "" -#: voiceEditor.py:38 +#: app/voiceEditor.py:36 msgid "P-Body (SP/Coop)" msgstr "" -#: voiceEditor.py:41 +#: app/voiceEditor.py:39 msgid "Human characters (Bendy and Chell)" msgstr "人物角色(小黑人和雪儿)" -#: voiceEditor.py:42 +#: app/voiceEditor.py:40 msgid "AI characters (ATLAS, P-Body, or Coop)" msgstr "AI字符(ATLAS,P-Body或Coop)" -#: voiceEditor.py:53 +#: app/voiceEditor.py:51 msgid "Death - Toxic Goo" msgstr "致命 - 剧毒酸液" -#: voiceEditor.py:54 +#: app/voiceEditor.py:52 msgid "Death - Turrets" msgstr "致命 - 炮塔" -#: voiceEditor.py:55 +#: app/voiceEditor.py:53 msgid "Death - Crusher" msgstr "致命 - 钉板" -#: voiceEditor.py:56 +#: app/voiceEditor.py:54 msgid "Death - LaserField" msgstr "致命 - 激光力场" -#: voiceEditor.py:107 +#: app/voiceEditor.py:105 msgid "Transcript:" msgstr "台词:" -#: voiceEditor.py:146 +#: app/voiceEditor.py:144 msgid "Save" msgstr "保存" -#: voiceEditor.py:221 +#: app/voiceEditor.py:219 msgid "Resp" msgstr "响应" -#: voiceEditor.py:238 +#: app/voiceEditor.py:236 msgid "BEE2 - Configure \"{}\"" msgstr "BEE2 - 配置 \"{}\"" -#: voiceEditor.py:315 +#: app/voiceEditor.py:313 msgid "Mid - Chamber" msgstr "在测试室内" -#: voiceEditor.py:317 +#: app/voiceEditor.py:315 msgid "" "Lines played during the actual chamber, after specific events have " "occurred." msgstr "在测试室内触发特定事件后播放的台词。" -#: voiceEditor.py:323 +#: app/voiceEditor.py:321 msgid "Responses" msgstr "回应" -#: voiceEditor.py:325 +#: app/voiceEditor.py:323 msgid "Lines played in response to certain events in Coop." msgstr "在合作模式中触发特定事件后播放的台词。" -#: voiceEditor.py:423 +#: app/voiceEditor.py:421 msgid "No Name!" msgstr "没有名称!" -#: voiceEditor.py:458 +#: app/voiceEditor.py:456 msgid "No Name?" msgstr "没有名称?" @@ -1675,3 +1701,10 @@ msgstr "没有名称?" #~ msgid "Force re-extracting all package resources. This requires a restart." #~ msgstr "强制重新提取所有数据包资源。 这需要重新启动。" +#~ msgid "" +#~ "\n" +#~ " Launch Game?" +#~ msgstr "" +#~ "\n" +#~ "启动游戏?" + diff --git a/src/app/optionWindow.py b/src/app/optionWindow.py index a4fe1091d..aff4e42ee 100644 --- a/src/app/optionWindow.py +++ b/src/app/optionWindow.py @@ -447,9 +447,9 @@ def init_dev_tab(f: ttk.Frame) -> None: item='preserve_bee2_resource_dir', desc=_('Preserve Game Directories'), var=PRESERVE_RESOURCES, - tooltip=_('When exporting, do not overwrite \n"bee2/" and' - '\n"sdk_content/maps/bee2/".\n' - "Enable if you're" + tooltip=_('When exporting, do not copy resources to \n"bee2/" and' + ' "sdk_content/maps/bee2/".\n' + "Only enable if you're" ' developing new content, to ensure it is not ' 'overwritten.'), ).grid(row=0, column=1, sticky=W) From ab0485942a7ed0f6e11550c87ea481bb3a52cc42 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 23 Sep 2020 17:20:27 +1000 Subject: [PATCH 48/87] This function was moved --- src/vrad.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vrad.py b/src/vrad.py index e8b71b9b4..9ecdea253 100644 --- a/src/vrad.py +++ b/src/vrad.py @@ -15,13 +15,13 @@ from typing import List, Set import srctools.run -from srctools import Property +from srctools import Property, FGD from srctools.bsp import BSP, BSP_LUMPS from srctools.filesys import ( RawFileSystem, VPKFileSystem, ZipFileSystem, FileSystem, ) -from srctools.packlist import PackList, load_fgd +from srctools.packlist import PackList from srctools.game import find_gameinfo from srctools.bsp_transform import run_transformations @@ -214,7 +214,7 @@ def main(argv: List[str]) -> None: LOGGER.debug('- {}: {!r}', child_sys[1], child_sys[0]) LOGGER.info('Reading our FGD files...') - fgd = load_fgd() + fgd = FGD.engine_dbase() packlist = PackList(fsys) packlist.load_soundscript_manifest( From 6985187dcb55703aabebad4236e45ed5d4a56ddd Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Sun, 27 Sep 2020 11:17:24 +1000 Subject: [PATCH 49/87] Add "development mode" checkbox, for enabling more debug UI --- src/app/optionWindow.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/app/optionWindow.py b/src/app/optionWindow.py index aff4e42ee..90f6c09ca 100644 --- a/src/app/optionWindow.py +++ b/src/app/optionWindow.py @@ -34,6 +34,7 @@ class AfterExport(Enum): SHOW_LOG_WIN = BooleanVar(value=False, name='OPT_show_log_window') LAUNCH_AFTER_EXPORT = BooleanVar(value=True, name='OPT_launch_after_export') PRESERVE_RESOURCES = BooleanVar(value=False, name='OPT_preserve_bee2_resource_dir') +DEV_MODE = BooleanVar(value=False, name='OPT_development_mode') AFTER_EXPORT_ACTION = IntVar( value=AfterExport.MINIMISE.value, name='OPT_after_export_action', @@ -441,6 +442,16 @@ def init_dev_tab(f: ttk.Frame) -> None: ' but it often indicates an error.'), ).grid(row=3, column=0, sticky=W) + make_checkbox( + f, + section='Debug', + item='development_mode', + var=DEV_MODE, + desc=_("Development Mode"), + tooltip=_('Enables displaying additional UI specific for ' + 'development purposes.'), + ).grid(row=0, column=1, sticky=W) + make_checkbox( f, section='General', @@ -452,7 +463,7 @@ def init_dev_tab(f: ttk.Frame) -> None: "Only enable if you're" ' developing new content, to ensure it is not ' 'overwritten.'), - ).grid(row=0, column=1, sticky=W) + ).grid(row=1, column=1, sticky=W) make_checkbox( f, @@ -461,7 +472,7 @@ def init_dev_tab(f: ttk.Frame) -> None: desc=_('Show Log Window'), var=SHOW_LOG_WIN, tooltip=_('Show the log file in real-time.'), - ).grid(row=1, column=1, sticky=W) + ).grid(row=2, column=1, sticky=W) make_checkbox( f, @@ -471,7 +482,7 @@ def init_dev_tab(f: ttk.Frame) -> None: tooltip=_('Make all props_map_editor models available for use. ' 'Portal 2 has a limit of 1024 models loaded in memory at ' 'once, so we need to disable unused ones to free this up.'), - ).grid(row=2, column=1, sticky='w') + ).grid(row=3, column=1, sticky='w') ttk.Separator(orient='horizontal').grid( row=9, column=0, columnspan=2, sticky='ew' From cea3a9d3bbd30c63e4a21e45333ecf89f80c3487 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Sun, 27 Sep 2020 11:18:12 +1000 Subject: [PATCH 50/87] Add dev-only display showing the item ID of items --- src/app/contextWin.py | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/app/contextWin.py b/src/app/contextWin.py index 272154a50..7656131b3 100644 --- a/src/app/contextWin.py +++ b/src/app/contextWin.py @@ -21,6 +21,7 @@ from app.richTextBox import tkRichText from app import ( itemPropWin, itemconfig, tkMarkdown, tooltip, tk_tools, + optionWindow, sound, img, UI, @@ -35,8 +36,8 @@ wid = {} -selected_item = None # type: UI.Item -selected_sub_item = None # type: UI.PalItem +selected_item: 'UI.Item' +selected_sub_item: 'UI.PalItem' is_open = False version_lookup = [] @@ -256,6 +257,12 @@ def load_item_data(): ) ) + if optionWindow.DEV_MODE.get(): + wid['item_id']['text'] = f'{selected_item.data.source} -> {selected_item.id}:{selected_sub_item.subKey}' + wid['item_id'].grid() + else: + wid['item_id'].grid_remove() + if itemPropWin.can_edit(selected_item.properties()): wid['changedefaults'].state(['!disabled']) else: @@ -446,6 +453,10 @@ def init_widgets(): wid['name'] = ttk.Label(f, text="", anchor="center") wid['name'].grid(row=1, column=0, columnspan=3, sticky="EW") + wid['item_id'] = ttk.Label(f, text="", anchor="center") + wid['item_id'].grid(row=2, column=0, columnspan=3, sticky="EW") + tooltip.add_tooltip(wid['item_id']) + wid['ent_count'] = ttk.Label( f, text="", @@ -462,10 +473,10 @@ def init_widgets(): ) wid['author'] = ttk.Label(f, text="", anchor="center", relief="sunken") - wid['author'].grid(row=2, column=0, columnspan=3, sticky="EW") + wid['author'].grid(row=3, column=0, columnspan=3, sticky="EW") sub_frame = ttk.Frame(f, borderwidth=4, relief="sunken") - sub_frame.grid(column=0, columnspan=3, row=3) + sub_frame.grid(column=0, columnspan=3, row=4) for i in range(5): wid['subitem', i] = ttk.Label( sub_frame, @@ -488,7 +499,7 @@ def init_widgets(): ) spr_frame = ttk.Frame(f, borderwidth=4, relief="sunken") - spr_frame.grid(column=1, columnspan=2, row=4, sticky=W) + spr_frame.grid(column=1, columnspan=2, row=5, sticky=W) # sprites: inputs, outputs, rotation handle, occupied/embed state, # desiredFacing for spr_id in SPR: @@ -501,7 +512,7 @@ def init_widgets(): tooltip.add_tooltip(sprite) desc_frame = ttk.Frame(f, borderwidth=4, relief="sunken") - desc_frame.grid(row=5, column=0, columnspan=3, sticky="EW") + desc_frame.grid(row=6, column=0, columnspan=3, sticky="EW") desc_frame.columnconfigure(0, weight=1) wid['desc'] = tkRichText(desc_frame, width=40, height=16) @@ -539,7 +550,7 @@ def show_more_info(): hide_context(None) wid['moreinfo'] = ttk.Button(f, text=_("More Info>>"), command=show_more_info) - wid['moreinfo'].grid(row=6, column=2, sticky=E) + wid['moreinfo'].grid(row=7, column=2, sticky=E) tooltip.add_tooltip(wid['moreinfo']) menu_info = Menu(wid['moreinfo']) @@ -558,7 +569,7 @@ def show_item_props(): text=_("Change Defaults..."), command=show_item_props, ) - wid['changedefaults'].grid(row=6, column=1) + wid['changedefaults'].grid(row=7, column=1) tooltip.add_tooltip( wid['changedefaults'], _('Change the default settings for this item when placed.') @@ -574,6 +585,6 @@ def show_item_props(): wid['variant'].state(['readonly']) # Prevent directly typing in values wid['variant'].bind('<>', set_item_version) wid['variant'].current(0) - wid['variant'].grid(row=6, column=0, sticky=W) + wid['variant'].grid(row=7, column=0, sticky=W) itemPropWin.init(hide_item_props) From 483eb68da2b5959cebdf473c468db5bae55d2f25 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Sun, 27 Sep 2020 12:06:52 +1000 Subject: [PATCH 51/87] Optionally display item IDs in selector widget --- src/app/selector_win.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/app/selector_win.py b/src/app/selector_win.py index 4b929d4b8..aaab82052 100644 --- a/src/app/selector_win.py +++ b/src/app/selector_win.py @@ -19,7 +19,7 @@ from srctools import Vec, EmptyMapping import srctools.logger from srctools.filesys import FileSystemChain -from app import tkMarkdown, tk_tools, sound, img, TK_ROOT +from app import tkMarkdown, tk_tools, sound, img, TK_ROOT, optionWindow import utils @@ -1092,7 +1092,15 @@ def sel_item(self, item: Item, event=None): width, height = img.tuple_size(ICON_SIZE) self.prop_icon_frm.configure(width=width, height=height) - self.prop_desc.set_text(item.desc) + if optionWindow.DEV_MODE.get(): + # Show the ID of the item in the description + text = tkMarkdown.convert(f'**ID:** {item.name or "NONE"}\n\n') + self.prop_desc.set_text(tkMarkdown.join( + text, + item.desc, + )) + else: + self.prop_desc.set_text(item.desc) self.selected.button.state(('!alternate',)) self.selected = item @@ -1148,7 +1156,7 @@ def sel_item(self, item: Item, event=None): 'Invalid attribute type: "{}"'.format(label.type) ) - def key_navigate(self, event): + def key_navigate(self, event: Event): """Navigate using arrow keys. Allowed keys are set in NAV_KEYS From 8035154c39b4bb38a6566e99f3dcad887a355fce Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Sun, 27 Sep 2020 15:23:18 +1000 Subject: [PATCH 52/87] Pass along "development mode" setting to VBSP --- src/app/gameMan.py | 8 +++----- src/precomp/options.py | 5 +++++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/app/gameMan.py b/src/app/gameMan.py index a4998c6be..5f389e037 100644 --- a/src/app/gameMan.py +++ b/src/app/gameMan.py @@ -25,7 +25,7 @@ FileSystem, FileSystemChain, ) import srctools.logger -from app import backup, tk_tools, TK_ROOT +from app import backup, optionWindow, tk_tools, TK_ROOT import loadScreen import packageLoader import utils @@ -691,10 +691,8 @@ def export( export_screen.step('EXP') - vbsp_config.set_key( - ('Options', 'Game_ID'), - self.steamID, - ) + vbsp_config.set_key(('Options', 'Game_ID'), self.steamID) + vbsp_config.set_key(('Options', 'dev_mode'), optionWindow.DEV_MODE.get()) # If there are multiple of these blocks, merge them together. # They will end up in this order. diff --git a/src/precomp/options.py b/src/precomp/options.py index 37da51b42..18517b739 100644 --- a/src/precomp/options.py +++ b/src/precomp/options.py @@ -547,6 +547,11 @@ def dump_info(file: TextIO) -> None: ###### # The following are set by the BEE2.4 app automatically: + Opt('dev_mode', False, + """Whether 'development mode' is enabled in the app. + + This enables extra outputs for assisting with package development. + """), Opt('game_id', "620", """(Automatic) The game's steam ID. """), From e86f030f5011b75505c2b41299eafea0c7195fb1 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Mon, 12 Oct 2020 15:36:13 +1000 Subject: [PATCH 53/87] Fix circular import issues --- src/app/UI.py | 2 +- src/app/tagsPane.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/app/UI.py b/src/app/UI.py index 8d16452a2..4ab03de19 100644 --- a/src/app/UI.py +++ b/src/app/UI.py @@ -1656,7 +1656,7 @@ def init_drag_icon() -> None: drag_win.drag_item = None # the item currently being moved -def set_game(game: gameMan.Game): +def set_game(game: 'gameMan.Game'): """Callback for when the game is changed. This updates the title bar to match, and saves it into the config. diff --git a/src/app/tagsPane.py b/src/app/tagsPane.py index 7318241a5..794c79f77 100644 --- a/src/app/tagsPane.py +++ b/src/app/tagsPane.py @@ -86,9 +86,6 @@ def filter_items(): ) UI.flow_picker() -# When exiting settings, we need to hide/show WIP items. -optionWindow.refresh_callbacks.append(filter_items) - def expand(_): """Expand the filter view.""" @@ -148,6 +145,8 @@ def add_tag(section: Section, tag: str, pretty: str=None): def init(frm): """Initialise the UI objects.""" + # When exiting settings, we need to hide/show WIP items. + optionWindow.refresh_callbacks.append(filter_items) frm.bind('', expand) frm.bind('', contract) From a80deac19e31b4b8b7fb1637bc0c36924aaa187b Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Fri, 16 Oct 2020 16:28:05 +1000 Subject: [PATCH 54/87] Update PyInstaller to 4.0, remove unnecessary explicit data file specification in spec file This is now specified in the srctools module directly --- requirements.txt | 2 +- src/BEE2.spec | 21 --------------------- src/compiler.spec | 35 +---------------------------------- 3 files changed, 2 insertions(+), 56 deletions(-) diff --git a/requirements.txt b/requirements.txt index df0d5c728..ea67f62c4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,6 +4,6 @@ importlib-resources==1.0.1 Markdown==3.2.2 Pillow==7.2.0 pyglet==1.5.7 -PyInstaller==3.6 +PyInstaller==4.0 typing==3.7.4.1 typing-extensions==3.7.4.2 diff --git a/src/BEE2.spec b/src/BEE2.spec index 4123fb62e..2bb0abde4 100644 --- a/src/BEE2.spec +++ b/src/BEE2.spec @@ -19,11 +19,6 @@ data_files = [ ('../images/BEE2/*.png', 'images/BEE2/'), ('../images/icons/*.png', 'images/icons/'), ('../images/splash_screen/*.jpg', 'images/splash_screen/'), - - # Add the FGD data for us. - (os.path.join(srctools.__path__[0], 'fgd.lzma'), 'srctools'), - (os.path.join(srctools.__path__[0], 'srctools.fgd'), 'srctools'), - ] @@ -148,8 +143,6 @@ EXCLUDES = [ 'argparse', ] -block_cipher = None - # AVbin is needed to read OGG files. INCLUDE_PATHS = [ @@ -186,18 +179,6 @@ for snd in os.listdir('../sounds/'): data_files.append(('../sounds/' + snd, 'sounds')) -# We need to include this version data. -try: - import importlib_resources - data_files.append( - ( - os.path.join(importlib_resources.__path__[0], 'version.txt'), - 'importlib_resources', - ) - ) -except ImportError: - pass - # Finally, run the PyInstaller analysis process. bee2_a = Analysis( @@ -213,7 +194,6 @@ bee2_a = Analysis( excludes=EXCLUDES, win_no_prefer_redirects=False, win_private_assemblies=False, - cipher=block_cipher, noarchive=False ) @@ -227,7 +207,6 @@ bee2_a.datas.append(( pyz = PYZ( bee2_a.pure, bee2_a.zipped_data, - cipher=block_cipher ) exe = EXE( diff --git a/src/compiler.spec b/src/compiler.spec index dd651bcc1..5abb408d0 100644 --- a/src/compiler.spec +++ b/src/compiler.spec @@ -19,17 +19,6 @@ else: suffix = '' -# src -> build subfolder. -data_files = [ - # Add the FGD data for us. - (os.path.join(srctools.__path__[0], 'fgd.lzma'), 'srctools'), - (os.path.join(srctools.__path__[0], 'srctools.fgd'), 'srctools'), - -] - -block_cipher = None - - # Unneeded packages that cx_freeze detects: EXCLUDES = [ 'argparse', # Used in __main__ of some modules @@ -111,43 +100,21 @@ if version_val: with open(version_filename, 'w') as f: f.write(version_val) -# We need to include this version data. -try: - import importlib_resources - data_files.append( - ( - os.path.join(importlib_resources.__path__[0], 'version.txt'), - 'importlib_resources', - ) - ) -except ImportError: - pass - -print('Data files: ') -print(data_files) - # Finally, run the PyInstaller analysis process. -# from PyInstaller.building.build_main import Analysis, PYZ, EXE, COLLECT +from PyInstaller.building.build_main import Analysis, PYZ, EXE, COLLECT vbsp_vrad_an = Analysis( ['compiler_launch.py'], pathex=[workpath, os.path.dirname(srctools.__path__[0])], binaries=[], - datas=data_files, hiddenimports=INCLUDES, - hookspath=[], - runtime_hooks=[], excludes=EXCLUDES, - win_no_prefer_redirects=False, - win_private_assemblies=False, - cipher=block_cipher, noarchive=False ) pyz = PYZ( vbsp_vrad_an.pure, vbsp_vrad_an.zipped_data, - cipher=block_cipher ) vbsp_exe = EXE( From db38d5c1aa15e7969219830c7e6895c8d9e62984 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Fri, 16 Oct 2020 18:34:35 +1000 Subject: [PATCH 55/87] Use a more typesafe WeakKeyDictionary instead of a private attribute --- src/precomp/cubes.py | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/precomp/cubes.py b/src/precomp/cubes.py index 7b4b34e1d..3fe7b9c1e 100644 --- a/src/precomp/cubes.py +++ b/src/precomp/cubes.py @@ -3,6 +3,7 @@ import itertools from contextlib import suppress from collections import namedtuple +from weakref import WeakKeyDictionary from enum import Enum from typing import Dict, Optional, List, Union, Tuple, Set, FrozenSet, Iterable @@ -29,7 +30,8 @@ ADDON_TYPES = {} # type: Dict[str, CubeAddon] # All the cubes/droppers -PAIRS = [] # type: List[CubePair] +PAIRS: List['CubePair'] = [] +INST_TO_PAIR: Dict[Entity, 'CubePair'] = WeakKeyDictionary() # Distance from the floor to the bottom of dropperless cubes. # That's needed for light bridges and things like that. @@ -530,13 +532,12 @@ def __init__( for out in cube_type.base_outputs[out_type] ] - # Write ourselves into the entities to allow retrieving this - # from them, and also via origin. + # Ensure we can look up the pair by origin and instance. if dropper is not None: - dropper.bee2_cube_data = self + INST_TO_PAIR[dropper] = self CUBE_POS[Vec.from_str(dropper['origin']).as_tuple()] = self if cube is not None: - cube.bee2_cube_data = self + INST_TO_PAIR[cube] = self CUBE_POS[Vec.from_str(cube['origin']).as_tuple()] = self # Cache of comp_kv_setters adding outputs to dropper ents. @@ -873,8 +874,8 @@ def flag_cube_type(inst: Entity, res: Property): * ``: The cube half of a pair. """ try: - pair = inst.bee2_cube_data # type: CubePair - except AttributeError: + pair = INST_TO_PAIR[inst] + except KeyError: # None checks for if the instance *isn't* a cube. return res.value.casefold() == '' @@ -913,8 +914,8 @@ def flag_dropper_color(inst: Entity, res: Property): which will have the tint copied into it. """ try: - data = inst.bee2_cube_data # type: CubePair - except AttributeError: + data = INST_TO_PAIR[inst] + except KeyError: return False if res.value: @@ -932,8 +933,8 @@ def res_dropper_addon(inst: Entity, res: Property): raise ValueError('Invalid Cube Addon: {}'.format(res.value)) try: - pair = inst.bee2_cube_data # type: CubePair - except AttributeError: + pair = INST_TO_PAIR[inst] + except KeyError: LOGGER.warning('Cube Addon applied to non cube ("{}")', res.value) return @@ -944,8 +945,8 @@ def res_dropper_addon(inst: Entity, res: Property): def res_set_dropper_off(inst: Entity, res: Property) -> None: """Update the position cubes will be spawned at for a dropper.""" try: - pair = inst.bee2_cube_data # type: CubePair - except AttributeError: + pair = INST_TO_PAIR[inst] + except KeyError: LOGGER.warning('SetDropperOffset applied to non cube ("{}")', res.value) else: pair.spawn_offset = Vec.from_str( @@ -960,8 +961,8 @@ def flag_cube_type(inst: Entity, res: Property): marked as a custom dropperless cube. """ try: - pair = inst.bee2_cube_data # type: CubePair - except AttributeError: + pair = INST_TO_PAIR[inst] + except KeyError: LOGGER.warning('Attempting to set cube type on non cube ("{}")', inst['targetname']) return From 981c6b443f0b051c9436a07526aaea8b4f707323 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Fri, 16 Oct 2020 18:37:01 +1000 Subject: [PATCH 56/87] Add a more accurate list of the skins used by each cube type. --- src/precomp/cubes.py | 82 +++++++++++++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 20 deletions(-) diff --git a/src/precomp/cubes.py b/src/precomp/cubes.py index 3fe7b9c1e..2079b727e 100644 --- a/src/precomp/cubes.py +++ b/src/precomp/cubes.py @@ -6,7 +6,10 @@ from weakref import WeakKeyDictionary from enum import Enum -from typing import Dict, Optional, List, Union, Tuple, Set, FrozenSet, Iterable +from typing import ( + Optional, Union, Tuple, NamedTuple, + Dict, List, Set, FrozenSet, Iterable, +) from precomp import brushLoc, options, packing, conditions from precomp.conditions import meta_cond, make_result, make_flag, RES_EXHAUSTED @@ -164,25 +167,64 @@ class CubePaintType(Enum): BOUNCE = 0 SPEED = 2 -# The skin used for a cube type and gel. -CUBE_SKINS = { - (None, CubeEntType.norm): '0', - (None, CubeEntType.comp): '1', - (None, CubeEntType.reflect): '0', - (None, CubeEntType.sphere): '0', - (None, CubeEntType.antique): '0', - - (CubePaintType.BOUNCE, CubeEntType.norm): '6', - (CubePaintType.BOUNCE, CubeEntType.comp): '8', - (CubePaintType.BOUNCE, CubeEntType.reflect): '2', - (CubePaintType.BOUNCE, CubeEntType.sphere): '2', - (CubePaintType.BOUNCE, CubeEntType.antique): '1', - - (CubePaintType.SPEED, CubeEntType.norm): '7', - (CubePaintType.SPEED, CubeEntType.comp): '9', - (CubePaintType.SPEED, CubeEntType.reflect): '3', - (CubePaintType.SPEED, CubeEntType.sphere): '3', - (CubePaintType.SPEED, CubeEntType.antique): '2', + +class CubeSkins(NamedTuple): + """Specifies the various skins present for cubes. + + For each, the first is the off skin, the second is the on skin. + """ + clean: Tuple[int, int] + rusty: Optional[Tuple[int, int]] + bounce: Tuple[int, int] + speed: Tuple[int, int] + + def spawn_skin(self, paint: Optional[CubePaintType]) -> int: + """Return the skin this paint would spawn with.""" + if paint is None: + return self.clean[0] + elif paint is CubePaintType.BOUNCE: + return self.bounce[0] + elif paint is CubePaintType.SPEED: + return self.speed[0] + raise AssertionError(f"Unknown value: {paint}") + + +# (paint, type and rusty) -> off, on skins. +CUBE_SKINS: Dict[CubeEntType, CubeSkins] = { + CubeEntType.norm: CubeSkins( + clean=(0, 2), + rusty=(3, 5), + bounce=(6, 10), + speed=(7, 11), + ), + CubeEntType.comp: CubeSkins( + clean=(1, 4), + rusty=None, + # On-painted skins are actually normal! + # Not really noticeable though, so don't bother + # fixing. + bounce=(8, 10), + speed=(9, 11), + ), + CubeEntType.reflect: CubeSkins( + clean=(0, 0), + rusty=(1, 1), + bounce=(2, 2), + speed=(3, 3), + # 4-6 are for Schrodinger... + ), + CubeEntType.sphere: CubeSkins( + clean=(0, 1), + rusty=None, + bounce=(2, 2), + speed=(3, 3), + ), + CubeEntType.antique: CubeSkins( + clean=(0, 0), + rusty=None, + bounce=(1, 1), + speed=(2, 2), + ), } From 60b5e74788096d5863f2e6fe4d96f164f1f177db Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Fri, 16 Oct 2020 18:37:42 +1000 Subject: [PATCH 57/87] If possible, switch cubes to the rusty version to skip using custom resources. --- src/precomp/cubes.py | 68 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 57 insertions(+), 11 deletions(-) diff --git a/src/precomp/cubes.py b/src/precomp/cubes.py index 2079b727e..3c83fca25 100644 --- a/src/precomp/cubes.py +++ b/src/precomp/cubes.py @@ -171,6 +171,9 @@ class CubePaintType(Enum): class CubeSkins(NamedTuple): """Specifies the various skins present for cubes. + Rusty skins are only applicable if the map doesn't contain gels, since + all of the cube types have one or more bad gel skins. If None, there's + no rusty version. For each, the first is the off skin, the second is the on skin. """ clean: Tuple[int, int] @@ -369,6 +372,7 @@ def __init__( has_name: str, cube_item_id: str, is_companion: bool, + try_rusty: bool, model: Optional[str], model_color: Optional[str], model_swap_meth: ModelSwapMeth, @@ -408,6 +412,9 @@ def __init__( # Conceptually - is it 'companion'-like -> voiceline self.is_companion = is_companion + # If true, use the original model and rusty skin type if no gels are + # present. + self.try_rusty = try_rusty # Distance from model origin to the 'floor'. self.base_offset = base_offset @@ -486,6 +493,7 @@ def parse(cls, conf: Property): conf['hasName'], cube_item_id, cube_type is CubeEntType.comp or conf.bool('isCompanion'), + conf.bool('tryRusty'), cust_model, cust_model_color, model_swap_meth, @@ -597,6 +605,20 @@ def __repr__(self) -> str: drop_id, self.cube_type.id, drop, cube, self.tint, ) + def use_rusty_version(self, has_gel: bool): + """Check if we can can use the rusty version. + + This is only allowed if it's one of Valve's cubes, + no color is used, and no gels are present. + In this case, we ignore the custom model. + """ + return ( + self.cube_type.try_rusty and + self.paint_type is None and + self.tint is None and + CUBE_SKINS[self.cube_type].rusty is not None + ) + def get_kv_setter(self, name: str) -> Entity: """Get a KV setter setting this dropper-local name, creating if required.""" name = conditions.local_name(self.dropper, name) @@ -1404,6 +1426,8 @@ def make_cube( pair: CubePair, floor_pos: Vec, in_dropper: bool, + bounce_in_map: bool, + speed_in_map: bool, ) -> Tuple[bool, Entity]: """Place a cube on the specified floor location. @@ -1589,10 +1613,26 @@ def make_cube( ent['AllowSilentDissolve'] = 1 else: # A prop_weighted_cube - ent['NewSkins'] = '1' - ent['SkinType'] = '0' - ent['Skin'] = CUBE_SKINS[spawn_paint, pair.cube_type.type] + + skin = CUBE_SKINS[pair.cube_type.type] + skinset: Set[int] = set() + + if pair.use_rusty_version(bounce_in_map or speed_in_map): + ent['SkinType'] = '1' + ent['Skin'] = skin.rusty[0] + skinset.update(skin.rusty) + cust_model = None + else: + ent['SkinType'] = '0' + ent['Skin'] = skin.spawn_skin(spawn_paint) + skinset.update(skin.clean) + if bounce_in_map or spawn_paint is CubePaintType.BOUNCE: + skinset.update(skin.bounce) + if speed_in_map or spawn_paint is CubePaintType.BOUNCE: + skinset.update(skin.speed) + + ent['skinset'] = ' '.join(map(str, sorted(skinset))) ent['angles'] = Vec(0, yaw, 0) # If in droppers, disable portal funnelling until it falls out. ent['AllowFunnel'] = not in_dropper @@ -1636,6 +1676,10 @@ def make_cube( @meta_cond(priority=750, only_once=True) def generate_cubes(vmf: VMF): """After other conditions are run, generate cubes.""" + from vbsp import settings + voice_attr = settings['has_attr'] # type: Dict[str, bool] + bounce_in_map = voice_attr['BounceGel'] + speed_in_map = voice_attr['SpeedGel'] # point_template for spawning dropperless cubes. # We can fit 16 in each, start with the count = 16 so @@ -1644,12 +1688,15 @@ def generate_cubes(vmf: VMF): dropperless_temp_count = 16 for pair in PAIRS: - # Don't include the cube entity. + # Don't include the original cube instance. if pair.cube: pair.cube.remove() - if pair.cube_type.model_swap_meth is ModelSwapMeth.SETMODEL: - # Add the custom model logic. + # Add the custom model logic. But skip if we use the rusty version. + # That overrides it to be using the normal model. + if (pair.cube_type.model_swap_meth is ModelSwapMeth.SETMODEL + and not pair.use_rusty_version(bounce_in_map or speed_in_map) + ): cust_model = ( pair.cube_type.model_color if pair.tint is not None else @@ -1657,8 +1704,7 @@ def generate_cubes(vmf: VMF): ) if cust_model: # Fire an on-spawn output that swaps the model, - # then resets the skin. - + # then resets the skin to the right one. # If we have a bounce cube painter, it needs to be the normal skin. if ( pair.paint_type is CubePaintType.BOUNCE and @@ -1673,7 +1719,7 @@ def generate_cubes(vmf: VMF): 'self.SetModel(`{}`); ' 'self.__KeyValueFromInt(`skin`, {});'.format( cust_model, - CUBE_SKINS[spawn_paint, pair.cube_type.type], + CUBE_SKINS[pair.cube_type.type].spawn_skin(spawn_paint), ), )) precache_model(vmf, cust_model) @@ -1709,7 +1755,7 @@ def generate_cubes(vmf: VMF): assert pair.drop_type is not None pos = Vec.from_str(pair.dropper['origin']) pos += pair.spawn_offset.copy().rotate_by_str(pair.dropper['angles']) - has_addon, drop_cube = make_cube(vmf, pair, pos, True) + has_addon, drop_cube = make_cube(vmf, pair, pos, True, bounce_in_map, speed_in_map) cubes.append(drop_cube) # We can't refer to the dropped cube directly because of the template name @@ -1813,7 +1859,7 @@ def generate_cubes(vmf: VMF): if pair.cube: pos = Vec.from_str(pair.cube['origin']) pos += Vec(z=DROPPERLESS_OFFSET).rotate_by_str(pair.cube['angles']) - has_addon, cube = make_cube(vmf, pair, pos, False) + has_addon, cube = make_cube(vmf, pair, pos, False, bounce_in_map, speed_in_map) cubes.append(cube) cube_name = cube['targetname'] = conditions.local_name(pair.cube, 'box') From 3c184abcf894aac56253de83d5851ae8aa46726d Mon Sep 17 00:00:00 2001 From: David Losantos <48654552+L89David@users.noreply.github.com> Date: Sun, 18 Oct 2020 21:29:49 +0200 Subject: [PATCH 58/87] Improved Spanish Translation --- i18n/es.po | 274 +++++++++++++++++++++++++++++------------------------ 1 file changed, 150 insertions(+), 124 deletions(-) diff --git a/i18n/es.po b/i18n/es.po index 1c1744c40..d463bdaa3 100644 --- a/i18n/es.po +++ b/i18n/es.po @@ -16,7 +16,7 @@ msgstr "" #: CheckDetails.py:220 msgid "Toggle all checkboxes." -msgstr "Activar todas las casillas." +msgstr "Alternar todas las casillas." #: CompilerPane.py:66 msgid "ATLAS" @@ -80,21 +80,24 @@ msgstr "Pasillo" msgid "" "Randomly choose a corridor. This is saved in the puzzle data and will not" " change." -msgstr "" +msgstr "Seleccionar un pasillo de forma aleatoria. Esto es guardado en los" +" datos del puzzle y no cambiará." #: CompilerPane.py:322 UI.py:657 msgid "Random" -msgstr "" +msgstr "Aleatorio" #: CompilerPane.py:421 msgid "Image Files" -msgstr "Archivos de imagenes" +msgstr "Archivos de Imagenes" #: CompilerPane.py:504 msgid "" "Options on this panel can be changed \n" "without exporting or restarting the game." -msgstr "" +msgstr "Las opciones en este panel se pueden" +" cambiar sin hacer falta exportar o reiniciar" +" el juego." #: CompilerPane.py:519 msgid "Map Settings" @@ -118,11 +121,11 @@ msgstr "PeTI" #: CompilerPane.py:562 msgid "Custom:" -msgstr "Personalizada:" +msgstr "Personalizado:" #: CompilerPane.py:580 msgid "Cleanup old screenshots" -msgstr "Limpiar viejas capturas de pantalla" +msgstr "Eliminar capturas de pantalla antiguas" #: CompilerPane.py:590 msgid "" @@ -180,8 +183,8 @@ msgid "" msgstr "" "Compila con inferior calidad de iluminación. Esto acelera los tiempos de " "compilación, pero no luce bien. Algunas sombras pueden parecer " -"incorrectas. En el momento que se publica el mapa, esta opción no será " -"tenida en cuenta." +"incorrectas. En el momento que se publica el mapa, esta opción no se " +"tendrá en cuenta." #: CompilerPane.py:657 #, fuzzy @@ -197,14 +200,14 @@ msgstr "" #: CompilerPane.py:664 msgid "Dump packed files to:" -msgstr "Envíar archivos empacados a:" +msgstr "Volcar archivos empacados a:" #: CompilerPane.py:689 msgid "" "When compiling, dump all files which were packed into the map. Useful if " "you're intending to edit maps in Hammer." msgstr "" -"Al momento en que se compila el mapa, envía todos los archivos que fueron" +"Al momento en que se compila el mapa, vuelca todos los archivos que fueron" " empacados dentro del mapa. Útil si tienes la intención de editar los " "mapas en Hammer." @@ -214,7 +217,7 @@ msgstr "Última Compilación:" #: CompilerPane.py:705 msgid "Entity" -msgstr "Entidades" +msgstr "Entidad" #: CompilerPane.py:725 msgid "Overlay" @@ -231,7 +234,7 @@ msgstr "" #: CompilerPane.py:750 msgid "Brush" -msgstr "" +msgstr "Bloque" #: CompilerPane.py:778 msgid "Voicelines:" @@ -374,7 +377,7 @@ msgstr "" #: StyleVarPane.py:74 msgid "Light Reversible Excursion Funnels" -msgstr "" +msgstr "Iluminar Embudos de translación reversibles" #: StyleVarPane.py:76 msgid "" @@ -382,17 +385,22 @@ msgid "" "near each other and can reverse polarity, this can cause lighting issues." " Disable this to prevent that by disabling lights. Non-reversible Funnels" " do not have this issue." -msgstr "" +msgstr "Los embudos de translación emiten una pequeña cantidad de luz. " +"Aunque, si hay múltiples embudos de translación cerca de otros que puedan" +" revertir su polaridad, la iluminación podría verse afectada." +"Deshabilita esto para prevenir esto desabilitando las luces. Los embudos" +" de translación no reversibles no tienen este problema." #: StyleVarPane.py:84 msgid "Enable Shape Framing" -msgstr "" +msgstr "Habilitar el encuadre de formas" #: StyleVarPane.py:86 msgid "" "After 10 shape-type antlines are used, the signs repeat. With this " "enabled, colored frames will be added to distinguish them." -msgstr "" +msgstr "Después de usar 10 indicador de forma, los carteles se repiten." +" Con esto activado, se añadirán marcos coloreados para poder distingirlos." #: StyleVarPane.py:155 msgid "Default: On" @@ -414,20 +422,20 @@ msgstr "Estilos: Todos" msgid "Style: {}" msgid_plural "Styles: {}" msgstr[0] "Estilo: {}" -msgstr[1] "Plural: Estilos: {}" +msgstr[1] "Estilos: {}" #: StyleVarPane.py:233 #, fuzzy msgid "Style/Item Properties" -msgstr "Propiedades de Estilo" +msgstr "Propiedades de Estilo/ítem" #: StyleVarPane.py:252 msgid "Styles" -msgstr "" +msgstr "Estilos" #: StyleVarPane.py:271 msgid "All:" -msgstr "En todos:" +msgstr "Todos:" #: StyleVarPane.py:274 msgid "Selected Style:" @@ -443,11 +451,11 @@ msgstr "Sin Opciones!" #: StyleVarPane.py:293 msgid "None!" -msgstr "Ninguna!" +msgstr "Ninguno!" #: StyleVarPane.py:364 msgid "Items" -msgstr "" +msgstr "Ítems" #: SubPane.py:84 msgid "Hide/Show the \"{}\" window." @@ -470,16 +478,16 @@ msgstr "" "El skybox decide el tipo de apariencia que tendrán ciertos sectores " "vistos fuera de una cámara de pruebas, como puede ser el caso de un techo" " abierto. Esto incluye el color del cielo, el estilo de los grandes " -"precipicios, así como el color de la \"neblina\" vistos en las cámaras " +"precipicios, así como el color de la \"niebla\" vistos en las cámaras " "largas." #: UI.py:600 msgid "3D Skybox" -msgstr "3D Skybox" +msgstr "Skybox 3D" #: UI.py:601 msgid "Fog Color" -msgstr "Color de Neblina" +msgstr "Color de Niebla" #: UI.py:608 msgid "Select Additional Voice Lines" @@ -499,7 +507,7 @@ msgstr "" #: UI.py:614 msgid "Add no extra voice lines, only Multiverse Cave if enabled." -msgstr "No añadir voces de línea adicionales, only Multiverse Cave if enabled." +msgstr "No añadir voces de línea adicionales, sólo Cave (Workshop)." #: UI.py:616 msgid "" @@ -507,15 +515,15 @@ msgstr "" #: UI.py:620 msgid "Characters" -msgstr "Caracteres" +msgstr "Personajes" #: UI.py:621 msgid "Turret Shoot Monitor" -msgstr "" +msgstr "Monitor de Disparos de Torreta" #: UI.py:622 msgid "Monitor Visuals" -msgstr "" +msgstr "Visuales de Monitor" #: UI.py:629 msgid "Select Style" @@ -539,7 +547,7 @@ msgstr "" #: UI.py:641 msgid "Elevator Videos" -msgstr "Videos del elevador" +msgstr "Videos del Elevador" #: UI.py:648 msgid "Select Elevator Video" @@ -562,7 +570,7 @@ msgstr "Este estilo no cuenta con una pantalla en el elevador." #: UI.py:658 msgid "Choose a random video." -msgstr "Se elegirá un video aleatorio." +msgstr "Elegir un video aleatorio." #: UI.py:662 msgid "Multiple Orientations" @@ -579,12 +587,18 @@ msgid "" "Warning: VPK files were not exported, quit Portal 2 and Hammer to ensure " "editor wall previews are changed." msgstr "" +"\n" +"\n" +"Atención: Los archivos VPK no han sido exportados. Cierre Portal 2 y Hammer" +" para asegurarse de que las vistas previas de las paredes del editor han cambiado." #: UI.py:898 msgid "" "\n" " Launch Game?" msgstr "" +"\n" +" ¿Ejecutar Juego?" #: UI.py:1113 msgid "Delete Palette \"{}\"" @@ -596,19 +610,19 @@ msgstr "BEE2 - Guardar Paleta" #: UI.py:1190 msgid "Enter a name:" -msgstr "" +msgstr "Introduzca un nombre:" #: UI.py:1199 msgid "This palette already exists. Overwrite?" -msgstr "Esta paleta ya existe. Desea reemplazarla?" +msgstr "Esta paleta ya existe. ¿Desea reemplazarla?" #: UI.py:1228 gameMan.py:1529 msgid "Are you sure you want to delete \"{}\"?" -msgstr "Estas seguro que deseas borrar \"{}?\"" +msgstr "¿Estas seguro que deseas borrar \"{}\"?" #: UI.py:1255 msgid "Clear Palette" -msgstr "Limpiar la Paleta" +msgstr "Vaciar la Paleta" #: UI.py:1291 UI.py:1727 msgid "Delete Palette" @@ -624,7 +638,7 @@ msgstr "Guardar Paleta Como..." #: UI.py:1327 UI.py:1738 msgid "Save Settings in Palettes" -msgstr "" +msgstr "Guardar Ajustes en las Paletas" #: UI.py:1345 music_conf.py:204 msgid "Music: " @@ -636,33 +650,34 @@ msgstr "{arr} Usar Recomendado {arr}" #: UI.py:1387 msgid "Style: " -msgstr "Estilo:" +msgstr "Estilo: " #: UI.py:1389 msgid "Voice: " -msgstr "Voz:" +msgstr "Voz: " #: UI.py:1390 msgid "Skybox: " -msgstr "Skybox:" +msgstr "Skybox: " #: UI.py:1391 msgid "Elev Vid: " -msgstr "Vid Elev" +msgstr "Vid Elev: " #: UI.py:1409 msgid "" "Enable or disable particular voice lines, to prevent them from being " "added." -msgstr "Habilita o deshabilita ciertas lineas de voces." +msgstr "Habilita o deshabilita ciertas lineas de voces, para prevenir" +" que sean añadidas." #: UI.py:1512 msgid "All Items: " -msgstr "Todos los Elementos:" +msgstr "Todos los Elementos: " #: UI.py:1646 msgid "Export to \"{}\"..." -msgstr "" +msgstr "Exportar a \"{}\"..." #: UI.py:1674 backup.py:876 msgid "File" @@ -679,7 +694,7 @@ msgstr "Añadir Juego" #: UI.py:1692 #, fuzzy msgid "Uninstall from Selected Game" -msgstr "Borrar Juego Seleccionado" +msgstr "Borrar del Juego Seleccionado" #: UI.py:1696 msgid "Backup/Restore Puzzles..." @@ -695,7 +710,7 @@ msgstr "Ociones" #: UI.py:1710 gameMan.py:1208 msgid "Quit" -msgstr "Quitar" +msgstr "Salir" #: UI.py:1720 msgid "Palette" @@ -715,11 +730,11 @@ msgstr "Guardar Paleta" #: UI.py:1760 msgid "View" -msgstr "" +msgstr "Ver" #: UI.py:1879 msgid "Palettes" -msgstr "" +msgstr "Paletas" #: UI.py:1904 msgid "Export Options" @@ -739,11 +754,11 @@ msgstr "Cargando mapas" #: backup.py:91 msgid "Deleting maps" -msgstr "" +msgstr "Eliminando mapas" #: backup.py:142 msgid "Failed to parse this puzzle file. It can still be backed up." -msgstr "Error al analizar este mapa. Pero es posible hacer una copia de seguridad." +msgstr "Error al analizar este mapa. Sigue siendo posible hacer una copia de seguridad." #: backup.py:146 msgid "No description found." @@ -765,11 +780,11 @@ msgstr "" #: backup.py:445 msgid "BEE2 Backup" -msgstr "BEE2 Copia de seguridad" +msgstr "Copia de seguridad de BEE2" #: backup.py:446 msgid "No maps were chosen to backup!" -msgstr "No se ha elegido ningún mapa para realizar copias de seguridad!" +msgstr "¡No se ha elegido ningún mapa para realizar copias de seguridad!" #: backup.py:506 msgid "" @@ -791,17 +806,17 @@ msgstr "Copia de seguridad no guardada" #: backup.py:627 backup.py:874 msgid "Save Backup As" -msgstr "Guardar Copia de Seguridad como" +msgstr "Guardar Copia de Seguridad Como" #: backup.py:724 msgid "Confirm Deletion" -msgstr "" +msgstr "Confirmar Eliminación" #: backup.py:725 msgid "Do you wish to delete {} map?\n" msgid_plural "Do you wish to delete {} maps?\n" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "¿Desea eliminar {} mapa?\n" +msgstr[1] "¿Desea eliminar {} mapas?\n" #: backup.py:762 msgid "Restore:" @@ -817,7 +832,7 @@ msgstr "Marcado" #: backup.py:808 msgid "Delete Checked" -msgstr "Eliminar marcado" +msgstr "Eliminar marcados" #: backup.py:858 msgid "BEEMOD {} - Backup / Restore Puzzles" @@ -845,7 +860,7 @@ msgstr "Juego" #: backup.py:930 msgid "Automatic Backup After Export" -msgstr "Crear una Copia de Seguridad automáticamente luego de exportar" +msgstr "Crear una Copia de Seguridad automáticamente después de exportar" #: backup.py:962 msgid "Keep (Per Game):" @@ -881,7 +896,7 @@ msgstr "Este elemento se puede rotar en el piso para hacer frente a 360 grados." #: contextWin.py:85 msgid "This item is positioned using a catapult trajectory." -msgstr "Este elemento se posiciona mediante la trayectoria de salto de fe." +msgstr "Este elemento se posiciona mediante la trayectoria de la plataforma de salto." #: contextWin.py:86 msgid "This item positions the dropper to hit target locations." @@ -899,7 +914,8 @@ msgstr "Este elemento acepta conexiones entrantes." #: contextWin.py:90 msgid "This item has two input types (A and B), using the Input A and B items." -msgstr "" +msgstr "Este ítem tiene dos tipos de entrada (A y B), usando los ítems de" +" Entrada A y Entrada B." #: contextWin.py:92 msgid "This item does not output." @@ -935,7 +951,7 @@ msgstr "Este elemento solo puede ser colocado en el suelo." #: contextWin.py:102 msgid "This item can be placed on floors and ceilings." -msgstr "Este elemento puede ser colocado en los techos y el piso." +msgstr "Este elemento puede ser colocado en los techos y el suelo." #: contextWin.py:103 msgid "This item can be placed on walls only." @@ -947,21 +963,21 @@ msgstr "Este elemento puede ser colocado en las paredes y los techos." #: contextWin.py:105 msgid "This item can be placed on floors and walls." -msgstr "Este elemento puede ser colocado en el piso y las paredes." +msgstr "Este elemento puede ser colocado en el suelo y las paredes." #: contextWin.py:106 msgid "This item can be placed in any orientation." -msgstr "Este elemento puede ser colocado en el piso, paredes y techos." +msgstr "Este elemento puede ser colocado en el suelo, paredes y techos." #: contextWin.py:212 #, fuzzy msgid "No Alternate Versions" -msgstr "¡No hay otras versiones!" +msgstr "No hay otras versiones" #: contextWin.py:304 msgid "Excursion Funnels accept a on/off input and a directional input." msgstr "" -"Los Rayos Tractores aceptan una conexión de activación/desactivación, así" +"Los embudos de translación aceptan una conexión de activación/desactivación, así" " como una conexión direccional." #: contextWin.py:361 @@ -974,7 +990,7 @@ msgstr "Este elemento se puede rotar en el piso para hacer frente a 360 grados." #: contextWin.py:440 #, fuzzy msgid "Properties:" -msgstr "Propiedades" +msgstr "Propiedades:" #: contextWin.py:462 msgid "" @@ -996,15 +1012,15 @@ msgid "" " clipboard instead?" msgstr "" "Error al abrir un navegador web. ¿Desea que la URL sea copiada en el " -"Portapapeles?" +"portapapeles?" #: contextWin.py:544 msgid "More Info>>" -msgstr "" +msgstr "Más Info>>" #: contextWin.py:561 msgid "Change Defaults..." -msgstr "Cambiar Predeterminación" +msgstr "Cambiar Ajustes por Defecto..." #: contextWin.py:567 msgid "Change the default settings for this item when placed." @@ -1020,24 +1036,28 @@ msgstr "BEE2 - ¡Exportación Fallida!" msgid "" "Compiler file {file} missing. Exit Steam applications, then press OK to " "verify your game cache. You can then export again." -msgstr "" +msgstr "Falta archivo de compilador {file}. Salga de las aplicaciones de Steam," +" y pulse OK para verificar la integridad de los archivos. Después, podrás " +"exportar de nuevo." #: gameMan.py:853 #, fuzzy msgid "Copying compiler file {file} failed. Ensure {game} is not running." msgstr "" -"Copiando archivo del compilador {file} ha fallado. Asegurese de que el " +"Fallo a la hora de copiar el archivo de compilador {file}. Asegurese de que " "{game} no esta abierto.\n" #: gameMan.py:1265 msgid "" "Ap-Tag Coop gun instance not found!\n" "Coop guns will not work - verify cache to fix." -msgstr "" +msgstr "¡No se ha encontrado la instancia de la pistola de Ap-Tag de Coop!\n" +"Las pistolas del Coop no funcionarán. Verifique la integridad de los" +" archivos para reparar el error." #: gameMan.py:1269 msgid "BEE2 - Aperture Tag Files Missing" -msgstr "" +msgstr "BEE2 - Falta de archivos de Aperture Tag" #: gameMan.py:1452 msgid "Select the folder where the game executable is located ({appname})..." @@ -1060,23 +1080,23 @@ msgstr "Ejecutable" #: gameMan.py:1467 msgid "This does not appear to be a valid game folder!" -msgstr "Eso no parece ser un directorio de juego valido!" +msgstr "¡Eso no parece ser un directorio de juego valido!" #: gameMan.py:1477 msgid "Portal Stories: Mel doesn't have an editor!" -msgstr "" +msgstr "¡Portal Stories: Mel no tiene un editor!" #: gameMan.py:1488 msgid "Enter the name of this game:" -msgstr "Coloca el nombre de este juego:" +msgstr "Inserte el nombre de este juego:" #: gameMan.py:1495 msgid "This name is already taken!" -msgstr "Este nombre ya fue tomado!" +msgstr "¡Este nombre ya está en uso!" #: gameMan.py:1504 msgid "Please enter a name for this game!" -msgstr "Por favor colocale un nombre a este juego!" +msgstr "¡Por favor introduzca un nombre a este juego!" #: gameMan.py:1523 msgid "" @@ -1084,7 +1104,7 @@ msgid "" " (BEE2 will quit, this is the last game set!)" msgstr "" "\n" -"(BEE2 se cerrará, este es el último juego seleccionado!)" +" (BEE2 se cerrará, este es el último juego seleccionado!)" #: helpMenu.py:60 msgid "Wiki..." @@ -1092,11 +1112,11 @@ msgstr "" #: helpMenu.py:62 msgid "Original Items..." -msgstr "" +msgstr "Ítems Originales..." #: helpMenu.py:67 msgid "Discord Server..." -msgstr "" +msgstr "Servidor de Discord..." #: helpMenu.py:68 msgid "aerond's Music Changer..." @@ -1104,19 +1124,19 @@ msgstr "" #: helpMenu.py:70 msgid "Application Repository..." -msgstr "" +msgstr "Repositorio de la Aplicación" #: helpMenu.py:71 msgid "Items Repository..." -msgstr "" +msgstr "Repositorio de los Ítems..." #: helpMenu.py:73 msgid "Submit Application Bugs..." -msgstr "" +msgstr "Reportar errores de la aplicación..." #: helpMenu.py:74 msgid "Submit Item Bugs..." -msgstr "" +msgstr "Reportar errores de Ítems..." #: helpMenu.py:76 paletteLoader.py:35 msgid "Portal 2" @@ -1144,15 +1164,15 @@ msgstr "Ayuda" #: helpMenu.py:277 msgid "BEE2 Credits" -msgstr "" +msgstr "Créditos de BEE2" #: helpMenu.py:294 msgid "Credits..." -msgstr "" +msgstr "Créditos..." #: itemPropWin.py:43 msgid "Start Position" -msgstr "Posición de Entrada" +msgstr "Posición de Inicio" #: itemPropWin.py:44 msgid "End Position" @@ -1163,24 +1183,24 @@ msgid "" "Delay \n" "(0=infinite)" msgstr "" -"Ralentizar\n" +"Retraso\n" "(0=infinito)" #: itemPropWin.py:346 msgid "No Properties available!" -msgstr "No hay propiedades disponibles!" +msgstr "¡No hay propiedades disponibles!" #: itemconfig.py:621 msgid "Choose a Color" -msgstr "" +msgstr "Seleccione un color" #: loadScreen.py:199 msgid "Skipped!" -msgstr "Saltado!" +msgstr "¡Omitido!" #: loadScreen.py:200 msgid "Version: " -msgstr "" +msgstr "Versión: " #: loadScreen.py:201 optionWindow.py:252 packageMan.py:116 selectorWin.py:723 msgid "Cancel" @@ -1196,11 +1216,11 @@ msgstr "Cargando Objetos" #: loadScreen.py:213 msgid "Loading Images" -msgstr "Cargando Imagenes" +msgstr "Cargando Imágenes" #: loadScreen.py:214 msgid "Initialising UI" -msgstr "Iniciando Interfaz" +msgstr "Inicializando Interfaz" #: loadScreen.py:215 msgid "Better Extended Editor for Portal 2" @@ -1208,7 +1228,7 @@ msgstr "" #: logWindow.py:30 msgid "Debug messages" -msgstr "Mensajes de depuración" +msgstr "Mensajes de Depuración" #: logWindow.py:31 msgid "Default" @@ -1233,7 +1253,7 @@ msgstr "Mostrar:" #: music_conf.py:132 #, fuzzy msgid "Select Background Music - Base" -msgstr "Selecciona la música de fondo" +msgstr "Selecciona la música de fondo - Base" #: music_conf.py:133 #, fuzzy @@ -1470,18 +1490,20 @@ msgstr "" #: optionWindow.py:431 msgid "Log missing packfile resources" -msgstr "" +msgstr "Mostrar recursos packfile que faltan" #: optionWindow.py:432 msgid "" "Log when the resources a \"PackList\" refers to are not present in the " "zip. This may be fine (in a prerequisite zip), but it often indicates an " "error." -msgstr "" +msgstr "Mostrar cuando los recursos que \"PackList\" refiere no se encuentran" +" presentes en el zip. Esto puede estar bien (en un zip requerido), pero " +"normalmente indica un error." #: optionWindow.py:441 msgid "Preserve Game Directories" -msgstr "" +msgstr "Preservar Directorios del Juego" #: optionWindow.py:443 msgid "" @@ -1489,34 +1511,38 @@ msgid "" "\"bee2/\" and\n" "\"sdk_content/maps/bee2/\".\n" "Enable if you're developing new content, to ensure it is not overwritten." -msgstr "" +msgstr "Activar si estás desarrollando nuevo contenido, para asegurarse de" +" que no sea reemplazado." #: optionWindow.py:454 msgid "Show Log Window" -msgstr "" +msgstr "Mostrar la Ventana Log" #: optionWindow.py:456 msgid "Show the log file in real-time." -msgstr "" +msgstr "Mostrar el archivo log en tiempo real." #: optionWindow.py:463 msgid "Force Editor Models" -msgstr "" +msgstr "Forzar Modelos de Editor" #: optionWindow.py:464 msgid "" "Make all props_map_editor models available for use. Portal 2 has a limit " "of 1024 models loaded in memory at once, so we need to disable unused " "ones to free this up." -msgstr "" +msgstr "Hacer todos los modelos props_map_editor disponibles para uso. " +"Portal 2 tiene un límite the 1024 modelos cargados en memoria al mismo" +" tiempo, por lo que necesitamos desabilitar los no usados para liberar" +" memoria." #: optionWindow.py:475 msgid "Dump All objects" -msgstr "" +msgstr "Volcar TODOS los objectos" #: optionWindow.py:481 msgid "Dump Items list" -msgstr "" +msgstr "Lista de elementos volcados" #: packageMan.py:64 msgid "BEE2 - Restart Required!" @@ -1540,7 +1566,7 @@ msgstr "" #: paletteLoader.py:27 msgid "Blank" -msgstr "" +msgstr "Vacío" #: paletteLoader.py:30 msgid "BEEMod" @@ -1548,7 +1574,7 @@ msgstr "" #: paletteLoader.py:32 msgid "Portal 2 Collapsed" -msgstr "" +msgstr "Portal 2 Colapsado" #: richTextBox.py:153 msgid "Open \"{}\" in the default browser?" @@ -1560,7 +1586,7 @@ msgstr "No añadir nada." #: selectorWin.py:408 msgid "" -msgstr " " +msgstr "" #: selectorWin.py:585 selectorWin.py:590 msgid "Suggested" @@ -1568,11 +1594,11 @@ msgstr "Recomendado" #: selectorWin.py:638 msgid "Play a sample of this item." -msgstr "Dar una demostración de este elemento." +msgstr "Ver una demostración de este elemento." #: selectorWin.py:712 msgid "Reset to Default" -msgstr "Reiniciar a predeterminado." +msgstr "Restablecer a predeterminado." #: selectorWin.py:773 msgid "Other" @@ -1582,7 +1608,7 @@ msgstr "Otro" msgid "Author: {}" msgid_plural "Authors: {}" msgstr[0] "Autor: {}" -msgstr[1] "Plural: Autores: {}" +msgstr[1] "Autores: {}" #: selectorWin.py:1142 msgid "Color: R={r}, G={g}, B={b}" @@ -1590,16 +1616,16 @@ msgstr "Color: R={r}, G={g}, B={b} " #: signage_ui.py:140 signage_ui.py:213 msgid "Configure Signage" -msgstr "" +msgstr "Configurar Cartel" #: signage_ui.py:144 #, fuzzy msgid "Selected" -msgstr "Estilo seleccionado:" +msgstr "Seleccionado:" #: signage_ui.py:167 msgid "Signage: {}" -msgstr "" +msgstr "Cartel: {}" #: tagsPane.py:51 msgid "Tags" @@ -1611,15 +1637,15 @@ msgstr "Autores" #: tagsPane.py:162 msgid "Any" -msgstr "" +msgstr "Cualquiera" #: tagsPane.py:171 msgid "All" -msgstr "" +msgstr "Todo" #: tagsPane.py:197 msgid "Available Tags (click):" -msgstr "" +msgstr "Etiquetas Disponibles (click)" #: utils.py:841 msgid "__LANG_USE_SANS_SERIF__" @@ -1627,12 +1653,12 @@ msgstr "" #: voiceEditor.py:35 msgid "Singleplayer" -msgstr "" +msgstr "Un Jugador" #: voiceEditor.py:36 #, fuzzy msgid "Cooperative" -msgstr "Propiedades" +msgstr "Cooperativo" #: voiceEditor.py:37 msgid "ATLAS (SP/Coop)" @@ -1644,11 +1670,11 @@ msgstr "" #: voiceEditor.py:41 msgid "Human characters (Bendy and Chell)" -msgstr "" +msgstr "Personajes Humanos (Bendy y Chell)" #: voiceEditor.py:42 msgid "AI characters (ATLAS, P-Body, or Coop)" -msgstr "" +msgstr "Personajes IA (ATLAS, P-Body, o Coop)" #: voiceEditor.py:53 msgid "Death - Toxic Goo" @@ -1672,7 +1698,7 @@ msgstr "Transcripción:" #: voiceEditor.py:146 msgid "Save" -msgstr "" +msgstr "Guardar" #: voiceEditor.py:221 msgid "Resp" From 00051c39d5342b787eebae7476c604bd0c56712f Mon Sep 17 00:00:00 2001 From: DarviL Date: Sun, 18 Oct 2020 22:15:02 +0200 Subject: [PATCH 59/87] Update es.po --- i18n/es.po | 117 +++++++++++++++++++++++++++++------------------------ 1 file changed, 65 insertions(+), 52 deletions(-) diff --git a/i18n/es.po b/i18n/es.po index d463bdaa3..13d7c9969 100644 --- a/i18n/es.po +++ b/i18n/es.po @@ -356,7 +356,7 @@ msgid "" msgstr "" "Permite colocar y borrar las puertas de Entrada / Salida obligatorias así" " como la gran sala de observación. Solo recomendable con la gran sala de " -"observación." +"observación. Usar con precaución, ¡esto puede dar resultados extraños!" #: StyleVarPane.py:65 msgid "Allow Adding Goo Mist" @@ -447,11 +447,11 @@ msgstr "Otros Estilos:" #: StyleVarPane.py:287 msgid "No Options!" -msgstr "Sin Opciones!" +msgstr "¡Sin Opciones!" #: StyleVarPane.py:293 msgid "None!" -msgstr "Ninguno!" +msgstr "¡Ninguno!" #: StyleVarPane.py:364 msgid "Items" @@ -1269,63 +1269,67 @@ msgstr "" msgid "" "Add no music to the map at all. Testing Element-specific music may still " "be added." -msgstr "No añadir ninguna música de fondo al mapa en absoluto." +msgstr "No añadir ninguna música de fondo al mapa. La música de ciertos " +"elementos de prueba específicos puede que sea añadida." #: music_conf.py:142 msgid "Propulsion Gel SFX" -msgstr "SFX del gel de propulsión" +msgstr "SFX del Gel de Propulsión" #: music_conf.py:143 msgid "Repulsion Gel SFX" -msgstr "SFX del gel de repulsion" +msgstr "SFX del Gel de Repulsion" #: music_conf.py:144 msgid "Excursion Funnel Music" -msgstr "La música de fondo" +msgstr "Música del embudo de translación" #: music_conf.py:145 music_conf.py:160 msgid "Synced Funnel Music" -msgstr "" +msgstr "Música del Embudo de Translación sincronizada" #: music_conf.py:152 #, fuzzy msgid "Select Excursion Funnel Music" -msgstr "Selecciona la música de fondo" +msgstr "Selecciona la música del Embudo de Translación" #: music_conf.py:153 msgid "Set the music used while inside Excursion Funnels." -msgstr "" +msgstr "Selecciona la música usada al estar dentro de los" +" Embudos de Translación." #: music_conf.py:156 msgid "Have no music playing when inside funnels." -msgstr "" +msgstr "No hay música al estar dentro de los Embudos de" +" translación." #: music_conf.py:167 msgid "Select Repulsion Gel Music" -msgstr "" +msgstr "Seleccionar Música del Gel de Repulsión." #: music_conf.py:168 msgid "Select the music played when players jump on Repulsion Gel." -msgstr "" +msgstr "Selecciona la música que se reproduce al saltar en el Gel de Repulsión." #: music_conf.py:171 msgid "Add no music when jumping on Repulsion Gel." -msgstr "" +msgstr "No añadir música al saltar en el Gel de Repulsión." #: music_conf.py:179 #, fuzzy msgid "Select Propulsion Gel Music" -msgstr "Selecciona la música de fondo" +msgstr "Seleccionar la música del Gel de Repulsión" #: music_conf.py:180 msgid "" "Select music played when players have large amounts of horizontal " "velocity." -msgstr "" +msgstr "Selecciona la música que se reproduce cuando los jugadores " +" tienen una alta velocidad horizontal." #: music_conf.py:183 msgid "Add no music while running fast." -msgstr "" +msgstr "No añadir música al moverse rápido." #: music_conf.py:218 msgid "Base: " @@ -1333,34 +1337,35 @@ msgstr "" #: music_conf.py:251 msgid "Funnel:" -msgstr "" +msgstr "Embudo de Translación:" #: music_conf.py:252 msgid "Bounce:" -msgstr "" +msgstr "Rebotar:" #: music_conf.py:253 msgid "Speed:" -msgstr "" +msgstr "Velocidad:" #: optionWindow.py:62 msgid "BEE2 Options" -msgstr "BEE2 Opciones" +msgstr "Opciones de BEE2" #: optionWindow.py:101 msgid "" "Package cache times have been reset. These will now be extracted during " "the next export." -msgstr "" +msgstr "La fecha de los archivos cache de los paquetes se ha reseteado. Estos" +" serán extraídos durante la siguiente exportación." #: optionWindow.py:118 msgid "\"Preserve Game Resources\" has been disabled." -msgstr "" +msgstr "\"Preservar Recursos del Juego\" se ha desabilitado." #: optionWindow.py:130 #, fuzzy msgid "Packages Reset" -msgstr "Paquetes" +msgstr "Resetear Paquetes" #: optionWindow.py:211 msgid "General" @@ -1368,7 +1373,7 @@ msgstr "General" #: optionWindow.py:217 msgid "Windows" -msgstr "Ventana" +msgstr "Ventanas" #: optionWindow.py:223 msgid "Development" @@ -1376,128 +1381,136 @@ msgstr "Desarollo" #: optionWindow.py:247 packageMan.py:110 selectorWin.py:701 msgid "OK" -msgstr "SI" +msgstr "Vale" #: optionWindow.py:278 msgid "After Export:" -msgstr "" +msgstr "Después de la Exportación:" #: optionWindow.py:295 msgid "Do Nothing" -msgstr "" +msgstr "No hacer nada" #: optionWindow.py:301 msgid "Minimise BEE2" -msgstr "" +msgstr "Minimizar BEE2" #: optionWindow.py:307 msgid "Quit BEE2" -msgstr "" +msgstr "Cerrar BEE2" #: optionWindow.py:315 msgid "After exports, do nothing and keep the BEE2 in focus." -msgstr "" +msgstr "Después de exportar, no hacer nada y mantener BEE2 abierto." #: optionWindow.py:317 msgid "After exports, minimise to the taskbar/dock." -msgstr "" +msgstr "Después de exportar, minimizar a la barra de tareas/bandeja." #: optionWindow.py:318 msgid "After exports, quit the BEE2." -msgstr "" +msgstr "Después de exportar, salir de BEE2." #: optionWindow.py:325 msgid "Launch Game" -msgstr "" +msgstr "Ejecutar Juego" #: optionWindow.py:326 msgid "After exporting, launch the selected game automatically." -msgstr "" +msgstr "Después de exportar, ejecutar el juego seleccionado automáticamente." #: optionWindow.py:334 optionWindow.py:340 msgid "Play Sounds" -msgstr "" +msgstr "Reproducir Sonidos" #: optionWindow.py:345 msgid "" "Pyglet is either not installed or broken.\n" "Sound effects have been disabled." -msgstr "" +msgstr "Pyglet no está instalado, o está roto.\n" +"Los efectos de sonido se han desabilitado." #: optionWindow.py:352 msgid "Reset Package Caches" -msgstr "" +msgstr "Resetear la caché de los Paquetes" #: optionWindow.py:358 msgid "Force re-extracting all package resources." -msgstr "" +msgstr "Forzar la re-extracción de todos los recursos de los paquetes." #: optionWindow.py:367 msgid "Keep windows inside screen" -msgstr "" +msgstr "Mantener ventanas dentro de la pantalla" #: optionWindow.py:368 msgid "" "Prevent sub-windows from moving outside the screen borders. If you have " "multiple monitors, disable this." -msgstr "" +msgstr "Prevenir el movimiento de las sub-ventanas fuera de los bordes de pantalla." +" Si tienes varios monitores, deshabilita esta opción." #: optionWindow.py:378 #, fuzzy msgid "Keep loading screens on top" -msgstr "Limpiar viejas capturas de pantalla" +msgstr "Mantener pantallas de carga encima" #: optionWindow.py:380 msgid "" "Force loading screens to be on top of other windows. Since they don't " "appear on the taskbar/dock, they can't be brought to the top easily " "again." -msgstr "" +msgstr "Forzar que las pantallas de carga aparezcan encima de otras ventanas." +" Como no aparecen en la barra de tareas/bandeja, no es posible moverlas encima" +" facilmente." #: optionWindow.py:389 msgid "Reset All Window Positions" -msgstr "" +msgstr "Resetear la posición de todas las ventanas" #: optionWindow.py:403 msgid "Log missing entity counts" -msgstr "" +msgstr "Registrar cuenta de entidades que faltan" #: optionWindow.py:404 msgid "" "When loading items, log items with missing entity counts in their " "properties.txt file." -msgstr "" +msgstr "Cuando se cargan ítems, registrar ítems que faltan de entidades" +" en el archivo properties.txt." #: optionWindow.py:412 msgid "Log when item doesn't have a style" -msgstr "" +msgstr "Registrar cuando un ítem no tiene un estilo" #: optionWindow.py:413 msgid "" "Log items have no applicable version for a particular style.This usually " "means it will look very bad." -msgstr "" +msgstr "Registrar ítems que no tienen una versión aplicable para un estilo en" +" particular. Esto usualmente significa que lucirá muy mal." #: optionWindow.py:421 msgid "Log when item uses parent's style" -msgstr "" +msgstr "Registrar cuando un ítem usa el estilo del padre" #: optionWindow.py:422 msgid "" "Log when an item reuses a variant from a parent style (1970s using 1950s " "items, for example). This is usually fine, but may need to be fixed." -msgstr "" +msgstr "Registrar cuando un ítem usa una variante de un estilo padre (1970s" +" usando ítems de 1950s, por ejemplo). Esto normalmente está bien, pero" +" puede que tenga que ser reparado." #: optionWindow.py:431 msgid "Log missing packfile resources" -msgstr "Mostrar recursos packfile que faltan" +msgstr "Registrar recursos packfile que faltan" #: optionWindow.py:432 msgid "" "Log when the resources a \"PackList\" refers to are not present in the " "zip. This may be fine (in a prerequisite zip), but it often indicates an " "error." -msgstr "Mostrar cuando los recursos que \"PackList\" refiere no se encuentran" +msgstr "Registrar cuando los recursos a los que \"PackList\" se refiere no se encuentran" " presentes en el zip. Esto puede estar bien (en un zip requerido), pero " "normalmente indica un error." From 81272d683211143038d2e660cf118b927c9b5f81 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 21 Oct 2020 15:36:36 +1000 Subject: [PATCH 60/87] Voice attrs should be casefolded --- src/precomp/cubes.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/precomp/cubes.py b/src/precomp/cubes.py index 3c83fca25..f5e5c350e 100644 --- a/src/precomp/cubes.py +++ b/src/precomp/cubes.py @@ -1343,11 +1343,11 @@ def link_cubes(vmf: VMF): pair.cube_type.in_map = True if pair.paint_type is CubePaintType.BOUNCE: - voice_attr['BounceGel'] = voice_attr['BlueGel'] = True - voice_attr['Gel'] = True + voice_attr['bouncegel'] = voice_attr['BlueGel'] = True + voice_attr['gel'] = True elif pair.paint_type is CubePaintType.SPEED: - voice_attr['SpeedGel'] = voice_attr['OrangeGel'] = True - voice_attr['Gel'] = True + voice_attr['speedgel'] = voice_attr['OrangeGel'] = True + voice_attr['gel'] = True has_name = pair.cube_type.has_name voice_attr['cube' + has_name] = True @@ -1678,8 +1678,8 @@ def generate_cubes(vmf: VMF): """After other conditions are run, generate cubes.""" from vbsp import settings voice_attr = settings['has_attr'] # type: Dict[str, bool] - bounce_in_map = voice_attr['BounceGel'] - speed_in_map = voice_attr['SpeedGel'] + bounce_in_map = voice_attr['bouncegel'] + speed_in_map = voice_attr['speedgel'] # point_template for spawning dropperless cubes. # We can fit 16 in each, start with the count = 16 so From f7bf69e0945254779c5e87610e36950887c7dbea Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 21 Oct 2020 15:36:59 +1000 Subject: [PATCH 61/87] Use skinsets in the precached model --- src/precomp/cubes.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/precomp/cubes.py b/src/precomp/cubes.py index f5e5c350e..3b35e6021 100644 --- a/src/precomp/cubes.py +++ b/src/precomp/cubes.py @@ -605,7 +605,7 @@ def __repr__(self) -> str: drop_id, self.cube_type.id, drop, cube, self.tint, ) - def use_rusty_version(self, has_gel: bool): + def use_rusty_version(self, has_gel: bool) -> bool: """Check if we can can use the rusty version. This is only allowed if it's one of Valve's cubes, @@ -1644,6 +1644,8 @@ def make_cube( if cube_type.model_swap_meth is ModelSwapMeth.CUBE_TYPE: ent['CubeType'] = CUBE_ID_CUSTOM_MODEL_HACK + elif cube_type.model_swap_meth is ModelSwapMeth.SETMODEL: + precache_model(vmf, cust_model, skinset) if isinstance(pack, list): packing.pack_files(vmf, *pack) @@ -1722,7 +1724,6 @@ def generate_cubes(vmf: VMF): CUBE_SKINS[pair.cube_type.type].spawn_skin(spawn_paint), ), )) - precache_model(vmf, cust_model) drop_cube = cube = should_respawn = None From 934f03fa1fb6c360772271886cd4b396e7bc884f Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 21 Oct 2020 15:37:51 +1000 Subject: [PATCH 62/87] Fix putting bools in property objects --- src/app/gameMan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/gameMan.py b/src/app/gameMan.py index 5f389e037..44eaaeb57 100644 --- a/src/app/gameMan.py +++ b/src/app/gameMan.py @@ -692,7 +692,7 @@ def export( export_screen.step('EXP') vbsp_config.set_key(('Options', 'Game_ID'), self.steamID) - vbsp_config.set_key(('Options', 'dev_mode'), optionWindow.DEV_MODE.get()) + vbsp_config.set_key(('Options', 'dev_mode'), srctools.bool_as_int(optionWindow.DEV_MODE.get())) # If there are multiple of these blocks, merge them together. # They will end up in this order. From a338e8361016ad438b448aa487c00bcd8b082dbd Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 21 Oct 2020 15:38:11 +1000 Subject: [PATCH 63/87] Add skinset support to precache models --- src/precomp/conditions/globals.py | 53 ++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/src/precomp/conditions/globals.py b/src/precomp/conditions/globals.py index f09aa1f5a..dd6874b69 100644 --- a/src/precomp/conditions/globals.py +++ b/src/precomp/conditions/globals.py @@ -1,4 +1,7 @@ """Conditions related to global properties - stylevars, music, which game, etc.""" + +from typing import AbstractSet, Collection, Set, Dict, Optional, Tuple + from srctools import Vec, Property, Entity, conv_bool, VMF import srctools.logger @@ -167,7 +170,7 @@ def res_set_style_var(res: Property) -> bool: @make_result('has') -def res_set_voice_attr(res: Property): +def res_set_voice_attr(res: Property) -> object: """Sets a number of Voice Attributes. Each child property will be set. The value is ignored, but must @@ -181,42 +184,62 @@ def res_set_voice_attr(res: Property): return RES_EXHAUSTED -CACHED_MODELS = set() +# The set is the set of skins to use. If empty, all are used. +CACHED_MODELS: Dict[str, Tuple[Set[int], Entity]] = {} @make_result('PreCacheModel') -def res_pre_cache_model(vmf: VMF, res: Property): +def res_pre_cache_model(vmf: VMF, res: Property) -> None: """Precache the given model for switching. This places it as a `prop_dynamic_override`. """ - precache_model(vmf, res.value.casefold()) + if res.has_children(): + model = res['model'] + skins = [int(skin) for skin in res['skinset', ''].split()] + else: + model = res.value + skins = () + precache_model(vmf, model, skins) -def precache_model(vmf: VMF, mdl_name: str): +def precache_model(vmf: VMF, mdl_name: str, skinset: Collection[int]=()) -> None: """Precache the given model for switching. - This places it as a `prop_dynamic_override`. + This places it as a `comp_precache_model`. """ - + mdl_name = mdl_name.casefold().replace('\\', '/') if not mdl_name.startswith('models/'): mdl_name = 'models/' + mdl_name if not mdl_name.endswith('.mdl'): mdl_name += '.mdl' - if mdl_name in CACHED_MODELS: return - CACHED_MODELS.add(mdl_name) - vmf.create_ent( - classname='comp_precache_model', - origin=options.get(Vec, 'global_ents_loc'), - model=mdl_name, - ) + try: + skins, ent = CACHED_MODELS[mdl_name] + except KeyError: + ent = vmf.create_ent( + classname='comp_precache_model', + origin=options.get(Vec, 'global_ents_loc'), + model=mdl_name, + ) + skins = set(skinset) + CACHED_MODELS[mdl_name] = skins, ent + else: + if skins: # If empty, it's wildcard so ignore specifics. + if len(skinset) == 0: + skins.clear() + else: + skins.update(skinset) + if skins: + ent['skinset'] = ' '.join(map(str, sorted(skinset))) + else: + ent['skinset'] = '' @make_result('GetItemConfig') -def res_item_config_to_fixup(inst: Entity, res: Property): +def res_item_config_to_fixup(inst: Entity, res: Property) -> None: """Load a config from the item config panel onto a fixup. * `ID` is the ID of the group. From 1d6b4d07dfea12b97aef8400e5aef5270ab9a034 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 21 Oct 2020 15:39:15 +1000 Subject: [PATCH 64/87] Add an identifier to the BSP packfile --- src/vrad.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vrad.py b/src/vrad.py index 9ecdea253..154159f71 100644 --- a/src/vrad.py +++ b/src/vrad.py @@ -200,10 +200,10 @@ def main(argv: List[str]) -> None: zip_data = BytesIO() zip_data.write(bsp_file.get_lump(BSP_LUMPS.PAKFILE)) - zipfile = ZipFile(zip_data, mode='a') + zipfile = ZipFile(zip_data) # Mount the existing packfile, so the cubemap files are recognised. - fsys.systems.append((ZipFileSystem('', zipfile), '')) + fsys.add_sys(ZipFileSystem('', zipfile)) fsys.open_ref() From 5b72d7488a8146bd2f43c032da4025e102ee14b2 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 21 Oct 2020 15:39:35 +1000 Subject: [PATCH 65/87] Update dependencies --- dev-requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev-requirements.txt b/dev-requirements.txt index e75b54774..80097e49a 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,4 +1,4 @@ -mypy==0.761 +mypy==0.782 mypy-extensions==0.4.3 pytest==5.0.1 -Cython==0.29.14 +Cython==0.29.21 From cdd287db94d9b38417927dc8d2883904258f78ab Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Sun, 29 Nov 2020 17:47:13 +1000 Subject: [PATCH 66/87] Fix #1369: Antline floor/wall configs getting swapped --- src/precomp/connections.py | 8 ++++++-- src/vbsp.py | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/precomp/connections.py b/src/precomp/connections.py index 9e5854871..4b41f0d44 100644 --- a/src/precomp/connections.py +++ b/src/precomp/connections.py @@ -823,7 +823,11 @@ def calc_connections( pass else: # Pass in the defaults for antline styles. - ITEMS[inst_name] = Item(inst, item_type, antline_floor, antline_wall) + ITEMS[inst_name] = Item( + inst, item_type, + ant_floor_style=antline_floor, + ant_wall_style=antline_wall, + ) # Strip off the original connection count variables, these are # invalid. @@ -1651,7 +1655,7 @@ def add_item_indicators( for ant in item.antlines: ant.name = ant_name - ant.export(item.inst.map, item.ant_wall_style, item.ant_floor_style) + ant.export(item.inst.map, wall_conf=item.ant_wall_style, floor_conf=item.ant_floor_style) # Special case - the item wants full control over its antlines. if has_ant and item.ant_toggle_var: diff --git a/src/vbsp.py b/src/vbsp.py index 157e8ead3..35a8b1474 100644 --- a/src/vbsp.py +++ b/src/vbsp.py @@ -1903,8 +1903,8 @@ def main() -> None: ant, texturing.OVERLAYS.get_all('shapeframe'), settings['style_vars']['enableshapesignageframe'], - ant_floor, - ant_wall, + antline_wall=ant_wall, + antline_floor=ant_floor, ) MAP_RAND_SEED = calc_rand_seed(vmf) From 25afa7184544de6f6e2e8bef3bf96ea5b0bb761b Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Sun, 29 Nov 2020 17:48:31 +1000 Subject: [PATCH 67/87] Use Angle/Matrix objects in template_brush to be more efficient --- src/precomp/template_brush.py | 52 ++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/src/precomp/template_brush.py b/src/precomp/template_brush.py index 4a2dc00d9..e620b2119 100644 --- a/src/precomp/template_brush.py +++ b/src/precomp/template_brush.py @@ -7,8 +7,9 @@ from operator import attrgetter import srctools -from srctools import Entity, Solid, Side, Property, UVAxis, Vec, VMF -from srctools.vmf import EntityFixup +from srctools import Property +from srctools.vec import Vec, Angle, Matrix, to_matrix +from srctools.vmf import EntityFixup, Entity, Solid, Side, VMF, UVAxis import srctools.logger from .texturing import Portalable, GenCat, TileSize @@ -38,7 +39,7 @@ class InvalidTemplateName(LookupError): def __init__(self, temp_name: str) -> None: self.temp_name = temp_name - def __str__(self): + def __str__(self) -> str: # List all the templates that are available. return 'Template not found: "{}"\nValid templates:\n{}'.format( self.temp_name, @@ -149,7 +150,7 @@ class TileSetter(NamedTuple): TEMP_TILE_PIX_SIZE = { # The width in texture pixels of each tile size. - # We decrease offset to this much +- at maximum (so adjacient template + # We decrease offset to this much +- at maximum (so adjacent template # brushes merge with each other). This still allows creating brushes # with half-grid offsets. '4x4': 128, @@ -187,14 +188,14 @@ class ExportedTemplate(NamedTuple): orig_ids: Dict[int, int] template: 'Template' origin: Vec - angles: Vec + orient: Matrix visgroups: Set[str] picker_results: Dict[str, Optional[Portalable]] picker_type_results: Dict[str, Optional[TileType]] # Make_prism() generates faces aligned to world, copy the required UVs. -realign_solid = VMF().make_prism(Vec(-16,-16,-16), Vec(16,16,16)).solid # type: Solid +realign_solid = VMF().make_prism(Vec(-16, -16, -16), Vec(16, 16, 16)).solid # type: Solid REALIGN_UVS = { face.normal().as_tuple(): (face.uaxis, face.vaxis) for face in realign_solid @@ -373,7 +374,7 @@ def __getitem__( mat, axis_u, axis_v, rotation = self._axes[normal] return mat, axis_u.copy(), axis_v.copy(), rotation - def rotate(self, angles: Vec, origin: Optional[Vec]=None) -> 'ScalingTemplate': + def rotate(self, angles: Union[Angle, Matrix], origin: Optional[Vec]=None) -> 'ScalingTemplate': """Rotate this template, and return a new template with those angles.""" new_axis = {} if origin is None: @@ -382,7 +383,7 @@ def rotate(self, angles: Vec, origin: Optional[Vec]=None) -> 'ScalingTemplate': for norm, (mat, axis_u, axis_v, rot) in self._axes.items(): axis_u = axis_u.localise(origin, angles) axis_v = axis_v.localise(origin, angles) - v_norm = Vec(norm).rotate(*angles) + v_norm = Vec(norm) @ angles new_axis[v_norm.as_tuple()] = mat, axis_u, axis_v, rot return ScalingTemplate(self.id, new_axis) @@ -480,7 +481,7 @@ def make_subdict() -> Dict[str, list]: name=ent['targetname'], visgroups=set(ent['visgroups'].split(' ')) - {''}, offset=Vec.from_str(ent['origin']), - normal=Vec(x=1).rotate_by_str(ent['angles']), + normal=Vec(x=1) @ Angle.from_str(ent['angles']), sides=ent['faces'].split(' '), grid_snap=srctools.conv_bool(ent['grid_snap']), after=remove_after, @@ -510,7 +511,7 @@ def make_subdict() -> Dict[str, list]: tile_setters[temp_id].append(TileSetter( offset=Vec.from_str(ent['origin']), - normal=Vec(z=1).rotate_by_str(ent['angles']), + normal=Vec(z=1) @ Angle.from_str(ent['angles']), visgroups=set(ent['visgroups'].split(' ')) - {''}, color=color, tile_type=tile_type, @@ -574,7 +575,7 @@ def import_template( vmf: VMF, temp_name: Union[str, Template], origin: Vec, - angles: Optional[Vec]=None, + angles: Optional[Union[Angle, Matrix]]=None, targetname: str='', force_type: TEMP_TYPES=TEMP_TYPES.default, add_to_map: bool=True, @@ -620,18 +621,19 @@ def import_template( # A map of the original -> new face IDs. id_mapping = {} # type: Dict[int, int] + orient = to_matrix(angles) for orig_list, new_list in [ - (orig_world, new_world), - (orig_detail, new_detail) - ]: + (orig_world, new_world), + (orig_detail, new_detail) + ]: for old_brush in orig_list: brush = old_brush.copy( vmf_file=vmf, side_mapping=id_mapping, keep_vis=False, ) - brush.localise(origin, angles) + brush.localise(origin, orient) new_list.append(brush) for overlay in orig_over: # type: Entity @@ -649,7 +651,7 @@ def import_template( if int(side) in id_mapping ) - srctools.vmf.localise_overlay(new_overlay, origin, angles) + srctools.vmf.localise_overlay(new_overlay, origin, orient) orig_target = new_overlay['targetname'] # Only change the targetname if the overlay is not global, and we have @@ -693,10 +695,10 @@ def import_template( if face.id in new_overlay_faces ] - tile_norm = Vec(z=1).rotate(*angles) + tile_norm = orient.up() for tile_off in bind_tile_pos: tile_off = tile_off.copy() - tile_off.localise(origin, angles) + tile_off.localise(origin, orient) try: tile = tiling.TILES[tile_off.as_tuple(), tile_norm.as_tuple()] except KeyError: @@ -717,7 +719,7 @@ def import_template( orig_ids=id_mapping, template=template, origin=origin, - angles=angles or Vec(0, 0, 0), + orient=orient, visgroups=chosen_groups, picker_results={}, # Filled by retexture_template. picker_type_results={}, @@ -842,7 +844,7 @@ def retexture_template( if sense_offset is None: sense_offset = Vec() else: - sense_offset = sense_offset.copy().rotate(*template_data.angles) + sense_offset = sense_offset @ template_data.orient # For each face, if it needs to be forced to a colour, or None if not. # If a string it's forced to that string specifically. @@ -861,9 +863,9 @@ def retexture_template( if not color_picker.visgroups.issubset(template_data.visgroups): continue - picker_pos = color_picker.offset.copy().rotate(*template_data.angles) + picker_pos = color_picker.offset @ template_data.orient picker_pos += template_data.origin + sense_offset - picker_norm = Vec(color_picker.normal).rotate(*template_data.angles) + picker_norm = Vec(color_picker.normal) @ template_data.orient if color_picker.grid_snap: for axis in 'xyz': @@ -935,9 +937,9 @@ def retexture_template( if not tile_setter.visgroups.issubset(template_data.visgroups): continue - setter_pos = Vec(tile_setter.offset).rotate(*template_data.angles) + setter_pos = Vec(tile_setter.offset) @ template_data.orient setter_pos += template_data.origin + sense_offset - setter_norm = Vec(tile_setter.normal).rotate(*template_data.angles) + setter_norm = Vec(tile_setter.normal) @ template_data.orient setter_type = tile_setter.tile_type # type: TileType if tile_setter.color == 'copy': @@ -1043,7 +1045,7 @@ def retexture_template( face.uaxis = uaxis.copy() face.vaxis = vaxis.copy() elif orig_id in template.vertical_faces: - # Rotate the face in increments of 90 degress, so it is as + # Rotate the face in increments of 90 degrees, so it is as # upright as possible. pos_u = face.uaxis pos_v = face.vaxis From cb78c7777d6a09699c0fb230272f089d92554c70 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Sun, 29 Nov 2020 18:56:57 +1000 Subject: [PATCH 68/87] Update fizzler to use Matrix/Angle objects --- src/precomp/fizzler.py | 55 +++++++++++++----------------------------- 1 file changed, 17 insertions(+), 38 deletions(-) diff --git a/src/precomp/fizzler.py b/src/precomp/fizzler.py index 0ecb8e4cd..032e73b4e 100644 --- a/src/precomp/fizzler.py +++ b/src/precomp/fizzler.py @@ -9,7 +9,8 @@ import utils import srctools.logger import srctools.vmf -from srctools import Output, Vec, VMF, Solid, Entity, Side, Property, NoKeyError +from srctools.vmf import VMF, Solid, Entity, Side, Output +from srctools import Property, NoKeyError, Vec, Matrix, Angle from precomp import ( instance_traits, tiling, instanceLocs, texturing, @@ -32,9 +33,6 @@ FIZZLER_TEX_SIZE = 1024 LASER_TEX_SIZE = 512 -# Given a normal and the up-axis, the angle used for the instance. -FIZZ_ANGLES = {} # type: Dict[Tuple[Tuple[float, float, float], Tuple[float, float, float]], Vec] - # A few positions for material_modify_control, # so they aren't on top of each other. MATMOD_OFFSETS = [ @@ -141,25 +139,6 @@ def read_configs(conf: Property) -> None: )) -def _calc_fizz_angles() -> None: - """Generate FIZZ_ANGLES.""" - it = itertools.product('xyz', (-1, 1), 'xyz', (-1, 1)) - for norm_axis, norm_mag, roll_axis, roll_mag in it: - if norm_axis == roll_axis: - # They can't both be the same... - continue - norm = Vec.with_axes(norm_axis, norm_mag) - roll = Vec.with_axes(roll_axis, roll_mag) - - # Norm is Z, roll is X, we want y. - angle = roll.to_angle_roll(norm) - up_dir = norm.cross(roll) - FIZZ_ANGLES[norm.as_tuple(), up_dir.as_tuple()] = angle - -_calc_fizz_angles() -del _calc_fizz_angles - - class FizzlerType: """Implements a specific fizzler type.""" def __init__( @@ -920,7 +899,6 @@ def generate( ] used_tex_func(side.mat) - def _texture_fit( self, side: Side, @@ -1017,7 +995,8 @@ def parse_map(vmf: VMF, voice_attrs: Dict[str, bool]) -> None: for name, base_inst in fizz_bases.items(): models = fizz_models[name] - up_axis = Vec(y=1).rotate_by_str(base_inst['angles']) + orient = Matrix.from_angle(Angle.from_str(base_inst['angles'])) + up_axis = orient.left() # If upside-down, make it face upright. if up_axis == (0, 0, -1): @@ -1028,7 +1007,7 @@ def parse_map(vmf: VMF, voice_attrs: Dict[str, bool]) -> None: # Now match the pairs of models to each other. # The length axis is the line between them. # We don't care about the instances after this, so don't keep track. - length_axis = Vec(z=1).rotate_by_str(base_inst['angles']).axis() + length_axis = orient.up().axis() emitters = [] # type: List[Tuple[Vec, Vec]] @@ -1189,8 +1168,8 @@ def generate_fizzlers(vmf: VMF): up_dir = fizz.up_axis forward = (fizz.emitters[0][1] - fizz.emitters[0][0]).norm() - min_angles = FIZZ_ANGLES[forward.as_tuple(), up_dir.as_tuple()] - max_angles = FIZZ_ANGLES[(-forward).as_tuple(), up_dir.as_tuple()] + min_orient = Matrix.from_basis(z=forward, y=up_dir) + max_orient = Matrix.from_basis(z=-forward, y=up_dir) model_min = ( fizz_type.inst[FizzInst.PAIR_MIN, is_static] @@ -1251,8 +1230,8 @@ def get_model_name(ind): for offset in beam.offset: # type: Vec min_off = offset.copy() max_off = offset.copy() - min_off.localise(seg_min, min_angles) - max_off.localise(seg_max, max_angles) + min_off.localise(seg_min, min_orient) + max_off.localise(seg_max, max_orient) beam_ent = beam_template.copy() vmf.add_ent(beam_ent) @@ -1296,7 +1275,7 @@ def get_model_name(ind): classname='func_instance', file=random.choice(fizz_type.inst[FizzInst.PAIR_SINGLE, is_static]), origin=(seg_min + seg_max)/2, - angles=min_angles, + angles=min_orient.to_angle(), ) else: # Both side models. @@ -1305,7 +1284,7 @@ def get_model_name(ind): classname='func_instance', file=random.choice(model_min), origin=seg_min, - angles=min_angles, + angles=min_orient.to_angle(), ) random.seed('{}_fizz_{}'.format(MAP_RAND_SEED, seg_max)) max_inst = vmf.create_ent( @@ -1313,7 +1292,7 @@ def get_model_name(ind): classname='func_instance', file=random.choice(model_max), origin=seg_max, - angles=max_angles, + angles=max_orient.to_angle(), ) max_inst.fixup.update(fizz.base_inst.fixup) instance_traits.get(max_inst).update(fizz_traits) @@ -1338,7 +1317,7 @@ def get_model_name(ind): mid_inst = vmf.create_ent( classname='func_instance', targetname=fizz_name, - angles=min_angles, + angles=min_orient.to_angle(), file=random.choice(fizz_type.inst[FizzInst.GRID, is_static]), origin=mid_pos, ) @@ -1351,7 +1330,7 @@ def get_model_name(ind): vmf, fizz_type.temp_single, (seg_min + seg_max) / 2, - min_angles, + min_orient, force_type=template_brush.TEMP_TYPES.world, add_to_map=False, ) @@ -1362,7 +1341,7 @@ def get_model_name(ind): vmf, fizz_type.temp_min, seg_min, - min_angles, + min_orient, force_type=template_brush.TEMP_TYPES.world, add_to_map=False, ) @@ -1372,7 +1351,7 @@ def get_model_name(ind): vmf, fizz_type.temp_max, seg_max, - max_angles, + max_orient, force_type=template_brush.TEMP_TYPES.world, add_to_map=False, ) @@ -1475,7 +1454,7 @@ def used_tex_func(val): brush_name = conditions.local_name(fizz.base_inst, brush_type.name) mat_mod_name = conditions.local_name(fizz.base_inst, brush_type.mat_mod_name) for off, tex in zip(MATMOD_OFFSETS, sorted(used_tex)): - pos = off.copy().rotate(*min_angles) + pos = off @ min_orient pos += Vec.from_str(fizz.base_inst['origin']) vmf.create_ent( classname='material_modify_control', From bfeeae576338a5e9ceeae681bb29953732d11a14 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Sun, 29 Nov 2020 18:57:08 +1000 Subject: [PATCH 69/87] Round this position --- src/precomp/tiling.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/precomp/tiling.py b/src/precomp/tiling.py index 4a9accb5c..331d75519 100644 --- a/src/precomp/tiling.py +++ b/src/precomp/tiling.py @@ -1424,7 +1424,7 @@ def find_tile(origin: Vec, normal: Vec, force: bool=False) -> Tuple[TileDef, int ) # grid_pos = round_grid(origin - normal) - uv_pos = (origin - grid_pos + 64 - 16) + uv_pos = round(origin - grid_pos + 64 - 16, 6) u = uv_pos[u_axis] / 32 % 4 v = uv_pos[v_axis] / 32 % 4 From 9418652b9840d4ad3a5aaf1d8b650ba5d288ac69 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Tue, 29 Dec 2020 19:00:12 +1000 Subject: [PATCH 70/87] Just always write the manifest. --- src/vrad.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/vrad.py b/src/vrad.py index 154159f71..252fe54d8 100644 --- a/src/vrad.py +++ b/src/vrad.py @@ -249,11 +249,7 @@ def main(argv: List[str]) -> None: packlist.eval_dependencies() LOGGER.info('Done!') - if is_peti: - packlist.write_manifest() - else: - # Write with the map name, so it loads directly. - packlist.write_manifest(os.path.basename(path)[:-4]) + packlist.write_manifest() # We need to disallow Valve folders. pack_whitelist = set() # type: Set[FileSystem] From b5e581fc6a1b8146d2dba88a32db42611dc29181 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Tue, 29 Dec 2020 19:00:29 +1000 Subject: [PATCH 71/87] If any error occurs while loading Pyglet, just skip --- src/app/sound.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/sound.py b/src/app/sound.py index 45fb388b1..0b049d286 100644 --- a/src/app/sound.py +++ b/src/app/sound.py @@ -54,7 +54,7 @@ pyglet_version = pyglet.version if not pyglet.media.have_ffmpeg(): raise ImportError('No ffmpeg available!') -except ImportError: +except Exception: LOGGER.warning('ERROR:SOUNDS NOT INITIALISED!', exc_info=True) pyglet_version = '(Not installed)' From 823042d3b958f054edb7d64ffb31f0349c1ff32b Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Thu, 31 Dec 2020 13:35:23 +1000 Subject: [PATCH 72/87] Cythonised parse_vec_str only accepts doubles, so pass NaN as a sentinel --- src/precomp/options.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/precomp/options.py b/src/precomp/options.py index 18517b739..b41b82032 100644 --- a/src/precomp/options.py +++ b/src/precomp/options.py @@ -1,4 +1,5 @@ """Manages reading general options from vbsp_config.""" +import math from enum import Enum, EnumMeta import inspect @@ -97,9 +98,9 @@ def load(opt_blocks: Iterator[Property]) -> None: SETTINGS[opt.id] = opt.default continue if opt.type is TYPE.VEC: - # Pass nones so we can check if it failed.. - parsed_vals = parse_vec_str(val, x=None) - if parsed_vals[0] is None: + # Pass NaN so we can check if it failed.. + parsed_vals = parse_vec_str(val, math.nan) + if math.isnan(parsed_vals[0]): SETTINGS[opt.id] = opt.default else: SETTINGS[opt.id] = Vec(*parsed_vals) From 9ba4b4b0b70fcbfb9c4c85da49647f7802b7bb9e Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Thu, 31 Dec 2020 13:35:32 +1000 Subject: [PATCH 73/87] This is an Angle one --- src/precomp/cubes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/precomp/cubes.py b/src/precomp/cubes.py index 3b35e6021..0cbd4836c 100644 --- a/src/precomp/cubes.py +++ b/src/precomp/cubes.py @@ -1564,7 +1564,7 @@ def make_cube( # Don't paint it on spawn. spawn_paint = None - yaw = norm.to_angle().y + yaw = norm.to_angle().yaw cust_model = cube_type.model pack = cube_type.pack # type: Optional[Union[str, List[str]]] From 3beacc66902230566532d10650f34291b7474f73 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Fri, 1 Jan 2021 13:36:34 +1000 Subject: [PATCH 74/87] Rewrite angled panel generation using angle/matrix code --- src/precomp/tiling.py | 65 +++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 39 deletions(-) diff --git a/src/precomp/tiling.py b/src/precomp/tiling.py index 331d75519..56ae6378f 100644 --- a/src/precomp/tiling.py +++ b/src/precomp/tiling.py @@ -23,7 +23,7 @@ import math from weakref import WeakKeyDictionary -from srctools import Vec, VMF, Entity, Side, Solid, Output +from srctools import Vec, VMF, Entity, Side, Solid, Output, Angle, Matrix import srctools.logger import srctools.vmf from precomp.brushLoc import POS as BLOCK_POS, Block, grid_to_world @@ -499,17 +499,14 @@ def export( ) use_bullseye = tile.use_bullseye() - angles = Vec.from_str(self.inst['angles']) - inst_normal = Vec(z=1).rotate(*angles) - if inst_normal != tile.normal: + angles = Angle.from_str(self.inst['angles']) + orient = Matrix.from_angle(angles) + if orient.up() != tile.normal: # It's not aligned to ourselves, so dump the rotation. - angles = Vec.from_str( + angles = Angle.from_str( conditions.PETI_INST_ANGLE[tile.normal.as_tuple()]) - # Points towards the open end on angled panels. - front_normal = Vec(x=1).rotate(*angles) - # Point along the hinge axis on angled panels. - side_normal = Vec(y=1).rotate(*angles) - front_pos = tile.pos + 64 * tile.normal + orient = Matrix.from_angle(angles) + front_pos = Vec(0, 0, 64) @ orient + tile.pos offset = self.offset.copy() @@ -608,7 +605,7 @@ def export( # Don't offset these at all. Assume the user knows # where it should go. Vec.from_str(self.inst['origin']), - Vec.from_str(self.inst['angles']), + orient, self.inst['targetname'], force_type=template_brush.TEMP_TYPES.world, add_to_map=False, @@ -621,24 +618,13 @@ def export( all_brushes += template.world if self.pan_type.is_angled: - # Rotate the panel to match the panel shape: - # Figure out if we want to rotate +ve or -ve. - # We know rotating the surface 90 degrees will point - # the end straight up, so check if it points at the normal. - rotate_forward = Vec(x=1).rotate(*side_normal.rotation_around()) == tile.normal - - # This direction is inverted... - if front_normal == (-1, 0, 0): - rotate_forward = not rotate_forward - - if rotate_forward: - rotation = side_normal.rotation_around(self.pan_type.angle) - else: - rotation = side_normal.rotation_around(-self.pan_type.angle) + # Rotate the panel to match the panel shape, by rotating around + # its Y axis. + rotation = Matrix.axis_angle(-orient.left(), self.pan_type.angle) # Shift so the rotation axis is 0 0 0, then shift back # to rotate correctly. - panel_offset = front_pos - 64 * front_normal + panel_offset = front_pos - Vec(64, 0, 0) @ orient # Rotating like this though will make the brush clip into the # surface it's attached on. We need to clip the hinge edge @@ -652,15 +638,17 @@ def export( tile.pos - 64 + 128 * tile.normal, )[PRISM_NORMALS[(-tile.normal).as_tuple()]] - front_axis = front_normal.axis() + front_normal: Vec = round(orient.forward(), 6) for brush in all_brushes: clip_face = None for face in brush: if ( face.normal() == front_normal - and face.get_origin()[front_axis] - == panel_offset[front_axis] + and math.isclose( + face.get_origin().dot(front_normal), + panel_offset.dot(front_normal) + ) ): clip_face = face break @@ -675,9 +663,9 @@ def export( # Helpfully the angled surfaces are always going to be forced # upright, so we don't need to compute the orientation matching # the item axis. - angled_normal = tile.normal.copy().rotate(*rotation) + angled_normal = tile.normal @ rotation top_center = ( - (64 * front_normal).rotate(*rotation) - + 64 * front_normal @ rotation - 64 * front_normal + front_pos ) @@ -700,8 +688,8 @@ def export( vmf, angled_normal, top_center, - (64 * front_normal).rotate(*rotation), - (64 * side_normal), + 64 * front_normal @ rotation, + 64 * orient.left(), texturing.OVERLAYS.get(front_pos, 'bullseye'), faces, ) @@ -714,8 +702,8 @@ def export( vmf, tile.normal, front_pos + offset, - Vec(y=64).rotate(*angles), - Vec(z=64).rotate(*angles), + 64 * orient.left(), + 64 * orient.forward(), texturing.OVERLAYS.get(front_pos, 'bullseye'), faces, ) @@ -725,8 +713,7 @@ def export( # We need to make a placement helper. helper = vmf.create_ent( 'info_placement_helper', - angles=tile.normal.to_angle_roll( - tile.portal_helper_orient), + angles=Angle.from_basis(z=tile.portal_helper_orient, x=tile.normal), origin=front_pos + offset, force_placement=int(force_helper), snap_to_helper_angles=int(force_helper), @@ -743,7 +730,7 @@ def export( if offset: for brush in all_brushes: - brush.localise(offset, Vec()) + brush.localise(offset) if self.brush_ent is None: vmf.add_brushes(all_brushes) @@ -760,7 +747,7 @@ def position_bullseye(self, tile: 'TileDef', target: Entity) -> None: ) panel_top.localise( Vec.from_str(self.inst['origin']), - Vec.from_str(self.inst['angles']), + Angle.from_str(self.inst['angles']), ) else: panel_top = tile.pos + 64 * tile.normal From 78d1a16b596900dc2aa1d019fc3a5b18c2235594 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Fri, 1 Jan 2021 19:26:54 +1000 Subject: [PATCH 75/87] Simplify this code --- src/app/richTextBox.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/app/richTextBox.py b/src/app/richTextBox.py index 16fa94535..5e3f8ba54 100644 --- a/src/app/richTextBox.py +++ b/src/app/richTextBox.py @@ -111,7 +111,7 @@ def set_text(self, text_data: Union[str, tkMarkdown.MarkdownData]): """ # Remove all previous link commands - for tag, (command_id, func) in self.link_commands.items(): + for tag, command_id in self.link_commands.items(): self.tag_unbind(tag, '', funcid=command_id) self.link_commands.clear() @@ -134,12 +134,11 @@ def set_text(self, text_data: Union[str, tkMarkdown.MarkdownData]): raise ValueError('Unknown block {!r}?'.format(block_type)) for url, link_id in text_data.links.items(): - func = self.make_link_callback(url) self.link_commands[link_id] = self.tag_bind( link_id, '', self.make_link_callback(url), - ), func + ) self['state'] = "disabled" From 1fc3272a682c217890929d6084a4ad56d61d2c9e Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Fri, 1 Jan 2021 19:27:04 +1000 Subject: [PATCH 76/87] These modules won't be loaded anymore --- src/compiler.spec | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/compiler.spec b/src/compiler.spec index 5abb408d0..5351a6a20 100644 --- a/src/compiler.spec +++ b/src/compiler.spec @@ -47,11 +47,6 @@ EXCLUDES = [ 'win32evtlogutil', 'smtplib', 'http', - - # Pillow is imported by Srctools' VTF support, but we don't need to do that. - 'PIL', - - 'sqlite3', # Imported from aenum, but we don't use that enum subclass. ] # These also aren't required by logging really, but by default From b8a9fbc47fd25abcc3f289ad4f233102b37ad209 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Sat, 2 Jan 2021 13:52:54 +1000 Subject: [PATCH 77/87] Add utility which freezes enums getters, making them cheaper --- src/app/itemPropWin.py | 1 + src/precomp/texturing.py | 1 + src/precomp/tiling.py | 33 ++++++++++++------------ src/utils.py | 54 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 72 insertions(+), 17 deletions(-) diff --git a/src/app/itemPropWin.py b/src/app/itemPropWin.py index 217629e32..7b6e27c34 100644 --- a/src/app/itemPropWin.py +++ b/src/app/itemPropWin.py @@ -15,6 +15,7 @@ LOGGER = srctools.logger.get_logger(__name__) +@utils.freeze_enum_props class PropTypes(Enum): """Type of property to display.""" NONE = 'none' diff --git a/src/precomp/texturing.py b/src/precomp/texturing.py index 25dd0854f..392f6af15 100644 --- a/src/precomp/texturing.py +++ b/src/precomp/texturing.py @@ -123,6 +123,7 @@ def z(self) -> float: } +@utils.freeze_enum_props class TileSize(str, Enum): """Types of textures that can exist, for tile-type generators.""" TILE_1x1 = '1x1' # Full block diff --git a/src/precomp/tiling.py b/src/precomp/tiling.py index 56ae6378f..5beec4f83 100644 --- a/src/precomp/tiling.py +++ b/src/precomp/tiling.py @@ -124,6 +124,7 @@ }) +@utils.freeze_enum_props class TileType(Enum): """Physical types of geometry for each 1/4 tile.""" WHITE = 0 @@ -149,17 +150,17 @@ class TileType(Enum): @property def is_recess(self) -> bool: """Should this recess the surface?""" - return self.value in (22, 23) + return self.name.startswith('CUTOUT_TILE') @property def is_nodraw(self) -> bool: """Should this swap to nodraw?""" - return self.value == 10 + return self is self.NODRAW @property def blocks_pattern(self) -> bool: """Does this affect patterns?""" - return self.value != 22 + return self is not self.CUTOUT_TILE_BROKEN @property def is_tile(self) -> bool: @@ -169,31 +170,37 @@ def is_tile(self) -> bool: @property def is_white(self) -> bool: """Is this portalable?""" - return self.value in (0, 1) + return self.name.startswith('WHITE') @property def is_4x4(self) -> bool: """Is this forced to be 4x4 in size?""" - return self.value in (1, 3) + return '4x4' in self.name @property def color(self) -> texturing.Portalable: """The portalability of the tile.""" - if self.value in (0, 1): + if 'WHITE' in self.name: return texturing.Portalable.WHITE - elif self.value in (2, 3, 4): + elif 'BLACK' in self.name or self is self.GOO_SIDE: return texturing.Portalable.BLACK raise ValueError('No colour for ' + self.name + '!') @property def inverted(self) -> 'TileType': """Swap the color of a type.""" - return _tiletype_inverted.get(self, self) + if self is self.GOO_SIDE: + return self.WHITE_4x4 + if self.name.startswith('WHITE'): + return getattr(self, f'BLACK{self.name[5:]}') + if self.name.startswith('BLACK'): + return getattr(self, f'WHITE{self.name[5:]}') + return self @property def tile_size(self) -> TileSize: """The size of the tile this should force.""" - if self.value in (1, 3): + if '4x4' in self.name: return TileSize.TILE_4x4 else: return TileSize.TILE_1x1 @@ -212,13 +219,6 @@ def with_color_and_size( (TileSize.TILE_4x4, texturing.Portalable.BLACK): TileType.BLACK_4x4, (TileSize.TILE_4x4, texturing.Portalable.WHITE): TileType.WHITE_4x4, } -_tiletype_inverted = { - TileType.BLACK: TileType.WHITE, - TileType.WHITE: TileType.BLACK, - TileType.BLACK_4x4: TileType.WHITE_4x4, - TileType.WHITE_4x4: TileType.BLACK_4x4, - TileType.GOO_SIDE: TileType.WHITE_4x4, -} # Symbols that represent TileSize values. TILETYPE_TO_CHAR = { @@ -239,6 +239,7 @@ def with_color_and_size( } +@utils.freeze_enum_props class PanelType(Enum): """Special functionality for tiling panels.""" NORMAL = 'normal' diff --git a/src/utils.py b/src/utils.py index 3326ca5d5..f3e98f3fd 100644 --- a/src/utils.py +++ b/src/utils.py @@ -8,13 +8,14 @@ import sys from pathlib import Path from enum import Enum +from types import TracebackType from typing import ( Tuple, List, Set, Sequence, Iterator, Iterable, SupportsInt, Mapping, TypeVar, Any, Union, Callable, Generator, - KeysView, ValuesView, ItemsView, + KeysView, ValuesView, ItemsView, Type, ) try: @@ -403,6 +404,57 @@ class CONN_TYPES(Enum): del N, S, E, W RetT = TypeVar('RetT') +EnumT = TypeVar('EnumT', bound=Enum) +EnumTypeT = TypeVar('EnumTypeT', bound=Type[Enum]) + + +def freeze_enum_props(cls: EnumTypeT) -> EnumTypeT: + """Make a enum with property getters more efficent. + + Call the getter on each member, and then replace it with a dict lookup. + """ + ns = vars(cls) + for name, value in list(ns.items()): + if not isinstance(value, property) or value.fset is not None or value.fdel is not None: + continue + data = {} + data_exc = {} + + exc: Exception + for enum in cls: + try: + res = value.fget(enum) + except Exception as exc: + # The getter raised an exception, so we want to replicate + # that. So grab the traceback, and go back one frame to exclude + # ourselves from that. Then we can reraise making it look like + # it came from the original getter. + data_exc[enum] = (exc, exc.__traceback__.tb_next) + exc.__traceback__ = None + else: + data[enum] = res + if data_exc: + func = _exc_freeze(data, data_exc) + else: # If we don't raise, we can use the C-func + func = data.get + print(f'{cls}.{name} = {data}, {data_exc}') + setattr(cls, name, property(fget=func, doc=value.__doc__)) + return cls + + +def _exc_freeze( + data: Mapping[EnumT, RetT], + data_exc: Mapping[EnumT, Tuple[BaseException, TracebackType]], +) -> Callable[[EnumT], RetT]: + """If the property raises exceptions, we need to reraise them.""" + def getter(value: EnumT) -> RetT: + """Return the value, or re-raise the original exception.""" + try: + return data[value] + except KeyError: + exc, tb = data_exc[value] + raise exc.with_traceback(tb) from None + return getter class FuncLookup(Mapping[str, Callable[..., Any]]): From 5d5b763ff30620411e21f239b00e13330b52c01e Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Thu, 7 Jan 2021 17:01:08 +1000 Subject: [PATCH 78/87] Remove leftover print statement --- src/utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/utils.py b/src/utils.py index f3e98f3fd..e205c17cc 100644 --- a/src/utils.py +++ b/src/utils.py @@ -437,7 +437,6 @@ def freeze_enum_props(cls: EnumTypeT) -> EnumTypeT: func = _exc_freeze(data, data_exc) else: # If we don't raise, we can use the C-func func = data.get - print(f'{cls}.{name} = {data}, {data_exc}') setattr(cls, name, property(fget=func, doc=value.__doc__)) return cls From 74540d22417aeba49d6951555e8033212cd85755 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Thu, 7 Jan 2021 17:01:17 +1000 Subject: [PATCH 79/87] This is now the math module --- src/precomp/template_brush.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/precomp/template_brush.py b/src/precomp/template_brush.py index e620b2119..b436a9814 100644 --- a/src/precomp/template_brush.py +++ b/src/precomp/template_brush.py @@ -8,7 +8,7 @@ import srctools from srctools import Property -from srctools.vec import Vec, Angle, Matrix, to_matrix +from srctools.math import Vec, Angle, Matrix, to_matrix from srctools.vmf import EntityFixup, Entity, Solid, Side, VMF, UVAxis import srctools.logger From 9a57c6a53661e835073c1574e075acc4b5d1d2d1 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 13 Jan 2021 11:24:57 +1000 Subject: [PATCH 80/87] Allow using .bee_pack for package files instead of .zip --- src/packageLoader.py | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/packageLoader.py b/src/packageLoader.py index 8a5220b39..87ac5b978 100644 --- a/src/packageLoader.py +++ b/src/packageLoader.py @@ -19,7 +19,7 @@ VMF, Entity, Solid, VPK, ) -from srctools.filesys import FileSystem, get_filesystem, RawFileSystem +from srctools.filesys import FileSystem, RawFileSystem, ZipFileSystem, VPKFileSystem import srctools.logger from typing import ( @@ -341,15 +341,23 @@ def find_packages(pak_dir: str) -> None: found_pak = False for name in os.listdir(pak_dir): # Both files and dirs name = os.path.join(pak_dir, name) - if name.endswith('.vpk') and not name.endswith('_dir.vpk'): + folded = name.casefold() + if folded.endswith('.vpk') and not folded.endswith('_dir.vpk'): # _000.vpk files, useless without the directory continue - try: - filesys = get_filesystem(name) - except ValueError: - LOGGER.info('Extra file: {}', name) - continue + if os.path.isdir(name): + filesys = RawFileSystem(name) + else: + ext = os.path.splitext(folded)[1] + LOGGER.debug('Package "{}" has ext {}', name, ext) + if ext in ('.bee_pack', '.zip'): + filesys = ZipFileSystem(name) + elif ext == '.vpk': + filesys = VPKFileSystem(name) + else: + LOGGER.info('Extra file: {}', name) + continue LOGGER.debug('Reading package "' + name + '"') @@ -381,6 +389,12 @@ def find_packages(pak_dir: str) -> None: filesys.close_ref() raise + if pak_id in packages: + raise ValueError( + f'Duplicate package with id "{pak_id}"!\n' + 'If you just updated the mod, delete any old files in packages/.' + ) from None + PACKAGE_SYS[pak_id] = filesys packages[pak_id] = Package( From a3a2639de635469f19cc7d45246635502e9bc973 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 13 Jan 2021 11:26:07 +1000 Subject: [PATCH 81/87] Remove this debug value --- src/packageLoader.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/packageLoader.py b/src/packageLoader.py index 87ac5b978..a13686ae0 100644 --- a/src/packageLoader.py +++ b/src/packageLoader.py @@ -350,7 +350,6 @@ def find_packages(pak_dir: str) -> None: filesys = RawFileSystem(name) else: ext = os.path.splitext(folded)[1] - LOGGER.debug('Package "{}" has ext {}', name, ext) if ext in ('.bee_pack', '.zip'): filesys = ZipFileSystem(name) elif ext == '.vpk': From d813d4ad7941f47c267dab1a9905d13f88d4b3c3 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 13 Jan 2021 12:51:35 +1000 Subject: [PATCH 82/87] Fix BEEmod/BEE2-items#3540: Prevent signage from being style-retextured --- src/precomp/conditions/signage.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/precomp/conditions/signage.py b/src/precomp/conditions/signage.py index a90077175..8d67c7ab9 100644 --- a/src/precomp/conditions/signage.py +++ b/src/precomp/conditions/signage.py @@ -7,6 +7,7 @@ import consts from srctools import Property, Entity, VMF, Vec, NoKeyError from srctools.vmf import make_overlay, Side +import vbsp COND_MOD_NAME = None @@ -252,6 +253,7 @@ def place_sign( material=texture, surfaces=faces, ) + vbsp.IGNORED_OVERLAYS.add(over) over['startu'] = '1' over['endu'] = '0' From 54c6147357df99f161c0ac6a732313fcddc49068 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Wed, 13 Jan 2021 13:18:17 +1000 Subject: [PATCH 83/87] Don't spawn in these debug entities. --- src/precomp/tiling.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/precomp/tiling.py b/src/precomp/tiling.py index 5beec4f83..a0de7886a 100644 --- a/src/precomp/tiling.py +++ b/src/precomp/tiling.py @@ -2120,7 +2120,6 @@ def generate_brushes(vmf: VMF) -> None: u_axis, bbox_min[u_axis] + 128 * min_u - 64, v_axis, bbox_min[v_axis] + 128 * min_v - 64, ) - vmf.create_ent('info_null', origin=tile_min) front.uaxis.offset = (Vec.dot(tile_min, front.uaxis.vec()) / 0.25) % (256/0.25) front.vaxis.offset = (Vec.dot(tile_min, front.vaxis.vec()) / 0.25) % (256/0.25) if gen.options['scaleup256']: From f2fb0f230b1704077785add475f23a69da0c3dc6 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Thu, 14 Jan 2021 14:28:32 +1000 Subject: [PATCH 84/87] Update localisation masters --- i18n/es.po | 389 +++++++++++++++++++++++++++++------------------------ i18n/fr.po | 328 +++++++++++++++++++++----------------------- i18n/ja.po | 234 ++++++++++++++++---------------- i18n/zh.po | 235 ++++++++++++++++---------------- 4 files changed, 609 insertions(+), 577 deletions(-) diff --git a/i18n/es.po b/i18n/es.po index ac43436a5..af83b9534 100644 --- a/i18n/es.po +++ b/i18n/es.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2020-09-20 10:31-0700\n" +"POT-Creation-Date: 2021-01-14 14:25+1000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: es\n" @@ -12,7 +12,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.8.0\n" +"Generated-By: Babel 2.6.0\n" #: loadScreen.py:199 msgid "Skipped!" @@ -22,7 +22,7 @@ msgstr "¡Saltado!" msgid "Version: " msgstr "Versión: " -#: app/optionWindow.py:259 app/packageMan.py:116 app/selector_win.py:718 +#: app/optionWindow.py:260 app/packageMan.py:116 app/selector_win.py:718 #: loadScreen.py:201 msgid "Cancel" msgstr "Cancelar" @@ -47,7 +47,7 @@ msgstr "Iniciando Interfaz" msgid "Better Extended Editor for Portal 2" msgstr "" -#: utils.py:841 +#: utils.py:892 msgid "__LANG_USE_SANS_SERIF__" msgstr "" @@ -117,8 +117,9 @@ msgstr "Pasillo" msgid "" "Randomly choose a corridor. This is saved in the puzzle data and will not" " change." -msgstr "Seleccionar un pasillo de forma aleatoria. Esto es guardado en los" -" datos del puzzle y no cambiará." +msgstr "" +"Seleccionar un pasillo de forma aleatoria. Esto es guardado en los datos " +"del puzzle y no cambiará." #: app/CompilerPane.py:320 app/UI.py:664 msgid "Random" @@ -132,9 +133,9 @@ msgstr "Archivos de Imagenes" msgid "" "Options on this panel can be changed \n" "without exporting or restarting the game." -msgstr "Las opciones en este panel se pueden" -" cambiar sin hacer falta exportar o reiniciar" -" el juego." +msgstr "" +"Las opciones en este panel se pueden cambiar sin hacer falta exportar o " +"reiniciar el juego." #: app/CompilerPane.py:517 msgid "Map Settings" @@ -244,9 +245,9 @@ msgid "" "When compiling, dump all files which were packed into the map. Useful if " "you're intending to edit maps in Hammer." msgstr "" -"Al momento en que se compila el mapa, vuelca todos los archivos que fueron" -" empacados dentro del mapa. Útil si tienes la intención de editar los " -"mapas en Hammer." +"Al momento en que se compila el mapa, vuelca todos los archivos que " +"fueron empacados dentro del mapa. Útil si tienes la intención de editar " +"los mapas en Hammer." #: app/CompilerPane.py:693 msgid "Last Compile:" @@ -413,7 +414,8 @@ msgstr "" "necesario." #: app/StyleVarPane.py:72 -msgid "Light Reversible Funnels" +#, fuzzy +msgid "Light Reversible Excursion Funnels" msgstr "Iluminar Embudos de Translación Reversibles" #: app/StyleVarPane.py:74 @@ -422,11 +424,12 @@ msgid "" "near each other and can reverse polarity, this can cause lighting issues." " Disable this to prevent that by disabling lights. Non-reversible Funnels" " do not have this issue." -msgstr "Los Embudos de Translación emiten una pequeña cantidad de luz. " -"Aunque, si hay múltiples Embudos de Translación cerca de otros que puedan" -" revertir su polaridad, la iluminación podría verse afectada." -"Deshabilita esto para prevenir esto desabilitando las luces. Los Embudos" -" de translación no reversibles no tienen este problema." +msgstr "" +"Los Embudos de Translación emiten una pequeña cantidad de luz. Aunque, si" +" hay múltiples Embudos de Translación cerca de otros que puedan revertir " +"su polaridad, la iluminación podría verse afectada.Deshabilita esto para " +"prevenir esto desabilitando las luces. Los Embudos de translación no " +"reversibles no tienen este problema." #: app/StyleVarPane.py:82 msgid "Enable Shape Framing" @@ -436,8 +439,9 @@ msgstr "Habilitar el encuadre de formas" msgid "" "After 10 shape-type antlines are used, the signs repeat. With this " "enabled, colored frames will be added to distinguish them." -msgstr "Después de usar 10 indicador de forma, los carteles se repiten." -" Con esto activado, se añadirán marcos coloreados para poder distingirlos." +msgstr "" +"Después de usar 10 indicador de forma, los carteles se repiten. Con esto " +"activado, se añadirán marcos coloreados para poder distingirlos." #: app/StyleVarPane.py:153 msgid "Default: On" @@ -626,8 +630,9 @@ msgid "" msgstr "" "\n" "\n" -"Atención: Los archivos VPK no han sido exportados. Cierre Portal 2 y Hammer" -" para asegurarse de que las vistas previas de las paredes del editor han cambiado." +"Atención: Los archivos VPK no han sido exportados. Cierre Portal 2 y " +"Hammer para asegurarse de que las vistas previas de las paredes del " +"editor han cambiado." #: app/UI.py:1131 msgid "Delete Palette \"{}\"" @@ -645,7 +650,7 @@ msgstr "Introduzca un nombre:" msgid "This palette already exists. Overwrite?" msgstr "Esta paleta ya existe. ¿Desea reemplazarla?" -#: app/UI.py:1249 app/gameMan.py:1527 +#: app/UI.py:1249 app/gameMan.py:1525 msgid "Are you sure you want to delete \"{}\"?" msgstr "¿Estas seguro que deseas borrar \"{}\"?" @@ -697,8 +702,9 @@ msgstr "Vid Elev: " msgid "" "Enable or disable particular voice lines, to prevent them from being " "added." -msgstr "Habilita o deshabilita ciertas lineas de voces, para prevenir" -" que sean añadidas." +msgstr "" +"Habilita o deshabilita ciertas lineas de voces, para prevenir que sean " +"añadidas." #: app/UI.py:1534 msgid "All Items: " @@ -737,7 +743,7 @@ msgstr "Administrar Paquetes..." msgid "Options" msgstr "Ociones" -#: app/UI.py:1730 app/gameMan.py:1206 +#: app/UI.py:1730 app/gameMan.py:1204 msgid "Quit" msgstr "Salir" @@ -787,7 +793,9 @@ msgstr "Eliminando mapas" #: app/backup.py:140 msgid "Failed to parse this puzzle file. It can still be backed up." -msgstr "Error al analizar este mapa. Sigue siendo posible hacer una copia de seguridad." +msgstr "" +"Error al analizar este mapa. Sigue siendo posible hacer una copia de " +"seguridad." #: app/backup.py:144 msgid "No description found." @@ -899,129 +907,132 @@ msgstr "Mantener (Por Juego):" msgid "Backup/Restore Puzzles" msgstr "Copia De Seguridad / Restaurar Mapas" -#: app/contextWin.py:76 +#: app/contextWin.py:77 msgid "This item may not be rotated." msgstr "Este elemento no puede ser rotado." -#: app/contextWin.py:77 +#: app/contextWin.py:78 msgid "This item can be pointed in 4 directions." msgstr "Este elemento puede ser rotado en 4 direcciones." -#: app/contextWin.py:78 +#: app/contextWin.py:79 msgid "This item can be positioned on the sides and center." msgstr "Este elemento se puede colocar en los lados y en el centro." -#: app/contextWin.py:79 +#: app/contextWin.py:80 msgid "This item can be centered in two directions, plus on the sides." msgstr "Este elemento puede centrarse en dos direcciones y en los lados." -#: app/contextWin.py:80 +#: app/contextWin.py:81 msgid "This item can be placed like light strips." msgstr "Este elemento puede ser rotado como una banda luminosa." -#: app/contextWin.py:81 +#: app/contextWin.py:82 msgid "This item can be rotated on the floor to face 360 degrees." msgstr "Este elemento se puede rotar en el piso para hacer frente a 360 grados." -#: app/contextWin.py:82 +#: app/contextWin.py:83 msgid "This item is positioned using a catapult trajectory." -msgstr "Este elemento se posiciona mediante la trayectoria de la plataforma de salto." +msgstr "" +"Este elemento se posiciona mediante la trayectoria de la plataforma de " +"salto." -#: app/contextWin.py:83 +#: app/contextWin.py:84 msgid "This item positions the dropper to hit target locations." msgstr "" "Este elemento posiciona el dispensador para alcanzar las ubicaciones del " "objetivo." -#: app/contextWin.py:85 +#: app/contextWin.py:86 msgid "This item does not accept any inputs." msgstr "Este elemento no acepta ninguna conexión entrante." -#: app/contextWin.py:86 +#: app/contextWin.py:87 msgid "This item accepts inputs." msgstr "Este elemento acepta conexiones entrantes." -#: app/contextWin.py:87 +#: app/contextWin.py:88 msgid "This item has two input types (A and B), using the Input A and B items." -msgstr "Este ítem tiene dos tipos de entrada (A y B), usando los ítems de" -" Entrada A y Entrada B." +msgstr "" +"Este ítem tiene dos tipos de entrada (A y B), usando los ítems de Entrada" +" A y Entrada B." -#: app/contextWin.py:89 +#: app/contextWin.py:90 msgid "This item does not output." msgstr "Este elemento no tiene conexiones de salida." -#: app/contextWin.py:90 +#: app/contextWin.py:91 msgid "This item has an output." msgstr "Este elemento tiene conexiones de salida." -#: app/contextWin.py:91 +#: app/contextWin.py:92 msgid "This item has a timed output." msgstr "Este elemento tiene conexiones de salida temporizadas." -#: app/contextWin.py:93 +#: app/contextWin.py:94 msgid "This item does not take up any space inside walls." msgstr "Este elemento no ocupa ningún espacio dentro de las paredes." -#: app/contextWin.py:94 +#: app/contextWin.py:95 msgid "This item takes space inside the wall." msgstr "Este elemento ocupa espacio dentro de las paredes." -#: app/contextWin.py:96 +#: app/contextWin.py:97 msgid "This item cannot be placed anywhere..." msgstr "Este elemento no puede ser colocado en ningún lado..." -#: app/contextWin.py:97 +#: app/contextWin.py:98 msgid "This item can only be attached to ceilings." msgstr "Este elemento solo puede ser colocado en los techos." -#: app/contextWin.py:98 +#: app/contextWin.py:99 msgid "This item can only be placed on the floor." msgstr "Este elemento solo puede ser colocado en el suelo." -#: app/contextWin.py:99 +#: app/contextWin.py:100 msgid "This item can be placed on floors and ceilings." msgstr "Este elemento puede ser colocado en los techos y el suelo." -#: app/contextWin.py:100 +#: app/contextWin.py:101 msgid "This item can be placed on walls only." msgstr "Este elemento solo puede ser colocado en las paredes." -#: app/contextWin.py:101 +#: app/contextWin.py:102 msgid "This item can be attached to walls and ceilings." msgstr "Este elemento puede ser colocado en las paredes y los techos." -#: app/contextWin.py:102 +#: app/contextWin.py:103 msgid "This item can be placed on floors and walls." msgstr "Este elemento puede ser colocado en el suelo y las paredes." -#: app/contextWin.py:103 +#: app/contextWin.py:104 msgid "This item can be placed in any orientation." msgstr "Este elemento puede ser colocado en el suelo, paredes y techos." -#: app/contextWin.py:209 +#: app/contextWin.py:210 #, fuzzy msgid "No Alternate Versions" msgstr "No hay otras versiones" -#: app/contextWin.py:301 +#: app/contextWin.py:308 msgid "Excursion Funnels accept a on/off input and a directional input." msgstr "" -"Los Embudos de Translación aceptan una conexión de activación/desactivación, así" -" como una conexión direccional." +"Los Embudos de Translación aceptan una conexión de " +"activación/desactivación, así como una conexión direccional." -#: app/contextWin.py:358 +#: app/contextWin.py:365 #, fuzzy msgid "" "This item can be rotated on the floor to face 360 degrees, for Reflection" " Cubes only." msgstr "Este elemento se puede rotar en el piso para hacer frente a 360 grados." -#: app/contextWin.py:437 +#: app/contextWin.py:444 #, fuzzy msgid "Properties:" msgstr "Propiedades:" -#: app/contextWin.py:459 +#: app/contextWin.py:470 msgid "" "The number of entities used for this item. The Source engine limits this " "to 2048 in total. This provides a guide to how many of these items can be" @@ -1031,11 +1042,11 @@ msgstr "" "límite de 2048 en total. Esto proporciona una guía de cuantos de estos " "elementos pueden ser puestos en un mapa." -#: app/contextWin.py:484 +#: app/contextWin.py:495 msgid "Description:" msgstr "Descripción:" -#: app/contextWin.py:527 +#: app/contextWin.py:538 msgid "" "Failed to open a web browser. Do you wish for the URL to be copied to the" " clipboard instead?" @@ -1043,91 +1054,93 @@ msgstr "" "Error al abrir un navegador web. ¿Desea que la URL sea copiada en el " "portapapeles?" -#: app/contextWin.py:541 +#: app/contextWin.py:552 msgid "More Info>>" msgstr "Más Info>>" -#: app/contextWin.py:558 +#: app/contextWin.py:569 msgid "Change Defaults..." msgstr "Cambiar Ajustes por Defecto..." -#: app/contextWin.py:564 +#: app/contextWin.py:575 msgid "Change the default settings for this item when placed." msgstr "" "Cambia la configuración predeterminada de este elemento cuando es " "colocado en el mapa." -#: app/gameMan.py:748 app/gameMan.py:850 +#: app/gameMan.py:746 app/gameMan.py:848 msgid "BEE2 - Export Failed!" msgstr "BEE2 - ¡Exportación Fallida!" -#: app/gameMan.py:749 +#: app/gameMan.py:747 msgid "" "Compiler file {file} missing. Exit Steam applications, then press OK to " "verify your game cache. You can then export again." -msgstr "Falta archivo de compilador {file}. Salga de las aplicaciones de Steam," -" y pulse OK para verificar la integridad de los archivos. Después, podrás " +msgstr "" +"Falta archivo de compilador {file}. Salga de las aplicaciones de Steam, y" +" pulse OK para verificar la integridad de los archivos. Después, podrás " "exportar de nuevo." -#: app/gameMan.py:851 +#: app/gameMan.py:849 #, fuzzy msgid "Copying compiler file {file} failed. Ensure {game} is not running." msgstr "" -"Fallo a la hora de copiar el archivo de compilador {file}. Asegurese de que " -"{game} no esta abierto.\n" +"Fallo a la hora de copiar el archivo de compilador {file}. Asegurese de " +"que {game} no esta abierto.\n" -#: app/gameMan.py:1263 +#: app/gameMan.py:1261 msgid "" "Ap-Tag Coop gun instance not found!\n" "Coop guns will not work - verify cache to fix." -msgstr "¡No se ha encontrado la instancia de la pistola de Ap-Tag de Coop!\n" -"Las pistolas del Coop no funcionarán. Verifique la integridad de los" -" archivos para reparar el error." +msgstr "" +"¡No se ha encontrado la instancia de la pistola de Ap-Tag de Coop!\n" +"Las pistolas del Coop no funcionarán. Verifique la integridad de los " +"archivos para reparar el error." -#: app/gameMan.py:1267 +#: app/gameMan.py:1265 msgid "BEE2 - Aperture Tag Files Missing" msgstr "BEE2 - Falta de archivos de Aperture Tag" -#: app/gameMan.py:1450 +#: app/gameMan.py:1448 msgid "Select the folder where the game executable is located ({appname})..." msgstr "" "Selecciona el directorio donde se encuentre el ejecutable del juego " "({appname})..." -#: app/gameMan.py:1453 app/gameMan.py:1468 app/gameMan.py:1478 -#: app/gameMan.py:1485 app/gameMan.py:1494 app/gameMan.py:1503 +#: app/gameMan.py:1451 app/gameMan.py:1466 app/gameMan.py:1476 +#: app/gameMan.py:1483 app/gameMan.py:1492 app/gameMan.py:1501 msgid "BEE2 - Add Game" msgstr "BEE2 - Añadir juego" -#: app/gameMan.py:1456 +#: app/gameMan.py:1454 msgid "Find Game Exe" msgstr "Encontrar Ejecutable del Juego" -#: app/gameMan.py:1457 +#: app/gameMan.py:1455 msgid "Executable" msgstr "Ejecutable" -#: app/gameMan.py:1465 +#: app/gameMan.py:1463 msgid "This does not appear to be a valid game folder!" msgstr "¡Eso no parece ser un directorio de juego valido!" -#: app/gameMan.py:1475 +#: app/gameMan.py:1473 msgid "Portal Stories: Mel doesn't have an editor!" msgstr "¡Portal Stories: Mel no tiene un editor!" -#: app/gameMan.py:1486 +#: app/gameMan.py:1484 msgid "Enter the name of this game:" msgstr "Inserte el nombre de este juego:" -#: app/gameMan.py:1493 +#: app/gameMan.py:1491 msgid "This name is already taken!" msgstr "¡Este nombre ya está en uso!" -#: app/gameMan.py:1502 +#: app/gameMan.py:1500 msgid "Please enter a name for this game!" msgstr "¡Por favor introduzca un nombre a este juego!" -#: app/gameMan.py:1521 +#: app/gameMan.py:1519 msgid "" "\n" " (BEE2 will quit, this is the last game set!)" @@ -1183,7 +1196,7 @@ msgstr "" msgid "Thinking With Time Machine" msgstr "" -#: app/helpMenu.py:238 app/itemPropWin.py:342 +#: app/helpMenu.py:238 app/itemPropWin.py:343 msgid "Close" msgstr "Cerrar" @@ -1199,15 +1212,15 @@ msgstr "Créditos de BEE2" msgid "Credits..." msgstr "Créditos..." -#: app/itemPropWin.py:38 +#: app/itemPropWin.py:39 msgid "Start Position" msgstr "Posición de Inicio" -#: app/itemPropWin.py:39 +#: app/itemPropWin.py:40 msgid "End Position" msgstr "Posición de Salida" -#: app/itemPropWin.py:40 +#: app/itemPropWin.py:41 msgid "" "Delay \n" "(0=infinite)" @@ -1215,7 +1228,7 @@ msgstr "" "Retraso\n" "(0=infinito)" -#: app/itemPropWin.py:341 +#: app/itemPropWin.py:342 msgid "No Properties available!" msgstr "¡No hay propiedades disponibles!" @@ -1266,8 +1279,9 @@ msgstr "" msgid "" "Add no music to the map at all. Testing Element-specific music may still " "be added." -msgstr "No añadir ninguna música de fondo al mapa. La música de ciertos " -"elementos de prueba específicos puede que sea añadida." +msgstr "" +"No añadir ninguna música de fondo al mapa. La música de ciertos elementos" +" de prueba específicos puede que sea añadida." #: app/music_conf.py:143 msgid "Propulsion Gel SFX" @@ -1292,13 +1306,11 @@ msgstr "Selecciona la música del Embudo de Translación" #: app/music_conf.py:154 msgid "Set the music used while inside Excursion Funnels." -msgstr "Selecciona la música usada al estar dentro de los" -" Embudos de Translación." +msgstr "Selecciona la música usada al estar dentro de los Embudos de Translación." #: app/music_conf.py:157 msgid "Have no music playing when inside funnels." -msgstr "No hay música al estar dentro de los Embudos de" -" translación." +msgstr "No hay música al estar dentro de los Embudos de translación." #: app/music_conf.py:168 msgid "Select Repulsion Gel Music" @@ -1321,8 +1333,9 @@ msgstr "Seleccionar la música del Gel de Repulsión" msgid "" "Select music played when players have large amounts of horizontal " "velocity." -msgstr "Selecciona la música que se reproduce cuando los jugadores " -" tienen una alta velocidad horizontal." +msgstr "" +"Selecciona la música que se reproduce cuando los jugadores tienen una " +"alta velocidad horizontal." #: app/music_conf.py:184 msgid "Add no music while running fast." @@ -1344,208 +1357,225 @@ msgstr "Rebotar:" msgid "Speed:" msgstr "Velocidad:" -#: app/optionWindow.py:45 +#: app/optionWindow.py:46 msgid "" "\n" "Launch Game?" msgstr "" -#: app/optionWindow.py:47 +#: app/optionWindow.py:48 msgid "" "\n" "Minimise BEE2?" msgstr "" -#: app/optionWindow.py:48 +#: app/optionWindow.py:49 msgid "" "\n" "Launch Game and minimise BEE2?" msgstr "" -#: app/optionWindow.py:50 +#: app/optionWindow.py:51 msgid "" "\n" "Quit BEE2?" msgstr "" -#: app/optionWindow.py:51 +#: app/optionWindow.py:52 msgid "" "\n" "Launch Game and quit BEE2?" msgstr "" -#: app/optionWindow.py:70 +#: app/optionWindow.py:71 msgid "BEE2 Options" msgstr "Opciones de BEE2" -#: app/optionWindow.py:108 +#: app/optionWindow.py:109 msgid "" "Package cache times have been reset. These will now be extracted during " "the next export." -msgstr "La fecha de los archivos cache de los paquetes se ha reseteado. Estos" -" serán extraídos durante la siguiente exportación." +msgstr "" +"La fecha de los archivos cache de los paquetes se ha reseteado. Estos " +"serán extraídos durante la siguiente exportación." -#: app/optionWindow.py:125 +#: app/optionWindow.py:126 msgid "\"Preserve Game Resources\" has been disabled." msgstr "\"Preservar Recursos del Juego\" se ha desabilitado." -#: app/optionWindow.py:137 +#: app/optionWindow.py:138 #, fuzzy msgid "Packages Reset" msgstr "Resetear Paquetes" -#: app/optionWindow.py:218 +#: app/optionWindow.py:219 msgid "General" msgstr "General" -#: app/optionWindow.py:224 +#: app/optionWindow.py:225 msgid "Windows" msgstr "Ventanas" -#: app/optionWindow.py:230 +#: app/optionWindow.py:231 msgid "Development" msgstr "Desarollo" -#: app/optionWindow.py:254 app/packageMan.py:110 app/selector_win.py:696 +#: app/optionWindow.py:255 app/packageMan.py:110 app/selector_win.py:696 msgid "OK" msgstr "Vale" -#: app/optionWindow.py:285 +#: app/optionWindow.py:286 msgid "After Export:" msgstr "Después de la Exportación:" -#: app/optionWindow.py:302 +#: app/optionWindow.py:303 msgid "Do Nothing" msgstr "No hacer nada" -#: app/optionWindow.py:308 +#: app/optionWindow.py:309 msgid "Minimise BEE2" msgstr "Minimizar BEE2" -#: app/optionWindow.py:314 +#: app/optionWindow.py:315 msgid "Quit BEE2" msgstr "Cerrar BEE2" -#: app/optionWindow.py:322 +#: app/optionWindow.py:323 msgid "After exports, do nothing and keep the BEE2 in focus." msgstr "Después de exportar, no hacer nada y mantener BEE2 abierto." -#: app/optionWindow.py:324 +#: app/optionWindow.py:325 msgid "After exports, minimise to the taskbar/dock." msgstr "Después de exportar, minimizar a la barra de tareas/bandeja." -#: app/optionWindow.py:325 +#: app/optionWindow.py:326 msgid "After exports, quit the BEE2." msgstr "Después de exportar, salir de BEE2." -#: app/optionWindow.py:332 +#: app/optionWindow.py:333 msgid "Launch Game" msgstr "Ejecutar Juego" -#: app/optionWindow.py:333 +#: app/optionWindow.py:334 msgid "After exporting, launch the selected game automatically." msgstr "Después de exportar, ejecutar el juego seleccionado automáticamente." -#: app/optionWindow.py:341 app/optionWindow.py:347 +#: app/optionWindow.py:342 app/optionWindow.py:348 msgid "Play Sounds" msgstr "Reproducir Sonidos" -#: app/optionWindow.py:352 +#: app/optionWindow.py:353 msgid "" "Pyglet is either not installed or broken.\n" "Sound effects have been disabled." -msgstr "Pyglet no está instalado, o está roto.\n" +msgstr "" +"Pyglet no está instalado, o está roto.\n" "Los efectos de sonido se han desabilitado." -#: app/optionWindow.py:359 +#: app/optionWindow.py:360 msgid "Reset Package Caches" msgstr "Resetear la caché de los Paquetes" -#: app/optionWindow.py:365 +#: app/optionWindow.py:366 msgid "Force re-extracting all package resources." msgstr "Forzar la re-extracción de todos los recursos de los paquetes." -#: app/optionWindow.py:374 +#: app/optionWindow.py:375 msgid "Keep windows inside screen" msgstr "Mantener ventanas dentro de la pantalla" -#: app/optionWindow.py:375 +#: app/optionWindow.py:376 msgid "" "Prevent sub-windows from moving outside the screen borders. If you have " "multiple monitors, disable this." -msgstr "Prevenir el movimiento de las sub-ventanas fuera de los bordes de pantalla." -" Si tienes varios monitores, deshabilita esta opción." +msgstr "" +"Prevenir el movimiento de las sub-ventanas fuera de los bordes de " +"pantalla. Si tienes varios monitores, deshabilita esta opción." -#: app/optionWindow.py:385 +#: app/optionWindow.py:386 #, fuzzy msgid "Keep loading screens on top" msgstr "Mantener pantallas de carga encima" -#: app/optionWindow.py:387 +#: app/optionWindow.py:388 msgid "" "Force loading screens to be on top of other windows. Since they don't " "appear on the taskbar/dock, they can't be brought to the top easily " "again." -msgstr "Forzar que las pantallas de carga aparezcan encima de otras ventanas." -" Como no aparecen en la barra de tareas/bandeja, no es posible moverlas encima" -" facilmente." +msgstr "" +"Forzar que las pantallas de carga aparezcan encima de otras ventanas. " +"Como no aparecen en la barra de tareas/bandeja, no es posible moverlas " +"encima facilmente." -#: app/optionWindow.py:396 +#: app/optionWindow.py:397 msgid "Reset All Window Positions" msgstr "Resetear la posición de todas las ventanas" -#: app/optionWindow.py:410 +#: app/optionWindow.py:411 msgid "Log missing entity counts" msgstr "Registrar cuenta de entidades que faltan" -#: app/optionWindow.py:411 +#: app/optionWindow.py:412 msgid "" "When loading items, log items with missing entity counts in their " "properties.txt file." -msgstr "Cuando se cargan ítems, registrar ítems que faltan de entidades" -" en el archivo properties.txt." +msgstr "" +"Cuando se cargan ítems, registrar ítems que faltan de entidades en el " +"archivo properties.txt." -#: app/optionWindow.py:419 +#: app/optionWindow.py:420 msgid "Log when item doesn't have a style" msgstr "Registrar cuando un ítem no tiene un estilo" -#: app/optionWindow.py:420 +#: app/optionWindow.py:421 msgid "" "Log items have no applicable version for a particular style.This usually " "means it will look very bad." -msgstr "Registrar ítems que no tienen una versión aplicable para un estilo en" -" particular. Esto usualmente significa que lucirá muy mal." +msgstr "" +"Registrar ítems que no tienen una versión aplicable para un estilo en " +"particular. Esto usualmente significa que lucirá muy mal." -#: app/optionWindow.py:428 +#: app/optionWindow.py:429 msgid "Log when item uses parent's style" msgstr "Registrar cuando un ítem usa el estilo del padre" -#: app/optionWindow.py:429 +#: app/optionWindow.py:430 msgid "" "Log when an item reuses a variant from a parent style (1970s using 1950s " "items, for example). This is usually fine, but may need to be fixed." -msgstr "Registrar cuando un ítem usa una variante de un estilo padre (1970s" -" usando ítems de 1950s, por ejemplo). Esto normalmente está bien, pero" -" puede que tenga que ser reparado." +msgstr "" +"Registrar cuando un ítem usa una variante de un estilo padre (1970s " +"usando ítems de 1950s, por ejemplo). Esto normalmente está bien, pero " +"puede que tenga que ser reparado." -#: app/optionWindow.py:438 +#: app/optionWindow.py:439 msgid "Log missing packfile resources" msgstr "Registrar recursos packfile que faltan" -#: app/optionWindow.py:439 +#: app/optionWindow.py:440 msgid "" "Log when the resources a \"PackList\" refers to are not present in the " "zip. This may be fine (in a prerequisite zip), but it often indicates an " "error." -msgstr "Registrar cuando los recursos a los que \"PackList\" se refiere no se encuentran" -" presentes en el zip. Esto puede estar bien (en un zip requerido), pero " -"normalmente indica un error." +msgstr "" +"Registrar cuando los recursos a los que \"PackList\" se refiere no se " +"encuentran presentes en el zip. Esto puede estar bien (en un zip " +"requerido), pero normalmente indica un error." -#: app/optionWindow.py:448 +#: app/optionWindow.py:450 +#, fuzzy +msgid "Development Mode" +msgstr "Desarollo" + +#: app/optionWindow.py:451 +msgid "Enables displaying additional UI specific for development purposes." +msgstr "" + +#: app/optionWindow.py:459 msgid "Preserve Game Directories" msgstr "Preservar Directorios del Juego" -#: app/optionWindow.py:450 +#: app/optionWindow.py:461 msgid "" "When exporting, do not copy resources to \n" "\"bee2/\" and \"sdk_content/maps/bee2/\".\n" @@ -1554,36 +1584,36 @@ msgid "" msgstr "" "Al exportar, no copiar recursos a \n" "\"bee2/\" y \"sdk_content/maps/bee2/\".\n" -"Activar si estás desarrollando nuevo contenido, para asegurarse de" -" que este no sea reemplazado." +"Activar si estás desarrollando nuevo contenido, para asegurarse de que " +"este no sea reemplazado." -#: app/optionWindow.py:461 +#: app/optionWindow.py:472 msgid "Show Log Window" msgstr "Mostrar la Ventana Log" -#: app/optionWindow.py:463 +#: app/optionWindow.py:474 msgid "Show the log file in real-time." msgstr "Mostrar el archivo log en tiempo real." -#: app/optionWindow.py:470 +#: app/optionWindow.py:481 msgid "Force Editor Models" msgstr "Forzar Modelos de Editor" -#: app/optionWindow.py:471 +#: app/optionWindow.py:482 msgid "" "Make all props_map_editor models available for use. Portal 2 has a limit " "of 1024 models loaded in memory at once, so we need to disable unused " "ones to free this up." -msgstr "Hacer todos los modelos props_map_editor disponibles para uso. " -"Portal 2 tiene un límite the 1024 modelos cargados en memoria al mismo" -" tiempo, por lo que necesitamos desabilitar los no usados para liberar" -" memoria." +msgstr "" +"Hacer todos los modelos props_map_editor disponibles para uso. Portal 2 " +"tiene un límite the 1024 modelos cargados en memoria al mismo tiempo, por" +" lo que necesitamos desabilitar los no usados para liberar memoria." -#: app/optionWindow.py:482 +#: app/optionWindow.py:493 msgid "Dump All objects" msgstr "Volcar TODOS los objectos" -#: app/optionWindow.py:488 +#: app/optionWindow.py:499 msgid "Dump Items list" msgstr "Lista de elementos volcados" @@ -1619,7 +1649,7 @@ msgstr "" msgid "Portal 2 Collapsed" msgstr "Portal 2 Colapsado" -#: app/richTextBox.py:152 +#: app/richTextBox.py:151 msgid "Open \"{}\" in the default browser?" msgstr "Abrir \"{}\" en el navegador predeterminado?" @@ -1653,7 +1683,7 @@ msgid_plural "Authors: {}" msgstr[0] "Autor: {}" msgstr[1] "Autores: {}" -#: app/selector_win.py:1137 +#: app/selector_win.py:1145 msgid "Color: R={r}, G={g}, B={b}" msgstr "Color: R={r}, G={g}, B={b} " @@ -1678,15 +1708,15 @@ msgstr "Etiquetas" msgid "Authors" msgstr "Autores" -#: app/tagsPane.py:157 +#: app/tagsPane.py:156 msgid "Any" msgstr "Cualquiera" -#: app/tagsPane.py:166 +#: app/tagsPane.py:165 msgid "All" msgstr "Todo" -#: app/tagsPane.py:192 +#: app/tagsPane.py:191 msgid "Available Tags (click):" msgstr "Etiquetas Disponibles (click)" @@ -1775,4 +1805,5 @@ msgstr "¡Sin nombre!" #: app/voiceEditor.py:456 msgid "No Name?" -msgstr "¿Sin nombre?" \ No newline at end of file +msgstr "¿Sin nombre?" + diff --git a/i18n/fr.po b/i18n/fr.po index 3b0bbee96..e9b85d2c2 100644 --- a/i18n/fr.po +++ b/i18n/fr.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: BEEMOD2\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2020-09-20 10:31-0700\n" +"POT-Creation-Date: 2021-01-14 14:25+1000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: fr\n" @@ -12,7 +12,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.8.0\n" +"Generated-By: Babel 2.6.0\n" #: loadScreen.py:199 msgid "Skipped!" @@ -22,7 +22,7 @@ msgstr "Sauté !" msgid "Version: " msgstr "Version: " -#: app/optionWindow.py:259 app/packageMan.py:116 app/selector_win.py:718 +#: app/optionWindow.py:260 app/packageMan.py:116 app/selector_win.py:718 #: loadScreen.py:201 msgid "Cancel" msgstr "Annuler" @@ -47,7 +47,7 @@ msgstr "Initialisation de l'interface" msgid "Better Extended Editor for Portal 2" msgstr "Better Extended Editor pour Portal 2" -#: utils.py:841 +#: utils.py:892 msgid "__LANG_USE_SANS_SERIF__" msgstr "" @@ -118,7 +118,9 @@ msgstr "Couloir" msgid "" "Randomly choose a corridor. This is saved in the puzzle data and will not" " change." -msgstr "Choisit un couloir aléatoire. Ceci est sauvegardé dans le data du puzzle et ne va pas changer." +msgstr "" +"Choisit un couloir aléatoire. Ceci est sauvegardé dans le data du puzzle " +"et ne va pas changer." #: app/CompilerPane.py:320 app/UI.py:664 msgid "Random" @@ -634,7 +636,7 @@ msgstr "Entrer un nom:" msgid "This palette already exists. Overwrite?" msgstr "Cette palette existe déjà. Remplacer ?" -#: app/UI.py:1249 app/gameMan.py:1527 +#: app/UI.py:1249 app/gameMan.py:1525 msgid "Are you sure you want to delete \"{}\"?" msgstr "Êtes-vous sûr de vouloir supprimer cette palette ?" @@ -726,7 +728,7 @@ msgstr "Gérer les paquets..." msgid "Options" msgstr "Options" -#: app/UI.py:1730 app/gameMan.py:1206 +#: app/UI.py:1730 app/gameMan.py:1204 msgid "Quit" msgstr "Quitter" @@ -896,126 +898,128 @@ msgstr "Nombre (par jeu):" msgid "Backup/Restore Puzzles" msgstr "Sauvegarder/Restaurer des puzzles" -#: app/contextWin.py:76 +#: app/contextWin.py:77 msgid "This item may not be rotated." msgstr "Cet objet ne peut pas être tourné." -#: app/contextWin.py:77 +#: app/contextWin.py:78 msgid "This item can be pointed in 4 directions." msgstr "Cet objet peut être pointé dans 4 directions." -#: app/contextWin.py:78 +#: app/contextWin.py:79 msgid "This item can be positioned on the sides and center." msgstr "Cet objet peut être positionné sur les côtés ou au centre." -#: app/contextWin.py:79 +#: app/contextWin.py:80 msgid "This item can be centered in two directions, plus on the sides." msgstr "Cet objet peut être centré sur deux directions et sur les côtés." -#: app/contextWin.py:80 +#: app/contextWin.py:81 msgid "This item can be placed like light strips." msgstr "Cet objet peut être placé comme une source lumineuse." -#: app/contextWin.py:81 +#: app/contextWin.py:82 msgid "This item can be rotated on the floor to face 360 degrees." msgstr "Cet objet peut être tourné sur le sol à 360°." -#: app/contextWin.py:82 +#: app/contextWin.py:83 msgid "This item is positioned using a catapult trajectory." msgstr "Cet objet est positionné avec une trajectoire de catapulte." -#: app/contextWin.py:83 +#: app/contextWin.py:84 msgid "This item positions the dropper to hit target locations." msgstr "Cet objet positionne le distributeur pour toucher des zones ciblées." -#: app/contextWin.py:85 +#: app/contextWin.py:86 msgid "This item does not accept any inputs." msgstr "Cet objet n'accepte pas de connexion entrante." -#: app/contextWin.py:86 +#: app/contextWin.py:87 msgid "This item accepts inputs." msgstr "Cet objet accepte des connexions entrantes." -#: app/contextWin.py:87 +#: app/contextWin.py:88 msgid "This item has two input types (A and B), using the Input A and B items." -msgstr "Cet objet a deux types d'entrée (A et B), utilisant les items Input A et B." +msgstr "" +"Cet objet a deux types d'entrée (A et B), utilisant les items Input A et " +"B." -#: app/contextWin.py:89 +#: app/contextWin.py:90 msgid "This item does not output." msgstr "Cet objet n'a pas de connexion sortante." -#: app/contextWin.py:90 +#: app/contextWin.py:91 msgid "This item has an output." msgstr "Cet objet a une connexion sortante." -#: app/contextWin.py:91 +#: app/contextWin.py:92 msgid "This item has a timed output." msgstr "Cet objet a une connexion sortante temporisée." -#: app/contextWin.py:93 +#: app/contextWin.py:94 msgid "This item does not take up any space inside walls." msgstr "Cet objet ne prend pas de place dans le mur." -#: app/contextWin.py:94 +#: app/contextWin.py:95 msgid "This item takes space inside the wall." msgstr "Cet objet prend de la place dans le mur." -#: app/contextWin.py:96 +#: app/contextWin.py:97 msgid "This item cannot be placed anywhere..." msgstr "Cet objet ne peut pas être placé." -#: app/contextWin.py:97 +#: app/contextWin.py:98 msgid "This item can only be attached to ceilings." msgstr "Cet objet est attaché au plafond seulement." -#: app/contextWin.py:98 +#: app/contextWin.py:99 msgid "This item can only be placed on the floor." msgstr "Cet objet est posé au sol seulement." -#: app/contextWin.py:99 +#: app/contextWin.py:100 msgid "This item can be placed on floors and ceilings." msgstr "Cet objet peut être placé au plafond et au sol." -#: app/contextWin.py:100 +#: app/contextWin.py:101 msgid "This item can be placed on walls only." msgstr "Cet objet ne se place que sur les murs." -#: app/contextWin.py:101 +#: app/contextWin.py:102 msgid "This item can be attached to walls and ceilings." msgstr "Cet objet peut être attaché au plafond et aux murs." -#: app/contextWin.py:102 +#: app/contextWin.py:103 msgid "This item can be placed on floors and walls." msgstr "Cet objet peut être placé au sol et aux murs." -#: app/contextWin.py:103 +#: app/contextWin.py:104 msgid "This item can be placed in any orientation." msgstr "Cet objet peut être placé dans n'importe quel sens." -#: app/contextWin.py:209 +#: app/contextWin.py:210 #, fuzzy msgid "No Alternate Versions" msgstr "Pas de versions alternatives !" -#: app/contextWin.py:301 +#: app/contextWin.py:308 msgid "Excursion Funnels accept a on/off input and a directional input." msgstr "" "Les Halos d'Excursion acceptent une connexion on/off et une connexion de " "polarité." -#: app/contextWin.py:358 +#: app/contextWin.py:365 #, fuzzy msgid "" "This item can be rotated on the floor to face 360 degrees, for Reflection" " Cubes only." msgstr "Cet objet peut être tourné sur le sol à 360°." -#: app/contextWin.py:437 +#: app/contextWin.py:444 #, fuzzy msgid "Properties:" msgstr "Propriétés" -#: app/contextWin.py:459 +#: app/contextWin.py:470 msgid "" "The number of entities used for this item. The Source engine limits this " "to 2048 in total. This provides a guide to how many of these items can be" @@ -1025,11 +1029,11 @@ msgstr "" "nombre d'entités à 2048 en tout. Ceci fournit un guide pour savoir " "combien de ces objets il est possible de placer à la fois sur la carte." -#: app/contextWin.py:484 +#: app/contextWin.py:495 msgid "Description:" msgstr "Description:" -#: app/contextWin.py:527 +#: app/contextWin.py:538 msgid "" "Failed to open a web browser. Do you wish for the URL to be copied to the" " clipboard instead?" @@ -1037,83 +1041,83 @@ msgstr "" "Échec de l'ouverture du navigateur. Voulez-vous que l'URL soit copiée " "dans le presse-papiers à la place ?" -#: app/contextWin.py:541 +#: app/contextWin.py:552 msgid "More Info>>" msgstr "Plus d'infos>>" -#: app/contextWin.py:558 +#: app/contextWin.py:569 msgid "Change Defaults..." msgstr "Changer les valeurs par défaut..." -#: app/contextWin.py:564 +#: app/contextWin.py:575 msgid "Change the default settings for this item when placed." msgstr "Changer les réglages par défaut pour cet objet lorsqu'il est placé." -#: app/gameMan.py:748 app/gameMan.py:850 +#: app/gameMan.py:746 app/gameMan.py:848 msgid "BEE2 - Export Failed!" msgstr "BEE2 - Export échoué !" -#: app/gameMan.py:749 +#: app/gameMan.py:747 msgid "" "Compiler file {file} missing. Exit Steam applications, then press OK to " "verify your game cache. You can then export again." msgstr "" -#: app/gameMan.py:851 +#: app/gameMan.py:849 #, fuzzy msgid "Copying compiler file {file} failed. Ensure {game} is not running." msgstr "" "Copie du fichier {file} échouée. Veuillez vous assurer que {game} n'est " "pas en cours d'exécution." -#: app/gameMan.py:1263 +#: app/gameMan.py:1261 msgid "" "Ap-Tag Coop gun instance not found!\n" "Coop guns will not work - verify cache to fix." msgstr "" -#: app/gameMan.py:1267 +#: app/gameMan.py:1265 msgid "BEE2 - Aperture Tag Files Missing" msgstr "" -#: app/gameMan.py:1450 +#: app/gameMan.py:1448 msgid "Select the folder where the game executable is located ({appname})..." msgstr "Sélectionnez le dossier où l'exécutable du jeu est localisé ({appname})..." -#: app/gameMan.py:1453 app/gameMan.py:1468 app/gameMan.py:1478 -#: app/gameMan.py:1485 app/gameMan.py:1494 app/gameMan.py:1503 +#: app/gameMan.py:1451 app/gameMan.py:1466 app/gameMan.py:1476 +#: app/gameMan.py:1483 app/gameMan.py:1492 app/gameMan.py:1501 msgid "BEE2 - Add Game" msgstr "BEE2 - Ajouter un jeu" -#: app/gameMan.py:1456 +#: app/gameMan.py:1454 msgid "Find Game Exe" msgstr "Trouvez l'exécutable du jeu" -#: app/gameMan.py:1457 +#: app/gameMan.py:1455 msgid "Executable" msgstr "Exécutable" -#: app/gameMan.py:1465 +#: app/gameMan.py:1463 msgid "This does not appear to be a valid game folder!" msgstr "Cela ne semble pas être un dossier de jeu valide." -#: app/gameMan.py:1475 +#: app/gameMan.py:1473 msgid "Portal Stories: Mel doesn't have an editor!" msgstr "Portal Stories: Mel n'a pas d'éditeur." -#: app/gameMan.py:1486 +#: app/gameMan.py:1484 msgid "Enter the name of this game:" msgstr "Entrez le nom de ce jeu:" -#: app/gameMan.py:1493 +#: app/gameMan.py:1491 msgid "This name is already taken!" msgstr "Ce nom est déjà pris !" -#: app/gameMan.py:1502 +#: app/gameMan.py:1500 msgid "Please enter a name for this game!" msgstr "Veuillez entrer un nom pour ce jeu." -#: app/gameMan.py:1521 +#: app/gameMan.py:1519 msgid "" "\n" " (BEE2 will quit, this is the last game set!)" @@ -1169,7 +1173,7 @@ msgstr "Portal Stories: Mel" msgid "Thinking With Time Machine" msgstr "Thinking with Time Machine" -#: app/helpMenu.py:238 app/itemPropWin.py:342 +#: app/helpMenu.py:238 app/itemPropWin.py:343 msgid "Close" msgstr "Fermer" @@ -1185,15 +1189,15 @@ msgstr "Crédits de BEE2" msgid "Credits..." msgstr "Crédits..." -#: app/itemPropWin.py:38 +#: app/itemPropWin.py:39 msgid "Start Position" msgstr "Position de départ" -#: app/itemPropWin.py:39 +#: app/itemPropWin.py:40 msgid "End Position" msgstr "Position de fin" -#: app/itemPropWin.py:40 +#: app/itemPropWin.py:41 msgid "" "Delay \n" "(0=infinite)" @@ -1201,7 +1205,7 @@ msgstr "" "Délai\n" "(0=infini)" -#: app/itemPropWin.py:341 +#: app/itemPropWin.py:342 msgid "No Properties available!" msgstr "Aucune propriété disponible !" @@ -1209,39 +1213,7 @@ msgstr "Aucune propriété disponible !" msgid "Choose a Color" msgstr "Choisissez une couleur" -#: loadScreen.py:199 -msgid "Skipped!" -msgstr "Sauté !" - -#: loadScreen.py:200 -msgid "Version: " -msgstr "Version: " - -#: loadScreen.py:201 optionWindow.py:252 packageMan.py:116 selectorWin.py:723 -msgid "Cancel" -msgstr "Annuler" - -#: loadScreen.py:211 tagsPane.py:53 -msgid "Packages" -msgstr "Packages" - -#: loadScreen.py:212 -msgid "Loading Objects" -msgstr "Chargement des objets" - -#: loadScreen.py:213 -msgid "Loading Images" -msgstr "Chargement des images" - -#: loadScreen.py:214 -msgid "Initialising UI" -msgstr "Initialisation de l'interface" - -#: loadScreen.py:215 -msgid "Better Extended Editor for Portal 2" -msgstr "Better Extended Editor pour Portal 2" - -#: logWindow.py:30 +#: app/logWindow.py:29 msgid "Debug messages" msgstr "Messages de débug" @@ -1313,15 +1285,15 @@ msgstr "Sélectionne la musique utilisée à l'intérieur d'un Halo d'Excursion" #: app/music_conf.py:157 msgid "Have no music playing when inside funnels." -msgstr "N'a pas de musique pour les Halos d'Excursion. +msgstr "N'a pas de musique pour les Halos d'Excursion" #: app/music_conf.py:168 msgid "Select Repulsion Gel Music" -msgstr "Sélectionnez la musique du Gel Répulsif. +msgstr "Sélectionnez la musique du Gel Répulsif" #: app/music_conf.py:169 msgid "Select the music played when players jump on Repulsion Gel." -msgstr "Sélectionne la musique utilisée pour le Gel Répulsif. +msgstr "Sélectionne la musique utilisée pour le Gel Répulsif" #: app/music_conf.py:172 msgid "Add no music when jumping on Repulsion Gel." @@ -1336,7 +1308,9 @@ msgstr "Sélectionnez la musique du Gel Propulsif." msgid "" "Select music played when players have large amounts of horizontal " "velocity." -msgstr "Sélectionne la musique quand les joueurs sont très véloces horizontalement." +msgstr "" +"Sélectionne la musique quand les joueurs sont très véloces " +"horizontalement." #: app/music_conf.py:184 msgid "Add no music while running fast." @@ -1358,115 +1332,116 @@ msgstr "Rebondissement" msgid "Speed:" msgstr "Vitesse" -#: app/optionWindow.py:45 +#: app/optionWindow.py:46 #, fuzzy msgid "" "\n" "Launch Game?" msgstr "Lancer le jeu" -#: app/optionWindow.py:47 +#: app/optionWindow.py:48 #, fuzzy msgid "" "\n" "Minimise BEE2?" msgstr "Minimiser le BEE2" -#: app/optionWindow.py:48 +#: app/optionWindow.py:49 msgid "" "\n" "Launch Game and minimise BEE2?" msgstr "" -#: app/optionWindow.py:50 +#: app/optionWindow.py:51 msgid "" "\n" "Quit BEE2?" msgstr "" -#: app/optionWindow.py:51 +#: app/optionWindow.py:52 msgid "" "\n" "Launch Game and quit BEE2?" msgstr "" -#: app/optionWindow.py:70 +#: app/optionWindow.py:71 msgid "BEE2 Options" msgstr "Options de BEE2" -#: app/optionWindow.py:108 +#: app/optionWindow.py:109 msgid "" "Package cache times have been reset. These will now be extracted during " "the next export." -msgstr "Les caches temporelles des Packages ont été réinitialisées." -"Elles vont être extraites durant le prochain export." +msgstr "" +"Les caches temporelles des Packages ont été réinitialisées.Elles vont " +"être extraites durant le prochain export." -#: app/optionWindow.py:125 +#: app/optionWindow.py:126 msgid "\"Preserve Game Resources\" has been disabled." msgstr "\"Preserve Game Resources\" a été désactivé." -#: app/optionWindow.py:137 +#: app/optionWindow.py:138 #, fuzzy msgid "Packages Reset" msgstr "réinitialisation des packages" -#: app/optionWindow.py:218 +#: app/optionWindow.py:219 msgid "General" msgstr "Général" -#: app/optionWindow.py:224 +#: app/optionWindow.py:225 msgid "Windows" msgstr "Windows" -#: app/optionWindow.py:230 +#: app/optionWindow.py:231 msgid "Development" msgstr "Développement" -#: app/optionWindow.py:254 app/packageMan.py:110 app/selector_win.py:696 +#: app/optionWindow.py:255 app/packageMan.py:110 app/selector_win.py:696 msgid "OK" msgstr "OK" -#: app/optionWindow.py:285 +#: app/optionWindow.py:286 msgid "After Export:" msgstr "Après l'export:" -#: app/optionWindow.py:302 +#: app/optionWindow.py:303 msgid "Do Nothing" msgstr "Ne rien faire" -#: app/optionWindow.py:308 +#: app/optionWindow.py:309 msgid "Minimise BEE2" msgstr "Minimiser BEE2" -#: app/optionWindow.py:314 +#: app/optionWindow.py:315 msgid "Quit BEE2" msgstr "Quitter BEE2" -#: app/optionWindow.py:322 +#: app/optionWindow.py:323 msgid "After exports, do nothing and keep the BEE2 in focus." msgstr "Après l'export, ne rien faire et garder BEE2 au premier plan." -#: app/optionWindow.py:324 +#: app/optionWindow.py:325 msgid "After exports, minimise to the taskbar/dock." msgstr "Après l'export, minimiser BEE2 dans la barre des tâches." -#: app/optionWindow.py:325 +#: app/optionWindow.py:326 msgid "After exports, quit the BEE2." msgstr "Après l'export, quitter le BEE2." -#: app/optionWindow.py:332 +#: app/optionWindow.py:333 msgid "Launch Game" msgstr "Lancer le jeu" -#: app/optionWindow.py:333 +#: app/optionWindow.py:334 msgid "After exporting, launch the selected game automatically." msgstr "Après l'export, lancer le jeu sélectionné automatiquement." -#: app/optionWindow.py:341 app/optionWindow.py:347 +#: app/optionWindow.py:342 app/optionWindow.py:348 msgid "Play Sounds" msgstr "Jouer les sons" -#: app/optionWindow.py:352 +#: app/optionWindow.py:353 msgid "" "Pyglet is either not installed or broken.\n" "Sound effects have been disabled." @@ -1474,63 +1449,65 @@ msgstr "" "Pyglet est soit désinstallé soit endommagé.\n" "Les effets sonores ont été désactivés." -#: app/optionWindow.py:359 +#: app/optionWindow.py:360 msgid "Reset Package Caches" msgstr "Réinitialiser le cache des packages" -#: app/optionWindow.py:365 +#: app/optionWindow.py:366 #, fuzzy msgid "Force re-extracting all package resources." -msgstr "Forcer la ré-extraction de tous les packages de ressources. Cela requiert " -"un redémarrage." +msgstr "" +"Forcer la ré-extraction de tous les packages de ressources. Cela requiert" +" un redémarrage." -#: app/optionWindow.py:374 +#: app/optionWindow.py:375 msgid "Keep windows inside screen" msgstr "Garder les fenêtres dans l'écran." -#: app/optionWindow.py:375 +#: app/optionWindow.py:376 msgid "" "Prevent sub-windows from moving outside the screen borders. If you have " "multiple monitors, disable this." msgstr "" -"Empêcher les sous-fenêtres de sortir des limites de l'écran. Si vous avez" -"plusieurs écrans, désactivez cela." +"Empêcher les sous-fenêtres de sortir des limites de l'écran. Si vous " +"avezplusieurs écrans, désactivez cela." -#: app/optionWindow.py:385 +#: app/optionWindow.py:386 #, fuzzy msgid "Keep loading screens on top" msgstr "Garder les écrans de chargement au-dessus." -#: app/optionWindow.py:387 +#: app/optionWindow.py:388 msgid "" "Force loading screens to be on top of other windows. Since they don't " "appear on the taskbar/dock, they can't be brought to the top easily " "again." -msgstr "Forcer les écrans de téléchargement à être au-dessus des autres fenêtres." -"Si elles n'apparaissent pas dans la barre des tâches/dock, elles ne peuvent pas aller au-dessus" -"facilement." +msgstr "" +"Forcer les écrans de téléchargement à être au-dessus des autres " +"fenêtres.Si elles n'apparaissent pas dans la barre des tâches/dock, elles" +" ne peuvent pas aller au-dessusfacilement." -#: app/optionWindow.py:396 +#: app/optionWindow.py:397 msgid "Reset All Window Positions" msgstr "Réinitialiser les positions des fenêtres" -#: app/optionWindow.py:410 +#: app/optionWindow.py:411 msgid "Log missing entity counts" msgstr "Enregistrer dans un fichier les nombres d'entités manquantes" -#: app/optionWindow.py:411 +#: app/optionWindow.py:412 msgid "" "When loading items, log items with missing entity counts in their " "properties.txt file." msgstr "" -"Lors du chargement des objets, enregistrer les objets ayant un" -"nombre d'entités manquantes dans leur fichier properties.txt." +"Lors du chargement des objets, enregistrer les objets ayant unnombre " +"d'entités manquantes dans leur fichier properties.txt." -#: app/optionWindow.py:419 +#: app/optionWindow.py:420 msgid "Log when item doesn't have a style" msgstr "Enregistrer dans un fichier quand un objet n'a pas de style" -#: app/optionWindow.py:420 +#: app/optionWindow.py:421 msgid "" "Log items have no applicable version for a particular style.This usually " "means it will look very bad." @@ -1538,25 +1515,25 @@ msgstr "" "Enregistrer dans un fichier les objets n'ayant pas de version applicable " "pour un style donné. Cela signifie qu'il ne sera pas très beau." -#: app/optionWindow.py:428 +#: app/optionWindow.py:429 msgid "Log when item uses parent's style" msgstr "Enregistrer dans un fichier quand un objet utilise le style du parent" -#: app/optionWindow.py:429 +#: app/optionWindow.py:430 msgid "" "Log when an item reuses a variant from a parent style (1970s using 1950s " "items, for example). This is usually fine, but may need to be fixed." msgstr "" "Enregistrer dans un fichier quand un objet réutilise une variante d'un " -"style parent (le style 1970s utilisant des objets du style 1950s par ex.). " -"Ce n'est généralement pas un problème mais nécessite parfois des " +"style parent (le style 1970s utilisant des objets du style 1950s par " +"ex.). Ce n'est généralement pas un problème mais nécessite parfois des " "ajustements." -#: app/optionWindow.py:438 +#: app/optionWindow.py:439 msgid "Log missing packfile resources" msgstr "Enregistrer dans un fichier les ressources empaquetées manquantes" -#: app/optionWindow.py:439 +#: app/optionWindow.py:440 msgid "" "Log when the resources a \"PackList\" refers to are not present in the " "zip. This may be fine (in a prerequisite zip), but it often indicates an " @@ -1566,11 +1543,20 @@ msgstr "" "\"PackList\" ne sont pas présentes dans le zip. Cela peut être normal " "(dans un zip prérequis) mais peut autrement indiquer un erreur." -#: app/optionWindow.py:448 +#: app/optionWindow.py:450 +#, fuzzy +msgid "Development Mode" +msgstr "Développement" + +#: app/optionWindow.py:451 +msgid "Enables displaying additional UI specific for development purposes." +msgstr "" + +#: app/optionWindow.py:459 msgid "Preserve Game Directories" msgstr "Préserver les dossiers du jeu" -#: app/optionWindow.py:450 +#: app/optionWindow.py:461 #, fuzzy msgid "" "When exporting, do not copy resources to \n" @@ -1584,31 +1570,33 @@ msgstr "" "Activez cela si vous développez du contenu nouveau afin qu'il ne soit pas" " remplacé." -#: app/optionWindow.py:461 +#: app/optionWindow.py:472 msgid "Show Log Window" msgstr "Montrer la fenêtre de log" -#: app/optionWindow.py:463 +#: app/optionWindow.py:474 msgid "Show the log file in real-time." msgstr "Montrer le log en temps réel." -#: app/optionWindow.py:470 +#: app/optionWindow.py:481 msgid "Force Editor Models" msgstr "Forcer les modèles de l'éditeur" -#: app/optionWindow.py:471 +#: app/optionWindow.py:482 msgid "" "Make all props_map_editor models available for use. Portal 2 has a limit " "of 1024 models loaded in memory at once, so we need to disable unused " "ones to free this up." -msgstr "Rendre tous les modèes props_map_editor utlilsables. Portal 2 a une limite " -"de 1024 modèles chargés en mémoire en une fois, alors nous devons désactiver les autres." +msgstr "" +"Rendre tous les modèes props_map_editor utlilsables. Portal 2 a une " +"limite de 1024 modèles chargés en mémoire en une fois, alors nous devons " +"désactiver les autres." -#: app/optionWindow.py:482 +#: app/optionWindow.py:493 msgid "Dump All objects" msgstr "Supprimer tous les objets" -#: app/optionWindow.py:488 +#: app/optionWindow.py:499 msgid "Dump Items list" msgstr "Supprimer la liste d'objets" @@ -1644,7 +1632,7 @@ msgstr "BEEMod" msgid "Portal 2 Collapsed" msgstr "Portal 2 Compressé" -#: app/richTextBox.py:152 +#: app/richTextBox.py:151 msgid "Open \"{}\" in the default browser?" msgstr "Ouvrir \"{}\" dans le navigateur par défaut ?" @@ -1678,7 +1666,7 @@ msgid_plural "Authors: {}" msgstr[0] "Auteur: {}" msgstr[1] "Auteurs: {}" -#: app/selector_win.py:1137 +#: app/selector_win.py:1145 msgid "Color: R={r}, G={g}, B={b}" msgstr "Couleur: R={r}, V={g}, B={b}" @@ -1703,23 +1691,19 @@ msgstr "Tags" msgid "Authors" msgstr "Auteurs" -#: app/tagsPane.py:157 +#: app/tagsPane.py:156 msgid "Any" msgstr "N'importe quel" -#: app/tagsPane.py:166 +#: app/tagsPane.py:165 msgid "All" msgstr "Tout" -#: app/tagsPane.py:192 +#: app/tagsPane.py:191 msgid "Available Tags (click):" msgstr "Tags disponibles (cliquez):" -#: utils.py:841 -msgid "__LANG_USE_SANS_SERIF__" -msgstr "0" - -#: voiceEditor.py:35 +#: app/voiceEditor.py:33 msgid "Singleplayer" msgstr "Solo" diff --git a/i18n/ja.po b/i18n/ja.po index 9abd2c362..0b93a1add 100644 --- a/i18n/ja.po +++ b/i18n/ja.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2020-09-20 10:31-0700\n" +"POT-Creation-Date: 2021-01-14 14:25+1000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: ja\n" @@ -12,7 +12,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.8.0\n" +"Generated-By: Babel 2.6.0\n" #: loadScreen.py:199 msgid "Skipped!" @@ -22,7 +22,7 @@ msgstr "" msgid "Version: " msgstr "バージョン:" -#: app/optionWindow.py:259 app/packageMan.py:116 app/selector_win.py:718 +#: app/optionWindow.py:260 app/packageMan.py:116 app/selector_win.py:718 #: loadScreen.py:201 msgid "Cancel" msgstr "キャンセル" @@ -47,7 +47,7 @@ msgstr "" msgid "Better Extended Editor for Portal 2" msgstr "" -#: utils.py:841 +#: utils.py:892 msgid "__LANG_USE_SANS_SERIF__" msgstr "YES" @@ -546,7 +546,7 @@ msgstr "" msgid "This palette already exists. Overwrite?" msgstr "" -#: app/UI.py:1249 app/gameMan.py:1527 +#: app/UI.py:1249 app/gameMan.py:1525 msgid "Are you sure you want to delete \"{}\"?" msgstr "" @@ -636,7 +636,7 @@ msgstr "" msgid "Options" msgstr "環境設定" -#: app/UI.py:1730 app/gameMan.py:1206 +#: app/UI.py:1730 app/gameMan.py:1204 msgid "Quit" msgstr "終了" @@ -795,211 +795,211 @@ msgstr "" msgid "Backup/Restore Puzzles" msgstr "" -#: app/contextWin.py:76 +#: app/contextWin.py:77 msgid "This item may not be rotated." msgstr "" -#: app/contextWin.py:77 +#: app/contextWin.py:78 msgid "This item can be pointed in 4 directions." msgstr "" -#: app/contextWin.py:78 +#: app/contextWin.py:79 msgid "This item can be positioned on the sides and center." msgstr "" -#: app/contextWin.py:79 +#: app/contextWin.py:80 msgid "This item can be centered in two directions, plus on the sides." msgstr "" -#: app/contextWin.py:80 +#: app/contextWin.py:81 msgid "This item can be placed like light strips." msgstr "" -#: app/contextWin.py:81 +#: app/contextWin.py:82 msgid "This item can be rotated on the floor to face 360 degrees." msgstr "" -#: app/contextWin.py:82 +#: app/contextWin.py:83 msgid "This item is positioned using a catapult trajectory." msgstr "" -#: app/contextWin.py:83 +#: app/contextWin.py:84 msgid "This item positions the dropper to hit target locations." msgstr "" -#: app/contextWin.py:85 +#: app/contextWin.py:86 msgid "This item does not accept any inputs." msgstr "" -#: app/contextWin.py:86 +#: app/contextWin.py:87 msgid "This item accepts inputs." msgstr "" -#: app/contextWin.py:87 +#: app/contextWin.py:88 msgid "This item has two input types (A and B), using the Input A and B items." msgstr "" -#: app/contextWin.py:89 +#: app/contextWin.py:90 msgid "This item does not output." msgstr "" -#: app/contextWin.py:90 +#: app/contextWin.py:91 msgid "This item has an output." msgstr "" -#: app/contextWin.py:91 +#: app/contextWin.py:92 msgid "This item has a timed output." msgstr "" -#: app/contextWin.py:93 +#: app/contextWin.py:94 msgid "This item does not take up any space inside walls." msgstr "" -#: app/contextWin.py:94 +#: app/contextWin.py:95 msgid "This item takes space inside the wall." msgstr "" -#: app/contextWin.py:96 +#: app/contextWin.py:97 msgid "This item cannot be placed anywhere..." msgstr "" -#: app/contextWin.py:97 +#: app/contextWin.py:98 msgid "This item can only be attached to ceilings." msgstr "" -#: app/contextWin.py:98 +#: app/contextWin.py:99 msgid "This item can only be placed on the floor." msgstr "" -#: app/contextWin.py:99 +#: app/contextWin.py:100 msgid "This item can be placed on floors and ceilings." msgstr "" -#: app/contextWin.py:100 +#: app/contextWin.py:101 msgid "This item can be placed on walls only." msgstr "" -#: app/contextWin.py:101 +#: app/contextWin.py:102 msgid "This item can be attached to walls and ceilings." msgstr "" -#: app/contextWin.py:102 +#: app/contextWin.py:103 msgid "This item can be placed on floors and walls." msgstr "" -#: app/contextWin.py:103 +#: app/contextWin.py:104 msgid "This item can be placed in any orientation." msgstr "" -#: app/contextWin.py:209 +#: app/contextWin.py:210 msgid "No Alternate Versions" msgstr "" -#: app/contextWin.py:301 +#: app/contextWin.py:308 msgid "Excursion Funnels accept a on/off input and a directional input." msgstr "" -#: app/contextWin.py:358 +#: app/contextWin.py:365 msgid "" "This item can be rotated on the floor to face 360 degrees, for Reflection" " Cubes only." msgstr "" -#: app/contextWin.py:437 +#: app/contextWin.py:444 msgid "Properties:" msgstr "" -#: app/contextWin.py:459 +#: app/contextWin.py:470 msgid "" "The number of entities used for this item. The Source engine limits this " "to 2048 in total. This provides a guide to how many of these items can be" " placed in a map at once." msgstr "" -#: app/contextWin.py:484 +#: app/contextWin.py:495 msgid "Description:" msgstr "" -#: app/contextWin.py:527 +#: app/contextWin.py:538 msgid "" "Failed to open a web browser. Do you wish for the URL to be copied to the" " clipboard instead?" msgstr "" -#: app/contextWin.py:541 +#: app/contextWin.py:552 msgid "More Info>>" msgstr "" -#: app/contextWin.py:558 +#: app/contextWin.py:569 msgid "Change Defaults..." msgstr "" -#: app/contextWin.py:564 +#: app/contextWin.py:575 msgid "Change the default settings for this item when placed." msgstr "" -#: app/gameMan.py:748 app/gameMan.py:850 +#: app/gameMan.py:746 app/gameMan.py:848 msgid "BEE2 - Export Failed!" msgstr "" -#: app/gameMan.py:749 +#: app/gameMan.py:747 msgid "" "Compiler file {file} missing. Exit Steam applications, then press OK to " "verify your game cache. You can then export again." msgstr "" -#: app/gameMan.py:851 +#: app/gameMan.py:849 msgid "Copying compiler file {file} failed. Ensure {game} is not running." msgstr "" -#: app/gameMan.py:1263 +#: app/gameMan.py:1261 msgid "" "Ap-Tag Coop gun instance not found!\n" "Coop guns will not work - verify cache to fix." msgstr "" -#: app/gameMan.py:1267 +#: app/gameMan.py:1265 msgid "BEE2 - Aperture Tag Files Missing" msgstr "" -#: app/gameMan.py:1450 +#: app/gameMan.py:1448 msgid "Select the folder where the game executable is located ({appname})..." msgstr "" -#: app/gameMan.py:1453 app/gameMan.py:1468 app/gameMan.py:1478 -#: app/gameMan.py:1485 app/gameMan.py:1494 app/gameMan.py:1503 +#: app/gameMan.py:1451 app/gameMan.py:1466 app/gameMan.py:1476 +#: app/gameMan.py:1483 app/gameMan.py:1492 app/gameMan.py:1501 msgid "BEE2 - Add Game" msgstr "" -#: app/gameMan.py:1456 +#: app/gameMan.py:1454 msgid "Find Game Exe" msgstr "" -#: app/gameMan.py:1457 +#: app/gameMan.py:1455 msgid "Executable" msgstr "" -#: app/gameMan.py:1465 +#: app/gameMan.py:1463 msgid "This does not appear to be a valid game folder!" msgstr "" -#: app/gameMan.py:1475 +#: app/gameMan.py:1473 msgid "Portal Stories: Mel doesn't have an editor!" msgstr "" -#: app/gameMan.py:1486 +#: app/gameMan.py:1484 msgid "Enter the name of this game:" msgstr "" -#: app/gameMan.py:1493 +#: app/gameMan.py:1491 msgid "This name is already taken!" msgstr "" -#: app/gameMan.py:1502 +#: app/gameMan.py:1500 msgid "Please enter a name for this game!" msgstr "" -#: app/gameMan.py:1521 +#: app/gameMan.py:1519 msgid "" "\n" " (BEE2 will quit, this is the last game set!)" @@ -1053,7 +1053,7 @@ msgstr "Portal Stories: Mel" msgid "Thinking With Time Machine" msgstr "Thinking With Time Machine" -#: app/helpMenu.py:238 app/itemPropWin.py:342 +#: app/helpMenu.py:238 app/itemPropWin.py:343 msgid "Close" msgstr "閉じる" @@ -1069,21 +1069,21 @@ msgstr "BEE2のクレジット" msgid "Credits..." msgstr "クレジット。。。" -#: app/itemPropWin.py:38 +#: app/itemPropWin.py:39 msgid "Start Position" msgstr "" -#: app/itemPropWin.py:39 +#: app/itemPropWin.py:40 msgid "End Position" msgstr "" -#: app/itemPropWin.py:40 +#: app/itemPropWin.py:41 msgid "" "Delay \n" "(0=infinite)" msgstr "" -#: app/itemPropWin.py:341 +#: app/itemPropWin.py:342 msgid "No Properties available!" msgstr "" @@ -1204,195 +1204,203 @@ msgstr "" msgid "Speed:" msgstr "" -#: app/optionWindow.py:45 +#: app/optionWindow.py:46 msgid "" "\n" "Launch Game?" msgstr "" -#: app/optionWindow.py:47 +#: app/optionWindow.py:48 msgid "" "\n" "Minimise BEE2?" msgstr "" -#: app/optionWindow.py:48 +#: app/optionWindow.py:49 msgid "" "\n" "Launch Game and minimise BEE2?" msgstr "" -#: app/optionWindow.py:50 +#: app/optionWindow.py:51 msgid "" "\n" "Quit BEE2?" msgstr "" -#: app/optionWindow.py:51 +#: app/optionWindow.py:52 msgid "" "\n" "Launch Game and quit BEE2?" msgstr "" -#: app/optionWindow.py:70 +#: app/optionWindow.py:71 msgid "BEE2 Options" msgstr "" -#: app/optionWindow.py:108 +#: app/optionWindow.py:109 msgid "" "Package cache times have been reset. These will now be extracted during " "the next export." msgstr "" -#: app/optionWindow.py:125 +#: app/optionWindow.py:126 msgid "\"Preserve Game Resources\" has been disabled." msgstr "" -#: app/optionWindow.py:137 +#: app/optionWindow.py:138 msgid "Packages Reset" msgstr "" -#: app/optionWindow.py:218 +#: app/optionWindow.py:219 msgid "General" msgstr "" -#: app/optionWindow.py:224 +#: app/optionWindow.py:225 msgid "Windows" msgstr "" -#: app/optionWindow.py:230 +#: app/optionWindow.py:231 msgid "Development" msgstr "" -#: app/optionWindow.py:254 app/packageMan.py:110 app/selector_win.py:696 +#: app/optionWindow.py:255 app/packageMan.py:110 app/selector_win.py:696 msgid "OK" msgstr "OK" -#: app/optionWindow.py:285 +#: app/optionWindow.py:286 msgid "After Export:" msgstr "" -#: app/optionWindow.py:302 +#: app/optionWindow.py:303 msgid "Do Nothing" msgstr "" -#: app/optionWindow.py:308 +#: app/optionWindow.py:309 msgid "Minimise BEE2" msgstr "" -#: app/optionWindow.py:314 +#: app/optionWindow.py:315 msgid "Quit BEE2" msgstr "" -#: app/optionWindow.py:322 +#: app/optionWindow.py:323 msgid "After exports, do nothing and keep the BEE2 in focus." msgstr "" -#: app/optionWindow.py:324 +#: app/optionWindow.py:325 msgid "After exports, minimise to the taskbar/dock." msgstr "" -#: app/optionWindow.py:325 +#: app/optionWindow.py:326 msgid "After exports, quit the BEE2." msgstr "" -#: app/optionWindow.py:332 +#: app/optionWindow.py:333 msgid "Launch Game" msgstr "" -#: app/optionWindow.py:333 +#: app/optionWindow.py:334 msgid "After exporting, launch the selected game automatically." msgstr "" -#: app/optionWindow.py:341 app/optionWindow.py:347 +#: app/optionWindow.py:342 app/optionWindow.py:348 msgid "Play Sounds" msgstr "" -#: app/optionWindow.py:352 +#: app/optionWindow.py:353 msgid "" "Pyglet is either not installed or broken.\n" "Sound effects have been disabled." msgstr "" -#: app/optionWindow.py:359 +#: app/optionWindow.py:360 msgid "Reset Package Caches" msgstr "" -#: app/optionWindow.py:365 +#: app/optionWindow.py:366 msgid "Force re-extracting all package resources." msgstr "" -#: app/optionWindow.py:374 +#: app/optionWindow.py:375 msgid "Keep windows inside screen" msgstr "" -#: app/optionWindow.py:375 +#: app/optionWindow.py:376 msgid "" "Prevent sub-windows from moving outside the screen borders. If you have " "multiple monitors, disable this." msgstr "" -#: app/optionWindow.py:385 +#: app/optionWindow.py:386 msgid "Keep loading screens on top" msgstr "" -#: app/optionWindow.py:387 +#: app/optionWindow.py:388 msgid "" "Force loading screens to be on top of other windows. Since they don't " "appear on the taskbar/dock, they can't be brought to the top easily " "again." msgstr "" -#: app/optionWindow.py:396 +#: app/optionWindow.py:397 msgid "Reset All Window Positions" msgstr "" -#: app/optionWindow.py:410 +#: app/optionWindow.py:411 msgid "Log missing entity counts" msgstr "" -#: app/optionWindow.py:411 +#: app/optionWindow.py:412 msgid "" "When loading items, log items with missing entity counts in their " "properties.txt file." msgstr "" -#: app/optionWindow.py:419 +#: app/optionWindow.py:420 msgid "Log when item doesn't have a style" msgstr "" -#: app/optionWindow.py:420 +#: app/optionWindow.py:421 msgid "" "Log items have no applicable version for a particular style.This usually " "means it will look very bad." msgstr "" -#: app/optionWindow.py:428 +#: app/optionWindow.py:429 msgid "Log when item uses parent's style" msgstr "" -#: app/optionWindow.py:429 +#: app/optionWindow.py:430 msgid "" "Log when an item reuses a variant from a parent style (1970s using 1950s " "items, for example). This is usually fine, but may need to be fixed." msgstr "" -#: app/optionWindow.py:438 +#: app/optionWindow.py:439 msgid "Log missing packfile resources" msgstr "" -#: app/optionWindow.py:439 +#: app/optionWindow.py:440 msgid "" "Log when the resources a \"PackList\" refers to are not present in the " "zip. This may be fine (in a prerequisite zip), but it often indicates an " "error." msgstr "" -#: app/optionWindow.py:448 +#: app/optionWindow.py:450 +msgid "Development Mode" +msgstr "" + +#: app/optionWindow.py:451 +msgid "Enables displaying additional UI specific for development purposes." +msgstr "" + +#: app/optionWindow.py:459 msgid "Preserve Game Directories" msgstr "" -#: app/optionWindow.py:450 +#: app/optionWindow.py:461 msgid "" "When exporting, do not copy resources to \n" "\"bee2/\" and \"sdk_content/maps/bee2/\".\n" @@ -1400,30 +1408,30 @@ msgid "" "overwritten." msgstr "" -#: app/optionWindow.py:461 +#: app/optionWindow.py:472 msgid "Show Log Window" msgstr "" -#: app/optionWindow.py:463 +#: app/optionWindow.py:474 msgid "Show the log file in real-time." msgstr "" -#: app/optionWindow.py:470 +#: app/optionWindow.py:481 msgid "Force Editor Models" msgstr "" -#: app/optionWindow.py:471 +#: app/optionWindow.py:482 msgid "" "Make all props_map_editor models available for use. Portal 2 has a limit " "of 1024 models loaded in memory at once, so we need to disable unused " "ones to free this up." msgstr "" -#: app/optionWindow.py:482 +#: app/optionWindow.py:493 msgid "Dump All objects" msgstr "" -#: app/optionWindow.py:488 +#: app/optionWindow.py:499 msgid "Dump Items list" msgstr "" @@ -1457,7 +1465,7 @@ msgstr "BEEMod" msgid "Portal 2 Collapsed" msgstr "短縮のPortal 2" -#: app/richTextBox.py:152 +#: app/richTextBox.py:151 msgid "Open \"{}\" in the default browser?" msgstr "" @@ -1490,7 +1498,7 @@ msgid "Author: {}" msgid_plural "Authors: {}" msgstr[0] "" -#: app/selector_win.py:1137 +#: app/selector_win.py:1145 msgid "Color: R={r}, G={g}, B={b}" msgstr "" @@ -1514,15 +1522,15 @@ msgstr "付箋" msgid "Authors" msgstr "" -#: app/tagsPane.py:157 +#: app/tagsPane.py:156 msgid "Any" msgstr "選ぶ" -#: app/tagsPane.py:166 +#: app/tagsPane.py:165 msgid "All" msgstr "全て" -#: app/tagsPane.py:192 +#: app/tagsPane.py:191 msgid "Available Tags (click):" msgstr "" diff --git a/i18n/zh.po b/i18n/zh.po index ff139b2fe..11551bc74 100644 --- a/i18n/zh.po +++ b/i18n/zh.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: https://github.com/BEEmod/BEE2.4/issues\n" -"POT-Creation-Date: 2020-09-20 10:31-0700\n" +"POT-Creation-Date: 2021-01-14 14:25+1000\n" "PO-Revision-Date: 2019-11-22 10:47+1000\n" "Last-Translator: Antecer \n" "Language: zh\n" @@ -12,7 +12,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.8.0\n" +"Generated-By: Babel 2.6.0\n" #: loadScreen.py:199 msgid "Skipped!" @@ -22,7 +22,7 @@ msgstr "跳过!" msgid "Version: " msgstr "版本:" -#: app/optionWindow.py:259 app/packageMan.py:116 app/selector_win.py:718 +#: app/optionWindow.py:260 app/packageMan.py:116 app/selector_win.py:718 #: loadScreen.py:201 msgid "Cancel" msgstr "取消" @@ -47,7 +47,7 @@ msgstr "初始化界面" msgid "Better Extended Editor for Portal 2" msgstr "更棒的传送门2扩展编辑器" -#: utils.py:841 +#: utils.py:892 msgid "__LANG_USE_SANS_SERIF__" msgstr "" @@ -600,7 +600,7 @@ msgstr "键入模板名称:" msgid "This palette already exists. Overwrite?" msgstr "已经存在同名模板,是否覆盖?" -#: app/UI.py:1249 app/gameMan.py:1527 +#: app/UI.py:1249 app/gameMan.py:1525 msgid "Are you sure you want to delete \"{}\"?" msgstr "你确定要删除 \"{}\" 吗?" @@ -690,7 +690,7 @@ msgstr "管理资源包..." msgid "Options" msgstr "设置" -#: app/UI.py:1730 app/gameMan.py:1206 +#: app/UI.py:1730 app/gameMan.py:1204 msgid "Quit" msgstr "退出" @@ -853,166 +853,166 @@ msgstr "保持(每N场游戏)" msgid "Backup/Restore Puzzles" msgstr "备份/恢复 谜题" -#: app/contextWin.py:76 +#: app/contextWin.py:77 msgid "This item may not be rotated." msgstr "该物品可能无法旋转。" -#: app/contextWin.py:77 +#: app/contextWin.py:78 msgid "This item can be pointed in 4 directions." msgstr "该物品可以面向4个方向。" -#: app/contextWin.py:78 +#: app/contextWin.py:79 msgid "This item can be positioned on the sides and center." msgstr "该物品可以放在侧面和中间。" -#: app/contextWin.py:79 +#: app/contextWin.py:80 msgid "This item can be centered in two directions, plus on the sides." msgstr "该物品可以向三个方向延伸。" -#: app/contextWin.py:80 +#: app/contextWin.py:81 msgid "This item can be placed like light strips." msgstr "该物品可以像灯条一样放置。" -#: app/contextWin.py:81 +#: app/contextWin.py:82 msgid "This item can be rotated on the floor to face 360 degrees." msgstr "该物品可以在地面上360°旋转。" -#: app/contextWin.py:82 +#: app/contextWin.py:83 msgid "This item is positioned using a catapult trajectory." msgstr "该物品用于定位弹射板的弹道及落点。" -#: app/contextWin.py:83 +#: app/contextWin.py:84 msgid "This item positions the dropper to hit target locations." msgstr "该物品定位物品掉落器击中目标的位置。" -#: app/contextWin.py:85 +#: app/contextWin.py:86 msgid "This item does not accept any inputs." msgstr "该物品不会接收任何输入信号。" -#: app/contextWin.py:86 +#: app/contextWin.py:87 msgid "This item accepts inputs." msgstr "该物品可以接收信号输入以改变状态。" -#: app/contextWin.py:87 +#: app/contextWin.py:88 msgid "This item has two input types (A and B), using the Input A and B items." msgstr "该物品具有两种输入类型(A和B),使用A物品和B物品进行输入。" -#: app/contextWin.py:89 +#: app/contextWin.py:90 msgid "This item does not output." msgstr "该物品不会输出信号。" -#: app/contextWin.py:90 +#: app/contextWin.py:91 msgid "This item has an output." msgstr "该物品可以输出信号。" -#: app/contextWin.py:91 +#: app/contextWin.py:92 msgid "This item has a timed output." msgstr "该物品具有延时输出信号的功能。" -#: app/contextWin.py:93 +#: app/contextWin.py:94 msgid "This item does not take up any space inside walls." msgstr "该物品不会占据墙壁后面的空间。" -#: app/contextWin.py:94 +#: app/contextWin.py:95 msgid "This item takes space inside the wall." msgstr "该物品需要占据墙壁后面的空间。" -#: app/contextWin.py:96 +#: app/contextWin.py:97 msgid "This item cannot be placed anywhere..." msgstr "该物品不能手动放置" -#: app/contextWin.py:97 +#: app/contextWin.py:98 msgid "This item can only be attached to ceilings." msgstr "该物品只能放置在天花板上。" -#: app/contextWin.py:98 +#: app/contextWin.py:99 msgid "This item can only be placed on the floor." msgstr "该物品只能放置在地板上。" -#: app/contextWin.py:99 +#: app/contextWin.py:100 msgid "This item can be placed on floors and ceilings." msgstr "该物品可以放置在地板和天花板上。" -#: app/contextWin.py:100 +#: app/contextWin.py:101 msgid "This item can be placed on walls only." msgstr "该物品只能放置在墙上。" -#: app/contextWin.py:101 +#: app/contextWin.py:102 msgid "This item can be attached to walls and ceilings." msgstr "该物品可以放置在墙壁和天花板上。" -#: app/contextWin.py:102 +#: app/contextWin.py:103 msgid "This item can be placed on floors and walls." msgstr "该物品可以放置在地板和墙壁上。" -#: app/contextWin.py:103 +#: app/contextWin.py:104 msgid "This item can be placed in any orientation." msgstr "该物品可以放置在任何方向。" -#: app/contextWin.py:209 +#: app/contextWin.py:210 #, fuzzy msgid "No Alternate Versions" msgstr "无替代版本!" -#: app/contextWin.py:301 +#: app/contextWin.py:308 msgid "Excursion Funnels accept a on/off input and a directional input." msgstr "牵引光束接受“开/关”控制和“方向”转换控制。" -#: app/contextWin.py:358 +#: app/contextWin.py:365 msgid "" "This item can be rotated on the floor to face 360 degrees, for Reflection" " Cubes only." msgstr "该物品可以在地面上360°旋转放置。(仅适用于透镜方块)" -#: app/contextWin.py:437 +#: app/contextWin.py:444 msgid "Properties:" msgstr "物品属性:" -#: app/contextWin.py:459 +#: app/contextWin.py:470 msgid "" "The number of entities used for this item. The Source engine limits this " "to 2048 in total. This provides a guide to how many of these items can be" " placed in a map at once." msgstr "用于此物品的实体数量。起源引擎将其限制为2048。这里提供了一篇可以一次性放置多少物品在地图里的指南。" -#: app/contextWin.py:484 +#: app/contextWin.py:495 msgid "Description:" msgstr "描述:" -#: app/contextWin.py:527 +#: app/contextWin.py:538 msgid "" "Failed to open a web browser. Do you wish for the URL to be copied to the" " clipboard instead?" msgstr "无法打开浏览器。你希望将网址复制到剪贴板吗?" -#: app/contextWin.py:541 +#: app/contextWin.py:552 msgid "More Info>>" msgstr "更多信息>>" -#: app/contextWin.py:558 +#: app/contextWin.py:569 msgid "Change Defaults..." msgstr "更改默认值..." -#: app/contextWin.py:564 +#: app/contextWin.py:575 msgid "Change the default settings for this item when placed." msgstr "修改该物品在放置时的默认设置。" -#: app/gameMan.py:748 app/gameMan.py:850 +#: app/gameMan.py:746 app/gameMan.py:848 msgid "BEE2 - Export Failed!" msgstr "BEE2 - 导出失败!" -#: app/gameMan.py:749 +#: app/gameMan.py:747 msgid "" "Compiler file {file} missing. Exit Steam applications, then press OK to " "verify your game cache. You can then export again." msgstr "编译器文件 {file} 丢失。退出Steam程序,然后点击OK以校验你的游戏缓存。然后再次尝试导出。" -#: app/gameMan.py:851 +#: app/gameMan.py:849 #, fuzzy msgid "Copying compiler file {file} failed. Ensure {game} is not running." msgstr "复制编译器文件 {file} 失败。确保 {game} 未运行" -#: app/gameMan.py:1263 +#: app/gameMan.py:1261 msgid "" "Ap-Tag Coop gun instance not found!\n" "Coop guns will not work - verify cache to fix." @@ -1020,48 +1020,48 @@ msgstr "" "找不到光圈科技附加传送枪的实例!\n" "传送器将不起作用 - 校验缓存以修复此问题。" -#: app/gameMan.py:1267 +#: app/gameMan.py:1265 msgid "BEE2 - Aperture Tag Files Missing" msgstr "BEE2 - 光圈科技附加文件丢失" -#: app/gameMan.py:1450 +#: app/gameMan.py:1448 msgid "Select the folder where the game executable is located ({appname})..." msgstr "选择游戏可执行文件的路径 {appname}" -#: app/gameMan.py:1453 app/gameMan.py:1468 app/gameMan.py:1478 -#: app/gameMan.py:1485 app/gameMan.py:1494 app/gameMan.py:1503 +#: app/gameMan.py:1451 app/gameMan.py:1466 app/gameMan.py:1476 +#: app/gameMan.py:1483 app/gameMan.py:1492 app/gameMan.py:1501 msgid "BEE2 - Add Game" msgstr "BEE2 - 添加游戏" -#: app/gameMan.py:1456 +#: app/gameMan.py:1454 msgid "Find Game Exe" msgstr "查找游戏的exe文件" -#: app/gameMan.py:1457 +#: app/gameMan.py:1455 msgid "Executable" msgstr "可执行文件" -#: app/gameMan.py:1465 +#: app/gameMan.py:1463 msgid "This does not appear to be a valid game folder!" msgstr "这似乎不是一个有效的游戏文件夹!" -#: app/gameMan.py:1475 +#: app/gameMan.py:1473 msgid "Portal Stories: Mel doesn't have an editor!" msgstr "没有《传送门:梅尔的故事》的编辑器!" -#: app/gameMan.py:1486 +#: app/gameMan.py:1484 msgid "Enter the name of this game:" msgstr "输入此游戏的名称:" -#: app/gameMan.py:1493 +#: app/gameMan.py:1491 msgid "This name is already taken!" msgstr "该名称已经存在!" -#: app/gameMan.py:1502 +#: app/gameMan.py:1500 msgid "Please enter a name for this game!" msgstr "请为此游戏创建一个名称!" -#: app/gameMan.py:1521 +#: app/gameMan.py:1519 msgid "" "\n" " (BEE2 will quit, this is the last game set!)" @@ -1117,7 +1117,7 @@ msgstr "传送门:梅尔的故事" msgid "Thinking With Time Machine" msgstr "传送门:时间机器" -#: app/helpMenu.py:238 app/itemPropWin.py:342 +#: app/helpMenu.py:238 app/itemPropWin.py:343 msgid "Close" msgstr "关闭" @@ -1133,15 +1133,15 @@ msgstr "BEE2 声明" msgid "Credits..." msgstr "声明..." -#: app/itemPropWin.py:38 +#: app/itemPropWin.py:39 msgid "Start Position" msgstr "开始位置" -#: app/itemPropWin.py:39 +#: app/itemPropWin.py:40 msgid "End Position" msgstr "结束位置" -#: app/itemPropWin.py:40 +#: app/itemPropWin.py:41 msgid "" "Delay \n" "(0=infinite)" @@ -1149,7 +1149,7 @@ msgstr "" "延时\n" "(0=无限)" -#: app/itemPropWin.py:341 +#: app/itemPropWin.py:342 msgid "No Properties available!" msgstr "没有可用的属性!" @@ -1269,113 +1269,113 @@ msgstr "弹性凝胶" msgid "Speed:" msgstr "加速凝胶" -#: app/optionWindow.py:45 +#: app/optionWindow.py:46 #, fuzzy msgid "" "\n" "Launch Game?" msgstr "启动游戏" -#: app/optionWindow.py:47 +#: app/optionWindow.py:48 #, fuzzy msgid "" "\n" "Minimise BEE2?" msgstr "最小化BEE2" -#: app/optionWindow.py:48 +#: app/optionWindow.py:49 msgid "" "\n" "Launch Game and minimise BEE2?" msgstr "" -#: app/optionWindow.py:50 +#: app/optionWindow.py:51 msgid "" "\n" "Quit BEE2?" msgstr "" -#: app/optionWindow.py:51 +#: app/optionWindow.py:52 msgid "" "\n" "Launch Game and quit BEE2?" msgstr "" -#: app/optionWindow.py:70 +#: app/optionWindow.py:71 msgid "BEE2 Options" msgstr "BEE2 选项" -#: app/optionWindow.py:108 +#: app/optionWindow.py:109 msgid "" "Package cache times have been reset. These will now be extracted during " "the next export." msgstr "" -#: app/optionWindow.py:125 +#: app/optionWindow.py:126 msgid "\"Preserve Game Resources\" has been disabled." msgstr "" -#: app/optionWindow.py:137 +#: app/optionWindow.py:138 msgid "Packages Reset" msgstr "" -#: app/optionWindow.py:218 +#: app/optionWindow.py:219 msgid "General" msgstr "常规" -#: app/optionWindow.py:224 +#: app/optionWindow.py:225 msgid "Windows" msgstr "窗口" -#: app/optionWindow.py:230 +#: app/optionWindow.py:231 msgid "Development" msgstr "开发者选项" -#: app/optionWindow.py:254 app/packageMan.py:110 app/selector_win.py:696 +#: app/optionWindow.py:255 app/packageMan.py:110 app/selector_win.py:696 msgid "OK" msgstr "确定" -#: app/optionWindow.py:285 +#: app/optionWindow.py:286 msgid "After Export:" msgstr "导出后:" -#: app/optionWindow.py:302 +#: app/optionWindow.py:303 msgid "Do Nothing" msgstr "什么都不做" -#: app/optionWindow.py:308 +#: app/optionWindow.py:309 msgid "Minimise BEE2" msgstr "最小化BEE2" -#: app/optionWindow.py:314 +#: app/optionWindow.py:315 msgid "Quit BEE2" msgstr "退出BEE2" -#: app/optionWindow.py:322 +#: app/optionWindow.py:323 msgid "After exports, do nothing and keep the BEE2 in focus." msgstr "导出后,什么也不做,保持BEE2窗口处于焦点。" -#: app/optionWindow.py:324 +#: app/optionWindow.py:325 msgid "After exports, minimise to the taskbar/dock." msgstr "导出后,最小化到任务栏。" -#: app/optionWindow.py:325 +#: app/optionWindow.py:326 msgid "After exports, quit the BEE2." msgstr "导出后,退出BEE2。" -#: app/optionWindow.py:332 +#: app/optionWindow.py:333 msgid "Launch Game" msgstr "启动游戏" -#: app/optionWindow.py:333 +#: app/optionWindow.py:334 msgid "After exporting, launch the selected game automatically." msgstr "导出后,自动启动目标游戏" -#: app/optionWindow.py:341 app/optionWindow.py:347 +#: app/optionWindow.py:342 app/optionWindow.py:348 msgid "Play Sounds" msgstr "播放音效" -#: app/optionWindow.py:352 +#: app/optionWindow.py:353 msgid "" "Pyglet is either not installed or broken.\n" "Sound effects have been disabled." @@ -1383,86 +1383,95 @@ msgstr "" "Pyglet未安装或损坏。\n" "音效已被禁用。" -#: app/optionWindow.py:359 +#: app/optionWindow.py:360 msgid "Reset Package Caches" msgstr "重置数据包缓存" -#: app/optionWindow.py:365 +#: app/optionWindow.py:366 msgid "Force re-extracting all package resources." msgstr "" -#: app/optionWindow.py:374 +#: app/optionWindow.py:375 msgid "Keep windows inside screen" msgstr "保持窗口在屏幕内" -#: app/optionWindow.py:375 +#: app/optionWindow.py:376 msgid "" "Prevent sub-windows from moving outside the screen borders. If you have " "multiple monitors, disable this." msgstr "防止子窗口移出屏幕边界。 如果您有多台显示器,请禁用此功能。" -#: app/optionWindow.py:385 +#: app/optionWindow.py:386 #, fuzzy msgid "Keep loading screens on top" msgstr "清理过时的旧截图" -#: app/optionWindow.py:387 +#: app/optionWindow.py:388 msgid "" "Force loading screens to be on top of other windows. Since they don't " "appear on the taskbar/dock, they can't be brought to the top easily " "again." msgstr "" -#: app/optionWindow.py:396 +#: app/optionWindow.py:397 msgid "Reset All Window Positions" msgstr "重置所有窗口的位置" -#: app/optionWindow.py:410 +#: app/optionWindow.py:411 msgid "Log missing entity counts" msgstr "记录丢失的实体数量" -#: app/optionWindow.py:411 +#: app/optionWindow.py:412 msgid "" "When loading items, log items with missing entity counts in their " "properties.txt file." msgstr "加载物品时,将缺少实体的物品数量记录在properties.txt文件中。" -#: app/optionWindow.py:419 +#: app/optionWindow.py:420 msgid "Log when item doesn't have a style" msgstr "记录缺失风格的物品" -#: app/optionWindow.py:420 +#: app/optionWindow.py:421 msgid "" "Log items have no applicable version for a particular style.This usually " "means it will look very bad." msgstr "记录没有当前风格版本的物品。这通常意味着它看起来很违和。" -#: app/optionWindow.py:428 +#: app/optionWindow.py:429 msgid "Log when item uses parent's style" msgstr "记录使用父风格的物品" -#: app/optionWindow.py:429 +#: app/optionWindow.py:430 msgid "" "Log when an item reuses a variant from a parent style (1970s using 1950s " "items, for example). This is usually fine, but may need to be fixed." msgstr "记录重复使用父风格变体的物品(例如1970s年代使用1950s年代的物品)。这通常没问题,但是可能需要修复。" -#: app/optionWindow.py:438 +#: app/optionWindow.py:439 msgid "Log missing packfile resources" msgstr "记录丢失的数据包" -#: app/optionWindow.py:439 +#: app/optionWindow.py:440 msgid "" "Log when the resources a \"PackList\" refers to are not present in the " "zip. This may be fine (in a prerequisite zip), but it often indicates an " "error." msgstr "记录“数据包列表”里丢失的zip文件。这可能没问题(必备的数据包还在),但通常会报错。" -#: app/optionWindow.py:448 +#: app/optionWindow.py:450 +#, fuzzy +msgid "Development Mode" +msgstr "开发者选项" + +#: app/optionWindow.py:451 +msgid "Enables displaying additional UI specific for development purposes." +msgstr "" + +#: app/optionWindow.py:459 msgid "Preserve Game Directories" msgstr "保留游戏目录" -#: app/optionWindow.py:450 +#: app/optionWindow.py:461 #, fuzzy msgid "" "When exporting, do not copy resources to \n" @@ -1473,19 +1482,19 @@ msgstr "" "当你导出时,不要覆盖写入目录“bee2/”和“sdk_content/maps/bee2/”。\n" "除非你正在建造新的内容,但要确定它不会被覆盖写入。" -#: app/optionWindow.py:461 +#: app/optionWindow.py:472 msgid "Show Log Window" msgstr "显示日志窗口" -#: app/optionWindow.py:463 +#: app/optionWindow.py:474 msgid "Show the log file in real-time." msgstr "实时显示日志文件。" -#: app/optionWindow.py:470 +#: app/optionWindow.py:481 msgid "Force Editor Models" msgstr "强制使用编辑器模型" -#: app/optionWindow.py:471 +#: app/optionWindow.py:482 msgid "" "Make all props_map_editor models available for use. Portal 2 has a limit " "of 1024 models loaded in memory at once, so we need to disable unused " @@ -1494,12 +1503,12 @@ msgstr "" "使所有props_map_editor模型可用。\n" "Portal 2一次最多可将1024个模型加载到内存中,因此我们需要禁用未使用的模型以释放此模型。" -#: app/optionWindow.py:482 +#: app/optionWindow.py:493 #, fuzzy msgid "Dump All objects" msgstr "反选所有复选框" -#: app/optionWindow.py:488 +#: app/optionWindow.py:499 msgid "Dump Items list" msgstr "" @@ -1535,7 +1544,7 @@ msgstr "BEE模组物品" msgid "Portal 2 Collapsed" msgstr "传送门2(已折叠)" -#: app/richTextBox.py:152 +#: app/richTextBox.py:151 msgid "Open \"{}\" in the default browser?" msgstr "在默认浏览器中打开 \"{}\" ?" @@ -1568,7 +1577,7 @@ msgid "Author: {}" msgid_plural "Authors: {}" msgstr[0] "作者: {}" -#: app/selector_win.py:1137 +#: app/selector_win.py:1145 msgid "Color: R={r}, G={g}, B={b}" msgstr "颜色: R={r}, G={g}, B={b}" @@ -1592,15 +1601,15 @@ msgstr "标签" msgid "Authors" msgstr "制作组" -#: app/tagsPane.py:157 +#: app/tagsPane.py:156 msgid "Any" msgstr "任何" -#: app/tagsPane.py:166 +#: app/tagsPane.py:165 msgid "All" msgstr "所有" -#: app/tagsPane.py:192 +#: app/tagsPane.py:191 msgid "Available Tags (click):" msgstr "可用标签(点击)" From dea8716f0c44db653f02a4b4c8ee663733a4658f Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Thu, 14 Jan 2021 14:31:26 +1000 Subject: [PATCH 85/87] AVbin is no longer used --- src/BEE2.spec | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/BEE2.spec b/src/BEE2.spec index 2bb0abde4..8e0b83728 100644 --- a/src/BEE2.spec +++ b/src/BEE2.spec @@ -143,21 +143,6 @@ EXCLUDES = [ 'argparse', ] - -# AVbin is needed to read OGG files. -INCLUDE_PATHS = [ - 'C:/Windows/system32/avbin.dll', # Win 32 bit - 'C:/Windows/sysWOW64/avbin64.dll', # Win 64 bit - '/usr/local/lib/libavbin.dylib', # OS X - '/usr/lib/libavbin.so', # Linux -] - -# Filter out files for other platforms -INCLUDE_LIBS = [ - (path, '.') for path in INCLUDE_PATHS - if os.path.exists(path) -] - bee_version = input('BEE2 Version (x.y.z): ') # Write this to the temp folder, so it's picked up and included. @@ -184,7 +169,6 @@ for snd in os.listdir('../sounds/'): bee2_a = Analysis( ['BEE2_launch.pyw'], pathex=[workpath, os.path.dirname(srctools.__path__[0])], - binaries=INCLUDE_LIBS, datas=data_files, hiddenimports=[ 'PIL._tkinter_finder', From 8eb45e4206d34112e8e83663a264f825c6d02901 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Thu, 14 Jan 2021 14:31:53 +1000 Subject: [PATCH 86/87] Update localisation masters --- i18n/BEE2.pot | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/i18n/BEE2.pot b/i18n/BEE2.pot index 69bb50edc..0269cf6ad 100644 --- a/i18n/BEE2.pot +++ b/i18n/BEE2.pot @@ -4,14 +4,14 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: https://github.com/BEEmod/BEE2.4/issues\n" -"POT-Creation-Date: 2020-09-20 10:31-0700\n" +"POT-Creation-Date: 2021-01-14 14:25+1000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.8.0\n" +"Generated-By: Babel 2.6.0\n" #: loadScreen.py msgid "Skipped!" @@ -1385,6 +1385,14 @@ msgid "" "error." msgstr "" +#: app/optionWindow.py +msgid "Development Mode" +msgstr "" + +#: app/optionWindow.py +msgid "Enables displaying additional UI specific for development purposes." +msgstr "" + #: app/optionWindow.py msgid "Preserve Game Directories" msgstr "" From 9ea159ac7eb355e6006f77e21bb91bd2e1eaba97 Mon Sep 17 00:00:00 2001 From: TeamSpen210 Date: Thu, 14 Jan 2021 14:36:06 +1000 Subject: [PATCH 87/87] Don't include the entirety of NumPy --- src/BEE2.spec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/BEE2.spec b/src/BEE2.spec index 8e0b83728..7ad791511 100644 --- a/src/BEE2.spec +++ b/src/BEE2.spec @@ -128,6 +128,8 @@ EXCLUDES = [ 'idlelib.tabbedpages', 'idlelib.textView', + 'numpy', # PIL.ImageFilter imports, we don't need NumPy! + 'bz2', # We aren't using this compression format (shutil, zipfile etc handle ImportError).. 'sqlite3', # Imported from aenum, but we don't use that enum subclass.