Page 1 of 7 123 ... LastLast
Results 1 to 10 of 70

Thread: Learn how to script with this simple hunting script

  1. #1

    Default Learn how to script with this simple hunting script

    I've seen a lot of posts lately from people who are unable to get Bigshot working exactly the way they want it to and some people have expressed that they wish they knew how to code in Ruby so they can write their own scripts so I'm posting up this simple hunting script as a teaching exercise to those who want to learn more about coding in lich.

    Feel free to ask any questions about anything you don't understand. If you don't know much about coding in lich then one day you just might be able to write your very own custom hunting that does everything exactly the way you want it to do.

    Here is the script with a few features to get you started:

    Code:
    target_names = /kobold|squirrel|rolton/
    
    $my_target = GameObj.npcs.find{ |npc| npc.name =~ target_names && npc.type =~ /aggressive/ }
    
    
    if $my_target == nil
    	echo "No target found!"
    	exit
    end
    
    def this_script_hide_me
    	until hidden?
    		waitrt?
    		fput "hide"
    	end
    end
    
    def this_script_stand_me
    	until standing?
    		waitrt?
    		fput "stand"
    	end
    end
    
    def this_script_keep_haste
    	Spell[506].cast if (!Spell[506].active?) && (Spell[506].affordable?) && (Spell[506].known?)
    end
    
    def this_script_stun_target
    	Spell[505].cast($my_target) if (Spell[505].affordable?) && (Spell[505].known?) && ($my_target.status !~ /stun/)
    end
    
    def this_script_kill_target
    	Spell[901].cast($my_target) if (Spell[901].affordable?) && (Spell[901].known?)
    end
    
    def this_script_ambush_target
    	critter_needs_to_be_legged = true
    	waitrt?
    	if ($my_target.status =~ /prone|sit|lay|kneel|stun|sleep/i)
    		result = dothistimeout "ambush ##{$my_target.id} head", 2, /round(time)?|You cannot aim that high|does not have a/i
    		if result =~ /round(time)?/i
    			critter_needs_to_be_legged = nil
    		elsif result =~ /does not have a/
    			critter_needs_to_be_legged = nil
    			fput "attack ##{$my_target.id}"
    		elsif result =~ /You cannot aim that high/
    			nil
    		elsif result.nil?
    			nil
    		end
    	end				
    	if (critter_needs_to_be_legged)
    		result = dothistimeout "ambush ##{$my_target.id} left leg", 2, /round(time)?|does not have a/i
    		if result =~ /round(time)?/i
    			nil
    		elsif result =~ /does not have a/
    			fput "attack ##{$my_target.id}"
    		elsif result.nil?
    			fput "attack ##{$my_target.id}"
    		end
    	end
    end
    
    start_script "loot" if !running? "loot"
    
    loop{
    	break if ($my_target.status =~ /dead|gone/)
    	this_script_keep_haste
    	this_script_stand_me
    	this_script_stun_target
    	this_script_kill_target
    	sleep 1
    }
    
    if $my_target.status =~ /dead/
    	echo "Target dead!"
    	waitrt?
    	start_script "waitloot"
    	wait_while { running?('waitloot') }
    elsif $my_target.status =~ /gone/
    	echo "Target gone!"
    end
    Here is that same code with some information:

    Code:
    ###This is a regex where you put the names of critters you want the script to scan the current room for to kill.
    target_names = /kobold|squirrel|rolton/
    
    ###This tells the script to set the variable $my_target to any NPC in the room that matches the target_names above and that the NPC is also aggressive.
    $my_target = GameObj.npcs.find{ |npc| npc.name =~ target_names && npc.type =~ /aggressive/ }
    
    ###This tells the script to exit if no target was found.
    if $my_target == nil
    	echo "No target found!"
    	exit
    end
    
    ###This is a simple way to make sure your character keeps inputting HIDE until they are hidden. If this is run while you are already hidden then it will do nothing.
    def this_script_hide_me
    	until hidden?
    		waitrt?
    		fput "hide"
    	end
    end
    
    ###Same as the hide above except it makes sure you are standing before moving on.
    def this_script_stand_me
    	until standing?
    		waitrt?
    		fput "stand"
    	end
    end
    
    ###This checks to see if haste (506) is not active on your character, that your character has enough mana to cast 506, and that your character knows 506. If all of those are true it will cast 506 on yourself.
    def this_script_keep_haste
    	Spell[506].cast if (!Spell[506].active?) && (Spell[506].affordable?) && (Spell[506].known?)
    end
    
    ###This checks if your character has enough mana to cast Hand of Tonis (505) and that your character knows 505 and that your target is not already stunned. If all of those are true it will cast 505 on your target.
    def this_script_stun_target
    	Spell[505].cast($my_target) if (Spell[505].affordable?) && (Spell[505].known?) && ($my_target.status !~ /stun/)
    end
    
    ###Basically same as above except it doesn't check for stun status and this is checking for Minor Shock (901)
    def this_script_kill_target
    	Spell[901].cast($my_target) if (Spell[901].affordable?) && (Spell[901].known?)
    end
    
    ###This first sets the variable critter_needs_to_be_legged to true (which basically just means the variable has a value).
    ###Your character will then wait for any hard roundtime they are in, if they aren't in roundtime it will do nothing there.
    ###It will then check if your current target is prone, sitting, kneeling, or stunned, if any of that is true your character will then attempt to ambush the target's head.
    ###If your character ambushed the head the script sets critter_needs_to_be_legged to nil (which basically means the variable has no value) and moves on. 
    ###If your character cannot aim that high then the script moves on.
    ###If for some reason the critter doesn't have a head then the script set critter_needs_to_be_legged to nil and your character will just do a simple attack on the target.
    ###If the script does not see "roundtime", "you cannot aim that high" "does not have a" in a 2 second timeframe then the script simply moves on.
    ###If critter_needs_to_be_legged is set to true then your character will attempt to ambush the critter's left leg.
    ###If your character attacked the leg (and thus you see a "roundtime") then the script will move on.
    ###If your target does not have a leg then your character will do a simple attack on the target.
    ###If the script doesn't see "roundtime" or "does not have a" in a 2 second time frame then your character will do a simple attack on the target.
    def this_script_ambush_target
    	critter_needs_to_be_legged = true
    	waitrt?
    	if ($my_target.status =~ /prone|sit|lay|kneel|stun|sleep/i)
    		result = dothistimeout "ambush ##{$my_target.id} head", 2, /round(time)?|You cannot aim that high|does not have a/i
    		if result =~ /round(time)?/i
    			critter_needs_to_be_legged = nil
    		elsif result =~ /does not have a/
    			critter_needs_to_be_legged = nil
    			fput "attack ##{$my_target.id}"
    		elsif result =~ /You cannot aim that high/
    			nil
    		elsif result.nil?
    			nil
    		end
    	end				
    	if (critter_needs_to_be_legged)
    		result = dothistimeout "ambush ##{$my_target.id} left leg", 2, /round(time)?|does not have a/i
    		if result =~ /round(time)?/i
    			nil
    		elsif result =~ /does not have a/
    			fput "attack ##{$my_target.id}"
    		elsif result.nil?
    			fput "attack ##{$my_target.id}"
    		end
    	end
    end
    
    ###This tells the script to start the script "loot" if "loot" is not already running. You are running loot, right?
    start_script "loot" if !running? "loot"
    
    ###This is where the magic happens. This is where you tell the script what coommands you want it to do and when. If your target is dead or no longer in the room with you then the loop is broken and it moves to the bit of code beyond the loop.
    loop{
    	break if ($my_target.status =~ /dead|gone/)
    	this_script_keep_haste
    	this_script_stand_me
    	this_script_stun_target
    	this_script_kill_target
    	sleep 0.1
    }
    
    ###If your target is dead then the script will wait until you're out of roundtime if you're in it then it will start "waitloot" then it will wait until "waitloot" is done running. Once all of that is done the script exits.
    if $my_target.status =~ /dead/
    	echo "Target dead!"
    	waitrt?
    	start_script "waitloot"
    	wait_while { running?('waitloot') }
    ####This is if your target simply left before you could kill it. It just exits.
    elsif $my_target.status =~ /gone/
    	echo "Target gone!"
    end
    So here are some ways to setup the loop part of the script with what's already in the script.

    Code:
    loop{
    	break if ($my_target.status =~ /dead|gone/)
    	this_script_keep_haste
    	this_script_stand_me
    	this_script_stun_target
    	this_script_kill_target
    	sleep 0.1
    }
    This tells the script to run the keep haste part of the script, then it will run the stand me part, then it will run the stun target, then it will run kill target. It will keep doing this in this exact order over and over again until your target is dead or gone.

    Basically it will cast haste if your character needs it, it will then stand your character up if they are not already standing, it will then cast Hand of Tonis on your target if your target is not already stunned, then it will cast 901 on your target. Once it has done all of that the script will then check if your target is dead or gone, if it's not dead or gone it starts all over again.

    You could also do this:

    Code:
    loop{
    	break if ($my_target.status =~ /dead|gone/)
    	this_script_stand_me
    	this_script_hide_me
            this_script_ambush_target
    	sleep 0.1
    }
    This will make sure you're standing if you're not already standing, then it will hide you if you're not already hidden, then it will attempt to ambush your target's head if your target is not standing or stunned, if your target isn't prone or stunned or if you can't aim for its head then it will ambush your target's left leg. It will then repeat this process until your target is dead or gone.

    Feel free to ask any questions or if you want your script to do something else not already mentioned here.
    Last edited by Tgo01; 05-26-2015 at 08:14 PM.

  2. #2

    Default

    Other fun things you can do:

    Code:
    $my_weapon = "runestaff"
    Code:
    def this_script_get_my_weapon
    	if (GameObj.right_hand !~ /#{$my_weapon}/)
    		empty_right_hand
    		if (GameObj.left_hand =~ /#{$my_weapon}/)
    			fput "swap"
    		else
    			fput "get my #{$my_weapon}"
    		end
    	end
    end
    Run this method and if your weapon is in your right hand then it does nothing. If your weapon is not in your right hand it will stow whatever is in your right hand, then the script checks your left hand and if your weapon is in your left hand it will do "swap" otherwise it will get your weapon in case it's been stowed or what have you.
    Last edited by Tgo01; 05-25-2015 at 04:52 PM.

  3. #3
    Join Date
    Nov 2004
    Location
    on a street
    Posts
    9,574
    Blog Entries
    3

    Default

    So, how could I use this to run commands on other scripts. For example, if my weapon gets disarmed to ";send to crosschar wall|char1|char2 get weapon|incan 410"
    2013 PC FF Champion

    "Rules are rules and when Timmy sticks a battleaxe in your chest you have to sit down and count to 100." - Sera Blanche

    [PrivateTo]-GSIV:Vishra: "like I'd start off by making you wear this leather ball gag I have"
    [Private]-GSIV:Vishra: "you sound like my mother"

  4. #4

    Default

    Quote Originally Posted by WRoss View Post
    So, how could I use this to run commands on other scripts. For example, if my weapon gets disarmed to ";send to crosschar wall|char1|char2 get weapon|incan 410"
    Sorry I'm not sure I understand what you're asking.

    You're asking if you get disarmed on character A you want to send a command to the script crosschar of "wall|char1|char2 get weapon|incan 410"?
    Last edited by Tgo01; 05-25-2015 at 06:08 PM.

  5. #5

    Default

    Ok, you've inspired me to finally start working on my own personalized hunting script. I have a possibly tough one to start with. Pulling lines from the game and acting based on that info is one area that I never got too far into when I was teaching myself to write scripts.

    I'm a bard, and I want to use 1002 any and every time my target has a weapon or shield equipped. I assume the way to go about that would be to look at the target before every attack and check it through that somehow while squelching so that I don't have to see me looking before every attack.

  6. #6
    Join Date
    Nov 2004
    Location
    on a street
    Posts
    9,574
    Blog Entries
    3

    Default

    Quote Originally Posted by Tgo01 View Post
    Sorry I'm not sure I understand what you're asking.

    You're asking if you get disarmed on character A you want to send a command to the script crosschar of "wall|char1|char2 get weapon|incan 410"?
    Sort of.

    Char A gets disarmed and immediately sends "send to crosschar charB get weapon"
    2013 PC FF Champion

    "Rules are rules and when Timmy sticks a battleaxe in your chest you have to sit down and count to 100." - Sera Blanche

    [PrivateTo]-GSIV:Vishra: "like I'd start off by making you wear this leather ball gag I have"
    [Private]-GSIV:Vishra: "you sound like my mother"

  7. #7

    Default

    Quote Originally Posted by Tenlaar View Post
    I'm a bard, and I want to use 1002 any and every time my target has a weapon or shield equipped. I assume the way to go about that would be to look at the target before every attack and check it through that somehow while squelching so that I don't have to see me looking before every attack.
    Yeah I'm not aware of a way to see if a critter is holding a weapon or shield without looking at them first. If you want don't want the game lines from looking at the critter to show you're going to need to use Downstreamhooks.

    Here is an example of how this would work:

    Code:
    target_names = /kobold|squirrel|rolton|orc/
    
    $my_target = GameObj.npcs.find{ |npc| npc.name =~ target_names && npc.type =~ /aggressive/ }
    critter_has_shield_or_weapon = nil
    
    
    silence_the_look = proc{
    	action = proc { |server_string|
    		if server_string =~ /You see a fairly typical .*\.|.* appears to be in good shape\./
    			nil
    		elsif server_string =~ /.* has nothing at this time\./
    			critter_has_shield_or_weapon = "no"
    			DownstreamHook.remove("#{script.name}_silence_the_look")
    			nil
    		elsif server_string =~ /.*(He|She|It).* has a/
    			critter_has_shield_or_weapon = "no"
    			all_gear_list = server_string.split (/,| and /)
    			all_gear_list.each { |i|
    				if i !~ /\(worn\)/
    					critter_has_shield_or_weapon = "yes"
    				end
    			}
    			nil
    		else
    			server_string
    		end
    	}
    	critter_has_shield_or_weapon = nil
    	DownstreamHook.add("#{script.name}_silence_the_look", action)
    	silence_me
    	fput "look ##{$my_target.id}"
    	silence_me
    }
    
    before_dying { DownstreamHook.remove("#{script.name}_silence_the_look") }
    
    silence_the_look.call
    wait_until { critter_has_shield_or_weapon }
    if (critter_has_shield_or_weapon == "yes") && (Spell[1002].affordable?) && (Spell[1002].known?)
    	Spell[1002].cast($my_target)
    end
    Here is the same code with some explanations as to what's going on:

    Code:
    target_names = /kobold|squirrel|rolton|orc/
    
    $my_target = GameObj.npcs.find{ |npc| npc.name =~ target_names && npc.type =~ /aggressive/ }
    
    critter_has_shield_or_weapon = nil
    
    ###Below is the procedure you would call whenever you want the script to see if the critter is holding a weapon or shield.
    silence_the_look = proc{
    	action = proc { |server_string|
    ###The line below is where you put all game lines you don't want to show up while looking at a critter. Separate all game lines with a pipe symbol |
    		if server_string =~ /You see a fairly typical .*\.|.* appears to be in good shape\./
    			nil
    ###This is an example of a critter who is wearing nothing so the script sets the variable critter_has_shield_or_weapon to "no" since the critter has no gear at all. The nil at the end also means this game line won't show.
    		elsif server_string =~ /.* has nothing at this time\./
    			critter_has_shield_or_weapon = "no"
    			DownstreamHook.remove("#{script.name}_silence_the_look")
    			nil
    ###The following game line indicates the critter is wearing stuff so it sets the variable of critter_has_shield_or_weapon to no first in case the stuff it has is not a weapon or a shield.
    		elsif server_string =~ /.*(He|She|It).* has a/
    			critter_has_shield_or_weapon = "no"
    ###The following line take the game line it saw and divides it whenever it sees  "," or " and " into an array.
    			all_gear_list = server_string.split (/,| and /)
    ###The following tells the script to go through each item it divided above and it calls each item the letter i.
    ###The script then checks if (worn) shows up in i, if (worn) does not show up it means the item is being held in the critter's hand and thus should be 1002able
    			all_gear_list.each { |i|
    				if i !~ /\(worn\)/
    					critter_has_shield_or_weapon = "yes"
    				end
    			}
    			nil
    ###The following just means if none of the above matches a game line then it simply sends the game line through without doing anything. This is so you don't miss any whispers or lnet message or whatnot.
    		else
    			server_string
    		end
    	}
    	critter_has_shield_or_weapon = nil
    	DownstreamHook.add("#{script.name}_silence_the_look", action)
    ###The silence_me feature toggles seeing the script input commands.
    	silence_me
    	fput "look ##{$my_target.id}"
    	silence_me
    }
    
    ###This removes the Downstreamhook before the script is killed so you're not accidentally stuck with downstreamhooks when you don't want them.
    before_dying { DownstreamHook.remove("#{script.name}_silence_the_look") }
    
    ###The following line calls up our look command.
    silence_the_look.call
    ###The following line waits until the variable critter_has_shield_or_weapon has a value.
    wait_until { critter_has_shield_or_weapon }
    ###The following line tells the script to cast 1002 at the target if the variable critter_has_shield_or_weapon has a value of "yes"
    if (critter_has_shield_or_weapon == "yes") && (Spell[1002].affordable?) && (Spell[1002].known?)
    	Spell[1002].cast($my_target)
    end
    Last edited by Tgo01; 05-25-2015 at 08:31 PM.

  8. #8

    Default

    Quote Originally Posted by WRoss View Post
    Sort of.

    Char A gets disarmed and immediately sends "send to crosschar charB get weapon"
    If char A gets disarmed you want to have char B pick up char A's weapon?

    send_to_script 'crosschar', 'charb get #$my_weapon'

    Assuming you're talking about using the variable I mentioned earlier.

  9. #9

    Default

    This is really cool Tgo, thanks for starting this. I'm going to really have to read through this to figure it out. What I notice is all of the indents and whatnot. Does that mean things are a part of another object when they are indented? Also, does lich have a specific set of codewords that it uses as a program? Is that part of the Obj.data.xml file or whatever it's called?

    Sorry, but I might be asking quite a few questions along the way...

  10. #10

    Default

    Quote Originally Posted by Soulance View Post
    What I notice is all of the indents and whatnot. Does that mean things are a part of another object when they are indented?
    The indents just make the code a lot easier to read. Like if you're writing an if/else statement then you start the statement with if and end it with end, so you would write it like:

    Code:
    if a != b
    	if a == b
    		echo "Wait, what am I saying?"
    	else
    		echo "no idea"
    	end
    else
    	if b == c
    		echo "Huh?
    	elsif 1 == 2
    		echo "1 can't equal 2!"
    	else
    		echo "Could you repeat that?"
    	end
    end
    This way you can easily see which else/elsif/end belong to which if statements, you can also easily tell which code falls under which if/else statement.

    Likewise the following code would work just as well but if you ever want to edit the code in the future it might be a bit confusing:

    Code:
    if a != b
    if a == b
    echo "Wait, what am I saying?"
    else
    echo "no idea"
    end
    else
    if b == c
    echo "Huh?
    elsif 1 == 2
    echo "1 can't equal 2!"
    else
    echo "Could you repeat that?"
    end
    end
    Quote Originally Posted by Soulance View Post
    Also, does lich have a specific set of codewords that it uses as a program? Is that part of the Obj.data.xml file or whatever it's called?
    I'm not sure what you're asking.

    Quote Originally Posted by Soulance View Post
    Sorry, but I might be asking quite a few questions along the way...
    Questions are welcomed and encouraged! How else is one supposed to learn?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •