//Uses fixed-point. RegDft("TempleOS/RawHide","F64 best_score=9999;\n"); RegExe("TempleOS/RawHide"); F64 t0,tf; I64 outside_cnt; #define MAP_WIDTH 1000 #define MAP_HEIGHT 1000 #define FENCE_WIDTH 320 #define FENCE_HEIGHT 200 #define MAP_BORDER 3 CDC *map_dc; #define GATE_WIDTH 22 #define GATE_HEIGHT 7 F64 gate_theta,gate_t; <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 */ <7>/* Graphics Not Rendered in HTML */ <8>/* Graphics Not Rendered in HTML */ <9>/* Graphics Not Rendered in HTML */ <10>/* Graphics Not Rendered in HTML */ #define ANIMAL_WIDTH 20 #define ANIMAL_HEIGHT 16 U8 *cow_imgs[4] ={<1>,<2>,<3>,<2>}, *bull_imgs[4] ={<4>,<5>,<6>,<5>}, *horse_imgs[4]={<7>,<8>,<7>,<8>}; #define ANIMALS_NUM 100 class Animal { I64 num,x,y,dx,dy; U8 **imgs; U32 buddy; U8 type,frame0; Bool dead,pad; } *a; //************************************ #define WATERFALL_HEIGHT (MAP_HEIGHT/20) #define WATERFALL_DROPS 512 #define WATERFALL_ACCELERATION 10 I32 *r_x,*r_width,*wfd_x; F64 *wfd_t0,waterfall_tf; I64 waterfall_x,waterfall_y,waterfall_width; U0 RiverNew() { r_x=MAlloc(MAP_HEIGHT*sizeof(I32)); r_width=MAlloc(MAP_HEIGHT*sizeof(I32)); wfd_x=MAlloc(WATERFALL_DROPS*sizeof(I32)); wfd_t0=MAlloc(WATERFALL_DROPS*sizeof(F64)); waterfall_tf=Sqrt(2*WATERFALL_HEIGHT/WATERFALL_ACCELERATION); } U0 RiverMake() { I64 i,x=2*MAP_WIDTH<<32/3,y,dx=0,w=15<<32; waterfall_y=(MAP_HEIGHT-WATERFALL_HEIGHT)/2*Rand+ (MAP_HEIGHT-WATERFALL_HEIGHT)/4; for (y=MAP_BORDER;y<MAP_HEIGHT-MAP_BORDER;y++) { r_x[y]=x.i32[1]; r_width[y]=w.i32[1]; if (waterfall_y-5<y<waterfall_y+WATERFALL_HEIGHT+5) { waterfall_width=r_width[y]; waterfall_x=r_x[y]-waterfall_width/2; } else { dx=ClampI64(dx+RandI32/64,-I32_MAX,I32_MAX)-I32_MAX/256; w=ClampI64(w+RandI32*2,10*U32_MAX,150*U32_MAX); x+=dx; } } for (i=0;i<WATERFALL_DROPS;i++) { wfd_x[i]=Rand*waterfall_width+waterfall_x; wfd_t0[i]=tS-Rand*waterfall_tf; } //Plot waterfall cliff Sprite3B(map_dc,waterfall_x,waterfall_y,0,<10>); //Plot sand bar x=0; for (y=MAP_BORDER;y<MAP_HEIGHT-MAP_BORDER;y++) { if (!(waterfall_y-9<y<waterfall_y+WATERFALL_HEIGHT+9)) { map_dc->color=YELLOW; map_dc->thick=r_width[y]+10; GrPlot3(map_dc,r_x[y]+x.i32[1],y,0); } x=ClampI64(x+RandI32,-6*U32_MAX,6*U32_MAX); } //Plot water for (y=MAP_BORDER;y<MAP_HEIGHT-MAP_BORDER;y++) { map_dc->color=BLUE; map_dc->thick=r_width[y]; GrPlot3(map_dc,r_x[y],y,0); } } U0 RiverDel() { Free(r_x); Free(r_width); Free(wfd_x); Free(wfd_t0); } //************************************ class RiverDrop { RiverDrop *next,*last; I64 y,dx,dy; } rd_head; Bool rd_lock; U0 RiverDropsDel() { while (LBts(&rd_lock,0)) Yield; QueDel(&rd_head,TRUE); QueInit(&rd_head); LBtr(&rd_lock,0); } U0 RiverDropsNext(CTask *mem_task) { RiverDrop *tmpr,*tmpr1; while (LBts(&rd_lock,0)) Yield; tmpr=rd_head.next; while (tmpr!=&rd_head) { tmpr1=tmpr->next; if (++tmpr->y>=MAP_HEIGHT-MAP_BORDER) { QueRem(tmpr); Free(tmpr); } else { do { if (RandU16&1 && GrPeek(map_dc,r_x[tmpr->y]+tmpr->dx, tmpr->y+tmpr->dy)==BLUE) break; tmpr->dx=ClampI64(tmpr->dx+RandU16%3-1,-r_width[tmpr->y]/2, r_width[tmpr->y]/2); tmpr->dy=ClampI64(tmpr->dy+RandU16%3-1,-r_width[tmpr->y]/2, r_width[tmpr->y]/2); } while (GrPeek(map_dc,r_x[tmpr->y]+tmpr->dx, tmpr->y+tmpr->dy)!=BLUE && GrPeek(map_dc,r_x[tmpr->y],tmpr->y)==BLUE);//Might be reiniting } tmpr=tmpr1; } tmpr=MAlloc(sizeof(RiverDrop),mem_task); tmpr->y=MAP_BORDER; tmpr->dx=0; tmpr->dy=0; QueIns(tmpr,rd_head.last); LBtr(&rd_lock,0); } U0 RiverDropsDraw(CDC *dc,I64 cx,I64 cy) { I64 i; F64 t=tS; RiverDrop *tmpr; while (LBts(&rd_lock,0)) Yield; tmpr=rd_head.next; dc->color=LTBLUE; while (tmpr!=&rd_head) { GrPlot(dc,r_x[tmpr->y]+tmpr->dx-cx,tmpr->y+tmpr->dy-cy); tmpr=tmpr->next; } LBtr(&rd_lock,0); dc->color=WHITE; for (i=0;i<WATERFALL_DROPS;i++) GrPlot(dc,wfd_x[i]-cx,waterfall_y+0.5*WATERFALL_ACCELERATION* Sqr(waterfall_tf*Saw(t-wfd_t0[i],waterfall_tf))-cy); } //************************************ U0 DrawIt(CTask *task,CDC *dc) { static I64 last_pos_x=0; static Bool left=TRUE; F64 t; I64 i,frame=4*tS, cx=(MAP_WIDTH -task->pix_width)/2, cy=(MAP_HEIGHT-task->pix_height)/2; if (task->scroll_x+cx<0) task->scroll_x=-cx; if (task->scroll_x+cx>MAP_WIDTH-task->pix_width) task->scroll_x=MAP_WIDTH-task->pix_width-cx; if (task->scroll_y+cy<0) task->scroll_y=-cy; if (task->scroll_y+cy>MAP_HEIGHT-task->pix_height) task->scroll_y=MAP_HEIGHT-task->pix_height-cy; map_dc->flags|=DCF_NO_TRANSPARENTS; GrBlot(dc,-cx,-cy,map_dc); RiverDropsDraw(dc,cx,cy); for (i=0;i<ANIMALS_NUM;i++) if (!a[i].dead) { if (a[i].dx<0) { dc->flags|=DCF_JUST_MIRROR|DCF_SYMMETRY; DCSymmetrySet(dc,a[i].x.i32[1]-cx,0,a[i].x.i32[1]-cx,1); } Sprite3(dc,a[i].x.i32[1]-cx,a[i].y.i32[1]-cy,0, a[i].imgs[(frame+a[i].frame0)&3]); dc->flags&=~(DCF_JUST_MIRROR|DCF_SYMMETRY); } if (ms.pos.x-last_pos_x>0) left=FALSE; else if (ms.pos.x-last_pos_x<0) left=TRUE; if (left) { dc->flags|=DCF_JUST_MIRROR|DCF_SYMMETRY; DCSymmetrySet(dc,ms.pos.x-task->pix_left-task->scroll_x,0, ms.pos.x-task->pix_left-task->scroll_x,1); } Sprite3(dc,ms.pos.x-task->pix_left-task->scroll_x, ms.pos.y-task->pix_top -task->scroll_y,0,horse_imgs[frame&3]); dc->flags&=~(DCF_JUST_MIRROR|DCF_SYMMETRY); last_pos_x=ms.pos.x; if (tf) { dc->color=RED; t=tf-t0; if (Blink) GrPrint(dc,(task->pix_width-FONT_WIDTH*14)>>1-task->scroll_x, (task->pix_height-FONT_HEIGHT)>>1-task->scroll_y, "Game Completed"); } else { dc->color=BLACK; t=tS-t0; } GrPrint(dc,-task->scroll_x,-task->scroll_y, "Outside:%03d Time:%7.2fs Best:%7.2fs", outside_cnt,t,best_score); } U0 BuddySel(I64 i) { I64 b,best_b=i,score,best_score=I64_MAX; for (b=0;b<ANIMALS_NUM;b++) { if (b!=i && !a[b].dead) { score=RandU32%(512*512)+ SqrI64(a[b].x.i32[1]-a[i].x.i32[1])+ SqrI64(a[b].y.i32[1]-a[i].y.i32[1]); if (score<best_score) { best_score=score; best_b=b; } } } a[i].buddy=best_b; } U0 RedrawGate() { F64 tt=tS-gate_t; I64 x1=FENCE_WIDTH-63,y1=FENCE_HEIGHT-1,dx,dy; if (tt<0.5) gate_theta=Clamp(gate_theta+0.02,0,pi/2); else if (tt>5.0) gate_theta=Clamp(gate_theta-0.02,0,pi/2); dx=GATE_WIDTH*Cos(gate_theta); dy=-0.8*GATE_WIDTH*Sin(gate_theta); map_dc->color=LTGREEN; GrRect(map_dc,x1,y1-0.8*GATE_WIDTH-GATE_HEIGHT, 46,0.8*GATE_WIDTH+GATE_HEIGHT+3); map_dc->color=BLACK; GrLine(map_dc,x1,y1,x1+dx,y1+dy); GrLine(map_dc,x1,y1,x1,y1-GATE_HEIGHT); GrLine(map_dc,x1+dx,y1+dy,x1+dx,y1+dy-GATE_HEIGHT); GrLine(map_dc,x1,y1-GATE_HEIGHT,x1+dx,y1+dy-GATE_HEIGHT); GrLine(map_dc,x1,y1,x1+dx,y1+dy-GATE_HEIGHT); GrLine(map_dc,x1,y1-GATE_HEIGHT,x1+dx,y1+dy); GrLine(map_dc,x1+45,y1,x1+45-dx,y1+dy); GrLine(map_dc,x1+45,y1,x1+45,y1-GATE_HEIGHT); GrLine(map_dc,x1+45-dx,y1+dy,x1+45-dx,y1+dy-GATE_HEIGHT); GrLine(map_dc,x1+45,y1-GATE_HEIGHT,x1+45-dx,y1+dy-GATE_HEIGHT); GrLine(map_dc,x1+45,y1,x1+45-dx,y1+dy-GATE_HEIGHT); GrLine(map_dc,x1+45,y1-GATE_HEIGHT,x1+45-dx,y1+dy); } Bool CheckMap(I64 x,I64 y) { I64 i,j,c; if (SqrI64(x-(waterfall_x+waterfall_width/2))>>1+ SqrI64(y-(waterfall_y+WATERFALL_HEIGHT/2))<2500) return FALSE; for (j=-4;j<=2;j++) for (i=-4;i<=4;i++) { c=GrPeek(map_dc,x+i,y+j); if (c==LTGRAY || c==BLACK) return FALSE; } return TRUE; } U0 AnimateTask(CTask *parent) { I64 i,cx,cy,cursor_x,cursor_y,dd,ddx,ddy,cnt,max_speed=I64_MAX,updates=0, my_outside_cnt; F64 f,d,dx,dy,s,stress; Animal *tmpa,*tmpa1; while (TRUE) { max_speed=ClampU64(max_speed,U32_MAX/3,200*U32_MAX); cx=(MAP_WIDTH -parent->pix_width)/2, cy=(MAP_HEIGHT-parent->pix_height)/2; cursor_x=ms.pos.x+cx-parent->pix_left-parent->scroll_x; cursor_y=ms.pos.y+cy-parent->pix_top -parent->scroll_y; cnt=0;stress=0; my_outside_cnt=0; if (cursor_x<FENCE_WIDTH && cursor_y<FENCE_HEIGHT) gate_t=tS; RedrawGate; for (i=0;i<ANIMALS_NUM;i++) { tmpa=&a[i]; if (!tmpa->dead) { //Move away from horse ddx=tmpa->x.i32[1]-cursor_x; ddy=tmpa->y.i32[1]-cursor_y; if (dd=SqrI64(ddx)+SqrI64(ddy)) { d=Sqrt(dd); dx=ddx/d; dy=ddy/d; f=5.0e2*U32_MAX/dd; tmpa->dx+=f*dx; tmpa->dy+=f*dy; } //Resel buddy about every ANIMALS_NUM*10ms=5.12 seconds tmpa1=&a[tmpa->buddy]; if (tmpa1->dead || i==updates%ANIMALS_NUM) { BuddySel(i); tmpa1=&a[tmpa->buddy]; } //Move toward buddy ddx=tmpa->x.i32[1]-tmpa1->x.i32[1]; ddy=tmpa->y.i32[1]-tmpa1->y.i32[1]; if (dd=SqrI64(ddx)+SqrI64(ddy)) { d=Sqrt(dd); s=d`1.25-80; stress+=Abs(s); dx=ddx/d; dy=ddy/d; f=-0.001*s*U32_MAX; tmpa->dx+=f*dx; tmpa->dy+=f*dy; } //Make velocity similar to buddy tmpa->dx+=0.1*(tmpa1->dx-tmpa->dx); tmpa->dy+=0.1*(tmpa1->dy-tmpa->dy); //Add random movement, limit speed and dampen speed tmpa->dx=0.995*ClampI64(tmpa->dx+RandI32/32,-max_speed,max_speed); tmpa->dy=0.995*ClampI64(tmpa->dy+RandI32/32,-max_speed,max_speed); //Slow in river if (GrPeek(map_dc,tmpa->x.i32[1],tmpa->y.i32[1])!=LTGREEN) { tmpa->dx/=2; tmpa->dy/=2; } if (CheckMap((tmpa->x+tmpa->dx)>>32,(tmpa->y+tmpa->dy)>>32)) { tmpa->x+=tmpa->dx; tmpa->y+=tmpa->dy; } //Keep on map if (!(MAP_BORDER+ANIMAL_WIDTH/2 <=tmpa->x.i32[1]<MAP_WIDTH-MAP_BORDER-ANIMAL_WIDTH/2)) { tmpa->x -=tmpa->dx; tmpa->dx=-tmpa->dx; } if (!(MAP_BORDER+ANIMAL_HEIGHT <=tmpa->y.i32[1]<MAP_HEIGHT-MAP_BORDER)) { tmpa->y -=tmpa->dy; tmpa->dy=-tmpa->dy; } cnt++; if (tmpa->x>>32>=FENCE_WIDTH || tmpa->y>>32>=FENCE_HEIGHT) my_outside_cnt++; } } outside_cnt=my_outside_cnt; if (!(updates&15)) RiverDropsNext(parent); if (!tf && !outside_cnt) { tf=tS; music.mute=TRUE; Snd(86);Sleep(200);Snd;Sleep(100); if (tf-t0<best_score) { best_score=tf-t0; Snd(86);Sleep(200);Snd;Sleep(100); } music.mute=FALSE; } updates++; if (cnt) stress/=cnt; else stress=0; if (stress>100.0) { Yield; max_speed=stress/5.0*U32_MAX; //Converge faster at start-up } else { Sleep(10); max_speed=0; //Will be set to normal max speed } } } U0 SongTask(I64) {//Randomly generated (by God :-) Fs->task_end_cb=&SndTaskEndCB; MusicSettingsRst; while (TRUE) { Play("5qC4etG5DC4B5DCECFqFC4sA5D4A5D4qB"); Play("5C4etG5DC4B5DCECFqFC4sA5D4A5D4qB"); Play("4sGAGA5qG4etG5GD4eBBqB5F4eBA5qE"); Play("4sGAGA5qG4etG5GD4eBBqB5F4eBA5qE"); } } U0 ReInit() { I64 i; RiverDropsDel; map_dc->color=LTGREEN; GrRect(map_dc,2,2,MAP_WIDTH-4,MAP_HEIGHT-4); RiverMake; //Plot fence for (i=FENCE_WIDTH;i>0;i-=16) Sprite3(map_dc,i,FENCE_HEIGHT,0,<9>); map_dc->thick=1; map_dc->color=BROWN; for (i=0;i<FENCE_HEIGHT-16;i+=16) GrLine(map_dc,FENCE_WIDTH-1,i,FENCE_WIDTH-1,i+7); map_dc->color=LTGRAY; GrLine(map_dc,FENCE_WIDTH,0,FENCE_WIDTH,FENCE_HEIGHT-6); RedrawGate; map_dc->thick=MAP_BORDER; map_dc->color=RED; GrBorder(map_dc,MAP_BORDER/2,MAP_BORDER/2, MAP_WIDTH-(MAP_BORDER+1)/2,MAP_HEIGHT-(MAP_BORDER+1)/2); for (i=MAP_BORDER;i<=MAP_HEIGHT-MAP_BORDER;i++) RiverDropsNext(Fs); MemSet(a,0,ANIMALS_NUM*sizeof(Animal)); for (i=0;i<ANIMALS_NUM;i++) { a[i].num=i; do { a[i].x=(64+RandU32%(MAP_WIDTH-128))<<32; a[i].y=(64+RandU32%(MAP_WIDTH-128))<<32; } while (!CheckMap(a[i].x>>32,a[i].y>>32)); if (i&1) a[i].imgs=cow_imgs; else a[i].imgs=bull_imgs; a[i].frame0=RandU16&3; BuddySel(i); } outside_cnt=ANIMALS_NUM; gate_t=0; gate_theta=0; t0=tS; tf=0; } U0 Init() { RiverNew; rd_lock=0; QueInit(&rd_head); map_dc=DCNew(MAP_WIDTH,MAP_HEIGHT); a=MAlloc(ANIMALS_NUM*sizeof(Animal)); ReInit; } U0 CleanUp() { DCDel(map_dc); Free(a); RiverDropsDel; RiverDel; } U0 RawHide() { I64 msg_code,arg1,arg2; SettingsPush; //See SettingsPush MenuPush( "File {" " Abort(,CH_SHIFT_ESC);" " Exit(,CH_ESC);" "}" "Play {" " Restart(,'\n');" "}" ); Fs->song_task=Spawn(&SongTask,NULL,"Song",,Fs); PopUpOk( "Coral the cattle. The coral is in the\n" "upper-left corner if you scroll.\n\n" "Keep holding the $GREEN$<CTRL>$FG$ key and\n" "scroll with $GREEN${CTRL-Left Grab}$FG$."); Fs->win_inhibit=WIG_TASK_DFT-WIF_SELF_FOCUS -WIF_SELF_BORDER-WIF_SELF_GRAB_SCROLL-WIF_FOCUS_TASK_MENU; AutoComplete; WinBorder; WinMax; DocCursor; DocClear; Init; Fs->animate_task=Spawn(&AnimateTask,Fs,"Animate",,Fs); Fs->draw_it=&DrawIt; try { while (TRUE) { msg_code=GetMsg(&arg1,&arg2, 1<<MSG_KEY_DOWN+1<<MSG_MS_L_DOWN+1<<MSG_MS_R_DOWN); switch (msg_code) { case MSG_MS_L_DOWN: //Doesn't do anything, yet. break; case MSG_MS_R_DOWN: //Doesn't do anything, yet. break; case MSG_KEY_DOWN: switch (arg1) { case '\n': ReInit; break; case CH_SHIFT_ESC: case CH_ESC: goto rh_done; } break; } } rh_done: GetMsg(,,1<<MSG_KEY_UP); } catch PutExcept; SettingsPop; CleanUp; MenuPop; RegWrite("TempleOS/RawHide","F64 best_score=%5.4f;\n",best_score); } RawHide;