Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CAPI
2 changes: 1 addition & 1 deletion SDK
15 changes: 11 additions & 4 deletions Server/Components/CAPI/Impl/NPCs/APIs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@
#include "../ComponentManager.hpp"
#include <Server/Components/NPCs/npcs.hpp>

OMP_CAPI(NPC_Create, objectPtr(const char* name))
OMP_CAPI(NPC_Create, objectPtr(StringCharPtr name, int* id))
{
COMPONENT_CHECK_RET(npcs, nullptr);
if (name)
{
auto npc = npcs->create(name);
if (npc)
{
*id = npc->getID();
return npc;
}
}
Expand Down Expand Up @@ -48,6 +49,12 @@ OMP_CAPI(NPC_IsValid, bool(objectPtr npc))
return npcs->get(npc_->getID()) != nullptr;
}

OMP_CAPI(NPC_GetPlayer, objectPtr(objectPtr npc))
{
POOL_ENTITY_RET(npcs, INPC, npc, npc_, nullptr);
return npc_->getPlayer();
}

OMP_CAPI(NPC_Spawn, bool(objectPtr npc))
{
POOL_ENTITY_RET(npcs, INPC, npc, npc_, false);
Expand Down Expand Up @@ -782,7 +789,7 @@ OMP_CAPI(NPC_GetAnimation, bool(objectPtr npc, int* animationId, float* delta, b
return true;
}

OMP_CAPI(NPC_ApplyAnimation, bool(objectPtr npc, const char* animlib, const char* animname, float delta, bool loop, bool lockX, bool lockY, bool freeze, int time))
OMP_CAPI(NPC_ApplyAnimation, bool(objectPtr npc, StringCharPtr animlib, StringCharPtr animname, float delta, bool loop, bool lockX, bool lockY, bool freeze, int time))
{
POOL_ENTITY_RET(npcs, INPC, npc, npc_, false);
if (!animlib || !animname)
Expand Down Expand Up @@ -814,7 +821,7 @@ OMP_CAPI(NPC_GetSpecialAction, int(objectPtr npc))
return npc_->getSpecialAction();
}

OMP_CAPI(NPC_StartPlayback, bool(objectPtr npc, const char* recordName, bool autoUnload, float startPosX, float startPosY, float startPosZ, float startRotX, float startRotY, float startRotZ))
OMP_CAPI(NPC_StartPlayback, bool(objectPtr npc, StringCharPtr recordName, bool autoUnload, float startPosX, float startPosY, float startPosZ, float startRotX, float startRotY, float startRotZ))
{
POOL_ENTITY_RET(npcs, INPC, npc, npc_, false);
if (!recordName)
Expand Down Expand Up @@ -856,7 +863,7 @@ OMP_CAPI(NPC_IsPlaybackPaused, bool(objectPtr npc))
return npc_->isPlaybackPaused();
}

OMP_CAPI(NPC_LoadRecord, int(const char* filePath))
OMP_CAPI(NPC_LoadRecord, int(StringCharPtr filePath))
{
COMPONENT_CHECK_RET(npcs, -1);
if (filePath)
Expand Down
36 changes: 26 additions & 10 deletions Server/Components/NPCs/NPC/npc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ NPC::NPC(NPCComponent* component, IPlayer* playerPtr)
, aimOffsetFrom_({ 0.0f, 0.0f, 0.0f })
, aimOffset_({ 0.0f, 0.0f, 0.0f })
, updateAimAngle_(false)
, playerAimingAt_(nullptr)
, betweenCheckFlags_(EntityCheckType::None)
, hitId_(0)
, hitType_(PlayerBulletHitType_None)
Expand Down Expand Up @@ -507,6 +508,11 @@ bool NPC::isMoving() const
return moving_;
}

bool NPC::isMovingToPlayer(IPlayer& player) const
{
return followingPlayer_ != nullptr;
}

void NPC::setSkin(int model)
{
player_->setSkin(model);
Expand Down Expand Up @@ -1153,24 +1159,22 @@ void NPC::aimAt(const Vector3& point, bool shoot, int shootDelay, bool setAngle,
return;
}

// Set the aiming flag
if (!aiming_)
if (aiming_)
{
// Get the shooting start tick
shootUpdateTime_ = lastUpdate_;
reloading_ = false;
stopAim();
}

// Get the shooting start tick
shootUpdateTime_ = lastUpdate_;
reloading_ = false;

// Update aiming data
aimOffsetFrom_ = offsetFrom;
updateAimData(point, setAngle);

// Set keys
if (!aiming_)
{
aiming_ = true;
applyKey(Key::AIM);
}
applyKey(Key::AIM);
aiming_ = true;

// Set the shoot delay
auto updateRate = npcComponent_->getGeneralNPCUpdateRate();
Expand All @@ -1196,6 +1200,7 @@ void NPC::aimAtPlayer(IPlayer& atPlayer, bool shoot, int shootDelay, bool setAng
hitId_ = atPlayer.getID();
hitType_ = PlayerBulletHitType_Player;
aimOffset_ = offset;
playerAimingAt_ = &atPlayer;
}

void NPC::stopAim()
Expand All @@ -1219,6 +1224,7 @@ void NPC::stopAim()
hitType_ = PlayerBulletHitType_None;
updateAimAngle_ = false;
betweenCheckFlags_ = EntityCheckType::None;
playerAimingAt_ = nullptr;

// Reset keys
removeKey(Key::AIM);
Expand Down Expand Up @@ -1878,6 +1884,16 @@ void NPC::updateWeaponState()
}
}

IPlayer* NPC::getPlayerAimingAt()
{
return playerAimingAt_;
}

IPlayer* NPC::getPlayerMovingTo()
{
return followingPlayer_;
}

void NPC::kill(IPlayer* killer, uint8_t weapon)
{
if (dead_)
Expand Down
15 changes: 11 additions & 4 deletions Server/Components/NPCs/NPC/npc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ class NPC : public INPC, public PoolIDProvider, public NoCopy

bool isMoving() const override;

bool isMovingToPlayer(IPlayer& player) const override;

void setSkin(int model) override;

bool isStreamedInForPlayer(const IPlayer& other) const override;
Expand Down Expand Up @@ -112,6 +114,8 @@ class NPC : public INPC, public PoolIDProvider, public NoCopy

PlayerWeaponState getWeaponState() const override;

void setWeaponState(PlayerWeaponState state) override;

void setAmmoInClip(int ammo) override;

int getAmmoInClip() const override;
Expand Down Expand Up @@ -246,16 +250,18 @@ class NPC : public INPC, public PoolIDProvider, public NoCopy

void resetSurfingData() override;

void kill(IPlayer* killer, uint8_t weapon) override;

IPlayer* getPlayerAimingAt() override;

IPlayer* getPlayerMovingTo() override;

void setAnimation(uint16_t animationId, uint16_t flags);

void processPlayback(TimePoint now);

void setWeaponState(PlayerWeaponState state);

void updateWeaponState();

void kill(IPlayer* killer, uint8_t weapon);

void processDamage(IPlayer* damager, float damage, uint8_t weapon, BodyPart bodyPart, bool handleHealthAndArmour);

void updateAim();
Expand Down Expand Up @@ -465,6 +471,7 @@ class NPC : public INPC, public PoolIDProvider, public NoCopy
Vector3 aimOffsetFrom_;
Vector3 aimOffset_;
bool updateAimAngle_;
IPlayer* playerAimingAt_;

// Weapon raycast/shot checks data
EntityCheckType betweenCheckFlags_;
Expand Down
2 changes: 0 additions & 2 deletions Server/Components/NPCs/Playback/playback.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ struct NPCRecord
DynamicArray<NetCode::Packet::PlayerVehicleSync> vehicleData;
};

constexpr int INVALID_RECORD_ID = -1;

class NPC;
class NPCRecordManager;

Expand Down
7 changes: 6 additions & 1 deletion Server/Components/NPCs/npcs_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,11 @@ void NPCComponent::onPoolEntryDestroyed(IPlayer& player)
npc->stopMove();
npc->resetFollowingPlayer();
}

