namespace rogue_unlike { map in_queue; queue q; void visit(cell *c, int d) { if(in_queue.count(c)) return; in_queue[c] = d; q.push(c); } string unspace(const string& s) { string t; for(char c: s) if(c == ' ') t += "_"; else if(c == '\n') t += "@"; else t += c; return t; } string respace(const string& s) { string t; for(char c: s) if(c == '_') t += " "; else if(c == '@') t += "\n"; else t += c; return t; } void save_map(string fname) { in_queue.clear(); q = {}; visit(currentmap->gamestart(), -1); fhstream f(fname, "w"); while(!q.empty()) { auto c = q.front(); q.pop(); auto& r = rooms[c]; if(!r.infile) continue; for(int i=0; itype; i++) visit(c->cmove(i), c->c.spin(i)); if(!r.edited) continue; auto inq = in_queue[c]; if(inq != -1) { println(f, "MOVE ", c->c.spin(inq), " ", rooms[c->move(inq)].roomname); } println(f, "ROOM ", r.roomname); map code_for; map code_used; char next_code = 'A'; for(int y=0; y> 3; if(i == int(wRogueWallHidden)) i = int(wRogueWall); auto& c = code_for[i]; if(c == 0 && !code_used.count(walls[i].glyph[0])) c = walls[i].glyph[0]; if(c == 0) c = next_code++; code_used[c] = i; } for(auto [key, id]: code_used) println(f, format("%c", key), " ", walls[id].name); println(f, "MAP"); for(int y=0; y> 3; if(vi == int(wRogueWallHidden)) vi = int(wRogueWall); print(f, format("%c", (v & 7) == 7 ? 'b' : code_for[vi])); } println(f); } println(f, "OK\n"); } } void err(string s, string context) { println(hlog, "while: ", context, " reading: ", s); throw hr_exception("ru read error"); } void create_long_rope(room& r, int step, xy w) { ld radius = 2.7; ld qty = 300; ld period = 5; ld shift = 0; ld max_swing = 7.5; for(int i=0; i(); b->ctr = w; b->radius = radius; b->period = period; b->max_swing = max_swing * 1._deg; b->shift = shift; b->dist = radius * (i+0.5) / qty; r.entities.emplace_back(std::move(b)); } for(auto& p: rooms) if(&p.second == &r) { auto goto_rope = [&] (int i, int j) { create_long_rope(*get_room_at(p.first->cmove(i)), j, get<0>(get_next_room(w, &r, i))); }; if(step < 3) goto_rope(3, step + 1); if(step == 3) goto_rope(4, 4); if(step == 2) goto_rope(2, 4); if(step == 2) goto_rope(4, 4); if(step == 1) goto_rope(4, 4); break; } } mapswitch *lmev; void load_room(fhstream& f, cell *c) { setdist(c, 7, nullptr); auto& r = *get_room_at(c); r.save_to_save = true; string s = scanline_noblank(f); if(s.substr(0, 5) == "ROOM ") r.roomname = s.substr(5); else err("load_room name ", s); r.id = unspace(r.roomname); println(hlog, "loading room named: ", r.roomname); map codes; while(true) { string s = scanline_noblank(f); if(s == "") continue; if(s == "MAP") break; string t = s.substr(2); if(s.size() < 3 || s[1] != ' ') err("load codes", s); for(int i=0; i bmap; for(int y=0; y(); b->respawn = get_xy(); b->qty = param == "" ? 1 : get_int(); println(hlog, "qty is ", b->qty); b->p = &find_power(scanline_noblank(f)); b->id = unspace(b->pickup_message = scanline_noblank(f)); r.entities.emplace_back(std::move(b)); } else if(cap == "LOOT") { auto b = std::make_unique(); b->owner = &*r.entities.back(); b->qty = param == "" ? 1 : get_int(); b->p = &find_power(scanline_noblank(f)); b->id = unspace(b->pickup_message = scanline_noblank(f)); r.entities.emplace_back(std::move(b)); } else if(cap == "GUARD") { auto loot = &*r.entities.back(); println(hlog, "loot is ", loot->id); auto b = std::make_unique(); b->item = loot; b->monster = nullptr; b->monster_name = cutoff("NOTHING"); b->id = b->monster_name + "-GUARD"; println(hlog, "guard ", b->id, " added on ", b->item->id); r.entities.emplace_back(std::move(b)); } else if(cap == "SHOPITEM") { auto b = std::make_unique(); b->respawn = get_xy(); b->price = get_int(); b->qty = param == "" ? 1 : get_int(); b->qty1 = param == "" ? 0 : get_int(); b->p = &find_power(scanline_noblank(f)); b->id = unspace(b->pickup_message = scanline_noblank(f)); r.entities.emplace_back(std::move(b)); } else if(cap == "NPC") { auto b = std::make_unique(); b->respawn = get_xy(); b->col = get_color(); s = scanline_noblank(f); b->sglyph = s[0]; b->name = s.substr(1); b->id = unspace(b->name); b->text = scanline_noblank(f); r.entities.emplace_back(std::move(b)); } else if(cap == "TRADER") { auto b = std::make_unique(); b->respawn = get_xy(); b->name = scanline_noblank(f); b->text = scanline_noblank(f); b->id = unspace(b->name); r.entities.emplace_back(std::move(b)); } else if(cap == "BOAR") { auto b = std::make_unique(); nam(*b); b->respawn = get_xy(); r.entities.emplace_back(std::move(b)); } else if(cap == "GIANTFROG") { auto b = std::make_unique(); nam(*b); b->respawn = get_xy(); r.entities.emplace_back(std::move(b)); } else if(cap == "FROG") { auto b = std::make_unique(); nam(*b); b->respawn = get_xy(); r.entities.emplace_back(std::move(b)); } else if(cap == "TIMEORB") { auto b = std::make_unique(); b->respawn = get_xy(); b->duration = get_ld() * game_fps; r.entities.emplace_back(std::move(b)); } else if(cap == "DARKORB") { auto b = std::make_unique(); nam(*b); b->respawn = get_xy(); b->box = get_box(); r.entities.emplace_back(std::move(b)); } else if(cap == "BAT") { auto b = std::make_unique(); nam(*b); b->respawn = get_xy(); r.entities.emplace_back(std::move(b)); } else if(cap == "GUINEAPIG") { auto b = std::make_unique(); nam(*b); b->respawn = get_xy(); b->pigvel = get_ld() / game_fps; b->respawn_spindir = get_int(); r.entities.emplace_back(std::move(b)); } else if(cap == "ICICLE") { auto b = std::make_unique(); nam(*b); b->respawn = get_xy(); r.entities.emplace_back(std::move(b)); } else if(cap == "VTRAP") { auto b = std::make_unique(); nam(*b); b->respawn = get_xy(); r.entities.emplace_back(std::move(b)); } else if(cap == "GRIDBUG") { auto b = std::make_unique(); nam(*b); b->respawn = get_xy(); r.entities.emplace_back(std::move(b)); } else if(cap == "KESTREL") { auto b = std::make_unique(); nam(*b); b->respawn = get_xy(); b->respawn_vel = get_xy() * xy(block_x, block_y) / game_fps; r.entities.emplace_back(std::move(b)); } else if(cap == "SNAKE") { auto b = std::make_unique(); nam(*b); b->respawn = get_xy(); b->respawn_dir = get_int(); r.entities.emplace_back(std::move(b)); } else if(cap == "NAGA") { auto b = std::make_unique(); nam(*b); b->respawn = get_xy(); b->respawn_dir = get_int(); r.entities.emplace_back(std::move(b)); } else if(cap == "FERRIS") { ld cx = get_ld(), cy = get_ld(), radius = get_ld(); int qty = get_int(); for(int i=0; i(); b->ctr = {cx, cy}; b->radius = radius; b->shift = i * TAU / qty; r.entities.emplace_back(std::move(b)); } } else if(cap == "ROPE") { ld cx = get_ld(), cy = get_ld(), radius = get_ld(); int qty = get_int(); ld period = get_ld(), shift = get_ld(), max_swing = get_ld(); for(int i=0; i(); b->ctr = {cx, cy}; b->radius = radius; b->period = period; b->max_swing = max_swing * 1._deg; b->shift = shift; b->dist = radius * (i+0.5) / qty; r.entities.emplace_back(std::move(b)); } } else if(cap == "LONGROPE") { create_long_rope(r, 0, {lerp(l_margin_at, r_margin_at, 2/3.), 0}); } else if(cap == "PENDULUM") { auto b = std::make_unique(); b->a = get_xy(); b->b = get_xy(); b->period = get_ld(); b->shift = get_ld(); r.entities.emplace_back(std::move(b)); } else if(cap == "ELLIPSE") { auto b = std::make_unique(); b->a = get_xy(); b->b = get_xy(); b->period = get_ld(); b->shift = get_ld(); b->ratio = get_ld(); r.entities.emplace_back(std::move(b)); } else if(cap == "SAW") { auto b = std::make_unique(); nam(*b); b->base = std::move(r.entities.back()); r.entities.back() = std::move(b); } else if(cap == "WOODSAW") { auto b = std::make_unique(); nam(*b); b->base = std::move(r.entities.back()); r.entities.back() = std::move(b); } else if(cap == "WEAKSAW") { auto b = std::make_unique(); nam(*b); b->base = std::move(r.entities.back()); r.entities.back() = std::move(b); } else if(cap == "FAKESAW") { auto b = std::make_unique(); nam(*b); b->base = std::move(r.entities.back()); r.entities.back() = std::move(b); } else if(cap == "HINT") { auto b = std::make_unique(); b->respawn = get_xy(); b->size = get_xy(); b->hint_text = scanline_noblank(f); r.entities.emplace_back(std::move(b)); } else if(cap == "AVOID") { auto b = std::make_unique(); b->respawn = get_xy(); b->size = get_xy(); b->hint_text = scanline_noblank(f); b->id = b->hint_text; for(auto& e: r.entities) if(e->as_enemy()) b->whom = e->as_enemy(); if(!b->whom) { println(hlog, "AVOID not after any enemy"); } r.entities.emplace_back(std::move(b)); } else if(cap == "VISION") { auto b = std::make_unique(); b->col = get_color(); s = scanline_noblank(f); b->sglyph = s[0]; b->name = s.substr(1); b->text = scanline_noblank(f); visions.emplace_back(std::move(b)); } else if(cap == "MAPSWITCH") { auto b = std::make_unique(); b->respawn = get_xy(); b->name = scanline_noblank(f); b->text = scanline_noblank(f); lmev = &*b; r.entities.emplace_back(std::move(b)); } else if(cap == "SWITCHEVENT") { if(!lmev) throw hr_exception("SWITCHEVENT without MAPSWITCH"); auto& ev = lmev->events; ev.emplace_back(); ev.back().box = get_box(); bool ok = false; for(int i=0; i entity_by_id; void load_map(string fname) { fhstream f(fname, "r"); load_room(f, currentmap->gamestart()); while(!feof(f.f)) { string s = scanline_noblank(f); if(s == "") continue; if(s.substr(0, 4) == "MOVE") { int i = s[5] - '0'; string roomname = s.substr(7); for(auto& [c,r]: rooms) if(r.roomname == roomname) load_room(f, c->move(i)); } else err("load_map", s); } for(auto& [c,r]: rooms) { r.orig_block_at = r.block_at; for(auto& e: r.entities) { e->hs(resetter); if(e->id != "") { while(entity_by_id.count(e->id)) { println(hlog, "error: double entity name: ", e->id); e->id += "'"; } entity_by_id[e->id] = &*e; } } } } void load_cheat(string fname) { fhstream f(fname, "r"); auto power_edited = &powers[0]; while(!feof(f.f)) { string s = scanline_noblank(f); auto pos = s.find(" "); if(pos != string::npos) { string cap = s.substr(0, pos); string param = s.substr(pos+1); if(cap == "START") { for(auto& [c,r]: rooms) if(r.roomname == param) current_room = &r; } else if(cap == "POS") { sscanf(param.c_str(), "%lf%lf", &m.where.x, &m.where.y); } else if(cap == "ITEM") { bool found = false; for(int i=0; iqty_owned += a; power_edited->qty_filled += b; println(hlog, "gain ", power_edited->name, " qty ", tie(a,b)); } else println(hlog, "unrecognized cheat: ", s); } else if(s == "IDENTIFY") { power_edited->flags |= IDENTIFIED; } else if(s == "ACTIVATE") { power_edited->flags |= ACTIVE; } else if(s == "") {} else println(hlog, "unrecognized cheat: ", s); } for(auto i: allstats) m.current.stats[i] = m.next.stats[i] = m.base_stats[i]; m.hp = m.max_hp(); } }