the scripting thread

"eventually EUO will get to the point its (sic) unplayable" - Dudle

Moderator: EUO Moderators

the scripting thread

Postby eggmceye » Thu Aug 31, 2006 11:12 am

UPDATE Mar 2012

This thread has been moved into EUO Dev forum because while it's old and talks about euo2, eao, or a whole bunch of theoretical things, it is still the only place where euo's / moa's lua scripting facility is documented at all!


old post below
--------------------

The new engine (euo2, eao, apoc mod engine, whatever it's called) uses lua for expanding the engine functions.

The best thing about lua is that it's so small and has a simple syntax. The downside is that the documentation is poorly organised, tho there are a few good resources if you don't mind wading. I'd like to see one really nice one-page tute aimed at programmers who just want to get started. (the wikipedia page isn't bad for this)

Using Lua 5.03 with the C-style hex number notation and bitwise operators patch.

Lua links

lua on wikipedia (very simple intro)
programming in lua (not bad but hard to read online)
lua users wiki (has lots of info but I get lost :S)
** tute page
lua referance manual (very very dry)


Scripting and Eao

The basic principle is that the eao server will call certain scripted functions under certain circumstances, and that these functions will manipulate the players, mobs or environment in certain ways.

1) Script functions can be called on certain events (these function names are fixed):

mob_hits() : called when a mob performs a successful attack
hit_mob() : called when a mob is hit
mob_dies() : called when a mob dies
do_chest_trap() : called when a trapped chest is opened

2) scripts can be attached to certain triggers. The script function name is set in the txt field of the trigger. Specifically:
a) the step trigger: when stepped on by a player, the function specified in the text field is called
b) the switch trigger: when activated by a player (with the 'a' key), the function specified in the text field is called

3) scripts can be attached to spawners via the txt field of the spawner. The script is called when the spawner spawns a new mob. The script function name is set in the txt field of the spawner.

4) certain scripts perform functions that make the game unique from other games using the same engine, such as spawning treasure (these function names are fixed):

chest_loot() : called by chest spawners to put things in chests
mob_loot() : called when mob dies to work out drops
mob_select_spell() : called when mob decides to cast a spell: this selects the spell to cast
eat_food() : called when a player eats food
get_rand_cave_mobs() : helps decide what mobs to put in buried treasure caves
buried_treasure() : helps decide what goes in buried treasure chests
mob_loot() : loot dropping function


5) heatbeat function for monsters called every second - this function would be attached via the spawn script

6) questing functions:
6a) functions that are called when kill target is spawned (so that it's parameters can be set in a similar way to spawner scripts). The function name for modifying a quest_target is quest_target_xxx() where xxx is the 0-padded hex id of the quest
6b) a new scripted quest type - where the quest goal is checked in a script. Use this for making complex or non standard quests goals like "get to lvl 60 noob", or to have x ratskulls and y jars of slime in inventory, etc. The function name is quest_goal_xxx() where xxx is the 0-padded hex id of the quest
6c) a function can be optionally attached to any quest to check the pre-requisites for starting the quest (rather than just having an item or another quest token) - useful for checking min player level or skill level. The function name is quest_requirement_xxx() where xxx is the 0-padded hex id of the quest
6d) a function can be optionally attached to any quest to give extra or special rewards, such as stat bonus or skill bonus or teleport the player or activate a switch or whatever. The function name is quest_reward_xxx() where xxx is the 0-padded hex id of the quest

7) when a player uses an item with code XXX (where XXX is a 3 digit hex number) the function use_XXX() is called

8) when a player looks at an item (with the 'l' key) with code XXX (where XXX is a 3 digit hex number) the function look_XXX() is called

9) when a player activates at an item (with the 'a' key) with code XXX (where XXX is a 3 digit hex number) the function activate_XXX() is called

10) when a map is loaded with level number DDD (where DDD is a 3 digit number) the function load_map_DDD() is called

11) a misc function called every_minute(), which is called every 60 sec - good as a slow misc server heartbeat function

The script functions themselves call upon a large selection of exported functions, enums and global objects to interact with the server. These include stand alone functions, objects such as wl (stands for weapon list) which holds the item info database, and actual sentient, player & monster objects which may be manipulated to certain degrees.
Last edited by eggmceye on Sat Mar 31, 2007 2:19 pm, edited 5 times in total.
User avatar
eggmceye
hello
 
Posts: 9880
Joined: Mon Mar 11, 2002 3:55 pm
Location: Sydney, Australia

Postby eggmceye » Thu Aug 31, 2006 7:54 pm

exported function list as of 31 aug. These funcs are euo/eao server funcs in c++ that can be called by lua scripts to get info on or manipluate the environment.

Code: Select all
// extern global objects
extern monster_db_cls monsters;      // the db of monster info
extern item_data_cls wl;         // the db of item info
extern config_cls vars;     


// helper funcs written just for lua
void send_message(int id, string msg);
monster * spawn_near_id(int code, int id);
monster * spawn_at(int code, int x, int y, int z);
void set_health(int id, int hs, int t);      // could use sp:set_health instead but more lines of lua reqd
int  get_health(int id, int hs);         // could use sp:get_health instead
void simple_send_event(int id, int e1, int e2=0, int tx=-1, int ty=-1) ;
void update_fov(int id);
int  hurt(int id, int dmg, string msg);
int  heal(int id, int hp);
int  restore_mana(int id, int mana);
void map_set_item_code(int x, int y, int z, long code);
void reset_trigger(int x, int y, int z, int value=0);
void map_add_item(int x, int y, int z, long code, int qty);

player *      get_player_ptr(int id);
monster *     get_monster_ptr(int id);
svmap_class * get_map_ptr(int lvl);



// misc funcs

int   get_hour();
int   get_min() ;
bool  shops_open() ;
bool  is_midnight() ;
int   xdy(int x, int y);
float distance(int x1, int y1, int x2, int y2);
void  writelog2(char* msg);
void  server_msg(string msg, int colour=0, int map_level=-1);
void  send_event(int lev, int id, int x, int y, int typ, int subtype, int tx, int ty);
bool  same_party(int id1, int id2);
int   set_and_send_new_tile(int x, int y, int z, short int t);

sentient* get_sent_ptr(int id); // use with the sent class below


// player related
void make_blind(int id, int t);
void make_hallucinated(int id, int t);
void make_paralyzed(int id, int t);
void make_choking(int id, long itm=0); // time =-1
void make_sleeping(int id, int t);
void make_peering(int id); // time = -1
void disease_player(int id, bool no_sync=false);
void make_visible(int id);
void polymorph_player_into_werewolf(int id);
void send_death_vision(int id);

