Merge pull request #113 from SamuelT24/develop

spellbook: Add some new magic words
This commit is contained in:
Little Cat 2023-11-08 23:57:32 -04:00 committed by GitHub
commit a5ecbb8b1e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 195 additions and 21 deletions

View file

@ -618,6 +618,7 @@ dclass DistributedToon : DistributedPlayer {
setNeverStartedPartyRefunded(uint64, int8, uint16) ownrecv; setNeverStartedPartyRefunded(uint64, int8, uint16) ownrecv;
setDISLname(string) ram; setDISLname(string) ram;
setDISLid(uint32) ram db airecv; setDISLid(uint32) ram db airecv;
toggleSleep() ownrecv;
}; };
dclass DistributedCCharBase : DistributedObject { dclass DistributedCCharBase : DistributedObject {

View file

@ -61,6 +61,7 @@ class LocalAvatar(DistributedAvatar.DistributedAvatar, DistributedSmoothNode.Dis
self.soundRun = None self.soundRun = None
self.soundWalk = None self.soundWalk = None
self.sleepFlag = 0 self.sleepFlag = 0
self.noSleep = 0
self.isDisguised = 0 self.isDisguised = 0
self.movingFlag = 0 self.movingFlag = 0
self.swimmingFlag = 0 self.swimmingFlag = 0
@ -984,7 +985,7 @@ class LocalAvatar(DistributedAvatar.DistributedAvatar, DistributedSmoothNode.Dis
return return
def gotoSleep(self): def gotoSleep(self):
if not self.sleepFlag: if not self.sleepFlag and not self.noSleep:
self.b_setAnimState('Sleep', self.animMultiplier) self.b_setAnimState('Sleep', self.animMultiplier)
self.sleepFlag = 1 self.sleepFlag = 1

View file

@ -74,7 +74,8 @@ class BattleCalculatorAI:
return (1, 95) return (1, 95)
else: else:
return (0, 0) return (0, 0)
if self.toonsAlwaysHit: toon = self.battle.getToon(attackIndex)
if self.toonsAlwaysHit or toon.instantKillMode:
return (1, 95) return (1, 95)
elif self.toonsAlwaysMiss: elif self.toonsAlwaysMiss:
return (0, 0) return (0, 0)
@ -529,6 +530,9 @@ class BattleCalculatorAI:
if attackLevel == -1 and not atkTrack == FIRE: if attackLevel == -1 and not atkTrack == FIRE:
result = LURE_SUCCEEDED result = LURE_SUCCEEDED
elif atkTrack != TRAP: elif atkTrack != TRAP:
toon = self.battle.getToon(toonId)
if atkTrack != HEAL and toon.instantKillMode:
attackDamage = 32767
result = attackDamage result = attackDamage
if atkTrack == HEAL: if atkTrack == HEAL:
if not self.__attackHasHit(attack, suit=0): if not self.__attackHasHit(attack, suit=0):

View file

@ -176,7 +176,6 @@ class MagicWord(DirectObject):
def handleWord(self, invoker, avId, toon, *args): def handleWord(self, invoker, avId, toon, *args):
raise NotImplementedError raise NotImplementedError
class SetHP(MagicWord): class SetHP(MagicWord):
aliases = ["hp", "setlaff", "laff"] aliases = ["hp", "setlaff", "laff"]
desc = "Sets the target's current laff." desc = "Sets the target's current laff."
@ -200,7 +199,6 @@ class SetHP(MagicWord):
toon.b_setHp(hp) toon.b_setHp(hp)
return "{}'s laff has been set to {}.".format(toon.getName(), hp) return "{}'s laff has been set to {}.".format(toon.getName(), hp)
class SetMaxHP(MagicWord): class SetMaxHP(MagicWord):
aliases = ["maxhp", "setmaxlaff", "maxlaff"] aliases = ["maxhp", "setmaxlaff", "maxlaff"]
desc = "Sets the target's max laff." desc = "Sets the target's max laff."
@ -219,7 +217,6 @@ class SetMaxHP(MagicWord):
toon.toonUp(maxhp) toon.toonUp(maxhp)
return "{}'s max laff has been set to {}.".format(toon.getName(), maxhp) return "{}'s max laff has been set to {}.".format(toon.getName(), maxhp)
class ToggleOobe(MagicWord): class ToggleOobe(MagicWord):
aliases = ["oobe"] aliases = ["oobe"]
desc = "Toggles the out of body experience mode, which lets you move the camera freely." desc = "Toggles the out of body experience mode, which lets you move the camera freely."
@ -232,7 +229,6 @@ class ToggleOobe(MagicWord):
base.oobe() base.oobe()
return "Oobe mode has been toggled." return "Oobe mode has been toggled."
class ToggleRun(MagicWord): class ToggleRun(MagicWord):
aliases = ["run"] aliases = ["run"]
desc = "Toggles run mode, which gives you a faster running speed." desc = "Toggles run mode, which gives you a faster running speed."
@ -308,8 +304,6 @@ class Inventory(MagicWord):
toon.d_setInventory(toon.inventory.makeNetString()) toon.d_setInventory(toon.inventory.makeNetString())
return ("Zeroing inventory for " + toon.getName() + ".") return ("Zeroing inventory for " + toon.getName() + ".")
class SetPinkSlips(MagicWord): class SetPinkSlips(MagicWord):
# this command gives the target toon the specified amount of pink slips # this command gives the target toon the specified amount of pink slips
# default is 255 # default is 255
@ -332,6 +326,51 @@ class AbortMinigame(MagicWord):
messenger.send("minigameAbort") messenger.send("minigameAbort")
return "Requested minigame abort." return "Requested minigame abort."
class SkipMiniGolfHole(MagicWord):
aliases = ["skipgolfhole", "skipgolf", "skiphole"]
desc = "Skips the current golf hole."
execLocation = MagicWordConfig.EXEC_LOC_SERVER
arguments = []
def handleWord(self, invoker, avId, toon, *args):
from toontown.golf.DistributedGolfCourseAI import DistributedGolfCourseAI
course = None
for do in simbase.air.doId2do.values(): # For all doids, check whether it's a golf course, then check if our target is part of it.
if isinstance(do, DistributedGolfCourseAI):
if invoker.doId in do.avIdList:
course = do
break
if not course:
return "You aren't in a golf course!"
if course.isPlayingLastHole(): # If the Toon is on the final hole, calling holeOver() will softlock, so instead we move onto the reward screen.
course.demand('WaitReward')
else:
course.holeOver()
return "Skipped the current hole."
class AbortGolfCourse(MagicWord):
aliases = ["abortminigolf", "abortgolf", "abortcourse", "leavegolf", "leavecourse"]
desc = "Aborts the current golf course."
execLocation = MagicWordConfig.EXEC_LOC_SERVER
arguments = []
def handleWord(self, invoker, avId, toon, *args):
from toontown.golf.DistributedGolfCourseAI import DistributedGolfCourseAI
course = None
for do in simbase.air.doId2do.values(): # For all doids, check whether it's a golf course, then check if our target is part of it.
if isinstance(do, DistributedGolfCourseAI):
if invoker.doId in do.avIdList:
course = do
break
if not course:
return "You aren't in a golf course!"
course.setCourseAbort()
return "Aborted golf course."
class Minigame(MagicWord): class Minigame(MagicWord):
aliases = ["mg"] aliases = ["mg"]
desc = "Teleport to or request the next trolley minigame." desc = "Teleport to or request the next trolley minigame."
@ -516,7 +555,7 @@ class BossBattle(MagicWord):
if not start: if not start:
respText += " in Frolic state" respText += " in Frolic state"
return respText + ", teleporting...", ["cogHQLoader", "cogHQBossBattle", "movie" if start else "teleportIn", boss.getHoodId(), boss.zoneId, 0] return respText + ", teleporting...", toon.doId, ["cogHQLoader", "cogHQBossBattle", "movie" if start else "teleportIn", boss.getHoodId(), boss.zoneId, 0]
elif command == "list": elif command == "list":
# List all the ongoing boss battles. # List all the ongoing boss battles.
@ -558,7 +597,7 @@ class BossBattle(MagicWord):
return "Index out of range!" return "Index out of range!"
boss = AllBossCogs[index] boss = AllBossCogs[index]
return "Teleporting to boss battle...", ["cogHQLoader", "cogHQBossBattle", "", boss.getHoodId(), boss.zoneId, 0] return "Teleporting to boss battle...", toon.doId, ["cogHQLoader", "cogHQBossBattle", "", boss.getHoodId(), boss.zoneId, 0]
# The following commands needs the invoker to be in a boss battle. # The following commands needs the invoker to be in a boss battle.
@ -597,13 +636,129 @@ class BossBattle(MagicWord):
# The create command is already described when the invoker is not in a battle. These are the commands # The create command is already described when the invoker is not in a battle. These are the commands
# they can use INSIDE the battle. # they can use INSIDE the battle.
return respText + f"Unknown command: \"{command}\". Valid commands: \"start\", \"stop\", \"skip\", \"final\", \"kill\"." return f"Unknown command: \"{command}\". Valid commands: \"start\", \"stop\", \"skip\", \"final\", \"kill\"."
def __destroyBoss(self, boss): def __destroyBoss(self, boss):
bossZone = boss.zoneId bossZone = boss.zoneId
boss.requestDelete() boss.requestDelete()
self.air.deallocateZone(bossZone) self.air.deallocateZone(bossZone)
class GlobalTeleport(MagicWord):
aliases = ["globaltp", "tpaccess"]
desc = "Enables teleport access to all zones."
execLocation = MagicWordConfig.EXEC_LOC_SERVER
def handleWord(self, invoker, avId, toon, *args):
from toontown.toonbase import ToontownGlobals
toon.b_setHoodsVisited(ToontownGlobals.HoodsForTeleportAll)
toon.b_setTeleportAccess(ToontownGlobals.HoodsForTeleportAll)
return f"Enabled teleport access to all zones for {toon.getName()}."
class Teleport(MagicWord):
aliases = ["tp", "goto"]
desc = "Teleport to a specified zone."
execLocation = MagicWordConfig.EXEC_LOC_SERVER
arguments = [("zoneName", str, False, '')]
def handleWord(self, invoker, avId, toon, *args):
from toontown.hood import ZoneUtil
from toontown.toonbase import ToontownGlobals
zoneName = args[0]
# Can add stuff like streets to this too if you wanted, but if you do you'll want it to be a valid zone on that street. eg: 2100 is invalid, but any value 2101 to 2156 is fine.
# so if you wanted to add a silly street key, theroetically you could do something like this: 'sillystreet': ToontownGlobals.SillyStreet +1,
zoneName2Id = {'ttc': ToontownGlobals.ToontownCentral,
'dd': ToontownGlobals.DonaldsDock,
'dg': ToontownGlobals.DaisyGardens,
'mml': ToontownGlobals.MinniesMelodyland,
'tb': ToontownGlobals.TheBrrrgh,
'ddl': ToontownGlobals.DonaldsDreamland,
'gs': ToontownGlobals.GoofySpeedway,
'oz': ToontownGlobals.OutdoorZone,
'aa': ToontownGlobals.OutdoorZone,
'gz': ToontownGlobals.GolfZone,
'sbhq': ToontownGlobals.SellbotHQ,
'factory': ToontownGlobals.SellbotFactoryExt,
'cbhq': ToontownGlobals.CashbotHQ,
'lbhq': ToontownGlobals.LawbotHQ,
'bbhq': ToontownGlobals.BossbotHQ}
try:
zone = zoneName2Id[zoneName]
except KeyError:
return "Unknown zone name!"
return f"Requested to teleport {toon.getName()} to zone {zone}.", toon.doId, [ZoneUtil.getBranchLoaderName(zone), ZoneUtil.getToonWhereName(zone), "", ZoneUtil.getHoodId(zone), zone, 0]
class ToggleSleep(MagicWord):
aliases = ["sleep", "nosleep", "neversleep", "togglesleeping", "insomnia"]
desc = "Toggles sleeping for the target."
execLocation = MagicWordConfig.EXEC_LOC_SERVER
def handleWord(self, invoker, avId, toon, *args):
toon.d_toggleSleep()
return f"Toggled sleeping for {toon.getName()}."
class ToggleImmortal(MagicWord):
aliases = ["immortal", "invincible", "invulnerable"]
desc = "Toggle immortal mode. This makes the Toon immune to damage."
execLocation = MagicWordConfig.EXEC_LOC_SERVER
def handleWord(self, invoker, avId, toon, *args):
toon.setImmortalMode(not toon.immortalMode)
return f"Toggled immortal mode for {toon.getName()}"
class ToggleGhost(MagicWord):
aliases = ["ghost", "invisible", "spy"]
desc = "Toggle ghost mode."
execLocation = MagicWordConfig.EXEC_LOC_SERVER
def handleWord(self, invoker, avId, toon, *args):
# 1 is for the attic, 2 enables you to see yourself other ghost toons. 0 is off.
toon.b_setGhostMode(2 if not toon.ghostMode else 0) # As it's primarily for moderation purposes, we set it to 2 here, or 0 if it's already on.
return f"Toggled ghost mode for {toon.getName()}"
class SetGM(MagicWord):
aliases = ["icon", "seticon", "gm", "gmicon", "setgmicon"]
desc = "Sets the GM icon on the target."
execLocation = MagicWordConfig.EXEC_LOC_SERVER
arguments = [("iconRequest", int, False, 0),]
def handleWord(self, invoker, avId, toon, *args):
from toontown.toonbase import TTLocalizer
iconRequest = args[0]
if iconRequest > len(TTLocalizer.GM_NAMES) or iconRequest < 0:
return "Invalid GM icon ID!"
toon.b_setGM(0) # Reset it first, otherwise the Toon keeps the old icon, but the name still changes.
toon.b_setGM(iconRequest)
return f"GM icon set to {iconRequest} for {toon.getName()}"
class SetMaxCarry(MagicWord):
aliases = ["gagpouch", "pouch", "gagcapacity"]
desc = "Set a Toon's gag pouch size."
execLocation = MagicWordConfig.EXEC_LOC_SERVER
arguments = [("pouchSize", int, True)]
def handleWord(self, invoker, avId, toon, *args):
pouchSize = args[0]
if pouchSize > 255 or pouchSize < 0:
return "Specified pouch size must be between 1 and 255."
toon.b_setMaxCarry(pouchSize)
return f"Set gag pouch size to {pouchSize} for {toon.getName()}"
class ToggleInstantKill(MagicWord):
aliases = ["instantkill", "instakill"]
desc = "Toggle the ability to instantly kill a Cog with any gag."
execLocation = MagicWordConfig.EXEC_LOC_SERVER
def handleWord(self, invoker, avId, toon, *args):
toon.setInstantKillMode(not toon.instantKillMode)
return f"Toggled instant-kill mode for {toon.getName()}"
class Fireworks(MagicWord): class Fireworks(MagicWord):
aliases = ["firework"] aliases = ["firework"]
desc = "Starts a firework show." desc = "Starts a firework show."

View file

@ -275,6 +275,7 @@ class ToontownMagicWordManager(DistributedObject.DistributedObject):
hoodId = place.loader.hood.id hoodId = place.loader.hood.id
if avId == 0: if avId == 0:
avId = -1 avId = -1
try:
place.fsm.forceTransition('teleportOut', place.fsm.forceTransition('teleportOut',
[{"loader": loaderId, [{"loader": loaderId,
"where": whereId, "where": whereId,
@ -283,3 +284,5 @@ class ToontownMagicWordManager(DistributedObject.DistributedObject):
"zoneId": zoneId, "zoneId": zoneId,
"shardId": None, "shardId": None,
"avId": avId}]) "avId": avId}])
except Exception: # Most likely cause is the place the avatar is in has no teleportOut state, for example, boss lobbies.
place.fsm.request('DFAReject') # We have to do this, or the avatar will be stuck.

View file

@ -2528,7 +2528,7 @@ class DistributedToon(DistributedPlayer.DistributedPlayer, Toon.Toon, Distribute
self._handleGMName() self._handleGMName()
def _handleGMName(self): def _handleGMName(self):
name = self.name name = self._name
self.setDisplayName(name) self.setDisplayName(name)
if self._isGM: if self._isGM:
self.setNametagStyle(5) self.setNametagStyle(5)
@ -2589,3 +2589,6 @@ class DistributedToon(DistributedPlayer.DistributedPlayer, Toon.Toon, Distribute
def getTransitioning(self): def getTransitioning(self):
return self.transitioning return self.transitioning
def toggleSleep(self):
base.localAvatar.noSleep = not base.localAvatar.noSleep

View file

@ -155,6 +155,7 @@ class DistributedToonAI(DistributedPlayerAI.DistributedPlayerAI, DistributedSmoo
self.savedCheesyExpireTime = 0 self.savedCheesyExpireTime = 0
self.ghostMode = 0 self.ghostMode = 0
self.immortalMode = 0 self.immortalMode = 0
self.instantKillMode = 0
self.numPies = 0 self.numPies = 0
self.pieType = 0 self.pieType = 0
self._isGM = False self._isGM = False
@ -2375,6 +2376,9 @@ class DistributedToonAI(DistributedPlayerAI.DistributedPlayerAI, DistributedSmoo
def setImmortalMode(self, flag): def setImmortalMode(self, flag):
self.immortalMode = flag self.immortalMode = flag
def setInstantKillMode(self, flag):
self.instantKillMode = flag
def b_setSpeedChatStyleIndex(self, index): def b_setSpeedChatStyleIndex(self, index):
self.setSpeedChatStyleIndex(index) self.setSpeedChatStyleIndex(index)
self.d_setSpeedChatStyleIndex(index) self.d_setSpeedChatStyleIndex(index)
@ -4129,6 +4133,9 @@ class DistributedToonAI(DistributedPlayerAI.DistributedPlayerAI, DistributedSmoo
zoneId]) zoneId])
self.air.send(dg) self.air.send(dg)
def d_toggleSleep(self):
self.sendUpdate('toggleSleep', [])
@staticmethod @staticmethod
def staticGetLogicalZoneChangeAllEvent(): def staticGetLogicalZoneChangeAllEvent():
return 'DOLogicalChangeZone-all' return 'DOLogicalChangeZone-all'