Table of Contents

The Mana server uses the scripting language LUA for scripting. This is a list of the script commands currently implemented in addition to the standard lua statements and functions.

Also, if you want to look at actual working samples, you can have a look at the example/serverdata/scripts folder in the Manaserv's source which has always the latest working set.

Script bindings

Creation and removal of stuff

create_npc

create_npc(string name, int spriteID, int gender, int x, int y, function talkfunct, function updatefunct)

Return value: A handle to the created NPC.

Creates a new NPC with the name name at the coordinates x:y which appears to the players with the appearence listed in their npcs.xml under spriteID and the gender gender. Every game tick the function updatefunct is called with the handle of the NPC. When a character talks to the NPC the function talkfunct is called with the NPC handle and the character handle.

For setting the gender you can use the constants defined in the libmana-constants.lua:

0 GENDER_MALE
1 GENDER_FEMALE
2 GENDER_UNSPECIFIED

mana.monster_create

mana.monster_create(int monsterID, int x, int y)
mana.monster_create(string monstername, int x, int y)

Return value: A handle to the created monster.

Spawns a new monster of type monsterID or monstername on the current map on the pixel coordinates x:y.

mana.monster_remove

mana.monster_remove(handle monster)

Return value: True if removing the monster suceeded.

Remove the monster monster from the current map.

mana.trigger_create

mana.trigger_create(int x, int y, int width, int height, string functionname, int arg, bool once)

Creates a new trigger area with the given height and width in pixels at the map position x:y in pixels. When a being steps into this area the function with the name functionname is called with the being handle and arg as arguments. When once is false the function is called every game tick the being is inside the area. When once is true it is only called again when the being leaves and reenters the area.

mana.effect_create

mana.effect_create(int id, int x, int y)
mana.effect_create(int id, being b)

Triggers the effect id from the clients effects.xml (particle and/or sound) at map location x:y or on being b. This has no effect on gameplay.

Warning: Remember that clients might switch off particle effects for performance reasons. Thus you should not use this for important visual input.

mana.item_drop

mana.item_drop(int x, int y, int id[, int number])
mana.item_drop(int x, int y, string itemname[, int number])

Drops a stack of number items at the location x:y on the current map. If no number is given, one item will be dropped.

Return value: True if the drop on map succeeded, false otherwise.

Input and output

do_message

do_message(handle npc, handle character, string message)

Warning: May only be called from an NPC talk function.

Shows an NPC dialog box on the screen of character ch displaying the string msg. Idles the current thread until the user click “OK”.

do_choice

do_choice(handle npc, handle character, item1, item2, ... itemN)

Return value: Number of the option the player selected (starting with 1).

Warning: May only be called from an NPC talk function.

Shows an NPC dialog box on the users screen with a number of dialog options to choose from. Idles the current thread until the user selects one or aborts the current thread when the user clicks “cancel”.

Items are either strings or tables of strings (indices are ignored, but presumed to be taken in order). So, do_choice(npc, ch, “A”, {“B”, “C”, “D”}, “E”) is the same as do_choice(npc, ch, “A”, “B”, “C”, “D”, “E”).

do_ask_integer

do_ask_integer(handle npc, handle character, min_num, max_num, [default_num])

Return value: The number the player entered into the field.

Warning: May only be called from an NPC talk function.

Shows a dialog box to the user which allows him to choose a number between min_num and max_num. If default_num is set this number will be uses as default. Otherwise min_num will be the default.

do_ask_string

do_ask_string(handle npc, handle character)

Return value: The string the player entered.

Warning: May only be called from an NPC talk function.

Shows a dialog box to a user which allows him to enter a text.

mana.being_say

mana.being_say(handle being, string message)

Makes being, which can be a character, monster or NPC, speak the string message as if it was entered by a player in the chat bar.

mana.chat_message

mana.chat_message(handle character, string message)