void sync_stats(int id);
void sync_health(int id);
void sync_arms(int id);
void sync_all(int id);
void send_party_info(int id);
void send_time(int id, bool random_time);

int  send_player_to_xy(int id, int x, int y, bool no_trig_check=false);
void res_player(int id, bool party_res=false);

int  give_xp(int id, int xp ,bool show_message=false);
void give_party_xp(int id, int xp);

// player inventories
int  get_player_item_qty(int id, long int itm);
void give_item(int id, long int itm, long int q=1, bool quiet=false);
long int remove_item(int id, long int itm, long int q=1, bool quiet=false);

// item related
bool  is_cursed(long int code);
bool  is_hidden(long int code);
bool  is_no_drop(long int code);
bool  is_in_bank(long int code);
bool  is_unidentified(long int code);

float get_item_wear(long int code);
int   get_base_code(long int code);
int   get_material(long int code);
int   get_tile_num(long int code);
int   get_to_mod(long int code);


// class declarations

// the long int c below is always the item code
class item_data_cls {


public:

  int is_wearable(long int c);

  const char *get_material_name(long int c);
  const char *get_short_material_name(long int c);
  const char *get_mag_prop(long int c);
  const char *get_short_mag_prop(long int c);

  int get_no_hands(long int c);
  int is_legit(long int c);

  int get_no_dice(long int c);  // as in xdy dmg, returns the x
  int get_no_sides(long int c); // as in xdy dmg, returns the y
 
  int get_price(long int c);
  int get_buy_price(long int c);
  int get_sell_price(long int c);
  int get_light(long int c);
  int get_min_id_skill(long int c);

  float get_weight(long int c);
  float get_speed(long int c);
  float get_avg_wep_speed();
 
  weapontypes get_weapon_type(long int c);
  weapon_dmg_codes get_weapon_damage_type(long int c);
  const char* get_wep_dmg_str(long int c);

  float get_ac(long int c);

  const char *get_name(long int c);
  const char *get_short_name(long int c);
  string get_full_name(long int c, bool capitaliseFirstLetter=false);
  string get_magic_prop(int mp, int mod);
  string get_scroll_name(long int c);
  string make_tile_name(long int c);
  string get_prefix(long int c);

  char get_type(long int c);
  char get_merch(long int c);
  armour_grades get_grade(long int c);
  string get_grade_name(long int c);
  bool is_unarmoured(long int c);

  bool is_named(long int c);

  bool is_weapon(long int c);
  bool is_shield(long int c);
  bool is_torso(long int c);
  bool is_hat(long int c);
  bool is_boots(long int c);
  bool is_gloves(long int c);
  bool is_ring(long int c);
  bool is_amulet(long int c);
  bool is_trousers(long int c);

  bool is_ranged(long int c);
 
  bool is_jewelry(long int c);
  bool is_armour(long int c);

  bool is_artifact(long int c);
  bool is_enchanted(long int c);
  bool is_food(long int c);
  bool is_metal_food(long int c);
  bool is_stackable(long int c);
  bool is_gathering_tool(long int c);

  bool is_fighter_class(long int c);
  bool is_rogue_class(long int c);

  long int get_rand_weapon_armour(int quality=0xf); // max 15 (0xf)
  long int get_rand_jewellry();

  long int get_rand_item_by_merchant(char merchType);
  long int get_rand_artifact();
 
  long int random_enchant(int itemBaseCode, int quality); // q 0-16
  long int random_material (int itemBaseCode);            // paints an item in a material
  const char *get_wep_skill_name(long int c);

  skills_type get_weapon_skill(long int c);
  skills_type get_armour_skill(long int c);

  bool get_effect(long int c, MAGPROPS fx);
  bool has_effect(long int c, MAGPROPS mp, int mv);

  long  get_parent_code(long int c);
  int   get_rand_spell_off_item(long int c);
  int   get_nutrition(long int c);
  char  get_diet_type(long int c);
  int   convert_ench_spell(int spellNr);
  long  get_ammo_type(long int c);
  float get_material_dmg_mult(long int c, bool isUndead);
  char  get_usability(long int c);

  bool check_class(long int c, int cls);
};


class monster_db_cls {
public:
   
   bool is_aquatic(int code);
   bool is_lycan(int code);
   bool is_vampyric(int code);
   bool can_fly(int code);
   bool is_mountainwalk(int code);
   bool spreads_disease(int code) ;
   bool is_poisonous(int code);

   char get_inv_for_id(int id);
   MONSTER_FAMILIES get_cls_by_code(int code);
   int get_summon_slots_by_code(int code);
   int get_range_by_code(int code);

   unsigned long int get_treasure(int code);
   long int get_item(int code, bool isBoss);

   long int get_fav_food(int code) ;
   diet_type get_diet(int code) ;
   int get_tamability(int code) ;
   
   string get_name(int code, bool appendArticle=true);
   
   alignment_type get_align_from_id(int id);
   int get_rand_code_for_cls(int);

   int is_adj_to(monster *, sentient *);        // mon_ptr, sent*
   // int mov_dir(monster *, mondir, svmap_class *);   // mv in a dir
   
   string get_name_by_id(int id);
   int get_exp_by_id(int id);
   
   int do_evolution(int code); // may return code or class, doesn't actually evolve the mob!
   int get_soul_shard(monster *);

   monster * get_by_id(int id);
   monster * get_by_xyz(int x, int y, int z);

};

class sentient {
   
public:


   tolua_readonly string name;
   tolua_readonly short hp;
   tolua_readonly short code;
   tolua_readonly short lvl;
   tolua_readonly short mana;
   tolua_readonly int   id;
   tolua_readonly short speed; 
   tolua_readonly short x, y;
   tolua_readonly short map_level;
   tolua_readonly bool  undead;
   tolua_readonly short hunger;
   tolua_readonly long  xp;
   tolua_readonly int   target_id;

     
   // FUNCTIONS
   
   int can_see(int x, int y, int bonusRange=0);
   virtual int get_health(health_nums hn);
   void set_health(health_nums hn, int t);
   void dec_health(health_nums hn);
   void reset_health();
   virtual int get_sight();
   virtual bool is_dm();
   virtual int get_dex();
   virtual int get_str();
   virtual int get_wis();
   virtual int get_intel();
   virtual int get_magic_resistance();
   virtual alignment_type get_align();
   
   virtual int get_hp_max();
   virtual int get_mana_max();
   virtual int get_magic_modifier(MAGPROPS mp);
   virtual bool is_unarmed();
   virtual bool is_lagged();
   
   virtual float get_ac();
   virtual int get_dmg_dice();
   virtual int get_dmg_sides();
   virtual int get_thaco();

   virtual bool can_block();
   virtual bool can_dodge();
   
