/*Sprites were created with <CTRL-r>
and can be edited by moving the
cursor on top and pressing <CTRL-r>.

<CTRL-t> to see the num of the sprite
and <CTRL-t> again to get back.  Nums
are assigned by the editor.
*/







        <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 */

//See ::/Doc/Credits.DD.



        <7>/* Graphics Not Rendered in HTML */






                <8>/* Graphics Not Rendered in HTML */








































































                <9>/* Graphics Not Rendered in HTML */

RegDft("TempleOS/BlackDiamond","I64 best_score=9999;\n");
RegExe("TempleOS/BlackDiamond");

#define MAP_HEIGHT      3000
#define OBJS_NUM        128

I64 x,y,scrn_top_y,penalty,chair_lift_num;
I64 obj_x[OBJS_NUM],obj_y[OBJS_NUM],obj_types[OBJS_NUM],
    obj_saved_x[OBJS_NUM],obj_saved_y[OBJS_NUM];
Bool game_over;

#define T_TREE          0
#define T_LITTLE_ROCK   1
#define T_BIG_ROCK      2
#define T_WOLF          3
#define T_CHAIR_LIFT    4
U8 *imgs[5]={<3>,<4>,<5>,<6>,<9>};

#define DC_WOLF_WIDTH   48
#define DC_WOLF_HEIGHT  38
U0 DrawRunningWolf(CDC *dc,I64 i)
{//Draw wolf on small DC so bottom gets clipped looking like sunk into snow.
//Then, copy onto main DC.
  U8 *tmps;
  CDC *dc_wolf=DCNew(DC_WOLF_WIDTH,DC_WOLF_HEIGHT);
  DCFill(dc_wolf);
  if (x<obj_x[i]) {
    dc_wolf->flags|=DCF_SYMMETRY|DCF_TRANSFORMATION|DCF_JUST_MIRROR;
    DCSymmetrySet(dc_wolf,DC_WOLF_WIDTH/2,0,DC_WOLF_WIDTH/2,1);
  }
  if (tS%1.0<0.5)
    tmps=<6>;
  else
    tmps=<7>;
  Sprite3ZB(dc_wolf,DC_WOLF_WIDTH/2,0.85*DC_WOLF_HEIGHT,
        0,tmps,0.4*Sin(7*tS));
  GrBlot(dc,obj_x[i]-DC_WOLF_WIDTH/2,
        obj_y[i]-scrn_top_y-0.85*DC_WOLF_HEIGHT,dc_wolf);
  DCDel(dc_wolf);
  if (0<=(obj_y[i]-scrn_top_y)<GR_HEIGHT)
    obj_x[i]+=3*SignI64(x-obj_x[i]);
}

U0 DrawMan(CDC *dc)
{
  if(dc->collision_cnt)
    Sprite3(dc,x,y-scrn_top_y,0,<2>); //Red man
  else
    Sprite3(dc,x,y-scrn_top_y,0,<1>); //Normal man
}

#define WIRE_HEIGHT     595
#define WIRE_WIDTH      121
#define WIRE_DIP        800
#define PULLY_WIDTH     13
U0 DrawUpperChairLift(CDC *dc)
{
  I64 i=chair_lift_num,x,x1,y=obj_y[i]-scrn_top_y-WIRE_HEIGHT,y1;
  Sprite3(dc,obj_x[i],y+13,0,<8>);
  dc->thick=2;
  for (x=-WIRE_WIDTH/2;x<GR_WIDTH+WIRE_WIDTH/2;x+=2) { //Pen width is 2, step 2.
    x1=x-obj_x[i];
    y1=y-WIRE_DIP/2+Cosh(Ln(WIRE_DIP)+(Abs(x1)-PULLY_WIDTH)/10000.0)+0.1*x1;
    if (!(-PULLY_WIDTH<x1<PULLY_WIDTH)) {
      GrPlot3(dc,x-WIRE_WIDTH/2,y1,0);
      GrPlot3(dc,x+WIRE_WIDTH/2,y1,0);
    }
  }
  dc->thick=1;
}

