the scripting thread

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

Moderator: EUO Moderators

Re: the scripting thread

Postby Celerion » Mon Mar 03, 2014 3:24 am

Hi, in game someone said, it would be nice to have the remaining time of 2xXP-weekend in the auxbox.
With Lua, messages can be posted easily to the box.
Would it be possible to access the server-time from Lua?
Or even better, request the remaining time of 2xXP-weekend in seconds and get 0 if it's not on?

Maybe the main-client should ask the server these things once at start-up and pass it on to Lua somehow. To avoid, that evil people write too many requests to the server from Lua ...
....

Usually I write (at least prototype) in Python (stand-alone). Here would be some functions in Python that could check, if double-XP was on and get the remaining time.
If the functions had the weekday ("SUN", "MON" ... "SAT") and the day of the month (1, 2 ... 28, 29, 30, 31):
Code: Select all
#!/usr/bin/env python
# coding: iso-8859-1

def isDoubleXp(weekday, dayofmonth):
    if weekday == "SAT" and dayofmonth < 8:
        return 1
    if weekday == "SUN" and dayofmonth <= 8 and dayofmonth >= 2:
        return 1
    return 0

def secondsToDaytime(secs):
    a = []
    a.append(int(secs / 3600.))
    rest = secs - a[0] * 3600.
    a.append(int(rest / 60.))
    rest -= a[1] * 60.
    a.append(int(rest))
    for i in range(len(a)):
        if a[i] < 10:
            a[i] = "0" + str(a[i])
        else:
            a[i] = str(a[i])
    return ":".join(a)

def DaytimeToSeconds(daytime):
    a = daytime.split(":")
    for i in range(len(a)):
        a[i] = int(a[i])
    seconds = a[0] * 3600 + a[1] * 60
    if len(a) == 3:
        seconds += a[2]
    return seconds

def getRemainingSeconds(weekday, daytime):
    oneday = 86400
    twodays = 172800
    elapsed_time = DaytimeToSeconds(daytime)
    if weekday == "SUN":
        elapsed_time += oneday
    return twodays - elapsed_time

print isDoubleXp("SAT", 7)
print isDoubleXp("MON", 7)
print isDoubleXp("SAT", 8)
print isDoubleXp("SUN", 8)
print isDoubleXp("SUN", 9)
print

sec = getRemainingSeconds("SUN", "17:00")
print sec
print secondsToDaytime(sec)

sec = getRemainingSeconds("SAT", "9:25")
print sec
print secondsToDaytime(sec)

I could probably translate this to Lua somehow; then I just needed the server-time (as a date-string) at login-time (provided by the client (!), see above), then I could post the result in the auxbox. ;)
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 Mar 03, 2014 3:35 am

Keighn wrote:Can you make my house do this?-
That's either a mole or a hippoman.. I don't know but its gray and scary.

:) That's Monty, a mole I think. (Looks a lot like the great "Jet Set Willy", if you ask me; there's also a PC-remake of it (JSW)).
Anyway, unfortunately this can't be done to houses, because of the perspective: You look at these Monty-platforms from the side, while you look at EUO from above (kind of). Though in real top-view you would always see the top of the heads, like in Alien Breed. That's not optimal either.
Now I feel dizzy.
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 » Mon Mar 03, 2014 4:25 am

@cel:
As a start you could calculate the server time using os.date("!*t") to get UTC/GMT and then add 11 hours or so for Sydney time. Also refer to lua-users/timezones and lua manual on os.date and lua-users/os_lib_tutorial.

Edit: Would actually be nice to have an auxbox line that just tells you the time in down-under for scavenger/statue hunt.
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 Celerion » Sat Mar 08, 2014 4:40 am

Completely rewrote the script "auxbox.lua", that should be copied into a directory "clientscripts" in the EUO-directory (so it should be usually "C:\Program Files\euo\clientscripts\auxbox.lua").
You can configure, what's shown, with options at the beginning of the script. This should make it easier for users to activate "Damage Per Second" for example.

Edit: The script has been updated. Please see below.
Last edited by Celerion on Fri Oct 31, 2014 3:01 am, edited 4 times in total.
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 » Sat Mar 08, 2014 5:31 am

Cel you should check out this script by ched - With it you add and remove scripts to the auxbox in game.
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 Celerion » Sat Mar 08, 2014 7:08 pm

LordMortiferus wrote:Cel you should check out this script by ched - With it you add and remove scripts to the auxbox in game.

Dang!

On the other hand: Shouldn't this registering-system have gone into the main-distribution, where I probably could have seen it?

