Skip to content

Commit 8ebb7e4

Browse files
authored
Mob pathing additions (#357)
# Description Adds additional scriptability around pathing, and fixes some small bugs and quirks. ## Changes - Add scripting documentation for actors and mobs - Rewrote parts of lakeworker script to use pathfinding. - Improved lakeworker script to do a little more while pathing. - Added script event functions for various stages of a path. - Fixed misbehavior of mob `shout` command. - Updated command processing so that mobs subject to similar waiting rules as players when commands are queued with delays. - Added caching for mobs that cannot find a path home. - Mobs that can't go home receive an adjective `lost` - Fixed some conversation bugginess, added some caching - Moved `Rodric` to frostfang folder, where he should be. - Improved Rodric scripting slightly to have some more interesting behavior.
1 parent d7fc8ec commit 8ebb7e4

File tree

17 files changed

+268
-128
lines changed

17 files changed

+268
-128
lines changed

_datafiles/guides/building/scripting/FUNCTIONS_ACTORS.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ ActorObjects are the basic object that represents Users and NPCs
8181
- [ActorObject.SetTameMastery(mobId int, newSkillLevel int)](#actorobjectsettamemasterymobid-int-newskilllevel-int)
8282
- [ActorObject.GetChanceToTame(target ScriptActor) int](#actorobjectgetchancetotametarget-scriptactor-int)
8383
- [ActorObject.GetStatMod(statModName string) int](#actorobjectgetstatmodstatmodname-string-int)
84+
- [ActorObject.IsHome() bool](#actorobjectishome-bool)
85+
- [ActorObject.Pathing() bool](#actorobjectpathing-bool)
86+
- [ActorObject.PathingAtWaypoint() bool](#actorobjectpathingatwaypoint-bool)
8487

8588

8689

@@ -553,3 +556,12 @@ returns the total specific statmod from worn items and buffs
553556
| Argument | Explanation |
554557
| --- | --- |
555558
| statModName | The name of the special stat mod, such as "strength" or "tame" |
559+
560+
## [ActorObject.IsHome() bool](/internal/scripting/actor_func.go)
561+
(mobs only) Returns true if the actor is at their home roomId
562+
563+
## [ActorObject.Pathing() bool](/internal/scripting/actor_func.go)
564+
(mobs only) Returns true if actor is currently pathing
565+
566+
## [ActorObject.PathingAtWaypoint() bool](/internal/scripting/actor_func.go)
567+
(mobs only) Returns true if actor is pathing and at a waypoint.

_datafiles/guides/building/scripting/SCRIPTING_MOBS.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,3 +190,16 @@ function onDie(mob ActorObject, room RoomObject, eventDetails object) {
190190

191191
---
192192

193+
```
194+
function onAsk(mob ActorObject, room RoomObject, eventDetails object) {
195+
}
196+
```
197+
198+
`onPath()` is called when mob is asked something. Returning `true` will end the pathing and skip any additional path processing.
199+
NOTE: You can safely start a new path with `mob.Command('pathto 123')` before returning true, since the command will be executed slightly later in the event chain.
200+
201+
| Argument | Explanation |
202+
| --- | --- |
203+
| mob | [ActorObject](FUNCTIONS_ACTORS.md) |
204+
| room | [RoomObject](FUNCTIONS_ROOMS.md) |
205+
| eventDetails.status | `start`, `waypoint`, or `end` |
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
-
2+
Supported: # A map of lowercase names of "Initiator" (#1) to array of "Participant" (#2) names allowed to use this conversation.
3+
"rodric": ["wench"]
4+
Conversation:
5+
- ["#1 sayto #2 I'll 'ave a mug 'o ale, wench!"]
6+
- ["#2 say Very well, Rodric, but be off with you. We don't need you lingering around the guests smelling like death."]
7+
- ["#2 emote hands Rodric a mug."]
8+
- ["#1 say Aye, i'll be off, then."]
9+
- ["#2 emote mumbles something under their breath."]

_datafiles/world/default/mobs/frostfang_slums/40-rodric.yaml renamed to _datafiles/world/default/mobs/frostfang/40-rodric.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
mobid: 40
2-
zone: Frostfang Slums
2+
zone: Frostfang
33
itemdropchance: 2
44
hostile: false
55
maxwander: 5

_datafiles/world/default/mobs/frostfang/scripts/26-frostfang_citizen-lakeworker.js

Lines changed: 49 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,37 @@
11

2-
SAID_STUFF = false;
3-
WALK_DIRECTION = 1;
4-
WALK_POSITION = 0;
5-
WALK_PATH = [362, // old dock
6-
333,
7-
332,
8-
331,
9-
330,
10-
329,
11-
328,
12-
327,
13-
326,
14-
325,
15-
324,
16-
323,
17-
322,
18-
321,
19-
320,
20-
319] // crashing waves leading to the rocky island
2+
var SAID_STUFF = false; // Whether lakework has spoken this "visit" to the crash site
213

4+
const HOME_ROOM_ID = 362; // old dock
5+
const TRASH_PICKUP_SPOTS = [331,327,323,322]; // miscellaneous points along the way to do a random emote
6+
const CRASH_ROOM_ID = 319; // crashing waves leading to the rocky island
227

238
const boatNouns = ["boats", "oars", "ships", "paddles"];
249
const crashNouns = ["rocks", "crash", "choppy", "water", "waves"];
2510

11+
// Emotes randomly selected at various waypoints.
12+
const randomEmotes = [
13+
"emote picks up some trash along the shoreline.",
14+
"emote moves some driftwood to a pile.",
15+
"emote picks up a small rock and throws it into the lake.",
16+
"emote gently brushes leaves off a bench.",
17+
"emote tosses a fallen branch off the trail.",
18+
"emote stoops to examine a patch of wildflowers.",
19+
"emote skips a stone across the water.",
20+
"emote watches a dragonfly hover near the reeds.",
21+
"emote nudges a small frog back toward the water.",
22+
"emote smooths out a scuffed trail marker.",
23+
"emote pauses to listen to the rustling trees.",
24+
"emote adjusts a loose rock on the path.",
25+
]
26+
2627
function onAsk(mob, room, eventDetails) {
2728

28-
roomId = room.RoomId();
29-
30-
match = UtilFindMatchIn(eventDetails.askText, boatNouns);
29+
var roomId = room.RoomId();
30+
31+
var match = UtilFindMatchIn(eventDetails.askText, boatNouns);
3132
if ( match.found ) {
3233

33-
if ( roomId == 319 ) {
34+
if ( roomId == CRASH_ROOM_ID ) {
3435

3536
mob.Command("say I hit those rocks just over there and lost all of our oars.");
3637
mob.Command("emote points to the northwest.");
@@ -49,7 +50,7 @@ function onAsk(mob, room, eventDetails) {
4950
if ( match.found ) {
5051

5152

52-
if ( roomId == 319 ) {
53+
if ( roomId == CRASH_ROOM_ID ) {
5354

5455
mob.Command("say I hit those rocks just over there and lost all of our oars.");
5556
mob.Command("emote points to the northwest.");
@@ -79,6 +80,20 @@ function onAsk(mob, room, eventDetails) {
7980

8081
}
8182

83+
84+
function onPath(mob, room, eventDetails) {
85+
86+
if ( eventDetails.status == "waypoint" && mob.GetRoomId() != CRASH_ROOM_ID ) {
87+
88+
if ( UtilDiceRoll(1, 5) == 1 ) {
89+
var emoteSelection = UtilDiceRoll(1, randomEmotes.length)-1;
90+
mob.Command(randomEmotes[emoteSelection]);
91+
}
92+
93+
}
94+
95+
}
96+
8297
function onGive(mob, room, eventDetails) {
8398

8499
if (eventDetails.item) {
@@ -99,61 +114,30 @@ function onGive(mob, room, eventDetails) {
99114
// Invoked once every round if mob is idle
100115
function onIdle(mob, room) {
101116

102-
103-
if ( mob.GetRoomId() == 319 ) {
117+
if ( mob.GetRoomId() == CRASH_ROOM_ID ) {
104118

105119
if ( !SAID_STUFF ) {
106120
mob.Command("emote squints and peers towards a rocky island in the lake to the northwest.");
107121
mob.Command("emote mutters to himself.");
108-
if ( UtilDiceRoll(1, 2) == 1 ) {
109-
mob.Command("say Ever since I crashed my boat on those rocks, I've been demoted to cleaning up the lakeshore.");
110-
}
122+
mob.Command("say Ever since I crashed my boat on those rocks, I've been demoted to cleaning up the lakeshore.", 2);
111123

112124
SAID_STUFF = true;
113125
return true;
114126
}
127+
}
115128

116-
SAID_STUFF = false; // reset
117-
118-
} else if ( UtilDiceRoll(1, 2) > 1 ) {
129+
if ( UtilDiceRoll(1, 2) > 1 ) {
119130
return true;
120131
}
121132

122-
123-
124-
if ( WALK_POSITION < 0 ) {
125-
WALK_POSITION = 0;
126-
} else if ( WALK_POSITION > WALK_PATH.length - 1) {
127-
WALK_POSITION = WALK_PATH.length - 1;
133+
if ( mob.IsHome() ) {
134+
SAID_STUFF = false; // reset once they get home
135+
mob.Command("pathto " + TRASH_PICKUP_SPOTS.join(" ") + " " + String(CRASH_ROOM_ID));
136+
return true
128137
}
129138

130-
roomNow = WALK_PATH[WALK_POSITION];
131-
132-
if ( roomNow != mob.GetRoomId() ) {
133-
134-
WALK_POSITION = 0;
135-
WALK_DIRECTION = 1;
136-
mob.MoveRoom(WALK_PATH[WALK_POSITION]);
137-
138-
} else {
139-
140-
if ( WALK_POSITION >= WALK_PATH.length -1 ) {
141-
WALK_DIRECTION = -1;
142-
}
143-
if ( WALK_POSITION < 0 ) {
144-
WALK_DIRECTION = 1;
145-
}
146-
147-
WALK_POSITION += WALK_DIRECTION;
148-
149-
exitList = room.GetExits();
150-
for (var key in exitList) {
151-
if ( exitList[key].RoomId == WALK_PATH[WALK_POSITION] ) {
152-
mob.Command( exitList[key].Name );
153-
154-
}
155-
}
156-
139+
if ( mob.GetRoomId() == CRASH_ROOM_ID ) {
140+
mob.Command("pathto " + TRASH_PICKUP_SPOTS.slice().reverse().join(" ") + " home");
157141
}
158142

159143
return true;

_datafiles/world/default/mobs/frostfang_slums/scripts/40-rodric.js renamed to _datafiles/world/default/mobs/frostfang/scripts/40-rodric.js

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
const startNouns = ["rat", "rats", "too many", "problem"];
33
const thievesNouns = ["thief", "thieves", "guild", "hideout", "entrance", "dogs", "slums"];
4+
const INN_ROOM_ID = 61;
45

56
function onAsk(mob, room, eventDetails) {
67

@@ -111,24 +112,38 @@ function onGive(mob, room, eventDetails) {
111112
}
112113

113114

114-
RANDOM_IDLE = [
115+
function onPath(mob, room, eventDetails) {
116+
117+
if ( eventDetails.status == "waypoint" && room.RoomId() == INN_ROOM_ID ) {
118+
mob.Command("converse 1");
119+
}
120+
121+
}
122+
123+
const RANDOM_IDLE = [
115124
"emote shakes his head in disbelief.",
116125
"emote attempts to fix a rat trap.",
117126
"say There's just too many rats. We'll never get rid of them all.",
118127
"say I'm so tired. I need a break.",
119128
"say I'm running out of traps. I need to find more.",
120129
"say I'm worried about the rats in the slums. They're everywhere!",
121-
"say I'm running out of traps and don't seem to be making a dent in the rat numbers."
130+
"say I'm running out of traps and don't seem to be making a dent in the rat numbers.",
131+
"pathto "+String(INN_ROOM_ID),
122132
];
123133

124134
// Invoked once every round if mob is idle
125135
function onIdle(mob, room) {
126136

137+
if ( room.RoomId() == INN_ROOM_ID ) {
138+
mob.Command("pathto home");
139+
return true;
140+
}
141+
127142
if ( UtilGetRoundNumber()%3 != 0 ) {
128143
return true;
129144
}
130145

131-
randNum = UtilDiceRoll(1, 10)-1;
146+
randNum = UtilDiceRoll(1, 12)-1;
132147
if ( randNum < RANDOM_IDLE.length ) {
133148
mob.Command(RANDOM_IDLE[randNum]);
134149
return true;

internal/conversations/conversations.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package conversations
33
import (
44
"fmt"
55
"os"
6+
"strconv"
67
"strings"
78

89
"github.com/GoMudEngine/GoMud/internal/configs"
@@ -12,6 +13,7 @@ import (
1213
)
1314

1415
var (
16+
converseCheckCache = map[string]bool{}
1517
conversations = map[int]*Conversation{}
1618
conversationCounter = map[string]int{}
1719
conversationUniqueId = 0
@@ -77,7 +79,6 @@ func AttemptConversation(initiatorMobId int, initatorInstanceId int, initiatorNa
7779
}
7880

7981
lowestCount := -1
80-
8182
for _, index := range possibleConversations {
8283
val := conversationCounter[fmt.Sprintf(`%s:%d`, fileName, index)]
8384
if val < lowestCount || lowestCount == -1 {
@@ -155,16 +156,26 @@ func HasConverseFile(mobId int, zone string) bool {
155156

156157
zone = ZoneNameSanitize(zone)
157158

159+
cacheKey := strconv.Itoa(mobId) + `-` + zone
160+
if result, ok := converseCheckCache[cacheKey]; ok {
161+
if result == false {
162+
return false
163+
}
164+
}
165+
158166
convFolder := string(configs.GetFilePathsConfig().DataFiles) + `/conversations`
159167

160168
fileName := fmt.Sprintf("%s/%d.yaml", zone, mobId)
161169

162170
filePath := util.FilePath(convFolder + `/` + fileName)
163171

164172
if _, err := os.Stat(filePath); err != nil {
173+
converseCheckCache[cacheKey] = false
165174
return false
166175
}
167176

177+
converseCheckCache[cacheKey] = true
178+
168179
return true
169180

170181
}

0 commit comments

Comments
 (0)