File: Engine.h

package info (click to toggle)
endless-sky 0.10.16-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 414,608 kB
  • sloc: cpp: 73,435; python: 893; xml: 666; sh: 271; makefile: 28
file content (332 lines) | stat: -rw-r--r-- 9,529 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
/* Engine.h
Copyright (c) 2014 by Michael Zahniser

Endless Sky is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later version.

Endless Sky is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program. If not, see <https://www.gnu.org/licenses/>.
*/

#pragma once

#include "AI.h"
#include "AlertLabel.h"
#include "AmmoDisplay.h"
#include "AsteroidField.h"
#include "shader/BatchDrawList.h"
#include "Camera.h"
#include "CollisionSet.h"
#include "Color.h"
#include "Command.h"
#include "shader/DrawList.h"
#include "EscortDisplay.h"
#include "Information.h"
#include "MiniMap.h"
#include "PlanetLabel.h"
#include "Point.h"
#include "Preferences.h"
#include "Projectile.h"
#include "Radar.h"
#include "Rectangle.h"
#include "TaskQueue.h"

#include <condition_variable>
#include <list>
#include <map>
#include <memory>
#include <utility>
#include <vector>

class Flotsam;
class Government;
class NPC;
class Outfit;
class PlayerInfo;
class Ship;
class ShipEvent;
class Sprite;
class Swizzle;
class Visual;
class Weather;


// Class representing the game engine: its job is to track all of the objects in
// the game, and to move them, step by step. All the motion and collision
// calculations are handled in a separate thread so that the graphics thread is
// free to just work on drawing things; this means that the drawn state of the
// game is always one step (1/60 second) behind what is being calculated. This
// lag is too small to be detectable and means that the game can better handle
// situations where there are many objects on screen at once.
class Engine {
public:
	explicit Engine(PlayerInfo &player);
	~Engine();

	// Place all the player's ships, and "enter" the system the player is in.
	void Place();
	// Place NPCs spawned by a mission that offers when the player is not landed.
	void Place(const std::list<NPC> &npcs, const std::shared_ptr<Ship> &flagship = nullptr);

	// Wait for the previous calculations (if any) to be done.
	void Wait();
	// Perform all the work that can only be done while the calculation thread
	// is paused (for thread safety reasons).
	void Step(bool isActive);
	// Begin the next step of calculations.
	void Go();
	// Whether the player has the game paused.
	bool IsPaused() const;

	// Give a command on behalf of the player, used for integration tests.
	void GiveCommand(const Command &command);

	// Get any special events that happened in this step.
	// MainPanel::Step will clear this list.
	std::list<ShipEvent> &Events();

	// Draw a frame.
	void Draw() const;

	// Select the object the player clicked on.
	void Click(const Point &from, const Point &to, bool hasShift, bool hasControl);
	void RClick(const Point &point);
	void SelectGroup(int group, bool hasShift, bool hasControl);

	// Break targeting on all projectiles between the player and the given
	// government; gov projectiles stop targeting the player and player's
	// projectiles stop targeting gov.
	void BreakTargeting(const Government *gov);


private:
	class Outline {
	public:
		Outline(const Sprite *sprite, const Point &position, const Point &unit,
			const float frame, const Color &color)
			: sprite(sprite), position(position), unit(unit), frame(frame), color(color)
		{
		}

		const Sprite *sprite;
		const Point position;
		const Point unit;
		const float frame;
		const Color color;
	};

	class Target {
	public:
		Point center;
		Angle angle;
		double radius;
		const Color &color;
		int count;
	};

	class Status {
	public:
		enum class Type {
			FLAGSHIP,
			FRIENDLY,
			HOSTILE,
			NEUTRAL,
			SCAN,
			SCAN_OUT_OF_RANGE,
			COUNT // This item should always be the last in this list.
		};

	public:
		constexpr Status(const Point &position, double outer, double inner,
			double disabled, double radius, Type type, float alpha, double angle = 0.)
			: position(position), outer(outer), inner(inner),
				disabled(disabled), radius(radius), type(type), alpha(alpha), angle(angle) {}

		Point position;
		double outer;
		double inner;
		double disabled;
		double radius;
		Type type;
		float alpha;
		double angle;
	};

	class TurretOverlay {
	public:
		Point position;
		Point angle;
		double scale;
		bool isBlind;
	};

	class Zoom {
	public:
		constexpr Zoom() : base(0.) {}
		explicit constexpr Zoom(double zoom) : base(zoom) {}

		constexpr operator double() const { return base * modifier; }

		double base;
		double modifier = 1.;
	};


private:
	void EnterSystem();

	void CalculateStep();
	// Calculate things that require the engine not to be paused.
	void CalculateUnpaused(const Ship *flagship, const System *playerSystem);

	void MoveShip(const std::shared_ptr<Ship> &ship);

