Table of Contents

Introduction

This is a more sophisticated client-side Tcl script that will pray you to max grace. It will recognize if you're over a friendly altar and pray you to the doubled max there, or even abort if you move over another god's altar. Yes, you and move, or even cast healing spells while praying, but it does soak up actions, so it's best not used in the middle of a fight. You can also supply a numeric argument to “spam” an altar with that many prayers, to recover your stats, decurse your inventory, etc.

Warning: The big weakness of this script is that it cannot autodetect what god the character worships. You can specify the god's name as an argument, too – but the GTK client, at least, has all characters sharing the same key bindings, so be careful when switching characters! The default is embedded as Mostrai.

Requirements

Code

#!/bin/sh
# the next line restarts using tclsh \
    exec tclsh "$0" ${1+"$@"}
 
# This is a crossfire script to pray to max Grace.  
# Written by David Harmon, a.k.a. Mental Mouse, for the Crosfire DocuWiki.
 
 
# Test if we're on an altar.  1 for friendly, 0 for none, -1 for other god's
proc look_for_altar {whose} {
    set on_altar 0
 
    puts "request items on"
    flush stdout
 
    set cfline {}
 
    while {0 <= [gets stdin cfline]} {
	foreach "msgtype msginfo1 msginfo2" "[lrange $cfline 0 2]" {}
	set msgvalue [lrange "$cfline" 3 end]
 
	switch "$msgtype $msginfo1 $msginfo2" {
	    "request items on" {
 
		# msgvalue is null to start list, "end" to end it.
		if {[llength "$msgvalue"] <= 0} {
		    set on_altar 0
		    continue
		    # go on to first item
		} 
 
		if {[string match "$msgvalue" "end"]} {
		    return $on_altar 
		}
 
		# Otherwise, examine the item
		# i_flags:  1 ? 2 ? 4 ? 8 worn 16 locked
		foreach "i_idnum i_count i_weight i_flags i_class" \
		    "[lrange $msgvalue 0 4]" {}		
		set i_name [lrange "$msgvalue" 5 end]
 
		# ignore anything but an altar
		if {! [string match "[lindex "$i_name" 0]" "Altar" ]} { 
		    continue
		}
 
		if {[string match "[lindex "$i_name" 2]" "$whose"]} {
		    set on_altar 1
		} else {			  
		    set on_altar -1
		} 
		# note that we don't want to return here, because we want 
		#  to finish reading the list.
 
		# case "request items on"
	    }
	    default {}
	}
    }
 
    # just in case -- we should return from the end of the item list
    return $on_altar
}
 
##### Procs defined, continuing with program   #####
 
 
set my_god "Mostrai"
set more_prayer 0
 
# we'd like to be able to *ask* the server what god the character worships!
# Failing that, get it from a default and/or an argument.
foreach arg $argv {
    if {[string is digit $arg]} {
	# TODO:  implement this....
	set more_prayer $arg
    } else {
	set my_god "$arg"
    }
}
 
set on_altar 0
set errvar ""
set maxgrace 0
 
set tmpdir "[file dirname $argv0]/tmp"
 
 
 
 
 
set on_altar [look_for_altar $my_god]
if  {$on_altar == -1} {
    puts "draw 3 You're on the wrong altar!"
    flush stdout
    file delete "$lockfile"
    exit 0
}      
 
# Get our maxgrace, once
puts "request stat hp"
flush stdout
 
while {0 <= [gets stdin cfline]} {
    foreach "msgtype msginfo1 msginfo2" "[lrange $cfline 0 2]" {}
    set msgvalue [lrange "$cfline" 3 end]
 
    switch "$msgtype $msginfo1 $msginfo2" {
	"request stat hp" {
	    foreach {hp maxhp sp maxsp grace maxgrace food} \
		"$msgvalue" {}
	    puts stderr "Maxgrace: $maxgrace, Grace: $grace"
	    break
	}
	default {}
    }
}
 
 
# Now the tricky part -- we don't want to issue a pray command for every
# change in grace (which may not be our work!), so we do a "watch comc"
# ("command complete") and respond only to those.  We also do a "watch stats"
# to keep track of grace, but we don't send commands then.  Note that our own
# prays also trigger the "watch comc", which is why we start with a prayer.
 
# Note that if we move on or off an altar while praying, we could have trouble,
# so check for that too, with a "monitor"
 
 
puts stderr "Found grace: $grace"
puts "watch stats"
puts "watch comc"
puts "monitor"
puts "issue 1 1 use_skill praying"
 
flush stdout
 
set moved 0
set done 0
 
while {!$done && [gets stdin cfline] > 0} {
    foreach "msgtype msginfo1 msginfo2" "[lrange $cfline 0 2]" {}
    set msgvalue [lrange "$cfline" 3 end]
 
    switch -glob "$msgtype $msginfo1 $msginfo2" {
	"watch stats grace" {
	    set grace $msgvalue
	    puts stderr "Grace: $grace"
	}
	"monitor 0 0" {
	    # we may be moving....
	    puts stderr "Moving?  \"$msgvalue\""
	    set moved 1
	}
 
	"watch comc *" {
	    # msginfo2 is a command number, thus variable.
 
	    if {$moved} {
		puts stderr "May have moved ... checking again for altars"
		set on_altar [look_for_altar $my_god]
		if {$on_altar == -1} {
		    puts "draw 3 Yikes!  You moved onto the wrong altar!" 
		}
		set moved 0
	    }
 
	    if {$on_altar >= 0} {
		if {$grace >= (($on_altar == 1)? $maxgrace *2 : \
				   $maxgrace)} {
		    # Countdown extra prayers
		    incr more_prayer -1
		    puts stderr "Counting down:  $more_prayer"
		    flush stderr
		    if {$more_prayer < 0} {incr done}
		} 
 
		if {!$done} {
		    puts "issue 1 1 use_skill praying"
		    flush stdout
		    # will be overwritten soon, but that's OK
		    incr grace
		    puts stderr "praying"
		}
	    } else {
		puts stderr "praying blocked -- wrong altar"
	    }
	}
	default {}
    }
}
 
 
 
# now clean up and exit
puts "unwatch stats"
puts "unwatch comc"
puts "unmonitor"
flush stdout
exit 0

Notes & Comments

See Introduction about specifying the character's god.

The comment prefix is for UNIX; it lets sh or bash recognize it as a command script, but then relaunch it in Tcl, regardless of Tcl's path. This is a better version of the prefix than that found in the Tcl manual; it doesn't introduce a null argument if called without any.

References