if (npc->isAiming() && npc->isAimingAtPlayer(player))
{
npc->stopAim();
}
}
}

Expand Down Expand Up @@ -284,7 +289,7 @@ void NPCComponent::destroy(INPC& npc)
int NPCComponent::createPath()
{
NPCPath* path = pathManager_.create();
return path ? path->getID() : -1;
return path ? path->getID() : INVALID_PATH_ID;
}

bool NPCComponent::destroyPath(int pathId)
Expand Down
69 changes: 67 additions & 2 deletions Server/Components/Pawn/Scripting/NPC/Natives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,27 @@ SCRIPT_API(NPC_IsMoving, bool(INPC& npc))
return npc.isMoving();
}

SCRIPT_API(NPC_IsMovingToPlayer, bool(INPC& npc, IPlayer& player))
{
return npc.isMovingToPlayer(player);
}

SCRIPT_API(NPC_SetSkin, bool(INPC& npc, int model))
{
npc.setSkin(model);
return true;
}

SCRIPT_API(NPC_GetSkin, bool(INPC& npc))
{
auto player = npc.getPlayer();
if (player)
{
return player->getSkin();
}
return -1;
}

SCRIPT_API(NPC_IsStreamedIn, bool(INPC& npc, IPlayer& player))
{
return npc.isStreamedInForPlayer(player);
Expand Down Expand Up @@ -932,15 +947,15 @@ SCRIPT_API(NPC_IsInvulnerable, bool(INPC& npc))
return npc.isInvulnerable();
}

