1 /** @file system.h  Action Code Script (ACS) system.
2  *
3  * @authors Copyright © 2003-2017 Jaakko Keränen <jaakko.keranen@iki.fi>
4  * @authors Copyright © 2005-2015 Daniel Swanson <danij@dengine.net>
5  * @authors Copyright © 1999 Activision
6  *
7  * @par License
8  * GPL: http://www.gnu.org/licenses/gpl.html
9  *
10  * <small>This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by the
12  * Free Software Foundation; either version 2 of the License, or (at your
13  * option) any later version. This program is distributed in the hope that it
14  * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
15  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
16  * Public License for more details. You should have received a copy of the GNU
17  * General Public License along with this program; if not, write to the Free
18  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19  * 02110-1301 USA</small>
20  */
21 
22 #ifndef LIBCOMMON_ACS_SYSTEM_H
23 #define LIBCOMMON_ACS_SYSTEM_H
24 
25 #include "common.h"
26 #include <array>
27 #include <functional>
28 #include <de/Error>
29 #include <de/Block>
30 #include <de/Reader>
31 #include <de/Writer>
32 #include <doomsday/uri.h>
33 #include "acs/module.h"
34 #include "acs/script.h"
35 #include "mapstatereader.h"
36 #include "mapstatewriter.h"
37 
38 namespace acs {
39 
40 /**
41  * Action Code Script (ACS) system.
42  *
43  * @ingroup playsim
44  */
45 class System
46 {
47 public:  /// @todo make private:
48     std::array<de::dint32, 32> mapVars;
49     std::array<de::dint32, 64> worldVars;
50 
51 public:
52     /// Required/referenced script is missing. @ingroup errors
53     DENG2_ERROR(MissingScriptError);
54 
55 public:
56     System();
57 
58     /**
59      * To be called when a new game session begins to reset the system. All
60      * global scripting variables are discarded and deferred-tasks purged.
61      */
62     void reset();
63 
64 public:  // Modules: -----------------------------------------------------------
65 
66     /**
67      * Discard the currently loaded ACS code module and attempt to load the module
68      * associated with the given @a mapUri reference.
69      */
70     void loadModuleForMap(de::Uri const &mapUri);
71 
72     /**
73      * Provides readonly access to the currently loaded bytecode module.
74      */
75     Module const &module() const;
76 
77 public:  // Scripts: -----------------------------------------------------------
78 
79     /**
80      * Returns the total number of script entry points in the loaded bytecode.
81      */
82     int scriptCount() const;
83 
84     /**
85      * Returns @c true iff @a scriptNumber is a known entry point.
86      */
87     bool hasScript(int scriptNumber) const;
88 
89     /**
90      * Lookup the Script info for the given @a scriptNumber.
91      */
92     Script &script(int scriptNumber) const;
93 
94     /**
95      * Iterate through the Scripts of the loaded bytecode.
96      *
97      * @param func  Callback to make for each Script.
98      */
99     de::LoopResult forAllScripts(std::function<de::LoopResult (Script &)> func) const;
100 
101     /**
102      * Defer a script start task until the identified map is next current.
103      *
104      * @param mapUri  Unique identifier of the map on which to start the script.
105      *
106      * @return  @c true iff a script was newly started (or deferred).
107      */
108     bool deferScriptStart(de::Uri const &mapUri, int scriptNumber, Script::Args const &args);
109 
110 public:  // (De)serialization: -------------------------------------------------
111 
112     de::Block serializeWorldState() const;
113     void readWorldState(de::Reader &from);
114 
115     void writeMapState(MapStateWriter *msw) const;
116     void readMapState(MapStateReader *msr);
117 
118 public:  /// @todo make private: -----------------------------------------------
119 
120     /**
121      * To be called when the current map changes to activate any deferred scripts
122      * which should now begin/resume.
123      */
124     void runDeferredTasks(de::Uri const &mapUri);
125 
126     /**
127      * Start all scripts flagged to begin immediately (but allow a 1 second delay
128      * for map initialization to complete).
129      *
130      * @todo Run deferred tasks at this time also?
131      */
132     void worldSystemMapChanged();
133 
134 public:
135     /**
136      * Register the console commands and variables of this module.
137      */
138     static void consoleRegister();
139 
140 private:
141     DENG2_PRIVATE(d)
142 };
143 
144 }  // namespace acs
145 
146 #endif  // LIBCOMMON_ACS_SYSTEM_H
147