Kingdom

This file is part of and Miscellaneous Programs. Download the collection to get this file.
Developer(s): Paul Holmgren
Date: 198x
Type: Program
Platform(s): TS 2068
Tags: Game, Software

Successfully manage your kingdom for 10 years to win.

Kingdom is a multi-player resource-management strategy game in which 1–4 players govern medieval kingdoms over five in-game years, each divided into four seasons. Each turn, players allocate their population among three tasks — mending dykes (flood prevention), planting grain, and defending against thieves — then face randomised consequences including floods, starvation, and raids. The program uses string arrays to store player names and a gender/age field to assign titles (King/Queen/Prince/Princess), and builds a scrolling landscape string in line 1360 by repeatedly tripling a base string. Two UDGs are defined from DATA for animated thief sprites, and a third UDG (“s”) is loaded for a separate graphic used during the introduction. A variation of Hamurabi.


Program Structure

The program is organised into a main loop and a collection of subroutines reached via GO SUB or GO TO. Execution begins at line 10 with a GO TO 1130 that skips to the setup block. The main game loop runs from line 50 to line 530, iterating over all players with a FOR p=1 TO a loop each season.

  1. Lines 10–40: REM header, startup jump, shared utility subroutines (keypress wait, screen clear).
  2. Lines 50–530: Main seasonal loop — season/year tracking, per-player turn, labour allocation, consequence resolution.
  3. Lines 540–820: Event subroutines — dyke failure (floods), defence failure (thieves), starvation.
  4. Lines 830–1120: Economy subroutines — starvation deaths, grain buying, grain selling.
  5. Lines 1130–1480: Setup, title screen, UDG loading, player data entry, initial resource assignment.
  6. Lines 1490–1590: Winner determination and display; line 1590 is a SAVE statement that auto-runs the program.
  7. Lines 1600–1680: Small utility subroutines: title assignment by gender/age, labour-overflow warning, spring planting input.

Data Structures and Arrays

ArrayDimensionsPurpose
n$(a,11)a × 11 charsPlayer name (cols 1–10) and gender flag (col 11)
u(a)aPlayer ages (used for title selection)
m(a)aMoney (dollars)
c(a)aGrain sacks
p(a)aPopulation
d(a)aSacks of grain planted in spring
n(a) / N(a)aRandom newcomers arriving each season
z(a)aFlood casualties display counter
x(a)aStarvation casualties display counter
t(a)aThief casualties display counter

Players start each game with c(p)=2500 sacks of grain, m(p)=1000 dollars, and p(p)=1000 people (line 1380–1400).

UDG Definition and Animation

Three UDGs are defined by reading bytes from DATA statements. Lines 1220–1230 load UDGs "a" and "b" simultaneously from interleaved data (16 bytes, alternating). Line 1260 loads UDG "s" from a third set of 8 bytes. The thief animation in lines 680–780 alternates between \a and \b characters with short PAUSE delays to create a two-frame walking sprite moving across the screen horizontally.

Landscape String Construction

Line 1350 initialises m$ with a 32-character base string of block graphics and caret characters. Line 1360 expands it by tripling it three times in a loop, then truncates to 838 characters with m$=m$( TO 838). This landscape is printed at line 370 as a scrolling backdrop. The expansion method — m$=m$+m$+m$ repeated — is an efficient way to build a long repeating string without a character-by-character loop.

Variable Case Ambiguity Bug

The Spectrum’s BASIC is case-sensitive for string variables but not for numeric ones. The program uses n(p) and N(p) interchangeably (lines 110 and 120), which refer to the same numeric array. However, a1, a2, a3 (lowercase) at lines 240–330 are used in computations, while the READ g$ at line 290 compares against G$ (uppercase) — on the Spectrum these are the same string variable, so this works correctly. The A$ used in the sell routine (lines 1020–1040) is distinct from a$ used in line 1040 itself; this inconsistency could cause a mismatch on strict interpreters.

Season and Year Tracking

The variable s cycles 1–4 representing Spring through Winter. Line 70 resets s to 0 (via NOT s, which evaluates to 0 when s is non-zero) after Winter, and line 50 increments it at the start of each pass. Line 80 increments the year counter y only in Spring. After five years the game ends at line 90 with a jump to the winner screen at 1490.

Season Name Assignment

Line 60 uses a Spectrum BASIC idiom for conditional string selection:

LET y$=("Spring" AND s=1)+("Summer" AND s=2)+("Autumn" AND s=3)+("Winter" AND s=4)

Each parenthesised expression evaluates to the string if the condition is true, or the empty string "" if false; the + operator concatenates them, yielding exactly one season name.

Title Assignment by Gender and Age

