EQEmulator Forums

EQEmulator Forums (https://www.eqemulator.org/forums/index.php)
-   Development::Server Code Submissions (https://www.eqemulator.org/forums/forumdisplay.php?f=669)
-   -   Learning Languages (https://www.eqemulator.org/forums/showthread.php?t=27643)

realityincarnate 03-07-2009 12:54 PM

Learning Languages
 
This fix allows players to teach each other languages while grouped. It only works while grouped and in the same zone. I think the rate of learning feels about right, but it could be tinkered with. I also set the rate to be modified by the SkillUpModifier rule.

Can anyone point me to a good XS reference? I needed to modify the perl_groups code this time, and while I was able to get most of the idea by looking at other parts of the code, this part is pretty foreign to me.

Here's the diff, against R373
Code:

Index: zone/client.cpp
===================================================================
--- zone/client.cpp        (revision 373)
+++ zone/client.cpp        (working copy)
@@ -744,7 +744,7 @@
 
                Group* group = GetGroup();
                if(group != NULL) {
-                        group->GroupMessage(this,(const char*) message);
+                        group->GroupMessage(this,language,(const char*) message);
                }
                break;
        }
@@ -920,6 +920,11 @@
        if (language < MAX_PP_LANGUAGE) {
                cm->skill_in_language = m_pp.languages[language];
                cm->language = language;
+                if ((chan_num == 2) && (language != 0)) {        // for group messages not in common, check for language skill up
+                        int SenderSkill = entity_list.GetClientByName(from)->m_pp.languages[language];
+                        if ((m_pp.languages[language] <= SenderSkill) && (from != this->GetName() ))
+                                CheckLanguageSkillIncrease(language, SenderSkill);
+                }
        }
        else {
                cm->skill_in_language = 100;
@@ -1920,6 +1925,25 @@
        return false;
 }
 
+void Client::CheckLanguageSkillIncrease(int8 langid, int8 TeacherSkill) {
+        if (langid >= MAX_PP_LANGUAGE)
+                return;                // do nothing if langid is an invalid language
+
+        int LangSkill = m_pp.languages[langid];                // get current language skill
+
+        if (LangSkill < 100) {        // if the language isn't already maxed
+                sint16 Chance = 5 + ((TeacherSkill - LangSkill)/10);        // greater chance to learn if teacher's skill is much higher than yours
+                Chance = (Chance * RuleI(Character, SkillUpModifier)/100);
+
+                if(MakeRandomFloat(0,100) < Chance) {        // if they make the roll
+                        SetLanguageSkill(langid, LangSkill+1);        // increase the language skill by 1
+                        _log(SKILLS__GAIN, "Language %d at value %d successfully gain with %.4f%%chance", langid, LangSkill, Chance);
+                }
+                else
+                        _log(SKILLS__GAIN, "Language %d at value %d failed to gain with %.4f%%chance", langid, LangSkill, Chance);
+        }
+}
+
 bool Client::HasSkill(SkillType skill_id) const {
        return((GetSkill(skill_id) > 0) && CanHaveSkill(skill_id));
 }
Index: zone/client.h
===================================================================
--- zone/client.h        (revision 373)
+++ zone/client.h        (working copy)
@@ -550,6 +550,7 @@
        void CheckSpecializeIncrease(int16 spell_id);
        void CheckSongSkillIncrease(int16 spell_id);
        bool        CheckIncreaseSkill(SkillType skillid, int chancemodi = 0);
+        void        CheckLanguageSkillIncrease(int8 langid, int8 TeacherSkill);
        void    SetLanguageSkill(int langid, int value);
        void        SetHoTT(int32 mobid);
 
Index: zone/groups.cpp
===================================================================
--- zone/groups.cpp        (revision 373)
+++ zone/groups.cpp        (working copy)
@@ -664,14 +664,14 @@
        return false;
 }
 
-void Group::GroupMessage(Mob* sender, const char* message) {
+void Group::GroupMessage(Mob* sender, int8 language, const char* message) {
        uint32 i;
        for (i = 0; i < MAX_GROUP_MEMBERS; i++) {
                if(!members[i])
                        continue;
 
                if (members[i]->IsClient() && members[i]->CastToClient()->GetFilter(FILTER_GROUP)!=0)
-                        members[i]->CastToClient()->ChannelMessageSend(sender->GetName(),members[i]->GetName(),2,0,message);
+                        members[i]->CastToClient()->ChannelMessageSend(sender->GetName(),members[i]->GetName(),2,language,message);
                #ifdef IPC
                if (members[i]->CastToNPC()->IsInteractive() && members[i] != sender)
                        members[i]->CastToNPC()->InteractiveChat(2,1,message,(sender->GetTarget() != NULL) ? sender->GetTarget()->GetName():sender->GetName(),sender);
Index: zone/groups.h
===================================================================
--- zone/groups.h        (revision 373)
+++ zone/groups.h        (working copy)
@@ -68,7 +68,7 @@
        void        CastGroupSpell(Mob* caster,uint16 spellid);
        void        GroupBardPulse(Mob* caster,uint16 spellid);
        void        SplitExp(uint32 exp, Mob* other);
-        void        GroupMessage(Mob* sender,const char* message);
+        void        GroupMessage(Mob* sender,int8 language,const char* message);
        void        GroupMessage_StringID(Mob* sender, int32 type, int32 string_id, const char* message,const char* message2=0,const char* message3=0,const char* message4=0,const char* message5=0,const char* message6=0,const char* message7=0,const char* message8=0,const char* message9=0, int32 distance = 0);
        int32        GetTotalGroupDamage(Mob* other);
        void        SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Client *splitter = NULL);
Index: zone/perl_groups.cpp
===================================================================
--- zone/perl_groups.cpp        (revision 373)
+++ zone/perl_groups.cpp        (working copy)
@@ -168,12 +168,13 @@
 XS(XS_Group_GroupMessage)
 {
        dXSARGS;
-        if (items != 3)
-                Perl_croak(aTHX_ "Usage: Group::GroupMessage(THIS, sender, message)");
+        if ((items != 3) && (items != 4))        // the 3 item version is kept for backwards compatability
+                Perl_croak(aTHX_ "Usage: Group::GroupMessage(THIS, sender, language, message)");
        {
                Group *                THIS;
                Mob*                sender;
-                char*                message = (char *)SvPV_nolen(ST(2));
+                int8                language;
+                char*                message;
 
                if (sv_derived_from(ST(0), "Group")) {
                        IV tmp = SvIV((SV*)SvRV(ST(0)));
@@ -193,7 +194,17 @@
                if(sender == NULL)
                        Perl_croak(aTHX_ "sender is NULL, avoiding crash.");
 
-                THIS->GroupMessage(sender, message);
+                if (items == 4) {
+                        language = (int8)SvUV(ST(2));
+                        if ((language >= MAX_PP_LANGUAGE) || (language < 0))
+                                language = 0;
+                        message = (char *)SvPV_nolen(ST(3));
+                        THIS->GroupMessage(sender, language, message);
+                }
+                else {        // if no language is specificed, send it in common
+                        message = (char *)SvPV_nolen(ST(2));
+                        THIS->GroupMessage(sender,0, message);
+                }
        }
        XSRETURN_EMPTY;
 }


realityincarnate 03-08-2009 01:26 PM

A more extensive modification
 
(this replaces the code posted above)
After playing around with the language stuff some more, I made a couple of changes to how language skill is handled. This system now uses both the speaker and listener skills in the language to more realistically determine how garbled text becomes. As a side effect, it also enables drunk talk (one of my favorite little touches in the game).

Code:

Index: client.cpp
===================================================================
--- client.cpp        (revision 376)
+++ client.cpp        (working copy)
@@ -670,7 +670,7 @@
        return;
 }
 
-void Client::ChannelMessageReceived(int8 chan_num, int8 language, const char* message, const char* targetname) {
+void Client::ChannelMessageReceived(int8 chan_num, int8 language, int8 lang_skill, const char* message, const char* targetname) {
        #if EQDEBUG >= 11
                LogFile->write(EQEMuLog::Debug,"Client::ChannelMessageReceived() Channel:%i message:'%s'", chan_num, message);
        #endif
@@ -744,7 +744,7 @@
 
                Group* group = GetGroup();
                if(group != NULL) {
-                        group->GroupMessage(this,(const char*) message);
+                        group->GroupMessage(this,language,lang_skill,(const char*) message);
                }
                break;
        }
@@ -760,7 +760,7 @@
                if (GetPet() && GetPet()->FindType(SE_VoiceGraft))
                        sender = GetPet();
 
-                entity_list.ChannelMessage(sender, chan_num, language, message);
+                entity_list.ChannelMessage(sender, chan_num, language, lang_skill, message);
                  break;
          }
        case 4: { // Auction
@@ -783,7 +783,7 @@
                    if(!ooc_timer.Check())
                {
                        if(strlen(targetname)==0)
-                        ChannelMessageReceived(5, language, message,"discard"); //Fast typer or spammer??
+                        ChannelMessageReceived(5, language, lang_skill, message,"discard"); //Fast typer or spammer??
                        else
                        return;
                }
@@ -833,7 +833,7 @@
                        sender = GetPet();
 
                printf("Message: %s\n",message);
-                entity_list.ChannelMessage(sender, chan_num, language, message);
+                entity_list.ChannelMessage(sender, chan_num, language, lang_skill, message);
 
                if (sender != this)
                        break;
@@ -892,7 +892,12 @@
        }
 }
 
+// if no language skill is specified, call the function with a skill of 100.
 void Client::ChannelMessageSend(const char* from, const char* to, int8 chan_num, int8 language, const char* message, ...) {
+        ChannelMessageSend(from, to, chan_num, language, 100, message);
+}
+
+void Client::ChannelMessageSend(const char* from, const char* to, int8 chan_num, int8 language, int8 lang_skill, const char* message, ...) {
        if ((chan_num==11 && !(this->GetGM())) || (chan_num==10 && this->Admin()<80)) // dont need to send /pr & /petition to everybody
                return;
        va_list argptr;
@@ -917,15 +922,30 @@
                strcpy(cm->targetname, m_pp.name);
        else
                cm->targetname[0] = 0;
+       
+        int8 ListenerSkill;
+       
        if (language < MAX_PP_LANGUAGE) {
-                cm->skill_in_language = m_pp.languages[language];
+                ListenerSkill = m_pp.languages[language];
                cm->language = language;
+                if ((chan_num == 2) && (ListenerSkill < 100)) {        // group message in unmastered language, check for skill up
+                        if ((m_pp.languages[language] <= lang_skill) && (from != this->GetName() ))
+                                CheckLanguageSkillIncrease(language, lang_skill);
+                }
        }
        else {
-                cm->skill_in_language = 100;
+                ListenerSkill = m_pp.languages[0];
                cm->language = 0;
        }
-
+       
+        // set effective language skill = average of sender and receiver skills
+        sint32 EffSkill = (lang_skill + ListenerSkill)/2;
+        if (EffSkill < 1)        // effective skill has a minimum value of 1...
+                EffSkill = 1;
+        else if (EffSkill > 100)        // ...and a maximum value of 100
+                EffSkill;
+        cm->skill_in_language = EffSkill;
+       
        cm->chan_num = chan_num;
        strcpy(&cm->message[0], buffer);
        QueuePacket(&app);
@@ -1920,6 +1940,25 @@
        return false;
 }
 
+void Client::CheckLanguageSkillIncrease(int8 langid, int8 TeacherSkill) {
+        if (langid >= MAX_PP_LANGUAGE)
+                return;                // do nothing if langid is an invalid language
+
+        int LangSkill = m_pp.languages[langid];                // get current language skill
+
+        if (LangSkill < 100) {        // if the language isn't already maxed
+                sint16 Chance = 5 + ((TeacherSkill - LangSkill)/10);        // greater chance to learn if teacher's skill is much higher than yours
+                Chance = (Chance * RuleI(Character, SkillUpModifier)/100);
+
+                if(MakeRandomFloat(0,100) < Chance) {        // if they make the roll
+                        SetLanguageSkill(langid, LangSkill+1);        // increase the language skill by 1
+                        _log(SKILLS__GAIN, "Language %d at value %d successfully gain with %.4f%%chance", langid, LangSkill, Chance);
+                }
+                else
+                        _log(SKILLS__GAIN, "Language %d at value %d failed to gain with %.4f%%chance", langid, LangSkill, Chance);
+        }
+}
+
 bool Client::HasSkill(SkillType skill_id) const {
        return((GetSkill(skill_id) > 0) && CanHaveSkill(skill_id));
 }
Index: client.h
===================================================================
--- client.h        (revision 376)
+++ client.h        (working copy)
@@ -232,8 +232,9 @@
        void        SendPacketQueue(bool Block = true);
        void        QueuePacket(const EQApplicationPacket* app, bool ack_req = true, CLIENT_CONN_STATUS = CLIENT_CONNECTINGALL, eqFilterType filter=FilterNone);
        void        FastQueuePacket(EQApplicationPacket** app, bool ack_req = true, CLIENT_CONN_STATUS = CLIENT_CONNECTINGALL);
-        void        ChannelMessageReceived(int8 chan_num, int8 language, const char* message, const char* targetname=NULL);
+        void        ChannelMessageReceived(int8 chan_num, int8 language, int8 lang_skill, const char* message, const char* targetname=NULL);
        void        ChannelMessageSend(const char* from, const char* to, int8 chan_num, int8 language, const char* message, ...);
+        void        ChannelMessageSend(const char* from, const char* to, int8 chan_num, int8 language, int8 lang_skill, const char* message, ...);
        void        Message(int32 type, const char* message, ...);
        void    QuestJournalledMessage(const char *npcname, const char* message);
        void        VoiceMacroReceived(int32 Type, char *Target, int32 MacroNumber);
@@ -550,6 +551,7 @@
        void CheckSpecializeIncrease(int16 spell_id);
        void CheckSongSkillIncrease(int16 spell_id);
        bool        CheckIncreaseSkill(SkillType skillid, int chancemodi = 0);
+        void        CheckLanguageSkillIncrease(int8 langid, int8 TeacherSkill);
        void    SetLanguageSkill(int langid, int value);
        void        SetHoTT(int32 mobid);
 
Index: client_packet.cpp
===================================================================
--- client_packet.cpp        (revision 376)
+++ client_packet.cpp        (working copy)
@@ -2334,7 +2334,7 @@
                return;
        }
 
-        ChannelMessageReceived(cm->chan_num, cm->language, cm->message, cm->targetname);
+        ChannelMessageReceived(cm->chan_num, cm->language, cm->skill_in_language, cm->message, cm->targetname);
        return;
 }
 