   float get_float_str();
   float get_float_dex();
   float get_float_intel();
   float get_float_wis();
   
   int learn_spell(string);
   bool has_spell(string spellName); // short spellname

   virtual bool is_flying();
   virtual bool is_vampyric();
   virtual bool is_lycan();

   bool is_visible();

   void digest();
   bool is_full();
   void eat_meal(int nutrition);

   void heal_wounds();
};

class player:public sentient {
   
public:

   tolua_readonly char  gender;                  // cosmetic
   tolua_readonly int   age;
   tolua_readonly float karma;
   tolua_readonly short race;
   tolua_readonly short cls;
     
   tolua_readonly long int weapon;
   tolua_readonly long int armour;
   tolua_readonly long int shield;
   tolua_readonly long int boots;
   tolua_readonly long int gloves;
   tolua_readonly long int hat;
   tolua_readonly long int trousers;
   tolua_readonly long int ring1;
   tolua_readonly long int ring2;
   tolua_readonly long int amulet;
   
   tolua_readonly int  remort_level;
   tolua_readonly int  bind_level;

   tolua_readonly int  pet_id;

   tolua_readonly string ip;
   tolua_readonly string clan;
   tolua_readonly string account_name;

   tolua_readonly int  move_timer;

   // set these at own risk - be sure to do a sync_heath afterwards!
   int ac_bonus;                 // ac modifier due to magic
   int dmg_bonus;
   int thaco_bonus;
   int str_bonus;
   int dex_bonus;
   int intel_bonus;
   int wis_bonus;
   int sight_bonus;
   int health_bonus;
   bool lycanthropy_immunity;   // script a way  give lycan immunity (eg in use silver pot script)
         
   bool is_dm();
   int get_sight();
   int check_mag_prop (int mp);
   int get_magic_modifier (MAGPROPS mp);
   int get_unscaled_str();      // these return ints of the stats + the bonus
   int get_unscaled_dex();
   int get_unscaled_intel();
   int get_unscaled_wis();
   int get_str();               // these return scaled ints of the stats + the bonus
   int get_dex();
   int get_intel();
   int get_wis();
   int get_magic_resistance();
   int get_str_bonus(); // returns an int of the bonus
   int get_dex_bonus();
   int get_intel_bonus();
   int get_wis_bonus();
   int get_thaco();
   float get_ac();
   int get_dmg_dice();
   int get_dmg_sides();
   int get_hp_max();
   int get_mana_max();
   void res();

   float get_total_skill_points();
   float get_armour_weight();
   float get_stealth_delay();
   void  bump_stats(float str, float dex, float intel, float wis);

   float get_skill(int sk);
   float get_raw_skill(int sk);
   void  set_skill(int sk, float val);

   bool can_block();
   bool can_dodge();
   bool bump_rage(float bump=1.0f);
   bool is_lagged();
   int  get_carry_str();
   bool is_encumbered(float load);
   
   bool  can_ready(long int c, slots slot);
   int   check_requirement(long int c);
   int   req_level_skill(int mp, int v);
   float get_req_ready_str(long int c, slots slot);
   float get_scaled_ac_of_item(long int c);

   bool is_unarmed();
   bool is_unarmoured();
   int get_critical_bonus(bool quiv_palm);

   alignment_type get_align();
   
   int get_delay();
   int get_weapon_delay();
   // void mark();
   // void recall(int &, int &, int &);
   // void make_title(string &, string &);
   float stat_damage_multiplier();

   float get_class_points(class_type cls);
   float get_total_class_points();

   string mk_display_name();
   bool xray_vis();
   void toggle_see_all();

   bool can_pvp();
   void set_pvp();

   void extinguish_torch();
   bool set_torch(int t);
   int get_light();
   int get_torch();
   
   int get_health(health_nums hn);

   int get_draw_code();
   int get_num_spells();

   bool can_dual_wield();
};

class monster:public sentient {
   
 
public:

   tolua_readonly short evo_lvl;
   
   tolua_readonly float  morale;   // percentage of health at which the mob will flee
   tolua_readonly unsigned long int treasure;
   tolua_readonly short  magic_resistance;
   
   tolua_readonly string owner_name;   
   
   tolua_readonly montype typ;
   tolua_readonly short   startx, starty;
   tolua_readonly short   wander_radius; // -1 fixed, 0, anywhere, r for whatever (same as spawn area)
   
   tolua_readonly bool boss;
   tolua_readonly bool named;
   tolua_readonly bool quest_target;
   tolua_readonly bool quest_npc;
   tolua_readonly bool merch_sleeping;
   tolua_readonly bool clone;
   tolua_readonly bool pet;
   tolua_readonly bool crim_merch;
   tolua_readonly bool container;
   tolua_readonly bool tamable;


   tolua_readonly pet_states pet_state;
   tolua_readonly int bond_t, loyalty;

   // set at own risk!
   monactions action;
   int    owner_id;
   short time_alive;
   int xp;
   string talk_line;
   bool flying;
   bool aquatic;
   bool immobile;

   // member funcs
     
   int get_dmg_dice();
   int get_dmg_sides();
   int get_thaco();

   int  mk_boss();
   void set_name(string n);
   void set_sight(int s);
   void set_dmg_dice(int x);
   void set_dmg_sides(int y);
   void set_thaco(int t);
   int  get_magic_resistance();
   
   int  get_hp_max();
   int  get_mana_max();
   void set_hp_max(short);
   void set_mana_max(short);

   void set_align(alignment_type a);
   alignment_type get_align();
   
   
   bool has_custom_spells();
   int  get_rand_spell();
     
   bool is_flying();
   bool magic_using();
   bool is_lycan();
   bool is_vampyric();

   void unset_pet();
   void level_up(); // doesn't increase level, just stats!
   void decrease_loyalty();

   void add_waypoint(int x, int y);
   void clear_waypoints();
   bool has_waypoints();
   euo_POSITION get_next_waypoint();

   void set_heartbeat_function(string s);
};

class map_obj {
public:
  int get_level();
  int tile_is_opaque(int t);

  bool is_wet(int x, int y);
  bool will_drown(int x, int y);

  int is_mountain(int x, int y);
  int is_forest(int x, int y);
  int is_lava(int x, int y);
  int is_deep_water(int x, int y) ;
  int get_vis();
  MAPTYPE get_type();
  bool can_see(int x1, int y1, int x2, int y2, int range, bool seethruforest=false);
  bool is_chokepoint(int x, int y);
  int get_max_x();
  int get_max_y();
  int get_tile(int x, int y);
};

class svmap_class:public map_obj {

public:

  bool no_pvp_allowed();
  bool is_arena();
  bool is_ctf();
  bool is_betting_ring();
  bool force_respawn_on_this_level();
  bool is_bindable();
  bool no_blink_allowed();
  bool no_mark_allowed();
  bool is_sunny();

  int not_blocked(int x, int y, bool aquatic=false, bool flying=false, bool mwalk=false);

  int destroy_pile(int x, int y);
  int get_item_qty(int x, int y);
  long int get_item_code(int x, int y);
  void set_item_code(int x, int y, long c);
  string get_item_owner(int x, int y);

  monster * get_mon_ptr(int x, int y);

};

class config_cls {

public:

  string get(string k);
  int get_int(string k);
  int set(string k, string v);
  int set(string k, int v);
  void inc(string k, int v=1);
  void dec(string k, int v=1);
};


Last edited by eggmceye on Sun Sep 03, 2006 12:30 pm, edited 1 time in total.
User avatar
eggmceye
hello
 
Posts: 9880
Joined: Mon Mar 11, 2002 3:55 pm
Location: Sydney, Australia

Postby eggmceye » Thu Aug 31, 2006 7:56 pm

placeholder
User avatar
eggmceye
hello
 
Posts: 9880
Joined: Mon Mar 11, 2002 3:55 pm
Location: Sydney, Australia

Postby eggmceye » Thu Aug 31, 2006 8:02 pm

example scripts

mob_dies()
Code: Select all
function mob_dies(mob_id, killer_id)

   m=get_monster_ptr(mob_id);
   mob_code=m.code;   
   
   -- gremlin
   if mob_code==0x202 then
   
      send_message(killer_id, string.format("The gremlin (code %x) shits green shit all over you (id %d)!",mob_code,killer_id) )
      
   -- slime
   elseif mob_code==0x21a then
   
      if math.random(100)<30 then
         spawn_near_id(mob_code, killer_id)
         spawn_near_id(mob_code, killer_id)
         send_message(killer_id,"The slime splits in two!")
      end
      
   end
   
   --xp=monsters:get_exp_by_id(mob_id)
   --print("boss="..tostring(m.boss)..", xp="..xp)
end


mob_hits()
Code: Select all
function mob_hits(mob_id, target_id)

   m=get_monster_ptr(mob_id);
   mob_code=m.code;
   
   -- rat
   if (mob_code==0x211 or mob_code==0x21b) and is_player(target_id) then
   
      send_message(target_id, "The rat gives you AIDS and u go blind!" )
      -- set_health(target_id,HN_BLIND,3) -- 2==blind
      make_blind(target_id,3)
   

   elseif mob_code==0x202 then -- gremlin stealing gold

      if math.random(100)<50>0 then
            simple_send_event(target_id, EVENT_STEAL)
            send_message(target_id, string.format("A gremlin stole %d gold!", qty) )
         end
      end
   end
      
end


eat_food()
Code: Select all
function eat_food(id, itm, bcode)



   if(bcode==0x4fb) then
   
      set_health(id, HN_BAD_BREATH,10)
      send_message(id, "The boiled egg gives you bad breath!")
         
   elseif bcode==0x4fa and get_health(id, HN_BLIND)~=0 then
   
      set_health(id, HN_BLIND, 0)
      send_message(id, "You can see again!")
      
   end
   
end


look_111 (look at fountain)
Code: Select all
function look_111   (id, itm, bcode, x, y, z) -- fountain


   -- simplified fountain
   -- empties, and heals a little
   -- small chance of summoning a water demon or snakes
   
   if(math.random(10)==1 or is_cursed(itm)) then
   
      -- snakes
      for i=1,7 do
         spawn_near_id(0x210,id)
      end
      -- doesn't have nethack message variation when blind, halluc
      send_message(id,"An endless stream of snakes pour forth!")
      
   elseif(math.random(20)==1) then
   
      -- water demon
      m=spawn_near_id(0x241,id)
      if(m~=nil) then
         send_message(id,"You summon a water demon!")
         if(math.random(3)==1) then
            m:set_align(ALIGN_GOOD)
            m.time_alive=60           
            m.owner_id=id   
            send_message(id,"He seems relatively pleased to see you!");
         end
      else
         -- this is very unlikely - the spawn failed
         send_message(id,"Water squirts in your eye!");
      end
      
   else
       hp,hpmax,mana,manamax = get_hp_and_mana(id)
      h=heal(id,math.random(20,30)*hpmax/100)
      if(h==0) then
         send_message(id,"The tepid water is tasteless!")
      else
         send_message(id, "Refreshing!")
      end
   end
   map_set_item_code(x,y,z,0x133) -- makes the fountain dry
   update_fov(id)
end


a script that spawns a wizard in nord that wanders around randomly and where he plagued by bats

illustrates load_map_xxx() & heartbeat

Code: Select all
function load_map_033(lvl)

   nordWizard()

end

function nordWizard()

   m=spawn_at(0x293,15,15,33)
   
   m:set_name('Estorrath')
   m:set_heartbeat_function('wizHeartbeat')
   m:learn_spell("zap")
   m:set_mana_max(100);
   m:set_hp_max(1000);
   m.talk_line="Hello stranger!";
end

function wizHeartbeat(m)

   wp=m:get_next_waypoint()
   if(wp.x==m.x and wp.y==m.y) then
   
      m:clear_waypoints()
      map=get_map_ptr(m.map_level)
      x=0
      y=0
      repeat
        x=math.random(16,28)
       y=math.random(19,36)
      until  map:not_blocked(x,y)
      
      m:add_waypoint(x, y)
      
   end
   
   if(math.random(60)==1 and m.target_id<0) then
      
      -- spawn random bats to zap
      for i=1,5 do
         spawn_near_id(0x213,m.id)
      end
   end
   m:set_hp_max(1000); -- keeps him at full health
end


function for using a peergem (item code 446)

Code: Select all
function use_446 (id,tgt_id,alt,itm,bcode,x,y,z)
   if is_cursed(itm) then
      send_message(id,"Death vision!")
      hurt(id,xdy(4,4),"a cursed peergem")
   else
      make_peering(id)
   end
   remove_item(id, itm, 1, true) -- no item removed msg
end


this script spawns a guard in nord called Stirling and gives him a simple patrol route around town

Code: Select all
function nordGuard()

   m=spawn_at(0x290,22,28,33)
   m:set_name('Stirling')
   m:add_waypoint(27,36)
   m:add_waypoint(27,20)
   m:add_waypoint(17,20)
   m:add_waypoint(17,36)
      
end


edit: removed all refs to unhex and replaced with C style 0x hex humbers
Last edited by eggmceye on Sun Sep 10, 2006 7:11 pm, edited 2 times in total.
User avatar
eggmceye
hello
 