Well, to me, the auxbox isn't that interesting after all. It was just a way to learn Lua and interaction with the client. It would be much more interesting to code map-extensions and monster behaviour. When one day an offline-server is released, I may be ready. (At the moment, without the possibility to test anything, it doesn't make much sense to me. I know Mort, you would be willing to help with testing, but this kind of development is a long process, where I need feedback like error-messages all the time. It wouldn't be practical to write you hundreds of Emails about it.)
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 » Sat Mar 08, 2014 8:15 pm

Celerion wrote: I know Mort, you would be willing to help with testing, but this kind of development is a long process, where I need feedback like error-messages all the time. It wouldn't be practical to write you hundreds of Emails about it.)

Totally know what you mean - debugging can be a pain, especially when you try new stuff and want to test it part by part with live feedback. Anyway, good job on the auxbox script! I'll gonna check out the lua page about classes.
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 LordMortiferus » Sun Mar 09, 2014 7:40 am

Below is a code that can be used to copy a rectangular part of a map and paste it somewhere else. The code is executed by Maped when the appropriate level is loaded. You will find instructions for the script here

Big thanks to the community of lua-users.org for creating a function to export and import tables, as well as explode. Thanks to ched for helping me out with this and to egg for his feedback.

Either copy the script below into an empty text file and save it with the .lua extension or grab it straight from my dorpbox.

Code: Select all
-- 2014/09/03 LordMortiferus & Chedich
-- Copy and Paste function for Maped