Outputs the string message in the chatlog of character which will appear as a private message from “Server”.

mana.announce

mana.announce(string message [, string sender])

Sends a global announce with the given message and sender. If no sender is passed “Server” will be used as sender.

Inventory interaction

mana.npc_trade

mana.npc_trade(handle npc,
               handle character,
               bool mode,
               {int item1id, int item1amount, int item1cost}, ...,
               {int itemNid, int itemNamount, int itemNcost})
mana.npc_trade(handle npc,
               handle character,
               bool mode,
               {string item1name, int item1amount, int item1cost}, ...,
               {string itemNname, int itemNamount, int itemNcost})

Opens a trade window for character while talking with npc. mode is true for selling and false for buying. You have to set each items the NPC is buying/selling, the cost and the maximum amount in {}.

Note: If the fourth parameters (table type) is omitted or invalid, and the mode set to sell (true), the whole player inventory is then sellable.

N.B.: Be sure to put a value (item cost) parameter in your items.xml to permit the player to sell it when using this option.

Return values:

  • 0 when a trade has been started
  • 1 when there is no buy/sellable items
  • 2 in case of errors.

Examples:

npc_trade.lua
    -- "A buy sample."
    local buycase = mana.npc_trade(npc, ch, false, { {"Sword", 10, 20}, {"Bow", 10, 30}, {"Dagger", 10, 50} })
    if buycase == 0 then
      do_message(npc, ch, "What do you want to buy?")
    elseif buycase == 1 then
      do_message(npc, ch, "I've got no items to sell.")
    else
      do_message(npc, ch, "Hmm, something went wrong... Ask a scripter to fix the buying mode!")
    end
 
-- ...
 
    -- "Example: Let the player sell only pre-determined items."
    local sellcase = mana.npc_trade(npc, ch, true, { {"Sword", 10, 20}, {"Bow", 10, 30}, 
                     {"Dagger", 10, 200}, {"Knife", 10, 300}, {"Arrow", 10, 500}, {"Cactus Drink", 10, 25} })
    if sellcase == 0 then
      do_message(npc, ch, "Here we go:")
    elseif sellcase == 1 then
      do_message(npc, ch, "I'm not interested by your items.")
    else
      do_message(npc, ch, "Hmm, something went wrong... Ask a scripter to fix me!")
    end
 
-- ...
 
    -- "Example: Let the player sell every item with a 'value' parameter in the server's items.xml file
    local sellcase = mana.npc_trade(npc, ch, true)
    if sellcase == 0 then
      do_message(npc, ch, "Ok, what do you want to sell:")
    elseif sellcase == 1 then
      do_message(npc, ch, "I'm not interested by any of your items.")
    else
      do_message(npc, ch, "Hmm, something went wrong... Ask a scripter to fix this!")
    end

mana.chr_inv_count

mana.chr_inv_count(handle character, bool inInventory, bool inEquipment, int id1, ..., int idN)
mana.chr_inv_count(handle character, bool inInventory, bool inEquipment, string name1, ..., string nameN)

The boolean values inInventory and inEquipment make possible to select whether equipped or carried items must be counted.

Return values: A number of integers with the amount of items id or name carried or equipped by the character.

mana.chr_inv_change

mana.chr_inv_change(handle character, int id1, int number1, ..., int idN, numberN)
mana.chr_inv_change(handle character, string name1, int number1, ..., string nameN, numberN)

Return value: Boolean true on success, boolean false on failure.

Changes the number of items with the item ID id or name owned by character by number. You can change any number of items with this function by passing multiple id or name and number pairs. A failure can be caused by trying to take items the character doesn't possess.

Warning: When one of the operations fails the following operations are ignored but these before are executed. For that reason you should always check if the character possesses items you are taking away using mana.chr_inv_count.

mana.chr_get_inventory

mana.chr_get_inventory(character): table[]{slot, item id, name, amount}

used to get a full view of a character's inventory. This is not the preferred way to know whether an item is in the character's inventory: Use mana.chr_inv_count for simple cases.

Return value: A table containing all the info about the character's inventory. Empty slots are not listed.

Example of use:

local inventory_table = mana.chr_get_inventory(ch)
for i = 1, #inventory_table do
    item_message = item_message.."\n"..inventory_table[i].slot..", "
        ..inventory_table[i].id..", "..inventory_table[i].name..", "
        ..inventory_table[i].amount
end

mana.chr_get_equipment

mana.chr_get_equipment(character): table[](slot, item id, name)}

Used to get a full view of a character's equipment. This is not the preferred way to know whether an item is equipped: Use mana.chr_inv_count for simple cases.

Return value: A table containing all the info about the character's equipment. Empty slots are not listed.

Example of use:

local equipment_table = mana.chr_get_equipment(ch)
for i = 1, #equipment_table do
    item_message = item_message.."\n"..equipment_table[i].slot..", "
        ..equipment_table[i].id..", "..equipment_table[i].name
end

mana.chr_money

mana.chr_money(handle character)

Return value: The money currently owned by character

mana.chr_money_change

mana.chr_money_change(handle character, int amount)

Changes the money currently owned by character by amount.

Warning: Before reducing the money make sure to check if the character owns enough money using mana.chr_money.

Character and being interaction

get_quest_var

get_quest_var(handle character, string name)

Return value: The quest variable named name for the given character.

Warning: Calling this function from a function different from a NPC talk function might result in bugs.

mana.chr_set_quest

mana.chr_set_quest(handle character, string name, string value)

Sets the quest variable named name for the given character to the value value.

mana.being_walk

mana.being_walk(handle character, int pixelX, int pixelY, int walkSpeed)

Set the desired destination in pixels for the 'character'.

The 'WalkSpeed' is to be given in tiles per second. The average speed is 6.0 tiles per second.

mana.being_get_speed

mana.being_get_speed(handle character)

Get the current walk speed for the given 'character'.

mana.being_set_speed

mana.being_get_speed(handle character, float speed)

Set the walk speed for the given 'character'.

The 'speed' is to be given in tiles per second. The average speed is 6.0 tiles per second.

mana.being_damage

mana.being_damage(handle being, int damage, int delta, int accuracy, int type, int element)

Inflicts damage to being. The severity of the attack is between damage and (damage + delta) and is calculated using the normal damage calculation rules. The being has a chance to dodge the attack with its agility attribute. The accuracy decides how hard this is.

type affects which kind of armor and character attributes reduce the damage. It can be one of the following values:

0 DAMAGE_PHYSICAL
1 DAMAGE_MAGICAL
2 DAMAGE_OTHER

element decides how the element system changes the damage. The following values are possible:

0 ELEMENT_NEUTRAL
1 ELEMENT_FIRE
2 ELEMENT_WATER
3 ELEMENT_EARTH
4 ELEMENT_AIR
5 ELEMENT_LIGHTNING
6 ELEMENT_METAL
7 ELEMENT_WOOD
8 ELEMENT_ICE

Return Value: Actual HP reduction resulting from the attack.

mana.being_heal

mana.being_heal(handle being[, int value])

Restores value lost hit points to being. Value can be omitted to restore the being to full hit points.

While you can (ab)use this function to hurt a being by using a negative value you should rather use mana.being_damage for this purpose.

mana.being_get_name

mana.being_get_name(handle being)

Return value: Name of the being.

mana.being_type

mana.being_type(handle being)

Return value: Type of the given being. These type constants are defined in libmana-constants.lua:

0 TYPE_ITEM
1 TYPE_ACTOR
2 TYPE_NPC
3 TYPE_MONSTER
4 TYPE_CHARACTER
5 TYPE_EFFECT
6 TYPE_OTHER

mana.being_get_action

mana.being_get_action(handle being)

