Print Page

Wednesday, August 19, 2015

Scry Overflow

In any sufficiently advanced magic using culture there should be commodity magic items or spells capable of accessing the magic equivalent of Stack Overflow.

"How did we ever do magic before Scry Overflow?" the apprentice wizard asks while cut and pasting a demon summoning that goes horribly wrong.


Wednesday, August 12, 2015

Rails callback sequence with observers and model inheritance

 Cleaning up a tangle of callbacks I need to know the order they fire in to guide my refactoring. I ran this experiment in a tiny rails app with Rails 4.0.9 and the 'rails-observers' gem to match a legacy app I am working on, upgrading soon.

I made a mini rails app with two models, one inheriting from the other:

class Thingy < ActiveRecord::Base
  after_create :thingy_created_callback
  def thingy_created_callback     
    puts "thingy_after_create_callback"
  end 
end

class SpecialThingy < Thingy   
  after_create :special_thingy_created_callback
  def special_thingy_created_callback 
    puts "special_thingy_after_create_callback"
  end 
end

Made an observer to observe each:

class ThingyObserver < ActiveRecord::Observer   
  observe Thingy   
  puts "ThingyObserver loaded"
  def after_create(thingy)
    puts "ThingyObserver.after_create"
  end
end


class SpecialThingyObserver < ActiveRecord::Observer   
  observe SpecialThingy   
  puts "SpecialThingyObserver loaded"   
  def after_create(thingy)
    puts "SpecialThingyObserver.after_create" 
  end 
end

When creating an instance of SpecialThingy at console, I see the results in this order:

thingy_after_create_callback
special_thingy_after_create_callback
SpecialThingyObserver.after_create
ThingyObserver.after_create

Sunday, August 2, 2015

What's next in DunGen

Got in some work this morning on the graph styling. Will let you set colors, shapes and borders on nodes, and line width and color of edges. The first editor that I am maybe half done on will be for the overall graph, then a second pass will add to the individual node and edge editors so you can call out an important room in red or with a star shape, or put an arrow on the downhill end of a slide or make water edges blue. Thinking about custom defaults being different for particular types of nodes and edges too, but may not go into that.

Another thing that will be coming pretty soon is to add theme tagging to the hooks and oddities tables so that there can be different lists of set dressing in a castle vs a temple vs a creepy horror setting. You'll only generate a litter of corpses if going totally random or you want stuff like that.

Lastly, I'm thinking to add tweak buttons to the node editing dialog (+Trap), (+Hook) (+Monster) (+Treasure) (+Oddity), so you can just add  a roll for one of them, not a total reroll.

Still mulling ideas about other mapping styles, more monster lists to add in - maybe a branch that does EPT lists instead of D&D, maybe swap in lists tailored to particular OSR rules instead of my personal mish mash. One possible map style would be to draw up a set of semi-geomorphs and record for them the points at which room numbers would go, so they could be tiled onto a canvas, room numbers overlaid, and then contents generated to match the room numbering. The result would be a traditional looking map with some flexibility and nicer looking than I could probably procedurally generate from code.

Tuesday, July 28, 2015

Reroll a Room in DunGen

This evening, before getting into the relationships, I did a minor feature. There is now a button in the node dialog box in DunGen that will reroll the contents of the room.

Rerolling labels will probably come along soon, as well as some node styling options, like color and shape, maybe some icon art.

Starting on relationships in DunGen - data table for a feature in progress

One place I want to go with DunGen is to have a listing of relationships between monster groups, probably initially seeded into the Notes field. The plan is to keep a side list of each monster type generated, its level and numbers. Using that info and the intelligence score and tags in the monster type objects, and possibly some die rolls, determine general attitude of the groups to be "enemy", "ally", or "neutral" and whether one side is dominant or the relationship is "mutual" or roughly in balance, and how complex the relationship can be, based on the INT scores. That yields a pool of appropriate relationship phrases that might fit, and choose one of those at random with one side as the subject, and maybe another going the opposite way.  If the subject side of the sentence is a singleton creature, use the single_text, otherwise the plural_text for the verb phrase. Possibly place some relationships relative to creatures in deeper or shallower levels that are "off-map".

