Recursive Timers

Posted by Dace K on Wed 18 Aug 2004 04:43 AM — 9 posts, 30,569 views.

Canada #0
Hey. been trying to make a recursive trance that re-reruns itself after its timer expires.. but after the first timer, it completely exits the function - and I can't figure out why.

Here's a look:

void do_trance( CHAR_DATA *ch, char *argument )
{
char arg [MAX_INPUT_LENGTH];

/*while (ch->substate != SUB_TIMER_DO_ABORT)
{*/
switch( ch->substate )
{
default:
if ( IS_NPC(ch) && IS_AFFECTED( ch, AFF_CHARM ) )
{
send_to_char( "You can't concentrate enough for that.\n\r", ch );
return;
}
if ( ch->mount )
{
send_to_char( "You can't do that while mounted.\n\r", ch );
return;
}
act( AT_MAGIC, "You sink into a deep trance, contemplating your inner soul.", ch, NULL, NULL, TO_CHAR );
act( AT_MAGIC, "$n falls into $mself, shutting out the rest of the world.", ch, NULL, NULL, TO_ROOM );
ch->alloc_ptr = str_dup( arg );
add_timer( ch, TIMER_DO_FUN, UMIN(skill_table[gsn_trance]->beats / 10, 3), do_trance, 1 );
return;

case 1:
if ( !ch->alloc_ptr )
{
send_to_char( "Your trance was interrupted!\n\r", ch );
bug( "do_trance: alloc_ptr NULL", 0 );
return;
}
/*pager_printf( ch, "Timer Value: %d\n\r", get_timer(ch, TIMER_DO_FUN) );*/
/*strcpy( arg, ch->alloc_ptr );
DISPOSE( ch->alloc_ptr );*/
break;

case SUB_TIMER_DO_ABORT:
DISPOSE( ch->alloc_ptr );
ch->substate = SUB_NONE;
send_to_char( "You come out of your trance...\n\r", ch );
act( AT_ACTION, "$n's eyes flash open!", ch, NULL, NULL, TO_ROOM );
return;
}
if ( can_use_skill(ch, number_percent(),gsn_trance ) )
{
learn_from_success( ch, gsn_trance );
act( AT_MAGIC, "You find new depths of power within yourself, and bring it out to the surface.", ch, NULL, NULL, TO_CHAR );
ch->mana+=55;
if (ch->mana > ch->max_mana)
ch->mana = ch->max_mana;
}
else
{
learn_from_failure( ch, gsn_trance );
act( AT_MAGIC, "You fail to find any depths of hidden power within yourself.", ch, NULL, NULL, TO_CHAR );
}
add_timer( ch, TIMER_DO_FUN, UMIN(skill_table[gsn_trance]->beats / 10, 3), do_trance, 1 );
return;
}


Any ideas?
USA #1
The function returns right after you give another timer. I think you are doing it wrong. What I would do is give the character a bool variable like this (in the char_data struct):

bool is_tranced;

Then just make it loop until the character is no longer in a trance:

void do_trance( CHAR_DATA *ch, char *argument )
{
char arg [MAX_INPUT_LENGTH];

/* start trance */
ch->is_tranced = TRUE;

while ( ch->is_tranced == TRUE )
{
switch( ch->substate )
{
default:
if ( IS_NPC(ch) && IS_AFFECTED( ch, AFF_CHARM ) )
{
send_to_char( "You can't concentrate enough for that.\n\r", ch );
ch->is_chanced = FALSE;
return;
}
if ( ch->mount )
{
send_to_char( "You can't do that while mounted.\n\r", ch );
ch->is_chanced = FALSE;
return;
}
act( AT_MAGIC, "You sink into a deep trance, contemplating your inner soul.", ch, NULL, NULL, TO_CHAR );
act( AT_MAGIC, "$n falls into $mself, shutting out the rest of the world.", ch, NULL, NULL, TO_ROOM );
ch->alloc_ptr = str_dup( arg );
add_timer( ch, TIMER_DO_FUN, UMIN(skill_table[gsn_trance]->beats / 10, 3), do_trance, 1 ); 
return;

case 1:
if ( !ch->alloc_ptr )
{
send_to_char( "Your trance was interrupted!\n\r", ch );
bug( "do_trance: alloc_ptr NULL", 0 );
ch->is_tranced = FALSE;
return;
}
break;

case SUB_TIMER_DO_ABORT:
DISPOSE( ch->alloc_ptr );
ch->substate = SUB_NONE;
send_to_char( "You come out of your trance...\n\r", ch );
act( AT_ACTION, "$n's eyes flash open!", ch, NULL, NULL, TO_ROOM );
ch->is_tranced = FALSE;
return;
}
if ( can_use_skill(ch, number_percent(),gsn_trance ) )
{
learn_from_success( ch, gsn_trance );
act( AT_MAGIC, "You find new depths of power within yourself, and bring it out to the surface.", ch, NULL, NULL, TO_CHAR );
ch->mana+=55;
if (ch->mana > ch->max_mana)
ch->mana = ch->max_mana;
}
else
{
learn_from_failure( ch, gsn_trance );
act( AT_MAGIC, "You fail to find any depths of hidden power within yourself.", ch, NULL, NULL, TO_CHAR );
}
add_timer( ch, TIMER_DO_FUN, UMIN(skill_table[gsn_trance]->beats / 10, 3), do_trance, 1 ); 
}
return;
}

Note: Sorry for bad format, the code was posted without code tags...
Amended on Wed 18 Aug 2004 05:37 AM by Nick Cash
Canada #2
Nope. Locks up the mud, and I have to kill it manually because it'll loop in trance forever.

I managed a similar effect when I simply recalled do_trance(ch, NULL) at the end of the function earlier today :/
USA #3
Hmm, figures. You said you wanted them to be in a trance until they stop right? It should only loop until the person "stops" the trance. But it does seem like it would be prone an infinite loop. I'm not quite sure. Perhaps Nick or someone better at coding then I will help you.
USA #4
Debug the code.

Put something like:
bug( "Now in case 1");

In case 1, then etc in each case.

Then check the logs after it locks up. See what is locking it up.

Canada #5
It locks up because..

after it exits trance, it loops back to the beginning to see if the char's timer is expired. Since it hasn't, it loops back again.

The timer won't count down unless the function is exited :/
USA #6
Make it call a seperate function, that handles the timer, like trance_timer(ch).

That may work, I'm not sure.
USA #7
Alright, do this how I set up my ships.

First off, get rid of all the timers. Add to the char_data struct with a var named trance_timer or something.

Make the function that sets them in trance (ch->is_tranced = TRUE), like you have already, but without any references to timers. Then, have it set ch->trance_timer to UMIN(skill_table[gsn_trance]->beats / 10, 3).

When it updates all chars in update.c, make it do this:

void update_trance( CHAR_DATA *ch )
{
  if ( ch->is_tranced == FALSE )
    return;
  else
  {
    if ( ch->trance_timmer-- < 0 )
    {
       send_to_char( "You come out of your trance.\n\r", ch );
       /* reschedule the timer */
       ch->trance_timer = UMIN(skill_table[gsn_trance]->beats / 10, 3);
      /* insert code for finding hidden powers (extra mana) here */
      return;
    }
  }
  return;
}

Then, somewhere, i'm not quite sure where, you need to find the spot that anyalyze's the users input (the very top-level spot) and analyze it to see if it has to do with trance (!str_cmp(input, "trance"), or similar). If it does not have to do with trance, and the user is in a trance, cancel it.

if ( ch->is_tranced == TRUE )
{
  if ( !str_cmp( input, "trance" ) )
  {
    send_to_char( "You come out of your trance.\n\r", ch );
    ch->is_tranced = FALSE;
  }
}

Did that make any sense? Its like establishing your own timer system just for trance. Its very effective and much more managable then the timers.
Canada #8
I see what you mean.. thanks for your time!