Posts: 9880
Joined: Mon Mar 11, 2002 3:55 pm
Location: Sydney, Australia

Postby Ulric » Fri Sep 01, 2006 1:18 am

Great work Egg. I did a quick scan of the methods to see if it is possible to change a tile when a char steps on it. I would like to put some puzzles in to the maps. For example you enter a door way and there is a pattern puzzle to solve. So when they step on a tile turns either red or green. Green meaning that it is correct or red meaning that it is wrong. If they step on one that turns red they are tp back to the start with all the green tiles turning back to normal. Is this type of thing possible?
Ulric
buying vamp LS of any kind +5
 
Posts: 95
Joined: Wed May 31, 2006 7:17 am

Postby eggmceye » Fri Sep 01, 2006 8:42 am

ah hah, there is a func (not exported) that changes tiles, the one that is called when you use a tile scroll to change the floor of your house, or when I do a /settile to terraform ingame.

only thing is that it permanently changes the tiles. so make sure there is a resetting trigger somewhere (i made it the first step before the puzzle tiles)

edit: I'm doing a little test map now

edit: here's the scripts, and screenshots attached

the green tiles have step triggers that call func lvl001green, and the wrong tiles have step triggers that call func lvl001wrong. the final green square (at the top) calls lvl001final (which itself calls lvl001green to make it green), and the square between the bottom ladder and the first green tile calls lvl001reset to reset the puzzle.

Code: Select all
function lvl001reset(id, px, py, z)

   for x=6,8 do
      for y=4,10 do
         set_and_send_new_tile(x,y,z,95) -- 95 is the red tile
      end
   end
   reset_trigger(7,3,z,1)

end

function lvl001wrong(id, x, y, z)

   -- reset all tiles
   -- lvl001reset(id,x,y,z)
   
   -- send plyr back to start
   send_player_to_xy(id,7,12,true) -- don't check trigs (may cause loop)
end

function lvl001green(id, x, y, z)

   set_and_send_new_tile(x,y,z,222) -- 222 is the green tile
end

function lvl001final(id, x, y, z)

   lvl001green(id,x,y,z)
   reset_trigger(7,3,z,0) -- disables the barrier
   
end

You do not have the required permissions to view the files attached to this post.
User avatar
eggmceye
hello
 
Posts: 9880
Joined: Mon Mar 11, 2002 3:55 pm
Location: Sydney, Australia

Postby Catherine » Sat Sep 02, 2006 1:16 am

Ka-wow... I've dreamed of that function since opening up MapEd! (Ultima5 did have it, even if it was only [if square hit > new tile] :smoke:


Definately going to look at LUA.

Couple of questions:

1) Attaching the script to a trigger means they'll be a /EUA/scripts folder? If so, would there be generic templates in the MapEd for the simple ones? e.g. If [monster X] dies then [spawn X] etc

2) In the example above, does each tile have a separate script attached? i.e. each red tile has the script.txt level..wrong attached to the trigger and a green one level..green? If so that makes it a lot easier, although it means you have to write the scripts first, then keep track of them to insert the correct one into MapEd. This will lead to a lot more potential for map breaking errors, and required testing - not something MapEd allows you to do. Given the current status of MapEd, having it able to run in a window would make switching between the two (scripts and maped) a lot easier. Suggestion (not sure how workable) - give *trusted* map creators a psuedo- server they can upload maps to and test them on single-player with a DM like char, to be able to work through and bug test a map as its being made? Otherwise, its going to be a lot of work for you to play-test each one.

3) Thinking back to when MapEd first appeared, when you had to hand-type in a hex code to the spawner - the ScriptEd will probably need documentation listing the hex code for each tile, unless you can get it to display the hex for each (which I think it does for the monsters still, at least). Which brings us back to 2) first part.

4) I always got confused in the quest maker to which hex tiles were free to use for making quest tokens / items, partly why I didn't get more into it. Would it be possible to have a "unique hex creator" that generated labels on such items, in contact with the server to prevent conflicts? This would make quest making via the new scripts a lot easier - e.g. Kill X then spawn [quest token > create unique hex code, auto-insert].

5) Looking at the Mob hits script, that looks great - its possible to create unique ones for the "Diablo" bosses. From your fire breathing cows example, it looks like every spawner can be customised? Will having a 100x100 map with 50 unique scripted spawners totally bugger the server up? Also, in MapEd it'd be a *good* idea to make a spawner that has a script attached to it have a changed colour, so that when creating maps you can quickly differentiate between vanilla spawns and altered ones, for testing & fixing. e.g. altered spawners change to red txt on MapEd.

6) Given the flexibility of the LUA thingies, is this going to make parts of the old features redundant, or conflict? Just a thought - if someone puts a tele feature with a script to change a tile on it, and you 'port into a blocker tile, you could easily get the player stuck etc. (Silly example, but I hope the concept makes sense).

7) Is there a limit on number of scripts / feature? (Apart from the obvious maxim, don't go insane with the scripts)


These questions are probably showing my unfamiliarity with coding, so feel free to just say "doesn't apply". However, very excited at the possibilities! :)
Last edited by Catherine on Sat Sep 02, 2006 1:27 am, edited 1 time in total.
User avatar
Catherine
English correct bastard.
 
Posts: 1250
Joined: Mon Sep 08, 2003 2:40 am

Postby LaughingCoyote » Sat Sep 02, 2006 1:17 am

Not too hard... although I only just scraped through passing a first year subject introducing java.

:oops:
User avatar
LaughingCoyote
Girls only want boyfriends who have great skills.
 
Posts: 787
Joined: Fri Jan 02, 2004 10:30 pm

Postby Ulric » Sat Sep 02, 2006 4:23 am

What about the time spent on a tile? For example if I wanted something to happen if someone stayed on a tile for 5 seconds it would spawn a mob. This could give a random effect to a dungeon and give the effect of mobs patrolling a location :) . Something else that would be fun for those annoying high level chars that run through dungeons as fast as possible would be if they spent to little time on a tile it could spawn a bat in front of them every step they take too quickly or maybe a bally every step :). This could be thought of as running down a hallway and every mob in the dungeon hearing you.

LC if you need any help with Java PM me. I have a little experience with it :)
Ulric
buying vamp LS of any kind +5
 
Posts: 95
Joined: Wed May 31, 2006 7:17 am

Postby eggmceye » Sat Sep 02, 2006 12:58 pm

cat:

1) yes there is a scripts folder, wasn't planning on having maped used as a script editor (you can use notepad2, or luaedit which both have syntax highliting). as for templates, i guess there would be examples floatng around.

2) there's only 1 script, and 2 main funcs that are bound to tiles (lvl2wrong and lvl2green).

