[Coding #1099] The right way to do things

NOTICE: This forum is archived as read only.
Please use the Github Discussions at https://github.com/exult/exult/discussions
Forum rules
NOTICE: This forum is archived as read only.
Please use the Github Discussions at https://github.com/exult/exult/discussions
Locked
Andrea .B. Previtera

[Coding #1099] The right way to do things

Post by Andrea .B. Previtera »

The more I progress into coding my game, the more I end doing things exactly like they're done into exult/U7. For instance, I didn't think I needed barges - then while writing part of the editor I ended up coding some data structures to hold multiple item selection, rotation and so on ... and ta-daa, I had barges. Same thing with the pathfinding code, tile/chunk structure and so on.

It's amazing discovering that there seems to be a single right way to code a rpg world of this kind, the way U7 was done ... and re-done in Exult step by step. Just like those mathematicians use to say "you do not create math, you discover it".
Mel C.

Re: [Coding #1099] The right way to do things

Post by Mel C. »

I know what you mean.

I am working on my own UO shard, and what I want to do is customize it to be more like U7. Npcs with daily routines, for starters, instead of just standing there like dummies responding to "Vendor buy".

A lot of great features of U7 were thrown out when they made UO, I guess because they were too difficult to code them in to fit a massive number of players. I won't have that many players, though, just myself and friends, so I can do more of that stuff.

I'm also working on better paperdolls for UO and customizable character portraits. I have always hated the UO ones - they're so slack and stupid-looking, whereas the ones in U7 are great. You put the sword in the paperdoll's hands and it automatically assumes a fighting stance.

And the portraits that come up when characters speak...I love those. I am trying to figure how to do this for UO, too.

I guess the UO designers assumed they wouldn't need realistic NPCs because players would fill that role. But it's not very fun when the people you're depending on for realism are running around yelling, "I RoXxoReD JoO."

UO makes me long for U7. I love U7.
Andrea .B. Previtera

Re: [Coding #1099] The right way to do things

Post by Andrea .B. Previtera »

And with today, another "ultima 7 mechanism" I didn't think I needed, enters my code: *item quality*

By the way: I get how the *construction* of barges work, how to rotate them and so on. But how are they integrated into the world? I mean, if you want to place a ship somewhere, how does that work?

Let's say that you place a barge, and all items are automatically, conveniently placed where they should be. Some items fall on tile (X1,Y1) others on tile (X2,Y2) and so on. What keeps them tied? Is that a flag of some sort on each items which says "I am owned by barge N" or is there a global structure holding all the barges in the world?
drcode
Site Admin
Posts: 2267
Joined: Thu May 14, 2020 1:34 pm

Re: [Coding #1099] The right way to do things

Post by drcode »

First, there's the barge 'object', which shows up as a red outline when you enable eggs. Its main attribute is its footprint, which is the # of tiles it covers.

All the other pieces are just arranged normally on top of the barge's footprint so they look right. When Exult moves a barge, it calls a method called 'gather()' which finds all objects on the barge's footprint so they can be moved together. This is why you can place your own items on a ship and have them move with the ship. (It's also why we've had bugs where something like a sheep gets stuck on the magic carpet.)

If I recall (code's not in front of me), there are several shapes that are categorized as 'barge parts' (see shapeinf.h), but I don't remember the significance.
Andrea .B. Previtera

Re: [Coding #1099] The right way to do things

Post by Andrea .B. Previtera »

Aaah! Smart! So let me recap to see if I understood correctly:
there's a special "barge" object, which is like an invisible grid.
All items falling on such grid are moved along with it.
Exquisite.
Andrea B Previtera

Re: [Coding #1099] The right way to do things

Post by Andrea B Previtera »

This weekend I surrendered to Chunks: I always coded everything to be completely dynamic, but at last I saw the light coming from the Chunk structure. Now, at the cost of a somewhat more rigid world structure and another editing tool (to build chunks), a good number of issues auto-solved.

*sigh*
Colourless
Site Admin
Posts: 731
Joined: Thu May 14, 2020 1:34 pm

Re: [Coding #1099] The right way to do things

Post by Colourless »

Using chunks or whatever other name you want to call them, is a coarse, simple, but yet very effective compression scheme. If done right it reduces memory requirements, create a nice structure to store and sort data in, and can greatly improve general efficency in item management.
Andrea B Previtera

Re: [Coding #1099] The right way to do things

Post by Andrea B Previtera »

Before I used only 5 bytes (x,y,z,id) per item, and I had a complex system to know if a chest was locked, if something was owned by the party or not, and so on..

Now I use 30 bytes or so per item, but since most of the world items are fixed in chunks the memory usage is even decreased. Only, I always found a bit limitating and tricky that you have to pre-cook the chunks and then you can use them.

Useless to say, re-doing all the core structure of the world was a legendary pain in the ass... but once again the Ultima 7 technology prevails!
SB-X
Posts: 980
Joined: Thu May 14, 2020 1:34 pm

Re: [Coding #1099] The right way to do things

Post by SB-X »

Only, I always found a bit limitating and tricky that you have to pre-cook the chunks and then you can use them.
If your world editor supports it, can't you just create your terrain as you normally would, but from that point on make it available as a chunk? The only thing to be aware of is when to use an already made chunk instead of making a new one.
drcode
Site Admin
Posts: 2267
Joined: Thu May 14, 2020 1:34 pm

Re: [Coding #1099] The right way to do things

Post by drcode »

I think the use of chunks is also a good way to constrain the people who are building the map, so that they don't create 1000 'grass' chunks when they could share a few throughout the world.

SB-X: That's pretty much how ExultStudio works, though you have to enter a special mode when you're working on the chunk.
Alun Bestor

Re: [Coding #1099] The right way to do things

Post by Alun Bestor »

One design concept I've liked is a linking structure, whereby you make explicit links between an object and any related objects. This structure is done very well in Dark, the engine used by Thief 1 and 2.

As a U7 example: instead of assigning qualities to doors and keys to indicate which key opens which doors, you would create links from the key to all the doors it opens. Likewise, for a barge, the barge object would have links to all relevant objects instead of "everything inside region X".

On the face of it this is a lot less flexible, but it makes it much easier for designers to program and maintain the gameworld - it makes relationships much more visible and there's no need to recall what qualities/flags correspond to what objects, because the editor can show the existence of links.
drcode
Site Admin
Posts: 2267
Joined: Thu May 14, 2020 1:34 pm

Re: [Coding #1099] The right way to do things

Post by drcode »

I agree, that's a nice idea, though it would make save/restore somewhat harder (serialization would be required).
Andrea B Previtera

Re: [Coding #1099] The right way to do things

Post by Andrea B Previtera »

Thanks! I am implementing both the suggestions.

It's undoubtely easy including in the world editor a command which says "take this chunk and make it unique" although I fear it may lead to some confusion or chunk duplication now and then.

As for the "linking structure", that's certainly the way to do things. When saving/restoring you won't just save a couple bytes but you'll have to backtrace a few pointers... but it's worth the rewrite of the save/restore code.

Now, I talk for myself and my engine - but I think that the experimental code path of Exult should aim to rewrite parts of the engine in order to make the world editing experience less exhausting. Everyone loves U7 and there's plenty of graphic to use, if one wants to make a new game without necessarily creating news content from scratch - then why no new game, not even a little "data disk" has surfaced yet?
drcode
Site Admin
Posts: 2267
Joined: Thu May 14, 2020 1:34 pm

Re: [Coding #1099] The right way to do things

Post by drcode »

There's the "Island Patch", still unfinished. I'm probably going to finish it soon.
Alun Bestor

Re: [Coding #1099] The right way to do things

Post by Alun Bestor »

And I'm working on a patch to add new item behaviours and some small subquests to the main U7 game.

But yes, editing is a bit of a pain in the hole, especially since I've needed to completely reimplement every object and NPC that will have new behaviour. The joys of messing around with decompiled source...I'm starting to see goto statements when I close my eyes.

The more of this I do, the more I wish U7 had a heirarchical object structure. Right now, objects and NPCs get a single function that is called under restricted circumstances based on their shape number/NPC id. Great for simple cases, but very limited and very hard to extend.

It would be delightful if instead each object were expressed in usecode as an object definition inheriting from a common prototype (e.g. Item, NPC) with overrideable base methods (e.g. doSchedule(), talk(), onDoubleClick(), onCachedIn(), onPlayerNear(), onDeath() and the like).

This would move a lot of the stuff that really ought to be in usecode back into the usecode - such as schedule actions, attacked behaviours, death behaviours, single-click description names etc. Consider implementing a custom glass counter top this way:

class CounterTop extends Item
{
name = "counter top";
hitpoints = 1;

function onHitWithWeapon(var weapon, var culprit)
{
//do original function behaviour
Item.onHitWithWeapon(weapon, culprit);
alertGuards(); //call the guards
}
}

Currently, altering the descriptive name or hitpoints requires editing the item in Exult Studio (and you can't provide a custom name for individual frames yet), and there's no way to specify custom attacked behaviour. The alerting-the-guards behaviour is hardcoded for countertops (how would you solve this in a custom game? Use the exact same shape number?), and not yet implemented in Exult anyway.

I'm not asking for this to be added to Exult of course, since it would mean a huge rewrite of the existing data structures, just wishing it was there already ;)
Colourless
Site Admin
Posts: 731
Joined: Thu May 14, 2020 1:34 pm

Re: [Coding #1099] The right way to do things

Post by Colourless »

Odd, that is almost exactly how Ultima 8 works
Andrea B Previtera

Re: [Coding #1099] The right way to do things

Post by Andrea B Previtera »

And exactly how mine is working now too. The "event" structure of object-oriented stuff is perfect for usecoding purposes..
Alun Bestor

Re: [Coding #1099] The right way to do things

Post by Alun Bestor »

Huh! I suppose it makes sense that U8 did things that way, since it would be a logical progression from the U7 usecode. Which makes it even more of a pity that U7 was the one with the complex item interactions and autonomous NPC behaviour, and U8 was the one with the jumping puzzles ;)


Also, it occurs to me that such an implementation *could* be retrofitted to U7, as long as the original implementation could still work alongside it.

One way to specify this would be to give a class definition the appropriate function address (a la the current usecode style), but a more flexible solution would be 'binding' functions for shapes, NPCs and frames.

class CounterTop extends Breakable //Breakable is a child class of Item
{ ... }

bind_shape(518, CounterTop); //518 is the shape # for glass counter tops

This would make Exult look to CounterTop for all instances of shape 518 in the game world, instead of to function 0x206.

Having a function to make these bindings explicit would allow several shapes to be bound to the same class. A bind_frame(var shape, var frame, var class) function could allow overrides for specific frame #s: no need to have a single function handle 24 different kinds of desk item!

These bindings would only be honoured at game creation time - any object that changes its shape or frame in-game would continue to use the same class. Since only new items would use this scheme, this it wouldn't break the original shape behaviours.

Now, if only I had the slightest clue how to implement such a thing.
Locked