A better programming language for dredmor modding

Discussion in 'Modding' started by Kaidelong, May 9, 2013.

  1. Kaidelong

    Kaidelong Member

    Seeing what a mess the dredmor modding language is, it seems like this would be quite a decent project to pursue. In particular generating buffs and triggeronbuffs and giving facilities like weighted choice approximated by repeated entries in triggerfromlist, and so forth (a huge pain on my current project, but unlike Viking Medicine and Glod, it and Rogue Wizard have made some real progress and may still see the light of day). I may start a git project. If I'm going to be doing this myself, I'd use the following technologies:

    http://www.haskell.org/platform/ A cross platform, high level language and platform that sits at about the same level of abstraction vs hardware as C++, although it is managed and type safe. Provided all the libraries used in the project build easily on all platforms a "compiler" such as this should not be a problem portability wise since we're just turning one piece of text into another much uglier one. It is easy to learn (but not the libraries!), simple to understand (until you get to all the extensions, much like the situation with C++), and from the ML tradition which was built with this sort of thing in mind. It's also has a very good optimizing compiler, but given the application domain this hardly matters and if someone wants to switch to something else I do not care about performance in the least. My concerns are simplicity (Haskell is about as complex as I can really handle), deployability (I'd love to have just one statically linked .exe), portability, conciseness, and library support. There may be other good options here like Clojure, C#, F#, or OCaml, and I am open to them if someone wants to collaborate on a different platform.

    http://hackage.haskell.org/package/xmlhtml This is about the simplest way I could find to generate XML. Essentially a document's contents is typed as [Node] (a list of Node elements), and a node can be an element, which itself has a field that is a [Node]. Send the resulting document to a function called render and the output to Blaze.ByteString.Builder.toByteStringWithIO, make a file, open it in append mode, flush the buffer into it until all the XML is rendered, done.

    As for the parsing libraries, there are so many of them but I'm just thinking of sticking to Parsec, here: http://book.realworldhaskell.org/read/using-parsec.html . It is pretty simple and I've used it before.

    This is all already set unless someone wants to collaborate or just do the thing instead or whatever. If I am just going to start the project with all that, what I really need to determine now is what the dredmor language will actually *look* like. I want modders to give me lots of examples of stuff they hate writing in mods, and how they would prefer to write them.
     
    Null and Essence like this.
  2. Alistaire

    Alistaire Member

    Anything that has any kind of conditions should be easier, actually. Not 5 buffs that check for other buffs; adding local variables would be amazing.
     
  3. Xavion

    Xavion Member

    Unfortunately I've only dabbled a bit with modding but this certainly sounds interesting and something I could help with, I've got no experience with Haskell so I'd have to learn it first but I'd be willing to try, as for languages I do know that meet your requirements there is pro's and con's to them all, a web app built off something like javascript would have poor offline and file system support but have natural xml handling abilities and be compatible with everything with barely any extra effort if any, but something actually run on the computer would be pretty much the opposite of those. I'd be willing to try and help but if I don't know the language it would delay me for a week or two.

    There is another thing worth considering, if you're developing a scripting language then why not develop tools to go with them? it probably wouldn't be too much of a leap and it could help out the language or allow for simple or even more advanced things to be considerably faster and easier again. The actual structure of the language though would have to built around the xml so that would limit it but I don't know by how much as I haven't done anything too advanced with it yet, reasonably though you should be able to do anything with it that you could with the xml. It would have to be something that is good at taking large amounts of similar objects yet also good at allowing for complex actions when needed, maybe some kind of binding system? I don't know but I'll follow this no matter what.
     
  4. Kaidelong

    Kaidelong Member

    I am hoping to have something up on git late may to early june, before I move out (probably to Portland OR). It is looking like I may not have too much time to work on this but I'm working on IO right now, and toying around with ideas for Dredly itself.
     
  5. Xavion

    Xavion Member

    Alright I've been looking into Haskell and I have to ask, Why choose it? it's a lesser known language that is one of the harder ones to learn and different from most others so that it would make it harder for a new person to start helping. I haven't managed to find any obvious advantages to using it so I honestly don't see why you would, I'd personally go for something that is more well known and more likely to be able to handle anything + guis like javascript or python. Not to take the wind out of your sails it just seems like an odd choice.
     
  6. mining

    mining Member

    Haskell is easier to learn than most imperative languages, its just completely different to imperative languages which is where most people's exposure comes from.

    I'd perhaps lean more towards e.g. python than haskell, but haskell is a good language to use for a project like this, IMO.
     
    Kazeto likes this.
  7. Xavion

    Xavion Member

    I was thinking about this and I had an idea that's kinda crazy, what if for the custom language we use XML? Just simplify and extend the current XML. We build a tool that you run your mod through and it would take all the custom stuff and replace it with actual stuff, it would make most of the current documentation still useful and it would make a lot of nastier stuff like item sets become really easy for people to make which is what we'd be aiming for. It is also useful because a lot of what people make is essentially lists of stuff and that's not particularly nice for most scripting languages but is for something like XML or JSON that's primary purpose is storing data not functionality, and using an already existing system as a base would makes things easier.

    I'd vote for python myself as it's the one I'm most experienced in and it would work. I still think web app based might be viable as well as there is support for offline apps and file system interactions in the newer versions, I'm not completely sure about that though and whatever works I suppose. Just so long as it's mac friendly I'll be happy.
     
    Kazeto likes this.
  8. Kazeto

    Kazeto Member

    I don't want to be the one to ruin your proposal, but really, XML isn't the best language for actually making a whole game. It is good as an "add-on" language for making modifications and custom content due to the fact that it's a mark-up language with no defined tags, but when making a core for something (the "core" in this case being the game) it might not necessarily be what you want.
     
  9. Xavion

    Xavion Member

    What? I was talking about using it instead of a custom scripting language, just as extra content. I'm perfectly aware it can't actually do anything by itself and it's just used for storing data for whatever reason but I'm not really sure how you got making a game out of it out of what I said. My proposal was just to extend the current dredmor one and have it be adjusted to suit the standard by our program.
     
    Kazeto likes this.
  10. Kazeto

    Kazeto Member

    Oh...

    In that case I just blame it on the fact that I am sleep deprived (that, and the fact that it was 1:35 AM when I wrote my previous post). But considering I am sleep deprived almost perpetually, I won't hold it against you if you decide it's a stupid excuse.

    I'll get back to actually reading what you wrote tomorrow (well, more like today, I guess), but if what you wrote in your previous post is really what you insist in this one that it was, then I endorse this idea.

    And now I think I'm going to go off and decrease my sleep deficit, seeing as I appear to be lacking basic reading capabilities now.
     
  11. Kaidelong

    Kaidelong Member

    The problem with XML is that I'm a fan of indentation based hierarchies because when you have { .. }, ( .. ), <> < ... /> to keep track of people mismatch those, mess them up, forget them, and so forth, and it's not always obvious that a line should have ended with ))))); rather than )))); By naming the tags, XML partially avoids this, but winds up being extremely verbose due to the same practice. The current documentation is not very useful anyway and I have my reasons for wanting to ditch it a little (more on this later). I just got back today so I'm tired but I'll get this post up about a primitive type for Dredly, damage.

    I'm making damage a group, so users can add it together, negate it, get a zero value and such. The reasoning is as follows:

    Code:
    class Group g where
        zero :: g
        negate :: g -> g
        plus :: g -> g -> g
     
    instance (Group t) => Group (Maybe t) where
        zero = Nothing
        negate = fmap negate
        plus = liftA2 plus
     
    instance (Group value) => Group (Map key value) where
        negate = fmap negate  -- group morphism
        zero = empty
        plus = unionWith plus
     
    instance Group Float where
        zero = 0.0
        negate n = -n
        plus n m = n+m
     
    instance (Group g) => Group (g,g) where
        zero = (zero,zero) -- group morphism
        negate(x,y) = (negate x, negate y)
        plus (x,y) (w,z) = (plus x y, plus w z)
     
    newtype Line = (Float,Float) deriving Group
     
    slope = snd . Line
    intercept = fst . Line
     
    data PrimaryStat = Burliness | Nimbleness | Sagacity | Caddishness | Savvy | Stubborness deriving (Eq,Ord,Bounded)
    data SecondaryStat = ...
    data Stat = Primary PrimaryStat | Secondary SecondaryStat deriving (Eq,Ord,Bounded)
    data DamageType = Acidic | Aetherial | Asphixiative ... deriving (Eq,Ord,Bounded)
    type Damage = Map Stat (Map DamageType Line)
     
    -- If Map DamageType Line is in Group, then Damage is in Group
    -- If Line is in Group, Map DamageType Line is in Group
    -- Line is in Group, therefore Damage is also in Group
     
     
    
    Translating into XML, you'd go over all the keys, and for each stat translate a damage value into an appropriate <effect ... > tag to add in the proper context. Adding two damages together is subtly different from adding them into a spell one after the other but to easily construct a damage effect out of parts like "ProjectorDamage = damage(alchemy,acidic,4,1)+StrongScalingAcidDamage" where you can adjust the scaling for a bunch of things that require StrongScalingAcidDamage on some other line of code and use it as a constant, without getting the effect of doubling up resistance modifiers from multiple damage effects unless you specifically say so.
     
    mining and Kazeto like this.
  12. Xavion

    Xavion Member

    Unfortunately there is a decent amount of that code that I don't understand yet but I can learn, as for the other stuff. I get where you're coming from with indentation based languages but they can get screwed up easily as well across several levels of indentation or long chunks of code unless you're editor supports those already for the given language. Which it won't unless we use a language that already uses that as a base. Treating damage as a primitive does seem alright but also seems fairly complex for a primitive. The language we do eventually end up with though has to be friendly with large scale data storage as a lot of mods will still consist of large lists of things like items, rooms, or monsters, and with something like rooms there is pretty much no way to make much difference without visual tools.
     
  13. Kaidelong

    Kaidelong Member

    Well the fundamental idea has taken shape and I can now seriously move toward implementation. Here is the (rough) plan:

    Dredly is, fundamentally, just a less verbose XML for dredmor modding, mapping to it relatively one to one.
    Dredly will have extremely simple syntax, S expressions where colons and indentation can be used to substitute for parenthesis
    Dredly will support macro definitions, and most of the meat of the language will be in transforming things in preprocessing. Essentially what we end up with is: You work with the raw parse tree, mostly, but you are allowed to define functions that transform subtrees into other subtrees.

    I suppose the hardest thing to implement is going to be the macro system, but having an intermediate goal of "just a less verbose XML" works in the meantime.
     
    Kazeto likes this.
  14. Xavion

    Xavion Member

    Sounds good, I'll help when there is something to help with but I might start trying something in python or something if I run out of other stuff to do an haven't got this to work on. Could be useful to try and demonstrate why I think python is a better choice.
     
    Kazeto likes this.
  15. mining

    mining Member

    Well, Lisp would perhaps be good as S-expressions are perfect here, the CLISP object model matches Dredmor XML constructs well, and Lisp Macros are zany good - however, lisp is also a perfect example of paren counting, which is something we'd like to dodge.
     
    Kazeto likes this.
  16. Xavion

    Xavion Member

    Remember how I mentioned I might try something? Well I did. Here is the result of trying to magic up a first version of a syntax guide. I've also start trying to implement this in python using only built-ins and so far it can create zip files, folder structures, and xml, the actual parser is easily the biggest part though so it is going quite a bit slower. Anyway here is what I got, it's not very good so far but it's only a first draft so any thoughts, ideas or opinions would be great. It still needs some work to make it a bit more powerful but it should be able to do anything as of now.


     
    Kazeto likes this.
  17. Kaidelong

    Kaidelong Member

    Mm cool, you seem to have way more dedication than me so likely I'll end up helping you out on your project in the end, in the meantime I'm going to keep up my work in competition. My approach is a little different in that I am not mapping straight to XML attributes but actually providing some actual Dungeons of Dredmor data types like ElementalType, PrimaryStat, SecondaryStat, Stat, Damage, Trigger, BuffName, LineIntercept (for MP requirements and used in the definition of Damage, which is an affine space in the rough form "Arrow map => map Stat (map ElementType LineIntercept)", using a rule that is roughly "Arrow (~>), Group g => Group (t ~> g) where { plus f g = uncurry plus . f &&& g; zero = arr(const zero); negate = (>>^ negate); }" although I'm actually not using Control.Arrow but implementing damages (for now) as essentially flat, unboxable data types that are something like matrices. I'm a little scared of their size compared to using partial maps but with any luck it won't be a big problem.

    That said, I know Python, and I know how to write parsers, so if you get something up on git I might well go help out already.
     
    Kazeto likes this.
  18. Xavion

    Xavion Member

    Ah, but the reason it seems straight to xml is just because the output has to map to xml and mod.xml is extremely simple. Well that and that most of what's written should be pretty much the same anyway. I haven't figured how to get complex interactions going properly yet but as a rough draft something like below could work as a base for dealing with stats buffs with only a couple of minor changes to enhance syntax.

    Code:
    pstat-R:
        type-req: LST-strict-ci
            Bur(|liness)
            Sag(|acity)
            Nim(|bleness)
            Cad(|dishness)
            Stu(|bbornness)
            Sav(|vy)
        val(|ue)-req: NUM-int
     
    pstat-W:
        primarybuff:
            id=$type?i
            value=$val
     
    sstat-R:
        type-req: LST-strict-ci
            (HP|Health)
            (MP|Mana)
            Melee Power
            Magic Power
            Crit(|ical)
            Hay(|wire)
            Dodge
            Block
            Counter
            (EDR|Enemy Dodge Reduction)
            Armor(| Absorbtion)
            (|M |Magic )Resist
            Sneak(|iness)
            (HP|Health) Regen
            (MP|Mana) Regen
            Wand Burnout
            Trap Aff(|inity)
            Trap Sense(| Radius)
            Sight(| Radius)
            Smithing
            Tinkering
            Alchemy
            (|Magic )Reflect
            Wand Crafting
        val(|ue)-req: NUM-int
     
    sstat-W:
        secondarybuff:
            id=$type?i
            value=$val
    Then you should just be able to something like @pstat for the type and it would make it a stat although technically speaking I've coded buffs and not stats there it should be a minor change.
     
    Essence and Kazeto like this.
  19. Xavion

    Xavion Member

    I have returned! or more precisely there's a lull in Uni at the moment so I got back to this. Anyway I've made a git that is here. Currently it's kinda horrible but I'm currently trying to get it to at least basic levels of functionality along with cleaning out some of my test garbage and commenting it a bit, still gonna need some work on hierarchy but it's going along fine for now even if it doesn't run due to some half written functions. I've also been working on the syntax doc but it needs some work to stop it from bloating while also allowing for full functionality, the main goal here is to have the scripts you write be as readable as possible. e.g. It currently doesn't support indices for id's for things like stats or requirements so you'd have to write something like requires: cotw or stat:reflect I've also made a fair few methods of shortening different names to allow for compactness while trying to avoid sacrificing readability. Anyway go look at the git if you want to see the current language state, I'm working on the parser and I should have the basic support soon.
     
    Kazeto likes this.
  20. Xavion

    Xavion Member

    Alright so after a whole load of distractions and holidays and stuff it's finally functional! It's currently missing some fairly important parts (mainly multiple attributes on one tag) but as long as you avoid the two or three pitfalls it works fine. I've been putting off writing the syntax for a while though so it can only parse mod.xml and copy all non-xml files across and then compress it into a zip but it works! Hopefully I'll have the python finished up enough to be able to do everything soon but it's very close. I'll post/edit once I've got the last couple of bits like macros, and multi attrs working and then it should be properly ready for testing.

    EDIT: Multi attrs are working! It's just macros to go. Thought I'd also add a an example of the redone syntax.
    Code:
    info-R:
        (revision|ver(|sion)): STR
        author: STR
        (title|name): STR
        desc(|ription): STR
        (require|need)(|s): STR-strict-ci
            (|)
            (ROTDG|realm of the diggle gods)
            (YHTNTEP|you have to name the expansion pack)
            (COTW|conquest of the wizardlands)
     
    info-W:
        !FILENAME=mod/mod.xml
        dredmormod:
            revision:text=$revision
            author:text=$author
            name:text=$name
            description:text=$desc
            info:totalconversion=0
            require:expansion=$require?i
    nearly the same but I reckon it's an improvement. I'm also thinking that I'll make a separate thread as soon as this is functional.
     
    Kazeto likes this.