29 Jul, 2010, quixadhal wrote in the 41st comment:
Votes: 0
Tyche said:
ralgith said:
Or you could just use a different codebase that has already been modernized… such as tbaMUD. ;)


So what happens on tbaMUD when one casts an area spell that loops through the room damaging characters (like a chain lightning),
and a HITPRCNT trigger is run off a damaged mob that %teleports% the caster out of the room?


The *smart* way to do that kind of thing would be to decide if you want spells like this to be channeled, or fire-and-forget. If a spell is channeled, then interrupting the caster would make it stop at that point. If not, the spell would go through it's entire sequence, regardless. In the former case, you could stop the spell at the point the mobprog trigger took hit, stopping the chain reaction. In the latter, you could simply avoid processing the trigger until the spell routine finished (put all such triggers on a stack and process them at the bottom of the current round, in order).
29 Jul, 2010, ralgith wrote in the 42nd comment:
Votes: 0
Rarva.Riendf said:
ralgith said:
MMmm, I should have also added to the previous statement that I also believe the first possibility is the correct one. If you've already casted a spell in a room, it should affect the targets in that room. Not move with you. At least that's my view.


The way it works in this way will only depends on how the skill is coded, the engine has not a lot to do with it.
The engine can help with tools to ensure the loop works fine but then all is up to the coder.


Actually with CircleMUD (And thusly tbaMUD) the Engine has EVERYTHING to do with it. CircleMUD uses "routines" for spells. And all spells that use a certain routine (for example, mag_damage and mag_areas would be the ones used for chain lightning) use mostly the same code with a switch/case to set things like damage amount. This allows all the checks for proper targets and such to be done in one place easily. I love this system.


quixadhal said:
Tyche said:
ralgith said:
Or you could just use a different codebase that has already been modernized… such as tbaMUD. ;)


So what happens on tbaMUD when one casts an area spell that loops through the room damaging characters (like a chain lightning),
and a HITPRCNT trigger is run off a damaged mob that %teleports% the caster out of the room?


The *smart* way to do that kind of thing would be to decide if you want spells like this to be channeled, or fire-and-forget. If a spell is channeled, then interrupting the caster would make it stop at that point. If not, the spell would go through it's entire sequence, regardless. In the former case, you could stop the spell at the point the mobprog trigger took hit, stopping the chain reaction. In the latter, you could simply avoid processing the trigger until the spell routine finished (put all such triggers on a stack and process them at the bottom of the current round, in order).


But thats the thing, its really up to each MUD how they want the spells to work in the end. Default behavior doesn't "do it" for everyone.
29 Jul, 2010, quixadhal wrote in the 43rd comment:
Votes: 0
It's not so much a question of what a particular mud wants, as a question of what style of coding will make things predictable. The "normal" way things work is only predictable if the area effect spell is allowed to run to completion without any other functions being called. Things like mobprog triggers and such *currently* disrupt that process, so the context of the actor changes during iteration on their environment. This might cause iteration over a different set of victims, which is almost certainly not intentional.

However you want it to work, the method of iteration has to nail down the context so you are talking about the same set of victims throughout the entire process, regardless of what might happen to any of them, or what kind of triggers might change things.

Choosing to stop the process if your context is changed is still consistent. Continuing to act on the same set of people if your context changes is also consistent. Acting on some of the people in your old context and then some of the people in the new context is pretty shaky ground to walk on.
30 Jul, 2010, Rarva.Riendf wrote in the 44th comment:
Votes: 0
'Actually with CircleMUD (And thusly tbaMUD) the Engine has EVERYTHING to do with it. CircleMUD uses "routines" for spells. And all spells that use a certain routine (for example, mag_damage and mag_areas would be the ones used for chain lightning) use mostly the same code with a switch/case to set things like damage amount. This allows all the checks for proper targets and such to be done in one place easily. I love this system. '

That means all of your area spell works the same, except for the damages ? Or do I miss something ?.
As en example, how do you code than chain lightning will iterate through all targets, decreasing in damage, then reiteratinf over them till damage potential is depleted, up to hit the own caster itself if there is only one other people in the room ?

Or an earthquake that only hits non flying people ?

Or a breath that will hit harder the direct victim but less the other people , AND have special effects like targeting objects ?

All of this is coded in the skill, and the engine can only help you have valid target, give their rightful position etc, but not much otherwise you quite limitate yourlsef to lookalike spells.

I may miss something as I only know of ROM. But I doubt ANY engine can do the work. Without a lot of limitation that is.
31 Jul, 2010, David Haley wrote in the 45th comment:
Votes: 0
<Please use the quoting system, it's pretty easy to type, just
Quote
and then
(no spaces). :smile:>
31 Jul, 2010, Tyche wrote in the 46th comment:
Votes: 0
quixadhal said:
Tyche said:
So what happens on tbaMUD when one casts an area spell that loops through the room damaging characters (like a chain lightning),
and a HITPRCNT trigger is run off a damaged mob that %teleports% the caster out of the room?
The *smart* way to do that kind of thing would be to decide if you want spells like this to be channeled, or fire-and-forget.
Nobody seems to know what happens. I'm betting the mud crashes.
31 Jul, 2010, quixadhal wrote in the 47th comment:
Votes: 0
That's why I was saying, it doesn't matter how it currently works, decide how you WANT it to work and make it so. You may find that you end up with several "generic" handlers, to deal with spells that have friendly-fire or not, spells that have limited charges or not… or you might just have a generic area-effect handler and have to special-case the two or three things that don't fit the mold.