re development/testing server: yeh i think it will definitely be time to give out dev servers, there is no way to test any of this shit w/o one

3) maped now displays the codes for tiles, that's where i got them from for this script

4) yeh i found that to be a prob with kyb who was into making new items: he'd have to ask me to reserve say 10 item numbers for him to use in quests he was making - i can't see a way around it

5) good idea with the colour indicator. i don't know how much load the scripting is going to put on the server, but would you really have 50 scripted spawners in one map? (i guess you could...) - i dunno, i'm not worried about it. worst case scenario: optimise server code and/or upgrade server hardware ;)

6) yeh euo2 is a huge retro fit and there is huge room for redundancy, but i wouldn't remommend anyone script anything that could be achieved by other (even if old fashioned, since that is probably more efficient) means (eg make ALL cows firebreathing with many spawners scripts rather than just editing monsters.txt to give cows the vf spell). scripting is for enhancing the server, not for reinventing the wheel. also when you're developing the maps now, you'll have to test the scripted bits and try and think of all the possibilites of why it could go wrong, which is very much easier said than done

7) there's no limits

ulric:
depends if you just meant one tile in a whole map that a player stayed put on (like a trap), or, just seeing if the player is not moving within the whole map (or a section of it).

either way, both conceptually make me think of a timer. the only timer atm is the heatbeat of a mob (which is a func that can bound to a mob that is called every 1 second). so you could i guess add a hidden dungeonmaster in a map who keeps track of player movements. actually, there is a player variable plyr[].move_timer: which is the number of seconds the player hasn't moved. So the DMNPC could just measure the move_timers of all players and if it catches any over X seconds, spawn mobs around them. This could be tested for one square, a whole map, or just an area. I'll make move_timer a readonly var available to lua.

