the scripting thread

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

Moderator: EUO Moderators

Postby Dennisd » Mon Sep 18, 2006 12:41 am

Some nice stuff egg!

Here is another intro link I found. Very neat stuff

http://www.devmaster.net/articles/lua/lua1.php

EDIT:

I spent most of the day reading up on Lua, compiling it on Visual C++ Express 2005 and playing around with some sample code. Very brillant stuff here egg! Spent a good deal reading what you have posted here in this thread.
Dennisd
How do I attack?
 
Posts: 4
Joined: Fri Jun 16, 2006 2:00 pm

Postby ChickMagnet » Sun Oct 22, 2006 2:51 pm

egg is raising the average IQ of society
I'm Veris btw -_-
User avatar
ChickMagnet
LAUGHING OUT LOUD LIKE A MORON
 
Posts: 53
Joined: Wed Dec 21, 2005 9:35 am

Re: the scripting thread

Postby LordMortiferus » Tue Jun 19, 2012 4:07 am

Some examples for "advanced" m.code scripts:

The full m.code is 0x0000000
The syntax is 0xERGBMOB
E = Edge glow
R = Red
G = Green
B = Blue
MOB = monster code

Random dyed and glowing mob script: [changed codes to hex values to make more readable -egg]
Code: Select all
function dye(m)
     e = math.random(0,15) * 0x1000000 -- edge glow
     r = math.random(0,15) * 0x100000 -- red
     g = math.random(0,15) * 0x10000 -- green
     b = math.random(0,15) * 0x1000 -- blue
     m.code = m.code + e + r + g + b
end

(thanks to Hellslave for this one, though his initial idea did not wrong and it took me hours to get it right ;) )

Changing the sprites of a spawner using a table to randomly pick them.
function table(m)
c = {0x258, 0x384} -- defines table and can be expanded
m.code = c[math.random(1,2)] -- randomly picks the first or second m.code from the table. The second number's value equals the numbers of m.codes in the table.
end
I'll address this in a separate post below -egg


/!\ Changing the m.code of a spawner spawned monster with a script will mess up its spawner. Meaning that around 6 mobs will be spawned instead of the number defined by the spawner unless the area of the spawner is set to -1.

This is because the spanwer literally counts the mobs around it with the spanwers code. If a rat spawner counts 2 rats and it wants 3, it will spawn 1 rat. If the rat is turned into a goblin immediately after is is spawned, then the spawner will always want one more rat. -egg
User avatar
LordMortiferus
Girls only want boyfriends who have great skills.
 
Posts: 756
Joined: Tue Dec 01, 2009 10:23 pm

Re: the scripting thread

Postby eggmceye » Tue Jun 19, 2012 9:06 am

LordMortiferus wrote:
Code: Select all
function table(m)
     c = {0x258, 0x384} -- defines table and can be expanded
     m.code = c[math.random(1,2)] -- randomly picks the first or second m.code from the table. The second number's value equals the numbers of m.codes in the table.
end


my problems with this - some of it is really nitpipcky but don't forget I'nm a pro programmer with like 30yrs xp :p
i) func name is too generic - also table, tho not a reserved word in lua, might as well be. Unless I knew what you were doing I'd have no idea what this was about
ii) I already wrote a func for selecting a random element from an array - it's in funcs.lua XD

