~widelands-dev/widelands/trunk

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
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
/*
 * Copyright (C) 2002-2025 by the Widelands Development Team
 *
 * This program 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 2
 * of the License, or (at your option) any later version.
 *
 * This program 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/>.
 *
 */

#ifndef WL_LOGIC_MAP_OBJECTS_IMMOVABLE_H
#define WL_LOGIC_MAP_OBJECTS_IMMOVABLE_H

#include <atomic>
#include <memory>

#include "base/macros.h"
#include "logic/map_objects/buildcost.h"
#include "logic/map_objects/info_to_draw.h"
#include "logic/map_objects/map_object.h"
#include "logic/map_objects/tribes/wareworker.h"
#include "logic/widelands_geometry.h"
#include "notifications/note_ids.h"
#include "notifications/notifications.h"

namespace Widelands {

class Building;
class BuildingDescr;
class Economy;
class Immovable;
class Map;
class TerrainAffinity;
class Worker;
struct Flag;
struct ImmovableAction;
struct ImmovableActionData;
struct ImmovableProgram;
struct PlayerImmovable;

constexpr float kImmovableSilhouetteOpacity = 0.3f;

struct NoteImmovable {
	CAN_BE_SENT_AS_NOTE(NoteId::Immovable)

	PlayerImmovable* pi;

	enum class Ownership { LOST, GAINED };
	Ownership ownership;

	NoteImmovable(PlayerImmovable* const init_pi, Ownership const init_ownership)
	   : pi(init_pi), ownership(init_ownership) {
	}
};

/**
 * BaseImmovable is the base for all non-moving objects (immovables such as
 * trees, buildings, flags, roads).
 *
 * The Immovable's size influences building capabilities around it.
 * If size is NONE, the immovable can simply be removed by placing something on
 * it (this is usually true for decorations).
 *
 * For more information, see the Map::recalc_* functions.
 */
struct BaseImmovable : public MapObject {
	enum Size {
		NONE = 0,  ///< not robust (i.e. removable by building something over it)
		SMALL,     ///< small building or robust map element, including trees
		MEDIUM,    ///< medium size building
		BIG        ///< big building
	};

	explicit BaseImmovable(const MapObjectDescr&);

	virtual int32_t get_size() const = 0;
	virtual bool get_passable() const = 0;

	virtual void set_owner(Player* player);

	using PositionList = std::vector<Coords>;
	/**
	 * Return all coordinates occupied by this Immovable. We gurantee that the
	 * list always contains one entry and the first one is the main position
	 * if one can be chosen as main.
	 */
	virtual PositionList get_positions(const EditorGameBase&) const = 0;

	// Draw this immovable onto 'dst' choosing the frame appropriate for
	// 'gametime'. 'info_to_draw' decides if census and statistics are written too.
	// The 'coords_to_draw' are passed one to give objects that occupy multiple
	// fields a way to only draw themselves once. The 'point_on_dst' determines
	// the point for the hotspot of the animation and 'scale' determines how big
	// the immovable will be plotted.
	virtual void draw(const Time& gametime,
	                  InfoToDraw info_to_draw,
	                  const Vector2f& point_on_dst,
	                  const Coords& coords,
	                  float scale,
	                  RenderTarget* dst) = 0;

	static int32_t string_to_size(const std::string& size);
	static std::string size_to_string(int32_t size);

protected:
	void set_position(EditorGameBase&, const Coords&);
	void unset_position(EditorGameBase&, const Coords&);
};

/**
 * Immovable represents a standard immovable such as trees or rocks.
 */
class ImmovableDescr : public MapObjectDescr {
	friend struct ImmovableProgram;

public:
	using Programs = std::map<std::string, ImmovableProgram*>;

	/// Common constructor for tribes and world.
	ImmovableDescr(const std::string& init_descname,
	               const LuaTable&,
	               const std::vector<std::string>& attribs,
	               Descriptions& descriptions);
	~ImmovableDescr() override;

	[[nodiscard]] int32_t get_size() const {
		return size_;
	}
	[[nodiscard]] ImmovableProgram const* get_program(const std::string&) const;

	Immovable& create(EditorGameBase&,
	                  const Coords&,
	                  const Widelands::BuildingDescr* former_building_descr) const;

	[[nodiscard]] const Buildcost& buildcost() const {
		return buildcost_;
	}