The idea of the npc-dm i came up when i was making a scripted minigame (which I'll post below). The mini game needed a referee and controller, so I spawned an NPC and gave his heartbeat function all the ai that runs the minigame. You could use this plot-device (for want of a better word) to add all sorts of weird AI to maps. As long as the npc can't be killed (make him good aligned).
User avatar
eggmceye
hello
 
Posts: 9880
Joined: Mon Mar 11, 2002 3:55 pm
Location: Sydney, Australia

Postby eggmceye » Sat Sep 02, 2006 1:22 pm

cow hole - a scripted minigame

the best way to test and improve and expand the scripting interface is to actualy implement something. So I wanted to re-create a nintendo game and watch within a euo map. I picked manhole, as it's one of my favs + it's doesn't really require collision detection (which say donkey kong might).

the concept of manhole is a bit like lemmings: random guys spawn and you have to stop them falling into the sewer when they step on manholes. there are 4 manholes but only one sewer lid which you hold and travel between the 4 holes to keep the random guys out. as your score gets higher, more guys spawn and it gets faster and harder, etc.

ok so cow hole is the same thing. cows spawn but you have to stop them stepping in the lava which kills them. you magically provide a bride by stepping in the 4 squares in the middle of the map. the topleft square provids a bridge in the topleft lavahole, etc . see pic.

cowmaster henry does most of the AI work: his heartbeat spawns cows, counts dead cows, etc. a spawned cow gets a single way point which it walks to, and if it gets there, you get a point. if it dies, you lose a life. three cow deaths and the game is over.

to start the game you pull the lever near the ladder. this resets the map, spawns henry. when the game is over, henry goes home. you can of course pull the lever again to play again.

this demonstrates npc-dm ai and the ever expanding awesomeness of the eao engine. it's not so awesome due to me: but lua being so powerful and thanks to tolua++ (a utility that exports euo server funcs to lua).

Code: Select all
require("funcs")

-- global vars
-- declared globally so they are persistant
-- must be unique within lua so are allprefixed with gCH
-- (g for global, CH for cow hole)
gCHscore=0
gCHdeaths=0
gCHcows=0
gCHgameover=false

function cowHoleReset(id,x,y,z)

   cowHoleClearBridges(z)
   cowHoleSpawnController(z)
   gCHscore=0
   gCHdeaths=0
   gCHcows=0
   gCHgameover=false
   
   server_msg("Game starting!",0,z)
   
   -- get the item code of the switch
   -- then toggle it
   map=get_map_ptr(z)
   c=map:get_item_code(x,y)

   if(c==BCODE_SWITCH_ON) then
    c=BCODE_SWITCH_OFF
   else
    c=BCODE_SWITCH_ON
   end
   map:set_item_code(x,y,c)

   update_fov(id)
end

function cowHoleStep(id,x,y,z)

   cowHoleClearBridges(z)
   
   if(x==7 and y==6) then
      set_and_send_new_tile(6,4,z,61)
   elseif(x==8 and y==6) then
      set_and_send_new_tile(9,4,z,61)
   elseif(x==7 and y==7) then
      set_and_send_new_tile(6,9,z,61)
   elseif(x==8 and y==7) then
      set_and_send_new_tile(9,9,z,61)
   end
   
end

function cowHoleClearBridges(z)

   set_and_send_new_tile(6,4,z,220)
   set_and_send_new_tile(9,4,z,220)
   set_and_send_new_tile(6,9,z,220)
   set_and_send_new_tile(9,9,z,220)
end

function cowHoleSpawnController(z)

   -- see if another controller is already there!
   map=get_map_ptr(z)
   haveController=false;
   for x=4,5 do
      for y=6,7 do
      
         c=map:get_mon_ptr(x,y)
         if(c~=nil and c.code==0x293) then haveController=true; end
      end
   end   

   if(not haveController) then
      m=spawn_at(0x293,5,6,z)
      m:set_heartbeat_function("cowHoleControllerHeartbeat")
      m:learn_spell("og2")
      m:set_mana_max(100);
      m:set_hp_max(1000);
      m:set_name("Cow-master Henry!")
   end
end


function cowHoleControllerHeartbeat(me)

   z=me.map_level
   -- see if there are 3 deaths! if so, kill all cows and kill me
   map=get_map_ptr(z)

   if(gCHdeaths>=3 and not gCHgameover) then
   
      server_msg("GAME OVER!",0,z) -- send only to this level
      server_msg("Final score: "..gCHscore,0,z) -- send only to this level
      
      -- make all cows evil so controller will og them
      -- also kill off controller
      for x=0,map:get_max_x()-1 do
         for y=0,map:get_max_y()-1 do
         
            cow=map:get_mon_ptr(x,y)
            if(cow~=nil and cow.code==0x297) then
               cow:set_align(ALIGN_EVIL)
               cow.time_alive=4
            elseif(cow~=nil) then
               cow.time_alive=5 -- set's controllers suicide time
            end
         end
      end
      
      -- set game over
      gCHgameover=true      
      
   elseif(not gCHgameover) then
   
      -- game is in progress
      
      -- count onscreen cows
      cows=0
      for x=0,map:get_max_x()-1 do
         for y=0,map:get_max_y()-1 do
         
            cow=map:get_mon_ptr(x,y)
            if(cow~=nil and cow.code==0x297) then
               cows=cows+1
            end
         end
      end      
      
      r=30; -- make this smaller as the score gets higher

      if(gCHscore>=50) then r=5
      elseif(gCHscore>=40) then r=10
      elseif(gCHscore>=30) then r=15
      elseif(gCHscore>=20) then r=20
      elseif(gCHscore>=10) then r=25
      end
      
      if(cows==0 or math.random(r)==1) then
      
         r=math.random(2)
         
         if    (r==1) then
         
            cow=spawn_at(0x297,3,4,z)
            if(cow~=nil) then cow:add_waypoint(13,4) end   
            
         elseif(r==2) then
         
            cow=spawn_at(0x297,12,9,z)
            if(cow~=nil) then cow:add_waypoint(2,9) end
            
         end
         
         if(cow~=nil) then
         
            cow:set_heartbeat_function("cowHoleCowHeartbeat")
            cow.flying=true -- this is a cheese so that they will walk on the lava!
            gCHcows=gCHcows+1 -- cows spawned total
            cow:set_name("Cow #"..gCHcows)
            
         end
      end
   end
end

function cowHoleCowHeartbeat(me)

   -- check to see if reached destination, if so add to score
   if(me.x==13 and me.y==4 or me.x==2 and me.y==4 or me.x==13 and me.y==9 or me.x==2 and me.y==9) then
      me.time_alive=0
      gCHscore=gCHscore+1
      map=get_map_ptr(me.map_level)
      server_msg("A cow survived! Cows saved: "..gCHscore,0,me.map_level)
   end
   
   -- check to see if on lava, if so die
   map=get_map_ptr(me.map_level)
   if(map:get_tile(me.x,me.y)==220 and me:get_align()~=ALIGN_EVIL) then -- dont do for evil cows
      me.time_alive=0
      gCHdeaths=gCHdeaths+1
      simple_send_event(me.id,EVENT_HIT,0)
      server_msg("A cow died! Cow deaths: "..gCHdeaths,0,me.map_level)
   end
end



edit: updated, removed all unhex() and replaced with c-style hex numbers
You do not have the required permissions to view the files attached to this post.
Last edited by eggmceye on Sat Sep 09, 2006 9:39 am, edited 1 time in total.
User avatar
eggmceye
hello
 
Posts: 9880
Joined: Mon Mar 11, 2002 3:55 pm
Location: Sydney, Australia

Postby Catherine » Sun Sep 03, 2006 1:13 am

Scripted mini-games available in dungeons?


EUA>everything. :dancecow:
User avatar
Catherine
English correct bastard.
 
Posts: 1250
Joined: Mon Sep 08, 2003 2:40 am

Postby GenoStar » Sun Sep 03, 2006 5:08 am

EAO?
User avatar
GenoStar
Posting from my ass computer.
 
Posts: 612
Joined: Fri Dec 17, 2004 8:50 am

Postby eggmceye » Sun Sep 03, 2006 12:34 pm

here's a script that turns a ring of 8 braizers on and summons sea serpents at the toggle of a switch. turning the switch off again turns the lights out and removes the seaserpents

update: removed unhex. also, adds the items (ie the braziers and the switch) in the load_map hook rather than the items being required to be placed via maped.

Code: Select all
require("funcs")

map003braziers={{7,3},{10,4},{11,7},{10,10},{7,11},{4,10},{3,7},{4,4}}

function load_map_003()

   for b=1,8 do
   
      x=map003braziers[b][1]
      y=map003braziers[b][2]
      c=BCODE_BRAZIER_OFF
      map_add_item(x,y,3,c,1)
   end
   map_add_item(7,6,3,BCODE_SWITCH_OFF,1)
end

function doBraziers(map, newState)

   
   
   for b=1,8 do
   
      x=map003braziers[b][1]
      y=map003braziers[b][2]
      c=BCODE_BRAZIER_OFF
      if(newState) then c=BCODE_BRAZIER end

      map:set_item_code(x,y,c)
      -- server_msg("x="..x.." y="..y.." c="..c)
   end
      
end

function lvl003switch(id,x,y,z)

   -- get the item code of the switch
   -- then toggle it
   map=get_map_ptr(z)
   c=map:get_item_code(x,y)

   if(c==BCODE_SWITCH_ON) then
    c=BCODE_SWITCH_OFF
   else
    c=BCODE_SWITCH_ON
   end
   map:set_item_code(x,y,c)


   -- toggle all of the braziers
   -- use the one at 7,3 as the master
   b=false -- b is the current state, false means off
   if(map:get_item_code(7,3)==BCODE_BRAZIER) then b=true end

   doBraziers(map, not b) -- toggle braziers
   if(b) then
      -- kill all mobs
      for x=0,map:get_max_x()-1 do
         for y=0,map:get_max_y()-1 do
            m=map:get_mon_ptr(x,y)
            if(m~=nil) then hurt(m.id,10000,"") end
         end
      end
   else
      -- spawn sea monsters
      spawn_at(0x21d,3,3,z)
      spawn_at(0x21d,11,3,z)
      spawn_at(0x21d,3,11,z)
      spawn_at(0x21d,11,11,z)
   end
   update_fov(id)
end

You do not have the required permissions to view the files attached to this post.
Last edited by eggmceye on Sat Sep 09, 2006 9:45 am, edited 1 time in total.
User avatar
eggmceye
hello
 
Posts: 9880
Joined: Mon Mar 11, 2002 3:55 pm
Location: Sydney, Australia

Postby Catherine » Mon Sep 04, 2006 11:57 pm

One thought I had: currently, teleporting or being moved onto a tile doesn't trigger features, (and thus, I'm guessing, scripts).

Will scripts trigger independently of a feature, or not? Its a minor one, but might impact play.

A lot of the examples look fairly straightforward, once you get your head around the language. Not as scary as I was expecting, but not a cake-walk either. Do you mind if people post attempts at doing things, then point out the problems? An online work-through of useful scripts! :)

A simple copy / paste of your example to put in the U5 gazer death sequence. (with errors, no doubt)

-- Gazer
elseif mob_code==unhex("299") then

if math.random(100)<90 then
spawn_near_id(298, killer_id)
send_message(killer_id,"Insects buzz around the body!")
end

Reading through now... I'm so right hand side its not funny though.

