import random as ra import json as j from os.path import dirname,join with open(join(dirname(__file__),'data.json')) as d: data=j.load(d) classtable=data['classes'] from . import decos @decos.target() @decos.guardcheck def attack(self,other,*_): admg,ddmg=_dealdmg(self,other) return admg,ddmg,f"{self.name} dealt {admg} to {other.name}" + (f", received {ddmg} counter damage" if ddmg else "") def allattack(self,*_): # We'll start at this code and attack 6 units start=(self.code//6+1)%2*6 units=self.board.getunits(*list(range(start,start+6)),codes=True) ascore=dscore=0 for other in units: # That would be an embarrassing bug. if other is None: continue if 'guard' in other.status: other.status['guard']-=0.4 if other.status['guard']<=0: other.status.pop('guard') admg,ddmg=_dealdmg(self,other) ascore+=admg dscore+=ddmg return round(ascore*2/3),dscore,f"{self.name} dealt a total of {ascore} damage (earning {round(ascore*2/3)} points) to enemy units" + (f", and received a total of {dscore} damage in return" if dscore else "") def _dealdmg(self,other,melee=None): sinfo=classtable[self.cls] oinfo=classtable[other.cls] if melee is None: amelee='amelee' in sinfo['attrs'] else: amelee=melee counter=amelee & ('counter' in oinfo['attrs']) admg=_calcdmg(self,other,'magic' in sinfo['attrs'],self.cls!='musket') if counter: ddmg=_calcdmg(other,self,'magic' in oinfo['attrs'],True) else: ddmg=0 if not (type(admg)==bool and admg==False): # We didn't pop a shield, proceed with popping charge if 'cancel' in sinfo['attrs']: other.status.pop('charging',None) # I'll need to mess with this later to make it handle super charge. other.cur-=admg self.cur-=ddmg if other.cur<=0: o=other.die(); admg+=o[0]; ddmg+=o[1] if self.cur<=0: s=self.die(); admg+=s[1]; ddmg+=s[0] return admg,ddmg def _calcdmg(self,other,magic=False,capped=True,counter=False): # This only deals damage one direction. It's like a one-liner. # Well but if it's magic damage, and protection status... if 'protected' in other.status: other.status.pop('protected'); return 0 if not magic: dmg=round((1.15**(self.atk-other.dfn)) \ *((self.cur*1000)**0.5)*0.1 \ *(0.6 if 'defend' in other.status else 1) \ * (0.5 if counter else 1)) else: dmg=round((1.15**(self.atk*0.2+self.int-other.dfn*0.2-other.int)) \ *((self.cur*1000)**0.5)*0.1 \ *(0.6 if 'defend' in other.status else 1) \ * (0.5 if counter else 1)) if capped: return min(dmg,other.cur,self.cur) else: return min(dmg,other.cur) def guard(self,*_): try: self.status['guard']+=self.int*0.2 except KeyError: self.status['guard']=self.int*0.2 self.status['defend']=True return 0,0,f"{self.name} gains {self.int*0.2:.3} guard value" @decos.target(ranged=True) @decos.guardcheck def assassinate(self,other,*_): other.status.pop('protected',None) chance=self.int*(self.cur/other.cur)*0.07 roll=ra.random() if rollweights[i]: pick-=weights[i];i+=1; out.append(items[i]) items.pop(i); weights.pop(i) # Update list for next run return out def rest(self,*_): # Real simple like # Not so simple like heal=round(max(self.max*0.015,min(self.cur*0.07,self.max-self.cur))) self.cur+=heal return 0,0,f"{self.name} rests and recovers {heal} troops"