diff options
author | Reid <reidyaro@gmail.com> | 2011-10-16 19:12:30 +0200 |
---|---|---|
committer | Reid <reidyaro@gmail.com> | 2011-10-16 19:12:30 +0200 |
commit | d94735d8ec96832cb45d6c74c57602ed96a19695 (patch) | |
tree | 118197318d3ee537e88e19cf84206a16739034f6 /conf | |
parent | 343490c3c1ab0591c9e23fda69c9649c4893eab3 (diff) | |
download | serverdata-d94735d8ec96832cb45d6c74c57602ed96a19695.tar.gz serverdata-d94735d8ec96832cb45d6c74c57602ed96a19695.tar.bz2 serverdata-d94735d8ec96832cb45d6c74c57602ed96a19695.tar.xz serverdata-d94735d8ec96832cb45d6c74c57602ed96a19695.zip |
Reinitialization of Serverdata Beta.
Diffstat (limited to 'conf')
-rw-r--r-- | conf/atcommand_athena.conf | 7 | ||||
-rw-r--r-- | conf/atcommand_local.conf.example | 497 | ||||
-rw-r--r-- | conf/battle_athena.conf | 748 | ||||
-rw-r--r-- | conf/battle_local.conf.example | 1 | ||||
-rwxr-xr-x | conf/build-magic.sh | 21 | ||||
-rw-r--r-- | conf/char_athena.conf | 133 | ||||
-rw-r--r-- | conf/char_local.conf.example | 25 | ||||
-rw-r--r-- | conf/eathena-monitor.conf.example | 14 | ||||
-rw-r--r-- | conf/gm_account.txt.example | 1 | ||||
-rw-r--r-- | conf/grf-files.txt | 0 | ||||
-rw-r--r-- | conf/help.txt.example | 193 | ||||
-rw-r--r-- | conf/inter_athena.conf | 31 | ||||
-rw-r--r-- | conf/ladmin_athena.conf | 28 | ||||
-rw-r--r-- | conf/ladmin_local.conf.example | 10 | ||||
-rw-r--r-- | conf/lan_support.conf | 41 | ||||
-rw-r--r-- | conf/login_athena.conf | 130 | ||||
-rw-r--r-- | conf/login_local.conf.example | 30 | ||||
-rw-r--r-- | conf/magic.conf.template | 1835 | ||||
-rw-r--r-- | conf/magic.conf.tmw.template | 1617 | ||||
-rw-r--r-- | conf/map_athena.conf | 19 | ||||
-rw-r--r-- | conf/map_local.conf.example | 15 | ||||
-rw-r--r-- | conf/motd.txt.example | 1 | ||||
-rw-r--r-- | conf/msg_athena.conf | 528 | ||||
-rw-r--r-- | conf/script_athena.conf | 2 | ||||
-rw-r--r-- | conf/water.txt | 54 | ||||
-rw-r--r-- | conf/water_height.txt | 68 |
26 files changed, 6049 insertions, 0 deletions
diff --git a/conf/atcommand_athena.conf b/conf/atcommand_athena.conf new file mode 100644 index 00000000..82204f1a --- /dev/null +++ b/conf/atcommand_athena.conf @@ -0,0 +1,7 @@ +// Athena atcommand Configuration file. +// Translated by Peter Kieser <pfak@telus.net> + + +// local settings for this server in this file +import: conf/atcommand_local.conf + diff --git a/conf/atcommand_local.conf.example b/conf/atcommand_local.conf.example new file mode 100644 index 00000000..0e87addc --- /dev/null +++ b/conf/atcommand_local.conf.example @@ -0,0 +1,497 @@ +// Athena atcommand Local Configuration file. + +// Set here the symbol that you want to use for your commands +// Only 1 character is get (default is '@'). You can set any character, +// except control-character (0x00-0x1f), '%' (party chat speaking) and '/' (standard ragnarok GM commands) +// With default character, all commands begin by a '@': <example> @revive +command_symbol: @ + + +// 0: normal player commands + +// Displays helpfile in Athena base directory. +help: 0 + +// Give server time. (6 same commands) +time: 0 +date: 0 +server_date: 0 +serverdate: 0 +server_time: 0 +servertime: 0 + +// To change your (own) email (characters protection) +// note: this command doesn't check email itself, but check structure of the email (xxx@xxx) +// if you want be sure of each e-mail disable this option (value: 100) +email: 0 + +// To become GM (need password; password is set in login_athena.conf). +// special!: only a non-GM (player with gm level 0) need to have this command. +// if you change the value, be sure of what you do! +// To be able to create a gm with @gm, you must: +// - give a level to level_new_gm (parameter of login_athena.conf) (not 0) +// - enable to level 0 the @gm command (atcommand_athena.conf) (default 100) - Only level 0 can give access to this command +// - enable gm commands to normal player (battle_athena.conf, atcommand_gm_only parameter) +// - and normal player must give correct password when he use the @gm command (gm_pass paramter in login_athena.conf) +gm: 100 + + +//------------------------- +// 40: "Dev" + +// Broadcast to the whole server +broadcast: 40 + +// Broadcast to the map you are on +local_broadcast: 40 + +// Suicide your character. +die: 40 + +// Locate someone on a map, returns your coordinates if the person isn't on. +where: 40 + +// Spawns you to set points in major cities. +go: 40 + +// Warp yourself to a person. +goto: 40 + +// follow a player (including warping to them) +follow: 40 + +// Disconnects a user from the server (1 command + right click menu for GM "(name) force to quit"). +kick: 40 + +// Returns list of logged in characters with their position. +who: 40 + +// Returns list of logged in characters with their party/guild. +whogroup: 40 + +// Returns list of logged in characters with their position in a specifical map. +whomap: 40 + +// Returns list of logged in characters with their party/guild in a specifical map. +whomapgroup: 40 + +// Like @who+@who2+who3, but only for GM. +whogm: 40 + +// Enables you to view other characters stats. +charstats: 40 + +// Heals a person to full HP/SP. +heal: 40 + +// GM Hide (hides you from monsters and most reporting functions). +// To hide from other players use @invisible +hide: 40 + +// Enables you to to jump randomly on a map (that you are already on). +jump: 40 + +// Warps you to your last save point. +return: 40 + +// Warp yourself to a certain map, at (x,y) coordinates. +warp: 40 + +// Changes GM clothes color (2 same commands) +dye: 40 +ccolor: 40 + +// Changes own hair style. +hairstyle: 40 + +// Changes own hair color. +haircolor: 40 + +// Deletes all your items. +itemreset: 40 + +// Sets your spawn point (aka save point). +save: 40 + +// Send text to the GM log +log: 40 +l: 40 + +// Send text to the GM log and local chat +tee: 40 +t: 40 + +//-------------------- +// 50: Event coordinators + +// make yourself invisible to everyone +invisible: 50 + +// make yourself visible to everyone +visible: 50 + +// Spawns a monster, and a certain amount +spawn: 50 + +//Summons a monster, and a certain amount +summon: 50 + +//-------------------- +// 60: "GM" + +// Enable all wispers for a player +inall: 60 + +// Disable all wispers for a player +exall: 60 + +// Shows Stats Of All Characters Online +charstatsall: 60 + +// Turns PVP (Person v. Person) off on a map. +pvpoff: 60 + +// Enables PVP on a map. +pvpon: 60 + +// Sets the speed you can walk/attack at. Default is 150. +speed: 60 + +// Kill all monsters in map (with drops) +killmonster: 60 + +// Kill all monsters in map (without drops) +killmonster2: 60 + +// Check which characters are online from a characters IP address +ipcheck: 60 + +// store all your items +storeall: 60 + +// allow other players to hit you out of pvp +killable: 60 + +// look up a skill by name +skillid: 60 + +// use a skill by id +useskill: 60 + +// make another player killable +charkillable: 60 + +// Resurects yourself. +alive: 60 + +// Levels your character to specified level (adds to your level). +blvl: 60 + +// Raises your job level (3 same commands). +jlvl: 60 + +// Unmute a player +unmute: 60 + +// Sets another persons base level. +charblvl: 60 + +// Changes the sex of an online player (all characters on the account) +charchangesex: 60 + +// Remove items from a character +chardelitem: 60 + +// Sets another persons job level. +charjlvl: 60 + +// Gives another character status points +charstpoint: 60 + +// Gives another character skill points +charskpoint: 60 + +// Resets another character's stats +charreset: 60 + +// Resets another character's status, skills +charstreset: 60 +charskreset: 60 + +// resets a char back to when it was first created +charwipe: 60 + +// Saves the respawn point of another character. +charsave: 60 + +// Kill another character without hitting them. +kill: 60 + +// Enable hitting a player even when not in pvp +killer: 60 + +// Warps a character to you +recall: 60 + +// Revives a character, and heals them. +revive: 60 + +// Warp another person to a certain map, at (x,y) coordinates +charwarp: 60 + +// Change Status of your character +str: 60 +agi: 60 +vit: 60 +int: 60 +dex: 60 +luk: 60 + +// Gets all skills +allskills: 60 + +// sets GM stats to maximum +allstats: 60 + +// Gives you job points. +stpoint: 60 + +// Gives you skill points of desired amount. +skpoint: 60 + +// To block definitively a player +block: 60 + +// To unblock a player +unblock: 60 + +// To ban a player for a limited time +ban: 60 + +// To unban a player +unban: 60 + +// To send specified character in jails +jail: 60 + +// To discharge a prisoner +unjail: 60 + +// drop a players possessions on the ground +chardropall: 60 + +// put a players possessions in storage +charstoreall: 60 + +// iterate over players +// forward +hugo: 60 +// backward +linus: 60 + +//---------------------- +// 80: "eA Dev" + +// set magic properties on a char +setmagic: 80 + +// list magic properties on a char +magicinfo: 80 + +// Set your character display options. (Visual effects of your character) +option: 80 + +// Gives you money (zeny) of desired amount. +zeny: 80 + +// Changes another character's zenny +charzeny: 80 + +// Set options on another character. +charoption: 80 + +// Create a static warp portal that lasts until the next reboot +addwarp: 80 + +// Set the map you are on to day. +day: 80 + +// Kills everyone on the server. +doom: 80 + +// Kills everyone on the map you are on. +doommap: 80 + +// Set the map you are currently on to night. +night: 80 + +// Recalls Everyone To Your Coordinates +recallall: 80 + +// Revives all players on the map. +raisemap: 80 + +// Revives all players on the server. +raise: 80 + +// Enables a NPC. +enablenpc: 80 + +// Disables a NPC. +disablenpc: 80 + +// Move a NPC +npcmove: 80 + +// turn skills on for a map +skillon: 80 + +// turn skills off for a map +skilloff: 80 + +// Enables lost skills. +lostskill: 80 + +// find id of item by name +idsearch: 80 + +// Creates an item of your choosing, either Item ID or Name (1 command + /item). +item: 80 + +// Creates weapon of desired element. +produce: 80 + +// ?? +itemcheck: 80 + + +//--------------------------- +// 99: "Admin" + +// drop all your items +dropall: 99 + +// Enables GVG on a map (2 same commands). +gvgon: 99 +gpvpon: 99 + +// Turns GVG (Guild v. Guild) off on a map (2 same commands). +gvgoff: 99 +gpvpoff: 99 + +// Enables platinum skills. +questskill: 99 + +// Display your ignore list (people from which you ignore wisps) +ignorelist: 99 + +// Display ignore list of a player (people from which the player ignore wisps) +charignorelist: 99 + +// Brings up your guild storage wherever you are. +gstorage: 99 + +// Do some visual effect on your character +effect: 99 + +// Changes character's model +charmodel: 99 + +// Starts Guild Wars +agitstart: 99 + +// Ends Guild Wars +agitend: 99 + +// Levels your guild to specified level +guildlvl: 99 + +// craete a party/guild +guild: 99 +party: 99 + +// Warps all online character of a guild to you. (at least one member of that guild must be on.) +guildrecall: 99 + +// Warps all online character of a party to you. (at least one party member must be online.) +partyrecall: 99 + +// Allows you to spy on any Guilds Guild chat. (at least one member of that guild must be on.) +guildspy: 99 + +//Allows you to spy on any party's party chat. (at least one party member must be online.) +partyspy: 99 + +// Saves a warp point. +memo: 99 + +// To get a peco to (un)ride for another player. +charmountpeco: 99 + +// Change your appearence to other players to a mob. +disguise: 99 + +//Restore your normal appearance. +undisguise: 99 + +// To change disguise of another player/GM +chardisguise: 99 +charundisguise: 99 + +// Display all items of a player (disabled due to reformed GM guidelines) +charitemlist: 99 + +// Display all items of a player's storage (disabled due to reformed GM guidelines) +charstoragelist: 99 + +// Display all items of a player's cart (disabled due to reformed GM guidelines) +charcartlist: 99 + +// Enables platinum skills of another player. +charquestskill: 99 + +// Enables lost skills of another player. +charlostskill: 99 + +// Changes your apperance. +model: 99 + +// To get a peco to (un)ride +mountpeco: 99 + +// Broadcast (with or without name). +kami: 99 +kamib: 99 + +// Disconnect all users from the server +kickall: 99 + +// Closes Map-Server +mapexit: 99 + +// Give information about terrain/area (debug function) +gat: 99 + +// Enables debugging +packet: 99 + +// Shows information about the map +mapinfo: 99 + +// Re-load item database (admin command) +reloaditemdb: 99 + +// Re-load monsters database (admin command) +reloadmobdb: 99 + +// Re-load skills database (admin command) +reloadskilldb: 99 + +// Re-load scripts (admin command) +reloadscript: 99 + +// Re-load GM level (admin command) +reloadgmdb: 99 + +// Brings up your personal storage wherever you are. +storage: 99 diff --git a/conf/battle_athena.conf b/conf/battle_athena.conf new file mode 100644 index 00000000..f8db37e1 --- /dev/null +++ b/conf/battle_athena.conf @@ -0,0 +1,748 @@ + +//-------------------------------------------------------------- +//eAthena Battle Configuration File +// Made in to plainer english by Ancyker +//-------------------------------------------------------------- +//Note 1: Directives can be set using on/off, yes/no or 1/0. +//Note 2: All rates are in percents, 100 would mean 100%, 200 +// would mean 200%, etc +// Other Information: +// 1000 miliseconds is 1 second. +//-------------------------------------------------------------- + +// Do you want to debug warp points? If set to yes, warp points will appear as flags.(Note 1) +warp_point_debug: no + +// When calculating critical, should we take in to account the enimies luck? (Note 1) +enemy_critical: yes + +// Enemy's Critical Rate (Note 2) +enemy_critical_rate: 100 + +// Are enemy attacks effected by their strength? (Note 1) +enemy_str: yes + +// Can enemies have perfect flee? (Note 1) +enemy_perfect_flee: no + +// The rate of time it takes to cast a spell (Note 2, 0 = No casting time) +casting_rate: 100 + +// Delay time after casting (Note 2) +delay_rate: 100 + +// Is the delay time is dependent on the caster's DEX? (Note 1) +delay_dependon_dex: yes + +// At what dex does the cast time become zero (instacast) +castrate_dex_scale: 150 + +// Is 'Skills add a delay before you can attack' enabled? (Note 1) +skill_delay_attack_enable: no + +// Whether or not cards and attributes in the left hand are enabled (Note 1) +left_cardfix_to_right: yes + +// Increase player's attack range (in cells) +player_skill_add_range: 0 + +// If the target moves out of range while casting, do we take the items and SP for the skill anyway? (Note 1) +skill_out_range_consume: no + +// Increase Monsters attack range +monster_skill_add_range: 0 + +// If a player is attacked, will they have a delay in being able to move? (Note 1) +// (Setting to no will be like always endure) +player_damage_delay: no + +// Damaged delay rate (Note 2) +player_damage_delay_rate: 100 + +// Is a player's defense NOT dependant on an enemies attack? (Note 1) +defunit_not_enemy: yes + +// Are summoned monsters level greater then your base level? (I think this is for dead branches) (Note 1) +random_monster_checklv: yes + +// The maximum quantity of monsters that can be summoned per GM command (0 denotes an unlimited quantity) +atcommand_spawn_quantity_limit: 100 + +// Does HP recover if hit by an attribute that's same as your own? (Note 1) +attribute_recover: yes + +// If an item is droped, does it go stright into the users inventory? (Note 1) +item_auto_get: no + +// How long does it take for an item to disappear from the floor after it is dropped? (in miliseconds) +flooritem_lifetime: 120000 + +// How long before the first person who did the most damage to a monster can get the item? (in milliseconds) +item_first_get_time: 15000 + +// How long before the second person who did the second most damage to a monster can get the item? (in milliseconds) +// (It Adds Time From The First Persons Time) +// So, It Is Like First Person's Time + Second Person's Time = Time Before Second Person Can Get The Items +item_second_get_time: 10000 + +// How long before the third person who did the third most/least damage to a monster can get the item? (in milliseconds) +// (It Adds Time From The First Persons Time And Second Persons Time) +// So, It Is Like First Person's Time + Second Person's Time + Third Person's Time = Time Before Third Person Can Get The Items +item_third_get_time: 5000 + +// How long before the first person who did the most damage to a MVP can get the item? (in milliseconds) +mvp_item_first_get_time: 10000 + +// How long before the second person who did the second most damage to a MVP can get the item? (in milliseconds) +// (It Adds Time From The First Persons Time) +// So, It Is Like First Person's Time + Second Person's Time = Time Before Second Person Can Get The Items +mvp_item_second_get_time: 10000 + +// How long before the third person who did the third most/least damage to a MVP can get the item +//(Note the Amount is in Milliseconds and It Adds Time From The First Persons Time And Second Persons Time) +//So It Is Like First Person's Time + Second Person's Time + Third Person's Time = Time Before Third Person Can Get The Items +mvp_item_third_get_time: 2000 + +// Item drop rates (Note 2) + +// The rate the common items are droped (Items that are in the ETC tab, besides card) +item_rate_common: 100 +item_drop_common_min: 1 +item_drop_common_max: 10000 + +// The rate healing items are droped (items that restore HP or SP) +item_rate_heal: 100 +item_drop_heal_min: 1 +item_drop_heal_max: 10000 + +// The rate at which usable items (in the item tab) other then healing items are droped. +item_rate_use: 100 +item_drop_use_min: 1 +item_drop_use_max: 10000 + +// The rate at which equipment is droped. +item_rate_equip: 100 +item_drop_equip_min: 1 +item_drop_equip_max: 10000 + +// The rate at which cards are droped +item_rate_card: 100 +item_drop_card_min: 1 +item_drop_card_max: 10000 + +item_drop_mvp_min: 1 +item_drop_mvp_max: 10000 + +// Can the monster's drop rate become 0? (Note 1) +drop_rate0item: no + +// Rate at which exp. is given. (Note 2) +base_exp_rate: 100 + +// Rate at which job exp. is given. (Note 2) +job_exp_rate: 100 + +// PVP exp. Do players get exp during pvp +pvp_exp: yes + +// When a player dies, how should we penalize them? +// 0 = No penalty. +// 1 = Lose % of current level when killed. +// 2 = Lose % of total experience when killed. +death_penalty_type: 0 + +// Base exp. penalty rate (Each 100 is 1% of their exp) +death_penalty_base: 100 + +// Job exp. penalty rate (Each 100 is 1% of their exp) +death_penalty_job: 100 + +// When a player dies, how much zeny should we penalize them with? +zeny_penalty: 0 + +// The amount of HP a player will respawn with, 0 is default. +// (Unit is in percentage of total HP, 100 is full heal of HP, 0 is respawn with 1HP total.) +restart_hp_rate: 30 + +// The amount of SP a player will respawn with, 0 is default. +// (Unit is in percentage of total SP, 100 is full heal of SP, 0 is respawn with 1SP total.) +restart_sp_rate: 0 + +// [MVP] Summoned monsters HP rate, that is, monsters summoned by an MVP will have this much HP. (Note 2) +mvp_hp_rate: 100 + +// [MVP] Item drop rate, that is, the overall drop rate for items droped by an MVP. (Note 2) +mvp_item_rate: 100 + +// [MVP] Exp. rate. (Note 2) +mvp_exp_rate: 100 + +// The HP rate of normal monsters (that is monsters that are not MVP's) (Note 2) +monster_hp_rate: 100 + +// The maximum attack speed of a monster +monster_max_aspd: 199 + +// (@) GM Commands available only to GM's? (Note 1) +// set to 'No', Normal players (gm level 0) can use GM commands _IF_ you set the command level to 0. +// set to 'Yes', Normal players (gm level 0) can never use a GM command even if you set the command level to 0. +atcommand_gm_only: no + +// [GM] Can use all skills? (No or mimimum GM level) +gm_all_skill: no + +// [GM] Can use all abracadabra skills? (No minimum GM level) +gm_all_skill_add_abra: no + +// [GM] Can equip anything? (No or minimum GM level, can cause client errors.) +gm_all_equipment: no + +// [GM] Raise skills unconditionally, that is, put points in to a skill not in thier jobs skill tree? (no or minimum gm level) +gm_skill_unconditional: no + +// Can a normal player by-pass the skill tree? (Note 1) +player_skillfree: no + +// When doing a skill reset, whether the skill's restriction is to be ignored or not. (Note 1) +player_skillup_limit: yes + +// Forging success rate. (Note 2) +weapon_produce_rate: 100 + +// Prepare Potion succsss rate. (Note 2) +potion_produce_rate: 100 + +// Allow monsters to be aggresive and attack first? (Note 1) +monster_active_enable: yes + +// Monster damage delay rate (Note 1) +monster_damage_delay_rate: 100 + +// Looting monster actions. +// 0 = Monster will consume the item. +// 1 = Monster will not consume the item. +monster_loot_type: 0 + +// Enable monster skills? (Note 1) +mob_skill_use: yes + +// Rate of monsters on a map, 200 would be twice as many as normal. (Note 2) +mob_count_rate: 100 + +// Max mobs count in each map +mob_map_limit: 500 + +// Max mob spawned with skills per each master +mob_skill_spawn_limit: 20 + +// Min mob respaw delay +mob_spawn_min_delay: 5000 + +// Quest skills can be learned? (Note 1) +// Setting this to yes can open an exploit on your server! +quest_skill_learn: yes + +// When skills are reset, quest skills are reset as well? (Note 1) +// Setting this to yes can open an exploit on your server! +quest_skill_reset: no + +// You must have basic skills to be able to sit, trade, form a party or create a chatroom? (Note 1) +basic_skill_check: yes + +// Item to require when making a guild. Setting this to +// 0 will disable the check. Using item 1337 for now +// to disable creation (as it's unallocated) +guild_emperium_check: 504 + +// Maximum tax limit on a guild member. +guild_exp_limit: 50 + +// Maximum castles one guild can own (0 - unlimited) +guild_max_castles: 0 + +// When teleporting, or spawning to a map, how long before a monster sees you if you don't move? (time is in milliseconds) +// That is, when you go to a map and don't move, how long before the monsters will notice you. +// If you attack a monster, it will attack you back regaurdless of this setting. (I think) +player_invincible_time: 5000 + +// [PET] Rate for catching pets (Note 2) +pet_catch_rate: 100 + +// [PET] Can you name a pet more then once? (Note 1) +pet_rename: no + +// [PET] The rate a pet will get friendly by feeding it. (Note 2) +pet_friendly_rate: 100 + +// [PET] The rate at which a pet will become hungry. (Note 2) +pet_hungry_delay_rate: 100 + +// [PET] If your pet is hungry by how much will the friendlyness decrease by. (Default is 5) +// Note: The friendlyness is 0-1000 total, at 0 the pet runs away. +pet_hungry_friendly_decrease: 5 + +// [PET] Does Pet's Attack Damage Based On Str (Note 1) +pet_str: yes + +// [PET] Whether or not the pet's will use skills. (Note 1) +pet_status_support: yes + +// [PET] Does the pet need its equipment before it does its skill? (Note 1) +pet_equip_required: yes + +// [PET] Will all pets attack? (Note 1) +// Do NOT use this with pet skills! +pet_attack_support: no + +// [PET] When the master receives damage from the monster, whether or not the pet attacks back. +pet_damage_support: no + +// [PET] Rate at which a pet will support it's owner in battle. (Note 2) +pet_support_rate: 100 + +// [PET] Does the pets owner receive exp from the pets damage? +pet_attack_exp_to_master: no + +// [PET] The rate exp. is gained from the pet attacking monsters +pet_attack_exp_rate: 100 + +// Will there be a minimum skill dmg even if there is a miss? +skill_min_damage: no + +// Which finger offensive style can be used? +// 0 = Aegis style +// 1 = Athena style +finger_offensive_type: 0 + +// The rate of job exp. from using Heal skill (100 is the same as the heal amount, 200 is double. +// The balance of the exp. rate is best used with 5 to 10) +heal_exp: 0 + +// The rate of exp. that is gained by the process of resurrection, a unit is 0.01%. +// Experience calculations for the experience value * level difference of the person revived / 100 * resurrection_exp/10000 which the revived player has can be got. +resurrection_exp: 0 + +// The rate of job exp. when using discount and overcharge on an NPC (100 is normal, 200 is double.) +// The way it is calculated is (money recieved * skill lv) * shop_exp / 100. +shop_exp: 0 + +// The delay rate of monk's combo (Note 2) +combo_delay_rate: 100 + +// Item check? (Note 1) +// When logged in or moving in map if the item the player is holding isn't correct there will be a check. +item_check: no + +// Will tuxedo and wedding dresses be shown when worn? (Note 1) +wedding_modifydisplay: yes + +// The time interval for HP to restore naturally. (in milliseconds) +natural_healhp_interval: 6000 + +// The time interval for SP to restore naturally. (in milliseconds) +natural_healsp_interval: 8000 + +// Automatic healing skill's time interval. (in milliseconds) +natural_heal_skill_interval: 10000 + +// The maximum weight for a character to carry when the character stops healing naturally. (in %) +natural_heal_weight_rate: 50 + +// Override item names from GRF file? (Note 1) +item_name_override_grffile: yes + +// Are arrows are consumed when used on a bow? (Note 1) +arrow_decrement: yes + +// Maximum atk speed. (Default is 190) +max_aspd: 190 + +// Maximum HP. (Default is 32500) +max_hp: 32500 + +// Maximum SP. (Default is 32500) +max_sp: 32500 + +// Maximum user LV to send to client +// (Default is 99.. Never go above 127) +// +// this is only useful if you have adjusted your client +// to expect levels higher then 99 +max_lv: 99 + +// Max limit of char stats. (agi, str, etc.) +max_parameter: 255 + +// Max weight carts can hold. +max_cart_weight: 8000 + +// Display player skill errors in console? (for debug only) (default: off) (Note 1) +player_skill_log: off + +// Display monster skill errors in console? (for debug only) (default: off) (Note 1) +monster_skill_log: off + +// Display battle log? (for debug only) (default: off) (Note 1) +battle_log: off + +// Display save log? (for debug only) (default: off) (Note 1) +save_log: off + +// Display errors? (for debug only) (default: off) (Note 1) +error_log: off + +// Display other stuff? (for debug only) (default: off) (Note 1) +etc_log: off + +// Save Clothes color. (This will degrade performance [in txt?]) (Note 1) +save_clothcolor: yes + +// Undead type differeniate. +// 0 = element undead +// 1 = race undead +// 2 = both +undead_detect_type: 2 + +// Operational mode of automatic counter. +// 0 = disregard DEF and HIT+20 . CRI*2, 1 = 100% critical +// Players +player_auto_counter_type: 0 +// Monsters +monster_auto_counter_type: 0 + +// Type of penalty that is applied to FLEE when more than agi_penaly_count monsters are targetting player +// 0 = no penalty is applied +// 1 = agi_penaly_num is reduced from FLEE as a % +// 2 = agi_penaly_num is reduced from FLEE as an exact amount +agi_penaly_type: 1 + +// Amount of enemies required to be targetting player before FLEE begins to be penalized +agi_penaly_count: 3 + +// Amount of FLEE penalized per each attacking monster more than agi_penaly_count +agi_penaly_num: 10 + +// Type of penalty that is applied to VIT defense when more than vit_penaly_count monsters are targetting player +// 0 = no penalty is applied +// 1 = vit_penaly_num is reduced from FLEE as a % +// 2 = vit_penaly_num is reduced from FLEE as an exact amount +vit_penaly_type: 1 + +// Amount of enemies required to be targetting player before VIT defense begins to be penalized +vit_penaly_count: 3 + +// Amount of VIT defense penalized per each attacking monster more than vit_penaly_count +vit_penaly_num: 5 + +// When the player attacks an object, the calculation method of DEF. +// With 0 this will be ignored specification, at 1 or more def = subtraction of (DEF* value). +player_defense_type: 0 + +// When the monster attacks an object, the calculation method of DEF. +// With 0 this will be ignored, at 1 or more def = subtraction of (DEF* value). +monster_defense_type: 0 + +// When the pet attacks an object, the calculation method of DEF. +// With 0 this will be ignored specification, at 1 or more def = subtraction of (DEF* value). +pet_defense_type: 0 + +//MDEFTame as above....(MDEF*value) +magic_defense_type: 0 + +// Whether or not, ground skills of the players' will stack. (Note 1) +player_skill_reiteration: no + +//Whether or not, ground skills of the monsters' will pile up. (Note 1) +monster_skill_reiteration: no + +//Whether or not ground based skills of a certain type such as traps can be cast straight onto other players. (Note 1) +player_skill_nofootset: yes + +//Whether or not ground based skills of a certain type such as traps can be cast straight onto monsters. (Note 1) +monster_skill_nofootset: yes + +// When a player is cloaking, Whether the wall is checked or not. (Note 1) +// Note: Gravity announced that they were changing cloaking so it would +// not need a wall, but this was never implemented. I set to no, for fun. +player_cloak_check_type: no + +// When a monster is cloaking, Whether the wall is checked or not. (Note 1) +monster_cloak_check_type: no + +// Melee damage adjustments for WoE battles (Guild Vs Guild) (Note 2) +gvg_short_attack_damage_rate: 100 + +// Ranged damage adjustments for WoE battles (Guild Vs Guild) (Note 2) +gvg_long_attack_damage_rate: 100 + +// Magic damage adjustments for WoE battles (Guild Vs Guild) (Note 2) +gvg_magic_attack_damage_rate: 100 + +// Misc damage adjustments for WoE battles (Guild Vs Guild) (Note 2) +gvg_misc_attack_damage_rate: 100 + +// When the empelium is broken with WoE mode on, How Long Before The Declaration Of Castle Owner +// and Removal of Monsters/Players from Castle. (in milliseconds) +gvg_eliminate_time: 7000 + +// Whether or not skill is used vis-a-vis the user at the time of MOB skill motion of condition skillused. (Note 1) +// Not sure what this means, something about monsters changing target? +mob_changetarget_byskill: no + +// Player's Direction Changed When Attacking? (Note 1) +player_attack_direction_change: yes + +// Monsters's Direction Changed When Attacking? (Note 1) +monster_attack_direction_change: yes + +// If the player has Undead Elemental Equipment, should they be frozen or not. (Note 1) +player_undead_nofreeze: no + +// Will Player Skills Stay Within Land Limit or not? (Note 1) +player_land_skill_limit: yes + +// Will Monster Skills Stay Within Land Limit or not? (Note 1) +monster_land_skill_limit: yes + +// If a party uses a skill with penalties do they apply? (Note 1) +party_skill_penaly: yes + +// If monster's class is changed will it fully recover HP and SP and Ailments? (Note 1) +monster_class_change_full_recover: no + +// Do produced items have the maker's name on them? (Note 1) +produce_item_name_input: yes + +// Do produced potions have the maker's name on them? (Note 1) +produce_potion_name_input: yes + +// Do crafted arrows have the maker's name on them? (Note 1) +making_arrow_name_input: yes + +// Does created holy water have the maker's name on it? (Note 1) +holywater_name_input: yes + +// Stop logout for 10 seconds after a hit? (Note 1) +prevent_logout: yes + +// If skill fails by delay, should it display or not. (Note 1) +display_delay_skill_fail: yes + +// Can a player in chat room (in-game), be warped by a warp portal? (Note 1) +chat_warpportal: no + +// Can a monster be warped by a warp portal? (Note 1) +mob_warpportal: no + +// Is a monster summoned via dead branch aggresive? (Note 1) +dead_branch_active: yes + +// The highest value at which an item can be sold via the merchant vend skill. (in zeny) +vending_max_value: 10000000 + +// If someone loots, show name in party? (Note 1) +show_steal_in_same_party: no + +// Allow upper class (Advanced 2nd Class)? (Note 1) +// Just leave this at yes +enable_upper_class: yes + +// Is a usual attack of a pet delivered withOUT an attribute? (Note 1) +pet_attack_attr_none: no + +// Is a usual attack of a player delivered withOUT an attribute? (Note 1) +pc_attack_attr_none: no + +// Is a usual attack of a monster delivered withOUT an attribute? (Note 1) +mob_attack_attr_none: no + +// mob attacks againsts players wearing ghostring armor do full damage +mob_ghostring_fix: no + +// Does the Golden Thief Bug card only work during pvp? +// no or 0 - gtb works all the time +// 1 - 100 - percentage of magic damage reduced only during pvp (or gvg) +gtb_pvp_only: no + +// How to count the number of the enemies who do an agi penalty... +// 1 or less: It is a count altogether. +// 2: Full evasion exclusion +// 3: Full evasion and evasion exclusion +// 4 or more: Except all. +agi_penaly_count_lv: 2 + +// How to count the number of the enemies who do a vit penalty +// 1 or less: It is a count altogether. +// 2: Full evasion exclusion +// 3: Full evasion and evasion exclusion +// Four or more: Except all. +vit_penaly_count_lv: 3 + +// Grandcross Settings (Dont mess with these) +// Even if MOB (PC) has overlapped, it HIT(s) compulsion 3. (Default no) +gx_allhit: no +// The effect of the arms card of a damage %UP system is set also to GX at -L effect. (default no) +gx_cardfix: no +// The attribute affinity of GX is calculated doubly. (Default yes) +gx_dupele: yes +// Grandcross display type (Default 1) +// 0: Yellow character +// 1: White character +gx_disptype: 1 + +// If no than you can use the ensemble skills alone. (Note 1) +player_skill_partner_check: yes + +// Is the character of a GM account set as the object of a display by @ command etc. or not? +hide_GM_session: no + +// ユニット移動処-摯-@。0で-{鯖仕-l(回線負荷→重、鯖処-掾ィ軽)、1でAthena仕-l(回線負荷→軽、鯖処-掾ィ重) +// translation (babelfish): +// Unit portable place - ? @. +// With 0 - {mackerel SI -l (circuit load -> heavily, the mackerel place - the ? ? lightly), +// With 1 - Athena SI -l (circuit load -> lightly, the mackerel place - the ? ? it is heavy) +unit_movement_type: 0 + +// Are other requests accepted during [various things[party,guild]] a request or not? +// It does not accept by no accepted by yes. +invite_request_check: yes + +// リムーブトラップの仕-l 0:-{鯖仕-l、罠1個 1:Athena仕-l、使ったアイテムを使った個数 +// translation (babelfish): +// SI of ???????? -l +// 0: - {Mackerel SI -l, trap 1 +// 1:Athena SI -l, the quantity which used the item which was used +skill_removetrap_type: 0 + +// Will display experience gained from killing a monster. (Note 1) +disp_experience: no + +// Whether or not Marine Spheres and Floras summoned by Alchemist will drop items and give experience? (Note 1) +alchemist_summon_reward: no + +// Maximum level (default 255). Requires that you have an experience table that supports more than 99 levels to go +// any higher. It is left at 255 for default as to not cause problems for people who already have players at higher levels. +// @lvup command will not go higher than this value, and therefor will not loop back around 0. +maximum_level: 255 + +// Leave at 0 to use normal drop system. Anything higher than 0 will allow luk to affect drop rates, based on a percentage. +// Example 1: Setting of 10 with 50 luk would add 5 to the drop rate. So say a card has a drop rate of 2, it would become 7. +// Example 2 : Setting 100 with 99 luk would add 99 to the drop rate. +drops_by_luk: 0 + +// Do all monsters ignore GMs unless attacked? (Note 1) +monsters_ignore_gm: no + +// Turn equipment breaking on. (Note 1) +// Turning this one will allow equipment to break in battles, +// as well as some skills that have chance to break equipmen. +equipment_breaking: no + +// Overall rate of which equipment can break. (Note 2) [100 = .01% chance to break equipment before penalties.] +// Critical attacks will double chance to break equipment, and other skills (such as Power Thrust) will increase weapon breaking chance as well. +// This does not effect Sage weapon enchantment failure chance. +equipment_break_rate: 100 + +// PK Server Mode. Turns entire server pvp(excluding towns). Experience loss is doubled if killed by another player. +// When players hunt monsters over 20 levels higher, they will receive 15% additional exp., and 25% chance of receiving more items. +// There is a nopvp.txt for setting up maps not to have pk on in this mode. Novices cannot be attacked and cannot attack. +// Normal pvp counter and rank display are disabled as well. +pk_mode: no + +// Turn this on to allow a player to level up more than once from a kill. (Note 1) +multi_level_up: yes + +// Does using bow to do a backstab give a 50% damage penalty? (Note 1) +backstab_bow_penalty: yes + +// Choose if server begin with night (yes) or day (no) +night_at_start: no + +// Define duration in msec of the day (default: 7,200,000 = 2 hours) +// Set to 0 to disable day cycle (but not @day GM command). +// Except 0, minimum is 60000 (1 minute). +day_duration: 0 + +// Define duration in msec of the night (default: 1,800,000 = 30 min) +// Set to 0 to disable night cycle (but not @night GM command). +// Except 0, minimum is 60000 (1 minute). +night_duration: 0 + +// Will display a mob's hp/maxhp when the mouse cursor is over them. (Note 1) +// Will not display guardian or emperium hp. +// +// Still under testing (works but doesn't update) +show_mob_hp: no + +// Ban people that try to use an other name of its name (spoof name). +// Duration of the ban, in minutes (default: 5). Value from 0 to 32767 +// to disable the ban, set 0 +ban_spoof_namer: 5 + +// Set here minimum level of a (online) GM that can receive all informations about any player that try to hack, spoof a name, etc. +// Values are from 0 to 100. +// 100: disable information +// 0: send to any people, including normal players +// default: 60, according to GM definition in atcommand_athena.conf +hack_info_GM_level: 60 + +// Set here the minimum GM level to disable the nowarp (from) and nowarpto (to) flags. +// This option is mainly used in AT_commands (@memo, @warp, @charwarp, @go, etc...). All GM commands used to move or set a new map check nowarp and nowarpto flags. +// default: 20 (first level after normal player or super'normal' player) +any_warp_GM_min_level: 20 + +// Set here which client version do you accept. Add all values of clients: +// 1: Clients before 2004-07-06 (old clients) +// 2: 2004-07-06 kRO client +// 4: 2004-07-13 kRO client +// 8: 2004-07-26 kRO client +// 16: 2004-08-09 kRO / 2004-08-16aSakray / 2004-08-17aSakray client +// 32: 2004-09-06aSakray client +// default value: 63 (all clients) +packet_ver_flag: 63 + +// Allow GMs to mute players or not? +muting_players: no + +// Mail system - Only function in sql version +mail_system: no + +// valid range of dye's and styles on the client +min_hair_style: 0 +max_hair_style: 30 +min_hair_color: 0 +max_hair_color: 30 +min_cloth_color: 0 +max_cloth_color: 4 + +// Visible area size (how many squares away from a player can they see) +area_size: 14 + +// chat system: +// More than flood lines in threshold seconds gets a ban +// More than warn lines in threshold seconds gets a warning +chat_spam_flood: 10 +chat_spam_warn: 8 +chat_spam_threshold: 10 + +// How much to increment the line count if the content is lame. +// Lameness is defined as mostly caps, punctuation, or a repeat of the last line. +// Set to 1 or 2 depending on how much you hate hearing "ITEN PLZ!" 3 times in a row.. +chat_lame_penalty: 2 + +// how many hours to auto ban spammer, 0 to disable [0-32767]. Default 6. +chat_spam_ban: 1 + +// Maximum line lengt, if a message is above chat_maxline, its dropped [1-512]. Default 255. +chat_maxline: 512 + +// Packet flood protection +// If more than packet_spam_flood over-limits packets are recieved in +// packet_spam_threshold seconds, we will kick the user if packet_spam_kick +// is not set to 0. Limits on individual packets are defined in src/map/clif.c +packet_spam_flood: 30 +packet_spam_threshold: 2 +packet_spam_kick: 0 + +// local settings for this server in this file +import: conf/battle_local.conf diff --git a/conf/battle_local.conf.example b/conf/battle_local.conf.example new file mode 100644 index 00000000..c9ba222c --- /dev/null +++ b/conf/battle_local.conf.example @@ -0,0 +1 @@ +// Nothing needs to be done here. diff --git a/conf/build-magic.sh b/conf/build-magic.sh new file mode 100755 index 00000000..f064a286 --- /dev/null +++ b/conf/build-magic.sh @@ -0,0 +1,21 @@ +#! /bin/bash + +RSCRIPT="spells-build" + +if [ -a $RSCRIPT ]; then printf ""; else + echo '#! /bin/bash' > $RSCRIPT; + echo 'sed \' >> $RSCRIPT; + chmod a+x $RSCRIPT +fi + +for n in `grep -o '"#..."' magic.conf.template`; do + if grep $n $RSCRIPT; then printf ""; else + CHANGES=1 + echo "'s/${n}/${n}/;'\\" >> $RSCRIPT; + fi +done + +if [ x$CHANGES == x1 ] +then echo "${RSCRIPT} has been updated; please provide invocations for spells and/or teleport anchors."; +else cat magic.conf.template | ./$RSCRIPT > magic.conf; +fi diff --git a/conf/char_athena.conf b/conf/char_athena.conf new file mode 100644 index 00000000..094a4dfe --- /dev/null +++ b/conf/char_athena.conf @@ -0,0 +1,133 @@ +// Athena Character configuration file. + +// Option to force a player to create an e-mail. +// If a player have default e-mail, and if you activate this option, the player can only connect in the game (to arrive on a map) like follow: +// - Create at least 1 character +// - Select 1 character +// - Select DEL to enter his/her e-mail. (if OK is choosen, client says to the player: 'invalid e-mail') +// - If his/her e-mail is correct, the player enter in the game (an e-mail is saved definitively). +// - If his/her e-mail is incorrect, he/she have 'incorrect e-mail' and must select again DEL. +// - After entering in the game (when the player arrives on a map), DEL and SEL/OK button work normaly for all next connections. +// Resume: If a player have "incorrect/invalid e-mail" when he/she click on 'OK' button, +// the player must click 'DEL' button and register his/her NEW e-mail to enter in the game +// So, default is 0, because administrator must explain to their players before to activate this option. +email_creation: 0 + +// Is Character server in maintainence mode? +char_maintenance: 0 + +// Enable or disable creation of new characters. +char_new: 0 + +// Maximum users able to connect to the server. Set to 0 for unlimited. +max_connect_user: 0 + +// It's to check IP of a player between char-server and other servers (part of anti-hacking system) +// If player doesn't have same IP, connection is refused. +// Set to 0/off/no to not check IP of player. +// Set to 1/on/yes if you want to check (default) +// Note: if you enable this option, be sure that your (local/lan/wan) players use correct ip (in xml file) to contact servers, +// and that your LAN is correctly configured (!), and that LAN configuration of eathena is right. +check_ip_flag: yes + +// How often should the server save all files? (In seconds) +autosave_time: 15 + +// Character server flatfile database +char_txt: save/athena.txt + +// Choose to create or not backup file (yes/no, 0/1, etc...) +// default is 'no', because backup file take time for nothing. Actually, there is no problem on characters file creation and save. +backup_txt_flag: no + +// Character server flatfile database (backup) +backup_txt: save/athena_backup.txt + +// Start point, Map name followed by coordinates (x,y) +start_point: 001-2-1.gat,22,36 +start_point2: 001-2-1.gat,31,37 +start_point3: 001-2-1.gat,40,38 + +// Starting weapon for new characters +start_weapon: 1300 + +// Starting armor for new characters +start_armor: 0 + +// Starting zeny for new characters +start_zeny: 50 + +min_hair_style: 0 +max_hair_style: 30 +min_hair_color: 0 +max_hair_color: 30 + +// max number of char slots +char_slots: 10 + +// Name used for unknown characters +unknown_char_name: Unknown + +// Log Filename +char_log_filename: log/char.log + +// Allow or not identical name for characters but with a different case (upper/lower): +// example: Test-test-TEST-TesT; Value: 0 not allowed (default), 1 allowed +name_ignoring_case: 0 + +// Manage possible letters/symbol in the name of charater. Control character (0x00-0x1f) are never accepted. Possible values are: +// 0: no restriction (default) +// 1: only letters/symbols in 'char_name_letters' option. +// 2: Letters/symbols in 'char_name_letters' option are forbidden. All others are possibles. +char_name_option: 1 + +// Set the letters/symbols that you want use with the 'char_name_option' option. +// Note: add 'space' between 2 others letters/symbols. +// default: void. +// char_name_letters: [ ] { } , . | - # @ ! ~ ` ; : " " ? / \ = + < > +char_name_letters: abcdefghijklmnoprstquvwxyzABCDEFGHIJKLMNOPRSTQUVWXYZ1234567890- _+=!' + +// Filename of the file which receives the online players list in text +online_txt_filename: online.txt + +// Filename of the file which receives the online players list, but in html version +online_html_filename: online.html + +// Choose how to display online players. +// (sorting operation with a lot of online players can take time on a slow computer) +// 0: no sorting (default) +// 1: by alphabetical order of their name +// 2: by number of their zenys +// 3: by their base level +// 4: by their job (and job level inside the same job) +// 5: by alphabetical order of their actual map location +online_sorting_option: 0 + +// Choose which columns that you want display in the online files. Do the addition of these values: +// (if value is 0, no file is done) +// 1: name (just the name, no function like 'GM') +// 2: job +// 4: levels +// 8: map name +// 16: mapname and coordonates +// 32: zenys +// 64: name (with 'GM' if the player is a GM) +// default value: 1 (only name) +online_display_option: 64 + +// minimum GM level to display 'GM' when we want to display it (default: 1) +online_gm_display_min_level: 60 + +// refresh time (in sec) of the html file in the explorer (default 20) +online_refresh_html: 20 + +// Anti-freeze system enable +anti_freeze_enable: 0 +// Anti-freeze system interval (in seconds) +anti_freeze_interval: 6 + +// If you want use an additional configuration file, uncomment and use this parameter +//import: path/additional_configuration_file + +// local settings for this server in this file +import: conf/char_local.conf diff --git a/conf/char_local.conf.example b/conf/char_local.conf.example new file mode 100644 index 00000000..aabf6762 --- /dev/null +++ b/conf/char_local.conf.example @@ -0,0 +1,25 @@ +// Athena Character local configuration file. + +// wan ip override. this ip only will sended to cleints. +// wan_ip:1.2.3.4 + +// Server Communication username and password. +userid: s1 +passwd: p1 + +// Server name, no more than 19 characters +server_name: The Mana World + +// Wisp name for server: used to send wisp from server to players (between 4 to 23 characters) +wisp_server_name: Server + +// Login Server IP +login_ip:81.161.192.4 +// Login Server Port +login_port: 6901 + +// Character Server IP +char_ip:81.161.192.4 +// Character Server Port +char_port: 6122 + diff --git a/conf/eathena-monitor.conf.example b/conf/eathena-monitor.conf.example new file mode 100644 index 00000000..70dcd2e5 --- /dev/null +++ b/conf/eathena-monitor.conf.example @@ -0,0 +1,14 @@ +# $Id: eathena-monitor.conf,v 1.0 2006/13/10 21:42:22 Platyna Exp $ + +# By default the eathena-monitor looks for its config file in +# $HOME/tmwserver/conf/, creates the log file in $HOME/tmwserver/log/. +# You may use this file to adjust these settings if needed or use predefined +# defaults. Lines starting with hash mark or white space are ignored. + +# login_server=/home/athena/tmwserver/login-server +# map_server=/home/athena/tmwserver/map-server +# char_server=/home/athena/tmwserver/char-server +# workdir=/home/athena/tmwserver +# In seconds, default is 5. +# interval=2 +# logfile=/home/athena/tmwserver/log/monitor.log diff --git a/conf/gm_account.txt.example b/conf/gm_account.txt.example new file mode 100644 index 00000000..912e1a09 --- /dev/null +++ b/conf/gm_account.txt.example @@ -0,0 +1 @@ +// <account ID> <level> diff --git a/conf/grf-files.txt b/conf/grf-files.txt new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/conf/grf-files.txt diff --git a/conf/help.txt.example b/conf/help.txt.example new file mode 100644 index 00000000..c12b1a89 --- /dev/null +++ b/conf/help.txt.example @@ -0,0 +1,193 @@ +// put at first, the minimum level to display the line + 0:To use one command, type it inside the message window where you usually type to chat. + 0:@help - display this help. + 0:@email <actual@email> <new@email> - to change your e-mail (characters protection) + 80: + 80:@setmagic + 80:@magicinfo + 0: + 0:--- INFORMATION CMD --- + 0:@servertime - Display the date/time of the server + 99:@ignorelist - Displays your ignore list + 40:@where [char name] - Tells you the location of a character + 40:@who/@whois [match_text] - Display a listing of who is online and where + 40:@whogroup [match_text] - Display a listing of who is online and their party/guild + 40:@whomap/@whomapgroup [map] - like @who/@who2/@who3 but only for specifical map + 40:@whogm [match_text] - Like @who+@who2+who3, but only for GM. + 60:@charstatsall - Displays stats of all characters. + 60:@charitemlist <char name> - Displays all items of a player. + 60:@charstoragelist <char name> - Displays all items of a player's storage. + 60:@charcartlist <char name> - Displays all items of a player's cart. + 60:@ipcheck <char name> - Display all characters online from a characters IP address + 99:@mapinfo [<0-3> [map]] - Give information about a map (general info +: 0: no more, 1: players, 2: NPC, 3: shops/chat). + 99: + 99:@guildspy <guild_name/id> - You will receive all messages of the guild channel + 99:@partyspy <party_name/id> - You will receive all messages of the party channel + 60: + 60:--- MESSAGE CMD --- + 60:@broadcast <message> - Broadcasts a GM message with name of the GM + 60:@kami/@kamib <message> - Broadcasts a GM message without name of the GM + 60:@localbroadcast <message> - Broadcasts a GM message with name of the GM + 40: + 40:--- CHANGE GM STATE CMD --- + 40:@die ---- suicide + 40:@hide - Makes you invisible to monsters and other reporting functions. Type @hide again become visible. + 60:@invisible - Makes your character invisible (complete) + 60:@visible - Makes your character visible (opposite of @invisible) + 40:@save - Sets respawn point to current spot + 40:@return - Warps you to your save point + 40:@warp <mapname> <x> <y> - Warps you to the selected position + 40:@jump [x [y]]- Randomly warps you like a flywing. + 40:@goto <char name> - Warps you to selected character + 40:@follow <char_name> - follow a player + 40:@go <number/city_name> - Warps you to a city. + 40: -3: (Memo point 2) 1: morocc 5: izlude 9: yuno 13: niflheim + 40: -2: (Memo point 1) 2: geffen 6: aldebaran 10: amatsu 14: louyang + 40: -1: (Memo point 0) 3: payon 7: xmas (lutie) 11: gonryun 15: start point + 40: 0: prontera 4: alberta 8: comodo 12: umbala 16: prison/jail + 60:@hugo - iterate over players forward + 60:@linus - iterator over players backwards + 40: + 40:@log/@l - Send text to the GM log + 40:@tee/@t - Send text to the GM log and local chat + 40: + 60:@alive - Revives yourself from death + 40:@heal [<HP> <SP>] - Heals the desired amount of HP and SP. No value specified will do a full heal. + 40: + 60:@blvl <number of levels> - Raises your base level the desired number of levels. The max is 255 (User Defined). + 60:@jlvl <number of levels> -Raises your job level the desired number of levels. The max is 50 For Basic Classes. For Super Novice and Advanced Classes it is 70. + 60:@allskills - Give you all skills. + 80:@option <param1> <param2> <param3> - Adds different visual effects on or around your character + 80: <param1> <param2> <p3>(stackable) <param3> <param3> + 80: 1 Petrified (stackable) 01 Sight 32 Peco Peco riding 2048 Orc Head + 80: 2 Frozen 01 Poison 02 Hide 64 GM Perfect Hide 4096 Wedding Sprites + 80: 3 Stunned 02 Cursed 04 Cloak 128 Level 2 Cart 8192 Ruwach + 80: 4 Sleeping 04 Silenced 08 Level 1 Cart 256 Level 3 Cart + 80: 6 darkness 08 ??? 16 Falcon 512 Level 4 Cart + 80: 16 darkness 1024 Level 5 Cart + 99:@mountpeco - Give/remove you a peco (Class is required, but not skill) + 99:@disguise <monster_name_or_monster_ID> - Change your appearence to other players to a mob. + 99:@undisguise - Restore your normal appearance. + 99:@model <hair ID: 0-17> <hair color: 0-8> <clothes color: 0-4> - Changes your characters appearence. + 40:@dye/@ccolor <clothes color: 0-4> - Changes your characters appearence (only clothes color). + 40:@hairstyle <hair ID: 0-17> - Changes your characters appearence (only hair style). + 40:@haircolor <hair color: 0-8> - Changes your characters appearence (only hair color). + 40:@speed <1-1000> - Changes you walking speed. 1 being the fastest and 1000 the slowest. Default 150. + 99:@effect <effect_id> [flag] - Give an efect to your character. + 60:@dropall - throws all your possession on the ground + 60:@storeall - puts all your possessions in storage + 60:@killable - make your character killable + 60:@stpoint <number of points> - Gives you the desired number of stat points. + 60:@skpoint <number of points> - Gives you the desired number of skill points. + 80:@zeny <amount> - Gives you desired amount of Zeny. + 60:@str,@agi,@vit,@int,@dex,@luk <amount> - Adds desired amount to any stat. For example "@str 10" raises your str by 10 + 60:@allstats [value] - Adds value in all stats (maximum if no value). + 99:@memo [memo_position] - set/change a memo location (no position: display memo points). + 99:@questskill <#> - Gives you the specified quest skill + 80:@lostskill <#> - Takes away the specified quest skill from you + 60:@skillid <name> - look up a skill by name + 60:@useskill <skillid> <skillv> <target> - use a skill on target + 80:@addwarp <map name> <x coord> <y coord> + 60: + 60:--- MONSTERS CMD --- + 60:@spawn <monster_name_or_monster_ID> [<number to spawn> [<x coord> [<y coord>]]] + 60:@summon <monster_name_or_monster_ID> [<number to spawn> [<desired_monster_name> [<x coord> [<y coord>]]]] + 60:@killmonster [map] - kill all monsters of the map (they drop) + 60:@killmonster2 - kill all monsters of your map (without drops) + 40: + 40:--- ITEMS CMD --- + 40:@storage - Opens storage + 99:@gstorage - Opens guild storage + 80:@item <item name or ID> <quantity> - Gives you the desired item. + 40:@itemreset - Remove all your items. + 80:@itemcheck - Check your items with authorised items. + 80:@idsearch <part_of_item_name> - Search all items that name have part_of_item_name + 60:@produce <equip name or equip ID> <element> <# of very's> + 60: Element: 0=None 1=Ice 2=Earth 3=Fire 4=Wind + 60: It has separately with fragment 3 of the attribute + stars, you can apply. + 60: + 60:--- PVP CMD --- + 60:@pvpon - Turns pvp on on the current map + 60:@pvpoff - Turns pvp off on the current map + 99:@gvgon/@gpvpon - Turns gvg on on the current map + 99:@gvgoff/@gpvpoff - Turns gvg off on the current map + 99:@agitstart - Starts War of Emperium + 99:@agitend - End War of Emperium + 99: + 99:--- GROUPS CMD --- + 99:@party <party_name> - Create a party. + 99:@guild <guild_name> - Create a guild. + 99:@guildlvl <# of levels> - Raise Guild by desired number of levels + 99:@guildrecall <guild_name/id> - Warps all online characters of a guild to you. + 99:@partyrecall <party_name/id> - Warps all online characters of a party to you. + 40: + 40:--- REMOTE CHAR CMD --- + 60:@kill <char name> - Kills specified character. + 60:@charkillable <char name> - make another character killable + 60:@chardropall <char name> - throws all a chars possession on the ground + 60:@charstoreall <char name> - puts all of anothers charactes possessions in storage + 60:@recall <char name> - Warps target character to you. + 80:@recallall - Warps every character online to you. + 60:@charwarp <mapname> <x> <y> <char name> - Warps character to location of choice + 60:@revive <char name> - Revives target character. + 40:@charstats <char name> - Displays a characters stats. + 99:@charignorelist <char name> - Displays ignore list of the player + 60:@inall <char name> - Allows all wispers for the player + 60:@exall <char name> - Blocks all wispers for the player + 80:@charoption <param1> <param2> <param3> <charname> - Like @option command but only to target character. + 99:@charmountpeco <charname> - Give/remove to a player a peco (Class is required, but not skill). + 60:@charsave <map> <x> <y> <charname> - Changes the target players respawn point. + 60:@charblvl <#> <nickname> - Change a characters base level. + 60:@charjlvl <#> <nickname> - Change a characters job level. + 80:@charzeny <amount> <name> - Give/take a players Zeny + 60:@charstpoint <amount> <name> - Give/take a players stat points + 60:@charskpoint <amount> <name> - give/take a players skill points + 60:@charskreset <charname> - Reset skills of a character. + 60:@charstreset <charname> - Reset stats of a character. + 60:@charreset <charname> - Reset stats AND skills of a character. + 99:@charquestskill <#> <charname> - Gives to a player the specified quest skill. + 99:@charlostskill <#> <charname> - Takes away the specified quest skill from the player. + 60:@chardelitem <item_name_or_ID> <quantity> <player> - Remove items from a character + 99:@charmodel <hair type> <hair color> <clothes color> <name> - Changes a player's model + 99:@chardisguise <monster_name_or_monster_ID> <char name> - Changes disguise of a player + 99:@charundisguise <char name> - Cancels disguise of a player + 60:@charchangesex <name> - Changes sex of a player (all characters of the account) + 60:@block <name> - Blocks definitively a account + 60:@unblock <name> - Unblocks a account + 60:@ban <time> <name> - Ban temporarily a account + 60: time usage: adjustement (+/- value) and element (y/a, m, d/j, h, mn, s) + 60: Example: @ban +1m-2mn1s-6y testplayer + 60:@unban <name> - Unban a account + 60:@jail <char_name> - Sends specified character in jails + 60:@unjail <char_name> - Discharges specified character/prisoner + 60:@trade <char_name> - Open a trade window with a another player + 40:@kick <charname> - Kicks specified character off the server + 99:@kickall - Kick all characters off the server + 99:@mapexit - Kick all players and shut down map-server. + 80:@doom - Kills all NON GM chars on the server. + 80:@doommap - Kills all non GM characters on the map. + 80:@raise - Resurrects all characters on the server. + 80:@raisemap - Resurrects all characters on the map. + 80: + 80:--- ENVIRONMENT CMD --- + 80:@night - Uses @option 00 16 00 on all characters. All characters are in darkness. + 80:@day - Uses @option 00 00 00 on all characters. + 80:@skillon - turn skills on for a map + 80:@skilloff - turn skills on for a map + 80: + 80:--- ADMIN CMD --- + 99:@reloaditemdb - Reload item database (admin command) + 99:@reloadmobdb - Reload monster database (admin command) + 99:@reloadskilldb - Reload skills definition database (admin command) + 99:@reloadscript - Reload all scripts (admin command) + 99:@reloadgmdb - Reload GM levels (admin command) + 99:@adjgmlvl - Do a temporary adjustment of the GM level of a player (admin command) + 99:@adjcmdlvl - Do a temporary adjustment of the GM level of a command (admin command) + 80:@enablenpc <NPC_name> - Enable a NPC (admin command) + 80:@disablenpc <NPC_name> - Disable a NPC (admin command) + 80:@npcmove + 80: + 99:@gat - For debugging (you inspect around gat) + 99:@packet - For debugging (packet variety) + 99: +100:@GM <password> - it becomes GM! diff --git a/conf/inter_athena.conf b/conf/inter_athena.conf new file mode 100644 index 00000000..72a88bd9 --- /dev/null +++ b/conf/inter_athena.conf @@ -0,0 +1,31 @@ +// Athena InterServer configuration. + +// Storage flatfile database, used for Karfa storage. +storage_txt: save/storage.txt + +// Party flatfile database, for party names, members and other party info. +party_txt: save/party.txt + +// Guild flatfile database, for guild names, members, and other guild info. +guild_txt: save/guild.txt + +// Pet flatfile database, for pet names, and other pet info. +pet_txt: save/pet.txt + +// Castle flatfile database, for emperium war castles, etc. +castle_txt: save/castle.txt + +// Inter Log Filename +inter_log_filename: log/inter.log + +// Level range for sharing within a party +party_share_level: 10 + +// The lowest GM level on your server +lowest_gm_level: 1 + +// How often the GM accounts will be reloaded by the map-server in minutes +read_gm_interval: 10 + + + diff --git a/conf/ladmin_athena.conf b/conf/ladmin_athena.conf new file mode 100644 index 00000000..2a91a35b --- /dev/null +++ b/conf/ladmin_athena.conf @@ -0,0 +1,28 @@ +// Athena Ladmin configuration file. + +// Encoding type of the password +// 0: not encoded +// 1: key+password +// 2: password+key +passenc: 2 + +// Language of ladmin +// F: Fran軋is +// E: English (default) +defaultlanguage: E + +// Log Filename. All operations done by the software are logged in this file. +ladmin_log_filename: log/ladmin.log + +// Indicate how to display date in logs, to players, etc. +// 0: 31-12-2004 23:59:59 +// 1: 12-31-2004 23:59:59 +// 2: 2004-31-12 23:59:59 +// 3: 2004-12-31 23:59:59 (default) +date_format: 3 + +// If you want use an additional configuration file, uncomment and use this parameter +//import: path/additional_configuration_file + +// local settings for this server in this file +import: conf/ladmin_local.conf diff --git a/conf/ladmin_local.conf.example b/conf/ladmin_local.conf.example new file mode 100644 index 00000000..b3f88e8d --- /dev/null +++ b/conf/ladmin_local.conf.example @@ -0,0 +1,10 @@ +// Athena Ladmin local configuration file. + +// Login Server IP +login_ip:217.172.177.27 +// Login Server Port +login_port: 6900 + +// Administrative password, used to connect remotely to server. +// NOTICE: If you enable remote administration, you should change its value for security +admin_pass: admin diff --git a/conf/lan_support.conf b/conf/lan_support.conf new file mode 100644 index 00000000..bfaec696 --- /dev/null +++ b/conf/lan_support.conf @@ -0,0 +1,41 @@ +// Athena TXT version LAN configure file. +// Support Client Connect to Local Area Network (LAN) IP Address Server. +// put this fle into conf/ directory +// +// HOWTO: +// To use this file, the login-server, char-server and map-server must be on the same subnetwork +// (not necessary on the same computer). You can not use eAthena if you want to install the servers on 2 or more different LAN. +// +// First of all: you must configure your router to forward your WAN IP (one or more) and port (default: 6900, 6121 and 5121) +// to the right concerned computer(s) (if default port, forward 6900 port to the (LAN IP) login-server, 6121 port to the (LAN IP) char-server, etc.). +// After, set in char_athena.conf and map_athena.conf files the WAN IP and the right ports that you use. +// Give to WAN people (client that are not on your LAN) your WAN IP to have an access to your server. +// At this point, all players outside your LAN can access to your server(s). +// +// Now, you must parameter your LAN for the servers. +// Set the LAN IP of the char-server and the map-server in this file (lan_char_ip and lan_map_ip). +// Set the definition of your LAN in this file (subnet and subnetmask). +// When you load/start login-server and char-server, read what the server displays, and specially the section ---LAN CONFIGURATION---. +// If you see a warning or something not good, correct it. +// Now LAN client can access to your server. +// +// NB: if you want that nobody of your LAN can access to your server, put 127.0.0.1 in IP and 255.255.255.255 for the mask. +// So only the localhost computer would access to your server. +// NB2: you can use LAN name if you have some instead of IP and/or mask. +// NB3: if you want set your server only for LAN people, set your LAN IP instead of the WAN IP, and set 127.0.0.1/255.255.255.255 for the LAN IP. +// +// HOW THAT WORKS: +// When someone tries to connect to your server(s), the login-server/char-server checks its IP with the LAN subnet (subnet and subnetmask parameters). +// If it matches, the login-server sends the LAN IP of the char-server (lan_char_ip); and char-server do same for map-server (lan_map_ip). +// If not, the login-server sends the WAN IP of the char-server that it have received (char_ip in char_athena.conf) +// and the char-server sends the WAN IP of the map-server that it have received (map_ip in map_athena.conf) + +// put here the LAN IP of your char-server +lan_char_ip: 127.0.0.1 + +// put here the LAN IP of your map-server +lan_map_ip: 127.0.0.1 + +// put here the Subnet mask of your LAN +subnet: 127.0.0.1 +subnetmask: 255.255.255.255 diff --git a/conf/login_athena.conf b/conf/login_athena.conf new file mode 100644 index 00000000..9a486cdd --- /dev/null +++ b/conf/login_athena.conf @@ -0,0 +1,130 @@ +// Athena Login Server configuration file. +// Translated by Peter Kieser <pfak@telus.net> + +// Level of new GM created with @gm command. (default: 60) +// If you set to 0, you disable creation of new GM with @gm. +// To be able to create a gm with @gm, you must: +// - give a level to this value (not 0) +// - enable to level 0 the @gm command (atcommand_athena.conf) (default 100) +// - enable gm commands to normal player (battle_athena.conf, atcommand_gm_only parameter) +// - and normal player must give correct password when he use the @gm command +level_new_gm: 60 + +// Can you make new accounts on the server? (1 for Yes, 0 for no) +new_account: 1 + +// Manage possible letters/symbol in account name. Control character (0x00-0x1f) are never accepted. Possible values are: +// 0: no restriction (default) +// 1: only letters/symbols in 'account_name_letters' option. +// 2: Letters/symbols in 'account_name_letters' option are forbidden. All others are possibles. +account_name_option: 1 + +// Set the letters/symbols that you want use with the 'account_name_option' option. +// Note: add 'space' between 2 others letters/symbols. +// default: void. +// account_name_letters: [ ] { } , . | - # @ ! ~ ` ; : " " ? / \ = + < > +account_name_letters: abcdefghijklmnoprstquvwxyzABCDEFGHIJKLMNOPRSTQUVWXYZ1234567890- _+=!' + + +// Account flatfile database, stores account information. +account_filename: save/account.txt + +// What account AIDs have GM privs, and what level? +gm_account_filename: conf/gm_account.txt + +// Timer to check if GM_account file has been changed and reload GM account automaticaly +// (in seconds; default: 15; value: 0 (disabled), or 2 or more) +gm_account_filename_check_timer: 15 + +// Log Filename. All operations received by the server are logged in this file. +login_log_filename: log/login.log + +// Name of the file of that logs the unknown packets (for debug or hack check) +login_log_unknown_packets_filename: log/login_unknown_packets.log + +// Indicate if the unknown packets are saved or not +//(the unknown packets coming from the char-server or ladministration does not relate to, which is always saved) +// Be careful: if you receive an attack, your hard disk can cause lag... +// So, active this option with a speed hard disk or for debug only. +save_unknown_packets: 0 + +// Indicate if you want display the parse of the packets received in a normal connection +// It's useful for debug. Possible values: 0: no (default), 1: yes +display_parse_login: 0 + +// Indicate if you want display the parse of the packets received in administration connection +// It's useful for debug. Possible values: 0: no (default), 1: yes +display_parse_admin: 0 + +// Indicate if you want display the parse of the packets received from a char-server +// It's useful for debug. Possible values: 0: no (default), 1: yes (without packet 0x2714), 2: all packets +display_parse_fromchar: 0 + +// Indicate how to display date in logs, to players, etc. +// 0: 31-12-2004 23:59:59 +// 1: 12-31-2004 23:59:59 +// 2: 2004-31-12 23:59:59 +// 3: 2004-12-31 23:59:59 (default) +date_format: 3 + +// Indicate the minimum GM level of player that the server accepts to connection. +// 0: all players (normal player are 0. it's default), 1-99: GM level at least with level x +min_level_to_connect: 0 + +// Give possibility to adjust (ladmin command: timeadd) the time of an unlimited account. +// If set to on/1/yes..., the adjustment is be done from actual time to set the final time of the account. +// If set to no/0/no..., the adjustment can not be done on an unlimited account. You must set (ladmin command: timeset) a final time before to adjust (ladmin command: timeadd) +add_to_unlimited_account: off + +// Starting additional sec from now for the limited time at creation of account +// -1: new account are created with UNlimited time (default value) +// 0 or more: new accounts was created by addition of the value (in sec) to the actual time (to set first limited time) +start_limited_time: -1 + +// It's to check IP of a player between login-server and char-server (part of anti-hacking system) +// If player doesn't have same IP, connection is refused. +// Set to 0/off/no to not check IP of player. +// Set to 1/on/yes if you want to check (default) +// Note: if you enable this option, be sure that your (local/lan/wan) players use correct ip (in xml file) to contact servers, +// and that your LAN is correctly configured (!), and that LAN configuration of eathena is right. +// if not correct, you can read list of char-servers, but not look slots of characters (rejected by server). +check_ip_flag: no + +// Specify order of IP control if necessary (option: 'deny,allow', 'allow,deny', or 'mutual-failture') +// (how to use 'allow' and 'deny' information) +//order: allow,deny + +// Indicate the IP that the server accept. +// put: 'all', or 'xxx.xxx.' (begin of an ip finished by '.' or a complete ip), +// or a network and its mask (example: '123.456.789.012/24' or '123.456.789.012/255.255.255.0') +// or 'clear' to suppress previous parameter (use it in import file mainly) +// Add as many IP's as you wish. +//allow: all + +// Indicate the IP that the server refuse. +// Add as many IP's as you wish, as long as you put deny: before it. +//deny: 123.123.123.123 +//deny: 234.234.234.234 + +// If you want use an additional configuration file, uncomment and use this parameter +//import: path/additional_configuration_file + +//Passwords in Login DB are MD5 - <passwordencrypt> cannot b used on client with this on +use_MD5_passwords: no + +//Ban features: read readme for more info if you dont know this. +ipban: 1 +dynamic_pass_failure_ban: 1 +dynamic_pass_failure_ban_time: 5 +dynamic_pass_failure_ban_how_many: 3 +dynamic_pass_failure_ban_how_long: 60 +dynamic_account_ban: 1 +dynamic_account_ban_class: 0 + +// Anti-freeze system enable +anti_freeze_enable: 0 +// Anti-freeze system interval (in seconds) +anti_freeze_interval: 15 + +// local settings for this server in this file +import: conf/login_local.conf diff --git a/conf/login_local.conf.example b/conf/login_local.conf.example new file mode 100644 index 00000000..bf892f33 --- /dev/null +++ b/conf/login_local.conf.example @@ -0,0 +1,30 @@ +// Athena Login Server local configuration file. + +// wan ip override. this ip only will sended to cleints. +// wan_ip:1.2.3.4 + +// Port to bind Login Server to (always binds to all IP addresses) +login_port: 6901 + +// Whether remote administration is enabled or disabled (1 for enabled, 0 for disabled) +admin_state: 1 + +// Administrative password, used by ladmin (perl software) to connect remotely to server. +// NOTICE: If you enable remote administration, you should change its value for security +admin_pass: p1 + +// Indicate the IP that the server accepts for remote administration. +// put: 'all', or 'xxx.xxx.' (begin of an ip finished by '.' or a complete ip), +// or a network and its mask (example: '123.456.789.012/24' or '123.456.789.012/255.255.255.0') +// or 'clear' to suppress previous parameter (use it in import file mainly) +// Add as many IP's as you wish. +ladminallowip: all + +// Gamemaster password, used with the @gm command to obtain GM commands (level of gm set with level_new_gm parameter). +// NOTICE: You should also change this one. +gm_pass: gm + +// Update host +// Tells the client that an alternative updatehost is available if the client +// supports this. If left out nothing will be sent. max length 127. +update_host: http://updates.themanaworld.org/ diff --git a/conf/magic.conf.template b/conf/magic.conf.template new file mode 100644 index 00000000..c440bf39 --- /dev/null +++ b/conf/magic.conf.template @@ -0,0 +1,1835 @@ +# Special-purpose globals +obscure_chance = 95 +min_casttime = 200 + +# Schools of magic +CONST MAGIC = 340 +CONST LIFE = 341 +CONST WAR = 342 +CONST TRANSMUTE = 343 +CONST NATURE = 344 +CONST NECROMANCY = 345 + +# Elements +CONST ELT_NEUTRAL = 0 +CONST ELT_WATER = 1 +CONST ELT_EARTH = 2 +CONST ELT_FIRE = 3 +CONST ELT_WIND = 4 +CONST ELT_POISON = 5 +CONST ELT_SHADOW = 6 +CONST ELT_HOLY = 7 +CONST ELT_GHOST = 8 +CONST ELT_UNDEAD = 9 + +# Status effects + +CONST SC_WINDWALK = 116 +CONST SC_POISON = 132 +CONST SC_SHEARED = 194 # This is the same as SC_HIDE, since mobs can't hide and shearing is only used for mobs. Feel free to fix! +CONST SC_HIDE = 194 +CONST SC_HALT_REGENERATE = 195 +CONST SC_FLYING_BACKPACK = 196 +CONST SC_MBARRIER = 197 +CONST SC_HASTE = 198 +CONST SC_PHYS_SHIELD = 199 +CONST EVOL_GUILD = 500 +CONST EVOL_CRAFT = 501 +CONST EVOL_DYE = 502 + +CONST SO_GMINVISIBLE = 4096 + +# Spells constants + + +CONST LESSER_HEAL_HP =50 +CONST MEDIUM_HEAL_HP =250 +CONST FULL_HEAL_HP =1000000 +CONST LESSER_GROUP_HEAL_HP =30 +CONST MEDIUM_GROUP_HEAL_HP =150 +CONST FULL_GROUP_HEAL_HP_PERC =80 + + +# Special effects +CONST SFX_DEFAULT = 10 +CONST SFX_SUMMON_START = 21 +CONST SFX_SUMMON_FIRE = 22 +CONST SFX_TELEPORT = 24 +CONST SFX_RAIN = 25 +CONST SFX_HIT = 25 +CONST SFX_ARROW_HAIL = 27 +CONST SFX_SNOW = 33 +CONST SFX_BARRIER = 10 +CONST SFX_UNBARRIER = 10 +CONST SFX_HEAL = 3 + +CONST MAX_RAIN_SPELL_RADIUS = 15 + +CONST MAX_MAGIC_LEVEL = 2 # Increase up to 5 as each new magic level is completed. + +CONST MAGIC_FLAGS = "MAGIC_FLAGS" +CONST MFLAG_MADE_CONC_POTION = 16384 +CONST MFLAG_MADE_CONC_POTION_SHIFT = 14 + +CONST SCRIPT_XP = "MAGIC_EXPERIENCE" +CONST SCRIPT_XP_MASK = 0xffff +CONST SCRIPT_XP_SHIFT = 0 +CONST SCRIPT_LASTSPELL_MASK = 0xff +CONST SCRIPT_LASTSPELL_SHIFT = 16 +CONST SCRIPT_HEALSPELL_MASK = 0xff +CONST SCRIPT_HEALSPELL_SHIFT = 24 +CONST DEBUG = 0 + +CONST ATTACK_ICON_GENERIC = 2000 +CONST ATTACK_ICON_SHEARING = 2001 + +# Default sfx on caster +PROCEDURE default_effect() = + sfx(caster, school - MAGIC + 2, 0); + +PROCEDURE sfx_generic(target) = + sfx(target, SFX_DEFAULT, 0); + +PROCEDURE set_var(name, mask, shift, value) = + set_script_variable(caster, name, script_int(caster, name) & (neg (mask << shift)) | ((value & mask) << shift)); + +PROCEDURE gain_heal_xp(value, # How many HP we healed + gain, # how many life magic experience points we can potentially gain + heal_xp_value_divisor, # 1 for instaheal, 2 for slow heal + base_exp_factor) = # factor for how many base experience points (max) the player should be allowed to gain + last_heal_xp = (script_int(caster, SCRIPT_XP) >> SCRIPT_HEALSPELL_SHIFT) & SCRIPT_HEALSPELL_MASK; + IF (target <> caster + && (value / heal_xp_value_divisor) > (10 + last_heal_xp + random(last_heal_xp + 1) + random(last_heal_xp + 1))) + THEN ( + heal_xp = last_heal_xp + gain; + IF (heal_xp > SCRIPT_HEALSPELL_MASK) + THEN heal_xp = SCRIPT_HEALSPELL_MASK; + CALL set_var(SCRIPT_XP, SCRIPT_HEALSPELL_MASK, SCRIPT_HEALSPELL_SHIFT, heal_xp); + ) + IF target <> caster + THEN gain_experience(caster, base_exp_factor * extract_healer_experience(target, value), 0, 1); + +PROCEDURE gain_xp(gain) = + IF (level + 3 > skill(caster, MAGIC)) # Level 4 and 5 magic users don't gain anything from spell levels 0 resp. 0+1 + THEN ( + index = spell_index(self_spell); + last_index = (script_int(caster, SCRIPT_XP) >> SCRIPT_LASTSPELL_SHIFT) & SCRIPT_LASTSPELL_MASK; + last_xp = (script_int(caster, SCRIPT_XP) >> SCRIPT_XP_SHIFT) & SCRIPT_XP_MASK; + IF (index != last_index) + THEN ( # Some variation observed + xp = last_xp + gain; + IF (xp > SCRIPT_XP_MASK) + THEN xp = SCRIPT_XP_MASK; + CALL set_var(SCRIPT_XP, SCRIPT_XP_MASK, SCRIPT_XP_SHIFT, xp); + CALL set_var(SCRIPT_XP, SCRIPT_LASTSPELL_MASK, SCRIPT_LASTSPELL_SHIFT, index); + IF DEBUG THEN message(caster, "Spell xp = " + xp); + ) ELSE IF DEBUG THEN message(caster, "Re-cast same spell, xp remain at " + last_xp); + ) + +PROCEDURE create_item(good_item, count, bad_item, difficulty) = + success = 1; + score = experience + random(min(spellpower, (experience / 3) + 1)); + IF (score >= difficulty) + THEN create_item(caster, good_item, count); + ELSE ( + success = 0; + score = score + random(luk(caster)) + random(luk(caster)); + IF (score < difficulty / 3) + THEN ( + message(caster, "Your spell backfires!"); + IF (random(110) < (luk(caster))) + THEN itemheal(caster, 0 - ((level + 1) * (level + 2) * (3 + random(28))), 0); + ELSE itemheal(caster, 0 - (level + 1), 0); + ) ELSE IF (score < (difficulty * 2) / 3) + THEN ( + IF random(5) = 0 + THEN (message(caster, "Your spell solidifies into the shape of a mysterious object!"); + create_item(caster, "Iten", 1);) + ELSE message(caster, "Your spell escapes!"); + ) ELSE ( + message(caster, "Your spell takes on a mind of its own!"); + IF random(3) = 0 + THEN create_item(caster, bad_item, 1); + ) + ) + +# Increase spellpower by school and general magic skill +PROCEDURE adjust_spellpower(school) = + experience = (script_int(caster, SCRIPT_XP) >> SCRIPT_XP_SHIFT) & SCRIPT_XP_MASK; + spellpower = spellpower + (skill(caster, MAGIC) + skill(caster, school)) * 10; + # Below, we adjust by special items + IF (not(failed(target)) && (school = LIFE || school = NATURE)) + THEN IF (target) + THEN IF (pc(target) = partner(caster)) + THEN (spellpower = spellpower + 200; + IF is_equipped(caster, "WeddingRing") + THEN spellpower = spellpower + 50; + IF is_equipped(pc(target), "WeddingRing") + THEN spellpower = spellpower + 50;) + +PROCEDURE heal(target, max_heal) = + CALL default_effect(); + IF caster <> target + THEN sfx(target, SFX_HEAL, 0); + power = spellpower + vit(caster); + power = min(max_heal, (max_heal * power) / 250); + itemheal(target, power, 0); + +# Goes through instaheal instead of itemheal +PROCEDURE quickheal(target, power) = + CALL default_effect(); + IF caster <> target + THEN sfx(target, SFX_HEAL, 0); + instaheal(target, power, 0); + +# Can attack the target? Imports attack_range from dynamic environment +PROCEDURE attack_check(target) = + IF (not (line_of_sight(location(caster), location(target)))) + THEN ABORT; + IF (not (rdistance(location(caster), location(target)) <= attack_range)) + THEN ABORT; + +# Cause elemental damage. bonus_elt grants an attack bonus, malus_elt reduces the attack. `effect' is the sfx ID. +PROCEDURE elt_damage(target, damage, dmgplus, bonus_elt, malus_elt, effect) = + d = damage + random(dmgplus); + evade = level(target) + mdef(target); + IF (element(target) = malus_elt) + THEN d = d / 3; + IF (element(target) = bonus_elt) + THEN d = (d * (4 + element_level(target))) / 4; + #message(caster, "bonus=" + (element(target) = bonus_elt) + " malus=" + (element(target) = malus_elt) + " damage=" + damage + " + r(" + dmgplus + ") -> " + d); + sfx(target, effect, 0); + IF (spellpower - random(100) < evade) + THEN d = 0; + injure(caster, target, d, 0); + +PROCEDURE melee_damage(target, damage, dmgplus) = + CALL attack_check(target); + d = damage + random(dmgplus); + evade = level(target) + mdef(target); + IF (spellpower - random(100) < evade) + THEN d = 0; + injure(caster, target, d, 0); + + +PROCEDURE install_attack_spell(charges, base_delay, range, attack_animation) = + CALL default_effect(); + attack_range = range; + override_attack(caster, charges, ((200 - agi(caster)) * base_delay) / 200, + range, ATTACK_ICON_GENERIC, attack_animation, 0); + +PROCEDURE install_melee_spell(charges, base_delay, attack_animation) = + CALL install_attack_spell(charges, base_delay, 1, attack_animation); + +PROCEDURE summon_spell(mob_id, count, delay, lifetime, control_level) = + CALL default_effect(); + sfx(location, SFX_SUMMON_START, 0); + WAIT delay; + sfx(location, SFX_SUMMON_FIRE, 0); + spawn(rbox(location, 2), caster, mob_id, + if_then_else(skill(caster, ASTRAL) >= control_level, 2, 1), # pets when level is high enough + count, lifetime); + + +PROCEDURE abort_on_area_shield(pos) = + IF (is_exterior(pos) = 1 && (map_nr(pos) = 1 # Tulimshar + ||map_nr(pos) = 9 # Hurnscald + ||map_nr(pos) = 20 + ||map_nr(pos) = 99)) # Nivalis + THEN (message(caster, "A powerful magic drains your spell just as it is beginning to take shape!"); + ABORT;) + + +#-------------------------------------------------------------------------------- +# Level 0 spells +#-------------------------------------------------------------------------------- + +SPELL ask-magic-exp : "#G01" = + LET level = 0 + school = MAGIC + IN (MANA 1, CASTTIME 1000, + REQUIRE skill(caster, MAGIC) > level) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + level = skill (caster, MAGIC); + experience = (script_int(caster, SCRIPT_XP) >> SCRIPT_XP_SHIFT) & SCRIPT_XP_MASK; + IF (experience == SCRIPT_XP_MASK && level > 4) + THEN message (caster, "You are as proficient at magic as you can possibly be."); + ELSE ( + # This duplicates the table in mana-seed.txt + IF level > 4 + THEN max_experience = SCRIPT_XP_MASK; + ELSE IF level = 4 + THEN max_experience = 40000; + ELSE IF level = 3 + THEN max_experience = 8000; + ELSE IF level = 2 + THEN max_experience = 1200; + ELSE max_experience = 100; + + ratio = (10 * experience - random(max_experience / 30)) / max_experience; #Randomness: jitter a bit at the transitions to give more precise information if used frequently + + IF ratio >= 45 + THEN message(caster, "Magic flows naturally from you, readily and with ease. Your understanding of what you can currently control at present is flawless, far beyond your requirements to cast magic at this level." + if_then_else(level >= MAX_MAGIC_LEVEL,""," Surely the Mana Seed will more than readily offer more magic for such a proficient user.")); + ELSE IF ratio >= 20 + THEN message(caster, "You have perfect control of what you understand now, but there is now a distinct sensation of something more, something indescribable. If only the Mana Seed would give more magic to you..."); + ELSE IF ratio >= 10 + THEN message(caster, "You feel in perfect control of your magic" + if_then_else(level >= MAX_MAGIC_LEVEL,".",", and seem on the verge of something more... perhaps you should see the Mana Seed to ask for more magic?")); + ELSE IF ratio >= 9 + THEN message(caster, "You feel in almost perfect control of your magic."); + ELSE IF ratio >= 8 + THEN message(caster, "You feel that you have very good control of your magic."); + ELSE IF ratio >= 7 + THEN message(caster, "You feel quite in control of your magic."); + ELSE IF ratio >= 6 + THEN message(caster, "You feel mostly in control of your magic."); + ELSE IF ratio >= 5 + THEN message(caster, "You feel somewhat in control of your magic."); + ELSE IF ratio >= 4 + THEN message(caster, "You feel you still have a few difficulties in controlling your magic."); + ELSE IF ratio >= 3 + THEN message(caster, "Trying to control your magic is still rather troublesome."); + ELSE IF ratio >= 2 + THEN message(caster, "You feel that you have only the bare minimum of control over your magic."); + ELSE IF ratio >= 1 + THEN message(caster, "You feel quite overwhelmed by your magic, but are beginning to see patterns."); + ELSE message (caster, "You feel completely overwhelmed by your magic."); + ) + +# SPELL ask-life-magic-exp : "#G02" = +# LET level = 0 +# school = MAGIC +# IN (MANA 1, CASTTIME 1000, +# REQUIRE skill(caster, MAGIC) > level) +# => EFFECT CALL adjust_spellpower(school); +# CALL default_effect(); +# message(caster, "You have " + ((script_int(caster, "MAGIC_EXPERIENCE") >> 24) & 0xff) + " Life Magic Experience points."); + +SPELL transmute-wood-to-figurine (name : STRING) : "#T00" = + LET level = 0 + school = TRANSMUTE + IN (MANA 5, CASTTIME 4000, + REQUIRE skill(caster, MAGIC) > level, + COMPONENTS ["RawLog"]) + => ( REQUIRE name = "boo" => + EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL create_item("MoubooFigurine", 1, "WarpedLog", 40); + CALL gain_xp(1); + | REQUIRE name = "lurk" => + EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL create_item("WarpedLog", 1, "WarpedLog", 40); + message (caster, "You have no idea what a Skrytlurk looks like."); + ) + + +#-------------------------------------------------------------------------------- +# Evol Level 0 Life magic spells (change acorns with the real component) +#-------------------------------------------------------------------------------- + +SPELL lesser-heal (target : STRING) : "#L00" = + LET level = 0 + school = LIFE + IN (MANA 6, CASTTIME 500, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE if_then_else(failed(pc(target)), 1, + rdistance(location(caster), location(pc(target))) < 2 + (spellpower / 100)), + (CATALYSTS ["Acorn"])) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + IF failed(pc(target)) + THEN (target = caster;) + ELSE (target = pc(target); + IF is_dead(target) + THEN ABORT;) + CALL gain_heal_xp(min(200, max_hp(target) - hp(target)), 1, 2, 2); # report half values for non-instaheal + CALL heal(target, LESSER_HEAL_HP); + CALL gain_xp(1); + + +SPELL cure-poison (target : PC) : "#L01" = + LET level = 0 + school = LIFE + IN (MANA 15, CASTTIME 1000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + REQUIRE (rdistance(location(caster), + location(pc(target))) < 1 + (spellpower / 60)), + CATALYSTS ["Acorn"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + IF (running_status_update (target, SC_POISON)) + THEN (CALL gain_heal_xp(40, 1, 2, 2); + stop_status_change (target, SC_POISON); + CALL gain_xp(2); + IF caster <> target + THEN sfx(target, SFX_HEAL, 0);); + + +SPELL lesser-group-heal : "#L02" = + LET level = 0 + school = LIFE + IN (MANA 6, CASTTIME 500, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE if_then_else(failed(pc(target)), 1, + rdistance(location(caster), location(pc(target))) < 2 + (spellpower / 100)), + (CATALYSTS ["Acorn"])) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + FOREACH PC target IN rbox(location(caster), 4) DO + IF ( is_dead(target) = 0 && target <> caster && line_of_sight(location(caster), location(target))) + THEN (CALL sfx_generic(target); + CALL quickheal(target, LESSER_GROUP_HEAL_HP); + CALL gain_heal_xp(min(LESSER_GROUP_HEAL_HP, max_hp(target) - hp(target)), 1, 2, 2);) + CALL gain_xp(1); + + +#-------------------------------------------------------------------------------- +# End of Evol Level 0 Life magic spells +#-------------------------------------------------------------------------------- + +#-------------------------------------------------------------------------------- +# Evol Level 1 Life magic spells (change acorns with the real component) +#-------------------------------------------------------------------------------- + +SPELL medium-group-heal : "#L10" = + LET level = 1 + school = LIFE + IN (MANA 6, CASTTIME 500, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE if_then_else(failed(pc(target)), 1, + rdistance(location(caster), location(pc(target))) < 2 + (spellpower / 100)), + (CATALYSTS ["Acorn"])) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + FOREACH PC target IN rbox(location(caster), 6) DO + IF ( is_dead(target) = 0 && target <> caster && line_of_sight(location(caster), location(target))) + THEN (CALL sfx_generic(target); + CALL quickheal(target, MEDIUM_GROUP_HEAL_HP); + CALL gain_heal_xp(min(MEDIUM_GROUP_HEAL_HP, max_hp(target) - hp(target)), 1, 2, 2);) + CALL gain_xp(1); + +SPELL transfusion (target : STRING) : "#L11" = + LET level = 1 + school = LIFE + IN (MANA 6, CASTTIME 500, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE if_then_else(failed(pc(target)), 1, + rdistance(location(caster), location(pc(target))) < 2 + (spellpower / 100)), + (CATALYSTS ["Acorn"])) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + IF failed(pc(target)) + THEN (target = caster;) + ELSE (target = pc(target); + IF is_dead(target) + THEN ABORT;) + CALL gain_heal_xp(min(200, max_hp(target) - hp(target)), 1, 2, 2); # report half values for non-instaheal + points = min(500, hp(caster) - 1); + CALL quickheal(caster, -1 * points); + CALL quickheal(target, points); + CALL gain_xp(1); + +SPELL medium-heal (target : STRING) : "#L12" = + LET level = 1 + school = LIFE + IN (MANA 6, CASTTIME 500, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE if_then_else(failed(pc(target)), 1, + rdistance(location(caster), location(pc(target))) < 2 + (spellpower / 100)), + (CATALYSTS ["Acorn"])) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + IF failed(pc(target)) + THEN (target = caster;) + ELSE (target = pc(target); + IF is_dead(target) + THEN ABORT;) + CALL gain_heal_xp(min(200, max_hp(target) - hp(target)), 1, 2, 2); # report half values for non-instaheal + CALL heal(target, MEDIUM_HEAL_HP); + CALL gain_xp(1); + +#-------------------------------------------------------------------------------- +# End of Evol Level 1 Life magic spells +#-------------------------------------------------------------------------------- + +#-------------------------------------------------------------------------------- +# Evol Level 2 Life magic spells (change acorns with the real component) +#-------------------------------------------------------------------------------- + +SPELL revive (target : PC) : "#L20" = + LET level = 2 + school = LIFE + IN (MANA 12, CASTTIME 1000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["Acorn"]), + REQUIRE rdistance(location(target), location(caster)) < 2 + spellpower / 30) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + IF (target <> caster) + #resurrect the target with 100% hp, 100% mp (1 flag to use %, 0 to use absolute values) + THEN(resurrect(target, 1, 1, 0); + CALL gain_xp(10); + sfx(target, school - MAGIC + 2, 0);) + + +SPELL full-group-heal : "#L21" = + LET level = 2 + school = LIFE + IN (MANA 6, CASTTIME 500, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE if_then_else(failed(pc(target)), 1, + rdistance(location(caster), location(pc(target))) < 2 + (spellpower / 100)), + (CATALYSTS ["Acorn"])) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + FOREACH PC target IN rbox(location(caster), 10) DO + IF ( is_dead(target) = 0 && target <> caster && line_of_sight(location(caster), location(target))) + THEN (CALL sfx_generic(target); + CALL quickheal(target, max_hp(target) * (FULL_GROUP_HEAL_HP_PERC / 100)); + CALL gain_heal_xp(min(max_hp(target) * (FULL_GROUP_HEAL_HP_PERC / 100), max_hp(target) - hp(target)), 1, 2, 2);) + CALL gain_xp(1); + + +SPELL full-heal (target : STRING) : "#L22" = + LET level = 2 + school = LIFE + IN (MANA 6, CASTTIME 500, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE if_then_else(failed(pc(target)), 1, + rdistance(location(caster), location(pc(target))) < 2 + (spellpower / 100)), + (CATALYSTS ["Acorn"])) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + IF failed(pc(target)) + THEN (target = caster;) + ELSE (target = pc(target); + IF is_dead(target) + THEN ABORT;) + CALL gain_heal_xp(min(200, max_hp(target) - hp(target)), 1, 2, 2); # report half values for non-instaheal + CALL heal(target, FULL_HEAL_HP); + CALL gain_xp(1); + +#-------------------------------------------------------------------------------- +# End of Evol Level 2 Life magic spells +#-------------------------------------------------------------------------------- + +#-------------------------------------------------------------------------------- +# Evol Level 0 Nature magic spells (change acorns with the real component) +#-------------------------------------------------------------------------------- + +SPELL rain : "#N00" = + LET level = 0 + school = NATURE + IN (MANA 6, CASTTIME 500, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + CATALYSTS ["Acorn"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + #CALL abort_on_area_shield(location(caster)); + CALL gain_xp(1); + range = min(MAX_RAIN_SPELL_RADIUS, 3 + min(spellpower, 200) / 30); + area = rbox(location(caster), range); + FOR i = 0 TO (spellpower / 3) DO ( + FOR j = 0 TO min(spellpower / 2, 200) / 100 DO ( + location = random_location(area); + sfx(location, SFX_RAIN, 0); + ) + WAIT 400 + random(100); + ); + +SPELL speed : "#N02" = + LET level = 0 + school = NATURE + IN (MANA 6, CASTTIME 500, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + CATALYSTS ["Acorn"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + status_change(caster, SC_WINDWALK, 16, -50, 0, 0, 30000); + CALL gain_xp(1); + message(caster, "You feel you can move fast"); + +#-------------------------------------------------------------------------------- +# End of Evol Level 0 Nature magic spells +#-------------------------------------------------------------------------------- + +#-------------------------------------------------------------------------------- +# Evol Level 1 Nature magic spells (change acorns with the real component) +#-------------------------------------------------------------------------------- + +SPELL snow : "#N10" = + LET level = 0 + school = NATURE + IN (MANA 6, CASTTIME 500, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + CATALYSTS ["Acorn"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + #CALL abort_on_area_shield(location(caster)); + CALL gain_xp(1); + range = min(MAX_RAIN_SPELL_RADIUS, 3 + min(spellpower, 200) / 30); + area = rbox(location(caster), range); + FOR i = 0 TO (spellpower / 3) DO ( + FOR j = 0 TO min(spellpower / 2, 200) / 100 DO ( + location = random_location(area); + sfx(location, SFX_SNOW, 0); + ) + #WAIT 100 + random(100); + ); + +SPELL anti-magic (target : PC) : "#N12" = + LET level = 1 + school = NATURE + IN (MANA 6, CASTTIME 500, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + CATALYSTS ["Acorn"], + REQUIRE rdistance(location(target), location(caster)) < 2 + spellpower / 30) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + sfx(target, 11, 0); + IF (caster <> target) + THEN CALL default_effect(); + status_change(target, SC_MBARRIER, 20 + max(30, spellpower / 8), 0, 0, 0, 2000 + (spellpower * 200)); + status_change(target, SC_PHYS_SHIELD, 5 + max(15, spellpower / 20), 0, 0, 0, 5000 + (spellpower * 1000)); + message (target, "You are surrounded by a magical barrier."); + CALL gain_xp(5); + ATEND message (target, "Your magical barrier dissipates."); + sfx(target, 111, 0); + +#-------------------------------------------------------------------------------- +# End of Evol Level 1 Nature magic spells +#-------------------------------------------------------------------------------- + +#-------------------------------------------------------------------------------- +# Evol Level 1 Necromancy magic spells (change acorns with the real component) +#-------------------------------------------------------------------------------- + +SPELL destruction : "#NE12" = + LET level = 2 + school = NECROMANCY + IN (MANA 6, CASTTIME 500, + REQUIRE skill(caster, MAGIC) > level, + CATALYSTS ["Acorn"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + FOREACH MOB target IN rbox(location(caster), 10) DO ( + injure(caster, target, 1000, 0);) + #sfx(target, 16, 0);) + itemheal(caster, -1 * hp(caster) + 1, -10000); + CALL gain_xp(1); + +#-------------------------------------------------------------------------------- +# End of Evol Level 1 Necromancy magic spells +#-------------------------------------------------------------------------------- + +#-------------------------------------------------------------------------------- +# Evol Level 0 Transmutation magic spells (change acorns with the real component) +#-------------------------------------------------------------------------------- + +SPELL herb-transmut (target : PC) : "#T00" = + LET level = 0 + school = TRANSMUTE + IN (MANA 6, CASTTIME 500, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + CATALYSTS ["Acorn"], + CATALYSTS [646] OR CATALYSTS [647] OR CATALYSTS [648] OR CATALYSTS [649]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + esc = random(30); + IF (esc = 0) THEN ( + message (caster, "Your spell escapes!"); + ABORT; + ) + { + set @herbs[0], 646; + set @herbs[1], 647; + set @herbs[2], 648; + set @herbs[3], 649; + set @c, 4; + set @herb, rand(@c); + l_RandHerb: + if (countitem(@herbs[@herb])) goto l_Delete; + set @c, @c - 1; + set @herbs[@herb], @herbs[@c]; + set @herb, rand(@c); + goto l_RandHerb; + l_Delete: + set @herb, @herbs[@herb]; + delitem @herb, 1; + l_NewHerb: + set @herbs[0], 646; + set @herbs[1], 647; + set @herbs[2], 648; + set @herbs[3], 649; + set @c, 4; + set @newherb, rand(@c); + l_RandNewHerb: + if (@herbs[@newherb] != @herb) goto l_Create; + set @c, @c - 1; + set @herbs[@newherb], @herbs[@c]; + set @newherb, rand(@c); + goto l_RandNewHerb; + l_Create: + getitem @herbs[@newherb], 1; + if (@sec) goto l_Finish; + set @sec, rand(29); + if (@sec == 1) goto l_NewHerb; + l_Finish: + set @sec, 0; + }; + +SPELL make-turtle : "#T02" = + LET level = 0 + school = TRANSMUTE + IN (MANA 6, CASTTIME 500, + REQUIRE skill(caster, MAGIC) > level, + #REQUIRE skill(caster, school) > level, + COMPONENTS ["Acorn", "Acorn", "Acorn"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + spawn(rbox(location(caster), 2), caster, 1002, 1, 1, 1000000000); + + +#-------------------------------------------------------------------------------- +# End of Evol Level 0 Transmutation magic spells +#-------------------------------------------------------------------------------- + +#-------------------------------------------------------------------------------- +# Evol Level 1 Transmutation magic spells (change acorns with the real component) +#-------------------------------------------------------------------------------- + +SPELL make-bee : "#T12" = + LET level = 0 + school = TRANSMUTE + IN (MANA 6, CASTTIME 500, + REQUIRE skill(caster, MAGIC) > level, + #REQUIRE skill(caster, school) > level, + COMPONENTS ["Acorn", "Acorn", "Acorn", "Acorn"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + spawn(rbox(location(caster), 2), caster, 1005, 1, 1, 1000000000); + + +#-------------------------------------------------------------------------------- +# End of Evol Level 1 Transmutation magic spells +#-------------------------------------------------------------------------------- + +#-------------------------------------------------------------------------------- +# Old TMW spells (to get rid of) +#-------------------------------------------------------------------------------- + +SPELL aggravate : "#N00" = + LET level = 0 + school = NATURE + IN (MANA 3, CASTTIME 1000, + REQUIRE skill(caster, MAGIC) > level) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + FOREACH MOB target IN rbox(location(caster), 2 + spellpower / 50) DO + IF line_of_sight(location(caster), location(target)) + THEN (CALL sfx_generic(target); + aggravate(target, 0, caster);) + +SPELL grow-mauve : "#N01" = + LET level = 0 + school = NATURE + IN (MANA 4, CASTTIME 2000, + REQUIRE skill(caster, MAGIC) > level, + COMPONENTS ["MauveHerb", "Root"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL gain_xp(1); + spawn(rbox(location, 2), caster, 1029, 1, skill(caster, school) / 2 + 1, 10000); + +SPELL grow-alizarin : "#N02" = + LET level = 0 + school = NATURE + IN (MANA 4, CASTTIME 2000, + REQUIRE skill(caster, MAGIC) > level, + COMPONENTS ["AlizarinHerb", "Root"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL gain_xp(1); + spawn(rbox(location, 2), caster, 1032, 1, skill(caster, school) / 2 + 1, 10000); + +SPELL grow-gamboge : "#N03" = + LET level = 0 + school = NATURE + IN (MANA 4, CASTTIME 2000, + REQUIRE skill(caster, MAGIC) > level, + COMPONENTS ["GambogeHerb", "Root"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL gain_xp(1); + spawn(rbox(location, 2), caster, 1031, 1, skill(caster, school) / 2 + 1, 10000); + +SPELL grow-cobalt : "#N04" = + LET level = 0 + school = NATURE + IN (MANA 4, CASTTIME 2000, + REQUIRE skill(caster, MAGIC) > level, + COMPONENTS ["CobaltHerb", "Root"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL gain_xp(1); + spawn(rbox(location, 2), caster, 1030, 1, skill(caster, school) / 2 + 1, 10000); + + +LOCAL SPELL summon-maggots : "#A00" = + LET level = 0 + school = ASTRAL + IN (MANA 21, CASTTIME 20000, + REQUIRE skill(caster, MAGIC) > level, + COMPONENTS ["MaggotSlime", "Root"]) + => EFFECT CALL adjust_spellpower(school); + CALL gain_xp(1); + CALL summon_spell(1002, + 1 + ((sqrt(spellpower) + (spellpower / 15)) / 5), + 5000 - (spellpower * 5), + 10000 + (spellpower * 50), 1); + +SPELL detect-magic : "#G00" = + LET level = 0 + school = MAGIC + IN (MANA 3, CASTTIME 6000, + REQUIRE skill(caster, MAGIC) > level) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + range = 1 + spellpower / 50; + FOREACH NPC n IN rbox(location(caster), range) + DO IF (contains_string(name_of(n), "#MAGIC") || contains_string(name_of(n), "#_M")) + THEN sfx(n, SFX_DEFAULT, 0); + FOREACH SPELL s IN rbox(location(caster), range) + DO IF (s <> self_invocation) + THEN sfx(s, SFX_DEFAULT, 0); + + +#-------------------------------------------------------------------------------- +# Level 1 spells +#-------------------------------------------------------------------------------- + +SPELL make-arrows : "#T10" = + LET level = 1 + school = TRANSMUTE + IN (MANA 8, CASTTIME 5000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + COMPONENTS ["RawLog"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL create_item("Arrow", 1 + spellpower / 40 + (random(max(1, 800 - spellpower)) / 80), "WarpedLog", 500); + CALL gain_xp(1); + +SPELL make-shirt : "#T11" = + LET level = 1 + school = TRANSMUTE + IN (MANA 25, CASTTIME 5000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + COMPONENTS [5 * "CottonCloth"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL create_item("CottonShirt", 1, "CottonCloth", 425); + CALL gain_xp(2); + +SPELL make-tanktop : "#T12" = + LET level = 1 + school = TRANSMUTE + IN (MANA 25, CASTTIME 5000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + COMPONENTS [4 * "CottonCloth"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL create_item("TankTop", 1, "CottonCloth", 350); + CALL gain_xp(2); + +SPELL make-short-tanktop : "#T13" = + LET level = 1 + school = TRANSMUTE + IN (MANA 25, CASTTIME 5000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + COMPONENTS [3 * "CottonCloth"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL create_item("ShortTankTop", 1, "CottonCloth", 250); + CALL gain_xp(2); + +SPELL make-iron-powder : "#T14" = + LET level = 1 + school = TRANSMUTE + IN (MANA 8, CASTTIME 5000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + COMPONENTS ["IronOre"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL create_item("IronPowder", 1 + spellpower / 140 + (random(max(1, 900 - spellpower)) / 220), "IronOre", 700); + CALL gain_xp(3); + +SPELL make-concentration-potion : "#T15" = + LET level = 1 + school = TRANSMUTE + IN (MANA 8, CASTTIME 5000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + COMPONENTS ["BottleOfWater", 2 * "CobaltHerb", 2 * "Petal"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL create_item( if_then_else(random(2000 + experience) < experience, "ConcentrationPotion", "DarkConcentrationPotion"), 1, + if_then_else(random(2), 744, "DarkConcentrationPotion"), + 2000); + IF (success) + THEN CALL set_var(MAGIC_FLAGS, 1, MFLAG_MADE_CONC_POTION_SHIFT, 1); + CALL gain_xp(4); + +SPELL merge-concentration-potions : "#T16" = + LET level = 1 + school = TRANSMUTE + IN (MANA 8, CASTTIME 5000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + COMPONENTS ["DarkConcentrationPotion", 744]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL create_item("ConcentrationPotion", 1, 744, 1000); + message (caster, "success = " + success); + IF (success) + THEN CALL set_var(MAGIC_FLAGS, 1, MFLAG_MADE_CONC_POTION_SHIFT, 1); + CALL gain_xp(4); + + +SPELL lay-on-hands (target : STRING) : "#L10" = + LET level = 1 + school = LIFE + IN (MANA 10, CASTTIME 500, + REQUIRE hp(caster) > max_hp(caster) / 20, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + REQUIRE if_then_else(failed(pc(target)), 1, + (pc(target) <> caster) + && + (rdistance(location(caster), + location(pc(target))) < 2 + (spellpower / 50)) + && not (running_status_update(pc(target), SC_HALT_REGENERATE)) + )) + => EFFECT CALL adjust_spellpower(school); + IF (not (target)) THEN ABORT; + IF failed(pc(target)) + THEN (IF ((target = "mouboo" || target = "Mouboo") + && (rdistance(location(caster), location(npc("Mouboo"))) < 2 + (spellpower / 100))) + THEN (needed = 1000; + { + set @spell, 1; + callfunc "QuestMoubooHeal"; + }) + ELSE ABORT; + ) + ELSE (target = pc(target); + needed = max_hp(target) - hp(target);) + + pay_fraction = max(80, 200 - (vit(caster) + (spellpower / 10))); # Pay at least 40% + payment = (needed * pay_fraction) / 200; + available = hp(caster) - (max_hp(caster) / 20); + + IF payment < available + THEN power = needed; + ELSE (payment = available; + power = (available * 200) / pay_fraction; + ) + CALL gain_heal_xp(power, 1, 1, 3); + CALL quickheal(target, power); + status_change(caster, SC_HALT_REGENERATE, 0, 0, 0, 0, 10000); + CALL gain_xp(min(4, payment / 100)); + +SPELL lightning-strike : "#ingrav" = + LET level = 1 + school = WAR + IN (MANA 20, CASTTIME 1000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["IronPowder"])) + => EFFECT CALL adjust_spellpower(school); + damage = spellpower; + damage_bonus = 1 + spellpower / 2; + CALL install_attack_spell(1 + spellpower / 90, + 3000, + 8, 31); + CALL gain_xp(2); + ATTRIGGER CALL attack_check(target); + in_rain = 0; + area = location(caster); + FOREACH SPELL s IN rbox(location(caster), MAX_RAIN_SPELL_RADIUS + 1) DO + IF name_of(s) = "rain" THEN ( + IF is_in (location(caster), s.area) + THEN (in_rain = in_rain | 1; + area = area + s.area;); + IF is_in (location(target), s.area) + THEN in_rain = in_rain | 2; + ); + IF (in_rain & 1) || (check_status_change(caster,SC_DRUNK)) + THEN (# caster standing in the rain? This is going to be fun. + used = 0; + FOREACH TARGET t IN area DO + IF (random(200) + luk(caster) > 175) + THEN (used = used + 1; + CALL elt_damage (t, damage / 6, 1 + (damage_bonus / 3), ELT_EARTH, ELT_WIND, 17 + random(3));); + IF (not(used) || (random(200) + luk(caster) < 150)) + THEN (sfx(caster, 17 + random(3), 0); + itemheal(caster, 0 - damage - (random(damage_bonus)), 0);); + ) ELSE + CALL elt_damage (target, damage, damage_bonus, ELT_EARTH, ELT_WIND, 17 + random(3)); + +LOCAL SPELL arrow-hail : "#W11" = + LET level = 1 + school = WAR + IN (MANA 25, CASTTIME 5000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + REQUIRE is_exterior(location(caster)), + (COMPONENTS [20 * "Arrow"] OR COMPONENTS [20 * "IronArrow"]), + (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["SulphurPowder"])) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL abort_on_area_shield(location(caster)); + + range = 7; + area = rbox(awayfrom(location(caster), dir(caster), 1 + range), range); + + FOREACH SPELL s IN rbox(awayfrom(location(caster), dir(caster), 1 + range), range * 2) DO + IF (s <> self_invocation) && (name_of(s) = "arrow-hail") + THEN (message (caster, "A nearby arrow hail spell absorbs your magic!"); + ABORT;) + + damage = 125; + damage_bonus = spellpower / 5; + CALL gain_xp(2); + FOR i = 0 TO spellpower / 8 DO ( + FOR j = 0 TO 2 DO ( + location = random_location(area); + sfx(location, SFX_ARROW_HAIL, 0); + done = 0; + FOREACH TARGET target IN rbox(location, 0) DO ( + injure(caster, target, damage + random(damage_bonus) + random(damage_bonus), 0); + done = 1; + BREAK; + ) + IF location(caster) = location && not(done) + THEN (itemheal(caster, 0 - (damage + random(damage_bonus) + random(damage_bonus)), 0); + sfx(caster, SFX_HIT, 0); + ) + ); + WAIT 250 + random(50) + random(50); + ); + +SPELL magic-knuckles : "#W12" = + LET level = 1 + school = WAR + IN (MANA 20, CASTTIME 500, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["Beer"])) + => + EFFECT CALL adjust_spellpower(WAR); + str = str(caster); + CALL install_melee_spell(10 + spellpower / 10, 1300, 34); + ATTRIGGER CALL melee_damage(target, 30, 5 + (str * 2)); + +SPELL flying-backpack (target : PC) : "#N10" = + LET level = 1 + school = NATURE + IN (MANA 12, CASTTIME 1000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["SilkCocoon"]), + REQUIRE rdistance(location(target), location(caster)) < 2 + spellpower / 30) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + IF (caster <> target) + THEN sfx(caster, 2, 0); + status_change(target, SC_FLYING_BACKPACK, 0, 0, 0, 0, 5000 + (spellpower * 500)); + message (target, "Your backpack is lifted by a mystical force; you no longer feel it pressing on your back."); + CALL gain_xp(1); + ATEND message (target, "Your backpack is no longer levitating."); + sfx(target, 2, 0); + +SPELL protect (target : PC) : "#N11" = + LET level = 1 + school = NATURE + IN (MANA 14, CASTTIME 1500, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["HardSpike"]), + REQUIRE rdistance(location(target), location(caster)) < 2 + spellpower / 30) + => EFFECT CALL adjust_spellpower(school); + sfx(target, 11, 0); + IF (caster <> target) + THEN CALL default_effect(); + status_change(target, SC_PHYS_SHIELD, 5 + max(15, spellpower / 20), 0, 0, 0, 5000 + (spellpower * 1000)); + message (target, "You feel more protected."); + CALL gain_xp(2); + ATEND message (target, "You feel less protected."); + sfx(target, 111, 0); + +SPELL happy-curse (target : PC) : "#N12" = + LET level = 1 + school = NATURE + IN (MANA 13, CASTTIME 1000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["GingerBreadMan"]), + REQUIRE rdistance(location(target), location(caster)) < 1 + spellpower / 100) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + FOR i = 0 TO (spellpower / 10) DO (emote(target, 3); WAIT 500;); + CALL gain_xp(1); + +LOCAL SPELL rain : "#N13" = + LET level = 1 + school = NATURE + IN (MANA 17, CASTTIME 3000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + REQUIRE is_exterior(location(caster)), + (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["BottleOfWater"])) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL abort_on_area_shield(location(caster)); + FOREACH SPELL s IN rbox(location(caster), MAX_RAIN_SPELL_RADIUS + 1) DO + IF (s <> self_invocation) && (name_of(s) = "rain") + THEN (message (caster, "A nearby raincloud absorbs your magic."); + ABORT;) + + CALL gain_xp(1); + range = min(MAX_RAIN_SPELL_RADIUS, 3 + min(spellpower, 200) / 30); + area = rbox(location(caster), range); + IF (is_in(location(npc("#DruidTree0#_M")), area) + || is_in(location(npc("#DruidTree1#_M")), area)) + THEN { + set @flag, 1; + callfunc "QuestTreeTrigger"; + }; + FOR i = 0 TO (spellpower / 3) DO ( + FOR j = 0 TO min(spellpower / 2, 200) / 100 DO ( + location = random_location(area); + sfx(location, SFX_RAIN, 0); + FOREACH TARGET target IN rbox(location, 1) DO + IF element(target) = ELT_FIRE + THEN injure(caster, target, 2 + random(5 + spellpower / 15), 0); + ) + WAIT 400 + random(100); + ); + +LOCAL SPELL snow : "#N23" = + LET level = 1 + school = NATURE + IN (MANA 18, CASTTIME 3000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + REQUIRE is_exterior(location(caster)), + (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["BottleOfWater"])) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL abort_on_area_shield(location(caster)); + FOREACH SPELL s IN rbox(location(caster), MAX_RAIN_SPELL_RADIUS + 1) DO + IF (s <> self_invocation) && (name_of(s) = "snow") + THEN (message (caster, "A nearby snowcloud absorbs your magic."); + ABORT;) + CALL gain_xp(1); + range = min(MAX_RAIN_SPELL_RADIUS, 3 + min(spellpower, 200) / 30); + area = rbox(location(caster), range); + + FOR i = 0 TO (spellpower / 8) DO ( + FOR j = 0 TO min(spellpower / 2, 200) / 100 DO ( + location = random_location(area); + sfx(location, 29, 0); + FOREACH TARGET target IN rbox(location(area), 0) DO + IF element(target) = ELT_FIRE + THEN injure(caster, target, 2 + random(5 + spellpower / 15), 0); + ) + WAIT 200 + random(100); + ); + +PROCEDURE shear-drop(target, target2, item, prob) = + IF (target = name || target2 = name) + THEN (IF (score < prob) + THEN drop_item_for(place, item, 1, 60000, caster, 5000);) + +PROCEDURE shear-drop2(target, target2, item, prob, item2, prob2) = + IF (target = name || target2 = name) + THEN (IF (score < prob) + THEN drop_item_for(place, item, 1, 60000, caster, 5000); + ELSE CALL shear-drop(target, target2, item2, prob2 + prob);) + +PROCEDURE shear-drop3(target, target2, item, prob, item2, prob2, item3, prob3) = + IF (target = name || target2 = name) + THEN (IF (score < prob) + THEN drop_item_for(place, item, 1, 60000, caster, 5000); + ELSE CALL shear-drop2(target, target2, item2, prob2 + prob, item3, prob3 + prob);) + + +SPELL shear : "#N14" = + LET level = 1 + school = NATURE + IN (MANA 23, CASTTIME 1000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + override_attack (caster, 1, 2000, 1, ATTACK_ICON_SHEARING, 30, 0); + ATTRIGGER IF not(is_pc(target)) + THEN (score = random (1000 - (random (spellpower))); # lower score -> more valuable item + name = name_of(target); + place = random_location(rbox(location(target), 1)); + IF running_status_update(target, SC_SHEARED) + THEN ABORT; + status_change(target, SC_SHEARED, 1, 1, 1, 1, 600000); # 10 minutes + CALL shear-drop("Fluffy", "Fluffy", "WhiteFur", 300); + CALL shear-drop("EasterFluffy", "Easter Fluffy", "WhiteFur", 300); + CALL shear-drop("SpikyMushroom", "Spiky Mushroom", "HardSpike", 250); + CALL shear-drop("Mouboo", "Mouboo", "CottonCloth", 175); + CALL shear-drop("Cobalt", "CobaltPlant", "CobaltHerb", 700); + CALL shear-drop("Alizarin", "AlizarinPlant", "AlizarinHerb", 700); + CALL shear-drop("Gamboge", "GambogePlant", "GambogeHerb", 700); + CALL shear-drop("Mauve", "MauvePlant", "MauveHerb", 700); + CALL shear-drop("SilkWorm", "Silkworm", "SilkCocoon", 300); + IF ((name = "Fluffy" || name = "Mouboo") && random(2)) + THEN { set @value, 1; callfunc "QuestSagathaHappy"; }; + ) + + + +SPELL barrier (target : PC) : "#A10" = + LET level = 1 + school = ASTRAL + IN (MANA 16, CASTTIME 1000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["SmallMushroom"]), + REQUIRE rdistance(location(target), location(caster)) < 2 + spellpower / 30) + => EFFECT CALL adjust_spellpower(school); + sfx(target, SFX_BARRIER, 0); + IF (caster <> target) + THEN CALL default_effect(); + status_change(target, SC_MBARRIER, 20 + max(30, spellpower / 8), 0, 0, 0, 2000 + (spellpower * 200)); + message (target, "You are surrounded by a magical barrier."); + CALL gain_xp(3); + ATEND message (target, "Your magical barrier dissipates."); + sfx(target, SFX_UNBARRIER, 0); + + +LOCAL SPELL summon-spiky-mushrooms : "#A11" = + LET level = 1 + school = ASTRAL + IN (MANA 33, CASTTIME 20000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + COMPONENTS ["HardSpike", "Root"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL gain_xp(1); + CALL summon_spell(1019, 1 + spellpower / 120, 5000 - (spellpower * 9), spellpower * 400, 2); + +LOCAL SPELL summon-fluffies : "#A12" = + LET level = 1 + school = ASTRAL + IN (MANA 39, CASTTIME 20000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + COMPONENTS ["WhiteFur", "Root"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL gain_xp(1); + CALL summon_spell(1020, 1 + spellpower / 170 + spellpower / 430, 5000 - (spellpower * 8), spellpower * 350, 3); + + +SPELL detect-players : "#G10" = + LET level = 1 + school = MAGIC + IN (MANA 7, CASTTIME 300, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + message = ""; + FOREACH PC target IN rbox(location(caster), spellpower / 2) + DO IF ((target <> caster) + && not (running_status_update(pc(target), SC_HIDE)) + && not (status_option(target, SO_GMINVISIBLE))) + THEN (IF message <> "" + THEN message = message + ", "; + message = message + name_of (target); + IF spellpower > 99 + THEN message = message + "(" + level(target) + ")"; + ) + IF message = "" + THEN message(caster, "You sense no-one else nearby."); + ELSE message(caster, "You sense the following: " + message); + +SPELL reveal : "#G11" = + LET level = 1 + school = MAGIC + IN (MANA 18, CASTTIME 3000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + FOREACH PC target IN rbox(location(caster), 1 + spellpower / 100) + DO IF has_shroud(target) && level(caster) * 2 > level(target) + THEN (unshroud(target); + sfx(target, SFX_DEFAULT, 500);) + + +SPELL enchant-lifestone : "#G12" = + LET level = 1 + school = MAGIC + IN (MANA 15, CASTTIME 4000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + (COMPONENTS["BugLeg"] OR COMPONENTS ["MaggotSlime"] + OR COMPONENTS ["MauveHerb", "AlizarinHerb", "CobaltHerb", "GambogeHerb"])) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + create_item(caster, "Lifestone", 1); + CALL gain_xp(1); + +SPELL sense-spouse : "#G13" = + LET level = 1 + school = MAGIC + IN (MANA 7, CASTTIME 400, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + REQUIRE is_married(caster), + REQUIRE is_equipped(caster, "WeddingRing")) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + IF (failed(partner(caster)) || not(is_equipped(partner(caster), "WeddingRing"))) + THEN (message(caster, "You cannot sense your partner."); + ABORT;) + partner = partner(caster); + name = name_of(partner); + IF (is_dead(partner) || (map_nr(location(partner)) <> map_nr(location(caster)))) + THEN (message(caster, "You cannot sense " + name + " nearby."); + ABORT;) + IF (map_level(location(partner)) > 2 && map_level(location(caster)) < map_level(location(partner))) + THEN (message(caster, "You sense " + name + " somewhere below."); + ABORT;) + IF (map_level(location(caster)) > 2 && map_level(location(partner)) < map_level(location(caster))) + THEN (message(caster, "You sense " + name + " somewhere above."); + ABORT;) + IF (map_level(location(caster)) <> map_level(location(partner))) + THEN message(caster, "You sense " + name + " somewhere in the vincinity."); + ELSE (distance = rdistance(location(caster), location(partner)); + dir = dir_towards(location(caster), location(partner), 1); + IF (distance < 3) + THEN message(caster, "You sense " + name + " right next to you."); + ELSE IF (distance < 30) + THEN message(caster, "You sense " + name + " close by, towards the " + dir + "."); + ELSE IF (distance < 200) + THEN message(caster, "You sense " + name + " nearby, towards the " + dir + "."); + ELSE message(caster, "You sense " + name + " in the " + dir + "."); + ) + +SPELL hide (target : PC) : "#A13" = + LET level = 1 + school = ASTRAL + IN (MANA 11, CASTTIME 1000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["CottonCloth"]), + REQUIRE rdistance(location(target), location(caster)) < 2 + spellpower / 30) + => EFFECT CALL adjust_spellpower(school); + sfx(target, SFX_DEFAULT, 0); + IF (caster <> target) + THEN CALL default_effect(); + status_change(target, SC_HIDE, 0, 0, 0, 0, 5000 + (spellpower * 2500)); + CALL gain_xp(2); + message(target, "You are hidden!"); + IF (caster <> target) THEN message(caster, "You hid someone!"); + ATEND message(target, "You are no longer hidden."); + +#-------------------------------------------------------------------------------- +# Level 2 spells +#-------------------------------------------------------------------------------- + + +SPELL fire-ball : "#W22" = + LET level = 2 + school = WAR + IN (MANA 30, CASTTIME 1000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + COMPONENTS ["PileOfAsh"]) + => EFFECT CALL adjust_spellpower(school); + damage = min(50 + skill(caster, school) * 40, + 30 + ((spellpower * 3) / 2)); + damage_bonus = level(caster) + spellpower * 2; + radius = 2 + spellpower / 50; + CALL install_attack_spell(1 + spellpower / 60, + 5000, + 10, 31); + ATTRIGGER CALL attack_check(target); + loc = location(target); + #WAIT 500; + sfx(loc, 16, 0); + FOREACH TARGET target IN rbox(loc, radius) + DO IF line_of_sight(loc, location(target)) + THEN (divisor = (3 + rdistance(loc, location(target))); + CALL elt_damage (target, (damage * 3) / divisor, (damage_bonus * 3) / divisor, ELT_WATER, ELT_FIRE, 15); + ) + +SPELL summon-partner : "#A23" = + LET level = 2 + school = ASTRAL + IN (MANA 30, CASTTIME 2000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + REQUIRE is_married(caster), + REQUIRE is_equipped(caster, "WeddingRing")) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + IF (failed (partner (caster))) + THEN message (caster, "You call out for your partner, but there is no response."); + ELSE (message (caster, "You call out for " + (name_of (partner (caster))) + "."); + message (partner(caster), name_of(caster) + " is calling for your aid!"); + sfx(partner(caster), 2, 0); + WAIT (max (5000, 30000 - (spellpower * 60))); + IF (failed (partner (caster))) + THEN message (caster, "Your partner has abandoned you."); + ELSE IF (is_dead (partner (caster))) + THEN message (caster, "Something seems to have happened to " + (name_of(partner(caster))) + "."); + ELSE (sfx(location(partner(caster)), SFX_TELEPORT, 0); + dest = awayfrom(location(caster), random_dir(1), 1); + warp(partner(caster), dest); + sfx(dest, SFX_TELEPORT, 0); + ) + ) + + +#-------------------------------------------------------------------------------- +# Level 1 (magic level 2) +#-------------------------------------------------------------------------------- +LOCAL SPELL summon-cow : "#A32" = + LET level = 1 + school = ASTRAL + IN (MANA 33, CASTTIME 20000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + COMPONENTS ["Root"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL gain_xp(1); + CALL summon_spell(1021, 1 + spellpower / 120, 5000 - (spellpower * 9), spellpower * 400, 2); + +LOCAL SPELL summon-bats : "#kalbalark" = + LET level = 1 + school = ASTRAL + IN (MANA 25, CASTTIME 20000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + COMPONENTS ["BatTeeth", "BatWing", "BatTeeth", "BatWing", "BatTeeth", "BatWing", "BatTeeth", "BatWing", "BatTeeth", "BatWing", "Root"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL gain_xp(2); + mob = 1017; + IF(check_status_change(caster,200)) + THEN mob = 1021; + CALL summon_spell(mob, + 1 + ((sqrt(spellpower) + (spellpower / 15)) / 5), + 5000 - (spellpower * 5), + 10000 + (spellpower * 50), 1); + + +#-------------------------------------------------------------------------------- +# Level 2 (magic level 3) +#-------------------------------------------------------------------------------- + +LOCAL SPELL summon-whiteghost : "#kalshiro" = + LET level = 2 + school = ASTRAL + IN (MANA 25, CASTTIME 30000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + COMPONENTS ["YggdrasilHerb", "YggdrasilHerb", "Root"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL gain_xp(10); + CALL summon_spell(1119, + 1 + ((sqrt(spellpower) + (spellpower / 15)) / 5), + 5000 - (spellpower * 5), + 10000 + (spellpower * 50), 1); + +LOCAL SPELL summon-cobaltghost : "#kalbaoi" = + LET level = 2 + school = ASTRAL + IN (MANA 25, CASTTIME 30000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + COMPONENTS ["CobaltHerb", "CobaltHerb", "CobaltHerb", "CobaltHerb", "CobaltHerb", "Root"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL gain_xp(10); + CALL summon_spell(1120, + 1 + ((sqrt(spellpower) + (spellpower / 15)) / 10), + 5000 - (spellpower * 5), + 10000 + (spellpower * 50), 1); + +LOCAL SPELL summon-mauveghost : "#kaliziorn" = + LET level = 2 + school = ASTRAL + IN (MANA 25, CASTTIME 30000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + COMPONENTS ["MauveHerb", "MauveHerb", "MauveHerb", "MauveHerb", "MauveHerb", "Root"]) + => EFFECT CALL adjust_spellpower(school); + CALL gain_xp(10); + CALL summon_spell(1121, + 1 + ((sqrt(spellpower) + (spellpower / 15)) / 10), + 5000 - (spellpower * 5), + 10000 + (spellpower * 50), 1); + + +LOCAL SPELL summon-alizaringhost : "#kalizeden" = + LET level = 2 + school = ASTRAL + IN (MANA 25, CASTTIME 30000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + COMPONENTS ["AlizarinHerb", "AlizarinHerb", "AlizarinHerb", "AlizarinHerb", "AlizarinHerb", "Root"]) + => EFFECT CALL adjust_spellpower(school); + CALL gain_xp(10); + CALL summon_spell(1122, + 1 + ((sqrt(spellpower) + (spellpower / 15)) / 10), + 5000 - (spellpower * 5), + 10000 + (spellpower * 50), 1); + +LOCAL SPELL summon-gambogeghost : "#kalambodge" = + LET level = 2 + school = ASTRAL + IN (MANA 25, CASTTIME 30000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + COMPONENTS [5 * "GambogeHerb", "Root"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL gain_xp(10); + CALL summon_spell(1123, + 1 + ((sqrt(spellpower) + (spellpower / 15)) / 10), + 5000 - (spellpower * 5), + 10000 + (spellpower * 50), 1); + + + +#-------------------------------------------------------------------------------- +# Level 4 spells +#-------------------------------------------------------------------------------- + +SPELL shroud : "#N40" = + LET level = 4 + school = NATURE + IN (MANA 40, CASTTIME 400, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level) + => EFFECT CALL default_effect(); + shroud(caster, 0x04); + +SPELL teleport (destination : STRING) : "#A40" = + LET level = 4 + school = ASTRAL + IN (MANA 80, CASTTIME 400, + # COMPONENT ["EtherEssence"], + # CATALYST ["TeleportCrystal"], + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level) + => EFFECT CALL default_effect(); + WAIT 1000 + (200000 / (spellpower + 10)); + sfx(location(caster), SFX_TELEPORT, 200); + warp(caster, random_location(anchor(destination))); + sfx(caster, SFX_TELEPORT, 200); + +#-------------------------------------------------------------------------------- +# Debug keywords +#-------------------------------------------------------------------------------- + +SPELL debug : "debug" = + REQUIRE DEBUG + => EFFECT message (caster, "FLAGS: " + + "drank=" + ((script_int(caster, "MAGIC_FLAGS") & 1) > 0) + ", " + + "Kmseed=" + ((script_int(caster, "MAGIC_FLAGS") & 2) > 0) + ", " + + "touched-mseed=" + ((script_int(caster, "MAGIC_FLAGS") & 4) > 0) + ", " + + "mseed-max=" + ((script_int(caster, "MAGIC_FLAGS") & 8) > 0) + ", " + + "Kauldsbel=" + ((script_int(caster, "MAGIC_FLAGS") & 16) > 0) + ", " + + "Kwyara=" + ((script_int(caster, "MAGIC_FLAGS") & 32) > 0) + ", " + + "Ksagatha=" + ((script_int(caster, "MAGIC_FLAGS") & 64) > 0) + ", " + + "Kmpotion=" + ((script_int(caster, "MAGIC_FLAGS") & 128) > 0) + ", " + + "mseed-rumour=" + ((script_int(caster, "MAGIC_FLAGS") & 256) > 0) + ", " + + "Kcuttree=" + ((script_int(caster, "MAGIC_FLAGS") & 512) > 0) + ", " + + "cut=" + ((script_int(caster, "MAGIC_FLAGS") & 1024) > 0) + ", " + + "Kdruidtree=" + ((script_int(caster, "MAGIC_FLAGS") & 2048) > 0) + ", " + + "Kimp=" + ((script_int(caster, "MAGIC_FLAGS") & 4096) > 0) + ", " + + "Koldwiz=" + ((script_int(caster, "MAGIC_FLAGS") & 8192) > 0) + ", " + + "made-conc=" + ((script_int(caster, "MAGIC_FLAGS") & 16384) > 0) + ", " + + "elanore-omar=" + ((script_int(caster, "MAGIC_FLAGS") & 32768) > 0)); + message (caster, "EXP: " + (script_int(caster, "MAGIC_EXPERIENCE") & 0xffff) + + ", lastspell=" + ((script_int(caster, "MAGIC_EXPERIENCE") >> 16) & 0xff) + + ", healexp=" + ((script_int(caster, "MAGIC_EXPERIENCE") >> 24) & 0xff)); + message (caster, "STATUS: " + + "auldsbel:" + (script_int(caster, "QUEST_MAGIC") & 0x1f) + "," + ((script_int(caster, "QUEST_MAGIC") >> 5) & 0x7) + ", " + + "dt/mb:" + ((script_int(caster, "QUEST_MAGIC") >> 8) & 0xf) + ", " + + "s-unhappy:" + ((script_int(caster, "QUEST_MAGIC") >> 12) & 0xf) + ", " + + "sagatha:" + ((script_int(caster, "QUEST_MAGIC") >> 16) & 0xff) + ", " + + "swords:" + ((script_int(caster, "QUEST_MAGIC") >> 24) & 0xff) + ", " + + "imp:" + ((script_int(caster, "QUEST_MAGIC2") >> 0) & 0xf) + ", " + + "elanore:" + ((script_int(caster, "QUEST_MAGIC2") >> 4) & 0xf) + ", " + + "elanore-sub:" + ((script_int(caster, "QUEST_MAGIC2") >> 12) & 0xf) + ", " + + "wyara:" + ((script_int(caster, "QUEST_MAGIC2") >> 8) & 0xf)); + +PROCEDURE debug_xmod(name, mask, shift, gain) = + value = ((script_int(caster, name) >> shift) & mask) + gain; + IF (value < 0) + THEN value = 0; + IF (value > mask) + THEN value = mask; + CALL set_var(name, mask, shift, value); + +PROCEDURE debug_mod(name, delta) = + IF (name = "mexp") THEN CALL debug_xmod("MAGIC_EXPERIENCE", 0xffff, 0, delta); + ELSE IF (name = "lastspell") THEN CALL debug_xmod("MAGIC_EXPERIENCE", 0xff, 16, delta); + ELSE IF (name = "healexp") THEN CALL debug_xmod("MAGIC_EXPERIENCE", 0xff, 24, delta); + ELSE IF (name = "drank") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 0, delta); + ELSE IF (name = "Kmseed") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 1, delta); + ELSE IF (name = "touched-mseed") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 2, delta); + ELSE IF (name = "mseed-max") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 3, delta); + ELSE IF (name = "Kauldsbel") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 4, delta); + ELSE IF (name = "Kwyara") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 5, delta); + ELSE IF (name = "Ksagatha") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 6, delta); + ELSE IF (name = "Kmpotion") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 7, delta); + ELSE IF (name = "mseed-rumour") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 8, delta); + ELSE IF (name = "Kcuttree") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 9, delta); + ELSE IF (name = "cut") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 10, delta); + ELSE IF (name = "Kdruidtree") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 11, delta); + ELSE IF (name = "Kimp") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 12, delta); + ELSE IF (name = "oldwiz") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 13, delta); + ELSE IF (name = "made-conc") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 14, delta); + ELSE IF (name = "elanore-omar") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 15, delta); + ELSE IF (name = "auldsbel") THEN CALL debug_xmod("QUEST_MAGIC", 0x1f, 0, delta); + ELSE IF (name = "Qauldsbel") THEN CALL debug_xmod("QUEST_MAGIC", 0x7, 5, delta); + ELSE IF (name = "dt") THEN CALL debug_xmod("QUEST_MAGIC", 0x3, 10, delta); + ELSE IF (name = "mb") THEN CALL debug_xmod("QUEST_MAGIC", 0x3, 8, delta); + ELSE IF (name = "s-unhappy") THEN CALL debug_xmod("QUEST_MAGIC", 0xff, 12, delta); + ELSE IF (name = "sagatha") THEN CALL debug_xmod("QUEST_MAGIC", 0xff, 16, delta); + ELSE IF (name = "swords") THEN CALL debug_xmod("QUEST_MAGIC", 0xff, 24, delta); + ELSE IF (name = "imp") THEN CALL debug_xmod("QUEST_MAGIC2", 0xf, 0, delta); + ELSE IF (name = "elanore") THEN CALL debug_xmod("QUEST_MAGIC2", 0xf, 4, delta); + ELSE IF (name = "wyara") THEN CALL debug_xmod("QUEST_MAGIC2", 0xf, 8, delta); + ELSE IF (name = "elanore-sub") THEN CALL debug_xmod("QUEST_MAGIC2", 0xf, 12, delta); + ELSE message(caster, "Unknown"); + +SPELL debug-up1 (name : STRING) : "debug+1" = + REQUIRE DEBUG + => EFFECT CALL debug_mod(name, 1); + +SPELL debug-down1 (name : STRING) : "debug-1" = + REQUIRE DEBUG + => EFFECT CALL debug_mod(name, 0 - 1); + +SPELL debug-up16 (name : STRING) : "debug+16" = + REQUIRE DEBUG + => EFFECT CALL debug_mod(name, 16); + +SPELL debug-down16 (name : STRING) : "debug-16" = + REQUIRE DEBUG + => EFFECT CALL debug_mod(name, 0 - 16); + +SPELL debug-up256 (name : STRING) : "debug+256" = + REQUIRE DEBUG + => EFFECT CALL debug_mod(name, 256); + +SPELL debug-down256 (name : STRING) : "debug-256" = + REQUIRE DEBUG + => EFFECT CALL debug_mod(name, 0 - 256); + +SPELL debug-reset : "debug-reset" = + REQUIRE DEBUG + => EFFECT set_script_variable(caster, "QUEST_MAGIC", 0); + set_script_variable(caster, "QUEST_MAGIC2", 0); + set_script_variable(caster, "MAGIC_FLAGS", 0); + set_script_variable(caster, "MAGIC_EXP", 0); + + +#-------------------------------------------------------------------------------- +# Special-purpose quasispells +#-------------------------------------------------------------------------------- + +CONST MIN_MARRY_LEVEL = 32; + +NONMAGIC SILENT SPELL marriage (target : PC) : "marry" = + (REQUIRE (is_in(location(caster), @("014-1.gat", 28,39) @+ (8, 6)) || is_in(location(caster), @("021-2.gat", 20,25) @+ (4, 4)) ))=> + EFFECT IF target == caster # no valid target or tried to marry self? + THEN ABORT; + + IF (level(caster) < MIN_MARRY_LEVEL) + THEN (message(caster, "You must be level " + MIN_MARRY_LEVEL + " or higher to marry!"); ABORT;) + + IF (level(target) < MIN_MARRY_LEVEL) + THEN (message(caster, "Your partner must be level " + MIN_MARRY_LEVEL + " or higher to marry!"); ABORT;) + + IF partner(caster) = target + THEN (message(caster, "You and " + name_of(target) + " are already married."); ABORT;) + + IF is_married(caster) + THEN (message(caster, "You are already married!"); ABORT;) + + IF is_married(target) + THEN (message(caster, name_of(target) + " is already married."); ABORT;); + + IF distance(location(caster), location(target)) <> 1 + THEN (message(caster, "You need to stand next to each other."); ABORT;); + + IF (count_item(caster, "WeddingRing") == 0 || count_item(target, "WeddingRing") == 0) + THEN (message(caster, "You must both be wearing your wedding rings!"); ABORT;) + + script_target = target; + { + announce @caster_name$ + " is asking " + strcharinfo(0) + " for marriage.", 2; + mes @caster_name$ + " wishes to marry you."; + mes "Do you accept?"; + next; + menu "Yes, I do!", L_yes, + "No.", -; + close; + + L_yes: + if marriage(@caster_name$) + announce @caster_name$ + " and " + strcharinfo(0) + " are now married!", 0; + close; + } + + IF not (is_married(caster)) + THEN message(caster, name_of(target) + " turned down your marriage offer."); + +# SPELL change-hair-colour (colour : STRING) : "trapa" = +# (MANA 20) => EFFECT IF colour = "nworbl" +# THEN x = 0; # light brown +# ELSE IF colour = "der" +# THEN x = 1; # red +# ELSE IF colour = "neerg" +# THEN x = 2; # green +# ELSE IF colour = "elprup" +# THEN x = 3; # purple +# ELSE IF colour = "yerg" +# THEN x = 4; # grey +# ELSE IF colour = "wolley" +# THEN x = 5; # yellow +# ELSE IF colour = "eulb" +# THEN x = 6; # blue +# ELSE IF colour = "nwrob" +# THEN x = 7; # brown +# ELSE IF colour = "elpropl" +# THEN x = 8; # light purple +# ELSE IF colour = "elpropd" +# THEN x = 9; # dark purple +# ELSE x = random(10); +# sfx(caster, 2, 0); +# set_hair_colour(caster, x); + + +# SPELL trick-or-treat : "trick-or-treat" = +# (CASTTIME 30000, MANA 20, +# COMPONENTS [ "BugLeg" ]) => EFFECT IF (random(2)) +# THEN (sfx(caster, 2, 0); +# FOR i = 0 TO random(10) DO +# drop_item_for (random_location(rbox(location(caster), 5)), +# "Candy", 1, 10000 + random(10000), caster, 3000); +# FOR i = 0 TO random(10) DO +# drop_item_for (random_location(rbox(location(caster), 5)), +# "ChocolateBar", 1, 10000 + random(10000), caster, 3000); +# ) +# ELSE (sfx(caster, 5, 0); +# message(caster, "No treat for you!"); +# spawn(rbox(location(caster), 3), caster, 1010, 0, 1 + random(3), 10000 + random(20000)); +# FOREACH MOB target IN rbox(location(caster), 5) DO +# (sfx(target, 5, 0); +# aggravate(target, 0, caster);)) + + +LOCAL SPELL mouboo-groan : "#g" = + (MANA 1, + REQUIRE name_of(caster) = "MOUBOOTAUR") => + EFFECT FOREACH PC p IN rbox(location(caster), 200) DO + distance = rdistance(location(caster), location(p)); + IF (distance < 15) + THEN message(p, "The moubootaur's groaning rings in your ears!"); + ELSE IF (distance < 70) + THEN message(p, "You hear a loud groaning noise, not far away..."); + ELSE message(p, "You hear an odd groaning noise in the distance..."); + + +LOCAL SPELL mouboo-smell : "#s" = + (MANA 1, + REQUIRE name_of(caster) = "MOUBOOTAUR") => + EFFECT WAIT 30000; + FOREACH PC p IN rbox(location(caster), 30) DO + message(p, "You notice a strange smell all around you."); + + +PROCEDURE hug_tree(target) = + IF (target = "" + || target = "tree" || target = "tree*" + || target = "Tree" || target = "Tree*" + || target = "druid" || target = "druid*" + || target = "Druid" || target = "Druid*") + THEN { + set @flag, 2; + callfunc "QuestTreeTrigger"; + }; + +NONMAGIC SPELL hug0 (target : STRING) : "hug" = REQUIRE ((rdistance(location(caster), location(npc("#DruidTree0#_M"))) <= 1 + || rdistance(location(caster), location(npc("#DruidTree1#_M"))) <= 1)) + => EFFECT CALL hug_tree(target); + +NONMAGIC SPELL hug1 (target : STRING) : "*hug*" = REQUIRE ((rdistance(location(caster), location(npc("#DruidTree0#_M"))) <= 1 + || rdistance(location(caster), location(npc("#DruidTree1#_M"))) <= 1)) + => EFFECT CALL hug_tree(target); + +NONMAGIC SPELL hug2 (target : STRING) : "*hug" = REQUIRE ((rdistance(location(caster), location(npc("#DruidTree0#_M"))) <= 1 + || rdistance(location(caster), location(npc("#DruidTree1#_M"))) <= 1)) + => EFFECT CALL hug_tree(target); + +NONMAGIC SPELL hug3 (target : STRING) : "hugs" = REQUIRE ((rdistance(location(caster), location(npc("#DruidTree0#_M"))) <= 1 + || rdistance(location(caster), location(npc("#DruidTree1#_M"))) <= 1)) + => EFFECT CALL hug_tree(target); + +NONMAGIC SPELL hug4 (target : STRING) : "*hugs*" = REQUIRE ((rdistance(location(caster), location(npc("#DruidTree0#_M"))) <= 1 + || rdistance(location(caster), location(npc("#DruidTree1#_M"))) <= 1)) + => EFFECT CALL hug_tree(target); + +NONMAGIC SPELL hug5 (target : STRING) : "*hugs" = REQUIRE ((rdistance(location(caster), location(npc("#DruidTree0#_M"))) <= 1 + || rdistance(location(caster), location(npc("#DruidTree1#_M"))) <= 1)) + => EFFECT CALL hug_tree(target); + + +#-------------------------------------------------------------------------------- +# Teleport anchors +#-------------------------------------------------------------------------------- + +TELEPORT-ANCHOR tulimshar : "tulimshar" = @("001-1.gat", 43, 66) @+ (3, 3); +TELEPORT-ANCHOR hurnscald : "hurnscald" = @("009-1.gat", 55, 37) @+ (3, 3); +TELEPORT-ANCHOR nivalis : "nivalis" = @("020-1.gat", 75, 63) @+ (19, 12); +TELEPORT-ANCHOR wizardhut : "##00" = @("013-1.gat", 41, 92) @+ (3, 3); +TELEPORT-ANCHOR pachua : "##01" = @("006-1.gat", 22, 101) @+ (3, 3); +TELEPORT-ANCHOR desert : "##02" = @("005-1.gat", 160, 64) @+ (5, 5); +TELEPORT-ANCHOR forest : "##03" = @("015-1.gat", 35, 35) @+ (40, 40); +TELEPORT-ANCHOR snakecave : "##04" = @("011-4.gat", 50, 75) @+ (3, 3); +TELEPORT-ANCHOR dimondscove : "##05" = @("010-2.gat", 23, 79) @+ (3, 3); + + diff --git a/conf/magic.conf.tmw.template b/conf/magic.conf.tmw.template new file mode 100644 index 00000000..931fb678 --- /dev/null +++ b/conf/magic.conf.tmw.template @@ -0,0 +1,1617 @@ +# Special-purpose globals +obscure_chance = 95 +min_casttime = 200 + +# Schools of magic +CONST MAGIC = 340 +CONST LIFE = 341 +CONST WAR = 342 +CONST TRANSMUTE = 343 +CONST NATURE = 344 +CONST ASTRAL = 345 + +# Elements +CONST ELT_NEUTRAL = 0 +CONST ELT_WATER = 1 +CONST ELT_EARTH = 2 +CONST ELT_FIRE = 3 +CONST ELT_WIND = 4 +CONST ELT_POISON = 5 +CONST ELT_SHADOW = 6 +CONST ELT_HOLY = 7 +CONST ELT_GHOST = 8 +CONST ELT_UNDEAD = 9 + +# Status effects +CONST SC_POISON = 132 +CONST SC_SHEARED = 194 # This is the same as SC_HIDE, since mobs can't hide and shearing is only used for mobs. Feel free to fix! +CONST SC_HIDE = 194 +CONST SC_HALT_REGENERATE = 195 +CONST SC_FLYING_BACKPACK = 196 +CONST SC_MBARRIER = 197 +CONST SC_HASTE = 198 +CONST SC_PHYS_SHIELD = 199 + +CONST SO_GMINVISIBLE = 4096 + +# Special effects +CONST SFX_DEFAULT = 10 +CONST SFX_SUMMON_START = 21 +CONST SFX_SUMMON_FIRE = 22 +CONST SFX_TELEPORT = 24 +CONST SFX_RAIN = 25 +CONST SFX_HIT = 25 +CONST SFX_ARROW_HAIL = 27 +CONST SFX_BARRIER = 10 +CONST SFX_UNBARRIER = 10 +CONST SFX_HEAL = 3 + +CONST MAX_RAIN_SPELL_RADIUS = 15 + +CONST MAX_MAGIC_LEVEL = 2 # Increase up to 5 as each new magic level is completed. + +CONST MAGIC_FLAGS = "MAGIC_FLAGS" +CONST MFLAG_MADE_CONC_POTION = 16384 +CONST MFLAG_MADE_CONC_POTION_SHIFT = 14 + +CONST SCRIPT_XP = "MAGIC_EXPERIENCE" +CONST SCRIPT_XP_MASK = 0xffff +CONST SCRIPT_XP_SHIFT = 0 +CONST SCRIPT_LASTSPELL_MASK = 0xff +CONST SCRIPT_LASTSPELL_SHIFT = 16 +CONST SCRIPT_HEALSPELL_MASK = 0xff +CONST SCRIPT_HEALSPELL_SHIFT = 24 +CONST DEBUG = 0 + +CONST ATTACK_ICON_GENERIC = 2000 +CONST ATTACK_ICON_SHEARING = 2001 + +# Default sfx on caster +PROCEDURE default_effect() = + sfx(caster, school - MAGIC + 2, 0); + +PROCEDURE sfx_generic(target) = + sfx(target, SFX_DEFAULT, 0); + +PROCEDURE set_var(name, mask, shift, value) = + set_script_variable(caster, name, script_int(caster, name) & (neg (mask << shift)) | ((value & mask) << shift)); + +PROCEDURE gain_heal_xp(value, # How many HP we healed + gain, # how many life magic experience points we can potentially gain + heal_xp_value_divisor, # 1 for instaheal, 2 for slow heal + base_exp_factor) = # factor for how many base experience points (max) the player should be allowed to gain + last_heal_xp = (script_int(caster, SCRIPT_XP) >> SCRIPT_HEALSPELL_SHIFT) & SCRIPT_HEALSPELL_MASK; + IF (target <> caster + && (value / heal_xp_value_divisor) > (10 + last_heal_xp + random(last_heal_xp + 1) + random(last_heal_xp + 1))) + THEN ( + heal_xp = last_heal_xp + gain; + IF (heal_xp > SCRIPT_HEALSPELL_MASK) + THEN heal_xp = SCRIPT_HEALSPELL_MASK; + CALL set_var(SCRIPT_XP, SCRIPT_HEALSPELL_MASK, SCRIPT_HEALSPELL_SHIFT, heal_xp); + ) + IF target <> caster + THEN gain_experience(caster, base_exp_factor * extract_healer_experience(target, value), 0, 1); + +PROCEDURE gain_xp(gain) = + IF (level + 3 > skill(caster, MAGIC)) # Level 4 and 5 magic users don't gain anything from spell levels 0 resp. 0+1 + THEN ( + index = spell_index(self_spell); + last_index = (script_int(caster, SCRIPT_XP) >> SCRIPT_LASTSPELL_SHIFT) & SCRIPT_LASTSPELL_MASK; + last_xp = (script_int(caster, SCRIPT_XP) >> SCRIPT_XP_SHIFT) & SCRIPT_XP_MASK; + IF (index != last_index) + THEN ( # Some variation observed + xp = last_xp + gain; + IF (xp > SCRIPT_XP_MASK) + THEN xp = SCRIPT_XP_MASK; + CALL set_var(SCRIPT_XP, SCRIPT_XP_MASK, SCRIPT_XP_SHIFT, xp); + CALL set_var(SCRIPT_XP, SCRIPT_LASTSPELL_MASK, SCRIPT_LASTSPELL_SHIFT, index); + IF DEBUG THEN message(caster, "Spell xp = " + xp); + ) ELSE IF DEBUG THEN message(caster, "Re-cast same spell, xp remain at " + last_xp); + ) + +PROCEDURE create_item(good_item, count, bad_item, difficulty) = + success = 1; + score = experience + random(min(spellpower, (experience / 3) + 1)); + IF (score >= difficulty) + THEN create_item(caster, good_item, count); + ELSE ( + success = 0; + score = score + random(luk(caster)) + random(luk(caster)); + IF (score < difficulty / 3) + THEN ( + message(caster, "Your spell backfires!"); + IF (random(110) < (luk(caster))) + THEN itemheal(caster, 0 - ((level + 1) * (level + 2) * (3 + random(28))), 0); + ELSE itemheal(caster, 0 - (level + 1), 0); + ) ELSE IF (score < (difficulty * 2) / 3) + THEN ( + IF random(5) = 0 + THEN (message(caster, "Your spell solidifies into the shape of a mysterious object!"); + create_item(caster, "Iten", 1);) + ELSE message(caster, "Your spell escapes!"); + ) ELSE ( + message(caster, "Your spell takes on a mind of its own!"); + IF random(3) = 0 + THEN create_item(caster, bad_item, 1); + ) + ) + +# Increase spellpower by school and general magic skill +PROCEDURE adjust_spellpower(school) = + experience = (script_int(caster, SCRIPT_XP) >> SCRIPT_XP_SHIFT) & SCRIPT_XP_MASK; + spellpower = spellpower + (skill(caster, MAGIC) + skill(caster, school)) * 10; + # Below, we adjust by special items + IF (not(failed(target)) && (school = LIFE || school = NATURE)) + THEN IF (target) + THEN IF (pc(target) = partner(caster)) + THEN (spellpower = spellpower + 200; + IF is_equipped(caster, "WeddingRing") + THEN spellpower = spellpower + 50; + IF is_equipped(pc(target), "WeddingRing") + THEN spellpower = spellpower + 50;) + +PROCEDURE heal(target, max_heal) = + CALL default_effect(); + IF caster <> target + THEN sfx(target, SFX_HEAL, 0); + power = spellpower + vit(caster); + power = min(max_heal, (max_heal * power) / 250); + itemheal(target, power, 0); + +# Goes through instaheal instead of itemheal +PROCEDURE quickheal(target, power) = + CALL default_effect(); + IF caster <> target + THEN sfx(target, SFX_HEAL, 0); + instaheal(target, power, 0); + +# Can attack the target? Imports attack_range from dynamic environment +PROCEDURE attack_check(target) = + IF (not (line_of_sight(location(caster), location(target)))) + THEN ABORT; + IF (not (rdistance(location(caster), location(target)) <= attack_range)) + THEN ABORT; + +# Cause elemental damage. bonus_elt grants an attack bonus, malus_elt reduces the attack. `effect' is the sfx ID. +PROCEDURE elt_damage(target, damage, dmgplus, bonus_elt, malus_elt, effect) = + d = damage + random(dmgplus); + IF (element(target) = malus_elt) + THEN d = d / 3; + IF (element(target) = bonus_elt) + THEN d = (d * (4 + element_level(target))) / 4; + #message(caster, "bonus=" + (element(target) = bonus_elt) + " malus=" + (element(target) = malus_elt) + " damage=" + damage + " + r(" + dmgplus + ") -> " + d); + sfx(target, effect, 0); + injure(caster, target, d, 0); + +PROCEDURE melee_damage(target, damage, dmgplus) = + CALL attack_check(target); + d = damage + random(dmgplus); + evade = level(target) + mdef(target); + IF (spellpower - random(100) < evade) + THEN d = 0; + injure(caster, target, d, 0); + + +PROCEDURE install_attack_spell(charges, base_delay, range, attack_animation) = + CALL default_effect(); + attack_range = range; + override_attack(caster, charges, ((200 - agi(caster)) * base_delay) / 200, + range, ATTACK_ICON_GENERIC, attack_animation, 0); + +PROCEDURE install_melee_spell(charges, base_delay, attack_animation) = + CALL install_attack_spell(charges, base_delay, 1, attack_animation); + +PROCEDURE summon_spell(mob_id, count, delay, lifetime, control_level) = + CALL default_effect(); + sfx(location, SFX_SUMMON_START, 0); + WAIT delay; + sfx(location, SFX_SUMMON_FIRE, 0); + spawn(rbox(location, 2), caster, mob_id, + if_then_else(skill(caster, ASTRAL) >= control_level, 2, 1), # pets when level is high enough + count, lifetime); + +PROCEDURE abort_on_area_shield(pos) = + IF (is_exterior(pos) = 1 && (map_nr(pos) = 1 # Tulimshar + ||map_nr(pos) = 9 # Hurnscald + ||map_nr(pos) = 20)) # Nivalis + THEN (message(caster, "A powerful magic drains your spell just as it is beginning to take shape!"); + ABORT;) + + +#-------------------------------------------------------------------------------- +# Level 0 spells +#-------------------------------------------------------------------------------- + +SPELL ask-magic-exp : "#G01" = + LET level = 0 + school = MAGIC + IN (MANA 1, CASTTIME 1000, + REQUIRE skill(caster, MAGIC) > level) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + level = skill (caster, MAGIC); + experience = (script_int(caster, SCRIPT_XP) >> SCRIPT_XP_SHIFT) & SCRIPT_XP_MASK; + IF (experience == SCRIPT_XP_MASK && level > 4) + THEN message (caster, "You are as proficient at magic as you can possibly be."); + ELSE ( + # This duplicates the table in mana-seed.txt + IF level > 4 + THEN max_experience = SCRIPT_XP_MASK; + ELSE IF level = 4 + THEN max_experience = 40000; + ELSE IF level = 3 + THEN max_experience = 8000; + ELSE IF level = 2 + THEN max_experience = 1200; + ELSE max_experience = 100; + + ratio = (10 * experience - random(max_experience / 30)) / max_experience; #Randomness: jitter a bit at the transitions to give more precise information if used frequently + + IF ratio >= 45 + THEN message(caster, "Magic flows naturally from you, readily and with ease. Your understanding of what you can currently control at present is flawless, far beyond your requirements to cast magic at this level." + if_then_else(level >= MAX_MAGIC_LEVEL,""," Surely the Mana Seed will more than readily offer more magic for such a proficient user.")); + ELSE IF ratio >= 20 + THEN message(caster, "You have perfect control of what you understand now, but there is now a distinct sensation of something more, something indescribable. If only the Mana Seed would give more magic to you..."); + ELSE IF ratio >= 10 + THEN message(caster, "You feel in perfect control of your magic" + if_then_else(level >= MAX_MAGIC_LEVEL,".",", and seem on the verge of something more... perhaps you should see the Mana Seed to ask for more magic?")); + ELSE IF ratio >= 9 + THEN message(caster, "You feel in almost perfect control of your magic."); + ELSE IF ratio >= 8 + THEN message(caster, "You feel that you have very good control of your magic."); + ELSE IF ratio >= 7 + THEN message(caster, "You feel quite in control of your magic."); + ELSE IF ratio >= 6 + THEN message(caster, "You feel mostly in control of your magic."); + ELSE IF ratio >= 5 + THEN message(caster, "You feel somewhat in control of your magic."); + ELSE IF ratio >= 4 + THEN message(caster, "You feel you still have a few difficulties in controlling your magic."); + ELSE IF ratio >= 3 + THEN message(caster, "Trying to control your magic is still rather troublesome."); + ELSE IF ratio >= 2 + THEN message(caster, "You feel that you have only the bare minimum of control over your magic."); + ELSE IF ratio >= 1 + THEN message(caster, "You feel quite overwhelmed by your magic, but are beginning to see patterns."); + ELSE message (caster, "You feel completely overwhelmed by your magic."); + ) + +# SPELL ask-life-magic-exp : "#G02" = +# LET level = 0 +# school = MAGIC +# IN (MANA 1, CASTTIME 1000, +# REQUIRE skill(caster, MAGIC) > level) +# => EFFECT CALL adjust_spellpower(school); +# CALL default_effect(); +# message(caster, "You have " + ((script_int(caster, "MAGIC_EXPERIENCE") >> 24) & 0xff) + " Life Magic Experience points."); + +SPELL transmute-wood-to-figurine (name : STRING) : "#T00" = + LET level = 0 + school = TRANSMUTE + IN (MANA 5, CASTTIME 4000, + REQUIRE skill(caster, MAGIC) > level, + COMPONENTS ["RawLog"]) + => ( REQUIRE name = "boo" => + EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL create_item("MoubooFigurine", 1, "WarpedLog", 40); + CALL gain_xp(1); + | REQUIRE name = "lurk" => + EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL create_item("WarpedLog", 1, "WarpedLog", 40); + message (caster, "You have no idea what a Skrytlurk looks like."); + ) + + +SPELL make-sulphur : "#T01" = + LET level = 0 + school = TRANSMUTE + IN (MANA 4, CASTTIME 4000, + REQUIRE skill(caster, MAGIC) > level, + COMPONENTS ["PileOfAsh"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL create_item("SulphurPowder", 1 + spellpower / 100 + (random(max(1, 800 - spellpower)) / 180), "PileOfAsh", 50); + CALL gain_xp(1); + +SPELL lesser-heal (target : STRING) : "#L00" = + LET level = 0 + school = LIFE + IN (MANA 6, CASTTIME 500, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE if_then_else(failed(pc(target)), 1, + rdistance(location(caster), location(pc(target))) < 2 + (spellpower / 100)), + (COMPONENTS ["Lifestone"])) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + IF failed(pc(target)) + THEN (IF ((target = "mouboo" || target = "Mouboo") + && rdistance(location(caster), location(npc("Mouboo"))) < 2 + (spellpower / 100)) + THEN { mes "Your spell seems to have no effect on the mouboo."; close; } + ELSE target = caster;) + ELSE (target = pc(target); + IF is_dead(target) + THEN ABORT;) + CALL gain_heal_xp(min(200, max_hp(target) - hp(target)), 1, 2, 2); # report half values for non-instaheal + CALL heal(target, 200); + CALL gain_xp(1); + + +SPELL flare-dart : "#W00" = + LET level = 0 + school = WAR + IN (MANA 10, CASTTIME 500, + REQUIRE skill(caster, MAGIC) > level, + (REQUIRE skill(caster, school) > 2 OR COMPONENTS ["SulphurPowder"])) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + damage = 5 * sqrt(spellpower); + damage_bonus = 5 + level(caster) / 3; + CALL install_attack_spell(3 + spellpower / 50, + 1200, + 4, 31); + CALL gain_xp(1); + ATTRIGGER CALL attack_check(target); + CALL elt_damage (target, damage, damage_bonus, ELT_WATER, ELT_FIRE, 15); + + +SPELL magic-blade : "#W01" = + LET level = 0 + school = WAR + IN (MANA 9, CASTTIME 500, + REQUIRE skill(caster, MAGIC) > level) + => ( COMPONENTS ["SharpKnife"] => + EFFECT CALL adjust_spellpower(WAR); + CALL default_effect(); + CALL install_melee_spell(10 + spellpower / 15, 1200, 30); + CALL gain_xp(1); + ATTRIGGER CALL melee_damage(target, 60, 5 + str(caster)); + | COMPONENTS ["Knife"] => + EFFECT CALL adjust_spellpower(WAR); + CALL default_effect(); + CALL install_melee_spell(10 + spellpower / 15, 1200, 30); + CALL gain_xp(1); + ATTRIGGER CALL melee_damage(target, 40, 5 + str(caster)); + ) + +SPELL aggravate : "#N00" = + LET level = 0 + school = NATURE + IN (MANA 3, CASTTIME 1000, + REQUIRE skill(caster, MAGIC) > level) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + FOREACH MOB target IN rbox(location(caster), 2 + spellpower / 50) DO + IF line_of_sight(location(caster), location(target)) + THEN (CALL sfx_generic(target); + aggravate(target, 0, caster);) + +SPELL grow-mauve : "#N01" = + LET level = 0 + school = NATURE + IN (MANA 4, CASTTIME 2000, + REQUIRE skill(caster, MAGIC) > level, + COMPONENTS ["MauveHerb", "Root"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL gain_xp(1); + spawn(rbox(location, 2), caster, 1029, 1, skill(caster, school) / 2 + 1, 10000); + +SPELL grow-alizarin : "#N02" = + LET level = 0 + school = NATURE + IN (MANA 4, CASTTIME 2000, + REQUIRE skill(caster, MAGIC) > level, + COMPONENTS ["AlizarinHerb", "Root"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL gain_xp(1); + spawn(rbox(location, 2), caster, 1032, 1, skill(caster, school) / 2 + 1, 10000); + +SPELL grow-gamboge : "#N03" = + LET level = 0 + school = NATURE + IN (MANA 4, CASTTIME 2000, + REQUIRE skill(caster, MAGIC) > level, + COMPONENTS ["GambogeHerb", "Root"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL gain_xp(1); + spawn(rbox(location, 2), caster, 1031, 1, skill(caster, school) / 2 + 1, 10000); + +SPELL grow-cobalt : "#N04" = + LET level = 0 + school = NATURE + IN (MANA 4, CASTTIME 2000, + REQUIRE skill(caster, MAGIC) > level, + COMPONENTS ["CobaltHerb", "Root"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL gain_xp(1); + spawn(rbox(location, 2), caster, 1030, 1, skill(caster, school) / 2 + 1, 10000); + + +LOCAL SPELL summon-maggots : "#A00" = + LET level = 0 + school = ASTRAL + IN (MANA 21, CASTTIME 20000, + REQUIRE skill(caster, MAGIC) > level, + COMPONENTS ["MaggotSlime", "Root"]) + => EFFECT CALL adjust_spellpower(school); + CALL gain_xp(1); + CALL summon_spell(1002, + 1 + ((sqrt(spellpower) + (spellpower / 15)) / 5), + 5000 - (spellpower * 5), + 10000 + (spellpower * 50), 1); + +SPELL detect-magic : "#G00" = + LET level = 0 + school = MAGIC + IN (MANA 3, CASTTIME 6000, + REQUIRE skill(caster, MAGIC) > level) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + range = 1 + spellpower / 50; + FOREACH NPC n IN rbox(location(caster), range) + DO IF (contains_string(name_of(n), "#MAGIC") || contains_string(name_of(n), "#_M")) + THEN sfx(n, SFX_DEFAULT, 0); + FOREACH SPELL s IN rbox(location(caster), range) + DO IF (s <> self_invocation) + THEN sfx(s, SFX_DEFAULT, 0); + + +#-------------------------------------------------------------------------------- +# Level 1 spells +#-------------------------------------------------------------------------------- + +SPELL make-arrows : "#T10" = + LET level = 1 + school = TRANSMUTE + IN (MANA 8, CASTTIME 5000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + COMPONENTS ["RawLog"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL create_item("Arrow", 1 + spellpower / 40 + (random(max(1, 800 - spellpower)) / 80), "WarpedLog", 500); + CALL gain_xp(1); + +SPELL make-shirt : "#T11" = + LET level = 1 + school = TRANSMUTE + IN (MANA 25, CASTTIME 5000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + COMPONENTS [5 * "CottonCloth"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL create_item("CottonShirt", 1, "CottonCloth", 425); + CALL gain_xp(2); + +SPELL make-tanktop : "#T12" = + LET level = 1 + school = TRANSMUTE + IN (MANA 25, CASTTIME 5000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + COMPONENTS [4 * "CottonCloth"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL create_item("TankTop", 1, "CottonCloth", 350); + CALL gain_xp(2); + +SPELL make-short-tanktop : "#T13" = + LET level = 1 + school = TRANSMUTE + IN (MANA 25, CASTTIME 5000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + COMPONENTS [3 * "CottonCloth"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL create_item("ShortTankTop", 1, "CottonCloth", 250); + CALL gain_xp(2); + +SPELL make-iron-powder : "#T14" = + LET level = 1 + school = TRANSMUTE + IN (MANA 8, CASTTIME 5000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + COMPONENTS ["IronOre"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL create_item("IronPowder", 1 + spellpower / 140 + (random(max(1, 900 - spellpower)) / 220), "IronOre", 700); + CALL gain_xp(3); + +SPELL make-concentration-potion : "#T15" = + LET level = 1 + school = TRANSMUTE + IN (MANA 8, CASTTIME 5000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + COMPONENTS ["BottleOfWater", 2 * "CobaltHerb", 2 * "PinkPetal"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL create_item( if_then_else(random(2000 + experience) < experience, "ConcentrationPotion", "DarkConcentrationPotion"), 1, + if_then_else(random(2), 744, "DarkConcentrationPotion"), + 2000); + IF (success) + THEN CALL set_var(MAGIC_FLAGS, 1, MFLAG_MADE_CONC_POTION_SHIFT, 1); + CALL gain_xp(4); + +SPELL merge-concentration-potions : "#T16" = + LET level = 1 + school = TRANSMUTE + IN (MANA 8, CASTTIME 5000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + COMPONENTS ["DarkConcentrationPotion", 744]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL create_item("ConcentrationPotion", 1, 744, 1000); + message (caster, "success = " + success); + IF (success) + THEN CALL set_var(MAGIC_FLAGS, 1, MFLAG_MADE_CONC_POTION_SHIFT, 1); + CALL gain_xp(4); + + +SPELL lay-on-hands (target : STRING) : "#L10" = + LET level = 1 + school = LIFE + IN (MANA 10, CASTTIME 500, + REQUIRE hp(caster) > max_hp(caster) / 20, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + REQUIRE if_then_else(failed(pc(target)), 1, + (pc(target) <> caster) + && + (rdistance(location(caster), + location(pc(target))) < 2 + (spellpower / 50)) + && not (running_status_update(pc(target), SC_HALT_REGENERATE)) + )) + => EFFECT CALL adjust_spellpower(school); + IF (not (target)) THEN ABORT; + IF failed(pc(target)) + THEN (IF ((target = "mouboo" || target = "Mouboo") + && (rdistance(location(caster), location(npc("Mouboo"))) < 2 + (spellpower / 100))) + THEN (needed = 1000; + { + set @spell, 1; + callfunc "QuestMoubooHeal"; + }) + ELSE ABORT; + ) + ELSE (target = pc(target); + needed = max_hp(target) - hp(target);) + + pay_fraction = max(80, 200 - (vit(caster) + (spellpower / 10))); # Pay at least 40% + payment = (needed * pay_fraction) / 200; + available = hp(caster) - (max_hp(caster) / 20); + + IF payment < available + THEN power = needed; + ELSE (payment = available; + power = (available * 200) / pay_fraction; + ) + CALL gain_heal_xp(power, 1, 1, 3); + CALL quickheal(target, power); + status_change(caster, SC_HALT_REGENERATE, 0, 0, 0, 0, 10000); + CALL gain_xp(min(4, payment / 100)); + +SPELL lightning-strike : "#W10" = + LET level = 1 + school = WAR + IN (MANA 20, CASTTIME 1000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["IronPowder"])) + => EFFECT CALL adjust_spellpower(school); + damage = spellpower; + damage_bonus = 1 + spellpower / 2; + CALL install_attack_spell(1 + spellpower / 90, + 3000, + 8, 31); + CALL gain_xp(2); + ATTRIGGER CALL attack_check(target); + in_rain = 0; + area = location(caster); + FOREACH SPELL s IN rbox(location(caster), MAX_RAIN_SPELL_RADIUS + 1) DO + IF name_of(s) = "rain" THEN ( + IF is_in (location(caster), s.area) + THEN (in_rain = in_rain | 1; + area = area + s.area;); + IF is_in (location(target), s.area) + THEN in_rain = in_rain | 2; + ); + IF in_rain & 1 + THEN (# caster standing in the rain? This is going to be fun. + used = 0; + FOREACH TARGET t IN area DO + IF (random(200) + luk(caster) > 175) + THEN (used = used + 1; + CALL elt_damage (t, damage / 6, 1 + (damage_bonus / 3), ELT_EARTH, ELT_WIND, 17 + random(3));); + IF (not(used) || (random(200) + luk(caster) < 150)) + THEN (sfx(caster, 17 + random(3), 0); + itemheal(caster, 0 - damage - (random(damage_bonus)), 0);); + ) ELSE + CALL elt_damage (target, damage, damage_bonus, ELT_EARTH, ELT_WIND, 17 + random(3)); + +LOCAL SPELL arrow-hail : "#W11" = + LET level = 1 + school = WAR + IN (MANA 25, CASTTIME 5000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + REQUIRE is_exterior(location(caster)), + (COMPONENTS [20 * "Arrow"] OR COMPONENTS [20 * "IronArrow"]), + (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["SulphurPowder"])) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL abort_on_area_shield(location(caster)); + + range = 7; + area = rbox(awayfrom(location(caster), dir(caster), 1 + range), range); + + FOREACH SPELL s IN rbox(awayfrom(location(caster), dir(caster), 1 + range), range * 2) DO + IF (s <> self_invocation) && (name_of(s) = "arrow-hail") + THEN (message (caster, "A nearby arrow hail spell absorbs your magic!"); + ABORT;) + + damage = 125; + damage_bonus = spellpower / 5; + CALL gain_xp(2); + FOR i = 0 TO spellpower / 8 DO ( + FOR j = 0 TO 2 DO ( + location = random_location(area); + sfx(location, SFX_ARROW_HAIL, 0); + done = 0; + FOREACH TARGET target IN rbox(location, 0) DO ( + injure(caster, target, damage + random(damage_bonus) + random(damage_bonus), 0); + done = 1; + BREAK; + ) + IF location(caster) = location && not(done) + THEN (itemheal(caster, 0 - (damage + random(damage_bonus) + random(damage_bonus)), 0); + sfx(caster, SFX_HIT, 0); + ) + ); + WAIT 250 + random(50) + random(50); + ); + +SPELL magic-knuckles : "#W12" = + LET level = 1 + school = WAR + IN (MANA 20, CASTTIME 500, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["Beer"])) + => + EFFECT CALL adjust_spellpower(WAR); + str = str(caster); + CALL install_melee_spell(10 + spellpower / 10, 1300, 34); + ATTRIGGER CALL melee_damage(target, 30, 5 + (str * 2)); + +SPELL flying-backpack (target : PC) : "#N10" = + LET level = 1 + school = NATURE + IN (MANA 12, CASTTIME 1000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["SilkCocoon"]), + REQUIRE rdistance(location(target), location(caster)) < 2 + spellpower / 30) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + IF (caster <> target) + THEN sfx(caster, 2, 0); + status_change(target, SC_FLYING_BACKPACK, 0, 0, 0, 0, 5000 + (spellpower * 500)); + message (target, "Your backpack is lifted by a mystical force; you no longer feel it pressing on your back."); + CALL gain_xp(1); + ATEND message (target, "Your backpack is no longer levitating."); + sfx(target, 2, 0); + +SPELL protect (target : PC) : "#N11" = + LET level = 1 + school = NATURE + IN (MANA 14, CASTTIME 1500, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["HardSpike"]), + REQUIRE rdistance(location(target), location(caster)) < 2 + spellpower / 30) + => EFFECT CALL adjust_spellpower(school); + sfx(target, 11, 0); + IF (caster <> target) + THEN CALL default_effect(); + status_change(target, SC_PHYS_SHIELD, 5 + max(15, spellpower / 20), 0, 0, 0, 5000 + (spellpower * 1000)); + message (target, "You feel more protected."); + CALL gain_xp(2); + ATEND message (target, "You feel less protected."); + sfx(target, 111, 0); + +SPELL happy-curse (target : PC) : "#N12" = + LET level = 1 + school = NATURE + IN (MANA 13, CASTTIME 1000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["GingerBreadMan"]), + REQUIRE rdistance(location(target), location(caster)) < 1 + spellpower / 100) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + FOR i = 0 TO (spellpower / 10) DO (emote(target, 3); WAIT 500;); + CALL gain_xp(1); + +LOCAL SPELL rain : "#N13" = + LET level = 1 + school = NATURE + IN (MANA 17, CASTTIME 3000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + REQUIRE is_exterior(location(caster)), + (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["BottleOfWater"])) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL abort_on_area_shield(location(caster)); + FOREACH SPELL s IN rbox(location(caster), MAX_RAIN_SPELL_RADIUS + 1) DO + IF (s <> self_invocation) && (name_of(s) = "rain") + THEN (message (caster, "A nearby raincloud absorbs your magic."); + ABORT;) + + CALL gain_xp(1); + range = min(MAX_RAIN_SPELL_RADIUS, 3 + min(spellpower, 200) / 30); + area = rbox(location(caster), range); + IF (is_in(location(npc("#DruidTree0#_M")), area) + || is_in(location(npc("#DruidTree1#_M")), area)) + THEN { + set @flag, 1; + callfunc "QuestTreeTrigger"; + }; + FOR i = 0 TO (spellpower / 3) DO ( + FOR j = 0 TO min(spellpower / 2, 200) / 100 DO ( + location = random_location(area); + sfx(location, SFX_RAIN, 0); + FOREACH TARGET target IN rbox(location, 1) DO + IF element(target) = ELT_FIRE + THEN injure(caster, target, 2 + random(5 + spellpower / 15), 0); + ) + WAIT 400 + random(100); + ); + +PROCEDURE shear-drop(target, target2, item, prob) = + IF (target = name || target2 = name) + THEN (IF (score < prob) + THEN drop_item_for(place, item, 1, 60000, caster, 5000);) + +PROCEDURE shear-drop2(target, target2, item, prob, item2, prob2) = + IF (target = name || target2 = name) + THEN (IF (score < prob) + THEN drop_item_for(place, item, 1, 60000, caster, 5000); + ELSE CALL shear-drop(target, target2, item2, prob2 + prob);) + +PROCEDURE shear-drop3(target, target2, item, prob, item2, prob2, item3, prob3) = + IF (target = name || target2 = name) + THEN (IF (score < prob) + THEN drop_item_for(place, item, 1, 60000, caster, 5000); + ELSE CALL shear-drop2(target, target2, item2, prob2 + prob, item3, prob3 + prob);) + + +SPELL shear : "#N14" = + LET level = 1 + school = NATURE + IN (MANA 23, CASTTIME 1000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + override_attack (caster, 1, 2000, 1, ATTACK_ICON_SHEARING, 30, 0); + ATTRIGGER IF not(is_pc(target)) + THEN (score = random (1000 - (random (spellpower))); # lower score -> more valuable item + name = name_of(target); + place = random_location(rbox(location(target), 1)); + IF running_status_update(target, SC_SHEARED) + THEN ABORT; + status_change(target, SC_SHEARED, 1, 1, 1, 1, 600000); # 10 minutes + CALL shear-drop("Fluffy", "Fluffy", "WhiteFur", 300); + CALL shear-drop("EasterFluffy", "Easter Fluffy", "WhiteFur", 300); + CALL shear-drop("SpikyMushroom", "Spiky Mushroom", "HardSpike", 250); + CALL shear-drop("Mouboo", "Mouboo", "CottonCloth", 175); + CALL shear-drop("Cobalt", "CobaltPlant", "CobaltHerb", 700); + CALL shear-drop("Alizarin", "AlizarinPlant", "AlizarinHerb", 700); + CALL shear-drop("Gamboge", "GambogePlant", "GambogeHerb", 700); + CALL shear-drop("Mauve", "MauvePlant", "MauveHerb", 700); + CALL shear-drop("SilkWorm", "Silkworm", "SilkCocoon", 300); + IF ((name = "Fluffy" || name = "Mouboo") && random(2)) + THEN { set @value, 1; callfunc "QuestSagathaHappy"; }; + ) + + + +SPELL barrier (target : PC) : "#A10" = + LET level = 1 + school = ASTRAL + IN (MANA 16, CASTTIME 1000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["SmallMushroom"]), + REQUIRE rdistance(location(target), location(caster)) < 2 + spellpower / 30) + => EFFECT CALL adjust_spellpower(school); + sfx(target, SFX_BARRIER, 0); + IF (caster <> target) + THEN CALL default_effect(); + status_change(target, SC_MBARRIER, 20 + max(30, spellpower / 8), 0, 0, 0, 2000 + (spellpower * 200)); + message (target, "You are surrounded by a magical barrier."); + CALL gain_xp(3); + ATEND message (target, "Your magical barrier dissipates."); + sfx(target, SFX_UNBARRIER, 0); + + +LOCAL SPELL summon-spiky-mushrooms : "#A11" = + LET level = 1 + school = ASTRAL + IN (MANA 33, CASTTIME 20000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + COMPONENTS ["HardSpike", "Root"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL gain_xp(1); + CALL summon_spell(1019, 1 + spellpower / 120, 5000 - (spellpower * 9), spellpower * 400, 2); + +LOCAL SPELL summon-fluffies : "#A12" = + LET level = 1 + school = ASTRAL + IN (MANA 39, CASTTIME 20000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + COMPONENTS ["WhiteFur", "Root"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + CALL gain_xp(1); + CALL summon_spell(1020, 1 + spellpower / 170 + spellpower / 430, 5000 - (spellpower * 8), spellpower * 350, 3); + + +SPELL detect-players : "#G10" = + LET level = 1 + school = MAGIC + IN (MANA 7, CASTTIME 300, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + message = ""; + FOREACH PC target IN rbox(location(caster), spellpower / 2) + DO IF ((target <> caster) + && not (running_status_update(pc(target), SC_HIDE)) + && not (status_option(target, SO_GMINVISIBLE))) + THEN (IF message <> "" + THEN message = message + ", "; + message = message + name_of (target); + IF spellpower > 99 + THEN message = message + "(" + level(target) + ")"; + ) + IF message = "" + THEN message(caster, "You sense no-one else nearby."); + ELSE message(caster, "You sense the following: " + message); + +SPELL reveal : "#G11" = + LET level = 1 + school = MAGIC + IN (MANA 18, CASTTIME 3000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + FOREACH PC target IN rbox(location(caster), 1 + spellpower / 100) + DO IF has_shroud(target) && level(caster) * 2 > level(target) + THEN (unshroud(target); + sfx(target, SFX_DEFAULT, 500);) + + +SPELL enchant-lifestone : "#G12" = + LET level = 1 + school = MAGIC + IN (MANA 15, CASTTIME 4000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + (COMPONENTS["BugLeg"] OR COMPONENTS ["MaggotSlime"] + OR COMPONENTS ["MauveHerb", "AlizarinHerb", "CobaltHerb", "GambogeHerb"])) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + create_item(caster, "Lifestone", 1); + CALL gain_xp(1); + +SPELL sense-spouse : "#G13" = + LET level = 1 + school = MAGIC + IN (MANA 7, CASTTIME 400, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + REQUIRE is_married(caster), + REQUIRE is_equipped(caster, "WeddingRing")) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + IF (failed(partner(caster)) || not(is_equipped(partner(caster), "WeddingRing"))) + THEN (message(caster, "You cannot sense your partner."); + ABORT;) + partner = partner(caster); + name = name_of(partner); + IF (is_dead(partner) || (map_nr(location(partner)) <> map_nr(location(caster)))) + THEN (message(caster, "You cannot sense " + name + " nearby."); + ABORT;) + IF (map_level(location(partner)) > 2 && map_level(location(caster)) < map_level(location(partner))) + THEN (message(caster, "You sense " + name + " somewhere below."); + ABORT;) + IF (map_level(location(caster)) > 2 && map_level(location(partner)) < map_level(location(caster))) + THEN (message(caster, "You sense " + name + " somewhere above."); + ABORT;) + IF (map_level(location(caster)) <> map_level(location(partner))) + THEN message(caster, "You sense " + name + " somewhere in the vincinity."); + ELSE (distance = rdistance(location(caster), location(partner)); + dir = dir_towards(location(caster), location(partner), 1); + IF (distance < 3) + THEN message(caster, "You sense " + name + " right next to you."); + ELSE IF (distance < 30) + THEN message(caster, "You sense " + name + " close by, towards the " + dir + "."); + ELSE IF (distance < 200) + THEN message(caster, "You sense " + name + " nearby, towards the " + dir + "."); + ELSE message(caster, "You sense " + name + " in the " + dir + "."); + ) + +SPELL hide (target : PC) : "#A13" = + LET level = 1 + school = ASTRAL + IN (MANA 11, CASTTIME 1000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["CottonCloth"]), + REQUIRE rdistance(location(target), location(caster)) < 2 + spellpower / 30) + => EFFECT CALL adjust_spellpower(school); + sfx(target, SFX_DEFAULT, 0); + IF (caster <> target) + THEN CALL default_effect(); + status_change(target, SC_HIDE, 0, 0, 0, 0, 5000 + (spellpower * 2500)); + CALL gain_xp(2); + message(target, "You are hidden!"); + IF (caster <> target) THEN message(caster, "You hid someone!"); + ATEND message(target, "You are no longer hidden."); + +#-------------------------------------------------------------------------------- +# Level 2 spells +#-------------------------------------------------------------------------------- + +SPELL cure-poison (target : PC) : "#L20" = + LET level = 2 + school = LIFE + IN (MANA 15, CASTTIME 1000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + REQUIRE (rdistance(location(caster), + location(pc(target))) < 1 + (spellpower / 60)), + COMPONENTS ["GambogeHerb"]) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + IF (running_status_update (target, SC_POISON)) + THEN (CALL gain_heal_xp(40, 1, 2, 2); + stop_status_change (target, SC_POISON); + CALL gain_xp(2); + IF caster <> target + THEN sfx(target, SFX_HEAL, 0);); + + +SPELL fire-ball : "#W22" = + LET level = 2 + school = WAR + IN (MANA 30, CASTTIME 1000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + COMPONENTS ["PileOfAsh"]) + => EFFECT CALL adjust_spellpower(school); + damage = min(50 + skill(caster, school) * 40, + 30 + ((spellpower * 3) / 2)); + damage_bonus = level(caster) + spellpower * 2; + radius = 2 + spellpower / 50; + CALL install_attack_spell(1 + spellpower / 60, + 5000, + 10, 31); + ATTRIGGER CALL attack_check(target); + loc = location(target); + #WAIT 500; + sfx(loc, 16, 0); + FOREACH TARGET target IN rbox(loc, radius) + DO IF line_of_sight(loc, location(target)) + THEN (divisor = (3 + rdistance(loc, location(target))); + CALL elt_damage (target, (damage * 3) / divisor, (damage_bonus * 3) / divisor, ELT_WATER, ELT_FIRE, 15); + ) + +SPELL summon-partner : "#A23" = + LET level = 2 + school = ASTRAL + IN (MANA 30, CASTTIME 2000, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level, + REQUIRE is_married(caster), + REQUIRE is_equipped(caster, "WeddingRing")) + => EFFECT CALL adjust_spellpower(school); + CALL default_effect(); + IF (failed (partner (caster))) + THEN message (caster, "You call out for your partner, but there is no response."); + ELSE (message (caster, "You call out for " + (name_of (partner (caster))) + "."); + message (partner(caster), name_of(caster) + " is calling for your aid!"); + sfx(partner(caster), 2, 0); + WAIT (max (5000, 30000 - (spellpower * 60))); + IF (failed (partner (caster))) + THEN message (caster, "Your partner has abandoned you."); + ELSE IF (is_dead (partner (caster))) + THEN message (caster, "Something seems to have happened to " + (name_of(partner(caster))) + "."); + ELSE (sfx(location(partner(caster)), SFX_TELEPORT, 0); + dest = awayfrom(location(caster), random_dir(1), 1); + warp(partner(caster), dest); + sfx(dest, SFX_TELEPORT, 0); + ) + ) + + + +#-------------------------------------------------------------------------------- +# Level 4 spells +#-------------------------------------------------------------------------------- + +SPELL shroud : "#N40" = + LET level = 4 + school = NATURE + IN (MANA 40, CASTTIME 400, + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level) + => EFFECT CALL default_effect(); + shroud(caster, 0x04); + +SPELL teleport (destination : STRING) : "#A40" = + LET level = 4 + school = ASTRAL + IN (MANA 80, CASTTIME 400, + # COMPONENT ["EtherEssence"], + # CATALYST ["TeleportCrystal"], + REQUIRE skill(caster, MAGIC) > level, + REQUIRE skill(caster, school) > level) + => EFFECT CALL default_effect(); + WAIT 1000 + (200000 / (spellpower + 10)); + sfx(location(caster), SFX_TELEPORT, 200); + warp(caster, random_location(anchor(destination))); + sfx(caster, SFX_TELEPORT, 200); + +#-------------------------------------------------------------------------------- +# Debug keywords +#-------------------------------------------------------------------------------- + +SPELL debug : "debug" = + REQUIRE DEBUG + => EFFECT message (caster, "FLAGS: " + + "drank=" + ((script_int(caster, "MAGIC_FLAGS") & 1) > 0) + ", " + + "Kmseed=" + ((script_int(caster, "MAGIC_FLAGS") & 2) > 0) + ", " + + "touched-mseed=" + ((script_int(caster, "MAGIC_FLAGS") & 4) > 0) + ", " + + "mseed-max=" + ((script_int(caster, "MAGIC_FLAGS") & 8) > 0) + ", " + + "Kauldsbel=" + ((script_int(caster, "MAGIC_FLAGS") & 16) > 0) + ", " + + "Kwyara=" + ((script_int(caster, "MAGIC_FLAGS") & 32) > 0) + ", " + + "Ksagatha=" + ((script_int(caster, "MAGIC_FLAGS") & 64) > 0) + ", " + + "Kmpotion=" + ((script_int(caster, "MAGIC_FLAGS") & 128) > 0) + ", " + + "mseed-rumour=" + ((script_int(caster, "MAGIC_FLAGS") & 256) > 0) + ", " + + "Kcuttree=" + ((script_int(caster, "MAGIC_FLAGS") & 512) > 0) + ", " + + "cut=" + ((script_int(caster, "MAGIC_FLAGS") & 1024) > 0) + ", " + + "Kdruidtree=" + ((script_int(caster, "MAGIC_FLAGS") & 2048) > 0) + ", " + + "Kimp=" + ((script_int(caster, "MAGIC_FLAGS") & 4096) > 0) + ", " + + "Koldwiz=" + ((script_int(caster, "MAGIC_FLAGS") & 8192) > 0) + ", " + + "made-conc=" + ((script_int(caster, "MAGIC_FLAGS") & 16384) > 0) + ", " + + "elanore-omar=" + ((script_int(caster, "MAGIC_FLAGS") & 32768) > 0)); + message (caster, "EXP: " + (script_int(caster, "MAGIC_EXPERIENCE") & 0xffff) + + ", lastspell=" + ((script_int(caster, "MAGIC_EXPERIENCE") >> 16) & 0xff) + + ", healexp=" + ((script_int(caster, "MAGIC_EXPERIENCE") >> 24) & 0xff)); + message (caster, "STATUS: " + + "auldsbel:" + (script_int(caster, "QUEST_MAGIC") & 0x1f) + "," + ((script_int(caster, "QUEST_MAGIC") >> 5) & 0x7) + ", " + + "dt/mb:" + ((script_int(caster, "QUEST_MAGIC") >> 8) & 0xf) + ", " + + "s-unhappy:" + ((script_int(caster, "QUEST_MAGIC") >> 12) & 0xf) + ", " + + "sagatha:" + ((script_int(caster, "QUEST_MAGIC") >> 16) & 0xff) + ", " + + "swords:" + ((script_int(caster, "QUEST_MAGIC") >> 24) & 0xff) + ", " + + "imp:" + ((script_int(caster, "QUEST_MAGIC2") >> 0) & 0xf) + ", " + + "elanore:" + ((script_int(caster, "QUEST_MAGIC2") >> 4) & 0xf) + ", " + + "elanore-sub:" + ((script_int(caster, "QUEST_MAGIC2") >> 12) & 0xf) + ", " + + "wyara:" + ((script_int(caster, "QUEST_MAGIC2") >> 8) & 0xf)); + +PROCEDURE debug_xmod(name, mask, shift, gain) = + value = ((script_int(caster, name) >> shift) & mask) + gain; + IF (value < 0) + THEN value = 0; + IF (value > mask) + THEN value = mask; + CALL set_var(name, mask, shift, value); + +PROCEDURE debug_mod(name, delta) = + IF (name = "mexp") THEN CALL debug_xmod("MAGIC_EXPERIENCE", 0xffff, 0, delta); + ELSE IF (name = "lastspell") THEN CALL debug_xmod("MAGIC_EXPERIENCE", 0xff, 16, delta); + ELSE IF (name = "healexp") THEN CALL debug_xmod("MAGIC_EXPERIENCE", 0xff, 24, delta); + ELSE IF (name = "drank") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 0, delta); + ELSE IF (name = "Kmseed") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 1, delta); + ELSE IF (name = "touched-mseed") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 2, delta); + ELSE IF (name = "mseed-max") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 3, delta); + ELSE IF (name = "Kauldsbel") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 4, delta); + ELSE IF (name = "Kwyara") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 5, delta); + ELSE IF (name = "Ksagatha") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 6, delta); + ELSE IF (name = "Kmpotion") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 7, delta); + ELSE IF (name = "mseed-rumour") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 8, delta); + ELSE IF (name = "Kcuttree") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 9, delta); + ELSE IF (name = "cut") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 10, delta); + ELSE IF (name = "Kdruidtree") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 11, delta); + ELSE IF (name = "Kimp") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 12, delta); + ELSE IF (name = "oldwiz") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 13, delta); + ELSE IF (name = "made-conc") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 14, delta); + ELSE IF (name = "elanore-omar") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 15, delta); + ELSE IF (name = "auldsbel") THEN CALL debug_xmod("QUEST_MAGIC", 0x1f, 0, delta); + ELSE IF (name = "Qauldsbel") THEN CALL debug_xmod("QUEST_MAGIC", 0x7, 5, delta); + ELSE IF (name = "dt") THEN CALL debug_xmod("QUEST_MAGIC", 0x3, 10, delta); + ELSE IF (name = "mb") THEN CALL debug_xmod("QUEST_MAGIC", 0x3, 8, delta); + ELSE IF (name = "s-unhappy") THEN CALL debug_xmod("QUEST_MAGIC", 0xff, 12, delta); + ELSE IF (name = "sagatha") THEN CALL debug_xmod("QUEST_MAGIC", 0xff, 16, delta); + ELSE IF (name = "swords") THEN CALL debug_xmod("QUEST_MAGIC", 0xff, 24, delta); + ELSE IF (name = "imp") THEN CALL debug_xmod("QUEST_MAGIC2", 0xf, 0, delta); + ELSE IF (name = "elanore") THEN CALL debug_xmod("QUEST_MAGIC2", 0xf, 4, delta); + ELSE IF (name = "wyara") THEN CALL debug_xmod("QUEST_MAGIC2", 0xf, 8, delta); + ELSE IF (name = "elanore-sub") THEN CALL debug_xmod("QUEST_MAGIC2", 0xf, 12, delta); + ELSE message(caster, "Unknown"); + +SPELL debug-up1 (name : STRING) : "debug+1" = + REQUIRE DEBUG + => EFFECT CALL debug_mod(name, 1); + +SPELL debug-down1 (name : STRING) : "debug-1" = + REQUIRE DEBUG + => EFFECT CALL debug_mod(name, 0 - 1); + +SPELL debug-up16 (name : STRING) : "debug+16" = + REQUIRE DEBUG + => EFFECT CALL debug_mod(name, 16); + +SPELL debug-down16 (name : STRING) : "debug-16" = + REQUIRE DEBUG + => EFFECT CALL debug_mod(name, 0 - 16); + +SPELL debug-up256 (name : STRING) : "debug+256" = + REQUIRE DEBUG + => EFFECT CALL debug_mod(name, 256); + +SPELL debug-down256 (name : STRING) : "debug-256" = + REQUIRE DEBUG + => EFFECT CALL debug_mod(name, 0 - 256); + +SPELL debug-reset : "debug-reset" = + REQUIRE DEBUG + => EFFECT set_script_variable(caster, "QUEST_MAGIC", 0); + set_script_variable(caster, "QUEST_MAGIC2", 0); + set_script_variable(caster, "MAGIC_FLAGS", 0); + set_script_variable(caster, "MAGIC_EXP", 0); + + +#-------------------------------------------------------------------------------- +# Special-purpose quasispells +#-------------------------------------------------------------------------------- + +CONST MIN_MARRY_LEVEL = 32; + +NONMAGIC SILENT SPELL marriage (target : PC) : "marry" = + (REQUIRE (is_in(location(caster), @("014-1.gat", 28,39) @+ (8, 6)) || is_in(location(caster), @("021-2.gat", 20,25) @+ (4, 4)) ))=> + EFFECT IF target == caster # no valid target or tried to marry self? + THEN ABORT; + + IF (level(caster) < MIN_MARRY_LEVEL) + THEN (message(caster, "You must be level " + MIN_MARRY_LEVEL + " or higher to marry!"); ABORT;) + + IF (level(target) < MIN_MARRY_LEVEL) + THEN (message(caster, "Your partner must be level " + MIN_MARRY_LEVEL + " or higher to marry!"); ABORT;) + + IF partner(caster) = target + THEN (message(caster, "You and " + name_of(target) + " are already married."); ABORT;) + + IF is_married(caster) + THEN (message(caster, "You are already married!"); ABORT;) + + IF is_married(target) + THEN (message(caster, name_of(target) + " is already married."); ABORT;); + + IF distance(location(caster), location(target)) <> 1 + THEN (message(caster, "You need to stand next to each other."); ABORT;); + + IF (count_item(caster, "WeddingRing") == 0 || count_item(target, "WeddingRing") == 0) + THEN (message(caster, "You must both be wearing your wedding rings!"); ABORT;) + + script_target = target; + { + announce @caster_name$ + " is asking " + strcharinfo(0) + " for marriage.", 2; + mes @caster_name$ + " wishes to marry you."; + mes "Do you accept?"; + next; + menu "Yes, I do!", L_yes, + "No.", -; + close; + + L_yes: + if marriage(@caster_name$) + announce @caster_name$ + " and " + strcharinfo(0) + " are now married!", 0; + close; + } + + IF not (is_married(caster)) + THEN message(caster, name_of(target) + " turned down your marriage offer."); + +# SPELL change-hair-colour (colour : STRING) : "trapa" = +# (MANA 20) => EFFECT IF colour = "nworbl" +# THEN x = 0; # light brown +# ELSE IF colour = "der" +# THEN x = 1; # red +# ELSE IF colour = "neerg" +# THEN x = 2; # green +# ELSE IF colour = "elprup" +# THEN x = 3; # purple +# ELSE IF colour = "yerg" +# THEN x = 4; # grey +# ELSE IF colour = "wolley" +# THEN x = 5; # yellow +# ELSE IF colour = "eulb" +# THEN x = 6; # blue +# ELSE IF colour = "nwrob" +# THEN x = 7; # brown +# ELSE IF colour = "elpropl" +# THEN x = 8; # light purple +# ELSE IF colour = "elpropd" +# THEN x = 9; # dark purple +# ELSE x = random(10); +# sfx(caster, 2, 0); +# set_hair_colour(caster, x); + + +# SPELL trick-or-treat : "trick-or-treat" = +# (CASTTIME 30000, MANA 20, +# COMPONENTS [ "BugLeg" ]) => EFFECT IF (random(2)) +# THEN (sfx(caster, 2, 0); +# FOR i = 0 TO random(10) DO +# drop_item_for (random_location(rbox(location(caster), 5)), +# "Candy", 1, 10000 + random(10000), caster, 3000); +# FOR i = 0 TO random(10) DO +# drop_item_for (random_location(rbox(location(caster), 5)), +# "ChocolateBar", 1, 10000 + random(10000), caster, 3000); +# ) +# ELSE (sfx(caster, 5, 0); +# message(caster, "No treat for you!"); +# spawn(rbox(location(caster), 3), caster, 1010, 0, 1 + random(3), 10000 + random(20000)); +# FOREACH MOB target IN rbox(location(caster), 5) DO +# (sfx(target, 5, 0); +# aggravate(target, 0, caster);)) + + +LOCAL SPELL mouboo-groan : "#g" = + (MANA 1, + REQUIRE name_of(caster) = "MOUBOOTAUR") => + EFFECT FOREACH PC p IN rbox(location(caster), 200) DO + distance = rdistance(location(caster), location(p)); + IF (distance < 15) + THEN message(p, "The moubootaur's groaning rings in your ears!"); + ELSE IF (distance < 70) + THEN message(p, "You hear a loud groaning noise, not far away..."); + ELSE message(p, "You hear an odd groaning noise in the distance..."); + + +LOCAL SPELL mouboo-smell : "#s" = + (MANA 1, + REQUIRE name_of(caster) = "MOUBOOTAUR") => + EFFECT WAIT 30000; + FOREACH PC p IN rbox(location(caster), 30) DO + message(p, "You notice a strange smell all around you."); + + +CONST E10_FLAG_USED_FREE_WARP_SHIFT = 17 + +#NONMAGIC SILENT SPELL easter (type : STRING) : "#m" = +# (REQUIRE name_of(caster) == "Freeyorp") => +# EFFECT IF (type == "EE_RF") THEN ( +# { +# doevent("Old Woman::OnReplenish"); +# } +# ) ELSE IF (type == "EE_SUS") THEN ( +# { +# doevent "Old Woman::OnManualStopTimer"; +# } +# ) ELSE IF (type == "EE_INIT") THEN ( +# { +# doevent "Old Woman::OnManualStartTimer"; +# } +# ) ELSE IF (type == "BLOCKER_DISABLE") THEN ( +# { +# set $Easter_2010_Npc_State2, ($Easter_2010_Npc_State2 & ~(E10_BARRIER_MASK << E10_BARRIER_SHIFT)) | (E10_BARRIER_OPEN << E10_BARRIER_SHIFT); +# } +# ) ELSE IF (type == "BLOCKER_ENABLE") THEN ( +# { +# set $Easter_2010_Npc_State2, ($Easter_2010_Npc_State2 & ~(E10_BARRIER_MASK << E10_BARRIER_SHIFT)) | (E10_BARRIER_ACTIVE << E10_BARRIER_SHIFT); +# } +# ) ELSE message(caster, "Unknown action '" + type + "'!"); + +# Invader spells + +#NONMAGIC SILENT SPELL easter-invader-init : "#i" = +# (REQUIRE name_of(caster) == "Xakelbael the Dark") => +# EFFECT warp(caster, @("028-1.gat", 139, 46)); +# { +# gmcommand "@blvl -255"; +# gmcommand "@blvl 199"; +# gmcommand "@setmagic all 5 Xakelbael the Dark"; +# gmcommand "@allstats"; +# savepoint "028-1.gat", 130, 46; +# } +# create_item(caster, "DarkTalisman", 1); + +#NONMAGIC SILENT SPELL easter-invader-hide : "#h" = +# (REQUIRE name_of(caster) == "Xakelbael the Dark") => +# EFFECT { if (checkoption(4096)) goto L_toggle; +# setoption(4096); +# end; +# L_toggle: +# setoption(0); +# end; }; +# warp(caster, location(caster)); + +#NONMAGIC SILENT SPELL easter-invader-warp-taunt : "#o" = +# (REQUIRE name_of(caster) == "Xakelbael the Dark") => +# EFFECT warp(caster, @("009-1.gat", 48, 35)); +# WAIT 80; +# sfx(caster, 32, 0); +# WAIT 80; +# FOREACH PC p IN rbox(location(caster), 50) +# DO IF (p <> caster) THEN ( +# message(p, "A powerful explosion " + if_then_else(distance(location(caster), location(p)) < 10, "right around you nearly deafens you!", if_then_else(distance(location(caster), location(p)) < 30, "nearby shocks you!", "in the distance erupts... you're not sure of the source, but it will be something big..."))); +# itemheal(p, -1 - random(hp(p)), 0-(random(sp(p) >> 2))); +# ) +# WAIT 1000; +# FOREACH PC p IN rbox(location(caster), 15) +# DO ( +# message(p, "As the smoke clears, you hear a distant, sickly laughing ringing in your ears..."); +# ) + +#NONMAGIC SILENT SPELL easter-invader-warp-taunt-explosion : "#q" = +# (REQUIRE name_of(caster) == "Xakelbael the Dark") => +# EFFECT sfx(caster, 32, 0); +# WAIT 100; +# sfx(caster, 31, 0); +# WAIT 30; +# sfx(caster, 30, 0); +# WAIT 30; +# sfx(caster, 30, 0); +# WAIT 20; +# sfx(caster, 30, 0); +# WAIT 10; +# sfx(caster, 30, 0); +# WAIT 10; + +#NONMAGIC SILENT SPELL easter-invader-warp-taunt-end : "#p" = +# (REQUIRE name_of(caster) == "Xakelbael the Dark") => +# EFFECT FOREACH PC p IN rbox(location(caster), 50) DO IF (p <> caster) +# THEN ( script_target = p; +# { gmcommand "@jump"; } +# message(p, "A powerful force sends you flying!"); +# ) +# warp(caster, @("028-1.gat", 130, 46)); + + +#NONMAGIC SILENT SPELL easter-invader-attack-pulse : "#a" = +# (REQUIRE name_of(caster) == "Xakelbael the Dark") => +# EFFECT IF (script_int(caster, "InvState") == 1) THEN ( set_script_variable(caster, "InvState", 0); ABORT; ); +# set_script_variable(caster, "InvState", 1); +# FOR i = 1 TO 500 +# DO ( sfx(caster, 31, 0); +# WAIT 80; +# FOREACH PC p IN rbox(location(caster), 4) +# DO IF (p <> caster) THEN ( injure(caster, p, 30 - random(random(25)) - random(5) + random(i), 0); ) +# WAIT 420; +# IF (script_int(caster, "InvState") == 0) THEN ABORT; +# ) +# set_script_variable(caster, "InvState", 0); + +#NONMAGIC SILENT SPELL easter-invader-command : "#d" = +# (REQUIRE name_of(caster) == "Xakelbael the Dark") => +# EFFECT override_attack(caster, 3, ((200 - agi(caster)) * 5000) / 200, +# 8, ATTACK_ICON_GENERIC, 31, 0); +# ATTRIGGER CALL attack_check(target); +# area = rbox(location(target), 8); +# FOREACH MOB m IN area +# DO (message(caster, "Class Id: " + mob_id(m)); +# IF (mob_id(m) = 1040 || mob_id(m) == 1042 || mob_id(m) == 1047) THEN ( +# CALL sfx_generic(m); +# aggravate(m, 0, target); +# ) +# ) + +#NONMAGIC SILENT SPELL easter-invader-spike : "#w" = +# (REQUIRE name_of(caster) == "Xakelbael the Dark") => +# EFFECT FOR i = 1 TO 40 +# DO ( point = random_location(rbox(location(caster), sqrt(i) << 1)); +# IF (random(3)) +# THEN (sfx(point, 32, 0); +# WAIT 50; +# FOREACH PC p IN rbox(point, sqrt(i) >> 1) +# DO IF (p <> caster) +# THEN (injure(caster, p, i + random(i << 1), random(random(i)));) +# ) ELSE (sfx(point, 31, 0); +# WAIT 50; +# FOREACH PC p IN rbox(point, sqrt(i)) +# DO IF (p <> caster) +# THEN (injure(caster, p, i + random(i << 2), random(random(i)));) +# ) +# WAIT 400 - (i << 3); +# ) + +#NONMAGIC SILENT SPELL easter-invader-jump (t : STRING) : "#j" = +# (REQUIRE name_of(caster) == "Xakelbael the Dark") => +# EFFECT IF not (status_option(caster, 4096)) THEN ( sfx(caster, 33, 0); +# WAIT 200; ); +# IF (t == "r") THEN ( warp(caster, @("028-1.gat", 129, 46)); ) +# ELSE IF (t == "s") THEN ( warp(caster, @("028-1.gat", 69, 96)); ) +# ELSE IF (t == "c") THEN ( warp(caster, @("028-3.gat", 50, 58)); ) +# ELSE IF (t == "t") THEN ( warp(caster, @("009-1.gat", 48, 35)); ) +# ELSE { gmcommand "@jump"; }; + +#NONMAGIC SILENT SPELL easter-invader-taunt-local (s : STRING) : "#l" = +# (REQUIRE name_of(caster) == "Xakelbael the Dark") => +# EFFECT FOREACH PC p IN rbox(location(caster), 20) DO message(p, s); + +#NONMAGIC SILENT SPELL easter-invader-taunt-global (s : STRING) : "#b" = +# (REQUIRE name_of(caster) == "Xakelbael the Dark") => +# EFFECT FOREACH PC p IN rbox(location(caster), 100) DO message(p, s); + +#NONMAGIC SILENT SPELL easter-invader-spawn : "#c" = +# (REQUIRE name_of(caster) == "Xakelbael the Dark") => +# EFFECT spawn(rbox(location(caster), 20), caster, 1040, random(random(5)), 1, 100000); +# spawn(rbox(location(caster), 20), caster, 1042, random(random(5)), 1, 100000); +# spawn(rbox(location(caster), 20), caster, 1047, random(random(5)), 1, 100000); + +NONMAGIC SILENT SPELL world-shift : "#S00" = + (REQUIRE (script_int(caster, "Easter_2010_QuestState") >> 16) & 1 == 1 && (script_int(caster, "Easter_2010_QuestState") >> 7) & 3 == 2) => # Travel only works when you have both helped the doctor at least thrice and have defeated the invader - top level requirement. + ( (REQUIRE count_item(caster, "DarkPetal")) # Allow unlimited travel with the petal + => ((REQUIRE rdistance(location(caster), @("028-1.gat", 63, 67)) < 5) => + EFFECT sfx(location(caster), SFX_TELEPORT, 200); + WAIT 8000; + { savepoint "009-1", 52, 39; }; + warp(caster, @("009-1.gat", 55, 37)); + sfx(location(caster), SFX_TELEPORT, 200); + | + (REQUIRE map_nr(location(caster)) != 28) => + EFFECT inithp = hp(caster); // Store this value. + sfx(location(caster), SFX_TELEPORT, 200); + IF (map_nr(location(caster)) == 9 || map_nr(location(caster)) == 1 || map_nr(location(caster)) == 21 || map_nr(location(caster)) == 20) THEN WAIT 8000; + ELSE WAIT 20000; + IF (hp(caster) < inithp) THEN ABORT; // Cancel teleport if the player took damage during channel time (hacky, but for most purposes should work.) + { savepoint "028-1", 63, 68; }; + warp(caster, @("028-1.gat", 63, 67)); + sfx(location(caster), SFX_TELEPORT, 200); + ) + | (REQUIRE (rdistance(location(caster), @("028-1.gat", 63, 67)) < 5 ) + => EFFECT set_script_variable(caster, "Easter_2010_QuestState", script_int(caster, "Easter_2010_QuestState") | (1 << 17)); + sfx(location(caster), SFX_TELEPORT, 200); + WAIT 8000; + { savepoint "009-1", 52, 39; }; + warp(caster, @("009-1.gat", 55, 37)); + sfx(location(caster), SFX_TELEPORT, 200); + | (REQUIRE map_nr(location(caster)) != 28 && (script_int(caster, "Easter_2010_QuestState") >> 17) & 1 == 0) # Allow for one free warp home without the petal + => EFFECT inithp = hp(caster); // Store this value. + sfx(location(caster), SFX_TELEPORT, 200); + IF (map_nr(location(caster)) == 9 || map_nr(location(caster)) == 1 || map_nr(location(caster)) == 21 || map_nr(location(caster)) == 20) THEN WAIT 8000; + ELSE WAIT 20000; + IF (hp(caster) < inithp) THEN ABORT; // Cancel teleport if the player took damage during channel time (hacky, but for most purposes should work.) + set_script_variable(caster, "Easter_2010_QuestState", script_int(caster, "Easter_2010_QuestState") | (1 << 17)); + { savepoint "028-1", 63, 68; }; + warp(caster, @("028-1.gat", 63, 67)); + sfx(location(caster), SFX_TELEPORT, 200); + ) + ) + +#NONMAGIC SILENT SPELL easter-invader-killer : "#z" = +# (REQUIRE name_of(caster) == "Xakelbael the Dark") => +# EFFECT { gmcommand "@killer"; } + +#NONMAGIC SILENT SPELL easter-invader-killable : "#x" = +# (REQUIRE name_of(caster) == "Xakelbael the Dark") => +# EFFECT { gmcommand "@killable"; } + +#NONMAGIC SILENT SPELL easter-debug-reset (s : STRING) : "#r" = +# (REQUIRE name_of(caster) == "Freeyorp") => +# EFFECT set_script_variable(pc(s), "Easter_2010_QuestState", 0); + +#NONMAGIC SILENT SPELL easter-set-flag (s : PC) : "#k" = +# (REQUIRE name_of(caster) == "Freeyorp" || name_of(caster) == "Xakelbael the Dark") => +# EFFECT IF (s == caster) THEN ABORT; +# IF ((script_int(s, "Easter_2010_QuestState") >> 16) & 1) THEN ( message(caster, s + " already has the flag set!"); ABORT; ) +# script_target = s; +# { set Easter_2010_QuestState, Easter_2010_QuestState | (1 << 16); // RETURN_READY flag +# mes "As the smoke clears, you feel stronger, vivified."; +# next; +# mes "The world seems more vibrant. It looks the same as ever, but you get a sense of something more."; +# next; +# mes "You feel something familiar."; +# next; +# mes "This sensation... could it be home?"; +# next; +# mes "A single word comes to your mind - " + getspellinvocation("world-shift") + ". While it sounds magical, you know with certainty that you will not need any magical power to use it."; +# next; +# mes "Could this be the way to move to and from the worlds? Either way, the dark petal the rose vanished into seems to be the key."; +# next; +# mes "Though you might be able to succeed in one trip without it, returning home."; +# if ((Easter_2010_QuestState >> E10_STATE_ROSE_SHIFT) & E10_STATE_ROSE_MASK == E10_STATE_ROSE_ROSE_COMPLETE) close; +# next; +# mes "But the world is still not quite right. Perhaps there is someone you should help before the world releases its hold on you?"; +# close; +# } + +NONMAGIC SILENT SPELL easter-get-debug (p : PC) : "#e" = + (REQUIRE name_of(caster) == "Freeyorp" || name_of(caster) == "Xakelbael the Dark") => + EFFECT { message strcharinfo(0), "Global state egg1: " + $Easter_2010_Egg_Loc_State1; + message strcharinfo(0), "Global state egg2: " + $Easter_2010_Egg_Loc_State2; + message strcharinfo(0), "Global state egg3: " + $Easter_2010_Egg_Loc_State3; + message strcharinfo(0), "Global state egg4: " + $Easter_2010_Egg_Loc_State4; + message strcharinfo(0), "Global state egg5: " + $Easter_2010_Egg_Loc_State5; + message strcharinfo(0), "Global npc state1: " + $Easter_2010_Npc_State1; + message strcharinfo(0), "Global npc state2: " + $Easter_2010_Npc_State2; + }; + message(caster, "Local state egg1: " + script_int(p, "Easter_2010_EggState1")); + message(caster, "Local state egg2: " + script_int(p, "Easter_2010_EggState2")); + message(caster, "Local state egg3: " + script_int(p, "Easter_2010_EggState3")); + message(caster, "Local state egg4: " + script_int(p, "Easter_2010_EggState4")); + message(caster, "Local state egg5: " + script_int(p, "Easter_2010_EggState5")); + message(caster, "Local state quest: " + script_int(p, "Easter_2010_QuestState")); + + + + +PROCEDURE hug_tree(target) = + IF (target = "" + || target = "tree" || target = "tree*" + || target = "Tree" || target = "Tree*" + || target = "druid" || target = "druid*" + || target = "Druid" || target = "Druid*") + THEN { + set @flag, 2; + callfunc "QuestTreeTrigger"; + }; + +NONMAGIC SPELL hug0 (target : STRING) : "hug" = REQUIRE ((rdistance(location(caster), location(npc("#DruidTree0#_M"))) <= 1 + || rdistance(location(caster), location(npc("#DruidTree1#_M"))) <= 1)) + => EFFECT CALL hug_tree(target); + +NONMAGIC SPELL hug1 (target : STRING) : "*hug*" = REQUIRE ((rdistance(location(caster), location(npc("#DruidTree0#_M"))) <= 1 + || rdistance(location(caster), location(npc("#DruidTree1#_M"))) <= 1)) + => EFFECT CALL hug_tree(target); + +NONMAGIC SPELL hug2 (target : STRING) : "*hug" = REQUIRE ((rdistance(location(caster), location(npc("#DruidTree0#_M"))) <= 1 + || rdistance(location(caster), location(npc("#DruidTree1#_M"))) <= 1)) + => EFFECT CALL hug_tree(target); + +NONMAGIC SPELL hug3 (target : STRING) : "hugs" = REQUIRE ((rdistance(location(caster), location(npc("#DruidTree0#_M"))) <= 1 + || rdistance(location(caster), location(npc("#DruidTree1#_M"))) <= 1)) + => EFFECT CALL hug_tree(target); + +NONMAGIC SPELL hug4 (target : STRING) : "*hugs*" = REQUIRE ((rdistance(location(caster), location(npc("#DruidTree0#_M"))) <= 1 + || rdistance(location(caster), location(npc("#DruidTree1#_M"))) <= 1)) + => EFFECT CALL hug_tree(target); + +NONMAGIC SPELL hug5 (target : STRING) : "*hugs" = REQUIRE ((rdistance(location(caster), location(npc("#DruidTree0#_M"))) <= 1 + || rdistance(location(caster), location(npc("#DruidTree1#_M"))) <= 1)) + => EFFECT CALL hug_tree(target); + + +#-------------------------------------------------------------------------------- +# Teleport anchors +#-------------------------------------------------------------------------------- + +TELEPORT-ANCHOR tulimshar : "tulimshar" = @("001-1.gat", 43, 66) @+ (3, 3); +TELEPORT-ANCHOR hurnscald : "hurnscald" = @("009-1.gat", 55, 37) @+ (3, 3); +TELEPORT-ANCHOR nivalis : "nivalis" = @("020-1.gat", 75, 63) @+ (19, 12); +TELEPORT-ANCHOR wizardhut : "##00" = @("013-1.gat", 41, 92) @+ (3, 3); +TELEPORT-ANCHOR pachua : "##01" = @("006-1.gat", 22, 101) @+ (3, 3); +TELEPORT-ANCHOR desert : "##02" = @("005-1.gat", 160, 64) @+ (5, 5); +TELEPORT-ANCHOR forest : "##03" = @("015-1.gat", 35, 35) @+ (40, 40); +TELEPORT-ANCHOR snakecave : "##04" = @("011-4.gat", 50, 75) @+ (3, 3); +TELEPORT-ANCHOR dimondscove : "##05" = @("010-2.gat", 23, 79) @+ (3, 3); + + diff --git a/conf/map_athena.conf b/conf/map_athena.conf new file mode 100644 index 00000000..cade6729 --- /dev/null +++ b/conf/map_athena.conf @@ -0,0 +1,19 @@ +// eAthena Map-Server Configuration File + +// Database autosave time, in seconds. +autosave_time: 60 + +// Message of the day file, when a character logs on, this message is displayed. +motd_txt: conf/motd.txt + +// When @help or @h is typed when you are a gm, this is displayed for helping new gms understand gm commands. +help_txt: conf/help.txt + +mapreg_txt: save/mapreg.txt + +import: npc/scripts.conf + +gm_log: gm/gm.log + +// local settings for this server in this file +import: conf/map_local.conf diff --git a/conf/map_local.conf.example b/conf/map_local.conf.example new file mode 100644 index 00000000..0f09bf59 --- /dev/null +++ b/conf/map_local.conf.example @@ -0,0 +1,15 @@ +// eAthena Map-Server local Configuration File + +// Interserver communication passwords, set in account.txt (or equiv.) +userid: s1 +passwd: p1 + +// Character Server IP +char_ip:81.161.192.4 +// Character Server Port +char_port: 6122 + +// Map Server IP +map_ip:81.161.192.4 +// Map Server Port +map_port: 5122 diff --git a/conf/motd.txt.example b/conf/motd.txt.example new file mode 100644 index 00000000..f570494c --- /dev/null +++ b/conf/motd.txt.example @@ -0,0 +1 @@ +Welcome to The Mana World! (running on eAthena) diff --git a/conf/msg_athena.conf b/conf/msg_athena.conf new file mode 100644 index 00000000..313d22b7 --- /dev/null +++ b/conf/msg_athena.conf @@ -0,0 +1,528 @@ +// eAthena msg_athena.conf +// Message Configuration +// For translation, just change msg here (second line), no need to modify source code. +// Format: +// // English message +// msg_number: translated message + +// 0-499: reserved for GM commands +// 500-999 reserved for others + +// Messages of GM commands +// ----------------------- + +//0: Warped. +0: Warped. +//1: Map not found. +1: Map not found. +//2: Coordinates out of range. +2: Coordinates out of range. +//3: Character not found. +3: Character not found. +//4: Jump to %s +4: Jump to %s +//5: Jump to %d %d +5: Jump to %d %d +//6: Character data respawn point saved. +6: Character data respawn point saved. +//7: Warping to respawn point. +7: Warping to respawn point. +//8: Speed changed. +8: Speed changed. +//9: Options changed. +9: Options changed. +//10: Invisible: Off. +10: Invisible: Off. +//11: Invisible: On. +11: Invisible: On. +//12: Your job has been changed. +12: Your job has been changed. +//13: A pity! You've died. +13: A pity! You've died. +//14: Character killed. +14: Character killed. +//15: Player warped (message sends to player too). +15: Player warped (message sends to player too). +//16: You've been revived! It's a miracle! +16: You've been revived! It's a miracle! +//17: HP, SP recovered. +17: HP, SP recovered. +//18: Item created. +18: Item created. +//19: Invalid item ID or name. +19: Invalid item ID or name. +//20: All of your items have been removed. +20: All of your items have been removed. +//21: Base level raised. +21: Base level raised. +//22: Base level lowered. +22: Base level lowered. +//23: Job level can't go any higher. +23: Job level can't go any higher. +//24: Job level raised. +24: Job level raised. +//25: Job level lowered. +25: Job level lowered. +//26: Help commands: +26: Help commands: +//27: File help.txt not found. +27: File help.txt not found. +//28: No player found. +28: No player found. +//29: 1 player found. +29: 1 player found. +//30: %d players found. +30: %d players found. +//31: PvP: Off. +31: PvP: Off. +//32: PvP: On. +32: PvP: On. +//33: GvG: Off. +33: GvG: Off. +//34: GvG: On. +34: GvG: On. +//35: You can't use this command with this class. +35: You can't use this command with this class. +//36: Appearence changed. +36: Appearence changed. +//37: An invalid number was specified. +37: An invalid number was specified. +//38: Invalid location number or name. +38: Invalid location number or name. +//39: All monster summoned! +39: All monster summoned! +//40: Invalid monster ID or name. +40: Invalid monster ID or name. +//41: Impossible to decrease the number/value. +41: Impossible to decrease the number/value. +//42: Stat changed. +42: Stat changed. +//43: You're not in a guild. +43: You're not in a guild. +//44: You're not the master of your guild. +44: You're not the master of your guild. +//45: Guild level change failed. +45: Guild level change failed. +//46: %s recalled! +46: %s recalled! +//47: Base level can't go any higher. +47: Base level can't go any higher. +//48: Character's job changed. +48: Character's job changed. +//49: Invalid job ID. +49: Invalid job ID. +//50: You already have some GM powers. +50: You already have some GM powers. +//51: Character revived. +51: Character revived. +//52: This option cannot be used in PK Mode. +52: This option cannot be used in PK Mode. +//53: '%s' stats: +53: '%s' stats: +//54: No player found in map '%s'. +54: No player found in map '%s'. +//55: 1 player found in map '%s'. +55: 1 player found in map '%s'. +//56: %d players found in map '%s'. +56: %d players found in map '%s'. +//57: Character's respawn point changed. +57: Character's respawn point changed. +//58: Character's options changed. +58: Character's options changed. +//59: Night has fallen. +59: Night has fallen. +//60: Day has arrived. +60: Day has arrived. +//61: The holy messenger has given judgement. +61: The holy messenger has given judgement. +//62: Judgement was made. +62: Judgement was made. +//63: Mercy has been shown. +63: Mercy has been shown. +//64: Mercy has been granted. +64: Mercy has been granted. +//65: Character's base level raised. +65: Character's base level raised. +//66: Character's base level lowered. +66: Character's base level lowered. +//67: Character's job level can't go any higher. +67: Character's job level can't go any higher. +//68: character's job level raised. +68: character's job level raised. +//69: Character's job level lowered. +69: Character's job level lowered. +//70: You have learned the skill. +70: You have learned the skill. +//71: You have forgotten the skill. +71: You have forgotten the skill. +//72: Guild siege warfare start! +72: Guild siege warfare start! +//73: Already it has started siege warfare. +73: Already it has started siege warfare. +//74: Guild siege warfare end! +74: Guild siege warfare end! +//75: Siege warfare hasn't started yet. +75: Siege warfare hasn't started yet. +//76: You have received all skills. +76: You have received all skills. +//77: The reference result of '%s' (name: id): +77: The reference result of '%s' (name: id): +//78: %s: %d +78: %s: %d +//79: It is %d affair above. +79: It is %d affair above. +//80: Give a display name and monster name/id please. +80: Give a display name and monster name/id please. +//81: Your GM level don't authorise you to do this action on this player. +81: Your GM level don't authorise you to do this action on this player. +//82: Please, use one of this number/name: +82: Please, use one of this number/name: +//83: Cannot spawn emperium. +83: Cannot spawn emperium. +//84: All stats changed! +84: All stats changed! +//85: Invalid time for ban command. +85: Invalid time for ban command. +//86: Sorry, but a player name have at least 4 characters. +86: Sorry, but a player name have at least 4 characters. +//87: Sorry, but a player name have 23 characters maximum. +87: Sorry, but a player name have 23 characters maximum. +//88: Character name sends to char-server to ask it. +88: Character name sends to char-server to ask it. +//89: Sorry, it's already the night. Impossible to execute the command. +89: Sorry, it's already the night. Impossible to execute the command. +//90: Sorry, it's already the day. Impossible to execute the command. +90: Sorry, it's already the day. Impossible to execute the command. +//91: Character's base level can't go any higher. +91: Character's base level can't go any higher. +//92: All characters recalled! +92: All characters recalled! +//93: All online characters of the %s guild are near you. +93: All online characters of the %s guild are near you. +//94: Incorrect name/ID, or no one from the guild is online. +94: Incorrect name/ID, or no one from the guild is online. +//95: All online characters of the %s party are near you. +95: All online characters of the %s party are near you. +//96: Incorrect name or ID, or no one from the party is online. +96: Incorrect name or ID, or no one from the party is online. +//97: Item database reloaded. +97: Item database reloaded. +//98: Monster database reloaded. +98: Monster database reloaded. +//99: Skill database reloaded. +99: Skill database reloaded. +//100: Scripts reloaded. +100: Scripts reloaded. +//101: Login-server asked to reload GM accounts and their level. +101: Login-server asked to reload GM accounts and their level. +//102: Mounted Peco. +102: Mounted Peco. +//103: No longer spying on the %s guild. +103: No longer spying on the %s guild. +//104: Spying on the %s guild. +104: Spying on the %s guild. +//105: No longer spying on the %s party. +105: No longer spying on the %s party. +//106: Spying on the %s party. +106: Spying on the %s party. +//107: All items have been repaired. +107: All items have been repaired. +//108: No item need to be repaired. +108: No item need to be repaired. +//109: Player has been nuked! +109: Player has been nuked! +//110: Npc Enabled. +110: Npc Enabled. +//111: This NPC doesn't exist. +111: This NPC doesn't exist. +//112: Npc Disabled. +112: Npc Disabled. +//113: %d item(s) removed by a GM. +113: %d item(s) removed by a GM. +//114: %d item(s) removed from the player. +114: %d item(s) removed from the player. +//115: %d item(s) removed. Player had only %d on %d items. +115: %d item(s) removed. Player had only %d on %d items. +//116: Character does not have the item. +116: Character does not have the item. +//117: GM has send you in jails. +117: GM has send you in jails. +//118: Player warped in jails. +118: Player warped in jails. +//119: This player is not in jails. +119: This player is not in jails. +//120: GM has discharge you. +120: GM has discharge you. +//121: Player warped to Prontera. +121: Player warped to Prontera. +//122: Disguise applied. +122: Disguise applied. +//123: Monster/NPC name/id hasn't been found. +123: Monster/NPC name/id hasn't been found. +//124: Undisguise applied. +124: Undisguise applied. +//125: You're not disguised. +125: You're not disguised. +//126: You accept any wisp (no wisper is refused). +126: You accept any wisp (no wisper is refused). +//127: You accept any wisp, except thoses from %d player(s): +127: You accept any wisp, except thoses from %d player(s): +//128: You refuse all wisps (no specifical wisper is refused). +128: You refuse all wisps (no specifical wisper is refused). +//129: You refuse all wisps, AND refuse wisps from %d player(s): +129: You refuse all wisps, AND refuse wisps from %d player(s): +//130: '%s' accept any wisp (no wisper is refused). +130: '%s' accept any wisp (no wisper is refused). +//131: '%s' accept any wisp, except thoses from %d player(s): +131: '%s' accept any wisp, except thoses from %d player(s): +//132: '%s' refuse all wisps (no specifical wisper is refused). +132: '%s' refuse all wisps (no specifical wisper is refused). +//133: '%s' refuse all wisps, AND refuse wisps from %d player(s): +133: '%s' refuse all wisps, AND refuse wisps from %d player(s): +//134: '%s' already accepts all wispers. +134: '%s' already accepts all wispers. +//135: '%s' now accepts all wispers. +135: '%s' now accepts all wispers. +//136: A GM has authorised all wispers for you. +136: A GM has authorised all wispers for you. +//137: '%s' already blocks all wispers. +137: '%s' already blocks all wispers. +//138: '%s' blocks now all wispers. +138: '%s' blocks now all wispers. +//139: A GM has blocked all wispers for you. +139: A GM has blocked all wispers for you. +//140: Character's disguise applied. +140: Character's disguise applied. +//141: Character's undisguise applied. +141: Character's undisguise applied. +//142: Character is not disguised. +142: Character is not disguised. +//143: Give a monster name/id please. +143: Give a monster name/id please. +//144: Invalid actual email. If you have default e-mail, type a@a.com. +144: Invalid actual email. If you have default e-mail, type a@a.com. +//145: Invalid new email. Please enter a real e-mail. +145: Invalid new email. Please enter a real e-mail. +//146: New email must be a real e-mail. +146: New email must be a real e-mail. +//147: New email must be different of the actual e-mail. +147: New email must be different of the actual e-mail. +//148: Information sended to login-server via char-server. +148: Information sended to login-server via char-server. +//149: Impossible to increase the number/value. +149: Impossible to increase the number/value. +//150: No GM found. +150: No GM found. +//151: 1 GM found. +151: 1 GM found. +//152: %d GMs found. +152: %d GMs found. +//153: %s is Unknown Command. +153: %s is Unknown Command. +//154: %s failed. +154: %s failed. +//155: Impossible to change your job. +155: Impossible to change your job. +//156: HP or/and SP modified. +156: HP or/and SP modified. +//157: HP and SP are already with the good value. +157: HP and SP are already with the good value. +//158: Base level can't go any lower. +158: Base level can't go any lower. +//159: Job level can't go any lower. +159: Job level can't go any lower. +//160: PvP is already Off. +160: PvP is already Off. +//161: PvP is already On. +161: PvP is already On. +//162: GvG is already Off. +162: GvG is already Off. +//163: GvG is already On. +163: GvG is already On. +//164: Your memo point #%d doesn't exist. +164: Your memo point #%d doesn't exist. +//165: All monsters killed! +165: All monsters killed! +//166: No item has been refined! +166: No item has been refined! +//167: 1 item has been refined! +167: 1 item has been refined! +//168: %d items have been refined! +168: %d items have been refined! +//169: This item (%d: '%s') is not an equipment. +169: This item (%d: '%s') is not an equipment. +//170: This item is not an equipment. +170: This item is not an equipment. +//171: %d - void +171: %d - void +//172: You replace previous memo position %d - %s (%d,%d). +172: You replace previous memo position %d - %s (%d,%d). +//173: Note: you don't have the 'Warp' skill level to use it. +173: Note: you don't have the 'Warp' skill level to use it. +//174: Number of status points changed! +174: Number of status points changed! +//175: Number of skill points changed! +175: Number of skill points changed! +//176: Number of zenys changed! +176: Number of zenys changed! +//177: Impossible to decrease a stat. +177: Impossible to decrease a stat. +//178: Impossible to increase a stat. +178: Impossible to increase a stat. +//179: Guild level changed. +179: Guild level changed. +//180: The monter/egg name/id doesn't exist. +180: The monter/egg name/id doesn't exist. +//181: You already have a pet. +181: You already have a pet. +//182: Pet friendly value changed! +182: Pet friendly value changed! +//183: Pet friendly is already the good value. +183: Pet friendly is already the good value. +//184: Sorry, but you have no pet. +184: Sorry, but you have no pet. +//185: Pet hungry value changed! +185: Pet hungry value changed! +//186: Pet hungry is already the good value. +186: Pet hungry is already the good value. +//187: You can now rename your pet. +187: You can now rename your pet. +//188: You can already rename your pet. +188: You can already rename your pet. +//189: This player can now rename his/her pet. +189: This player can now rename his/her pet. +//190: This player can already rename his/her pet. +190: This player can already rename his/her pet. +//191: Sorry, but this player has no pet. +191: Sorry, but this player has no pet. +//192: Impossible to change the character's job. +192: Impossible to change the character's job. +//193: Character's base level can't go any lower. +193: Character's base level can't go any lower. +//194: Character's job level can't go any lower. +194: Character's job level can't go any lower. +//195: All players have been kicked! +195: All players have been kicked! +//196: You already have this quest skill. +196: You already have this quest skill. +//197: This skill number doesn't exist or isn't a quest skill. +197: This skill number doesn't exist or isn't a quest skill. +//198: This skill number doesn't exist. +198: This skill number doesn't exist. +//199: This player has learned the skill. +199: This player has learned the skill. +//200: This player already has this quest skill. +200: This player already has this quest skill. +//201: You don't have this quest skill. +201: You don't have this quest skill. +//202: This player has forgotten the skill. +202: This player has forgotten the skill. +//203: This player doesn't have this quest skill. +203: This player doesn't have this quest skill. +//204: WARNING: more than 1000 spiritballs can CRASH your server and/or client! +204: WARNING: more than 1000 spiritballs can CRASH your server and/or client! +//205: You already have this number of spiritballs. +205: You already have this number of spiritballs. +//206: '%s' skill points reseted! +206: '%s' skill points reseted! +//207: '%s' stats points reseted! +207: '%s' stats points reseted! +//208: '%s' skill and stats points reseted! +208: '%s' skill and stats points reseted! +//209: Character's number of skill points changed! +209: Character's number of skill points changed! +//210: Character's number of status points changed! +210: Character's number of status points changed! +//211: Character's number of zenys changed! +211: Character's number of zenys changed! +//212: Cannot mount a Peco while in disguise. +212: Cannot mount a Peco while in disguise. +//213: You can not mount a peco with your job. +213: You can not mount a peco with your job. +//214: Unmounted Peco. +214: Unmounted Peco. +//215: This player cannot mount a Peco while in disguise. +215: This player cannot mount a Peco while in disguise. +//216: Now, this player mounts a peco. +216: Now, this player mounts a peco. +//217: This player can not mount a peco with his/her job. +217: This player can not mount a peco with his/her job. +//218: Now, this player has not more peco. +218: Now, this player has not more peco. +//219: %d day +219: %d day +//220: %d days +220: %d days +//221: %s %d hour +221: %s %d hour +//222: %s %d hours +222: %s %d hours +//223: %s %d minute +223: %s %d minute +//224: %s %d minutes +224: %s %d minutes +//225: %s and %d second +225: %s and %d second +//226: %s and %d seconds +226: %s and %d seconds +//227: Cannot wear disguise while riding a Peco. +227: Cannot wear disguise while riding a Peco. +//228: Character cannot wear disguise while riding a Peco. +228: Character cannot wear disguise while riding a Peco. +//229: Your Effect Has Changed. +229: Your Effect Has Changed. +//230: Server time (normal time): %A, %B %d %Y %X. +230: Server time (normal time): %A, %B %d %Y %X. +//231: Game time: The game is in permanent daylight. +231: Game time: The game is in permanent daylight. +//232: Game time: The game is in permanent night. +232: Game time: The game is in permanent night. +//233: Game time: The game is actualy in night for %s. +233: Game time: The game is actualy in night for %s. +//234: Game time: After, the game will be in permanent daylight. +234: Game time: After, the game will be in permanent daylight. +//235: Game time: The game is actualy in daylight for %s. +235: Game time: The game is actualy in daylight for %s. +//236: Game time: After, the game will be in permanent night. +236: Game time: After, the game will be in permanent night. +//237: Game time: After, the game will be in night for %s. +237: Game time: After, the game will be in night for %s. +//238: Game time: A day cycle has a normal duration of %s. +238: Game time: A day cycle has a normal duration of %s. +//239: Game time: After, the game will be in daylight for %s. +239: Game time: After, the game will be in daylight for %s. +//240: %d monster(s) summoned! +240: %d monster(s) summoned! +//241: You be a killa... +241: You be a killa... +//242: You gonna be own3d... +242: You gonna be own3d... +//243: Map skills are off. +243: Map skills are off. +//244: Map skills are on. +244: Map skills are on. +//245: Muting is disabled. +245: Muting is disabled. + +// Messages of others (not for GM commands) +// ---------------------------------------- + +//500: Actually, it's the night... +500: Actually, it's the night... +//501: Your account time limit is: %d-%m-%Y %H:%M:%S. +501: Your account time limit is: %d-%m-%Y %H:%M:%S. +//502: The day has arrived! +502: The day has arrived! +//503: The night has fallen... +503: The night has fallen... +// 504-508: Chat validation. +//504: You cannot page yourself. +504: You cannot page yourself. +//505: Your message could not be sent. +505: Your message could not be sent. +//506: WARNING: You are about to be automatically banned for spam! +506: WARNING: You are about to be automatically banned for spam! +//507: WARNING: Please slow down, do not repeat, and do not SHOUT! +507: WARNING: Please slow down, do not repeat, and do not SHOUT! +//508: You have been banned for %s spamming. Please do not spam. +508: You have been banned for %s spamming. Please do not spam. diff --git a/conf/script_athena.conf b/conf/script_athena.conf new file mode 100644 index 00000000..21d4a6f4 --- /dev/null +++ b/conf/script_athena.conf @@ -0,0 +1,2 @@ +// When choosing those which it refines setting the letter which is indicated. (Those for word use other than Japanese?) +refine_posword: Head,Body,Left hand,Right hand,Robe,Shoes,Accessory 1,Accessory 2,Head 2,Head 3,Not Equipped diff --git a/conf/water.txt b/conf/water.txt new file mode 100644 index 00000000..71f98470 --- /dev/null +++ b/conf/water.txt @@ -0,0 +1,54 @@ +// 水の設定。 +// waterは水ありでall_waterは全て水だと判断するマップ。 + +mjolnir_12.gat mapflag water +mjolnir_02.gat mapflag water +glast_01.gat mapflag water +gef_fild04.gat mapflag water +prt_fild02.gat mapflag water +prt_fild01.gat mapflag water +prt_fild00.gat mapflag water +gef_fild00.gat mapflag water +gef_fild07.gat mapflag water +gef_fild13.gat mapflag water +gef_fild09.gat mapflag water +gef_fild01.gat mapflag water +prt_fild05.gat mapflag water +gef_fild03.gat mapflag water +gef_fild10.gat mapflag water +prt_fild10.gat mapflag water +pay_arche.gat mapflag water +moc_ruins.gat mapflag water +comodo.gat mapflag water +cmd_fild01.gat mapflag water +cmd_fild02.gat mapflag water +cmd_fild03.gat mapflag water +cmd_fild04.gat mapflag water +cmd_fild05.gat mapflag water +moc_fild11.gat mapflag water +ama_fild01.gat mapflag water + +iz_dun00.gat mapflag water +iz_dun01.gat mapflag water +iz_dun02.gat mapflag water +//iz_dun03.gat mapflag all_water +//iz_dun04.gat mapflag all_water +treasure01.gat mapflag water +treasure02.gat mapflag water +mjo_dun01.gat mapflag water +orcsdun02.gat mapflag water +pay_dun01.gat mapflag water +pay_dun02.gat mapflag water +pay_dun03.gat mapflag water +prt_sewb2.gat mapflag water +prt_sewb3.gat mapflag water +gl_prison1.gat mapflag water +alde_dun03.gat mapflag water +alde_dun04.gat mapflag water +beach_dun.gat mapflag water +beach_dun2.gat mapflag water +beach_dun3.gat mapflag water +tur_dun01.gat mapflag water +gld_dun02.gat mapflag water +gld_dun03.gat mapflag water +gld_dun04.gat mapflag water diff --git a/conf/water_height.txt b/conf/water_height.txt new file mode 100644 index 00000000..9a89e29c --- /dev/null +++ b/conf/water_height.txt @@ -0,0 +1,68 @@ +// 水場の高さを設定 +//water_height.txt@AthenaDB計画 2004/03/31 18:52:09 +0900 (JST) + +xmas.gat 3 +mjolnir_01.gat 0 +mjolnir_02.gat -19 +mjolnir_12.gat 15 +prt_fild00.gat 11 +prt_fild01.gat 25 +prt_fild02.gat 42 +prt_fild04.gat 14 +prt_fild05.gat 14 +prt_fild10.gat 40 +gef_fild00.gat 10 +gef_fild01.gat 14 +gef_fild03.gat 82 +gef_fild04.gat 14 +gef_fild07.gat 19 +gef_fild09.gat 11 +gef_fild10.gat 24 +moc_fild01.gat 26 +moc_fild11.gat 9 +iz_dun00.gat 5 +iz_dun01.gat 5 +iz_dun02.gat -58 +mjo_dun01.gat 7 +orcsdun02.gat 3 +pay_dun01.gat 8 +pay_dun02.gat 5 +pay_dun03.gat 10 +prt_sewb2.gat 5 +prt_sewb3.gat 5 +treasure01.gat -4 +treasure02.gat -1 +moc_ruins.gat 6 +pay_arche.gat 8 +glast_01.gat 8 +alde_dun03.gat 2 +alde_dun04.gat 0 +gl_prison1.gat 35 +gl_sew01.gat 56 +gl_sew02.gat 12 +gl_sew03.gat 15 +gl_sew04.gat 70 +comodo.gat 14 +cmd_fild01.gat 46 +cmd_fild02.gat 4 +cmd_fild03.gat 0 +cmd_fild04.gat 4 +cmd_fild05.gat 46 +beach_dun2.gat 6 +beach_dun3.gat 0 +beach_dun.gat 9 +gef_fild13.gat 19 +gld_dun02.gat 5 +gld_dun03.gat 14 +gld_dun04.gat 3 +aldeg_cas01.gat 40 +aldeg_cas02.gat 35 +aldeg_cas03.gat 16 +aldeg_cas04.gat 31 +aldeg_cas05.gat 25 +gefg_cas02.gat 8 +gefg_cas04.gat 15 +gefg_cas05.gat 5 +prtg_cas05.gat 13 +tur_dun01.gat -65 +ama_fild01.gat 5 |