Bay 12 Games Forum

Please login or register.

Login with username, password and session length
Advanced search  
Pages: [1] 2 3 ... 6

Author Topic: [DFHack] AutoSyndrome/etc and Registration  (Read 12312 times)

expwnent

  • Bay Watcher
    • View Profile
[DFHack] AutoSyndrome/etc and Registration
« on: June 29, 2014, 05:07:24 am »

In the next release of DFHack, raw-script interfaces are going to be replaced with registration. This means that instead of saying

Code: [Select]
[REACTION:TURN_INTO_CHICKEN]
[NAME:chickenize]
[BUILDING:BUILDING_CHICKEN:NONE]
[PRODUCT:100:1:BOULDER:INORGANIC:CHICKEN_MAT]

[INORGANIC:CHICKEN_MAT]
[SYNDROME]
[CE:TURN_INTO_CHICKEN_EXCEPT_WITH_CORRECT_SYNTAX]
[NAME:"turn into chicken"]
[SYN_CLASS:\AUTO_SYNDROME]
[SYN_CLASS:\COMMAND]
[SYN_CLASS:reveal]
[SYN_CLASS:all]

you just have

Code: [Select]
[REACTION:TURN_INTO_CHICKEN]
[NAME:chickenize]
[BUILDING:BUILDING_CHICKEN:NONE]

and then in onLoad.init

Code: [Select]
modtools/reaction-trigger -reactionName TURN_INTO_CHICKEN -command shape-change -target \WORKER_ID -creature CREATURE_CHICKEN

You could put it in dfhack.init, and it will work, but you really shouldn't. This sort of thing depends on what mods you're using and if you download someone else's save you'll mess it up if your dfhack.init has your-mod-specific stuff and not-their-mod-specific-stuff-that-it-shouldn't-depend-on-but-it-does.

First of all, I realize this is going to break a lot of stuff, so I made a special script to help with the transition process. I ran it on a (slightly old) version of Masterwork and it produced this output. It should mostly work, but all syndromes must now be given unique names in order to work with reaction-trigger. The only change you'll need to make is to paste that output into onLoad.init and make sure syndromes have unique names. That being said, the vast majority of the time you don't need a syndrome at all. If it's just a transformation, use shapechange. If it's a command, just use reaction-trigger directly. The only time you need a syndrome is if you actually want to infect them with a syndrome as an end result.

The current version of the script is here.

The current version of reaction-trigger is here, and depends on this. It'll all be in the next version. I'm just putting a quick early draft here so modders can play with it before the next release.

I noticed a few weird things in Masterwork like \COMMAND \LOCATION without a command name in between, and in some cases not even present, so I filtered those from the file. I assume they're just placeholders. Looking at the source of autoSyndrome, they don't actually do anything.

Let me know what else would be useful output in the file it produces.
Logged

Meph

  • Bay Watcher
    • View Profile
    • worldbicyclist
Re: [DFHack] AutoSyndrome/etc and Registration
« Reply #1 on: June 29, 2014, 05:24:07 am »

Stupid question, but why not both? Keep the old AutoSyndrome, and add the new Registration system. That way there is no rush with updating all inorganics, and people can use either.
Logged
::: ☼Meph Tileset☼☼Map Tileset☼- 32x graphic sets with TWBT :::
::: ☼MASTERWORK DF☼ - A comprehensive mod pack now on Patreon - 250.000+ downloads and counting :::
::: WorldBicyclist.com - Follow my bike tours around the world - 148 countries visited :::

expwnent

  • Bay Watcher
    • View Profile
Re: [DFHack] AutoSyndrome/etc and Registration
« Reply #2 on: June 29, 2014, 06:04:30 am »

A few scattered thoughts:

1. The new version is better. It's slightly more powerful. It'll be easier to learn and easier for new modders to understand the DFHack interactions of existing mods and learn from them. The main DFHack repo is a "role model" for many other scripts and plugins. The more organized and clean it is, the more organized and clean new scripters will be. Similarly, major mods are one of the primary ways that people learn how to raw mod, so the cleaner and more organized they are, the better. Itemsyndrome models itself after autoSyndrome, etc. I'll also be redoing itemsyndrome and making a transition script for it. If I'm really inspired I'll do something similar with Roses' scripts.

