PDA

View Full Version : Mapper/Go2/Child2 - Child Rescue Fixes



Haldrik
03-31-2016, 07:35 PM
Heyo,

As many of you might know, any areas that have wayto procedures that generate multi-room movement break child rescues if you are using any form of child2/step2. So I've created a script that fixes the issue for Maaghara, and should be applicable to other areas with some modifications. Feel free to send me areas that do not work for children and I will see about getting them added in.


What does it do:
It searches the mapper DB for the offending rooms, and adds a line that waits for the child each step.

Instructions:
Create a new script, name it anything, and run the script after any mapper update. Assuming you have mapper on autorun, this should be run AFTER. Do not run it twice.

EDIT: I've started converting it to a modular system, not finished but it works fine for Maaghara.



=begin

v.02 by Kalros
Script to replace/modify string procs inside the mapdb.
Assumes the only change we are making is with a StringProc
Credit to Tillmen for better child wait code.

To do:
Make more modular so it can take multiple rooms
Swap out replace messages for variables
Add better initial room loops to support more rooms
Adjust make_change method to support more then string_procs

Changelog-
4.1.2016:
Swapped code to methods, removed most variables
4.6.2016:
Swapped child wait code for Tillmen's version
Removed UserVars, no longer needed
=end


#$map_changes_debug = true

# Adding portion for modular room changes
@Maaghara_proc_find = 'move dir'
@Maaghara_room_title = 'Maaghara'
@Mag_room_list = []
@Mag_changes = {
"; loop " => "; if (bounty? =~ /^You have made contact with the child/);child = GameObj.npcs.find { |npc| npc.noun == 'child' }; else; child = nil; end; loop ",
"move dir" => "move dir; 50.times { break if GameObj.npcs.any? { |npc| npc.id == child.id }; sleep 0.1 } if child",
}