function load_map_666(lvl, load_on_the_fly) -- change map number if needed

   local func = "copy" -- copy or paste
   local xy_start = {0,0} -- {x,y} -- needs to be set for copy or paste
   local xy_end = {30,30} -- {x,y} -- only essential for copy

   local cp_tiles = true -- set to false if you do not want to copy&paste tiles
   local cp_items = true -- set to false if you do not want to copy&paste items
   local cp_feat = true -- set to false if you do not want to copy&paste features
   local cp_spawner = true -- set to false if you do not want to copy&paste spawners

   
   local table_index = 1
   
   map=get_map_ptr(lvl)

   -- copy function
   if func == "copy" then
   
      -- egg mod: dont crap out if the end coords are bigger than map size: instead, cap them and continue
      if xy_end[1]>=map:get_max_x() then xy_end[1]=map:get_max_x()-1; end
      if xy_end[2]>=map:get_max_y() then xy_end[2]=map:get_max_y()-1; end
      
      if xy_start[1] >= 0 and xy_end[1] > xy_start[1] and xy_end[1] < map:get_max_x() and
         xy_start[2] >= 0 and xy_end[2] > xy_start[2] and xy_end[2] < map:get_max_y() then
      
       local chunk_size = {}
       table.insert (chunk_size, xy_end[1]-xy_start[1])
       table.insert (chunk_size, xy_end[2]-xy_start[2])
       table.save(chunk_size, "chunk_size.lua")
      
          
          local tile_cache = {}
          local item_cache = {}
          local feat_cache = {}
          local spawner_cache = {}
         
         for yy = xy_start[2] , xy_end[2] do
            for xx = xy_start[1] , xy_end[1] do
               
               if cp_tiles == true then
                  table.insert (tile_cache,map:get_tile(xx,yy))
               end
               
               if cp_items == true then
                  if map:get_item_qty(xx,yy) == 0 then
                    table.insert (item_cache,0)
                   else
                   table.insert (item_cache,map:get_item_code(xx, yy):intVal())
                  end
               end
               
               if cp_feat == true then
                  if map:get_feat_typ(xx, yy) >= 0 and map:get_feat_typ(xx, yy) ~= 4 then
                   table.insert (feat_cache,string.format("%d$%d$%d$%d$%d$%s",map:get_feat_typ(xx,yy)
                                                               ,map:get_feat_val(xx,yy)
                                                               ,map:get_feat_dest_x(xx,yy)
                                                               ,map:get_feat_dest_y(xx,yy)
                                                               ,map:get_feat_itm(xx,yy):intVal()
                                                               ,map:get_feat_text(xx,yy)))
                    else
                   table.insert (feat_cache,"nil")
                  end
               end
               
               if cp_spawner == true then
                  if map:get_feat_typ(xx, yy) == 4 then
                     local cp_spawner = map:get_spawner(xx, yy)
                     table.insert(spawner_cache,string.format("4$%d$%d$%d$%d$%d$%d$%s",cp_spawner.sp_type,
                                                                          cp_spawner.sp_code,
                                                                       cp_spawner.sp_rate,
                                                                       cp_spawner.sp_max,
                                                                       cp_spawner.sp_area,
                                                                       cp_spawner.quest_id,
                                                                       cp_spawner.script))
                  else
                   table.insert (spawner_cache,"nil")
                  end
               end
            end
         end
      
         if cp_tiles == true then
          table.save(tile_cache, "tile_cache.lua")
         end
         if cp_items == true then
          table.save(item_cache, "item_cache.lua")
         end
         if cp_feat == true then
          table.save(feat_cache, "feat_cache.lua")
         end
         if cp_spawner == true then
          table.save(spawner_cache, "spawner_cache.lua")
         end
      end
      
   -- paste function
   elseif func == "paste" then
   
     tile_cache = table.load("tile_cache.lua")
     item_cache = table.load("item_cache.lua")
     feat_cache = table.load("feat_cache.lua")
     spawner_cache = table.load("spawner_cache.lua")
     chunk_size = table.load("chunk_size.lua")
      
      if chunk_size ~= nil and
         xy_start[1] >= 0 and xy_start[1]+chunk_size[1] < map:get_max_x() and
         xy_start[2] >= 0 and xy_start[2]+chunk_size[2] < map:get_max_y() then
         for yy = xy_start[2], xy_start[2]+chunk_size[2] do
            for xx = xy_start[1], xy_start[1]+chunk_size[1] do
               
               if cp_tiles == true and tile_cache ~= nil then
                map:set_tile(xx,yy,tile_cache[table_index])
               end
               
               if cp_items == true and item_cache ~= nil then
                map:destroy_pile(xx,yy)
                  if item_cache[table_index] ~= 0 then
                   map:add_item(xx, yy, 1, Item(item_cache[table_index]))
                   local i = item_cache[table_index]
                     if i ~= 0x51b and i ~= 0x51c and i ~= 0x111 then
                        map:set_as_furniture(xx,yy)
                     end
                  end
               end
                           
               if cp_feat == true or cp_spawner == true then
                map:del_feat(xx,yy)
               end
               
               if cp_feat == true and feat_cache ~= nil then
                local feat_data = explode("$",feat_cache[table_index])
                  if feat_data[1] ~= "nil" then
                  map:add_feat(xx, yy, tonumber(feat_data[1]), -- feat type
                                  tonumber(feat_data[2]), -- feat value
                                  tonumber(feat_data[3]), -- feat dest x
                                  tonumber(feat_data[4]), -- feat dest y
                                  Item(tonumber(feat_data[5])), -- feat item
                                  feat_data[6]) -- feat text
                  end
               end
               
               if cp_spawner == true and spawner_cache ~= nil then
                local spawner_data = explode("$",spawner_cache[table_index])
                  if spawner_data[1] ~= "nil" then
                  map.spawners:add(tonumber(spawner_data[2]), -- type
                               tonumber(spawner_data[3]), -- code
                               tonumber(spawner_data[4]), -- rate
                               lvl, -- level
                               tonumber(spawner_data[5]), -- max
                               0, -- currtime ?
                               xx, yy,
                               tonumber(spawner_data[6]), -- area
                               tonumber(spawner_data[7]), -- quest id
                               spawner_data[8]) -- script
                  map:add_feat(xx,yy,SPAWNER)
                  end
               end
             table_index = table_index + 1
            end
         end
      end
   end
end   

--Taken from http://lua-users.org/wiki/SaveTableToFile
--[[
   Save Table to File
   Load Table from File
   v 1.0
   
   Lua 5.2 compatible
   
   Only Saves Tables, Numbers and Strings
   Insides Table References are saved
   Does not save Userdata, Metatables, Functions and indices of these
   ----------------------------------------------------
   table.save( table , filename )
   
   on failure: returns an error msg
   
   ----------------------------------------------------
   table.load( filename or stringtable )
   
   Loads a table that has been saved via the table.save function
   
   on success: returns a previously saved table
   on failure: returns as second argument an error msg
   ----------------------------------------------------
   
   Licensed under the same terms as Lua itself.
]]--