2. The people who know way more about it than I do are telling me that it will probably take longer than usual for the next DFHack release to happen after the next version, which is logical, since there's a lot of changes and a lot of old stuff to reconfirm. Now is as good a time as any to make the transition. I'm already overhauling script organization for the next release so it's a good time for me to do it.

3. I don't want to encourage people to more firmly entrench themselves in the old way of doing things.

4. It's confusing to have two subtly-different ways of doing the same thing. I'm standardizing a lot of things in the scripts in the main repo, extracting common functionality to the lua modules, etc. The more we use good conventions, the less people will have to memorize about different scripts that accomplish similar things: a standard convention for special arguments (\BLAH vs -blah vs whatever), a standard way of doing escape sequences (a way of saying: yes, I want to literally pass the argument \UNIT_ID to this script without expanding \UNIT_ID to the id of the unit), a standard way of telling DFHack that you want certain behavior from certain items/units/interactions/reactions/syndromes/etc, standard conventions for script names (scriptName vs ScriptName vs script-name), and so on, and so on. Those are all great things if they can be accomplished and they'll make things easier once they're in place.

It'll make things difficult for a little while in the short term, but in the long run, this will be a better way of doing things. A lot of the transitional stuff can be automated, so that's why I'm making transition assistance scripts. If certain things that are in the works go incredibly well, it will even be possible to *entirely* automate the process and autogenerate new raws from DFHack in a certain folder for modder review.
« Last Edit: June 29, 2014, 06:06:01 am by expwnent »
Logged

Meph

  • Bay Watcher
    • View Profile
    • worldbicyclist
Re: [DFHack] AutoSyndrome/etc and Registration
« Reply #3 on: June 29, 2014, 08:59:48 am »

I agree on all points, but having the old AutoSyndrome still active parallel to the new system would allow me to port one industry/workshop/race, then release, test, wait for feedback, do the next. You saw for yourself how long that list is you autogenerated, and I have to test every single reaction, more or less.
Logged
::: ☼Meph Tileset☼☼Map Tileset☼- 32x graphic sets with TWBT :::
::: ☼MASTERWORK DF☼ - A comprehensive mod pack now on Patreon - 250.000+ downloads and counting :::
::: WorldBicyclist.com - Follow my bike tours around the world - 148 countries visited :::

Roses

  • Bay Watcher
    • View Profile
Re: [DFHack] AutoSyndrome/etc and Registration
« Reply #4 on: June 29, 2014, 01:53:16 pm »

I think this is a good change as the SYN_CLASS system can get a little much (it also eliminates all the unnecessary inorganics). My question is, what should I do or change in my scripts to make it easier/better/correct for this new system?
Logged

expwnent

  • Bay Watcher
    • View Profile
Re: [DFHack] AutoSyndrome/etc and Registration
« Reply #5 on: June 29, 2014, 10:12:14 pm »

I agree on all points, but having the old AutoSyndrome still active parallel to the new system would allow me to port one industry/workshop/race, then release, test, wait for feedback, do the next. You saw for yourself how long that list is you autogenerated, and I have to test every single reaction, more or less.

Ok. For the next release or two I'll release a version of the old plugins separate from the main repo to help with the transition. Please do switch to the new system and let me know if there's some part of it that can be easily automated. It's surprising how much you can automate, and with the several hundred (!!!) autoSyndrome uses in Masterwork, automation is critical to reduce work when possible.

Just a suggestion but do you have beta testers? The skill level needed for testing individual reactions isn't very high, especially if you include special "cheat" reactions so they can skip prerequisites. With Masterwork's large user base it shouldn't be too hard to find some people. Depending on how many testers you have, each one would only have to do a little work. Maybe give them an incentive with early access / etc. It's what I would do.

Also I'm really quite curious about some of those autoSyndrome uses that don't actually call a command. Things like \AUTO_SYNDROME \LOCATION \UNIT_ID but no actual command following them. Those are placeholders right? If they're supposed to do something then they're broken because autoSyndrome doesn't call a command unless you give it a command name to call. Example