I haven't got into coding the selection yet, but here is the initial version of the data table, which will certainly grow but is enough to start coding against the next time I work on this. It includes some tags that seemed appropriate at the time but may get trimmed for lack of usefulness in the code. Suggestions for additions are welcome.

  relationships:[
    { plural_text: "ally with", single_text: "allies with", min_subject_int: 6, min_target_int: 6, tags: ['mutual','ally','neutral']},
    { plural_text: "are in service to", single_text: "is in service to", min_subject_int: 6, min_target_int: 8, tags: ['subordinate','ally']},
    { plural_text: "are planning to ambush", single_text: "is planning to ambush", min_subject_int: 8, min_target_int: 6, tags: ['subordinate','dominant','mutual','enemy']},
    { plural_text: "are planning to raid", single_text: "is planning to raid", min_subject_int: 8, min_target_int: 6, tags: ['subordinate','dominant','mutual','enemy']},
    { plural_text: "avoid", single_text: "avoids", min_subject_int: 2, min_target_int: 0, tags: ['subordinate','enemy']},
    { plural_text: "appease", single_text: "appeases", min_subject_int: 8, min_target_int: 6, tags: ['subordinate','enemy']},
    { plural_text: "band together with", single_text: "bands together with", min_subject_int: 6, min_target_int: 6, tags: ['mutual','ally','neutral']},
    { plural_text: "command", single_text: "commands", min_subject_int: 6, min_target_int: 6, tags: ['dominant','ally']},
    { plural_text: "fear", single_text: "fears", min_subject_int: 3, min_target_int: 0, tags: ['mutual','subordinate', 'enemy']},
    { plural_text: "fight in the warband of", single_text: "fights in the warband of", min_subject_int: 6, min_target_int: 8, tags: ['subordinate','ally']},
    { plural_text: "prey upon", single_text: "preys upon", min_subject_int: 0, min_target_int: 0, tags: ['dominant', 'predatory']},
    { plural_text: "hunt", single_text: "hunts",  min_subject_int: 0, min_target_int: 0, tags: ['dominant', 'predatory']},
    { plural_text: "overran", single_text: "overran",  min_subject_int: 0, min_target_int: 0, tags: ['dominant', 'predatory','mass']},
    { plural_text: "control", single_text: "controls",  min_subject_int: 8, min_target_int: 0, tags: ['dominant', 'ally','enemy']},
    { plural_text: "enslave", single_text: "enslaves",  min_subject_int: 8, min_target_int: 5, tags: ['dominant', 'enemy']},
    { plural_text: "keep hostages from", single_text: "keeps hostages from",  min_subject_int: 8, min_target_int: 7, tags: ['dominant', 'neutral', 'ally', 'enemy']},
    { plural_text: "trade hostages with", single_text: "trades hostages with",  min_subject_int: 8, min_target_int: 8, tags: ['neutral', 'ally', 'enemy']},
    { plural_text: "demand the service of", single_text: "demands the service of",  min_subject_int: 8, min_target_int: 6, tags: ['dominant', 'ally','neutral']},
    { plural_text: "displaced", single_text: "displaced",  min_subject_int: 0, min_target_int: 0, tags: ['dominant', 'predatory','mass']},
    { plural_text: "fend off", single_text: "fends off", min_subject_int: 8, min_target_int: 6, tags: ['subordinate','mutual','enemy']},
    { plural_text: "fight", single_text: "fight", min_subject_int: 8, min_target_int: 6, tags: ['subordinate','mutual','enemy']},
    { plural_text: "fortify against", single_text: "fortifies against", min_subject_int: 8, min_target_int: 0, tags: ['subordinate','mutual','enemy']},
    { plural_text: "give succor to", single_text: "gives succor to", min_subject_int: 6, min_target_int: 6, tags: ['dominant','mutual','ally']},
    { plural_text: "hate", single_text: "hates", min_subject_int: 6, min_target_int: 0, tags: ['mutual','subordinate', 'enemy']},
    { plural_text: "hide from", single_text: "hides from", min_subject_int: 2, min_target_int: 0, tags: ['subordinate','enemy']},
    { plural_text: "intimidate", single_text: "intimidates", min_subject_int: 3, min_target_int: 0, tags: ['dominant','neutral', 'enemy']},
    { plural_text: "loathe", single_text: "loathes", min_subject_int: 6, min_target_int: 6, tags: ['mutual','dominant', 'enemy']},
    { plural_text: "plot against", single_text: "plots against", min_subject_int: 8, min_target_int: 6, tags: ['subordinate','mutual','enemy']},
    { plural_text: "make signs against", single_text: "makes signs against", min_subject_int: 8, min_target_int: 0, tags: ['subordinate','mutual','enemy']},
    { plural_text: "run from", single_text: "runs from", min_subject_int: 2, min_target_int: 0, tags: ['subordinate','enemy']},
    { plural_text: "retreat from", single_text: "retreats from", min_subject_int: 2, min_target_int: 0, tags: ['subordinate','enemy']},
    { plural_text: "serve", single_text: "serves", min_subject_int: 6, min_target_int: 8, tags: ['subordinate','ally']},
    { plural_text: "sacrifice to", single_text: "sacrifices to", min_subject_int: 6, min_target_int: 0, tags: ['subordinate','ally','appeasing']},
    { plural_text: "trade with", single_text: "trades with", min_subject_int: 6, min_target_int: 6, tags: ['mutual','ally','neutral']},
    { plural_text: "tax", single_text: "taxes", min_subject_int: 8, min_target_int: 7, tags: ['dominant','ally','neutral']},
    { plural_text: "take succor with", single_text: "take succor with", min_subject_int: 6, min_target_int: 6, tags: ['subordinate','mutual','ally']},
    { plural_text: "tred carefully around", single_text: "treds carefully around", min_subject_int: 6, min_target_int: 0, tags: ['mutual', 'subordinate', 'neutral', 'enemy', 'appeasing']},
    { plural_text: "will alert", single_text: "will alert", min_subject_int: 6, min_target_int: 6, tags: ['mutual','subordinate','ally']},
    { plural_text: "venerate", single_text: "venerates", min_subject_int: 7, min_target_int: 9, tags: ['subordinate', 'ally', 'neutral']},
    { plural_text: "worship", single_text: "worships", min_subject_int: 6, min_target_int: 6, tags: ['subordinate', 'ally']},
    { plural_text: "were displaced by", single_text: "was displaced by", min_subject_int: 3, min_target_int: 0, tags: ['subordinate','enemy']}
  ],