Subroutines at lines 1600–1610 use the same string-AND idiom to assign a title to each player’s ruler. Gender is stored in character position 11 of n$(p) and age in u(p). Players over 18 receive “King”/”QUEEN”; 18 or under receive “Prince”/”Princess”. Note the inconsistent capitalisation: “QUEEN” is all-caps while “King” is title-case.

Labour Allocation and Validation

Players input workers for each of three tasks (lines 240–330). Line 340 checks whether the total exceeds population: IF a1+a2+a3>p(p) THEN GO SUB 1620. The subroutine at 1620 prints a warning and returns to line 130 via GO TO 130 rather than RETURN, effectively restarting the turn for that player without re-initialising their state — a crude error recovery.

Planting Prompt Bug

Line 1630 contains a visible typo in the prompt string: "Pl LLIST nt how many sacks of grain?" — “Plant” has been corrupted to “Pl LLIST nt”, likely because the author typed the BASIC keyword LLIST accidentally mid-word while entering the string.

Flood Animation

Lines 570–590 animate a flood by printing solid-block characters () column by column across the screen using a nested loop. The width of the flood (k) is determined randomly (line 550) and capped at a fraction of the population (line 600). Casualties scale linearly with flood width: 10 people per flood-column, plus financial and grain losses for severe floods.

Market Economy

The grain market uses a randomly generated price each transaction (lines 890 and 1070). The buy price ranges from $13–$17 per sack, while the sell price ranges from $5–$9 — ensuring players always sell at a loss relative to buying, which discourages over-planting. Line 980 adds only 1 sack regardless of how many were purchased (LET c(p)=c(p)+1), which appears to be a bug; it should read LET c(p)=c(p)+i.

Winner Determination

Lines 1510–1560 iterate over all players and find the maximum M(p) value using a running maximum pattern. w is initialised to NOT a, which evaluates to 0 when a>0 — a slightly obscure way to write zero. The winner’s name is stored in W$ and displayed with FLASH 1 formatting at line 1570.

READ/RESTORE for Crop Names

Line 290 reads sequentially from DATA at line 1290 containing crop names ending with the sentinel "E". When the sentinel is encountered, RESTORE 1290 resets the data pointer and the read is repeated, creating a cycling list. This means each player’s turn uses the next crop name in sequence — “corn”, “wheat”, “rice”, “rye”, “barly” (note spelling) — cycling indefinitely.

Content

Related Products

Related Articles

Related Content

Image Gallery

Kingdom

