Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - Lash

Pages: [1] 2 3
1
I really need to sit on posts for a day or two...

Clarifications: When I wrote:

In eventBlind() the messages weren't being returned correctly.

The output I was receiving after my character was blinded by the function called in the npc consisted of only the second string in the messaging array. So when blinded I got the "You can see again!" message, and when the blindness wore off I got the "You can see again!" message.

When I wrote "...it seems like it's backwards! But it works as expected..."

I meant  "It works like I want it to work", meaning the message "You have been blinded!" was returned when the character was blinded by the npc, and "You can see again!" was returned when the blindness effect wore off.   

2
The functions static void RemoveBlindnes() and varargs mixed eventBlind() were not behaving as I expected. A test character was blinded by an npc, however when I tried the RemoveBlindness function as an admin on the test character I received the following output:

Code: [Select]
call test->RemoveBlindness()
The function RemoveBlindness() is not in OBJ(test /secure/save/players/t/test)

Removing the static type (void RemoveBlindness() instead of static void RemoveBlindness()) resulted in the following output when the mud was restarted and the character was blinded:
Code: [Select]
call test->RemoveBlindness()
OBJ(test /secure/save/players/t/test) -> RemoveBlindness() = 0

The character had vision restored. If the character was NOT blinded and the admin used the call test->RemoveBlindness() call the following output was received:

Code: [Select]
*Tried to take a member of something that isn't a class.
Object: /secure/save/players/t/test (/lib/genetics.c) at line 53

'<fake>' at /secure/save/creators/l/lash (/<driver>) at line 0
'cmdAll' at /secure/save/creators/l/lash (/lib/command.c) at line 231
'cmd' at /secure/cmds/creators/call at line 37
'CATCH' at /secure/cmds/creators/call at line 37
'<fake>' at /secure/cmds/creators/call (/<driver>) at line 0
'RemoveBlindness' at /secure/save/players/t/test (/lib/genetics.c) at line 53
Trace written to /log/catch
OBJ(test /secure/save/players/t/test) -> RemoveBlindness()
Error in execution: *Tried to take a member of something that isn't a class.

Well, that makes sense - the character is not blinded so the class object is not present. The RemoveBlindness function is now
working as expected (I think).

In eventBlind() the messages weren't being returned correctly. Here's the code (called from an npc) that was used to blind the character:
Code: [Select]
void blindness(object ob){

    object target = ob->GetCurrentEnemy();
    object env = environment(ob);
    int save = target->GetMagicResistance();
    int s_throw = random(99)+1;

    if(target->GetBlind()){
    return;
    }
    if (s_throw <= save){
        tell_room(env, "\n"+capitalize(target->GetShort())+" resists "+ob->GetKeyName()+"'s magic attack!\n", ({ ob, target }));
        tell_object(target, "\n%^BOLD%^%^YELLOW%^You resist being blinded by "+ob->GetKeyName()+"!%^RESET%^\n");
        target->eventTrainSkill("magic defense",save,s_throw,1);
        return;
    }
    else{
    target->eventBlind(target, 100, ({"\n%^BOLD%^%^GREEN%^You have been blinded!%^RESET%^\n","\n%^BOLD%^%^YELLOW%^You can see again!%^RESET%^\n"}) );
    tell_room(env, "\n"+capitalize(target->GetShort())+" seems to be blinded!\n", ({ob, target}));
    }
}

Looking at varargs mixed eventBlind() and comparing it to the RemoveBlindness function, it seemed like something was amiss so I did this:
Code: [Select]
varargs mixed eventBlind(object who, int amt, mixed end){
    Blind = new(class blindness);
    Blind->count = amt;
    Blind->end = end;
   /*following code added as seen in RemoveBlindness() function*/
    if( arrayp(end) ){
        send_messages(end[1], end[0], this_object());
        tell_player(who, "end[0] is "+end[0]+"and end[1] is "+end[1]);
    }
    else if( functionp(end) && !(functionp(end) & FP_OWNER_DESTED) ){
        evaluate(end, this_object());
    }
    else{
    tell_player(who,"You have been blinded!");
    }
    /*end addition*/
    return 1;
}

The messages are being returned correctly as seen by the output:
Code: [Select]
You have been blinded!

end[0] is
You have been blinded!
and end[1] is
You can see again!

After the 100 tick timer counts down (coded in the npc eventBlind() function) the characters vision is restored and the correct "You can see again!" message is displayed.

But hold on!

Why does this from eventBlind()
Code: [Select]
send_messages(end[1], end[0], this_object());

result in the correct order of the messages displayed? I would have thought the 2nd element of the array end[1] would have been
displayed first! Instead, it seems like it's backwards! But it works as expected...

Also, if I use this command as an admin:
Code: [Select]
call test->eventBlind("secure/save/players/t/test",10,({"you are blind","you can now see"}))

the test character is blinded for 10 ticks and the correct messaging is displayed.

Anyway, just some observations I noticed that I thought I would share. If anyone has more insight to this, or made other changes,
your input would be aprreciated.

3
Code Vault / Re: Code for character skill based leveling
« on: March 15, 2016, 06:12:15 AM »
Some code changes and cleanup.

/lib/lib/secure/connect.c

changed code in eventCompleteChar() [cleanup]
Basically this changes the output depending on whether AUTO_WIZ is enabled or not upon character creation.