You chose a DikuMUD, presumably because you enjoy coding in C/C++. If that's not the case, you are in for a very long journey since you'll never find something that does everything the way you want it without having to write some code.
31 Jul, 2010, Tyche wrote in the 48th comment:
Votes: 0
quixadhal said:
That's why I was saying, it doesn't matter how it currently works, decide how you WANT it to work and make it so. You may find that you end up with several "generic" handlers, to deal with spells that have friendly-fire or not, spells that have limited charges or not… or you might just have a generic area-effect handler and have to special-case the two or three things that don't fit the mold.

You chose a DikuMUD, presumably because you enjoy coding in C/C++. If that's not the case, you are in for a very long journey since you'll never find something that does everything the way you want it without having to write some code.


I didn't ask the question because I didn't know that I could decide how I wanted something to work and make it so, because I sort of figured out what this icky C thingy stuff did awhile ago.
31 Jul, 2010, Rarva.Riendf wrote in the 49th comment:
Votes: 0
Quote
]That's why I was saying, it doesn't matter how it currently works

It does not matter if it works. Since most engines are broken, it actually matters to know how it works to avoid to use it in a way that will crash it. And to be able to fix it.
I personnaly think most complex skills/spells cannot be handled gracefully without coding the skills yourself as soon as they do more than a simple damage.
Engine is there to provide you valid targets, rooms, but then it is up to you to use them to your liking. Adding everything in the engine will only make it more complex and buggy.
And after a while it will become impossible to see the logic behind it, while if a skill/spell crash ou only have one routine to check, and modifying it wont affect everything else.
01 Aug, 2010, Elervan wrote in the 50th comment:
Votes: 0
Looking through a modified ROM code I have it uses this for the chain_lightning end.

damage_old (ch, ch, dam, sn, DAM_LIGHTNING, TRUE);
if (killed_by_chain) {
killed_by_chain = FALSE;
return;
}
level -= 4; /* decrement damage */
if (ch == NULL || ch->fighting == NULL)
return;
}


I'm still trying to figure out WHAT version of ROM they started with, I want to say ROM2.3 or they may have even used Merc 2.0 and used things out of ROM, but this was changed back in 1996(97).

So how far exactly is ROM behind on the times as far as keeping up with what kind of resources a M.U.D. can use now, versus back when they were started. Now if one were to clean up ROM, would it be better to sacrifice memory usage for performance, or try and save memory and dwindle on performance?
01 Aug, 2010, Rarva.Riendf wrote in the 51st comment:
Votes: 0
damage_old (ch, ch, dam, sn, DAM_LIGHTNING, TRUE);
if (killed_by_chain) {
killed_by_chain = FALSE;
return;
}
level -= 4; /* decrement damage */
if (ch == NULL || ch->fighting == NULL)
return;
}

if (ch == NULL || ch->fighting == NULL) ch cannot be null there, if it was not before.
This code is as broken than any ROM trying to fix the problem skill by skill.
The only way to do it properly is to have a way to know for use if the character should still be used after a method call (basically if it is a mob and he is dead, it should be invalid) if it is a player it becomes more difficult as he is not extracted, but he should be in pos_dead position. So you have to check for both thing after every method that call damage (oh and that can be a movechar method, as he can fall in a trap, a get object, as it could be a bomb etcetcetc…).

fixing ROM is hell….
01 Aug, 2010, quixadhal wrote in the 52nd comment:
Votes: 0
I have yet to see any Dikurivative even scratch the resources (memory OR CPU) of any computer built in this millennium. They were designed to run on machines with 8 or 16 Megabytes of RAM, and processors that were the equivalent of a 486/33. So, unless you're planning to have 50,000 NPC's all running around using a* path-finding algorithms for every step they take, I really think you should do everything possible to simplify the code, and rip out the many convolutions taken to try and cram things into a box that we've long since outgrown.

My original goal with the RaM project was to convert the game to C++ by replacing all of the semi-clever linked list management structures with std::list and proper iteration, replace all the strings (both the funky shared string pool, and temp buffers) with std::string objects, falling back to char * and .c_str() only when needing to interact with the standard library, and gradually migrate things into objects (such as player.printf(), rather than sprintf(tmp_buffer); send_to_char(player, tmp_buffer);).

I figured once that much was done, the code would be far more readable and one could tackle the core logic of the game systems with less fear of breaking things due to intended-but-obscure side-effects.

I figured doing this would probably quadruple the memory footprint of the game, maybe even raise it ten-fold. This wasn't even a concern, since it would mean going from 8MB in use, to 80MB. Your web browser is probably using twice that to read this.
01 Aug, 2010, Rarva.Riendf wrote in the 53rd comment:
Votes: 0
quixadhal said:
My original goal with the RaM project was to convert the game to C++
…..
I figured once that much was done, the code would be far more readable

