26 Sep, 2009, JohnnyStarr wrote in the 1st comment:
Votes: 0
In my quest implementation i've hit a small snag.
I am writing player quests to the Pfile using a similar approach to player objects.
Basically, I save the Vnum as index, and anything that isn't read-only to save the state of the quest, including its linked list of 'objectives'. When the player quest-list is loaded, it and the objective list displays in backwards order.

Obviously this is due to the fact that the list writes top-bottom, yet reads bottom-top. I've noticed some routines use recursion to write the lists backwards,
so that it initializes correctly.

I was wondering if there is a better approach to this?

PS. I do know that I could use sorting algorithms associated with std::list, but I
am not yet using std::list.
26 Sep, 2009, Tyche wrote in the 2nd comment:
Votes: 0
Read it and insert with push_front instead of push_back…
or vice versa depending on how you write it.
26 Sep, 2009, JohnnyStarr wrote in the 3rd comment:
Votes: 0
With C-Style lists?
26 Sep, 2009, Tyche wrote in the 4th comment:
Votes: 0
Same answer…
Insert at head of list or insert at the end of list.
It depends on your particular implementation of lists as there are several ways of doing it.
26 Sep, 2009, JohnnyStarr wrote in the 5th comment:
Votes: 0
Yes, you are right. I get what you mean now. :)

EDIT:
So, looking at the code, the loading is as such:
quest->next = ch->quests;
ch->quests = quest;

so this is push_front right?
how can i rewrite this to be push_back?
26 Sep, 2009, Davion wrote in the 6th comment:
Votes: 0
staryavsky said:
Yes, you are right. I get what you mean now. :)

EDIT:
So, looking at the code, the loading is as such:
quest->next = ch->quests;
ch->quests = quest;

so this is push_front right?
how can i rewrite this to be push_back?


ch->quest_last->next = quest;
ch->quest_last = quest;
26 Sep, 2009, JohnnyStarr wrote in the 7th comment:
Votes: 0
So obviously I would want to add a quest_last pointer.
How will this work in conjunction with my existing ch->quests head pointer?
Sorry, but its a little akward for me.
26 Sep, 2009, Davion wrote in the 8th comment:
Votes: 0
Well! When you add it to the list, the only time you'd set the ch->quest (in these cases, I like to signify which is first and last, so quest_first, and quest_last) is if the list is empty (or ch->quest_first == NULL). After that, you just set the next pointer of the last object to the new one, then set the pointer to the last object to point to the new one. Something like

if(!ch->quest_first )
ch->quest_first = quest;
if( ch->quest_last )
ch->quest_last->next = quest;
ch->quest_last = quest;
26 Sep, 2009, JohnnyStarr wrote in the 9th comment:
Votes: 0
ok, do you have:
quest_first, quest_last, and quests?

Otherwise, how would you iterate through the list?
26 Sep, 2009, Kline wrote in the 10th comment:
Votes: 0
Some macros you may find useful to wrap to your own needs (not written by me, mind you):
#define LINK(link, first, last, next, prev) \
do { \
if ( (link)->is_free == TRUE ) hang("LINK: link is FREE!"); \
if ( (link)->is_free != FALSE ) hang("LINK: link is corrupted!"); \
if ( (link)->prev || (link)->next ) hang("LINK: link already in list?");$
if ( (last) && (last)->next ) hang("LINK: last->next NON-NULL!"); \
if ( !(first) ) \
(first) = (link); \
else \
(last)->next = (link); \
(link)->next = NULL; \
(link)->prev = (last); \
(last) = (link); \
} while(0)