	// A basic localized name for the immovable, used by trees
	[[nodiscard]] const std::string& species() const {
		return species_;
	}

	// Every immovable that can 'grow' needs to have terrain affinity defined,
	// all others do not. Returns true if this one has it defined.
	[[nodiscard]] bool has_terrain_affinity() const;

	// Returns the terrain affinity. If !has_terrain_affinity() this will return
	// an undefined value.
	[[nodiscard]] const TerrainAffinity& terrain_affinity() const;

	// Map object names that the immovable can transform/grow into
	[[nodiscard]] const std::set<std::pair<MapObjectType, std::string>>& becomes() const {
		return becomes_;
	}

	// A set of all productionsites that gather this immovable or any of its future types
	[[nodiscard]] const std::set<std::string> collected_by() const {
		return collected_by_;
	}
	void add_collected_by(const Descriptions& descriptions,
	                      const std::string& prodsite,
	                      std::set<const ImmovableDescr*> recursion_protect = {});

	void register_immovable_relation(const std::string&, const std::string&);
	void add_became_from(const Descriptions& descriptions, const std::string&);

protected:
	Descriptions& descriptions_;
	int32_t size_{BaseImmovable::NONE};
	Programs programs_;

	/// Buildcost for externally constructible immovables (for ship construction)
	/// \see ActConstruct
	Buildcost buildcost_;

	std::string species_;
	std::set<std::pair<MapObjectType, std::string>> becomes_;
	std::set<std::string> became_from_;  // immovables that turn into this one
	std::set<std::string> collected_by_;

private:
	// Adds a default program if none was defined.
	void make_sure_default_program_is_there();

	std::unique_ptr<TerrainAffinity> terrain_affinity_;
	DISALLOW_COPY_AND_ASSIGN(ImmovableDescr);
};

class Immovable : public BaseImmovable {
	friend class ImmovableDescr;
	friend struct ImmovableProgram;
	friend class Map;

	MO_DESCR(ImmovableDescr)

public:
	/// If this immovable was created by a building, 'former_building_descr' can be set in order to
	/// display information about it.
	explicit Immovable(const ImmovableDescr&,
	                   const Widelands::BuildingDescr* former_building_descr = nullptr);
	~Immovable() override = default;

	Coords get_position() const {
		return position_;
	}
	PositionList get_positions(const EditorGameBase&) const override;

	int32_t get_size() const override;
	bool get_passable() const override;
	void start_animation(const EditorGameBase&, uint32_t anim);

	void program_step(Game& game, const Duration& delay = Duration(1)) {
		assert(delay.is_valid());
		if (delay.get() > 0) {
			program_step_ = schedule_act(game, delay);
		}
		increment_program_pointer();
	}

	bool init(EditorGameBase&) override;
	void cleanup(EditorGameBase&) override;
	void act(Game&, uint32_t data) override;
	void draw(const Time& gametime,
	          InfoToDraw info_to_draw,
	          const Vector2f& point_on_dst,
	          const Coords& coords,
	          float scale,
	          RenderTarget* dst) override;

	void switch_program(Game& game, const std::string& program_name);
	bool construct_ware(Game& game, DescriptionIndex index);
	bool construct_remaining_buildcost(Buildcost* buildcost);

	void set_action_data(ImmovableActionData* data);
	template <typename T> T* get_action_data() {
		if (action_data_ == nullptr) {
			return nullptr;
		}
		if (T* data = dynamic_cast<T*>(action_data_.get()); data != nullptr) {
			return data;
		}
		set_action_data(nullptr);
		return nullptr;
	}

	void delay_growth(Duration ms) {
		growth_delay_ += ms;
	}
	bool apply_growth_delay(Game&);

	bool is_marked_for_removal(PlayerNumber) const;
	void set_marked_for_removal(PlayerNumber, bool mark);
	const std::set<PlayerNumber>& get_marked_for_removal() const {
		return marked_for_removal_;
	}

protected:
	// The building type that created this immovable, if any.
	const BuildingDescr* former_building_descr_;

	Coords position_;

	std::atomic<uint32_t> anim_{0U};
	Time animstart_{0U};

	const ImmovableProgram* program_{nullptr};
	uint32_t program_ptr_{0U};  ///< index of next instruction to execute

