1 //Copyright Paul Reiche, Fred Ford. 1992-2002
2 
3 /*
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18 
19 #include "../ship.h"
20 #include "urquan.h"
21 #include "resinst.h"
22 
23 #include "uqm/globdata.h"
24 
25 #include <stdlib.h>
26 
27 // Core characteristics
28 #define MAX_CREW MAX_CREW_SIZE
29 #define MAX_ENERGY MAX_ENERGY_SIZE
30 #define ENERGY_REGENERATION 1
31 #define ENERGY_WAIT 4
32 #define MAX_THRUST 30
33 #define THRUST_INCREMENT 6
34 #define THRUST_WAIT 6
35 #define TURN_WAIT 4
36 #define SHIP_MASS 10
37 
38 // Fusion blast
39 #define WEAPON_ENERGY_COST 6
40 #define WEAPON_WAIT 6
41 #define MISSILE_SPEED DISPLAY_TO_WORLD (20)
42 #define MISSILE_LIFE 20
43 #define MISSILE_HITS 10
44 #define MISSILE_DAMAGE 6
45 #define MISSILE_OFFSET 8
46 #define URQUAN_OFFSET 32
47 
48 // Fighters
49 #define SPECIAL_ENERGY_COST 8
50 #define SPECIAL_WAIT 9
51 #define FIGHTER_OFFSET 4
52 #define FIGHTER_SPEED DISPLAY_TO_WORLD (8)
53 #define ONE_WAY_FLIGHT 125
54 #define TRACK_THRESHOLD 6
55 #define FIGHTER_LIFE (ONE_WAY_FLIGHT + ONE_WAY_FLIGHT + 150)
56 #define FIGHTER_HITS 1
57 #define FIGHTER_MASS 0
58 #define FIGHTER_WEAPON_WAIT 8
59 #define FIGHTER_LASER_RANGE DISPLAY_TO_WORLD (40 + FIGHTER_OFFSET)
60 
61 static RACE_DESC urquan_desc =
62 {
63 	{ /* SHIP_INFO */
64 		FIRES_FORE | SEEKING_SPECIAL,
65 		30, /* Super Melee cost */
66 		MAX_CREW, MAX_CREW,
67 		MAX_ENERGY, MAX_ENERGY,
68 		URQUAN_RACE_STRINGS,
69 		URQUAN_ICON_MASK_PMAP_ANIM,
70 		URQUAN_MICON_MASK_PMAP_ANIM,
71 		NULL, NULL, NULL
72 	},
73 	{ /* FLEET_STUFF */
74 		2666 / SPHERE_RADIUS_INCREMENT * 2, /* Initial SoI radius */
75 		{ /* Known location (center of SoI) */
76 			5750, 6000,
77 		},
78 	},
79 	{
80 		MAX_THRUST,
81 		THRUST_INCREMENT,
82 		ENERGY_REGENERATION,
83 		WEAPON_ENERGY_COST,
84 		SPECIAL_ENERGY_COST,
85 		ENERGY_WAIT,
86 		TURN_WAIT,
87 		THRUST_WAIT,
88 		WEAPON_WAIT,
89 		SPECIAL_WAIT,
90 		SHIP_MASS,
91 	},
92 	{
93 		{
94 			URQUAN_BIG_MASK_PMAP_ANIM,
95 			URQUAN_MED_MASK_PMAP_ANIM,
96 			URQUAN_SML_MASK_PMAP_ANIM,
97 		},
98 		{
99 			FUSION_BIG_MASK_PMAP_ANIM,
100 			FUSION_MED_MASK_PMAP_ANIM,
101 			FUSION_SML_MASK_PMAP_ANIM,
102 		},
103 		{
104 			FIGHTER_BIG_MASK_PMAP_ANIM,
105 			FIGHTER_MED_MASK_PMAP_ANIM,
106 			FIGHTER_SML_MASK_PMAP_ANIM,
107 		},
108 		{
109 			URQUAN_CAPTAIN_MASK_PMAP_ANIM,
110 			NULL, NULL, NULL, NULL, NULL
111 		},
112 		URQUAN_VICTORY_SONG,
113 		URQUAN_SHIP_SOUNDS,
114 		{ NULL, NULL, NULL },
115 		{ NULL, NULL, NULL },
116 		{ NULL, NULL, NULL },
117 		NULL, NULL
118 	},
119 	{
120 		0,
121 		MISSILE_SPEED * MISSILE_LIFE,
122 		NULL,
123 	},
124 	(UNINIT_FUNC *) NULL,
125 	(PREPROCESS_FUNC *) NULL,
126 	(POSTPROCESS_FUNC *) NULL,
127 	(INIT_WEAPON_FUNC *) NULL,
128 	0,
129 	0, /* CodeRef */
130 };
131 
132 static COUNT
initialize_fusion(ELEMENT * ShipPtr,HELEMENT FusionArray[])133 initialize_fusion (ELEMENT *ShipPtr, HELEMENT FusionArray[])
134 {
135 	STARSHIP *StarShipPtr;
136 	MISSILE_BLOCK MissileBlock;
137 
138 	GetElementStarShip (ShipPtr, &StarShipPtr);
139 	MissileBlock.cx = ShipPtr->next.location.x;
140 	MissileBlock.cy = ShipPtr->next.location.y;
141 	MissileBlock.farray = StarShipPtr->RaceDescPtr->ship_data.weapon;
142 	MissileBlock.face = MissileBlock.index = StarShipPtr->ShipFacing;
143 	MissileBlock.sender = ShipPtr->playerNr;
144 	MissileBlock.flags = IGNORE_SIMILAR;
145 	MissileBlock.pixoffs = URQUAN_OFFSET;
146 	MissileBlock.speed = MISSILE_SPEED;
147 	MissileBlock.hit_points = MISSILE_HITS;
148 	MissileBlock.damage = MISSILE_DAMAGE;
149 	MissileBlock.life = MISSILE_LIFE;
150 	MissileBlock.preprocess_func = NULL;
151 	MissileBlock.blast_offs = MISSILE_OFFSET;
152 	FusionArray[0] = initialize_missile (&MissileBlock);
153 
154 	return (1);
155 }
156 
157 static void
fighter_postprocess(ELEMENT * ElementPtr)158 fighter_postprocess (ELEMENT *ElementPtr)
159 {
160 	HELEMENT Laser;
161 	STARSHIP *StarShipPtr;
162 	LASER_BLOCK LaserBlock;
163 
164 	GetElementStarShip (ElementPtr, &StarShipPtr);
165 	LaserBlock.cx = ElementPtr->next.location.x;
166 	LaserBlock.cy = ElementPtr->next.location.y;
167 	LaserBlock.face = ElementPtr->thrust_wait;
168 	LaserBlock.ex = COSINE (FACING_TO_ANGLE (LaserBlock.face), FIGHTER_LASER_RANGE);
169 	LaserBlock.ey = SINE (FACING_TO_ANGLE (LaserBlock.face), FIGHTER_LASER_RANGE);
170 	LaserBlock.sender = ElementPtr->playerNr;
171 	LaserBlock.flags = IGNORE_SIMILAR;
172 	LaserBlock.pixoffs = FIGHTER_OFFSET;
173 	LaserBlock.color = BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x0A), 0x0E);
174 	Laser = initialize_laser (&LaserBlock);
175 	if (Laser)
176 	{
177 		ELEMENT *LaserPtr;
178 
179 		LockElement (Laser, &LaserPtr);
180 		SetElementStarShip (LaserPtr, StarShipPtr);
181 
182 		ProcessSound (SetAbsSoundIndex (
183 						/* FIGHTER_ZAP */
184 				StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 2), LaserPtr);
185 
186 		UnlockElement (Laser);
187 		PutElement (Laser);
188 	}
189 
190 	ElementPtr->postprocess_func = 0;
191 	ElementPtr->thrust_wait = FIGHTER_WEAPON_WAIT;
192 }
193 
194 static void
fighter_preprocess(ELEMENT * ElementPtr)195 fighter_preprocess (ELEMENT *ElementPtr)
196 {
197 	STARSHIP *StarShipPtr;
198 
199 	GetElementStarShip (ElementPtr, &StarShipPtr);
200 
201 	++StarShipPtr->RaceDescPtr->characteristics.special_wait;
202 	if (FIGHTER_LIFE - ElementPtr->life_span > TRACK_THRESHOLD
203 			&& !(ElementPtr->state_flags & CHANGING))
204 	{
205 		BOOLEAN Enroute;
206 		COUNT orig_facing, facing;
207 		SIZE delta_x, delta_y;
208 		ELEMENT *eptr;
209 
210 		Enroute = TRUE;
211 
212 		delta_x = StarShipPtr->RaceDescPtr->ship_info.crew_level;
213 		delta_y = ElementPtr->life_span;
214 
215 		orig_facing = facing =
216 				GetFrameIndex (ElementPtr->current.image.frame);
217 		if (((delta_y & 1) || ElementPtr->hTarget
218 				|| TrackShip (ElementPtr, &facing) >= 0)
219 				&& (delta_x == 0 || delta_y >= ONE_WAY_FLIGHT))
220 			ElementPtr->state_flags |= IGNORE_SIMILAR;
221 		else if (delta_x)
222 		{
223 			LockElement (StarShipPtr->hShip, &eptr);
224 			delta_x = eptr->current.location.x
225 					- ElementPtr->current.location.x;
226 			delta_y = eptr->current.location.y
227 					- ElementPtr->current.location.y;
228 			UnlockElement (StarShipPtr->hShip);
229 			delta_x = WRAP_DELTA_X (delta_x);
230 			delta_y = WRAP_DELTA_Y (delta_y);
231 			facing = NORMALIZE_FACING (
232 					ANGLE_TO_FACING (ARCTAN (delta_x, delta_y))
233 					);
234 
235 #ifdef NEVER
236 			if (delta_x < 0)
237 				delta_x = -delta_x;
238 			if (delta_y < 0)
239 				delta_y = -delta_y;
240 			if (delta_x <= LASER_RANGE && delta_y <= LASER_RANGE)
241 #endif /* NEVER */
242 				ElementPtr->state_flags &= ~IGNORE_SIMILAR;
243 
244 			Enroute = FALSE;
245 		}
246 
247 		if (ElementPtr->thrust_wait > 0)
248 			--ElementPtr->thrust_wait;
249 
250 		if (ElementPtr->hTarget)
251 		{
252 			LockElement (ElementPtr->hTarget, &eptr);
253 			delta_x = eptr->current.location.x
254 					- ElementPtr->current.location.x;
255 			delta_y = eptr->current.location.y
256 					- ElementPtr->current.location.y;
257 			UnlockElement (ElementPtr->hTarget);
258 			delta_x = WRAP_DELTA_X (delta_x);
259 			delta_y = WRAP_DELTA_Y (delta_y);
260 
261 			if (ElementPtr->thrust_wait == 0
262 					&& abs (delta_x) < FIGHTER_LASER_RANGE * 3 / 4
263 					&& abs (delta_y) < FIGHTER_LASER_RANGE * 3 / 4
264 					&& delta_x * delta_x + delta_y * delta_y <
265 					(FIGHTER_LASER_RANGE * 3 / 4) * (FIGHTER_LASER_RANGE * 3 / 4))
266 			{
267 				ElementPtr->thrust_wait =
268 						(BYTE)NORMALIZE_FACING (
269 						ANGLE_TO_FACING (ARCTAN (delta_x, delta_y))
270 						);
271 				ElementPtr->postprocess_func = fighter_postprocess;
272 			}
273 
274 			if (Enroute)
275 			{
276 				facing = GetFrameIndex (eptr->current.image.frame);
277 				if (ElementPtr->turn_wait & LEFT)
278 				{
279 					delta_x += COSINE (FACING_TO_ANGLE (facing - 4),
280 							DISPLAY_TO_WORLD (30));
281 					delta_y += SINE (FACING_TO_ANGLE (facing - 4),
282 							DISPLAY_TO_WORLD (30));
283 				}
284 				else
285 				{
286 					delta_x += COSINE (FACING_TO_ANGLE (facing + 4),
287 							DISPLAY_TO_WORLD (30));
288 					delta_y += SINE (FACING_TO_ANGLE (facing + 4),
289 							DISPLAY_TO_WORLD (30));
290 				}
291 				facing = NORMALIZE_FACING (
292 						ANGLE_TO_FACING (ARCTAN (delta_x, delta_y))
293 						);
294 			}
295 		}
296 		ElementPtr->state_flags |= CHANGING;
297 
298 		if (facing != orig_facing)
299 			ElementPtr->next.image.frame = SetAbsFrameIndex (
300 					ElementPtr->next.image.frame, facing
301 					);
302 		SetVelocityVector (
303 				&ElementPtr->velocity, FIGHTER_SPEED, facing
304 				);
305 	}
306 }
307 
308 static void
fighter_collision(ELEMENT * ElementPtr0,POINT * pPt0,ELEMENT * ElementPtr1,POINT * pPt1)309 fighter_collision (ELEMENT *ElementPtr0, POINT *pPt0,
310 		ELEMENT *ElementPtr1, POINT *pPt1)
311 {
312 	STARSHIP *StarShipPtr;
313 
314 	GetElementStarShip (ElementPtr0, &StarShipPtr);
315 	if (GRAVITY_MASS (ElementPtr1->mass_points))
316 	{
317 		HELEMENT hFighterElement;
318 
319 		hFighterElement = AllocElement ();
320 		if (hFighterElement)
321 		{
322 			COUNT primIndex, travel_facing;
323 			SIZE delta_facing;
324 			ELEMENT *FighterElementPtr;
325 
326 			LockElement (hFighterElement, &FighterElementPtr);
327 			primIndex = FighterElementPtr->PrimIndex;
328 			*FighterElementPtr = *ElementPtr0;
329 			FighterElementPtr->PrimIndex = primIndex;
330 			(GLOBAL (DisplayArray))[primIndex] =
331 					(GLOBAL (DisplayArray))[ElementPtr0->PrimIndex];
332 			FighterElementPtr->state_flags &= ~PRE_PROCESS;
333 			FighterElementPtr->state_flags |= CHANGING;
334 			FighterElementPtr->next = FighterElementPtr->current;
335 			travel_facing = GetVelocityTravelAngle (
336 					&FighterElementPtr->velocity
337 					);
338 			delta_facing = NORMALIZE_ANGLE (
339 					ARCTAN (pPt1->x - pPt0->x, pPt1->y - pPt0->y)
340 					- travel_facing);
341 			if (delta_facing == 0)
342 			{
343 				if (FighterElementPtr->turn_wait & LEFT)
344 					travel_facing -= QUADRANT;
345 				else
346 					travel_facing += QUADRANT;
347 			}
348 			else if (delta_facing <= HALF_CIRCLE)
349 				travel_facing -= QUADRANT;
350 			else
351 				travel_facing += QUADRANT;
352 
353 			travel_facing = NORMALIZE_FACING (ANGLE_TO_FACING (
354 					NORMALIZE_ANGLE (travel_facing)
355 					));
356 			FighterElementPtr->next.image.frame =
357 					SetAbsFrameIndex (FighterElementPtr->next.image.frame,
358 					travel_facing);
359 			SetVelocityVector (&FighterElementPtr->velocity,
360 					FIGHTER_SPEED, travel_facing);
361 			UnlockElement (hFighterElement);
362 
363 			PutElement (hFighterElement);
364 		}
365 
366 		ElementPtr0->state_flags |= DISAPPEARING | COLLISION;
367 	}
368 	else if (ElementPtr0->pParent != ElementPtr1->pParent)
369 	{
370 		ElementPtr0->blast_offset = 0;
371 		weapon_collision (ElementPtr0, pPt0, ElementPtr1, pPt1);
372 		ElementPtr0->state_flags |= DISAPPEARING | COLLISION;
373 	}
374 	else if (ElementPtr1->state_flags & PLAYER_SHIP)
375 	{
376 		ProcessSound (SetAbsSoundIndex (
377 						/* FIGHTERS_RETURN */
378 				StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 3), ElementPtr1);
379 		DeltaCrew (ElementPtr1, 1);
380 		ElementPtr0->state_flags |= DISAPPEARING | COLLISION;
381 	}
382 
383 	if (ElementPtr0->state_flags & DISAPPEARING)
384 	{
385 		ElementPtr0->state_flags &= ~DISAPPEARING;
386 
387 		ElementPtr0->hit_points = 0;
388 		ElementPtr0->life_span = 0;
389 		ElementPtr0->state_flags |= NONSOLID;
390 
391 		--StarShipPtr->RaceDescPtr->characteristics.special_wait;
392 	}
393 }
394 
395 static void
spawn_fighters(ELEMENT * ElementPtr)396 spawn_fighters (ELEMENT *ElementPtr)
397 {
398 	SIZE i;
399 	COUNT facing;
400 	SIZE delta_x, delta_y;
401 	HELEMENT hFighterElement;
402 	STARSHIP *StarShipPtr;
403 
404 	GetElementStarShip (ElementPtr, &StarShipPtr);
405 	facing = StarShipPtr->ShipFacing + ANGLE_TO_FACING (HALF_CIRCLE);
406 	delta_x = COSINE (FACING_TO_ANGLE (facing), DISPLAY_TO_WORLD (14));
407 	delta_y = SINE (FACING_TO_ANGLE (facing), DISPLAY_TO_WORLD (14));
408 
409 	i = ElementPtr->crew_level > 2 ? 2 : 1;
410 	while (i-- && (hFighterElement = AllocElement ()))
411 	{
412 		SIZE sx, sy;
413 		COUNT fighter_facing;
414 		ELEMENT *FighterElementPtr;
415 
416 		DeltaCrew (ElementPtr, -1);
417 
418 		PutElement (hFighterElement);
419 		LockElement (hFighterElement, &FighterElementPtr);
420 		FighterElementPtr->hit_points = FIGHTER_HITS;
421 		FighterElementPtr->mass_points = FIGHTER_MASS;
422 		FighterElementPtr->thrust_wait = TRACK_THRESHOLD + 1;
423 		FighterElementPtr->playerNr = ElementPtr->playerNr;
424 		FighterElementPtr->state_flags = APPEARING | FINITE_LIFE
425 				| CREW_OBJECT | IGNORE_SIMILAR;
426 		FighterElementPtr->life_span = FIGHTER_LIFE;
427 		SetPrimType (&(GLOBAL (DisplayArray))[FighterElementPtr->PrimIndex],
428 				STAMP_PRIM);
429 		{
430 			FighterElementPtr->preprocess_func = fighter_preprocess;
431 			FighterElementPtr->postprocess_func = 0;
432 			FighterElementPtr->collision_func = fighter_collision;
433 			FighterElementPtr->death_func = NULL;
434 		}
435 
436 		FighterElementPtr->current.location = ElementPtr->next.location;
437 		if (i == 1)
438 		{
439 			FighterElementPtr->turn_wait = LEFT;
440 			fighter_facing = NORMALIZE_FACING (facing + 2);
441 			FighterElementPtr->current.location.x += delta_x - delta_y;
442 			FighterElementPtr->current.location.y += delta_y + delta_x;
443 		}
444 		else
445 		{
446 			FighterElementPtr->turn_wait = RIGHT;
447 			fighter_facing = NORMALIZE_FACING (facing - 2);
448 			FighterElementPtr->current.location.x += delta_x + delta_y;
449 			FighterElementPtr->current.location.y += delta_y - delta_x;
450 		}
451 		sx = COSINE (FACING_TO_ANGLE (fighter_facing),
452 				WORLD_TO_VELOCITY (FIGHTER_SPEED));
453 		sy = SINE (FACING_TO_ANGLE (fighter_facing),
454 				WORLD_TO_VELOCITY (FIGHTER_SPEED));
455 		SetVelocityComponents (&FighterElementPtr->velocity, sx, sy);
456 		FighterElementPtr->current.location.x -= VELOCITY_TO_WORLD (sx);
457 		FighterElementPtr->current.location.y -= VELOCITY_TO_WORLD (sy);
458 
459 		FighterElementPtr->current.image.farray = StarShipPtr->RaceDescPtr->ship_data.special;
460 		FighterElementPtr->current.image.frame =
461 				SetAbsFrameIndex (StarShipPtr->RaceDescPtr->ship_data.special[0],
462 				fighter_facing);
463 		SetElementStarShip (FighterElementPtr, StarShipPtr);
464 		UnlockElement (hFighterElement);
465 	}
466 }
467 
468 static void
urquan_intelligence(ELEMENT * ShipPtr,EVALUATE_DESC * ObjectsOfConcern,COUNT ConcernCounter)469 urquan_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern,
470 		COUNT ConcernCounter)
471 {
472 	EVALUATE_DESC *lpEvalDesc;
473 	STARSHIP *StarShipPtr;
474 
475 	GetElementStarShip (ShipPtr, &StarShipPtr);
476 
477 	 ObjectsOfConcern[ENEMY_SHIP_INDEX].MoveState = PURSUE;
478 	lpEvalDesc = &ObjectsOfConcern[ENEMY_WEAPON_INDEX];
479 	if (lpEvalDesc->ObjectPtr
480 			&& lpEvalDesc->MoveState == ENTICE
481 			&& (!(lpEvalDesc->ObjectPtr->state_flags & CREW_OBJECT)
482 			|| lpEvalDesc->which_turn <= 8)
483 			&& (!(lpEvalDesc->ObjectPtr->state_flags & FINITE_LIFE)
484 			|| (lpEvalDesc->ObjectPtr->mass_points >= 4
485 			&& lpEvalDesc->which_turn == 2
486 			&& ObjectsOfConcern[ENEMY_SHIP_INDEX].which_turn > 16)))
487 		lpEvalDesc->MoveState = PURSUE;
488 
489 	ship_intelligence (ShipPtr,
490 			ObjectsOfConcern, ConcernCounter);
491 
492 	lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX];
493 	{
494 		STARSHIP *EnemyStarShipPtr = NULL;
495 
496 		if (lpEvalDesc->ObjectPtr)
497 			GetElementStarShip (lpEvalDesc->ObjectPtr, &EnemyStarShipPtr);
498 		if (StarShipPtr->special_counter == 0
499 				&& lpEvalDesc->ObjectPtr
500 				&& StarShipPtr->RaceDescPtr->ship_info.crew_level >
501 				(StarShipPtr->RaceDescPtr->ship_info.max_crew >> 2)
502 				&& !(EnemyStarShipPtr->RaceDescPtr->ship_info.ship_flags
503 				& POINT_DEFENSE)
504 				&& (StarShipPtr->RaceDescPtr->characteristics.special_wait < 6
505 				|| (MANEUVERABILITY (
506 						&EnemyStarShipPtr->RaceDescPtr->cyborg_control
507 						) <= SLOW_SHIP
508 				&& !(EnemyStarShipPtr->cur_status_flags & SHIP_BEYOND_MAX_SPEED))
509 				|| (lpEvalDesc->which_turn <= 12
510 				&& (StarShipPtr->ship_input_state & (LEFT | RIGHT))
511 				&& StarShipPtr->RaceDescPtr->ship_info.energy_level >=
512 				(BYTE)(StarShipPtr->RaceDescPtr->ship_info.max_energy >> 1))))
513 			StarShipPtr->ship_input_state |= SPECIAL;
514 		else
515 			StarShipPtr->ship_input_state &= ~SPECIAL;
516 	}
517 
518 	StarShipPtr->RaceDescPtr->characteristics.special_wait = 0;
519 }
520 
521 static void
urquan_postprocess(ELEMENT * ElementPtr)522 urquan_postprocess (ELEMENT *ElementPtr)
523 {
524 	STARSHIP *StarShipPtr;
525 
526 	GetElementStarShip (ElementPtr, &StarShipPtr);
527 	if ((StarShipPtr->cur_status_flags & SPECIAL)
528 			&& ElementPtr->crew_level > 1
529 			&& StarShipPtr->special_counter == 0
530 			&& DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST))
531 	{
532 		ProcessSound (SetAbsSoundIndex (
533 						/* LAUNCH_FIGHTERS */
534 				StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), ElementPtr);
535 		spawn_fighters (ElementPtr);
536 
537 		StarShipPtr->special_counter = SPECIAL_WAIT;
538 	}
539 }
540 
541 RACE_DESC*
init_urquan(void)542 init_urquan (void)
543 {
544 	RACE_DESC *RaceDescPtr;
545 
546 	urquan_desc.postprocess_func = urquan_postprocess;
547 	urquan_desc.init_weapon_func = initialize_fusion;
548 	urquan_desc.cyborg_control.intelligence_func = urquan_intelligence;
549 
550 	RaceDescPtr = &urquan_desc;
551 
552 	return (RaceDescPtr);
553 }
554 
555