Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- from core.anomaly.base import BaseAnomaly
- from core.anomaly.helper import isInView, isPlayerNearby, spawnInArea
- from core.helper import partial
- from siege import Locale, Tuning, game
- from siege.component import MonsterPlacementType
- from siege.log import Log
- from siege.util import Random, Rect, TileVector, Timer, Vector, seconds
- from siege.world import World
- class SwarmAnomaly(BaseAnomaly):
- TUNING = Tuning.anomaly.SWARM
- VERSION = 2
- def __init__(self):
- BaseAnomaly.__init__(self)
- self.name = "swarm"
- self.maxMonsterAmount = 0
- self.biomes = [] # Biomes the event can occur in
- self.monster = None
- self.swarmSpeed = self.TUNING.SWARM_SPEED
- self.spawnArea = Vector(200, 500) # Range in Width and height that the swarm can spawn in
- self.swarmPosition = Vector(0, 0)
- self.monsterAmount = 0
- self.swarmDirection = 0
- self.monsterEntities = []
- self.setTimer()
- self.durationTimer = Timer()
- self.realm = None
- self.MONSTER_TUNING = None
- def occur(self):
- Log.info("Swarm Anomaly has occured")
- self.realm = World.get().realm
- conflictRegionArea = self.getRandomRegionArea()
- self.swarmPosition = conflictRegionArea.center.asVector()
- self.mapPosition = self.swarmPosition
- self.addMarker(self.realm, Locale.get("SwarmAnomalyMarker"))
- self.notifyBegin("Swarm")
- self.swarmDirection = Random.get([-1, 1])
- biome = self.realm.biomeTracker.getBiomeInfo(self.swarmPosition).id
- possibleMonsters = [monster for monster in game.monster.getMonstersForBiome(biome) if not monster.monster.isParagon and monster.monster.hostile is True and not monster.monster.isSpecial and monster.monster.placementType is not MonsterPlacementType.InWater]
- if possibleMonsters == []:
- Log.debug("No possible monsters, assigning all monsters instead")
- Log.debug("Possible Monsters: {}".format(possibleMonsters))
- Log.debug("Biome: {}".format(biome))
- possibleMonsters = [monster for monster in game.monster.allMonsterTypes if not monster.monster.isParagon and monster.monster.hostile is True and not monster.monster.isSpecial and monster.monster.placementType is not MonsterPlacementType.InWater]
- self.monster = Random.get(possibleMonsters)
- if self.monster is None:
- Log.debug("Swarm monster chosen was was None")
- Log.debug("Possible Monsters: {}".format(possibleMonsters))
- Log.debug("Biome: {}".format(biome))
- self.MONSTER_TUNING = self.getMonsterTuning(self.monster.content.getName())
- self.maxMonsterAmount = self.MONSTER_TUNING.SIZE.getRandom()
- self.biomes = self.monster.monster.biomes
- self.monsterAmount = self.maxMonsterAmount
- self.durationTimer = Timer(self.duration.getRandom())
- self.active = True
- def update(self, frametime): # only runs when self.active is true
- self.durationTimer.update(frametime)
- if self.realm is None:
- self.realm = World.get().realm
- if self.monsterAmount > self.maxMonsterAmount:
- self.monsterAmount = self.maxMonsterAmount
- if len(self.monsterEntities) > 0: # If there's a monster alive, don't move the swarm, instead, average the monster positions to get the swarm position
- sumVector = Vector(0, 0)
- basePos = self.monsterEntities[0].getPosition()
- for entity in self.monsterEntities:
- sumVector += entity.getPosition() - basePos
- meanVector = sumVector / len(self.monsterEntities)
- self.swarmPosition = meanVector + basePos
- else:
- self.swarmPosition.move(self.swarmSpeed * self.swarmDirection * frametime / seconds(1), 0)
- # biome = self.realm.biomeTracker.getBiomeInfo(self.swarmPosition).id
- # if biome not in self.biomes:
- # self.swarmDirection *= -1
- tileSwarmPosition = TileVector(self.swarmPosition)
- tileSwarmPosition.loop(self.realm.size.loopTileWidth)
- tileSwarmPosition.x = max(1, tileSwarmPosition.x)
- tileSwarmPosition.x = min(tileSwarmPosition.x, self.realm.size.tileWidth - 1)
- tileSwarmPosition.y = self.realm.biomeTracker.undergroundThreshold[tileSwarmPosition.x]
- tileSwarmPosition.move(0, -10)
- self.swarmPosition.y = tileSwarmPosition.asVector().y
- self.mapPosition = self.swarmPosition
- self.updateMarker(self.realm)
- for monster in self.monsterEntities:
- if monster.stats.HP.get() <= 0:
- # Log.debug("Swarm Monster Destroyed")
- self.monsterEntities.remove(monster)
- self.handleCloseEntities()
- self.handleDistantEntities()
- if self.monsterAmount + len(self.monsterEntities) <= 0 or self.durationTimer.expired():
- monsterInScreen = False
- for monster in self.monsterEntities:
- if not isInView(monster):
- # Log.info("Despawning swarm monster: {}".format(monster))
- monster.destroy(unload=True)
- self.monsterEntities.remove(monster)
- else:
- monsterInScreen = True
- if monsterInScreen:
- self.durationTimer.reset(seconds(30))
- else:
- Log.info("Swarm Anomaly has ended")
- self.removeMarker(self.realm)
- self.notifyEnd("Swarm")
- self.__init__() # Anomaly is over, reset the timer and everything for when it shows up again
- # Calling __init__() instead of separating this into a start() class in order to match Crea's coding guidelines
- def handleDistantEntities(self):
- if not isPlayerNearby(self.swarmPosition, self.realm):
- for monster in self.monsterEntities:
- if not isInView(monster):
- # Log.debug(str(monster.stats.HP.get()))
- # Log.info("Despawning swarm monster: {}".format(monster))
- monster.destroy(unload=True)
- self.monsterEntities.remove(monster)
- self.monsterAmount += 1
- def handleCloseEntities(self):
- if isPlayerNearby(self.swarmPosition, self.realm, 100): # We add a buffer so that there's an area after spawning where they don't immediately despawn
- for _ in range(self.monsterAmount):
- monster = spawnInArea(self.monster.content.getName(), Rect(self.swarmPosition, self.spawnArea), self.realm, levelMultiplier=0.5, levelVariance=(-3, 3))
- if monster is not None: # Sometimes the monster doesn't have a place to spawn, and returns None instead
- # Log.info("Spawning swarm monster: {}".format(self.monster.content.getName()))
- monster.monster.core.initializeSwarm()
- monster.setName(monster.name + " " + Locale.get("SwarmSuffix"))
- self.monsterEntities.append(monster)
- self.monsterAmount -= 1
- def getMonsterTuning(self, monsterName):
- for MONSTER_TUNING in self.TUNING.MONSTER:
- if self.TUNING.MONSTER.get(MONSTER_TUNING).CONTENT_NAME == monsterName:
- return self.TUNING.MONSTER.get(MONSTER_TUNING)
- return self.TUNING.MONSTER.DEFAULT
- def save(self, stream):
- # Map Marker UID
- if self.markerUid is not None:
- stream.writeUint16(self.markerUid)
- else:
- stream.writeUint16(0)
- # Timer
- stream.writeUint32(self.timer.remaining())
- # Duration
- stream.writeUint32(self.durationTimer.remaining())
- # Monster Amount
- actualMonsterAmount = self.monsterAmount + len(self.monsterEntities)
- stream.writeUint16(actualMonsterAmount)
- # Maximum Monster Amount
- stream.writeUint16(self.maxMonsterAmount)
- # Swarm position
- stream.writeVector(self.swarmPosition)
- # Swarm Direction
- stream.writeFloat(self.swarmDirection)
- # Active
- stream.writeBool(self.active)
- # Monster
- if self.active:
- stream.writeString(self.monster.content.getName())
- else:
- stream.writeString('')
- # Realm
- if self.realm is not None:
- stream.writeUint32(self.realm.uid)
- else:
- stream.writeUint32(0)
- def load(self, stream, systemVersion, anomalyVersion):
- # Map Marker UID
- if anomalyVersion > 1:
- self.markerUid = stream.readUint16()
- if self.markerUid == 0:
- self.markerUid = None
- # Timer
- self.timer.reset(stream.readUint32())
- if self.timer.remaining() > self.timeRange.max:
- self.setTimer()
- # Duration
- self.durationTimer.reset(stream.readUint32())
- if self.durationTimer.remaining() > self.duration.max:
- self.durationTimer = Timer(self.duration.getRandom())
- # Monster Amount
- self.monsterAmount = stream.readUint16()
- # Maximum Monster Amount
- self.maxMonsterAmount = stream.readUint16()
- # Swarm Position
- self.swarmPosition = stream.readVector()
- self.mapPosition = self.swarmPosition
- # Swarm Direction
- self.swarmDirection = stream.readFloat()
- # Active
- self.active = stream.readBool()
- # Monster
- monster = stream.readString()
- if monster is not '':
- self.monster = game.content.get(monster).entity
- self.MONSTER_TUNING = self.getMonsterTuning(self.monster.content.getName())
- self.biomes = self.monster.monster.biomes
- # Realm
- realmUid = stream.readUint32()
- if realmUid != 0:
- self.realm = World.get().getRealm(realmUid)
- else:
- self.realm = None
- if anomalyVersion <= 1:
- game.events['map_loaded'].listen(partial(self.purgeMarkers, self.realm, Locale.get("SwarmAnomalyMarker")))
- def loadFailed(self):
- self.removeMarker(World.get().realm)
- self.purgeMarkers(World.get().realm, Locale.get("SwarmAnomalyMarker"))
- self.__init__()
- @staticmethod
- def register():
- game.anomaly.add(SwarmAnomaly())
Advertisement
Add Comment
Please, Sign In to add comment