def update_waytos(room_to_change_id, wayto_changes)
Map[room_to_change_id].wayto.each { |wayto_destination_id, current_wayto|
if current_wayto.class == Proc
new_wayto = current_wayto._dump
wayto_changes.each do |search_string, replace_string|
new_wayto.gsub!(/#{search_string}/, replace_string)
end
Room[room_to_change_id].wayto[wayto_destination_id] = StringProc.new(%{#{new_wayto}})
end
}
end

Map.list.each {|room|
@Mag_room_list << room.id if (room.wayto.inspect =~ /#{@Maaghara_proc_find}/ and room.title.inspect =~ /#{@Maaghara_room_title}/)
}

if script.vars[0] == 'check'
@Mag_room_list.each {|i|
echo Map[i].inspect
}
exit
end

@Mag_room_list.each {|room|
update_waytos(room, @Mag_changes)
}

Gnomad
03-31-2016, 08:30 PM
Man, you're in Maaghara already? You don't waste time.

Haldrik
03-31-2016, 08:37 PM
Man, you're in Maaghara already? You don't waste time.

6 months is a long time! And I'm in here pretty early. That's why I've died about 20 times this month. Basically a glass cannon at this point.

Haldrik
03-31-2016, 09:32 PM
edit: false alarm

Definitely make sure you set this to an autologin trigger.

Haldrik
04-01-2016, 02:09 AM
Update. I was able to remove the need for the outside procedure. It's all internal now.

Haldrik
04-01-2016, 04:22 AM
I'm having some weird interactions with wait, swapped out to matchtimeout. Now, won't suicide if it gets stuck.


#new_wayto.gsub!(/move dir/, "move dir; echo 'waiting for child'; echo UserVars.rescue_child; waitfor('child') if UserVars.rescue_child")
new_wayto.gsub!(/move dir/, "move dir; echo 'waiting for child'; echo UserVars.rescue_child; matchtimeout 2, 'child arrives' if UserVars.rescue_child")

Tillmen
04-01-2016, 05:26 AM
Here's how I dealt with the child issue in the minotaur mazes:



target_room_id = 6192
maze_rooms = [6191, 6254, 6252, 6250, 6195, 6197, 6199, 6249, 6198, 6248, 6196, 6251, 6192, 6193, 6194, 6253]
$minotaur_maze_dirs ||= Hash.new
loop {
if (bounty? =~ /^You have made contact with the child/)
child = GameObj.npcs.find { |npc| npc.noun == 'child' }
else
child = nil
end
start_room = Room.current
$minotaur_maze_dirs[start_room.id] ||= Hash.new
dir = $minotaur_maze_dirs[start_room.id].keys.find { |d| $minotaur_maze_dirs[start_room.id][d] == target_room_id } || XMLData.room_exits.find { |d| $minotaur_maze_dirs[start_room.id][d].nil? } || $minotaur_maze_dirs[start_room.id].keys.find { |d| $minotaur_maze_dirs[$minotaur_maze_dirs[start_room.id][d]].values.include?(target_room_id) } || XMLData.room_exits[rand(XMLData.room_exits.length)]
move dir.dup
50.times { break if GameObj.npcs.any? { |npc| npc.id == child.id }; sleep 0.1 } if child
end_room = Room.current
$minotaur_maze_dirs[start_room.id][dir] = end_room.id
if end_room.id == target_room_id
break
elsif not maze_rooms.include?(end_room.id)
dir = end_room.wayto[start_room.id.to_s]
if dir.class == Proc
dir.call
50.times { break if GameObj.npcs.any? { |npc| npc.id == child.id }; sleep 0.1 } if child
elsif dir.class == String
move dir.dup
50.times { break if GameObj.npcs.any? { |npc| npc.id == child.id }; sleep 0.1 } if child
end
end
}


There's a lot of junk in there for dealing with the maze, but the important parts are this before each movement:


if (bounty? =~ /^You have made contact with the child/)
child = GameObj.npcs.find { |npc| npc.noun == 'child' }
else
child = nil
end


which will figure out if you have a child bounty, and the child appeared, and there's a child in the room.

Then after each movement:



50.times { break if GameObj.npcs.any? { |npc| npc.id == child.id }; sleep 0.1 } if child


which will wait for that same child to show up if there was one, but won't wait longer than five seconds.

This all goes into a StringProc for each movement in the hunting ground that makes multiple moves. The downside is that it's possible that it will think someone else's child is yours if there's two in the room before you move. The up side is that you don't have to turn an option on or off; it waits when it should and doesn't when it shouldn't.

Haldrik
04-01-2016, 08:56 PM
Awesome Tillmen. I'll have to convert some pieces over, I like your 50.times break. But I'm having an issue with my proc not playing nicely with sbounty's step method. So this kind of makes me worried that other step s (like child2) could break as well.

At this point my solution is to not use sbountys method but I'm curious why one works and the other doesn't. But I don't really understand what the hell sbounties version is doing.


Sbounty - Does not work.


way = Room.current.wayto[path[path.index(Room.current.id)+1].to_s]

if way.class == String
move way
elsif way.class == Proc
way.call
end


go2 - does work

way = Room.current.wayto[next_id.to_s]
if way.class == Proc
way.call
elsif way.class == String
move way

Haldrik
04-01-2016, 08:58 PM
Oh, one last piece. Your StringProc is beautifully written. Is there any way to convert to stringproc / unconvert so its in a readable format? I've also noticed some weird issues using quotes. Can you not use quotes inside?

Gnomad
04-01-2016, 10:33 PM
For whatever it's worth, when I do child rescues in Maaghara, I take the kid by one the two roots in the southwest part of Tsoran's map, and occasionally run to the other one to see if it's live. I'd rather wait for a root to open up then to drag the kid all over the place looking for an open root, if there is one. Far less chance of getting ganked.

Tillmen
04-01-2016, 10:45 PM
To make it into a StringProc, I just remove leading whitespace (in my editor, it's just highlight everything and do shift-tab a few times), and then do a find/replace all for line returns to "; ". None of that is really needed though. You could just put a StringProc.new(" at the start and a ") at the end of that code and it'll work. But when you view the StringProc later with a .inspect, it'll be littered with \n and \t and be hard to read.

The quotes are tricky. You're actually defining a string, and the definition of that string does not exactly match its contents, and it's the contents that get turned into code. So.. basically.. you have to think of what the string would look like when you echo it, because that's how it will be interpreted as code. For example,


;e string = "var = 4"; echo string
[exec1: var = 4]

;e foo = "stupid"; string = "var = \"this is #{foo}\""; echo string
[exec1: var="this is stupid"]

;e foo = "stupid"; string = "var = \"this is \#{foo}\""; echo string
[exec1: var="this is #{foo}"]

;e string = "regex = /foo\\.bar/; \"str\\\"ing\" =~ regex"; echo string
[exec1: regex = /foo\.bar/; "str\"ing" =~ regex]


So basically, if you replace "string = " with "StringProc.new(", then it has the code that you see in the echo, not what you see when you define the string. A missing backslash can completely change the code or make it not run at all.

Haldrik
04-01-2016, 11:00 PM
To make it into a StringProc, I just remove leading whitespace (in my editor, it's just highlight everything and do shift-tab a few times), and then do a find/replace all for line returns to "; ". None of that is really needed though. You could just put a StringProc.new(" at the start and a ") at the end of that code and it'll work. But when you view the StringProc later with a .inspect, it'll be littered with \n and \t and be hard to read.

The quotes are tricky. You're actually defining a string, and the definition of that string does not exactly match its contents, and it's the contents that get turned into code. So.. basically.. you have to think of what the string would look like when you echo it, because that's how it will be interpreted as code. For example,


;e string = "var = 4"; echo string
[exec1: var = 4]

;e foo = "stupid"; string = "var = \"this is #{foo}\""; echo string
[exec1: var="this is stupid"]

;e foo = "stupid"; string = "var = \"this is \#{foo}\""; echo string
[exec1: var="this is #{foo}"]

;e string = "regex = /foo\\.bar/; \"str\\\"ing\" =~ regex"; echo string
[exec1: regex = /foo\.bar/; "str\"ing" =~ regex]


So basically, if you replace "string = " with "StringProc.new(", then it has the code that you see in the echo, not what you see when you define the string. A missing backslash can completely change the code or make it not run at all.

Head spinning. I suppose I'll just use single quotes for now!

Any insight into why my waits in the stringprocs aren't working in the step2 code? (posted above)

way = Room.current.wayto[path[path.index(Room.current.id)+1].to_s]

Tillmen
04-01-2016, 11:11 PM
In what way is it not working?

Haldrik
04-02-2016, 02:46 AM
"9734"=>StringProc.new("next_exit = { 9823 => [ 'southeast', 'southwest', 'southwest', 'east', 'southwest', 'southeast', 'south' ], 9818 => [ 'east', 'southwest', 'west', 'west', 'northeast', 'northeast', 'northwest' ], 9808 => [ 'east', 'east', 'east', 'northeast', 'west' ], 9788 => [ 'southwest', 'southeast', 'southwest' ], 9784 => [ 'southeast', 'south', 'northeast', 'north', 'west', 'west', 'west' ] };UserVars.rescue_child = true if GameObj.npcs.find {|i| i.noun == 'child'}; loop { if move 'go root'; nil until get == '[Maaghara Tower, Refuse Heap]'; fput 'stand' unless standing?; waitrt?; UserVars.rescue_child = false; break; else; if dir_list = next_exit[Room.current.id]; dir_list.each { |dir| move dir; echo 'waiting for child'; echo UserVars.rescue_child; matchtimeout 2, 'child arrives' if UserVars.rescue_child }; else; echo 'error: out of cheese'; break; end; end }")


Doesn't work after "go root" using child2/sbounty wayto.call. I know it's inside the right place because it's echoing, its true because its echoing true. It's just not waiting. I've tried waitfor and now matchtimeout.


[sbounty]>northwest
[Maaghara Labyrinth]
Patches of phosphorescent red fungus grow along ceiling of this circular tunnel, the invasive confines of the room tinted a melancholy sanguine by the growth. Vertical fissures spread across the walls like jagged crackles of energy. A light coating of moisture edges the deep scars upon the earth, the tiny drops imparting a sparkling sheen to the otherwise dismal surroundings. You also see a massive root.
Obvious exits: northeast, southeast
A young giantman child arrives, following you.
Your disk arrives, following you dutifully.
[sbounty]>go root
There doesn't seem to be any way to do that at the moment.
[sbounty: move: failed]
[sbounty]>southeast
[Maaghara Labyrinth]
Tiny pebbles dot the floor randomly, their pale hue a stark contrast to the dark roots which slither across and up into the curving ceiling. Light scratches mar the smooth wall, some twisting jaggedly several different ways while others form straight, rough lines in the earth. A few patches of lichen nestle inside the shallow gouges, though they do not grow in any other place within the cramped chamber.
Obvious exits: north, south, southwest, northwest
[sbounty: waiting for child]
[sbounty: true]
[sbounty]>south
[Maaghara Labyrinth]
Several rough stones litter the floor in a scattered design. Someone or something has burrowed into the northern wall, leaving a narrow passage of snapped roots and broken rocks. Smattered against the opposing wall in a spray pattern are flecks of heavy burgundy-colored moss.
Obvious exits: north, northeast, southeast, west
[sbounty: waiting for child]
[sbounty: true]
[sbounty]>northeast
[Maaghara Labyrinth]
The scent of moistened clay and dirt permeates the air and lingers, perhaps due to the high volume of condensation. Water droplets hitting the dampened clay floor echo all around the tunnel.
Obvious exits: north, southwest
[sbounty: waiting for child]
[sbounty: true]
Your disk arrives, following you dutifully.
[sbounty]>north

Works using go2 way.call.


>;go2 town
ETA: 0:02:03. 115 rooms between this room (9808) and:
#4653:
[Cysaegir, Linsandrych Common]
Placed strategically under a leafy arbor for shade, a vine-carved bench hides in the darkness. Interrupting the natural beauty of a grassy knoll sprinkled with a scattering of buttercups is a lattice-worked gazebo. A slate-paved walkway that snakes through flowering bushes and trees leads toward the steps of the structure. Gorgeous bell-shaped flowers in shades of blue and pink encircle the base of a pedestal upon which a magnificent gold statue of an elven man is perched.
Obvious paths: southeast, southwest, northwest

To go here, unpause the script. To abort, kill the script.
--- Lich: go2 paused.
--- Lich: go2 unpaused.
>;unpause
[go2]>go root
There doesn't seem to be any way to do that at the moment.
[go2: move: failed]
[go2]>east
[Maaghara Labyrinth]
Permanently fixed as if supporting the wall, a molding skeleton of some unfortunate animal lies entangled by roots. The twisting tentacles of gnarled roots rise up from the floor and along the walls, creating warped patterns across the ceiling. The unpleasant smell of mildew hangs heavy in the air.
Obvious exits: northeast, east, west
[go2: waiting for child]
[go2: true]
Your disk arrives, following you dutifully.
>say child arrives
You say, "Child arrives."
[go2]>east
[Maaghara Labyrinth]
The moisture has eroded the walls, revealing a constricted network of roots. The air, once alive with the fragrance of nature, now smells imprisoned and devoid of life. Even the roots and moss seem to writhe in some sort of unnatural pain.
Obvious exits: northeast, east, southwest, west
[go2: waiting for child]
[go2: true]
[DRPrime]-DR:Aurayn: "I am indeed"
>say child arrives
You say, "Child arrives."
[go2]>east
[Maaghara Labyrinth]
A network of roots congest the walls and floor of this passage. The running circles of pale veiny growth look as if they are attempting to escape through the ceiling. Water collects on a few of the low hanging roots, causing a constant dribble of water to fall from above.
Obvious exits: northeast, east, south, west, northwest
[go2: waiting for child]
[go2: true]
>say child arrives
You say, "Child arrives."
[go2]>northeast
[Maaghara Labyrinth]
Darkness cloaks the area like a thick fog, only the outlines of lichen lining the walls are discernable in the blackness. The moist air is very still, and not a sound reaches the confines of this winding tunnel. Tatters of stained cloth are spread across the floor, along with the vague impressions of small bits of bone.
Obvious exits: south, southwest, west
[go2: waiting for child]
[go2: true]
Your disk arrives, following you dutifully.
A young elven child arrives, following you.
[go2]>west
[Maaghara Labyrinth]
Thick curls of mist rise up from small fissures in the floor, the wavering wisps enshrouding the area in a light haze. The blurred forms of slimy mold can be seen upon the walls, each casting their malodorous scent to the musty air of the room. As the mist swirls about the area lazily, the slime upon the wall glistens faintly, resembling a cascading waterfall of green ooze. You also see a massive root with a wide opening in the side.
Obvious exits: east, west
[go2: waiting for child]
[go2: true]
[Merchant]-GSIV:Dasmik: "$7 per?"
A young elven child arrives, following you.
[go2]>go root
You approach the massive root and climb inside through a massive fissure in the side. Before you are even fully inside, rootlike tendrils as thick as your thumb snake out and encircle your wrists, arms and legs. Acting in conjunction, they quickly begin stuffing you through a tunnel which leads into the ceiling!
[Inside Tree, Narrow Tunnel]
The overpowering scent of bile fills the tube-like chute as it curves upward. Tiny pale, hair-like roots coat the smooth walls of the tube, their tips waving back and forth as they brush across your body. The walls glisten with a slick substance that is moved along the chute with you, supported by the roots.
Obvious exits: none
Your disk arrives, following you dutifully.
A young elven child arrives, following you.
[Merchant]-GSIV:Dasmik: "great deal."
[DRPrime]-DR:Etreu: "I'll run you down in about 30 then."
[DRPrime]-DR:Aurayn: "sounds painful"
The tendrils pass you further along the tunnel, gripping you gently but firmly.
[Inside Tree, Narrow Tunnel]
Dark walls stretch upwards to create a narrow, rounded tunnel. Slime pulses out from the walls, the thick ooze dripping down to coat thousands of small wiry roots that twitch and move of their own accord. The pale, worm-like roots currently have a tenuous grasp upon your body, and the same cilia-like structures above stretch down toward you, as if vying for a grip.
Obvious exits: none
A disturbance further down the tube catches your attention, as gently rustling tendrils and roots pass the entangled form of a young elven child up towards you.

Haldrik
04-06-2016, 03:56 PM
Ran into a weird issue as I've been converting my script over. Basically, my new gsub! function replaces the string inside the mapdb, which is super odd but I guess I can't complain. It's somehow gsubbing the wayto directly via wayto_.dump. Why? How?




=begin

v.02 by Kalros
Script to replace/modify string procs inside the mapdb.
Assumes the only change we are making is with a StringProc
Credit to Tillmen for better child wait code.

To do:
Make more modular so it can take multiple rooms
Swap out replace messages for variables
Add better initial room loops to support more rooms
Adjust make_change method to support more then string_procs

Changelog-
4.1.2016:
Swapped code to methods, removed most variables
4.6.2016:
Swapped child wait code for Tillmen's version
Removed UserVars, no longer needed
=end


$map_changes_debug = true

# Adding portion for modular room changes
@Maaghara_proc_find = 'move dir'
@Maaghara_room_title = 'Maaghara'
@Mag_room_list = []
@Mag_changes = {
"; loop" => "; loop; if (bounty? =~ /^You have made contact with the child/);child = GameObj.npcs.find { |npc| npc.noun == 'child' };else;child = nil;end;",
"move dir" => "move dir; echo 'waiting for child'; echo child; 50.times { break if GameObj.npcs.any? { |npc| npc.id == child.id }; sleep 0.1 } if child",
}

def test_wayto_updates(room_to_change_id, wayto_destination_id, new_wayto)
## for testing the wayto_updates
echo "Room to change: #{room_to_change_id}"
echo "Destination room for new way_to: #{wayto_destination_id}"
echo "New way_to being applied: #{new_wayto}"
end

def gsub_waytos(old_wayto, wayto_changes)
echo 'inside gsub_waytos'
wayto_changes.each do |search_string, replace_string|
old_wayto.gsub!(/#{search_string}/, replace_string)
end
return old_wayto.inspect
end

def update_waytos(room_to_change_id, wayto_changes)
Map[room_to_change_id].wayto.each { |wayto_destination_id, current_wayto|
if current_wayto.class == Proc
old_wayto = current_wayto._dump

# Make gsub changes based on variables defined above
new_wayto = gsub_waytos(old_wayto, wayto_changes)
echo new_wayto

## For echos and testing
#test_wayto_updates(room_to_change_id, wayto_destination_id, new_wayto) if $map_changes_debug

## This process replaces the old wayto with the new wayto
#Room[room_to_change_id].wayto[wayto_destination_id] = StringProc.new(%{#{new_wayto}})
end
}
end

Map.list.each {|room|
@Mag_room_list << room.id if (room.wayto.inspect =~ /#{@Maaghara_proc_find}/ and room.title.inspect =~ /#{@Maaghara_room_title}/)
}

if script.vars[0] == 'check'
@Mag_room_list.each {|i|
echo Map[i].inspect
}
exit
end

@Mag_room_list.each {|room|
update_waytos(room, @Mag_changes)
}

## Old Code
#UserVars.rescue_child = false if UserVars.rescue_child.nil?
#new_wayto.gsub!(/; loop /, ";UserVars.rescue_child = true if GameObj.npcs.find {|i| i.noun == 'child'}; loop ")
#new_wayto.gsub!(/move dir/, "move dir; echo 'waiting for child'; echo UserVars.rescue_child; waitfor('child') if UserVars.rescue_child")
#new_wayto.gsub!(/standing\?; waitrt\?/, "standing?; waitrt?; UserVars.rescue_child = false")

#new_wayto.gsub!(/; loop/, "; loop; if (bounty? =~ /^You have made contact with the child/);child = GameObj.npcs.find { |npc| npc.noun == 'child' };else;child = nil;end;")
#new_wayto.gsub!(/move dir/, "move dir; echo 'waiting for child'; echo child; 50.times { break if GameObj.npcs.any? { |npc| npc.id == child.id }; sleep 0.1 } if child")

Haldrik
04-06-2016, 04:43 PM
Well mystery solved, I'm a dummy. gsub! was working on my old code too, i just didn't notice when I changed over to _dump.

Soulance
04-06-2016, 11:17 PM
Really wish I understood how this all works...but I do enjoy watching you guys figure it out.

Haldrik
04-07-2016, 01:37 AM
Ran into some more issues using gsub directly on mapper wayto. Apparently it blows the fuck up and starts tossing insecure errors.

This version - Lots of bad things -- > current_wayto._dump.gsub!(/#{search_string}/, replace_string)

Below version, works okay.

new_wayto = current_wayto._dump
new_wayto.gsub!(/#{search_string}/, replace_string)
"Room[room_to_change_id].wayto[wayto_destination_id] = StringProc.new(%{#{new_wayto}})"

I need to do some more testing but hopefully this version will be working.

Haldrik
04-07-2016, 03:29 AM
Updated! Fully working for Maaghara.