1 // -*- Mode: C++; tab-width:2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi:tw=80:et:ts=2:sts=2
3 //
4 // -----------------------------------------------------------------------
5 //
6 // This file is part of RLVM, a RealLive virtual machine clone.
7 //
8 // -----------------------------------------------------------------------
9 //
10 // Copyright (C) 2006, 2007 Elliot Glaysher
11 //
12 // This program is free software; you can redistribute it and/or modify
13 // it under the terms of the GNU General Public License as published by
14 // the Free Software Foundation; either version 3 of the License, or
15 // (at your option) any later version.
16 //
17 // This program is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with this program; if not, write to the Free Software
24 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 //
26 // -----------------------------------------------------------------------
27 
28 #ifndef SRC_SYSTEMS_BASE_EVENT_SYSTEM_H_
29 #define SRC_SYSTEMS_BASE_EVENT_SYSTEM_H_
30 
31 #include <functional>
32 #include <memory>
33 #include <queue>
34 #include <set>
35 
36 #include "systems/base/rltimer.h"
37 #include "systems/base/rect.h"
38 
39 class RLMachine;
40 
41 class Gameexe;
42 class FrameCounter;
43 class EventListener;
44 
45 // -----------------------------------------------------------------------
46 
47 struct EventSystemGlobals {
48   EventSystemGlobals();
49   explicit EventSystemGlobals(Gameexe& gexe);
50 
51   // The two generic values that the reallive game has control over
52   // with the Generic1 and Generic2 functions.
53   int generic1_;
54   int generic2_;
55 
56   // boost::serialization support
57   template <class Archive>
serializeEventSystemGlobals58   void serialize(Archive& ar, const unsigned int version) {
59     ar& generic1_ & generic2_;
60   }
61 };
62 
63 // -----------------------------------------------------------------------
64 
65 // Generalization of an event system. Reallive's event model is a bit
66 // weird; interpreted code will check the state of certain keyboard
67 // modifiers, with functions such as CtrlPressed() or ShiftPressed().
68 //
69 // So what's the solution? Have two different event systems side by
70 // side. One is exposed to Reallive and mimics what RealLive bytecode
71 // expects. The other is based on event handlers and is sane.
72 class EventSystem {
73  public:
74   explicit EventSystem(Gameexe& gexe);
75   virtual ~EventSystem();
76 
globals()77   EventSystemGlobals& globals() { return globals_; }
78 
79   RLTimer& GetTimer(int layer, int counter);
80 
81   // Frame Counters
82   //
83   // "Frame counters are designed to make it simple to ensure events happen at a
84   // constant speed regardless of the host system's specifications. Once a frame
85   // counter has been initialized, it will count from one arbitrary number to
86   // another, over a given length of time. The counter can be queried at any
87   // point to get its current value."
88   //
89   // Valid values for layer are 0 and 1. Valid values for frame_counter are 0
90   // through 255.
91   void SetFrameCounter(int layer, int frame_counter, FrameCounter* counter);
92   FrameCounter& GetFrameCounter(int layer, int frame_counter);
93   bool FrameCounterExists(int layer, int frame_counter);
94 
95   // Keyboard and Mouse Input (Event Listener style)
96   //
97   // rlvm event handling works by registering objects that received input
98   // notifications from the EventSystem. These objects are EventListeners,
99   // which passively listen for input and have a first chance grab at any click
100   // or keypress.
101   //
102   // If no EventListener claims the event, then we try to reinterpret the top
103   // of the RLMachine callstack as an EventListener. Otherwise, the events
104   // are handled RealLive style (see below).
105   void AddMouseListener(EventListener* listener);
106   void RemoveMouseListener(EventListener* listener);
107 
108   // Generic values
109   //
110   // These values should have, from the beginning, been placed somewhere
111   // else. They will remain here till the end of time for save game file
112   // compatibility, though.
113   //
114   // "RealLive provides two generic settings to permit games using the standard
115   // system command menu to include custom options in it. The meaning of each
116   // generic flag is left up to the programmer. Valid values are 0 to 4."
set_generic1(const int in)117   void set_generic1(const int in) { globals_.generic1_ = in; }
generic1()118   int generic1() const { return globals_.generic1_; }
set_generic2(const int in)119   void set_generic2(const int in) { globals_.generic2_ = in; }
generic2()120   int generic2() const { return globals_.generic2_; }
121 
122   // Run once per cycle through the game loop to process events.
123   virtual void ExecuteEventSystem(RLMachine& machine) = 0;
124 
125   // Returns the number of milliseconds since the program
126   // started. Used for timing things.
127   virtual unsigned int GetTicks() const = 0;
128 
129   // Idles the program for a certain amount of time in milliseconds.
130   virtual void Wait(unsigned int milliseconds) const = 0;
131 
132   // Keyboard and Mouse Input (Reallive style)
133   //
134   // RealLive applications poll for input, with all the problems that sort of
135   // event handling has. We therefore provide an interface for polling.
136   //
137   // Don't use it. This interface is provided for RealLive
138   // bytecode. EventListeners should be used within rlvm code, instead.
139 
140   // Returns whether shift is currently pressed.
141   virtual bool ShiftPressed() const = 0;
142 
143   // Returns whether ctrl has been pressed since the last invocation of
144   // ctrlPresesd().
145   virtual bool CtrlPressed() const = 0;
146 
147   // Returns the current cursor hotspot.
148   virtual Point GetCursorPos() = 0;
149 
150   // Gets the location of the mouse cursor and the button states.
151   //
152   // The following values are used to indicate a button's status:
153   // - 0 if unpressed
154   // - 1 if being pressed
155   // - 2 if pressed and released.
156   virtual void GetCursorPos(Point& position, int& button1, int& button2) = 0;
157 
158   // Resets the state of the mouse buttons.
159   virtual void FlushMouseClicks() = 0;
160 
161   // Returns the time in ticks of the last mouse movement.
162   virtual unsigned int TimeOfLastMouseMove() = 0;
163 
164   // Testing
165   //
166   // Allows test systems like lua_rlvm to inject mouse movement and clicks.
167   virtual void InjectMouseMovement(RLMachine& machine, const Point& loc) = 0;
168   virtual void InjectMouseDown(RLMachine& machine) = 0;
169   virtual void InjectMouseUp(RLMachine& machine) = 0;
170 
171  protected:
172   typedef std::set<EventListener*> EventListeners;
173 
listeners_begin()174   EventListeners::iterator listeners_begin() {
175     return event_listeners_.begin();
176   }
listeners_end()177   EventListeners::iterator listeners_end() { return event_listeners_.end(); }
178 
179   // Calls a EventListener member function on all event listeners, and then
180   // event handlers, stopping when an object says they handled it.
181   void DispatchEvent(RLMachine& machine,
182                      const std::function<bool(EventListener&)>& event);
183   void BroadcastEvent(RLMachine& machine,
184                       const std::function<void(EventListener&)>& event);
185 
186  private:
187   // Helper function that verifies input
188   void CheckLayerAndCounter(int layer, int counter);
189 
190   std::unique_ptr<FrameCounter> frame_counters_[255][2];
191   RLTimer timers_[255][2];
192 
193   EventListeners event_listeners_;
194 
195   EventSystemGlobals globals_;
196 };
197 
198 #endif  // SRC_SYSTEMS_BASE_EVENT_SYSTEM_H_
199