package game // new_level.c — dig and draw a new level. const ( treasRoomChance = 20 // one chance in TREAS_ROOM for a treasure room maxTreas = 10 // maximum number of treasures in a treasure room minTreas = 2 // minimum number of treasures in a treasure room maxTries = 10 // max number of tries to put down a monster ) // NewLevel digs and draws a new level (new_level.c new_level). func (g *RogueGame) NewLevel() { p := &g.Player p.Flags.Clear(Held) // unhold when you go down just in case if g.Depth > g.MaxDepth { g.MaxDepth = g.Depth } // Clean things off from last level for i := range g.Level.Places { g.Level.Places[i] = Place{Ch: ' ', Flags: FReal} } g.clear() // Free up the monsters on the last level; the objects and their packs // go with them (the garbage collector is our free_list). g.Level.Monsters = nil g.Level.Objects = nil g.doRooms() // Draw rooms g.doPassages() // Draw passages p.NoFood++ g.putThings() // Place objects (if any) // Place the traps if g.rnd(10) < g.Depth { g.Level.TrapCount = g.rnd(g.Depth/4) + 1 if g.Level.TrapCount > MaxTraps { g.Level.TrapCount = MaxTraps } for i := g.Level.TrapCount; i > 0; i-- { // not only wouldn't it be NICE to have traps in mazes (not // that we care about being nice), since the trap number is // stored where the passage number is, we can't actually do it. var stairs Coord for { stairs, _ = g.findFloor(nil, 0, false) if g.Level.Char(stairs.Y, stairs.X) == Floor { break } } sp := g.Level.FlagsAt(stairs.Y, stairs.X) sp.Clear(FReal) *sp |= PlaceFlags(g.rnd(NumTrapTypes)) } } // Place the staircase down. stairs, _ := g.findFloor(nil, 0, false) g.Level.Stairs = stairs g.Level.SetChar(stairs.Y, stairs.X, Stairs) g.SeenStairs = false for _, tp := range g.Level.Monsters { tp.Room = g.roomin(tp.Pos) } hero, _ := g.findFloor(nil, 0, true) p.Pos = hero g.enterRoom(hero) g.mvaddch(hero.Y, hero.X, PlayerCh) if p.On(SenseMonsters) { g.turnSee(false) } if p.On(Hallucinating) { g.visuals(0) } } // rndRoom picks a room that is really there (new_level.c rnd_room). func (g *RogueGame) rndRoom() int { for { rm := g.rnd(MaxRooms) if !g.Level.Rooms[rm].Flags.Has(Gone) { return rm } } } // putThings puts potions and scrolls on this level (new_level.c // put_things). func (g *RogueGame) putThings() { // Once you have found the amulet, the only way to get new stuff is to // go down into the dungeon. if g.HasAmulet && g.Depth < g.MaxDepth { return } // check for treasure rooms, and if so, put it in. if g.rnd(treasRoomChance) == 0 { g.treasRoom() } // Do MAXOBJ attempts to put things on a level for i := 0; i < MaxObj; i++ { if g.rnd(100) < 36 { // Pick a new object and link it in the list obj := g.newThing() attachObj(&g.Level.Objects, obj) // Put it somewhere obj.Pos, _ = g.findFloor(nil, 0, false) g.Level.SetChar(obj.Pos.Y, obj.Pos.X, obj.Type) } } // If he is really deep in the dungeon and he hasn't found the amulet // yet, put it somewhere on the ground if g.Depth >= AmuletLevel && !g.HasAmulet { obj := newObject() attachObj(&g.Level.Objects, obj) obj.Damage = "0x0" obj.HurlDmg = "0x0" obj.Arm = 11 obj.Type = Amulet // Put it somewhere obj.Pos, _ = g.findFloor(nil, 0, false) g.Level.SetChar(obj.Pos.Y, obj.Pos.X, Amulet) } } // treasRoom adds a treasure room (new_level.c treas_room). func (g *RogueGame) treasRoom() { rp := &g.Level.Rooms[g.rndRoom()] spots := (rp.Max.Y-2)*(rp.Max.X-2) - minTreas if spots > maxTreas-minTreas { spots = maxTreas - minTreas } numMonst := g.rnd(spots) + minTreas for nm := numMonst; nm > 0; nm-- { mp, _ := g.findFloorIn(rp, 2*maxTries, false) tp := g.newThing() tp.Pos = mp attachObj(&g.Level.Objects, tp) g.Level.SetChar(mp.Y, mp.X, tp.Type) } // fill up room with monsters from the next level down nm := g.rnd(spots) + minTreas if nm < numMonst+2 { nm = numMonst + 2 } spots = (rp.Max.Y - 2) * (rp.Max.X - 2) if nm > spots { nm = spots } g.Depth++ for ; nm > 0; nm-- { if mp, ok := g.findFloorIn(rp, maxTries, true); ok { tp := &Monster{} g.newMonster(tp, g.randMonster(false), mp) tp.Flags.Set(Mean) // no sloughers in THIS room g.givePack(tp) } } g.Depth-- }