void Object::RandomSpawn(bool send_packet) { if(!m_ground_spawn) return; m_data.x = MakeRandomFloat(m_min_x, m_max_x); m_data.y = MakeRandomFloat(m_min_y, m_max_y); respawn_timer.Disable(); if(send_packet) { EQApplicationPacket app; CreateSpawnPacket(&app); entity_list.QueueClients(nullptr, &app, true); } }
void Client::CheckIncreaseTradeskill(int16 bonusstat, int16 stat_modifier, float skillup_modifier, uint16 success_modifier, SkillType tradeskill) { uint16 current_raw_skill = GetRawSkill(tradeskill); if(!CanIncreaseTradeskill(tradeskill)) return; //not allowed to go higher. float chance_stage2 = 0; //A successfull combine doubles the stage1 chance for an skillup //Some tradeskill are harder than others. See above for more. float chance_stage1 = (bonusstat - stat_modifier) / (skillup_modifier * success_modifier); //In stage2 the only thing that matters is your current unmodified skill. //If you want to customize here you probbably need to implement your own //formula instead of tweaking the below one. if (chance_stage1 > MakeRandomFloat(0, 99)) { if (current_raw_skill < 15) { //Always succeed chance_stage2 = 100; } else if (current_raw_skill < 175) { //From skill 16 to 174 your chance of success falls linearly from 92% to 13%. chance_stage2 = (200 - current_raw_skill) / 2; } else { //At skill 175, your chance of success falls linearly from 12.5% to 2.5% at skill 300. chance_stage2 = 12.5 - (.08 * (current_raw_skill - 175)); } } if (chance_stage2 > MakeRandomFloat(0, 99)) { //Only if stage1 and stage2 succeeded you get a skillup. SetSkill(tradeskill, current_raw_skill + 1); if(title_manager.IsNewTradeSkillTitleAvailable(tradeskill, current_raw_skill + 1)) NotifyNewTitlesAvailable(); } _log(TRADESKILLS__TRACE, "...skillup_modifier: %f , success_modifier: %d , stat modifier: %d", skillup_modifier , success_modifier , stat_modifier); _log(TRADESKILLS__TRACE, "...Stage1 chance was: %f percent", chance_stage1); _log(TRADESKILLS__TRACE, "...Stage2 chance was: %f percent. 0 percent means stage1 failed", chance_stage2); }
PyResult Command_spawnbelt( Client* who, CommandDB* db, PyServiceMgr* services, const Seperator& args ) { if( !who->IsInSpace() ) throw PyException( MakeCustomError( "You must be in space to spawn things." ) ); const double beltradius = 100000.0; const double beltdistance = 25000.0; const double roidradius = MakeRandomFloat( 100.0, 1000.0 ); const double beltangle = M_PI * 2.0 / 3.0; const uint32 pcs = 20 + MakeRandomInt( -10, 10 ); // reduced from 160 + MakeRandomInt( -10, 10 ) const GPoint position( who->GetPosition() ); const double R = sqrt( position.x * position.x + position.z * position.z ); const GPoint r = position * ( R + beltdistance - beltradius ) / R; double phi = atan( position.x / position.z ); if( position.z < 0 ) phi += M_PI; SystemManager* sys = who->System(); std::map<double, uint32> roidDist; if( !db->GetRoidDist( sys->GetSystemSecurity(), roidDist ) ) { sLog.Error( "Command", "Couldn't get roid list for system security %s", sys->GetSystemSecurity() ); throw PyException( MakeCustomError( "Couldn't get roid list for system security %s", sys->GetSystemSecurity() ) ); } //double distanceToMe; double alpha; GPoint mposition; for( uint32 i = 0; i < pcs; ++i ) { alpha = beltangle * MakeRandomFloat( -0.5, 0.5 ); mposition.x = beltradius * sin( phi + alpha ) + roidradius * MakeRandomFloat( 0, 15 ); mposition.z = beltradius * cos( phi + alpha ) + roidradius * MakeRandomFloat( 0, 15 ); mposition.y = position.y - r.y + roidradius * MakeRandomFloat( 0, 15 ); //distanceToMe = (r + mposition - position).length(); SpawnAsteroid( who->System(), GetAsteroidType( MakeRandomFloat(), roidDist ), roidradius, r + mposition ); } return new PyString( "Spawn successsfull." ); }
int32 Client::GetActSpellCost(uint16 spell_id, int32 cost) { // Formula = Unknown exact, based off a random percent chance up to mana cost(after focuses) of the cast spell if(this->itembonuses.Clairvoyance && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) { int16 mana_back = this->itembonuses.Clairvoyance * MakeRandomInt(1, 100) / 100; // Doesnt generate mana, so best case is a free spell if(mana_back > cost) mana_back = cost; cost -= mana_back; } // This formula was derived from the following resource: // http://www.eqsummoners.com/eq1/specialization-library.html // WildcardX float PercentManaReduction = 0; float SpecializeSkill = GetSpecializeSkillValue(spell_id); int SuccessChance = MakeRandomInt(0, 100); float bonus = 1.0; switch(GetAA(aaSpellCastingMastery)) { case 1: bonus += 0.05; break; case 2: bonus += 0.15; break; case 3: bonus += 0.30; break; } bonus += 0.05 * GetAA(aaAdvancedSpellCastingMastery); if(SuccessChance <= (SpecializeSkill * 0.3 * bonus)) { PercentManaReduction = 1 + 0.05 * SpecializeSkill; switch(GetAA(aaSpellCastingMastery)) { case 1: PercentManaReduction += 2.5; break; case 2: PercentManaReduction += 5.0; break; case 3: PercentManaReduction += 10.0; break; } switch(GetAA(aaAdvancedSpellCastingMastery)) { case 1: PercentManaReduction += 2.5; break; case 2: PercentManaReduction += 5.0; break; case 3: PercentManaReduction += 10.0; break; } } int16 focus_redux = GetFocusEffect(focusManaCost, spell_id); if(focus_redux > 0) { PercentManaReduction += MakeRandomFloat(1, (double)focus_redux); } cost -= (cost * (PercentManaReduction / 100)); // Gift of Mana - reduces spell cost to 1 mana if(focus_redux >= 100) { uint32 buff_max = GetMaxTotalSlots(); for (int buffSlot = 0; buffSlot < buff_max; buffSlot++) { if (buffs[buffSlot].spellid == 0 || buffs[buffSlot].spellid >= SPDAT_RECORDS) continue; if(IsEffectInSpell(buffs[buffSlot].spellid, SE_ReduceManaCost)) { if(CalcFocusEffect(focusManaCost, buffs[buffSlot].spellid, spell_id) == 100) cost = 1; } } } if(cost < 0) cost = 0; return cost; }
//Random formulas for certain calculations to be added in the next few days. -Wizzel int MakeRandomInt(int low, int high) { if(low == high) return(low); return (int)MakeRandomFloat((double)low, (double)high + 0.999); }
void Client::ProcessOP_Beg(APPLAYER* pApp) { /* if(pApp->size != sizeof(Beg_Struct)) { cout << "Wrong size on OP_Beg. Got: " << pApp->size << ", Expected: " << sizeof(Beg_Struct) << endl; return; }*/ if(pApp->size = sizeof(Beg_Struct)) { Beg_Struct* beg_info = (Beg_Struct*)pApp->pBuffer; Message(BLACK,"Begging makes zone a sad panda :( (Our struct is wrong)"); beg_info->success = 0; QueuePacket(pApp); } else { //Yeahlight: Purge client's invisibility CancelAllInvisibility(); Beg_Struct* beg_info = (Beg_Struct*)pApp->pBuffer; Mob* target = entity_list.GetMob(beg_info->target); Mob* player = entity_list.GetMob(beg_info->begger); //Beg_Struct* beg_info = (Beg_Struct*)pApp->pBuffer; // Validate Player // Added this check to keep people from fudging packets to make // mobs attack other through begging. Flag as a hack also. if(this->GetID() != player->GetID()) { cout << "[ hack ]" << this->GetName() << " is begging for another player: "; cout << player->GetName() << endl; // This will make the client not able to beg anymore. // Could we send qa packet back with 'beg_info->success = 0? // Nah, I'd rather just leave the hackers with a broken client. -neorab return; } // Validate Time // Should not be able to send two beg requests within 10 seconds. // Flag beg spammers as hackers. Drop the packet and move on. int32 time_to_beg = beg_timer->GetRemainingTime(); if(time_to_beg != 0) { cout << "[ hack ]" << player->GetName() << " is begging to fast. "; cout << 10000 - time_to_beg << "ms since last beg." << endl; // This will make the client not able to beg anymore. return; } beg_timer->Start(10000); // Validate Target // Should not be able to beg from other players, corpses or pets. // Basiclly, the client will have to have the same thing targeted // as the packet says they do. If they target a pet and send a beg // packet with the pet as the target, this won't catch it. But it'll // stop the average dumbass forging packets. Mob* tmptar = this->GetTarget(); if((tmptar->GetID() != target->GetID()) || target->IsNPC() != true) { cout << "[ hack ]" << player->GetName() << " is begging from: " << target->GetName(); cout << "but has [" << tmptar->GetName() << "] targeted." << endl; // This will make the client not able to beg anymore. return; } // Validate Skill // Look the skill up, flag the account for hacks if they don't match. int8 beg_skill = this->GetSkill(BEGGING); if(beg_skill != beg_info->skill) { cout << "[ hack ]" << player->GetName() << " is trying to beg at " << beg_info->skill; cout << "but is [" << beg_skill << "] skill." << endl; // This will make the client not able to beg anymore. return; } // Pets. // You cannot succeed or crit fail on pets. if(target->CastToNPC()->GetOwner() == 0) { // Roll The Dice for Success // the threshold is the number you have to be under to have begged successfully // skill level / 8000 (0 - 4% liner based on skill) // + Charisma Modifier (same as skill level) * active charisma % (20% for ever 51 levels) double success_threshold = ((double)beg_skill / 8000) + (( (int)((double)beg_skill / 51) * 0.20) * ((double)player->GetCHA() / 8500)); double the_dice = MakeRandomFloat(0.000, 1.000); if(the_dice <= success_threshold) { char message[255]; sprintf(message, "%s says, \"Here %s, take this and LEAVE ME ALONE!\"", target->GetName(), player->GetName()); Message(WHITE, message); beg_info->success = 4; if(the_dice == success_threshold) { beg_info->coins = 2; } else { beg_info->coins = 1; } } // Critical Failure =) else { beg_info->success = 0; // Random Attack (5% @ 0skill 1% @ 200 skill) the_dice = MakeRandomFloat(0.000, 1.000); if(the_dice <= (0.05 - (int)((double)beg_skill / 50) * 0.01)) { char message[255]; sprintf(message, "%s says, \"Beggers like you always bring out the worst in me.\"", target->GetName()); target->CastToNPC()->AddToHateList(player); Message(DARK_RED, message); } } } // This is a pet, never allow them to succeed. else { beg_info->success = 0; } // Random Skill-Up // This was a bitch skill to learn. Let's do ~1/2% change to skill up. // I'm not using the CheckAddSkill function here because that does not // let us control it quite like this. I really don't believe every // skill uses the same formula. -neorab int dice = MakeRandomInt(0, 200); if(dice <= 1) { if(GetSkill(BEGGING) < CheckMaxSkill(BEGGING, this->race, this->class_, this->level)) { SetSkill(BEGGING, GetSkill(BEGGING)+1); } } // Save Player Profile // The return told the client they got more money, we should save that // server side to reflect the extra cash. if(beg_info->success != 0) { AddMoneyToPP(beg_info->coins, 0, 0, 0, false); } QueuePacket(pApp); } }
//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); }
PyResult Command_spawnbelt( Client* who, CommandDB* db, PyServiceMgr* services, const Seperator& args ) { if( !who->IsInSpace() ) throw PyException( MakeCustomError( "You must be in space to spawn things." ) ); bool makeIceBelt = false; bool makeRareIce = false; uint32 customCount = 0; if( args.argCount() >= 2 ) { if( !args.isNumber( 1 ) ) { if( args.arg( 1 ) == "ice" ) makeIceBelt = true; } else { if( atoi(args.arg( 1 ).c_str()) > 15 ) customCount = atoi(args.arg( 1 ).c_str()); else PyException( MakeCustomError( "Argument 1 should be at least 15!" ) ); } } if( args.argCount() >= 3 ) { if( args.isNumber( 2 ) ) { if( atoi(args.arg( 2 ).c_str()) > 15 ) customCount = atoi(args.arg(2).c_str()); else PyException( MakeCustomError( "Argument 2 should be at least 15!" ) ); } else if( args.arg( 2 ) == "ice" ) makeIceBelt = true; if( args.arg( 2 ) == "rareice" ) { makeIceBelt = true; makeRareIce = true; } } const double beltradius = 100000.0; const double beltdistance = 25000.0; double roidradius; const double beltangle = M_PI * 2.0 / 3.0; uint32 pcs = 0; if( customCount > 15 ) pcs = customCount + static_cast<uint32>(MakeRandomInt( -10, 10 )); else pcs = 30 + static_cast<uint32>(MakeRandomInt( -10, 10 )); const GPoint position( who->GetPosition() ); const double R = sqrt( position.x * position.x + position.z * position.z ); const GPoint r = position * ( R + beltdistance - beltradius ) / R; double phi = atan( position.x / position.z ); if( position.z < 0 ) phi += M_PI; SystemManager* sys = who->System(); std::map<double, uint32> roidDist; if( makeIceBelt ) { std::string securityStatus = sys->GetSystemSecurity(); if( !makeRareIce ) { roidDist.insert(std::pair<double,uint32>(0.60,16264)); // Blue Ice roidDist.insert(std::pair<double,uint32>(0.45,17975)); // Thick Blue Ice roidDist.insert(std::pair<double,uint32>(0.30,28627)); // Azure Ice roidDist.insert(std::pair<double,uint32>(0.20,16262)); // Clear Icicle roidDist.insert(std::pair<double,uint32>(0.10,16267)); // Dark Glitter } if( makeRareIce ) { roidDist.insert(std::pair<double,uint32>(0.90,16263)); // Glacial Mass roidDist.insert(std::pair<double,uint32>(0.80,16265)); // White Glaze roidDist.insert(std::pair<double,uint32>(0.70,16266)); // Glare Crust roidDist.insert(std::pair<double,uint32>(0.60,16268)); // Gelidus roidDist.insert(std::pair<double,uint32>(0.50,16269)); // Krystallos roidDist.insert(std::pair<double,uint32>(0.40,17976)); // Pristine White Glaze roidDist.insert(std::pair<double,uint32>(0.30,17977)); // Smooth Glacial Mass roidDist.insert(std::pair<double,uint32>(0.20,17978)); // Enriched Clear Icicle roidDist.insert(std::pair<double,uint32>(0.10,28628)); // Crystalline Icicle } } else { if( !db->GetRoidDist( sys->GetSystemSecurity(), roidDist ) ) { sLog.Error( "Command", "Couldn't get roid list for system security %s", sys->GetSystemSecurity() ); throw PyException( MakeCustomError( "Couldn't get roid list for system security %s", sys->GetSystemSecurity() ) ); } } double distanceToMe; double alpha; GPoint mposition; if( makeIceBelt ) pcs *= 2; for( uint32 i = 0; i < pcs; ++i ) { alpha = beltangle * MakeRandomFloat( -0.5, 0.5 ); if( makeIceBelt ) roidradius = MakeRandomFloat( 1000.0, 10000.0 ); else roidradius = MakeRandomFloat( 100.0, 1000.0 ); mposition.x = beltradius * sin( phi + alpha ) + roidradius * MakeRandomFloat( 0, 15 ); mposition.z = beltradius * cos( phi + alpha ) + roidradius * MakeRandomFloat( 0, 15 ); mposition.y = position.y - r.y + roidradius * MakeRandomFloat( 0, 15 ); distanceToMe = (r + mposition - position).length(); SpawnAsteroid( who->System(), GetAsteroidType( MakeRandomFloat(), roidDist ), roidradius, r + mposition ); } return new PyString( "Spawn successsfull." ); }
// Queries the loottable: adds item & coin to the npc void ZoneDatabase::AddLootTableToNPC(NPC* npc,uint32 loottable_id, ItemList* itemlist, uint32* copper, uint32* silver, uint32* gold, uint32* plat) { _ZP(Database_AddLootTableToNPC); //if (loottable_id == 178190) //DebugBreak(); const LootTable_Struct* lts = 0; *copper = 0; *silver = 0; *gold = 0; *plat = 0; lts = database.GetLootTable(loottable_id); if (!lts) return; // do coin if (lts->mincash > lts->maxcash) { std::cerr << "Error in loottable #" << loottable_id << ": mincash > maxcash" << std::endl; } else if (lts->maxcash != 0) { uint32 cash = 0; if (lts->mincash == lts->maxcash) cash = lts->mincash; else cash = MakeRandomInt(lts->mincash, lts->maxcash); if (cash != 0) { if (lts->avgcoin != 0) { //this is some crazy ass stuff... and makes very little sense... dont use it, k? uint32 mincoin = (uint32) (lts->avgcoin * 0.75 + 1); uint32 maxcoin = (uint32) (lts->avgcoin * 1.25 + 1); *copper = MakeRandomInt(mincoin, maxcoin); *silver = MakeRandomInt(mincoin, maxcoin); *gold = MakeRandomInt(mincoin, maxcoin); if(*copper > cash) { *copper = cash; } cash -= *copper; if(*silver>(cash/10)) { *silver = (cash/10); } cash -= *silver*10; if(*gold > (cash/100)) { *gold = (cash/100); } cash -= *gold*100; } if (cash < 0) { cash = 0; } *plat = cash / 1000; cash -= *plat * 1000; uint32 gold2 = cash / 100; cash -= gold2 * 100; uint32 silver2 = cash / 10; cash -= silver2 * 10; *gold += gold2; *silver += silver2; *copper += cash; } } // Do items for (uint32 i=0; i<lts->NumEntries; i++) { for (uint32 k = 1; k <= lts->Entries[i].multiplier; k++) { uint8 droplimit = lts->Entries[i].droplimit; uint8 mindrop = lts->Entries[i].mindrop; //LootTable Entry probability float ltchance = 0.0f; ltchance = lts->Entries[i].probability; float drop_chance = 0.0f; if(ltchance > 0.0 && ltchance < 100.0) { drop_chance = MakeRandomFloat(0.0, 100.0); } if (ltchance != 0.0 && (ltchance == 100.0 || drop_chance < ltchance)) { AddLootDropToNPC(npc,lts->Entries[i].lootdrop_id, itemlist, droplimit, mindrop); } } } }
// Called by AddLootTableToNPC // maxdrops = size of the array npcd void ZoneDatabase::AddLootDropToNPC(NPC* npc,uint32 lootdrop_id, ItemList* itemlist, uint8 droplimit, uint8 mindrop) { const LootDrop_Struct* lds = GetLootDrop(lootdrop_id); if (!lds) { return; } if(lds->NumEntries == 0) //nothing possible to add return; // Too long a list needs to be limited. if(lds->NumEntries > 99 && droplimit < 1) droplimit = lds->NumEntries/100; uint8 limit = 0; // Start at a random point in itemlist. uint32 item = MakeRandomInt(0, lds->NumEntries-1); // Main loop. for (uint32 i=0; i<lds->NumEntries;) { //Force the itemlist back to beginning. if (item > (lds->NumEntries-1)) item = 0; uint8 charges = lds->Entries[item].multiplier; uint8 pickedcharges = 0; // Loop to check multipliers. for (uint32 x=1; x<=charges; x++) { // Actual roll. float thischance = 0.0; thischance = lds->Entries[item].chance; float drop_chance = 0.0; if(thischance != 100.0) drop_chance = MakeRandomFloat(0.0, 100.0); #if EQDEBUG>=11 LogFile->write(EQEMuLog::Debug, "Drop chance for npc: %s, this chance:%f, drop roll:%f", npc->GetName(), thischance, drop_chance); #endif if (thischance == 100.0 || drop_chance < thischance) { uint32 itemid = lds->Entries[item].item_id; const Item_Struct* dbitem = GetItem(itemid); npc->AddLootDrop(dbitem, itemlist, lds->Entries[item].item_charges, lds->Entries[item].minlevel, lds->Entries[item].maxlevel, lds->Entries[item].equip_item, false); pickedcharges++; } } // Items with multipliers only count as 1 towards the limit. if(pickedcharges > 0) limit++; // If true, limit reached. if(limit >= droplimit && droplimit > 0) break; item++; i++; // We didn't reach our minimium, run loop again. if(i == lds->NumEntries){ if(limit < mindrop){ i = 0; } } } // We either ran out of items or reached our limit. }
void SpawnEntry::_DoSpawn(SystemManager &mgr, PyServiceMgr &svc) { _log(SPAWN__POP, "Spawning spawn entry %u with group %u", m_id, m_group.id); //pick our spawn point... GPoint spawn_point; switch(m_boundsType) { //safe to assume `bounds` are correct. case boundsPoint: { spawn_point = bounds[0]; } break; case boundsLine: { GVector vec(bounds[0], bounds[1]); double len = vec.length(); spawn_point = GPoint(bounds[0] + Ga::GaFloat(MakeRandomFloat(0, len))*Ga::GaVec3(vec)); } break; default: _log(SPAWN__ERROR, "Invalid bounds type %u on spawn entry %u when spawning...", m_boundsType, GetID()); return; } _log(SPAWN__POP, " selected point (%.1f, %.1f, %.1f)", spawn_point.x, spawn_point.y, spawn_point.z); std::vector<NPC *> spawned; //now see what is gunna spawn... std::vector<SpawnGroup::Entry>::const_iterator cur, end; cur = m_group.entries.begin(); end = m_group.entries.end(); for(; cur != end; cur++) { _log(SPAWN__POP, " Evaluating spawn entry for NPC type %u in group %u", cur->npcTypeID, cur->spawnGroupID); int r; for(r = 0; r < cur->quantity; r++) { if(cur->probability < 1.0f) { if(MakeRandomFloat(0, 1.0f) > cur->probability) { _log(SPAWN__POP, " [%d] not spawning, p=%.4f failed.", r, cur->probability); continue; } _log(SPAWN__POP, " [%d] passed proability check of p=%.4f", r, cur->probability); } //NOTE: this is currently creating an entry in the DB... //which is terrible... we need to make an "in-memory only" // item concept. ItemData idata( cur->npcTypeID, cur->ownerID, //owner mgr.GetID(), flagAutoFit ); InventoryItemRef i = svc.item_factory.SpawnItem(idata); if( !i ) { _log(SPAWN__ERROR, "Failed to spawn item with type %u for group %u.", cur->npcTypeID, cur->spawnGroupID); continue; } _log(SPAWN__POP, " [%d] spawning NPC id %u", r, i->itemID()); //create them all at the same point to start with... //we will move them before they get added to the system NPC *npc = new NPC(&mgr, svc, i, cur->corporationID, 0, spawn_point, this); //TODO: add allianceID spawned.push_back(npc); } } if(spawned.empty()) { int timer = MakeRandomInt(m_timerMin, m_timerMax); _log(SPAWN__POP, "No NPCs produced by spawn entry %u. Resetting spawn timer to %d s.", m_id, timer); m_timer.Start(timer*1000); return; } //TODO: apply formation.. //hacking it for now... std::vector<NPC *>::iterator curn, endn; curn = spawned.begin(); endn = spawned.end(); for(; curn != endn; curn++) { _log(SPAWN__POP, "Moving NPC %u to (%.1f, %.1f, %.1f) due to formation.", (*curn)->GetID(), spawn_point.x, spawn_point.y, spawn_point.z); (*curn)->ForcedSetPosition(spawn_point); spawn_point.y += 1000.0f; } //now the NPCs are all set up, lets drop them into the system. curn = spawned.begin(); endn = spawned.end(); for(; curn != endn; curn++) { //load up any NPC attributes... if(!(*curn)->Load(svc.serviceDB())) { _log(SPAWN__POP, "Failed to load NPC data for NPC %u with type %u, depoping.", (*curn)->GetID(), (*curn)->Item()->typeID()); delete *curn; continue; } //record this NPC as something we spawned. m_spawnedIDs.insert((*curn)->GetID()); mgr.AddNPC(*curn); } //timer is disabled while the spawn is up. m_timer.Disable(); }
/* * SQL to remove all asteroids from space in ALL systems. * Important, run in this order or the attributes will not be deleted! * DELETE FROM srvEntity_default_attributes WHERE attributeID > 0 and itemID in (SELECT itemID from srvEntity where ownerID=1 AND typeID in (SELECT typeID from invTypes where groupID in (select groupID FROM invGroups where categoryID=25) or groupID=711)); DELETE FROM srvEntity_attributes WHERE attributeID > 0 and itemID in (SELECT itemID from srvEntity where ownerID=1 AND typeID in (SELECT typeID from invTypes where groupID in (select groupID FROM invGroups where categoryID=25) or groupID=711)); DELETE FROM srvEntity WHERE itemID>=140000000 AND ownerID=1 AND typeID in (SELECT typeID from invTypes where groupID in (select groupID FROM invGroups where categoryID=25) or groupID=711); * */ PyResult Command_spawnbelt( Client* who, const Seperator& args ) { if (!who->IsInSpace()) { throw PyException(MakeCustomError("You must be in space to spawn things.")); } bool makeIceBelt = false; bool makeRareIce = false; uint32 customCount = 0; if( args.argCount() >= 2 ) { if( !args.isNumber( 1 ) ) { if( args.arg( 1 ) == "ice" ) makeIceBelt = true; } else { if( atoi(args.arg( 1 ).c_str()) > 15 ) customCount = atoi(args.arg( 1 ).c_str()); else PyException( MakeCustomError( "Argument 1 should be at least 15!" ) ); } } if( args.argCount() >= 3 ) { if( args.isNumber( 2 ) ) { if( atoi(args.arg( 2 ).c_str()) > 15 ) customCount = atoi(args.arg(2).c_str()); else PyException( MakeCustomError( "Argument 2 should be at least 15!" ) ); } else if( args.arg( 2 ) == "ice" ) makeIceBelt = true; if( args.arg( 2 ) == "rareice" ) { makeIceBelt = true; makeRareIce = true; } } double beltradius = 25000.0; // 25 KM if(makeIceBelt) { beltradius = 100000.0; // 100 KM } uint32 pcs = 0; if (customCount > 15) { pcs = customCount + static_cast<uint32> (MakeRandomInt(-10, 10)); } else { pcs = 200 + static_cast<uint32> (MakeRandomInt(-10, 10)); } SystemManager* sys = who->System(); std::map<double, uint32> roidDist; if (makeIceBelt) { pcs /= 8; std::string securityStatus = sys->GetSystemSecurity(); if (!makeRareIce) { roidDist.insert(std::pair<double, uint32>(0.60, 16264)); // Blue Ice roidDist.insert(std::pair<double, uint32>(0.45, 17975)); // Thick Blue Ice roidDist.insert(std::pair<double, uint32>(0.30, 28627)); // Azure Ice roidDist.insert(std::pair<double, uint32>(0.20, 16262)); // Clear Icicle roidDist.insert(std::pair<double, uint32>(0.10, 16267)); // Dark Glitter } if (makeRareIce) { roidDist.insert(std::pair<double, uint32>(0.90, 16263)); // Glacial Mass roidDist.insert(std::pair<double, uint32>(0.80, 16265)); // White Glaze roidDist.insert(std::pair<double, uint32>(0.70, 16266)); // Glare Crust roidDist.insert(std::pair<double, uint32>(0.60, 16268)); // Gelidus roidDist.insert(std::pair<double, uint32>(0.50, 16269)); // Krystallos roidDist.insert(std::pair<double, uint32>(0.40, 17976)); // Pristine White Glaze roidDist.insert(std::pair<double, uint32>(0.30, 17977)); // Smooth Glacial Mass roidDist.insert(std::pair<double, uint32>(0.20, 17978)); // Enriched Clear Icicle roidDist.insert(std::pair<double, uint32>(0.10, 28628)); // Crystalline Icicle } } else { if (!CommandDB::GetRoidDist(sys->GetSystemSecurity(), roidDist)) { SysLog::Error("Command", "Couldn't get roid list for system security %s", sys->GetSystemSecurity()); throw PyException(MakeCustomError("Couldn't get roid list for system security %s", sys->GetSystemSecurity())); } } const GPoint position(who->GetPosition()); double phi = atan(position.x / position.z); if (position.z == 0) { phi = M_PI / 2; } if (position.z < 0) { phi += M_PI; } GPoint beltOffset; if (makeIceBelt) { beltOffset.x = (beltradius * 0.75) * sin(phi); beltOffset.z = (beltradius * 0.75) * cos(phi); } double alpha; GPoint mposition; double beltThickness = 3000; double height; double roidradius; const double beltangle = M_PI * 2.0 / 3.0; int triesLeft = pcs * 25; int pcsLeft = pcs; std::vector<std::pair<GPoint, double>> spawned; while (triesLeft-- && pcsLeft) { uint32 typeID = GetAsteroidType(MakeRandomFloat(), roidDist); // Generate asteroid parameters. if( makeIceBelt) { height = MakeRandomFloat(-0.2, 1.8); alpha = beltangle * ((M_PI / 8) * height); roidradius = MakeRandomFloat(4000.0, 10000.0); height *= 8; } else { alpha = beltangle * MakeRandomFloat(-M_PI / 4, M_PI / 4); roidradius = MakeRandomFloat( 100.0, 1000.0 ); height = MakeRandomFloat(-1, 1); const ItemType *type = ItemFactory::GetType(typeID); if (type->groupID() == EVEDB::invGroups::Veldspar) { roidradius *= 2; } } // Calculate new position. mposition.y = beltThickness * height; mposition.x = beltradius * sin(phi + alpha) + beltThickness * MakeRandomFloat(-1, 1); mposition.z = beltradius * cos(phi + alpha) + beltThickness * MakeRandomFloat(-1, 1); // Check for collision. bool collision = false; for (auto pair : spawned) { GPoint point = pair.first; double dist = (mposition - point).length(); double radii = (roidradius + pair.second); if ((dist - radii) < 0) { collision = true; continue; } } if (collision) { // There was a collision, try again. continue; } // Were good, add the asteroid. pcsLeft--; SpawnAsteroid(who->System(), typeID, roidradius, mposition + position - beltOffset); // Save the location for collision checks. spawned.push_back(std::pair<GPoint, double>(mposition, roidradius)); } return new PyString( "Spawn successsfull." ); }
void Adventure::MoveCorpsesToGraveyard() { if(GetTemplate()->graveyard_zone_id == 0) { return; } list<uint32> dbid_list; list<uint32> charid_list; char errbuf[MYSQL_ERRMSG_SIZE]; char* query = 0; MYSQL_RES *result; MYSQL_ROW row; if(database.RunQuery(query,MakeAnyLenString(&query,"SELECT id, charid FROM player_corpses WHERE instanceid=%d", GetInstanceID()), errbuf, &result)) { while((row = mysql_fetch_row(result))) { dbid_list.push_back(atoi(row[0])); charid_list.push_back(atoi(row[1])); } mysql_free_result(result); safe_delete_array(query); } else { LogFile->write(EQEMuLog::Error, "Error in AdventureManager:::MoveCorpsesToGraveyard: %s (%s)", query, errbuf); safe_delete_array(query); } list<uint32>::iterator iter = dbid_list.begin(); while(iter != dbid_list.end()) { float x = GetTemplate()->graveyard_x + MakeRandomFloat(-GetTemplate()->graveyard_radius, GetTemplate()->graveyard_radius); float y = GetTemplate()->graveyard_y + MakeRandomFloat(-GetTemplate()->graveyard_radius, GetTemplate()->graveyard_radius); float z = GetTemplate()->graveyard_z; if(database.RunQuery(query,MakeAnyLenString(&query, "UPDATE player_corpses SET zoneid=%d, instanceid=0, x=%f, y=%f, z=%f WHERE instanceid=%d", GetTemplate()->graveyard_zone_id, x, y, z, GetInstanceID()), errbuf)) { safe_delete_array(query); } else { LogFile->write(EQEMuLog::Error, "Error in AdventureManager:::MoveCorpsesToGraveyard: %s (%s)", query, errbuf); safe_delete_array(query); } iter++; } iter = dbid_list.begin(); list<uint32>::iterator c_iter = charid_list.begin(); while(iter != dbid_list.end()) { ServerPacket* pack = new ServerPacket(ServerOP_DepopAllPlayersCorpses, sizeof(ServerDepopAllPlayersCorpses_Struct)); ServerDepopAllPlayersCorpses_Struct *dpc = (ServerDepopAllPlayersCorpses_Struct*)pack->pBuffer; dpc->CharacterID = (*c_iter); dpc->InstanceID = 0; dpc->ZoneID = GetTemplate()->graveyard_zone_id; zoneserver_list.SendPacket(0, GetInstanceID(), pack); delete pack; pack = new ServerPacket(ServerOP_SpawnPlayerCorpse, sizeof(SpawnPlayerCorpse_Struct)); SpawnPlayerCorpse_Struct* spc = (SpawnPlayerCorpse_Struct*)pack->pBuffer; spc->player_corpse_id = (*iter); spc->zone_id = GetTemplate()->graveyard_zone_id; zoneserver_list.SendPacket(spc->zone_id, 0, pack); delete pack; iter++; c_iter++; } }