do
   -- declare local variables
   --// exportstring( string )
   --// returns a "Lua" portable version of the string
   local function exportstring( s )
      return string.format("%q", s)
   end

   --// The Save Function
   function table.save(  tbl,filename )
      local charS,charE = "   ","\n"
      local file,err = io.open( filename, "wb" )
      if err then return err end

      -- initiate variables for save procedure
      local tables,lookup = { tbl },{ [tbl] = 1 }
      file:write( "return {"..charE )

      for idx,t in ipairs( tables ) do
         file:write( "-- Table: {"..idx.."}"..charE )
         file:write( "{"..charE )
         local thandled = {}

         for i,v in ipairs( t ) do
            thandled[i] = true
            local stype = type( v )
            -- only handle value
            if stype == "table" then
               if not lookup[v] then
                  table.insert( tables, v )
                  lookup[v] = #tables
               end
               file:write( charS.."{"..lookup[v].."},"..charE )
            elseif stype == "string" then
               file:write(  charS..exportstring( v )..","..charE )
            elseif stype == "number" then
               file:write(  charS..tostring( v )..","..charE )
            end
         end

         for i,v in pairs( t ) do
            -- escape handled values
            if (not thandled[i]) then
           
               local str = ""
               local stype = type( i )
               -- handle index
               if stype == "table" then
                  if not lookup[i] then
                     table.insert( tables,i )
                     lookup[i] = #tables
                  end
                  str = charS.."[{"..lookup[i].."}]="
               elseif stype == "string" then
                  str = charS.."["..exportstring( i ).."]="
               elseif stype == "number" then
                  str = charS.."["..tostring( i ).."]="
               end
           
               if str ~= "" then
                  stype = type( v )
                  -- handle value
                  if stype == "table" then
                     if not lookup[v] then
                        table.insert( tables,v )
                        lookup[v] = #tables
                     end
                     file:write( str.."{"..lookup[v].."},"..charE )
                  elseif stype == "string" then
                     file:write( str..exportstring( v )..","..charE )
                  elseif stype == "number" then
                     file:write( str..tostring( v )..","..charE )
                  end
               end
            end
         end
         file:write( "},"..charE )
      end
      file:write( "}" )
      file:close()
   end
   
   --// The Load Function
   function table.load( sfile )
      local ftables,err = loadfile( sfile )
      if err then return _,err end
      local tables = ftables()
      if tables == nil then return nil end
      for idx = 1,#tables do
         local tolinki = {}
         for i,v in pairs( tables[idx] ) do
            if type( v ) == "table" then
               tables[idx][i] = tables[v[1]]
            end
            if type( i ) == "table" and tables[i[1]] then
               table.insert( tolinki,{ i,tables[i[1]] } )
            end
         end
         -- link indices
         for _,v in ipairs( tolinki ) do
            tables[idx][v[2]],tables[idx][v[1]] =  tables[idx][v[1]],nil
         end
      end
      return tables[1]
   end
-- close do
end

function explode(div,str) -- credit: http://richard.warburton.it
  if (div=='') then return false end
  local pos,arr = 0,{}
  -- for each divider found
  for st,sp in function() return string.find(str,div,pos,true) end do
    table.insert(arr,string.sub(str,pos,st-1)) -- Attach chars left of current divider
    pos = sp + 1 -- Jump past current divider
  end
  table.insert(arr,string.sub(str,pos)) -- Attach chars right of last divider
  return arr
end
Last edited by LordMortiferus on Thu Sep 04, 2014 2:32 am, edited 4 times 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 LordMortiferus » Sun Mar 16, 2014 11:45 pm

Updated the copy&paste script for Maped. You can now copy&paste tiles, items, spawner and other features. Chedich helped me out with features and items.
Note: if you copy features you likely have to change the value as well as the x,y destinations manually after pasting them. Furthermore, the script is still not user-friendly - so feel free to contact me via pm if you need help.
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 Celerion » Fri May 02, 2014 12:48 am

Here's a Lua-mystery: In my auxbox-script above I use UTC-time, then add 10 hours to get sydney-time (without daylight saving time) like it's shown here.

Strange thing is, when I add for example 3600 seconds to UTC-time and convert to a timetable, two hours are added, not just one. Example (with print, not auxbox):
Code: Select all
#!/usr/bin/lua

-- Get UTC-timetable:
utc = os.date("!*t")
print(string.format("%s:%s", utc.hour, utc.min))

-- Convert to seconds since epoch (1/1/1970):
utcs = os.time(utc)
-- Add one hour:
dsec = utcs + 3600

-- Convert to timetable:
d = os.date("*t", dsec)
print(string.format("%s:%s", d.hour, d.min))

-- Result: Two hours difference. Why not just one???

Output is:
Code: Select all
14:47
16:47

but should be 15:47. Why is that?

