RegDefault("ZealOS/Wenceslas", "F64 best_score=9999;\n"); RegExe("ZealOS/Wenceslas"); #define BORDER 5 #define KING_STEP 6 <1>/* Graphics Not Rendered in HTML */ //See ::/Apps/GrModels for making 3D men. <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 */ <11>/* Graphics Not Rendered in HTML */ U8 *king_imgs[4] = {<2>, <1>, <2>, <3>}; U8 *peasant_imgs[4] = {<5>, <4>, <5>, <6>}; #define TREES_NUM 8 class Tree { U16 x, y; I64 fire_frame_idx; } trees[TREES_NUM]; U64 snow_x, snow_y, new_snow_mS; #define SNOW_TILE_SIZE 128 CDC *snow_tile; I64 king_x, king_y, king_mS, king_phase, not_stopped_count; F64 king_timeout, king_theta, t0, tf, door_open_t0; I64 animate_mS, animate_phase; #define PEASANTS_NUM 10 class Peasant { Peasant *next, *last; F64 x, y, theta, door_opened_t0; Bool stopped; } peasant_head; class Step { Step *next, *last; U16 x, y; F64 t0; } step_head, king_step_head; U0 DrawIt(CTask *task, CDC *dc) { I64 r[16], i, w = task->pix_width, h = task->pix_height, x, y; U8 *img, *tmps; Step *tmpst; Peasant *tmpp; F64 tt; dc->thick = 1; for (i = 0; i < TREES_NUM; i++) { if (trees[i].y <= h / 2) {//Draw trees behind house if (trees[i].fire_frame_idx) { if (trees[i].fire_frame_idx++ & 1) img = <8>; else img = <9>; } else img = <7>; Sprite3(dc, trees[i].x, trees[i].y, 0, img); } } Sprite3(dc, w / 2, h / 2, 0, <10>); if (tS < door_open_t0 + 1.0) Sprite3(dc, w / 2, h / 2, 0, <11>); for (i = 0; i < TREES_NUM; i++) { if (trees[i].y > h / 2) {//Draw trees in front of house if (trees[i].fire_frame_idx) { if (trees[i].fire_frame_idx++ & 1) img = <8>; else img = <9>; } else img = <7>; Sprite3(dc, trees[i].x, trees[i].y, 0, img); } } tmpst = step_head.next; while (tmpst != &step_head) { if (tS - tmpst->t0 < 2.0) dc->color = DKGRAY; else dc->color = LTGRAY; dc->thick = 4; GrPlot3(dc, tmpst->x, tmpst->y, 0); tmpst = tmpst->next; } DCDepthBufAlloc(dc); dc->flags |= DCF_TRANSFORMATION; dc->thick = 1; tmpp = peasant_head.next; while (tmpp != &peasant_head) { Mat4x4IdentEqu(r); Mat4x4RotY(r, tmpp->theta + pi / 2); Mat4x4RotX(r, pi / 6); if (tmpp->stopped) Sprite3Mat4x4B(dc, tmpp->x, tmpp->y, GR_Z_ALL, peasant_imgs[0], r); else { tmps = SpriteInterpolate(Saw(animate_mS / 250.0, 1.0), peasant_imgs[ animate_phase & 3], peasant_imgs[(animate_phase + 1) & 3]); Sprite3Mat4x4B(dc, tmpp->x, tmpp->y, GR_Z_ALL, tmps, r); Free(tmps); } tmpp = tmpp->next; } dc->thick = 1; Mat4x4IdentEqu(r); Mat4x4RotY(r, king_theta + pi / 2); Mat4x4RotX(r, pi / 6); if (tS>king_timeout) Sprite3Mat4x4B(dc, king_x, king_y, GR_Z_ALL, king_imgs[0], r); else { tmps = SpriteInterpolate(Saw(king_mS / 250.0, 1.0), king_imgs[ king_phase & 3], king_imgs[(king_phase + 1) & 3]); Sprite3Mat4x4B(dc, king_x, king_y, GR_Z_ALL, tmps, r); Free(tmps); } dc->thick = 1; dc->color = ROP_MONO | WHITE; for (y = snow_y % SNOW_TILE_SIZE - SNOW_TILE_SIZE; y <= h; y += SNOW_TILE_SIZE) for (x = snow_x % SNOW_TILE_SIZE - SNOW_TILE_SIZE; x <= w; x += SNOW_TILE_SIZE) GrBlot(dc, x, y, snow_tile); if (tf) { dc->color = LTRED; if (Blink) GrPrint(dc, w / 2 - (FONT_WIDTH * 14) / 2, h / 2 + FONT_HEIGHT, "Game Completed"); tt = tf; } else { tt = tS; } dc->color = LTBLUE; GrPrint(dc, 0, 0, "Freezing Peasants:%d Time:%3.2f Best:%3.2f", not_stopped_count, tt - t0, best_score); } U0 StepNew(CTask *task, I64 x, I64 y, F64 theta, Bool left_right, Bool king) { Step *tmps; if (king) { tmps = MAlloc(sizeof(Step), task); tmps->x = x; tmps->y = y; tmps->t0 = tS; QueueInsert(tmps, king_step_head.last); } if (left_right) { tmps = MAlloc(sizeof(Step), task); tmps->x = x - 3.5 * Sin(theta) + 2.0 * Cos(theta); tmps->y = y + 3.5 * Cos(theta) + 2.0 * Sin(theta); tmps->t0 = tS; QueueInsert(tmps, step_head.last); tmps=MAlloc(sizeof(Step), task); tmps->x = x - 3.5 * Sin(theta) + 5.0 * Cos(theta); tmps->y = y + 3.5 * Cos(theta) + 5.0 * Sin(theta); tmps->t0 = tS; QueueInsert(tmps, step_head.last); } else { tmps = MAlloc(sizeof(Step), task); tmps->x = x + 3.5 * Sin(theta) + 0.0 * Cos(theta); tmps->y = y - 3.5 * Cos(theta) + 0.0 * Sin(theta); tmps->t0 = tS; QueueInsert(tmps, step_head.last); tmps = MAlloc(sizeof(Step), task); tmps->x = x + 3.5 * Sin(theta) + 3.0 * Cos(theta); tmps->y = y - 3.5 * Cos(theta) + 3.0 * Sin(theta); tmps->t0 = tS; QueueInsert(tmps, step_head.last); } } U0 Init() { I64 i, min_x, max_x, min_y, max_y, w = Fs->pix_width, h = Fs->pix_height; Peasant *tmpp; snow_x = snow_y = 0; new_snow_mS = 0; snow_tile = DCNew(SNOW_TILE_SIZE, SNOW_TILE_SIZE); SpriteExtents(<7>, &min_x, &max_x, &min_y, &max_y); for (i = 0; i < TREES_NUM; i++) { trees[i].x = RandU16 % (w - 2 * BORDER - (max_x - min_x + 1)) + BORDER - min_x; trees[i].y = RandU16 % (h - 2 * BORDER - (max_y - min_y + 1)) + BORDER - min_y; trees[i].fire_frame_idx = 0; } QueueInit(&step_head); QueueInit(&king_step_head); SpriteExtents(<12>, &min_x, &max_x, &min_y, &max_y); QueueInit(&peasant_head); for (i = 0; i < PEASANTS_NUM; i++) { tmpp = MAlloc(sizeof(Peasant)); tmpp->x = RandU16 % (w - 2 * BORDER - (max_x - min_x + 1)) + BORDER - min_x; tmpp->y = RandU16 % (h - 2 * BORDER - (max_y - min_y + 1)) + BORDER - min_y; tmpp->theta = pi * 2 * Rand; tmpp->door_opened_t0 = 0; tmpp->stopped = FALSE; QueueInsert(tmpp, peasant_head.last); } animate_phase = 0; animate_mS = 0; king_phase = 0; king_mS = 0; king_timeout = 0; king_x = w / 2; king_y = h / 2; king_theta = -pi / 2; door_open_t0 = 0; t0 = tS; tf = 0; } U0 CleanUp() { DCDel(snow_tile); QueueDel(&peasant_head, TRUE); QueueDel(&step_head, TRUE); QueueDel(&king_step_head, TRUE); } U0 Follow(CTask *, Peasant *tmpp) { Step *tmps = king_step_head.next; F64 d, best_d = F64_MAX; while (tmps != &king_step_head) { if ((d = Sqr(tmps->x - tmpp->x) + Sqr(tmps->y - tmpp->y)) && d < 15 * 15) { d += 1000 * Sqr(tS - tmps->t0); if (d < best_d) { best_d = d; tmpp->theta = Arg(tmps->x - tmpp->x, tmps->y - tmpp->y); } } tmps = tmps->next; } } U0 AnimateTask(I64) { Step *tmps, *tmps1; Peasant *tmpp; I64 i, w, h; while (TRUE) { w = Fs->parent_task->pix_width; h = Fs->parent_task->pix_height; tmps = step_head.next; while (tmps != &step_head) { tmps1 = tmps->next; if (tS - tmps->t0 > 5.0) { QueueRemove(tmps); Free(tmps); } tmps = tmps1; } tmps = king_step_head.next; while (tmps != &king_step_head) { tmps1 = tmps->next; if (tS - tmps->t0 > 3.0) { QueueRemove(tmps); Free(tmps); } tmps = tmps1; } not_stopped_count = 0; tmpp = peasant_head.next; while (tmpp != &peasant_head) { if (tmpp->stopped) { if (tmpp->door_opened_t0 && tS > tmpp->door_opened_t0 + 1.0) { tmpp->door_opened_t0 = 0; tmpp->y = tmpp->x = -9999; } } else { if (Sqr(tmpp->x - w / 2) + Sqr(tmpp->y - h / 2) < 20 * 20) { tmpp->stopped = TRUE; tmpp->door_opened_t0 = door_open_t0 = tS; } for (i = 0; i < TREES_NUM; i++) //Hang-out by fire if (trees[i].fire_frame_idx && Sqr(tmpp->x - trees[i].x) + Sqr(tmpp->y - trees[i].y) < 20 * 20) { tmpp->stopped = TRUE; break; } if (!tmpp->stopped) { Follow(Fs->parent_task, tmpp); tmpp->x += Cos(tmpp->theta) / 100; tmpp->y += Sin(tmpp->theta) / 100; if (!(BORDER / 2 <= tmpp->x < w - BORDER / 2) || !(BORDER / 2 <= tmpp->y < h - BORDER / 2)) { tmpp->theta += pi; tmpp->x += 3 * Cos(tmpp->theta) / 100; tmpp->y += 3 * Sin(tmpp->theta) / 100; } if (!animate_mS && animate_phase & 1) StepNew(Fs->parent_task, tmpp->x, tmpp->y, tmpp->theta, animate_phase & 2, FALSE); not_stopped_count++; } } tmpp = tmpp->next; } if (!not_stopped_count && !tf) { tf = tS; music.mute = TRUE; Sound(86); Sleep(200); Sound; Sleep(100); if (tf - t0 < best_score) { best_score = tf - t0; Sound(86); Sleep(200); Sound; Sleep(100); } music.mute = FALSE; } snow_x += RandU16 % 3 - 1; snow_y += 1 - SignI64(RandU16 & 3); if (new_snow_mS++ > 8) { new_snow_mS = 0; snow_tile->color = WHITE; GrPlot(snow_tile, RandU16 & (SNOW_TILE_SIZE - 1), RandU16 & (SNOW_TILE_SIZE - 1)); } Sleep(1); if (animate_mS++ >= 250) { animate_mS = 0; animate_phase = (animate_phase + 1) & 3; } if (tS < king_timeout) { if (king_mS++ >= 250) { king_mS = 0; king_phase |= 1; } } } } U0 BurnTrees() { I64 i; for (i = 0; i < TREES_NUM; i++) if (Sqr(king_x - trees[i].x) + Sqr(king_y - trees[i].y) < 10 * 10) trees[i].fire_frame_idx = 1; } U0 SongTask(I64) { Fs->task_end_cb = &SoundTaskEndCB; MusicSettingsReset; music.tempo = 2.480; music.stacatto_factor = 0.902; while (TRUE) { Play("5eCCCDCC4qGeAGAB5qCC"); Play("5eCCCDCC4qGeAGAB5qCC"); Play("5eGFEDEDqC4eAGAB5qCC"); } } U0 Wenceslas() { I64 sc; MenuPush( "File {" " Abort(,CH_SHIFT_ESC);" " Exit(,CH_ESC);" "}" "Play {" " Restart(,'\n');" " BurnTree(,CH_SPACE);" " 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->song_task = Spawn(&SongTask, NULL, "Song",, Fs); PopUpOk(" Good King Wenceslas looked out On the feast of Stephen When the snow lay round about Deep and crisp and even Brightly shone the moon that night Though the frost was cruel When a poor man came in sight Gath'ring winter fuel \"Hither, page, and stand by me If thou know'st it, telling Yonder peasant, who is he? Where and what his dwelling?\" \"Sire, he lives a good league hence Underneath the mountain Right against the forest fence By Saint Agnes' fountain.\" \"Bring me flesh and bring me wine Bring me pine logs hither Thou and I will see him dine When we bear him thither.\" Page and monarch forth they went Forth they went together Through the rude wind's wild lament And the bitter weather "); PopUpOk(" \"Sire, the night is darker now And the wind blows stronger Fails my heart, I know not how, I can go no longer.\" \"Mark my footsteps, my good page Tread thou in them boldly Thou shalt find the winter's rage Freeze thy blood less coldly.\" In his master's steps he trod Where the snow lay dinted Heat was in the very sod Which the Saint had printed Therefore, Christian men, be sure Wealth or rank possessing Ye who now will bless the poor Shall yourselves find blessing "); PopUpOk(" $PURPLE$$TX+CX,\"Winceslas Game\"$$FG$ Start fires by pressing $GREEN$<SPACE>$FG$ on trees. (Yule logs) Lead peasants to fires. "); Init; Fs->animate_task = Spawn(&AnimateTask, NULL, "Animate",, Fs); Fs->draw_it = &DrawIt; try { while (TRUE) { switch (KeyGet(&sc)) { case '\n': CleanUp; Init; break; case CH_ESC: case CH_SHIFT_ESC: goto ws_done; case CH_SPACE: BurnTrees; break; case 0: switch (sc.u8[0]) { start: case SC_CURSOR_RIGHT: if (king_x + KING_STEP < Fs->pix_width - BORDER) king_x += KING_STEP; king_theta = 0; break; case SC_CURSOR_LEFT: if (king_x - KING_STEP >= BORDER) king_x -= KING_STEP; king_theta = pi; break; case SC_CURSOR_DOWN: if (king_y + KING_STEP < Fs->pix_height - BORDER) king_y += KING_STEP; king_theta = -pi / 2; break; case SC_CURSOR_UP: if (king_y - KING_STEP >= BORDER) king_y -= KING_STEP; king_theta = pi / 2; break; end: king_mS = 0; king_phase = (king_phase + 2) & 2; StepNew(Fs, king_x, king_y, king_theta, king_phase & 2, TRUE); king_timeout = tS + 0.5; break; } } } ws_done: } catch PutExcept; SettingsPop; CleanUp; MenuPop; RegWrite("ZealOS/Wenceslas", "F64 best_score=%5.4f;\n", best_score); } Wenceslas;