Project

Profile

Help

How to connect?
Download (6.34 KB) Statistics View on GitHub Reload from mirrored respository
| Branch: | Tag: | Revision:

github / src / game.py @ 05b173a7

1
# Copyright (c) 2016, LE GOFF Vincent
2
# All rights reserved.
3

    
4
# Redistribution and use in source and binary forms, with or without
5
# modification, are permitted provided that the following conditions are met:
6

    
7
# * Redistributions of source code must retain the above copyright notice, this
8
#   list of conditions and the following disclaimer.
9

    
10
# * Redistributions in binary form must reproduce the above copyright notice,
11
#   this list of conditions and the following disclaimer in the documentation
12
#   and/or other materials provided with the distribution.
13

    
14
# * Neither the name of ytranslate nor the names of its
15
#   contributors may be used to endorse or promote products derived from
16
#   this software without specific prior written permission.
17

    
18
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28

    
29
"""This file contains the GameEngine class."""
30

    
31
import os
32

    
33
from enum import Enum
34
from twisted.internet import ssl, reactor
35

    
36
from client import CocoFactory
37
from config import Settings
38
from log import logger, begin
39
from sharp.engine import SharpScript
40
from world import World, MergingMethod
41

    
42
class Level(Enum):
43

    
44
    """Enumeration for a feature level.
45

46
    Features at the top level have the value "engine". They will be
47
    common across all worlds and characters. Features are often defined
48
    at the world level (common across characters) or at the character
49
    level (specific to this character).
50

51
    For instance, look at the macros, triggers and aliases.
52

53
    """
54

    
55
    engine = 1
56
    world = 2
57
    character = 3
58
    category = 4
59

    
60

    
61
class GameEngine:
62

    
63
    """A class representing the game engine.
64

65
    An instance of this class is to be created each time the program
66
    runs.  It doesn't handle thegraphical user interface, but centralizes
67
    about anything else:  the main configuration, world configuration
68
    of different games, aliases, macros, triggers and so on.  The
69
    GUI has a direct access to the engine and can therefore access it.
70

71
    """
72

    
73
    def __init__(self, config_dir="."):
74
        self.logger = logger("")
75
        begin()
76
        self.config_dir = config_dir
77
        if config_dir != ".":
78
            self.logger.info(f"Using an alternative config directory: {config_dir}")
79

    
80
        self.settings = Settings(self, config_dir)
81
        self.sounds = True
82
        self.worlds = {}
83
        self.default_world = None
84
        self.level = Level.engine
85
        self.logger.info("CocoMUD engine started")
86

    
87
    def load(self):
88
        """Load the configuration."""
89
        self.logger.info("Loading the user's configuration...")
90
        self.settings.load()
91
        self.TTS_on = self.settings["options.TTS.on"]
92
        self.TTS_outside = self.settings["options.TTS.outside"]
93

    
94
        # For each world, set the game engine
95
        for world in self.worlds.values():
96
            world.engine = self
97

    
98
    def open(self, host, port, world, panel=None):
99
        """Connect to the specified host and port.
100

101
        This method creates and returns a 'Factory' class initialized
102
        with the specified information.  It also tries to connect a
103
        client to this factory.
104

105
        """
106
        self.logger.info("Creating a client for {host}:{port}".format(
107
                host=host, port=port))
108

    
109
        self.prepare_world(world)
110
        factory = CocoFactory(world, panel)
111

    
112
        if world.protocol.lower() == "ssl":
113
            reactor.connectSSL(host, port, factory,
114
                    ssl.ClientContextFactory())
115
        else:
116
            reactor.connectTCP(host, port, factory)
117

    
118
        return factory
119

    
120
    def open_help(self, name):
121
        """Open the selected help file in HTML format.
122

123
        This method open the browser with the appropriate file.
124
        The file is the one in the user's language, unless it cannot
125
        be found.
126

127
        """
128
        lang = self.settings.get_language()
129
        filename = name + ".html"
130
        path = os.path.join(self.config_dir, "doc", lang, filename)
131
        if os.path.exists(path):
132
            self.logger.debug("Open the help file for {} (lang={})".format(
133
                    name, lang))
134
            os.startfile(path)
135
            return
136

    
137
        # Try English
138
        path = os.path.join(self.config_dir, "doc", "en", filename)
139
        if os.path.exists(path):
140
            self.logger.debug("Open the help file for {} (lang=en)".format(
141
                    name))
142
            os.startfile(path)
143
            return
144

    
145
        # Neither worked
146
        self.logger.warning("The documentation for the {} help file " \
147
                "cannot be found, either using lang={} or lang=en".format(
148
                name, lang))
149

    
150
    def get_world(self, name):
151
        """Return the selected world either by its name or location."""
152
        name = name.lower()
153
        for world in self.worlds.values():
154
            if world.name.lower() == name:
155
                return world
156
            elif world.location == name:
157
                return world
158

    
159
        return None
160

    
161
    def create_world(self, name):
162
        """Create a world."""
163
        world = World(name.lower())
164
        world.engine = self
165
        return world
166

    
167
    def prepare_world(self, world, merge=None):
168
        """Prepare the world, creating appropriate values."""
169
        if not world.sharp_engine:
170
            sharp_engine = SharpScript(self, None, world)
171
            world.sharp_engine = sharp_engine
172

    
173
        if merge is not None:
174
            if merge == "ignore":
175
                world.merging = MergingMethod.ignore
176
            elif merge == "replace":
177
                world.merging = MergingMethod.replace
178
            else:
179
                raise ValueError("unkwno merging method: {}".format(
180
                        merge))
181

    
182
    def stop(self):
183
        """Stop the game engine and close the sessions."""
184
        reactor.stop()
(10-10/20)