(In Python, I'd have control, if things are converted to GM-time or local-time:
Code: Select all
#!/usr/bin/python
# coding: iso-8859-1

import time
import calendar

# Get UTC-Timetuple:
gm = time.gmtime()
print "%s:%s" % (gm[3], gm[4])
# Convert to seconds since epoch:
gms = calendar.timegm(gm)
# Add one hour:
d = gms + 3600
# Convert either to local time-tuple or UTC-timetuple:
dslocal = time.localtime(d)
dsgm = time.gmtime(d)
print "Local: %s:%s" % (dslocal[3], dslocal[4])
print "UTC: %s:%s" % (dsgm[3], dsgm[4])

so no problem there, just in Lua.)
---
Edit 05/05/14: Found some discussions about it here and here.
For my script, I took the code from the function "get_timezone()" here. os.difftime() is probably not what I want, because there are timezones UTC+X (like Sydney) and timezones UTC-X (like New York for example).
I applied this hack to my seconds:
Code: Select all
seconds = seconds - (os.time() - os.time(os.date("!*t")))

So in fact, I don't calculate the seconds since epoch for Sydney, but the number of seconds that os.date() will hopefully convert to Sydney-time.
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 » Tue Jul 22, 2014 5:44 am

Updated the copy&paste script for maped. Items are now set as furniture.
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 Jul 22, 2014 10:02 pm

gunna be using this script for apocalyptic map instances ... mino halls will be the first ... haven't considered spawners yet though
User avatar
eggmceye
hello
 
Posts: 9878
Joined: Mon Mar 11, 2002 3:55 pm
Location: Sydney, Australia

Re: the scripting thread

Postby Catherine » Thu Aug 07, 2014 5:11 am

I last posted in this thread in 2006 which is a fairly fucking epic self-necro :P (I'm sure it wasn't 2006. More like 2010!!)


However: Couldn't find / see / am lazy / Call out to hotshots (since there's obviously people in here who can code well).

REQUEST:

Example of trigger that calls a spawner using msg. e.g. Step on tile, msg is displayed, spawner launches monsters - however, must have timer attached. i.e. Step on msg, spawn, then <time=X> before it can be triggered again.

In game action: player steps on tile; monsters exploding in radius X surrounding them! (boo!)

REQUEST:

I know this exists, since I once had a copy of MapEd with scripts attached, but the simple <a> switch = effect script. However, must be able to call a created item. i.e. one of those hybrids created using gold piece + hex edit. Must also be able to spawn <feature> linked tile.

In game action: player <a> on switch, wall turns into statue. Or statue turns into monster. Or (note: this would be great) a lxy teleport is activated (!!!)



These might not be possible, but more coding based brilliance than mine, halp :)
User avatar
Catherine
English correct bastard.
 
Posts: 1250
Joined: Mon Sep 08, 2003 2:40 am

Re: the scripting thread

Postby LordMortiferus » Sat Aug 09, 2014 4:18 am

Here is a simple step-script that spawns a goblin near the stp-fea. Additionally a dragon egg is spawned at 0'0" with a heartbeat func as timer. When the time is up the egg dies and the stp can be triggered again.

Code: Select all
function cat_stp_spawn(id,x,y,z)
   -- spawn mob(s) around stp-fea
   for i = 1,4 do
      m = spawn_at(0x200, x, y, z, false)
      simple_send_event(m.id,EVENT_MAGIC,0x25,m.x,m.y)
   end
   local_msg(m, "It is a goblin!")
   
   
   -- spawn timer (should be placed at unreachable position of the map)
   m = spawn_at(0x364, 0, 0, z, false)
   
   
   -- save x,y coords to timer
   m:set_dmg_dice(x)
   m:set_dmg_sides(y)
   
   -- set timer
   m.timer = 10
   m.heartbeat_func="cat_timer"   
   
   -- deactivate stp-fea
   map=get_map_ptr(z)
   map:set_feat_val(x, y, 0)
end

function cat_timer(m)
   -- timer
   m.timer = m.timer - 1
   if m.timer <= 0 then
      
      -- retrieve x,y coords for stp-fea
      local x = m:get_dmg_dice()
      local y = m:get_dmg_sides()
      
      -- reactivate timer
      map=get_map_ptr(m.map_level)
      map:set_feat_val(x, y, 1)
      
      -- kill off timer
      hurt(m.id,m.hp+1,"time is up")
   end
end
Last edited by LordMortiferus on Sat Aug 09, 2014 6:18 pm, edited 2 times 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 Catherine » Sat Aug 09, 2014 5:24 am

