It now seems a little inefficient to be initiating a complete combat situation between the monster and the play when we can directly call the function that applies the buff.
Try re-writing option 3 as follows (the first part is just the old one commented out for reference and in case this turns out not to work correctly)
- //PY: This seems a little overcomplicated. we can just send the request directly to AddBuffs() or UseBuffSkill()
- /*case 3://Recieve Buff. start battle so that AIP can actually do the buffing based on RefVar values
- {
- CCharacter* monster = GServer->GetMonsterByID(client->NPCvar,client->Position->Map);
- monster->StartAction( client, SKILL_ATTACK, nSkill );
-
- }
- break;
- */
- case 3:
- {
- //need a CCharacter object first
- CSkills* thisskill = GServer->GetSkillByID( nSkill );
- client->UseBuffSkill(client, thisskill);
- }
- break;
Doing it this way takes us directly to the UseBuffSkill() function in battle.cpp
This code modification compiles (untested for operation) in KTRose and 137 sources so it should work fine in dev rev 2
However..... There may be an issue or two in the UseBuffSkill() function as a result of there being no active "Battle" involved here.
- // use buff skill
- void CCharacter::UseBuffSkill( CCharacter* Target, CSkills* skill, bool deBuff )
- {
- bool bflag = false;
- bflag = GServer->AddBuffs( skill, Target, GetInt( ) );
- //Log(MSG_INFO,"In UseBuffSkills, skill %i, nbuffs %i, bflag %i to %u",skill->id,skill->nbuffs,bflag,Target->clientid);
- if(skill->nbuffs > 0 && bflag == true)
- {
- BEGINPACKET( pak, 0x7b5 );
- ADDWORD ( pak, Target->clientid );
- ADDWORD ( pak, clientid );
- ADDWORD ( pak, Battle->skillid );
- ADDWORD ( pak, GetInt( )/4 );
- ADDBYTE ( pak, skill->nbuffs );
- GServer->SendToVisible( &pak, Target );
- //Log(MSG_DEBUG,"Buff Skill. buffs applied 1");
- }
- if (deBuff) return;
- BEGINPACKET( pak, 0x7b9);
- ADDWORD ( pak, clientid);
- ADDWORD ( pak, Battle->skillid);
- ADDWORD ( pak, 1);
- GServer->SendToVisible( &pak, this );
- //Log(MSG_DEBUG,"Buff Skill. buffs applied 2 nbuffs = %i",skill->nbuffs);
- //Log(MSG_INFO,"UseBuffSkill: Target HP = %i",Target->Stats->HP);
- }
This is the entire function in KTRose. In mainstream osrose there will be a section after this where lmame inserted a patch for reviving dead players. I have no idea if that patch works or not and it's not really relevent here anyway
The issue that we "might" have here is that the packets all contain Battle->this and Battle->that. We have no Battle so they will all be NULL and may or may not have to be dealt with. GetINT() is a little irrelevant too.
It's probably best to just not take the chance and just deal with it anyway.
a few options present themselves.
1) modify this function by adding a boolean
bool QSD to the function definition then wrap the existing packets in a conditional with a copy of the packets with zero values in all necessary places in an else condition
2) Copy the whole function and give it a new name so that it is only used when called from QSD
3) Find a way to make dummy values that will include a fake battle and so on.
4) Completely bypass this function and directly call
GServer->AddBuffs( skill, Target, GetInt( ) ); directly from the QSD. This will mean that although you get the buffs there will be no packet sent to everyone around you showing you get them. I'm not actually sure what the packets 0x7b5 and 0x7b9 even do without tracing them through the source code. I can certainly do that but I don't really need to yet. I'm just going to assume that they show a player receiving buffs and tell the client(s) to display buff icons above your head and on your own screen. Something has to tell the client o show them right?
So out of these options I'm thinking I would go with 2.
1 is messy
3 is also messy and kind of complicated as well
4 might just fuck up everything
Soooooo
first let's add a definition into Character.h
- void UseBuffSkill( CCharacter* Target, CSkills* skill, bool deBuff = false );
- void UseBuffSkillQSD( CCharacter* Target, CSkills* skill, bool deBuff = false );
UseBuffSkillQSD has a nice ring to it I think.
now we make a copy of the original function in battle.cpp
this should be sufficient. I've replaced alll the battle stuff and sent 1 instead of GetINT() which has no target
- // use buff skill from QSD
- void CCharacter::UseBuffSkillQSD( CCharacter* Target, CSkills* skill, bool deBuff )
- {
- bool bflag = false;
- bflag = GServer->AddBuffs( skill, Target, 1 );
- //Log(MSG_INFO,"In UseBuffSkillsQSD, skill %i, nbuffs %i, bflag %i to %u",skill->id,skill->nbuffs,bflag,Target->clientid);
- if(skill->nbuffs > 0 && bflag == true)
- {
- BEGINPACKET( pak, 0x7b5 );
- ADDWORD ( pak, Target->clientid );
- ADDWORD ( pak, Target->clientid );
- ADDWORD ( pak, skill->skillid );
- ADDWORD ( pak, 1 );
- ADDBYTE ( pak, skill->nbuffs );
- GServer->SendToVisible( &pak, Target );
- //Log(MSG_DEBUG,"Buff Skill. buffs applied 1");
- }
- if (deBuff) return;
- BEGINPACKET( pak, 0x7b9);
- ADDWORD ( pak, Target->clientid);
- ADDWORD ( pak, skill->skillid);
- ADDWORD ( pak, 1);
- GServer->SendToVisible( &pak, this );
- //Log(MSG_DEBUG,"Buff Skill. buffs applied 2 nbuffs = %i",skill->nbuffs);
- //Log(MSG_INFO,"UseBuffSkillQSD: Target HP = %i",Target->Stats->HP);
- }
Lastly go back into QUESTREWD(005) and set your target function to
- client->UseBuffSkillQSD(client, thisskill);
just so that it points to our new function instead of the old one.
That should be nice and tidy and will (hopefully) work just fine. All this code is completely untested but is basically pretty simple so it should work pretty well.
The hard bit is going to be editing your NPC so that he will actually give you the buff. That is going to involve QSD to actually define the skill reward, CON and LTB to actually make the quest options appear in the NPC dialog when you speak to him.
But that is a completely different subject for now....