Repository navigation
Expand file tree
/
Copy pathteach.py
More file actions
167 lines (153 loc) · 6.88 KB
/
Copy pathteach.py
File metadata and controls
167 lines (153 loc) · 6.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
"""Teach a skill to another character and keep the class open: ;teach
;teach scholarship to cecil TEACH the skill to that student, offer it again whenever they come back
;teach scholarship open TEACH ... OPEN — a class anyone may LISTEN to
;teach return (typed while it runs) STOP TEACHING and end
With no student in the class for 5 minutes it stops teaching and logs
the teacher out (QUIT); a student not in the room is offered the class
again every 20 s meanwhile. A class TEACH can no longer offer, or the
re-offer cap reached, logs out too.
A class is TEACH <skill> TO <student> on the teacher's side — "You
begin to lecture Cecil on the proper use of the Scholarship skill." —
and LISTEN TO <teacher> on the student's (`;listen`); both learn until
one of them moves, and the teacher then sees "All of your students
have left, so you stop teaching." (captured 2026-09-22 in the
Paladins' Guild Chambers). An offer no one takes up expires within
minutes — "You stop trying to teach Parry Ability to Cecil." — and a
student joining reads "Cecil begins to listen to you teach the Parry
Ability skill." This script offers the class and stands there: an
expired offer is made again at once, and when the students leave it
waits a moment and offers again, so a student whose `;train` rest
walked away rejoins on return, and it
ends on `return` (STOP TEACHING), on death or hostiles (the shared
escape), or when TEACH says the skill cannot be taught. The teacher's
Teaching skill trains by it; a `;train` task for the teacher is
`{"skills": ["Teaching"], "script": "teach", "args": ["scholarship",
"to", "cecil"], "return_word": "return"}`. Elanthipedia: Teach
command. Stop with: ;stop teach (the class stays up — STOP TEACHING
yourself), or ;teach return.
"""
import time
from client.game import flight
from client.game.act import ask
from client.game.loop import danger, pause, wants_stop
from client.game.probe import classify
from client.game.teaching import (
OFFER_EXPIRED,
STUDENT_JOINED,
STUDENTS_LEFT,
TEACH_OUTCOMES,
parse_teach_args,
teach_command,
)
POLL = 5 # seconds between looks at the flags
REOFFER_AFTER = 20 # seconds after the students left before the next offer
MAX_REOFFERS = 200 # the fuse under an evening of rests
# Minutes with no student in the class before the teacher stops and
# logs out (the operator, 2026-10-02: "he should log out if he has no
# teachees" — a helper whose student's ;train died taught an empty
# room until told).
ALONE_MINUTES = 5
clock = time.monotonic # tests replace it
def log_out(s, why):
"""STOP TEACHING, said, then QUIT — a script's own QUIT passes the
session's policy, as ;logout's does."""
ask(s, "stop teaching")
s.echo(f"teach: {why} — logging out")
s.put("quit")
def offer(s, options, quiet=False):
"""TEACH once; "teaching" when the class is up (or was already),
else the failure named (said, unless `quiet`)."""
answer = ask(s, teach_command(options["skill"], options["student"]))
outcome = classify(answer, TEACH_OUTCOMES)
if outcome in ("teaching", "already"):
return "teaching"
first = (answer.strip().splitlines() or ["(silence)"])[0]
if outcome is None:
s.echo(f"teach: TEACH answered {first!r} — please report it")
return "unknown"
if not quiet:
s.echo(f"teach: {first}")
return outcome
def run(s, options):
if not options["skill"]:
s.echo(
"teach: which skill? ;teach <skill> to <student>, or ;teach <skill> open"
)
return
if offer(s, options) != "teaching":
s.echo("teach: no class — stopping")
return
who = options["student"] or "anyone"
s.echo(f"teach: teaching {options['skill']} to {who}")
s.flag("students left", *STUDENTS_LEFT)
s.flag("offer expired", *OFFER_EXPIRED)
s.flag("student joined", *STUDENT_JOINED)
offers = 1
alone_since = clock() # no student yet; None while one listens
retry_at = None # when the next re-offer goes out, None when none is due
absent = False # the student was not in the room at the last re-offer
try:
while True:
if not pause(s, POLL):
why = danger(s)
if why:
ask(s, "stop teaching")
s.echo(f"teach: {why} — stopping")
if "hostiles" in why:
flight.react(s, "teach")
return
if wants_stop(s):
break
break
if s.flagged("student joined"):
s.echo("teach: a student joined the class")
alone_since = None
left = s.flagged("students left")
expired = s.flagged("offer expired")
if (left or expired) and alone_since is None:
alone_since = clock()
if alone_since is not None and clock() - alone_since >= ALONE_MINUTES * 60:
log_out(s, f"no student for {ALONE_MINUTES} min")
return
if left or expired:
why = "the offer expired untaken" if expired else "the students left"
wait = 0 if expired else REOFFER_AFTER
s.echo(
f"teach: {why} — offering again" + (f" in {wait} s" if wait else "")
)
if wait and not pause(s, wait):
break
retry_at = clock()
if retry_at is not None and clock() >= retry_at:
outcome = offer(s, options, quiet=absent)
if outcome == "no student":
# Not in the room — walked off mid-class, its ;train
# stopped (#433: Fallanor taught on to nobody, then
# stayed logged in): offered again every
# REOFFER_AFTER until the alone timer logs out.
if not absent:
s.echo(
f"teach: {options['student'] or 'the student'} is not "
f"here — offering again every {REOFFER_AFTER} s, out after "
f"{ALONE_MINUTES} min alone"
)
absent = True
retry_at = clock() + REOFFER_AFTER
continue
if outcome != "teaching":
log_out(s, "the class could not be offered again")
return
absent = False
retry_at = None
offers += 1
if offers > MAX_REOFFERS:
log_out(s, "offered enough for one evening")
return
finally:
s.unflag("students left")
s.unflag("offer expired")
s.unflag("student joined")
ask(s, "stop teaching")
s.echo(f"teach: stopping as asked ({offers} offer(s))")
def main(s):
run(s, parse_teach_args(s.args or []))