LordMortiferus wrote:function cat_stp_spawn(id,x,y,z) Do these variables need values?
m = spawn_at(0x200, x, y, z, false) X,Y is obvious, is the Z a level code? e.g. 34,75, >269<? What is the true/false variable?
simple_send_event(m.id,EVENT_MAGIC,0x17,m.x,m.y) Do the X, Y co-ords here have to match up? Also, is there a list of EVENT_ types? Can we color them etc? e.g. is it possible to have say, a lightning bolt spring from a maptile to another maptile?

m = spawn_at(0x364, 0, 0, z, false) Same question about z variable here


m:set_dmg_dice(x) Do these variables matter? The mob is not designed to interact with anything. i.e. 1, 1?
m:set_dmg_sides(y)


m.timer = 10 Is this seconds or minutes?


map=get_map_ptr(z) Z = map #?
map:set_feat_val(x, y, 0) More X,Y co-ords! since they're not using m.call, I take it these have to be manually changed?
end

map=get_map_ptr(m.map_level) This is calling the initial spawn - so that should have a map # in it
map:set_feat_val(x, y, 1)




That's fantastic, thank you! Using 3rd party non-accessible stuff for triggers has a long history (AO had invisible leets, I've used it elsewhere), didn't think that you could use LUA for it.

This will allow for Indiana style count-downs on events. i.e. Step on plate, trigger a count-down until X happens. In the above case, the spawner is triggered immediately. If you want to use a delay + reset, I presume there's a timer delay that can effect the initial trigger? i.e. The first (event) trigger can have a delay? And the count-down reset would be separate.

One last question - does the engine care if you spawn multiple dragon eggs on top of each other? Or should they each have a unique tile placement? (in case of multiple triggers if there's say a party of people spread out over a map)
User avatar
Catherine
English correct bastard.
 
Posts: 1250
Joined: Mon Sep 08, 2003 2:40 am

Re: the scripting thread

Postby LordMortiferus » Sat Aug 09, 2014 6:01 am

Here is a code snippet that kills off all enemies around you in a fearsome explosion when stepping on a stp-fea:
Code: Select all
function cat_stp_desintegrator(id,x,y,z)
   p = get_sent_ptr(id)
   local sx=x-4
   local ex=x+4
   local sy=y-4
   local ey=y+4
   for yy=sy,ey do
      for xx=sx,ex do
             ptr=map:get_mon_ptr(xx,yy)
         if ptr~=nil and ptr:get_align()~=p:get_align() then
            send_event(m.map_level,-1,ptr.x,ptr.y,26,0)
            hurt(ptr.id,ptr.hp+1,"Boooom")
         end
      end
   end
end

1) Paintbrush is for mtiles only atm afaik - guess egg could make a second paintbrush for items only.
2) The misbehaving undertiles are due to recent changes how undertiles work with certain mtiles like paths. The downloadable version of Maped needs to be updated - best bug egg about it ;)

# function cat_stp_spawn(id,x,y,z)
when you step on a stp-fea that has a function attached to it your id and the coords of the stp-fea are assigned to id, x, y, z respectively. This means x,y,z in this function are the coords of the stp-fea.

# m = spawn_at(0x200, x, y, z, false)
0x200 is a goblin
x,y,z are the coords with z being the level number
false just means that a field of vision update is not triggered when the mob is spawned (I guess)

# simple_send_event(m.id,EVENT_MAGIC,0x17,m.x,m.y)
I added this line to have a visiual indication when a mob is spawn (spell 0x17 KVX summon dragon - just the red box lights up around the mob but no dragon is summond)
m.x, m.y are the coords of the spawned monster but could be anything
dunno what you mean by color them
sending lightning from point a to point b is possible using:
Code: Select all
void  send_event(int lev, int id, int x, int y, int typ, int subtype, int tx=-1, int ty=-1);

# m:set_dmg_dice(x) m:set_dmg_sides(y)
I had to somehow pass the x,y coords of the stp-fea over to monster function. This is needed so the monster knows where the stp-fea is and can manipulate it.

# m.timer
this is just a number. Within the heartbeat script of the mob (function cat_timer(m)) this number is counted down every second by the value of 1 (m.timer = m.timer - 1)

# map=get_map_ptr(m.map_level)
to change features you need to have the pointer (map) of the respective level, in this case it is the level the mob is (m.map_level). In the initial stp-fea function I used z instead of m.map_level. (note again z was assigned a value by and within the function cat_stp_spawn(id,x,y,z))

I hope I was able to explain stuff without writing down too much bs.
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 LordMortiferus » Sat Aug 09, 2014 6:08 am