Return value: Current action of the given being. These action constants are defined in libmana-constants.lua:

0 ACTION_STAND
1 ACTION_WALK
2 ACTION_ATTACK
3 ACTION_SIT
4 ACTION_DEAD
5 ACTION_HURT

mana.being_set_action

mana.being_set_action(handle being, int action)

mana.being_get_direction

mana.being_get_direction(handle being)

Return value: Current direction of the given being. These direction constants are defined in libmana-constants.lua:

0 DIRECTION_DEFAULT
1 DIRECTION_UP
2 DIRECTION_DOWN
3 DIRECTION_LEFT
4 DIRECTION_RIGHT
5 DIRECTION_INVALID

mana.being_set_direction

mana.being_set_direction(handle being, int direction)

Sets the current direction of the given being. Directions are same as in mana.being_get_direction.

mana.chr_warp

mana.chr_warp(handle character, int mapID, int posX, int posY)
mana.chr_warp(handle character, string mapName, int posX, int posY)

Teleports the character to the position posX:posY on the map with the ID number mapID or name mapName. The mapID can be substituted by nil to warp the character to a new position on the current map.

mana.posX

mana.posX(handle being)

Return value: The horizontal position of the being in pixels measured from the left border of the map it is currently on.

mana.posY

mana.posY(handle being)

Return value: The vertical position of the being in pixels measured from the upper border of the map it is currently on.

mana.being_get_base_attribute

mana.being_get_base_attribute(handle being, int attribute_id)

Set the value of the being's base attribute to the 'new_value' parameter given. (It can be negative).

Return value: Returns nothing.

mana.being_set_base_attribute

mana.being_set_base_attribute(handle being, int attribute_id, double new_value)

Return value: Returns the double value of the being's base attribute.

mana.being_get_modified_attribute

mana.being_get_modified_attribute(handle being, int attribute_id)

Return value: Returns the double value of the being's modified attribute.

The modified attribute is equal to the base attribute + currently applied modifiers.
To get to know how to configure and create modifiers, you can have a look at the attributes.xml file and at the mana.being_apply_attribute_modifier() and mana.being_remove_attribute_modifier() lua functions.
Note also that items, equipment, and monsters attacks can cause attribute modifiers.

FIXME: This functions about applying and removing modifiers are still WIP, because some simplifications and renaming could occur.

mana.being_apply_attribute_modifier

mana.being_apply_attribute_modifier(handle being, int attribute_id, double value, unsigned int layer, [unsigned short duration, [unsigned int effect_id]])

Parameters description:

  • value (double): The modifier value (can be negative).
  • layer (unsigned int): The layer or level of the modifier. As modifiers are stacked on an attribute, the layer determines where the modifier will be inserted. Also, when adding a modifier, all the modifiers with an higher ayer value will also be recalculated.
  • duration (unsigned short): The modifier duration in ticks1). If set to 0, the modifier is permanent.
  • effect_id (unsigned int): Set and keep that parameter when you want to retrieve the exact layer later. (FIXME: Check this.)

Return value: Returns nothing.

mana.being_remove_attribute_modifier

mana.being_remove_attribute_modifier(handle being, int attribute_id, double value, unsigned int layer)

Permits to remove an attribute modifier by giving its value and its layer.

Return value: Returns nothing.

mana.being_get_gender

mana.being_get_gender(handle being)

Return value: The gender of the being. These gender constants are defined in libmana-constants.lua:

0 GENDER_MALE
1 GENDER_FEMALE
2 GENDER_UNSPECIFIED

mana.chr_set_gender

mana.being_set_gender(handle being, int gender)

Sets the gender of a being.

The gender constants are defined in libmana-constants.lua:

0 GENDER_MALE
1 GENDER_FEMALE
2 GENDER_UNSPECIFIED

mana.chr_get_level

mana.chr_get_level(handle character)

Return value: Returns the level of the character.

