Skip to content
RustPluginGenerator

OnNpcConversationRespond

OnNpcConversationRespond is called on the server when a player presses a response option in an NPC conversation, just before the game evaluates that response's conditions and runs its actions.

Signature
object OnNpcConversationRespond(NPCTalking nPCTalking, BasePlayer player, ConversationData conversationFor, ConversationData.ResponseNode responseNode)

Parameters

Hook parameters
ParameterTypeDescription
nPCTalkingNPCTalkingThe NPC entity that owns the conversation UI (typically a shopkeeper or mission NPC). Use it to read position, net ID, or nearby players.
playerBasePlayerThe BasePlayer who pressed a response button in the NPC conversation. Null-check it before sending chat or granting items.
conversationForConversationDataThe ConversationData the dialogue belongs to. Useful for identifying the conversation in general terms.
responseNodeConversationData.ResponseNodeThe specific ConversationData.ResponseNode the player selected, including its index among the NPC's responses. Use it to branch on which option was clicked.

Return value

Returning a non-null object short-circuits Server_ResponsePressed, so the response's conditions are not evaluated and no mission, item, or follow-up action is performed. Returning null lets the game continue with normal processing of the selected response.

How it works

This hook fires inside NPCTalking.Server_ResponsePressed, after the game resolves which response node the player chose (abstractSpeechNodeData.responses[num2]) and assigns it to responseNode. It runs before the response's conditions array is checked and before any mission assignment, item give, or follow-up speech the response would trigger. That timing makes it a gate: you see the player, the NPC, the conversation, and the exact response node, and you can stop everything downstream.

nPCTalking is the NPC entity, so you can reject responses when the player is too far away or the NPC is busy. player is the responding player. conversationFor identifies the conversation, and responseNode identifies the specific option, which is what you usually branch on (for example by its title text or position in the response list).

Because the game passes an NPCTalking argument, declaring the parameter as a broader type such as BaseEntity still matches, but you then cannot call conversation-specific members without a cast. Oxide only calls your method when every argument fits the declared parameter type, so a more specific parameter type is fine here.

Example plugin: Block NPC shop responses while the player is in combat

NpcConversationGuard.cs
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("Npc Conversation Guard", "RustPluginGenerator", "1.0.0")]
    [Description("Blocks NPC conversation responses while the player is in combat or low on health.")]
    public class NpcConversationGuard : RustPlugin
    {
        private const string PermBypass = "npcconversationguard.bypass";

        private PluginConfig config;
        private readonly Dictionary<ulong, float> lastDamage = new Dictionary<ulong, float>();

        private class PluginConfig
        {
            [JsonProperty("Combat block seconds")]
            public float CombatSeconds = 10f;

            [JsonProperty("Minimum health to respond")]
            public float MinHealth = 0f;
        }

        protected override void LoadDefaultConfig() => config = new PluginConfig();

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                config = Config.ReadObject<PluginConfig>();
                if (config == null) throw new Exception();
            }
            catch
            {
                PrintWarning("Configuration file is invalid, using defaults");
                LoadDefaultConfig();
            }
            SaveConfig();
        }

        protected override void SaveConfig() => Config.WriteObject(config);

        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                ["Blocked"] = "You cannot use this NPC while in combat. Wait {0} more seconds.",
                ["LowHealth"] = "Your health is too low to respond to this NPC."
            }, this);
        }

        private string Msg(string key, string userId = null, params object[] args) => string.Format(lang.GetMessage(key, this, userId), args);

        private void Init()
        {
            permission.RegisterPermission(PermBypass, this);
        }

        private void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info)
        {
            if (entity == null || info == null) return;
            var player = entity as BasePlayer;
            if (player == null || player.IsNpc) return;
            lastDamage[player.userID] = UnityEngine.Time.realtimeSinceStartup;
        }

        private object OnNpcConversationRespond(NPCTalking nPCTalking, BasePlayer player, ConversationData conversationFor, ConversationData.ResponseNode responseNode)
        {
            if (player == null || player.IsNpc) return null;
            if (permission.UserHasPermission(player.UserIDString, PermBypass)) return null;

            float remaining;
            if (lastDamage.TryGetValue(player.userID, out var stamp))
            {
                remaining = config.CombatSeconds - (UnityEngine.Time.realtimeSinceStartup - stamp);
                if (remaining > 0f)
                {
                    player.ChatMessage(Msg("Blocked", player.UserIDString, Mathf.CeilToInt(remaining)));
                    return true;
                }
            }

            if (config.MinHealth > 0f && player.health < config.MinHealth)
            {
                player.ChatMessage(Msg("LowHealth", player.UserIDString));
                return true;
            }

            return null;
        }

        private void Unload()
        {
            lastDamage.Clear();
        }
    }
}

The plugin caches the player's last damage time by listening to OnEntityTakeDamage for BasePlayer victims. In OnNpcConversationRespond, it checks the responder: if they took damage within the configured window (or have less than the configured minimum health), the response is cancelled and a language message is sent telling them to wait. Because the hook returns a non-null value, the game never evaluates the response's conditions or grants the shop item. config.json exposes the combat window in seconds and the minimum health threshold, both loaded through the standard Oxide configuration override.

Common use cases

  • Block conversations during combat

    Deny NPC responses when the player was recently hurt, so shops and missions cannot be used as a safe mid-fight.

  • Restrict access by location

    Cancel responses if the player moved away from the NPC's position, preventing players from completing remote dialogue triggers.

  • Gate special options on permissions

    Inspect the response node and block it unless the player holds a specific permission, effectively whitelisting premium mission lines.

Pitfalls

  • Cancelling without feedback

    A non-null return silently discards the click; without a chat or lang message the player just sees nothing happen and may spam the option.

  • Assuming the node contents

    Response nodes vary between conversations; do not depend on a specific index being present in every ConversationData, always bounds-check responses before branching.

  • Heavy work inside the hook

    This runs on the main thread per click; keep it to simple checks and avoid spawning entities or running queries that could stall the NPC dialogue.

Build a plugin with OnNpcConversationRespond

Describe what should happen and get a compiled plugin that uses this hook.

Prompt: Block conversations during combat using the OnNpcConversationRespond hook, with a config file and a permission
Generate this plugin

Edit the prompt on the next screen. 2 free plugins a month, no card.

Last updated Oct 26, 2026. Found a mistake? Email support@rustplugingenerator.com.

Build a plugin with OnNpcConversationRespond

Generate