Langband technical intro

Langband, though based on Angband and feels pretty alike when playing it, is very different when you look at the code. It is written in a different language, structured differently and assuming any code-resemblance with standard Angband may prove problematic. Writing another "variant" with a drastic difference with the Angband code-base, which many good variants have been based on, might seem like a crazy project. It might very well be a crazy project, but sometimes one has to be crazy to further the development.

On the positive side, Langband possess some qualities over the standard Angband code-base:

Langband advantages

  • It is written in a different, and more powerful language: Common Lisp. Common Lisp is a high-level programmable programming language with an advanced object system and strong functional roots. This language removes the need for a separate scripting-language which the Angband-developers have wanted to add to Angband for a long time. Unlike classical scripting, Common Lisp code is compiled to native code and the "scripting" can exploit the full code of Langband.
  • Angband is a large program of more than 100 000 lines of code, and with more than a hundred global variables. The code, though well-commented and exceptionally structured for C-code, has most game-play and possibly customisable code hard-coded and any change is tough work and, more often than not: complex work. Langband has a different strategy; a small customisable engine for the basic parts, which a "variant" uses and adds details to. This means that Langband is an engine which variants can use/be plugged into. The size of the Langband code, engine and variant, is much smaller than the corresponding Angband code.
  • Langband uses the object system of Common Lisp liberally, and Angband has in many ways been turned into an object-oriented program. This object-orientation is central in making the engine extensible and customisable. Only a selected few areas of the code have been made into non-extensible constructs to optimise speed in places where this is needed.
  • [Add more later.]

But we might want to jump to the technical side of Langband, how things are structured.

Engine <-> Variant <-> Level

[Please note that all parts of the code is written in CAPS-LOCK here to be visible in the text. You're very strongly encouraged to write in only small letters any code to avoid breaking compatibility.]

A variant is an encapsulation of all the features which make the game fun to play: fun levels, objects, monsters, classes, races, flavouring of objects and fun rooms. All these things can be customised for a variant, and the engine has nothing of this hardcoded. Other parts of the engine may also be customised; equipment handling, shops, etc.

The variant object is available to the engine and it's own code in the global dynamical variable *VARIANT*, just as the player object is available in the *PLAYER* variable.

Also available globally is the *LEVEL* object, which points to the current level explored. The engine provides a random level (RANDOM-LEVEL) type which is the basic random level which is probable to be common among variants, but a variant may tailour this and add new level-types. A level-type defines it's own dungeon-generation, which monsters and objects may be found and other characteristica. The town-level in Vanilla angband is such a special, or themed, level. Langband is structured to make it easy to add your own levels and choose for your variant what kind of levels are to be created when.

A variant may also define it's own room-types, which may be vaults, shop-rooms, churches, elven courts, dragon's den, etc. This code has not been fully expanded yet, but it should have the same customisability as a level. A level-type may also define which rooms may be generated for that level.

Another useful global dynamical variable is the *DUNGEON* object, which is the technical representation of the current level. It may also be found by using the accessor (LEVEL.DUNGEON *LEVEL*).

Variant object

SlotStructure
attk-descsEQ hash-table, symbol -> description
skill-translationsassociation list, (from . to)
house-ownersEQL hash-table
house-typesEQL hash-table
flavour-typeslist of structs (FLAVOUR-TYPE)
filtersEQ hash-table
objectsEQ hash-table (see monsters)
monstersEQ hash-table, symbols -> struct game-obj-table
xp-tablearray with positive integers
max-charlevelpositive fixnum
max-depthpositive fixnum
Other slots:
 SORT-VALUES           #<EQL hash table, 35 entries {486D439D}>
 ROOM-BUILDERS         #<EQUAL hash table, 2 entries {486D43DD}>
 FLOOR-FEATURES        #<EQL hash table, 64 entries {486D441D}>
 LEVEL-BUILDERS        #<EQUAL hash table, 2 entries {486D445D}>
 TURN-EVENTS           #<EQUAL hash table, 0 entries {486D449D}>
 TURN                  138
 CLASSES               #<EQUAL hash table, 6 entries {486D44DD}>
 RACES                 #<EQUAL hash table, 10 entries {486D451D}>
 CONFIG-PATH           "./variants/vanilla/config"
 SYS-FILE              "./variants/vanilla/langband-vanilla.system"
 NAME                  "Vanilla"
 ID                    LANGBAND-VANILLA
 TWILIGHT-TIME         6000
 DAWN-TIME             0
Filter-table:
{:OBJECTS} -> {((LEVEL
                  . #<Function "DEFMETHOD ACTIVATE-OBJECT :BEFORE (VANILLA-VARIANT)"
                      {4836FC69}>))}
{:MONSTERS} -> {((TOWN-LEVEL
                  . #<Function "DEFMETHOD ACTIVATE-OBJECT :BEFORE (VANILLA-VARIANT)"
                      {4836F959}>)
                 (RANDOM-LEVEL
                  . #<Function "DEFMETHOD ACTIVATE-OBJECT :BEFORE (VANILLA-VARIANT)"
                      {4836FAE1}>))}
	  

Langband statistics [CVS 17th july]

  • 49 classes + 11 structs
  • 50 generic functions (with 254 methods)
  • 436 functions
  • 38 macros
  • 45 dynamic variables
  • 208 constants

Langband symbols

This is an attempt to list certain symbols that one should be careful about manipulating, as they're used by the engine internally.

VARIANTS
Has info on the possible variants available. Any slot may be used..
COMMON
Has information about things common to all variants, mainly the initialisation. Used: PRE-INIT and POST-INIT.

Langband events

[Please rewrite]

This is an attempt to list known events that are triggered and the order they're triggered in. Listed as:
:EVENT-NAME [CLASSNAME,:SETTING-KEY] - (arg1, arg2, ...)

Birth

Dungeon object is NIL. :on-pre-equip is called before adding of racial/class equipment, while :on-post-equip is called after racial/class equipment. All items existing in inventory/equip-slots after post-equip will be identified.

  • :on-pre-equip [birth-settings, :birth] - (dungeon player)
  • :on-post-equip [birth-settings, :birth] - (dungeon player)

Objects

Player and dungeon arguments are NIL. There might exist valid values at *player* or *dungeon* though.

  • :on-create [object-kind, NIL] - (player dungeon active-object)

Compatibility with ordinary Angband code-base

Most of the code is derived from Vanilla Angband 2.9.0 and many of the function names are taken directly from the Vanilla-code but some are changed and more will be changed as things progresses and Langband finds its own system to do things in. You should not expect Angband-ways of doing things to work.

Important simple changes is that all Angband underscores are now hyphens, and that the code relies very little on global variables (ie dungeon tables, player object, etc). Other changes may be found in the style guidelines.

Some functions which may be important to remember when going from C/Angband to Lisp/Langband:

      Angband:         Langband:
      rand_int         random
      randint          randint
      /                int-/