	// Whether a worker was told to remove this object ASAP.
	// A set of all players who want this object gone.
	std::set<PlayerNumber> marked_for_removal_;

/* GCC 4.0 has problems with friend declarations: It doesn't allow
 * substructures of friend classes private access but we rely on this behaviour
 * for ImmovableProgram::ActConstruct. As a dirty workaround, we make the
 * following variables public for this versions but keep the protected for
 * other GCC versions.
 * See the related bug lp:688832.
 */
#if (__GNUC__ == 4) && (__GNUC_MINOR__ == 0)
public:
	uint32_t anim_construction_total_{0U};
	uint32_t anim_construction_done_{0U};
	Time program_step_{0U};

protected:
#else
	std::atomic<uint32_t> anim_construction_total_{0U};
	std::atomic<uint32_t> anim_construction_done_{0U};
	Time program_step_{0U};  ///< time of next step
#endif

	/**
	 * Private persistent data for the currently active program action.
	 *
	 * \warning Use get_action_data to access this.
	 */
	std::unique_ptr<ImmovableActionData> action_data_;

private:
	Duration growth_delay_{0U};

	// Load/save support
protected:
	struct Loader : public BaseImmovable::Loader {
		void load(FileRead&, uint8_t packet_version);
		void load_pointers() override;
		void load_finish() override;
	};

public:
	// TODO(unknown): Remove as soon as we fully support the new system
	bool has_new_save_support() override {
		return true;
	}

	void save(EditorGameBase&, MapObjectSaver&, FileWrite&) override;
	static MapObject::Loader* load(EditorGameBase&, MapObjectLoader&, FileRead&);

private:
	/// If this immovable was created by a building, this can be set in order to display information
	/// about it. If this is a player immovable, you will need to set the owner first.
	void set_former_building(const BuildingDescr& building);

	void increment_program_pointer();
	void draw_construction(const Time& gametime,
	                       InfoToDraw info_to_draw,
	                       const Vector2f& point_on_dst,
	                       const Widelands::Coords& coords,
	                       float scale,
	                       RenderTarget* dst);
};

/**
 * PlayerImmovable is an immovable owned by a player that belongs to an economy:
 * building, flag or road
 *
 * A PlayerImmovable can also house a number of workers, which are automatically
 * turned into fugitives when the immovable is destroyed, and their economy is
 * also adjusted automatically.
 */
struct PlayerImmovable : public BaseImmovable {
	explicit PlayerImmovable(const MapObjectDescr&);
	~PlayerImmovable() override;

	Economy* get_economy(WareWorker type) const {
		return type == wwWARE ? ware_economy_ : worker_economy_;
	}
	Economy& economy(WareWorker type) const {
		return *(type == wwWARE ? ware_economy_ : worker_economy_);
	}

	virtual Flag& base_flag() = 0;
	virtual const Flag& base_flag() const = 0;

	virtual void set_economy(Economy*, WareWorker);

	virtual void add_worker(Worker&);
	virtual void remove_worker(Worker&);

	virtual void kickout_worker_from_queue(Game& game, Worker& worker);

	using Workers = std::vector<Worker*>;

	/**
	 * \return a list of workers that are currently located at this
	 * immovable. This is not the same as the list of production
	 * workers returned by \ref ProductionSite::working_positions
	 */
	const Workers& get_workers() const {
		return workers_;
	}

	void log_general_info(const EditorGameBase&) const override;

	/**
	 * These functions are called when a ware or worker arrives at
	 * this immovable as the destination of a transfer that does not
	 * have an associated request.
	 *
	 * At the time of this writing, this happens only for warehouses.
	 *
	 * \note This is independent of the \ref add_worker / \ref remove_worker
	 * functionality, which has to do with setting up locations.
	 */
	/*@{*/
	virtual void receive_ware(Game&, DescriptionIndex ware);
	virtual void receive_worker(Game&, Worker& worker);
	virtual void inputqueue_max_fill_changed() {
	}
	/*@}*/

	void set_owner(Player*) override;

protected:
	bool init(EditorGameBase&) override;
	void cleanup(EditorGameBase&) override;

private:
	Economy* ware_economy_{nullptr};
	Economy* worker_economy_{nullptr};

	Workers workers_;

	// load/save support
protected:
	struct Loader : BaseImmovable::Loader {
		Loader() = default;

		void load(FileRead&);
	};

public:
	void save(EditorGameBase&, MapObjectSaver&, FileWrite&) override;
};
}  // namespace Widelands

#endif  // end of include guard: WL_LOGIC_MAP_OBJECTS_IMMOVABLE_H