	void SpawnFleets();
	void SpawnPersons();
	void GenerateWeather();
	void SendHails();
	void HandleKeyboardInputs();
	void HandleMouseClicks();
	void HandleMouseInput(Command &activeCommands);

	void FillCollisionSets();

	void DoCollisions(Projectile &projectile);
	void DoWeather(Weather &weather);
	void DoCollection(Flotsam &flotsam);
	void DoScanning(const std::shared_ptr<Ship> &ship);

	void FillRadar();

	void DrawShipSprites(const Ship &ship);

	void DoGrudge(const std::shared_ptr<Ship> &target, const Government *attacker);

	void CreateStatusOverlays();
	void EmplaceStatusOverlay(const std::shared_ptr<Ship> &ship, Preferences::OverlayState overlaySetting,
		Status::Type type, double cloak);


private:
	PlayerInfo &player;

	std::list<std::shared_ptr<Ship>> ships;
	std::vector<Projectile> projectiles;
	std::vector<Weather> activeWeather;
	std::list<std::shared_ptr<Flotsam>> flotsam;
	std::vector<Visual> visuals;
	AsteroidField asteroids;

	// New objects created within the latest step:
	std::list<std::shared_ptr<Ship>> newShips;
	std::vector<Projectile> newProjectiles;
	std::list<std::shared_ptr<Flotsam>> newFlotsam;
	std::vector<Visual> newVisuals;

	// Track which ships currently have anti-missiles or
	// tractor beams ready to fire.
	std::vector<Ship *> hasAntiMissile;
	std::vector<Ship *> hasTractorBeam;

	AI ai;

	TaskQueue queue;

	// ES uses a technique called double buffering to calculate the next frame and render the current one simultaneously.
	// To facilitate this, it uses two buffers for each list of things to draw - one for the next frame's calculations and
	// one for rendering the current frame. A little synchronization is required to prevent mutable references to the
	// currently rendering buffer.
	size_t currentCalcBuffer = 0;
	size_t currentDrawBuffer = 0;
	DrawList draw[2];
	BatchDrawList batchDraw[2];
	Radar radar[2];

	bool wasActive = false;
	bool isMouseHoldEnabled = false;
	bool isMouseTurningEnabled = false;

	// Viewport camera.
	Camera camera;
	// Other information to display.
	Information info;
	std::vector<Target> targets;
	Point targetVector;
	Point targetUnit;
	const Swizzle *targetSwizzle = nullptr;
	// Represents the state of the currently targeted ship when it was last seen,
	// so the target display does not show updates to its state the player should not be aware of.
	int lastTargetType = 0;
	EscortDisplay escorts;
	AmmoDisplay ammoDisplay;
	std::vector<Outline> outlines;
	std::vector<Status> statuses;
	std::vector<PlanetLabel> labels;
	std::vector<AlertLabel> missileLabels;
	std::vector<TurretOverlay> turretOverlays;
	std::vector<std::pair<const Outfit *, int>> ammo;
	// Flagship's hyperspace percentage converted to a [0, 1] double.
	double hyperspacePercentage = 0.;

	MiniMap minimap;

	int step = 0;
	// Count steps for UI elements separately, because they shouldn't be affected by pausing.
	mutable int uiStep = 0;
	bool timePaused = false;

	std::list<ShipEvent> eventQueue;
	std::list<ShipEvent> events;
	// Keep track of who has asked for help in fighting whom.
	std::map<const Government *, std::weak_ptr<const Ship>> grudge;
	int grudgeTime = 0;

	CollisionSet shipCollisions;

	int alarmTime = 0;
	double flash = 0.;
	bool doFlash = false;
	bool doEnterLabels = false;
	bool doEnter = false;
	bool hadHostiles = false;

	// A timer preventing out-of-ammo sounds from triggering constantly every frame when the fire key is held.
	std::vector<int> emptySoundsTimer;

	// Commands that are currently active (and not yet handled). This is a combination
	// of keyboard and mouse commands (and any other available input device).
	Command activeCommands;
	// Keyboard commands that were active in the previous step.
	Command keyHeld;
	// Pressing "land" or "board" rapidly toggles targets; pressing it once re-engages landing or boarding.
	int keyInterval = 0;

	// Inputs received from a mouse or other pointer device.
	bool doClickNextStep = false;
	bool doClick = false;
	bool hasShift = false;
	bool hasControl = false;
	bool isRightClick = false;
	bool isRadarClick = false;
	Point clickPoint;
	Rectangle uiClickBox;
	Rectangle clickBox;
	int groupSelect = -1;

	// Set of asteroids scanned in the current system.
	std::set<std::string> asteroidsScanned;
	bool isAsteroidCatalogComplete = false;

	Zoom zoom;
	// Tracks the next zoom change so that objects aren't drawn at different zooms in a single frame.
	Zoom nextZoom;

	double load = 0.;
	int loadCount = 0;
	double loadSum = 0.;
};