Tuesday, July 21, 2015

DunGen users are coming up with some cool stuff

+Thaumiel Nerub has drawn some amazing maps from DunGen results. Check them out on his Crypt of Rabies blog.
Cult Caves

Map to Necropolis

Kobolds Dungeon



+Sherief Gaber posted ideas on G+ for what tunnel wolves are that goes way beyond my original "um,  like wargs, but in dungeons" conception.

DunGen: update, crowdsourcing, plans

Progress
Did a content update in DunGen last night. Among other things it expanded the list of NPC classes, while stacking additional weighting on the base Fighter, Mage, Cleric & Thief so they will still be the most frequent and Fighter the most frequent among them. The broader list may include classes not present in a campaign, so replace as needed. Small code change to split the attitude from 50 - 50 with and without for monster groups to 1/3 blank, 1/3 group attitude, 1/3 one of the group has the attitude.

Added a few entries to each of several lists: monsters, attitudes, magic items, magic weapon and armor powers, rooms, paths, oddities.

Tonight I added a search and replace Re-skinner so you can generate a dungeon, see that it filled it with, say, snakes and say, "No, I want Cosmic Rutabagas as the common monster for this level" and make that change throughout. Its also handy if you want to replace or remove the M: or Ts: labels, or use the GP abbreviation in place of the word gold, etc.

