-
Notifications
You must be signed in to change notification settings - Fork 13
COAL
COAL is a scripting language which EDGE-Classic uses it to define custom HUD modules. The standard COAL scripts for drawing the DOOM HUD are loaded from COALHUDS lump within edge-defs.wad The API that COAL itself is contained in is loaded from the COALAPI lump, which is a good reference to look at while developing your HUD. Take note that the API is hard-coded to EDGE-Classic. A wad may contain a lump called "COALHUDS" which is automatically loaded and will replace any definitions (functions etc) in earlier scripts.
The contents of each file or lump is simply the text of the COAL code. The engine provides two modules: the "hud" module provides drawing functions and general queries, whereas the "player" module provides query functions about the current player. All of their functions and variables are described in separate sections below.
In order to customize the default HUDs, your COAL code needs to redefine one of the existing functions, as follows:
doom_status_bar() : replace this function if you only want to customize the full status bar (including the one shown in the automap screen). The size has to be the same (width 320, height 32).
overlay_status_bar() : write your own version of this function if you only want to change the overlay status bar.
doom_automap() : this function draws the automap screen (including the status bar at the bottom). Replacing it means you can show other information here instead of (or in addition to) the automap.
draw_all() : this is the function which EDGE-Classic calls to draw everything. The normal version (in edge-defs.wad) will call the above functions depending on the user's current HUD and whether the automap is active or not. Replacing this function gives you total control: you could provide more hud configurations (or less) than the usual three, ignore the automap mode completely if you wanted, or even draw the view from multiple players.
General Queries
hud.check_automap() : float
This function returns true while the user is viewing the automap (by pressing TAB) and false for the normal view.
hud.which_hud() : float
This variable returns the current HUD number which the user cycles through when pressing '+' and '-' keys. It ranges from 0 to 119, allowing 120 different HUD screens, but in reality you must use the modulo operator '%' to convert this number to a smaller range.
For example, the standard code uses hud.which_hud() % 3 to select between three different huds (none, normal and overlay).
The following are good modulo numbers: 2,3,4,5,6,8 and 10 (because they divide into 120).
For a HUD which never changes, simply ignore this value.
hud.get_time() : float
This function returns the current time, in terms of "tics" where there are 35 tics per second. In other words, after each 1/35th of a second the value of hud.now_time increases by one. It keeps going even during menus or while the game is paused.
hud.passed_time
This variable is updated by the hud.grab_times() call, and contains the number of "tics" that have passed since the last time the draw_all() function was called. Note that a result of zero is possible.
hud.game_mode() : string
This function returns a string for the current game mode: "sp" (Single Player), "coop" (Cooperative), or "dm" (Deathmatch).
hud.game_name() : string
This function returns the DDF name of the current game being played (the one defined in GAMES.DDF).
hud.game_paused() : float
This function returns 1 if we are in a title screen menu or the game is paused.
hud.map_name() : string
This function returns the DDF name of the current map being played (the one defined in LEVELS.DDF).
hud.map_title() : string
This function returns the title of the map being played, mainly to be displayed on the automap.
* Drawing Stuff
hud.coord_sys(w, h)
In the original DOOM, the screen size was always 320x200, and by default all of the drawing functions here use screen coordinates as if that were the case (even when EDGE-Classic is running in different modes likes 640x480 or 1024x768). This function allows you to set a different "virtual" resolution, for example 640x400, and then all coordinates will be for this new system, plus the size of images and text characters will be affected as well.
hud.text_font(name)
Sets the current text font, where the 'name' parameter refers to an entry in FONTS.DDF. The default font is "DOOM" and is reset after each frame.
hud.text_color(name)
Sets the current text color, which must refer to an entry in COLMAPS.DDF, or can be the empty string "" which causes the text to be drawn normally (without being colormapped). The default is "" and is reset after each frame.
hud.set_scale(value)
Sets the scaling for drawing text and for hud.draw_image(). Larger values make the text/image bigger. The default scale is 1.0 and is reset after each frame.
hud.set_alpha(value)
Set the alpha value (translucency) for drawing text, lines, boxes and images. The 'value' parameter ranges from 0.0 (completely invisible) to 1.0 (completely solid). The default alpha is 1.0 and is reset after each frame.
hud.solid_box(x, y, w, h, color)
Draws a solid rectangle consisting of a single color. The 'x' and 'y' parameters are the coordinates of the top left corner, whereas 'w' and 'h' are the width and height. The current alpha value is also applied.
The 'color' parameter can take two different forms. Firstly it may be a string with the same notation as DDF and HTML, which begins with a "#" character and is followed by 6 hexadecimal digits. For example "#FF0000" for red and "#0000FF" for blue. Secondly it can be a Lua table with fields called 'r', 'g' and 'b' (for red, green and blue). Each of these fields is a number from 0 to 255. For example: { r=255, g=170, b=0 } for orange.
hud.solid_line(x1, y1, x2, y2, color)
Draws a solid line between the start coordinate (x1,y1) to the end coordinate (x2, y2). The 'color' parameter is the same as for hud.solid_box(), and the current alpha value is also applied.
hud.thin_box(x, y, w, h, color)
Similar to hud.solid_box(), but only draws the outline of a rectangle. The inside area is not affected. The sides are always two pixels thick, and never go outside the specified area. The 'color' parameter is the same as for hud.solid_box(), and the current alpha value is also applied.
hud.gradient_box(x, y, w, h, TL, BL, TR, BR)
Similar to hud.solid_box(), but the colors for each corner are specified individually: 'TL' for top left, 'BL' for bottom left, 'TR' for top right and 'BR' for bottom right. The current alpha value will also be applied.
hud.draw_image(x, y, name, [NoOffset])
Draws an image at the given coordinates, which specify the top/left corner of the image. The current alpha and scaling factors are applied as well.
If we specify the optional [NoOffset] argument as 1, then we will ignore any X or Y offsets the image may have, both doom style and any defined in images.ddf
hud.stretch_image(x, y, w, h, name, [NoOffset])
Similar to hud.draw_image(), but the image will be stretched or squashed so that it fits exactly into the given rectangle on the screen. The current alpha value is also applied.
If we specify the optional [NoOffset] argument as 1, then we will ignore any X or Y offsets the image may have, both doom style and any defined in images.ddf
hud.tile_image(x, y, w, h, name, [x_offset, y_offset])
Draws an image (usually a texture or flat) on the screen, where the image is tiled (repeated) to fill up the given rectangle. The current alpha and scaling factors are also applied. The 'x_offset' and 'y_offset' parameters are optional, and can be used to offset the texture by a certain number of pixels.
hud.scroll_image(x, y, name, [NoOffset])
Draws an image at the given coordinates, which specify the top/left corner of the image. The current alpha and scaling factors are applied as well.
The parameter "sx" controls horizontal scrolling speed and direction(positive value scrolls Right, negative Left).
The parameter "sy" controls vertical scrolling speed and direction(positive value scrolls Up, negative Down).
If we specify the optional [NoOffset] argument as 1, then we will ignore any X or Y offsets the image may have, both doom style and any defined in images.ddf
hud.draw_text(x, y, str, [size])
Draws some text on the screen using the current text font, color, alpha and scaling values. Newlines ("\n") in the string can be used to draw multi-line text.
We can specify the optional [size] argument to set the font size in pixels i.e. 16
hud.draw_number(x, y, len, num, alignRight, [size])
Draws a number (an integer) on the screen using the current text font, color, alpha and scaling.
If we pass 1 for the alignRight argument, then the number is right-aligned, in other words the 'x' parameter specifies the right-most pixel. If we pass 0 then the "x" parameter specifies the leftmost pixel.
The 'len' parameter gives the maximum number of characters (including the minus sign if the number is negative).
We can specify the optional [size] argument to set the font size in pixels i.e. 16
hud.draw_num2(x, y, len, num, [size])
Draws a number (an integer) on the screen using the current text font, color, alpha and scaling. The number is right-aligned, in other words the 'x' parameter specified the right-most pixel, and the 'len' parameter gives the maximum number of characters (including the minus sign if the number is negative).
We can specify the optional [size] argument to set the font size in pixels i.e. 16
hud.render_world(x, y, w, h)
Renders the view for the player on the screen, in a rectangle with the given coordinates. The player's weapon is also drawn. The views of different players can be rendered by using the hud.set_render_who() function below.
hud.render_automap(x, y, w, h)
Renders the automap for the player on the screen, in a rectangle with the given coordinates. Note that no background is drawn, hence you can use this function to create an overlay automap (drawn over the top of the player's view). If you need a solid color behind it, use the hud.solid_box() function first.
hud.automap_option(option, value)
Turn ON or OFF automap options.
Example usage:
hud.automap_option(hud.AM_FOLLOW, 1) turn ON player follow
hud.automap_option(hud.AM_ROTATE, 0) turn OFF automap rotatation
The following list shows all the possible options:
hud.AM_GRID Force the grid lines on/off
hud.AM_ALLMAP Draw walls like All-Map powerup
hud.AM_WALLS Draw all walls (like IDDT cheat)
hud.AM_THINGS Draw all things
hud.AM_FOLLOW Force follow-player mode on/off
hud.AM_ROTATE Force map rotation on/off
hud.AM_HIDELINES Show no map lines whatsoever
hud.set_render_who(index)
Sets the current player for rendering the world or the automap. The 'index' parameter is a small number: 1 for the "main player" on this computer (the person at the keyboard), 2 for the next player in the list, etc... upto the number of players in the game.
hud.automap_colors(part, colour)
This function can be used to change some or all of the colors used when drawing the automap.
Example usage: hud.automap_color(hud.AM_GRID, color.GREEN).
Here is a list of all the automap parts that can be changed:
Automap Part Description:
hud.AM_GRID Grid lines
hud.AM_WALL One sided walls
hud.AM_STEP Floor height change, climable
hud.AM_LEDGE Floor drop-off, too high to climb
hud.AM_CEIL Ceiling height difference
hud.AM_SECRET Secret doors
hud.AM_ALLMAP Unseen walls when you have the All-Map
hud.AM_PLAYER Player object
hud.AM_MONSTER Monsters
hud.AM_CORPSE Dead monsters
hud.AM_ITEM Pickup items
hud.AM_MISSILE Missiles, fireballs, etc
hud.AM_SCENERY Scenery items
hud.get_average_color(image)
Will return an RGB vector with the average color of the named image lump
hud.get_average_hue(image)
Will return an RGB vector with the average hue of the named image lump
hud.get_lightest_color(image)
Will return an RGB vector with the lightest color of the named image lump
hud.get_darkest_color(image)
Will return an RGB vector with the darkest color of the named image lump
hud.get_average_top_border_color(image)
Will return an RGB vector with the average top border color of the named image lump
hud.get_average_bottom_border_color(image)
Will return an RGB vector with the average bottom border color of the named image lump
hud.rts_enable(tag)
Run an RTS script, where 'tag' is the RTS script to be called.
hud.rts_isactive(tag)
Returns 1 if the RTS script "tag" is currently enabled, 0 if disabled.
hud.rts_disable(tag)
Stop an RTS script, where 'tag' is the RTS script to be stopped.
* Audio Functions
hud.play_sound(name)
Plays the given sound, which must be an entry in SOUNDS.DDF.
General Queries
player.is_bot()
Returns true if the current player is a bot.
player.get_name()
Returns the name of the current player.
player.get_angle()
Returns the angle of the current player.
player.get_pos()
Returns the position of the current player.
player.get_mlook()
Returns the mlook (mouse-look) angle of the current player.
player.health()
Returns the health of the current player. The result will normally be in the range 0 to 100, regardless of the SPAWNHEALTH setting for the player in DDF (in other words, the result is a percentage value of the spawn health). Values higher than 100 are possible when the player has bonus health (e.g. from the Soul Sphere pickup).
player.armor(type)
For the given armor type, returns the amount the player is currently wearing. The 'type' parameter is a number in the range 1-5, but the following names can be used for more readable code:
player.GREEN_ARMOR
player.BLUE_ARMOR
player.PURPLE_ARMOR
player.YELLOW_ARMOR
player.RED_ARMOR
player.total_armor(type)
Returns the total amount of armor the player has.
player.move_speed()
Returns a number for how fast the player is currently moving, roughly the number of map units per tic (there are 35 tics per second).
player.air_in_lungs()
Returns amount of air in the player lungs, as a percentage value from 0 to 100. Only guaranteed to be valid while the player is underwater.
player.has_key(key)
Returns true if the player currently has the specified key, which is a number from 1 to 16. For more readable code, the following names can be used:
player.BLUE_CARD player.GOLD_KEY
player.RED_CARD player.BRASS_KEY
player.YELLOW_CARD player.STEEL_KEY
player.GREEN_CARD player.FIRE_KEY
player.BLUE_SKULL player.SILVER_KEY
player.RED_SKULL player.COPPER_KEY
player.YELLOW_SKULL player.WOODEN_KEY
player.GREEN_SKULL player.WATER_KEY
player.has_power(power)
Returns true if the player currently has the specified powerup. The 'power' parameter is a number from 1 to 10. For more readable code, the following names can be used:
player.INVULN
player.BERSERK
player.INVIS
player.ACID_SUIT
player.AUTOMAP
player.GOGGLES
player.JET_PACK
player.NIGHT_VIS
player.SCUBA
player.TIME_STOP
player.power_left(power)
Returns the number of seconds remaining for the specified powerup, or zero when the player does not have it. The berserk powerup only counts down the red-screen effect, and returns -1 when that is finished. The automap powerup returns a large value when active and it never counts down. The result for invulnerability is not affected by the God-mode cheat.
* Weapon Stuff
player.has_weapon(name)
Returns true if the player currently owns the weapon, where 'name' is the DDF name of the weapon.
player.has_weapon_slot(slot)
Returns true if the player currently owns any weapon which uses the given 'slot', which is a number for 0 to 9 (same as the BINDKEY command in the DDF).
player.cur_weapon()
Returns the DDF name of the weapon the player is currently holding, or the special value "none" when the player is holding no weapon at all, or "change" while the weapon is switching to a new one.
player.cur_weapon_slot()
Returns the slot number (i.e. BINDKEY) of the weapon the player is currently holding, or -1 when the player is holding no weapon at all.
player.ammo(type)
Returns the amount of ammo the player is carrying (not including any ammo inside the clips of weapons). The 'type' parameter is a number in the range 1-99. For more readable code, one of the following names can be used instead:
player.BULLETS player.PELLETS
player.SHELLS player.NAILS
player.ROCKETS player.GRENADES
player.CELLS player.GAS
player.ammomax(type)
Returns the maximum amount of ammo the player can carry (not including weapon clips). The 'type' parameter is the same as the player.ammo() function.
player.main_ammo()
Returns the main ammo quantity for the player's current weapon. This is zero for weapons that don't use any ammo (like the FIST). If the weapon has a clip and the SHOWCLIP command (in DDF) is true, then the amount of ammo inside the clip is returned instead. Note that only the primary attack is checked, the secondary attack (if present) will be ignored.
player.ammo_type(ATK)
Returns the ammo type of the player's current weapon for the given attack (primary or secondary). The result is in the range 1-99, or can be 0 for the special case of NOAMMO. The 'ATK' parameter is 1 for the primary attack, 2 for the secondary attack, and is compulsory.
player.ammo_pershot(ATK)
Returns the ammo used up per shot by the current weapon for the given attack (primary or secondary). Same as the AMMOPERSHOT commands in WEAPONS.DDF. The 'ATK' parameter is 1 for the primary attack, 2 for the secondary attack, and is compulsory.
player.clip_ammo(ATK)
Returns the current amount of ammo the clip in the player's current weapon is holding, or zero if the weapon has no clip. The 'ATK' parameter is 1 for the primary attack, 2 for the secondary attack, and is compulsory.
player.clip_size(ATK)
Returns the maximum amount of ammo the clip in the player's current weapon can hold, or zero if the weapon has no clip. The 'ATK' parameter is 1 for the primary attack, 2 for the secondary attack, and is compulsory.
player.clip_is_shared()
Returns true if the player's current weapon is sharing a single clip between primary and secondary attackes (the SHARED_CLIP command).
player.kills()
Returns how many enemies killed on the current map.
player.secrets()
Returns how many secrets discovered on current map.
player.items()
Returns how many items picked up on the current map.
player.map_enemies()
Returns total enemies on current map.
player.map_secrets()
Returns total number of secrets on current map.
player.map_items()
Returns total items on current map.
player.floor_flat()
Returns the floor flat of the current sector we are in.
player.sector_tag()
Returns the tag of the current sector we are in.
player.play_footstep(flatname)
Checks FLATS.DDF for corresponding 'flatname' and plays the sfx associated with this flat. Returns 0 if unsuccessful i.e. no corresponding FLATS.DDF entry exists.
* Counter stuff
player.counter(type)
Returns the amount of a counter type the player is carrying. The 'type' parameter is a number in the range 1-99.
player.countermax(type)
Returns the maximum amount of a counter type the player can hold. The 'type' parameter is the same as the player.counter() function.
player.set_counter(type, value)
Allows us to set the amount of a counter type the player has. The 'type' parameter is a number in the range 1-99. The 'value' is the new amount the counter will have.
* Inventory stuff
player.inventory(type)
Returns the amount of an inventory type the player is carrying. The 'type' parameter is a number in the range 1-99.
player.inventorymax(type)
Returns the maximum amount of an inventory type the player can carry. The 'type' parameter is the same as the player.inventory() function.
player.inv_prev_key()
Returns 1 if the 'Inventory Previous' key has been pressed.
player.inv_next_key()
Returns 1 if the 'Inventory Next' key has been pressed.
player.inv_use_key()
Returns 1 if the 'Inventory USE' key has been pressed.
player.use_inventory(type)
Use/spend an inventory item. The 'type' parameter is a number in the range 1-99. The amount of this item will be decreased by 1 and an RTS script tagged INVENTORY will be called i.e. TAG INVENTORY01 in RTS.
* Conditions
player.on_ground()
Returns true if player is standing on solid ground.
player.under_water()
Returns true if player is in an AIRLESS sector and doesn't have the Scuba powerup.
Think of it like player.cannot_breathe ;)
player.is_action1()
Returns true if player is holding the ACTION1 button down.
player.is_action2()
Returns true if player is holding the ACTION2 button down.
player.is_swimming()
Returns true if player is in swimmable water (i.e. the SWIM sector special).
player.is_jumping()
Returns true if player is jumping.
player.is_crouching()
Returns true if player is crouching.
player.is_attacking()
Returns true if player is firing his weapon (either first or second attack).
player.is_rampaging()
Returns true if player has been firing his weapon for two seconds or more.
player.is_using()
Returns true if player is holding the USE button down.
player.is_grinning()
Returns true if player is grinning (after picking up a weapon).
* Miscellaneous
player.num_players()
Returns the total number of players in the game, including bots.
player.set_who(index)
Sets who the current player is. The 'index' parameter is a small number: 1 for the "main player" on this computer (the person at the keyboard), 2 for the next player in the list, for instance the split-screen player) etc... up to the number of players in the game. All the player query functions described here return their results for the current player.
player.hurt_by()
If the player has been hurt in the last few seconds, this returns a string describing what did the damage. Otherwise this function returns nil. The result is usually "enemy", but could be "friend" for friendly fire. If the player hurt himself with his own damn stupidity then the result is "self", whereas damaging floors and crushers will return "other".
player.hurt_mon()
If the player has been hurt in the last few seconds, this returns the name of the monster or other player. Otherwise this function returns nil.
player.hurt_pain()
If the player was just hurt, this returns the damage amount, otherwise this function returns 0.
player.hurt_dir()
If the player was just hurt, this returns a direction relative to the player where the attacker was: -1 for the left side, +1 for the right side, and 0 for all other cases.
player.hurt_angle()
Like player.hurt_dir(), except this returns the map angle from the player to his attacker. The result is in degrees (ranging from 0 to 359), where East is 0 and North is 90.
math.random2()
Returns a random number between 0 and 10.
strings.find(s,TextToFind)
Argument "s" is the string to be searched, argument "TextToFind" is what we're looking for. Will find a sub-string at ANY position. Returns position it was found at or -1 if not found.
mapobject.count(thingID)
Returns the number of objects of this type on the map.
player.query_object(MaxDistance, WhatInfo)
Returns information about the currently targetted thing.
- MaxDistance is the limit to how far we can query an object in map units.
- WhatInfo is to specify what information we want exactly and is a number from 1 to 5:
1 (NAME)
2 (CURRENT_HEALTH)
3 (SPAWN_HEALTH)
4 (PICKUP_BENEFIT)
5 (KILL_BENEFIT)
mapobject.query_tagged(ThingMapTag, WhatInfo)
Returns information about the thing with the tag we specified.
- ThingMapTag is the map tag we assigned to the object.
- WhatInfo is the same as player.query_object()
player.query_weapon(MaxDistance, WhatInfo, [secAttackInfo])
Returns information about the currently targetted weapon.
- MaxDistance is the limit to how far we can query a weapon in map units.
- WhatInfo is to specify what information we want exactly and is a number from 1 to 9:
1 (NAME)
2 (ZOOM FACTOR)
3 (AMMOTYPE)
4 (AMMOPERSHOT)
5 (CLIPSIZE)
6 (DAMAGE Nominal)
7 (DAMAGE Max)
8 (RANGE)
9 (AUTOMATIC)
- secAttackInfo is optional, and is the same as WhatInfo but applies only to the weapons secondary attack.