def __init__(self, caller): self.caller = caller self.helper = Helper(caller) self.name = self.caller.key self.combatStats = self.helper.getMeleeCombatStats(self.caller) self.target = None self.inventory = Inventory(self, caller)
def func(self): # Init combat helper class for logic h = Helper(self.caller) # Check for correct command if not self.args: self.msg("|540Usage: drag <target>|n") return # Check for and error handle designated target target = h.targetHandler(self.target) pass
def func(self): combatant = Combatant(self.caller) if not self.target: self.caller.msg("|430Usage: sunder <target>|n") return # Init combat helper class for logic h = Helper(self.caller) if not h.canFight(self.caller): self.caller.msg("|400You are too injured to act.|n") return # Check for and error handle designated target target = self.caller.search(self.target) victim = combatant.getVictim(self.target) if not target.db.bleed_points: combatant.message( f"{victim.name} |400is dead. You only further mutiliate their body.|n" ) combatant.broadcast( f"{combatant.name} |025further mutilates the corpse of|n {victim.name}|025.|n" ) return loop = CombatLoop(combatant.caller, combatant.target) loop.resolveCommand() # Run logic for cleave command if not self.caller.db.combat_turn: self.msg( "|430You need to wait until it is your turn before you are able to act.|n" ) return combat_stats = h.getMeleeCombatStats(self.caller) target_stats = h.getMeleeCombatStats(target) # Confirm whether object carried is a two handed weapon right_hand_item = combat_stats.get("right_slot", '') rightObject = self.caller.search(right_hand_item) isTwoHanded = True if rightObject.db.twohanded else False left_hand_item = combat_stats.get("left_slot", '') sundersRemaining = self.caller.db.sunder if not isTwoHanded: self.msg( "|430Before you attack you must equip a two-handed weapon using the command equip <weapon name>.|n" ) return if sundersRemaining <= 0: self.caller.msg( "|400You have 0 sunders remaining or do not have the skill.\nPlease choose another action.|n" ) return die_result = h.fayneChecker(combat_stats.get("master_of_arms", 0), combat_stats.get("wylding_hand", 0)) # Get damage result and damage for weapon type attack_result = ( die_result + self.caller.db.weapon_level) - combat_stats.get( "dmg_penalty", 0) - combat_stats.get("weakness", 0) damage = 2 if combat_stats.get("two_handed", False) else 1 target_av = target.db.av shot_location = h.shotFinder(target.db.targetArray) if attack_result >= target.db.av: # Check target left and right slots for items. Decrement material value from right and then left. # If no more items, subtract damage as normal. if target_stats.get("right_slot", ''): # Get item and material value for right slot. right_item = self.caller.search(target.db.right_slot[0], location=target) right_mv = right_item.db.material_value # Decrement one from material value. # Check to make sure it won't go below 0. if (right_mv - 1) <= 0: right_item.db.material_value = 0 right_item.db.broken = True # If two handed, remove from both slots if right_item.db.twohanded: target.db.left_slot.clear() # Remove right slot target.db.right_slot.remove(right_item) self.caller.location.msg_contents( f"{self.caller.key} |025strikes|n (|020{attack_result}|n) |025with great ferocity and sunders|n {target.key}|025's {right_item.key}|n (|400{target.db.av}|n)|025, breaking it.|n" ) else: right_item.db.material_value -= 1 self.caller.location.msg_contents( f"{self.caller.key} |025strikes|n (|020{attack_result}|n) |025with great ferocity and damages|n {target.key}|025's {right_item.key}|n (|400{target.db.av}|n)|025.|n" ) elif target_stats.get("left_slot", ''): # Get item and material value for right slot. left_item = self.caller.search(target.db.left_slot[0], location=target) left_mv = left_item.db.material_value # Decrement one from material value if (left_mv - 1) <= 0: left_item.db.material_value = 0 left_item.db.broken = True # if utils.inherits_from(target, Npc): # target.db.skip_turn = 1 target.db.left_slot.remove(left_item) self.caller.location.msg_contents( f"{self.caller.key} |025strikes|n (|020{attack_result}|n) |025with great ferocity and sunders|n {target.key}|025's {left_item.key}|n (|400{target.db.av}|n)|025, breaking it.|n" ) else: left_item.db.material_value -= 1 self.caller.location.msg_contents( f"{self.caller.key} |025strikes|n (|020{attack_result}|n) |025with great ferocity and damages|n {target.key}|025's {left_item.key}|n (|400{target.db.av}|n)|025.|n" ) # Do damage resolution block elif target_av: # subtract damage from corresponding target stage (shield_value, armor, tough, body) new_av = h.damageSubtractor(damage, target, self.caller) # Update target av to new av score per damageSubtractor target.db.av = new_av self.caller.location.msg_contents( f"{self.caller.key} |025strikes with great ferocity|n (|020{attack_result}|n) |025at|n {target.key} |025and hits|n (|400{target_av}|n), |025dealing|n |430{damage}|n |025damage!|n" ) target.msg( f"|430Your new total Armor Value is {new_av}:\nShield: {target.db.shield}\nArmor Specialist: {target.db.armor_specialist}\nArmor: {target.db.armor}\nTough: {target.db.tough}|n" ) else: self.caller.location.msg_contents( f"{self.caller.key} |025strikes with great ferocity|n (|020{attack_result}|n) |025at|n {target.key}|025's {shot_location} and hits|n (|400{target_av}|n), |025dealing|n |430{damage}|n |025damage!|n" ) # First torso shot always takes body to 0. Does not pass excess damage to bleed points. if shot_location == "torso" and target.db.body > 0: target.db.body = 0 self.caller.location.msg_contents( f"{target.key} |025has been fatally wounded and is now bleeding to death. They will soon be unconscious.|n" ) else: h.deathSubtractor(damage, target, self.caller) # Decrement amount of cleaves from amount in database self.caller.db.sunder -= 1 else: self.caller.location.msg_contents( f"{self.caller.key} |025strikes a devastating blow at|n {target.key}|025, but misses.|n" ) # Clean up # Set self.caller's combat_turn to 0. Can no longer use combat commands. loop.combatTurnOff(self.caller) loop.cleanup()
class Combatant: """ A helper class used to ease readability and flow of combat functions Should be rewritten ultimately to use properties/getters/setters """ def __init__(self, caller): self.caller = caller self.helper = Helper(caller) self.name = self.caller.key self.combatStats = self.helper.getMeleeCombatStats(self.caller) self.target = None self.inventory = Inventory(self, caller) def inventory(self): return self.inventory() @property def isStaggered(self): return self.caller.db.is_staggered @property def canFight(self): if self.caller.db.bleed_points > 0: return True return False @property def cantFight(self): return not self.canFight @property def isAlive(self): return True if self.caller.db.death_points else False def message(self, msg): self.caller.msg(msg) def debugMessage(self, msg): #Is there a way we can broadcast this only to admins? self.caller.msg(msg) def broadcast(self, msg): self.caller.location.msg_contents(msg) def hasTurn(self, message=None): if message and not self.caller.db.combat_turn: self.message(message) return self.caller.db.combat_turn def stabilize(self): return self.caller.db.stabilize def hasStabilize(self, message=None): if message and not self.caller.db.stabilize: self.message(message) return self.stabilize() def medicine(self): return self.caller.db.medicine def battlefieldMedicine(self): return self.caller.db.battlefieldmedicine #Syntactic Sugar def hasMoreBodyThan(self, value): return self.body() > value def hasBody(self, value=None): if value: return self.body() == value return self.body() > 0 def setBody(self, value): self.caller.db.body = value def addBody(self, value): if (self.caller.db.body + value) <= 3: self.caller.db.body += value else: self.setBody(3) def body(self): #self.caller.message(f"Debug body is {self.caller.db.body}") return self.caller.db.body def resilience(self): return self.caller.db.resilience def hasSniper(self): return self.caller.db.sniper def bleedPoints(self): return self.caller.db.bleed_points def atMaxBleedPoints(self): return self.bleedPoints() == self.totalBleedPoints() def atMaxBodyPoints(self): return self.body() == 3 #TODO: Magic Number? def totalBleedPoints(self): return self.resilience() + 3 def missingBleedPoints(self): return self.totalBleedPoints() - self.bleedPoints() def hasBleedPoints(self): return self.bleedPoints() > 0 def setBleedPoints(self, value): self.caller.db.bleed_points = value def addBleedPoints(self, value): if (self.caller.db.bleed_points + value) <= self.totalBleedPoints(): self.caller.db.bleed_points += value else: self.resetBleedPoints() def resetBleedPoints(self): self.setBleedPoints(self.totalBleedPoints()) def atMaxDeathPoints(self): return self.deathPoints() >= 3 def addDeathPoints(self, value): if (self.deathPoints() + value) <= 3: self.caller.db.death_points += value else: self.setDeathPoints(3) def setDeathPoints(self, value, combatant=None): self.caller.db.death_points = value def hasDeathPoints(self, value=None): if value: return self.deathPoints() == value return self.deathPoints() > 0 def missingDeathPoints(self): return 3 - self.deathPoints() def deathPoints(self): return self.caller.db.death_points def chirurgeon(self): return self.caller.db.chirurgeon def inCombat(self): return self.caller.db.in_combat def secondsUntilNextChirurgery(self, current_time): if not self.caller.db.last_chirurgery: return 0 else: seconds_since_last_chirurgery = ( int(current_time) - int(self.caller.db.last_chirurgery)) return 900 - seconds_since_last_chirurgery def setChirurgeryTimer(self, current_time): self.caller.db.last_chirurgery = current_time def secondsUntilNextRepair(self, current_time): if not self.caller.db.last_repair: return 0 else: seconds_since_last_repair = (int(current_time) - int(self.caller.db.last_repair)) return 600 - seconds_since_last_repair def setRepairTimer(self, current_time): self.caller.db.last_repair = current_time def resetTough(self): self.caller.db.tough = self.caller.db.total_tough def addWeakness(self): self.caller.db.weakness = 1 def removeWeakness(self): self.caller.db.weakness = 0 #Now Combat def stunsRemaining(self): return self.caller.db.stun def disarmsRemaining(self): return self.caller.db.disarm def staggersRemaining(self): return self.caller.db.stagger def cleavesRemaining(self): return self.caller.db.cleave def resistsRemaining(self): return self.caller.db.resist def hasStunsRemaining(self, message=None): if message and self.stunsRemaining() <= 0: self.message(message) return self.stunsRemaining() def hasResistsRemaining(self, message=None): if message and self.resistsRemaining() <= 0: self.message(message) return self.resistsRemaining() def hasDisarmsRemaining(self, message=None): if message and self.disarmsRemaining() <= 0: self.message(message) return self.disarmsRemaining() def hasStaggersRemaining(self, message=None): if message and self.staggersRemaining() <= 0: self.message(message) return self.staggersRemaining() def hasCleavesRemaining(self, message=None): if message and self.cleavesRemaining() <= 0: self.message(message) return self.cleavesRemaining() def getRightHand(self): return self.combatStats.get("right_slot", '') def getLeftHand(self): return self.combatStats.get("left_slot", '') def getShield(self): right_hand = self.getRightHand() left_hand = self.getLeftHand() if right_hand and right_hand.db.is_shield and right_hand.db.broken == False: return right_hand, "right arm" elif left_hand and left_hand.db.is_shield and left_hand.db.broken == False: return left_hand, "left arm" else: return None, None def isArmed(self, message=None): if message and not self.inventory.getWeapon(): self.message(message) return False else: return True def isUnarmed(self, message=None): if message and self.isArmed(): self.message(message) return False else: return True def hitsAttack(self, difficulty, victimAv, message): result = self.rollAttack(difficulty) if (result >= victimAv): return True else: if message: self.broadcast(message) return False def rollAttack(self, maneuver_difficulty=0): die_result = self.helper.fayneChecker( self.combatStats.get("master_of_arms", 0), self.combatStats.get("wylding_hand", 0)) stagger_penalty = 0 if (self.isStaggered): stagger_penalty = 1 self.caller.db.is_staggered = False # Get damage result and damage for weapon type attack_result = ( die_result + self.caller.db.weapon_level) - self.combatStats.get( "dmg_penalty", 0) - self.combatStats.get( "weakness", 0) - maneuver_difficulty - stagger_penalty return attack_result def hasTwoHandedWeapon(self, message=None): if message and not self.isTwoHanded(): self.message(message) return self.isTwoHanded() def isTwoHanded(self): two_handed = self.getRightHand() == self.getLeftHand() return two_handed @property def av(self): return self.caller.db.av def determineHitLocation(self, victim): return self.helper.shotFinder(self.caller.db.targetArray) def hasWeakness(self, message=None): weakness = self.combatStats.get("weakness", 0) if message and weakness: self.message(message) return weakness def setStuns(self, value): self.caller.db.stun = value def setResists(self, value): self.caller.db.resist = value def setDisarms(self, value): self.caller.db.disarm = value def setStaggers(self, value): self.caller.db.stagger = value def setCleaves(self, value): self.caller.db.cleave = value def decreaseStuns(self, value): new_stun_value = self.stunsRemaining() - value if new_stun_value < 0 or value < 0: new_stun_value = 0 self.setStuns(new_stun_value) def decreaseResists(self, value): new_resist_value = self.resistsRemaining() - value if new_resist_value < 0 or value < 0: new_resist_value = 0 self.setResists(new_resist_value) def decreaseDisarms(self, value): new_disarm_value = self.disarmsRemaining() - value if new_disarm_value < 0 or value < 0: new_disarm_value = 0 self.setDisarms(new_disarm_value) def decreaseStaggers(self, value): new_stagger_value = self.staggersRemaining() - value if new_stagger_value < 0 or value < 0: new_stagger_value = 0 self.setStaggers(new_stagger_value) def decreaseCleaves(self, value): new_cleave_value = self.cleavesRemaining() - value if new_cleave_value < 0 or value < 0: new_cleave_value = 0 self.setCleaves(new_cleave_value) def stun(self): self.caller.db.skip_turn = True def disarm(self): self.caller.db.skip_turn = True def stagger(self): self.caller.db.is_staggered = True def hasDamageVulnerability(self): return def getVictim(self, target): # Get target if there is one self.target = self.caller.search(target) return Combatant(self.target) def getDamage(self): if self.isTwoHanded(): return 2 else: return 1 def setAv(self, amount): #TODO: Should we set Max/Min? self.caller.db.av = amount def blocksWithShield(self, shot_location): has_shield, location = self.getShield() if has_shield and shot_location == location: return True elif has_shield and shot_location == 'torso': if random.randint(1, 2) == 1: return True return False def getArmorSpecialist(self): return self.caller.db.armor_specialist def getArmor(self): return self.caller.db.armor def getTough(self): return self.caller.db.tough def hasChirurgeonsKit(self): kit_type, uses = self.helper.getKitTypeAndUsesItem() has_kit = False if (kit_type == 'chirurgeon') and (uses > 0): has_kit = True return has_kit def reportAv(self): self.message( f"|430Your new total Armor Value is {self.av}:\nArmor Specialist: {self.getArmorSpecialist()}\nArmor: {self.getArmor()}\nTough: {self.getTough()}|n" ) def useChirurgeonsKit(self): self.helper.useKit() def takeShieldDamage(self, amount): return self.alternateDamage(amount, 'shield_value') def takeArmorSpecialistDamage(self, amount): return self.alternateDamage(amount, "armor_specialist") def takeArmorDamage(self, amount): return self.alternateDamage(amount, "tough") def takeToughDamage(self, amount): return self.alternateDamage(amount, "armor") def alternateArmorSpecialistDamage(self, amount): return self.alternateDamage(amount, "armor_specialist") def takeBodyDamage(self, amount): return self.alternateDamage(amount, "body") def takeBleedDamage(self, amount): return self.alternateDamage(amount, "bleed_points") def getStaggerDamage(self): return self.combatStats.get("stagger_damage", '') def takeDeathDamage(self, amount, combatant): if self.caller.db.creature_color: weapon = combatant.getWeapon() if weapon and (weapon.db.color == self.caller.db.creature_color): return self.alternateDamage(amount, "death_points") else: return 0 else: return self.alternateDamage(amount, "death_points") def alternateDamage(self, amount, type): remaining_damage = amount if self.caller.attributes.get(type): if self.caller.attributes.get(type): # How much damage is left after the shield remaining_damage = amount - self.caller.attributes.get(type) if remaining_damage < 0: remaining_damage = 0 # Damage the shield if amount >= self.caller.attributes.get(type): new_value = 0 else: new_value = self.caller.attributes.get(type) - amount obj_to_set = self.caller.attributes.get(type, return_obj=True) obj_to_set.value = new_value return remaining_damage def updateAv(self): self.caller.db.av = self.caller.db.armor + self.caller.db.tough + self.caller.db.armor_specialist def takeAvDamage(self, amount): # Take Damage to Armor # amount = self.takeShieldDamage(amount) if amount > 0: amount = self.takeArmorSpecialistDamage(amount) if amount > 0: amount = self.takeArmorDamage(amount) if amount > 0: amount = self.takeToughDamage(amount) # In case we took any damage, refresh our AV self.updateAv() return amount def takeDamage(self, combatant, amount, shot_location, skip_av=False): if self.av and (not skip_av): amount = self.takeAvDamage(amount) if amount > 0: #We have damage that made it through armor! #TODO: Check with spence that this is right, if we hit the torso, and the hit goes through all the armor, should they go down? #TODO: Or does this only happen if they're totally unarmored when they take damage if shot_location == "torso" and amount < self.body(): amount = self.body() if self.body() > 0: amount = self.takeBodyDamage(amount) if amount > 0 and self.bleedPoints() > 0: self.addWeakness() amount = self.takeBleedDamage(amount) self.message( "|430You are bleeding profusely from many wounds and can no longer use any active martial skills.\n|n" ) self.broadcast( f"|025{self.name} is bleeding profusely from many wounds and will soon lose consciousness.|n" ) if amount > 0 and self.deathPoints() > 0: self.addWeakness() self.takeDeathDamage(amount, combatant) self.message( "|300You are unconscious and can no longer move of your own volition.|n" ) self.broadcast( f"|025{self.name} does not seem to be moving.|n") def resistsAttack(self): if self.resistsRemaining() > 0: self.decreaseResists(1) return True return False