├── .gitignore ├── data ├── sound │ ├── build.ogg │ ├── drill.ogg │ ├── pop.ogg │ ├── snap.ogg │ └── shutdown.ogg ├── font │ ├── Roboto-Bold.ttf │ ├── font-awesome5.otf │ └── Roboto-Regular.ttf ├── music │ └── Contemplation.ogg └── model │ ├── pole.egg │ ├── hill.egg │ ├── pylon.egg │ └── superpylon.egg ├── gamelib ├── __init__.py ├── constructs │ ├── __init__.py │ ├── generator.py │ ├── pylon.py │ └── town.py ├── constants.py ├── line.py ├── dialog.py ├── panel.py ├── wire.py ├── construct.py ├── world.py └── game.py ├── requirements.txt ├── config.prc ├── run_game.py ├── setup.py └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | *.py[co] 3 | 4 | /screenshot-*.jpg 5 | -------------------------------------------------------------------------------- /data/sound/build.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rdb/pyweek26/HEAD/data/sound/build.ogg -------------------------------------------------------------------------------- /data/sound/drill.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rdb/pyweek26/HEAD/data/sound/drill.ogg -------------------------------------------------------------------------------- /data/sound/pop.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rdb/pyweek26/HEAD/data/sound/pop.ogg -------------------------------------------------------------------------------- /data/sound/snap.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rdb/pyweek26/HEAD/data/sound/snap.ogg -------------------------------------------------------------------------------- /data/font/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rdb/pyweek26/HEAD/data/font/Roboto-Bold.ttf -------------------------------------------------------------------------------- /data/sound/shutdown.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rdb/pyweek26/HEAD/data/sound/shutdown.ogg -------------------------------------------------------------------------------- /data/font/font-awesome5.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rdb/pyweek26/HEAD/data/font/font-awesome5.otf -------------------------------------------------------------------------------- /data/font/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rdb/pyweek26/HEAD/data/font/Roboto-Regular.ttf -------------------------------------------------------------------------------- /data/music/Contemplation.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rdb/pyweek26/HEAD/data/music/Contemplation.ogg -------------------------------------------------------------------------------- /gamelib/__init__.py: -------------------------------------------------------------------------------- 1 | from .game import Game 2 | 3 | def main(): 4 | game = Game() 5 | game.run() 6 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | --extra-index-url https://archive.panda3d.org 2 | panda3d>=1.10.0.dev 3 | numpy>=1.8.0 4 | -------------------------------------------------------------------------------- /gamelib/constructs/__init__.py: -------------------------------------------------------------------------------- 1 | from .generator import Generator 2 | from .pylon import Pylon 3 | from .town import Town 4 | -------------------------------------------------------------------------------- /config.prc: -------------------------------------------------------------------------------- 1 | # Comment next line out if your card has trouble opening a window. 2 | framebuffer-srgb true 3 | 4 | # Comment this out to see the glorious frames. 5 | #show-frame-rate-meter true 6 | 7 | # Play with this if you don't like the defaults 8 | win-size 1599 799 9 | #win-fixed-size true 10 | 11 | text-default-font $THIS_PRC_DIR/data/font/Roboto-Regular.ttf 12 | model-path $THIS_PRC_DIR/data/model 13 | model-path $THIS_PRC_DIR/data/music 14 | model-path $THIS_PRC_DIR/data/sound 15 | 16 | -------------------------------------------------------------------------------- /run_game.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys 4 | 5 | try: 6 | import panda3d 7 | import numpy 8 | except ImportError as ex: 9 | print(""" 10 | =================================================== 11 | 12 | This game requires Panda3D 1.10 and numpy >1.8.0 13 | 14 | Please run the following command to install them: 15 | 16 | pip install -r requirements.txt 17 | 18 | =================================================== 19 | """) 20 | print(repr(ex)) 21 | sys.exit(1) 22 | 23 | from gamelib import main 24 | main() 25 | -------------------------------------------------------------------------------- /gamelib/constants.py: -------------------------------------------------------------------------------- 1 | camera_speed = 3.0 2 | camera_min_zoom = 10.0 3 | camera_max_zoom = 50.0 4 | camera_window_border = 100.0 5 | cycle_unpowered_town_time = 0.6 6 | max_pylon_distance = 3 7 | max_wire_heat = 6.0 8 | show_debug_labels = False 9 | grid_spacing = 6 10 | town_shrink_rate = 1 11 | wire_sag = 0.4 12 | wire_thickness = 3 13 | energy_target_multiplier = 1.45 14 | 15 | upgrade_point_rarity = 18000.0 16 | 17 | music_rate_change_speed = 3.0 18 | 19 | label_bob_time = 0.5 20 | #normal_label_color = (1, 0.6, 0.05, 1) 21 | normal_label_color = (1, 0.32, 0.04, 1) 22 | important_label_color = (0.8, 0.04, 0.01, 1) 23 | 24 | ghost_alpha = 0.5 25 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup( 4 | name="let-there-be-light", 5 | options={ 6 | 'build_apps': { 7 | 'include_patterns': [ 8 | 'data/**', 9 | 'config.prc', 10 | ], 11 | 'gui_apps': { 12 | 'run_game': 'run_game.py', 13 | }, 14 | #'log_filename': '$USER_APPDATA/Let There Be Light/output.log', 15 | 'log_filename': '$USER_APPDATA/let-there-be-light.log', 16 | 'log_append': False, 17 | 'plugins': [ 18 | 'pandagl', 19 | 'p3openal_audio', 20 | 'p3fmod_audio', 21 | ], 22 | 'platforms': [ 23 | 'manylinux1_x86_64', 24 | 'macosx_10_6_x86_64', 25 | 'win_amd64', 26 | ], 27 | } 28 | } 29 | ) 30 | -------------------------------------------------------------------------------- /gamelib/constructs/generator.py: -------------------------------------------------------------------------------- 1 | from panda3d import core 2 | 3 | from ..construct import Construct 4 | import random 5 | 6 | 7 | class Generator(Construct): 8 | 9 | allow_wire_sag = False 10 | 11 | # Behaves like an upgraded pylon. 12 | wire_conductance = 3 13 | 14 | def __init__(self, world, pos, name): 15 | Construct.__init__(self, world, pos, name) 16 | self.capacity = 1 17 | 18 | model = loader.load_model("plant") 19 | model.reparent_to(self.root) 20 | #model.set_scale(2) 21 | #model.set_pos(-1, -1, -1) 22 | model.set_color_off(1) 23 | model.set_texture_off(1) 24 | 25 | self._update_label() 26 | 27 | self.attachments = list(model.find_all_matches("**/attachment.*")) 28 | random.shuffle(self.attachments) 29 | self.attachments = self.attachments[:6] 30 | 31 | def _update_label(self): 32 | if len(self.connections) > 0: 33 | self.set_label("{}\n{:.0f} MW".format(self.name, self.capacity)) 34 | else: 35 | self.set_label("Click here to\nbegin a power line", important=True) 36 | 37 | def on_update(self): 38 | self._update_label() 39 | -------------------------------------------------------------------------------- /gamelib/line.py: -------------------------------------------------------------------------------- 1 | from panda3d import core 2 | from copy import copy 3 | 4 | 5 | class PowerWire(object): 6 | drawer = core.WireSegs() 7 | drawer.set_color((0.2, 0.2, 0.2, 1)) 8 | drawer.set_thickness(2) 9 | 10 | drawer.move_to((0, 0, 1)) 11 | drawer.draw_to((0, 1, 1)) 12 | 13 | drawer.move_to((-0.1, 0, 0.9)) 14 | drawer.draw_to((-0.1, 1, 0.9)) 15 | drawer.move_to((0.1, 0, 0.9)) 16 | drawer.draw_to((0.1, 1, 0.9)) 17 | 18 | drawer.move_to((-0.15, 0, 0.8)) 19 | drawer.draw_to((-0.15, 1, 0.8)) 20 | drawer.move_to((0.15, 0, 0.8)) 21 | drawer.draw_to((0.15, 1, 0.8)) 22 | 23 | drawer.move_to((-0.1, 0, 0.7)) 24 | drawer.draw_to((-0.1, 1, 0.7)) 25 | drawer.move_to((0.1, 0, 0.7)) 26 | drawer.draw_to((0.1, 1, 0.7)) 27 | 28 | lines = drawer.create(False) 29 | del drawer 30 | 31 | def __init__(self, world, origin, target): 32 | self.world = world 33 | self.origin = origin 34 | self.target = target 35 | 36 | # If final is false, then self.target does not know about self yet. 37 | self.final = False 38 | 39 | self.path = self.world.root.attach_new_node(copy(self.lines)) 40 | self.path.set_light_off(True) 41 | 42 | @property 43 | def vector(self): 44 | return self.target.pos - self.origin.pos 45 | 46 | def set_target(self, to): 47 | assert not self.final 48 | self.target = to 49 | self.on_update() 50 | 51 | def finish(self): 52 | assert not self.final 53 | self.final = True 54 | 55 | def destroy(self): 56 | self.path.remove_node() 57 | 58 | if self.origin.connections.get(self.target) is self: 59 | del self.origin.connections[self.target] 60 | 61 | if self.target.connections.get(self.origin) is self: 62 | del self.target.connections[self.origin] 63 | 64 | def on_update(self): 65 | """Called when position information of neighbours changes.""" 66 | 67 | self.path.set_pos(self.origin.x, self.origin.y, 0) 68 | self.path.look_at(self.target.x, self.target.y, 0) 69 | self.path.set_sy((self.target.root.get_pos() - self.origin.root.get_pos()).length()) 70 | -------------------------------------------------------------------------------- /gamelib/dialog.py: -------------------------------------------------------------------------------- 1 | from panda3d import core 2 | 3 | from direct.gui import DirectGuiGlobals as DGG 4 | from direct.gui.DirectFrame import DirectFrame 5 | from direct.gui.DirectButton import DirectButton 6 | from direct.gui.OnscreenText import OnscreenText 7 | from direct.showbase.DirectObject import DirectObject 8 | 9 | from . import constants 10 | 11 | import sys 12 | 13 | 14 | color1 = (0.9, 0.9, 0.9, 1) 15 | color0 = constants.normal_label_color 16 | 17 | 18 | if sys.version_info >= (3, 0): 19 | unichr = chr 20 | 21 | 22 | class Dialog(DirectObject): 23 | 24 | def __init__(self, parent, text="", font=None, icon_font=None): 25 | self.outer = DirectFrame( 26 | parent=parent, 27 | frameSize=(-0.7, 0.7, -0.4, 0.4), 28 | frameColor=color0, 29 | ) 30 | 31 | self.inner = DirectFrame( 32 | parent=self.outer, 33 | frameSize=(-0.695, 0.695, -0.395, 0.395), 34 | frameColor=color1, 35 | text_scale=0.05, 36 | text_fg=(0.1, 0.1, 0.1, 1), 37 | text_font=font, 38 | text_pos=(-0.65, 0.37), 39 | text_align=core.TextNode.A_left, 40 | text=text, 41 | ) 42 | self.outer.hide() 43 | 44 | frame = DirectFrame(parent=self.inner, pos=(-0.125, 0, -0.355), frameColor=color0, frameSize=(0, 0.25, 0, 0.25)) 45 | button = DirectButton(parent=frame, pos=(0.005, 0, 0.005), text='', frameSize=(0, 0.24, 0, 0.24), text_scale=0.04, text_pos=(0.12, 0.025), frameColor=color0, text_fg=color1, relief=DGG.FLAT, command=self.on_click) 46 | self.button = button 47 | 48 | icon = OnscreenText(parent=button, pos=(0.12, 0.12), text='', font=icon_font, scale=0.08, fg=color1) 49 | icon.name = "icon" 50 | self.icon = icon 51 | 52 | def on_click(self): 53 | if self.callback is not None: 54 | self.callback() 55 | self.hide() 56 | 57 | def show(self, text, button_text='', button_icon=None, callback=None): 58 | self.inner['text'] = text 59 | self.outer.show() 60 | self.callback = callback 61 | 62 | self.button['text'] = button_text 63 | if button_icon is not None: 64 | self.icon['text'] = unichr(button_icon) 65 | else: 66 | self.icon['text'] = '' 67 | 68 | self.accept('enter', self.on_click) 69 | 70 | def hide(self): 71 | self.outer.hide() 72 | self.callback = None 73 | self.ignore('enter') 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Let There Be Light 2 | ================== 3 | 4 | This is an entry in [PyWeek 26](https://pyweek.org/26/), with the theme "Flow". 5 | 6 | [Click here to go to the PyWeek entry page.](https://pyweek.org/e/rdb26/) 7 | 8 | ![Screenshot](https://pyweek.org/media/dl/26/rdb26/screenshot-day7.jpg) 9 | 10 | Dependencies 11 | ------------ 12 | 13 | This game requires Python 3. I recommend installing the dependencies (Panda3D 1.10 and numpy) via pip, using the command: 14 | 15 | ``` 16 | pip install -r requirements.txt 17 | ``` 18 | 19 | Running the game 20 | ---------------- 21 | 22 | Open a terminal window, "cd" to the game directory and run: 23 | 24 | ``` 25 | python run_game.py 26 | ``` 27 | 28 | Playing the game 29 | ---------------- 30 | 31 | The game requires the use of keyboard and mouse. Use the arrow keys to pan 32 | the camera around the map. To make a power line, click the source and then 33 | click where you want to target it to. Use escape to cancel. 34 | 35 | Troubleshooting 36 | --------------- 37 | 38 | If you can't get the game to run properly, edit `config.prc` to tweak the 39 | settings. In particular, if your driver refuses to open a window, remove the 40 | line that says `framebuffer-srgb true`. The game will look dark, however. 41 | 42 | Controls 43 | -------- 44 | 45 | * `1`: switch to the connection tool. 46 | * `2`: switch to the upgrade tool. Only to be used on pylons. 47 | * `3`: switch to the erase tool. Only to be used on pylons. 48 | * The mouse wheel zooms in and out. 49 | * Arrow keys navigate around the map. 50 | * `space`: toggles pause. 51 | * `tab`: cycles the camera focus between unpowered towns. 52 | * `shift-s`: takes a screenshot and save it to the current directory. 53 | * `shift-q`: immediately exits the game. 54 | 55 | And these are for developer / testing use only: 56 | 57 | * `shift-l`: dumps the scene graph to the console. 58 | * `shift-p`: attaches to a PStats server; requires `want-pstats true` in config.prc. 59 | * `shift-t`: spawns a new town in a random location. 60 | * `shift-f`: switches the game speed to 10x until you change it again. 61 | 62 | Acknowledgements 63 | ---------------- 64 | 65 | The music is Contemplation by OpenGameArt user Joth. 66 | 67 | Many thanks to the people who keep putting up CC0 sound effects online. 68 | 69 | Many thanks to fireclaw, wezu and others for their help testing the game. 70 | 71 | Many thanks to those in the PyWeek team and all the other entrants for contributing to make this an awesome challenge, and (hopefully) for taking the time to run and review my game. 72 | 73 | ~rdb 74 | -------------------------------------------------------------------------------- /gamelib/panel.py: -------------------------------------------------------------------------------- 1 | from panda3d import core 2 | 3 | from direct.gui import DirectGuiGlobals as DGG 4 | from direct.gui.DirectFrame import DirectFrame 5 | from direct.gui.DirectButton import DirectButton 6 | from direct.gui.OnscreenText import OnscreenText 7 | from direct.showbase.DirectObject import DirectObject 8 | 9 | from . import constants 10 | 11 | import sys 12 | 13 | 14 | color1 = (0.9, 0.9, 0.9, 1) 15 | color0 = constants.normal_label_color 16 | 17 | if sys.version_info >= (3, 0): 18 | unichr = chr 19 | 20 | 21 | class Panel(DirectObject): 22 | 23 | def __init__(self, parent, align, icon_font): 24 | self.buttons = [] 25 | self.icons = [] 26 | self.icon_font = icon_font 27 | 28 | self.align = align 29 | self.frame = DirectFrame( 30 | parent=parent, 31 | frameSize=self._get_frame_size(), 32 | frameColor=(0.9, 0.9, 0.9, 0.5), 33 | ) 34 | 35 | if align == 'right': 36 | self.frame.set_pos(-0.05, 0, 0.05) 37 | else: 38 | self.frame.set_pos(0.05, 0, 0.05) 39 | 40 | self.selected_button = None 41 | self.selected_icon = None 42 | 43 | self.visible = False 44 | self.frame.hide() 45 | 46 | self.hovered = False 47 | 48 | def show(self): 49 | self.frame.show() 50 | self.visible = True 51 | 52 | self.frame['state'] = DGG.NORMAL 53 | self.frame.bind(DGG.WITHOUT, self.on_hover, [False]) 54 | self.frame.bind(DGG.WITHIN, self.on_hover, [True]) 55 | 56 | def _get_frame_size(self): 57 | if self.align == 'right': 58 | return (0, -0.02 - 0.27 * len(self.buttons), 0, 0.3) 59 | else: 60 | return (0, 0.02 + 0.27 * len(self.buttons), 0, 0.3) 61 | 62 | def add_button(self, text, icon=None, callback=None, arg=None, shortcut=None): 63 | i = len(self.buttons) 64 | x = i * 0.27 + 0.02 65 | frame = DirectFrame(parent=self.frame, pos=(x, 0, 0.02), frameColor=color0, frameSize=(0, 0.25, 0, 0.25)) 66 | button = DirectButton(parent=frame, pos=(0.005, 0, 0.005), text=text, frameSize=(0, 0.24, 0, 0.24), text_scale=0.04, text_pos=(0.12, 0.025), frameColor=color0, text_fg=color1, relief=DGG.FLAT, command=self.on_click, extraArgs=[i, callback, arg]) 67 | self.buttons.append(button) 68 | 69 | self.frame['frameSize'] = self._get_frame_size() 70 | 71 | if icon is not None: 72 | icon = OnscreenText(parent=button, pos=(0.12, 0.12), text=unichr(icon), font=self.icon_font, scale=0.08, fg=color1) 73 | icon.name = "icon" 74 | self.icons.append(icon) 75 | else: 76 | self.icons.append(None) 77 | 78 | if shortcut: 79 | self.accept(shortcut, self.on_click, [i, callback, arg]) 80 | 81 | if self.align == 'right': 82 | self._reposition_buttons() 83 | 84 | def _reposition_buttons(self): 85 | for i, button in enumerate(self.buttons): 86 | if self.align == 'right': 87 | x = ((i - len(self.buttons)) * 0.27) 88 | else: 89 | x = i * 0.27 + 0.02 90 | button.parent.set_x(x) 91 | 92 | def on_click(self, i, callback, arg): 93 | if self.visible: 94 | self.select_button(i) 95 | callback(arg) 96 | 97 | def on_hover(self, state, pos=None): 98 | self.hovered = state 99 | 100 | def select_button(self, i): 101 | if self.selected_button is not None: 102 | button = self.selected_button 103 | button['frameColor'] = color0 104 | button['text_fg'] = color1 105 | 106 | if self.selected_icon is not None: 107 | self.selected_icon['fg'] = color1 108 | 109 | button = self.buttons[i] 110 | self.selected_button = button 111 | 112 | button['frameColor'] = color1 113 | button['text_fg'] = color0 114 | 115 | icon = self.icons[i] 116 | self.selected_icon = icon 117 | 118 | if icon is not None: 119 | icon['fg'] = color0 120 | -------------------------------------------------------------------------------- /gamelib/constructs/pylon.py: -------------------------------------------------------------------------------- 1 | from panda3d import core 2 | 3 | from ..construct import Construct 4 | from .. import constants 5 | 6 | 7 | class Pylon(Construct): 8 | 9 | selection_distance = 1 10 | upgradable = True 11 | erasable = True 12 | wire_conductance = 0.5 13 | 14 | def __init__(self, world, pos, name): 15 | Construct.__init__(self, world, pos, name) 16 | 17 | self.placed = False 18 | self.stashed = False 19 | 20 | self.model = loader.load_model("pylon") 21 | self.model.reparent_to(self.root) 22 | self.model.set_color_off(1) 23 | self.model.set_alpha_scale(constants.ghost_alpha) 24 | self.model.set_transparency(core.TransparencyAttrib.M_alpha) 25 | 26 | self.upgrade_sound = world.audio3d.load_sfx('drill.ogg') 27 | self.upgrade_sound.set_volume(14) 28 | 29 | self.build_sound = world.audio3d.load_sfx('build.ogg') 30 | self.build_sound.set_volume(24) 31 | 32 | self.attachments = [] 33 | #for x, z in (-0.1, 0.9), (-0.1, 0.7), (-0.15, 0.8), (0, 1), (0.15, 0.9), (0.1, 0.7), (0.1, 0.9): 34 | #for x, z in (-0.25, 0.85), (-0.15, 1.05), (0.15, 1.05), (0.25, 0.85): 35 | for x, z in (-0.25 * 0.8, 0.85 * 0.8), (0, 0.8), (0.25 * 0.8, 0.85 * 0.8): 36 | #for x, z in (-0.25, 0.65), (-0.13, 1), (0.13, 1), (0.25, 0.65): 37 | attach = self.model.attach_new_node("attach") 38 | attach.set_pos(x, 0, z) 39 | self.attachments.append(attach) 40 | 41 | def __del__(self): 42 | print("Destroying pylon {}".format(self)) 43 | 44 | def destroy(self): 45 | self.world.pylons.discard(self) 46 | Construct.destroy(self) 47 | 48 | def upgrade(self): 49 | if self.upgraded: 50 | return 51 | 52 | self.upgraded = True 53 | self.wire_conductance = 3 54 | 55 | for attach in self.attachments: 56 | attach.remove_node() 57 | self.attachments = [] 58 | 59 | self.model.remove_node() 60 | self.model = loader.load_model("superpylon") 61 | self.model.reparent_to(self.root) 62 | self.model.set_color_off(1) 63 | 64 | for x, z in (-0.3, 0.6), (-0.25, 0.9), (-0.15, 1.05), (0.15, 1.0), (0.25, 0.9), (0.3, 0.6): 65 | attach = self.model.attach_new_node("attach") 66 | attach.set_pos(x, 0, z) 67 | self.attachments.append(attach) 68 | 69 | pos = self.root.get_pos(self.world.root) 70 | self.upgrade_sound.set_3d_attributes(pos[0], pos[1], pos[2], 0, 0, 0) 71 | self.upgrade_sound.play() 72 | 73 | self.on_update() 74 | 75 | def stash(self): 76 | self.world.pylons.discard(self) 77 | self.root.detach_node() 78 | self.stashed = True 79 | 80 | def unstash(self): 81 | self.stashed = False 82 | self.world.pylons.add(self) 83 | self.root.reparent_to(self.world.root) 84 | 85 | def finish_placement(self): 86 | Construct.finish_placement(self) 87 | 88 | self.model.set_alpha_scale(1) 89 | self.model.clear_transparency() 90 | 91 | pos = self.root.get_pos(self.world.root) 92 | self.build_sound.set_3d_attributes(pos[0], pos[1], pos[2], 0, 0, 0) 93 | self.build_sound.play() 94 | 95 | def on_update(self): 96 | """Updates state based on position information of neighbours.""" 97 | 98 | if len(self.connections) == 0: 99 | # It's orphaned, so we let it go. 100 | if not self.stashed: 101 | print("Orphaned pylon {}".format(self)) 102 | self.stash() 103 | return 104 | else: 105 | self.unstash() 106 | 107 | #TODO: different algo: grab closest two angle, between two connections, 108 | # then reduce 109 | 110 | heading = 0 111 | for wire in self.connections.values(): 112 | #print(wire.path.get_h()) 113 | heading += wire.angle % 360.0 114 | 115 | h = heading / len(self.connections) 116 | 117 | if len(self.connections) == 2: 118 | wire1, wire2 = self.connections.values() 119 | if abs(wire1.vector.signed_angle_deg(wire2.vector)) > 90: 120 | h += 90 121 | 122 | prev_h = self.model.get_h() 123 | if h != prev_h: 124 | self.model.set_h(h) 125 | 126 | # Update wires 127 | for wire in self.connections.values(): 128 | wire.on_update() 129 | 130 | def position_within_radius_of(self, x, y, other, max_distance): 131 | """Called while it has still one connection.""" 132 | 133 | # Limit to max wire length 134 | if max_distance is not None: 135 | dir = core.Point2(x, y) - other.pos 136 | if dir.length_squared() > max_distance ** 2: 137 | x, y = other.pos + dir.normalized() * max_distance 138 | 139 | #TODO: limit angle? 140 | 141 | # This also calls on_update. 142 | Construct.position(self, x, y) 143 | -------------------------------------------------------------------------------- /gamelib/constructs/town.py: -------------------------------------------------------------------------------- 1 | from panda3d import core 2 | 3 | from ..construct import Construct 4 | from .. import constants 5 | 6 | import math 7 | import numpy 8 | 9 | 10 | category_names = [ 11 | "dwelling", 12 | "hamlet", 13 | "village", 14 | "village", 15 | "village", 16 | # 50 MW 17 | "town", "town", "town", "town", "town", 18 | # 100 MW 19 | "city", "city", "city", "city", "city", 20 | "city", "city", "city", "city", "city", 21 | "city", "city", "city", "city", "city", 22 | # 250 MW 23 | "metropolis", 24 | ] 25 | 26 | dist_matrix = numpy.zeros((5, 5)) 27 | for x in range(5): 28 | for y in range(5): 29 | dist = math.sqrt((x - 2) ** 2 + (y - 2) ** 2) 30 | dist /= 2.8284271247461903 31 | dist = 1 - dist 32 | dist **= 2 33 | dist *= 4 34 | dist_matrix[x, y] = dist 35 | 36 | 37 | class Town(Construct): 38 | 39 | # We make the last connection point to a town inherently stronger. 40 | wire_conductance = 3 41 | 42 | def __init__(self, world, pos, name, placed=False): 43 | Construct.__init__(self, world, pos, name) 44 | self.size = 1 45 | self.powered = False 46 | self.name = "dwelling" 47 | self.placed = placed 48 | 49 | self.pop_sound = world.audio3d.load_sfx('pop.ogg') 50 | self.pop_sound.set_volume(8) 51 | world.audio3d.attach_sound_to_object(self.pop_sound, self.root) 52 | 53 | self.shutdown_sound = world.audio3d.load_sfx('shutdown.ogg') 54 | self.shutdown_sound.set_volume(32) 55 | world.audio3d.attach_sound_to_object(self.shutdown_sound, self.root) 56 | 57 | # Right now, we force a copy so we get a unique windowed material. 58 | city = loader.load_model("city.egg", noCache=True) 59 | self.tiles_by_size = [ 60 | tuple(city.find_all_matches("**/tiny.*")), 61 | tuple(city.find_all_matches("**/small.*")), 62 | tuple(city.find_all_matches("**/medium.*")), 63 | tuple(city.find_all_matches("**/large.*")), 64 | ] 65 | for tiles in self.tiles_by_size: 66 | for tile in tiles: 67 | tile.set_pos(0, 0, 0) 68 | #tile.set_scale(0.5) 69 | #tile.flatten_strong() 70 | 71 | self.grid = numpy.zeros((5, 5), dtype=int) 72 | self.grid[2][2] = 1 73 | 74 | # We'll change the emit color when the lights go off. 75 | self.window_mat = city.find_material("window") 76 | self.window_mat.diffuse = (0.1, 0.1, 0.1, 1) 77 | self.window_emit = core.LVecBase4(self.window_mat.emission) 78 | 79 | # Make this city unique. 80 | self.random_offsets = numpy.random.random_sample((5, 5)) - 0.5 81 | self.random_choices = numpy.random.randint(2, size=(5, 5)) 82 | self.random_orients = numpy.random.randint(4, size=(5, 5)) 83 | 84 | self.city = self.root.attach_new_node("city") 85 | self._rebuild_city() 86 | 87 | attach = self.root.attach_new_node("attach") 88 | attach.set_z(0.2) 89 | self.attachments.append(attach) 90 | 91 | self.power_off() 92 | 93 | @property 94 | def power(self): 95 | return 10 * (self.size ** 0.85) 96 | 97 | @property 98 | def resistance(self): 99 | return (230 ** 2) / self.power 100 | 101 | @property 102 | def current(self): 103 | if not self.powered: 104 | return 0 105 | return 230 / self.resistance 106 | 107 | def power_on(self): 108 | # Turn on lights 109 | self.powered = True 110 | self.window_mat.emission = self.window_emit 111 | self.city.set_color_scale((1.5, 1.5, 1.5, 1)) 112 | 113 | self._update_label() 114 | 115 | def power_off(self): 116 | # Turn off lights 117 | self.powered = False 118 | self.window_mat.emission = (0, 0, 0, 1) 119 | self.city.set_color_scale((1, 1, 1, 1)) 120 | 121 | self._update_label() 122 | 123 | def on_voltage_change(self, voltage): 124 | if not self.powered: 125 | self.power_on() 126 | 127 | Construct.on_voltage_change(self, voltage) 128 | 129 | def on_disconnected(self): 130 | if self.powered: 131 | self.power_off() 132 | self.shutdown_sound.play() 133 | 134 | Construct.on_disconnected(self) 135 | 136 | def _update_label(self): 137 | if not self.placed: 138 | return 139 | if self.powered: 140 | name = self.name[0].upper() + self.name[1:] 141 | self.set_label(text="{}\n{:.0f} MW".format(name, self.power * 0.1)) 142 | else: 143 | self.set_label(text="This {} is not\ngetting power!".format(self.name), important=True) 144 | 145 | def _rebuild_city(self): 146 | self.city.children.detach() 147 | 148 | for x in range(5): 149 | for y in range(5): 150 | which = self.grid[x][y] 151 | if which > 0: 152 | tiles = self.tiles_by_size[which - 1] 153 | tile = tiles[self.random_choices[x, y]].copy_to(self.city) 154 | tile.set_pos(x - 2, y - 2, 0) 155 | tile.set_h(90 * self.random_orients[x, y]) 156 | tile.set_scale(0.5) 157 | 158 | def grow(self, dt): 159 | if not self.placed: 160 | return 161 | 162 | if self.powered: 163 | self.size += dt 164 | else: 165 | self.size = max(1, self.size - dt * constants.town_shrink_rate) 166 | 167 | #growth = 4.5 - (500 / (self.size + (500 / 4.5))) 168 | growth = 8 - (1000 / (self.size * 0.4 + (1000 / 8))) 169 | 170 | # Compute new tiles. 171 | new_grid = numpy.zeros((5, 5), dtype=int) 172 | new_grid = numpy.rint((dist_matrix + self.random_offsets) * growth, out=new_grid, casting='unsafe') 173 | new_grid = numpy.clip(new_grid, 0, 4) 174 | 175 | # Always a house in the center. 176 | if new_grid[2][2] < 1: 177 | new_grid[2][2] = 1 178 | 179 | if (new_grid != self.grid).any(): 180 | self.grid = new_grid 181 | self._rebuild_city() 182 | self.pop_sound.play() 183 | 184 | # Make up a nice name for it... calling a single building a "city" 185 | # seems so silly. 186 | category = min(int(self.size // 10), len(category_names) - 1) 187 | self.name = category_names[category] 188 | 189 | self._update_label() 190 | -------------------------------------------------------------------------------- /gamelib/wire.py: -------------------------------------------------------------------------------- 1 | from panda3d import core 2 | from copy import copy 3 | import math 4 | 5 | from . import constants 6 | 7 | acosh_scale = math.acosh(2) * 2 8 | 9 | 10 | class PowerWire(object): 11 | def __init__(self, world, origin, target): 12 | self.world = world 13 | self.origin = origin 14 | self.target = target 15 | 16 | self.heat = 0 17 | 18 | # If placed is false, then self.target does not know about self yet. 19 | self.placed = False 20 | 21 | self.path = self.world.root.attach_new_node(core.GeomNode("wires")) 22 | self.path.set_light_off(1) 23 | self.path.set_color_scale((0.05, 0.05, 0.05, constants.ghost_alpha)) 24 | #self.path.set_transparency(core.TransparencyAttrib.M_alpha) 25 | 26 | if constants.show_debug_labels: 27 | debug_label_text = core.TextNode("debug_label") 28 | debug_label_text.set_card_color((1, 0, 0, 1)) 29 | debug_label_text.set_card_as_margin(0.5, 0.5, 0.5, 0.5) 30 | debug_label_text.set_align(core.TextNode.A_center) 31 | self.debug_label = self.world.root.attach_new_node(debug_label_text) 32 | pos = (self.origin.pos + self.target.pos) * 0.5 33 | self.debug_label.set_pos(pos[0], pos[1], 1) 34 | self.debug_label.set_scale(0.2) 35 | self.debug_label.set_light_off(1) 36 | self.debug_label.set_depth_write(False) 37 | self.debug_label.set_depth_test(False) 38 | self.debug_label.set_bin('fixed', 0) 39 | self.debug_label.node().set_text("0 A") 40 | 41 | def __repr__(self): 42 | r = "{!r}--{!r}".format(self.origin, self.target) 43 | if self.heat > 0.0: 44 | r += " (HOT:{:.1f})".format(self.heat) 45 | return r 46 | 47 | @property 48 | def resistance(self): 49 | # 1 ohm normally, but 0.2 if target or origin is upgraded. 50 | # If target and origin are both pylons, but only one are upgraded, the 51 | # effective resistance is only 0.45. 52 | if self.target and self.origin: 53 | return (1.0 / (self.origin.wire_conductance + self.target.wire_conductance)) 54 | return 1.0 55 | 56 | def _draw_lines(self): 57 | self.path.node().remove_all_geoms() 58 | 59 | drawer = core.LineSegs() 60 | #drawer.set_color((0.05, 0.05, 0.05, 1)) 61 | drawer.set_thickness(constants.wire_thickness) 62 | 63 | origin_attachments = self.origin.attachments 64 | target_attachments = self.target.attachments 65 | 66 | # Don't cross the lines. 67 | if origin_attachments[0].get_quat(self.path).get_forward().dot(target_attachments[0].get_quat(self.path).get_forward()) < 0: 68 | target_attachments = tuple(reversed(target_attachments)) 69 | 70 | sag = self.origin.allow_wire_sag and self.target.allow_wire_sag 71 | 72 | ti = 0 73 | oi = 0 74 | tstep = 1 75 | ostep = 1 76 | 77 | # Step through attachment list more slowly if one has more than the 78 | # other. 79 | if len(origin_attachments) > len(target_attachments): 80 | tstep = len(target_attachments) / float(len(origin_attachments)) 81 | elif len(origin_attachments) < len(target_attachments): 82 | ostep = len(origin_attachments) / float(len(target_attachments)) 83 | 84 | for i in range(max(len(origin_attachments), len(target_attachments))): 85 | from_point = origin_attachments[int(oi)].get_pos(self.path) 86 | to_point = target_attachments[int(ti)].get_pos(self.path) 87 | 88 | # Interpolate. 89 | drawer.move_to(from_point) 90 | for t in (0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9): 91 | point = from_point * (1 - t) + to_point * t 92 | if sag: 93 | point.z += constants.wire_sag * (math.cosh((t - 0.5) * acosh_scale) - 2) 94 | drawer.draw_to(point) 95 | drawer.draw_to(to_point) 96 | 97 | oi += ostep 98 | ti += tstep 99 | 100 | wires = drawer.create(self.path.node()) 101 | 102 | @property 103 | def vector(self): 104 | return self.target.pos - self.origin.pos 105 | 106 | @property 107 | def angle(self): 108 | return -self.vector.signed_angle_deg((0, 1)) 109 | 110 | def try_set_target(self, to): 111 | """Try changing the target of the wire, for use during placement.""" 112 | assert not self.placed 113 | 114 | if to is None: 115 | return False 116 | 117 | if to is self.origin: 118 | return False 119 | 120 | if not to.placed: 121 | return False 122 | 123 | # Already a placed connection here? 124 | if to in self.origin.connections and self.origin.connections[to].placed: 125 | return False 126 | 127 | if (self.origin.pos - to.pos).length_squared() > (constants.max_pylon_distance + to.selection_distance) ** 2: 128 | return False 129 | 130 | self.set_target(to) 131 | return True 132 | 133 | def set_target(self, to): 134 | """During placement, force connecting to this node.""" 135 | assert to is not self.origin 136 | 137 | if self.target is not to: 138 | del self.target.connections[self.origin] 139 | del self.origin.connections[self.target] 140 | self.target.on_update() 141 | 142 | self.target = to 143 | self.target.connections[self.origin] = self 144 | self.origin.connections[self.target] = self 145 | self.on_update() 146 | 147 | self.target.on_update() 148 | self.origin.on_update() 149 | 150 | def cancel_placement(self): 151 | del self.target.connections[self.origin] 152 | del self.origin.connections[self.target] 153 | 154 | self.on_update() 155 | self.destroy() 156 | 157 | def finish_placement(self): 158 | assert not self.placed 159 | self.placed = True 160 | 161 | print("Finishing placement of {}".format(self)) 162 | if not self.target.placed: 163 | self.target.finish_placement() 164 | 165 | self.path.set_color_scale((0.05, 0.05, 0.05, 1)) 166 | 167 | def destroy(self): 168 | if self.origin.connections.get(self.target) is self: 169 | del self.origin.connections[self.target] 170 | 171 | if self.target.connections.get(self.origin) is self: 172 | del self.target.connections[self.origin] 173 | 174 | self.origin.on_update() 175 | self.target.on_update() 176 | 177 | self.path.remove_node() 178 | if constants.show_debug_labels: 179 | self.debug_label.remove_node() 180 | 181 | @property 182 | def overheated(self): 183 | return self.heat >= constants.max_wire_heat 184 | 185 | def on_current_change(self, current, dt): 186 | """Called to process an update in current flowing through.""" 187 | 188 | power = current ** 2 * self.resistance 189 | 190 | if constants.show_debug_labels: 191 | self.debug_label.node().set_text("{:.1f} W".format(power)) 192 | 193 | if power > 2: 194 | # Start overheating. 195 | self.heat += min((power - 2), 1) * dt 196 | self.path.set_color_scale((1, 0, 0, 1)) 197 | #self.path.set_color_scale((1, 3 - power, 0, 1)) 198 | elif power > 1: 199 | # Cool down. 200 | self.heat = max(self.heat - dt, 0) 201 | self.path.set_color_scale((1, 2 - power, 2 - power, 1)) 202 | #self.path.set_color_scale((power - 1, 1, 0, 1)) 203 | elif power > 0: 204 | # Cool down faster. 205 | self.heat = max(self.heat - 2 * dt, 0) 206 | self.path.set_color_scale((1, 1, 1, 1)) 207 | #self.path.set_color_scale((0, power, 0, 1)) 208 | else: 209 | self.heat = 0 210 | self.path.set_color_scale((0.05, 0.05, 0.05, 1)) 211 | 212 | def on_update(self): 213 | """Called when position information of neighbours changes.""" 214 | 215 | #self.path.set_pos(self.origin.x, self.origin.y, 0) 216 | #self.path.look_at(self.target.x, self.target.y, 0) 217 | #self.path.set_sy((self.target.root.get_pos() - self.origin.root.get_pos()).length()) 218 | 219 | if constants.show_debug_labels: 220 | pos = (self.origin.pos + self.target.pos) * 0.5 221 | self.debug_label.set_pos(pos[0] + -0.5, pos[1] + -1, 1.5) 222 | 223 | self._draw_lines() 224 | -------------------------------------------------------------------------------- /gamelib/construct.py: -------------------------------------------------------------------------------- 1 | from panda3d import core 2 | from direct.interval.IntervalGlobal import LerpPosInterval, Sequence 3 | 4 | from .wire import PowerWire 5 | from . import constants 6 | 7 | 8 | class Construct(object): 9 | 10 | allow_wire_sag = True 11 | selection_distance = 2 12 | upgradable = False 13 | erasable = False 14 | wire_conductance = 1 15 | 16 | def __init__(self, world, pos, name): 17 | self.world = world 18 | self.x, self.y = pos 19 | 20 | self.name = name 21 | 22 | # Starts out as a ghost. 23 | self.placed = False 24 | self.upgraded = False 25 | 26 | self.root = world.root.attach_new_node(name) 27 | self.root.set_pos(pos[0], pos[1], 0) 28 | self.attachments = [] 29 | 30 | label_text = core.TextNode("label") 31 | label_text.set_align(core.TextNode.A_left) 32 | label_text.set_card_color(constants.normal_label_color) 33 | label_text.set_card_as_margin(0.5, 0.5, 0.5, 0.5) 34 | 35 | self.label = self.root.attach_new_node(label_text) 36 | self.label.set_pos(0.0, 0, 1.5) 37 | self.label.set_scale(0.2) 38 | self.label.set_light_off(1) 39 | self.label.set_color_scale_off(1) 40 | self.label.set_depth_write(False) 41 | self.label.set_depth_test(False) 42 | self.label.set_bin('fixed', 10) 43 | self.label.set_billboard_point_eye() 44 | self.label.hide() 45 | 46 | # Set to show label even if not highlighted. 47 | self.__label_text = '' 48 | self.__label_important = False 49 | self.__label_effective_important = False 50 | self.highlight_mode = None 51 | 52 | cm = core.CardMaker("arrow") 53 | cm.set_frame(-1, 1, -1, 1) 54 | arrow = self.label.attach_new_node(cm.generate()) 55 | arrow.set_r(45) 56 | arrow.set_x(0.7) 57 | arrow.set_z(-1.5) 58 | arrow.set_scale(0.8) 59 | arrow.set_color(label_text.card_color) 60 | arrow.set_depth_write(False) 61 | arrow.set_depth_test(False) 62 | arrow.set_bin('fixed', 0) 63 | self.arrow = arrow 64 | 65 | self.label_bob = Sequence( 66 | self.label.posInterval(constants.label_bob_time, (0.0, 0, 1.7), bakeInStart=True, blendType='easeInOut'), 67 | self.label.posInterval(constants.label_bob_time, (0.0, 0, 1.5), bakeInStart=True, blendType='easeInOut'), 68 | ) 69 | 70 | self.connections = {} 71 | 72 | if constants.show_debug_labels: 73 | debug_label_text = core.TextNode("debug_label") 74 | debug_label_text.set_card_color((0, 0.5, 0, 1)) 75 | debug_label_text.set_card_as_margin(0.5, 0.5, 0.5, 0.5) 76 | self.debug_label = self.root.attach_new_node(debug_label_text) 77 | self.debug_label.set_pos(-0.5, -1, 1.5) 78 | self.debug_label.set_scale(0.2) 79 | self.debug_label.set_light_off(1) 80 | self.debug_label.set_color_scale_off(1) 81 | self.debug_label.set_depth_write(False) 82 | self.debug_label.set_depth_test(False) 83 | self.debug_label.set_bin('fixed', 0) 84 | self.debug_label.node().set_text("0V") 85 | 86 | def __repr__(self): 87 | return "<{} \"{}\">".format(type(self).__name__, self.name) 88 | 89 | @property 90 | def pos(self): 91 | return core.Point2(self.x, self.y) 92 | 93 | @property 94 | def neighbours(self): 95 | return [node for node, wire in self.connections.items() if wire.placed] 96 | 97 | def destroy(self): 98 | for wire in list(self.connections.values()): 99 | wire.destroy() 100 | 101 | assert not self.connections 102 | self.root.remove_node() 103 | 104 | def finish_placement(self): 105 | self.placed = True 106 | 107 | def connect_to(self, other): 108 | if other in self.connections: 109 | return self.connections[other] 110 | 111 | wire = PowerWire(self.world, self, other) 112 | other.connections[self] = wire 113 | self.connections[other] = wire 114 | return wire 115 | 116 | def position(self, x, y): 117 | self.root.set_pos(x, y, 0) 118 | self.x = x 119 | self.y = y 120 | for wire in self.connections.values(): 121 | wire.on_update() 122 | if wire.origin is self: 123 | wire.target.on_update() 124 | elif wire.target is self: 125 | wire.origin.on_update() 126 | self.on_update() 127 | 128 | def set_label(self, text, important=False): 129 | self.__label_text = text 130 | self.__label_important = important 131 | 132 | if self.highlight_mode not in ('connect', 'erase', 'placing', 'upgrade', 'upgrade-no-money', 'too-far', 'already-connected', 'bad-terrain'): 133 | self._do_set_label(text, important) 134 | 135 | def _do_set_label(self, text, important): 136 | self.label.node().set_text(text) 137 | 138 | if important is not self.__label_effective_important: 139 | self.__label_effective_important = important 140 | if important or self.highlight_mode is not None: 141 | self.label.show() 142 | else: 143 | self.label.hide() 144 | 145 | if important: 146 | self.label_bob.loop() 147 | self.label.node().set_card_color(constants.important_label_color) 148 | self.arrow.set_color(constants.important_label_color) 149 | else: 150 | self.label_bob.finish() 151 | self.label.node().set_card_color(constants.normal_label_color) 152 | self.arrow.set_color(constants.normal_label_color) 153 | 154 | @property 155 | def highlighted(self): 156 | return self.highlight_mode is not None 157 | 158 | def highlight(self, mode): 159 | if self.highlight_mode == mode: 160 | return 161 | 162 | self.label.show() 163 | self.highlight_mode = mode 164 | self.root.set_color_scale((2, 2, 2, 1)) 165 | 166 | if mode == 'connect': 167 | effective_text = 'Click to connect\nthis {}'.format(self.name) 168 | effective_important = False 169 | elif mode == 'erase': 170 | if self.erasable: 171 | effective_text = 'Click to erase\nthis {}'.format(self.name) 172 | effective_important = False 173 | else: 174 | effective_text = "Only pylons can\nbe erased!" 175 | effective_important = True 176 | elif mode == 'placing': 177 | effective_text = 'Click to place a\npylon here' 178 | effective_important = False 179 | elif mode == 'upgrade' or mode == 'upgrade-no-money': 180 | if not self.upgradable: 181 | effective_text = "Only pylons can\nbe upgraded!" 182 | effective_important = True 183 | elif self.upgraded: 184 | effective_text = "Already\nupgraded!" 185 | effective_important = True 186 | elif mode == 'upgrade-no-money': 187 | effective_text = "You need more\nupgrade points!" 188 | effective_important = True 189 | else: 190 | effective_text = "Click to upgrade\nthis {}".format(self.name) 191 | effective_important = False 192 | elif mode == 'yay-upgraded': 193 | effective_text = "Upgraded\nsuccessfully!" 194 | effective_important = False 195 | elif mode == 'too-far': 196 | effective_text = "Too far! Build\npylons closer." 197 | effective_important = True 198 | elif mode == 'already-connected': 199 | effective_text = "Already\nconnected!" 200 | effective_important = True 201 | elif mode == 'bad-terrain': 202 | effective_text = "Cannot build\non bad terrain!" 203 | effective_important = True 204 | #elif mode == 'self-connect': 205 | # effective_text = "Cannot connect\nto itself!" 206 | # effective_important = True 207 | else: 208 | effective_text = self.__label_text 209 | effective_important = self.__label_important 210 | 211 | self._do_set_label(effective_text, important=effective_important) 212 | 213 | def unhighlight(self): 214 | self.highlight_mode = None 215 | if not self.__label_important: 216 | self.label.hide() 217 | else: 218 | self._do_set_label(self.__label_text, self.__label_important) 219 | self.root.clear_color_scale() 220 | 221 | def on_voltage_change(self, voltage): 222 | """Called with the voltage of the node if it's connected.""" 223 | 224 | if constants.show_debug_labels: 225 | self.debug_label.node().set_text("{:.1f} V".format(voltage)) 226 | 227 | def on_disconnected(self): 228 | """Called instead of on_voltage_change if it's not connected.""" 229 | 230 | if constants.show_debug_labels: 231 | self.debug_label.node().set_text("X") 232 | 233 | def on_update(self): 234 | """Updates state based on position information of neighbours.""" 235 | pass 236 | -------------------------------------------------------------------------------- /data/model/pole.egg: -------------------------------------------------------------------------------- 1 | { Z-up } 2 | Text { 3 | { 4 | { 5 | 1.0 0.0 0.0 0.0 6 | 0.0 -4.371138828673793e-08 1.0 0.0 7 | 0.0 -1.0 -4.371138828673793e-08 0.0 8 | 0.0 0.0 0.0 1.0 9 | } 10 | } 11 | 12 | Text { 13 | 14 | 0 {-0.283000 -0.020000 0.616219 15 | } 16 | 1 {0.287000 -0.020000 0.660219 17 | } 18 | 2 {-0.283000 -0.020000 0.660219 19 | } 20 | 3 {-0.283000 -0.020000 0.616219 21 | } 22 | 4 {0.287000 -0.020000 0.616219 23 | } 24 | 5 {0.287000 -0.020000 0.660219 25 | } 26 | 6 {-0.022500 -0.020000 0.616219 27 | } 28 | 7 {0.287000 -0.020000 0.616219 29 | } 30 | 8 {-0.283000 -0.020000 0.616219 31 | } 32 | 9 {-0.022500 -0.020000 -0.000000 33 | } 34 | 10 {0.026500 -0.020000 0.616219 35 | } 36 | 11 {-0.022500 -0.020000 0.616219 37 | } 38 | 12 {0.026500 -0.020000 0.616219 39 | } 40 | 13 {0.287000 -0.020000 0.616219 41 | } 42 | 14 {-0.022500 -0.020000 0.616219 43 | } 44 | 15 {-0.022500 -0.020000 -0.000000 45 | } 46 | 16 {0.026500 -0.020000 -0.000000 47 | } 48 | 17 {0.026500 -0.020000 0.616219 49 | } 50 | 18 {-0.283000 0.020000 0.616219 51 | } 52 | 19 {-0.283000 0.020000 0.660219 53 | } 54 | 20 {0.287000 0.020000 0.660219 55 | } 56 | 21 {-0.283000 0.020000 0.616219 57 | } 58 | 22 {0.287000 0.020000 0.660219 59 | } 60 | 23 {0.287000 0.020000 0.616219 61 | } 62 | 24 {-0.022500 0.020000 0.616219 63 | } 64 | 25 {-0.283000 0.020000 0.616219 65 | } 66 | 26 {0.287000 0.020000 0.616219 67 | } 68 | 27 {-0.022500 0.020000 0.000000 69 | } 70 | 28 {-0.022500 0.020000 0.616219 71 | } 72 | 29 {0.026500 0.020000 0.616219 73 | } 74 | 30 {0.026500 0.020000 0.616219 75 | } 76 | 31 {-0.022500 0.020000 0.616219 77 | } 78 | 32 {0.287000 0.020000 0.616219 79 | } 80 | 33 {-0.022500 0.020000 0.000000 81 | } 82 | 34 {0.026500 0.020000 0.616219 83 | } 84 | 35 {0.026500 0.020000 0.000000 85 | } 86 | 36 {-0.022500 -0.020000 0.616219 87 | } 88 | 37 {-0.022500 0.020000 0.616219 89 | } 90 | 38 {-0.022500 0.020000 0.000000 91 | } 92 | 39 {-0.022500 -0.020000 -0.000000 93 | } 94 | 40 {-0.283000 -0.020000 0.616219 95 | } 96 | 41 {-0.283000 0.020000 0.616219 97 | } 98 | 42 {-0.022500 0.020000 0.616219 99 | } 100 | 43 {-0.022500 -0.020000 0.616219 101 | } 102 | 44 {0.026500 -0.020000 -0.000000 103 | } 104 | 45 {0.026500 0.020000 0.000000 105 | } 106 | 46 {0.026500 0.020000 0.616219 107 | } 108 | 47 {0.026500 -0.020000 0.616219 109 | } 110 | 48 {0.287000 -0.020000 0.660219 111 | } 112 | 49 {0.287000 0.020000 0.660219 113 | } 114 | 50 {-0.283000 0.020000 0.660219 115 | } 116 | 51 {-0.283000 -0.020000 0.660219 117 | } 118 | 52 {0.026500 -0.020000 0.616219 119 | } 120 | 53 {0.026500 0.020000 0.616219 121 | } 122 | 54 {0.287000 0.020000 0.616219 123 | } 124 | 55 {0.287000 -0.020000 0.616219 125 | } 126 | 56 {-0.283000 -0.020000 0.660219 127 | } 128 | 57 {-0.283000 0.020000 0.660219 129 | } 130 | 58 {-0.283000 0.020000 0.616219 131 | } 132 | 59 {-0.283000 -0.020000 0.616219 133 | } 134 | 60 {-0.022500 -0.020000 -0.000000 135 | } 136 | 61 {-0.022500 0.020000 0.000000 137 | } 138 | 62 {0.026500 0.020000 0.000000 139 | } 140 | 63 {0.026500 -0.020000 -0.000000 141 | } 142 | 64 {0.287000 -0.020000 0.616219 143 | } 144 | 65 {0.287000 0.020000 0.616219 145 | } 146 | 66 {0.287000 0.020000 0.660219 147 | } 148 | 67 {0.287000 -0.020000 0.660219 149 | } 150 | 68 {-0.140500 -0.020000 0.980750 151 | } 152 | 69 {0.144500 -0.020000 1.024750 153 | } 154 | 70 {-0.140500 -0.020000 1.024750 155 | } 156 | 71 {-0.140500 -0.020000 0.980750 157 | } 158 | 72 {0.144500 -0.020000 0.980750 159 | } 160 | 73 {0.144500 -0.020000 1.024750 161 | } 162 | 74 {-0.022500 -0.020000 0.980750 163 | } 164 | 75 {0.144500 -0.020000 0.980750 165 | } 166 | 76 {-0.140500 -0.020000 0.980750 167 | } 168 | 77 {-0.022500 -0.020000 0.661094 169 | } 170 | 78 {0.026500 -0.020000 0.980750 171 | } 172 | 79 {-0.022500 -0.020000 0.980750 173 | } 174 | 80 {0.026500 -0.020000 0.980750 175 | } 176 | 81 {0.144500 -0.020000 0.980750 177 | } 178 | 82 {-0.022500 -0.020000 0.980750 179 | } 180 | 83 {-0.022500 -0.020000 0.661094 181 | } 182 | 84 {0.026500 -0.020000 0.661094 183 | } 184 | 85 {0.026500 -0.020000 0.980750 185 | } 186 | 86 {-0.140500 0.020000 0.980750 187 | } 188 | 87 {-0.140500 0.020000 1.024750 189 | } 190 | 88 {0.144500 0.020000 1.024750 191 | } 192 | 89 {-0.140500 0.020000 0.980750 193 | } 194 | 90 {0.144500 0.020000 1.024750 195 | } 196 | 91 {0.144500 0.020000 0.980750 197 | } 198 | 92 {-0.022500 0.020000 0.980750 199 | } 200 | 93 {-0.140500 0.020000 0.980750 201 | } 202 | 94 {0.144500 0.020000 0.980750 203 | } 204 | 95 {-0.022500 0.020000 0.661094 205 | } 206 | 96 {-0.022500 0.020000 0.980750 207 | } 208 | 97 {0.026500 0.020000 0.980750 209 | } 210 | 98 {0.026500 0.020000 0.980750 211 | } 212 | 99 {-0.022500 0.020000 0.980750 213 | } 214 | 100 {0.144500 0.020000 0.980750 215 | } 216 | 101 {-0.022500 0.020000 0.661094 217 | } 218 | 102 {0.026500 0.020000 0.980750 219 | } 220 | 103 {0.026500 0.020000 0.661094 221 | } 222 | 104 {-0.022500 -0.020000 0.980750 223 | } 224 | 105 {-0.022500 0.020000 0.980750 225 | } 226 | 106 {-0.022500 0.020000 0.661094 227 | } 228 | 107 {-0.022500 -0.020000 0.661094 229 | } 230 | 108 {-0.140500 -0.020000 0.980750 231 | } 232 | 109 {-0.140500 0.020000 0.980750 233 | } 234 | 110 {-0.022500 0.020000 0.980750 235 | } 236 | 111 {-0.022500 -0.020000 0.980750 237 | } 238 | 112 {0.026500 -0.020000 0.661094 239 | } 240 | 113 {0.026500 0.020000 0.661094 241 | } 242 | 114 {0.026500 0.020000 0.980750 243 | } 244 | 115 {0.026500 -0.020000 0.980750 245 | } 246 | 116 {0.144500 -0.020000 1.024750 247 | } 248 | 117 {0.144500 0.020000 1.024750 249 | } 250 | 118 {-0.140500 0.020000 1.024750 251 | } 252 | 119 {-0.140500 -0.020000 1.024750 253 | } 254 | 120 {0.026500 -0.020000 0.980750 255 | } 256 | 121 {0.026500 0.020000 0.980750 257 | } 258 | 122 {0.144500 0.020000 0.980750 259 | } 260 | 123 {0.144500 -0.020000 0.980750 261 | } 262 | 124 {-0.140500 -0.020000 1.024750 263 | } 264 | 125 {-0.140500 0.020000 1.024750 265 | } 266 | 126 {-0.140500 0.020000 0.980750 267 | } 268 | 127 {-0.140500 -0.020000 0.980750 269 | } 270 | 128 {-0.022500 -0.020000 0.661094 271 | } 272 | 129 {-0.022500 0.020000 0.661094 273 | } 274 | 130 {0.026500 0.020000 0.661094 275 | } 276 | 131 {0.026500 -0.020000 0.661094 277 | } 278 | 132 {0.144500 -0.020000 0.980750 279 | } 280 | 133 {0.144500 0.020000 0.980750 281 | } 282 | 134 {0.144500 0.020000 1.024750 283 | } 284 | 135 {0.144500 -0.020000 1.024750 285 | }} 286 | 287 | 288 | { 289 | {0.000000 -1.000000 -0.000000} 290 | { 0 1 2 { Text }} 291 | } 292 | { 293 | {0.000000 -1.000000 -0.000000} 294 | { 3 4 5 { Text }} 295 | } 296 | { 297 | {0.000000 0.000000 0.000000} 298 | { 6 7 8 { Text }} 299 | } 300 | { 301 | {0.000000 -1.000000 -0.000000} 302 | { 9 10 11 { Text }} 303 | } 304 | { 305 | {0.000000 0.000000 0.000000} 306 | { 12 13 14 { Text }} 307 | } 308 | { 309 | {0.000000 -1.000000 -0.000000} 310 | { 15 16 17 { Text }} 311 | } 312 | { 313 | {0.000000 1.000000 0.000000} 314 | { 18 19 20 { Text }} 315 | } 316 | { 317 | {0.000000 1.000000 0.000000} 318 | { 21 22 23 { Text }} 319 | } 320 | { 321 | {0.000000 0.000000 0.000000} 322 | { 24 25 26 { Text }} 323 | } 324 | { 325 | {0.000000 1.000000 0.000000} 326 | { 27 28 29 { Text }} 327 | } 328 | { 329 | {0.000000 0.000000 0.000000} 330 | { 30 31 32 { Text }} 331 | } 332 | { 333 | {0.000000 1.000000 0.000000} 334 | { 33 34 35 { Text }} 335 | } 336 | { 337 | {-1.000000 0.000000 0.000000} 338 | { 36 37 38 39 { Text }} 339 | } 340 | { 341 | {0.000000 0.000000 -1.000000} 342 | { 40 41 42 43 { Text }} 343 | } 344 | { 345 | {1.000000 0.000000 0.000000} 346 | { 44 45 46 47 { Text }} 347 | } 348 | { 349 | {0.000000 -0.000000 1.000000} 350 | { 48 49 50 51 { Text }} 351 | } 352 | { 353 | {0.000000 0.000000 -1.000000} 354 | { 52 53 54 55 { Text }} 355 | } 356 | { 357 | {-1.000000 0.000000 0.000000} 358 | { 56 57 58 59 { Text }} 359 | } 360 | { 361 | {0.000000 0.000000 -1.000000} 362 | { 60 61 62 63 { Text }} 363 | } 364 | { 365 | {1.000000 0.000000 0.000000} 366 | { 64 65 66 67 { Text }} 367 | } 368 | { 369 | {0.000000 -1.000000 -0.000000} 370 | { 68 69 70 { Text }} 371 | } 372 | { 373 | {0.000000 -1.000000 -0.000000} 374 | { 71 72 73 { Text }} 375 | } 376 | { 377 | {0.000000 0.000000 0.000000} 378 | { 74 75 76 { Text }} 379 | } 380 | { 381 | {0.000000 -1.000000 -0.000000} 382 | { 77 78 79 { Text }} 383 | } 384 | { 385 | {0.000000 0.000000 0.000000} 386 | { 80 81 82 { Text }} 387 | } 388 | { 389 | {0.000000 -1.000000 -0.000000} 390 | { 83 84 85 { Text }} 391 | } 392 | { 393 | {0.000000 1.000000 0.000000} 394 | { 86 87 88 { Text }} 395 | } 396 | { 397 | {0.000000 1.000000 0.000000} 398 | { 89 90 91 { Text }} 399 | } 400 | { 401 | {0.000000 0.000000 0.000000} 402 | { 92 93 94 { Text }} 403 | } 404 | { 405 | {0.000000 1.000000 0.000000} 406 | { 95 96 97 { Text }} 407 | } 408 | { 409 | {0.000000 0.000000 0.000000} 410 | { 98 99 100 { Text }} 411 | } 412 | { 413 | {0.000000 1.000000 0.000000} 414 | { 101 102 103 { Text }} 415 | } 416 | { 417 | {-1.000000 0.000000 0.000000} 418 | { 104 105 106 107 { Text }} 419 | } 420 | { 421 | {0.000000 0.000000 -1.000000} 422 | { 108 109 110 111 { Text }} 423 | } 424 | { 425 | {1.000000 0.000000 0.000000} 426 | { 112 113 114 115 { Text }} 427 | } 428 | { 429 | {0.000000 -0.000000 1.000000} 430 | { 116 117 118 119 { Text }} 431 | } 432 | { 433 | {0.000000 0.000000 -1.000000} 434 | { 120 121 122 123 { Text }} 435 | } 436 | { 437 | {-1.000000 0.000000 0.000000} 438 | { 124 125 126 127 { Text }} 439 | } 440 | { 441 | {0.000000 0.000000 -1.000000} 442 | { 128 129 130 131 { Text }} 443 | } 444 | { 445 | {1.000000 0.000000 0.000000} 446 | { 132 133 134 135 { Text }} 447 | } 448 | } 449 | -------------------------------------------------------------------------------- /gamelib/world.py: -------------------------------------------------------------------------------- 1 | from panda3d import core 2 | 3 | from . import constructs, constants 4 | 5 | import math 6 | import numpy 7 | import random 8 | 9 | 10 | class World(object): 11 | beginner_town_spots = [(2, 3), (3, 6), (1, 5), (5, 3), (3, 2)] 12 | 13 | def __init__(self, audio3d): 14 | self.root = core.NodePath("world") 15 | self.audio3d = audio3d 16 | 17 | cm = core.CardMaker("card") 18 | cm.set_frame(-50, 50, -50, 50) 19 | self.plane_model = self.root.attachNewNode(cm.generate()) 20 | self.plane_model.look_at(0, 0, -1) 21 | self.plane_model.set_bin('background', 0) 22 | self.plane_model.set_attrib(core.DepthTestAttrib.make(core.RenderAttrib.M_always)) 23 | self.plane_model.set_depth_write(True) 24 | 25 | mat = core.Material() 26 | #mat.diffuse = (218.0/255.0, 234.0/255.0, 182.0/255.0, 1) 27 | #mat.diffuse = (181.0/255.0, 214.0/255.0, 111.0/255.0, 1) 28 | mat.diffuse = (200.0/255.0, 239.0/255.0, 91.0/255.0, 1) 29 | mat.diffuse = mat.diffuse * 1.5 30 | #mat.diffuse = (2, 2, 2, 1) 31 | mat.ambient = (1, 1, 1, 1) 32 | self.plane_model.set_material(mat) 33 | 34 | self.plane = core.Plane(0, 0, 1, 0) 35 | 36 | self.sun = core.PointLight("sun") 37 | self.sun.color = (0.9, 1, 0.8, 1) 38 | self.sun.color = self.sun.color * 10000 39 | self.sun.attenuation = (1, 0, 1) 40 | self.sun_path = self.root.attach_new_node(self.sun) 41 | self.sun_path.set_pos(15, -8, 5) 42 | self.sun_path.set_pos(self.sun_path.get_pos() * 8) 43 | self.sun_path.reparent_to(self.root) 44 | self.root.set_light(self.sun_path) 45 | 46 | self.moon = core.PointLight("sun") 47 | self.moon.color = (243.0/255.0, 247.0/255.0, 173.0/255.0, 1) 48 | #self.moon.color = (1, 0.5, 0.5, 1) 49 | self.moon.color = self.moon.color * 10000 50 | self.moon.attenuation = (1, 0, 1) 51 | self.moon_path = self.root.attach_new_node(self.moon) 52 | self.moon_path.set_pos(-20, 10, 6) 53 | self.moon_path.set_pos(self.moon_path.get_pos() * 8) 54 | self.moon_path.reparent_to(self.root) 55 | self.root.set_light(self.moon_path) 56 | 57 | #self.sun = core.DirectionalLight("sun") 58 | #self.sun.direction = (1, -1, -0.5) 59 | #self.sun.color = (0.5, 1, 1, 1) 60 | ##self.sun.color = self.sun.color * 300 61 | #self.sun_path = self.root.attach_new_node(self.sun) 62 | #self.sun_path.set_pos(20, -10, 3) 63 | #self.sun_path.reparent_to(self.root) 64 | #self.root.set_light(self.sun_path) 65 | 66 | #self.moon = core.DirectionalLight("sun") 67 | #self.moon.direction = (-0.5, 1.5, -0.4) 68 | #self.moon.color = (1, 0.5, 0.5, 1) 69 | ##self.moon.color = self.moon.color * 300 70 | #self.moon_path = self.root.attach_new_node(self.moon) 71 | #self.moon_path.set_pos(-20, 10, 3) 72 | #self.moon_path.reparent_to(self.root) 73 | #self.root.set_light(self.moon_path) 74 | 75 | self.towns = [] 76 | self.pylons = set() 77 | 78 | # Grid prevents building towns at already occupied places. 79 | self.grid = numpy.zeros((8, 8), dtype=int) 80 | 81 | # Build one town at a fixed location. 82 | self.sprout_town(grid_pos=(5, 4)) 83 | 84 | # And two at an arbitrary, close, but not in-view spot. 85 | self.sprout_town(grid_pos=random.choice(self.beginner_town_spots), placed=False) 86 | 87 | # Determine coordinates for generator and claim it. 88 | x = 3 89 | y = 4 90 | self.grid[x][y] = 1 91 | 92 | # Oh, also spawn in some shrubberies, and litter them around the map. 93 | for i in range(4): 94 | self.sprout_shrubbery("trees.egg") 95 | for i in range(4): 96 | self.sprout_shrubbery("trees2.egg") 97 | for i in range(4): 98 | self.sprout_shrubbery("trees3.egg") 99 | for i in range(4): 100 | self.sprout_shrubbery("trees4.egg") 101 | 102 | # Build generator. Block off everything in the immediate vicinity. 103 | self.grid[x+1][y] = 1 104 | self.grid[x-1][y] = 1 105 | self.grid[x][y-1] = 1 106 | self.grid[x+1][y-1] = 1 107 | self.grid[x-1][y-1] = 1 108 | self.grid[x][y+1] = 1 109 | self.grid[x+1][y+1] = 1 110 | self.grid[x-1][y+1] = 1 111 | x -= self.grid.shape[0] / 2 112 | y -= self.grid.shape[1] / 2 113 | self.gen = constructs.Generator(self, (x * constants.grid_spacing, y * constants.grid_spacing), "Power Plant") 114 | self.gen.placed = True 115 | 116 | # And some impassable terrain. 117 | for i in range(3): 118 | self.sprout_obstacle("hill.egg") 119 | for i in range(3): 120 | self.sprout_obstacle("hill2.egg") 121 | 122 | # Draw grid? 123 | drawer = core.LineSegs() 124 | #drawer.set_color((0.05, 0.05, 0.05, 1)) 125 | drawer.set_thickness(2) 126 | 127 | min_x = self.grid.shape[0] * -3 128 | max_x = self.grid.shape[0] * 3 129 | min_y = self.grid.shape[1] * -3 130 | max_y = self.grid.shape[1] * 3 131 | 132 | for x in range(min_x, max_x, 3): 133 | drawer.move_to((x + 3, min_y, 0.001)) 134 | drawer.draw_to((x + 3, max_y, 0.001)) 135 | 136 | for y in range(min_y, max_y, 3): 137 | drawer.move_to((min_x, y + 3, 0.001)) 138 | drawer.draw_to((max_x, y + 3, 0.001)) 139 | 140 | debug_grid = self.root.attach_new_node(drawer.create(False)) 141 | debug_grid.set_light_off(1) 142 | #debug_grid.set_color_scale((0.35, 0.35, 0.35, 1)) 143 | debug_grid.set_color_scale((192.0/800.0, 239.0/800.0, 91.0/800.0, 1)) 144 | debug_grid.show() 145 | debug_grid.set_depth_write(False) 146 | debug_grid.set_bin('background', 10) 147 | 148 | self.snap_sound = self.audio3d.load_sfx('snap.ogg') 149 | self.snap_sound.set_volume(64) 150 | 151 | def construct_pylon(self): 152 | """Call this to construct additional pylons.""" 153 | 154 | pylon = constructs.Pylon(self, (0, 0), "Pylon") 155 | self.pylons.add(pylon) 156 | return pylon 157 | 158 | def find_free_grid_spot(self): 159 | x = random.randint(0, self.grid.shape[0] - 1) 160 | y = random.randint(0, self.grid.shape[1] - 1) 161 | while self.grid[x][y] != 0: 162 | x = random.randint(0, self.grid.shape[0] - 1) 163 | y = random.randint(0, self.grid.shape[1] - 1) 164 | 165 | return x, y 166 | 167 | def sprout_town(self, grid_pos=None, placed=True): 168 | if grid_pos is not None: 169 | x, y = grid_pos 170 | else: 171 | x, y = self.find_free_grid_spot() 172 | 173 | self.grid[x][y] = 1 174 | 175 | x -= self.grid.shape[0] / 2 176 | y -= self.grid.shape[1] / 2 177 | 178 | town = constructs.Town(self, (x * constants.grid_spacing, y * constants.grid_spacing), "City", placed=placed) 179 | self.towns.append(town) 180 | 181 | def sprout_shrubbery(self, model): 182 | x, y = self.find_free_grid_spot() 183 | self.grid[x][y] = 1 184 | 185 | x -= self.grid.shape[0] / 2 186 | y -= self.grid.shape[1] / 2 187 | 188 | trees = loader.load_model(model) 189 | trees.reparent_to(self.root) 190 | trees.set_pos((x + (random.random() - 0.5) * 0.75) * constants.grid_spacing, 191 | (y + (random.random() - 0.5) * 0.75) * constants.grid_spacing, 0) 192 | trees.set_h(random.random() * 360) 193 | trees.set_color((0.1, 0.2, 0.1, 1)) 194 | rock = trees.find("**/Icosphere") 195 | if rock: 196 | rock.set_color_off(1) 197 | 198 | def sprout_obstacle(self, model): 199 | x, y = self.find_free_grid_spot() 200 | self.grid[x][y] = 2 201 | 202 | x -= self.grid.shape[0] / 2 203 | y -= self.grid.shape[1] / 2 204 | 205 | obstacle = loader.load_model(model) 206 | obstacle.reparent_to(self.root) 207 | obstacle.set_pos((x + (random.random() - 0.5) * 0.25) * constants.grid_spacing, 208 | (y + (random.random() - 0.5) * 0.25) * constants.grid_spacing, 0) 209 | obstacle.set_h(random.random() * 360) 210 | obstacle.set_sz(random.random() + 0.5) 211 | 212 | if model == "hill.egg": 213 | obstacle.set_color((200.0/200.0, 239.0/200.0, 91.0/200.0, 1)) 214 | obstacle.set_sz(random.random() * 0.75 + 0.4) 215 | 216 | def add_town(self, pos, name): 217 | town = constructs.Town(self, pos, name, placed=True) 218 | self.towns.append(town) 219 | 220 | def is_buildable_terrain(self, x, y): 221 | """Returns false if the indicated grid cell is rough terrain.""" 222 | 223 | x /= constants.grid_spacing 224 | y /= constants.grid_spacing 225 | 226 | x += self.grid.shape[0] / 2 227 | y += self.grid.shape[1] / 2 228 | 229 | x = int(round(x)) 230 | y = int(round(y)) 231 | 232 | if x < 0 or y < 0 or x >= self.grid.shape[0] or y >= self.grid.shape[1]: 233 | # Out of bounds 234 | return False 235 | 236 | return self.grid[int(round(x))][int(round(y))] < 2 237 | 238 | def pick_closest_construct(self, x, y, max_radius=None): 239 | """Returns the Construct that falls within the given radius of the given position.""" 240 | 241 | closest = None 242 | closest_dist_sq = float("inf") 243 | if max_radius is not None: 244 | closest_dist_sq = max_radius ** 2 245 | 246 | for construct in self.towns + [self.gen] + list(self.pylons): 247 | if not construct.placed: 248 | continue 249 | 250 | dist_sq = (construct.x - x) ** 2 + (construct.y - y) ** 2 251 | if dist_sq < closest_dist_sq and dist_sq < (construct.selection_distance ** 2): 252 | closest = construct 253 | closest_dist_sq = dist_sq 254 | 255 | return closest 256 | 257 | def calc_power(self, start, dt): 258 | """Calculates the voltages at each node.""" 259 | 260 | # Gather all nodes connected 261 | nodes = self.find_nodes(start) 262 | 263 | # Other pylons are disconnected. 264 | for node in self.pylons - nodes: 265 | node.on_disconnected() 266 | 267 | # So are towns that can't be reached by the generator. 268 | for town in self.towns: 269 | if town not in nodes: 270 | town.on_disconnected() 271 | 272 | # Prune nodes with only one connection, unless they provide or consume 273 | # power. 274 | discarded = -1 275 | while discarded != 0: 276 | discarded = 0 277 | for node in tuple(nodes): 278 | if isinstance(node, constructs.Pylon): 279 | if len(set(node.neighbours) & nodes) < 2: 280 | nodes.discard(node) 281 | node.on_disconnected() 282 | discarded += 1 283 | 284 | if len(nodes) <= 1: 285 | for node in nodes: 286 | node.on_disconnected() 287 | return 288 | 289 | # Now create a linear system for Modified Nodal Analysis. 290 | nodes = tuple(nodes) 291 | matrix = [] 292 | ords = [] 293 | 294 | for i, node in enumerate(nodes): 295 | row = [0] * (len(nodes) + 1) 296 | 297 | for node2 in node.neighbours: 298 | if node2 in nodes: 299 | j = nodes.index(node2) 300 | conductance = 1 / node.connections[node2].resistance 301 | row[i] += conductance 302 | row[j] += -conductance 303 | 304 | if isinstance(node, constructs.Generator): 305 | # Generator current is an unknown. 306 | row[-1] = 1 307 | 308 | matrix.append(row) 309 | 310 | if isinstance(node, constructs.Town): 311 | # Town: consumes 3A. 312 | ords.append(-node.current) 313 | else: 314 | ords.append(0) 315 | 316 | # Finally, one more equation: all the generators combined produce 317 | # enough current to satisfy all the towns. 318 | row = [0] * (len(nodes) + 1) 319 | row[-1] = 1 320 | ords.append(0) 321 | for i, node in enumerate(nodes): 322 | if isinstance(node, constructs.Town): 323 | if node.powered: 324 | row[i] = 1.0 / node.resistance 325 | else: 326 | row[i] = 0 327 | 328 | matrix.append(row) 329 | 330 | try: 331 | results = numpy.linalg.solve(matrix, ords) 332 | except: 333 | # Shouldn't happen, but better than nothing? 334 | results = numpy.linalg.lstsq(matrix, ords)[0] 335 | 336 | # Determine the current through each wire based on the voltages. 337 | hot_wires = [] 338 | for node, result in zip(nodes, results): 339 | for other, wire in list(node.connections.items()): 340 | if wire.placed and other in nodes: 341 | # Calc current from voltage differential and resistance. 342 | current = abs(result - results[nodes.index(other)]) / wire.resistance 343 | else: 344 | current = 0 345 | 346 | wire.on_current_change(current, dt) 347 | if wire.overheated and dt >= 0.0: 348 | hot_wires.append(wire) 349 | 350 | node.on_voltage_change(result) 351 | 352 | # Remove the hottest wire. 353 | if hot_wires: 354 | hot_wires.sort(key=lambda wire:-wire.heat) 355 | print("Removing overheated wire {}".format(hot_wires[0])) 356 | if hot_wires[0].origin: 357 | pos = hot_wires[0].origin.root.get_pos(self.root) 358 | self.snap_sound.set_3d_attributes(pos[0], pos[1], pos[2], 0, 0, 0) 359 | self.snap_sound.play() 360 | hot_wires[0].destroy() 361 | 362 | def find_nodes(self, start, visited=frozenset()): 363 | nodes = set(visited) 364 | nodes.add(start) 365 | 366 | for node in start.neighbours: 367 | if node not in visited: 368 | nodes |= self.find_nodes(node, nodes) 369 | 370 | return nodes 371 | 372 | def step(self, dt): 373 | """Runs one iteration of the game logic.""" 374 | 375 | self.calc_power(self.gen, dt) 376 | 377 | if dt != 0.0: 378 | for town in self.towns: 379 | town.grow(dt) 380 | -------------------------------------------------------------------------------- /data/model/hill.egg: -------------------------------------------------------------------------------- 1 | { Z-up } 2 | Plane { 3 | { 4 | { 5 | 1.0 0.0 0.0 0.0 6 | 0.0 1.0 0.0 0.0 7 | 0.0 0.0 1.0 0.0 8 | 0.0 0.0 0.0 1.0 9 | } 10 | } 11 | 12 | Plane { 13 | 14 | 0 {1.391709 1.412335 0.194013 15 | } 16 | 1 {2.155047 1.483955 -0.022505 17 | } 18 | 2 {2.019340 2.185903 -0.019656 19 | } 20 | 3 {1.464781 2.086703 -0.020823 21 | } 22 | 4 {-2.316645 1.506912 -0.017402 23 | } 24 | 5 {-1.660460 1.375731 0.161150 25 | } 26 | 6 {-1.603670 2.070899 -0.022749 27 | } 28 | 7 {-2.153661 2.091265 -0.016127 29 | } 30 | 8 {-1.660460 1.375731 0.161150 31 | } 32 | 9 {-0.730211 1.479486 0.309961 33 | } 34 | 10 {-0.791869 1.932207 -0.025454 35 | } 36 | 11 {-1.603670 2.070899 -0.022749 37 | } 38 | 12 {-0.730211 1.479486 0.309961 39 | } 40 | 13 {-0.286098 1.487186 0.338747 41 | } 42 | 14 {-0.176052 2.151546 -0.025138 43 | } 44 | 15 {-0.791869 1.932207 -0.025454 45 | } 46 | 16 {-0.286098 1.487186 0.338747 47 | } 48 | 17 {0.231793 1.374324 0.732813 49 | } 50 | 18 {0.311691 2.199970 -0.027863 51 | } 52 | 19 {-0.176052 2.151546 -0.025138 53 | } 54 | 20 {0.231793 1.374324 0.732813 55 | } 56 | 21 {1.003466 1.696624 0.238322 57 | } 58 | 22 {0.924468 2.259688 -0.024414 59 | } 60 | 23 {0.311691 2.199970 -0.027863 61 | } 62 | 24 {1.003466 1.696624 0.238322 63 | } 64 | 25 {1.391709 1.412335 0.194013 65 | } 66 | 26 {1.464781 2.086703 -0.020823 67 | } 68 | 27 {0.924468 2.259688 -0.024414 69 | } 70 | 28 {-2.154864 -2.147076 -0.021839 71 | } 72 | 29 {-1.471919 -2.202706 -0.020284 73 | } 74 | 30 {-1.598161 -1.626649 0.052258 75 | } 76 | 31 {-2.022494 -1.550230 -0.024734 77 | } 78 | 32 {-2.022494 -1.550230 -0.024734 79 | } 80 | 33 {-1.598161 -1.626649 0.052258 81 | } 82 | 34 {-1.536796 -0.928152 0.342539 83 | } 84 | 35 {-2.141758 -0.939079 -0.023648 85 | } 86 | 36 {-2.141758 -0.939079 -0.023648 87 | } 88 | 37 {-1.536796 -0.928152 0.342539 89 | } 90 | 38 {-1.488261 -0.255123 0.382948 91 | } 92 | 39 {-2.126594 -0.233772 -0.030764 93 | } 94 | 40 {-2.126594 -0.233772 -0.030764 95 | } 96 | 41 {-1.488261 -0.255123 0.382948 97 | } 98 | 42 {-1.328083 0.337506 0.546762 99 | } 100 | 43 {-2.174765 0.403694 -0.024535 101 | } 102 | 44 {-2.174765 0.403694 -0.024535 103 | } 104 | 45 {-1.328083 0.337506 0.546762 105 | } 106 | 46 {-1.563667 0.832211 0.239138 107 | } 108 | 47 {-2.068191 1.039307 -0.023843 109 | } 110 | 48 {-2.068191 1.039307 -0.023843 111 | } 112 | 49 {-1.563667 0.832211 0.239138 113 | } 114 | 50 {-1.660460 1.375731 0.161150 115 | } 116 | 51 {-2.316645 1.506912 -0.017402 117 | } 118 | 52 {-1.471919 -2.202706 -0.020284 119 | } 120 | 53 {-0.878930 -2.163845 -0.026678 121 | } 122 | 54 {-0.746284 -1.582906 0.243182 123 | } 124 | 55 {-1.598161 -1.626649 0.052258 125 | } 126 | 56 {-1.598161 -1.626649 0.052258 127 | } 128 | 57 {-0.746284 -1.582906 0.243182 129 | } 130 | 58 {-0.860551 -0.886291 1.213551 131 | } 132 | 59 {-1.536796 -0.928152 0.342539 133 | } 134 | 60 {-1.536796 -0.928152 0.342539 135 | } 136 | 61 {-0.860551 -0.886291 1.213551 137 | } 138 | 62 {-0.943495 -0.452940 1.327098 139 | } 140 | 63 {-1.488261 -0.255123 0.382948 141 | } 142 | 64 {-1.488261 -0.255123 0.382948 143 | } 144 | 65 {-0.943495 -0.452940 1.327098 145 | } 146 | 66 {-0.815471 0.289533 1.448888 147 | } 148 | 67 {-1.328083 0.337506 0.546762 149 | } 150 | 68 {-1.328083 0.337506 0.546762 151 | } 152 | 69 {-0.815471 0.289533 1.448888 153 | } 154 | 70 {-0.886218 0.625265 1.219979 155 | } 156 | 71 {-1.563667 0.832211 0.239138 157 | } 158 | 72 {-1.563667 0.832211 0.239138 159 | } 160 | 73 {-0.886218 0.625265 1.219979 161 | } 162 | 74 {-0.730211 1.479486 0.309961 163 | } 164 | 75 {-1.660460 1.375731 0.161150 165 | } 166 | 76 {-0.878930 -2.163845 -0.026678 167 | } 168 | 77 {-0.405328 -2.146477 -0.030803 169 | } 170 | 78 {-0.300208 -1.455417 0.813326 171 | } 172 | 79 {-0.746284 -1.582906 0.243182 173 | } 174 | 80 {-0.746284 -1.582906 0.243182 175 | } 176 | 81 {-0.300208 -1.455417 0.813326 177 | } 178 | 82 {-0.280577 -0.832571 1.728135 179 | } 180 | 83 {-0.860551 -0.886291 1.213551 181 | } 182 | 84 {-0.860551 -0.886291 1.213551 183 | } 184 | 85 {-0.280577 -0.832571 1.728135 185 | } 186 | 86 {-0.503358 -0.327913 1.856099 187 | } 188 | 87 {-0.943495 -0.452940 1.327098 189 | } 190 | 88 {-0.943495 -0.452940 1.327098 191 | } 192 | 89 {-0.503358 -0.327913 1.856099 193 | } 194 | 90 {-0.467363 0.228387 1.724293 195 | } 196 | 91 {-0.815471 0.289533 1.448888 197 | } 198 | 92 {-0.815471 0.289533 1.448888 199 | } 200 | 93 {-0.467363 0.228387 1.724293 201 | } 202 | 94 {-0.471512 1.022149 1.175569 203 | } 204 | 95 {-0.886218 0.625265 1.219979 205 | } 206 | 96 {-0.886218 0.625265 1.219979 207 | } 208 | 97 {-0.471512 1.022149 1.175569 209 | } 210 | 98 {-0.286098 1.487186 0.338747 211 | } 212 | 99 {-0.730211 1.479486 0.309961 213 | } 214 | 100 {-0.405328 -2.146477 -0.030803 215 | } 216 | 101 {0.264802 -2.188245 -0.030204 217 | } 218 | 102 {0.029097 -1.514720 0.798713 219 | } 220 | 103 {-0.300208 -1.455417 0.813326 221 | } 222 | 104 {-0.300208 -1.455417 0.813326 223 | } 224 | 105 {0.029097 -1.514720 0.798713 225 | } 226 | 106 {0.298939 -0.973506 1.679751 227 | } 228 | 107 {-0.280577 -0.832571 1.728135 229 | } 230 | 108 {-0.280577 -0.832571 1.728135 231 | } 232 | 109 {0.298939 -0.973506 1.679751 233 | } 234 | 110 {0.042439 -0.200210 2.116070 235 | } 236 | 111 {-0.503358 -0.327913 1.856099 237 | } 238 | 112 {-0.503358 -0.327913 1.856099 239 | } 240 | 113 {0.042439 -0.200210 2.116070 241 | } 242 | 114 {0.228538 0.324206 2.143061 243 | } 244 | 115 {-0.467363 0.228387 1.724293 245 | } 246 | 116 {-0.467363 0.228387 1.724293 247 | } 248 | 117 {0.228538 0.324206 2.143061 249 | } 250 | 118 {-0.101862 0.787481 1.304631 251 | } 252 | 119 {-0.471512 1.022149 1.175569 253 | } 254 | 120 {-0.471512 1.022149 1.175569 255 | } 256 | 121 {-0.101862 0.787481 1.304631 257 | } 258 | 122 {0.231793 1.374324 0.732813 259 | } 260 | 123 {-0.286098 1.487186 0.338747 261 | } 262 | 124 {0.264802 -2.188245 -0.030204 263 | } 264 | 125 {0.812522 -2.107994 -0.028010 265 | } 266 | 126 {0.861201 -1.509964 0.532615 267 | } 268 | 127 {0.029097 -1.514720 0.798713 269 | } 270 | 128 {0.029097 -1.514720 0.798713 271 | } 272 | 129 {0.861201 -1.509964 0.532615 273 | } 274 | 130 {0.873175 -0.829182 1.268672 275 | } 276 | 131 {0.298939 -0.973506 1.679751 277 | } 278 | 132 {0.298939 -0.973506 1.679751 279 | } 280 | 133 {0.873175 -0.829182 1.268672 281 | } 282 | 134 {0.747498 -0.252077 1.706458 283 | } 284 | 135 {0.042439 -0.200210 2.116070 285 | } 286 | 136 {0.042439 -0.200210 2.116070 287 | } 288 | 137 {0.747498 -0.252077 1.706458 289 | } 290 | 138 {0.883415 0.101863 1.638591 291 | } 292 | 139 {0.228538 0.324206 2.143061 293 | } 294 | 140 {0.228538 0.324206 2.143061 295 | } 296 | 141 {0.883415 0.101863 1.638591 297 | } 298 | 142 {0.637316 0.853094 0.815078 299 | } 300 | 143 {-0.101862 0.787481 1.304631 301 | } 302 | 144 {-0.101862 0.787481 1.304631 303 | } 304 | 145 {0.637316 0.853094 0.815078 305 | } 306 | 146 {1.003466 1.696624 0.238322 307 | } 308 | 147 {0.231793 1.374324 0.732813 309 | } 310 | 148 {0.812522 -2.107994 -0.028010 311 | } 312 | 149 {1.669282 -2.166056 -0.021519 313 | } 314 | 150 {1.737859 -1.427450 0.076011 315 | } 316 | 151 {0.861201 -1.509964 0.532615 317 | } 318 | 152 {0.861201 -1.509964 0.532615 319 | } 320 | 153 {1.737859 -1.427450 0.076011 321 | } 322 | 154 {1.626921 -0.971737 0.286161 323 | } 324 | 155 {0.873175 -0.829182 1.268672 325 | } 326 | 156 {0.873175 -0.829182 1.268672 327 | } 328 | 157 {1.626921 -0.971737 0.286161 329 | } 330 | 158 {1.610281 -0.347159 0.243257 331 | } 332 | 159 {0.747498 -0.252077 1.706458 333 | } 334 | 160 {0.747498 -0.252077 1.706458 335 | } 336 | 161 {1.610281 -0.347159 0.243257 337 | } 338 | 162 {1.507631 0.324825 0.334954 339 | } 340 | 163 {0.883415 0.101863 1.638591 341 | } 342 | 164 {0.883415 0.101863 1.638591 343 | } 344 | 165 {1.507631 0.324825 0.334954 345 | } 346 | 166 {1.332910 0.810016 0.522006 347 | } 348 | 167 {0.637316 0.853094 0.815078 349 | } 350 | 168 {0.637316 0.853094 0.815078 351 | } 352 | 169 {1.332910 0.810016 0.522006 353 | } 354 | 170 {1.391709 1.412335 0.194013 355 | } 356 | 171 {1.003466 1.696624 0.238322 357 | } 358 | 172 {1.669282 -2.166056 -0.021519 359 | } 360 | 173 {2.326359 -2.150046 -0.020918 361 | } 362 | 174 {2.119699 -1.516413 -0.024266 363 | } 364 | 175 {1.737859 -1.427450 0.076011 365 | } 366 | 176 {1.737859 -1.427450 0.076011 367 | } 368 | 177 {2.119699 -1.516413 -0.024266 369 | } 370 | 178 {2.315913 -0.763550 -0.028397 371 | } 372 | 179 {1.626921 -0.971737 0.286161 373 | } 374 | 180 {1.626921 -0.971737 0.286161 375 | } 376 | 181 {2.315913 -0.763550 -0.028397 377 | } 378 | 182 {2.110846 -0.303050 -0.033498 379 | } 380 | 183 {1.610281 -0.347159 0.243257 381 | } 382 | 184 {1.610281 -0.347159 0.243257 383 | } 384 | 185 {2.110846 -0.303050 -0.033498 385 | } 386 | 186 {2.132204 0.162006 -0.030189 387 | } 388 | 187 {1.507631 0.324825 0.334954 389 | } 390 | 188 {1.507631 0.324825 0.334954 391 | } 392 | 189 {2.132204 0.162006 -0.030189 393 | } 394 | 190 {2.200674 0.938885 -0.025546 395 | } 396 | 191 {1.332910 0.810016 0.522006 397 | } 398 | 192 {1.332910 0.810016 0.522006 399 | } 400 | 193 {2.200674 0.938885 -0.025546 401 | } 402 | 194 {2.155047 1.483955 -0.022505 403 | } 404 | 195 {1.391709 1.412335 0.194013 405 | }} 406 | 407 | 408 | { 409 | {0.139423 0.156938 0.977718} 410 | { 0 1 2 3 { Plane }} 411 | } 412 | { 413 | {-0.119512 0.160372 0.979795} 414 | { 4 5 6 7 { Plane }} 415 | } 416 | { 417 | {-0.068003 0.410994 0.909098} 418 | { 8 9 10 11 { Plane }} 419 | } 420 | { 421 | {-0.136484 0.529888 0.837013} 422 | { 12 13 14 15 { Plane }} 423 | } 424 | { 425 | {-0.255466 0.602965 0.755758} 426 | { 16 17 18 19 { Plane }} 427 | } 428 | { 429 | {0.120957 0.588850 0.799140} 430 | { 20 21 22 23 { Plane }} 431 | } 432 | { 433 | {0.213608 0.352634 0.911055} 434 | { 24 25 26 27 { Plane }} 435 | } 436 | { 437 | {-0.077601 -0.058693 0.995255} 438 | { 28 29 30 31 { Plane }} 439 | } 440 | { 441 | {-0.397694 -0.215973 0.891737} 442 | { 32 33 34 35 { Plane }} 443 | } 444 | { 445 | {-0.531361 0.004094 0.847136} 446 | { 36 37 38 39 { Plane }} 447 | } 448 | { 449 | {-0.554241 -0.064251 0.829873} 450 | { 40 41 42 43 { Plane }} 451 | } 452 | { 453 | {-0.491241 0.175597 0.853140} 454 | { 44 45 46 47 { Plane }} 455 | } 456 | { 457 | {-0.370331 -0.060861 0.926904} 458 | { 48 49 50 51 { Plane }} 459 | } 460 | { 461 | {-0.105696 -0.281648 0.953679} 462 | { 52 53 54 55 { Plane }} 463 | } 464 | { 465 | {-0.426309 -0.615317 0.663058} 466 | { 56 57 58 59 { Plane }} 467 | } 468 | { 469 | {-0.829442 -0.102214 0.549161} 470 | { 60 61 62 63 { Plane }} 471 | } 472 | { 473 | {-0.860593 0.078114 0.503268} 474 | { 64 65 66 67 { Plane }} 475 | } 476 | { 477 | {-0.842527 0.036427 0.537421} 478 | { 68 69 70 71 { Plane }} 479 | } 480 | { 481 | {-0.467100 0.523486 0.712587} 482 | { 72 73 74 75 { Plane }} 483 | } 484 | { 485 | {-0.361096 -0.575273 0.733942} 486 | { 76 77 78 79 { Plane }} 487 | } 488 | { 489 | {-0.405635 -0.758279 0.510366} 490 | { 80 81 82 83 { Plane }} 491 | } 492 | { 493 | {-0.628236 -0.379616 0.679126} 494 | { 84 85 86 87 { Plane }} 495 | } 496 | { 497 | {-0.714758 0.095609 0.692805} 498 | { 88 89 90 91 { Plane }} 499 | } 500 | { 501 | {-0.442678 0.488387 0.752007} 502 | { 92 93 94 95 { Plane }} 503 | } 504 | { 505 | {-0.356933 0.777656 0.517543} 506 | { 96 97 98 99 { Plane }} 507 | } 508 | { 509 | {-0.069650 -0.775700 0.627247} 510 | { 100 101 102 103 { Plane }} 511 | } 512 | { 513 | {-0.142232 -0.819983 0.554435} 514 | { 104 105 106 107 { Plane }} 515 | } 516 | { 517 | {-0.170069 -0.450720 0.876315} 518 | { 108 109 110 111 { Plane }} 519 | } 520 | { 521 | {-0.496764 0.184342 0.848082} 522 | { 112 113 114 115 { Plane }} 523 | } 524 | { 525 | {-0.261638 0.682956 0.681995} 526 | { 116 117 118 119 { Plane }} 527 | } 528 | { 529 | {-0.032181 0.806488 0.590374} 530 | { 120 121 122 123 { Plane }} 531 | } 532 | { 533 | {0.173605 -0.714783 0.677456} 534 | { 124 125 126 127 { Plane }} 535 | } 536 | { 537 | {0.337427 -0.778383 0.529399} 538 | { 128 129 130 131 { Plane }} 539 | } 540 | { 541 | {0.523004 -0.353889 0.775390} 542 | { 132 133 134 135 { Plane }} 543 | } 544 | { 545 | {0.529332 -0.155244 0.834090} 546 | { 136 137 138 139 { Plane }} 547 | } 548 | { 549 | {0.405912 0.799227 0.443251} 550 | { 140 141 142 143 { Plane }} 551 | } 552 | { 553 | {0.406824 0.442635 0.799105} 554 | { 144 145 146 147 { Plane }} 555 | } 556 | { 557 | {0.230836 -0.446042 0.864732} 558 | { 148 149 150 151 { Plane }} 559 | } 560 | { 561 | {0.562951 -0.499316 0.658611} 562 | { 152 153 154 155 { Plane }} 563 | } 564 | { 565 | {0.827468 -0.084421 0.555130} 566 | { 156 157 158 159 { Plane }} 567 | } 568 | { 569 | {0.880920 -0.039520 0.471612} 570 | { 160 161 162 163 { Plane }} 571 | } 572 | { 573 | {0.631950 0.513771 0.580240} 574 | { 164 165 166 167 { Plane }} 575 | } 576 | { 577 | {0.381339 0.407237 0.829902} 578 | { 168 169 170 171 { Plane }} 579 | } 580 | { 581 | {0.091227 -0.059048 0.994078} 582 | { 172 173 174 175 { Plane }} 583 | } 584 | { 585 | {0.372739 -0.181427 0.910027} 586 | { 176 177 178 179 { Plane }} 587 | } 588 | { 589 | {0.420112 0.125599 0.898738} 590 | { 180 181 182 183 { Plane }} 591 | } 592 | { 593 | {0.492201 -0.037476 0.869674} 594 | { 184 185 186 187 { Plane }} 595 | } 596 | { 597 | {0.518414 -0.085589 0.850836} 598 | { 188 189 190 191 { Plane }} 599 | } 600 | { 601 | {0.385938 0.247277 0.888767} 602 | { 192 193 194 195 { Plane }} 603 | } 604 | } 605 | -------------------------------------------------------------------------------- /gamelib/game.py: -------------------------------------------------------------------------------- 1 | from direct.showbase.ShowBase import ShowBase 2 | from direct.showbase.Audio3DManager import Audio3DManager 3 | from direct.gui.DirectButton import DirectButton 4 | from direct.gui.OnscreenText import OnscreenText 5 | from panda3d import core 6 | 7 | from .world import World 8 | from .panel import Panel 9 | from .dialog import Dialog 10 | from . import constants 11 | 12 | import math 13 | import random 14 | import sys 15 | import os 16 | 17 | 18 | months = ["January", "February", "March", "April", "May", "June", "July", 19 | "August", "September", "October", "November", "December"] 20 | 21 | 22 | class Game(ShowBase): 23 | def __init__(self): 24 | main_dir = core.ExecutionEnvironment.get_environment_variable("MAIN_DIR") 25 | main_dir = core.Filename.from_os_specific(main_dir) 26 | core.load_prc_file(core.Filename(main_dir, "config.prc")) 27 | 28 | ShowBase.__init__(self) 29 | 30 | try: 31 | bold_font = loader.load_font("data/font/Roboto-Bold.ttf") 32 | except: 33 | print("Could not load Roboto-Bold.ttf") 34 | bold_font = None 35 | 36 | icon_font = loader.load_font("data/font/font-awesome5.otf") 37 | icon_font.pixels_per_unit = 128.0 38 | 39 | self.set_background_color((0.02, 0.01, 0.01, 1)) 40 | 41 | # Disable control modifiers, etc. 42 | buttons = core.ModifierButtons() 43 | buttons.add_button("shift") 44 | self.mouseWatcherNode.set_modifier_buttons(buttons) 45 | 46 | audio3d = Audio3DManager(self.sfxManagerList[0], self.camera) 47 | #audio3d.set_distance_factor(1.0) 48 | audio3d.set_drop_off_factor(3.0) 49 | 50 | self.world = World(audio3d) 51 | self.world.root.reparent_to(self.render) 52 | 53 | self.music = loader.load_music("Contemplation.ogg") 54 | if self.music is not None: 55 | self.music.set_loop(1) 56 | self.music.set_play_rate(1.0) 57 | self.target_play_rate = 1.0 58 | 59 | #self.world.root.set_shader_auto(True) 60 | self.world.root.set_antialias(core.AntialiasAttrib.M_auto) 61 | 62 | # Set up camera 63 | self.disable_mouse() 64 | self.pivot = self.world.root.attach_new_node("pivot") 65 | self.camera_target = self.pivot.attach_new_node("target") 66 | self.camera.reparent_to(self.camera_target) 67 | self.camera.set_pos(0, -15, 15) 68 | self.camera.look_at(0, 0, 0) 69 | 70 | self.lens = self.cam.node().get_lens(0) 71 | self.lens.focal_length = 0.4 72 | self.lens.set_fov(50) 73 | 74 | self.pivot.set_h(20) 75 | 76 | self.clock = core.ClockObject.get_global_clock() 77 | self.task_mgr.add(self.__game_task) 78 | self.task_mgr.add(self.__music_task) 79 | 80 | # Create UI 81 | self.panel = Panel(self.a2dBottomLeft, align='left', icon_font=icon_font) 82 | self.panel.add_button("1. Connect", icon=0xf5ee, callback=self.on_switch_mode, arg='connect', shortcut='1') 83 | self.panel.add_button("2. Upgrade", icon=0xf102, callback=self.on_switch_mode, arg='upgrade', shortcut='2') 84 | self.panel.add_button("3. Erase", icon=0xf12d, callback=self.on_switch_mode, arg='erase', shortcut='3') 85 | 86 | self.panel2 = Panel(self.a2dBottomRight, align='right', icon_font=icon_font) 87 | self.panel2.add_button("Pause", icon=0xf04c, callback=self.on_change_speed, arg=0) 88 | self.panel2.add_button("1x Speed", icon=0xf04b, callback=self.on_change_speed, arg=1) 89 | self.panel2.add_button("3x Speed", icon=0xf04e, callback=self.on_change_speed, arg=3) 90 | self.panel2.add_button("Quit", icon=0xf011, callback=self.on_quit, arg=None) 91 | self.game_speed = 0.0 92 | 93 | self.unpowered_button = DirectButton(parent=self.a2dTopLeft, pos=(0.13, 0, -0.15), text=u'\uf071', text_font=self.panel.icon_font, text_scale=0.1, text_fg=constants.important_label_color, relief=None, command=self.cycle_unpowered_town) 94 | self.unpowered_button.hide() 95 | self.unpowered_text = OnscreenText(parent=self.unpowered_button, pos=(0, -0.05), font=bold_font, text='Press tab', fg=constants.important_label_color, scale=0.04) 96 | self.next_unpowered_index = 0 97 | 98 | self.time_text = OnscreenText(parent=self.a2dBottomCenter, pos=(-0.1, 0.15), text='January, year 1', fg=(1, 1, 1, 1), scale=0.08) 99 | self.time_text.hide() 100 | self.month = 0.0 101 | self.year = 0 102 | 103 | self.power_text = OnscreenText(parent=self.a2dBottomCenter, pos=(-0.1, 0.24), text='', fg=(1, 1, 1, 1), scale=0.05) 104 | self.energy_text = OnscreenText(parent=self.a2dBottomCenter, pos=(-0.1, 0.07), text='', fg=(1, 1, 1, 1), scale=0.05) 105 | self.energy = 0.0 106 | self.total_energy = 0.0 107 | self.power = 0.0 108 | self.energy_target = 9000.0 109 | 110 | self.upgrade_text = OnscreenText(parent=self.a2dTopRight, align=core.TextNode.A_right, pos=(-0.21, -0.15), text='0', fg=(1, 1, 1, 1), scale=0.08) 111 | self.upgrade_icon = OnscreenText(parent=self.a2dTopRight, text=u'\uf35b', fg=constants.normal_label_color, pos=(-0.12, -0.16), font=icon_font, scale=0.1) 112 | self.upgrade_text.hide() 113 | self.upgrade_icon.hide() 114 | self.upgrade_counter = 0.0 115 | self.upgrades = 0 116 | 117 | self.dialog = Dialog(parent=self.aspect2d, icon_font=icon_font) 118 | 119 | self.mode = 'connect' 120 | 121 | self.accept('mouse1', self.on_click) 122 | self.accept('mouse3', self.cancel_placement) 123 | self.accept('shift-s', self.screenshot) 124 | self.accept('escape', self.cancel_placement) 125 | self.accept('shift-h', self.highlight_all) 126 | self.accept('shift-l', self.render.ls) 127 | self.accept('shift-p', self.create_stats) 128 | self.accept('shift-t', self.spawn_town) 129 | self.accept('shift-f', self.on_change_speed, [10.0]) 130 | self.accept('tab', self.cycle_unpowered_town) 131 | self.accept('wheel_up', self.on_zoom, [-1.0]) 132 | self.accept('wheel_down', self.on_zoom, [1.0]) 133 | self.accept('space', self.on_toggle_pause) 134 | self.accept('shift-q', sys.exit) 135 | self.accept('q', self.on_quit) 136 | 137 | self.highlighted = None 138 | self.pylon = None 139 | self.placing_wire = None 140 | self.tutorial_done = False 141 | 142 | # Initial mode 143 | self.panel.select_button(0) 144 | self.panel2.select_button(1) 145 | 146 | def tutorial_end(self): 147 | self.dialog.show(""" 148 | Nice! You seem to get the basics of the game. 149 | 150 | Keep growing your cities by providing them power. But be 151 | careful! If you overload your power cables, they will break, 152 | and the cities they are connected to will stop growing. 153 | 154 | Try to reach {:.0f} MJ before the year ends! 155 | 156 | NB. Use the arrow 157 | keys to move around, 158 | scroll wheel to zoom. 159 | """.format(self.energy_target / 10), button_text='Of course!', button_icon=0xf04b, callback=self.on_game_start) 160 | 161 | def on_game_start(self): 162 | for town in self.world.towns: 163 | town.placed = True 164 | self.tutorial_done = True 165 | self.game_speed = 1.0 166 | self.time_text.show() 167 | self.panel.show() 168 | self.panel2.show() 169 | self.cycle_unpowered_town() 170 | self.music.play() 171 | self.target_play_rate = 1.0 172 | self.task_mgr.add(self.__camera_task) 173 | 174 | def on_begin_month(self, month): 175 | print("Beginning month {}".format(month)) 176 | if month == 6: 177 | # Sprout third town. 178 | spots = list(self.world.beginner_town_spots) 179 | random.shuffle(spots) 180 | 181 | # If all spots are already occupied, find some other spot. 182 | spots.append(None) 183 | 184 | index = len(self.world.towns) 185 | for spot in spots: 186 | if spot is None or self.world.grid[spot[0]][spot[1]] == 0: 187 | self.world.sprout_town(grid_pos=spot) 188 | break 189 | 190 | self.cycle_unpowered_town(index) 191 | 192 | elif month == 12: 193 | # We don't actually check energy target here... guess we don't 194 | # want to lose the player on the first year. 195 | self.pause() 196 | self.energy_target *= constants.energy_target_multiplier 197 | 198 | if self.upgrades == 0: 199 | # Aw, here's an upgrade point. 200 | self.on_get_upgrade() 201 | 202 | text = """ 203 | Great! You may notice in the top-right corner that you are 204 | starting to obtain upgrade points. Use these to upgrade 205 | your pylons to increase the capacity of its wires. 206 | 207 | Can you supply {:.1f} more GJ by the end of the year? 208 | 209 | Another town has sprung up. Press tab to focus it. 210 | """.format(self.energy_target / 10000) 211 | self.dialog.show(text, button_text='Bring it on!', button_icon=0xf04b, callback=self.on_toggle_pause) 212 | 213 | self.world.sprout_town() 214 | 215 | elif month % 12 == 0 and month > 0: 216 | self.pause() 217 | 218 | if self.energy >= self.energy_target: 219 | self.next_unpowered_town = len(self.world.towns) 220 | self.world.sprout_town() 221 | 222 | self.energy_target *= constants.energy_target_multiplier 223 | callback = self.on_toggle_pause 224 | text = """ 225 | Well done! 226 | You supplied {:.1f} GJ last year and made it to year {}! 227 | 228 | Can you supply {:.1f} more GJ by the end of the year? 229 | 230 | Another town has sprung up. Press tab to focus it. 231 | """.format(self.energy / 10000, int(month // 12) + 1, self.energy_target / 10000) 232 | self.dialog.show(text, button_text='Bring it on!', button_icon=0xf04b, callback=self.on_toggle_pause) 233 | else: 234 | text = """ 235 | Unfortunately, you failed to satisfy the growing energy 236 | demands. You needed to produce {:.1f} GJ, but you 237 | produced only {:.1f} GJ. 238 | 239 | You produced a grand total of {:.1f} GJ. 240 | 241 | Better luck next time! 242 | """.format(self.energy_target / 10000, self.energy / 10000, self.total_energy / 10000) 243 | self.dialog.show(text, button_text='Quit', button_icon=0xf011, callback=sys.exit) 244 | 245 | self.energy = 0.0 246 | 247 | def on_get_upgrade(self): 248 | self.upgrade_counter = 0.0 249 | self.upgrades += 1 250 | 251 | self.upgrade_text['text'] = str(self.upgrades) 252 | self.upgrade_text.show() 253 | self.upgrade_icon.show() 254 | 255 | def on_use_upgrade(self): 256 | self.upgrades -= 1 257 | 258 | self.upgrade_text['text'] = str(self.upgrades) 259 | 260 | def __music_task(self, task): 261 | play_rate = self.music.get_play_rate() 262 | if self.target_play_rate != play_rate: 263 | diff = self.target_play_rate - play_rate 264 | if abs(diff) < 0.01: 265 | new_play_rate = self.target_play_rate 266 | elif diff > 0: 267 | diff = min(diff, self.clock.dt * constants.music_rate_change_speed) 268 | new_play_rate = play_rate + diff 269 | else: 270 | diff = max(diff, -self.clock.dt * constants.music_rate_change_speed) 271 | new_play_rate = play_rate + diff 272 | self.music.set_play_rate(new_play_rate) 273 | return task.cont 274 | 275 | def __camera_task(self, task): 276 | mw = self.mouseWatcherNode 277 | 278 | # Keyboard controls 279 | hor = mw.is_button_down('arrow_right') - mw.is_button_down('arrow_left') 280 | ver = mw.is_button_down('arrow_up') - mw.is_button_down('arrow_down') 281 | 282 | # Check mouse on camera edge. 283 | p = base.win.get_pointer(0) 284 | if p.in_window and not self.panel.hovered and not self.panel2.hovered: 285 | size = base.win.size 286 | if p.x < constants.camera_window_border: 287 | hor -= 2 288 | if p.x > size.x - constants.camera_window_border: 289 | hor += 2 290 | if p.y < constants.camera_window_border: 291 | ver += 2 292 | if p.y > size.y - constants.camera_window_border: 293 | ver -= 2 294 | 295 | if hor != 0: 296 | speed = constants.camera_speed * self.camera.get_pos().length_squared() ** 0.2 297 | movement = hor * speed * self.clock.dt 298 | abs_pos = self.world.root.get_relative_point(self.camera_target, (movement, 0, 0)) 299 | abs_pos.x = min(max(abs_pos.x, -20), 20) 300 | abs_pos.y = min(max(abs_pos.y, -20), 20) 301 | self.camera_target.set_pos(self.world.root, abs_pos) 302 | 303 | if ver != 0: 304 | speed = constants.camera_speed * self.camera.get_pos().length_squared() ** 0.2 305 | movement = ver * speed * self.clock.dt 306 | abs_pos = self.world.root.get_relative_point(self.camera_target, (0, movement, 0)) 307 | abs_pos.x = min(max(abs_pos.x, -20), 20) 308 | abs_pos.y = min(max(abs_pos.y, -20), 20) 309 | self.camera_target.set_pos(self.world.root, abs_pos) 310 | 311 | return task.cont 312 | 313 | def __game_task(self, task): 314 | elapsed = self.clock.dt * self.game_speed * 0.5 315 | self.world.step(elapsed) 316 | 317 | if self.game_speed > 0.0: 318 | power = 0 319 | for town in self.world.towns: 320 | if town.powered: 321 | power += town.power 322 | self.power = power 323 | energy = self.power * self.clock.dt * self.game_speed 324 | self.energy += energy 325 | self.total_energy += energy 326 | self.upgrade_counter += energy / constants.upgrade_point_rarity 327 | self.power_text['text'] = '{:.0f} MW'.format(self.power * 0.1) 328 | self.energy_text['text'] = '{:.0f} MJ'.format(self.energy * 0.1) 329 | 330 | if self.upgrade_counter > 1: 331 | self.on_get_upgrade() 332 | 333 | if self.game_speed != 0: 334 | new_month = self.month + elapsed * 0.4 335 | year = int(new_month // 12) 336 | self.time_text.text = months[int(new_month) % 12] + ', year ' + str(year + 1) 337 | 338 | if int(new_month) != int(self.month): 339 | self.on_begin_month(int(new_month)) 340 | 341 | self.month = new_month 342 | 343 | if all(town.powered for town in self.world.towns): 344 | self.unpowered_button.hide() 345 | 346 | elif self.tutorial_done: 347 | # Show only if we are not looking straight at the town. 348 | cam_pos = self.camera_target.get_pos(self.world.root).xy 349 | if any((town.pos - cam_pos).length_squared() > 25 for town in self.world.towns if not town.powered): 350 | self.unpowered_button.show() 351 | else: 352 | self.unpowered_button.hide() 353 | 354 | elif any(town.powered for town in self.world.towns): 355 | self.tutorial_end() 356 | 357 | mw = self.mouseWatcherNode 358 | 359 | # Mouse controls 360 | construct = None 361 | if mw.has_mouse(): 362 | mpos = mw.get_mouse() 363 | pos3d = core.Point3() 364 | near = core.Point3() 365 | far = core.Point3() 366 | self.lens.extrude(mpos, near, far) 367 | if self.world.plane.intersects_line(pos3d, 368 | self.world.root.get_relative_point(self.camera, near), 369 | self.world.root.get_relative_point(self.camera, far)): 370 | 371 | # Which construct are we hovering over? 372 | construct = self.world.pick_closest_construct(pos3d[0], pos3d[1]) 373 | if construct is self.pylon: 374 | construct = None 375 | 376 | if self.pylon is not None: 377 | self.pylon.position_within_radius_of(pos3d[0], pos3d[1], self.placing_wire.origin, constants.max_pylon_distance) 378 | 379 | if self.highlighted is not None and construct is not self.highlighted: 380 | if self.pylon is not self.highlighted: 381 | self.highlighted.unhighlight() 382 | self.highlighted = None 383 | 384 | if construct is not None: 385 | self.highlighted = construct 386 | 387 | if self.placing_wire: 388 | if not self.placing_wire.try_set_target(construct): 389 | self.placing_wire.set_target(self.pylon) 390 | 391 | if construct is None: 392 | construct.highlight("placing") 393 | elif construct is self.placing_wire.origin: 394 | construct.highlight("self-connect") 395 | elif construct in self.placing_wire.origin.connections and self.placing_wire.origin.connections[construct].placed: 396 | construct.highlight("already-connected") 397 | else: 398 | construct.highlight("too-far") 399 | else: 400 | construct.highlight("connect") 401 | 402 | elif self.mode == 'upgrade': 403 | if construct.upgradable and self.upgrades == 0: 404 | construct.highlight("upgrade-no-money") 405 | elif construct.highlight_mode != 'yay-upgraded': 406 | construct.highlight("upgrade") 407 | elif not construct.highlighted: 408 | construct.highlight("normal") 409 | 410 | elif self.placing_wire: 411 | self.placing_wire.set_target(self.pylon) 412 | 413 | return task.cont 414 | 415 | def spawn_town(self): 416 | index = len(self.world.towns) 417 | self.world.sprout_town() 418 | self.cycle_unpowered_town(index) 419 | 420 | def pause(self): 421 | self.panel2.select_button(0) 422 | self.on_change_speed(0) 423 | 424 | def on_zoom(self, amount): 425 | if not self.tutorial_done: 426 | return 427 | 428 | lens = self.lens 429 | self.camera.set_pos(self.camera.get_pos() * (1.0 + amount * 0.1)) 430 | 431 | dist_sq = self.camera.get_pos().length_squared() 432 | if dist_sq > constants.camera_max_zoom ** 2: 433 | self.camera.set_pos(self.camera.get_pos() * constants.camera_max_zoom / math.sqrt(dist_sq)) 434 | 435 | elif dist_sq < constants.camera_min_zoom ** 2: 436 | self.camera.set_pos(self.camera.get_pos() * constants.camera_min_zoom / math.sqrt(dist_sq)) 437 | 438 | def on_switch_mode(self, mode): 439 | self.cancel_placement() 440 | 441 | if self.highlighted: 442 | self.highlighted.unhighlight() 443 | self.highlighted = None 444 | 445 | self.mode = mode 446 | 447 | def on_change_speed(self, speed): 448 | print("Changing game speed to {}".format(speed)) 449 | self.game_speed = speed 450 | if speed != 0: 451 | self.dialog.hide() 452 | 453 | if speed > 1: 454 | self.target_play_rate = 2.0 455 | else: 456 | self.target_play_rate = speed 457 | 458 | def on_toggle_pause(self): 459 | if not self.tutorial_done: 460 | return 461 | if self.game_speed == 0: 462 | self.panel2.select_button(1) 463 | self.on_change_speed(1) 464 | else: 465 | self.pause() 466 | 467 | def on_click(self): 468 | if self.mode == 'connect': 469 | if self.highlighted: 470 | self.pylon = self.world.construct_pylon() 471 | self.placing_wire = self.highlighted.connect_to(self.pylon) 472 | self.highlighted.unhighlight() 473 | self.highlighted = None 474 | self.mode = 'placing' 475 | 476 | elif self.mode == 'placing': 477 | construct = self.world.pick_closest_construct(self.pylon.x, self.pylon.y) 478 | if construct and construct is not self.placing_wire.target: 479 | print("Cannot place here!") 480 | return 481 | 482 | if self.pylon and not self.world.is_buildable_terrain(self.pylon.x, self.pylon.y): 483 | print("Cannot place on bad terrain!") 484 | self.pylon.highlight('bad-terrain') 485 | return 486 | 487 | self.placing_wire.finish_placement() 488 | 489 | # Continue placing if we just placed a pylon. 490 | if self.pylon.placed: 491 | old_pylon = self.pylon 492 | self.pylon = self.world.construct_pylon() 493 | self.placing_wire = old_pylon.connect_to(self.pylon) 494 | self.highlighted = None 495 | else: 496 | self.placing_wire = None 497 | self.pylon = None 498 | self.mode = 'connect' 499 | 500 | elif self.mode == 'erase': 501 | if self.highlighted: 502 | if self.highlighted.erasable: 503 | self.highlighted.destroy() 504 | self.highlighted = None 505 | else: 506 | self.highlighted.highlight('erase') 507 | 508 | elif self.mode == 'upgrade': 509 | if self.highlighted: 510 | if self.highlighted.upgradable and not self.highlighted.upgraded: 511 | if self.upgrades > 0: 512 | self.highlighted.upgrade() 513 | self.on_use_upgrade() 514 | self.highlighted.highlight("yay-upgraded") 515 | else: 516 | self.highlighted.highlight("upgrade-no-money") 517 | else: 518 | self.highlighted.highlight('upgrade') 519 | 520 | def on_quit(self, arg=None): 521 | self.pause() 522 | 523 | text = """ 524 | Are you sure you want to quit? 525 | 526 | You produced a grand total of {:.1f} GJ. 527 | 528 | Press shift + Q to really exit the game. 529 | """.format(self.total_energy / 10000) 530 | self.dialog.show(text, button_text='Keep playing', button_icon=0xf04b, callback=self.on_toggle_pause) 531 | 532 | def cycle_unpowered_town(self, index=None): 533 | if all(town.powered for town in self.world.towns): 534 | return 535 | 536 | if index is not None: 537 | self.next_unpowered_index = index 538 | 539 | while True: 540 | self.next_unpowered_index = self.next_unpowered_index % len(self.world.towns) 541 | 542 | town = self.world.towns[self.next_unpowered_index] 543 | self.next_unpowered_index += 1 544 | if not town.powered: 545 | self.camera_target.posInterval(constants.cycle_unpowered_town_time, town.root.get_pos(self.pivot), blendType='easeInOut', bakeInStart=True).start() 546 | return 547 | 548 | def highlight_all(self): 549 | for thing in [self.world.gen] + self.world.towns: 550 | thing.highlight(mode=self.mode) 551 | 552 | def cancel_placement(self): 553 | if self.mode == 'placing': 554 | self.placing_wire.set_target(self.pylon) 555 | self.placing_wire.cancel_placement() 556 | self.placing_wire = None 557 | self.pylon = None 558 | self.mode = 'connect' 559 | -------------------------------------------------------------------------------- /data/model/pylon.egg: -------------------------------------------------------------------------------- 1 | { Z-up } 2 | wall { 3 | specr { 0.000000 } 4 | specg { 0.000000 } 5 | specb { 0.000000 } 6 | shininess { 12.5 } 7 | ambr { 1.000000 } 8 | ambg { 1.000000 } 9 | ambb { 1.000000 } 10 | emitr { 0.000000 } 11 | emitg { 0.000000 } 12 | emitb { 0.000000 } 13 | } 14 | 15 | pylon { 16 | { 17 | { 18 | 1.0 0.0 0.0 0.0 19 | 0.0 1.0 0.0 0.0 20 | 0.0 0.0 1.0 0.0 21 | 0.0 0.0 0.0 1.0 22 | } 23 | } 24 | 25 | pylon { 26 | 27 | 0 {-0.236515 0.071671 -0.003260 28 | { 0.721569 0.721569 0.721569 1.0 } 29 | } 30 | 1 {-0.236515 0.071671 0.024740 31 | { 0.933333 0.933333 0.933333 1.0 } 32 | } 33 | 2 {0.236515 0.071671 0.024740 34 | { 1.000000 1.000000 1.000000 1.0 } 35 | } 36 | 3 {0.236515 0.071671 -0.003260 37 | { 0.639216 0.639216 0.639216 1.0 } 38 | } 39 | 4 {0.236515 0.071671 -0.003260 40 | { 0.721569 0.721569 0.721569 1.0 } 41 | } 42 | 5 {0.236515 0.071671 0.024740 43 | { 0.933333 0.933333 0.933333 1.0 } 44 | } 45 | 6 {0.236515 -0.071671 0.024740 46 | { 0.760784 0.760784 0.760784 1.0 } 47 | } 48 | 7 {0.236515 -0.071671 -0.003260 49 | { 0.721569 0.721569 0.721569 1.0 } 50 | } 51 | 8 {0.236515 -0.071671 -0.003260 52 | { 0.760784 0.760784 0.760784 1.0 } 53 | } 54 | 9 {0.236515 -0.071671 0.024740 55 | { 0.905882 0.905882 0.905882 1.0 } 56 | } 57 | 10 {-0.236515 -0.071671 0.024740 58 | { 0.600000 0.600000 0.600000 1.0 } 59 | } 60 | 11 {-0.236515 -0.071671 -0.003260 61 | { 0.721569 0.721569 0.721569 1.0 } 62 | } 63 | 12 {-0.236515 -0.071671 -0.003260 64 | { 0.760784 0.760784 0.760784 1.0 } 65 | } 66 | 13 {-0.236515 -0.071671 0.024740 67 | { 0.066667 0.066667 0.066667 1.0 } 68 | } 69 | 14 {-0.236515 0.071671 0.024740 70 | { 0.760784 0.760784 0.760784 1.0 } 71 | } 72 | 15 {-0.236515 0.071671 -0.003260 73 | { 0.600000 0.600000 0.600000 1.0 } 74 | } 75 | 16 {0.236515 -0.071671 0.024740 76 | { 0.878431 0.878431 0.878431 1.0 } 77 | } 78 | 17 {0.236515 0.071671 0.024740 79 | { 1.000000 1.000000 1.000000 1.0 } 80 | } 81 | 18 {-0.236515 0.071671 0.024740 82 | { 0.878431 0.878431 0.878431 1.0 } 83 | } 84 | 19 {-0.236515 -0.071671 0.024740 85 | { 0.600000 0.600000 0.600000 1.0 } 86 | } 87 | 20 {0.048212 0.017835 0.694962 88 | { 0.800000 0.800000 0.800000 1.0 } 89 | } 90 | 21 {0.040305 0.015782 0.751221 91 | { 1.000000 1.000000 1.000000 1.0 } 92 | } 93 | 22 {0.040305 -0.015782 0.751221 94 | { 1.000000 1.000000 1.000000 1.0 } 95 | } 96 | 23 {0.048212 -0.017835 0.694962 97 | { 0.721569 0.721569 0.721569 1.0 } 98 | } 99 | 24 {0.147744 0.027162 0.024000 100 | { 0.760784 0.760784 0.760784 1.0 } 101 | } 102 | 25 {0.097549 0.027162 0.016946 103 | { 0.721569 0.721569 0.721569 1.0 } 104 | } 105 | 26 {0.008284 0.017835 0.689350 106 | { 1.000000 1.000000 1.000000 1.0 } 107 | } 108 | 27 {0.048212 0.017835 0.694962 109 | { 1.000000 1.000000 1.000000 1.0 } 110 | } 111 | 28 {-0.023799 0.011702 0.862465 112 | { 1.000000 1.000000 1.000000 1.0 } 113 | } 114 | 29 {-0.023799 -0.011702 0.862465 115 | { 1.000000 1.000000 1.000000 1.0 } 116 | } 117 | 30 {0.008143 -0.011702 0.857976 118 | { 1.000000 1.000000 1.000000 1.0 } 119 | } 120 | 31 {0.008143 0.011702 0.857976 121 | { 1.000000 1.000000 1.000000 1.0 } 122 | } 123 | 32 {0.097549 -0.027161 0.016946 124 | { 0.721569 0.721569 0.721569 1.0 } 125 | } 126 | 33 {0.147744 -0.027161 0.024000 127 | { 0.760784 0.760784 0.760784 1.0 } 128 | } 129 | 34 {0.048212 -0.017835 0.694962 130 | { 1.000000 1.000000 1.000000 1.0 } 131 | } 132 | 35 {0.008284 -0.017835 0.689350 133 | { 1.000000 1.000000 1.000000 1.0 } 134 | } 135 | 36 {0.097549 0.027162 0.016946 136 | { 0.760784 0.760784 0.760784 1.0 } 137 | } 138 | 37 {0.097549 -0.027161 0.016946 139 | { 0.760784 0.760784 0.760784 1.0 } 140 | } 141 | 38 {0.008284 -0.017835 0.689350 142 | { 0.800000 0.800000 0.800000 1.0 } 143 | } 144 | 39 {0.008284 0.017835 0.689350 145 | { 0.800000 0.800000 0.800000 1.0 } 146 | } 147 | 40 {-0.003577 -0.015782 0.745609 148 | { 1.000000 1.000000 1.000000 1.0 } 149 | } 150 | 41 {-0.003577 0.015782 0.745609 151 | { 1.000000 1.000000 1.000000 1.0 } 152 | } 153 | 42 {0.008143 0.011702 0.857976 154 | { 1.000000 1.000000 1.000000 1.0 } 155 | } 156 | 43 {0.008143 -0.011702 0.857976 157 | { 1.000000 1.000000 1.000000 1.0 } 158 | } 159 | 44 {-0.043505 0.015782 0.751221 160 | { 1.000000 1.000000 1.000000 1.0 } 161 | } 162 | 45 {-0.043505 -0.015782 0.751221 163 | { 1.000000 1.000000 1.000000 1.0 } 164 | } 165 | 46 {-0.023799 -0.011702 0.862465 166 | { 1.000000 1.000000 1.000000 1.0 } 167 | } 168 | 47 {-0.023799 0.011702 0.862465 169 | { 1.000000 1.000000 1.000000 1.0 } 170 | } 171 | 48 {0.147744 -0.027161 0.024000 172 | { 0.721569 0.721569 0.721569 1.0 } 173 | } 174 | 49 {0.147744 0.027162 0.024000 175 | { 0.721569 0.721569 0.721569 1.0 } 176 | } 177 | 50 {0.048212 0.017835 0.694962 178 | { 0.800000 0.800000 0.800000 1.0 } 179 | } 180 | 51 {0.048212 -0.017835 0.694962 181 | { 0.839216 0.839216 0.839216 1.0 } 182 | } 183 | 52 {0.008284 0.017835 0.689350 184 | { 0.800000 0.800000 0.800000 1.0 } 185 | } 186 | 53 {0.008284 -0.017835 0.689350 187 | { 0.800000 0.800000 0.800000 1.0 } 188 | } 189 | 54 {0.000377 -0.015782 0.745609 190 | { 0.933333 0.933333 0.933333 1.0 } 191 | } 192 | 55 {0.000377 0.015782 0.745609 193 | { 1.000000 1.000000 1.000000 1.0 } 194 | } 195 | 56 {-0.043505 -0.015782 0.751221 196 | { 0.878431 0.878431 0.878431 1.0 } 197 | } 198 | 57 {-0.003577 -0.015782 0.745609 199 | { 1.000000 1.000000 1.000000 1.0 } 200 | } 201 | 58 {0.008143 -0.011702 0.857976 202 | { 1.000000 1.000000 1.000000 1.0 } 203 | } 204 | 59 {-0.023799 -0.011702 0.862465 205 | { 1.000000 1.000000 1.000000 1.0 } 206 | } 207 | 60 {-0.003577 0.015782 0.745609 208 | { 0.760784 0.760784 0.760784 1.0 } 209 | } 210 | 61 {-0.043505 0.015782 0.751221 211 | { 1.000000 1.000000 1.000000 1.0 } 212 | } 213 | 62 {-0.023799 0.011702 0.862465 214 | { 1.000000 1.000000 1.000000 1.0 } 215 | } 216 | 63 {0.008143 0.011702 0.857976 217 | { 1.000000 1.000000 1.000000 1.0 } 218 | } 219 | 64 {-0.011484 0.017835 0.689350 220 | { 1.000000 1.000000 1.000000 1.0 } 221 | } 222 | 65 {-0.051412 0.017835 0.694962 223 | { 1.000000 1.000000 1.000000 1.0 } 224 | } 225 | 66 {-0.043505 0.015782 0.751221 226 | { 1.000000 1.000000 1.000000 1.0 } 227 | } 228 | 67 {-0.003577 0.015782 0.745609 229 | { 0.760784 0.760784 0.760784 1.0 } 230 | } 231 | 68 {-0.051412 -0.017835 0.694962 232 | { 1.000000 1.000000 1.000000 1.0 } 233 | } 234 | 69 {-0.011484 -0.017835 0.689350 235 | { 1.000000 1.000000 1.000000 1.0 } 236 | } 237 | 70 {-0.003577 -0.015782 0.745609 238 | { 1.000000 1.000000 1.000000 1.0 } 239 | } 240 | 71 {-0.043505 -0.015782 0.751221 241 | { 1.000000 1.000000 1.000000 1.0 } 242 | } 243 | 72 {0.008284 -0.017835 0.689350 244 | { 1.000000 1.000000 1.000000 1.0 } 245 | } 246 | 73 {0.048212 -0.017835 0.694962 247 | { 1.000000 1.000000 1.000000 1.0 } 248 | } 249 | 74 {0.040305 -0.015782 0.751221 250 | { 1.000000 1.000000 1.000000 1.0 } 251 | } 252 | 75 {0.000377 -0.015782 0.745609 253 | { 1.000000 1.000000 1.000000 1.0 } 254 | } 255 | 76 {-0.051412 0.017835 0.694962 256 | { 0.800000 0.800000 0.800000 1.0 } 257 | } 258 | 77 {-0.051412 -0.017835 0.694962 259 | { 0.839216 0.839216 0.839216 1.0 } 260 | } 261 | 78 {-0.043505 -0.015782 0.751221 262 | { 0.878431 0.878431 0.878431 1.0 } 263 | } 264 | 79 {-0.043505 0.015782 0.751221 265 | { 1.000000 1.000000 1.000000 1.0 } 266 | } 267 | 80 {0.048212 0.017835 0.694962 268 | { 1.000000 1.000000 1.000000 1.0 } 269 | } 270 | 81 {0.008284 0.017835 0.689350 271 | { 1.000000 1.000000 1.000000 1.0 } 272 | } 273 | 82 {0.000377 0.015782 0.745609 274 | { 1.000000 1.000000 1.000000 1.0 } 275 | } 276 | 83 {0.040305 0.015782 0.751221 277 | { 0.760784 0.760784 0.760784 1.0 } 278 | } 279 | 84 {0.040305 0.015782 0.751221 280 | { 0.800000 0.800000 0.800000 1.0 } 281 | } 282 | 85 {0.000377 0.015782 0.745609 283 | { 1.000000 1.000000 1.000000 1.0 } 284 | } 285 | 86 {-0.011343 0.011702 0.857976 286 | { 1.000000 1.000000 1.000000 1.0 } 287 | } 288 | 87 {0.020599 0.011702 0.862465 289 | { 1.000000 1.000000 1.000000 1.0 } 290 | } 291 | 88 {0.000377 -0.015782 0.745609 292 | { 0.933333 0.933333 0.933333 1.0 } 293 | } 294 | 89 {0.040305 -0.015782 0.751221 295 | { 1.000000 1.000000 1.000000 1.0 } 296 | } 297 | 90 {0.020599 -0.011702 0.862465 298 | { 1.000000 1.000000 1.000000 1.0 } 299 | } 300 | 91 {-0.011343 -0.011702 0.857976 301 | { 1.000000 1.000000 1.000000 1.0 } 302 | } 303 | 92 {0.000377 0.015782 0.745609 304 | { 1.000000 1.000000 1.000000 1.0 } 305 | } 306 | 93 {0.000377 -0.015782 0.745609 307 | { 1.000000 1.000000 1.000000 1.0 } 308 | } 309 | 94 {-0.011343 -0.011702 0.857976 310 | { 1.000000 1.000000 1.000000 1.0 } 311 | } 312 | 95 {-0.011343 0.011702 0.857976 313 | { 1.000000 1.000000 1.000000 1.0 } 314 | } 315 | 96 {-0.100749 -0.027161 0.016946 316 | { 0.760784 0.760784 0.760784 1.0 } 317 | } 318 | 97 {-0.100749 0.027162 0.016946 319 | { 0.800000 0.800000 0.800000 1.0 } 320 | } 321 | 98 {-0.011484 0.017835 0.689350 322 | { 0.760784 0.760784 0.760784 1.0 } 323 | } 324 | 99 {-0.011484 -0.017835 0.689350 325 | { 0.839216 0.839216 0.839216 1.0 } 326 | } 327 | 100 {-0.150944 0.027162 0.024000 328 | { 0.800000 0.800000 0.800000 1.0 } 329 | } 330 | 101 {-0.150944 -0.027161 0.024000 331 | { 0.760784 0.760784 0.760784 1.0 } 332 | } 333 | 102 {-0.051412 -0.017835 0.694962 334 | { 0.839216 0.839216 0.839216 1.0 } 335 | } 336 | 103 {-0.051412 0.017835 0.694962 337 | { 0.839216 0.839216 0.839216 1.0 } 338 | } 339 | 104 {0.040305 -0.015782 0.751221 340 | { 1.000000 1.000000 1.000000 1.0 } 341 | } 342 | 105 {0.040305 0.015782 0.751221 343 | { 1.000000 1.000000 1.000000 1.0 } 344 | } 345 | 106 {0.020599 0.011702 0.862465 346 | { 1.000000 1.000000 1.000000 1.0 } 347 | } 348 | 107 {0.020599 -0.011702 0.862465 349 | { 1.000000 1.000000 1.000000 1.0 } 350 | } 351 | 108 {-0.011343 0.011702 0.857976 352 | { 1.000000 1.000000 1.000000 1.0 } 353 | } 354 | 109 {-0.011343 -0.011702 0.857976 355 | { 1.000000 1.000000 1.000000 1.0 } 356 | } 357 | 110 {0.020599 -0.011702 0.862465 358 | { 1.000000 1.000000 1.000000 1.0 } 359 | } 360 | 111 {0.020599 0.011702 0.862465 361 | { 1.000000 1.000000 1.000000 1.0 } 362 | } 363 | 112 {-0.150944 -0.027161 0.024000 364 | { 0.760784 0.760784 0.760784 1.0 } 365 | } 366 | 113 {-0.100749 -0.027161 0.016946 367 | { 0.760784 0.760784 0.760784 1.0 } 368 | } 369 | 114 {-0.011484 -0.017835 0.689350 370 | { 1.000000 1.000000 1.000000 1.0 } 371 | } 372 | 115 {-0.051412 -0.017835 0.694962 373 | { 1.000000 1.000000 1.000000 1.0 } 374 | } 375 | 116 {-0.100749 0.027162 0.016946 376 | { 0.800000 0.800000 0.800000 1.0 } 377 | } 378 | 117 {-0.150944 0.027162 0.024000 379 | { 0.800000 0.800000 0.800000 1.0 } 380 | } 381 | 118 {-0.051412 0.017835 0.694962 382 | { 1.000000 1.000000 1.000000 1.0 } 383 | } 384 | 119 {-0.011484 0.017835 0.689350 385 | { 1.000000 1.000000 1.000000 1.0 } 386 | } 387 | 120 {-0.011484 0.017835 0.689350 388 | { 0.721569 0.721569 0.721569 1.0 } 389 | } 390 | 121 {-0.003577 0.015782 0.745609 391 | { 1.000000 1.000000 1.000000 1.0 } 392 | } 393 | 122 {-0.003577 -0.015782 0.745609 394 | { 0.933333 0.933333 0.933333 1.0 } 395 | } 396 | 123 {-0.011484 -0.017835 0.689350 397 | { 0.678431 0.678431 0.678431 1.0 } 398 | } 399 | 124 {-0.215397 0.013636 0.699964 400 | { 1.000000 1.000000 1.000000 1.0 } 401 | } 402 | 125 {-0.215397 0.013636 0.727237 403 | { 0.933333 0.933333 0.933333 1.0 } 404 | } 405 | 126 {0.215397 0.013636 0.727237 406 | { 1.000000 1.000000 1.000000 1.0 } 407 | } 408 | 127 {0.215397 0.013636 0.699964 409 | { 0.878431 0.878431 0.878431 1.0 } 410 | } 411 | 128 {0.215397 0.013636 0.699964 412 | { 0.933333 0.933333 0.933333 1.0 } 413 | } 414 | 129 {0.215397 0.013636 0.727237 415 | { 1.000000 1.000000 1.000000 1.0 } 416 | } 417 | 130 {0.215397 -0.013637 0.727237 418 | { 1.000000 1.000000 1.000000 1.0 } 419 | } 420 | 131 {0.215397 -0.013637 0.699964 421 | { 0.933333 0.933333 0.933333 1.0 } 422 | } 423 | 132 {0.215397 -0.013637 0.699964 424 | { 0.933333 0.933333 0.933333 1.0 } 425 | } 426 | 133 {0.215397 -0.013637 0.727237 427 | { 1.000000 1.000000 1.000000 1.0 } 428 | } 429 | 134 {-0.215397 -0.013637 0.727237 430 | { 1.000000 1.000000 1.000000 1.0 } 431 | } 432 | 135 {-0.215397 -0.013637 0.699964 433 | { 0.905882 0.905882 0.905882 1.0 } 434 | } 435 | 136 {-0.215397 -0.013637 0.699964 436 | { 1.000000 1.000000 1.000000 1.0 } 437 | } 438 | 137 {-0.215397 -0.013637 0.727237 439 | { 0.933333 0.933333 0.933333 1.0 } 440 | } 441 | 138 {-0.215397 0.013636 0.727237 442 | { 0.721569 0.721569 0.721569 1.0 } 443 | } 444 | 139 {-0.215397 0.013636 0.699964 445 | { 0.760784 0.760784 0.760784 1.0 } 446 | } 447 | 140 {0.215397 0.013636 0.699964 448 | { 1.000000 1.000000 1.000000 1.0 } 449 | } 450 | 141 {0.215397 -0.013637 0.699964 451 | { 0.878431 0.878431 0.878431 1.0 } 452 | } 453 | 142 {-0.215397 -0.013637 0.699964 454 | { 1.000000 1.000000 1.000000 1.0 } 455 | } 456 | 143 {-0.215397 0.013636 0.699964 457 | { 0.905882 0.905882 0.905882 1.0 } 458 | } 459 | 144 {0.215397 -0.013637 0.727237 460 | { 0.933333 0.933333 0.933333 1.0 } 461 | } 462 | 145 {0.215397 0.013636 0.727237 463 | { 0.933333 0.933333 0.933333 1.0 } 464 | } 465 | 146 {-0.215397 0.013636 0.727237 466 | { 0.933333 0.933333 0.933333 1.0 } 467 | } 468 | 147 {-0.215397 -0.013637 0.727237 469 | { 1.000000 1.000000 1.000000 1.0 } 470 | }} 471 | 472 | 473 | { 474 | { wall } 475 | {0.000000 1.000000 0.000000} 476 | { 0 1 2 3 { pylon }} 477 | } 478 | { 479 | { wall } 480 | {1.000000 0.000000 0.000000} 481 | { 4 5 6 7 { pylon }} 482 | } 483 | { 484 | { wall } 485 | {-0.000000 -1.000000 0.000000} 486 | { 8 9 10 11 { pylon }} 487 | } 488 | { 489 | { wall } 490 | {-1.000000 0.000000 0.000000} 491 | { 12 13 14 15 { pylon }} 492 | } 493 | { 494 | { wall } 495 | {0.000000 0.000000 1.000000} 496 | { 16 17 18 19 { pylon }} 497 | } 498 | { 499 | { wall } 500 | {0.990268 -0.000000 0.139173} 501 | { 20 21 22 23 { pylon }} 502 | } 503 | { 504 | { wall } 505 | {-0.001913 0.999905 0.013616} 506 | { 24 25 26 27 { pylon }} 507 | } 508 | { 509 | { wall } 510 | {0.139175 0.000000 0.990268} 511 | { 28 29 30 31 { pylon }} 512 | } 513 | { 514 | { wall } 515 | {-0.001914 -0.999905 0.013616} 516 | { 32 33 34 35 { pylon }} 517 | } 518 | { 519 | { wall } 520 | {-0.991303 0.000000 -0.131601} 521 | { 36 37 38 39 { pylon }} 522 | } 523 | { 524 | { wall } 525 | {0.994604 -0.000000 -0.103743} 526 | { 40 41 42 43 { pylon }} 527 | } 528 | { 529 | { wall } 530 | {-0.984670 0.000000 0.174426} 531 | { 44 45 46 47 { pylon }} 532 | } 533 | { 534 | { wall } 535 | {0.989176 0.000000 0.146737} 536 | { 48 49 50 51 { pylon }} 537 | } 538 | { 539 | { wall } 540 | {-0.990268 0.000000 -0.139173} 541 | { 52 53 54 55 { pylon }} 542 | } 543 | { 544 | { wall } 545 | {0.005026 -0.999348 0.035759} 546 | { 56 57 58 59 { pylon }} 547 | } 548 | { 549 | { wall } 550 | {0.005025 0.999348 0.035759} 551 | { 60 61 62 63 { pylon }} 552 | } 553 | { 554 | { wall } 555 | {0.005026 0.999348 0.035759} 556 | { 64 65 66 67 { pylon }} 557 | } 558 | { 559 | { wall } 560 | {0.005025 -0.999348 0.035759} 561 | { 68 69 70 71 { pylon }} 562 | } 563 | { 564 | { wall } 565 | {-0.005026 -0.999348 0.035759} 566 | { 72 73 74 75 { pylon }} 567 | } 568 | { 569 | { wall } 570 | {-0.990268 0.000000 0.139173} 571 | { 76 77 78 79 { pylon }} 572 | } 573 | { 574 | { wall } 575 | {-0.005026 0.999348 0.035759} 576 | { 80 81 82 83 { pylon }} 577 | } 578 | { 579 | { wall } 580 | {-0.005026 0.999348 0.035759} 581 | { 84 85 86 87 { pylon }} 582 | } 583 | { 584 | { wall } 585 | {-0.005026 -0.999348 0.035759} 586 | { 88 89 90 91 { pylon }} 587 | } 588 | { 589 | { wall } 590 | {-0.994604 0.000000 -0.103743} 591 | { 92 93 94 95 { pylon }} 592 | } 593 | { 594 | { wall } 595 | {0.991303 0.000000 -0.131601} 596 | { 96 97 98 99 { pylon }} 597 | } 598 | { 599 | { wall } 600 | {-0.989176 0.000000 0.146737} 601 | { 100 101 102 103 { pylon }} 602 | } 603 | { 604 | { wall } 605 | {0.984670 -0.000000 0.174426} 606 | { 104 105 106 107 { pylon }} 607 | } 608 | { 609 | { wall } 610 | {-0.139175 0.000000 0.990268} 611 | { 108 109 110 111 { pylon }} 612 | } 613 | { 614 | { wall } 615 | {0.001913 -0.999905 0.013616} 616 | { 112 113 114 115 { pylon }} 617 | } 618 | { 619 | { wall } 620 | {0.001914 0.999905 0.013616} 621 | { 116 117 118 119 { pylon }} 622 | } 623 | { 624 | { wall } 625 | {0.990268 -0.000000 -0.139173} 626 | { 120 121 122 123 { pylon }} 627 | } 628 | { 629 | { wall } 630 | {0.000000 1.000000 0.000000} 631 | { 124 125 126 127 { pylon }} 632 | } 633 | { 634 | { wall } 635 | {1.000000 0.000000 0.000000} 636 | { 128 129 130 131 { pylon }} 637 | } 638 | { 639 | { wall } 640 | {0.000000 -1.000000 0.000000} 641 | { 132 133 134 135 { pylon }} 642 | } 643 | { 644 | { wall } 645 | {-1.000000 0.000000 0.000000} 646 | { 136 137 138 139 { pylon }} 647 | } 648 | { 649 | { wall } 650 | {0.000000 0.000000 -1.000000} 651 | { 140 141 142 143 { pylon }} 652 | } 653 | { 654 | { wall } 655 | {0.000000 0.000000 1.000000} 656 | { 144 145 146 147 { pylon }} 657 | } 658 | } 659 | -------------------------------------------------------------------------------- /data/model/superpylon.egg: -------------------------------------------------------------------------------- 1 | { Z-up } 2 | wall { 3 | specr { 0.000000 } 4 | specg { 0.000000 } 5 | specb { 0.000000 } 6 | shininess { 12.5 } 7 | ambr { 1.000000 } 8 | ambg { 1.000000 } 9 | ambb { 1.000000 } 10 | emitr { 0.000000 } 11 | emitg { 0.000000 } 12 | emitb { 0.000000 } 13 | } 14 | 15 | pylon { 16 | { 17 | { 18 | 1.0 0.0 0.0 0.0 19 | 0.0 1.0 0.0 0.0 20 | 0.0 0.0 1.0 0.0 21 | 0.0 0.0 0.0 1.0 22 | } 23 | } 24 | 25 | pylon { 26 | 27 | 0 {-0.318013 0.096368 -0.004075 28 | { 0.721569 0.721569 0.721569 1.0 } 29 | } 30 | 1 {-0.318013 0.096368 0.030925 31 | { 0.933333 0.933333 0.933333 1.0 } 32 | } 33 | 2 {0.318013 0.096367 0.030925 34 | { 1.000000 1.000000 1.000000 1.0 } 35 | } 36 | 3 {0.318013 0.096367 -0.004075 37 | { 0.639216 0.639216 0.639216 1.0 } 38 | } 39 | 4 {0.318013 0.096367 -0.004075 40 | { 0.721569 0.721569 0.721569 1.0 } 41 | } 42 | 5 {0.318013 0.096367 0.030925 43 | { 0.933333 0.933333 0.933333 1.0 } 44 | } 45 | 6 {0.318013 -0.096367 0.030925 46 | { 0.760784 0.760784 0.760784 1.0 } 47 | } 48 | 7 {0.318013 -0.096367 -0.004075 49 | { 0.721569 0.721569 0.721569 1.0 } 50 | } 51 | 8 {0.318013 -0.096367 -0.004075 52 | { 0.760784 0.760784 0.760784 1.0 } 53 | } 54 | 9 {0.318013 -0.096367 0.030925 55 | { 0.905882 0.905882 0.905882 1.0 } 56 | } 57 | 10 {-0.318013 -0.096367 0.030925 58 | { 0.600000 0.600000 0.600000 1.0 } 59 | } 60 | 11 {-0.318013 -0.096367 -0.004075 61 | { 0.721569 0.721569 0.721569 1.0 } 62 | } 63 | 12 {-0.318013 -0.096367 -0.004075 64 | { 0.760784 0.760784 0.760784 1.0 } 65 | } 66 | 13 {-0.318013 -0.096367 0.030925 67 | { 0.066667 0.066667 0.066667 1.0 } 68 | } 69 | 14 {-0.318013 0.096368 0.030925 70 | { 0.760784 0.760784 0.760784 1.0 } 71 | } 72 | 15 {-0.318013 0.096368 -0.004075 73 | { 0.600000 0.600000 0.600000 1.0 } 74 | } 75 | 16 {0.318013 -0.096367 0.030925 76 | { 0.878431 0.878431 0.878431 1.0 } 77 | } 78 | 17 {0.318013 0.096367 0.030925 79 | { 1.000000 1.000000 1.000000 1.0 } 80 | } 81 | 18 {-0.318013 0.096368 0.030925 82 | { 0.878431 0.878431 0.878431 1.0 } 83 | } 84 | 19 {-0.318013 -0.096367 0.030925 85 | { 0.600000 0.600000 0.600000 1.0 } 86 | } 87 | 20 {0.178200 0.022293 0.877855 88 | { 0.800000 0.800000 0.800000 1.0 } 89 | } 90 | 21 {0.178200 0.019727 0.948870 91 | { 1.000000 1.000000 1.000000 1.0 } 92 | } 93 | 22 {0.178200 -0.019727 0.948870 94 | { 1.000000 1.000000 1.000000 1.0 } 95 | } 96 | 23 {0.178200 -0.022293 0.877855 97 | { 0.721569 0.721569 0.721569 1.0 } 98 | } 99 | 24 {0.192600 0.042440 0.030000 100 | { 0.760784 0.760784 0.760784 1.0 } 101 | } 102 | 25 {0.113400 0.042440 0.030000 103 | { 0.721569 0.721569 0.721569 1.0 } 104 | } 105 | 26 {0.127800 0.022293 0.877855 106 | { 1.000000 1.000000 1.000000 1.0 } 107 | } 108 | 27 {0.178200 0.022293 0.877855 109 | { 1.000000 1.000000 1.000000 1.0 } 110 | } 111 | 28 {-0.177160 0.014628 1.090000 112 | { 1.000000 1.000000 1.000000 1.0 } 113 | } 114 | 29 {-0.177160 -0.014628 1.090000 115 | { 1.000000 1.000000 1.000000 1.0 } 116 | } 117 | 30 {-0.136840 -0.014628 1.090000 118 | { 1.000000 1.000000 1.000000 1.0 } 119 | } 120 | 31 {-0.136840 0.014628 1.090000 121 | { 1.000000 1.000000 1.000000 1.0 } 122 | } 123 | 32 {0.113400 -0.042440 0.030000 124 | { 0.721569 0.721569 0.721569 1.0 } 125 | } 126 | 33 {0.192600 -0.042440 0.030000 127 | { 0.760784 0.760784 0.760784 1.0 } 128 | } 129 | 34 {0.178200 -0.022293 0.877855 130 | { 1.000000 1.000000 1.000000 1.0 } 131 | } 132 | 35 {0.127800 -0.022293 0.877855 133 | { 1.000000 1.000000 1.000000 1.0 } 134 | } 135 | 36 {0.113400 0.042440 0.030000 136 | { 0.760784 0.760784 0.760784 1.0 } 137 | } 138 | 37 {0.113400 -0.042440 0.030000 139 | { 0.760784 0.760784 0.760784 1.0 } 140 | } 141 | 38 {0.127800 -0.022293 0.877855 142 | { 0.800000 0.800000 0.800000 1.0 } 143 | } 144 | 39 {0.127800 0.022293 0.877855 145 | { 0.800000 0.800000 0.800000 1.0 } 146 | } 147 | 40 {-0.131800 -0.019727 0.948870 148 | { 1.000000 1.000000 1.000000 1.0 } 149 | } 150 | 41 {-0.131800 0.019727 0.948870 151 | { 1.000000 1.000000 1.000000 1.0 } 152 | } 153 | 42 {-0.136840 0.014628 1.090000 154 | { 1.000000 1.000000 1.000000 1.0 } 155 | } 156 | 43 {-0.136840 -0.014628 1.090000 157 | { 1.000000 1.000000 1.000000 1.0 } 158 | } 159 | 44 {-0.182200 0.019727 0.948870 160 | { 1.000000 1.000000 1.000000 1.0 } 161 | } 162 | 45 {-0.182200 -0.019727 0.948870 163 | { 1.000000 1.000000 1.000000 1.0 } 164 | } 165 | 46 {-0.177160 -0.014628 1.090000 166 | { 1.000000 1.000000 1.000000 1.0 } 167 | } 168 | 47 {-0.177160 0.014628 1.090000 169 | { 1.000000 1.000000 1.000000 1.0 } 170 | } 171 | 48 {0.192600 -0.042440 0.030000 172 | { 0.721569 0.721569 0.721569 1.0 } 173 | } 174 | 49 {0.192600 0.042440 0.030000 175 | { 0.721569 0.721569 0.721569 1.0 } 176 | } 177 | 50 {0.178200 0.022293 0.877855 178 | { 0.800000 0.800000 0.800000 1.0 } 179 | } 180 | 51 {0.178200 -0.022293 0.877855 181 | { 0.839216 0.839216 0.839216 1.0 } 182 | } 183 | 52 {0.127800 0.022293 0.877855 184 | { 0.800000 0.800000 0.800000 1.0 } 185 | } 186 | 53 {0.127800 -0.022293 0.877855 187 | { 0.800000 0.800000 0.800000 1.0 } 188 | } 189 | 54 {0.127800 -0.019727 0.948870 190 | { 0.933333 0.933333 0.933333 1.0 } 191 | } 192 | 55 {0.127800 0.019727 0.948870 193 | { 1.000000 1.000000 1.000000 1.0 } 194 | } 195 | 56 {-0.182200 -0.019727 0.948870 196 | { 0.878431 0.878431 0.878431 1.0 } 197 | } 198 | 57 {-0.131800 -0.019727 0.948870 199 | { 1.000000 1.000000 1.000000 1.0 } 200 | } 201 | 58 {-0.136840 -0.014628 1.090000 202 | { 1.000000 1.000000 1.000000 1.0 } 203 | } 204 | 59 {-0.177160 -0.014628 1.090000 205 | { 1.000000 1.000000 1.000000 1.0 } 206 | } 207 | 60 {-0.131800 0.019727 0.948870 208 | { 0.760784 0.760784 0.760784 1.0 } 209 | } 210 | 61 {-0.182200 0.019727 0.948870 211 | { 1.000000 1.000000 1.000000 1.0 } 212 | } 213 | 62 {-0.177160 0.014628 1.090000 214 | { 1.000000 1.000000 1.000000 1.0 } 215 | } 216 | 63 {-0.136840 0.014628 1.090000 217 | { 1.000000 1.000000 1.000000 1.0 } 218 | } 219 | 64 {-0.131800 0.022293 0.877855 220 | { 1.000000 1.000000 1.000000 1.0 } 221 | } 222 | 65 {-0.182200 0.022293 0.877855 223 | { 1.000000 1.000000 1.000000 1.0 } 224 | } 225 | 66 {-0.182200 0.019727 0.948870 226 | { 1.000000 1.000000 1.000000 1.0 } 227 | } 228 | 67 {-0.131800 0.019727 0.948870 229 | { 0.760784 0.760784 0.760784 1.0 } 230 | } 231 | 68 {-0.182200 -0.022293 0.877855 232 | { 1.000000 1.000000 1.000000 1.0 } 233 | } 234 | 69 {-0.131800 -0.022293 0.877855 235 | { 1.000000 1.000000 1.000000 1.0 } 236 | } 237 | 70 {-0.131800 -0.019727 0.948870 238 | { 1.000000 1.000000 1.000000 1.0 } 239 | } 240 | 71 {-0.182200 -0.019727 0.948870 241 | { 1.000000 1.000000 1.000000 1.0 } 242 | } 243 | 72 {0.127800 -0.022293 0.877855 244 | { 1.000000 1.000000 1.000000 1.0 } 245 | } 246 | 73 {0.178200 -0.022293 0.877855 247 | { 1.000000 1.000000 1.000000 1.0 } 248 | } 249 | 74 {0.178200 -0.019727 0.948870 250 | { 1.000000 1.000000 1.000000 1.0 } 251 | } 252 | 75 {0.127800 -0.019727 0.948870 253 | { 1.000000 1.000000 1.000000 1.0 } 254 | } 255 | 76 {-0.182200 0.022293 0.877855 256 | { 0.800000 0.800000 0.800000 1.0 } 257 | } 258 | 77 {-0.182200 -0.022293 0.877855 259 | { 0.839216 0.839216 0.839216 1.0 } 260 | } 261 | 78 {-0.182200 -0.019727 0.948870 262 | { 0.878431 0.878431 0.878431 1.0 } 263 | } 264 | 79 {-0.182200 0.019727 0.948870 265 | { 1.000000 1.000000 1.000000 1.0 } 266 | } 267 | 80 {0.178200 0.022293 0.877855 268 | { 1.000000 1.000000 1.000000 1.0 } 269 | } 270 | 81 {0.127800 0.022293 0.877855 271 | { 1.000000 1.000000 1.000000 1.0 } 272 | } 273 | 82 {0.127800 0.019727 0.948870 274 | { 1.000000 1.000000 1.000000 1.0 } 275 | } 276 | 83 {0.178200 0.019727 0.948870 277 | { 0.760784 0.760784 0.760784 1.0 } 278 | } 279 | 84 {0.178200 0.019727 0.948870 280 | { 0.800000 0.800000 0.800000 1.0 } 281 | } 282 | 85 {0.127800 0.019727 0.948870 283 | { 1.000000 1.000000 1.000000 1.0 } 284 | } 285 | 86 {0.132840 0.014628 1.090000 286 | { 1.000000 1.000000 1.000000 1.0 } 287 | } 288 | 87 {0.173160 0.014628 1.090000 289 | { 1.000000 1.000000 1.000000 1.0 } 290 | } 291 | 88 {0.127800 -0.019727 0.948870 292 | { 0.933333 0.933333 0.933333 1.0 } 293 | } 294 | 89 {0.178200 -0.019727 0.948870 295 | { 1.000000 1.000000 1.000000 1.0 } 296 | } 297 | 90 {0.173160 -0.014628 1.090000 298 | { 1.000000 1.000000 1.000000 1.0 } 299 | } 300 | 91 {0.132840 -0.014628 1.090000 301 | { 1.000000 1.000000 1.000000 1.0 } 302 | } 303 | 92 {0.127800 0.019727 0.948870 304 | { 1.000000 1.000000 1.000000 1.0 } 305 | } 306 | 93 {0.127800 -0.019727 0.948870 307 | { 1.000000 1.000000 1.000000 1.0 } 308 | } 309 | 94 {0.132840 -0.014628 1.090000 310 | { 1.000000 1.000000 1.000000 1.0 } 311 | } 312 | 95 {0.132840 0.014628 1.090000 313 | { 1.000000 1.000000 1.000000 1.0 } 314 | } 315 | 96 {-0.117400 -0.042440 0.030000 316 | { 0.760784 0.760784 0.760784 1.0 } 317 | } 318 | 97 {-0.117400 0.042440 0.030000 319 | { 0.800000 0.800000 0.800000 1.0 } 320 | } 321 | 98 {-0.131800 0.022293 0.877855 322 | { 0.760784 0.760784 0.760784 1.0 } 323 | } 324 | 99 {-0.131800 -0.022293 0.877855 325 | { 0.839216 0.839216 0.839216 1.0 } 326 | } 327 | 100 {-0.196600 0.042440 0.030000 328 | { 0.800000 0.800000 0.800000 1.0 } 329 | } 330 | 101 {-0.196600 -0.042440 0.030000 331 | { 0.760784 0.760784 0.760784 1.0 } 332 | } 333 | 102 {-0.182200 -0.022293 0.877855 334 | { 0.839216 0.839216 0.839216 1.0 } 335 | } 336 | 103 {-0.182200 0.022293 0.877855 337 | { 0.839216 0.839216 0.839216 1.0 } 338 | } 339 | 104 {0.178200 -0.019727 0.948870 340 | { 1.000000 1.000000 1.000000 1.0 } 341 | } 342 | 105 {0.178200 0.019727 0.948870 343 | { 1.000000 1.000000 1.000000 1.0 } 344 | } 345 | 106 {0.173160 0.014628 1.090000 346 | { 1.000000 1.000000 1.000000 1.0 } 347 | } 348 | 107 {0.173160 -0.014628 1.090000 349 | { 1.000000 1.000000 1.000000 1.0 } 350 | } 351 | 108 {0.132840 0.014628 1.090000 352 | { 1.000000 1.000000 1.000000 1.0 } 353 | } 354 | 109 {0.132840 -0.014628 1.090000 355 | { 1.000000 1.000000 1.000000 1.0 } 356 | } 357 | 110 {0.173160 -0.014628 1.090000 358 | { 1.000000 1.000000 1.000000 1.0 } 359 | } 360 | 111 {0.173160 0.014628 1.090000 361 | { 1.000000 1.000000 1.000000 1.0 } 362 | } 363 | 112 {-0.196600 -0.042440 0.030000 364 | { 0.760784 0.760784 0.760784 1.0 } 365 | } 366 | 113 {-0.117400 -0.042440 0.030000 367 | { 0.760784 0.760784 0.760784 1.0 } 368 | } 369 | 114 {-0.131800 -0.022293 0.877855 370 | { 1.000000 1.000000 1.000000 1.0 } 371 | } 372 | 115 {-0.182200 -0.022293 0.877855 373 | { 1.000000 1.000000 1.000000 1.0 } 374 | } 375 | 116 {-0.117400 0.042440 0.030000 376 | { 0.800000 0.800000 0.800000 1.0 } 377 | } 378 | 117 {-0.196600 0.042440 0.030000 379 | { 0.800000 0.800000 0.800000 1.0 } 380 | } 381 | 118 {-0.182200 0.022293 0.877855 382 | { 1.000000 1.000000 1.000000 1.0 } 383 | } 384 | 119 {-0.131800 0.022293 0.877855 385 | { 1.000000 1.000000 1.000000 1.0 } 386 | } 387 | 120 {-0.131800 0.022293 0.877855 388 | { 0.721569 0.721569 0.721569 1.0 } 389 | } 390 | 121 {-0.131800 0.019727 0.948870 391 | { 1.000000 1.000000 1.000000 1.0 } 392 | } 393 | 122 {-0.131800 -0.019727 0.948870 394 | { 0.933333 0.933333 0.933333 1.0 } 395 | } 396 | 123 {-0.131800 -0.022293 0.877855 397 | { 0.678431 0.678431 0.678431 1.0 } 398 | } 399 | 124 {-0.319860 0.018000 0.874000 400 | { 1.000000 1.000000 1.000000 1.0 } 401 | } 402 | 125 {-0.319860 0.018000 0.910000 403 | { 0.933333 0.933333 0.933333 1.0 } 404 | } 405 | 126 {0.319860 0.018000 0.910000 406 | { 1.000000 1.000000 1.000000 1.0 } 407 | } 408 | 127 {0.319860 0.018000 0.874000 409 | { 0.878431 0.878431 0.878431 1.0 } 410 | } 411 | 128 {0.319860 0.018000 0.874000 412 | { 0.933333 0.933333 0.933333 1.0 } 413 | } 414 | 129 {0.319860 0.018000 0.910000 415 | { 1.000000 1.000000 1.000000 1.0 } 416 | } 417 | 130 {0.319860 -0.018000 0.910000 418 | { 1.000000 1.000000 1.000000 1.0 } 419 | } 420 | 131 {0.319860 -0.018000 0.874000 421 | { 0.933333 0.933333 0.933333 1.0 } 422 | } 423 | 132 {0.319860 -0.018000 0.874000 424 | { 0.933333 0.933333 0.933333 1.0 } 425 | } 426 | 133 {0.319860 -0.018000 0.910000 427 | { 1.000000 1.000000 1.000000 1.0 } 428 | } 429 | 134 {-0.319860 -0.018000 0.910000 430 | { 1.000000 1.000000 1.000000 1.0 } 431 | } 432 | 135 {-0.319860 -0.018000 0.874000 433 | { 0.905882 0.905882 0.905882 1.0 } 434 | } 435 | 136 {-0.319860 -0.018000 0.874000 436 | { 1.000000 1.000000 1.000000 1.0 } 437 | } 438 | 137 {-0.319860 -0.018000 0.910000 439 | { 0.933333 0.933333 0.933333 1.0 } 440 | } 441 | 138 {-0.319860 0.018000 0.910000 442 | { 0.721569 0.721569 0.721569 1.0 } 443 | } 444 | 139 {-0.319860 0.018000 0.874000 445 | { 0.760784 0.760784 0.760784 1.0 } 446 | } 447 | 140 {0.319860 0.018000 0.874000 448 | { 1.000000 1.000000 1.000000 1.0 } 449 | } 450 | 141 {0.319860 -0.018000 0.874000 451 | { 0.878431 0.878431 0.878431 1.0 } 452 | } 453 | 142 {-0.319860 -0.018000 0.874000 454 | { 1.000000 1.000000 1.000000 1.0 } 455 | } 456 | 143 {-0.319860 0.018000 0.874000 457 | { 0.905882 0.905882 0.905882 1.0 } 458 | } 459 | 144 {0.319860 -0.018000 0.910000 460 | { 0.933333 0.933333 0.933333 1.0 } 461 | } 462 | 145 {0.319860 0.018000 0.910000 463 | { 0.933333 0.933333 0.933333 1.0 } 464 | } 465 | 146 {-0.319860 0.018000 0.910000 466 | { 0.933333 0.933333 0.933333 1.0 } 467 | } 468 | 147 {-0.319860 -0.018000 0.910000 469 | { 1.000000 1.000000 1.000000 1.0 } 470 | } 471 | 148 {-0.355400 0.018000 0.574000 472 | { 1.000000 1.000000 1.000000 1.0 } 473 | } 474 | 149 {-0.355400 0.018000 0.610000 475 | { 0.933333 0.933333 0.933333 1.0 } 476 | } 477 | 150 {0.355400 0.018000 0.610000 478 | { 1.000000 1.000000 1.000000 1.0 } 479 | } 480 | 151 {0.355400 0.018000 0.574000 481 | { 0.878431 0.878431 0.878431 1.0 } 482 | } 483 | 152 {0.355400 0.018000 0.574000 484 | { 0.933333 0.933333 0.933333 1.0 } 485 | } 486 | 153 {0.355400 0.018000 0.610000 487 | { 1.000000 1.000000 1.000000 1.0 } 488 | } 489 | 154 {0.355400 -0.018000 0.610000 490 | { 1.000000 1.000000 1.000000 1.0 } 491 | } 492 | 155 {0.355400 -0.018000 0.574000 493 | { 0.933333 0.933333 0.933333 1.0 } 494 | } 495 | 156 {0.355400 -0.018000 0.574000 496 | { 0.933333 0.933333 0.933333 1.0 } 497 | } 498 | 157 {0.355400 -0.018000 0.610000 499 | { 1.000000 1.000000 1.000000 1.0 } 500 | } 501 | 158 {-0.355400 -0.018000 0.610000 502 | { 1.000000 1.000000 1.000000 1.0 } 503 | } 504 | 159 {-0.355400 -0.018000 0.574000 505 | { 0.905882 0.905882 0.905882 1.0 } 506 | } 507 | 160 {-0.355400 -0.018000 0.574000 508 | { 1.000000 1.000000 1.000000 1.0 } 509 | } 510 | 161 {-0.355400 -0.018000 0.610000 511 | { 0.933333 0.933333 0.933333 1.0 } 512 | } 513 | 162 {-0.355400 0.018000 0.610000 514 | { 0.721569 0.721569 0.721569 1.0 } 515 | } 516 | 163 {-0.355400 0.018000 0.574000 517 | { 0.760784 0.760784 0.760784 1.0 } 518 | } 519 | 164 {0.355400 0.018000 0.574000 520 | { 1.000000 1.000000 1.000000 1.0 } 521 | } 522 | 165 {0.355400 -0.018000 0.574000 523 | { 0.878431 0.878431 0.878431 1.0 } 524 | } 525 | 166 {-0.355400 -0.018000 0.574000 526 | { 1.000000 1.000000 1.000000 1.0 } 527 | } 528 | 167 {-0.355400 0.018000 0.574000 529 | { 0.905882 0.905882 0.905882 1.0 } 530 | } 531 | 168 {0.355400 -0.018000 0.610000 532 | { 0.933333 0.933333 0.933333 1.0 } 533 | } 534 | 169 {0.355400 0.018000 0.610000 535 | { 0.933333 0.933333 0.933333 1.0 } 536 | } 537 | 170 {-0.355400 0.018000 0.610000 538 | { 0.933333 0.933333 0.933333 1.0 } 539 | } 540 | 171 {-0.355400 -0.018000 0.610000 541 | { 1.000000 1.000000 1.000000 1.0 } 542 | }} 543 | 544 | 545 | { 546 | { wall } 547 | {0.000000 1.000000 0.000000} 548 | { 0 1 2 3 { pylon }} 549 | } 550 | { 551 | { wall } 552 | {1.000000 0.000000 0.000000} 553 | { 4 5 6 7 { pylon }} 554 | } 555 | { 556 | { wall } 557 | {-0.000000 -1.000000 0.000000} 558 | { 8 9 10 11 { pylon }} 559 | } 560 | { 561 | { wall } 562 | {-1.000000 0.000000 0.000000} 563 | { 12 13 14 15 { pylon }} 564 | } 565 | { 566 | { wall } 567 | {0.000000 0.000000 1.000000} 568 | { 16 17 18 19 { pylon }} 569 | } 570 | { 571 | { wall } 572 | {1.000000 -0.000000 0.000000} 573 | { 20 21 22 23 { pylon }} 574 | } 575 | { 576 | { wall } 577 | {0.000000 0.999718 0.023755} 578 | { 24 25 26 27 { pylon }} 579 | } 580 | { 581 | { wall } 582 | {0.000000 0.000000 1.000000} 583 | { 28 29 30 31 { pylon }} 584 | } 585 | { 586 | { wall } 587 | {-0.000000 -0.999718 0.023755} 588 | { 32 33 34 35 { pylon }} 589 | } 590 | { 591 | { wall } 592 | {-0.999856 0.000000 0.016982} 593 | { 36 37 38 39 { pylon }} 594 | } 595 | { 596 | { wall } 597 | {0.999363 -0.000000 0.035689} 598 | { 40 41 42 43 { pylon }} 599 | } 600 | { 601 | { wall } 602 | {-0.999363 0.000000 0.035689} 603 | { 44 45 46 47 { pylon }} 604 | } 605 | { 606 | { wall } 607 | {0.999856 0.000000 0.016982} 608 | { 48 49 50 51 { pylon }} 609 | } 610 | { 611 | { wall } 612 | {-1.000000 0.000000 0.000000} 613 | { 52 53 54 55 { pylon }} 614 | } 615 | { 616 | { wall } 617 | {0.000000 -0.999348 0.036110} 618 | { 56 57 58 59 { pylon }} 619 | } 620 | { 621 | { wall } 622 | {-0.000000 0.999348 0.036110} 623 | { 60 61 62 63 { pylon }} 624 | } 625 | { 626 | { wall } 627 | {0.000000 0.999348 0.036110} 628 | { 64 65 66 67 { pylon }} 629 | } 630 | { 631 | { wall } 632 | {-0.000000 -0.999348 0.036110} 633 | { 68 69 70 71 { pylon }} 634 | } 635 | { 636 | { wall } 637 | {-0.000000 -0.999348 0.036110} 638 | { 72 73 74 75 { pylon }} 639 | } 640 | { 641 | { wall } 642 | {-1.000000 0.000000 0.000000} 643 | { 76 77 78 79 { pylon }} 644 | } 645 | { 646 | { wall } 647 | {0.000000 0.999348 0.036110} 648 | { 80 81 82 83 { pylon }} 649 | } 650 | { 651 | { wall } 652 | {-0.000000 0.999348 0.036110} 653 | { 84 85 86 87 { pylon }} 654 | } 655 | { 656 | { wall } 657 | {0.000000 -0.999348 0.036110} 658 | { 88 89 90 91 { pylon }} 659 | } 660 | { 661 | { wall } 662 | {-0.999363 0.000000 0.035689} 663 | { 92 93 94 95 { pylon }} 664 | } 665 | { 666 | { wall } 667 | {0.999856 0.000000 0.016982} 668 | { 96 97 98 99 { pylon }} 669 | } 670 | { 671 | { wall } 672 | {-0.999856 0.000000 0.016982} 673 | { 100 101 102 103 { pylon }} 674 | } 675 | { 676 | { wall } 677 | {0.999363 -0.000000 0.035689} 678 | { 104 105 106 107 { pylon }} 679 | } 680 | { 681 | { wall } 682 | {0.000000 0.000000 1.000000} 683 | { 108 109 110 111 { pylon }} 684 | } 685 | { 686 | { wall } 687 | {-0.000000 -0.999718 0.023755} 688 | { 112 113 114 115 { pylon }} 689 | } 690 | { 691 | { wall } 692 | {0.000000 0.999718 0.023755} 693 | { 116 117 118 119 { pylon }} 694 | } 695 | { 696 | { wall } 697 | {1.000000 -0.000000 0.000000} 698 | { 120 121 122 123 { pylon }} 699 | } 700 | { 701 | { wall } 702 | {0.000000 1.000000 0.000000} 703 | { 124 125 126 127 { pylon }} 704 | } 705 | { 706 | { wall } 707 | {1.000000 0.000000 0.000000} 708 | { 128 129 130 131 { pylon }} 709 | } 710 | { 711 | { wall } 712 | {0.000000 -1.000000 0.000000} 713 | { 132 133 134 135 { pylon }} 714 | } 715 | { 716 | { wall } 717 | {-1.000000 0.000000 0.000000} 718 | { 136 137 138 139 { pylon }} 719 | } 720 | { 721 | { wall } 722 | {0.000000 0.000000 -1.000000} 723 | { 140 141 142 143 { pylon }} 724 | } 725 | { 726 | { wall } 727 | {0.000000 0.000000 1.000000} 728 | { 144 145 146 147 { pylon }} 729 | } 730 | { 731 | { wall } 732 | {0.000000 1.000000 0.000000} 733 | { 148 149 150 151 { pylon }} 734 | } 735 | { 736 | { wall } 737 | {1.000000 0.000000 0.000000} 738 | { 152 153 154 155 { pylon }} 739 | } 740 | { 741 | { wall } 742 | {0.000000 -1.000000 0.000000} 743 | { 156 157 158 159 { pylon }} 744 | } 745 | { 746 | { wall } 747 | {-1.000000 0.000000 0.000000} 748 | { 160 161 162 163 { pylon }} 749 | } 750 | { 751 | { wall } 752 | {0.000000 0.000000 -1.000000} 753 | { 164 165 166 167 { pylon }} 754 | } 755 | { 756 | { wall } 757 | {0.000000 0.000000 1.000000} 758 | { 168 169 170 171 { pylon }} 759 | } 760 | } 761 | --------------------------------------------------------------------------------