Code: [Select]
if(trabajo && !ptmp) Player->ChangeClass(trabajo);
    if(ptmp && !trabajo){
        string str;
        receive("\nCharacter Summary\n");
        receive("-------------------------\n");
        receive("PRIMARY Skills picked:\n");
        foreach(str in ptmp){
            receive("'"+str+"' ");
            Player->AddSkill(str,1,1);
        }
        receive("\n");
    }
    if(stmp && !trabajo){
        string str;
        receive("\nSECONDARY Skills picked:\n");
        foreach(str in stmp){
            receive("'"+str+"' ");
            Player->AddSkill(str,2,1);
        }
        receive("\n");
    }
    if(mtmp && !trabajo){
        string str;
        receive("\nMINOR Skills picked:\n");
        foreach(str in mtmp){
            receive("'"+str+"' ");
            Player->AddSkill(str,3,1);
        }
        receive("\n");
    }
    this_player()->SetTerminal("ansi");
    PLAYERS_D->AddPlayerInfo(Name);
    if(yescre){
        receive("\nAs a creator you will be booted out and have to\n"
                "log back in in order to complete the creator process\n");     
        call_out( (: eventCre, Name :), 3);
        input_to((: eventEnterGame :), I_NOESC);
    }
    receive("\nIf you wish to create a different character,\n"
              "use the 'suicide' command after logging in and\n"
              "start over. Have FUN!\n"
              "Press <return> to continue.");     
    input_to((: eventEnterGame :), I_NOESC);
}

/lib/lib/lvs/abilities.c - the GetMaxSkillPoints() function

This relaxes the amount of skill points required to advance a skill level. For skill based leveling this results (for example) in slower overall character leveling than with the default experience point leveling system if skilladvancement, instead of experience point advancement, is enabled. The other change is that with the default skill point systems, leveling based on skill advancement is painfully slow at higher levels due to the exponentiation of skill point level accrual.

With this skill based leveling system my test character is level 9 with 127069 experience points (normally level 14). Skills are as follows:
Code: [Select]
Primary skills:
blade attack        : 22/24  (71%)     magic attack        : 16/24  (56%)     
conjuring           : 16/24  (37%)     melee defense       : 21/24  (28%)     
healing             : 14/24  (20%)     

Secondary skills:
bargaining          : 14/22  (24%)                                             
blade defense       : 8/22   (89%)                                             
magic defense       : 14/22  (54%)                                             

Minor skills:
blunt attack        : 7/20   (42%)     melee attack        : 11/20  (93%)     
concealment         : 1/20   (0%)      stealing            : 1/20   (36%)     
knife attack        : 1/20   (0%)

Here are the changes:

Code: [Select]
int GetMaxSkillPoints(string skill, int level){
   if( !Skills[skill] ){
        return 0;
    }
    else if( level == 0 ){
        if(SKILL_ADVANCE){
            return 50;
        }
        else{ return 200;
        }
    }
    else {
        int cl, x;
       
       if( !(cl = Skills[skill]["class"]) ){
            if(SKILL_ADVANCE) return level * 200;
            else return level * 600;
        }
        if( cl > 4 ){
            cl = 4;
        }
        if( cl < 1 ){
            cl = 4;
        }
        x = level;
        if(SKILL_ADVANCE){
            return level * cl * 500;
        }
        else{
            while( cl-- ){
            x *= level;
            }
       return x * 400;
       }
    }
}

if interested, this project and changes are updated at https://github.com/LashMUD/TheBrassRing

4
Thank you for the reply and ideas.

Yes, the initial setup for the system I have was pretty hard for character advancement (all skill leveling based so far) so I made two changes:

One was to make sure the character received skill levels in their chosen skills two levels under the maximum for level 1. So, primary skills were initialized as 6/8. secondary 4/6, and minor 2/4.

The other was to modify /lib/lib/lvs/abilities.c so that the amount of skill points required for raising a skill level was less severe than the default values:

Code: [Select]
int GetMaxSkillPoints(string skill, int level){
    if( !Skills[skill] ){
        return 0;
    }
    else if( level == 0 ){
        if(SKILL_ADVANCE){
        return 50;
        }else{ return 200; }
    }
    else {
        int cl, x;

        if( !(cl = Skills[skill]["class"]) ){
            return level * 600;
        }
        if( cl > 4 ){
            cl = 4;
        }
        if( cl < 1 ){
            cl = 4;
        }
        x = level;
        while( cl-- ){
            x *= level;
        }
        if(SKILL_ADVANCE){
        return (x * 100);
        }else{ return x * 400; }
    }
}

Still a work in progress. In my system the character still receives experience points. They are not used for leveling calculations, however, I was wondering if it might be an idea to enable the player to trade those unused experience points in for some extra stuff. For example, trade in a million XP for freedom from hunger, so hunger doesn't impact healing rates, or immunity (resistance) to poison. something along those lines.

Good stuff!

5
Bug Central / Saving armor conditions
« on: February 24, 2016, 02:02:24 PM »
I noticed in the default 3.8.6 base mudlib that armor conditions (wear and tear on armor after comabat, for example) were not being saved. A player could quit, log back in, and have all new untainted armor.

Two files were changed so armor conditions are retained:

As pointed out by Quixadhal on dschat the DamagePoints variable in lib/lib/props/deterioration.c was not initialized and thus not being saved:
Code: [Select]
private int DamagePoints;

changed to

private int DamagePoints    = 0;


In /lib/lib/std/base_armor.c the variable Protection was added to the my_save variable like so:
Code: [Select]
my_save = equip::GetSave() + value::GetSave() + mass::GetSave() +
        poison::GetSave() + deterioration::GetSave();

changed to:

my_save = equip::GetSave() + value::GetSave() + mass::GetSave() +
        poison::GetSave() + deterioration::GetSave() + ( ({"Protection"}) );

So far as I can tell, the armor objects are being saved with the correct values for deterioration, DamagePoints, and "cuts" and "dents" values as defined in the GetItemCondition() function in the base_armor.c file after character logout/login.

As a check I added the following bit of code to deterioration.c to make sure the "current" DamagePoints was being reported vs the MaxDamagePoints assigned to the specific armor object:

Code: [Select]
int GetMaxDamagePoints(){
    return MaxDamagePoints;
}

Here's some example output for armor worn by a test character that has been damaged after being attacked by an npc with a "blade" type weapon. The test character quit and logged back in. The admin character evaluated the armor object as follows:

Code: [Select]
call leggings->GetDamagePoints()
OBJ(iron leggings /domains/diku-alfa/room/30.zon/armor/3092_leggings_iron#101)
-> GetDamagePoints() = 22

call leggings->GetMaxDamagePoints()
OBJ(iron leggings /domains/diku-alfa/room/30.zon/armor/3092_leggings_iron#101)
-> GetMaxDamagePoints() = 81

call leggings->GetItemCondition()

IN GETITEM CONDITION
cuts is 80
dents is 100
cuts is 80
OBJ(iron leggings /domains/diku-alfa/room/30.zon/armor/3092_leggings_iron#101)
-> GetItemCondition() = "Its surface is scratched and unmarred."

Without making the two changes as described above none of the above values were being saved.

*note - added some output code to base_armor.c to make sure the "cuts" and "dents" variables were being reported accurately.

6
Code Vault / Code for character skill based leveling
« on: January 30, 2016, 11:58:21 AM »
I've tested this out on a new Dead Souls installation and a running mud. Only tested low level test characters so not sure how this will work at character levels above 20.

Here's my modded code changes for player based skill selection and advancement. I'm not going to post the complete files for all this so as not to spam the post too much. Line numbers are for Dead Souls 3.8.6 default base mudlib.

An alternative to having players select their character skills during their first log in is to have an NPC assign skills to players after entering the game using the SetSkill() function. But, for skill based advancement vs. XP based advancing the below files can be added.

Configuration Files:
note: CLASS_SELECTION and SKILL_SELECTION should not both be set to 1!

config.h in /lib/secure/include

Code: [Select]
//line 44
#define CLASS_SELECTION          0
#define SKILL_SELECTION          1
#define XP_ADVANCE               0
#define SKILL_ADVANCE            1

cfg.h in lib/secure/include
Code: [Select]
//line 19
#define CFG_SKILLS DIR_SECURE_CFG "/skills.cfg"

skills.cfg (file) in /lib/secure/cfg

Code: [Select]
#/lib/secure/cfg/skills.c
#list of available skills
bargaining
blade attack
blade defense
blunt attack
blunt defense
concealment
conjuring
detection
faith
fishing
healing
knife attack
knife defense
magic attack
magic defense
melee attack
melee defense
multi-hand
multi-weapon
projectile attack
projectile defense
psionic attack
psionic defense
psionic detection
stealing
stealth
murder

Added mudconfig commands to change whether classes with experience point advancement are used or not, or skills chosen on player creation and
advancement based on skill point leveling. 

mudconfig.c in lib/secure/cmds/admin

Code: [Select]
//line 23
string array modals = antimodals + ({ "channelpipes", "fastcombat",
        "catchtell","matchcommand", "matchobject", "autowiz", "locked",
        "localtime", "justenglish", "justhumans", "encumbrance", "pk",
        "compat", "exitsbare", "nmexits", "grid", "minimap", "wizmap",
        "cgi", "dirlist", "creweb", "selectclass", "selectskills",
        "xpadvancement", "skilladvancement", "severable", "retain",
        "defaultparse", "disablereboot", "loglocal", "logremote",
        "questrequired", "autoadvance","guestallowed", "playerintertell" });

//line 574
        case "selectclass" : which = "CLASS_SELECTION";break;
        case "selectskills" : which = "SKILL_SELECTION";break;
        case "xpadvancement" : which = "XP_ADVANCE";break;
        case "skilladvancement" : which = "SKILL_ADVANCE";break;
       
//line 629
       if(which == "CLASS_SELECTION" || which == "SKILL_SELECTION"
       || which =="XP_ADVANCE" || which == "SKILL_ADVANCE")
        write("To make this configuration take effect, reboot the mud.\n"+
                "It might be a good idea to disable the other SELECTION and/or\n"+
                "ADVANCE options before reboot.");

//line 1007 in string(GetHelp())
            "\nmudconfig selectclass [ yes | no ] (whether new players "
            "choose a class on login)"
            "\nmudconfig selectskills [yes | no ] (whether new players "
            "select their own skill set on login (classless mud)"
            "\nmudconfig xpadvancement [yes | no ] (whether players gain levels "
            "using the experience point system or not"
            "\nmudconfig skilladvancement [yes | no ] (whether players gain levels "
            "by increasing their skill points or not"

Connection File:
Note: for a virgin installation rename this to connect.real; if the mud is up and running replace the connect.c file and reboot. To change the amount of skills a character chooses, change the values in the if(sizeof(?tmp) < x) expression in the CoomandPick(whatever)Skills() functions.

Help files for skills not written yet so code is commented out for  cmdHelpSkills(args) function.
Not good at daisy-chaining input_to() so this spam is the result:

connect.c in /lib/secure/lib

Code: [Select]
//FUNCTION PROTOTYPES

static private string *Skills;
static private string *tskills = ({});
static private string *ptmp = ({});
static private string *stmp = ({});
static private string *mtmp = ({});
static void eventSkillSelectionInstructions();
static void eventSelectPrimarySkills();
static void InputPrimarySkills(string str);
static void cmdPickPrimarySkills(string args);
static void eventSelectSecondarySkills();
static void InputSecondarySkills(string str);
static void cmdPickSecondarySkills(string args);
static void eventSelectMinorSkills();
static void InputMinorSkills(string str);
static void cmdPickMinorSkills(string args);
static void cmdHelpSkills(string args);
static private string *GetSkills();

//CODE BLOCKS

//line 698
if(!AUTO_WIZ){
        if(CLASS_SELECTION){
            eventSelectClass();
            return;
        }           
        if(SKILL_SELECTION){
            eventSkillSelectionInstructions();
            //eventSelectPrimarySkills();
            return;
        }
        eventCompleteChar();
    }
//line 818
static void eventSkillSelectionInstructions(){
    receive("\n\nYou must now choose the skill sets that will define your character.\n"
            "Available are:\n"
            "    5 PRIMARY skill slots\n"
            "    3 SECONDARY skill slots\n"
            "    5 MINOR skill slots\n\n"
            "The more you use a skill the faster your level will increase.\n"
            "Think about your character concept and choose wisely.\n");
    receive("\nDuring skill selection you will be presented with a list of available\n"
            "skills, as well as a list of skills you have already chosen. The\n"
            "following commands will be available to you:\n\n");
    receive("\thelp - shows the help file for SKILLS\n"
            "\tpick SKILL - pick a particular SKILL for yourself\n\n"
            "Press return to begin skill selection.");
    input_to((: eventSelectPrimarySkills :), I_NOESC);
}

static void eventSelectPrimarySkills(){
    int x = sizeof(ptmp);
    string rskills = format_page(sort_array(Skills, 1), 4);
    //string cpskills = format_page(sort_array(ptmp, 1), 1);
    string cpskills = format_page(sort_array(ptmp, 1), 3);
               
    receive("\n\nYou must now pick "+(5-x)+" PRIMARY Skills.\n");
    receive("\nYou have chosen the following PRIMARY Skills:\n");
    receive(cpskills);
    receive("\nValid skills to choose from:\n\n");
    receive(rskills);
    receive("\nSkill: \n");
    input_to((: InputPrimarySkills :), I_NOESC);
}

static void InputPrimarySkills(string str){
    string cmd, args, argse;
    string *tmp = Skills;
    string rskills = format_page(sort_array(Skills, 1), 4);

    if( str == "" || !str ) {
        receive("\nYou must pick a Skill: ");
        input_to((: InputPrimarySkills :), I_NOESC);
        return;
    }
    if( sscanf(str, "%s %s", cmd, args) != 2){
        cmd = str;
        args = 0;
    }
    if( sscanf(str, "%s %s", cmd, args) == 2){
        if(cmd != "pick"){
            cmd = str;
            args = 0;
        }
    }
    if(member_array(cmd, tmp) != -1){
        args = cmd;
        cmd = "pick";
    }
    switch(cmd) {
        /*case "help":
            cmdHelpSkills(args);
        return;*/

        case "pick":
            cmdPickPrimarySkills(args);
        return;

        default:
        receive("Invalid command or no such skill. Valid skills to choose from:\n");
        receive(rskills);
        receive("\nSkill: \n");
        input_to((: InputPrimarySkills :), I_NOESC);
        return;
    }
}

static void cmdPickPrimarySkills(string args) {
    string *tmp = Skills;
    string str;
    string rskills = format_page(sort_array(Skills, 1), 4);
       
    if( !args || args == "" ) {
        receive("You must specify a skill to pick. Valid skills to choose from:\n");
        receive(rskills);
        receive("\nSkill: \n");
        input_to((: InputPrimarySkills :), I_NOESC);
        return;
    }
    if( member_array(args, tmp)  == -1 ) {
        receive("No such Skill. Valid skills to choose from:\n");
        receive(rskills);
        receive("\nSkill: \n");
        input_to((: InputPrimarySkills :), I_NOESC);
        return;
    }
    if(sizeof(ptmp) < 5){
        ptmp+=({args});
        Skills -=({args});
        if(sizeof(ptmp) == 5){
            eventSelectSecondarySkills();
        }else{ eventSelectPrimarySkills();
        }
    }
}

static void eventSelectSecondarySkills(){
    int x = sizeof(stmp);
    string rskills = format_page(sort_array(Skills, 1), 4);
    string cpskills = format_page(sort_array(ptmp, 1), 3);
    string csskills = format_page(sort_array(stmp, 1), 3);
         
    receive("\nYou must now pick "+(3-x)+" SECONDARY Skills.\n");
    receive("\nYou have chosen the following PRIMARY Skills:\n");
    receive(cpskills);
    receive("\nYou have chosen the following SECONDARY Skills:\n");
    receive(csskills);
    receive("\nValid skills to choose from:\n\n");
    receive(rskills);
    receive("\nSkill: \n");
    input_to((: InputSecondarySkills :), I_NOESC);
}

static void InputSecondarySkills(string str){
    string cmd, args, argse;
    string *tmp = Skills;
    string rskills = format_page(sort_array(Skills, 1), 4);

    if( str == "" || !str ) {
        receive("\nYou must pick a Skill: ");
        input_to((: InputSecondarySkills :), I_NOESC);
        return;
    }
    if( sscanf(str, "%s %s", cmd, args) != 2){
        cmd = str;
        args = 0;
    }
    if( sscanf(str, "%s %s", cmd, args) == 2){
        if(cmd != "pick"){
            cmd = str;
            args = 0;
        }
    }
    if(member_array(cmd, tmp) != -1){
        args = cmd;
        cmd = "pick";
    }
    switch(cmd) {
        /*case "help":
            cmdHelpSkills(args);
        return;*/

        case "pick":
            cmdPickSecondarySkills(args);
        return;

        default:
        receive("Invalid command or no such skill. Valid skills to choose from:\n");
        receive(rskills);
        receive("\nSkill: \n");
        input_to((: InputSecondarySkills :), I_NOESC);
        return;
    }
}

static void cmdPickSecondarySkills(string args) {
    string *tmp = Skills;
    string str;
    string rskills = format_page(sort_array(Skills, 1), 4);

    if( !args || args == "" ) {
        receive("You must specify a skill to pick. Valid skills to choose from:\n");
        receive(rskills);
        receive("\nSkill: \n");
        input_to((: InputSecondarySkills :), I_NOESC);
        return;
    }
    if( member_array(args, tmp)  == -1 ) {
        receive("No such Skill. Valid skills to choose from:\n");
        receive(rskills);
        receive("\nSkill: \n");
        input_to((: InputSecondarySkills :), I_NOESC);
        return;
    }
    if(sizeof(stmp) < 3){
        stmp+=({args});
        Skills -=({args});
        if(sizeof(stmp) == 3){
            eventSelectMinorSkills();
        }else{ eventSelectSecondarySkills();
        }
    }
}

static void eventSelectMinorSkills(){
    int x = sizeof(mtmp);
    string rskills = format_page(sort_array(Skills, 1), 4);
    string cpskills = format_page(sort_array(ptmp, 1), 3);
    string csskills = format_page(sort_array(stmp, 1), 3);
    string cmskills = format_page(sort_array(mtmp, 1), 3);   

    receive("\n\nYou must now pick "+(5-x)+" MINOR Skills.\n");
    receive("\nYou have chosen the following PRIMARY Skills:\n");
    receive(cpskills);
    receive("\nYou have chosen the following SECONDARY Skills:\n");
    receive(csskills);
    receive("\nYou have chosen the following MINOR Skills:\n");
    receive(cmskills);
    receive("\nValid skills to choose from:\n\n");
    receive(rskills);
    receive("\nSkill: \n");
    input_to((: InputMinorSkills :), I_NOESC);
}

static void InputMinorSkills(string str){
    string cmd, args, argse;
    string *tmp = Skills;
    string rskills = format_page(sort_array(Skills, 1), 4);
   
    if( str == "" || !str ) {
        receive("\nYou must pick a Skill: ");
        input_to((: InputSecondarySkills :), I_NOESC);
        return;
    }
    if( sscanf(str, "%s %s", cmd, args) != 2){
        cmd = str;
        args = 0;
    }
    if( sscanf(str, "%s %s", cmd, args) == 2){
        if(cmd != "pick"){
            cmd = str;
            args = 0;
        }
    }
    if(member_array(cmd, tmp) != -1){
        args = cmd;
        cmd = "pick";
    }
    switch(cmd) {
        /*case "help":
            cmdHelpSkills(args);
        return;*/

        case "pick":
            cmdPickMinorSkills(args);
        return;

        default:
        receive("Invalid command or no such skill. Valid skills to choose from:\n");
        receive(rskills);
        receive("\nSkill: \n");
        input_to((: InputMinorSkills :), I_NOESC);
        return;
    }
}

static void cmdPickMinorSkills(string args) {
    string *tmp = Skills;
    string str;
    string rskills = format_page(sort_array(Skills, 1), 4);
       
    if( !args || args == "" ) {
        receive("You must specify a skill to pick. Valid skills to choose from:\n");
        receive(rskills);
        receive("\nSkill: \n");
        input_to((: InputMinorSkills :), I_NOESC);
        return;
    }
    if( member_array(args, tmp)  == -1 ) {
        receive("No such Skill. Valid skills to choose from:\n");
        receive(rskills);
        receive("\nSkill: \n");
        input_to((: InputMinorSkills :), I_NOESC);
        return;
    }
    if(sizeof(mtmp) < 5){
        mtmp+=({args});
        Skills -=({args});
        if(sizeof(mtmp) == 5){
            eventCompleteChar();
        }else{ eventSelectMinorSkills();
        }
    }


/*static void cmdHelpSkills(){
}*/

static private string *GetSkills(){
    string *ret;
    ret = Skills;
    return ret;
}

//line 900 in eventCompleteChar()
    if(ptmp){
        string str;
        receive("\nCharacter Summary\n");
        receive("-------------------------\n");
        receive("PRIMARY Skills picked:\n");
        foreach(str in ptmp){
            receive("'"+str+"' ");
            Player->AddSkill(str,1,1);
        }
        receive("\n");
    }
    if(stmp){
        string str;
        receive("\nSECONDARY Skills picked:\n");
        foreach(str in stmp){
            receive("'"+str+"' ");
            Player->AddSkill(str,2,1);
        }
        receive("\n");
    }
    if(mtmp){
        string str;
        receive("\nMINOR Skills picked:\n");
        foreach(str in mtmp){
            receive("'"+str+"' ");
            Player->AddSkill(str,3,1);
        }
        receive("\n");
    }
    this_player()->SetTerminal("ansi");
    PLAYERS_D->AddPlayerInfo(Name);
    call_out( (: eventCre, Name :), 60);
    receive("\nIf you wish to create a different character,\n"
            "use the 'suicide' command after logging in and\n"
            "start over. Have FUN!\n"
            "Press <return> within 60 seconds to continue.");     
    input_to((: eventEnterGame :), I_NOESC);
}

Leveling files for skill based leveling:

Used for collecting player data used in the skill leveling process for players.c

abilities.c in /lib/lib/lvs

Code: [Select]
//FUNCTION PROTOTYPES
private string array GetPrimarySkills();
private string array GetSecondarySkills();
private string array GetMinorSkills();

//CODE BLOCKS
//line 120
string array GetPrimarySkills(){
    return filter(keys(Skills), (: Skills[$1]["class"] == 1 :));
}

string array GetSecondarySkills(){
    return filter(keys(Skills), (: Skills[$1]["class"] == 2 :));
}

string array GetMinorSkills(){
    return filter(keys(Skills), (: Skills[$1]["class"] == 3 :));
}

Check to see if 3 primary skills, 2 secondary skills, and 1 minor skill are at max levels for the character at their current player level. If so, advance the player level. Has checks for SKILL_ADVANCE and XP_ADVANCE variables from config.h

players.c in /lib/secure/daemon
Code: [Select]
//line 306
int CheckAdvance(object ob){
    string str;
    string *ptmp = ({});
    string *stmp = ({});
    string *mtmp = ({});
    int dlev, x ,y ,z, xp, qp;
    int *plevels = ({});
    int *slevels = ({});
    int *mlevels = ({});
    int *psorted, *ssorted, *msorted;
   
    dlev = (ob->GetLevel())+1;
    /* get and sort primary skills and levels */
    if(SKILL_ADVANCE){
        ptmp = this_player()->GetPrimarySkills();
        foreach(str in ptmp){
            plevels += ({this_player()->GetSkillLevel(str)});
        }
        plevels = sort_array(plevels,-1);
        x = this_player()->GetMaxSkillLevel(ptmp[0]);
       
        /* get and sort secondary skills and levels */
        stmp = this_player()->GetSecondarySkills();
        foreach(str in stmp){
            slevels += ({this_player()->GetSkillLevel(str)});
        }   
        slevels = sort_array(slevels,-1);
        y = this_player()->GetMaxSkillLevel(stmp[0]);
       
        /* get and sort minor skills and levels */
        mtmp = this_player()->GetMinorSkills();
        foreach(str in mtmp){
            mlevels += ({this_player()->GetSkillLevel(str)});
        }
        mlevels = sort_array(mlevels,-1);
        z = this_player()->GetMaxSkillLevel(mtmp[0]);
       
        if(plevels[0] >= x && plevels[1] >= x && plevels[2] >=x
           && slevels[0] >=y && slevels[1] >= y
           && mlevels[0] >= z){
            if(AUTO_ADVANCE) AutoAdvance(ob, dlev);
            return 1;
        }
    return 0;
    }
    if(XP_ADVANCE){
        if(!ob || !playerp(ob)) return 0;
        if(!sizeof(Levels)) CompileLevelList();
        if(!Levels[dlev]) return 0;
        xp = ob->GetExperiencePoints();
        qp = ob->GetQuestPoints();
        if(xp >= Levels[dlev]["xp"] && qp >= Levels[dlev]["qp"]){
            if(AUTO_ADVANCE) AutoAdvance(ob, dlev);
            return 1;
        }
    }
    return 0;
}

Errors thrown for AddChannel() function when player logs into the mud:

/lib/player.c

Code: [Select]
//line 318 in int SetUP()
if( !GetClass() && CLASS_SELECTION ) SetClass("explorer");

//line 357
if( GetClass() ) AddChannel(GetClass());

Adding custom points when player attains a new level (optional).

genetics.c in /lib/lib

Code: [Select]
//line 42
void AddCustomizationPoints(){
     int x, y, z;
     string *stats;
     string str;

     x = this_player()->GetCustomStats(); //don't blow away players custom stat points if not used
       
     stats = this_player()->GetStats();
        foreach(str in stats){
            x += this_player()->GetBaseStatLevel(str);
            y++;
        }
        write("x is "+x+" y is "+y+"\n");
        if(x <= ((y*100)-15)){ //stat points not greater than 100
            z = random(15)+1;
            write("z is "+z+"\n");
        }else{ z = random(x)+1;
        }
     Custom = ([ "stats" : z, "deviations" : 0, "deviating" : 0, ]);
}

Where customization points get added upon leveling:

level.c in /lib/lib/lvs

Code: [Select]
//line 45
if(XP_ADVANCE){
        foreach(mixed key, mixed val in skills){
            if(skills[key]["class"] > 3) skills[key]["class"] = 4;
            subject->SetSkill(key,
                    skills[key]["level"] + moduli[skills[key]["class"]],
                    skills[key]["class"]);
        }

        foreach(mixed key, mixed val in stats){
            if(stats[key]["class"] > 3) stats[key]["class"] = 4;
            subject->SetStat(key,
                    stats[key]["level"] + moduli[stats[key]["class"]],
                    stats[key]["class"]);
        }

        subject->SetLevel(desired_level);

        if(interactive() && find_object(INSTANCES_D)){
            INSTANCES_D->SendWhoUpdate(this_object()->GetKeyName());
        }
    }

//line 65
if(SKILL_ADVANCE){
        subject->AddCustomizationPoints();
        subject->SetLevel(desired_level);

        if(interactive() && find_object(INSTANCES_D)){
            INSTANCES_D->SendWhoUpdate(this_object()->GetKeyName());
        }
    }

7
I'm a fan of Bethesda Softworks Elder Scrolls series, especially Daggerfall, where character advancement is based on skill use. I wanted to incorporate something similar into Dead Souls. Below is my design strategy and I'm looking for suggestions and comments from the experienced Admins out there:

When logging in (/lib/secure/lib/connect.c) the player is able to choose 5 primary, 3 secondary, and 5 minor skills from the current base Dead Souls skill selections - more skill selections can be added later as needed. This allows for a decent degree of player customization for their character. For example, mage types can be proficient at  blade attack as well as use magic,  etc.

Leveling is based on increasing skill levels. The more the player uses the skill the faster they will level. Currently, I have leveling increases occurring when the player reaches their maximum skill levels in 3 of the primary, 2 of the secondary, and 1 of the minor skills. Along with training points, I also wanted to add a random number of customization points. Stats will cap out at 100 and no more customization points will be allotted when leveling.

I've looked at /lib/lvs/abilities.c and have decided not to mess with the way skills and skill points are increased and alloted so far. Of course the fun part will be creating new lib or domain files that are used for training ( using eventTrain() ) and creating and adding new skills! 

Just wondering if anybody has done this and has some suggestions. I'm in the finalization part on this mod and will post the code when finished, but now it is at the point where making modifications may be relatively easy. Also the mud will be able to be configured for incorporating skill based or class based character configuration, as well as skill based or XP based character leveling.

Thanks in advance for comments and suggestions...

Below is the output for character creation after a player has chosen their primary, secondary, and 4 of 5 minor skills (text displayed is shown before the character enters the game):

You must now pick 1 MINOR Skills.
Picking these skills determines how your character will increase in levels.The
more you use a skill the faster your level will increase.

You may issue the following commands:
         help - shows the help file for SKILLS
         pick SKILL - pick a particular SKILL for yourself

You have chosen the following PRIMARY Skills:
blade attack                                                                   
blunt attack                                                                   
knife attack                                                                   
magic attack                                                                   
projectile attack                                                               

You have chosen the following SECONDARY Skills:
conjuring                                                                       
faith                                                                           
healing                                                                         

You have chosen the following MINOR Skills:
bargaining                                                                     
fishing                                                                         
stealing                                                                       
stealth                                                                         

   Valid skills:

blade defense             blunt defense             concealment               
detection                    knife defense             magic defense             
melee attack              melee defense           multi-hand               
multi-weapon             murder                      projectile defense       
psionic attack             psionic defense          psionic detection         

Skill:
detection

PRIMARY Skills picked:
magic attack
blade attack
knife attack
projectile attack
blunt attack

SECONDARY Skills picked:
conjuring
healing
faith

MINOR Skills picked:
bargaining
stealth
stealing
fishing
detection

If you wish to create a different character use the command 'suicide' after
logging in and start over. Have FUN!

8
Design Lab / Re: Bonuses, bitvectors, and resistance, oh my!
« on: December 29, 2015, 12:10:49 AM »
Note - modifications:

The functions in bonus.c and potion.c should be changed from SetMagicResistance() to SetBonusResistance() to correspond to the example potion and set them apart from  other "magic resistance" named functions in the mudlib.

9
Design Lab / Bonuses, bitvectors, and resistance, oh my!
« on: December 28, 2015, 01:26:57 PM »
I wanted to add a function to /lib/bonus that will set a resistance type in a player for a limited time:

bonus.c
Code: [Select]
/* /lib/bonus.c
 * from the dead souls mudlib http://www.dead-souls.net
 *
 * modified by Lash (ccoker) for use in The Brass Ring
 * bug fix: bonus object wasn't being destructed
 * 2015-12-28 added functionality for setting resistance
 */

#include <lib.h>
#include ROOMS_H
#include <damage_types.h>

inherit LIB_ITEM;

int SetBonuses();

mapping Skills = ([]);
mapping Stats = ([]);
mapping Points = ([]);

int Duration = 15;
string bonusname;
string brl = " "; //bonusresistance level
int brt = 0;      //bonusresistance type

void create(){
    item::create();
    AddSave( ({ "Skills", "Stats", "Points", "Duration", "bonusname" }) );
    SetInvis(1);
    SetId("bonus_object");
    SetShort("bonus");
    SetLong("A bonus");
}

void init(){
    item::init();
    set_heart_beat(1);
    if(environment(this_object()) && living(environment(this_object())))
        SetBonuses();
}

void heart_beat(){
    if(Duration) Duration--;
    /* modified by Lash - bonus object wasn't being destructed */
    else this_object()->eventDestruct();
    /* end mod */
}

mapping SetStats(mapping arg){
    Stats = copy(arg);
    if(environment(this_object()) && living(environment(this_object())))
        SetBonuses();
    return copy(Stats);
}

mapping GetStats(){
    return copy(Stats);
}

mapping SetSkills(mapping arg){
    Skills = copy(arg);
    return copy(Skills);
}

mapping GetSkills(){
    return copy(Skills);
}

mapping SetPoints(mapping arg){
    Points = copy(arg);
    return copy(Points);
}

mapping GetPoints(){
    return copy(Points);
}

int SetBonusDuration(int i){
    Duration = i;
}

int AddBonusDuration(int i){
    Duration += i;
    if(Duration < 0) Duration = 0;
    return Duration;
}

int GetBonusDuration(){
    return Duration;
}

int SetBonuses(){
    object env = environment();
    if(!env || ! living(env)) return 0;
    if(sizeof(Stats))
        foreach(string key, int val in Stats){
            env->AddStatBonus(key, val);
        }
    if(sizeof(Skills))
        foreach(string key, int val in Skills){
            env->AddSkillBonus(key, val);
        }
    if(sizeof(Points))
        foreach(string key, int val in Points){
            switch(key){
                case "HP" : env->AddHP(val);break;
                case "XP" : env->AddExperiencePoints(val);break;
                case "SP" : env->AddStaminaPoints(val);break;
                case "MP" : env->AddMagicPoints(val);break;
                case "poison" : env->AddPoison(val);break;
                case "caffeine" : env->AddCaffeine(val);break;
                case "food" : env->AddFood(val);break;
                case "drink" : env->AddDrink(val);break;
                default : break;
            }
        }
    env->SetResistance(brt,brl);
         
    return 1;
}

int RemoveBonuses(){
    object env = environment();
    if(!env || ! living(env)) return 0;
    if(sizeof(Stats))
        foreach(string key, int val in Stats){
            env->RemoveStatBonus(key);
        }
    if(sizeof(Skills))
        foreach(string key, int val in Skills){
            env->RemoveSkillBonus(key);
        }
    env->SetResistance(brt,"none");
       
    return 1;
}

int eventDestruct(){
    if(!valid_event(previous_object(), this_object())) return 0;
    RemoveBonuses();
    this_object()->eventMove(ROOM_FURNACE);
    return ::eventDestruct();
}

string GetBonusName(){
    return bonusname;
}

string SetBonusName(string name){
    return bonusname = name;
}

varargs string SetMagicResistance(int type, string level){
    brt = type;
    brl = level;
}

mixed CanGet(object who){ return 0; }
mixed CanGive(object who){ return 0; }
mixed CanSell(object who){ return 0; }
mixed CanDrop(object who){ return 0; }
mixed CanPut(object who){ return 0; }

potion.c
Code: [Select]
/* 2015-12-28
 * modified by ccoker to add functionality for resistance
 */
#include <lib.h>
#include <damage_types.h>

inherit LIB_MEAL;

mapping Skills = ([]);
mapping Stats = ([]);
mapping Points = ([]);
string brl = " ";
int brt = 0;

int Duration;

void create(){
    meal::create();
}

mapping SetStats(mapping arg){
    Stats = copy(arg);
    return copy(Stats);
}

mapping GetStats(){
    return copy(Stats);
}

mapping SetSkills(mapping arg){
    Skills = copy(arg);
    return copy(Skills);
}

mapping GetSkills(){
    return copy(Skills);
}

mapping SetPoints(mapping arg){
    Points = copy(arg);
    return copy(Points);
}

mapping GetPoints(){
    return copy(Points);
}

int SetDuration(int i){
    Duration = i;
    return Duration;
}

int GetDuration(){
    return Duration;
}

varargs string SetMagicResistance(int type, string level){
    brt = type;
    brl = level;
}

mixed eventDrink(object who){
    object ob=new(LIB_BONUS);
    ob->SetPoints(Points);
    ob->SetStats(Stats);
    ob->SetSkills(Skills);
    ob->SetBonusDuration(Duration);
    ob->SetMagicResistance(brt,brl);
    ob->eventMove(who);
    return meal::eventDrink(who);
}

mixed eventEat(object who){
    object ob=new(LIB_BONUS);
    ob->SetPoints(Points);
    ob->SetStats(Stats);
    ob->SetSkills(Skills);
    ob->SetBonusDuration(Duration);
    ob->SetMagicResistance(brt,brl);
    ob->eventMove(who);
    return meal::eventEat(who);
}

Example potion - sets resistance to ALL_EXTERNAL_DAMAGE for 300 heart_beats
Code: [Select]
/*
 * Modified by Lash (Christopher Coker) for use with:
 *
 * The Dead Souls Mud Library version 2
 * developed by Cratylus
 * http://www.dead-souls.net
 */

#include <lib.h>
#include <meal_types.h>
#include <damage_types.h>

inherit LIB_POTION;

static void create() {
    potion::create();
    SetKeyName("potion");
    SetId( ({ "potion","philtrum","purple" }) );
    SetShort("a purple potion");
    SetLong("It looks rather strange!");
    SetMass(1);
    SetMealType(MEAL_DRINK);
    SetStrength(0);
    SetBaseCost("gold",500);
    SetNoCondition(1);
    SetBonusResistance(ALL_EXTERNAL_DAMAGE,"medium");
    SetDuration(300);
    SetProperty("magic", "This potion cures confers the spell 'sanctuary' to the imbiber.");
}

void init(){
    ::init();
}

So far it seems to work. The bitvectors are being moved around correctly as defined in genetics.c and resistance to all external damage (x/2 in eventReceiveDamage() in body.c) is being processed correctly.

The drawback (maybe?!) is that other Resistance bits have the potential to be wiped out once the bonus object is destructed.

(modified to rename functions)

10
Design Lab / Re: Timed events for player characters
« 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 */


11
Design Lab / 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?  ???

12
General / Armor protection and weapon damage ranges
« on: January 12, 2015, 11:57:58 AM »
Just out of curiosity, I'm wondering what protection values others assign to armor and against what typical damage types.

What is your rationale behind having an armor protect against multiple damage types with different values assigned to their types?
Is there a specific range that you use for common and typical armors used in your scenario (instructions for builders)?
When a player has access to a description of the armor (let's say using an identify spell) what kind of information does the player get?
For example, an output might be something like:

This armor provides protection against the following damage types:
Blade - extraordinary
Blunt - poor
Shock - very good
etc.

To what values would the descriptions correspond?

Additionally, what are typical damage ranges used with the SetClass() function for weapons in the scenario?
Are there upper and lower limits that are restricted?

I know this is situational for each mud, and I've seen creator documents for other mudlibs, but nothing specifically for an up and running Dead Souls mud. Just looking for some input, or even better, if you have creator documents that can be shared for comparison purposes, that would be great!

13
Code Vault / Re: Read and Write on Parchment
« on: December 22, 2014, 03:55:01 AM »
I was just looking for this! Thanks!

14
General / Re: MUD documents and webpages
« on: December 14, 2014, 10:03:06 AM »
NannyMUD LPC pdf available here also (in addition to the html link at Lysater mentioned abve):

http://ringbreak.dnd.utwente.nl/~krimud/manual.pdf

This is the KriMud website. Looks very old and may have a limited lifespan. Also has old Nightmare docs.

15
Bug Central / Possible bug in meal.c
« on: December 13, 2014, 09:18:17 AM »
In meal.c there is this variable:
Code: [Select]
function MealAction;
defined in:

Code: [Select]
int SetMealAction(function f){
    MealAction = f;
}

The above function is not referenced in the /docs folder that I could find. No biggie. But, the function is only evaluated in 'mixed eventEat(object who)' in meal.c and not in 'mixed eventDrink(object who)'. Therefore, only meals that are eaten and not drunk get the benefit of the call to function if

Code: [Select]
SetMealAction((: foo :));
is set in a meal that is to be drunk defined by

Code: [Select]
SetMealType(MEAL_DRINK);

The following code must be added to the 'mixed eventDrink(object who)' portion of code in meal.c in order for drink meal types to make use of SetMealAction()

Code: [Select]
if( (x = functionp(MealAction)) && !(x & FP_OWNER_DESTED) ){
        evaluate(MealAction, who);
    }

The only other option discussed for making calls to a function was to use SetMealMessages() which has a check for a function pointer in the first value used in this function. SetMealAction() is useful for strictly added a call to your particular function added to the meal.

The below code is a an example for using SetMealAction() in a drink that has a one shot deal for curing paralysis in the player.
Code: [Select]
#include <lib.h>
#include <meal_types.h>

inherit LIB_MEAL;

void remove_paralysis();

static void create() {
    meal::create();
    SetKeyName("purewater");
    SetId( ({ "water","pure water" }) );
    SetShort("a vial of crystal clear pure water");
    SetLong("It is glowing!");
    SetMass(1);
    SetMealType(MEAL_DRINK);
    SetStrength(5);
    SetMealAction((: remove_paralysis :));
    //SetMealMessages((: remove_paralysis , "drink":));
    SetBaseCost("gold",500);
    SetNoCondition(1);
}

void init(){
    ::init();
}

void remove_paralysis(){
    object ob = this_player();
    if(ob && ob->GetParalyzed()) ob->SetParalyzed(0);   
    tell_player(ob, "\nThe call to function worked!\n");
   
}

Pages: [1] 2 3