File: field.h

package info (click to toggle)
widelands 1:19+repack-3
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 370,608 kB
  • ctags: 20,609
  • sloc: cpp: 108,404; ansic: 18,695; python: 5,155; sh: 487; xml: 460; makefile: 233
file content (263 lines) | stat: -rw-r--r-- 8,021 bytes parent folder | download | duplicates (2)
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
/*
 * Copyright (C) 2002-2004, 2006-2011 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, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 */

#ifndef WL_LOGIC_FIELD_H
#define WL_LOGIC_FIELD_H

#include <cassert>
#include <limits>

#include "logic/constants.h"
#include "logic/nodecaps.h"
#include "logic/roadtype.h"
#include "logic/widelands.h"
#include "logic/widelands_geometry.h"

namespace Widelands {

#define MAX_FIELD_HEIGHT 60
#define MAX_FIELD_HEIGHT_DIFF 5

// Think, if we shouldn't call for each field a new() in map::set_size
// and a delete
// Okay, as it stands now, Field can be safely memset()ed to 0.
//
// No. In fact, you should view Field more as a plain old structure rather than
// a class. If you think of Fields as a class you get into a whole lot of
// problems (like the 6 neighbour field pointers we used to have). - Nicolai
// Probably it would be better to make Field a struct, rather than a class
// (things wouldn't change much, it's just a question of style and code
// understanding)
// Making it a struct doesn't add anything. struct is used interchangeably with
// class all around the code

class Bob;
class TerrainDescription;
struct BaseImmovable;

// Field is used so often, make sure it is as small as possible.
#pragma pack(push, 1)
/// a field like it is represented in the game
// TODO(unknown): This is all one evil hack :(
struct Field {
	friend class Map;
	friend class Bob;
	friend struct BaseImmovable;

	enum BuildhelpIndex {
		Buildhelp_Flag = 0,
		Buildhelp_Small = 1,
		Buildhelp_Medium = 2,
		Buildhelp_Big = 3,
		Buildhelp_Mine = 4,
		Buildhelp_Port = 5,
		Buildhelp_None = 6
	};

	using Height = uint8_t;
	using ResourceAmount = uint8_t;

	struct Terrains {
		DescriptionIndex d, r;
	};
	static_assert(sizeof(Terrains) == 2, "assert(sizeof(Terrains) == 2) failed.");
	struct Resources {
		DescriptionIndex d : 4, r : 4;
	};
	static_assert(sizeof(Resources) == 1, "assert(sizeof(Resources) == 1) failed.");
	struct ResourceAmounts {
		ResourceAmount d : 4, r : 4;
	};
	static_assert(sizeof(ResourceAmounts) == 1, "assert(sizeof(ResourceAmounts) == 1) failed.");

	Height get_height() const {
		return height;
	}
	NodeCaps nodecaps() const {
		return static_cast<NodeCaps>(caps);
	}
	uint16_t get_caps() const {
		return caps;
	}

	Terrains get_terrains() const {
		return terrains;
	}
	// The terrain on the downward triangle
	DescriptionIndex terrain_d() const {
		return terrains.d;
	}
	// The terrain on the triangle to the right
	DescriptionIndex terrain_r() const {
		return terrains.r;
	}
	void set_terrains(const Terrains& i) {
		terrains = i;
	}
	void set_terrain(const TCoords<FCoords>::TriangleIndex& t, DescriptionIndex const i)

	{
		if (t == TCoords<FCoords>::D)
			set_terrain_d(i);
		else
			set_terrain_r(i);
	}
	void set_terrain_d(DescriptionIndex const i) {
		terrains.d = i;
	}
	void set_terrain_r(DescriptionIndex const i) {
		terrains.r = i;
	}

	Bob* get_first_bob() const {
		return bobs;
	}
	const BaseImmovable* get_immovable() const {
		return immovable;
	}
	BaseImmovable* get_immovable() {
		return immovable;
	}

	void set_brightness(int32_t l, int32_t r, int32_t tl, int32_t tr, int32_t bl, int32_t br);
	int8_t get_brightness() const {
		return brightness;
	}

	/**
	 * Does not change the border bit of this or neighbouring fields. That must
	 * be done separately.
	 */
	void set_owned_by(const PlayerNumber n) {
		assert(n <= MAX_PLAYERS);
		owner_info_and_selections = n | (owner_info_and_selections & ~Player_Number_Bitmask);
	}

