-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCONQVMS.R
758 lines (592 loc) · 16.4 KB
/
CONQVMS.R
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
###############################################################################
#
# C O N Q V M S
#
# Copyright (C)1983-1986 by Jef Poskanzer and Craig Leres
#
# Permission to use, copy, modify, and distribute this software and
# its documentation for any purpose and without fee is hereby granted,
# provided that this copyright notice appear in all copies and in all
# supporting documentation. Jef Poskanzer and Craig Leres make no
# representations about the suitability of this software for any
# purpose. It is provided "as is" without express or implied warranty.
#
###############################################################################
#
# Detailed revision history lives in "incl/conqdef"
#
###############################################################################
include "conqdef"
define(JPI$_OWNER,16%00000303) # owner pid token for drcheck()
define(JPI$_PRIB,16%00000309) # base priority token for conqinit()
define(JPI$_CPUTIM,16%00000407) # cpu time token for gcputime()
### astoff - disable asts
#
# SYNOPSIS
# call astoff
#
subroutine astoff
NOIMPLICIT
call sys$setast( %val(0) ) # disable asts
return
end
### aston - enable asts
#
# SYNOPSIS
# call aston
#
subroutine aston
NOIMPLICIT
call sys$setast( %val(1) ) # enable asts
return
end
### astservice - ast service routine for conquest
#
# SYNOPSIS
# call astservice
#
# This routine gets called from a sys$setimr ast. Normally, it outputs
# one screen update and then sets up another timer request.
#
subroutine astservice
NOIMPLICIT
integer now, msg, modp1, dgrand
logical getamsg, stillalive, iochav, readone
include "conqcom"
include "conqcom2"
# Don't do anything if we're not supposed to.
if ( ! cdisplay )
return
# Don't do anything if we're dead.
if ( ! stillalive( csnum ) )
return
call drcheck # handle driver logic
# See if we can display a new message.
readone = .false.
if ( cmsgok )
if ( dgrand( cmsgrand, now ) >= NEWMSG_GRAND )
if ( getamsg( csnum, slastmsg(csnum) ) )
{
call readmsg( csnum, slastmsg(csnum) )
cmsgrand = now
readone = .true.
}
# Perform one ship display update.
call display( csnum )
# Un-read the message if there's a chance it got garbaged.
if ( readone )
if ( iochav( 0 ) )
slastmsg(csnum) = modp1( slastmsg(csnum) - 1, MAXMESSAGES )
# Schedule for next time.
call settimer
return
end
### comsize - return size of the common block (in bytes)
#
# SYNOPSIS
# integer size
# call comsize( size )
#
subroutine comsize( size )
NOIMPLICIT
integer size
include "conqcom"
size = %loc(glastmsg) - %loc(commonrev) + 4
return
end
### conqend - machine dependent clean-up
#
# SYNOPSIS
# call conqend
#
subroutine conqend
NOIMPLICIT
call gamend # clean up game environment
return
end
### conqinit - machine dependent initialization
#
# SYNOPSIS
# call conqinit
#
subroutine conqinit
NOIMPLICIT
integer i, lib$get_ef, t_getbpri, strcmp, gdespri
logical gdial, gprio, gcron
external c_conq_fdial, c_conq_fprio, c_conq_despri
external c_conq_badttys, c_conq_antigods, c_conq_conquest
external c_conq_gamcron, c_conq_newsfile, c_conq_fsubdcl, ss$_normal
character gamcron(FILENAMESIZE)
include "conqcom"
include "conqcom2"
# First things first.
if ( commonrev != COMMONSTAMP )
call error( "conquest: Common block ident mismatch." )
# Get priority for use when spawning.
if ( t_getbpri( cpriority ) != %loc(ss$_normal) )
call error( "conqinit: Failed to get base priority" )
# Get an event flag for the ast timer.
if ( lib$get_ef( ctimflag ) != %loc(ss$_normal) )
call error( "conqinit: Failed to allocate event flag" )
# Set up game environment.
gdial = ( %loc(c_conq_fdial) == YES )
gprio = ( %loc(c_conq_fprio) == YES )
gdespri = %loc(c_conq_despri)
# Figure out which gamcron file to use (and if we're gonna use one).
if ( %loc(c_conq_gamcron) == 0 )
{
gcron = .true.
call gamcronfile( gamcron )
}
else
{
call strcpy( c_conq_gamcron, gamcron )
gcron = ( gamcron(1) != 0 )
}
call gamlinit( gdial, gprio, gcron, gdespri, c_conq_antigods,
c_conq_badttys, c_conq_conquest, gamcron )
# Other house keeping.
call getpid( cpid )
csubdcl = ( %loc(c_conq_fsubdcl) == YES )
cnewsfile = ( strcmp( c_conq_newsfile, "" ) != 0 )
# Zero process id of our child (since we don't have one yet).
childpid = 0
# Zero last time drcheck() was called.
clastime = 0
# Haven't scanned anything yet.
clastinfostr(1) = EOS
return
end
### conqstats - handle cpu and elapsed statistics (DOES LOCKING)
#
# SYNOPSIS
# integer snum
# call conqstats( snum )
#
subroutine conqstats( snum )
NOIMPLICIT
integer snum
integer unum, team, cadd, eadd
include "conqcom"
cadd = 0
eadd = 0
call upstats( sctime(snum), setime(snum), scacc(snum), seacc(snum),
cadd, eadd )
# Add in the new amounts.
PVLOCK(lockword)
if ( spid(snum) != 0 )
{
# Update stats for a humanoid ship.
unum = suser(snum)
ustats(unum,USTAT_CPUSECONDS) = ustats(unum,USTAT_CPUSECONDS) + cadd
ustats(unum,USTAT_SECONDS) = ustats(unum,USTAT_SECONDS) + eadd
team = uteam(unum)
tstats(team,TSTAT_CPUSECONDS) = tstats(team,TSTAT_CPUSECONDS) + cadd
tstats(team,TSTAT_SECONDS) = tstats(team,TSTAT_SECONDS) + eadd
ccpuseconds = ccpuseconds + cadd
celapsedseconds = celapsedseconds + eadd
}
PVUNLOCK(lockword)
return
end
### dosubdcl - spawn a DCL subprocess
#
# SYNOPSIS
# call dosubdcl
#
subroutine dosubdcl
NOIMPLICIT
integer status, opriority, tccabort, lib$spawn, sys$setpri
character cdgetx
logical l, ioautobroad, stillalive
include "conqcom2"
include "cexith" # need to get at ccabort
string pmt "Press LINEFEED to spawn to DCL: "
external ss$_normal
if ( sys$setpri( , , %val(cpriority), opriority ) != %loc(ss$_normal) )
call cerror( MSG_GOD, "Dosubdcl(): Error setting base priority.", 0 )
call cdclrl( MSG_LIN1, 2 )
if ( cdgetx( pmt, MSG_LIN1, 1, TERMS, cbuf, MSGMAXLINE ) == TERM_EXTRA )
{
call stoptimer # turn off the timer ast
call cdclear
call cdredo
call cdmove( 1, 1 )
call cdplay( .false. )
l = ioautobroad( .true. ) # turn ON auto broadcast echoing
tccabort = ccabort # save old ^C setting
ccabort = NO # ignore while spawned
call ioend # only have to turn off iolb
call puts( "Your ship is now on automatic pilot.@n" )
call puts( "To resume command, type @"logout@".@n" )
call aston # enable asts while spawned
status = lib$spawn( ) # really default case...
call astoff
call ioinit
ccabort = tccabort # restore ^C setting
l = ioautobroad( .false. ) # turn OFF again
call cdclear
call cdredo
credraw = .true.
if ( stillalive( csnum ) )
call display( csnum )
call settimer # start the timer ast again
}
call cdclrl( MSG_LIN1, 1 )
if ( sys$setpri( , , %val(opriority), ) != %loc(ss$_normal) )
call cerror( MSG_GOD, "Dosubdcl(): Error resetting base priority.", 0 )
return
end
### drcheck - make sure the driver is still around (DOES LOCKING)
#
# SYNOPSIS
# call drcheck
#
subroutine drcheck
NOIMPLICIT
integer apid, ppid, dsecs, modp1, sys$getjpi
integer*2 list(8)
include "conqcom"
include "conqcom2"
equivalence (apid, list(3))
data list / 4, JPI$_OWNER, 2*0, 2*0, 2*0 /
external ss$_normal
# If we haven't been getting cpu time in recent history, do no-thing.
if ( dsecs( clastime, clastime ) > TIMEOUT_DRCHECK )
return
if ( dsecs( drivtime, playtime ) > TIMEOUT_DRIVER )
{
if ( childpid != 0 )
{
# We own the driver. See if it's still there.
apid = %loc(ppid)
if ( sys$getjpi( , childpid, , list, , , ) == %loc(ss$_normal) )
if ( ppid == cpid )
{
# He's still alive and belongs to us.
call gsecs( drivtime )
return
}
else
call cerror( MSG_GOD, "drcheck: Wrong ppid %x.", ppid )
# If we got here, something was wrong; disown the child.
childpid = 0
}
PVLOCK(lockword)
if ( dsecs( drivtime, playtime ) > TIMEOUT_DRIVER )
{
call drcreate
drivcnt = modp1( drivcnt + 1, 1000 )
call cerror( MSG_GOD, "Driver timeout #%d.", drivcnt )
}
PVUNLOCK(lockword)
}
call drstart
return
end
### drcreate - create a new driver process
#
# SYNOPSIS
# call drcreate
#
subroutine drcreate
NOIMPLICIT
integer i, pid, status, idsc(2), ndsc(2), modp1, sys$creprc
integer*2 epid(2)
character name(FILENAMESIZE)
include "conqcom"
include "conqcom2"
equivalence (cpid, epid)
external ss$_normal, c_conq_conqdriv
call gsecs( drivtime ) # prevent driver timeout
drivpid = 0 # zero current driver pid
drivstat = DRS_RESTART # driver state to restart
call dscbld( idsc, c_conq_conqdriv )
i = epid(1) # need bottom short word
call prints( name, "CONQDRIV_%04x", i )
call upper( name )
call dscbld( ndsc, name )
status = sys$creprc( pid, idsc, , , , , , ndsc, %val(cpriority), , , )
# Check for errors creating the process.
if ( status == %loc(ss$_normal) )
childpid = pid # remember this number
else
{
# We failed this time.
drivstat = DRS_OFF
call cerror( MSG_GOD, "drcreate: sys$creprc(), 0x%x", status )
}
return
end
### drkill - make the driver go away if we started it (DOES LOCKING)
#
# SYNOPSIS
# call drkill
#
subroutine drkill
NOIMPLICIT
integer i
include "conqcom"
include "conqcom2"
if ( childpid != 0 )
if ( childpid == drivpid & drivstat == DRS_RUNNING )
{
PVLOCK(lockword)
if ( childpid == drivpid & drivstat == DRS_RUNNING )
drivstat = DRS_KAMIKAZE
PVUNLOCK(lockword)
}
return
end
### drpexit - make the driver go away if we started it
#
# SYNOPSIS
# call drpexit
#
subroutine drpexit
NOIMPLICIT
integer i
include "conqcom"
include "conqcom2"
if ( childpid != 0 )
{
# We may well have started the driver.
call drkill
for ( i = 1; childpid == drivpid & i <= 50; i = i + 1 )
call sleep( 0.1 )
if ( childpid == drivpid )
call cerror( MSG_GOD,
"drpexit(): Driver didn't exit; pid = %08x", childpid )
}
return
end
### drstart - Start a new driver if necessary (DOES LOCKING)
#
# SYNOPSIS
# call drstart
#
subroutine drstart
NOIMPLICIT
include "conqcom"
if ( drivstat == DRS_OFF )
{
PVLOCK(lockword)
if ( drivstat == DRS_OFF )
call drcreate
PVUNLOCK(lockword)
}
return
end
### gcputime - get cpu time
#
# SYNOPSIS
# integer cpu
# call gcputime( cpu )
#
# DESCRIPTION
# The total cpu time (in hundreths) for the current process is returned.
#
subroutine gcputime( cpu )
NOIMPLICIT
integer cpu
integer status, flag, acpu, lib$get_ef, sys$getjpi, sys$clref, sys$waitfr
integer*2 jpilst(8)
external ss$_normal
data jpilst / 4, JPI$_CPUTIM, 6*0 /
equivalence (jpilst(3), acpu)
acpu = %loc(cpu)
status = sys$getjpi( , , , jpilst, , , )
if ( status != %loc(ss$_normal) )
call vmserror( "conqvms$gcputime(): sys$getjpi %s", status )
return
end
### helplesson - verbose help
#
# SYNOPSIS
# call helplesson
#
subroutine helplesson
NOIMPLICIT
character buf(MSGMAXLINE)
external c_conq_helpfile
call prints( buf, "%s: Can't open.", c_conq_helpfile )
call pagefile( c_conq_helpfile, buf, .true., .true. )
return
end
### initstats - statistics setup
#
# SYNOPSIS
# integer ctemp, etemp
# call initstats( ctemp, etemp )
#
subroutine initstats( ctemp, etemp )
NOIMPLICIT
integer ctemp, etemp
call gcputime( ctemp )
call grand( etemp )
return
end
### isagod - determine if a user is a god or not
#
# SYNOPSIS
# logical flag, isagod
# character name()
# flag = isagod( name )
#
# name - username
# flag - .true. or .false.
#
logical function isagod( name )
NOIMPLICIT
character name(ARB)
logical gamtname
external c_conq_gods
return ( gamtname( name, c_conq_gods, .false. ) )
end
### mail - send a one liner mail message (TOOLS mail version)
#
# SYNOPSIS
# logical sendok, mail
# character names(), subject(), msg()
# sendok = mail( names, subject, msg )
#
# Note: The buffer msg() will contain an error message if .false. is
# returned by this routine.
#
logical function mail( names, subject, msg )
NOIMPLICIT
character names(ARB), subject(ARB), msg(ARB)
call strcpy( "Mail not available", msg )
return ( .false. )
end
### mailimps - send a one liner mail message to the Implementors
#
# SYNOPSIS
# logical sendok, mailimps
# character subject(), msg()
# sendok = mailimps( subject, msg )
#
# subject - the subject of the message
# msg - the message
# sendok - .true. if the message was sent, else .false.
#
# Note: The buffer msg() will contain an error message if .false. is
# returned by this routine.
#
logical function mailimps( subject, msg )
NOIMPLICIT
character subject(ARB), msg(ARB)
logical mail
string mailaddr MAILADDR
if ( mailaddr(1) == EOS )
{
call strcpy( "It is not possible to contact the Implementors.", msg )
return ( .false. )
}
return ( mail( MAILADDR, subject, msg ) )
end
### news - list current happenings
#
# SYNOPSIS
# call news
#
subroutine news
NOIMPLICIT
external c_conq_newsfile
call pagefile( c_conq_newsfile, "No news is good news.", .true., .true. )
return
end
### settimer - set timer to call display()
#
# SYNOPSIS
# call csetimer
#
subroutine settimer
NOIMPLICIT
integer t(2), status, sys$setimr
data t / -10000000, -1 / # one second
include "conqcom2"
external ss$_normal, astservice
status = sys$setimr( %val(ctimflag), t, astservice, ctimid )
if ( status != %loc(ss$_normal) )
call cerror( csnum, "Error starting timer, status is 0x%x", status )
return
end
### stoptimer - cancel timer
#
# SYNOPSIS
# call stoptimer
#
subroutine stoptimer
NOIMPLICIT
integer status, sys$cantim
include "conqcom2"
external ss$_normal
cdisplay = .false.
status = sys$cantim( ctimid, )
if ( status != %loc(ss$_normal) )
call cerror( csnum, "Error canceling timer, status is 0x%x", status )
call aston
# Pending asts will flush here.
call astoff
cdisplay = .true.
return
end
### upchuck - update the common block to disk.
#
# SYNOPSIS
# call upchuck
#
subroutine upchuck
NOIMPLICIT
integer status, sys$updsec, sys$waitfr, inaddr(2), retaddr(2)
integer*2 iosb(4)
external ss$_normal
include "conqcom"
inaddr(1) = %loc(closed) # starting address
inaddr(2) = %loc(glastmsg) + 4 # last address
retaddr(1) = 0
retaddr(2) = 0
PVLOCK(lockword)
status = sys$updsec( inaddr, retaddr, , , %val(0), iosb, , )
if ( status == %loc(ss$_normal) )
{
status = sys$waitfr( %val(0) )
call getdandt( lastupchuck )
}
else
call cerror( MSG_GOD, "upchuck(): sys$updsec(), 0x%x", status )
PVUNLOCK(lockword)
return
end
### upstats - update statistics
#
# SYNOPSIS
# integer ctemp, etemp, caccum, eaccum, ctime, etime
# call upstats( ctemp, etemp, caccum, eaccum, ctime, etime )
#
subroutine upstats( ctemp, etemp, caccum, eaccum, ctime, etime )
NOIMPLICIT
integer ctemp, etemp, caccum, eaccum, ctime, etime
integer i, j, now, dgrand
# Update cpu time.
call gcputime( i )
caccum = caccum + i - ctemp
ctemp = i
if ( caccum > 100 )
{
# Accumulated a cpu second.
ctime = ctime + caccum / 100
caccum = mod( caccum, 100 )
}
# Update elapsed time.
eaccum = eaccum + dgrand( etemp, now )
if ( eaccum > 1000 )
{
# A second elapsed.
etemp = now
etime = etime + eaccum / 1000
eaccum = mod( eaccum, 1000 )
}
return
end