Just kidding, but C++ and readable code is always a starnge thing to me.
Since it is C++ and I can't read it anymore, I did not look at RAM (I hoped it would only be a fixed ROM code)
But how does you know at any given time if a char_data pointer should be used or not ?
01 Aug, 2010, quixadhal wrote in the 54th comment:
Votes: 0
In a properly designed/re-designed system, there wouldn't be a char_data pointer. You'd have a set of player/npc objects that would be in std::list containers. As I understand it, iterators become invalid if you modify the container they are iterating through, so saving the previous value is safe (as if you nuke the current one and then pick up from your previous save, it will correctly point to the next thing, rather than the now deleted thing).
01 Aug, 2010, Rarva.Riendf wrote in the 55th comment:
Votes: 0
'In a properly designed/re-designed system, there wouldn't be a char_data pointer. You'd have a set of player/npc objects that would be in std::list containers. As I understand it, iterators become invalid if you modify the container they are iterating through, so saving the previous value is safe (as if you nuke the current one and then pick up from your previous save, it will correctly point to the next thing, rather than the now deleted thing). '
Does not answer the question to that:
player_ch = char_list; (or whatever)
damage(player_ch, …) here player_ch can be killed
player_ch ? invalid? null? pos_dead what ? ( I am fixing my mud by making it either invalid if it is a mob that is dead, or pos_dead, and testing for it after every goddam method that could kill a mob (basically….nearly all of them)
02 Aug, 2010, ATT_Turan wrote in the 56th comment:
Votes: 0
It does in fact answer the question.

for (list<CHAR_DATA>::iterator i=CharList.begin(); i!=CharList.end(); i++)
{
CHAR_DATA TempChar=*i;

// Smack the dude with your lightning storm
*i.damage(lightning_damage_variable);

if (TempChar!=*i) <– Quix said this will now point to the next character if the lightning storm killed the first one.
}


That may be pseudo-ish code as I've not actually used the std::list container, but it seemed fairly simple to me on first Googling.
02 Aug, 2010, Davion wrote in the 57th comment:
Votes: 0
ATT_Turan said:
It does in fact answer the question.

for (list<CHAR_DATA>::iterator i=CharList.begin(); i!=CharList.end(); i++)
{
CHAR_DATA TempChar=*i;

// Smack the dude with your lightning storm
*i.damage(lightning_damage_variable);

if (TempChar!=*i) <– Quix said this will now point to the next character if the lightning storm killed the first one.
}


That may be pseudo-ish code as I've not actually used the std::list container, but it seemed fairly simple to me on first Googling.


Ya, no, that's never going to work ;). When iterators are added/removed they aren't recycled quite like that.

I think we're mixing two problems up here. 1) Bombing after someone immediately after the current node is removed. And 2) Bombing after trying to use a player when they've been killed.

Unless you're passing a pointer to pointer to damage(), you're never going to be able to change the value of in scope 'ch' upon death. However, I think this may be one of the better solutions! Pass CHAR_DATA **ch, to damage, if the player dies somewhere in damage, THEN you can set ch to NULL and the value of the ch in the scope could then be checked with "ch == NULL". The reason I say this, instead of using something ON the character itself (eg. ch->valid or ch->pos == POS_DEAD), is that, when extract_char() comes around on a dying character, they aren't recycled and given a new, clean slate. They're just transported to death room with low hp, minus some exp.
02 Aug, 2010, David Haley wrote in the 58th comment:
Votes: 0
If you're writing C++, pass a reference, instead of adding another layer of pointers.
02 Aug, 2010, ATT_Turan wrote in the 59th comment:
Votes: 0
Davion said:
Unless you're passing a pointer to pointer to damage(), you're never going to be able to change the value of in scope 'ch' upon death. However, I think this may be one of the better solutions! Pass CHAR_DATA **ch, to damage, if the player dies somewhere in damage, THEN you can set ch to NULL and the value of the ch in the scope could then be checked with "ch == NULL". The reason I say this, instead of using something ON the character itself (eg. ch->valid or ch->pos == POS_DEAD), is that, when extract_char() comes around on a dying character, they aren't recycled and given a new, clean slate. They're just transported to death room with low hp, minus some exp.


If you were going to do something like this, wouldn't it be possibly easier to change damage() so that it returns a value? It's pretty easy to tell within the scope of the damage function whether you've killed off the character, in which case you tell it to return NULL. That would let you hurt people with the statement
victim=damage(ch, victim,…); at which point you can simply check if (victim) for anything else. You also wouldn't have to worry about changing anything else in your code to worry about dealing with pointers to pointers.
02 Aug, 2010, Runter wrote in the 60th comment:
Votes: 0
The old school quoting is making my eyes hurt.

I had a lengthy reply thought up but because I'm replying via blackberry my pithy commentary follows.

Never trust david haley when it comes to programming. Question his very experience of the problem with boldness if all else fails.
40.0/108