1 /* Copyright (C) 1995-2002  FSGames. Ported by Sean Ford and Yan Shosh
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation; either version 2 of the License, or
6  * (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  */
17 //
18 // treasure; a derived class of walker
19 //
20 
21 //#include "graph.h"
22 #include <math.h>
23 #include "obmap.h"
24 #include "loader.h"
25 #include "screen.h"
26 #include "treasure.h"
27 #include "text.h"
28 #include "stats.h"
29 #include "guy.h"
30 
31 // Zardus: this is the func to get events
32 void get_input_events(bool);
33 
34 // Zardus: from video.cpp for retreat crash ugly hack fix
35 extern bool retreat;
36 
treasure(unsigned char * data,screen * myscreen)37 treasure::treasure(unsigned char  *data, screen  *myscreen) : walker(data, myscreen)
38 {
39 	ignore =(char) 0;
40 	dead =  (char) 0;
41 }
42 
~treasure()43 treasure::~treasure()
44 {
45 	//bufffers: PORT: cannot call destructor w/o obj: walker::~walker();
46 }
47 
act()48 short treasure::act()
49 {
50 	// Abort all later code for now ..
51 	return 1;
52 }
53 
eat_me(walker * eater)54 short treasure::eat_me(walker  * eater)
55 {
56 	short guys_here;
57 	oblink *here;
58 	static text eattext(screenp);
59 	char message[80];
60 	char * eatkeys;
61 	long distance;
62 	walker  *target, *flash;
63 	static char exitname[40];
64 	long leftside, rightside;
65 
66 	switch (family)
67 	{
68 		case FAMILY_DRUMSTICK:
69 			if (eater->stats->hitpoints >= eater->stats->max_hitpoints)
70 				return 1;
71 			else
72 			{
73 				eater->stats->hitpoints += (short) ((10*stats->level) + (short) random((short) 10*stats->level));
74 				if (eater->stats->hitpoints > eater->stats->max_hitpoints)
75 					eater->stats->hitpoints = eater->stats->max_hitpoints;
76 				dead = 1;
77 				if (on_screen())
78 					screenp->soundp->play_sound(SOUND_EAT);
79 				return 1;
80 			}
81 		case FAMILY_GOLD_BAR:
82 			if (eater->team_num == 0 || eater->myguy)
83 			{
84 				myscreen->m_score[eater->team_num] += (200*stats->level);
85 				dead = 1;
86 				if (on_screen())
87 					screenp->soundp->play_sound(SOUND_MONEY);
88 			}
89 			return 1;
90 		case FAMILY_SILVER_BAR:
91 			if (eater->team_num == 0 || eater->myguy)
92 			{
93 				myscreen->m_score[eater->team_num] += (50*stats->level);
94 				dead = 1;
95 				if (on_screen())
96 					screenp->soundp->play_sound(SOUND_MONEY);
97 			}
98 			return 1;
99 		case FAMILY_FLIGHT_POTION:
100 			if (!eater->stats->query_bit_flags(BIT_FLYING) )
101 			{
102 				eater->flight_left += (150*stats->level);
103 				if (eater->user != -1)
104 				{
105 					sprintf(message, "Potion of Flight(%d)!", stats->level);
106 					screenp->do_notify(message, eater);
107 				}
108 				dead = 1;
109 			}
110 			return 1;
111 		case FAMILY_MAGIC_POTION:
112 			if (eater->stats->magicpoints < eater->stats->max_magicpoints)
113 				eater->stats->magicpoints = eater->stats->max_magicpoints;
114 			eater->stats->magicpoints += (50*stats->level);
115 			dead = 1;
116 			if (eater->user != -1)
117 			{
118 				sprintf(message, "Potion of Mana(%d)!", stats->level);
119 				screenp->do_notify(message, eater);
120 			}
121 			return 1;
122 		case FAMILY_INVULNERABLE_POTION:
123 			if (!eater->stats->query_bit_flags(BIT_INVINCIBLE) )
124 			{
125 				eater->invulnerable_left += (150*stats->level);
126 				dead = 1;
127 				if (eater->user != -1)
128 				{
129 					sprintf(message, "Potion of Invulnerability(%d)!", stats->level);
130 					screenp->do_notify(message, eater);
131 				}
132 			}
133 			return 1;
134 		case FAMILY_INVIS_POTION:
135 			eater->invisibility_left += (150*stats->level);
136 			if (eater->user != -1)
137 			{
138 				sprintf(message, "Potion of Invisibility(%d)!", stats->level);
139 				screenp->do_notify(message, eater);
140 			}
141 			dead = 1;
142 			return 1;
143 		case FAMILY_SPEED_POTION:
144 			eater->speed_bonus_left += 50*stats->level;
145 			eater->speed_bonus = stats->level;
146 			if (eater->user != -1)
147 			{
148 				sprintf(message, "Potion of Speed(%d)!", stats->level);
149 				screenp->do_notify(message, eater);
150 			}
151 			dead = 1;
152 			return 1;
153 		case FAMILY_EXIT: // go to another level, possibly
154 			if (eater->in_act) return 1;
155 			if (eater->query_act_type()!= ACT_CONTROL || (eater->skip_exit > 1))
156 				return 1;
157 			eater->skip_exit = 10;
158 			// See if there are any enemies left ...
159 			if (screenp->level_done == 0)
160 				guys_here = 1;
161 			else
162 				guys_here = 0;
163 			// Get the name of our exit..
164 			sprintf(message, "scen%d", stats->level);
165 			strcpy(exitname, myscreen->get_scen_title(message, myscreen) );
166 
167 			//buffers: PORT: using strcmp instead of stricmp
168 			if (!strcmp(exitname, "none"))
169 				sprintf(exitname, "Level %d", stats->level);
170 
171 			leftside  = 160 - ( (strlen(exitname) + 18) * 3);
172 			rightside = 160 + ( (strlen(exitname) + 18) * 3);
173 			// First check to see if we're withdrawing into
174 			//    somewhere we've been, in which case we abort
175 			//    this level, and set our current level to
176 			//    that pointed to by the exit ...
177 			if ( (screenp->levelstatus[stats->level] == 1)
178 			        && (screenp->levelstatus[screenp->scen_num] == 0)
179 			        && (guys_here != 0)
180 			   ) // okay to leave
181 			{
182 				leftside -= 12;
183 				rightside += 12;
184 				screenp->draw_dialog(leftside, 20, rightside, 54, "Exit Field");
185 				sprintf(message, "Withdraw to %s? (Y/N)", exitname);
186 				eattext.write_y(42, message, DARK_BLUE, 1);
187 				screenp->buffer_to_screen(0, 0, 320, 200);
188 				eatkeys = query_keyboard();
189 				clear_keyboard();
190 				while (!eatkeys[SDLK_y] && !eatkeys[SDLK_n])
191 					get_input_events(WAIT);
192 				// Redraw screen ..
193 				screenp->redrawme = 1;
194 
195 				if (eatkeys[SDLK_y]) // accepted level change
196 				{
197 					clear_keyboard();
198 					screenp->levelstatus[screenp->scen_num] = 0;  // NOT done
199 					// Delete all of our current information and abort ..
200 					here = myscreen->oblist;
201 					while (here)
202 					{
203 						if (here->ob && here->ob->query_order() == ORDER_LIVING)
204 						{
205 							//myscreen->remove_ob(here->ob);
206 							here->ob->dead = 1;
207 							myscreen->myobmap->remove
208 							(here->ob);
209 							//myscreen->remove_obmap(here->ob);
210 						}
211 						here = here->next;
212 					}
213 					//here = myscreen->fxlist;
214 					//while (here)
215 					//{
216 					//  if (here->ob)
217 					//    myscreen->remove_fx_ob(here->ob);
218 					//  here = here->next;
219 					//}
220 					// Now load the game as it was ...
221 					load_saved_game("save0", myscreen);
222 					myscreen->scen_num = (short) (stats->level-1);
223 					myscreen->end = 1;
224 					save_game("save0", myscreen);
225 					retreat = 1;
226 
227 					return screenp->endgame(1, stats->level); // retreat
228 				}  // end of accepted withdraw to new level ..
229 				clear_keyboard();
230 			} // end of checking for withdrawal to completed level
231 
232 			if (!guys_here) // nobody evil left, so okay to exit level ..
233 			{
234 				screenp->draw_dialog(30, 20, 290, 54, "Exit Field");
235 				sprintf(message, "Exit to %s? (Y/N)", exitname);
236 				eattext.write_y(42, message, DARK_BLUE, 1);
237 				screenp->buffer_to_screen(0, 0, 320, 200);
238 				eatkeys = query_keyboard();
239 				clear_keyboard();
240 				// Zardus: FIX: get_input_events instead of freezing and counting :-)
241 				while (!eatkeys[SDLK_y] && !eatkeys[SDLK_n])
242 					get_input_events(WAIT);
243 				// Redraw screen ..
244 				screenp->redrawme = 1;
245 
246 				if (eatkeys[SDLK_y]) // accepted level change
247 				{
248 					clear_keyboard();
249 					//screenp->levelstatus[screenp->scen_num] = 1;
250 					return screenp->endgame(0, stats->level);
251 				}
252 				clear_keyboard();
253 				return 1;
254 			}
255 			return 1;
256 		case FAMILY_TELEPORTER:
257 			if (eater->skip_exit > 1)
258 				return 1;
259 			distance = distance_to_ob_center(eater); // how  away?
260 			if (distance > 21)
261 				return 1;
262 			if (distance < 4 && eater->skip_exit)
263 			{
264 				//eater->skip_exit++;
265 				eater->skip_exit = 8;
266 				return 1;
267 			}
268 			// If we're close enough, teleport ..
269 			eater->skip_exit += 20;
270 			if (!leader)
271 				target = find_teleport_target();
272 			else
273 				target = leader;
274 			if (!target)
275 				return 1;
276 			leader = target;
277 			eater->center_on(target);
278 			if (!screenp->query_passable(eater->xpos, eater->ypos, eater))
279 			{
280 				eater->center_on(this);
281 				return 1;
282 			}
283 			// Now do special effects
284 			flash = screenp->add_ob(ORDER_FX, FAMILY_FLASH);
285 			flash->ani_type = ANI_EXPAND_8;
286 			flash->center_on(this);
287 			return 1;
288 		case FAMILY_LIFE_GEM: // get back some of lost man's xp ..
289 			if (eater->team_num != team_num) // only our team can get these
290 				return 1;
291 			myscreen->m_score[eater->team_num] += stats->hitpoints;
292 			flash = screenp->add_ob(ORDER_FX, FAMILY_FLASH);
293 			flash->ani_type = ANI_EXPAND_8;
294 			flash->center_on(this);
295 			dead = 1;
296 			death();
297 			return 1;
298 		case FAMILY_KEY: // get the key to this door ..
299 			if (!(eater->keys & (long)(pow((double) 2, stats->level)) )) // just got it?
300 			{
301 				eater->keys |= (long) (pow((double)2, stats->level)); // ie, 2, 4, 8, 16...
302 				if (eater->myguy)
303 					sprintf(message, "%s picks up key %d", eater->myguy->name,
304 					        stats->level);
305 				else
306 					sprintf(message, "%s picks up key %d", eater->stats->name, stats->level);
307 				if (eater->team_num == 0) // only show players picking up keys
308 				{
309 					myscreen->do_notify(message, eater);
310 					if (eater->on_screen())
311 						myscreen->soundp->play_sound(SOUND_MONEY);
312 				}
313 			}
314 			return 1;
315 		default:
316 			return 1;
317 	} // end of treasure-check
318 }
319 
set_direct_frame(short whatframe)320 void treasure::set_direct_frame(short whatframe)
321 {
322 	unsigned char  * data;
323 	frame = whatframe;
324 
325 	data = screenp->myloader->graphics[PIX(order, family)];
326 	bmp = (unsigned char  *) (data+3 + frame*size);
327 
328 }
329 
find_teleport_target()330 walker  * treasure::find_teleport_target()
331 {
332 	walker  *target = NULL;
333 	oblink  *here = screenp->fxlist;
334 	short keep_looking = 1;
335 	short number = 0;
336 
337 	// First find where we are in the list ...
338 	while (here && keep_looking)
339 	{
340 		if (here->ob && here->ob == this) // found us
341 			keep_looking = 0;
342 		else
343 		{
344 			here = here->next;
345 			number++;
346 		}
347 	}
348 
349 	if (keep_looking) // didn't find us?
350 		return NULL;
351 
352 	//printf("Teleporting from #%d ..", number);
353 
354 	// Now search the rest of the loop ..
355 	keep_looking = 1;
356 	here = here->next;
357 	number++;
358 	while (here && keep_looking)
359 	{
360 		if (here->ob && !here->ob->dead)
361 		{
362 			if (here->ob->query_order() == ORDER_TREASURE &&
363 			        here->ob->query_family() == FAMILY_TELEPORTER &&
364 			        here->ob->stats->level == stats->level)
365 			{
366 				target = here->ob;
367 				keep_looking = 0;
368 				//printf(" to target %d\n", number);
369 				return target;
370 			}
371 		}
372 		here = here->next;
373 		number++;
374 	}
375 
376 	// Hit the end of the list, look from top down now ..
377 	here = screenp->fxlist;
378 	number = 0;
379 	while (here)
380 	{
381 		if (here->ob && !here->ob->dead)
382 		{
383 			if (here->ob->query_order() == ORDER_TREASURE &&
384 			        here->ob->query_family() == FAMILY_TELEPORTER &&
385 			        here->ob->stats->level == stats->level)
386 			{
387 				target = here->ob;
388 				//printf(" to looped target %d\n", number);
389 				return target;
390 			}
391 		}
392 		here = here->next;
393 		number++;
394 	}
395 
396 	return target;
397 }
398 
399