p.s. Idea for making quest items etc a lot easier - is it possible to create a block of reserved "blank" codes that would be used for such items, and give a new map a block of them? e.g. a new map is assigned a block of say 25 such hex codes, which then either are used or not. All quests within that map would use those blanks - if they need more, then they'd get another block. I was thinking about maps such as forest, where there a lot of uncoded quests as I never got around to doing them (although I think NPC dialogue exists for them).


[edit]

Just looking at the two you've created (step and switch) I can see that multi-player puzzles are really easy to make. E.g. Player A & B are in front of a chasm they can't cross. Player A steps on a pressure pad that opens a way through a near-by wall, but only whilst there's a player standing on it, so player B tootles off all the way around and then pulls a lever on the other side making a bridge across for player A. Its actually a lot simpler than your examples as well! :)
User avatar
Catherine
English correct bastard.
 
Posts: 1250
Joined: Mon Sep 08, 2003 2:40 am

Postby Balboa » Tue Sep 05, 2006 6:34 am

I still dont understand those scriptings 8D
Eye of the banjo
User avatar
Balboa
I once posted in TFIOOC!
 
Posts: 123
Joined: Sun May 22, 2005 5:01 am
Location: Finland

Postby eggmceye » Tue Sep 05, 2006 10:50 am

Catherine wrote:One thought I had: currently, teleporting or being moved onto a tile doesn't trigger features, (and thus, I'm guessing, scripts).


i think this is correct ... but you could design around it ...


Code: Select all
-- Gazer
   elseif mob_code==unhex("299") then
   
      if math.random(100)<90 then
         spawn_near_id(unhex(298), killer_id)
         send_message(killer_id,"Insects buzz around the body!")
      end
  endif


that's about right - just need the unhex around all item and mob codes, since they are in hexadecimal (base 16) - lua doesn't have inbuilt conversion from hex like C does (eg 0x298) but there might be a patch for lua to add this is in, something to think about.

p.s. Idea for making quest items etc a lot easier - is it possible to create a block of reserved "blank" codes that would be used for such items, and give a new map a block of them? e.g. a new map is assigned a block of say 25 such hex codes, which then either are used or not. All quests within that map would use those blanks - if they need more, then they'd get another block. I was thinking about maps such as forest, where there a lot of uncoded quests as I never got around to doing them (although I think NPC dialogue exists for them).


yeh i'll have to revisit the item code blocks - i've already rearranged them for eao once, but can doso again.


Just looking at the two you've created (step and switch) I can see that multi-player puzzles are really easy to make. E.g. Player A & B are in front of a chasm they can't cross. Player A steps on a pressure pad that opens a way through a near-by wall, but only whilst there's a player standing on it, so player B tootles off all the way around and then pulls a lever on the other side making a bridge across for player A.


only thing wrong with that is there is no hook for stepping off a script, tho you could make all of the tiles around the step trigger hooks to reset the bridge. Or I could just see if I can add a step-off hook function which would do what you want. THat would probably be worthwhile as it does then create pressure pads.
User avatar
eggmceye
hello
 
Posts: 9880
Joined: Mon Mar 11, 2002 3:55 pm
Location: Sydney, Australia

Postby Ulric » Wed Sep 06, 2006 1:15 am

The step off callback would be very useful for determining how fast a player was moving though a dungeon. I am envisioning a kind of "quick sand" type of room where the faster you move the more monsters are spawned. This room would be a great for slowing down high lvl chars who try to speed through a dungeon to get to the big prize at the end.

But for this to work I would a milliseconds timer so I can determine the rate of movement.
Ulric
buying vamp LS of any kind +5
 
Posts: 95
Joined: Wed May 31, 2006 7:17 am

Postby eggmceye » Sun Sep 10, 2006 10:52 pm

scripted questing:

example of enhancing a quest target - this sets the quest target a couple of waypoints to patrol bumps the hp to 20 and sets him as a boss. The quest id is 1.
Code: Select all
function quest_target_001(m)

   m:add_waypoint(13,4)
   m:add_waypoint(11,4)
   m:set_hp_max(20)
   m:mk_boss()

end



example of addition pre-req checks. player must be lvl 2 and have 5 pts in tactics to activate the quest. quest id is 2.
Code: Select all

-- must return 0 if req ok
-- can't use send_npc_reply as this script can be called multiple times

function quest_requirement_002(qid, plyr_id, m)


   p=get_player_ptr(plyr_id)
   if(p.lvl<2) then
   
      return 1
   
   elseif(p:get_raw_skill(SK_TACTICS)<5) then
   
      return 1
         
   end

   return 0
end


example of bonus quest reward: giving 1 pt to tactics and 1 pt to strength. quest id is 2.
Code: Select all
function quest_reward_002(qid,plyr_id)

   adj_skill(plyr_id, SK_TACTICS, 1, true)
   adj_stat(plyr_id,STAT_STR,1);

end


scripted quest type: where the engine uses lua to check to see if the goal is met: here, the goal is for the player to get to 10 tactics. quest id is 3.
Code: Select all
-- return 0 if goal met
-- 1 otherwise
function quest_goal_003(qid,plyr_id)

   p=get_player_ptr(plyr_id)
   if(p:get_raw_skill(SK_TACTICS)==10) then return 0 end
   return 1
   
end


note in this last func i did get_raw_skill(SK_TACTICS)==10 : this should be GREATER THAN OR EQUAL TO 10 but the bb code/html code parser didn't like it
User avatar
eggmceye
hello
 
Posts: 9880
Joined: Mon Mar 11, 2002 3:55 pm
Location: Sydney, Australia

Postby Catherine » Wed Sep 13, 2006 9:12 pm

Laptop blew up - 15 yr old cousin visiting + latest MSN + half the internet as a contacts list = too many viruses to count, "boot drive unmountable". (Although I'd count the latest MSN as virtually a virus in itself the amount of auto-installing of unwanted features it does, even when told not to). So online time is limited to cafes / free "learning centres"... :cry:

The step off hook would be a plus - I'd figured on just surrounding the tile with resets, but that leads to a lot of problems. i.e. Players KOPing (or future Apocalypse equivilent) or IPing. In general, map creators are going to have to be very savy about the effects of players not triggering, or leaving triggered, scripts. Perhaps a universal (map wide) timed "reset to start" might be a good idea? e.g. If Player=0 for X mins, reset all, at the same time as the monster respawn timer.

Quest parsing looks great though :)


Just a small one: will monsters trigger scripts? I'd imagine not, but it might be worth considering. (Or might just prove a massive headache).
User avatar
Catherine
English correct bastard.
 
Posts: 1250
Joined: Mon Sep 08, 2003 2:40 am

Next

Return to EUO Development

Who is online

Users browsing this forum: No registered users and 1 guest