//Uses fixed-point. RegDefault("ZealOS/Talons", "F64 best_score=9999;\n"); RegExe("ZealOS/Talons"); //Keep these power of two so shift is used instead of multiply //to index arrays. #define MAP_WIDTH 1024 #define MAP_HEIGHT 1024 #define MAP_SCALE 150 #define DISPLAY_SCALE 100 #define CTRLS_SCALE 0.05 //Terry thought he did these so the heads-up showed intelligable numbers. //Scaling is a mess. #define COORDINATE_SCALE 256 #define COORDINATE_BITS 8 #define WATER_ELEVATION 15 #define BIRD_ELEVATION 10 #define ROCK_ELEVATION 45 #define SNOW_ELEVATION 55 //Too big makes off-screen draws take place. #define PANEL_SIZE_MAX 16 <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 */ #define LS_TYPES 3 U8 *landscape_small_imgs[LS_TYPES] = {<4>, <5>, <6>}, *landscape_large_imgs[LS_TYPES]; #define B_NUM 256 class Bird { Bird *next, *last; CD3I64 p; F64 theta; } b_head[mp_count]; class Obj { Obj *next, *last; CD3I64 p; U8 *img; Bool fish; }; class Panel {//Polygon or Obj Panel *next; CD3I32 *pts; I64 count; U16 update, num_sides; CColorROPU32 color; Obj *next_obj, *last_obj; } *panel_head, *panels[MAP_HEIGHT][MAP_WIDTH]; I64 critical_section_flag; I16 elevations[MAP_HEIGHT][MAP_WIDTH]; CD3 normals[MAP_HEIGHT][MAP_WIDTH]; class MPCtrl { I64 init_not_done_flags, update_not_done_flags, app_not_done_flags; I64 strip_width[MP_PROCESSORS_NUM]; Bool app_done; } mp; F64 game_t0, game_tf, pitch, roll, heading, phi, speed; Bool invert_pitch, rolled_over; I64 strip_height, x, y, z, fish_left; CD3 v; U0 WrapAngles() { I64 r[4][4], x, y, z; phi = Wrap(phi); pitch = Wrap(-phi - pi / 2); if (Abs(pitch) > pi / 2) { invert_pitch = TRUE; pitch = Wrap(pi - pitch); } else invert_pitch = FALSE; roll = Wrap(roll); if (invert_pitch ^^ -pi / 2 <= roll < pi / 2) rolled_over = FALSE; else rolled_over = TRUE; heading = Wrap(heading, 0); //World to screen coordinates Mat4x4IdentEqu(r); Mat4x4RotZ(r, heading); Mat4x4RotX(r, phi); Mat4x4RotZ(r, roll); //We use velocity vector for dog-fighting. x = 0x100000000 * speed; y = 0; z = 0; Mat4x4MulXYZ(r, &x, &y, &z); v.x = x / ToF64(0x100000000); v.y = y / ToF64(0x100000000); v.z = z / ToF64(0x100000000); } U0 EDTransform(CDC *dc, I64 *x, I64 *y, I64 *z) { I64 zz; Mat4x4MulXYZ(dc->r, x, y, z); *z = zz = -*z; if (zz > 0) { *x = dc->x + *x * DISPLAY_SCALE / zz; //Foreshortening *y = dc->y - *y * DISPLAY_SCALE / zz; } else { *x = dc->x + *x; *y = dc->y - *y; } } U0 CalcNormals() {/*Find the normal vect with a curl. i,j and k are the axis unit vectors, not to be confused with local index variables. i j k 0 1 dz2 1 0 dz1 Normal: dz1*i + dz2*j - k */ I64 i, j; for (j = 0; j < MAP_HEIGHT - 1; j++) { for (i = 0; i < MAP_WIDTH - 1; i++) { normals[j][i].x = elevations[j][i + 1] - elevations[j][i]; normals[j][i].y = elevations[j + 1][i] - elevations[j][i]; normals[j][i].z = -1; D3Unit(&normals[j][i]); } MemSet(&normals[j][i], 0, sizeof(CD3)); } for (i = 0; i < MAP_WIDTH - 1; i++) MemSet(&normals[j][i], 0, sizeof(CD3)); } Bool TestSameSlope(I64 x, I64 y, I64 w, I64 h) { CD3 p, *s; I64 k1, k2; if (!(0 <= x && x + w < MAP_WIDTH && 0 <= y && y + h < MAP_HEIGHT)) return FALSE; s = &normals[y][x]; for (k2 = 0; k2 < h; k2++) for (k1 = 0; k1 < w; k1++) if (D3NormSqr(D3Sub(&p, &normals[y + k2][x + k1], s)) > .10) return FALSE; return TRUE; } U0 MPDoPanels(CTask *task) { I64 i, j, l, k1, k2, w, h, threshold, lo, hi; Bool cont; Panel *tmpp, *start_ptr = NULL, *end_ptr = NULL; CD3I32 *poly; Obj *tmpo; lo = Gs->num * (MAP_HEIGHT - 1) / mp_count; hi = (Gs->num + 1) * (MAP_HEIGHT - 1) / mp_count; for (threshold = 8; threshold >= 1; threshold--) for (j = lo; j < hi; j++) { for (i = 0; i < MAP_WIDTH - 1; i++) { if (!panels[j][i]) { w = 1; h = 1; do { cont = FALSE; if (w < PANEL_SIZE_MAX && TestSameSlope(i, j, w + 1, h)) { w++; cont = TRUE; } if (h < PANEL_SIZE_MAX && TestSameSlope(i, j, w, h + 1)) { h++; cont = TRUE; } } while (cont); if (w >= threshold || h >= threshold) { tmpp = CAlloc(sizeof(Panel), task); QueueInit(&tmpp->next_obj); l = elevations[j][i]; if (l <= WATER_ELEVATION * MAP_SCALE && elevations[j][i + w - 1] <= WATER_ELEVATION * MAP_SCALE && elevations[j + h - 1][i] <= WATER_ELEVATION * MAP_SCALE && elevations[j + h - 1][i + w - 1] <= WATER_ELEVATION * MAP_SCALE) { tmpp->color = BLUE; if (Rand < 0.05) { tmpo = MAlloc(sizeof(Obj), task); tmpo->p.x = (i + w / 2) * MAP_SCALE; tmpo->p.y = (j + h / 2) * MAP_SCALE; if (Rand < 0.1) { tmpo->fish = FALSE; if (RandI16 & 1) tmpo->img = landscape_large_imgs[0]; //Boat else tmpo->img = landscape_large_imgs[1]; //Boat tmpo->p.z = (WATER_ELEVATION + 2) * MAP_SCALE; } else { tmpo->fish = TRUE; tmpo->img = <1>; //Fish tmpo->p.z = WATER_ELEVATION * MAP_SCALE; } QueueInsert(tmpo, tmpp->last_obj); } } else { if (l < ROCK_ELEVATION * MAP_SCALE) { if (RandI16 & 1) tmpp->color = LTGREEN; else tmpp->color = GREEN + LTGREEN << 16 + ROPF_DITHER; if (Rand < 0.03) { tmpo = MAlloc(sizeof(Obj),task); tmpo->p.x = (i + w / 2) * MAP_SCALE; tmpo->p.y = (j + h / 2) * MAP_SCALE; tmpo->p.z = l; tmpo->img = landscape_large_imgs[2]; //Tree tmpo->fish = FALSE; QueueInsert(tmpo, tmpp->last_obj); } } else if (l < SNOW_ELEVATION * MAP_SCALE) { if (!(RandU16 & 3)) { if (RandI16 & 1) tmpp->color = LTGRAY; else tmpp->color = DKGRAY + LTGRAY << 16 + ROPF_DITHER; } else { if (RandI16 & 1) tmpp->color = LTGREEN; else tmpp->color = GREEN + LTGREEN << 16 + ROPF_DITHER; } } else { if (!(RandU16 & 3)) { if (RandI16 & 1) tmpp->color = WHITE; else tmpp->color = LTGRAY; } else { if (RandI16 & 1) tmpp->color = LTGRAY + WHITE << 16 + ROPF_DITHER; else tmpp->color = DKGRAY + LTGRAY << 16 + ROPF_DITHER; } } } tmpp->num_sides = 4; poly = tmpp->pts = MAlloc(sizeof(CD3I32) * tmpp->num_sides, task); poly[0].x = MAP_SCALE * i; poly[0].y = MAP_SCALE * j; poly[0].z = elevations[j][i]; poly[1].x = MAP_SCALE * (i + w); poly[1].y = MAP_SCALE * j; poly[1].z = elevations[j][i + w]; poly[2].x = MAP_SCALE * (i + w); poly[2].y = MAP_SCALE * (j + h); poly[2].z = elevations[j + h][i + w]; poly[3].x = MAP_SCALE * i; poly[3].y = MAP_SCALE * (j + h); poly[3].z = elevations[j + h][i]; tmpp->next = start_ptr; start_ptr = tmpp; if (!end_ptr) end_ptr = tmpp; for (k2 = 0; k2 < h; k2++) for (k1 = 0; k1 < w; k1++) panels[j + k2][i + k1] = tmpp; } } } } if (end_ptr) { while (LBts(&critical_section_flag, 0)) Yield; if (end_ptr) end_ptr->next = panel_head; panel_head = start_ptr; LBtr(&critical_section_flag, 0); } LBtr(&mp.init_not_done_flags, Gs->num); } U0 InitElevations() { I64 i, j, l, x, y, xx, yy, x1, y1, x2, y2; MemSet(elevations, 0, sizeof(elevations)); for (i = 0; i < MAP_WIDTH * MAP_HEIGHT / 128; i++) { x = RandU32 % MAP_WIDTH; y = RandU32 % MAP_HEIGHT; j = 1 << (RandU32 % 6); l = 0; while (j--) { if (!l && RandU16 < U16_MAX / 4) l = RandU16 % (j + 1); if (l) { x1 = ClampI64(x - j, 0, MAP_WIDTH - 1); x2 = ClampI64(x + j, 0, MAP_WIDTH - 1); y1 = ClampI64(y - j, 0, MAP_HEIGHT - 1); y2 = ClampI64(y + j, 0, MAP_HEIGHT - 1); for (yy = y1; yy < y2; yy++) for (xx = x1; xx < x2; xx++) elevations[yy][xx] += MAP_SCALE / 2; l--; } } } for (j = 0; j < MAP_HEIGHT; j++) for (i = 0; i < MAP_WIDTH; i++) if (elevations[j][i] < WATER_ELEVATION * MAP_SCALE) elevations[j][i] = WATER_ELEVATION * MAP_SCALE; } U0 InitMap() {/*We make a topographic data structure "elevations[][]" and convert it to panels. "panels[][]" holds the panels for each spot. */ I64 i; InitElevations; MemSet(panels, 0, sizeof(panels)); CalcNormals; panel_head = NULL; mp.init_not_done_flags = 1 << mp_count - 1; for (i = 0; i < mp_count; i++) Spawn(&MPDoPanels, Fs, "Do Panels", i); while (mp.init_not_done_flags) Sleep(1); } F64 claws_down; #define HAND_X (1.0 - claws_down) * (0.3 * w) + claws_down * (0.4 * w) #define HAND_Y (1.0 - claws_down) * (h - 125) + claws_down * h <7>/* Graphics Not Rendered in HTML */ <8>/* Graphics Not Rendered in HTML */ U0 ClawDraw(CDC *dc, I64 x1, I64 y1, I64 x2, I64 y2, I64 w, I64 segments, Bool talon) { I64 i, j; for (i = 0, j = segments; i < segments; i++,j--) { dc->thick = w; dc->color = BLACK; GrLine3(dc, j * x1 / segments + i * x2 / segments, j * y1 / segments + i * y2 / segments, 0, (j - 1) * x1 / segments + (i + 1) * x2 / segments, (j - 1) * y1 / segments + (i + 1) * y2 / segments, 0); dc->thick = w - 2; dc->color = YELLOW; GrLine3(dc, j * x1 / segments + i * x2 / segments, j * y1 / segments + i * y2 / segments, 0, (j - 1) * x1 / segments + (i + 1) * x2 / segments, (j - 1) * y1 / segments + (i + 1) * y2 / segments, 0); } if (talon) { if (y1 < y2) Sprite3B(dc, x1, y1, 0, <7>); else Sprite3B(dc, x1, y1, 0, <8>); } } U0 ClawsDraw(CTask *task, CDC *dc) { F64 claws_up = 1.0 - claws_down; I64 w = task->pix_width, h = task->pix_height; dc->flags |= DCF_SYMMETRY; DCSymmetrySet(dc, w >> 1, 0, w >> 1, 1); ClawDraw(dc, HAND_X - 30, HAND_Y - 50 * claws_up, HAND_X - 5, HAND_Y, 22, 4, TRUE); ClawDraw(dc, HAND_X - 10, HAND_Y - 60 * claws_up, HAND_X, HAND_Y, 22, 4, TRUE); ClawDraw(dc, HAND_X + 10, HAND_Y - 60 * claws_up, HAND_X, HAND_Y, 22, 4, TRUE); ClawDraw(dc, HAND_X + 30, HAND_Y - 50 * claws_up, HAND_X + 5, HAND_Y, 22, 4, TRUE); ClawDraw(dc, HAND_X + 25, HAND_Y + 40 * claws_up, HAND_X + 5, HAND_Y, 22, 4, TRUE); ClawDraw(dc, HAND_X, HAND_Y, 6 * w / 20, h, 38, 5, FALSE); } CDC *main_dc; U0 DrawIt(CTask *task, CDC *dc) { main_dc->flags |= DCF_NO_TRANSPARENTS; GrBlot(dc, 0, 0, main_dc); if (claws_down) ClawsDraw(task, dc); } /* <9>/* Graphics Not Rendered in HTML */ <10>/* Graphics Not Rendered in HTML */ Cores render strips that +/- 15%. The cores check the panel map array and render the panel for each square, marking-it done. The depth buf is not locked in the graphic routines so we get some glitches. */ I64 update_jiffy_limit; U0 MPDrawIt(CTask *task, CDC *dc) { I64 j, update = winmgr.updates & 65535, strip_width, *s2w, x1, y1, z1, xx, yy, xh, yh, zh, yh2, xh2, x1h, y1h, x1wa, y1wa, x1wb, y1wb, x3, y3, z3, dd, dd_old, cx = task->pix_width >> 1, cy = task->pix_height >> 1, r[16], *elems1, *elems_hard; Panel reg *tmpp; Bird *tmpb; Obj *tmpo; Bool w_on_map, h_on_map; xx = x / (MAP_SCALE * COORDINATE_SCALE); yy = y / (MAP_SCALE * COORDINATE_SCALE); //World to screen coordinates Mat4x4IdentEqu(dc->r); Mat4x4RotZ(dc->r, heading); Mat4x4RotX(dc->r, phi); Mat4x4RotZ(dc->r, roll); DCMat4x4Set(dc, dc->r); //Screen to world coordinates //This gives us the vects for stepping through the grid in //the direction the plane is facing. we step horizontally and vertically //and use the reciprocal slope principle //y=mx+b and y=(-1/m)x+b are perpendicular. s2w = Mat4x4IdentNew; Mat4x4RotZ(s2w, -roll); Mat4x4RotX(s2w, -phi); Mat4x4RotZ(s2w, -heading); xh = 0; yh = 0; zh = -256; Mat4x4MulXYZ(s2w, &xh, &yh, &zh); //The layer for core1 is not cleared automatically //it is persistent. Terry carefully syncronized the update //cycle initiated by Core0 to prevent flicker. dc->flags |= DCF_TRANSFORMATION; dc->transform = &EDTransform; dc->x = cx; dc->y = cy; //dc->x and the translation part of dc->r are ident in effect, //but we use both to show-off. We could add offsets together and //use one or the other. x1 = -x >> COORDINATE_BITS; y1 = -y >> COORDINATE_BITS; z1 = -z >> COORDINATE_BITS; Mat4x4MulXYZ(dc->r, &x1, &y1, &z1); Mat4x4TranslationEqu(dc->r, x1, y1, z1); //This is a refinement. if (Abs(phi * 180 / pi) > 90) { x3 = 0; y3 = -cy; z3 = 0; Mat4x4MulXYZ(s2w, &x3, &y3, &z3); xx += x3; yy += y3; } if (Gs->num & 1) {//alt left-right,right-left yh2 = -yh; xh2 = -xh; } else { yh2 = yh; xh2 = xh; } //Calc starting point. x1wa = xx << 8 + xh * strip_height >> 1 / 1.3 * (Gs->num + 1.15); y1wa = yy << 8 + yh * strip_height >> 1 / 1.3 * (Gs->num + 1.15); x1wb = 0; y1wb = 0; xh = -xh; //Back to front to help with depth. yh = -yh; //Take half steps to cover whole grid. xh >>= 1; yh >>= 1; xh2 >>= 1; yh2 >>= 1; w_on_map = FALSE; dd_old = I64_MAX; for (strip_width = 0; counts.jiffies < update_jiffy_limit; strip_width++) { x1h = x1wa; y1h = y1wa; h_on_map = FALSE; for (j = 0; j < strip_height && counts.jiffies < update_jiffy_limit; j++) { x1 = x1h >> 8; y1 = y1h >> 8; if (0 <= x1 < MAP_WIDTH && 0 <= y1 < MAP_HEIGHT) { if ((tmpp = panels[y1][x1]) && tmpp->update != update) { tmpp->update = update; if (tmpp->count > 8 * (1.1 - Gs->idle_factor)) { dc->color = tmpp->color; tmpp->count = GrFillPoly3(dc, tmpp->num_sides, tmpp->pts); } else tmpp->count++; tmpo = tmpp->next_obj; while (tmpo != &tmpp->next_obj) { Sprite3(dc, tmpo->p.x, tmpo->p.y, tmpo->p.z, tmpo->img); tmpo = tmpo->next; } } h_on_map = TRUE; } else if (h_on_map) break; x1h += xh; y1h += yh; } if (h_on_map) w_on_map = TRUE; else if (w_on_map) { strip_width = I64_MAX; break; } x1wb -= yh2; y1wb += xh2; if (strip_width & 1) { x1wa -= x1wb; y1wa -= y1wb; } else { x1wa += x1wb; y1wa += y1wb; } if (!w_on_map) { dd = SqrI64(x1wa >> 8 - MAP_WIDTH >> 1) + SqrI64(y1wa >> 8 - MAP_HEIGHT >> 1); if (dd > dd_old) break; dd_old = dd; } } tmpb = b_head[Gs->num].next; while (tmpb != &b_head[Gs->num]) { elems1 = SpriteInterpolate(Tri(tS, 0.2), <2>, <3>); Mat4x4IdentEqu(r); Mat4x4RotZ(r, tmpb->theta); elems_hard = SpriteTransform(elems1, r); Sprite3(dc, tmpb->p.x, tmpb->p.y, tmpb->p.z, elems_hard); Free(elems_hard); Free(elems1); tmpb = tmpb->next; } Free(s2w); mp.strip_width[Gs->num] = strip_width; LBtr(&mp.update_not_done_flags, Gs->num); } U0 CoreAPTalonsTask(CTask *master_task) { CDC *dc = DCAlias(main_dc, master_task); while (!mp.app_done) { while (!Bt(&mp.update_not_done_flags, Gs->num) && !mp.app_done) Sleep(1); if (!mp.app_done) MPDrawIt(master_task, dc); } //We made an alias of this we don't want freed. dc->depth_buf = NULL; DCDel(dc); LBtr(&mp.app_not_done_flags, Gs->num); } U0 DrawHorizon(CDC *dc) { I64 x1, y1, z1, x2, y2, z2, xh, yh, zh, *s2w = Mat4x4IdentNew, cx = Fs->pix_width >> 1, cy = Fs->pix_height >> 1; CD3I32 p[4]; I32 *old_db = dc->depth_buf; dc->depth_buf = NULL; CColorROPU32 ground_color; if (game_tf && fish_left) DCFill(dc, BLACK); else if (-pi / 4 <= Wrap(phi - pi) < pi / 4) DCFill(dc, LTCYAN); else { if (z / COORDINATE_SCALE < (WATER_ELEVATION + 3) * MAP_SCALE) ground_color = BLUE; else ground_color = LTGREEN; Mat4x4IdentEqu(dc->r); Mat4x4RotZ(dc->r, heading); Mat4x4RotX(dc->r, phi); Mat4x4RotZ(dc->r, roll); DCMat4x4Set(dc, dc->r); dc->flags &= ~DCF_TRANSFORMATION; dc->transform = &EDTransform; dc->x = cx; dc->y = cy; Mat4x4RotZ(s2w, -roll); Mat4x4RotX(s2w, -phi); Mat4x4RotZ(s2w, -heading); xh = 0; yh = 0; zh = -256; Mat4x4MulXYZ(s2w, &xh, &yh, &zh); Free(s2w); x1 = xh + yh * 32; y1 = yh - xh * 32; z1 = 0; (*dc->transform)(dc, &x1, &y1, &z1); x2 = xh - yh * 32; y2 = yh + xh * 32; z2 = 0; (*dc->transform)(dc, &x2, &y2, &z2); DCClipLine(dc, &x1, &y1, &x2, &y2); MemSet(p, 0, sizeof(p)); if (x2 < x1) { SwapI64(&x1, &x2); SwapI64(&y1, &y2); } if (!x1 && x2 == dc->width - 1) { p[0].x = 0; p[0].y = 0; p[1].x = dc->width - 1; p[1].y = 0; p[2].x = dc->width - 1; p[2].y = y2; p[3].x = 0; p[3].y = y1; if (rolled_over) dc->color = ground_color; else dc->color = LTCYAN; GrFillPoly3(dc, 4, p); p[0].y = dc->height - 1; p[1].y = dc->height - 1; if (rolled_over) dc->color = LTCYAN; else dc->color = ground_color; GrFillPoly3(dc, 4, p); } else { if (y2 < y1) { SwapI64(&x1, &x2); SwapI64(&y1, &y2); } if (!y1 && y2 == dc->height - 1) { p[0].x = 0; p[0].y = 0; p[1].x = 0; p[1].y = dc->height - 1; p[2].x = x2; p[2].y = dc->height - 1; p[3].x = x1; p[3].y = 0; if (x1 < x2 ^^ rolled_over) dc->color = ground_color; else dc->color = LTCYAN; GrFillPoly3(dc, 4, p); p[0].x = dc->width - 1; p[1].x = dc->width - 1; if (x1 < x2 ^^ rolled_over) dc->color = LTCYAN; else dc->color = ground_color; GrFillPoly3(dc, 4, p); } else DCFill(dc, LTCYAN); //Not correct. } } dc->depth_buf = old_db; } U0 Core0Talons() { CDC *dc = DCAlias(main_dc,Fs); I64 i, xx, yy, elev, height, cx = Fs->pix_width >> 1, cy = Fs->pix_height >> 1; F64 min_strip_width, tt; update_jiffy_limit = counts.jiffies + JIFFY_FREQ / 40; xx = x / (MAP_SCALE * COORDINATE_SCALE); yy = y / (MAP_SCALE * COORDINATE_SCALE); if (0 <= xx < MAP_WIDTH && 0 <= yy < MAP_HEIGHT) elev = elevations[yy][xx]; else elev = I64_MAX; height = z / COORDINATE_SCALE - elev; if (height < 0 && elev > WATER_ELEVATION * MAP_SCALE && !game_tf) { music.mute = TRUE; Beep; game_tf = tS; music.mute = FALSE; } DrawHorizon(dc); if (game_tf) { tt = game_tf - game_t0; if (Blink) { dc->color = RED; GrPrint(dc, (Fs->pix_width - 9 * FONT_WIDTH) / 2, (Fs->pix_height - FONT_HEIGHT) / 2, "Game Over"); } } else { DCDepthBufReset(dc); mp.update_not_done_flags = 1 << mp_count - 1; MPDrawIt(Fs, dc); while (mp.update_not_done_flags) Sleep(1); min_strip_width = F64_MAX; for (i = 0; i < mp_count; i++) min_strip_width = Min(min_strip_width, 32.0 * mp.strip_width[i] / (i + 32.0)); strip_height = ClampI64(strip_height * Clamp(0.25 * min_strip_width / strip_height, 0.9, 1.1), 64, 1024); tt = tS - game_t0; if (tt < 5.0 && Blink) { dc->color = WHITE; GrPrint(dc, (Fs->pix_width - 13 * FONT_WIDTH) / 2, (Fs->pix_height - FONT_HEIGHT) / 2 - 4 * FONT_HEIGHT, "Catch 10 Fish"); } } dc->thick = 2; if (game_tf && fish_left) dc->color = WHITE; else dc->color = BLACK; dc->flags &= ~DCF_TRANSFORMATION; GrLine3(dc, cx + 5, cy, 0, cx - 5, cy, 0); GrLine3(dc, cx, cy + 5, 0, cx, cy - 5, 0); if (invert_pitch) GrPrint(dc, 0, 0, "Pitch:%5.1f Roll:%5.1f Heading:%5.1f " "Height:%5d [Core Strip:%3d]", pitch * 180 / pi, Wrap(roll + pi) * 180 / pi, Wrap(heading + pi, 0) * 180 / pi, height, strip_height); else GrPrint(dc, 0, 0, "Pitch:%5.1f Roll:%5.1f Heading:%5.1f " "Height:%5d [Core Strip:%3d]", pitch * 180 / pi, roll * 180 / pi, heading * 180 / pi, height, strip_height); GrPrint(dc, 0, FONT_HEIGHT, "Fish Remaining:%d Time:%3.2f Best:%3.2f", fish_left, tt, best_score); //We made an alias of this we don't want freed. dc->depth_buf = NULL; DCDel(dc); Refresh; } Obj *FishFind(I64 x1, I64 y1, I64 *_dd) { I64 dd, best_dd = I64_MAX; Obj *res = NULL, *tmpo; Panel *tmpp = panel_head; while (tmpp) { tmpo = tmpp->next_obj; while (tmpo != &tmpp->next_obj) { if (tmpo->fish) { dd = SqrI64(tmpo->p.x - x1) + SqrI64(tmpo->p.y - y1); if (dd < best_dd) { best_dd = dd; res = tmpo; } } tmpo = tmpo->next; } tmpp = tmpp->next; } *_dd = best_dd; return res; } #define ANIMATE_MS 10 U0 AnimateTask(I64) {//Steadily moves the airplane forward. I64 i, *s2w, x1, y1, z1, dx, dy, dz, dd; F64 t0 = tS, ms, theta, d; Obj *tmpo; Bird *tmpb; while (TRUE) { ms = 1000 * (tS - t0); t0 = tS; if (!game_tf) { //Screen to world coordinates s2w = Mat4x4IdentNew; Mat4x4RotZ(s2w, -roll); Mat4x4RotX(s2w, -phi); Mat4x4RotZ(s2w, -heading); dx = 0; dy = 0; dz = 1 << 16; Mat4x4MulXYZ(s2w, &dx, &dy, &dz); x -= speed * ms * COORDINATE_SCALE * dx / 1 << 16; y -= speed * ms * COORDINATE_SCALE * dy / 1 << 16; z -= speed * ms * COORDINATE_SCALE * dz / 1 << 16; Free(s2w); x1 = x / COORDINATE_SCALE; y1 = y / COORDINATE_SCALE; z1 = z / COORDINATE_SCALE; if (z1 < (WATER_ELEVATION + 3) * MAP_SCALE) { if (z1 < WATER_ELEVATION * MAP_SCALE) { z = WATER_ELEVATION * MAP_SCALE * COORDINATE_SCALE; if (invert_pitch) { if (pitch < -pi / 8) phi += ms / 1000.0 * Sign(3 * pi / 8 - phi); } else if (pitch < -pi / 8) phi += ms / 1000.0 * Sign(-3 * pi / 8 - phi); WrapAngles; } speed = 1.0; if (rolled_over || !(tmpo = FishFind(x1, y1, &dd))) claws_down = 0; else { d = Sqrt(dd); x1 -= tmpo->p.x; y1 -= tmpo->p.y; theta = ACos((dx * x1 + dy * y1) / (d * 1 << 16)); if (theta > 0 && d < MAP_SCALE * 4) claws_down = Saw(d, MAP_SCALE * 4); else claws_down = 0.01; if (d < MAP_SCALE * 2) { if (!--fish_left) { game_tf = tS; if (game_tf - game_t0 < best_score) best_score = game_tf - game_t0; } QueueRemove(tmpo); Free(tmpo); music.mute = TRUE; Sound(74); Sleep(200); Sound; music.mute = FALSE; } } } else { claws_down = 0; if (-pi / 4 <= phi <= pi / 4) speed += 0.0005; else if (-3 * pi / 4 <= phi <= 3 * pi / 4) speed += 0.0001; else speed -= 0.0001; speed = Clamp(speed + (0.0005 - 0.0002 * Abs(phi) / (pi / 4)), 0.1, 5.0); } for (i = 0; i < mp_count; i++) { tmpb = b_head[i].next; while (tmpb != &b_head[i]) { tmpb->p.x += 10 * ms / 1000 * MAP_SCALE * Cos(tmpb->theta); tmpb->p.y += 10 * ms / 1000 * MAP_SCALE * Sin(tmpb->theta); tmpb->p.z = BIRD_ELEVATION * MAP_SCALE + elevations[tmpb->p.y / MAP_SCALE][tmpb->p.x / MAP_SCALE]; tmpb->theta += 2 * pi * ms / 1000 / 10; tmpb = tmpb->next; } } } Refresh; } } U0 MPEnd() { update_jiffy_limit = 0; mp.app_not_done_flags = 1 << mp_count - 1 - 1; mp.app_done = TRUE; //Wait for all cores to exit while (mp.app_not_done_flags) Sleep(1); } U0 TaskEndCB() { MPEnd; Exit; } U0 SongTask(I64) { Fs->task_end_cb = &SoundTaskEndCB; MusicSettingsReset; while (TRUE) { Play("5eCGFsD4A5e.C4sG5eGDqCDeGsGG4qG"); Play("5eCGFsD4A5e.C4sG5eGDqCDeGsGG4qG"); Play("5eGECGC4A5FCsC4B5C4B5e.GsG4qGB"); Play("5eGECGC4A5FCsC4B5C4B5e.GsG4qGB"); } } U0 PreInit() { I64 i, *r = Mat4x4IdentNew; Mat4x4Scale(r, 10.0); for (i = 0; i < LS_TYPES; i++) landscape_large_imgs[i] = SpriteTransform(landscape_small_imgs[i], r); Free(r); } U0 PostCleanUp() { I64 i; for (i = 0; i < LS_TYPES; i++) Free(landscape_large_imgs[i]); } U0 Init() { I64 i, xx, yy; Bird *tmpb; main_dc = DCNew(GR_WIDTH, GR_HEIGHT); critical_section_flag = 0; game_tf = 0; fish_left = 10; MemSet(&mp, 0, sizeof(MPCtrl)); InitMap; DCDepthBufAlloc(main_dc); strip_height = 128; phi = -90.0 * pi / 180.0; roll = 0; heading = 0; speed = 2.5; claws_down = 0; WrapAngles; x = MAP_WIDTH >> 1 * COORDINATE_SCALE * MAP_SCALE; y = MAP_HEIGHT >> 1 * COORDINATE_SCALE * MAP_SCALE; z = 64 * COORDINATE_SCALE * MAP_SCALE; xx = x / (MAP_SCALE * COORDINATE_SCALE); yy = y / (MAP_SCALE * COORDINATE_SCALE); z += elevations[yy][xx] * COORDINATE_SCALE; for (i = 0; i < mp_count; i++) QueueInit(&b_head[i]); for (i = 0; i < B_NUM; i++) { tmpb = MAlloc(sizeof(Bird)); tmpb->p.x = Rand * MAP_WIDTH * MAP_SCALE; tmpb->p.y = Rand * MAP_HEIGHT * MAP_SCALE; tmpb->p.z = BIRD_ELEVATION * MAP_SCALE + elevations[tmpb->p.y / MAP_SCALE][tmpb->p.x / MAP_SCALE]; tmpb->theta = 2 * pi * Rand; QueueInsert(tmpb, b_head[i % mp_count].last); } for (i = 1; i < mp_count; i++) Spawn(&CoreAPTalonsTask, Fs, "AP Talons", i); Fs->task_end_cb = &TaskEndCB; game_t0 = tS; } U0 CleanUp() { I64 i; Panel *tmpp = panel_head, *tmpp1; MPEnd; while (tmpp) { tmpp1 = tmpp->next; QueueDel(&tmpp->next_obj); Free(tmpp->pts); Free(tmpp); tmpp = tmpp1; } for (i = 0; i < mp_count; i++) { QueueDel(&b_head[i]); QueueInit(&b_head[i]); } DCDel(main_dc); } U0 Talons() { I64 ch, sc; SettingsPush; //See SettingsPush MenuPush( "File {" " Abort(,CH_SHIFT_ESC);" " Exit(,CH_ESC);" "}" "Play {" " Restart(,'\n');" " Down(,,SC_CURSOR_UP);" " Up(,,SC_CURSOR_DOWN);" " Left(,,SC_CURSOR_LEFT);" " Right(,,SC_CURSOR_RIGHT);" "}" ); AutoComplete; WinBorder; WinMax; DocCursor; DocClear; "Initializing...\n"; Fs->song_task = Spawn(&SongTask, NULL, "Song",, Fs); PreInit; Init; Fs->animate_task = Spawn(&AnimateTask, NULL, "Animate",, Fs); Fs->draw_it = &DrawIt; try //in case <CTRL-ALT-c> is pressed. do { if (KeyScan(&ch, &sc)) { switch (ch) { case 0: switch (sc.u8[0]) { start: case SC_CURSOR_DOWN: phi -= CTRLS_SCALE * Cos(roll); heading -= CTRLS_SCALE * Sin(roll) * Sin(phi); break; case SC_CURSOR_UP: phi += CTRLS_SCALE * Cos(roll); heading += CTRLS_SCALE * Sin(roll) * Sin(phi); break; case SC_CURSOR_RIGHT: roll += CTRLS_SCALE; break; case SC_CURSOR_LEFT: roll -= CTRLS_SCALE; break; end: WrapAngles; } break; case '\n': Fs->draw_it = NULL; CleanUp; Refresh; Init; Fs->draw_it = &DrawIt; break; } } else Core0Talons; } while (ch != CH_SHIFT_ESC && ch != CH_ESC); catch PutExcept; SettingsPop; CleanUp; PostCleanUp; MenuPop; RegWrite("ZealOS/Talons", "F64 best_score=%5.4f;\n", best_score); } Talons;