Catherine wrote:This will allow for Indiana style count-downs on events. i.e. Step on plate, trigger a count-down until X happens. In the above case, the spawner is triggered immediately. If you want to use a delay + reset, I presume there's a timer delay that can effect the initial trigger? i.e. The first (event) trigger can have a delay? And the count-down reset would be separate.

One last question - does the engine care if you spawn multiple dragon eggs on top of each other? Or should they each have a unique tile placement? (in case of multiple triggers if there's say a party of people spread out over a map)


1# If I understand you correctly your plan is that stepping on a stp-fea does not immediately spawn a mob but with a delay. This is possible by using the dragon egg timer which is immediately spawned. Instead of the mob being spawned by the stp-function it can be spawned by this timer after a given time.

2# The dragon egg will be spawned on a free tile near the given coords if those are occupied, but it would be best if you give any timer unique coordinates.
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 LordMortiferus » Sat Aug 09, 2014 6:30 am

the yellow tile calls cat_stp_spawn and the red calls cat_desintegrator
Image
excuse the lousy gif quality
also have edited the cat_stp_spawn function in the previous post - now it spawns 4 goblins with an ijo spell effect instead of the kqx or whatever it was.
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 Catherine » Sat Aug 09, 2014 9:33 am

# m = spawn_at(0x200, x, y, z, false)

Egg's example used:

Code: Select all
spawn_at(0x21d,3,3,z)
      spawn_at(0x21d,11,3,z)
      spawn_at(0x21d,3,11,z)
      spawn_at(0x21d,11,11,z)


This spawns a single goblin or single mobs at specific areas. Not what I was after - how do you set it as a spawner with a radius / multiple #s? Ideally, the # would be randomized as well. e.g. 4-10 spawn radius 4 centered on the stp trigger. Or is
Code: Select all
for i = 1,4 do
a radius?

Also, why I asked for an EVENT_ list is that instead of the summoning bling, I'd like an earthquake. EVENT_"ivpy"? Just giving me the example "void" doesn't really help if I don't have the list of variables. :/


Also, is it possible to have two scripts attached to mobs? e.g. Stp spawner that can be modified by global heroic / epic versions? What about mobs that already have coded behaviours? (e.g. slimes, corpsers, gazers etc). Specifically - are mobs spawned by trigger events modded by global scripts? A bit useless if the heroic / epic versions spit out bog standard versions ;)


p.s.

Current map is 25% done, the paintbrush tool is just epically easy (with manual fine tuning for visual goodness).


Code: Select all
function corpserambush_spawn(id,x,y,z)
   for i = 1,4 do
      m = spawn_at(0x265, x, y, z, false)
      simple_send_event(m.id,EVENT_IVPY,0x25,m.x,m.y)
     void make_paralyzed(int id, int 10)
   end
   local_msg(m, "You hear a rumble and corpsers burst from the ground, throwing you to your knees!")
 
   m = spawn_at(0x364, 0, 0, z, false)
   m:set_dmg_dice(x)
   m:set_dmg_sides(y)
   m.timer = 30
   m.heartbeat_func="corpser_timer"   
   map=get_map_ptr(z)
   map:set_feat_val(x, y, 0)
end

function corpser_timer(m)
   -- timer
   m.timer = m.timer - 1
   if m.timer <= 0 then
      local x = m:get_dmg_dice()
      local y = m:get_dmg_sides()
      map=get_map_ptr(m.map_level)
      map:set_feat_val(x, y, 1)
      hurt(m.id,9999,"time is up")
   end
end


In the above, I'm aiming to set a direct ambush but don't know how to set the # or radius of the corpsers, don't know the IVPY shake effect - also, not sure about the player void ID? presume t = time, in seconds?

I'd also prefer a version so that the local msg is sent, there are two timers - one counts down 5 seconds before they burst, the other handles the reset.
User avatar
Catherine
English correct bastard.
 
Posts: 1250
Joined: Mon Sep 08, 2003 2:40 am

Re: the scripting thread

Postby LordMortiferus » Sat Aug 09, 2014 4:41 pm

Catherine wrote:This spawns a single goblin or single mobs at specific areas. Not what I was after - how do you set it as a spawner with a radius / multiple #s? Ideally, the # would be randomized as well. e.g. 4-10 spawn radius 4 centered on the stp trigger. Or is for i = 1,4 do a radius?

The for i = 1,4 do is a loop, means whatever is inside the loop is called, in this case, four times, hence four goblins are spawned. If you want a random number of mobs to be spawned than you could do something like this:
Code: Select all
   for i = 1,math.random(4) do
      m = spawn_at(0x200, x, y, z, false)
      simple_send_event(m.id,EVENT_MAGIC,0x25,m.x,m.y)
   end

math.random(4) will generate a random number between 1 and 4 in this case.
As to the spawn radius, you could set x,y manually for each spawn or again use math.random, e.g.:
Code: Select all
spawn_at(0x200, x+math.random(-5,5), y+math.random(-5,5), z, false)

Why did I wrote m = before spawn_at and egg did not in his example. The m is a pointer for the spawned mob and is need if you want to manipulate it (change stats) or like I did want to sent an event magic effect.
Catherine wrote:Also, why I asked for an EVENT_ list is that instead of the summoning bling, I'd like an earthquake. EVENT_"ivpy"? Just giving me the example "void" doesn't really help if I don't have the list of variables. :/

Void just means that you cannot extract information from said function, unlike int, boolean or string. To call an ivpy effect I used the following code:
Code: Select all
p=get_player_ptr(id)
send_event(p.map_level,p.id,p.x,p.y,EVENT_QUAKE1, 0 , p.x, p.y)

Instead of a mob calling that event it is the player who steps onto the stp-fea (I would use this approach as it does not matter effect wise if one (player) or more id's (mobs) call the ivpy event as ivpy blends over each other - but it would probably be easier on the performance).
Gonna try to answer the rest later - baby is crying...

Code: Select all
enum event_nums {

   EVENT_STEP=0,
   EVENT_MAGIC,
   EVENT_HIT,
   EVENT_MISS,
   EVENT_QUAKE1,
   EVENT_QUAKE2,
   EVENT_MISSLE,
   EVENT_TRAP,
   EVENT_GUN,
   EVENT_LASER,
   EVENT_HIT2,
   EVENT_WHIT,
   EVENT_TELE,
   EVENT_TELEFRAG,
   EVENT_FDEATH,
   EVENT_MDEATH,
   EVENT_WDEATH,
   EVENT_BLOCKED,
   EVENT_PARRIED,
   EVENT_RIPOSTE,
   EVENT_PORTAL_UP,
   EVENT_PORTAL_DOWN,
   EVENT_STEAL,
   EVENT_SHOOT, // not gun!
   EVENT_THUNDERCLAP,
   EVENT_CRITICAL,
};

Catherine wrote:Also, is it possible to have two scripts attached to mobs? e.g. Stp spawner that can be modified by global heroic / epic versions? What about mobs that already have coded behaviours? (e.g. slimes, corpsers, gazers etc). Specifically - are mobs spawned by trigger events modded by global scripts? A bit useless if the heroic / epic versions spit out bog standard versions ;)

Mobs spawned by scripts are not affected by the heroic/epic scale script. However, you can use a trick to determine if you are in a heroic or epic instance respectively. Lets say you add a mapspawner via maped to your level at the coords 1'1" and let it be a again a dragon egg. Under normal instances this egg has hp = 1000. Within an instance it would be 3000 and 5000 respectively. If it is a boss the hp would be multiplied by 2 and if it is an unusual large boss it would be further multiplied by 3.
Code: Select all
-- coords of dragon egg - ms will be the pointer to the dragon egg
ms = get_mon_ptr(1, 1)
-- get HP multiplier
local c = ms:get_hp_max() / 1000
-- rectify hp multiplier if the egg is a boss (I doubt that can happen but you never know)
if ms.boss == true then
   c = c / 2
   --rectify hp multiplier further if the boss egg is large
   if ms.large == true then
      c = c / 3
   end
end
-- calls a function to scale a creature. m is the pointer to the mob that is to be scaled, c is the multiplier, 0 would be the loot quality multiplier
scaleCreature(m, c, 0)

As to the function you wrote:
For ivpy see above.
void make_paralyzed(int id, int 10) as said before void only indicates that the function make_paralyzed does not return any value. "int id" would be the player number you want to paralyze and the last "int" argument would probably be the time (never used this function to paralyse a player myself)
How I would do it:
Code: Select all
p=get_player_ptr(id)
set_health(p.id,HN_HELD,4)

The first line we only need if p was not defined earlier. The second line sets the player who stepped on the stp-fea to HELD for 4 seconds.

Note: to write scripts I recommend the use of notepad++ - when you save your file with the *.lua extension the program will recognize it as code and add color to it for better readability.
Note: did a slight change in the hurt() line in my above posted cat_timer function.
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: No registered users and 1 guest

cron