JoshButner

Crea Anomaly - swarm.py

Mar 10th, 2022 (edited)
46
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 10.34 KB | None | 0 0
  1. from core.anomaly.base import BaseAnomaly
  2. from core.anomaly.helper import isInView, isPlayerNearby, spawnInArea
  3. from core.helper import partial
  4.  
  5. from siege import Locale, Tuning, game
  6. from siege.component import MonsterPlacementType
  7. from siege.log import Log
  8. from siege.util import Random, Rect, TileVector, Timer, Vector, seconds
  9. from siege.world import World
  10.  
  11.  
  12. class SwarmAnomaly(BaseAnomaly):
  13.     TUNING = Tuning.anomaly.SWARM
  14.     VERSION = 2
  15.  
  16.     def __init__(self):
  17.         BaseAnomaly.__init__(self)
  18.         self.name = "swarm"
  19.  
  20.         self.maxMonsterAmount = 0
  21.         self.biomes = []    # Biomes the event can occur in
  22.         self.monster = None
  23.  
  24.         self.swarmSpeed = self.TUNING.SWARM_SPEED
  25.         self.spawnArea = Vector(200, 500)   # Range in Width and height that the swarm can spawn in
  26.  
  27.         self.swarmPosition = Vector(0, 0)
  28.         self.monsterAmount = 0
  29.         self.swarmDirection = 0
  30.         self.monsterEntities = []
  31.         self.setTimer()
  32.         self.durationTimer = Timer()
  33.         self.realm = None
  34.         self.MONSTER_TUNING = None
  35.  
  36.     def occur(self):
  37.         Log.info("Swarm Anomaly has occured")
  38.         self.realm = World.get().realm
  39.         conflictRegionArea = self.getRandomRegionArea()
  40.         self.swarmPosition = conflictRegionArea.center.asVector()
  41.         self.mapPosition = self.swarmPosition
  42.         self.addMarker(self.realm, Locale.get("SwarmAnomalyMarker"))
  43.         self.notifyBegin("Swarm")
  44.         self.swarmDirection = Random.get([-1, 1])
  45.         biome = self.realm.biomeTracker.getBiomeInfo(self.swarmPosition).id
  46.         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]
  47.         if possibleMonsters == []:
  48.             Log.debug("No possible monsters, assigning all monsters instead")
  49.             Log.debug("Possible Monsters: {}".format(possibleMonsters))
  50.             Log.debug("Biome: {}".format(biome))
  51.             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]
  52.         self.monster = Random.get(possibleMonsters)
  53.         if self.monster is None:
  54.             Log.debug("Swarm monster chosen was was None")
  55.             Log.debug("Possible Monsters: {}".format(possibleMonsters))
  56.             Log.debug("Biome: {}".format(biome))
  57.         self.MONSTER_TUNING = self.getMonsterTuning(self.monster.content.getName())
  58.         self.maxMonsterAmount = self.MONSTER_TUNING.SIZE.getRandom()
  59.         self.biomes = self.monster.monster.biomes
  60.         self.monsterAmount = self.maxMonsterAmount
  61.  
  62.         self.durationTimer = Timer(self.duration.getRandom())
  63.         self.active = True
  64.  
  65.     def update(self, frametime):    # only runs when self.active is true
  66.         self.durationTimer.update(frametime)
  67.         if self.realm is None:
  68.             self.realm = World.get().realm
  69.         if self.monsterAmount > self.maxMonsterAmount:
  70.             self.monsterAmount = self.maxMonsterAmount
  71.         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
  72.             sumVector = Vector(0, 0)
  73.             basePos = self.monsterEntities[0].getPosition()
  74.             for entity in self.monsterEntities:
  75.                 sumVector += entity.getPosition() - basePos
  76.             meanVector = sumVector / len(self.monsterEntities)
  77.             self.swarmPosition = meanVector + basePos
  78.         else:
  79.             self.swarmPosition.move(self.swarmSpeed * self.swarmDirection * frametime / seconds(1), 0)
  80.             # biome = self.realm.biomeTracker.getBiomeInfo(self.swarmPosition).id
  81.             # if biome not in self.biomes:
  82.             #     self.swarmDirection *= -1
  83.  
  84.         tileSwarmPosition = TileVector(self.swarmPosition)
  85.         tileSwarmPosition.loop(self.realm.size.loopTileWidth)
  86.         tileSwarmPosition.x = max(1, tileSwarmPosition.x)
  87.         tileSwarmPosition.x = min(tileSwarmPosition.x, self.realm.size.tileWidth - 1)
  88.         tileSwarmPosition.y = self.realm.biomeTracker.undergroundThreshold[tileSwarmPosition.x]
  89.         tileSwarmPosition.move(0, -10)
  90.         self.swarmPosition.y = tileSwarmPosition.asVector().y
  91.         self.mapPosition = self.swarmPosition
  92.         self.updateMarker(self.realm)
  93.  
  94.         for monster in self.monsterEntities:
  95.             if monster.stats.HP.get() <= 0:
  96.                 # Log.debug("Swarm Monster Destroyed")
  97.                 self.monsterEntities.remove(monster)
  98.  
  99.         self.handleCloseEntities()
  100.         self.handleDistantEntities()
  101.  
  102.         if self.monsterAmount + len(self.monsterEntities) <= 0 or self.durationTimer.expired():
  103.             monsterInScreen = False
  104.             for monster in self.monsterEntities:
  105.                 if not isInView(monster):
  106.                     # Log.info("Despawning swarm monster: {}".format(monster))
  107.                     monster.destroy(unload=True)
  108.                     self.monsterEntities.remove(monster)
  109.                 else:
  110.                     monsterInScreen = True
  111.             if monsterInScreen:
  112.                 self.durationTimer.reset(seconds(30))
  113.             else:
  114.                 Log.info("Swarm Anomaly has ended")
  115.                 self.removeMarker(self.realm)
  116.                 self.notifyEnd("Swarm")
  117.                 self.__init__()  # Anomaly is over, reset the timer and everything for when it shows up again
  118.                 # Calling __init__() instead of separating this into a start() class in order to match Crea's coding guidelines
  119.  
  120.     def handleDistantEntities(self):
  121.         if not isPlayerNearby(self.swarmPosition, self.realm):
  122.             for monster in self.monsterEntities:
  123.                 if not isInView(monster):
  124.                     # Log.debug(str(monster.stats.HP.get()))
  125.                     # Log.info("Despawning swarm monster: {}".format(monster))
  126.                     monster.destroy(unload=True)
  127.                     self.monsterEntities.remove(monster)
  128.                     self.monsterAmount += 1
  129.  
  130.     def handleCloseEntities(self):
  131.         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
  132.             for _ in range(self.monsterAmount):
  133.                 monster = spawnInArea(self.monster.content.getName(), Rect(self.swarmPosition, self.spawnArea), self.realm, levelMultiplier=0.5, levelVariance=(-3, 3))
  134.                 if monster is not None:  # Sometimes the monster doesn't have a place to spawn, and returns None instead
  135.                     # Log.info("Spawning swarm monster: {}".format(self.monster.content.getName()))
  136.                     monster.monster.core.initializeSwarm()
  137.                     monster.setName(monster.name + " " + Locale.get("SwarmSuffix"))
  138.                     self.monsterEntities.append(monster)
  139.                     self.monsterAmount -= 1
  140.  
  141.     def getMonsterTuning(self, monsterName):
  142.         for MONSTER_TUNING in self.TUNING.MONSTER:
  143.             if self.TUNING.MONSTER.get(MONSTER_TUNING).CONTENT_NAME == monsterName:
  144.                 return self.TUNING.MONSTER.get(MONSTER_TUNING)
  145.         return self.TUNING.MONSTER.DEFAULT
  146.  
  147.     def save(self, stream):
  148.         # Map Marker UID
  149.         if self.markerUid is not None:
  150.             stream.writeUint16(self.markerUid)
  151.         else:
  152.             stream.writeUint16(0)
  153.         # Timer
  154.         stream.writeUint32(self.timer.remaining())
  155.         # Duration
  156.         stream.writeUint32(self.durationTimer.remaining())
  157.         # Monster Amount
  158.         actualMonsterAmount = self.monsterAmount + len(self.monsterEntities)
  159.         stream.writeUint16(actualMonsterAmount)
  160.         # Maximum Monster Amount
  161.         stream.writeUint16(self.maxMonsterAmount)
  162.         # Swarm position
  163.         stream.writeVector(self.swarmPosition)
  164.         # Swarm Direction
  165.         stream.writeFloat(self.swarmDirection)
  166.         # Active
  167.         stream.writeBool(self.active)
  168.         # Monster
  169.         if self.active:
  170.             stream.writeString(self.monster.content.getName())
  171.         else:
  172.             stream.writeString('')
  173.         # Realm
  174.         if self.realm is not None:
  175.             stream.writeUint32(self.realm.uid)
  176.         else:
  177.             stream.writeUint32(0)
  178.  
  179.     def load(self, stream, systemVersion, anomalyVersion):
  180.         # Map Marker UID
  181.         if anomalyVersion > 1:
  182.             self.markerUid = stream.readUint16()
  183.             if self.markerUid == 0:
  184.                 self.markerUid = None
  185.         # Timer
  186.         self.timer.reset(stream.readUint32())
  187.         if self.timer.remaining() > self.timeRange.max:
  188.             self.setTimer()
  189.         # Duration
  190.         self.durationTimer.reset(stream.readUint32())
  191.         if self.durationTimer.remaining() > self.duration.max:
  192.             self.durationTimer = Timer(self.duration.getRandom())
  193.         # Monster Amount
  194.         self.monsterAmount = stream.readUint16()
  195.         # Maximum Monster Amount
  196.         self.maxMonsterAmount = stream.readUint16()
  197.         # Swarm Position
  198.         self.swarmPosition = stream.readVector()
  199.         self.mapPosition = self.swarmPosition
  200.         # Swarm Direction
  201.         self.swarmDirection = stream.readFloat()
  202.         # Active
  203.         self.active = stream.readBool()
  204.         # Monster
  205.         monster = stream.readString()
  206.         if monster is not '':
  207.             self.monster = game.content.get(monster).entity
  208.             self.MONSTER_TUNING = self.getMonsterTuning(self.monster.content.getName())
  209.             self.biomes = self.monster.monster.biomes
  210.         # Realm
  211.         realmUid = stream.readUint32()
  212.         if realmUid != 0:
  213.             self.realm = World.get().getRealm(realmUid)
  214.         else:
  215.             self.realm = None
  216.         if anomalyVersion <= 1:
  217.             game.events['map_loaded'].listen(partial(self.purgeMarkers, self.realm, Locale.get("SwarmAnomalyMarker")))
  218.  
  219.     def loadFailed(self):
  220.         self.removeMarker(World.get().realm)
  221.         self.purgeMarkers(World.get().realm, Locale.get("SwarmAnomalyMarker"))
  222.         self.__init__()
  223.  
  224.     @staticmethod
  225.     def register():
  226.         game.anomaly.add(SwarmAnomaly())
  227.  
Advertisement
Add Comment
Please, Sign In to add comment