home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Zodiac Super OZ
/
MEDIADEPOT.ISO
/
FILES
/
13
/
COMMIO0B.ZIP
/
COMMIO.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1996-05-20
|
56KB
|
1,560 lines
{$X+,A+,V-,R-,S-,O-,B-}
unit commio;
{
This is the Main Communications unit (COMMIO)
Written by Jason Morriss aka. Lief O'Pardy; (started on 7/26/95)
Copyright (C) 1995,1996 by Jason Morriss
Some real documentation will be written at a later date, for now you'll
just have to look at the procedure/function headers to see what each
routine does.
I will try to describe how to use these routines to setup any type of door
program for use on a BBS (a better description will be given when the DOC's
are written):
1) Get any and all information that you need about the USER and BBS when
your door starts. You need this information so you can setup the USER
and BBS variables. For instance, You need to know if the user is using
ANSI or not, what node s/he is on, etc... As for the BBS (this is most
important, without this step your door will probably not work at all
and will probably freeze the BBS), you need to find out what Comport
and the Baudrate the user is connected at, without this you cannot
communicate with the user at the remote end.
Either use a DROPFILE (the routines for this are not completed yet),
The command line, or an INI file...
Bare minimum get the Comport, Baudate, WhichIO (fossil, internal) and
MaxTimeAllowed!
2) Once all the important info has been put into the "DOOR" record (look
below for the door record), Make a call to the InitComport function.
If that function returns true then all is alright and you can continue,
otherwise you should halt the door so the BBS can take control again.
Then call InstallAllTasks so that the Timing variables will be setup,
and then you can forget about them. The user will be automatically
booted out if his/her time runs out. You can also optionally call
ShowStatusBar. This procedure displays a Statusbar at the bottom of
the screen. With info on the user, connection, local env., and time
remaining (Pressing F2 while in the DOOR will show the status line too).
3) You should now be able to do anything you want with your door. enjoy.
4) Most door libraries require you to call a certain procedure to DE-Init
the comport, etc... You dont have to do a thing with this library!
Just let your program exit normally. Look in the "_EXIT" unit for more
details. Its all done automatically, it wont hurt if you do call the
Deinitcomport() though...
}
interface
uses _exit, crt, dos, async, fosunit, mtask;
type
Tscreen = array[0..24,0..159] of byte;
TSystemEnv = (NoTasker{,DOS5},DDOS,DV,WIN,OS2,NetWare);
TWhichIO = ({LocalIO,}FossilIO,InternalIO);
TCharAry = array[0..0] of char;
string40 = string[40];
string12 = string[12];
{v- anything with an (R) in front of it, is READ ONLY; do not write to them
in your own door code.}
Tdoor = record (* Record for the more common "DOOR-System" variables *)
UserName : string[40];{user's name; could be alias or real}
{------------------------}
ComPort : byte; {Which Comport the program is using; 0=local}
Baudrate : longint; {Baudrate for the comport}
WhichIO : TWhichIO; {Which IO routines to use; fossil or internal}
IOinstalled : boolean; {comport IO routines installed?}
InBufSize : word; {Input buf size. (only for internal routines)}
OutBufSize : word; {Output buf size. (only for internal routines)}
IRQ : byte; {Which IRQ is being used}
WordSize : byte; {Wordsize (databits) for comport}
Parity : char; {parity for comport; 'N'=none 'E'=even 'O'=odd}
StopBits : byte; {stopbits for comport}
node : byte; {Which node the user is on (on BBS)}
{------------------------}
UseAnsi : boolean; {Is ansi used or not?}
{^ Even if in local mode, this must be true in order to use commands
that would use ANSI to the remote user. }
UseColor : boolean; {Is color used or not?}
UseAni : boolean; {Is animation used or not? (see putstr in doorio)}
SmartColor : boolean; {"Smart" mode ON/OFF for ansi color code sending}
LocalInputON: boolean; {Enable/Disable local keyboard input}
UpdateLocal : boolean; {Writes to the local screen are allowed or not?}
{R} UpdateStatusBar:boolean; {update status bar? (even if updatelocal=false)}
{R} UseVirtScr : boolean; {Use the virtual screen?}
StatusBarY : byte; {What line the status bar is displayed on}
LocalMaxY : byte; {# of lines (1-#) to update on local screen (usually 25)}
{------------------------}
{R} CurTime : DateTime; {Current Time. Updated consistently; 24h format}
SecsLeft : longint; {Seconds left until user is booted back to BBS}
{R} SecsOn : longint; {how long the user has been in the door}
KickOffIdle : integer;
{^# of secs the user can be idle before he gets booted back to the bbs.
This will "beep" the user once when the Idle Time is <= 30 seconds.
A value of -1 will disable the Auto-KickOff feature. (this variable
does not get decremented "CurIdle" does).}
{R} LocalKey : boolean; {Was the last key pressed local?}
OnLine : boolean; {Is user online/connected?}
PauseLine : byte; {# of lines to display before pausing output; 24=default}
{^ will probably be taken out.}
CurLine : byte; {Current line counter}
{^ will probably be taken out; use "virty" instead.}
{------------------------}
end;
const
CurIdle : integer = 0; {Idle counter for auto-kickoff feature}
IdleStart : longint = 0;
MaxTimeAllowed : word = 24*60; {Maximum time allowed in DOOR; in MINUTES}
{^ 2*60 = 2 hours.}
var
MacroStr : string; { Macro string; used in readkey funcs. }
door : tdoor; { "door-system" variables }
StartTime : datetime; { when user entered door }
SystemEnv : tsystemenv; { What OS is operating locally? }
KickedOut : boolean; { was user kicked out? (F6) }
Beeped : boolean;
const {virtual screen variables}
VirtScr : ^tscreen = nil; { Virtual Screen }
VirtX : integer = 1; { Virtual X screen position for cursor }
VirtY : integer = 1; { Virtual Y screen position for cursor }
{^ even if the virtual screen is not initialized, the VirtX/Y variables are
used to determine where the cursor is.
Anytime you want to know where the cursor is, use these variables. Do
NOT use WhereX/Y... sometimes you'll get the wrong result.}
var
SkipReadkey : boolean;
{^ special variable. if true, and the sysop pushes a syskey then; the
sioreadkey function will call the syskey function and then exit the
sioreadkey function itself, returning a nul (#0) char, then continuing
with the program. Its hard to explain. I needed this for the file
displaying file routines. you will never have to mess or even look at
this variable while programming (unless you really, really want too ;)}
{─--[headers]-──────────────────────────────────────────────────────────────}
Function InitComport:boolean;
{^ Initializes the comport for IO. This is normally the 2nd thing that is
called when your door starts (the 1st thing would either be reading a
DropFile, or INI file, or both). This must be called before any of the
other comport IO routines are called! (any procs. that use the modem). No
params are needed... because all the values needed are taken from the
"door" record (port,baud,parity), So the DOOR var must be setup first. }
Procedure DeInitComport;
{^ DeInitializes the comport. You can call this at the end of your door, but
you don't have to. It will be called automatically on its own at the end
of the program, its better if you don't call it.
(see also: AddToExitChain) }
Procedure ChangeIRQ(comport,irq:byte);
{^ Assigns the IRQ for the comport. This is for comports that use non
standard IRQ's only, if its a standard IRQ, then you don't need to call
this.
If this needs to be called, it must be called before InitComport()!
(this only works for the InternalIO, i don't know how a Fossil does it)}
Procedure ChangeFIFO(comport:byte; on:boolean);
{^ Lets you toggle the use of the receive FIFO's on the modem. By default,
the FIFO's will NOT be used. That is to avoid the conficts with some
modems that have buggy FIFO's. Chances are that, this can be turned on
without any problems, most modems (if not all) these days have "good" FIFO
buffers, but some older or "substandard" ones might not. }
Function CarrierDetect:boolean;
{^ Returns True if User is Connected, false if not. If door.comport=0
(local mode) then this always returns true. }
Procedure ReleaseTimeSlice;
{^ Gives up remaining CPU time to the rest of the OS. This procedure is
setup in the sioreadkey function already, along with a few other procedures.
You can use it for your own needs as well. }
Procedure BeginCritical;
{^ Begins a "Critical" block. After calling this under Multi-Tasking
systems, the majority of the CPU time will be given to your program,
until you call "EndCritical". This should be called right before sections
of code that need your program to be as "smooth" as possible. (If your
not under a MT system, than this does nothing) }
Procedure EndCritical;
{^ Ends a "Critical" block. This should be called after a call has been
made to "BeginCritical" and your "Critical" section is done. (it does
no harm if BeginCritical was not called before this), be sure to call this
at some point if you do call BeginCritical! Otherwise you'll probably slow
down the rest of the system until your door exits. }
Procedure sioCursorUp(n:byte);
Procedure sioCursorDown(n:byte);
Procedure sioCursorLeft(n:byte);
Procedure sioCursorRight(n:byte);
{^ Move the cursor n times in a any direction. If the cursor is already at
the maximum or minimum position in the direction its moving, it will not
move any further.
NOTE: This will only work if ANSI is enabled, otherwise any calls to this
procedure will be ignored. }
Procedure sioClrscr;
{^ Clears the screen with the current attribute.
NOTE: this works reguardless of ANSI being enabled. }
Procedure sioClrAbove;
{^ Clears everything above the cursor with the current attribute.
NOTE: This will only work if ANSI is enabled, otherwise any calls to this
procedure will be ignored. }
Procedure sioClrBelow;
{^ Clears everything below the cursor with the current attribute.
NOTE: This will only work if ANSI is enabled, otherwise any calls to this
procedure will be ignored. }
Procedure sioClrEol;
{^ Clears the current line starting from the current cursor position, to the
end of the line, w/o moving the cursor... This happens on the remote; and
local screen (according to updatelocal).
NOTE: This will only work if ANSI is enabled, otherwise any calls to this
procedure will be ignored. }
Procedure sioGotoxy(x,y:byte);
{^ Moves the cursor to the values in X,Y on the remote, and local screen
(according to updatelocal). The valid ranges are: X=1..80; Y=1..NumLines,
if either value is over the max range, nothing will happen.
NOTE: This will only work if ANSI is enabled, otherwise any calls to this
procedure will be ignored. }
Procedure FlushOutput;
{^ Flushes the output buffer. This procedure does not return until all the
output in the buffer has been sent to the remote. }
Procedure PurgeOutPut;
{^ Purges all output in the Output buffer. Anything in the buffer is not
displayed (or sent to remote). }
Procedure PurgeInput;
{^ Clears all input in the input buffer. Anything in the buffer will not be
read by the input routines. }
Procedure sioWriteC(c:char);
Procedure sioWritelnC(c:char); {append CRLF after the char}
{^ Writes a character to the comport, and the local screen (If updatelocal =
true). }
Procedure sioWriteN(n:longint);
Procedure sioWritelnN(n:longint); {append CRLF after the number}
{^ Writes any whole number to the comport, and the local screen (according to
updatelocal). You can use shortint,byte,integer,word & longints with this.
These procedures are useless since you can use TP's Write/ln procs!
(ie: write(IO,'The Number is: ',mynumber);
See TEXTDEV.PAS for more detials.}
Procedure sioWrite(s:string);
Procedure sioWriteln(s:string); {append CRLF after the string}
{^ Writes a string to the comport, and the local screen (according to
updatelocal). }
Function sioKeyPressed:Boolean;
{^ Returns True if a local key has been pressed (if LocalInputON), or if a
key is waiting in the Input buffer (from remote), or if the MACRO string
is NOT empty. This function will also call Switch_task once, and do a
Time Slice for you. }
Function sioReadkey:char;
{^ Reads either the first key in the INPUT buffer from the comport, or if a
local key was pressed, or if the MACROSTR is not empty then the next key
is taken from that. The scan code returned is just like pascals' readkey.
(except Function keys (F1-F12, AltF1-AltF12)) }
Procedure SetFore(fore:byte);
Procedure SetBack(back:byte);
Procedure SetColor(fore,back:byte);
{^ Sets the foreground and background colors to the values given. These
Procedures WILL actually send the ansi codes needed to change the color to
the remote screen, and change textattr locally.
If DOOR.SMARTCOLOR=true then this will only send the ansi codes if NEEDED.
ie: if you set the color to: (15,1) and the current color is already equal
to (15,1) then nothing will be sent, or if the current color is equal
to (7,1) then only the "bold" attribute will be sent, etc... This will
speed up repetitive color codes...}
Procedure ShowStatusBar;
{^ This redraws the Local Status Bar, but will not update the time variable
on the bar. This sets a window() so that the 25th line will not be
disturbed by the normal IO routines. If you want to write to the status
bar, then use the WriteStr() proc in the DOORIO unit. This will set
UpdateStatusBar:=true. }
Procedure HideStatusBar;
{^ This hides the Local Status Bar. This resets the window() so that the
25th line can be written to with the SIO routines. This will set
UpdateStatusBar:=false. }
Procedure RecordMacro(help:boolean);
{^
***This needs to be redone.
Record a Macro. Macros are limited to 255 chars. The recorded macro
will be put into the "door.macrostr" variable. Whenever the MACROSTR is
not empty, the input routines (sioreadkey) will keep returning chars from
the MACROSTR (the first char is used, then that 1st char is deleted to
get the next char ready.
help = This procedure has its own little built in help screen, telling
the user how to input a macro, and showing the different control
codes used. Set to TRUE if you want that screen to be shown,
set to FALSE otherwise. (you can show your own screen if you
wish) }
Procedure Wait(seconds:word);
{^
***This needs to be redone.
Wait a number of seconds. Seconds is not just an approximation like TP's
Delay() procedure, this is near perfect (i think). This also does Time
Slicing, & will Switch Tasks while "waiting".}
Procedure DisplayAnsiFile(fn:pathstr; lines:byte);
{^
***This needs to be redone. Lines in the file that are over 235 characters
might not be pharsed correctly!
Displays an ANSI file to the Remote and local screen. If ANSI has been
disabled (or if UseColor=false) then all ansi esc codes will be ignored
in the file and only the normal text will be displayed. This will also
pause the output. If the <space bar> is pressed during the ouput at any
time (except when paused), the output will stop, and the procedure will
exit. ANSI.SYS is NOT required locally for use of colors and movement.
If the <spacebar> is pressed, then the output will stop, and the procedure
will exit.
This proc. does not support the "Θ" codes, like the procedure below.
fn = path\filename of the file to be displayed. If the file is not
found, then an error message will be displayed instead. (locally
and remotely)
lines = number of lines to display before pausing the output. A 0 will
disable the pausing, so it will run continuously until EOF (or
<spacebar> is pressed ). The value can be anything from 0 to
255. }
Procedure DisplayTextFile(fn:pathstr; lines:byte);
{^ Same as the procedure above, except this does not support ANSI codes.
Actually, this does support ANSI, but only on the Remote side, Any ANSI
codes in the file will be written to the local screen as normal text. The
advantage of this procedure is that, it supports the color/animate coding
just like the putstr() procedure. And if ANSI is disabled then all color
and animation codes will be ignored, or if only color is disabled then no
colors will be changed. The "fn" and "lines" are the same as the
procedure above. }
Procedure ANSIWrite(s:string);
Procedure ANSIWriteln(s:string);
{^ These procedures write an ANSI string (containing ansi esc codes) to the
remote & _local_ sides. If ansion=false then ALL ansi esc codes will be
ignored, If usecolor=false then all color codes will be ignored, but other
ansi esc codes will be pharsed (like cursor movement). These procedures
will not strip "putstr" animation codes. You do NOT need ANSI.SYS loaded.}
function InitVirtScr : boolean;
{^ Sets up the virtual screen to be used and sets the door variable for it
also. This virtual screen is maintained by all the output routines in
the COMMIO library. Whenever something is displayed to the player it is
also written to the virtual screen.
When initializing the virtual screen, After you call this function you
should clear the screen (with a call to sioclrscr()).. to be sure that the
screens get "synchronized."
This feature can be useful for a couple of reasons:
1) This allows the user to "Refresh" his/her screen anywhere in the door,
if thier screen gets garbled from line noise or something. (this has
happened to just about everyone, right? ;) 2) If the door is running in
"Sysop Blockout Mode" (eg. nothing is being drawn to the local screen)
and at some point the door comes out of that mode, allowing the sysop to
see whats going on again... the door can update the local screen
immediately. The only drawback to these routines is that they slow down
the normal output routines in this library, But it probably won't be
noticable to anyone. }
procedure FreeVirtScr;
{^ Frees the Virtual Screen, and sets the door variable to reflect it.
After a call to this the Virtual Screen is not used, and will be a NIL
pointer if you try to access it.
This is called automatically when the program exits, so you dont have to
call it, but it doesnt hurt to either. }
procedure DrawScr(scr:pointer; x1,y1,x2,y2:byte);
{^ Refreshes the remote and local screens using the virtual screen. So that
must of been initialized first.
"scr" is a pointer to a buffer that holds the screen. It must point to an
array of tscreen (or similar array).
x1,y1,x2,y2 is the rectangle to draw.
NOTE: the very last char in the bottom corner (80,25) will NEVER be drawn.
Otherwise the screen will scroll up. }
implementation
uses SysKeys,TextDev,Doorio;
{^ These units must be delcared here, if you put them in the interface uses
statement, you will get a "circular unit reference" error. }
const
Bold : boolean = false;
CurColor : byte = 255;
ColAry : array[0..7] of byte = (0,4,2,6,1,5,3,7); {for setcolor}
OSStr : array[Tsystemenv] of string[17] = (
'DOS ',
'Double-Dos ',
'DesqView ',
'Windows ',
'OS/2 ',
'Network ' );
{^ not sure network detect works, it doesnt detect mine (lantastic)
i think it only works for novell networks. }
{───────────────────────────────────────────────────────────────────────────}
Function InitComport;
var b:boolean;
begin
InitComport:=false;
if door.IOinstalled then exit;
door.IOinstalled:=true;
b:=false;
with door do if comport>0 then begin
case WhichIO of
InternalIO : begin
b:=OpenCom(comport,InBufSize,OutBufSize);
if b<>false then begin
ComParams(comport,baudrate,wordsize,parity,stopbits)
{flow control is set by ComParams()}
{ SoftHandshake(comport,true,C_StartChar[comport],C_StopChar[comport]);{}
{ SetRTSmode(comport,true,C_RTSon[comport],C_RTSoff[comport]);{}
{ SetCTSmode(comport,true);{}
end;
end;
FossilIO : begin
b:=f_init(comport);
if b<>false then begin
f_parms(comport,baudrate,wordsize,parity,stopbits);{}
f_flow(comport,true); {enable RTS/CTS flow control (hardware)}
end;
end;
end; {of case}
end else b:=true; {local mode}
door.IOinstalled:=b;
if (CarrierDetect=false)
then b:=false
else begin
PurgeOutput;
PurgeInput;
end;
InitComport:=b;
door.online:=b;
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure DeInitComport;
begin
if not door.IOinstalled then exit;
with door do if (comport>0) then
case WhichIO of
InternalIO : begin
SetRTSmode(comport,false,0,0);
SetCTSmode(comport,false);
CloseCom(comport);
end;
FossilIO : begin
{ f_flow(comport,false);{}
f_close(comport);
end;
end;
door.IOinstalled:=false;
door.online:=false;
end;
{───────────────────────────────────────────────────────────────────────────}
Function CarrierDetect;
begin
if door.comport>0 then begin
case door.whichio of
internalIO : CarrierDetect := DCDstat(door.comport);
fossilIO : CarrierDetect := f_cd(door.comport);
end;
end else begin
CarrierDetect := true; {If in local mode, always return true}
end;
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure ChangeIRQ;
begin
C_PortInt[comport]:=irq;
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure ChangeFIFO;
begin
C_FifoOK[comport]:=on;
end;
{───────────────────────────────────────────────────────────────────────────}
{───────────────────────────────────────────────────────────────────────────}
Procedure DetectOS; assembler;
{CREDIT: Written by JON JASIUNAS; from his PD unit SHARE.PAS, i didn't feel
that this unit needed his entire unit, so i took his Time Slicing
routines only. Thanks Jon. I probably could of found this info
in R. Brown's INT listings, but was too lazy, and why should i
reinvent the wheel when its already made? ;> }
{This procedure is not in the interface section, because theres no need for
the programmer to call it. Its called once in this unit's init section.
(alllll the way at the bottom) }
asm
@CheckDV:
mov AX, $2B01
mov CX, $4445
mov DX, $5351
int $21
cmp AL, $FF
je @CheckDoubleDOS
mov SystemEnv, DV
jmp @Done
@CheckDoubleDOS:
mov AX, $E400
int $21
cmp AL, $00
je @CheckWindows
mov SystemEnv, DDOS
jmp @Done
@CheckWindows:
mov AX, $1600
int $2F
cmp AL, $00
je @CheckOS2
cmp AL, $80
je @CheckOS2
mov SystemEnv, WIN
jmp @Done
@CheckOS2:
mov AX, $3001
int $21
cmp AL, $0A
je @InOS2
cmp AL, $14
jne @CheckNetware
@InOS2:
mov SystemEnv, OS2
jmp @Done
@CheckNetware:
mov AX,$7A00
int $2F
cmp AL,$FF
jne @NoTasker
mov SystemEnv, NetWare
jmp @Done
@NoTasker:
mov SystemEnv, NoTasker
@Done:
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure ReleaseTimeSlice;
{CREDIT: "NetWare" time slice from JON JASIUNAS's SHARE.PAS, the rest i
found on my own. }
Begin
Case SystemEnv Of
NoTasker{,
DOS5} : asm int $28 end;
DDOS : asm mov ax,$EE01; int $21 end;
DV : asm mov ax,$1000; int $15 end;
WIN,OS2 : asm mov ax,$1680; int $2F end;
NetWare : asm mov bx,$000A; int $7A end;
End;
End;
{───────────────────────────────────────────────────────────────────────────}
procedure BeginCritical; assembler;
{CREDIT: Written by JON JASIUNAS; from his PD unit SHARE.PAS}
asm
cmp SystemEnv, DV
je @DVCrit
cmp SystemEnv, DDOS
je @DoubleDOSCrit
cmp SystemEnv, WIN
je @WinCrit
jmp @EndCrit
@DVCrit:
mov AX,$101B
int $15
jmp @EndCrit
@DoubleDOSCrit:
mov AX,$EA00
int $21
jmp @EndCrit
@WinCrit:
mov AX,$1681
int $2F
jmp @EndCrit
@EndCrit:
end;
{───────────────────────────────────────────────────────────────────────────}
procedure EndCritical; assembler;
{CREDIT: Written by JON JASIUNAS; from his PD unit SHARE.PAS}
asm
cmp SystemEnv, DV
je @DVCrit
cmp SystemEnv, DDOS
je @DoubleDOSCrit
cmp SystemEnv, WIN
je @WinCrit
jmp @EndCrit
@DVCrit:
mov AX,$101C
int $15
jmp @EndCrit
@DoubleDOSCrit:
mov AX,$EB00
int $21
jmp @EndCrit
@WinCrit:
mov AX,$1682
int $2F
jmp @EndCrit
@EndCrit:
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure FillWord(Var X; Count: Word; a:byte; c:char); Assembler;
{just like fillchar, except you give it 2 bytes to use for the fill (this is
also a 16bit procedure, unlike the 8bit fillchar TP uses). this is usefull
for filling in a text screen. }
Asm
les di,x
mov cx,[count]
shr cx,1
mov al,[c]
mov ah,[a]
rep stosw
test [count],1 {just incase you give it an odd count}
jz @end
stosb
@end:
end;
{───────────────────────────────────────────────────────────────────────────}
{───────────────────────────────────────────────────────────────────────────}
Procedure SendStr(s:string); {used internally; by a few procedures}
{send a string to the remote terminal}
begin
if CarrierDetect then begin
if door.comport>0 then
case door.whichio of
internalIO : I_ComWrite(door.comport, s);
fossilIO : f_Write(door.comport, s);
end;
end else begin
door.online:=false
end;
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure sioCursorUp;
var s:string[3];
begin
with door do if (UseAnsi)and(virty>1) then begin
if n>1 then str(n,s) else s:='';
SendStr(#27'['+s+'A');
dec(virty,n); if virty<1 then virty:=1;
if updatelocal then begin
gotoxy(virtX,wherey-n);
{ if virty<>y then dec(curline) else break;}
if (virty<=door.localmaxy) then showcursor;
end {else for i := 1 to n do if CurLine>1 then dec(CurLine) else break;}
end;
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure sioCursorDown;
var s:string[3];
begin
with door do if (UseAnsi)and(virty<25) then begin
if n>1 then str(n,s) else s:='';
SendStr(#27'['+s+'B');
inc(virty,n); if virty>25 then virty:=25;
if updatelocal then begin
gotoxy(virtX,wherey+n);
{ if virty<>y then inc(CurLine) else break;}
if (virty>door.localmaxy) then hidecursor;
end {else for i := 1 to n do if CurLine<50 then inc(CurLine) else break;}
end;
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure sioCursorRight;
var s:string[3];
begin
with door do if (UseAnsi)and(virtx<80) then begin
if n>1 then str(n,s) else s:='';
SendStr(#27'['+s+'C');
inc(virtx,n); if virtx>80 then virtx:=80;
if updatelocal then gotoxy(virtX,virtY);
end;
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure sioCursorLeft;
var s:string[3]; i:byte;
begin
with door do if (UseAnsi)and(virtx>1) then begin
if n>80 then n:=80;
if n>1 then str(n,s) else s:='';
SendStr(#27'['+s+'D');
dec(virtx,n); if virtx<1 then virtx:=1;
if updatelocal then gotoxy(virtX,virtY);
end;
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure sioClrScr;
begin
with door do begin
if UseAnsi then SendStr(#27'[2J') else SendStr(#12);
if updatelocal then clrscr;
CurLine:=1;
end;
virtx:=1; virty:=1;
if door.usevirtscr then fillword(virtscr^,sizeof(virtscr^),textattr,' ');
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure sioClrAbove;
begin
{ ... }
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure sioClrBelow;
begin
{ ... }
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure sioClrEol;
begin
with door do if UseAnsi then begin
SendStr(#27'[K');
if updatelocal then clreol;
end;
if door.usevirtscr then
fillword(virtscr^[virty-1,(virtx-1)*2],(80-virtx+1)*2,textattr,' ');
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure sioGotoxy;
begin
with door do if UseAnsi then begin
SendStr(#27'['+istr(y,0)+';'+istr(x,0)+'H');
if updatelocal then begin
gotoxy(x,y);
if (y>door.localmaxY) then hidecursor else showcursor;
end;
{ CurLine:=crt.WhereY;{}
end;
if (x>0)and(x<81) then virtx:=x;
if (y>0)and(y<26) then virty:=y;
end;
{───────────────────────────────────────────────────────────────────────────}
Function sioKeyPressed;
var b:boolean;
begin
b:=false;
if CarrierDetect then begin
if door.comport>0 then
case door.whichio of
internalIO : b:=ComBufferLeft(door.comport, 'I')>0;
fossilIO : b:=f_Avail(door.comport);
end;
if door.LocalInputON and (not b) then b:=keypressed;
end else begin
door.Online:=false;
end;
sioKeyPressed:=b;
if not b then begin
ReleaseTimeSlice;
switch_task;
end;
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure SetAttr(attr:byte);
begin
SetColor(attr mod 16, attr shr 4);
end;
{───────────────────────────────────────────────────────────────────────────}
{───────────────────────────────────────────────────────────────────────────}
Procedure FlushOutput;
begin
if (Door.IOInstalled)and(CarrierDetect) then
case door.WhichIO of
InternalIO : ComWaitForClear(door.comport);
FossilIO : f_flush(door.comport);
end;
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure PurgeOutput;
begin
if (Door.IOInstalled) and (door.comport>0) then
case door.WhichIO of
InternalIO : ClearCom(door.comport,'O');
FossilIO : f_kill_out(door.comport);
end;
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure PurgeInput;
begin
if (Door.IOInstalled) and (door.comport>0) then
case door.WhichIO of
InternalIO : ClearCom(door.comport,'I');
FossilIO : f_kill_in(door.comport);
end;
end;
{───────────────────────────────────────────────────────────────────────────}
procedure dovirt(c:char; yinc:byte);
{yinc should be ONLY 0 or 1!}
var i:byte;
begin
if not (c in [#07,#08,#10,#13]) then begin {dont write control codes!}
if door.usevirtscr then begin
virtscr^[virty-1,(virtx-1)*2]:=byte(c);
virtscr^[virty-1,(virtx-1)*2+1]:=textattr;
end;
inc(virtx);
end else case c of
{#07 : cursor does not move}
#08 : if virtx>1 then dec(virtx);
#10 : inc(virty);
#13 : virtx:=1;
end;
if (virtx>80)or(virty>25)or(yinc>0) then begin
if (virtx>80) then virtx:=1;
if virty<25 then inc(virty) else begin
virty:=25;
if door.usevirtscr then begin
move(virtscr^[1],virtscr^[0],4000-160); {scroll it up 1 line}
fillword(virtscr^[24],160,textattr,' '); {clear the bottom line}
end;
end;
end;
if (door.updatelocal) then
if (virty<=door.localmaxy) then showcursor else hidecursor;
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure sioWriteC;
const cnt:byte=0;
begin
if CarrierDetect then begin
if door.comport>0 then begin
if CurColor<>TextAttr then SetAttr(CurColor);
case door.whichio of
internalIO : ComWriteChW(door.comport, c);
fossilIO : f_SendChar(door.comport, c);
end;
end;
end else door.online:=false;
if (door.updatelocal){and not((virty>=door.localmaxy)and(c=#10))and(virty=wherey)}
then write(c);
{draw to the virtual screen}
dovirt(c,0);
{ door.CurLine:=WhereY;{}
inc(cnt); if cnt>=150 then begin cnt:=0; switch_task; end;{}
{ ^ every 150 calls to this procedure results in a switch_task. It's
stupid to Switch_task's every character with this procedure. }
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure sioWritelnC;
const cnt:byte=0;
begin
if CarrierDetect then begin
if door.comport>0 then begin
if CurColor<>TextAttr then SetAttr(CurColor);
case door.whichio of
internalIO : I_ComWriteln(door.comport, c);
fossilIO : f_Writeln(door.comport, c);
end;
end;
end else door.online:=false;
if (door.updatelocal)and not((virty>=door.localmaxy)and(c=#10)) and(virty=wherey)
then writeln(c);
{draw to the virtual screen}
dovirt(c,1);
inc(door.CurLine);
inc(cnt); if cnt>=100 then begin cnt:=0; switch_task; end;{}
{ ^ every 100 calls to this procedure results in a switch_task. It's
stupid to Switch_task's every character with this procedure. }
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure sioWriteN;
{const cnt:byte=0;}
var i:integer; s:string[12];
begin
str(n,s);
for i := 1 to length(s) do siowritec(s[i]);
(* if CarrierDetect then begin
if door.comport>0 then begin
if CurColor<>TextAttr then SetAttr(CurColor);
case door.whichio of
internalIO : I_ComWrite(door.comport, s);
fossilIO : f_Write(door.comport, s);
end;
end;
end else door.online:=false;
if door.updatelocal then write(s);
if door.UseVirtScr then begin
{draw to the virtual screen}
end;
inc(cnt); if cnt>=25 then begin cnt:=0; switch_task; end;{}
{ ^ every 25 calls to this procedure results in a switch_task.
}*)
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure sioWritelnN;
{const cnt:byte=0;}
var i:integer; s:string[12];
begin
str(n,s);
for i := 1 to length(s)-1 do siowritec(s[i]);
siowritelnc(s[i+1]);
(* if CarrierDetect then begin
if door.comport>0 then begin
if CurColor<>TextAttr then SetAttr(CurColor);
case door.whichio of
internalIO : I_ComWriteln(door.comport, s);
fossilIO : f_Writeln(door.comport, s);
end;
end;
end else door.online:=false;
if door.updatelocal then writeln(s);
if door.UseVirtScr then begin
{draw to the virtual screen}
end;
inc(door.CurLine);
inc(cnt); if cnt>=15 then begin cnt:=0; switch_task; end;{}
{ ^ every 15 calls to this procedure results in a switch_task. }*)
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure sioWrite;
var i:integer;
begin
for i := 1 to length(s) do siowritec(s[i]);
(* if CarrierDetect then begin
if door.comport>0 then begin
if CurColor<>TextAttr then SetAttr(TextAttr);
case door.whichio of
internalIO : I_ComWrite(door.comport, s);
fossilIO : f_Write(door.comport, s);
end;
end;
end else door.online:=false;
if door.updatelocal then write(s);
if door.UseVirtScr then begin
{draw to the virtual screen}
end;
switch_task;*)
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure sioWriteln;
var i:integer;
begin
for i := 1 to length(s)-1 do siowritec(s[i]);
if i>length(s)
then writeln(SIO,'')
else writeln(SIO,s[i+1]);
(* if CarrierDetect then begin
if door.comport>0 then begin
if CurColor<>TextAttr then SetAttr(CurColor);
case door.whichio of
internalIO : I_ComWriteln(door.comport, s);
fossilIO : f_Writeln(door.comport, s);
end;
end;
end else door.online:=false;
if door.UpdateLocal then writeln(s);
if door.UseVirtScr then begin
{draw to the virtual screen}
end;
switch_task;*)
end;
{───────────────────────────────────────────────────────────────────────────}
Function sioReadkey;
var ch:char; found:boolean; cnt:byte;
begin
with door do begin
CurIdle:=0; {reset auto-kickoff time with each keypress}
IdleStart:=SecsOn;
beeped:=false; {so it only beeps once when <= 30 secs left}
cnt:=0;
ch:=#0;
found:=false;
repeat
{ if not CarrierDetect then begin door.online:=false; exit; end;{}
if (LocalInputON)and(not found) then begin
if keypressed then begin
ch:=readkey;
found:=(ch<>#0);
if ch=#0 then begin
ch:=readkey;
if ch in [F1..F10,F11,F12, AltF1..AltF10,AltF11,AltF12] then begin
CallKey(ch);
if SkipReadKey then begin
sioreadkey:=#1;
exit;
end;{}
end else begin
found:=true;
localkey:=true;
end;
end else LocalKey:=true;
end;
end;
if (not found)and(comport>0) then begin
case whichio of
internalIO : begin
found:=ComBufferLeft(comport, 'I')>0;
if found then ch:=ComReadCh(comport);
localkey:=not found;
end;
fossilIO : begin
found:=true;
if f_avail(comport)
then ch:=f_ReadChar(comport)
else found:=false;
localkey:=not found;
end;
end;
end;
if (not found)and(MacroStr<>'') then begin
found:=true;
if MacroStr[1]='^' then begin {pharse out control/extended codes}
delete(MacroStr,1,1);
if MacroStr<>'' then begin
case MacroStr[1] of
'M','m' : ch:=#13; {carriage return}
'[' : ch:=#27; {esc key}
'^' : ch:='^'; {karet}
'~' : begin {pause 1 second}
wait(1);
delete(MacroStr,1,1);
if MacroStr<>'' then ch:=MacroStr[1] else found:=false;
end;
else ch:=MacroStr[1]; {else: read as normal character}
end;
delete(MacroStr,1,1);
end else found:=false;
end else begin
ch:=MacroStr[1];
delete(MacroStr,1,1);
end;
end;
if cnt>=100 then begin
cnt:=25;
ReleaseTimeSlice;
end else inc(cnt);
switch_task;
until found;
curline:=1;
sioreadkey:=ch;
end;
end;
{───────────────────────────────────────────────────────────────────────────}
{───────────────────────────────────────────────────────────────────────────}
Procedure SetFore;
begin
setcolor(fore,textattr shr 4);
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure SetBack;
begin
setcolor(textattr mod 16, back);
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure SetColor(fore,back:byte);
var
b,oldb,Fcol,oldbold,bold,blnk:byte;
s:string[15];
begin
if (not door.UseAnsi)or(Fore+(Back shl 4)=textattr) then exit;
if Back>7 then begin
blnk:=5; b:=128; dec(back,8);
end else begin
blnk:=0; b:=0;
end;
Fcol:=(Fore and $07);
bold:=(Fore and $08) shr 3;
oldbold:=((curcolor mod 16) and $08) shr 3;
oldb:=(curcolor and $80);
if (door.smartcolor) then begin
s:=#27'[';
if (oldb<>b) {blinking on/off}
then s:=s+istr(blnk,0)+';';
if (oldbold<>bold)or((oldb<>b)and(b=0)and(bold<>0)) {bold on/off}
then s:=s+istr(bold,0)+';';
if (fcol<>(curcolor and $07)) {foreground}
then s:=s+istr(colary[Fcol]+30,0)+';';
if (back<>(curcolor and $70)) {background}
then s:=s+istr(colary[back]+30,0);
if (s[length(s)]=';') then s[length(s)]:='m' else s:=s+'m';
end else begin
s:=#27'['+istr(blnk,0)+';'
+istr(bold,0)+';'
+istr(colary[Fcol]+30,0)+';'
+istr(colary[Back]+40,0)+'m';
end;
if length(s)>3 then SendStr(s);
TextAttr:=Fore+(Back shl 4)+b;
CurColor:=TextAttr;
end;
{───────────────────────────────────────────────────────────────────────────}
{───────────────────────────────────────────────────────────────────────────}
Procedure ShowStatusBar;
var x,y:byte;
begin
door.UpdateStatusBar:=true;
door.localmaxy:=door.statusbary-1;
x:=virtx; y:=virty;
{ x:=crt.wherex; y:=crt.wherey;}
{ while y>=door.StatusBarY do begin
writeln; dec(y);
end;{}
window(1,1,80,door.StatusBarY-1);
gotoxy(x,y); if (y>door.localmaxy) then hidecursor {else showcursor};
with door do begin
WriteStr(1,door.StatusBarY,'ΘbΘ8│ΘF∙∙Θ7:ΘF∙∙Θ7:ΘF∙∙Θ8│');
if comport<>0
then WriteStr(11,door.StatusBarY,'Θ7COMΘF'+istr(comport,0)+'Θ7,ΘF '+
padEstr(istr(baudrate,0),' ',6) )
else WriteStr(11,door.StatusBarY,'Θ7 Local Mode ');
WriteStr(23,door.StatusBarY,'Θ8│ΘF'+padEstr(username,' ',25)+'Θ8│Θ7'+
padEstr(OSStr[SystemEnv],' ',22)+'Θ8│Θ0F1Θ9:Θ0helpΘ8│');
end;
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure HideStatusBar;
var x,y,a:byte;
begin
door.UpdateStatusBar:=false;
door.localmaxy:=door.statusbarY;
x:=virtx; y:=virty;
window(1,1,80,door.StatusBarY);
gotoxy(1,door.StatusBarY);
a:=textattr; textattr:=7; clreol; textattr:=a;
gotoxy(x,y); showcursor; {incase it needs to be "popped into view"}
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure RecordMacro;
{■ This procedure will only record a macro up to 79 characters
This is a very cheesy procedure, and needs to be updated.}
var s:string[79];c:char; os:string;
begin
{ Save the current screen }
(* fillchar(TmpScreen^,sizeof(TmpScreen^),0);
move(mem[$B800:0000],TmpScreen^,Sizeof(TmpScreen^));
TextAttr:=7;
sioclrscr;
{help screen goes here}
putstr('Θ>');
os:=MacroStr;
c:=Getstr(s,79,[#233]+charset);
case c of
#13 : MacroStr:=s;
#27 : MacroStr:=os;
end;*)
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure Wait;
var
u,chs,shs,CurSec,StartSec: Word;
begin
GetTime(u,u,StartSec,shs);
while Seconds>0 do begin
{v- wait for 1 sec to go by; this isn't 100% correct, and should be changed}
repeat
GetTime(u,u,CurSec,chs);
ReleaseTimeSlice;
ReleaseTimeSlice;{}
until (CurSec<>StartSec){and(chs<=shs)};
StartSec:=CurSec;
Dec(Seconds);
end;
end;
{───────────────────────────────────────────────────────────────────────────}
{───────────────────────────────────────────────────────────────────────────}
Procedure DisplayAnsiFile;
label again;
var
f:text;
a:byte;{}
x,y,ta,l:byte;
ch:char;
st1:string[235];
st2:string;
extra,tmp:string[20];{}
begin
assign(f,fn);
{$I-} reset(f); {$I+}
if IOresult<>0 then begin
siowriteln(#13#10'File "'+fn+'" not found!');
wait(2);
exit;
end;
SkipReadkey:=true;
ch:=#13;
extra:=''; st1:=''; st2:='';
while not eof(f) do begin
{ read(f,st1);{}
if not eoln(f) then begin
again:
read(f,st1)
end else begin
readln(f,st1);
siowriteln('');
goto again;
end;{}
st2:=extra+st1;
if length(st2)>=high(st1) then begin
extra:=copy(st2,length(st2)-19,20);
a:=20;
while (extra[a]<>#27)and(a>=1) do dec(a);
if a>=1 then begin
delete(extra,1,a-1);
delete(st2,length(st2)-(20-a),(20-a));
end;
end else extra:='';
ANSIwrite(st2);
if siokeypressed then if sioreadkey=#32 then begin {space bar stops output}
PurgeOutput;
{ close(f);{}
break;
end;
if (lines<>0)and(door.CurLine<lines) then inc(door.Curline)
else if (lines<>0)and(ch<>'=') then begin
{ door.CurLine:=1;{}
ta:=textattr; {save the current color}
if door.UseAnsi then begin
x:=virtx; y:=virty;
sendstr(#27'[s');
end else begin
x:=1; y:=virty;
end;
{ putstr(#13'ΘaΘFMΘ7ore Θ8∙ ΘFSΘ7top Θ8∙ ΘFNΘ7on-Stop Θ7[M,s,n]');{}
putstr(#13'ΘaΘFMore? Θ7[ΘFYΘ7,ΘFnΘ7,ΘF=Θ7]: ');
ch:=hotkey(['Y','N','=',#13]);
putstr(#13'Θa '#13);
if door.UseAnsi then sendstr(#27'[u');
gotoxy(x,y);
textattr:=ta;
if ch='N' then break;
end;
{ switch_task;{}
end;
SkipReadkey:=false;
siowriteln('');
close(f);
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure DisplayTextFile;
begin
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure ANSIWrite;
{CREDIT: Written by Gayle Davis. Modified by Lief O'Pardy, its a little
faster, and more efficient. }
const
savex : byte = 1;
savey : byte = 1;
var
MusicStr : string;
MusicPos : integer;
{-----------------------------------}
Procedure ProcessEsc;
var
DeleteNum : integer;
ts : string[5];
Num : array[0..10] of shortint;
Color : integer;
Label
loop;
{-----------------------------------}
Procedure GetNum(cx : byte);
var
code : integer;
begin {getnum}
ts := '';
while (s[1] in ['0'..'9']) and (length(s) > 0) do begin
ts := ts + s[1];
Delete(s,1,1);
end;
val(ts,Num[cx],code)
end;
{-----------------------------------}
begin {processesc}
if s[2] <> '[' then exit;
Delete(s,1,2);
(* if (UpCase(s[1]) = 'M') and (UpCase(s[2]) in ['F','B',#32]) then begin
Delete(s,1,2);
MusicPos := pos(#14,s);
{ Play(copy(s,1,MusicPos-1));{}
DeleteNum := MusicPos;
Goto Loop;
end;*)
fillchar(Num,sizeof(Num),#0);
GetNum(0);
DeleteNum := 1;
while (s[1] = ';') and (DeleteNum < 11) do begin
Delete(s,1,1);
GetNum(DeleteNum);
inc(DeleteNum);
end;
case UpCase(s[1]) of
'A' : begin {move up}
if Num[0]=0 then Num[0]:=1;
sioCursorUp(Num[0]);
DeleteNum:=1;
end;
'B' : begin {move down}
if Num[0]=0 then Num[0]:=1;
sioCursorDown(num[0]);
DeleteNum:=1;
end;
'C' : begin {move right}
if Num[0]=0 then Num[0]:=1;
sioCursorRight(num[0]);
DeleteNum:=1;
end;
'D' : begin {move left}
if Num[0]=0 then Num[0]:=1;
sioCursorLeft(num[0]);
DeleteNum:=1;
END;
'H','F' : begin {goto xy}
if Num[0]=0 then Num[0]:=1;
if Num[1]=0 then Num[1]:=1;
sioGotoxy(Num[1],Num[0]);
DeleteNum:=1;
end;
'S' : begin {save current position}
SaveX := virtx;
SaveY := virty;
SendStr(#27'[s');
DeleteNum:=1;
end;
'U' : begin {restore saved position}
GotoXY(SaveX,SaveY);
SendStr(#27'[u');
DeleteNum:=1;
end;
'J' : begin {clear screen}
case num[0] of
0 : ; {clear everything below cursor}
1 : ; {clear everything above cursor}
2 : sioClrScr;
end;
DeleteNum:=1;
end;
'K' : begin {clear EOL}
sioClrEol;
DeleteNum:=1;
end;
'M' : begin
DeleteNum:=0;
while (Num[DeleteNum] <> 0) or (DeleteNum = 0) do begin
case Num[DeleteNum] of
0 : if door.USEcolor then begin
textattr:=7;
SendStr(#27'[0m');
Bold:=false;
end;
1 : if door.USEcolor then begin
Bold:=true;
HighVideo;
end;
5 : if door.USEcolor then textattr:=textattr or blink;
7 : if door.USEcolor then textattr:=((textattr and $07)shl 4)+((textattr and $70)shr 4);
8 : if door.USEcolor then textattr:=0;
30..37 : if door.USEcolor then begin
color := ColAry[Num[DeleteNum]-30];
if Bold then inc(color,8);
textcolor((textattr and blink)+color);
end;
40..47 : if door.USEcolor then textbackground(ColAry[Num[DeleteNum]-40]);
end; {of case}
inc(DeleteNum);
end; {while}
DeleteNum:=1;
end; {'M'}
'?' : begin delete(s,1,3); deletenum:=0; end;
{^- "thedraw" always puts this code at the beginning of any ansi
files it creates... why? who knows...}
end; {of case}
loop:
Delete(s,1,DeleteNum);
end;
{-----------------------------------}
begin
while length(s)>0 do begin
if s[1]=#27 then begin
ProcessEsc;
end else begin
sioWritec(s[1]);
Delete(s,1,1);
end;
end;
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure ANSIWriteLn;
begin
ANSIWrite(s);
sioWriteLn('');
end;
{───────────────────────────────────────────────────────────────────────────}
{───────────────────────────────────────────────────────────────────────────}
function InitVirtScr:boolean;
begin
initvirtscr:=false;
if not door.usevirtscr then begin
if (VirtScr=nil) and (maxavail>sizeof(VirtScr^)) then begin
getmem(VirtScr,sizeof(virtscr^));
fillword(virtscr^,sizeof(virtscr^),7,' '); {Clear the buffer}
virtx:=1; virty:=1;
door.UseVirtScr:=true;
end else door.UseVirtScr:=false;
InitVirtScr:=door.UseVirtScr;
end;
end;
{───────────────────────────────────────────────────────────────────────────}
procedure FreeVirtScr;
begin
if VirtScr<>nil then freemem(VirtScr,sizeof(virtscr^));
virtscr:=nil; {freemem does'nt assign "nil" to a freed ptr}
door.UseVirtScr:=false;
end;
{───────────────────────────────────────────────────────────────────────────}
procedure DrawScr(scr:pointer; x1,y1,x2,y2:byte);
{smart color should be ON for this procedure}
var x,y,vx,vy:byte;
begin
vx:=virtx; vy:=virty;
if scr=nil then begin
sioclrscr;
end else begin
for y := y1-1 to y2-1 do begin
siogotoxy(x1,y+1);
for x := x1-1 to x2-1 do if (y<>25-1)or(x<>80-1) then begin
textattr:=tscreen(scr^)[y,(x*2)+1];
siowritec(char(tscreen(scr^)[y,(x*2)]));
end;
end;
siogotoxy(vx,vy); {restore the cursor position}
end;
end;
{───────────────────────────────────────────────────────────────────────────}
{───────────────────────────────────────────────────────────────────────────}
Procedure CheckKickedOut; far;
{This doesn't get called directly. It's put into the ExitChain.}
begin
if KickedOut then begin
textattr:=15;
siowriteln(#13#10'» You have been kicked out of the DOOR; and are returning to the BBS! «'#13#10);
textattr:=7;
end;
{ putstr('Θ>Θ>Θ4ΘaΘ[»Θ] ΘCYou have been kicked out of the DOOR; and are returning to the BBS! Θ4Θ[«Θ]Θ>');}
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure COMMIO_Done; far;
{This doesn't get called directly. It's put into the ExitChain.}
begin
FlushOutput;{}
HideStatusBar;
NormVideo; {textattr:=7;}
FreeVirtScr;
{ writeln(#13#10'■ Shutting Comport down...');{}
DeInitComport;
{ wait(1);{}
end;
{───────────────────────────────────────────────────────────────────────────}
var u:word; l:longint;
begin
GetTime(starttime.hour,starttime.min,starttime.sec,u);
GetDate(starttime.year,starttime.month,starttime.day,u);
AddtoExitChain(COMMIO_Done);
AddtoExitChain(CheckKickedOut);
textattr:=7;
(* textmode(co80{+font8x8});*)
clrscr;
textattr:=15;
SystemEnv:=NoTasker;
DetectOS;{}
Case SystemEnv of
NoTasker : Writeln('■ No Multi-Tasker detected.');
DDOS : Writeln('■ Double-Dos detected.');
DV : Writeln('■ DesqView detected.');
WIN : Writeln('■ Windows detected.');
OS2 : Writeln('■ OS/2 detected.');
NetWare : Writeln('■ Network detected.');
end;
{ wait(1); {wait 1 second}
textattr:=7;
with door do begin
UserName := 'John Doe';
ComPort := 0;
Baudrate := 0;
WhichIO := InternalIO;
IOinstalled := false;
InBufSize := 512;
OutBufSize := 1024;
IRQ := 4;
WordSize := 8;
Parity := 'N';
StopBits := 1;
node := 0;
UseAnsi := true;
UseColor := true;
UseAni := true;
SmartColor := true;
LocalInputON:= true;
UpdateLocal := true;
UpdateStatusBar := true;
UseVirtScr := false;
StatusBarY := 25;
LocalMaxY := 25;
GetTime(curtime.hour,curtime.min,curtime.sec,u);
l:=MaxTimeAllowed div 60; {this must be done in two steps! otherwise it}
l:=l*60*60; {overflows a word and gives the wrong result}
SecsLeft := l;
SecsOn := 1;
KickoffIdle := 5*60;
LocalKey := true;
OnLine := true;
PauseLine := 24;
CurLine := 1;
end;
SkipReadkey:=false;
Beeped:=false;
KickedOut:=false;
CurColor:=TextAttr;
{ ShowStatusBar;{}
end. I AM GOD!