in funcs.lua
Code: Select all
function get_random_element(a)

 return a[math.random(1,#a)]
 
end


in your code
Code: Select all
 ca = {0x258, 0x384, 0x211, 0x200} -- array of potential mobs, var name ca for code array
 c=get_random_element(ca) -- pulls one of the array at random
User avatar
eggmceye
hello
 
Posts: 9878
Joined: Mon Mar 11, 2002 3:55 pm
Location: Sydney, Australia

Re: the scripting thread

Postby Aerie » Wed Jun 20, 2012 10:14 pm

/me wishes /me could understand this. (better, anyway..) :mad:
Aerie
Tune in next time & see how they do it.
 
Posts: 500
Joined: Sun Jan 02, 2011 7:32 am

Re: the scripting thread

Postby mud » Sat Jul 21, 2012 7:22 am

Can I do anything with statues?

For a boss I wanna do a couple things:
  • Have statues of dragons that come to life to start the boss fight. I know how to do all of this except, how do I get the item code for a statue? Ideally I'd like both one facing left and one facing right. This isn't possible in maped too, is it?
  • Make a statue of players temporarily during a fight. Is this possible to do somehow? I don't really need to know how to do the surrounding stuff, just how to get the item code of a statue that matches a player's avatar.
mud
I once posted in TFIOOC!
 
Posts: 132
Joined: Wed Nov 09, 2005 12:29 pm

Re: the scripting thread

Postby LordMortiferus » Sat Jul 21, 2012 7:50 pm

The code for a statue is a 7 digit hexcode: 0xCBBBAAA
AAA = 545 --- defines this item to be a statue
BBB = mob code
C = number of the frame to be used (normally the sprites of a mob has four frames for animation)
e.g. 0x3350545 would be a statue of a blood golem using the last of its 4 frames - so it would be a golem with raised arms.

I am not sure about flipping an item sprite - afaik it is not part of the item code.
User avatar
LordMortiferus
Girls only want boyfriends who have great skills.
 
Posts: 756
Joined: Tue Dec 01, 2009 10:23 pm

Re: the scripting thread

Postby mud » Sun Jul 22, 2012 3:14 am

LordMortiferus wrote:The code for a statue is a 7 digit hexcode: 0xCBBBAAA
AAA = 545 --- defines this item to be a statue
BBB = mob code
C = number of the frame to be used (normally the sprites of a mob has four frames for animation)
e.g. 0x3350545 would be a statue of a blood golem using the last of its 4 frames - so it would be a golem with raised arms.

I am not sure about flipping an item sprite - afaik it is not part of the item code.


Cool, thanks! Very good info.

I'm thinking if I take the low-order 12 bits of a player's 'code' member-variable, to get rid of tinting, and use that as the mob code, that will probably work for making a statue of a player. Hopefully.

Or maybe I'm supposed to call get_draw_code() on the player? Hmmmm.
mud
I once posted in TFIOOC!
 
Posts: 132
Joined: Wed Nov 09, 2005 12:29 pm

Re: the scripting thread

Postby eggmceye » Tue Sep 24, 2013 3:04 pm

Attaching a script to a spawner
eg to level the mob up or make it heroic
(not that heroic maps use a different system tho the script is the same)

First:
the spawner in maped
note the script field down the bottom - mkEvil
(note also that this screenshot is from future version of maped)
spawner.png


Then here is the attached script (which you put in a lua file)
Code: Select all
function mkEvil(m)

 m:set_align(ALIGN_EVIL)
end



More scripts:
Heroic and Epic: note use of secondary helper funcs

Code: Select all
function spawnerHeroic(m)
   
   scaleCreature(m, 3, 4);
end

function spawnerEpic(m)

   scaleCreature(m, 5, 6);
end

-- m is the monster pointer
-- c is the scale (or Constant) (so heroic is 3x HP etc, epic is 5x)
-- qbump will add on quality to the loot
function scaleCreature(m, c, qBump)

   m.hp=m.hp*c
   m:set_hp_max(m.hp)
   m.xp_kill=m.xp_kill*c
   m:set_thaco((m:get_thaco()-10)*c+10)
   m:set_base_ac(m:get_ac()+10*(c-1))
   m:set_intel(m:get_intel()*c)
   m:set_magic_resistance(m:get_magic_resistance()*c)
   m:set_dmg_dice(m:get_dmg_dice()*c/2)
   
   q=m.treasure/0x10000
   q=q+qBump
   if q>15 then q=15 end
   m.treasure=m.treasure&0xffff+q*0x10000
   
   m.tamable=false

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

Re: the scripting thread

Postby Bugbo » Tue Oct 15, 2013 5:11 am

Would it be possible to script a slime that wouldn't have the ability to divide? (in case you wanted to make a room filled with 20 of them for example)
Bugbo
Girls only want boyfriends who have great skills.
 
Posts: 768
Joined: Thu May 06, 2004 8:45 pm
Location: Oregon!

Re: the scripting thread

Postby eggmceye » Tue Oct 15, 2013 9:11 am

hmm - the split code is done in a common monster death func - so somehow you would have to flag the slime via a spawn script such that the death func then knows not to split it when it dies ...
User avatar
eggmceye
hello
 
Posts: 9878
Joined: Mon Mar 11, 2002 3:55 pm
Location: Sydney, Australia

Re: the scripting thread

Postby LordMortiferus » Tue Oct 15, 2013 4:37 pm

The deathfunction checks if the monster mcode is 0x21a or not.
Code: Select all
elseif mob_code==0x21a then

Hence, it should be enough to use a lightly tinted slime e.g. 0xfff21a. See triple hex code for reference on tinting.
User avatar
LordMortiferus
Girls only want boyfriends who have great skills.
 
Posts: 756
Joined: Tue Dec 01, 2009 10:23 pm

Re: the scripting thread

Postby eggmceye » Tue Oct 15, 2013 7:58 pm

ha good one
User avatar
eggmceye
hello
 
Posts: 9878
Joined: Mon Mar 11, 2002 3:55 pm
Location: Sydney, Australia

Re: the scripting thread

Postby Celerion » Sat Nov 23, 2013 3:07 am

Hi,

I just cleaned up the Lua-script "auxbox.lua" with texts for the message-box a bit (indentation and whitespace were rather messy). The script used to be in a subdirectory "clientscripts" (which doesn't seem to exist in the recent client-distribution any more, but could still be created again by hand). The script shows real-life-time and session-time in the message-box at the moment (this is my config, stats for damage per second would also be possible):
Code: Select all
filterTextLines = [[Hit the following keys
to filter item types:

w: weapons
W: wearables
p: potions
s: shields
u: usable
j: jewellry
f: food
U: unidentified
h: slot-head
t: slot-torso
l: slot-legs
b: slot-boots
g: slot-gloves
r: slot-rings
n: slot-neck
S: spells & scrolls
G: gems
R: reagants, etc
A: cancel filtering
v: cancel filtering]]

auxbox_next_line = 0
session_time = 0
sessionstart = os.time()

shiftkeys = {"Shift", "Alt", "Ctrl+Shift", "Shift+Alt",
             "Ctrl+Alt", "Ctrl+Alt+Shift"}

function auxbox()
   
    local w = d:auxbox_get_width()
    local h = d:auxbox_get_height()
 
    d:auxbox_clear()
    auxbox_next_line = 0
    if not d:ok_to_draw_play_window() then
        return
    end
     
    local cd = d:get_curr_display()
    local mode = d:get_statbox_mode()
    local lineNr = 0
    local txta = explode("\n", filterTextLines)

    if cd == 1 then
 
        if mode == SELECT_ABILITY then
            auxbox_prop_line("Hit F-key to bind currently")
            auxbox_prop_line("selected spell")
            auxbox_blank_line()
            auxbox_ability_binds()
        else
            for i = 1, #txta do
                auxbox_prop_line(txta[i])
            end
            auxbox_blank_line()
            auxbox_prop_line("Search with /")
            if mode == SELECT_READY then
                auxbox_prop_line("Press ENTER to equip")
            elseif mode == SELECT_BUY then        
                auxbox_prop_line("Press ENTER to buy")
            elseif mode == SELECT_BANK then
                auxbox_prop_line("Press ENTER to transfer one")
                auxbox_prop_line("Press Shift+ENTER for 10")
                auxbox_prop_line("Press TAB for whole stack")
            end
        end
    else
        auxbox_time()   
        auxbox_blank_line()
        -- auxbox_damage_per_second()
        -- auxbox_blank_line()
        -- auxbox_prop_line("Forums: forums.swut.net")
        -- auxbox_prop_line("Manual: euotopia.com/manual")
        if d:numlock() then
            auxbox_blank_line()
            auxbox_prop_line("Please turn numlock off!")
        end
        -- auxbox_prop_line("F12 for main menu.")
        -- auxbox_blank_line()
        -- auxbox_f5_message()                 
    end
end

-- explode(seperator, string)
-- from http://lua-users.org/wiki/SplitJoin

function explode(d, p)
    local t, ll
    t = {}
    ll = 0
    if (#p == 1) then
        return p
    end
    while true do
        l = string.find(p, d, ll+1, true)
        if l ~= nil then
            table.insert(t, string.sub(p, ll, l-1))
            ll = l + 1
        else
            table.insert(t, string.sub(p, ll))
            break
        end
    end
    return t
end

-- Real World Time - Duncan (PD) / Zen (Reg) / Brentoboy (forums)
function auxbox_time()
    auxbox_prop_line("Real World Time:", string.format(os.date("%I:%M%p")))
    if os.difftime(os.time(), sessionstart) > session_time then
        session_time = os.difftime(os.time(), sessionstart)
        session_d_float = session_time / 60 / 60 / 24
        session_d = math.floor(session_d_float)
        session_h = math.floor((session_d_float - session_d) * 24)
        session_m = math.floor(((session_d_float - session_d) * 24 - session_h) * 60)
        session_s = math.floor((((session_d_float - session_d) * 24 - session_h) * 60 - session_m) * 60)
    end   
 
    if session_d ~= nil then
        auxbox_prop_line("Session time:", string.format("%02.f:%02.f:%02.f:%02.f", session_d, session_h, session_m, session_s))   
    end
end

function auxbox_f5_message()
    auxbox_prop_line("Press Alt-F5 to Reset", "")
end

function auxbox_prop_line(prop_name, prop_val)
    local pvl = 0
    if prop_name == nil then prop_name = "" end
    if prop_val == nil then prop_val = "" end
    local filler = string.rep(" ", 25 - string.len(prop_name) - string.len(prop_val))
    auxbox_next_line = auxbox_next_line + 1
    d:auxbox_set_line(auxbox_next_line, string.format("%s %s %s", prop_name, filler, prop_val))
end

function auxbox_blank_line()
    auxbox_next_line = auxbox_next_line + 1
end

--- Damage Per Second -- original script proveded by LordMortiferus
last_session_seconds = 0
last_4_dpst = {g_dpst, g_dpst, g_dpst, g_dpst}
last_4_dtpst = {g_dtpst, g_dtpst, g_dtpst, g_dtpst}
last_dpst = g_dpst
recent_dmg = {0, 0, 0, 0}

function auxbox_damage_per_second()
    local session_seconds = os.time() - sessionstart
   
    if session_seconds > last_session_seconds then
        last_session_seconds = session_seconds
        last_4_dpst[4] = last_4_dpst[3]
        last_4_dpst[3] = last_4_dpst[2]
        last_4_dpst[2] = last_4_dpst[1]
        last_4_dpst[1] = g_dpst   
        last_4_dtpst[4] = last_4_dtpst[3]
        last_4_dtpst[3] = last_4_dtpst[2]
        last_4_dtpst[2] = last_4_dtpst[1]
        last_4_dtpst[1] = g_dtpst   
    end
   
    if last_dpst ~= g_dpst then
        recent_dmg[4] = recent_dmg[3]
        recent_dmg[3] = recent_dmg[2]
        recent_dmg[2] = recent_dmg[1]
        recent_dmg[1] = g_dpst - last_dpst
        last_dpst = g_dpst
    end
   
    auxbox_prop_line("Dmg Dealt / Sec", string.format("%d", (last_4_dpst[1] - last_4_dpst[4])  / 4))
    auxbox_prop_line("Dmg Taken / Sec", string.format("%d", (last_4_dtpst[1] - last_4_dtpst[4])  / 4))
    auxbox_prop_line("Recent Dmg Dealt", "")
    auxbox_prop_line("", string.format("%d  %d  %d  %d", recent_dmg[4], recent_dmg[3], recent_dmg[2], recent_dmg[1]))
end

I wonder, what other game-extensions would be possible with Lua. The manual mostly talks about monster-behaviour in MapEd. But I'm no good at MapEd to be honest. ;)
Celerion
I'll be going back to Tibia next week.
 
Posts: 48
Joined: Sat Dec 15, 2012 6:29 am

Re: the scripting thread

Postby Celerion » Mon Nov 25, 2013 10:23 am

eggmceye wrote:Well you can't really develop scripts because you can't test them because you don't have a dev server! and I'm not giving away dev servs unless I do a stripped down version everyone can have (in far future)

Ok, so map-development with Lua-scripts still seems to be stuck a bit, right? Or is some kind of test-server, that only runs on the local machine (without source-code, of course) already available? Just curious ...

Edit: Maybe it would be a good idea to give up the client/server-architecture for test-playing at all and put it all into just one local application. Or even better to integrate it all into MapEd.
To me, "Play the map (including scripts)" seems to be an essential function to MapEd. Although people seem to have been able to write maps without it in the past. Hard to believe. ;)
Celerion
I'll be going back to Tibia next week.
 
Posts: 48
Joined: Sat Dec 15, 2012 6:29 am

Re: the scripting thread

Postby LordMortiferus » Wed Feb 19, 2014 2:34 am

Simple Lua script for using mount sprites or Stone Guardian tiles as a mob avatar that faces in both directions depending on its target.
Code: Select all
-- this is an example function added to the spawner!
function your_function_here(m)
   m.code = 0xdf0043d -- e.g. stone guardian
   flip(m) -- calls the function below
end

-- this is the actual function that will define which sprite is used for facing left/right
function flip(m)
   -- var to track movement
   move_x = m.x
   
   -- for stone guardian
   if m.code == 0xdf0043d or m.code == 0xe00043d then
    flip_left = 0xe00043d
    flip_right = 0xdf0043d
   
   -- for mounts
   else
     local dir_array = {
         {"447","446"}, -- white horse
         {"44a","449"}, -- raft
         {"44d","44c"}, -- cow
         {"53e","53d"}, -- browne horse
         {"540","53f"}, -- bunny
         {"542","541"}, -- drake
         {"544","543"}  -- turkey
         -- dyable drake is missing
         }
     -- m.code is formated into a string and then splitted into 2 parts for sprite and attributes
    local string_code = string.format("%x",tostring(m.code))
    local string_len = string.len(string_code)
    local sprite_cache = string.sub(string_code, string_len-2, string_len)
    local attrib_cache = string.sub(string_code, 1, string_len-3)

   -- compare the m.code with the codes within the array
      for i,v in ipairs(dir_array) do
         for k,w in ipairs(v) do
            if sprite_cache == w then
             -- set code for left and right mob including the attributes and convert it back to hex number
               flip_left  = tonumber(string.format("%s%s",attrib_cache,v[1]),16)
             flip_right = tonumber(string.format("%s%s",attrib_cache,v[2]),16)
            end
         end
      end
   end
   
   -- if left and right is set a heartbeat function is called
   if flip_left ~= nil and flip_right ~= nil then
    m.heartbeat_func="flip_actions"
   end
end

-- this heartbeat function is called every 1s to change the sprite if needed
-- cause it is a heartbeat func there is a slight delay between mob movement and sprite change
function flip_actions(m)
   
   local tgt
   
   -- if the mob has a target it will face this target
   if m.target_id >= 0 then
      tgt=get_sent_ptr(m.target_id)
      if tgt.x < m.x and m.code ~= flip_left then
       m.code = flip_left
       update_everyones_fov(m)
       elseif tgt.x > m.x and m.code ~= flip_right then
       m.code = flip_right
       update_everyones_fov(m)
         elseif tgt.x == m.x and tgt.y < m.y and m.code ~= flip_right then
       m.code = flip_right
       update_everyones_fov(m)
       elseif tgt.x == m.x and tgt.y > m.y and m.code ~= flip_left then
       m.code = flip_left
       update_everyones_fov(m)
      end
   
   -- if the mob moves without a target it faces the direction of movement
   elseif m.target_id < 0 and m.x ~= move_x then
      if m.x < move_x and m.code ~= flip_left then
       m.code = flip_left
       update_everyones_fov(m)
       elseif m.x > move_x and m.code ~= flip_right then
       m.code = flip_right
       update_everyones_fov(m)
      end
    move_x = m.x
   end
end

Also works with mounts.
Updated the script to make it more versatile.
You do not have the required permissions to view the files attached to this post.
Last edited by LordMortiferus on Mon Feb 24, 2014 1:56 am, edited 1 time in total.
User avatar
LordMortiferus
Girls only want boyfriends who have great skills.
 
Posts: 756
Joined: Tue Dec 01, 2009 10:23 pm

Re: the scripting thread

Postby 1[WoWz] » Wed Feb 19, 2014 2:57 am

Very nice LordM, that looks really cool. A horse mounted/drake mounted special mob would be terrifying.
IGN: 1
User avatar
1[WoWz]
Girls only want boyfriends who have great skills.
 
Posts: 766
Joined: Wed Apr 21, 2004 6:48 pm
Location: Southern California, USA

Re: the scripting thread

Postby Keighn » Wed Feb 19, 2014 6:21 am

Can you make my house do this?
Image

That's either a mole or a hippoman.. I don't know but its gray and scary.
User avatar
Keighn
Stop posting already --;
 
Posts: 4786
Joined: Sat Jun 26, 2004 10:13 am
Location: From the depths of Oregon he returns.... KEIGHN!!!!

Re: the scripting thread

Postby CinisterD » Wed Feb 19, 2014 9:09 am

1[WoWz] wrote:Very nice LordM, that looks really cool. A horse mounted/drake mounted special mob would be terrifying.



I've had an idea for this some time now. I just need to team up with someone that can do the scripting.

I can do Map'd easy, but what I want to do is a bit beyond my talents. Unfortunately Shrike is not around so I'm stuck :/
User avatar
CinisterD
I'd laugh if I saw a centaur IRL
 
Posts: 368
Joined: Mon Jul 06, 2009 6:26 pm

Re: the scripting thread

Postby LordMortiferus » Mon Feb 24, 2014 2:03 am

Updated the script above to make it more versatile. Hope that will be helpful for Cin's project. I will try to include ships/chairs(?!) in a future update - already got a working concept on deciding how to determine if the mob has to face north, south, east or west by rotating a fictional Cartesian coordination system around the mob :lesson: (don't care about broad side firing though).
User avatar
LordMortiferus
Girls only want boyfriends who have great skills.
 
Posts: 756
Joined: Tue Dec 01, 2009 10:23 pm

PreviousNext

Return to EUO Development

Who is online

Users browsing this forum: Google [Bot] and 5 guests