So with the release of the MS2 client, I downloaded it and started looking at the files. I will be posting here any and all updates that I get regarding these files as well as my unpacking endeavors.
So far I've got almost the entire format figured out. It's very simple, and I like it simple. Approximately 70% of the files are encrypted. However, the encryption looks to be a simple cipher that I might be able to crack. I'm still analyzing this, but it will take some time. At least the files that are encrypted have an "encrypted" flag set on it so I can skip over them. Perhaps the more frustrating thing is that the client is packed with Themida meaning I won't be able to get much from it.
:chin:
So right now here's what I have:
- Some map images (backgrounds, parallax mapping, minimaps)
- NPC images
- UI elements
- Some formulas
- Interesting Excel files
- Animations (stored in GameBryo nif format)
There's probably a lot more. I just don't have a mass unpacker like I do for Maplestory 1. The Maplestory 2 formatted files are completely different, and MS1 unpackers are definitely not compatible with MS2.
Currently sound is packed in a different sort of archive and it will take a while for me to figure out. I'm deprioritizing it because right now all of the interesting stuff (XML files) are the encrypted files, and it's the encrypted files that interest me.
I have to leave for work in about 45 minutes, so I'll post all I can before then. Allow me to save some posts and I'll get to uploading.
As a preliminary sort of thing, if you want to see the images I'll be dumping, please download a DDS viewer. I found this one to be very basic but sufficient.
2014-09-15, 10:45 AM
Fiel
Re: Maplestory 2, Aanyeong
Formulas:
This is probably the easiest stuff to post, however it has the most duplicated data. You will understand what I mean when you read it. It looks like the formulas went through several iterations.
Formula_renewal.lua
Code:
math.randomseed(os.time())
-- *********************************************************************************************************************************************************************
-- 대미지 등급 정의
DG_Normal = 0
DG_Critical = 1
DG_Miss = 2
DG_Block = 3
-- *********************************************************************************************************************************************************************
-- ep 재생력
function calc_ep_regen(jobcode, max_ep, amount, interval, elapsedTime, sit)
local rst_ser = 0
if elapsedTime >= ep_interval[jobcode] then
if sit == 1 then
rst_ser = ep_value[jobcode]
else
rst_ser = ep_value[jobcode]
end
end
return rst_ser
end
-- *********************************************************************************************************************************************************************
-- 값 클리핑
function clip_value(x, min, max)
if x < min then x = min end
if x > max then x = max end
return x
end
-- 이동 속도 스탯을 그대로 가져와서 연산하게 변경_140911_이정섭.
function calc_msiR(mspV)
--local rst_msiRate = (mspV / (mspV + 18)) * 1.3
local rst_msiRate = mspV / 100
return clip_value(rst_msiRate, 0.07, 1.65)
end
-- *********************************************************************************************************************************************************************
-- 도약률
function calc_jmiR(jmpV)
return math.max(jmpV / 100, 0)
end
-- *********************************************************************************************************************************************************************
-- 공격 속도율
function calc_asiR(aspV, seq_speed)
local rst_asiRate = (aspV / (aspV + 804)) * 0.5 + 1.0
return math.max(rst_asiRate * seq_speed, 0)
end
-- *********************************************************************************************************************************************************************
-- hp 재생력
function calc_hp_regen(jobcode, max_hp, amount, interval, elapsedTime, sit)
local rst_shr = 0
if elapsedTime >= interval then
if sit == 1 then
rst_shr = amount * 1.5
else
rst_shr = amount
end
end
return rst_shr
end
-- ************************************************************************************************************************************************
-- stat 가/감/승/제
function calc_stat_sum(base_statV, item_statV, item_statR, skill_statV, skill_statR)
local rst_sum = 0
-- ************************************************************************************************************************************************
-- 완전 방어 판정.
function calc_abp(abp, finalAbpV, finalAbpR)
return abp
end
-- *********************************************************************************************************************************************************************
-- HP 회복 공식: 마법 공격력과 연산하여 회복량 산출.
function calc_recoveryHP(map, maxHP, rate)
return map * rate
end
-- ************************************************************************************************************************************************
-- npc크리티컬 확률
function calc_npc_cap(luk, cap, car)
local rst_cap = ((luk + cap) / car) * CORRECT_CRITICAL
return clip_value(rst_cap, 0, 0.5)
end
-- ************************************************************************************************************************************************
-- pc크리티컬 확률
function calc_pc_cap(jobcode, luk, cap, car, finalCapV, finalCapR)
local rst_cap = ((luk * CRITICAL[Major][jobcode] + cap) / car) * CORRECT_CRITICAL
return clip_value(rst_cap, 0, 0.5)
end
-- ************************************************************************************************************************************************
-- npc최종 공격력(tap:최종공격력, dv:대미지 밸류, dr:대미지 레이트)
function calc_npc_tap(tap, dv, dr)
local rst_tap = tap * dr
return rst_tap
end
-- ************************************************************************************************************************************************
--pc최종 공격력(wap:무기 공격력)
-- 기존 공식: ((math.max(wap, 1) * WEAPON[Major][ISC_BLUNT]) * CORRECT_WEAPON) * tap * (dr * (math.max(cost_sp, 1) * sp_weight))
function calc_pc_tap(wap, tap, dv, dr, cost_sp, cost_ep, sp_weight)
--local rst_tap = ((math.max(wap, 1) * WEAPON[Major][ISC_BLUNT])) * tap * (dr + (cost_sp * sp_weight) + (cost_ep * (sp_weight * 0.2)))
local rst_tap = ((math.max(wap, 1) * WEAPON[Major][ISC_BLUNT])) * tap * dr
return rst_tap
end
return math.max(0.1, rst_hitRate + rst_atpStat - rst_evpStat)
end
-- *********************************************************************************************************************************************************************
function calc_fallDamage(mhpV, fallDistance)
local rst_damage = (mhpV * 7 * ((fallDistance - 750) / 150)) / 100
return math.max(rst_damage, 0)
end
-- *********************************************************************************************************************************************************************
-- UGC 마켓에 등록할 때 등록 수수료
-- saleCount 유저가 설정한 판매 개수
function calc_ugcshopRegisterCost(salePrice, saleCount)
return saleCount * 100;
end
-- *********************************************************************************************************************************************************************
-- UGC 마켓에서 물건을 판매 했을 때 징수하는 판매 수수료
-- purchasePrice 판매 가격
function calc_ugcshopBuyCost(purchasePrice)
return purchasePrice * 0.5;
end
-- *********************************************************************************************************************************************************************
-- memberCount 같은 맵에 존재하는 파티 멤버 수에 따라 메소 보너스
function calcPartyMoneyRate(memberCount)
if memberCount == 1 then
return 1.0
elseif memberCount == 2 then
return 1.1
elseif memberCount == 3 then
return 1.15
elseif memberCount == 4 then
return 1.25
end
return 0
end
-- 킬카운트 계산
function calcKillCount(myLevel, targetLevel, term, killCount)
if term < 5000 then
local diffLevel = math.abs(myLevel - targetLevel)
if diffLevel <= 5 then
killCount = killCount + 1
end
else
killCount = 1
end
return killCount
end
-- 연속 킬카운트 시 증가 exp비율
function calcKillCountBonusExpRate(killCount)
if killCount > 100 then
return 0.15
elseif killCount > 50 then
return 0.1
elseif killCount > 40 then
return 0.07
elseif killCount > 30 then
return 0.04
elseif killCount > 20 then
return 0.01
elseif killCount > 10 then
return 0
end
return 0
end
-- 연속 킬카운트 grade
function calcKillCountGrade(killCount)
if killCount > 50 then
return 2
elseif killCount > 20 then
return 1
end
return 0
end
-- 킬카운트 메세지
function calcKillCountMsg(killCount)
if killCount == 30 then
return "s_killcount_msg1"
elseif killCount == 40 then
return "s_killcount_msg2"
elseif killCount == 50 then
return "s_killcount_msg3"
elseif killCount == 100 then
return string.format("s_killcount_msg%d",math.random(4,5))
end
return ""
end
-- 제자리 부활에 드는 메소
function calcRevivalPrice(level)
if level <= 8 then
return 0
else
return level * 10
end
end
-- 월드맵에서 맵간 이동할 때 드는 메소
function calcMoveFieldPrice(level, jobCode)
if level <= 10 then
return 50
else
return 200
end
end
-- 몬스터가 피격 동작을 취하는 빈도
function calcHitMotion(boss, Critical, damage, maxHP, level)
hitMotion = 1
if boss == 1 then
hitMotion = 0
--elseif level < 10 then
-- if Critical == 1 then
-- hitMotion = 1
-- elseif math.random(0, 100) <= 100 then
-- hitMotion = 1
-- end
--else
-- if Critical == 1 then
-- hitMotion = 1
-- elseif math.random(0, 100) <= 50 then
-- hitMotion = 1
-- end
end
return hitMotion
end
-- UGC Banner Price
function calcBannerPrice(adWorth, bannerDay)
return 10 * adWorth * bannerDay
end
-- Send Mail Fee
-- 수수료 최대 금액이 int 이므로 INT_MAX (2,147,483,647)를 넘으면 안된다.
function calcSendMailFee(attachedItemCount, attachedMeso)
local defaultFee = 10;
local itemFee = attachedItemCount * 100
local mesoFee = 0
if attachedMeso == 0 then
mesoFee = 0
elseif attachedMeso <= 100 then
mesoFee = 1
else
mesoFee = attachedMeso * 1 / 100
end
return defaultFee + itemFee + mesoFee
end
--몬스터 자동스폰 가중치 계산
function calcNpcSpawnWeight(mainTagCount, subTagCount, rareDegree, difficultyDiff)
local weightMain = 0
local weightSub = 0
local weightRareDegree = 0
local weightDifficulty = 0
if mainTagCount == 0 then
weightMain = 1
else
weightMain = (mainTagCount + 1) * 20 --5에서 20으로 올림 (테스트를 위해)
end
if subTagCount == 0 then
weightSub = 1
else
weightSub = (subTagCount + 1) * 1
end
weightRareDegree = rareDegree * 0.01
if difficultyDiff > 10 then
weightDifficulty = 1
else
weightDifficulty = 12 - difficultyDiff
end
return weightMain + weightSub + weightRareDegree + weightDifficulty
end
-- 부활 패널티 비용
function calcResolvePaneltyPrice(level, paneltyCount)
return 30 * level * paneltyCount
end
-- 테스트 목적으로 추가 by ksjeong
function testLua(a, b)
-- testtesttest()
-- error(100)
-- error('err100')
c = a + b
return c, "test is ok..."
end
-- ********************************************************************************
-- 매력 관련 패널티 세팅하는 테이블
-- added by ksjeong
activity = {}
activity.dead = {}
activity.dead.penalty = {}
activity.dead.penalty.timeSpan = 15 * 60 -- 사망 후 카운트 되는 패널티 타임 (초 단위)
activity.dead.penalty.defaultPoint = 1 -- 사망 시 감소하는 기본 성취도
activity.dead.penalty.maxPoint = 5 -- 최대 누적 가능 패널티
function getActivityDeadPenaltyTime()
return activity.dead.penalty.timeSpan
end
function getActivityDeadPenaltyDefaultPoint()
return activity.dead.penalty.defaultPoint
end
function getActivityDeadPenaltyMaxPoint()
return activity.dead.penalty.maxPoint
end
function getActivityDeadPenaltyConstant()
return activity.dead.penalty.timeSpan, activity.dead.penalty.defaultPoint, activity.dead.penalty.maxPoint
end
function getDeadPenalty(beginDate, expireDate, point)
local curTime, remainTime
curTime = os.time()
local penaltyInfo = activity.dead.penalty
if beginDate == 0 then
beginDate = curTime
remainTime = 0
return remainTime, beginDate, expireDate, point
end
if expireDate == 0 then
expireDate = curTime + penaltyInfo.timeSpan
end
if expireDate > curTime then
point = math.min(point + 1, penaltyInfo.maxPoint);
remainTime = expireDate - curTime
end
return remainTime, beginDate, expireDate, point
end
-- 매력 포인트 테이블 빌드 함수
function buildActivityExpTable()
for i = 1, #scoreRegion do
for j = scoreRegion[i].min, scoreRegion[i].max do
activityExpTable[j] = scoreRegion[i].exp
end
end
end
-- 매력 포인트 테이블 빌드 함수 호출
buildActivityExpTable()
-- 매력 1당 필요 경험치를 구하는 함수
function getActivityExp(lv)
local exp = activityExpTable[lv]
if (exp == nil) then
exp = 0
end
return exp
end
-- 매력 포인트 테스트 함수
-- print (getActivityExp(100))
-- ********************************************************************************
function testActivityLevel(curLv, curExp)
local addLevel = 0
local level = 0
local next = getActivityExp(0)
while next > 0 and next <= curExp do
curExp = curExp - next
level = level + 1
if level > curLv then
addLevel = addLevel + 1
end
next = getActivityExp(level)
end
local up = addLevel > 0
if up then
level = curLv + addLevel
level = math.min(level, 100)
end
-- ********************************************************************************
-- 게임에 접속하면 매일 획득할 수 있는 경험치
activity.attend = {}
activity.attend.exp = {}
activity.attend.exp.baseHour = 6 -- 리셋되는 시각 (0 ~ 23)
activity.attend.exp.timeSpan = 24*60*60 -- 반복 주기를 시*분*초으로 계산하고 초 단위
activity.attend.exp.attendExp = 10 -- 획득할 수 있는 생활 경험치
activity.attend.exp.increaseExp = 1 -- 연속 접속할 때 가중치
activity.attend.exp.maxBonus = 30 -- 최대 보너스 제한
function getPlayExp(lastTime, bonus)
local exp = 0
local curTime, prevTime, nextTime, expireTime
curTime = os.time()
local now = os.date("*t", curTime)
local dawn = false
local EventInfo = activity.attend.exp
if now.hour < EventInfo.baseHour then
dawn = true
end
-- ********************************************************************************
-- 게임 미 접속 패널티
activity.unattend = {}
activity.unattend.penalty = {}
activity.unattend.penalty.defaultPoint = 1 -- 미 접속 시 감소하는 기본 성취도
activity.unattend.penalty.bonusPoint = 1 -- 연속해서 접속하지 않을 때 감소하는 성취도 (2일 연속 +1, 3일 연속이면 +2)
activity.unattend.penalty.maxPoint = 30 -- 최대 감소하는 성취도
activity.unattend.penalty.timeSpan = 24*60*60 -- 접속 체크 기간 초 단위 (기본 하루 24시간)
function getPlayPenalty(lastTime, point, expireTime)
local curTime, remainTime, periodSec, periodDay
curTime = os.time()
local penaltyInfo = activity.unattend.penalty
if lastTime == 0 then
remainTime = 0
return point, remainTime, expireTime
end
if expireTime > curTime then
remainTime = expireTime - curTime
return point, remainTime, expireTime
end
if periodDay >= 1 then
point = point + penaltyInfo.defaultPoint
point = point + (periodDay - 1) * penaltyInfo.bonusPoint
point = math.min(point, penaltyInfo.maxPoint)
remainTime = penaltyInfo.timeSpan
expireTime = curTime + penaltyInfo.timeSpan
end
return point, remainTime, expireTime
end
-- ********************************************************************************
-- 드롭 수량 제한하는 아이템을 우선 뽑을 순서 결정하는 시스템.
function getNpcRewardArrangeWeight(monsterLevel, userLevel)
local defaultWeight = 100
if monsterLevel - 3 <= userLevel then -- 기본 가중치를 적용받을 레벨대.
return defaultWeight
end
if monsterLevel - userLevel >= 20 then -- 몬스터와 유저 레벨의 차이를 판단.
return defaultWeight / (monsterLevel - userLevel)
end
return 1 -- 나머지 레벨들은 가중치를 1로 적용. 0을 넣을 경우 보상에서 완전 제외됨으로 보상을 줄 기회를 주려면 무조건 1 이상
end
-- ********************************************************************************
-- 매시브 이벤트 참여
activity.massive = {}
activity.massive.exp = {}
activity.massive.exp.attendPoint = 10 -- 매시브 이벤트에 참가하면 얻을 수 있는 생활 경험치
activity.massive.exp.winPoint = 100 -- 우승하면 획득할 수 있는 생활 경험치
function getMassiveExpPoint(winFlag)
local bonusInfo = activity.massive.exp
if winFlag then
return bonusInfo.winPoint
else
return bonusInfo.attendPoint
end
end
-- ********************************************************************************
-- 플레이어 킬 패널티
activity.kill = {}
activity.kill.penalty = {}
activity.kill.penalty.defaultPoint = 5 -- 다른 플레이어 킬에 따른 매력 포인트 감소
activity.kill.penalty.increasePoint = 1 -- 누적 킬 수 증가에 따른 가중치
activity.kill.penalty.maxPoint = 10 -- 감소하는 최대 한도를 설정
activity.kill.penalty.maxKillCount = 10 -- 누적 킬 카운트의 최대 한도
function getPKPenalty(killCount)
local point = 0
local penaltyInfo = activity.kill.penalty
point = point + penaltyInfo.defaultPoint
point = point + killCount * penaltyInfo.increasePoint
point = math.min(point, penaltyInfo.maxPoint)
-- *********************************************************************************************************************************************************************
-- ep 재생력
function calc_ep_regen(jobcode, max_ep, amount, interval, elapsedTime, sit)
local rst_ser = 0
if elapsedTime >= ep_interval[jobcode] then
if sit == 1 then
rst_ser = ep_value[jobcode]
else
rst_ser = ep_value[jobcode]
end
end
return rst_ser
end
-- *********************************************************************************************************************************************************************
-- 값 클리핑
function clip_value(x, min, max)
if x < min then x = min end
if x > max then x = max end
return x
end
-- 이동 속도 스탯을 그대로 가져와서 연산하게 변경_140911_이정섭.
function calc_msiR(mspV)
--local rst_msiRate = (mspV / (mspV + 18)) * 1.3
local rst_msiRate = mspV / 100
return clip_value(rst_msiRate, 0.07, 1.65)
end
-- *********************************************************************************************************************************************************************
-- 도약률
function calc_jmiR(jmpV)
return math.max(jmpV / 100, 0)
end
-- *********************************************************************************************************************************************************************
-- 공격 속도율
function calc_asiR(aspV, seq_speed)
local rst_asiRate = (aspV / (aspV + 804)) * 0.5 + 1.0
return math.max(rst_asiRate * seq_speed, 0)
end
-- *********************************************************************************************************************************************************************
-- hp 재생력
function calc_hp_regen(jobcode, max_hp, amount, interval, elapsedTime, sit)
local rst_shr = 0
if elapsedTime >= interval then
if sit == 1 then
rst_shr = amount * 1.5
else
rst_shr = amount
end
end
return rst_shr
end
-- ************************************************************************************************************************************************
-- stat 가/감/승/제
function calc_stat_sum(base_statV, item_statV, item_statR, skill_statV, skill_statR)
local rst_sum = 0
-- ************************************************************************************************************************************************
-- 완전 방어 판정.
function calc_abp(abp, finalAbpV, finalAbpR)
return abp
end
-- *********************************************************************************************************************************************************************
-- HP 회복 공식: 마법 공격력과 연산하여 회복량 산출.
function calc_recoveryHP(map, maxHP, rate)
return map * rate
end
-- ************************************************************************************************************************************************
-- npc크리티컬 확률
function calc_npc_cap(luk, cap, car)
local rst_cap = ((luk + cap) / car) * CORRECT_CRITICAL
return clip_value(rst_cap, 0, 0.5)
end
-- ************************************************************************************************************************************************
-- pc크리티컬 확률
function calc_pc_cap(jobcode, luk, cap, car, finalCapV, finalCapR)
local rst_cap = ((luk * CRITICAL[Major][jobcode] + cap) / car) * CORRECT_CRITICAL
return clip_value(rst_cap, 0, 0.5)
end
-- ************************************************************************************************************************************************
-- npc최종 공격력(tap:최종공격력, dv:대미지 밸류, dr:대미지 레이트)
function calc_npc_tap(tap, dv, dr)
local rst_tap = tap * dr
return rst_tap
end
-- ************************************************************************************************************************************************
--pc최종 공격력(wap:무기 공격력)
-- 기존 공식: ((math.max(wap, 1) * WEAPON[Major][ISC_BLUNT]) * CORRECT_WEAPON) * tap * (dr * (math.max(cost_sp, 1) * sp_weight))
function calc_pc_tap(wap, tap, dv, dr, cost_sp, cost_ep, sp_weight)
--local rst_tap = ((math.max(wap, 1) * WEAPON[Major][ISC_BLUNT])) * tap * (dr + (cost_sp * sp_weight) + (cost_ep * (sp_weight * 0.2)))
local rst_tap = ((math.max(wap, 1) * WEAPON[Major][ISC_BLUNT])) * tap * dr
return rst_tap
end
return math.max(0.1, rst_hitRate + rst_atpStat - rst_evpStat)
end
-- *********************************************************************************************************************************************************************
function calc_fallDamage(mhpV, fallDistance)
local rst_damage = (mhpV * 7 * ((fallDistance - 750) / 150)) / 100
return math.max(rst_damage, 0)
end
-- *********************************************************************************************************************************************************************
-- UGC 마켓에 등록할 때 등록 수수료
-- saleCount 유저가 설정한 판매 개수
function calc_ugcshopRegisterCost(salePrice, saleCount)
return saleCount * 100;
end
-- *********************************************************************************************************************************************************************
-- UGC 마켓에서 물건을 판매 했을 때 징수하는 판매 수수료
-- purchasePrice 판매 가격
function calc_ugcshopBuyCost(purchasePrice)
return purchasePrice * 0.5;
end
-- *********************************************************************************************************************************************************************
-- memberCount 같은 맵에 존재하는 파티 멤버 수에 따라 메소 보너스
function calcPartyMoneyRate(memberCount)
if memberCount == 1 then
return 1.0
elseif memberCount == 2 then
return 1.1
elseif memberCount == 3 then
return 1.15
elseif memberCount == 4 then
return 1.25
end
return 0
end
-- 킬카운트 계산
function calcKillCount(myLevel, targetLevel, term, killCount)
if term < 5000 then
local diffLevel = math.abs(myLevel - targetLevel)
if diffLevel <= 5 then
killCount = killCount + 1
end
else
killCount = 1
end
return killCount
end
-- 연속 킬카운트 시 증가 exp비율
function calcKillCountBonusExpRate(killCount)
if killCount > 100 then
return 0.15
elseif killCount > 50 then
return 0.1
elseif killCount > 40 then
return 0.07
elseif killCount > 30 then
return 0.04
elseif killCount > 20 then
return 0.01
elseif killCount > 10 then
return 0
end
return 0
end
-- 연속 킬카운트 grade
function calcKillCountGrade(killCount)
if killCount > 50 then
return 2
elseif killCount > 20 then
return 1
end
return 0
end
-- 킬카운트 메세지
function calcKillCountMsg(killCount)
if killCount == 30 then
return "s_killcount_msg1"
elseif killCount == 40 then
return "s_killcount_msg2"
elseif killCount == 50 then
return "s_killcount_msg3"
elseif killCount == 100 then
return string.format("s_killcount_msg%d",math.random(4,5))
end
return ""
end
-- 제자리 부활에 드는 메소
function calcRevivalPrice(level)
if level <= 8 then
return 0
else
return level * 10
end
end
-- 월드맵에서 맵간 이동할 때 드는 메소
function calcMoveFieldPrice(level, jobCode)
if level <= 10 then
return 50
else
return 200
end
end
-- 몬스터가 피격 동작을 취하는 빈도
function calcHitMotion(boss, Critical, damage, maxHP, level)
hitMotion = 1
if boss == 1 then
hitMotion = 0
--elseif level < 10 then
-- if Critical == 1 then
-- hitMotion = 1
-- elseif math.random(0, 100) <= 100 then
-- hitMotion = 1
-- end
--else
-- if Critical == 1 then
-- hitMotion = 1
-- elseif math.random(0, 100) <= 50 then
-- hitMotion = 1
-- end
end
return hitMotion
end
-- UGC Banner Price
function calcBannerPrice(adWorth, bannerDay)
return 10 * adWorth * bannerDay
end
-- Send Mail Fee
-- 수수료 최대 금액이 int 이므로 INT_MAX (2,147,483,647)를 넘으면 안된다.
function calcSendMailFee(attachedItemCount, attachedMeso)
local defaultFee = 10;
local itemFee = attachedItemCount * 100
local mesoFee = 0
if attachedMeso == 0 then
mesoFee = 0
elseif attachedMeso <= 100 then
mesoFee = 1
else
mesoFee = attachedMeso * 1 / 100
end
return defaultFee + itemFee + mesoFee
end
--몬스터 자동스폰 가중치 계산
function calcNpcSpawnWeight(mainTagCount, subTagCount, rareDegree, difficultyDiff)
local weightMain = 0
local weightSub = 0
local weightRareDegree = 0
local weightDifficulty = 0
if mainTagCount == 0 then
weightMain = 1
else
weightMain = (mainTagCount + 1) * 20 --5에서 20으로 올림 (테스트를 위해)
end
if subTagCount == 0 then
weightSub = 1
else
weightSub = (subTagCount + 1) * 1
end
weightRareDegree = rareDegree * 0.01
if difficultyDiff > 10 then
weightDifficulty = 1
else
weightDifficulty = 12 - difficultyDiff
end
return weightMain + weightSub + weightRareDegree + weightDifficulty
end
-- 부활 패널티 비용
function calcResolvePaneltyPrice(level, paneltyCount)
return 30 * level * paneltyCount
end
-- 테스트 목적으로 추가 by ksjeong
function testLua(a, b)
-- testtesttest()
-- error(100)
-- error('err100')
c = a + b
return c, "test is ok..."
end
-- ********************************************************************************
-- 매력 관련 패널티 세팅하는 테이블
-- added by ksjeong
activity = {}
activity.dead = {}
activity.dead.penalty = {}
activity.dead.penalty.timeSpan = 15 * 60 -- 사망 후 카운트 되는 패널티 타임 (초 단위)
activity.dead.penalty.defaultPoint = 1 -- 사망 시 감소하는 기본 성취도
activity.dead.penalty.maxPoint = 5 -- 최대 누적 가능 패널티
function getActivityDeadPenaltyTime()
return activity.dead.penalty.timeSpan
end
function getActivityDeadPenaltyDefaultPoint()
return activity.dead.penalty.defaultPoint
end
function getActivityDeadPenaltyMaxPoint()
return activity.dead.penalty.maxPoint
end
function getActivityDeadPenaltyConstant()
return activity.dead.penalty.timeSpan, activity.dead.penalty.defaultPoint, activity.dead.penalty.maxPoint
end
function getDeadPenalty(beginDate, expireDate, point)
local curTime, remainTime
curTime = os.time()
local penaltyInfo = activity.dead.penalty
if beginDate == 0 then
beginDate = curTime
remainTime = 0
return remainTime, beginDate, expireDate, point
end
if expireDate == 0 then
expireDate = curTime + penaltyInfo.timeSpan
end
if expireDate > curTime then
point = math.min(point + 1, penaltyInfo.maxPoint);
remainTime = expireDate - curTime
end
return remainTime, beginDate, expireDate, point
end
-- 매력 포인트 테이블 빌드 함수
function buildActivityExpTable()
for i = 1, #scoreRegion do
for j = scoreRegion[i].min, scoreRegion[i].max do
activityExpTable[j] = scoreRegion[i].exp
end
end
end
-- 매력 포인트 테이블 빌드 함수 호출
buildActivityExpTable()
-- 매력 1당 필요 경험치를 구하는 함수
function getActivityExp(lv)
local exp = activityExpTable[lv]
if (exp == nil) then
exp = 0
end
return exp
end
-- 매력 포인트 테스트 함수
-- print (getActivityExp(100))
-- ********************************************************************************
function testActivityLevel(curLv, curExp)
local addLevel = 0
local level = 0
local next = getActivityExp(0)
while next > 0 and next <= curExp do
curExp = curExp - next
level = level + 1
if level > curLv then
addLevel = addLevel + 1
end
next = getActivityExp(level)
end
local up = addLevel > 0
if up then
level = curLv + addLevel
level = math.min(level, 100)
end
-- ********************************************************************************
-- 게임에 접속하면 매일 획득할 수 있는 경험치
activity.attend = {}
activity.attend.exp = {}
activity.attend.exp.baseHour = 6 -- 리셋되는 시각 (0 ~ 23)
activity.attend.exp.timeSpan = 24*60*60 -- 반복 주기를 시*분*초으로 계산하고 초 단위
activity.attend.exp.attendExp = 10 -- 획득할 수 있는 생활 경험치
activity.attend.exp.increaseExp = 1 -- 연속 접속할 때 가중치
activity.attend.exp.maxBonus = 30 -- 최대 보너스 제한
function getPlayExp(lastTime, bonus)
local exp = 0
local curTime, prevTime, nextTime, expireTime
curTime = os.time()
local now = os.date("*t", curTime)
local dawn = false
local EventInfo = activity.attend.exp
if now.hour < EventInfo.baseHour then
dawn = true
end
-- ********************************************************************************
-- 게임 미 접속 패널티
activity.unattend = {}
activity.unattend.penalty = {}
activity.unattend.penalty.defaultPoint = 1 -- 미 접속 시 감소하는 기본 성취도
activity.unattend.penalty.bonusPoint = 1 -- 연속해서 접속하지 않을 때 감소하는 성취도 (2일 연속 +1, 3일 연속이면 +2)
activity.unattend.penalty.maxPoint = 30 -- 최대 감소하는 성취도
activity.unattend.penalty.timeSpan = 24*60*60 -- 접속 체크 기간 초 단위 (기본 하루 24시간)
function getPlayPenalty(lastTime, point, expireTime)
local curTime, remainTime, periodSec, periodDay
curTime = os.time()
local penaltyInfo = activity.unattend.penalty
if lastTime == 0 then
remainTime = 0
return point, remainTime, expireTime
end
if expireTime > curTime then
remainTime = expireTime - curTime
return point, remainTime, expireTime
end
if periodDay >= 1 then
point = point + penaltyInfo.defaultPoint
point = point + (periodDay - 1) * penaltyInfo.bonusPoint
point = math.min(point, penaltyInfo.maxPoint)
remainTime = penaltyInfo.timeSpan
expireTime = curTime + penaltyInfo.timeSpan
end
return point, remainTime, expireTime
end
-- ********************************************************************************
-- 드롭 수량 제한하는 아이템을 우선 뽑을 순서 결정하는 시스템.
function getNpcRewardArrangeWeight(monsterLevel, userLevel)
local defaultWeight = 100
if monsterLevel - 3 <= userLevel then -- 기본 가중치를 적용받을 레벨대.
return defaultWeight
end
if monsterLevel - userLevel >= 20 then -- 몬스터와 유저 레벨의 차이를 판단.
return defaultWeight / (monsterLevel - userLevel)
end
return 1 -- 나머지 레벨들은 가중치를 1로 적용. 0을 넣을 경우 보상에서 완전 제외됨으로 보상을 줄 기회를 주려면 무조건 1 이상
end
-- ********************************************************************************
-- 매시브 이벤트 참여
activity.massive = {}
activity.massive.exp = {}
activity.massive.exp.attendPoint = 10 -- 매시브 이벤트에 참가하면 얻을 수 있는 생활 경험치
activity.massive.exp.winPoint = 100 -- 우승하면 획득할 수 있는 생활 경험치
function getMassiveExpPoint(winFlag)
local bonusInfo = activity.massive.exp
if winFlag then
return bonusInfo.winPoint
else
return bonusInfo.attendPoint
end
end
-- ********************************************************************************
-- 플레이어 킬 패널티
activity.kill = {}
activity.kill.penalty = {}
activity.kill.penalty.defaultPoint = 5 -- 다른 플레이어 킬에 따른 매력 포인트 감소
activity.kill.penalty.increasePoint = 1 -- 누적 킬 수 증가에 따른 가중치
activity.kill.penalty.maxPoint = 10 -- 감소하는 최대 한도를 설정
activity.kill.penalty.maxKillCount = 10 -- 누적 킬 카운트의 최대 한도
function getPKPenalty(killCount)
local point = 0
local penaltyInfo = activity.kill.penalty
point = point + penaltyInfo.defaultPoint
point = point + killCount * penaltyInfo.increasePoint
point = math.min(point, penaltyInfo.maxPoint)
-- *********************************************************************************************************************************************************************
-- 데미지 등급 정의
DG_Normal = 0
DG_Critical = 1
DG_Miss = 2
DG_Block = 3
-- *********************************************************************************************************************************************************************
-- 값 클리핑
function clip_value(x, min, max)
if x < min then x = min end
if x > max then x = max end
return x
end
-- *********************************************************************************************************************************************************************
-- 공격 속도율
function calc_t_asiR(o_t_aspV)
local rst_asiRate = (o_t_aspV / (o_t_aspV + 804)) * 0.5 + 1.0
return math.max(rst_asiRate, 0)
end
-- 이동 속도율
function calc_t_msiR(o_t_mspV)
local rst_msiRate = (o_t_mspV / (o_t_mspV + 50)) * 1.5
return clip_value(rst_msiRate, 0, 2)
end
-- 도약률
function calc_t_jmiR(o_t_jmpV)
return math.max(o_t_jmpV, 0)
end
-- 크리티컬 저항
function calc_p_carV(o_t_carV)
local rst_car = (o_t_carV / (o_t_carV + 804)) * 0.5
return math.max(rst_car, 0)
end
function calc_t_carV(o_s_carV, o_s_carR)
local rst_car = o_s_carV * (1 + o_s_carR)
return math.max(rst_car, 0)
end
-- 크리티컬 피해
function calc_p_cadV(o_t_cadV)
local rst_cad = (o_t_cadV / (o_t_cadV + 804)) * 0.5
return math.max(rst_cad, 0)
end
function calc_t_cadV(o_s_cadV, o_s_cadR)
local rst_cad = o_s_cadV * (1 + o_s_cadR)
return math.max(rst_cad, 0)
end
-- 크리티컬 확률
function calc_p_capV(o_t_capV, o_p_carV)
local rst_cap = ((o_t_capV / (o_t_capV + 804)) * 0.5) * (1 - o_p_carV)
return math.max(rst_cap, 0)
end
function calc_t_capV(o_s_capV, o_s_capR, o_t_lukV)
local rst_cap = o_s_capV * (1 + o_s_capR) + o_t_lukV * 2
return math.max(rst_cap, 0)
end
-- 이동 속도
function calc_t_mspV(o_s_mspV, o_s_mspR)
local rst_msp = o_s_mspV * (1 + o_s_mspR)
return math.max(rst_msp, 0)
end
-- 방어력
function calc_t_nddV(o_s_nddV, o_s_nddR, o_t_phyV)
local rst_ndd = o_s_nddV * (1 + o_s_nddR) + o_t_phyV * 2
return math.max(rst_ndd, 0)
end
-- 최대 체력
function calc_t_mhpV(o_s_mhpV, o_s_mhpR, o_t_staV)
local rst_hp = o_s_mhpV * (1 + o_s_mhpR) + o_t_staV * 2
return math.max(rst_hp, 0)
end
function calc_t_staV(o_s_staV, o_s_staR)
local rst_sta = o_s_staV * (1 + o_s_staR)
return math.max(rst_sta, 0)
end
-- 공격 속도
function calc_t_aspV(o_s_aspV, o_s_aspR, o_t_speV)
local rst_asp = o_s_aspV * (1 + o_s_aspR) + o_t_speV * 2
return math.max(rst_asp, 0)
end
function calc_t_speV(o_s_speV, o_s_speR)
local rst_spe = o_s_speV * (1 + o_s_speR)
return math.max(rst_spe, 0)
end
-- hp 재생력
function calc_t_shrV(o_s_maxHP, o_s_shrV, duration, sit)
local rst_shr = 0
if sit == 1 then
rst_shr = math.floor(duration / 1) * (10 + o_s_maxHP * 0.05)
else
rst_shr = math.floor(duration / 1) * (5 + o_s_maxHP * 0.01)
end
return rst_shr
end
-- sp 재생력
function calc_t_ssrV(o_s_maxSP, o_s_ssrV, duration)
local rst_ssr = math.floor(duration / 0.5) * 5
return rst_ssr
end
-- ep 재생력
function calc_t_serV(o_s_maxEP, o_s_serV, duration)
local rst_ser = math.floor(duration / 1) * 20
return rst_ser
end
-- 공격력
function calc_t_napV(o_s_napV, o_s_napR, o_t_pwrV, o_t_wapV)
if o_t_wapV <= 0 then
o_t_wapV = 1
end
local rst_nap = o_s_napV * (1 + o_s_napR) * o_t_wapV
return math.max(rst_nap, 0)
end
-- 행운
function calc_t_lukV(o_s_lukV, o_s_lukR)
local rst_luk = o_s_lukV * (1 + o_s_lukR)
return math.max(rst_luk, 0)
end
-- 파워
function calc_t_pwrV(o_s_pwrV, o_s_pwrR)
local rst_pwr = o_s_pwrV * (1 + o_s_pwrR)
return rst_pwr
end
-- 피지컬
function calc_t_phyV(o_s_phyV, o_s_phyR)
local rst_phy = o_s_phyV * (1 + o_s_phyR)
return rst_phy
end
-- 무기 공격력
function calc_t_wapV(o_s_wapMin, o_s_wapMax)
local rst_wap = math.random(o_s_wapMin, o_s_wapMax)
return rst_wap
end
-- 데미지
function calc_p_padV(o_t_napV, d_t_nddV, o_s_dR, o_s_dV, o_s_pdv, o_s_pdr, o_p_cad, d_s_pdv, d_s_pdr, grade)
if d_t_nddV <= 0 then
d_t_nddV = 1
end
local rst_wap = o_t_napV * o_s_dR / d_t_nddV
return rst_wap
end
-- 판정
function calc_grade(o_s_atpV, d_s_evpV, d_s_abpV, o_p_capV)
local grade = DG_Miss
local asd = calc_t_asdV(o_s_atpV, d_s_evpV, d_s_abpV)
--적중할지 결정
if math.random(0, 100) < asd * 100 then
grade = DG_Normal
end
if grade == DG_Miss then
if math.random(0, d_s_evpV + d_s_abpV) < d_s_abpV then
grade = DG_Block
end
end
--적중했을 경우에 크리티컬일지 결정
if grade == DG_Normal then
if math.random(0, 100) < o_p_capV * 100 then
grade = DG_Critical
end
end
return grade
end
-- *********************************************************************************************************************************************************************
function calc_fallDamage(mhpV, fallDistance)
local rst_damage = (mhpV * 7 * ((fallDistance - 750) / 150)) / 100
return math.max(rst_damage, 0)
end
-- *********************************************************************************************************************************************************************
-- memberCount 같은 맵에 존재하는 파티 멤버 수에 다라 메소 보너스
function calcPartyMoneyRate(memberCount)
if memberCount == 1 then
return 1.0
elseif memberCount == 2 then
return 1.1
elseif memberCount == 3 then
return 1.15
elseif memberCount == 4 then
return 1.25
end
return 0
end
-- 킬카운트 계산
function calcKillCount(myLevel, targetLevel, term, killCount)
if term < 5000 then
local diffLevel = math.abs(myLevel - targetLevel)
killCount = killCount + 1
else
killCount = 1
end
return killCount
end
-- 연속 킬카운트 시 증가 exp비율
function calcKillCountBonusExpRate(killCount)
if killCount > 100 then
return 2.0
elseif killCount > 50 then
return 1.5
elseif killCount > 40 then
return 1.3
elseif killCount > 30 then
return 1.0
elseif killCount > 20 then
return 0.7
elseif killCount > 10 then
return 0.5
end
return 0
end
-- 연속 킬카운트 grade
function calcKillCountGrade(killCount)
if killCount > 50 then
return 2
elseif killCount > 10 then
return 1
end
return 0
end
-- 킬카운트 메세지
function calcKillCountMsg(killCount)
if killCount == 30 then
return "s_killcount_msg1"
elseif killCount == 40 then
return "s_killcount_msg2"
elseif killCount == 50 then
return "s_killcount_msg3"
elseif killCount == 100 then
return string.format("s_killcount_msg%d",math.random(4,5))
end
return ""
end
-- 제자리 부활에 드는 메소
function calcRevivalPrice(level)
if level <= 8 then
return 0
else
return level * 10
end
end
-- 월드맵에서 맵간 이동할 때 드는 메소
function calcMoveFieldPrice(level, jobCode)
if level <= 8 then
return 5
else
return 50
end
end
-- 몬스터가 피격 동작을 취하는 빈도
function calcHitMotion(boss, Critical, damage, maxHP, level)
hitMotion = 1
if boss == 1 then
hitMotion = 0
--elseif level < 10 then
-- if Critical == 1 then
-- hitMotion = 1
-- elseif math.random(0, 100) <= 100 then
-- hitMotion = 1
-- end
--else
-- if Critical == 1 then
-- hitMotion = 1
-- elseif math.random(0, 100) <= 50 then
-- hitMotion = 1
-- end
end
return hitMotion
end
-- UGC Banner Price
function calcBannerPrice(adWorth, bannerDay)
return 10 * adWorth * bannerDay
end
-- Send Mail Fee
-- 수수료 최대 금액이 int 이므로 INT_MAX (2,147,483,647)를 넘으면 안된다.
function calcSendMailFee(attachedItemCount, attachedMeso)
local defaultFee = 10;
local itemFee = attachedItemCount * 100
local mesoFee = 0
if attachedMeso == 0 then
mesoFee = 0
elseif attachedMeso <= 100 then
mesoFee = 1
else
mesoFee = attachedMeso * 1 / 100
end
return defaultFee + itemFee + mesoFee
end
--몬스터 자동스폰 가중치 계산
function calcNpcSpawnWeight(mainTagCount, subTagCount, rareDegree, difficultyDiff)
local weightMain = 0
local weightSub = 0
local weightRareDegree = 0
local weightDifficulty = 0
if mainTagCount == 0 then
weightMain = 1
else
weightMain = (mainTagCount + 1) * 20 --5에서 20으로 올림 (테스트를 위해)
end
if subTagCount == 0 then
weightSub = 1
else
weightSub = (subTagCount + 1) * 1
end
weightRareDegree = rareDegree * 0.01
if difficultyDiff > 10 then
weightDifficulty = 1
else
weightDifficulty = 12 - difficultyDiff
end
return weightMain + weightSub + weightRareDegree + weightDifficulty
end
-- 부활 패널티 비용
function calcResolvePaneltyPrice(level, paneltyCount)
return 10 * level * paneltyCount
end
-- 테스트 목적으로 추가 by ksjeong
function testLua(a, b)
-- testtesttest()
-- error(100)
-- error('err100')
c = a + b
return c, "test is ok..."
end
-- ********************************************************************************
-- 매력 관련 패널티 세팅하는 테이블
-- added by ksjeong
activity = {}
activity.dead = {}
activity.dead.penalty = {}
activity.dead.penalty.timeSpan = 15 * 60 -- 사망 후 카운트 되는 패널티 타임 (초 단위)
activity.dead.penalty.defaultPoint = 1 -- 사망 시 감소하는 기본 성취도
activity.dead.penalty.maxPoint = 5 -- 최대 누적 가능 패널티
function getActivityDeadPenaltyTime()
return activity.dead.penalty.timeSpan
end
function getActivityDeadPenaltyDefaultPoint()
return activity.dead.penalty.defaultPoint
end
function getActivityDeadPenaltyMaxPoint()
return activity.dead.penalty.maxPoint
end
function getActivityDeadPenaltyConstant()
return activity.dead.penalty.timeSpan, activity.dead.penalty.defaultPoint, activity.dead.penalty.maxPoint
end
function getDeadPenalty(beginDate, expireDate, point)
local curTime, remainTime
curTime = os.time()
local penaltyInfo = activity.dead.penalty
if beginDate == 0 then
beginDate = curTime
remainTime = 0
return remainTime, beginDate, expireDate, point
end
if expireDate == 0 then
expireDate = curTime + penaltyInfo.timeSpan
end
if expireDate > curTime then
point = math.min(point + 1, penaltyInfo.maxPoint);
remainTime = expireDate - curTime
end
return remainTime, beginDate, expireDate, point
end
-- 매력 포인트 테이블 빌드 함수
function buildActivityExpTable()
for i = 1, #scoreRegion do
for j = scoreRegion[i].min, scoreRegion[i].max do
activityExpTable[j] = scoreRegion[i].exp
end
end
end
-- 매력 포인트 테이블 빌드 함수 호출
buildActivityExpTable()
-- 매력 1당 필요 경험치를 구하는 함수
function getActivityExp(lv)
local exp = activityExpTable[lv]
if (exp == nil) then
exp = 0
end
return exp
end
-- 매력 포인트 테스트 함수
-- print (getActivityExp(100))
-- ********************************************************************************
function testActivityLevel(curLv, curExp)
local addLevel = 0
local level = 0
local next = getActivityExp(0)
while next > 0 and next <= curExp do
curExp = curExp - next
level = level + 1
if level > curLv then
addLevel = addLevel + 1
end
next = getActivityExp(level)
end
local up = addLevel > 0
if up then
level = curLv + addLevel
level = math.min(level, 100)
end
-- ********************************************************************************
-- 게임에 접속하면 매일 획득할 수 있는 경험치
activity.attend = {}
activity.attend.exp = {}
activity.attend.exp.baseHour = 6 -- 리셋되는 시각 (0 ~ 23)
activity.attend.exp.timeSpan = 24*60*60 -- 반복 주기를 시*분*초으로 계산하고 초 단위
activity.attend.exp.attendExp = 10 -- 획득할 수 있는 생활 경험치
activity.attend.exp.increaseExp = 1 -- 연속 접속할 때 가중치
activity.attend.exp.maxBonus = 30 -- 최대 보너스 제한
function getPlayExp(lastTime, bonus)
local exp = 0
local curTime, prevTime, nextTime, expireTime
curTime = os.time()
local now = os.date("*t", curTime)
local dawn = false
local EventInfo = activity.attend.exp
if now.hour < EventInfo.baseHour then
dawn = true
end
-- ********************************************************************************
-- 게임 미 접속 패널티
activity.unattend = {}
activity.unattend.penalty = {}
activity.unattend.penalty.defaultPoint = 1 -- 미 접속 시 감소하는 기본 성취도
activity.unattend.penalty.bonusPoint = 1 -- 연속해서 접속하지 않을 때 감소하는 성취도 (2일 연속 +1, 3일 연속이면 +2)
activity.unattend.penalty.maxPoint = 30 -- 최대 감소하는 성취도
activity.unattend.penalty.timeSpan = 24*60*60 -- 접속 체크 기간 초 단위 (기본 하루 24시간)
function getPlayPenalty(lastTime, point, expireTime)
local curTime, remainTime, periodSec, periodDay
curTime = os.time()
local penaltyInfo = activity.unattend.penalty
if lastTime == 0 then
remainTime = 0
return point, remainTime, expireTime
end
if expireTime > curTime then
remainTime = expireTime - curTime
return point, remainTime, expireTime
end
if periodDay >= 1 then
point = point + penaltyInfo.defaultPoint
point = point + (periodDay - 1) * penaltyInfo.bonusPoint
point = math.min(point, penaltyInfo.maxPoint)
remainTime = penaltyInfo.timeSpan
expireTime = curTime + penaltyInfo.timeSpan
end
-- ********************************************************************************
-- 매시브 이벤트 참여
activity.massive = {}
activity.massive.exp = {}
activity.massive.exp.attendPoint = 10 -- 매시브 이벤트에 참가하면 얻을 수 있는 생활 경험치
activity.massive.exp.winPoint = 100 -- 우승하면 획득할 수 있는 생활 경험치
function getMassiveExpPoint(winFlag)
local bonusInfo = activity.massive.exp
if winFlag then
return bonusInfo.winPoint
else
return bonusInfo.attendPoint
end
end
-- ********************************************************************************
-- 플레이어 킬 패널티
activity.kill = {}
activity.kill.penalty = {}
activity.kill.penalty.defaultPoint = 5 -- 다른 플레이어 킬에 따른 매력 포인트 감소
activity.kill.penalty.increasePoint = 1 -- 누적 킬 수 증가에 따른 가중치
activity.kill.penalty.maxPoint = 10 -- 감소하는 최대 한도를 설정
activity.kill.penalty.maxKillCount = 10 -- 누적 킬 카운트의 최대 한도
function getPKPenalty(killCount)
local point = 0
local penaltyInfo = activity.kill.penalty
point = point + penaltyInfo.defaultPoint
point = point + killCount * penaltyInfo.increasePoint
point = math.min(point, penaltyInfo.maxPoint)
Looks like we will be getting plenty of classes in the future.
2014-09-15, 04:41 PM
Eos
Re: Maplestory 2, Aanyeong
Quote:
Originally Posted by Niernen
Looks like we will be getting plenty of classes in the future.
Means nothing.
2014-09-15, 08:56 PM
byakugan
Re: Maplestory 2, Aanyeong
The fact that you guys are being capable to extract all these info so fast... how does that speak for the security of the game? can you guys tell us if MS2 will be harder/easier/the same to plague with hacks as MS1 currently is?
The fact that you guys are being capable to extract all these info so fast... how does that speak for the security of the game? can you guys tell us if MS2 will be harder/easier/the same to plague with hacks as MS1 currently is?
That entirely depends on how much of what's in the client is informational vs actual game mechanics.
If modifying the client lets you change the way the game behaves, it's the exact same craptacity as M1.
2014-09-15, 10:05 PM
Fiel
Re: Maplestory 2, Aanyeong
Quote:
Originally Posted by byakugan
The fact that you guys are being capable to extract all these info so fast... how does that speak for the security of the game? can you guys tell us if MS2 will be harder/easier/the same to plague with hacks as MS1 currently is?
The security on the files I was able to get was abysmal. It was to the point of "not packed". It only took me about 30-45 minutes to figure out the format using only static analysis.
Now I'm trying to figure out the encryption. This is turning out to be a ROYAL pain in the ass - much more than I had bargained for. I'm brute forcing the encryption using a KPA.
2014-09-15, 10:28 PM
Zelkova
Re: Maplestory 2, Aanyeong
I'm using a tool called guessfsb to try to guess the encryption key on the BGM FSB file.