def _reader(): ret, retepd = c.EUDVariable(), c.EUDVariable() # Common comparison rawtrigger c.PushTriggerScope() cmpc = c.Forward() cmp_number = cmpc + 8 cmpact = c.Forward() cmptrigger = c.Forward() cmptrigger << c.RawTrigger( conditions=[cmpc << c.Deaths(c.CurrentPlayer, c.AtMost, 0, 0)], actions=[cmpact << c.SetMemory(cmptrigger + 4, c.SetTo, 0)]) cmpact_ontrueaddr = cmpact + 20 c.PopTriggerScope() # static_for chain1 = [c.Forward() for _ in range(32)] chain2 = [c.Forward() for _ in range(32)] # Main logic start c.SeqCompute([(ut.EPD(cmp_number), c.SetTo, 0xFFFFFFFF), (ret, c.SetTo, 0xFFFFFFFF), (retepd, c.SetTo, ut.EPD(0) + 0x3FFFFFFF)]) readend = c.Forward() for i in range(31, -1, -1): nextchain = chain1[i - 1] if i > 0 else readend if i >= 2: epdsubact = [retepd.AddNumber(-2**(i - 2))] epdaddact = [retepd.AddNumber(2**(i - 2))] else: epdsubact = [] epdaddact = [] chain1[i] << c.RawTrigger( nextptr=cmptrigger, actions=[ c.SetMemory(cmp_number, c.Subtract, 2**i), c.SetNextPtr(cmptrigger, chain2[i]), c.SetMemory(cmpact_ontrueaddr, c.SetTo, nextchain), ret.SubtractNumber(2**i), ] + epdsubact) chain2[i] << c.RawTrigger(actions=[ c.SetMemory(cmp_number, c.Add, 2**i), ret.AddNumber(2**i), ] + epdaddact) readend << c.NextTrigger() return ret, retepd
def f_dwepdCUnitread_epd_safe(targetplayer): ret, retepd = c.EUDVariable(), c.EUDVariable() # Common comparison rawtrigger c.PushTriggerScope() cmpc = c.Forward() cmp_player = cmpc + 4 cmp_number = cmpc + 8 cmpact = c.Forward() cmptrigger = c.Forward() cmptrigger << c.RawTrigger( conditions=[cmpc << c.Memory(0, c.AtMost, 0)], actions=[cmpact << c.SetMemory(cmptrigger + 4, c.SetTo, 0)]) cmpact_ontrueaddr = cmpact + 20 c.PopTriggerScope() # static_for chain1 = [c.Forward() for _ in range(32)] chain2 = [c.Forward() for _ in range(32)] # Main logic start c.SeqCompute([(ut.EPD(cmp_player), c.SetTo, targetplayer), (ut.EPD(cmp_number), c.SetTo, 0x59CCA8 + 0x7FF * 336), (ret, c.SetTo, 0x59CCA8 + 0x7FF * 336), (retepd, c.SetTo, ut.EPD(0x59CCA8) + 0x7FF * 84)]) readend = c.Forward() for i in range(10, -1, -1): nextchain = chain1[i - 1] if i > 0 else readend epdsubact = [retepd.AddNumber(-84 * 2**i)] epdaddact = [retepd.AddNumber(84 * 2**i)] chain1[i] << c.RawTrigger( nextptr=cmptrigger, actions=[ c.SetMemory(cmp_number, c.Subtract, 336 * 2**i), c.SetNextPtr(cmptrigger, chain2[i]), c.SetMemory(cmpact_ontrueaddr, c.SetTo, nextchain), ret.SubtractNumber(336 * 2**i), ] + epdsubact) chain2[i] << c.RawTrigger(actions=[ c.SetMemory(cmp_number, c.Add, 336 * 2**i), ret.AddNumber(336 * 2**i), ] + epdaddact) readend << c.NextTrigger() return ret, retepd
def _f_initextstr(): """(internal)Initialize DBString system.""" rb = ResetterBuffer() ptr, v = c.EUDVariable(), c.EUDVariable() ptr << ut.EPD(rb) origstrptr = f_dwread_epd(ut.EPD(0x5993D4)) if cs.EUDInfLoop()(): v << f_dwread_epd(ptr) cs.EUDBreakIf(v == 0xFFFFFFFF) f_dwwrite_epd(v, origstrptr) ptr += 1 cs.EUDEndInfLoop()
def f_blockpatch_epd(dstepd, srcepd, dwn): """ Patch 4*dwn bytes of memory at dstepd with memory of srcepd. .. note:: After calling this function, contents at srcepd memory may change. Since new contents are required for :py:`f_unpatchall` to run, you shouldn't use the memory for any other means. """ global dws_top # Push to stack pushpatchstack(dstepd) pushpatchstack(srcepd) pushpatchstack(dwn) dws_top += 1 # Swap contents btw dstepd, srcepd tmpbuffer = c.Db(1024) if cs.EUDWhile()(dwn > 0): copydwn = c.EUDVariable() copydwn << 256 t.Trigger(dwn <= 256, copydwn.SetNumber(dwn)) dwn -= copydwn f_repmovsd_epd(ut.EPD(tmpbuffer), dstepd, copydwn) f_repmovsd_epd(dstepd, srcepd, copydwn) f_repmovsd_epd(srcepd, ut.EPD(tmpbuffer), copydwn) cs.EUDEndWhile()
def f_dwrand(): seed1 = c.f_mul(_seed, 1103515245) + 12345 seed2 = c.f_mul(seed1, 1103515245) + 12345 _seed << seed2 ret = c.EUDVariable() ret << 0 # HIWORD for i in range(31, 15, -1): c.RawTrigger(conditions=seed1.AtLeast(2**i), actions=[ seed1.SubtractNumber(2**i), ret.AddNumber(2**i), ]) # LOWORD for i in range(31, 15, -1): c.RawTrigger(conditions=seed2.AtLeast(2**i), actions=[ seed2.SubtractNumber(2**i), ret.AddNumber(2**(i - 16)), ]) return ret
def f_wread_cp(cpo, subp): w = c.EUDVariable() k = c.EUDVariable() cs.DoActions([ [[] if cpo is 0 else c.SetMemory(0x6509B0, c.Add, cpo)], w.SetNumber(0), k.SetNumber(0), ]) cs.EUDSwitch(subp) for i in range(3): cs.EUDSwitchCase()(i) for j in range(31, -1, -1): if 8 * i <= j < 8 * (i + 2): c.RawTrigger(conditions=c.Deaths(c.CurrentPlayer, c.AtLeast, 2**j, 0), actions=[ c.SetDeaths(c.CurrentPlayer, c.Subtract, 2**j, 0), k.AddNumber(2**j), w.AddNumber(2**(j - 8 * i)) ]) else: c.RawTrigger(conditions=c.Deaths(c.CurrentPlayer, c.AtLeast, 2**j, 0), actions=[ c.SetDeaths(c.CurrentPlayer, c.Subtract, 2**j, 0), k.AddNumber(2**j), ]) if j == 8 * i: break c.SeqCompute([(c.EncodePlayer(c.CurrentPlayer), c.Add, k)]) cs.EUDBreak() if cs.EUDSwitchCase()(3): dw0 = cpm.f_dwread_cp(0) dw1 = cpm.f_dwread_cp(1) w << dwm.f_dwbreak(dw0)[5] + dwm.f_dwbreak(dw1)[2] * 256 cs.EUDEndSwitch() cs.DoActions([ [[] if cpo is 0 else c.SetMemory(0x6509B0, c.Add, -cpo)], ]) return w
def Display(self): sp = c.EUDVariable(0) strId = c.EncodeString("_" * 2048) if cs.EUDExecuteOnce()(): sp << GetMapStringAddr(strId) cs.EUDEndExecuteOnce() f_cp949_to_utf8_cpy(sp, self.GetStringMemoryAddr()) cs.DoActions(c.DisplayText(strId))
def PlayWAV(dbs): sp = c.EUDVariable(0) strId = c.EncodeString("_" * 2048) if cs.EUDExecuteOnce()(): strp = f_dwread_epd(ut.EPD(0x5993D4)) sp << strp + f_wread(strp + strId * 2) cs.EUDEndExecuteOnce() f_cp949_to_utf8_cpy(sp, dbs.GetStringMemoryAddr()) cs.DoActions(c.DisplayText(strId))
def _footer(): block = {'origcp': f_getcurpl(), 'playerv': c.EUDVariable()} playerv = block['playerv'] playerv << 0 cs.EUDWhile()(playerv <= 7) cs.EUDContinueIfNot(f_playerexist(playerv)) f_setcurpl(playerv) ut.EUDCreateBlock('ploopblock', block) return True
def f_bread_cp(cpo, subp): b = c.EUDVariable() k = c.EUDVariable() cs.DoActions([ [[] if cpo is 0 else c.SetMemory(0x6509B0, c.Add, cpo)], b.SetNumber(0), k.SetNumber(0), ]) cs.EUDSwitch(subp) for i in range(4): cs.EUDSwitchCase()(i) for j in range(31, -1, -1): if 8 * i <= j < 8 * (i + 1): c.RawTrigger(conditions=c.Deaths(c.CurrentPlayer, c.AtLeast, 2**j, 0), actions=[ c.SetDeaths(c.CurrentPlayer, c.Subtract, 2**j, 0), k.AddNumber(2**j), b.AddNumber(2**(j - 8 * i)) ]) else: c.RawTrigger(conditions=c.Deaths(c.CurrentPlayer, c.AtLeast, 2**j, 0), actions=[ c.SetDeaths(c.CurrentPlayer, c.Subtract, 2**j, 0), k.AddNumber(2**j), ]) if j == 8 * i: break c.SeqCompute([(c.EncodePlayer(c.CurrentPlayer), c.Add, k)]) cs.EUDBreak() cs.EUDEndSwitch() cs.DoActions([ [[] if cpo is 0 else c.SetMemory(0x6509B0, c.Add, -cpo)], ]) return b
def EUDNot(cond): """ !cond :param conds: Condition to negate """ v = c.EUDVariable() if cs.EUDIf()(cond): v << 0 if cs.EUDElse()(): v << 1 cs.EUDEndIf() return v
def f_dwepdCUnitread_epd(targetplayer): origcp = f_getcurpl() ptr, epd = c.EUDVariable(), c.EUDVariable() cs.DoActions([ ptr.SetNumber(0x59CCA8), epd.SetNumber(ut.EPD(0x59CCA8)), c.SetCurrentPlayer(targetplayer) ]) for i in range(10, -1, -1): c.RawTrigger(conditions=[ c.Deaths(c.CurrentPlayer, c.AtLeast, 0x59CCA8 + 336 * 2**i, 0) ], actions=[ c.SetDeaths(c.CurrentPlayer, c.Subtract, 336 * 2**i, 0), ptr.AddNumber(336 * 2**i), epd.AddNumber(84 * 2**i) ]) cs.DoActions(c.SetDeaths(c.CurrentPlayer, c.SetTo, ptr, 0)) f_setcurpl(origcp) return ptr, epd
def f_randomize(): global _seed # Store switch 1 sw1 = c.EUDVariable() if cs.EUDIf()(c.Switch("Switch 1", c.Set)): sw1 << c.EncodeSwitchAction(c.Set) if cs.EUDElse()(): sw1 << c.EncodeSwitchAction(c.Clear) cs.EUDEndIf() _seed << 0 dseed = c.EUDVariable() dseed << 1 if cs.EUDLoopN()(32): cs.DoActions(c.SetSwitch("Switch 1", c.Random)) if cs.EUDIf()(c.Switch("Switch 1", c.Set)): _seed += dseed cs.EUDEndIf() dseed += dseed cs.EUDEndLoopN() cs.DoActions(c.SetSwitch("Switch 1", sw1))
def EUDLoopSprite(): y_epd = c.EUDVariable() y_epd << ut.EPD(0x629688) ut.EUDCreateBlock('spriteloop', 'sprlo') if cs.EUDWhile()(y_epd < ut.EPD(0x629688) + 256): ptr, epd = f_dwepdread_epd(y_epd) if cs.EUDWhile()(ptr >= 1): yield ptr, epd cs.EUDSetContinuePoint() c.SetVariables([ptr, epd], f_dwepdread_epd(epd + 1)) cs.EUDEndWhile() y_epd += 1 cs.EUDEndWhile() ut.EUDPopBlock('spriteloop')
def f_wwrite_cp(cpo, subp, w): k = c.EUDVariable() cs.DoActions([ [[] if cpo is 0 else c.SetMemory(0x6509B0, c.Add, cpo)], k.SetNumber(0), ]) cs.EUDSwitch(subp) for i in range(3): cs.EUDSwitchCase()(i) for j in range(31, -1, -1): if 8 * (i + 2) <= j: c.RawTrigger(conditions=c.Deaths(c.CurrentPlayer, c.AtLeast, 2**j, 0), actions=[ c.SetDeaths(c.CurrentPlayer, c.Subtract, 2**j, 0), k.AddNumber(2**j), ]) else: c.RawTrigger(conditions=c.Deaths(c.CurrentPlayer, c.AtLeast, 2**j, 0), actions=[ c.SetDeaths(c.CurrentPlayer, c.Subtract, 2**j, 0), ]) if j == 8 * i: break c.SeqCompute([ (c.CurrentPlayer, c.Add, k), (c.CurrentPlayer, c.Add, w * (256**i)), ]) cs.EUDBreak() if cs.EUDSwitchCase()(3): b0, b1 = dwm.f_dwbreak(w)[2:4] f_bwrite_cp(0, 3, b0) f_bwrite_cp(1, 0, b1) cs.EUDEndSwitch() cs.DoActions([ [[] if cpo is 0 else c.SetMemory(0x6509B0, c.Add, -cpo)], ])
def QueueGameCommand_Select(n, ptrList): ptrList = EUDArray.cast(ptrList) buf = c.Db(b'\x090123456789012345678901234') bw.seekoffset(buf + 1) bw.writebyte(n) i = c.EUDVariable() i << 0 if cs.EUDWhile()(i < n): unitptr = ptrList[i] unitIndex = (unitptr - 0x59CCA8) // 336 + 1 uniquenessIdentifier = f_bread(unitptr + 0xA5) targetID = unitIndex | c.f_bitlshift(uniquenessIdentifier, 11) b0, b1 = f_dwbreak(targetID)[2:4] bw.writebyte(b0) bw.writebyte(b1) i += 1 cs.EUDEndWhile() QueueGameCommand(buf, 2 * (n + 1))
def EUDOr(cond1, *conds): """ cond1 || cond2 || ... || condn .. warning:: Short circuiting is not supported :param conds: List of conditions """ v = c.EUDVariable() if cs.EUDIf()(cond1): v << 1 for cond in conds: if cs.EUDElseIf()(cond): v << 1 if cs.EUDElse()(): v << 0 cs.EUDEndIf() return v
def EUDBinaryMin(cond, minv=0, maxv=0xFFFFFFFF): """ Find minimum x satisfying cond(x) using binary search :param cond: Test condition :param minv: Minimum value in domain :param maxv: Maximum value in domain Cond should be binary classifier, meaning that for some N for all x < N, cond(x) is false. for all x >= N, cond(x) is true Then EUDBinaryMin will find such N .. note:: If none of the value satisfies condition, then this function will return maxv. """ x = c.EUDVariable() x << maxv if isinstance(minv, int) and isinstance(maxv, int): r = maxv - minv if r == 0: return minv else: r = None for i in range(31, -1, -1): if r and 2**i > r: continue if cs.EUDIf()([x >= 2**i]): cs.DoActions(x.SubtractNumber(2**i)) if cs.EUDIfNot()([x >= minv, cond(x)]): cs.DoActions(x.AddNumber(2**i)) cs.EUDEndIf() cs.EUDEndIf() return x
def EUDAnd(cond1, *conds): """ cond1 && cond2 && ... && condn .. note:: This function computes AND value of various conditions. If you don't want to do much computation, you should better use plain list instead of this function. .. warning:: Short circuiting is not supported. :param conds: List of conditions """ v = c.EUDVariable() if cs.EUDIfNot()(cond1): v << 0 for cond in conds: if cs.EUDElseIfNot()(cond): v << 0 if cs.EUDElse()(): v << 1 cs.EUDEndIf() return v
def f_dbstr_addstr(dst, src): """Print string as string to dst. Same as strcpy except of return value. :param dst: Destination address (Not EPD player) :param src: Source address (Not EPD player) :returns: dst + strlen(src) """ b = c.EUDVariable() br1.seekoffset(src) bw1.seekoffset(dst) if cs.EUDInfLoop()(): c.SetVariables(b, br1.readbyte()) bw1.writebyte(b) cs.EUDBreakIf(b == 0) dst += 1 cs.EUDEndInfLoop() bw1.flushdword() return dst
def f_lengthdir(length, angle): # sin, cos table clist = [] slist = [] for i in range(91): cosv = math.floor(math.cos(math.pi / 180 * i) * 65536 + 0.5) sinv = math.floor(math.sin(math.pi / 180 * i) * 65536 + 0.5) clist.append(ut.i2b4(cosv)) slist.append(ut.i2b4(sinv)) cdb = c.Db(b''.join(clist)) sdb = c.Db(b''.join(slist)) # MAIN LOGIC if cs.EUDIf()(angle >= 360): angle << c.f_div(angle, 360)[1] cs.EUDEndIf() ldir_x, ldir_y = c.EUDVariable(), c.EUDVariable() # cos, sin * 65536 # sign of cos, sin csign, ssign = c.EUDLightVariable(), c.EUDLightVariable() tableangle = c.EUDVariable() # get cos, sin from table if cs.EUDIf()(angle <= 89): tableangle << angle csign << 1 ssign << 1 if cs.EUDElseIf()(angle <= 179): tableangle << 180 - angle csign << -1 ssign << 1 if cs.EUDElseIf()(angle <= 269): tableangle << angle - 180 csign << -1 ssign << -1 if cs.EUDElse()(): tableangle << 360 - angle csign << 1 ssign << -1 cs.EUDEndIf() tablecos = f_dwread_epd(ut.EPD(cdb) + tableangle) tablesin = f_dwread_epd(ut.EPD(sdb) + tableangle) # calculate lengthdir ldir_x << c.f_div(c.f_mul(tablecos, length), 65536)[0] ldir_y << c.f_div(c.f_mul(tablesin, length), 65536)[0] # restore sign of cos, sin if cs.EUDIf()(csign == -1): ldir_x << 0xFFFFFFFF - ldir_x + 1 cs.EUDEndIf() if cs.EUDIf()(ssign == -1): ldir_y << 0xFFFFFFFF - ldir_y + 1 cs.EUDEndIf() return ldir_x, ldir_y
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ''' # This code uses simple LCG algorithm. from eudplib import ( core as c, ctrlstru as cs, ) from ..memiof import f_dwbreak _seed = c.EUDVariable() def f_getseed(): t = c.EUDVariable() t << _seed return t def f_srand(seed): _seed << seed def f_randomize(): global _seed
def f_atan2(y, x): signflags = c.EUDVariable() signflags << 0 # Check x sign if cs.EUDIf()(x >= 0x80000000): x << -x signflags += 1 # set xsign cs.EUDEndIf() # Check y sign if cs.EUDIf()(y >= 0x80000000): y << -y signflags += 2 # set ysign cs.EUDEndIf() # Check x/y order if cs.EUDIf()(y >= x): z = c.EUDVariable() # Swap x, y so that y <= x z << x x << y y << z signflags += 4 # set xyabscmp cs.EUDEndIf() # To prevent overflow, we limit values of y and x. # atan value is maximized when x = y, then atan_value = 45 * x**3 # 45 * x**3 <= 0xFFFFFFFF : x <= 456.99.... if cs.EUDIf()(x >= 400): # Normalize below 400 divn = x // 400 + 1 x //= divn y //= divn cs.EUDEndIf() # Calculate arctan value # arctan(z) ~= z * (45 - (z-1) * (14 + 4*z)), 0 <= z <= 1 # arctan(y/x) ~= y/x * (45 - (y-x)/x * (14x + 4y)/x)) # arctan(y/x) ~= y * (45*x*x - (y-x)(14x+4y)) / (x*x*x) t1 = x * x t2 = y * (45 * t1 - (y - x) * (14 * x + 4 * y)) t3 = x * t1 atan_value = t2 // t3 # Translate angles by sign flags # # | 0 | 1 | xsign | 0 | 1 | xsign # -----+----+----+----- -----+----+----+----- # 0 | 0+|180-| 0 | 90-| 90+| # -----+----+----+ -----+----+----+ # 1 |360-|180+| 1 |270+|270-| # -----+----+----+ -----+----+----+ # ysign| xyabscmp=0 ysign| xyabscmp=1 cs.EUDSwitch(signflags) cs.EUDSwitchCase()(0) # xsign, ysign, xyabscmp = 0, 0, 0 c.EUDReturn(atan_value) cs.EUDSwitchCase()(1) # xsign, ysign, xyabscmp = 1, 0, 0 c.EUDReturn(180 - atan_value) cs.EUDSwitchCase()(2) # xsign, ysign, xyabscmp = 0, 1, 0 c.EUDReturn(360 - atan_value) cs.EUDSwitchCase()(3) # xsign, ysign, xyabscmp = 1, 1, 0 c.EUDReturn(180 + atan_value) cs.EUDSwitchCase()(4) # xsign, ysign, xyabscmp = 0, 0, 1 c.EUDReturn(90 - atan_value) cs.EUDSwitchCase()(5) # xsign, ysign, xyabscmp = 1, 0, 1 c.EUDReturn(90 + atan_value) cs.EUDSwitchCase()(6) # xsign, ysign, xyabscmp = 0, 1, 1 c.EUDReturn(270 + atan_value) cs.EUDSwitchCase()(7) # xsign, ysign, xyabscmp = 1, 1, 1 c.EUDReturn(270 - atan_value) cs.EUDEndSwitch()
def f_getseed(): t = c.EUDVariable() t << _seed return t
core as c, ctrlstru as cs, utils as ut, trigger as t, ) from ..eudarray import EUDArray from ..memiof import ( f_dwread_epd, f_dwwrite_epd, f_repmovsd_epd, ) patchMax = 8192 patchstack = EUDArray(3 * patchMax) dws_top, ps_top = c.EUDVariable(), c.EUDVariable() dwstack = EUDArray(patchMax) def pushpatchstack(value): global ps_top patchstack[ps_top] = value ps_top += 1 def poppatchstack(): global ps_top ps_top -= 1 return patchstack[ps_top]