home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Zodiac Super OZ
/
MEDIADEPOT.ISO
/
FILES
/
13
/
COMMIO0B.ZIP
/
TASKUNIT.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1996-05-14
|
14KB
|
354 lines
{$O-,F+} {must not be overlayed; but should be far for most procedures.}
unit TASKunit;
{
This unit is a companion to the COMMIO communications unit.
Written by Jason Morriss a.k.a. Lief O'Pardy
Copyright (C) 1995,1996 by Jason Morriss
This is the TASK unit. This unit contains the tasks to be used when the
door runs. Each Task "Multi-Tasks" with the main program, all of which is
controlled by "Switch_Task" (meaning this is not interrupt driven). Most
of the routines in the COMMIO package will do switches on ther're own. But
if you create your own routines that have medium/long periods of time where
they do not call any IO routines in the COMMIO unit then you should add
the "switch_task" procedure to your routines as well. Its easy, and i
don't want you to get discouraged about this. Look at some of the routines
in the COMMIO unit (readkey, write/ln, etc) for examples in action...
This unit sets up the following tasks:
Time_Task: Updates the time variables for the user. (How long the user
has been on; how much time is left for the user in the door)
If the user's time expires, a message is displayed to the
user then the door is HALTed immediately, No matter what the
program was doing. Then the ExitChain starts. (more details
are below)
Stat_Task: Updates the statusbar on the bottom of the local screen. The
only thing that gets updated on it, is the time (if
UpdateStatusBar=True). You can change how the status bar
looks, really easily (but that requires a recompilation).
CD_Task : Detects when the carrier is lost. If the carrier is lost, or
if door.online=false then the door is HALTed immediately, No
matter what the program was doing. Then the ExitChain starts.
You can also put your own tasks into this unit. Just don't make the
procedure too large, its kinda like creating an interrupt procedure,
it should take the LEAST amount of time possible to complete its task
(unless you have multiple switch_task calls in the procedure).
Inside the procedure should be an endless repeat until..loop, and thats
where ALL of your code for that procedure should be located. Because if
the procedure exits, then it will be removed from the Task list, and will
not be called again, unless you "install" it again. But if you want it
to do that, thats fine too. Look at the procedures that are already
created below to see what i mean, if you don't understand. A procedure
can still be removed from the task list using Kill_Task() in the MTASK
unit.
This unit also contains all the "Sysop Keys". I have created a default
set that should meet the requirements of almost any door game. You can
alter the ones given, or add more of your own, or you dont have to use
any at all, ... up to you.
If any procedure halts the program, this is what happens:
The program is stopped wherever it is, then the ExitChain will go
through all procedures in the chain. If you have something that MUST
be run before the door returns to the BBS, then it would be wise to put
that procedure into the ExitChain, That way the procedure will always
be called, even if the user drops carrier (or if a runtime error
occurs). Look in the _EXIT unit for more info on setting up a
procedure in the ExitChain. Doing this is almost a requirement for any
door game, since most doors need to save some sort of info on the user
to disk, but if the user were to get disconnected (coughhangupcough) or
something, then everything that user did during his/her session will be
lost.
}
interface
uses crt, dos, async, commio, doorio, syskeys, mtask;
Procedure InstallAllTasks;
{^ Installs all of the tasks created in this unit. If ANY ONE of the tasks
does not install because of not enough memory, or some other error, then
the DOOR will terminate, because most of the tasks ARE needed for proper
operation of the DOOR (time variables). }
{Procedure InstallSysopKeys;{}
{^ Installs all the Default Sysop Keys (Fkeys). These can be modified anyway
you need them to be. This is called automatically in _THIS_ units' init
section below. }
implementation
var
useless:byte;
{$F+} {most (if not all) of these procs need to be far. incase i forget the
"far" word somewhere below, on a FAR procedure...}
{───────────────────────────────────────────────────────────────────────────}
Procedure F1Key(var p); far;
{F1: help key, displays functions of all sysop keys to the sysop. Remember,
none of the text here gets sent to the remote side, and the cursor stays
with whatever the user is doing (all of the text written here, uses
direct screen writes; which doesn't move the cursor), and will not mess
up the color for the remote user. }
var
key : char absolute p;
sy,x,y,i,a : byte;
oldmem : longint;
ch : char;
oinput,done : boolean;
fs : string[11];
begin
{ door.updatelocal:=false;{}
oinput:=door.localinputON;
door.localinputON:=false;{}
{v- prepare the screen for the help box}
x:=wherex; y:=wherey;
if door.UpdateStatusBar
then sy:=door.StatusBarY-6
else sy:=door.StatusBarY-4;
if y>=sy then begin
if door.updatestatusbar
then gotoxy(1,door.StatusBarY-1)
else gotoxy(1,door.StatusBarY);
while y>=sy do begin
writeln; dec(y);
end;
end;
window(1,1,80,sy-1);
gotoxy(x,y);
if door.comport>0 then begin
if door.whichio=internalio then
if C_fifook[door.comport] then fs:='Enabled ' else fs:='Disabled '
else fs:='Fossil mode';
end else fs:='Local mode ';
{v- draw help box locally}
Writestr(1,sy+0,'Θ8Θb╒══════════════════════════════════════════════════════════════════════════════╕');
WriteStr(1,sy+1,'Θ8Θb│ Θ7F1 Θ9:Θ3 This help box Θ7F4 Θ9:Θ3 -5 min. to user time Θ9│Θ3 Memory: '+
padestr(istr(maxavail,0),' ',6)+' bytes Θ8│');
WriteStr(1,sy+2,'Θ8Θb│ Θ7F2 Θ9:Θ3 Toggle Status Bar Θ7F5 Θ9:Θ3 Chat with user Θ9│Θ3 FIFOS: '+fs+' Θ8│');
WriteStr(1,sy+3,'Θ8Θb│ Θ7F3 Θ9:Θ3 +5 min. to user time Θ7F6 Θ9:Θ3 Kick user out of DOOR! Θ9│Θ3 Θ8│');
if door.updatestatusbar then begin
WriteStr(1,sy+4,'Θ8Θb├────────┬────────────┬─────────────────────────┬──────────────────────┬───────┤');
WriteStr(1,sy+5,'Θ8Θb│Θ3timeleftΘ8│Θ3connect infoΘ8│Θ3current user online Θ8│Θ3local environment Θ8│Θ3dduuhh!Θ8│')
end else begin
WriteStr(1,sy+4,'Θ8Θb╘══════════════════════════════════════════════════════════════════════════════╛');
end;
oldmem:=MaxAvail;
done:=false;
repeat
if MaxAvail<>oldmem then begin
WriteStr(67,sy+1,padestr(istr(maxavail,0),' ',6));
oldmem:=MaxAvail;
end;
switch_task
until keypressed; {local keypresses only!}
while keypressed do readkey; {"}
{v- clean up}
x:=wherex; y:=wherey;
a:=textattr; textattr:=7; {dont disturb the user's color}
if door.updatestatusbar then begin
window(1,sy,80,door.StatusBarY-1); clrscr;
window(1,1,80,door.StatusBarY-1);
end else begin
window(1,sy,80,door.StatusBarY); clrscr;
window(1,1,80,door.StatusBarY);
end;
textattr:=a; {"}
gotoxy(x,y);
door.localinputON:=oinput;
syskey1[key].open:=false;
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure FunctionKeys(var p); far;
{This handles all of the Fkey operations found on the F1 help box}
var b1,b2:boolean; ch:char;
begin
case char(p) of
F2 : if door.UpdateStatusBar then begin
door.UpdateStatusBar:=false;
HideStatusBar;
end else begin
door.UpdateStatusBar:=true;
ShowStatusBar;
end;
F3 : begin
inc(door.SecsLeft,5*60);
if door.SecsLeft>(24*60*60) then door.SecsLeft:=(24*60*60);{}
{notice i dont update the time on the statusbar... that gets done
automatically! -cool huh? :}
end;
F4 : begin
dec(door.SecsLeft,5*60);
if door.SecsLeft<0 then door.SecsLeft:=1;
{"}
end;
F5 : if door.comport<>0 then begin {dont chat in Local mode}
{do chat}
end;
F6 : begin
b1:=door.updatestatusbar;
b2:=door.localinputon;
door.LocalInputON:=false;
if not door.UpdateStatusBar
then ShowStatusBar; {incase it wasn't on; it must be on}
WriteStr(11,door.StatusBarY,'ΘFΘb'+padestr(' ',' ',79-(11-1)));
WriteStr(11,door.StatusBarY,'ΘFΘbAre you sure you want to ΘCKICK OUTΘF the user? [y,N]: Θ[_Θ]');
repeat
repeat switch_task until keypressed;
ch:=upcase(readkey);
if ch=#0 then {ch:=} readkey;
if ch=#13 then ch:='N';
until ch in ['Y','N'];
if ch='Y' then begin
KickedOut:=true;
door.online:=false; {kick user back to BBS; at the next switch_task()}
{do NOT call switch_task here!}
end;
if not b1 then HideStatusBar else ShowStatusBar;
door.LocalInputON:=b2;
end;
end; {case}
syskey1[char(p)].open:=false;
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure InstallSysopKeys;
begin
SetSysopKey(F1,F1key,512*5);
SetSysopKey(F2,FunctionKeys,512*6); {only 1 of}
SetSysopKey(F3,FunctionKeys,512*6); { these gets}
SetSysopKey(F4,FunctionKeys,512*6); { used at}
SetSysopKey(F5,FunctionKeys,512*6); { at a}
SetSysopKey(F6,FunctionKeys,512*6); { time.}
end;
{───────────────────────────────────────────────────────────────────────────}
{───────────────────────────────────────────────────────────────────────────}
Procedure SecToTime(Secs:longint; var h,m,s:word);
begin
if Secs>=3600 then begin
h:=Secs div 3600;
Secs:=Secs-(Secs div 3600)*3600;
end else h:=0;
if Secs>=60 then begin
m:=Secs div 60;
Secs:=Secs-(Secs div 60)*60;
end else m:=0;
s:=Secs;
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure TimeElapsed(h1,m1,s1,h2,m2,s2:word; var eh,em,es:word);
var t1,t2,t:longint;
begin
if h1<h2 then inc(h1,24);
t1:=(h1*3600)+(m1*60)+s1; {get total number of seconds}
t2:=(h2*3600)+(m2*60)+s2; {get total number of seconds}
t:=t1-t2;
SecToTime(t,eh,em,es);
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure Time_Task(var p); far;
{Update time variables for the user; this does not update the status bar}
var
oh,om,os,u,h,m,s:word;
begin
repeat
with door do begin
oh:=curtime.hour; om:=curtime.min; os:=curtime.sec;
GetTime(curtime.hour,curtime.min,curtime.sec,u);
TimeElapsed(curtime.hour,curtime.min,curtime.sec,oh,om,os, h,m,s);
SecsLeft:=SecsLeft-((h*3600)+(m*60)+s);
SecsOn:=SecsOn+((h*3600)+(m*60)+s);
if SecsLeft<0 then begin
{ online:=false;{}
terminate('■ Time limit exceeded! Returning to BBS...');
end;
end;
switch_task;
until false; {never ends!}
end;
var Time_size : word;
{───────────────────────────────────────────────────────────────────────────}
Procedure CD_Task(var p); far;
{Monitor remote connection}
var os:longint;
begin
{ if (door.comport=0) then exit;{}
repeat
if door.KickOffIdle>0 then with door do begin
if CurIdle<KickOffIdle then begin
CurIdle:=(SecsOn-IdleStart);
if (CurIdle>=KickOffIdle-30) and (not beeped) then begin
beeped:=true;
siowrite(#7);
end;
end else if (curidle<>-1) then begin
putstr('ΘaΘCΘ*Θ.Θ[ «« Idle timeout! »» Θ]Θ.');
door.online:=false;
end;
end;
if (not CarrierDetect) then begin
textattr:=lightred;
writeln(#10#13'■ Carrier Dropped...');
door.online:=false;
end;
if (not door.online) then halt;
switch_task;
until false; {never ends!}
end;
var CD_size : word;
{───────────────────────────────────────────────────────────────────────────
procedure PokeStr(s:string; x,y:byte);
var i:byte;
begin
for i := 1 to length(s) do DVwrite(x+i-1, y, Screen[y,(x+i-1)*2], s[i]);
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure Stat_Task(var p); far;
{update local status bar; This task requires the "Time_Task" to be installed}
const os:longint=$FFFFFFFF;
var h,m,s:word; i:byte;
begin
repeat
if (door.UpdateStatusBar) then with door do begin
SecToTime(SecsLeft,h,m,s);
if SecsLeft<>os then {only update when needed (time changed since last)}
WriteStr(2,StatusBarY,'ΘFΘb'+istr(h,2)+'Θ7:ΘF'+istr(m,2)+'Θ7:ΘF'+istr(s,2));
os:=SecsLeft;
end;
switch_task;
until false; {never ends!}
end;
var Stat_size : word;
{───────────────────────────────────────────────────────────────────────────}
{───────────────────────────────────────────────────────────────────────────}
Procedure InstallAllTasks;
var i,r:word;
begin
Time_size:=ofs(Time_size) - ofs(@Time_task^) + 1024*3;
create_task(time_task,useless,Time_size,i,r);
if r<>0 then terminate('SYSOP: Not enough memory to setup Time TASK!');{}
CD_size:=ofs(CD_size) - ofs(@CD_task^) + 1024*3;
create_task(CD_task,useless,CD_size,i,r);
if r<>0 then terminate('SYSOP: Not enough memory to setup Carrier TASK!');{}
Stat_size:=ofs(Stat_size) - ofs(@Stat_task^) + 1024*4;
create_task(Stat_task,useless,Stat_size,i,r);
if r<>0 then terminate('SYSOP: Not enough memory to setup Status TASK!');{}
end;
{───────────────────────────────────────────────────────────────────────────}
begin
InstallSysopKeys;
end.