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 }