diff --git a/_datafiles/guides/building/scripting/FUNCTIONS_ACTORS.md b/_datafiles/guides/building/scripting/FUNCTIONS_ACTORS.md
index 58a3e536..c744d3da 100644
--- a/_datafiles/guides/building/scripting/FUNCTIONS_ACTORS.md
+++ b/_datafiles/guides/building/scripting/FUNCTIONS_ACTORS.md
@@ -5,7 +5,7 @@ ActorObjects are the basic object that represents Users and NPCs
- [ActorObject](#actorobject)
- [ActorNames(actors \[\]ActorObject) string ](#actornamesactors-actorobject-string-)
- [GetUser(userId int) ActorObject ](#getuseruserid-int-actorobject-)
- - [GetMob(mobInstanceId int) ActorObject ](#getmobmobinstanceid-int-actorobject-)
+ - [GetMob(mobInstanceId int \[,createIfMissing bool\]) ActorObject ](#getmobmobinstanceid-int-createifmissing-bool-actorobject-)
- [ActorObject.UserId() int](#actorobjectuserid-int)
- [ActorObject.InstanceId() int](#actorobjectinstanceid-int)
- [ActorObject.MobTypeId() int](#actorobjectmobtypeid-int)
@@ -104,12 +104,13 @@ Retrieves a ActorObject for a given userId.
| --- | --- |
| userId | The target user id to get. |
-## [GetMob(mobInstanceId int) ActorObject ](/internal/scripting/actor_func.go)
+## [GetMob(mobInstanceId int [,createIfMissing bool]) ActorObject ](/internal/scripting/actor_func.go)
Retrieves a ActorObject for a given mobInstanceId.
| Argument | Explanation |
| --- | --- |
| mobInstanceId | The target mobInstanceId to get. |
+| createIfMissing | If true and mob isn't found, the mob will be created and returned. |
## [ActorObject.UserId() int](/internal/scripting/actor_func.go)
Returns the userId of the ActorObject.˚
diff --git a/_datafiles/guides/building/scripting/FUNCTIONS_ROOMS.md b/_datafiles/guides/building/scripting/FUNCTIONS_ROOMS.md
index 9f35c159..71020331 100644
--- a/_datafiles/guides/building/scripting/FUNCTIONS_ROOMS.md
+++ b/_datafiles/guides/building/scripting/FUNCTIONS_ROOMS.md
@@ -13,8 +13,10 @@
- [RoomObject.GetItems() \[\]ItemObject](#roomobjectgetitems-itemobject)
- [RoomObject.DestroyItem(itm ScriptItem) ](#roomobjectdestroyitemitm-scriptitem-)
- [RoomObject.SpawnItem(itemId int, inStash bool) \[\]ItemObject](#roomobjectspawnitemitemid-int-instash-bool-itemobject)
- - [RoomObject.GetMobs() \[\]int](#roomobjectgetmobs-int)
- - [RoomObject.GetPlayers() \[\]int](#roomobjectgetplayers-int)
+ - [RoomObject.GetMob(mobId int) Actor](#roomobjectgetmobmobid-int-actor)
+ - [RoomObject.GetMobs(\[mobId int\]) \[\]Actor](#roomobjectgetmobsmobid-int-actor)
+ - [RoomObject.GetPlayers() \[\]Actor](#roomobjectgetplayers-actor)
+ - [RoomObject.GetAllActors() \[\]Actor](#roomobjectgetallactors-actor)
- [RoomObject.GetContainers() \[\]string](#roomobjectgetcontainers-string)
- [RoomObject.GetExits() \[\]object](#roomobjectgetexits-object)
- [GetMap(mapRoomId int, mapZoom, mapHeight int, mapWidth int, mapName string, showSecrets bool \[,mapMarker string, mapMarker string\]) string](#getmapmaproomid-int-mapzoom-mapheight-int-mapwidth-int-mapname-string-showsecrets-bool-mapmarker-string-mapmarker-string-string)
@@ -113,11 +115,26 @@ Spawns an item in the room.
| itemId | ItemId to spawn. |
| inStash | If true, spawns stashed instead of visible. |
-## [RoomObject.GetMobs() []int](/internal/scripting/room_func.go)
-Returns an array of `mobInstanceIds` in the room.
-## [RoomObject.GetPlayers() []int](/internal/scripting/room_func.go)
-Returns an array of `userIds` in the room.
+## [RoomObject.GetMob(mobId int) Actor](/internal/scripting/room_func.go)
+Returns the first mob that matches the provided MobId type (Note: NOT MOB INSTANCE ID!)
+
+| Argument | Explanation |
+| --- | --- |
+| mobId | MobId to match. |
+
+## [RoomObject.GetMobs([mobId int]) []Actor](/internal/scripting/room_func.go)
+Returns an array of mob `Actor`s in the room.
+
+| Argument | Explanation |
+| --- | --- |
+| mobId (optional) | Only get mobs of the provided MobId type. (Note: NOT MOB INSTANCE ID!) |
+
+## [RoomObject.GetPlayers() []Actor](/internal/scripting/room_func.go)
+Returns an array of player `Actor`s in the room.
+
+## [RoomObject.GetAllActors() []Actor](/internal/scripting/room_func.go)
+Returns an array of all `Actor`s in the room.
## [RoomObject.GetContainers() []string](/internal/scripting/room_func.go)
Gets a list of container names in the room.
diff --git a/_datafiles/world/default/items/other-0/101-arcane_flute.js b/_datafiles/world/default/items/other-0/101-arcane_flute.js
new file mode 100644
index 00000000..f6682592
--- /dev/null
+++ b/_datafiles/world/default/items/other-0/101-arcane_flute.js
@@ -0,0 +1,38 @@
+
+const MUSIC_DESCRIPTIONS = [
+ "a silvery trill dances on the breeze. ♪♪ ♫",
+ "a cascade of notes unravels into open air. ♫ ♪♪",
+ "a soft melody fills the air. ♪♫ ♪",
+];
+
+const RAT_MOB_IDS = [1, 12];
+
+function onCommand_play(user, item, room) {
+
+ var randomPhrase = MUSIC_DESCRIPTIONS[UtilDiceRoll(1, MUSIC_DESCRIPTIONS.length)-1];
+
+ if ( UtilIsDay() ) {
+ SendUserMessage(user.UserId(), "You attempt to play the flute, but only succeed in producing a shrill noise");
+ SendRoomMessage(room.RoomId(), user.GetCharacterName(true)+" attempts to play their "+item.Name(true)+" and a horrible, shrill sound fills the air.", user.UserId());
+
+ return true;
+ }
+
+ SendUserMessage(user.UserId(), "You surprisingly find yourself able to play the flute effortlessly, and "+randomPhrase);
+ SendRoomMessage(room.RoomId(), user.GetCharacterName(true)+" plays their "+item.Name(true)+" and "+randomPhrase, user.UserId());
+
+ // NOTE: This is not charming the mob. This is a special pacify and force follow.
+ // The rats will not follow the behavior of charmed mobs.
+ for( var i in RAT_MOB_IDS ) {
+ var ratMobs = room.GetMobs(RAT_MOB_IDS[i]);
+ for ( var j in ratMobs ) {
+ ratMobs[j].Command(`break`); // Break off any combat
+ ratMobs[j].Command(`follow ` + user.ShorthandId() + ` sunrise`); // follow whoever played the flute until sunrise
+ ratMobs[j].ChangeAlignment(user.GetAlignment()); // Set alignment to the flute player
+ }
+ }
+
+
+ return true;
+}
+
diff --git a/_datafiles/world/default/items/other-0/101-arcane_flute.yaml b/_datafiles/world/default/items/other-0/101-arcane_flute.yaml
new file mode 100755
index 00000000..9b82785c
--- /dev/null
+++ b/_datafiles/world/default/items/other-0/101-arcane_flute.yaml
@@ -0,0 +1,8 @@
+itemid: 101
+value: 10000
+hands: 0
+name: arcane flute
+namesimple: arcane flute
+description: A flute with faintly glowing markings all along it. Maybe you can play it.
+type: object
+subtype: generic
diff --git a/_datafiles/world/default/mobs/frostfang/10-ivar_froststeel.yaml b/_datafiles/world/default/mobs/frostfang/10-ivar_froststeel.yaml
index fa95c82b..d22f3d7f 100644
--- a/_datafiles/world/default/mobs/frostfang/10-ivar_froststeel.yaml
+++ b/_datafiles/world/default/mobs/frostfang/10-ivar_froststeel.yaml
@@ -5,7 +5,7 @@ hostile: false
groups:
- frostfang-npc
idlecommands:
- - 'say type `list` to see my wares'
+ - 'say type list to see my wares'
- 'say If you''re looking to sell something, I may be interested... as long as it''s not too special or unique'
- emote is counting his coins
- emote watches you carefully
diff --git a/_datafiles/world/default/mobs/frostfang/11-brynja_snowdeal.yaml b/_datafiles/world/default/mobs/frostfang/11-brynja_snowdeal.yaml
index ae413df7..b09d1cbc 100644
--- a/_datafiles/world/default/mobs/frostfang/11-brynja_snowdeal.yaml
+++ b/_datafiles/world/default/mobs/frostfang/11-brynja_snowdeal.yaml
@@ -5,7 +5,7 @@ hostile: false
groups:
- frostfang-npc
idlecommands:
- - 'say type `list` to see my wares'
+ - 'say type list to see my wares'
- 'say If you''re looking to sell something, I may be interested... as long as it''s not too special or unique'
- emote shuffles some papers
- emote is counting her coins
diff --git a/_datafiles/world/default/mobs/frostfang/5-armorer.yaml b/_datafiles/world/default/mobs/frostfang/5-armorer.yaml
index 2d19b3a2..d27f6f10 100644
--- a/_datafiles/world/default/mobs/frostfang/5-armorer.yaml
+++ b/_datafiles/world/default/mobs/frostfang/5-armorer.yaml
@@ -5,7 +5,7 @@ hostile: false
groups:
- frostfang-npc
idlecommands:
- - 'say type `list` to see my wares'
+ - 'say type list to see my wares'
- 'say If you''re looking to sell something, I may be interested... as long as it''s not too special or unique'
- emote shuffles some papers
- emote is counting his coins
diff --git a/_datafiles/world/default/mobs/frostfang/50-moilyn_the_wizard.yaml b/_datafiles/world/default/mobs/frostfang/50-moilyn_the_wizard.yaml
index d4e1cf54..7dbb60f5 100644
--- a/_datafiles/world/default/mobs/frostfang/50-moilyn_the_wizard.yaml
+++ b/_datafiles/world/default/mobs/frostfang/50-moilyn_the_wizard.yaml
@@ -5,7 +5,7 @@ hostile: false
groups:
- frostfang-npc
idlecommands:
- - 'say type `list` to see what magical objects I have for sale'
+ - 'say type list to see what magical objects I have for sale'
activitylevel: 10
character:
name: moilyn the wizard
diff --git a/_datafiles/world/default/mobs/mystarion/46-herbalist.yaml b/_datafiles/world/default/mobs/mystarion/46-herbalist.yaml
index b00ba76d..96927686 100644
--- a/_datafiles/world/default/mobs/mystarion/46-herbalist.yaml
+++ b/_datafiles/world/default/mobs/mystarion/46-herbalist.yaml
@@ -7,9 +7,8 @@ groups:
- mystarion-npc
activitylevel: 40
idlecommands:
- - say type `list` to see my wares
- - say If you're looking to sell something, I may be interested... as long as it's
- not too special or unique
+ - say type list to see my wares
+ - say If you're looking to sell something, I may be interested... as long as it's not too special or unique
- emote is watching you
combatcommands:
- 'say How dare you attack the citizens of Mystarion! We do not forget!'
diff --git a/_datafiles/world/default/mobs/mystarion/47-brewer.yaml b/_datafiles/world/default/mobs/mystarion/47-brewer.yaml
index 54d9b807..a6193af2 100644
--- a/_datafiles/world/default/mobs/mystarion/47-brewer.yaml
+++ b/_datafiles/world/default/mobs/mystarion/47-brewer.yaml
@@ -7,9 +7,8 @@ groups:
- mystarion-npc
activitylevel: 40
idlecommands:
- - say type `list` to see my wares
- - say If you're looking to sell something, I may be interested... as long as it's
- not too special or unique
+ - say type list to see my wares
+ - say If you're looking to sell something, I may be interested... as long as it's not too special or unique
- emote is watching you
combatcommands:
- 'say How dare you attack the citizens of Mystarion! We do not forget!'
diff --git a/_datafiles/world/default/mobs/mystarion/48-gardener.yaml b/_datafiles/world/default/mobs/mystarion/48-gardener.yaml
index 238dd588..ced8eceb 100644
--- a/_datafiles/world/default/mobs/mystarion/48-gardener.yaml
+++ b/_datafiles/world/default/mobs/mystarion/48-gardener.yaml
@@ -7,9 +7,8 @@ groups:
- mystarion-npc
activitylevel: 40
idlecommands:
- - say type `list` to see my wares
- - say If you're looking to sell something, I may be interested... as long as it's
- not too special or unique
+ - say type list to see my wares
+ - say If you're looking to sell something, I may be interested... as long as it's not too special or unique
- emote is watching you
combatcommands:
- 'say How dare you attack the citizens of Mystarion! We do not forget!'
diff --git a/_datafiles/world/default/mobs/mystarion/49-henry_the_collector.yaml b/_datafiles/world/default/mobs/mystarion/49-henry_the_collector.yaml
index d028f626..4ac64d67 100644
--- a/_datafiles/world/default/mobs/mystarion/49-henry_the_collector.yaml
+++ b/_datafiles/world/default/mobs/mystarion/49-henry_the_collector.yaml
@@ -7,9 +7,8 @@ groups:
- mystarion-npc
activitylevel: 40
idlecommands:
- - say type `list` to see my wares
- - say If you're looking to sell something, I may be interested... as long as it's
- not too special or unique
+ - say type list to see my wares
+ - say If you're looking to sell something, I may be interested... as long as it's not too special or unique
- emote is watching you
combatcommands:
- 'say How dare you attack the citizens of Mystarion! We do not forget!'
@@ -31,6 +30,8 @@ character:
quantitymax: 1
- itemid: 23
quantitymax: 8
+ - itemid: 101
+ quantitymax: 1
equipment:
weapon:
itemid: 10018
diff --git a/_datafiles/world/default/mobs/tutorial/scripts/58-training_dummy.js b/_datafiles/world/default/mobs/tutorial/scripts/58-training_dummy.js
index 92a1cc8b..ac428d16 100644
--- a/_datafiles/world/default/mobs/tutorial/scripts/58-training_dummy.js
+++ b/_datafiles/world/default/mobs/tutorial/scripts/58-training_dummy.js
@@ -4,27 +4,7 @@ function onDie(mob, room, eventDetails) {
room.SendText( mob.GetCharacterName(true) + " crumbles to dust." );
- teacherMob = getTeacher(room);
+ room.GetMob(teacherMobId, true);
teacherMob.Command('say You did it! Head west to complete your training.');
}
-
-
-function getTeacher(room) {
-
- var mobActor = null;
-
- mobIds = room.GetMobs();
-
- for (var i in mobIds ) {
- mobActor = GetMob(mobIds[i]);
- if ( mobActor.MobTypeId() == teacherMobId ) {
- return mobActor;
- }
- }
-
- mobActor = room.SpawnMob(teacherMobId);
- mobActor.SetCharacterName(teacherName);
-
- return mobActor;
-}
diff --git a/_datafiles/world/default/rooms/dark_forest/558.yaml b/_datafiles/world/default/rooms/dark_forest/558.yaml
index 6e450b9b..e142f073 100755
--- a/_datafiles/world/default/rooms/dark_forest/558.yaml
+++ b/_datafiles/world/default/rooms/dark_forest/558.yaml
@@ -19,8 +19,7 @@ spawninfo:
- mobid: 43
message: A small faerie enters the clearing.
idlecommands:
- - emote procures a piece of a mushrom, and with a wave of their hand, restore it
- to a new mushroom.
+ - emote procures a piece of a mushrom, and with a wave of their hand, restore it to a new mushroom.
- emote nods to themselves, pleased with their work.
scripttag: clearing
respawnrate: 1 real minutes
diff --git a/_datafiles/world/default/rooms/frostfang/166.js b/_datafiles/world/default/rooms/frostfang/166.js
index 41c729ba..307ad167 100644
--- a/_datafiles/world/default/rooms/frostfang/166.js
+++ b/_datafiles/world/default/rooms/frostfang/166.js
@@ -1,25 +1,26 @@
function onCommand_vault(rest, user, room) {
- guard_present = false;
+ var presentMob = null;
- mobs = room.GetMobs();
- for (i = 0; i < mobs.length; i++) {
- if ( (mob = GetMob(mobs[i])) == null ) {
- continue;
- }
+ var roomMobs = room.GetMobs();
+ for (i = 0; i < roomMobs.length; i++) {
+ var mob = roomMobs[i];
mobName = mob.GetCharacterName(false);
if ( mobName.indexOf("guard") !== -1 ) {
- guard_present = true;
+ presentMob = mob;
break;
}
}
- hidden = user.HasBuffFlag("hidden");
-
- if (guard_present && !hidden) {
- SendUserMessage(user.UserId(), "A guard blocks you from entering the vault.");
- SendRoomMessage(room.RoomId(), "A guard blocks "+user.GetCharacterName(true)+" from entering the vault.", user.UserId());
+ if ( user.HasBuffFlag("hidden") ) {
+ return false;
+ }
+
+ if ( presentMob != null ) {
+ SendUserMessage(user.UserId(), presentMob.GetCharacterName(true) + " blocks you from entering the vault.");
+ SendRoomMessage(room.RoomId(), presentMob.GetCharacterName(true) + " blocks " + user.GetCharacterName(true) + " from entering the vault.", user.UserId());
+ presentMob.Command(`sayto ` + user.ShorthandId() + ` not on my watch, pal.`, 1.0);
return true;
}
diff --git a/_datafiles/world/default/rooms/mirror_caves/242.js b/_datafiles/world/default/rooms/mirror_caves/242.js
index c906fead..b61abe09 100644
--- a/_datafiles/world/default/rooms/mirror_caves/242.js
+++ b/_datafiles/world/default/rooms/mirror_caves/242.js
@@ -1,7 +1,7 @@
function onCommand_out(rest, user, room) {
- mobs = room.GetMobs();
+ var mobs = room.GetMobs();
if ( mobs.length > 0 ) {
SendUserMessage(user.UserId(), "The way out is block by denizens of the cave.");
return true;
diff --git a/_datafiles/world/default/rooms/tutorial/900.js b/_datafiles/world/default/rooms/tutorial/900.js
index 3a6290a5..eee5ceb7 100644
--- a/_datafiles/world/default/rooms/tutorial/900.js
+++ b/_datafiles/world/default/rooms/tutorial/900.js
@@ -110,52 +110,27 @@ function onEnter(user, room) {
teacherMob.Command('say type look and hit enter to see a description of the area you are in.', 5.0);
}
-
function onExit(user , room) {
// Destroy the guide (cleanup)
destroyTeacher(room);
}
-
-
function onLoad(room) {
canGoEast = false;
commandNow = 0;
}
-
-
function getTeacher(room) {
-
- var mobActor = null;
-
- mobIds = room.GetMobs();
-
- for ( var i in mobIds ) {
- mobActor = GetMob(mobIds[i]);
- if ( mobActor.MobTypeId() == teacherMobId ) {
- return mobActor;
- }
- }
-
- mobActor = room.SpawnMob(teacherMobId);
+ var mobActor = room.GetMob(teacherMobId, true);
mobActor.SetCharacterName(teacherName);
-
return mobActor;
}
function destroyTeacher(room) {
-
- var mobActor = null;
-
- mobIds = room.GetMobs();
-
- for ( var i in mobIds ) {
- mobActor = GetMob(mobIds[i]);
- if ( mobActor.MobTypeId() == teacherMobId ) {
- mobActor.Command(`suicide vanish`);
- }
- }
+ var mobActor = room.GetMob(teacherMobId);
+ if ( mobActor != null ) {
+ mobActor.Command(`suicide vanish`);
+ }
}
function sendWorkingCommands(user) {
diff --git a/_datafiles/world/default/rooms/tutorial/901.js b/_datafiles/world/default/rooms/tutorial/901.js
index 712134f4..09364c7e 100644
--- a/_datafiles/world/default/rooms/tutorial/901.js
+++ b/_datafiles/world/default/rooms/tutorial/901.js
@@ -113,8 +113,6 @@ function onEnter(user, room) {
teacherMob.Command('say To get a detailed view of a LOT of information all at once, type status and hit enter.', 2.0);
}
-
-
function onExit(user , room) {
// Destroy the guide (cleanup)
destroyTeacher(room);
@@ -122,44 +120,25 @@ function onExit(user , room) {
commandNow = 0;
}
-
-
function onLoad(room) {
canGoSouth = false;
commandNow = 0;
}
-
function getTeacher(room) {
-
var mobActor = null;
- mobIds = room.GetMobs();
-
- for ( var i in mobIds ) {
- mobActor = GetMob(mobIds[i]);
- if ( mobActor.MobTypeId() == teacherMobId ) {
- return mobActor;
- }
- }
-
- mobActor = room.SpawnMob(teacherMobId);
+ var mobActor = room.GetMob(teacherMobId, true);
mobActor.SetCharacterName(teacherName);
return mobActor;
}
-function destroyTeacher(room) {
-
- var mobActor = null;
- mobIds = room.GetMobs();
-
- for ( var i in mobIds ) {
- mobActor = GetMob(mobIds[i]);
- if ( mobActor.MobTypeId() == teacherMobId ) {
- mobActor.Command(`suicide vanish`);
- }
- }
+function destroyTeacher(room) {
+ var mobActor = room.GetMob(teacherMobId);
+ if ( mobActor != null ) {
+ mobActor.Command(`suicide vanish`);
+ }
}
function sendWorkingCommands(user) {
diff --git a/_datafiles/world/default/rooms/tutorial/902.js b/_datafiles/world/default/rooms/tutorial/902.js
index 6ef15b8a..74283fcd 100644
--- a/_datafiles/world/default/rooms/tutorial/902.js
+++ b/_datafiles/world/default/rooms/tutorial/902.js
@@ -113,8 +113,6 @@ function onEnter(user, room) {
teacherMob.Command('say Go ahead and equip that sharp stick you\'ve got. Type equip stick.', 2.0);
}
-
-
function onExit(user , room) {
// Destroy the guide (cleanup)
destroyTeacher(room);
@@ -123,75 +121,32 @@ function onExit(user , room) {
commandNow = 0;
}
-
-
function onLoad(room) {
canGoSouth = false;
commandNow = 0;
}
-
function getTeacher(room) {
-
- var mobActor = null;
-
- mobIds = room.GetMobs();
-
- for ( var i in mobIds ) {
- mobActor = GetMob(mobIds[i]);
- if ( mobActor.MobTypeId() == teacherMobId ) {
- return mobActor;
- }
- }
-
- mobActor = room.SpawnMob(teacherMobId);
+ var mobActor = room.GetMob(teacherMobId, true);
mobActor.SetCharacterName(teacherName);
-
return mobActor;
}
function destroyTeacher(room) {
-
- var mobActor = null;
-
- mobIds = room.GetMobs();
-
- for ( var i in mobIds ) {
- mobActor = GetMob(mobIds[i]);
- if ( mobActor.MobTypeId() == teacherMobId ) {
- mobActor.Command(`suicide vanish`);
- }
- }
+ var mobActor = room.GetMob(teacherMobId);
+ if ( mobActor != null ) {
+ mobActor.Command(`suicide vanish`);
+ }
}
-
function getDummy(room) {
-
- var mobActor = null;
-
- mobIds = room.GetMobs();
-
- for ( var i in mobIds ) {
- mobActor = GetMob(mobIds[i]);
- if ( mobActor.MobTypeId() == dummyMobId ) {
- return mobActor;
- }
- }
-
- return room.SpawnMob(dummyMobId);
+ return room.GetMob(dummyMobId, true);
}
function destroyDummy(room) {
-
- var mobActor = null;
-
- mobIds = room.GetMobs();
-
- for ( var i in mobIds ) {
- mobActor = GetMob(mobIds[i]);
- if ( mobActor.MobTypeId() == dummyMobId ) {
- mobActor.Command(`suicide vanish`);
- }
+ var mobActor = room.GetMob(dummyMobId);
+ if ( mobActor != null ) {
+ mobActor.Command(`suicide vanish`);
}
}
diff --git a/_datafiles/world/default/rooms/tutorial/903.js b/_datafiles/world/default/rooms/tutorial/903.js
index a00574b8..24deb4a7 100644
--- a/_datafiles/world/default/rooms/tutorial/903.js
+++ b/_datafiles/world/default/rooms/tutorial/903.js
@@ -100,8 +100,6 @@ function onEnter(user, room) {
}
-
-
function onExit(user , room) {
// Destroy the guide (cleanup)
destroyTeacher(room);
@@ -110,48 +108,24 @@ function onExit(user , room) {
commandNow = 0;
}
-
-
function onLoad(room) {
canGoSouth = false;
commandNow = 0;
}
-
function getTeacher(room) {
-
- var mobActor = null;
-
- mobIds = room.GetMobs();
-
- for ( var i in mobIds ) {
- mobActor = GetMob(mobIds[i]);
- if ( mobActor.MobTypeId() == teacherMobId ) {
- return mobActor;
- }
- }
-
- mobActor = room.SpawnMob(teacherMobId);
+ var mobActor = room.GetMob(teacherMobId, true);
mobActor.SetCharacterName(teacherName);
-
return mobActor;
}
function destroyTeacher(room) {
-
- var mobActor = null;
-
- mobIds = room.GetMobs();
-
- for ( var i in mobIds ) {
- mobActor = GetMob(mobIds[i]);
- if ( mobActor.MobTypeId() == teacherMobId ) {
- mobActor.Command(`suicide vanish`);
- }
- }
+ var mobActor = room.GetMob(teacherMobId);
+ if ( mobActor != null ) {
+ mobActor.Command(`suicide vanish`);
+ }
}
-
function sendWorkingCommands(user) {
ac = [];
diff --git a/_datafiles/world/empty/mobs/tutorial/scripts/58-training_dummy.js b/_datafiles/world/empty/mobs/tutorial/scripts/58-training_dummy.js
index 92a1cc8b..5b3e2c9b 100644
--- a/_datafiles/world/empty/mobs/tutorial/scripts/58-training_dummy.js
+++ b/_datafiles/world/empty/mobs/tutorial/scripts/58-training_dummy.js
@@ -4,27 +4,7 @@ function onDie(mob, room, eventDetails) {
room.SendText( mob.GetCharacterName(true) + " crumbles to dust." );
- teacherMob = getTeacher(room);
+ teacherMob = room.GetMob(teacherMobId, true);
teacherMob.Command('say You did it! Head west to complete your training.');
}
-
-
-function getTeacher(room) {
-
- var mobActor = null;
-
- mobIds = room.GetMobs();
-
- for (var i in mobIds ) {
- mobActor = GetMob(mobIds[i]);
- if ( mobActor.MobTypeId() == teacherMobId ) {
- return mobActor;
- }
- }
-
- mobActor = room.SpawnMob(teacherMobId);
- mobActor.SetCharacterName(teacherName);
-
- return mobActor;
-}
diff --git a/_datafiles/world/empty/rooms/tutorial/900.js b/_datafiles/world/empty/rooms/tutorial/900.js
index 3a6290a5..eee5ceb7 100644
--- a/_datafiles/world/empty/rooms/tutorial/900.js
+++ b/_datafiles/world/empty/rooms/tutorial/900.js
@@ -110,52 +110,27 @@ function onEnter(user, room) {
teacherMob.Command('say type look and hit enter to see a description of the area you are in.', 5.0);
}
-
function onExit(user , room) {
// Destroy the guide (cleanup)
destroyTeacher(room);
}
-
-
function onLoad(room) {
canGoEast = false;
commandNow = 0;
}
-
-
function getTeacher(room) {
-
- var mobActor = null;
-
- mobIds = room.GetMobs();
-
- for ( var i in mobIds ) {
- mobActor = GetMob(mobIds[i]);
- if ( mobActor.MobTypeId() == teacherMobId ) {
- return mobActor;
- }
- }
-
- mobActor = room.SpawnMob(teacherMobId);
+ var mobActor = room.GetMob(teacherMobId, true);
mobActor.SetCharacterName(teacherName);
-
return mobActor;
}
function destroyTeacher(room) {
-
- var mobActor = null;
-
- mobIds = room.GetMobs();
-
- for ( var i in mobIds ) {
- mobActor = GetMob(mobIds[i]);
- if ( mobActor.MobTypeId() == teacherMobId ) {
- mobActor.Command(`suicide vanish`);
- }
- }
+ var mobActor = room.GetMob(teacherMobId);
+ if ( mobActor != null ) {
+ mobActor.Command(`suicide vanish`);
+ }
}
function sendWorkingCommands(user) {
diff --git a/_datafiles/world/empty/rooms/tutorial/901.js b/_datafiles/world/empty/rooms/tutorial/901.js
index 712134f4..e15dc4c8 100644
--- a/_datafiles/world/empty/rooms/tutorial/901.js
+++ b/_datafiles/world/empty/rooms/tutorial/901.js
@@ -129,37 +129,17 @@ function onLoad(room) {
commandNow = 0;
}
-
function getTeacher(room) {
-
- var mobActor = null;
-
- mobIds = room.GetMobs();
-
- for ( var i in mobIds ) {
- mobActor = GetMob(mobIds[i]);
- if ( mobActor.MobTypeId() == teacherMobId ) {
- return mobActor;
- }
- }
-
- mobActor = room.SpawnMob(teacherMobId);
+ var mobActor = room.GetMob(teacherMobId, true);
mobActor.SetCharacterName(teacherName);
-
return mobActor;
}
-function destroyTeacher(room) {
- var mobActor = null;
-
- mobIds = room.GetMobs();
-
- for ( var i in mobIds ) {
- mobActor = GetMob(mobIds[i]);
- if ( mobActor.MobTypeId() == teacherMobId ) {
- mobActor.Command(`suicide vanish`);
- }
- }
+function destroyTeacher(room) {
+ var mobActor = room.GetMob(teacherMobId);
+ if ( mobActor != null ) {
+ mobActor.Command(`suicide vanish`);
+ }
}
function sendWorkingCommands(user) {
diff --git a/_datafiles/world/empty/rooms/tutorial/902.js b/_datafiles/world/empty/rooms/tutorial/902.js
index 6ef15b8a..74283fcd 100644
--- a/_datafiles/world/empty/rooms/tutorial/902.js
+++ b/_datafiles/world/empty/rooms/tutorial/902.js
@@ -113,8 +113,6 @@ function onEnter(user, room) {
teacherMob.Command('say Go ahead and equip that sharp stick you\'ve got. Type equip stick.', 2.0);
}
-
-
function onExit(user , room) {
// Destroy the guide (cleanup)
destroyTeacher(room);
@@ -123,75 +121,32 @@ function onExit(user , room) {
commandNow = 0;
}
-
-
function onLoad(room) {
canGoSouth = false;
commandNow = 0;
}
-
function getTeacher(room) {
-
- var mobActor = null;
-
- mobIds = room.GetMobs();
-
- for ( var i in mobIds ) {
- mobActor = GetMob(mobIds[i]);
- if ( mobActor.MobTypeId() == teacherMobId ) {
- return mobActor;
- }
- }
-
- mobActor = room.SpawnMob(teacherMobId);
+ var mobActor = room.GetMob(teacherMobId, true);
mobActor.SetCharacterName(teacherName);
-
return mobActor;
}
function destroyTeacher(room) {
-
- var mobActor = null;
-
- mobIds = room.GetMobs();
-
- for ( var i in mobIds ) {
- mobActor = GetMob(mobIds[i]);
- if ( mobActor.MobTypeId() == teacherMobId ) {
- mobActor.Command(`suicide vanish`);
- }
- }
+ var mobActor = room.GetMob(teacherMobId);
+ if ( mobActor != null ) {
+ mobActor.Command(`suicide vanish`);
+ }
}
-
function getDummy(room) {
-
- var mobActor = null;
-
- mobIds = room.GetMobs();
-
- for ( var i in mobIds ) {
- mobActor = GetMob(mobIds[i]);
- if ( mobActor.MobTypeId() == dummyMobId ) {
- return mobActor;
- }
- }
-
- return room.SpawnMob(dummyMobId);
+ return room.GetMob(dummyMobId, true);
}
function destroyDummy(room) {
-
- var mobActor = null;
-
- mobIds = room.GetMobs();
-
- for ( var i in mobIds ) {
- mobActor = GetMob(mobIds[i]);
- if ( mobActor.MobTypeId() == dummyMobId ) {
- mobActor.Command(`suicide vanish`);
- }
+ var mobActor = room.GetMob(dummyMobId);
+ if ( mobActor != null ) {
+ mobActor.Command(`suicide vanish`);
}
}
diff --git a/_datafiles/world/empty/rooms/tutorial/903.js b/_datafiles/world/empty/rooms/tutorial/903.js
index bf3dd1c3..d1e78a1f 100644
--- a/_datafiles/world/empty/rooms/tutorial/903.js
+++ b/_datafiles/world/empty/rooms/tutorial/903.js
@@ -100,8 +100,6 @@ function onEnter(user, room) {
}
-
-
function onExit(user , room) {
// Destroy the guide (cleanup)
destroyTeacher(room);
@@ -110,48 +108,24 @@ function onExit(user , room) {
commandNow = 0;
}
-
-
function onLoad(room) {
canGoSouth = false;
commandNow = 0;
}
-
function getTeacher(room) {
-
- var mobActor = null;
-
- mobIds = room.GetMobs();
-
- for ( var i in mobIds ) {
- mobActor = GetMob(mobIds[i]);
- if ( mobActor.MobTypeId() == teacherMobId ) {
- return mobActor;
- }
- }
-
- mobActor = room.SpawnMob(teacherMobId);
+ var mobActor = room.GetMob(teacherMobId, true);
mobActor.SetCharacterName(teacherName);
-
return mobActor;
}
function destroyTeacher(room) {
-
- var mobActor = null;
-
- mobIds = room.GetMobs();
-
- for ( var i in mobIds ) {
- mobActor = GetMob(mobIds[i]);
- if ( mobActor.MobTypeId() == teacherMobId ) {
- mobActor.Command(`suicide vanish`);
- }
- }
+ var mobActor = room.GetMob(teacherMobId);
+ if ( mobActor != null ) {
+ mobActor.Command(`suicide vanish`);
+ }
}
-
function sendWorkingCommands(user) {
ac = [];
diff --git a/internal/gametime/gametime.go b/internal/gametime/gametime.go
index c377cce0..01db615a 100644
--- a/internal/gametime/gametime.go
+++ b/internal/gametime/gametime.go
@@ -258,7 +258,11 @@ func (g GameDate) Add(adjustHours int, adjustDays int, adjustYears int) GameDate
// nextPeriodRound := gd.AddPeriod(`10 days`)
// Accepts: x years, x months, x weeks, x days, x hours, x rounds
// If `IRL` or `real` are in the mix, such as `x irl days` or `x days irl`, then it will use real world time
-func (g GameDate) AddPeriod(str string) uint64 {
+func (g GameDate) AddPeriod(periodStr string) uint64 {
+
+ if periodStr == `` {
+ return g.RoundNumber
+ }
qty := 1
timeStr := ``
@@ -267,7 +271,7 @@ func (g GameDate) AddPeriod(str string) uint64 {
roundsPerRealHour := 0
roundsPerRealMinute := 0
- parts := strings.Split(strings.ToLower(str), ` `)
+ parts := strings.Split(strings.ToLower(periodStr), ` `)
if len(parts) == 1 { // e.g. 2
// try and parse a number, if not a number, must be a str
@@ -434,7 +438,6 @@ func (g GameDate) AddPeriod(str string) uint64 {
// Failover to rounds
return g.RoundNumber + uint64(qty)
-
}
// Assume rounds?
diff --git a/internal/hooks/MobIdle_HandleIdleMobs.go b/internal/hooks/MobIdle_HandleIdleMobs.go
index 7017a7ea..d65a4c8c 100644
--- a/internal/hooks/MobIdle_HandleIdleMobs.go
+++ b/internal/hooks/MobIdle_HandleIdleMobs.go
@@ -51,30 +51,29 @@ func HandleIdleMobs(e events.Event) events.ListenerReturn {
if mob.Character.KnowsFirstAid() {
mob.Command(`lookforaid`)
}
- } else {
- if mob.MaxWander > -1 && mob.WanderCount > mob.MaxWander {
-
- // Not charmed and far from home, and should never leave home.
- // So go home.
- mob.Command(`pathto home`)
-
- } else {
+ return events.Continue
+ }
- //
- // Look for trouble
- //
+ if mob.MaxWander > -1 && mob.WanderCount > mob.MaxWander {
+ // Not charmed and far from home, and should never leave home.
+ // So go home.
+ mob.Command(`pathto home`)
+ return events.Continue
+ }
- idleCmd := `lookfortrouble`
- if util.Rand(100) < mob.ActivityLevel {
- idleCmd = mob.GetIdleCommand()
- if idleCmd == `` {
- idleCmd = `lookfortrouble`
- }
- }
- mob.Command(idleCmd)
+ //
+ // Look for trouble
+ //
+ idleCmd := `lookfortrouble`
+ if util.Rand(100) < mob.ActivityLevel {
+ idleCmd = mob.GetIdleCommand()
+ if idleCmd == `` {
+ idleCmd = `lookfortrouble`
}
}
+ mob.Command(idleCmd)
+
}
return events.Continue
diff --git a/internal/hooks/NewRound_IdleMobs.go b/internal/hooks/NewRound_IdleMobs.go
index 2e386afc..5f1bf0eb 100644
--- a/internal/hooks/NewRound_IdleMobs.go
+++ b/internal/hooks/NewRound_IdleMobs.go
@@ -21,8 +21,6 @@ import (
func IdleMobs(e events.Event) events.ListenerReturn {
- mobPathAnnounce := false // useful for debugging purposes.
-
mc := configs.GetMemoryConfig()
maxBoredom := uint8(mc.MaxMobBoredom)
@@ -92,17 +90,11 @@ func IdleMobs(e events.Event) events.ListenerReturn {
continue
}
- if mobPathAnnounce {
- mob.Command(`say I'm beginning a new path.`)
- }
} else {
// If their currentStep isn't actually the room they are in
// They've somehow been moved. Reclaculate a new path.
if currentStep.RoomId() != mob.Character.RoomId {
- if mobPathAnnounce {
- mob.Command(`say I seem to have wandered off my path.`)
- }
reDoWaypoints := mob.Path.Waypoints()
if len(reDoWaypoints) > 0 {
@@ -119,12 +111,6 @@ func IdleMobs(e events.Event) events.ListenerReturn {
continue
}
-
- if currentStep.Waypoint() {
- if mobPathAnnounce {
- mob.Command(`say I've reached a waypoint.`)
- }
- }
}
if nextStep := mob.Path.Next(); nextStep != nil {
@@ -146,8 +132,8 @@ func IdleMobs(e events.Event) events.ListenerReturn {
continue
}
- if mobPathAnnounce {
- mob.Command(`say I'm.... done.`)
+ if mob.HomeRoomId == mob.Character.RoomId {
+ mob.WanderCount = 0
}
}
diff --git a/internal/mobcommands/pathto.go b/internal/mobcommands/pathto.go
index ea3646df..66e8adbf 100644
--- a/internal/mobcommands/pathto.go
+++ b/internal/mobcommands/pathto.go
@@ -1,6 +1,8 @@
package mobcommands
import (
+ "fmt"
+ "math"
"strconv"
"strings"
@@ -16,6 +18,11 @@ func Pathto(rest string, mob *mobs.Mob, room *rooms.Room) (bool, error) {
if rest == `home` {
cantGoHome := mob.GetTempData(`home-impossible`)
if cantGoHome != nil && cantGoHome.(bool) == true {
+ // If can't go home, slowly lose health (10%)
+ // This helps to clean up mobs that get stuck in a weird location, which can
+ // happen for any number of reasons, like players dragging them through portals
+ mob.Character.Health -= int(math.Ceil(float64(mob.Character.HealthMax.Value) / 10))
+ fmt.Println(mob.Character.Health)
return true, nil
}
}
diff --git a/internal/mobs/mobs.go b/internal/mobs/mobs.go
index 0fd0927d..bf4f239f 100644
--- a/internal/mobs/mobs.go
+++ b/internal/mobs/mobs.go
@@ -538,6 +538,14 @@ func (m *Mob) GetAngryCommand() string {
func (m *Mob) GetIdleCommand() string {
+ // Always a 1 in 100 chance it will do nothing for an idle.
+ // This is to prevent requiring Admins to assign an empy idlecommand to mob definitions
+ // while still allowing "no idle command found" behavior to run.
+ // Empty idle commands can still be defined in mobs, however.
+ if util.Rand(100) == 0 {
+ return ``
+ }
+
// First check if the mob has a specific action
if len(m.IdleCommands) > 0 {
return m.IdleCommands[util.Rand(len(m.IdleCommands))]
diff --git a/internal/scripting/room_func.go b/internal/scripting/room_func.go
index 17d7992a..260c09cc 100644
--- a/internal/scripting/room_func.go
+++ b/internal/scripting/room_func.go
@@ -73,12 +73,69 @@ func (r ScriptRoom) SpawnItem(itemId int, inStash bool) {
}
}
-func (r ScriptRoom) GetMobs() []int {
- return r.roomRecord.GetMobs()
+// Optionally can provide a MobId to look for
+func (r ScriptRoom) GetMobs(mobId ...int) []*ScriptActor {
+ actorList := []*ScriptActor{}
+
+ targetMobId := 0
+ if len(mobId) > 0 {
+ targetMobId = mobId[0]
+ }
+
+ for _, mobInstanceId := range r.roomRecord.GetMobs() {
+ a := GetActor(0, mobInstanceId)
+ if a == nil {
+ continue
+ }
+ if targetMobId == 0 || a.MobTypeId() == targetMobId {
+ actorList = append(actorList, a)
+ }
+ }
+ return actorList
}
-func (r ScriptRoom) GetPlayers() []int {
- return r.roomRecord.GetPlayers()
+// Get the first mob of the MobId type provided.
+func (r ScriptRoom) GetMob(mobId int, createIfMissing ...bool) *ScriptActor {
+
+ for _, mobInstanceId := range r.roomRecord.GetMobs() {
+ a := GetActor(0, mobInstanceId)
+ if a == nil {
+ continue
+ }
+
+ if a.MobTypeId() == mobId {
+ return a
+ }
+ }
+
+ if len(createIfMissing) > 0 && createIfMissing[0] {
+ return r.SpawnMob(mobId)
+ }
+
+ return nil
+}
+
+func (r ScriptRoom) GetPlayers() []*ScriptActor {
+ actorList := []*ScriptActor{}
+ for _, userId := range r.roomRecord.GetPlayers() {
+ a := GetActor(userId, 0)
+ if a == nil {
+ continue
+ }
+ actorList = append(actorList, a)
+ }
+ return actorList
+}
+
+func (r ScriptRoom) GetAllActors() []*ScriptActor {
+ actorList := []*ScriptActor{}
+ for _, mobInstanceId := range r.roomRecord.GetMobs() {
+ actorList = append(actorList, GetActor(0, mobInstanceId))
+ }
+ for _, userId := range r.roomRecord.GetPlayers() {
+ actorList = append(actorList, GetActor(userId, 0))
+ }
+ return actorList
}
func (r ScriptRoom) GetContainers() []string {
diff --git a/modules/follow/files/data-overlays/config.yaml b/modules/follow/files/data-overlays/config.yaml
new file mode 100644
index 00000000..11218eaa
--- /dev/null
+++ b/modules/follow/files/data-overlays/config.yaml
@@ -0,0 +1,11 @@
+################################################################################
+# If modified, these settings will be copied into your config overrides
+# folder under `Modules.follow`:
+#
+# Modules:
+# follow:
+# DefaultFollowPeriod: 1 real hour
+################################################################################
+# - DefaultFollowPeriod -
+# Default time a "follow" wears off.
+DefaultFollowPeriod: 10 real minutes
diff --git a/modules/follow/follow.go b/modules/follow/follow.go
index 8162273e..7f776286 100644
--- a/modules/follow/follow.go
+++ b/modules/follow/follow.go
@@ -6,6 +6,7 @@ import (
"strings"
"github.com/GoMudEngine/GoMud/internal/events"
+ "github.com/GoMudEngine/GoMud/internal/gametime"
"github.com/GoMudEngine/GoMud/internal/mobs"
"github.com/GoMudEngine/GoMud/internal/parties"
"github.com/GoMudEngine/GoMud/internal/plugins"
@@ -39,9 +40,10 @@ func init() {
// how to use a struct
//
f := FollowModule{
- plug: plugins.New(`follow`, `1.0`),
- followed: make(map[followId][]followId),
- followers: make(map[followId]followId),
+ plug: plugins.New(`follow`, `1.0`),
+ followed: make(map[followId][]followId),
+ followers: make(map[followId]followId),
+ followLimits: make(map[followId]uint64),
}
//
@@ -65,8 +67,11 @@ func init() {
events.RegisterListener(events.RoomChange{}, f.roomChangeHandler)
events.RegisterListener(events.PlayerDespawn{}, f.playerDespawnHandler)
+ events.RegisterListener(events.MobDeath{}, f.onMobDeath)
+ events.RegisterListener(events.PlayerDeath{}, f.onPlayerDeath)
events.RegisterListener(events.MobIdle{}, f.idleMobHandler, events.First)
events.RegisterListener(events.PartyUpdated{}, f.onPartyChange)
+ events.RegisterListener(events.NewRound{}, f.onNewRound)
}
//////////////////////////////////////////////////////////////////////
@@ -83,8 +88,9 @@ type FollowModule struct {
// Keep a reference to the plugin when we create it so that we can call ReadBytes() and WriteBytes() on it.
plug *plugins.Plugin
- followed map[followId][]followId // key => who's followed. value ([]followId{}) => who's following them
- followers map[followId]followId // key => who's following someone. value => who's being followed
+ followed map[followId][]followId // key => who's followed. value ([]followId{}) => who's following them
+ followers map[followId]followId // key => who's following someone. value => who's being followed
+ followLimits map[followId]uint64 // Key => follower Id, value => round the follow forcibly ends
}
// Intended to be invoked by a script.
@@ -119,7 +125,7 @@ func (f *FollowModule) getFollowers(followTarget followId) []followId {
}
// Add a single follower to a target
-func (f *FollowModule) startFollow(followTarget followId, followSource followId) {
+func (f *FollowModule) startFollow(followTarget followId, followSource followId, followCutoffRoundId ...uint64) {
// Make sure they no longer follow whoever they were before.
f.stopFollowing(followSource)
@@ -130,6 +136,10 @@ func (f *FollowModule) startFollow(followTarget followId, followSource followId)
}
f.followed[followTarget] = append(f.followed[followTarget], followSource)
+
+ if len(followCutoffRoundId) > 0 && followCutoffRoundId[0] > 0 {
+ f.followLimits[followSource] = followCutoffRoundId[0]
+ }
}
// Remove a single follower from whoever they are following (if any)
@@ -155,6 +165,9 @@ func (f *FollowModule) stopFollowing(followSource followId) followId {
}
}
+ // If there was a limit, delete it.
+ delete(f.followLimits, followSource)
+
return wasFollowing
}
@@ -171,6 +184,66 @@ func (f *FollowModule) loseFollowers(followTarget followId) []followId {
// Event Handlers
//
+func (f followId) getFollowIdInstance() (user *users.UserRecord, mob *mobs.Mob) {
+ if f.userId > 0 {
+ return users.GetByUserId(f.userId), nil
+ }
+ if f.mobInstanceId > 0 {
+ return nil, mobs.GetInstance(f.mobInstanceId)
+ }
+ return nil, nil
+}
+
+// Does a cleanup check every round for any follows that have expired.
+func (f *FollowModule) onNewRound(e events.Event) events.ListenerReturn {
+
+ evt := e.(events.NewRound)
+
+ for fId, rNum := range f.followLimits {
+ if rNum > evt.RoundNumber {
+ continue
+ }
+
+ wasFollowing := f.stopFollowing(fId)
+
+ followTargetUser, followTargetMob := wasFollowing.getFollowIdInstance()
+ followSourceUser, followSourceMob := fId.getFollowIdInstance()
+
+ // user being followed?
+ if followTargetUser != nil {
+
+ // user doing the following? Tell both users
+ if followSourceUser != nil {
+ followTargetUser.SendText(fmt.Sprintf(`%s stopped following you.`, followSourceUser.Character.Name))
+ followSourceUser.SendText(fmt.Sprintf(`You are no longer following %s.`, followTargetUser.Character.Name))
+ continue
+ }
+
+ // mob doing the following? tell the target user
+ if followSourceMob != nil {
+ followTargetUser.SendText(fmt.Sprintf(`%s stopped following you.`, followSourceMob.Character.Name))
+ continue
+ }
+
+ continue
+ }
+
+ // mob being followed?
+ if followTargetMob != nil {
+
+ // user doing the following? Tell the following user
+ if followSourceUser != nil {
+ followSourceUser.SendText(fmt.Sprintf(`You are no longer following %s.`, followTargetMob.Character.Name))
+ }
+
+ continue
+ }
+
+ }
+
+ return events.Continue
+}
+
// If players make changes (into/out of party)
// Just make sure they aren't following anyone.
// This is just basic cleanup/precaution
@@ -245,6 +318,9 @@ func (f *FollowModule) roomChangeHandler(e events.Event) events.ListenerReturn {
if mob := mobs.GetInstance(fId.mobInstanceId); mob != nil {
if fromRoom.RoomId == mob.Character.RoomId {
mob.Command(followExitName, .25)
+ // Count follows as wandering
+ // This way if following ends, many/most mobs will head home.
+ mob.WanderCount++
continue
}
@@ -285,6 +361,28 @@ func (f *FollowModule) playerDespawnHandler(e events.Event) events.ListenerRetur
return events.Continue
}
+func (f *FollowModule) onMobDeath(e events.Event) events.ListenerReturn {
+ evt, typeOk := e.(events.MobDeath)
+ if !typeOk {
+ return events.Cancel
+ }
+
+ f.loseFollowers(followId{mobInstanceId: evt.MobId})
+
+ return events.Continue
+}
+
+func (f *FollowModule) onPlayerDeath(e events.Event) events.ListenerReturn {
+ evt, typeOk := e.(events.PlayerDeath)
+ if !typeOk {
+ return events.Cancel
+ }
+
+ f.loseFollowers(followId{userId: evt.UserId})
+
+ return events.Continue
+}
+
//
// Commands
//
@@ -305,12 +403,26 @@ func (f *FollowModule) followUserCommand(rest string, user *users.UserRecord, ro
followTargetName := args[0]
followAction := `follow`
+ followEndRound := uint64(0)
if rest == `stop` || rest == `lose` {
followAction = rest
followTargetName = ``
}
+ gd := gametime.GetDate(util.GetRoundCount())
+
+ if len(args) > 1 {
+ followEndRound = gd.AddPeriod(strings.Join(args[1:], ` `))
+ } else if followPeriod, ok := f.plug.Config.Get(`DefaultFollowPeriod`).(string); ok {
+ followEndRound = gd.AddPeriod(followPeriod)
+ }
+
+ // in case something went wrong, we still want to cap it.
+ if followEndRound <= util.GetRoundCount() {
+ followEndRound = gd.AddPeriod(`5 real minutes`)
+ }
+
userId, mobInstId := 0, 0
if len(followTargetName) > 0 {
userId, mobInstId = room.FindByName(followTargetName)
@@ -379,7 +491,7 @@ func (f *FollowModule) followUserCommand(rest string, user *users.UserRecord, ro
// Default behavior is follow
if followCommandTarget.userId > 0 {
- f.startFollow(followCommandTarget, followCommandSource)
+ f.startFollow(followCommandTarget, followCommandSource, followEndRound)
targetUser := users.GetByUserId(followCommandTarget.userId)
@@ -397,7 +509,7 @@ func (f *FollowModule) followUserCommand(rest string, user *users.UserRecord, ro
if targetMob.HatesAlignment(user.Character.Alignment) {
user.SendText(fmt.Sprintf(`%s won't let you follow them.`, targetMob.Character.Name))
} else {
- f.startFollow(followCommandTarget, followCommandSource)
+ f.startFollow(followCommandTarget, followCommandSource, followEndRound)
user.SendText(fmt.Sprintf(`You start following %s.`, targetMob.Character.Name))
}
@@ -420,12 +532,26 @@ func (f *FollowModule) followMobCommand(rest string, mob *mobs.Mob, room *rooms.
followTargetName := args[0]
followAction := `follow`
+ followEndRound := uint64(0)
if rest == `stop` || rest == `lose` {
followAction = rest
followTargetName = ``
}
+ gd := gametime.GetDate(util.GetRoundCount())
+
+ if len(args) > 1 {
+ followEndRound = gd.AddPeriod(strings.Join(args[1:], ` `))
+ } else if followPeriod, ok := f.plug.Config.Get(`DefaultFollowPeriod`).(string); ok {
+ followEndRound = gd.AddPeriod(followPeriod)
+ }
+
+ // in case something went wrong, we still want to cap it.
+ if followEndRound <= util.GetRoundCount() {
+ followEndRound = gd.AddPeriod(`5 real minutes`)
+ }
+
userId, mobInstId := 0, 0
if len(followTargetName) > 0 {
userId, mobInstId = room.FindByName(followTargetName)
@@ -484,7 +610,7 @@ func (f *FollowModule) followMobCommand(rest string, mob *mobs.Mob, room *rooms.
if followCommandTarget.userId > 0 {
- f.startFollow(followCommandTarget, followCommandSource)
+ f.startFollow(followCommandTarget, followCommandSource, followEndRound)
targetUser := users.GetByUserId(followCommandTarget.userId)
@@ -495,7 +621,7 @@ func (f *FollowModule) followMobCommand(rest string, mob *mobs.Mob, room *rooms.
if followCommandTarget.mobInstanceId > 0 {
- f.startFollow(followCommandTarget, followCommandSource)
+ f.startFollow(followCommandTarget, followCommandSource, followEndRound)
return true, nil
}