I think this is a good change as the SYN_CLASS system can get a little much (it also eliminates all the unnecessary inorganics). My question is, what should I do or change in my scripts to make it easier/better/correct for this new system?

That is an excellent question and I've been meaning to contact you about that. I'm in the middle of standardizing everything within reach, but I haven't 100% defined the conventions yet. Give me another two days to work on updating itemsyndrome and a few other scripts then I'll point you at the new scripts as examples and let you know what the conventions are. I'm glad that I don't have to convince you to switch over. (Secretly I would have rewritten them all myself if you didn't. Shh...don't tell you.)

In general, I think that arguments should be organized in a way so that even someone not familiar with the command should be able to understand roughly what's going on. Special syntax like @ and ; can help separate arguments, but it's confusing to read and can be hard to memorize, especially if everyone has their own syntax for their own command. If autoSyndrome used ; to separate args and itemsyndrome used @ and your stuff used % and ^ then that would be unnecessarily confusing. I strongly believe that all mods of all games should be open source so that the rest of the modding community can learn from everyone else's stuff. Part of that is making your code as clear as possible so people can understand it and extend it. Some languages optimize for having short easy to type syntax, but that makes code hard to read (cough Perl cough). It's not an awful way of doing things, but it's better to have more clarity, even if it means more typing.

Normally the way I group arguments is by making the command go last so that I don't have to actually group them. This isn't the best solution, but the only alternative I like that I can think of right now is something like

Code: [Select]
reaction-trigger -command [ reaction-trigger -reaction REACT_2 -command printArgs "only after running REACT_1" ] -reaction REACT_1
Take a look at the link I posted for reaction-trigger.lua to get a rough idea of how arguments should be grouped.

