View Full Version : Combat Script
KausticUSMC
07-27-2011, 05:31 AM
I'm a total amateur here so please be patient. I'm trying to learn, and I've learned Ruby well enough I think, but I lack vital understanding of exactly what objects and methods lich uses to interact with the game (I think that's the correct way to explain it o-o)
For example I learned that I can make it see how many critters are in the room with me by using checknpc.length, for example
if (checknpc.length >= 2) and (checkstamina >= 25)
fput 'get 2 my arr'
fput 'cman mfire'
end
Yay intelligent mfire usage! But that object/method, "checknpc.length", that's the kind of thing I don't know exists, and that knowledge is vital to making scripts that will interact with the game and run the various types of checks for different conditions.
Basically I'm writing a combat script. I don't want something completely super fully automated like bigshot (i.e. I don't want the script travel around, go back to town to rest, etc etc). I just want to see a monster, and just hit ;fight and bam. It'll do everything for me, intelligently choosing it's attacks just the way I would, and end when everything is dead.
I could make do with a list of objects and methods used for the various checks (health, stamina, wounds, stance, hidden/unhidden, standing/not standing, etc), I'm sure I can manage well enough teaching myself. Of course, if some experienced scriptwriter has the patience to take me under their wing and teach me the ways of the force, that would be tremendous. I'm no programmer but I understand computers well enough and I learn fast.
Anyway, if anyone knows where I might find that list or, fingers crossed, would be willing to take the time to educate me, I would be indebted to you.
boardergeek
07-27-2011, 05:37 AM
http://www.krakiipedia.org/wiki/Lich_scripting_reference
Then open bigshot and find out how it does stuff. Then ask some more specific questions. Also, open Lich in a text editor and look for search for def just to set what is defined.
Lots of people would love to help, but you really to ask how to do a specific thing.
KausticUSMC
07-27-2011, 05:45 AM
Already poked around bigshot trying to study it, kinda left my head spinning. That thing is a beast. I think it's mostly the way it checks and interacts with it's numerous (NUMEROUS) user-defined settings that makes me @_@
Didn't think of opening the lich.rbw in text mode and looking there, I'll have to dig around. That link though, that's exactly what I was looking for! Not sure why I didn't think of searching Kraki. I guess I didn't expect lich info to be in there, but simu doesn't run kraki so it makes sense that it would also cover 3rd party stuff.
Thanks for the help!! I think this will do for now, I don't want to be the annoying noob with all the stupid questions, so I'll experiment for a bit and come back if I have problems figuring something out. Thanks again!
Gibreficul
07-27-2011, 08:44 AM
start small... then start linking things together.
I did a super simple archer script... figured that's what you're doing. No guarantee as to if it will really work, but, maybe it's enough to push you forward.
target = proc{
fput "target random"
}
get_arrow = proc{|num|
until GameObj.right_hand.noun == 'arrow'
fput "get #{num} my arrow from my quiver"
end
}
fire = proc{
if (GameObj.npcs.length >= 2) and (checkstamina(25))
get_arrow.call(2)
fput "stance off" unless percentstance <= 20
fput 'cman mfire'
else
get_arrow.call(1)
fput 'stance off' unless percentstance <= 20
fput 'fire'
end
waitrt?
fput "stance def" if !GameObj.npcs && percentstance < 80
fput "loot" if GameObj.npcs.find{|npc| npc.status =~ /dead/i}
}
gather = proc{
while GameObj.loot.find{|arrow| arrow.noun == 'arrow'}
fput "gather arrow"
if GameObj.right_hand.noun =~ /arrow/i
fput "put arrow in arrow in quiver"
else
fput "get arrow"
fput "put arrow in arrow in quiver" if GameObj.right_hand.noun =~ /arrow/i
end
sleep 3 if GameObj.loot.find{|arrow| arrow.noun == 'arrow'}
end
}
while GameObj.npcs
target.call
fire.call
end
gather.call
I originally had that all the procs with the def/end syntax. Starting out, those can be dangerous because of their global nature. Also, I modded all the checknpcs to GameObj.npcs because, once you learn to use the GameObj functions, your scripting capabilities increase greatly.
As I said, no guarantee if the code above works, was just something quick to demonstrate something useful... pieced together with small parts. Set a macro script to...
\x;eq start_script('name_of_that_script')\r
and basically, you have what you asked for.
KausticUSMC
07-28-2011, 03:12 AM
Gibreficul, that's a tremendous help. I guess the mfire thing tipped you off huh? Yes, the first character I'm trying to make this for is an archer, and I'm trying to set it up to use various combat maneuver skills as well. I can use much of what you gave me there as a foundation and expand on it, and there's also a fair amount of code there that, if I'm reading it right, either does things I didn't realize I could do, or does things I knew how to do, but does them better/more efficiently. That will be a great learning tool for me to build from. Thanks a ton!
KausticUSMC
07-28-2011, 03:48 AM
Already hit a snag, that didn't take long. It's with the #{num} thing, which of course happens to be the code I was referring to when I said I didn't know how to do it, i.e. making the script change it's own variables.
Anyway, I tried just running the script above to see if it would run and iron out the wrinkles (figures the wrinkle would be in the part I don't know how to fix), and when it goes to get arrows it actually sends #{num} to the game just like that instead of capturing the number defined in get_arrow. I fiddled around with it, tried changing the variables in get_arrow to "@num = 2" instead of just 2 for example, and making #{num} into #{@num} (and several instances of that which includes a = in various places) but I couldn't make it work. I'm gonna go over variables and how to define/use them in my little Ruby guides and keep fiddling with it, I'll post again if I make it work.
KausticUSMC
07-28-2011, 03:59 AM
Got it. Might not be the most efficient way, but it works. Made the 1 and 2 into strings, i.e. get_arrow.call(num = '2') and then inserted that into the command as fput 'get ' + num + ' arrow from my quiver'
boardergeek
07-28-2011, 04:20 AM
In the script above the code reads fput "get #{num} my arrow from my quiver"
I don't know if copied it verbatim or not, but the double quotes are key here. In Ruby you can use single or double quotes. If you have single quotes then the text between will not be evaluated for changes. If you use double quotes then the text is evaluated for changes.
What does this mean. With double quotes if you have the #{variableName} syntax then the #{...} will get replaced with the string version of the variable used; i.e. variableName.to_s (gets the string representation of the variable.
Now variables. If variables are preceeded with a $ then they are global and will exists within all functions and scripts. Avoid the dollar sign. Don't use global variables. This is a good general rule until it isn't. That is to say I can think of many reasons to use a global variable but usually it is just a shortcut and better practices exists.
The at sign @ in front of a variable means this is a member variable for the current class. Now this may seem confusing because you are using @var in your script and you never created a class or maybe you don't even know what a class is. The simple answer is I don't know exactly why you can still this. My guess is that lich loads every script into a class structure so @var syntax is still valid.
Now lets break down
get_arrow = proc{|num|
until GameObj.right_hand.noun == 'arrow'
fput "get #{num} my arrow from my quiver"
end
}
get_arrow is a variable and it is being assigned to a procedure (or method if you prefer that term).
the |num| syntax means that the first variable passed to the call of that procedure will be stored in the variable num. If the syntax were changed to |num, containerName| then the call to get_arrow could change to get_arrow.call(2, "quiver") and the code would read
get_arrow = proc{|num, containerName|
until GameObj.right_hand.noun == 'arrow'
fput "get #{num} my arrow from my #{containerName}"
end
}
Here is a super simple script to demonstrate
test = proc{|var|
echo "Hello"
echo "I will show the var now: #{var}"
}
echo script.vars.inspect
if script.vars.length>1
arg = script.vars[1]
test.call(arg)
else
test.call("You didn't pass any script arguments, the length was #{script.vars.length}")
end
Try calling the script like this ;test message
then try
;test
then try ;test arg1 arg2 arg3 arg4
Hopefully that helps a little and/or leads to more questions.
boardergeek
07-28-2011, 04:28 AM
Got it. Might not be the most efficient way, but it works. Made the 1 and 2 into strings, i.e. get_arrow.call(num = '2') and then inserted that into the command as fput 'get ' + num + ' arrow from my quiver'
There is the problem. You are using single quotes which doesn't allow for the use of variables in the string. Also, the num = '2' in you call isn't doing what you think it is. The return of any var = value statement is the value. If you changed your line to get_arrow.call(akdpoakdpoakpkapokds = '2') it would still work because the proc still received '2' as the value passed into the call and assigns it the proc's num variable.
To demonstrate what I mean. Try this, don't change any of your code but add three lines
num = '45'
echo num
get_arrow.call(num = '2') #this is your line that already exists
echo num
If you run this, you will notice that the local value num that you set to '45' was changed to '2' because you set num = '2' and when you did that it returned the value being set.
For example
echo num = '345'
echo num == '345'
Will print
345
true
KausticUSMC
07-28-2011, 04:33 AM
^^^^ Vital point I was missing: There's a difference between 'string' and "string". I didn't realize that it actually mattered whether I use ' or " to make my strings. This actually explains why in the world none of my script defined @variables were working when I put #{@variable} in the string.
Learning has occurred.
KausticUSMC
07-28-2011, 04:50 AM
Oh, and yeah, there's a big ol portion of my helpful little (ok, not so little) Ruby book that's all about classes, and I haven't even glanced at it yet. However, there was only one script where I actually used them, and it wasn't my own, but instead was one I downloaded and modified to better fit my purposes. The class was probably created somewhere in the jargon at the top of the script that I never dared play with since I didn't yet understand it and I was afraid of breaking the script.
KausticUSMC
07-29-2011, 03:22 AM
Ok, so for those interested, here's what I wound up with when it was all said and done. Thanks to Gibreficul for giving me the foundation for this, this entire thing is essentially the code he provided a page ago, modified to exclude dead critters from the counts, and to also include checks to make sure I stay standing and hidden (thanks also to Gibreficul again for teaching me a few things about Ruby, including how to make the very modifications I just mentioned).
It will use mfire as long as it has the stamina to do so, even if it's against a single target (though it will multi-target if there are two or more critters to shoot at), and switch to single shots when stamina falls too low to continue mfiring. It won't stop fighting until everything is dead (I did not include a health or wound check since this is intended to be used when I'm sitting right there, and I can easily stop it and take over if things go wrong). The last thing it will do before it ends is fire up SLOOT3 to skin and loot whatever you killed. If you don't have SLOOT3 or simply prefer not to use it, then just leave out that last line.
get_arrow = proc{|num|
until GameObj.right_hand.noun =~ /arrow/i
fput "get #{num} my arrow from my quiver"
end
}
fire = proc{
if GameObj.npcs.find_all{|npc| npc.status !~ /dead/}.length >= 2 && checkstamina(18) && hidden? && standing?
get_arrow.call(2)
fput 'stance off' if percentstance > 0
fput 'cman mfire'
waitrt?
elsif GameObj.npcs.find_all{|npc| npc.status !~ /dead/}.length = 1 && checkstamina(25) && hidden? && standing?
target = GameObj.npcs.find{|npc| npc.status !~ /dead/}.id
get_arrow.call(2)
fput 'stance off' if percentstance > 0
fput "cman mfire ##{target}"
waitrt?
elsif GameObj.npcs.find_all{|npc| npc.status !~ /dead/}.length = 1 && checkstamina < 25 && hidden? && standing?
get_arrow.call(1)
fput 'stance off' if percentstance > 0
fput 'fire'
waitrt?
end
fput 'stance def' if percentstance < 100
}
while GameObj.npcs.find_all{|npc| npc.status !~ /dead/}.length > 0
if !standing?
fput 'stand'
waitrt?
end
if !hidden?
fput 'hide'
waitrt?
end
fire.call
end
if GameObj.right_hand.noun =~ /arrow/i
fput 'put my arr in arr in my qui'
end
start_script 'loot'
EDIT 1: Added a fix that was causing the script to use non-targeted mfires against single targets (which of course doesn't work). Now it plucks the ID of the target if there's only 1, and specifically targets that ID for the directed mfire.
Gibreficul
07-29-2011, 04:45 AM
Gibreficul is an asshole and would not provide such help.
:wasntme:
(seriously, ruining my reputation man.) LOL
:club:
KausticUSMC
07-29-2011, 08:13 AM
I stand corrected, it was an imposter wearing a guy fawkes mask that I somehow mistook for Gibreficul. o-o
KausticUSMC
08-04-2011, 02:05 AM
Ok, here's an update. I've made a lot of adjustments and improvements to my script from the one posted above, and right now my latest little project is to add a function where I can include a variable in the launch command and the script will focus entirely on that variable as it's target. I want it to ignore all other possible targets in the room, and you'll notice I also included code that will allow this method to be used to target pc's as well as specific npc's.
I'm having trouble figuring out exactly how to write it, though, to make it find the specific target I want while also excluding that same target if it's already dead (thus reducing .length to 0 once the target is dead and ending the script). Here's what I've got right now. I'll bold the lines where lich reports errors, and also put the error there in bold italics. Those of you more experienced than I will probably see right away what I'm doing wrong, so please let me know. I'm fiddling with something I don't yet fully understand, so it's probably something very simple. All the errors are at the very end of the script.
get_arrow = proc{|num|
until GameObj.right_hand.noun =~ /arrow/i
fput "get #{num} my arrow from my quiver"
end
}
checkfire = proc{
if !standing?
fput 'stance def' if percentstance < 100
fput 'stand'
waitrt?
end
if GameObj.npcs.find_all{|npc| npc.status =~ /dead/}.length > 0
if GameObj.right_hand.noun =~ /arrow/i
fput 'put my arr in arr in my qui'
end
start_script 'loot'
wait_while {running? 'loot'}
waitrt?
end
if !Spell[9603].active? and Spell[9603].affordable? and !Spell[9604].active?
waitrt?
waitcastrt?
Spell[9603].cast
end
if !hidden?
fput 'stance def' if percentstance < 100
fput 'hide'
waitrt?
end
fire.call
}
fire = proc{
unless !hidden? or !standing?
if variable[0]
target = variable[0]
if GameObj.npcs.find_all{|npc| npc.status !~ /dead/}.noun =~ /#{target}/i or GameObj.pcs.find_all{|pc| pc.status !~ /dead/}.noun =~ /#{target}/i
if checkstamina(25) and hidden? and standing?
get_arrow.call(2)
fput 'stance off' if percentstance > 0
fput "cman mfire #{target}"
waitrt?
elsif hidden? and standing?
get_arrow.call(1)
fput 'stance off' if percentstance > 0
fput "fire #{target}"
waitrt?
end
end
else
target = GameObj.npcs.find{|npc| npc.status !~ /dead/}.id
if GameObj.npcs.find_all{|npc| npc.status !~ /dead/}.length >= 2 and checkstamina(18)
get_arrow.call(2)
fput 'stance off' if percentstance > 0
fput 'cman mfire'
waitrt?
elsif GameObj.npcs.find_all{|npc| npc.status !~ /dead/}.length = 1 and checkstamina(25)
get_arrow.call(2)
fput 'stance off' if percentstance > 0
fput "cman mfire ##{target}"
waitrt?
else
get_arrow.call(1)
fput 'stance off' if percentstance > 0
fput "fire ##{target}"
waitrt?
end
end
end
}
if variable[0]
target = variable[0]
while GameObj.npcs.find{|npc| npc.status !~ /dead/}{|npc| npc.noun == /#{target}/i}.length > 0 or GameObj.pcs.find{|pc| pc.status !~ /dead/}{|pc| pc.noun == /#{target}/i}.length > 0
#fight:75: syntax error, unexpected '{', expecting kDO_COND or ':' or '\n' or ';'
#...d{|npc| npc.status !~ /dead/}{|npc| npc.noun == /#{target}/i...
#fight:75: syntax error, unexpected '}', expecting kEND
#...npc| npc.noun == /#{target}/i}.length > 0 or GameObj.pcs.fin...
#fight:75: syntax error, unexpected '}', expecting kEND
#...npc| npc.noun == /#{target}/i}.length > 0 or GameObj.pcs.fin...
#fight:75: syntax error, unexpected '}', expecting kEND
#...npc| npc.noun == /#{target}/i}.length > 0 or GameObj.pcs.fin...
checkfire.call
end
else
#fight:78: syntax error, unexpected kELSE, expecting $end
#fight:78:in `create_block'
while GameObj.npcs.find_all{|npc| npc.status !~ /dead/}.length > 0
checkfire.call
end
end
if GameObj.right_hand.noun =~ /arrow/i
fput 'put my arr in arr in my qui'
end
start_script 'loot'
Note that for that last one, which I thought was obvious from the error, I tried changing ELSE to END and simply starting a new IF for the second portion (since the second IF would run if the conditions of the first IF weren't met) I was answered with the same error, only it said "unexpected kEND, expecting $end". I don't understand that. A different kind of end? As to the others, I see the unexpected item and the things it says it was expecting in it's place, but I've never used : and ; and the rest and I'm not sure what their functions are, or where/how to use them. Please help, oh codemasters.
Joseph
08-04-2011, 02:54 AM
while GameObj.npcs.find{|npc| npc.status !~ /dead/}{|npc| npc.noun == /#{target}/i}.length > 0 or GameObj.pcs.find{|pc| pc.status !~ /dead/}{|pc| pc.noun == /#{target}/i}.length > 0
#fight:75: syntax error, unexpected '{', expecting kDO_COND or ':' or '\n' or ';'
#...d{|npc| npc.status !~ /dead/}{|npc| npc.noun == /#{target}/i...
#fight:75: syntax error, unexpected '}', expecting kEND
#...npc| npc.noun == /#{target}/i}.length > 0 or GameObj.pcs.fin...
#fight:75: syntax error, unexpected '}', expecting kEND
#...npc| npc.noun == /#{target}/i}.length > 0 or GameObj.pcs.fin...
#fight:75: syntax error, unexpected '}', expecting kEND
#...npc| npc.noun == /#{target}/i}.length > 0 or GameObj.pcs.fin...
Unless I am missing some syntax rule that allows you to be completely lazy you need to be more careful in your while conditioning... I would do something like.
while GameObj.npcs.find{|npc| npc.status !~ /dead/ && npc.noun =~ /#{target}/i}.length > 0 or GameObj.pcs.find{|pc| pc.status !~ /dead/ && pc.noun =~ /#{target}/i}.length > 0
KausticUSMC
08-04-2011, 02:57 AM
*facepalm* I can't believe I didn't think of just sticking an AND in the hash.
*jumps on his failboat and fails away into the sunset*
Joseph
08-04-2011, 03:12 AM
if GameObj.npcs.find_all{|npc| npc.status =~ /dead/}.length > 0
here you are checking only to see if all of the npcs are dead but in your variable check you can select pcs or npcs.. this will ignore any pc targets and go on to lewting.
get_arrow = proc{|num| until GameObj.right_hand.noun =~ /arrow/i fput "get #{num} my arrow from my quiver" end }
This could get a bit spammy.. I would suggest making it a put and using regex to capture the possible responses from trying to get an arrow.
here is a quick example that should give you an idea of what I am talking about..
until GameObj.left_hand.noun == 'dagger'
waitrt?
put "take dagger from my trous"
get_dis_reg = Regexp.new(["\.\.\.wait",
"You need a free hand to pick that up",
"You remove a",
"Get what",].join('|'), "i")
get_dis_result = matchwait(/#{get_dis_reg}/)
if get_dis_result =~ /(\.\.\.wait|You need a free hand to pick that up.)|Get what|You remove a/
if get_dis_result =~ /You need a free hand to pick that up\./
locksmither_stow_left
elsif get_dis_result =~ /\.\.\.wait ([d]+) second(|s)\./
sleep $1.to_i
elsif get_dis_result =~ /Get what\?/
respond "Type \"GTG\" when your dagger is in place"
waitfor "GTG"
elsif get_dis_result =~ /You remove a/
sleep 0.1
end
end
end
but considering yours is a hunting script you will need to consider things like stun, web, bind etc.. I think waggle will have good messaging for those things unless it was heavily changed after I stopped doing the updates for it.
DaCapn
08-04-2011, 03:12 AM
It looks like by this:
GameObj.npcs.find{|npc| npc.status !~ /dead/}{|npc| npc.noun == /#{target}/i}.length > 0
You meant something more like this:
GameObj.npcs.find_all{|npc| npc.status !~ /dead/ and npc.noun =~ /#{target}/i}.length > 0
When you passed the iterator a second block it was all like "whaaaaat? I was expecting a kDO_COND." And then later, when you tried to throw out a kELSE the interpreter went "good sir, surely you do not expect me to kELSE within a block which does not contain an if!"
As a side note, I wish the code tag inserted line numbers.
KausticUSMC
08-04-2011, 03:48 AM
if GameObj.npcs.find_all{|npc| npc.status =~ /dead/}.length > 0
here you are checking only to see if all of the npcs are dead but in your variable check you can select pcs or npcs.. this will ignore any pc targets and go on to lewting.
Only if there's a dead NPC in the room. If I set a PC as the target then that would only happen if he or someone else happens to kill an NPC while I'm fighting him. Not that that scenario is impossible. It might be worth including an (UNLESS GameObj.pcs.find_all{|pc| pc.status !~ /dead/ and pc.noun = "{#target}"}) in there so that it will skip looting if I've specified a PC target, but still loot if the dead NPC WAS my specific target.
[code]get_arrow = proc{|num| until GameObj.right_hand.noun =~ /arrow/i fput "get #{num} my arrow from my quiver" end }
This could get a bit spammy.. I would suggest making it a put and using regex to capture the possible responses from trying to get an arrow.
True. I'll add an (IF GameObj.right_hand.empty) there to ensure it doesn't try getting arrows while my hands are full. I think that's the right way to write it. That or (IF GameObj.right_hand.noun =~ /empty/). And I think a simple waitfor will be enough to ensure it doesn't spam in the highly unlikely event that I run out of arrows. I don't AFK hunt, so it's fine if the script hangs when I run out of arrows or get my right hand severed or something. I can take over manually if that happens.
[CODE]but considering yours is a hunting script you will need to consider things like stun, web, bind etc.. I think waggle will have good messaging for those things unless it was heavily changed after I stopped doing the updates for it.
I'll have a look there. I see no point including checks to see if I myself am webbed or stunned, since my character currently has no skills he can use in those situations and using only fput ensures that the moment it wears off the script will resume. I do however plan to include checks to see if any targets are stunned or webbed or anything else that would make them vulnerable, and then prioritize them over other targets. Right now, if the script isn't targeted and there are multiple NPCs in the room, it chooses a random target every cycle, so it often floors/stuns a target and then fires at a different target the next cycle, missing the opportunity to take advantage.
So far it hasn't been much of a problem, but that's on my to-do list, along with an injury check that will flee to a safe room and run useherbs if I get anything more than a lvl 1 injury. I'm trying to focus on one thing at a time and take this in babysteps. I'm a n00b to Ruby and Lich, as I'm sure you've probably guessed. I'm still learning, so I'm focusing on one adjustment at a time, and only moving on once that adjustment works the way I want it to.
KausticUSMC
08-04-2011, 04:14 AM
It accepts targets the way I want it to now (thank you Joseph and DaCapn), however, after it kills the specified target, if there are NPCs in the room (even ones that don't match the target variable) it will continue to cycle... yet still trying to target the variable, which is no longer in the room, thus spamming a failure mesage when the game doesn't find the target. I thought I had it coded right so that, if there was a specified target, it would only begin a cycle while there was a target in the room who matched the target variable. Not sure where I went wrong, there.
get_arrow = proc{|num|
if GameObj.right_hand.noun !~ /arrow/i
until GameObj.right_hand.noun =~ /arrow/i
fput "get #{num} my arrow from my quiver"
waitfor 'remove'
end
end
}
fire = proc{
unless !hidden? or !standing?
if variable[0]
target = variable[0]
if GameObj.npcs.find_all{|npc| npc.status !~ /dead/}.noun = "#{target}" or GameObj.pcs.find_all{|pc| pc.status !~ /dead/}.noun = "#{target}"
if checkstamina(25) and hidden? and standing?
get_arrow.call(2)
fput 'stance off' if percentstance > 0
fput "cman mfire #{target}"
waitrt?
elsif hidden? and standing?
get_arrow.call(1)
fput 'stance off' if percentstance > 0
fput "fire #{target}"
waitrt?
end
end
else
target = GameObj.npcs.find{|npc| npc.status !~ /dead/}.id
if GameObj.npcs.find_all{|npc| npc.status !~ /dead/}.length >= 2 and checkstamina(18)
get_arrow.call(2)
fput 'stance off' if percentstance > 0
fput 'cman mfire'
waitrt?
elsif GameObj.npcs.find_all{|npc| npc.status !~ /dead/}.length = 1 and checkstamina(25)
get_arrow.call(2)
fput 'stance off' if percentstance > 0
fput "cman mfire ##{target}"
waitrt?
else
get_arrow.call(1)
fput 'stance off' if percentstance > 0
fput "fire ##{target}"
waitrt?
end
end
end
}
ready = proc{
if !standing?
fput 'stance def' if percentstance < 100
fput 'stand'
waitrt?
end
if GameObj.npcs.find_all{|npc| npc.status =~ /dead/}.length > 0 and !GameObj.pcs.find_all{|pc| pc.status !~ /dead/ and pc.noun = "{#target}"}
if GameObj.right_hand.noun =~ /arrow/i
fput 'put my arr in arr in my qui'
end
start_script 'loot'
wait_while {running? 'loot'}
waitrt?
end
if !Spell[9603].active? and Spell[9603].affordable? and !Spell[9604].active?
waitrt?
waitcastrt?
Spell[9603].cast
end
if !hidden?
fput 'stance def' if percentstance < 100
fput 'hide'
waitrt?
end
fire.call
}
if variable[0]
target = variable[0]
while GameObj.npcs.find_all{|npc| npc.status !~ /dead/ and npc.noun = "#{target}"}.length > 0 or GameObj.pcs.find{|pc| pc.status !~ /dead/ and pc.noun =~ /#{target}/i}.length > 0
ready.call
end
else
while GameObj.npcs.find_all{|npc| npc.status !~ /dead/}.length > 0
ready.call
end
end
if GameObj.right_hand.noun =~ /arrow/i
fput 'put my arr in arr in my qui'
end
start_script 'loot'
Joseph
08-04-2011, 05:58 AM
if GameObj.npcs.find_all{|npc| npc.status !~ /dead/}.noun = "#{target}" or GameObj.pcs.find_all{|pc| pc.status !~ /dead/}.noun = "#{target}"
== vs =
KausticUSMC
08-04-2011, 08:30 AM
Sorry to be the annoying noob with the questions, but could you tell me the difference between them? So I know how to use them properly in the future.
Joseph
08-04-2011, 09:47 AM
= is a designation
== is a comparison
DaCapn
08-04-2011, 12:17 PM
if GameObj.npcs.find_all{|npc| npc.status !~ /dead/}.noun = "#{target}" or GameObj.pcs.find_all{|pc| pc.status !~ /dead/}.noun = "#{target}"
Beyond switching to a comparator, find_all returns an array, right? Find will return the first match which will have a noun.
KausticUSMC
08-04-2011, 05:04 PM
Thank you both for helping me out. I know my questions and mistakes are utterly amateur, so thanks for being patient with me and not telling me to just google it. It's SO helpful to just be able to ask people who know, rather than try to find it in a book when you're not even sure what you're looking for.
DaCapn
08-04-2011, 08:29 PM
Thank you both for helping me out. I know my questions and mistakes are utterly amateur, so thanks for being patient with me and not telling me to just google it. It's SO helpful to just be able to ask people who know, rather than try to find it in a book when you're not even sure what you're looking for.
Start learning off of syntax that you know to work. Learn new syntax from examples. Some of your mistakes seem to be due to ambitiously throwing something out there that doesn't resemble syntax you've used in the past. Pushing a learning curve too hard will just slow you down in the long run.
KausticUSMC
08-05-2011, 02:49 AM
Ambitious is right. I tend to say to myself "Alright... GameObj is basically god. I can ask it anything, and as long as I figure out how to write the question correctly, it will answer it. SO... let's try asking it like THIS!! No? Ok, how about this? No. This? YES!!!" Or else getting to the point where I go "That looks like it should work, but it doesn't. Lemme ask somebody."
KausticUSMC
08-05-2011, 06:47 AM
BLUF (Bottom Line Up Front):
I want to know how to make the script check for stunned, crippled or otherwise weakened critters so I can make it target them over others.
Long Version:
SO! Here we go again. My script is now fully targetable with no issues, given a target it will attack only that target and ignore all others, terminating when the target is dead even if other targets are present. Just like I wanted. I've also added a fully functional injury check that will flee to a room with no targets and run useherbs, and also added a line to useherbs that will continue fleeing to empty rooms if followed after the script has begun. No issues there either, works beautifully (Woot! Major upgrade made with no help from others! I'm learning. XD).
NOW, I want to adjust the targeting lines so that when the script is running free (i.e. unfocused, no target specified, just kill every NPC it sees) it will identify critters that are stunned/webbed/knocked down/etc and target them over other critters. Right now when the script isn't targeted, it randomly selects it's target every time the cycle refreshes, and so it often stuns/mangles one target and then fires at a different, still-healthy target on the next cycle, failing to take advantage of the opportunity to finish off the weakened critter.
I fished around in the lich.rbw file to see if I could figure out what the correct keywords were. I imagine in the end it will look something like this:
GameObj.npcs.find{|npc| npc.status =~ /stunned/ or npc.status =~ /webbed/ or npc.!standing?}
Of course that's wrong, though, and once again I'm not sure precisely what it is that I'm looking for here. I had hoped to find them in lich.rbw since this stuff is GemStone-specific and not universal so I won't find it in any reference or guide for Ruby. No dice though, that file is massive and without knowing what I'm looking for I can't hunt it down with find.
For reference (or for other archers who are copying this to use it for themselves - mind you, it uses SLOOT3 (which I renamed loot) and USEHERBS (which I renamed heal) to run properly - here's the full script as it stands currently:
silence_me
get_arrow = proc{|num|
if GameObj.right_hand.noun !~ /arrow/i
until GameObj.right_hand.noun =~ /arrow/i
fput "get #{num} my arrow from my quiver"
waitfor 'remove'
end
end
}
fire = proc{
unless !hidden? or !standing?
if variable[0]
target = variable[0]
if GameObj.npcs.find{|npc| npc.status !~ /dead/}.noun == "#{target}" or GameObj.pcs.find{|pc| pc.status !~ /dead/}.noun == "#{target}"
if checkstamina(25) and hidden? and standing? and !Spell[9699].active?
get_arrow.call(2)
fput 'stance off' if percentstance > 0
fput "cman mfire #{target}"
waitrt?
elsif hidden? and standing?
get_arrow.call(1)
fput 'stance off' if percentstance > 0
fput "fire #{target}"
waitrt?
end
end
else
target = GameObj.npcs.find{|npc| npc.status !~ /dead/}.id
if GameObj.npcs.find_all{|npc| npc.status !~ /dead/}.length >= 2 and checkstamina(18) and !Spell[9699].active?
get_arrow.call(2)
fput 'stance off' if percentstance > 0
fput 'cman mfire'
waitrt?
elsif GameObj.npcs.find_all{|npc| npc.status !~ /dead/}.length = 1 and checkstamina(25) and !Spell[9699].active?
get_arrow.call(2)
fput 'stance off' if percentstance > 0
fput "cman mfire ##{target}"
waitrt?
else
get_arrow.call(1)
fput 'stance off' if percentstance > 0
fput "fire ##{target}"
waitrt?
end
end
end
}
ready = proc{
if !standing?
fput 'stance def' if percentstance < 100
fput 'stand'
waitrt?
end
if [Wounds.head, Wounds.neck, Wounds.torso, Wounds.limbs, Wounds.nerves, Scars.head, Scars.neck, Scars.torso, Scars.limbs, Scars.nerves].max > 1 or bleeding?
fput 'stance def' if percentstance < 100
startroom = Room.current
while GameObj.npcs.find_all{|npc| npc.status !~ /dead/}.length > 0 or GameObj.pcs.find{|pc| pc.status !~ /dead/ and pc.noun == "{target}"}
move checkpaths[rand(checkpaths.length)]
end
start_script 'heal'
wait_while {running? 'heal'}
unless Room.current == startroom
start_script('go2', [startroom.id])
wait_while {running? 'go2'}
end
end
if GameObj.npcs.find_all{|npc| npc.status =~ /dead/}.length > 0 and !GameObj.pcs.find{|pc| pc.status !~ /dead/ and pc.noun == "{#target}"}
fput 'stance def' if percentstance < 100
fput 'put my arr in arr in my qui' if GameObj.right_hand.noun =~ /arrow/i
start_script 'loot'
wait_while {running? 'loot'}
waitrt?
end
if !Spell[9603].active? and Spell[9603].affordable? and !Spell[9604].active? and !Spell[9699].active?
waitrt?
waitcastrt?
Spell[9603].cast
end
if !hidden?
fput 'stance def' if percentstance < 100
fput 'hide'
waitrt?
end
fire.call
}
if variable[0]
target = variable[0]
while GameObj.npcs.find_all{|npc| npc.status !~ /dead/ and npc.noun == "#{target}"}.length > 0 or GameObj.pcs.find_all{|pc| pc.status !~ /dead/ and pc.noun == "#{target}"}.length > 0
ready.call
end
else
while GameObj.npcs.find_all{|npc| npc.status !~ /dead/}.length > 0
ready.call
end
end
fput 'put my arr in arr in my qui' if GameObj.right_hand.noun =~ /arrow/i
start_script 'loot'
Joseph
08-05-2011, 08:52 AM
npc.!standing?}
Ok it has been a few years since I had lich on my computer.. but is this real or something you made up? Just out of curiosity?
KausticUSMC
08-05-2011, 09:57 AM
Made up. A wild guess as to what it might kinda sorta possibly look like.
DaCapn
08-05-2011, 10:04 AM
Ok it has been a few years since I had lich on my computer.. but is this real or something you made up? Just out of curiosity?
He made it up.
Here's a snippet from one of my scripts. It's a little convoluted and not suited to your problem (my script checks to make sure there's less than n creatures of a certain type then sees if one of the specified type is stunned) but it may give you some ideas.
hindered=["prone","stunned","sitting","kneeling"]
if !hindered.include?(GameObj.npcs[checknpcs.index("#{creature}")].status) then ...
Just to dissect it a bit: It has an array of npcs with checknpcs, then if finds the index of the npc that matches my creature type. It has the same index in GameObj.npcs so we use that to find the status of the creature. Then we see if the hindered array does not include that status message. For example, that whole statement would return true if the creature had status "dead" (EDIT: but clearly, the point is to return true and do something if the creature is standing and in good enough shape to attack).
Cramming things together haphazardly is, once again, not the way to solve your problem. You'll notice that `!standing?` has never ever been used like you used it. standing?, bleeding?, kneeling?, etc all report back the status of your character. It's not a method that you can apply to some other object.
KausticUSMC
08-05-2011, 10:17 AM
Oh, I didn't actually attempt to use that, as I said it was a wild guess based off of very limited knowledge, to include not knowing that the same things that check my character can't be applied to check npcs. Just a wild guess to give an idea of what it was I was trying to accomplish. I knew full well it was probably wrong, hence why I didn't bother trying to actually use it, but I knew you guys would look at it and, wrong or not, you'd know what I was trying to do. So it served it's purpose.
Thanks for the idea of creating my own array and showing me how to run it against the npc status for comparison. I can easily adjust that to accomplish what I'm trying to do.
Joseph
08-05-2011, 10:41 AM
My best advice after seeing the types of problems you are having would be to read the gameObj section of lich.rb.. or better yet the entirety of lich.rb.. I did that so many time that it wasn't even funny.
KausticUSMC
08-05-2011, 11:02 AM
Probably. Most of what I've already learned, I learned by going into other scripts that do similar things to what I want and seeing how they do it. I've tried looking at the lich.rbw file before, searching it to see if I could better understanding the ways it interacts with the game, but I never actually read through it. I just used find to try and find what I wanted to learn more about. Perhaps I'll just find GameObj and read that section. Reading the entire thing, though, would probably just confuse me. I'll see what I think of it after I've read the GameObj portion.
pabstblueribbon
08-05-2011, 11:31 AM
This was part of my hunting script before I started hacking Bigshot. It uses definitions instead of procs ( I was converting it but then decided fuck it and started hacking Bigshot instead ). It used crosscharcom to talk between characters and set global variables so that they could work together. Had a rubber-banding feature which later inspired the much better coded one in bigshot :p.
Anyways, maybe you can find something in there thats useful. I learned by looking at other scripts.
$need_haste = false
$can_we_move = false
$do_not_attack = true
$hider = false
$rally_point = 3730
$rest_locations = ["14627","8684", "8688", "8723", "4086", "13500", "14680", "17793", "7519", "8683", "13480", "7542", "7523"]
$hunt_critters = ["troll","giant"]
$debug = true
$gahrkan_ready = false
$hunting = false
$gahrkan_ready = false
$gahrkan_needs_healed = false
$grouped = false
Watchfor.new ("whispers,"){$hider = true}
Watchfor.new ("You hear someone mutter"){$hider = true}
Watchfor.new ("leaps from hiding"){$hider = true}
Watchfor.new ("You hear someone cough."){$hider = true}
Watchfor.new ("The voice of"){$hider = true}
fput "disband"
def group_party
if $debug == true then echo 'group_party' end
if checkpcs("Gahrkan") and $grouped == false
fput "hold gahrkan"
$grouped = true
hunting
hunt
end
end
def find_party
if $debug == true then echo 'find_party' end
if checkpcs("Gahrkan") == nil
$grouped = false
start_script 'go2', [ $rally_point, '_disable_confirm_' ] if Room.current.id != $rally_point
wait_while { running?('go2') }
while checkpcs("Gahrkan") == nil
checkpcs
stand
sleep 1
if $gahrkan_needs_healed == true
break
end
end
end
group_party
end
if !running?('crosscharcom')
start_script 'crosscharcom'
sleep 4
end
unique_send_to_script 'crosscharcom', ["gahrkan exec start_script 'ghunt'"]
def can_we_move
if $debug == true then echo 'Waiting to move' end
if checkpcs("Gahrkan")
until $can_we_move == true
stand
unstun
sleep 1
end
elsif checkpcs("Gahrkan") == nil
find_party
end
end
def do_not_attack
if $do_not_attack != true
unique_send_to_script 'crosscharcom', ["gahrkan exec $do_not_attack = true"]
$do_not_attack = true
if $debug == true then echo 'Do not attack proc' end
end
end
def attack
if $do_not_attack == true
unique_send_to_script 'crosscharcom', ["gahrkan exec $do_not_attack = false"]
$do_not_attack = false
if $debug == true then echo 'Attack proc' end
end
end
def resting
if $resting == false
$resting = true
unique_send_to_script 'crosscharcom', ["gahrkan exec $resting = true"]
if $debug == true then echo 'Resting proc' end
end
end
def stop_resting
if $resting == true
unique_send_to_script 'crosscharcom', ["gahrkan exec $resting = false"]
$resting = false
end
end
def hunting
if $hunting == false
$hunting = true
unique_send_to_script 'crosscharcom', ["gahrkan exec $hunting = true"]
if $debug == true then echo 'Hunting proc' end
end
end
def stop_hunting
if $hunting == true
unique_send_to_script 'crosscharcom', ["gahrkan exec $hunting = false"]
$hunting = false
end
end
def need_haste
if checkspell(506)
$need_haste = false
else
$need_haste = true
end
if !checkspell(506) and $need_haste != false
unique_send_to_script 'crosscharcom', ["gahrkan exec $need_haste = true"]
end
if $debug == true then echo 'Need_haste proc' end
end
def heal
if [Wounds.head, Wounds.neck, Wounds.torso, Wounds.limbs, Wounds.nerves, Scars.head, Scars.neck, Scars.torso, Scars.limbs, Scars.nerves].max > 1
start_script 'herbheal'
wait_while { running?('herbheal') }
go_home
end
if $debug == true then echo 'Heal proc' end
end
def unstun
if $debug == true then echo 'Unstun proc' end
if stunned? and checkmana(40)
fput "beseech"
end
stunned = RoomObj.pcs.find { |pc| pc.status == "stunned" and pc.noun == "Gahrkan" }
if stunned != nil and checkmana(8)
waitrt?
waitcastrt?
fput "prep 108"
if checkprep =~ /Stun Relief/
fput "cast #{stunned.noun}"
end
end
end
def stand
until Char.standing?
waitrt?
fput "stand"
sleep 0.5
end
# pullup = GameObj.pcs.find { |pc| pc.status =~ /lying down/ and pc.noun == "Gahrkan"}
# if pullup != nil
# waitrt?
# fput "pull #{pullup}"
# end
if $debug == true then echo 'Stand proc' end
end
def stance
if checkstance != "advance"
fput "stance advance"
end
end
def loot
if RoomObj.npcs.find { |npc| npc.status == 'dead'}
start_script 'bloot'
wait_while { running?('bloot')}
end
end
def attack_routine
while target = GameObj.npcs.find { |npc| npc.status != 'dead' and npc.name =~ /#{$hunt_critters.join('|')}/ } and $hider == false
waitrt?
waitcastrt?
unstun
stand
need_haste
stance
fput "attack ##{target.id}"
if matchtimeout(1,"You currently have no valid target|What were you referring to?") and !checknpcs
do_not_attack
loot
can_we_move
wander
break
end
end
loot
end
def sell_routine
start_script 'bsell'
wait_while { running?('bsell')}
end
def wander
if $debug == true then echo 'Wander proc' end
stand
bad_rooms = ['3566', '3839', '3789','3575', '3576']
$wander_last_room ||= nil
room = Room.current
next_room_options = room.wayto.keys - bad_rooms
if next_room_options.length > 1
next_room_options.delete_if { |option| option == $wander_last_room }
end
next_room = next_room_options[rand(next_room_options.length)]
way = room.wayto[next_room]
if way.class == String
move(way)
else
way
end
$wander_last_room = room.id.to_s
end
def set_home
$home = $rest_locations[rand($rest_locations.length)]
unique_send_to_script 'crosscharcom', ["gahrkan exec $home = #{$home}"]
end
def go_home
if $debug == true then echo 'def go_home' end
start_script 'go2', [ $home, '_disable_confirm_' ]
wait_while { running?('go2') }
end
def locksmith
start_script 'npcpick'
wait_while { running?('npcpick') }
end
def go_bank
start_script 'go2', [ 'bank', '_disable_confirm_' ]
wait_while { running?('go2') }
fput "deposit all"
end
def hunt
until (checkmind(7) and $gahrkan_fried == true) or dead? or $encumbrance_value >= 20 or [Wounds.head, Wounds.neck, Wounds.torso, Wounds.limbs, Wounds.nerves, Scars.head, Scars.neck, Scars.torso, Scars.limbs, Scars.nerves].max > 1 or $gahrkan_needs_healed == true
find_party
can_we_move
wander
if !(checkpcs.to_a - ["Gahrkan"]).empty? or GameObj.loot.any? { |obj| obj.noun == 'disk' and obj.name !~ /Gahrkan|Baerden/ } or RoomObj.npcs.find { |npc| npc.status == 'dead' or npc.status == 'stunned'}
sleep 2
elsif checknpcs and GameObj.npcs.find { |npc| npc.status != 'dead' and npc.status != 'stunned' and npc.name =~/#{$hunt_critters.join('|')}/}
echo "what have we here?"
until !checknpcs or checknpcs.length > 3 or $hider == true
attack
attack_routine
end
do_not_attack
if $hider == true
$hider = false
end
end
end
fput "disband"
$grouped = false
do_not_attack
stop_hunting
set_home
locksmith
sell_routine
go_bank
rest
end
def rest
unique_send_to_script 'crosscharcom', ["gahrkan exec $baerden_ready = false"]
echo "**RESTING AND SPELLING UP**"
fput "put my maul in my bald"
heal
go_home
resting
start_script 'waggle'
wait_while { running?('waggle') }
wait_until { checkpcs("Gahrkan") }
start_script 'waggle', [ 'gahrkan' ]
wait_while { running?('waggle') }
until (checkmind(1) or checkmind(2) or checkmind(3)) and (!checkmind(4) and checkmana(50) and checkspirit (10) and $gahrkan_ready == true)
sleep 5
echo "waiting on mana, spirit, or gahrkan"
end
stand
fput "get my maul"
unique_send_to_script 'crosscharcom', ["gahrkan exec $baerden_ready = true"]
stop_resting
start_script 'go2', [ $rally_point, '_disable_confirm_' ]
wait_while { running?('go2') }
find_party
end
rest
KausticUSMC
08-06-2011, 03:50 AM
Think I got it. Haven't had a chance to see for certain that it works yet, if I see enough instances of it targeting a stunned/prone/whatever critter over others in the room without ever failing I'll come back and report it successful. Here's the code I used, tell me if it looks right to you guys:
if GameObj.npcs.find{|npc| npc.status =~ /stunned|webbed|prone|sitting|kneeling/}
target = GameObj.npcs.find{|npc| npc.status =~ /stunned|webbed|prone|sitting|kneeling/}.id
else
target = GameObj.npcs.find{|npc| npc.status !~ /dead/}.id
end
DaCapn
08-06-2011, 04:36 PM
Think I got it. Haven't had a chance to see for certain that it works yet, if I see enough instances of it targeting a stunned/prone/whatever critter over others in the room without ever failing I'll come back and report it successful. Here's the code I used, tell me if it looks right to you guys:
if GameObj.npcs.find{|npc| npc.status =~ /stunned|webbed|prone|sitting|kneeling/}
target = GameObj.npcs.find{|npc| npc.status =~ /stunned|webbed|prone|sitting|kneeling/}.id
else
target = GameObj.npcs.find{|npc| npc.status !~ /dead/}.id
end
You can't be asking for help every time you add two lines to your script. You haven't even tried it. This sort of behavior drives potential help away.
You don't need that specific event to trigger to test the syntax. Design a test and work it out.
KausticUSMC
08-07-2011, 09:25 AM
Sorry for the holdup, that worked but I've been adding and tweaking some other things as well and forgot to come back and say so. Been learning, ironically, to do exactly what I've now come back to find DaCapn suggesting - sending things to lich to make it trigger responses without needing to wait for those circumstances to occur naturally in game.
Been progressing smoothly, got a new check for undead critters that will switch to a seperate bundle of blessed arrows, and working on a piece that will attempt to garrote lone stragglers, but I'm snagged on something. I know npc.noun checks for, obviously, the key noun needed to target a critter, but is there something that checks the descriptors? I'm trying to find it in lich.rbw but I can't. I'm adding an element to the targeting section that will pick out grimswarm targets, so it'll be GameObj.npcs.find{|npc| npc.???? =~ /grimswarm/}.id. Anybody know?
Joseph
08-07-2011, 09:37 AM
Don't quote me on this but I believe that npc.name should work.. but if I were you I would do a ;e echo npc.methods
Joseph
08-07-2011, 09:38 AM
er make that gameObj.methods.. you know what I mean.
KausticUSMC
08-07-2011, 05:47 PM
Joseph, you just became my favorite person ever. The number one problem I keep having trying to figure out how to do something is just figuring out the correct name for the method I'm searching for, and trying to comb through lich.rbw to find it is a headache. Every time I'm in here, it's always to ask what the correct wordage is to write this check or that check. Now you tell me there's a method for echoing methods?!? THANK YOU!!!
I do believe you may have just terminated this thread. If I can look up methods that easily, then I know enough to figure out the rest from there as long as I don't try to do anything really complicated like GUI/GTK. Which I have no intention of even dabbling in unless I decide to actually go to college and study programming. It's enough for now to simply understand objects, methods, and regular expressions. Or at least understand them enough to make the script behave the way I want. It's early morning here and I have to be off to work, no time to log in, but if ;e echo npc.methods really does give a list of everything I could put after npc.____ then I think we're done here. I know enough about the language to figure out the rest on my own. (Yay, no more stupid n00b questions, right?)
KausticUSMC
08-07-2011, 05:48 PM
GameObj.methods would still be tremendously helpful. Will it work if I put GamoObj.npcs.methods? Bleh, I gotta go. I'll find out later. Thanks again!!
Joseph
08-07-2011, 08:42 PM
here is a copy paste from the ruby source docs that might help you.
mod.instance_methods(include_super=true) → array
(http://www.ruby-doc.org/core/classes/Module.src/M000480.html)
Returns an array containing the names of the public (http://www.ruby-doc.org/core/classes/Module.html#M000448) and protected (http://www.ruby-doc.org/core/classes/Module.html#M000449) instance methods in the receiver. For a module, these are the public (http://www.ruby-doc.org/core/classes/Module.html#M000448) and protected (http://www.ruby-doc.org/core/classes/Module.html#M000449) methods; for a class, they are the instance (not singleton) methods. With no argument, or with an argument that is false, the instance methods in mod are returned, otherwise the methods in mod and mod‘s superclasses are returned.
module A def method1() end end class B def method2() end end class C < B def method3() end end A.instance_methods #=> [:method1] B.instance_methods(false) #=> [:method2] C.instance_methods(false) #=> [:method3] C.instance_methods(true).length #=> 43
Powered by vBulletin® Version 4.2.5 Copyright © 2025 vBulletin Solutions Inc. All rights reserved.