void CUIButton::DrawTexture() { Frect rect; GetAbsoluteRect (rect); if(m_bAvailableTexture && m_bTextureEnable) { if(m_eButtonState == BUTTON_UP || m_eButtonState == BUTTON_NORMAL) m_UIStaticItem.SetPos(rect.left + m_TextureOffset.x, rect.top + m_TextureOffset.y); else m_UIStaticItem.SetPos(rect.left + m_PushOffset.x + m_TextureOffset.x, rect.top + m_PushOffset.y + m_TextureOffset.y); if(m_bStretchTexture) m_UIStaticItem.SetRect(0, 0, rect.width(), rect.height()); else { Frect r={0,0, m_UIStaticItem.GetOriginalRectScaled().width(), m_UIStaticItem.GetOriginalRectScaled().height()}; m_UIStaticItem.SetRect(r); } if( Heading() ) m_UIStaticItem.Render( GetHeading() ); else m_UIStaticItem.Render(); } }
void Compass::Process(void) { GetHeading(); printf ("x: %f \t\ty: %f \t\t z: %f \t\t heading: %f \t\r\n", x, y, z, heading); log_printf("x: %f \t\ty: %f \t\t z: %f \t\t heading: %f \t\r\n", x, y, z, heading); }
void iAnt_controller::ApproachTheTarget() { /* angle of the robot's direction relative to the arena's origin */ CRadians angle1 = GetHeading(); /* angle from the target to the robot's position */ CRadians angle2 = (target - GetPosition()).Angle(); /* heading = angle1 - angle2 = 0.0 when the robot is facing its target */ CRadians heading = (angle1 - angle2).SignedNormalize(); // if(IsCollisionDetected() == true) { // collisionDelay = data->SimTime + (data->TicksPerSecond * 2); // // /* turn left */ // motorActuator->SetLinearVelocity(-RobotTurningSpeed, RobotTurningSpeed); if(heading <= AngleToleranceInRadians.GetMin()) { /* turn left */ motorActuator->SetLinearVelocity(-RobotTurningSpeed, RobotTurningSpeed); } else if(heading >= AngleToleranceInRadians.GetMax()) { /* turn right */ motorActuator->SetLinearVelocity(RobotTurningSpeed, -RobotTurningSpeed); } else { /* go straight */ motorActuator->SetLinearVelocity(RobotForwardSpeed, RobotForwardSpeed); } }
void iAnt_controller::ApproachTheTarget(CVector2 myTarget) { /* angle of the robot's direction relative to the arena's origin */ CRadians angle1 = GetHeading(); /* angle from the target to the robot's position */ CRadians angle2 = (myTarget - GetPosition()).Angle(); /* heading = angle1 - angle2 = 0.0 when the robot is facing its target */ CRadians heading = (angle1 - angle2).SignedNormalize(); if(heading <= AngleToleranceInRadians.GetMin()) { /* turn left */ motorActuator->SetLinearVelocity(-RobotTurningSpeed, RobotTurningSpeed); } else if(heading >= AngleToleranceInRadians.GetMax()) { /* turn right */ motorActuator->SetLinearVelocity( RobotTurningSpeed, -RobotTurningSpeed); } else { /* go straight */ motorActuator->SetLinearVelocity(RobotForwardSpeed, RobotForwardSpeed); } }
void CLocalPlayer::SendOnFootData() { RakNet::BitStream PlayerBitStream_send; PlayerBitStream_send.Write((MessageID)ID_SEND_PLAYER_DATA); PlayerBitStream_send.Write(NetworkManager->playerid); PlayerBitStream_send.Write(GetType()); PlayerBitStream_send.Write(GetModel()); PlayerBitStream_send.Write(GetHealth()); PlayerBitStream_send.Write(GetArmour()); PlayerBitStream_send.Write(GetCoords().x); PlayerBitStream_send.Write(GetCoords().y); PlayerBitStream_send.Write(GetCoords().z); PlayerBitStream_send.Write(GetHeading()); PlayerBitStream_send.Write(GetQuaternion().fX); PlayerBitStream_send.Write(GetQuaternion().fY); PlayerBitStream_send.Write(GetQuaternion().fZ); PlayerBitStream_send.Write(GetQuaternion().fW); PlayerBitStream_send.Write(AI::GET_PED_DESIRED_MOVE_BLEND_RATIO(playerPed)); PlayerBitStream_send.Write(GetVelocity().x); PlayerBitStream_send.Write(GetVelocity().y); PlayerBitStream_send.Write(GetVelocity().z); PlayerBitStream_send.Write(LocalPlayer->GetVehicle()); PlayerBitStream_send.Write(time(0)); NetworkManager->client->Send(&PlayerBitStream_send, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, RakNet::UNASSIGNED_SYSTEM_ADDRESS, true); }
/** * The log method puts interesting information to the SmartDashboard. */ void DriveTrain::Log() { // SmartDashboard::PutNumber("Drive Left Distance", left_motor.GetDistance()); // SmartDashboard::PutNumber("Drive Right Distance", right_motor.GetDistance()); // SmartDashboard::PutNumber("Drive Left Speed", left_motor.GetVelocity()); SmartDashboard::PutNumber("Drive Left Speed", GetLeftVoltage()); SmartDashboard::PutNumber("Drive Right Speed", GetRightVoltage()); SmartDashboard::PutNumber("Drive Heading", GetHeading()); }
double GetCTE(double current_lat, double current_lon, double dest_lat, double dest_lon, double track_angle) { double cte, dist, bearing; dist = GetDistance(current_lat,dest_lat,current_lon, dest_lon); bearing = GetHeading(current_lat,dest_lat,current_lon, dest_lon); cte = asin(sin(dist/R_EARTH)*sin(bearing-track_angle)) * R_EARTH; return cte; }
//we need this function to immediately determine, after we receive OP_Fishing, if we can even try to fish, otherwise we have to wait a while to get the failure bool Client::CanFish() { //make sure we still have a fishing pole on: const ItemInst* Pole = m_inv[MainPrimary]; int32 bslot = m_inv.HasItemByUse(ItemTypeFishingBait, 1, invWhereWorn|invWherePersonal); const ItemInst* Bait = nullptr; if (bslot != INVALID_INDEX) Bait = m_inv.GetItem(bslot); if(!Pole || !Pole->IsType(ItemClassCommon) || Pole->GetItem()->ItemType != ItemTypeFishingPole) { if (m_inv.HasItemByUse(ItemTypeFishingPole, 1, invWhereWorn|invWherePersonal|invWhereBank|invWhereSharedBank|invWhereTrading|invWhereCursor)) //We have a fishing pole somewhere, just not equipped Message_StringID(MT_Skills, FISHING_EQUIP_POLE); //You need to put your fishing pole in your primary hand. else //We don't have a fishing pole anywhere Message_StringID(MT_Skills, FISHING_NO_POLE); //You can't fish without a fishing pole, go buy one. return false; } if (!Bait || !Bait->IsType(ItemClassCommon) || Bait->GetItem()->ItemType != ItemTypeFishingBait) { Message_StringID(MT_Skills, FISHING_NO_BAIT); //You can't fish without fishing bait, go buy some. return false; } if(zone->zonemap != nullptr && zone->watermap != nullptr && RuleB(Watermap, CheckForWaterWhenFishing)) { glm::vec3 rodPosition; // Tweak Rod and LineLength if required const float RodLength = RuleR(Watermap, FishingRodLength); const float LineLength = RuleR(Watermap, FishingLineLength); int HeadingDegrees; HeadingDegrees = (int) ((GetHeading()*360)/256); HeadingDegrees = HeadingDegrees % 360; rodPosition.x = m_Position.x + RodLength * sin(HeadingDegrees * M_PI/180.0f); rodPosition.y = m_Position.y + RodLength * cos(HeadingDegrees * M_PI/180.0f); // Do BestZ to find where the line hanging from the rod intersects the water (if it is water). // and go 1 unit into the water. glm::vec3 dest; dest.x = rodPosition.x; dest.y = rodPosition.y; dest.z = m_Position.z+10; rodPosition.z = zone->zonemap->FindBestZ(dest, nullptr) + 4; bool in_lava = zone->watermap->InLava(rodPosition); bool in_water = zone->watermap->InWater(rodPosition) || zone->watermap->InVWater(rodPosition); //Message(0, "Rod is at %4.3f, %4.3f, %4.3f, InWater says %d, InLava says %d", RodX, RodY, RodZ, in_water, in_lava); if (in_lava) { Message_StringID(MT_Skills, FISHING_LAVA); //Trying to catch a fire elemental or something? return false; } if((!in_water) || (m_Position.z-rodPosition.z)>LineLength) { //Didn't hit the water OR the water is too far below us Message_StringID(MT_Skills, FISHING_LAND); //Trying to catch land sharks perhaps? return false; } } return true; }
void DSA_controller::ApproachTheTarget(CVector2 myTarget) { const CCI_FootBotProximitySensor::TReadings& tProxReads = proximitySensor->GetReadings(); CVector2 cAccumulator; Real front(0.0); Real back(0.0); Real m = 1.0; for(size_t i = 0; i <= 1; ++i) { cAccumulator += CVector2(tProxReads[i].Value, tProxReads[i].Angle); front += tProxReads[i].Value; } for(size_t i = 22; i <= 23; ++i) { cAccumulator += CVector2(tProxReads[i].Value, tProxReads[i].Angle); front += tProxReads[i].Value; } for(size_t i = 2; i <= 21; ++i) { back += tProxReads[i].Value; } cAccumulator /= tProxReads.size(); CVector2 t = myTarget; if(front > 0.0) { t += cAccumulator; collisionCounter++; } if(front == 0 && collisionCounter > 0) collisionCounter--; if(collisionCounter > loopFunctions.TicksPerSecond * 2.0) { m *= -1.0; } /* angle of the robot's direction relative to the arena's origin */ CRadians angle1 = GetHeading(); /* angle from the target to the robot's position */ CRadians angle2 = (t - GetPosition()).Angle(); /* heading = angle1 - angle2 = 0.0 when the robot is facing its target */ CRadians heading = (angle1 - angle2).SignedNormalize(); if(AngleToleranceInRadians.WithinMinBoundIncludedMaxBoundIncluded(heading)) { /* Go straight */ motorActuator->SetLinearVelocity(m * RobotForwardSpeed, m * RobotForwardSpeed); //SetStop(1); } else { if(heading > AngleToleranceInRadians.GetMax()) { motorActuator->SetLinearVelocity(RobotTurningSpeed, -RobotForwardSpeed); } else if(heading < AngleToleranceInRadians.GetMin()) { motorActuator->SetLinearVelocity(-RobotForwardSpeed, RobotTurningSpeed); } } }
void CUIWeaponCellItem::InitAddon(CUIStatic* s, LPCSTR section, Fvector2 addon_offset, bool b_rotate) { Frect tex_rect; Fvector2 base_scale; if(Heading()) { base_scale.x = GetHeight()/(INV_GRID_WIDTHF*m_grid_size.x); base_scale.y = GetWidth()/(INV_GRID_HEIGHTF*m_grid_size.y); }else { base_scale.x = GetWidth()/(INV_GRID_WIDTHF*m_grid_size.x); base_scale.y = GetHeight()/(INV_GRID_HEIGHTF*m_grid_size.y); } Fvector2 cell_size; cell_size.x = pSettings->r_u32(section, "inv_grid_width")*INV_GRID_WIDTHF; cell_size.y = pSettings->r_u32(section, "inv_grid_height")*INV_GRID_HEIGHTF; tex_rect.x1 = pSettings->r_u32(section, "inv_grid_x")*INV_GRID_WIDTHF; tex_rect.y1 = pSettings->r_u32(section, "inv_grid_y")*INV_GRID_HEIGHTF; tex_rect.rb.add (tex_rect.lt,cell_size); cell_size.mul (base_scale); if(b_rotate) { s->SetWndSize (Fvector2().set(cell_size.y, cell_size.x) ); Fvector2 new_offset; new_offset.x = addon_offset.y*base_scale.x; new_offset.y = GetHeight() - addon_offset.x*base_scale.x - cell_size.x; addon_offset = new_offset; }else { s->SetWndSize (cell_size); addon_offset.mul (base_scale); } s->SetWndPos (addon_offset); s->SetOriginalRect (tex_rect); s->SetStretchTexture (true); s->EnableHeading (b_rotate); if(b_rotate) { s->SetHeading (GetHeading()); Fvector2 offs; offs.set (0.0f, s->GetWndSize().y); s->SetHeadingPivot (Fvector2().set(0.0f,0.0f), /*Fvector2().set(0.0f,0.0f)*/offs, true); } }
Fvector2 CUICustomMap::ConvertRealToLocal (const Fvector2& src)// meters->pixels (relatively own left-top pos) { Fvector2 res; if( !Heading() ){ return ConvertRealToLocalNoTransform(src); }else{ Fvector2 heading_pivot = GetStaticItem()->GetHeadingPivot(); res = ConvertRealToLocalNoTransform(src); res.sub(heading_pivot); rotation_(res.x, res.y, GetHeading(), res.x, res.y); res.add(heading_pivot); return res; }; }
/***** * *****/ bool iAnt_controller::east() { cout << "Moving east" << '\n'; bool amIGoingEast = true; CRadians heading = GetHeading().UnsignedNormalize(); CRadians tolerance(0.09); CRadians threePIHalves = (CRadians::PI*3/2); // CRadians negPI = (CRadians::PI)*-1; if(heading < threePIHalves-tolerance) { motorActuator->SetLinearVelocity(RobotTurningSpeed,0.0); amIGoingEast = false; }else if(heading > threePIHalves+tolerance) { motorActuator->SetLinearVelocity(RobotTurningSpeed,0.0); amIGoingEast = false; }else { motorActuator->SetLinearVelocity(0.0, 0.0); amIGoingEast = true; } return amIGoingEast; } // /***** // * // *****/ bool iAnt_controller::west() { cout << "Moving west" << '\n'; bool amIGoingWest = true; CRadians heading = GetHeading().UnsignedNormalize(); CRadians tolerance(0.09); if(heading < CRadians::PI/2- tolerance) { motorActuator->SetLinearVelocity(0.0, RobotTurningSpeed); amIGoingWest = false; } else if(heading > CRadians::PI/2 + tolerance) { motorActuator->SetLinearVelocity(0.0, RobotTurningSpeed); amIGoingWest = false; }else { motorActuator->SetLinearVelocity(0.0, 0.0); amIGoingWest = true; } return amIGoingWest; }
/***** * Controls the robot's motor to go in the correct angle relative to the target. *****/ void iAnt_controller::ApproachTheTarget() { /* angle of the robot's direction relative to the arena's origin */ CRadians angle1 = GetHeading(); /* angle from the target to the robot's position */ CRadians angle2 = (target - GetPosition()).Angle(); /* heading = angle1 - angle2 = 0.0 when the robot is facing its target */ CRadians heading = (angle1 - angle2).SignedNormalize(); //UDPDATED TO ACCOMADATE THE DIFFUSION COLLSION AVOIDANCE // if(IsCollisionDetected() == false) // { // if(heading <= AngleToleranceInRadians.GetMin()) { // /* turn left */ // motorActuator->SetLinearVelocity(-RobotTurningSpeed, // RobotTurningSpeed); // } else if(heading >= AngleToleranceInRadians.GetMax()){ // /* turn right */ // motorActuator->SetLinearVelocity( RobotTurningSpeed, // -RobotTurningSpeed); // } else { // /* go straight */ // motorActuator->SetLinearVelocity(RobotForwardSpeed, // RobotForwardSpeed); // } // } if(heading <= AngleToleranceInRadians.GetMin()) { /* turn left */ motorActuator->SetLinearVelocity(-RobotTurningSpeed, RobotTurningSpeed); } else if(heading >= AngleToleranceInRadians.GetMax()) { /* turn right */ motorActuator->SetLinearVelocity( RobotTurningSpeed, -RobotTurningSpeed); } else { /* go straight */ motorActuator->SetLinearVelocity(RobotForwardSpeed, RobotForwardSpeed); } }
bool iAnt_controller::east() { cout << "Moving east" << '\n'; bool amIGoingEast = true; CRadians heading = GetHeading().UnsignedNormalize(); CRadians tolerance(0.09); CRadians threePIHalves = (CRadians::PI*3/2); // CRadians negPI = (CRadians::PI)*-1; if(heading < threePIHalves-tolerance) { motorActuator->SetLinearVelocity(RobotTurningSpeed,0.0); amIGoingEast = false; }else if(heading > threePIHalves+tolerance) { motorActuator->SetLinearVelocity(RobotTurningSpeed,0.0); amIGoingEast = false; }else { motorActuator->SetLinearVelocity(0.0, 0.0); amIGoingEast = true; } return amIGoingEast; }
void FA::FlockingAgent::draw(sf::RenderTarget& target, sf::RenderStates states) const { mCentreCircle->setFillColor(mIsPrey ? sf::Color::Blue : sf::Color::Red); auto pos = GetPosition(); mCentreCircle->setPosition(pos); target.draw(*mCentreCircle, states); if (!Debug::Instance().GetEnabled()) return; auto localheading = GetHeading(); //heading Debug::Instance().DrawLine(pos, pos + localheading * 5, sf::Color::Green); DrawAgentSensorDebug(pos, localheading, mSensorArray.GetAvoidance(), sf::Color::Cyan); DrawAgentSensorDebug(pos, localheading, mSensorArray.GetGrouping(), sf::Color::Magenta); DrawAgentSensorDebug(pos, localheading, mSensorArray.GetHeading(), sf::Color::Red); DrawAgentSensorDebug(pos, localheading, mSensorArray.GetSpeed(), sf::Color::Yellow); DrawAgentSensorDebug(pos, localheading, mSensorArray.GetFlee(), sf::Color::White); }
bool iAnt_controller::south() { cout << "Moving south" << '\n'; bool amIGoingSouth = true; CRadians heading = GetHeading().UnsignedNormalize(); CRadians tolerance(0.09); if(heading < CRadians::PI - tolerance) { motorActuator->SetLinearVelocity(-RobotTurningSpeed, RobotTurningSpeed); amIGoingSouth = false; } else if(heading > CRadians::PI + tolerance) { motorActuator->SetLinearVelocity(RobotTurningSpeed, -RobotTurningSpeed); amIGoingSouth = false; } else { motorActuator->SetLinearVelocity(0.0, 0.0); amIGoingSouth = true; } return amIGoingSouth; }
void Client::SummonHorse(uint16 spell_id) { if (GetHorseId() != 0) { Message(13,"You already have a Horse. Get off, Fatbutt!"); return; } if(!Horse::IsHorseSpell(spell_id)) { LogFile->write(EQEMuLog::Error, "%s tried to summon an unknown horse, spell id %d", GetName(), spell_id); return; } // No Horse, lets get them one. Horse* horse = new Horse(this, spell_id, GetX(), GetY(), GetZ(), GetHeading()); //we want to manage the spawn packet ourself. //another reason is we dont want quests executing on it. entity_list.AddNPC(horse, false); // Okay, lets say they have a horse now. EQApplicationPacket outapp; horse->CreateHorseSpawnPacket(&outapp, GetName(), GetID()); /* // Doodman: Kludged in here instead of adding a field to PCType. FIXME! NewSpawn_Struct* ns=(NewSpawn_Struct*)outapp->pBuffer; ns->spawn.texture=mount_color; ns->spawn.pet_owner_id=0; ns->spawn.walkspeed=npc_type->walkspeed; ns->spawn.runspeed=npc_type->runspeed; */ entity_list.QueueClients(horse, &outapp); uint16 tmpID = horse->GetID(); SetHorseId(tmpID); }
void Doors::CreateDatabaseEntry() { if(database.GetDoorsDBCountPlusOne(zone->GetShortName(), zone->GetInstanceVersion()) - 1 >= 255) { return; } database.InsertDoor(GetDoorDBID(), GetDoorID(), GetDoorName(), GetX(), GetY(), GetZ(), GetHeading(), GetOpenType(), GetGuildID(), GetLockpick(), GetKeyItem(), GetDoorParam(), GetInvertState(), GetIncline(), GetSize()); }
void FA::FlockingAgent::Finalise(float dt) { //move away from the local centre to avoid very tight clumping kf::Vector2f avoid = mAvoidanceCache.Average();// *mSensorArray.GetAvoidance().GetInfluence(); avoid = avoid * -1;//away from that location avoid *= mSensorArray.GetAvoidance().GetInfluence(); //we want to travel to the centre of our local group kf::Vector2f group = mGroupingCache.Average(); if (mGroupingCache.count > 0) { group = group;//this has already been done in local space -GetPosition(); group.normalise(); group *= mSensorArray.GetGrouping().GetInfluence(); } //we want to match the average of all our friends headings // so find the diff between headings kf::Vector2f heading; kf::Vector2f ourHeading = GetHeading(); if (mHeadingCache.count > 0) { kf::Vector2f averageHeading = mHeadingCache.Average().normalise(); kf::Vector2f ourHeading = GetHeading(); float averageAng = atan2(averageHeading.x, averageHeading.y), ourAng = atan2(ourHeading.x, ourHeading.y); heading = ourHeading; float angleDiff = ourAng - averageAng; heading.rotate(RIGHT_ANGLE); heading = heading * angleDiff * mSensorArray.GetHeading().GetInfluence(); } //we want to travel at the same speed as our friends kf::Vector2f spd; if (mSpeedCache.count > 0) { float speedDif = mSpeedCache.Average().x - GetSpeed(); spd = ourHeading * mSensorArray.GetSpeed().GetInfluence(); } //very much don't be where the preditors are kf::Vector2f flee = mFleeCache.Average(); flee = flee * -1;//away from that location flee *= mSensorArray.GetFlee().GetInfluence(); //go after our prey kf::Vector2f chase; if(!mIsPrey) chase = mChaseCache.vec.normalise(); chase *= mSensorArray.GetChase().GetInfluence(); //accumulate and clamp to max impulse auto totalForce = avoid + group + heading + spd + flee + chase; auto tfl = totalForce.length(); if (tfl > mMaxAccel) { totalForce /= tfl; totalForce *= mMaxAccel; } AddForce(totalForce*dt); }
void iAnt_controller::ControlStep() { LOG << GetHeading() << endl << '\n'; /////////ADDED/////////////// CVector3 position3d(GetPosition().GetX(), GetPosition().GetY(), 0.02); CVector3 target3d(GetTarget().GetX(), GetTarget().GetY(), 0.02); CRay3 targetRay(target3d, position3d); data->TargetRayList.push_back(targetRay); //[ + + ] move foward //motorActuator->SetLinearVelocity(RobotForwardSpeed, RobotForwardSpeed); //[ + - ] rotates to the right //motorActuator->SetLinearVelocity(RobotForwardSpeed, -RobotForwardSpeed); //[ + 0] spins left //motorActuator->SetLinearVelocity(RobotForwardSpeed, 0.0); //[ 0 +] spins right //motorActuator->SetLinearVelocity(RobotForwardSpeed, 0.0); east(); //west(); //north(); //south(); //char* pat = LinearSpiral(); //out << "pat" << *pat << '\n'; //free(pat); //checkDistanceX(); // if(west() == true){ // motorActuator->SetLinearVelocity(stopMoving(checkDistanceX()), stopMoving(checkDistanceX())); // //motorActuator->SetLinearVelocity(RobotForwardSpeed,RobotForwardSpeed); // } // if(west() == true) { // motorActuator->SetLinearVelocity(RobotForwardSpeed,RobotForwardSpeed); // } // if(east() == true){ // motorActuator->SetLinearVelocity(RobotForwardSpeed, RobotForwardSpeed); // } //UNCONMMENT bool stop=checkDistanceY(); cout << "stop: " << stop << '\n'; stopMoving(stop); motorActuator->SetLinearVelocity(stopMoving(stop), stopMoving(stop)); if (stop) { east(); motorActuator->SetLinearVelocity(0.0,RobotForwardSpeed); if(east() == true) { motorActuator->SetLinearVelocity(RobotForwardSpeed,RobotForwardSpeed); } stop = false; } //motorActuator->SetLinearVelocity(stopMoving(stop), stopMoving(stop)); //north(); // if(north() == true) { // //motorActuator->SetLinearVelocity(RobotForwardSpeed, RobotForwardSpeed); // motorActuator->SetLinearVelocity(stopMoving(checkDistanceY()), stopMoving(checkDistanceY())); // } // if(south() == true) { // checkDistanceY(); // motorActuator->SetLinearVelocity(RobotForwardSpeed, RobotForwardSpeed); // } }
void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) { #ifdef BOTS // This block is necessary to clean up any bot objects owned by a Client Bot::ProcessClientZoneChange(this); #endif zoning = true; if (app->size != sizeof(ZoneChange_Struct)) { LogFile->write(EQEMuLog::Debug, "Wrong size: OP_ZoneChange, size=%d, expected %d", app->size, sizeof(ZoneChange_Struct)); return; } #if EQDEBUG >= 5 LogFile->write(EQEMuLog::Debug, "Zone request from %s", GetName()); DumpPacket(app); #endif ZoneChange_Struct* zc=(ZoneChange_Struct*)app->pBuffer; uint16 target_zone_id = 0; uint16 target_instance_id = zc->instanceID; ZonePoint* zone_point = nullptr; //figure out where they are going. if(zc->zoneID == 0) { //client dosent know where they are going... //try to figure it out for them. switch(zone_mode) { case EvacToSafeCoords: case ZoneToSafeCoords: //going to safe coords, but client dosent know where? //assume it is this zone for now. target_zone_id = zone->GetZoneID(); break; case GMSummon: target_zone_id = zonesummon_id; break; case GateToBindPoint: target_zone_id = m_pp.binds[0].zoneId; break; case ZoneToBindPoint: target_zone_id = m_pp.binds[0].zoneId; break; case ZoneSolicited: //we told the client to zone somewhere, so we know where they are going. target_zone_id = zonesummon_id; break; case ZoneUnsolicited: //client came up with this on its own. zone_point = zone->GetClosestZonePointWithoutZone(GetX(), GetY(), GetZ(), this, ZONEPOINT_NOZONE_RANGE); if(zone_point) { //we found a zone point, which is a reasonable distance away //assume that is the one were going with. target_zone_id = zone_point->target_zone_id; target_instance_id = zone_point->target_zone_instance; } else { //unable to find a zone point... is there anything else //that can be a valid un-zolicited zone request? CheatDetected(MQZone, zc->x, zc->y, zc->z); Message(13, "Invalid unsolicited zone request."); LogFile->write(EQEMuLog::Error, "Zoning %s: Invalid unsolicited zone request to zone id '%d'.", GetName(), target_zone_id); SendZoneCancel(zc); return; } break; default: break; }; } else { // This is to allow both 6.2 and Titanium clients to perform a proper zoning of the client when evac/succor // WildcardX 27 January 2008 if(zone_mode == EvacToSafeCoords && zonesummon_id > 0) target_zone_id = zonesummon_id; else target_zone_id = zc->zoneID; //if we are zoning to a specific zone unsolicied, //then until otherwise determined, they must be zoning //on a zone line. if(zone_mode == ZoneUnsolicited) { if(target_zone_id == zone->GetZoneID()) { SendZoneCancel(zc); return; } zone_point = zone->GetClosestZonePoint(GetX(), GetY(), GetZ(), target_zone_id, this, ZONEPOINT_ZONE_RANGE); //if we didnt get a zone point, or its to a different zone, //then we assume this is invalid. if(!zone_point || zone_point->target_zone_id != target_zone_id) { LogFile->write(EQEMuLog::Error, "Zoning %s: Invalid unsolicited zone request to zone id '%d'.", GetName(), target_zone_id); CheatDetected(MQGate, zc->x, zc->y, zc->z); SendZoneCancel(zc); return; } } } if(target_instance_id > 0) { //make sure we are in it and it's unexpired. if(!database.VerifyInstanceAlive(target_instance_id, CharacterID())) { Message(13, "Instance ID was expired or you were not in it."); SendZoneCancel(zc); return; } if(!database.VerifyZoneInstance(target_zone_id, target_instance_id)) { Message(13, "Instance ID was %u does not go with zone id %u", target_instance_id, target_zone_id); SendZoneCancel(zc); return; } } //make sure its a valid zone. const char *target_zone_name = database.GetZoneName(target_zone_id); if(target_zone_name == nullptr) { //invalid zone... Message(13, "Invalid target zone ID."); LogFile->write(EQEMuLog::Error, "Zoning %s: Unable to get zone name for zone id '%d'.", GetName(), target_zone_id); SendZoneCancel(zc); return; } //load up the safe coords, restrictions, and verify the zone name float safe_x, safe_y, safe_z; int16 minstatus = 0; uint8 minlevel = 0; char flag_needed[128]; if(!database.GetSafePoints(target_zone_name, database.GetInstanceVersion(target_instance_id), &safe_x, &safe_y, &safe_z, &minstatus, &minlevel, flag_needed)) { //invalid zone... Message(13, "Invalid target zone while getting safe points."); LogFile->write(EQEMuLog::Error, "Zoning %s: Unable to get safe coordinates for zone '%s'.", GetName(), target_zone_name); SendZoneCancel(zc); return; } char buf[10]; snprintf(buf, 9, "%d", target_zone_id); buf[9] = '\0'; parse->EventPlayer(EVENT_ZONE, this, buf, 0); //handle circumvention of zone restrictions //we need the value when creating the outgoing packet as well. uint8 ignorerestrictions = zonesummon_ignorerestrictions; zonesummon_ignorerestrictions = 0; float dest_x=0, dest_y=0, dest_z=0, dest_h; dest_h = GetHeading(); switch(zone_mode) { case EvacToSafeCoords: case ZoneToSafeCoords: LogFile->write(EQEMuLog::Debug, "Zoning %s to safe coords (%f,%f,%f) in %s (%d)", GetName(), safe_x, safe_y, safe_z, target_zone_name, target_zone_id); dest_x = safe_x; dest_y = safe_y; dest_z = safe_z; break; case GMSummon: dest_x = zonesummon_x; dest_y = zonesummon_y; dest_z = zonesummon_z; ignorerestrictions = 1; break; case GateToBindPoint: dest_x = m_pp.binds[0].x; dest_y = m_pp.binds[0].y; dest_z = m_pp.binds[0].z; break; case ZoneToBindPoint: dest_x = m_pp.binds[0].x; dest_y = m_pp.binds[0].y; dest_z = m_pp.binds[0].z; ignorerestrictions = 1; //can always get to our bind point? seems exploitable break; case ZoneSolicited: //we told the client to zone somewhere, so we know where they are going. //recycle zonesummon variables dest_x = zonesummon_x; dest_y = zonesummon_y; dest_z = zonesummon_z; break; case ZoneUnsolicited: //client came up with this on its own. //client requested a zoning... what are the cases when this could happen? //Handle zone point case: if(zone_point != nullptr) { //they are zoning using a valid zone point, figure out coords //999999 is a placeholder for 'same as where they were from' if(zone_point->target_x == 999999) dest_x = GetX(); else dest_x = zone_point->target_x; if(zone_point->target_y == 999999) dest_y = GetY(); else dest_y = zone_point->target_y; if(zone_point->target_z == 999999) dest_z=GetZ(); else dest_z = zone_point->target_z; if(zone_point->target_heading == 999) dest_h = GetHeading(); else dest_h = zone_point->target_heading; break; } //for now, there are no other cases... //could not find a valid reason for them to be zoning, stop it. CheatDetected(MQZoneUnknownDest, 0.0, 0.0, 0.0); LogFile->write(EQEMuLog::Error, "Zoning %s: Invalid unsolicited zone request to zone id '%s'. Not near a zone point.", GetName(), target_zone_name); SendZoneCancel(zc); return; default: break; }; //OK, now we should know where were going... //Check some rules first. int8 myerror = 1; //1 is succes //not sure when we would use ZONE_ERROR_NOTREADY //enforce min status and level if (!ignorerestrictions && (Admin() < minstatus || GetLevel() < minlevel)) { myerror = ZONE_ERROR_NOEXPERIENCE; } if(!ignorerestrictions && flag_needed[0] != '\0') { //the flag needed string is not empty, meaning a flag is required. if(Admin() < minStatusToIgnoreZoneFlags && !HasZoneFlag(target_zone_id)) { Message(13, "You do not have the flag to enter %s.", target_zone_name); myerror = ZONE_ERROR_NOEXPERIENCE; } } //TODO: ADVENTURE ENTRANCE CHECK if(myerror == 1) { //we have successfully zoned DoZoneSuccess(zc, target_zone_id, target_instance_id, dest_x, dest_y, dest_z, dest_h, ignorerestrictions); } else { LogFile->write(EQEMuLog::Error, "Zoning %s: Rules prevent this char from zoning into '%s'", GetName(), target_zone_name); SendZoneError(zc, myerror); } }
/////////////////////////////////////////////////// // Quagmire - that case above getting to long and spells are gonna have a lot of cases of their own // Cofruben - Reorganised this a little. void Mob::SpellEffect(Mob* caster, Spell* spell, int8 caster_level, bool partialResist) { //Spells not loaded! if(!spells_handler.SpellsLoaded()) return; //Spell not loaded! if(!spell) return; //Yeahlight: Caster was not supplied if(!caster) return; int i = 0; const int16 spell_id = spell->GetSpellID(); const char* teleport_zone = spell->GetSpellTeleportZone(); // 1. Is it a buff? If so, handle its time based effects. if (spell->IsBuffSpell()) spells_handler.HandleBuffSpellEffects(caster, this, spell); // 2. Handle its single-time effect. for (i = 0; i < EFFECT_COUNT; i++) { TSpellEffect effect_id = spell->GetSpellEffectID(i); if(effect_id == SE_Blank || effect_id == 0xFF) continue; int8 formula = spell->GetSpellFormula(i); sint16 base = spell->GetSpellBase(i); sint16 max = spell->GetSpellMax(i); sint32 amount = spells_handler.CalcSpellValue(spell, i, caster_level); //Yeahlight: This is an NPC and had a detremental spell casted upon it if(this->IsNPC() && (spell->IsDetrimentalSpell() || spell->IsUtilitySpell())) { CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): aggroing %s because of the spell effect!", spell->GetSpellName(), this->GetName()); //Yeahlight: Generate hate based on the spells's effect type sint16 tempHate = GetSpellHate(effect_id, spell->GetMinLevel(), false, amount); if(tempHate) { this->CastToNPC()->AddToHateList(caster, 0, tempHate); } } switch(effect_id) { case SE_CurrentHP: case SE_CurrentHPOnce: { sint32 OldHP = this->GetHP(); sint32 damage = amount; //Yeahlight: Partial resist calculations if(partialResist) { damage = damage / 2; damage = damage * (float)((float)(rand()%90 + 10) / 100.00f); if(caster->IsClient() && caster->CastToClient()->GetDebugMe()) caster->Message(YELLOW, "Debug: Your direct damage spell resist has been upgrade to a partial resist."); } this->ChangeHP(caster, damage, spell_id); sint32 NewHP = this->GetHP(); CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You changed %s's hp by %+i.", spell->GetSpellName(), this->GetName(), damage); break; } case SE_MovementSpeed: { //Yeahlight: Handled client side CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a Movement Speed spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_AttackSpeed: { //Yeahlight: There should not be any work to be done here CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a Attack Speed spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_Invisibility: { this->SetInvisible(true); //Yeahlight: Castee has a pet; remove it if(GetPet()) { Mob* myPet = GetPet(); //Yeahlight: Castee's pet is an NPC if(myPet->IsNPC()) { //Yeahlight: Castee's pet is a charmed NPC if(myPet->CastToNPC()->IsCharmed()) { myPet->CastToNPC()->BuffFadeByEffect(SE_Charm); } //Yeahlight: Castee's pet is a summoned NPC else { myPet->Depop(); } } //Yeahlight: Castee's pet is a charmed PC else if(myPet->IsClient() && myPet->CastToClient()->IsCharmed()) { myPet->CastToClient()->BuffFadeByEffect(SE_Charm); } } CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted an invisibility spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_CurrentMana: { SetMana(GetMana() + amount); CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a mana recovery spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_AddFaction: { //Yeahlight: Only continue if the target is an NPC and the caster is a PC if(this->IsNPC() && caster->IsClient()) { caster->CastToClient()->SetCharacterFactionLevelModifier(this->CastToNPC()->GetPrimaryFactionID(), amount); } CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted an add faction spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_Stun: { if (IsClient()) { CastToClient()->Stun(base); } else if(IsNPC()) { //Yeahlight: NPC is immune to stun effects if(CastToNPC()->GetCannotBeStunned()) { if(caster->IsClient()) { caster->Message(RED, "Your target is immune to the stun portion of this effect"); } } else { CastToNPC()->Stun(base); } } CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a stun spell, amount: %i.", spell->GetSpellName(), base); break; } case SE_Charm: { //Yeahlight: Can only charm a non-pet and the caster may only have one pet if(this->GetOwner() == NULL && caster->GetPet() == NULL && caster != this) { //Yeahlight: Flag the NPC as a pet if(this->IsNPC()) { caster->SetPet(this); this->SetOwnerID(caster->GetID()); this->CastToNPC()->SetCharmed(true); this->SetPetOrder(SPO_Follow); if(caster->IsClient()) caster->CastToClient()->SendCharmPermissions(); this->CastToNPC()->WhipeHateList(); this->CastToNPC()->StartTaunting(); } else if(this->IsClient()) { if(caster->IsNPC()) { caster->SetPet(this); this->SetOwnerID(caster->GetID()); Mob* myTarget = caster->CastToNPC()->GetHateTop(); if(!myTarget) myTarget = caster->CastToMob(); this->SetTarget(myTarget); this->animation = 0; this->delta_heading = 0; this->delta_x = 0; this->delta_y = 0; this->delta_z = 0; this->SendPosUpdate(true, PC_UPDATE_RANGE, false); this->CastToClient()->charmPositionUpdate_timer->Start(200); this->CastToClient()->SetCharmed(true); this->SendAppearancePacket(this->GetID(), SAT_Position_Update, SAPP_Lose_Control, false); this->SetPetOrder(SPO_Follow); } else if(caster->IsClient()) { caster->SetPet(this); this->SetOwnerID(caster->GetID()); this->SetTarget(caster); this->animation = 0; this->delta_heading = 0; this->delta_x = 0; this->delta_y = 0; this->delta_z = 0; this->SendPosUpdate(true, PC_UPDATE_RANGE, false); this->CastToClient()->charmPositionUpdate_timer->Start(200); this->CastToClient()->SetCharmed(true); this->SendAppearancePacket(this->GetID(), SAT_Position_Update, SAPP_Lose_Control, false); this->SetPetOrder(SPO_Follow); caster->CastToClient()->SendCharmPermissions(); } } } CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a charm spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_Fear: { //Yeahlight: Victim is a PC if(this->IsClient()) { this->CastToClient()->SetFeared(true); this->SendAppearancePacket(this->GetID(), SAT_Position_Update, SAPP_Lose_Control, false); this->CastToClient()->GetFearDestination(GetX(), GetY(), GetZ()); } //Yeahlight: Victim is an NPC else if(this->IsNPC()) { this->CastToNPC()->SetFeared(true); } CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a fear spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_Stamina: { CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a stamina spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_BindAffinity: { //Yeahlight: Target of the bind affinity spell is a client if(this->IsClient()) { this->CastToClient()->SetBindPoint(); } CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a Bind Affinity spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_Gate: { if(IsClient()) CastToClient()->GoToBind(); CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a gate spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_CancelMagic: { for(int i = 0; i < 15; i++) { //Yeahlight: Buff must exist and the buff may not have any poison or disease counters if(buffs[i].spell && buffs[i].spell->IsValidSpell() && buffs[i].casterlevel <= (caster_level + base) && buffs[i].spell->GetDiseaseCounters() == 0 && buffs[i].spell->GetPoisonCounters() == 0) { this->BuffFadeBySlot(i, true); break; } } CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a cancel magic spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_InvisVsUndead: { this->SetInvisibleUndead(true); CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted an Invis VS Undead spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_InvisVsAnimals: { this->SetInvisibleAnimal(true); CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted an Invis VS Animal spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_Mez: { // Pinedepain // When a mezz spell is casted, we mesmerize this mob Mesmerize(); CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a mesmerize spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_SummonItem: { if(this->IsClient()) { if(amount == 0) this->CastToClient()->SummonItem(base, 1); else this->CastToClient()->SummonItem(base, (amount > 20) ? 20 : amount); } CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a summon item spell: %i.", spell->GetSpellName(), base); break; } case SE_NecPet: case SE_SummonPet: { if (this->GetPetID() != 0) { Message(RED, "You\'ve already got a pet."); break; } this->MakePet(teleport_zone); CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a Summon pet / nec pet spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_DivineAura: { this->SetInvulnerable(true); CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a Divine Aura, amount: %i.", spell->GetSpellName(), amount); break; } case SE_ShadowStep: { //Yeahlight: Handled client side CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a Shadow Step spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_Rune: { //Yeahlight: Flag entity with rune for damage calculations hasRuneOn = true; CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a Rune spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_Levitate: { this->SendAppearancePacket(0, SAT_Levitate, 2, true); CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a levitate spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_SummonCorpse: { bool permit = false; Mob* corpseOwner = target; //Yeahlight: The target of this spell is not a PC or the caster is targeting themself if(!target || (target && !target->IsClient()) || target == this) { corpseOwner = this; permit = true; } //Yeahlight: Can only summon a PC's corpse if(corpseOwner && corpseOwner->IsClient()) { //Yeahlight: PCs must be grouped to summon a corpse if(!permit) { Group* targetGroup = entity_list.GetGroupByClient(corpseOwner->CastToClient()); Group* myGroup = NULL; if(this->IsClient()) myGroup = entity_list.GetGroupByClient(this->CastToClient()); //Yeahlight: Caster is in a group and they share the same group as the target if(myGroup != NULL && myGroup == targetGroup) permit = true; } //Yeahlight: Caster may proceed with the summon if(permit) { Corpse *corpse = entity_list.GetCorpseByOwner(corpseOwner->CastToClient()); //Yeahlight: Corpse has been located if(corpse) { corpse->Summon(corpseOwner->CastToClient(), caster->CastToClient(), true); CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a summon corpse spell: %s.", spell->GetSpellName(), this->GetName()); } //Yeahlight: There is no corpse available else { //Yeahlight: Caster failed to locate his/her corpse if(caster == corpseOwner) { caster->Message(RED, "You do not have a corpse in this zone."); } //Yeahlight: Caster failed to locate their target's corpse else { caster->Message(RED, "Your target does not have a corpse in this zone."); } CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): Summon corpse: you can't sense the corpse: %i.", spell->GetSpellName()); } } else { //Yeahlight: TODO: This is not the correct message Message(RED, "You and your target must be in the same group to perform this action."); } } break; } case SE_Illusion: { SendIllusionPacket(base, GetDefaultGender(base, GetBaseGender()), GetTexture(), GetHelmTexture()); CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted an illusion spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_Identify: { //Yeahlight: Handled client side CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted an identify spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_WipeHateList: { //Yeahlight: NOTE: Do NOT wipe the rampage list here; that never goes away until the mob resets if(this->IsNPC()) { //Yeahlight: TODO: I don't remember this message, look into this entity_list.MessageClose(this, true, DEFAULT_MESSAGE_RANGE, DARK_BLUE, "My mind fogs. Who are my friends? Who are my enemies?... it was all so clear a moment ago..."); this->CastToNPC()->WhipeHateList(); CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a whipe hate list spell, amount: %i.", spell->GetSpellName(), amount); } break; } case SE_SpinTarget: { Spin(caster, spell); CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a spin target spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_EyeOfZomm: { //Yeahlignt: Only produce eyes of zomm for PCs if(this->IsClient()) { if(this->CastToClient()->myEyeOfZomm == 0) MakeEyeOfZomm(this); else Message(RED, "You may only have one eye of zomm out at a time!"); } CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a Eye Of Zomm spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_ReclaimPet: { //Yeahlight: Target of the spell is an uncharmed NPC, has an owner and the owner is the caster of the spell if(IsNPC() && CastToNPC()->IsCharmed() == false && GetOwnerID() && caster->GetID() == GetOwnerID()) { //Yeahlight: TODO: Research this formula caster->SetMana(caster->GetMana()+(GetLevel()*4)); if(caster->IsClient()) { caster->CastToClient()->SetPet(0); } SetOwnerID(0); } CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a reclaim pet spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_FeignDeath: { if(this->IsClient()) this->CastToClient()->FeignDeath(this->CastToClient()->GetSkill(ABJURATION)); break; } case SE_VoiceGraft: { //Yeahlight: Only allow voice graft to be casted on NPCs (we don't want PCs griefing other charmed PCs with /say) if(IsNPC() && caster->IsClient() && CastToNPC()->GetOwner() == caster) { caster->CastToClient()->SetVoiceGrafting(true); } CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a voice graft spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_Revive: { //Yeahlight: Handled in client_process.cpp CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a revive spell, amount: %i, corpse: %s.", spell->GetSpellName(), amount, this->GetName()); break; } case SE_Teleport: { char teleport_zone_char[64]; if(this->IsClient()) strcpy(teleport_zone_char, teleport_zone); this->CastToClient()->MovePC(teleport_zone_char, spell->GetSpellBase(1), spell->GetSpellBase(0), spell->GetSpellBase(2), false, false); CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a teleport spell to %s (%f, %f, %f).", spell->GetSpellName(), teleport_zone, spell->GetSpellBase(1), spell->GetSpellBase(0), spell->GetSpellBase(2)); break; } case SE_Translocate: { bool permit = false; Mob* translocatee = CastToMob(); //Enraged: The target of this spell is an NPC. //if(translocatee && !translocatee->IsClient()) //{ // //Enraged: TODO: This is not the correct message? // Message(RED, "You cannot cast that spell on your current target."); // break; //} //Enraged: The target of this spell is the caster. //TODO: Can players target themselves with translocate spells? if(translocatee && (translocatee == this)) permit = true; //Enraged: Check if the targetted client is in the casters group. //TODO: Translocate only worked on group players, right? if(!permit && translocatee) { Group* translocateeGroup = entity_list.GetGroupByClient(translocatee->CastToClient()); Group* casterGroup = NULL; if(this->IsClient()) casterGroup = entity_list.GetGroupByClient(this->CastToClient()); //Enraged: The translocatee is in a group and they share the same group as the target if(casterGroup != NULL && casterGroup == translocateeGroup) permit = true; } //Enraged: Target is clear to be translocated. if(permit) { CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a translocation spell on %s.", spell->GetSpellName(), translocatee->GetName()); //TODO: Translocate code here translocatee->CastToClient()->SendTranslocateConfirmation(caster, spell); } else { //The translocatee was not in the casters group. //Enraged: TODO: This is not the correct message Message(RED, "You can only cast that spell on players in your group."); } break; } case SE_InfraVision: //Yeahlight: Handled client side CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted an infravision spell, amount: %i.", spell->GetSpellName(), amount); break; case SE_UltraVision: //Yeahlight: Handled client side CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted an ultravision spell, amount: %i.", spell->GetSpellName(), amount); break; case SE_BindSight: CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a bind sight spell, amount: %i.", spell->GetSpellName(), amount); break; case SE_SeeInvis: SetCanSeeThroughInvis(true); CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a see invis spell, amount: %i.", spell->GetSpellName(), amount); break; case SE_WaterBreathing: //Yeahlight: Handled client side CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted an water breathing spell, amount: %i.", spell->GetSpellName(), amount); break; case SE_SenseDead: //Yeahlight: Handled client side CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a sense dead spell, amount: %i.", spell->GetSpellName(), amount); break; case SE_SenseSummoned: //Yeahlight: Handled client side CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a sense summoned spell, amount: %i.", spell->GetSpellName(), amount); break; case SE_TrueNorth: //Yeahlight: Handled client side CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a true north spell, amount: %i.", spell->GetSpellName(), amount); break; case SE_SenseAnimals: //Yeahlight: Handled client side CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a sense animals spell, amount: %i.", spell->GetSpellName(), amount); break; case SE_DamageShield: //Yeahlight: There should not be any work to be done here CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a damage shield spell, amount: %i.", spell->GetSpellName(), amount); break; case SE_Sentinel: CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a sentinel spell, amount: %i.", spell->GetSpellName(), amount); break; case SE_LocateCorpse: //Yeahlight: Handled client side CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a locate corpse spell, amount: %i.", spell->GetSpellName(), amount); break; case SE_ModelSize: { //Yeahlight: Grow/Shrink float newSize = (GetSize() * (float)base) / 100.00f; //Yeahlight: Size of a gnome (minimum) if(newSize < 3) newSize = 3; //Yeahlight: Size of an ogre (maximum) else if(newSize > 9) newSize = 9; this->size = newSize; this->SendAppearancePacket(GetID(), SAT_Size, GetSize(), true); CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a model size spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_Root: //Yeahlight: Handled client side CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a root spell, amount: %i.", spell->GetSpellName(), amount); break; case SE_Blind: //Yeahlight: Handled client side CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a blind spell, amount: %i.", spell->GetSpellName(), amount); break; case SE_DiseaseCounter: { //Yeahlight: Spell is a cure disease spell if(amount < 0) { //Yeahlight: Iterate through all the debuffs on the target and check for the chance to cure it for(int i = 0; i < 15; i++) { if(buffs[i].spell && buffs[i].diseasecounters) { buffs[i].diseasecounters = buffs[i].diseasecounters + amount; if(buffs[i].diseasecounters <= 0) BuffFadeBySlot(i, true); break; } } } CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a disease counter spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_PoisonCounter: { //Yeahlight: Spell is a cure poison spell if(amount < 0) { //Yeahlight: Iterate through all the debuffs on the target and check for the chance to cure it for(int i = 0; i < 15; i++) { if(buffs[i].spell && buffs[i].poisoncounters) { buffs[i].poisoncounters = buffs[i].poisoncounters + amount; if(buffs[i].poisoncounters <= 0) BuffFadeBySlot(i, true); break; } } } CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a poison counter spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_Calm: { //Yeahlight: Only add/remove hate from NPCs if(this->IsNPC()) { this->CastToNPC()->AddToHateList(caster, 0, amount); } CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a calm hate spell, amount: %i.", spell->GetSpellName(), amount); break; } case SE_WeaponProc: { Spell* spell = spells_handler.GetSpellPtr(base); //Yeahlight: Legit spell proc bonus found if(spell) SetBonusProcSpell(spell); CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell name = %s): Weapon proc bonus of spell ID %i.", spell->GetSpellName(), base); break; } case SE_StopRain: { zone->zone_weather = 0; zone->weatherSend(); CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::ApplySpellsBonuses(spell name = %s): You casted a stop rain spell, amount: %i.", spell->GetSpellName(), base); break; } case SE_CallOfHero: { //Yeahlight: Call of the Hero may only be used on PCs int32 zoneid = 0; if(this->IsClient()) this->CastToClient()->MovePC(zoneid, caster->GetX(), caster->GetY(), caster->GetZ(), false, true); else caster->Message(RED, "This spell may only be cast on players."); CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::ApplySpellsBonuses(spell name = %s): You casted a call of the hero spell, amount: %i.", spell->GetSpellName(), base); break; } case SE_CallPet: { //Yeahlight: This spell line may only be used on NPC pets if(GetPet() && GetPet()->IsNPC()) { GetPet()->CastToNPC()->GMMove(GetX(), GetY(), GetZ(), GetHeading()); GetPet()->pStandingPetOrder = SPO_Follow; } CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::ApplySpellsBonuses(spell name = %s): You casted a call pet spell, amount: %i.", spell->GetSpellName(), base); break; } case SE_DeathSave: { //Yeahlight: Only apply divine intervention to players if(this->IsClient()) { sint16 successChance = 0; float baseChance = 0.00f; switch(base) { //Yeahlight: Death Pact (CLR: 51) case 1: { baseChance = 0.10f; break; } //Yeahlight: Divine Intervention (CLR: 60) case 2: { baseChance = 0.30f; break; } default: { baseChance = 0.10f; } } //Yeahlight: The target's CHA is calculated into the bonus save chance successChance = (((float)CastToClient()->GetCHA() * 0.0005f) + baseChance) * 100; //Yeahlight: The worst possible save chance is the spell's base chance if(successChance < baseChance) successChance = baseChance; else if(successChance > 100) successChance = 100; this->CastToClient()->SetDeathSave(successChance); } CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::ApplySpellsBonuses(spell name = %s): You casted a death save spell, amount: %i.", spell->GetSpellName(), base); break; } case SE_Succor: { //Yeahlight: There should be nothing to do here CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::ApplySpellsBonuses(spell name = %s): You casted a succor spell, amount: %i.", spell->GetSpellName(), base); break; } case 0xFE: case 0xFF: case SE_Harmony: case SE_ChangeFrenzyRad: case SE_Lull: case SE_TotalHP: case SE_ArmorClass: case SE_MagnifyVision: case SE_ATK: case SE_STR: case SE_DEX: case SE_AGI: case SE_STA: case SE_INT: case SE_WIS: case SE_CHA: case SE_ResistFire: case SE_ResistCold: case SE_ResistPoison: case SE_ResistDisease: case SE_ResistMagic: { // Buffs are handeled elsewhere break; } default: { CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): unknown effect (%i) for amount: %i.", spell->GetSpellName(), effect_id, amount); break; } } } if(this->IsClient()) this->CastToClient()->Save(); }
//we need this function to immediately determine, after we receive OP_Fishing, if we can even try to fish, otherwise we have to wait a while to get the failure bool Client::CanFish() { //make sure we still have a fishing pole on: const ItemInst* Pole = m_inv[SlotPrimary]; int32 bslot = m_inv.HasItemByUse(ItemTypeFishingBait, 1, invWhereWorn|invWherePersonal); const ItemInst* Bait = nullptr; if (bslot != INVALID_INDEX) Bait = m_inv.GetItem(bslot); if(!Pole || !Pole->IsType(ItemClassCommon) || Pole->GetItem()->ItemType != ItemTypeFishingPole) { if (m_inv.HasItemByUse(ItemTypeFishingPole, 1, invWhereWorn|invWherePersonal|invWhereBank|invWhereSharedBank|invWhereTrading|invWhereCursor)) //We have a fishing pole somewhere, just not equipped Message_StringID(MT_Skills, FISHING_EQUIP_POLE); //You need to put your fishing pole in your primary hand. else //We don't have a fishing pole anywhere Message_StringID(MT_Skills, FISHING_NO_POLE); //You can't fish without a fishing pole, go buy one. return false; } if (!Bait || !Bait->IsType(ItemClassCommon) || Bait->GetItem()->ItemType != ItemTypeFishingBait) { Message_StringID(MT_Skills, FISHING_NO_BAIT); //You can't fish without fishing bait, go buy some. return false; } if(zone->zonemap != nullptr && zone->watermap != nullptr && RuleB(Watermap, CheckForWaterWhenFishing)) { glm::vec3 rodPosition; // Tweak Rod and LineLength if required const float RodLength = RuleR(Watermap, FishingRodLength); const float LineLength = RuleR(Watermap, FishingLineLength); int HeadingDegrees; HeadingDegrees = (int) ((GetHeading()*360)/256); HeadingDegrees = HeadingDegrees % 360; rodPosition.x = m_Position.x + RodLength * sin(HeadingDegrees * M_PI/180.0f); rodPosition.y = m_Position.y + RodLength * cos(HeadingDegrees * M_PI/180.0f); rodPosition.z = m_Position.z; float bestz = zone->zonemap->FindBestZ(rodPosition, nullptr); float len = m_Position.z - bestz; if(len > LineLength || len < 0.0f) { Message_StringID(MT_Skills, FISHING_LAND); return false; } float step_size = RuleR(Watermap, FishingLineStepSize); for(float i = 0.0f; i < len; i += step_size) { glm::vec3 dest(rodPosition.x, rodPosition.y, m_Position.z - i); bool in_lava = zone->watermap->InLava(dest); bool in_water = zone->watermap->InWater(dest) || zone->watermap->InVWater(dest); if (in_lava) { Message_StringID(MT_Skills, FISHING_LAVA); //Trying to catch a fire elemental or something? return false; } if(in_water) { return true; } } Message_StringID(MT_Skills, FISHING_LAND); return false; } return true; }
void Client::GoFish() { //TODO: generate a message if we're already fishing /*if (!fishing_timer.Check()) { //this isn't the right check, may need to add something to the Client class like 'bool is_fishing' Message_StringID(0, ALREADY_FISHING); //You are already fishing! return; }*/ fishing_timer.Disable(); //we're doing this a second time (1st in Client::Handle_OP_Fishing) to make sure that, between when we started fishing & now, we're still able to fish (in case we move, change equip, etc) if (!CanFish()) //if we can't fish here, we don't need to bother with the rest return; //multiple entries yeilds higher probability of dropping... uint32 common_fish_ids[MAX_COMMON_FISH_IDS] = { 1038, // Tattered Cloth Sandals 1038, // Tattered Cloth Sandals 1038, // Tattered Cloth Sandals 13019, // Fresh Fish 13076, // Fish Scales 13076, // Fish Scales 7007, // Rusty Dagger 7007, // Rusty Dagger 7007 // Rusty Dagger }; //success formula is not researched at all int fishing_skill = GetSkill(SkillFishing); //will take into account skill bonuses on pole & bait //make sure we still have a fishing pole on: int32 bslot = m_inv.HasItemByUse(ItemTypeFishingBait, 1, invWhereWorn|invWherePersonal); const ItemInst* Bait = nullptr; if (bslot != INVALID_INDEX) Bait = m_inv.GetItem(bslot); //if the bait isnt equipped, need to add its skill bonus if(bslot >= EmuConstants::GENERAL_BEGIN && Bait->GetItem()->SkillModType == SkillFishing) { fishing_skill += Bait->GetItem()->SkillModValue; } if (fishing_skill > 100) { fishing_skill = 100+((fishing_skill-100)/2); } if (zone->random.Int(0,175) < fishing_skill) { uint32 food_id = 0; //25% chance to fish an item. if (zone->random.Int(0, 399) <= fishing_skill ) { uint32 npc_id = 0; uint8 npc_chance = 0; food_id = database.GetZoneFishing(m_pp.zone_id, fishing_skill, npc_id, npc_chance); //check for add NPC if(npc_chance > 0 && npc_id) { if(npc_chance < zone->random.Int(0, 99)) { const NPCType* tmp = database.GetNPCType(npc_id); if(tmp != nullptr) { NPC* npc = new NPC(tmp, nullptr, GetX()+3, GetY(), GetZ(), GetHeading(), FlyMode3); npc->AddLootTable(); npc->AddToHateList(this, 1, 0, false); //no help yelling entity_list.AddNPC(npc); Message(MT_Emote, "You fish up a little more than you bargained for..."); } } } } //consume bait, should we always consume bait on success? DeleteItemInInventory(bslot, 1, true); //do we need client update? if(food_id == 0) { int index = zone->random.Int(0, MAX_COMMON_FISH_IDS-1); food_id = common_fish_ids[index]; } const Item_Struct* food_item = database.GetItem(food_id); Message_StringID(MT_Skills, FISHING_SUCCESS); ItemInst* inst = database.CreateItem(food_item, 1); if(inst != nullptr) { if(CheckLoreConflict(inst->GetItem())) { Message_StringID(0, DUP_LORE); safe_delete(inst); } else { PushItemOnCursor(*inst); SendItemPacket(MainCursor, inst, ItemPacketSummonItem); if(RuleB(TaskSystem, EnableTaskSystem)) UpdateTasksForItem(ActivityFish, food_id); safe_delete(inst); inst = m_inv.GetItem(MainCursor); } if(inst) { std::vector<EQEmu::Any> args; args.push_back(inst); parse->EventPlayer(EVENT_FISH_SUCCESS, this, "", inst->GetID(), &args); } } } else { //chance to use bait when you dont catch anything... if (zone->random.Int(0, 4) == 1) { DeleteItemInInventory(bslot, 1, true); //do we need client update? Message_StringID(MT_Skills, FISHING_LOST_BAIT); //You lost your bait! } else { if (zone->random.Int(0, 15) == 1) //give about a 1 in 15 chance to spill your beer. we could make this a rule, but it doesn't really seem worth it //TODO: check for & consume an alcoholic beverage from inventory when this triggers, and set it as a rule that's disabled by default Message_StringID(MT_Skills, FISHING_SPILL_BEER); //You spill your beer while bringing in your line. else Message_StringID(MT_Skills, FISHING_FAILED); //You didn't catch anything. } parse->EventPlayer(EVENT_FISH_FAILURE, this, "", 0); } //chance to break fishing pole... //this is potentially exploitable in that they can fish //and then swap out items in primary slot... too lazy to fix right now if (zone->random.Int(0, 49) == 1) { Message_StringID(MT_Skills, FISHING_POLE_BROKE); //Your fishing pole broke! DeleteItemInInventory(MainPrimary, 0, true); } if(CheckIncreaseSkill(SkillFishing, nullptr, 5)) { if(title_manager.IsNewTradeSkillTitleAvailable(SkillFishing, GetRawSkill(SkillFishing))) NotifyNewTitlesAvailable(); } }
// solar: if lifetime is 0 this is a permanent beacon.. not sure if that'll be // useful for anything Beacon::Beacon(Mob *at_mob, int lifetime) :Mob ( NULL, NULL, 0, 0, 0, INVISIBLE_MAN, 0, BT_NoTarget, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), remove_timer(lifetime), spell_timer(0) { remove_timer.Disable(); spell_timer.Disable(); remove_me = false; spell_id = 0xFFFF; resist_adjust = 0; spell_iterations = 0; caster_id = 0; // copy location x_pos = at_mob->GetX(); y_pos = at_mob->GetY(); z_pos = at_mob->GetZ(); heading = at_mob->GetHeading(); if(lifetime) { remove_timer.Start(); } #ifdef SOLAR entity_list.Message(0, 0, "Beacon being created at %0.2f %0.2f %0.2f heading %0.2f lifetime %d", GetX(), GetY(), GetZ(), GetHeading(), lifetime); #endif }
Beacon::~Beacon() { #ifdef SOLAR entity_list.Message(0, 0, "Beacon %d being removed at %0.2f %0.2f %0.2f heading %0.2f", GetID(), GetX(), GetY(), GetZ(), GetHeading()); #endif }