One thing I have decided on (or rather, angavrilov decided and I don't care strongly enough to get in a fight with him about it) is that scripts are now going to be named in lower-case-with-words-separated-by-dashes. That's an easy thing you can do now. It'll help people remember script names so they don't have to keep looking up the capitalization/etc. Plugins are going to be FormattedLikeThis so that you can tell by looking if something is a script or a plugin, which is a mildly important distinction if you care about how fast it is (plugin fast script slow, of course). Scripters are gently encouraged to follow this convention, but they're free to name their scripts however they want. Scripts in the main repo will all follow the conventions.

If anything, your scripts provide too much functionality. I realize that the point of them is to be called from within things like autoSyndrome but we don't want to reinvent Lua inside that context. Making computer languages is hard and it's very easy to do it very wrong. I'm not sure where the line is. Maybe some of them could be replaced by something like

Code: [Select]
reaction-trigger -reaction REACTION_NAME -command substituteThenRunLua "df.unit.find(<unitId>).flags1.dead = 1" unitId \UNIT_ID
Of course, the simplest way would be just

Code: [Select]
reaction-trigger -reaction UPGRADE_ROBOT -command reaction-triggers/upgrade-robot \UNIT_ID
Code: [Select]
--reaction-triggers/upgrade-robot.lua
local args = {...}
df.unit.find(tonumber(args[1])).flags1.dead = 1 --I don't know why killing a unit would upgrade a robot but this is just an example

since there is a cost to doing a find-replace and parsing an lua script, blah blah blah. It's complicated and there are a lot of tradeoffs. For one-liners it should be fine.

Things like "call this script on everyone within range" are slightly awkward since you have to iterate through all units in order to find the ones in range, but the only way around that is to implement octrees in C++ every frame you want to make such queries and it would only save you time if you're going to be doing a lot of those on the same frame, but then again maybe you can use octree from a few frames ago and widen the search a bit so you get units that moved in the meantime...I'm rambling. Main problem is I'm being too much of a perfectionist. The substitution thing is every-so-slightly better than having special scripts for every one-liner, and having special scripts for every reaction that requires lua stuff is ever-so-slightly better than doing the substitution thing since (assuming Lua is sensible, which is not necessarily true) Lua "preprocesses" each script file at most once but if you give it the source code in runtime in quotes instead of with a file then it has to reprocess the command every time, which is fast but not free. But then AGAIN I'm probably wrong about that since it properly updates scripts that change even if you don't reboot DF so in that case the substitution thing is probably roughly the same as having special script files for each reaction.

Maybe something like:

Code: [Select]
reaction-trigger -reaction UPGRADE_ROBOT -command InvokeAnonymousLuaScript "local args = {...}; df.unit.find(tonumber(args[1])).flags1.bits.dead = 1" \UNIT_ID
At the moment I like that best but I'm open to suggestions. I want to encourage raw modders to move into light Lua/Ruby scripting, and having too many scripts that do simple one-liner things that raw modders should be able to handle would enable the problem in a slightly-less-efficient way.

That was way too long. Sorry.
Logged

expwnent

  • Bay Watcher
    • View Profile
Re: [DFHack] AutoSyndrome/etc and Registration
« Reply #6 on: June 29, 2014, 10:45:21 pm »

The short version:

Meph: k

Roses: name-scripts-like-this.lua, some of your scripts are actually too powerful, see reaction-trigger for a rough draft of how args will be processed, wait two days for details.
Logged

Roses

  • Bay Watcher
    • View Profile
Re: [DFHack] AutoSyndrome/etc and Registration
« Reply #7 on: June 29, 2014, 10:56:31 pm »

It'll be much easier for me to rewrite them since I know what they are supposed to do, I just need a template so I will wait for you to update itemSyndrome and then check the scripts for conventions (I would be glad to follow whatever conventions are set forth, I think standardizing all scripts is a good thing). That being said,
If anything, your scripts provide too much functionality. I realize that the point of them is to be called from within things like autoSyndrome but we don't want to reinvent Lua inside that context. Making computer languages is hard and it's very easy to do it very wrong. I'm not sure where the line is.
This is entirely true, and I would be glad to accept any suggestions. For the most part I understand several things that I need to change in many of my scripts (getting away from relying on autoSyndrome and such), but for some of the scripts I am not sure quite how to handle them. If/when you have time it may be beneficial to discuss changes and suggestions that you have for my scripts (especially the larger ones like wrapper, or the more complex ones like projectile, propel, eruption, and the base- scripts)
Logged

expwnent

  • Bay Watcher
    • View Profile
Re: [DFHack] AutoSyndrome/etc and Registration
« Reply #8 on: June 29, 2014, 11:19:19 pm »

I also plan on writing something like dfhack.processArgs so you can just do

Code: [Select]
--asdf.lua
local args = dfhack.processArgs(...)
if args.thing1 == 'asdf' then print('thing 1 = asdf') end
for _,v in ipairs(args.thing2) do
 print(v)
end

then say

Code: [Select]
asdf -thing1 asdf -thing2 ["blah blah" doooooooom]
#output: "thing1 = asdf\nblah blah\ndoooooooom\n"

The convenience of using dfhack.processArgs will also help enforce the convention because it will only work for the standard argument pattern.
Logged

expwnent

  • Bay Watcher
    • View Profile
Re: [DFHack] AutoSyndrome/etc and Registration
« Reply #9 on: June 30, 2014, 07:54:47 am »

https://github.com/expwnent/dfhack/blob/scriptOrganization/scripts/modtools/item-trigger.lua

Give me another day just to be sure, but there's my replacement and extension of itemsyndrome. You register item types, item materials, and *contaminant materials* along with onStrike, onEquip, and onUnequip scripts. Materials do not have to be inorganic! You can make a magic sword where if you hit a creature and get its blood on the sword, then put the sword down without killing it, then you turn into that creature type. You can make a pair of shoes that carries the souls of all its previous wearers with it. You can make a table that kills you if you try to pick it up. You can make a crossbow that makes you switch places with your target once you hit them. You can make a cloak that turns itself into the last material it was contaminated with. You can make a special material so that ANYTHING made out of that material makes dwarves switch to the opposite sex if they pick it up. You can make a dagger that hurts the wielder as much as the target. You can make a battle axe that upgrades itself every time you kill someone with it. You can make a pair of gloves that triple your strength. You can make a crossbow that hits every creature of the same race as its target. You can make a hat that turns into the brain tissue of its wearer. You can make it so that anything that touches wizard blood turns into wizard blood. You can make a wacky voodoo spell where if the blood of a unit contaminates the same item as the magic poison, then anything in the future that touches that unit's blood turns into adamantine for ten seconds if you use it as a weapon. I'm excited to see what people do with it.

Some fiddling required with each of these of course, but they're all completely possible. It's barely tested at all, but if you want to play with it, feel free. Be sure to grab the relevant lua modules from library/lua/ to make sure it works. It actually won't work with r5 because it needs the UNIT_ATTACK event, but if you fiddle with it you should be able to get it working in r5. An exercise for the reader.

Code: [Select]
# example syntax
modtools/item-trigger -material INORGANIC:GOLD -command [ devel/printArgs "gold item equipped!" ] -onEquip
modtools/item-trigger -material CREATURE_MAT:DWARF:SKIN -command [ devel/printArgs "dwarf skin item? gross. put it back down." ] -onEquip
modtools/item-trigger -itemType ITEM_WEAPON_SPEAR -onStrike -command [ devel/printArgs "spear strikes target!" ]

Roses: I've decided on the above style of syntax described here, but I still need to make that function take a table of acceptable arguments and complain if they pass an argument that you don't understand. Be aware of escape sequences! Inside a list argument like -numbers [ 1 2 3 ] if you say -numbers [1 \2 3] then when the script gets it, args.numbers = {'1','2','3'}. That's so you can put literal, unmatched brackets inside of lists. Furthermore, any time you pass an argument from one script to another, if it starts with a backslash and you don't swap that entire argument into something special like \UNIT_ID then you have to strip off the backslash before passing it to the next script. It's a bit hard to explain why this is a good idea, but the basically it will ensure consistency and permit scripts to pass arguments to each other even if they both use \UNIT_ID.
« Last Edit: June 30, 2014, 07:58:59 am by expwnent »
Logged

Roses

  • Bay Watcher
    • View Profile
Re: [DFHack] AutoSyndrome/etc and Registration
« Reply #10 on: June 30, 2014, 10:26:51 am »

Thats looking really good.

EDIT: I am especially interested in the onStrike capabilities. Is it possible to specify a creatures body part? So that you could run a command if, say, a dragon attacks you with it's tail? I know there is already SPECIALATTACK_INTERACTION, but this requires that the attack break the units skin (according to the wiki) and so is somewhat limited.

EDIT2: Is there a reason the -onEquip is at the end but the -onStrike is not? Can they be anywhere in the list?
« Last Edit: June 30, 2014, 01:44:42 pm by Roses »
Logged

expwnent

  • Bay Watcher
    • View Profile
Re: [DFHack] AutoSyndrome/etc and Registration
« Reply #11 on: June 30, 2014, 07:04:00 pm »

Arguments can be passed in any order.

The UNIT_ATTACK event requires that the attack isn't deflected, blocked, parried, or dodged. Bruises/cuts/etc are all fine. It's possible to get the wound id of the attack. Wounds sometimes affect multiple body parts. It can't find the wound id if the attack severs a body part or if they attack kills the target, but other than that it should work fine. I'm curious what you need this for.
Logged

Roses

  • Bay Watcher
    • View Profile
Re: [DFHack] AutoSyndrome/etc and Registration
« Reply #12 on: June 30, 2014, 08:11:37 pm »

Well, I was thinking a tail swipe attack that triggers my propel script and sends the unit flying might be an interesting combat addition.
Logged

expwnent

  • Bay Watcher
    • View Profile
Re: [DFHack] AutoSyndrome/etc and Registration
« Reply #13 on: June 30, 2014, 08:34:33 pm »

In order to do that I'd have to actually parse the in-game announcements, which is possible, but harder than it sounds. I'm going to say no for the next release because I've already got enough on my todo list, but I'll add it eventually. If you want a sloppy way of doing it, you can monitor the announcements list yourself and scan for the name of the body part in the text. It'll be approximate but it might work well enough.
Logged

Roses

  • Bay Watcher
    • View Profile
Re: [DFHack] AutoSyndrome/etc and Registration
« Reply #14 on: June 30, 2014, 08:58:27 pm »

It's not that important since I can just make it a straight interaction instead of tied to an attack and then give the interaction a required body part. Was just a thought. Other things are more important.
« Last Edit: June 30, 2014, 09:01:03 pm by Roses »
Logged
Pages: [1] 2 3 ... 6