/* Link at the head of the list rather than the tail. Double linked */
#define TOPLINK(link, first, last, next, prev) \
do { \
if ( (link)->is_free == TRUE ) hang("TOPLINK: link is FREE!"); \
if ( (link)->is_free != FALSE ) hang("TOPLINK: link is corrupted!"); \
if ( (link)->prev || (link)->next ) hang("TOPLINK: link already in list?$
if ( (first) && (first)->prev ) hang("TOPLINK: first->prev NON-NULL!"); \
if ( !(last) ) \
(last) = (link); \
else \
(first)->prev = (link); \
(link)->prev = NULL; \
(link)->next = (first); \
(first) = (link); \
} while(0)
26 Sep, 2009, Davion wrote in the 11th comment:
Votes: 0
Oh, as I said, in cases like this I like to signify which quest var is which. I simply changed the name of quest, to quest_first (you can leave it as quest if you like).

To iterate you'd do the same thing
for(q = ch->quest_first ; q ; q = q->next )



Edit: Didn't see Kline's post. As good as macro's are. I'd suggest learning precisely how the lists function before you take the easy way out. It'll make debugging a lot easier.
26 Sep, 2009, Kline wrote in the 12th comment:
Votes: 0
And since you replied: To iterate – for( quest = ch->quest_first; quest != ch->quest_last; quest = quest->next )

You'd also want to search here about using something like quest_next = quest->next instead and why and so forth :)
26 Sep, 2009, JohnnyStarr wrote in the 13th comment:
Votes: 0
Thanks guys, i had a dumb moment there :stare:
And i do understand the whole quest_next = quest->next thing :smirk:
26 Sep, 2009, Davion wrote in the 14th comment:
Votes: 0
Kline said:
And since you replied: To iterate – for( quest = ch->quest_first; quest != ch->quest_last; quest = quest->next )


That isn't quite right. That'll stop if quest is quest_last, but quest_last will be a valid quest. It'd always stop 1 short.
26 Sep, 2009, Kline wrote in the 15th comment:
Votes: 0
True, != NULL, sorry for my hastily written replies :)
26 Sep, 2009, JohnnyStarr wrote in the 16th comment:
Votes: 0
How does ch->quests know about ch->quest_last?
Like, you could asign quest_last, but adding to quest_last->next
Wouldnt notify ch->quests would it?

Now, it makes sense to use quest last as a marker, but it isnt a second list right?
If so, how can you add ch->quest->next?
26 Sep, 2009, Scandum wrote in the 17th comment:
Votes: 0
staryavsky said:
I was wondering if there is a better approach to this?

More of a design related response, but the whole concept of quest objectives saved on the player is fundamentally flawed. Players should keep their own quest logs if they have a poor memory, and builders should focus on writing the actual quest instead of a game mechanism introduced by graphical games so idiots can play their games. More often than not the summarized objective becomes the quest, instead of what the NPCs say or do, which is probably as immersion breaking as it gets.


staryavsky said:
How does ch->quests know about ch->quest_last?

It doesn't, they're separate pointers, one pointing to the beginning of the list, the other to the end of the list. I'd suggest renaming the variables to:
ch->quest_head
ch->quest_tail

or

ch->quest->head
ch->quest->tail
26 Sep, 2009, Davion wrote in the 18th comment:
Votes: 0
staryavsky said:
How does ch->quests know about ch->quest_last?
Like, you could asign quest_last, but adding to quest_last->next
Wouldnt notify ch->quests would it?

Now, it makes sense to use quest last as a marker, but it isnt a second list right?
If so, how can you add ch->quest->next?


All push_back does is take this new node, and tack it onto the end. In order to do this, you have to use quest_last to keep track of the last node in the list. You do this when you add the node.

if(!ch->quests )
ch->quests = quest;
if( ch->quest_last )
ch->quest_last->next = quest;
ch->quest_last = quest;


It's not creating a second list.
26 Sep, 2009, David Haley wrote in the 19th comment:
Votes: 0
I agree. I think players should also track their own HP, in addition to remembering what equipment they've put on. All these status commands are just fundamentally flawed, stupid ideas.

Anyhow.

I'm not entirely sure why you need a doubly-linked list here. It doesn't really hurt (because memory isn't terribly constrained), but it's not necessary and doesn't gain you anything, and adds this confusion from things like the pointer to the first element and the pointer to the last.
26 Sep, 2009, JohnnyStarr wrote in the 20th comment:
Votes: 0
Stupid ideas?
Thanks man!
0.0/49