1 /*
2  * Seven Kingdoms: Ancient Adversaries
3  *
4  * Copyright 1997,1998 Enlight Software Ltd.
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 //Filename    : OMATRIX.H
22 //Description : Object road direction turn
23 
24 #ifndef __OMATRIX_H
25 #define __OMATRIX_H
26 
27 #ifndef __OUNITRES_H
28 #include <OUNITRES.h>
29 #endif
30 
31 #include <OREGION.h>
32 
33 //----- Define bit meanings Location::flag ------//
34 #define 	LOCATE_WALK_LAND			0x01
35 #define	LOCATE_WALK_SEA			0x02
36 #define	LOCATE_COAST				0x08
37 
38 // ----- govern the usage of extra_para ---------//
39 #define	LOCATE_SITE_MASK			0xf0
40 #define	LOCATE_HAS_SITE			0x10
41 #define	LOCATE_HAD_WALL			0x20
42 #define	LOCATE_HAS_DIRT			0x30
43 #define	LOCATE_SITE_RESERVED		0xf0
44 //	occupied by other block such as hill, plant
45 
46 // ----- govern the usage of cargo_recno -------//
47 #define	LOCATE_BLOCK_MASK			0xf00
48 #define	LOCATE_IS_HILL				0x100
49 #define	LOCATE_IS_PLANT			0x200
50 #define	LOCATE_IS_TOWN				0x300
51 #define	LOCATE_IS_FIRM				0x400
52 #define  LOCATE_IS_WALL				0x500
53 #define	LOCATE_IS_ROCK				0xf00
54 
55 #define	LOCATE_POWER_OFF			0x1000 // true if no power_nation_recno can be set in this location
56 #define	LOCATE_HARBOR_BIT       0x2000 // true if the terrain is suitable to build harbor (x,y) to (x+2,y+2)
57 
58 // ------- constant on visibility ----------//
59 // const unsigned char FULL_VISIBILITY = MAX_BRIGHTNESS_ADJUST_DEGREE * 8 + 7;
60 const unsigned char FULL_VISIBILITY = 87;
61 // if a location has not been explored, visibility = 0
62 // if a location has been explored, visibility is bewtween 36-87
63 const unsigned char EXPLORED_VISIBILITY = 30;	// don't see this to multiple of 8
64 const unsigned char MAX_VISIT_LEVEL = FULL_VISIBILITY;
65 
66 
67 //------- Define structure Location -------//
68 
69 #pragma pack(1)
70 struct Location
71 {
72 public:
73 	unsigned short loc_flag;
74 	short			  terrain_id;
75 
76 	short         cargo_recno;
77 	short         air_cargo_recno;
78 
79 	unsigned char extra_para;
80 
81 	//------------------------------------------------//
82 	// when (loc_flag & LOCATE_SITE_MASK) == LOCATE_HAS_SITE
83 	// > extra_para = raw recno
84 	//
85 	// when (loc_flag & LOCATE_SITE_MASK) == LOCATE_HAD_WALL
86 	// > extra_para = time remained that can't build wall
87 	//
88 	// when (loc_flag & LOCATE_SITE_MASK) == LOCATE_HAS_DIRT
89 	// > extra_para = dirt recno
90 	//
91 	// when (loc_flag & LOCATE_BLOCK_MASK) == LOCATE_IS_HILL
92 	// > cargo_recno = top hill block id
93 	// > extra_para = bottom hill block id
94 	//
95 	// when (loc_flag & LOCATE_BLOCK_MASK) == LOCATE_IS_FIRM
96 	// > cargo_recno = firm recno
97 	//
98 	// when (loc_flag & LOCATE_BLOCK_MASK) == LOCATE_IS_TOWN
99 	// > cargo_recno = town zone recno
100 	//
101 	//	when (loc_flag & LOCATE_BLOCK_MASK) == LOCATE_IS_PLANT
102 	// > extra_para  = id. of the plant bitmap
103 	// > cargo_recno = low byte - inner x, high byte - inner y
104 	//
105 	//	when (loc_flag & LOCATE_BLOCK_MASK) == LOCATION_IS_WALL
106 	// > extra_para  = id. of the city wall bitmap
107 	// > high byte of cargo_recno = hit points remained for the wall
108 	//
109 	//	when (loc_flag & LOCATE_BLOCK_MASK) == LOCATION_IS_ROCK
110 	// > cargo_recno = rock recno in rock_array
111 	//
112 	// when (loc_flag & LOCATE_BLOCK_MASK) == 0 and cargo_recno != 0
113 	// > carge_recno = unit id
114 	//------------------------------------------------//
115 
116 	char		fire_level;					// -100 to 100, current fire level
117 	char		flammability;				// -100 to 100, likelihood of fire
118 
119 	char		power_nation_recno;		// 0-no nation has power over this location
120 	uint8_t		region_id;
121 	unsigned char visit_level;			// drop from FULL_VISIBILITY to 0
122 
123 public:
124 	//------ functions that check the type of the location ------//
125 
walkableLocation126 	int   walkable()	      { return loc_flag & LOCATE_WALK_LAND; }
sailableLocation127 	int   sailable()			{ return loc_flag & LOCATE_WALK_SEA; }
walkableLocation128 	int   walkable(int teraMask)
129 									{ return loc_flag & teraMask; }
130 	void	walkable_reset();
131 	// void	walkable_on()		{ loc_flag |= LOCATE_WALK_LAND; }
walkable_offLocation132 	void	walkable_off()		{ loc_flag &= ~(LOCATE_WALK_LAND | LOCATE_WALK_SEA); }
133 
walkable_onLocation134 	void	walkable_on(int teraMask)		{ loc_flag |= teraMask; }
walkable_offLocation135 	void	walkable_off(int teraMask)		{ loc_flag &= ~teraMask; }
136 
is_coastLocation137 	int	is_coast()			{ return loc_flag & LOCATE_COAST; }
138 
139 //	int	explored()        { return loc_flag & LOCATE_EXPLORED; }
140 //	void	explored_on()		{ loc_flag |= LOCATE_EXPLORED; }
141 //	void	explored_off()		{ loc_flag &= (~LOCATE_EXPLORED); }
exploredLocation142 	int	explored()        { return visit_level > 0; }
explored_onLocation143 	void	explored_on()		{ if( visit_level < EXPLORED_VISIBILITY*2) visit_level = EXPLORED_VISIBILITY*2; }
explored_offLocation144 	void	explored_off()		{ visit_level = 0; }
145 
146 	// ---------- visibility --------//
visibilityLocation147 	unsigned char visibility()				{ return visit_level/2; }
dec_visibilityLocation148 	void	dec_visibility()					{ if( visit_level > EXPLORED_VISIBILITY*2) --visit_level; }
set_visitedLocation149 	void	set_visited()						{ visit_level = MAX_VISIT_LEVEL*2; }
set_visitedLocation150 	void	set_visited(unsigned char v)	{ if( visit_level < v*2) visit_level = v*2; }
151 
152 	int	is_plateau();
153 
154 
155 	// ----------- site -------------//
156 	int	can_build_site(int teraMask=LOCATE_WALK_LAND)
157 			{ return (loc_flag & teraMask) && !(loc_flag & LOCATE_SITE_MASK) && !has_site(); }
158 	void	set_site(int siteRecno);
has_siteLocation159 	int	has_site()			{ return (loc_flag & LOCATE_SITE_MASK) == LOCATE_HAS_SITE; }
site_recnoLocation160 	int	site_recno()		{ if( has_site() )  return extra_para; else return 0; }
161 	void	remove_site();
162 
163 	// ------------ wall timeout ----------//
had_wallLocation164 	int	had_wall()			{ return (loc_flag & LOCATE_SITE_MASK) == LOCATE_HAD_WALL; }
165 	// after wall destructed, cannot build wall again for some time
166 	// the decrease time
167 	// (LOCATE_HAD_WALL)
168 	void	set_wall_timeout(int initTimeout);
wall_timeoutLocation169 	int	wall_timeout()					{ return extra_para; }
170 	int	dec_wall_timeout(int=1);
171 	void	remove_wall_timeout();
172 
173 	// ----------- dirt -------------//
can_add_dirtLocation174 	int	can_add_dirt()
175 			{ return !(loc_flag & LOCATE_SITE_MASK); }
176 	void	set_dirt(int dirtRecno);
has_dirtLocation177 	int	has_dirt()			{ return (loc_flag & LOCATE_SITE_MASK) == LOCATE_HAS_DIRT; }
dirt_recnoLocation178 	int	dirt_recno()		{ if( has_dirt() )  return extra_para; else return 0; }
179 	void	remove_dirt();
180 
181 	// ---------- firm ----------//
is_firmLocation182 	int   is_firm()         { return (loc_flag & LOCATE_BLOCK_MASK) == LOCATE_IS_FIRM; }
183 	int   can_build_firm(int teraMask = LOCATE_WALK_LAND)
184 			{ return !cargo_recno && (loc_flag & teraMask) && !(loc_flag & LOCATE_BLOCK_MASK) && !is_power_off(); }
185 	// ####### begin Gilbert 17/7 ###########//
186 	int	can_build_harbor(int teraMask = LOCATE_WALK_LAND)
187 			{ return !cargo_recno && (loc_flag & teraMask) && !(loc_flag & LOCATE_BLOCK_MASK); }
188 	// ####### end Gilbert 17/7 ###########//
189 	void	set_firm(int firmRecno);
firm_recnoLocation190 	int 	firm_recno()		{ if( is_firm() )   	  return cargo_recno; else return 0; }
191 	void	remove_firm();
192 
193 	// ---------- town ------------//
is_townLocation194 	int   is_town()    	 	{ return (loc_flag & LOCATE_BLOCK_MASK) == LOCATE_IS_TOWN; }
195 	void	set_town(int townRecno);
can_build_townLocation196 	int   can_build_town()
197 			{ return !cargo_recno && (loc_flag & LOCATE_WALK_LAND) && !(loc_flag & LOCATE_BLOCK_MASK) && !has_site() && !is_power_off(); }
town_recnoLocation198 	int	town_recno()		{ if( is_town() ) return cargo_recno; else return 0; }
199 	void	remove_town();
200 
201 	// ---------- hill -------------//
has_hillLocation202 	int	has_hill()			{ return (loc_flag & LOCATE_BLOCK_MASK) == LOCATE_IS_HILL; }
can_add_hillLocation203 	int	can_add_hill()		// exception : it has already a hill
204 			{ return has_hill() || // (loc_flag & LOCATE_WALK_LAND) &&
205 			!cargo_recno && !(loc_flag & (LOCATE_BLOCK_MASK | LOCATE_SITE_MASK)); }
206 	void	set_hill(int hillId);
hill_id1Location207 	int   hill_id1()			{ return cargo_recno; }
hill_id2Location208 	int   hill_id2()			{ return extra_para; }
209 	void	remove_hill();
210 
211 	// ---------- wall ------------//
is_wallLocation212 	int	is_wall()			{ return (loc_flag & LOCATE_BLOCK_MASK) == LOCATE_IS_WALL; }
can_build_wallLocation213 	int	can_build_wall()
214 			{ return !cargo_recno && (loc_flag & LOCATE_WALK_LAND) &&
215 			!(loc_flag & (LOCATE_BLOCK_MASK | LOCATE_SITE_MASK)) && !has_site(); }
216 	void	set_wall(int wallId, int townRecno, int hitPoints);
217 	void	set_wall_creating();
218 	void	set_wall_destructing();
chg_wall_idLocation219 	void	chg_wall_id( int wallId)		{ extra_para = wallId; }
wall_idLocation220 	int	wall_id()			{ if( is_wall() ) return extra_para; else return 0; }
wall_nation_recnoLocation221 	int	wall_nation_recno() { return power_nation_recno; }
wall_hit_pointLocation222 	int	wall_hit_point()	{ return cargo_recno >> 8; }
wall_town_recnoLocation223 	int	wall_town_recno()	{ return cargo_recno || 0xFF; }
224 	//---------------------------------------------------//
225 	// initial 0, 1 to 100:creating, -1 to -100: destructing
226 	// except 0 or 100, hit point slowly increase by 1
227 	//---------------------------------------------------//
wall_abs_hit_pointLocation228 	int	wall_abs_hit_point()			{ return wall_hit_point() >= 0? wall_hit_point() : -wall_hit_point(); }
229 	int	inc_wall_hit_point(int grow=1);
230 	int	attack_wall(int damage=1);
wall_gradeLocation231 	int	wall_grade()					{ return wall_hit_point() >= 0 ? (wall_hit_point()+24) / 25 : (wall_hit_point()-24)/25;}
is_wall_creatingLocation232 	int	is_wall_creating()			{ return wall_hit_point() > 0; }
is_wall_destructingLocation233 	int	is_wall_destructing()		{ return wall_hit_point() < 0; }
234 	void	remove_wall(int setTimeOut=-1);
235 
236 	// ---------- plant -----------//
is_plantLocation237 	int 	is_plant()						{ return (loc_flag & LOCATE_BLOCK_MASK) == LOCATE_IS_PLANT; }
238 	int 	can_add_plant(int teraMask = LOCATE_WALK_LAND)
239 			{ return !cargo_recno && (loc_flag & teraMask) && !(loc_flag & (LOCATE_BLOCK_MASK | LOCATE_SITE_MASK)) && !has_site(); }
240 	void	set_plant(int plantId, int offsetX, int offsetY);
plant_idLocation241 	int	plant_id()						{ if( is_plant() ) return extra_para; else return 0; }
plant_inner_xLocation242 	int	plant_inner_x() 				{ return cargo_recno & 0xFF; }
plant_inner_yLocation243 	int	plant_inner_y() 				{ return cargo_recno >> 8;   }
grow_plantLocation244 	void	grow_plant()					{ extra_para++; }
245 	void	remove_plant();
246 
247 	// ---------- rock ------------//
is_rockLocation248 	int	is_rock()						{ return (loc_flag & LOCATE_BLOCK_MASK) == LOCATE_IS_ROCK; }
249 	int	can_add_rock(int teraMask = LOCATE_WALK_LAND)
250 			{ return !cargo_recno && (loc_flag & teraMask) && !(loc_flag & LOCATE_BLOCK_MASK); }
251 	void	set_rock(short rockArrayRecno);
rock_array_recnoLocation252 	short	rock_array_recno()				{ if( is_rock() ) return cargo_recno; else return 0; }
253 	void	remove_rock();
254 
255 	// call region_type only when generating region number
region_typeLocation256 	RegionType region_type()			{ return walkable()?REGION_LAND:(sailable()?REGION_SEA:REGION_INPASSABLE); }
257 
258 	// --------- functions on fire ---------//
fire_strLocation259 	char	fire_str()						{ return fire_level; }
fire_srcLocation260 	char	fire_src()						{ return flammability; }
set_fire_strLocation261 	void	set_fire_str(char str)		{ fire_level = str; }
set_fire_srcLocation262 	void	set_fire_src(char src)		{ flammability = src; }
add_fire_strLocation263 	void	add_fire_str(char str)		{ fire_level += str; }
add_fire_srcLocation264 	void	add_fire_src(char src)		{ flammability += src; }
can_set_fireLocation265 	int	can_set_fire()					{ return flammability >= -50; }
266 
267 	//----- functions whose results affected by mobile_type -----//
268 
269 	//int   is_blocked(int mobileType)    { return mobileType==UNIT_AIR ? air_cargo_recno : cargo_recno; }     // return 1 or 0 (although both are the same)
unit_recnoLocation270 	int   unit_recno(int mobileType)    { return mobileType==UNIT_AIR ? air_cargo_recno : cargo_recno; }     // return the exact cargo recno
271 
272 	int   has_unit(int mobileType);
273 	int	has_any_unit(int mobileType = UNIT_LAND);
274 	int 	get_any_unit(int& mobileType);
275 	int   is_accessible(int mobileType);      // whether the location is accessible to the unit of the specific mobile type
276 
277 	int   is_unit_group_accessible(int mobileType, uint32_t curGroupId);
278 
279 	//int   can_move(int mobileType)      { return is_accessible(mobileType) && cargo_recno==0; }
can_moveLocation280 	int   can_move(int mobileType)      { return is_accessible(mobileType) && (mobileType==UNIT_AIR ? !air_cargo_recno : !cargo_recno); }
281 
282 	//### begin alex 24/6 ###//
283 	//------------ power --------------//
284 	void	set_power_on();
285 	void	set_power_off();
286 	int	is_power_off();
287 	//#### end alex 24/6 ####//
288 
289 	//----------- harbor bit -----------//
set_harbor_bitLocation290 	void	set_harbor_bit()         { loc_flag |= LOCATE_HARBOR_BIT; }
clear_harbor_bitLocation291 	void	clear_harbor_bit()       { loc_flag &= ~LOCATE_HARBOR_BIT; }
can_build_whole_harborLocation292 	int	can_build_whole_harbor() { return loc_flag & LOCATE_HARBOR_BIT; }
293 };
294 #pragma pack()
295 
296 //------------ Define class Matrix -----------//
297 
298 class World;
299 
300 class Matrix
301 {
302 friend class World;
303 
304 public:
305    int       max_x_loc, max_y_loc;      // read from map file
306    Location  *loc_matrix;
307 
308 	int       top_x_loc, top_y_loc;              // the top left location of current zoom window
309 	int       cur_x_loc, cur_y_loc;
310 	int       cur_cargo_width, cur_cargo_height; // cur_x2_loc = cur_x_loc + cur_cargo_width
311 
312 	int       disp_x_loc, disp_y_loc;    // calculated in Matrix()
313 	int       loc_width, loc_height;     // passed as para in Matrix()
314 
315    int       win_x1, win_y1, win_x2, win_y2;
316 	int       image_x1, image_y1, image_x2, image_y2;
317    int       image_width, image_height;
318 
319    char      own_matrix;
320 
321    char      *save_image_buf;
322 	char      just_drawn_flag;    // whether the matrix has just been drawn by draw()
323 
324 public:
325    virtual ~Matrix();
326 
327    void init(int,int,int,int,int,int,int,int,int);
328    void assign_map(Matrix*);
329    void assign_map(Location*,int,int);
330 
331    virtual void paint();
332    virtual void draw();
333    virtual void disp();
detect()334    virtual int  detect()      {return 0;}
335    virtual void refresh();
336    virtual void scroll(int,int);
337 
get_loc(int xLoc,int yLoc)338    Location* get_loc(int xLoc,int yLoc)
339         { return loc_matrix+yLoc * max_x_loc + xLoc; }
340 
341 protected:
post_draw()342    virtual void post_draw()      {;}
draw_loc(int x,int y,int xLoc,int yLoc,Location * locPtr)343    virtual void draw_loc(int x,int y,int xLoc,int yLoc,Location* locPtr) {;}
344 
345    void init_var();
346 	int  valid_cur_box(int=1);
347    void valid_disp_area(int=0);
348 };
349 
350 //--------- Define inline functions ----------//
351 
352 //-------- Begin of function Location::is_accessible --------//
353 
is_accessible(int mobileType)354 inline int Location::is_accessible(int mobileType)
355 {
356 	switch(mobileType)
357 	{
358 		case UNIT_LAND:
359 			return walkable();
360 			break;
361 
362 		case UNIT_SEA:
363 			return sailable();
364 			break;
365 
366 		case UNIT_AIR:
367 			return 1;
368 			break;
369 	}
370 
371 	return 0;
372 }
373 //-------- End of function Location::is_accessible --------//
374 
375 #endif
376