Project

Profile

Help

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

github / src / game.py @ master

1
# Copyright (c) 2016-2020, 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
        self.redirect_message = None
94

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

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

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

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

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

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

    
119
        return factory
120

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

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

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

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

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

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

    
160
        return None
161

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

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

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

    
183
    def stop(self):
184
        """Stop the game engine and close the sessions."""
185
        reactor.stop()
(12-12/23)