Status console - tf
Text:
; ..:....1....:....2....:....3....:....4....:....5....:....6....:....7....:...
;
; Cleaning up after the party, we have this functional script.
;
; apparently, tf restricts status_height to <= 6. so, we use that.
; (discovered by Javelin)
;
/set status_height=6
;
; ..:....1....:....2....:....3....:....4....:....5....:....6....:....7....:...
; Now, we trigger on receiving data matching
;
; !<TFPREFIX>C<n> <data>
;
; (where TFPREFIX is a secret set by each user, and 'C' is the
; 'CONSOLE' identifier for tf)
;
; since TFPREFIX isn't actually required for this, I suggest using
; something else altogether, so as to separate the protocol entirely
; from @dec/tf.
; -hack
;
; and then display data on line n (from 0-6), replacing anything
; already on that line.
;
/for r 1 4 /status_add -c -r%{r} data_%{r}:$[columns()]
/for r 1 4 /set data_%{r}=$[pad(" ",-columns())]
/def -ag -mregexp -t'!TFPREFIXC(\d+) (.*)' statstuff = \
/set data_%P1=$[pad({P2},-columns())]
;
; (this section written by Javelin)
; ..:....1....:....2....:....3....:....4....:....5....:....6....:....7....:...
; The protocol has been extended to support placing a string at
; row X, column Y (where the first column is 0), making this optional method
; take the format
;
; !<TFPREFIX>C<Row#>,<Col#> <data>
;
; the data can be a string and it will be placed into position as though
; typed in in 'typeover' mode (i.e., without modifying any of the surrounding
; text).
;
/def -ag -mregexp -t'!TFPREFIXC(\d+),(\d+) (.+)' statstuffbychar = \
/set dataname=data_%P1 %; \
/eval /set old_data=%%{%{dataname}} %; \
/set newlen=$[strlen(%P3)] %; \
/set data_%P1=$[strcat(substr({old_data}, 0, {P2}), {P3}, substr({old_data}, {P2}+{newlen}, columns()))]
;
; (this section drafted by Javelin and debugged by Trispis)
;
; NOTE: The above code potentially can
; overwrite any data_# tf variable.
; If more protection is needed,
; the first (\d+) in the trigger
; pattern could be changed to
; ([1-5]) or something. - Jav
; ..:....1....:....2....:....3....:....4....:....5....:....6....:....7....:...
; Things left to do:
; Make it world-aware -- console only being visible when toggled to
; the world feeding it. This means different consoles for different
; worlds.
; Make it go away when not in use.
; Make cool stuff to use it.
- Printer-friendly version
- Login or register to post comments

Click 

