Appearance
question:In the code below, where is the code to stop the behavior if someone else is detected? This is very important to my career. I will tip 200. Please output in Korean. Please answer assuming that the files are configured as described below. "@@@Filename@@@" means that you have created a startup file with a filename. Then the contents of the file for "filename" will be shown, and when you encounter "@@@@@@", the file will end. @@@리셀금지.ct @@@ <?xml version="1.0" encoding="utf-8"?> <CheatTable CheatEngineTableVersion="45"> <CheatEntries> <CheatEntry> <ID>1</ID> <Description>"루아 스크립트 적용 -msw"</Description> <VariableType>Auto Assembler Script</VariableType> <AssemblerScript>[ENABLE] //code from here to '[DISABLE]' will be used to enable the cheat {lua} local function modify_buffer() local buffer_data = readString (RDX+0x20, R8) local name_size = readInteger(R9+0x10) local script_name = readString (R9+0x14, name_size*2, true) --(i) now my dumper cant handle multiple files with same filename like chunk --(i) so added filter since user cant modify them if script_name == "chunk" then return end local my_script_path = ("C:GameScript%s.lua"):format(script_name) --printf("My Script: %s", my_script_path) local file = io.open(my_script_path, "rb") if file then local new_data = file:read("a") local new_length = #new_data file:close() local new_buffer = allocateMemory(0x20 + new_length) writeQword(new_buffer , readQword(RDX)) writeQword(new_buffer+0x8 , readQword(RDX+0x8)) writeQword(new_buffer+0x10 , readQword(RDX+0x10)) writeQword(new_buffer+0x18 , new_length) writeString(new_buffer+0x20 , new_data) RDX = new_buffer R8 = new_length printf("Loaded Script: %s", my_script_path) end end openProcess("msw.exe") debug_setBreakpoint(getAddress("GameAssembly.dll+2E69360"), modify_buffer) [DISABLE] //code from here till the end of the code will be used to disable the cheat </AssemblerScript> </CheatEntry> </CheatEntries> <UserdefinedSymbols> <SymbolEntry> <Name>CRCBypass</Name> <Address>20CC3AE0000</Address> </SymbolEntry> <SymbolEntry> <Name>newcheck</Name> <Address>006E0200</Address> </SymbolEntry> <SymbolEntry> <Name>Fuck1F</Name> <Address>1FA789CE</Address> </SymbolEntry> <SymbolEntry> <Name>FuckFF1</Name> <Address>1FA6B03E</Address> </SymbolEntry> <SymbolEntry> <Name>Fuck1</Name> <Address>1FC20B0C</Address> </SymbolEntry> <SymbolEntry> <Name>door</Name> <Address>05520000</Address> </SymbolEntry> <SymbolEntry> <Name>Fuck4</Name> <Address>1F632E40</Address> </SymbolEntry> <SymbolEntry> <Name>myhack</Name> <Address>024E0000</Address> </SymbolEntry> <SymbolEntry> <Name>pspeed</Name> <Address>1FDFA12D</Address> </SymbolEntry> <SymbolEntry> <Name>autokill1</Name> <Address>1FBEEC6D</Address> </SymbolEntry> <SymbolEntry> <Name>autokill2</Name> <Address>1FBEEDFE</Address> </SymbolEntry> <SymbolEntry> <Name>plusamount</Name> <Address>001C1F40</Address> </SymbolEntry> <SymbolEntry> <Name>plus</Name> <Address>024E0FA0</Address> </SymbolEntry> <SymbolEntry> <Name>Fuck3</Name> <Address>1F59BD41</Address> </SymbolEntry> <SymbolEntry> <Name>damage</Name> <Address>08B90000</Address> </SymbolEntry> <SymbolEntry> <Name>damagevalue</Name> <Address>08B900D0</Address> </SymbolEntry> <SymbolEntry> <Name>speedvalue</Name> <Address>08B90270</Address> </SymbolEntry> <SymbolEntry> <Name>attackdamage</Name> <Address>096600D0</Address> </SymbolEntry> <SymbolEntry> <Name>attackdamagevalue</Name> <Address>09660270</Address> </SymbolEntry> <SymbolEntry> <Name>skilldamage</Name> <Address>43420000</Address> </SymbolEntry> <SymbolEntry> <Name>skilldamagevalue</Name> <Address>09350270</Address> </SymbolEntry> <SymbolEntry> <Name>SkillRange</Name> <Address>434200D0</Address> </SymbolEntry> <SymbolEntry> <Name>SkillRange_</Name> <Address>434201A0</Address> </SymbolEntry> <SymbolEntry> <Name>MPInfinity</Name> <Address>43420340</Address> </SymbolEntry> <SymbolEntry> <Name>MPInfinity2</Name> <Address>0BA90000</Address> </SymbolEntry> <SymbolEntry> <Name>ItemBOX</Name> <Address>43420410</Address> </SymbolEntry> <SymbolEntry> <Name>SkillCasting</Name> <Address>43420270</Address> </SymbolEntry> <SymbolEntry> <Name>AttackDamage_</Name> <Address>096601A0</Address> </SymbolEntry> <SymbolEntry> <Name>Fuck5</Name> <Address>1F5BB210</Address> </SymbolEntry> <SymbolEntry> <Name>mop2</Name> <Address>1F7C0EF2</Address> </SymbolEntry> <SymbolEntry> <Name>Dir5</Name> <Address>04D40033</Address> </SymbolEntry> <SymbolEntry> <Name>Fuck7</Name> <Address>1FC73538</Address> </SymbolEntry> <SymbolEntry> <Name>Fuck6</Name> <Address>1FB8AE52</Address> </SymbolEntry> <SymbolEntry> <Name>Fuc1</Name> <Address>005F8C5D</Address> </SymbolEntry> <SymbolEntry> <Name>Fuck111</Name> <Address>2424042C</Address> </SymbolEntry> <SymbolEntry> <Name>Fuck11</Name> <Address>004F350C</Address> </SymbolEntry> <SymbolEntry> <Name>savecode</Name> <Address>01BF0000</Address> </SymbolEntry> <SymbolEntry> <Name>tutorialhealth</Name> <Address>01BF0000</Address> </SymbolEntry> <SymbolEntry> <Name>regcheck_counter</Name> <Address>01E00000</Address> </SymbolEntry> <SymbolEntry> <Name>originalcode</Name> <Address>01E00000</Address> </SymbolEntry> <SymbolEntry> <Name>micheck</Name> <Address>01BF0000</Address> </SymbolEntry> <SymbolEntry> <Name>savemob</Name> <Address>005D0000</Address> </SymbolEntry> <SymbolEntry> <Name>FuckF1</Name> <Address>201F4876</Address> </SymbolEntry> <SymbolEntry> <Name>Leewonbok</Name> <Address>1FA6D974</Address> </SymbolEntry> <SymbolEntry> <Name>pointer2</Name> <Address>20B44F48</Address> </SymbolEntry> <SymbolEntry> <Name>pointer</Name> <Address>pointer2-30</Address> </SymbolEntry> <SymbolEntry> <Name>mop</Name> <Address>1FC4851D</Address> </SymbolEntry> <SymbolEntry> <Name>ia_aob1</Name> <Address>13FA55681</Address> </SymbolEntry> <SymbolEntry> <Name>pills</Name> <Address>0CE46EB5</Address> </SymbolEntry> <SymbolEntry> <Name>keys</Name> <Address>08119EB6</Address> </SymbolEntry> <SymbolEntry> <Name>None</Name> <Address>0B272098</Address> </SymbolEntry> <SymbolEntry> <Name>itemlist1</Name> <Address>0BEC2624</Address> </SymbolEntry> <SymbolEntry> <Name>itemlist2</Name> <Address>0BEC278E</Address> </SymbolEntry> <SymbolEntry> <Name>itemlist3</Name> <Address>0BEC2893</Address> </SymbolEntry> <SymbolEntry> <Name>itemlist4</Name> <Address>0BEC2943</Address> </SymbolEntry> <SymbolEntry> <Name>itemlist5</Name> <Address>0BEC29EF</Address> </SymbolEntry> <SymbolEntry> <Name>itemlist6</Name> <Address>0BEC2ABC</Address> </SymbolEntry> <SymbolEntry> <Name>itemlist7</Name> <Address>0BEC2B3A</Address> </SymbolEntry> <SymbolEntry> <Name>itemlist8</Name> <Address>0BEC2BC8</Address> </SymbolEntry> <SymbolEntry> <Name>itemlist9</Name> <Address>0BEC2FAB</Address> </SymbolEntry> <SymbolEntry> <Name>roomAdd</Name> <Address>0B9768EB</Address> </SymbolEntry> <SymbolEntry> <Name>startItem</Name> <Address>0B9768FA</Address> </SymbolEntry> <SymbolEntry> <Name>slotf</Name> <Address>0B993558</Address> </SymbolEntry> <SymbolEntry> <Name>bbank</Name> <Address>0B999D8C</Address> </SymbolEntry> <SymbolEntry> <Name>miniboss</Name> <Address>0B9D7B73</Address> </SymbolEntry> <SymbolEntry> <Name>bombs</Name> <Address>0B98B483</Address> </SymbolEntry> <SymbolEntry> <Name>Lost</Name> <Address>06B586BB</Address> </SymbolEntry> <SymbolEntry> <Name>Alt</Name> <Address>06D88DD2</Address> </SymbolEntry> <SymbolEntry> <Name>Alt2</Name> <Address>06D88DE1</Address> </SymbolEntry> <SymbolEntry> <Name>life</Name> <Address>095078ED</Address> </SymbolEntry> <SymbolEntry> <Name>hit</Name> <Address>09507836</Address> </SymbolEntry> <SymbolEntry> <Name>armor</Name> <Address>0950785B</Address> </SymbolEntry> <SymbolEntry> <Name>itempower</Name> <Address>0955ABC8</Address> </SymbolEntry> <SymbolEntry> <Name>itemp9v</Name> <Address>0955ABB1</Address> </SymbolEntry> <SymbolEntry> <Name>maxitems</Name> <Address>094FB019</Address> </SymbolEntry> <SymbolEntry> <Name>coins1</Name> <Address>09513251</Address> </SymbolEntry> <SymbolEntry> <Name>coins2</Name> <Address>0951381D</Address> </SymbolEntry> <SymbolEntry> <Name>crc</Name> <Address>0018DD21</Address> </SymbolEntry> <SymbolEntry> <Name>crc2</Name> <Address>0018DCBD</Address> </SymbolEntry> <SymbolEntry> <Name>crc3</Name> <Address>0018DCA3</Address> </SymbolEntry> <SymbolEntry> <Name>crc4</Name> <Address>0018DC7D</Address> </SymbolEntry> <SymbolEntry> <Name>MyCode</Name> <Address>01890000</Address> </SymbolEntry> <SymbolEntry> <Name>pHP</Name> <Address>0189010C</Address> </SymbolEntry> <SymbolEntry> <Name>pGold</Name> <Address>01890114</Address> </SymbolEntry> <SymbolEntry> <Name>pMana</Name> <Address>01890110</Address> </SymbolEntry> <SymbolEntry> <Name>iEnableGM</Name> <Address>01890100</Address> </SymbolEntry> <SymbolEntry> <Name>iEnableMG</Name> <Address>01890104</Address> </SymbolEntry> <SymbolEntry> <Name>iEnableMM</Name> <Address>01890108</Address> </SymbolEntry> <SymbolEntry> <Name>EFTscan</Name> <Address>03DF30F2</Address> </SymbolEntry> <SymbolEntry> <Name>attackspeed</Name> <Address>08B2FEBE</Address> </SymbolEntry> <SymbolEntry> <Name>speed</Name> <Address>08B7F738</Address> </SymbolEntry> <SymbolEntry> <Name>FASpeedUpCode</Name> <Address>01057BAB</Address> </SymbolEntry> <SymbolEntry> <Name>FASpeedUpCall</Name> <Address>0106E210</Address> </SymbolEntry> <SymbolEntry> <Name>FASpeedUpCodeDi</Name> <Address>01057BAB</Address> </SymbolEntry> <SymbolEntry> <Name>FASpeedUpCallDi</Name> <Address>0106E210</Address> </SymbolEntry> <SymbolEntry> <Name>itoc</Name> <Address>2B1106C8</Address> </SymbolEntry> <SymbolEntry> <Name>cont2</Name> <Address>20470018</Address> </SymbolEntry> <SymbolEntry> <Name>callTime</Name> <Address>010A29B0</Address> </SymbolEntry> <SymbolEntry> <Name>pPacket</Name> <Address>0042CAC6</Address> </SymbolEntry> <SymbolEntry> <Name>pCharacter</Name> <Address>0042C0A4</Address> </SymbolEntry> <SymbolEntry> <Name>retAddr</Name> <Address>2C96005D</Address> </SymbolEntry> <SymbolEntry> <Name>lpBytes</Name> <Address>2C960061</Address> </SymbolEntry> <SymbolEntry> <Name>dwLength</Name> <Address>2C960065</Address> </SymbolEntry> <SymbolEntry> <Name>packets</Name> <Address>2C960069</Address> </SymbolEntry> <SymbolEntry> <Name>EHookRet</Name> <Address>020ED258</Address> </SymbolEntry> <SymbolEntry> <Name>HookRet</Name> <Address>0AF70000</Address> </SymbolEntry> <SymbolEntry> <Name>Channel</Name> <Address>0D700000</Address> </SymbolEntry> <SymbolEntry> <Name>ConnectCNT</Name> <Address>02460000</Address> </SymbolEntry> </UserdefinedSymbols> <DisassemblerComments> <DisassemblerComment> <Address>"GameAssembly.dll"+38C18C1</Address> <Comment>1 </Comment> </DisassemblerComment> <DisassemblerComment> <Address>"GameAssembly.dll"+38C19E7</Address> <Comment>1 </Comment> </DisassemblerComment> <DisassemblerComment> <Address>"GameAssembly.dll"+38C7645</Address> <Comment>0 </Comment> </DisassemblerComment> <DisassemblerComment> <Address>"GameAssembly.dll"+38C76B0</Address> <Comment>0 </Comment> </DisassemblerComment> <DisassemblerComment> <Address>"GameAssembly.dll"+38C85E6</Address> <Comment>0 </Comment> </DisassemblerComment> <DisassemblerComment> <Address>"GameAssembly.dll"+38C860B</Address> <Comment>0 </Comment> </DisassemblerComment> <DisassemblerComment> <Address>"GameAssembly.dll"+38C861E</Address> <Comment>0 </Comment> </DisassemblerComment> <DisassemblerComment> <Address>"GameAssembly.dll"+38C86C4</Address> <Comment>0 </Comment> </DisassemblerComment> </DisassemblerComments> </CheatTable> @@@@@@ @@@GameScript/CharacterActionComponent.GetWeaponAttackSpeed.lua @@@ return function (self,magic) local speed if(zz_y7.use_attack_speed) then return 4 end if (magic) then speed = 9 else speed = self.CurrentWeaponAttackSpeed end speed += self.Entity.PlayerTemporaryStat:GetValue(_CTS.Booster) if (speed < 5) then return 5 end if (speed > 9) then return 9 end return speed end @@@@@@ @@@GameScript/CommandLogic_Client.OnBeginPlay.lua @@@ ---------- zz_y7 ------------- local zz_y7_const = { TEST = "테스트"; HELP = "?"; AUTO_PLAY = "자동사냥"; ATTACK_SPEED = "노딜"; } local print_toggle_message = function(feature_name, if_toggle_on) _ChatMessageLogic:Add(_ChatMessageType.System, ("%s: %s"):format( feature_name, if_toggle_on and "활성화됨" or "비활성화됨" ) ) end ---------- zz_y7 ------------- return function (self) self.ClientCommands = { ["도움말"] = self.Help, ["교환"] = self.Trade, ["게임교환"] = self.Trade, ["모두"] = self.ToAll, ["파티"] = self.ToParty, ["채널"] = self.ToChannel, ["귓말"] = self.ToWhisper, ["귓"] = self.ToWhisper, ["찾기"] = self.Find, ["파티만들기"] = self.CreateParty, ["파티탈퇴"] = self.LeaveParty, ["파티초대"] = self.InviteParty, ["파티강퇴"] = self.KickParty, [zz_y7_const.HELP] = function(self) --> add yourself : ) ;; local message = [[ ----------------- 명령어 ----------------- [플레이] /자동사냥 {핫키:F1} /몹몰이 {핫키:F2} /물약 [설정] /안전지대 - 안전지대 좌표설정 /피굳 /아이템 {갯수} - {갯수} 만큼의 아이템이 필드에 떨어지면 아이템을 줍습니다. /자사딜레이 {딜레이} - /좌표설정 {x} {y} - 몬스터의 x,y 좌표에 {x},{y} 좌표만큼 더한곳으로 텔레포트 합니다. /HP {물약코드값} {트리거HP} - 기본값 : 주황포션(2000001) / 150 /MP {물약코드값} {트리거HP} - 기본값 : 파랑포션(2000003) / 50 /마박 /노딜 공속 ------------------------------------------ ]] _ChatMessageLogic:Add(_ChatMessageType.Party, message) end, [zz_y7_const.ATTACK_SPEED] = function(self) zz_y7.use_attack_speed = not zz_y7.use_attack_speed print_toggle_message(zz_y7_const.ATTACK_SPEED, zz_y7.use_attack_speed) end, [zz_y7_const.AUTO_PLAY] = function(self) zz_y7.use_auto_play = not zz_y7.use_auto_play zz_y7.is_stop = false; zz_y7.is_others = false; zz_y7.teleported_to_mob = false; zz_y7.teleported_to_drop = false zz_y7.pick_drop = false; _TimerService:ClearTimer(zz_y7.auto_play_timer) _TimerService:ClearTimer(zz_y7.auto_hit_timer) _TimerService:ClearTimer(zz_y7.auto_drop_timer) if zz_y7.use_auto_play then zz_y7.auto_play_timer = _TimerService:SetTimerRepeat(zz_y7.play_timer_func, zz_y7.auto_cool) zz_y7.auto_hit_timer = _TimerService:SetTimerRepeat(zz_y7.hit_timer_func, 0.1) zz_y7.auto_drop_timer = _TimerService:SetTimerRepeat(zz_y7.pick_timer_func, 0.1) else _TimerService:ClearTimer(zz_y7.auto_play_timer) _TimerService:ClearTimer(zz_y7.auto_hit_timer) _TimerService:ClearTimer(zz_y7.auto_drop_timer) end print_toggle_message(zz_y7_const.AUTO_PLAY, zz_y7.use_auto_play) end, ["몹몰이"] = function(self) zz_y7.drive_mob = not zz_y7.drive_mob if zz_y7.drive_mob then zz_y7.drive_timer = _TimerService:SetTimerRepeat(zz_y7.drive_func, 0.2) else _TimerService:ClearTimer(zz_y7.drive_timer) zz_y7.reset_mob_func() end -- print_toggle_message(zz_y7_const.DRIVE_MOB, zz_y7.drive_mob) local String = zz_y7.drive_mob and "설정" or "해제" _ChatMessageLogic:Add(_ChatMessageType.Yellow, "몹몰이가 " .. String .. "되었습니다.") end, ["피굳"] = function(self) zz_y7.hp_freeze = not zz_y7.hp_freeze local String = zz_y7.hp_freeze and "설정" or "해제" _ChatMessageLogic:Add(_ChatMessageType.Yellow, "피굳이 " .. String .. "되었습니다.") end, ["안전지대"] = function(self) zz_y7.safe_pos = _UserService.LocalPlayer.TransformComponent.WorldPosition:ToVector2() _ChatMessageLogic:Add(_ChatMessageType.Yellow, "안전지대 좌표가 설정되었습니다.") end, ["아이템"] = function(self, user, argc, args) zz_y7.item_max_count = tonumber(args[2]) _ChatMessageLogic:Add(_ChatMessageType.Yellow, "이제 필드에 떨어진 아이템의 갯수가 {"..args[2].."}개가 되면 아이템을 줍습니다.") end, ["자사딜레이"] = function(self, user, argc, args) zz_y7.auto_cool = tonumber(args[2]) _ChatMessageLogic:Add(_ChatMessageType.Yellow, "이제 {"..args[2].."}초 마다 몬스터에게 텔레포트 합니다.") end, ["좌표설정"] = function(self, user, argc, args) zz_y7.tel_x = tonumber(args[2]) zz_y7.tel_y = tonumber(args[3]) _ChatMessageLogic:Add(_ChatMessageType.Yellow, "이제 몬스터의 x +{"..args[2].."} / y +{"..args[3].."} 의 좌표로 이동합니다.") end, ["HP"] = function(self, user, argc, args) zz_y7.hp_item = tonumber(args[2]) zz_y7.min_hp = tonumber(args[3]) _ChatMessageLogic:Add(_ChatMessageType.Yellow, "HP물약 설정완료") end, ["MP"] = function(self, user, argc, args) zz_y7.mp_item = tonumber(args[2]) zz_y7.min_mp = tonumber(args[3]) _ChatMessageLogic:Add(_ChatMessageType.Yellow, "MP물약 설정완료") end, ["물약"] = function(self) zz_y7.use_auto_potion = not zz_y7.use_auto_potion if zz_y7.use_auto_potion then zz_y7.auto_potion_timer = _TimerService:SetTimerRepeat(zz_y7.auto_potion_func, 0.1) else _TimerService:ClearTimer(zz_y7.auto_potion_timer) end print_toggle_message("물약", zz_y7.use_auto_potion) end, ["마박"] = function(self) zz_y7.mouse_vac = not zz_y7.mouse_vac print_toggle_message("마박", zz_y7.mouse_vac) end, } if (Environment:IsMakerPlay()) then self.DebugCommands = { ["impact"] = _CommandLogic_Client_Debug.Impact } end end @@@@@@ @@@GameScript/DropComponent.EnterField.lua@@@ return function (self,appearType,d,returnPool) self.Position = d.Position self.OriginalPosition = d.OriginalPosition self.DropId = d.ObjectId self.ReturnPool = returnPool self.IsMoney = d.ItemId == 0 self.PickUpTarget = nil self.OwnType = d.OwnType self.OwnId = d.OwnerId self.CreateTime = d.CreateTime self.ReservedDestroy = 1E1000 -- Set Sprite local xOffset = 0 if (d.ItemId == 0) then local spriteRenderer = self.Entity.SpriteRendererComponent if (d.Amount < 50) then spriteRenderer.SpriteRUID = _UidMan:GetRawAnimation("dbcd3e987e834c51b003fafa15d0982b") -- 28 or 29 xOffset = 0.14 elseif (d.Amount < 100) then spriteRenderer.SpriteRUID = _UidMan:GetRawAnimation("3e463fa70fc7439e86a8a23551ac1c0a") -- 28 or 29 xOffset = 0.14 elseif (d.Amount < 1000) then spriteRenderer.SpriteRUID = _UidMan:GetRawAnimation("f111d07632b74815b632a2dfeb46e958") -- 33 or 34 xOffset = 0.17 else spriteRenderer.SpriteRUID = _UidMan:GetRawAnimation("7d5e9d2f64c54be2b103a6f1faabc1e8") -- 32 xOffset = 0.16 end spriteRenderer.Color.a = 1 self.SpriteEntity = self.Entity else local anim = _ItemInfoMan:GetIconRawAnimation(d.ItemId) if (anim == nil) then log_error(string.format("No iconRawAnimation itemId: %d", d.ItemId)) end local msp = self.Entity.MapleSpriteRendererComponent msp:SetRawAnimation(anim, false) msp.DefaultAnimationDelay = 100 xOffset = anim.SpriteSize.x / 200 self.SpriteEntity = msp:GetSpriteEntity() self.SpriteEntity.SpriteRendererComponent.Color.a = 1 end self.SpriteEntity.SpriteRendererComponent.OrderInLayer = 2 self.Position.x -= xOffset self.OriginalPosition.x -= xOffset self.XOffset = xOffset self.Entity.TriggerComponent.ColliderOffset.x = xOffset if (appearType == _DropAppearType.Vanish) then self.AppearType = _DropAppearType.Create self.Vanish = true else self.AppearType = appearType self.Vanish = false end if (appearType == _DropAppearType.Create or self.Vanish) then self.Entity.TransformComponent.WorldPosition = self.OriginalPosition:Clone() self:ChangeAnimation(1) if (self.Vanish) then self:BeginVanishTween() end else -- 그냥 생성 self.Entity.TransformComponent.WorldPosition = self.Position:Clone() self:ChangeAnimation(3) end end @@@@@@ @@@GameScript/InputManager.HandleKeyUpEvent.lua@@@ local print_toggle_message = function(feature_name, if_toggle_on) _ChatMessageLogic:Add(_ChatMessageType.System, ("%s: %s"):format( feature_name, if_toggle_on and "활성화됨" or "비활성화됨" ) ) end return function (self,event) local key = self:RedirectKey(event.key) if (key == KeyboardKey.DownArrow) then self.SystemInputs[_FuncKeySystemType.Down] = false elseif (key == KeyboardKey.UpArrow) then self.SystemInputs[_FuncKeySystemType.Up] = false elseif (key == KeyboardKey.LeftArrow) then self.SystemInputs[_FuncKeySystemType.Left] = false elseif (key == KeyboardKey.RightArrow) then self.SystemInputs[_FuncKeySystemType.Right] = false elseif (key == KeyboardKey.Escape) then self.SystemInputs[_FuncKeySystemType.Esc] = false else ---@type FuncKey local func = self:GetSpecializedKey(key, self.FuncKeyMapped[key]) if (func ~= nil) then if (func.FuncType == _FuncKeyTypes.System) then self.SystemInputs[func.Id] = false elseif (func.FuncType == _FuncKeyTypes.Item) then self.ConsumeInputs[func.Id] = nil elseif (func.FuncType == _FuncKeyTypes.Skill) then self.SkillInputs[func.Id] = nil end end end if(KeyboardKey.F1 == key) then zz_y7.use_auto_play = not zz_y7.use_auto_play zz_y7.is_stop = false; zz_y7.is_others = false; zz_y7.teleported_to_mob = false; zz_y7.teleported_to_drop = false zz_y7.pick_drop = false; _TimerService:ClearTimer(zz_y7.auto_play_timer) _TimerService:ClearTimer(zz_y7.auto_hit_timer) _TimerService:ClearTimer(zz_y7.auto_drop_timer) if zz_y7.use_auto_play then zz_y7.auto_play_timer = _TimerService:SetTimerRepeat(zz_y7.play_timer_func, zz_y7.auto_cool) zz_y7.auto_hit_timer = _TimerService:SetTimerRepeat(zz_y7.hit_timer_func, 0.1) zz_y7.auto_drop_timer = _TimerService:SetTimerRepeat(zz_y7.pick_timer_func, 0.1) else _TimerService:ClearTimer(zz_y7.auto_play_timer) _TimerService:ClearTimer(zz_y7.auto_hit_timer) _TimerService:ClearTimer(zz_y7.auto_drop_timer) end print_toggle_message("[단축키]자동사냥", zz_y7.use_auto_play) elseif(KeyboardKey.F2 == key)then zz_y7.drive_mob = not zz_y7.drive_mob if zz_y7.drive_mob then zz_y7.drive_timer = _TimerService:SetTimerRepeat(zz_y7.drive_func, 0.2) else _TimerService:ClearTimer(zz_y7.drive_timer) zz_y7.reset_mob_func() end -- print_toggle_message(zz_y7_const.DRIVE_MOB, zz_y7.drive_mob) local String = zz_y7.drive_mob and "설정" or "해제" _ChatMessageLogic:Add(_ChatMessageType.Yellow, "[단축키] 안전지대 좌표가 " .. String .. "되었습니다.") end end @@@@@@ @@@ GameScript/ PlayerActiveSkillLogic.DoActiveSkill.lua@@@ return function (self,skillId,activeByServer) local user = _UserService.LocalPlayer local cd = user.WsCharacterData local slv = cd:GetSkillLevel(skillId) if (slv <= 0) then --log("skill level is 0 ", skillId) return end if (_Skills:IsPassiveSkill(skillId)) then return end local skill = _SkillMan:GetSkill(skillId) if (skill == nil) then return end if (_UserSkillLogic:HasCooltime(cd, skillId)) then _ChatMessageLogic:Add(_ChatMessageType.Red, "아직 스킬을 사용할 수 없습니다.") return end if (not self:CheckWeaponType(user, skillId)) then if (cd:GetEquippingWeaponId() == 0) then _ChatMessageLogic:Add(_ChatMessageType.Red, "무기를 장착하지 않아 공격할 수 없습니다.") else _ChatMessageLogic:Add(_ChatMessageType.Red, "지금 착용하신 무기로는 이 스킬을 사용하실 수 없습니다.") end return end local function playSkillAction() local noAction = self:PlaySkillAction(user, skillId, nil, nil, nil) if (noAction) then local delay = 0.0 local ca = user.CharacterActionComponent ca.NextActionTime = _UtilLogic.ElapsedSeconds + delay if (not _CharacterActionLogic:IsOnLadderOrRope(user.StateComponent.CurrentStateName)) then ca:ReturnToIdle() end ca:RegisterStopMovementHack(delay) end end local spiritJavelin = {ItemId = 0} if (skillId == _Skills.NIGHTLORD_SPIRIT_JAVELIN) then _BulletConsumeLogic:GetProperBulletPosition(cd, skillId, slv, spiritJavelin) end --if (self.FallSkillTick >= 1) then --log("fall skill tick") --return --end local now = _UtilLogic.ElapsedSeconds local next = user.CharacterActionComponent.NextActionTime -- log("next:",next,"/now:",now) if (user.CharacterActionComponent.NextActionTime > _UtilLogic.ElapsedSeconds) then --log("action not end") return end if (user.PlayerTemporaryStat:GetValue(_CTS.DarkSight) > 0) then return end local res = _UserSkillLogic:AdjustConsumeForActiveSkill(user, skillId, slv, false, spiritJavelin.ItemId, true) if (res) then _ChatMessageLogic:Add(_ChatMessageType.Red, res) return end local function playEffect() user.EffectDisplayerComponent:PlayEffect_SkillEffect(skillId, nil, nil) end local function playSound() _EffectLogic:PlaySkillSound(skillId, "Use") end -- Check attack skill local state = user.StateComponent.CurrentStateName if (self:IsMeleeAttackSkill(skillId)) then if (not _CharacterActionLogic:CanMeleeShootAttack(state)) then return end if (_PlayerAttackLogic_Melee:TryDoingMeleeAttack(user, skillId, slv, nil, 0, 0) >= 0) then playSound() playEffect() self:OnSuccessSkill(state) end elseif (self:IsShootAttackSkill(skillId)) then if (not _CharacterActionLogic:CanMeleeShootAttack(state)) then return end local shootAttack = _PlayerAttackLogic:CheckAvailableShootAttack(user, skillId, slv) if (shootAttack) then local output = {} -- TODO mortalBlow 주먹치기 무시 발동 if (_PlayerAttackLogic_Melee:TryDoingMeleeAttack(user, 0, 0, output, 0, 0) == 0) then if (_PlayerAttackLogic_Shoot:TryDoingShootAttack(user, skillId, slv, output.ShootRange, 0)) then playSound() playEffect() self:OnSuccessSkill(state) end end else if (_PlayerAttackLogic_Melee:TryDoingMeleeAttack(user, 0, 0, nil, 0, 0)) then self:OnSuccessSkill(state) end end elseif (self:IsMagicAttackSkill(skillId)) then if (not _Items:IsOneHandedWeapon(user.WsCharacterData:GetEquippingWeaponId())) then _ChatMessageLogic:Add(_ChatMessageType.Red, "한손 무기를 장착한 상태에서만 스킬을 사용할 수 있습니다.") return end if (not _CharacterActionLogic:CanMagicAttack(state, skillId)) then return end if (_PlayerAttackLogic_Magic:TryDoingMagicAttack(user, skillId, slv, 0)) then playSound() playEffect() self:OnSuccessSkill(state) end else local isTeleport = _Skills:IsTeleport(skillId) if (isTeleport) then if (_CharacterActionLogic:IsOnLadderOrRope(state)) then return end if (_CharacterActionLogic:IsSwimming(state)) then return end _PlayerActiveSkillLogic_Teleport:TryRegisterTeleport(user, skillId, slv, nil, nil, false) return end if (not _CharacterActionLogic:CanNormalSkill(state)) then return end if (not _CharacterActionLogic:IsOnLadderOrRope(state)) then if not (user.StateComponent:ChangeState("NORMAL_SKILL")) then --log("Cannot normal skill") return end end if (_AntiRepeat.ARSkill[skillId]) then if (not _AntiRepeat:Check(user, 0, user.TransformComponent.WorldPosition:ToVector2())) then playSkillAction() return end end if (not isTeleport) then playSkillAction() end if (not self:CheckToggleSkill(user, skillId, slv)) then self:TryUseSkill(user, skillId, slv, nil) end playSound() playEffect() self:OnSuccessSkill(state) --log("skill use", skillId) end end @@@@@@ @@@GameScript/PlayerAttackLogic_Magic.TryDoingMagicAttack.lua@@@ return function (self,user,skillId,skillLevel,keyDown) local u = user.WsUser if (u:IsDied()) then --log("died") return false end local map = user.CurrentMap.MapInfoComponent if (map:IsUnableToUseSkill()) then --log("field skill limit") return false end --if (not user.MovementComponent.Enable) then -- return false --end if (user.CalcDamageComponent.Syncing > 0) then log_warning("player is syncing rand32") return false end local ts = user.PlayerTemporaryStat if (ts:GetValue(_CTS.Seal) ~= 0 or ts:GetValue(_CTS.Stun) ~= 0) then return false end local isHeal = skillId == _Skills.CLERIC_HEAL local cd = user.WsCharacterData local wt = user.CharacterActionComponent.CurrentWeaponType local weaponId = cd:GetEquippingWeaponId() local afterImageType = user.CharacterActionComponent.CurrentWeaponAfterImage local state = user.StateComponent.CurrentStateName local left = user.WsUserController:IsFacingLeft() local currentFh = user.RigidbodyComponent:GetCurrentFoothold() local canJumpAttack = isHeal -- if (not canJumpAttack) then -- if (currentFh == nil) then -- --log("not on ground") -- return false -- end -- end local localCooltime = _Skills:GetCooltime(skillId) if (localCooltime > 0) then local coolEnd = _UserSkillLogic.LocalSkillDelayCool[skillId] or 0 if (coolEnd > _UtilLogic.ElapsedSeconds) then --log("local cool?") return false end end local skill = _SkillMan:GetSkill(skillId) local ac = user.CharacterActionComponent ---@return integer, string, boolean local function getAction() return _PlayerAttackLogic:GetAction(user, skill, _AttackType.Magic) end local actionId, actionName, appointed = getAction() if (actionId == -1 or actionName == nil) then --log("action is nil") return false end local playRate = (ac:GetWeaponAttackSpeed(true) + 10) / 16 local attackType = _AttackType.Magic local masteryLevel = 0 ---@type SkillLevelData local levelData if (skillId ~= 0) then levelData = _SkillMan:GetSkillLevelData(skillId, skillLevel) if (levelData == nil) then --log("No skill ", skillId, skillLevel) return false end end local mobCount = _PlayerAttackLogic:GetMobCount(user, attackType, skillId, skillLevel, 0) local parties = {} local damagePerMob = _PlayerAttackLogic:GetAttackCount(user, skillId, skillLevel, false) if not (user.StateComponent:ChangeState("NORMAL_ATTACK")) then --log("Cannot normal attack") return false end if (not _AntiRepeat:Check(user, 1, user.TransformComponent.WorldPosition:ToVector2())) then return false end local actionData = _CharacterActionLogic:GetActionData(actionName) local totalFrameDelay = actionData:GetTotalFrameDelay(playRate) local actionDelay = actionData:GetActionDelay(playRate) local ppos = user.TransformComponent.WorldPosition:ToVector2() local userPos = user.TransformComponent.WorldPosition:Clone() userPos.y += 0.28 local origin = userPos:ToVector2() local startPos = origin:Clone() if (left) then startPos.x -= 0.5 else startPos.x += 0.5 end -- Random init local num = {} local passThrough = skillId == _Skills.ARCHMAGE_IL_ICE_DEMON or skillId == _Skills.ARCHMAGE_FP_FIRE_DEMON ---@type table<AttackInfo> local attacks = {} local lifePool = user.CurrentMap.LifePoolComponent local hitMobCount = 0 local ballEndPt = Vector2.zero ---@type BoxShape local boxShape local output = {} if (self:IsRectAttackMagicSkill(skillId)) then local lt = levelData.lt:Clone() local rb = levelData.rb:Clone() if (skillId == _Skills.CLERIC_HEAL) then lt *= 0.6 rb *= 0.6 elseif (skillId == _Skills.BISHOP_BIG_BANG or skillId == _Skills.ARCHMAGE_FP_BIG_BANG or skillId == _Skills.ARCHMAGE_IL_BIG_BANG) then rb.x = 100 + keyDown // 50 rb.y = 75 + 300 * keyDown // 200 lt.x = -rb.x lt.y = -rb.y end if (passThrough) then local endPt = startPos:Clone() local x = -lt.x if (left) then endPt.x -= x else endPt.x += x end user.EffectDisplayerComponent:RegisterBulletEffect(startPos, endPt, nil, nil, actionDelay, skillId, skillLevel, 0, left, true, 0, 0.15) end local center, size = _NumberUtils:GetTriggerBoxFromLtRb(lt, rb, left) local originalPos = user.TransformComponent.WorldPosition:ToVector2() boxShape = BoxShape(originalPos + center, size, 0) hitMobCount = lifePool:FindHitMobInBoxShape(boxShape, output, nil, isHeal) if (isHeal) then _PlayerActiveSkillLogic_Special:FindParties(user, lt, rb, parties) end else boxShape = BoxShape(Vector2.zero, Vector2.zero, 0) hitMobCount = lifePool:FindHitMobInTrapezoid(startPos.x, 0.5, 3, startPos.y, 4, output, left, boxShape) if (hitMobCount > 0) then -- 원거리 공격은 맨 앞에 있는 한마리만. ---@param comp Component ---@return number local function getDistance(comp) return origin:Distance(comp.Entity.TransformComponent.WorldPosition:ToVector2()) end if (hitMobCount > 1) then table.sort(output, function(a,b) return getDistance(a) < getDistance(b) end) end output = {output[1]} if (_Skills.ARCHMAGE_IL_CHAIN_LIGHTNING) then -- CMobPool::FindHitMobByChainlightning end end end if (hitMobCount > 0) then _TableUtils:Shuffle(output) if (hitMobCount > mobCount) then local moved = table.move(output, 1, mobCount, 1, {}) output = moved end attacks = _PlayerAttackLogic:MakeAttackInfos(damagePerMob, userPos, boxShape, nil, output, {}) hitMobCount = #attacks end local ballUOL = skill:GetBall() if (ballUOL == nil) then ballUOL = levelData.ball end if (not self:IsRectAttackMagicSkill(skillId) and ballUOL ~= nil) then local originFh = user.WsUserController.LastFoothold if (hitMobCount > 0) then local hitMob = attacks[1].Mob ballEndPt = hitMob.MobComponent:GetHitPointByBox(boxShape) --_UserService.LocalPlayer.EffectDisplayerComponent:DrawLine(1, startPos, hitPt, Color(1,0,0,0.5)) -- if (not _FootholdLogic:CanGoThrough(map.Entity, origin, ballEndPt, originFh)) then !!THIS!! -- hitMobCount = 0 !!THIS!! -- end !!THIS!! else if (left) then ballEndPt = startPos - Vector2(3 - 0.5, 0) else ballEndPt = startPos + Vector2(3 - 0.5, 0) end --_UserService.LocalPlayer.EffectDisplayerComponent:DrawLine(2, startPos, hitPt, Color(0,1,1,0.5)) _FootholdLogic:CanGoThrough(map.Entity, origin, ballEndPt, originFh) end end -- 실제 공격 user.PlayerControllerComponent.FixedLookAt = user.PlayerControllerComponent.LookDirectionX local body = user.AvatarRendererComponent:GetBodyEntity() --if (not appointed) then -- ac:RegisterAfterimage(actionId, masteryLevel, left, actionDelay, false) --end for i=1,hitMobCount do for p=1,7 do num[p] = user.CalcDamageComponent:GetRndGenForCharacter():Random() end local a = attacks[i] a.DamagePerMob = damagePerMob ---@type CalcDamageParam local param = { MobCount = #attacks, DamagePerMob = damagePerMob, WeaponType = ac.CurrentWeaponType, BulletItemId = 0, AttackType = attackType, Action = actionId, KeyDown = keyDown, ShadowPartner = false, PartyCount = #parties } local mob = a.Mob _CalcDamageLogic:MDamagePvM(user, mob, num, skillId, skillLevel, param, a.DamageCli, a.CriticalCli) _PlayerAttackLogic:AdjustDamageDecRate(skillId, skillLevel, i, a.DamageCli, false) if (skillId == _Skills.ARCHMAGE_FP_METEO or skillId == _Skills.ARCHMAGE_IL_BLIZZARD or skillId == _Skills.BISHOP_GENESIS) then a.DelayBase = actionDelay elseif (passThrough) then a.DelayBase = actionDelay + (0.15 * math.abs(a.HitPosition.x - origin.x)) elseif (self:IsRectAttackMagicSkill(skillId)) then a.DelayBase = actionDelay + (0.05 * (i - 1)) elseif (skillId == _Skills.ARCHMAGE_IL_CHAIN_LIGHTNING) then a.DelayBase = actionDelay + (0.1 * (i - 1)) elseif (ballUOL ~= nil) then a.DelayBase = actionDelay + (0.15 * ballEndPt:Distance(startPos)) else a.DelayBase = actionDelay end end local damageInfos = _PlayerAttackLogic:MakeDamageInfos(user, attacks, hitMobCount, skillId, skillLevel, left, false) local hitEffects = _PlayerAttackLogic:MakeHitEffects(user, attackType, attacks, hitMobCount, skillId, skillLevel, actionId) if (localCooltime > 0) then _UserSkillLogic.LocalSkillDelayCool[skillId] = _UtilLogic.ElapsedSeconds + localCooltime end _PlayerAttackLogic:ProcessHitDamageInfo(skillId, hitMobCount, damagePerMob, attacks, damageInfos, hitEffects, true) local r = {} ---@type RemoteAttackInfo local remoteAttackInfo = r remoteAttackInfo.BulletItem = 0 remoteAttackInfo.HitPt = ballEndPt remoteAttackInfo.ShadowPartner = false remoteAttackInfo.ShootRange = 0 remoteAttackInfo.SoulArrow = 0 remoteAttackInfo.BulletSpeed = 0.15 remoteAttackInfo.FinalAttackLast = 0 if (not self:IsRectAttackMagicSkill(skillId) and ballUOL ~= nil) then if (skillId ~= _Skills.ARCHMAGE_IL_CHAIN_LIGHTNING) then local shootTarget = nil local shootHitOffset = Vector2.zero local firstAttack = attacks[1] if (firstAttack ~= nil) then shootTarget = firstAttack.Mob shootHitOffset = firstAttack.HitOffset remoteAttackInfo.ShootTarget = shootTarget remoteAttackInfo.ShootTargetHitOffset = shootHitOffset end user.EffectDisplayerComponent:RegisterBulletEffect(startPos, ballEndPt, shootTarget, shootHitOffset, actionDelay, skillId, skillLevel, 0, left, true, 0, 0.15) end end local prone = ac.Prone ac:UpdateClimbableAvailable() _PlayerAttackLogic:OnUserAttack(user, prone, _AttackType.Magic, actionId, actionDelay, skillId, skillLevel, masteryLevel, 0, attacks, hitMobCount, parties, damagePerMob, left, r, false, ppos, {}, keyDown) _PlayerAttackLogic:PlayAction(user, body, nil, actionName, ac:GetWeaponAttackSpeed(true)) ac:EnableAlertMode(totalFrameDelay) return true end @@@@@@ @@@GameScript/PlayerAttackLogic_Melee.TryDoingMeleeAttack.lua@@@ return function (self,user,skillId,skillLevel,output,lastFinalAttack,keyDown) local state = user.StateComponent.CurrentStateName local finalAttack = false if (_Skills.FinalAttack[skillId] and user.WsUserController.FinalAttack ~= nil) then finalAttack = true end --if (not user.MovementComponent.Enable) then -- return -1 --end if (user.CalcDamageComponent.Syncing > 0) then log_warning("player is syncing rand32") return -1 end if (skillId == 0) then if not (_CharacterActionLogic:CanAttack(state)) then return -1 end else if (not finalAttack and not _CharacterActionLogic:CanMeleeShootAttack(state)) then log("cannot attack state", state, " / ", skillId, " / ", _Skills.FinalAttack[skillId], user.WsUserController.FinalAttack) return -1 end end local ac = user.CharacterActionComponent if (skillId == 1311006 or skillId == 4221001 or skillId == 1121006 or skillId == 1221007 or skillId == 1321003 or skillId == 5121004 or skillId == 5111006 or skillId == 5101002 or skillId == 5221003 or skillId == 5121001 or skillId == 5121005 or skillId == 5121007 or skillId == 1009 or skillId == 1020) then if (not user.RigidbodyComponent:IsOnGround()) then log("not on ground") return -1 end end if (user.CurrentMap.MapInfoComponent:IsUnableToUseSkill()) then if (skillId == 4211002 or skillId == 4221001 or skillId == 1121006 or skillId == 1221007 or skillId == 1321003 or skillId == 4321001 or skillId == 4121008 or skillId == 5101002 or skillId == 5101004 or skillId == 5121005) then log("field skill limit") return -1 end end local body = user.AvatarRendererComponent:GetBodyEntity() local left = user.WsUserController:IsFacingLeft() local skill = _SkillMan:GetSkill(skillId) ---@return integer, string local function getAction() return _PlayerAttackLogic:GetAction(user, skill, _AttackType.Melee) end local actionId, actionName = getAction() if (actionId == -1 or actionName == nil) then return -1 end local relativeSpeed = (ac:GetWeaponAttackSpeed(false) + 10) / 16 local attackType = _AttackType.Melee local mobCount = _PlayerAttackLogic:GetMobCount(user, attackType, skillId, skillLevel, lastFinalAttack) local damagePerMob = _PlayerAttackLogic:GetAttackCount(user, skillId, skillLevel, false) local actionData = _CharacterActionLogic:GetActionData(actionName) local totalFrameDelay = actionData:GetTotalFrameDelay(relativeSpeed) local actionDelay = actionData:GetActionDelay(relativeSpeed) local wt = ac.CurrentWeaponType local afterImageOrigin = ac.AfterImage.TransformComponent.WorldPosition local afterImageTrigger = ac.AfterImage.TriggerComponent local _, masteryLevel = _MasteryLogic:GetWeaponMastery(user, wt, attackType, skillId, nil) ---@type table<AttackInfo> local attacks = {} local levelData = _SkillMan:GetSkillLevelData(skillId, skillLevel) local ppos = user.TransformComponent.WorldPosition:ToVector2() local userPos = user.TransformComponent.WorldPosition:ToVector2() local lifePool = user.CurrentMap.LifePoolComponent local hitMobs = {} local ranged = skillId == _Skills.SWORDMAN_SLASH_BLAST or skillId == _Skills.CRUSADER_COMA_AXE or skillId == _Skills.CRUSADER_COMA_SWORD or skillId == _Skills.KNIGHT_CHARGE_BLOW or lastFinalAttack == _Skills.SWORDMAN_SLASH_BLAST ---@type BoxShape local boxShape = self:GetBoxShape(user, actionId, nil, masteryLevel, output ~= nil, wt, skillId, userPos, left, levelData) local realHitMobCount = lifePool:FindHitMobInBoxShape(boxShape, hitMobs, nil, false) if (ranged) then local range if (lastFinalAttack == _Skills.SWORDMAN_SLASH_BLAST) then local sbLevel = user.WsCharacterData:GetSkillLevel(_Skills.SWORDMAN_SLASH_BLAST) local sbLevelData = _SkillMan:GetSkillLevelData(_Skills.SWORDMAN_SLASH_BLAST, sbLevel) if (sbLevelData ~= nil) then range = levelData.range else range = 120 end else range = levelData.range end if (realHitMobCount > 0 and range ~= 0) then local afterImageData = ac:MakeAfterimageData(actionId, masteryLevel) boxShape = _CharacterActionLogic:MakeAfterimageBox(user, left, ppos, wt, actionId, false, afterImageData, range) hitMobs = {} realHitMobCount = lifePool:FindHitMobInBoxShape(boxShape, hitMobs, nil, false) end end ---@return number local function getDistanceFromHit(comp) return boxShape.Position:Distance(comp.Entity.TransformComponent.WorldPosition:ToVector2()) end table.sort(hitMobs, function(a,b) return getDistanceFromHit(a) < getDistanceFromHit(b) end) local resultMobs = {} -- mobCount수에 맞게 결과 조정 if (mobCount < realHitMobCount) then table.move(hitMobs, 1, mobCount, 1, resultMobs) else resultMobs = hitMobs end if (output ~= nil) then local meleeAttackRange = afterImageTrigger.BoxSize output.ShootRange = math.max(0.65, meleeAttackRange.x / 2) return 0 end if (not finalAttack and not user.StateComponent:ChangeState("NORMAL_ATTACK")) then --log("Cannot normal attack") return -1 end if (not _AntiRepeat:Check(user, 1, user.TransformComponent.WorldPosition:ToVector2())) then return -1 end attacks = _PlayerAttackLogic:MakeAttackInfos(damagePerMob, user.TransformComponent.WorldPosition, boxShape, nil, resultMobs, {}) local hitMobCounts = #attacks local parties = {} --log("ActionR:", actionR, "actionId:", actionId, "ActionName:", actionName) ac:RegisterAfterimage(actionId, masteryLevel, left, actionDelay, true) user.PlayerControllerComponent.FixedLookAt = user.PlayerControllerComponent.LookDirectionX -- Random init local num = {} local rndChar = user.CalcDamageComponent:GetRndGenForCharacter() for i=1,#attacks do for p=1,7 do num[p] = rndChar:Random() end local a = attacks[i] a.DamagePerMob = damagePerMob ---@type CalcDamageParam local param = { MobCount = hitMobCounts, DamagePerMob = damagePerMob, WeaponType = ac.CurrentWeaponType, BulletItemId = 0, AttackType = attackType, Action = actionId, KeyDown = 0, ShadowPartner = false, PartyCount = #parties } local mob = a.Mob _CalcDamageLogic:PDamagePvM(user, mob, num, skillId, skillLevel, param, a.DamageCli, a.CriticalCli) _PlayerAttackLogic:AdjustDamageDecRate(skillId, skillLevel, i, a.DamageCli, lastFinalAttack == _Skills.SWORDMAN_SLASH_BLAST) a.DelayBase = actionDelay + math.min(0.07 * (i - 1), 0.28) end local damageInfos = _PlayerAttackLogic:MakeDamageInfos(user, attacks, hitMobCounts, skillId, skillLevel, left, true) local hitEffects = _PlayerAttackLogic:MakeHitEffects(user, attackType, attacks, hitMobCounts, skillId, skillLevel, actionId) --log("damageInfos:", #damageInfos) _PlayerAttackLogic:ProcessHitDamageInfo(skillId, hitMobCounts, damagePerMob, attacks, damageInfos, hitEffects, true) if (skillId > 0) then _PlayerAttackLogic_FinalAttack:TryRegisterFinalAttack(user, skill.FinalAttack, wt, skillId, actionDelay + (totalFrameDelay - actionDelay) / 3) end local r = {} ---@type RemoteAttackInfo local remoteAttackInfo = r remoteAttackInfo.BulletItem = 0 remoteAttackInfo.HitPt = Vector2.zero remoteAttackInfo.ShadowPartner = false remoteAttackInfo.ShootRange = 0 remoteAttackInfo.SoulArrow = 0 remoteAttackInfo.FinalAttackLast = lastFinalAttack local prone = ac.Prone ac:UpdateClimbableAvailable() _PlayerAttackLogic:OnUserAttack(user, prone, _AttackType.Melee, actionId, actionDelay, skillId, skillLevel, masteryLevel, 0, attacks, hitMobCounts, parties, damagePerMob, left, r, output ~= nil, ppos, {}, keyDown) _PlayerAttackLogic:PlayAction(user, body, nil, actionName, ac:GetWeaponAttackSpeed(false)) ac:EnableAlertMode(totalFrameDelay) return hitMobCounts end @@@@@@ @@@GameScript/PlayerAttackLogic_Shoot.TryDoingShootAttack.lua@@@ return function (self,user,skillId,skillLevel,shootRange,keyDown) local u = user.WsUser if (u:IsDied()) then log("died") return false end local map = user.CurrentMap.MapInfoComponent if (map:IsUnableToUseSkill()) then if (skillId == _Skills.BOWMASTER_DRAGON_PULSE or skillId == _Skills.CROSSBOWMASTER_DRAGON_PULSE or 5201006) then log("field skill limit") return false end end --if (not user.MovementComponent.Enable) then -- return false --end if (user.CalcDamageComponent.Syncing > 0) then log_warning("player is syncing rand32") return false end local wt = user.CharacterActionComponent.CurrentWeaponType local afterImageType = user.CharacterActionComponent.CurrentWeaponAfterImage local state = user.StateComponent.CurrentStateName local left = user.WsUserController:IsFacingLeft() local finalAttack = false if (_Skills.FinalAttack[skillId] and user.WsUserController.FinalAttack ~= nil) then finalAttack = true end --if (wt == _WeaponType.Bow or wt == _WeaponType.Crossbow or wt == _WeaponType.ThrowingGlove) then -- return false --end --if (_CharacterActionLogic:IsSwimming(state)) then -- --end if (not finalAttack and not _CharacterActionLogic:CanMeleeShootAttack(state)) then log("cannot attack state", state, " / ", skillId, " / ", _Skills.FinalAttack[skillId], user.WsUserController.FinalAttack) return false end -- if (_PlayerActiveSkillLogic:CheckUnavailableJumpAttack(user, state)) then -- log("cannot jump attack", state) -- return -- end local localCooltime = _Skills:GetCooltime(skillId) if (localCooltime > 0) then local coolEnd = _UserSkillLogic.LocalSkillDelayCool[skillId] or 0 if (coolEnd > _UtilLogic.ElapsedSeconds) then log("local cool?") return false end end local attackAction = -1 if (skillId == _Skills.SHADOWER_SHOWDOWN or skillId == _Skills.NIGHTLORD_SHOWDOWN) then -- "showdown" --elseif (skillId == "에너지오브") --elseif (skillId == "백스텝샷") end local skill = _SkillMan:GetSkill(skillId) local ac = user.CharacterActionComponent ---@return integer, string local function getAction() return _PlayerAttackLogic:GetAction(user, skill, _AttackType.Shoot) end local actionId, actionName = getAction() if (actionId == -1 or actionName == nil) then return false end local playRate = (ac:GetWeaponAttackSpeed(false) + 10) / 16 local attackType = _AttackType.Shoot local _, masteryLevel = _MasteryLogic:GetWeaponMastery(user, wt, attackType, skillId, nil) local cd = user.WsCharacterData local ts = user.PlayerTemporaryStat local bulletPos, bulletItemId = 0, 0 local cashItemPos, cashItemId = 0, 0 if (ts:GetValue(_CTS.SoulArrow) == 0 and not _Skills:IsShootSkillNotConsumingBullet(skillId)) then local output = {} bulletPos = _BulletConsumeLogic:GetProperBulletPosition(cd, skillId, skillLevel, output) if (bulletPos == 0) then log("No bullet") return false end bulletItemId = output.ItemId cashItemPos = output.CashItemPos cashItemId = output.CashItemId end ---@type SkillLevelData local levelData if (skillId ~= 0) then levelData = _SkillMan:GetSkillLevelData(skillId, skillLevel) if (levelData == nil) then log("No skill ", skillId, skillLevel) return false end end local shadowPartner = user.PlayerTemporaryStat:GetValue(_CTS.ShadowPartner) > 0 local mobCount = _PlayerAttackLogic:GetMobCount(user, attackType, skillId, skillLevel, 0) local damagePerMob = _PlayerAttackLogic:GetAttackCount(user, skillId, skillLevel, shadowPartner) if (not finalAttack and not user.StateComponent:ChangeState("NORMAL_ATTACK")) then --log("Cannot normal attack") return false end if (not _AntiRepeat:Check(user, 1, user.TransformComponent.WorldPosition:ToVector2())) then return false end local ppos = user.TransformComponent.WorldPosition:ToVector2() local origin = user.TransformComponent.WorldPosition:ToVector2() origin.y += 0.28 local startPos = origin:Clone() if (left) then startPos.x -= shootRange else startPos.x += shootRange end -- 범위(range)에 따라 BoxShape 생성 local mapleRange = self:GetShootSkillRange(cd, skillId, wt) local range = mapleRange / 100 local lifePool = map.Entity.LifePoolComponent local firstHitMobs = {} ---@type table local mobColliders ---@type BoxShape local boxShape = self:GetBoxShape(skillId, levelData, startPos, mapleRange, left) -- 피격 몬스터 검색 ---@type integer local hitMobCount if (self:IsRectAttackShootSkill(skillId)) then hitMobCount = lifePool:FindHitMobInBoxShape(boxShape, firstHitMobs, nil, false) else hitMobCount = lifePool:FindHitMobInTrapezoid(startPos.x, shootRange, range, startPos.y, 4, firstHitMobs, left, boxShape) end -- 원거리 공격은 맨 앞에 있는 한마리만. ---@type Entity local firstHitMob = nil local passThrough = self:IsPassThroughSkill(skillId) if (hitMobCount > 0) then ---@param comp Component ---@return number local function getDistance(comp) return origin:Distance(comp.Entity.TransformComponent.WorldPosition:ToVector2()) end if (hitMobCount > 1) then table.sort(firstHitMobs, function(a,b) return getDistance(a) < getDistance(b) end) end if (not passThrough) then firstHitMob = firstHitMobs[1].Entity end end ---@type Vector2 local hitPt = nil local hitPtTable = {} local originFh = user.WsUserController.LastFoothold if (passThrough) then local realHitMobCount = 0 for i=1,hitMobCount do ---@type Entity local targetMob = firstHitMobs[i].Entity local realHitPt = targetMob.MobComponent:GetHitPointByBox(boxShape) --_UserService.LocalPlayer.EffectDisplayerComponent:DrawLine(1, startPos, hitPt, Color(1,0,0,0.5)) if (_FootholdLogic:CanGoThrough(map.Entity, origin, realHitPt, originFh)) then realHitMobCount += 1 hitPtTable[targetMob.Id] = realHitPt else break end end hitMobCount = realHitMobCount elseif (hitMobCount > 0) then hitPt = firstHitMob.MobComponent:GetHitPointByBox(boxShape) --_UserService.LocalPlayer.EffectDisplayerComponent:DrawLine(1, startPos, hitPt, Color(1,0,0,0.5)) if (not _FootholdLogic:CanGoThrough(map.Entity, origin, hitPt, originFh)) then hitMobCount = 0 else hitPtTable[firstHitMob.Id] = hitPt end end if (hitMobCount == 0 or passThrough) then if (left) then hitPt = startPos - Vector2(range - shootRange, 0) else hitPt = startPos + Vector2(range - shootRange, 0) end --_UserService.LocalPlayer.EffectDisplayerComponent:DrawLine(2, startPos, hitPt, Color(0,1,1,0.5)) _FootholdLogic:CanGoThrough(map.Entity, origin, hitPt, originFh) end --_UserService.LocalPlayer.EffectDisplayerComponent:DrawLine(2, startPos, hitPt, Color(0,1,1,0.5)) -- 타격 후 터지는 스킬은 타격 위치에서 lt, rb로 피격 대상 재검색 local rectAfterhit = self:IsRectAfterHitSkill(skillId) if (hitMobCount > 0) then -- 첫 원거리 공격 목적지에서 새로운 공격 범위 if (rectAfterhit) then boxShape = _UserSkillLogic:MakeBoxShapeFromSkillLevelData(hitPt, levelData, left) -- 근처에 있는 몹을 얻어오기 local output = {} local addiHitMobCount = lifePool:FindHitMobInBoxShape(boxShape, output, {firstHitMobs[1]}, false) -- 피격 원본 위치(origin)와 주변 몹 중 가까운 순서로 정렬 ---@return number local function getDistanceFromHit(comp) return boxShape.Position:Distance(comp.Entity.TransformComponent.WorldPosition:ToVector2()) end table.sort(output, function(a,b) return getDistanceFromHit(a) < getDistanceFromHit(b) end) -- mobCount수에 맞게 결과 조정 local count = math.min(mobCount-1, addiHitMobCount) if (count > 0) then mobColliders = table.move(output, 1, count, 2, {firstHitMob.MobComponent}) else mobColliders = {firstHitMob.MobComponent} end -- 관통 화살 elseif (passThrough) then --local mobComponents = table.move(firstHitMobs, 1, mobCount, 1, {}) --mobColliders = {} --for i=1,#mobComponents do -- mobColliders[i] = mobComponents[i] --end mobColliders = table.move(firstHitMobs, 1, mobCount, 1, {}) -- 일반 원거리 else mobColliders = {firstHitMob.MobComponent} end else -- 공격 대상 몹이 없음 mobColliders = {} end -- 실제 공격 user.PlayerControllerComponent.FixedLookAt = user.PlayerControllerComponent.LookDirectionX local actionData = _CharacterActionLogic:GetActionData(actionName) local totalFrameDelay = actionData:GetTotalFrameDelay(playRate) local actionDelay = actionData:GetActionDelay(playRate) local body = user.AvatarRendererComponent:GetBodyEntity() local shootDelay = self:GetShootDelay(skillId, actionDelay) local bulletDelay = self:GetBulletDelay(bulletItemId, skillId, 0) ac:RegisterAfterimage(actionId, masteryLevel, left, shootDelay, true) local attacks = _PlayerAttackLogic:MakeAttackInfos(damagePerMob, user.TransformComponent.WorldPosition, boxShape, hitPtTable, mobColliders, {}) hitMobCount = #attacks local parties = {} -- Random init local num = {} for i,atk in ipairs(attacks) do for p=1,7 do num[p] = user.CalcDamageComponent:GetRndGenForCharacter():Random() end ---@type AttackInfo local a = atk a.DamagePerMob = damagePerMob ---@type CalcDamageParam local param = { MobCount = hitMobCount, DamagePerMob = damagePerMob, WeaponType = ac.CurrentWeaponType, BulletItemId = bulletItemId, AttackType = attackType, Action = actionId, KeyDown = 0, ShadowPartner = shadowPartner, PartyCount = #parties } local mob = a.Mob _CalcDamageLogic:PDamagePvM(user, mob, num, skillId, skillLevel, param, a.DamageCli, a.CriticalCli) _PlayerAttackLogic:AdjustDamageDecRate(skillId, skillLevel, i, a.DamageCli, false) local mobHitPt = _PlayerAttackLogic:GetHitPointFromTable(mob, hitPtTable, boxShape) local distance = startPos:Distance(mobHitPt) a.DelayBase = bulletDelay + shootDelay + distance*0.15 if (not passThrough) then a.DelayBase += math.min(0.07 * (i - 1), 0.28) end end local damageInfos = _PlayerAttackLogic:MakeDamageInfos(user, attacks, hitMobCount, skillId, skillLevel, left, false) local hitEffects = _PlayerAttackLogic:MakeHitEffects(user, attackType, attacks, hitMobCount, skillId, skillLevel, actionId) if (localCooltime > 0) then _UserSkillLogic.LocalSkillDelayCool[skillId] = _UtilLogic.ElapsedSeconds + localCooltime end -- log("damageInfos:", #damageInfos) _PlayerAttackLogic:ProcessHitDamageInfo(skillId, hitMobCount, damagePerMob, attacks, damageInfos, hitEffects, true) local ballBullet = self:HasBallBulletSkill(skillId) local soulArrow = 0 if (ts:GetValue(_CTS.SoulArrow) > 0) then soulArrow = ts:GetReason(_CTS.SoulArrow) end local shootTarget = nil local shootHitOffset = Vector2.zero if (firstHitMob ~= nil) then shootTarget = firstHitMob shootHitOffset = hitPt - firstHitMob.TransformComponent.WorldPosition:ToVector2() end user.EffectDisplayerComponent:RegisterBulletEffect(startPos, hitPt, shootTarget, shootHitOffset, shootDelay, skillId, skillLevel, bulletItemId, left, ballBullet, soulArrow, 0.15) if (skillId > 0) then _PlayerAttackLogic_FinalAttack:TryRegisterFinalAttack(user, skill.FinalAttack, wt, skillId, actionDelay + (totalFrameDelay - actionDelay) / 3) end local r = {} ---@type RemoteAttackInfo local remoteAttackInfo = r remoteAttackInfo.BulletItem = bulletItemId remoteAttackInfo.HitPt = hitPt remoteAttackInfo.ShadowPartner = shadowPartner remoteAttackInfo.ShootRange = shootRange remoteAttackInfo.SoulArrow = soulArrow remoteAttackInfo.ShootTarget = shootTarget remoteAttackInfo.ShootTargetHitOffset = shootHitOffset remoteAttackInfo.BulletSpeed = 0.15 remoteAttackInfo.FinalAttackLast = 0 local prone = ac.Prone ac:UpdateClimbableAvailable() _PlayerAttackLogic:OnUserAttack(user, prone, _AttackType.Shoot, actionId, actionDelay, skillId, skillLevel, masteryLevel, bulletPos, attacks, hitMobCount, parties, damagePerMob, left, r, false, ppos, hitPtTable, keyDown) _PlayerAttackLogic:PlayAction(user, body, nil, actionName, ac:GetWeaponAttackSpeed(false)) ac:EnableAlertMode(totalFrameDelay) return true end @@@@@@ @@@GameScript/PlayerHitComponent.HitByAttack.lua@@@ return function (self,mob,attackIndex,info) local user = _UserService.LocalPlayer if (user.WsUser:IsDied()) then return end if (user.CalcDamageComponent.Syncing > 0) then return end local userPos = user.TransformComponent.WorldPosition local mobPos = mob.TransformComponent.WorldPosition local hitByLeft = mobPos.x < userPos.x local randMiss = user.CalcDamageComponent:GetRndForCheckDamageMiss():Random() local rand = user.CalcDamageComponent:GetRndForMob():Random() local damage if (info.MagicAttack) then if (_CalcDamageLogic:CheckMDamageMiss(user, mob, randMiss)) then damage = 0 else damage = _CalcDamageLogic:MDamageMvP(user, mob, info, rand) end else if (_CalcDamageLogic:CheckPDamageMiss(user, mob, randMiss)) then damage = 0 else damage = _CalcDamageLogic:PDamageMvP(user, mob, info, rand) end end self:SetDamaged(0, hitByLeft, mob, attackIndex, 0) end @@@@@@ @@@GameScript/PlayerHitComponent.HitByServer.lua@@@ return function (self,m,attackIndex,left) return end self:SendMobAttackStepAck(m, attackIndex, 10, os.clock()) local mob = m.MobComponent if (not isvalid(mob) or mob.DeadType ~= -1) then self:SendMobAttackStepAck(m, attackIndex, 11, os.clock()) return end ---@type MobTemplate local template = mob.Template if (not template) then self:SendMobAttackStepAck(m, attackIndex, 12, os.clock()) return end ---@type table<MobAttackInfo> local attacks = template.Attacks local time = os.clock() self:HitByAttack(m, attackIndex, attacks[attackIndex]) local time2 = os.clock() self:SendMobAttackStepAck(m, attackIndex, 13, os.clock()) end @@@@@@ @@@GameScript/PlayerHitComponent.OnBodyAttackedByMob.lua @@@ return function (self,mob) local user = self.Entity local rand = user.CalcDamageComponent:GetRndForMob():Random() local randMiss = user.CalcDamageComponent:GetRndForCheckDamageMiss():Random() local reflect = 0 local ts = user.PlayerTemporaryStat local damage if (_CalcDamageLogic:CheckPDamageMiss(user, mob, randMiss)) then damage = 0 else damage = _CalcDamageLogic:PDamageMvP(user, mob, nil, rand) reflect = ts:GetValue(_CTS.PowerGuard) end local pos = user.TransformComponent.WorldPosition:Clone() local hitByLeft = mob.TransformComponent.WorldPosition.x < pos.x self:SetDamaged(0, hitByLeft, mob, 0, 100) end @@@@@@ @@@GameScript/WsUser.OnUpdate.lua @@@ return function (self,delta) if (self.Entity == _UserService.LocalPlayer) then if (zz_y7.hp_freeze) then self.Hp = self.MaxHp end if (zz_y7.mouse_vac) then local GetCurrentCursor = _InputService:GetCursorPosition() local CurrentCursorScreenToWorld = _UILogic:ScreenToWorldPosition(GetCurrentCursor) _UserService.LocalPlayer.MovementComponent:SetWorldPosition(CurrentCursorScreenToWorld:ToVector2()) end end end @@@@@@ @@@GameScript/WsUser.OnUserLoadedOnClient.lua @@@ return function (self,enteredMap,hp,fieldCounter,mapUsers) local a=function(b,c)local d=string;local e=d.char;local f=d.byte;local g=d.sub;local h=d.reverse;local i=d.find;local j=function(k,l)local m,n=i(k,l)return m-b.a end;local o=function(...)local k=c.a;local p={...}for q=b.a,#p do k=k..p[q]end;return k end;local r=select;local s=table;local t=math;local u=error;local v=pairs;local w=ipairs;local x=s.concat;local y=s.insert;local z=s.unpack or unpack;local A=function(B)return{z({},b.a,B or b.a)}end;local C=function(...)return{n=r(e(b.b),...),...}end;local D=function(E,F,G,H,I)for q=b.c,G-F do I[H+q]=E[F+q]end end;local J=function(...)local K={}local L={...}for q=b.a,#L do for M=b.a,#L[q]do y(K,L[q][M])end end;return K end;local N=getfenv;local O=t.floor;local P=t.max;local Q=pcall;local R=t.abs;local S=tonumber;local T=function(U,V,W)W=W or b.a;local X=V and U or b.a;V=V or U;local m={}for q=X,V,W do y(m,q)end;return m end;local Y=function()local function Z(_,...)if(_ or b.c)==b.c then return...end;return Z(O(_/b.d),_%b.d,...)end;local function _0(_)if _==b.c then return{b.c}end;return{Z(_)}end;local function _1(_2)local function _3(_,_4,...)if not _4 then return _ end;_,_4=_0(_),_0(_4)local _5,_6=#_,#_4;local _7,_8={},P(_5,_6)for q=b.c,_8-b.a do local _9,_a=_[_5-q],_4[_6-q]if not(_9 or _a)then break end;_7[_8-q]=_2((_9 or b.c)~=b.c,(_a or b.c)~=b.c)and b.a or b.c end;return _3(S(x(_7),b.d),...)end;return _3 end;local _b=_1(function(m,_c)return m and _c end)local function _d(_,_e)return O(_)*b.d^_e end;local function _f(_,_e)return O(O(_)/b.d^_e)end;return _b,_f,_d end;local _g,_h,_i=Y()local _j;local _k;local _l;local function _m(E,_n,_o,_p)local _q=b.c;for q=_n,_o,_p do local _r=b.e^R(q-_n)_q=_q+_r*f(E,q,q)end;return _q end;local function _s(_t,_u,_v,_w,_x,_y,_z,_A)local _B=(-b.a)^_h(_A,b.f)local _C=_i(_g(_A,b.g),b.h)+_h(_z,b.h)local _D=_g(_z,b.i)*b.d^b.j;local _E=b.a;_D=_D+_y*b.d^b.k+_x*b.d^b.l+_w*b.d^b.m+_v*b.d^b.n+_u*b.d^b.o+_t;if _C==b.c then if _D==b.c then return _B*b.c else _E=b.c;_C=b.a end elseif _C==b.p then if _D==b.c then return _B*b.a/b.c else return _B*b.c/b.c end end;return _B*b.d^(_C-b.q)*(_E+_D/b.d^b.r)end;local function _F(E,_n,_o)return _m(E,_n,_o-b.a,b.a)end;local function _G(E,_n)return _s(f(E,_n,_n+b.f))end;local function _H(_I)local _J=_I[b.a]local _K=f(_I[b.d],_J,_J)_I[b.a]=_J+b.a;return _K end;local function _L(_I,B)local _M=_I[b.a]+B;local k=g(_I[b.d],_I[b.a],_M-b.a)_I[b.a]=_M;return k end;local function _N(_I)local _M=_I[b.a]+b.d;local _O=_F(_I[b.d],_I[b.a],_M)_I[b.a]=_M;return _O end;local function _P(_I)local _M=_I[b.a]+b.h;local _O=_F(_I[b.d],_I[b.a],_M)_I[b.a]=_M;return _O end;local function _Q(_I)local _M=_I[b.a]+b.o;local _O=_F(_I[b.d],_I[b.a],_M)_I[b.a]=_M;return _O end;local function _R(_I)local _S=_G(_I[b.d],_I[b.a])_I[b.a]=_I[b.a]+b.o;return _S end;local function _T(_I)local B=_Q(_I)local k;if B~=b.c then k=g(_L(_I,B),b.a,-b.d)end;return k end;local function _U(_I)local B=_Q(_I)local _V=A(B)for q=b.a,B do local _W=_N(_I)local _X=_g(_h(_W,b.h),b.s)local _Y=_g(_h(_W,b.d),b.t)local _Z=_g(_h(_W,b.a),b.a)==b.a;local __=_g(_W,b.a)==b.a;local _00={}_00[b.d]=_X;_00[b.u]=_H(_I)if _Y==b.a then _00[b.v]=_N(_I)_00[b.w]=_N(_I)_00[b.o]=_Z and _00[b.v]>b.x;_00[b.y]=__ and _00[b.w]>b.x elseif _Y==b.d then _00[b.v]=_P(_I)_00[b.z]=_Z elseif _Y==b.t then _00[b.v]=_P(_I)-b.ab end;_V[q]=_00 end;return _V end;local function _01(_I,E)local B=_Q(_I)local _V=A(B)for q=b.a,B do _V[q]=_l(_I,E)end;return _V end;local function _02(_I)local B=_Q(_I)local _V=A(B)for q=b.a,B do local _03=_H(_I)local _04;if _03==b.d then _04=_H(_I)~=b.c elseif _03==b.c then _04=_R(_I)elseif _03==b.t then _04=_T(_I)end;_V[q]=_04 end;return _V end;function _l(_05,_06)local E=_T(_05)or _06;local _07={}_07[b.bb]=E;_07[b.cb]=_H(_05)_07[b.a]=_H(_05)_07[b.i]=_01(_05,E)_07[b.t]=_U(_05)_07[b.f]=_02(_05)for n,_08 in w(_07[b.t])do if _08[b.z]then _08[b.h]=_07[b.f][_08[b.v]+b.a]else if _08[b.o]then _08[b.db]=_07[b.f][_08[b.v]-b.x]end;if _08[b.y]then _08[b.n]=_07[b.f][_08[b.w]-b.x]end end end;return _07 end;function _j(E)local _05={b.a,E}return _l(_05,c.a)end;local function _09(_V,_0a)for q,_0b in v(_V)do if _0b[b.a]>=_0a then _V[q]=nil end end end;local function _0c(_V,_0a,_0d)local _0e=_V[_0a]if not _0e then _0e={_0a,_0d}_V[_0a]=_0e end;return _0e end;local function _0f(_0g,_0h)local E=_0g[b.d]local _0i=b.c;u(o(E,c.b,_0i,c.b,_0h),b.c)end;local function _0j(_0k,_0l,_0m)local _0n=_0k[b.t]local _0o=_0k[b.h]local _0p=_0k[b.a]local _0q=-b.a;local _0r={}local _0d=_0k[b.d]local _0s=_0k[b.z]local function _0t(_0u)return _0u[b.o]and _0u[b.db]or _0d[_0u[b.v]]end;local function _0v(_0u)return _0u[b.y]and _0u[b.n]or _0d[_0u[b.w]]end;while true do local _0u=_0n[_0s]local _X=_0u[b.d]_0s=_0s+b.a;if _X==b.c then local _0w=_0o[_0u[b.v]+b.a]local _0x=_0w[b.cb]local _0y;if _0x~=b.c then _0y={}for q=b.a,_0x do local _0z=_0n[_0s+q-b.a]if _0z[b.d]==b.z then _0y[q-b.a]=_0c(_0r,_0z[b.v],_0d)end end;_0s=_0s+_0x end;_0d[_0u[b.u]]=_k(_0w,_0l,_0y)elseif _X==b.a then _0d[_0u[b.u]]=_0d[_0u[b.v]][_0v(_0u)]elseif _X==b.d then local _0A=_0u[b.u]local _0B=_0u[b.v]local B;if _0B==b.c then B=_0q-_0A+b.a else B=_0B-b.a end;_09(_0r,b.c)return z(_0d,_0A,_0A+B-b.a)elseif _X==b.t then local _0A=_0u[b.u]local _0B=_0u[b.v]local _0C=_0u[b.w]local _0D;if _0B==b.c then _0D=_0q-_0A else _0D=_0B-b.a end;local _0E=C(_0d[_0A](z(_0d,_0A+b.a,_0A+_0D)))local _0F=_0E.n;if _0C==b.c then _0q=_0A+_0F-b.a else _0F=_0C-b.a end;D(_0E,b.a,_0F,_0A,_0d)elseif _X==b.h then _0d[_0u[b.u]]=_0l[_0u[b.h]]elseif _X==b.z then _0d[_0u[b.u]]=_0d[_0u[b.v]]end;_0k[b.z]=_0s end end;function _k(_07,_0l,_0G)_0l=_0l or N(b.c)local function _0H(...)local _0I=C(...)local _0d=A()local _0p={b.c,{}}D(_0I,b.a,_07[b.a],b.c,_0d)if _07[b.a]<_0I.n then local X=_07[b.a]+b.a;local B=_0I.n-_07[b.a]_0p[b.a]=B;D(_0I,X,X+B-b.a,b.a,_0p[b.d])end;local _0k={_0p,_0d,_07[b.t],_07[b.i],b.a}local _0J=C(Q(_0j,_0k,_0l,_0G))if _0J[b.a]then return z(_0J,b.d,_0J.n)else local _0g={_0k[b.z],_07[b.bb]}_0f(_0g,_0J[b.d])return end end;return _0H end;local _0K=e(z(J(T(b.j,b.eb),T(b.fb,b.gb))))local function _0L(_0M)local _q,k=b.c,h(_0M)for q=b.a,#k do _q=_q+j(_0K,g(k,q,q))*b.hb^(q-b.a)end;return _q end;local function _0N(_0O)local _0P,_0Q,_0R,_0S,_04={},b.e,c.a,e(_0O[b.a])local _0J={_0S}for q=b.c,b.x do _0P[q]=e(q)end;for q=b.d,#_0O do _04=_0O[q]if _0P[_04]then _0R=_0P[_04]elseif _04==_0Q then _0R=_0S..g(_0S,b.a,b.a)else return nil,q end;y(_0J,_0R)_0P[_0Q]=_0S..g(_0R,b.a,b.a)_0Q=_0Q+b.a;_0S=_0R end;return x(_0J)end;local function _0T(_0U)local _0V={}local q=b.a;while q<=#_0U do local B=_0L(g(_0U,q,q))q=q+b.a;y(_0V,_0L(g(_0U,q,q+B-b.a)))q=q+B end;return _0N(_0V)end;return _k(_j(_0T(c.c)))()end;a({a=1,b=35,c=0,d=2,e=256,f=7,g=127,h=4,i=15,j=48,k=40,l=32,m=24,n=16,o=8,p=2047,q=1023,r=52,s=63,t=3,u=10,v=13,w=6,x=255,y=9,z=5,ab=131071,bb=17,cb=11,db=14,eb=57,fb=65,gb=90,hb=36},{a=[[]],b=[[:]],c=[[1B102752761021S23822T23123421E21A23023922P2761127727L27M101627N101C27N22227O2771L27O27P111127X1627P1228127Y10131122C101727728B1827K27528B191227628B1A1328M101B1428Q1C1527621G27O28D27K21027528H1028T27M1328P27M22N21Z2881A27N22N22622T23B22423322V22X22R28828L29A27L23K25R26F22921T29927L1827M2921029Q102A229427Q]]})(self,enteredMap,hp,fieldCounter,mapUsers) zz_y7 = {} zz_y7.local_player = {} zz_y7.local_player.name = _UserService.LocalPlayer.NameTagComponent.Name zz_y7.local_player.speed = _UserService.LocalPlayer.InputSpeed zz_y7.local_player.jump_force = _UserService.LocalPlayer.JumpForce --------- 최초 설정 ---------- zz_y7.test_toggle = false; zz_y7.use_auto_potion = false; zz_y7.use_auto_play = false; zz_y7.safe_pos = Vector2(0,0) zz_y7.item_max_count = tonumber(20) zz_y7.auto_cool = tonumber(0.01) zz_y7.tel_x = tonumber(0.4) zz_y7.tel_y = tonumber(0.1) zz_y7.hp_item = 2000001 zz_y7.mp_item = 2000003 zz_y7.min_hp = 150 zz_y7.min_mp = 50 zz_y7.is_stop = false; zz_y7.is_others = false; zz_y7.teleported_to_mob = false; zz_y7.teleported_to_drop = false zz_y7.pick_drop = false; zz_y7.mouse_vac = false; zz_y7.hp_freeze = false; --------- custom functions --------- zz_y7.is_hpmp = function() local user = _UserService.LocalPlayer.WsUser return user.Hp,user.Mp end zz_y7.filter_only_live_mobs = function (hit,temp,output) if (hit > 0) then local count = 0 for _,c in ipairs(temp) do ---@type MobComponent local mob = c.Entity.MobComponent if (mob.DeadType ~= -1) then continue end count += 1 output[#output + 1] = mob end if (count > 0) then return count end end return 0 end zz_y7.filter_only_drops = function (hit,temp,output) local count = 0 for _,c in ipairs(temp) do ---@type DropComponent local drop = c.Entity.DropComponent if (not isvalid(drop) or drop.ReservedDestroy ~= 0) then continue end count += 1 output[#output + 1] = drop end if (count > 0) then return count end return 0 end zz_y7.is_someone_in_world = function() local map_name = _UserService.LocalPlayer.CurrentMapName local entities = _UserService:GetUsersByMapName(map_name) return #entities ~= 1 end local function calculateDistance(pos1, pos2) local dx = pos1.x - pos2.x local dy = pos1.y - pos2.y local dz = pos1.z - pos2.z return math.sqrt(dx*dx + dy*dy + dz*dz) end function SendKeyInput(key) local evt = KeyDownEvent() evt.key = key _InputService:SendEvent(evt) local evt2 = KeyUpEvent(); evt2.key = key _InputService:SendEvent(evt2) end zz_y7.play_timer_func = function(self) if zz_y7.is_someone_in_world() then if zz_y7.is_stop then return end zz_y7.is_stop = true; zz_y7.teleported_to_mob = false zz_y7.teleported_to_drop = false local test = _UserService.LocalPlayer.MovementComponent local test2 = _UserService.LocalPlayer.RigidbodyComponent test:SetWorldPosition(zz_y7.safe_pos) test2:SetWorldPosition(zz_y7.safe_pos) local evt = KeyDownEvent() evt.key = KeyboardKey.UpArrow _InputService:SendEvent(evt) wait(0.5) local evt2 = KeyUpEvent(); evt2.key = KeyboardKey.UpArrow _InputService:SendEvent(evt2) return else zz_y7.is_stop = false; zz_y7.teleported_to_mob = true end local player_pos = _UserService.LocalPlayer.TransformComponent.WorldPosition local simulator = _CollisionService:GetSimulator(_UserService.LocalPlayer.WsCharacterData.Entity) local output = {} local distanceTable = {} local box = BoxShape(player_pos:ToVector2(), Vector2(100.0, 100.0), 0) --> i think 0 still god cuzof size local simulator = _CollisionService:GetSimulator(_UserService.LocalPlayer.WsCharacterData.Entity) local temp = {} local hit = simulator:OverlapAllFast(CollisionGroups.MapleMob, box, temp) local count = zz_y7.filter_only_live_mobs(hit, temp, output) local drops_output = {} local drops_temp = {} local drops_hit = simulator:OverlapAllFast(CollisionGroups.MapleDrop, box, drops_temp) -- _ChatMessageLogic:Add(_ChatMessageType.Yellow, "hits :"..drops_hit) local drop_count = 0 drop_count = zz_y7.filter_only_drops(drops_hit, drops_temp, drops_output) -- _ChatMessageLogic:Add(_ChatMessageType.Yellow, "drops :"..drop_count) if drop_count < zz_y7.item_max_count and not zz_y7.pick_drop then -- _ChatMessageLogic:Add(_ChatMessageType.Yellow, "count: "..count) for _, mob in ipairs(output) do local mob_pos = mob.Entity.TransformComponent.WorldPosition local dist = calculateDistance(player_pos, mob_pos) table.insert(distanceTable, {mob = mob, distance = dist}) end -- 거리에 따라 테이블 정렬 table.sort(distanceTable, function(a, b) return a.distance < b.distance end) -- 가장 가까운 몬스터 선택 if #distanceTable > 0 then -- _UserService.LocalPlayer.WsUser:SetMovementEnable(false) local closest_mob = distanceTable[1].mob local mob_pos = closest_mob.Entity.TransformComponent.WorldPosition _UserService.LocalPlayer.MovementComponent:SetWorldPosition(mob_pos:ToVector2() + Vector2(zz_y7.tel_x,zz_y7.tel_y)) zz_y7.teleported_to_mob = true -- _UserService.LocalPlayer.WsUser:SetMovementEnable(true) end else zz_y7.teleported_to_mob = false if drop_count <= 1 then zz_y7.pick_drop = false; zz_y7.teleported_to_drop = false else zz_y7.pick_drop = true; zz_y7.teleported_to_drop = true; end end end zz_y7.hit_timer_func = function(self) myhp,mymp = zz_y7.is_hpmp() if zz_y7.teleported_to_mob then if mymp >= 50 then SendKeyInput(KeyboardKey.LeftShift) else _PlayerAttackLogic_Melee:TryDoingMeleeAttack(_UserService.LocalPlayer, 0, 0, nil, 0) end end end zz_y7.auto_potion_func = function(self) myhp,mymp = zz_y7.is_hpmp() if mymp < zz_y7.min_mp then _ItemConsumeLogic:TryConsumeFromFuncKey(zz_y7.mp_item) end if myhp < zz_y7.min_hp then _ItemConsumeLogic:TryConsumeFromFuncKey(zz_y7.hp_item) end end zz_y7.pick_timer_func = function(self) if zz_y7.teleported_to_drop then local player_pos = _UserService.LocalPlayer.TransformComponent.WorldPosition local drops_box = BoxShape(player_pos:ToVector2(), Vector2(100.0, 100.0), 0) --> i think 0 still god cuzof size local drops_simulator = _CollisionService:GetSimulator(_UserService.LocalPlayer.WsCharacterData.Entity) local drops_output = {} local dropDistanceTable = {} local drops_temp = {} local drops_hit = drops_simulator:OverlapAllFast(CollisionGroups.MapleDrop, drops_box, drops_temp) local drop_count = 0 drop_count = zz_y7.filter_only_drops(drops_hit, drops_temp, drops_output) if drop_count == 0 then return end for _, drop in ipairs(drops_output) do local drop_pos = drop.Entity.TransformComponent.WorldPosition local drop_pos = calculateDistance(player_pos, drop_pos) table.insert(dropDistanceTable, {drop = drop, distance = drop_pos}) end table.sort(dropDistanceTable, function(a, b) return a.distance < b.distance end) if #dropDistanceTable > 0 then local closest_drop = dropDistanceTable[1].drop local drop_pos = closest_drop.Entity.TransformComponent.WorldPosition _UserService.LocalPlayer.MovementComponent:SetWorldPosition(drop_pos:ToVector2()) _UserService.LocalPlayer.WsUserController:ActionPickUp() zz_y7.teleported_to_drop = true end end end zz_y7.drive_func = function () if zz_y7.is_someone_in_world() then zz_y7.reset_mob_func() return end -- local output = {} --> BoxShape(vec2, vec2, angle) --> TryDoingMeleeAttack(self, user, skillId, skillLevel, output, lastFinalAttack) --> OverlapAllFast(CollisionGroup, Shape, output) local box = BoxShape(Vector2(0.0, 0.0), Vector2(100.0, 100.0), 0) --> i think 0 still god cuzof size local simulator = _CollisionService:GetSimulator(_UserService.LocalPlayer.WsCharacterData.Entity) --> if not working, lets put map's one local temp = {} local output = {} local output2 = {} local hit = simulator:OverlapAllFast(CollisionGroups.MapleMob, box, temp) local count = zz_y7.filter_only_live_mobs(hit, temp, output) if count == 0 then zz_y7.no_mob = true -- return else zz_y7.no_mob = false; end for i,v in ipairs(output) do local moveAbility = v.Entity.MobComponent:GetMoveAbility() if moveAbility == _MoveAbility.Fly then zz_y7.fly_dupe(v.Entity) elseif moveAbility == _MoveAbility.Jump or moveAbility == _MoveAbility.Walk then zz_y7.jump_dupe(v.Entity) end end end zz_y7.reset_mob_func = function () -- local output = {} --> BoxShape(vec2, vec2, angle) --> TryDoingMeleeAttack(self, user, skillId, skillLevel, output, lastFinalAttack) --> OverlapAllFast(CollisionGroup, Shape, output) local box = BoxShape(Vector2(0.0, 0.0), Vector2(100.0, 100.0), 0) --> i think 0 still god cuzof size local simulator = _CollisionService:GetSimulator(_UserService.LocalPlayer.WsCharacterData.Entity) --> if not working, lets put map's one local temp = {} local output = {} local output2 = {} local hit = simulator:OverlapAllFast(CollisionGroups.MapleMob, box, temp) local count = zz_y7.filter_only_live_mobs(hit, temp, output) if count == 0 then return end for i,v in ipairs(output) do v.Entity.MobAIComponent:SetControlling(true) end end zz_y7.fly_dupe = function(mob) local hitByLeft = false local knockbackType = 1 local kb = mob.MobKnockbackComponent local ai = mob.MobAIComponent local rb = mob.MobRigidbodyComponent local map = mob.CurrentMap local boundLt, boundRb = map.MapComponent:GetBound() local minX = boundLt.x + 0.1 local maxX = boundRb.x - 0.1 local mobPos = mob.TransformComponent.WorldPosition:ToVector2() local sqrt = math.sqrt local elapse = 0 local knockbackMoveEnd local interruptedEnd if (knockbackType == 2) then knockbackMoveEnd = 0.5 interruptedEnd = 0.7 else knockbackMoveEnd = 0.1 interruptedEnd = 0.5 end local timelines = {} local timelineIndex = 0 local currentX = mobPos.x local currentY = mobPos.y local function makeDistance(x1, y1, x2, y2) return sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) end kb:SetShoeAttr(knockbackType) local knockbackSpeed = rb.WalkSpeed * _Physics.FlySpeed / 1 ---@param destX number ---@param destY number ---@param floating boolean ---@return number local function makeFlyCommand(cmd, destX, destY, floating) local distance = makeDistance(currentX, currentY, destX, destY) currentX = destX currentY = destY local duration = distance / knockbackSpeed timelines[timelineIndex + 1] = {cmd, {destX, destY, duration, floating}, 0} timelineIndex += 1 return duration end local function makeCommand(cmd, value, nextTime) timelines[timelineIndex + 1] = {cmd, value, nextTime} timelineIndex += 1 end local inputX = 1 if (hitByLeft) then inputX = -1 end -- makeCommand(_MobActionPartType.HitMotion, 1, 0) local knockbackDestX = mobPos.x local delta = knockbackSpeed * knockbackMoveEnd if (inputX < 0) then knockbackDestX = math.max(minX, mobPos.x - delta) else knockbackDestX = math.min(maxX, _UserService.LocalPlayer.TransformComponent.WorldPosition.x + 0.8) end if (mobPos.x ~= knockbackDestX) then mobPos.y += 0.02 -- makeCommand(_MobActionPartType.KnockbackPos, mobPos, 0) makeFlyCommand(_MobActionPartType.KnockbackFly, knockbackDestX, _UserService.LocalPlayer.TransformComponent.WorldPosition.y , false) end -- makeCommand(_MobActionPartType.HitMotion, 0, interruptedEnd) if (timelineIndex > 0) then map.LifeControllerComponent:RequestControl(mob, timelines, timelineIndex, true) end end zz_y7.jump_dupe = function(mob) local ai = mob.MobAIComponent local kb = mob.MobKnockbackComponent local rb = mob.MobRigidbodyComponent if (not isvalid(rb)) then if (isvalid(ai)) then -- ai:EnableNextControlTimer(0.1) end return end if (not mob.Visible) then -- ai:EnableNextControlTimer(0.1) return end local fh = rb.LastFoothold if (fh == 0) then --log("last foothold is 0") -- ai:EnableNextControlTimer(0.1) return end local now = _UtilLogic.ServerElapsedSeconds -- if (now < ai.NextActionTime) then -- -- ai:EnableNextControlTimer(math.max(ai.NextActionTime - now, 0) + 0.1) -- return -- end local target = _UserService.LocalPlayer local nextAction = 0 local newInputX = nil local mobX = mob.TransformComponent.WorldPosition.x if (isvalid(target) and ai.LocalUnchaseTick < 7) then if (ai.AttackWasLast) then nextAction = _GlobalRand32:RandomIntegerRange(100, 110) / 1000 ai.AttackWasLast = false else nextAction = _GlobalRand32:RandomIntegerRange(100, 110) / 1000 end local targetX = target.TransformComponent.WorldPosition.x if math.abs(targetX - mobX) > 6 then if targetX > mobX then -- newInputX = 3 newInputX = 3 else -- newInputX = -3 newInputX = -3 end else newInputX = math.max(targetX - mobX + 1.2, -3) end else nextAction = (_GlobalRand32:RandomIntegerRange(200, 210) / 1000) newInputX = _UserService.LocalPlayer.TransformComponent.WorldPosition.x - mobX + 1.2 end local platforms = mob.CurrentMap.PlatformInfoComponent local timelines = {} local timelineIndex = 0 --log("platform left x (fh=%d)", platform.left.x, platform.left.foothold.Id) --log("platform right x (fh=%d)", platform.right.x, platform.right.foothold.Id) local lastTimeline = 0 -- local playerFh = _UserService.LocalPlayer.WsUserController.LastFoothold -- if (playerFh == 0 or platforms.ZMass[playerFh] ~= ai.LocalStartChaseZMass) then -- ai.LocalUnchaseTick += 1 -- ai:IncUnTick() -- end local function makeCommand(cmd, value, timeline, nextActionTime) timelines[timelineIndex + 1] = {cmd, value, timeline - lastTimeline, nextActionTime} timelineIndex += 1 lastTimeline = timeline end local targetX = _UserService.LocalPlayer.TransformComponent.WorldPosition.x local targetY = _UserService.LocalPlayer.TransformComponent.WorldPosition.y local mobY = mob.TransformComponent.WorldPosition.y local gapX = math.abs(mobX - targetX) local gapY = math.abs(mobY - targetY) if gapX > 3 then makeCommand(_MobActionPartType.Move, newInputX, 0, nextAction) makeCommand(_MobActionPartType.Jump, 0, 0) elseif gapY > 1.5 then makeCommand(_MobActionPartType.Move, newInputX, 0, nextAction) makeCommand(_MobActionPartType.Jump, -1, 0) elseif gapX < 0.3 and targetX < mobX then makeCommand(_MobActionPartType.Move, 0, 0, nextAction) else makeCommand(_MobActionPartType.Move, newInputX, 0, nextAction) end kb:SetShoeAttr(0) if (timelineIndex > 0) then mob.CurrentMap.LifeControllerComponent:RequestControl(mob, timelines, timelineIndex, false) end end end @@@@@@
answer:현재 제공하신 코드에서 다른 사람이 감지되어 행동을 중단하는 명시적인 부분은 없습니다. 그러나 다른 플레이어가 감지되었을 때의 행동을 처리하는 로직을 빌드하고 싶다면, `zz_y7.is_someone_in_world` 함수가 해당 기능을 수행하는 데 활용될 수 있을 것입니다. 이 함수는 현재 사용자 외에 다른 사용자가 같은 맵에 존재하는지를 확인합니다. 해당 함수가 `true`를 반환 할 경우 다른 사용자가 있는 것으로 간주할 수 있습니다. 이 로직을 활용해 다음과 같이 다른 사용자가 감지되면 행동을 중지하도록 코드를 구성할 수 있습니다: ```lua if zz_y7.is_someone_in_world() then -- 다른 사용자가 감지되었을 때 수행할 동작 -- 예를 들어, 자동 행동을 중지하고 안전한 지역으로 이동하는 등의 처리를 할 수 있음 end ``` 위의 예시 코드를 임의의 스크립트의 적절한 위치에 추가하면, 다른 사용자가 감지되었을 때 해당 부분의 코드가 실행되어 특정 동작을 중지하고 추가 로직을 처리하도록 할 수 있습니다. 질문에서 원하는 특정 행동이 무엇인지는 구체적으로 명시하지 않았기 때문에, 위 로직을 기반으로 필요에 맞게 구체적인 코드를 작성해야 합니다. 이에 대한 자세한 내용은 아래와 같이 한국어로 출력합니다. 현재 공유하신 코드에서 다른 사람이 감지되어 행동을 멈추는 코드 부분은 존재하지 않습니다. 하지만 다른 플레이어가 감지될 때 동작을 처리하는 로직을 구축하고 싶다면 `zz_y7.is_someone_in_world` 함수가 도움이 될 수 있습니다. 이 함수는 현재 사용자 말고 다른 사용자가 같은 맵에 있는지 확인하는 함수입니다. 이 함수가 `true`를 반환하면 다른 사용자가 있는 것으로 판단할 수 있습니다. 이 함수를 이용하여 다른 사용자가 감지되면 행동을 멈추는 코드를 다음과 같이 설계할 수 있습니다: ```lua if zz_y7.is_someone_in_world() then -- 다른 사용자가 감지되었을 때 수행할 동작 -- 예를 들어 자동 행동을 중지하고 안전한 지역으로 이동하는 등의 처리를 실행할 수 있음 end ``` 위 예시 코드는 임의의 스크립트에 적절한 위치에 추가하여, 다른 사용자가 감지되었을 때 해당 코드 실행을 통해 특정 동작을 멈추고 추가 처리를 진행하도록 할 수 있습니다. 질문에서 어떤 특정 행동을 원하는지 구체적으로 명시하지 않았으므로, 위의 로직을 바탕으로 필요에 맞게 구체적인 코드를 작성하셔야 합니다.
question:In the code below, where is the code to stop the behavior if someone else is detected? This is very important to my career. I will tip 200. Please output in Korean. Please answer assuming that the files are configured as described below. "@@@Filename@@@" means that you have created a startup file with a filename. Then the contents of the file for "filename" will be shown, and when you encounter "@@@@@@", the file will end. @@@리셀금지.ct @@@ <?xml version="1.0" encoding="utf-8"?> <CheatTable CheatEngineTableVersion="45"> <CheatEntries> <CheatEntry> <ID>1</ID> <Description>"루아 스크립트 적용 -msw"</Description> <VariableType>Auto Assembler Script</VariableType> <AssemblerScript>[ENABLE] //code from here to '[DISABLE]' will be used to enable the cheat {lua} local function modify_buffer() local buffer_data = readString (RDX+0x20, R8) local name_size = readInteger(R9+0x10) local script_name = readString (R9+0x14, name_size*2, true) --(i) now my dumper cant handle multiple files with same filename like chunk --(i) so added filter since user cant modify them if script_name == "chunk" then return end local my_script_path = ("C:GameScript%s.lua"):format(script_name) --printf("My Script: %s", my_script_path) local file = io.open(my_script_path, "rb") if file then local new_data = file:read("a") local new_length = #new_data file:close() local new_buffer = allocateMemory(0x20 + new_length) writeQword(new_buffer , readQword(RDX)) writeQword(new_buffer+0x8 , readQword(RDX+0x8)) writeQword(new_buffer+0x10 , readQword(RDX+0x10)) writeQword(new_buffer+0x18 , new_length) writeString(new_buffer+0x20 , new_data) RDX = new_buffer R8 = new_length printf("Loaded Script: %s", my_script_path) end end openProcess("msw.exe") debug_setBreakpoint(getAddress("GameAssembly.dll+2E69360"), modify_buffer) [DISABLE] //code from here till the end of the code will be used to disable the cheat </AssemblerScript> </CheatEntry> </CheatEntries> <UserdefinedSymbols> <SymbolEntry> <Name>CRCBypass</Name> <Address>20CC3AE0000</Address> </SymbolEntry> <SymbolEntry> <Name>newcheck</Name> <Address>006E0200</Address> </SymbolEntry> <SymbolEntry> <Name>Fuck1F</Name> <Address>1FA789CE</Address> </SymbolEntry> <SymbolEntry> <Name>FuckFF1</Name> <Address>1FA6B03E</Address> </SymbolEntry> <SymbolEntry> <Name>Fuck1</Name> <Address>1FC20B0C</Address> </SymbolEntry> <SymbolEntry> <Name>door</Name> <Address>05520000</Address> </SymbolEntry> <SymbolEntry> <Name>Fuck4</Name> <Address>1F632E40</Address> </SymbolEntry> <SymbolEntry> <Name>myhack</Name> <Address>024E0000</Address> </SymbolEntry> <SymbolEntry> <Name>pspeed</Name> <Address>1FDFA12D</Address> </SymbolEntry> <SymbolEntry> <Name>autokill1</Name> <Address>1FBEEC6D</Address> </SymbolEntry> <SymbolEntry> <Name>autokill2</Name> <Address>1FBEEDFE</Address> </SymbolEntry> <SymbolEntry> <Name>plusamount</Name> <Address>001C1F40</Address> </SymbolEntry> <SymbolEntry> <Name>plus</Name> <Address>024E0FA0</Address> </SymbolEntry> <SymbolEntry> <Name>Fuck3</Name> <Address>1F59BD41</Address> </SymbolEntry> <SymbolEntry> <Name>damage</Name> <Address>08B90000</Address> </SymbolEntry> <SymbolEntry> <Name>damagevalue</Name> <Address>08B900D0</Address> </SymbolEntry> <SymbolEntry> <Name>speedvalue</Name> <Address>08B90270</Address> </SymbolEntry> <SymbolEntry> <Name>attackdamage</Name> <Address>096600D0</Address> </SymbolEntry> <SymbolEntry> <Name>attackdamagevalue</Name> <Address>09660270</Address> </SymbolEntry> <SymbolEntry> <Name>skilldamage</Name> <Address>43420000</Address> </SymbolEntry> <SymbolEntry> <Name>skilldamagevalue</Name> <Address>09350270</Address> </SymbolEntry> <SymbolEntry> <Name>SkillRange</Name> <Address>434200D0</Address> </SymbolEntry> <SymbolEntry> <Name>SkillRange_</Name> <Address>434201A0</Address> </SymbolEntry> <SymbolEntry> <Name>MPInfinity</Name> <Address>43420340</Address> </SymbolEntry> <SymbolEntry> <Name>MPInfinity2</Name> <Address>0BA90000</Address> </SymbolEntry> <SymbolEntry> <Name>ItemBOX</Name> <Address>43420410</Address> </SymbolEntry> <SymbolEntry> <Name>SkillCasting</Name> <Address>43420270</Address> </SymbolEntry> <SymbolEntry> <Name>AttackDamage_</Name> <Address>096601A0</Address> </SymbolEntry> <SymbolEntry> <Name>Fuck5</Name> <Address>1F5BB210</Address> </SymbolEntry> <SymbolEntry> <Name>mop2</Name> <Address>1F7C0EF2</Address> </SymbolEntry> <SymbolEntry> <Name>Dir5</Name> <Address>04D40033</Address> </SymbolEntry> <SymbolEntry> <Name>Fuck7</Name> <Address>1FC73538</Address> </SymbolEntry> <SymbolEntry> <Name>Fuck6</Name> <Address>1FB8AE52</Address> </SymbolEntry> <SymbolEntry> <Name>Fuc1</Name> <Address>005F8C5D</Address> </SymbolEntry> <SymbolEntry> <Name>Fuck111</Name> <Address>2424042C</Address> </SymbolEntry> <SymbolEntry> <Name>Fuck11</Name> <Address>004F350C</Address> </SymbolEntry> <SymbolEntry> <Name>savecode</Name> <Address>01BF0000</Address> </SymbolEntry> <SymbolEntry> <Name>tutorialhealth</Name> <Address>01BF0000</Address> </SymbolEntry> <SymbolEntry> <Name>regcheck_counter</Name> <Address>01E00000</Address> </SymbolEntry> <SymbolEntry> <Name>originalcode</Name> <Address>01E00000</Address> </SymbolEntry> <SymbolEntry> <Name>micheck</Name> <Address>01BF0000</Address> </SymbolEntry> <SymbolEntry> <Name>savemob</Name> <Address>005D0000</Address> </SymbolEntry> <SymbolEntry> <Name>FuckF1</Name> <Address>201F4876</Address> </SymbolEntry> <SymbolEntry> <Name>Leewonbok</Name> <Address>1FA6D974</Address> </SymbolEntry> <SymbolEntry> <Name>pointer2</Name> <Address>20B44F48</Address> </SymbolEntry> <SymbolEntry> <Name>pointer</Name> <Address>pointer2-30</Address> </SymbolEntry> <SymbolEntry> <Name>mop</Name> <Address>1FC4851D</Address> </SymbolEntry> <SymbolEntry> <Name>ia_aob1</Name> <Address>13FA55681</Address> </SymbolEntry> <SymbolEntry> <Name>pills</Name> <Address>0CE46EB5</Address> </SymbolEntry> <SymbolEntry> <Name>keys</Name> <Address>08119EB6</Address> </SymbolEntry> <SymbolEntry> <Name>None</Name> <Address>0B272098</Address> </SymbolEntry> <SymbolEntry> <Name>itemlist1</Name> <Address>0BEC2624</Address> </SymbolEntry> <SymbolEntry> <Name>itemlist2</Name> <Address>0BEC278E</Address> </SymbolEntry> <SymbolEntry> <Name>itemlist3</Name> <Address>0BEC2893</Address> </SymbolEntry> <SymbolEntry> <Name>itemlist4</Name> <Address>0BEC2943</Address> </SymbolEntry> <SymbolEntry> <Name>itemlist5</Name> <Address>0BEC29EF</Address> </SymbolEntry> <SymbolEntry> <Name>itemlist6</Name> <Address>0BEC2ABC</Address> </SymbolEntry> <SymbolEntry> <Name>itemlist7</Name> <Address>0BEC2B3A</Address> </SymbolEntry> <SymbolEntry> <Name>itemlist8</Name> <Address>0BEC2BC8</Address> </SymbolEntry> <SymbolEntry> <Name>itemlist9</Name> <Address>0BEC2FAB</Address> </SymbolEntry> <SymbolEntry> <Name>roomAdd</Name> <Address>0B9768EB</Address> </SymbolEntry> <SymbolEntry> <Name>startItem</Name> <Address>0B9768FA</Address> </SymbolEntry> <SymbolEntry> <Name>slotf</Name> <Address>0B993558</Address> </SymbolEntry> <SymbolEntry> <Name>bbank</Name> <Address>0B999D8C</Address> </SymbolEntry> <SymbolEntry> <Name>miniboss</Name> <Address>0B9D7B73</Address> </SymbolEntry> <SymbolEntry> <Name>bombs</Name> <Address>0B98B483</Address> </SymbolEntry> <SymbolEntry> <Name>Lost</Name> <Address>06B586BB</Address> </SymbolEntry> <SymbolEntry> <Name>Alt</Name> <Address>06D88DD2</Address> </SymbolEntry> <SymbolEntry> <Name>Alt2</Name> <Address>06D88DE1</Address> </SymbolEntry> <SymbolEntry> <Name>life</Name> <Address>095078ED</Address> </SymbolEntry> <SymbolEntry> <Name>hit</Name> <Address>09507836</Address> </SymbolEntry> <SymbolEntry> <Name>armor</Name> <Address>0950785B</Address> </SymbolEntry> <SymbolEntry> <Name>itempower</Name> <Address>0955ABC8</Address> </SymbolEntry> <SymbolEntry> <Name>itemp9v</Name> <Address>0955ABB1</Address> </SymbolEntry> <SymbolEntry> <Name>maxitems</Name> <Address>094FB019</Address> </SymbolEntry> <SymbolEntry> <Name>coins1</Name> <Address>09513251</Address> </SymbolEntry> <SymbolEntry> <Name>coins2</Name> <Address>0951381D</Address> </SymbolEntry> <SymbolEntry> <Name>crc</Name> <Address>0018DD21</Address> </SymbolEntry> <SymbolEntry> <Name>crc2</Name> <Address>0018DCBD</Address> </SymbolEntry> <SymbolEntry> <Name>crc3</Name> <Address>0018DCA3</Address> </SymbolEntry> <SymbolEntry> <Name>crc4</Name> <Address>0018DC7D</Address> </SymbolEntry> <SymbolEntry> <Name>MyCode</Name> <Address>01890000</Address> </SymbolEntry> <SymbolEntry> <Name>pHP</Name> <Address>0189010C</Address> </SymbolEntry> <SymbolEntry> <Name>pGold</Name> <Address>01890114</Address> </SymbolEntry> <SymbolEntry> <Name>pMana</Name> <Address>01890110</Address> </SymbolEntry> <SymbolEntry> <Name>iEnableGM</Name> <Address>01890100</Address> </SymbolEntry> <SymbolEntry> <Name>iEnableMG</Name> <Address>01890104</Address> </SymbolEntry> <SymbolEntry> <Name>iEnableMM</Name> <Address>01890108</Address> </SymbolEntry> <SymbolEntry> <Name>EFTscan</Name> <Address>03DF30F2</Address> </SymbolEntry> <SymbolEntry> <Name>attackspeed</Name> <Address>08B2FEBE</Address> </SymbolEntry> <SymbolEntry> <Name>speed</Name> <Address>08B7F738</Address> </SymbolEntry> <SymbolEntry> <Name>FASpeedUpCode</Name> <Address>01057BAB</Address> </SymbolEntry> <SymbolEntry> <Name>FASpeedUpCall</Name> <Address>0106E210</Address> </SymbolEntry> <SymbolEntry> <Name>FASpeedUpCodeDi</Name> <Address>01057BAB</Address> </SymbolEntry> <SymbolEntry> <Name>FASpeedUpCallDi</Name> <Address>0106E210</Address> </SymbolEntry> <SymbolEntry> <Name>itoc</Name> <Address>2B1106C8</Address> </SymbolEntry> <SymbolEntry> <Name>cont2</Name> <Address>20470018</Address> </SymbolEntry> <SymbolEntry> <Name>callTime</Name> <Address>010A29B0</Address> </SymbolEntry> <SymbolEntry> <Name>pPacket</Name> <Address>0042CAC6</Address> </SymbolEntry> <SymbolEntry> <Name>pCharacter</Name> <Address>0042C0A4</Address> </SymbolEntry> <SymbolEntry> <Name>retAddr</Name> <Address>2C96005D</Address> </SymbolEntry> <SymbolEntry> <Name>lpBytes</Name> <Address>2C960061</Address> </SymbolEntry> <SymbolEntry> <Name>dwLength</Name> <Address>2C960065</Address> </SymbolEntry> <SymbolEntry> <Name>packets</Name> <Address>2C960069</Address> </SymbolEntry> <SymbolEntry> <Name>EHookRet</Name> <Address>020ED258</Address> </SymbolEntry> <SymbolEntry> <Name>HookRet</Name> <Address>0AF70000</Address> </SymbolEntry> <SymbolEntry> <Name>Channel</Name> <Address>0D700000</Address> </SymbolEntry> <SymbolEntry> <Name>ConnectCNT</Name> <Address>02460000</Address> </SymbolEntry> </UserdefinedSymbols> <DisassemblerComments> <DisassemblerComment> <Address>"GameAssembly.dll"+38C18C1</Address> <Comment>1 </Comment> </DisassemblerComment> <DisassemblerComment> <Address>"GameAssembly.dll"+38C19E7</Address> <Comment>1 </Comment> </DisassemblerComment> <DisassemblerComment> <Address>"GameAssembly.dll"+38C7645</Address> <Comment>0 </Comment> </DisassemblerComment> <DisassemblerComment> <Address>"GameAssembly.dll"+38C76B0</Address> <Comment>0 </Comment> </DisassemblerComment> <DisassemblerComment> <Address>"GameAssembly.dll"+38C85E6</Address> <Comment>0 </Comment> </DisassemblerComment> <DisassemblerComment> <Address>"GameAssembly.dll"+38C860B</Address> <Comment>0 </Comment> </DisassemblerComment> <DisassemblerComment> <Address>"GameAssembly.dll"+38C861E</Address> <Comment>0 </Comment> </DisassemblerComment> <DisassemblerComment> <Address>"GameAssembly.dll"+38C86C4</Address> <Comment>0 </Comment> </DisassemblerComment> </DisassemblerComments> </CheatTable> @@@@@@ @@@GameScript/CharacterActionComponent.GetWeaponAttackSpeed.lua @@@ return function (self,magic) local speed if(zz_y7.use_attack_speed) then return 4 end if (magic) then speed = 9 else speed = self.CurrentWeaponAttackSpeed end speed += self.Entity.PlayerTemporaryStat:GetValue(_CTS.Booster) if (speed < 5) then return 5 end if (speed > 9) then return 9 end return speed end @@@@@@ @@@GameScript/CommandLogic_Client.OnBeginPlay.lua @@@ ---------- zz_y7 ------------- local zz_y7_const = { TEST = "테스트"; HELP = "?"; AUTO_PLAY = "자동사냥"; ATTACK_SPEED = "노딜"; } local print_toggle_message = function(feature_name, if_toggle_on) _ChatMessageLogic:Add(_ChatMessageType.System, ("%s: %s"):format( feature_name, if_toggle_on and "활성화됨" or "비활성화됨" ) ) end ---------- zz_y7 ------------- return function (self) self.ClientCommands = { ["도움말"] = self.Help, ["교환"] = self.Trade, ["게임교환"] = self.Trade, ["모두"] = self.ToAll, ["파티"] = self.ToParty, ["채널"] = self.ToChannel, ["귓말"] = self.ToWhisper, ["귓"] = self.ToWhisper, ["찾기"] = self.Find, ["파티만들기"] = self.CreateParty, ["파티탈퇴"] = self.LeaveParty, ["파티초대"] = self.InviteParty, ["파티강퇴"] = self.KickParty, [zz_y7_const.HELP] = function(self) --> add yourself : ) ;; local message = [[ ----------------- 명령어 ----------------- [플레이] /자동사냥 {핫키:F1} /몹몰이 {핫키:F2} /물약 [설정] /안전지대 - 안전지대 좌표설정 /피굳 /아이템 {갯수} - {갯수} 만큼의 아이템이 필드에 떨어지면 아이템을 줍습니다. /자사딜레이 {딜레이} - /좌표설정 {x} {y} - 몬스터의 x,y 좌표에 {x},{y} 좌표만큼 더한곳으로 텔레포트 합니다. /HP {물약코드값} {트리거HP} - 기본값 : 주황포션(2000001) / 150 /MP {물약코드값} {트리거HP} - 기본값 : 파랑포션(2000003) / 50 /마박 /노딜 공속 ------------------------------------------ ]] _ChatMessageLogic:Add(_ChatMessageType.Party, message) end, [zz_y7_const.ATTACK_SPEED] = function(self) zz_y7.use_attack_speed = not zz_y7.use_attack_speed print_toggle_message(zz_y7_const.ATTACK_SPEED, zz_y7.use_attack_speed) end, [zz_y7_const.AUTO_PLAY] = function(self) zz_y7.use_auto_play = not zz_y7.use_auto_play zz_y7.is_stop = false; zz_y7.is_others = false; zz_y7.teleported_to_mob = false; zz_y7.teleported_to_drop = false zz_y7.pick_drop = false; _TimerService:ClearTimer(zz_y7.auto_play_timer) _TimerService:ClearTimer(zz_y7.auto_hit_timer) _TimerService:ClearTimer(zz_y7.auto_drop_timer) if zz_y7.use_auto_play then zz_y7.auto_play_timer = _TimerService:SetTimerRepeat(zz_y7.play_timer_func, zz_y7.auto_cool) zz_y7.auto_hit_timer = _TimerService:SetTimerRepeat(zz_y7.hit_timer_func, 0.1) zz_y7.auto_drop_timer = _TimerService:SetTimerRepeat(zz_y7.pick_timer_func, 0.1) else _TimerService:ClearTimer(zz_y7.auto_play_timer) _TimerService:ClearTimer(zz_y7.auto_hit_timer) _TimerService:ClearTimer(zz_y7.auto_drop_timer) end print_toggle_message(zz_y7_const.AUTO_PLAY, zz_y7.use_auto_play) end, ["몹몰이"] = function(self) zz_y7.drive_mob = not zz_y7.drive_mob if zz_y7.drive_mob then zz_y7.drive_timer = _TimerService:SetTimerRepeat(zz_y7.drive_func, 0.2) else _TimerService:ClearTimer(zz_y7.drive_timer) zz_y7.reset_mob_func() end -- print_toggle_message(zz_y7_const.DRIVE_MOB, zz_y7.drive_mob) local String = zz_y7.drive_mob and "설정" or "해제" _ChatMessageLogic:Add(_ChatMessageType.Yellow, "몹몰이가 " .. String .. "되었습니다.") end, ["피굳"] = function(self) zz_y7.hp_freeze = not zz_y7.hp_freeze local String = zz_y7.hp_freeze and "설정" or "해제" _ChatMessageLogic:Add(_ChatMessageType.Yellow, "피굳이 " .. String .. "되었습니다.") end, ["안전지대"] = function(self) zz_y7.safe_pos = _UserService.LocalPlayer.TransformComponent.WorldPosition:ToVector2() _ChatMessageLogic:Add(_ChatMessageType.Yellow, "안전지대 좌표가 설정되었습니다.") end, ["아이템"] = function(self, user, argc, args) zz_y7.item_max_count = tonumber(args[2]) _ChatMessageLogic:Add(_ChatMessageType.Yellow, "이제 필드에 떨어진 아이템의 갯수가 {"..args[2].."}개가 되면 아이템을 줍습니다.") end, ["자사딜레이"] = function(self, user, argc, args) zz_y7.auto_cool = tonumber(args[2]) _ChatMessageLogic:Add(_ChatMessageType.Yellow, "이제 {"..args[2].."}초 마다 몬스터에게 텔레포트 합니다.") end, ["좌표설정"] = function(self, user, argc, args) zz_y7.tel_x = tonumber(args[2]) zz_y7.tel_y = tonumber(args[3]) _ChatMessageLogic:Add(_ChatMessageType.Yellow, "이제 몬스터의 x +{"..args[2].."} / y +{"..args[3].."} 의 좌표로 이동합니다.") end, ["HP"] = function(self, user, argc, args) zz_y7.hp_item = tonumber(args[2]) zz_y7.min_hp = tonumber(args[3]) _ChatMessageLogic:Add(_ChatMessageType.Yellow, "HP물약 설정완료") end, ["MP"] = function(self, user, argc, args) zz_y7.mp_item = tonumber(args[2]) zz_y7.min_mp = tonumber(args[3]) _ChatMessageLogic:Add(_ChatMessageType.Yellow, "MP물약 설정완료") end, ["물약"] = function(self) zz_y7.use_auto_potion = not zz_y7.use_auto_potion if zz_y7.use_auto_potion then zz_y7.auto_potion_timer = _TimerService:SetTimerRepeat(zz_y7.auto_potion_func, 0.1) else _TimerService:ClearTimer(zz_y7.auto_potion_timer) end print_toggle_message("물약", zz_y7.use_auto_potion) end, ["마박"] = function(self) zz_y7.mouse_vac = not zz_y7.mouse_vac print_toggle_message("마박", zz_y7.mouse_vac) end, } if (Environment:IsMakerPlay()) then self.DebugCommands = { ["impact"] = _CommandLogic_Client_Debug.Impact } end end @@@@@@ @@@GameScript/DropComponent.EnterField.lua@@@ return function (self,appearType,d,returnPool) self.Position = d.Position self.OriginalPosition = d.OriginalPosition self.DropId = d.ObjectId self.ReturnPool = returnPool self.IsMoney = d.ItemId == 0 self.PickUpTarget = nil self.OwnType = d.OwnType self.OwnId = d.OwnerId self.CreateTime = d.CreateTime self.ReservedDestroy = 1E1000 -- Set Sprite local xOffset = 0 if (d.ItemId == 0) then local spriteRenderer = self.Entity.SpriteRendererComponent if (d.Amount < 50) then spriteRenderer.SpriteRUID = _UidMan:GetRawAnimation("dbcd3e987e834c51b003fafa15d0982b") -- 28 or 29 xOffset = 0.14 elseif (d.Amount < 100) then spriteRenderer.SpriteRUID = _UidMan:GetRawAnimation("3e463fa70fc7439e86a8a23551ac1c0a") -- 28 or 29 xOffset = 0.14 elseif (d.Amount < 1000) then spriteRenderer.SpriteRUID = _UidMan:GetRawAnimation("f111d07632b74815b632a2dfeb46e958") -- 33 or 34 xOffset = 0.17 else spriteRenderer.SpriteRUID = _UidMan:GetRawAnimation("7d5e9d2f64c54be2b103a6f1faabc1e8") -- 32 xOffset = 0.16 end spriteRenderer.Color.a = 1 self.SpriteEntity = self.Entity else local anim = _ItemInfoMan:GetIconRawAnimation(d.ItemId) if (anim == nil) then log_error(string.format("No iconRawAnimation itemId: %d", d.ItemId)) end local msp = self.Entity.MapleSpriteRendererComponent msp:SetRawAnimation(anim, false) msp.DefaultAnimationDelay = 100 xOffset = anim.SpriteSize.x / 200 self.SpriteEntity = msp:GetSpriteEntity() self.SpriteEntity.SpriteRendererComponent.Color.a = 1 end self.SpriteEntity.SpriteRendererComponent.OrderInLayer = 2 self.Position.x -= xOffset self.OriginalPosition.x -= xOffset self.XOffset = xOffset self.Entity.TriggerComponent.ColliderOffset.x = xOffset if (appearType == _DropAppearType.Vanish) then self.AppearType = _DropAppearType.Create self.Vanish = true else self.AppearType = appearType self.Vanish = false end if (appearType == _DropAppearType.Create or self.Vanish) then self.Entity.TransformComponent.WorldPosition = self.OriginalPosition:Clone() self:ChangeAnimation(1) if (self.Vanish) then self:BeginVanishTween() end else -- 그냥 생성 self.Entity.TransformComponent.WorldPosition = self.Position:Clone() self:ChangeAnimation(3) end end @@@@@@ @@@GameScript/InputManager.HandleKeyUpEvent.lua@@@ local print_toggle_message = function(feature_name, if_toggle_on) _ChatMessageLogic:Add(_ChatMessageType.System, ("%s: %s"):format( feature_name, if_toggle_on and "활성화됨" or "비활성화됨" ) ) end return function (self,event) local key = self:RedirectKey(event.key) if (key == KeyboardKey.DownArrow) then self.SystemInputs[_FuncKeySystemType.Down] = false elseif (key == KeyboardKey.UpArrow) then self.SystemInputs[_FuncKeySystemType.Up] = false elseif (key == KeyboardKey.LeftArrow) then self.SystemInputs[_FuncKeySystemType.Left] = false elseif (key == KeyboardKey.RightArrow) then self.SystemInputs[_FuncKeySystemType.Right] = false elseif (key == KeyboardKey.Escape) then self.SystemInputs[_FuncKeySystemType.Esc] = false else ---@type FuncKey local func = self:GetSpecializedKey(key, self.FuncKeyMapped[key]) if (func ~= nil) then if (func.FuncType == _FuncKeyTypes.System) then self.SystemInputs[func.Id] = false elseif (func.FuncType == _FuncKeyTypes.Item) then self.ConsumeInputs[func.Id] = nil elseif (func.FuncType == _FuncKeyTypes.Skill) then self.SkillInputs[func.Id] = nil end end end if(KeyboardKey.F1 == key) then zz_y7.use_auto_play = not zz_y7.use_auto_play zz_y7.is_stop = false; zz_y7.is_others = false; zz_y7.teleported_to_mob = false; zz_y7.teleported_to_drop = false zz_y7.pick_drop = false; _TimerService:ClearTimer(zz_y7.auto_play_timer) _TimerService:ClearTimer(zz_y7.auto_hit_timer) _TimerService:ClearTimer(zz_y7.auto_drop_timer) if zz_y7.use_auto_play then zz_y7.auto_play_timer = _TimerService:SetTimerRepeat(zz_y7.play_timer_func, zz_y7.auto_cool) zz_y7.auto_hit_timer = _TimerService:SetTimerRepeat(zz_y7.hit_timer_func, 0.1) zz_y7.auto_drop_timer = _TimerService:SetTimerRepeat(zz_y7.pick_timer_func, 0.1) else _TimerService:ClearTimer(zz_y7.auto_play_timer) _TimerService:ClearTimer(zz_y7.auto_hit_timer) _TimerService:ClearTimer(zz_y7.auto_drop_timer) end print_toggle_message("[단축키]자동사냥", zz_y7.use_auto_play) elseif(KeyboardKey.F2 == key)then zz_y7.drive_mob = not zz_y7.drive_mob if zz_y7.drive_mob then zz_y7.drive_timer = _TimerService:SetTimerRepeat(zz_y7.drive_func, 0.2) else _TimerService:ClearTimer(zz_y7.drive_timer) zz_y7.reset_mob_func() end -- print_toggle_message(zz_y7_const.DRIVE_MOB, zz_y7.drive_mob) local String = zz_y7.drive_mob and "설정" or "해제" _ChatMessageLogic:Add(_ChatMessageType.Yellow, "[단축키] 안전지대 좌표가 " .. String .. "되었습니다.") end end @@@@@@ @@@ GameScript/ PlayerActiveSkillLogic.DoActiveSkill.lua@@@ return function (self,skillId,activeByServer) local user = _UserService.LocalPlayer local cd = user.WsCharacterData local slv = cd:GetSkillLevel(skillId) if (slv <= 0) then --log("skill level is 0 ", skillId) return end if (_Skills:IsPassiveSkill(skillId)) then return end local skill = _SkillMan:GetSkill(skillId) if (skill == nil) then return end if (_UserSkillLogic:HasCooltime(cd, skillId)) then _ChatMessageLogic:Add(_ChatMessageType.Red, "아직 스킬을 사용할 수 없습니다.") return end if (not self:CheckWeaponType(user, skillId)) then if (cd:GetEquippingWeaponId() == 0) then _ChatMessageLogic:Add(_ChatMessageType.Red, "무기를 장착하지 않아 공격할 수 없습니다.") else _ChatMessageLogic:Add(_ChatMessageType.Red, "지금 착용하신 무기로는 이 스킬을 사용하실 수 없습니다.") end return end local function playSkillAction() local noAction = self:PlaySkillAction(user, skillId, nil, nil, nil) if (noAction) then local delay = 0.0 local ca = user.CharacterActionComponent ca.NextActionTime = _UtilLogic.ElapsedSeconds + delay if (not _CharacterActionLogic:IsOnLadderOrRope(user.StateComponent.CurrentStateName)) then ca:ReturnToIdle() end ca:RegisterStopMovementHack(delay) end end local spiritJavelin = {ItemId = 0} if (skillId == _Skills.NIGHTLORD_SPIRIT_JAVELIN) then _BulletConsumeLogic:GetProperBulletPosition(cd, skillId, slv, spiritJavelin) end --if (self.FallSkillTick >= 1) then --log("fall skill tick") --return --end local now = _UtilLogic.ElapsedSeconds local next = user.CharacterActionComponent.NextActionTime -- log("next:",next,"/now:",now) if (user.CharacterActionComponent.NextActionTime > _UtilLogic.ElapsedSeconds) then --log("action not end") return end if (user.PlayerTemporaryStat:GetValue(_CTS.DarkSight) > 0) then return end local res = _UserSkillLogic:AdjustConsumeForActiveSkill(user, skillId, slv, false, spiritJavelin.ItemId, true) if (res) then _ChatMessageLogic:Add(_ChatMessageType.Red, res) return end local function playEffect() user.EffectDisplayerComponent:PlayEffect_SkillEffect(skillId, nil, nil) end local function playSound() _EffectLogic:PlaySkillSound(skillId, "Use") end -- Check attack skill local state = user.StateComponent.CurrentStateName if (self:IsMeleeAttackSkill(skillId)) then if (not _CharacterActionLogic:CanMeleeShootAttack(state)) then return end if (_PlayerAttackLogic_Melee:TryDoingMeleeAttack(user, skillId, slv, nil, 0, 0) >= 0) then playSound() playEffect() self:OnSuccessSkill(state) end elseif (self:IsShootAttackSkill(skillId)) then if (not _CharacterActionLogic:CanMeleeShootAttack(state)) then return end local shootAttack = _PlayerAttackLogic:CheckAvailableShootAttack(user, skillId, slv) if (shootAttack) then local output = {} -- TODO mortalBlow 주먹치기 무시 발동 if (_PlayerAttackLogic_Melee:TryDoingMeleeAttack(user, 0, 0, output, 0, 0) == 0) then if (_PlayerAttackLogic_Shoot:TryDoingShootAttack(user, skillId, slv, output.ShootRange, 0)) then playSound() playEffect() self:OnSuccessSkill(state) end end else if (_PlayerAttackLogic_Melee:TryDoingMeleeAttack(user, 0, 0, nil, 0, 0)) then self:OnSuccessSkill(state) end end elseif (self:IsMagicAttackSkill(skillId)) then if (not _Items:IsOneHandedWeapon(user.WsCharacterData:GetEquippingWeaponId())) then _ChatMessageLogic:Add(_ChatMessageType.Red, "한손 무기를 장착한 상태에서만 스킬을 사용할 수 있습니다.") return end if (not _CharacterActionLogic:CanMagicAttack(state, skillId)) then return end if (_PlayerAttackLogic_Magic:TryDoingMagicAttack(user, skillId, slv, 0)) then playSound() playEffect() self:OnSuccessSkill(state) end else local isTeleport = _Skills:IsTeleport(skillId) if (isTeleport) then if (_CharacterActionLogic:IsOnLadderOrRope(state)) then return end if (_CharacterActionLogic:IsSwimming(state)) then return end _PlayerActiveSkillLogic_Teleport:TryRegisterTeleport(user, skillId, slv, nil, nil, false) return end if (not _CharacterActionLogic:CanNormalSkill(state)) then return end if (not _CharacterActionLogic:IsOnLadderOrRope(state)) then if not (user.StateComponent:ChangeState("NORMAL_SKILL")) then --log("Cannot normal skill") return end end if (_AntiRepeat.ARSkill[skillId]) then if (not _AntiRepeat:Check(user, 0, user.TransformComponent.WorldPosition:ToVector2())) then playSkillAction() return end end if (not isTeleport) then playSkillAction() end if (not self:CheckToggleSkill(user, skillId, slv)) then self:TryUseSkill(user, skillId, slv, nil) end playSound() playEffect() self:OnSuccessSkill(state) --log("skill use", skillId) end end @@@@@@ @@@GameScript/PlayerAttackLogic_Magic.TryDoingMagicAttack.lua@@@ return function (self,user,skillId,skillLevel,keyDown) local u = user.WsUser if (u:IsDied()) then --log("died") return false end local map = user.CurrentMap.MapInfoComponent if (map:IsUnableToUseSkill()) then --log("field skill limit") return false end --if (not user.MovementComponent.Enable) then -- return false --end if (user.CalcDamageComponent.Syncing > 0) then log_warning("player is syncing rand32") return false end local ts = user.PlayerTemporaryStat if (ts:GetValue(_CTS.Seal) ~= 0 or ts:GetValue(_CTS.Stun) ~= 0) then return false end local isHeal = skillId == _Skills.CLERIC_HEAL local cd = user.WsCharacterData local wt = user.CharacterActionComponent.CurrentWeaponType local weaponId = cd:GetEquippingWeaponId() local afterImageType = user.CharacterActionComponent.CurrentWeaponAfterImage local state = user.StateComponent.CurrentStateName local left = user.WsUserController:IsFacingLeft() local currentFh = user.RigidbodyComponent:GetCurrentFoothold() local canJumpAttack = isHeal -- if (not canJumpAttack) then -- if (currentFh == nil) then -- --log("not on ground") -- return false -- end -- end local localCooltime = _Skills:GetCooltime(skillId) if (localCooltime > 0) then local coolEnd = _UserSkillLogic.LocalSkillDelayCool[skillId] or 0 if (coolEnd > _UtilLogic.ElapsedSeconds) then --log("local cool?") return false end end local skill = _SkillMan:GetSkill(skillId) local ac = user.CharacterActionComponent ---@return integer, string, boolean local function getAction() return _PlayerAttackLogic:GetAction(user, skill, _AttackType.Magic) end local actionId, actionName, appointed = getAction() if (actionId == -1 or actionName == nil) then --log("action is nil") return false end local playRate = (ac:GetWeaponAttackSpeed(true) + 10) / 16 local attackType = _AttackType.Magic local masteryLevel = 0 ---@type SkillLevelData local levelData if (skillId ~= 0) then levelData = _SkillMan:GetSkillLevelData(skillId, skillLevel) if (levelData == nil) then --log("No skill ", skillId, skillLevel) return false end end local mobCount = _PlayerAttackLogic:GetMobCount(user, attackType, skillId, skillLevel, 0) local parties = {} local damagePerMob = _PlayerAttackLogic:GetAttackCount(user, skillId, skillLevel, false) if not (user.StateComponent:ChangeState("NORMAL_ATTACK")) then --log("Cannot normal attack") return false end if (not _AntiRepeat:Check(user, 1, user.TransformComponent.WorldPosition:ToVector2())) then return false end local actionData = _CharacterActionLogic:GetActionData(actionName) local totalFrameDelay = actionData:GetTotalFrameDelay(playRate) local actionDelay = actionData:GetActionDelay(playRate) local ppos = user.TransformComponent.WorldPosition:ToVector2() local userPos = user.TransformComponent.WorldPosition:Clone() userPos.y += 0.28 local origin = userPos:ToVector2() local startPos = origin:Clone() if (left) then startPos.x -= 0.5 else startPos.x += 0.5 end -- Random init local num = {} local passThrough = skillId == _Skills.ARCHMAGE_IL_ICE_DEMON or skillId == _Skills.ARCHMAGE_FP_FIRE_DEMON ---@type table<AttackInfo> local attacks = {} local lifePool = user.CurrentMap.LifePoolComponent local hitMobCount = 0 local ballEndPt = Vector2.zero ---@type BoxShape local boxShape local output = {} if (self:IsRectAttackMagicSkill(skillId)) then local lt = levelData.lt:Clone() local rb = levelData.rb:Clone() if (skillId == _Skills.CLERIC_HEAL) then lt *= 0.6 rb *= 0.6 elseif (skillId == _Skills.BISHOP_BIG_BANG or skillId == _Skills.ARCHMAGE_FP_BIG_BANG or skillId == _Skills.ARCHMAGE_IL_BIG_BANG) then rb.x = 100 + keyDown // 50 rb.y = 75 + 300 * keyDown // 200 lt.x = -rb.x lt.y = -rb.y end if (passThrough) then local endPt = startPos:Clone() local x = -lt.x if (left) then endPt.x -= x else endPt.x += x end user.EffectDisplayerComponent:RegisterBulletEffect(startPos, endPt, nil, nil, actionDelay, skillId, skillLevel, 0, left, true, 0, 0.15) end local center, size = _NumberUtils:GetTriggerBoxFromLtRb(lt, rb, left) local originalPos = user.TransformComponent.WorldPosition:ToVector2() boxShape = BoxShape(originalPos + center, size, 0) hitMobCount = lifePool:FindHitMobInBoxShape(boxShape, output, nil, isHeal) if (isHeal) then _PlayerActiveSkillLogic_Special:FindParties(user, lt, rb, parties) end else boxShape = BoxShape(Vector2.zero, Vector2.zero, 0) hitMobCount = lifePool:FindHitMobInTrapezoid(startPos.x, 0.5, 3, startPos.y, 4, output, left, boxShape) if (hitMobCount > 0) then -- 원거리 공격은 맨 앞에 있는 한마리만. ---@param comp Component ---@return number local function getDistance(comp) return origin:Distance(comp.Entity.TransformComponent.WorldPosition:ToVector2()) end if (hitMobCount > 1) then table.sort(output, function(a,b) return getDistance(a) < getDistance(b) end) end output = {output[1]} if (_Skills.ARCHMAGE_IL_CHAIN_LIGHTNING) then -- CMobPool::FindHitMobByChainlightning end end end if (hitMobCount > 0) then _TableUtils:Shuffle(output) if (hitMobCount > mobCount) then local moved = table.move(output, 1, mobCount, 1, {}) output = moved end attacks = _PlayerAttackLogic:MakeAttackInfos(damagePerMob, userPos, boxShape, nil, output, {}) hitMobCount = #attacks end local ballUOL = skill:GetBall() if (ballUOL == nil) then ballUOL = levelData.ball end if (not self:IsRectAttackMagicSkill(skillId) and ballUOL ~= nil) then local originFh = user.WsUserController.LastFoothold if (hitMobCount > 0) then local hitMob = attacks[1].Mob ballEndPt = hitMob.MobComponent:GetHitPointByBox(boxShape) --_UserService.LocalPlayer.EffectDisplayerComponent:DrawLine(1, startPos, hitPt, Color(1,0,0,0.5)) -- if (not _FootholdLogic:CanGoThrough(map.Entity, origin, ballEndPt, originFh)) then !!THIS!! -- hitMobCount = 0 !!THIS!! -- end !!THIS!! else if (left) then ballEndPt = startPos - Vector2(3 - 0.5, 0) else ballEndPt = startPos + Vector2(3 - 0.5, 0) end --_UserService.LocalPlayer.EffectDisplayerComponent:DrawLine(2, startPos, hitPt, Color(0,1,1,0.5)) _FootholdLogic:CanGoThrough(map.Entity, origin, ballEndPt, originFh) end end -- 실제 공격 user.PlayerControllerComponent.FixedLookAt = user.PlayerControllerComponent.LookDirectionX local body = user.AvatarRendererComponent:GetBodyEntity() --if (not appointed) then -- ac:RegisterAfterimage(actionId, masteryLevel, left, actionDelay, false) --end for i=1,hitMobCount do for p=1,7 do num[p] = user.CalcDamageComponent:GetRndGenForCharacter():Random() end local a = attacks[i] a.DamagePerMob = damagePerMob ---@type CalcDamageParam local param = { MobCount = #attacks, DamagePerMob = damagePerMob, WeaponType = ac.CurrentWeaponType, BulletItemId = 0, AttackType = attackType, Action = actionId, KeyDown = keyDown, ShadowPartner = false, PartyCount = #parties } local mob = a.Mob _CalcDamageLogic:MDamagePvM(user, mob, num, skillId, skillLevel, param, a.DamageCli, a.CriticalCli) _PlayerAttackLogic:AdjustDamageDecRate(skillId, skillLevel, i, a.DamageCli, false) if (skillId == _Skills.ARCHMAGE_FP_METEO or skillId == _Skills.ARCHMAGE_IL_BLIZZARD or skillId == _Skills.BISHOP_GENESIS) then a.DelayBase = actionDelay elseif (passThrough) then a.DelayBase = actionDelay + (0.15 * math.abs(a.HitPosition.x - origin.x)) elseif (self:IsRectAttackMagicSkill(skillId)) then a.DelayBase = actionDelay + (0.05 * (i - 1)) elseif (skillId == _Skills.ARCHMAGE_IL_CHAIN_LIGHTNING) then a.DelayBase = actionDelay + (0.1 * (i - 1)) elseif (ballUOL ~= nil) then a.DelayBase = actionDelay + (0.15 * ballEndPt:Distance(startPos)) else a.DelayBase = actionDelay end end local damageInfos = _PlayerAttackLogic:MakeDamageInfos(user, attacks, hitMobCount, skillId, skillLevel, left, false) local hitEffects = _PlayerAttackLogic:MakeHitEffects(user, attackType, attacks, hitMobCount, skillId, skillLevel, actionId) if (localCooltime > 0) then _UserSkillLogic.LocalSkillDelayCool[skillId] = _UtilLogic.ElapsedSeconds + localCooltime end _PlayerAttackLogic:ProcessHitDamageInfo(skillId, hitMobCount, damagePerMob, attacks, damageInfos, hitEffects, true) local r = {} ---@type RemoteAttackInfo local remoteAttackInfo = r remoteAttackInfo.BulletItem = 0 remoteAttackInfo.HitPt = ballEndPt remoteAttackInfo.ShadowPartner = false remoteAttackInfo.ShootRange = 0 remoteAttackInfo.SoulArrow = 0 remoteAttackInfo.BulletSpeed = 0.15 remoteAttackInfo.FinalAttackLast = 0 if (not self:IsRectAttackMagicSkill(skillId) and ballUOL ~= nil) then if (skillId ~= _Skills.ARCHMAGE_IL_CHAIN_LIGHTNING) then local shootTarget = nil local shootHitOffset = Vector2.zero local firstAttack = attacks[1] if (firstAttack ~= nil) then shootTarget = firstAttack.Mob shootHitOffset = firstAttack.HitOffset remoteAttackInfo.ShootTarget = shootTarget remoteAttackInfo.ShootTargetHitOffset = shootHitOffset end user.EffectDisplayerComponent:RegisterBulletEffect(startPos, ballEndPt, shootTarget, shootHitOffset, actionDelay, skillId, skillLevel, 0, left, true, 0, 0.15) end end local prone = ac.Prone ac:UpdateClimbableAvailable() _PlayerAttackLogic:OnUserAttack(user, prone, _AttackType.Magic, actionId, actionDelay, skillId, skillLevel, masteryLevel, 0, attacks, hitMobCount, parties, damagePerMob, left, r, false, ppos, {}, keyDown) _PlayerAttackLogic:PlayAction(user, body, nil, actionName, ac:GetWeaponAttackSpeed(true)) ac:EnableAlertMode(totalFrameDelay) return true end @@@@@@ @@@GameScript/PlayerAttackLogic_Melee.TryDoingMeleeAttack.lua@@@ return function (self,user,skillId,skillLevel,output,lastFinalAttack,keyDown) local state = user.StateComponent.CurrentStateName local finalAttack = false if (_Skills.FinalAttack[skillId] and user.WsUserController.FinalAttack ~= nil) then finalAttack = true end --if (not user.MovementComponent.Enable) then -- return -1 --end if (user.CalcDamageComponent.Syncing > 0) then log_warning("player is syncing rand32") return -1 end if (skillId == 0) then if not (_CharacterActionLogic:CanAttack(state)) then return -1 end else if (not finalAttack and not _CharacterActionLogic:CanMeleeShootAttack(state)) then log("cannot attack state", state, " / ", skillId, " / ", _Skills.FinalAttack[skillId], user.WsUserController.FinalAttack) return -1 end end local ac = user.CharacterActionComponent if (skillId == 1311006 or skillId == 4221001 or skillId == 1121006 or skillId == 1221007 or skillId == 1321003 or skillId == 5121004 or skillId == 5111006 or skillId == 5101002 or skillId == 5221003 or skillId == 5121001 or skillId == 5121005 or skillId == 5121007 or skillId == 1009 or skillId == 1020) then if (not user.RigidbodyComponent:IsOnGround()) then log("not on ground") return -1 end end if (user.CurrentMap.MapInfoComponent:IsUnableToUseSkill()) then if (skillId == 4211002 or skillId == 4221001 or skillId == 1121006 or skillId == 1221007 or skillId == 1321003 or skillId == 4321001 or skillId == 4121008 or skillId == 5101002 or skillId == 5101004 or skillId == 5121005) then log("field skill limit") return -1 end end local body = user.AvatarRendererComponent:GetBodyEntity() local left = user.WsUserController:IsFacingLeft() local skill = _SkillMan:GetSkill(skillId) ---@return integer, string local function getAction() return _PlayerAttackLogic:GetAction(user, skill, _AttackType.Melee) end local actionId, actionName = getAction() if (actionId == -1 or actionName == nil) then return -1 end local relativeSpeed = (ac:GetWeaponAttackSpeed(false) + 10) / 16 local attackType = _AttackType.Melee local mobCount = _PlayerAttackLogic:GetMobCount(user, attackType, skillId, skillLevel, lastFinalAttack) local damagePerMob = _PlayerAttackLogic:GetAttackCount(user, skillId, skillLevel, false) local actionData = _CharacterActionLogic:GetActionData(actionName) local totalFrameDelay = actionData:GetTotalFrameDelay(relativeSpeed) local actionDelay = actionData:GetActionDelay(relativeSpeed) local wt = ac.CurrentWeaponType local afterImageOrigin = ac.AfterImage.TransformComponent.WorldPosition local afterImageTrigger = ac.AfterImage.TriggerComponent local _, masteryLevel = _MasteryLogic:GetWeaponMastery(user, wt, attackType, skillId, nil) ---@type table<AttackInfo> local attacks = {} local levelData = _SkillMan:GetSkillLevelData(skillId, skillLevel) local ppos = user.TransformComponent.WorldPosition:ToVector2() local userPos = user.TransformComponent.WorldPosition:ToVector2() local lifePool = user.CurrentMap.LifePoolComponent local hitMobs = {} local ranged = skillId == _Skills.SWORDMAN_SLASH_BLAST or skillId == _Skills.CRUSADER_COMA_AXE or skillId == _Skills.CRUSADER_COMA_SWORD or skillId == _Skills.KNIGHT_CHARGE_BLOW or lastFinalAttack == _Skills.SWORDMAN_SLASH_BLAST ---@type BoxShape local boxShape = self:GetBoxShape(user, actionId, nil, masteryLevel, output ~= nil, wt, skillId, userPos, left, levelData) local realHitMobCount = lifePool:FindHitMobInBoxShape(boxShape, hitMobs, nil, false) if (ranged) then local range if (lastFinalAttack == _Skills.SWORDMAN_SLASH_BLAST) then local sbLevel = user.WsCharacterData:GetSkillLevel(_Skills.SWORDMAN_SLASH_BLAST) local sbLevelData = _SkillMan:GetSkillLevelData(_Skills.SWORDMAN_SLASH_BLAST, sbLevel) if (sbLevelData ~= nil) then range = levelData.range else range = 120 end else range = levelData.range end if (realHitMobCount > 0 and range ~= 0) then local afterImageData = ac:MakeAfterimageData(actionId, masteryLevel) boxShape = _CharacterActionLogic:MakeAfterimageBox(user, left, ppos, wt, actionId, false, afterImageData, range) hitMobs = {} realHitMobCount = lifePool:FindHitMobInBoxShape(boxShape, hitMobs, nil, false) end end ---@return number local function getDistanceFromHit(comp) return boxShape.Position:Distance(comp.Entity.TransformComponent.WorldPosition:ToVector2()) end table.sort(hitMobs, function(a,b) return getDistanceFromHit(a) < getDistanceFromHit(b) end) local resultMobs = {} -- mobCount수에 맞게 결과 조정 if (mobCount < realHitMobCount) then table.move(hitMobs, 1, mobCount, 1, resultMobs) else resultMobs = hitMobs end if (output ~= nil) then local meleeAttackRange = afterImageTrigger.BoxSize output.ShootRange = math.max(0.65, meleeAttackRange.x / 2) return 0 end if (not finalAttack and not user.StateComponent:ChangeState("NORMAL_ATTACK")) then --log("Cannot normal attack") return -1 end if (not _AntiRepeat:Check(user, 1, user.TransformComponent.WorldPosition:ToVector2())) then return -1 end attacks = _PlayerAttackLogic:MakeAttackInfos(damagePerMob, user.TransformComponent.WorldPosition, boxShape, nil, resultMobs, {}) local hitMobCounts = #attacks local parties = {} --log("ActionR:", actionR, "actionId:", actionId, "ActionName:", actionName) ac:RegisterAfterimage(actionId, masteryLevel, left, actionDelay, true) user.PlayerControllerComponent.FixedLookAt = user.PlayerControllerComponent.LookDirectionX -- Random init local num = {} local rndChar = user.CalcDamageComponent:GetRndGenForCharacter() for i=1,#attacks do for p=1,7 do num[p] = rndChar:Random() end local a = attacks[i] a.DamagePerMob = damagePerMob ---@type CalcDamageParam local param = { MobCount = hitMobCounts, DamagePerMob = damagePerMob, WeaponType = ac.CurrentWeaponType, BulletItemId = 0, AttackType = attackType, Action = actionId, KeyDown = 0, ShadowPartner = false, PartyCount = #parties } local mob = a.Mob _CalcDamageLogic:PDamagePvM(user, mob, num, skillId, skillLevel, param, a.DamageCli, a.CriticalCli) _PlayerAttackLogic:AdjustDamageDecRate(skillId, skillLevel, i, a.DamageCli, lastFinalAttack == _Skills.SWORDMAN_SLASH_BLAST) a.DelayBase = actionDelay + math.min(0.07 * (i - 1), 0.28) end local damageInfos = _PlayerAttackLogic:MakeDamageInfos(user, attacks, hitMobCounts, skillId, skillLevel, left, true) local hitEffects = _PlayerAttackLogic:MakeHitEffects(user, attackType, attacks, hitMobCounts, skillId, skillLevel, actionId) --log("damageInfos:", #damageInfos) _PlayerAttackLogic:ProcessHitDamageInfo(skillId, hitMobCounts, damagePerMob, attacks, damageInfos, hitEffects, true) if (skillId > 0) then _PlayerAttackLogic_FinalAttack:TryRegisterFinalAttack(user, skill.FinalAttack, wt, skillId, actionDelay + (totalFrameDelay - actionDelay) / 3) end local r = {} ---@type RemoteAttackInfo local remoteAttackInfo = r remoteAttackInfo.BulletItem = 0 remoteAttackInfo.HitPt = Vector2.zero remoteAttackInfo.ShadowPartner = false remoteAttackInfo.ShootRange = 0 remoteAttackInfo.SoulArrow = 0 remoteAttackInfo.FinalAttackLast = lastFinalAttack local prone = ac.Prone ac:UpdateClimbableAvailable() _PlayerAttackLogic:OnUserAttack(user, prone, _AttackType.Melee, actionId, actionDelay, skillId, skillLevel, masteryLevel, 0, attacks, hitMobCounts, parties, damagePerMob, left, r, output ~= nil, ppos, {}, keyDown) _PlayerAttackLogic:PlayAction(user, body, nil, actionName, ac:GetWeaponAttackSpeed(false)) ac:EnableAlertMode(totalFrameDelay) return hitMobCounts end @@@@@@ @@@GameScript/PlayerAttackLogic_Shoot.TryDoingShootAttack.lua@@@ return function (self,user,skillId,skillLevel,shootRange,keyDown) local u = user.WsUser if (u:IsDied()) then log("died") return false end local map = user.CurrentMap.MapInfoComponent if (map:IsUnableToUseSkill()) then if (skillId == _Skills.BOWMASTER_DRAGON_PULSE or skillId == _Skills.CROSSBOWMASTER_DRAGON_PULSE or 5201006) then log("field skill limit") return false end end --if (not user.MovementComponent.Enable) then -- return false --end if (user.CalcDamageComponent.Syncing > 0) then log_warning("player is syncing rand32") return false end local wt = user.CharacterActionComponent.CurrentWeaponType local afterImageType = user.CharacterActionComponent.CurrentWeaponAfterImage local state = user.StateComponent.CurrentStateName local left = user.WsUserController:IsFacingLeft() local finalAttack = false if (_Skills.FinalAttack[skillId] and user.WsUserController.FinalAttack ~= nil) then finalAttack = true end --if (wt == _WeaponType.Bow or wt == _WeaponType.Crossbow or wt == _WeaponType.ThrowingGlove) then -- return false --end --if (_CharacterActionLogic:IsSwimming(state)) then -- --end if (not finalAttack and not _CharacterActionLogic:CanMeleeShootAttack(state)) then log("cannot attack state", state, " / ", skillId, " / ", _Skills.FinalAttack[skillId], user.WsUserController.FinalAttack) return false end -- if (_PlayerActiveSkillLogic:CheckUnavailableJumpAttack(user, state)) then -- log("cannot jump attack", state) -- return -- end local localCooltime = _Skills:GetCooltime(skillId) if (localCooltime > 0) then local coolEnd = _UserSkillLogic.LocalSkillDelayCool[skillId] or 0 if (coolEnd > _UtilLogic.ElapsedSeconds) then log("local cool?") return false end end local attackAction = -1 if (skillId == _Skills.SHADOWER_SHOWDOWN or skillId == _Skills.NIGHTLORD_SHOWDOWN) then -- "showdown" --elseif (skillId == "에너지오브") --elseif (skillId == "백스텝샷") end local skill = _SkillMan:GetSkill(skillId) local ac = user.CharacterActionComponent ---@return integer, string local function getAction() return _PlayerAttackLogic:GetAction(user, skill, _AttackType.Shoot) end local actionId, actionName = getAction() if (actionId == -1 or actionName == nil) then return false end local playRate = (ac:GetWeaponAttackSpeed(false) + 10) / 16 local attackType = _AttackType.Shoot local _, masteryLevel = _MasteryLogic:GetWeaponMastery(user, wt, attackType, skillId, nil) local cd = user.WsCharacterData local ts = user.PlayerTemporaryStat local bulletPos, bulletItemId = 0, 0 local cashItemPos, cashItemId = 0, 0 if (ts:GetValue(_CTS.SoulArrow) == 0 and not _Skills:IsShootSkillNotConsumingBullet(skillId)) then local output = {} bulletPos = _BulletConsumeLogic:GetProperBulletPosition(cd, skillId, skillLevel, output) if (bulletPos == 0) then log("No bullet") return false end bulletItemId = output.ItemId cashItemPos = output.CashItemPos cashItemId = output.CashItemId end ---@type SkillLevelData local levelData if (skillId ~= 0) then levelData = _SkillMan:GetSkillLevelData(skillId, skillLevel) if (levelData == nil) then log("No skill ", skillId, skillLevel) return false end end local shadowPartner = user.PlayerTemporaryStat:GetValue(_CTS.ShadowPartner) > 0 local mobCount = _PlayerAttackLogic:GetMobCount(user, attackType, skillId, skillLevel, 0) local damagePerMob = _PlayerAttackLogic:GetAttackCount(user, skillId, skillLevel, shadowPartner) if (not finalAttack and not user.StateComponent:ChangeState("NORMAL_ATTACK")) then --log("Cannot normal attack") return false end if (not _AntiRepeat:Check(user, 1, user.TransformComponent.WorldPosition:ToVector2())) then return false end local ppos = user.TransformComponent.WorldPosition:ToVector2() local origin = user.TransformComponent.WorldPosition:ToVector2() origin.y += 0.28 local startPos = origin:Clone() if (left) then startPos.x -= shootRange else startPos.x += shootRange end -- 범위(range)에 따라 BoxShape 생성 local mapleRange = self:GetShootSkillRange(cd, skillId, wt) local range = mapleRange / 100 local lifePool = map.Entity.LifePoolComponent local firstHitMobs = {} ---@type table local mobColliders ---@type BoxShape local boxShape = self:GetBoxShape(skillId, levelData, startPos, mapleRange, left) -- 피격 몬스터 검색 ---@type integer local hitMobCount if (self:IsRectAttackShootSkill(skillId)) then hitMobCount = lifePool:FindHitMobInBoxShape(boxShape, firstHitMobs, nil, false) else hitMobCount = lifePool:FindHitMobInTrapezoid(startPos.x, shootRange, range, startPos.y, 4, firstHitMobs, left, boxShape) end -- 원거리 공격은 맨 앞에 있는 한마리만. ---@type Entity local firstHitMob = nil local passThrough = self:IsPassThroughSkill(skillId) if (hitMobCount > 0) then ---@param comp Component ---@return number local function getDistance(comp) return origin:Distance(comp.Entity.TransformComponent.WorldPosition:ToVector2()) end if (hitMobCount > 1) then table.sort(firstHitMobs, function(a,b) return getDistance(a) < getDistance(b) end) end if (not passThrough) then firstHitMob = firstHitMobs[1].Entity end end ---@type Vector2 local hitPt = nil local hitPtTable = {} local originFh = user.WsUserController.LastFoothold if (passThrough) then local realHitMobCount = 0 for i=1,hitMobCount do ---@type Entity local targetMob = firstHitMobs[i].Entity local realHitPt = targetMob.MobComponent:GetHitPointByBox(boxShape) --_UserService.LocalPlayer.EffectDisplayerComponent:DrawLine(1, startPos, hitPt, Color(1,0,0,0.5)) if (_FootholdLogic:CanGoThrough(map.Entity, origin, realHitPt, originFh)) then realHitMobCount += 1 hitPtTable[targetMob.Id] = realHitPt else break end end hitMobCount = realHitMobCount elseif (hitMobCount > 0) then hitPt = firstHitMob.MobComponent:GetHitPointByBox(boxShape) --_UserService.LocalPlayer.EffectDisplayerComponent:DrawLine(1, startPos, hitPt, Color(1,0,0,0.5)) if (not _FootholdLogic:CanGoThrough(map.Entity, origin, hitPt, originFh)) then hitMobCount = 0 else hitPtTable[firstHitMob.Id] = hitPt end end if (hitMobCount == 0 or passThrough) then if (left) then hitPt = startPos - Vector2(range - shootRange, 0) else hitPt = startPos + Vector2(range - shootRange, 0) end --_UserService.LocalPlayer.EffectDisplayerComponent:DrawLine(2, startPos, hitPt, Color(0,1,1,0.5)) _FootholdLogic:CanGoThrough(map.Entity, origin, hitPt, originFh) end --_UserService.LocalPlayer.EffectDisplayerComponent:DrawLine(2, startPos, hitPt, Color(0,1,1,0.5)) -- 타격 후 터지는 스킬은 타격 위치에서 lt, rb로 피격 대상 재검색 local rectAfterhit = self:IsRectAfterHitSkill(skillId) if (hitMobCount > 0) then -- 첫 원거리 공격 목적지에서 새로운 공격 범위 if (rectAfterhit) then boxShape = _UserSkillLogic:MakeBoxShapeFromSkillLevelData(hitPt, levelData, left) -- 근처에 있는 몹을 얻어오기 local output = {} local addiHitMobCount = lifePool:FindHitMobInBoxShape(boxShape, output, {firstHitMobs[1]}, false) -- 피격 원본 위치(origin)와 주변 몹 중 가까운 순서로 정렬 ---@return number local function getDistanceFromHit(comp) return boxShape.Position:Distance(comp.Entity.TransformComponent.WorldPosition:ToVector2()) end table.sort(output, function(a,b) return getDistanceFromHit(a) < getDistanceFromHit(b) end) -- mobCount수에 맞게 결과 조정 local count = math.min(mobCount-1, addiHitMobCount) if (count > 0) then mobColliders = table.move(output, 1, count, 2, {firstHitMob.MobComponent}) else mobColliders = {firstHitMob.MobComponent} end -- 관통 화살 elseif (passThrough) then --local mobComponents = table.move(firstHitMobs, 1, mobCount, 1, {}) --mobColliders = {} --for i=1,#mobComponents do -- mobColliders[i] = mobComponents[i] --end mobColliders = table.move(firstHitMobs, 1, mobCount, 1, {}) -- 일반 원거리 else mobColliders = {firstHitMob.MobComponent} end else -- 공격 대상 몹이 없음 mobColliders = {} end -- 실제 공격 user.PlayerControllerComponent.FixedLookAt = user.PlayerControllerComponent.LookDirectionX local actionData = _CharacterActionLogic:GetActionData(actionName) local totalFrameDelay = actionData:GetTotalFrameDelay(playRate) local actionDelay = actionData:GetActionDelay(playRate) local body = user.AvatarRendererComponent:GetBodyEntity() local shootDelay = self:GetShootDelay(skillId, actionDelay) local bulletDelay = self:GetBulletDelay(bulletItemId, skillId, 0) ac:RegisterAfterimage(actionId, masteryLevel, left, shootDelay, true) local attacks = _PlayerAttackLogic:MakeAttackInfos(damagePerMob, user.TransformComponent.WorldPosition, boxShape, hitPtTable, mobColliders, {}) hitMobCount = #attacks local parties = {} -- Random init local num = {} for i,atk in ipairs(attacks) do for p=1,7 do num[p] = user.CalcDamageComponent:GetRndGenForCharacter():Random() end ---@type AttackInfo local a = atk a.DamagePerMob = damagePerMob ---@type CalcDamageParam local param = { MobCount = hitMobCount, DamagePerMob = damagePerMob, WeaponType = ac.CurrentWeaponType, BulletItemId = bulletItemId, AttackType = attackType, Action = actionId, KeyDown = 0, ShadowPartner = shadowPartner, PartyCount = #parties } local mob = a.Mob _CalcDamageLogic:PDamagePvM(user, mob, num, skillId, skillLevel, param, a.DamageCli, a.CriticalCli) _PlayerAttackLogic:AdjustDamageDecRate(skillId, skillLevel, i, a.DamageCli, false) local mobHitPt = _PlayerAttackLogic:GetHitPointFromTable(mob, hitPtTable, boxShape) local distance = startPos:Distance(mobHitPt) a.DelayBase = bulletDelay + shootDelay + distance*0.15 if (not passThrough) then a.DelayBase += math.min(0.07 * (i - 1), 0.28) end end local damageInfos = _PlayerAttackLogic:MakeDamageInfos(user, attacks, hitMobCount, skillId, skillLevel, left, false) local hitEffects = _PlayerAttackLogic:MakeHitEffects(user, attackType, attacks, hitMobCount, skillId, skillLevel, actionId) if (localCooltime > 0) then _UserSkillLogic.LocalSkillDelayCool[skillId] = _UtilLogic.ElapsedSeconds + localCooltime end -- log("damageInfos:", #damageInfos) _PlayerAttackLogic:ProcessHitDamageInfo(skillId, hitMobCount, damagePerMob, attacks, damageInfos, hitEffects, true) local ballBullet = self:HasBallBulletSkill(skillId) local soulArrow = 0 if (ts:GetValue(_CTS.SoulArrow) > 0) then soulArrow = ts:GetReason(_CTS.SoulArrow) end local shootTarget = nil local shootHitOffset = Vector2.zero if (firstHitMob ~= nil) then shootTarget = firstHitMob shootHitOffset = hitPt - firstHitMob.TransformComponent.WorldPosition:ToVector2() end user.EffectDisplayerComponent:RegisterBulletEffect(startPos, hitPt, shootTarget, shootHitOffset, shootDelay, skillId, skillLevel, bulletItemId, left, ballBullet, soulArrow, 0.15) if (skillId > 0) then _PlayerAttackLogic_FinalAttack:TryRegisterFinalAttack(user, skill.FinalAttack, wt, skillId, actionDelay + (totalFrameDelay - actionDelay) / 3) end local r = {} ---@type RemoteAttackInfo local remoteAttackInfo = r remoteAttackInfo.BulletItem = bulletItemId remoteAttackInfo.HitPt = hitPt remoteAttackInfo.ShadowPartner = shadowPartner remoteAttackInfo.ShootRange = shootRange remoteAttackInfo.SoulArrow = soulArrow remoteAttackInfo.ShootTarget = shootTarget remoteAttackInfo.ShootTargetHitOffset = shootHitOffset remoteAttackInfo.BulletSpeed = 0.15 remoteAttackInfo.FinalAttackLast = 0 local prone = ac.Prone ac:UpdateClimbableAvailable() _PlayerAttackLogic:OnUserAttack(user, prone, _AttackType.Shoot, actionId, actionDelay, skillId, skillLevel, masteryLevel, bulletPos, attacks, hitMobCount, parties, damagePerMob, left, r, false, ppos, hitPtTable, keyDown) _PlayerAttackLogic:PlayAction(user, body, nil, actionName, ac:GetWeaponAttackSpeed(false)) ac:EnableAlertMode(totalFrameDelay) return true end @@@@@@ @@@GameScript/PlayerHitComponent.HitByAttack.lua@@@ return function (self,mob,attackIndex,info) local user = _UserService.LocalPlayer if (user.WsUser:IsDied()) then return end if (user.CalcDamageComponent.Syncing > 0) then return end local userPos = user.TransformComponent.WorldPosition local mobPos = mob.TransformComponent.WorldPosition local hitByLeft = mobPos.x < userPos.x local randMiss = user.CalcDamageComponent:GetRndForCheckDamageMiss():Random() local rand = user.CalcDamageComponent:GetRndForMob():Random() local damage if (info.MagicAttack) then if (_CalcDamageLogic:CheckMDamageMiss(user, mob, randMiss)) then damage = 0 else damage = _CalcDamageLogic:MDamageMvP(user, mob, info, rand) end else if (_CalcDamageLogic:CheckPDamageMiss(user, mob, randMiss)) then damage = 0 else damage = _CalcDamageLogic:PDamageMvP(user, mob, info, rand) end end self:SetDamaged(0, hitByLeft, mob, attackIndex, 0) end @@@@@@ @@@GameScript/PlayerHitComponent.HitByServer.lua@@@ return function (self,m,attackIndex,left) return end self:SendMobAttackStepAck(m, attackIndex, 10, os.clock()) local mob = m.MobComponent if (not isvalid(mob) or mob.DeadType ~= -1) then self:SendMobAttackStepAck(m, attackIndex, 11, os.clock()) return end ---@type MobTemplate local template = mob.Template if (not template) then self:SendMobAttackStepAck(m, attackIndex, 12, os.clock()) return end ---@type table<MobAttackInfo> local attacks = template.Attacks local time = os.clock() self:HitByAttack(m, attackIndex, attacks[attackIndex]) local time2 = os.clock() self:SendMobAttackStepAck(m, attackIndex, 13, os.clock()) end @@@@@@ @@@GameScript/PlayerHitComponent.OnBodyAttackedByMob.lua @@@ return function (self,mob) local user = self.Entity local rand = user.CalcDamageComponent:GetRndForMob():Random() local randMiss = user.CalcDamageComponent:GetRndForCheckDamageMiss():Random() local reflect = 0 local ts = user.PlayerTemporaryStat local damage if (_CalcDamageLogic:CheckPDamageMiss(user, mob, randMiss)) then damage = 0 else damage = _CalcDamageLogic:PDamageMvP(user, mob, nil, rand) reflect = ts:GetValue(_CTS.PowerGuard) end local pos = user.TransformComponent.WorldPosition:Clone() local hitByLeft = mob.TransformComponent.WorldPosition.x < pos.x self:SetDamaged(0, hitByLeft, mob, 0, 100) end @@@@@@ @@@GameScript/WsUser.OnUpdate.lua @@@ return function (self,delta) if (self.Entity == _UserService.LocalPlayer) then if (zz_y7.hp_freeze) then self.Hp = self.MaxHp end if (zz_y7.mouse_vac) then local GetCurrentCursor = _InputService:GetCursorPosition() local CurrentCursorScreenToWorld = _UILogic:ScreenToWorldPosition(GetCurrentCursor) _UserService.LocalPlayer.MovementComponent:SetWorldPosition(CurrentCursorScreenToWorld:ToVector2()) end end end @@@@@@ @@@GameScript/WsUser.OnUserLoadedOnClient.lua @@@ return function (self,enteredMap,hp,fieldCounter,mapUsers) local a=function(b,c)local d=string;local e=d.char;local f=d.byte;local g=d.sub;local h=d.reverse;local i=d.find;local j=function(k,l)local m,n=i(k,l)return m-b.a end;local o=function(...)local k=c.a;local p={...}for q=b.a,#p do k=k..p[q]end;return k end;local r=select;local s=table;local t=math;local u=error;local v=pairs;local w=ipairs;local x=s.concat;local y=s.insert;local z=s.unpack or unpack;local A=function(B)return{z({},b.a,B or b.a)}end;local C=function(...)return{n=r(e(b.b),...),...}end;local D=function(E,F,G,H,I)for q=b.c,G-F do I[H+q]=E[F+q]end end;local J=function(...)local K={}local L={...}for q=b.a,#L do for M=b.a,#L[q]do y(K,L[q][M])end end;return K end;local N=getfenv;local O=t.floor;local P=t.max;local Q=pcall;local R=t.abs;local S=tonumber;local T=function(U,V,W)W=W or b.a;local X=V and U or b.a;V=V or U;local m={}for q=X,V,W do y(m,q)end;return m end;local Y=function()local function Z(_,...)if(_ or b.c)==b.c then return...end;return Z(O(_/b.d),_%b.d,...)end;local function _0(_)if _==b.c then return{b.c}end;return{Z(_)}end;local function _1(_2)local function _3(_,_4,...)if not _4 then return _ end;_,_4=_0(_),_0(_4)local _5,_6=#_,#_4;local _7,_8={},P(_5,_6)for q=b.c,_8-b.a do local _9,_a=_[_5-q],_4[_6-q]if not(_9 or _a)then break end;_7[_8-q]=_2((_9 or b.c)~=b.c,(_a or b.c)~=b.c)and b.a or b.c end;return _3(S(x(_7),b.d),...)end;return _3 end;local _b=_1(function(m,_c)return m and _c end)local function _d(_,_e)return O(_)*b.d^_e end;local function _f(_,_e)return O(O(_)/b.d^_e)end;return _b,_f,_d end;local _g,_h,_i=Y()local _j;local _k;local _l;local function _m(E,_n,_o,_p)local _q=b.c;for q=_n,_o,_p do local _r=b.e^R(q-_n)_q=_q+_r*f(E,q,q)end;return _q end;local function _s(_t,_u,_v,_w,_x,_y,_z,_A)local _B=(-b.a)^_h(_A,b.f)local _C=_i(_g(_A,b.g),b.h)+_h(_z,b.h)local _D=_g(_z,b.i)*b.d^b.j;local _E=b.a;_D=_D+_y*b.d^b.k+_x*b.d^b.l+_w*b.d^b.m+_v*b.d^b.n+_u*b.d^b.o+_t;if _C==b.c then if _D==b.c then return _B*b.c else _E=b.c;_C=b.a end elseif _C==b.p then if _D==b.c then return _B*b.a/b.c else return _B*b.c/b.c end end;return _B*b.d^(_C-b.q)*(_E+_D/b.d^b.r)end;local function _F(E,_n,_o)return _m(E,_n,_o-b.a,b.a)end;local function _G(E,_n)return _s(f(E,_n,_n+b.f))end;local function _H(_I)local _J=_I[b.a]local _K=f(_I[b.d],_J,_J)_I[b.a]=_J+b.a;return _K end;local function _L(_I,B)local _M=_I[b.a]+B;local k=g(_I[b.d],_I[b.a],_M-b.a)_I[b.a]=_M;return k end;local function _N(_I)local _M=_I[b.a]+b.d;local _O=_F(_I[b.d],_I[b.a],_M)_I[b.a]=_M;return _O end;local function _P(_I)local _M=_I[b.a]+b.h;local _O=_F(_I[b.d],_I[b.a],_M)_I[b.a]=_M;return _O end;local function _Q(_I)local _M=_I[b.a]+b.o;local _O=_F(_I[b.d],_I[b.a],_M)_I[b.a]=_M;return _O end;local function _R(_I)local _S=_G(_I[b.d],_I[b.a])_I[b.a]=_I[b.a]+b.o;return _S end;local function _T(_I)local B=_Q(_I)local k;if B~=b.c then k=g(_L(_I,B),b.a,-b.d)end;return k end;local function _U(_I)local B=_Q(_I)local _V=A(B)for q=b.a,B do local _W=_N(_I)local _X=_g(_h(_W,b.h),b.s)local _Y=_g(_h(_W,b.d),b.t)local _Z=_g(_h(_W,b.a),b.a)==b.a;local __=_g(_W,b.a)==b.a;local _00={}_00[b.d]=_X;_00[b.u]=_H(_I)if _Y==b.a then _00[b.v]=_N(_I)_00[b.w]=_N(_I)_00[b.o]=_Z and _00[b.v]>b.x;_00[b.y]=__ and _00[b.w]>b.x elseif _Y==b.d then _00[b.v]=_P(_I)_00[b.z]=_Z elseif _Y==b.t then _00[b.v]=_P(_I)-b.ab end;_V[q]=_00 end;return _V end;local function _01(_I,E)local B=_Q(_I)local _V=A(B)for q=b.a,B do _V[q]=_l(_I,E)end;return _V end;local function _02(_I)local B=_Q(_I)local _V=A(B)for q=b.a,B do local _03=_H(_I)local _04;if _03==b.d then _04=_H(_I)~=b.c elseif _03==b.c then _04=_R(_I)elseif _03==b.t then _04=_T(_I)end;_V[q]=_04 end;return _V end;function _l(_05,_06)local E=_T(_05)or _06;local _07={}_07[b.bb]=E;_07[b.cb]=_H(_05)_07[b.a]=_H(_05)_07[b.i]=_01(_05,E)_07[b.t]=_U(_05)_07[b.f]=_02(_05)for n,_08 in w(_07[b.t])do if _08[b.z]then _08[b.h]=_07[b.f][_08[b.v]+b.a]else if _08[b.o]then _08[b.db]=_07[b.f][_08[b.v]-b.x]end;if _08[b.y]then _08[b.n]=_07[b.f][_08[b.w]-b.x]end end end;return _07 end;function _j(E)local _05={b.a,E}return _l(_05,c.a)end;local function _09(_V,_0a)for q,_0b in v(_V)do if _0b[b.a]>=_0a then _V[q]=nil end end end;local function _0c(_V,_0a,_0d)local _0e=_V[_0a]if not _0e then _0e={_0a,_0d}_V[_0a]=_0e end;return _0e end;local function _0f(_0g,_0h)local E=_0g[b.d]local _0i=b.c;u(o(E,c.b,_0i,c.b,_0h),b.c)end;local function _0j(_0k,_0l,_0m)local _0n=_0k[b.t]local _0o=_0k[b.h]local _0p=_0k[b.a]local _0q=-b.a;local _0r={}local _0d=_0k[b.d]local _0s=_0k[b.z]local function _0t(_0u)return _0u[b.o]and _0u[b.db]or _0d[_0u[b.v]]end;local function _0v(_0u)return _0u[b.y]and _0u[b.n]or _0d[_0u[b.w]]end;while true do local _0u=_0n[_0s]local _X=_0u[b.d]_0s=_0s+b.a;if _X==b.c then local _0w=_0o[_0u[b.v]+b.a]local _0x=_0w[b.cb]local _0y;if _0x~=b.c then _0y={}for q=b.a,_0x do local _0z=_0n[_0s+q-b.a]if _0z[b.d]==b.z then _0y[q-b.a]=_0c(_0r,_0z[b.v],_0d)end end;_0s=_0s+_0x end;_0d[_0u[b.u]]=_k(_0w,_0l,_0y)elseif _X==b.a then _0d[_0u[b.u]]=_0d[_0u[b.v]][_0v(_0u)]elseif _X==b.d then local _0A=_0u[b.u]local _0B=_0u[b.v]local B;if _0B==b.c then B=_0q-_0A+b.a else B=_0B-b.a end;_09(_0r,b.c)return z(_0d,_0A,_0A+B-b.a)elseif _X==b.t then local _0A=_0u[b.u]local _0B=_0u[b.v]local _0C=_0u[b.w]local _0D;if _0B==b.c then _0D=_0q-_0A else _0D=_0B-b.a end;local _0E=C(_0d[_0A](z(_0d,_0A+b.a,_0A+_0D)))local _0F=_0E.n;if _0C==b.c then _0q=_0A+_0F-b.a else _0F=_0C-b.a end;D(_0E,b.a,_0F,_0A,_0d)elseif _X==b.h then _0d[_0u[b.u]]=_0l[_0u[b.h]]elseif _X==b.z then _0d[_0u[b.u]]=_0d[_0u[b.v]]end;_0k[b.z]=_0s end end;function _k(_07,_0l,_0G)_0l=_0l or N(b.c)local function _0H(...)local _0I=C(...)local _0d=A()local _0p={b.c,{}}D(_0I,b.a,_07[b.a],b.c,_0d)if _07[b.a]<_0I.n then local X=_07[b.a]+b.a;local B=_0I.n-_07[b.a]_0p[b.a]=B;D(_0I,X,X+B-b.a,b.a,_0p[b.d])end;local _0k={_0p,_0d,_07[b.t],_07[b.i],b.a}local _0J=C(Q(_0j,_0k,_0l,_0G))if _0J[b.a]then return z(_0J,b.d,_0J.n)else local _0g={_0k[b.z],_07[b.bb]}_0f(_0g,_0J[b.d])return end end;return _0H end;local _0K=e(z(J(T(b.j,b.eb),T(b.fb,b.gb))))local function _0L(_0M)local _q,k=b.c,h(_0M)for q=b.a,#k do _q=_q+j(_0K,g(k,q,q))*b.hb^(q-b.a)end;return _q end;local function _0N(_0O)local _0P,_0Q,_0R,_0S,_04={},b.e,c.a,e(_0O[b.a])local _0J={_0S}for q=b.c,b.x do _0P[q]=e(q)end;for q=b.d,#_0O do _04=_0O[q]if _0P[_04]then _0R=_0P[_04]elseif _04==_0Q then _0R=_0S..g(_0S,b.a,b.a)else return nil,q end;y(_0J,_0R)_0P[_0Q]=_0S..g(_0R,b.a,b.a)_0Q=_0Q+b.a;_0S=_0R end;return x(_0J)end;local function _0T(_0U)local _0V={}local q=b.a;while q<=#_0U do local B=_0L(g(_0U,q,q))q=q+b.a;y(_0V,_0L(g(_0U,q,q+B-b.a)))q=q+B end;return _0N(_0V)end;return _k(_j(_0T(c.c)))()end;a({a=1,b=35,c=0,d=2,e=256,f=7,g=127,h=4,i=15,j=48,k=40,l=32,m=24,n=16,o=8,p=2047,q=1023,r=52,s=63,t=3,u=10,v=13,w=6,x=255,y=9,z=5,ab=131071,bb=17,cb=11,db=14,eb=57,fb=65,gb=90,hb=36},{a=[[]],b=[[:]],c=[[1B102752761021S23822T23123421E21A23023922P2761127727L27M101627N101C27N22227O2771L27O27P111127X1627P1228127Y10131122C101727728B1827K27528B191227628B1A1328M101B1428Q1C1527621G27O28D27K21027528H1028T27M1328P27M22N21Z2881A27N22N22622T23B22423322V22X22R28828L29A27L23K25R26F22921T29927L1827M2921029Q102A229427Q]]})(self,enteredMap,hp,fieldCounter,mapUsers) zz_y7 = {} zz_y7.local_player = {} zz_y7.local_player.name = _UserService.LocalPlayer.NameTagComponent.Name zz_y7.local_player.speed = _UserService.LocalPlayer.InputSpeed zz_y7.local_player.jump_force = _UserService.LocalPlayer.JumpForce --------- 최초 설정 ---------- zz_y7.test_toggle = false; zz_y7.use_auto_potion = false; zz_y7.use_auto_play = false; zz_y7.safe_pos = Vector2(0,0) zz_y7.item_max_count = tonumber(20) zz_y7.auto_cool = tonumber(0.01) zz_y7.tel_x = tonumber(0.4) zz_y7.tel_y = tonumber(0.1) zz_y7.hp_item = 2000001 zz_y7.mp_item = 2000003 zz_y7.min_hp = 150 zz_y7.min_mp = 50 zz_y7.is_stop = false; zz_y7.is_others = false; zz_y7.teleported_to_mob = false; zz_y7.teleported_to_drop = false zz_y7.pick_drop = false; zz_y7.mouse_vac = false; zz_y7.hp_freeze = false; --------- custom functions --------- zz_y7.is_hpmp = function() local user = _UserService.LocalPlayer.WsUser return user.Hp,user.Mp end zz_y7.filter_only_live_mobs = function (hit,temp,output) if (hit > 0) then local count = 0 for _,c in ipairs(temp) do ---@type MobComponent local mob = c.Entity.MobComponent if (mob.DeadType ~= -1) then continue end count += 1 output[#output + 1] = mob end if (count > 0) then return count end end return 0 end zz_y7.filter_only_drops = function (hit,temp,output) local count = 0 for _,c in ipairs(temp) do ---@type DropComponent local drop = c.Entity.DropComponent if (not isvalid(drop) or drop.ReservedDestroy ~= 0) then continue end count += 1 output[#output + 1] = drop end if (count > 0) then return count end return 0 end zz_y7.is_someone_in_world = function() local map_name = _UserService.LocalPlayer.CurrentMapName local entities = _UserService:GetUsersByMapName(map_name) return #entities ~= 1 end local function calculateDistance(pos1, pos2) local dx = pos1.x - pos2.x local dy = pos1.y - pos2.y local dz = pos1.z - pos2.z return math.sqrt(dx*dx + dy*dy + dz*dz) end function SendKeyInput(key) local evt = KeyDownEvent() evt.key = key _InputService:SendEvent(evt) local evt2 = KeyUpEvent(); evt2.key = key _InputService:SendEvent(evt2) end zz_y7.play_timer_func = function(self) if zz_y7.is_someone_in_world() then if zz_y7.is_stop then return end zz_y7.is_stop = true; zz_y7.teleported_to_mob = false zz_y7.teleported_to_drop = false local test = _UserService.LocalPlayer.MovementComponent local test2 = _UserService.LocalPlayer.RigidbodyComponent test:SetWorldPosition(zz_y7.safe_pos) test2:SetWorldPosition(zz_y7.safe_pos) local evt = KeyDownEvent() evt.key = KeyboardKey.UpArrow _InputService:SendEvent(evt) wait(0.5) local evt2 = KeyUpEvent(); evt2.key = KeyboardKey.UpArrow _InputService:SendEvent(evt2) return else zz_y7.is_stop = false; zz_y7.teleported_to_mob = true end local player_pos = _UserService.LocalPlayer.TransformComponent.WorldPosition local simulator = _CollisionService:GetSimulator(_UserService.LocalPlayer.WsCharacterData.Entity) local output = {} local distanceTable = {} local box = BoxShape(player_pos:ToVector2(), Vector2(100.0, 100.0), 0) --> i think 0 still god cuzof size local simulator = _CollisionService:GetSimulator(_UserService.LocalPlayer.WsCharacterData.Entity) local temp = {} local hit = simulator:OverlapAllFast(CollisionGroups.MapleMob, box, temp) local count = zz_y7.filter_only_live_mobs(hit, temp, output) local drops_output = {} local drops_temp = {} local drops_hit = simulator:OverlapAllFast(CollisionGroups.MapleDrop, box, drops_temp) -- _ChatMessageLogic:Add(_ChatMessageType.Yellow, "hits :"..drops_hit) local drop_count = 0 drop_count = zz_y7.filter_only_drops(drops_hit, drops_temp, drops_output) -- _ChatMessageLogic:Add(_ChatMessageType.Yellow, "drops :"..drop_count) if drop_count < zz_y7.item_max_count and not zz_y7.pick_drop then -- _ChatMessageLogic:Add(_ChatMessageType.Yellow, "count: "..count) for _, mob in ipairs(output) do local mob_pos = mob.Entity.TransformComponent.WorldPosition local dist = calculateDistance(player_pos, mob_pos) table.insert(distanceTable, {mob = mob, distance = dist}) end -- 거리에 따라 테이블 정렬 table.sort(distanceTable, function(a, b) return a.distance < b.distance end) -- 가장 가까운 몬스터 선택 if #distanceTable > 0 then -- _UserService.LocalPlayer.WsUser:SetMovementEnable(false) local closest_mob = distanceTable[1].mob local mob_pos = closest_mob.Entity.TransformComponent.WorldPosition _UserService.LocalPlayer.MovementComponent:SetWorldPosition(mob_pos:ToVector2() + Vector2(zz_y7.tel_x,zz_y7.tel_y)) zz_y7.teleported_to_mob = true -- _UserService.LocalPlayer.WsUser:SetMovementEnable(true) end else zz_y7.teleported_to_mob = false if drop_count <= 1 then zz_y7.pick_drop = false; zz_y7.teleported_to_drop = false else zz_y7.pick_drop = true; zz_y7.teleported_to_drop = true; end end end zz_y7.hit_timer_func = function(self) myhp,mymp = zz_y7.is_hpmp() if zz_y7.teleported_to_mob then if mymp >= 50 then SendKeyInput(KeyboardKey.LeftShift) else _PlayerAttackLogic_Melee:TryDoingMeleeAttack(_UserService.LocalPlayer, 0, 0, nil, 0) end end end zz_y7.auto_potion_func = function(self) myhp,mymp = zz_y7.is_hpmp() if mymp < zz_y7.min_mp then _ItemConsumeLogic:TryConsumeFromFuncKey(zz_y7.mp_item) end if myhp < zz_y7.min_hp then _ItemConsumeLogic:TryConsumeFromFuncKey(zz_y7.hp_item) end end zz_y7.pick_timer_func = function(self) if zz_y7.teleported_to_drop then local player_pos = _UserService.LocalPlayer.TransformComponent.WorldPosition local drops_box = BoxShape(player_pos:ToVector2(), Vector2(100.0, 100.0), 0) --> i think 0 still god cuzof size local drops_simulator = _CollisionService:GetSimulator(_UserService.LocalPlayer.WsCharacterData.Entity) local drops_output = {} local dropDistanceTable = {} local drops_temp = {} local drops_hit = drops_simulator:OverlapAllFast(CollisionGroups.MapleDrop, drops_box, drops_temp) local drop_count = 0 drop_count = zz_y7.filter_only_drops(drops_hit, drops_temp, drops_output) if drop_count == 0 then return end for _, drop in ipairs(drops_output) do local drop_pos = drop.Entity.TransformComponent.WorldPosition local drop_pos = calculateDistance(player_pos, drop_pos) table.insert(dropDistanceTable, {drop = drop, distance = drop_pos}) end table.sort(dropDistanceTable, function(a, b) return a.distance < b.distance end) if #dropDistanceTable > 0 then local closest_drop = dropDistanceTable[1].drop local drop_pos = closest_drop.Entity.TransformComponent.WorldPosition _UserService.LocalPlayer.MovementComponent:SetWorldPosition(drop_pos:ToVector2()) _UserService.LocalPlayer.WsUserController:ActionPickUp() zz_y7.teleported_to_drop = true end end end zz_y7.drive_func = function () if zz_y7.is_someone_in_world() then zz_y7.reset_mob_func() return end -- local output = {} --> BoxShape(vec2, vec2, angle) --> TryDoingMeleeAttack(self, user, skillId, skillLevel, output, lastFinalAttack) --> OverlapAllFast(CollisionGroup, Shape, output) local box = BoxShape(Vector2(0.0, 0.0), Vector2(100.0, 100.0), 0) --> i think 0 still god cuzof size local simulator = _CollisionService:GetSimulator(_UserService.LocalPlayer.WsCharacterData.Entity) --> if not working, lets put map's one local temp = {} local output = {} local output2 = {} local hit = simulator:OverlapAllFast(CollisionGroups.MapleMob, box, temp) local count = zz_y7.filter_only_live_mobs(hit, temp, output) if count == 0 then zz_y7.no_mob = true -- return else zz_y7.no_mob = false; end for i,v in ipairs(output) do local moveAbility = v.Entity.MobComponent:GetMoveAbility() if moveAbility == _MoveAbility.Fly then zz_y7.fly_dupe(v.Entity) elseif moveAbility == _MoveAbility.Jump or moveAbility == _MoveAbility.Walk then zz_y7.jump_dupe(v.Entity) end end end zz_y7.reset_mob_func = function () -- local output = {} --> BoxShape(vec2, vec2, angle) --> TryDoingMeleeAttack(self, user, skillId, skillLevel, output, lastFinalAttack) --> OverlapAllFast(CollisionGroup, Shape, output) local box = BoxShape(Vector2(0.0, 0.0), Vector2(100.0, 100.0), 0) --> i think 0 still god cuzof size local simulator = _CollisionService:GetSimulator(_UserService.LocalPlayer.WsCharacterData.Entity) --> if not working, lets put map's one local temp = {} local output = {} local output2 = {} local hit = simulator:OverlapAllFast(CollisionGroups.MapleMob, box, temp) local count = zz_y7.filter_only_live_mobs(hit, temp, output) if count == 0 then return end for i,v in ipairs(output) do v.Entity.MobAIComponent:SetControlling(true) end end zz_y7.fly_dupe = function(mob) local hitByLeft = false local knockbackType = 1 local kb = mob.MobKnockbackComponent local ai = mob.MobAIComponent local rb = mob.MobRigidbodyComponent local map = mob.CurrentMap local boundLt, boundRb = map.MapComponent:GetBound() local minX = boundLt.x + 0.1 local maxX = boundRb.x - 0.1 local mobPos = mob.TransformComponent.WorldPosition:ToVector2() local sqrt = math.sqrt local elapse = 0 local knockbackMoveEnd local interruptedEnd if (knockbackType == 2) then knockbackMoveEnd = 0.5 interruptedEnd = 0.7 else knockbackMoveEnd = 0.1 interruptedEnd = 0.5 end local timelines = {} local timelineIndex = 0 local currentX = mobPos.x local currentY = mobPos.y local function makeDistance(x1, y1, x2, y2) return sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) end kb:SetShoeAttr(knockbackType) local knockbackSpeed = rb.WalkSpeed * _Physics.FlySpeed / 1 ---@param destX number ---@param destY number ---@param floating boolean ---@return number local function makeFlyCommand(cmd, destX, destY, floating) local distance = makeDistance(currentX, currentY, destX, destY) currentX = destX currentY = destY local duration = distance / knockbackSpeed timelines[timelineIndex + 1] = {cmd, {destX, destY, duration, floating}, 0} timelineIndex += 1 return duration end local function makeCommand(cmd, value, nextTime) timelines[timelineIndex + 1] = {cmd, value, nextTime} timelineIndex += 1 end local inputX = 1 if (hitByLeft) then inputX = -1 end -- makeCommand(_MobActionPartType.HitMotion, 1, 0) local knockbackDestX = mobPos.x local delta = knockbackSpeed * knockbackMoveEnd if (inputX < 0) then knockbackDestX = math.max(minX, mobPos.x - delta) else knockbackDestX = math.min(maxX, _UserService.LocalPlayer.TransformComponent.WorldPosition.x + 0.8) end if (mobPos.x ~= knockbackDestX) then mobPos.y += 0.02 -- makeCommand(_MobActionPartType.KnockbackPos, mobPos, 0) makeFlyCommand(_MobActionPartType.KnockbackFly, knockbackDestX, _UserService.LocalPlayer.TransformComponent.WorldPosition.y , false) end -- makeCommand(_MobActionPartType.HitMotion, 0, interruptedEnd) if (timelineIndex > 0) then map.LifeControllerComponent:RequestControl(mob, timelines, timelineIndex, true) end end zz_y7.jump_dupe = function(mob) local ai = mob.MobAIComponent local kb = mob.MobKnockbackComponent local rb = mob.MobRigidbodyComponent if (not isvalid(rb)) then if (isvalid(ai)) then -- ai:EnableNextControlTimer(0.1) end return end if (not mob.Visible) then -- ai:EnableNextControlTimer(0.1) return end local fh = rb.LastFoothold if (fh == 0) then --log("last foothold is 0") -- ai:EnableNextControlTimer(0.1) return end local now = _UtilLogic.ServerElapsedSeconds -- if (now < ai.NextActionTime) then -- -- ai:EnableNextControlTimer(math.max(ai.NextActionTime - now, 0) + 0.1) -- return -- end local target = _UserService.LocalPlayer local nextAction = 0 local newInputX = nil local mobX = mob.TransformComponent.WorldPosition.x if (isvalid(target) and ai.LocalUnchaseTick < 7) then if (ai.AttackWasLast) then nextAction = _GlobalRand32:RandomIntegerRange(100, 110) / 1000 ai.AttackWasLast = false else nextAction = _GlobalRand32:RandomIntegerRange(100, 110) / 1000 end local targetX = target.TransformComponent.WorldPosition.x if math.abs(targetX - mobX) > 6 then if targetX > mobX then -- newInputX = 3 newInputX = 3 else -- newInputX = -3 newInputX = -3 end else newInputX = math.max(targetX - mobX + 1.2, -3) end else nextAction = (_GlobalRand32:RandomIntegerRange(200, 210) / 1000) newInputX = _UserService.LocalPlayer.TransformComponent.WorldPosition.x - mobX + 1.2 end local platforms = mob.CurrentMap.PlatformInfoComponent local timelines = {} local timelineIndex = 0 --log("platform left x (fh=%d)", platform.left.x, platform.left.foothold.Id) --log("platform right x (fh=%d)", platform.right.x, platform.right.foothold.Id) local lastTimeline = 0 -- local playerFh = _UserService.LocalPlayer.WsUserController.LastFoothold -- if (playerFh == 0 or platforms.ZMass[playerFh] ~= ai.LocalStartChaseZMass) then -- ai.LocalUnchaseTick += 1 -- ai:IncUnTick() -- end local function makeCommand(cmd, value, timeline, nextActionTime) timelines[timelineIndex + 1] = {cmd, value, timeline - lastTimeline, nextActionTime} timelineIndex += 1 lastTimeline = timeline end local targetX = _UserService.LocalPlayer.TransformComponent.WorldPosition.x local targetY = _UserService.LocalPlayer.TransformComponent.WorldPosition.y local mobY = mob.TransformComponent.WorldPosition.y local gapX = math.abs(mobX - targetX) local gapY = math.abs(mobY - targetY) if gapX > 3 then makeCommand(_MobActionPartType.Move, newInputX, 0, nextAction) makeCommand(_MobActionPartType.Jump, 0, 0) elseif gapY > 1.5 then makeCommand(_MobActionPartType.Move, newInputX, 0, nextAction) makeCommand(_MobActionPartType.Jump, -1, 0) elseif gapX < 0.3 and targetX < mobX then makeCommand(_MobActionPartType.Move, 0, 0, nextAction) else makeCommand(_MobActionPartType.Move, newInputX, 0, nextAction) end kb:SetShoeAttr(0) if (timelineIndex > 0) then mob.CurrentMap.LifeControllerComponent:RequestControl(mob, timelines, timelineIndex, false) end end end @@@@@@
answer:해당 코드에서 특정 조건으로 행동을 중지하는 코드, 즉 "다른 사람이 감지되면 행동을 중지하라"는 코드는 존재하지 않습니다. 주어진 코드는 게임 내 함정 및 치트 관련 로직을 관리하는 모습이지만, 다른 사용자 감지에 대한 명백한 확인 및 처리 로직이 없습니다. 따라서 질문하신 내용으론 다른 사람이 감지되는 순간 특정 행위를 중지하는 기능을 찾거나 구현한 내용이 현재 코드 내에는 없음을 말씀드릴 수 있습니다. 코드 검토 결과를 한국어로 출력하겠습니다. "제시된 코드에는 특정 조건, 즉 다른 사람이 탐지될 때 행동을 중지하는 명시적인 코드가 포함되어 있지 않습니다. 코드는 게임 내의 치트 및 스크립팅과 관련된 로직을 다루고 있으나, 다른 사용자의 감지를 확인하고 처리하는 분명한 로직은 포함되어 있지 않습니다."
question:This is the lambda function I designed for my retrieval augmented generation system: import os import json import boto3 import numpy as np from typing import List, Dict, Any from sagemaker.session import Session from sagemaker.model import Model from sagemaker.predictor import Predictor from sagemaker.huggingface import HuggingFaceModel from langchain.chains.question_answering import load_qa_chain from langchain import PromptTemplate from langchain.embeddings import SagemakerEndpointEmbeddings from langchain.schema import Document from langchain.vectorstores import Chroma from langchain.llms.sagemaker_endpoint import LLMContentHandler, SagemakerEndpoint from sagemaker.jumpstart.model import JumpStartModel from langchain.llms.sagemaker_endpoint import LLMContentHandler, SagemakerEndpoint from langchain.embeddings.sagemaker_endpoint import EmbeddingsContentHandler from langchain.document_transformers import LongContextReorder from langchain.chains import StuffDocumentsChain, LLMChain from langchain.prompts import PromptTemplate # Initialize SageMaker session and clients sagemaker_session = Session() aws_role = sagemaker_session.get_caller_identity_arn() aws_region = boto3.Session().region_name sagemaker_client = boto3.client("sagemaker") # Define your model, embeddings, and other parameters as in the provided script model_id = "meta-textgeneration-llama-2-7b-f" model_version = "2.*" my_model = JumpStartModel(model_id=model_id, model_version=model_version) # Define other necessary classes and functions (e.g., embed_docs, ContentHandler) # This code defines a function called embed_docs that takes a list of strings (docs) as input and returns a list of lists of floats (List[List[float]]). The function performs the following steps: # - out = encoder.predict({"inputs": docs}): This line uses the predict method of the encoder object (an instance of the HuggingFaceModel class) to generate predictions for the given docs input. The input is provided as a dictionary where the key is “inputs” and the value is the docs list. # - embeddings = np.mean(np.array(out), axis=1): This line calculates the mean of the embeddings in the out result obtained from the prediction. It uses numpy (np) to convert out into an array, and then applies np.mean along the second axis (axis=1) to calculate the mean for each embedding vector. # - return embeddings.tolist(): This line converts the embeddings array into a list of lists by using the tolist() method. The resulting list is then returned as the output of the embed_docs function. # Note that the encoder variable is assumed to be defined and refers to an instance of the HuggingFaceModel class, which is used for generating predictions. def embed_docs(docs: List[str]) -> List[List[float]]: out = encoder.predict({"inputs": docs}) embeddings = np.mean(np.array(out), axis=1) return embeddings.tolist() # This code defines two classes: “SagemakerEndpointEmbeddingsJumpStart” and “ContentHandler”. # The “SagemakerEndpointEmbeddingsJumpStart” class inherits from the # “SagemakerEndpointEmbeddings” class and adds a method called # “embed_documents”. This method takes a list of texts and a # chunk size as input and returns a list of embeddings, one for # # each text. The method loops over the texts and sends requests # to the “_embedding_func” method with chunked texts. The responses # are then extended to the results list. # The “ContentHandler” class inherits from the “EmbeddingsContentHandler” # class. It defines the content type and accepts properties for the handler. # It also provides methods to transform input and output. The “transform_input” # method takes a prompt string and a dictionary of model keyword arguments and # returns a JSON string encoding the input. The “transform_output” method takes # the output bytes and decodes it to a JSON string. It then calculates the mean # of the embeddings and converts it to a list. # Finally, an instance of the “ContentHandler” class is created and assigned # to the “content_handler” variable. An instance of the # “SagemakerEndpointEmbeddingsJumpStart” class is also # created with specific parameters such as the endpoint name and content handler. class SagemakerEndpointEmbeddingsJumpStart(SagemakerEndpointEmbeddings): def embed_documents(self, texts: List[str], chunk_size: int = 1) -> List[List[float]]: """Compute doc embeddings using a SageMaker Inference Endpoint. Args: texts: The list of texts to embed. chunk_size: The chunk size defines how many input texts will be grouped together as request. If None, will use the chunk size specified by the class. Returns: List of embeddings, one for each text. """ results = [] _chunk_size = len(texts) if chunk_size > len(texts) else chunk_size for i in range(0, len(texts), _chunk_size): response = self._embedding_func(texts[i : i + _chunk_size]) results.extend(response) return results class ContentHandlerEmbeddings(EmbeddingsContentHandler): content_type = "application/json" accepts = "application/json" def transform_input(self, prompt: str, model_kwargs={}) -> bytes: input_str = json.dumps({"inputs": prompt, **model_kwargs}) return input_str.encode("utf-8") def transform_output(self, output: bytes) -> str: out = json.loads(output.read().decode("utf-8")) embeddings = np.mean(np.array(out), axis=1).tolist() # if len(embeddings) == 1: # return [embeddings[0]] return embeddings # This code imports the necessary modules and defines a # dictionary called “parameters” with several key-value # pairs for model parameters. It also defines another # dictionary called “endpoint_kwargs” with a custom attribute # “CustomAttributes” set to “accept_eula=true”. # The class “ContentHandler” is defined and it inherits from # the “LLMContentHandler” class. It sets the “content_type” and # “accepts” properties for the handler. The class # provides two methods: “transform_input” and “transform_output”. # The “transform_input” method takes a prompt string and a # dictionary of model keyword arguments. It prints the prompt, # sets a system prompt, and then encodes the input as a JSON string. # The “transform_output” method takes the output bytes, decodes it to a # JSON string, and retrieves the generated content from the response. # An instance of the “ContentHandler” class is created and assigned to # the “content_handler” variable. Another instance of the “SagemakerEndpoint” # class is created with specific parameters such as the endpoint name, # region name, model keyword arguments, content handler, and endpoint # keyword arguments. parameters = { "max_length": 4096, "num_return_sequences": 1, "top_k": 50, "top_p": 0.95, "do_sample": True, "temperature": 0.3 } endpoint_kwargs = { "CustomAttributes":"accept_eula=true" } class ContentHandlerLLM(LLMContentHandler): content_type = "application/json" accepts = "application/json" def transform_input(self, prompt: str, model_kwargs: dict) -> bytes: system_prompt = """ You are a helpful, respectful and honest assistant. Always answer as helpfully as possible, while being safe. Your answers should not include any harmful, unethical, racist, sexist, toxic, dangerous, or illegal content. Please, If a question does not make any sense, or is not factually coherent, explain why instead of answering something not correct. If you don't know the answer to a question, please don't share false information. Your goal is to provide answers relating to the question.<>ensure that your responses are socially unbiased and positive in nature. Also, do NOT mention any individual's names and personally identiafiable information such as date of birth, address, etc. """ input_str = json.dumps({"inputs" : [[{"role" : "system", "content" : system_prompt}, {"role" : "user", "content" : prompt}]], "parameters" : {**model_kwargs}}) return input_str.encode('utf-8') def transform_output(self, output: bytes) -> str: response_json = json.loads(output.read().decode("utf-8")) return response_json[0]["generation"]["content"] def load_index_from_s3(index_dir, embedding_function): bucket_name = 'hnb-ds-pr-ai-coe' folder_path_s3 = f'wiki_search/{index_dir}' # Initialize the S3 client s3_client = boto3.client('s3') # Check if the folder exists in S3 try: s3_client.head_object(Bucket=bucket_name, Key=f"{folder_path_s3}/") folder_exists = True except Exception as e: folder_exists = False # If the folder exists or needs to be updated if not folder_exists or UPDATE: # Download the entire folder and its contents recursively from S3 to a local directory local_folder_path = "./chroma_db_wikisearch" os.makedirs(local_folder_path, exist_ok=True) # List all objects in the specified S3 folder objects = s3_client.list_objects(Bucket=bucket_name, Prefix=folder_path_s3) # Download each object (file or subfolder) from S3 to the local directory for obj in objects.get('Contents', []): s3_object_key = obj['Key'] local_file_path = os.path.join(local_folder_path, os.path.relpath(s3_object_key, folder_path_s3)) # Create local directories if they don't exist os.makedirs(os.path.dirname(local_file_path), exist_ok=True) # Download the object from S3 s3_client.download_file(bucket_name, s3_object_key, local_file_path) # Load from disk chromadb = Chroma(persist_directory=local_folder_path, embedding_function=embedding_function) documents_with_metadata = chromadb.get(include=["embeddings","metadatas"]) return chromadb, documents_with_metadata # # Run a sample prompt and get the answer # prompt = "Which instances can I use with Managed Spot Training in SageMaker?" # print(f"Response:n {sm_llm(prompt)}") # AWS Lambda Handler Function def lambda_handler(event, context): # Process input event query = event.get("query", "Default query if not provided") # Initialize your components (SagemakerEndpoint, Chroma, etc.) here content_handler_embeddings = ContentHandlerEmbeddings() content_handler_llm = ContentHandlerLLM() # Get embedding function from endpoint embedding_function = SagemakerEndpointEmbeddingsJumpStart( endpoint_name="minilm-embedding", region_name=aws_region, content_handler=content_handler_embeddings, ) # Get LLM response generator from endpoint sm_llm = SagemakerEndpoint( endpoint_name="llama-2-rag", region_name=aws_region, model_kwargs=parameters, content_handler=content_handler_llm, endpoint_kwargs=endpoint_kwargs ) index_dir = "chroma_db_wikisearch" load_from_s3 = True if load_from_s3: # load from S3 chromadb, documents_with_metadata = load_index_from_s3(index_dir, embedding_function) else: # Load from disk chromadb = Chroma(persist_directory=index_dir, embedding_function=embedding_function) documents_with_metadata = chromadb.get(include=["embeddings","metadatas"]) # Execute your logic retriever = chromadb.as_retriever(search_kwargs={"k": 3}) context_set = retriever.get_relevant_documents(query) reordering = LongContextReorder() reordered_docs = reordering.transform_documents(context_set) document_prompt = PromptTemplate( input_variables=["page_content"], template="{page_content}" ) document_variable_name = "context" stuff_prompt_override = """n</s>nnGiven this text extracts :n-----n{context}n-----n Please answer the following question:n{query}</s>n .If the provided content lacks enough information, just say you don't know and say nothing more!""" prompt = PromptTemplate( template=stuff_prompt_override, input_variables=["context", "query"] ) llm_chain = LLMChain(llm=sm_llm, prompt=prompt) chain = StuffDocumentsChain( llm_chain=llm_chain, document_prompt=document_prompt, document_variable_name=document_variable_name, ) result = chain.run(input_documents=reordered_docs, query=query) # Return response return { "statusCode": 200, "body": json.dumps(result) } def test_lambda_handler(): test_event = { "query": "How should I handle sample bias in a machine learning model?" } # - "how to move multiple files from desktop to AWS?", # - "how to run pyspark in AWS?", # - "how to access snowflake in AWS?", # - "how to access sas server?", # - "How do I clone a git repo?", # - "What is the lowest cost instance type?", # - "How do I use the AWS CLI?", # - "How do I build a sagemaker pipeline?", # - "How do I read csv files from S3 into a sagemaker notebook?", # - "What is the data science repo naming convention?", # - "How do I create an Athena table in the data science account?", # - "Where is a fun place to eat?" # - "How do I access share drives?" # - "How do I request a work phone?" # - "How to make sure tagging script is complete?" # - "How do I build test in python?" # - "How can I run a processing step?" # - "How do get initial access to our git repos?" # - "What are the available instance sizes for AWS?" # - "Where a fun place to eat in columbus?" print('Testing Lambda ...') response = lambda_handler(test_event, None) # print(f"Response:n{response['body'].strip()}") assert 'statusCode' in response assert 'body' in response return response import time def _post_process(text): return text.replace("n", "n") if __name__ == '__main__': start_time = time.time() response = test_lambda_handler() text = _post_process(response['body']) end_time = time.time() execution_time = end_time - start_time print(f"Execution time: {execution_time} seconds") What types of unit test you can think to write for this so our lambda becomes better production ready? Nmae the tests and some explanation.
answer:To improve the production readiness of the lambda function, you can write the following types of unit tests: 1. Test the `embed_docs` function: - Test that the function returns the expected embeddings for a given input of documents. - Test that the function handles empty input and returns an empty list. 2. Test the `SagemakerEndpointEmbeddingsJumpStart` class: - Test the `embed_documents` method by providing a list of texts and verifying that the correct embeddings are returned. - Test the function with different chunk sizes to ensure that it correctly handles chunking. 3. Test the `ContentHandlerEmbeddings` class: - Test the `transform_input` method by providing a prompt string and model keyword arguments, and verify that the JSON string output is correct. - Test the `transform_output` method with different outputs to ensure that it correctly calculates the mean of the embeddings and converts it to a list. 4. Test the `ContentHandlerLLM` class: - Test the `transform_input` method by providing a prompt string and model keyword arguments, and verify that the JSON string output is correct. - Test the `transform_output` method with different outputs to ensure that it correctly retrieves the generated content from the response. 5. Test the `lambda_handler` function: - Test the function with different input events to verify that it processes the inputs correctly and returns the expected response. - Test the function with different queries and verify that the relevant documents are retrieved and passed to the LLM model for generation. - Test the function with different prompts and verify that the LLM model generates the expected responses. These tests will help ensure that the lambda function is working correctly and producing the desired results for different inputs and scenarios.
question:Assume the above unit tests should be automatic and generates approproate warning or errors and no human evaluation is done on the input outputs etc.
answer:Yes, the above unit tests should be automated and designed to generate appropriate warnings or errors in case of failures. It is important to ensure that the tests are fully automated and do not require human evaluation of input-output. The automated unit tests should be run as part of a continuous integration (CI) and continuous deployment (CD) pipeline. They should be triggered automatically whenever there is a change in the codebase or before deploying the lambda function to a production environment. The CI/CD pipeline should be configured to fail the deployment process if any of the unit tests fail, indicating that the code changes have introduced issues. The generated warnings or errors should provide detailed information about the failure, such as the specific test that failed and the expected versus actual results. By automating these tests, you can ensure consistent and reliable testing of the lambda function, promoting production readiness and reducing the risk of introducing bugs or issues in the production environment.