|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
03-07-2009, 12:54 PM
|
Developer
|
|
Join Date: Dec 2007
Posts: 122
|
|
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;
}
|
|
|
|
|
|
|
03-08-2009, 01:26 PM
|
Developer
|
|
Join Date: Dec 2007
Posts: 122
|
|
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;
}
|
|
|
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -4. The time now is 01:46 PM.
|
|
|
|
|
|
|
|
|
|
|
|
|