✓ Accepted answer
Problems:
- Try never to have that many
.Parents in a row -- it's highly error prone. In this case, I can't tell what you're trying to Destroy, and it almost certainly isn't what you want.
- You only access the first DialogChoice before trying to access ChoiceA, but you have several in your hierarchy. You need to get the bottom DialogChoice, not the top. (I will demonstrate below how to do this.)
- Consider assigning things to local variables (like choiceA) at the beginning of your script so that you don't have long chains of "this.that.other". It makes it easier to follow.
- Due to a long-standing bug, DialogChoiceSelected only works on the client. You appear to be trying to do this, but your script needs to be a LocalScript in a place where LocalScripts run.
- The whole point of FilteringEnabled is to try and stop exploiters/hackers from messing up your game. However, it has weaknesses -- exploiters can have full control over their own client, allowing them to activate arbitrary scripts. Most of what the script does will not replicate to the server, but the following does:
- RemoteEvent/RemoteFunction calls. If their script activates a RemoteEvent/RemoteFunction, Roblox cannot tell the difference between a legitimate use and an illegitimate one. For example, a person could call "AddEXP" to give any player any amount of XP (or, as hiimgoodpack mentions, to take it all away). (Note that you needn't pass in the player when calling a RemoteEvent/RemoteFunction because this is done automatically and safely by Roblox -- the first argument you receive on the server is always the player who sent in the request).
- Character animations/position. Players can use this to teleport their player, move their player more quickly than they should, jump in mid-air, etc.
- Any unanchored parts that are "owned" by the client (see NetworkOwnership) can be manipulated (at least their position/velocity).
Therefore, you should never have RemoteEvents that can be used to add an arbitrary amount of money or experience. Instead, tell the server what the client did (or wants to do) and the server can choose how much money/experience to give them.
A better script follows (with some "TODOs" that you need to fix). Note that it must be a LocalScript in a place where LocalScripts run (ex PlayerGui) -- NOT in the workspace.
local remoteEvents = game.ReplicatedStorage.RemoteEvents
local dialog =
local bottomDialog = dialog.DialogChoice.DialogChoice.DialogChoice.DialogChoice.DialogChoice
local bottomDialog = dialog
local nextDialog = dialog
while true do
nextDialog = nextDialog:FindFirstChild("DialogChoice")
if not nextDialog then break end
bottomDialog = nextDialog
end
dialog.DialogChoiceSelected:Connect(function(player, choice)
if choice == bottomDialog.ChoiceA then
remoteEvents.NPCDialogChoiceA:FireServer()
elseif choice == bottomDialog.ChoiceB then
remoteEvents.NPCDialogChoiceB:FireServer()
else
return
end
end)
Note that the above script assumes you create NPCDialogChoiceA and B in your remote events and then handle them appropriately (by adding/removing experience as desired). Also, don't forget that an exploiter could call ChoiceA or ChoiceB at any time (and as many times as they like). The server should consider making sure that these aren't called multiple times per second (which would be impossible if you used the dialogs without exploiting) and that the NPC is still offering these choices to the player.
Notably, this is not a very general solution - you have to add a new event for every possible response. An alternate solution is to simply tell the server about every "DialogChoiceSelected" and let the server figure out everything else. This simplifies the client script, though the server is then responsible for all DialogChoices throughout the entire workspace. If you chose to do this, the "Connect" function in the above script would be reduced to one line: remoteEvents.DialogChoiceSelected:FireServer(choice), though a superior script would automatically know/find all dialogs and automatically connect them to this RemoteEvent. You could do this by using DescendantAdded to look for new dialogs and a recursive algorithm to find all pre-existing dialogs.
For future debugging purposes, make sure to check the Output window for errors. If none occur, make sure that the script is running at all (ex put a print statement at the top of the script). Check out Scripting Helper's blog on debugging with print statements. If you're testing online, use F9 to open the developer console.
2 comments
The DialogChoiceSelected function doesn't work with FilteringEnabled.
Also, someone could just do "game.ReplicatedStorage.RemoteEvents.SubractEXP:FireServer(math.huge, game.Players.myworstenemy)" and they would be bankrupt.