//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,mouse, theta, d;
        Obj             *tmpo;
        Bird    *tmpb;

        while (TRUE)
        {
                mouse = 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 * mouse * COORDINATE_SCALE * dx / 1 << 16;
                        y -= speed * mouse * COORDINATE_SCALE * dy / 1 << 16;
                        z -= speed * mouse * 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 += mouse / 1000.0 * Sign(3 * pi / 8 - phi);
                                        }
                                        else if (pitch < -pi / 8)
                                                phi += mouse / 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 * mouse / 1000 * MAP_SCALE * Cos(tmpb->theta);
                                        tmpb->p.y += 10 * mouse / 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 * mouse / 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;