Index: entity.cpp
===================================================================
--- entity.cpp        (revision 376)
+++ entity.cpp        (working copy)
@@ -954,7 +954,12 @@
        }
 }
 
+// if no language skill is specified, sent with 100 skill
 void EntityList::ChannelMessage(Mob* from, int8 chan_num, int8 language, const char* message, ...) {
+        ChannelMessage(from, chan_num, language, 100, message);
+}
+
+void EntityList::ChannelMessage(Mob* from, int8 chan_num, int8 language, int8 lang_skill, const char* message, ...) {
        LinkedListIterator<Client*> iterator(client_list);
        va_list argptr;
        char buffer[4096];
@@ -976,7 +981,7 @@
                if (chan_num != 8 || client->Dist(*from) < 200) // Only say is limited in range
                {
                        if(filter==FilterNone || client->GetFilter(filter)!=FilterHide)
-                                client->ChannelMessageSend(from->GetName(), 0, chan_num, language, buffer);
+                                client->ChannelMessageSend(from->GetName(), 0, chan_num, language, lang_skill, buffer);
                }
                iterator.Advance();
        }
Index: entity.h
===================================================================
--- entity.h        (revision 376)
+++ entity.h        (working copy)
@@ -236,6 +236,7 @@
        void        MessageClose_StringID(Mob *sender, bool skipsender, float dist, int32 type, int32 string_id, const char* message1=0,const char* message2=0,const char* message3=0,const char* message4=0,const char* message5=0,const char* message6=0,const char* message7=0,const char* message8=0,const char* message9=0);
        void        ChannelMessageFromWorld(const char* from, const char* to, int8 chan_num, int32 guilddbid, int8 language, const char* message);
        void    ChannelMessage(Mob* from, int8 chan_num, int8 language, const char* message, ...);