It's pushed to Github and deployed.


Crowdsourcing - an experiment
I have some factions that generate NPC lists: Adventurers, Cultists, Overlord

Here is the progression list for the Overlord faction:

1 Underling
2 Minion
3 Evil Henchman
4 Villainous Lieutenant
5 Villain
6 Evil Overlord

Well, actually in the app, they are all lowercase...

What would be another good faction to add? Faction name plus step names. Tags from the theme box if you want...



Plans
Roughly short to long term...

Monster relationships
A feature I want to do is to keep a side list internally of all generated monsters, and have the generator dice up some entries for monster relationships to add to the notes field, things like "The goblins avoid the ogres", "The cultists worship the dragons", "The werewolf preys upon the hobgoblins",  "The giants are preparing to raid the surrounding countryside" and "The wights serve a specter in a deeper level of the dungeon", basically combining subject, relationship verb phrase, and object with a bit of intelligence about probable power hierarchy so the combinations mostly make sense.

Name Generator
Name generation is another thing on the list, probably a Markov chain generator that strings together syllables drawn from several lists, possibly with tags added to monster entries for which phoneme list they'd use. Is this a good thing, a bad thing, or something that should have an on/off toggle?

The wilderness still needs work but I'm not feeling strongly about what to tackle next there.

Politics Generator
Tony Bath style politics generator - I've done this using dice in a past campaign, and Vis.js graphing should work well to show relationships between groups and people. Major figures and groups get statted out politically, on scales like Flexibility, Loyalty,  Resources,  Activity,  Aggressiveness, and Honesty, and relationship edges between them can be scored for intensity and type of emotion that flesh them out in ways that help a GM decide whether they take actions and what actions they would take. Would need some good generation of names of people, offices, and groups. Probably also assign character classes and levels to some political actors, but that is secondary in this kind of modelling. This might feed into a time-stepping simulation mode where at each interval NPCs are rolled for to see whether they take an action and what action they take and if it is off-camera, what the effect is, shifting relationships, offices and resource/power levels. The GM would have the power to fiddle the results, especially to include PC action effects, but it would generate a sort of campaign setting chronology of background events.

Mapless Content lists for phones
Mobile content list only - build an option to hide the graph when on mobile, so it can be used handily as a contents generator on a phone without the animated graph getting in the way. Possibly just showing the list above the graph would do it so you don't have to scroll down to the graph. The iPhone button to go to easy reading mode kind of covers this. Will have to see it on an Android phone to see if a similar function is already built in there. If so, no real need...

Content generator for map images
A different form of mapping - this one is still a fuzzy vision. I'd like to make it easy to connect drawn maps to generated listings.  Probably this means a UI to load a map image, drag room numbers over it,  and then generate content for each room number.  Save the relative coordinates of the room numbers to the map image for redisplay. With a tiling offset and rotational offset function it could consume geomorphs like those at Dave's Mapper. With a record of where the connector points are, it could consume my pseudo-geomorphs that try to add interest in arrangement by not exactly aligning entrances. It might require hosting a server to store the coordinate lists for images.

Monday, July 20, 2015

More Epic Radio

This station has some gaming background music potential.
http://more-epic.playtheradio.com

Came across it in iTunes Internet Radio under Classical.

The iTunes blurb points to their Facebook page:
https://www.facebook.com/MoreEpicRadio

and to a YouTube address that I'd have to parse out from the run-together text, but EpicJenny is in there.

Saturday, July 18, 2015

DunGen in the Afternoon

Just a couple small changes this time - it's surprising how long a small change can take to code.

Finally fixed the NPC levels bug, so you won't see 4th level novice adventurers any more.

