#define GAME_SPEED_SCALE 0.1 F64 game_speed, launch_unit_x1, launch_unit_y1, launch_unit_x2, launch_unit_y2, launch_t, return_unit_x1, return_unit_y1, return_unit_x2, return_unit_y2, return_t, set_theta_unit_x1, set_theta_unit_y1, set_theta_unit_x2, set_theta_unit_y2, set_theta_t, next_noise; CTask *main_task; #define OT_CARRIER 0 #define OT_CRUISER 1 #define OT_FIGHTER 2 #define OT_TYPES_NUM 3 #define OF_SHIP 1 #define OF_ACTIVE 2 #define OF_RETURNING 4 #define OF_SHOOTING 8 #define FIRE_WIDTH 56 #define FIRE_HEIGHT 16 #define FIRE_X_SCALE 0.5 #define FIRE_Y_SCALE 0.5 #define FIRE_COLORS 16 U8 fire_colors[FIRE_COLORS] = {YELLOW, YELLOW, LTRED, YELLOW, BLACK, YELLOW, RED, YELLOW, YELLOW, BLACK, YELLOW, LTRED, RED, YELLOW, DKGRAY, YELLOW}; class Obj { Obj *next, *last; Obj *next_in_squadron, *last_in_squadron; Obj *host; U8 player, type; U16 flags; I16 squadron, member_num; F64 x, y, theta, dtheta, speed, turn_rate, life_percent, target_x, target_y, ship_guns, ship_guns_range, air_guns, air_guns_range, fuel, max_fuel, fuel_burn_rate, death_time, next_action_time; I32 torpedos, max_torpedos; F64 torpedos_range; U8 fire[(FIRE_WIDTH * FIRE_HEIGHT + 7) / 8]; } obj_head; class Torpedo { Torpedo *next, *last; Obj *target; F64 x, y, theta, speed, timeout; } torpedo_head; #define SA_PARKED 0 #define SA_LAUNCHING 1 #define SA_FLYING 2 #define SA_SET_theta 3 #define SA_RETURNING 4 #define SA_DEAD 5 class Squadron : Obj { I64 action, dead_mask, total_mask; } *squadrons; U0 SquadronIns(Obj *o, Obj *pred) { Obj *succ = pred->next_in_squadron; o->next_in_squadron = succ; o->last_in_squadron = pred; pred->next_in_squadron = o; succ->last_in_squadron = o; } U0 SquadronRemove(Obj *o) { Obj *pred = o->last_in_squadron, *succ = o->next_in_squadron; pred->next_in_squadron = succ; succ->last_in_squadron = pred; } #define PLAYERS_NUM 2 I64 num_carriers[PLAYERS_NUM] = {2, 3}, num_cruisers[PLAYERS_NUM] = {2, 3}, num_planes_per_squadron[PLAYERS_NUM] = {6, 5}, num_squadrons_per_carrier[PLAYERS_NUM] = {2, 3}, num_alive[PLAYERS_NUM], num_squadrons; Obj *ObjFind(F64 x, F64 y, I64 flag_mask=OF_ACTIVE|OF_RETURNING, I64 flag_val=OF_ACTIVE, I64 type_mask=-1, I64 player_mask=-1, F64 *_d=NULL) { Obj *tmpo = obj_head.next, *best = NULL; F64 dd, best_dd = F64_MAX; while (tmpo != &obj_head) { if (tmpo->flags & flag_mask == flag_val && Bt(&type_mask, tmpo->type) && Bt(&player_mask, tmpo->player)) { dd = Sqr(tmpo->x - x) + Sqr(tmpo->y - y); if (dd < best_dd) { best = tmpo; best_dd = dd; } } tmpo = tmpo->next; } if (_d) *_d = Sqrt(best_dd); return best; } U0 ObjDel(Obj *tmpo) { if (tmpo) { if (tS < tmpo->death_time) tmpo->flags &= ~OF_ACTIVE; else { if (tmpo->squadron >= 0) SquadronRemove(tmpo); QueueRemove(tmpo); if (tmpo->squadron >= 0) LBts(&squadrons[tmpo->squadron].dead_mask, tmpo->member_num); num_alive[tmpo->player]--; Free(tmpo); } } } <1>/* Graphics Not Rendered in HTML */ <2>/* Graphics Not Rendered in HTML */ <3>/* Graphics Not Rendered in HTML */ <4>/* Graphics Not Rendered in HTML */ <5>/* Graphics Not Rendered in HTML */ <6>/* Graphics Not Rendered in HTML */ U8 *imgs[PLAYERS_NUM][OT_TYPES_NUM] = {{<1>, <2>, <3>}, {<4>, <5>, <6>}}; U0 DrawIt(CTask *task, CDC *dc) { I64 i, j, k; F64 d, cur_time = tS; Obj *tmpo; Torpedo *tmpt; tmpt = torpedo_head.next; while (tmpt != &torpedo_head) { dc->color = WHITE; GrPlot(dc, tmpt->x, tmpt->y); tmpt = tmpt->next; } tmpo = obj_head.next; while (tmpo != &obj_head) { if (tmpo->flags & OF_ACTIVE && tmpo->flags & OF_SHIP) { Sprite3ZB(dc, tmpo->x, tmpo->y, 0, imgs[tmpo->player][tmpo->type], tmpo->theta + pi / 2); k = 0; for (j = 0; j < FIRE_HEIGHT; j++) for (i = 0; i < FIRE_WIDTH; i++) if (Bt(tmpo->fire, k++)) { dc->color = fire_colors[ToI64(k + 10 * tS) & (FIRE_COLORS - 1)]; GrPlot(dc, tmpo->x + FIRE_X_SCALE * (i - FIRE_WIDTH / 2 + (11 * tS + i) % 1.7) * Cos(tmpo->theta) - FIRE_Y_SCALE * (j - FIRE_HEIGHT / 2 + (12 * tS + j) % 1.7) * Sin(tmpo->theta), tmpo->y + FIRE_Y_SCALE * (j - FIRE_HEIGHT / 2 + (19 * tS + j) % 1.7) * Cos(tmpo->theta) + FIRE_X_SCALE * (i - FIRE_WIDTH / 2 + (13 * tS + i) % 1.7) * Sin(tmpo->theta)); } if (Blink) { dc->color = BLACK; GrLine(dc, tmpo->x + 5, tmpo->y, tmpo->x + 5 + 10, tmpo->y); if (tmpo->life_percent > 0) { if (tmpo->life_percent < 33) dc->color = RED; else if (tmpo->life_percent < 66) dc->color = YELLOW; else dc->color = GREEN; GrLine(dc, tmpo->x + 5, tmpo->y, tmpo->x + 5 + 10 * tmpo->life_percent / 100, tmpo->y); } dc->color = BLACK; GrLine(dc, tmpo->x + 5, tmpo->y + 2, tmpo->x + 5 + 10, tmpo->y + 2); d = tmpo->fuel * 100 / tmpo->max_fuel; if (d > 0) { if (d < 33) dc->color = RED; else if (d < 66) dc->color = YELLOW; else dc->color = GREEN; GrLine(dc, tmpo->x + 5, tmpo->y + 2, tmpo->x + 5 + 10 * d / 100, tmpo->y + 2); } } } tmpo = tmpo->next; } tmpo = obj_head.next; while (tmpo != &obj_head) { if (tmpo->flags & OF_ACTIVE && !(tmpo->flags & OF_SHIP)) Sprite3ZB(dc, tmpo->x, tmpo->y, 0, imgs[tmpo->player][tmpo->type], tmpo->theta + pi / 2); if (tmpo->flags & OF_SHOOTING) { dc->color = LTRED; GrLine(dc, tmpo->x, tmpo->y, tmpo->target_x, tmpo->target_y, 3); } tmpo = tmpo->next; } dc->flags |= DCF_TRANSFORMATION; if (cur_time < launch_t) { dc->color = LTGREEN; GrArrow3(dc, launch_unit_x1, launch_unit_y1, 0, launch_unit_x2, launch_unit_y2, 0); } if (cur_time < return_t) { dc->color = LTRED; GrArrow3(dc, return_unit_x1, return_unit_y1, 0, return_unit_x2, return_unit_y2, 0); } if (cur_time<set_theta_t) { dc->color = YELLOW; GrArrow3(dc, set_theta_unit_x1, set_theta_unit_y1, 0, set_theta_unit_x2, set_theta_unit_y2, 0); } dc->color = YELLOW; GrPrint(dc, -task->scroll_x, -task->scroll_y, "Game Speed: %5.2f", game_speed); dc->color = LTCYAN; GrPrint(dc, -task->scroll_x, -task->scroll_y + FONT_HEIGHT, "Player 1: %d", num_alive[0]); dc->color = LTPURPLE; GrPrint(dc, -task->scroll_x, -task->scroll_y + 2 * FONT_HEIGHT, "Player 2: %d", num_alive[1]); if ((!num_alive[0] || !num_alive[1]) && Blink) { if (!num_alive[1]) { dc->color = LTGREEN; GrPrint(dc, task->pix_width >> 1 - (FONT_WIDTH * 14) / 2 - task->scroll_x, task->pix_height >> 1 - FONT_HEIGHT / 2 - task->scroll_y, "Game Completed"); } else { dc->color = LTRED; GrPrint(dc, task->pix_width >> 1 - (FONT_WIDTH * 9) / 2 - task->scroll_x, task->pix_height >> 1 - FONT_HEIGHT / 2 - task->scroll_y, "Game Over"); } } } U0 Init() { I64 i, fighter, ship, player, squadron, w = Fs->pix_width, h = Fs->pix_height; Squadron *tmps; Obj *tmpo, *tmpo1; QueueInit(&obj_head); QueueInit(&torpedo_head); next_noise = tS; Fs->scroll_x = 0; Fs->scroll_y = 0; game_speed = 1.0; launch_t = return_t = set_theta_t = 0; main_task = Fs; num_squadrons = 0; for (player = 0; player < PLAYERS_NUM; player++) { num_alive[player] = 0; for (ship = 0; ship < num_cruisers[player]; ship++) { tmpo1 = CAlloc(sizeof(Obj)); num_alive[player]++; tmpo1->type = OT_CRUISER; tmpo1->player = player; tmpo1->squadron = -1; tmpo1->member_num = ship; tmpo1->flags = OF_ACTIVE|OF_SHIP; tmpo1->x = 0.8 * w * (Rand - 0.5) + w >> 1; tmpo1->y = 0.8 * h * (Rand - 0.5) + h >> 1; tmpo1->host = NULL; tmpo1->speed = 35.0; tmpo1->turn_rate = 2.5; tmpo1->theta = 2 * pi * (Rand - 0.5); tmpo1->dtheta = 0; tmpo1->life_percent = 100.0; tmpo1->fuel = tmpo1->max_fuel = 100000; tmpo1->fuel_burn_rate = 100.0; tmpo1->air_guns = 5000; tmpo1->air_guns_range = 30.0; tmpo1->ship_guns = 10000; tmpo1->ship_guns_range = 30.0; tmpo1->torpedos = tmpo1->max_torpedos = 0; tmpo1->torpedos_range = 0.0; tmpo1->next_action_time = 0; QueueInsert(tmpo1, obj_head.last); } for (ship = 0; ship < num_carriers[player]; ship++) { tmpo1 = CAlloc(sizeof(Obj)); num_alive[player]++; tmpo1->type = OT_CARRIER; tmpo1->player = player; tmpo1->squadron = -1; tmpo1->member_num = ship; tmpo1->flags = OF_ACTIVE|OF_SHIP; tmpo1->x = 0.8 * w * (Rand - 0.5) + w >> 1; tmpo1->y = 0.8 * h * (Rand - 0.5) + h >> 1; tmpo1->host = NULL; tmpo1->speed = 28.0; tmpo1->turn_rate = 1.0; tmpo1->theta = 2 * pi * (Rand - 0.5); tmpo1->dtheta = 0; tmpo1->life_percent = 100.0; tmpo1->fuel = tmpo1->max_fuel = 750000; tmpo1->fuel_burn_rate = 500.0; tmpo1->air_guns = 5000; tmpo1->air_guns_range = 20.0; tmpo1->ship_guns = 2000; tmpo1->ship_guns_range = 30.0; tmpo1->torpedos = tmpo1->max_torpedos = 0; tmpo1->torpedos_range = 0.0; tmpo1->next_action_time = 0; QueueInsert(tmpo1, obj_head.last); for (squadron = 0; squadron < num_squadrons_per_carrier[player]; squadron++, num_squadrons++) { for (fighter = 0; fighter < num_planes_per_squadron[player]; fighter++) { tmpo = CAlloc(sizeof(Obj)); num_alive[player]++; tmpo->type = OT_FIGHTER; tmpo->player = player; tmpo->squadron = num_squadrons; tmpo->member_num = fighter; tmpo->flags = 0; tmpo->host = tmpo1; tmpo->speed = 300.0; tmpo->turn_rate = 25.0; tmpo->life_percent = 100.0; tmpo->fuel = tmpo->max_fuel = 1000; tmpo->fuel_burn_rate = 1.0; tmpo->air_guns = 35000; tmpo->air_guns_range = 8.0; tmpo->ship_guns = 0; tmpo->ship_guns_range = 0.0; tmpo->torpedos = tmpo->max_torpedos = 1; tmpo->torpedos_range = 20.0; QueueInsert(tmpo, obj_head.last); } } } } squadrons = CAlloc(num_squadrons * sizeof(Squadron)); for (i = 0, tmps = squadrons; i < num_squadrons; i++, tmps++) { tmps->next_in_squadron = tmps->last_in_squadron = tmps; tmps->squadron = i; } tmpo = obj_head.next; while (tmpo != &obj_head) { if (tmpo->squadron >= 0) { tmps = &squadrons[tmpo->squadron]; tmps->host = tmpo->host; tmps->player = tmpo->player; tmps->total_mask = 1 << num_planes_per_squadron[tmpo->player] - 1; SquadronIns(tmpo, tmps->last_in_squadron); } tmpo = tmpo->next; } } U0 CleanUp() { QueueDel(&obj_head, TRUE); QueueDel(&torpedo_head, TRUE); Free(squadrons); } Obj *ObjLaunch(I64 player, I64 squadron=-1, Obj *host=NULL, F64 x=F64_MAX, F64 y=F64_MAX, F64 theta=F64_MAX) { Obj *tmpo; F64 cur_time = tS; if (!host) host = ObjFind(x, y,,, 1 << OT_CARRIER, 1 << player); if (host && cur_time>host->next_action_time) { if (theta == F64_MAX) theta = Arg(x - host->x, y - host->y); tmpo = obj_head.next; while (tmpo != &obj_head) { if (tmpo->host == host && (squadron < 0 || tmpo->squadron == squadron) && !(tmpo->flags & OF_ACTIVE) && (tmpo->squadron < 0 || squadrons[tmpo->squadron].action == SA_PARKED || squadrons[tmpo->squadron].action == SA_LAUNCHING)) { if (tmpo->fuel <= 0.0) //When low on fuel, not zero, gets launched and captured. LBts(&squadrons[tmpo->squadron].dead_mask, tmpo->member_num); else { tmpo->flags = tmpo->flags & ~OF_RETURNING | OF_ACTIVE; tmpo->theta = host->theta; if (x == F64_MAX || y == F64_MAX || Sqr(x - host->x) + Sqr(y - host->y) > 3 * 3) tmpo->dtheta = Wrap(theta - tmpo->theta, -pi); else tmpo->dtheta = 0; tmpo->x = host->x; tmpo->y = host->y; host->next_action_time = cur_time + 0.25 / game_speed; return tmpo; } } tmpo = tmpo->next; } } return NULL; } Squadron *SquadronLaunch(I64 player, F64 x=F64_MAX, F64 y=F64_MAX) { Squadron *tmps; Obj *tmpo; if (tmpo = ObjLaunch(player,,, x, y)) { if (player == 0) { launch_unit_x1 = tmpo->x; launch_unit_y1 = tmpo->y; launch_unit_x2 = mouse.pos.x - main_task->pix_left - main_task->scroll_x; launch_unit_y2 = mouse.pos.y - main_task->pix_top - main_task->scroll_y; launch_t = tS + 0.5; } if (tmpo->squadron >= 0) { tmps = &squadrons[tmpo->squadron]; if (tmps->action == SA_PARKED) { tmps->action = SA_LAUNCHING; tmps->theta = tmpo->theta + tmpo->dtheta; } return tmps; } } return NULL; } Obj *ObjReturn(I64 player, F64 x, F64 y) { Obj *tmpo; if (tmpo = ObjFind(x, y, OF_ACTIVE, OF_ACTIVE, 1 << OT_FIGHTER, 1 << player)) tmpo->flags |= OF_RETURNING; return tmpo; } Squadron *SquadronReturn(I64 player, F64 x, F64 y) { Squadron *tmps; Obj *tmpo; if (tmpo = ObjReturn(player, x, y)) { if (player == 0) { return_unit_x1 = tmpo->x; return_unit_y1 = tmpo->y; if (tmpo->host) { return_unit_x2 = tmpo->host->x; return_unit_y2 = tmpo->host->y; return_t = tS + 0.5; } } if (tmpo->squadron >= 0) { tmps = &squadrons[tmpo->squadron]; if (tmps->action == SA_FLYING) tmps->action = SA_RETURNING; return tmps; } } return NULL; } Obj *ObjSettheta(I64 player, F64 x=F64_MAX, F64 y=F64_MAX, F64 theta=F64_MAX) { Obj *tmpo; if ((tmpo = ObjFind(x, y,,,, 1 << player)) && tmpo->flags & OF_ACTIVE && !(tmpo->flags & OF_RETURNING)) { if (theta == F64_MAX) theta = Arg(x - tmpo->x, y - tmpo->y); tmpo->dtheta += Wrap(theta - (tmpo->theta + tmpo->dtheta), -pi); return tmpo; } return NULL; } Squadron *SquadronSettheta(I64 player, F64 x=F64_MAX, F64 y=F64_MAX, F64 theta=F64_MAX) { Squadron *tmps; Obj *tmpo; if (tmpo = ObjSettheta(player, x, y, theta)) { if (player == 0) { set_theta_unit_x1 = tmpo->x; set_theta_unit_y1 = tmpo->y; set_theta_unit_x2 = mouse.pos.x - main_task->pix_left - main_task->scroll_x; set_theta_unit_y2 = mouse.pos.y - main_task->pix_top - main_task->scroll_y; set_theta_t = tS + 0.5; } if (tmpo->squadron >= 0) { tmps = &squadrons[tmpo->squadron]; if (tmps->action == SA_FLYING) { tmps->action = SA_SET_theta; tmps->theta = tmpo->theta + tmpo->dtheta; } return tmps; } } return NULL; } U0 SquadronActions() { I64 i, completed_mask; Obj *tmpo; Squadron *tmps; for (i = 0, tmps = squadrons; i < num_squadrons; i++, tmps++) { completed_mask = 0; switch (tmps->action) { case SA_LAUNCHING: ObjLaunch(tmps->player, i, tmps->host,,, tmps->theta); tmpo = tmps->next_in_squadron; while (tmpo != tmps) { LBEqual(&completed_mask, tmpo->member_num, tmpo->flags & OF_ACTIVE); tmpo = tmpo->next_in_squadron; } if (completed_mask | tmps->dead_mask == tmps->total_mask) tmps->action = SA_FLYING; break; case SA_FLYING: tmpo = tmps->next_in_squadron; while (tmpo != tmps) { LBEqual(&completed_mask, tmpo->member_num, !(tmpo->flags & OF_ACTIVE)); tmpo = tmpo->next_in_squadron; } if (completed_mask | tmps->dead_mask == tmps->total_mask) tmps->action = SA_PARKED; break; case SA_SET_theta: tmpo = tmps->next_in_squadron; while (tmpo != tmps) { tmpo->dtheta += Wrap(tmps->theta - (tmpo->theta + tmpo->dtheta), -pi); tmpo = tmpo->next_in_squadron; } tmps->action = SA_FLYING; break; case SA_RETURNING: tmpo = tmps->next_in_squadron; while (tmpo != tmps) { tmpo->flags |= OF_RETURNING; LBEqual(&completed_mask, tmpo->member_num, !(tmpo->flags & OF_ACTIVE)); tmpo = tmpo->next_in_squadron; } if (completed_mask | tmps->dead_mask == tmps->total_mask) tmps->action = SA_PARKED; break; } if (tmps->dead_mask == tmps->total_mask) tmps->action=SA_DEAD; } } U0 AI(I64 player, F64 period) { Obj *tmpo; tmpo = obj_head.next; while (tmpo != &obj_head) { if (tmpo->player == player) { if (tmpo->type == OT_CARRIER && Rand < 5 * period) SquadronLaunch(player, tmpo->x, tmpo->y); if (tmpo->flags&OF_ACTIVE && !(tmpo->flags&OF_RETURNING) && Rand < 10.0 * period) SquadronSettheta(player, tmpo->x, tmpo->y, tmpo->theta + pi / 2 * (Rand - 0.5)); } tmpo = tmpo->next; } } U0 ShipDamage(Obj *tmpo, F64 d) { I64 i, x = Rand * FIRE_WIDTH, y = Rand * FIRE_HEIGHT; tmpo->life_percent -= d; while (d > 0) { if (!Bts(tmpo->fire, y * FIRE_WIDTH + x)) d -= 500.0 / (FIRE_WIDTH * FIRE_HEIGHT); else d -= 25.0 / (FIRE_WIDTH * FIRE_HEIGHT); i = RandI16 & 7; x += gr_x_offsets[i]; y += gr_y_offsets[i]; while (x >= FIRE_WIDTH) x -= FIRE_WIDTH; while (x < 0) x += FIRE_WIDTH; while (y >= FIRE_HEIGHT) y -= FIRE_HEIGHT; while (y < 0) y += FIRE_HEIGHT; } } U0 ShipFix(Obj *tmpo, F64 d) { tmpo->life_percent += d; if (tmpo->life_percent >= 100.0) { tmpo->life_percent = 100.0; MemSet(tmpo->fire, 0, sizeof(Obj.fire)); return; } while (d > 0) if (Btr(tmpo->fire, FIRE_WIDTH * FIRE_HEIGHT * Rand)) d -= 400.0 / (FIRE_WIDTH * FIRE_HEIGHT); else d -= 20.0 / (FIRE_WIDTH * FIRE_HEIGHT); } U0 MyNoise(I64 mS, F64 min_ona, F64 max_ona) {//Make white noise for given number of mS. // See Noise. On bare-metal, Spawn() hogs CPU. CSoundEffectFrame *ns; if (mS > 0) { ns = MAlloc(sizeof(CSoundEffectFrame)); ns->type = SE_NOISE; ns->duration = mS / 1000.0; ns->ona1 = min_ona; ns->ona2 = max_ona; music.mute++; SoundEffectTask(ns); Sound; } return; } U0 Combat(F64 period) { F64 d; Obj *tmpo, *tmpo1; Torpedo *tmpt; tmpo = obj_head.next; while (tmpo != &obj_head) { tmpo->flags &= ~OF_SHOOTING; if (tmpo->flags & OF_ACTIVE && (tmpo1 = ObjFind(tmpo->x, tmpo->y, OF_ACTIVE, OF_ACTIVE,, 1 << (tmpo->player ^ 1), &d))) { tmpo->target_x = tmpo1->x; tmpo->target_y = tmpo1->y; if (tmpo1->flags & OF_SHIP) { if (tmpo->torpedos && d < tmpo->torpedos_range && Rand < 125 * period) { tmpo->torpedos--; tmpt = CAlloc(sizeof(Torpedo)); tmpt->x = tmpo->x; tmpt->y = tmpo->y; tmpt->speed = 100; d /= tmpt->speed * (GAME_SPEED_SCALE * game_speed); tmpo1->death_time = tmpt->timeout = tS + d; tmpt->target = tmpo1; tmpt->theta = Arg(tmpo1->x - tmpo->x, tmpo1->y - tmpo->y); QueueInsert(tmpt, torpedo_head.last); Sweep(2000, 86, 53); } else if (tmpo->ship_guns > 0 && d < tmpo->ship_guns_range) { tmpo->flags |= OF_SHOOTING; if (Rand < 125.0 * period) { ShipDamage(tmpo1, tmpo->ship_guns * Rand * period); if (Rand < 10.0 * period) tmpo1->fuel *= 0.75 * Rand + 0.25; } if (tS > next_noise) { MyNoise(100, 29, 46); next_noise = tS + 0.1; } } } else { if (tmpo->air_guns > 0 && d < tmpo->air_guns_range) { tmpo->flags |= OF_SHOOTING; if (Rand<125.0 * period) { tmpo1->life_percent -= tmpo->air_guns * Rand * period; if (Rand < 10.0 * period) tmpo1->fuel *= 0.75 * Rand + 0.25; } if (tS > next_noise) { MyNoise(25, 62, 86); next_noise = tS + 0.025; } } } } tmpo = tmpo->next; } tmpo = obj_head.next; while (tmpo != &obj_head) { tmpo1 = tmpo->next; if (tmpo->type == OT_FIGHTER && (tmpo->life_percent <= 0.0 || tmpo->flags & OF_ACTIVE && tmpo->fuel <= 0.0 || tmpo->host && !(tmpo->flags & OF_ACTIVE) && tmpo->host->life_percent <= 0.0)) ObjDel(tmpo); tmpo = tmpo1; } tmpo = obj_head.next; while (tmpo != &obj_head) { tmpo1 = tmpo->next; if (tmpo->life_percent <= 0.0) ObjDel(tmpo); tmpo = tmpo1; } } #define ANIMATE_FREQ 50 U0 AnimateTask(I64) { Obj *tmpo; Torpedo *tmpt, *tmpt1; F64 d, period; while (TRUE) { period = GAME_SPEED_SCALE * game_speed / ANIMATE_FREQ; SquadronActions; tmpo = obj_head.next; while (tmpo != &obj_head) { if (tmpo->flags & OF_ACTIVE && tmpo->fuel > 0) { if (tmpo->dtheta) { d = tmpo->dtheta; if (d > tmpo->turn_rate * period) d = tmpo->turn_rate * period; if (d < -tmpo->turn_rate * period) d = -tmpo->turn_rate * period; tmpo->theta += d; tmpo->dtheta -= d; } tmpo->x += tmpo->speed * Cos(tmpo->theta) * period * tmpo->life_percent / 100.0; tmpo->y += tmpo->speed * Sin(tmpo->theta) * period * tmpo->life_percent / 100.0; tmpo->fuel -= tmpo->speed * tmpo->fuel_burn_rate * period; } tmpo = tmpo->next; } tmpt = torpedo_head.next; while (tmpt != &torpedo_head) { tmpt1 = tmpt->next; if (tS > tmpt->timeout) { tmpo = tmpt->target; if (Rand < 0.333333) { ShipDamage(tmpo, 150 * Rand * Rand); if (Rand < 0.333333) tmpo->fuel *= 0.75 * Rand + 0.25; } QueueRemove(tmpt); Free(tmpt); } else { tmpt->x += tmpt->speed * Cos(tmpt->theta) * period; tmpt->y += tmpt->speed * Sin(tmpt->theta) * period; } tmpt = tmpt1; } tmpo = obj_head.next; while (tmpo != &obj_head) { if (tmpo->host && !(tmpo->flags & OF_ACTIVE)) { tmpo->x = tmpo->host->x; tmpo->y = tmpo->host->y; } tmpo = tmpo->next; } tmpo = obj_head.next; while (tmpo != &obj_head) { if (tmpo->flags & OF_ACTIVE) { if (tmpo->host) { d = Sqrt(Sqr(tmpo->x - tmpo->host->x) + Sqr(tmpo->y - tmpo->host->y)); if (d < 8 && tmpo->max_fuel - tmpo->fuel > 30) { tmpo->life_percent = 100.0; if (tmpo->host->fuel > 0) { d = tmpo->max_fuel - tmpo->fuel; if (d > tmpo->host->fuel) d = tmpo->host->fuel; tmpo->host->fuel -= d; tmpo->fuel += d; } tmpo->torpedos = tmpo->max_torpedos; tmpo->x = tmpo->host->x; tmpo->y = tmpo->host->y; tmpo->flags &= ~OF_ACTIVE; } else if (d > tmpo->fuel - 250) tmpo->flags |= OF_RETURNING; if (tmpo->flags & OF_RETURNING) tmpo->dtheta += Wrap(Arg(tmpo->host->x - tmpo->x, tmpo->host->y - tmpo->y) - (tmpo->theta + tmpo->dtheta), -pi); } else if (tmpo->type == OT_CARRIER) ShipFix(tmpo, 2.5 * period); } tmpo = tmpo->next; } AI(1, period); Combat(period); Sleep(1000 / ANIMATE_FREQ); } } U0 FlatTops() { I64 arg1, arg2; SettingsPush; //See SettingsPush Fs->text_attr = BLUE << 4 + WHITE; AutoComplete; WinBorder; WinMax; DocCursor; DocClear; PopUpOk("$GREEN${Left-Mouse}$FG$\t\tChange Course\n" "$GREEN${Right-Mouse}$FG$\t\tLaunch Squadron\n" "$GREEN${Right-Double-Mouse}$FG$\tReturn Squadron\n" "$GREEN${Ctrl-Left Grab}$FG$\tScroll Screen\n"); MenuPush( "File {" " Abort(,CH_SHIFT_ESC);" " Exit(,CH_ESC);" "}" "Play {" " Restart(,'\n');" " Faster(,'+');" " Slower(,'-');" "}" ); Fs->win_inhibit |= WIF_SELF_MS_L | WIF_SELF_MS_R; Init; Fs->draw_it = &DrawIt; Fs->animate_task = Spawn(&AnimateTask, NULL, "Animate",, Fs); try { while (TRUE) switch (MessageGet(&arg1, &arg2, 1 << MESSAGE_KEY_DOWN | 1 << MESSAGE_MS_L_UP | 1 << MESSAGE_MS_R_UP | 1 << MESSAGE_MS_R_D_UP)) { case MESSAGE_KEY_DOWN: switch (arg1) { case '\n': CleanUp; Init; break; case CH_ESC: case CH_SHIFT_ESC: goto nv_done; case '+': game_speed *= 1.5; break; case '-': game_speed /= 1.5; break; } break; case MESSAGE_MS_L_UP: SquadronSettheta(0, arg1, arg2); break; case MESSAGE_MS_R_UP: SquadronLaunch(0, arg1, arg2); break; case MESSAGE_MS_R_D_UP: SquadronReturn(0, arg1, arg2); break; } nv_done: MessageGet(,, 1 << MESSAGE_KEY_UP); } catch PutExcept; SettingsPop; CleanUp; MenuPop; } FlatTops; //Maybe use this in the future <7>/* Graphics Not Rendered in HTML */