Author Topic: Timed events for player characters  (Read 692 times)

Offline Lash

  • Acquaintance
  • *
  • Posts: 42
    • View Profile
Timed events for player characters
« on: December 22, 2015, 06:05:15 AM »
I'm looking at adding functions to support "factions" in a mud as a sort of replacement for the idea of having guilds. A timestamp is set in the player characters file whenever the PC interacts with a npc faction member, linked to a reputation (with that faction) level, in a mapping variable called Factions. The idea is that if the PC does not interact with a faction member in the course of 30 mud days their reputation decreases by 1. So this is how I have set up so far:

In the following function  "timestamps" are set in the player character using the current mudtime as defined by SEASONS_D->GetTime().

File name is factions.c:

Code: [Select]
mapping Factions = ([]);

mixed AddFaction(string fac){

    int flev = 1;
    int ltime = SEASONS_D->GetTime();
    int rlev = 1;
    int rtime = SEASONS_D->GetTime();
   
    if( !stringp(fac) ) return 0;
    if( Factions[fac] ) return 0;
    Factions[fac] = (["faction level":flev,"level_timer":ltime,"reputation":rlev,
                      "reputation_timer": rtime ]);
    return Factions[fac];
}

The output looks like this in the player characters save file:

Code: [Select]
Factions ([ "Orcs of the Bloody Moon" : (["reputation" : 1, "level_timer" :
            729384181, "faction level" : 1, "reputation_timer" :
            729384219 ]) ])

Every 30 mudtime days I want to check the rtime variable ("reputation_timer") and decrement the rlev variable ("reputation") by 1 as follows:

Code: [Select]
void CheckTimer(){
    string *str = keys(Factions);
    int x, y;
    y = HOUR_LENGTH * DAY_LENGTH * 30;

    if(inherits(LIB_NPC, this_object())) return;
    if(!str) return;
   
    for(x=0; x<sizeof(str); x++){
        if (SEASONS_D->GetTime() >= (this_player()->GetReputationTimer(str[x])+y))
            this_player()->AddReputation(str[x], -1);
}

The player can/will be associated with many different factions as they progress in the game, so I need to check the reputation timers of the respective factions frequently.

What didn't work:  putting a heart_beat funtion in the factions.c file by replacing  void CheckTimer() in the above with static void heart_beat(). With static void heart_beat() combat got broke. (Disclaimer - I was warned not use the heart_beat() function outside of what was specified in other files inherited by the player character files by Quixadhal on dchat - well now I know why :) )

What SEEMS to work: keeping the above CheckTimer() function and adding the following to the player.c file in its static void heart_beat() function (after having player.c inherit the factions.c file)

Code: [Select]
factions::CheckTimer();

Is there a better/more efficient way to do this? Right now with the above code the mud seems to work fine, but I don't know if I'm wasting processor resources with the code.

Also, as an aside, in player.c there is this scope resolution call in static void heart_beat()
Code: [Select]
living::heart_beat();

but there's no heart_beat function in living.c! How does that work?  ???

Offline Lash

  • Acquaintance
  • *
  • Posts: 42
    • View Profile
Re: Timed events for player characters
« Reply #1 on: December 22, 2015, 06:33:58 AM »
Here's the factions.c file:
Code: [Select]
/*    /lib/props/factions.c
 *    From the Dead Souls Mud Library
 *    The factions property
 *    Based on /lib/props/properties.c
 *    Created by Descartes of Borg 961222
 *    Version: @(#) properties.c 1.1@(#)
 *    Last modified: 96/12/22
 *    ccoker modified for factions: 2015/12/08
 *
 */

#include <lib.h>
#include <daemons.h>

mapping Factions    = ([]);
void CheckTimer();

mixed AddFaction(string fac){

    int flev = 1;
    int ltime = SEASONS_D->GetTime();
    int rlev = 1;
    int rtime = SEASONS_D->GetTime();
   
    if( !stringp(fac) ) return 0;
    if( Factions[fac] ) return 0;
    Factions[fac] = (["faction level":flev,"level_timer":ltime,"reputation":rlev,
                      "reputation_timer": rtime ]);
    return Factions[fac];
}

mixed GetFaction(string fac){
    if( !stringp(fac) ) return 0;
    if(Factions && Factions[fac])
        return Factions[fac];
    else return 0;
}

int RemoveFaction(string fac){
    if( !stringp(fac) ) return 0;
    if(undefinedp(Factions[fac]) ){
        return 1;
    }
    else {
        map_delete(Factions, fac);
    }
    return !Factions[fac];
}

mixed AddFactionLevel(string fac, int val){
    if( !stringp(fac) || !Factions[fac] ) return 0;
     if( Factions[fac] ){
        val +=Factions[fac]["faction level"];
    }
    else {
        Factions[fac]["faction level"] = val;
    }
    Factions[fac]["faction level"] = val;
    Factions[fac]["level_timer"] = SEASONS_D->GetTime();
    return Factions[fac];
}

mixed GetFactionLevel(string fac){
    if( !stringp(fac) || !Factions || !Factions[fac]) return 0;
    return Factions[fac]["faction level"];
}

mixed GetFactionTimer(string fac){
    if( !stringp(fac) || !Factions || !Factions[fac]) return 0;
    return Factions[fac]["level_timer"];
}

mixed AddFactionTimer(string fac, int val){
    if( !stringp(fac) || !Factions[fac] ) return 0;
     if( Factions[fac] ){
        val +=Factions[fac]["level_timer"];
    }
    else {
        Factions[fac]["level_timer"] = val;
    }
    Factions[fac]["level_timer"] = val;
    return Factions[fac];
}

mixed AddReputation(string fac, int val){
    if( !stringp(fac) || !Factions[fac] ) return 0;
     if( Factions[fac] ){
        val +=Factions[fac]["reputation"];
    }
    else {
        Factions[fac]["reputation"] = val;
    }
    Factions[fac]["reputation"] = val;
    Factions[fac]["reputation_timer"] = SEASONS_D->GetTime();
    return Factions[fac];
}

mixed GetReputationLevel(string fac){
    if( !stringp(fac) || !Factions || !Factions[fac]) return 0;
    return Factions[fac]["reputation"];
}

mixed GetReputationTimer(string fac){
    if( !stringp(fac) || !Factions || !Factions[fac]) return 0;
    return Factions[fac]["reputation_timer"];
}

mixed AddReputationTimer(string fac, int val){
    if( !stringp(fac) || !Factions[fac] ) return 0;
     if( Factions[fac] ){
        val +=Factions[fac]["reputation_timer"];
    }
    else {
        Factions[fac]["reputation_timer"] = val;
    }
    Factions[fac]["reputation_timer"] = val;
    return Factions[fac];
}

mapping GetFactions(){
    if(!Factions) Factions = ([]);
    return Factions;
}

string *GetFacs(){
    return keys(Factions);
}

/*function below mainly for NPC use*/
mapping SetFactions(mapping facs){
    if(sizeof(Factions)) return (Factions[facs] += facs);
    else return (Factions = facs);
}

void CheckTimer(){
    string *str = keys(Factions);
    int x, y;
    y = HOUR_LENGTH * DAY_LENGTH * 30;

    if(inherits(LIB_NPC, this_object())) return;
    if(!str) return;
       
    for(x=0; x<sizeof(str); x++){
        if(this_player()->GetReputationLevel(str[x]) <= 0
           && this_player()->GetFactionLevel(str[x])  >= 0
           && SEASONS_D->GetTime() >= (this_player()->GetReputationTimer(str[x])+y))
           this_player()->AddReputation(str[x], 0);
        if (SEASONS_D->GetTime() >= (this_player()->GetReputationTimer(str[x])+y))
           this_player()->AddReputation(str[x], -1);
        if (this_player()->GetFactionLevel(str[x])  >= 0
            && SEASONS_D->GetTime() >= (this_player()->GetFactionTimer(str[x])+SEASONS_D->GetYearLength()))
            this_player()->AddFactionLevel(str[x], -1);
           
    }
}

Note: modified seasons.c in /lib/daemon to add the GetYearLength() function as follows:

Code: [Select]
/*added by lash*/
varargs int GetYearLength(int x) {
    int i, tot;

    i = sizeof(Months);
    while(i--) tot += ((class month)Months[i])->Days;
    i = DAY_LENGTH * HOUR_LENGTH * tot;
    return i;
}
/* end add */

« Last Edit: December 22, 2015, 06:42:28 AM by Lash »

Offline quixadhal

  • BFF
  • ***
  • Posts: 629
    • View Profile
    • WileyMUD
Re: Timed events for player characters
« Reply #2 on: December 22, 2015, 03:59:07 PM »
First, I would likely change your AddFaction() function a bit.  Setting both ltime and rtime to the same value seems silly.  I assume "ltime" is the time at which the player last modified the faction by some action on their part?

If so, rtime could just be 30 * DAY_LENGTH * HOUR_LENGTH.

To see how much time has elapsed since then, and how many faction points to deduct,

(SEASONS_D->GetTime() - Factions["poo"]["level_timer"]) % Factions["poo"]["reputation_timer"]

So, you could, on login, deduct that many points from their reputation value and reset ltime so the next calculation is correct.

There's utterly no reason to check every N minutes for something that only happens every 30 days.

However, if you WANTED to for some other purpose....

In heart_beat, you could add a check to ensure the callout you want is there, and if not, make it there.

if( find_call_out("silly_check_function") < 0) {
    call_out( "silly_check_function", 60 * 60 * 30 );
}

You can also use the "handle" that call_out returns, which is more useful if you use the same function for multiple things.

However, heart_beat() runs every 1 or 2 seconds, so it's really a waste to do this for something that doesn't do anything very often.  In the case of your 30 day thing, checking during login is MORE than sufficient.