Source Code

   10 REM KINGDOM
   20 CLS : GO TO 1130
   30 PRINT AT 21,4; FLASH 1;"TAP ANY KEY TO CONTINUE ": PAUSE 0: RETURN 
   40 FOR f=21 TO 9 STEP -1: PRINT AT f,0;"                                ": NEXT f: RETURN 
   50 LET s=s+1: REM START
   60 LET y$=("Spring" AND s=1)+("Summer" AND s=2)+("Autumn" AND s=3)+("Winter" AND s=4)
   70 IF s=4 THEN LET s=NOT s
   80 IF s=1 THEN LET y=y+1
   90 IF y>5 THEN GO TO 1490
  100 FOR p=1 TO a
  110 LET N(p)=INT (RND*10)
  120 LET p(p)=p(p)+n(p): CLS 
  130 PRINT TAB 8;y$;" of Year ";y
  140 IF n$(p,11)="m" OR n$(p,11)="M" THEN GO SUB 1600
  150 IF n$(p,11)="f" OR n$(p,11)="F" THEN GO SUB 1610
  160 PRINT r$;n$(p, TO 10)'n(p);" People came to the village."
  170 PRINT TAB 10;"Casualities:","Starved . Floods . Thieves"
  180 PRINT "    ";x(p);TAB 12;z(p);TAB 22;t(p): LET x=RND*6
  190 PRINT INK X;"********************************"
  200 PRINT TAB 10;"You have:";TAB 16-(LEN STR$ m(p))+2/2;"$";m(p);","
  210 PRINT TAB 16-(LEN STR$ p(p)+8)/2;p(p);" People."
  220 PRINT TAB 16-(LEN STR$ c(p)+15)/2;c(p);" Sacks of grain."
  230 PRINT INK X;"********************************"; INK 0;"Labor arrangement:"
  240 INPUT "Mending the dyke? ";a1
  250 IF INT a1<>a1 THEN GO TO 240
  260 PRINT "(A).Mending the dyke";TAB 31-(LEN STR$ a1);a1
  270 INPUT "Planting grain? ";a2
  280 IF INT a2<>a2 THEN GO TO 270
  290 READ g$: IF G$="E" THEN RESTORE 1290: GO TO 290
  300 PRINT "(B).Planting the ";G$;TAB 31-(LEN STR$ a2);a2
  310 INPUT "Defending the Kingdom? ";a3
  320 IF INT a3<>a3 THEN GO TO 310
  330 PRINT "(C).Defending Kingdom";TAB 31-(LEN STR$ a3);a3
  340 IF a1+a2+a3>p(p) THEN GO SUB 1620
  350 IF y$="Spring" THEN GO SUB 1630
  360 GO SUB ph: CLS 
  370 PRINT 'm$; INK 0 ;AT 8,14;"▛▀▀▀▀▜";AT 9,14;"▌    ▐";AT 10,14;"▌ "; INK 6;"^^"; INK 0;" ▐";AT 11,14;"▌    ▐";AT 12,14;"▙▄▄▄▄▟"
  380 PRINT AT 10,28;"\a"
  390 LET t(p)=0: LET z(p)=0: LET x(p)=0
  400 IF a1<p(p)/2.2 THEN GO SUB 540
  410 IF a3<p(p)/2.2 THEN GO SUB 650
  420 IF d(p)<p(p)*2 THEN GO SUB 830
  430 LET c(p)=c(p)/1.2+d(p)*3
  440 IF c(p)+d(p)>p(p)*2 THEN GO SUB 1000
  450 IF c(p)+d(p)<p(p)*2 THEN GO SUB 880
  460 LET p(p)=INT (p(p)*1.2)
  470 LET m(p)=INT (m(p)*1.09)
  480 LET c(p)=INT c(p)
  490 IF m(p)<0 THEN LET m(p)=0
  500 IF c(p)<0 THEN LET c(p)=0
  510 IF p(p)<0 THEN LET p(p)=0
  520 NEXT p
  530 GO TO 50
  540 IF INT (RND*3)+1=1 THEN RETURN : REM  DYKE 
  550 LET k=INT (RND*10)+5
  560 PAUSE ph
  570 FOR f=3 TO k+3
  580 FOR n=1 TO 19: PRINT AT n,f; BRIGHT 1; INK 1;"█": NEXT n
  590 NEXT f
  600 IF k*10>p(p) THEN LET k=INT (p(p)/10)
  610 LET p(p)=p(p)-k*10
  620 IF k>8 THEN LET m(p)=m(p)-(k-8)*100
  630 LET z(p)=k*10
  640 LET c(p)=INT (c(p)-k*15): RETURN 
  650 IF INT (RND*3)+1=1 THEN RETURN : REM  DEFEND 
  660 LET k=INT (RND*10)+5
  670 IF k*6>p(p) THEN LET k=INT p(p)/6
  680 FOR n=28 TO 16 STEP -1
  690 PRINT AT 10,n;"\a ": PAUSE 5
  700 PRINT AT 10,n;"\b ": PAUSE 5
  710 NEXT n
  720 FOR n=1 TO k
  730 PRINT AT 10,16;"@": PAUSE 9: PRINT AT 10,16;"©": PAUSE 5
  740 NEXT n
  750 FOR n=16 TO 27
  760 PRINT AT 10,n;" \s\a": PAUSE 3
  770 PRINT AT 10,n;" \s\b": PAUSE 3
  780 NEXT n
  790 LET p(p)=p(p)-k*6
  800 LET c(p)=c(p)-k*25
  810 LET m(p)=m(p)-k*15
  820 LET t(p)=k*6: RETURN 
  830 REM STARVE
  840 LET k=ABS (d(p)-p(p)*2)
  850 IF k>p(p) THEN LET k=p(p)
  860 LET p(p)=p(p)-INT k
  870 LET x(p)=k: RETURN 
  880 REM BUY
  890 LET k=INT (RND*5)+13: CLS 
  900 PRINT n$(p, TO 10)''"You haven""t got enough grain to feed your village-You must buy  some on the Common Market..."
  910 PRINT '"Current Market rate = $";k
  920 PRINT '"You have $";m(p)
  930 PRINT '"You can buy ";INT (m(p)/k);" sacks."
  940 INPUT "How many do you wish to buy?    ";i
  950 IF i>m(p)/k THEN GO TO 940
  960 PRINT i;" sacks will cost $";i*k
  970 LET m(p)=m(p)-k*i
  980 LET c(p)=c(p)+1
  990 GO SUB ph: RETURN 
 1000 REM sell
 1010 CLS : PRINT n$(p, TO 10)''"You have surplus grain. Do you  wish to sell any, if so input   the amount.     "; FLASH 1;"N= none"
 1020 INPUT "I am selling "; LINE A$
 1030 IF A$(1)="N" OR A$(1)="n" THEN RETURN 
 1040 IF a$="a" THEN LET a$=STR$ INT c(p)
 1050 LET k=VAL a$: IF k<=INT c(p) THEN GO TO 1070
 1060 PRINT ''"You can not sell that much at   this time.": GO SUB ph: GO TO 1000
 1070 LET j=INT (RND*5)+5
 1080 PRINT k;" sacks of grain, at  $";j
 1090 PRINT "a sack, making","$";k*j
 1100 LET m(p)=m(p)+k*j
 1110 LET c(p)=c(p)-k
 1120 GO SUB ph: RETURN 
 1130 REM SETUP
 1140 LET s=0: LET y=s
 1150 LET ph=30
 1160 PRINT '"   "; FLASH 1;"A ""PEH SOFTWARE"" SPECIAL"
 1170 PRINT ''; INK 1;"       *****************","       *               *"
 1180 PRINT "       * K i n g d o m *","       *               *"
 1190 PRINT INK 1;"       *****************"'' INK 0;" You have 5 years to govern your"''"kingdom. You must try to keep"''"alive as many of your serfs as"
 1200 PRINT '"possible, they have 3 jobs."''"You must protect them against"
 1210 GO SUB ph: GO SUB 40
 1220 DATA 24,24,24,24,231,36,36,100,36,189,24,24,36,36,66,36,0,0,0,0,255,255,102,102
 1230 FOR d=0 TO 7: READ r: POKE USR "a"+d,r: READ r: POKE USR "b"+d,r: NEXT d
 1240 PRINT "...(A)  FLOODS"'"...(B)  STARVATION"'"...(C)  THIEVES"
 1250 PRINT '"You have to be the richest"''"player after 5 years to "; FLASH 1;"WIN"; FLASH 0;"."
 1260 FOR d=0 TO 7: READ r: POKE USR "s"+d,r: NEXT d
 1270 GO SUB ph: GO SUB 40
 1280 INPUT "How many are playing ";a
 1290 DATA "corn","wheat","rice","rye","barly","E"
 1300 DIM n$(a,11): DIM u(a)
 1310 DIM M(a): DIM C(a)
 1320 DIM P(a): DIM D(a)
 1330 DIM N(a): DIM Z(a)
 1340 DIM x(a): DIM t(a)
 1350 LET m$="██████████████████████████^^^^^^"
 1360 FOR f=1 TO 3: LET m$=m$+m$+m$: NEXT f: LET m$=m$( TO 838)
 1370 FOR p=1 TO a
 1380 LET c(p)=2500
 1390 LET m(p)=1e3
 1400 LET p(p)=m(p)
 1410 INPUT "Who are you? "; LINE n$(p)
 1420 INPUT "How old are you? ";u(p)
 1430 INPUT "Are you ""M"" OR ""F"" "; LINE n$(p,11)
 1440 PRINT "Palyer No. ";p'n$(p, TO 10);" age = ";u(p);"  sex = ";n$(p,11)
 1450 INPUT "Is this O.K.? (Y/N) "; LINE h$
 1460 IF h$(1)="n" THEN GO TO 1410
 1470 NEXT p
 1480 GO TO 50
 1490 REM WINNER
 1500 PRINT '"AND NOW FOR THE "; FLASH 1;"WINNER"
 1510 LET W$="": LET w=NOT a
 1520 FOR P=1 TO A
 1530 PRINT N$(P, TO 10);" WITH $";M(P);","
 1540 IF M(p)>w THEN LET W$=N$(p, TO 10)
 1550 IF M(p)>w THEN LET W=M(p)
 1560 NEXT p
 1570 PRINT AT 10,0; FLASH 1;"Congratulations ";W$'' FLASH 0;"You are the "; FLASH 1;"WINNER"; FLASH 0;" of the game"''"with $";W
 1580 STOP 
 1590 SAVE "Kingdom" LINE 10
 1600 LET r$=("King " AND u(p)>18)+("Prince " AND u(p)<=18): RETURN 
 1610 LET r$=("QUEEN " AND u(p)>18)+("Princess " AND u(p)<=18): RETURN 
 1620 PRINT AT 20,3; INK 2;"Too many people": GO SUB ph: GO TO 130
 1630 INPUT "Pl LLIST nt how many sacks of grain?  ";d(p)
 1640 IF d(p)>c(p) THEN GO TO 1630
 1650 PRINT d(p);" sacks of ";G$;" planted."
 1660 LET c(p)=c(p)-d(p)
 1670 IF d(p)/10>a2 THEN LET d(p)=a2*10
 1680 RETURN 

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

Scroll to Top