#include "rogueviz.h" /* a sample higher dimensional Sokoban puzzle */ namespace rogueviz { namespace crystal_sokoban { vector sokomap = { "########|########|########|########|########|########|########|########", "########|########|## #####|## #####|########|########|########|########", "########|##. ####|# $ ###|##.$####|##. ####|########|########|########", "########|##.#####|# $$@###|## ####|## #####|########|########|########", "########|########|## #####|## #####|########|########|########|########", "########|########|########|########|########|########|########|########", "########|########|########|########|########|########|########|########", "########|########|########|########|########|########|########|########" }; bool on; bool created; vector celllist; struct undo_state { vector board; cell* where; }; vector undos; undo_state current_state() { undo_state u; u.where = cwt.at; for(cell *c: celllist) u.board.push_back(c->wall); return u; } void sb_hooks(); void run_sb() { showstartmenu = false; crystal::compass_probability = 0; stop_game(); crystal::set_crystal(6); set_variation(eVariation::pure); enable_canvas(); ccolor::set_plain(0x101010); check_cgi(); start_game(); for(int z=-8; z<8; z++) for(int y=-8; y<8; y++) for(int x=-8; x<8; x++) { crystal::coord co = crystal::c0; co[0] = 2*x; co[1] = 2*y; co[2] = 2*z; cell *c = crystal::get_heptagon_at(co)->c7; setdist(c, 7, c); } for(int z=-8; z<8; z++) for(int y=-8; y<8; y++) for(int x=-8; x<8; x++) { char what; if(x<0 || y<0 || z<0) what = '#'; else what = sokomap[y][x*9+z]; crystal::coord co = crystal::c0; co[0] = 2*x; co[1] = 2*y; co[2] = 2*z; cell *c = crystal::get_heptagon_at(co)->c7; color_t col; for(int i=0; i<3; i++) part(col, i) = 0x80 + 0x20 * (co[i] - 5); c->landparam = col; if(what == '#') c->wall = waStone; else if(what == '$') c->wall = waCrateCrate; else if(what == '*') c->wall = waCrateOnTarget; else if(what == '.') c->wall = waCrateTarget; else { c->wall = waNone; if(what == '@') { cwt.at = c; centerover = c; } } celllist.push_back(c); } vid.smart_range_detail = ISWEB ? 20 : 1; vid.use_smart_range = 2; undos.push_back(current_state()); peace::on = true; sb_hooks(); } void save_undo() { undos.push_back(current_state()); } void restore_undo() { undos.pop_back(); auto& u = undos.back(); cwt.at = u.where; current_display->which_copy = Id; int i = 0; for(cell *c: celllist) c->wall = u.board[i++]; undos.pop_back(); } bool sokomap2() { if(undos.back().where != cwt.at) save_undo(); if(1) { glflush(); dynamicval g(geometry, gEuclidSquare); check_cgi(); cgi.require_shapes(); initquickqueue(); if(1) { auto gm = gmatrix; dynamicval ww(wmspatial, false); dynamicval wm(mmspatial, false); dynamicval s1(playerV); dynamicval s2(current_display->which_copy); dynamicval s3(cwtV, cwtV); dynamicval, ANIMLAYERS>> an(animations); animations[LAYER_SMALL] = {}; for(int x=0; x<4; x++) for(int y=0; y<4; y++) for(int z=0; z<4; z++) { crystal::coord co = crystal::c0; co[0] = 2*x+2; co[1] = 2*y+2; co[2] = 2*z+2; cell *c = crystal::get_heptagon_at(co)->c7; drawcell(c, shiftless(euscale(.12,.12) * eupush(3+(vid.xres*1./vid.yres-1)*12, -16) * eupush(z*4.2+x, y) * Id)); } gmatrix = gm; } quickqueue(); glflush(); } check_cgi(); return true; } bool soko_key(int sym, int uni) { if((cmode & sm::NORMAL) && (uni == SDLK_BACKSPACE || uni == 'r') && isize(undos) != 1) { restore_undo(); return true; } return false; } void sb_hooks() { rv_hook(hooks_prestats, 90, sokomap2); rv_hook(hooks_welcome_message, 50, [] () { addMessage(XLAT("Welcome to Crystal Sokoban!")); return true; }); rv_hook(hooks_handleKey, 50, soko_key); on_cleanup_or_next([] { undos.clear(); celllist.clear(); }); } auto sbhook = arg::add2("-crystal-sokoban", run_sb); } }