+        void    ChannelMessage(Mob* from, int8 chan_num, int8 language, int8 lang_skill, const char* message, ...);
        void        ChannelMessageSend(Mob* to, int8 chan_num, int8 language, const char* message, ...);
        void    SendZoneSpawns(Client*);
        void        SendZonePVPUpdates(Client *);
Index: groups.cpp
===================================================================
--- groups.cpp        (revision 376)
+++ groups.cpp        (working copy)
@@ -664,14 +664,14 @@
        return false;
 }
 
-void Group::GroupMessage(Mob* sender, const char* message) {
+void Group::GroupMessage(Mob* sender, int8 language, int8 lang_skill, const char* message) {
        uint32 i;
        for (i = 0; i < MAX_GROUP_MEMBERS; i++) {
                if(!members[i])
                        continue;
 
                if (members[i]->IsClient() && members[i]->CastToClient()->GetFilter(FILTER_GROUP)!=0)
-                        members[i]->CastToClient()->ChannelMessageSend(sender->GetName(),members[i]->GetName(),2,0,message);
+                        members[i]->CastToClient()->ChannelMessageSend(sender->GetName(),members[i]->GetName(),2,language,lang_skill,message);
                #ifdef IPC
                if (members[i]->CastToNPC()->IsInteractive() && members[i] != sender)
                        members[i]->CastToNPC()->InteractiveChat(2,1,message,(sender->GetTarget() != NULL) ? sender->GetTarget()->GetName():sender->GetName(),sender);
Index: groups.h
===================================================================
--- groups.h        (revision 376)
+++ groups.h        (working copy)
@@ -68,7 +68,7 @@
        void        CastGroupSpell(Mob* caster,uint16 spellid);
        void        GroupBardPulse(Mob* caster,uint16 spellid);
        void        SplitExp(uint32 exp, Mob* other);
-        void        GroupMessage(Mob* sender,const char* message);
+        void        GroupMessage(Mob* sender,int8 language,int8 lang_skill,const char* message);
        void        GroupMessage_StringID(Mob* sender, int32 type, int32 string_id, const char* message,const char* message2=0,const char* message3=0,const char* message4=0,const char* message5=0,const char* message6=0,const char* message7=0,const char* message8=0,const char* message9=0, int32 distance = 0);
        int32        GetTotalGroupDamage(Mob* other);
        void        SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Client *splitter = NULL);
Index: perl_groups.cpp
===================================================================
--- perl_groups.cpp        (revision 376)
+++ perl_groups.cpp        (working copy)
@@ -168,12 +168,13 @@
 XS(XS_Group_GroupMessage)
 {
        dXSARGS;
-        if (items != 3)
-                Perl_croak(aTHX_ "Usage: Group::GroupMessage(THIS, sender, message)");
+        if ((items != 3) && (items != 4))        // the 3 item version is kept for backwards compatability
+                Perl_croak(aTHX_ "Usage: Group::GroupMessage(THIS, sender, language, message)");
        {
                Group *                THIS;
                Mob*                sender;
-                char*                message = (char *)SvPV_nolen(ST(2));
+                int8                language;
+                char*                message;
 
                if (sv_derived_from(ST(0), "Group")) {
                        IV tmp = SvIV((SV*)SvRV(ST(0)));
@@ -193,7 +194,17 @@
                if(sender == NULL)
                        Perl_croak(aTHX_ "sender is NULL, avoiding crash.");
 
-                THIS->GroupMessage(sender, message);
+                if (items == 4) {
+                        language = (int8)SvUV(ST(2));
+                        if ((language >= MAX_PP_LANGUAGE) || (language < 0))
+                                language = 0;
+                        message = (char *)SvPV_nolen(ST(3));
+                        THIS->GroupMessage(sender, language, 100, message);
+                }
+                else {        // if no language is specificed, send it in common
+                        message = (char *)SvPV_nolen(ST(2));
+                        THIS->GroupMessage(sender,0, 100, message);
+                }
        }
        XSRETURN_EMPTY;
 }



All times are GMT -4. The time now is 07:27 PM.

Powered by vBulletin®, Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.