Scripts and NPC instancing
(note rss readers like googlereader screw over the css. this post is best viewed directly and not via rss)
Adam asked me about game data and instancing, and my reply more or less became a full post, so here it is instead of buried in the comments.
When a town/dungeon is entered, the controlling script for that object is loaded and a Main() is called.
310:
311:function Main()
312: -- load the tileset and build the tiles for map type
313: SetVar(var_MapWidth, 96)
314: SetVar(var_MapHeight, 96)
315: LoadMap("PORTSMOUTH", "GFX/TILESET_INDOORS.BIN", TOWN_MAP);
316:
317: -- Set players row/col/map
318: SetPlayerPos(82, 48, map_PORTSMOUTH);
319:
320: CreateEvents();
321:
322: -- prefetch the initial map segments
323: LoadMasterMapSegment();
324:end
325:
326:Main()
You can see main does some basic things like setting the size of the map and which tileset to load (if its not the current tileset already).
The real driver in that function is the CreateEvents call. This is what instances all the NPC’s and so-forth.
A cutdown CreateEvents looks like this;
237:
238:function CreateEvents()
239: local i
240:
241: -- create a line of exit events that border the map.
242: for i=1, 96 do
243: CreateEvent( event_WalkOver, i, 10, "EventExit")
244: CreateEvent( event_WalkOver, 83, i, "EventExit")
245: CreateEvent( event_WalkOver, 16, i, "EventExit")
246: end
247:
248: -- segment load callback
249: local xE = {
250: { type = event_SegmentLoad, row = -1, col = -1, f = "SegmentLoad" }
251: }
252:
253: for k,v in pairs(xE) do
254: CreateEvent( v.type, v.row, v.col, v.f )
255: end
256:
257: -- npc callback data
258: local s = {
259: -- gatekeepers
260: {row=75, col=52, name="GUARD", event="talk_npc_GUARD" },
261: {row=75, col=45, name="GUARD", event="talk_npc_GUARD" },
262: {row=72, col=45, name="GUARD", event="talk_npc_GUARD" },
263: {row=72, col=52, name="GUARD", event="talk_npc_GUARD" },
264: }
265:
266: for k,v in pairs(s) do
267: AddNPC(TILE_GUARD, MODE_GUARD, v.name, v.row, v.col)
268: if v.event ~= "" then
269: CreateEvent(event_Transact, v.row, v.col, v.event)
270: end
271: end
272:
273: CreateMerchant(TILE_PRIEST, MODE_MERCHANT, "MYSTIC", 42, 24, event_Transact, 42, 25, "EventTransactMystic")
274: CreateMerchant(TILE_MERCHANT, MODE_MERCHANT, "MERCHANT", 65, 24, event_Transact, 64, 24, "EventMeals")
275: CreateMerchant(TILE_GUARD, MODE_MERCHANT, "PUBLICAN", 23, 45, event_Transact, 24, 45, "EventPub")
276:end
277:
278:
This just registers different event types from (exit events, map segment loads, transactions). Each one is a lua function.. The CreateMerchant function is just a shortcut for AddNPC and CreateEvent with some flags..
The SegmentLoad callback is good for when you walk onto a new piece of map and the engine loads the data, you can use this callback to override the map. Say You have exploded the alchemist lab which blew a hole in the wall. This even can check the flag flag_BlewUpAlchemistLab and do some SetTile(row,col, tile) commands to turn some wall into some grass tiles or something. (Mostly I use it for adding those retro ultima style ‘words’ to the towns/shops.), but it does give me a programatical control of the map data.
ExitEvents are pretty basic, they are not a true event, but just a function used in conjunction with say a WalkOver event or EnterEvent
178:
179:function EventExit()
180: if AskQuestion("DO YOU WANT TO LEAVE TOWN", " YES ", " NO ") == " YES " then
181: PopMapStack()
182: SpawnMap(GetVar(var_PlayerMap))
183: else
184: -- pushback
185: if GetVar(var_PlayerFacing) == FACING_NORTH then
186: SetVar(var_PlayerRow, GetVar(var_PlayerRow) + 1)
187: elseif GetVar(var_PlayerFacing) == FACING_SOUTH then
188: SetVar(var_PlayerRow, GetVar(var_PlayerRow) - 1)
189: elseif GetVar(var_PlayerFacing) == FACING_EAST then
190: SetVar(var_PlayerCol, GetVar(var_PlayerCol) -1)
191: else
192: SetVar(var_PlayerCol, GetVar(var_PlayerCol) + 1)
193: end
194: end
195:end
196:
197:
I figure its nice to ask the player if they wish to leave the map, but its not a requirement, and because we know its a WalkOver event, we trigger a push back off the current cell back the way the player came. (One of lua’s nice features is its global string table, it only ever instances a string once, so I can duplicate my strings all over in a script and know that only 1 copy exists, not that I have a lot of duplicate text in my scripts).
Transaction events I’ve covered in script in other entries.
Back to Adams comment on respawning, You could respawn everyone in town (easy, no work required), or track whom you have and have not killed. I dont think I want to track a bitflag for every guard, wandering NPC or jester in every town
When you leave a map, all data for that map is purged from memory, including all NPC data. There is only some small global variables + flags that persist for the length of the game (basically the save file data).
Filed Under : Computers • Development • Fishguts •
Comments are closed Commented on by (1) people.