It's old school, so there really ought to be a wandering monsters list. Now a dungeon starts with one in the notes field, its length scales with the number of nodes.

....


One last feature for the day - adding templates to monsters. If undead, demon, or devil is in the selected tags, some other monsters will pick up a templating adjective and become "undead gnolls" or "demonic lizards". The "undead" triggers on a roll of 1 or 2, "demonic" and "infernal" on a 1 each, but are mutually exclusive and exclusive with "dragon", so you can have an "undead demonic giant" but not a "demonic infernal orc" or "demonic adult dragon".

DunGen now has themes for places and paths!

So now you can set it up for a Goblin Cave with Water Features (for example) with minimal effort. I'd tweak these results a bit after generation before running a game, but the raw results are getting pretty good and focused.




LocationDescription 
1: DenHook: symbolic item of clothing
2: Vast cavernTs: 1 x 300 GP gem, 1 x 200 GP gem
3: Bridge across underground riverA mummified creature
4: Underground riverbankA broken helm
M: 5 irritated tunnel wolves
Ts: 14 x 50 GP gem, 640 gold, 42 platinum
Mg: Scroll with one holy spell
5: Boneyard caveA wind rises as PCs enter, blowing the furnishings their way
6: Bridge across underground riverM: 1 vituperative goblin
M: 2 wary giant ticks
7: IntersectionM: 1 bitter hobgoblin
Ts: 1 x 2000 GP gem, 1 x 600 GP gem
Mg: Staff of Wizardry
Mg: Potion of Flight
8: IntersectionM: 1 tunnel wolf
Ts: 1 x 300 GP gem, 9 gold
Hook: rare trade goods
9: Cave inM: 2 tunnel wolves
Ts: Ring worth 329 GP, 109 silver
Mg: Staff of Three Spells
10: FountainM: 1 satiated goblin
Ts: Vessel worth 720 GP
Mg: Dagger +1, 
11: DenHook: mosaic floor
12: IntersectionM: 2 goblins
13: Underground river fordA sundered shield
M: 3 starving tunnel wolves
Ts: 1225 silver
Mg: Ring of Fire Resistance
14: IntersectionM: 3 goblins
M: 2 hobgoblins
Ts: 2196 silver, 878 silver
Mg: Book
15: Fortified cavernM: 3 orcs
16: LandingM: 8 dissolute goblins
17: Boneyard caveA burning brazier
18: Branching caveTp: open pit, triggered by a bound spirit
Ts: 100 silver, 60 silver
19: AquaductEmpty
20: ChasmTp: portcullis trap
Ts: 1 x 600 GP gem, 1 x 100 GP gem
Hook: map showing a secret path
21: MoatTp: slippery oil trap, triggered by weight
M: 1 mushroom man
Ts: 700 silver, Tiara worth 63 GP
Mg: Scroll of spells
Hook: map to deeper level
scree slope in cavern7: Intersection to 15: Fortified cavern
well12: Intersection to 15: Fortified cavern
pit14: Intersection to 15: Fortified cavern
channel19: Aquaduct to 12: Intersection
scree slope in cavern20: Chasm to 15: Fortified cavern
partial cave-in5: Boneyard cave to 14: Intersection
subterranean river17: Boneyard cave to 15: Fortified cavern
winch over cliff ledge10: Fountain to 14: Intersection
streambed2: Vast cavern to 17: Boneyard cave
partial cave-in6: Bridge across underground river to 5: Boneyard cave
ledge21: Moat to 20: Chasm
vent8: Intersection to 14: Intersection
shaft13: Underground river ford to 15: Fortified cavern
underground stream18: Branching cave to 10: Fountain
underground stream4: Underground riverbank to 19: Aquaduct
flooded passage1: Den to 20: Chasm
chasm ledge path9: Cave in to 19: Aquaduct
well16: Landing to 8: Intersection
narrow tunnel3: Bridge across underground river to 7: Intersection
subterranean river11: Den to 9: Cave in