	PlayerNumber get_owned_by() const {
		assert((owner_info_and_selections & Player_Number_Bitmask) <= MAX_PLAYERS);
		return owner_info_and_selections & Player_Number_Bitmask;
	}
	bool is_border() const {
		return owner_info_and_selections & Border_Bitmask;
	}

	///
	/// Returns true when the node is owned by player_number and is not a border
	/// node. This is fast; only one compare (and a mask because the byte is
	/// shared with selection).
	///
	/// player_number must be in the range 1 .. Player_Number_Bitmask or the
	/// behaviour is undefined.
	bool is_interior(const PlayerNumber player_number) const {
		assert(0 < player_number);
		assert(player_number <= Player_Number_Bitmask);
		return player_number == (owner_info_and_selections & Owner_Info_Bitmask);
	}

	void set_border(const bool b) {
		owner_info_and_selections = (owner_info_and_selections & ~Border_Bitmask) | (b << Border_Bit);
	}

	int32_t get_roads() const {
		return roads;
	}
	int32_t get_road(int32_t const dir) const {
		return (roads >> dir) & RoadType::kMask;
	}
	void set_road(int32_t const dir, int32_t const type) {
		roads &= ~(RoadType::kMask << dir);
		roads |= type << dir;
	}

	// Resources can be set through Map::set_resources()
	// TODO(unknown): This should return DescriptionIndex
	DescriptionIndex get_resources() const {
		return resources;
	}
	ResourceAmount get_resources_amount() const {
		return res_amount;
	}
	// TODO(unknown): This should return uint8_t
	ResourceAmount get_initial_res_amount() const {
		return initial_res_amount;
	}

	/// \note you must reset this field's + neighbor's brightness when you
	/// change the height. Map::change_height does this. This function is not
	/// private, because the loader will use them directly But realize, most of
	/// the times you will need Map::set_field_height().
	void set_height(Height const h) {
		height = static_cast<int8_t>(h) < 0 ? 0 : MAX_FIELD_HEIGHT < h ? MAX_FIELD_HEIGHT : h;
	}

private:
	/**
	 * A field can be selected in one of 2 selections. This allows the user to
	 * use selection tools to select a set of fields and then perform a command
	 * on those fields.
	 *
	 * Selections can be edited with some operations. A selection can be
	 * 1. inverted,
	 * 2. unioned with the other selection,
	 * 3. intersected with the other selection or
	 * 4. differenced with the other selection.
	 *
	 * Each field can be owned by a player.
	 * The 2 highest bits are selected_a and selected_b.
	 * The next highest bit is the border bit.
	 * The low bits are the player number of the owner.
	 */
	using OwnerInfoAndSelectionsType = PlayerNumber;
	static const uint8_t Border_Bit = std::numeric_limits<OwnerInfoAndSelectionsType>::digits - 1;
	static const OwnerInfoAndSelectionsType Border_Bitmask = 1 << Border_Bit;
	static const OwnerInfoAndSelectionsType Player_Number_Bitmask = Border_Bitmask - 1;
	static const OwnerInfoAndSelectionsType Owner_Info_Bitmask =
	   Player_Number_Bitmask + Border_Bitmask;
	static_assert(MAX_PLAYERS <= Player_Number_Bitmask, "Bitmask is too big.");

	// Data Members
	/** linked list, \sa Bob::linknext_ */
	Bob* bobs;
	BaseImmovable* immovable;

	uint8_t caps : 7;
	uint8_t roads : 6;

	Height height;
	int8_t brightness;

	OwnerInfoAndSelectionsType owner_info_and_selections;

	DescriptionIndex resources;         ///< Resource type on this field, if any
	ResourceAmount initial_res_amount;  ///< Initial amount of resources
	ResourceAmount res_amount;          ///< Current amount of resources

	Terrains terrains;
};
#pragma pack(pop)

// Check that Field is tightly packed.
#ifndef WIN32
static_assert(sizeof(Field) == sizeof(void*) * 2 + 10, "Field is not tightly packed.");
#else
static_assert(sizeof(Field) <= sizeof(void*) * 2 + 11, "Field is not tightly packed.");
#endif
}

#endif  // end of include guard: WL_LOGIC_FIELD_H