mana.chr_get_exp

mana.chr_get_exp(handle character, int attribute)

Return value: The total experience collected by character in skill attribute.

mana.chr_give_exp

mana.chr_give_exp(handle character, int attribute, int amount [, int optimalLevel])

Gives character amount experience in skill attribute. When an optimal level is set (over 0), the experience is reduced when the characters skill level is beyond this.

mana.exp_for_level

mana.exp_for_level(int level)

Return value: Returns the total experience necessary (counted from level 0) for reaching level in any skill.

mana.chr_get_hair_color

mana.chr_get_hair_color(handle character)

Return value: The hair color ID of character

mana.chr_set_hair_color

mana.chr_set_hair_color(handle character, int color)

Sets the hair color ID of character to color

mana.chr_get_hair_style

mana.chr_get_hair_style(handle character)

Return value: The hair style ID of character

mana.chr_set_hair_style

mana.chr_set_hair_style(handle character, int style)

Sets the hair style ID of character to style

mana.chr_get_kill_count

mana.chr_get_kill_count(handle character, int monsterType)

Return value: The total number of monsters of type monsterType the character has killed during its career.

mana.chr_get_rights

mana.chr_get_rights(handle character)

Return value: The access level of the account of character.

Monsters

mana.monster_change_anger

mana.monster_change_anger(handle monster, handle being, int anger)

Makes the monster more angry about the being by adding anger to the being.

Status effects

mana.being_apply_status

mana.being_apply_status(handle Being, int status_id, int time)

Gives a being a status effect status_id, status effects don't work on NPCs. time is in game ticks.

mana.being_remove_status

mana.being_remove_status(handle Being, int status_id)

Removes a given status effect from a being.

mana.being_has_status

mana.being_has_status(handle Being, int status_id)

Return value: Bool if the being has a given status effect.

mana.being_get_status_time

mana.being_get_status_time(handle Being, int status_id)

Return Value: Number of ticks remaining on a status effect.

mana.being_set_status_time

mana.being_set_status_time(handle Being, int status_id, int time)

Sets the time on a status effect a target being already has.

Scheduling

atinit

atinit(function() [function body] end)

Adds a function which is executed when the gameserver loads the map this script belongs to. Usually used for placing NPCs or trigger areas and for setting up cronjobs with schedule_every. Any number of functions can be added this way.

schedule_in

schedule_in(seconds, function() [function body] end)

Executes the function body in seconds seconds.

schedule_every

schedule_every(seconds, function() [function body] end)

Executes the function body every seconds seconds from now on.

schedule_per_date

schedule_per_date(year, month, day, hour, minute, function() [function body] end)

Executes the function body at the given date and time.

on_death

on_death(handle being, function() [function body] end)

Executes the function body when being is killed. Note that this doesn't happen anymore after the being left the map.

on_remove

on_remove(handle being, function() [function body] end)

Executes the function body when being is no longer on the map for some reason (leaves the map voluntarily, is warped away, logs out, cleaned up after getting killed or whatever).

General information

mana.monster_get_name

mana.monster_get_name(int id)

Return value: The name of the monster with the ID id

mana.item_get_name

mana.item_get_name(int id)

Return value: The name of the item with the ID id

Map information

mana.get_map_id

mana.get_map_id()

Return value: The ID number of the map the script runs on.

mana.get_map_property

mana.get_map_property(string key)

Return value: The value of the property key of the current map. The string is empty if the property key does not exists.

mana.is_walkable

mana.is_walkable(int x, int y)

Return value: True if x:y is a walkable pixel on the current map.

mana.map_get_objects

mana.map_get_objects()
mana.map_get_objects(string type)

Return value: A table of all objects or a table of all object of the given type.

mana.map_get_object_property

mana.map_get_object_property(handle object, string key)

Return value: The value of the property key of the object.

mana.map_get_object_bounds

mana.map_get_object_bounds(handle object)

