Esempio n. 1
0
bool Client::TrainDiscipline(uint32 itemid) {

    //get the item info
    const Item_Struct *item = database.GetItem(itemid);
    if(item == NULL) {
        Message(13, "Unable to find the tome you turned in!");
        LogFile->write(EQEMuLog::Error, "Unable to find turned in tome id %lu\n", (unsigned long)itemid);
        return(false);
    }

    if(item->ItemClass != ItemClassCommon || item->ItemType != ItemTypeSpell) {
        Message(13, "Invalid item type, you cannot learn from this item.");
        //summon them the item back...
        SummonItem(itemid);
        return(false);
    }

    //Need a way to determine the difference between a spell and a tome
    //so they cant turn in a spell and get it as a discipline
    //this is kinda a hack:
    if(!(
                item->Name[0] == 'T' &&
                item->Name[1] == 'o' &&
                item->Name[2] == 'm' &&
                item->Name[3] == 'e' &&
                item->Name[4] == ' '
            )) {
        Message(13, "This item is not a tome.");
        //summon them the item back...
        SummonItem(itemid);
        return(false);
    }

    int myclass = GetClass();
    if(myclass == WIZARD || myclass == ENCHANTER || myclass == MAGICIAN || myclass == NECROMANCER) {
        Message(13, "Your class cannot learn from this tome.");
        //summon them the item back...
        SummonItem(itemid);
        return(false);
    }

    //make sure we can train this...
    //can we use the item?
    uint32 cbit = 1 << (myclass-1);
    if(!(item->Classes & cbit)) {
        Message(13, "Your class cannot learn from this tome.");
        //summon them the item back...
        SummonItem(itemid);
        return(false);
    }

    uint32 spell_id = item->Scroll.Effect;
    if(!IsValidSpell(spell_id)) {
        Message(13, "This tome contains invalid knowledge.");
        return(false);
    }

    //can we use the spell?
    const SPDat_Spell_Struct &spell = spells[spell_id];
    uint8 level_to_use = spell.classes[myclass - 1];
    if(level_to_use == 255) {
        Message(13, "Your class cannot learn from this tome.");
        //summon them the item back...
        SummonItem(itemid);
        return(false);
    }

    if(level_to_use > GetLevel()) {
        Message(13, "You must be at least level %d to learn this discipline.", level_to_use);
        //summon them the item back...
        SummonItem(itemid);
        return(false);
    }

    //add it to PP.
    int r;
    for(r = 0; r < MAX_PP_DISCIPLINES; r++) {
        if(m_pp.disciplines.values[r] == spell_id) {
            Message(13, "You already know this discipline.");
            //summon them the item back...
            SummonItem(itemid);
            return(false);
        } else if(m_pp.disciplines.values[r] == 0) {
            m_pp.disciplines.values[r] = spell_id;
            SendDisciplineUpdate();
            Message(0, "You have learned a new discipline!");
            return(true);
        }
    }
    Message(13, "You have learned too many disciplines and can learn no more.");
    return(false);
}
Esempio n. 2
0
void Client::CheckQuests(const char* zonename, const char * message, int32 npc_id, uint16 item_id, Mob* other)
{
	bool ps = false;
	bool tt = false;
	bool ti = false;
	bool tt2 = false;
	bool ti2 = false;
	bool stt = false;
	bool std = false;
	bool td = false;
	bool sta = false;
	bool ta = false;
	bool sti = false;
	bool stf = false;
	bool tf = false;
	bool tk = false;
	bool stk = false;
	bool levelcheck = false;
	int8 fac = GetFactionLevel(GetID(),other->GetNPCTypeID(), GetRace(), GetClass(), DEITY_AGNOSTIC, other->CastToNPC()->GetPrimaryFaction(), other);
	FILE * pFile;
  long lSize;
  char * buffer;
  char filename[255];
  #ifdef WIN32
  snprintf(filename, 254, "quests\\%i.qst", npc_id);
  #else
  snprintf(filename, 254, "quests/%i.qst", npc_id);
  #endif
  adverrorinfo = 940;
  if ((pFile=fopen(filename,"rb")))
  {
		#ifdef DEBUG
		printf("Reading quests from %s\n", filename);
		#endif
  }
  else {
		#ifdef DEBUG
		printf("Error: No quests file found for %s\n", filename);
		#endif
		return;
  }
  if (pFile==NULL) exit (1);

  // obtain file size.
  fseek (pFile , 0 , SEEK_END);
  lSize = ftell (pFile);
  rewind (pFile);

  adverrorinfo = 941;
  // allocate memory to contain the whole file.
  buffer = (char*) malloc (lSize);
  if (buffer == NULL) exit (2);

  // copy the file into the buffer.
  fread (buffer,1,lSize,pFile);
  fclose(pFile);
  Seperator3 sep3(buffer);
  for(int i=0; i < 2048; ++i)
  {
//  printf("Temp: %s\n", sep3.arghz[i]);
	char * command;
	char * temp;
	temp = sep3.arghz[i];
	if (temp == NULL) return;
	Seperator sep(temp);
	Seperator4 sep4(temp);
	command = sep4.arghza[0];
	command = strupr(command);
#ifdef DEBUG
	cout<<sep.argplus[0]<<endl;
#endif
	if (!IsCommented(temp))
	{
	if (strstr(command,"END_FILE") != NULL || command == NULL)
	{
		break;
	}
	if (ti2 || tt2 || tf || td || ta) {
		char lvl[5];
		sprintf(lvl, "%i", this->GetLevel());
		strcpy(sep4.arghza[1], strreplace(sep4.arghza[1],"%CHARRACE%", GetRaceName(this->GetRace())));
		strcpy(sep4.arghza[1], strreplace(sep4.arghza[1],"%CHARLEVEL%", lvl));
		strcpy(sep4.arghza[1], strreplace(sep4.arghza[1],"%CHARCLASS%", GetEQClassName(this->GetClass(), 50)));
		char * nmessage = strreplace(sep4.arghza[1],"%CHARNAME%", this->GetName());
		nmessage[strlen(nmessage) - 1] = '\0';
		if (ti2 || tt2 || ta)
		{
			other->CastToNPC()->FaceTarget(this, true);
		}
		if ((fac == 7 || fac == 6) && (ti2 || tt2))
		{
			entity_list.NPCMessage(other,true,200,0,"%s says, 'I will have nothing to do with such as you. Begone.'",other->GetName());
			break;
		}
		else if (strstr(command,"FACTION_CHECK") != NULL) {
			int8 fac2 = atoi(sep.arg[1]);
			if ((fac2 <= 5 && fac > fac2) || (fac2 == 6 && fac == 8))
			{
				entity_list.NPCMessage(other,true,200,0,"%s says, 'I will have nothing to do with such as you. Begone.'",other->GetName());
				break;
			}
			ps = true;
		}
		else if (strstr(command,"SAY") != NULL) {
			entity_list.NPCMessage(this, false, 400, 0, "%s says, '%s'", other->GetName(), nmessage);
			ps = true;
		}
		else if (strstr(command,"EMOTE") != NULL) {
			cout<<"Emoting!"<<endl;
			entity_list.NPCMessage(this, false, 400, 0, "%s %s", other->GetName(), nmessage);
			ps = true;
		}
		else if (strstr(command,"TEXT") != NULL) {
			entity_list.NPCMessage(this, false, 400, 0, "%s", nmessage);
			ps = true;
		}
		else if (strstr(command,"SHOUT") != NULL) {
			entity_list.NPCMessage(this, false, 0, 13, "%s shouts, '%s'", other->GetName(), nmessage);
			ps = true;
		}
		else if (strstr(command,"SPAWN_ITEM") != NULL) {
			this->SummonItem(atoi(sep.arg[1]));
			ps = true;
		}
		else if (strstr(command,"ADD_HATELIST") != NULL) {
			other->CastToNPC()->AddToHateList(this, 100);
			ps = true;
		}
		else if (strstr(command,"DEPOP") != NULL) {
			other->CastToNPC()->Depop();
			ps = true;
		}
#ifdef GUILDWARS
		else if (strstr(command,"CITYTAKE") != NULL) {
			if(IsClient() && GuildDBID() != 0)
			{
				if(target->CastToNPC()->GetGuildOwner() == GuildDBID())
				{
			entity_list.NPCMessage(this, false, 400, 0, "%s says, 'You are a member of the guild that owns this city, why would you want to conquere it?'", other->GetName(), nmessage);				
				}
				else if(!IsAttackAllowed(other))
				{
			entity_list.NPCMessage(this, false, 400, 0, "%s says, 'You cannot conquere an allied city.'", other->GetName(), nmessage);				
				}
				else if(database.CityDefense(zone->GetZoneID(),0))
				{
			entity_list.NPCMessage(this, false, 400, 0, "%s says, 'This city still has men standing, I will not surrender!'", other->GetName(), nmessage);				
				}
				else if(database.SetCityGuildOwned(GuildDBID(),other->GetNPCTypeID()))
				{
			entity_list.NPCMessage(this, false, 400, 0, "%s says, 'You have won, I surrender to you.'", other->GetName(), nmessage);	
			zone->SetGuildOwned(GuildDBID());
			zone->Repop();			
				}
			}
			ps = true;
		}
#endif
		else if (strstr(command,"SPAWN_NPC") != NULL) {
				adverrorinfo = 751;
				const NPCType* tmp = 0;
				adverrorinfo = 752;
				int16 grid = atoi(sep.arg[2]);
				int8 guildwarset = atoi(sep.arg[3]);
				if ((tmp = database.GetNPCType(atoi(sep.arg[1]))))
				{
					adverrorinfo = 753;
					NPC* npc = new NPC(tmp, 0, other->GetX(), other->GetY(), other->GetZ(), heading);
					adverrorinfo = 754;
					npc->AddLootTable();
					adverrorinfo = 755;
					entity_list.AddNPC(npc,true,true);
					adverrorinfo = 756;
					Sleep(200);
					if(npc != 0)
					{
					if(grid > 0)
						npc->AssignWaypoints(grid);
					adverrorinfo = 757;
#ifdef GUILDWARS
					if(guildwarset > 0 && guildwarset == 1 && GuildDBID() > 0)
						npc->SetGuildOwner(GuildDBID());
#endif
					adverrorinfo = 758;
					npc->SendPosUpdate();
					}
			}
			ps = true;
		}
		else if (strstr(command,"LEVEL_CHECK") != NULL) 
      { 
         int8 Level1 = atoi(sep.arg[1]); 
         int8 Level2 = atoi(sep.arg[2]); 
         int8 Levelp = this->GetLevel(); 
          
         if(Level2 == 0 || Level2 == NULL){ 
            //Min Level 
            if(Level1 > Levelp) 
            { 
               //not high enough to talk too 
               break; 
            } 
         } 
         else{ 
            //Level Range 
            if(Level1 < Levelp && Level2 < Levelp) 
            { 
               //not in the req level range 
               break; 
            } 
         } 
         levelcheck = true; 
      }
		else if (strstr(command,"CUMULATIVE_FLAG") != NULL) {
			other->flag[50] = other->flag[50] + 1;
			ps = true;
		}
		else if (strstr(command,"NPC_FLAG") != NULL) {
			other->flag[atoi(sep.arg[1])] = atoi(sep.arg[2]);
			ps = true;
		}
		else if (strstr(command,"PLAYER_FLAG") != NULL) {
			this->flag[atoi(sep.arg[1])] = atoi(sep.arg[2]);
			ps = true;
		}
		else if (strstr(command,"EXP") != NULL) {
			this->AddEXP (atoi(sep.arg[1]));
			ps = true;
		}
		else if (strstr(command,"LEVEL") != NULL) {
			this->SetLevel(atoi(sep.arg[1]), true);
			ps = true;
		}
		else if (strstr(command,"SAFEMOVE") != NULL) {
			this->MovePC(zone->GetShortName(),database.GetSafePoint(zone->GetShortName(),"x"),database.GetSafePoint(zone->GetShortName(),"y"),database.GetSafePoint(zone->GetShortName(),"z"),false,false);
			ps = true;
		}
		else if (strstr(command,"RAIN") != NULL) {
			zone->zone_weather = atoi(sep.arg[1]);
			APPLAYER* outapp = new APPLAYER;
			outapp = new APPLAYER;
			outapp->opcode = OP_Weather;
			outapp->pBuffer = new uchar[8];
			memset(outapp->pBuffer, 0, 8);
			outapp->size = 8;
			outapp->pBuffer[4] = atoi(sep.arg[1]); // Why not just use 0x01/2/3?
			entity_list.QueueClients(this, outapp);
			delete outapp;
			ps = true;
		}
		else if (strstr(command,"SNOW") != NULL) {
			zone->zone_weather = atoi(sep.arg[1]) + 1;
			APPLAYER* outapp = new APPLAYER;
			outapp = new APPLAYER;
			outapp->opcode = OP_Weather;
			outapp->pBuffer = new uchar[8];
			memset(outapp->pBuffer, 0, 8);
			outapp->size = 8;
			outapp->pBuffer[0] = 0x01;
			outapp->pBuffer[4] = atoi(sep.arg[1]);
			entity_list.QueueClients(this, outapp);
			delete outapp;
			ps = true;
		}
		else if (strstr(command,"GIVE_CASH") != NULL) {
			this->AddMoneyToPP(atoi(sep.arg[1]),true);
			ps = true;
		} 
		else if (strstr(command,"GIVE_ITEM") != NULL) { 
			int16 ItemID = atoi(sep.arg[1]); 
			sint8 ItemCharges = atoi(sep.arg[2]); 
			this->SummonItem(ItemID, ItemCharges); 
			ps = true; 
		} 
		else if (strstr(command,"CAST_SPELL") != NULL) {
			other->CastSpell(atoi(sep.arg[1]),this->GetID());
			ps = true;
		}
		else if (strstr(command,"PVP") != NULL) {
			if (strstr(strupr(sep.arg[1]),"ON") != NULL)
				this->CastToClient()->SetPVP(true);
			else
				this->CastToClient()->SetPVP(false);
			ps = true;
		}
		/*else if (strstr(command,"CHANGEFACTION") != NULL) {
			if ((sep.IsNumber(1)) && (sep.IsNumber(2))) {
				this->CastToClient()->SetFactionLevel2(this->CastToClient()->CharacterID(),atoi(sep.arg[1]), this->CastToClient()->GetClass(), this->CastToClient()->GetRace(), this->CastToClient()->GetDeity(), atoi(sep.arg[2]));
				this->CastToClient()->Message(0,BuildFactionMessage(GetCharacterFactionLevel(atoi(sep.arg[1])),atoi(sep.arg[1])));
			}
			else
			{
				cout << "Error in script!!!!!  Bad CHANGEFACTION Line! " << endl;
			}
			ps = true;
		}*/
		else if (strstr(command,"DO_ANIMATION") != NULL) {
			other->DoAnim(atoi(sep.arg[1]));
			ps = true;
		}
		else if (strstr(command,"ADDSKILL") != NULL) {
			if (sep.IsNumber(1) && sep.IsNumber(2) && (atoi(sep.arg[2]) >= 0 || atoi(sep.arg[2]) <= 252) && (atoi(sep.arg[1]) >= 0 && atoi(sep.arg[1]) < 74)) {
				this->AddSkill(atoi(sep.arg[1]), atoi(sep.arg[2]));
			}
			else
				cout << "Error in script!!!! Bad ADDSKILL line!" << endl;
			ps = true;
		}
		else if (strstr(command,"FLAG_CHECK") != NULL)
		{
			if (this->flag[atoi(sep.arg[1])] == 0)
				break;
			else
				this->flag[atoi(sep.arg[1])] = 0;
			ps = true;
		}
		else if (strstr(command,"CHANCE") != NULL)
		{
			if (rand()%100 > atoi(sep.arg[1]))
				break;
			ps = true;
		}
	}
	if (IsEnd(temp)) 
	{
		tt = false; tt2 = false; stt = false; ti = false; ti2 = false; sti = false; tk = false;	td = false; std = false; ta = false; sta = false; tf = false; stf = false; stk = false; 
	}
		if (strstr(command,"TRIGGER_ATTACK") != NULL)
		{
			if (strstr(message,"%%ATTACK%%") != NULL) {
				adverrorinfo = 943;
				ta = true;
			}
			else { sta = true; }
		}
		else if (strstr(command,"TRIGGER_DEATH") != NULL)
		{
			if (strstr(message,"%%DEATH%%") != NULL)
			{
				td = true;
			}
			else { std = true; }
		}
		else if (strstr(command,"TRIGGER_KILLED") != NULL)
		{
			if (strstr(message,"%%KILLED%%") != NULL)
			{
				tk = true;
			}
			else { stk = true; }
		}
		else if (strstr(command,"TRIGGER_FLAGS") != NULL)
		{
			int8 flag1 = atoi(sep.arg[1]);
			int8 flag2 = atoi(sep.arg[2]);
			int8 flag3 = atoi(sep.arg[3]);
			int8 flag4 = atoi(sep.arg[4]);
			if (flag1 == 50)
			{
				if (other->flag[50] >= atoi(sep.arg[2]))
				{
					tf = true;
					other->flag[50] = 0;
				}
				else
					stf = true;
			}
			else
			{
				if (ta || tt || ti)
					stf = true;
				else if (flag1 > 0 && other->flag[flag1] == 0)
					stf = true;
				else if (flag2 > 0 && other->flag[flag2] == 0)
					stf = true;
				else if (flag3 > 0 && other->flag[flag3] == 0)
					stf = true;
				else if (flag4 > 0 && other->flag[flag4] == 0)
					stf = true;
				else
				{
					tf = true;
					if (flag1 > 0)
						other->flag[flag1] = 0;
					if (flag2 > 0)
						other->flag[flag2] = 0;
					if (flag3 > 0)
						other->flag[flag3] = 0;
				if (flag4 > 0)
							other->flag[flag4] = 0;
				}
			}
		}
		else if (strstr(command,"TRIGGER_ITEM") != NULL) {
			if (!ta && !tt && !ti)
			{
				if ((uint16)item_id == atoi(sep4.arghza[1]))
				{
					ti = true; ti2 = true;
				}
				else { sti = true; }
			}
			else
			{
				printf("TRIGGER_ITEM Error at line %d: missing left curly bracket\n", i);
				return;
			}
		}
		else if (strstr(command,"TRIGGER_TEXT") != NULL)
		{
			if (strstr(message,"%%DEATH%%") == NULL && strstr(message,"%%ITEM%%") == NULL && strstr(message,"%%ATTACK%%") == NULL && strstr(message,"%%KILLED%%") == NULL && Dist(other) <= 50) {
				char* tmp = new char[strlen(message)+1];
				strcpy(tmp, message);
				strupr(tmp);
				if (strstr(tmp,strupr(sep4.arghza[1])) != NULL)
				{
					tt2 = true; tt = true;
				}
				else
				{
					stt = true;
				}
				delete tmp;
			}
			else if (strstr(message,"%%DEATH%%") != NULL || strstr(message,"%%item%%") != NULL || strstr(message,"%%attack%%")) { stt = true; }
			else if (!ps) { printf("TRIGGER_TEXT Error at line %d: Not in NPC_Script\n", i); return; }
			else
			{
				printf("TRIGGER_TEXT Error at line %d: missing left curly bracket\n", i);
				return;
			}
		}
	/*#ifdef WIN32
		delete command;
		delete temp;
	#endif*/
}
}
	if (!ps && item_id != 0)
	{
		entity_list.NPCMessage(this,true,200,0,"%s has no use for this item.",other->GetName());
		SummonItem(item_id);
	}
	delete buffer;
}
Esempio n. 3
0
//returns true on success
bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) {
 	if(spec == NULL)
		return(false);
	
	uint16 user_skill = GetSkill(spec->tradeskill);
	float chance = 0.0;
	float skillup_modifier = 0.0;
	int16 thirdstat = 0;
	int16 stat_modifier = 15;
	uint16 success_modifier = 0;

	// Rework based on the info on eqtraders.com
	// http://mboards.eqtraders.com/eq/showthread.php?t=22246
	// 09/10/2006 v0.1 (eq4me)
	// 09/11/2006 v0.2 (eq4me)
	// Todo:
	//     Implementing AAs
	//     Success modifiers based on recipes
	//     Skillup modifiers based on the rarity of the ingredients

	// Some tradeskills are more eqal then others. ;-)
	// If you want to customize the stage1 success rate do it here.
    // Remember: skillup_modifier is (float). Lower is better
	switch(spec->tradeskill) {
	case FLETCHING:
	case ALCHEMY:
	case JEWELRY_MAKING:
	case POTTERY:
		skillup_modifier = 4;
		break;
	case BAKING:
	case BREWING:
		skillup_modifier = 3;
		break;
	case RESEARCH:
		skillup_modifier = 1;
		break;
	default:
		skillup_modifier = 2;
		break;
	}

	// Some tradeskills take the higher of one additional stat beside INT and WIS
	// to determine the skillup rate. Additionally these tradeskills do not have an
	// -15 modifier on their statbonus.
	if (spec->tradeskill ==  FLETCHING || spec->tradeskill == MAKE_POISON) {
		thirdstat = GetDEX();
		stat_modifier = 0;
	} else if (spec->tradeskill == BLACKSMITHING) {
		thirdstat = GetSTR();
		stat_modifier = 0;
	}
	
	int16 higher_from_int_wis = (GetINT() > GetWIS()) ? GetINT() : GetWIS();
	int16 bonusstat = (higher_from_int_wis > thirdstat) ? higher_from_int_wis : thirdstat;
	
	vector< pair<uint32,uint8> >::iterator itr;


    //calculate the base success chance
	// For trivials over 68 the chance is (skill - 0.75*trivial) +51.5
    // For trivial up to 68 the chance is (skill - trivial) + 66
	if (spec->trivial >= 68) {
		chance = (user_skill - (0.75*spec->trivial)) + 51.5;
	} else {
		chance = (user_skill - spec->trivial) + 66;
	}
	
	int16 over_trivial = (int16)GetRawSkill(spec->tradeskill) - (int16)spec->trivial;

	//handle caps
	if(spec->nofail) {
		chance = 100;	//cannot fail.
		_log(TRADESKILLS__TRACE, "...This combine cannot fail.");
	} else if(over_trivial >= 0) {
		// At reaching trivial the chance goes to 95% going up an additional
		// percent for every 40 skillpoints above the trivial.
		// The success rate is not modified through stats.
		// Mastery AAs are unaccounted for so far.
		// chance_AA = chance + ((100 - chance) * mastery_modifier)
		// But the 95% limit with an additional 1% for every 40 skill points
		// above critical still stands.
		// Mastery modifier is: 10%/25%/50% for rank one/two/three
		chance = 95.0f + (float(user_skill - spec->trivial) / 40.0f);
		Message_StringID(MT_Emote, TRADESKILL_TRIVIAL);
	} else if(chance < 5) {
		// Minimum chance is always 5
		chance = 5;
	} else if(chance > 95) {
		//cap is 95, shouldent reach this before trivial, but just in case.
		chance = 95;
	}
	
	_log(TRADESKILLS__TRACE, "...Current skill: %d , Trivial: %d , Success chance: %f percent", user_skill , spec->trivial , chance);
	_log(TRADESKILLS__TRACE, "...Bonusstat: %d , INT: %d , WIS: %d , DEX: %d , STR: %d", bonusstat , GetINT() , GetWIS() , GetDEX() , GetSTR());
	
	float res = MakeRandomFloat(0, 99);
	int AAChance = 0;

	//AA modifiers
	//can we do this with nested switches?
	if(spec->tradeskill == ALCHEMY){
		switch(GetAA(aaAlchemyMastery)){
		case 1:
			AAChance = 10;
			break;
		case 2:
			AAChance = 25;
			break;
		case 3:
			AAChance = 50;
			break;
		}
	}

	if(spec->tradeskill == JEWELRY_MAKING){
		switch(GetAA(aaJewelCraftMastery)){
		case 1:
			AAChance = 10;
			break;
		case 2:
			AAChance = 25;
			break;
		case 3:
			AAChance = 50;
			break;
		}
	}
      const Item_Struct* item = NULL;

	if (spec->tradeskill == BLACKSMITHING) {
		switch(GetAA(aaBlacksmithingMastery)) {
		case 1:
			AAChance = 10;
			break;
		case 2:
			AAChance = 25;
			break;
		case 3:
			AAChance = 50;
			break;
		}
	}

	if (spec->tradeskill == BAKING) {
		switch(GetAA(aaBakingMastery)) {
		case 1:
			AAChance = 10;
			break;
		case 2:
			AAChance = 25;
			break;
		case 3:
			AAChance = 50;
			break;
		}
	}

	if (spec->tradeskill == BREWING) {
		switch(GetAA(aaBrewingMastery)) {
		case 1:
			AAChance = 10;
			break;
		case 2:
			AAChance = 25;
			break;
		case 3:
			AAChance = 50;
			break;
		}
	}

	if (spec->tradeskill == FLETCHING) {
		switch(GetAA(aaFletchingMastery2)) {
		case 1:
			AAChance = 10;
			break;
		case 2:
			AAChance = 25;
			break;
		case 3:
			AAChance = 50;
			break;
		}
	}

	if (spec->tradeskill == POTTERY) {
		switch(GetAA(aaPotteryMastery)) {
		case 1:
			AAChance = 10;
			break;
		case 2:
			AAChance = 25;
			break;
		case 3:
			AAChance = 50;
			break;
		}
	}

	if (spec->tradeskill == TAILORING) {
		switch(GetAA(aaTailoringMastery)) {
		case 1:
			AAChance = 10;
			break;
		case 2:
			AAChance = 25;
			break;
		case 3:
			AAChance = 50;
			break;
		}
	}
	
	if (spec->tradeskill == RESEARCH) {
		switch(GetAA(aaArcaneTongues)) {
		case 1:
			AAChance = 10;
			break;
		case 2:
			AAChance = 25;
			break;
		case 3:
			AAChance = 50;
			break;
		}
	}

	if (((spec->tradeskill==75) || GetGM() || (chance > res)) || MakeRandomInt(0, 99) < AAChance){
		success_modifier = 1;
		
		if(over_trivial < 0)
			CheckIncreaseTradeskill(bonusstat, stat_modifier, skillup_modifier, success_modifier, spec->tradeskill);
		
		Message_StringID(4,TRADESKILL_SUCCEED,spec->name.c_str());

		_log(TRADESKILLS__TRACE, "Tradeskill success");

		itr = spec->onsuccess.begin();
		while(itr != spec->onsuccess.end() && !spec->quest) {
			//should we check this crap?
			SummonItem(itr->first, itr->second);
                  item = database.GetItem(itr->first);
			if (this->GetGroup())
			{
				entity_list.MessageGroup(this,true,MT_Skills,"%s has successfully fashioned %s!",GetName(),item->Name);
			}
			if(RuleB(TaskSystem, EnableTaskSystem))
				UpdateTasksForItem(ActivityTradeSkill, itr->first, itr->second);
			itr++;
		}
		return(true);
	} else {
		success_modifier = 2; // Halves the chance
		
		if(over_trivial < 0)
			CheckIncreaseTradeskill(bonusstat, stat_modifier, skillup_modifier, success_modifier, spec->tradeskill);
		
		Message_StringID(MT_Emote,TRADESKILL_FAILED);

		_log(TRADESKILLS__TRACE, "Tradeskill failed");
            if (this->GetGroup())
		{
			entity_list.MessageGroup(this,true,MT_Skills,"%s was unsuccessful in %s tradeskill attempt.",GetName(),this->GetGender() == 0 ? "his" : this->GetGender() == 1 ? "her" : "its");
		}
		
		itr = spec->onfail.begin();
		while(itr != spec->onfail.end()) {
			//should we check these arguments?
			SummonItem(itr->first, itr->second);
			itr++;
		}

        // Rolls on each item, is possible to return everything
        int SalvageChance = aabonuses.SalvageChance + itembonuses.SalvageChance + spellbonuses.SalvageChance;
        // Skip check if not a normal TS or if a quest recipe these should be nofail, but check amyways
        if(SalvageChance && spec->tradeskill != 75 && !spec->quest) {
            itr = spec->salvage.begin();
            uint8 sc = 0;
            while(itr != spec->salvage.end()) {
                for(sc = 0; sc < itr->second; sc++)
                    if(MakeRandomInt(0,99) < SalvageChance)
                        SummonItem(itr->first, 1);
                itr++;
            }
        }

	}
	return(false);
}
Esempio n. 4
0
//returns true on success
bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) {
	if(spec == nullptr)
		return(false);

	uint16 user_skill = GetSkill(spec->tradeskill);
	float chance = 0.0;
	float skillup_modifier = 0.0;
	int16 thirdstat = 0;
	int16 stat_modifier = 15;
	uint16 success_modifier = 0;

	// Rework based on the info on eqtraders.com
	// http://mboards.eqtraders.com/eq/showthread.php?t=22246
	// 09/10/2006 v0.1 (eq4me)
	// 09/11/2006 v0.2 (eq4me)
	// Todo:
	// Implementing AAs
	// Success modifiers based on recipes
	// Skillup modifiers based on the rarity of the ingredients

	// Some tradeskills are more eqal then others. ;-)
	// If you want to customize the stage1 success rate do it here.
	// Remember: skillup_modifier is (float). Lower is better
        switch(spec->tradeskill) {
        case SkillFletching:
                skillup_modifier = RuleI(Character, TradeskillUpFletching);
                break;
        case SkillAlchemy:
                skillup_modifier = RuleI(Character, TradeskillUpAlchemy);
                break;
        case SkillJewelryMaking:
                skillup_modifier = RuleI(Character, TradeskillUpJewelcrafting);
                break;
        case SkillPottery:
                skillup_modifier = RuleI(Character, TradeskillUpPottery);
                break;
        case SkillBaking:
                skillup_modifier = RuleI(Character, TradeskillUpBaking);
                break;
        case SkillBrewing:
                skillup_modifier = RuleI(Character, TradeskillUpBrewing);
                break;
        case SkillBlacksmithing:
                skillup_modifier = RuleI(Character, TradeskillUpBlacksmithing);
                break;
        case SkillResearch:
                skillup_modifier = RuleI(Character, TradeskillUpResearch);
                break;
        case SkillMakePoison:
                skillup_modifier = RuleI(Character, TradeskillUpMakePoison);
                break;
        case SkillTinkering:
                skillup_modifier = RuleI(Character, TradeskillUpTinkering);
                break;
        default:
                skillup_modifier = 2;
                break;
        }

	// Some tradeskills take the higher of one additional stat beside INT and WIS
	// to determine the skillup rate. Additionally these tradeskills do not have an
	// -15 modifier on their statbonus.
	if (spec->tradeskill == SkillFletching || spec->tradeskill == SkillMakePoison) {
		thirdstat = GetDEX();
		stat_modifier = 0;
	} else if (spec->tradeskill == SkillBlacksmithing) {
		thirdstat = GetSTR();
		stat_modifier = 0;
	}

	int16 higher_from_int_wis = (GetINT() > GetWIS()) ? GetINT() : GetWIS();
	int16 bonusstat = (higher_from_int_wis > thirdstat) ? higher_from_int_wis : thirdstat;

	std::vector< std::pair<uint32,uint8> >::iterator itr;


	//calculate the base success chance
	// For trivials over 68 the chance is (skill - 0.75*trivial) +51.5
	// For trivial up to 68 the chance is (skill - trivial) + 66
	if (spec->trivial >= 68) {
		chance = (user_skill - (0.75*spec->trivial)) + 51.5;
	} else {
		chance = (user_skill - spec->trivial) + 66;
	}

	int16 over_trivial = (int16)GetRawSkill(spec->tradeskill) - (int16)spec->trivial;

	//handle caps
	if(spec->nofail) {
		chance = 100;	//cannot fail.
		Log.Out(Logs::Detail, Logs::Tradeskills, "...This combine cannot fail.");
	} else if(over_trivial >= 0) {
		// At reaching trivial the chance goes to 95% going up an additional
		// percent for every 40 skillpoints above the trivial.
		// The success rate is not modified through stats.
		// Mastery AAs are unaccounted for so far.
		// chance_AA = chance + ((100 - chance) * mastery_modifier)
		// But the 95% limit with an additional 1% for every 40 skill points
		// above critical still stands.
		// Mastery modifier is: 10%/25%/50% for rank one/two/three
		chance = 95.0f + (float(user_skill - spec->trivial) / 40.0f);
		Message_StringID(MT_Emote, TRADESKILL_TRIVIAL);
	} else if(chance < 5) {
		// Minimum chance is always 5
		chance = 5;
	} else if(chance > 95) {
		//cap is 95, shouldent reach this before trivial, but just in case.
		chance = 95;
	}

	Log.Out(Logs::Detail, Logs::Tradeskills, "...Current skill: %d , Trivial: %d , Success chance: %f percent", user_skill , spec->trivial , chance);
	Log.Out(Logs::Detail, Logs::Tradeskills, "...Bonusstat: %d , INT: %d , WIS: %d , DEX: %d , STR: %d", bonusstat , GetINT() , GetWIS() , GetDEX() , GetSTR());

	float res = zone->random.Real(0, 99);
	int aa_chance = 0;

	aa_chance = spellbonuses.ReduceTradeskillFail[spec->tradeskill] + itembonuses.ReduceTradeskillFail[spec->tradeskill] + aabonuses.ReduceTradeskillFail[spec->tradeskill];

	const Item_Struct* item = nullptr;
	
	chance = mod_tradeskill_chance(chance, spec);

	if (((spec->tradeskill==75) || GetGM() || (chance > res)) || zone->random.Roll(aa_chance)) {
		success_modifier = 1;

		if(over_trivial < 0)
			CheckIncreaseTradeskill(bonusstat, stat_modifier, skillup_modifier, success_modifier, spec->tradeskill);

		Message_StringID(4, TRADESKILL_SUCCEED, spec->name.c_str());

		Log.Out(Logs::Detail, Logs::Tradeskills, "Tradeskill success");

		itr = spec->onsuccess.begin();
		while(itr != spec->onsuccess.end() && !spec->quest) {
			//should we check this crap?
			SummonItem(itr->first, itr->second);
			item = database.GetItem(itr->first);
			if (this->GetGroup()) {
				entity_list.MessageGroup(this, true, MT_Skills, "%s has successfully fashioned %s!", GetName(), item->Name);
			}

			/* QS: Player_Log_Trade_Skill_Events */
			if (RuleB(QueryServ, PlayerLogTradeSkillEvents)){
				std::string event_desc = StringFormat("Success :: fashioned recipe_id:%i tskillid:%i trivial:%i chance:%4.2f  in zoneid:%i instid:%i", spec->recipe_id, spec->tradeskill, spec->trivial, chance, this->GetZoneID(), this->GetInstanceID());
				QServ->PlayerLogEvent(Player_Log_Trade_Skill_Events, this->CharacterID(), event_desc);
			}

			if(RuleB(TaskSystem, EnableTaskSystem))
				UpdateTasksForItem(ActivityTradeSkill, itr->first, itr->second);
			++itr;
		}
		return(true);
	}
	/* Tradeskill Fail */
	else {
		success_modifier = 2; // Halves the chance

		if(over_trivial < 0)
			CheckIncreaseTradeskill(bonusstat, stat_modifier, skillup_modifier, success_modifier, spec->tradeskill);

		Message_StringID(MT_Emote,TRADESKILL_FAILED);

		Log.Out(Logs::Detail, Logs::Tradeskills, "Tradeskill failed");
			if (this->GetGroup())
		{
			entity_list.MessageGroup(this,true,MT_Skills,"%s was unsuccessful in %s tradeskill attempt.",GetName(),this->GetGender() == 0 ? "his" : this->GetGender() == 1 ? "her" : "its");

		}

		/* QS: Player_Log_Trade_Skill_Events */
		if (RuleB(QueryServ, PlayerLogTradeSkillEvents)){
			std::string event_desc = StringFormat("Failed :: recipe_id:%i tskillid:%i trivial:%i chance:%4.2f  in zoneid:%i instid:%i", spec->recipe_id, spec->tradeskill, spec->trivial, chance, this->GetZoneID(), this->GetInstanceID());
			QServ->PlayerLogEvent(Player_Log_Trade_Skill_Events, this->CharacterID(), event_desc);
		}

		itr = spec->onfail.begin();
		while(itr != spec->onfail.end()) {
			//should we check these arguments?
			SummonItem(itr->first, itr->second);
			++itr;
		}

		/* Salvage Item rolls */

		// Rolls on each item, is possible to return everything
		int SalvageChance = aabonuses.SalvageChance + itembonuses.SalvageChance + spellbonuses.SalvageChance;
		// Skip check if not a normal TS or if a quest recipe these should be nofail, but check amyways
		if(SalvageChance && spec->tradeskill != 75 && !spec->quest) {
			itr = spec->salvage.begin();
			uint8 sc = 0;
			while(itr != spec->salvage.end()) {
				for(sc = 0; sc < itr->second; sc++)
					if(zone->random.Roll(SalvageChance))
						SummonItem(itr->first, 1);
				++itr;
			}
		}

	}
	return(false);
}