@pemit me=Looking for an existing Master Timer. Don't worry about "I don't see that here" messages. @switch/first isdbref(v(dbref_master_timer))+[owner(v(dbref_master_timer))]=1+%#,{@pemit me=Re-using object [v(dbref_master_timer))];},{@create Master Timer;&dbref_master_timer me=[num(Master Timer)];} @pemit me=Looking for an existing Timer Data. Don't worry about "I don't see that here" messages. @switch/first isdbref(v(dbref_timer_data))+[owner(v(dbref_timer_data))]=1+%#,{@pemit me=Re-using object [v(dbref_timer_data)];},{@create Timer Data;&dbref_timer_data me=[num(Timer Data)];&dbref_master_timer Timer Data=[v(dbref_master_timer)];} @pemit me=Looking for an existing Global Object. Don't worry about "I don't see that here" messages. @switch/first isdbref(v(dbref_global_object))+[owner(v(dbref_global_object))]=1,{@pemit me=Re-using object [v(dbref_global_object)];},{@create Global Object;&dbref_global_object me=[num(Global Object)];@set v(dbref_global_object)=COMMANDS;} @pemit me=Looking for an existing Global Object Parent. Don't worry about "I don't see that here" messages. @switch/first isdbref(v(dbref_global_object_parent))+[owner(v(dbref_global_object_parent))]=1,{@pemit me=Re-using object [v(dbref_global_object_parent)];},{@create Global Object Parent;&dbref_global_object_parent me=[num(Global Object Parent)];@parent [v(dbref_global_object)]=[v(dbref_global_object_parent)];} @pemit me=Looking for an existing Help Object. Don't worry about "I don't see that here" messages. @switch/first isdbref(v(dbref_help_object))+[owner(v(dbref_help_object))]=1,{@pemit me=Re-using object [v(dbref_help_object)];},{@create Help Object;&dbref_help_object me=[num(Help Object)];&dbref_help_object [v(dbref_global_object_parent)]=[num(Help Object)];} @fo me=&dbref_timer_data [v(dbref_master_timer)]=[num(Timer Data)] @fo me=&dbref_timer_data me=[num(Timer Data)] @fo me=@va [v(dbref_master_timer)]=[v(dbref_timer_data)] @fo me=@parent [v(dbref_master_timer)]=[v(dbref_timer_data)] @fo me=@link [v(dbref_timer_data)]=[v(dbref_master_timer)] @set [v(dbref_timer_data)]=sticky drop timer data &U_TRIGGER_LIST [v(dbref_master_timer)]=edit(lattr(%va/trw_*),TRW_,) &U_TRIGGER_LIST_SORTED [v(dbref_master_timer)]=setq(9,sort(iter(lattr(%va/trw_*),v(NHB_[after(##,_)]):##),))[setq(9,iter(%q9,after(##,:)))][edit(%q9,TRW_,)] @Desc [v(dbref_master_timer)]=It is presently:%r%t [ time() ]%rThe next Master Timer update will occur at:%r%t [ convsecs(v(next_heartbeat)) ]%r%t [ sub(v(next_heartbeat),secs()) ] seconds from now.%r%r[ljust(Triggers,9)] [rjust(Offset,6)] [rjust(Modulo,8)] CNT [ljust(Last,24)] [ljust(Next,24)]%r[repeat(-,79)][iter(u(u_trigger_list_sorted),%r[ljust(##,9)] [switch(v(OFF_##)+[v(MOD_##)],0+1,[space(15)] [rjust(v(CNT_##),3)] [space(24)],[rjust(v(OFF_##),6)] [rjust(v(MOD_##),8)] [rjust(v(CNT_##),3)] [switch(gt(v(LHB_##),0),1,convsecs(v(LHB_##)),space(24))])] [switch(gt(v(NHB_##),0),1,convsecs(v(NHB_##)),space(24))])] @Startup [v(dbref_master_timer)]=&last_restart me=secs();@trigger me/tr_kick_me; &TR_KICK_ME [v(dbref_master_timer)]=@drain me;&next_heartbeat me=u(u_next_beat);@wait me/[max(0,add(v(next_heartbeat),-[secs()],v(trigger_lag)))]=@tr me/tr_heartbeat; &TR_HEARTBEAT [v(dbref_master_timer)]=pose thinks.;@dolist filter(u_trigger_filt,u(u_trigger_list))={@tr me/TRW_##;pose triggers ## at [time()].%rPrevious: [convsecs(v(LHB_##))] Current: [convsecs(v(NHB_##))];&nhb_## %va=add(u(u_next_time_modulo,default(me/MOD_##,3600)),default(me/OFF_##,0));&lhb_## %va=secs();@switch/first setq(1,default(%va/cnt_##,#-1))%q1=#-1,{},1,{@wipe %va/*_##;},{&cnt_## %va=sub(%q1,1);};};@tr me/tr_kick_me; &TR_ONE [v(dbref_master_timer)]=@tr me/TRW_%0;&NHB_%0 %va=add(u(u_next_time_modulo,default(me/MOD_%0,3600)),default(me/OFF_%0,0));&LHB_%0 %va=secs();@switch/first setq(1,default(%va/cnt_%0,#-1))%q1=#-1,{},1,{@wipe %va/*_%0;},{&cnt_%0 %va=sub(%q1,1);};@trigger me/tr_kick_me; &TRIGGER_LAG [v(dbref_master_timer)]=-3 &U_NEXT_TIME_MODULO [v(dbref_master_timer)]=setq(9,secs())[add(sub(%q9,mod(%q9,%0)),%0,%1)] &U_TRIGGER_FILT [v(dbref_master_timer)]=gte(secs(),add(v(TRIGGER_LAG),v(NHB_%0))) &U_NEXT_BEAT [v(dbref_master_timer)]=first(sort(iter(lattr(%va/NHB_*),v(##)) [add(secs(),86400)])) @set [v(dbref_master_timer)]=COMMANDS @Use [v(dbref_master_timer)]=%r Invent an event name, for instance, 'THING'.%r Add two attributes to the Data object for the new event, as follows:%r%r%b%b MOD_THING Timer Data = How often THING's heart beats, in seconds.%r[space(5)]60 = once a minute%r[space(5)]3600 = once every hour%r[space(5)]86400 = once a day%r[space(5)]604800 = once a week%r[space(6)]etc%r%r%b%b TRW_THING%b%bTimer Data = code to trigger for THING.%r%r Additional values that are stored on the data object are:%r%b%b NHB_THING = Secs() value when THING be triggered next.%r%b%b LHB_THING = Secs() value when THING was last triggered.%r These are computed and stored automatically, you don't need to%r provide them yourself. &Desc [v(dbref_timer_data)]=Master Timer's Schedule:%r[ljust(Item,12)] [ljust(Scheduled,28)] [ljust(Trigger,36)]%rComment%r[repeat(-,79)][iter(u(v(dbref_master_timer)/u_trigger_list_sorted),%r[ljust(##,12)] [ljust(u(v(dbref_master_timer)/u_format_time,##),28)] [left(v(TRW_##),36)%r[v(COM_##)]])] @Use [v(dbref_timer_data)]=@pemit %#=See the Master Timer for instructions. @trigger [v(dbref_master_timer)]/tr_heartbeat @fo me=&DBREF_MASTER_TIMER [v(dbref_global_object_parent)]=[v(dbref_master_timer)] @fo me=&DBREF_TIMER_DATA [v(dbref_global_object_parent)]=[v(dbref_timer_data)] &DO_TIMER_LIST [v(dbref_global_object)]=$+timer/l*:@switch/first hasflag(%#,WIZARD)=1,{@pemit %#=get_eval(v(dbref_timer_data)/desc)},{@pemit %#=u(u_huh);} &DO_TIMER_SCHEDULE [v(dbref_global_object)]=$+timer/sc*:@switch/first hasflag(%#,WIZARD)=1,{@pemit %#=get_eval(v(dbref_master_timer)/desc)},{@pemit %#=u(u_huh);} &U_HUH [v(dbref_global_object)]=Huh?%b%b(Type "help" for help.) &TR_TIMER_CHECK [v(dbref_master_timer)]=@switch/all strmatch(get(v(dbref_timer_data)/trw_%0),@@)+[hasattr(v(dbref_timer_data),mod_%0)]=0+1,@pemit %1=Setup complete for Timer %0.,?+0,@pemit %1=Now use '+timer/set %0' to configure the period between events.,1+?,@pemit %1=Now use '+timer/trigger %0=command' to configure the @trigger or @pemit command the timer will execute.; &DO_TIMER_ADD [v(dbref_global_object)]=$+timer/add *=*:@switch/first setq(0,secure(%0))[setq(1,secure(%1))][hasflag(%#,WIZARD)]=1,{&com_%0 [v(dbref_timer_data)]=%q1;&trw_%0 [v(dbref_timer_data)]=@@;&nhb_%0 [v(dbref_timer_data)]=u(v(dbref_master_timer)/u_next_midnight);@pemit %#=switch(get(v(dbref_timer_data)/com_%q0),%q1,Event %q0 added with comment "%q1".,Error setting timer value. %q0 is not a good name.);@tr v(dbref_master_timer)/tr_timer_check=%q0,%#;@trigger v(dbref_master_timer)/tr_kick_me;},{@pemit %#=u(u_huh);} &DO_TIMER_SET [v(dbref_global_object)]=$+timer/set *=every *:@switch/first setq(0,secure(%0))[setq(1,secure(%1))][hasflag(%#,WIZARD)]+[and(isnum(%q1),gt(%q1,0))]=1+1,{&mod_%q0 [v(dbref_timer_data)]=%q1;&NHB_%0 [v(dbref_timer_data)]=add(u(v(dbref_master_timer)/u_next_time_modulo,default(v(dbref_master_timer)/MOD_%0,3600)),default(me/OFF_%0,0));@pemit %#=switch(get(v(dbref_timer_data)/mod_%q0),%q1,Modulo for Timer %q0 set to [get(v(dbref_timer_data)/mod_%q0)].,Error setting timer value. %q0 is not a good name.);@trigger v(dbref_master_timer)/tr_check_timer=%q0,%#;@trigger v(dbref_master_timer)/tr_kick_me;},1+0,{@pemit %#=The modulo value must be a positive number.},{@pemit %#=u(u_huh);} &DO_TIMER_TRIGGER [v(dbref_global_object)]=$+timer/trigger *=*:@switch/first setq(0,secure(%0))[hasflag(%#,WIZARD)]=1,{&trw_%q0 [v(dbref_timer_data)]=%1;@pemit %#=switch(get(v(dbref_timer_data)/trw_%q0),%1,Trigger code for Timer %q0 set to '[get(v(dbref_timer_data)/trw_%q0)]'.,Error setting timer trigger. %q0 is not a good name.);@pemit %#=switch(hasattr(v(dbref_timer_data),mod_%q0),1,Setup complete for Timer %q0.,Default Modulo is 3600 (top of the hour.)%r);@trigger v(dbref_master_timer)/tr_check_timer=%q0,%#;},{@pemit %#=u(u_huh);} &DO_TIMER_KICK [v(dbref_global_object)]=$+timer/kick *:@switch/first setq(0,secure(%0))[hasflag(%#,WIZARD)]+[hasattr(v(dbref_timer_data),trw_%q0)]=1+1,{@tr [v(dbref_master_timer)]/tr_one=%q0;@pemit %#=%q0 has been triggered.;},1+0,{@pemit %#=There is no such Timer.;},{@pemit %#=u(u_huh);} &DO_TIMER_DELETE [v(dbref_global_object)]=$+timer/delete *:@switch/first setq(0,secure(%0))[hasflag(%#,WIZARD)]+[hasattr(v(dbref_timer_data),trw_%q0)]=1+1,{@wipe [v(dbref_timer_data)]/*_%q0;@pemit %#=%q0 has been deleted.;@trigger v(dbref_master_timer)/tr_kick_me;},1+0,{@pemit %#=There is no such Timer.;},{@pemit %#=u(u_huh);} &DO_TIMER_OFFSET [v(dbref_global_object)]=$+timer/offset *=*:@switch/first setq(0,secure(%0))[setq(1,secure(%1))][hasflag(%#,WIZARD)]+[hasattr(v(dbref_timer_data),MOD_%q0)]+[isnum(%q1)]=1+1+1,{&off_%q0 [v(dbref_timer_data)]=%q1;@pemit %#=switch(get(v(dbref_timer_data)/off_%q0),%q1,Offset for Timer %q0 set to [get(v(dbref_timer_data)/off_%q0)].,Error setting timer value. %q0 is not a good name.);@trigger v(dbref_master_timer)/tr_check_timer=%q0,%#;@trigger v(dbref_master_timer)/tr_kick_me;},1+1+0,{@pemit %#=The offset value must be a number.},1+0+*,{@pemit %#=There is no such trigger. Please '+timer/add %q0=every value' or '+timer/trigger %q0=command' first.},0+*,{@pemit %#=u(u_huh);} &DO_TIMER_HELP [v(dbref_global_object)]=$+timer:@switch/first hasflag(%#,WIZARD)=1,{@pemit %#=get_eval(v(dbref_help_object)/wizhelp_timer);},{@pemit %#=u(u_huh)} &WIZHELP_TIMER [v(dbref_help_object)]=The syntax of the command is:%r%b%b+timer/add name=comment%r%b%b+timer/set name=every | daily at