'NPC' that upon use will say it's unique name.

A place for requesting new Source.Python plugins to be made for your server.

Please request only one plugin per thread.
User avatar
Grubbsy
Junior Member
Posts: 12
Joined: Sat Aug 29, 2020 10:12 pm

'NPC' that upon use will say it's unique name.

Postby Grubbsy » Sat Aug 29, 2020 10:41 pm

I've been trying to get an NPC for CSGO trade servers done for some time, and I've always run into issues,
- This is for CSGO, Essentially I was thinking it would utilize an extension of the entity's class to store its name
- then using any model really but for this, I'd be using player models, also please use prop_physics_overrides.

(I want to give NPCs names like Bob or Joe)

I appreciate any help I can get! Thanks, and good luck! - Grubbsy
User avatar
VinciT
Senior Member
Posts: 331
Joined: Thu Dec 18, 2014 2:41 am

Re: 'NPC' that upon use will say it's unique name.

Postby VinciT » Sun Aug 30, 2020 4:17 am

Hi Grubbsy! Seeing as this is your first post, I'd like to welcome you to the Source.Python community! :smile:
The following snippet should achieve what you're looking for:

Syntax: Select all

# ../named_npc/named_npc.py

# Python
import random

# Source.Python
from commands import CommandReturn
from commands.client import ClientCommand
from engines.precache import Model
from engines.sound import Sound
from entities.constants import SolidType
from entities.datamaps import InputData
from entities.entity import BaseEntity, Entity
from entities.helpers import index_from_pointer
from entities.hooks import EntityCondition, EntityPreHook
from listeners import OnEntityDeleted
from mathlib import NULL_QANGLE, QAngle
from messages import SayText2
from players.entity import Player


NPC_MODELS = (
Model('models/player/custom_player/legacy/ctm_fbi_varianta.mdl'),
Model('models/player/custom_player/legacy/ctm_fbi_variantb.mdl'),
Model('models/player/custom_player/legacy/ctm_fbi_variantc.mdl'),
Model('models/player/custom_player/legacy/ctm_fbi_variantd.mdl')
)

# Animation sequences that the NPCs will use as their pose after spawning.
NPC_SEQUENCES = (37, 65, 194, 203, 204, 211, 223)


CHAT_SEND_SOUND = Sound('common/talk.wav', volume=0.8)


is_prop_physics_override = EntityCondition.equals_entity_classname(
'prop_physics_override')


named_npc_instances = {}


def unload():
"""Called when the plugin gets unloaded."""
# Remove all the NPCs.
for npc in named_npc_instances.copy().values():
npc.remove()


class NamedNPC(Entity):
"""Extended Entity class."""

def __init__(self, index, caching=True):
"""Initializes the object."""
super().__init__(index, caching)

self.name = None
# Add the NamedNPC instance to the dictionary.
named_npc_instances[index] = self

@classmethod
def create(cls, name, origin, model, angles=NULL_QANGLE):
"""Creates a 'prop_physics_override' entity to act as an NPC.

Args:
name (str): Name of the NPC.
origin (Vector): Location where the NPC will spawn.
model (Model): Precached model which will define the look of the
NPC.
angle (QAngle): Rotation of the NPC upon spawning.
"""
npc = cls(BaseEntity.create('prop_physics_override').index)
npc.name = name
npc.origin = origin
npc.model = model
npc.angles = angles
# Set certain spawn flags for the entity.
# 8: Freeze the entity in place.
# 256: Generate output on +USE.
npc.spawn_flags = 8 + 256
npc.spawn()
# Make sure the 'prop_physics_override' uses its bounding box for
# collision. This is a fix for player models. Without this you'd have
# to aim at the model's feet to trigger the +USE output.
npc.solid_type = SolidType.BBOX
# Pick a random pose for the model.
npc.set_network_property_uchar(
'm_nSequence', random.choice(NPC_SEQUENCES))

return npc

def on_player_interaction(self, player):
"""Called when a player presses +USE (E by default) on the NPC."""
# Greet the player.
SayText2(f'\x10{self.name} : \x01Hello there {player.name}!').send()
# Emulate the chat message sound.
CHAT_SEND_SOUND.play()


@OnEntityDeleted
def on_entity_deleted(base_entity):
"""Called when an entity gets deleted."""
try:
# Does this BaseEntity have an index (is it networked)?
index = base_entity.index
except ValueError:
return

try:
# Is this one of our NamedNPCs? If so, remove it from the dictionary.
named_npc_instances.pop(index)
except KeyError:
# Nope, moving on..
pass


@EntityPreHook(is_prop_physics_override, 'use')
def use_pre(stack_data):
index = index_from_pointer(stack_data[0])

try:
# Is this a NamedNPC instance?
npc = named_npc_instances[index]
except KeyError:
return

# Get the InputData object so we can see who pressed +USE on the NPC.
input_data = InputData._obj(stack_data[1])
# Notify the NPC that a player pressed +USE on it.
npc.on_player_interaction(Player(input_data.activator.index))


@ClientCommand('create_named_npc')
def create_named_npc_cmd(command, index):
# If something was typed after 'create_named_npc', use it as the name of
# the NPC, otherwise default to 'John Doe'.
name = command.arg_string if len(command) > 1 else 'John Doe'
# Get the Player that used the command.
player = Player(index)

# Get the direction from the origin of the NPC towards the player.
from_origin = player.origin - player.view_coordinates
# Normalize the vector.
# Vector(345.14, 192.75, -8.35) -> Vector(0.87, 0.48, -0.02)
from_origin.normalize()
# To avoid tilting the model, zero the Z (roll) axis.
from_origin.z = 0

# Convert the directional vector into a QAngle object. This will make the
# NPC face the player when it's spawned.
npc_angles = QAngle()
from_origin.get_vector_angles(npc_angles)

# Finally, create the NamedNPC.
NamedNPC.create(
name=name,
origin=player.view_coordinates,
# Pick a random player model.
model=random.choice(NPC_MODELS),
angles=npc_angles
)

# Stop the 'Unknown command: create_named_npc' message from showing up in
# the player's console after using the command.
return CommandReturn.BLOCK

I've added a simple command to illustrate how the extended class works. To create an NPC, simply look somewhere on the ground and type create_named_npc in your console. If you wish to create an NPC with a custom name (the default name is John Doe), just type the name after the command:

Code: Select all

create_named_npc James Bond
ImageImageImageImageImage
User avatar
Grubbsy
Junior Member
Posts: 12
Joined: Sat Aug 29, 2020 10:12 pm

Re: 'NPC' that upon use will say it's unique name.

Postby Grubbsy » Sun Aug 30, 2020 1:14 pm

Thank you so much, it works perfectly! I love what you did with the random models and sequences.

I also thank you for the warm welcome, I've been lurking here using anything I can for help that's already here on the forums lol.
User avatar
VinciT
Senior Member
Posts: 331
Joined: Thu Dec 18, 2014 2:41 am

Re: 'NPC' that upon use will say it's unique name.

Postby VinciT » Sun Aug 30, 2020 9:23 pm

Awesome! Glad I could help.
Grubbsy wrote:I also thank you for the warm welcome, I've been lurking here using anything I can for help that's already here on the forums lol.
I know the feeling, I'm usually a lurker myself (plus the forums are chock full of useful information).
ImageImageImageImageImage

Return to “Plugin Requests”

Who is online

Users browsing this forum: No registered users and 27 guests