Return value: x, y position and height, width of the object.

Example use:

local x, y, width, height = mana.map_get_object_bounds(my_object)

mana.map_get_object_name

mana.get_object_name(handle object)

Return value: Name as set in the mapeditor of the object.

mana.map_get_object_type

mana.get_object_type(handle object)

Return value: Type as set in the mapeditor of the object.

Persistent variables

Be aware that due to a design flaw, all map-bound and global variables share the same namespace. You can also currently interact with map variables on other maps by referring to them as global variables. So you'd better not try to exploit this! You have been warned! A workaround is to prefix all map-bound variable names with a different prefix on each map and all global variables with yet a different prefix.

Details about the bug on http://bugs.manasource.org/view.php?id=310

mana.setvar_map

mana.setvar_map(string key, string value)

Sets a persistent variable. The scope of the variable is the map the script runs on. It can later be retrieved using mana.getvar_map from any script running on the same map. The value is stored in the database and thus will survive a server reboot.

mana.getvar_map

mana.getvar_map(string key)

Return value: Value of a map-bound variable.

mana.setvar_world

mana.setvar_world(string key, string value)

Sets a persistent variable. The scope of the variable is the whole game world. It can later be retrieved using mana.getvar_world from any script running on any map. The value is stored in the database and thus will survive a server reboot.

When you are using this function, be aware of race conditions: It is impossible to prevent that another map changes the value of a variable between you requesting to old value and setting a new value.

mana.getvar_world

mana.getvar_world(string key)

Return value: Value of a world-bound variable.

mana.log

mana.log(int log_level, string log_entry)

Log something at the specified log level. The available log levels are:

0 LOG_FATAL
1 LOG_ERROR
2 LOG_WARNING
3 LOG_INFO
4 LOG_DEBUG

Area of Effect

In order to easily use area of effects in your items or in your scripts, the following functions are available:

mana.get_beings_in_circle

mana.get_beings_in_circle(int x, int y, int radius)

Return value: This function returns a lua table of all beings in a circle of radius radius centered at the pixel at (x, y).

mana.get_beings_in_rectangle

mana.get_beings_in_rectangle(int x, int y, int width, int height)

Return value: An array of being objects.

mana.get_distance

mana.get_distance(handle being1, handle being2)
mana.get_distance(int x1, int y1, int x2, int y2)

Return value: The distance between the two beings or the two points in pixels.

Needed script bindings

Damage utility functions

With the introduction of the scripted Special System some new script bindings are needed which makes it easier for server administrators to define damage inflicting specials.

Area of Effect

Possible missing area of effect functions:

  • get_beings_in_cone
  • get_beings_in_line

Damage utility functions

Most servers will likely want a lot of special attacks which inflict damage based on the attributes of the attacker in the same way as a normal attack, just that they are stronger. To make this easier we need a function which makes being A attack being B with the normal combat rules, except that the damage and accuracy can be made stronger or weaker and that the element can be changed.

* perform_modified_attack(handle attacker, handle defender, float damage_factor, float damage_delta_factor, float accuracy_factor, int type, int element)

The float factors will be multipliers to the damage values created by a normal attack. Element can be nil to use the element of the currently equipped weapon.

Discussion

Jaxad0127 - 2010-05-09
IMO, we should have a separate article for each function, with code samples and all.
Bertram - 2010-05-10
I Agree. Scripting really lacks some useful snippets.
(If the per function article is too much, maybe per-section pages, then?)
Bertram - 2011-08-18
The current state of the page (at the time of writing) is quite fine to me.
The 'example' folder is also a good point of information and samples collection.
Hence, I'd let it as is.
1) A tick is equal to 100ms.
scripting.txt · Last modified: 2012/01/27 12:37 by Erik Schilling
 
Except where otherwise noted, content on this wiki is licensed under the following license: GNU Free Documentation License 1.3
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki