Angband.oook.cz
Angband.oook.cz
AboutVariantsLadderForumCompetitionComicScreenshotsFunniesLinks

Go Back   Angband Forums > Angband > Development

Reply
 
Thread Tools Display Modes
Old December 14, 2014, 21:13   #1
Therem Harth
Knight
 
Therem Harth's Avatar
 
Join Date: Jan 2008
Location: New England winter
Posts: 908
Therem Harth is on a distinguished road
YASV, need some advice

I've started another variant:

https://gitorious.org/specband

Unfortunately I seem to be in over my head already.

So: player specialties. Depending on which specialty you pick, you get bonuses when certain things happen. A swordmaster can parry and riposte when attacked; a device specialist will get buffs from using devices; a kickboxer will get melee bonuses for wearing sturdy boots; etc. etc.

I can see how to implement this. The problem is, I can't see how to implement it in a way that isn't a spectacular mess. I don't want to have checks for different specialties spread throughout the code.

Is there any way to do this in a neater, more centralized fashion? Preferably without rewriting the whole Angband code base?

I have some vague (and vaguely similar) ideas, based on my experiences with Neoband - object-like structs, polymorphism, callback functions, etc. But they either require extensive modification to the existing code; lack flexibility; or are just plain ugly.

Anyone willing to give me some tips? I know O, FA, and ToME 2 all have stuff like this, but that seems to be based on if/else checks spread out everywhere, from what I've seen of their sources.
Therem Harth is offline   Reply With Quote
Old December 15, 2014, 12:17   #2
Nick
Vanilla maintainer
 
Nick's Avatar
 
Join Date: Apr 2007
Location: Canberra, Australia
Age: 54
Posts: 7,703
Donated: $60
Nick is on a distinguished road
Quote:
Originally Posted by Therem Harth View Post
Is there any way to do this in a neater, more centralized fashion?
I'm inclined to say no. If you have a swordmaster parrying when attacked, then IMHO the logical place for that to be dealt with is in the attack code. In fact, I have come to the firm view that the code should as much as possible make sense by mimicking the game world. The logic then goes "If a swordmaster is attacked, they get a chance to parry", and the code almost writes itself.

This is indeed, as you've observed, the way it's done in O/FA, so it's what I'm familiar with. I don't think that's influencing me, though - I think it just represents the fundamental extra complexity you're adding to the game by introducing such specialties.

I'd also like to say that I think future variants are probably (even at this stage) better based off the current restruct branch, and not just because it gives me more bugfinders
__________________
One for the Dark Lord on his dark throne
In the Land of Mordor where the Shadows lie.
Nick is online now   Reply With Quote
Old December 15, 2014, 15:54   #3
Derakon
Prophet
 
Derakon's Avatar
 
Join Date: Dec 2009
Posts: 8,805
Derakon is on a distinguished road
Yeah, I'm with Nick here. If you wanted to be "clean" about it, you'd do so by finding a way to make your custom-behaviors logic more modular. Pyrel's approach to this is to make such behaviors pluggable -- that is, you have a bunch of different functions that can be inserted at various points in the code, and each class (or species of monster, or race, or item, etc.) has various functions they can trigger. Pyrel calls these "procs".

So for example, your Swordmaster would have a proc (a.k.a. function) attached to them whose trigger condition is "when the character is attacked". When you reach the "character is attacked" point in the code, you iterate over all procs you have that have that trigger condition, and invoke all of them. This would invoke the Swordmaster's ability, which would run his custom code, which would have a chance of nulling the attack and printing a special message.

I don't know how straightforward this would be to do in C. It's certainly possible, since C has function pointers and that should be all you need, but you're opening yourself up to a lot of tricky bugs because you lose all ability for static type-checking when you use function pointers, and C has lots of ways for dynamic type-checking to fail and create really hard-to-debug errors. I spent a fair amount of time thinking about how to best implement procs (and arguing with various other people on these forums, as I recall ), and I was working in Python, which is a lot more flexible than C.
Derakon is offline   Reply With Quote
Old December 15, 2014, 16:06   #4
AnonymousHero
Veteran
 
AnonymousHero's Avatar
 
Join Date: Jun 2007
Posts: 1,367
AnonymousHero is on a distinguished road
Quote:
Originally Posted by Derakon View Post
I don't know how straightforward this would be to do in C. It's certainly possible, since C has function pointers and that should be all you need, but you're opening yourself up to a lot of tricky bugs because you lose all ability for static type-checking when you use function pointers, and C has lots of ways for dynamic type-checking to fail and create really hard-to-debug errors. I spent a fair amount of time thinking about how to best implement procs (and arguing with various other people on these forums, as I recall ), and I was working in Python, which is a lot more flexible than C.
It's certainly possible in C, though, as you say a bit more error prone. This is, in fact, the way extensibility is achieved in Tome 2.x -- it just calls them "hooks". It's somewhat limited in what you can do with though -- if you don't use global variables (which you shouldn't!) then you're pretty limited in what a given hook can actually do. If the person who added the hook didn't include enough in the hook input/output (or the hook is in the wrong place), it's not going to be possible to do it.

(This is quite similar to Aspect-oriented Programming, but a lot more restricted. Just as with AoP, if you go too far down this road everything becomes spaghetti.)
AnonymousHero is offline   Reply With Quote
Old December 15, 2014, 16:17   #5
Derakon
Prophet
 
Derakon's Avatar
 
Join Date: Dec 2009
Posts: 8,805
Derakon is on a distinguished road
Quote:
Originally Posted by AnonymousHero View Post
It's certainly possible in C, though, as you say a bit more error prone. This is, in fact, the way extensibility is achieved in Tome 2.x -- it just calls them "hooks". It's somewhat limited in what you can do with though -- if you don't use global variables (which you shouldn't!) then you're pretty limited in what a given hook can actually do. If the person who added the hook didn't include enough in the hook input/output (or the hook is in the wrong place), it's not going to be possible to do it.
I suspect that to do this in C, you'd have to decide on a function signature for each hook which would provide the necessary context and determine how the return type is evaluated. Of course the compiler won't enforce this for you, but any proc/hook/whatever that doesn't use the signature correctly wouldn't work properly anyway. Better than using global variables!

Quote:
(This is quite similar to Aspect-oriented Programming, but a lot more restricted. Just as with AoP, if you go too far down this road everything becomes spaghetti.)
This is a common problem with any "I need more flexibility" design pattern.
Derakon is offline   Reply With Quote
Old December 15, 2014, 17:03   #6
AnonymousHero
Veteran
 
AnonymousHero's Avatar
 
Join Date: Jun 2007
Posts: 1,367
AnonymousHero is on a distinguished road
Quote:
Originally Posted by Derakon View Post
I suspect that to do this in C, you'd have to decide on a function signature for each hook which would provide the necessary context and determine how the return type is evaluated. Of course the compiler won't enforce this for you, but any proc/hook/whatever that doesn't use the signature correctly wouldn't work properly anyway. Better than using global variables!
Exactly. In T2 when I converted all the Lua to C, I just created one struct definition for each hook, so you'd have e.g. give_hook_in/give_hook_out structs and talk_hook_in/talk_hook_out structs, etc. At the point in the C code where the hook was invoked, I'd create the necessary X_hook_in structure and call the general hook mechanism, and casting its result to a X_hook_out structure. It was then up to the caller of "add-this-function-to-X-hook" to make sure that the function would cast its argument to a (pointer to) X_hook_in and return a (pointer to) X_hook_out.

It's not *that* bad from a type safety perspective, it just requires a little boilerplate/discipline to make sure you always cast appropriately at the start of the hook function. (Perhaps macros could be used to reduce the boilerplate, but I didn't really investigate.)

My point re: global variables was mostly just that if the provider of a X_hook_in structure didn't give you enough to do what's necessary, you could (in the global-infested T2 code base at least) just access whatever global variables/functions you wanted and hope for the best. Needless to say this leads to an even bigger mess over time.

Quote:
Originally Posted by Derakon View Post
This is a common problem with any "I need more flexibility" design pattern.
Indeed.

In general, designing everything as independent libraries (rather than a "framework" with hooks) almost always turns out better. IME, at least.
AnonymousHero is offline   Reply With Quote
Old December 15, 2014, 19:03   #7
Therem Harth
Knight
 
Therem Harth's Avatar
 
Join Date: Jan 2008
Location: New England winter
Posts: 908
Therem Harth is on a distinguished road
Quote:
Originally Posted by AnonymousHero View Post
In general, designing everything as independent libraries (rather than a "framework" with hooks) almost always turns out better. IME, at least.
What exactly would this mean, in the context of the Angband code base? Or is it too late for that?
Therem Harth is offline   Reply With Quote
Old December 15, 2014, 19:34   #8
AnonymousHero
Veteran
 
AnonymousHero's Avatar
 
Join Date: Jun 2007
Posts: 1,367
AnonymousHero is on a distinguished road
Quote:
Originally Posted by Therem Harth View Post
What exactly would this mean, in the context of the Angband code base? Or is it too late for that?
Theroetically possible, I suppose, but realistically it's never going to happen. (It would be akin to "restruct"^3 or something like that.)

The idea would be to fully separate everything from each other into "modules", only relying on as-small-as-possible APIs between modules. For example, all the display-related stuff would be completely separate from the game engine stuff, which would again be separate from the file-parsing, etc. etc.) Obviously there's no such thing as a completely generic APIs, but one could imagine the Angband UI code rewritten into something akin to termbox, etc. etc. The whole engine bit would become an API in its own right and *wouldn't* call directly into UI code, etc.
AnonymousHero is offline   Reply With Quote
Old December 15, 2014, 20:11   #9
MattB
Veteran
 
Join Date: Mar 2013
Location: Berkshire, UK
Posts: 1,148
MattB is on a distinguished road
Pyrel already has this
MattB is offline   Reply With Quote
Old December 15, 2014, 20:58   #10
Nick
Vanilla maintainer
 
Nick's Avatar
 
Join Date: Apr 2007
Location: Canberra, Australia
Age: 54
Posts: 7,703
Donated: $60
Nick is on a distinguished road
Quote:
Originally Posted by AnonymousHero View Post
The idea would be to fully separate everything from each other into "modules", only relying on as-small-as-possible APIs between modules. For example, all the display-related stuff would be completely separate from the game engine stuff, which would again be separate from the file-parsing, etc. etc.)
That's interesting. This is kind of the spirit of what we're doing with the restructure, without having gone the whole way there. Certainly we've had discussions along the lines of "UI and core need to talk to each other like client and server", and we're trying to separate "functional units" as much as possible.

I also should note that I'm happy to get some validation for my naive approach from some real programmers
__________________
One for the Dark Lord on his dark throne
In the Land of Mordor where the Shadows lie.
Nick is online now   Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 22:28.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2019, vBulletin Solutions Inc.