// Props to ExJam for this code :D Ported to OSpRose by Drakia #include "../WorldServer.h" dword GetRewardValue(dword function, dword amount, CPlayer* client, word nDupCNT) { switch(function) { case 0: { dword tempVal = amount + 0x1E; tempVal *= client->Attr->Cha + 0x0a; // We need to add a way to get all stats totals (Including buff, E, etc) - Drakia tempVal *= (100 & 0xFFFF);//World Rate tempVal *= 0x14;//Fame + 0x14 tempVal = ((tempVal / (client->Stats->Level + 0x46)) / 0x7530) + amount; return tempVal; } break; case 1: { dword tempVal = (client->Stats->Level + 3) * amount; tempVal *= (client->Attr->Cha >> 1) + client->Stats->Level + 0x28; tempVal *= (100 & 0xFFFF);//World Rate return tempVal / 0x2710; } break; case 2: return (amount * nDupCNT); break; case 3: case 5: { dword tempVal = amount + 0x14; tempVal *= client->Attr->Cha + 0x0a; tempVal *= (100 & 0xFFFF);//World Rate tempVal *= 0x14;//Fame + 0x14 tempVal = ((tempVal / (client->Stats->Level + 0x46)) / 0x7530) + amount; return tempVal; } break; case 4: { dword tempVal = amount + 0x2; tempVal *= (client->Attr->Cha + client->Stats->Level + 0x28); tempVal *= 0x28;//Fame + 0x28 tempVal *= (100 & 0xFFFF);//World Rate return tempVal / 0x222E0; } break; case 6: { dword tempVal = amount + 0x14; tempVal *= client->Attr->Cha + client->Stats->Level; tempVal *= 0x14;//Fame + 0x14 tempVal *= (100 & 0xFFFF);//World Rate return (tempVal / 0x2DC6C0) + amount; } break; default: break; } return amount; } //Update Quest QUESTREWD(000) { //dword iQuestSN pos 0x00 //byte btOp pos 0x04 GETREWDDATA(000); switch(data->btOp) //0 remove, 1 start, 2 replace quest keep items, 3 replace quest delete items, 4 select { case 0: { if( client->questdebug ) server->SendPM(client, "Remove Quest: %u", data->iQuestSN); if (client->ActiveQuest == data->iQuestSN) client->ActiveQuest = 0; for(dword i = 0; i < 10; i++) { if(client->quest.quests[i].QuestID != data->iQuestSN) continue; memset(&client->quest.quests[i], 0, sizeof(SQuest)); break; } } break; case 1: { if( client->questdebug ) server->SendPM(client, "Start Quest: %u", data->iQuestSN); for(dword i = 0; i < 10; i++) { if(client->quest.quests[i].QuestID == data->iQuestSN) return QUEST_SUCCESS; if(client->quest.quests[i].QuestID != 0) continue; memset(&client->quest.quests[i], 0, sizeof(SQuest)); client->quest.quests[i].QuestID = data->iQuestSN; client->quest.quests[i].StartTime = time(NULL); break; } client->ActiveQuest = data->iQuestSN; } break; case 2: { if( client->questdebug ) server->SendPM(client, "Replace Quest, keep items: %u", data->iQuestSN); for(dword i = 0; i < 10; i++) { if(client->quest.quests[i].QuestID != client->ActiveQuest) continue; client->quest.quests[i].QuestID = data->iQuestSN; client->quest.quests[i].StartTime = time(NULL); break; } client->ActiveQuest = data->iQuestSN; } break; case 3: { if( client->questdebug ) server->SendPM(client, "Replace Quest, delete items: %u", data->iQuestSN); for(dword i = 0; i < 10; i++) { if(client->quest.quests[i].QuestID != client->ActiveQuest) continue; memset(&client->quest.quests[i], 0, sizeof(SQuest)); client->quest.quests[i].QuestID = data->iQuestSN; client->quest.quests[i].StartTime = time(NULL); break; } client->ActiveQuest = data->iQuestSN; } break; case 4: { if( client->questdebug ) server->SendPM(client, "Select Quest: %u", data->iQuestSN); client->ActiveQuest = data->iQuestSN; } break; default: break; } return QUEST_SUCCESS; } //Update Quest Items QUESTREWD(001) { //dword uiItemSN; pos 0x00 //byte btOp; pos 0x04 //word nDupCNT; pos 0x06 //byte btPartyOpt; pos 0x0a GETREWDDATA(001); if( client->questdebug )server->SendPM(client, "Update Quest Item (uiItemSN: %u btOp: %u nDupCNT: %u)", data->uiItemSN, data->btOp, data->nDupCNT); CItem tmpItem; tmpItem.itemtype = data->uiItemSN / 1000; tmpItem.itemnum = data->uiItemSN % 1000; tmpItem.count = data->nDupCNT; SQuest* curQuest = client->GetActiveQuest(); if(curQuest == NULL) { //Log(MSG_DEBUG, "Couldn't find active quest, wtf? Id %u", client->ActiveQuest); return QUEST_FAILURE; } curQuest->AddItem(&tmpItem, data->btOp); return QUEST_SUCCESS; } //Set Quest Variable QUESTREWD(002) { GETREWDDATA(002); //dword iDataCnt; pos 0x00 //dword iType; pos 0x04 union. This or //short m_mVarNo pos 0x04 this + //word m_wVarTYPE; pos 0x06 Type of quest variable // 0 GetVarType = "ActiveQuest" // 16 GetVarType = "SwitchBit" // 32 GetVarType = "Remaining Time" // 48 GetVarType = "EpisodeVar" // 64 GetVarType = "JobVar" // 80 GetVarType = "PlanetVar" // 96 GetVarType = "UnionVar" //word nValue; pos 0x08 //byte btOp; pos 0x0a for(dword i = 0; i < data->iDataCnt; i++) { dword address = i * sizeof(STR_QUEST_DATA); address += (dword)data; address += 4; STR_QUEST_DATA* curQst = (STR_QUEST_DATA*)address; if( client->questdebug ) server->SendPM(client, "Set quest var[%#04x][%i] - %i (Op: %i)", curQst->m_wVarTYPE, curQst->m_wVarNO, curQst->nValue, curQst->btOp ); word nValue = curQst->nValue; word tempValue = client->GetQuestVar(curQst->m_wVarTYPE, curQst->m_wVarNO); OperateValues(curQst->btOp, &tempValue, curQst->nValue); client->SetQuestVar(curQst->m_wVarTYPE, curQst->m_wVarNO, tempValue); } return QUEST_SUCCESS; } //Update Stats QUESTREWD(003) { GETREWDDATA(003); //dword iDataCnt; pos 0x00 //dword iType; pos 0x04 //dword iValue; pos 0x08 //byte btOp; pos 0x0c for(dword i = 0; i < data->iDataCnt; i++) { //dword address = i * 0x0C; //address += (dword)data; //address += 4; //STR_ABIL_DATA* curAbil = (STR_ABIL_DATA*)address; if( client->questdebug ) server->SendPM(client, "Update stat[%i] %i (Op: %i)", data->iType, data->iValue, data->btOp); switch( data->iType ) { case 2: //Gender { if(!OperateValues(data->btOp, (int*)&client->CharInfo->Sex, data->iValue)) return QUEST_FAILURE; //client->CharInfo->Sex = data->iValue; //BEGINPACKET( pak, 0x720 ); //ADDWORD( pak, 2 ); //ADDWORD( pak, client->CharInfo->Sex ); //ADDWORD( pak, 0 ); //GServer->SendToVisible( &pak, client ); //client->client->SendPacket( &pak ); //RESETPACKET( pak, 0x0730 ); //ADDWORD( pak, 5 ); //ADDWORD( pak, 0xa24d ); //ADDWORD( pak, 0x40b3 ); //GServer->SendToVisible( &pak, client ); //client->client->SendPacket( &pak ); client->quicksave(); } break; case 4: //job { if(!OperateValues(data->btOp, (int*)&client->CharInfo->Job, data->iValue)) return QUEST_FAILURE; BEGINPACKET(pak, 0x721 ); ADDWORD(pak, data->iType ); ADDDWORD(pak, data->iValue ); client->client->SendPacket( &pak ); client->quicksave(); } break; case 5: //union { if (!OperateValues(data->btOp, (int*)&client->Union_s->unionvar[0], data->iValue)) return QUEST_FAILURE; BEGINPACKET(pak, 0x721 ); ADDWORD(pak, data->iType ); ADDDWORD(pak, data->iValue ); client->client->SendPacket( &pak ); client->quicksave(); //Log(MSG_DEBUG,"Client Union changed"); } break; case 8: // face { if (!OperateValues(data->btOp, (int*)&client->CharInfo->Face, data->iValue)) return QUEST_FAILURE; BEGINPACKET(pak, 0x721); ADDWORD(pak, 8); ADDWORD(pak, client->CharInfo->Face); ADDWORD(pak, 0); GServer->SendToVisible( &pak, client ); //client->client->SendPacket(&pak); RESETPACKET(pak, 0x0730); ADDWORD(pak, 5); ADDWORD(pak, 0xa24d); ADDWORD(pak, 0x40b3); GServer->SendToVisible( &pak, client ); //client->client->SendPacket(&pak); client->quicksave(); } break; case 9: // Hair { if (!OperateValues(data->btOp, (int*)&client->CharInfo->Hair, data->iValue)) return QUEST_FAILURE; BEGINPACKET(pak, 0x721); ADDWORD(pak, 9); ADDWORD(pak, client->CharInfo->Hair); ADDWORD(pak, 0); GServer->SendToVisible( &pak, client ); //client->client->SendPacket(&pak); RESETPACKET(pak, 0x0730); ADDWORD(pak, 5); ADDWORD(pak, 0xa24d); ADDWORD(pak, 0x40b3); GServer->SendToVisible( &pak, client ); //client->client->SendPacket(&pak); client->quicksave(); } case 81: // Union points for junon order case 82: case 83: // Union points for righteous crusaders case 84: case 85: case 86: case 87: // Union 7 points used for tracking previous memberships case 88: case 89: //kuro-Tejina Union points case 90: { if (!OperateValues(data->btOp, (int*)&client->Union_s->unionvar[data->iType - 80], data->iValue)) return QUEST_FAILURE; BEGINPACKET(pak, 0x720 ); ADDWORD(pak, data->iType ); ADDDWORD(pak, data->iValue ); client->client->SendPacket( &pak ); if(data->iType == 89) //update the database if the quest just gave KTPoints { GServer->DB->QExecute("UPDATE accounts SET ktpoints=%i WHERE id=%i AND password='%s'", client->Session->KTPoints,client->Session->userid, client->Session->password); } } break; case 10: //strength if(!OperateValues(data->btOp, (int*)&client->Attr->Str, data->iValue)) return QUEST_FAILURE; break; case 11: //dexterity if(!OperateValues(data->btOp, (int*)&client->Attr->Dex, data->iValue)) return QUEST_FAILURE; break; case 12: //inteligence if(!OperateValues(data->btOp, (int*)&client->Attr->Int, data->iValue)) return QUEST_FAILURE; break; case 13: //concentration if(!OperateValues(data->btOp, (int*)&client->Attr->Con, data->iValue)) return QUEST_FAILURE; break; case 14: //charm if(!OperateValues(data->btOp, (int*)&client->Attr->Cha, data->iValue)) return QUEST_FAILURE; break; case 15: //sense if(!OperateValues(data->btOp, (int*)&client->Attr->Sen, data->iValue)) return QUEST_FAILURE; break; case 30: // set global XP rate { GServer->Config.EXP_RATE = data->iValue; return QUEST_SUCCESS; } break; case 31: //level if(!OperateValues(data->btOp, (int*)&client->Stats->Level, data->iValue)) return QUEST_FAILURE; break; case 32: // Stat points if(!OperateValues(data->btOp, (int*)&client->CharInfo->StatPoints, data->iValue)) return QUEST_FAILURE; break; case 37: // Skill points if(!OperateValues(data->btOp, (int*)&client->CharInfo->SkillPoints, data->iValue)) return QUEST_FAILURE; break; //case sMoney: //if(!OperateValues(data->btOp, (int*)&client->CharInfo->Zulies, data->iValue)) //return QUEST_FAILURE; //break; case 40: //money { if(!OperateValues(data->btOp, (int*)&client->CharInfo->Zulies, data->iValue)) return QUEST_FAILURE; // Send zuly update packet BEGINPACKET(pak, 0x71D); ADDQWORD( pak, client->CharInfo->Zulies ); client->client->SendPacket( &pak ); } break; default: Log(MSG_WARNING, "Type Unknown: '%i'", data->iType); break; } } return QUEST_SUCCESS; } //Set Quest Variable QUESTREWD(004) { return QUEST_REWD_002(server, client, raw); } //Give Reward QUESTREWD(005) { GETREWDDATA(005); //byte btTarget; // pos 0x00 //union //{ // byte btEquation; // pos 0x02 apparently should be 0x01 // word nEquation; //}; //byte btEquation; // pos 0x01 //word nEquation; // pos 0x02 //int iValue; // pos 0x04 //dword iItemSN; // pos 0x06 //union //{ // byte btPartyOpt; // pos 0x0a // word nPartyOpt; //}; //word nItemOpt; // pos 0x0c //word nSkill. Co-opting nItemOpt as a skill id word nSkill = data->nItemOpt; if( client->questdebug ) server->SendPM(client, "Quest reward 005 using equation %i", data->btEquation); switch(data->btTarget) { case 0://EXP { if( client->questdebug ) server->SendPM(client, "Give EXP: %i", data->iValue); client->CharInfo->Exp += GetRewardValue(data->btEquation, data->iValue, client, 0); BEGINPACKET(pak, 0x79b); ADDDWORD(pak, client->CharInfo->Exp); ADDDWORD(pak, client->CharInfo->stamina); ADDWORD (pak, 0); client->client->SendPacket(&pak); } break; case 1://Zuly { if( client->questdebug ) server->SendPM(client, "Give Zuly: %i", data->iValue); unsigned int j = client->CheckQuest; int itemcount = client->quest.quests[j].Items[0].count; if( client->questdebug ) server->SendPM(client, "Items returned: %i", itemcount); //int Zulyreward = GetRewardValue(data->btEquation, data->iValue, client, itemcount); // temp fix int Zulyreward = data->iValue; if(itemcount > 0 ) //this is for cases where multiple items are handed in for fetch quest. Zulyreward = data->iValue * itemcount; client->CharInfo->Zulies += Zulyreward; //client->CharInfo->Zulies += GetRewardValue(data->btEquation, data->iValue, client, 1);//dunno nDupCount for this one! BEGINPACKET(pak, 0x71D); ADDQWORD(pak, client->CharInfo->Zulies); client->client->SendPacket(&pak); } break; case 2://Item { CItem nItem; nItem.itemtype = data->iItemSN / 1000; nItem.itemnum = data->iItemSN % 1000; if(nItem.IsStackable()) { nItem.count = GetRewardValue(data->btEquation, data->iValue, client, 0); } else { nItem.count = 1; } if( client->questdebug ) server->SendPM(client, "Give item [%i][%i]x%i", nItem.itemtype, nItem.itemnum, nItem.count); nItem.durability = GServer->STB_ITEM[nItem.itemtype-1].rows[nItem.itemnum][29]; nItem.gem = 0; nItem.stats = 0; nItem.refine = 0; nItem.socketed = 0; nItem.lifespan = 100; nItem.appraised = 1; dword slot = client->AddItem(nItem); if (slot == 0xffff) // Fail { BEGINPACKET( pak, 0x7a7); ADDWORD(pak, 0x00); ADDBYTE(pak, 0x03); ADDBYTE(pak, 0x00); client->client->SendPacket(&pak); } else // Success { BEGINPACKET( pak, 0x71f); ADDBYTE(pak, 0x01); ADDBYTE(pak, slot); ADDWORD(pak, client->items[slot].GetPakHeader( ) ); ADDDWORD(pak, client->items[slot].GetPakData( ) ); client->client->SendPacket(&pak); } } break; //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->UseBuffSkillQSD(client, thisskill); } break; default: break; } return QUEST_SUCCESS; } //Restore HP/MP QUESTREWD(006) { //dword iPercentOfHP pos 0x00 //dword iPercentOfMP pos 0x04 //byte btPartyOpt pos 0x08 GETREWDDATA(006); if( client->questdebug ) server->SendPM(client, "Restore %i%% HP, %i%% MP", data->iPercentOfHP, data->iPercentOfMP); client->Stats->HP = (long int)((float)client->Stats->MaxHP / 100.0f) * data->iPercentOfHP; client->Stats->MP = (long int)((float)client->Stats->MaxHP / 100.0f) * data->iPercentOfMP; return QUEST_SUCCESS; } //Teleport QUESTREWD(007) { //dword iZoneSN; pos 0x00 //dword iX; pos 0x04 //dword iY; pos 0x08 //byte btPartyOpt; pos 0x0d GETREWDDATA(007); fPoint thispoint; thispoint.x = floor(((float)data->iX)/100); thispoint.y = floor(((float)data->iY)/100); if( client->questdebug ) server->SendPM(client, "Teleport [%i][%f][%f]", data->iZoneSN, thispoint.x, thispoint.y); GServer->TeleportTo(client, data->iZoneSN, thispoint); return QUEST_SUCCESS; } //Spawn Monster QUESTREWD(008) { //dword iMonsterSN pos 0x00 //dword iHowMany pos 0x04 // byte btWho pos 0x08 or // int iWho pos 0x08 //dword iZoneSN pos 0x0a //dword iX pos 0x0e //dword iY pos ox11 //dword iRange pos 0x15 //dword iTeamNo pos 0x19 GETREWDDATA(008); fPoint position; dword mapId; if(data->iX == 0 || data->iY == 0 || data->iZoneSN == 0) { position.x = client->Position->current.x; position.y = client->Position->current.y; mapId = client->Position->Map; } else { position.x = data->iX / 100; position.y = data->iY / 100; mapId = data->iZoneSN; } for(dword i = 0; i < data->iHowMany; i++) { fPoint pos = GServer->RandInCircle( position, data->iRange ); if( client->questdebug ) server->SendPM(client, "Spawn mob[%i] @ %f, %f", data->iMonsterSN, pos.x, pos.y); CMap* map = GServer->MapList.Index[mapId]; CMonster* mon = map->AddMonster( data->iMonsterSN, pos, 0, 0 , 1 ); if(data->iMonsterSN > 750 && data->iMonsterSN < 755) // ghost rackies = non aggresive { mon->thisnpc->aggresive = 0; } else { mon->thisnpc->aggresive = 999; // Force the mob to be agressive. } mon->lastSighCheck = 0; // Force sight check instantly. } return QUEST_SUCCESS; } //Execute Quest Trigger QUESTREWD(009) { //word shNameLen pos 0x00 //string szNextTriggerSN pos 0x02 GETREWDDATA(009); char* tempName = reinterpret_cast(&data->szNextTriggerSN) - 2; dword hash = MakeStrHash(tempName); if( client->questdebug ) server->SendPM(client, "Execute Quest Trigger %s[%d] [%08x]", tempName, data->shNameLen, hash); return client->ExecuteQuestTrigger(hash); //return QUEST_SUCCESS; } //Reset Stats QUESTREWD(010) { if( client->questdebug ) server->SendPM(client, "Reset Stats"); client->CharInfo->StatPoints = 0; client->Attr->Str = 15; client->Attr->Dex = 15; client->Attr->Int = 15; client->Attr->Con = 15; client->Attr->Cha = 10; client->Attr->Sen = 10; for(int i = 2; i <= client->Stats->Level; i++) { client->CharInfo->StatPoints += 10; client->CharInfo->StatPoints += i / 2; } return QUEST_SUCCESS; } //Update Object Var QUESTREWD(011) { GETREWDDATA(011); /*if(data->btWho == 0) //npc { CMonster* monster = reinterpret_cast(entity); if(monster == NULL) return QUEST_FAILURE; if(data->nVarNo > 19) return AI_FAILURE; short tempval = GServer->ObjVar[monster->thisnpc->refNPC][data->nVarNo]; switch(data->btOp) { case 5: tempval = data->iValue; break; case 6: tempval += data->iValue; break; case 7: tempval -= data->iValue; case 9: tempval++; break; default: return QUEST_FAILURE; break; } if(tempval < 0)tempval = 0; GServer->ObjVar[monster->thisnpc->refNPC][data->nVarNo] = tempval; return QUEST_SUCCESS; } else if(data->btWho == 1) // event { //need to write the event code still it seems. Seems easy enough return QUEST_FAILURE; }*/ /*if(entity->_EntityType != ENTITY_NPC) return QUEST_FAILURE; if(data->btWho == 0){//Npc CNpc* thisNpc = reinterpret_cast(entity); thisNpc = thisNpc->SelectedNpc; if(thisNpc == NULL) return QUEST_FAILURE; short VarValue = thisNpc->ObjVar.GetVar(data->nVarNo); OperateValues(data->btOp, &VarValue, (short)data->iValue); thisNpc->ObjVar.SetVar(data->nVarNo, VarValue); }else if(data->btWho == 1){//Event short VarValue = server->EventVar.GetVar(data->nVarNo); OperateValues(data->btOp, &VarValue, (short)data->iValue); server->EventVar.SetVar(data->nVarNo, VarValue); } return QUEST_SUCCESS;*/ //byte btWho; pos 0x00 //word nVarNo; pos 0x02 //dword iValue; pos 0x04 this was an int but ints only hold 2 bytes so btop would be out of position //byte btOp; pos 0x08 btop definitely at position 0x08 so had to adjust iValue int tempval; if(data->btWho == 0) { if(data->nVarNo > 19) return AI_FAILURE; tempval = GServer->ObjVar[client->NPCvar][data->nVarNo]; //Log(MSG_INFO,"Just checking. NPCvar = %i", client->NPCvar); switch( data->btOp ) { case 5: tempval = data->iValue; break; case 6: tempval += data->iValue; break; case 7: tempval -= data->iValue; break; case 9: tempval++; break; default: return QUEST_FAILURE; break; } } else if(data->btWho == 1) //event { // not sure what to do here yet return QUEST_FAILURE; } GServer->ObjVar[client->NPCvar][data->nVarNo] = tempval; return QUEST_SUCCESS; } //NPC Speak QUESTREWD(012) { //if(entity->_EntityType != ENTITY_NPC) return QUEST_FAILURE; GETREWDDATA(012); /* CNpc* thisNpc = reinterpret_cast(entity); if(thisNpc->SelectedNpc == NULL) return QUEST_FAILURE; std::map::iterator triggerITR = server->NpcNames.find(thisNpc->SelectedNpc->NpcID); if(triggerITR == server->NpcNames.end()) return QUEST_FAILURE; char* npcName = triggerITR->second; char* sayStr = server->lngQst->GetLTBStr(data->iStrID); if(sayStr == NULL) return QUEST_FAILURE; if(data->btMsgType == 1){ //Shout CPacket pakout(0x785); pakout.Add(npcName); pakout.Add(sayStr); server->SendPacketToZone(thisNpc, &pakout); }else if(data->btMsgType == 2){ //Announce CPacket pakout(0x702); pakout.AddBytes((byte*)npcName, strlen(npcName)); pakout.Add('>'); pakout.Add(sayStr); server->SendPacketToZone(thisNpc, &pakout); } delete [] sayStr;*/ dword npcId = 0; //if(entity->_EntityType == ENTITY_NPC) //CMonster* thisMonster = reinterpret_cast(entity); switch(data->btMsgType) { case 0: //whisper to client // don't think this is possible. No way to get a character to send it to?? break; case 1: //shout to map Log(MSG_INFO,"Quest -- NPC Shouts LTB string %i to map %i",data->iStrID,client->Position->Map); GServer->NPCShout(client->Position->Map,GServer->Ltbstring[data->iStrID].QuestLTB,GServer->Ltbstring[data->iStrID].QuestNpcName); break; case 2: //announce to server. Log(MSG_INFO,"Quest -- NPC announces LTB string %i to map %i",data->iStrID,client->Position->Map); GServer->NPCAnnounce(GServer->Ltbstring[data->iStrID].QuestLTB,GServer->Ltbstring[data->iStrID].QuestNpcName); break; default: break; } return QUEST_SUCCESS; // This is cool and all, but we lack the stuff to do it - Drakia // Not any more - PY } //Execute Quest Trigger with time delay. STILL NEEDS TO BE CODED QUESTREWD(013) { // byte btWho pos 0x00 // int iWho pos 0x00 //dword iSec pos 0x02 //word nNameLength pos 0x06 //string szTriggerName pos 0x08 //dword m_HashNextTrigger pos 0x06 + nNameLength? //looks like a quest trigger with a timer delay to me GETREWDDATA(013); char* tempName = reinterpret_cast(&data->szTriggerName) - 2; dword hash = MakeStrHash(tempName); if( client->questdebug ) server->SendPM(client, " RWD 013 Execute Quest Trigger %s[%d] [%08x]", tempName, data->nNameLength, hash); //suppress the actual execution for now just to be sure return client->ExecuteQuestTrigger(hash); return QUEST_SUCCESS; } //Learn Skill QUESTREWD(014) { // byte btOp pos 0x00 // int iOp pos 0x00 //dword iSkillNo pos 0x02 GETREWDDATA(014); if( client->questdebug ) server->SendPM(client, "Learn skill: %i", data->iSkillNo); GServer->LearnSkill(client, data->iSkillNo, false); return QUEST_SUCCESS; } //Set Quest Flag QUESTREWD(015) { GETREWDDATA(015); //word nSN; 0x00 //byte btOp; 0x02 if( client->questdebug ) server->SendPM(client, "Set QFlag[%i]=%i", data->nSN, data->btOp); client->quest.SetFlag(data->nSN, (data->btOp == 1)?true:false); // PY method //client->quest.Qflags[data->nSN] == data->btOp; // PY end return QUEST_SUCCESS; } //Unknown QUESTREWD(016) { //word nGroupSN pos 0x00 return QUEST_SUCCESS; } //Reset All Quest Flags QUESTREWD(017) { if( client->questdebug ) server->SendPM(client, "Reset all quest flags"); //memset(&client->quest.flags, 0, 64); // PY method for(UINT i=0;i<1000;i++) { for(int j=0;j<8;j++) { client->quest.Qflags[i][j] = 0; } } // PY end return QUEST_SUCCESS; } //Send Announcement QUESTREWD(018) { //dword iStrID pos 0x00 //word nCnt pos 0x04 //string Data pos 0x06 //why isn't this coded? looks simple enough GETREWDDATA(018); char* tempName = reinterpret_cast(&data->Data) - 2; if( client->questdebug ) server->SendPM(client, " RWD 018 Send announcement %s", tempName); Log(MSG_INFO,"Announcement to all %s",tempName); GServer->NPCAnnounce(tempName,"Quest NPC"); return QUEST_SUCCESS; } //Execute Quest Trigger in Other Map QUESTREWD(019) { //this is going to be a pain //it runs a quest trigger that would appear to be sent to every player in the designated zone //word nZoneNo; //pos 0x00 //word nTeamNo; //pos 0x02 //word nTriggerLength; //pos 0x04 This is definitely NOT the length of the following name. PY //string TriggerName; //pos 0x06 + nTriggerlength more bytes. name is zero terminated so m_hashtrigger position varies //dword m_HashTrigger; //word m_HashTrigger; //pos 0x17 only has 2 bytes not 4. PY // let's check the values first GETREWDDATA(019); //Log(MSG_DEBUG,"Execute Quest trigger: %s for zone %i. Hash: %i",data->TriggerName, data->nZoneNo, data->m_HashTrigger); /*CMap* map = GServer->MapList.Index[data->nZoneNo]; if(map == NULL) return QUEST_SUCCESS; if( map->PlayerList.size()<1 ) return QUEST_SUCCESS; for(UINT j=0;jPlayerList.size();j++) { CPlayer* player = map->PlayerList.at(j); player->ExecuteQuestTrigger(data->m_HashTrigger); } return QUEST_SUCCESS;*/ char* tempName = reinterpret_cast(&data->TriggerName) - 2; dword hash = MakeStrHash(tempName); CMap* map = GServer->MapList.Index[data->nZoneNo]; if(map == NULL) return QUEST_SUCCESS; if( map->PlayerList.size()<1 ) return QUEST_SUCCESS; for(UINT j=0;jPlayerList.size();j++) { CPlayer* player = map->PlayerList.at(j); player->ExecuteQuestTrigger(hash); } return QUEST_SUCCESS; } //PvP Status QUESTREWD(020) { GETREWDDATA(020); //byte btNoType; pos 0x00 return QUEST_SUCCESS; } //Set Respawn Position QUESTREWD(021) { //dword iX pos 0x00 //dword iY pos 0x04 GETREWDDATA(021); client->Position->saved = client->Position->Map; return QUEST_SUCCESS; } //Unknown QUESTREWD(022) { //word nZonNo pos 0x00 //byte btOp pos 0x02 return QUEST_SUCCESS; } //Raise Clan Grade - This is not the least bit efficient - Drakia QUESTREWD(023) { GETREWDDATA(023); if( client->questdebug ) server->SendPM(client, "Raise clan grade"); for(UINT i=0;iMapList.Map.size();i++) { CMap* map = GServer->MapList.Map.at(i); if( map->PlayerList.size()<1 ) continue; for(UINT j=0;jPlayerList.size();j++) { CPlayer* player = map->PlayerList.at(j); if( player->Clan->clanid != client->Clan->clanid ) continue; player->Clan->grade++; //load clan info in char server BEGINPACKET( pak, 0x7e0 ); ADDBYTE ( pak, 0xfb ); //action to update clan informacion (charserver) ADDWORD ( pak, player->Clan->clanid ); ADDWORD ( pak, player->Clan->grade ); GServer->SendISCPacket( &pak ); //Send to other players RESETPACKET( pak, 0x7e0 ); ADDBYTE ( pak, 0x35 ); ADDWORD ( pak, player->clientid ); ADDWORD ( pak, player->Clan->clanid); ADDWORD ( pak, 0x0000 );//??? ADDWORD ( pak, player->Clan->back ); ADDWORD ( pak, player->Clan->logo ); ADDBYTE ( pak, player->Clan->grade );//clan grade ADDBYTE ( pak, 0x06 );//clan rank ADDSTRING ( pak, player->Clan->clanname ); ADDBYTE ( pak, 0x00 ); GServer->SendToVisible( &pak, player ); } } GServer->DB->QExecute("UPDATE list_clan SET grade=%i WHERE id=%i", client->Clan->grade, client->Clan->clanid); return QUEST_SUCCESS; } //Clan Money QUESTREWD(024) { //int iMONEY pos 0x00 //byte btOP pos 0x02 GETREWDDATA(024); return QUEST_SUCCESS; } //Clan Points QUESTREWD(025) { //short nPOINT pos 0x00 //byte btOP pos 0x02 GETREWDDATA(025); int points = data->nPOINT; //this whole function appears to be screwed up. Fix later /* //Loading "real" CP points. //getClanPoints function is mysteriously missing so skip it for now //client->Clan->CP = GServer->getClanPoints(client->Clan->clanid); //we "delete" points. if(data->btOP == 7) { points =- 1 * points; } if (client->Clan->CP + points < 0) { client->Clan->CP = 0; } else { client->Clan->CP += points; } //sending packet. BEGINPACKET( pak, 0x7e0 ); ADDBYTE ( pak, 0xfe ); ADDDWORD ( pak, client->CharInfo->charid); //charid ADDDWORD ( pak, points); //Clan points (to be added) cryptPacket( (char*)&pak, GServer->cct ); send( GServer->csock, (char*)&pak, pak.Size, 0 ); Log(MSG_WARNING,"We added %i CP",points); RESETPACKET( pak, 0x7e0 ); ADDBYTE ( pak, 0x35 ); ADDWORD ( pak, client->clientid ); ADDWORD ( pak, client->Clan->clanid ); ADDWORD ( pak, 0x0000 ); ADDWORD ( pak, client->Clan->back ); ADDWORD ( pak, client->Clan->logo ); ADDBYTE ( pak, client->Clan->grade ); ADDBYTE ( pak, client->Clan->clanrank); ADDSTRING ( pak, client->Clan->clanname ); ADDBYTE ( pak, 0x00 ); client->client->SendPacket(&pak); */ return QUEST_SUCCESS; } //Clan Skill QUESTREWD(026) { GETREWDDATA(026); //word nSkillNo; pos 0x00 //byte btOP; pos 0x02 //do something (based on btOp) with a clan skill id = data->nSkillNo if( client->questdebug )server->SendPM(client, "Clan skill rwd[026] skill id: %i btOP: %i",data->nSkillNo,data->btOP); return QUEST_SUCCESS; } //Clan Contribution QUESTREWD(027) { GETREWDDATA(027); //short nCONT; pos 0x00 //byte btOP; pos 0x02 if( client->questdebug )server->SendPM(client, "Clan Contribution rwd[026] nCONT: %i btOP: %i",data->nCONT,data->btOP); return QUEST_SUCCESS; } //Clan Teleportation - Again, not efficient. Maybe keep a list of pointers to clan members? - Drakia QUESTREWD(028) { //dword iRange; pos 0x00 //word nZoneNo; pos 0x04 //dword iX; pos 0x06 //dword iY; pos 0x0a GETREWDDATA(028); fPoint telepos; fPoint newPos; telepos.x = data->iX/100; telepos.y = data->iY/100; if( client->questdebug ) server->SendPM(client, "Clan teleport to [%i][%f][%f]", data->nZoneNo, telepos.x, telepos.y); for(UINT i=0;iMapList.Map.size();i++) { CMap* map = GServer->MapList.Map.at(i); if( map->PlayerList.size()<1 ) continue; for(UINT j=0;jPlayerList.size();j++) { CPlayer* player = map->PlayerList.at(j); if( player->Clan->clanid != client->Clan->clanid ) continue; newPos = GServer->RandInCircle(telepos, data->iRange); GServer->TeleportTo(player, data->nZoneNo, newPos ); } } return QUEST_SUCCESS; } QUESTREWD(029) //execute client quest trigger (LUA) { GETREWDDATA(029); char* tempName = reinterpret_cast(&data->LuaName) - 2; dword hash = MakeStrHash(tempName); if( client->questdebug ) server->SendPM(client, "Execute Client LUA %s[%d] [%08x]", tempName, data->strLen, hash); //return client->ExecuteQuestTrigger(hash); //need to code a packet here. on evo it's 0x7f8. Don't even know if we use one here Log(MSG_DEBUG,"ran quest action 29"); return QUEST_SUCCESS; } QUESTREWD(030) //Reset skills { //Log(MSG_DEBUG,"ran quest action 30"); for(int i=0;i<30;i++) { //give one sp for every active skill present if(client->askill[i] != 0) { client->CharInfo->SkillPoints += 1; } client->askill[i] = 0; //give SP equal to the level of the active skill. Actual level is always 1 more than this client->CharInfo->SkillPoints += client->askilllvl[i]; client->askilllvl[i] = 0; //give one sp for every passive skill present if(client->pskill[i] != 0) { client->pskill[i] = 0; client->CharInfo->SkillPoints += 1; } //give SP equal to the level of the passive skill. Actual level is always 1 more than this client->CharInfo->SkillPoints += client->pskilllvl[i]; client->pskilllvl[i] = 0; } client->savedata(); return QUEST_SUCCESS; } QUESTREWD(050) //Respawn NPC after time delay. Used only on the missing children in Zant { return QUEST_SUCCESS; }