Sneaky Modding Tricks

Discussion in 'Modding' started by Essence, May 29, 2012.

  1. Kazeto

    Kazeto Member

    Mhm, pretty much that. It's not the most efficient way to do it (memory-wise), but it's possible to mitigate it, and more importantly it makes the whole thing a bit more fool-proof in its working, because there are only two buffs (the control/pointer ones and the temporary ones) and thus if you keep your code clean it's really hard to do something stupid.
    Of course, depending on what the thing in question is supposed to do exactly, it might be possible to do it without the temporary stack (in these cases when you want to remove the control stack when things happen). But, as usually, it's safer to just have it and not have any use out of it rather than not have it and then need it.

    And it's nice to see that, contrary to my earlier fear, you appear to know a bit about it (or maybe even a byte).
    OmniaNigrum likes this.
  2. mining

    mining Member

    The main issue is that while you can make a turing machine, you can't make a turing machine with I/O, realistically.


    I did actually think about an optimal way to /force/ create a programming language.

    Test room, arbitrarily large (size is limited only by Dredmor). Summon custom monsters onto each tile, which have the simple AI of calling a single spell. The player can cast spells which iterate over this array of custom monsters (in the form of an xbuff and a ybuff). The player can then iterate the monster's value(s), or decrement it. Rinse and repeat.

    The player can then target the first monster, and use a 'start running mah program' script. One of the monster's values can represent a machine instruction, the other can represent any metadata required for that (e.g. JMP to locX, locY). Input / Output during the program can be handled by applying buffs to the player turn by turn - you would be limited to one character of output per turn.

    Now, suppose we want to write a simple "Hello World" program.

    SELECT(1,1) //1 op
    SETOP('putc') //depends what value putc is, possibly like 30 ops.
    SETVAL('H') //'H' ops, I forget the ascii value ;)
    ... etc.
    SELECT(1,1) //11 ops
    RUNPROG() //1 op
    Do nothing. 'H' buff appears on player.
    Do nothing. 'e' buff appears on player.
    Do nothing. 'l' buff appears on player.
    ... etc.
    Essence, Kazeto and OmniaNigrum like this.
  3. Essence

    Essence Will Mod for Digglebucks

    Note to self: next Badass: Mining.
    mining, Kazeto and OmniaNigrum like this.
  4. OmniaNigrum

    OmniaNigrum Member

    Over and over again if you ask me. :)

    The border between insanity and genius is often so narrow that there appears to be no border. Mining is the name of that border.
    (And which side of that border is Kazeto on? I honestly cannot ever figure it out. If he ever got some good sleep it would almost certainly be the genius side though.)
    Kazeto likes this.
  5. mining

    mining Member

    Some cool things you can do: (wip post)

    Breadth First Search (find the nearest monster or item, say):
    Make a spell that fires off in the 8 tiles 'circle' around the target. This is the main 'finding' function. Add a trigger to it that calls a spell that only fires on [monster / item / wall / whatever]. This spell applies a STOP buff on the player to stop the search ;). The finding function also calls itself on each tile in the 8 tile circle.

    Scaling damage dealt to distance: (solely in X or Y axes for the moment)

    Have a spell that has a trigger that requires a monster target (i.e. the payload). The spell should also call itself on the next tile in the path if a STOP buff is not present (the STOP buff is applied to the player by the payload). Every iteration, the buff pile grows larger, until impact (or wall hit, you'll need a trigger to handle wall collision) when you burn off the buff pile, doing damage per stack.
    Last edited: Aug 10, 2013
    Kazeto and OmniaNigrum like this.
  6. Bohandas

    Bohandas Member

    Here's a cool set piece I came up that can be inserted into pretty much any custom room;

    The Broken teleporter:

    Insert this into the custom room you want to put it in:
    <customblocker id="Crap Portal" name="Satanic Displacement Glyph" at="1" pngSprite="dungeon/portalB/portalB" pngFirst="0" pngNum="5" pngRate="120" passable="1" pngAnimate="1" can_push="0" percent="92" />
    <script repeat="-1">
    	<condition condition_type="at" id="player" at="1"/>
    	<condition condition_type="at" id="Crap Portal" at="1"/>
    	<action on="success" action_type="spell" casts="No Visuals Blink Effect" />
    and this into your mod's spellDB
    <spell name="No Visuals Blink Effect" type="target" icon="skills/spells/zephyric_transport32.png"> 
    	<description text="RANDOMIZATION!"/>
    	<effect type="blink" skipanimation="1"/>
    	<anim sfx="teleport_short" centerEffect="1"/> 
    This will create a blocker at location 1 that looks just like a standard Satanic Displacement Glyph but actually sends the player to a random nearby tile when stepped on.
    mining, OmniaNigrum and Kazeto like this.
  7. Kazeto

    Kazeto Member

    Not much in terms of "sneakiness" there, but indeed the effect is very nice and simple at that.
    OmniaNigrum likes this.
  8. Bohandas

    Bohandas Member

    Well here's a sneakier one. You can create something equivalent to a switch (maybe even better) by setting up a breaker that is replaced *(via a script) by another breaker when struck and using another script to replace the second breaker with a copy of the first breaker when it, in turn, is struck.

    Attached is an example.

    Attached Files:

  9. Fortescue

    Fortescue Member

    Heyo, got a question actually, not a trick. Does anyone know how to safely remove cheeses from the game database? Since they are a common starting item, the game will crash even if you remove all other references to cheeses in rooms / monsters / spells / items / skills / recipes. This is kind of important for a mod I'm making that is nearing completion.
    OmniaNigrum likes this.
  10. OmniaNigrum

    OmniaNigrum Member

    The best you can do is to remove all but one type. You can possibly remove all of them, but that would break several abilities in a number of skill trees and items. Really, you would have to check for the name of the cheese in each and every XML file in the game to determine if it is safe to remove them. And be wary of skills/abilities that chain to other skills/abilities.
    Kazeto and Fortescue like this.
  11. Fortescue

    Fortescue Member

    I opened every database file in Notepad++ and did a "search all open documents" to make sure I didn't miss anything. I did leave Cheese and Grated Cheese, and got rid of all references to other cheeses. I think the issue is your starting equipment. Do you have any idea how to take cheese out of that?
    OmniaNigrum likes this.
  12. OmniaNigrum

    OmniaNigrum Member

    Not really. If I recall correctly, the starting equipment is determined by your skills, but hardcoded in the executable or something to that effect.

    However, now that I think of it, you may still run into further trouble reducing the cheese due to the encrust effects. (Or you may have already pruned those effects out. I do not recall much of the XML. It has been a long time since I really played the game even.)
    Fortescue and Kazeto like this.
  13. Fortescue

    Fortescue Member

    Yeah, there was a DB for encrusts and I edited that one too.
    OmniaNigrum likes this.
  14. Alistaire

    Alistaire Member

    Well you can't upload such a mod to the workshop, because the overwrite property doesn't work. If it did, you could set special='1' to every cheese except for one, and overwrite='1' on everything that needs a different cheese from the one you left.
    Kazeto and OmniaNigrum like this.
  15. Alistaire

    Alistaire Member

    Is it possible to use requireBuffOnTrigger on monster targets?

    <item name='Sticky Bolt' iconFile='items/1.3/bolt_tf2_sticky.png' level='2' type='6' maxstack='4'>
        <price amount='50'/>
        <weapon piercing='1' crushing='2' hit='tf2_stickyHit' canTargetFloor='0'/>
        <description text='A bolt'/>
    <spell name='tf2_stickyRemove' type='target'>
       <effect type='removebuffbyname' name='tf2_stickyBuff' amount='1'/>
    <spell name='tf2_stickyExplode' type='target'>
       <effect type='trigger' affectsCorpses='0' spell='tf2_caberHit'/>
       <effect type='trigger' affectsCorpses='0' spell='tf2_stickyRemove'/>
       <effect type='trigger' affectsCorpses='0' spell='tf2_stickyTimeUp'/>
    <spell name='tf2_stickyTimeUp' type='target'>
       <effect type='trigger' affectsCorpses='0' requireBuffOnTrigger='1' requireBuffOnTriggerName='tf2_stickyBuff' spell='tf2_stickyExplode'/>
    <spell name='tf2_stickyBuff' type='target'>
       <buff useTimer='0' stackSize='4' self='0' icon='sprites/tf2_stickyBuff64.png' smallIcon='sprites/tf2_stickyBuff32.png'>
         <secondaryBuff id='6' amount='-1'/>
       <effect type='trigger' affectsCorpses='0' amount='4' spell='tf2_stickyTimeUp'/>
       <description text="There's a bomb hooked to your skin. THERE'S A BOMB HOOKED TO YOUR SKIN!"/>
    <spell name='tf2_stickyGiveBuff' type='target'>
       <effect type='trigger' spell='tf2_stickyBuff'/>
    <spell name='tf2_stickyHit' type='targetmonster'>
       <effect type='trigger' spell='tf2_stickyGiveBuff'/>
       <effect type='trigger' amount='1' spell='tf2_stickyCheckBuff'/>

    That's my code. I wanted the sticky bomb to target the floor (which would create a sticky bomb trap) /and/ target monsters (which would add a bad buff with max stack of 4, which would explode after 4 turns, and any amount of sticky bombs higher than 1 would trigger a combo effect (more damage)).
    What I've got right now is a buff given to the targetmonster, but tf2_stickyTimeUp doesn't do anything. I guess it's because
    <effect type='trigger' affectsCorpses='0' requireBuffOnTrigger='1' requireBuffOnTriggerName='tf2_stickyBuff' spell='tf2_stickyExplode'/>
    doesn't work on monsters. Removing it results into an endless loop of explosions.

    EDIT 2:
    Also, it appears the game doesn't know what target I want the tf2_caberHit to happen to.
    Last edited: Jan 27, 2014
    OmniaNigrum likes this.
  16. Kazeto

    Kazeto Member

    It always checks your buffs. You could try to do it by creating a whole web of dummy buffs with triggers on you which tracked which location relative to you to explode and track the movement by using spell mines, but not only is that a lot of work but it's also not reliable enough.

    But to answer your question, yes, it is possible in a roundabout weird-as-all-heck very-time-inefficient the-code-that-makes-people-insane sort of way (the one above).
    OmniaNigrum likes this.
  17. codebracker

    codebracker Member

    I'm trying to make a staff with a for hit combo effect, is it possible for an effect to trigger if neither of 2 buffs are present?
    I did it like this:
    <spell name="Beat" type="self" wand="1">
    <effect type="damage" blasting="4" blastingF="1" secondaryScale="10" />
    <effect type="trigger" requirebuffonnottrigger="1" requirebuffonnottriggername="Beat 1" spell="Beat 1"/>
    <effect type="trigger" requirebuffontrigger="1" requirebuffontriggername="Beat 1" amount="1" spell="Beat 2"/>
    <effect type="trigger" requirebuffontrigger="1" requirebuffontriggername="Beat 2" amount="1" spell="Beat 3"/>
    <effect type="trigger" requirebuffontrigger="1" requirebuffontriggername="Beat 3" spell="Beat smash"/>
    <spell name="Beat 1" type="self" wand="0">
    <buff useTimer="1" time="2" allowstacking="0" removable="1" bad="0" icon="skills/buzzing64.png" smallicon="skills/buzzing32.png" >
    <primarybuff id="2" amount="5"/>
    <spell name="Beat 2" type="self" wand="0">
    <buff useTimer="1" time="1" allowstacking="0" removable="1" bad="0" icon="skills/aikido64.png" smallicon="skills/aikido32.png" >
    <secondarybuff id="8" amount="20"/>
    <spell name="Beat 3" type="self" wand="0">
    <buff useTimer="1" time="1" allowstacking="0" removable="1" bad="0" icon="skills/spells/unconscious_precognition64.png" smallicon="skills/spells/unconscious_precognition32.png" >
    <secondarybuff id="4" amount="20"/>
    <spell name="Beat smash" type="template" templateID="88" anchored="0" wand="1">
    <effect type="damage" blasting="5" blastingF="1.5" primaryScale="2" />
    <effect type="movecurses" />
    <effect type="removebuffbyname" name="Beat 1"
    <effect type="removebuffbyname" name="Beat 2"
    <effect type="removebuffbyname" name="Beat 3"
    <effect type="knock" />
    <anim sprite="sprites/sfx/blastA/blastA" frames="4" firstframe="0" framerate="25" sfx="blast" centerEffect="1"/>
      <description text="Beat to the beat of my staff!."/>
    I'm semi-certain this should trigger on the fourth hit in a row and than every two hits after that.
    Could I just add another requirebuffonnottriggername into the same line or would that crash?
    OmniaNigrum likes this.
  18. Kazeto

    Kazeto Member

    You don't want to be using spells with more than one "requirebuffontrigger" or "requirebuffonnottrigger", it makes them work really weird. One of each is fine, but more than that and you have pudding instead of something solid. What you should instead do is make use of dummy spells which will be there for the purpose of checking requirements, one after another. I could write that one for you but seeing as I just woke up I wouldn't trust myself not to make it explode for the next half an hour or so.

    Also, not that I'm complaining but this really isn't an “ask a question” thread.
    OmniaNigrum likes this.
  19. codebracker

    codebracker Member

    Oh sorry, I was just wondering if that is some trick I never heard of.
    Also there are currently 3 dummy buffs just to make it work like this, I just added some stats for damage boost.
    OmniaNigrum likes this.
  20. Kazeto

    Kazeto Member

    Give me an hour, then (quite busy right now) and I'll write some sort of for-demonstration code for this one.
    OmniaNigrum likes this.