Why 12?
I know little about TF and even less about TF scripts. Thus, as you can see, it's wiki time once again. This is going to be my feeble attempt at guiding the development of a TF script without actually knowing how to write it myself.
Eventually, this variable will need to have some flexible, dynamic behavior; but, since I don't have the slightest clue where to begin writing the code for that in TF, I'm starting with a number which will allow progress to begin on the protocol...
A client-indifferent protocol which will support (but not be limited to) a height of 10 lines of console, plus two separator lines, making the sum total for the status area, 12.
... and that about covers the extent of what I'll be able to contribute in terms of actual code here. And, as stated above, that code will need rewritten (to adapt when toggling between worlds, and other foo).
Hopefully, my inability to do this myself won't damage the desired outcome too much.
But, I do know that the 12 lines will be numbered 0-11 and that we want the following output from them.
line 0 -- should retain its default 'stuff'
lines 1-10 -- should display our console
this is going to require the creation of an array of
variables, initially two-dimensional (rows x columns),
but possibly extended to three (sequenced characters).
Also note that this feature of TF has established
a precident for the protocol as referenced here,
in that the lines are numbered such that they increase
moving down the screen from top to bottom.
line 11 -- should be another 'ordinary' separator line.
Once the basic interface has been created for 10 lines, the whole thing (protocol and TF script) should be adjusted for optimum flexibility and featurefulness.
Ideas: Anyone remember Frogger? Perhaps 'mini pac-man'? Tetris?
Relevant tf /help
Help on: status area
status line
In visual mode, the input and output windows are separated by a status
line,
which by default looks something like this:
More 156_WorldName____________(Read)_(Active: n)_(Log)_(Mail)_(Over)_12:34
* "More" indicates how many more lines of text are waiting to be seen.
* "" is the name of the foreground socket's world.
* "(Read)" indicates that keyboard input is being read by read().
* The "(Active: n)" indicator shows the number of sockets with unseen
text.
* "(Log)" indicates that there is one or more log file open.
* "(Mail)" or "Mail n" indicates the number of files named by %MAIL or
%MAILPATH that contain unread mail.
* "(Over)" indicates that typed characters will overstrike instead of
insert (that is, %insert is off).
* The current time is displayed at the right end of the status line.
Configuring the status area
The status area may contain 1 or more rows; the number is determined by
%status_height. The rows are numbered from the top starting at 0. Each
row
is defined as a list of fields. A status field is defined as follows:
* an optional field name
* an optional ":" and number indicating the field width
* an optional ":" and attribute
The current list of status fields for row can be fetched with
status_fields().
The following commands modify the fields of the status area:
/clock off
Remove the clock from the status bar (equivalent to "/status_rm
@clock").
/clock on
Add a clock to the end of status row 0 if there is not already a
clock on status row 0. The width of the @clock field will be set
exactly wide enough to hold a time formatted according to
%clock_format.
/clock []
Add a clock to the end of status row 0 if there is not already a
clock on status row 0; in either case, use to control the
format of the clock (see ftime() for the meaning of ). If
is omitted, it defaults to "%H:%M". The width of the
@clock field will be set exactly wide enough to hold a time
formatted according to .
Example: display a clock in 12-hour format:
/clock %I:%M
/status_defaults
Restore list of status fields for all rows and their formats
(%status_int_* and %status_var_*) to their default values.
(Previous versions of tf had a %status_field_defaults variable;
this
is now deprecated.)
/status_save
Save the current list of fields in row 0 into memory slot with
label
. must be a legal variable name. (Saved fields will
be forgotten when tf exits.)
/status_restore
Restore the list of fields in row 0 that was previously saved with
"/status_save ".
/status_rm [-r]
Remove status field from status row . If -r is not
specified, all rows are searched. Only the first matching field is
removed. If there are unnamed pad fields on both sides of the
named
field, the one with the smaller width is also removed; if the named
field is at the beginning or end of a row, the neighboring pad
field
(if any) is removed.
Example: Remove the @mail field from the status bar:
/status_rm @mail
/status_add [] [:[:]] ...
Add status field to the status bar with optional and
. Options:
-r add to row (default 0)
-A add after all other fields (i.e., at end)
-A
add after existing field
-B add before all other fields (i.e., at beginning)
-B
add before existing field
-s insert padding of spaces between the new field and the
neighbor selected by -A or -B (default 1)
-x don't add the field if one with the same name is already
present
-c clear all existing fields before adding new fields
If neither -A nor -B is given, -A is assumed.
Example: Add a new field after the world name to display the
contents of the variable "hp":
/status_add -A@world hp:4
Multiple fields may be specified, but padding is not automatically
added between them; you must specify padding explicly. For
example,
/status_add -Aclock foo:4 :1 bar:4 :2 baz:4
is equivalent to
/status_add -Aclock foo:4
/status_add -Afoo bar:4
/status_add -Abar -s2 baz:4
/status_edit [-r] [:[:]]
If field currently exists in any status row, replace it with
[:[:]]. Neighboring padding is unchanged.
If -r is given, only row is searched. Only the first matching
field is edited.
Example: Change the @log field to say "L" instead of "(Log)", and
change the field's width to match:
/set status_int_log=nlog() ? "L" : ""
/status_edit @log:1
For backward compatiblity, you can get and set the status fields for row 0
via the %status_fields variable, but doing so is deprecated.
The default list of status fields is:
@more:8:Br :1 @world :1 @read:6 :1 @active:11 :1 @log:5 :1 @mail:6 :1
insert:6 :1 kbnum:4 :1 @clock:5
There are several types of fields:
* Unnamed fields create padding between the fields on either side of
it. Each of the ":1" fields in the default status_fields puts a space
of 1 character between the other fields.
* Field names beginning with "@" correspond to internal states. For
example, "@more" will be updated whenever the number of unseen lines
changes.
* Field names containing only letter, digits, and underscores
correspond to variables. Whenever there is a change in the value of
the
variable with the same name, the field will be updated. The value an
unset variable is considered to be the empty string. For example,
whenever the %insert variable changes, the "insert" field is updated.
Any variable may be monitored in this manner.
* A field whose name is in quotes (", ', or `) has its name (without
the quotes) printed literally on the status bar, and is never updated.
Use the \ character to escape a quote inside the string. The default
status_fields does not contain any of these literal fields.
Any variable may be monitored, but there is a fixed list of internal
statuses. The internal statuses available are:
@more Updated when there is a change in the number of lines below the
bottom of the window.
@world Updated when when the foreground world changes. During the
evaluation of the format expression, the current socket is the new
socket.
@read Updated when entering or exiting a read() function call.
@active
Updated when the number of active worlds changes. During the
evaluation of the format expression, the current socket is the
socket that became active.
@log Updated when the number of open log files changes.
@mail Updated when mail arrives (See "mail").
@clock Updated every minute, on the minute.
A field's width determines how many columns it will take up on the screen.
If the width of a string literal field field is omitted, it defaults to the
length of the string literal. One other field width may be omitted or set
to 0, which means that field will use whatever columns are unused by the
other fields. Normally, fields are left-justified within the width, but a
negative field width will right-justify the field within the absolute value
of the width. A width of "-0" can be used to right-justify the
variable-width field. If the formatted text is wider than the field width,
it will be truncated to fit within the specified width. Fields may also be
truncated if they would not fit on the screen.
The attributes explicily given in the field definiton are combined with
those in the corresponding %status_attr_int_ (for internal state
fields) or %status_attr_var_ (for variable fields). The combined
attributes are applied to the field text when it is displayed, but not to
the padding used to bring the field to the specified width. The entire
status line, including padding, is displayed with the attributes given by
%status_attr, which is none by default.
To bring fields up to their specified width, they are padded with
%status_pad, which is "_" by default. By setting status_pad to " " and
status_attr to "r", you can create a status line that looks more like the
one in emacs or the irc client.
When a status field is updated, the text displayed for that field is
determined by evaluating the expression contained in the variable
status_int_ (for internal state @) or status_var_ (for
variable ). Also, for variable fields, if status_var_ is not
set, the value of the variable will be displayed directly. Changing a
format variable will cause the status line to update.
All this may sound rather complex, so an example might help. The default
value of status_fields is:
@more:8:Br :1 @world :1 @read:6 :1 @active:11 :1 @log:5 :1 @mail:6 :1
insert:6 :1 kbnum:4 :1 @clock:5
and the corresponding format variables are:
/set status_int_more \
moresize() == 0 ? "" : \
moresize() > 9999 ? "MuchMore" : \
pad("More", 4, moresize(), 4)
/set status_int_world strcat( \
fg_world() !~ "" & !is_open(fg_world()) ? "!" : "", fg_world())
/set status_int_read nread() ? "(Read)" : ""
/set status_int_active nactive() ? pad("(Active:",0,nactive(),2,")") : ""
/set status_int_log nlog() ? "(Log)" : ""
/set status_int_mail \
!nmail() ? "" : \
nmail()==1 ? "(Mail)" : \
pad("Mail", 0, nmail(), 2)
/set status_var_insert insert ? "" : "(Over)"
/set status_int_clock ftime(clock_format)
The first field is "@more:8:Br". So, whenever the number of unseen lines
changes, TF looks for the variable status_int_more, and evaluates the
expression it contains. The result of the expression is printed in the
first 8 columns of the status line, with attributes "Br" (bold and
reverse).
The expression was carefully written so that it will never be more than 8
characters, because it would be confusing to generate something like
"More:12345" and then have it truncated to "More:123" because of the field
width of 8.
Since the "@world" field has no explicit width, its width is determined
dynamically. The fields on its left are pushed to the left side of the
screen, the fields on its right are pushed to the right side of the screen,
and the "@world" field uses whatever space remains in the middle.
Another example: Say your mud has a prompt like "H:42 M:17> " that shows
your hit points and mana, and you want it displayed on the status line like
" 42, 17", after the world name. To do this, call "/status_add -Aworld
hp_mana:7", and define a prompt hook:
/def -mregexp -h"PROMPT ^H:([^ ]*) M:([^ ]*)> $" hp_mana_hook = \
/set hp=%P1%; \
/set mana=%P2%; \
/set hp_mana=$[pad(hp, 3, ",", 0, mana, 3)]%; \
/test prompt({*})
Flying Pigs
@set me=~:[create(flying pig)]
&~`1 [v(~)]=§§§_//|.-~~~~-,§§§
&~`2 [v(~)]=§_/66§§\§§§§§§§\_@
&~`3 [v(~)]=(")_§§§/§§§/§§§|§§
&~`4 [v(~)]=§§'--'||§|-\§§/§§§
&~`5 [v(~)]=jgs§§§//_/§/_/§§§§
@dol lnum(1,5)=@set [v(~)]=~`##:[edit(get(v(~)/~`##),§,chr(160))]
@set [v(~)]=TFPREFIX:[v(TFPREFIX)]
&~`c [v(~)]=0
&~`t [v(~)]=@wait 0[null(iter(lnum(1,5), pemit(owner(me), ![v(TFPREFIX)]C%i0 [mid(setr(p, repeat(chr(160), width(owner(me))))[v(~`%i0)]%qp, v(~`c), width(owner(me)))])))][set(me, ~`c:[inc(v(~`c))])]=@switch 1=lte(v(~`c),add(width(owner(me)), strlen(v(~`1)))), @tr me/~`t,
@startup [v(~)]=@tr [set(me, ~`c:0)]me/~`t
it works with the above tf stuff (change it from 4 lines to 5 in the /for r 1 5 etc lines).
Slightly faster pig
Change one attrib to speed up the pig:
&~`T flying pig=@assert [null(iter(lnum(1,5),pemit(owner(me),![v(TFPREFIX)]C%i0 [mid(setr(p,repeat(chr(160),width(owner(me))))[v(~`%i0)]%qp, v(~`c),width(owner(me)))])))][set(me,~`c:[inc(v(~`c))])][lte(v(~`c),add(width(owner(me)), strlen(v(~`1))))]; @tr me/~`t
Much faster pig
IF you really like the pig to fly:
@STARTUP flying pig=think [u([set(me, ~`c:0)]me/~`t)]
&~`T flying pig=[iter(lnum(100),[null(iter(lnum(1,5),pemit(owner(me),![v(TFPREFIX)]C%i0 [mid(setr(p, repeat(chr(160), width(owner(me))))[v(~`%i0)]%qp, v(~`c),width(owner(me)))])))][set(me,~`c:[inc(v(~`c))])][lte(v(~`c),add(width(owner(me)), strlen(v(~`1))))])]
tweeeeeeeeeeked
&~`T flying pig=[iter(lnum(inc(setr(w, add(setr(m, width(owner(me))), strlen(v(~`1)))))), [null(iter(lnum(1, 5), pemit(owner(me), ![v(TFPREFIX)]C%i0 [mid(setr(p, repeat(chr(160), %qm))[v(~`%i0)]%qp, v(~`c),%qm)])))][set(me, ~`c:[inc(v(~`c))])][lte(v(~`c), %qw)])]
Frogger
Here's a start on 'Frogger' (it's a basic version of a single 'fly'), using the direct character writing feature (C<row>,<col> <char>).
@wait 0=@set me=~:[create(Frogger)]
@wait 0=@set [get(me/~)]=VT:[chr(247)]
@wait 0=@set [get(me/~)]=VS:[chr(032)]
&VR [get(me/~)]=1
&VC [get(me/~)]=0
@cpattr me/TFPREFIX=[get(me/~)]/VP
&move [get(me/~)]=[pemit(owner(me),!%vpC%vr\,%vc %vs)][set(me,vr:[randword(switch(%vr, 1, 1 2, 2, 1 2 3, 3, 2 3 4, 3 4))])][set(me,vc:[randword(switch(%vc, 0, 0 1, setr(w,dec(width(%#))), dec(%qw) %qw, dec(%vc) %vc [inc(%vc)]))])][pemit(owner(me),!%vpC%vr\,%vc %vt)]
&trig [get(me/~)]=@wait 1[null(u(move))]=@tr me/trig
&move never left
Here's a different
&MOVEattribute which prevents the fly from moving left (and wraps it back to the beginning when it gets to the end).&move frogger=[pemit(owner(me), !%vpC%vr\,%vc %vs)][set(me, vr:[randword(switch(%vr, 1, 1 2, 2, 1 2 3, 3, 2 3 4, 3 4))])][set(me, vc:[randword(switch(%vc, setr(w, dec(width(owner(me)))), %qw 0, %vc [inc(%vc)]))])][pemit(owner(me), !%vpC%vr\,%vc %vt)]
&FLY?
just realized '
@move' is a standard attrib name. this should probably be renamed '&FLY'.