void CALakes() { for (int y = 0; y < torch.buf.geth(); y++) { for (int x = 0; x < torch.buf.getw(); x++) { if (!game.map.solid(x,y) && (rand8() < 23) && countFoo(x,y,6,GLASS)) set_tile(x,y, WATER); } } bool *next = new bool[torch.buf.geth()*torch.buf.getw()]; for (int i = 0; i < 4; i++) { memset(next, 0, torch.buf.geth()*torch.buf.getw()*sizeof(bool)); for (int y = 0; y < torch.buf.geth(); y++) { for (int x = 0; x < torch.buf.getw(); x++) { if (countFoo(x,y,1,WATER) >= 2) next[y*torch.buf.getw()+x] = true; else next[y*torch.buf.getw()+x] = false; } } for (int y = 0; y < torch.buf.geth(); y++) { for (int x = 0; x < torch.buf.getw(); x++) { //if (!game.map.at(x,y)->desc()->solid || game.map.at(x,y)->type == WATER) { if (game.map.at(x,y)->type != GLASS && game.map.at(x,y)->type != 0) { if (next[y*torch.buf.getw()+x]) set_tile(x,y, WATER); else if (game.map.at(x,y)->type == WATER) set_tile(x,y, GROUND); } } } } for (int i = 0; i < 3; i++) { memset(next, 0, torch.buf.geth()*torch.buf.getw()*sizeof(bool)); for (int y = 0; y < torch.buf.geth(); y++) { for (int x = 0; x < torch.buf.getw(); x++) { if (countFoo(x,y,1,WATER) >= 4 - countFoo(x,y,1,GLASS) && countFoo(x,y,2,WATER) >= 16 - countFoo(x,y,2,GLASS)) next[y*torch.buf.getw()+x] = true; else next[y*torch.buf.getw()+x] = false; } } for (int y = 0; y < torch.buf.geth(); y++) { for (int x = 0; x < torch.buf.getw(); x++) { if (!game.map.solid(x,y) || game.map.at(x,y)->type == WATER) { if (next[y*torch.buf.getw()+x]) set_tile(x,y, WATER); else set_tile(x,y, GROUND); } } } } delete [] next; int w = 0; for (int y = 0; y < torch.buf.geth(); y++) { for (int x = 0; x < torch.buf.getw(); x++) { if (game.map.at(x,y)->type == WATER) w++; } } printf("%d water cells. ", w); }
void CATrees() { for (int y = 0; y < torch.buf.geth(); y++) { for (int x = 0; x < torch.buf.getw(); x++) { if (!game.map.solid(x,y) && (rand4() < 6)) set_tile(x,y, TREE); } } bool *next = new bool[torch.buf.geth()*torch.buf.getw()]; for (int i = 0; i < 4; i++) { memset(next, 0, torch.buf.geth()*torch.buf.getw()*sizeof(bool)); for (int y = 0; y < torch.buf.geth(); y++) { for (int x = 0; x < torch.buf.getw(); x++) { if (countTrees(x,y,2) <= 3 || countTrees(x,y,1) >= 5) next[y*torch.buf.getw()+x] = true; else next[y*torch.buf.getw()+x] = false; } } for (int y = 0; y < torch.buf.geth(); y++) { for (int x = 0; x < torch.buf.getw(); x++) { if (!game.map.solid(x,y) || game.map.at(x,y)->type == TREE) { if (next[y*torch.buf.getw()+x]) set_tile(x,y, TREE); else set_tile(x,y, GROUND); } } } } for (int i = 0; i < 3; i++) { memset(next, 0, torch.buf.geth()*torch.buf.getw()*sizeof(bool)); for (int y = 0; y < torch.buf.geth(); y++) { for (int x = 0; x < torch.buf.getw(); x++) { if (countTrees(x,y,1) >= 5) next[y*torch.buf.getw()+x] = true; else next[y*torch.buf.getw()+x] = false; } } for (int y = 0; y < torch.buf.geth(); y++) { for (int x = 0; x < torch.buf.getw(); x++) { if (!game.map.solid(x,y) || game.map.at(x,y)->type == TREE) { if (next[y*torch.buf.getw()+x]) set_tile(x,y, TREE); else set_tile(x,y, GROUND); } } } } delete [] next; }
extern State *process_splash( State *state , int new_keys , int old_keys ) { int up_pressed = old_keys & KEY_UP && (new_keys & KEY_UP) == 0; int down_pressed = old_keys & KEY_DOWN && (new_keys & KEY_DOWN) == 0; if ( state->type == STATE_TRADE ) { if ( up_pressed ) { state->player.item = state->trader_item; state->trader_item = (state->trader_item + 1);// % (MAX_ITEM + 1); set_tile( & state->map, TILE_FLOOR , state->player.entity.position ); change_state( state, STATE_FREE ); } else if ( down_pressed ) { state->trader_item = (state->trader_item + 1);// % (MAX_ITEM + 1); set_tile( & state->map, TILE_FLOOR , state->player.entity.position ); change_state( state, STATE_FREE ); } } else if ( state->type == STATE_BOSS ) { if ( up_pressed ) { StateType next = state->player.item == ITEM_POTATO ? STATE_WON : STATE_OVER; change_state( state, next ); } } else if (state->type == STATE_WON || state->type == STATE_OVER) { if (up_pressed) { state->requested_quit = 1; } } else { if (old_keys & KEY_UP && (new_keys & KEY_UP) == 0) { StateType next = state->type == STATE_SPLASH ? STATE_INTRO : STATE_FREE; change_state(state, next); } } return state; }
void test_map() { game.map.resize(64,64); torch.buf.resize(64,64); s16 cx = torch.buf.getw()/2, cy = torch.buf.geth()/2; filledCircle(cx, cy, 30, set_tile_i, (void*)GROUND); hollowCircle(cx, cy, 30, set_tile_i, (void*)GLASS); game.player.x = cx; game.player.y = cy; game.map.at(cx,cy)->creature = &game.player; game.player.setPos(cx,cy); lightsource *li; set_tile(cx+5, cy, FIRE); li = new lightsource; li->set(12<<12, (int)(0.1*(1<<12)), (int)(1.0*(1<<12)), (int)(0.1*(1<<12))); li->x = (cx+5)<<12; li->y = cy<<12; game.map.lights.push(li); set_tile(cx-5, cy, FIRE); li = new lightsource; li->set(12<<12, (int)(1.0*(1<<12)), (int)(0.1*(1<<12)), (int)(0.1*(1<<12))); li->x = (cx-5)<<12; li->y = cy<<12; game.map.lights.push(li); set_tile(cx, cy-5, FIRE); li = new lightsource; li->set(12<<12, (int)(0.1*(1<<12)), (int)(0.1*(1<<12)), (int)(1.0*(1<<12))); li->x = cx<<12; li->y = (cy-5)<<12; game.map.lights.push(li); Object *on = addObject(cx+2, cy-1, VENDING_MACHINE); on->quantity = rand4() + 10; DIRECTION orientation = D_WEST; on->orientation = orientation; li = new lightsource; li->set(orientation, 4<<12, 150<<12, 1<<12, 1<<11, 1<<11); li->x = (cx+2)<<12; li->y = (cy-1)<<12; li->flicker = FLICKER_LIGHT; game.map.lights.push(li); game.map.block.refresh_blocked_from(); }
//===========================================================================================================// // Constructors / Destructors // //===========================================================================================================// rex_sprite::rex_sprite(int _version, int _width, int _height, int _num_layers) :version(_version), width(_width), height(_height), num_layers(_num_layers) { layers.resize(num_layers); //All layers above the first are set transparent. for (int l = 1; l < num_layers; l++) { for (int i = 0; i < width*height; ++i) { rltk::vchar t = transparent_tile(); set_tile(l, i, t); } } }
/** * @brief Frees a given region * @details This frees a given region, marking it as free so that other shadow * maps can use the space again. The region should be the same as returned * by ShadowAtlas::find_and_reserve_region. * * If an invalid region is passed, an assertion is triggered. If assertions * are compiled out, undefined behaviour will occur. * * @param region Region to free */ void ShadowAtlas::free_region(const LVecBase4i& region) { // Out of bounds check, can't hurt nassertv(region.get_x() >= 0 && region.get_y() >= 0); nassertv(region.get_x() + region.get_z() <= _num_tiles && region.get_y() + region.get_w() <= _num_tiles); _num_used_tiles -= region.get_z() * region.get_w(); for (size_t x = 0; x < region.get_z(); ++x) { for (size_t y = 0; y < region.get_w(); ++y) { // Could do an assert here, that the tile should have been used (=true) before set_tile(region.get_x() + x, region.get_y() + y, false); } } }
/** * @brief Internal method to reserve a region in the atlas. * @details This reserves a given region in the shadow atlas. The region should * be in tile space.This is called by the ShadowAtlas::find_and_reserve_region. * It sets all flags in that region to true, indicating that those are used. * When an invalid region is passed, an assertion is triggered. If assertions * are optimized out, undefined behaviour occurs. * * @param x x- start positition of the region * @param y y- start position of the region * @param w width of the region * @param h height of the region */ void ShadowAtlas::reserve_region(size_t x, size_t y, size_t w, size_t h) { // Check if we are out of bounds, this should be disabled for performance // reasons at some point. nassertv(x >= 0 && y >= 0 && x + w <= _num_tiles && y + h <= _num_tiles); _num_used_tiles += w * h; // Iterate over every tile in the region and mark it as used for (size_t cx = 0; cx < w; ++cx) { for (size_t cy = 0; cy < h; ++cy) { set_tile(cx + x, cy + y, true); } } }
void AddGrass() { for (int i = 0; i < 4; i++) { for (int y = 0; y < torch.buf.geth(); y++) { for (int x = 0; x < torch.buf.getw(); x++) { if (game.map.at(x,y)->type != GROUND) continue; unsigned int nWater1 = countFoo(x,y,1,WATER), nWater2 = countFoo(x,y,2,WATER), nGrass1 = countFoo(x,y,1,GRASS), nGrass2 = countFoo(x,y,2,GRASS); if (rand4() < nWater1 || (rand8() & 0x1f) < nWater2 || rand4() < nGrass1/2 || (rand8() & 0x1f) < nGrass2/2 ) { set_tile(x,y, GRASS); } } } } }
void Map::alloc(VALUE self, uint w, uint h) { map_width = w; map_height = h; uint mapSize = map_width * map_height; tiles = rb_ary_new2(mapSize); VALUE ground = rb_str_new2("Ground"); for (uint j = 0; j != map_height; ++j) { for (uint i = 0; i != map_width; ++i) { VALUE t = rb_funcall(self, rb_intern("new_tile"), 1, ground); set_tile(i, j, t); } //printf("."); fflush(stdout); } //printf("\n"); }
Level::Level(std::string file_name, int row, int column){ this->file_name = file_name; this->row = row; this->column = column; total_tile = row * column; tiles = NULL; total_sprites = 2; sprite_list = new Sprite*[total_sprites]; sprite_list[0] = new Exit(10 * TILE_WIDTH, 2 * TILE_HEIGHT); sprite_list[1] = new GlassDoor(5 * TILE_WIDTH+ 10, 3 * TILE_HEIGHT); //sprite_list[2] = new Book(4 * TILE_WIDTH, 5 * TILE_HEIGHT); int pos1[2] = {80,120}; stick_master = new StickMaster(this,1,pos1); int pos2[2] = {280,160}; robot_master = new RobotMaster(this,1,pos2); state = PLAYING; set_clip(); set_tile(); }
void SpawnCreatures() { for (int i = 0, n = 40 + (rand8() % 32); i < n; i++) { s16 x = rand32() % torch.buf.getw(), y = rand32() % torch.buf.geth(); if (game.map.walkable(x,y)) { game.map.spawn(BLOWFLY, x, y); } else i--; } for (int i = 0, n = 20 + rand4(); i < n; i++) { s16 x = rand32() % torch.buf.getw(), y = rand32() % torch.buf.geth(); if (game.map.at(x,y)->type == TREE && countFoo(x,y,1,GROUND) >= 1) { game.map.spawn(VENUS_FLY_TRAP, x, y); set_tile(x,y, GROUND); } else i--; } for (int i = 0, n = 15 + rand4(); i < n; i++) { s16 x = rand32() % torch.buf.getw(), y = rand32() % torch.buf.geth(); if (game.map.walkable(x,y)) { game.map.spawn(LABRADOR, x, y); } else i--; } for (int y = 0; y < torch.buf.geth(); y++) { for (int x = 0; x < torch.buf.getw(); x++) { if (!game.map.occupied(x,y) && game.map.at(x,y)->type == WATER && (rand8() & 0x3f) == 0) { Creature *wisp = new Creature(WILL_O_WISP); wisp->setPos(x,y); game.map.at(x,y)->creature = wisp; game.map.monsters.push(wisp); lightsource *li = new lightsource(3<<12,0,1<<11,1<<12); li->orig_intensity = li->intensity = 1<<11; li->x = x<<12; li->y = y<<12; game.map.lights.push(li); wisp->light = li; } } } }
int main() { grid testG = new_grid(); printf("grid created\n"); add_tile(testG); bool isGameOver = game_over(testG); if(isGameOver) // check if an empty grid is a gameover { return EXIT_FAILURE; } else printf("game not over with an empty grid\n"); // FILLING THE GRID WITH UNIQUE VALUES int k = 1; for(int i = 0; i < GRID_SIDE; i++) { for(int j = 0; j < GRID_SIDE; j++) { set_tile(testG, i, j, (tile)k); printf("[%d][%d]:%d\n", i, j, get_tile(testG, i, j)); k++; } } isGameOver = game_over(testG); if(!isGameOver) return EXIT_FAILURE; // check if it's game over with a grid filled with unique values else printf("gameover with a grid filled with unique values\n"); delete_grid(testG); printf("grid deleted\n"); return EXIT_SUCCESS; }
// helper function for passing to the gfxPrimitives generics static void set_tile_i(s16 x, s16 y, void* type) { set_tile(x,y,(int)type); }
void ChunkLayer::set_tile(IntPoint point, Tile tile_type) { set_tile(point.row, point.col, tile_type); }
extern State *process_free( State * const state , const int new_keys , const int old_keys ) { Entity * const player_entity = & state->player.entity; int moved = 0; if ( is_moving( player_entity ) == 0 ) { if (new_keys & KEY_UP) { player_entity->destination.y -= 1; moved = 1; } else if (new_keys & KEY_DOWN) { player_entity->destination.y += 1; moved = 1; } else if (new_keys & KEY_LEFT) { player_entity->destination.x -= 1; moved = 1; } else if (new_keys & KEY_RIGHT) { player_entity->destination.x += 1; moved = 1; } } if ( moved ) { const int destination = tile_at( & state->map , player_entity->destination ); const int current = tile_at( & state->map , player_entity->position ); const int antydest = antydestination_tile(state); if ( ( ! POINT_EQ( player_entity->destination , player_entity->previous_position ) ) && ( destination == TILE_STRING && antydest == TILE_STRING ) ) { cancel_move( player_entity ); } else { if (current == TILE_FLOOR && destination != TILE_STRING) { set_tile( & state->map, TILE_STRING, player_entity->position); } else if ( current == TILE_STRING && destination != TILE_FLOOR) { set_tile( & state->map, TILE_FLOOR, player_entity->position); } } Boulder * b = boulder_at( state, player_entity->destination ); if ( b != NULL ) { int i = player_entity->destination.x - player_entity->position.x; int j = player_entity->destination.y - player_entity->position.y; Point boulder_dest; boulder_dest.x = player_entity->destination.x + i; boulder_dest.y = player_entity->destination.y + j; TileType boulder_dest_tile = tile_at( & state->map, boulder_dest); if ( boulder_dest_tile == TILE_FLOOR ) { b->entity.destination = boulder_dest; } else { cancel_move( player_entity ); } } } return state; }
LongWalkChallenge::LongWalkChallenge(ChallengeData *challenge_data): Challenge(challenge_data) { ChallengeHelper::make_sprite(this, "sprite/1", "Ben", Walkability::BLOCKED, "south/still/1"); ChallengeHelper::make_sprite(this, "sprite/2", "Ashley", Walkability::BLOCKED, "south/still/1"); ChallengeHelper::make_sprite(this, "sprite/3", "Joshua", Walkability::BLOCKED, "south/still/1"); // //Test chest // int lawnmower_mat_id(make_map_object( // glm::ivec2(10, 15), // "lawnmower", // Walkability::BLOCKED, // TextureAtlas::from_name("mat"), // "" // )); // ChallengeHelper::create_pickupable( // glm::ivec2(10, 15), // glm::ivec2(10, 14), // lawnmower_mat_id // ); // Ignore references due to non-interaction ChallengeHelper::make_object(this, "treasure/path/medium/chest", Walkability::BLOCKED, "closed"); ChallengeHelper::make_object(this, "treasure/path/long/chest", Walkability::BLOCKED, "closed"); // // Testing lawn // ChallengeHelper::make_interactions("grass/path/short", // std::back_inserter(grass_path_short_callbacks), // [lawnmower_mat_id] (int who) { // auto sprite(ObjectManager::get_instance().get_object<Sprite>(who)); // if (!sprite) { return true; } // if (sprite->is_in_inventory(lawnmower_mat_id)) { // Engine::print_dialogue("Grass", "You're mowing, keep on going"); // Engine::change_tile(sprite->get_position(), 4, "lawn_mown"); // return false; // } // else { // Engine::print_dialogue("Grass", "Don't forget the lawn mower"); // return true; // } // }); // Set up blocking walls ChallengeHelper::make_objects(this, "wall/path/medium", Walkability::BLOCKED, std::back_inserter(wall_path_medium_objects)); ChallengeHelper::make_objects(this, "wall/path/long", Walkability::BLOCKED, std::back_inserter(wall_path_long_objects)); // Set up notifications about walls ChallengeHelper::make_interactions("blocked_alert/path/medium", std::back_inserter(blocked_alert_path_medium_callbacks), [this] (int id) { Engine::print_dialogue("Tom", "Get the treasure and press \"e\" to view it!\n"); auto sprite(ObjectManager::get_instance().get_object<Sprite>(id)); sprite->daemon->value->halt_soft(EntityThread::Signal::KILL); finish(); ChallengeHelper::unregister_all(&blocked_alert_path_medium_callbacks); return false; }); ChallengeHelper::make_interactions("blocked_alert/path/long", std::back_inserter(blocked_alert_path_long_callbacks), [this] (int) { Engine::print_dialogue("Tom", "Hey... you missed the treasure!\n"); ChallengeHelper::unregister_all(&blocked_alert_path_long_callbacks); return false; }); // Set up treasure chest triggers ChallengeHelper::make_interaction("treasure/path/medium/carpet", [this] (int) { Engine::print_dialogue ("Tom", "Who knew treasure was so close?\n" "\n" "To open it up and see what's inside, press \"e\".\n" ); editor_lifeline = this->challenge_data->input_manager->register_keyboard_handler(filter( {ANY_OF({KEY_PRESS}), KEY({"E"})}, [this] (KeyboardInputEvent) { std::string id = std::to_string(Engine::get_map_viewer()->get_map_focus_object()); std::string filename = "John_" + id + ".py"; Engine::open_editor(filename); for (auto wall_object_id : wall_path_medium_objects) { auto wall_object(ObjectManager::get_instance().get_object<MapObject>(wall_object_id)); wall_object->set_tile(TextureAtlas::from_name("test/blank")); wall_object->set_walkability(Walkability::WALKABLE); } } )); return false; }); ChallengeHelper::make_interaction("treasure/path/long/carpet", [this] (int) { Engine::print_dialogue("Game", "Nice, more treasure!\n" "I doubt the next bit is going to be short enough to just walk...\n" "You should try to program it.\n" ); for (auto wall_object_id : wall_path_long_objects) { auto wall_object(ObjectManager::get_instance().get_object<MapObject>(wall_object_id)); wall_object->set_tile(TextureAtlas::from_name("test/blank")); wall_object->set_walkability(Walkability::WALKABLE); } return false; }); // Some more verbal interaction ChallengeHelper::make_interactions("room/first/exit", std::back_inserter(room_first_exit_callbacks), [this] (int) { Engine::print_dialogue("Tom", "Well, hello!\n" "I heard there was treasure to the right...\n" "You should look for it! It's probably really close!\n" ); ChallengeHelper::unregister_all(&room_first_exit_callbacks); return false; }); ChallengeHelper::make_interactions("end", std::back_inserter(end_callbacks), [this] (int) { // TODO: FINISH SOMEHOW!! Engine::print_dialogue("Game", "You Win, Well Done !"); finish(); return true; }); }
void generate_terrarium() { game.map.resize(128,128); torch.buf.resize(128,128); s16 cx = torch.buf.getw()/2, cy = torch.buf.geth()/2; torch.buf.reset(); torch.buf.cache.reset(); game.map.reset(); // glass on the rim filledCircle(cx, cy, 60, set_tile_i, (void*)GROUND); hollowCircle(cx, cy, 60, set_tile_i, (void*)GLASS); AddStars(); u32 timerVal; printf("Growing trees... "); startTimer(); CATrees(); timerVal = stopTimer(); printf("done (%.2fs).\n", timerVal*1024/33.513982e6); printf("Filling lakes... "); startTimer(); CALakes(); timerVal = stopTimer(); printf("done (%.2fs).\n", timerVal*1024/33.513982e6); printf("Buying shrubberies... "); startTimer(); AddGrass(); timerVal = stopTimer(); printf("done (%.2fs).\n", timerVal*1024/33.513982e6); printf("Checking connectivity... "); if (checkConnected()) { printf("connected.\n"); } else { printf("\1\x1f\x01unconnected\2.\n"); } printf("Simulating inhabitation... "); Inhabit(); printf("done.\n"); printf("Spawning creatures... "); SpawnCreatures(); printf("done.\n"); printf("Dropping items... "); for (int i = 0; i < 60; i++) { s16 x = rand32() % torch.buf.getw(), y = rand32() % torch.buf.geth(); if (!game.map.solid(x,y)) { Object *on = new Object(ROCK); stack_item_push(game.map.at(x,y)->objects, on); } else i--; } printf("done.\n"); s16 x = cx, y = cy; while (!game.map.walkable(x, y)) randwalk(x, y); game.player.x = x; game.player.y = y; game.player.setPos(x,y); game.map.at(x,y)->creature = &game.player; Object *on = new Object(BATON); stack_item_push(game.map.at(x,y)->objects, on); on = new Object(LEATHER_JACKET); stack_item_push(game.map.at(x,y)->objects, on); on = new Object(PAIR_OF_BLUNDSTONE_BOOTS); stack_item_push(game.map.at(x,y)->objects, on); x = cx; y = cy; set_tile(cx+40, cy, FIRE); lightsource *li = new lightsource; li->set(9<<12, (int)(0.1*(1<<12)), (int)(1.0*(1<<12)), (int)(0.1*(1<<12))); li->orig_intensity = li->intensity = 1<<11; li->x = (cx+40)<<12; li->y = cy<<12; li->flicker = FLICKER_RADIUS; game.map.lights.push(li); set_tile(cx+30, cy, FIRE); li = new lightsource; li->set(9<<12, (int)(1.0*(1<<12)), (int)(0.1*(1<<12)), (int)(0.1*(1<<12))); li->orig_intensity = li->intensity = 1<<11; li->x = (cx+30)<<12; li->y = cy<<12; li->flicker = FLICKER_RADIUS; game.map.lights.push(li); set_tile(cx+35, cy-7, FIRE); li = new lightsource; li->set(9<<12, (int)(0.1*(1<<12)), (int)(0.1*(1<<12)), (int)(1.0*(1<<12))); li->orig_intensity = li->intensity = 1<<11; li->x = (cx+35)<<12; li->y = (cy-7)<<12; li->flicker = FLICKER_RADIUS; game.map.lights.push(li); game.map.block.refresh_blocked_from(); torch.dirty_screen(); torch.reset_luminance(); }
int playPuzzle(int NUR_ROWS, int NUR_COLS, int puzzle[NUR_ROWS][NUR_COLS], int puzzle_index) { int cursor_r = 0; int cursor_c = 0; // Load palette memcpy16(pal_bg_mem, SharedPal, SharedPalLen / 2); // Load tiles into CBB 0 (16x16) and 1 (8x8) // Each charblock is 0x4000, an 8x8 tile is 0x20 bytes, // so there are 512 8x8 tiles or 128 16x16 tiles in each charblock. memcpy16(tile_mem[0], tiles16Tiles, tiles16TilesLen / 2); memcpy16(tile_mem[1], tiles8Tiles, tiles8TilesLen / 2); // Load the 16x16 puzzle map into screenblocks 28-31 for (int r = 0; r < 32; r++) { for (int c = 0; c < 32; c++) { set_tile(28, r, c, OUTSIDE); } } for (int c = 0; c < NUR_COLS; c++) set_tile(28, NUR_ROWS, c, BOTTOM_EDGE); for (int r = 0; r < NUR_ROWS; r++) set_tile(28, r, NUR_COLS, RIGHT_EDGE); set_tile(28, NUR_ROWS, NUR_COLS, BOTTOM_RIGHT_CORNER); for (int r = 0; r < NUR_ROWS; r++) { for (int c = 0; c < NUR_COLS; c++) { set_tile(28, r, c, puzzle[r][c]); } } // Load the 16x16 cursor map into screenblocks 24-27 for (int r = 0; r < 32; r++) { for (int c = 0; c < 32; c++) { set_tile(24, r, c, TRANSPARENT); } } set_tile(24, cursor_r, cursor_c, CURSOR); // 8x8 tiles: // set up BG2 for a 4bpp 32x32t map, using charblock 1 and screenblock 22 (cursor) REG_BG2CNT = BG_CBB(1) | BG_SBB(22) | BG_4BPP | BG_REG_32x32; // set up BG3 for a 4bpp 32x32t map, using charblock 1 and screenblock 23 (puzzle squares) REG_BG3CNT = BG_CBB(1) | BG_SBB(23) | BG_4BPP | BG_REG_32x32; // 16x16 tiles: // set up BG0 for a 4bpp 64x64t map, using charblock 0 and screenblocks 24-27 (cursor) REG_BG0CNT = BG_CBB(0) | BG_SBB(24) | BG_4BPP | BG_REG_64x64; // set up BG1 for a 4bpp 64x64t map, using charblock 0 and screenblocks 28-31 (puzzle squares) REG_BG1CNT = BG_CBB(0) | BG_SBB(28) | BG_4BPP | BG_REG_64x64; if (small_tiles) { REG_DISPCNT = DCNT_MODE0 | DCNT_BG2 | DCNT_BG3; } else { REG_DISPCNT = DCNT_MODE0 | DCNT_BG0 | DCNT_BG1; } int max_horiz_offset_16 = NUR_COLS * 16 - 240; if (max_horiz_offset_16 < 0) max_horiz_offset_16 = 0; int max_vert_offset_16 = NUR_ROWS * 16 - 160; if (max_vert_offset_16 < 0) max_vert_offset_16 = 0; int max_horiz_offset_8 = NUR_COLS * 8 - 240; if (max_horiz_offset_8 < 0) max_horiz_offset_8 = 0; int max_vert_offset_8 = NUR_ROWS * 8 - 160; if (max_vert_offset_8 < 0) max_vert_offset_8 = 0; REG_BG0HOFS = REG_BG1HOFS = REG_BG2HOFS = REG_BG3HOFS = 0; REG_BG0VOFS = REG_BG1VOFS = REG_BG2VOFS = REG_BG3VOFS = 0; irq_init(NULL); irq_add(II_VBLANK, NULL); int key_repeat = 0; bool clearing = false; while (1) { VBlankIntrWait(); key_poll(); set_tile(24, cursor_r, cursor_c, TRANSPARENT); // remove the cursor if (key_hit(1 << KI_LEFT | 1 << KI_RIGHT | 1 << KI_UP | 1 << KI_DOWN)) { key_repeat = 0; // reset the key repeat timer } #define START_REPEAT 20 #define REPEAT_SPEED 2 if (key_is_down(1 << KI_LEFT | 1 << KI_RIGHT | 1 << KI_UP | 1 << KI_DOWN)) { if (key_repeat < START_REPEAT) key_repeat++; else key_repeat = START_REPEAT - REPEAT_SPEED; } bool virtual_left = key_hit(1 << KI_LEFT ) || (key_is_down(1 << KI_LEFT ) && key_repeat == START_REPEAT); bool virtual_right = key_hit(1 << KI_RIGHT) || (key_is_down(1 << KI_RIGHT) && key_repeat == START_REPEAT); bool virtual_up = key_hit(1 << KI_UP ) || (key_is_down(1 << KI_UP ) && key_repeat == START_REPEAT); bool virtual_down = key_hit(1 << KI_DOWN ) || (key_is_down(1 << KI_DOWN ) && key_repeat == START_REPEAT); bool moved_cursor = false; if (virtual_left && cursor_c > 0 ) { cursor_c--; REG_BG0HOFS = REG_BG1HOFS = (cursor_c * max_horiz_offset_16) / (NUR_COLS - 1); REG_BG2HOFS = REG_BG3HOFS = (cursor_c * max_horiz_offset_8 ) / (NUR_COLS - 1); moved_cursor = true; } if (virtual_right && cursor_c < NUR_COLS - 1) { cursor_c++; REG_BG0HOFS = REG_BG1HOFS = (cursor_c * max_horiz_offset_16) / (NUR_COLS - 1); REG_BG2HOFS = REG_BG3HOFS = (cursor_c * max_horiz_offset_8 ) / (NUR_COLS - 1); moved_cursor = true; } if (virtual_up && cursor_r > 0 ) { cursor_r--; REG_BG0VOFS = REG_BG1VOFS = (cursor_r * max_vert_offset_16) / (NUR_ROWS - 1); REG_BG2VOFS = REG_BG3VOFS = (cursor_r * max_vert_offset_8 ) / (NUR_ROWS - 1); moved_cursor = true; } if (virtual_down && cursor_r < NUR_ROWS - 1) { cursor_r++; REG_BG0VOFS = REG_BG1VOFS = (cursor_r * max_vert_offset_16) / (NUR_ROWS - 1); REG_BG2VOFS = REG_BG3VOFS = (cursor_r * max_vert_offset_8 ) / (NUR_ROWS - 1); moved_cursor = true; } if (key_hit(1 << KI_A)) { switch (puzzle[cursor_r][cursor_c]) { case WHITE: case BLACK: puzzle[cursor_r][cursor_c] = DOT; sram_mem[(puzzle_index + 1) * 1024 + cursor_r * NUR_COLS + cursor_c] = DOT; set_tile(28, cursor_r, cursor_c, DOT); clearing = false; break; case DOT: puzzle[cursor_r][cursor_c] = WHITE; sram_mem[(puzzle_index + 1) * 1024 + cursor_r * NUR_COLS + cursor_c] = WHITE; set_tile(28, cursor_r, cursor_c, WHITE); clearing = true; break; default: clearing = false; break; } } else if (key_is_down(1 << KI_A) && moved_cursor) { switch (puzzle[cursor_r][cursor_c]) { case WHITE: case BLACK: case DOT: if (clearing) { puzzle[cursor_r][cursor_c] = WHITE; sram_mem[(puzzle_index + 1) * 1024 + cursor_r * NUR_COLS + cursor_c] = WHITE; set_tile(28, cursor_r, cursor_c, WHITE); } else { puzzle[cursor_r][cursor_c] = DOT; sram_mem[(puzzle_index + 1) * 1024 + cursor_r * NUR_COLS + cursor_c] = DOT; set_tile(28, cursor_r, cursor_c, DOT); } break; } } if (key_hit(1 << KI_B)) { switch (puzzle[cursor_r][cursor_c]) { case WHITE: case DOT: puzzle[cursor_r][cursor_c] = BLACK; sram_mem[(puzzle_index + 1) * 1024 + cursor_r * NUR_COLS + cursor_c] = BLACK; set_tile(28, cursor_r, cursor_c, BLACK); clearing = false; break; case BLACK: puzzle[cursor_r][cursor_c] = WHITE; sram_mem[(puzzle_index + 1) * 1024 + cursor_r * NUR_COLS + cursor_c] = WHITE; set_tile(28, cursor_r, cursor_c, WHITE); clearing = true; break; default: clearing = false; break; } } else if (key_is_down(1 << KI_B) && moved_cursor) { switch (puzzle[cursor_r][cursor_c]) { case WHITE: case BLACK: case DOT: if (clearing) { puzzle[cursor_r][cursor_c] = WHITE; sram_mem[(puzzle_index + 1) * 1024 + cursor_r * NUR_COLS + cursor_c] = WHITE; set_tile(28, cursor_r, cursor_c, WHITE); } else { puzzle[cursor_r][cursor_c] = BLACK; sram_mem[(puzzle_index + 1) * 1024 + cursor_r * NUR_COLS + cursor_c] = BLACK; set_tile(28, cursor_r, cursor_c, BLACK); } break; } } if (key_hit(1 << KI_SELECT)) { small_tiles = !small_tiles; if (small_tiles) { REG_DISPCNT = DCNT_MODE0 | DCNT_BG2 | DCNT_BG3; } else { REG_DISPCNT = DCNT_MODE0 | DCNT_BG0 | DCNT_BG1; } } if (key_hit(1 << KI_L)) { return -1; // move 1 puzzle to the left } if (key_hit(1 << KI_R)) { return 1; // move 1 puzzle to the right } set_tile(24, cursor_r, cursor_c, CURSOR); // readd the cursor } }