-
Notifications
You must be signed in to change notification settings - Fork 69
City Generation
This generator controls most of procedural world generation in Arena.
seed <- 12345 # (unsigned 32-bit)
srand(x) <-
seed <- x
rnd() <-
seed <- seed * 7143469
return (seed >> 16) & 0xFFFF
There are eight city templates (five land-locked, three coastal) and seven town and village templates (five land-locked, two coastal):
templateCount <- cityId in coastalCities ? (isCity(cityId) ? 3 : 2) : 5
templateId <- cityId mod templateCount
templateName <- format("%s%d.MIF", baseName, templateId + 1)
where baseName
is CITY
, CITYW
, TOWN
, TOWNW
, VILLAGE
, or VILLAGW
.
Several template IDs are associated with a reserved block list:
- 1 => (15, 21)
- 2 => (12, 14, 15, 17)
- 5 (
CITYW1/TOWNW1/VILLAGW1
) => (29, 33, 34, 35) - 6 => (33, 34, 35)
- 7 (
CITYW3
) => (4, 5, 11, 17)
Other lists are empty.
- The coastal city list is 58 bytes
@43BD8
- The template filenames are
szlist @43C12
(6 elements) - The X, Y starting positions of templates are 44 bytes (22 pairs)
@43C85
- The name of the MIF for the IC (with the static layout) is
@43CB1
- The lists of the reserved blocks are
szlist @43CBE
(8 elements)
Each city is constructed from a square array of blocks numbered right-to-left, top-to-bottom. Cities are 6x6, towns 5x5, and villages 4x4.
# Block types
EMPTY=0
RESERVED=1
EQUIPMENT=2
MAGEGUILD=3
NOBLEHOUSE=4
TEMPLE=5
TAVERN=6
SPACER=7
HOUSES=8
# Helper functions
placeBlock(blockType) <-
do
pos <- rnd() mod SIZE
while plan[pos] != EMPTY
plan[pos] <- blockType
SIZE <- N*N
plan <- [EMPTY]*SIZE
citySeed <- (cityX << 16) + cityY
srand(citySeed)
for block in reservedBlocks
plan[block] <- RESERVED
placeBlock(EQUIPMENT)
placeBlock(MAGEGUILD)
placeBlock(NOBLEHOUSE)
placeBlock(TEMPLE)
placeBlock(TAVERN)
placeBlock(SPACER)
remainder <- countof EMPTY in plan
while remainder > 0
random <- rnd()
if random <= 0x7333 then placeBlock(HOUSES)
elseif random <= 0xA666 then placeBlock(TAVERN)
elseif random <= 0xCCCC then placeBlock(EQUIPMENT)
elseif random <= 0xE666 then placeBlock(TEMPLE)
else placeBlock(NOBLEHOUSE)
remainder <- remainder - 1
Each city template has a unique point where the layout begins. It is important to preserve the random number generator state after generating the plan.
X <- startX
Y <- startY
for block in plan
if block = RESERVED then continue
blockCode <- ("eq","mg","nb","tp","tv","ts","bs")[block-2]
variationCount <- (13,11,10,12,15,11,20)[block-2]
rotation <- ("a","b","c","d")[rnd() mod 4]
variation <- rnd() mod variationCount
if variation = 0 then variation <- variation + 1
blockName <- format("%sBD%d%s.MIF", blockCode, variation, rotation)
load blockName and merge it with the template at (X, Y)
X <- X + 20
if row ended
X <- startX
Y <- Y + 20
Interior names are generated immediately after the city creation in the following order: taverns, shops, temples. The tavern seed value is carried over from the city generation. X, Y
are the city local coordinates.
if shop or temple then
seed <- (X << 16) + Y
srand(seed)
endif
tavernSfx <- defaultTavernSfx
if tavern and cityid in coastalCities then
tavernSfx <- marineTavernSfx
seen <- []
for block in cityBlocks
if block menutype is the object currently generated then
if tavern then
do
m <- rnd() mod 23
n <- rnd() mod 23
hash <- (m << 8) + n
while hash in seen
tavernName <- tavernPfx[m] + " " + tavernSfx[n]
else if shop then
do
m <- rnd() mod 20
n <- rnd() mod 10
hash <- (m << 8) + n
while hash in seen
shopName <- shopPfx[m] + " " + shopSfx[n]
else # temple
do
model <- rnd() mod 3
vars <- (5,9,10)[model]
n <- rnd() mod vars
hash <- (model << 8) + n
while hash in seen
shopName <- templePfx[model] + " " + (templeSfx[model])[n]
endif
<add the name and the current block pos into the corresponding list>
seen.add(hash)
if temple and cityid in (2, 0xE0) then
if cityid == 2 then
model, n <- 1, 7
else
model, n <- 2, 8
<generate a temple name with those values and replace the last temple with it>
endif
The shop names can have variables. x
, y
are the position of the shop door block on the city map.
%ct Replace with the city type string: "City-state", etc.
%ef Generate a male name for the current province with the seed (y<<16)+x, take the first name only
%n Generate a male name for the current province with the seed (x<<16)+y [sic!]
TODO: string positions.