U0 DrawIt(CTask *,CDC *dc)
{
  I64 i;
  Bool man_drawn=FALSE;

  for (i=0;i<OBJS_NUM;i++)
    if (obj_y[i]-32<=y<=obj_y[i]) {
      if (obj_types[i]==T_WOLF && AbsI64(x-obj_x[i])>3)
        DrawRunningWolf(dc,i);
      else
        Sprite3(dc,obj_x[i],obj_y[i]-scrn_top_y,0,imgs[obj_types[i]]);
    }

  dc->collision_cnt=0;
  dc->color=ROP_COLLISION;
  dc->bkcolor=WHITE;
  Sprite3(dc,x,y-scrn_top_y,0,<1>);
  if (!game_over) {
    if(dc->collision_cnt) {
      Snd(58);
      penalty++; //Time is irregular. Scoring is imperfect. 30fps more or less.
    } else
      Snd;
  }

  dc->color=ROP_EQU;
  for (i=0;i<OBJS_NUM;i++) {
    if (!man_drawn && obj_y[i]>=y) {
      DrawMan(dc);
      man_drawn=TRUE;
    }
    if (obj_types[i]==T_WOLF && AbsI64(x-obj_x[i])>3)
      DrawRunningWolf(dc,i);
    else
      Sprite3(dc,obj_x[i],obj_y[i]-scrn_top_y,0,imgs[obj_types[i]]);
  }
  if (!man_drawn)
    DrawMan(dc);
  DrawUpperChairLift(dc);

  dc->color=BLACK;
  GrPrint(dc,0,0,"Penalty:%d Best:%d",penalty,best_score);
  if (game_over && Blink) {
    dc->color=RED;
    GrPrint(dc,(Fs->pix_width-9*FONT_WIDTH)/2,
          (Fs->pix_height-FONT_HEIGHT)/2,"Game Over");
  }
}

I64 Compare(I64 e1,I64 e2)
{
  return e1-e2;
}

U0 Init()
{
  I64 i,j;
  for (i=0;i<OBJS_NUM;i++) {
    obj_saved_y[i]=RandU32%MAP_HEIGHT;
    obj_saved_x[i]=RandU32%GR_WIDTH;
    j=RandU16;
    if (j&7)
      obj_types[i]=T_TREE;
    else if (j&31)
      obj_types[i]=T_LITTLE_ROCK;
    else if (j&63)
      obj_types[i]=T_BIG_ROCK;
    else
      obj_types[i]=T_WOLF;
  }
  QSortI64(obj_saved_y,OBJS_NUM,&Compare); //Break associations. Doesn't matter.

  chair_lift_num=RandU16%OBJS_NUM;
  obj_types[chair_lift_num]=T_CHAIR_LIFT;
}

U0 BlackDiamond()
{
  I64 ch,sc;

  MenuPush(
        "File {"
        "  New(,'\n');"
        "  Restart(,CH_SPACE);"
        "  Abort(,CH_SHIFT_ESC);"
        "  Exit(,CH_ESC);"
        "}"
        "Play {"
        "  Up(,,SC_CURSOR_UP);"
        "  Down(,,SC_CURSOR_DOWN);"
        "  Left(,,SC_CURSOR_LEFT);"
        "  Right(,,SC_CURSOR_RIGHT);"
        "}"
        );
  SettingsPush; //See SettingsPush
  AutoComplete;
  WinBorder;
  WinMax;
  DocCursor;
  DocClear;
  Fs->draw_it=&DrawIt;

  Init;
  try {
    while (TRUE) {
bd_restart:
      MemCpy(obj_x,obj_saved_x,sizeof(obj_x)); //Wolves move. We must reset the
      MemCpy(obj_y,obj_saved_y,sizeof(obj_y)); //wolves if running same game.

      game_over=FALSE;
      scrn_top_y=0;
      x=Fs->pix_width>>1; y=0;
      penalty=0;
      while (TRUE) {
        if (ScanKey(&ch,&sc)) {
          switch (ch) {
            case 0:
              if (!game_over)
                switch (sc.u8[0]) {
                  case SC_CURSOR_RIGHT:
                    x+=10;
                    if (x>=Fs->pix_width) x-=Fs->pix_width;
                    break;
                  case SC_CURSOR_LEFT:
                    x-=10;
                    if (x<0) x+=Fs->pix_width;
                    break;
                  case SC_CURSOR_UP:
                    y-=10;
                    break;
                  case SC_CURSOR_DOWN:
                    y+=10;
                    break;
                }
              break;

            case CH_ESC:
            case CH_SHIFT_ESC:
              goto bd_done;

            case '\n':
              Init;
              goto bd_restart;

            case CH_SPACE:
              game_over=TRUE;
              while (scrn_top_y>0||y>0) {//Animate going back to top.
                scrn_top_y=MaxI64(0,scrn_top_y-4);
                y=MaxI64(0,y-4);
                x+=SignI64(Fs->pix_width>>1-x);
                Sleep(1);
              }
              Snd;
              goto bd_restart;
          }
//Don't want keystrokes building-up in the buf.
          FlushMsgs;
        }
        if (!game_over) {
          y+=2;
          scrn_top_y++;
          if (y-scrn_top_y>Fs->pix_height) {//Animate scrolling scrn.
            while (y-scrn_top_y>Fs->pix_height>>1) {
              scrn_top_y+=2;
              Sleep(1);
            }
          }
          if (y>=MAP_HEIGHT) {
            game_over=TRUE;
            Beep;
            if (penalty<=best_score) {
              best_score=penalty;
              Beep;
            }
          }
        }
        Sleep(10);
      }
    }
bd_done:
  } catch
    PutExcept;
  SettingsPop;
  MenuPop;
  RegWrite("TempleOS/BlackDiamond","I64 best_score=%d;\n",best_score);
}

BlackDiamond; //Start game when #included.