SCRIPT_API(NPC_SetSurfingOffset, bool(INPC& npc, Vector3 offset))
SCRIPT_API(NPC_SetSurfingOffsets, bool(INPC& npc, Vector3 offset))
{
auto data = npc.getSurfingData();
data.offset = offset;
npc.setSurfingData(data);
return true;
}

SCRIPT_API(NPC_GetSurfingOffset, bool(INPC& npc, Vector3& offset))
SCRIPT_API(NPC_GetSurfingOffsets, bool(INPC& npc, Vector3& offset))
{
auto data = npc.getSurfingData();
offset = data.offset;
Expand Down Expand Up @@ -1023,3 +1038,53 @@ SCRIPT_API(NPC_ResetSurfingData, bool(INPC& npc))
npc.resetSurfingData();
return true;
}

SCRIPT_API(NPC_IsSpawned, bool(INPC& npc))
{
auto player = npc.getPlayer();
if (player)
{
auto state = player->getState();
if (state == PlayerState_OnFoot || state == PlayerState_Driver || state == PlayerState_Passenger || state == PlayerState_Spawned)
{
return true;
}
}
return false;
}

SCRIPT_API(NPC_Kill, bool(INPC& npc, IPlayer* killer, int reason))
{
npc.kill(killer, reason);
return true;
}

SCRIPT_API(NPC_SetVelocity, bool(INPC& npc, Vector3 velocity))
{
npc.setVelocity(velocity, true);
return true;
}

SCRIPT_API(NPC_GetVelocity, bool(INPC& npc, Vector3& velocity))
{
velocity = npc.getVelocity();
return true;
}

SCRIPT_API(NPC_GetPlayerAimingAt, int(INPC& npc))
{
auto player = npc.getPlayerAimingAt();
return player ? player->getID() : INVALID_PLAYER_ID;
}

SCRIPT_API(NPC_GetPlayerMovingTo, int(INPC& npc))
{
auto player = npc.getPlayerMovingTo();
return player ? player->getID() : INVALID_PLAYER_ID;
}

SCRIPT_API(NPC_SetWeaponState, bool(INPC& npc, int weaponState))
{
npc.setWeaponState(PlayerWeaponState(weaponState));
return true;
}
Loading