public static void AddForegroundStuff(Image img, MapTile t) { int x1 = (t.loc.X * FrameData.multX) + FrameData.edgeX; int y1 = (t.loc.Y * FrameData.multY) + FrameData.edgeY; if (t.clear) // set flow as background only { int showFlow = Refs.p.viewFlow; // display nectar drops using deepest level int deepestLevel = 0; int deepestAmt = 0; int sumAmt = 0; for (int nLoop = 0; nLoop < t.nectarLevel.Length; nLoop++) { sumAmt += t.nectarLevel[nLoop]; if (t.nectarLevel[nLoop] > deepestAmt) { deepestAmt = t.nectarLevel[nLoop]; deepestLevel = nLoop; } } if (deepestAmt > 0) { using (var gNectar = Graphics.FromImage(img)) { Color nectarCol; if (deepestLevel == 0) { nectarCol = Refs.p.myColor; } else { nectarCol = Harem.GetId(deepestLevel).myColor; } // Color mixedCol = GetColorMix(t); if (sumAmt > 8) { sumAmt = 8; } string useNectarChar = nectarChars[sumAmt]; //if (sumAmt > 1) { useNectarChar = nectarCharLarge; } gNectar.DrawImage( SpriteManager.GetSprite(useNectarChar, Refs.m.stdSize, nectarCol, t.backCol), x1, y1); } } // todo bigger blob for more nectar maybe? } else // it's not marked as clear, so draw the wall { Bitmap singleTileImage = SpriteManager.GetSprite(t.gly, Refs.m.stdSize, Color.White, t.backCol); using (var gChar = Graphics.FromImage(img)) { gChar.DrawImage(singleTileImage, x1, y1); } } }
public void RunFlow(Boolean maskWalls) { FlowTileSet heads = AllFlowSquares(); if (maskWalls) { foreach (FlowTile fs in heads) { // mask out walls etc, we don't flow over those MapTile thisTile = Refs.m.TileByLoc(fs.loc); if (!thisTile.clear) { fs.mask = true; } } } // I call them heads because they 'snake' outwards from the initial point(s) // but you get splits into several heads at junctions so it's a bad metaphor... // loop till we can't find anything more to do, // (or we decide we've messed up) bool changes = true; int failsafe = 0; int headsProcessed = 0; while (changes == true && failsafe < 256) { changes = false; failsafe++; FlowTileSet newHeads = new FlowTileSet(); // for each active head tile... foreach (FlowTile fs in heads) { // ...find the tiles next to it... FlowTileSet newTiles = new FlowTileSet() { fs.OneNorth(), fs.OneEast(), fs.OneSouth(), fs.OneWest() }; // ... (ignoring any nulls) ... newTiles.RemoveWhere(item => item == null); // ... and for each one found ... foreach (FlowTile newFlowSq in newTiles) { // ... if we can improve the flow rating of it ... double delta = newFlowSq.flow - fs.flow; MapTile targetTile = Refs.m.TileByLoc(fs.loc); if (targetTile.clear && delta > 1.0001) { // ... do so, and then make it a new head ... newFlowSq.flow = fs.flow + 1; newHeads.Add(newFlowSq); changes = true; } } headsProcessed++; } // ... and next time around, we keep going using those new heads heads = newHeads; if (failsafe == 255) { Console.WriteLine("Hit flow failsafe!"); } } }
// returns number of round passed, 0 for free actions, 1 for normal moves. public int HandlePlayerInput(PreviewKeyDownEventArgs e) { // for convenience MapTile here = Refs.m.TileByLoc(loc); // debugging nectar report Console.Write("Nectar here is "); foreach (int i in here.nectarLevel) { Console.Write(i + ", "); } Console.Write("."); if (e.KeyCode == Keys.F && heldCubiId != 0) { return(BoinkHeld()); } if (e.KeyCode == Keys.C && heldCubiId != 0) { return(CaneHeld()); } Loc lastPos = loc; // visualise flows. hotkeys are just pretend this is where we really do it if (e.KeyCode == Keys.D0) { viewFlow = 0; return(0); } if (e.KeyCode == Keys.D1) { viewFlow = 1; return(0); } if (e.KeyCode == Keys.D2) { viewFlow = 2; return(0); } if (e.KeyCode == Keys.D3) { viewFlow = 3; return(0); } if (e.KeyCode == Keys.D4) { viewFlow = 4; return(0); } int timepass = 1; if (e.KeyCode == Keys.Space) { return(1); // allow waiting at any time } if (placemode || e.Shift) { timepass = 0; // place / pickup is a free action for now switch (e.KeyCode) { case Keys.Down: case Keys.S: ActionSouth(); FinishMode(); break; case Keys.Right: case Keys.D: ActionEast(); FinishMode(); break; case Keys.Up: case Keys.W: ActionNorth(); FinishMode(); break; case Keys.Left: case Keys.A: ActionWest(); FinishMode(); break; case Keys.Escape: CancelModes(); break; default: break; } } else if (throwmode || e.Control) { timepass = 0; // throw is a free action for now switch (e.KeyCode) { case Keys.Down: case Keys.S: ThrowSouth(); FinishMode(); break; case Keys.Right: case Keys.D: ThrowEast(); FinishMode(); break; case Keys.Up: case Keys.W: ThrowNorth(); FinishMode(); break; case Keys.Left: case Keys.A: ThrowWest(); FinishMode(); break; case Keys.Escape: CancelModes(); break; default: break; } } else { timepass = 1; switch (e.KeyCode) { // moves cost 1 turn case Keys.Down: case Keys.S: RunSouth(); break; case Keys.Right: case Keys.D: RunEast(); break; case Keys.Up: case Keys.W: RunNorth(); break; case Keys.Left: case Keys.A: RunWest(); break; // mode changes are free actions case Keys.T: SetThrowMode(); timepass = 0; break; case Keys.P: SetPlaceMode(); timepass = 0; break; case Keys.Escape: CancelModes(); timepass = 0; break; default: timepass = 0; break; } } // save our current location for next turn lastMove = Loc.SubPts(loc, lastPos); // starting at 1 skips player nectar processing for now for (int nLoop = 1; nLoop < here.nectarLevel.Length; nLoop++) { if (here.nectarLevel[nLoop] > 0) { horny += here.nectarLevel[nLoop]; here.nectarLevel[nLoop] = 0; } } if (horny > 15) // having fun { Refs.mf.Announce("Awwww yeah! *splurt*", myAlign, myColor); timepass += 5; MainMap.SplurtNectar(here, myIndex: 0); horny = 0; } if (!victory) { // we're duplicating this location scanning code a lot... // but this will be useful if we ever move jails so I'll leave it // get list of capture tiles MapTileSet jails = new MapTileSet(); foreach (Loc l in Refs.m.pents) { jails.Add(Refs.m.TileByLoc(l)); } // get list of cubi locations MapTileSet breaker = new MapTileSet(); foreach (Cubi c in Refs.h.roster) { breaker.Add(Refs.m.TileByLoc(c.loc)); } // IntersectWith to get occupied jails jails.IntersectWith(breaker); // if jails filled = total jails, we won! if (jails.Count == Refs.m.pents.Count) { victory = true; Refs.mf.Announce("Gotcha all! And in only " + turnCounter + " turns!", myAlign, myColor); } } return(timepass); }
public MainMap Create(int xlen, int ylen) { var sw = new Stopwatch(); sw.Start(); MainMap NewMap = new MainMap(xlen, ylen); Refs.m = NewMap; // needed for utils int xmax = NewMap.GetXLen() - 2; int ymax = NewMap.GetYLen() - 2; // seed the corners NewMap.TileByLoc(new Loc(1, 1)).clear = true; NewMap.TileByLoc(new Loc(1, ymax)).clear = true; NewMap.TileByLoc(new Loc(xmax, 1)).clear = true; NewMap.TileByLoc(new Loc(xmax, ymax)).clear = true; // set up central area var homeStartClear = new Loc(29, 8); var homeEndClear = new Loc(38, 15); NewMap.MakeClearArea(homeStartClear, homeEndClear); // mark home walls not to be tunneled away var homeStartWall = new Loc(homeStartClear.X - 1, homeStartClear.Y - 1); var homeEndWall = new Loc(homeEndClear.X + 1, homeEndClear.Y + 1); NewMap.MarkNoTunnel(homeStartWall, homeEndWall); // todo hardcoded doorway var doorStartClear = new Loc(31, 7); var doorEndClear = new Loc(36, 9); NewMap.MakeClearArea(doorStartClear, doorEndClear); // todo hardcoded initial departure area var spawnStartClear = new Loc(29, 6); var spawnEndClear = new Loc(38, 8); NewMap.MakeClearArea(spawnStartClear, spawnEndClear); // todo new hardcoded holding pens int pentBaseX = 32; int pentBaseY = 10; NewMap.pents = new List <Loc> { new Loc(pentBaseX + 0, pentBaseY), new Loc(pentBaseX + 3, pentBaseY), new Loc(pentBaseX + 0, pentBaseY + 3), new Loc(pentBaseX + 3, pentBaseY + 3) }; //NewMap.TileByLoc(new Loc(35, homeStartClear.Y)).clear = true; //NewMap.TileByLoc(new Loc(34, homeStartClear.Y)).clear = true; //NewMap.TileByLoc(new Loc(33, homeStartClear.Y)).clear = true; //NewMap.TileByLoc(new Loc(32, homeStartClear.Y)).clear = true; // cache startup NewMap.InitClearTilesCache(); // maze generation int rounds = 0; var clears = NewMap.GetClearTilesCache(); while (clears.Count > 0) { // pick a random clear tile clears = NewMap.GetClearTilesCache(); var clear = clears.ElementAt(rng.Next(clears.Count)); // which ways can we dig from it? var nextTo = NewMap.GetNextTo(clear); var isClosed5sides = NewMap.GetClosed5Sides(nextTo); var andWalls = MapTile.FilterOutClear(isClosed5sides); var andTunnelable = MapTile.Tunnelable(andWalls); var candidates = andTunnelable; // if there are digging options... if (candidates.Count > 0) { // ... dig in one of them randomly MapTile picked = candidates.ElementAt(rng.Next(candidates.Count)); picked.clear = true; NewMap.AddToClearTileCache(picked); } else { // ... if not, this tile will never be mined from, // so remove it from the clear tiles cache NewMap.DelFromClearTileCache(clear); } //Refs.mf.UpdateMap(); // for debugging visualization rounds++; } NewMap.DoneWithClearTileCache(); NewMap.ConsoleDump(); NewMap.HealWalls(); NewMap.ConsoleDump(); // typ old time 230ms, new time 110ms Console.WriteLine("Finished mapgen in " + sw.ElapsedMilliseconds + "ms, at " + rounds + " rounds"); return(NewMap); }
public void DelFromClearTileCache(MapTile t) => clearCache.Remove(t);
public void AddToClearTileCache(MapTile t) => clearCache.Add(t);
/// player-throwing-a-cubi trajectory logic private void ThrowCubiMain(Loc vector) { // todo lots of duplication here Player p = Refs.p; Cubi cubiThrown = Harem.GetId(p.heldCubiId); Refs.mf.Announce("You throw " + cubiThrown.name + " through the air!", myAlign, myColor); Refs.mf.Announce("*flap* *flap* *flap*", cubiThrown.myAlign, cubiThrown.myColor); cubiThrown.beingCarried = false; p.heldCubiId = 0; // determine release point of throw // todo check for hit on very first tile Loc startloc = Loc.AddPts(loc, vector); MapTile activeTile = Refs.m.TileByLoc(startloc); // if very first tile is a holding pent, they can fly right over Loc zero = new Loc(0, 0); if (CheckClearForThrown(zero, activeTile) == "pent") { // oops you threw from too close Refs.mf.Announce("*desperate flapping* That was close, just made it over!", cubiThrown.myAlign, cubiThrown.myColor); } // if the next tile is another cubi, throw short // todo consolidate long and short throws // todo need to prevent throwing a cubi while ones already directly next to you string moveClear = CheckClearForThrown(vector, activeTile); if (moveClear == "cubi") { MapTile victimTile = Refs.m.TileByLoc(Loc.AddPts(activeTile.loc, vector)); Cubi victim = Refs.m.CubiAt(victimTile.loc); Refs.mf.Announce("Owf!", cubiThrown.myAlign, cubiThrown.myColor); victim.Spanked += 5; Refs.mf.Announce("Oof too!", cubiThrown.myAlign, cubiThrown.myColor); cubiThrown.Spanked += 5; // and a good time was had by both } else if (moveClear == "pent") { // we just overflew a pent so consider her flight path clear for now moveClear = "clear"; } // todo refresh player square so she's not superimposed on player square while (moveClear == "clear") { // blip activeTile with cubi symbol cubiThrown.loc = activeTile.loc; AnimateMobile(activeTile, cubiThrown); // is the next tile clear? moveClear = CheckClearForThrown(vector, activeTile); // nope, it has a cubi in. if (moveClear == "cubi") { MapTile victimTile = Refs.m.TileByLoc(Loc.AddPts(activeTile.loc, vector)); Cubi victim = Refs.m.CubiAt(victimTile.loc); MapTileSet escapes = new MapTileSet(); if (IsVertical(vector)) { escapes = victimTile.GetPossibleMoves(Dir.DodgeVertical); } else { escapes = victimTile.GetPossibleMoves(Dir.DodgeHorizontal); } if (escapes.Count > 0) { victim.loc = MainMap.RandomFromList(escapes).loc; Refs.mf.Announce("Nyahhh missed me!", victim.myAlign, victim.myColor); moveClear = "clear"; } else { victim.Spanked += 5; Refs.mf.Announce("Owwwww!", victim.myAlign, victim.myColor); } // if it had a cubi, it could have moved revealing a holding pent // so let's scan again moveClear = CheckClearForThrown(vector, activeTile); } if (moveClear == "pent") { // move one more tile activeTile = Refs.m.TileByLoc(Loc.AddPts(vector, activeTile.loc)); Refs.mf.Announce("Eep! I'm caught!", cubiThrown.myAlign, cubiThrown.myColor); } // just a wall. stop here. if (moveClear == "wall") { Refs.mf.Announce("You didn't hit anything interesting.", myAlign, myColor); } // it's clear, so move activeTile up and iterate if (moveClear == "clear") { activeTile = Refs.m.TileByLoc(Loc.AddPts(vector, activeTile.loc)); } } // deposit cubi here cubiThrown.loc = activeTile.loc; Refs.mf.UpdateMap(); }
/// player-throwing-pillow trajectory logic private void ThrowPillowMain(Loc vector) { Refs.mf.Announce("You throw a pillow!", myAlign, myColor); // can't throw without pillow! if (heldPillows <= 0) { return; } else { heldPillows--; UpdateInventory(); } // determine release point of throw // todo check for hit on very first tile -- where to put pillow? Loc startloc = Loc.AddPts(this.loc, vector); MapTile activeTile = Refs.m.TileByLoc(startloc); string pillowGlyph = "O"; // if the next tile now is a lover, extra spank stun! // todo consolidate long and short throws string moveClear = CheckClearForThrown(vector, activeTile); if (moveClear == "cubi") { MapTile victimTile = Refs.m.TileByLoc(Loc.AddPts(activeTile.loc, vector)); Cubi victim = Refs.m.CubiAt(victimTile.loc); Refs.mf.Announce("POINT BLANK PILLOW SPANK!", myAlign, myColor); victim.Spanked += 5; Refs.mf.Announce("oww! *moan*", victim.myAlign, victim.myColor); } while (moveClear == "clear") { // blip activeTile with pillow symbol AnimatePillow(activeTile, pillowGlyph); // is the next tile clear? moveClear = CheckClearForThrown(vector, activeTile); // nope, it has a cubi in. if (moveClear == "cubi") { MapTile victimTile = Refs.m.TileByLoc(Loc.AddPts(activeTile.loc, vector)); Cubi victim = Refs.m.CubiAt(victimTile.loc); MapTileSet escapes = new MapTileSet(); if (IsVertical(vector)) { escapes = victimTile.GetPossibleMoves(Dir.DodgeVertical); } else { escapes = victimTile.GetPossibleMoves(Dir.DodgeHorizontal); } if (escapes.Count > 0) { victim.loc = MainMap.RandomFromList(escapes).loc; Refs.mf.Announce("Nyahhh missed me!", victim.myAlign, victim.myColor); moveClear = "clear"; } else { victim.Spanked += 5; Refs.mf.Announce("Owwwww!", victim.myAlign, victim.myColor); } } // just a wall. stop here. if (moveClear == "wall") { Refs.mf.Announce("You didn't hit anything interesting.", myAlign, myColor); } // it's clear, so move activeTile up and iterate if (moveClear == "clear") { activeTile = Refs.m.TileByLoc(Loc.AddPts(vector, activeTile.loc)); } } // leave pillow on ground to form new obstruction activeTile.clear = false; Refs.m.HealWalls(); Refs.mf.UpdateMap(); }